LibreOffice Module sw (master) 1
fntcache.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <sal/config.h>
21
23#include <officecfg/Office/Common.hxx>
24#include <vcl/outdev.hxx>
25#include <vcl/kernarray.hxx>
26#include <vcl/lineinfo.hxx>
27#include <vcl/metric.hxx>
28#include <vcl/svapp.hxx>
29#include <vcl/lazydelete.hxx>
31#include <com/sun/star/i18n/CharacterIteratorMode.hpp>
32#include <com/sun/star/i18n/WordType.hpp>
33#include <com/sun/star/i18n/XBreakIterator.hpp>
34#include <breakit.hxx>
35#include <paintfrm.hxx>
36#include <viewsh.hxx>
37#include <viewopt.hxx>
38#include <fntcache.hxx>
40#include <swfont.hxx>
41#include <wrong.hxx>
42#include <txtfrm.hxx>
43#include <pagefrm.hxx>
44#include <tgrditem.hxx>
45#include <scriptinfo.hxx>
46#include <editeng/brushitem.hxx>
47#include <accessibilityoptions.hxx>
49#include <doc.hxx>
50#include <editeng/fhgtitem.hxx>
51#include <vcl/glyphitem.hxx>
52#include <vcl/vcllayout.hxx>
53#include <docsh.hxx>
54#include <strings.hrc>
55#include <fntcap.hxx>
57#include <o3tl/hash_combine.hxx>
58#include <cstdint>
59#include <memory>
60#include "justify.hxx"
61
62using namespace ::com::sun::star;
63
64// global variables declared in fntcache.hxx
65// FontCache is created in txtinit.cxx TextInit_ and deleted in TextFinit
67// last Font set by ChgFntCache
69
70constexpr Color gWaveCol(COL_GRAY);
71
75
77{
78 if ( pLastFont )
79 {
81 pLastFont = nullptr;
82 }
84}
85
86SwFntObj::SwFntObj(const SwSubFont &rFont, std::uintptr_t nFontCacheId, SwViewShell const *pSh)
87 : SwCacheObj(reinterpret_cast<void *>(nFontCacheId))
88 , m_aFont(rFont)
89 , m_pScrFont(nullptr)
90 , m_pPrtFont(&m_aFont)
91 , m_pPrinter(nullptr)
92 , m_nGuessedLeading(USHRT_MAX)
93 , m_nExtLeading(USHRT_MAX)
94 , m_nScrAscent(0)
95 , m_nPrtAscent(USHRT_MAX)
96 , m_nScrHeight(0)
97 , m_nPrtHeight(USHRT_MAX)
98 , m_nPropWidth(rFont.GetPropWidth())
99 , m_nScrHangingBaseline(0)
100 , m_nPrtHangingBaseline(0)
101{
102 m_nZoom = pSh ? pSh->GetViewOptions()->GetZoom() : USHRT_MAX;
103 m_bSymbol = RTL_TEXTENCODING_SYMBOL == m_aFont.GetCharSet();
108 m_aFont.SetLanguage(rFont.GetLanguage());
109}
110
112{
113 if ( m_pScrFont != m_pPrtFont )
114 delete m_pScrFont;
115 if ( m_pPrtFont != &m_aFont )
116 delete m_pPrtFont;
117}
118
120{
121 if ( m_nPropWidth == 100 || m_pPrinter == &rPrt )
122 return;
123
124 if( m_pScrFont != m_pPrtFont )
125 delete m_pScrFont;
126 if( m_pPrtFont != &m_aFont )
127 delete m_pPrtFont;
128
129 const vcl::Font aOldFnt( rPrt.GetFont() );
130 const_cast<OutputDevice&>(rPrt).SetFont( m_aFont );
131 const FontMetric aWinMet( rPrt.GetFontMetric() );
132 const_cast<OutputDevice&>(rPrt).SetFont( aOldFnt );
133 auto nWidth = ( aWinMet.GetFontSize().Width() * m_nPropWidth ) / 100;
134
135 if( !nWidth )
136 ++nWidth;
139 m_pScrFont = nullptr;
140
141}
142
143/*
144 * returns whether we have to adjust the output font to resemble
145 * the formatting font
146 *
147 * _Not_ necessary if
148 *
149 * 1. RefDef == OutDev (text formatting, online layout...)
150 * 2. PDF export from online layout
151 * 3. Prospect/PagePreview printing
152 */
154 const vcl::RenderContext& rRefDev )
155{
156 return &rRefDev != &rOutDev &&
157 OUTDEV_WINDOW != rRefDev.GetOutDevType() &&
158 ( OUTDEV_PRINTER != rRefDev.GetOutDevType() ||
159 OUTDEV_PRINTER != rOutDev.GetOutDevType() );
160}
161
162namespace {
163
164struct CalcLinePosData
165{
166 SwDrawTextInfo& rInf;
167 vcl::Font& rFont;
168 TextFrameIndex nCnt;
169 const bool bSwitchH2V;
170 const bool bSwitchH2VLRBT;
171 const bool bSwitchL2R;
172 tools::Long nHalfSpace;
173 KernArray& rKernArray;
174 const bool bBidiPor;
175
176 CalcLinePosData( SwDrawTextInfo& _rInf, vcl::Font& _rFont,
177 TextFrameIndex const _nCnt, const bool _bSwitchH2V, const bool _bSwitchH2VLRBT, const bool _bSwitchL2R,
178 tools::Long _nHalfSpace, KernArray& _rKernArray, const bool _bBidiPor) :
179 rInf( _rInf ),
180 rFont( _rFont ),
181 nCnt( _nCnt ),
182 bSwitchH2V( _bSwitchH2V ),
183 bSwitchH2VLRBT( _bSwitchH2VLRBT ),
184 bSwitchL2R( _bSwitchL2R ),
185 nHalfSpace( _nHalfSpace ),
186 rKernArray( _rKernArray ),
187 bBidiPor( _bBidiPor )
188 {
189 }
190};
191
192}
193
194// Computes the start and end position of an underline. This function is called
195// from the DrawText-method (for underlining misspelled words or smarttag terms).
196static void lcl_calcLinePos( const CalcLinePosData &rData,
197 Point &rStart, Point &rEnd, TextFrameIndex const nStart, TextFrameIndex const nWrLen)
198{
199 tools::Long nBlank = 0;
200 const TextFrameIndex nEnd = nStart + nWrLen;
201 const tools::Long nTmpSpaceAdd = rData.rInf.GetSpace() / SPACING_PRECISION_FACTOR;
202
203 if ( nEnd < rData.nCnt
204 && CH_BLANK == rData.rInf.GetText()[sal_Int32(rData.rInf.GetIdx() + nEnd)] )
205 {
206 if (nEnd + TextFrameIndex(1) == rData.nCnt)
207 nBlank -= nTmpSpaceAdd;
208 else
209 nBlank -= rData.nHalfSpace;
210 }
211
212 // determine start, end and length of wave line
213 sal_Int32 nKernStart = nStart ? rData.rKernArray[sal_Int32(nStart) - 1] : 0;
214 sal_Int32 nKernEnd = rData.rKernArray[sal_Int32(nEnd) - 1];
215
216 const Degree10 nDir = rData.bBidiPor ? 1800_deg10
217 : UnMapDirection(rData.rFont.GetOrientation(),
218 rData.bSwitchH2V, rData.bSwitchH2VLRBT);
219
220 switch ( nDir.get() )
221 {
222 case 0 :
223 rStart.AdjustX(nKernStart );
224 rEnd.setX( nBlank + rData.rInf.GetPos().X() + nKernEnd );
225 rEnd.setY( rData.rInf.GetPos().Y() );
226 break;
227 case 900 :
228 rStart.AdjustY( -nKernStart );
229 rEnd.setX( rData.rInf.GetPos().X() );
230 rEnd.setY( nBlank + rData.rInf.GetPos().Y() - nKernEnd );
231 break;
232 case 1800 :
233 rStart.AdjustX( -nKernStart );
234 rEnd.setX( rData.rInf.GetPos().X() - nKernEnd - nBlank );
235 rEnd.setY( rData.rInf.GetPos().Y() );
236 break;
237 case 2700 :
238 rStart.AdjustY(nKernStart );
239 rEnd.setX( rData.rInf.GetPos().X() );
240 rEnd.setY( nBlank + rData.rInf.GetPos().Y() + nKernEnd );
241 break;
242 }
243
244 if ( rData.bSwitchL2R )
245 {
246 rData.rInf.GetFrame()->SwitchLTRtoRTL( rStart );
247 rData.rInf.GetFrame()->SwitchLTRtoRTL( rEnd );
248 }
249
250 if ( rData.bSwitchH2V )
251 {
252 rData.rInf.GetFrame()->SwitchHorizontalToVertical( rStart );
253 rData.rInf.GetFrame()->SwitchHorizontalToVertical( rEnd );
254 }
255}
256
257// Returns the Ascent of the Font on the given output device;
258// it may be necessary to create the screen font first.
259sal_uInt16 SwFntObj::GetFontAscent( const SwViewShell *pSh, const OutputDevice& rOut )
260{
261 sal_uInt16 nRet = 0;
262 const OutputDevice& rRefDev = pSh ? pSh->GetRefDev() : rOut;
263
264 if ( pSh && lcl_IsFontAdjustNecessary( rOut, rRefDev ) )
265 {
266 CreateScrFont( *pSh, rOut );
267 OSL_ENSURE( USHRT_MAX != m_nScrAscent, "nScrAscent is going berzerk" );
268 nRet = m_nScrAscent;
269 }
270 else
271 {
272 if (m_nPrtAscent == USHRT_MAX) // printer ascent unknown?
273 {
274 CreatePrtFont( rOut );
275 const vcl::Font aOldFnt( rRefDev.GetFont() );
276 const_cast<OutputDevice&>(rRefDev).SetFont( *m_pPrtFont );
277 const FontMetric aOutMet( rRefDev.GetFontMetric() );
278 m_nPrtAscent = o3tl::narrowing<sal_uInt16>(aOutMet.GetAscent());
279 m_nPrtHangingBaseline = o3tl::narrowing<sal_uInt16>(aOutMet.GetHangingBaseline());
280 const_cast<OutputDevice&>(rRefDev).SetFont( aOldFnt );
281 }
282
283 nRet = m_nPrtAscent;
284 }
285
286#if !defined(MACOSX) // #i89844# extleading is below the line for Mac
287 // TODO: move extleading below the line for all platforms too
288 nRet += GetFontLeading( pSh, rRefDev );
289#endif
290
291 OSL_ENSURE( USHRT_MAX != nRet, "GetFontAscent returned USHRT_MAX" );
292 return nRet;
293}
294
295// Returns the height of the Font on the given output device;
296// it may be necessary to create the screen font first.
297sal_uInt16 SwFntObj::GetFontHeight( const SwViewShell* pSh, const OutputDevice& rOut )
298{
299 sal_uInt16 nRet = 0;
300 const OutputDevice& rRefDev = pSh ? pSh->GetRefDev() : rOut;
301
302 if ( pSh && lcl_IsFontAdjustNecessary( rOut, rRefDev ) )
303 {
304 CreateScrFont( *pSh, rOut );
305 OSL_ENSURE( USHRT_MAX != m_nScrHeight, "nScrHeight is going berzerk" );
306 nRet = m_nScrHeight + GetFontLeading( pSh, rRefDev );
307 }
308 else
309 {
310 if (m_nPrtHeight == USHRT_MAX) // printer height unknown?
311 {
312 CreatePrtFont( rOut );
313 const vcl::Font aOldFnt( rRefDev.GetFont() );
314 const_cast<OutputDevice&>(rRefDev).SetFont( *m_pPrtFont );
315 m_nPrtHeight = o3tl::narrowing<sal_uInt16>(rRefDev.GetTextHeight());
316
317#if OSL_DEBUG_LEVEL > 0
318 // Check if vcl did not change the meaning of GetTextHeight
319 const FontMetric aOutMet( rRefDev.GetFontMetric() );
320 tools::Long nTmpPrtHeight = o3tl::narrowing<sal_uInt16>(aOutMet.GetAscent()) + aOutMet.GetDescent();
321 // #i106098#: do not compare with == here due to rounding error
322 OSL_ENSURE( std::abs(nTmpPrtHeight - m_nPrtHeight) < 3,
323 "GetTextHeight != Ascent + Descent" );
324#endif
325
326 const_cast<OutputDevice&>(rRefDev).SetFont( aOldFnt );
327 }
328
329 nRet = m_nPrtHeight + GetFontLeading( pSh, rRefDev );
330 }
331
332 OSL_ENSURE( USHRT_MAX != nRet, "GetFontHeight returned USHRT_MAX" );
333 return nRet;
334}
335
336sal_uInt16 SwFntObj::GetFontLeading( const SwViewShell *pSh, const OutputDevice& rOut )
337{
338 sal_uInt16 nRet = 0;
339
340 if ( pSh )
341 {
342 if ( USHRT_MAX == m_nGuessedLeading || USHRT_MAX == m_nExtLeading )
343 {
344 SolarMutexGuard aGuard;
345
346 const vcl::Font aOldFnt( rOut.GetFont() );
347 const_cast<OutputDevice&>(rOut).SetFont( *m_pPrtFont );
348 const FontMetric aMet( rOut.GetFontMetric() );
349 const_cast<OutputDevice&>(rOut).SetFont( aOldFnt );
350 m_bSymbol = RTL_TEXTENCODING_SYMBOL == aMet.GetCharSet();
351 GuessLeading( *pSh, aMet );
352 m_nExtLeading = o3tl::narrowing<sal_uInt16>(aMet.GetExternalLeading());
353 /* HACK: FIXME There is something wrong with Writer's bullet rendering, causing lines
354 with bullets to be higher than they should be. I think this is because
355 Writer uses font's external leading incorrect, as the vertical distance
356 added to every line instead of only a distance between multiple lines,
357 which means a single bullet has external leading added even though it
358 shouldn't, but frankly this is just an educated guess rather than understanding
359 Writer's layout (heh).
360 Symbol font in some documents is 'StarSymbol; Arial Unicode MS', and Windows
361 machines often do not have StarSymbol, falling back to Arial Unicode MS, which
362 has unusually high external leading. So just reset external leading for fonts
363 which are used to bullets, as those should not be used on multiple lines anyway,
364 so in correct rendering external leading should be irrelevant anyway.
365 Interestingly enough, bSymbol is false for 'StarSymbol; Arial Unicode MS', so
366 also check explicitly.
367 */
369 m_nExtLeading = 0;
370 }
371
373 const bool bBrowse = ( pSh->GetWin() &&
374 pSh->GetViewOptions()->getBrowseMode() &&
375 !pSh->GetViewOptions()->IsPrtFormat() );
376
377 if ( !bBrowse && rIDSA.get(DocumentSettingId::ADD_EXT_LEADING) )
378 nRet = m_nExtLeading;
379 else
380 nRet = m_nGuessedLeading;
381 }
382
383 OSL_ENSURE( USHRT_MAX != nRet, "GetFontLeading returned USHRT_MAX" );
384 return nRet;
385}
386
387sal_uInt16 SwFntObj::GetFontHangingBaseline( const SwViewShell* pSh, const OutputDevice& rOut )
388{
389 sal_uInt16 nRet = 0;
390 const OutputDevice& rRefDev = pSh ? pSh->GetRefDev() : rOut;
391
392 GetFontAscent(pSh, rOut);
393
394 if ( pSh && lcl_IsFontAdjustNecessary( rOut, rRefDev ) )
396 else
398
399 return nRet;
400}
401
402// pOut is the output device, not the reference device
403void SwFntObj::CreateScrFont( const SwViewShell& rSh, const OutputDevice& rOut )
404{
405 if ( m_pScrFont )
406 return;
407
408 // any changes to the output device are reset at the end of the function
409 OutputDevice* pOut = const_cast<OutputDevice*>(&rOut);
410
411 // Save old font
412 vcl::Font aOldOutFont( pOut->GetFont() );
413
414 m_nScrHeight = USHRT_MAX;
415
416 // Condition for output font / refdev font adjustment
417 OutputDevice* pPrt = &rSh.GetRefDev();
418
419 if( !rSh.GetWin() ||
420 !rSh.GetViewOptions()->getBrowseMode() ||
421 rSh.GetViewOptions()->IsPrtFormat() )
422 {
423 // After CreatePrtFont m_pPrtFont is the font which is actually used
424 // by the reference device
425 CreatePrtFont( *pPrt );
426 m_pPrinter = pPrt;
427
428 // save old reference device font
429 vcl::Font aOldPrtFnt( pPrt->GetFont() );
430
431 // set the font used at the reference device at the reference device
432 // and the output device
433 pPrt->SetFont( *m_pPrtFont );
434 pOut->SetFont( *m_pPrtFont );
435
436 // This should be the default for pScrFont.
438
439 FontMetric aMet = pPrt->GetFontMetric( );
440 // Don't lose "faked" properties of the logical font that don't truly
441 // exist in the physical font metrics which vcl which fake up for us
444
445 m_bSymbol = RTL_TEXTENCODING_SYMBOL == aMet.GetCharSet();
446
447 if ( USHRT_MAX == m_nGuessedLeading )
448 GuessLeading( rSh, aMet );
449
450 if ( USHRT_MAX == m_nExtLeading )
451 m_nExtLeading = o3tl::narrowing<sal_uInt16>(aMet.GetExternalLeading());
452
453 // reset the original reference device font
454 pPrt->SetFont( aOldPrtFnt );
455 }
456 else
457 {
458 m_bSymbol = RTL_TEXTENCODING_SYMBOL == m_aFont.GetCharSet();
459 if ( m_nGuessedLeading == USHRT_MAX )
461
462 // no external leading in browse mode
463 if ( m_nExtLeading == USHRT_MAX )
464 m_nExtLeading = 0;
465
467 }
468
469 m_nScrAscent = o3tl::narrowing<sal_uInt16>(pOut->GetFontMetric().GetAscent());
470 m_nScrHangingBaseline = o3tl::narrowing<sal_uInt16>(pOut->GetFontMetric().GetHangingBaseline());
471 if ( USHRT_MAX == m_nScrHeight )
472 m_nScrHeight = o3tl::narrowing<sal_uInt16>(pOut->GetTextHeight());
473
474 // reset original output device font
475 pOut->SetFont( aOldOutFont );
476}
477
479#if defined(_WIN32)
480 rSh
481#endif
482 , const FontMetric& rMet )
483{
484 // If leading >= 5, this seems to be enough leading.
485 // Nothing has to be done.
486 if ( rMet.GetInternalLeading() >= 5 )
487 {
489 return;
490 }
491
492#if defined(_WIN32)
493 OutputDevice *pWin = rSh.GetWin() ?
494 rSh.GetWin()->GetOutDev() :
496 if ( pWin )
497 {
498 MapMode aTmpMap( MapUnit::MapTwip );
499 MapMode aOldMap = pWin->GetMapMode( );
500 pWin->SetMapMode( aTmpMap );
501 const vcl::Font aOldFnt( pWin->GetFont() );
502 pWin->SetFont( *m_pPrtFont );
503 const FontMetric aWinMet( pWin->GetFontMetric() );
504 const sal_uInt16 nWinHeight = sal_uInt16( aWinMet.GetFontSize().Height() );
505 if( m_pPrtFont->GetFamilyName().indexOf( aWinMet.GetFamilyName() ) != -1 )
506 {
507 // If the Leading on the Window is also 0, then it has to stay
508 // that way (see also StarMath).
509 tools::Long nTmpLeading = aWinMet.GetInternalLeading();
510 if( nTmpLeading <= 0 )
511 {
512 pWin->SetFont( rMet );
513 nTmpLeading = pWin->GetFontMetric().GetInternalLeading();
514 if( nTmpLeading < 0 )
516 else
517 m_nGuessedLeading = sal_uInt16(nTmpLeading);
518 }
519 else
520 {
521 m_nGuessedLeading = sal_uInt16(nTmpLeading);
522 // Manta-Hack #50153#:
523 // Wer beim Leading luegt, luegt moeglicherweise auch beim
524 // Ascent/Descent, deshalb wird hier ggf. der Font ein wenig
525 // tiefergelegt, ohne dabei seine Hoehe zu aendern.
526 // (above original comment preserved for cultural reasons)
527 // Those who lie about their Leading, may lie about their
528 // Ascent/Descent as well, hence the Font will be lowered a
529 // little without changing its height.
530 tools::Long nDiff = std::min( rMet.GetDescent() - aWinMet.GetDescent(),
531 aWinMet.GetAscent() - rMet.GetAscent() - nTmpLeading );
532 if( nDiff > 0 )
533 {
534 OSL_ENSURE( m_nPrtAscent < USHRT_MAX, "GuessLeading: PrtAscent-Fault" );
535 if ( m_nPrtAscent < USHRT_MAX )
536 m_nPrtAscent = m_nPrtAscent + o3tl::narrowing<sal_uInt16>(( 2 * nDiff ) / 5);
537 }
538 }
539 }
540 else
541 {
542 // If all else fails, take 15% of the height, as empirically
543 // determined by CL
544 m_nGuessedLeading = (nWinHeight * 15) / 100;
545 }
546 pWin->SetFont( aOldFnt );
547 pWin->SetMapMode( aOldMap );
548 }
549 else
551#else
553#endif
554}
555
556// Set the font at the given output device; for screens it may be
557// necessary to do some adjustment first.
559{
560 const OutputDevice& rRefDev = pSh ? pSh->GetRefDev() : rOut;
561
562 if ( pSh && lcl_IsFontAdjustNecessary( rOut, rRefDev ) )
563 {
564 CreateScrFont( *pSh, rOut );
565 if( !GetScrFont()->IsSameInstance( rOut.GetFont() ) )
566 rOut.SetFont( *m_pScrFont );
567 if( m_pPrinter && ( !m_pPrtFont->IsSameInstance( m_pPrinter->GetFont() ) ) )
568 m_pPrinter->SetFont( *m_pPrtFont );
569 }
570 else
571 {
572 CreatePrtFont( rOut );
573 if( !m_pPrtFont->IsSameInstance( rOut.GetFont() ) )
574 rOut.SetFont( *m_pPrtFont );
575 }
576
577 // Here, we actually do not need the leading values, but by calling
578 // GetFontLeading() we assure that the values are calculated for later use.
579 GetFontLeading( pSh, rRefDev );
580}
581
582#define WRONG_SHOW_MIN 5
583
584/*
585 * Output text:
586 * on screen => DrawTextArray
587 * on printer, !Kerning => DrawText
588 * on printer + Kerning => DrawStretchText
589 */
590static bool lcl_IsMonoSpaceFont( const vcl::RenderContext& rOut )
591{
592 const tools::Long nWidth1 = rOut.GetTextWidth( OUString( u'\x3008' ) );
593 const tools::Long nWidth2 = rOut.GetTextWidth( OUString( u'\x307C' ) );
594 return nWidth1 == nWidth2;
595}
596
598{
599 const FontMetric aMetric( rOut.GetFontMetric() );
600 return aMetric.IsFullstopCentered() ;
601}
602
603/* This helper structure (SwForbidden) contains the already marked parts of the string
604 to avoid double lines (e.g grammar + spell check error) */
605
606typedef std::vector<std::pair<TextFrameIndex, TextFrameIndex>> SwForbidden;
607
609 SwForbidden &rForbidden,
610 const SwDrawTextInfo &rInf,
611 sw::WrongListIterator *pWList,
612 const CalcLinePosData &rCalcLinePosData,
613 const Size &rPrtFontSize )
614{
615 if (!pWList) return;
616
617 TextFrameIndex nStart = rInf.GetIdx();
618 TextFrameIndex nWrLen = rInf.GetLen();
619
620 // check if respective data is available in the current text range
621 if (!pWList->Check( nStart, nWrLen ))
622 {
623 return;
624 }
625
626 tools::Long nHght = rInf.GetOut().LogicToPixel( rPrtFontSize ).Height();
627
628 // Draw wavy lines for spell and grammar errors only if font is large enough.
629 // Lines for smart tags will always be drawn.
630 if (pWList != rInf.GetSmartTags() && WRONG_SHOW_MIN >= nHght)
631 {
632 return;
633 }
634
635 SwForbidden::iterator pIter = rForbidden.begin();
636 if (rInf.GetOut().GetConnectMetaFile())
637 rInf.GetOut().Push();
638
639 const Color aCol( rInf.GetOut().GetLineColor() );
640
641 // iterate over all ranges stored in the respective SwWrongList
642 do
643 {
644 nStart -= rInf.GetIdx();
645
646 const TextFrameIndex nEnd = nStart + nWrLen;
647 TextFrameIndex nNext = nStart;
648 while( nNext < nEnd )
649 {
650 while( pIter != rForbidden.end() && pIter->second <= nNext )
651 ++pIter;
652
653 const TextFrameIndex nNextStart = nNext;
654 TextFrameIndex nNextEnd = nEnd;
655
656 if( pIter == rForbidden.end() || nNextEnd <= pIter->first )
657 {
658 // No overlapping mark up found
659 rForbidden.insert(pIter, std::make_pair(nNextStart, nNextEnd));
660 pIter = rForbidden.begin();
661 nNext = nEnd;
662 }
663 else
664 {
665 nNext = pIter->second;
666 if( nNextStart < pIter->first )
667 {
668 nNextEnd = pIter->first;
669 pIter->first = nNextStart;
670 }
671 else
672 continue;
673 }
674 // determine line pos
675 Point aStart( rInf.GetPos() );
676 Point aEnd;
677 lcl_calcLinePos( rCalcLinePosData, aStart, aEnd, nNextStart, nNextEnd - nNextStart );
678
679 SwWrongArea const*const wrongArea = pWList->GetWrongElement(nNextStart + rInf.GetIdx());
680 if (wrongArea != nullptr)
681 {
682 const SwViewShell* pShell = rInf.GetShell();
683 sal_uInt16 nZoom = pShell ? round(pShell->GetViewOptions()->GetZoom()/100) : 1;
684 if (WRONGAREA_WAVE == wrongArea->mLineType)
685 {
686 vcl::ScopedAntialiasing a(rInf.GetOut(), true);
687 rInf.GetOut().SetLineColor( wrongArea->mColor );
688 rInf.GetOut().DrawWaveLine( aStart, aEnd, 1 + nZoom, 3 + nZoom );
689 }
690 else if (WRONGAREA_BOLDWAVE == wrongArea->mLineType)
691 {
692 vcl::ScopedAntialiasing a(rInf.GetOut(), true);
693 rInf.GetOut().SetLineColor( wrongArea->mColor );
694 rInf.GetOut().DrawWaveLine( aStart, aEnd, 2 + nZoom, 4 + nZoom );
695 }
696 else if (WRONGAREA_BOLD == wrongArea->mLineType)
697 {
698 rInf.GetOut().SetLineColor( wrongArea->mColor );
699
700 aStart.AdjustY(30 );
701 aEnd.AdjustY(30 );
702
703 LineInfo aLineInfo( LineStyle::Solid, 26 );
704
705 rInf.GetOut().DrawLine( aStart, aEnd, aLineInfo );
706 }
707 else if (WRONGAREA_DASHED == wrongArea->mLineType)
708 {
709 rInf.GetOut().SetLineColor( wrongArea->mColor );
710
711 aStart.AdjustY(30 );
712 aEnd.AdjustY(30 );
713
714 LineInfo aLineInfo( LineStyle::Dash );
715 aLineInfo.SetDistance( 40 );
716 aLineInfo.SetDashLen( 1 );
717 aLineInfo.SetDashCount(1);
718
719 rInf.GetOut().DrawLine( aStart, aEnd, aLineInfo );
720 }
721 }
722 }
723
724 nStart = nEnd + rInf.GetIdx();
725 nWrLen = rInf.GetIdx() + rInf.GetLen() - nStart;
726 }
727 while (nWrLen && pWList->Check( nStart, nWrLen ));
728
729 rInf.GetOut().SetLineColor( aCol );
730
731 if (rInf.GetOut().GetConnectMetaFile())
732 rInf.GetOut().Pop();
733}
734
735static void GetTextArray(const OutputDevice& rDevice, const OUString& rStr, KernArray& rDXAry,
736 sal_Int32 nIndex, sal_Int32 nLen, bool bCaret = false,
737 const vcl::text::TextLayoutCache* layoutCache = nullptr)
738{
739 const SalLayoutGlyphs* pLayoutCache = SalLayoutGlyphsCache::self()->GetLayoutGlyphs(&rDevice, rStr, nIndex, nLen,
740 0, layoutCache);
741 rDevice.GetTextArray(rStr, &rDXAry, nIndex, nLen, bCaret, layoutCache, pLayoutCache);
742}
743
744static void GetTextArray(const OutputDevice& rOutputDevice, const SwDrawTextInfo& rInf, KernArray& rDXAry,
745 bool bCaret = false)
746{
747 return GetTextArray(rOutputDevice, rInf.GetText(), rDXAry, rInf.GetIdx().get(), rInf.GetLen().get(),
748 bCaret, rInf.GetVclCache());
749}
750
751static void GetTextArray(const OutputDevice& rOutputDevice, const SwDrawTextInfo& rInf, KernArray& rDXAry,
752 sal_Int32 nLen, bool bCaret = false)
753{
754 // Substring is fine.
755 assert( nLen <= rInf.GetLen().get());
756 return GetTextArray(rOutputDevice, rInf.GetText(), rDXAry, rInf.GetIdx().get(), nLen, bCaret, rInf.GetVclCache());
757}
758
760{
761 OSL_ENSURE( rInf.GetShell(), "SwFntObj::DrawText without shell" );
762
763 OutputDevice& rRefDev = rInf.GetShell()->GetRefDev();
764 vcl::Window* pWin = rInf.GetShell()->GetWin();
765
766 // true if pOut is the printer and the printer has been used for formatting
767 const bool bPrt = OUTDEV_PRINTER == rInf.GetOut().GetOutDevType() &&
768 OUTDEV_PRINTER == rRefDev.GetOutDevType();
769 const bool bBrowse = ( pWin &&
771 !rInf.GetShell()->GetViewOptions()->IsPrtFormat() &&
772 !rInf.GetBullet() &&
773 ( rInf.GetSpace() || !rInf.GetKern() ) &&
774 !rInf.GetWrong() &&
775 !rInf.GetGrammarCheck() &&
776 !rInf.GetSmartTags() &&
777 !rInf.GetGreyWave() );
778
779 // bDirectPrint indicates that we can enter the branch which calls
780 // the DrawText functions instead of calling the DrawTextArray functions
781 const bool bDirectPrint = bPrt || bBrowse;
782
783 // Condition for output font / refdev font adjustment
784 const bool bUseScrFont =
785 lcl_IsFontAdjustNecessary( rInf.GetOut(), rRefDev );
786
787 vcl::Font* pTmpFont = bUseScrFont ? m_pScrFont : m_pPrtFont;
788
789 // bDirectPrint and bUseScrFont should have these values:
790
791 // Outdev / RefDef | Printer | VirtPrinter | Window
792
793 // Printer | 1 - 0 | 0 - 1 | -
794
795 // VirtPrinter/PDF | 0 - 1 | 0 - 1 | -
796
797 // Window/VirtWindow| 0 - 1 | 0 - 1 | 1 - 0
798
799 // Exception: During painting of a Writer OLE object, we do not have
800 // a window. Therefore bUseSrcFont is always 0 in this case.
801
802#if OSL_DEBUG_LEVEL > 0
803
804 const bool bNoAdjust = bPrt ||
805 ( pWin &&
807 !rInf.GetShell()->GetViewOptions()->IsPrtFormat() );
808
809 if ( OUTDEV_PRINTER == rInf.GetOut().GetOutDevType() )
810 {
811 // Printer output
812 if ( OUTDEV_PRINTER == rRefDev.GetOutDevType() )
813 {
814 OSL_ENSURE( bNoAdjust && !bUseScrFont, "Outdev Check failed" );
815 }
816 else if ( rRefDev.IsVirtual() )
817 {
818 OSL_ENSURE( !bNoAdjust && bUseScrFont, "Outdev Check failed" );
819 }
820 else
821 {
822 OSL_FAIL( "Outdev Check failed" );
823 }
824 }
825 else if ( rInf.GetOut().IsVirtual() && ! pWin )
826 {
827 // PDF export
828 if ( OUTDEV_PRINTER == rRefDev.GetOutDevType() )
829 {
830 OSL_ENSURE( !bNoAdjust && bUseScrFont, "Outdev Check failed" );
831 }
832 else if ( rRefDev.IsVirtual() )
833 {
834 OSL_ENSURE( !bNoAdjust && bUseScrFont, "Outdev Check failed" );
835 }
836 else
837 {
838 OSL_FAIL( "Outdev Check failed" );
839 }
840 }
841 else if ( OUTDEV_WINDOW == rInf.GetOut().GetOutDevType() ||
842 ( rInf.GetOut().IsVirtual() && pWin ) )
843 {
844 // Window or virtual window
845 if ( OUTDEV_PRINTER == rRefDev.GetOutDevType() )
846 {
847 OSL_ENSURE( !bNoAdjust && bUseScrFont, "Outdev Check failed" );
848 }
849 else if ( rRefDev.IsVirtual() )
850 {
851 OSL_ENSURE( !bNoAdjust && bUseScrFont, "Outdev Check failed" );
852 }
853 else if ( OUTDEV_WINDOW == rRefDev.GetOutDevType() )
854 {
855 OSL_ENSURE( bNoAdjust && !bUseScrFont, "Outdev Check failed" );
856 }
857 else
858 {
859 OSL_FAIL( "Outdev Check failed" );
860 }
861 }
862 else
863 {
864 OSL_FAIL( "Outdev Check failed" );
865 }
866
867#endif
868
869 // robust: better use the printer font instead of using no font at all
870 OSL_ENSURE( pTmpFont, "No screen or printer font?" );
871 if ( ! pTmpFont )
872 pTmpFont = m_pPrtFont;
873
874 // HACK: LINESTYLE_WAVE must not be abused any more, hence the grey wave
875 // line of the ExtendedAttributeSets will appear in the font color first
876
877 const bool bSwitchH2V = rInf.GetFrame() && rInf.GetFrame()->IsVertical();
878 const bool bSwitchH2VLRBT = rInf.GetFrame() && rInf.GetFrame()->IsVertLRBT();
879 const bool bSwitchL2R = rInf.GetFrame() && rInf.GetFrame()->IsRightToLeft() &&
880 ! rInf.IsIgnoreFrameRTL();
882 const bool bBidiPor = ( bSwitchL2R !=
884
885 // be sure to have the correct layout mode at the printer
886 if ( m_pPrinter )
887 {
888 m_pPrinter->SetLayoutMode( rInf.GetOut().GetLayoutMode() );
889 m_pPrinter->SetDigitLanguage( rInf.GetOut().GetDigitLanguage() );
890 }
891
892 Point aTextOriginPos( rInf.GetPos() );
893 if( !bPrt )
894 {
895 if( rInf.GetpOut() != *s_pFntObjPixOut.get() || rInf.GetOut().GetMapMode() != *s_pPixMap )
896 {
897 *s_pPixMap = rInf.GetOut().GetMapMode();
898 (*s_pFntObjPixOut.get()) = rInf.GetpOut();
899 Size aTmp( 1, 1 );
900 s_nPixWidth = rInf.GetOut().PixelToLogic( aTmp ).Width();
901 }
902
903 aTextOriginPos.AdjustX(rInf.GetFrame()->IsRightToLeft() ? 0 : s_nPixWidth );
904 }
905
906 Color aOldColor( pTmpFont->GetColor() );
907 bool bChgColor = rInf.ApplyAutoColor( pTmpFont );
908 if( !pTmpFont->IsSameInstance( rInf.GetOut().GetFont() ) )
909 rInf.GetOut().SetFont( *pTmpFont );
910 if ( bChgColor )
911 pTmpFont->SetColor( aOldColor );
912
914 rInf.SetLen( TextFrameIndex(rInf.GetText().getLength()) );
915
916 // ASIAN LINE AND CHARACTER GRID MODE START
917
918 if ( rInf.GetFrame() && rInf.SnapToGrid() && rInf.GetFont() &&
919 SwFontScript::CJK == rInf.GetFont()->GetActual() )
920 {
921 SwTextGridItem const*const pGrid(GetGridItem(rInf.GetFrame()->FindPageFrame()));
922
923 // ASIAN LINE AND CHARACTER GRID MODE
924 if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() )
925 {
926 //for textgrid refactor
927 const SwDoc* pDoc = rInf.GetShell()->GetDoc();
928 const tools::Long nGridWidth = GetGridWidth(*pGrid, *pDoc);
929 tools::Long nSpaceAdd = rInf.GetSpace() / SPACING_PRECISION_FACTOR;
930
931 // kerning array - gives the absolute position of end of each character
932 KernArray aKernArray;
933
934 if ( m_pPrinter )
935 GetTextArray(*m_pPrinter, rInf, aKernArray);
936 else
937 GetTextArray(rInf.GetOut(), rInf, aKernArray);
938
939 tools::Long nDelta = 0;
940
941 if (pGrid->IsSnapToChars())
942 {
943 nDelta = sw::Justify::SnapToGrid(aKernArray, rInf.GetText(), sal_Int32(rInf.GetIdx()),
944 sal_Int32(rInf.GetLen()), nGridWidth, false);
945 }
946 else
947 {
948 sw::Justify::SnapToGridEdge(aKernArray, sal_Int32(rInf.GetLen()), nGridWidth,
949 nSpaceAdd, rInf.GetKern());
950 }
951
952 if (nDelta)
953 aTextOriginPos.AdjustX(nDelta);
954
955 if ( bSwitchH2V )
956 rInf.GetFrame()->SwitchHorizontalToVertical( aTextOriginPos );
957
958 rInf.GetOut().DrawTextArray( aTextOriginPos, rInf.GetText(),
959 aKernArray, {}, sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()));
960
961 return;
962 }
963 }
964
965 // DIRECT PAINTING WITHOUT SCREEN ADJUSTMENT
966
967 if ( bDirectPrint )
968 {
969 const Fraction aTmp( 1, 1 );
970 bool bStretch = rInf.GetWidth() && (rInf.GetLen() > TextFrameIndex(1)) && bPrt
971 && ( aTmp != rInf.GetOut().GetMapMode().GetScaleX() );
972
973 if ( bSwitchL2R )
974 rInf.GetFrame()->SwitchLTRtoRTL( aTextOriginPos );
975
976 if ( bSwitchH2V )
977 rInf.GetFrame()->SwitchHorizontalToVertical( aTextOriginPos );
978
979 // In the good old days we used to have a simple DrawText if the
980 // output device is the printer. Now we need a DrawTextArray if
981 // 1. KanaCompression is enabled
982 // 2. Justified alignment
983 // Simple kerning is handled by DrawStretchText
984 if( rInf.GetSpace() || rInf.GetKanaComp() )
985 {
986 KernArray aKernArray;
987 GetTextArray(rInf.GetOut(), rInf, aKernArray);
988 std::vector<sal_Bool> aKashidaArray;
989
990 if( bStretch )
991 {
992 sal_Int32 nZwi = sal_Int32(rInf.GetLen()) - 1;
993 tools::Long nDiff = rInf.GetWidth() - aKernArray[ nZwi ]
994 - sal_Int32(rInf.GetLen()) * rInf.GetKern();
995 tools::Long nRest = nDiff % nZwi;
996 tools::Long nAdd;
997 if( nRest < 0 )
998 {
999 nAdd = -1;
1000 nRest += nZwi;
1001 }
1002 else
1003 {
1004 nAdd = +1;
1005 nRest = nZwi - nRest;
1006 }
1007 nDiff /= nZwi;
1008 tools::Long nSum = nDiff;
1009 for( sal_Int32 i = 0; i < nZwi; )
1010 {
1011 aKernArray.adjust(i, nSum);
1012 if( ++i == nRest )
1013 nDiff += nAdd;
1014 nSum += nDiff;
1015 }
1016 }
1017
1018 // Modify Array for special justifications
1019
1020 tools::Long nSpaceAdd = rInf.GetSpace() / SPACING_PRECISION_FACTOR;
1021 bool bSpecialJust = false;
1022
1023 if ( rInf.GetFont() && rInf.GetLen() )
1024 {
1025 const SwScriptInfo* pSI = rInf.GetScriptInfo();
1026 const SwFontScript nActual = rInf.GetFont()->GetActual();
1027
1028 // Kana Compression
1029 if ( SwFontScript::CJK == nActual && rInf.GetKanaComp() &&
1030 pSI && pSI->CountCompChg() &&
1031 lcl_IsMonoSpaceFont( rInf.GetOut() ) )
1032 {
1033 pSI->Compress( aKernArray, rInf.GetIdx(), rInf.GetLen(),
1034 rInf.GetKanaComp(),
1035 o3tl::narrowing<sal_uInt16>(m_aFont.GetFontSize().Height()), lcl_IsFullstopCentered( rInf.GetOut() ), &aTextOriginPos );
1036 bSpecialJust = true;
1037 }
1038
1039 // Asian Justification
1040 if ( SwFontScript::CJK == nActual && nSpaceAdd )
1041 {
1043
1044 if (!MsLangId::isKorean(aLang))
1045 {
1046 SwScriptInfo::CJKJustify( rInf.GetText(), aKernArray,
1047 rInf.GetIdx(), rInf.GetLen(), aLang, nSpaceAdd, rInf.IsSpaceStop() );
1048
1049 bSpecialJust = true;
1050 nSpaceAdd = 0;
1051 }
1052 }
1053
1054 // Kashida Justification
1055 if ( SwFontScript::CTL == nActual && nSpaceAdd )
1056 {
1057 if ( SwScriptInfo::IsArabicText( rInf.GetText(), rInf.GetIdx(), rInf.GetLen() ) )
1058 {
1059 aKashidaArray.resize(aKernArray.size(), false);
1060 if ( pSI && pSI->CountKashida() &&
1061 pSI->KashidaJustify( &aKernArray, aKashidaArray.data(), rInf.GetIdx(),
1062 rInf.GetLen(), nSpaceAdd ) != -1 )
1063 {
1064 bSpecialJust = true;
1065 nSpaceAdd = 0;
1066 }
1067 else
1068 aKashidaArray.clear();
1069 }
1070 }
1071
1072 // Thai Justification
1073 if ( SwFontScript::CTL == nActual && nSpaceAdd )
1074 {
1076
1077 if ( LANGUAGE_THAI == aLang )
1078 {
1079 // Use rInf.GetSpace() because it has more precision than
1080 // nSpaceAdd:
1081 SwScriptInfo::ThaiJustify( rInf.GetText(), &aKernArray,
1082 rInf.GetIdx(), rInf.GetLen(),
1083 rInf.GetNumberOfBlanks(),
1084 rInf.GetSpace() );
1085
1086 // adding space to blanks is already done
1087 bSpecialJust = true;
1088 nSpaceAdd = 0;
1089 }
1090 }
1091 }
1092
1093 tools::Long nKernSum = rInf.GetKern();
1094
1095 if ( bStretch || m_bPaintBlank || rInf.GetKern() || bSpecialJust )
1096 {
1097 for (sal_Int32 i = 0; i < sal_Int32(rInf.GetLen()); i++,
1098 nKernSum += rInf.GetKern() )
1099 {
1100 if (CH_BLANK == rInf.GetText()[sal_Int32(rInf.GetIdx()) + i])
1101 nKernSum += nSpaceAdd;
1102 aKernArray.adjust(i, nKernSum);
1103 }
1104
1105 // In case of underlined/strike-through justified text
1106 // a blank at the end requires special handling:
1107 if( m_bPaintBlank && rInf.GetLen() && ( CH_BLANK ==
1108 rInf.GetText()[sal_Int32(rInf.GetIdx() + rInf.GetLen())-1]))
1109 {
1110 // If it is a single underlined space, output 2 spaces:
1111 if (TextFrameIndex(1) == rInf.GetLen())
1112 {
1113 aKernArray.set(0, rInf.GetWidth() + nSpaceAdd);
1114
1115 rInf.GetOut().DrawTextArray( aTextOriginPos, rInf.GetText(),
1116 aKernArray, aKashidaArray, sal_Int32(rInf.GetIdx()), 1 );
1117 }
1118 else
1119 {
1120 sal_Int32 nIndex(sal_Int32(rInf.GetLen()) - 2);
1121 aKernArray.adjust(nIndex, nSpaceAdd);
1122 rInf.GetOut().DrawTextArray( aTextOriginPos, rInf.GetText(),
1123 aKernArray, aKashidaArray, sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()));
1124 }
1125 }
1126 else
1127 rInf.GetOut().DrawTextArray( aTextOriginPos, rInf.GetText(),
1128 aKernArray, aKashidaArray, sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()));
1129 }
1130 else
1131 {
1132 Point aTmpPos( aTextOriginPos );
1133 sal_Int32 j = 0;
1134 sal_Int32 i;
1135 for( i = 0; i < sal_Int32(rInf.GetLen()); i++ )
1136 {
1137 if (CH_BLANK == rInf.GetText()[sal_Int32(rInf.GetIdx()) + i])
1138 {
1139 nKernSum += nSpaceAdd;
1140 if( j < i )
1141 rInf.GetOut().DrawText( aTmpPos, rInf.GetText(),
1142 sal_Int32(rInf.GetIdx()) + j, i - j);
1143 j = i + 1;
1144 SwTwips nAdd = aKernArray[ i ] + nKernSum;
1146 nAdd *= -1;
1147 aTmpPos.setX( aTextOriginPos.X() + nAdd );
1148 }
1149 }
1150 if( j < i )
1151 rInf.GetOut().DrawText( aTmpPos, rInf.GetText(),
1152 sal_Int32(rInf.GetIdx()) + j, i - j);
1153 }
1154 }
1155 else if( bStretch )
1156 {
1157 tools::Long nTmpWidth = rInf.GetWidth();
1158 if( rInf.GetKern() && rInf.GetLen() && nTmpWidth > rInf.GetKern() )
1159 nTmpWidth -= rInf.GetKern();
1160 rInf.GetOut().DrawStretchText( aTextOriginPos, nTmpWidth,
1161 rInf.GetText(),
1162 sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()));
1163 }
1164 else if( rInf.GetKern() )
1165 {
1166 const tools::Long nTmpWidth = GetTextSize( rInf ).Width();
1167
1168 const Color aSaveColor( pTmpFont->GetColor() );
1169 const bool bColorChanged = rInf.ApplyAutoColor( pTmpFont );
1170
1171 if( bColorChanged )
1172 {
1173 if( !pTmpFont->IsSameInstance( rInf.GetOut().GetFont() ) )
1174 rInf.GetOut().SetFont( *pTmpFont );
1175 pTmpFont->SetColor( aSaveColor );
1176 }
1177
1178 rInf.GetOut().DrawStretchText( aTextOriginPos, nTmpWidth,
1179 rInf.GetText(),
1180 sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()));
1181 }
1182 else
1183 rInf.GetOut().DrawText( aTextOriginPos, rInf.GetText(),
1184 sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()));
1185 }
1186
1187 // PAINTING WITH FORMATTING DEVICE/SCREEN ADJUSTMENT
1188
1189 else
1190 {
1191 OUString aBulletOverlay;
1192 bool bBullet = rInf.GetBullet();
1193 if( m_bSymbol )
1194 bBullet = false;
1195 CreateScrFont( *rInf.GetShell(), rInf.GetOut() );
1196
1197 VclPtr<OutputDevice> xFormattingDevice;
1198
1199 // OLE: no printer available
1200 // OSL_ENSURE( pPrinter, "DrawText needs pPrinter" )
1201 if ( m_pPrinter )
1202 {
1203 // pTmpFont has already been set as current font for rInf.GetOut()
1204 if ( m_pPrinter.get() != rInf.GetpOut() || pTmpFont != m_pPrtFont )
1205 {
1206 if( !m_pPrtFont->IsSameInstance( m_pPrinter->GetFont() ) )
1207 m_pPrinter->SetFont( *m_pPrtFont );
1208 }
1209 xFormattingDevice = m_pPrinter;
1210 }
1211 else
1212 {
1213 xFormattingDevice = &rInf.GetOut();
1214 }
1215
1216 //tdf#152094 see if we can retain a subpixel factor
1217 int nSubPixels = 1;
1218 MapMode aMapMode(xFormattingDevice->GetMapMode());
1219 if (aMapMode.IsSimple() && aMapMode.GetMapUnit() == MapUnit::MapTwip)
1220 {
1221 if (xFormattingDevice->GetDPIX() == xFormattingDevice->GetDPIY())
1222 {
1223 int nRatio = xFormattingDevice->GetDPIX() / 1440;
1224 if (nRatio * 1440 == xFormattingDevice->GetDPIX())
1225 nSubPixels = nRatio;
1226 }
1227 }
1228 KernArray aKernArray(nSubPixels);
1229 GetTextArray(*xFormattingDevice, rInf, aKernArray);
1230
1231 std::vector<sal_Bool> aKashidaArray;
1232
1233 // Modify Printer and ScreenArrays for special justifications
1234
1235 tools::Long nSpaceAdd = rInf.GetSpace() / SPACING_PRECISION_FACTOR;
1236 bool bNoHalfSpace = false;
1237
1238 if ( rInf.GetFont() && rInf.GetLen() )
1239 {
1240 const SwFontScript nActual = rInf.GetFont()->GetActual();
1241 const SwScriptInfo* pSI = rInf.GetScriptInfo();
1242
1243 // Kana Compression
1244 if ( SwFontScript::CJK == nActual && rInf.GetKanaComp() &&
1245 pSI && pSI->CountCompChg() &&
1246 lcl_IsMonoSpaceFont( rInf.GetOut() ) )
1247 {
1248 pSI->Compress( aKernArray, rInf.GetIdx(), rInf.GetLen(),
1249 rInf.GetKanaComp(),
1250 o3tl::narrowing<sal_uInt16>(m_aFont.GetFontSize().Height()), lcl_IsFullstopCentered( rInf.GetOut() ), &aTextOriginPos );
1251 }
1252
1253 // Asian Justification
1254 if ( SwFontScript::CJK == nActual && nSpaceAdd )
1255 {
1257
1258 if (!MsLangId::isKorean(aLang))
1259 {
1260 SwScriptInfo::CJKJustify( rInf.GetText(), aKernArray,
1261 rInf.GetIdx(), rInf.GetLen(), aLang, nSpaceAdd, rInf.IsSpaceStop() );
1262
1263 nSpaceAdd = 0;
1264 }
1265 }
1266
1267 // Kashida Justification
1268 if ( SwFontScript::CTL == nActual && nSpaceAdd )
1269 {
1270 if ( SwScriptInfo::IsArabicText( rInf.GetText(), rInf.GetIdx(), rInf.GetLen() ) )
1271 {
1272 aKashidaArray.resize(aKernArray.size(), false);
1273 if ( pSI && pSI->CountKashida() &&
1274 pSI->KashidaJustify( &aKernArray, aKashidaArray.data(), rInf.GetIdx(),
1275 rInf.GetLen(), nSpaceAdd ) != -1 )
1276 nSpaceAdd = 0;
1277 else
1278 {
1279 aKashidaArray.clear();
1280 bNoHalfSpace = true;
1281 }
1282 }
1283 }
1284
1285 // Thai Justification
1286 if ( SwFontScript::CTL == nActual && nSpaceAdd )
1287 {
1289
1290 if ( LANGUAGE_THAI == aLang )
1291 {
1292 SwScriptInfo::ThaiJustify( rInf.GetText(), &aKernArray,
1293 rInf.GetIdx(),
1294 rInf.GetLen(),
1295 rInf.GetNumberOfBlanks(),
1296 rInf.GetSpace() );
1297
1298 // adding space to blanks is already done
1299 nSpaceAdd = 0;
1300 }
1301 }
1302 }
1303
1304 if( bBullet )
1305 {
1306 // Copy the substring that will be painted, and replace spaces with
1307 // bullets, and everything else with space.
1308 sal_Int32 nCopyStart = sal_Int32(rInf.GetIdx());
1309 sal_Int32 nCopyLen = sal_Int32(rInf.GetLen());
1310
1311 aBulletOverlay = rInf.GetText().copy( nCopyStart, nCopyLen );
1312
1313 for( sal_Int32 i = 0; i < aBulletOverlay.getLength(); ++i )
1314 if( CH_BLANK == aBulletOverlay[ i ] )
1315 {
1316 /* fdo#72488 Hack: try to see if the space is zero width
1317 * and don't bother with inserting a bullet in this case.
1318 */
1319 if ((i + nCopyStart + 1 >= sal_Int32(rInf.GetLen())) ||
1320 aKernArray[i + nCopyStart] != aKernArray[ i + nCopyStart + 1])
1321 {
1322 aBulletOverlay = aBulletOverlay.replaceAt(i, 1, rtl::OUStringChar(CH_BULLET));
1323 }
1324 else
1325 {
1326 aBulletOverlay = aBulletOverlay.replaceAt(i, 1, rtl::OUStringChar(CH_BLANK));
1327 }
1328 }
1329 else
1330 {
1331 aBulletOverlay = aBulletOverlay.replaceAt(i, 1, rtl::OUStringChar(CH_BLANK));
1332 }
1333 }
1334
1335 TextFrameIndex nCnt(rInf.GetText().getLength());
1336 if ( nCnt < rInf.GetIdx() )
1337 assert(false); // layout bug, not handled below
1338 else
1339 nCnt = nCnt - rInf.GetIdx();
1340 nCnt = std::min(nCnt, rInf.GetLen());
1341 sal_Unicode cChPrev = rInf.GetText()[sal_Int32(rInf.GetIdx())];
1342
1343 // In case of a single underlined space in justified text,
1344 // have to output 2 spaces:
1345 if ((nCnt == TextFrameIndex(1)) && rInf.GetSpace() && (cChPrev == CH_BLANK))
1346 {
1347 aKernArray.set(0, rInf.GetWidth() +
1348 rInf.GetKern() +
1350
1351 if ( bSwitchL2R )
1352 rInf.GetFrame()->SwitchLTRtoRTL( aTextOriginPos );
1353
1354 if ( bSwitchH2V )
1355 rInf.GetFrame()->SwitchHorizontalToVertical( aTextOriginPos );
1356
1357 rInf.GetOut().DrawTextArray( aTextOriginPos, rInf.GetText(),
1358 aKernArray, aKashidaArray, sal_Int32(rInf.GetIdx()), 1 );
1359 if( bBullet )
1360 rInf.GetOut().DrawTextArray( aTextOriginPos, rInf.GetText(), aKernArray, {},
1361 sal_Int32(rInf.GetIdx()), 1 );
1362 }
1363 else
1364 {
1366 bNoHalfSpace = true;
1367
1368 sw::Justify::SpaceDistribution(aKernArray, rInf.GetText(), sal_Int32(rInf.GetIdx()),
1369 sal_Int32(nCnt), nSpaceAdd, rInf.GetKern(), bNoHalfSpace);
1370
1371 if( rInf.GetGreyWave() )
1372 {
1373 if( rInf.GetLen() )
1374 {
1375 tools::Long nHght = rInf.GetOut().LogicToPixel(
1376 m_pPrtFont->GetFontSize() ).Height();
1377 if( WRONG_SHOW_MIN < nHght )
1378 {
1379 if ( rInf.GetOut().GetConnectMetaFile() )
1380 rInf.GetOut().Push();
1381
1382 Color aCol( rInf.GetOut().GetLineColor() );
1383 bool bColSave = aCol != gWaveCol;
1384 if ( bColSave )
1385 rInf.GetOut().SetLineColor( gWaveCol );
1386
1387 Point aEnd;
1388 tools::Long nKernVal = aKernArray[sal_Int32(rInf.GetLen()) - 1];
1389
1390 const Degree10 nDir = bBidiPor
1391 ? 1800_deg10
1392 : UnMapDirection(GetFont().GetOrientation(),
1393 bSwitchH2V, bSwitchH2VLRBT);
1394
1395 switch ( nDir.get() )
1396 {
1397 case 0 :
1398 aEnd.setX( rInf.GetPos().X() + nKernVal );
1399 aEnd.setY( rInf.GetPos().Y() );
1400 break;
1401 case 900 :
1402 aEnd.setX( rInf.GetPos().X() );
1403 aEnd.setY( rInf.GetPos().Y() - nKernVal );
1404 break;
1405 case 1800 :
1406 aEnd.setX( rInf.GetPos().X() - nKernVal );
1407 aEnd.setY( rInf.GetPos().Y() );
1408 break;
1409 case 2700 :
1410 aEnd.setX( rInf.GetPos().X() );
1411 aEnd.setY( rInf.GetPos().Y() + nKernVal );
1412 break;
1413 }
1414
1415 Point aCurrPos( rInf.GetPos() );
1416
1417 if ( bSwitchL2R )
1418 {
1419 rInf.GetFrame()->SwitchLTRtoRTL( aCurrPos );
1420 rInf.GetFrame()->SwitchLTRtoRTL( aEnd );
1421 }
1422
1423 if ( bSwitchH2V )
1424 {
1425 rInf.GetFrame()->SwitchHorizontalToVertical( aCurrPos );
1426 rInf.GetFrame()->SwitchHorizontalToVertical( aEnd );
1427 }
1428 {
1429 vcl::ScopedAntialiasing a(rInf.GetOut(), true);
1430 rInf.GetOut().DrawWaveLine( aCurrPos, aEnd );
1431 }
1432 if ( bColSave )
1433 rInf.GetOut().SetLineColor( aCol );
1434
1435 if ( rInf.GetOut().GetConnectMetaFile() )
1436 rInf.GetOut().Pop();
1437 }
1438 }
1439 }
1440 else if( !m_bSymbol && rInf.GetLen() )
1441 {
1442 // anything to do?
1443 if (rInf.GetWrong() || rInf.GetGrammarCheck() || rInf.GetSmartTags())
1444 {
1445 const tools::Long nHalfSpace = bNoHalfSpace ? 0 : nSpaceAdd / 2;
1446 CalcLinePosData aCalcLinePosData(rInf, GetFont(), nCnt, bSwitchH2V,
1447 bSwitchH2VLRBT, bSwitchL2R, nHalfSpace,
1448 aKernArray, bBidiPor);
1449
1450 SwForbidden aForbidden;
1451 // draw line for smart tag data
1452 lcl_DrawLineForWrongListData( aForbidden, rInf, rInf.GetSmartTags(), aCalcLinePosData, Size() );
1453 // draw wave line for spell check errors
1454 // draw them BEFORE the grammar check lines to 'override' the latter in case of conflict.
1455 // reason: some grammar errors can only be found if spelling errors are fixed,
1456 // therefore we don't want the user to miss a spelling error.
1457 lcl_DrawLineForWrongListData( aForbidden, rInf, rInf.GetWrong(), aCalcLinePosData, m_pPrtFont->GetFontSize() );
1458 // draw wave line for grammar check errors
1459 lcl_DrawLineForWrongListData( aForbidden, rInf, rInf.GetGrammarCheck(), aCalcLinePosData, m_pPrtFont->GetFontSize() );
1460 }
1461 }
1462
1463 sal_Int32 nLen = sal_Int32(rInf.GetLen());
1464
1465 if( nLen > 0 )
1466 {
1467
1468 if ( bSwitchL2R )
1469 rInf.GetFrame()->SwitchLTRtoRTL( aTextOriginPos );
1470
1471 if ( bSwitchH2V )
1472 rInf.GetFrame()->SwitchHorizontalToVertical( aTextOriginPos );
1473
1474 sal_Int32 nIdx = sal_Int32(rInf.GetIdx());
1476 rInf.GetText(), nIdx, nLen);
1477 rInf.GetOut().DrawTextArray( aTextOriginPos, rInf.GetText(), aKernArray, aKashidaArray,
1478 nIdx, nLen, SalLayoutFlags::NONE, pGlyphs );
1479 if (bBullet)
1480 {
1481 rInf.GetOut().Push();
1482 Color aPreviousColor = pTmpFont->GetColor();
1483
1484 FontLineStyle aPreviousUnderline = pTmpFont->GetUnderline();
1485 FontLineStyle aPreviousOverline = pTmpFont->GetOverline();
1486 FontStrikeout aPreviousStrikeout = pTmpFont->GetStrikeout();
1487
1489 pTmpFont->SetUnderline(LINESTYLE_NONE);
1490 pTmpFont->SetOverline(LINESTYLE_NONE);
1491 pTmpFont->SetStrikeout(STRIKEOUT_NONE);
1492 rInf.GetOut().SetFont( *pTmpFont );
1493 tools::Long nShift = rInf.GetOut( ).GetFontMetric( ).GetBulletOffset( );
1494 if ( nShift )
1495 {
1496 tools::Long nAdd = 0;
1497
1498 if ( aBulletOverlay[ 0 ] == CH_BULLET )
1499 {
1500 if (bSwitchH2V)
1501 aTextOriginPos.AdjustY(nShift ) ;
1502 else
1503 aTextOriginPos.AdjustX(nShift ) ;
1504 nAdd = nShift ;
1505 }
1506 for( sal_Int32 i = 1 ; i < nLen ; ++i )
1507 {
1508 if ( aBulletOverlay[ i ] == CH_BULLET )
1509 aKernArray.adjust(i - 1, nShift);
1510 if ( nAdd )
1511 aKernArray.adjust(i - 1, -nAdd);
1512 }
1513 }
1514 rInf.GetOut().DrawTextArray( aTextOriginPos, aBulletOverlay, aKernArray,
1515 {}, 0, nLen );
1516 pTmpFont->SetColor( aPreviousColor );
1517
1518 pTmpFont->SetUnderline(aPreviousUnderline);
1519 pTmpFont->SetOverline(aPreviousOverline);
1520 pTmpFont->SetStrikeout(aPreviousStrikeout);
1521 rInf.GetOut().Pop();
1522 }
1523 }
1524 }
1525 }
1526}
1527
1529{
1530 Size aTextSize;
1531 const TextFrameIndex nLn = (TextFrameIndex(COMPLETE_STRING) != rInf.GetLen())
1532 ? rInf.GetLen()
1533 : TextFrameIndex(rInf.GetText().getLength());
1534
1536 ? rInf.GetMeasureLen()
1537 : nLn;
1538
1539 // If the measure length is different from the length, then we are
1540 // measuring substring width for caret positioning, see SetMeasureLength()
1541 // use in TextCursor::GetCharRect_().
1542 bool bCaret(nMsrLn != nLn);
1543
1544 // be sure to have the correct layout mode at the printer
1545 if ( m_pPrinter )
1546 {
1547 m_pPrinter->SetLayoutMode( rInf.GetOut().GetLayoutMode() );
1548 m_pPrinter->SetDigitLanguage( rInf.GetOut().GetDigitLanguage() );
1549 }
1550
1551 if ( rInf.GetFrame() && nLn && rInf.SnapToGrid() && rInf.GetFont() &&
1552 SwFontScript::CJK == rInf.GetFont()->GetActual() )
1553 {
1554 SwTextGridItem const*const pGrid(GetGridItem(rInf.GetFrame()->FindPageFrame()));
1555 if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() )
1556 {
1557 const SwDoc* pDoc = rInf.GetShell()->GetDoc();
1558 const sal_uInt16 nGridWidth = GetGridWidth(*pGrid, *pDoc);
1559
1560 OutputDevice* pOutDev;
1561
1562 if ( m_pPrinter )
1563 {
1564 if( !m_pPrtFont->IsSameInstance( m_pPrinter->GetFont() ) )
1565 m_pPrinter->SetFont(*m_pPrtFont);
1566 pOutDev = m_pPrinter;
1567 }
1568 else
1569 pOutDev = rInf.GetpOut();
1570
1571 aTextSize.setWidth( pOutDev->GetTextWidth(rInf.GetText(),
1572 sal_Int32(rInf.GetIdx()), sal_Int32(nLn)) );
1573
1574 OSL_ENSURE( !rInf.GetShell() ||
1575 ( USHRT_MAX != GetGuessedLeading() && USHRT_MAX != GetExternalLeading() ),
1576 "Leading values should be already calculated" );
1577 aTextSize.setHeight( pOutDev->GetTextHeight() +
1578 GetFontLeading( rInf.GetShell(), rInf.GetOut() ) );
1579
1580 KernArray aKernArray;
1581 GetTextArray(*pOutDev, rInf, aKernArray, sal_Int32(nLn), bCaret);
1582 if (pGrid->IsSnapToChars())
1583 {
1584 sw::Justify::SnapToGrid(aKernArray, rInf.GetText(), sal_Int32(rInf.GetIdx()),
1585 sal_Int32(rInf.GetLen()), nGridWidth, true);
1586 }
1587 else
1588 {
1589 // use 0 to calculate raw width without rInf.GetSpace().
1590 sw::Justify::SnapToGridEdge(aKernArray, sal_Int32(rInf.GetLen()), nGridWidth, 0,
1591 rInf.GetKern());
1592 }
1593
1594 aTextSize.setWidth(aKernArray[sal_Int32(nMsrLn) - 1]);
1595 rInf.SetKanaDiff( 0 );
1596 return aTextSize;
1597 }
1598 }
1599
1600 const bool bCompress = rInf.GetKanaComp() && nLn &&
1601 rInf.GetFont() &&
1602 SwFontScript::CJK == rInf.GetFont()->GetActual() &&
1603 rInf.GetScriptInfo() &&
1604 rInf.GetScriptInfo()->CountCompChg() &&
1605 lcl_IsMonoSpaceFont( rInf.GetOut() );
1606
1607 OSL_ENSURE( !bCompress || ( rInf.GetScriptInfo() && rInf.GetScriptInfo()->
1608 CountCompChg()), "Compression without info" );
1609
1610 // This is the part used e.g., for cursor travelling
1611 // See condition for DrawText or DrawTextArray (bDirectPrint)
1612 KernArray aKernArray;
1613 if ( m_pPrinter && m_pPrinter.get() != rInf.GetpOut() )
1614 {
1615 if( !m_pPrtFont->IsSameInstance( m_pPrinter->GetFont() ) )
1616 m_pPrinter->SetFont(*m_pPrtFont);
1617 aTextSize.setHeight( m_pPrinter->GetTextHeight() );
1618
1619 CreateScrFont( *rInf.GetShell(), rInf.GetOut() );
1620 if( !GetScrFont()->IsSameInstance( rInf.GetOut().GetFont() ) )
1621 rInf.GetOut().SetFont( *m_pScrFont );
1622
1623 GetTextArray(*m_pPrinter, rInf.GetText(), aKernArray,
1624 sal_Int32(rInf.GetIdx()), sal_Int32(nLn), bCaret);
1625 }
1626 else
1627 {
1628 if( !m_pPrtFont->IsSameInstance( rInf.GetOut().GetFont() ) )
1629 rInf.GetOut().SetFont( *m_pPrtFont );
1630 aTextSize.setHeight( rInf.GetOut().GetTextHeight() );
1631
1632 GetTextArray(rInf.GetOut(), rInf, aKernArray, nLn.get(), bCaret);
1633 }
1634
1635 if (bCompress)
1636 {
1637 rInf.SetKanaDiff(rInf.GetScriptInfo()->Compress(aKernArray, rInf.GetIdx(), nLn, rInf.GetKanaComp(),
1638 o3tl::narrowing<sal_uInt16>(m_aFont.GetFontSize().Height()), lcl_IsFullstopCentered(rInf.GetOut())));
1639 }
1640 else
1641 rInf.SetKanaDiff( 0 );
1642
1643 if (nMsrLn)
1644 {
1645 aTextSize.setWidth(aKernArray[sal_Int32(nMsrLn) - 1]);
1646
1647 // Note that we can't simply use sal_Int(nMsrLn) - 1 as nSpaceCount
1648 // because a glyph may be made up of more than one characters.
1649 sal_Int32 nSpaceCount = 0;
1650 tools::Long nOldValue = aKernArray[0];
1651
1652 for(sal_Int32 i = 1; i < sal_Int32(nMsrLn); ++i)
1653 {
1654 if (nOldValue != aKernArray[i])
1655 {
1656 ++nSpaceCount;
1657 nOldValue = aKernArray[i];
1658 }
1659 }
1660
1661 if (rInf.GetKern())
1662 aTextSize.AdjustWidth(nSpaceCount * rInf.GetKern());
1663 }
1664
1665 OSL_ENSURE( !rInf.GetShell() ||
1666 ( USHRT_MAX != GetGuessedLeading() && USHRT_MAX != GetExternalLeading() ),
1667 "Leading values should be already calculated" );
1668 aTextSize.AdjustHeight(GetFontLeading( rInf.GetShell(), rInf.GetOut() ) );
1669 return aTextSize;
1670}
1671
1673{
1674 tools::Long nSpaceAdd = rInf.GetSpace() / SPACING_PRECISION_FACTOR;
1675 const tools::Long nCharacterSpacing = -rInf.GetCharacterSpacing() / SPACING_PRECISION_FACTOR;
1676 tools::Long nKern = rInf.GetKern();
1677
1678 if( 0 != nCharacterSpacing )
1679 nKern -= nCharacterSpacing;
1680
1681 KernArray aKernArray;
1682
1683 // be sure to have the correct layout mode at the printer
1684 if ( m_pPrinter )
1685 {
1686 m_pPrinter->SetLayoutMode( rInf.GetOut().GetLayoutMode() );
1687 m_pPrinter->SetDigitLanguage( rInf.GetOut().GetDigitLanguage() );
1688 GetTextArray(*m_pPrinter, rInf, aKernArray);
1689 }
1690 else
1691 {
1692 GetTextArray(rInf.GetOut(), rInf, aKernArray);
1693 }
1694
1695 if ( rInf.GetFrame() && rInf.GetLen() && rInf.SnapToGrid() &&
1696 rInf.GetFont() && SwFontScript::CJK == rInf.GetFont()->GetActual() )
1697 {
1698 SwTextGridItem const*const pGrid(GetGridItem(rInf.GetFrame()->FindPageFrame()));
1699 if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() )
1700 {
1701 const SwDoc* pDoc = rInf.GetShell()->GetDoc();
1702 const sal_uInt16 nGridWidth = GetGridWidth(*pGrid, *pDoc);
1703
1704 if (pGrid->IsSnapToChars())
1705 {
1706 sw::Justify::SnapToGrid(aKernArray, rInf.GetText(), sal_Int32(rInf.GetIdx()),
1707 sal_Int32(rInf.GetLen()), nGridWidth, true);
1708 }
1709 else
1710 {
1711 sw::Justify::SnapToGridEdge(aKernArray, sal_Int32(rInf.GetLen()), nGridWidth,
1712 nSpaceAdd, rInf.GetKern());
1713 }
1714
1715 return TextFrameIndex(sw::Justify::GetModelPosition(aKernArray, sal_Int32(rInf.GetLen()),
1716 rInf.GetOffset()));
1717 }
1718 }
1719
1720 const SwScriptInfo* pSI = rInf.GetScriptInfo();
1721 if ( rInf.GetFont() && rInf.GetLen() )
1722 {
1723 const SwFontScript nActual = rInf.GetFont()->GetActual();
1724
1725 // Kana Compression
1726 if ( SwFontScript::CJK == nActual && rInf.GetKanaComp() &&
1727 pSI && pSI->CountCompChg() &&
1728 lcl_IsMonoSpaceFont( rInf.GetOut() ) )
1729 {
1730 pSI->Compress( aKernArray, rInf.GetIdx(), rInf.GetLen(),
1731 rInf.GetKanaComp(),
1732 o3tl::narrowing<sal_uInt16>(m_aFont.GetFontSize().Height()),
1733 lcl_IsFullstopCentered( rInf.GetOut() ) );
1734 }
1735
1736 // Asian Justification
1737 if ( SwFontScript::CJK == rInf.GetFont()->GetActual() )
1738 {
1740
1741 if (!MsLangId::isKorean(aLang))
1742 {
1743 SwScriptInfo::CJKJustify( rInf.GetText(), aKernArray,
1744 rInf.GetIdx(), rInf.GetLen(), aLang, nSpaceAdd, rInf.IsSpaceStop() );
1745
1746 nSpaceAdd = 0;
1747 }
1748
1749 }
1750
1751 // Kashida Justification
1752 if ( SwFontScript::CTL == nActual && rInf.GetSpace() )
1753 {
1754 if ( SwScriptInfo::IsArabicText( rInf.GetText(), rInf.GetIdx(), rInf.GetLen() ) )
1755 {
1756 if ( pSI && pSI->CountKashida() &&
1757 pSI->KashidaJustify( &aKernArray, nullptr, rInf.GetIdx(), rInf.GetLen(),
1758 nSpaceAdd ) != -1 )
1759 nSpaceAdd = 0;
1760 }
1761 }
1762
1763 // Thai Justification
1764 if ( SwFontScript::CTL == nActual && nSpaceAdd )
1765 {
1767
1768 if ( LANGUAGE_THAI == aLang )
1769 {
1770 SwScriptInfo::ThaiJustify( rInf.GetText(), &aKernArray,
1771 rInf.GetIdx(), rInf.GetLen(),
1772 rInf.GetNumberOfBlanks(),
1773 rInf.GetSpace() );
1774
1775 // adding space to blanks is already done
1776 nSpaceAdd = 0;
1777 }
1778 }
1779 }
1780
1781 tools::Long nLeft = 0;
1782 tools::Long nRight = 0;
1783 TextFrameIndex nCnt(0);
1784 tools::Long nSpaceSum = 0;
1785 tools::Long nKernSum = 0;
1786
1787 sal_Int32 nDone = 0;
1788 TextFrameIndex nIdx = rInf.GetIdx();
1789 TextFrameIndex nLastIdx = nIdx;
1790 const TextFrameIndex nEnd = rInf.GetIdx() + rInf.GetLen();
1791
1792 // #i105901#
1793 // skip character cells for all script types
1794 LanguageType aLang = rInf.GetFont()->GetLanguage();
1795
1796 while ( ( nRight < tools::Long( rInf.GetOffset() ) ) && ( nIdx < nEnd ) )
1797 {
1798 if (nSpaceAdd && CH_BLANK == rInf.GetText()[ sal_Int32(nIdx)])
1799 nSpaceSum += nSpaceAdd;
1800
1801 // go to next character (cell).
1802 nLastIdx = nIdx;
1803
1804 nIdx = TextFrameIndex(g_pBreakIt->GetBreakIter()->nextCharacters(
1805 rInf.GetText(), sal_Int32(nIdx),
1806 g_pBreakIt->GetLocale( aLang ),
1807 i18n::CharacterIteratorMode::SKIPCELL, 1, nDone));
1808 if ( nIdx <= nLastIdx )
1809 break;
1810
1811 // the next character might be outside the layout range (e.g tdf124116-1.odt)
1812 if (nIdx > nEnd)
1813 nIdx = nEnd;
1814
1815 nLeft = nRight;
1816 nRight = aKernArray[sal_Int32(nIdx - rInf.GetIdx()) - 1] + nKernSum + nSpaceSum;
1817
1818 nKernSum += nKern;
1819 }
1820
1821 // step back if position is before the middle of the character
1822 // or if we do not want to go to the next character
1823 if ( nIdx > rInf.GetIdx() &&
1824 ( rInf.IsPosMatchesBounds() ||
1825 ( ( nRight > tools::Long( rInf.GetOffset() ) ) &&
1826 ( nRight - rInf.GetOffset() > rInf.GetOffset() - nLeft ) ) ) )
1827 nCnt = nLastIdx - rInf.GetIdx(); // first half
1828 else
1829 nCnt = nIdx - rInf.GetIdx(); // second half
1830
1831 if ( pSI )
1832 rInf.SetCursorBidiLevel( pSI->DirType( nLastIdx ) );
1833
1834 return nCnt;
1835}
1836
1837SwFntAccess::SwFntAccess( const void* & rnFontCacheId,
1838 sal_uInt16 &rIndex, const void *pOwn, SwViewShell const *pSh,
1839 bool bCheck ) :
1840 SwCacheAccess( *pFntCache, rnFontCacheId, rIndex ),
1841 m_pShell( pSh )
1842{
1843 // the used ctor of SwCacheAccess searches for rnFontCacheId+rIndex in the cache
1844 if ( m_pObj )
1845 {
1846 // fast case: known Font (rnFontCacheId), no need to check printer and zoom
1847 if ( !bCheck )
1848 return;
1849
1850 // Font is known, but has to be checked
1851 }
1852 else
1853 { // Font not known, must be searched
1854 bCheck = false;
1855 }
1856
1857 {
1858 OutputDevice* pOut = nullptr;
1859 sal_uInt16 nZoom = USHRT_MAX;
1860
1861 // Get the reference device
1862 if ( pSh )
1863 {
1864 pOut = &pSh->GetRefDev();
1865 nZoom = pSh->GetViewOptions()->GetZoom();
1866 }
1867
1868 SwFntObj *pFntObj;
1869 if ( bCheck )
1870 {
1871 pFntObj = Get();
1872 if ( ( pFntObj->GetZoom( ) == nZoom ) &&
1873 ( pFntObj->m_pPrinter == pOut ) &&
1874 pFntObj->GetPropWidth() ==
1875 static_cast<SwSubFont const *>(pOwn)->GetPropWidth() )
1876 {
1877 return; // result of Check: Drucker+Zoom okay.
1878 }
1879 pFntObj->Unlock(); // forget this object, printer/zoom differs
1880 m_pObj = nullptr;
1881 }
1882
1883 // Search by font comparison, quite expensive!
1884 // Look for same font and same printer
1885 pFntObj = pFntCache->First();
1886 while ( pFntObj && !( pFntObj->m_aFont == *static_cast<vcl::Font const *>(pOwn) &&
1887 pFntObj->GetZoom() == nZoom &&
1888 pFntObj->GetPropWidth() ==
1889 static_cast<SwSubFont const *>(pOwn)->GetPropWidth() &&
1890 ( !pFntObj->m_pPrinter || pFntObj->m_pPrinter == pOut ) ) )
1891 pFntObj = SwFntCache::Next( pFntObj );
1892
1893 if( pFntObj && pFntObj->m_pPrinter.get() != pOut )
1894 {
1895 // found one without printer, let's see if there is one with
1896 // the same printer as well
1897 SwFntObj *pTmpObj = pFntObj;
1898 while( pTmpObj && !( pTmpObj->m_aFont == *static_cast<vcl::Font const *>(pOwn) &&
1899 pTmpObj->GetZoom()==nZoom && pTmpObj->m_pPrinter==pOut &&
1900 pTmpObj->GetPropWidth() ==
1901 static_cast<SwSubFont const *>(pOwn)->GetPropWidth() ) )
1902 pTmpObj = SwFntCache::Next( pTmpObj );
1903 if( pTmpObj )
1904 pFntObj = pTmpObj;
1905 }
1906
1907 if ( !pFntObj ) // Font has not been found, create one
1908 {
1909 // Have to create new Object, hence Owner must be a SwFont, later
1910 // the Owner will be the "MagicNumber"
1912 pFntObj = Get(); // will create via NewObj() and lock
1913 OSL_ENSURE(pFntObj, "No Font, no Fun.");
1914 }
1915 else // Font has been found, so we lock it.
1916 {
1917 pFntObj->Lock();
1918 if (pFntObj->m_pPrinter.get() != pOut) // if no printer is known by now
1919 {
1920 OSL_ENSURE( !pFntObj->m_pPrinter, "SwFntAccess: Printer Changed" );
1921 pFntObj->CreatePrtFont( *pOut );
1922 pFntObj->m_pPrinter = pOut;
1923 pFntObj->m_pScrFont = nullptr;
1924 pFntObj->m_nGuessedLeading = USHRT_MAX;
1925 pFntObj->m_nExtLeading = USHRT_MAX;
1926 pFntObj->m_nPrtAscent = USHRT_MAX;
1927 pFntObj->m_nPrtHeight = USHRT_MAX;
1928 }
1929 m_pObj = pFntObj;
1930 }
1931
1932 // no matter if new or found, now the Owner of the Object is a
1933 // MagicNumber, and will be given to the SwFont, as well as the Index
1934 // for later direct access
1935 rnFontCacheId = reinterpret_cast<void*>(reinterpret_cast<sal_IntPtr>(pFntObj->GetOwner()));
1936 SwCacheAccess::m_pOwner = pFntObj->GetOwner();
1937 rIndex = pFntObj->GetCachePos();
1938 }
1939}
1940
1942{
1943 // "MagicNumber" used to identify Fonts
1944 static std::uintptr_t fontCacheIdCounter = 0;
1945 // a new Font, a new "MagicNumber".
1946 return new SwFntObj( *static_cast<SwSubFont const *>(m_pOwner), ++fontCacheIdCounter, m_pShell );
1947}
1948
1950{
1951 ChgFnt( rInf.GetShell(), rInf.GetOut() );
1952
1953 const bool bCompress = rInf.GetKanaComp() && rInf.GetLen() &&
1955 rInf.GetScriptInfo() &&
1956 rInf.GetScriptInfo()->CountCompChg() &&
1957 lcl_IsMonoSpaceFont( rInf.GetOut() );
1958
1959 OSL_ENSURE( !bCompress || ( rInf.GetScriptInfo() && rInf.GetScriptInfo()->
1960 CountCompChg()), "Compression without info" );
1961
1962 TextFrameIndex nTextBreak(0);
1963 tools::Long nKern = 0;
1964
1966 ? TextFrameIndex(rInf.GetText().getLength()) : rInf.GetLen();
1967
1968 if ( rInf.GetFrame() && nLn && rInf.SnapToGrid() &&
1969 rInf.GetFont() && SwFontScript::CJK == rInf.GetFont()->GetActual() )
1970 {
1971 SwTextGridItem const*const pGrid(GetGridItem(rInf.GetFrame()->FindPageFrame()));
1972 if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() )
1973 {
1974 const SwDoc* pDoc = rInf.GetShell()->GetDoc();
1975 const sal_uInt16 nGridWidth = GetGridWidth(*pGrid, *pDoc);
1976
1977 KernArray aKernArray;
1978 GetTextArray( rInf.GetOut(), rInf.GetText(), aKernArray,
1979 sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()));
1980
1981 if (pGrid->IsSnapToChars())
1982 {
1983 sw::Justify::SnapToGrid(aKernArray, rInf.GetText(), sal_Int32(rInf.GetIdx()),
1984 sal_Int32(rInf.GetLen()), nGridWidth, true);
1985 }
1986 else
1987 {
1988 // use 0 to calculate raw width without rInf.GetSpace().
1989 sw::Justify::SnapToGridEdge(aKernArray, sal_Int32(rInf.GetLen()), nGridWidth,
1990 0, rInf.GetKern());
1991 }
1992
1993 while(nTextBreak < rInf.GetLen() && aKernArray[sal_Int32(nTextBreak)] <= nTextWidth)
1994 ++nTextBreak;
1995
1996 return nTextBreak + rInf.GetIdx();
1997 }
1998 }
1999
2000 if( m_aSub[m_nActual].IsCapital() && nLn )
2001 {
2002 nTextBreak = GetCapitalBreak( rInf.GetShell(), rInf.GetpOut(),
2003 rInf.GetScriptInfo(), rInf.GetText(), nTextWidth, rInf.GetIdx(),
2004 nLn );
2005 }
2006 else
2007 {
2008 nKern = CheckKerning();
2009
2010 const OUString* pTmpText;
2011 OUString aTmpText;
2012 TextFrameIndex nTmpIdx;
2013 TextFrameIndex nTmpLen;
2014 bool bTextReplaced = false;
2015
2016 if ( !m_aSub[m_nActual].IsCaseMap() )
2017 {
2018 pTmpText = &rInf.GetText();
2019 nTmpIdx = rInf.GetIdx();
2020 nTmpLen = nLn;
2021 }
2022 else
2023 {
2024 const OUString aSnippet(rInf.GetText().copy(sal_Int32(rInf.GetIdx()), sal_Int32(nLn)));
2025 aTmpText = m_aSub[m_nActual].CalcCaseMap( aSnippet );
2026 const bool bTitle = SvxCaseMap::Capitalize == m_aSub[m_nActual].GetCaseMap();
2027
2028 // Uaaaaahhhh!!! In title case mode, we would get wrong results
2029 if ( bTitle && nLn )
2030 {
2031 // check if rInf.GetIdx() is begin of word
2032 if ( !g_pBreakIt->GetBreakIter()->isBeginWord(
2033 rInf.GetText(), sal_Int32(rInf.GetIdx()),
2034 g_pBreakIt->GetLocale( m_aSub[m_nActual].GetLanguage() ),
2035 i18n::WordType::ANYWORD_IGNOREWHITESPACES ) )
2036 {
2037 // In this case, the beginning of aTmpText is wrong.
2038 OUString aSnippetTmp(aSnippet.copy(0, 1));
2039 aSnippetTmp = m_aSub[m_nActual].CalcCaseMap( aSnippetTmp );
2040 aTmpText = aTmpText.replaceAt( 0, aSnippetTmp.getLength(), rtl::OUStringChar(aSnippet[0]) );
2041 }
2042 }
2043
2044 pTmpText = &aTmpText;
2045 nTmpIdx = TextFrameIndex(0);
2046 nTmpLen = TextFrameIndex(aTmpText.getLength());
2047 bTextReplaced = true;
2048 }
2049
2050 if( rInf.GetHyphPos() ) {
2051 sal_Int32 nHyphPos = sal_Int32(*rInf.GetHyphPos());
2053 &rInf.GetOut(), *pTmpText, nTmpIdx.get(), nTmpLen.get(), 0, rInf.GetVclCache());
2054 nTextBreak = TextFrameIndex(rInf.GetOut().GetTextBreak(
2055 *pTmpText, nTextWidth,
2056 u'-', nHyphPos,
2057 sal_Int32(nTmpIdx), sal_Int32(nTmpLen),
2058 nKern, rInf.GetVclCache(), pGlyphs));
2059 *rInf.GetHyphPos() = TextFrameIndex((nHyphPos == -1) ? COMPLETE_STRING : nHyphPos);
2060 }
2061 else
2062 {
2063 SwFntAccess aFntAccess(m_aSub[m_nActual].m_nFontCacheId, m_aSub[m_nActual].m_nFontIndex,
2064 &m_aSub[m_nActual], rInf.GetShell());
2066 *pTmpText, nTmpIdx.get(), nTmpLen.get(), 0, rInf.GetVclCache());
2067 nTextBreak = TextFrameIndex(rInf.GetOut().GetTextBreak(
2068 *pTmpText, nTextWidth,
2069 sal_Int32(nTmpIdx), sal_Int32(nTmpLen),
2070 nKern, rInf.GetVclCache(), pGlyphs));
2071 }
2072
2073 if (bTextReplaced && sal_Int32(nTextBreak) != -1)
2074 {
2075 if ( nTmpLen != nLn )
2076 nTextBreak = sw_CalcCaseMap( *this, rInf.GetText(),
2077 rInf.GetIdx(), nLn, nTextBreak );
2078 else
2079 nTextBreak = nTextBreak + rInf.GetIdx();
2080 }
2081 }
2082
2083 TextFrameIndex nTextBreak2 = sal_Int32(nTextBreak) == -1
2085 : nTextBreak;
2086
2087 // tdf112290 tdf136588 Break the line correctly only if there is an image inline,
2088 // and the image wider than the line...
2089 if (GetCaseMap() == SvxCaseMap::SmallCaps && TextFrameIndex(COMPLETE_STRING) == nTextBreak2 &&
2090 ! bCompress && nTextWidth == 0)
2091 // If nTextWidth == 0 means the line is full, we have to break it
2092 nTextBreak2 = TextFrameIndex(1);
2093
2094 if ( ! bCompress )
2095 return nTextBreak2;
2096
2097 nTextBreak2 = nTextBreak2 - rInf.GetIdx();
2098
2099 if( nTextBreak2 < nLn )
2100 {
2101 if( !nTextBreak2 && nLn )
2102 nLn = TextFrameIndex(1);
2103 else if (nLn > nTextBreak2 + nTextBreak2)
2104 nLn = nTextBreak2 + nTextBreak2;
2105 KernArray aKernArray;
2106 GetTextArray( rInf.GetOut(), rInf.GetText(), aKernArray,
2107 sal_Int32(rInf.GetIdx()), sal_Int32(nLn));
2108 if( rInf.GetScriptInfo()->Compress( aKernArray, rInf.GetIdx(), nLn,
2109 rInf.GetKanaComp(), o3tl::narrowing<sal_uInt16>(GetHeight( m_nActual )),
2110 lcl_IsFullstopCentered( rInf.GetOut() ) ) )
2111 {
2112 tools::Long nKernAdd = nKern;
2113 TextFrameIndex const nTmpBreak = nTextBreak2;
2114 if( nKern && nTextBreak2 )
2115 nKern *= sal_Int32(nTextBreak2) - 1;
2116 while (nTextBreak2 < nLn && nTextWidth >= aKernArray[sal_Int32(nTextBreak2)] + nKern)
2117 {
2118 nKern += nKernAdd;
2119 ++nTextBreak2;
2120 }
2121 if( rInf.GetHyphPos() )
2122 *rInf.GetHyphPos() += nTextBreak2 - nTmpBreak; // It's not perfect
2123 }
2124 }
2125 nTextBreak2 = nTextBreak2 + rInf.GetIdx();
2126
2127 return nTextBreak2;
2128}
2129
2131{
2132 const vcl::Font& rFnt = pFont ? *pFont : GetOut().GetFont();
2133 Color nNewColor = COL_BLACK;
2134 bool bChgFntColor = false;
2135 bool bChgLineColor = false;
2136
2137 const SwViewShell *pVSh = GetShell();
2138 const bool bOutputToWindow(pVSh && (pVSh->GetWin() || pVSh->isOutputToWindow()));
2139
2140 if (pVSh && !bOutputToWindow && pVSh->GetViewOptions()->IsBlackFont())
2141 {
2142 if ( COL_BLACK != rFnt.GetColor() )
2143 bChgFntColor = true;
2144
2145 if ( (COL_BLACK != GetOut().GetLineColor()) ||
2146 (COL_BLACK != GetOut().GetOverlineColor()) )
2147 bChgLineColor = true;
2148 }
2149 else
2150 {
2151 // FontColor has to be changed if:
2152 // 1. FontColor = AUTO or 2. IsAlwaysAutoColor is set
2153 // LineColor has to be changed if:
2154 // 1. IsAlwaysAutoColor is set
2155
2156 bChgLineColor = pVSh && bOutputToWindow &&
2158
2159 bChgFntColor = COL_AUTO == rFnt.GetColor() || bChgLineColor;
2160
2161 if ( bChgFntColor )
2162 {
2163 // check if current background has a user defined setting
2164 std::optional<Color> pCol;
2165 if (GetFont())
2166 pCol = GetFont()->GetBackColor();
2167 if( ! pCol || COL_TRANSPARENT == *pCol )
2168 {
2169 const SvxBrushItem* pItem;
2170 SwRect aOrigBackRect;
2172
2179 if( GetFrame()->GetBackgroundBrush( aFillAttributes, pItem, pCol, aOrigBackRect, false, /*bConsiderTextBox=*/true ) )
2180 {
2181 if (aFillAttributes && aFillAttributes->isUsed())
2182 {
2183 // First see if fill attributes provide a color.
2184 pCol = Color(aFillAttributes->getAverageColor(aGlobalRetoucheColor.getBColor()));
2185 }
2186
2187 // If not, then fall back to the old brush item.
2188 if ( !pCol )
2189 {
2190 pCol = pItem->GetColor();
2191 }
2192
2195 if ( *pCol == COL_TRANSPARENT)
2196 pCol.reset();
2197 }
2198 else
2199 pCol.reset();
2200 }
2201
2202 // no user defined color at paragraph or font background
2203 if ( ! pCol )
2204 pCol = aGlobalRetoucheColor;
2205
2206 if (pVSh && bOutputToWindow)
2207 {
2208 // here we determine the preferred window text color for painting
2209 const SwViewOption* pViewOption = pVSh->GetViewOptions();
2210 if(pViewOption->IsPagePreview() &&
2212 nNewColor = COL_BLACK;
2213 else
2214 // we take the font color from the appearance page
2215 nNewColor = pViewOption->GetFontColor();
2216 }
2217
2218 // change painting color depending of dark/bright background
2219 Color aTmpColor( nNewColor );
2220 if ( pCol->IsDark() && aTmpColor.IsDark() )
2221 nNewColor = COL_WHITE;
2222 else if ( pCol->IsBright() && aTmpColor.IsBright() )
2223 nNewColor = COL_BLACK;
2224 }
2225 }
2226
2227 if ( bChgFntColor || bChgLineColor )
2228 {
2229 Color aNewColor( nNewColor );
2230
2231 if ( bChgFntColor )
2232 {
2233 if ( pFont && aNewColor != pFont->GetColor() )
2234 {
2235 // only set the new color at the font passed as argument
2236 pFont->SetColor( aNewColor );
2237 }
2238 else if ( aNewColor != GetOut().GetFont().GetColor() )
2239 {
2240 // set new font with new color at output device
2241 vcl::Font aFont( rFnt );
2242 aFont.SetColor( aNewColor );
2243 GetOut().SetFont( aFont );
2244 }
2245 }
2246
2247 // the underline and overline colors have to be set separately
2248 if ( bChgLineColor )
2249 {
2250 // get current font color or color set at output device
2251 aNewColor = pFont ? pFont->GetColor() : GetOut().GetFont().GetColor();
2252 if ( aNewColor != GetOut().GetLineColor() )
2253 GetOut().SetLineColor( aNewColor );
2254 if ( aNewColor != GetOut().GetOverlineColor() )
2255 GetOut().SetOverlineColor( aNewColor );
2256 }
2257
2258 return true;
2259 }
2260
2261 return false;
2262}
2263
2264/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
o3tl::strong_int< sal_Int32, struct Tag_TextFrameIndex > TextFrameIndex
Denotes a character index in a text frame at a layout level, after extent mapping from a text node at...
SwBreakIt * g_pBreakIt
Definition: breakit.cxx:34
static OutputDevice * GetDefaultDevice()
bool IsBright() const
basegfx::BColor getBColor() const
bool IsDark() const
tools::Long GetDescent() const
tools::Long GetHangingBaseline() const
tools::Long GetExternalLeading() const
tools::Long GetBulletOffset() const
tools::Long GetAscent() const
tools::Long GetInternalLeading() const
bool IsFullstopCentered() const
Provides access to settings of a document.
virtual bool get(DocumentSettingId id) const =0
Return the specified document setting.
size_t size() const
void set(size_t nIndex, sal_Int32 nValue)
void adjust(size_t nIndex, sal_Int32 nDiff)
void SetDashCount(sal_uInt16 nDashCount)
void SetDashLen(double nDashLen)
void SetDistance(double nDistance)
const Fraction & GetScaleX() const
MapUnit GetMapUnit() const
bool IsSimple() const
static bool isKorean(LanguageType nLang)
GDIMetaFile * GetConnectMetaFile() const
const vcl::Font & GetFont() const
sal_Int32 GetTextBreak(const OUString &rStr, tools::Long nTextWidth, sal_Int32 nIndex, sal_Int32 nLen=-1, tools::Long nCharExtra=0, vcl::text::TextLayoutCache const *=nullptr, const SalLayoutGlyphs *pGlyphs=nullptr) const
void DrawTextArray(const Point &rStartPt, const OUString &rStr, KernArraySpan aKernArray, o3tl::span< const sal_Bool > pKashidaAry, sal_Int32 nIndex, sal_Int32 nLen, SalLayoutFlags flags=SalLayoutFlags::NONE, const SalLayoutGlyphs *pLayoutCache=nullptr)
void SetFont(const vcl::Font &rNewFont)
void DrawWaveLine(const Point &rStartPos, const Point &rEndPos, tools::Long nLineWidth=1, tools::Long nWaveHeight=3)
SAL_WARN_UNUSED_RESULT Point PixelToLogic(const Point &rDevicePt) const
void DrawLine(const Point &rStartPt, const Point &rEndPt)
void SetLineColor()
void SetMapMode()
tools::Long GetTextWidth(const OUString &rStr, sal_Int32 nIndex=0, sal_Int32 nLen=-1, vcl::text::TextLayoutCache const *=nullptr, SalLayoutGlyphs const *const pLayoutCache=nullptr) const
tools::Long GetTextArray(const OUString &rStr, KernArray *pDXAry, sal_Int32 nIndex=0, sal_Int32 nLen=-1, bool bCaret=false, vcl::text::TextLayoutCache const *=nullptr, SalLayoutGlyphs const *const pLayoutCache=nullptr) const
vcl::text::ComplexTextLayoutFlags GetLayoutMode() const
SAL_WARN_UNUSED_RESULT Point LogicToPixel(const Point &rLogicPt) const
FontMetric GetFontMetric() const
const Color & GetLineColor() const
const MapMode & GetMapMode() const
void Push(vcl::PushFlags nFlags=vcl::PushFlags::ALL)
tools::Long GetTextHeight() const
OutDevType GetOutDevType() const
void DrawText(const Point &rStartPt, const OUString &rStr, sal_Int32 nIndex=0, sal_Int32 nLen=-1, std::vector< tools::Rectangle > *pVector=nullptr, OUString *pDisplayText=nullptr, const SalLayoutGlyphs *pLayoutCache=nullptr)
void SetOverlineColor()
LanguageType GetDigitLanguage() const
void DrawStretchText(const Point &rStartPt, sal_Int32 nWidth, const OUString &rStr, sal_Int32 nIndex=0, sal_Int32 nLen=-1)
virtual bool IsVirtual() const
static SalLayoutGlyphsCache * self()
const SalLayoutGlyphs * GetLayoutGlyphs(VclPtr< const OutputDevice > outputDevice, const OUString &text, const vcl::text::TextLayoutCache *layoutCache=nullptr)
constexpr tools::Long Height() const
tools::Long AdjustHeight(tools::Long n)
void setWidth(tools::Long nWidth)
tools::Long AdjustWidth(tools::Long n)
void setHeight(tools::Long nHeight)
constexpr tools::Long Width() const
const Color & GetColor() const
css::uno::Reference< css::i18n::XBreakIterator > const & GetBreakIter() const
Definition: breakit.hxx:63
const css::lang::Locale & GetLocale(const LanguageType aLang)
Definition: breakit.hxx:68
Access class for the Cache.
Definition: swcache.hxx:198
const void * m_pOwner
Definition: swcache.hxx:205
SwCacheObj * m_pObj
Definition: swcache.hxx:204
The Cache object base class Users of the Cache must derive a class from the SwCacheObj and store thei...
Definition: swcache.hxx:137
void Lock()
Definition: swcache.cxx:471
sal_uInt16 GetCachePos() const
Definition: swcache.hxx:173
const void * GetOwner() const
Definition: swcache.hxx:170
void Unlock()
Definition: swcache.cxx:477
void Flush()
Definition: swcache.cxx:148
Definition: doc.hxx:197
void SetCursorBidiLevel(sal_uInt8 nNew)
Definition: drawfont.hxx:564
bool SnapToGrid() const
Definition: drawfont.hxx:388
bool IsPosMatchesBounds() const
Definition: drawfont.hxx:398
TextFrameIndex GetIdx() const
Definition: drawfont.hxx:269
TextFrameIndex GetLen() const
Definition: drawfont.hxx:274
const OUString & GetText() const
Definition: drawfont.hxx:222
bool GetBullet() const
Definition: drawfont.hxx:357
sw::WrongListIterator * GetSmartTags() const
Definition: drawfont.hxx:243
bool IsSpaceStop() const
Definition: drawfont.hxx:383
sal_uInt16 GetKanaComp() const
Definition: drawfont.hxx:318
TextFrameIndex * GetHyphPos() const
Definition: drawfont.hxx:209
sw::WrongListIterator * GetGrammarCheck() const
Definition: drawfont.hxx:235
SwViewShell const * GetShell() const
Definition: drawfont.hxx:181
tools::Long GetKern() const
Definition: drawfont.hxx:331
sw::WrongListIterator * GetWrong() const
Definition: drawfont.hxx:227
void SetKanaDiff(tools::Long nNew)
Definition: drawfont.hxx:512
tools::Long GetCharacterSpacing() const
Definition: drawfont.hxx:323
const SwScriptInfo * GetScriptInfo() const
Definition: drawfont.hxx:196
vcl::RenderContext & GetOut() const
Definition: drawfont.hxx:186
TextFrameIndex GetMeasureLen() const
Definition: drawfont.hxx:279
bool GetGreyWave() const
Definition: drawfont.hxx:378
SwFont * GetFont() const
Definition: drawfont.hxx:256
bool ApplyAutoColor(vcl::Font *pFnt=nullptr)
Definition: fntcache.cxx:2130
vcl::RenderContext * GetpOut() const
Definition: drawfont.hxx:191
const SwTextFrame * GetFrame() const
Definition: drawfont.hxx:171
void SetLen(TextFrameIndex const nNew)
Definition: drawfont.hxx:492
sal_uInt16 GetWidth() const
Definition: drawfont.hxx:305
const Point & GetPos() const
Definition: drawfont.hxx:201
sal_Int32 GetOffset() const
Definition: drawfont.hxx:284
bool IsIgnoreFrameRTL() const
Definition: drawfont.hxx:393
TextFrameIndex GetNumberOfBlanks() const
Definition: drawfont.hxx:344
tools::Long GetSpace() const
Definition: drawfont.hxx:336
vcl::text::TextLayoutCache const * GetVclCache() const
Definition: drawfont.hxx:217
SwFntObj * Get()
Definition: fntcache.hxx:141
SwFntAccess(const void *&rnFontCacheId, sal_uInt16 &rIndex, const void *pOwner, SwViewShell const *pShell, bool bCheck=false)
Definition: fntcache.cxx:1837
virtual SwCacheObj * NewObj() override
Can be use in NewObj.
Definition: fntcache.cxx:1941
SwViewShell const * m_pShell
Definition: fntcache.hxx:133
static SwFntObj * Next(SwFntObj *pFntObj)
Definition: fntcache.hxx:126
SwFntObj * First()
Definition: fntcache.hxx:121
void Flush()
Definition: fntcache.cxx:76
void GuessLeading(const SwViewShell &rSh, const FontMetric &rMet)
Definition: fntcache.cxx:478
sal_uInt16 m_nPrtHeight
Definition: fntcache.hxx:75
sal_uInt16 m_nPropWidth
Definition: fntcache.hxx:76
sal_uInt16 GetFontHeight(const SwViewShell *pSh, const OutputDevice &rOut)
Definition: fntcache.cxx:297
void CreateScrFont(const SwViewShell &rSh, const OutputDevice &rOut)
Definition: fntcache.cxx:403
sal_uInt16 GetZoom() const
Definition: fntcache.hxx:108
vcl::Font * GetScrFont()
Definition: fntcache.hxx:92
vcl::Font & GetFont()
Definition: fntcache.hxx:93
void SetDevFont(const SwViewShell *pSh, OutputDevice &rOut)
Definition: fntcache.cxx:558
sal_uInt16 m_nExtLeading
Definition: fntcache.hxx:71
TextFrameIndex GetModelPositionForViewPoint(SwDrawTextInfo &rInf)
Definition: fntcache.cxx:1672
void CreatePrtFont(const OutputDevice &rOut)
Definition: fntcache.cxx:119
sal_uInt16 GetExternalLeading() const
Definition: fntcache.hxx:97
sal_uInt16 m_nScrHeight
Definition: fntcache.hxx:74
sal_uInt16 GetFontAscent(const SwViewShell *pSh, const OutputDevice &rOut)
Definition: fntcache.cxx:259
sal_uInt16 GetFontLeading(const SwViewShell *pSh, const OutputDevice &rOut)
Definition: fntcache.cxx:336
virtual ~SwFntObj() override
Definition: fntcache.cxx:111
void DrawText(SwDrawTextInfo &rInf)
Definition: fntcache.cxx:759
VclPtr< OutputDevice > m_pPrinter
Definition: fntcache.hxx:69
bool m_bSymbol
Definition: fntcache.hxx:80
sal_uInt16 GetGuessedLeading() const
Definition: fntcache.hxx:96
sal_uInt16 m_nPrtAscent
Definition: fntcache.hxx:73
sal_uInt16 m_nScrAscent
Definition: fntcache.hxx:72
sal_uInt16 GetPropWidth() const
Definition: fntcache.hxx:109
sal_uInt16 GetFontHangingBaseline(const SwViewShell *pSh, const OutputDevice &rOut)
Definition: fntcache.cxx:387
vcl::Font * m_pPrtFont
Definition: fntcache.hxx:68
sal_uInt16 m_nZoom
Definition: fntcache.hxx:79
static MapMode * s_pPixMap
Definition: fntcache.hxx:84
bool m_bPaintBlank
Definition: fntcache.hxx:81
vcl::Font m_aFont
Definition: fntcache.hxx:66
sal_uInt16 m_nScrHangingBaseline
Definition: fntcache.hxx:77
sal_uInt16 m_nPrtHangingBaseline
Definition: fntcache.hxx:78
SwFntObj(const SwSubFont &rFont, std::uintptr_t nFontCacheId, SwViewShell const *pSh)
Definition: fntcache.cxx:86
Size GetTextSize(SwDrawTextInfo &rInf)
determine the TextSize (of the printer)
Definition: fntcache.cxx:1528
static tools::Long s_nPixWidth
Definition: fntcache.hxx:83
vcl::Font * m_pScrFont
Definition: fntcache.hxx:67
sal_uInt16 m_nGuessedLeading
Definition: fntcache.hxx:70
void ChgFnt(SwViewShell const *pSh, OutputDevice &rOut)
Definition: swfont.hxx:180
const std::optional< Color > & GetBackColor() const
Definition: swfont.hxx:195
SwFontScript m_nActual
Definition: swfont.hxx:168
o3tl::enumarray< SwFontScript, SwSubFont > m_aSub
Definition: swfont.hxx:138
TextFrameIndex GetCapitalBreak(SwViewShell const *pSh, const OutputDevice *pOut, const SwScriptInfo *pScript, const OUString &rText, tools::Long nTextWidth, TextFrameIndex nIdx, TextFrameIndex nLen)
Definition: fntcap.cxx:221
short CheckKerning()
Definition: swfont.hxx:327
SwFontScript GetActual() const
Definition: swfont.hxx:187
TextFrameIndex GetTextBreak(SwDrawTextInfo const &rInf, tools::Long nTextWidth)
Definition: fntcache.cxx:1949
SvxCaseMap GetCaseMap() const
Definition: swfont.hxx:283
LanguageType GetLanguage() const
Definition: swfont.hxx:286
tools::Long GetHeight() const
Definition: swfont.hxx:287
bool IsVertLRBT() const
Definition: frame.hxx:989
bool IsRightToLeft() const
Definition: frame.hxx:993
bool IsVertical() const
Definition: frame.hxx:979
SwPageFrame * FindPageFrame()
Definition: frame.hxx:686
Of course Writer needs its own rectangles.
Definition: swrect.hxx:35
tools::Long Compress(KernArray &rKernArray, TextFrameIndex nIdx, TextFrameIndex nLen, const sal_uInt16 nCompress, const sal_uInt16 nFontHeight, const bool bCentered, Point *pPoint=nullptr) const
Definition: porlay.cxx:2191
sal_Int32 KashidaJustify(KernArray *pKernArray, sal_Bool *pKashidaArray, TextFrameIndex nStt, TextFrameIndex nLen, tools::Long nSpaceAdd=0) const
Performs a kashida justification on the kerning array.
Definition: porlay.cxx:2310
sal_uInt8 DirType(const TextFrameIndex nPos) const
Definition: porlay.cxx:1902
static void CJKJustify(const OUString &rText, KernArray &rKernArray, TextFrameIndex nStt, TextFrameIndex nLen, LanguageType aLang, tools::Long nSpaceAdd, bool bIsSpaceStop)
Definition: porlay.cxx:2934
static TextFrameIndex ThaiJustify(std::u16string_view aText, KernArray *pKernArray, TextFrameIndex nIdx, TextFrameIndex nLen, TextFrameIndex nNumberOfBlanks=TextFrameIndex(0), tools::Long nSpaceAdd=0)
Performs a thai justification on the kerning array.
Definition: porlay.cxx:2572
size_t CountKashida() const
Definition: scriptinfo.hxx:152
static bool IsArabicText(const OUString &rText, TextFrameIndex nStt, TextFrameIndex nLen)
Checks if text is Arabic text.
Definition: porlay.cxx:2398
size_t CountCompChg() const
Definition: scriptinfo.hxx:163
sal_uInt16 GetPropWidth() const
Definition: swfont.hxx:120
void SwitchLTRtoRTL(SwRect &rRect) const
Calculates the coordinates of a rectangle when switching from LTR to RTL layout.
Definition: txtfrm.cxx:683
void SwitchHorizontalToVertical(SwRect &rRect) const
Calculates the coordinates of a rectangle when switching from horizontal to vertical layout.
Definition: txtfrm.cxx:473
SwTextGrid GetGridType() const
Definition: tgrditem.hxx:81
bool IsSnapToChars() const
Definition: tgrditem.hxx:100
bool IsPagePreview() const
Definition: viewopt.hxx:801
const Color & GetFontColor() const
Definition: viewopt.cxx:525
sal_uInt16 GetZoom() const
Definition: viewopt.hxx:671
bool IsPrtFormat() const
Definition: viewopt.hxx:707
bool IsBlackFont() const
Definition: viewopt.hxx:564
bool getBrowseMode() const
Definition: viewopt.hxx:638
const SwViewOption * GetViewOptions() const
Definition: viewsh.hxx:451
bool isOutputToWindow() const
Definition: viewsh.cxx:138
const IDocumentSettingAccess & getIDocumentSettingAccess() const
Provides access to the document setting interface.
Definition: viewsh.cxx:2801
vcl::Window * GetWin() const
Definition: viewsh.hxx:363
SwDoc * GetDoc() const
Definition: viewsh.hxx:307
const SwAccessibilityOptions * GetAccessibilityOptions() const
Definition: viewsh.hxx:459
vcl::RenderContext & GetRefDev() const
Definition: viewsh.cxx:2154
Color mColor
Definition: wrong.hxx:74
WrongAreaLineType mLineType
Definition: wrong.hxx:75
reference_type * get() const
bool Check(TextFrameIndex &rStart, TextFrameIndex &rLen)
Definition: wrong.cxx:673
const SwWrongArea * GetWrongElement(TextFrameIndex nStart)
Definition: wrong.cxx:786
void SetFontSize(const Size &)
bool IsSameInstance(const Font &) const
void SetColor(const Color &)
FontStrikeout GetStrikeout() const
FontLineStyle GetOverline() const
FontItalic GetItalic()
void SetItalic(FontItalic)
void SetWeight(FontWeight)
const OUString & GetFamilyName() const
void SetUnderline(FontLineStyle)
const Size & GetFontSize() const
const Color & GetColor() const
FontWeight GetWeight()
void SetOverline(FontLineStyle)
FontLineStyle GetUnderline() const
rtl_TextEncoding GetCharSet() const
void SetLanguage(LanguageType)
bool IsWordLineMode() const
void SetStrikeout(FontStrikeout)
constexpr ::Color COL_WHITE(0xFF, 0xFF, 0xFF)
constexpr ::Color COL_AUTO(ColorTransparency, 0xFF, 0xFF, 0xFF, 0xFF)
constexpr ::Color COL_BLACK(0x00, 0x00, 0x00)
constexpr ::Color COL_TRANSPARENT(ColorTransparency, 0xFF, 0xFF, 0xFF, 0xFF)
float u
std::vector< std::pair< TextFrameIndex, TextFrameIndex > > SwForbidden
Definition: fntcache.cxx:606
static bool lcl_IsFontAdjustNecessary(const vcl::RenderContext &rOutDev, const vcl::RenderContext &rRefDev)
Definition: fntcache.cxx:153
constexpr Color gWaveCol(COL_GRAY)
static void lcl_calcLinePos(const CalcLinePosData &rData, Point &rStart, Point &rEnd, TextFrameIndex const nStart, TextFrameIndex const nWrLen)
Definition: fntcache.cxx:196
static vcl::DeleteOnDeinit< VclPtr< OutputDevice > > s_pFntObjPixOut
Definition: fntcache.cxx:74
static void lcl_DrawLineForWrongListData(SwForbidden &rForbidden, const SwDrawTextInfo &rInf, sw::WrongListIterator *pWList, const CalcLinePosData &rCalcLinePosData, const Size &rPrtFontSize)
Definition: fntcache.cxx:608
#define WRONG_SHOW_MIN
Definition: fntcache.cxx:582
SwFntObj * pLastFont
Definition: fntcache.cxx:68
static bool lcl_IsFullstopCentered(const vcl::RenderContext &rOut)
Definition: fntcache.cxx:597
static bool lcl_IsMonoSpaceFont(const vcl::RenderContext &rOut)
Definition: fntcache.cxx:590
static void GetTextArray(const OutputDevice &rDevice, const OUString &rStr, KernArray &rDXAry, sal_Int32 nIndex, sal_Int32 nLen, bool bCaret=false, const vcl::text::TextLayoutCache *layoutCache=nullptr)
Definition: fntcache.cxx:735
SwFntCache * pFntCache
Definition: fntcache.cxx:66
TextFrameIndex sw_CalcCaseMap(const SwFont &rFnt, const OUString &rOrigString, TextFrameIndex nOfst, TextFrameIndex nLen, TextFrameIndex nIdx)
Definition: fntcap.cxx:60
UNOTOOLS_DLLPUBLIC bool IsOpenSymbol(std::u16string_view rFontName)
FontLineStyle
LINESTYLE_NONE
FontStrikeout
STRIKEOUT_NONE
Font m_aFont
Shell * m_pShell
sal_Int32 nIndex
uno_Any a
#define LANGUAGE_THAI
std::shared_ptr< SdrAllFillAttributesHelper > SdrAllFillAttributesHelperPtr
Definition: format.hxx:41
int i
constexpr OUStringLiteral first
tools::Long SnapToGrid(KernArray &rKernArray, std::u16string_view aText, sal_Int32 nStt, sal_Int32 nLen, tools::Long nGridWidth, bool bForceLeft)
Snap ideographs to text grids: a) Ideographic open brackets are aligned to the rightmost edge of span...
Definition: justify.cxx:176
void SnapToGridEdge(KernArray &rKernArray, sal_Int32 nLen, tools::Long nGridWidth, tools::Long nSpace, tools::Long nKern)
Snap ideographs to text grids edge ( used when snap to char is off ): space will be distributed ( in ...
Definition: justify.cxx:216
void SpaceDistribution(KernArray &rKernArray, std::u16string_view aText, sal_Int32 nStt, sal_Int32 nLen, tools::Long nSpaceAdd, tools::Long nKern, bool bNoHalfSpace)
Distribute space between words and letters.
Definition: justify.cxx:101
sal_Int32 GetModelPosition(const KernArray &rKernArray, sal_Int32 nLen, tools::Long nX)
Get model position base on given kern array.
Definition: justify.cxx:77
css::uno::Reference< css::linguistic2::XProofreadingIterator > get(css::uno::Reference< css::uno::XComponentContext > const &context)
long Long
Color GetLineColor(Color const &rColor, DrawModeFlags nDrawMode, StyleSettings const &rStyleSettings)
ComplexTextLayoutFlags
SwNodeOffset min(const SwNodeOffset &a, const SwNodeOffset &b)
Definition: nodeoffset.hxx:35
SwNodeOffset abs(const SwNodeOffset &a)
Definition: nodeoffset.hxx:34
OUTDEV_WINDOW
OUTDEV_PRINTER
SwTextGridItem const * GetGridItem(SwPageFrame const *const)
Definition: pagechg.cxx:2659
sal_uInt16 GetGridWidth(SwTextGridItem const &, SwDoc const &)
Definition: pagechg.cxx:2673
Color aGlobalRetoucheColor
Definition: paintfrm.cxx:251
#define SPACING_PRECISION_FACTOR
Definition: scriptinfo.hxx:41
UNDERLYING_TYPE get() const
const sal_Unicode CH_BLANK
Definition: swfont.hxx:42
SwFontScript
Definition: swfont.hxx:124
Degree10 UnMapDirection(Degree10 nDir, const bool bVertFormat, const bool bVertFormatLRBT)
Definition: swfont.cxx:373
const sal_Unicode CH_BULLET
Definition: swfont.hxx:46
tools::Long SwTwips
Definition: swtypes.hxx:51
constexpr sal_Int32 COMPLETE_STRING
Definition: swtypes.hxx:57
@ GRID_LINES_CHARS
Definition: tgrditem.hxx:30
#define NON_PRINTING_CHARACTER_COLOR
Definition: txtfrm.hxx:57
sal_uInt16 sal_Unicode
oslFileHandle & pOut
@ WRONGAREA_BOLDWAVE
Definition: wrong.hxx:51
@ WRONGAREA_WAVE
Definition: wrong.hxx:50
@ WRONGAREA_DASHED
Definition: wrong.hxx:53
@ WRONGAREA_BOLD
Definition: wrong.hxx:52