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