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