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