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 <memory>
21 #include <sal/config.h>
22 
23 #include <cstdlib>
24 
25 #include <i18nlangtag/mslangid.hxx>
26 #include <vcl/outdev.hxx>
27 #include <vcl/print.hxx>
28 #include <vcl/lineinfo.hxx>
29 #include <vcl/metric.hxx>
30 #include <vcl/svapp.hxx>
31 #include <vcl/lazydelete.hxx>
32 #include <com/sun/star/i18n/CharacterIteratorMode.hpp>
33 #include <com/sun/star/i18n/WordType.hpp>
34 #include <com/sun/star/i18n/XBreakIterator.hpp>
35 #include <breakit.hxx>
36 #include <paintfrm.hxx>
37 #include <viewsh.hxx>
38 #include <viewopt.hxx>
39 #include <fntcache.hxx>
41 #include <swfont.hxx>
42 #include <wrong.hxx>
43 #include <dbg_lay.hxx>
44 #include <txtfrm.hxx>
45 #include <pagefrm.hxx>
46 #include <pagedesc.hxx>
47 #include <tgrditem.hxx>
48 #include <scriptinfo.hxx>
49 #include <editeng/brushitem.hxx>
50 #include <swmodule.hxx>
51 #include <accessibilityoptions.hxx>
54 #include <doc.hxx>
55 #include <editeng/fhgtitem.hxx>
56 #include <vcl/glyphitem.hxx>
57 #include <vcl/vcllayout.hxx>
58 #include <docsh.hxx>
59 #include <strings.hrc>
60 #include <fntcap.hxx>
61 
62 using namespace ::com::sun::star;
63 
64 // global variables declared in fntcache.hxx
65 // FontCache is created in txtinit.cxx TextInit_ and deleted in TextFinit
66 SwFntCache *pFntCache = nullptr;
67 // last Font set by ChgFntCache
68 SwFntObj *pLastFont = nullptr;
69 // "MagicNumber" used to identify Fonts
71 
72 static constexpr Color gWaveCol(COL_GRAY);
73 
75 MapMode* SwFntObj::pPixMap = nullptr;
77 
78 namespace
79 {
80 
81 long EvalGridWidthAdd( const SwTextGridItem *const pGrid, const SwDrawTextInfo &rInf )
82 {
83  SwDocShell* pDocShell = rInf.GetShell()->GetDoc()->GetDocShell();
84  SfxStyleSheetBasePool* pBasePool = pDocShell->GetStyleSheetPool();
85 
86  SfxStyleSheetBase* pStyle = pBasePool->Find(SwResId(STR_POOLCOLL_STANDARD), SfxStyleFamily::Para);
87  SfxItemSet& aTmpSet = pStyle->GetItemSet();
88  const SvxFontHeightItem &aDefaultFontItem = aTmpSet.Get(RES_CHRATR_CJK_FONTSIZE);
89 
90  const SwDoc* pDoc = rInf.GetShell()->GetDoc();
91  const sal_uInt16 nGridWidth = GetGridWidth(*pGrid, *pDoc);
92  const sal_uInt32 nFontHeight = aDefaultFontItem.GetHeight();
93  const long nGridWidthAdd = nGridWidth > nFontHeight ? nGridWidth - nFontHeight : 0;
94  if( SwFontScript::Latin == rInf.GetFont()->GetActual() )
95  return nGridWidthAdd / 2;
96 
97  return nGridWidthAdd;
98 }
99 
104 SalLayoutGlyphs* lcl_CreateLayout(const SwTextGlyphsKey& rKey, SalLayoutGlyphs& rTextGlyphs)
105 {
106  // Use pre-calculated result.
107  if (rTextGlyphs.IsValid())
108  return &rTextGlyphs;
109 
110  if (rKey.m_nIndex >= rKey.m_aText.getLength())
111  // Same as in OutputDevice::GetTextArray().
112  return nullptr;
113 
114  // Calculate glyph items.
115  std::unique_ptr<SalLayout> pLayout
116  = rKey.m_pOutputDevice->ImplLayout(rKey.m_aText, rKey.m_nIndex, rKey.m_nLength, Point(0, 0), 0,
117  nullptr, SalLayoutFlags::GlyphItemsOnly);
118  if (!pLayout)
119  return nullptr;
120 
121  const SalLayoutGlyphs* pGlyphs = pLayout->GetGlyphs();
122  if (!pGlyphs)
123  return nullptr;
124 
125  // Remember the calculation result.
126  rTextGlyphs = *pGlyphs;
127 
128  return &rTextGlyphs;
129 }
130 }
131 
132 bool operator<(const SwTextGlyphsKey& l, const SwTextGlyphsKey& r)
133 {
134  if (l.m_pOutputDevice.get() < r.m_pOutputDevice.get())
135  return true;
136  if (l.m_pOutputDevice.get() > r.m_pOutputDevice.get())
137  return false;
138  if (l.m_nIndex < r.m_nIndex)
139  return true;
140  if (l.m_nIndex > r.m_nIndex)
141  return false;
142  if (l.m_nLength < r.m_nLength)
143  return true;
144  if (l.m_nLength > r.m_nLength)
145  return false;
146 
147  // Comparing strings is expensive, so compare them:
148  // - only at the end of this function
149  // - only once
150  // - only the relevant substring (if the index/length is not out of bounds)
151  sal_Int32 nRet = 0;
152  if (l.m_nLength < 0 || l.m_nIndex < 0 || l.m_nIndex + l.m_nLength > l.m_aText.getLength())
153  nRet = l.m_aText.compareTo(r.m_aText);
154  else
155  nRet = memcmp(l.m_aText.getStr() + l.m_nIndex, r.m_aText.getStr() + r.m_nIndex,
156  l.m_nLength * sizeof(sal_Unicode));
157  if (nRet < 0)
158  return true;
159  if (nRet > 0)
160  return false;
161 
162  return false;
163 };
164 
166 {
167  if ( pLastFont )
168  {
169  pLastFont->Unlock();
170  pLastFont = nullptr;
171  }
172  SwCache::Flush( );
173 }
174 
175 SwFntObj::SwFntObj(const SwSubFont &rFont, const void* nFontCacheId, SwViewShell const *pSh)
176  : SwCacheObj(nFontCacheId)
177  , m_aFont(rFont)
178  , m_pScrFont(nullptr)
179  , m_pPrtFont(&m_aFont)
180  , m_pPrinter(nullptr)
181  , m_nGuessedLeading(USHRT_MAX)
182  , m_nExtLeading(USHRT_MAX)
183  , m_nScrAscent(0)
184  , m_nPrtAscent(USHRT_MAX)
185  , m_nScrHeight(0)
186  , m_nPrtHeight(USHRT_MAX)
187  , m_nPropWidth(rFont.GetPropWidth())
188 {
189  m_nZoom = pSh ? pSh->GetViewOptions()->GetZoom() : USHRT_MAX;
190  m_bSymbol = RTL_TEXTENCODING_SYMBOL == m_aFont.GetCharSet();
194  && !m_aFont.IsWordLineMode();
195  m_aFont.SetLanguage(rFont.GetLanguage());
196 }
197 
199 {
200  if ( m_pScrFont != m_pPrtFont )
201  delete m_pScrFont;
202  if ( m_pPrtFont != &m_aFont )
203  delete m_pPrtFont;
204 }
205 
207 {
208  if ( m_nPropWidth == 100 || m_pPrinter == &rPrt )
209  return;
210 
211  if( m_pScrFont != m_pPrtFont )
212  delete m_pScrFont;
213  if( m_pPrtFont != &m_aFont )
214  delete m_pPrtFont;
215 
216  const vcl::Font aOldFnt( rPrt.GetFont() );
217  const_cast<OutputDevice&>(rPrt).SetFont( m_aFont );
218  const FontMetric aWinMet( rPrt.GetFontMetric() );
219  const_cast<OutputDevice&>(rPrt).SetFont( aOldFnt );
220  auto nWidth = ( aWinMet.GetFontSize().Width() * m_nPropWidth ) / 100;
221 
222  if( !nWidth )
223  ++nWidth;
224  m_pPrtFont = new vcl::Font( m_aFont );
226  m_pScrFont = nullptr;
227 
228 }
229 
230 /*
231  * returns whether we have to adjust the output font to resemble
232  * the formatting font
233  *
234  * _Not_ necessary if
235  *
236  * 1. RefDef == OutDev (text formatting, online layout...)
237  * 2. PDF export from online layout
238  * 3. Prospect/PagePreview printing
239  */
240 static bool lcl_IsFontAdjustNecessary( const vcl::RenderContext& rOutDev,
241  const vcl::RenderContext& rRefDev )
242 {
243  return &rRefDev != &rOutDev &&
244  OUTDEV_WINDOW != rRefDev.GetOutDevType() &&
245  ( OUTDEV_PRINTER != rRefDev.GetOutDevType() ||
246  OUTDEV_PRINTER != rOutDev.GetOutDevType() );
247 }
248 
250 {
254  const bool bSwitchH2V;
255  const bool bSwitchH2VLRBT;
256  const bool bSwitchL2R;
257  long const nHalfSpace;
258  long* const pKernArray;
259  const bool bBidiPor;
260 
262  TextFrameIndex const _nCnt, const bool _bSwitchH2V, const bool _bSwitchH2VLRBT, const bool _bSwitchL2R,
263  long _nHalfSpace, long* _pKernArray, const bool _bBidiPor) :
264  rInf( _rInf ),
265  rFont( _rFont ),
266  nCnt( _nCnt ),
267  bSwitchH2V( _bSwitchH2V ),
268  bSwitchH2VLRBT( _bSwitchH2VLRBT ),
269  bSwitchL2R( _bSwitchL2R ),
270  nHalfSpace( _nHalfSpace ),
271  pKernArray( _pKernArray ),
272  bBidiPor( _bBidiPor )
273  {
274  }
275 };
276 
277 // Computes the start and end position of an underline. This function is called
278 // from the DrawText-method (for underlining misspelled words or smarttag terms).
279 static void lcl_calcLinePos( const CalcLinePosData &rData,
280  Point &rStart, Point &rEnd, TextFrameIndex const nStart, TextFrameIndex const nWrLen)
281 {
282  long nBlank = 0;
283  const TextFrameIndex nEnd = nStart + nWrLen;
284  const long nTmpSpaceAdd = rData.rInf.GetSpace() / SPACING_PRECISION_FACTOR;
285 
286  if ( nEnd < rData.nCnt
287  && CH_BLANK == rData.rInf.GetText()[sal_Int32(rData.rInf.GetIdx() + nEnd)] )
288  {
289  if (nEnd + TextFrameIndex(1) == rData.nCnt)
290  nBlank -= nTmpSpaceAdd;
291  else
292  nBlank -= rData.nHalfSpace;
293  }
294 
295  // determine start, end and length of wave line
296  sal_Int32 nKernStart = nStart ? rData.pKernArray[sal_Int32(nStart) - 1] : 0;
297  sal_Int32 nKernEnd = rData.pKernArray[sal_Int32(nEnd) - 1];
298 
299  const sal_uInt16 nDir = rData.bBidiPor ? 1800
301  rData.bSwitchH2V, rData.bSwitchH2VLRBT);
302 
303  switch ( nDir )
304  {
305  case 0 :
306  rStart.AdjustX(nKernStart );
307  rEnd.setX( nBlank + rData.rInf.GetPos().X() + nKernEnd );
308  rEnd.setY( rData.rInf.GetPos().Y() );
309  break;
310  case 900 :
311  rStart.AdjustY( -nKernStart );
312  rEnd.setX( rData.rInf.GetPos().X() );
313  rEnd.setY( nBlank + rData.rInf.GetPos().Y() - nKernEnd );
314  break;
315  case 1800 :
316  rStart.AdjustX( -nKernStart );
317  rEnd.setX( rData.rInf.GetPos().X() - nKernEnd - nBlank );
318  rEnd.setY( rData.rInf.GetPos().Y() );
319  break;
320  case 2700 :
321  rStart.AdjustY(nKernStart );
322  rEnd.setX( rData.rInf.GetPos().X() );
323  rEnd.setY( nBlank + rData.rInf.GetPos().Y() + nKernEnd );
324  break;
325  }
326 
327  if ( rData.bSwitchL2R )
328  {
329  rData.rInf.GetFrame()->SwitchLTRtoRTL( rStart );
330  rData.rInf.GetFrame()->SwitchLTRtoRTL( rEnd );
331  }
332 
333  if ( rData.bSwitchH2V )
334  {
335  rData.rInf.GetFrame()->SwitchHorizontalToVertical( rStart );
336  rData.rInf.GetFrame()->SwitchHorizontalToVertical( rEnd );
337  }
338 }
339 
340 // Returns the Ascent of the Font on the given output device;
341 // it may be necessary to create the screen font first.
342 sal_uInt16 SwFntObj::GetFontAscent( const SwViewShell *pSh, const OutputDevice& rOut )
343 {
344  sal_uInt16 nRet = 0;
345  const OutputDevice& rRefDev = pSh ? pSh->GetRefDev() : rOut;
346 
347  if ( pSh && lcl_IsFontAdjustNecessary( rOut, rRefDev ) )
348  {
349  CreateScrFont( *pSh, rOut );
350  OSL_ENSURE( USHRT_MAX != m_nScrAscent, "nScrAscent is going berzerk" );
351  nRet = m_nScrAscent;
352  }
353  else
354  {
355  if (m_nPrtAscent == USHRT_MAX) // printer ascent unknown?
356  {
357  CreatePrtFont( rOut );
358  const vcl::Font aOldFnt( rRefDev.GetFont() );
359  const_cast<OutputDevice&>(rRefDev).SetFont( *m_pPrtFont );
360  const FontMetric aOutMet( rRefDev.GetFontMetric() );
361  m_nPrtAscent = static_cast<sal_uInt16>(aOutMet.GetAscent());
362  const_cast<OutputDevice&>(rRefDev).SetFont( aOldFnt );
363  }
364 
365  nRet = m_nPrtAscent;
366  }
367 
368 #if !defined(MACOSX) // #i89844# extleading is below the line for Mac
369  // TODO: move extleading below the line for all platforms too
370  nRet += GetFontLeading( pSh, rRefDev );
371 #endif
372 
373  OSL_ENSURE( USHRT_MAX != nRet, "GetFontAscent returned USHRT_MAX" );
374  return nRet;
375 }
376 
377 // Returns the height of the Font on the given output device;
378 // it may be necessary to create the screen font first.
379 sal_uInt16 SwFntObj::GetFontHeight( const SwViewShell* pSh, const OutputDevice& rOut )
380 {
381  sal_uInt16 nRet = 0;
382  const OutputDevice& rRefDev = pSh ? pSh->GetRefDev() : rOut;
383 
384  if ( pSh && lcl_IsFontAdjustNecessary( rOut, rRefDev ) )
385  {
386  CreateScrFont( *pSh, rOut );
387  OSL_ENSURE( USHRT_MAX != m_nScrHeight, "nScrHeight is going berzerk" );
388  nRet = m_nScrHeight + GetFontLeading( pSh, rRefDev );
389  }
390  else
391  {
392  if (m_nPrtHeight == USHRT_MAX) // printer height unknown?
393  {
394  CreatePrtFont( rOut );
395  const vcl::Font aOldFnt( rRefDev.GetFont() );
396  const_cast<OutputDevice&>(rRefDev).SetFont( *m_pPrtFont );
397  m_nPrtHeight = static_cast<sal_uInt16>(rRefDev.GetTextHeight());
398 
399 #if OSL_DEBUG_LEVEL > 0
400  // Check if vcl did not change the meaning of GetTextHeight
401  const FontMetric aOutMet( rRefDev.GetFontMetric() );
402  long nTmpPrtHeight = static_cast<sal_uInt16>(aOutMet.GetAscent()) + aOutMet.GetDescent();
403  // #i106098#: do not compare with == here due to rounding error
404  OSL_ENSURE( std::abs(nTmpPrtHeight - m_nPrtHeight) < 3,
405  "GetTextHeight != Ascent + Descent" );
406 #endif
407 
408  const_cast<OutputDevice&>(rRefDev).SetFont( aOldFnt );
409  }
410 
411  nRet = m_nPrtHeight + GetFontLeading( pSh, rRefDev );
412  }
413 
414  OSL_ENSURE( USHRT_MAX != nRet, "GetFontHeight returned USHRT_MAX" );
415  return nRet;
416 }
417 
418 sal_uInt16 SwFntObj::GetFontLeading( const SwViewShell *pSh, const OutputDevice& rOut )
419 {
420  sal_uInt16 nRet = 0;
421 
422  if ( pSh )
423  {
425  {
426  SolarMutexGuard aGuard;
427 
428  const vcl::Font aOldFnt( rOut.GetFont() );
429  const_cast<OutputDevice&>(rOut).SetFont( *m_pPrtFont );
430  const FontMetric aMet( rOut.GetFontMetric() );
431  const_cast<OutputDevice&>(rOut).SetFont( aOldFnt );
432  m_bSymbol = RTL_TEXTENCODING_SYMBOL == aMet.GetCharSet();
433  GuessLeading( *pSh, aMet );
434  m_nExtLeading = static_cast<sal_uInt16>(aMet.GetExternalLeading());
435  /* HACK: FIXME There is something wrong with Writer's bullet rendering, causing lines
436  with bullets to be higher than they should be. I think this is because
437  Writer uses font's external leading incorrect, as the vertical distance
438  added to every line instead of only a distance between multiple lines,
439  which means a single bullet has external leading added even though it
440  shouldn't, but frankly this is just an educated guess rather than understanding
441  Writer's layout (heh).
442  Symbol font in some documents is 'StarSymbol; Arial Unicode MS', and Windows
443  machines often do not have StarSymbol, falling back to Arial Unicode MS, which
444  has unusually high external leading. So just reset external leading for fonts
445  which are used to bullets, as those should not be used on multiple lines anyway,
446  so in correct rendering external leading should be irrelevant anyway.
447  Interestingly enough, bSymbol is false for 'StarSymbol; Arial Unicode MS', so
448  also check explicitly.
449  */
451  m_nExtLeading = 0;
452  }
453 
455  const bool bBrowse = ( pSh->GetWin() &&
456  pSh->GetViewOptions()->getBrowseMode() &&
457  !pSh->GetViewOptions()->IsPrtFormat() );
458 
459  if ( !bBrowse && rIDSA.get(DocumentSettingId::ADD_EXT_LEADING) )
460  nRet = m_nExtLeading;
461  else
462  nRet = m_nGuessedLeading;
463  }
464 
465  OSL_ENSURE( USHRT_MAX != nRet, "GetFontLeading returned USHRT_MAX" );
466  return nRet;
467 }
468 
469 // pOut is the output device, not the reference device
470 void SwFntObj::CreateScrFont( const SwViewShell& rSh, const OutputDevice& rOut )
471 {
472  if ( m_pScrFont )
473  return;
474 
475  // any changes to the output device are reset at the end of the function
476  OutputDevice* pOut = const_cast<OutputDevice*>(&rOut);
477 
478  // Save old font
479  vcl::Font aOldOutFont( pOut->GetFont() );
480 
482 
483  // Condition for output font / refdev font adjustment
484  OutputDevice* pPrt = &rSh.GetRefDev();
485 
486  if( !rSh.GetWin() ||
487  !rSh.GetViewOptions()->getBrowseMode() ||
488  rSh.GetViewOptions()->IsPrtFormat() )
489  {
490  // After CreatePrtFont m_pPrtFont is the font which is actually used
491  // by the reference device
492  CreatePrtFont( *pPrt );
493  m_pPrinter = pPrt;
494 
495  // save old reference device font
496  vcl::Font aOldPrtFnt( pPrt->GetFont() );
497 
498  // set the font used at the reference device at the reference device
499  // and the output device
500  pPrt->SetFont( *m_pPrtFont );
501  pOut->SetFont( *m_pPrtFont );
502 
503  // This should be the default for pScrFont.
505 
506  FontMetric aMet = pPrt->GetFontMetric( );
507  // Don't lose "faked" properties of the logical font that don't truly
508  // exist in the physical font metrics which vcl which fake up for us
509  aMet.SetWeight(m_pScrFont->GetWeight());
510  aMet.SetItalic(m_pScrFont->GetItalic());
511 
512  m_bSymbol = RTL_TEXTENCODING_SYMBOL == aMet.GetCharSet();
513 
514  if ( USHRT_MAX == m_nGuessedLeading )
515  GuessLeading( rSh, aMet );
516 
517  if ( USHRT_MAX == m_nExtLeading )
518  m_nExtLeading = static_cast<sal_uInt16>(aMet.GetExternalLeading());
519 
520  // reset the original reference device font
521  pPrt->SetFont( aOldPrtFnt );
522  }
523  else
524  {
525  m_bSymbol = RTL_TEXTENCODING_SYMBOL == m_aFont.GetCharSet();
526  if ( m_nGuessedLeading == USHRT_MAX )
527  m_nGuessedLeading = 0;
528 
529  // no external leading in browse mode
530  if ( m_nExtLeading == USHRT_MAX )
531  m_nExtLeading = 0;
532 
534  }
535 
536  // check zoom factor, e.g. because of PrtOle2 during export
537  {
538  // In case the zoom factor of the output device differs from the
539  // one in the ViewOptions, this Font must not be cached,
540  // hence set zoom factor to an invalid value
541  long nTmp;
542  if( pOut->GetMapMode().GetScaleX().IsValid() &&
543  pOut->GetMapMode().GetScaleY().IsValid() &&
544  pOut->GetMapMode().GetScaleX() == pOut->GetMapMode().GetScaleY() )
545  {
546  nTmp = long(100 * pOut->GetMapMode().GetScaleX());
547  }
548  else
549  nTmp = 0;
550  if( nTmp != m_nZoom )
551  m_nZoom = USHRT_MAX - 1;
552  }
553 
554  m_nScrAscent = static_cast<sal_uInt16>(pOut->GetFontMetric().GetAscent());
555  if ( USHRT_MAX == m_nScrHeight )
556  m_nScrHeight = static_cast<sal_uInt16>(pOut->GetTextHeight());
557 
558  // reset original output device font
559  pOut->SetFont( aOldOutFont );
560 }
561 
563 #if defined(_WIN32)
564  rSh
565 #endif
566  , const FontMetric& rMet )
567 {
568  // If leading >= 5, this seems to be enough leading.
569  // Nothing has to be done.
570  if ( rMet.GetInternalLeading() >= 5 )
571  {
572  m_nGuessedLeading = 0;
573  return;
574  }
575 
576 #if defined(_WIN32)
577  OutputDevice *pWin = rSh.GetWin() ?
578  rSh.GetWin() :
580  if ( pWin )
581  {
582  MapMode aTmpMap( MapUnit::MapTwip );
583  MapMode aOldMap = pWin->GetMapMode( );
584  pWin->SetMapMode( aTmpMap );
585  const vcl::Font aOldFnt( pWin->GetFont() );
586  pWin->SetFont( *m_pPrtFont );
587  const FontMetric aWinMet( pWin->GetFontMetric() );
588  const sal_uInt16 nWinHeight = sal_uInt16( aWinMet.GetFontSize().Height() );
589  if( m_pPrtFont->GetFamilyName().indexOf( aWinMet.GetFamilyName() ) != -1 )
590  {
591  // If the Leading on the Window is also 0, then it has to stay
592  // that way (see also StarMath).
593  long nTmpLeading = aWinMet.GetInternalLeading();
594  if( nTmpLeading <= 0 )
595  {
596  pWin->SetFont( rMet );
597  nTmpLeading = pWin->GetFontMetric().GetInternalLeading();
598  if( nTmpLeading < 0 )
599  m_nGuessedLeading = 0;
600  else
601  m_nGuessedLeading = sal_uInt16(nTmpLeading);
602  }
603  else
604  {
605  m_nGuessedLeading = sal_uInt16(nTmpLeading);
606  // Manta-Hack #50153#:
607  // Wer beim Leading luegt, luegt moeglicherweise auch beim
608  // Ascent/Descent, deshalb wird hier ggf. der Font ein wenig
609  // tiefergelegt, ohne dabei seine Hoehe zu aendern.
610  // (above original comment preserved for cultural reasons)
611  // Those who lie about their Leading, may lie about their
612  // Ascent/Descent as well, hence the Font will be lowered a
613  // little without changing its height.
614  long nDiff = std::min( rMet.GetDescent() - aWinMet.GetDescent(),
615  aWinMet.GetAscent() - rMet.GetAscent() - nTmpLeading );
616  if( nDiff > 0 )
617  {
618  OSL_ENSURE( m_nPrtAscent < USHRT_MAX, "GuessLeading: PrtAscent-Fault" );
619  if ( m_nPrtAscent < USHRT_MAX )
620  m_nPrtAscent = m_nPrtAscent + static_cast<sal_uInt16>(( 2 * nDiff ) / 5);
621  }
622  }
623  }
624  else
625  {
626  // If all else fails, take 15% of the height, as empirically
627  // determined by CL
628  m_nGuessedLeading = (nWinHeight * 15) / 100;
629  }
630  pWin->SetFont( aOldFnt );
631  pWin->SetMapMode( aOldMap );
632  }
633  else
634  m_nGuessedLeading = 0;
635 #else
636  m_nGuessedLeading = 0;
637 #endif
638 }
639 
640 // Set the font at the given output device; for screens it may be
641 // necessary to do some adjustment first.
643 {
644  const OutputDevice& rRefDev = pSh ? pSh->GetRefDev() : rOut;
645 
646  if ( pSh && lcl_IsFontAdjustNecessary( rOut, rRefDev ) )
647  {
648  CreateScrFont( *pSh, rOut );
649  if( !GetScrFont()->IsSameInstance( rOut.GetFont() ) )
650  rOut.SetFont( *m_pScrFont );
653  }
654  else
655  {
656  CreatePrtFont( rOut );
657  if( !m_pPrtFont->IsSameInstance( rOut.GetFont() ) )
658  rOut.SetFont( *m_pPrtFont );
659  }
660 
661  // Here, we actually do not need the leading values, but by calling
662  // GetFontLeading() we assure that the values are calculated for later use.
663  GetFontLeading( pSh, rRefDev );
664 }
665 
666 #define WRONG_SHOW_MIN 5
667 
668 /*
669  * Output text:
670  * on screen => DrawTextArray
671  * on printer, !Kerning => DrawText
672  * on printer + Kerning => DrawStretchText
673  */
675 {
676  if ( ( cChar < 0x3001 || cChar > 0x3002 ) &&
677  ( cChar < 0x3008 || cChar > 0x3011 ) &&
678  ( cChar < 0x3014 || cChar > 0x301F ) &&
679  0xFF62 != cChar && 0xFF63 != cChar )
680  // no punctuation
681  return SwScriptInfo::NONE;
682  else if ( 0x3001 == cChar || 0x3002 == cChar ||
683  0x3009 == cChar || 0x300B == cChar ||
684  0x300D == cChar || 0x300F == cChar ||
685  0x3011 == cChar || 0x3015 == cChar ||
686  0x3017 == cChar || 0x3019 == cChar ||
687  0x301B == cChar || 0x301E == cChar ||
688  0x301F == cChar || 0xFF63 == cChar )
689  // right punctuation
691 
693 }
694 
695 static bool lcl_IsMonoSpaceFont( const vcl::RenderContext& rOut )
696 {
697  const long nWidth1 = rOut.GetTextWidth( OUString( u'\x3008' ) );
698  const long nWidth2 = rOut.GetTextWidth( OUString( u'\x307C' ) );
699  return nWidth1 == nWidth2;
700 }
701 
702 static bool lcl_IsFullstopCentered( const vcl::RenderContext& rOut )
703 {
704  const FontMetric aMetric( rOut.GetFontMetric() );
705  return aMetric.IsFullstopCentered() ;
706 }
707 
708 /* This helper structure (SwForbidden) contains the already marked parts of the string
709  to avoid double lines (e.g grammar + spell check error) */
710 
711 typedef std::vector<std::pair<TextFrameIndex, TextFrameIndex>> SwForbidden;
712 
714  SwForbidden &rForbidden,
715  const SwDrawTextInfo &rInf,
716  sw::WrongListIterator *pWList,
717  const CalcLinePosData &rCalcLinePosData,
718  const Size &rPrtFontSize )
719 {
720  if (!pWList) return;
721 
722  TextFrameIndex nStart = rInf.GetIdx();
723  TextFrameIndex nWrLen = rInf.GetLen();
724 
725  // check if respective data is available in the current text range
726  if (!pWList->Check( nStart, nWrLen ))
727  {
728  return;
729  }
730 
731  long nHght = rInf.GetOut().LogicToPixel( rPrtFontSize ).Height();
732 
733  // Draw wavy lines for spell and grammar errors only if font is large enough.
734  // Lines for smart tags will always be drawn.
735  if (pWList != rInf.GetSmartTags() && WRONG_SHOW_MIN >= nHght)
736  {
737  return;
738  }
739 
740  SwForbidden::iterator pIter = rForbidden.begin();
741  if (rInf.GetOut().GetConnectMetaFile())
742  rInf.GetOut().Push();
743 
744  const Color aCol( rInf.GetOut().GetLineColor() );
745 
746  // iterate over all ranges stored in the respective SwWrongList
747  do
748  {
749  nStart -= rInf.GetIdx();
750 
751  const TextFrameIndex nEnd = nStart + nWrLen;
752  TextFrameIndex nNext = nStart;
753  while( nNext < nEnd )
754  {
755  while( pIter != rForbidden.end() && pIter->second <= nNext )
756  ++pIter;
757 
758  const TextFrameIndex nNextStart = nNext;
759  TextFrameIndex nNextEnd = nEnd;
760 
761  if( pIter == rForbidden.end() || nNextEnd <= pIter->first )
762  {
763  // No overlapping mark up found
764  rForbidden.insert(pIter, std::make_pair(nNextStart, nNextEnd));
765  pIter = rForbidden.begin();
766  nNext = nEnd;
767  }
768  else
769  {
770  nNext = pIter->second;
771  if( nNextStart < pIter->first )
772  {
773  nNextEnd = pIter->first;
774  pIter->first = nNextStart;
775  }
776  else
777  continue;
778  }
779  // determine line pos
780  Point aStart( rInf.GetPos() );
781  Point aEnd;
782  lcl_calcLinePos( rCalcLinePosData, aStart, aEnd, nNextStart, nNextEnd - nNextStart );
783 
784  SwWrongArea const*const wrongArea = pWList->GetWrongElement(nNextStart + rInf.GetIdx());
785  if (wrongArea != nullptr)
786  {
787  if (WRONGAREA_DASHED == wrongArea->mLineType)
788  {
789  rInf.GetOut().SetLineColor( wrongArea->mColor );
790 
791  aStart.AdjustY(30 );
792  aEnd.AdjustY(30 );
793 
794  LineInfo aLineInfo( LineStyle::Dash );
795  aLineInfo.SetDistance( 40 );
796  aLineInfo.SetDashLen( 1 );
797  aLineInfo.SetDashCount(1);
798 
799  rInf.GetOut().DrawLine( aStart, aEnd, aLineInfo );
800  }
801  else if (WRONGAREA_WAVE == wrongArea->mLineType)
802  {
803  rInf.GetOut().SetLineColor( wrongArea->mColor );
804 
805  rInf.GetOut().DrawWaveLine( aStart, aEnd );
806  }
807  }
808  }
809 
810  nStart = nEnd + rInf.GetIdx();
811  nWrLen = rInf.GetIdx() + rInf.GetLen() - nStart;
812  }
813  while (nWrLen && pWList->Check( nStart, nWrLen ));
814 
815  rInf.GetOut().SetLineColor( aCol );
816 
817  if (rInf.GetOut().GetConnectMetaFile())
818  rInf.GetOut().Pop();
819 }
820 
822 {
823  OSL_ENSURE( rInf.GetShell(), "SwFntObj::DrawText without shell" );
824 
825  OutputDevice& rRefDev = rInf.GetShell()->GetRefDev();
826  OutputDevice* pWin = rInf.GetShell()->GetWin();
827 
828  // true if pOut is the printer and the printer has been used for formatting
829  const bool bPrt = OUTDEV_PRINTER == rInf.GetOut().GetOutDevType() &&
830  OUTDEV_PRINTER == rRefDev.GetOutDevType();
831  const bool bBrowse = ( pWin &&
832  rInf.GetShell()->GetViewOptions()->getBrowseMode() &&
833  !rInf.GetShell()->GetViewOptions()->IsPrtFormat() &&
834  !rInf.GetBullet() &&
835  ( rInf.GetSpace() || !rInf.GetKern() ) &&
836  !rInf.GetWrong() &&
837  !rInf.GetGrammarCheck() &&
838  !rInf.GetSmartTags() &&
839  !rInf.GetGreyWave() );
840 
841  // bDirectPrint indicates that we can enter the branch which calls
842  // the DrawText functions instead of calling the DrawTextArray functions
843  const bool bDirectPrint = bPrt || bBrowse;
844 
845  // Condition for output font / refdev font adjustment
846  const bool bUseScrFont =
847  lcl_IsFontAdjustNecessary( rInf.GetOut(), rRefDev );
848 
849  vcl::Font* pTmpFont = bUseScrFont ? m_pScrFont : m_pPrtFont;
850 
851  // bDirectPrint and bUseScrFont should have these values:
852 
853  // Outdev / RefDef | Printer | VirtPrinter | Window
854 
855  // Printer | 1 - 0 | 0 - 1 | -
856 
857  // VirtPrinter/PDF | 0 - 1 | 0 - 1 | -
858 
859  // Window/VirtWindow| 0 - 1 | 0 - 1 | 1 - 0
860 
861  // Exception: During painting of a Writer OLE object, we do not have
862  // a window. Therefore bUseSrcFont is always 0 in this case.
863 
864 #if OSL_DEBUG_LEVEL > 0
865 
866  const bool bNoAdjust = bPrt ||
867  ( pWin &&
868  rInf.GetShell()->GetViewOptions()->getBrowseMode() &&
869  !rInf.GetShell()->GetViewOptions()->IsPrtFormat() );
870 
871  if ( OUTDEV_PRINTER == rInf.GetOut().GetOutDevType() )
872  {
873  // Printer output
874  if ( OUTDEV_PRINTER == rRefDev.GetOutDevType() )
875  {
876  OSL_ENSURE( bNoAdjust && !bUseScrFont, "Outdev Check failed" );
877  }
878  else if ( rRefDev.IsVirtual() )
879  {
880  OSL_ENSURE( !bNoAdjust && bUseScrFont, "Outdev Check failed" );
881  }
882  else
883  {
884  OSL_FAIL( "Outdev Check failed" );
885  }
886  }
887  else if ( rInf.GetOut().IsVirtual() && ! pWin )
888  {
889  // PDF export
890  if ( OUTDEV_PRINTER == rRefDev.GetOutDevType() )
891  {
892  OSL_ENSURE( !bNoAdjust && bUseScrFont, "Outdev Check failed" );
893  }
894  else if ( rRefDev.IsVirtual() )
895  {
896  OSL_ENSURE( !bNoAdjust && bUseScrFont, "Outdev Check failed" );
897  }
898  else
899  {
900  OSL_FAIL( "Outdev Check failed" );
901  }
902  }
903  else if ( OUTDEV_WINDOW == rInf.GetOut().GetOutDevType() ||
904  ( rInf.GetOut().IsVirtual() && pWin ) )
905  {
906  // Window or virtual window
907  if ( OUTDEV_PRINTER == rRefDev.GetOutDevType() )
908  {
909  OSL_ENSURE( !bNoAdjust && bUseScrFont, "Outdev Check failed" );
910  }
911  else if ( rRefDev.IsVirtual() )
912  {
913  OSL_ENSURE( !bNoAdjust && bUseScrFont, "Outdev Check failed" );
914  }
915  else if ( OUTDEV_WINDOW == rRefDev.GetOutDevType() )
916  {
917  OSL_ENSURE( bNoAdjust && !bUseScrFont, "Outdev Check failed" );
918  }
919  else
920  {
921  OSL_FAIL( "Outdev Check failed" );
922  }
923  }
924  else
925  {
926  OSL_FAIL( "Outdev Check failed" );
927  }
928 
929 #endif
930 
931  // robust: better use the printer font instead of using no font at all
932  OSL_ENSURE( pTmpFont, "No screen or printer font?" );
933  if ( ! pTmpFont )
934  pTmpFont = m_pPrtFont;
935 
936  // HACK: LINESTYLE_WAVE must not be abused any more, hence the grey wave
937  // line of the ExtendedAttributeSets will appear in the font color first
938 
939  const bool bSwitchH2V = rInf.GetFrame() && rInf.GetFrame()->IsVertical();
940  const bool bSwitchH2VLRBT = rInf.GetFrame() && rInf.GetFrame()->IsVertLRBT();
941  const bool bSwitchL2R = rInf.GetFrame() && rInf.GetFrame()->IsRightToLeft() &&
942  ! rInf.IsIgnoreFrameRTL();
943  const ComplexTextLayoutFlags nMode = rInf.GetOut().GetLayoutMode();
944  const bool bBidiPor = ( bSwitchL2R !=
945  ( ComplexTextLayoutFlags::Default != ( ComplexTextLayoutFlags::BiDiRtl & nMode ) ) );
946 
947  // be sure to have the correct layout mode at the printer
948  if ( m_pPrinter )
949  {
952  }
953 
954  Point aTextOriginPos( rInf.GetPos() );
955  if( !bPrt )
956  {
957  if( rInf.GetpOut() != *s_pFntObjPixOut.get() || rInf.GetOut().GetMapMode() != *pPixMap )
958  {
959  *pPixMap = rInf.GetOut().GetMapMode();
960  (*s_pFntObjPixOut.get()) = rInf.GetpOut();
961  Size aTmp( 1, 1 );
962  nPixWidth = rInf.GetOut().PixelToLogic( aTmp ).Width();
963  }
964 
965  aTextOriginPos.AdjustX(rInf.GetFrame()->IsRightToLeft() ? 0 : nPixWidth );
966  }
967 
968  Color aOldColor( pTmpFont->GetColor() );
969  bool bChgColor = rInf.ApplyAutoColor( pTmpFont );
970  if( !pTmpFont->IsSameInstance( rInf.GetOut().GetFont() ) )
971  rInf.GetOut().SetFont( *pTmpFont );
972  if ( bChgColor )
973  pTmpFont->SetColor( aOldColor );
974 
975  if (TextFrameIndex(COMPLETE_STRING) == rInf.GetLen())
976  rInf.SetLen( TextFrameIndex(rInf.GetText().getLength()) );
977 
978  // ASIAN LINE AND CHARACTER GRID MODE START
979 
980  if ( rInf.GetFrame() && rInf.SnapToGrid() && rInf.GetFont() &&
981  SwFontScript::CJK == rInf.GetFont()->GetActual() )
982  {
983  SwTextGridItem const*const pGrid(GetGridItem(rInf.GetFrame()->FindPageFrame()));
984 
985  // ASIAN LINE AND CHARACTER GRID MODE: Do we want to snap asian characters to the grid?
986  if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && pGrid->IsSnapToChars())
987  {
988  //for textgrid refactor
989  //const sal_uInt16 nGridWidth = pGrid->GetBaseHeight();
990  const SwDoc* pDoc = rInf.GetShell()->GetDoc();
991  const sal_uInt16 nGridWidth = GetGridWidth(*pGrid, *pDoc);
992 
993  // kerning array - gives the absolute position of end of each character
994  std::unique_ptr<long[]> pKernArray(new long[sal_Int32(rInf.GetLen())]);
995 
996  if ( m_pPrinter )
997  m_pPrinter->GetTextArray( rInf.GetText(), pKernArray.get(),
998  sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()));
999  else
1000  rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray.get(),
1001  sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()));
1002 
1003  // Change the average width per character to an appropriate grid width
1004  // basically get the ratio of the avg width to the grid unit width, then
1005  // multiple this ratio to give the new avg width - which in this case
1006  // gives a new grid width unit size
1007 
1008  long nAvgWidthPerChar = pKernArray[sal_Int32(rInf.GetLen()) - 1] / sal_Int32(rInf.GetLen());
1009 
1010  const sal_uLong nRatioAvgWidthCharToGridWidth = nAvgWidthPerChar ?
1011  ( nAvgWidthPerChar - 1 ) / nGridWidth + 1:
1012  1;
1013 
1014  nAvgWidthPerChar = nRatioAvgWidthCharToGridWidth * nGridWidth;
1015 
1016  // the absolute end position of the first character is also its width
1017  long nCharWidth = pKernArray[ 0 ];
1018  sal_uLong nHalfWidth = nAvgWidthPerChar / 2;
1019 
1020  long nNextFix=0;
1021 
1022  // we work out the start position (origin) of the first character,
1023  // and we set the next "fix" offset to half the width of the char.
1024  // The exceptions are for punctuation characters that are not centered
1025  // so in these cases we just add half a regular "average" character width
1026  // to the first characters actual width to allow the next character to
1027  // be centred automatically
1028  // If the character is "special right", then the offset is correct already
1029  // so the fix offset is as normal - half the average character width
1030 
1031  sal_Unicode cChar = rInf.GetText()[ sal_Int32(rInf.GetIdx()) ];
1033  switch ( nType )
1034  {
1035  // centre character
1036  case SwScriptInfo::NONE :
1037  aTextOriginPos.AdjustX(( nAvgWidthPerChar - nCharWidth ) / 2 );
1038  nNextFix = nCharWidth / 2;
1039  break;
1041  nNextFix = nHalfWidth;
1042  break;
1043  // punctuation
1044  default:
1045  aTextOriginPos.AdjustX(nAvgWidthPerChar - nCharWidth );
1046  nNextFix = nCharWidth - nHalfWidth;
1047  }
1048 
1049  // calculate offsets
1050  for (sal_Int32 j = 1; j < sal_Int32(rInf.GetLen()); ++j)
1051  {
1052  long nCurrentCharWidth = pKernArray[ j ] - pKernArray[ j - 1 ];
1053  nNextFix += nAvgWidthPerChar;
1054 
1055  // almost the same as getting the offset for the first character:
1056  // punctuation characters are not centered, so just add half an
1057  // average character width minus the characters actual char width
1058  // to get the offset into the centre of the next character
1059 
1060  cChar = rInf.GetText()[ sal_Int32(rInf.GetIdx()) + j ];
1061  nType = lcl_WhichPunctuation( cChar );
1062  switch ( nType )
1063  {
1064  case SwScriptInfo::NONE :
1065  pKernArray[ j - 1 ] = nNextFix - ( nCurrentCharWidth / 2 );
1066  break;
1068  pKernArray[ j - 1 ] = nNextFix - nHalfWidth;
1069  break;
1070  default:
1071  pKernArray[ j - 1 ] = nNextFix + nHalfWidth - nCurrentCharWidth;
1072  }
1073  }
1074 
1075  // the layout engine requires the total width of the output
1076  pKernArray[sal_Int32(rInf.GetLen()) - 1] = rInf.GetWidth() -
1077  aTextOriginPos.X() + rInf.GetPos().X() ;
1078 
1079  if ( bSwitchH2V )
1080  rInf.GetFrame()->SwitchHorizontalToVertical( aTextOriginPos );
1081 
1082  rInf.GetOut().DrawTextArray( aTextOriginPos, rInf.GetText(),
1083  pKernArray.get(), sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()));
1084 
1085  return;
1086  }
1087  }
1088 
1089  // For text grid refactor
1090  // ASIAN LINE AND CHARACTER GRID MODE START: not snap to characters
1091 
1092  if ( rInf.GetFrame() && rInf.SnapToGrid() )
1093  {
1094  SwTextGridItem const*const pGrid(GetGridItem(rInf.GetFrame()->FindPageFrame()));
1095 
1096  // ASIAN LINE AND CHARACTER GRID MODE - do not snap to characters
1097  if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && !pGrid->IsSnapToChars() )
1098  {
1099  const long nGridWidthAdd = EvalGridWidthAdd( pGrid, rInf );
1100 
1101  std::unique_ptr<long[]> pKernArray(new long[sal_Int32(rInf.GetLen())]);
1102 
1103  if ( m_pPrinter )
1104  m_pPrinter->GetTextArray( rInf.GetText(), pKernArray.get(),
1105  sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()));
1106  else
1107  rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray.get(),
1108  sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()));
1109  if ( bSwitchH2V )
1110  rInf.GetFrame()->SwitchHorizontalToVertical( aTextOriginPos );
1111  if ( rInf.GetSpace() || rInf.GetKanaComp())
1112  {
1113  long nSpaceAdd = rInf.GetSpace() / SPACING_PRECISION_FACTOR;
1114  if ( rInf.GetFont() && rInf.GetLen() )
1115  {
1116  bool bSpecialJust = false;
1117  const SwScriptInfo* pSI = rInf.GetScriptInfo();
1118  const SwFontScript nActual = rInf.GetFont()->GetActual();
1120  if( SwFontScript::CJK == nActual && rInf.GetKanaComp() &&
1121  pSI && pSI->CountCompChg() &&
1122  lcl_IsMonoSpaceFont( *(rInf.GetpOut()) ) )
1123  {
1124  pSI->Compress( pKernArray.get(), rInf.GetIdx(), rInf.GetLen(),
1125  rInf.GetKanaComp(), static_cast<sal_uInt16>(m_aFont.GetFontSize().Height()), lcl_IsFullstopCentered( rInf.GetOut() ) , &aTextOriginPos );
1126  bSpecialJust = true;
1127  }
1129  if ( ( SwFontScript::CJK == nActual || SwFontScript::Latin == nActual ) && nSpaceAdd )
1130  {
1132  if (!MsLangId::isKorean(aLang))
1133  {
1134  long nSpaceSum = nSpaceAdd;
1135  for (sal_Int32 nI = 0; nI < sal_Int32(rInf.GetLen()); ++nI)
1136  {
1137  pKernArray[ nI ] += nSpaceSum;
1138  nSpaceSum += nSpaceAdd;
1139  }
1140  bSpecialJust = true;
1141  nSpaceAdd = 0;
1142  }
1143  }
1144  long nGridAddSum = nGridWidthAdd;
1145  for (sal_Int32 i = 0; i < sal_Int32(rInf.GetLen()); i++, nGridAddSum += nGridWidthAdd )
1146  {
1147  pKernArray[i] += nGridAddSum;
1148  }
1149  long nKernSum = rInf.GetKern();
1150  if ( bSpecialJust || rInf.GetKern() )
1151  {
1152  for (sal_Int32 i = 0; i < sal_Int32(rInf.GetLen()); i++, nKernSum += rInf.GetKern())
1153  {
1154  if (CH_BLANK == rInf.GetText()[sal_Int32(rInf.GetIdx())+i])
1155  nKernSum += nSpaceAdd;
1156  pKernArray[i] += nKernSum;
1157  }
1160  if( m_bPaintBlank && rInf.GetLen() && (CH_BLANK ==
1161  rInf.GetText()[sal_Int32(rInf.GetIdx() + rInf.GetLen()) - 1]))
1162  {
1165  if (TextFrameIndex(1) == rInf.GetLen())
1166  {
1167  pKernArray[0] = rInf.GetWidth() + nSpaceAdd;
1168  rInf.GetOut().DrawTextArray( aTextOriginPos, rInf.GetText(),
1169  pKernArray.get(), sal_Int32(rInf.GetIdx()), 1);
1170  }
1171  else
1172  {
1173  pKernArray[sal_Int32(rInf.GetLen()) - 2] += nSpaceAdd;
1174  rInf.GetOut().DrawTextArray( aTextOriginPos, rInf.GetText(),
1175  pKernArray.get(), sal_Int32(rInf.GetIdx()),
1176  sal_Int32(rInf.GetLen()));
1177  }
1178  }
1179  else
1180  {
1181  rInf.GetOut().DrawTextArray( aTextOriginPos, rInf.GetText(),
1182  pKernArray.get(), sal_Int32(rInf.GetIdx()),
1183  sal_Int32(rInf.GetLen()));
1184  }
1185  }
1186  else
1187  {
1188  Point aTmpPos( aTextOriginPos );
1189  sal_Int32 i;
1190  sal_Int32 j = 0;
1191  long nSpaceSum = 0;
1192  for (i = 0; i < sal_Int32(rInf.GetLen()); i++ )
1193  {
1194  if( CH_BLANK == rInf.GetText()[ sal_Int32(rInf.GetIdx()) + i ] )
1195  {
1196  nSpaceSum += nSpaceAdd;
1197  if( j < i)
1198  rInf.GetOut().DrawTextArray( aTmpPos, rInf.GetText(),
1199  pKernArray.get() + j,
1200  sal_Int32(rInf.GetIdx()) + j, i - j );
1201  j = i + 1;
1202  pKernArray[i] = pKernArray[i] + nSpaceSum;
1203  aTmpPos.setX( aTextOriginPos.X() + pKernArray[ i ] + nKernSum );
1204  }
1205  }
1206  if( j < i )
1207  rInf.GetOut().DrawTextArray( aTmpPos, rInf.GetText(),
1208  pKernArray.get() + j,
1209  sal_Int32(rInf.GetIdx()) + j, i - j );
1210  }
1211  }
1212  }
1213  else
1214  {
1215  //long nKernAdd = rInf.GetKern();
1216  long nKernAdd = 0;
1217  long nGridAddSum = nGridWidthAdd + nKernAdd;
1218  for (sal_Int32 i = 0; i < sal_Int32(rInf.GetLen());
1219  i++, nGridAddSum += nGridWidthAdd + nKernAdd)
1220  {
1221  pKernArray[i] += nGridAddSum;
1222  }
1223  rInf.GetOut().DrawTextArray( aTextOriginPos, rInf.GetText(),
1224  pKernArray.get(), sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()));
1225  }
1226  return;
1227  }
1228  }
1229 
1230  // DIRECT PAINTING WITHOUT SCREEN ADJUSTMENT
1231 
1232  if ( bDirectPrint )
1233  {
1234  const Fraction aTmp( 1, 1 );
1235  bool bStretch = rInf.GetWidth() && (rInf.GetLen() > TextFrameIndex(1)) && bPrt
1236  && ( aTmp != rInf.GetOut().GetMapMode().GetScaleX() );
1237 
1238  if ( bSwitchL2R )
1239  rInf.GetFrame()->SwitchLTRtoRTL( aTextOriginPos );
1240 
1241  if ( bSwitchH2V )
1242  rInf.GetFrame()->SwitchHorizontalToVertical( aTextOriginPos );
1243 
1244  // In the good old days we used to have a simple DrawText if the
1245  // output device is the printer. Now we need a DrawTextArray if
1246  // 1. KanaCompression is enabled
1247  // 2. Justified alignment
1248  // Simple kerning is handled by DrawStretchText
1249  if( rInf.GetSpace() || rInf.GetKanaComp() )
1250  {
1251  std::unique_ptr<long[]> pKernArray(new long[sal_Int32(rInf.GetLen())]);
1252  rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray.get(),
1253  sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()));
1254 
1255  if( bStretch )
1256  {
1257  sal_Int32 nZwi = sal_Int32(rInf.GetLen()) - 1;
1258  long nDiff = rInf.GetWidth() - pKernArray[ nZwi ]
1259  - sal_Int32(rInf.GetLen()) * rInf.GetKern();
1260  long nRest = nDiff % nZwi;
1261  long nAdd;
1262  if( nRest < 0 )
1263  {
1264  nAdd = -1;
1265  nRest += nZwi;
1266  }
1267  else
1268  {
1269  nAdd = +1;
1270  nRest = nZwi - nRest;
1271  }
1272  nDiff /= nZwi;
1273  long nSum = nDiff;
1274  for( sal_Int32 i = 0; i < nZwi; )
1275  {
1276  pKernArray[ i ] += nSum;
1277  if( ++i == nRest )
1278  nDiff += nAdd;
1279  nSum += nDiff;
1280  }
1281  }
1282 
1283  // Modify Array for special justifications
1284 
1285  long nSpaceAdd = rInf.GetSpace() / SPACING_PRECISION_FACTOR;
1286  bool bSpecialJust = false;
1287 
1288  if ( rInf.GetFont() && rInf.GetLen() )
1289  {
1290  const SwScriptInfo* pSI = rInf.GetScriptInfo();
1291  const SwFontScript nActual = rInf.GetFont()->GetActual();
1292 
1293  // Kana Compression
1294  if ( SwFontScript::CJK == nActual && rInf.GetKanaComp() &&
1295  pSI && pSI->CountCompChg() &&
1296  lcl_IsMonoSpaceFont( rInf.GetOut() ) )
1297  {
1298  pSI->Compress( pKernArray.get(), rInf.GetIdx(), rInf.GetLen(),
1299  rInf.GetKanaComp(),
1300  static_cast<sal_uInt16>(m_aFont.GetFontSize().Height()), lcl_IsFullstopCentered( rInf.GetOut() ), &aTextOriginPos );
1301  bSpecialJust = true;
1302  }
1303 
1304  // Asian Justification
1305  if ( SwFontScript::CJK == nActual && nSpaceAdd )
1306  {
1308 
1309  if (!MsLangId::isKorean(aLang))
1310  {
1311  SwScriptInfo::CJKJustify( rInf.GetText(), pKernArray.get(), nullptr,
1312  rInf.GetIdx(), rInf.GetLen(), aLang, nSpaceAdd, rInf.IsSpaceStop() );
1313 
1314  bSpecialJust = true;
1315  nSpaceAdd = 0;
1316  }
1317  }
1318 
1319  // Kashida Justification
1320  if ( SwFontScript::CTL == nActual && nSpaceAdd )
1321  {
1322  if ( SwScriptInfo::IsArabicText( rInf.GetText(), rInf.GetIdx(), rInf.GetLen() ) )
1323  {
1324  if ( pSI && pSI->CountKashida() &&
1325  pSI->KashidaJustify( pKernArray.get(), nullptr, rInf.GetIdx(),
1326  rInf.GetLen(), nSpaceAdd ) != -1 )
1327  {
1328  bSpecialJust = true;
1329  nSpaceAdd = 0;
1330  }
1331  }
1332  }
1333 
1334  // Thai Justification
1335  if ( SwFontScript::CTL == nActual && nSpaceAdd )
1336  {
1338 
1339  if ( LANGUAGE_THAI == aLang )
1340  {
1341  // Use rInf.GetSpace() because it has more precision than
1342  // nSpaceAdd:
1343  SwScriptInfo::ThaiJustify( rInf.GetText(), pKernArray.get(), nullptr,
1344  rInf.GetIdx(), rInf.GetLen(),
1345  rInf.GetNumberOfBlanks(),
1346  rInf.GetSpace() );
1347 
1348  // adding space to blanks is already done
1349  bSpecialJust = true;
1350  nSpaceAdd = 0;
1351  }
1352  }
1353  }
1354 
1355  long nKernSum = rInf.GetKern();
1356 
1357  if ( bStretch || m_bPaintBlank || rInf.GetKern() || bSpecialJust )
1358  {
1359  for (sal_Int32 i = 0; i < sal_Int32(rInf.GetLen()); i++,
1360  nKernSum += rInf.GetKern() )
1361  {
1362  if (CH_BLANK == rInf.GetText()[sal_Int32(rInf.GetIdx()) + i])
1363  nKernSum += nSpaceAdd;
1364  pKernArray[i] += nKernSum;
1365  }
1366 
1367  // In case of underlined/strike-through justified text
1368  // a blank at the end requires special handling:
1369  if( m_bPaintBlank && rInf.GetLen() && ( CH_BLANK ==
1370  rInf.GetText()[sal_Int32(rInf.GetIdx() + rInf.GetLen())-1]))
1371  {
1372  // If it is a single underlined space, output 2 spaces:
1373  if (TextFrameIndex(1) == rInf.GetLen())
1374  {
1375  pKernArray[0] = rInf.GetWidth() + nSpaceAdd;
1376 
1377  rInf.GetOut().DrawTextArray( aTextOriginPos, rInf.GetText(),
1378  pKernArray.get(), sal_Int32(rInf.GetIdx()), 1 );
1379  }
1380  else
1381  {
1382  pKernArray[ sal_Int32(rInf.GetLen()) - 2 ] += nSpaceAdd;
1383  rInf.GetOut().DrawTextArray( aTextOriginPos, rInf.GetText(),
1384  pKernArray.get(), sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()));
1385  }
1386  }
1387  else
1388  rInf.GetOut().DrawTextArray( aTextOriginPos, rInf.GetText(),
1389  pKernArray.get(), sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()));
1390  }
1391  else
1392  {
1393  Point aTmpPos( aTextOriginPos );
1394  sal_Int32 j = 0;
1395  sal_Int32 i;
1396  for( i = 0; i < sal_Int32(rInf.GetLen()); i++ )
1397  {
1398  if (CH_BLANK == rInf.GetText()[sal_Int32(rInf.GetIdx()) + i])
1399  {
1400  nKernSum += nSpaceAdd;
1401  if( j < i )
1402  rInf.GetOut().DrawText( aTmpPos, rInf.GetText(),
1403  sal_Int32(rInf.GetIdx()) + j, i - j);
1404  j = i + 1;
1405  SwTwips nAdd = pKernArray[ i ] + nKernSum;
1406  if ( ( ComplexTextLayoutFlags::BiDiStrong | ComplexTextLayoutFlags::BiDiRtl ) == nMode )
1407  nAdd *= -1;
1408  aTmpPos.setX( aTextOriginPos.X() + nAdd );
1409  }
1410  }
1411  if( j < i )
1412  rInf.GetOut().DrawText( aTmpPos, rInf.GetText(),
1413  sal_Int32(rInf.GetIdx()) + j, i - j);
1414  }
1415  }
1416  else if( bStretch )
1417  {
1418  long nTmpWidth = rInf.GetWidth();
1419  if( rInf.GetKern() && rInf.GetLen() && nTmpWidth > rInf.GetKern() )
1420  nTmpWidth -= rInf.GetKern();
1421  rInf.GetOut().DrawStretchText( aTextOriginPos, nTmpWidth,
1422  rInf.GetText(),
1423  sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()));
1424  }
1425  else if( rInf.GetKern() )
1426  {
1427  const long nTmpWidth = GetTextSize( rInf ).Width();
1428 
1429  const Color aSaveColor( pTmpFont->GetColor() );
1430  const bool bColorChanged = rInf.ApplyAutoColor( pTmpFont );
1431 
1432  if( bColorChanged )
1433  {
1434  if( !pTmpFont->IsSameInstance( rInf.GetOut().GetFont() ) )
1435  rInf.GetOut().SetFont( *pTmpFont );
1436  pTmpFont->SetColor( aSaveColor );
1437  }
1438 
1439  rInf.GetOut().DrawStretchText( aTextOriginPos, nTmpWidth,
1440  rInf.GetText(),
1441  sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()));
1442  }
1443  else
1444  rInf.GetOut().DrawText( aTextOriginPos, rInf.GetText(),
1445  sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()));
1446  }
1447 
1448  // PAINTING WITH FORMATTING DEVICE/SCREEN ADJUSTMENT
1449 
1450  else
1451  {
1452  const OUString* pStr = &rInf.GetText();
1453 
1454  OUString aStr;
1455  OUString aBulletOverlay;
1456  bool bBullet = rInf.GetBullet();
1457  if( m_bSymbol )
1458  bBullet = false;
1459  std::unique_ptr<long[]> pKernArray(new long[sal_Int32(rInf.GetLen())]);
1460  CreateScrFont( *rInf.GetShell(), rInf.GetOut() );
1461  long nScrPos;
1462 
1463  // get screen array
1464  std::unique_ptr<long[]> pScrArray(new long[sal_Int32(rInf.GetLen())]);
1465  SwTextGlyphsKey aGlyphsKey{ &rInf.GetOut(), rInf.GetText(), sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()) };
1466  SalLayoutGlyphs* pGlyphs = lcl_CreateLayout(aGlyphsKey, m_aTextGlyphs[aGlyphsKey]);
1467  rInf.GetOut().GetTextArray( rInf.GetText(), pScrArray.get(),
1468  sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()), nullptr, pGlyphs);
1469 
1470  // OLE: no printer available
1471  // OSL_ENSURE( pPrinter, "DrawText needs pPrinter" )
1472  if ( m_pPrinter )
1473  {
1474  // pTmpFont has already been set as current font for rInf.GetOut()
1475  if ( m_pPrinter.get() != rInf.GetpOut() || pTmpFont != m_pPrtFont )
1476  {
1479  }
1480  aGlyphsKey = SwTextGlyphsKey{ m_pPrinter, rInf.GetText(), sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()) };
1481  pGlyphs = lcl_CreateLayout(aGlyphsKey, m_aTextGlyphs[aGlyphsKey]);
1482  m_pPrinter->GetTextArray(rInf.GetText(), pKernArray.get(),
1483  sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()), nullptr, pGlyphs);
1484  }
1485  else
1486  {
1487  rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray.get(),
1488  sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()));
1489  }
1490 
1491  // Modify Printer and ScreenArrays for special justifications
1492 
1493  long nSpaceAdd = rInf.GetSpace() / SPACING_PRECISION_FACTOR;
1494  bool bNoHalfSpace = false;
1495 
1496  if ( rInf.GetFont() && rInf.GetLen() )
1497  {
1498  const SwFontScript nActual = rInf.GetFont()->GetActual();
1499  const SwScriptInfo* pSI = rInf.GetScriptInfo();
1500 
1501  // Kana Compression
1502  if ( SwFontScript::CJK == nActual && rInf.GetKanaComp() &&
1503  pSI && pSI->CountCompChg() &&
1504  lcl_IsMonoSpaceFont( rInf.GetOut() ) )
1505  {
1506  Point aTmpPos( aTextOriginPos );
1507  pSI->Compress( pScrArray.get(), rInf.GetIdx(), rInf.GetLen(),
1508  rInf.GetKanaComp(),
1509  static_cast<sal_uInt16>(m_aFont.GetFontSize().Height()), lcl_IsFullstopCentered( rInf.GetOut() ), &aTmpPos );
1510  pSI->Compress( pKernArray.get(), rInf.GetIdx(), rInf.GetLen(),
1511  rInf.GetKanaComp(),
1512  static_cast<sal_uInt16>(m_aFont.GetFontSize().Height()), lcl_IsFullstopCentered( rInf.GetOut() ), &aTextOriginPos );
1513  }
1514 
1515  // Asian Justification
1516  if ( SwFontScript::CJK == nActual && nSpaceAdd )
1517  {
1519 
1520  if (!MsLangId::isKorean(aLang))
1521  {
1522  SwScriptInfo::CJKJustify( rInf.GetText(), pKernArray.get(), pScrArray.get(),
1523  rInf.GetIdx(), rInf.GetLen(), aLang, nSpaceAdd, rInf.IsSpaceStop() );
1524 
1525  nSpaceAdd = 0;
1526  }
1527  }
1528 
1529  // Kashida Justification
1530  if ( SwFontScript::CTL == nActual && nSpaceAdd )
1531  {
1532  if ( SwScriptInfo::IsArabicText( rInf.GetText(), rInf.GetIdx(), rInf.GetLen() ) )
1533  {
1534  if ( pSI && pSI->CountKashida() &&
1535  pSI->KashidaJustify( pKernArray.get(), pScrArray.get(), rInf.GetIdx(),
1536  rInf.GetLen(), nSpaceAdd ) != -1 )
1537  nSpaceAdd = 0;
1538  else
1539  bNoHalfSpace = true;
1540  }
1541  }
1542 
1543  // Thai Justification
1544  if ( SwFontScript::CTL == nActual && nSpaceAdd )
1545  {
1547 
1548  if ( LANGUAGE_THAI == aLang )
1549  {
1550  SwScriptInfo::ThaiJustify( rInf.GetText(), pKernArray.get(),
1551  pScrArray.get(), rInf.GetIdx(),
1552  rInf.GetLen(),
1553  rInf.GetNumberOfBlanks(),
1554  rInf.GetSpace() );
1555 
1556  // adding space to blanks is already done
1557  nSpaceAdd = 0;
1558  }
1559  }
1560  }
1561 
1562  nScrPos = pScrArray[ 0 ];
1563 
1564  if( bBullet )
1565  {
1566  // !!! HACK !!!
1567  // The Arabic layout engine requires some context of the string
1568  // which should be painted.
1569  sal_Int32 nCopyStart = sal_Int32(rInf.GetIdx());
1570  if ( nCopyStart )
1571  --nCopyStart;
1572 
1573  sal_Int32 nCopyLen = sal_Int32(rInf.GetLen());
1574  if ( nCopyStart + nCopyLen < rInf.GetText().getLength() )
1575  ++nCopyLen;
1576 
1577  aStr = rInf.GetText().copy( nCopyStart, nCopyLen );
1578  pStr = &aStr;
1579 
1580  aBulletOverlay = rInf.GetText().copy( nCopyStart, nCopyLen );
1581 
1582  for( sal_Int32 i = 0; i < aBulletOverlay.getLength(); ++i )
1583  if( CH_BLANK == aBulletOverlay[ i ] )
1584  {
1585  /* fdo#72488 Hack: try to see if the space is zero width
1586  * and don't bother with inserting a bullet in this case.
1587  */
1588  if ((i + nCopyStart + 1 >= sal_Int32(rInf.GetLen())) ||
1589  pKernArray[i + nCopyStart] != pKernArray[ i + nCopyStart + 1])
1590  {
1591  aBulletOverlay = aBulletOverlay.replaceAt(i, 1, OUString(CH_BULLET));
1592  }
1593  else
1594  {
1595  aBulletOverlay = aBulletOverlay.replaceAt(i, 1, OUString(CH_BLANK));
1596  }
1597  }
1598  else
1599  {
1600  aBulletOverlay = aBulletOverlay.replaceAt(i, 1, OUString(CH_BLANK));
1601  }
1602  }
1603 
1604  TextFrameIndex nCnt(rInf.GetText().getLength());
1605  if ( nCnt < rInf.GetIdx() )
1606  assert(false); // layout bug, not handled below
1607  else
1608  nCnt = nCnt - rInf.GetIdx();
1609  nCnt = std::min(nCnt, rInf.GetLen());
1610  long nKernSum = rInf.GetKern();
1611  sal_Unicode cChPrev = rInf.GetText()[sal_Int32(rInf.GetIdx())];
1612 
1613  // In case of a single underlined space in justified text,
1614  // have to output 2 spaces:
1615  if ((nCnt == TextFrameIndex(1)) && rInf.GetSpace() && (cChPrev == CH_BLANK))
1616  {
1617  pKernArray[0] = rInf.GetWidth() +
1618  rInf.GetKern() +
1619  ( rInf.GetSpace() / SPACING_PRECISION_FACTOR );
1620 
1621  if ( bSwitchL2R )
1622  rInf.GetFrame()->SwitchLTRtoRTL( aTextOriginPos );
1623 
1624  if ( bSwitchH2V )
1625  rInf.GetFrame()->SwitchHorizontalToVertical( aTextOriginPos );
1626 
1627  rInf.GetOut().DrawTextArray( aTextOriginPos, rInf.GetText(),
1628  pKernArray.get(), sal_Int32(rInf.GetIdx()), 1 );
1629  if( bBullet )
1630  rInf.GetOut().DrawTextArray( aTextOriginPos, *pStr, pKernArray.get(),
1631  rInf.GetIdx() ? 1 : 0, 1 );
1632  }
1633  else
1634  {
1635  sal_Unicode nCh;
1636 
1637  // In case of Pair Kerning the printer influence on the positioning
1638  // grows
1639  const int nMul = m_pPrtFont->GetKerning() != FontKerning::NONE ? 1 : 3;
1640  const int nDiv = nMul+1;
1641 
1642  // nSpaceSum contains the sum of the intermediate space distributed
1643  // among Spaces by the Justification.
1644  // The Spaces themselves will be positioned in the middle of the
1645  // intermediate space, hence the nSpace/2.
1646  // In case of word-by-word underlining they have to be positioned
1647  // at the beginning of the intermediate space, so that the space
1648  // is not underlined.
1649  // A Space at the beginning or end of the text must be positioned
1650  // before (resp. after) the whole intermediate space, otherwise
1651  // the underline/strike-through would have gaps.
1652  long nSpaceSum = 0;
1653  // in word line mode and for Arabic, we disable the half space trick:
1654  const long nHalfSpace = m_pPrtFont->IsWordLineMode() || bNoHalfSpace ? 0 : nSpaceAdd / 2;
1655  const long nOtherHalf = nSpaceAdd - nHalfSpace;
1656  if ( nSpaceAdd && ( cChPrev == CH_BLANK ) )
1657  nSpaceSum = nHalfSpace;
1658  for (sal_Int32 i = 1; i < sal_Int32(nCnt); ++i, nKernSum += rInf.GetKern())
1659  {
1660  nCh = rInf.GetText()[sal_Int32(rInf.GetIdx()) + i];
1661 
1662  OSL_ENSURE( pScrArray, "Where is the screen array?" );
1663  long nScr;
1664  nScr = pScrArray[ i ] - pScrArray[ i - 1 ];
1665 
1666  // If there is an (ex-)Space before us, position optimally,
1667  // i.e., our right margin to the 100% printer position;
1668  // if we _are_ an ex-Space, position us left-aligned to the
1669  // printer position.
1670  if ( nCh == CH_BLANK )
1671  {
1672  nScrPos = pKernArray[i-1] + nScr;
1673 
1674  if ( cChPrev == CH_BLANK )
1675  nSpaceSum += nOtherHalf;
1676  if (i + 1 == sal_Int32(nCnt))
1677  nSpaceSum += nSpaceAdd;
1678  else
1679  nSpaceSum += nHalfSpace;
1680  }
1681  else
1682  {
1683  if ( cChPrev == CH_BLANK )
1684  {
1685  nScrPos = pKernArray[i-1] + nScr;
1686  // no Pixel is lost:
1687  nSpaceSum += nOtherHalf;
1688  }
1689  else if ( cChPrev == '-' )
1690  nScrPos = pKernArray[i-1] + nScr;
1691  else
1692  {
1693  nScrPos += nScr;
1694  nScrPos = ( nMul * nScrPos + pKernArray[i] ) / nDiv;
1695  }
1696  }
1697  cChPrev = nCh;
1698  pKernArray[i-1] = nScrPos - nScr + nKernSum + nSpaceSum;
1699  // In word line mode and for Arabic, we disabled the half space trick. If a portion
1700  // ends with a blank, the full nSpaceAdd value has been added to the character in
1701  // front of the blank. This leads to painting artifacts, therefore we remove the
1702  // nSpaceAdd value again:
1703  if ((bNoHalfSpace || m_pPrtFont->IsWordLineMode()) && i+1 == sal_Int32(nCnt) && nCh == CH_BLANK)
1704  pKernArray[i-1] = pKernArray[i-1] - nSpaceAdd;
1705  }
1706 
1707  // the layout engine requires the total width of the output
1708  pKernArray[sal_Int32(rInf.GetLen()) - 1] += nKernSum + nSpaceSum;
1709 
1710  if( rInf.GetGreyWave() )
1711  {
1712  if( rInf.GetLen() )
1713  {
1714  long nHght = rInf.GetOut().LogicToPixel(
1715  m_pPrtFont->GetFontSize() ).Height();
1716  if( WRONG_SHOW_MIN < nHght )
1717  {
1718  if ( rInf.GetOut().GetConnectMetaFile() )
1719  rInf.GetOut().Push();
1720 
1721  Color aCol( rInf.GetOut().GetLineColor() );
1722  bool bColSave = aCol != gWaveCol;
1723  if ( bColSave )
1724  rInf.GetOut().SetLineColor( gWaveCol );
1725 
1726  Point aEnd;
1727  long nKernVal = pKernArray[sal_Int32(rInf.GetLen()) - 1];
1728 
1729  const sal_uInt16 nDir = bBidiPor
1730  ? 1800
1731  : UnMapDirection(GetFont().GetOrientation(),
1732  bSwitchH2V, bSwitchH2VLRBT);
1733 
1734  switch ( nDir )
1735  {
1736  case 0 :
1737  aEnd.setX( rInf.GetPos().X() + nKernVal );
1738  aEnd.setY( rInf.GetPos().Y() );
1739  break;
1740  case 900 :
1741  aEnd.setX( rInf.GetPos().X() );
1742  aEnd.setY( rInf.GetPos().Y() - nKernVal );
1743  break;
1744  case 1800 :
1745  aEnd.setX( rInf.GetPos().X() - nKernVal );
1746  aEnd.setY( rInf.GetPos().Y() );
1747  break;
1748  case 2700 :
1749  aEnd.setX( rInf.GetPos().X() );
1750  aEnd.setY( rInf.GetPos().Y() + nKernVal );
1751  break;
1752  }
1753 
1754  Point aCurrPos( rInf.GetPos() );
1755 
1756  if ( bSwitchL2R )
1757  {
1758  rInf.GetFrame()->SwitchLTRtoRTL( aCurrPos );
1759  rInf.GetFrame()->SwitchLTRtoRTL( aEnd );
1760  }
1761 
1762  if ( bSwitchH2V )
1763  {
1764  rInf.GetFrame()->SwitchHorizontalToVertical( aCurrPos );
1765  rInf.GetFrame()->SwitchHorizontalToVertical( aEnd );
1766  }
1767  rInf.GetOut().DrawWaveLine( aCurrPos, aEnd );
1768 
1769  if ( bColSave )
1770  rInf.GetOut().SetLineColor( aCol );
1771 
1772  if ( rInf.GetOut().GetConnectMetaFile() )
1773  rInf.GetOut().Pop();
1774  }
1775  }
1776  }
1777  else if( !m_bSymbol && rInf.GetLen() )
1778  {
1779  // anything to do?
1780  if (rInf.GetWrong() || rInf.GetGrammarCheck() || rInf.GetSmartTags())
1781  {
1782  CalcLinePosData aCalcLinePosData(rInf, GetFont(), nCnt, bSwitchH2V,
1783  bSwitchH2VLRBT, bSwitchL2R, nHalfSpace,
1784  pKernArray.get(), bBidiPor);
1785 
1786  SwForbidden aForbidden;
1787  // draw line for smart tag data
1788  lcl_DrawLineForWrongListData( aForbidden, rInf, rInf.GetSmartTags(), aCalcLinePosData, Size() );
1789  // draw wave line for spell check errors
1790  // draw them BEFORE the grammar check lines to 'override' the latter in case of conflict.
1791  // reason: some grammar errors can only be found if spelling errors are fixed,
1792  // therefore we don't want the user to miss a spelling error.
1793  lcl_DrawLineForWrongListData( aForbidden, rInf, rInf.GetWrong(), aCalcLinePosData, m_pPrtFont->GetFontSize() );
1794  // draw wave line for grammar check errors
1795  lcl_DrawLineForWrongListData( aForbidden, rInf, rInf.GetGrammarCheck(), aCalcLinePosData, m_pPrtFont->GetFontSize() );
1796  }
1797  }
1798 
1799  sal_Int32 nLen = sal_Int32(rInf.GetLen());
1800 
1801  if( nLen > 0 )
1802  {
1803 
1804  if ( bSwitchL2R )
1805  rInf.GetFrame()->SwitchLTRtoRTL( aTextOriginPos );
1806 
1807  if ( bSwitchH2V )
1808  rInf.GetFrame()->SwitchHorizontalToVertical( aTextOriginPos );
1809 
1810  // If we paint bullets instead of spaces, we use a copy of
1811  // the paragraph string. For the layout engine, the copy
1812  // of the string has to be an environment of the range which
1813  // is painted
1814  sal_Int32 nTmpIdx = bBullet
1815  ? (rInf.GetIdx() ? 1 : 0)
1816  : sal_Int32(rInf.GetIdx());
1817  aGlyphsKey = SwTextGlyphsKey{ &rInf.GetOut(), *pStr, nTmpIdx, nLen };
1818  pGlyphs = lcl_CreateLayout(aGlyphsKey, m_aTextGlyphs[aGlyphsKey]);
1819  rInf.GetOut().DrawTextArray( aTextOriginPos, *pStr, pKernArray.get(),
1820  nTmpIdx , nLen, SalLayoutFlags::NONE, pGlyphs );
1821  if (bBullet)
1822  {
1823  rInf.GetOut().Push();
1824  Color aPreviousColor = pTmpFont->GetColor();
1825 
1826  FontLineStyle aPreviousUnderline = pTmpFont->GetUnderline();
1827  FontLineStyle aPreviousOverline = pTmpFont->GetOverline();
1828  FontStrikeout aPreviousStrikeout = pTmpFont->GetStrikeout();
1829 
1830  pTmpFont->SetColor( NON_PRINTING_CHARACTER_COLOR );
1831  pTmpFont->SetUnderline(LINESTYLE_NONE);
1832  pTmpFont->SetOverline(LINESTYLE_NONE);
1833  pTmpFont->SetStrikeout(STRIKEOUT_NONE);
1834  rInf.GetOut().SetFont( *pTmpFont );
1835  long nShift = rInf.GetOut( ).GetFontMetric( ).GetBulletOffset( );
1836  if ( nShift )
1837  {
1838  long nAdd = 0;
1839 
1840  if (aBulletOverlay.getLength() > nTmpIdx &&
1841  aBulletOverlay[ nTmpIdx ] == CH_BULLET )
1842  {
1843  if (bSwitchH2V)
1844  aTextOriginPos.AdjustY(nShift ) ;
1845  else
1846  aTextOriginPos.AdjustX(nShift ) ;
1847  nAdd = nShift ;
1848  }
1849  for( sal_Int32 i = 1 ; i < nLen ; ++i )
1850  {
1851  if ( aBulletOverlay[ i + nTmpIdx ] == CH_BULLET )
1852  pKernArray [ i - 1 ] += nShift ;
1853  if ( nAdd )
1854  pKernArray [ i - 1 ] -= nAdd;
1855  }
1856  }
1857  rInf.GetOut().DrawTextArray( aTextOriginPos, aBulletOverlay, pKernArray.get(),
1858  nTmpIdx , nLen );
1859  pTmpFont->SetColor( aPreviousColor );
1860 
1861  pTmpFont->SetUnderline(aPreviousUnderline);
1862  pTmpFont->SetOverline(aPreviousOverline);
1863  pTmpFont->SetStrikeout(aPreviousStrikeout);
1864  rInf.GetOut().Pop();
1865  }
1866  }
1867  }
1868  }
1869 }
1870 
1872 {
1873  Size aTextSize;
1874  const TextFrameIndex nLn = (TextFrameIndex(COMPLETE_STRING) != rInf.GetLen())
1875  ? rInf.GetLen()
1876  : TextFrameIndex(rInf.GetText().getLength());
1877 
1878  // be sure to have the correct layout mode at the printer
1879  if ( m_pPrinter )
1880  {
1883  }
1884 
1885  if ( rInf.GetFrame() && nLn && rInf.SnapToGrid() && rInf.GetFont() &&
1886  SwFontScript::CJK == rInf.GetFont()->GetActual() )
1887  {
1888  SwTextGridItem const*const pGrid(GetGridItem(rInf.GetFrame()->FindPageFrame()));
1889  if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && pGrid->IsSnapToChars() )
1890  {
1891  const SwDoc* pDoc = rInf.GetShell()->GetDoc();
1892  const sal_uInt16 nGridWidth = GetGridWidth(*pGrid, *pDoc);
1893 
1894  OutputDevice* pOutDev;
1895 
1896  if ( m_pPrinter )
1897  {
1900  pOutDev = m_pPrinter;
1901  }
1902  else
1903  pOutDev = rInf.GetpOut();
1904 
1905  aTextSize.setWidth( pOutDev->GetTextWidth(rInf.GetText(),
1906  sal_Int32(rInf.GetIdx()), sal_Int32(nLn)) );
1907 
1908  OSL_ENSURE( !rInf.GetShell() ||
1910  "Leading values should be already calculated" );
1911  aTextSize.setHeight( pOutDev->GetTextHeight() +
1912  GetFontLeading( rInf.GetShell(), rInf.GetOut() ) );
1913 
1914  long nAvgWidthPerChar = aTextSize.Width() / sal_Int32(nLn);
1915 
1916  const sal_uLong i = nAvgWidthPerChar ?
1917  ( nAvgWidthPerChar - 1 ) / nGridWidth + 1:
1918  1;
1919 
1920  aTextSize.setWidth(i * nGridWidth * sal_Int32(nLn));
1921  rInf.SetKanaDiff( 0 );
1922  return aTextSize;
1923  }
1924  }
1925 
1926  //for textgrid refactor
1927  if ( rInf.GetFrame() && nLn && rInf.SnapToGrid() && rInf.GetFont() )
1928  {
1929  SwTextGridItem const*const pGrid(GetGridItem(rInf.GetFrame()->FindPageFrame()));
1930  if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && !pGrid->IsSnapToChars() )
1931  {
1932  const long nGridWidthAdd = EvalGridWidthAdd( pGrid, rInf );
1933  OutputDevice* pOutDev;
1934  if ( m_pPrinter )
1935  {
1938  pOutDev = m_pPrinter;
1939  }
1940  else
1941  pOutDev = rInf.GetpOut();
1942  aTextSize.setWidth(pOutDev->GetTextWidth(rInf.GetText(),
1943  sal_Int32(rInf.GetIdx()), sal_Int32(nLn)));
1944  aTextSize.setHeight( pOutDev->GetTextHeight() +
1945  GetFontLeading( rInf.GetShell(), rInf.GetOut() ) );
1946  aTextSize.AdjustWidth(sal_Int32(nLn) * nGridWidthAdd);
1947  //if ( rInf.GetKern() && nLn )
1948  // aTextSize.Width() += ( nLn ) * long( rInf.GetKern() );
1949 
1950  rInf.SetKanaDiff( 0 );
1951  return aTextSize;
1952  }
1953  }
1954 
1955  const bool bCompress = rInf.GetKanaComp() && nLn &&
1956  rInf.GetFont() &&
1957  SwFontScript::CJK == rInf.GetFont()->GetActual() &&
1958  rInf.GetScriptInfo() &&
1959  rInf.GetScriptInfo()->CountCompChg() &&
1960  lcl_IsMonoSpaceFont( rInf.GetOut() );
1961 
1962  OSL_ENSURE( !bCompress || ( rInf.GetScriptInfo() && rInf.GetScriptInfo()->
1963  CountCompChg()), "Compression without info" );
1964 
1965  // This is the part used e.g., for cursor travelling
1966  // See condition for DrawText or DrawTextArray (bDirectPrint)
1967  if ( m_pPrinter && m_pPrinter.get() != rInf.GetpOut() )
1968  {
1971  aTextSize.setWidth( m_pPrinter->GetTextWidth( rInf.GetText(),
1972  sal_Int32(rInf.GetIdx()), sal_Int32(nLn)));
1973  aTextSize.setHeight( m_pPrinter->GetTextHeight() );
1974  std::unique_ptr<long[]> pKernArray(new long[sal_Int32(nLn)]);
1975  CreateScrFont( *rInf.GetShell(), rInf.GetOut() );
1976  if( !GetScrFont()->IsSameInstance( rInf.GetOut().GetFont() ) )
1977  rInf.GetOut().SetFont( *m_pScrFont );
1978  long nScrPos;
1979 
1980  m_pPrinter->GetTextArray(rInf.GetText(), pKernArray.get(),
1981  sal_Int32(rInf.GetIdx()), sal_Int32(nLn));
1982  if( bCompress )
1983  rInf.SetKanaDiff( rInf.GetScriptInfo()->Compress( pKernArray.get(),
1984  rInf.GetIdx(), nLn, rInf.GetKanaComp(),
1985  static_cast<sal_uInt16>(m_aFont.GetFontSize().Height()) ,lcl_IsFullstopCentered( rInf.GetOut() ) ) );
1986  else
1987  rInf.SetKanaDiff( 0 );
1988 
1989  if ( rInf.GetKanaDiff() )
1990  nScrPos = pKernArray[ sal_Int32(nLn) - 1 ];
1991  else
1992  {
1993  std::unique_ptr<long[]> pScrArray(new long[sal_Int32(rInf.GetLen())]);
1994  rInf.GetOut().GetTextArray( rInf.GetText(), pScrArray.get(),
1995  sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()));
1996  nScrPos = pScrArray[ 0 ];
1997  TextFrameIndex nCnt(rInf.GetText().getLength());
1998  if ( nCnt < rInf.GetIdx() )
1999  nCnt = TextFrameIndex(0); // assert???
2000  else
2001  nCnt = nCnt - rInf.GetIdx();
2002  nCnt = std::min(nCnt, nLn);
2003  sal_Unicode nChPrev = rInf.GetText()[ sal_Int32(rInf.GetIdx()) ];
2004 
2005  sal_Unicode nCh;
2006 
2007  // In case of Pair Kerning the printer influence on the positioning
2008  // grows
2009  const int nMul = m_pPrtFont->GetKerning() != FontKerning::NONE ? 1 : 3;
2010  const int nDiv = nMul+1;
2011  for (sal_Int32 i = 1; i < sal_Int32(nCnt); i++)
2012  {
2013  nCh = rInf.GetText()[ sal_Int32(rInf.GetIdx()) + i ];
2014  long nScr;
2015  nScr = pScrArray[ i ] - pScrArray[ i - 1 ];
2016  if ( nCh == CH_BLANK )
2017  nScrPos = pKernArray[i-1]+nScr;
2018  else
2019  {
2020  if ( nChPrev == CH_BLANK || nChPrev == '-' )
2021  nScrPos = pKernArray[i-1]+nScr;
2022  else
2023  {
2024  nScrPos += nScr;
2025  nScrPos = ( nMul * nScrPos + pKernArray[i] ) / nDiv;
2026  }
2027  }
2028  nChPrev = nCh;
2029  pKernArray[i-1] = nScrPos - nScr;
2030  }
2031  }
2032 
2033  pKernArray.reset();
2034  aTextSize.setWidth( nScrPos );
2035  }
2036  else
2037  {
2038  if( !m_pPrtFont->IsSameInstance( rInf.GetOut().GetFont() ) )
2039  rInf.GetOut().SetFont( *m_pPrtFont );
2040  if( bCompress )
2041  {
2042  std::unique_ptr<long[]> pKernArray( new long[sal_Int32(nLn)] );
2043  rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray.get(),
2044  sal_Int32(rInf.GetIdx()), sal_Int32(nLn));
2045  rInf.SetKanaDiff( rInf.GetScriptInfo()->Compress( pKernArray.get(),
2046  rInf.GetIdx(), nLn, rInf.GetKanaComp(),
2047  static_cast<sal_uInt16>(m_aFont.GetFontSize().Height()) ,lcl_IsFullstopCentered( rInf.GetOut() ) ) );
2048  aTextSize.setWidth( pKernArray[sal_Int32(nLn) - 1] );
2049  }
2050  else
2051  {
2052  SwTextGlyphsKey aGlyphsKey{ &rInf.GetOut(), rInf.GetText(), sal_Int32(rInf.GetIdx()), sal_Int32(nLn) };
2053  SalLayoutGlyphs* pGlyphs = lcl_CreateLayout(aGlyphsKey, m_aTextGlyphs[aGlyphsKey]);
2054  aTextSize.setWidth( rInf.GetOut().GetTextWidth( rInf.GetText(),
2055  sal_Int32(rInf.GetIdx()), sal_Int32(nLn),
2056  rInf.GetVclCache(), pGlyphs) );
2057  rInf.SetKanaDiff( 0 );
2058  }
2059 
2060  aTextSize.setHeight( rInf.GetOut().GetTextHeight() );
2061  }
2062 
2063  if ( rInf.GetKern() && nLn )
2064  aTextSize.AdjustWidth((sal_Int32(nLn) - 1) * rInf.GetKern());
2065 
2066  OSL_ENSURE( !rInf.GetShell() ||
2068  "Leading values should be already calculated" );
2069  aTextSize.AdjustHeight(GetFontLeading( rInf.GetShell(), rInf.GetOut() ) );
2070  return aTextSize;
2071 }
2072 
2074 {
2075  long nSpaceAdd = rInf.GetSpace() / SPACING_PRECISION_FACTOR;
2076  const long nSperren = -rInf.GetSperren() / SPACING_PRECISION_FACTOR;
2077  long nKern = rInf.GetKern();
2078 
2079  if( 0 != nSperren )
2080  nKern -= nSperren;
2081 
2082  std::unique_ptr<long[]> pKernArray(new long[sal_Int32(rInf.GetLen())]);
2083 
2084  // be sure to have the correct layout mode at the printer
2085  if ( m_pPrinter )
2086  {
2089  SwTextGlyphsKey aGlyphsKey{ m_pPrinter, rInf.GetText(), sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()) };
2090  SalLayoutGlyphs* pGlyphs = lcl_CreateLayout(aGlyphsKey, m_aTextGlyphs[aGlyphsKey]);
2091  m_pPrinter->GetTextArray( rInf.GetText(), pKernArray.get(),
2092  sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()), nullptr, pGlyphs);
2093  }
2094  else
2095  rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray.get(),
2096  sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()));
2097 
2098  const SwScriptInfo* pSI = rInf.GetScriptInfo();
2099  if ( rInf.GetFont() && rInf.GetLen() )
2100  {
2101  const SwFontScript nActual = rInf.GetFont()->GetActual();
2102 
2103  // Kana Compression
2104  if ( SwFontScript::CJK == nActual && rInf.GetKanaComp() &&
2105  pSI && pSI->CountCompChg() &&
2106  lcl_IsMonoSpaceFont( rInf.GetOut() ) )
2107  {
2108  pSI->Compress( pKernArray.get(), rInf.GetIdx(), rInf.GetLen(),
2109  rInf.GetKanaComp(),
2110  static_cast<sal_uInt16>(m_aFont.GetFontSize().Height()),
2111  lcl_IsFullstopCentered( rInf.GetOut() ) );
2112  }
2113 
2114  // Asian Justification
2115  if ( SwFontScript::CJK == rInf.GetFont()->GetActual() )
2116  {
2118 
2119  if (!MsLangId::isKorean(aLang))
2120  {
2121  SwScriptInfo::CJKJustify( rInf.GetText(), pKernArray.get(), nullptr,
2122  rInf.GetIdx(), rInf.GetLen(), aLang, nSpaceAdd, rInf.IsSpaceStop() );
2123 
2124  nSpaceAdd = 0;
2125  }
2126 
2127  }
2128 
2129  // Kashida Justification
2130  if ( SwFontScript::CTL == nActual && rInf.GetSpace() )
2131  {
2132  if ( SwScriptInfo::IsArabicText( rInf.GetText(), rInf.GetIdx(), rInf.GetLen() ) )
2133  {
2134  if ( pSI && pSI->CountKashida() &&
2135  pSI->KashidaJustify( pKernArray.get(), nullptr, rInf.GetIdx(), rInf.GetLen(),
2136  nSpaceAdd ) != -1 )
2137  nSpaceAdd = 0;
2138  }
2139  }
2140 
2141  // Thai Justification
2142  if ( SwFontScript::CTL == nActual && nSpaceAdd )
2143  {
2145 
2146  if ( LANGUAGE_THAI == aLang )
2147  {
2148  SwScriptInfo::ThaiJustify( rInf.GetText(), pKernArray.get(), nullptr,
2149  rInf.GetIdx(), rInf.GetLen(),
2150  rInf.GetNumberOfBlanks(),
2151  rInf.GetSpace() );
2152 
2153  // adding space to blanks is already done
2154  nSpaceAdd = 0;
2155  }
2156  }
2157  }
2158 
2159  long nLeft = 0;
2160  long nRight = 0;
2161  TextFrameIndex nCnt(0);
2162  long nSpaceSum = 0;
2163  long nKernSum = 0;
2164 
2165  if ( rInf.GetFrame() && rInf.GetLen() && rInf.SnapToGrid() &&
2166  rInf.GetFont() && SwFontScript::CJK == rInf.GetFont()->GetActual() )
2167  {
2168  SwTextGridItem const*const pGrid(GetGridItem(rInf.GetFrame()->FindPageFrame()));
2169  if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && pGrid->IsSnapToChars() )
2170  {
2171  const SwDoc* pDoc = rInf.GetShell()->GetDoc();
2172  const sal_uInt16 nGridWidth = GetGridWidth(*pGrid, *pDoc);
2173 
2174  long nAvgWidthPerChar = pKernArray[sal_Int32(rInf.GetLen()) - 1] / sal_Int32(rInf.GetLen());
2175 
2176  sal_uLong i = nAvgWidthPerChar ?
2177  ( nAvgWidthPerChar - 1 ) / nGridWidth + 1:
2178  1;
2179 
2180  nAvgWidthPerChar = i * nGridWidth;
2181 
2182 // stupid CLANG
2183  nCnt = TextFrameIndex(rInf.GetOfst() / nAvgWidthPerChar);
2184  if (2 * (rInf.GetOfst() - sal_Int32(nCnt) * nAvgWidthPerChar) > nAvgWidthPerChar)
2185  ++nCnt;
2186 
2187  return nCnt;
2188  }
2189  }
2190 
2191  //for textgrid refactor
2192  if ( rInf.GetFrame() && rInf.GetLen() && rInf.SnapToGrid() )
2193  {
2194  SwTextGridItem const*const pGrid(GetGridItem(rInf.GetFrame()->FindPageFrame()));
2195  if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && !pGrid->IsSnapToChars() )
2196  {
2197 
2198  const long nGridWidthAdd = EvalGridWidthAdd( pGrid, rInf );
2199 
2200  for (TextFrameIndex j(0); j < rInf.GetLen(); j++)
2201  {
2202  long nScr = pKernArray[sal_Int32(j)] + (nSpaceAdd + nGridWidthAdd) * (sal_Int32(j) + 1);
2203  if( nScr >= rInf.GetOfst())
2204  {
2205  nCnt = j;
2206  break;
2207  }
2208  }
2209  return nCnt;
2210  }
2211  }
2212 
2213  sal_Int32 nDone = 0;
2214  TextFrameIndex nIdx = rInf.GetIdx();
2215  TextFrameIndex nLastIdx = nIdx;
2216  const TextFrameIndex nEnd = rInf.GetIdx() + rInf.GetLen();
2217 
2218  // #i105901#
2219  // skip character cells for all script types
2220  LanguageType aLang = rInf.GetFont()->GetLanguage();
2221 
2222  while ( ( nRight < long( rInf.GetOfst() ) ) && ( nIdx < nEnd ) )
2223  {
2224  if (nSpaceAdd && CH_BLANK == rInf.GetText()[ sal_Int32(nIdx)])
2225  nSpaceSum += nSpaceAdd;
2226 
2227  // go to next character (cell).
2228  nLastIdx = nIdx;
2229 
2230  nIdx = TextFrameIndex(g_pBreakIt->GetBreakIter()->nextCharacters(
2231  rInf.GetText(), sal_Int32(nIdx),
2232  g_pBreakIt->GetLocale( aLang ),
2233  i18n::CharacterIteratorMode::SKIPCELL, 1, nDone));
2234  if ( nIdx <= nLastIdx )
2235  break;
2236 
2237  nLeft = nRight;
2238  nRight = pKernArray[sal_Int32(nIdx - rInf.GetIdx()) - 1] + nKernSum + nSpaceSum;
2239 
2240  nKernSum += nKern;
2241  }
2242 
2243  // step back if position is before the middle of the character
2244  // or if we do not want to go to the next character
2245  if ( nIdx > rInf.GetIdx() &&
2246  ( rInf.IsPosMatchesBounds() ||
2247  ( ( nRight > long( rInf.GetOfst() ) ) &&
2248  ( nRight - rInf.GetOfst() > rInf.GetOfst() - nLeft ) ) ) )
2249  nCnt = nLastIdx - rInf.GetIdx(); // first half
2250  else
2251  nCnt = nIdx - rInf.GetIdx(); // second half
2252 
2253  if ( pSI )
2254  rInf.SetCursorBidiLevel( pSI->DirType( nLastIdx ) );
2255 
2256  return nCnt;
2257 }
2258 
2259 SwFntAccess::SwFntAccess( const void* & rnFontCacheId,
2260  sal_uInt16 &rIndex, const void *pOwn, SwViewShell const *pSh,
2261  bool bCheck ) :
2262  SwCacheAccess( *pFntCache, rnFontCacheId, rIndex ),
2263  m_pShell( pSh )
2264 {
2265  // the used ctor of SwCacheAccess searches for rnFontCacheId+rIndex in the cache
2266  if ( IsAvail() )
2267  {
2268  // fast case: known Font (rnFontCacheId), no need to check printer and zoom
2269  if ( !bCheck )
2270  return;
2271 
2272  // Font is known, but has to be checked
2273  }
2274  else
2275  { // Font not known, must be searched
2276  bCheck = false;
2277  }
2278 
2279  {
2280  OutputDevice* pOut = nullptr;
2281  sal_uInt16 nZoom = USHRT_MAX;
2282 
2283  // Get the reference device
2284  if ( pSh )
2285  {
2286  pOut = &pSh->GetRefDev();
2287  nZoom = pSh->GetViewOptions()->GetZoom();
2288  }
2289 
2290  SwFntObj *pFntObj;
2291  if ( bCheck )
2292  {
2293  pFntObj = Get();
2294  if ( ( pFntObj->GetZoom( ) == nZoom ) &&
2295  ( pFntObj->m_pPrinter == pOut ) &&
2296  pFntObj->GetPropWidth() ==
2297  static_cast<SwSubFont const *>(pOwn)->GetPropWidth() )
2298  {
2299  return; // result of Check: Drucker+Zoom okay.
2300  }
2301  pFntObj->Unlock(); // forget this object, printer/zoom differs
2302  m_pObj = nullptr;
2303  }
2304 
2305  // Search by font comparison, quite expensive!
2306  // Look for same font and same printer
2307  pFntObj = pFntCache->First();
2308  while ( pFntObj && !( pFntObj->m_aFont == *static_cast<vcl::Font const *>(pOwn) &&
2309  pFntObj->GetZoom() == nZoom &&
2310  pFntObj->GetPropWidth() ==
2311  static_cast<SwSubFont const *>(pOwn)->GetPropWidth() &&
2312  ( !pFntObj->m_pPrinter || pFntObj->m_pPrinter == pOut ) ) )
2313  pFntObj = SwFntCache::Next( pFntObj );
2314 
2315  if( pFntObj && pFntObj->m_pPrinter.get() != pOut )
2316  {
2317  // found one without printer, let's see if there is one with
2318  // the same printer as well
2319  SwFntObj *pTmpObj = pFntObj;
2320  while( pTmpObj && !( pTmpObj->m_aFont == *static_cast<vcl::Font const *>(pOwn) &&
2321  pTmpObj->GetZoom()==nZoom && pTmpObj->m_pPrinter==pOut &&
2322  pTmpObj->GetPropWidth() ==
2323  static_cast<SwSubFont const *>(pOwn)->GetPropWidth() ) )
2324  pTmpObj = SwFntCache::Next( pTmpObj );
2325  if( pTmpObj )
2326  pFntObj = pTmpObj;
2327  }
2328 
2329  if ( !pFntObj ) // Font has not been found, create one
2330  {
2331  // Have to create new Object, hence Owner must be a SwFont, later
2332  // the Owner will be the "MagicNumber"
2333  SwCacheAccess::m_pOwner = pOwn;
2334  pFntObj = Get(); // will create via NewObj() and lock
2335  OSL_ENSURE(pFntObj, "No Font, no Fun.");
2336  }
2337  else // Font has been found, so we lock it.
2338  {
2339  pFntObj->Lock();
2340  if (pFntObj->m_pPrinter.get() != pOut) // if no printer is known by now
2341  {
2342  OSL_ENSURE( !pFntObj->m_pPrinter, "SwFntAccess: Printer Changed" );
2343  pFntObj->CreatePrtFont( *pOut );
2344  pFntObj->m_pPrinter = pOut;
2345  pFntObj->m_pScrFont = nullptr;
2346  pFntObj->m_nGuessedLeading = USHRT_MAX;
2347  pFntObj->m_nExtLeading = USHRT_MAX;
2348  pFntObj->m_nPrtAscent = USHRT_MAX;
2349  pFntObj->m_nPrtHeight = USHRT_MAX;
2350  }
2351  m_pObj = pFntObj;
2352  }
2353 
2354  // no matter if new or found, now the Owner of the Object is a
2355  // MagicNumber, and will be given to the SwFont, as well as the Index
2356  // for later direct access
2357  rnFontCacheId = reinterpret_cast<void*>(reinterpret_cast<sal_IntPtr>(pFntObj->GetOwner()));
2358  SwCacheAccess::m_pOwner = pFntObj->GetOwner();
2359  rIndex = pFntObj->GetCachePos();
2360  }
2361 }
2362 
2364 {
2365  // a new Font, a new "MagicNumber".
2366  return new SwFntObj( *static_cast<SwSubFont const *>(m_pOwner), ++mnFontCacheIdCounter, m_pShell );
2367 }
2368 
2370 {
2371  ChgFnt( rInf.GetShell(), rInf.GetOut() );
2372 
2373  const bool bCompress = rInf.GetKanaComp() && rInf.GetLen() &&
2375  rInf.GetScriptInfo() &&
2376  rInf.GetScriptInfo()->CountCompChg() &&
2377  lcl_IsMonoSpaceFont( rInf.GetOut() );
2378 
2379  OSL_ENSURE( !bCompress || ( rInf.GetScriptInfo() && rInf.GetScriptInfo()->
2380  CountCompChg()), "Compression without info" );
2381 
2382  TextFrameIndex nTextBreak(0);
2383  long nKern = 0;
2384 
2386  ? TextFrameIndex(rInf.GetText().getLength()) : rInf.GetLen();
2387 
2388  if ( rInf.GetFrame() && nLn && rInf.SnapToGrid() &&
2389  rInf.GetFont() && SwFontScript::CJK == rInf.GetFont()->GetActual() )
2390  {
2391  SwTextGridItem const*const pGrid(GetGridItem(rInf.GetFrame()->FindPageFrame()));
2392  if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && pGrid->IsSnapToChars() )
2393  {
2394  const SwDoc* pDoc = rInf.GetShell()->GetDoc();
2395  const sal_uInt16 nGridWidth = GetGridWidth(*pGrid, *pDoc);
2396 
2397  std::unique_ptr<long[]> pKernArray(new long[sal_Int32(rInf.GetLen())]);
2398  rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray.get(),
2399  sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()));
2400 
2401  long nAvgWidthPerChar = pKernArray[sal_Int32(rInf.GetLen()) - 1] / sal_Int32(rInf.GetLen());
2402 
2403  const sal_uLong i = nAvgWidthPerChar ?
2404  ( nAvgWidthPerChar - 1 ) / nGridWidth + 1:
2405  1;
2406 
2407  nAvgWidthPerChar = i * nGridWidth;
2408  long nCurrPos = nAvgWidthPerChar;
2409 
2410  while( nTextBreak < rInf.GetLen() && nTextWidth >= nCurrPos )
2411  {
2412  nCurrPos += nAvgWidthPerChar;
2413  ++nTextBreak;
2414  }
2415 
2416  return nTextBreak + rInf.GetIdx();
2417  }
2418  }
2419 
2420  //for text grid enhancement
2421  if ( rInf.GetFrame() && nLn && rInf.SnapToGrid() )
2422  {
2423  SwTextGridItem const*const pGrid(GetGridItem(rInf.GetFrame()->FindPageFrame()));
2424  if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && !pGrid->IsSnapToChars() )
2425  {
2426  const long nGridWidthAdd = EvalGridWidthAdd( pGrid, rInf );
2427 
2428  std::unique_ptr<long[]> pKernArray(new long[sal_Int32(rInf.GetLen())] );
2429  rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray.get(),
2430  sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()));
2431  long nCurrPos = pKernArray[sal_Int32(nTextBreak)] + nGridWidthAdd;
2432  while (++nTextBreak < rInf.GetLen() && nTextWidth >= nCurrPos)
2433  {
2434  nCurrPos = pKernArray[sal_Int32(nTextBreak)] + nGridWidthAdd * (sal_Int32(nTextBreak) + 1);
2435  }
2436  return nTextBreak + rInf.GetIdx();
2437  }
2438  }
2439 
2440  if( m_aSub[m_nActual].IsCapital() && nLn )
2441  {
2442  nTextBreak = GetCapitalBreak( rInf.GetShell(), rInf.GetpOut(),
2443  rInf.GetScriptInfo(), rInf.GetText(), nTextWidth, rInf.GetIdx(),
2444  nLn );
2445  }
2446  else
2447  {
2448  nKern = CheckKerning();
2449 
2450  const OUString* pTmpText;
2451  OUString aTmpText;
2452  TextFrameIndex nTmpIdx;
2453  TextFrameIndex nTmpLen;
2454  bool bTextReplaced = false;
2455 
2456  if ( !m_aSub[m_nActual].IsCaseMap() )
2457  {
2458  pTmpText = &rInf.GetText();
2459  nTmpIdx = rInf.GetIdx();
2460  nTmpLen = nLn;
2461  }
2462  else
2463  {
2464  const OUString aSnippet(rInf.GetText().copy(sal_Int32(rInf.GetIdx()), sal_Int32(nLn)));
2465  aTmpText = m_aSub[m_nActual].CalcCaseMap( aSnippet );
2466  const bool bTitle = SvxCaseMap::Capitalize == m_aSub[m_nActual].GetCaseMap();
2467 
2468  // Uaaaaahhhh!!! In title case mode, we would get wrong results
2469  if ( bTitle && nLn )
2470  {
2471  // check if rInf.GetIdx() is begin of word
2472  if ( !g_pBreakIt->GetBreakIter()->isBeginWord(
2473  rInf.GetText(), sal_Int32(rInf.GetIdx()),
2474  g_pBreakIt->GetLocale( m_aSub[m_nActual].GetLanguage() ),
2475  i18n::WordType::ANYWORD_IGNOREWHITESPACES ) )
2476  {
2477  // In this case, the beginning of aTmpText is wrong.
2478  OUString aSnippetTmp(aSnippet.copy(0, 1));
2479  aSnippetTmp = m_aSub[m_nActual].CalcCaseMap( aSnippetTmp );
2480  aTmpText = aTmpText.replaceAt( 0, aSnippetTmp.getLength(), OUString(aSnippet[0]) );
2481  }
2482  }
2483 
2484  pTmpText = &aTmpText;
2485  nTmpIdx = TextFrameIndex(0);
2486  nTmpLen = TextFrameIndex(aTmpText.getLength());
2487  bTextReplaced = true;
2488  }
2489 
2490  if( rInf.GetHyphPos() ) {
2491  sal_Int32 nHyphPos = sal_Int32(*rInf.GetHyphPos());
2492  nTextBreak = TextFrameIndex(rInf.GetOut().GetTextBreak(
2493  *pTmpText, nTextWidth,
2494  u'-', nHyphPos,
2495  sal_Int32(nTmpIdx), sal_Int32(nTmpLen),
2496  nKern, rInf.GetVclCache()));
2497  *rInf.GetHyphPos() = TextFrameIndex((nHyphPos == -1) ? COMPLETE_STRING : nHyphPos);
2498  }
2499  else
2500  {
2501  SwFntAccess aFntAccess(m_aSub[m_nActual].m_nFontCacheId, m_aSub[m_nActual].m_nFontIndex,
2502  &m_aSub[m_nActual], rInf.GetShell());
2503  SwTextGlyphsKey aGlyphsKey{ &rInf.GetOut(), *pTmpText, sal_Int32(nTmpIdx), sal_Int32(nTmpLen) };
2504  SalLayoutGlyphs* pGlyphs
2505  = lcl_CreateLayout(aGlyphsKey, aFntAccess.Get()->GetTextGlyphs()[aGlyphsKey]);
2506  nTextBreak = TextFrameIndex(rInf.GetOut().GetTextBreak(
2507  *pTmpText, nTextWidth,
2508  sal_Int32(nTmpIdx), sal_Int32(nTmpLen),
2509  nKern, rInf.GetVclCache(), pGlyphs));
2510  }
2511 
2512  if (bTextReplaced && sal_Int32(nTextBreak) != -1)
2513  {
2514  if ( nTmpLen != nLn )
2515  nTextBreak = sw_CalcCaseMap( *this, rInf.GetText(),
2516  rInf.GetIdx(), nLn, nTextBreak );
2517  else
2518  nTextBreak = nTextBreak + rInf.GetIdx();
2519  }
2520  }
2521 
2522  TextFrameIndex nTextBreak2 = sal_Int32(nTextBreak) == -1
2524  : nTextBreak;
2525 
2526  if ( ! bCompress )
2527  return nTextBreak2;
2528 
2529  nTextBreak2 = nTextBreak2 - rInf.GetIdx();
2530 
2531  if( nTextBreak2 < nLn )
2532  {
2533  if( !nTextBreak2 && nLn )
2534  nLn = TextFrameIndex(1);
2535  else if (nLn > nTextBreak2 + nTextBreak2)
2536  nLn = nTextBreak2 + nTextBreak2;
2537  std::unique_ptr<long[]> pKernArray( new long[sal_Int32(nLn)] );
2538  rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray.get(),
2539  sal_Int32(rInf.GetIdx()), sal_Int32(nLn));
2540  if( rInf.GetScriptInfo()->Compress( pKernArray.get(), rInf.GetIdx(), nLn,
2541  rInf.GetKanaComp(), static_cast<sal_uInt16>(GetHeight( m_nActual )),
2542  lcl_IsFullstopCentered( rInf.GetOut() ) ) )
2543  {
2544  long nKernAdd = nKern;
2545  TextFrameIndex const nTmpBreak = nTextBreak2;
2546  if( nKern && nTextBreak2 )
2547  nKern *= sal_Int32(nTextBreak2) - 1;
2548  while (nTextBreak2 < nLn && nTextWidth >= pKernArray[sal_Int32(nTextBreak2)] + nKern)
2549  {
2550  nKern += nKernAdd;
2551  ++nTextBreak2;
2552  }
2553  if( rInf.GetHyphPos() )
2554  *rInf.GetHyphPos() += nTextBreak2 - nTmpBreak; // It's not perfect
2555  }
2556  }
2557  nTextBreak2 = nTextBreak2 + rInf.GetIdx();
2558 
2559  return nTextBreak2;
2560 }
2561 
2563 {
2564  const vcl::Font& rFnt = pFont ? *pFont : GetOut().GetFont();
2565  Color nNewColor = COL_BLACK;
2566  bool bChgFntColor = false;
2567  bool bChgLineColor = false;
2568 
2569  if (GetShell() && !GetShell()->GetWin() && GetShell()->GetViewOptions()->IsBlackFont())
2570  {
2571  if ( COL_BLACK != rFnt.GetColor() )
2572  bChgFntColor = true;
2573 
2574  if ( (COL_BLACK != GetOut().GetLineColor()) ||
2575  (COL_BLACK != GetOut().GetOverlineColor()) )
2576  bChgLineColor = true;
2577  }
2578  else
2579  {
2580  // FontColor has to be changed if:
2581  // 1. FontColor = AUTO or 2. IsAlwaysAutoColor is set
2582  // LineColor has to be changed if:
2583  // 1. IsAlwaysAutoColor is set
2584 
2585  bChgLineColor = GetShell() && GetShell()->GetWin() &&
2587 
2588  bChgFntColor = COL_AUTO == rFnt.GetColor() || bChgLineColor;
2589 
2590  if ( bChgFntColor )
2591  {
2592  // check if current background has a user defined setting
2593  const Color* pCol = GetFont() ? GetFont()->GetBackColor() : nullptr;
2594  Color aColor;
2595  if( ! pCol || COL_TRANSPARENT == *pCol )
2596  {
2597  const SvxBrushItem* pItem;
2598  SwRect aOrigBackRect;
2600 
2607  if( GetFrame()->GetBackgroundBrush( aFillAttributes, pItem, pCol, aOrigBackRect, false, /*bConsiderTextBox=*/true ) )
2608  {
2609  if (aFillAttributes.get() && aFillAttributes->isUsed())
2610  {
2611  // First see if fill attributes provide a color.
2612  aColor = Color(aFillAttributes->getAverageColor(aGlobalRetoucheColor.getBColor()));
2613  pCol = &aColor;
2614  }
2615 
2616  // If not, then fall back to the old brush item.
2617  if ( !pCol )
2618  {
2619  pCol = &pItem->GetColor();
2620  }
2621 
2624  if ( *pCol == COL_TRANSPARENT)
2625  pCol = nullptr;
2626  }
2627  else
2628  pCol = nullptr;
2629  }
2630 
2631  // no user defined color at paragraph or font background
2632  if ( ! pCol )
2633  pCol = &aGlobalRetoucheColor;
2634 
2635  if( GetShell() && GetShell()->GetWin() )
2636  {
2637  // here we determine the preferred window text color for painting
2638  const SwViewOption* pViewOption = GetShell()->GetViewOptions();
2639  if(pViewOption->IsPagePreview() &&
2640  !SW_MOD()->GetAccessibilityOptions().GetIsForPagePreviews())
2641  nNewColor = COL_BLACK;
2642  else
2643  // we take the font color from the appearance page
2644  nNewColor = SwViewOption::GetFontColor();
2645  }
2646 
2647  // change painting color depending of dark/bright background
2648  Color aTmpColor( nNewColor );
2649  if ( pCol->IsDark() && aTmpColor.IsDark() )
2650  nNewColor = COL_WHITE;
2651  else if ( pCol->IsBright() && aTmpColor.IsBright() )
2652  nNewColor = COL_BLACK;
2653  }
2654  }
2655 
2656  if ( bChgFntColor || bChgLineColor )
2657  {
2658  Color aNewColor( nNewColor );
2659 
2660  if ( bChgFntColor )
2661  {
2662  if ( pFont && aNewColor != pFont->GetColor() )
2663  {
2664  // only set the new color at the font passed as argument
2665  pFont->SetColor( aNewColor );
2666  }
2667  else if ( aNewColor != GetOut().GetFont().GetColor() )
2668  {
2669  // set new font with new color at output device
2670  vcl::Font aFont( rFnt );
2671  aFont.SetColor( aNewColor );
2672  GetOut().SetFont( aFont );
2673  }
2674  }
2675 
2676  // the underline and overline colors have to be set separately
2677  if ( bChgLineColor )
2678  {
2679  // get current font color or color set at output device
2680  aNewColor = pFont ? pFont->GetColor() : GetOut().GetFont().GetColor();
2681  if ( aNewColor != GetOut().GetLineColor() )
2682  GetOut().SetLineColor( aNewColor );
2683  if ( aNewColor != GetOut().GetOverlineColor() )
2684  GetOut().SetOverlineColor( aNewColor );
2685  }
2686 
2687  return true;
2688  }
2689 
2690  return false;
2691 }
2692 
2694 {
2695  for (SwFntObj* pFntObj = pFntCache->First(); pFntObj; pFntObj = SwFntCache::Next(pFntObj))
2696  pFntObj->GetTextGlyphs().clear();
2697 }
2698 
2699 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const Fraction & GetScaleX() const
long Width() const
long const nHalfSpace
Definition: fntcache.cxx:257
void DrawText(const Point &rStartPt, const OUString &rStr, sal_Int32 nIndex=0, sal_Int32 nLen=-1, MetricVector *pVector=nullptr, OUString *pDisplayText=nullptr, const SalLayoutGlyphs *pLayoutCache=nullptr)
SwViewShell const * GetShell() const
Definition: drawfont.hxx:175
OutDevType GetOutDevType() const
sal_uInt16 m_nExtLeading
Definition: fntcache.hxx:86
void SetDigitLanguage(LanguageType)
const bool bBidiPor
Definition: fntcache.cxx:259
sal_uInt16 GetCachePos() const
Definition: swcache.hxx:162
SwFntObj(const SwSubFont &rFont, const void *nFontCacheId, SwViewShell const *pSh)
Definition: fntcache.cxx:175
long GetSpace() const
Definition: drawfont.hxx:325
sw::WrongListIterator * GetGrammarCheck() const
Definition: drawfont.hxx:229
const SwWrongArea * GetWrongElement(TextFrameIndex nStart)
Definition: wrong.cxx:787
void CreateScrFont(const SwViewShell &rSh, const OutputDevice &rOut)
Definition: fntcache.cxx:470
void SetFontSize(const Size &)
short CheckKerning()
Definition: swfont.hxx:320
constexpr::Color COL_BLACK(0x00, 0x00, 0x00)
bool IsPagePreview() const
Definition: viewopt.hxx:589
virtual SwCacheObj * NewObj() override
Can be use in NewObj.
Definition: fntcache.cxx:2363
const OUString & GetFamilyName() const
SwFntAccess(const void *&rnFontCacheId, sal_uInt16 &rIndex, const void *pOwner, SwViewShell const *pShell, bool bCheck=false)
Definition: fntcache.cxx:2259
vcl::RenderContext * GetpOut() const
Definition: drawfont.hxx:185
bool m_bPaintBlank
Definition: fntcache.hxx:94
std::map< SwTextGlyphsKey, SalLayoutGlyphs > m_aTextGlyphs
Cache of already calculated layout glyphs.
Definition: fntcache.hxx:97
SwFont * GetFont() const
Definition: drawfont.hxx:250
void Lock()
Definition: swcache.cxx:469
long AdjustWidth(long n)
SwCacheObj * m_pObj
Definition: swcache.hxx:193
bool IsVirtual() const
const SwAccessibilityOptions * GetAccessibilityOptions() const
Definition: viewsh.hxx:434
long AdjustX(long nHorzMove)
SwDocShell * GetDocShell()
Definition: doc.hxx:1340
sw::WrongListIterator * GetWrong() const
Definition: drawfont.hxx:221
long Height() const
sal_uInt16 GetFontHeight(const SwViewShell *pSh, const OutputDevice &rOut)
Definition: fntcache.cxx:379
bool m_bSymbol
Definition: fntcache.hxx:93
TextFrameIndex * GetHyphPos() const
Definition: drawfont.hxx:203
bool GetBullet() const
Definition: drawfont.hxx:346
FontLineStyle GetOverline() const
void SwitchHorizontalToVertical(SwRect &rRect) const
Calculates the coordinates of a rectangle when switching from horizontal to vertical layout...
Definition: txtfrm.cxx:476
sal_uIntPtr sal_uLong
static void lcl_DrawLineForWrongListData(SwForbidden &rForbidden, const SwDrawTextInfo &rInf, sw::WrongListIterator *pWList, const CalcLinePosData &rCalcLinePosData, const Size &rPrtFontSize)
Definition: fntcache.cxx:713
Definition: doc.hxx:185
sal_uInt16 GetFontAscent(const SwViewShell *pSh, const OutputDevice &rOut)
Definition: fntcache.cxx:342
sal_uInt16 m_nScrHeight
Definition: fntcache.hxx:89
void SetWeight(FontWeight)
sal_uInt16 GetGuessedLeading() const
Definition: fntcache.hxx:112
ComplexTextLayoutFlags GetLayoutMode() const
bool IsPosMatchesBounds() const
Definition: drawfont.hxx:387
const MapMode & GetMapMode() const
const IDocumentSettingAccess & getIDocumentSettingAccess() const
Provides access to the document setting interface.
Definition: viewsh.cxx:2588
WrongAreaLineType mLineType
Definition: wrong.hxx:73
sal_uInt16 GetWidth() const
Definition: drawfont.hxx:294
long SwTwips
Definition: swtypes.hxx:49
void SetLayoutMode(ComplexTextLayoutFlags nTextLayoutMode)
VclPtr< OutputDevice > m_pOutputDevice
Definition: fntcache.hxx:67
const sal_Unicode CH_BULLET
Definition: swfont.hxx:46
GDIMetaFile * GetConnectMetaFile() const
virtual SfxItemSet & GetItemSet()
void SetDashCount(sal_uInt16 nDashCount)
#define RES_CHRATR_CJK_FONTSIZE
Definition: hintids.hxx:91
Of course Writer needs its own rectangles.
Definition: swrect.hxx:34
static sal_uInt8 lcl_WhichPunctuation(sal_Unicode cChar)
Definition: fntcache.cxx:674
const void * m_pOwner
Definition: swcache.hxx:194
sal_uInt16 GetZoom() const
Definition: fntcache.hxx:123
long AdjustHeight(long n)
static void CJKJustify(const OUString &rText, long *pKernArray, long *pScrArray, TextFrameIndex nStt, TextFrameIndex nLen, LanguageType aLang, long nSpaceAdd, bool bIsSpaceStop)
Definition: porlay.cxx:2381
void SetMapMode()
sal_uInt8 DirType(const TextFrameIndex nPos) const
Definition: porlay.cxx:1466
bool operator<(const SwTextGlyphsKey &l, const SwTextGlyphsKey &r)
Definition: fntcache.cxx:132
VclPtr< OutputDevice > m_pPrinter
Definition: fntcache.hxx:84
void SetKanaDiff(long nNew)
Definition: drawfont.hxx:474
void SetDashLen(sal_Int32 nDashLen)
sal_Int32 GetOfst() const
Definition: drawfont.hxx:273
bool IsVertLRBT() const
Definition: frame.hxx:959
size_t CountCompChg() const
Definition: scriptinfo.hxx:157
vcl::Font & GetFont()
Definition: fntcache.hxx:109
const SwScriptInfo * GetScriptInfo() const
Definition: drawfont.hxx:190
static OutputDevice * GetDefaultDevice()
const Color & GetOverlineColor() const
void SetCursorBidiLevel(sal_uInt8 nNew)
Definition: drawfont.hxx:526
constexpr::Color COL_AUTO(0xFF, 0xFF, 0xFF, 0xFF)
const bool bSwitchH2V
Definition: fntcache.cxx:254
static SwFntObj * Next(SwFntObj *pFntObj)
Definition: fntcache.hxx:142
sal_uInt16 GetFontLeading(const SwViewShell *pSh, const OutputDevice &rOut)
Definition: fntcache.cxx:418
sal_uInt16 sal_Unicode
FontItalic GetItalic()
constexpr::Color COL_TRANSPARENT(0xFF, 0xFF, 0xFF, 0xFF)
void DrawStretchText(const Point &rStartPt, sal_uLong nWidth, const OUString &rStr, sal_Int32 nIndex=0, sal_Int32 nLen=-1)
const SwTextFrame * GetFrame() const
Definition: drawfont.hxx:165
Color mColor
Definition: wrong.hxx:72
FontKerning GetKerning() const
FUNC_TYPE const nType
LINESTYLE_NONE
void setX(long nX)
OUTDEV_WINDOW
const Fraction & GetScaleY() const
bool getBrowseMode() const
Definition: viewopt.hxx:426
const vcl::Font & GetFont() const
SwBreakIt * g_pBreakIt
Definition: breakit.cxx:34
long Compress(long *pKernArray, TextFrameIndex nIdx, TextFrameIndex nLen, const sal_uInt16 nCompress, const sal_uInt16 nFontHeight, const bool bCentered, Point *pPoint=nullptr) const
Definition: porlay.cxx:1708
std::shared_ptr< SdrAllFillAttributesHelper > SdrAllFillAttributesHelperPtr
Definition: format.hxx:38
TextFrameIndex GetCursorOfst(SwDrawTextInfo &rInf)
Definition: fntcache.cxx:2073
void Flush()
Definition: fntcache.cxx:165
o3tl::enumarray< SwFontScript, SwSubFont > m_aSub
Definition: swfont.hxx:131
FontMetric GetFontMetric() const
long GetKern() const
Definition: drawfont.hxx:320
SwDoc * GetDoc() const
Definition: viewsh.hxx:284
bool IsValid() const
sal_uInt16 UnMapDirection(sal_uInt16 nDir, const bool bVertFormat, const bool bVertFormatLRBT)
Definition: swfont.cxx:397
void setY(long nY)
void DrawLine(const Point &rStartPt, const Point &rEndPt)
vcl::TextLayoutCache const * GetVclCache() const
Definition: drawfont.hxx:211
SwFntCache * pFntCache
Definition: fntcache.cxx:66
sal_uInt16 GetKanaComp() const
Definition: drawfont.hxx:307
void SetLanguage(LanguageType)
SwFontScript GetActual() const
Definition: swfont.hxx:180
void SetLen(TextFrameIndex const nNew)
Definition: drawfont.hxx:461
Defines a substring on a given output device, to be used as an std::map<> key.
Definition: fntcache.hxx:65
OUString m_aText
Definition: fntcache.hxx:68
const OUString & GetText() const
Definition: drawfont.hxx:216
sw::WrongListIterator * GetSmartTags() const
Definition: drawfont.hxx:237
vcl::Font * m_pScrFont
Definition: fntcache.hxx:82
vcl::RenderContext & GetRefDev() const
Definition: viewsh.cxx:2077
static bool IsArabicText(const OUString &rText, TextFrameIndex nStt, TextFrameIndex nLen)
Checks if text is Arabic text.
Definition: porlay.cxx:1910
void CreatePrtFont(const OutputDevice &rOut)
Definition: fntcache.cxx:206
vcl::Font * m_pPrtFont
Definition: fntcache.hxx:83
const Color & GetColor() const
OUTDEV_PRINTER
bool SnapToGrid() const
Definition: drawfont.hxx:377
void DrawTextArray(const Point &rStartPt, const OUString &rStr, const long *pDXAry, sal_Int32 nIndex=0, sal_Int32 nLen=-1, SalLayoutFlags flags=SalLayoutFlags::NONE, const SalLayoutGlyphs *pLayoutCache=nullptr)
void SetLineColor()
bool ApplyAutoColor(vcl::Font *pFnt=nullptr)
Definition: fntcache.cxx:2562
sal_uInt8 * mnFontCacheIdCounter
Definition: fntcache.cxx:70
#define SW_MOD()
Definition: swmodule.hxx:255
void GuessLeading(const SwViewShell &rSh, const FontMetric &rMet)
Definition: fntcache.cxx:562
SwFontScript m_nActual
Definition: swfont.hxx:160
long GetDescent() const
bool IsIgnoreFrameRTL() const
Definition: drawfont.hxx:382
long AdjustY(long nVertMove)
TextFrameIndex const nCnt
Definition: fntcache.cxx:253
SwViewShell const * m_pShell
Definition: fntcache.hxx:149
void SetDistance(sal_Int32 nDistance)
static bool lcl_IsFullstopCentered(const vcl::RenderContext &rOut)
Definition: fntcache.cxx:702
bool IsDark() const
bool IsFullstopCentered() const
ComplexTextLayoutFlags
SwPageFrame * FindPageFrame()
Definition: frame.hxx:658
SwTextGridItem const * GetGridItem(SwPageFrame const *const)
Definition: pagechg.cxx:2516
int i
bool IsBright() const
const Color * GetBackColor() const
Definition: swfont.hxx:188
const sal_Unicode CH_BLANK
Definition: swfont.hxx:42
long GetHeight() const
Definition: swfont.hxx:280
bool IsWordLineMode() const
sal_uInt16 m_nZoom
Definition: fntcache.hxx:92
virtual SfxStyleSheetBasePool * GetStyleSheetPool() override
For Style PI.
Definition: docsh.cxx:1160
const Color & GetLineColor() const
TextFrameIndex sw_CalcCaseMap(const SwFont &rFnt, const OUString &rOrigString, TextFrameIndex nOfst, TextFrameIndex nLen, TextFrameIndex nIdx)
Definition: fntcap.cxx:59
#define WRONG_SHOW_MIN
Definition: fntcache.cxx:666
SwDrawTextInfo & rInf
Definition: fntcache.cxx:251
sal_uInt16 GetPropWidth() const
Definition: fntcache.hxx:124
float u
Provides access to settings of a document.
const Size & GetFontSize() const
#define NON_PRINTING_CHARACTER_COLOR
Definition: txtfrm.hxx:52
FontStrikeout GetStrikeout() const
void SetOverlineColor()
sal_uInt16 const m_nPropWidth
Definition: fntcache.hxx:91
OUString SwResId(const char *pId)
Definition: swmodule.cxx:191
Shell * m_pShell
long GetAscent() const
long GetExternalLeading() const
std::unique_ptr< SalLayout > ImplLayout(const OUString &, sal_Int32 nIndex, sal_Int32 nLen, const Point &rLogicPos=Point(0, 0), long nLogicWidth=0, const long *pLogicDXArray=nullptr, SalLayoutFlags flags=SalLayoutFlags::NONE, vcl::TextLayoutCache const *=nullptr, const SalLayoutGlyphs *pGlyphs=nullptr) const
void DrawWaveLine(const Point &rStartPos, const Point &rEndPos)
long GetTextHeight() const
static void lcl_calcLinePos(const CalcLinePosData &rData, Point &rStart, Point &rEnd, TextFrameIndex const nStart, TextFrameIndex const nWrLen)
Definition: fntcache.cxx:279
long X() const
bool GetGreyWave() const
Definition: drawfont.hxx:367
void Flush()
Definition: swcache.cxx:150
static bool lcl_IsFontAdjustNecessary(const vcl::RenderContext &rOutDev, const vcl::RenderContext &rRefDev)
Definition: fntcache.cxx:240
CalcLinePosData(SwDrawTextInfo &_rInf, vcl::Font &_rFont, TextFrameIndex const _nCnt, const bool _bSwitchH2V, const bool _bSwitchH2VLRBT, const bool _bSwitchL2R, long _nHalfSpace, long *_pKernArray, const bool _bBidiPor)
Definition: fntcache.cxx:261
#define LANGUAGE_THAI
std::vector< std::pair< TextFrameIndex, TextFrameIndex > > SwForbidden
Definition: fntcache.cxx:711
void SetColor(const Color &)
bool Check(TextFrameIndex &rStart, TextFrameIndex &rLen)
Definition: wrong.cxx:672
TextFrameIndex GetTextBreak(SwDrawTextInfo const &rInf, long nTextWidth)
Definition: fntcache.cxx:2369
const bool bSwitchL2R
Definition: fntcache.cxx:256
Point PixelToLogic(const Point &rDevicePt) const
Point LogicToPixel(const Point &rLogicPt) const
static constexpr Color gWaveCol(COL_GRAY)
void SwitchLTRtoRTL(SwRect &rRect) const
Calculates the coordinates of a rectangle when switching from LTR to RTL layout.
Definition: txtfrm.cxx:686
sal_Int32 m_nIndex
Definition: fntcache.hxx:69
vcl::Font & rFont
Definition: fntcache.cxx:252
const css::lang::Locale & GetLocale(const LanguageType aLang)
Definition: breakit.hxx:67
vcl::Font * GetScrFont()
Definition: fntcache.hxx:108
long GetSperren() const
Definition: drawfont.hxx:312
void SetDevFont(const SwViewShell *pSh, OutputDevice &rOut)
Definition: fntcache.cxx:642
LanguageType GetLanguage() const
Definition: swfont.hxx:279
static long nPixWidth
Definition: fntcache.hxx:99
const Color & GetColor() const
short GetOrientation() const
SwFntObj * Get()
Definition: fntcache.hxx:157
sal_uInt32 GetHeight() const
sal_Int32 m_nLength
Definition: fntcache.hxx:70
static bool lcl_IsMonoSpaceFont(const vcl::RenderContext &rOut)
Definition: fntcache.cxx:695
long GetKanaDiff() const
Definition: drawfont.hxx:286
virtual ~SwFntObj() override
Definition: fntcache.cxx:198
const SfxPoolItem & Get(sal_uInt16 nWhich, bool bSrchInParent=true) const
FontWeight GetWeight()
unsigned char sal_uInt8
TextFrameIndex GetNumberOfBlanks() const
Definition: drawfont.hxx:333
const SwViewOption * GetViewOptions() const
Definition: viewsh.hxx:426
vcl::Window * GetWin() const
Definition: viewsh.hxx:340
The Cache object base class Users of the Cache must derrive a class from the SwCacheObj and store the...
Definition: swcache.hxx:133
void SetFont(const vcl::Font &rNewFont)
const o3tl::enumarray< SvxAdjust, unsigned short > aSvxToUnoAdjust USHRT_MAX
Definition: unosett.cxx:259
const Point & GetPos() const
Definition: drawfont.hxx:195
LanguageType GetDigitLanguage() const
static MapMode * pPixMap
Definition: fntcache.hxx:100
TextFrameIndex GetLen() const
Definition: drawfont.hxx:268
sal_uInt16 m_nPrtAscent
Definition: fntcache.hxx:88
static Color & GetFontColor()
Definition: viewopt.cxx:427
static TextFrameIndex ThaiJustify(const OUString &rText, long *pKernArray, long *pScrArray, TextFrameIndex nIdx, TextFrameIndex nLen, TextFrameIndex nNumberOfBlanks=TextFrameIndex(0), long nSpaceAdd=0)
Performs a thai justification on the kerning array.
Definition: porlay.cxx:2084
SwFntObj * First()
Definition: fntcache.hxx:137
long GetInternalLeading() const
bool IsRightToLeft() const
Definition: frame.hxx:963
SwFntObj * pLastFont
Definition: fntcache.cxx:68
sal_uInt16 GetZoom() const
Definition: viewopt.hxx:459
void SwClearFntCacheTextGlyphs()
Clears the pre-calculated text glyphs in all SwFntObj instances.
Definition: fntcache.cxx:2693
static bool isKorean(LanguageType nLang)
long GetBulletOffset() const
bool IsPrtFormat() const
Definition: viewopt.hxx:495
constexpr::Color COL_WHITE(0xFF, 0xFF, 0xFF)
SwFontScript
Definition: swfont.hxx:119
sal_uInt16 GetGridWidth(SwTextGridItem const &, SwDoc const &)
Definition: pagechg.cxx:2530
virtual bool get(DocumentSettingId id) const =0
Return the specified document setting.
vcl::RenderContext & GetOut() const
Definition: drawfont.hxx:180
long GetTextWidth(const OUString &rStr, sal_Int32 nIndex=0, sal_Int32 nLen=-1, vcl::TextLayoutCache const *=nullptr, SalLayoutGlyphs const *const pLayoutCache=nullptr) const
basegfx::BColor getBColor() const
bool IsSnapToChars() const
Definition: tgrditem.hxx:100
void Unlock()
Definition: swcache.cxx:475
bool IsSameInstance(const Font &) const
sal_Int32 GetTextBreak(const OUString &rStr, long nTextWidth, sal_Int32 nIndex, sal_Int32 nLen=-1, long nCharExtra=0, vcl::TextLayoutCache const *=nullptr, const SalLayoutGlyphs *pGlyphs=nullptr) const
void SetItalic(FontItalic)
css::uno::Reference< css::i18n::XBreakIterator > const & GetBreakIter()
Definition: breakit.hxx:62
FontLineStyle GetUnderline() const
size_t CountKashida() const
Definition: scriptinfo.hxx:146
void DrawText(SwDrawTextInfo &rInf)
Definition: fntcache.cxx:821
bool IsVertical() const
Definition: frame.hxx:949
void SAL_CALL first(const css::awt::SpinEvent &rEvent) override
OutputDevice * get() const
#define SPACING_PRECISION_FACTOR
Definition: scriptinfo.hxx:37
Access class for the Cache.
Definition: swcache.hxx:186
TextFrameIndex GetIdx() const
Definition: drawfont.hxx:263
SwTextGrid GetGridType() const
Definition: tgrditem.hxx:81
bool IsSpaceStop() const
Definition: drawfont.hxx:372
bool IsValid() const
sal_uInt16 m_nGuessedLeading
Definition: fntcache.hxx:85
long GetTextArray(const OUString &rStr, long *pDXAry, sal_Int32 nIndex=0, sal_Int32 nLen=-1, vcl::TextLayoutCache const *=nullptr, SalLayoutGlyphs const *const pLayoutCache=nullptr) const
STRIKEOUT_NONE
bool IsStarSymbol(const OUString &rFontName)
FontLineStyle
void ChgFnt(SwViewShell const *pSh, OutputDevice &rOut)
Definition: swfont.hxx:173
vcl::Font m_aFont
Definition: fntcache.hxx:81
long *const pKernArray
Definition: fntcache.cxx:258
void Push(PushFlags nFlags=PushFlags::ALL)
virtual SfxStyleSheetBase * Find(const OUString &, SfxStyleFamily eFam, SfxStyleSearchBits n=SfxStyleSearchBits::All)
sal_Int32 KashidaJustify(long *pKernArray, long *pScrArray, TextFrameIndex nStt, TextFrameIndex nLen, long nSpaceAdd=0) const
Performs a kashida justification on the kerning array.
Definition: porlay.cxx:1825
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...
void setWidth(long nWidth)
const bool bSwitchH2VLRBT
Definition: fntcache.cxx:255
sal_uInt16 GetExternalLeading() const
Definition: fntcache.hxx:113
aStr
FontStrikeout
Color aGlobalRetoucheColor
Definition: paintfrm.cxx:233
TextFrameIndex GetCapitalBreak(SwViewShell const *pSh, const OutputDevice *pOut, const SwScriptInfo *pScript, const OUString &rText, long nTextWidth, TextFrameIndex nIdx, TextFrameIndex nLen)
Definition: fntcap.cxx:211
const sal_Int32 COMPLETE_STRING
Definition: swtypes.hxx:61
bool IsAvail() const
Shorthand for those who know that they did not override isAvailable() FIXME: wtf? ...
Definition: swcache.hxx:208
rtl_TextEncoding GetCharSet() const
long Y() const
const void * GetOwner() const
Definition: swcache.hxx:159
sal_uInt16 m_nScrAscent
Definition: fntcache.hxx:87
Size GetTextSize(SwDrawTextInfo &rInf)
determine the TextSize (of the printer)
Definition: fntcache.cxx:1871
sal_uInt16 m_nPrtHeight
Definition: fntcache.hxx:90
static vcl::DeleteOnDeinit< VclPtr< OutputDevice > > s_pFntObjPixOut(new VclPtr< OutputDevice >)
void setHeight(long nHeight)