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 59 : VclPtr<OutputDevice> SwFntObj::pPixOut;
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 : const SvxFontHeightItem &aDefaultFontItem = static_cast<const 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 3124 : void SwFntCache::Flush( )
97 : {
98 3124 : if ( pLastFont )
99 : {
100 3053 : pLastFont->Unlock();
101 3053 : pLastFont = NULL;
102 : }
103 3124 : SwCache::Flush( );
104 3124 : }
105 :
106 7743 : SwFntObj::SwFntObj(const SwSubFont &rFont, const void *pOwn, SwViewShell const *pSh)
107 : : SwCacheObj(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 7743 : , nPropWidth(rFont.GetPropWidth())
119 : {
120 7743 : nZoom = pSh ? pSh->GetViewOptions()->GetZoom() : USHRT_MAX;
121 7743 : bSymbol = RTL_TEXTENCODING_SYMBOL == aFont.GetCharSet();
122 7743 : bPaintBlank = ( UNDERLINE_NONE != aFont.GetUnderline()
123 7189 : || UNDERLINE_NONE != aFont.GetOverline()
124 7182 : || STRIKEOUT_NONE != aFont.GetStrikeout() )
125 8352 : && !aFont.IsWordLineMode();
126 7743 : aFont.SetLanguage(rFont.GetLanguage());
127 7743 : }
128 :
129 23229 : SwFntObj::~SwFntObj()
130 : {
131 7743 : if ( pScrFont != pPrtFont )
132 5937 : delete pScrFont;
133 7743 : if ( pPrtFont != &aFont )
134 77 : delete pPrtFont;
135 15486 : }
136 :
137 550457 : void SwFntObj::CreatePrtFont( const OutputDevice& rPrt )
138 : {
139 550457 : if ( nPropWidth != 100 && pPrinter != &rPrt )
140 : {
141 284 : if( pScrFont != pPrtFont )
142 284 : delete pScrFont;
143 284 : if( pPrtFont != &aFont )
144 207 : delete pPrtFont;
145 :
146 284 : const vcl::Font aOldFnt( rPrt.GetFont() );
147 284 : ((OutputDevice&)rPrt).SetFont( aFont );
148 568 : const FontMetric aWinMet( rPrt.GetFontMetric() );
149 284 : ((OutputDevice&)rPrt).SetFont( aOldFnt );
150 284 : long nWidth = ( aWinMet.GetSize().Width() * nPropWidth ) / 100;
151 :
152 284 : if( !nWidth )
153 0 : ++nWidth;
154 284 : pPrtFont = new vcl::Font( aFont );
155 284 : pPrtFont->SetSize( Size( nWidth, aFont.GetSize().Height() ) );
156 568 : pScrFont = NULL;
157 : }
158 550457 : }
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 1138402 : static bool lcl_IsFontAdjustNecessary( const vcl::RenderContext& rOutDev,
171 : const vcl::RenderContext& rRefDev )
172 : {
173 51706 : return &rRefDev != &rOutDev &&
174 1241314 : OUTDEV_WINDOW != rRefDev.GetOutDevType() &&
175 52092 : ( OUTDEV_PRINTER != rRefDev.GetOutDevType() ||
176 1139038 : 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 6076 : 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 6076 : bBidiPor( _bBidiPor )
201 : {
202 6076 : }
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 967 : static void lcl_calcLinePos( const CalcLinePosData &rData,
208 : Point &rStart, Point &rEnd, sal_Int32 nStart, sal_Int32 nWrLen )
209 : {
210 967 : long nBlank = 0;
211 967 : const sal_Int32 nEnd = nStart + nWrLen;
212 967 : const long nTmpSpaceAdd = rData.rInf.GetSpace() / SPACING_PRECISION_FACTOR;
213 :
214 1934 : if ( nEnd < rData.nCnt
215 967 : && CH_BLANK == rData.rInf.GetText()[ rData.rInf.GetIdx() + nEnd ] )
216 : {
217 303 : if( nEnd + 1 == rData.nCnt )
218 21 : nBlank -= nTmpSpaceAdd;
219 : else
220 282 : nBlank -= rData.nHalfSpace;
221 : }
222 :
223 : // determine start, end and length of wave line
224 967 : sal_Int32 nKernStart = nStart ? rData.pKernArray[ nStart - 1 ] : 0;
225 967 : sal_Int32 nKernEnd = rData.pKernArray[ nEnd - 1 ];
226 :
227 : const sal_uInt16 nDir = rData.bBidiPor ? 1800 :
228 967 : UnMapDirection( rData.rFont.GetOrientation(), rData.bSwitchH2V );
229 :
230 967 : switch ( nDir )
231 : {
232 : case 0 :
233 967 : rStart.X() += nKernStart;
234 967 : rEnd.X() = nBlank + rData.rInf.GetPos().X() + nKernEnd;
235 967 : rEnd.Y() = rData.rInf.GetPos().Y();
236 967 : 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 967 : if ( rData.bSwitchL2R )
255 : {
256 0 : rData.rInf.GetFrm()->SwitchLTRtoRTL( rStart );
257 0 : rData.rInf.GetFrm()->SwitchLTRtoRTL( rEnd );
258 : }
259 :
260 967 : if ( rData.bSwitchH2V )
261 : {
262 0 : rData.rInf.GetFrm()->SwitchHorizontalToVertical( rStart );
263 0 : rData.rInf.GetFrm()->SwitchHorizontalToVertical( rEnd );
264 : }
265 967 : }
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 247114 : sal_uInt16 SwFntObj::GetFontAscent( const SwViewShell *pSh, const OutputDevice& rOut )
270 : {
271 247114 : sal_uInt16 nRet = 0;
272 247114 : const OutputDevice& rRefDev = pSh ? pSh->GetRefDev() : rOut;
273 :
274 247114 : if ( pSh && lcl_IsFontAdjustNecessary( rOut, rRefDev ) )
275 : {
276 978 : CreateScrFont( *pSh, rOut );
277 : OSL_ENSURE( USHRT_MAX != nScrAscent, "nScrAscent is going berzerk" );
278 978 : nRet = nScrAscent;
279 : }
280 : else
281 : {
282 246136 : if (nPrtAscent == USHRT_MAX) // printer ascent unknown?
283 : {
284 8038 : CreatePrtFont( rOut );
285 8038 : const vcl::Font aOldFnt( rRefDev.GetFont() );
286 8038 : ((OutputDevice&)rRefDev).SetFont( *pPrtFont );
287 16076 : const FontMetric aOutMet( rRefDev.GetFontMetric() );
288 8038 : nPrtAscent = (sal_uInt16) aOutMet.GetAscent();
289 16076 : ( (OutputDevice&)rRefDev).SetFont( aOldFnt );
290 : }
291 :
292 246136 : 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 247114 : nRet += GetFontLeading( pSh, rRefDev );
298 : #endif
299 :
300 : OSL_ENSURE( USHRT_MAX != nRet, "GetFontAscent returned USHRT_MAX" );
301 247114 : 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 318614 : sal_uInt16 SwFntObj::GetFontHeight( const SwViewShell* pSh, const OutputDevice& rOut )
307 : {
308 318614 : sal_uInt16 nRet = 0;
309 318614 : const OutputDevice& rRefDev = pSh ? pSh->GetRefDev() : rOut;
310 :
311 318614 : if ( pSh && lcl_IsFontAdjustNecessary( rOut, rRefDev ) )
312 : {
313 696 : CreateScrFont( *pSh, rOut );
314 : OSL_ENSURE( USHRT_MAX != nScrHeight, "nScrHeight is going berzerk" );
315 696 : nRet = nScrHeight + GetFontLeading( pSh, rRefDev );
316 : }
317 : else
318 : {
319 317918 : if (nPrtHeight == USHRT_MAX) // printer height unknown?
320 : {
321 10514 : CreatePrtFont( rOut );
322 10514 : const vcl::Font aOldFnt( rRefDev.GetFont() );
323 10514 : ((OutputDevice&)rRefDev).SetFont( *pPrtFont );
324 10514 : 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 10514 : ((OutputDevice&)rRefDev).SetFont( aOldFnt );
337 : }
338 :
339 317918 : nRet = nPrtHeight + GetFontLeading( pSh, rRefDev );
340 : }
341 :
342 : OSL_ENSURE( USHRT_MAX != nRet, "GetFontHeight returned USHRT_MAX" );
343 318614 : return nRet;
344 : }
345 :
346 1222863 : sal_uInt16 SwFntObj::GetFontLeading( const SwViewShell *pSh, const OutputDevice& rOut )
347 : {
348 1222863 : sal_uInt16 nRet = 0;
349 :
350 1222863 : if ( pSh )
351 : {
352 1222473 : if ( USHRT_MAX == nGuessedLeading || USHRT_MAX == nExtLeading )
353 : {
354 10601 : SolarMutexGuard aGuard;
355 :
356 21202 : const vcl::Font aOldFnt( rOut.GetFont() );
357 10601 : ((OutputDevice&)rOut).SetFont( *pPrtFont );
358 21202 : const FontMetric aMet( rOut.GetFontMetric() );
359 10601 : ((OutputDevice&)rOut).SetFont( aOldFnt );
360 10601 : bSymbol = RTL_TEXTENCODING_SYMBOL == aMet.GetCharSet();
361 10601 : GuessLeading( *pSh, aMet );
362 10601 : 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 10601 : if( bSymbol || IsStarSymbol( pPrtFont->GetName()))
379 10747 : nExtLeading = 0;
380 : }
381 :
382 1222473 : const IDocumentSettingAccess& rIDSA = *pSh->getIDocumentSettingAccess();
383 2441998 : const bool bBrowse = ( pSh->GetWin() &&
384 1223001 : pSh->GetViewOptions()->getBrowseMode() &&
385 1223001 : !pSh->GetViewOptions()->IsPrtFormat() );
386 :
387 1222473 : if ( !bBrowse && rIDSA.get(DocumentSettingId::ADD_EXT_LEADING) )
388 1202133 : nRet = nExtLeading;
389 : else
390 20340 : nRet = nGuessedLeading;
391 : }
392 :
393 : OSL_ENSURE( USHRT_MAX != nRet, "GetFontLeading returned USHRT_MAX" );
394 1222863 : return nRet;
395 : }
396 :
397 : // pOut is the output device, not the reference device
398 52926 : void SwFntObj::CreateScrFont( const SwViewShell& rSh, const OutputDevice& rOut )
399 : {
400 52926 : if ( pScrFont )
401 104046 : return;
402 :
403 : // any changes to the output device are reset at the end of the function
404 1806 : OutputDevice* pOut = const_cast<OutputDevice*>(&rOut);
405 :
406 : // Save old font
407 1806 : vcl::Font aOldOutFont( pOut->GetFont() );
408 :
409 1806 : nScrHeight = USHRT_MAX;
410 :
411 : // Condition for output font / refdev font adjustment
412 1806 : OutputDevice* pPrt = &rSh.GetRefDev();
413 :
414 5240 : if( !rSh.GetWin() ||
415 1806 : !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 1806 : CreatePrtFont( *pPrt );
421 1806 : pPrinter = pPrt;
422 :
423 : // save old reference device font
424 1806 : 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 1806 : pPrt->SetFont( *pPrtFont );
429 1806 : pOut->SetFont( *pPrtFont );
430 :
431 : // This should be the default for pScrFont.
432 1806 : pScrFont = pPrtFont;
433 :
434 3612 : 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 1806 : aMet.SetWeight(pScrFont->GetWeight());
438 1806 : aMet.SetItalic(pScrFont->GetItalic());
439 :
440 1806 : bSymbol = RTL_TEXTENCODING_SYMBOL == aMet.GetCharSet();
441 :
442 1806 : if ( USHRT_MAX == nGuessedLeading )
443 559 : GuessLeading( rSh, aMet );
444 :
445 1806 : if ( USHRT_MAX == nExtLeading )
446 559 : nExtLeading = static_cast<sal_uInt16>(aMet.GetExtLeading());
447 :
448 : // reset the original reference device font
449 3612 : 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 5418 : if( pOut->GetMapMode().GetScaleX().IsValid() &&
471 3612 : pOut->GetMapMode().GetScaleY().IsValid() &&
472 1806 : pOut->GetMapMode().GetScaleX() == pOut->GetMapMode().GetScaleY() )
473 : {
474 1806 : nTmp = ( 100 * pOut->GetMapMode().GetScaleX().GetNumerator() ) /
475 1806 : pOut->GetMapMode().GetScaleX().GetDenominator();
476 : }
477 : else
478 0 : nTmp = 0;
479 1806 : if( nTmp != nZoom )
480 71 : nZoom = USHRT_MAX - 1;
481 : }
482 :
483 1806 : nScrAscent = (sal_uInt16)pOut->GetFontMetric().GetAscent();
484 1806 : if ( USHRT_MAX == nScrHeight )
485 1806 : nScrHeight = (sal_uInt16)pOut->GetTextHeight();
486 :
487 : // reset original output device font
488 1806 : pOut->SetFont( aOldOutFont );
489 : }
490 :
491 11160 : 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 11160 : if ( rMet.GetIntLeading() >= 5 )
500 : {
501 7560 : nGuessedLeading = 0;
502 18720 : 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 3600 : 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 552067 : void SwFntObj::SetDevFont( const SwViewShell *pSh, OutputDevice& rOut )
570 : {
571 552067 : const OutputDevice& rRefDev = pSh ? pSh->GetRefDev() : rOut;
572 :
573 552067 : if ( pSh && lcl_IsFontAdjustNecessary( rOut, rRefDev ) )
574 : {
575 28860 : CreateScrFont( *pSh, rOut );
576 28860 : if( !GetScrFont()->IsSameInstance( rOut.GetFont() ) )
577 19758 : rOut.SetFont( *pScrFont );
578 28860 : if( pPrinter && ( !pPrtFont->IsSameInstance( pPrinter->GetFont() ) ) )
579 5184 : pPrinter->SetFont( *pPrtFont );
580 : }
581 : else
582 : {
583 523207 : CreatePrtFont( rOut );
584 523207 : if( !pPrtFont->IsSameInstance( rOut.GetFont() ) )
585 46398 : 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 552067 : GetFontLeading( pSh, rRefDev );
591 552067 : }
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 vcl::RenderContext& 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 18228 : 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 35783 : if (!pWList) return;
644 :
645 6076 : sal_Int32 nStart = rInf.GetIdx();
646 6076 : sal_Int32 nWrLen = rInf.GetLen();
647 :
648 : // check if respective data is available in the current text range
649 6076 : if (!pWList->Check( nStart, nWrLen ))
650 : {
651 5403 : return;
652 : }
653 :
654 673 : 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 673 : if (pWList != rInf.GetSmartTags() && WRONG_SHOW_MIN >= nHght)
659 : {
660 0 : return;
661 : }
662 :
663 673 : SwForbidden::iterator pIter = rForbidden.begin();
664 673 : if (rInf.GetOut().GetConnectMetaFile())
665 0 : rInf.GetOut().Push();
666 :
667 673 : const Color aCol( rInf.GetOut().GetLineColor() );
668 :
669 : // iterate over all ranges stored in the respective SwWrongList
670 967 : do
671 : {
672 967 : nStart -= rInf.GetIdx();
673 :
674 967 : const sal_Int32 nEnd = nStart + nWrLen;
675 967 : sal_Int32 nNext = nStart;
676 2901 : while( nNext < nEnd )
677 : {
678 3556 : while( pIter != rForbidden.end() && pIter->second <= nNext )
679 1622 : ++pIter;
680 :
681 967 : const sal_Int32 nNextStart = nNext;
682 967 : sal_Int32 nNextEnd = nEnd;
683 :
684 967 : if( pIter == rForbidden.end() || nNextEnd <= pIter->first )
685 : {
686 : // No overlapping mark up found
687 967 : std::pair< sal_Int32, sal_Int32 > aNew;
688 967 : aNew.first = nNextStart;
689 967 : aNew.second = nNextEnd;
690 967 : rForbidden.insert( pIter, aNew );
691 967 : pIter = rForbidden.begin();
692 967 : 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 967 : Point aStart( rInf.GetPos() );
707 967 : Point aEnd;
708 967 : lcl_calcLinePos( rCalcLinePosData, aStart, aEnd, nNextStart, nNextEnd - nNextStart );
709 :
710 967 : const sal_uInt16 wrongPos = pWList->GetWrongPos(nNextStart + rInf.GetIdx());
711 :
712 967 : const SwWrongArea* wrongArea = pWList->GetElement(wrongPos);
713 :
714 967 : if (wrongArea != 0)
715 : {
716 967 : 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 967 : else if (WRONGAREA_WAVE == wrongArea->mLineType)
731 : {
732 967 : rInf.GetOut().SetLineColor( wrongArea->mColor );
733 :
734 967 : rInf.GetOut().DrawWaveLine( aStart, aEnd );
735 : }
736 : }
737 : }
738 :
739 967 : nStart = nEnd + rInf.GetIdx();
740 967 : nWrLen = rInf.GetIdx() + rInf.GetLen() - nStart;
741 : }
742 967 : while (nWrLen && pWList->Check( nStart, nWrLen ));
743 :
744 673 : rInf.GetOut().SetLineColor( aCol );
745 :
746 673 : if (rInf.GetOut().GetConnectMetaFile())
747 0 : rInf.GetOut().Pop();
748 : }
749 :
750 20965 : void SwFntObj::DrawText( SwDrawTextInfo &rInf )
751 : {
752 : OSL_ENSURE( rInf.GetShell(), "SwFntObj::DrawText without shell" );
753 :
754 20965 : OutputDevice& rRefDev = rInf.GetShell()->GetRefDev();
755 20965 : OutputDevice* pWin = rInf.GetShell()->GetWin();
756 :
757 : // true if pOut is the printer and the printer has been used for formatting
758 20965 : const bool bPrt = OUTDEV_PRINTER == rInf.GetOut().GetOutDevType() &&
759 20965 : OUTDEV_PRINTER == rRefDev.GetOutDevType();
760 20522 : const bool bBrowse = ( pWin &&
761 20565 : rInf.GetShell()->GetViewOptions()->getBrowseMode() &&
762 86 : !rInf.GetShell()->GetViewOptions()->IsPrtFormat() &&
763 86 : !rInf.GetBullet() &&
764 129 : ( rInf.GetSpace() || !rInf.GetKern() ) &&
765 86 : !rInf.GetWrong() &&
766 86 : !rInf.GetGrammarCheck() &&
767 21051 : !rInf.GetSmartTags() &&
768 21008 : !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 20965 : const bool bDirectPrint = bPrt || bBrowse;
773 :
774 : // Condition for output font / refdev font adjustment
775 : const bool bUseScrFont =
776 20965 : lcl_IsFontAdjustNecessary( rInf.GetOut(), rRefDev );
777 :
778 20965 : 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 20965 : 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 20965 : const bool bSwitchH2V = rInf.GetFrm() && rInf.GetFrm()->IsVertical();
869 20974 : const bool bSwitchL2R = rInf.GetFrm() && rInf.GetFrm()->IsRightToLeft() &&
870 20974 : ! rInf.IsIgnoreFrmRTL();
871 20965 : const ComplexTextLayoutMode nMode = rInf.GetOut().GetLayoutMode();
872 20965 : const bool bBidiPor = ( bSwitchL2R !=
873 20965 : ( TEXT_LAYOUT_DEFAULT != ( TEXT_LAYOUT_BIDI_RTL & nMode ) ) );
874 :
875 : // be sure to have the correct layout mode at the printer
876 20965 : if ( pPrinter )
877 : {
878 20960 : pPrinter->SetLayoutMode( rInf.GetOut().GetLayoutMode() );
879 20960 : pPrinter->SetDigitLanguage( rInf.GetOut().GetDigitLanguage() );
880 : }
881 :
882 20965 : Point aTextOriginPos( rInf.GetPos() );
883 20965 : if( !bPrt )
884 : {
885 20965 : if( rInf.GetpOut() != pPixOut || rInf.GetOut().GetMapMode() != *pPixMap )
886 : {
887 1000 : *pPixMap = rInf.GetOut().GetMapMode();
888 1000 : pPixOut = rInf.GetpOut();
889 1000 : Size aTmp( 1, 1 );
890 1000 : nPixWidth = rInf.GetOut().PixelToLogic( aTmp ).Width();
891 : }
892 :
893 20965 : aTextOriginPos.X() += rInf.GetFrm()->IsRightToLeft() ? 0 : nPixWidth;
894 : }
895 :
896 20965 : Color aOldColor( pTmpFont->GetColor() );
897 20965 : bool bChgColor = rInf.ApplyAutoColor( pTmpFont );
898 20965 : if( !pTmpFont->IsSameInstance( rInf.GetOut().GetFont() ) )
899 16432 : rInf.GetOut().SetFont( *pTmpFont );
900 20965 : if ( bChgColor )
901 16432 : pTmpFont->SetColor( aOldColor );
902 :
903 20965 : if ( COMPLETE_STRING == rInf.GetLen() )
904 0 : rInf.SetLen( rInf.GetText().getLength() );
905 :
906 : // ASIAN LINE AND CHARACTER GRID MODE START
907 :
908 40709 : if ( rInf.GetFrm() && rInf.SnapToGrid() && rInf.GetFont() &&
909 19744 : SW_CJK == rInf.GetFont()->GetActual() )
910 : {
911 57 : SwTextGridItem const*const pGrid(GetGridItem(rInf.GetFrm()->FindPageFrm()));
912 :
913 : // ASIAN LINE AND CHARACTER GRID MODE: Do we want to snap asian characters to the grid?
914 57 : if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && pGrid->IsSnapToChars())
915 : {
916 : //for textgrid refactor
917 : //const sal_uInt16 nGridWidth = pGrid->GetBaseHeight();
918 0 : const SwDoc* pDoc = rInf.GetShell()->GetDoc();
919 0 : const sal_uInt16 nGridWidth = GetGridWidth(*pGrid, *pDoc);
920 :
921 : // kerning array - gives the absolute position of end of each character
922 0 : long* pKernArray = new long[rInf.GetLen()];
923 :
924 0 : if ( pPrinter )
925 0 : pPrinter->GetTextArray( rInf.GetText(), pKernArray,
926 0 : rInf.GetIdx(), rInf.GetLen() );
927 : else
928 0 : rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray,
929 0 : rInf.GetIdx(), rInf.GetLen() );
930 :
931 : // Change the average width per character to an appropriate grid width
932 : // basically get the ratio of the avg width to the grid unit width, then
933 : // multiple this ratio to give the new avg width - which in this case
934 : // gives a new grid width unit size
935 :
936 0 : long nAvgWidthPerChar = pKernArray[ rInf.GetLen() - 1 ] / rInf.GetLen();
937 :
938 : const sal_uLong nRatioAvgWidthCharToGridWidth = nAvgWidthPerChar ?
939 0 : ( nAvgWidthPerChar - 1 ) / nGridWidth + 1:
940 0 : 1;
941 :
942 0 : nAvgWidthPerChar = nRatioAvgWidthCharToGridWidth * nGridWidth;
943 :
944 : // the absolute end position of the first character is also its width
945 0 : long nCharWidth = pKernArray[ 0 ];
946 0 : sal_uLong nHalfWidth = nAvgWidthPerChar / 2;
947 :
948 0 : long nNextFix=0;
949 :
950 : // we work out the start position (origin) of the first character,
951 : // and we set the next "fix" offset to half the width of the char.
952 : // The exceptions are for punctuation characters that are not centered
953 : // so in these cases we just add half a regular "average" character width
954 : // to the first characters actual width to allow the next character to
955 : // be centred automatically
956 : // If the character is "special right", then the offset is correct already
957 : // so the fix offset is as normal - half the average character width
958 :
959 0 : sal_Unicode cChar = rInf.GetText()[ rInf.GetIdx() ];
960 0 : sal_uInt8 nType = lcl_WhichPunctuation( cChar );
961 0 : switch ( nType )
962 : {
963 : // centre character
964 : case SwScriptInfo::NONE :
965 0 : aTextOriginPos.X() += ( nAvgWidthPerChar - nCharWidth ) / 2;
966 0 : nNextFix = nCharWidth / 2;
967 0 : break;
968 : case SwScriptInfo::SPECIAL_RIGHT :
969 0 : nNextFix = nHalfWidth;
970 0 : break;
971 : // punctuation
972 : default:
973 0 : aTextOriginPos.X() += nAvgWidthPerChar - nCharWidth;
974 0 : nNextFix = nCharWidth - nHalfWidth;
975 : }
976 :
977 : // calculate offsets
978 0 : for( sal_Int32 j = 1; j < rInf.GetLen(); ++j )
979 : {
980 0 : long nCurrentCharWidth = pKernArray[ j ] - pKernArray[ j - 1 ];
981 0 : nNextFix += nAvgWidthPerChar;
982 :
983 : // almost the same as getting the offset for the first character:
984 : // punctuation characters are not centered, so just add half an
985 : // average character width minus the characters actual char width
986 : // to get the offset intot the centre of the next character
987 :
988 0 : cChar = rInf.GetText()[ rInf.GetIdx() + j ];
989 0 : nType = lcl_WhichPunctuation( cChar );
990 0 : switch ( nType )
991 : {
992 : case SwScriptInfo::NONE :
993 0 : pKernArray[ j - 1 ] = nNextFix - ( nCurrentCharWidth / 2 );
994 0 : break;
995 : case SwScriptInfo::SPECIAL_RIGHT :
996 0 : pKernArray[ j - 1 ] = nNextFix - nHalfWidth;
997 0 : break;
998 : default:
999 0 : pKernArray[ j - 1 ] = nNextFix + nHalfWidth - nCurrentCharWidth;
1000 : }
1001 : }
1002 :
1003 : // the layout engine requires the total width of the output
1004 0 : pKernArray[ rInf.GetLen() - 1 ] = rInf.GetWidth() -
1005 0 : aTextOriginPos.X() + rInf.GetPos().X() ;
1006 :
1007 0 : if ( bSwitchH2V )
1008 0 : rInf.GetFrm()->SwitchHorizontalToVertical( aTextOriginPos );
1009 :
1010 0 : rInf.GetOut().DrawTextArray( aTextOriginPos, rInf.GetText(),
1011 0 : pKernArray, rInf.GetIdx(), rInf.GetLen() );
1012 :
1013 0 : delete[] pKernArray;
1014 0 : return;
1015 : }
1016 : }
1017 :
1018 : // For text grid refactor
1019 : // ASIAN LINE AND CHARACTER GRID MODE START: not snap to characters
1020 :
1021 40709 : if ( rInf.GetFrm() && rInf.SnapToGrid() && rInf.GetFont() &&
1022 19744 : SW_CJK == rInf.GetFont()->GetActual() )
1023 : {
1024 57 : SwTextGridItem const*const pGrid(GetGridItem(rInf.GetFrm()->FindPageFrm()));
1025 :
1026 : // ASIAN LINE AND CHARACTER GRID MODE - do not snap to characters
1027 57 : if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && !pGrid->IsSnapToChars() )
1028 : {
1029 0 : const long nGridWidthAdd = EvalGridWidthAdd( pGrid, rInf );
1030 :
1031 0 : long* pKernArray = new long[rInf.GetLen()];
1032 :
1033 0 : if ( pPrinter )
1034 0 : pPrinter->GetTextArray( rInf.GetText(), pKernArray,
1035 0 : rInf.GetIdx(), rInf.GetLen() );
1036 : else
1037 0 : rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray,
1038 0 : rInf.GetIdx(), rInf.GetLen() );
1039 0 : if ( bSwitchH2V )
1040 0 : rInf.GetFrm()->SwitchHorizontalToVertical( aTextOriginPos );
1041 0 : if ( rInf.GetSpace() || rInf.GetKanaComp())
1042 : {
1043 0 : long nSpaceAdd = rInf.GetSpace() / SPACING_PRECISION_FACTOR;
1044 0 : if ( rInf.GetFont() && rInf.GetLen() )
1045 : {
1046 0 : bool bSpecialJust = false;
1047 0 : const SwScriptInfo* pSI = rInf.GetScriptInfo();
1048 0 : const sal_uInt8 nActual = rInf.GetFont()->GetActual();
1049 : ///Kana Compression
1050 0 : if( SW_CJK == nActual && rInf.GetKanaComp() &&
1051 0 : pSI && pSI->CountCompChg() &&
1052 0 : lcl_IsMonoSpaceFont( *(rInf.GetpOut()) ) )
1053 : {
1054 : pSI->Compress( pKernArray, rInf.GetIdx(), rInf.GetLen(),
1055 0 : rInf.GetKanaComp(), (sal_uInt16)aFont.GetSize().Height(), &aTextOriginPos );
1056 0 : bSpecialJust = true;
1057 : }
1058 : ///Asian Justification
1059 0 : if ( ( SW_CJK == nActual || SW_LATIN == nActual ) && nSpaceAdd )
1060 : {
1061 0 : LanguageType aLang = rInf.GetFont()->GetLanguage( SW_CJK );
1062 0 : if (!MsLangId::isKorean(aLang))
1063 : {
1064 0 : long nSpaceSum = nSpaceAdd;
1065 0 : for ( sal_Int32 nI = 0; nI < rInf.GetLen(); ++nI )
1066 : {
1067 0 : pKernArray[ nI ] += nSpaceSum;
1068 0 : nSpaceSum += nSpaceAdd;
1069 : }
1070 0 : bSpecialJust = true;
1071 0 : nSpaceAdd = 0;
1072 : }
1073 : }
1074 0 : long nGridAddSum = nGridWidthAdd;
1075 0 : for(sal_Int32 i = 0; i < rInf.GetLen(); i++, nGridAddSum += nGridWidthAdd )
1076 : {
1077 0 : pKernArray[i] += nGridAddSum;
1078 : }
1079 0 : long nKernSum = rInf.GetKern();
1080 0 : if ( bSpecialJust || rInf.GetKern() )
1081 : {
1082 0 : for( sal_Int32 i = 0; i < rInf.GetLen(); i++, nKernSum += rInf.GetKern() )
1083 : {
1084 0 : if ( CH_BLANK == rInf.GetText()[ rInf.GetIdx()+i ] )
1085 0 : nKernSum += nSpaceAdd;
1086 0 : pKernArray[i] += nKernSum;
1087 : }
1088 : ///With through/uderstr. Grouped style requires a blank at the end
1089 : ///of a text edition special measures:
1090 0 : if( bPaintBlank && rInf.GetLen() && (CH_BLANK ==
1091 0 : rInf.GetText()[ rInf.GetIdx() + rInf.GetLen() - 1 ] ) )
1092 : {
1093 : ///If it concerns a singular, underlined space acts,
1094 : ///we must spend two:
1095 0 : if( 1 == rInf.GetLen() )
1096 : {
1097 0 : pKernArray[0] = rInf.GetWidth() + nSpaceAdd;
1098 0 : rInf.GetOut().DrawTextArray( aTextOriginPos, rInf.GetText(),
1099 0 : pKernArray, rInf.GetIdx(), 1 );
1100 : }
1101 : else
1102 : {
1103 0 : pKernArray[ rInf.GetLen() - 2] += nSpaceAdd;
1104 0 : rInf.GetOut().DrawTextArray( aTextOriginPos, rInf.GetText(),
1105 0 : pKernArray, rInf.GetIdx(), rInf.GetLen() );
1106 : }
1107 : }
1108 : else
1109 : {
1110 0 : rInf.GetOut().DrawTextArray( aTextOriginPos, rInf.GetText(),
1111 0 : pKernArray, rInf.GetIdx(), rInf.GetLen() );
1112 : }
1113 : }
1114 : else
1115 : {
1116 0 : Point aTmpPos( aTextOriginPos );
1117 : sal_Int32 i;
1118 0 : sal_Int32 j = 0;
1119 0 : long nSpaceSum = 0;
1120 0 : for( i = 0; i < rInf.GetLen(); i++ )
1121 : {
1122 0 : if( CH_BLANK == rInf.GetText()[ rInf.GetIdx() + i ] )
1123 : {
1124 0 : nSpaceSum += nSpaceAdd;
1125 0 : if( j < i)
1126 0 : rInf.GetOut().DrawText( aTmpPos, rInf.GetText(),
1127 0 : rInf.GetIdx() + j, i - j );
1128 0 : j = i + 1;
1129 0 : pKernArray[i] = pKernArray[i] + nSpaceSum;
1130 0 : aTmpPos.X() = aTextOriginPos.X() + pKernArray[ i ] + nKernSum;
1131 : }
1132 : }
1133 0 : if( j < i )
1134 0 : rInf.GetOut().DrawText( aTmpPos, rInf.GetText(),
1135 0 : rInf.GetIdx() +j , i - j );
1136 : }
1137 : }
1138 : }
1139 : else
1140 : {
1141 : //long nKernAdd = rInf.GetKern();
1142 0 : long nKernAdd = 0;
1143 0 : long nGridAddSum = nGridWidthAdd + nKernAdd;
1144 0 : for(sal_Int32 i = 0; i < rInf.GetLen(); i++,nGridAddSum += nGridWidthAdd + nKernAdd )
1145 : {
1146 0 : pKernArray[i] += nGridAddSum;
1147 : }
1148 0 : rInf.GetOut().DrawTextArray( aTextOriginPos, rInf.GetText(),
1149 0 : pKernArray, rInf.GetIdx(), rInf.GetLen() );
1150 : }
1151 0 : delete[] pKernArray;
1152 0 : return;
1153 : }
1154 : }
1155 :
1156 : // DIRECT PAINTING WITHOUT SCREEN ADJUSTMENT
1157 :
1158 20965 : if ( bDirectPrint )
1159 : {
1160 43 : const Fraction aTmp( 1, 1 );
1161 45 : bool bStretch = rInf.GetWidth() && ( rInf.GetLen() > 1 ) && bPrt
1162 43 : && ( aTmp != rInf.GetOut().GetMapMode().GetScaleX() );
1163 :
1164 43 : if ( bSwitchL2R )
1165 0 : rInf.GetFrm()->SwitchLTRtoRTL( aTextOriginPos );
1166 :
1167 43 : if ( bSwitchH2V )
1168 0 : rInf.GetFrm()->SwitchHorizontalToVertical( aTextOriginPos );
1169 :
1170 : // In the good old days we used to have a simple DrawText if the
1171 : // output device is the printer. Now we need a DrawTextArray if
1172 : // 1. KanaCompression is enabled
1173 : // 2. Justified alignment
1174 : // Simple kerning is handled by DrawStretchText
1175 43 : if( rInf.GetSpace() || rInf.GetKanaComp() )
1176 : {
1177 0 : long *pKernArray = new long[ rInf.GetLen() ];
1178 0 : rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray,
1179 0 : rInf.GetIdx(), rInf.GetLen() );
1180 :
1181 0 : if( bStretch )
1182 : {
1183 0 : sal_Int32 nZwi = rInf.GetLen() - 1;
1184 0 : long nDiff = rInf.GetWidth() - pKernArray[ nZwi ]
1185 0 : - rInf.GetLen() * rInf.GetKern();
1186 0 : long nRest = nDiff % nZwi;
1187 : long nAdd;
1188 0 : if( nRest < 0 )
1189 : {
1190 0 : nAdd = -1;
1191 0 : nRest += nZwi;
1192 : }
1193 : else
1194 : {
1195 0 : nAdd = +1;
1196 0 : nRest = nZwi - nRest;
1197 : }
1198 0 : nDiff /= nZwi;
1199 0 : long nSum = nDiff;
1200 0 : for( sal_Int32 i = 0; i < nZwi; )
1201 : {
1202 0 : pKernArray[ i ] += nSum;
1203 0 : if( ++i == nRest )
1204 0 : nDiff += nAdd;
1205 0 : nSum += nDiff;
1206 : }
1207 : }
1208 :
1209 : // Modify Array for special justifications
1210 :
1211 0 : long nSpaceAdd = rInf.GetSpace() / SPACING_PRECISION_FACTOR;
1212 0 : bool bSpecialJust = false;
1213 :
1214 0 : if ( rInf.GetFont() && rInf.GetLen() )
1215 : {
1216 0 : const SwScriptInfo* pSI = rInf.GetScriptInfo();
1217 0 : const sal_uInt8 nActual = rInf.GetFont()->GetActual();
1218 :
1219 : // Kana Compression
1220 0 : if ( SW_CJK == nActual && rInf.GetKanaComp() &&
1221 0 : pSI && pSI->CountCompChg() &&
1222 0 : lcl_IsMonoSpaceFont( rInf.GetOut() ) )
1223 : {
1224 : pSI->Compress( pKernArray, rInf.GetIdx(), rInf.GetLen(),
1225 0 : rInf.GetKanaComp(),
1226 0 : (sal_uInt16)aFont.GetSize().Height(), &aTextOriginPos );
1227 0 : bSpecialJust = true;
1228 : }
1229 :
1230 : // Asian Justification
1231 0 : if ( SW_CJK == nActual && nSpaceAdd )
1232 : {
1233 0 : LanguageType aLang = rInf.GetFont()->GetLanguage( SW_CJK );
1234 :
1235 0 : if (!MsLangId::isKorean(aLang))
1236 : {
1237 0 : long nSpaceSum = nSpaceAdd;
1238 0 : for ( sal_Int32 nI = 0; nI < rInf.GetLen(); ++nI )
1239 : {
1240 0 : pKernArray[ nI ] += nSpaceSum;
1241 0 : nSpaceSum += nSpaceAdd;
1242 : }
1243 :
1244 0 : bSpecialJust = true;
1245 0 : nSpaceAdd = 0;
1246 : }
1247 : }
1248 :
1249 : // Kashida Justification
1250 0 : if ( SW_CTL == nActual && nSpaceAdd )
1251 : {
1252 0 : if ( SwScriptInfo::IsArabicText( rInf.GetText(), rInf.GetIdx(), rInf.GetLen() ) )
1253 : {
1254 0 : if ( pSI && pSI->CountKashida() &&
1255 : pSI->KashidaJustify( pKernArray, 0, rInf.GetIdx(),
1256 0 : rInf.GetLen(), nSpaceAdd ) != -1 )
1257 : {
1258 0 : bSpecialJust = true;
1259 0 : nSpaceAdd = 0;
1260 : }
1261 : }
1262 : }
1263 :
1264 : // Thai Justification
1265 0 : if ( SW_CTL == nActual && nSpaceAdd )
1266 : {
1267 0 : LanguageType aLang = rInf.GetFont()->GetLanguage( SW_CTL );
1268 :
1269 0 : if ( LANGUAGE_THAI == aLang )
1270 : {
1271 : // Use rInf.GetSpace() because it has more precision than
1272 : // nSpaceAdd:
1273 0 : SwScriptInfo::ThaiJustify( rInf.GetText(), pKernArray, 0,
1274 : rInf.GetIdx(), rInf.GetLen(),
1275 : rInf.GetNumberOfBlanks(),
1276 0 : rInf.GetSpace() );
1277 :
1278 : // adding space to blanks is already done
1279 0 : bSpecialJust = true;
1280 0 : nSpaceAdd = 0;
1281 : }
1282 : }
1283 : }
1284 :
1285 0 : long nKernSum = rInf.GetKern();
1286 :
1287 0 : if ( bStretch || bPaintBlank || rInf.GetKern() || bSpecialJust )
1288 : {
1289 0 : for( sal_Int32 i = 0; i < rInf.GetLen(); i++,
1290 : nKernSum += rInf.GetKern() )
1291 : {
1292 0 : if ( CH_BLANK == rInf.GetText()[ rInf.GetIdx()+i ] )
1293 0 : nKernSum += nSpaceAdd;
1294 0 : pKernArray[i] += nKernSum;
1295 : }
1296 :
1297 : // In case of underlined/strike-through justified text
1298 : // a blank at the end requires special handling:
1299 0 : if( bPaintBlank && rInf.GetLen() && ( CH_BLANK ==
1300 0 : rInf.GetText()[ rInf.GetIdx()+rInf.GetLen()-1 ] ) )
1301 : {
1302 : // If it is a single underlined space, output 2 spaces:
1303 0 : if( 1 == rInf.GetLen() )
1304 : {
1305 0 : pKernArray[0] = rInf.GetWidth() + nSpaceAdd;
1306 :
1307 0 : rInf.GetOut().DrawTextArray( aTextOriginPos, rInf.GetText(),
1308 0 : pKernArray, rInf.GetIdx(), 1 );
1309 : }
1310 : else
1311 : {
1312 0 : pKernArray[ rInf.GetLen() - 2 ] += nSpaceAdd;
1313 0 : rInf.GetOut().DrawTextArray( aTextOriginPos, rInf.GetText(),
1314 0 : pKernArray, rInf.GetIdx(), rInf.GetLen() );
1315 : }
1316 : }
1317 : else
1318 0 : rInf.GetOut().DrawTextArray( aTextOriginPos, rInf.GetText(),
1319 0 : pKernArray, rInf.GetIdx(), rInf.GetLen() );
1320 : }
1321 : else
1322 : {
1323 0 : Point aTmpPos( aTextOriginPos );
1324 0 : sal_Int32 j = 0;
1325 : sal_Int32 i;
1326 0 : for( i = 0; i < rInf.GetLen(); i++ )
1327 : {
1328 0 : if( CH_BLANK == rInf.GetText()[ rInf.GetIdx()+i ] )
1329 : {
1330 0 : nKernSum += nSpaceAdd;
1331 0 : if( j < i )
1332 0 : rInf.GetOut().DrawText( aTmpPos, rInf.GetText(),
1333 0 : rInf.GetIdx() + j, i - j );
1334 0 : j = i + 1;
1335 0 : SwTwips nAdd = pKernArray[ i ] + nKernSum;
1336 0 : if ( ( TEXT_LAYOUT_BIDI_STRONG | TEXT_LAYOUT_BIDI_RTL ) == nMode )
1337 0 : nAdd *= -1;
1338 0 : aTmpPos.X() = aTextOriginPos.X() + nAdd;
1339 : }
1340 : }
1341 0 : if( j < i )
1342 0 : rInf.GetOut().DrawText( aTmpPos, rInf.GetText(),
1343 0 : rInf.GetIdx() + j, i - j );
1344 : }
1345 0 : delete[] pKernArray;
1346 : }
1347 43 : else if( bStretch )
1348 : {
1349 0 : long nTmpWidth = rInf.GetWidth();
1350 0 : if( rInf.GetKern() && rInf.GetLen() && nTmpWidth > rInf.GetKern() )
1351 0 : nTmpWidth -= rInf.GetKern();
1352 0 : rInf.GetOut().DrawStretchText( aTextOriginPos, nTmpWidth,
1353 0 : rInf.GetText(), rInf.GetIdx(), rInf.GetLen() );
1354 : }
1355 43 : else if( rInf.GetKern() )
1356 : {
1357 0 : const long nTmpWidth = GetTextSize( rInf ).Width();
1358 :
1359 0 : const Color aSaveColor( pTmpFont->GetColor() );
1360 0 : const bool bColorChanged = rInf.ApplyAutoColor( pTmpFont );
1361 :
1362 0 : if( bColorChanged )
1363 : {
1364 0 : if( !pTmpFont->IsSameInstance( rInf.GetOut().GetFont() ) )
1365 0 : rInf.GetOut().SetFont( *pTmpFont );
1366 0 : pTmpFont->SetColor( aSaveColor );
1367 : }
1368 :
1369 0 : rInf.GetOut().DrawStretchText( aTextOriginPos, nTmpWidth,
1370 0 : rInf.GetText(), rInf.GetIdx(), rInf.GetLen() );
1371 : }
1372 : else
1373 43 : rInf.GetOut().DrawText( aTextOriginPos, rInf.GetText(),
1374 86 : rInf.GetIdx(), rInf.GetLen() );
1375 : }
1376 :
1377 : // PAINTING WITH FORMATTING DEVICE/SCREEN ADJUSTMENT
1378 :
1379 : else
1380 : {
1381 20922 : const OUString* pStr = &rInf.GetText();
1382 :
1383 : #if !defined(MACOSX) && !defined(IOS)
1384 20922 : OUString aStr;
1385 41844 : OUString aBulletOverlay;
1386 : #endif
1387 20922 : bool bBullet = rInf.GetBullet();
1388 20922 : if( bSymbol )
1389 69 : bBullet = false;
1390 20922 : long* pKernArray = new long[ rInf.GetLen() ];
1391 20922 : CreateScrFont( *rInf.GetShell(), rInf.GetOut() );
1392 : long nScrPos;
1393 :
1394 : // get screen array
1395 20922 : long* pScrArray = new long[ rInf.GetLen() ];
1396 20922 : rInf.GetOut().GetTextArray( rInf.GetText(), pScrArray,
1397 41844 : rInf.GetIdx(), rInf.GetLen() );
1398 :
1399 : // OLE: no printer available
1400 : // OSL_ENSURE( pPrinter, "DrawText needs pPrinter" )
1401 20922 : if ( pPrinter )
1402 : {
1403 : // pTmpFont has already been set as current font for rInf.GetOut()
1404 20922 : if ( pPrinter.get() != rInf.GetpOut() || pTmpFont != pPrtFont )
1405 : {
1406 20922 : if( !pPrtFont->IsSameInstance( pPrinter->GetFont() ) )
1407 16431 : pPrinter->SetFont( *pPrtFont );
1408 : }
1409 20922 : pPrinter->GetTextArray( rInf.GetText(), pKernArray, rInf.GetIdx(),
1410 41844 : rInf.GetLen() );
1411 : }
1412 : else
1413 : {
1414 0 : rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray,
1415 0 : rInf.GetIdx(), rInf.GetLen() );
1416 : }
1417 :
1418 : // Modify Printer and ScreenArrays for special justifications
1419 :
1420 20922 : long nSpaceAdd = rInf.GetSpace() / SPACING_PRECISION_FACTOR;
1421 20922 : bool bNoHalfSpace = false;
1422 :
1423 20922 : if ( rInf.GetFont() && rInf.GetLen() )
1424 : {
1425 20922 : const sal_uInt8 nActual = rInf.GetFont()->GetActual();
1426 20922 : const SwScriptInfo* pSI = rInf.GetScriptInfo();
1427 :
1428 : // Kana Compression
1429 20979 : if ( SW_CJK == nActual && rInf.GetKanaComp() &&
1430 20922 : pSI && pSI->CountCompChg() &&
1431 0 : lcl_IsMonoSpaceFont( rInf.GetOut() ) )
1432 : {
1433 0 : Point aTmpPos( aTextOriginPos );
1434 : pSI->Compress( pScrArray, rInf.GetIdx(), rInf.GetLen(),
1435 0 : rInf.GetKanaComp(),
1436 0 : (sal_uInt16)aFont.GetSize().Height(), &aTmpPos );
1437 : pSI->Compress( pKernArray, rInf.GetIdx(), rInf.GetLen(),
1438 0 : rInf.GetKanaComp(),
1439 0 : (sal_uInt16)aFont.GetSize().Height(), &aTextOriginPos );
1440 : }
1441 :
1442 : // Asian Justification
1443 20922 : if ( SW_CJK == nActual && nSpaceAdd )
1444 : {
1445 0 : LanguageType aLang = rInf.GetFont()->GetLanguage( SW_CJK );
1446 :
1447 0 : if (!MsLangId::isKorean(aLang))
1448 : {
1449 0 : long nSpaceSum = nSpaceAdd;
1450 0 : for ( sal_Int32 nI = 0; nI < rInf.GetLen(); ++nI )
1451 : {
1452 0 : pKernArray[ nI ] += nSpaceSum;
1453 0 : pScrArray[ nI ] += nSpaceSum;
1454 0 : nSpaceSum += nSpaceAdd;
1455 : }
1456 :
1457 0 : nSpaceAdd = 0;
1458 : }
1459 : }
1460 :
1461 : // Kashida Justification
1462 20922 : if ( SW_CTL == nActual && nSpaceAdd )
1463 : {
1464 0 : if ( SwScriptInfo::IsArabicText( rInf.GetText(), rInf.GetIdx(), rInf.GetLen() ) )
1465 : {
1466 0 : if ( pSI && pSI->CountKashida() &&
1467 : pSI->KashidaJustify( pKernArray, pScrArray, rInf.GetIdx(),
1468 0 : rInf.GetLen(), nSpaceAdd ) != -1 )
1469 0 : nSpaceAdd = 0;
1470 : else
1471 0 : bNoHalfSpace = true;
1472 : }
1473 : }
1474 :
1475 : // Thai Justification
1476 20922 : if ( SW_CTL == nActual && nSpaceAdd )
1477 : {
1478 0 : LanguageType aLang = rInf.GetFont()->GetLanguage( SW_CTL );
1479 :
1480 0 : if ( LANGUAGE_THAI == aLang )
1481 : {
1482 0 : SwScriptInfo::ThaiJustify( rInf.GetText(), pKernArray,
1483 : pScrArray, rInf.GetIdx(),
1484 : rInf.GetLen(),
1485 : rInf.GetNumberOfBlanks(),
1486 0 : rInf.GetSpace() );
1487 :
1488 : // adding space to blanks is already done
1489 0 : nSpaceAdd = 0;
1490 : }
1491 : }
1492 : }
1493 :
1494 20922 : nScrPos = pScrArray[ 0 ];
1495 :
1496 : #if !defined(MACOSX) && !defined(IOS)
1497 20922 : if( bBullet )
1498 : {
1499 : // !!! HACK !!!
1500 : // The Arabic layout engine requires some context of the string
1501 : // which should be painted.
1502 0 : sal_Int32 nCopyStart = rInf.GetIdx();
1503 0 : if ( nCopyStart )
1504 0 : --nCopyStart;
1505 :
1506 0 : sal_Int32 nCopyLen = rInf.GetLen();
1507 0 : if ( nCopyStart + nCopyLen < rInf.GetText().getLength() )
1508 0 : ++nCopyLen;
1509 :
1510 0 : aStr = rInf.GetText().copy( nCopyStart, nCopyLen );
1511 0 : pStr = &aStr;
1512 :
1513 0 : aBulletOverlay = rInf.GetText().copy( nCopyStart, nCopyLen );
1514 :
1515 0 : for( sal_Int32 i = 0; i < aBulletOverlay.getLength(); ++i )
1516 0 : if( CH_BLANK == aBulletOverlay[ i ] )
1517 : {
1518 : /* fdo#72488 Hack: try to see if the space is zero width
1519 : * and don't bother with inserting a bullet in this case.
1520 : */
1521 0 : if ((i + nCopyStart + 1 >= rInf.GetLen()) ||
1522 0 : pKernArray[i + nCopyStart] != pKernArray[ i + nCopyStart + 1])
1523 : {
1524 0 : aBulletOverlay = aBulletOverlay.replaceAt(i, 1, OUString(CH_BULLET));
1525 : }
1526 : else
1527 : {
1528 0 : aBulletOverlay = aBulletOverlay.replaceAt(i, 1, OUString(CH_BLANK));
1529 : }
1530 : }
1531 : else
1532 : {
1533 0 : aBulletOverlay = aBulletOverlay.replaceAt(i, 1, OUString(CH_BLANK));
1534 : }
1535 : }
1536 : #endif
1537 20922 : sal_Int32 nCnt = rInf.GetText().getLength();
1538 20922 : if ( nCnt < rInf.GetIdx() )
1539 0 : nCnt = 0;
1540 : else
1541 20922 : nCnt = nCnt - rInf.GetIdx();
1542 20922 : nCnt = std::min<sal_Int32>( nCnt, rInf.GetLen() );
1543 20922 : long nKernSum = rInf.GetKern();
1544 20922 : sal_Unicode cChPrev = rInf.GetText()[ rInf.GetIdx() ];
1545 :
1546 : // In case of a single underlined space in justified text,
1547 : // have to output 2 spaces:
1548 20922 : if ( ( nCnt == 1 ) && rInf.GetSpace() && ( cChPrev == CH_BLANK ) )
1549 : {
1550 12 : pKernArray[0] = rInf.GetWidth() +
1551 12 : rInf.GetKern() +
1552 12 : ( rInf.GetSpace() / SPACING_PRECISION_FACTOR );
1553 :
1554 6 : if ( bSwitchL2R )
1555 0 : rInf.GetFrm()->SwitchLTRtoRTL( aTextOriginPos );
1556 :
1557 6 : if ( bSwitchH2V )
1558 0 : rInf.GetFrm()->SwitchHorizontalToVertical( aTextOriginPos );
1559 :
1560 : #if defined(MACOSX) || defined(IOS)
1561 : rInf.GetOut().DrawTextArray( aTextOriginPos, rInf.GetText(),
1562 : pKernArray, rInf.GetIdx(), 1, bBullet ? SalLayoutFlags::DrawBullet : SalLayoutFlags::NONE );
1563 : #else
1564 6 : rInf.GetOut().DrawTextArray( aTextOriginPos, rInf.GetText(),
1565 12 : pKernArray, rInf.GetIdx(), 1 );
1566 6 : if( bBullet )
1567 0 : rInf.GetOut().DrawTextArray( aTextOriginPos, *pStr, pKernArray,
1568 0 : rInf.GetIdx() ? 1 : 0, 1 );
1569 : #endif
1570 : }
1571 : else
1572 : {
1573 : sal_Unicode nCh;
1574 :
1575 : // In case of Pair Kerning the printer influence on the positioning
1576 : // grows
1577 20916 : const int nMul = pPrtFont->GetKerning() != FontKerning::NONE ? 1 : 3;
1578 20916 : const int nDiv = nMul+1;
1579 :
1580 : // nSpaceSum contains the sum of the intermediate space distributed
1581 : // among Spaces by the Justification.
1582 : // The Spaces themselves will be positioned in the middle of the
1583 : // intermediate space, hence the nSpace/2.
1584 : // In case of word-by-word underlining they have to be positioned
1585 : // at the beginning of the intermediate space, so that the space
1586 : // is not underlined.
1587 : // A Space at the beginning or end of the text must be positioned
1588 : // before (resp. after) the whole intermediate space, otherwise
1589 : // the underline/strike-through would have gaps.
1590 20916 : long nSpaceSum = 0;
1591 : // in word line mode and for Arabic, we disable the half space trick:
1592 20916 : const long nHalfSpace = pPrtFont->IsWordLineMode() || bNoHalfSpace ? 0 : nSpaceAdd / 2;
1593 20916 : const long nOtherHalf = nSpaceAdd - nHalfSpace;
1594 20916 : if ( nSpaceAdd && ( cChPrev == CH_BLANK ) )
1595 99 : nSpaceSum = nHalfSpace;
1596 891451 : for( sal_Int32 i=1; i<nCnt; ++i, nKernSum += rInf.GetKern() )
1597 : {
1598 870535 : nCh = rInf.GetText()[ rInf.GetIdx() + i ];
1599 :
1600 : OSL_ENSURE( pScrArray, "Where is the screen array?" );
1601 : long nScr;
1602 870535 : nScr = pScrArray[ i ] - pScrArray[ i - 1 ];
1603 :
1604 : // If there is an (ex-)Space before us, position optimally,
1605 : // i.e., our right margin to the 100% printer position;
1606 : // if we _are_ an ex-Space, position us left-aligned to the
1607 : // printer position.
1608 870535 : if ( nCh == CH_BLANK )
1609 : {
1610 97173 : nScrPos = pKernArray[i-1] + nScr;
1611 :
1612 97173 : if ( cChPrev == CH_BLANK )
1613 682 : nSpaceSum += nOtherHalf;
1614 97173 : if ( i + 1 == nCnt )
1615 7270 : nSpaceSum += nSpaceAdd;
1616 : else
1617 89903 : nSpaceSum += nHalfSpace;
1618 : }
1619 : else
1620 : {
1621 773362 : if ( cChPrev == CH_BLANK )
1622 : {
1623 90421 : nScrPos = pKernArray[i-1] + nScr;
1624 : // no Pixel is lost:
1625 90421 : nSpaceSum += nOtherHalf;
1626 : }
1627 682941 : else if ( cChPrev == '-' )
1628 3175 : nScrPos = pKernArray[i-1] + nScr;
1629 : else
1630 : {
1631 679766 : nScrPos += nScr;
1632 679766 : nScrPos = ( nMul * nScrPos + pKernArray[i] ) / nDiv;
1633 : }
1634 : }
1635 870535 : cChPrev = nCh;
1636 870535 : pKernArray[i-1] = nScrPos - nScr + nKernSum + nSpaceSum;
1637 : // In word line mode and for Arabic, we disabled the half space trick. If a portion
1638 : // ends with a blank, the full nSpaceAdd value has been added to the character in
1639 : // front of the blank. This leads to painting artifacts, therefore we remove the
1640 : // nSpaceAdd value again:
1641 870535 : if ( (bNoHalfSpace || pPrtFont->IsWordLineMode()) && i+1 == nCnt && nCh == CH_BLANK )
1642 0 : pKernArray[i-1] = pKernArray[i-1] - nSpaceAdd;
1643 : }
1644 :
1645 : // the layout engine requires the total width of the output
1646 20916 : pKernArray[ rInf.GetLen() - 1 ] += nKernSum + nSpaceSum;
1647 :
1648 20916 : if( rInf.GetGreyWave() )
1649 : {
1650 0 : if( rInf.GetLen() )
1651 : {
1652 0 : long nHght = rInf.GetOut().LogicToPixel(
1653 0 : pPrtFont->GetSize() ).Height();
1654 0 : if( WRONG_SHOW_MIN < nHght )
1655 : {
1656 0 : if ( rInf.GetOut().GetConnectMetaFile() )
1657 0 : rInf.GetOut().Push();
1658 :
1659 0 : Color aCol( rInf.GetOut().GetLineColor() );
1660 0 : bool bColSave = aCol != *pWaveCol;
1661 0 : if ( bColSave )
1662 0 : rInf.GetOut().SetLineColor( *pWaveCol );
1663 :
1664 0 : Point aEnd;
1665 0 : long nKernVal = pKernArray[ rInf.GetLen() - 1 ];
1666 :
1667 : const sal_uInt16 nDir = bBidiPor ?
1668 : 1800 :
1669 : UnMapDirection(
1670 0 : GetFont().GetOrientation(),
1671 0 : bSwitchH2V );
1672 :
1673 0 : switch ( nDir )
1674 : {
1675 : case 0 :
1676 0 : aEnd.X() = rInf.GetPos().X() + nKernVal;
1677 0 : aEnd.Y() = rInf.GetPos().Y();
1678 0 : break;
1679 : case 900 :
1680 0 : aEnd.X() = rInf.GetPos().X();
1681 0 : aEnd.Y() = rInf.GetPos().Y() - nKernVal;
1682 0 : break;
1683 : case 1800 :
1684 0 : aEnd.X() = rInf.GetPos().X() - nKernVal;
1685 0 : aEnd.Y() = rInf.GetPos().Y();
1686 0 : break;
1687 : case 2700 :
1688 0 : aEnd.X() = rInf.GetPos().X();
1689 0 : aEnd.Y() = rInf.GetPos().Y() + nKernVal;
1690 0 : break;
1691 : }
1692 :
1693 0 : Point aCurrPos( rInf.GetPos() );
1694 :
1695 0 : if ( bSwitchL2R )
1696 : {
1697 0 : rInf.GetFrm()->SwitchLTRtoRTL( aCurrPos );
1698 0 : rInf.GetFrm()->SwitchLTRtoRTL( aEnd );
1699 : }
1700 :
1701 0 : if ( bSwitchH2V )
1702 : {
1703 0 : rInf.GetFrm()->SwitchHorizontalToVertical( aCurrPos );
1704 0 : rInf.GetFrm()->SwitchHorizontalToVertical( aEnd );
1705 : }
1706 0 : rInf.GetOut().DrawWaveLine( aCurrPos, aEnd );
1707 :
1708 0 : if ( bColSave )
1709 0 : rInf.GetOut().SetLineColor( aCol );
1710 :
1711 0 : if ( rInf.GetOut().GetConnectMetaFile() )
1712 0 : rInf.GetOut().Pop();
1713 : }
1714 : }
1715 : }
1716 20916 : else if( !bSymbol && rInf.GetLen() )
1717 : {
1718 : // anything to do?
1719 20847 : if (rInf.GetWrong() || rInf.GetGrammarCheck() || rInf.GetSmartTags())
1720 : {
1721 6076 : CalcLinePosData aCalcLinePosData(rInf, GetFont(),
1722 : nCnt, bSwitchH2V, bSwitchL2R,
1723 12152 : nHalfSpace, pKernArray, bBidiPor);
1724 :
1725 6076 : SwForbidden aForbidden;
1726 : // draw line for smart tag data
1727 6076 : lcl_DrawLineForWrongListData( aForbidden, rInf, rInf.GetSmartTags(), aCalcLinePosData, Size() );
1728 : // draw wave line for spell check errors
1729 : // draw them BEFORE the grammar check lines to 'override' the latter in case of conflict.
1730 : // reason: some grammar errors can only be found if spelling errors are fixed,
1731 : // therefore we don't want the user to miss a spelling error.
1732 6076 : lcl_DrawLineForWrongListData( aForbidden, rInf, rInf.GetWrong(), aCalcLinePosData, pPrtFont->GetSize() );
1733 : // draw wave line for grammar check errors
1734 6076 : lcl_DrawLineForWrongListData( aForbidden, rInf, rInf.GetGrammarCheck(), aCalcLinePosData, pPrtFont->GetSize() );
1735 : }
1736 : }
1737 :
1738 20916 : sal_Int32 nOffs = 0;
1739 20916 : sal_Int32 nLen = rInf.GetLen();
1740 :
1741 20916 : if( nOffs < nLen )
1742 : {
1743 :
1744 20916 : if ( bSwitchL2R )
1745 9 : rInf.GetFrm()->SwitchLTRtoRTL( aTextOriginPos );
1746 :
1747 20916 : if ( bSwitchH2V )
1748 0 : rInf.GetFrm()->SwitchHorizontalToVertical( aTextOriginPos );
1749 :
1750 : #if defined(MACOSX) || defined(IOS)
1751 : rInf.GetOut().DrawTextArray( aTextOriginPos, *pStr, pKernArray + nOffs,
1752 : rInf.GetIdx() + nOffs , nLen - nOffs, bBullet ? SalLayoutFlags::DrawBullet : SalLayoutFlags::NONE );
1753 : #else
1754 : // If we paint bullets instead of spaces, we use a copy of
1755 : // the paragraph string. For the layout engine, the copy
1756 : // of the string has to be an environment of the range which
1757 : // is painted
1758 : sal_Int32 nTmpIdx = bBullet ?
1759 0 : ( rInf.GetIdx() ? 1 : 0 ) :
1760 20916 : rInf.GetIdx();
1761 20916 : rInf.GetOut().DrawTextArray( aTextOriginPos, *pStr, pKernArray + nOffs,
1762 41832 : nTmpIdx + nOffs , nLen - nOffs );
1763 20916 : if (bBullet)
1764 : {
1765 0 : rInf.GetOut().Push();
1766 0 : Color aPreviousColor = pTmpFont->GetColor();
1767 :
1768 0 : FontUnderline aPreviousUnderline = pTmpFont->GetUnderline();
1769 0 : FontUnderline aPreviousOverline = pTmpFont->GetOverline();
1770 0 : FontStrikeout aPreviousStrikeout = pTmpFont->GetStrikeout();
1771 :
1772 0 : pTmpFont->SetColor( Color(NON_PRINTING_CHARACTER_COLOR) );
1773 0 : pTmpFont->SetUnderline(UNDERLINE_NONE);
1774 0 : pTmpFont->SetOverline(UNDERLINE_NONE);
1775 0 : pTmpFont->SetStrikeout(STRIKEOUT_NONE);
1776 0 : rInf.GetOut().SetFont( *pTmpFont );
1777 0 : rInf.GetOut().DrawTextArray( aTextOriginPos, aBulletOverlay, pKernArray + nOffs,
1778 0 : nTmpIdx + nOffs , nLen - nOffs );
1779 0 : pTmpFont->SetColor( aPreviousColor );
1780 :
1781 0 : pTmpFont->SetUnderline(aPreviousUnderline);
1782 0 : pTmpFont->SetOverline(aPreviousOverline);
1783 0 : pTmpFont->SetStrikeout(aPreviousStrikeout);
1784 0 : rInf.GetOut().Pop();
1785 : }
1786 : #endif
1787 : }
1788 : }
1789 20922 : delete[] pScrArray;
1790 41844 : delete[] pKernArray;
1791 : }
1792 : }
1793 :
1794 105068 : Size SwFntObj::GetTextSize( SwDrawTextInfo& rInf )
1795 : {
1796 105068 : Size aTextSize;
1797 105068 : const sal_Int32 nLn = ( COMPLETE_STRING != rInf.GetLen() ) ? rInf.GetLen() :
1798 105068 : rInf.GetText().getLength();
1799 :
1800 : // be sure to have the correct layout mode at the printer
1801 105068 : if ( pPrinter )
1802 : {
1803 104282 : pPrinter->SetLayoutMode( rInf.GetOut().GetLayoutMode() );
1804 104282 : pPrinter->SetDigitLanguage( rInf.GetOut().GetDigitLanguage() );
1805 : }
1806 :
1807 194826 : if ( rInf.GetFrm() && nLn && rInf.SnapToGrid() && rInf.GetFont() &&
1808 89758 : SW_CJK == rInf.GetFont()->GetActual() )
1809 : {
1810 2282 : SwTextGridItem const*const pGrid(GetGridItem(rInf.GetFrm()->FindPageFrm()));
1811 2282 : if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && pGrid->IsSnapToChars() )
1812 : {
1813 0 : const SwDoc* pDoc = rInf.GetShell()->GetDoc();
1814 0 : const sal_uInt16 nGridWidth = GetGridWidth(*pGrid, *pDoc);
1815 :
1816 : OutputDevice* pOutDev;
1817 :
1818 0 : if ( pPrinter )
1819 : {
1820 0 : if( !pPrtFont->IsSameInstance( pPrinter->GetFont() ) )
1821 0 : pPrinter->SetFont(*pPrtFont);
1822 0 : pOutDev = pPrinter;
1823 : }
1824 : else
1825 0 : pOutDev = rInf.GetpOut();
1826 :
1827 0 : aTextSize.Width() =
1828 0 : pOutDev->GetTextWidth( rInf.GetText(), rInf.GetIdx(), nLn );
1829 :
1830 : OSL_ENSURE( !rInf.GetShell() ||
1831 : ( USHRT_MAX != GetGuessedLeading() && USHRT_MAX != GetExtLeading() ),
1832 : "Leading values should be already calculated" );
1833 0 : aTextSize.Height() = pOutDev->GetTextHeight() +
1834 0 : GetFontLeading( rInf.GetShell(), rInf.GetOut() );
1835 :
1836 0 : long nAvgWidthPerChar = aTextSize.Width() / nLn;
1837 :
1838 : const sal_uLong i = nAvgWidthPerChar ?
1839 0 : ( nAvgWidthPerChar - 1 ) / nGridWidth + 1:
1840 0 : 1;
1841 :
1842 0 : aTextSize.Width() = i * nGridWidth * nLn;
1843 0 : rInf.SetKanaDiff( 0 );
1844 0 : return aTextSize;
1845 : }
1846 : }
1847 :
1848 : //for textgrid refactor
1849 194826 : if ( rInf.GetFrm() && nLn && rInf.SnapToGrid() && rInf.GetFont() &&
1850 89758 : SW_CJK == rInf.GetFont()->GetActual() )
1851 : {
1852 2282 : SwTextGridItem const*const pGrid(GetGridItem(rInf.GetFrm()->FindPageFrm()));
1853 2282 : if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && !pGrid->IsSnapToChars() )
1854 : {
1855 0 : const long nGridWidthAdd = EvalGridWidthAdd( pGrid, rInf );
1856 : OutputDevice* pOutDev;
1857 0 : if ( pPrinter )
1858 : {
1859 0 : if( !pPrtFont->IsSameInstance( pPrinter->GetFont() ) )
1860 0 : pPrinter->SetFont(*pPrtFont);
1861 0 : pOutDev = pPrinter;
1862 : }
1863 : else
1864 0 : pOutDev = rInf.GetpOut();
1865 0 : aTextSize.Width() = pOutDev->GetTextWidth( rInf.GetText(), rInf.GetIdx(), nLn );
1866 0 : aTextSize.Height() = pOutDev->GetTextHeight() +
1867 0 : GetFontLeading( rInf.GetShell(), rInf.GetOut() );
1868 0 : aTextSize.Width() += nLn * nGridWidthAdd;
1869 : //if ( rInf.GetKern() && nLn )
1870 : // aTextSize.Width() += ( nLn ) * long( rInf.GetKern() );
1871 :
1872 0 : rInf.SetKanaDiff( 0 );
1873 0 : return aTextSize;
1874 : }
1875 : }
1876 :
1877 105068 : const bool bCompress = rInf.GetKanaComp() && nLn &&
1878 0 : rInf.GetFont() &&
1879 0 : SW_CJK == rInf.GetFont()->GetActual() &&
1880 0 : rInf.GetScriptInfo() &&
1881 105068 : rInf.GetScriptInfo()->CountCompChg() &&
1882 105068 : lcl_IsMonoSpaceFont( rInf.GetOut() );
1883 :
1884 : OSL_ENSURE( !bCompress || ( rInf.GetScriptInfo() && rInf.GetScriptInfo()->
1885 : CountCompChg()), "Compression without info" );
1886 :
1887 : // This is the part used e.g., for cursor travelling
1888 : // See condition for DrawText or DrawTextArray (bDirectPrint)
1889 105068 : if ( pPrinter && pPrinter.get() != rInf.GetpOut() )
1890 : {
1891 1470 : if( !pPrtFont->IsSameInstance( pPrinter->GetFont() ) )
1892 0 : pPrinter->SetFont(*pPrtFont);
1893 2940 : aTextSize.Width() = pPrinter->GetTextWidth( rInf.GetText(),
1894 2940 : rInf.GetIdx(), nLn );
1895 1470 : aTextSize.Height() = pPrinter->GetTextHeight();
1896 1470 : long* pKernArray = new long[nLn];
1897 1470 : CreateScrFont( *rInf.GetShell(), rInf.GetOut() );
1898 1470 : if( !GetScrFont()->IsSameInstance( rInf.GetOut().GetFont() ) )
1899 0 : rInf.GetOut().SetFont( *pScrFont );
1900 : long nScrPos;
1901 :
1902 1470 : pPrinter->GetTextArray( rInf.GetText(), pKernArray, rInf.GetIdx(),nLn );
1903 1470 : if( bCompress )
1904 : rInf.SetKanaDiff( rInf.GetScriptInfo()->Compress( pKernArray,
1905 0 : rInf.GetIdx(), nLn, rInf.GetKanaComp(),
1906 0 : (sal_uInt16)aFont.GetSize().Height() ) );
1907 : else
1908 1470 : rInf.SetKanaDiff( 0 );
1909 :
1910 1470 : if ( rInf.GetKanaDiff() )
1911 0 : nScrPos = pKernArray[ nLn - 1 ];
1912 : else
1913 : {
1914 1470 : long* pScrArray = new long[ rInf.GetLen() ];
1915 1470 : rInf.GetOut().GetTextArray( rInf.GetText(), pScrArray,
1916 2940 : rInf.GetIdx(), rInf.GetLen() );
1917 1470 : nScrPos = pScrArray[ 0 ];
1918 1470 : sal_Int32 nCnt = rInf.GetText().getLength();
1919 1470 : if ( nCnt < rInf.GetIdx() )
1920 0 : nCnt=0;
1921 : else
1922 1470 : nCnt = nCnt - rInf.GetIdx();
1923 1470 : nCnt = std::min<sal_Int32>(nCnt, nLn);
1924 1470 : sal_Unicode nChPrev = rInf.GetText()[ rInf.GetIdx() ];
1925 :
1926 : sal_Unicode nCh;
1927 :
1928 : // In case of Pair Kerning the printer influence on the positioning
1929 : // grows
1930 1470 : const int nMul = pPrtFont->GetKerning() != FontKerning::NONE ? 1 : 3;
1931 1470 : const int nDiv = nMul+1;
1932 12673 : for( sal_Int32 i = 1; i<nCnt; i++ )
1933 : {
1934 11203 : nCh = rInf.GetText()[ rInf.GetIdx() + i ];
1935 : long nScr;
1936 11203 : nScr = pScrArray[ i ] - pScrArray[ i - 1 ];
1937 11203 : if ( nCh == CH_BLANK )
1938 1945 : nScrPos = pKernArray[i-1]+nScr;
1939 : else
1940 : {
1941 9258 : if ( nChPrev == CH_BLANK || nChPrev == '-' )
1942 1470 : nScrPos = pKernArray[i-1]+nScr;
1943 : else
1944 : {
1945 7788 : nScrPos += nScr;
1946 7788 : nScrPos = ( nMul * nScrPos + pKernArray[i] ) / nDiv;
1947 : }
1948 : }
1949 11203 : nChPrev = nCh;
1950 11203 : pKernArray[i-1] = nScrPos - nScr;
1951 : }
1952 1470 : delete[] pScrArray;
1953 : }
1954 :
1955 1470 : delete[] pKernArray;
1956 1470 : aTextSize.Width() = nScrPos;
1957 : }
1958 : else
1959 : {
1960 103598 : if( !pPrtFont->IsSameInstance( rInf.GetOut().GetFont() ) )
1961 0 : rInf.GetOut().SetFont( *pPrtFont );
1962 103598 : if( bCompress )
1963 : {
1964 0 : long* pKernArray = new long[nLn];
1965 0 : rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray,
1966 0 : rInf.GetIdx(), nLn );
1967 : rInf.SetKanaDiff( rInf.GetScriptInfo()->Compress( pKernArray,
1968 0 : rInf.GetIdx(), nLn, rInf.GetKanaComp(),
1969 0 : (sal_uInt16) aFont.GetSize().Height() ) );
1970 0 : aTextSize.Width() = pKernArray[ nLn - 1 ];
1971 0 : delete[] pKernArray;
1972 : }
1973 : else
1974 : {
1975 207196 : aTextSize.Width() = rInf.GetOut().GetTextWidth( rInf.GetText(),
1976 : rInf.GetIdx(), nLn,
1977 207196 : rInf.GetVclCache());
1978 103598 : rInf.SetKanaDiff( 0 );
1979 : }
1980 :
1981 103598 : aTextSize.Height() = rInf.GetOut().GetTextHeight();
1982 : }
1983 :
1984 105068 : if ( rInf.GetKern() && nLn )
1985 333 : aTextSize.Width() += ( nLn - 1 ) * long( rInf.GetKern() );
1986 :
1987 : OSL_ENSURE( !rInf.GetShell() ||
1988 : ( USHRT_MAX != GetGuessedLeading() && USHRT_MAX != GetExtLeading() ),
1989 : "Leading values should be already calculated" );
1990 105068 : aTextSize.Height() += GetFontLeading( rInf.GetShell(), rInf.GetOut() );
1991 105068 : return aTextSize;
1992 : }
1993 :
1994 16 : sal_Int32 SwFntObj::GetCrsrOfst( SwDrawTextInfo &rInf )
1995 : {
1996 16 : long nSpaceAdd = rInf.GetSpace() / SPACING_PRECISION_FACTOR;
1997 16 : const long nSperren = -rInf.GetSperren() / SPACING_PRECISION_FACTOR;
1998 16 : long nKern = rInf.GetKern();
1999 :
2000 16 : if( 0 != nSperren )
2001 0 : nKern -= nSperren;
2002 :
2003 16 : long* pKernArray = new long[ rInf.GetLen() ];
2004 :
2005 : // be sure to have the correct layout mode at the printer
2006 16 : if ( pPrinter )
2007 : {
2008 16 : pPrinter->SetLayoutMode( rInf.GetOut().GetLayoutMode() );
2009 16 : pPrinter->SetDigitLanguage( rInf.GetOut().GetDigitLanguage() );
2010 16 : pPrinter->GetTextArray( rInf.GetText(), pKernArray,
2011 32 : rInf.GetIdx(), rInf.GetLen() );
2012 : }
2013 : else
2014 0 : rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray,
2015 0 : rInf.GetIdx(), rInf.GetLen() );
2016 :
2017 16 : const SwScriptInfo* pSI = rInf.GetScriptInfo();
2018 16 : if ( rInf.GetFont() && rInf.GetLen() )
2019 : {
2020 16 : const sal_uInt8 nActual = rInf.GetFont()->GetActual();
2021 :
2022 : // Kana Compression
2023 16 : if ( SW_CJK == nActual && rInf.GetKanaComp() &&
2024 16 : pSI && pSI->CountCompChg() &&
2025 0 : lcl_IsMonoSpaceFont( rInf.GetOut() ) )
2026 : {
2027 : pSI->Compress( pKernArray, rInf.GetIdx(), rInf.GetLen(),
2028 0 : rInf.GetKanaComp(),
2029 0 : (sal_uInt16) aFont.GetSize().Height() );
2030 : }
2031 :
2032 : // Asian Justification
2033 16 : if ( SW_CJK == rInf.GetFont()->GetActual() )
2034 : {
2035 0 : LanguageType aLang = rInf.GetFont()->GetLanguage( SW_CJK );
2036 :
2037 0 : if (!MsLangId::isKorean(aLang))
2038 : {
2039 0 : long nSpaceSum = nSpaceAdd;
2040 0 : for ( sal_Int32 nI = 0; nI < rInf.GetLen(); ++nI )
2041 : {
2042 0 : pKernArray[ nI ] += nSpaceSum;
2043 0 : nSpaceSum += nSpaceAdd;
2044 : }
2045 :
2046 0 : nSpaceAdd = 0;
2047 : }
2048 :
2049 : }
2050 :
2051 : // Kashida Justification
2052 16 : if ( SW_CTL == nActual && rInf.GetSpace() )
2053 : {
2054 0 : if ( SwScriptInfo::IsArabicText( rInf.GetText(), rInf.GetIdx(), rInf.GetLen() ) )
2055 : {
2056 0 : if ( pSI && pSI->CountKashida() &&
2057 : pSI->KashidaJustify( pKernArray, 0, rInf.GetIdx(), rInf.GetLen(),
2058 0 : nSpaceAdd ) != -1 )
2059 0 : nSpaceAdd = 0;
2060 : }
2061 : }
2062 :
2063 : // Thai Justification
2064 16 : if ( SW_CTL == nActual && nSpaceAdd )
2065 : {
2066 0 : LanguageType aLang = rInf.GetFont()->GetLanguage( SW_CTL );
2067 :
2068 0 : if ( LANGUAGE_THAI == aLang )
2069 : {
2070 0 : SwScriptInfo::ThaiJustify( rInf.GetText(), pKernArray, 0,
2071 : rInf.GetIdx(), rInf.GetLen(),
2072 : rInf.GetNumberOfBlanks(),
2073 0 : rInf.GetSpace() );
2074 :
2075 : // adding space to blanks is already done
2076 0 : nSpaceAdd = 0;
2077 : }
2078 : }
2079 : }
2080 :
2081 16 : long nLeft = 0;
2082 16 : long nRight = 0;
2083 16 : sal_Int32 nCnt = 0;
2084 16 : long nSpaceSum = 0;
2085 16 : long nKernSum = 0;
2086 :
2087 64 : if ( rInf.GetFrm() && rInf.GetLen() && rInf.SnapToGrid() &&
2088 48 : rInf.GetFont() && SW_CJK == rInf.GetFont()->GetActual() )
2089 : {
2090 0 : SwTextGridItem const*const pGrid(GetGridItem(rInf.GetFrm()->FindPageFrm()));
2091 0 : if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && pGrid->IsSnapToChars() )
2092 : {
2093 0 : const SwDoc* pDoc = rInf.GetShell()->GetDoc();
2094 0 : const sal_uInt16 nGridWidth = GetGridWidth(*pGrid, *pDoc);
2095 :
2096 0 : long nAvgWidthPerChar = pKernArray[ rInf.GetLen() - 1 ] / rInf.GetLen();
2097 :
2098 : sal_uLong i = nAvgWidthPerChar ?
2099 0 : ( nAvgWidthPerChar - 1 ) / nGridWidth + 1:
2100 0 : 1;
2101 :
2102 0 : nAvgWidthPerChar = i * nGridWidth;
2103 :
2104 0 : nCnt = rInf.GetOfst() / nAvgWidthPerChar;
2105 0 : if ( 2 * ( rInf.GetOfst() - nCnt * nAvgWidthPerChar ) > nAvgWidthPerChar )
2106 0 : ++nCnt;
2107 :
2108 0 : delete[] pKernArray;
2109 0 : return nCnt;
2110 : }
2111 : }
2112 :
2113 : //for textgrid refactor
2114 64 : if ( rInf.GetFrm() && rInf.GetLen() && rInf.SnapToGrid() &&
2115 48 : rInf.GetFont() && SW_CJK == rInf.GetFont()->GetActual() )
2116 : {
2117 0 : SwTextGridItem const*const pGrid(GetGridItem(rInf.GetFrm()->FindPageFrm()));
2118 0 : if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && !pGrid->IsSnapToChars() )
2119 : {
2120 :
2121 0 : const long nGridWidthAdd = EvalGridWidthAdd( pGrid, rInf );
2122 :
2123 0 : for(sal_Int32 j = 0; j < rInf.GetLen(); j++)
2124 : {
2125 0 : long nScr = pKernArray[ j ] + ( nSpaceAdd + nGridWidthAdd ) * ( j + 1 );
2126 0 : if( nScr >= rInf.GetOfst())
2127 : {
2128 0 : nCnt = j;
2129 0 : break;
2130 : }
2131 : }
2132 0 : delete[] pKernArray;
2133 0 : return nCnt;
2134 : }
2135 : }
2136 :
2137 16 : sal_Int32 nDone = 0;
2138 16 : LanguageType aLang = LANGUAGE_NONE;
2139 16 : bool bSkipCharacterCells = false;
2140 16 : sal_Int32 nIdx = rInf.GetIdx();
2141 16 : sal_Int32 nLastIdx = nIdx;
2142 16 : const sal_Int32 nEnd = rInf.GetIdx() + rInf.GetLen();
2143 :
2144 : // #i105901#
2145 : // skip character cells for all script types
2146 16 : if ( g_pBreakIt->GetBreakIter().is() )
2147 : {
2148 16 : aLang = rInf.GetFont()->GetLanguage();
2149 16 : bSkipCharacterCells = true;
2150 : }
2151 :
2152 37 : while ( ( nRight < long( rInf.GetOfst() ) ) && ( nIdx < nEnd ) )
2153 : {
2154 5 : if ( nSpaceAdd && CH_BLANK == rInf.GetText()[ nIdx ] )
2155 0 : nSpaceSum += nSpaceAdd;
2156 :
2157 : // go to next character (cell).
2158 5 : nLastIdx = nIdx;
2159 :
2160 5 : if ( bSkipCharacterCells )
2161 : {
2162 15 : nIdx = g_pBreakIt->GetBreakIter()->nextCharacters( rInf.GetText(),
2163 5 : nIdx, g_pBreakIt->GetLocale( aLang ),
2164 10 : i18n::CharacterIteratorMode::SKIPCELL, 1, nDone );
2165 5 : if ( nIdx <= nLastIdx )
2166 0 : break;
2167 : }
2168 : else
2169 0 : ++nIdx;
2170 :
2171 5 : nLeft = nRight;
2172 5 : nRight = pKernArray[ nIdx - rInf.GetIdx() - 1 ] + nKernSum + nSpaceSum;
2173 :
2174 5 : nKernSum += nKern;
2175 : }
2176 :
2177 : // step back if position is before the middle of the character
2178 : // or if we do not want to go to the next character
2179 17 : if ( nIdx > rInf.GetIdx() &&
2180 2 : ( rInf.IsPosMatchesBounds() ||
2181 1 : ( ( nRight > long( rInf.GetOfst() ) ) &&
2182 0 : ( nRight - rInf.GetOfst() > rInf.GetOfst() - nLeft ) ) ) )
2183 0 : nCnt = nLastIdx - rInf.GetIdx(); // first half
2184 : else
2185 16 : nCnt = nIdx - rInf.GetIdx(); // second half
2186 :
2187 16 : if ( pSI )
2188 16 : rInf.SetCursorBidiLevel( pSI->DirType( nLastIdx ) );
2189 :
2190 16 : delete[] pKernArray;
2191 16 : return nCnt;
2192 : }
2193 :
2194 1142620 : SwFntAccess::SwFntAccess( const void* &rMagic,
2195 : sal_uInt16 &rIndex, const void *pOwn, SwViewShell const *pSh,
2196 : bool bCheck ) :
2197 : SwCacheAccess( *pFntCache, rMagic, rIndex ),
2198 1142620 : pShell( pSh )
2199 : {
2200 : // the used ctor of SwCacheAccess searches for rMagic+rIndex in the cache
2201 1142620 : if ( IsAvail() )
2202 : {
2203 : // fast case: known Font (rMagic), no need to check printer and zoom
2204 990411 : if ( !bCheck )
2205 553199 : return;
2206 :
2207 : // Font is known, but has to be checked
2208 : }
2209 : else
2210 : { // Font not known, must be searched
2211 152209 : bCheck = false;
2212 : }
2213 :
2214 : {
2215 589421 : OutputDevice* pOut = 0;
2216 589421 : sal_uInt16 nZoom = USHRT_MAX;
2217 :
2218 : // Get the reference device
2219 589421 : if ( pSh )
2220 : {
2221 589045 : pOut = &pSh->GetRefDev();
2222 589045 : nZoom = pSh->GetViewOptions()->GetZoom();
2223 : }
2224 :
2225 : SwFntObj *pFntObj;
2226 589421 : if ( bCheck )
2227 : {
2228 437212 : pFntObj = Get();
2229 1306250 : if ( ( pFntObj->GetZoom( ) == nZoom ) &&
2230 864443 : ( pFntObj->pPrinter == pOut ) &&
2231 427231 : pFntObj->GetPropWidth() ==
2232 427231 : static_cast<SwSubFont const *>(pOwn)->GetPropWidth() )
2233 : {
2234 427231 : return; // result of Check: Drucker+Zoom okay.
2235 : }
2236 9981 : pFntObj->Unlock(); // forget this object, printer/zoom differs
2237 9981 : pObj = NULL;
2238 : }
2239 :
2240 : // Search by font comparison, quite expensive!
2241 : // Look for same font and same printer
2242 162190 : pFntObj = pFntCache->First();
2243 735085 : while ( pFntObj && !( pFntObj->aFont == *static_cast<vcl::Font const *>(pOwn) &&
2244 315191 : pFntObj->GetZoom() == nZoom &&
2245 154542 : pFntObj->GetPropWidth() ==
2246 154542 : static_cast<SwSubFont const *>(pOwn)->GetPropWidth() &&
2247 154532 : ( !pFntObj->pPrinter || pFntObj->pPrinter == pOut ) ) )
2248 125028 : pFntObj = SwFntCache::Next( pFntObj );
2249 :
2250 162190 : if( pFntObj && pFntObj->pPrinter.get() != pOut )
2251 : {
2252 : // found one without printer, let's see if there is one with
2253 : // the same printer as well
2254 6892 : SwFntObj *pTmpObj = pFntObj;
2255 81460 : while( pTmpObj && !( pTmpObj->aFont == *static_cast<vcl::Font const *>(pOwn) &&
2256 14112 : pTmpObj->GetZoom()==nZoom && pTmpObj->pPrinter==pOut &&
2257 10 : pTmpObj->GetPropWidth() ==
2258 10 : static_cast<SwSubFont const *>(pOwn)->GetPropWidth() ) )
2259 30267 : pTmpObj = SwFntCache::Next( pTmpObj );
2260 6892 : if( pTmpObj )
2261 0 : pFntObj = pTmpObj;
2262 : }
2263 :
2264 162190 : if ( !pFntObj ) // Font has not been found, create one
2265 : {
2266 : // Have to create new Object, hence Owner must be a SwFont, later
2267 : // the Owner will be the "MagicNumber"
2268 7743 : SwCacheAccess::pOwner = pOwn;
2269 7743 : pFntObj = Get(); // will create via NewObj() and lock
2270 : OSL_ENSURE(pFntObj, "No Font, no Fun.");
2271 : }
2272 : else // Font has been found, so we lock it.
2273 : {
2274 154447 : pFntObj->Lock();
2275 154447 : if (pFntObj->pPrinter.get() != pOut) // if no printer is known by now
2276 : {
2277 : OSL_ENSURE( !pFntObj->pPrinter, "SwFntAccess: Printer Changed" );
2278 6892 : pFntObj->CreatePrtFont( *pOut );
2279 6892 : pFntObj->pPrinter = pOut;
2280 6892 : pFntObj->pScrFont = NULL;
2281 6892 : pFntObj->nGuessedLeading = USHRT_MAX;
2282 6892 : pFntObj->nExtLeading = USHRT_MAX;
2283 6892 : pFntObj->nPrtAscent = USHRT_MAX;
2284 6892 : pFntObj->nPrtHeight = USHRT_MAX;
2285 : }
2286 154447 : pObj = pFntObj;
2287 : }
2288 :
2289 : // no matter if new or found, now the Owner of the Object is a
2290 : // MagicNumber, and will be given to the SwFont, as well as the Index
2291 : // for later direct access
2292 162190 : rMagic = pFntObj->GetOwner();
2293 162190 : SwCacheAccess::pOwner = rMagic;
2294 162190 : rIndex = pFntObj->GetCachePos();
2295 : }
2296 : }
2297 :
2298 7743 : SwCacheObj *SwFntAccess::NewObj( )
2299 : {
2300 : // a new Font, a new "MagicNumber".
2301 7743 : return new SwFntObj( *static_cast<SwSubFont const *>(pOwner), ++pMagicNo, pShell );
2302 : }
2303 :
2304 40313 : sal_Int32 SwFont::GetTextBreak( SwDrawTextInfo& rInf, long nTextWidth )
2305 : {
2306 40313 : ChgFnt( rInf.GetShell(), rInf.GetOut() );
2307 :
2308 40313 : const bool bCompress = rInf.GetKanaComp() && rInf.GetLen() &&
2309 0 : SW_CJK == GetActual() &&
2310 0 : rInf.GetScriptInfo() &&
2311 40313 : rInf.GetScriptInfo()->CountCompChg() &&
2312 40313 : lcl_IsMonoSpaceFont( rInf.GetOut() );
2313 :
2314 : OSL_ENSURE( !bCompress || ( rInf.GetScriptInfo() && rInf.GetScriptInfo()->
2315 : CountCompChg()), "Compression without info" );
2316 :
2317 40313 : sal_Int32 nTextBreak = 0;
2318 40313 : long nKern = 0;
2319 :
2320 40313 : sal_Int32 nLn = rInf.GetLen() == COMPLETE_STRING
2321 40313 : ? rInf.GetText().getLength() : rInf.GetLen();
2322 :
2323 156773 : if ( rInf.GetFrm() && nLn && rInf.SnapToGrid() &&
2324 111981 : rInf.GetFont() && SW_CJK == rInf.GetFont()->GetActual() )
2325 : {
2326 4 : SwTextGridItem const*const pGrid(GetGridItem(rInf.GetFrm()->FindPageFrm()));
2327 4 : if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && pGrid->IsSnapToChars() )
2328 : {
2329 0 : const SwDoc* pDoc = rInf.GetShell()->GetDoc();
2330 0 : const sal_uInt16 nGridWidth = GetGridWidth(*pGrid, *pDoc);
2331 :
2332 0 : long* pKernArray = new long[rInf.GetLen()];
2333 0 : rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray,
2334 0 : rInf.GetIdx(), rInf.GetLen() );
2335 :
2336 0 : long nAvgWidthPerChar = pKernArray[ rInf.GetLen() - 1 ] / rInf.GetLen();
2337 :
2338 : const sal_uLong i = nAvgWidthPerChar ?
2339 0 : ( nAvgWidthPerChar - 1 ) / nGridWidth + 1:
2340 0 : 1;
2341 :
2342 0 : nAvgWidthPerChar = i * nGridWidth;
2343 0 : long nCurrPos = nAvgWidthPerChar;
2344 :
2345 0 : while( nTextBreak < rInf.GetLen() && nTextWidth >= nCurrPos )
2346 : {
2347 0 : nCurrPos += nAvgWidthPerChar;
2348 0 : ++nTextBreak;
2349 : }
2350 :
2351 0 : delete[] pKernArray;
2352 0 : return nTextBreak + rInf.GetIdx();
2353 : }
2354 : }
2355 :
2356 : //for text grid enhancement
2357 76147 : if ( rInf.GetFrm() && nLn && rInf.SnapToGrid() && rInf.GetFont() &&
2358 35834 : SW_CJK == rInf.GetFont()->GetActual() )
2359 : {
2360 4 : SwTextGridItem const*const pGrid(GetGridItem(rInf.GetFrm()->FindPageFrm()));
2361 4 : if ( pGrid && GRID_LINES_CHARS == pGrid->GetGridType() && !pGrid->IsSnapToChars() )
2362 : {
2363 0 : const long nGridWidthAdd = EvalGridWidthAdd( pGrid, rInf );
2364 :
2365 0 : long* pKernArray = new long[rInf.GetLen()];
2366 0 : rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray,
2367 0 : rInf.GetIdx(), rInf.GetLen() );
2368 0 : long nCurrPos = pKernArray[nTextBreak] + nGridWidthAdd;
2369 0 : while( nTextBreak < rInf.GetLen() && nTextWidth >= nCurrPos)
2370 : {
2371 0 : nTextBreak++;
2372 0 : nCurrPos = pKernArray[nTextBreak] + nGridWidthAdd * ( nTextBreak + 1 );
2373 : }
2374 0 : delete[] pKernArray;
2375 0 : return nTextBreak + rInf.GetIdx();
2376 : }
2377 : }
2378 :
2379 40313 : if( aSub[nActual].IsCapital() && nLn )
2380 : {
2381 2 : nTextBreak = GetCapitalBreak( rInf.GetShell(), rInf.GetpOut(),
2382 2 : rInf.GetScriptInfo(), rInf.GetText(), nTextWidth, rInf.GetIdx(),
2383 6 : nLn );
2384 : }
2385 : else
2386 : {
2387 40311 : nKern = CheckKerning();
2388 :
2389 : const OUString* pTmpText;
2390 40311 : OUString aTmpText;
2391 : sal_Int32 nTmpIdx;
2392 : sal_Int32 nTmpLen;
2393 40311 : bool bTextReplaced = false;
2394 :
2395 40311 : if ( !aSub[nActual].IsCaseMap() )
2396 : {
2397 40216 : pTmpText = &rInf.GetText();
2398 40216 : nTmpIdx = rInf.GetIdx();
2399 40216 : nTmpLen = nLn;
2400 : }
2401 : else
2402 : {
2403 95 : const OUString aSnippet(rInf.GetText().copy(rInf.GetIdx(), nLn));
2404 95 : aTmpText = aSub[nActual].CalcCaseMap( aSnippet );
2405 95 : const bool bTitle = SVX_CASEMAP_TITEL == aSub[nActual].GetCaseMap() &&
2406 95 : g_pBreakIt->GetBreakIter().is();
2407 :
2408 : // Uaaaaahhhh!!! In title case mode, we would get wrong results
2409 95 : if ( bTitle && nLn )
2410 : {
2411 : // check if rInf.GetIdx() is begin of word
2412 0 : if ( !g_pBreakIt->GetBreakIter()->isBeginWord(
2413 0 : rInf.GetText(), rInf.GetIdx(),
2414 0 : g_pBreakIt->GetLocale( aSub[nActual].GetLanguage() ),
2415 0 : i18n::WordType::ANYWORD_IGNOREWHITESPACES ) )
2416 : {
2417 : // In this case, the beginning of aTmpText is wrong.
2418 0 : OUString aSnippetTmp(aSnippet.copy(0, 1));
2419 0 : aSnippetTmp = aSub[nActual].CalcCaseMap( aSnippetTmp );
2420 0 : aTmpText = aTmpText.replaceAt( 0, aSnippetTmp.getLength(), OUString(aSnippet[0]) );
2421 : }
2422 : }
2423 :
2424 95 : pTmpText = &aTmpText;
2425 95 : nTmpIdx = 0;
2426 95 : nTmpLen = aTmpText.getLength();
2427 95 : bTextReplaced = true;
2428 : }
2429 :
2430 40311 : if( rInf.GetHyphPos() ) {
2431 0 : sal_Int32 nHyphPos = *rInf.GetHyphPos();
2432 0 : nTextBreak = rInf.GetOut().GetTextBreak( *pTmpText, nTextWidth,
2433 : static_cast<sal_Unicode>('-'), nHyphPos,
2434 0 : nTmpIdx, nTmpLen, nKern, rInf.GetVclCache());
2435 0 : *rInf.GetHyphPos() = (nHyphPos == -1) ? COMPLETE_STRING : nHyphPos;
2436 : }
2437 : else
2438 40311 : nTextBreak = rInf.GetOut().GetTextBreak( *pTmpText, nTextWidth,
2439 80622 : nTmpIdx, nTmpLen, nKern, rInf.GetVclCache());
2440 :
2441 40311 : if ( bTextReplaced && nTextBreak != -1 )
2442 : {
2443 45 : if ( nTmpLen != nLn )
2444 0 : nTextBreak = sw_CalcCaseMap( *this, rInf.GetText(),
2445 0 : rInf.GetIdx(), nLn, nTextBreak );
2446 : else
2447 45 : nTextBreak = nTextBreak + rInf.GetIdx();
2448 40311 : }
2449 : }
2450 :
2451 40313 : sal_Int32 nTextBreak2 = nTextBreak == -1 ? COMPLETE_STRING : nTextBreak;
2452 :
2453 40313 : if ( ! bCompress )
2454 40313 : return nTextBreak2;
2455 :
2456 0 : nTextBreak2 = nTextBreak2 - rInf.GetIdx();
2457 :
2458 0 : if( nTextBreak2 < nLn )
2459 : {
2460 0 : if( !nTextBreak2 && nLn )
2461 0 : nLn = 1;
2462 0 : else if( nLn > 2 * nTextBreak2 )
2463 0 : nLn = 2 * nTextBreak2;
2464 0 : long* pKernArray = new long[ nLn ];
2465 0 : rInf.GetOut().GetTextArray( rInf.GetText(), pKernArray,
2466 0 : rInf.GetIdx(), nLn );
2467 0 : if( rInf.GetScriptInfo()->Compress( pKernArray, rInf.GetIdx(), nLn,
2468 0 : rInf.GetKanaComp(), (sal_uInt16)GetHeight( nActual ) ) )
2469 : {
2470 0 : long nKernAdd = nKern;
2471 0 : sal_Int32 nTmpBreak = nTextBreak2;
2472 0 : if( nKern && nTextBreak2 )
2473 0 : nKern *= nTextBreak2 - 1;
2474 0 : while( nTextBreak2<nLn && nTextWidth >= pKernArray[nTextBreak2] +nKern )
2475 : {
2476 0 : nKern += nKernAdd;
2477 0 : ++nTextBreak2;
2478 : }
2479 0 : if( rInf.GetHyphPos() )
2480 0 : *rInf.GetHyphPos() += nTextBreak2 - nTmpBreak; // It's not perfect
2481 : }
2482 0 : delete[] pKernArray;
2483 : }
2484 0 : nTextBreak2 = nTextBreak2 + rInf.GetIdx();
2485 :
2486 0 : return nTextBreak2;
2487 : }
2488 :
2489 : extern Color aGlobalRetoucheColor;
2490 :
2491 21115 : bool SwDrawTextInfo::ApplyAutoColor( vcl::Font* pFont )
2492 : {
2493 21115 : const vcl::Font& rFnt = pFont ? *pFont : GetOut().GetFont();
2494 21115 : bool bPrt = GetShell() && ! GetShell()->GetWin();
2495 21115 : ColorData nNewColor = COL_BLACK;
2496 21115 : bool bChgFntColor = false;
2497 21115 : bool bChgLineColor = false;
2498 :
2499 21115 : if( bPrt && GetShell() && GetShell()->GetViewOptions()->IsBlackFont() )
2500 : {
2501 0 : if ( COL_BLACK != rFnt.GetColor().GetColor() )
2502 0 : bChgFntColor = true;
2503 :
2504 0 : if ( (COL_BLACK != GetOut().GetLineColor().GetColor()) ||
2505 0 : (COL_BLACK != GetOut().GetOverlineColor().GetColor()) )
2506 0 : bChgLineColor = true;
2507 : }
2508 : else
2509 : {
2510 : // FontColor has to be changed if:
2511 : // 1. FontColor = AUTO or 2. IsAlwaysAutoColor is set
2512 : // LineColor has to be changed if:
2513 : // 1. IsAlwaysAutoColor is set
2514 :
2515 41787 : bChgLineColor = ! bPrt && GetShell() &&
2516 41787 : GetShell()->GetAccessibilityOptions()->IsAlwaysAutoColor();
2517 :
2518 21115 : bChgFntColor = COL_AUTO == rFnt.GetColor().GetColor() || bChgLineColor;
2519 :
2520 21115 : if ( bChgFntColor )
2521 : {
2522 : // check if current background has a user defined setting
2523 16475 : const Color* pCol = GetFont() ? GetFont()->GetBackColor() : NULL;
2524 16475 : if( ! pCol || COL_TRANSPARENT == pCol->GetColor() )
2525 : {
2526 : const SvxBrushItem* pItem;
2527 16303 : SwRect aOrigBackRect;
2528 :
2529 : //UUUU
2530 16303 : drawinglayer::attribute::SdrAllFillAttributesHelperPtr aFillAttributes;
2531 :
2532 : /// OD 21.08.2002
2533 : /// consider, that [GetBackgroundBrush(...)] can set <pCol>
2534 : /// - see implementation in /core/layout/paintfrm.cxx
2535 : /// OD 21.08.2002 #99657#
2536 : /// There is a user defined setting for the background, if there
2537 : /// is a background brush and its color is *not* "no fill"/"auto fill".
2538 16303 : if( GetFrm()->GetBackgroundBrush( aFillAttributes, pItem, pCol, aOrigBackRect, false ) )
2539 : {
2540 716 : if ( !pCol )
2541 : {
2542 308 : pCol = &pItem->GetColor();
2543 : }
2544 :
2545 : /// OD 30.08.2002 #99657#
2546 : /// determined color <pCol> can be <COL_TRANSPARENT>. Thus, check it.
2547 716 : if ( pCol->GetColor() == COL_TRANSPARENT)
2548 204 : pCol = NULL;
2549 : }
2550 : else
2551 15587 : pCol = NULL;
2552 : }
2553 :
2554 : // no user defined color at paragraph or font background
2555 16475 : if ( ! pCol )
2556 15791 : pCol = &aGlobalRetoucheColor;
2557 :
2558 16475 : if( GetShell() && GetShell()->GetWin() )
2559 : {
2560 : // here we determine the preferred window text color for painting
2561 16072 : const SwViewOption* pViewOption = GetShell()->GetViewOptions();
2562 16072 : if(pViewOption->IsPagePreview() &&
2563 0 : !SW_MOD()->GetAccessibilityOptions().GetIsForPagePreviews())
2564 0 : nNewColor = COL_BLACK;
2565 : else
2566 : // we take the font color from the appearance page
2567 16072 : nNewColor = SwViewOption::GetFontColor().GetColor();
2568 : }
2569 :
2570 : // change painting color depending of dark/bright background
2571 16475 : Color aTmpColor( nNewColor );
2572 16475 : if ( pCol->IsDark() && aTmpColor.IsDark() )
2573 58 : nNewColor = COL_WHITE;
2574 16417 : else if ( pCol->IsBright() && aTmpColor.IsBright() )
2575 0 : nNewColor = COL_BLACK;
2576 : }
2577 : }
2578 :
2579 21115 : if ( bChgFntColor || bChgLineColor )
2580 : {
2581 16475 : Color aNewColor( nNewColor );
2582 :
2583 16475 : if ( bChgFntColor )
2584 : {
2585 16475 : if ( pFont && aNewColor != pFont->GetColor() )
2586 : {
2587 : // only set the new color at the font passed as argument
2588 16432 : pFont->SetColor( aNewColor );
2589 : }
2590 43 : else if ( aNewColor != GetOut().GetFont().GetColor() )
2591 : {
2592 : // set new font with new color at output device
2593 43 : vcl::Font aFont( rFnt );
2594 43 : aFont.SetColor( aNewColor );
2595 43 : GetOut().SetFont( aFont );
2596 : }
2597 : }
2598 :
2599 : // the underline and overline colors have to be set separately
2600 16475 : if ( bChgLineColor )
2601 : {
2602 : // get current font color or color set at output device
2603 0 : aNewColor = pFont ? pFont->GetColor() : GetOut().GetFont().GetColor();
2604 0 : if ( aNewColor != GetOut().GetLineColor() )
2605 0 : GetOut().SetLineColor( aNewColor );
2606 0 : if ( aNewColor != GetOut().GetOverlineColor() )
2607 0 : GetOut().SetOverlineColor( aNewColor );
2608 : }
2609 :
2610 16475 : return true;
2611 : }
2612 :
2613 4640 : return false;
2614 177 : }
2615 :
2616 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|