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 <cstdint>
24 #include <cstdlib>
25 
26 #include <i18nlangtag/mslangid.hxx>
27 #include <vcl/outdev.hxx>
28 #include <vcl/print.hxx>
29 #include <vcl/lineinfo.hxx>
30 #include <vcl/metric.hxx>
31 #include <vcl/svapp.hxx>
32 #include <vcl/lazydelete.hxx>
33 #include <com/sun/star/i18n/CharacterIteratorMode.hpp>
34 #include <com/sun/star/i18n/WordType.hpp>
35 #include <com/sun/star/i18n/XBreakIterator.hpp>
36 #include <breakit.hxx>
37 #include <paintfrm.hxx>
38 #include <viewsh.hxx>
39 #include <viewopt.hxx>
40 #include <fntcache.hxx>
42 #include <swfont.hxx>
43 #include <wrong.hxx>
44 #include <dbg_lay.hxx>
45 #include <txtfrm.hxx>
46 #include <pagefrm.hxx>
47 #include <pagedesc.hxx>
48 #include <tgrditem.hxx>
49 #include <scriptinfo.hxx>
50 #include <editeng/brushitem.hxx>
51 #include <swmodule.hxx>
52 #include <accessibilityoptions.hxx>
55 #include <doc.hxx>
56 #include <editeng/fhgtitem.hxx>
57 #include <vcl/glyphitem.hxx>
58 #include <vcl/vcllayout.hxx>
59 #include <docsh.hxx>
60 #include <strings.hrc>
61 #include <fntcap.hxx>
63 
64 using namespace ::com::sun::star;
65 
66 // global variables declared in fntcache.hxx
67 // FontCache is created in txtinit.cxx TextInit_ and deleted in TextFinit
68 SwFntCache *pFntCache = nullptr;
69 // last Font set by ChgFntCache
70 SwFntObj *pLastFont = nullptr;
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, std::uintptr_t nFontCacheId, SwViewShell const *pSh)
176  : SwCacheObj(reinterpret_cast<void *>(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_WAVE == wrongArea->mLineType)
788  {
789  vcl::ScopedAntialiasing a(rInf.GetOut(), true);
790  rInf.GetOut().SetLineColor( wrongArea->mColor );
791  rInf.GetOut().DrawWaveLine( aStart, aEnd, 1 );
792  }
793  else if (WRONGAREA_BOLDWAVE == wrongArea->mLineType)
794  {
795  vcl::ScopedAntialiasing a(rInf.GetOut(), true);
796  rInf.GetOut().SetLineColor( wrongArea->mColor );
797  rInf.GetOut().DrawWaveLine( aStart, aEnd, 2 );
798  }
799  else if (WRONGAREA_BOLD == wrongArea->mLineType)
800  {
801  rInf.GetOut().SetLineColor( wrongArea->mColor );
802 
803  aStart.AdjustY(30 );
804  aEnd.AdjustY(30 );
805 
806  LineInfo aLineInfo( LineStyle::Solid, 26 );
807 
808  rInf.GetOut().DrawLine( aStart, aEnd, aLineInfo );
809  }
810  else if (WRONGAREA_DASHED == wrongArea->mLineType)
811  {
812  rInf.GetOut().SetLineColor( wrongArea->mColor );
813 
814  aStart.AdjustY(30 );
815  aEnd.AdjustY(30 );
816 
817  LineInfo aLineInfo( LineStyle::Dash );
818  aLineInfo.SetDistance( 40 );
819  aLineInfo.SetDashLen( 1 );
820  aLineInfo.SetDashCount(1);
821 
822  rInf.GetOut().DrawLine( aStart, aEnd, aLineInfo );
823  }
824  }
825  }
826 
827  nStart = nEnd + rInf.GetIdx();
828  nWrLen = rInf.GetIdx() + rInf.GetLen() - nStart;
829  }
830  while (nWrLen && pWList->Check( nStart, nWrLen ));
831 
832  rInf.GetOut().SetLineColor( aCol );
833 
834  if (rInf.GetOut().GetConnectMetaFile())
835  rInf.GetOut().Pop();
836 }
837 
839 {
840  OSL_ENSURE( rInf.GetShell(), "SwFntObj::DrawText without shell" );
841 
842  OutputDevice& rRefDev = rInf.GetShell()->GetRefDev();
843  OutputDevice* pWin = rInf.GetShell()->GetWin();
844 
845  // true if pOut is the printer and the printer has been used for formatting
846  const bool bPrt = OUTDEV_PRINTER == rInf.GetOut().GetOutDevType() &&
847  OUTDEV_PRINTER == rRefDev.GetOutDevType();
848  const bool bBrowse = ( pWin &&
849  rInf.GetShell()->GetViewOptions()->getBrowseMode() &&
850  !rInf.GetShell()->GetViewOptions()->IsPrtFormat() &&
851  !rInf.GetBullet() &&
852  ( rInf.GetSpace() || !rInf.GetKern() ) &&
853  !rInf.GetWrong() &&
854  !rInf.GetGrammarCheck() &&
855  !rInf.GetSmartTags() &&
856  !rInf.GetGreyWave() );
857 
858  // bDirectPrint indicates that we can enter the branch which calls
859  // the DrawText functions instead of calling the DrawTextArray functions
860  const bool bDirectPrint = bPrt || bBrowse;
861 
862  // Condition for output font / refdev font adjustment
863  const bool bUseScrFont =
864  lcl_IsFontAdjustNecessary( rInf.GetOut(), rRefDev );
865 
866  vcl::Font* pTmpFont = bUseScrFont ? m_pScrFont : m_pPrtFont;
867 
868  // bDirectPrint and bUseScrFont should have these values:
869 
870  // Outdev / RefDef | Printer | VirtPrinter | Window
871 
872  // Printer | 1 - 0 | 0 - 1 | -
873 
874  // VirtPrinter/PDF | 0 - 1 | 0 - 1 | -
875 
876  // Window/VirtWindow| 0 - 1 | 0 - 1 | 1 - 0
877 
878  // Exception: During painting of a Writer OLE object, we do not have
879  // a window. Therefore bUseSrcFont is always 0 in this case.
880 
881 #if OSL_DEBUG_LEVEL > 0
882 
883  const bool bNoAdjust = bPrt ||
884  ( pWin &&
885  rInf.GetShell()->GetViewOptions()->getBrowseMode() &&
886  !rInf.GetShell()->GetViewOptions()->IsPrtFormat() );
887 
888  if ( OUTDEV_PRINTER == rInf.GetOut().GetOutDevType() )
889  {
890  // Printer output
891  if ( OUTDEV_PRINTER == rRefDev.GetOutDevType() )
892  {
893  OSL_ENSURE( bNoAdjust && !bUseScrFont, "Outdev Check failed" );
894  }
895  else if ( rRefDev.IsVirtual() )
896  {
897  OSL_ENSURE( !bNoAdjust && bUseScrFont, "Outdev Check failed" );
898  }
899  else
900  {
901  OSL_FAIL( "Outdev Check failed" );
902  }
903  }
904  else if ( rInf.GetOut().IsVirtual() && ! pWin )
905  {
906  // PDF export
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
916  {
917  OSL_FAIL( "Outdev Check failed" );
918  }
919  }
920  else if ( OUTDEV_WINDOW == rInf.GetOut().GetOutDevType() ||
921  ( rInf.GetOut().IsVirtual() && pWin ) )
922  {
923  // Window or virtual window
924  if ( OUTDEV_PRINTER == rRefDev.GetOutDevType() )
925  {
926  OSL_ENSURE( !bNoAdjust && bUseScrFont, "Outdev Check failed" );
927  }
928  else if ( rRefDev.IsVirtual() )
929  {
930  OSL_ENSURE( !bNoAdjust && bUseScrFont, "Outdev Check failed" );
931  }
932  else if ( OUTDEV_WINDOW == rRefDev.GetOutDevType() )
933  {
934  OSL_ENSURE( bNoAdjust && !bUseScrFont, "Outdev Check failed" );
935  }
936  else
937  {
938  OSL_FAIL( "Outdev Check failed" );
939  }
940  }
941  else
942  {
943  OSL_FAIL( "Outdev Check failed" );
944  }
945 
946 #endif
947 
948  // robust: better use the printer font instead of using no font at all
949  OSL_ENSURE( pTmpFont, "No screen or printer font?" );
950  if ( ! pTmpFont )
951  pTmpFont = m_pPrtFont;
952 
953  // HACK: LINESTYLE_WAVE must not be abused any more, hence the grey wave
954  // line of the ExtendedAttributeSets will appear in the font color first
955 
956  const bool bSwitchH2V = rInf.GetFrame() && rInf.GetFrame()->IsVertical();
957  const bool bSwitchH2VLRBT = rInf.GetFrame() && rInf.GetFrame()->IsVertLRBT();
958  const bool bSwitchL2R = rInf.GetFrame() && rInf.GetFrame()->IsRightToLeft() &&
959  ! rInf.IsIgnoreFrameRTL();
960  const ComplexTextLayoutFlags nMode = rInf.GetOut().GetLayoutMode();
961  const bool bBidiPor = ( bSwitchL2R !=
962  ( ComplexTextLayoutFlags::Default != ( ComplexTextLayoutFlags::BiDiRtl & nMode ) ) );
963 
964  // be sure to have the correct layout mode at the printer
965  if ( m_pPrinter )
966  {
969  }
970 
971  Point aTextOriginPos( rInf.GetPos() );
972  if( !bPrt )
973  {
974  if( rInf.GetpOut() != *s_pFntObjPixOut.get() || rInf.GetOut().GetMapMode() != *pPixMap )
975  {
976  *pPixMap = rInf.GetOut().GetMapMode();
977  (*s_pFntObjPixOut.get()) = rInf.GetpOut();
978  Size aTmp( 1, 1 );
979  nPixWidth = rInf.GetOut().PixelToLogic( aTmp ).Width();
980  }
981 
982  aTextOriginPos.AdjustX(rInf.GetFrame()->IsRightToLeft() ? 0 : nPixWidth );
983  }
984 
985  Color aOldColor( pTmpFont->GetColor() );
986  bool bChgColor = rInf.ApplyAutoColor( pTmpFont );
987  if( !pTmpFont->IsSameInstance( rInf.GetOut().GetFont() ) )
988  rInf.GetOut().SetFont( *pTmpFont );
989  if ( bChgColor )
990  pTmpFont->SetColor( aOldColor );
991 
992  if (TextFrameIndex(COMPLETE_STRING) == rInf.GetLen())
993  rInf.SetLen( TextFrameIndex(rInf.GetText().getLength()) );
994 
995  // ASIAN LINE AND CHARACTER GRID MODE START
996 
997  if ( rInf.GetFrame() && rInf.SnapToGrid() && rInf.GetFont() &&
998  SwFontScript::CJK == rInf.GetFont()->GetActual() )
999  {
1000  SwTextGridItem const*const pGrid(GetGridItem(rInf.GetFrame()->FindPageFrame()));
1001 
1002  // ASIAN LINE AND CHARACTER GRID MODE: Do we want to snap asian characters to the grid?
1003  if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && pGrid->IsSnapToChars())
1004  {
1005  //for textgrid refactor
1006  //const sal_uInt16 nGridWidth = pGrid->GetBaseHeight();
1007  const SwDoc* pDoc = rInf.GetShell()->GetDoc();
1008  const sal_uInt16 nGridWidth = GetGridWidth(*pGrid, *pDoc);
1009 
1010  // kerning array - gives the absolute position of end of each character
1011  std::unique_ptr<long[]> pKernArray(new long[sal_Int32(rInf.GetLen())]);
1012 
1013  if ( m_pPrinter )
1014  m_pPrinter->GetTextArray( rInf.GetText(), pKernArray.get(),
1015  sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()));
1016  else
1017  rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray.get(),
1018  sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()));
1019 
1020  // Change the average width per character to an appropriate grid width
1021  // basically get the ratio of the avg width to the grid unit width, then
1022  // multiple this ratio to give the new avg width - which in this case
1023  // gives a new grid width unit size
1024 
1025  long nAvgWidthPerChar = pKernArray[sal_Int32(rInf.GetLen()) - 1] / sal_Int32(rInf.GetLen());
1026 
1027  const sal_uLong nRatioAvgWidthCharToGridWidth = nAvgWidthPerChar ?
1028  ( nAvgWidthPerChar - 1 ) / nGridWidth + 1:
1029  1;
1030 
1031  nAvgWidthPerChar = nRatioAvgWidthCharToGridWidth * nGridWidth;
1032 
1033  // the absolute end position of the first character is also its width
1034  long nCharWidth = pKernArray[ 0 ];
1035  sal_uLong nHalfWidth = nAvgWidthPerChar / 2;
1036 
1037  long nNextFix=0;
1038 
1039  // we work out the start position (origin) of the first character,
1040  // and we set the next "fix" offset to half the width of the char.
1041  // The exceptions are for punctuation characters that are not centered
1042  // so in these cases we just add half a regular "average" character width
1043  // to the first characters actual width to allow the next character to
1044  // be centred automatically
1045  // If the character is "special right", then the offset is correct already
1046  // so the fix offset is as normal - half the average character width
1047 
1048  sal_Unicode cChar = rInf.GetText()[ sal_Int32(rInf.GetIdx()) ];
1050  switch ( nType )
1051  {
1052  // centre character
1053  case SwScriptInfo::NONE :
1054  aTextOriginPos.AdjustX(( nAvgWidthPerChar - nCharWidth ) / 2 );
1055  nNextFix = nCharWidth / 2;
1056  break;
1058  nNextFix = nHalfWidth;
1059  break;
1060  // punctuation
1061  default:
1062  aTextOriginPos.AdjustX(nAvgWidthPerChar - nCharWidth );
1063  nNextFix = nCharWidth - nHalfWidth;
1064  }
1065 
1066  // calculate offsets
1067  for (sal_Int32 j = 1; j < sal_Int32(rInf.GetLen()); ++j)
1068  {
1069  long nCurrentCharWidth = pKernArray[ j ] - pKernArray[ j - 1 ];
1070  nNextFix += nAvgWidthPerChar;
1071 
1072  // almost the same as getting the offset for the first character:
1073  // punctuation characters are not centered, so just add half an
1074  // average character width minus the characters actual char width
1075  // to get the offset into the centre of the next character
1076 
1077  cChar = rInf.GetText()[ sal_Int32(rInf.GetIdx()) + j ];
1078  nType = lcl_WhichPunctuation( cChar );
1079  switch ( nType )
1080  {
1081  case SwScriptInfo::NONE :
1082  pKernArray[ j - 1 ] = nNextFix - ( nCurrentCharWidth / 2 );
1083  break;
1085  pKernArray[ j - 1 ] = nNextFix - nHalfWidth;
1086  break;
1087  default:
1088  pKernArray[ j - 1 ] = nNextFix + nHalfWidth - nCurrentCharWidth;
1089  }
1090  }
1091 
1092  // the layout engine requires the total width of the output
1093  pKernArray[sal_Int32(rInf.GetLen()) - 1] = rInf.GetWidth() -
1094  aTextOriginPos.X() + rInf.GetPos().X() ;
1095 
1096  if ( bSwitchH2V )
1097  rInf.GetFrame()->SwitchHorizontalToVertical( aTextOriginPos );
1098 
1099  rInf.GetOut().DrawTextArray( aTextOriginPos, rInf.GetText(),
1100  pKernArray.get(), sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()));
1101 
1102  return;
1103  }
1104  }
1105 
1106  // For text grid refactor
1107  // ASIAN LINE AND CHARACTER GRID MODE START: not snap to characters
1108 
1109  if ( rInf.GetFrame() && rInf.SnapToGrid() )
1110  {
1111  SwTextGridItem const*const pGrid(GetGridItem(rInf.GetFrame()->FindPageFrame()));
1112 
1113  // ASIAN LINE AND CHARACTER GRID MODE - do not snap to characters
1114  if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && !pGrid->IsSnapToChars() )
1115  {
1116  const long nGridWidthAdd = EvalGridWidthAdd( pGrid, rInf );
1117 
1118  std::unique_ptr<long[]> pKernArray(new long[sal_Int32(rInf.GetLen())]);
1119 
1120  if ( m_pPrinter )
1121  m_pPrinter->GetTextArray( rInf.GetText(), pKernArray.get(),
1122  sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()));
1123  else
1124  rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray.get(),
1125  sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()));
1126  if ( bSwitchH2V )
1127  rInf.GetFrame()->SwitchHorizontalToVertical( aTextOriginPos );
1128  if ( rInf.GetSpace() || rInf.GetKanaComp())
1129  {
1130  long nSpaceAdd = rInf.GetSpace() / SPACING_PRECISION_FACTOR;
1131  if ( rInf.GetFont() && rInf.GetLen() )
1132  {
1133  bool bSpecialJust = false;
1134  const SwScriptInfo* pSI = rInf.GetScriptInfo();
1135  const SwFontScript nActual = rInf.GetFont()->GetActual();
1137  if( SwFontScript::CJK == nActual && rInf.GetKanaComp() &&
1138  pSI && pSI->CountCompChg() &&
1139  lcl_IsMonoSpaceFont( *(rInf.GetpOut()) ) )
1140  {
1141  pSI->Compress( pKernArray.get(), rInf.GetIdx(), rInf.GetLen(),
1142  rInf.GetKanaComp(), static_cast<sal_uInt16>(m_aFont.GetFontSize().Height()), lcl_IsFullstopCentered( rInf.GetOut() ) , &aTextOriginPos );
1143  bSpecialJust = true;
1144  }
1146  if ( ( SwFontScript::CJK == nActual || SwFontScript::Latin == nActual ) && nSpaceAdd )
1147  {
1149  if (!MsLangId::isKorean(aLang))
1150  {
1151  long nSpaceSum = nSpaceAdd;
1152  for (sal_Int32 nI = 0; nI < sal_Int32(rInf.GetLen()); ++nI)
1153  {
1154  pKernArray[ nI ] += nSpaceSum;
1155  nSpaceSum += nSpaceAdd;
1156  }
1157  bSpecialJust = true;
1158  nSpaceAdd = 0;
1159  }
1160  }
1161  long nGridAddSum = nGridWidthAdd;
1162  for (sal_Int32 i = 0; i < sal_Int32(rInf.GetLen()); i++, nGridAddSum += nGridWidthAdd )
1163  {
1164  pKernArray[i] += nGridAddSum;
1165  }
1166  long nKernSum = rInf.GetKern();
1167  if ( bSpecialJust || rInf.GetKern() )
1168  {
1169  for (sal_Int32 i = 0; i < sal_Int32(rInf.GetLen()); i++, nKernSum += rInf.GetKern())
1170  {
1171  if (CH_BLANK == rInf.GetText()[sal_Int32(rInf.GetIdx())+i])
1172  nKernSum += nSpaceAdd;
1173  pKernArray[i] += nKernSum;
1174  }
1177  if( m_bPaintBlank && rInf.GetLen() && (CH_BLANK ==
1178  rInf.GetText()[sal_Int32(rInf.GetIdx() + rInf.GetLen()) - 1]))
1179  {
1182  if (TextFrameIndex(1) == rInf.GetLen())
1183  {
1184  pKernArray[0] = rInf.GetWidth() + nSpaceAdd;
1185  rInf.GetOut().DrawTextArray( aTextOriginPos, rInf.GetText(),
1186  pKernArray.get(), sal_Int32(rInf.GetIdx()), 1);
1187  }
1188  else
1189  {
1190  pKernArray[sal_Int32(rInf.GetLen()) - 2] += nSpaceAdd;
1191  rInf.GetOut().DrawTextArray( aTextOriginPos, rInf.GetText(),
1192  pKernArray.get(), sal_Int32(rInf.GetIdx()),
1193  sal_Int32(rInf.GetLen()));
1194  }
1195  }
1196  else
1197  {
1198  rInf.GetOut().DrawTextArray( aTextOriginPos, rInf.GetText(),
1199  pKernArray.get(), sal_Int32(rInf.GetIdx()),
1200  sal_Int32(rInf.GetLen()));
1201  }
1202  }
1203  else
1204  {
1205  sal_Int32 i;
1206  long nSpaceSum = 0;
1207  for (i = 0; i < sal_Int32(rInf.GetLen()); i++)
1208  {
1209  if(CH_BLANK == rInf.GetText()[sal_Int32(rInf.GetIdx()) + i])
1210  nSpaceSum += nSpaceAdd + nKernSum;
1211 
1212  pKernArray[i] += nSpaceSum;
1213  }
1214 
1215  rInf.GetOut().DrawTextArray(aTextOriginPos,
1216  rInf.GetText(), pKernArray.get(),
1217  sal_Int32(rInf.GetIdx()),
1218  sal_Int32(rInf.GetLen()));
1219  }
1220  }
1221  }
1222  else
1223  {
1224  //long nKernAdd = rInf.GetKern();
1225  long nKernAdd = 0;
1226  long nGridAddSum = nGridWidthAdd + nKernAdd;
1227  for (sal_Int32 i = 0; i < sal_Int32(rInf.GetLen());
1228  i++, nGridAddSum += nGridWidthAdd + nKernAdd)
1229  {
1230  pKernArray[i] += nGridAddSum;
1231  }
1232  rInf.GetOut().DrawTextArray( aTextOriginPos, rInf.GetText(),
1233  pKernArray.get(), sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()));
1234  }
1235  return;
1236  }
1237  }
1238 
1239  // DIRECT PAINTING WITHOUT SCREEN ADJUSTMENT
1240 
1241  if ( bDirectPrint )
1242  {
1243  const Fraction aTmp( 1, 1 );
1244  bool bStretch = rInf.GetWidth() && (rInf.GetLen() > TextFrameIndex(1)) && bPrt
1245  && ( aTmp != rInf.GetOut().GetMapMode().GetScaleX() );
1246 
1247  if ( bSwitchL2R )
1248  rInf.GetFrame()->SwitchLTRtoRTL( aTextOriginPos );
1249 
1250  if ( bSwitchH2V )
1251  rInf.GetFrame()->SwitchHorizontalToVertical( aTextOriginPos );
1252 
1253  // In the good old days we used to have a simple DrawText if the
1254  // output device is the printer. Now we need a DrawTextArray if
1255  // 1. KanaCompression is enabled
1256  // 2. Justified alignment
1257  // Simple kerning is handled by DrawStretchText
1258  if( rInf.GetSpace() || rInf.GetKanaComp() )
1259  {
1260  std::unique_ptr<long[]> pKernArray(new long[sal_Int32(rInf.GetLen())]);
1261  rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray.get(),
1262  sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()));
1263 
1264  if( bStretch )
1265  {
1266  sal_Int32 nZwi = sal_Int32(rInf.GetLen()) - 1;
1267  long nDiff = rInf.GetWidth() - pKernArray[ nZwi ]
1268  - sal_Int32(rInf.GetLen()) * rInf.GetKern();
1269  long nRest = nDiff % nZwi;
1270  long nAdd;
1271  if( nRest < 0 )
1272  {
1273  nAdd = -1;
1274  nRest += nZwi;
1275  }
1276  else
1277  {
1278  nAdd = +1;
1279  nRest = nZwi - nRest;
1280  }
1281  nDiff /= nZwi;
1282  long nSum = nDiff;
1283  for( sal_Int32 i = 0; i < nZwi; )
1284  {
1285  pKernArray[ i ] += nSum;
1286  if( ++i == nRest )
1287  nDiff += nAdd;
1288  nSum += nDiff;
1289  }
1290  }
1291 
1292  // Modify Array for special justifications
1293 
1294  long nSpaceAdd = rInf.GetSpace() / SPACING_PRECISION_FACTOR;
1295  bool bSpecialJust = false;
1296 
1297  if ( rInf.GetFont() && rInf.GetLen() )
1298  {
1299  const SwScriptInfo* pSI = rInf.GetScriptInfo();
1300  const SwFontScript nActual = rInf.GetFont()->GetActual();
1301 
1302  // Kana Compression
1303  if ( SwFontScript::CJK == nActual && rInf.GetKanaComp() &&
1304  pSI && pSI->CountCompChg() &&
1305  lcl_IsMonoSpaceFont( rInf.GetOut() ) )
1306  {
1307  pSI->Compress( pKernArray.get(), rInf.GetIdx(), rInf.GetLen(),
1308  rInf.GetKanaComp(),
1309  static_cast<sal_uInt16>(m_aFont.GetFontSize().Height()), lcl_IsFullstopCentered( rInf.GetOut() ), &aTextOriginPos );
1310  bSpecialJust = true;
1311  }
1312 
1313  // Asian Justification
1314  if ( SwFontScript::CJK == nActual && nSpaceAdd )
1315  {
1317 
1318  if (!MsLangId::isKorean(aLang))
1319  {
1320  SwScriptInfo::CJKJustify( rInf.GetText(), pKernArray.get(), nullptr,
1321  rInf.GetIdx(), rInf.GetLen(), aLang, nSpaceAdd, rInf.IsSpaceStop() );
1322 
1323  bSpecialJust = true;
1324  nSpaceAdd = 0;
1325  }
1326  }
1327 
1328  // Kashida Justification
1329  if ( SwFontScript::CTL == nActual && nSpaceAdd )
1330  {
1331  if ( SwScriptInfo::IsArabicText( rInf.GetText(), rInf.GetIdx(), rInf.GetLen() ) )
1332  {
1333  if ( pSI && pSI->CountKashida() &&
1334  pSI->KashidaJustify( pKernArray.get(), nullptr, rInf.GetIdx(),
1335  rInf.GetLen(), nSpaceAdd ) != -1 )
1336  {
1337  bSpecialJust = true;
1338  nSpaceAdd = 0;
1339  }
1340  }
1341  }
1342 
1343  // Thai Justification
1344  if ( SwFontScript::CTL == nActual && nSpaceAdd )
1345  {
1347 
1348  if ( LANGUAGE_THAI == aLang )
1349  {
1350  // Use rInf.GetSpace() because it has more precision than
1351  // nSpaceAdd:
1352  SwScriptInfo::ThaiJustify( rInf.GetText(), pKernArray.get(), nullptr,
1353  rInf.GetIdx(), rInf.GetLen(),
1354  rInf.GetNumberOfBlanks(),
1355  rInf.GetSpace() );
1356 
1357  // adding space to blanks is already done
1358  bSpecialJust = true;
1359  nSpaceAdd = 0;
1360  }
1361  }
1362  }
1363 
1364  long nKernSum = rInf.GetKern();
1365 
1366  if ( bStretch || m_bPaintBlank || rInf.GetKern() || bSpecialJust )
1367  {
1368  for (sal_Int32 i = 0; i < sal_Int32(rInf.GetLen()); i++,
1369  nKernSum += rInf.GetKern() )
1370  {
1371  if (CH_BLANK == rInf.GetText()[sal_Int32(rInf.GetIdx()) + i])
1372  nKernSum += nSpaceAdd;
1373  pKernArray[i] += nKernSum;
1374  }
1375 
1376  // In case of underlined/strike-through justified text
1377  // a blank at the end requires special handling:
1378  if( m_bPaintBlank && rInf.GetLen() && ( CH_BLANK ==
1379  rInf.GetText()[sal_Int32(rInf.GetIdx() + rInf.GetLen())-1]))
1380  {
1381  // If it is a single underlined space, output 2 spaces:
1382  if (TextFrameIndex(1) == rInf.GetLen())
1383  {
1384  pKernArray[0] = rInf.GetWidth() + nSpaceAdd;
1385 
1386  rInf.GetOut().DrawTextArray( aTextOriginPos, rInf.GetText(),
1387  pKernArray.get(), sal_Int32(rInf.GetIdx()), 1 );
1388  }
1389  else
1390  {
1391  pKernArray[ sal_Int32(rInf.GetLen()) - 2 ] += nSpaceAdd;
1392  rInf.GetOut().DrawTextArray( aTextOriginPos, rInf.GetText(),
1393  pKernArray.get(), sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()));
1394  }
1395  }
1396  else
1397  rInf.GetOut().DrawTextArray( aTextOriginPos, rInf.GetText(),
1398  pKernArray.get(), sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()));
1399  }
1400  else
1401  {
1402  Point aTmpPos( aTextOriginPos );
1403  sal_Int32 j = 0;
1404  sal_Int32 i;
1405  for( i = 0; i < sal_Int32(rInf.GetLen()); i++ )
1406  {
1407  if (CH_BLANK == rInf.GetText()[sal_Int32(rInf.GetIdx()) + i])
1408  {
1409  nKernSum += nSpaceAdd;
1410  if( j < i )
1411  rInf.GetOut().DrawText( aTmpPos, rInf.GetText(),
1412  sal_Int32(rInf.GetIdx()) + j, i - j);
1413  j = i + 1;
1414  SwTwips nAdd = pKernArray[ i ] + nKernSum;
1415  if ( ( ComplexTextLayoutFlags::BiDiStrong | ComplexTextLayoutFlags::BiDiRtl ) == nMode )
1416  nAdd *= -1;
1417  aTmpPos.setX( aTextOriginPos.X() + nAdd );
1418  }
1419  }
1420  if( j < i )
1421  rInf.GetOut().DrawText( aTmpPos, rInf.GetText(),
1422  sal_Int32(rInf.GetIdx()) + j, i - j);
1423  }
1424  }
1425  else if( bStretch )
1426  {
1427  long nTmpWidth = rInf.GetWidth();
1428  if( rInf.GetKern() && rInf.GetLen() && nTmpWidth > rInf.GetKern() )
1429  nTmpWidth -= rInf.GetKern();
1430  rInf.GetOut().DrawStretchText( aTextOriginPos, nTmpWidth,
1431  rInf.GetText(),
1432  sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()));
1433  }
1434  else if( rInf.GetKern() )
1435  {
1436  const long nTmpWidth = GetTextSize( rInf ).Width();
1437 
1438  const Color aSaveColor( pTmpFont->GetColor() );
1439  const bool bColorChanged = rInf.ApplyAutoColor( pTmpFont );
1440 
1441  if( bColorChanged )
1442  {
1443  if( !pTmpFont->IsSameInstance( rInf.GetOut().GetFont() ) )
1444  rInf.GetOut().SetFont( *pTmpFont );
1445  pTmpFont->SetColor( aSaveColor );
1446  }
1447 
1448  rInf.GetOut().DrawStretchText( aTextOriginPos, nTmpWidth,
1449  rInf.GetText(),
1450  sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()));
1451  }
1452  else
1453  rInf.GetOut().DrawText( aTextOriginPos, rInf.GetText(),
1454  sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()));
1455  }
1456 
1457  // PAINTING WITH FORMATTING DEVICE/SCREEN ADJUSTMENT
1458 
1459  else
1460  {
1461  const OUString* pStr = &rInf.GetText();
1462 
1463  OUString aStr;
1464  OUString aBulletOverlay;
1465  bool bBullet = rInf.GetBullet();
1466  if( m_bSymbol )
1467  bBullet = false;
1468  std::unique_ptr<long[]> pKernArray(new long[sal_Int32(rInf.GetLen())]);
1469  CreateScrFont( *rInf.GetShell(), rInf.GetOut() );
1470  long nScrPos;
1471 
1472  // get screen array
1473  std::unique_ptr<long[]> pScrArray(new long[sal_Int32(rInf.GetLen())]);
1474  SwTextGlyphsKey aGlyphsKey{ &rInf.GetOut(), rInf.GetText(), sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()) };
1475  SalLayoutGlyphs* pGlyphs = lcl_CreateLayout(aGlyphsKey, m_aTextGlyphs[aGlyphsKey]);
1476  rInf.GetOut().GetTextArray( rInf.GetText(), pScrArray.get(),
1477  sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()), nullptr, pGlyphs);
1478 
1479  // OLE: no printer available
1480  // OSL_ENSURE( pPrinter, "DrawText needs pPrinter" )
1481  if ( m_pPrinter )
1482  {
1483  // pTmpFont has already been set as current font for rInf.GetOut()
1484  if ( m_pPrinter.get() != rInf.GetpOut() || pTmpFont != m_pPrtFont )
1485  {
1488  }
1489  aGlyphsKey = SwTextGlyphsKey{ m_pPrinter, rInf.GetText(), sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()) };
1490  pGlyphs = lcl_CreateLayout(aGlyphsKey, m_aTextGlyphs[aGlyphsKey]);
1491  m_pPrinter->GetTextArray(rInf.GetText(), pKernArray.get(),
1492  sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()), nullptr, pGlyphs);
1493  }
1494  else
1495  {
1496  rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray.get(),
1497  sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()));
1498  }
1499 
1500  // Modify Printer and ScreenArrays for special justifications
1501 
1502  long nSpaceAdd = rInf.GetSpace() / SPACING_PRECISION_FACTOR;
1503  bool bNoHalfSpace = false;
1504 
1505  if ( rInf.GetFont() && rInf.GetLen() )
1506  {
1507  const SwFontScript nActual = rInf.GetFont()->GetActual();
1508  const SwScriptInfo* pSI = rInf.GetScriptInfo();
1509 
1510  // Kana Compression
1511  if ( SwFontScript::CJK == nActual && rInf.GetKanaComp() &&
1512  pSI && pSI->CountCompChg() &&
1513  lcl_IsMonoSpaceFont( rInf.GetOut() ) )
1514  {
1515  Point aTmpPos( aTextOriginPos );
1516  pSI->Compress( pScrArray.get(), rInf.GetIdx(), rInf.GetLen(),
1517  rInf.GetKanaComp(),
1518  static_cast<sal_uInt16>(m_aFont.GetFontSize().Height()), lcl_IsFullstopCentered( rInf.GetOut() ), &aTmpPos );
1519  pSI->Compress( pKernArray.get(), rInf.GetIdx(), rInf.GetLen(),
1520  rInf.GetKanaComp(),
1521  static_cast<sal_uInt16>(m_aFont.GetFontSize().Height()), lcl_IsFullstopCentered( rInf.GetOut() ), &aTextOriginPos );
1522  }
1523 
1524  // Asian Justification
1525  if ( SwFontScript::CJK == nActual && nSpaceAdd )
1526  {
1528 
1529  if (!MsLangId::isKorean(aLang))
1530  {
1531  SwScriptInfo::CJKJustify( rInf.GetText(), pKernArray.get(), pScrArray.get(),
1532  rInf.GetIdx(), rInf.GetLen(), aLang, nSpaceAdd, rInf.IsSpaceStop() );
1533 
1534  nSpaceAdd = 0;
1535  }
1536  }
1537 
1538  // Kashida Justification
1539  if ( SwFontScript::CTL == nActual && nSpaceAdd )
1540  {
1541  if ( SwScriptInfo::IsArabicText( rInf.GetText(), rInf.GetIdx(), rInf.GetLen() ) )
1542  {
1543  if ( pSI && pSI->CountKashida() &&
1544  pSI->KashidaJustify( pKernArray.get(), pScrArray.get(), rInf.GetIdx(),
1545  rInf.GetLen(), nSpaceAdd ) != -1 )
1546  nSpaceAdd = 0;
1547  else
1548  bNoHalfSpace = true;
1549  }
1550  }
1551 
1552  // Thai Justification
1553  if ( SwFontScript::CTL == nActual && nSpaceAdd )
1554  {
1556 
1557  if ( LANGUAGE_THAI == aLang )
1558  {
1559  SwScriptInfo::ThaiJustify( rInf.GetText(), pKernArray.get(),
1560  pScrArray.get(), rInf.GetIdx(),
1561  rInf.GetLen(),
1562  rInf.GetNumberOfBlanks(),
1563  rInf.GetSpace() );
1564 
1565  // adding space to blanks is already done
1566  nSpaceAdd = 0;
1567  }
1568  }
1569  }
1570 
1571  nScrPos = pScrArray[ 0 ];
1572 
1573  if( bBullet )
1574  {
1575  // !!! HACK !!!
1576  // The Arabic layout engine requires some context of the string
1577  // which should be painted.
1578  sal_Int32 nCopyStart = sal_Int32(rInf.GetIdx());
1579  if ( nCopyStart )
1580  --nCopyStart;
1581 
1582  sal_Int32 nCopyLen = sal_Int32(rInf.GetLen());
1583  if ( nCopyStart + nCopyLen < rInf.GetText().getLength() )
1584  ++nCopyLen;
1585 
1586  aStr = rInf.GetText().copy( nCopyStart, nCopyLen );
1587  pStr = &aStr;
1588 
1589  aBulletOverlay = rInf.GetText().copy( nCopyStart, nCopyLen );
1590 
1591  for( sal_Int32 i = 0; i < aBulletOverlay.getLength(); ++i )
1592  if( CH_BLANK == aBulletOverlay[ i ] )
1593  {
1594  /* fdo#72488 Hack: try to see if the space is zero width
1595  * and don't bother with inserting a bullet in this case.
1596  */
1597  if ((i + nCopyStart + 1 >= sal_Int32(rInf.GetLen())) ||
1598  pKernArray[i + nCopyStart] != pKernArray[ i + nCopyStart + 1])
1599  {
1600  aBulletOverlay = aBulletOverlay.replaceAt(i, 1, OUString(CH_BULLET));
1601  }
1602  else
1603  {
1604  aBulletOverlay = aBulletOverlay.replaceAt(i, 1, OUString(CH_BLANK));
1605  }
1606  }
1607  else
1608  {
1609  aBulletOverlay = aBulletOverlay.replaceAt(i, 1, OUString(CH_BLANK));
1610  }
1611  }
1612 
1613  TextFrameIndex nCnt(rInf.GetText().getLength());
1614  if ( nCnt < rInf.GetIdx() )
1615  assert(false); // layout bug, not handled below
1616  else
1617  nCnt = nCnt - rInf.GetIdx();
1618  nCnt = std::min(nCnt, rInf.GetLen());
1619  long nKernSum = rInf.GetKern();
1620  sal_Unicode cChPrev = rInf.GetText()[sal_Int32(rInf.GetIdx())];
1621 
1622  // In case of a single underlined space in justified text,
1623  // have to output 2 spaces:
1624  if ((nCnt == TextFrameIndex(1)) && rInf.GetSpace() && (cChPrev == CH_BLANK))
1625  {
1626  pKernArray[0] = rInf.GetWidth() +
1627  rInf.GetKern() +
1628  ( rInf.GetSpace() / SPACING_PRECISION_FACTOR );
1629 
1630  if ( bSwitchL2R )
1631  rInf.GetFrame()->SwitchLTRtoRTL( aTextOriginPos );
1632 
1633  if ( bSwitchH2V )
1634  rInf.GetFrame()->SwitchHorizontalToVertical( aTextOriginPos );
1635 
1636  rInf.GetOut().DrawTextArray( aTextOriginPos, rInf.GetText(),
1637  pKernArray.get(), sal_Int32(rInf.GetIdx()), 1 );
1638  if( bBullet )
1639  rInf.GetOut().DrawTextArray( aTextOriginPos, *pStr, pKernArray.get(),
1640  rInf.GetIdx() ? 1 : 0, 1 );
1641  }
1642  else
1643  {
1644  sal_Unicode nCh;
1645 
1646  // In case of Pair Kerning the printer influence on the positioning
1647  // grows
1648  const int nMul = m_pPrtFont->GetKerning() != FontKerning::NONE ? 1 : 3;
1649  const int nDiv = nMul+1;
1650 
1651  // nSpaceSum contains the sum of the intermediate space distributed
1652  // among Spaces by the Justification.
1653  // The Spaces themselves will be positioned in the middle of the
1654  // intermediate space, hence the nSpace/2.
1655  // In case of word-by-word underlining they have to be positioned
1656  // at the beginning of the intermediate space, so that the space
1657  // is not underlined.
1658  // A Space at the beginning or end of the text must be positioned
1659  // before (resp. after) the whole intermediate space, otherwise
1660  // the underline/strike-through would have gaps.
1661  long nSpaceSum = 0;
1662  // in word line mode and for Arabic, we disable the half space trick:
1663  const long nHalfSpace = m_pPrtFont->IsWordLineMode() || bNoHalfSpace ? 0 : nSpaceAdd / 2;
1664  const long nOtherHalf = nSpaceAdd - nHalfSpace;
1665  if ( nSpaceAdd && ( cChPrev == CH_BLANK ) )
1666  nSpaceSum = nHalfSpace;
1667  for (sal_Int32 i = 1; i < sal_Int32(nCnt); ++i, nKernSum += rInf.GetKern())
1668  {
1669  nCh = rInf.GetText()[sal_Int32(rInf.GetIdx()) + i];
1670 
1671  OSL_ENSURE( pScrArray, "Where is the screen array?" );
1672  long nScr;
1673  nScr = pScrArray[ i ] - pScrArray[ i - 1 ];
1674 
1675  // If there is an (ex-)Space before us, position optimally,
1676  // i.e., our right margin to the 100% printer position;
1677  // if we _are_ an ex-Space, position us left-aligned to the
1678  // printer position.
1679  if ( nCh == CH_BLANK )
1680  {
1681  nScrPos = pKernArray[i-1] + nScr;
1682 
1683  if ( cChPrev == CH_BLANK )
1684  nSpaceSum += nOtherHalf;
1685  if (i + 1 == sal_Int32(nCnt))
1686  nSpaceSum += nSpaceAdd;
1687  else
1688  nSpaceSum += nHalfSpace;
1689  }
1690  else
1691  {
1692  if ( cChPrev == CH_BLANK )
1693  {
1694  nScrPos = pKernArray[i-1] + nScr;
1695  // no Pixel is lost:
1696  nSpaceSum += nOtherHalf;
1697  }
1698  else if ( cChPrev == '-' )
1699  nScrPos = pKernArray[i-1] + nScr;
1700  else
1701  {
1702  nScrPos += nScr;
1703  nScrPos = ( nMul * nScrPos + pKernArray[i] ) / nDiv;
1704  }
1705  }
1706  cChPrev = nCh;
1707  pKernArray[i-1] = nScrPos - nScr + nKernSum + nSpaceSum;
1708  // In word line mode and for Arabic, we disabled the half space trick. If a portion
1709  // ends with a blank, the full nSpaceAdd value has been added to the character in
1710  // front of the blank. This leads to painting artifacts, therefore we remove the
1711  // nSpaceAdd value again:
1712  if ((bNoHalfSpace || m_pPrtFont->IsWordLineMode()) && i+1 == sal_Int32(nCnt) && nCh == CH_BLANK)
1713  pKernArray[i-1] = pKernArray[i-1] - nSpaceAdd;
1714  }
1715 
1716  // the layout engine requires the total width of the output
1717  pKernArray[sal_Int32(rInf.GetLen()) - 1] += nKernSum + nSpaceSum;
1718 
1719  if( rInf.GetGreyWave() )
1720  {
1721  if( rInf.GetLen() )
1722  {
1723  long nHght = rInf.GetOut().LogicToPixel(
1724  m_pPrtFont->GetFontSize() ).Height();
1725  if( WRONG_SHOW_MIN < nHght )
1726  {
1727  if ( rInf.GetOut().GetConnectMetaFile() )
1728  rInf.GetOut().Push();
1729 
1730  Color aCol( rInf.GetOut().GetLineColor() );
1731  bool bColSave = aCol != gWaveCol;
1732  if ( bColSave )
1733  rInf.GetOut().SetLineColor( gWaveCol );
1734 
1735  Point aEnd;
1736  long nKernVal = pKernArray[sal_Int32(rInf.GetLen()) - 1];
1737 
1738  const sal_uInt16 nDir = bBidiPor
1739  ? 1800
1740  : UnMapDirection(GetFont().GetOrientation(),
1741  bSwitchH2V, bSwitchH2VLRBT);
1742 
1743  switch ( nDir )
1744  {
1745  case 0 :
1746  aEnd.setX( rInf.GetPos().X() + nKernVal );
1747  aEnd.setY( rInf.GetPos().Y() );
1748  break;
1749  case 900 :
1750  aEnd.setX( rInf.GetPos().X() );
1751  aEnd.setY( rInf.GetPos().Y() - nKernVal );
1752  break;
1753  case 1800 :
1754  aEnd.setX( rInf.GetPos().X() - nKernVal );
1755  aEnd.setY( rInf.GetPos().Y() );
1756  break;
1757  case 2700 :
1758  aEnd.setX( rInf.GetPos().X() );
1759  aEnd.setY( rInf.GetPos().Y() + nKernVal );
1760  break;
1761  }
1762 
1763  Point aCurrPos( rInf.GetPos() );
1764 
1765  if ( bSwitchL2R )
1766  {
1767  rInf.GetFrame()->SwitchLTRtoRTL( aCurrPos );
1768  rInf.GetFrame()->SwitchLTRtoRTL( aEnd );
1769  }
1770 
1771  if ( bSwitchH2V )
1772  {
1773  rInf.GetFrame()->SwitchHorizontalToVertical( aCurrPos );
1774  rInf.GetFrame()->SwitchHorizontalToVertical( aEnd );
1775  }
1776  {
1777  vcl::ScopedAntialiasing a(rInf.GetOut(), true);
1778  rInf.GetOut().DrawWaveLine( aCurrPos, aEnd );
1779  }
1780  if ( bColSave )
1781  rInf.GetOut().SetLineColor( aCol );
1782 
1783  if ( rInf.GetOut().GetConnectMetaFile() )
1784  rInf.GetOut().Pop();
1785  }
1786  }
1787  }
1788  else if( !m_bSymbol && rInf.GetLen() )
1789  {
1790  // anything to do?
1791  if (rInf.GetWrong() || rInf.GetGrammarCheck() || rInf.GetSmartTags())
1792  {
1793  CalcLinePosData aCalcLinePosData(rInf, GetFont(), nCnt, bSwitchH2V,
1794  bSwitchH2VLRBT, bSwitchL2R, nHalfSpace,
1795  pKernArray.get(), bBidiPor);
1796 
1797  SwForbidden aForbidden;
1798  // draw line for smart tag data
1799  lcl_DrawLineForWrongListData( aForbidden, rInf, rInf.GetSmartTags(), aCalcLinePosData, Size() );
1800  // draw wave line for spell check errors
1801  // draw them BEFORE the grammar check lines to 'override' the latter in case of conflict.
1802  // reason: some grammar errors can only be found if spelling errors are fixed,
1803  // therefore we don't want the user to miss a spelling error.
1804  lcl_DrawLineForWrongListData( aForbidden, rInf, rInf.GetWrong(), aCalcLinePosData, m_pPrtFont->GetFontSize() );
1805  // draw wave line for grammar check errors
1806  lcl_DrawLineForWrongListData( aForbidden, rInf, rInf.GetGrammarCheck(), aCalcLinePosData, m_pPrtFont->GetFontSize() );
1807  }
1808  }
1809 
1810  sal_Int32 nLen = sal_Int32(rInf.GetLen());
1811 
1812  if( nLen > 0 )
1813  {
1814 
1815  if ( bSwitchL2R )
1816  rInf.GetFrame()->SwitchLTRtoRTL( aTextOriginPos );
1817 
1818  if ( bSwitchH2V )
1819  rInf.GetFrame()->SwitchHorizontalToVertical( aTextOriginPos );
1820 
1821  // If we paint bullets instead of spaces, we use a copy of
1822  // the paragraph string. For the layout engine, the copy
1823  // of the string has to be an environment of the range which
1824  // is painted
1825  sal_Int32 nTmpIdx = bBullet
1826  ? (rInf.GetIdx() ? 1 : 0)
1827  : sal_Int32(rInf.GetIdx());
1828  aGlyphsKey = SwTextGlyphsKey{ &rInf.GetOut(), *pStr, nTmpIdx, nLen };
1829  pGlyphs = lcl_CreateLayout(aGlyphsKey, m_aTextGlyphs[aGlyphsKey]);
1830  rInf.GetOut().DrawTextArray( aTextOriginPos, *pStr, pKernArray.get(),
1831  nTmpIdx , nLen, SalLayoutFlags::NONE, pGlyphs );
1832  if (bBullet)
1833  {
1834  rInf.GetOut().Push();
1835  Color aPreviousColor = pTmpFont->GetColor();
1836 
1837  FontLineStyle aPreviousUnderline = pTmpFont->GetUnderline();
1838  FontLineStyle aPreviousOverline = pTmpFont->GetOverline();
1839  FontStrikeout aPreviousStrikeout = pTmpFont->GetStrikeout();
1840 
1841  pTmpFont->SetColor( NON_PRINTING_CHARACTER_COLOR );
1842  pTmpFont->SetUnderline(LINESTYLE_NONE);
1843  pTmpFont->SetOverline(LINESTYLE_NONE);
1844  pTmpFont->SetStrikeout(STRIKEOUT_NONE);
1845  rInf.GetOut().SetFont( *pTmpFont );
1846  long nShift = rInf.GetOut( ).GetFontMetric( ).GetBulletOffset( );
1847  if ( nShift )
1848  {
1849  long nAdd = 0;
1850 
1851  if (aBulletOverlay.getLength() > nTmpIdx &&
1852  aBulletOverlay[ nTmpIdx ] == CH_BULLET )
1853  {
1854  if (bSwitchH2V)
1855  aTextOriginPos.AdjustY(nShift ) ;
1856  else
1857  aTextOriginPos.AdjustX(nShift ) ;
1858  nAdd = nShift ;
1859  }
1860  for( sal_Int32 i = 1 ; i < nLen ; ++i )
1861  {
1862  if ( aBulletOverlay[ i + nTmpIdx ] == CH_BULLET )
1863  pKernArray [ i - 1 ] += nShift ;
1864  if ( nAdd )
1865  pKernArray [ i - 1 ] -= nAdd;
1866  }
1867  }
1868  rInf.GetOut().DrawTextArray( aTextOriginPos, aBulletOverlay, pKernArray.get(),
1869  nTmpIdx , nLen );
1870  pTmpFont->SetColor( aPreviousColor );
1871 
1872  pTmpFont->SetUnderline(aPreviousUnderline);
1873  pTmpFont->SetOverline(aPreviousOverline);
1874  pTmpFont->SetStrikeout(aPreviousStrikeout);
1875  rInf.GetOut().Pop();
1876  }
1877  }
1878  }
1879  }
1880 }
1881 
1883 {
1884  Size aTextSize;
1885  const TextFrameIndex nLn = (TextFrameIndex(COMPLETE_STRING) != rInf.GetLen())
1886  ? rInf.GetLen()
1887  : TextFrameIndex(rInf.GetText().getLength());
1888 
1889  // be sure to have the correct layout mode at the printer
1890  if ( m_pPrinter )
1891  {
1894  }
1895 
1896  if ( rInf.GetFrame() && nLn && rInf.SnapToGrid() && rInf.GetFont() &&
1897  SwFontScript::CJK == rInf.GetFont()->GetActual() )
1898  {
1899  SwTextGridItem const*const pGrid(GetGridItem(rInf.GetFrame()->FindPageFrame()));
1900  if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && pGrid->IsSnapToChars() )
1901  {
1902  const SwDoc* pDoc = rInf.GetShell()->GetDoc();
1903  const sal_uInt16 nGridWidth = GetGridWidth(*pGrid, *pDoc);
1904 
1905  OutputDevice* pOutDev;
1906 
1907  if ( m_pPrinter )
1908  {
1911  pOutDev = m_pPrinter;
1912  }
1913  else
1914  pOutDev = rInf.GetpOut();
1915 
1916  aTextSize.setWidth( pOutDev->GetTextWidth(rInf.GetText(),
1917  sal_Int32(rInf.GetIdx()), sal_Int32(nLn)) );
1918 
1919  OSL_ENSURE( !rInf.GetShell() ||
1921  "Leading values should be already calculated" );
1922  aTextSize.setHeight( pOutDev->GetTextHeight() +
1923  GetFontLeading( rInf.GetShell(), rInf.GetOut() ) );
1924 
1925  long nAvgWidthPerChar = aTextSize.Width() / sal_Int32(nLn);
1926 
1927  const sal_uLong i = nAvgWidthPerChar ?
1928  ( nAvgWidthPerChar - 1 ) / nGridWidth + 1:
1929  1;
1930 
1931  aTextSize.setWidth(i * nGridWidth * sal_Int32(nLn));
1932  rInf.SetKanaDiff( 0 );
1933  return aTextSize;
1934  }
1935  }
1936 
1937  //for textgrid refactor
1938  if ( rInf.GetFrame() && nLn && rInf.SnapToGrid() && rInf.GetFont() )
1939  {
1940  SwTextGridItem const*const pGrid(GetGridItem(rInf.GetFrame()->FindPageFrame()));
1941  if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && !pGrid->IsSnapToChars() )
1942  {
1943  const long nGridWidthAdd = EvalGridWidthAdd( pGrid, rInf );
1944  OutputDevice* pOutDev;
1945  if ( m_pPrinter )
1946  {
1949  pOutDev = m_pPrinter;
1950  }
1951  else
1952  pOutDev = rInf.GetpOut();
1953  aTextSize.setWidth(pOutDev->GetTextWidth(rInf.GetText(),
1954  sal_Int32(rInf.GetIdx()), sal_Int32(nLn)));
1955  aTextSize.setHeight( pOutDev->GetTextHeight() +
1956  GetFontLeading( rInf.GetShell(), rInf.GetOut() ) );
1957  aTextSize.AdjustWidth(sal_Int32(nLn) * nGridWidthAdd);
1958  //if ( rInf.GetKern() && nLn )
1959  // aTextSize.Width() += ( nLn ) * long( rInf.GetKern() );
1960 
1961  rInf.SetKanaDiff( 0 );
1962  return aTextSize;
1963  }
1964  }
1965 
1966  const bool bCompress = rInf.GetKanaComp() && nLn &&
1967  rInf.GetFont() &&
1968  SwFontScript::CJK == rInf.GetFont()->GetActual() &&
1969  rInf.GetScriptInfo() &&
1970  rInf.GetScriptInfo()->CountCompChg() &&
1971  lcl_IsMonoSpaceFont( rInf.GetOut() );
1972 
1973  OSL_ENSURE( !bCompress || ( rInf.GetScriptInfo() && rInf.GetScriptInfo()->
1974  CountCompChg()), "Compression without info" );
1975 
1976  // This is the part used e.g., for cursor travelling
1977  // See condition for DrawText or DrawTextArray (bDirectPrint)
1978  if ( m_pPrinter && m_pPrinter.get() != rInf.GetpOut() )
1979  {
1982  aTextSize.setWidth( m_pPrinter->GetTextWidth( rInf.GetText(),
1983  sal_Int32(rInf.GetIdx()), sal_Int32(nLn)));
1984  aTextSize.setHeight( m_pPrinter->GetTextHeight() );
1985  std::unique_ptr<long[]> pKernArray(new long[sal_Int32(nLn)]);
1986  CreateScrFont( *rInf.GetShell(), rInf.GetOut() );
1987  if( !GetScrFont()->IsSameInstance( rInf.GetOut().GetFont() ) )
1988  rInf.GetOut().SetFont( *m_pScrFont );
1989  long nScrPos;
1990 
1991  m_pPrinter->GetTextArray(rInf.GetText(), pKernArray.get(),
1992  sal_Int32(rInf.GetIdx()), sal_Int32(nLn));
1993  if( bCompress )
1994  rInf.SetKanaDiff( rInf.GetScriptInfo()->Compress( pKernArray.get(),
1995  rInf.GetIdx(), nLn, rInf.GetKanaComp(),
1996  static_cast<sal_uInt16>(m_aFont.GetFontSize().Height()) ,lcl_IsFullstopCentered( rInf.GetOut() ) ) );
1997  else
1998  rInf.SetKanaDiff( 0 );
1999 
2000  if ( rInf.GetKanaDiff() )
2001  nScrPos = pKernArray[ sal_Int32(nLn) - 1 ];
2002  else
2003  {
2004  std::unique_ptr<long[]> pScrArray(new long[sal_Int32(rInf.GetLen())]);
2005  rInf.GetOut().GetTextArray( rInf.GetText(), pScrArray.get(),
2006  sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()));
2007  nScrPos = pScrArray[ 0 ];
2008  TextFrameIndex nCnt(rInf.GetText().getLength());
2009  if ( nCnt < rInf.GetIdx() )
2010  nCnt = TextFrameIndex(0); // assert???
2011  else
2012  nCnt = nCnt - rInf.GetIdx();
2013  nCnt = std::min(nCnt, nLn);
2014  sal_Unicode nChPrev = rInf.GetText()[ sal_Int32(rInf.GetIdx()) ];
2015 
2016  sal_Unicode nCh;
2017 
2018  // In case of Pair Kerning the printer influence on the positioning
2019  // grows
2020  const int nMul = m_pPrtFont->GetKerning() != FontKerning::NONE ? 1 : 3;
2021  const int nDiv = nMul+1;
2022  for (sal_Int32 i = 1; i < sal_Int32(nCnt); i++)
2023  {
2024  nCh = rInf.GetText()[ sal_Int32(rInf.GetIdx()) + i ];
2025  long nScr;
2026  nScr = pScrArray[ i ] - pScrArray[ i - 1 ];
2027  if ( nCh == CH_BLANK )
2028  nScrPos = pKernArray[i-1]+nScr;
2029  else
2030  {
2031  if ( nChPrev == CH_BLANK || nChPrev == '-' )
2032  nScrPos = pKernArray[i-1]+nScr;
2033  else
2034  {
2035  nScrPos += nScr;
2036  nScrPos = ( nMul * nScrPos + pKernArray[i] ) / nDiv;
2037  }
2038  }
2039  nChPrev = nCh;
2040  pKernArray[i-1] = nScrPos - nScr;
2041  }
2042  }
2043 
2044  pKernArray.reset();
2045  aTextSize.setWidth( nScrPos );
2046  }
2047  else
2048  {
2049  if( !m_pPrtFont->IsSameInstance( rInf.GetOut().GetFont() ) )
2050  rInf.GetOut().SetFont( *m_pPrtFont );
2051  if( bCompress )
2052  {
2053  std::unique_ptr<long[]> pKernArray( new long[sal_Int32(nLn)] );
2054  rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray.get(),
2055  sal_Int32(rInf.GetIdx()), sal_Int32(nLn));
2056  rInf.SetKanaDiff( rInf.GetScriptInfo()->Compress( pKernArray.get(),
2057  rInf.GetIdx(), nLn, rInf.GetKanaComp(),
2058  static_cast<sal_uInt16>(m_aFont.GetFontSize().Height()) ,lcl_IsFullstopCentered( rInf.GetOut() ) ) );
2059  aTextSize.setWidth( pKernArray[sal_Int32(nLn) - 1] );
2060  }
2061  else
2062  {
2063  SwTextGlyphsKey aGlyphsKey{ &rInf.GetOut(), rInf.GetText(), sal_Int32(rInf.GetIdx()), sal_Int32(nLn) };
2064  SalLayoutGlyphs* pGlyphs = lcl_CreateLayout(aGlyphsKey, m_aTextGlyphs[aGlyphsKey]);
2065  aTextSize.setWidth( rInf.GetOut().GetTextWidth( rInf.GetText(),
2066  sal_Int32(rInf.GetIdx()), sal_Int32(nLn),
2067  rInf.GetVclCache(), pGlyphs) );
2068  rInf.SetKanaDiff( 0 );
2069  }
2070 
2071  aTextSize.setHeight( rInf.GetOut().GetTextHeight() );
2072  }
2073 
2074  if ( rInf.GetKern() && nLn )
2075  aTextSize.AdjustWidth((sal_Int32(nLn) - 1) * rInf.GetKern());
2076 
2077  OSL_ENSURE( !rInf.GetShell() ||
2079  "Leading values should be already calculated" );
2080  aTextSize.AdjustHeight(GetFontLeading( rInf.GetShell(), rInf.GetOut() ) );
2081  return aTextSize;
2082 }
2083 
2085 {
2086  long nSpaceAdd = rInf.GetSpace() / SPACING_PRECISION_FACTOR;
2087  const long nSperren = -rInf.GetSperren() / SPACING_PRECISION_FACTOR;
2088  long nKern = rInf.GetKern();
2089 
2090  if( 0 != nSperren )
2091  nKern -= nSperren;
2092 
2093  std::unique_ptr<long[]> pKernArray(new long[sal_Int32(rInf.GetLen())]);
2094 
2095  // be sure to have the correct layout mode at the printer
2096  if ( m_pPrinter )
2097  {
2100  SwTextGlyphsKey aGlyphsKey{ m_pPrinter, rInf.GetText(), sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()) };
2101  SalLayoutGlyphs* pGlyphs = lcl_CreateLayout(aGlyphsKey, m_aTextGlyphs[aGlyphsKey]);
2102  m_pPrinter->GetTextArray( rInf.GetText(), pKernArray.get(),
2103  sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()), nullptr, pGlyphs);
2104  }
2105  else
2106  rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray.get(),
2107  sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()));
2108 
2109  const SwScriptInfo* pSI = rInf.GetScriptInfo();
2110  if ( rInf.GetFont() && rInf.GetLen() )
2111  {
2112  const SwFontScript nActual = rInf.GetFont()->GetActual();
2113 
2114  // Kana Compression
2115  if ( SwFontScript::CJK == nActual && rInf.GetKanaComp() &&
2116  pSI && pSI->CountCompChg() &&
2117  lcl_IsMonoSpaceFont( rInf.GetOut() ) )
2118  {
2119  pSI->Compress( pKernArray.get(), rInf.GetIdx(), rInf.GetLen(),
2120  rInf.GetKanaComp(),
2121  static_cast<sal_uInt16>(m_aFont.GetFontSize().Height()),
2122  lcl_IsFullstopCentered( rInf.GetOut() ) );
2123  }
2124 
2125  // Asian Justification
2126  if ( SwFontScript::CJK == rInf.GetFont()->GetActual() )
2127  {
2129 
2130  if (!MsLangId::isKorean(aLang))
2131  {
2132  SwScriptInfo::CJKJustify( rInf.GetText(), pKernArray.get(), nullptr,
2133  rInf.GetIdx(), rInf.GetLen(), aLang, nSpaceAdd, rInf.IsSpaceStop() );
2134 
2135  nSpaceAdd = 0;
2136  }
2137 
2138  }
2139 
2140  // Kashida Justification
2141  if ( SwFontScript::CTL == nActual && rInf.GetSpace() )
2142  {
2143  if ( SwScriptInfo::IsArabicText( rInf.GetText(), rInf.GetIdx(), rInf.GetLen() ) )
2144  {
2145  if ( pSI && pSI->CountKashida() &&
2146  pSI->KashidaJustify( pKernArray.get(), nullptr, rInf.GetIdx(), rInf.GetLen(),
2147  nSpaceAdd ) != -1 )
2148  nSpaceAdd = 0;
2149  }
2150  }
2151 
2152  // Thai Justification
2153  if ( SwFontScript::CTL == nActual && nSpaceAdd )
2154  {
2156 
2157  if ( LANGUAGE_THAI == aLang )
2158  {
2159  SwScriptInfo::ThaiJustify( rInf.GetText(), pKernArray.get(), nullptr,
2160  rInf.GetIdx(), rInf.GetLen(),
2161  rInf.GetNumberOfBlanks(),
2162  rInf.GetSpace() );
2163 
2164  // adding space to blanks is already done
2165  nSpaceAdd = 0;
2166  }
2167  }
2168  }
2169 
2170  long nLeft = 0;
2171  long nRight = 0;
2172  TextFrameIndex nCnt(0);
2173  long nSpaceSum = 0;
2174  long nKernSum = 0;
2175 
2176  if ( rInf.GetFrame() && rInf.GetLen() && rInf.SnapToGrid() &&
2177  rInf.GetFont() && SwFontScript::CJK == rInf.GetFont()->GetActual() )
2178  {
2179  SwTextGridItem const*const pGrid(GetGridItem(rInf.GetFrame()->FindPageFrame()));
2180  if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && pGrid->IsSnapToChars() )
2181  {
2182  const SwDoc* pDoc = rInf.GetShell()->GetDoc();
2183  const sal_uInt16 nGridWidth = GetGridWidth(*pGrid, *pDoc);
2184 
2185  long nAvgWidthPerChar = pKernArray[sal_Int32(rInf.GetLen()) - 1] / sal_Int32(rInf.GetLen());
2186 
2187  sal_uLong i = nAvgWidthPerChar ?
2188  ( nAvgWidthPerChar - 1 ) / nGridWidth + 1:
2189  1;
2190 
2191  nAvgWidthPerChar = i * nGridWidth;
2192 
2193 // stupid CLANG
2194  nCnt = TextFrameIndex(rInf.GetOfst() / nAvgWidthPerChar);
2195  if (2 * (rInf.GetOfst() - sal_Int32(nCnt) * nAvgWidthPerChar) > nAvgWidthPerChar)
2196  ++nCnt;
2197 
2198  return nCnt;
2199  }
2200  }
2201 
2202  //for textgrid refactor
2203  if ( rInf.GetFrame() && rInf.GetLen() && rInf.SnapToGrid() )
2204  {
2205  SwTextGridItem const*const pGrid(GetGridItem(rInf.GetFrame()->FindPageFrame()));
2206  if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && !pGrid->IsSnapToChars() )
2207  {
2208 
2209  const long nGridWidthAdd = EvalGridWidthAdd( pGrid, rInf );
2210 
2211  for (TextFrameIndex j(0); j < rInf.GetLen(); j++)
2212  {
2213  long nScr = pKernArray[sal_Int32(j)] + (nSpaceAdd + nGridWidthAdd) * (sal_Int32(j) + 1);
2214  if( nScr >= rInf.GetOfst())
2215  {
2216  nCnt = j;
2217  break;
2218  }
2219  }
2220  return nCnt;
2221  }
2222  }
2223 
2224  sal_Int32 nDone = 0;
2225  TextFrameIndex nIdx = rInf.GetIdx();
2226  TextFrameIndex nLastIdx = nIdx;
2227  const TextFrameIndex nEnd = rInf.GetIdx() + rInf.GetLen();
2228 
2229  // #i105901#
2230  // skip character cells for all script types
2231  LanguageType aLang = rInf.GetFont()->GetLanguage();
2232 
2233  while ( ( nRight < long( rInf.GetOfst() ) ) && ( nIdx < nEnd ) )
2234  {
2235  if (nSpaceAdd && CH_BLANK == rInf.GetText()[ sal_Int32(nIdx)])
2236  nSpaceSum += nSpaceAdd;
2237 
2238  // go to next character (cell).
2239  nLastIdx = nIdx;
2240 
2241  nIdx = TextFrameIndex(g_pBreakIt->GetBreakIter()->nextCharacters(
2242  rInf.GetText(), sal_Int32(nIdx),
2243  g_pBreakIt->GetLocale( aLang ),
2244  i18n::CharacterIteratorMode::SKIPCELL, 1, nDone));
2245  if ( nIdx <= nLastIdx )
2246  break;
2247 
2248  nLeft = nRight;
2249  nRight = pKernArray[sal_Int32(nIdx - rInf.GetIdx()) - 1] + nKernSum + nSpaceSum;
2250 
2251  nKernSum += nKern;
2252  }
2253 
2254  // step back if position is before the middle of the character
2255  // or if we do not want to go to the next character
2256  if ( nIdx > rInf.GetIdx() &&
2257  ( rInf.IsPosMatchesBounds() ||
2258  ( ( nRight > long( rInf.GetOfst() ) ) &&
2259  ( nRight - rInf.GetOfst() > rInf.GetOfst() - nLeft ) ) ) )
2260  nCnt = nLastIdx - rInf.GetIdx(); // first half
2261  else
2262  nCnt = nIdx - rInf.GetIdx(); // second half
2263 
2264  if ( pSI )
2265  rInf.SetCursorBidiLevel( pSI->DirType( nLastIdx ) );
2266 
2267  return nCnt;
2268 }
2269 
2270 SwFntAccess::SwFntAccess( const void* & rnFontCacheId,
2271  sal_uInt16 &rIndex, const void *pOwn, SwViewShell const *pSh,
2272  bool bCheck ) :
2273  SwCacheAccess( *pFntCache, rnFontCacheId, rIndex ),
2274  m_pShell( pSh )
2275 {
2276  // the used ctor of SwCacheAccess searches for rnFontCacheId+rIndex in the cache
2277  if ( m_pObj )
2278  {
2279  // fast case: known Font (rnFontCacheId), no need to check printer and zoom
2280  if ( !bCheck )
2281  return;
2282 
2283  // Font is known, but has to be checked
2284  }
2285  else
2286  { // Font not known, must be searched
2287  bCheck = false;
2288  }
2289 
2290  {
2291  OutputDevice* pOut = nullptr;
2292  sal_uInt16 nZoom = USHRT_MAX;
2293 
2294  // Get the reference device
2295  if ( pSh )
2296  {
2297  pOut = &pSh->GetRefDev();
2298  nZoom = pSh->GetViewOptions()->GetZoom();
2299  }
2300 
2301  SwFntObj *pFntObj;
2302  if ( bCheck )
2303  {
2304  pFntObj = Get();
2305  if ( ( pFntObj->GetZoom( ) == nZoom ) &&
2306  ( pFntObj->m_pPrinter == pOut ) &&
2307  pFntObj->GetPropWidth() ==
2308  static_cast<SwSubFont const *>(pOwn)->GetPropWidth() )
2309  {
2310  return; // result of Check: Drucker+Zoom okay.
2311  }
2312  pFntObj->Unlock(); // forget this object, printer/zoom differs
2313  m_pObj = nullptr;
2314  }
2315 
2316  // Search by font comparison, quite expensive!
2317  // Look for same font and same printer
2318  pFntObj = pFntCache->First();
2319  while ( pFntObj && !( pFntObj->m_aFont == *static_cast<vcl::Font const *>(pOwn) &&
2320  pFntObj->GetZoom() == nZoom &&
2321  pFntObj->GetPropWidth() ==
2322  static_cast<SwSubFont const *>(pOwn)->GetPropWidth() &&
2323  ( !pFntObj->m_pPrinter || pFntObj->m_pPrinter == pOut ) ) )
2324  pFntObj = SwFntCache::Next( pFntObj );
2325 
2326  if( pFntObj && pFntObj->m_pPrinter.get() != pOut )
2327  {
2328  // found one without printer, let's see if there is one with
2329  // the same printer as well
2330  SwFntObj *pTmpObj = pFntObj;
2331  while( pTmpObj && !( pTmpObj->m_aFont == *static_cast<vcl::Font const *>(pOwn) &&
2332  pTmpObj->GetZoom()==nZoom && pTmpObj->m_pPrinter==pOut &&
2333  pTmpObj->GetPropWidth() ==
2334  static_cast<SwSubFont const *>(pOwn)->GetPropWidth() ) )
2335  pTmpObj = SwFntCache::Next( pTmpObj );
2336  if( pTmpObj )
2337  pFntObj = pTmpObj;
2338  }
2339 
2340  if ( !pFntObj ) // Font has not been found, create one
2341  {
2342  // Have to create new Object, hence Owner must be a SwFont, later
2343  // the Owner will be the "MagicNumber"
2344  SwCacheAccess::m_pOwner = pOwn;
2345  pFntObj = Get(); // will create via NewObj() and lock
2346  OSL_ENSURE(pFntObj, "No Font, no Fun.");
2347  }
2348  else // Font has been found, so we lock it.
2349  {
2350  pFntObj->Lock();
2351  if (pFntObj->m_pPrinter.get() != pOut) // if no printer is known by now
2352  {
2353  OSL_ENSURE( !pFntObj->m_pPrinter, "SwFntAccess: Printer Changed" );
2354  pFntObj->CreatePrtFont( *pOut );
2355  pFntObj->m_pPrinter = pOut;
2356  pFntObj->m_pScrFont = nullptr;
2357  pFntObj->m_nGuessedLeading = USHRT_MAX;
2358  pFntObj->m_nExtLeading = USHRT_MAX;
2359  pFntObj->m_nPrtAscent = USHRT_MAX;
2360  pFntObj->m_nPrtHeight = USHRT_MAX;
2361  }
2362  m_pObj = pFntObj;
2363  }
2364 
2365  // no matter if new or found, now the Owner of the Object is a
2366  // MagicNumber, and will be given to the SwFont, as well as the Index
2367  // for later direct access
2368  rnFontCacheId = reinterpret_cast<void*>(reinterpret_cast<sal_IntPtr>(pFntObj->GetOwner()));
2369  SwCacheAccess::m_pOwner = pFntObj->GetOwner();
2370  rIndex = pFntObj->GetCachePos();
2371  }
2372 }
2373 
2375 {
2376  // "MagicNumber" used to identify Fonts
2377  static std::uintptr_t fontCacheIdCounter = 0;
2378  // a new Font, a new "MagicNumber".
2379  return new SwFntObj( *static_cast<SwSubFont const *>(m_pOwner), ++fontCacheIdCounter, m_pShell );
2380 }
2381 
2383 {
2384  ChgFnt( rInf.GetShell(), rInf.GetOut() );
2385 
2386  const bool bCompress = rInf.GetKanaComp() && rInf.GetLen() &&
2388  rInf.GetScriptInfo() &&
2389  rInf.GetScriptInfo()->CountCompChg() &&
2390  lcl_IsMonoSpaceFont( rInf.GetOut() );
2391 
2392  OSL_ENSURE( !bCompress || ( rInf.GetScriptInfo() && rInf.GetScriptInfo()->
2393  CountCompChg()), "Compression without info" );
2394 
2395  TextFrameIndex nTextBreak(0);
2396  long nKern = 0;
2397 
2399  ? TextFrameIndex(rInf.GetText().getLength()) : rInf.GetLen();
2400 
2401  if ( rInf.GetFrame() && nLn && rInf.SnapToGrid() &&
2402  rInf.GetFont() && SwFontScript::CJK == rInf.GetFont()->GetActual() )
2403  {
2404  SwTextGridItem const*const pGrid(GetGridItem(rInf.GetFrame()->FindPageFrame()));
2405  if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && pGrid->IsSnapToChars() )
2406  {
2407  const SwDoc* pDoc = rInf.GetShell()->GetDoc();
2408  const sal_uInt16 nGridWidth = GetGridWidth(*pGrid, *pDoc);
2409 
2410  std::unique_ptr<long[]> pKernArray(new long[sal_Int32(rInf.GetLen())]);
2411  rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray.get(),
2412  sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()));
2413 
2414  long nAvgWidthPerChar = pKernArray[sal_Int32(rInf.GetLen()) - 1] / sal_Int32(rInf.GetLen());
2415 
2416  const sal_uLong i = nAvgWidthPerChar ?
2417  ( nAvgWidthPerChar - 1 ) / nGridWidth + 1:
2418  1;
2419 
2420  nAvgWidthPerChar = i * nGridWidth;
2421  long nCurrPos = nAvgWidthPerChar;
2422 
2423  while( nTextBreak < rInf.GetLen() && nTextWidth >= nCurrPos )
2424  {
2425  nCurrPos += nAvgWidthPerChar;
2426  ++nTextBreak;
2427  }
2428 
2429  return nTextBreak + rInf.GetIdx();
2430  }
2431  }
2432 
2433  //for text grid enhancement
2434  if ( rInf.GetFrame() && nLn && rInf.SnapToGrid() )
2435  {
2436  SwTextGridItem const*const pGrid(GetGridItem(rInf.GetFrame()->FindPageFrame()));
2437  if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && !pGrid->IsSnapToChars() )
2438  {
2439  const long nGridWidthAdd = EvalGridWidthAdd( pGrid, rInf );
2440 
2441  std::unique_ptr<long[]> pKernArray(new long[sal_Int32(rInf.GetLen())] );
2442  rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray.get(),
2443  sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()));
2444  long nCurrPos = pKernArray[sal_Int32(nTextBreak)] + nGridWidthAdd;
2445  while (++nTextBreak < rInf.GetLen() && nTextWidth >= nCurrPos)
2446  {
2447  nCurrPos = pKernArray[sal_Int32(nTextBreak)] + nGridWidthAdd * (sal_Int32(nTextBreak) + 1);
2448  }
2449  return nTextBreak + rInf.GetIdx();
2450  }
2451  }
2452 
2453  if( m_aSub[m_nActual].IsCapital() && nLn )
2454  {
2455  nTextBreak = GetCapitalBreak( rInf.GetShell(), rInf.GetpOut(),
2456  rInf.GetScriptInfo(), rInf.GetText(), nTextWidth, rInf.GetIdx(),
2457  nLn );
2458  }
2459  else
2460  {
2461  nKern = CheckKerning();
2462 
2463  const OUString* pTmpText;
2464  OUString aTmpText;
2465  TextFrameIndex nTmpIdx;
2466  TextFrameIndex nTmpLen;
2467  bool bTextReplaced = false;
2468 
2469  if ( !m_aSub[m_nActual].IsCaseMap() )
2470  {
2471  pTmpText = &rInf.GetText();
2472  nTmpIdx = rInf.GetIdx();
2473  nTmpLen = nLn;
2474  }
2475  else
2476  {
2477  const OUString aSnippet(rInf.GetText().copy(sal_Int32(rInf.GetIdx()), sal_Int32(nLn)));
2478  aTmpText = m_aSub[m_nActual].CalcCaseMap( aSnippet );
2479  const bool bTitle = SvxCaseMap::Capitalize == m_aSub[m_nActual].GetCaseMap();
2480 
2481  // Uaaaaahhhh!!! In title case mode, we would get wrong results
2482  if ( bTitle && nLn )
2483  {
2484  // check if rInf.GetIdx() is begin of word
2485  if ( !g_pBreakIt->GetBreakIter()->isBeginWord(
2486  rInf.GetText(), sal_Int32(rInf.GetIdx()),
2487  g_pBreakIt->GetLocale( m_aSub[m_nActual].GetLanguage() ),
2488  i18n::WordType::ANYWORD_IGNOREWHITESPACES ) )
2489  {
2490  // In this case, the beginning of aTmpText is wrong.
2491  OUString aSnippetTmp(aSnippet.copy(0, 1));
2492  aSnippetTmp = m_aSub[m_nActual].CalcCaseMap( aSnippetTmp );
2493  aTmpText = aTmpText.replaceAt( 0, aSnippetTmp.getLength(), OUString(aSnippet[0]) );
2494  }
2495  }
2496 
2497  pTmpText = &aTmpText;
2498  nTmpIdx = TextFrameIndex(0);
2499  nTmpLen = TextFrameIndex(aTmpText.getLength());
2500  bTextReplaced = true;
2501  }
2502 
2503  if( rInf.GetHyphPos() ) {
2504  sal_Int32 nHyphPos = sal_Int32(*rInf.GetHyphPos());
2505  nTextBreak = TextFrameIndex(rInf.GetOut().GetTextBreak(
2506  *pTmpText, nTextWidth,
2507  u'-', nHyphPos,
2508  sal_Int32(nTmpIdx), sal_Int32(nTmpLen),
2509  nKern, rInf.GetVclCache()));
2510  *rInf.GetHyphPos() = TextFrameIndex((nHyphPos == -1) ? COMPLETE_STRING : nHyphPos);
2511  }
2512  else
2513  {
2514  SwFntAccess aFntAccess(m_aSub[m_nActual].m_nFontCacheId, m_aSub[m_nActual].m_nFontIndex,
2515  &m_aSub[m_nActual], rInf.GetShell());
2516  SwTextGlyphsKey aGlyphsKey{ &rInf.GetOut(), *pTmpText, sal_Int32(nTmpIdx), sal_Int32(nTmpLen) };
2517  SalLayoutGlyphs* pGlyphs
2518  = lcl_CreateLayout(aGlyphsKey, aFntAccess.Get()->GetTextGlyphs()[aGlyphsKey]);
2519  nTextBreak = TextFrameIndex(rInf.GetOut().GetTextBreak(
2520  *pTmpText, nTextWidth,
2521  sal_Int32(nTmpIdx), sal_Int32(nTmpLen),
2522  nKern, rInf.GetVclCache(), pGlyphs));
2523  }
2524 
2525  if (bTextReplaced && sal_Int32(nTextBreak) != -1)
2526  {
2527  if ( nTmpLen != nLn )
2528  nTextBreak = sw_CalcCaseMap( *this, rInf.GetText(),
2529  rInf.GetIdx(), nLn, nTextBreak );
2530  else
2531  nTextBreak = nTextBreak + rInf.GetIdx();
2532  }
2533  }
2534 
2535  TextFrameIndex nTextBreak2 = sal_Int32(nTextBreak) == -1
2537  : nTextBreak;
2538 
2539  if ( ! bCompress )
2540  return nTextBreak2;
2541 
2542  nTextBreak2 = nTextBreak2 - rInf.GetIdx();
2543 
2544  if( nTextBreak2 < nLn )
2545  {
2546  if( !nTextBreak2 && nLn )
2547  nLn = TextFrameIndex(1);
2548  else if (nLn > nTextBreak2 + nTextBreak2)
2549  nLn = nTextBreak2 + nTextBreak2;
2550  std::unique_ptr<long[]> pKernArray( new long[sal_Int32(nLn)] );
2551  rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray.get(),
2552  sal_Int32(rInf.GetIdx()), sal_Int32(nLn));
2553  if( rInf.GetScriptInfo()->Compress( pKernArray.get(), rInf.GetIdx(), nLn,
2554  rInf.GetKanaComp(), static_cast<sal_uInt16>(GetHeight( m_nActual )),
2555  lcl_IsFullstopCentered( rInf.GetOut() ) ) )
2556  {
2557  long nKernAdd = nKern;
2558  TextFrameIndex const nTmpBreak = nTextBreak2;
2559  if( nKern && nTextBreak2 )
2560  nKern *= sal_Int32(nTextBreak2) - 1;
2561  while (nTextBreak2 < nLn && nTextWidth >= pKernArray[sal_Int32(nTextBreak2)] + nKern)
2562  {
2563  nKern += nKernAdd;
2564  ++nTextBreak2;
2565  }
2566  if( rInf.GetHyphPos() )
2567  *rInf.GetHyphPos() += nTextBreak2 - nTmpBreak; // It's not perfect
2568  }
2569  }
2570  nTextBreak2 = nTextBreak2 + rInf.GetIdx();
2571 
2572  return nTextBreak2;
2573 }
2574 
2576 {
2577  const vcl::Font& rFnt = pFont ? *pFont : GetOut().GetFont();
2578  Color nNewColor = COL_BLACK;
2579  bool bChgFntColor = false;
2580  bool bChgLineColor = false;
2581 
2582  if (GetShell() && !GetShell()->GetWin() && GetShell()->GetViewOptions()->IsBlackFont())
2583  {
2584  if ( COL_BLACK != rFnt.GetColor() )
2585  bChgFntColor = true;
2586 
2587  if ( (COL_BLACK != GetOut().GetLineColor()) ||
2588  (COL_BLACK != GetOut().GetOverlineColor()) )
2589  bChgLineColor = true;
2590  }
2591  else
2592  {
2593  // FontColor has to be changed if:
2594  // 1. FontColor = AUTO or 2. IsAlwaysAutoColor is set
2595  // LineColor has to be changed if:
2596  // 1. IsAlwaysAutoColor is set
2597 
2598  bChgLineColor = GetShell() && GetShell()->GetWin() &&
2600 
2601  bChgFntColor = COL_AUTO == rFnt.GetColor() || bChgLineColor;
2602 
2603  if ( bChgFntColor )
2604  {
2605  // check if current background has a user defined setting
2606  const Color* pCol = GetFont() ? GetFont()->GetBackColor() : nullptr;
2607  Color aColor;
2608  if( ! pCol || COL_TRANSPARENT == *pCol )
2609  {
2610  const SvxBrushItem* pItem;
2611  SwRect aOrigBackRect;
2613 
2620  if( GetFrame()->GetBackgroundBrush( aFillAttributes, pItem, pCol, aOrigBackRect, false, /*bConsiderTextBox=*/true ) )
2621  {
2622  if (aFillAttributes.get() && aFillAttributes->isUsed())
2623  {
2624  // First see if fill attributes provide a color.
2625  aColor = Color(aFillAttributes->getAverageColor(aGlobalRetoucheColor.getBColor()));
2626  pCol = &aColor;
2627  }
2628 
2629  // If not, then fall back to the old brush item.
2630  if ( !pCol )
2631  {
2632  pCol = &pItem->GetColor();
2633  }
2634 
2637  if ( *pCol == COL_TRANSPARENT)
2638  pCol = nullptr;
2639  }
2640  else
2641  pCol = nullptr;
2642  }
2643 
2644  // no user defined color at paragraph or font background
2645  if ( ! pCol )
2646  pCol = &aGlobalRetoucheColor;
2647 
2648  if( GetShell() && GetShell()->GetWin() )
2649  {
2650  // here we determine the preferred window text color for painting
2651  const SwViewOption* pViewOption = GetShell()->GetViewOptions();
2652  if(pViewOption->IsPagePreview() &&
2653  !SW_MOD()->GetAccessibilityOptions().GetIsForPagePreviews())
2654  nNewColor = COL_BLACK;
2655  else
2656  // we take the font color from the appearance page
2657  nNewColor = SwViewOption::GetFontColor();
2658  }
2659 
2660  // change painting color depending of dark/bright background
2661  Color aTmpColor( nNewColor );
2662  if ( pCol->IsDark() && aTmpColor.IsDark() )
2663  nNewColor = COL_WHITE;
2664  else if ( pCol->IsBright() && aTmpColor.IsBright() )
2665  nNewColor = COL_BLACK;
2666  }
2667  }
2668 
2669  if ( bChgFntColor || bChgLineColor )
2670  {
2671  Color aNewColor( nNewColor );
2672 
2673  if ( bChgFntColor )
2674  {
2675  if ( pFont && aNewColor != pFont->GetColor() )
2676  {
2677  // only set the new color at the font passed as argument
2678  pFont->SetColor( aNewColor );
2679  }
2680  else if ( aNewColor != GetOut().GetFont().GetColor() )
2681  {
2682  // set new font with new color at output device
2683  vcl::Font aFont( rFnt );
2684  aFont.SetColor( aNewColor );
2685  GetOut().SetFont( aFont );
2686  }
2687  }
2688 
2689  // the underline and overline colors have to be set separately
2690  if ( bChgLineColor )
2691  {
2692  // get current font color or color set at output device
2693  aNewColor = pFont ? pFont->GetColor() : GetOut().GetFont().GetColor();
2694  if ( aNewColor != GetOut().GetLineColor() )
2695  GetOut().SetLineColor( aNewColor );
2696  if ( aNewColor != GetOut().GetOverlineColor() )
2697  GetOut().SetOverlineColor( aNewColor );
2698  }
2699 
2700  return true;
2701  }
2702 
2703  return false;
2704 }
2705 
2707 {
2708  for (SwFntObj* pFntObj = pFntCache->First(); pFntObj; pFntObj = SwFntCache::Next(pFntObj))
2709  pFntObj->GetTextGlyphs().clear();
2710 }
2711 
2712 /* 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:88
void SetDigitLanguage(LanguageType)
const bool bBidiPor
Definition: fntcache.cxx:259
sal_uInt16 GetCachePos() const
Definition: swcache.hxx:170
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:323
constexpr::Color COL_BLACK(0x00, 0x00, 0x00)
bool IsPagePreview() const
Definition: viewopt.hxx:596
virtual SwCacheObj * NewObj() override
Can be use in NewObj.
Definition: fntcache.cxx:2374
const OUString & GetFamilyName() const
SwFntAccess(const void *&rnFontCacheId, sal_uInt16 &rIndex, const void *pOwner, SwViewShell const *pShell, bool bCheck=false)
Definition: fntcache.cxx:2270
vcl::RenderContext * GetpOut() const
Definition: drawfont.hxx:185
bool m_bPaintBlank
Definition: fntcache.hxx:96
std::map< SwTextGlyphsKey, SalLayoutGlyphs > m_aTextGlyphs
Cache of already calculated layout glyphs.
Definition: fntcache.hxx:99
SwFont * GetFont() const
Definition: drawfont.hxx:250
void Lock()
Definition: swcache.cxx:477
long AdjustWidth(long n)
SwCacheObj * m_pObj
Definition: swcache.hxx:201
virtual bool IsVirtual() const
const SwAccessibilityOptions * GetAccessibilityOptions() const
Definition: viewsh.hxx:434
long AdjustX(long nHorzMove)
void DrawWaveLine(const Point &rStartPos, const Point &rEndPos, long nLineWidth=1)
SwDocShell * GetDocShell()
Definition: doc.hxx:1342
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:95
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:483
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:91
void SetWeight(FontWeight)
sal_uInt16 GetGuessedLeading() const
Definition: fntcache.hxx:114
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:2591
WrongAreaLineType mLineType
Definition: wrong.hxx:75
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:69
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:92
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:202
sal_uInt16 GetZoom() const
Definition: fntcache.hxx:125
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:2382
void SetMapMode()
sal_uInt8 DirType(const TextFrameIndex nPos) const
Definition: porlay.cxx:1467
bool operator<(const SwTextGlyphsKey &l, const SwTextGlyphsKey &r)
Definition: fntcache.cxx:132
VclPtr< OutputDevice > m_pPrinter
Definition: fntcache.hxx:86
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:111
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:144
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:74
FontKerning GetKerning() const
LINESTYLE_NONE
void setX(long nX)
OUTDEV_WINDOW
const Fraction & GetScaleY() const
bool getBrowseMode() const
Definition: viewopt.hxx:433
const vcl::Font & GetFont() const
SwBreakIt * g_pBreakIt
Definition: breakit.cxx:33
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:1709
std::shared_ptr< SdrAllFillAttributesHelper > SdrAllFillAttributesHelperPtr
Definition: format.hxx:38
TextFrameIndex GetCursorOfst(SwDrawTextInfo &rInf)
Definition: fntcache.cxx:2084
void Flush()
Definition: fntcache.cxx:165
o3tl::enumarray< SwFontScript, SwSubFont > m_aSub
Definition: swfont.hxx:134
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:68
sal_uInt16 GetKanaComp() const
Definition: drawfont.hxx:307
void SetLanguage(LanguageType)
SwFontScript GetActual() const
Definition: swfont.hxx:183
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:67
OUString m_aText
Definition: fntcache.hxx:70
const OUString & GetText() const
Definition: drawfont.hxx:216
sw::WrongListIterator * GetSmartTags() const
Definition: drawfont.hxx:237
vcl::Font * m_pScrFont
Definition: fntcache.hxx:84
vcl::RenderContext & GetRefDev() const
Definition: viewsh.cxx:2080
static bool IsArabicText(const OUString &rText, TextFrameIndex nStt, TextFrameIndex nLen)
Checks if text is Arabic text.
Definition: porlay.cxx:1911
void CreatePrtFont(const OutputDevice &rOut)
Definition: fntcache.cxx:206
vcl::Font * m_pPrtFont
Definition: fntcache.hxx:85
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:2575
#define SW_MOD()
Definition: swmodule.hxx:256
void GuessLeading(const SwViewShell &rSh, const FontMetric &rMet)
Definition: fntcache.cxx:562
SwFontScript m_nActual
Definition: swfont.hxx:163
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:151
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:2514
int i
QPRO_FUNC_TYPE const nType
bool IsBright() const
const Color * GetBackColor() const
Definition: swfont.hxx:191
const sal_Unicode CH_BLANK
Definition: swfont.hxx:42
long GetHeight() const
Definition: swfont.hxx:283
bool IsWordLineMode() const
sal_uInt16 m_nZoom
Definition: fntcache.hxx:94
virtual SfxStyleSheetBasePool * GetStyleSheetPool() override
For Style PI.
Definition: docsh.cxx:1165
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:126
float u
Provides access to settings of a document.
const Size & GetFontSize() const
#define NON_PRINTING_CHARACTER_COLOR
Definition: txtfrm.hxx:50
FontStrikeout GetStrikeout() const
void SetOverlineColor()
sal_uInt16 const m_nPropWidth
Definition: fntcache.hxx:93
OUString SwResId(const char *pId)
Definition: swmodule.cxx:190
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
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:149
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:2382
const bool bSwitchL2R
Definition: fntcache.cxx:256
Point PixelToLogic(const Point &rDevicePt) const
Point LogicToPixel(const Point &rLogicPt) const
css::uno::Reference< css::i18n::XBreakIterator > const & GetBreakIter() const
Definition: breakit.hxx:62
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:693
sal_Int32 m_nIndex
Definition: fntcache.hxx:71
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:110
long GetSperren() const
Definition: drawfont.hxx:312
void SetDevFont(const SwViewShell *pSh, OutputDevice &rOut)
Definition: fntcache.cxx:642
LanguageType GetLanguage() const
Definition: swfont.hxx:282
static long nPixWidth
Definition: fntcache.hxx:101
const Color & GetColor() const
short GetOrientation() const
SwFntObj * Get()
Definition: fntcache.hxx:159
sal_uInt32 GetHeight() const
sal_Int32 m_nLength
Definition: fntcache.hxx:72
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 derive a class from the SwCacheObj and store thei...
Definition: swcache.hxx:133
void SetFont(const vcl::Font &rNewFont)
const o3tl::enumarray< SvxAdjust, unsigned short > aSvxToUnoAdjust USHRT_MAX
Definition: unosett.cxx:261
const Point & GetPos() const
Definition: drawfont.hxx:195
LanguageType GetDigitLanguage() const
static MapMode * pPixMap
Definition: fntcache.hxx:102
TextFrameIndex GetLen() const
Definition: drawfont.hxx:268
sal_uInt16 m_nPrtAscent
Definition: fntcache.hxx:90
static Color & GetFontColor()
Definition: viewopt.cxx:428
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:2085
SwFntObj * First()
Definition: fntcache.hxx:139
long GetInternalLeading() const
bool IsRightToLeft() const
Definition: frame.hxx:963
SwFntObj * pLastFont
Definition: fntcache.cxx:70
sal_uInt16 GetZoom() const
Definition: viewopt.hxx:466
void SwClearFntCacheTextGlyphs()
Clears the pre-calculated text glyphs in all SwFntObj instances.
Definition: fntcache.cxx:2706
static bool isKorean(LanguageType nLang)
SwFntObj(const SwSubFont &rFont, std::uintptr_t nFontCacheId, SwViewShell const *pSh)
Definition: fntcache.cxx:175
long GetBulletOffset() const
bool IsPrtFormat() const
Definition: viewopt.hxx:502
constexpr::Color COL_WHITE(0xFF, 0xFF, 0xFF)
SwFontScript
Definition: swfont.hxx:122
sal_uInt16 GetGridWidth(SwTextGridItem const &, SwDoc const &)
Definition: pagechg.cxx:2528
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:483
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)
FontLineStyle GetUnderline() const
size_t CountKashida() const
Definition: scriptinfo.hxx:146
void DrawText(SwDrawTextInfo &rInf)
Definition: fntcache.cxx:838
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:194
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:87
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:176
vcl::Font m_aFont
Definition: fntcache.hxx:83
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:1826
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:115
aStr
FontStrikeout
Color aGlobalRetoucheColor
Definition: paintfrm.cxx:239
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
rtl_TextEncoding GetCharSet() const
long Y() const
const void * GetOwner() const
Definition: swcache.hxx:167
sal_uInt16 m_nScrAscent
Definition: fntcache.hxx:89
Size GetTextSize(SwDrawTextInfo &rInf)
determine the TextSize (of the printer)
Definition: fntcache.cxx:1882
sal_uInt16 m_nPrtHeight
Definition: fntcache.hxx:92
static vcl::DeleteOnDeinit< VclPtr< OutputDevice > > s_pFntObjPixOut(new VclPtr< OutputDevice >)
void setHeight(long nHeight)
typedef void(CALLTYPE *GetFuncDataPtr)(sal_uInt16 &nNo