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