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