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