LCOV - code coverage report
Current view: top level - sw/source/core/txtnode - fntcache.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 633 1207 52.4 %
Date: 2015-06-13 12:38:46 Functions: 24 27 88.9 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.11