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