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