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