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