LCOV - code coverage report
Current view: top level - vcl/source/gdi - outdev3.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 2612 4152 62.9 %
Date: 2012-08-25 Functions: 133 173 76.9 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 2349 5995 39.2 %

           Branch data     Line data    Source code
       1                 :            : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2                 :            : /*************************************************************************
       3                 :            :  *
       4                 :            :  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       5                 :            :  *
       6                 :            :  * Copyright 2000, 2010 Oracle and/or its affiliates.
       7                 :            :  *
       8                 :            :  * OpenOffice.org - a multi-platform office productivity suite
       9                 :            :  *
      10                 :            :  * This file is part of OpenOffice.org.
      11                 :            :  *
      12                 :            :  * OpenOffice.org is free software: you can redistribute it and/or modify
      13                 :            :  * it under the terms of the GNU Lesser General Public License version 3
      14                 :            :  * only, as published by the Free Software Foundation.
      15                 :            :  *
      16                 :            :  * OpenOffice.org is distributed in the hope that it will be useful,
      17                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      18                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      19                 :            :  * GNU Lesser General Public License version 3 for more details
      20                 :            :  * (a copy is included in the LICENSE file that accompanied this code).
      21                 :            :  *
      22                 :            :  * You should have received a copy of the GNU Lesser General Public License
      23                 :            :  * version 3 along with OpenOffice.org.  If not, see
      24                 :            :  * <http://www.openoffice.org/license.html>
      25                 :            :  * for a copy of the LGPLv3 License.
      26                 :            :  *
      27                 :            :  ************************************************************************/
      28                 :            : 
      29                 :            : 
      30                 :            : #include "i18npool/mslangid.hxx"
      31                 :            : 
      32                 :            : #include "rtl/tencinfo.h"
      33                 :            : #include "rtl/logfile.hxx"
      34                 :            : 
      35                 :            : #include "tools/debug.hxx"
      36                 :            : #include "tools/poly.hxx"
      37                 :            : 
      38                 :            : #include "basegfx/polygon/b2dpolygon.hxx"
      39                 :            : #include "basegfx/polygon/b2dpolypolygon.hxx"
      40                 :            : #include "basegfx/matrix/b2dhommatrix.hxx"
      41                 :            : 
      42                 :            : #include "vcl/metric.hxx"
      43                 :            : #include "vcl/metaact.hxx"
      44                 :            : #include "vcl/gdimtf.hxx"
      45                 :            : #include "vcl/virdev.hxx"
      46                 :            : #include "vcl/print.hxx"
      47                 :            : #include "vcl/event.hxx"
      48                 :            : #include "vcl/window.hxx"
      49                 :            : #include "vcl/svapp.hxx"
      50                 :            : #include "vcl/bmpacc.hxx"
      51                 :            : #include "vcl/outdev.hxx"
      52                 :            : #include "vcl/edit.hxx"
      53                 :            : // declare system types in sysdata.hxx
      54                 :            : #include <svsys.h>
      55                 :            : #include "vcl/sysdata.hxx"
      56                 :            : #include "vcl/unohelp.hxx"
      57                 :            : #include "vcl/controllayout.hxx"
      58                 :            : 
      59                 :            : #include "salgdi.hxx"
      60                 :            : #include "sallayout.hxx"
      61                 :            : #include "svdata.hxx"
      62                 :            : #include "impfont.hxx"
      63                 :            : #include "outdata.hxx"
      64                 :            : #include "outfont.hxx"
      65                 :            : #include "outdev.h"
      66                 :            : #include "textlayout.hxx"
      67                 :            : #include "svids.hrc"
      68                 :            : #include "window.h"
      69                 :            : 
      70                 :            : #include "unotools/fontcvt.hxx"
      71                 :            : #include "unotools/fontcfg.hxx"
      72                 :            : 
      73                 :            : #include "osl/file.h"
      74                 :            : 
      75                 :            : #ifdef ENABLE_GRAPHITE
      76                 :            : #include "graphite_features.hxx"
      77                 :            : #endif
      78                 :            : 
      79                 :            : #include "pdfwriter_impl.hxx"
      80                 :            : 
      81                 :            : #include "com/sun/star/beans/PropertyValues.hpp"
      82                 :            : #include "com/sun/star/i18n/XBreakIterator.hpp"
      83                 :            : #include "com/sun/star/i18n/WordType.hpp"
      84                 :            : #include "com/sun/star/linguistic2/XLinguServiceManager.hpp"
      85                 :            : 
      86                 :            : #if defined UNX
      87                 :            : #define GLYPH_FONT_HEIGHT   128
      88                 :            : #else
      89                 :            : #define GLYPH_FONT_HEIGHT   256
      90                 :            : #endif
      91                 :            : 
      92                 :            : #include "sal/alloca.h"
      93                 :            : 
      94                 :            : #include <cmath>
      95                 :            : #include <cstring>
      96                 :            : 
      97                 :            : #include <memory>
      98                 :            : #include <algorithm>
      99                 :            : 
     100                 :            : 
     101                 :            : // =======================================================================
     102                 :            : 
     103                 :            : DBG_NAMEEX( OutputDevice )
     104                 :            : DBG_NAMEEX( Font )
     105                 :            : 
     106                 :            : // =======================================================================
     107                 :            : 
     108                 :            : using namespace ::com::sun::star;
     109                 :            : using namespace ::com::sun::star::uno;
     110                 :            : using namespace ::rtl;
     111                 :            : using namespace ::vcl;
     112                 :            : using namespace ::utl;
     113                 :            : 
     114                 :            : // =======================================================================
     115                 :            : 
     116                 :            : #define TEXT_DRAW_ELLIPSIS  (TEXT_DRAW_ENDELLIPSIS | TEXT_DRAW_PATHELLIPSIS | TEXT_DRAW_NEWSELLIPSIS)
     117                 :            : 
     118                 :            : // =======================================================================
     119                 :            : 
     120                 :            : #define UNDERLINE_LAST      UNDERLINE_BOLDWAVE
     121                 :            : #define STRIKEOUT_LAST      STRIKEOUT_X
     122                 :            : 
     123                 :            : // =======================================================================
     124                 :            : 
     125                 :     243505 : static void ImplRotatePos( long nOriginX, long nOriginY, long& rX, long& rY,
     126                 :            :                            int nOrientation )
     127                 :            : {
     128 [ +  + ][ +  + ]:     243505 :     if ( (nOrientation >= 0) && !(nOrientation % 900) )
     129                 :            :     {
     130         [ -  + ]:       9994 :         if ( (nOrientation >= 3600) )
     131                 :          0 :             nOrientation %= 3600;
     132                 :            : 
     133         [ +  - ]:       9994 :         if ( nOrientation )
     134                 :            :         {
     135                 :       9994 :             rX -= nOriginX;
     136                 :       9994 :             rY -= nOriginY;
     137                 :            : 
     138         [ +  + ]:       9994 :             if ( nOrientation == 900 )
     139                 :            :             {
     140                 :       2864 :                 long nTemp = rX;
     141                 :       2864 :                 rX = rY;
     142                 :       2864 :                 rY = -nTemp;
     143                 :            :             }
     144         [ -  + ]:       7130 :             else if ( nOrientation == 1800 )
     145                 :            :             {
     146                 :          0 :                 rX = -rX;
     147                 :          0 :                 rY = -rY;
     148                 :            :             }
     149                 :            :             else /* ( nOrientation == 2700 ) */
     150                 :            :             {
     151                 :       7130 :                 long nTemp = rX;
     152                 :       7130 :                 rX = -rY;
     153                 :       7130 :                 rY = nTemp;
     154                 :            :             }
     155                 :            : 
     156                 :       9994 :             rX += nOriginX;
     157                 :       9994 :             rY += nOriginY;
     158                 :       9994 :         }
     159                 :            :     }
     160                 :            :     else
     161                 :            :     {
     162                 :     233511 :         double nRealOrientation = nOrientation*F_PI1800;
     163                 :     233511 :         double nCos = cos( nRealOrientation );
     164                 :     233511 :         double nSin = sin( nRealOrientation );
     165                 :            : 
     166                 :            :         // Translation...
     167                 :     233511 :         long nX = rX-nOriginX;
     168                 :     233511 :         long nY = rY-nOriginY;
     169                 :            : 
     170                 :            :         // Rotation...
     171                 :     233511 :         rX = +((long)(nCos*nX + nSin*nY)) + nOriginX;
     172                 :     233511 :         rY = -((long)(nSin*nX - nCos*nY)) + nOriginY;
     173                 :            :     }
     174                 :     243505 : }
     175                 :            : 
     176                 :            : // =======================================================================
     177                 :            : 
     178                 :          8 : void OutputDevice::ImplUpdateFontData( bool bNewFontLists )
     179                 :            : {
     180                 :            :     // the currently selected logical font is no longer needed
     181         [ -  + ]:          8 :     if ( mpFontEntry )
     182                 :            :     {
     183                 :          0 :         mpFontCache->Release( mpFontEntry );
     184                 :          0 :         mpFontEntry = NULL;
     185                 :            :     }
     186                 :            : 
     187                 :          8 :     mbInitFont = true;
     188                 :          8 :     mbNewFont = true;
     189                 :            : 
     190         [ +  - ]:          8 :     if ( bNewFontLists )
     191                 :            :     {
     192         [ +  + ]:          8 :         if ( mpGetDevFontList )
     193                 :            :         {
     194         [ +  - ]:          2 :             delete mpGetDevFontList;
     195                 :          2 :             mpGetDevFontList = NULL;
     196                 :            :         }
     197         [ -  + ]:          8 :         if ( mpGetDevSizeList )
     198                 :            :         {
     199         [ #  # ]:          0 :             delete mpGetDevSizeList;
     200                 :          0 :             mpGetDevSizeList = NULL;
     201                 :            :         }
     202                 :            : 
     203                 :            :         // release all physically selected fonts on this device
     204         [ +  - ]:          8 :     if( ImplGetGraphics() )
     205                 :          8 :          mpGraphics->ReleaseFonts();
     206                 :            :     }
     207                 :            : 
     208 [ -  + ][ #  # ]:          8 :     if ( GetOutDevType() == OUTDEV_PRINTER || mpPDFWriter )
                 [ +  - ]
     209                 :            :     {
     210                 :          8 :         ImplSVData* pSVData = ImplGetSVData();
     211                 :            : 
     212 [ +  + ][ +  - ]:          8 :         if( mpFontCache && mpFontCache != pSVData->maGDIData.mpScreenFontCache )
     213                 :          5 :             mpFontCache->Invalidate();
     214                 :            : 
     215         [ +  - ]:          8 :         if ( bNewFontLists )
     216                 :            :         {
     217                 :            :             // we need a graphics
     218         [ +  - ]:          8 :             if ( ImplGetGraphics() )
     219                 :            :             {
     220 [ +  - ][ +  + ]:          8 :                 if( mpFontList && mpFontList != pSVData->maGDIData.mpScreenFontList )
     221                 :          5 :                     mpFontList->Clear();
     222                 :            : 
     223         [ -  + ]:          8 :                 if( mpPDFWriter )
     224                 :            :                 {
     225 [ #  # ][ #  # ]:          0 :                     if( mpFontList && mpFontList != pSVData->maGDIData.mpScreenFontList )
     226         [ #  # ]:          0 :                         delete mpFontList;
     227 [ #  # ][ #  # ]:          0 :                     if( mpFontCache && mpFontCache != pSVData->maGDIData.mpScreenFontCache )
     228         [ #  # ]:          0 :                         delete mpFontCache;
     229                 :          0 :                     mpFontList = mpPDFWriter->filterDevFontList( pSVData->maGDIData.mpScreenFontList );
     230         [ #  # ]:          0 :                     mpFontCache = new ImplFontCache( sal_False );
     231                 :            :                 }
     232                 :            :                 else
     233                 :            :                 {
     234         [ -  + ]:          8 :                     if( mpOutDevData )
     235                 :          0 :                         mpOutDevData->maDevFontSubst.Clear();
     236                 :          8 :                     mpGraphics->GetDevFontList( mpFontList );
     237                 :          8 :                     mpGraphics->GetDevFontSubstList( this );
     238                 :            :                 }
     239                 :            :             }
     240                 :            :         }
     241                 :            :     }
     242                 :            : 
     243                 :            :     // also update child windows if needed
     244         [ -  + ]:          8 :     if ( GetOutDevType() == OUTDEV_WINDOW )
     245                 :            :     {
     246                 :          0 :         Window* pChild = ((Window*)this)->mpWindowImpl->mpFirstChild;
     247         [ #  # ]:          0 :         while ( pChild )
     248                 :            :         {
     249                 :          0 :             pChild->ImplUpdateFontData( true );
     250                 :          0 :             pChild = pChild->mpWindowImpl->mpNext;
     251                 :            :         }
     252                 :            :     }
     253                 :          8 : }
     254                 :            : 
     255                 :            : // -----------------------------------------------------------------------
     256                 :            : 
     257                 :          0 : void OutputDevice::ImplUpdateAllFontData( bool bNewFontLists )
     258                 :            : {
     259                 :          0 :     ImplSVData* pSVData = ImplGetSVData();
     260                 :            : 
     261                 :            :     // update all windows
     262                 :          0 :     Window* pFrame = pSVData->maWinData.mpFirstFrame;
     263         [ #  # ]:          0 :     while ( pFrame )
     264                 :            :     {
     265                 :          0 :         pFrame->ImplUpdateFontData( bNewFontLists );
     266                 :            : 
     267                 :          0 :         Window* pSysWin = pFrame->mpWindowImpl->mpFrameData->mpFirstOverlap;
     268         [ #  # ]:          0 :         while ( pSysWin )
     269                 :            :         {
     270                 :          0 :             pSysWin->ImplUpdateFontData( bNewFontLists );
     271                 :          0 :             pSysWin = pSysWin->mpWindowImpl->mpNextOverlap;
     272                 :            :         }
     273                 :            : 
     274                 :          0 :         pFrame = pFrame->mpWindowImpl->mpFrameData->mpNextFrame;
     275                 :            :     }
     276                 :            : 
     277                 :            :     // update all virtual devices
     278                 :          0 :     VirtualDevice* pVirDev = pSVData->maGDIData.mpFirstVirDev;
     279         [ #  # ]:          0 :     while ( pVirDev )
     280                 :            :     {
     281                 :          0 :         pVirDev->ImplUpdateFontData( bNewFontLists );
     282                 :          0 :         pVirDev = pVirDev->mpNext;
     283                 :            :     }
     284                 :            : 
     285                 :            :     // update all printers
     286                 :          0 :     Printer* pPrinter = pSVData->maGDIData.mpFirstPrinter;
     287         [ #  # ]:          0 :     while ( pPrinter )
     288                 :            :     {
     289                 :          0 :         pPrinter->ImplUpdateFontData( bNewFontLists );
     290                 :          0 :         pPrinter = pPrinter->mpNext;
     291                 :            :     }
     292                 :            : 
     293                 :            :     // clear global font lists to have them updated
     294                 :          0 :     pSVData->maGDIData.mpScreenFontCache->Invalidate();
     295         [ #  # ]:          0 :     if ( bNewFontLists )
     296                 :            :     {
     297                 :          0 :         pSVData->maGDIData.mpScreenFontList->Clear();
     298                 :          0 :         pFrame = pSVData->maWinData.mpFirstFrame;
     299         [ #  # ]:          0 :         if ( pFrame )
     300                 :            :         {
     301         [ #  # ]:          0 :             if ( pFrame->ImplGetGraphics() )
     302                 :            :                 // MT: Stupid typecast here and somewhere ((OutputDevice*)&aVDev)->, because bug in .NET2002 compiler.
     303                 :          0 :                 ((OutputDevice*)pFrame)->mpGraphics->GetDevFontList( pFrame->mpWindowImpl->mpFrameData->mpFontList );
     304                 :            :         }
     305                 :            :     }
     306                 :          0 : }
     307                 :            : 
     308                 :            : // =======================================================================
     309                 :            : 
     310                 :            : 
     311                 :            : // =======================================================================
     312                 :            : 
     313                 :            : // TODO: remove this method when the CWS-gfbfcfg dust has settled
     314                 :        158 : void ImplFreeOutDevFontData()
     315                 :        158 : {}
     316                 :            : 
     317                 :            : // =======================================================================
     318                 :            : 
     319                 :        158 : void OutputDevice::BeginFontSubstitution()
     320                 :            : {
     321                 :        158 :     ImplSVData* pSVData = ImplGetSVData();
     322                 :        158 :     pSVData->maGDIData.mbFontSubChanged = sal_False;
     323                 :        158 : }
     324                 :            : 
     325                 :            : // -----------------------------------------------------------------------
     326                 :            : 
     327                 :        158 : void OutputDevice::EndFontSubstitution()
     328                 :            : {
     329                 :        158 :     ImplSVData* pSVData = ImplGetSVData();
     330         [ -  + ]:        158 :     if ( pSVData->maGDIData.mbFontSubChanged )
     331                 :            :     {
     332         [ #  # ]:          0 :         ImplUpdateAllFontData( false );
     333                 :            : 
     334         [ #  # ]:          0 :         Application* pApp = GetpApp();
     335         [ #  # ]:          0 :         DataChangedEvent aDCEvt( DATACHANGED_FONTSUBSTITUTION );
     336         [ #  # ]:          0 :         pApp->DataChanged( aDCEvt );
     337         [ #  # ]:          0 :         pApp->NotifyAllWindows( aDCEvt );
     338                 :          0 :         pSVData->maGDIData.mbFontSubChanged = sal_False;
     339                 :            :     }
     340                 :        158 : }
     341                 :            : 
     342                 :            : // -----------------------------------------------------------------------
     343                 :            : 
     344                 :          0 : void OutputDevice::AddFontSubstitute( const XubString& rFontName,
     345                 :            :                                       const XubString& rReplaceFontName,
     346                 :            :                                       sal_uInt16 nFlags )
     347                 :            : {
     348                 :          0 :     ImplDirectFontSubstitution*& rpSubst = ImplGetSVData()->maGDIData.mpDirectFontSubst;
     349         [ #  # ]:          0 :     if( !rpSubst )
     350         [ #  # ]:          0 :         rpSubst = new ImplDirectFontSubstitution();
     351                 :          0 :     rpSubst->AddFontSubstitute( rFontName, rReplaceFontName, nFlags );
     352                 :          0 :     ImplGetSVData()->maGDIData.mbFontSubChanged = sal_True;
     353                 :          0 : }
     354                 :            : 
     355                 :            : // -----------------------------------------------------------------------
     356                 :            : 
     357                 :          0 : void ImplDirectFontSubstitution::AddFontSubstitute( const String& rFontName,
     358                 :            :     const String& rSubstFontName, sal_uInt16 nFlags )
     359                 :            : {
     360         [ #  # ]:          0 :     maFontSubstList.push_back( ImplFontSubstEntry( rFontName, rSubstFontName, nFlags ) );
     361                 :          0 : }
     362                 :            : 
     363                 :            : // -----------------------------------------------------------------------
     364                 :            : 
     365                 :          0 : ImplFontSubstEntry::ImplFontSubstEntry( const String& rFontName,
     366                 :            :     const String& rSubstFontName, sal_uInt16 nSubstFlags )
     367                 :            : :   maName( rFontName )
     368                 :            : ,   maReplaceName( rSubstFontName )
     369 [ #  # ][ #  # ]:          0 : ,   mnFlags( nSubstFlags )
                 [ #  # ]
     370                 :            : {
     371         [ #  # ]:          0 :     maSearchName        = rFontName;
     372         [ #  # ]:          0 :     maSearchReplaceName = rSubstFontName;
     373         [ #  # ]:          0 :     GetEnglishSearchFontName( maSearchName );
     374         [ #  # ]:          0 :     GetEnglishSearchFontName( maSearchReplaceName );
     375                 :          0 : }
     376                 :            : 
     377                 :            : // -----------------------------------------------------------------------
     378                 :            : 
     379                 :          0 : void OutputDevice::ImplAddDevFontSubstitute( const XubString& rFontName,
     380                 :            :                                              const XubString& rReplaceFontName,
     381                 :            :                                              sal_uInt16 nFlags )
     382                 :            : {
     383                 :          0 :     ImplInitOutDevData();
     384                 :          0 :     mpOutDevData->maDevFontSubst.AddFontSubstitute( rFontName, rReplaceFontName, nFlags );
     385                 :          0 : }
     386                 :            : 
     387                 :            : // -----------------------------------------------------------------------
     388                 :            : 
     389                 :          0 : void OutputDevice::RemoveFontSubstitute( sal_uInt16 n )
     390                 :            : {
     391                 :          0 :     ImplDirectFontSubstitution* pSubst = ImplGetSVData()->maGDIData.mpDirectFontSubst;
     392         [ #  # ]:          0 :     if( pSubst )
     393                 :          0 :         pSubst->RemoveFontSubstitute( n );
     394                 :          0 : }
     395                 :            : 
     396                 :            : // -----------------------------------------------------------------------
     397                 :            : 
     398                 :          0 : void ImplDirectFontSubstitution::RemoveFontSubstitute( int nIndex )
     399                 :            : {
     400                 :          0 :     FontSubstList::iterator it = maFontSubstList.begin();
     401 [ #  # ][ #  # ]:          0 :     for( int nCount = 0; (it != maFontSubstList.end()) && (nCount++ != nIndex); ++it ) ;
         [ #  # ][ #  # ]
     402         [ #  # ]:          0 :     if( it != maFontSubstList.end() )
     403         [ #  # ]:          0 :         maFontSubstList.erase( it );
     404                 :          0 : }
     405                 :            : 
     406                 :            : // -----------------------------------------------------------------------
     407                 :            : 
     408                 :        158 : sal_uInt16 OutputDevice::GetFontSubstituteCount()
     409                 :            : {
     410                 :        158 :     const ImplDirectFontSubstitution* pSubst = ImplGetSVData()->maGDIData.mpDirectFontSubst;
     411         [ +  - ]:        158 :     if( !pSubst )
     412                 :        158 :     return 0;
     413                 :          0 :     int nCount =  pSubst->GetFontSubstituteCount();
     414                 :        158 :     return (sal_uInt16)nCount;
     415                 :            : }
     416                 :            : 
     417                 :            : // -----------------------------------------------------------------------
     418                 :            : 
     419                 :      49768 : bool ImplDirectFontSubstitution::FindFontSubstitute( String& rSubstName,
     420                 :            :     const String& rSearchName, sal_uInt16 nFlags ) const
     421                 :            : {
     422                 :            :     // TODO: get rid of O(N) searches
     423                 :      49768 :     FontSubstList::const_iterator it = maFontSubstList.begin();
     424         [ -  + ]:      49768 :     for(; it != maFontSubstList.end(); ++it )
     425                 :            :     {
     426                 :          0 :         const ImplFontSubstEntry& rEntry = *it;
     427 [ #  # ][ #  # ]:          0 :         if( ((rEntry.mnFlags & nFlags) || !nFlags)
         [ #  # ][ #  # ]
     428         [ #  # ]:          0 :         &&   (rEntry.maSearchName == rSearchName) )
     429                 :            :         {
     430         [ #  # ]:          0 :             rSubstName = rEntry.maSearchReplaceName;
     431                 :          0 :             return true;
     432                 :            :         }
     433                 :            :     }
     434                 :            : 
     435                 :      49768 :     return false;
     436                 :            : }
     437                 :            : 
     438                 :            : // -----------------------------------------------------------------------
     439                 :            : 
     440                 :     184643 : static void ImplFontSubstitute( String& rFontName,
     441                 :            :     sal_uInt16 nFlags, ImplDirectFontSubstitution* pDevSpecific )
     442                 :            : {
     443                 :            : #ifdef DBG_UTIL
     444                 :            :     String aTempName = rFontName;
     445                 :            :     GetEnglishSearchFontName( aTempName );
     446                 :            :     DBG_ASSERT( aTempName == rFontName, "ImplFontSubstitute() called without a searchname" );
     447                 :            : #endif
     448                 :            : 
     449         [ +  - ]:     184643 :     String aSubstFontName;
     450                 :            : 
     451                 :            :     // apply user-configurable font replacement (eg, from the list in Tools->Options)
     452         [ +  - ]:     184643 :     const ImplDirectFontSubstitution* pSubst = ImplGetSVData()->maGDIData.mpDirectFontSubst;
     453 [ -  + ][ #  # ]:     184643 :     if( pSubst && pSubst->FindFontSubstitute( aSubstFontName, rFontName, FONT_SUBSTITUTE_ALWAYS ) )
         [ #  # ][ -  + ]
     454                 :            :     {
     455         [ #  # ]:          0 :         rFontName = aSubstFontName;
     456                 :            :         return;
     457                 :            :     }
     458                 :            : 
     459                 :            :     // apply device specific font replacement (e.g. to use printer builtin fonts)
     460         [ +  + ]:     184643 :     if( !pDevSpecific )
     461                 :            :         return;
     462                 :            : 
     463 [ +  - ][ -  + ]:      49768 :     if( pDevSpecific->FindFontSubstitute( aSubstFontName, rFontName, nFlags ) )
     464                 :            :     {
     465         [ #  # ]:      49768 :         rFontName = aSubstFontName;
     466                 :            :         return;
     467 [ +  - ][ +  + ]:     184643 :     }
     468                 :            : }
     469                 :            : 
     470                 :            : // -----------------------------------------------------------------------
     471                 :            : 
     472                 :      97781 : Font OutputDevice::GetDefaultFont( sal_uInt16 nType, LanguageType eLang,
     473                 :            :                                    sal_uLong nFlags, const OutputDevice* pOutDev )
     474                 :            : {
     475                 :            :     OSL_TRACE( "OutputDevice::GetDefaultFont()" );
     476                 :            : 
     477                 :      97781 :     com::sun::star::lang::Locale aLocale;
     478 [ +  + ][ -  + ]:      97781 :     if( eLang == LANGUAGE_NONE || eLang == LANGUAGE_SYSTEM || eLang == LANGUAGE_DONTKNOW )
                 [ +  + ]
     479                 :            :     {
     480 [ +  - ][ +  - ]:        738 :         aLocale = Application::GetSettings().GetUILocale();
     481                 :            :     }
     482                 :            :     else
     483                 :            :     {
     484         [ +  - ]:      97043 :         MsLangId::convertLanguageToLocale( eLang, aLocale );
     485                 :            :     }
     486                 :            : 
     487         [ +  - ]:      97781 :     utl::DefaultFontConfiguration& rDefaults = utl::DefaultFontConfiguration::get();
     488 [ +  - ][ +  - ]:      97781 :     String aSearch = rDefaults.getUserInterfaceFont( aLocale ); // ensure a fallback
     489 [ +  - ][ +  - ]:      97781 :     String aDefault = rDefaults.getDefaultFont( aLocale, nType );
     490         [ +  + ]:      97781 :     if( aDefault.Len() )
     491         [ +  - ]:      93209 :         aSearch = aDefault;
     492                 :            : 
     493                 :      97781 :     int nDefaultHeight = 12;
     494                 :            : 
     495         [ +  - ]:      97781 :     Font aFont;
     496         [ +  - ]:      97781 :     aFont.SetPitch( PITCH_VARIABLE );
     497                 :            : 
     498   [ -  +  +  +  :      97781 :     switch ( nType )
             -  +  +  - ]
     499                 :            :     {
     500                 :            :         case DEFAULTFONT_SANS_UNICODE:
     501                 :            :         case DEFAULTFONT_UI_SANS:
     502         [ #  # ]:          0 :             aFont.SetFamily( FAMILY_SWISS );
     503                 :          0 :             break;
     504                 :            : 
     505                 :            :         case DEFAULTFONT_SANS:
     506                 :            :         case DEFAULTFONT_LATIN_HEADING:
     507                 :            :         case DEFAULTFONT_LATIN_SPREADSHEET:
     508                 :            :         case DEFAULTFONT_LATIN_DISPLAY:
     509         [ +  - ]:       4483 :             aFont.SetFamily( FAMILY_SWISS );
     510                 :       4483 :             break;
     511                 :            : 
     512                 :            :         case DEFAULTFONT_SERIF:
     513                 :            :         case DEFAULTFONT_LATIN_TEXT:
     514                 :            :         case DEFAULTFONT_LATIN_PRESENTATION:
     515         [ +  - ]:      28623 :             aFont.SetFamily( FAMILY_ROMAN );
     516                 :      28623 :             break;
     517                 :            : 
     518                 :            :         case DEFAULTFONT_FIXED:
     519                 :            :         case DEFAULTFONT_LATIN_FIXED:
     520                 :            :         case DEFAULTFONT_UI_FIXED:
     521         [ +  - ]:        579 :             aFont.SetPitch( PITCH_FIXED );
     522         [ +  - ]:        579 :             aFont.SetFamily( FAMILY_MODERN );
     523                 :        579 :             break;
     524                 :            : 
     525                 :            :         case DEFAULTFONT_SYMBOL:
     526         [ #  # ]:          0 :             aFont.SetCharSet( RTL_TEXTENCODING_SYMBOL );
     527                 :          0 :             break;
     528                 :            : 
     529                 :            :         case DEFAULTFONT_CJK_TEXT:
     530                 :            :         case DEFAULTFONT_CJK_PRESENTATION:
     531                 :            :         case DEFAULTFONT_CJK_SPREADSHEET:
     532                 :            :         case DEFAULTFONT_CJK_HEADING:
     533                 :            :         case DEFAULTFONT_CJK_DISPLAY:
     534         [ +  - ]:      32048 :             aFont.SetFamily( FAMILY_SYSTEM );   // don't care, but don't use font subst config later...
     535                 :      32048 :             break;
     536                 :            : 
     537                 :            :         case DEFAULTFONT_CTL_TEXT:
     538                 :            :         case DEFAULTFONT_CTL_PRESENTATION:
     539                 :            :         case DEFAULTFONT_CTL_SPREADSHEET:
     540                 :            :         case DEFAULTFONT_CTL_HEADING:
     541                 :            :         case DEFAULTFONT_CTL_DISPLAY:
     542         [ +  - ]:      32048 :             aFont.SetFamily( FAMILY_SYSTEM );   // don't care, but don't use font subst config later...
     543                 :      32048 :             break;
     544                 :            :     }
     545                 :            : 
     546         [ +  - ]:      97781 :     if ( aSearch.Len() )
     547                 :            :     {
     548         [ +  - ]:      97781 :         aFont.SetHeight( nDefaultHeight );
     549         [ +  - ]:      97781 :         aFont.SetWeight( WEIGHT_NORMAL );
     550         [ +  - ]:      97781 :         aFont.SetLanguage( eLang );
     551                 :            : 
     552 [ +  - ][ +  - ]:      97781 :         if ( aFont.GetCharSet() == RTL_TEXTENCODING_DONTKNOW )
     553 [ +  - ][ +  - ]:      97781 :             aFont.SetCharSet( osl_getThreadTextEncoding() );
     554                 :            : 
     555                 :            :         // Should we only return available fonts on the given device
     556         [ -  + ]:      97781 :         if ( pOutDev )
     557                 :            :         {
     558         [ #  # ]:          0 :             pOutDev->ImplInitFontList();
     559                 :            : 
     560                 :            :             // Search Font in the FontList
     561         [ #  # ]:          0 :             String      aName;
     562         [ #  # ]:          0 :             String      aSearchName;
     563                 :          0 :             xub_StrLen  nIndex = 0;
     564         [ #  # ]:          0 :             do
     565                 :            :             {
     566 [ #  # ][ #  # ]:          0 :                 aSearchName = GetNextFontToken( aSearch, nIndex );
                 [ #  # ]
     567         [ #  # ]:          0 :                 GetEnglishSearchFontName( aSearchName );
     568         [ #  # ]:          0 :                 ImplDevFontListData* pFontFamily = pOutDev->mpFontList->ImplFindBySearchName( aSearchName );
     569         [ #  # ]:          0 :                 if( pFontFamily )
     570                 :            :                 {
     571         [ #  # ]:          0 :                     AddTokenFontName( aName, pFontFamily->GetFamilyName() );
     572         [ #  # ]:          0 :                     if( nFlags & DEFAULTFONT_FLAGS_ONLYONE )
     573                 :          0 :                         break;
     574                 :            :                 }
     575                 :            :             }
     576                 :            :             while ( nIndex != STRING_NOTFOUND );
     577 [ #  # ][ #  # ]:          0 :             aFont.SetName( aName );
         [ #  # ][ #  # ]
     578                 :            :         }
     579                 :            : 
     580                 :            :         // No Name, than set all names
     581 [ +  - ][ +  - ]:      97781 :         if ( !aFont.GetName().Len() )
     582                 :            :         {
     583         [ +  + ]:      97781 :             if ( nFlags & DEFAULTFONT_FLAGS_ONLYONE )
     584                 :            :             {
     585                 :            : 
     586         [ +  - ]:      97309 :                 if( !pOutDev )
     587         [ +  - ]:      97309 :                     pOutDev = (const OutputDevice *)ImplGetSVData()->mpDefaultWin;
     588         [ +  + ]:      97309 :                 if( !pOutDev )
     589                 :            :                 {
     590                 :        735 :                     xub_StrLen nIndex = 0;
     591 [ +  - ][ +  - ]:        735 :                     aFont.SetName( aSearch.GetToken( 0, ';', nIndex ) );
         [ +  - ][ +  - ]
     592                 :            :                 }
     593                 :            :                 else
     594                 :            :                 {
     595         [ +  - ]:      96574 :                     pOutDev->ImplInitFontList();
     596                 :            : 
     597 [ +  - ][ +  - ]:      96574 :                     aFont.SetName( aSearch );
     598                 :            : 
     599                 :            :                     // convert to pixel height
     600 [ +  - ][ +  - ]:      96574 :                     Size aSize = pOutDev->ImplLogicToDevicePixel( aFont.GetSize() );
     601         [ -  + ]:      96574 :                     if ( !aSize.Height() )
     602                 :            :                     {
     603                 :            :                         // use default pixel height only when logical height is zero
     604 [ #  # ][ #  # ]:          0 :                         if ( aFont.GetHeight() )
     605                 :          0 :                             aSize.Height() = 1;
     606                 :            :                         else
     607                 :          0 :                             aSize.Height() = (12*pOutDev->mnDPIY)/72;
     608                 :            :                     }
     609                 :            : 
     610                 :            :                     // use default width only when logical width is zero
     611 [ +  - ][ +  - ]:      96574 :                     if( (0 == aSize.Width()) && (0 != aFont.GetSize().Width()) )
         [ -  + ][ -  + ]
     612                 :          0 :                         aSize.Width() = 1;
     613                 :            : 
     614                 :            :                     // get the name of the first available font
     615                 :      96574 :                     float fExactHeight = static_cast<float>(aSize.Height());
     616 [ +  - ][ -  + ]:      96574 :                     ImplFontEntry* pEntry = pOutDev->mpFontCache->GetFontEntry( pOutDev->mpFontList, aFont, aSize, fExactHeight, pOutDev->mpOutDevData ? &pOutDev->mpOutDevData->maDevFontSubst : NULL );
     617         [ +  - ]:      96574 :                     if (pEntry)
     618                 :            :                     {
     619         [ +  - ]:      96574 :                         if( pEntry->maFontSelData.mpFontData )
     620 [ +  - ][ +  - ]:      96574 :                             aFont.SetName( pEntry->maFontSelData.mpFontData->maName );
     621                 :            :                         else
     622 [ #  # ][ #  # ]:      96574 :                             aFont.SetName( pEntry->maFontSelData.maTargetName );
     623                 :            :                     }
     624                 :            :                 }
     625                 :            :             }
     626                 :            :             else
     627 [ +  - ][ +  - ]:        472 :                 aFont.SetName( aSearch );
     628                 :            :         }
     629                 :            :     }
     630                 :            : 
     631                 :            : #if OSL_DEBUG_LEVEL > 2
     632                 :            :     const char* s = "DEFAULTFONT_SANS_UNKNOWN";
     633                 :            :     switch ( nType )
     634                 :            :     {
     635                 :            :     case DEFAULTFONT_SANS_UNICODE:  s = "DEFAULTFONT_SANS_UNICODE"; break;
     636                 :            :     case DEFAULTFONT_UI_SANS:   s = "DEFAULTFONT_UI_SANS"; break;
     637                 :            : 
     638                 :            :     case DEFAULTFONT_SANS:  s = "DEFAULTFONT_SANS"; break;
     639                 :            :     case DEFAULTFONT_LATIN_HEADING: s = "DEFAULTFONT_LATIN_HEADING"; break;
     640                 :            :     case DEFAULTFONT_LATIN_SPREADSHEET: s = "DEFAULTFONT_LATIN_SPREADSHEET"; break;
     641                 :            :     case DEFAULTFONT_LATIN_DISPLAY: s = "DEFAULTFONT_LATIN_DISPLAY"; break;
     642                 :            : 
     643                 :            :     case DEFAULTFONT_SERIF: s = "DEFAULTFONT_SERIF"; break;
     644                 :            :     case DEFAULTFONT_LATIN_TEXT:    s = "DEFAULTFONT_LATIN_TEXT"; break;
     645                 :            :     case DEFAULTFONT_LATIN_PRESENTATION:    s = "DEFAULTFONT_LATIN_PRESENTATION"; break;
     646                 :            : 
     647                 :            :     case DEFAULTFONT_FIXED: s = "DEFAULTFONT_FIXED"; break;
     648                 :            :     case DEFAULTFONT_LATIN_FIXED:   s = "DEFAULTFONT_LATIN_FIXED"; break;
     649                 :            :     case DEFAULTFONT_UI_FIXED:  s = "DEFAULTFONT_UI_FIXED"; break;
     650                 :            : 
     651                 :            :     case DEFAULTFONT_SYMBOL:    s = "DEFAULTFONT_SYMBOL"; break;
     652                 :            : 
     653                 :            :     case DEFAULTFONT_CJK_TEXT:  s = "DEFAULTFONT_CJK_TEXT"; break;
     654                 :            :     case DEFAULTFONT_CJK_PRESENTATION:  s = "DEFAULTFONT_CJK_PRESENTATION"; break;
     655                 :            :     case DEFAULTFONT_CJK_SPREADSHEET:   s = "DEFAULTFONT_CJK_SPREADSHEET"; break;
     656                 :            :     case DEFAULTFONT_CJK_HEADING:   s = "DEFAULTFONT_CJK_HEADING"; break;
     657                 :            :     case DEFAULTFONT_CJK_DISPLAY:   s = "DEFAULTFONT_CJK_DISPLAY"; break;
     658                 :            : 
     659                 :            :     case DEFAULTFONT_CTL_TEXT:  s = "DEFAULTFONT_CTL_TEXT"; break;
     660                 :            :     case DEFAULTFONT_CTL_PRESENTATION:  s = "DEFAULTFONT_CTL_PRESENTATION"; break;
     661                 :            :     case DEFAULTFONT_CTL_SPREADSHEET:   s = "DEFAULTFONT_CTL_SPREADSHEET"; break;
     662                 :            :     case DEFAULTFONT_CTL_HEADING:   s = "DEFAULTFONT_CTL_HEADING"; break;
     663                 :            :     case DEFAULTFONT_CTL_DISPLAY:   s = "DEFAULTFONT_CTL_DISPLAY"; break;
     664                 :            :     }
     665                 :            :     fprintf( stderr, "   OutputDevice::GetDefaultFont() Type=\"%s\" lang=%d flags=%ld FontName=\"%s\"\n",
     666                 :            :          s, eLang, nFlags,
     667                 :            :          OUStringToOString( aFont.GetName(), RTL_TEXTENCODING_UTF8 ).getStr()
     668                 :            :          );
     669                 :            : #endif
     670                 :            : 
     671 [ +  - ][ +  - ]:      97781 :     return aFont;
     672                 :            : }
     673                 :            : 
     674                 :            : // =======================================================================
     675                 :            : 
     676                 :          0 : static unsigned ImplIsCJKFont( const String& rFontName )
     677                 :            : {
     678                 :            :     // Test, if Fontname includes CJK characters --> In this case we
     679                 :            :     // mention that it is a CJK font
     680                 :          0 :     const sal_Unicode* pStr = rFontName.GetBuffer();
     681         [ #  # ]:          0 :     while ( *pStr )
     682                 :            :     {
     683                 :            :         // japanese
     684 [ #  # ][ #  # ]:          0 :         if ( ((*pStr >= 0x3040) && (*pStr <= 0x30FF)) ||
         [ #  # ][ #  # ]
     685                 :            :              ((*pStr >= 0x3190) && (*pStr <= 0x319F)) )
     686                 :          0 :             return IMPL_FONT_ATTR_CJK|IMPL_FONT_ATTR_CJK_JP;
     687                 :            : 
     688                 :            :         // korean
     689 [ #  # ][ #  # ]:          0 :         if ( ((*pStr >= 0xAC00) && (*pStr <= 0xD7AF)) ||
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     690                 :            :              ((*pStr >= 0x3130) && (*pStr <= 0x318F)) ||
     691                 :            :              ((*pStr >= 0x1100) && (*pStr <= 0x11FF)) )
     692                 :          0 :             return IMPL_FONT_ATTR_CJK|IMPL_FONT_ATTR_CJK_KR;
     693                 :            : 
     694                 :            :         // chinese
     695 [ #  # ][ #  # ]:          0 :         if ( ((*pStr >= 0x3400) && (*pStr <= 0x9FFF)) )
     696                 :          0 :             return IMPL_FONT_ATTR_CJK|IMPL_FONT_ATTR_CJK_TC|IMPL_FONT_ATTR_CJK_SC;
     697                 :            : 
     698                 :            :         // cjk
     699 [ #  # ][ #  # ]:          0 :         if ( ((*pStr >= 0x3000) && (*pStr <= 0xD7AF)) ||
         [ #  # ][ #  # ]
     700                 :            :              ((*pStr >= 0xFF00) && (*pStr <= 0xFFEE)) )
     701                 :          0 :             return IMPL_FONT_ATTR_CJK;
     702                 :            : 
     703                 :          0 :         pStr++;
     704                 :            :     }
     705                 :            : 
     706                 :          0 :     return 0;
     707                 :            : }
     708                 :            : 
     709                 :            : // -----------------------------------------------------------------------
     710                 :            : 
     711                 :          0 : static void ImplCalcType( sal_uLong& rType, FontWeight& rWeight, FontWidth& rWidth,
     712                 :            :                           FontFamily eFamily, const FontNameAttr* pFontAttr )
     713                 :            : {
     714         [ #  # ]:          0 :     if ( eFamily != FAMILY_DONTKNOW )
     715                 :            :     {
     716         [ #  # ]:          0 :         if ( eFamily == FAMILY_SWISS )
     717                 :          0 :             rType |= IMPL_FONT_ATTR_SANSSERIF;
     718         [ #  # ]:          0 :         else if ( eFamily == FAMILY_ROMAN )
     719                 :          0 :             rType |= IMPL_FONT_ATTR_SERIF;
     720         [ #  # ]:          0 :         else if ( eFamily == FAMILY_SCRIPT )
     721                 :          0 :             rType |= IMPL_FONT_ATTR_SCRIPT;
     722         [ #  # ]:          0 :         else if ( eFamily == FAMILY_MODERN )
     723                 :          0 :             rType |= IMPL_FONT_ATTR_FIXED;
     724         [ #  # ]:          0 :         else if ( eFamily == FAMILY_DECORATIVE )
     725                 :          0 :             rType |= IMPL_FONT_ATTR_DECORATIVE;
     726                 :            :     }
     727                 :            : 
     728         [ #  # ]:          0 :     if ( pFontAttr )
     729                 :            :     {
     730                 :          0 :         rType |= pFontAttr->Type;
     731                 :            : 
     732 [ #  # ][ #  # ]:          0 :         if ( ((rWeight == WEIGHT_DONTKNOW) || (rWeight == WEIGHT_NORMAL)) &&
                 [ #  # ]
     733                 :            :              (pFontAttr->Weight != WEIGHT_DONTKNOW) )
     734                 :          0 :             rWeight = pFontAttr->Weight;
     735 [ #  # ][ #  # ]:          0 :         if ( ((rWidth == WIDTH_DONTKNOW) || (rWidth == WIDTH_NORMAL)) &&
                 [ #  # ]
     736                 :            :              (pFontAttr->Width != WIDTH_DONTKNOW) )
     737                 :          0 :             rWidth = pFontAttr->Width;
     738                 :            :     }
     739                 :          0 : }
     740                 :            : 
     741                 :            : // =======================================================================
     742                 :            : 
     743                 :      58332 : PhysicalFontFace::PhysicalFontFace( const ImplDevFontAttributes& rDFA, int nMagic )
     744                 :            : :   ImplDevFontAttributes( rDFA ),
     745                 :            :     mnWidth(0),
     746                 :            :     mnHeight(0),
     747                 :            :     mnMagic( nMagic ),
     748                 :      58332 :     mpNext( NULL )
     749                 :            : {
     750                 :            :     // StarSymbol is a unicode font, but it still deserves the symbol flag
     751         [ +  + ]:      58332 :     if( !mbSymbolFlag )
     752 [ +  - ][ +  - ]:     114772 :         if( 0 == GetFamilyName().CompareIgnoreCaseToAscii( "starsymbol", 10)
         [ +  + ][ +  + ]
     753         [ +  - ]:      57386 :         ||  0 == GetFamilyName().CompareIgnoreCaseToAscii( "opensymbol", 10) )
     754                 :        272 :             mbSymbolFlag = true;
     755                 :      58332 : }
     756                 :            : 
     757                 :            : // -----------------------------------------------------------------------
     758                 :            : 
     759                 :     532044 : StringCompare PhysicalFontFace::CompareIgnoreSize( const PhysicalFontFace& rOther ) const
     760                 :            : {
     761                 :            :     // compare their width, weight, italic and style name
     762         [ -  + ]:     532044 :     if( meWidthType < rOther.meWidthType )
     763                 :          0 :         return COMPARE_LESS;
     764         [ -  + ]:     532044 :     else if( meWidthType > rOther.meWidthType )
     765                 :          0 :         return COMPARE_GREATER;
     766                 :            : 
     767         [ +  + ]:     532044 :     if( meWeight < rOther.meWeight )
     768                 :       7900 :         return COMPARE_LESS;
     769         [ +  + ]:     524144 :     else if( meWeight > rOther.meWeight )
     770                 :     294524 :         return COMPARE_GREATER;
     771                 :            : 
     772         [ +  + ]:     229620 :     if( meItalic < rOther.meItalic )
     773                 :       8750 :         return COMPARE_LESS;
     774         [ +  + ]:     220870 :     else if( meItalic > rOther.meItalic )
     775                 :     211264 :         return COMPARE_GREATER;
     776                 :            : 
     777                 :       9606 :     StringCompare eCompare = maName.CompareTo( rOther.maName );
     778                 :     532044 :     return eCompare;
     779                 :            : }
     780                 :            : 
     781                 :            : // -----------------------------------------------------------------------
     782                 :            : 
     783                 :     329436 : StringCompare PhysicalFontFace::CompareWithSize( const PhysicalFontFace& rOther ) const
     784                 :            : {
     785                 :     329436 :     StringCompare eCompare = CompareIgnoreSize( rOther );
     786         [ +  + ]:     329436 :     if( eCompare != COMPARE_EQUAL )
     787                 :     319830 :         return eCompare;
     788                 :            : 
     789         [ -  + ]:       9606 :     if( mnHeight < rOther.mnHeight )
     790                 :          0 :         return COMPARE_LESS;
     791         [ -  + ]:       9606 :     else if( mnHeight > rOther.mnHeight )
     792                 :          0 :         return COMPARE_GREATER;
     793                 :            : 
     794         [ -  + ]:       9606 :     if( mnWidth < rOther.mnWidth )
     795                 :          0 :         return COMPARE_LESS;
     796         [ -  + ]:       9606 :     else if( mnWidth > rOther.mnWidth )
     797                 :          0 :         return COMPARE_GREATER;
     798                 :            : 
     799                 :     329436 :     return COMPARE_EQUAL;
     800                 :            : }
     801                 :            : 
     802                 :            : // -----------------------------------------------------------------------
     803                 :            : 
     804                 :            : struct FontMatchStatus
     805                 :            : {
     806                 :            : public:
     807                 :            :     int                 mnFaceMatch;
     808                 :            :     int                 mnHeightMatch;
     809                 :            :     int                 mnWidthMatch;
     810                 :            :     const xub_Unicode*  mpTargetStyleName;
     811                 :            : };
     812                 :            : 
     813                 :      28452 : bool PhysicalFontFace::IsBetterMatch( const FontSelectPattern& rFSD, FontMatchStatus& rStatus ) const
     814                 :            : {
     815                 :      28452 :     int nMatch = 0;
     816                 :            : 
     817                 :      28452 :     const String& rFontName = rFSD.maTargetName;
     818 [ +  + ][ -  + ]:      28452 :     if( (rFontName == maName) || rFontName.EqualsIgnoreCaseAscii( maName ) )
                 [ +  + ]
     819                 :      13920 :         nMatch += 240000;
     820                 :            : 
     821   [ -  +  #  # ]:      28452 :     if( rStatus.mpTargetStyleName
                 [ -  + ]
     822                 :          0 :     &&  maStyleName.EqualsIgnoreCaseAscii( rStatus.mpTargetStyleName ) )
     823                 :          0 :         nMatch += 120000;
     824                 :            : 
     825 [ +  + ][ +  + ]:      28452 :     if( (rFSD.mePitch != PITCH_DONTKNOW) && (rFSD.mePitch == mePitch) )
     826                 :      17180 :         nMatch += 20000;
     827                 :            : 
     828                 :            :     // prefer NORMAL font width
     829                 :            :     // TODO: change when the upper layers can tell their width preference
     830         [ +  + ]:      28452 :     if( meWidthType == WIDTH_NORMAL )
     831                 :      28084 :         nMatch += 400;
     832 [ +  - ][ -  + ]:        368 :     else if( (meWidthType == WIDTH_SEMI_EXPANDED) || (meWidthType == WIDTH_SEMI_CONDENSED) )
     833                 :          0 :         nMatch += 300;
     834                 :            : 
     835         [ +  + ]:      28452 :     if( rFSD.meWeight != WEIGHT_DONTKNOW )
     836                 :            :     {
     837                 :            :         // if not bold or requiring emboldening prefer light fonts to bold fonts
     838         [ -  + ]:      28140 :         FontWeight ePatternWeight = rFSD.mbEmbolden ? WEIGHT_NORMAL : rFSD.meWeight;
     839                 :            : 
     840                 :      28140 :         int nReqWeight = (int)ePatternWeight;
     841         [ +  + ]:      28140 :         if ( ePatternWeight > WEIGHT_MEDIUM )
     842                 :       4632 :             nReqWeight += 100;
     843                 :            : 
     844                 :      28140 :         int nGivenWeight = (int)meWeight;
     845         [ +  + ]:      28140 :         if( meWeight > WEIGHT_MEDIUM )
     846                 :      14070 :             nGivenWeight += 100;
     847                 :            : 
     848                 :      28140 :         int nWeightDiff = nReqWeight - nGivenWeight;
     849                 :            : 
     850         [ +  + ]:      28140 :         if ( nWeightDiff == 0 )
     851                 :      14070 :             nMatch += 1000;
     852 [ +  - ][ -  + ]:      14070 :         else if ( nWeightDiff == +1 || nWeightDiff == -1 )
     853                 :          0 :             nMatch += 700;
     854 [ +  + ][ -  + ]:      14070 :         else if ( nWeightDiff < +50 && nWeightDiff > -50)
     855                 :      28140 :             nMatch += 200;
     856                 :            :     }
     857                 :            :     else // requested weight == WEIGHT_DONTKNOW
     858                 :            :     {
     859                 :            :         // prefer NORMAL font weight
     860                 :            :         // TODO: change when the upper layers can tell their weight preference
     861         [ +  + ]:        312 :         if( meWeight == WEIGHT_NORMAL )
     862                 :        156 :             nMatch += 450;
     863         [ -  + ]:        156 :         else if( meWeight == WEIGHT_MEDIUM )
     864                 :          0 :             nMatch += 350;
     865 [ +  - ][ -  + ]:        156 :         else if( (meWeight == WEIGHT_SEMILIGHT) || (meWeight == WEIGHT_SEMIBOLD) )
     866                 :          0 :             nMatch += 200;
     867         [ -  + ]:        156 :         else if( meWeight == WEIGHT_LIGHT )
     868                 :          0 :             nMatch += 150;
     869                 :            :     }
     870                 :            : 
     871                 :            :     // if requiring custom matrix to fake italic, prefer upright font
     872         [ -  + ]:      28452 :     FontItalic ePatternItalic = rFSD.maItalicMatrix != ItalicMatrix() ? ITALIC_NONE : rFSD.meItalic;
     873                 :            : 
     874         [ +  + ]:      28452 :     if ( ePatternItalic == ITALIC_NONE )
     875                 :            :     {
     876         [ +  + ]:      24852 :         if( meItalic == ITALIC_NONE )
     877                 :      12426 :             nMatch += 900;
     878                 :            :     }
     879                 :            :     else
     880                 :            :     {
     881         [ +  + ]:       3600 :         if( ePatternItalic == meItalic )
     882                 :       1780 :             nMatch += 900;
     883         [ +  + ]:       1820 :         else if( meItalic != ITALIC_NONE )
     884                 :         20 :             nMatch += 600;
     885                 :            :     }
     886                 :            : 
     887         [ -  + ]:      28452 :     if( mbDevice )
     888                 :          0 :         nMatch += 1;
     889                 :            : 
     890                 :      28452 :     int nHeightMatch = 0;
     891                 :      28452 :     int nWidthMatch = 0;
     892                 :            : 
     893         [ +  - ]:      28452 :     if( IsScalable() )
     894                 :            :     {
     895         [ +  + ]:      28452 :         if( rFSD.mnOrientation != 0 )
     896                 :       1016 :             nMatch += 80;
     897         [ +  + ]:      27436 :         else if( rFSD.mnWidth != 0 )
     898                 :       2552 :             nMatch += 25;
     899                 :            :         else
     900                 :      24884 :             nMatch += 5;
     901                 :            :     }
     902                 :            :     else
     903                 :            :     {
     904         [ #  # ]:          0 :         if( rFSD.mnHeight == mnHeight )
     905                 :            :         {
     906                 :          0 :             nMatch += 20;
     907         [ #  # ]:          0 :             if( rFSD.mnWidth == mnWidth )
     908                 :          0 :                 nMatch += 10;
     909                 :            :         }
     910                 :            :         else
     911                 :            :         {
     912                 :            :             // for non-scalable fonts the size difference is very important
     913                 :            :             // prefer the smaller font face because of clipping/overlapping issues
     914                 :          0 :             int nHeightDiff = (rFSD.mnHeight - mnHeight) * 1000;
     915         [ #  # ]:          0 :             nHeightMatch = (nHeightDiff >= 0) ? -nHeightDiff : 100+nHeightDiff;
     916         [ #  # ]:          0 :             if( rFSD.mnHeight )
     917                 :          0 :                 nHeightMatch /= rFSD.mnHeight;
     918                 :            : 
     919 [ #  # ][ #  # ]:          0 :             if( (rFSD.mnWidth != 0) && (mnWidth != 0) && (rFSD.mnWidth != mnWidth) )
                 [ #  # ]
     920                 :            :             {
     921                 :          0 :                 int nWidthDiff = (rFSD.mnWidth - mnWidth) * 100;
     922                 :          0 :                 nWidthMatch = (nWidthDiff >= 0) ? -nWidthDiff : +nWidthDiff;
     923                 :            :             }
     924                 :            :         }
     925                 :            :     }
     926                 :            : 
     927         [ +  + ]:      28452 :     if( rStatus.mnFaceMatch > nMatch )
     928                 :      18807 :         return false;
     929         [ +  - ]:       9645 :     else if( rStatus.mnFaceMatch < nMatch )
     930                 :            :     {
     931                 :       9645 :         rStatus.mnFaceMatch      = nMatch;
     932                 :       9645 :         rStatus.mnHeightMatch    = nHeightMatch;
     933                 :       9645 :         rStatus.mnWidthMatch     = nWidthMatch;
     934                 :       9645 :         return true;
     935                 :            :     }
     936                 :            : 
     937                 :            :     // when two fonts are still competing prefer the
     938                 :            :     // one with the best matching height
     939         [ #  # ]:          0 :     if( rStatus.mnHeightMatch > nHeightMatch )
     940                 :          0 :         return false;
     941         [ #  # ]:          0 :     else if( rStatus.mnHeightMatch < nHeightMatch )
     942                 :            :     {
     943                 :          0 :         rStatus.mnHeightMatch    = nHeightMatch;
     944                 :          0 :         rStatus.mnWidthMatch     = nWidthMatch;
     945                 :          0 :         return true;
     946                 :            :     }
     947                 :            : 
     948         [ #  # ]:          0 :     if( rStatus.mnWidthMatch > nWidthMatch )
     949                 :          0 :         return false;
     950                 :            : 
     951                 :          0 :     rStatus.mnWidthMatch = nWidthMatch;
     952                 :      28452 :     return true;
     953                 :            : }
     954                 :            : 
     955                 :            : // =======================================================================
     956                 :            : 
     957                 :       9000 : ImplFontEntry::ImplFontEntry( const FontSelectPattern& rFontSelData )
     958                 :            : :   maFontSelData( rFontSelData ),
     959                 :            :     maMetric( rFontSelData ),
     960                 :            :     mpConversion( NULL ),
     961                 :            :     mnRefCount( 1 ),
     962                 :            :     mnSetFontFlags( 0 ),
     963                 :            :     mnOwnOrientation( 0 ),
     964                 :            :     mnOrientation( 0 ),
     965                 :            :     mbInit( false ),
     966         [ +  - ]:       9000 :     mpUnicodeFallbackList( NULL )
     967                 :            : {
     968                 :       9000 :     maFontSelData.mpFontEntry = this;
     969                 :       9000 : }
     970                 :            : 
     971                 :            : // -----------------------------------------------------------------------
     972                 :            : 
     973         [ +  - ]:       6931 : ImplFontEntry::~ImplFontEntry()
     974                 :            : {
     975 [ +  + ][ +  - ]:       6931 :     delete mpUnicodeFallbackList;
     976         [ -  + ]:       6931 : }
     977                 :            : 
     978                 :            : // -----------------------------------------------------------------------
     979                 :            : 
     980                 :      13170 : size_t ImplFontEntry::GFBCacheKey_Hash::operator()( const GFBCacheKey& rData ) const
     981                 :            : {
     982                 :            :     boost::hash<sal_UCS4> a;
     983                 :            :     boost::hash<int > b;
     984                 :      13170 :     return a(rData.first) ^ b(rData.second);
     985                 :            : }
     986                 :            : 
     987                 :       1062 : inline void ImplFontEntry::AddFallbackForUnicode( sal_UCS4 cChar, FontWeight eWeight, const String& rFontName )
     988                 :            : {
     989         [ +  + ]:       1062 :     if( !mpUnicodeFallbackList )
     990 [ +  - ][ +  - ]:        558 :         mpUnicodeFallbackList = new UnicodeFallbackList;
     991 [ +  - ][ +  - ]:       1062 :     (*mpUnicodeFallbackList)[ GFBCacheKey(cChar,eWeight) ] = rFontName;
     992                 :       1062 : }
     993                 :            : 
     994                 :            : // -----------------------------------------------------------------------
     995                 :            : 
     996                 :      13224 : inline bool ImplFontEntry::GetFallbackForUnicode( sal_UCS4 cChar, FontWeight eWeight, String* pFontName ) const
     997                 :            : {
     998         [ +  + ]:      13224 :     if( !mpUnicodeFallbackList )
     999                 :       1116 :         return false;
    1000                 :            : 
    1001 [ +  - ][ +  - ]:      12108 :     UnicodeFallbackList::const_iterator it = mpUnicodeFallbackList->find( GFBCacheKey(cChar,eWeight) );
    1002 [ +  + ][ +  - ]:      12108 :     if( it == mpUnicodeFallbackList->end() )
    1003                 :       3516 :         return false;
    1004                 :            : 
    1005 [ +  - ][ +  - ]:       8592 :     *pFontName = (*it).second;
    1006                 :      13224 :     return true;
    1007                 :            : }
    1008                 :            : 
    1009                 :            : // -----------------------------------------------------------------------
    1010                 :            : 
    1011                 :          0 : inline void ImplFontEntry::IgnoreFallbackForUnicode( sal_UCS4 cChar, FontWeight eWeight, const String& rFontName )
    1012                 :            : {
    1013                 :            : //  DBG_ASSERT( mpUnicodeFallbackList, "ImplFontEntry::IgnoreFallbackForUnicode no list" );
    1014 [ #  # ][ #  # ]:          0 :     UnicodeFallbackList::iterator it = mpUnicodeFallbackList->find( GFBCacheKey(cChar,eWeight) );
    1015                 :            : //  DBG_ASSERT( it != mpUnicodeFallbackList->end(), "ImplFontEntry::IgnoreFallbackForUnicode no match" );
    1016 [ #  # ][ #  # ]:          0 :     if( it == mpUnicodeFallbackList->end() )
    1017                 :          0 :         return;
    1018 [ #  # ][ #  # ]:          0 :     if( (*it).second == rFontName )
                 [ #  # ]
    1019         [ #  # ]:          0 :         mpUnicodeFallbackList->erase( it );
    1020                 :            : }
    1021                 :            : 
    1022                 :            : // =======================================================================
    1023                 :            : 
    1024                 :     131426 : ImplDevFontListData::ImplDevFontListData( const String& rSearchName )
    1025                 :            : :   mpFirst( NULL ),
    1026                 :            :     maSearchName( rSearchName ),
    1027                 :            :     mnTypeFaces( 0 ),
    1028                 :            :     mnMatchType( 0 ),
    1029                 :            :     meMatchWeight( WEIGHT_DONTKNOW ),
    1030                 :            :     meMatchWidth( WIDTH_DONTKNOW ),
    1031                 :            :     meFamily( FAMILY_DONTKNOW ),
    1032                 :            :     mePitch( PITCH_DONTKNOW ),
    1033 [ +  - ][ +  - ]:     131426 :     mnMinQuality( -1 )
                 [ +  - ]
    1034                 :     131426 : {}
    1035                 :            : 
    1036                 :            : // -----------------------------------------------------------------------
    1037                 :            : 
    1038 [ +  - ][ +  - ]:     120554 : ImplDevFontListData::~ImplDevFontListData()
                 [ +  - ]
    1039                 :            : {
    1040                 :            :     // release all physical font faces
    1041         [ +  + ]:     389614 :     while( mpFirst )
    1042                 :            :     {
    1043                 :     269060 :         PhysicalFontFace* pFace = mpFirst;
    1044                 :     269060 :         mpFirst = pFace->GetNextFace();
    1045 [ +  - ][ +  - ]:     269060 :         delete pFace;
    1046                 :            :     }
    1047                 :     120554 : }
    1048                 :            : 
    1049                 :            : // -----------------------------------------------------------------------
    1050                 :            : 
    1051                 :     301740 : bool ImplDevFontListData::AddFontFace( PhysicalFontFace* pNewData )
    1052                 :            : {
    1053                 :     301740 :     pNewData->mpNext = NULL;
    1054                 :            : 
    1055         [ +  + ]:     301740 :     if( !mpFirst )
    1056                 :            :     {
    1057                 :     131426 :         maName         = pNewData->maName;
    1058                 :     131426 :         maMapNames     = pNewData->maMapNames;
    1059                 :     131426 :         meFamily       = pNewData->meFamily;
    1060                 :     131426 :         mePitch        = pNewData->mePitch;
    1061                 :     131426 :         mnMinQuality   = pNewData->mnQuality;
    1062                 :            :     }
    1063                 :            :     else
    1064                 :            :     {
    1065         [ +  + ]:     170314 :         if( meFamily == FAMILY_DONTKNOW )
    1066                 :     168604 :             meFamily = pNewData->meFamily;
    1067         [ -  + ]:     170314 :         if( mePitch == PITCH_DONTKNOW )
    1068                 :          0 :             mePitch = pNewData->mePitch;
    1069         [ +  + ]:     170314 :         if( mnMinQuality > pNewData->mnQuality )
    1070                 :      67489 :             mnMinQuality = pNewData->mnQuality;
    1071                 :            :     }
    1072                 :            : 
    1073                 :            :     // set attributes for attribute based font matching
    1074         [ +  - ]:     301740 :     if( pNewData->IsScalable() )
    1075                 :     301740 :         mnTypeFaces |= IMPL_DEVFONT_SCALABLE;
    1076                 :            : 
    1077         [ +  + ]:     301740 :     if( pNewData->IsSymbolFont() )
    1078                 :       6315 :         mnTypeFaces |= IMPL_DEVFONT_SYMBOL;
    1079                 :            :     else
    1080                 :     295425 :         mnTypeFaces |= IMPL_DEVFONT_NONESYMBOL;
    1081                 :            : 
    1082         [ +  - ]:     301740 :     if( pNewData->meWeight != WEIGHT_DONTKNOW )
    1083                 :            :     {
    1084         [ +  + ]:     301740 :         if( pNewData->meWeight >= WEIGHT_SEMIBOLD )
    1085                 :     117691 :             mnTypeFaces |= IMPL_DEVFONT_BOLD;
    1086         [ +  + ]:     184049 :         else if( pNewData->meWeight <= WEIGHT_SEMILIGHT )
    1087                 :      17164 :             mnTypeFaces |= IMPL_DEVFONT_LIGHT;
    1088                 :            :         else
    1089                 :     166885 :             mnTypeFaces |= IMPL_DEVFONT_NORMAL;
    1090                 :            :     }
    1091                 :            : 
    1092         [ +  + ]:     301740 :     if( pNewData->meItalic == ITALIC_NONE )
    1093                 :     194718 :         mnTypeFaces |= IMPL_DEVFONT_NONEITALIC;
    1094 [ +  + ][ +  - ]:     107022 :     else if( (pNewData->meItalic == ITALIC_NORMAL)
    1095                 :            :          ||  (pNewData->meItalic == ITALIC_OBLIQUE) )
    1096                 :     107022 :         mnTypeFaces |= IMPL_DEVFONT_ITALIC;
    1097                 :            : 
    1098 [ -  + ][ #  # ]:     301740 :     if( (meMatchWeight == WEIGHT_DONTKNOW)
    1099                 :            :     ||  (meMatchWidth  == WIDTH_DONTKNOW)
    1100                 :            :     ||  (mnMatchType   == 0) )
    1101                 :            :     {
    1102                 :            :         // TODO: is it cheaper to calc matching attributes now or on demand?
    1103                 :            :         // calc matching attributes if other entries are already initialized
    1104                 :            : 
    1105                 :            :         // MT: Perform05: Do lazy, quite expensive, not needed in start-up!
    1106                 :            :         // const FontSubstConfiguration& rFontSubst = *FontSubstConfiguration::get();
    1107                 :            :         // InitMatchData( rFontSubst, maSearchName );
    1108                 :            :         // mbMatchData=true; // Somewhere else???
    1109                 :            :     }
    1110                 :            : 
    1111                 :            :     // reassign name (sharing saves memory)
    1112         [ +  - ]:     301740 :     if( pNewData->maName == maName )
    1113                 :     301740 :         pNewData->maName = maName;
    1114                 :            : 
    1115                 :            :     // insert new physical font face into linked list
    1116                 :            :     // TODO: get rid of linear search?
    1117                 :            :     PhysicalFontFace* pData;
    1118                 :     301740 :     PhysicalFontFace** ppHere = &mpFirst;
    1119         [ +  + ]:     604920 :     for(; (pData=*ppHere) != NULL; ppHere=&pData->mpNext )
    1120                 :            :     {
    1121                 :     329436 :         StringCompare eComp = pNewData->CompareWithSize( *pData );
    1122         [ +  + ]:     329436 :         if( eComp == COMPARE_GREATER )
    1123                 :     303180 :             continue;
    1124         [ +  + ]:      26256 :         if( eComp == COMPARE_LESS )
    1125                 :      16650 :             break;
    1126                 :            : 
    1127                 :            :         // ignore duplicate if its quality is worse
    1128         [ +  + ]:       9606 :         if( pNewData->mnQuality < pData->mnQuality )
    1129                 :       5562 :             return false;
    1130                 :            : 
    1131                 :            :         // keep the device font if its quality is good enough
    1132 [ +  - ][ +  - ]:       4044 :         if( (pNewData->mnQuality == pData->mnQuality)
                 [ +  - ]
    1133                 :       4044 :         &&  (pData->mbDevice || !pNewData->mbDevice) )
    1134                 :       4044 :             return false;
    1135                 :            : 
    1136                 :            :         // replace existing font face with a better one
    1137                 :          0 :         pNewData->mpNext = pData->mpNext;
    1138                 :          0 :         *ppHere = pNewData;
    1139         [ #  # ]:          0 :         delete pData;
    1140                 :          0 :         return true;
    1141                 :            :     }
    1142                 :            : 
    1143                 :            :     // insert into or append to list of physical font faces
    1144                 :     292134 :     pNewData->mpNext = pData;
    1145                 :     292134 :     *ppHere = pNewData;
    1146                 :     301740 :     return true;
    1147                 :            : }
    1148                 :            : 
    1149                 :            : // -----------------------------------------------------------------------
    1150                 :            : 
    1151                 :            : // get font attributes using the normalized font family name
    1152                 :          0 : void ImplDevFontListData::InitMatchData( const utl::FontSubstConfiguration& rFontSubst,
    1153                 :            :     const String& rSearchName )
    1154                 :            : {
    1155         [ #  # ]:          0 :     String aShortName;
    1156                 :            :     // get font attributes from the decorated font name
    1157                 :            :     rFontSubst.getMapName( rSearchName, aShortName, maMatchFamilyName,
    1158         [ #  # ]:          0 :                             meMatchWeight, meMatchWidth, mnMatchType );
    1159 [ #  # ][ #  # ]:          0 :     const FontNameAttr* pFontAttr = rFontSubst.getSubstInfo( rSearchName );
    1160                 :            :     // eventually use the stripped name
    1161         [ #  # ]:          0 :     if( !pFontAttr )
    1162 [ #  # ][ #  # ]:          0 :         if( aShortName != rSearchName )
    1163 [ #  # ][ #  # ]:          0 :             pFontAttr = rFontSubst.getSubstInfo( aShortName );
    1164                 :          0 :     ImplCalcType( mnMatchType, meMatchWeight, meMatchWidth, meFamily, pFontAttr );
    1165         [ #  # ]:          0 :     mnMatchType |= ImplIsCJKFont( maName );
    1166                 :          0 : }
    1167                 :            : 
    1168                 :            : // -----------------------------------------------------------------------
    1169                 :            : 
    1170                 :       9000 : PhysicalFontFace* ImplDevFontListData::FindBestFontFace( const FontSelectPattern& rFSD ) const
    1171                 :            : {
    1172         [ -  + ]:       9000 :     if( !mpFirst )
    1173                 :          0 :         return NULL;
    1174         [ +  + ]:       9000 :     if( !mpFirst->GetNextFace() )
    1175                 :       1887 :         return mpFirst;
    1176                 :            : 
    1177                 :            :     // FontName+StyleName should map to FamilyName+StyleName
    1178                 :       7113 :     const String& rSearchName = rFSD.maTargetName;
    1179                 :       7113 :     const xub_Unicode* pTargetStyleName = NULL;
    1180 [ +  + ][ -  + ]:      10878 :     if( (rSearchName.Len() > maSearchName.Len())
                 [ -  + ]
    1181         [ +  - ]:       3765 :     &&   rSearchName.Equals( maSearchName, 0, maSearchName.Len() ) )
    1182                 :          0 :         pTargetStyleName = rSearchName.GetBuffer() + maSearchName.Len() + 1;
    1183                 :            : 
    1184                 :            :     // linear search, TODO: improve?
    1185                 :       7113 :     PhysicalFontFace* pFontFace = mpFirst;
    1186                 :       7113 :     PhysicalFontFace* pBestFontFace = pFontFace;
    1187                 :       7113 :     FontMatchStatus aFontMatchStatus = {0,0,0, pTargetStyleName};
    1188         [ +  + ]:      35565 :     for(; pFontFace; pFontFace = pFontFace->GetNextFace() )
    1189 [ +  - ][ +  + ]:      28452 :         if( pFontFace->IsBetterMatch( rFSD, aFontMatchStatus ) )
    1190                 :       9645 :             pBestFontFace = pFontFace;
    1191                 :            : 
    1192                 :       9000 :     return pBestFontFace;
    1193                 :            : }
    1194                 :            : 
    1195                 :            : // -----------------------------------------------------------------------
    1196                 :            : 
    1197                 :            : // update device font list with unique font faces, with uniqueness
    1198                 :            : // meaning different font attributes, but not different fonts sizes
    1199                 :     164160 : void ImplDevFontListData::UpdateDevFontList( ImplGetDevFontList& rDevFontList ) const
    1200                 :            : {
    1201                 :     164160 :     PhysicalFontFace* pPrevFace = NULL;
    1202         [ +  + ]:     530928 :     for( PhysicalFontFace* pFace = mpFirst; pFace; pFace = pFace->GetNextFace() )
    1203                 :            :     {
    1204 [ +  + ][ +  - ]:     366768 :         if( !pPrevFace || pFace->CompareIgnoreSize( *pPrevFace ) )
                 [ +  - ]
    1205                 :     366768 :             rDevFontList.Add( pFace );
    1206                 :     366768 :         pPrevFace = pFace;
    1207                 :            :     }
    1208                 :     164160 : }
    1209                 :            : 
    1210                 :            : // -----------------------------------------------------------------------
    1211                 :            : 
    1212                 :       1464 : void ImplDevFontListData::GetFontHeights( std::set<int>& rHeights ) const
    1213                 :            : {
    1214                 :            :     // add all available font heights
    1215         [ +  + ]:       7320 :     for( const PhysicalFontFace* pFace = mpFirst; pFace; pFace = pFace->GetNextFace() )
    1216         [ +  - ]:       5856 :         rHeights.insert( pFace->GetHeight() );
    1217                 :       1464 : }
    1218                 :            : 
    1219                 :            : // -----------------------------------------------------------------------
    1220                 :            : 
    1221                 :     110142 : void ImplDevFontListData::UpdateCloneFontList( ImplDevFontList& rDevFontList,
    1222                 :            :     bool bScalable, bool bEmbeddable ) const
    1223                 :            : {
    1224         [ +  + ]:     353550 :     for( PhysicalFontFace* pFace = mpFirst; pFace; pFace = pFace->GetNextFace() )
    1225                 :            :     {
    1226 [ +  - ][ -  + ]:     243408 :         if( bScalable && !pFace->IsScalable() )
                 [ -  + ]
    1227                 :          0 :             continue;
    1228 [ -  + ][ #  # ]:     243408 :         if( bEmbeddable && !pFace->IsEmbeddable() && !pFace->IsSubsettable() )
         [ #  # ][ -  + ]
    1229                 :          0 :             continue;
    1230                 :            : 
    1231                 :     243408 :         PhysicalFontFace* pClonedFace = pFace->Clone();
    1232                 :     243408 :         rDevFontList.Add( pClonedFace );
    1233                 :            :     }
    1234                 :     110142 : }
    1235                 :            : 
    1236                 :            : // =======================================================================
    1237                 :            : 
    1238                 :       2379 : ImplDevFontList::ImplDevFontList()
    1239                 :            : :   mbMatchData( false )
    1240                 :            : ,   mbMapNames( false )
    1241                 :            : ,   mpPreMatchHook( NULL )
    1242                 :            : ,   mpFallbackHook( NULL )
    1243                 :            : ,   mpFallbackList( NULL )
    1244         [ +  - ]:       2379 : ,   mnFallbackCount( -1 )
    1245                 :       2379 : {}
    1246                 :            : 
    1247                 :            : // -----------------------------------------------------------------------
    1248                 :            : 
    1249                 :       2138 : ImplDevFontList::~ImplDevFontList()
    1250                 :            : {
    1251         [ +  - ]:       2138 :     Clear();
    1252         [ -  + ]:       4276 : }
    1253                 :            : 
    1254                 :            : // -----------------------------------------------------------------------
    1255                 :            : 
    1256                 :        359 : void ImplDevFontList::SetPreMatchHook( ImplPreMatchFontSubstitution* pHook )
    1257                 :            : {
    1258                 :        359 :     mpPreMatchHook = pHook;
    1259                 :        359 : }
    1260                 :            : 
    1261                 :            : // -----------------------------------------------------------------------
    1262                 :            : 
    1263                 :        359 : void ImplDevFontList::SetFallbackHook( ImplGlyphFallbackFontSubstitution* pHook )
    1264                 :            : {
    1265                 :        359 :     mpFallbackHook = pHook;
    1266                 :        359 : }
    1267                 :            : 
    1268                 :            : // -----------------------------------------------------------------------
    1269                 :            : 
    1270                 :       4123 : void ImplDevFontList::Clear()
    1271                 :            : {
    1272                 :            :     // remove fallback lists
    1273         [ -  + ]:       4123 :     delete[] mpFallbackList;
    1274                 :       4123 :     mpFallbackList = NULL;
    1275                 :       4123 :     mnFallbackCount = -1;
    1276                 :            : 
    1277                 :            :     // clear all entries in the device font list
    1278         [ +  - ]:       4123 :     DevFontList::iterator it = maDevFontList.begin();
    1279 [ +  - ][ +  + ]:     124677 :     for(; it != maDevFontList.end(); ++it )
    1280                 :            :     {
    1281         [ +  - ]:     120554 :         ImplDevFontListData* pEntry = (*it).second;
    1282 [ +  - ][ +  - ]:     120554 :         delete pEntry;
    1283                 :            :     }
    1284                 :            : 
    1285         [ +  - ]:       4123 :     maDevFontList.clear();
    1286                 :            : 
    1287                 :            :     // match data must be recalculated too
    1288                 :       4123 :     mbMatchData = false;
    1289                 :       4123 : }
    1290                 :            : 
    1291                 :            : 
    1292                 :            : // -----------------------------------------------------------------------
    1293                 :            : 
    1294                 :          0 : void ImplDevFontList::InitGenericGlyphFallback( void ) const
    1295                 :            : {
    1296                 :            :     // normalized family names of fonts suited for glyph fallback
    1297                 :            :     // if a font is available related fonts can be ignored
    1298                 :            :     // TODO: implement dynamic lists
    1299                 :            :     static const char* aGlyphFallbackList[] = {
    1300                 :            :         // empty strings separate the names of unrelated fonts
    1301                 :            :         "eudc", "",
    1302                 :            :         "arialunicodems", "cyberbit", "code2000", "",
    1303                 :            :         "andalesansui", "",
    1304                 :            :         "starsymbol", "opensymbol", "",
    1305                 :            :         "msmincho", "fzmingti", "fzheiti", "ipamincho", "sazanamimincho", "kochimincho", "",
    1306                 :            :         "sunbatang", "sundotum", "baekmukdotum", "gulim", "batang", "dotum", "",
    1307                 :            :         "hgmincholightj", "msunglightsc", "msunglighttc", "hymyeongjolightk", "",
    1308                 :            :         "tahoma", "dejavusans", "timesnewroman", "liberationsans", "",
    1309                 :            :         "shree", "mangal", "",
    1310                 :            :         "raavi", "shruti", "tunga", "",
    1311                 :            :         "latha", "gautami", "kartika", "vrinda", "",
    1312                 :            :         "shayyalmt", "naskmt", "scheherazade", "",
    1313                 :            :         "david", "nachlieli", "lucidagrande", "",
    1314                 :            :         "norasi", "angsanaupc", "",
    1315                 :            :         "khmerossystem", "",
    1316                 :            :         "muktinarrow", "",
    1317                 :            :         "phetsarathot", "",
    1318                 :            :         "padauk", "pinlonmyanmar", "",
    1319                 :            :         "iskoolapota", "lklug", "",
    1320                 :            :         0
    1321                 :            :     };
    1322                 :            : 
    1323                 :          0 :     bool bHasEudc = false;
    1324                 :          0 :     int nMaxLevel = 0;
    1325                 :          0 :     int nBestQuality = 0;
    1326                 :          0 :     ImplDevFontListData** pFallbackList = NULL;
    1327                 :          0 :     for( const char** ppNames = &aGlyphFallbackList[0];; ++ppNames )
    1328                 :            :     {
    1329                 :            :         // advance to next sub-list when end-of-sublist marker
    1330         [ #  # ]:          0 :         if( !**ppNames )    // #i46456# check for empty string, i.e., deref string itself not only ptr to it
    1331                 :            :         {
    1332         [ #  # ]:          0 :             if( nBestQuality > 0 )
    1333         [ #  # ]:          0 :                 if( ++nMaxLevel >= MAX_FALLBACK )
    1334                 :            :                     break;
    1335         [ #  # ]:          0 :             if( !ppNames[1] )
    1336                 :            :                 break;
    1337                 :          0 :             nBestQuality = 0;
    1338                 :          0 :             continue;
    1339                 :            :         }
    1340                 :            : 
    1341                 :            :         // test if the glyph fallback candidate font is available and scalable
    1342         [ #  # ]:          0 :         String aTokenName( *ppNames, RTL_TEXTENCODING_UTF8 );
    1343         [ #  # ]:          0 :         ImplDevFontListData* pFallbackFont = FindFontFamily( aTokenName );
    1344         [ #  # ]:          0 :         if( !pFallbackFont )
    1345                 :          0 :             continue;
    1346         [ #  # ]:          0 :         if( !pFallbackFont->IsScalable() )
    1347                 :          0 :             continue;
    1348                 :            : 
    1349                 :            :         // keep the best font of the glyph fallback sub-list
    1350         [ #  # ]:          0 :         if( nBestQuality < pFallbackFont->GetMinQuality() )
    1351                 :            :         {
    1352                 :          0 :             nBestQuality = pFallbackFont->GetMinQuality();
    1353                 :            :             // store available glyph fallback fonts
    1354         [ #  # ]:          0 :             if( !pFallbackList )
    1355         [ #  # ]:          0 :                 pFallbackList = new ImplDevFontListData*[ MAX_FALLBACK ];
    1356                 :          0 :             pFallbackList[ nMaxLevel ] = pFallbackFont;
    1357 [ #  # ][ #  # ]:          0 :             if( !bHasEudc && !nMaxLevel )
    1358                 :          0 :                 bHasEudc = !strncmp( *ppNames, "eudc", 5 );
    1359                 :            :         }
    1360 [ #  # ][ #  # ]:          0 :     }
    1361                 :            : 
    1362                 :            : #ifdef SAL_FONTENUM_STABLE_ON_PLATFORM // #i113472#
    1363                 :            :     // sort the list of fonts for glyph fallback by quality (highest first)
    1364                 :            :     // #i33947# keep the EUDC font at the front of the list
    1365                 :            :     // an insertion sort is good enough for this short list
    1366                 :            :     const int nSortStart = bHasEudc ? 1 : 0;
    1367                 :            :     for( int i = nSortStart+1, j; i < nMaxLevel; ++i )
    1368                 :            :     {
    1369                 :            :         ImplDevFontListData* pTestFont = pFallbackList[ i ];
    1370                 :            :         int nTestQuality = pTestFont->GetMinQuality();
    1371                 :            :         for( j = i; --j >= nSortStart; )
    1372                 :            :             if( nTestQuality > pFallbackList[j]->GetMinQuality() )
    1373                 :            :                 pFallbackList[ j+1 ] = pFallbackList[ j ];
    1374                 :            :             else
    1375                 :            :                 break;
    1376                 :            :         pFallbackList[ j+1 ] = pTestFont;
    1377                 :            :     }
    1378                 :            : #endif
    1379                 :            : 
    1380                 :          0 :     mnFallbackCount = nMaxLevel;
    1381                 :          0 :     mpFallbackList  = pFallbackList;
    1382                 :          0 : }
    1383                 :            : 
    1384                 :            : // -----------------------------------------------------------------------
    1385                 :            : 
    1386                 :       9357 : ImplDevFontListData* ImplDevFontList::GetGlyphFallbackFont( FontSelectPattern& rFontSelData,
    1387                 :            :     rtl::OUString& rMissingCodes, int nFallbackLevel ) const
    1388                 :            : {
    1389                 :       9357 :     ImplDevFontListData* pFallbackData = NULL;
    1390                 :            : 
    1391                 :            :     // find a matching font candidate for platform specific glyph fallback
    1392         [ +  - ]:       9357 :     if( mpFallbackHook )
    1393                 :            :     {
    1394                 :            :         // check cache for the first matching entry
    1395                 :            :         // to avoid calling the expensive fallback hook (#i83491#)
    1396                 :       9357 :         sal_UCS4 cChar = 0;
    1397                 :       9357 :         bool bCached = true;
    1398                 :       9357 :         sal_Int32 nStrIndex = 0;
    1399         [ +  - ]:       9357 :         while( nStrIndex < rMissingCodes.getLength() )
    1400                 :            :         {
    1401         [ +  - ]:       9357 :             cChar = rMissingCodes.iterateCodePoints( &nStrIndex );
    1402         [ +  - ]:       9357 :             bCached = rFontSelData.mpFontEntry->GetFallbackForUnicode( cChar, rFontSelData.GetWeight(), &rFontSelData.maSearchName );
    1403                 :            :             // ignore entries which don't have a fallback
    1404 [ +  + ][ +  - ]:       9357 :             if( !bCached || (rFontSelData.maSearchName.Len() != 0) )
                 [ +  - ]
    1405                 :       9357 :                 break;
    1406                 :            :         }
    1407                 :            : 
    1408         [ +  + ]:       9357 :         if( bCached )
    1409                 :            :         {
    1410                 :            :             // there is a matching fallback in the cache
    1411                 :            :             // so update rMissingCodes with codepoints not yet resolved by this fallback
    1412                 :       5787 :             int nRemainingLength = 0;
    1413                 :       5787 :             sal_UCS4* pRemainingCodes = (sal_UCS4*)alloca( rMissingCodes.getLength() * sizeof(sal_UCS4) );
    1414         [ +  - ]:       5787 :             String aFontName;
    1415         [ +  + ]:       6051 :             while( nStrIndex < rMissingCodes.getLength() )
    1416                 :            :             {
    1417         [ +  - ]:        264 :                 cChar = rMissingCodes.iterateCodePoints( &nStrIndex );
    1418         [ +  - ]:        264 :                 bCached = rFontSelData.mpFontEntry->GetFallbackForUnicode( cChar, rFontSelData.GetWeight(), &aFontName );
    1419 [ +  - ][ +  - ]:        264 :                 if( !bCached || (rFontSelData.maSearchName != aFontName) )
         [ -  + ][ -  + ]
    1420                 :          0 :                     pRemainingCodes[ nRemainingLength++ ] = cChar;
    1421                 :            :             }
    1422 [ +  - ][ +  - ]:       5787 :             rMissingCodes = rtl::OUString( pRemainingCodes, nRemainingLength );
    1423                 :            :         }
    1424                 :            :         else
    1425                 :            :         {
    1426                 :       3570 :             rtl::OUString aOldMissingCodes = rMissingCodes;
    1427                 :            :             // call the hook to query the best matching glyph fallback font
    1428 [ +  - ][ +  - ]:       3570 :             if( mpFallbackHook->FindFontSubstitute( rFontSelData, rMissingCodes ) )
    1429                 :            :                 // apply outdev3.cxx specific fontname normalization
    1430         [ +  - ]:       3570 :                 GetEnglishSearchFontName( rFontSelData.maSearchName );
    1431                 :            :             else
    1432 [ #  # ][ #  # ]:          0 :                 rFontSelData.maSearchName = String();
                 [ #  # ]
    1433                 :            : 
    1434                 :            :             //See fdo#32665 for an example. FreeSerif that has glyphs in normal
    1435                 :            :             //font, but not in the italic or bold version
    1436 [ +  - ][ -  + ]:       3570 :             bool bSubSetOfFontRequiresPropertyFaking = rFontSelData.mbEmbolden || rFontSelData.maItalicMatrix != ItalicMatrix();
                 [ +  - ]
    1437                 :            : 
    1438                 :            :             // cache the result even if there was no match, unless its from part of a font for which the properties need
    1439                 :            :             // to be faked. We need to rework this cache to take into account that fontconfig can return different fonts
    1440                 :            :             // for different input sizes, weights, etc. Basically the cache is way to naive
    1441         [ +  - ]:       3570 :             if (!bSubSetOfFontRequiresPropertyFaking)
    1442                 :            :             {
    1443                 :         33 :                 for(;;)
    1444                 :            :                 {
    1445 [ +  - ][ +  + ]:       3603 :                      if( !rFontSelData.mpFontEntry->GetFallbackForUnicode( cChar, rFontSelData.GetWeight(), &rFontSelData.maSearchName ) )
    1446         [ +  - ]:       1062 :                          rFontSelData.mpFontEntry->AddFallbackForUnicode( cChar, rFontSelData.GetWeight(), rFontSelData.maSearchName );
    1447         [ +  + ]:       3603 :                      if( nStrIndex >= aOldMissingCodes.getLength() )
    1448                 :       3570 :                          break;
    1449         [ +  - ]:         33 :                      cChar = aOldMissingCodes.iterateCodePoints( &nStrIndex );
    1450                 :            :                 }
    1451         [ +  - ]:       3570 :                 if( rFontSelData.maSearchName.Len() != 0 )
    1452                 :            :                 {
    1453                 :            :                     // remove cache entries that were still not resolved
    1454         [ -  + ]:       3570 :                     for( nStrIndex = 0; nStrIndex < rMissingCodes.getLength(); )
    1455                 :            :                     {
    1456         [ #  # ]:          0 :                         cChar = rMissingCodes.iterateCodePoints( &nStrIndex );
    1457         [ #  # ]:          0 :                         rFontSelData.mpFontEntry->IgnoreFallbackForUnicode( cChar, rFontSelData.GetWeight(), rFontSelData.maSearchName );
    1458                 :            :                     }
    1459                 :            :                 }
    1460                 :       3570 :             }
    1461                 :            :         }
    1462                 :            : 
    1463                 :            :         // find the matching device font
    1464         [ +  - ]:       9357 :         if( rFontSelData.maSearchName.Len() != 0 )
    1465         [ +  - ]:       9357 :             pFallbackData = FindFontFamily( rFontSelData.maSearchName );
    1466                 :            :     }
    1467                 :            : 
    1468                 :            :     // else find a matching font candidate for generic glyph fallback
    1469         [ -  + ]:       9357 :     if( !pFallbackData )
    1470                 :            :     {
    1471                 :            :         // initialize font candidates for generic glyph fallback if needed
    1472         [ #  # ]:          0 :         if( mnFallbackCount < 0 )
    1473                 :          0 :             InitGenericGlyphFallback();
    1474                 :            :         // TODO: adjust nFallbackLevel by number of levels resolved by the fallback hook
    1475         [ #  # ]:          0 :         if( nFallbackLevel < mnFallbackCount )
    1476                 :          0 :             pFallbackData = mpFallbackList[ nFallbackLevel ];
    1477                 :            :     }
    1478                 :            : 
    1479                 :       9357 :     return pFallbackData;
    1480                 :            : }
    1481                 :            : 
    1482                 :            : // -----------------------------------------------------------------------
    1483                 :            : 
    1484                 :     301740 : void ImplDevFontList::Add( PhysicalFontFace* pNewData )
    1485                 :            : {
    1486         [ +  - ]:     301740 :     String aSearchName = pNewData->maName;
    1487         [ +  - ]:     301740 :     GetEnglishSearchFontName( aSearchName );
    1488                 :            : 
    1489         [ +  - ]:     301740 :     DevFontList::const_iterator it = maDevFontList.find( aSearchName );
    1490                 :     301740 :     ImplDevFontListData* pFoundData = NULL;
    1491 [ +  + ][ +  - ]:     301740 :     if( it != maDevFontList.end() )
    1492         [ +  - ]:     170314 :         pFoundData = (*it).second;
    1493                 :            : 
    1494         [ +  + ]:     301740 :     if( !pFoundData )
    1495                 :            :     {
    1496 [ +  - ][ +  - ]:     131426 :         pFoundData = new ImplDevFontListData( aSearchName );
    1497         [ +  - ]:     131426 :         maDevFontList[ aSearchName ] = pFoundData;
    1498                 :            :     }
    1499                 :            : 
    1500         [ +  - ]:     301740 :     bool bKeepNewData = pFoundData->AddFontFace( pNewData );
    1501                 :            : 
    1502         [ +  + ]:     301740 :     if( !bKeepNewData )
    1503 [ +  - ][ +  - ]:     301740 :         delete pNewData;
                 [ +  - ]
    1504                 :     301740 : }
    1505                 :            : 
    1506                 :            : // -----------------------------------------------------------------------
    1507                 :            : 
    1508                 :            : // find the font from the normalized font family name
    1509                 :     488537 : ImplDevFontListData* ImplDevFontList::ImplFindBySearchName( const String& rSearchName ) const
    1510                 :            : {
    1511                 :            : #ifdef DEBUG
    1512                 :            :     String aTempName = rSearchName;
    1513                 :            :     GetEnglishSearchFontName( aTempName );
    1514                 :            :     DBG_ASSERT( aTempName == rSearchName, "ImplDevFontList::ImplFindBySearchName() called with non-normalized name" );
    1515                 :            : #endif
    1516                 :            : 
    1517         [ +  - ]:     488537 :     DevFontList::const_iterator it = maDevFontList.find( rSearchName );
    1518 [ +  - ][ +  + ]:     488537 :     if( it == maDevFontList.end() )
    1519                 :     311705 :         return NULL;
    1520                 :            : 
    1521         [ +  - ]:     176832 :     ImplDevFontListData* pFoundData = (*it).second;
    1522                 :     488537 :     return pFoundData;
    1523                 :            : }
    1524                 :            : 
    1525                 :            : // -----------------------------------------------------------------------
    1526                 :            : 
    1527                 :          0 : ImplDevFontListData* ImplDevFontList::ImplFindByAliasName(const rtl::OUString& rSearchName,
    1528                 :            :     const rtl::OUString& rShortName) const
    1529                 :            : {
    1530                 :            :     // short circuit for impossible font name alias
    1531         [ #  # ]:          0 :     if (rSearchName.isEmpty())
    1532                 :          0 :         return NULL;
    1533                 :            : 
    1534                 :            :     // short circuit if no alias names are available
    1535         [ #  # ]:          0 :     if (!mbMapNames)
    1536                 :          0 :         return NULL;
    1537                 :            : 
    1538                 :            :     // use the font's alias names to find the font
    1539                 :            :     // TODO: get rid of linear search
    1540         [ #  # ]:          0 :     DevFontList::const_iterator it = maDevFontList.begin();
    1541 [ #  # ][ #  # ]:          0 :     while( it != maDevFontList.end() )
    1542                 :            :     {
    1543         [ #  # ]:          0 :         ImplDevFontListData* pData = (*it).second;
    1544         [ #  # ]:          0 :         if( !pData->maMapNames.Len() )
    1545                 :          0 :             continue;
    1546                 :            : 
    1547                 :            :         // if one alias name matches we found a matching font
    1548                 :          0 :         rtl::OUString aTempName;
    1549                 :          0 :         xub_StrLen nIndex = 0;
    1550         [ #  # ]:          0 :         do
    1551                 :            :         {
    1552 [ #  # ][ #  # ]:          0 :            aTempName = GetNextFontToken( pData->maMapNames, nIndex );
                 [ #  # ]
    1553                 :            :            // Test, if the Font name match with one of the mapping names
    1554 [ #  # ][ #  # ]:          0 :            if ( (aTempName == rSearchName) || (aTempName == rShortName) )
                 [ #  # ]
    1555                 :          0 :               return pData;
    1556                 :            :         }
    1557                 :            :         while ( nIndex != STRING_NOTFOUND );
    1558         [ #  # ]:          0 :      }
    1559                 :            : 
    1560                 :          0 :      return NULL;
    1561                 :            : }
    1562                 :            : 
    1563                 :            : // -----------------------------------------------------------------------
    1564                 :            : 
    1565                 :      20240 : ImplDevFontListData* ImplDevFontList::FindFontFamily( const String& rFontName ) const
    1566                 :            : {
    1567                 :            :     // normalize the font fomily name and
    1568         [ +  - ]:      20240 :     String aName = rFontName;
    1569         [ +  - ]:      20240 :     GetEnglishSearchFontName( aName );
    1570         [ +  - ]:      20240 :     ImplDevFontListData* pFound = ImplFindBySearchName( aName );
    1571         [ +  - ]:      20240 :     return pFound;
    1572                 :            : }
    1573                 :            : 
    1574                 :            : // -----------------------------------------------------------------------
    1575                 :            : 
    1576                 :          0 : ImplDevFontListData* ImplDevFontList::ImplFindByTokenNames(const rtl::OUString& rTokenStr) const
    1577                 :            : {
    1578                 :          0 :     ImplDevFontListData* pFoundData = NULL;
    1579                 :            : 
    1580                 :            :     // use normalized font name tokens to find the font
    1581         [ #  # ]:          0 :     for( xub_StrLen nTokenPos = 0; nTokenPos != STRING_NOTFOUND; )
    1582                 :            :     {
    1583 [ #  # ][ #  # ]:          0 :         String aSearchName = GetNextFontToken( rTokenStr, nTokenPos );
                 [ #  # ]
    1584         [ #  # ]:          0 :         if( !aSearchName.Len() )
    1585                 :          0 :             continue;
    1586         [ #  # ]:          0 :         GetEnglishSearchFontName( aSearchName );
    1587         [ #  # ]:          0 :         pFoundData = ImplFindBySearchName( aSearchName );
    1588         [ #  # ]:          0 :         if( pFoundData )
    1589                 :            :             break;
    1590         [ #  # ]:          0 :     }
              [ #  #  # ]
    1591                 :            : 
    1592                 :          0 :     return pFoundData;
    1593                 :            : }
    1594                 :            : 
    1595                 :            : // -----------------------------------------------------------------------
    1596                 :            : 
    1597                 :      18632 : ImplDevFontListData* ImplDevFontList::ImplFindBySubstFontAttr( const utl::FontNameAttr& rFontAttr ) const
    1598                 :            : {
    1599                 :      18632 :     ImplDevFontListData* pFoundData = NULL;
    1600                 :            : 
    1601                 :            :     // use the font substitutions suggested by the FontNameAttr to find the font
    1602                 :      18632 :     ::std::vector< String >::const_iterator it = rFontAttr.Substitutions.begin();
    1603 [ +  - ][ +  - ]:     187303 :     for(; it != rFontAttr.Substitutions.end(); ++it )
                 [ +  - ]
    1604                 :            :     {
    1605 [ +  - ][ +  - ]:     168671 :         String aSearchName( *it );
    1606         [ +  - ]:     168671 :         GetEnglishSearchFontName( aSearchName );
    1607                 :            : 
    1608         [ +  - ]:     168671 :         pFoundData = ImplFindBySearchName( aSearchName );
    1609         [ +  + ]:     168671 :         if( pFoundData )
    1610                 :     168671 :             return pFoundData;
    1611 [ +  - ][ +  + ]:     168671 :     }
    1612                 :            : 
    1613                 :            :     // use known attributes from the configuration to find a matching substitute
    1614                 :          0 :     const sal_uLong nSearchType = rFontAttr.Type;
    1615         [ #  # ]:          0 :     if( nSearchType != 0 )
    1616                 :            :     {
    1617                 :          0 :         const FontWeight eSearchWeight = rFontAttr.Weight;
    1618                 :          0 :         const FontWidth  eSearchWidth  = rFontAttr.Width;
    1619                 :          0 :         const FontItalic eSearchSlant  = ITALIC_DONTKNOW;
    1620         [ #  # ]:          0 :         const String aSearchName;
    1621                 :            :         pFoundData = ImplFindByAttributes( nSearchType,
    1622 [ #  # ][ #  # ]:          0 :             eSearchWeight, eSearchWidth, eSearchSlant, aSearchName );
    1623         [ #  # ]:          0 :         if( pFoundData )
    1624 [ #  # ][ #  # ]:          0 :             return pFoundData;
    1625                 :            :     }
    1626                 :            : 
    1627                 :      18632 :     return NULL;
    1628                 :            : }
    1629                 :            : 
    1630                 :            : // -----------------------------------------------------------------------
    1631                 :            : 
    1632                 :          0 : void ImplDevFontList::InitMatchData() const
    1633                 :            : {
    1634                 :            :     // short circuit if already done
    1635         [ #  # ]:          0 :     if( mbMatchData )
    1636                 :          0 :         return;
    1637                 :          0 :     mbMatchData = true;
    1638                 :            : 
    1639                 :            :     // calculate MatchData for all entries
    1640         [ #  # ]:          0 :     const FontSubstConfiguration& rFontSubst = FontSubstConfiguration::get();
    1641                 :            : 
    1642         [ #  # ]:          0 :     DevFontList::const_iterator it = maDevFontList.begin();
    1643 [ #  # ][ #  # ]:          0 :     for(; it != maDevFontList.end(); ++it )
    1644                 :            :     {
    1645         [ #  # ]:          0 :         const String& rSearchName = (*it).first;
    1646         [ #  # ]:          0 :         ImplDevFontListData* pEntry = (*it).second;
    1647                 :            : 
    1648         [ #  # ]:          0 :         pEntry->InitMatchData( rFontSubst, rSearchName );
    1649                 :            :     }
    1650                 :            : }
    1651                 :            : 
    1652                 :            : // -----------------------------------------------------------------------
    1653                 :            : 
    1654                 :          0 : ImplDevFontListData* ImplDevFontList::ImplFindByAttributes( sal_uLong nSearchType,
    1655                 :            :     FontWeight eSearchWeight, FontWidth eSearchWidth,
    1656                 :            :     FontItalic eSearchItalic, const rtl::OUString& rSearchFamilyName ) const
    1657                 :            : {
    1658 [ #  # ][ #  # ]:          0 :     if( (eSearchItalic != ITALIC_NONE) && (eSearchItalic != ITALIC_DONTKNOW) )
    1659                 :          0 :         nSearchType |= IMPL_FONT_ATTR_ITALIC;
    1660                 :            : 
    1661                 :            :     // don't bother to match attributes if the attributes aren't worth matching
    1662 [ #  # ][ #  # ]:          0 :     if( !nSearchType
         [ #  # ][ #  # ]
                 [ #  # ]
    1663                 :            :     && ((eSearchWeight == WEIGHT_DONTKNOW) || (eSearchWeight == WEIGHT_NORMAL))
    1664                 :            :     && ((eSearchWidth == WIDTH_DONTKNOW) || (eSearchWidth == WIDTH_NORMAL)) )
    1665                 :          0 :         return NULL;
    1666                 :            : 
    1667         [ #  # ]:          0 :     InitMatchData();
    1668                 :          0 :     ImplDevFontListData* pFoundData = NULL;
    1669                 :            : 
    1670                 :            :     long    nTestMatch;
    1671                 :          0 :     long    nBestMatch = 40000;
    1672                 :          0 :     sal_uLong   nBestType = 0;
    1673                 :            : 
    1674         [ #  # ]:          0 :     DevFontList::const_iterator it = maDevFontList.begin();
    1675 [ #  # ][ #  # ]:          0 :     for(; it != maDevFontList.end(); ++it )
    1676                 :            :     {
    1677         [ #  # ]:          0 :         ImplDevFontListData* pData = (*it).second;
    1678                 :            : 
    1679                 :            :         // Get all information about the matching font
    1680                 :          0 :         sal_uLong       nMatchType  = pData->mnMatchType;
    1681                 :          0 :         FontWeight  eMatchWeight= pData->meMatchWeight;
    1682                 :          0 :         FontWidth   eMatchWidth = pData->meMatchWidth;
    1683                 :            : 
    1684                 :            :         // Calculate Match Value
    1685                 :            :         // 1000000000
    1686                 :            :         //  100000000
    1687                 :            :         //   10000000   CJK, CTL, None-Latin, Symbol
    1688                 :            :         //    1000000   FamilyName, Script, Fixed, -Special, -Decorative,
    1689                 :            :         //              Titling, Capitals, Outline, Shadow
    1690                 :            :         //     100000   Match FamilyName, Serif, SansSerif, Italic,
    1691                 :            :         //              Width, Weight
    1692                 :            :         //      10000   Scalable, Standard, Default,
    1693                 :            :         //              full, Normal, Knownfont,
    1694                 :            :         //              Otherstyle, +Special, +Decorative,
    1695                 :            :         //       1000   Typewriter, Rounded, Gothic, Schollbook
    1696                 :            :         //        100
    1697                 :          0 :         nTestMatch = 0;
    1698                 :            : 
    1699                 :            :         // test CJK script attributes
    1700         [ #  # ]:          0 :         if ( nSearchType & IMPL_FONT_ATTR_CJK )
    1701                 :            :         {
    1702                 :            :             // Matching language
    1703         [ #  # ]:          0 :             if( 0 == ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_CJK_ALLLANG) )
    1704                 :          0 :                 nTestMatch += 10000000*3;
    1705         [ #  # ]:          0 :             if( nMatchType & IMPL_FONT_ATTR_CJK )
    1706                 :          0 :                 nTestMatch += 10000000*2;
    1707         [ #  # ]:          0 :             if( nMatchType & IMPL_FONT_ATTR_FULL )
    1708                 :          0 :                 nTestMatch += 10000000;
    1709                 :            :         }
    1710         [ #  # ]:          0 :         else if ( nMatchType & IMPL_FONT_ATTR_CJK )
    1711                 :          0 :             nTestMatch -= 10000000;
    1712                 :            : 
    1713                 :            :         // test CTL script attributes
    1714         [ #  # ]:          0 :         if( nSearchType & IMPL_FONT_ATTR_CTL )
    1715                 :            :         {
    1716         [ #  # ]:          0 :             if( nMatchType & IMPL_FONT_ATTR_CTL )
    1717                 :          0 :                 nTestMatch += 10000000*2;
    1718         [ #  # ]:          0 :             if( nMatchType & IMPL_FONT_ATTR_FULL )
    1719                 :          0 :                 nTestMatch += 10000000;
    1720                 :            :         }
    1721         [ #  # ]:          0 :         else if ( nMatchType & IMPL_FONT_ATTR_CTL )
    1722                 :          0 :             nTestMatch -= 10000000;
    1723                 :            : 
    1724                 :            :         // test LATIN script attributes
    1725         [ #  # ]:          0 :         if( nSearchType & IMPL_FONT_ATTR_NONELATIN )
    1726                 :            :         {
    1727         [ #  # ]:          0 :             if( nMatchType & IMPL_FONT_ATTR_NONELATIN )
    1728                 :          0 :                 nTestMatch += 10000000*2;
    1729         [ #  # ]:          0 :             if( nMatchType & IMPL_FONT_ATTR_FULL )
    1730                 :          0 :                 nTestMatch += 10000000;
    1731                 :            :         }
    1732                 :            : 
    1733                 :            :         // test SYMBOL attributes
    1734         [ #  # ]:          0 :         if ( nSearchType & IMPL_FONT_ATTR_SYMBOL )
    1735                 :            :         {
    1736         [ #  # ]:          0 :             const String& rSearchName = it->first;
    1737                 :            :             // prefer some special known symbol fonts
    1738 [ #  # ][ #  # ]:          0 :             if ( rSearchName.EqualsAscii( "starsymbol" ) )
    1739                 :          0 :                 nTestMatch += 10000000*6+(10000*3);
    1740 [ #  # ][ #  # ]:          0 :             else if ( rSearchName.EqualsAscii( "opensymbol" ) )
    1741                 :          0 :                 nTestMatch += 10000000*6;
    1742 [ #  # ][ #  # ]:          0 :             else if ( rSearchName.EqualsAscii( "starbats" )
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1743         [ #  # ]:          0 :             ||        rSearchName.EqualsAscii( "wingdings" )
    1744         [ #  # ]:          0 :             ||        rSearchName.EqualsAscii( "monotypesorts" )
    1745         [ #  # ]:          0 :             ||        rSearchName.EqualsAscii( "dingbats" )
    1746         [ #  # ]:          0 :             ||        rSearchName.EqualsAscii( "zapfdingbats" ) )
    1747                 :          0 :                 nTestMatch += 10000000*5;
    1748         [ #  # ]:          0 :             else if ( pData->mnTypeFaces & IMPL_DEVFONT_SYMBOL )
    1749                 :          0 :                 nTestMatch += 10000000*4;
    1750                 :            :             else
    1751                 :            :             {
    1752         [ #  # ]:          0 :                 if( nMatchType & IMPL_FONT_ATTR_SYMBOL )
    1753                 :          0 :                     nTestMatch += 10000000*2;
    1754         [ #  # ]:          0 :                 if( nMatchType & IMPL_FONT_ATTR_FULL )
    1755                 :          0 :                     nTestMatch += 10000000;
    1756                 :            :             }
    1757                 :            :         }
    1758         [ #  # ]:          0 :         else if ( (pData->mnTypeFaces & (IMPL_DEVFONT_SYMBOL | IMPL_DEVFONT_NONESYMBOL)) == IMPL_DEVFONT_SYMBOL )
    1759                 :          0 :             nTestMatch -= 10000000;
    1760         [ #  # ]:          0 :         else if ( nMatchType & IMPL_FONT_ATTR_SYMBOL )
    1761                 :          0 :             nTestMatch -= 10000;
    1762                 :            : 
    1763                 :            :         // match stripped family name
    1764 [ #  # ][ #  # ]:          0 :         if( !rSearchFamilyName.isEmpty() && (rSearchFamilyName.equals(pData->maMatchFamilyName)) )
         [ #  # ][ #  # ]
           [ #  #  #  # ]
    1765                 :          0 :             nTestMatch += 1000000*3;
    1766                 :            : 
    1767                 :            :         // match ALLSCRIPT? attribute
    1768         [ #  # ]:          0 :         if( nSearchType & IMPL_FONT_ATTR_ALLSCRIPT )
    1769                 :            :         {
    1770         [ #  # ]:          0 :             if( nMatchType & IMPL_FONT_ATTR_ALLSCRIPT )
    1771                 :          0 :                 nTestMatch += 1000000*2;
    1772         [ #  # ]:          0 :             if( nSearchType & IMPL_FONT_ATTR_ALLSUBSCRIPT )
    1773                 :            :             {
    1774         [ #  # ]:          0 :                 if( 0 == ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_ALLSUBSCRIPT) )
    1775                 :          0 :                     nTestMatch += 1000000*2;
    1776         [ #  # ]:          0 :                 if( 0 != ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_BRUSHSCRIPT) )
    1777                 :          0 :                     nTestMatch -= 1000000;
    1778                 :            :             }
    1779                 :            :         }
    1780         [ #  # ]:          0 :         else if( nMatchType & IMPL_FONT_ATTR_ALLSCRIPT )
    1781                 :          0 :             nTestMatch -= 1000000;
    1782                 :            : 
    1783                 :            :         // test MONOSPACE+TYPEWRITER attributes
    1784         [ #  # ]:          0 :         if( nSearchType & IMPL_FONT_ATTR_FIXED )
    1785                 :            :         {
    1786         [ #  # ]:          0 :             if( nMatchType & IMPL_FONT_ATTR_FIXED )
    1787                 :          0 :                 nTestMatch += 1000000*2;
    1788                 :            :             // a typewriter attribute is even better
    1789         [ #  # ]:          0 :             if( 0 == ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_TYPEWRITER) )
    1790                 :          0 :                 nTestMatch += 10000*2;
    1791                 :            :         }
    1792         [ #  # ]:          0 :         else if( nMatchType & IMPL_FONT_ATTR_FIXED )
    1793                 :          0 :             nTestMatch -= 1000000;
    1794                 :            : 
    1795                 :            :         // test SPECIAL attribute
    1796         [ #  # ]:          0 :         if( nSearchType & IMPL_FONT_ATTR_SPECIAL )
    1797                 :            :         {
    1798         [ #  # ]:          0 :             if( nMatchType & IMPL_FONT_ATTR_SPECIAL )
    1799                 :          0 :                 nTestMatch += 10000;
    1800         [ #  # ]:          0 :             else if( !(nSearchType & IMPL_FONT_ATTR_ALLSERIFSTYLE) )
    1801                 :            :             {
    1802         [ #  # ]:          0 :                  if( nMatchType & IMPL_FONT_ATTR_SERIF )
    1803                 :          0 :                      nTestMatch += 1000*2;
    1804         [ #  # ]:          0 :                  else if( nMatchType & IMPL_FONT_ATTR_SANSSERIF )
    1805                 :          0 :                      nTestMatch += 1000;
    1806                 :            :              }
    1807                 :            :         }
    1808 [ #  # ][ #  # ]:          0 :         else if( (nMatchType & IMPL_FONT_ATTR_SPECIAL) && !(nSearchType & IMPL_FONT_ATTR_SYMBOL) )
    1809                 :          0 :             nTestMatch -= 1000000;
    1810                 :            : 
    1811                 :            :         // test DECORATIVE attribute
    1812         [ #  # ]:          0 :         if( nSearchType & IMPL_FONT_ATTR_DECORATIVE )
    1813                 :            :         {
    1814         [ #  # ]:          0 :             if( nMatchType & IMPL_FONT_ATTR_DECORATIVE )
    1815                 :          0 :                 nTestMatch += 10000;
    1816         [ #  # ]:          0 :             else if( !(nSearchType & IMPL_FONT_ATTR_ALLSERIFSTYLE) )
    1817                 :            :             {
    1818         [ #  # ]:          0 :                 if( nMatchType & IMPL_FONT_ATTR_SERIF )
    1819                 :          0 :                     nTestMatch += 1000*2;
    1820         [ #  # ]:          0 :                 else if ( nMatchType & IMPL_FONT_ATTR_SANSSERIF )
    1821                 :          0 :                     nTestMatch += 1000;
    1822                 :            :             }
    1823                 :            :         }
    1824         [ #  # ]:          0 :         else if( nMatchType & IMPL_FONT_ATTR_DECORATIVE )
    1825                 :          0 :             nTestMatch -= 1000000;
    1826                 :            : 
    1827                 :            :         // test TITLE+CAPITALS attributes
    1828         [ #  # ]:          0 :         if( nSearchType & (IMPL_FONT_ATTR_TITLING | IMPL_FONT_ATTR_CAPITALS) )
    1829                 :            :         {
    1830         [ #  # ]:          0 :             if( nMatchType & (IMPL_FONT_ATTR_TITLING | IMPL_FONT_ATTR_CAPITALS) )
    1831                 :          0 :                 nTestMatch += 1000000*2;
    1832         [ #  # ]:          0 :             if( 0 == ((nSearchType^nMatchType) & (IMPL_FONT_ATTR_TITLING | IMPL_FONT_ATTR_CAPITALS)))
    1833                 :          0 :                 nTestMatch += 1000000;
    1834 [ #  # ][ #  # ]:          0 :             else if( (nMatchType & (IMPL_FONT_ATTR_TITLING | IMPL_FONT_ATTR_CAPITALS))
    1835                 :            :             &&       (nMatchType & (IMPL_FONT_ATTR_STANDARD | IMPL_FONT_ATTR_DEFAULT)) )
    1836                 :          0 :                 nTestMatch += 1000000;
    1837                 :            :         }
    1838         [ #  # ]:          0 :         else if( nMatchType & (IMPL_FONT_ATTR_TITLING | IMPL_FONT_ATTR_CAPITALS) )
    1839                 :          0 :             nTestMatch -= 1000000;
    1840                 :            : 
    1841                 :            :         // test OUTLINE+SHADOW attributes
    1842         [ #  # ]:          0 :         if( nSearchType & (IMPL_FONT_ATTR_OUTLINE | IMPL_FONT_ATTR_SHADOW) )
    1843                 :            :         {
    1844         [ #  # ]:          0 :             if( nMatchType & (IMPL_FONT_ATTR_OUTLINE | IMPL_FONT_ATTR_SHADOW) )
    1845                 :          0 :                 nTestMatch += 1000000*2;
    1846         [ #  # ]:          0 :             if( 0 == ((nSearchType ^ nMatchType) & (IMPL_FONT_ATTR_OUTLINE | IMPL_FONT_ATTR_SHADOW)) )
    1847                 :          0 :                 nTestMatch += 1000000;
    1848 [ #  # ][ #  # ]:          0 :             else if( (nMatchType & (IMPL_FONT_ATTR_OUTLINE | IMPL_FONT_ATTR_SHADOW))
    1849                 :            :             &&       (nMatchType & (IMPL_FONT_ATTR_STANDARD | IMPL_FONT_ATTR_DEFAULT)) )
    1850                 :          0 :                 nTestMatch += 1000000;
    1851                 :            :         }
    1852         [ #  # ]:          0 :         else if ( nMatchType & (IMPL_FONT_ATTR_OUTLINE | IMPL_FONT_ATTR_SHADOW) )
    1853                 :          0 :             nTestMatch -= 1000000;
    1854                 :            : 
    1855                 :            :         // test font name substrings
    1856                 :            :     // TODO: calculate name matching score using e.g. Levenstein distance
    1857         [ #  # ]:          0 :         if( (rSearchFamilyName.getLength() >= 4) && (pData->maMatchFamilyName.Len() >= 4)
           [ #  #  #  # ]
         [ #  # ][ #  # ]
    1858 [ #  # ][ #  # ]:          0 :         &&    ((rSearchFamilyName.indexOf( pData->maMatchFamilyName ) != -1)
                 [ #  # ]
    1859 [ #  # ][ #  # ]:          0 :             || (pData->maMatchFamilyName.Search( rSearchFamilyName ) != STRING_NOTFOUND)) )
         [ #  # ][ #  # ]
                 [ #  # ]
    1860                 :          0 :                     nTestMatch += 5000;
    1861                 :            : 
    1862                 :            :         // test SERIF attribute
    1863         [ #  # ]:          0 :         if( nSearchType & IMPL_FONT_ATTR_SERIF )
    1864                 :            :         {
    1865         [ #  # ]:          0 :             if( nMatchType & IMPL_FONT_ATTR_SERIF )
    1866                 :          0 :                 nTestMatch += 1000000*2;
    1867         [ #  # ]:          0 :             else if( nMatchType & IMPL_FONT_ATTR_SANSSERIF )
    1868                 :          0 :                 nTestMatch -= 1000000;
    1869                 :            :         }
    1870                 :            : 
    1871                 :            :         // test SANSERIF attribute
    1872         [ #  # ]:          0 :         if( nSearchType & IMPL_FONT_ATTR_SANSSERIF )
    1873                 :            :         {
    1874         [ #  # ]:          0 :             if( nMatchType & IMPL_FONT_ATTR_SANSSERIF )
    1875                 :          0 :                 nTestMatch += 1000000;
    1876         [ #  # ]:          0 :             else if ( nMatchType & IMPL_FONT_ATTR_SERIF )
    1877                 :          0 :                 nTestMatch -= 1000000;
    1878                 :            :         }
    1879                 :            : 
    1880                 :            :         // test ITALIC attribute
    1881         [ #  # ]:          0 :         if( nSearchType & IMPL_FONT_ATTR_ITALIC )
    1882                 :            :         {
    1883         [ #  # ]:          0 :             if( pData->mnTypeFaces & IMPL_DEVFONT_ITALIC )
    1884                 :          0 :                 nTestMatch += 1000000*3;
    1885         [ #  # ]:          0 :             if( nMatchType & IMPL_FONT_ATTR_ITALIC )
    1886                 :          0 :                 nTestMatch += 1000000;
    1887                 :            :         }
    1888 [ #  # ][ #  # ]:          0 :         else if( !(nSearchType & IMPL_FONT_ATTR_ALLSCRIPT)
                 [ #  # ]
    1889                 :            :             &&  ((nMatchType & IMPL_FONT_ATTR_ITALIC)
    1890                 :          0 :                 || !(pData->mnTypeFaces & IMPL_DEVFONT_NONEITALIC)) )
    1891                 :          0 :             nTestMatch -= 1000000*2;
    1892                 :            : 
    1893                 :            :         // test WIDTH attribute
    1894 [ #  # ][ #  # ]:          0 :         if( (eSearchWidth != WIDTH_DONTKNOW) && (eSearchWidth != WIDTH_NORMAL) )
    1895                 :            :         {
    1896         [ #  # ]:          0 :             if( eSearchWidth < WIDTH_NORMAL )
    1897                 :            :             {
    1898         [ #  # ]:          0 :                 if( eSearchWidth == eMatchWidth )
    1899                 :          0 :                     nTestMatch += 1000000*3;
    1900 [ #  # ][ #  # ]:          0 :                 else if( (eMatchWidth < WIDTH_NORMAL) && (eMatchWidth != WIDTH_DONTKNOW) )
    1901                 :          0 :                     nTestMatch += 1000000;
    1902                 :            :             }
    1903                 :            :             else
    1904                 :            :             {
    1905         [ #  # ]:          0 :                 if( eSearchWidth == eMatchWidth )
    1906                 :          0 :                     nTestMatch += 1000000*3;
    1907         [ #  # ]:          0 :                 else if( eMatchWidth > WIDTH_NORMAL )
    1908                 :          0 :                     nTestMatch += 1000000;
    1909                 :            :             }
    1910                 :            :         }
    1911 [ #  # ][ #  # ]:          0 :         else if( (eMatchWidth != WIDTH_DONTKNOW) && (eMatchWidth != WIDTH_NORMAL) )
    1912                 :          0 :             nTestMatch -= 1000000;
    1913                 :            : 
    1914                 :            :         // test WEIGHT attribute
    1915 [ #  # ][ #  # ]:          0 :         if( (eSearchWeight != WEIGHT_DONTKNOW) && (eSearchWeight != WEIGHT_NORMAL) && (eSearchWeight != WEIGHT_MEDIUM) )
                 [ #  # ]
    1916                 :            :         {
    1917         [ #  # ]:          0 :             if( eSearchWeight < WEIGHT_NORMAL )
    1918                 :            :             {
    1919         [ #  # ]:          0 :                 if( pData->mnTypeFaces & IMPL_DEVFONT_LIGHT )
    1920                 :          0 :                     nTestMatch += 1000000;
    1921 [ #  # ][ #  # ]:          0 :                 if( (eMatchWeight < WEIGHT_NORMAL) && (eMatchWeight != WEIGHT_DONTKNOW) )
    1922                 :          0 :                     nTestMatch += 1000000;
    1923                 :            :             }
    1924                 :            :             else
    1925                 :            :             {
    1926         [ #  # ]:          0 :                 if( pData->mnTypeFaces & IMPL_DEVFONT_BOLD )
    1927                 :          0 :                     nTestMatch += 1000000;
    1928         [ #  # ]:          0 :                 if( eMatchWeight > WEIGHT_BOLD )
    1929                 :          0 :                     nTestMatch += 1000000;
    1930                 :            :             }
    1931                 :            :         }
    1932 [ #  # ][ #  # ]:          0 :         else if( ((eMatchWeight != WEIGHT_DONTKNOW) && (eMatchWeight != WEIGHT_NORMAL) && (eMatchWeight != WEIGHT_MEDIUM))
         [ #  # ][ #  # ]
    1933                 :          0 :             || !(pData->mnTypeFaces & IMPL_DEVFONT_NORMAL) )
    1934                 :          0 :             nTestMatch -= 1000000;
    1935                 :            : 
    1936                 :            :         // prefer scalable fonts
    1937         [ #  # ]:          0 :         if( pData->mnTypeFaces & IMPL_DEVFONT_SCALABLE )
    1938                 :          0 :             nTestMatch += 10000*4;
    1939                 :            :         else
    1940                 :          0 :             nTestMatch -= 10000*4;
    1941                 :            : 
    1942                 :            :         // test STANDARD+DEFAULT+FULL+NORMAL attributes
    1943         [ #  # ]:          0 :         if( nMatchType & IMPL_FONT_ATTR_STANDARD )
    1944                 :          0 :             nTestMatch += 10000*2;
    1945         [ #  # ]:          0 :         if( nMatchType & IMPL_FONT_ATTR_DEFAULT )
    1946                 :          0 :             nTestMatch += 10000;
    1947         [ #  # ]:          0 :         if( nMatchType & IMPL_FONT_ATTR_FULL )
    1948                 :          0 :             nTestMatch += 10000;
    1949         [ #  # ]:          0 :         if( nMatchType & IMPL_FONT_ATTR_NORMAL )
    1950                 :          0 :             nTestMatch += 10000;
    1951                 :            : 
    1952                 :            :         // test OTHERSTYLE attribute
    1953         [ #  # ]:          0 :         if( ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_OTHERSTYLE) != 0 )
    1954                 :            :         {
    1955                 :          0 :             nTestMatch -= 10000;
    1956                 :            :         }
    1957                 :            : 
    1958                 :            :         // test ROUNDED attribute
    1959         [ #  # ]:          0 :         if( 0 == ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_ROUNDED) )
    1960                 :          0 :             nTestMatch += 1000;
    1961                 :            : 
    1962                 :            :         // test TYPEWRITER attribute
    1963         [ #  # ]:          0 :         if( 0 == ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_TYPEWRITER) )
    1964                 :          0 :             nTestMatch += 1000;
    1965                 :            : 
    1966                 :            :         // test GOTHIC attribute
    1967         [ #  # ]:          0 :         if( nSearchType & IMPL_FONT_ATTR_GOTHIC )
    1968                 :            :         {
    1969         [ #  # ]:          0 :             if( nMatchType & IMPL_FONT_ATTR_GOTHIC )
    1970                 :          0 :                 nTestMatch += 1000*3;
    1971         [ #  # ]:          0 :             if( nMatchType & IMPL_FONT_ATTR_SANSSERIF )
    1972                 :          0 :                 nTestMatch += 1000*2;
    1973                 :            :         }
    1974                 :            : 
    1975                 :            :         // test SCHOOLBOOK attribute
    1976         [ #  # ]:          0 :         if( nSearchType & IMPL_FONT_ATTR_SCHOOLBOOK )
    1977                 :            :         {
    1978         [ #  # ]:          0 :             if( nMatchType & IMPL_FONT_ATTR_SCHOOLBOOK )
    1979                 :          0 :                 nTestMatch += 1000*3;
    1980         [ #  # ]:          0 :             if( nMatchType & IMPL_FONT_ATTR_SERIF )
    1981                 :          0 :                 nTestMatch += 1000*2;
    1982                 :            :         }
    1983                 :            : 
    1984                 :            :         // compare with best matching font yet
    1985         [ #  # ]:          0 :         if ( nTestMatch > nBestMatch )
    1986                 :            :         {
    1987                 :          0 :             pFoundData  = pData;
    1988                 :          0 :             nBestMatch  = nTestMatch;
    1989                 :          0 :             nBestType   = nMatchType;
    1990                 :            :         }
    1991         [ #  # ]:          0 :         else if( nTestMatch == nBestMatch )
    1992                 :            :         {
    1993                 :            :             // some fonts are more suitable defaults
    1994         [ #  # ]:          0 :             if( nMatchType & IMPL_FONT_ATTR_DEFAULT )
    1995                 :            :             {
    1996                 :          0 :                 pFoundData  = pData;
    1997                 :          0 :                 nBestType   = nMatchType;
    1998                 :            :             }
    1999 [ #  # ][ #  # ]:          0 :             else if( (nMatchType & IMPL_FONT_ATTR_STANDARD) &&
    2000                 :          0 :                     !(nBestType & IMPL_FONT_ATTR_DEFAULT) )
    2001                 :            :             {
    2002                 :          0 :                  pFoundData  = pData;
    2003                 :          0 :                  nBestType   = nMatchType;
    2004                 :            :             }
    2005                 :            :         }
    2006                 :            :     }
    2007                 :            : 
    2008                 :          0 :     return pFoundData;
    2009                 :            : }
    2010                 :            : 
    2011                 :            : // -----------------------------------------------------------------------
    2012                 :            : 
    2013                 :          0 : ImplDevFontListData* ImplDevFontList::FindDefaultFont() const
    2014                 :            : {
    2015                 :            :     // try to find one of the default fonts of the
    2016                 :            :     // UNICODE, SANSSERIF, SERIF or FIXED default font lists
    2017         [ #  # ]:          0 :     const DefaultFontConfiguration& rDefaults = DefaultFontConfiguration::get();
    2018         [ #  # ]:          0 :     com::sun::star::lang::Locale aLocale( OUString( RTL_CONSTASCII_USTRINGPARAM("en") ), OUString(), OUString() );
    2019 [ #  # ][ #  # ]:          0 :     String aFontname = rDefaults.getDefaultFont( aLocale, DEFAULTFONT_SANS_UNICODE );
    2020 [ #  # ][ #  # ]:          0 :     ImplDevFontListData* pFoundData = ImplFindByTokenNames( aFontname );
    2021         [ #  # ]:          0 :     if( pFoundData )
    2022                 :          0 :         return pFoundData;
    2023                 :            : 
    2024 [ #  # ][ #  # ]:          0 :     aFontname = rDefaults.getDefaultFont( aLocale, DEFAULTFONT_SANS );
    2025 [ #  # ][ #  # ]:          0 :     pFoundData = ImplFindByTokenNames( aFontname );
    2026         [ #  # ]:          0 :     if( pFoundData )
    2027                 :          0 :         return pFoundData;
    2028                 :            : 
    2029 [ #  # ][ #  # ]:          0 :     aFontname = rDefaults.getDefaultFont( aLocale, DEFAULTFONT_SERIF );
    2030 [ #  # ][ #  # ]:          0 :     pFoundData = ImplFindByTokenNames( aFontname );
    2031         [ #  # ]:          0 :     if( pFoundData )
    2032                 :          0 :         return pFoundData;
    2033                 :            : 
    2034 [ #  # ][ #  # ]:          0 :     aFontname = rDefaults.getDefaultFont( aLocale, DEFAULTFONT_FIXED );
    2035 [ #  # ][ #  # ]:          0 :     pFoundData = ImplFindByTokenNames( aFontname );
    2036         [ #  # ]:          0 :     if( pFoundData )
    2037                 :          0 :         return pFoundData;
    2038                 :            : 
    2039                 :            :     // now try to find a reasonable non-symbol font
    2040                 :            : 
    2041         [ #  # ]:          0 :     InitMatchData();
    2042                 :            : 
    2043         [ #  # ]:          0 :     DevFontList::const_iterator it = maDevFontList.begin();
    2044 [ #  # ][ #  # ]:          0 :     for(; it !=  maDevFontList.end(); ++it )
    2045                 :            :     {
    2046         [ #  # ]:          0 :         ImplDevFontListData* pData = (*it).second;
    2047         [ #  # ]:          0 :         if( pData->mnMatchType & IMPL_FONT_ATTR_SYMBOL )
    2048                 :          0 :             continue;
    2049                 :          0 :         pFoundData = pData;
    2050         [ #  # ]:          0 :         if( pData->mnMatchType & (IMPL_FONT_ATTR_DEFAULT|IMPL_FONT_ATTR_STANDARD) )
    2051                 :          0 :             break;
    2052                 :            :     }
    2053         [ #  # ]:          0 :     if( pFoundData )
    2054                 :          0 :         return pFoundData;
    2055                 :            : 
    2056                 :            :     // finding any font is better than finding no font at all
    2057         [ #  # ]:          0 :     it = maDevFontList.begin();
    2058 [ #  # ][ #  # ]:          0 :     if( it !=  maDevFontList.end() )
    2059         [ #  # ]:          0 :         pFoundData = (*it).second;
    2060                 :            : 
    2061         [ #  # ]:          0 :     return pFoundData;
    2062                 :            : }
    2063                 :            : 
    2064                 :            : // -----------------------------------------------------------------------
    2065                 :            : 
    2066                 :       2004 : ImplDevFontList* ImplDevFontList::Clone( bool bScalable, bool bEmbeddable ) const
    2067                 :            : {
    2068 [ +  - ][ +  - ]:       2004 :     ImplDevFontList* pClonedList = new ImplDevFontList;
    2069                 :            : //  pClonedList->mbMatchData    = mbMatchData;
    2070                 :       2004 :     pClonedList->mbMapNames     = mbMapNames;
    2071                 :       2004 :     pClonedList->mpPreMatchHook = mpPreMatchHook;
    2072                 :       2004 :     pClonedList->mpFallbackHook = mpFallbackHook;
    2073                 :            : 
    2074                 :            :     // TODO: clone the config-font attributes too?
    2075                 :       2004 :     pClonedList->mbMatchData    = false;
    2076                 :            : 
    2077         [ +  - ]:       2004 :     DevFontList::const_iterator it = maDevFontList.begin();
    2078 [ +  - ][ +  + ]:     112146 :     for(; it != maDevFontList.end(); ++it )
    2079                 :            :     {
    2080         [ +  - ]:     110142 :         const ImplDevFontListData* pFontFace = (*it).second;
    2081         [ +  - ]:     110142 :         pFontFace->UpdateCloneFontList( *pClonedList, bScalable, bEmbeddable );
    2082                 :            :     }
    2083                 :            : 
    2084                 :       2004 :     return pClonedList;
    2085                 :            : }
    2086                 :            : 
    2087                 :            : // -----------------------------------------------------------------------
    2088                 :            : 
    2089                 :       2925 : ImplGetDevFontList* ImplDevFontList::GetDevFontList() const
    2090                 :            : {
    2091 [ +  - ][ +  - ]:       2925 :     ImplGetDevFontList* pGetDevFontList = new ImplGetDevFontList;
    2092                 :            : 
    2093         [ +  - ]:       2925 :     DevFontList::const_iterator it = maDevFontList.begin();
    2094 [ +  - ][ +  + ]:     167085 :     for(; it != maDevFontList.end(); ++it )
    2095                 :            :     {
    2096         [ +  - ]:     164160 :         const ImplDevFontListData* pFontFamily = (*it).second;
    2097         [ +  - ]:     164160 :         pFontFamily->UpdateDevFontList( *pGetDevFontList );
    2098                 :            :     }
    2099                 :            : 
    2100                 :       2925 :     return pGetDevFontList;
    2101                 :            : }
    2102                 :            : 
    2103                 :            : // -----------------------------------------------------------------------
    2104                 :            : 
    2105                 :       1481 : ImplGetDevSizeList* ImplDevFontList::GetDevSizeList( const String& rFontName ) const
    2106                 :            : {
    2107         [ +  - ]:       1481 :     ImplGetDevSizeList* pGetDevSizeList = new ImplGetDevSizeList( rFontName );
    2108                 :            : 
    2109                 :       1481 :     ImplDevFontListData* pFontFamily = FindFontFamily( rFontName );
    2110         [ +  + ]:       1481 :     if( pFontFamily != NULL )
    2111                 :            :     {
    2112         [ +  - ]:       1464 :         std::set<int> rHeights;
    2113         [ +  - ]:       1464 :         pFontFamily->GetFontHeights( rHeights );
    2114                 :            : 
    2115                 :       1464 :         std::set<int>::const_iterator it = rHeights.begin();
    2116 [ #  # ][ +  - ]:       1464 :         for(; it != rHeights.begin(); ++it )
                 [ -  + ]
    2117 [ #  # ][ #  # ]:       1464 :             pGetDevSizeList->Add( *it );
    2118                 :            :     }
    2119                 :            : 
    2120                 :       1481 :     return pGetDevSizeList;
    2121                 :            : }
    2122                 :            : 
    2123                 :     841765 : FontSelectPatternAttributes::FontSelectPatternAttributes( const Font& rFont,
    2124                 :            :     const String& rSearchName, const Size& rSize, float fExactHeight )
    2125                 :            :     : maSearchName( rSearchName )
    2126                 :     841765 :     , mnWidth( rSize.Width() )
    2127                 :     841765 :     , mnHeight( rSize.Height() )
    2128                 :            :     , mfExactHeight( fExactHeight)
    2129         [ +  - ]:     841765 :     , mnOrientation( rFont.GetOrientation() )
    2130         [ +  - ]:     841765 :     , meLanguage( rFont.GetLanguage() )
    2131         [ +  - ]:     841765 :     , mbVertical( rFont.IsVertical() )
    2132                 :            :     , mbNonAntialiased( false )
    2133 [ +  - ][ +  - ]:    1683530 :     , mbEmbolden( false )
    2134                 :            : {
    2135         [ +  - ]:     841765 :     maTargetName = maName;
    2136                 :            : 
    2137         [ +  - ]:     841765 :     rFont.GetFontAttributes( *this );
    2138                 :            : 
    2139                 :            :     // normalize orientation between 0 and 3600
    2140         [ -  + ]:     841765 :     if( 3600 <= (unsigned)mnOrientation )
    2141                 :            :     {
    2142         [ #  # ]:          0 :         if( mnOrientation >= 0 )
    2143                 :          0 :             mnOrientation %= 3600;
    2144                 :            :         else
    2145                 :          0 :             mnOrientation = 3600 - (-mnOrientation % 3600);
    2146                 :            :     }
    2147                 :            : 
    2148                 :            :     // normalize width and height
    2149         [ +  + ]:     841765 :     if( mnHeight < 0 )
    2150                 :        304 :         mnHeight = -mnHeight;
    2151         [ +  + ]:     841765 :     if( mnWidth < 0 )
    2152                 :        450 :         mnWidth = -mnWidth;
    2153                 :     841765 : }
    2154                 :            : 
    2155                 :     841765 : FontSelectPattern::FontSelectPattern( const Font& rFont,
    2156                 :            :     const String& rSearchName, const Size& rSize, float fExactHeight)
    2157                 :            :     : FontSelectPatternAttributes(rFont, rSearchName, rSize, fExactHeight)
    2158                 :            :     , mpFontData( NULL )
    2159                 :     841765 :     , mpFontEntry( NULL )
    2160                 :            : {
    2161                 :     841765 : }
    2162                 :            : 
    2163                 :            : // NOTE: this ctor is still used on Windows. Do not remove.
    2164                 :          0 : FontSelectPatternAttributes::FontSelectPatternAttributes( const PhysicalFontFace& rFontData,
    2165                 :            :     const Size& rSize, float fExactHeight, int nOrientation, bool bVertical )
    2166                 :            :     : ImplFontAttributes( rFontData )
    2167                 :          0 :     , mnWidth( rSize.Width() )
    2168                 :          0 :     , mnHeight( rSize.Height() )
    2169                 :            :     , mfExactHeight( fExactHeight )
    2170                 :            :     , mnOrientation( nOrientation )
    2171                 :            :     , meLanguage( 0 )
    2172                 :            :     , mbVertical( bVertical )
    2173                 :            :     , mbNonAntialiased( false )
    2174 [ #  # ][ #  # ]:          0 :     , mbEmbolden( false )
    2175                 :            : {
    2176 [ #  # ][ #  # ]:          0 :     maTargetName = maSearchName = maName;
    2177                 :            :     // NOTE: no normalization for width/height/orientation
    2178                 :          0 : }
    2179                 :            : 
    2180                 :          0 : FontSelectPattern::FontSelectPattern( const PhysicalFontFace& rFontData,
    2181                 :            :     const Size& rSize, float fExactHeight, int nOrientation, bool bVertical )
    2182                 :            :     : FontSelectPatternAttributes(rFontData, rSize, fExactHeight, nOrientation, bVertical)
    2183                 :            :     , mpFontData( &rFontData )
    2184                 :          0 :     , mpFontEntry( NULL )
    2185                 :            : {
    2186                 :          0 : }
    2187                 :            : 
    2188                 :      91172 : void FontSelectPattern::copyAttributes(const FontSelectPatternAttributes &rAttributes)
    2189                 :            : {
    2190                 :      91172 :     static_cast<FontSelectPatternAttributes&>(*this) = rAttributes;
    2191                 :      91172 : }
    2192                 :            : 
    2193                 :            : // =======================================================================
    2194                 :            : 
    2195                 :     619457 : size_t ImplFontCache::IFSD_Hash::operator()( const FontSelectPattern& rFSD ) const
    2196                 :            : {
    2197                 :     619457 :     return rFSD.hashCode();
    2198                 :            : }
    2199                 :            : 
    2200                 :     619457 : size_t FontSelectPatternAttributes::hashCode() const
    2201                 :            : {
    2202                 :            :     // TODO: does it pay off to improve this hash function?
    2203                 :            :     static FontNameHash aFontNameHash;
    2204                 :     619457 :     size_t nHash = aFontNameHash( maSearchName );
    2205                 :            : #ifdef ENABLE_GRAPHITE
    2206                 :            :     // check for features and generate a unique hash if necessary
    2207         [ -  + ]:     619457 :     if (maTargetName.Search(grutils::GrFeatureParser::FEAT_PREFIX)
    2208                 :            :         != STRING_NOTFOUND)
    2209                 :            :     {
    2210                 :          0 :         nHash = aFontNameHash( maTargetName );
    2211                 :            :     }
    2212                 :            : #endif
    2213                 :     619457 :     nHash += 11 * mnHeight;
    2214                 :     619457 :     nHash += 19 * meWeight;
    2215                 :     619457 :     nHash += 29 * meItalic;
    2216                 :     619457 :     nHash += 37 * mnOrientation;
    2217                 :     619457 :     nHash += 41 * meLanguage;
    2218         [ -  + ]:     619457 :     if( mbVertical )
    2219                 :          0 :         nHash += 53;
    2220                 :     619457 :     return nHash;
    2221                 :            : }
    2222                 :            : 
    2223                 :     188552 : bool FontSelectPatternAttributes::operator==(const FontSelectPatternAttributes& rOther) const
    2224                 :            : {
    2225         [ +  + ]:     188552 :     if (static_cast<const ImplFontAttributes&>(*this) != static_cast<const ImplFontAttributes&>(rOther))
    2226                 :      49268 :         return false;
    2227                 :            : 
    2228         [ -  + ]:     139284 :     if (maTargetName != rOther.maTargetName)
    2229                 :          0 :         return false;
    2230                 :            : 
    2231         [ -  + ]:     139284 :     if (maSearchName != rOther.maSearchName)
    2232                 :          0 :         return false;
    2233                 :            : 
    2234         [ +  + ]:     139284 :     if (mnWidth != rOther.mnWidth)
    2235                 :      40155 :         return false;
    2236                 :            : 
    2237         [ +  + ]:      99129 :     if (mnHeight != rOther.mnHeight)
    2238                 :       6252 :         return false;
    2239                 :            : 
    2240         [ +  + ]:      92877 :     if (mfExactHeight != rOther.mfExactHeight)
    2241                 :          5 :         return false;
    2242                 :            : 
    2243         [ +  + ]:      92872 :     if (mnOrientation != rOther.mnOrientation)
    2244                 :       1486 :         return false;
    2245                 :            : 
    2246         [ +  + ]:      91386 :     if (meLanguage != rOther.meLanguage)
    2247                 :        214 :         return false;
    2248                 :            : 
    2249         [ -  + ]:      91172 :     if (mbVertical != rOther.mbVertical)
    2250                 :          0 :         return false;
    2251                 :            : 
    2252         [ -  + ]:      91172 :     if (mbNonAntialiased != rOther.mbNonAntialiased)
    2253                 :          0 :         return false;
    2254                 :            : 
    2255         [ -  + ]:      91172 :     if (mbEmbolden != rOther.mbEmbolden)
    2256                 :          0 :         return false;
    2257                 :            : 
    2258         [ -  + ]:      91172 :     if (maItalicMatrix != rOther.maItalicMatrix)
    2259                 :          0 :         return false;
    2260                 :            : 
    2261                 :     188552 :     return true;
    2262                 :            : }
    2263                 :            : 
    2264                 :            : // -----------------------------------------------------------------------
    2265                 :            : 
    2266                 :    1369369 : bool ImplFontCache::IFSD_Equal::operator()(const FontSelectPattern& rA, const FontSelectPattern& rB) const
    2267                 :            : {
    2268                 :            :     // check normalized font family name
    2269         [ +  + ]:    1369369 :     if( rA.maSearchName != rB.maSearchName )
    2270                 :     325522 :         return false;
    2271                 :            : 
    2272                 :            :     // check font transformation
    2273 [ +  + ][ +  + ]:    1043847 :     if( (rA.mnHeight       != rB.mnHeight)
                 [ +  + ]
    2274                 :            :     ||  (rA.mnWidth        != rB.mnWidth)
    2275                 :            :     ||  (rA.mnOrientation  != rB.mnOrientation) )
    2276                 :     122038 :         return false;
    2277                 :            : 
    2278                 :            :     // check mapping relevant attributes
    2279 [ +  - ][ +  + ]:     921809 :     if( (rA.mbVertical     != rB.mbVertical)
    2280                 :            :     ||  (rA.meLanguage     != rB.meLanguage) )
    2281                 :       2369 :         return false;
    2282                 :            : 
    2283                 :            :     // check font face attributes
    2284 [ +  + ][ +  + ]:     919440 :     if( (rA.meWeight       != rB.meWeight)
                 [ +  + ]
    2285                 :            :     ||  (rA.meItalic       != rB.meItalic)
    2286                 :            : //    ||  (rA.meFamily       != rB.meFamily) // TODO: remove this mostly obsolete member
    2287                 :            :     ||  (rA.mePitch        != rB.mePitch) )
    2288                 :      49067 :         return false;
    2289                 :            : 
    2290                 :            :     // check style name
    2291         [ +  + ]:     870373 :     if( rA.maStyleName != rB.maStyleName)
    2292                 :       7023 :         return false;
    2293                 :            : 
    2294                 :            :     // Symbol fonts may recode from one type to another So they are only
    2295                 :            :     // safely equivalent for equal targets
    2296   [ +  +  +  + ]:    1726832 :     if (
           [ +  -  +  + ]
                 [ +  + ]
    2297                 :       8745 :         (rA.mpFontData && rA.mpFontData->IsSymbolFont()) ||
    2298                 :     854737 :         (rB.mpFontData && rB.mpFontData->IsSymbolFont())
    2299                 :            :        )
    2300                 :            :     {
    2301         [ +  + ]:      47211 :         if (rA.maTargetName != rB.maTargetName)
    2302                 :      21228 :             return false;
    2303                 :            :     }
    2304                 :            : 
    2305                 :            : #ifdef ENABLE_GRAPHITE
    2306                 :            :     // check for features
    2307   [ +  -  -  +  :    1684244 :     if ((rA.maTargetName.Search(grutils::GrFeatureParser::FEAT_PREFIX)
           #  # ][ -  + ]
    2308                 :            :          != STRING_NOTFOUND ||
    2309                 :     842122 :          rB.maTargetName.Search(grutils::GrFeatureParser::FEAT_PREFIX)
    2310                 :          0 :          != STRING_NOTFOUND) && rA.maTargetName != rB.maTargetName)
    2311                 :          0 :         return false;
    2312                 :            : #endif
    2313                 :            : 
    2314         [ -  + ]:     842122 :     if (rA.mbEmbolden != rB.mbEmbolden)
    2315                 :          0 :         return false;
    2316                 :            : 
    2317         [ -  + ]:     842122 :     if (rA.maItalicMatrix != rB.maItalicMatrix)
    2318                 :          0 :         return false;
    2319                 :            : 
    2320                 :    1369369 :     return true;
    2321                 :            : }
    2322                 :            : 
    2323                 :            : // -----------------------------------------------------------------------
    2324                 :            : 
    2325                 :       2379 : ImplFontCache::ImplFontCache( bool bPrinter )
    2326                 :            : :   mpFirstEntry( NULL ),
    2327                 :            :     mnRef0Count( 0 ),
    2328 [ +  - ][ +  - ]:       2379 :     mbPrinter( bPrinter )
    2329                 :       2379 : {}
    2330                 :            : 
    2331                 :            : // -----------------------------------------------------------------------
    2332                 :            : 
    2333         [ +  - ]:       2138 : ImplFontCache::~ImplFontCache()
    2334                 :            : {
    2335         [ +  - ]:       2138 :     FontInstanceList::iterator it = maFontInstanceList.begin();
    2336 [ +  - ][ +  + ]:       7719 :     for(; it != maFontInstanceList.end(); ++it )
    2337                 :            :     {
    2338         [ +  - ]:       5581 :         ImplFontEntry* pEntry = (*it).second;
    2339 [ +  - ][ +  - ]:       5581 :         delete pEntry;
    2340                 :            :     }
    2341                 :       2138 : }
    2342                 :            : 
    2343                 :            : // -----------------------------------------------------------------------
    2344                 :            : 
    2345                 :     841765 : ImplFontEntry* ImplFontCache::GetFontEntry( ImplDevFontList* pFontList,
    2346                 :            :     const Font& rFont, const Size& rSize, float fExactHeight, ImplDirectFontSubstitution* pDevSpecific )
    2347                 :            : {
    2348 [ +  - ][ +  - ]:     841765 :     String aSearchName = rFont.GetName();
    2349                 :            : 
    2350                 :            :     // TODO: also add device specific name caching
    2351         [ +  + ]:     841765 :     if( !pDevSpecific )
    2352                 :            :     {
    2353                 :            :         // check if the requested font name is already known
    2354                 :            :         // if it is already known get its normalized search name
    2355         [ +  - ]:     792741 :         FontNameList::const_iterator it_name = maFontNameList.find( aSearchName );
    2356 [ +  + ][ +  - ]:     792741 :         if( it_name != maFontNameList.end() )
    2357 [ +  - ][ +  - ]:    1571588 :             if( !(*it_name).second.EqualsAscii( "hg", 0, 2)
         [ +  - ][ +  - ]
                 [ +  - ]
    2358                 :            : #ifdef ENABLE_GRAPHITE
    2359         [ +  - ]:     785794 :                 && (aSearchName.Search(grutils::GrFeatureParser::FEAT_PREFIX)
    2360                 :            :                     == STRING_NOTFOUND)
    2361                 :            : #endif
    2362                 :            :             )
    2363 [ +  - ][ +  - ]:     792741 :                 aSearchName = (*it_name).second;
    2364                 :            :     }
    2365                 :            : 
    2366                 :            :     // initialize internal font request object
    2367         [ +  - ]:     841765 :     FontSelectPattern aFontSelData( rFont, aSearchName, rSize, fExactHeight );
    2368 [ +  - ][ +  - ]:     841765 :     return GetFontEntry( pFontList, aFontSelData, pDevSpecific );
                 [ +  - ]
    2369                 :            : }
    2370                 :            : 
    2371                 :            : // -----------------------------------------------------------------------
    2372                 :            : 
    2373                 :     851122 : ImplFontEntry* ImplFontCache::GetFontEntry( ImplDevFontList* pFontList,
    2374                 :            :     FontSelectPattern& aFontSelData, ImplDirectFontSubstitution* pDevSpecific )
    2375                 :            : {
    2376                 :            :     // check if a directly matching logical font instance is already cached,
    2377                 :            :     // the most recently used font usually has a hit rate of >50%
    2378                 :     851122 :     ImplFontEntry *pEntry = NULL;
    2379                 :     851122 :     ImplDevFontListData* pFontFamily = NULL;
    2380                 :            :     IFSD_Equal aIFSD_Equal;
    2381 [ +  + ][ +  - ]:     851122 :     if( mpFirstEntry && aIFSD_Equal( aFontSelData, mpFirstEntry->maFontSelData ) )
         [ +  + ][ +  + ]
    2382                 :     404654 :         pEntry = mpFirstEntry;
    2383                 :            :     else
    2384                 :            :     {
    2385         [ +  - ]:     446468 :         FontInstanceList::iterator it = maFontInstanceList.find( aFontSelData );
    2386 [ +  - ][ +  + ]:     446468 :         if( it != maFontInstanceList.end() )
    2387         [ +  - ]:     446468 :             pEntry = (*it).second;
    2388                 :            :     }
    2389                 :            : 
    2390         [ +  + ]:     851122 :     if( !pEntry ) // no direct cache hit
    2391                 :            :     {
    2392                 :            :         // find the best matching logical font family and update font selector accordingly
    2393         [ +  - ]:     166011 :         pFontFamily = pFontList->ImplFindByFont( aFontSelData, mbPrinter, pDevSpecific );
    2394                 :            :         DBG_ASSERT( (pFontFamily != NULL), "ImplFontCache::Get() No logical font found!" );
    2395         [ +  - ]:     166011 :         if( pFontFamily )
    2396         [ +  - ]:     166011 :             aFontSelData.maSearchName = pFontFamily->GetSearchName();
    2397                 :            : 
    2398                 :            :         // check if an indirectly matching logical font instance is already cached
    2399         [ +  - ]:     166011 :         FontInstanceList::iterator it = maFontInstanceList.find( aFontSelData );
    2400 [ +  - ][ +  + ]:     166011 :         if( it != maFontInstanceList.end() )
    2401                 :            :         {
    2402                 :            :             // we have an indirect cache hit
    2403         [ +  - ]:     157011 :             pEntry = (*it).second;
    2404                 :            :             // cache the requested and the selected font names
    2405                 :            :             // => next time there is a good chance for a direct cache hit
    2406                 :            :             // don't allow the cache to grow too big
    2407                 :            :             // TODO: implement some fancy LRU caching?
    2408         [ -  + ]:     157011 :             if( maFontNameList.size() >= 4000 )
    2409         [ #  # ]:          0 :                 maFontNameList.clear();
    2410                 :            :             // TODO: also add device specific name caching
    2411         [ +  + ]:     157011 :             if( !pDevSpecific )
    2412 [ +  - ][ +  - ]:     108300 :                 if( aFontSelData.maName != aFontSelData.maSearchName )
    2413 [ +  - ][ +  - ]:     166011 :                     maFontNameList[ aFontSelData.maName ] = aFontSelData.maSearchName;
    2414                 :            :         }
    2415                 :            :     }
    2416                 :            : 
    2417                 :     851122 :     PhysicalFontFace* pFontData = NULL;
    2418                 :            : 
    2419 [ +  + ][ +  - ]:     851122 :     if (!pEntry && pFontFamily)// no cache hit => find the best matching physical font face
    2420                 :            :     {
    2421 [ +  + ][ +  + ]:       9000 :         bool bOrigWasSymbol = aFontSelData.mpFontData && aFontSelData.mpFontData->IsSymbolFont();
    2422         [ +  - ]:       9000 :         pFontData = pFontFamily->FindBestFontFace( aFontSelData );
    2423                 :       9000 :         aFontSelData.mpFontData = pFontData;
    2424 [ +  - ][ +  + ]:       9000 :         bool bNewIsSymbol = aFontSelData.mpFontData && aFontSelData.mpFontData->IsSymbolFont();
    2425                 :            : 
    2426         [ +  + ]:       9000 :         if (bNewIsSymbol != bOrigWasSymbol)
    2427                 :            :         {
    2428                 :            :             // it is possible, though generally unlikely, that at this point we
    2429                 :            :             // will attempt to use a symbol font as a last-ditch fallback for a
    2430                 :            :             // non-symbol font request or vice versa, and by changing
    2431                 :            :             // aFontSelData.mpFontData to/from a symbol font we may now find
    2432                 :            :             // something in the cache that can be reused which previously
    2433                 :            :             // wasn't a candidate
    2434         [ +  - ]:       1947 :             FontInstanceList::iterator it = maFontInstanceList.find( aFontSelData );
    2435 [ +  - ][ -  + ]:       1947 :             if( it != maFontInstanceList.end() )
    2436         [ #  # ]:       1947 :                 pEntry = (*it).second;
    2437                 :            :         }
    2438                 :            :     }
    2439                 :            : 
    2440         [ +  + ]:     851122 :     if( pEntry ) // cache hit => use existing font instance
    2441                 :            :     {
    2442                 :            :         // increase the font instance's reference count
    2443         [ +  + ]:     842122 :         if( !pEntry->mnRefCount++ )
    2444                 :     175945 :             --mnRef0Count;
    2445                 :            :     }
    2446                 :            : 
    2447 [ +  + ][ +  - ]:     851122 :     if (!pEntry && pFontData)// still no cache hit => create a new font instance
    2448                 :            :     {
    2449                 :            :         // create a new logical font instance from this physical font face
    2450         [ +  - ]:       9000 :         pEntry = pFontData->CreateFontInstance( aFontSelData );
    2451                 :            : 
    2452                 :            :         // if we found a different symbol font we need a symbol conversion table
    2453         [ +  + ]:       9000 :         if( pFontData->IsSymbolFont() )
    2454 [ +  - ][ +  - ]:       1365 :             if( aFontSelData.maTargetName != aFontSelData.maSearchName )
    2455         [ +  - ]:       1365 :                 pEntry->mpConversion = ConvertChar::GetRecodeData( aFontSelData.maTargetName, aFontSelData.maSearchName );
    2456                 :            : 
    2457                 :            :         // add the new entry to the cache
    2458         [ +  - ]:       9000 :         maFontInstanceList[ aFontSelData ] = pEntry;
    2459                 :            :     }
    2460                 :            : 
    2461                 :     851122 :     mpFirstEntry = pEntry;
    2462                 :     851122 :     return pEntry;
    2463                 :            : }
    2464                 :            : 
    2465                 :            : namespace
    2466                 :            : {
    2467                 :     114983 :     rtl::OUString stripCharSetFromName(rtl::OUString aName)
    2468                 :            :     {
    2469                 :            :         //I worry that someone will have a font which *does* have
    2470                 :            :         //e.g. "Greek" legitimately at the end of its name :-(
    2471                 :            :         const char*suffixes[] =
    2472                 :            :         {
    2473                 :            :             " baltic",
    2474                 :            :             " ce",
    2475                 :            :             " cyr",
    2476                 :            :             " greek",
    2477                 :            :             " tur",
    2478                 :            :             " (arabic)",
    2479                 :            :             " (hebrew)",
    2480                 :            :             " (thai)",
    2481                 :            :             " (vietnamese)"
    2482                 :     114983 :         };
    2483                 :            : 
    2484                 :            :         //These can be crazily piled up, e.g. Times New Roman CYR Greek
    2485                 :     114983 :         bool bFinished = false;
    2486         [ +  + ]:     229966 :         while (!bFinished)
    2487                 :            :         {
    2488                 :     114983 :             bFinished = true;
    2489         [ +  + ]:    1149830 :             for (size_t i = 0; i < SAL_N_ELEMENTS(suffixes); ++i)
    2490                 :            :             {
    2491                 :    1034847 :                 size_t nLen = strlen(suffixes[i]);
    2492         [ -  + ]:    1034847 :                 if (aName.endsWithIgnoreAsciiCaseAsciiL(suffixes[i], nLen))
    2493                 :            :                 {
    2494                 :          0 :                     bFinished = false;
    2495                 :          0 :                     aName = aName.copy(0, aName.getLength() - nLen);
    2496                 :            :                 }
    2497                 :            :             }
    2498                 :            :         }
    2499                 :     114983 :         return aName;
    2500                 :            :     }
    2501                 :            : }
    2502                 :            : 
    2503                 :            : // -----------------------------------------------------------------------
    2504                 :            : 
    2505                 :     166011 : ImplDevFontListData* ImplDevFontList::ImplFindByFont( FontSelectPattern& rFSD,
    2506                 :            :     bool bPrinter, ImplDirectFontSubstitution* pDevSpecific ) const
    2507                 :            : {
    2508                 :            :     // give up if no fonts are available
    2509 [ +  - ][ -  + ]:     166011 :     if( !Count() )
    2510                 :          0 :         return NULL;
    2511                 :            : 
    2512                 :            :     // test if a font in the token list is available
    2513                 :            :     // substitute the font if this was requested
    2514                 :     166011 :     sal_uInt16 nSubstFlags = FONT_SUBSTITUTE_ALWAYS;
    2515         [ +  + ]:     166011 :     if ( bPrinter )
    2516                 :        229 :         nSubstFlags |= FONT_SUBSTITUTE_SCREENONLY;
    2517                 :            : 
    2518                 :     166011 :     bool bMultiToken = false;
    2519                 :     166011 :     xub_StrLen nTokenPos = 0;
    2520                 :     166011 :     String& aSearchName = rFSD.maSearchName; // TODO: get rid of reference
    2521                 :     147379 :     for(;;)
    2522                 :            :     {
    2523 [ +  - ][ +  - ]:     166011 :         rFSD.maTargetName = GetNextFontToken( rFSD.maName, nTokenPos );
                 [ +  - ]
    2524         [ +  - ]:     166011 :         aSearchName = rFSD.maTargetName;
    2525                 :            : 
    2526                 :            : #ifdef ENABLE_GRAPHITE
    2527                 :            :         // Until features are properly supported, they are appended to the
    2528                 :            :         // font name, so we need to strip them off so the font is found.
    2529         [ +  - ]:     166011 :         xub_StrLen nFeat = aSearchName.Search(grutils::GrFeatureParser::FEAT_PREFIX);
    2530         [ +  - ]:     166011 :         String aOrigName = rFSD.maTargetName;
    2531 [ +  - ][ +  - ]:     166011 :         String aBaseFontName(aSearchName, 0, (nFeat != STRING_NOTFOUND)?nFeat:aSearchName.Len());
    2532 [ -  + ][ #  # ]:     166011 :         if (nFeat != STRING_NOTFOUND && STRING_NOTFOUND !=
                 [ -  + ]
    2533         [ #  # ]:          0 :             aSearchName.Search(grutils::GrFeatureParser::FEAT_ID_VALUE_SEPARATOR, nFeat))
    2534                 :            :         {
    2535         [ #  # ]:          0 :             aSearchName = aBaseFontName;
    2536         [ #  # ]:          0 :             rFSD.maTargetName = aBaseFontName;
    2537                 :            :         }
    2538                 :            : 
    2539                 :            : #endif
    2540                 :            : 
    2541         [ +  - ]:     166011 :         GetEnglishSearchFontName( aSearchName );
    2542         [ +  - ]:     166011 :         ImplFontSubstitute( aSearchName, nSubstFlags, pDevSpecific );
    2543                 :            :         // #114999# special emboldening for Ricoh fonts
    2544                 :            :         // TODO: smarter check for special cases by using PreMatch infrastructure?
    2545 [ +  + ][ -  + ]:     203762 :         if( (rFSD.meWeight > WEIGHT_MEDIUM)
                 [ -  + ]
    2546         [ +  - ]:      37751 :         &&  aSearchName.EqualsAscii( "hg", 0, 2) )
    2547                 :            :         {
    2548         [ #  # ]:          0 :             String aBoldName;
    2549 [ #  # ][ #  # ]:          0 :             if( aSearchName.EqualsAscii( "hggothicb", 0, 9) )
    2550 [ #  # ][ #  # ]:          0 :                 aBoldName = String(RTL_CONSTASCII_USTRINGPARAM("hggothice"));
                 [ #  # ]
    2551 [ #  # ][ #  # ]:          0 :             else if( aSearchName.EqualsAscii( "hgpgothicb", 0, 10) )
    2552 [ #  # ][ #  # ]:          0 :                 aBoldName = String(RTL_CONSTASCII_USTRINGPARAM("hgpgothice"));
                 [ #  # ]
    2553 [ #  # ][ #  # ]:          0 :             else if( aSearchName.EqualsAscii( "hgminchol", 0, 9) )
    2554 [ #  # ][ #  # ]:          0 :                 aBoldName = String(RTL_CONSTASCII_USTRINGPARAM("hgminchob"));
                 [ #  # ]
    2555 [ #  # ][ #  # ]:          0 :             else if( aSearchName.EqualsAscii( "hgpminchol", 0, 10) )
    2556 [ #  # ][ #  # ]:          0 :                 aBoldName = String(RTL_CONSTASCII_USTRINGPARAM("hgpminchob"));
                 [ #  # ]
    2557 [ #  # ][ #  # ]:          0 :             else if( aSearchName.EqualsAscii( "hgminchob" ) )
    2558 [ #  # ][ #  # ]:          0 :                 aBoldName = String(RTL_CONSTASCII_USTRINGPARAM("hgminchoe"));
                 [ #  # ]
    2559 [ #  # ][ #  # ]:          0 :             else if( aSearchName.EqualsAscii( "hgpminchob" ) )
    2560 [ #  # ][ #  # ]:          0 :                 aBoldName = String(RTL_CONSTASCII_USTRINGPARAM("hgpminchoe"));
                 [ #  # ]
    2561                 :            : 
    2562 [ #  # ][ #  # ]:          0 :             if( aBoldName.Len() && ImplFindBySearchName( aBoldName ) )
         [ #  # ][ #  # ]
    2563                 :            :             {
    2564                 :            :                 // the other font is available => use it
    2565         [ #  # ]:          0 :                 aSearchName = aBoldName;
    2566                 :            :                 // prevent synthetic emboldening of bold version
    2567                 :          0 :                 rFSD.meWeight = WEIGHT_DONTKNOW;
    2568         [ #  # ]:          0 :             }
    2569                 :            :         }
    2570                 :            : 
    2571                 :            : #ifdef ENABLE_GRAPHITE
    2572                 :            :         // restore the features to make the font selection data unique
    2573         [ +  - ]:     166011 :         rFSD.maTargetName = aOrigName;
    2574                 :            : #endif
    2575                 :            :         // check if the current font name token or its substitute is valid
    2576         [ +  - ]:     166011 :         ImplDevFontListData* pFoundData = ImplFindBySearchName( aSearchName );
    2577         [ +  + ]:     166011 :         if( pFoundData )
    2578                 :      51028 :             return pFoundData;
    2579                 :            : 
    2580                 :            :         // some systems provide special customization
    2581                 :            :         // e.g. they suggest "serif" as UI-font, but this name cannot be used directly
    2582                 :            :         //      because the system wants to map it to another font first, e.g. "Helvetica"
    2583                 :            : #ifdef ENABLE_GRAPHITE
    2584                 :            :         // use the target name to search in the prematch hook
    2585         [ +  - ]:     114983 :         rFSD.maTargetName = aBaseFontName;
    2586                 :            : #endif
    2587                 :            : 
    2588                 :            :         //Related: fdo#49271 RTF files often contain weird-ass
    2589                 :            :         //Win 3.1/Win95 style fontnames which attempt to put the
    2590                 :            :         //charset encoding into the filename
    2591                 :            :         //http://www.webcenter.ru/~kazarn/eng/fonts_ttf.htm
    2592 [ +  - ][ +  - ]:     114983 :         rtl::OUString sStrippedName = stripCharSetFromName(rFSD.maTargetName);
    2593 [ -  + ][ +  - ]:     114983 :         if (!sStrippedName.equals(rFSD.maTargetName))
    2594                 :            :         {
    2595         [ #  # ]:          0 :             rFSD.maTargetName = sStrippedName;
    2596         [ #  # ]:          0 :             aSearchName = rFSD.maTargetName;
    2597         [ #  # ]:          0 :             GetEnglishSearchFontName(aSearchName);
    2598         [ #  # ]:          0 :             pFoundData = ImplFindBySearchName(aSearchName);
    2599         [ #  # ]:          0 :             if( pFoundData )
    2600                 :          0 :                 return pFoundData;
    2601                 :            :         }
    2602                 :            : 
    2603         [ +  - ]:     114983 :         if( mpPreMatchHook )
    2604                 :            :         {
    2605 [ +  - ][ +  + ]:     114983 :             if( mpPreMatchHook->FindFontSubstitute( rFSD ) )
    2606         [ +  - ]:      96351 :                 GetEnglishSearchFontName( aSearchName );
    2607                 :            :         }
    2608                 :            : #ifdef ENABLE_GRAPHITE
    2609                 :            :         // the prematch hook uses the target name to search, but we now need
    2610                 :            :         // to restore the features to make the font selection data unique
    2611         [ +  - ]:     114983 :         rFSD.maTargetName = aOrigName;
    2612                 :            : #endif
    2613         [ +  - ]:     114983 :         pFoundData = ImplFindBySearchName( aSearchName );
    2614         [ +  + ]:     114983 :         if( pFoundData )
    2615                 :      96351 :             return pFoundData;
    2616                 :            : 
    2617                 :            :         // break after last font name token was checked unsuccessfully
    2618         [ +  - ]:      18632 :         if( nTokenPos == STRING_NOTFOUND)
    2619                 :            :             break;
    2620      [ +  +  - ]:     114983 :         bMultiToken = true;
    2621         [ +  - ]:     280994 :     }
              [ +  +  - ]
                 [ +  - ]
              [ -  +  + ]
    2622                 :            : 
    2623                 :            :     // if the first font was not available find the next available font in
    2624                 :            :     // the semicolon separated list of font names. A font is also considered
    2625                 :            :     // available when there is a matching entry in the Tools->Options->Fonts
    2626                 :            :     // dialog witho neither ALWAYS nor SCREENONLY flags set and the substitution
    2627                 :            :     // font is available
    2628         [ +  + ]:      37264 :     for( nTokenPos = 0; nTokenPos != STRING_NOTFOUND; )
    2629                 :            :     {
    2630         [ -  + ]:      18632 :         if( bMultiToken )
    2631                 :            :         {
    2632 [ #  # ][ #  # ]:          0 :             rFSD.maTargetName = GetNextFontToken( rFSD.maName, nTokenPos );
                 [ #  # ]
    2633         [ #  # ]:          0 :             aSearchName = rFSD.maTargetName;
    2634         [ #  # ]:          0 :             GetEnglishSearchFontName( aSearchName );
    2635                 :            :         }
    2636                 :            :         else
    2637                 :      18632 :             nTokenPos = STRING_NOTFOUND;
    2638         [ +  - ]:      18632 :         if( mpPreMatchHook )
    2639 [ +  - ][ -  + ]:      18632 :             if( mpPreMatchHook->FindFontSubstitute( rFSD ) )
    2640         [ #  # ]:          0 :                 GetEnglishSearchFontName( aSearchName );
    2641         [ +  - ]:      18632 :         ImplFontSubstitute( aSearchName, nSubstFlags, pDevSpecific );
    2642         [ +  - ]:      18632 :         ImplDevFontListData* pFoundData = ImplFindBySearchName( aSearchName );
    2643         [ -  + ]:      18632 :         if( pFoundData )
    2644                 :          0 :             return pFoundData;
    2645                 :            :     }
    2646                 :            : 
    2647                 :            :     // if no font with a directly matching name is available use the
    2648                 :            :     // first font name token and get its attributes to find a replacement
    2649         [ -  + ]:      18632 :     if ( bMultiToken )
    2650                 :            :     {
    2651                 :          0 :         nTokenPos = 0;
    2652 [ #  # ][ #  # ]:          0 :         rFSD.maTargetName = GetNextFontToken( rFSD.maName, nTokenPos );
                 [ #  # ]
    2653         [ #  # ]:          0 :         aSearchName = rFSD.maTargetName;
    2654         [ #  # ]:          0 :         GetEnglishSearchFontName( aSearchName );
    2655                 :            :     }
    2656                 :            : 
    2657         [ +  - ]:      18632 :     String      aSearchShortName;
    2658         [ +  - ]:      18632 :     String      aSearchFamilyName;
    2659                 :      18632 :     FontWeight  eSearchWeight   = rFSD.meWeight;
    2660                 :      18632 :     FontWidth   eSearchWidth    = rFSD.meWidthType;
    2661                 :      18632 :     sal_uLong       nSearchType     = 0;
    2662                 :            :     FontSubstConfiguration::getMapName( aSearchName, aSearchShortName, aSearchFamilyName,
    2663         [ +  - ]:      18632 :                                         eSearchWeight, eSearchWidth, nSearchType );
    2664                 :            : 
    2665                 :            :     // note: the search name was already translated to english (if possible)
    2666                 :            : 
    2667                 :            :     // use the font's shortened name if needed
    2668 [ +  - ][ -  + ]:      18632 :     if ( aSearchShortName != aSearchName )
    2669                 :            :     {
    2670         [ #  # ]:          0 :        ImplDevFontListData* pFoundData = ImplFindBySearchName( aSearchShortName );
    2671         [ #  # ]:          0 :        if( pFoundData )
    2672                 :            :        {
    2673                 :            : #ifdef UNX
    2674                 :            :             /* #96738# don't use mincho as an replacement for "MS Mincho" on X11: Mincho is
    2675                 :            :             a korean bitmap font that is not suitable here. Use the font replacement table,
    2676                 :            :             that automatically leads to the desired "HG Mincho Light J". Same story for
    2677                 :            :             MS Gothic, there are thai and korean "Gothic" fonts, so we even prefer Andale */
    2678 [ #  # ][ #  # ]:          0 :             static String aMS_Mincho( RTL_CONSTASCII_USTRINGPARAM("msmincho") );
         [ #  # ][ #  # ]
    2679 [ #  # ][ #  # ]:          0 :             static String aMS_Gothic( RTL_CONSTASCII_USTRINGPARAM("msgothic") );
         [ #  # ][ #  # ]
    2680 [ #  # ][ #  # ]:          0 :             if ((aSearchName != aMS_Mincho) && (aSearchName != aMS_Gothic))
         [ #  # ][ #  # ]
                 [ #  # ]
    2681                 :            :                 // TODO: add heuristic to only throw out the fake ms* fonts
    2682                 :            : #endif
    2683                 :            :             {
    2684                 :          0 :                 return pFoundData;
    2685                 :            :             }
    2686                 :            :         }
    2687                 :            :     }
    2688                 :            : 
    2689                 :            :     // use font fallback
    2690                 :      18632 :     const FontNameAttr* pFontAttr = NULL;
    2691         [ +  - ]:      18632 :     if( aSearchName.Len() )
    2692                 :            :     {
    2693                 :            :         // get fallback info using FontSubstConfiguration and
    2694                 :            :         // the target name, it's shortened name and family name in that order
    2695         [ +  - ]:      18632 :         const FontSubstConfiguration& rFontSubst = FontSubstConfiguration::get();
    2696 [ +  - ][ +  - ]:      18632 :         pFontAttr = rFontSubst.getSubstInfo( aSearchName );
    2697 [ #  # ][ #  # ]:      18632 :         if ( !pFontAttr && (aSearchShortName != aSearchName) )
         [ -  + ][ -  + ]
    2698 [ #  # ][ #  # ]:          0 :             pFontAttr = rFontSubst.getSubstInfo( aSearchShortName );
    2699 [ -  + ][ #  # ]:      18632 :         if ( !pFontAttr && (aSearchFamilyName != aSearchShortName) )
         [ #  # ][ -  + ]
    2700 [ #  # ][ #  # ]:          0 :             pFontAttr = rFontSubst.getSubstInfo( aSearchFamilyName );
    2701                 :            : 
    2702                 :            :         // try the font substitutions suggested by the fallback info
    2703         [ +  - ]:      18632 :         if( pFontAttr )
    2704                 :            :         {
    2705         [ +  - ]:      18632 :             ImplDevFontListData* pFoundData = ImplFindBySubstFontAttr( *pFontAttr );
    2706         [ +  - ]:      18632 :             if( pFoundData )
    2707                 :      18632 :                 return pFoundData;
    2708                 :            :         }
    2709                 :            :     }
    2710                 :            : 
    2711                 :            :     // if a target symbol font is not available use a default symbol font
    2712         [ #  # ]:          0 :     if( rFSD.IsSymbolFont() )
    2713                 :            :     {
    2714         [ #  # ]:          0 :         com::sun::star::lang::Locale aDefaultLocale( OUString( RTL_CONSTASCII_USTRINGPARAM("en") ), OUString(), OUString() );
    2715 [ #  # ][ #  # ]:          0 :         aSearchName = DefaultFontConfiguration::get().getDefaultFont( aDefaultLocale, DEFAULTFONT_SYMBOL );
                 [ #  # ]
    2716 [ #  # ][ #  # ]:          0 :         ImplDevFontListData* pFoundData = ImplFindByTokenNames( aSearchName );
    2717         [ #  # ]:          0 :         if( pFoundData )
    2718         [ #  # ]:          0 :             return pFoundData;
    2719                 :            :     }
    2720                 :            : 
    2721                 :            :     // now try the other font name tokens
    2722         [ #  # ]:          0 :     while( nTokenPos != STRING_NOTFOUND )
    2723                 :            :     {
    2724 [ #  # ][ #  # ]:          0 :         rFSD.maTargetName = GetNextFontToken( rFSD.maName, nTokenPos );
                 [ #  # ]
    2725         [ #  # ]:          0 :         if( !rFSD.maTargetName.Len() )
    2726                 :          0 :             continue;
    2727                 :            : 
    2728         [ #  # ]:          0 :         aSearchName = rFSD.maTargetName;
    2729         [ #  # ]:          0 :         GetEnglishSearchFontName( aSearchName );
    2730                 :            : 
    2731         [ #  # ]:          0 :         String      aTempShortName;
    2732         [ #  # ]:          0 :         String      aTempFamilyName;
    2733                 :          0 :         sal_uLong       nTempType   = 0;
    2734                 :          0 :         FontWeight  eTempWeight = rFSD.meWeight;
    2735                 :          0 :         FontWidth   eTempWidth  = WIDTH_DONTKNOW;
    2736                 :            :         FontSubstConfiguration::getMapName( aSearchName, aTempShortName, aTempFamilyName,
    2737         [ #  # ]:          0 :                                             eTempWeight, eTempWidth, nTempType );
    2738                 :            : 
    2739                 :            :         // use a shortend token name if available
    2740 [ #  # ][ #  # ]:          0 :         if( aTempShortName != aSearchName )
    2741                 :            :         {
    2742         [ #  # ]:          0 :             ImplDevFontListData* pFoundData = ImplFindBySearchName( aTempShortName );
    2743         [ #  # ]:          0 :             if( pFoundData )
    2744                 :          0 :                 return pFoundData;
    2745                 :            :         }
    2746                 :            : 
    2747                 :            :         // use a font name from font fallback list to determine font attributes
    2748                 :            : 
    2749                 :            :         // get fallback info using FontSubstConfiguration and
    2750                 :            :         // the target name, it's shortened name and family name in that order
    2751         [ #  # ]:          0 :         const FontSubstConfiguration& rFontSubst = FontSubstConfiguration::get();
    2752 [ #  # ][ #  # ]:          0 :         const FontNameAttr* pTempFontAttr = rFontSubst.getSubstInfo( aSearchName );
    2753 [ #  # ][ #  # ]:          0 :         if ( !pTempFontAttr && (aTempShortName != aSearchName) )
         [ #  # ][ #  # ]
    2754 [ #  # ][ #  # ]:          0 :             pTempFontAttr = rFontSubst.getSubstInfo( aTempShortName );
    2755 [ #  # ][ #  # ]:          0 :         if ( !pTempFontAttr && (aTempFamilyName != aTempShortName) )
         [ #  # ][ #  # ]
    2756 [ #  # ][ #  # ]:          0 :             pTempFontAttr = rFontSubst.getSubstInfo( aTempFamilyName );
    2757                 :            : 
    2758                 :            :         // try the font substitutions suggested by the fallback info
    2759         [ #  # ]:          0 :         if( pTempFontAttr )
    2760                 :            :         {
    2761         [ #  # ]:          0 :             ImplDevFontListData* pFoundData = ImplFindBySubstFontAttr( *pTempFontAttr );
    2762         [ #  # ]:          0 :             if( pFoundData )
    2763                 :          0 :                 return pFoundData;
    2764         [ #  # ]:          0 :             if( !pFontAttr )
    2765                 :          0 :                 pFontAttr = pTempFontAttr;
    2766                 :            :         }
    2767 [ #  # ][ #  # ]:          0 :     }
         [ #  # ][ #  # ]
    2768                 :            : 
    2769                 :            :     // if still needed use the alias names of the installed fonts
    2770         [ #  # ]:          0 :     if( mbMapNames )
    2771                 :            :     {
    2772 [ #  # ][ #  # ]:          0 :         ImplDevFontListData* pFoundData = ImplFindByAliasName( rFSD.maTargetName, aSearchShortName );
                 [ #  # ]
    2773         [ #  # ]:          0 :         if( pFoundData )
    2774                 :          0 :             return pFoundData;
    2775                 :            :     }
    2776                 :            : 
    2777                 :            :     // if still needed use the font request's attributes to find a good match
    2778 [ #  # ][ #  # ]:          0 :     if (MsLangId::isSimplifiedChinese(rFSD.meLanguage))
    2779                 :          0 :         nSearchType |= IMPL_FONT_ATTR_CJK | IMPL_FONT_ATTR_CJK_SC;
    2780 [ #  # ][ #  # ]:          0 :     else if (MsLangId::isTraditionalChinese(rFSD.meLanguage))
    2781                 :          0 :         nSearchType |= IMPL_FONT_ATTR_CJK | IMPL_FONT_ATTR_CJK_TC;
    2782 [ #  # ][ #  # ]:          0 :     else if (MsLangId::isKorean(rFSD.meLanguage))
    2783                 :          0 :         nSearchType |= IMPL_FONT_ATTR_CJK | IMPL_FONT_ATTR_CJK_KR;
    2784         [ #  # ]:          0 :     else if (rFSD.meLanguage == LANGUAGE_JAPANESE)
    2785                 :          0 :         nSearchType |= IMPL_FONT_ATTR_CJK | IMPL_FONT_ATTR_CJK_JP;
    2786                 :            :     else
    2787                 :            :     {
    2788                 :          0 :         nSearchType |= ImplIsCJKFont( rFSD.maName );
    2789         [ #  # ]:          0 :         if( rFSD.IsSymbolFont() )
    2790                 :          0 :             nSearchType |= IMPL_FONT_ATTR_SYMBOL;
    2791                 :            :     }
    2792                 :            : 
    2793                 :          0 :     ImplCalcType( nSearchType, eSearchWeight, eSearchWidth, rFSD.meFamily, pFontAttr );
    2794                 :            :     ImplDevFontListData* pFoundData = ImplFindByAttributes( nSearchType,
    2795 [ #  # ][ #  # ]:          0 :         eSearchWeight, eSearchWidth, rFSD.meItalic, aSearchFamilyName );
    2796                 :            : 
    2797         [ #  # ]:          0 :     if( pFoundData )
    2798                 :            :     {
    2799                 :            :         // overwrite font selection attributes using info from the typeface flags
    2800 [ #  # ][ #  # ]:          0 :         if( (eSearchWeight >= WEIGHT_BOLD)
                 [ #  # ]
    2801                 :            :         &&  (eSearchWeight > rFSD.meWeight)
    2802                 :            :         &&  (pFoundData->mnTypeFaces & IMPL_DEVFONT_BOLD) )
    2803                 :          0 :             rFSD.meWeight = eSearchWeight;
    2804 [ #  # ][ #  # ]:          0 :         else if( (eSearchWeight < WEIGHT_NORMAL)
         [ #  # ][ #  # ]
    2805                 :            :         &&  (eSearchWeight < rFSD.meWeight)
    2806                 :            :         &&  (eSearchWeight != WEIGHT_DONTKNOW)
    2807                 :            :         &&  (pFoundData->mnTypeFaces & IMPL_DEVFONT_LIGHT) )
    2808                 :          0 :             rFSD.meWeight = eSearchWeight;
    2809                 :            : 
    2810 [ #  # ][ #  # ]:          0 :         if( (nSearchType & IMPL_FONT_ATTR_ITALIC)
         [ #  # ][ #  # ]
    2811                 :            :         &&  ((rFSD.meItalic == ITALIC_DONTKNOW) || (rFSD.meItalic == ITALIC_NONE))
    2812                 :            :         &&  (pFoundData->mnTypeFaces & IMPL_DEVFONT_ITALIC) )
    2813                 :          0 :             rFSD.meItalic = ITALIC_NORMAL;
    2814                 :            :     }
    2815                 :            :     else
    2816                 :            :     {
    2817                 :            :         // if still needed fall back to default fonts
    2818         [ #  # ]:          0 :         pFoundData = FindDefaultFont();
    2819                 :            :     }
    2820                 :            : 
    2821 [ +  - ][ +  - ]:     166011 :     return pFoundData;
    2822                 :            : }
    2823                 :            : 
    2824                 :            : // -----------------------------------------------------------------------
    2825                 :            : 
    2826                 :       9357 : ImplFontEntry* ImplFontCache::GetGlyphFallbackFont( ImplDevFontList* pFontList,
    2827                 :            :     FontSelectPattern& rFontSelData, int nFallbackLevel, rtl::OUString& rMissingCodes )
    2828                 :            : {
    2829                 :            :     // get a candidate font for glyph fallback
    2830                 :            :     // unless the previously selected font got a device specific substitution
    2831                 :            :     // e.g. PsPrint Arial->Helvetica for udiaeresis when Helvetica doesn't support it
    2832         [ +  - ]:       9357 :     if( nFallbackLevel >= 1)
    2833                 :            :     {
    2834                 :       9357 :         ImplDevFontListData* pFallbackData = NULL;
    2835                 :            : 
    2836                 :            :         //fdo#33898 If someone has EUDC installed then they really want that to
    2837                 :            :         //be used as the first-choice glyph fallback seeing as it's filled with
    2838                 :            :         //private area codes with don't make any sense in any other font so
    2839                 :            :         //prioritise it here if it's available. Ideally we would remove from
    2840                 :            :         //rMissingCodes all the glyphs which it is able to resolve as an
    2841                 :            :         //optimization, but that's tricky to achieve cross-platform without
    2842                 :            :         //sufficient heavy-weight code that's likely to undo the value of the
    2843                 :            :         //optimization
    2844         [ +  - ]:       9357 :         if (nFallbackLevel == 1)
    2845 [ +  - ][ +  - ]:       9357 :             pFallbackData = pFontList->FindFontFamily(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("EUDC")));
                 [ +  - ]
    2846         [ +  - ]:       9357 :         if (!pFallbackData)
    2847                 :       9357 :             pFallbackData = pFontList->GetGlyphFallbackFont(rFontSelData, rMissingCodes, nFallbackLevel-1);
    2848                 :            :         // escape when there are no font candidates
    2849         [ -  + ]:       9357 :         if( !pFallbackData  )
    2850                 :          0 :             return NULL;
    2851                 :            :         // override the font name
    2852                 :       9357 :         rFontSelData.maName = pFallbackData->GetFamilyName();
    2853                 :            :         // clear the cached normalized name
    2854         [ +  - ]:       9357 :         rFontSelData.maSearchName = String();
    2855                 :            :     }
    2856                 :            : 
    2857                 :            :     // get device font without doing device specific substitutions
    2858                 :       9357 :     ImplFontEntry* pFallbackFont = GetFontEntry( pFontList, rFontSelData, NULL );
    2859                 :       9357 :     return pFallbackFont;
    2860                 :            : }
    2861                 :            : 
    2862                 :            : // -----------------------------------------------------------------------
    2863                 :            : 
    2864                 :     753509 : void ImplFontCache::Release( ImplFontEntry* pEntry )
    2865                 :            : {
    2866                 :            :     static const int FONTCACHE_MAX = 50;
    2867                 :            : 
    2868                 :            :     DBG_ASSERT( (pEntry->mnRefCount > 0), "ImplFontCache::Release() - font refcount underflow" );
    2869         [ +  + ]:     753509 :     if( --pEntry->mnRefCount > 0 )
    2870                 :            :         return;
    2871                 :            : 
    2872         [ +  + ]:     183740 :     if( ++mnRef0Count < FONTCACHE_MAX )
    2873                 :            :         return;
    2874                 :            : 
    2875                 :            :     // remove unused entries from font instance cache
    2876         [ +  - ]:         27 :     FontInstanceList::iterator it_next = maFontInstanceList.begin();
    2877 [ +  - ][ +  + ]:     755091 :     while( it_next != maFontInstanceList.end() )
    2878                 :            :     {
    2879         [ +  - ]:       1582 :         FontInstanceList::iterator it = it_next++;
    2880         [ +  - ]:       1582 :         ImplFontEntry* pFontEntry = (*it).second;
    2881         [ +  + ]:       1582 :         if( pFontEntry->mnRefCount > 0 )
    2882                 :        232 :             continue;
    2883                 :            : 
    2884         [ +  - ]:       1350 :         maFontInstanceList.erase( it );
    2885 [ +  - ][ +  - ]:       1350 :         delete pFontEntry;
    2886                 :       1350 :         --mnRef0Count;
    2887                 :            :         DBG_ASSERT( (mnRef0Count>=0), "ImplFontCache::Release() - refcount0 underflow" );
    2888                 :            : 
    2889         [ +  + ]:       1350 :         if( mpFirstEntry == pFontEntry )
    2890                 :       1350 :             mpFirstEntry = NULL;
    2891                 :            :     }
    2892                 :            : 
    2893                 :            :     DBG_ASSERT( (mnRef0Count==0), "ImplFontCache::Release() - refcount0 mismatch" );
    2894                 :            : }
    2895                 :            : 
    2896                 :            : // -----------------------------------------------------------------------
    2897                 :            : 
    2898                 :          5 : void ImplFontCache::Invalidate()
    2899                 :            : {
    2900                 :            :     // delete unreferenced entries
    2901         [ +  - ]:          5 :     FontInstanceList::iterator it = maFontInstanceList.begin();
    2902 [ +  - ][ -  + ]:          5 :     for(; it != maFontInstanceList.end(); ++it )
    2903                 :            :     {
    2904         [ #  # ]:          0 :         ImplFontEntry* pFontEntry = (*it).second;
    2905         [ #  # ]:          0 :         if( pFontEntry->mnRefCount > 0 )
    2906                 :          0 :             continue;
    2907                 :            : 
    2908 [ #  # ][ #  # ]:          0 :         delete pFontEntry;
    2909                 :          0 :         --mnRef0Count;
    2910                 :            :     }
    2911                 :            : 
    2912                 :            :     // #112304# make sure the font cache is really clean
    2913                 :          5 :     mpFirstEntry = NULL;
    2914         [ +  - ]:          5 :     maFontInstanceList.clear();
    2915                 :            : 
    2916                 :            :     DBG_ASSERT( (mnRef0Count==0), "ImplFontCache::Invalidate() - mnRef0Count non-zero" );
    2917                 :          5 : }
    2918                 :            : 
    2919                 :            : // =======================================================================
    2920                 :            : 
    2921                 :       2634 : ImplMultiTextLineInfo::ImplMultiTextLineInfo()
    2922                 :            : {
    2923                 :       2634 :     mpLines = new PImplTextLineInfo[MULTITEXTLINEINFO_RESIZE];
    2924                 :       2634 :     mnLines = 0;
    2925                 :       2634 :     mnSize  = MULTITEXTLINEINFO_RESIZE;
    2926                 :       2634 : }
    2927                 :            : 
    2928                 :            : 
    2929                 :       2634 : ImplMultiTextLineInfo::~ImplMultiTextLineInfo()
    2930                 :            : {
    2931         [ +  + ]:       5038 :     for ( xub_StrLen i = 0; i < mnLines; i++ )
    2932                 :       2404 :         delete mpLines[i];
    2933         [ +  - ]:       2634 :     delete [] mpLines;
    2934                 :       2634 : }
    2935                 :            : 
    2936                 :       2404 : void ImplMultiTextLineInfo::AddLine( ImplTextLineInfo* pLine )
    2937                 :            : {
    2938         [ -  + ]:       2404 :     if ( mnSize == mnLines )
    2939                 :            :     {
    2940                 :          0 :         mnSize += MULTITEXTLINEINFO_RESIZE;
    2941                 :          0 :         PImplTextLineInfo* pNewLines = new PImplTextLineInfo[mnSize];
    2942                 :          0 :         memcpy( pNewLines, mpLines, mnLines*sizeof(PImplTextLineInfo) );
    2943                 :          0 :         mpLines = pNewLines;
    2944                 :            :     }
    2945                 :            : 
    2946                 :       2404 :     mpLines[mnLines] = pLine;
    2947                 :       2404 :     mnLines++;
    2948                 :       2404 : }
    2949                 :            : 
    2950                 :       2634 : void ImplMultiTextLineInfo::Clear()
    2951                 :            : {
    2952         [ -  + ]:       2634 :     for ( xub_StrLen i = 0; i < mnLines; i++ )
    2953                 :          0 :         delete mpLines[i];
    2954                 :       2634 :     mnLines = 0;
    2955                 :       2634 : }
    2956                 :            : 
    2957                 :            : // =======================================================================
    2958                 :            : 
    2959                 :      69806 : FontEmphasisMark OutputDevice::ImplGetEmphasisMarkStyle( const Font& rFont )
    2960                 :            : {
    2961                 :      69806 :     FontEmphasisMark nEmphasisMark = rFont.GetEmphasisMark();
    2962                 :            : 
    2963                 :            :     // If no Position is set, then calculate the default position, which
    2964                 :            :     // depends on the language
    2965         [ +  + ]:      69806 :     if ( !(nEmphasisMark & (EMPHASISMARK_POS_ABOVE | EMPHASISMARK_POS_BELOW)) )
    2966                 :            :     {
    2967                 :      11727 :         LanguageType eLang = rFont.GetLanguage();
    2968                 :            :         // In Chinese Simplified the EmphasisMarks are below/left
    2969         [ -  + ]:      11727 :         if (MsLangId::isSimplifiedChinese(eLang))
    2970                 :          0 :             nEmphasisMark |= EMPHASISMARK_POS_BELOW;
    2971                 :            :         else
    2972                 :            :         {
    2973                 :      11727 :             eLang = rFont.GetCJKContextLanguage();
    2974                 :            :             // In Chinese Simplified the EmphasisMarks are below/left
    2975         [ -  + ]:      11727 :             if (MsLangId::isSimplifiedChinese(eLang))
    2976                 :          0 :                 nEmphasisMark |= EMPHASISMARK_POS_BELOW;
    2977                 :            :             else
    2978                 :      11727 :                 nEmphasisMark |= EMPHASISMARK_POS_ABOVE;
    2979                 :            :         }
    2980                 :            :     }
    2981                 :            : 
    2982                 :      69806 :     return nEmphasisMark;
    2983                 :            : }
    2984                 :            : 
    2985                 :            : // -----------------------------------------------------------------------
    2986                 :            : 
    2987                 :      15446 : sal_Bool OutputDevice::ImplIsUnderlineAbove( const Font& rFont )
    2988                 :            : {
    2989         [ +  - ]:      15446 :     if ( !rFont.IsVertical() )
    2990                 :      15446 :         return sal_False;
    2991                 :            : 
    2992   [ #  #  #  # ]:          0 :     if( (LANGUAGE_JAPANESE == rFont.GetLanguage())
                 [ #  # ]
    2993                 :          0 :     ||  (LANGUAGE_JAPANESE == rFont.GetCJKContextLanguage()) )
    2994                 :            :         // the underline is right for Japanese only
    2995                 :          0 :         return sal_True;
    2996                 :            : 
    2997                 :      15446 :     return sal_False;
    2998                 :            : }
    2999                 :            : 
    3000                 :            : // =======================================================================
    3001                 :            : 
    3002                 :    1368848 : void OutputDevice::ImplInitFontList() const
    3003                 :            : {
    3004         [ +  + ]:    1368848 :     if( ! mpFontList->Count() )
    3005                 :            :     {
    3006 [ -  + ][ #  # ]:        242 :         if( mpGraphics || ImplGetGraphics() )
                 [ +  - ]
    3007                 :            :         {
    3008                 :            :             RTL_LOGFILE_CONTEXT( aLog, "OutputDevice::ImplInitFontList()" );
    3009                 :        242 :             mpGraphics->GetDevFontList( mpFontList );
    3010                 :            :         }
    3011                 :            :     }
    3012 [ +  + ][ -  + ]:    1368848 :     if( meOutDevType == OUTDEV_WINDOW && ! mpFontList->Count() )
                 [ -  + ]
    3013                 :            :     {
    3014         [ #  # ]:          0 :         String aError( RTL_CONSTASCII_USTRINGPARAM( "Application error: no fonts and no vcl resource found on your system" ) );
    3015         [ #  # ]:          0 :         ResMgr* pMgr = ImplGetResMgr();
    3016         [ #  # ]:          0 :         if( pMgr )
    3017                 :            :         {
    3018 [ #  # ][ #  # ]:          0 :             String aResStr(ResId(SV_ACCESSERROR_NO_FONTS, *pMgr).toString());
    3019         [ #  # ]:          0 :             if( aResStr.Len() )
    3020 [ #  # ][ #  # ]:          0 :                 aError = aResStr;
    3021                 :            :         }
    3022 [ #  # ][ #  # ]:          0 :         Application::Abort( aError );
    3023                 :            :     }
    3024                 :    1368848 : }
    3025                 :            : 
    3026                 :            : // =======================================================================
    3027                 :            : 
    3028                 :     183958 : void OutputDevice::ImplInitFont() const
    3029                 :            : {
    3030                 :            :     DBG_TESTSOLARMUTEX();
    3031                 :            : 
    3032         [ -  + ]:     183958 :     if (!mpFontEntry)
    3033                 :     183958 :         return;
    3034                 :            : 
    3035         [ +  - ]:     183958 :     if ( mbInitFont )
    3036                 :            :     {
    3037         [ +  + ]:     183958 :         if ( meOutDevType != OUTDEV_PRINTER )
    3038                 :            :         {
    3039                 :            :             // decide if antialiasing is appropriate
    3040                 :     183645 :             bool bNonAntialiased = (GetAntialiasing() & ANTIALIASING_DISABLE_TEXT) != 0;
    3041                 :     183645 :             const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
    3042                 :     183645 :             bNonAntialiased |= ((rStyleSettings.GetDisplayOptions() & DISPLAY_OPTION_AA_DISABLE) != 0);
    3043                 :     183645 :             bNonAntialiased |= (int(rStyleSettings.GetAntialiasingMinPixelHeight()) > mpFontEntry->maFontSelData.mnHeight);
    3044                 :     183645 :             mpFontEntry->maFontSelData.mbNonAntialiased = bNonAntialiased;
    3045                 :            :         }
    3046                 :            : 
    3047 [ -  + ][ #  # ]:     183958 :         if( !mpPDFWriter || !mpPDFWriter->isBuiltinFont( mpFontEntry->maFontSelData.mpFontData ) )
                 [ +  - ]
    3048                 :            :         {
    3049                 :            :             // select font in the device layers
    3050                 :     183958 :             mpFontEntry->mnSetFontFlags = mpGraphics->SetFont( &(mpFontEntry->maFontSelData), 0 );
    3051                 :            :         }
    3052                 :     183958 :         mbInitFont = false;
    3053                 :            :     }
    3054                 :            : }
    3055                 :            : 
    3056                 :            : // -----------------------------------------------------------------------
    3057                 :            : 
    3058                 :      61581 : void OutputDevice::ImplInitTextColor()
    3059                 :            : {
    3060                 :            :     DBG_TESTSOLARMUTEX();
    3061                 :            : 
    3062         [ +  + ]:      61581 :     if ( mbInitTextColor )
    3063                 :            :     {
    3064                 :      56597 :         mpGraphics->SetTextColor( ImplColorToSal( GetTextColor() ) );
    3065                 :      56597 :         mbInitTextColor = sal_False;
    3066                 :            :     }
    3067                 :      61581 : }
    3068                 :            : 
    3069                 :            : // -----------------------------------------------------------------------
    3070                 :            : 
    3071                 :    1111898 : bool OutputDevice::ImplNewFont() const
    3072                 :            : {
    3073                 :            :     DBG_TESTSOLARMUTEX();
    3074                 :            : 
    3075                 :            :     // get correct font list on the PDF writer if necessary
    3076         [ -  + ]:    1111898 :     if( mpPDFWriter )
    3077                 :            :     {
    3078         [ #  # ]:          0 :         const ImplSVData* pSVData = ImplGetSVData();
    3079 [ #  # ][ #  # ]:          0 :         if( mpFontList == pSVData->maGDIData.mpScreenFontList
    3080                 :            :         ||  mpFontCache == pSVData->maGDIData.mpScreenFontCache )
    3081         [ #  # ]:          0 :             const_cast<OutputDevice&>(*this).ImplUpdateFontData( true );
    3082                 :            :     }
    3083                 :            : 
    3084         [ +  + ]:    1111898 :     if ( !mbNewFont )
    3085                 :     367515 :         return true;
    3086                 :            : 
    3087                 :            :     // we need a graphics
    3088 [ +  + ][ +  - ]:     744383 :     if ( !mpGraphics && !ImplGetGraphics() )
         [ -  + ][ -  + ]
    3089                 :          0 :         return false;
    3090                 :     744383 :     SalGraphics* pGraphics = mpGraphics;
    3091         [ +  - ]:     744383 :     ImplInitFontList();
    3092                 :            : 
    3093                 :            :     // convert to pixel height
    3094                 :            :     // TODO: replace integer based aSize completely with subpixel accurate type
    3095 [ +  - ][ +  - ]:     744383 :     float fExactHeight = ImplFloatLogicHeightToDevicePixel( static_cast<float>(maFont.GetHeight()) );
    3096 [ +  - ][ +  - ]:     744383 :     Size aSize = ImplLogicToDevicePixel( maFont.GetSize() );
    3097         [ +  + ]:     744383 :     if ( !aSize.Height() )
    3098                 :            :     {
    3099                 :            :         // use default pixel height only when logical height is zero
    3100 [ +  - ][ -  + ]:         99 :         if ( maFont.GetSize().Height() )
    3101                 :          0 :             aSize.Height() = 1;
    3102                 :            :         else
    3103                 :         99 :             aSize.Height() = (12*mnDPIY)/72;
    3104                 :         99 :         fExactHeight =  static_cast<float>(aSize.Height());
    3105                 :            :     }
    3106                 :            : 
    3107                 :            :     // select the default width only when logical width is zero
    3108 [ +  + ][ +  - ]:     744383 :     if( (0 == aSize.Width()) && (0 != maFont.GetSize().Width()) )
         [ +  + ][ +  + ]
    3109                 :        114 :         aSize.Width() = 1;
    3110                 :            : 
    3111                 :            :     // get font entry
    3112                 :     744383 :     ImplDirectFontSubstitution* pDevSpecificSubst = NULL;
    3113         [ +  + ]:     744383 :     if( mpOutDevData )
    3114                 :      49024 :         pDevSpecificSubst = &mpOutDevData->maDevFontSubst;
    3115                 :     744383 :     ImplFontEntry* pOldEntry = mpFontEntry;
    3116         [ +  - ]:     744383 :     mpFontEntry = mpFontCache->GetFontEntry( mpFontList, maFont, aSize, fExactHeight, pDevSpecificSubst );
    3117         [ +  + ]:     744383 :     if( pOldEntry )
    3118         [ +  - ]:     691740 :         mpFontCache->Release( pOldEntry );
    3119                 :            : 
    3120                 :     744383 :     ImplFontEntry* pFontEntry = mpFontEntry;
    3121                 :            : 
    3122         [ -  + ]:     744383 :     if (!pFontEntry)
    3123                 :          0 :         return false;
    3124                 :            : 
    3125                 :            :     // mark when lower layers need to get involved
    3126                 :     744383 :     mbNewFont = sal_False;
    3127         [ +  + ]:     744383 :     if( pFontEntry != pOldEntry )
    3128                 :     267313 :         mbInitFont = sal_True;
    3129                 :            : 
    3130                 :            :     // select font when it has not been initialized yet
    3131         [ +  + ]:     744383 :     if ( !pFontEntry->mbInit )
    3132                 :            :     {
    3133         [ +  - ]:       7334 :         ImplInitFont();
    3134                 :            : 
    3135                 :            :         // get metric data from device layers
    3136         [ +  - ]:       7334 :         if ( pGraphics )
    3137                 :            :         {
    3138                 :       7334 :             pFontEntry->mbInit = true;
    3139                 :            : 
    3140                 :       7334 :             pFontEntry->maMetric.mnOrientation  = sal::static_int_cast<short>(pFontEntry->maFontSelData.mnOrientation);
    3141 [ #  # ][ #  # ]:       7334 :             if( mpPDFWriter && mpPDFWriter->isBuiltinFont( pFontEntry->maFontSelData.mpFontData ) )
         [ -  + ][ -  + ]
    3142         [ #  # ]:          0 :                 mpPDFWriter->getFontMetric( &pFontEntry->maFontSelData, &(pFontEntry->maMetric) );
    3143                 :            :             else
    3144         [ +  - ]:       7334 :                 pGraphics->GetFontMetric( &(pFontEntry->maMetric) );
    3145                 :            : 
    3146                 :       7334 :             pFontEntry->maMetric.ImplInitTextLineSize( this );
    3147                 :       7334 :             pFontEntry->maMetric.ImplInitAboveTextLineSize();
    3148                 :            : 
    3149                 :       7334 :             pFontEntry->mnLineHeight = pFontEntry->maMetric.mnAscent + pFontEntry->maMetric.mnDescent;
    3150                 :            : 
    3151 [ -  + ][ #  # ]:       7334 :             if( pFontEntry->maFontSelData.mnOrientation
                 [ +  + ]
    3152                 :        442 :             && !pFontEntry->maMetric.mnOrientation
    3153                 :            :             && (meOutDevType != OUTDEV_PRINTER) )
    3154                 :            :             {
    3155                 :          0 :                 pFontEntry->mnOwnOrientation = sal::static_int_cast<short>(pFontEntry->maFontSelData.mnOrientation);
    3156                 :          0 :                 pFontEntry->mnOrientation = pFontEntry->mnOwnOrientation;
    3157                 :            :             }
    3158                 :            :             else
    3159                 :       7334 :                 pFontEntry->mnOrientation = pFontEntry->maMetric.mnOrientation;
    3160                 :            :         }
    3161                 :            :     }
    3162                 :            : 
    3163                 :            :     // enable kerning array if requested
    3164 [ +  - ][ +  + ]:     744383 :     if ( maFont.GetKerning() & KERNING_FONTSPECIFIC )
    3165                 :            :     {
    3166                 :            :         // TODO: test if physical font supports kerning and disable if not
    3167         [ +  + ]:     101905 :         if( pFontEntry->maMetric.mbKernableFont )
    3168                 :      95101 :             mbKerning = true;
    3169                 :            :     }
    3170                 :            :     else
    3171                 :     642478 :         mbKerning = false;
    3172 [ +  - ][ -  + ]:     744383 :     if ( maFont.GetKerning() & KERNING_ASIAN )
    3173                 :          0 :         mbKerning = true;
    3174                 :            : 
    3175                 :            :     // calculate EmphasisArea
    3176                 :     744383 :     mnEmphasisAscent = 0;
    3177                 :     744383 :     mnEmphasisDescent = 0;
    3178 [ +  - ][ +  + ]:     744383 :     if ( maFont.GetEmphasisMark() & EMPHASISMARK_STYLE )
    3179                 :            :     {
    3180         [ +  - ]:      55346 :         FontEmphasisMark    nEmphasisMark = ImplGetEmphasisMarkStyle( maFont );
    3181                 :      55346 :         long                nEmphasisHeight = (pFontEntry->mnLineHeight*250)/1000;
    3182         [ +  + ]:      55346 :         if ( nEmphasisHeight < 1 )
    3183                 :        164 :             nEmphasisHeight = 1;
    3184         [ -  + ]:      55346 :         if ( nEmphasisMark & EMPHASISMARK_POS_BELOW )
    3185                 :          0 :             mnEmphasisDescent = nEmphasisHeight;
    3186                 :            :         else
    3187                 :      55346 :             mnEmphasisAscent = nEmphasisHeight;
    3188                 :            :     }
    3189                 :            : 
    3190                 :            :     // calculate text offset depending on TextAlignment
    3191         [ +  - ]:     744383 :     TextAlign eAlign = maFont.GetAlign();
    3192         [ +  + ]:     744383 :     if ( eAlign == ALIGN_BASELINE )
    3193                 :            :     {
    3194                 :     654694 :         mnTextOffX = 0;
    3195                 :     654694 :         mnTextOffY = 0;
    3196                 :            :     }
    3197         [ +  + ]:      89689 :     else if ( eAlign == ALIGN_TOP )
    3198                 :            :     {
    3199                 :      87044 :         mnTextOffX = 0;
    3200                 :      87044 :         mnTextOffY = +pFontEntry->maMetric.mnAscent + mnEmphasisAscent;
    3201         [ +  + ]:      87044 :         if ( pFontEntry->mnOrientation )
    3202                 :       9689 :             ImplRotatePos( 0, 0, mnTextOffX, mnTextOffY, pFontEntry->mnOrientation );
    3203                 :            :     }
    3204                 :            :     else // eAlign == ALIGN_BOTTOM
    3205                 :            :     {
    3206                 :       2645 :         mnTextOffX = 0;
    3207                 :       2645 :         mnTextOffY = -pFontEntry->maMetric.mnDescent + mnEmphasisDescent;
    3208         [ -  + ]:       2645 :         if ( pFontEntry->mnOrientation )
    3209                 :          0 :             ImplRotatePos( 0, 0, mnTextOffX, mnTextOffY, pFontEntry->mnOrientation );
    3210                 :            :     }
    3211                 :            : 
    3212 [ +  - ][ +  - ]:     801671 :     mbTextLines     = ((maFont.GetUnderline() != UNDERLINE_NONE) && (maFont.GetUnderline() != UNDERLINE_DONTKNOW)) ||
    3213 [ +  - ][ +  - ]:     695367 :                       ((maFont.GetOverline()  != UNDERLINE_NONE) && (maFont.GetOverline()  != UNDERLINE_DONTKNOW)) ||
    3214 [ +  + ][ +  + ]:    1497038 :                       ((maFont.GetStrikeout() != STRIKEOUT_NONE) && (maFont.GetStrikeout() != STRIKEOUT_DONTKNOW));
         [ +  + ][ +  + ]
         [ +  - ][ +  + ]
         [ +  - ][ +  - ]
    3215 [ +  - ][ +  - ]:    1463000 :     mbTextSpecial   = maFont.IsShadow() || maFont.IsOutline() ||
    3216 [ +  + ][ +  + ]:    1463000 :                       (maFont.GetRelief() != RELIEF_NONE);
         [ +  - ][ +  + ]
    3217                 :            : 
    3218                 :            :     // #95414# fix for OLE objects which use scale factors very creatively
    3219 [ +  + ][ +  + ]:     744383 :     if( mbMap && !aSize.Width() )
                 [ +  + ]
    3220                 :            :     {
    3221                 :     619294 :         int nOrigWidth = pFontEntry->maMetric.mnWidth;
    3222                 :     619294 :         float fStretch = (float)maMapRes.mnMapScNumX * maMapRes.mnMapScDenomY;
    3223                 :     619294 :         fStretch /= (float)maMapRes.mnMapScNumY * maMapRes.mnMapScDenomX;
    3224                 :     619294 :         int nNewWidth = (int)(nOrigWidth * fStretch + 0.5);
    3225 [ +  + ][ +  - ]:     619294 :         if( (nNewWidth != nOrigWidth) && (nNewWidth != 0) )
    3226                 :            :         {
    3227         [ +  - ]:         56 :             Size aOrigSize = maFont.GetSize();
    3228         [ +  - ]:         56 :             const_cast<Font&>(maFont).SetSize( Size( nNewWidth, aSize.Height() ) );
    3229                 :         56 :             mbMap = sal_False;
    3230                 :         56 :             mbNewFont = sal_True;
    3231         [ +  - ]:         56 :             ImplNewFont();  // recurse once using stretched width
    3232                 :         56 :             mbMap = sal_True;
    3233         [ +  - ]:         56 :             const_cast<Font&>(maFont).SetSize( aOrigSize );
    3234                 :            :         }
    3235                 :            :     }
    3236                 :            : 
    3237                 :    1111898 :     return true;
    3238                 :            : }
    3239                 :            : 
    3240                 :            : // -----------------------------------------------------------------------
    3241                 :            : 
    3242                 :      93887 : void OutputDevice::ImplDrawTextRect( long nBaseX, long nBaseY,
    3243                 :            :                                      long nDistX, long nDistY, long nWidth, long nHeight )
    3244                 :            : {
    3245                 :      93887 :     long nX = nDistX;
    3246                 :      93887 :     long nY = nDistY;
    3247                 :            : 
    3248                 :      93887 :     short nOrientation = mpFontEntry->mnOrientation;
    3249         [ +  + ]:      93887 :     if ( nOrientation )
    3250                 :            :     {
    3251                 :            :         // Rotate rect without rounding problems for 90 degree rotations
    3252         [ +  + ]:      46119 :         if ( !(nOrientation % 900) )
    3253                 :            :         {
    3254         [ -  + ]:      32234 :             if ( nOrientation == 900 )
    3255                 :            :             {
    3256                 :          0 :                 long nTemp = nX;
    3257                 :          0 :                 nX = nY;
    3258                 :          0 :                 nY = -nTemp;
    3259                 :          0 :                 nTemp = nWidth;
    3260                 :          0 :                 nWidth = nHeight;
    3261                 :          0 :                 nHeight = nTemp;
    3262                 :          0 :                 nY -= nHeight;
    3263                 :            :             }
    3264         [ -  + ]:      32234 :             else if ( nOrientation == 1800 )
    3265                 :            :             {
    3266                 :          0 :                 nX = -nX;
    3267                 :          0 :                 nY = -nY;
    3268                 :          0 :                 nX -= nWidth;
    3269                 :          0 :                 nY -= nHeight;
    3270                 :            :             }
    3271                 :            :             else /* ( nOrientation == 2700 ) */
    3272                 :            :             {
    3273                 :      32234 :                 long nTemp = nX;
    3274                 :      32234 :                 nX = -nY;
    3275                 :      32234 :                 nY = nTemp;
    3276                 :      32234 :                 nTemp = nWidth;
    3277                 :      32234 :                 nWidth = nHeight;
    3278                 :      32234 :                 nHeight = nTemp;
    3279                 :      32234 :                 nX -= nWidth;
    3280                 :            :             }
    3281                 :            :         }
    3282                 :            :         else
    3283                 :            :         {
    3284                 :      13885 :             nX += nBaseX;
    3285                 :      13885 :             nY += nBaseY;
    3286                 :            :             // inflate because polygons are drawn smaller
    3287         [ +  - ]:      13885 :             Rectangle aRect( Point( nX, nY ), Size( nWidth+1, nHeight+1 ) );
    3288         [ +  - ]:      13885 :             Polygon   aPoly( aRect );
    3289         [ +  - ]:      13885 :             aPoly.Rotate( Point( nBaseX, nBaseY ), mpFontEntry->mnOrientation );
    3290         [ +  - ]:      13885 :             ImplDrawPolygon( aPoly );
    3291         [ +  - ]:      93887 :             return;
    3292                 :            :         }
    3293                 :            :     }
    3294                 :            : 
    3295                 :      80002 :     nX += nBaseX;
    3296                 :      80002 :     nY += nBaseY;
    3297                 :      80002 :     mpGraphics->DrawRect( nX, nY, nWidth, nHeight, this );
    3298                 :            : }
    3299                 :            : 
    3300                 :            : // -----------------------------------------------------------------------
    3301                 :            : 
    3302                 :       5844 : void OutputDevice::ImplDrawTextBackground( const SalLayout& rSalLayout )
    3303                 :            : {
    3304         [ +  - ]:       5844 :     const long nWidth = rSalLayout.GetTextWidth() / rSalLayout.GetUnitsPerPixel();
    3305                 :       5844 :     const Point aBase = rSalLayout.DrawBase();
    3306                 :       5844 :     const long nX = aBase.X();
    3307                 :       5844 :     const long nY = aBase.Y();
    3308                 :            : 
    3309 [ +  + ][ +  + ]:       5844 :     if ( mbLineColor || mbInitLineColor )
    3310                 :            :     {
    3311         [ +  - ]:       5794 :         mpGraphics->SetLineColor();
    3312                 :       5794 :         mbInitLineColor = sal_True;
    3313                 :            :     }
    3314 [ +  - ][ +  - ]:       5844 :     mpGraphics->SetFillColor( ImplColorToSal( GetTextFillColor() ) );
    3315                 :       5844 :     mbInitFillColor = sal_True;
    3316                 :            : 
    3317                 :            :     ImplDrawTextRect( nX, nY, 0, -(mpFontEntry->maMetric.mnAscent + mnEmphasisAscent),
    3318                 :            :                       nWidth,
    3319         [ +  - ]:       5844 :                       mpFontEntry->mnLineHeight+mnEmphasisAscent+mnEmphasisDescent );
    3320                 :       5844 : }
    3321                 :            : 
    3322                 :            : // -----------------------------------------------------------------------
    3323                 :            : 
    3324                 :          0 : Rectangle OutputDevice::ImplGetTextBoundRect( const SalLayout& rSalLayout )
    3325                 :            : {
    3326         [ #  # ]:          0 :     Point aPoint = rSalLayout.GetDrawPosition();
    3327                 :          0 :     long nX = aPoint.X();
    3328                 :          0 :     long nY = aPoint.Y();
    3329                 :            : 
    3330         [ #  # ]:          0 :     long nWidth = rSalLayout.GetTextWidth();
    3331                 :          0 :     long nHeight = mpFontEntry->mnLineHeight + mnEmphasisAscent + mnEmphasisDescent;
    3332                 :            : 
    3333                 :          0 :     nY -= mpFontEntry->maMetric.mnAscent + mnEmphasisAscent;
    3334                 :            : 
    3335         [ #  # ]:          0 :     if ( mpFontEntry->mnOrientation )
    3336                 :            :     {
    3337                 :          0 :         long nBaseX = nX, nBaseY = nY;
    3338         [ #  # ]:          0 :         if ( !(mpFontEntry->mnOrientation % 900) )
    3339                 :            :         {
    3340                 :          0 :             long nX2 = nX+nWidth;
    3341                 :          0 :             long nY2 = nY+nHeight;
    3342                 :          0 :             ImplRotatePos( nBaseX, nBaseY, nX, nY, mpFontEntry->mnOrientation );
    3343                 :          0 :             ImplRotatePos( nBaseX, nBaseY, nX2, nY2, mpFontEntry->mnOrientation );
    3344                 :          0 :             nWidth = nX2-nX;
    3345                 :          0 :             nHeight = nY2-nY;
    3346                 :            :         }
    3347                 :            :         else
    3348                 :            :         {
    3349                 :            :             // inflate by +1+1 because polygons are drawn smaller
    3350         [ #  # ]:          0 :             Rectangle aRect( Point( nX, nY ), Size( nWidth+1, nHeight+1 ) );
    3351         [ #  # ]:          0 :             Polygon   aPoly( aRect );
    3352         [ #  # ]:          0 :             aPoly.Rotate( Point( nBaseX, nBaseY ), mpFontEntry->mnOrientation );
    3353 [ #  # ][ #  # ]:          0 :             return aPoly.GetBoundRect();
    3354                 :            :         }
    3355                 :            :     }
    3356                 :            : 
    3357         [ #  # ]:          0 :     return Rectangle( Point( nX, nY ), Size( nWidth, nHeight ) );
    3358                 :            : }
    3359                 :            : 
    3360                 :            : // -----------------------------------------------------------------------
    3361                 :            : 
    3362                 :          0 : void OutputDevice::ImplInitTextLineSize()
    3363                 :            : {
    3364                 :          0 :     mpFontEntry->maMetric.ImplInitTextLineSize( this );
    3365                 :          0 : }
    3366                 :            : 
    3367                 :            : // -----------------------------------------------------------------------
    3368                 :            : 
    3369                 :          0 : void OutputDevice::ImplInitAboveTextLineSize()
    3370                 :            : {
    3371                 :          0 :     mpFontEntry->maMetric.ImplInitAboveTextLineSize();
    3372                 :          0 : }
    3373                 :            : 
    3374                 :            : // -----------------------------------------------------------------------
    3375                 :            : 
    3376                 :     188552 : bool ImplFontAttributes::operator==(const ImplFontAttributes& rOther) const
    3377                 :            : {
    3378         [ +  + ]:     188552 :     if (maName != rOther.maName)
    3379                 :      33727 :         return false;
    3380                 :            : 
    3381         [ +  + ]:     154825 :     if (maStyleName != rOther.maStyleName)
    3382                 :       3111 :         return false;
    3383                 :            : 
    3384         [ +  + ]:     151714 :     if (meWeight != rOther.meWeight)
    3385                 :       2635 :         return false;
    3386                 :            : 
    3387         [ +  + ]:     149079 :     if (meItalic != rOther.meItalic)
    3388                 :       5294 :         return false;
    3389                 :            : 
    3390         [ +  + ]:     143785 :     if (meFamily != rOther.meFamily)
    3391                 :       3944 :         return false;
    3392                 :            : 
    3393         [ +  + ]:     139841 :     if (mePitch != rOther.mePitch)
    3394                 :        557 :         return false;
    3395                 :            : 
    3396         [ -  + ]:     139284 :     if (meWidthType != rOther.meWidthType)
    3397                 :          0 :         return false;
    3398                 :            : 
    3399         [ -  + ]:     139284 :     if (mbSymbolFlag != rOther.mbSymbolFlag)
    3400                 :          0 :         return false;
    3401                 :            : 
    3402                 :     188552 :     return true;
    3403                 :            : }
    3404                 :            : 
    3405                 :            : // -----------------------------------------------------------------------
    3406                 :            : 
    3407                 :      18357 : ImplFontMetricData::ImplFontMetricData( const FontSelectPattern& rFontSelData )
    3408                 :      18357 : :   ImplFontAttributes( rFontSelData )
    3409                 :            : {
    3410                 :            :     // initialize the members provided by the font request
    3411                 :      18357 :     mnWidth        = rFontSelData.mnWidth;
    3412                 :      18357 :     mnOrientation  = sal::static_int_cast<short>(rFontSelData.mnOrientation);
    3413                 :            : 
    3414                 :            :     // intialize the used font name
    3415         [ +  - ]:      18357 :     if( rFontSelData.mpFontData )
    3416                 :            :     {
    3417         [ +  - ]:      18357 :         maName     = rFontSelData.mpFontData->maName;
    3418         [ +  - ]:      18357 :         maStyleName= rFontSelData.mpFontData->maStyleName;
    3419                 :      18357 :         mbDevice   = rFontSelData.mpFontData->mbDevice;
    3420                 :      18357 :         mbKernableFont = true;
    3421                 :            :     }
    3422                 :            :     else
    3423                 :            :     {
    3424                 :          0 :         xub_StrLen nTokenPos = 0;
    3425 [ #  # ][ #  # ]:          0 :         maName     = GetNextFontToken( rFontSelData.maName, nTokenPos );
                 [ #  # ]
    3426         [ #  # ]:          0 :         maStyleName= rFontSelData.maStyleName;
    3427                 :          0 :         mbDevice   = false;
    3428                 :          0 :         mbKernableFont = false;
    3429                 :            :     }
    3430                 :            : 
    3431                 :            :     // reset metrics that are usually measured for the font instance
    3432                 :      18357 :     mnAscent       = 0;
    3433                 :      18357 :     mnDescent      = 0;
    3434                 :      18357 :     mnIntLeading   = 0;
    3435                 :      18357 :     mnExtLeading   = 0;
    3436                 :      18357 :     mnSlant        = 0;
    3437                 :      18357 :     mnMinKashida   = 0;
    3438                 :            : 
    3439                 :            :     // reset metrics that are usually derived from the measurements
    3440                 :      18357 :     mnUnderlineSize            = 0;
    3441                 :      18357 :     mnUnderlineOffset          = 0;
    3442                 :      18357 :     mnBUnderlineSize           = 0;
    3443                 :      18357 :     mnBUnderlineOffset         = 0;
    3444                 :      18357 :     mnDUnderlineSize           = 0;
    3445                 :      18357 :     mnDUnderlineOffset1        = 0;
    3446                 :      18357 :     mnDUnderlineOffset2        = 0;
    3447                 :      18357 :     mnWUnderlineSize           = 0;
    3448                 :      18357 :     mnWUnderlineOffset         = 0;
    3449                 :      18357 :     mnAboveUnderlineSize       = 0;
    3450                 :      18357 :     mnAboveUnderlineOffset     = 0;
    3451                 :      18357 :     mnAboveBUnderlineSize      = 0;
    3452                 :      18357 :     mnAboveBUnderlineOffset    = 0;
    3453                 :      18357 :     mnAboveDUnderlineSize      = 0;
    3454                 :      18357 :     mnAboveDUnderlineOffset1   = 0;
    3455                 :      18357 :     mnAboveDUnderlineOffset2   = 0;
    3456                 :      18357 :     mnAboveWUnderlineSize      = 0;
    3457                 :      18357 :     mnAboveWUnderlineOffset    = 0;
    3458                 :      18357 :     mnStrikeoutSize            = 0;
    3459                 :      18357 :     mnStrikeoutOffset          = 0;
    3460                 :      18357 :     mnBStrikeoutSize           = 0;
    3461                 :      18357 :     mnBStrikeoutOffset         = 0;
    3462                 :      18357 :     mnDStrikeoutSize           = 0;
    3463                 :      18357 :     mnDStrikeoutOffset1        = 0;
    3464                 :      18357 :     mnDStrikeoutOffset2        = 0;
    3465                 :      18357 : }
    3466                 :            : 
    3467                 :            : // -----------------------------------------------------------------------
    3468                 :            : 
    3469                 :       7334 : void ImplFontMetricData::ImplInitTextLineSize( const OutputDevice* pDev )
    3470                 :            : {
    3471                 :       7334 :     long nDescent = mnDescent;
    3472         [ +  + ]:       7334 :     if ( nDescent <= 0 )
    3473                 :            :     {
    3474                 :          8 :         nDescent = mnAscent / 10;
    3475         [ +  - ]:          8 :         if ( !nDescent )
    3476                 :          8 :             nDescent = 1;
    3477                 :            :     }
    3478                 :            : 
    3479                 :            :     // #i55341# for some fonts it is not a good idea to calculate
    3480                 :            :     // their text line metrics from the real font descent
    3481                 :            :     // => work around this problem just for these fonts
    3482         [ +  + ]:       7334 :     if( 3*nDescent > mnAscent )
    3483                 :         34 :         nDescent = mnAscent / 3;
    3484                 :            : 
    3485                 :       7334 :     long nLineHeight = ((nDescent*25)+50) / 100;
    3486         [ +  + ]:       7334 :     if ( !nLineHeight )
    3487                 :        118 :         nLineHeight = 1;
    3488                 :       7334 :     long nLineHeight2 = nLineHeight / 2;
    3489         [ +  + ]:       7334 :     if ( !nLineHeight2 )
    3490                 :       1471 :         nLineHeight2 = 1;
    3491                 :            : 
    3492                 :       7334 :     long nBLineHeight = ((nDescent*50)+50) / 100;
    3493         [ +  + ]:       7334 :     if ( nBLineHeight == nLineHeight )
    3494                 :        597 :         nBLineHeight++;
    3495                 :       7334 :     long nBLineHeight2 = nBLineHeight/2;
    3496         [ +  + ]:       7334 :     if ( !nBLineHeight2 )
    3497                 :         10 :         nBLineHeight2 = 1;
    3498                 :            : 
    3499                 :       7334 :     long n2LineHeight = ((nDescent*16)+50) / 100;
    3500         [ +  + ]:       7334 :     if ( !n2LineHeight )
    3501                 :       1316 :         n2LineHeight = 1;
    3502                 :       7334 :     long n2LineDY = n2LineHeight;
    3503                 :            :      /* #117909#
    3504                 :            :       * add some pixels to minimum double line distance on higher resolution devices
    3505                 :            :       */
    3506                 :       7334 :     long nMin2LineDY = 1 + pDev->ImplGetDPIY()/150;
    3507         [ +  + ]:       7334 :     if ( n2LineDY < nMin2LineDY )
    3508                 :       3817 :         n2LineDY = nMin2LineDY;
    3509                 :       7334 :     long n2LineDY2 = n2LineDY/2;
    3510         [ +  + ]:       7334 :     if ( !n2LineDY2 )
    3511                 :       1730 :         n2LineDY2 = 1;
    3512                 :            : 
    3513                 :       7334 :     long nUnderlineOffset = mnDescent/2 + 1;
    3514                 :       7334 :     long nStrikeoutOffset = -((mnAscent - mnIntLeading) / 3);
    3515                 :            : 
    3516                 :       7334 :     mnUnderlineSize        = nLineHeight;
    3517                 :       7334 :     mnUnderlineOffset      = nUnderlineOffset - nLineHeight2;
    3518                 :            : 
    3519                 :       7334 :     mnBUnderlineSize       = nBLineHeight;
    3520                 :       7334 :     mnBUnderlineOffset     = nUnderlineOffset - nBLineHeight2;
    3521                 :            : 
    3522                 :       7334 :     mnDUnderlineSize       = n2LineHeight;
    3523                 :       7334 :     mnDUnderlineOffset1    = nUnderlineOffset - n2LineDY2 - n2LineHeight;
    3524                 :       7334 :     mnDUnderlineOffset2    = mnDUnderlineOffset1 + n2LineDY + n2LineHeight;
    3525                 :            : 
    3526                 :       7334 :     long nWCalcSize = mnDescent;
    3527         [ +  + ]:       7334 :     if ( nWCalcSize < 6 )
    3528                 :            :     {
    3529 [ +  + ][ +  + ]:       1471 :         if ( (nWCalcSize == 1) || (nWCalcSize == 2) )
    3530                 :        597 :             mnWUnderlineSize = nWCalcSize;
    3531                 :            :         else
    3532                 :       1471 :             mnWUnderlineSize = 3;
    3533                 :            :     }
    3534                 :            :     else
    3535                 :       5863 :         mnWUnderlineSize = ((nWCalcSize*50)+50) / 100;
    3536                 :            : 
    3537                 :            :     // #109280# the following line assures that wavelnes are never placed below the descent, however
    3538                 :            :     // for most fonts the waveline then is drawn into the text, so we better keep the old solution
    3539                 :            :     // pFontEntry->maMetric.mnWUnderlineOffset     = pFontEntry->maMetric.mnDescent + 1 - pFontEntry->maMetric.mnWUnderlineSize;
    3540                 :       7334 :     mnWUnderlineOffset     = nUnderlineOffset;
    3541                 :            : 
    3542                 :       7334 :     mnStrikeoutSize        = nLineHeight;
    3543                 :       7334 :     mnStrikeoutOffset      = nStrikeoutOffset - nLineHeight2;
    3544                 :            : 
    3545                 :       7334 :     mnBStrikeoutSize       = nBLineHeight;
    3546                 :       7334 :     mnBStrikeoutOffset     = nStrikeoutOffset - nBLineHeight2;
    3547                 :            : 
    3548                 :       7334 :     mnDStrikeoutSize       = n2LineHeight;
    3549                 :       7334 :     mnDStrikeoutOffset1    = nStrikeoutOffset - n2LineDY2 - n2LineHeight;
    3550                 :       7334 :     mnDStrikeoutOffset2    = mnDStrikeoutOffset1 + n2LineDY + n2LineHeight;
    3551                 :       7334 : }
    3552                 :            : 
    3553                 :            : // -----------------------------------------------------------------------
    3554                 :            : 
    3555                 :       7334 : void ImplFontMetricData::ImplInitAboveTextLineSize()
    3556                 :            : {
    3557                 :       7334 :     long nIntLeading = mnIntLeading;
    3558                 :            :     // TODO: assess usage of nLeading below (changed in extleading CWS)
    3559                 :            :     // if no leading is available, we assume 15% of the ascent
    3560         [ +  + ]:       7334 :     if ( nIntLeading <= 0 )
    3561                 :            :     {
    3562                 :        261 :         nIntLeading = mnAscent*15/100;
    3563         [ +  + ]:        261 :         if ( !nIntLeading )
    3564                 :         38 :             nIntLeading = 1;
    3565                 :            :     }
    3566                 :            : 
    3567                 :       7334 :     long nLineHeight = ((nIntLeading*25)+50) / 100;
    3568         [ +  + ]:       7334 :     if ( !nLineHeight )
    3569                 :        584 :         nLineHeight = 1;
    3570                 :            : 
    3571                 :       7334 :     long nBLineHeight = ((nIntLeading*50)+50) / 100;
    3572         [ +  + ]:       7334 :     if ( nBLineHeight == nLineHeight )
    3573                 :       1427 :         nBLineHeight++;
    3574                 :            : 
    3575                 :       7334 :     long n2LineHeight = ((nIntLeading*16)+50) / 100;
    3576         [ +  + ]:       7334 :     if ( !n2LineHeight )
    3577                 :       1567 :         n2LineHeight = 1;
    3578                 :            : 
    3579                 :       7334 :     long nCeiling = -mnAscent;
    3580                 :            : 
    3581                 :       7334 :     mnAboveUnderlineSize       = nLineHeight;
    3582                 :       7334 :     mnAboveUnderlineOffset     = nCeiling + (nIntLeading - nLineHeight + 1) / 2;
    3583                 :            : 
    3584                 :       7334 :     mnAboveBUnderlineSize      = nBLineHeight;
    3585                 :       7334 :     mnAboveBUnderlineOffset    = nCeiling + (nIntLeading - nBLineHeight + 1) / 2;
    3586                 :            : 
    3587                 :       7334 :     mnAboveDUnderlineSize      = n2LineHeight;
    3588                 :       7334 :     mnAboveDUnderlineOffset1   = nCeiling + (nIntLeading - 3*n2LineHeight + 1) / 2;
    3589                 :       7334 :     mnAboveDUnderlineOffset2   = nCeiling + (nIntLeading +   n2LineHeight + 1) / 2;
    3590                 :            : 
    3591                 :       7334 :     long nWCalcSize = nIntLeading;
    3592         [ +  + ]:       7334 :     if ( nWCalcSize < 6 )
    3593                 :            :     {
    3594 [ +  + ][ +  + ]:       1910 :         if ( (nWCalcSize == 1) || (nWCalcSize == 2) )
    3595                 :       1427 :             mnAboveWUnderlineSize = nWCalcSize;
    3596                 :            :         else
    3597                 :       1910 :             mnAboveWUnderlineSize = 3;
    3598                 :            :     }
    3599                 :            :     else
    3600                 :       5424 :         mnAboveWUnderlineSize = ((nWCalcSize*50)+50) / 100;
    3601                 :            : 
    3602                 :       7334 :     mnAboveWUnderlineOffset = nCeiling + (nIntLeading + 1) / 2;
    3603                 :       7334 : }
    3604                 :            : 
    3605                 :            : // -----------------------------------------------------------------------
    3606                 :            : 
    3607                 :     436240 : static void ImplDrawWavePixel( long nOriginX, long nOriginY,
    3608                 :            :                                long nCurX, long nCurY,
    3609                 :            :                                short nOrientation,
    3610                 :            :                                SalGraphics* pGraphics,
    3611                 :            :                                OutputDevice* pOutDev,
    3612                 :            :                                sal_Bool bDrawPixAsRect,
    3613                 :            : 
    3614                 :            :                                long nPixWidth, long nPixHeight )
    3615                 :            : {
    3616         [ +  + ]:     436240 :     if ( nOrientation )
    3617                 :     189900 :         ImplRotatePos( nOriginX, nOriginY, nCurX, nCurY, nOrientation );
    3618                 :            : 
    3619         [ +  + ]:     436240 :     if ( bDrawPixAsRect )
    3620                 :            :     {
    3621                 :            : 
    3622                 :     164150 :         pGraphics->DrawRect( nCurX, nCurY, nPixWidth, nPixHeight, pOutDev );
    3623                 :            :     }
    3624                 :            :     else
    3625                 :            :     {
    3626                 :     272090 :         pGraphics->DrawPixel( nCurX, nCurY, pOutDev );
    3627                 :            :     }
    3628                 :     436240 : }
    3629                 :            : 
    3630                 :            : // -----------------------------------------------------------------------
    3631                 :            : 
    3632                 :       6366 : void OutputDevice::ImplDrawWaveLine( long nBaseX, long nBaseY,
    3633                 :            :                                      long nDistX, long nDistY,
    3634                 :            :                                      long nWidth, long nHeight,
    3635                 :            :                                      long nLineWidth, short nOrientation,
    3636                 :            :                                      const Color& rColor )
    3637                 :            : {
    3638         [ +  - ]:       6366 :     if ( !nHeight )
    3639                 :       6366 :         return;
    3640                 :            : 
    3641                 :       6366 :     long nStartX = nBaseX + nDistX;
    3642                 :       6366 :     long nStartY = nBaseY + nDistY;
    3643                 :            : 
    3644                 :            :     // Bei Hoehe von 1 Pixel reicht es, eine Linie auszugeben
    3645 [ +  + ][ +  + ]:       6366 :     if ( (nLineWidth == 1) && (nHeight == 1) )
    3646                 :            :     {
    3647         [ +  - ]:          4 :         mpGraphics->SetLineColor( ImplColorToSal( rColor ) );
    3648                 :          4 :         mbInitLineColor = sal_True;
    3649                 :            : 
    3650                 :          4 :         long nEndX = nStartX+nWidth;
    3651                 :          4 :         long nEndY = nStartY;
    3652         [ -  + ]:          4 :         if ( nOrientation )
    3653                 :            :         {
    3654                 :          0 :             ImplRotatePos( nBaseX, nBaseY, nStartX, nStartY, nOrientation );
    3655                 :          0 :             ImplRotatePos( nBaseX, nBaseY, nEndX, nEndY, nOrientation );
    3656                 :            :         }
    3657         [ +  - ]:          4 :         mpGraphics->DrawLine( nStartX, nStartY, nEndX, nEndY, this );
    3658                 :            :     }
    3659                 :            :     else
    3660                 :            :     {
    3661                 :       6362 :         long    nCurX = nStartX;
    3662                 :       6362 :         long    nCurY = nStartY;
    3663                 :       6362 :         long    nDiffX = 2;
    3664                 :       6362 :         long    nDiffY = nHeight-1;
    3665                 :       6362 :         long    nCount = nWidth;
    3666                 :       6362 :         long    nOffY = -1;
    3667                 :            :         long    nFreq;
    3668                 :            :         long    i;
    3669                 :            :         long    nPixWidth;
    3670                 :            :         long    nPixHeight;
    3671                 :            :         sal_Bool    bDrawPixAsRect;
    3672                 :            :         // Auf Druckern die Pixel per DrawRect() ausgeben
    3673 [ +  - ][ +  + ]:       6362 :         if ( (GetOutDevType() == OUTDEV_PRINTER) || (nLineWidth > 1) )
                 [ +  + ]
    3674                 :            :         {
    3675 [ +  + ][ +  + ]:       2386 :             if ( mbLineColor || mbInitLineColor )
    3676                 :            :             {
    3677         [ +  - ]:       2291 :                 mpGraphics->SetLineColor();
    3678                 :       2291 :                 mbInitLineColor = sal_True;
    3679                 :            :             }
    3680         [ +  - ]:       2386 :             mpGraphics->SetFillColor( ImplColorToSal( rColor ) );
    3681                 :       2386 :             mbInitFillColor = sal_True;
    3682                 :       2386 :             bDrawPixAsRect  = sal_True;
    3683                 :       2386 :             nPixWidth       = nLineWidth;
    3684                 :       2386 :             nPixHeight      = ((nLineWidth*mnDPIX)+(mnDPIY/2))/mnDPIY;
    3685                 :            :         }
    3686                 :            :         else
    3687                 :            :         {
    3688         [ +  - ]:       3976 :             mpGraphics->SetLineColor( ImplColorToSal( rColor ) );
    3689                 :       3976 :             mbInitLineColor = sal_True;
    3690                 :       3976 :             nPixWidth       = 1;
    3691                 :       3976 :             nPixHeight      = 1;
    3692                 :       3976 :             bDrawPixAsRect  = sal_False;
    3693                 :            :         }
    3694                 :            : 
    3695         [ -  + ]:       6362 :         if ( !nDiffY )
    3696                 :            :         {
    3697         [ #  # ]:          0 :             while ( nWidth )
    3698                 :            :             {
    3699                 :            :                 ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
    3700                 :            :                                    mpGraphics, this,
    3701         [ #  # ]:          0 :                                    bDrawPixAsRect, nPixWidth, nPixHeight );
    3702                 :          0 :                 nCurX++;
    3703                 :          0 :                 nWidth--;
    3704                 :            :             }
    3705                 :            :         }
    3706                 :            :         else
    3707                 :            :         {
    3708                 :       6362 :             nCurY += nDiffY;
    3709                 :       6362 :             nFreq = nCount / (nDiffX+nDiffY);
    3710         [ +  + ]:      98247 :             while ( nFreq-- )
    3711                 :            :             {
    3712         [ +  + ]:     331592 :                 for( i = nDiffY; i; --i )
    3713                 :            :                 {
    3714                 :            :                     ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
    3715                 :            :                                        mpGraphics, this,
    3716         [ +  - ]:     239707 :                                        bDrawPixAsRect, nPixWidth, nPixHeight );
    3717                 :     239707 :                     nCurX++;
    3718                 :     239707 :                     nCurY += nOffY;
    3719                 :            :                 }
    3720         [ +  + ]:     275655 :                 for( i = nDiffX; i; --i )
    3721                 :            :                 {
    3722                 :            :                     ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
    3723                 :            :                                        mpGraphics, this,
    3724         [ +  - ]:     183770 :                                        bDrawPixAsRect, nPixWidth, nPixHeight );
    3725                 :     183770 :                     nCurX++;
    3726                 :            :                 }
    3727                 :      91885 :                 nOffY = -nOffY;
    3728                 :            :             }
    3729                 :       6362 :             nFreq = nCount % (nDiffX+nDiffY);
    3730         [ +  + ]:       6362 :             if ( nFreq )
    3731                 :            :             {
    3732 [ +  + ][ +  + ]:      15907 :                 for( i = nDiffY; i && nFreq; --i, --nFreq )
                 [ +  + ]
    3733                 :            :                 {
    3734                 :            :                     ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
    3735                 :            :                                        mpGraphics, this,
    3736         [ +  - ]:      11043 :                                        bDrawPixAsRect, nPixWidth, nPixHeight );
    3737                 :      11043 :                     nCurX++;
    3738                 :      11043 :                     nCurY += nOffY;
    3739                 :            : 
    3740                 :            :                 }
    3741 [ +  - ][ +  + ]:       8086 :                 for( i = nDiffX; i && nFreq; --i, --nFreq )
                 [ +  + ]
    3742                 :            :                 {
    3743                 :            :                     ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
    3744                 :            :                                        mpGraphics, this,
    3745         [ +  - ]:       1720 :                                        bDrawPixAsRect, nPixWidth, nPixHeight );
    3746                 :       1720 :                     nCurX++;
    3747                 :            :                 }
    3748                 :            :             }
    3749                 :            :         }
    3750                 :            : 
    3751                 :            :     }
    3752                 :            : }
    3753                 :            : 
    3754                 :            : // -----------------------------------------------------------------------
    3755                 :            : 
    3756                 :       2386 : void OutputDevice::ImplDrawWaveTextLine( long nBaseX, long nBaseY,
    3757                 :            :                                          long nDistX, long nDistY, long nWidth,
    3758                 :            :                                          FontUnderline eTextLine,
    3759                 :            :                                          Color aColor,
    3760                 :            :                                          sal_Bool bIsAbove )
    3761                 :            : {
    3762                 :       2386 :     ImplFontEntry*  pFontEntry = mpFontEntry;
    3763                 :            :     long            nLineHeight;
    3764                 :            :     long            nLinePos;
    3765                 :            : 
    3766         [ -  + ]:       2386 :     if ( bIsAbove )
    3767                 :            :     {
    3768                 :          0 :         nLineHeight = pFontEntry->maMetric.mnAboveWUnderlineSize;
    3769                 :          0 :         nLinePos = pFontEntry->maMetric.mnAboveWUnderlineOffset;
    3770                 :            :     }
    3771                 :            :     else
    3772                 :            :     {
    3773                 :       2386 :         nLineHeight = pFontEntry->maMetric.mnWUnderlineSize;
    3774                 :       2386 :         nLinePos = pFontEntry->maMetric.mnWUnderlineOffset;
    3775                 :            :     }
    3776 [ -  + ][ #  # ]:       2386 :     if ( (eTextLine == UNDERLINE_SMALLWAVE) && (nLineHeight > 3) )
    3777                 :          0 :         nLineHeight = 3;
    3778                 :       2386 :     long nLineWidth = (mnDPIX/300);
    3779         [ +  - ]:       2386 :     if ( !nLineWidth )
    3780                 :       2386 :         nLineWidth = 1;
    3781         [ +  - ]:       2386 :     if ( eTextLine == UNDERLINE_BOLDWAVE )
    3782                 :       2386 :         nLineWidth *= 2;
    3783                 :       2386 :     nLinePos += nDistY - (nLineHeight / 2);
    3784                 :       2386 :     long nLineWidthHeight = ((nLineWidth*mnDPIX)+(mnDPIY/2))/mnDPIY;
    3785         [ -  + ]:       2386 :     if ( eTextLine == UNDERLINE_DOUBLEWAVE )
    3786                 :            :     {
    3787                 :          0 :         long nOrgLineHeight = nLineHeight;
    3788                 :          0 :         nLineHeight /= 3;
    3789         [ #  # ]:          0 :         if ( nLineHeight < 2 )
    3790                 :            :         {
    3791         [ #  # ]:          0 :             if ( nOrgLineHeight > 1 )
    3792                 :          0 :                 nLineHeight = 2;
    3793                 :            :             else
    3794                 :          0 :                 nLineHeight = 1;
    3795                 :            :         }
    3796                 :          0 :         long nLineDY = nOrgLineHeight-(nLineHeight*2);
    3797         [ #  # ]:          0 :         if ( nLineDY < nLineWidthHeight )
    3798                 :          0 :             nLineDY = nLineWidthHeight;
    3799                 :          0 :         long nLineDY2 = nLineDY/2;
    3800         [ #  # ]:          0 :         if ( !nLineDY2 )
    3801                 :          0 :             nLineDY2 = 1;
    3802                 :            : 
    3803                 :          0 :         nLinePos -= nLineWidthHeight-nLineDY2;
    3804                 :            :         ImplDrawWaveLine( nBaseX, nBaseY, nDistX, nLinePos, nWidth, nLineHeight,
    3805                 :          0 :                           nLineWidth, mpFontEntry->mnOrientation, aColor );
    3806                 :          0 :         nLinePos += nLineWidthHeight+nLineDY;
    3807                 :            :         ImplDrawWaveLine( nBaseX, nBaseY, nDistX, nLinePos, nWidth, nLineHeight,
    3808                 :          0 :                           nLineWidth, mpFontEntry->mnOrientation, aColor );
    3809                 :            :     }
    3810                 :            :     else
    3811                 :            :     {
    3812                 :       2386 :         nLinePos -= nLineWidthHeight/2;
    3813                 :            :         ImplDrawWaveLine( nBaseX, nBaseY, nDistX, nLinePos, nWidth, nLineHeight,
    3814                 :       2386 :                           nLineWidth, mpFontEntry->mnOrientation, aColor );
    3815                 :            :     }
    3816                 :       2386 : }
    3817                 :            : 
    3818                 :            : // -----------------------------------------------------------------------
    3819                 :            : 
    3820                 :      58594 : void OutputDevice::ImplDrawStraightTextLine( long nBaseX, long nBaseY,
    3821                 :            :                                              long nDistX, long nDistY, long nWidth,
    3822                 :            :                                              FontUnderline eTextLine,
    3823                 :            :                                              Color aColor,
    3824                 :            :                                              sal_Bool bIsAbove )
    3825                 :            : {
    3826                 :      58594 :     ImplFontEntry*  pFontEntry = mpFontEntry;
    3827                 :      58594 :     long            nLineHeight = 0;
    3828                 :      58594 :     long            nLinePos  = 0;
    3829                 :      58594 :     long            nLinePos2 = 0;
    3830                 :            : 
    3831                 :      58594 :     const long nY = nDistY;
    3832                 :            : 
    3833         [ +  + ]:      58594 :     if ( eTextLine > UNDERLINE_LAST )
    3834                 :        864 :         eTextLine = UNDERLINE_SINGLE;
    3835                 :            : 
    3836   [ +  +  +  + ]:      58594 :     switch ( eTextLine )
    3837                 :            :     {
    3838                 :            :         case UNDERLINE_SINGLE:
    3839                 :            :         case UNDERLINE_DOTTED:
    3840                 :            :         case UNDERLINE_DASH:
    3841                 :            :         case UNDERLINE_LONGDASH:
    3842                 :            :         case UNDERLINE_DASHDOT:
    3843                 :            :         case UNDERLINE_DASHDOTDOT:
    3844         [ +  + ]:      28988 :             if ( bIsAbove )
    3845                 :            :             {
    3846                 :       5456 :                 nLineHeight = pFontEntry->maMetric.mnAboveUnderlineSize;
    3847                 :       5456 :                 nLinePos    = nY + pFontEntry->maMetric.mnAboveUnderlineOffset;
    3848                 :            :             }
    3849                 :            :             else
    3850                 :            :             {
    3851                 :      23532 :                 nLineHeight = pFontEntry->maMetric.mnUnderlineSize;
    3852                 :      23532 :                 nLinePos    = nY + pFontEntry->maMetric.mnUnderlineOffset;
    3853                 :            :             }
    3854                 :      28988 :             break;
    3855                 :            :         case UNDERLINE_BOLD:
    3856                 :            :         case UNDERLINE_BOLDDOTTED:
    3857                 :            :         case UNDERLINE_BOLDDASH:
    3858                 :            :         case UNDERLINE_BOLDLONGDASH:
    3859                 :            :         case UNDERLINE_BOLDDASHDOT:
    3860                 :            :         case UNDERLINE_BOLDDASHDOTDOT:
    3861         [ -  + ]:       1290 :             if ( bIsAbove )
    3862                 :            :             {
    3863                 :          0 :                 nLineHeight = pFontEntry->maMetric.mnAboveBUnderlineSize;
    3864                 :          0 :                 nLinePos    = nY + pFontEntry->maMetric.mnAboveBUnderlineOffset;
    3865                 :            :             }
    3866                 :            :             else
    3867                 :            :             {
    3868                 :       1290 :                 nLineHeight = pFontEntry->maMetric.mnBUnderlineSize;
    3869                 :       1290 :                 nLinePos    = nY + pFontEntry->maMetric.mnBUnderlineOffset;
    3870                 :            :             }
    3871                 :       1290 :             break;
    3872                 :            :         case UNDERLINE_DOUBLE:
    3873         [ +  + ]:       5454 :             if ( bIsAbove )
    3874                 :            :             {
    3875                 :       2604 :                 nLineHeight = pFontEntry->maMetric.mnAboveDUnderlineSize;
    3876                 :       2604 :                 nLinePos    = nY + pFontEntry->maMetric.mnAboveDUnderlineOffset1;
    3877                 :       2604 :                 nLinePos2   = nY + pFontEntry->maMetric.mnAboveDUnderlineOffset2;
    3878                 :            :             }
    3879                 :            :             else
    3880                 :            :             {
    3881                 :       2850 :                 nLineHeight = pFontEntry->maMetric.mnDUnderlineSize;
    3882                 :       2850 :                 nLinePos    = nY + pFontEntry->maMetric.mnDUnderlineOffset1;
    3883                 :       2850 :                 nLinePos2   = nY + pFontEntry->maMetric.mnDUnderlineOffset2;
    3884                 :            :             }
    3885                 :       5454 :             break;
    3886                 :            :         default:
    3887                 :      22862 :             break;
    3888                 :            :     }
    3889                 :            : 
    3890         [ +  + ]:      58594 :     if ( nLineHeight )
    3891                 :            :     {
    3892 [ +  + ][ +  + ]:      35732 :         if ( mbLineColor || mbInitLineColor )
    3893                 :            :         {
    3894                 :      30719 :             mpGraphics->SetLineColor();
    3895                 :      30719 :             mbInitLineColor = sal_True;
    3896                 :            :         }
    3897                 :      35732 :         mpGraphics->SetFillColor( ImplColorToSal( aColor ) );
    3898                 :      35732 :         mbInitFillColor = sal_True;
    3899                 :            : 
    3900                 :      35732 :         long nLeft = nDistX;
    3901                 :            : 
    3902   [ +  +  +  +  :      35732 :         switch ( eTextLine )
                -  +  - ]
    3903                 :            :         {
    3904                 :            :             case UNDERLINE_SINGLE:
    3905                 :            :             case UNDERLINE_BOLD:
    3906                 :      25536 :                 ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight );
    3907                 :      25536 :                 break;
    3908                 :            :             case UNDERLINE_DOUBLE:
    3909                 :       5454 :                 ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos,  nWidth, nLineHeight );
    3910                 :       5454 :                 ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos2, nWidth, nLineHeight );
    3911                 :       5454 :                 break;
    3912                 :            :             case UNDERLINE_DOTTED:
    3913                 :            :             case UNDERLINE_BOLDDOTTED:
    3914                 :            :                 {
    3915                 :       2564 :                     long nDotWidth = nLineHeight*mnDPIY;
    3916                 :       2564 :                     nDotWidth += mnDPIY/2;
    3917                 :       2564 :                     nDotWidth /= mnDPIY;
    3918                 :       2564 :                     long nTempWidth = nDotWidth;
    3919                 :       2564 :                     long nEnd = nLeft+nWidth;
    3920         [ +  + ]:      34776 :                     while ( nLeft < nEnd )
    3921                 :            :                     {
    3922         [ +  + ]:      32212 :                         if ( nLeft+nTempWidth > nEnd )
    3923                 :        922 :                             nTempWidth = nEnd-nLeft;
    3924                 :      32212 :                         ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempWidth, nLineHeight );
    3925                 :      32212 :                         nLeft += nDotWidth*2;
    3926                 :            :                     }
    3927                 :            :                 }
    3928                 :       2564 :                 break;
    3929                 :            :             case UNDERLINE_DASH:
    3930                 :            :             case UNDERLINE_LONGDASH:
    3931                 :            :             case UNDERLINE_BOLDDASH:
    3932                 :            :             case UNDERLINE_BOLDLONGDASH:
    3933                 :            :                 {
    3934                 :        888 :                     long nDotWidth = nLineHeight*mnDPIY;
    3935                 :        888 :                     nDotWidth += mnDPIY/2;
    3936                 :        888 :                     nDotWidth /= mnDPIY;
    3937                 :            :                     long nMinDashWidth;
    3938                 :            :                     long nMinSpaceWidth;
    3939                 :            :                     long nSpaceWidth;
    3940                 :            :                     long nDashWidth;
    3941 [ +  + ][ -  + ]:        888 :                     if ( (eTextLine == UNDERLINE_LONGDASH) ||
    3942                 :            :                          (eTextLine == UNDERLINE_BOLDLONGDASH) )
    3943                 :            :                     {
    3944                 :        516 :                         nMinDashWidth = nDotWidth*6;
    3945                 :        516 :                         nMinSpaceWidth = nDotWidth*2;
    3946                 :        516 :                         nDashWidth = 200;
    3947                 :        516 :                         nSpaceWidth = 100;
    3948                 :            :                     }
    3949                 :            :                     else
    3950                 :            :                     {
    3951                 :        372 :                         nMinDashWidth = nDotWidth*4;
    3952                 :        372 :                         nMinSpaceWidth = (nDotWidth*150)/100;
    3953                 :        372 :                         nDashWidth = 100;
    3954                 :        372 :                         nSpaceWidth = 50;
    3955                 :            :                     }
    3956                 :        888 :                     nDashWidth = ((nDashWidth*mnDPIX)+1270)/2540;
    3957                 :        888 :                     nSpaceWidth = ((nSpaceWidth*mnDPIX)+1270)/2540;
    3958                 :            :                     // DashWidth wird gegebenenfalls verbreitert, wenn
    3959                 :            :                     // die dicke der Linie im Verhaeltnis zur Laenge
    3960                 :            :                     // zu dick wird
    3961         [ +  + ]:        888 :                     if ( nDashWidth < nMinDashWidth )
    3962                 :        680 :                         nDashWidth = nMinDashWidth;
    3963         [ +  + ]:        888 :                     if ( nSpaceWidth < nMinSpaceWidth )
    3964                 :        680 :                         nSpaceWidth = nMinSpaceWidth;
    3965                 :        888 :                     long nTempWidth = nDashWidth;
    3966                 :        888 :                     long nEnd = nLeft+nWidth;
    3967         [ +  + ]:       1780 :                     while ( nLeft < nEnd )
    3968                 :            :                     {
    3969         [ +  + ]:        892 :                         if ( nLeft+nTempWidth > nEnd )
    3970                 :        864 :                             nTempWidth = nEnd-nLeft;
    3971                 :        892 :                         ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempWidth, nLineHeight );
    3972                 :        892 :                         nLeft += nDashWidth+nSpaceWidth;
    3973                 :            :                     }
    3974                 :            :                 }
    3975                 :        888 :                 break;
    3976                 :            :             case UNDERLINE_DASHDOT:
    3977                 :            :             case UNDERLINE_BOLDDASHDOT:
    3978                 :            :                 {
    3979                 :          0 :                     long nDotWidth = nLineHeight*mnDPIY;
    3980                 :          0 :                     nDotWidth += mnDPIY/2;
    3981                 :          0 :                     nDotWidth /= mnDPIY;
    3982                 :          0 :                     long nDashWidth = ((100*mnDPIX)+1270)/2540;
    3983                 :          0 :                     long nMinDashWidth = nDotWidth*4;
    3984                 :            :                     // DashWidth wird gegebenenfalls verbreitert, wenn
    3985                 :            :                     // die dicke der Linie im Verhaeltnis zur Laenge
    3986                 :            :                     // zu dick wird
    3987         [ #  # ]:          0 :                     if ( nDashWidth < nMinDashWidth )
    3988                 :          0 :                         nDashWidth = nMinDashWidth;
    3989                 :          0 :                     long nTempDotWidth = nDotWidth;
    3990                 :          0 :                     long nTempDashWidth = nDashWidth;
    3991                 :          0 :                     long nEnd = nLeft+nWidth;
    3992         [ #  # ]:          0 :                     while ( nLeft < nEnd )
    3993                 :            :                     {
    3994         [ #  # ]:          0 :                         if ( nLeft+nTempDotWidth > nEnd )
    3995                 :          0 :                             nTempDotWidth = nEnd-nLeft;
    3996                 :          0 :                         ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDotWidth, nLineHeight );
    3997                 :          0 :                         nLeft += nDotWidth*2;
    3998         [ #  # ]:          0 :                         if ( nLeft > nEnd )
    3999                 :          0 :                             break;
    4000         [ #  # ]:          0 :                         if ( nLeft+nTempDashWidth > nEnd )
    4001                 :          0 :                             nTempDashWidth = nEnd-nLeft;
    4002                 :          0 :                         ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDashWidth, nLineHeight );
    4003                 :          0 :                         nLeft += nDashWidth+nDotWidth;
    4004                 :            :                     }
    4005                 :            :                 }
    4006                 :          0 :                 break;
    4007                 :            :             case UNDERLINE_DASHDOTDOT:
    4008                 :            :             case UNDERLINE_BOLDDASHDOTDOT:
    4009                 :            :                 {
    4010                 :       1290 :                     long nDotWidth = nLineHeight*mnDPIY;
    4011                 :       1290 :                     nDotWidth += mnDPIY/2;
    4012                 :       1290 :                     nDotWidth /= mnDPIY;
    4013                 :       1290 :                     long nDashWidth = ((100*mnDPIX)+1270)/2540;
    4014                 :       1290 :                     long nMinDashWidth = nDotWidth*4;
    4015                 :            :                     // DashWidth wird gegebenenfalls verbreitert, wenn
    4016                 :            :                     // die dicke der Linie im Verhaeltnis zur Laenge
    4017                 :            :                     // zu dick wird
    4018         [ +  - ]:       1290 :                     if ( nDashWidth < nMinDashWidth )
    4019                 :       1290 :                         nDashWidth = nMinDashWidth;
    4020                 :       1290 :                     long nTempDotWidth = nDotWidth;
    4021                 :       1290 :                     long nTempDashWidth = nDashWidth;
    4022                 :       1290 :                     long nEnd = nLeft+nWidth;
    4023         [ +  + ]:       3434 :                     while ( nLeft < nEnd )
    4024                 :            :                     {
    4025         [ +  + ]:       2637 :                         if ( nLeft+nTempDotWidth > nEnd )
    4026                 :         94 :                             nTempDotWidth = nEnd-nLeft;
    4027                 :       2637 :                         ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDotWidth, nLineHeight );
    4028                 :       2637 :                         nLeft += nDotWidth*2;
    4029         [ +  + ]:       2637 :                         if ( nLeft > nEnd )
    4030                 :        177 :                             break;
    4031         [ +  + ]:       2460 :                         if ( nLeft+nTempDotWidth > nEnd )
    4032                 :        216 :                             nTempDotWidth = nEnd-nLeft;
    4033                 :       2460 :                         ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDotWidth, nLineHeight );
    4034                 :       2460 :                         nLeft += nDotWidth*2;
    4035         [ +  + ]:       2460 :                         if ( nLeft > nEnd )
    4036                 :        316 :                             break;
    4037         [ +  + ]:       2144 :                         if ( nLeft+nTempDashWidth > nEnd )
    4038                 :        633 :                             nTempDashWidth = nEnd-nLeft;
    4039                 :       2144 :                         ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDashWidth, nLineHeight );
    4040                 :       2144 :                         nLeft += nDashWidth+nDotWidth;
    4041                 :            :                     }
    4042                 :            :                 }
    4043                 :       1290 :                 break;
    4044                 :            :             default:
    4045                 :      35732 :                 break;
    4046                 :            :         }
    4047                 :            :     }
    4048                 :      58594 : }
    4049                 :            : 
    4050                 :            : // -----------------------------------------------------------------------
    4051                 :            : 
    4052                 :      28816 : void OutputDevice::ImplDrawStrikeoutLine( long nBaseX, long nBaseY,
    4053                 :            :                                           long nDistX, long nDistY, long nWidth,
    4054                 :            :                                           FontStrikeout eStrikeout,
    4055                 :            :                                           Color aColor )
    4056                 :            : {
    4057                 :      28816 :     ImplFontEntry*  pFontEntry = mpFontEntry;
    4058                 :      28816 :     long            nLineHeight = 0;
    4059                 :      28816 :     long            nLinePos  = 0;
    4060                 :      28816 :     long            nLinePos2 = 0;
    4061                 :            : 
    4062                 :      28816 :     long nY = nDistY;
    4063                 :            : 
    4064         [ +  + ]:      28816 :     if ( eStrikeout > STRIKEOUT_LAST )
    4065                 :       3430 :         eStrikeout = STRIKEOUT_SINGLE;
    4066                 :            : 
    4067   [ +  +  +  + ]:      28816 :     switch ( eStrikeout )
    4068                 :            :     {
    4069                 :            :         case STRIKEOUT_SINGLE:
    4070                 :       5890 :             nLineHeight = pFontEntry->maMetric.mnStrikeoutSize;
    4071                 :       5890 :             nLinePos    = nY + pFontEntry->maMetric.mnStrikeoutOffset;
    4072                 :       5890 :             break;
    4073                 :            :         case STRIKEOUT_BOLD:
    4074                 :        324 :             nLineHeight = pFontEntry->maMetric.mnBStrikeoutSize;
    4075                 :        324 :             nLinePos    = nY + pFontEntry->maMetric.mnBStrikeoutOffset;
    4076                 :        324 :             break;
    4077                 :            :         case STRIKEOUT_DOUBLE:
    4078                 :       2520 :             nLineHeight = pFontEntry->maMetric.mnDStrikeoutSize;
    4079                 :       2520 :             nLinePos    = nY + pFontEntry->maMetric.mnDStrikeoutOffset1;
    4080                 :       2520 :             nLinePos2   = nY + pFontEntry->maMetric.mnDStrikeoutOffset2;
    4081                 :       2520 :             break;
    4082                 :            :         default:
    4083                 :      20082 :             break;
    4084                 :            :     }
    4085                 :            : 
    4086         [ +  + ]:      28816 :     if ( nLineHeight )
    4087                 :            :     {
    4088 [ +  + ][ +  + ]:       8734 :         if ( mbLineColor || mbInitLineColor )
    4089                 :            :         {
    4090                 :       7356 :             mpGraphics->SetLineColor();
    4091                 :       7356 :             mbInitLineColor = sal_True;
    4092                 :            :         }
    4093                 :       8734 :         mpGraphics->SetFillColor( ImplColorToSal( aColor ) );
    4094                 :       8734 :         mbInitFillColor = sal_True;
    4095                 :            : 
    4096                 :       8734 :         const long& nLeft = nDistX;
    4097                 :            : 
    4098      [ +  +  - ]:       8734 :         switch ( eStrikeout )
    4099                 :            :         {
    4100                 :            :             case STRIKEOUT_SINGLE:
    4101                 :            :             case STRIKEOUT_BOLD:
    4102                 :       6214 :                 ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight );
    4103                 :       6214 :                 break;
    4104                 :            :             case STRIKEOUT_DOUBLE:
    4105                 :       2520 :                 ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight );
    4106                 :       2520 :                 ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos2, nWidth, nLineHeight );
    4107                 :       2520 :                 break;
    4108                 :            :             default:
    4109                 :       8734 :                 break;
    4110                 :            :         }
    4111                 :            :     }
    4112                 :      28816 : }
    4113                 :            : 
    4114                 :            : // -----------------------------------------------------------------------
    4115                 :            : 
    4116                 :       1674 : void OutputDevice::ImplDrawStrikeoutChar( long nBaseX, long nBaseY,
    4117                 :            :                                           long nDistX, long nDistY, long nWidth,
    4118                 :            :                                           FontStrikeout eStrikeout,
    4119                 :            :                                           Color aColor )
    4120                 :            : {
    4121                 :            :     //See qadevOOo/testdocs/StrikeThrough.odt for examples if you need
    4122                 :            :     //to tweak this
    4123         [ +  - ]:       1674 :     if (!nWidth)
    4124                 :            :         return;
    4125                 :            : 
    4126                 :            :     // PDF-export does its own strikeout drawing... why again?
    4127 [ -  + ][ #  # ]:       1674 :     if( mpPDFWriter && mpPDFWriter->isBuiltinFont(mpFontEntry->maFontSelData.mpFontData) )
         [ #  # ][ +  - ]
    4128                 :            :         return;
    4129                 :            : 
    4130                 :            :     // prepare string for strikeout measurement
    4131                 :            :     static char cStrikeoutChar;
    4132         [ +  + ]:       1674 :     if ( eStrikeout == STRIKEOUT_SLASH )
    4133                 :        564 :         cStrikeoutChar = '/';
    4134                 :            :     else // ( eStrikeout == STRIKEOUT_X )
    4135                 :       1110 :         cStrikeoutChar = 'X';
    4136                 :            :     static const int nTestStrLen = 4;
    4137                 :            :     static const int nMaxStrikeStrLen = 2048;
    4138                 :            :     xub_Unicode aChars[nMaxStrikeStrLen+1]; // +1 for valgrind...
    4139         [ +  + ]:       8370 :     for( int i = 0; i < nTestStrLen; ++i)
    4140                 :       6696 :         aChars[i] = cStrikeoutChar;
    4141                 :       1674 :     const rtl::OUString aStrikeoutTest(aChars, nTestStrLen);
    4142                 :            : 
    4143                 :            :     // calculate approximation of strikeout atom size
    4144                 :       1674 :     long nStrikeoutWidth = 0;
    4145 [ +  - ][ +  - ]:       1674 :     SalLayout* pLayout = ImplLayout( aStrikeoutTest, 0, nTestStrLen );
                 [ +  - ]
    4146         [ +  - ]:       1674 :     if( pLayout )
    4147                 :            :     {
    4148         [ +  - ]:       1674 :         nStrikeoutWidth = pLayout->GetTextWidth() / (nTestStrLen * pLayout->GetUnitsPerPixel());
    4149         [ +  - ]:       1674 :         pLayout->Release();
    4150                 :            :     }
    4151         [ +  + ]:       1674 :     if( nStrikeoutWidth <= 0 ) // sanity check
    4152                 :            :         return;
    4153                 :            : 
    4154                 :       1598 :     int nStrikeStrLen = (nWidth+(nStrikeoutWidth-1)) / nStrikeoutWidth;
    4155         [ -  + ]:       1598 :     if( nStrikeStrLen > nMaxStrikeStrLen )
    4156                 :          0 :         nStrikeStrLen = nMaxStrikeStrLen;
    4157                 :            : 
    4158                 :            :     // build the strikeout string
    4159         [ +  + ]:       8284 :     for( int i = nTestStrLen; i < nStrikeStrLen; ++i)
    4160                 :       6686 :         aChars[i] = cStrikeoutChar;
    4161                 :       1598 :     const rtl::OUString aStrikeoutText(aChars, nStrikeStrLen);
    4162                 :            : 
    4163         [ +  - ]:       1598 :     if( mpFontEntry->mnOrientation )
    4164                 :       1598 :         ImplRotatePos( 0, 0, nDistX, nDistY, mpFontEntry->mnOrientation );
    4165                 :       1598 :     nBaseX += nDistX;
    4166                 :       1598 :     nBaseY += nDistY;
    4167                 :            : 
    4168                 :            :     // strikeout text has to be left aligned
    4169                 :       1598 :     sal_uLong nOrigTLM = mnTextLayoutMode;
    4170                 :       1598 :     mnTextLayoutMode = TEXT_LAYOUT_BIDI_STRONG | TEXT_LAYOUT_COMPLEX_DISABLED;
    4171 [ +  - ][ +  - ]:       1598 :     pLayout = ImplLayout( aStrikeoutText, 0, STRING_LEN );
                 [ +  - ]
    4172                 :       1598 :     mnTextLayoutMode = nOrigTLM;
    4173                 :            : 
    4174         [ -  + ]:       1598 :     if( !pLayout )
    4175                 :            :         return;
    4176                 :            : 
    4177                 :            :     // draw the strikeout text
    4178                 :       1598 :     const Color aOldColor = GetTextColor();
    4179         [ +  - ]:       1598 :     SetTextColor( aColor );
    4180         [ +  - ]:       1598 :     ImplInitTextColor();
    4181                 :            : 
    4182                 :       1598 :     pLayout->DrawBase() = Point( nBaseX+mnTextOffX, nBaseY+mnTextOffY );
    4183                 :            : 
    4184         [ +  - ]:       1598 :     Rectangle aPixelRect;
    4185                 :       1598 :     aPixelRect.nLeft = nBaseX+mnTextOffX;
    4186                 :       1598 :     aPixelRect.nRight = aPixelRect.nLeft+nWidth;
    4187                 :       1598 :     aPixelRect.nBottom = nBaseY+mpFontEntry->maMetric.mnDescent;
    4188                 :       1598 :     aPixelRect.nTop = nBaseY-mpFontEntry->maMetric.mnAscent;
    4189                 :            : 
    4190         [ +  - ]:       1598 :     if (mpFontEntry->mnOrientation)
    4191                 :            :     {
    4192         [ +  - ]:       1598 :         Polygon aPoly( aPixelRect );
    4193         [ +  - ]:       1598 :         aPoly.Rotate( Point(nBaseX+mnTextOffX, nBaseY+mnTextOffY), mpFontEntry->mnOrientation);
    4194 [ +  - ][ +  - ]:       1598 :         aPixelRect = aPoly.GetBoundRect();
    4195                 :            :     }
    4196                 :            : 
    4197         [ +  - ]:       1598 :     Push( PUSH_CLIPREGION );
    4198 [ +  - ][ +  - ]:       1598 :     IntersectClipRegion( PixelToLogic(aPixelRect) );
    4199         [ +  - ]:       1598 :     if( mbInitClipRegion )
    4200         [ +  - ]:       1598 :         ImplInitClipRegion();
    4201                 :            : 
    4202         [ +  - ]:       1598 :     pLayout->DrawText( *mpGraphics );
    4203                 :            : 
    4204         [ +  - ]:       1598 :     pLayout->Release();
    4205         [ +  - ]:       1598 :     Pop();
    4206                 :            : 
    4207         [ +  - ]:       1598 :     SetTextColor( aOldColor );
    4208 [ +  - ][ -  + ]:       1674 :     ImplInitTextColor();
                 [ +  + ]
    4209                 :            : }
    4210                 :            : 
    4211                 :            : // -----------------------------------------------------------------------
    4212                 :            : 
    4213                 :      30502 : void OutputDevice::ImplDrawTextLine( long nX, long nY,
    4214                 :            :                                      long nDistX, long nWidth,
    4215                 :            :                                      FontStrikeout eStrikeout,
    4216                 :            :                                      FontUnderline eUnderline,
    4217                 :            :                                      FontUnderline eOverline,
    4218                 :            :                                      sal_Bool bUnderlineAbove )
    4219                 :            : {
    4220         [ +  + ]:      30502 :     if ( !nWidth )
    4221                 :      30502 :         return;
    4222                 :            : 
    4223                 :      30490 :     Color           aStrikeoutColor = GetTextColor();
    4224                 :      30490 :     Color           aUnderlineColor = GetTextLineColor();
    4225                 :      30490 :     Color           aOverlineColor  = GetOverlineColor();
    4226                 :      30490 :     sal_Bool            bStrikeoutDone = sal_False;
    4227                 :      30490 :     sal_Bool            bUnderlineDone = sal_False;
    4228                 :      30490 :     sal_Bool            bOverlineDone  = sal_False;
    4229                 :            : 
    4230         [ +  + ]:      30490 :     if ( IsRTLEnabled() )
    4231                 :            :     {
    4232                 :            :         // --- RTL --- mirror at basex
    4233                 :        198 :         long nXAdd = nWidth - nDistX;
    4234         [ +  - ]:        198 :         if( mpFontEntry->mnOrientation )
    4235                 :        198 :             nXAdd = FRound( nXAdd * cos( mpFontEntry->mnOrientation * F_PI1800 ) );
    4236                 :        198 :         nX += nXAdd - 1;
    4237                 :            :     }
    4238                 :            : 
    4239         [ +  + ]:      30490 :     if ( !IsTextLineColor() )
    4240                 :      17265 :         aUnderlineColor = GetTextColor();
    4241                 :            : 
    4242         [ +  + ]:      30490 :     if ( !IsOverlineColor() )
    4243                 :      18412 :         aOverlineColor = GetTextColor();
    4244                 :            : 
    4245 [ +  - ][ +  - ]:      30490 :     if ( (eUnderline == UNDERLINE_SMALLWAVE) ||
         [ +  - ][ +  + ]
    4246                 :            :          (eUnderline == UNDERLINE_WAVE) ||
    4247                 :            :          (eUnderline == UNDERLINE_DOUBLEWAVE) ||
    4248                 :            :          (eUnderline == UNDERLINE_BOLDWAVE) )
    4249                 :            :     {
    4250         [ +  - ]:       2386 :         ImplDrawWaveTextLine( nX, nY, nDistX, 0, nWidth, eUnderline, aUnderlineColor, bUnderlineAbove );
    4251                 :       2386 :         bUnderlineDone = sal_True;
    4252                 :            :     }
    4253 [ +  - ][ +  - ]:      30490 :     if ( (eOverline == UNDERLINE_SMALLWAVE) ||
         [ +  - ][ -  + ]
    4254                 :            :          (eOverline == UNDERLINE_WAVE) ||
    4255                 :            :          (eOverline == UNDERLINE_DOUBLEWAVE) ||
    4256                 :            :          (eOverline == UNDERLINE_BOLDWAVE) )
    4257                 :            :     {
    4258         [ #  # ]:          0 :         ImplDrawWaveTextLine( nX, nY, nDistX, 0, nWidth, eOverline, aOverlineColor, sal_True );
    4259                 :          0 :         bOverlineDone = sal_True;
    4260                 :            :     }
    4261                 :            : 
    4262 [ +  + ][ +  + ]:      30490 :     if ( (eStrikeout == STRIKEOUT_SLASH) ||
    4263                 :            :          (eStrikeout == STRIKEOUT_X) )
    4264                 :            :     {
    4265         [ +  - ]:       1674 :         ImplDrawStrikeoutChar( nX, nY, nDistX, 0, nWidth, eStrikeout, aStrikeoutColor );
    4266                 :       1674 :         bStrikeoutDone = sal_True;
    4267                 :            :     }
    4268                 :            : 
    4269         [ +  + ]:      30490 :     if ( !bUnderlineDone )
    4270         [ +  - ]:      28104 :         ImplDrawStraightTextLine( nX, nY, nDistX, 0, nWidth, eUnderline, aUnderlineColor, bUnderlineAbove );
    4271                 :            : 
    4272         [ +  - ]:      30490 :     if ( !bOverlineDone )
    4273         [ +  - ]:      30490 :         ImplDrawStraightTextLine( nX, nY, nDistX, 0, nWidth, eOverline, aOverlineColor, sal_True );
    4274                 :            : 
    4275         [ +  + ]:      30490 :     if ( !bStrikeoutDone )
    4276         [ +  - ]:      30502 :         ImplDrawStrikeoutLine( nX, nY, nDistX, 0, nWidth, eStrikeout, aStrikeoutColor );
    4277                 :            : }
    4278                 :            : 
    4279                 :            : // -----------------------------------------------------------------------
    4280                 :            : 
    4281                 :      15446 : void OutputDevice::ImplDrawTextLines( SalLayout& rSalLayout,
    4282                 :            :     FontStrikeout eStrikeout, FontUnderline eUnderline, FontUnderline eOverline, sal_Bool bWordLine, sal_Bool bUnderlineAbove )
    4283                 :            : {
    4284         [ +  + ]:      15446 :     if( bWordLine )
    4285                 :            :     {
    4286                 :            :         // draw everything relative to the layout base point
    4287                 :       7938 :      const Point aStartPt = rSalLayout.DrawBase();
    4288                 :            :      // calculate distance of each word from the base point
    4289                 :       7938 :         Point aPos;
    4290                 :       7938 :         sal_Int32 nDist = 0, nWidth = 0, nAdvance=0;
    4291                 :      47309 :         for( int nStart = 0;;)
    4292                 :            :         {
    4293                 :            :             // iterate through the layouted glyphs
    4294                 :            :             sal_GlyphId nGlyphIndex;
    4295 [ +  - ][ +  + ]:      47309 :             if( !rSalLayout.GetNextGlyphs( 1, &nGlyphIndex, aPos, nStart, &nAdvance ) )
    4296                 :            :                 break;
    4297                 :            : 
    4298                 :            :             // calculate the boundaries of each word
    4299 [ +  - ][ +  + ]:      39371 :             if( !rSalLayout.IsSpacingGlyph( nGlyphIndex ) )
    4300                 :            :             {
    4301         [ +  + ]:      37512 :                 if( !nWidth )
    4302                 :            :                 {
    4303                 :            :                     // get the distance to the base point (as projected to baseline)
    4304                 :       9200 :                     nDist = aPos.X() - aStartPt.X();
    4305         [ +  + ]:       9200 :                     if( mpFontEntry->mnOrientation )
    4306                 :            :                     {
    4307                 :       3986 :                         const long nDY = aPos.Y() - aStartPt.Y();
    4308                 :       3986 :                         const double fRad = mpFontEntry->mnOrientation * F_PI1800;
    4309                 :       3986 :                         nDist = FRound( nDist*cos(fRad) - nDY*sin(fRad) );
    4310                 :            :                     }
    4311                 :            :                 }
    4312                 :            : 
    4313                 :            :                 // update the length of the textline
    4314                 :      37512 :                 nWidth += nAdvance;
    4315                 :            :             }
    4316         [ +  + ]:       1859 :             else if( nWidth > 0 )
    4317                 :            :             {
    4318                 :            :              // draw the textline for each word
    4319                 :            :                 ImplDrawTextLine( aStartPt.X(), aStartPt.Y(), nDist, nWidth,
    4320         [ +  - ]:       1731 :                     eStrikeout, eUnderline, eOverline, bUnderlineAbove );
    4321                 :       1731 :                 nWidth = 0;
    4322                 :            :             }
    4323                 :            :         }
    4324                 :            : 
    4325                 :            :         // draw textline for the last word
    4326         [ +  + ]:       7938 :         if( nWidth > 0 )
    4327                 :            :         {
    4328                 :            :             ImplDrawTextLine( aStartPt.X(), aStartPt.Y(), nDist, nWidth,
    4329         [ +  - ]:       7938 :                 eStrikeout, eUnderline, eOverline, bUnderlineAbove );
    4330                 :            :         }
    4331                 :            :     }
    4332                 :            :     else
    4333                 :            :     {
    4334         [ +  - ]:       7508 :         Point aStartPt = rSalLayout.GetDrawPosition();
    4335         [ +  - ]:       7508 :         int nWidth = rSalLayout.GetTextWidth() / rSalLayout.GetUnitsPerPixel();
    4336                 :       7508 :         ImplDrawTextLine( aStartPt.X(), aStartPt.Y(), 0, nWidth,
    4337         [ +  - ]:       7508 :             eStrikeout, eUnderline, eOverline, bUnderlineAbove );
    4338                 :            :     }
    4339                 :      15446 : }
    4340                 :            : 
    4341                 :            : // -----------------------------------------------------------------------
    4342                 :            : 
    4343                 :      13794 : void OutputDevice::ImplDrawMnemonicLine( long nX, long nY, long nWidth )
    4344                 :            : {
    4345                 :      13794 :     long nBaseX = nX;
    4346         [ -  + ]:      13794 :     if( /*ImplHasMirroredGraphics() &&*/ IsRTLEnabled() )
    4347                 :            :     {
    4348                 :            :         // --- RTL ---
    4349                 :            :         // add some strange offset
    4350                 :          0 :         nX += 2;
    4351                 :            :         // revert the hack that will be done later in ImplDrawTextLine
    4352                 :          0 :         nX = nBaseX - nWidth - (nX - nBaseX - 1);
    4353                 :            :     }
    4354                 :            : 
    4355                 :      13794 :     ImplDrawTextLine( nX, nY, 0, nWidth, STRIKEOUT_NONE, UNDERLINE_SINGLE, UNDERLINE_NONE, sal_False );
    4356                 :      13794 : }
    4357                 :            : 
    4358                 :            : // -----------------------------------------------------------------------
    4359                 :            : 
    4360                 :      14460 : void OutputDevice::ImplGetEmphasisMark( PolyPolygon& rPolyPoly, sal_Bool& rPolyLine,
    4361                 :            :                                         Rectangle& rRect1, Rectangle& rRect2,
    4362                 :            :                                         long& rYOff, long& rWidth,
    4363                 :            :                                         FontEmphasisMark eEmphasis,
    4364                 :            :                                         long nHeight, short /*nOrient*/ )
    4365                 :            : {
    4366                 :            :     static const sal_uInt8 aAccentPolyFlags[24] =
    4367                 :            :     {
    4368                 :            :         0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 0, 2, 0, 2, 2
    4369                 :            :     };
    4370                 :            : 
    4371                 :            :     static const long aAccentPos[48] =
    4372                 :            :     {
    4373                 :            :          78,      0,
    4374                 :            :         348,     79,
    4375                 :            :         599,    235,
    4376                 :            :         843,    469,
    4377                 :            :         938,    574,
    4378                 :            :         990,    669,
    4379                 :            :         990,    773,
    4380                 :            :         990,    843,
    4381                 :            :         964,    895,
    4382                 :            :         921,    947,
    4383                 :            :         886,    982,
    4384                 :            :         860,    999,
    4385                 :            :         825,    999,
    4386                 :            :         764,    999,
    4387                 :            :         721,    964,
    4388                 :            :         686,    895,
    4389                 :            :         625,    791,
    4390                 :            :         556,    660,
    4391                 :            :         469,    504,
    4392                 :            :         400,    400,
    4393                 :            :         261,    252,
    4394                 :            :          61,     61,
    4395                 :            :           0,     27,
    4396                 :            :           9,      0
    4397                 :            :     };
    4398                 :            : 
    4399                 :      14460 :     rWidth      = 0;
    4400                 :      14460 :     rYOff       = 0;
    4401                 :      14460 :     rPolyLine   = sal_False;
    4402                 :            : 
    4403         [ -  + ]:      14460 :     if ( !nHeight )
    4404                 :      14460 :         return;
    4405                 :            : 
    4406                 :      14460 :     FontEmphasisMark    nEmphasisStyle = eEmphasis & EMPHASISMARK_STYLE;
    4407                 :      14460 :     long                nDotSize = 0;
    4408   [ +  +  +  +  :      14460 :     switch ( nEmphasisStyle )
                      - ]
    4409                 :            :     {
    4410                 :            :         case EMPHASISMARK_DOT:
    4411                 :            :             // Dot has 55% of the height
    4412                 :       4186 :             nDotSize = (nHeight*550)/1000;
    4413         [ +  + ]:       4186 :             if ( !nDotSize )
    4414                 :        368 :                 nDotSize = 1;
    4415         [ +  + ]:       4186 :             if ( nDotSize <= 2 )
    4416         [ +  - ]:       2480 :                 rRect1 = Rectangle( Point(), Size( nDotSize, nDotSize ) );
    4417                 :            :             else
    4418                 :            :             {
    4419                 :       1706 :                 long nRad = nDotSize/2;
    4420         [ +  - ]:       1706 :                 Polygon aPoly( Point( nRad, nRad ), nRad, nRad );
    4421 [ +  - ][ +  - ]:       1706 :                 rPolyPoly.Insert( aPoly );
    4422                 :            :             }
    4423                 :       4186 :             rYOff = ((nHeight*250)/1000)/2; // Center to the anthoer EmphasisMarks
    4424                 :       4186 :             rWidth = nDotSize;
    4425                 :       4186 :             break;
    4426                 :            : 
    4427                 :            :         case EMPHASISMARK_CIRCLE:
    4428                 :            :             // Dot has 80% of the height
    4429                 :       5578 :             nDotSize = (nHeight*800)/1000;
    4430         [ +  + ]:       5578 :             if ( !nDotSize )
    4431                 :        176 :                 nDotSize = 1;
    4432         [ +  + ]:       5578 :             if ( nDotSize <= 2 )
    4433         [ +  - ]:        938 :                 rRect1 = Rectangle( Point(), Size( nDotSize, nDotSize ) );
    4434                 :            :             else
    4435                 :            :             {
    4436                 :       4640 :                 long nRad = nDotSize/2;
    4437         [ +  - ]:       4640 :                 Polygon aPoly( Point( nRad, nRad ), nRad, nRad );
    4438         [ +  - ]:       4640 :                 rPolyPoly.Insert( aPoly );
    4439                 :            :                 // BorderWidth is 15%
    4440                 :       4640 :                 long nBorder = (nDotSize*150)/1000;
    4441         [ +  - ]:       4640 :                 if ( nBorder <= 1 )
    4442                 :       4640 :                     rPolyLine = sal_True;
    4443                 :            :                 else
    4444                 :            :                 {
    4445                 :            :                     Polygon aPoly2( Point( nRad, nRad ),
    4446         [ #  # ]:          0 :                                     nRad-nBorder, nRad-nBorder );
    4447 [ #  # ][ #  # ]:          0 :                     rPolyPoly.Insert( aPoly2 );
    4448         [ +  - ]:       4640 :                 }
    4449                 :            :             }
    4450                 :       5578 :             rWidth = nDotSize;
    4451                 :       5578 :             break;
    4452                 :            : 
    4453                 :            :         case EMPHASISMARK_DISC:
    4454                 :            :             // Dot has 80% of the height
    4455                 :       3898 :             nDotSize = (nHeight*800)/1000;
    4456         [ -  + ]:       3898 :             if ( !nDotSize )
    4457                 :          0 :                 nDotSize = 1;
    4458         [ -  + ]:       3898 :             if ( nDotSize <= 2 )
    4459         [ #  # ]:          0 :                 rRect1 = Rectangle( Point(), Size( nDotSize, nDotSize ) );
    4460                 :            :             else
    4461                 :            :             {
    4462                 :       3898 :                 long nRad = nDotSize/2;
    4463         [ +  - ]:       3898 :                 Polygon aPoly( Point( nRad, nRad ), nRad, nRad );
    4464 [ +  - ][ +  - ]:       3898 :                 rPolyPoly.Insert( aPoly );
    4465                 :            :             }
    4466                 :       3898 :             rWidth = nDotSize;
    4467                 :       3898 :             break;
    4468                 :            : 
    4469                 :            :         case EMPHASISMARK_ACCENT:
    4470                 :            :             // Dot has 80% of the height
    4471                 :        798 :             nDotSize = (nHeight*800)/1000;
    4472         [ -  + ]:        798 :             if ( !nDotSize )
    4473                 :          0 :                 nDotSize = 1;
    4474         [ -  + ]:        798 :             if ( nDotSize <= 2 )
    4475                 :            :             {
    4476         [ #  # ]:          0 :                 if ( nDotSize == 1 )
    4477                 :            :                 {
    4478         [ #  # ]:          0 :                     rRect1 = Rectangle( Point(), Size( nDotSize, nDotSize ) );
    4479                 :          0 :                     rWidth = nDotSize;
    4480                 :            :                 }
    4481                 :            :                 else
    4482                 :            :                 {
    4483         [ #  # ]:          0 :                     rRect1 = Rectangle( Point(), Size( 1, 1 ) );
    4484         [ #  # ]:          0 :                     rRect2 = Rectangle( Point( 1, 1 ), Size( 1, 1 ) );
    4485                 :            :                 }
    4486                 :            :             }
    4487                 :            :             else
    4488                 :            :             {
    4489                 :            :                 Polygon aPoly( sizeof( aAccentPos ) / sizeof( long ) / 2,
    4490                 :            :                                (const Point*)aAccentPos,
    4491         [ +  - ]:        798 :                                aAccentPolyFlags );
    4492                 :        798 :                 double dScale = ((double)nDotSize)/1000.0;
    4493         [ +  - ]:        798 :                 aPoly.Scale( dScale, dScale );
    4494         [ +  - ]:        798 :                 Polygon aTemp;
    4495         [ +  - ]:        798 :                 aPoly.AdaptiveSubdivide( aTemp );
    4496         [ +  - ]:        798 :                 Rectangle aBoundRect = aTemp.GetBoundRect();
    4497         [ +  - ]:        798 :                 rWidth = aBoundRect.GetWidth();
    4498         [ +  - ]:        798 :                 nDotSize = aBoundRect.GetHeight();
    4499 [ +  - ][ +  - ]:        798 :                 rPolyPoly.Insert( aTemp );
                 [ +  - ]
    4500                 :            :             }
    4501                 :        798 :             break;
    4502                 :            :     }
    4503                 :            : 
    4504                 :            :     // calculate position
    4505                 :      14460 :     long nOffY = 1+(mnDPIY/300); // one visible pixel space
    4506                 :      14460 :     long nSpaceY = nHeight-nDotSize;
    4507         [ +  + ]:      14460 :     if ( nSpaceY >= nOffY*2 )
    4508                 :      10542 :         rYOff += nOffY;
    4509         [ +  - ]:      14460 :     if ( !(eEmphasis & EMPHASISMARK_POS_BELOW) )
    4510                 :      14460 :         rYOff += nDotSize;
    4511                 :            : }
    4512                 :            : 
    4513                 :            : // -----------------------------------------------------------------------
    4514                 :            : 
    4515                 :      66998 : void OutputDevice::ImplDrawEmphasisMark( long nBaseX, long nX, long nY,
    4516                 :            :                                          const PolyPolygon& rPolyPoly, sal_Bool bPolyLine,
    4517                 :            :                                          const Rectangle& rRect1, const Rectangle& rRect2 )
    4518                 :            : {
    4519         [ +  + ]:      66998 :     if( IsRTLEnabled() )
    4520                 :            :         // --- RTL --- mirror at basex
    4521                 :        570 :         nX = nBaseX - (nX - nBaseX - 1);
    4522                 :            : 
    4523                 :      66998 :     nX -= mnOutOffX;
    4524                 :      66998 :     nY -= mnOutOffY;
    4525                 :            : 
    4526         [ +  + ]:      66998 :     if ( rPolyPoly.Count() )
    4527                 :            :     {
    4528         [ +  + ]:      51400 :         if ( bPolyLine )
    4529                 :            :         {
    4530 [ +  - ][ +  - ]:      21014 :             Polygon aPoly = rPolyPoly.GetObject( 0 );
    4531         [ +  - ]:      21014 :             aPoly.Move( nX, nY );
    4532 [ +  - ][ +  - ]:      21014 :             DrawPolyLine( aPoly );
    4533                 :            :         }
    4534                 :            :         else
    4535                 :            :         {
    4536         [ +  - ]:      30386 :             PolyPolygon aPolyPoly = rPolyPoly;
    4537         [ +  - ]:      30386 :             aPolyPoly.Move( nX, nY );
    4538 [ +  - ][ +  - ]:      30386 :             DrawPolyPolygon( aPolyPoly );
    4539                 :            :         }
    4540                 :            :     }
    4541                 :            : 
    4542         [ +  + ]:      66998 :     if ( !rRect1.IsEmpty() )
    4543                 :            :     {
    4544                 :      15598 :         Rectangle aRect( Point( nX+rRect1.Left(),
    4545 [ +  - ][ +  - ]:      31196 :                                 nY+rRect1.Top() ), rRect1.GetSize() );
    4546         [ +  - ]:      15598 :         DrawRect( aRect );
    4547                 :            :     }
    4548                 :            : 
    4549         [ -  + ]:      66998 :     if ( !rRect2.IsEmpty() )
    4550                 :            :     {
    4551                 :          0 :         Rectangle aRect( Point( nX+rRect2.Left(),
    4552 [ #  # ][ #  # ]:          0 :                                 nY+rRect2.Top() ), rRect2.GetSize() );
    4553                 :            : 
    4554         [ #  # ]:          0 :         DrawRect( aRect );
    4555                 :            :     }
    4556                 :      66998 : }
    4557                 :            : 
    4558                 :            : // -----------------------------------------------------------------------
    4559                 :            : 
    4560                 :      14460 : void OutputDevice::ImplDrawEmphasisMarks( SalLayout& rSalLayout )
    4561                 :            : {
    4562                 :      14460 :     Color               aOldLineColor   = GetLineColor();
    4563                 :      14460 :     Color               aOldFillColor   = GetFillColor();
    4564                 :      14460 :     sal_Bool                bOldMap         = mbMap;
    4565                 :      14460 :     GDIMetaFile*        pOldMetaFile    = mpMetaFile;
    4566                 :      14460 :     mpMetaFile = NULL;
    4567         [ +  - ]:      14460 :     EnableMapMode( sal_False );
    4568                 :            : 
    4569         [ +  - ]:      14460 :     FontEmphasisMark    nEmphasisMark = ImplGetEmphasisMarkStyle( maFont );
    4570         [ +  - ]:      14460 :     PolyPolygon         aPolyPoly;
    4571         [ +  - ]:      14460 :     Rectangle           aRect1;
    4572         [ +  - ]:      14460 :     Rectangle           aRect2;
    4573                 :            :     long                nEmphasisYOff;
    4574                 :            :     long                nEmphasisWidth;
    4575                 :            :     long                nEmphasisHeight;
    4576                 :            :     sal_Bool                bPolyLine;
    4577                 :            : 
    4578         [ -  + ]:      14460 :     if ( nEmphasisMark & EMPHASISMARK_POS_BELOW )
    4579                 :          0 :         nEmphasisHeight = mnEmphasisDescent;
    4580                 :            :     else
    4581                 :      14460 :         nEmphasisHeight = mnEmphasisAscent;
    4582                 :            : 
    4583                 :            :     ImplGetEmphasisMark( aPolyPoly, bPolyLine,
    4584                 :            :                          aRect1, aRect2,
    4585                 :            :                          nEmphasisYOff, nEmphasisWidth,
    4586                 :            :                          nEmphasisMark,
    4587         [ +  - ]:      14460 :                          nEmphasisHeight, mpFontEntry->mnOrientation );
    4588                 :            : 
    4589         [ +  + ]:      14460 :     if ( bPolyLine )
    4590                 :            :     {
    4591         [ +  - ]:       4640 :         SetLineColor( GetTextColor() );
    4592         [ +  - ]:       4640 :         SetFillColor();
    4593                 :            :     }
    4594                 :            :     else
    4595                 :            :     {
    4596         [ +  - ]:       9820 :         SetLineColor();
    4597         [ +  - ]:       9820 :         SetFillColor( GetTextColor() );
    4598                 :            :     }
    4599                 :            : 
    4600                 :      14460 :     Point aOffset = Point(0,0);
    4601                 :            : 
    4602         [ -  + ]:      14460 :     if ( nEmphasisMark & EMPHASISMARK_POS_BELOW )
    4603                 :          0 :         aOffset.Y() += mpFontEntry->maMetric.mnDescent + nEmphasisYOff;
    4604                 :            :     else
    4605                 :      14460 :         aOffset.Y() -= mpFontEntry->maMetric.mnAscent + nEmphasisYOff;
    4606                 :            : 
    4607                 :      14460 :     long nEmphasisWidth2  = nEmphasisWidth / 2;
    4608                 :      14460 :     long nEmphasisHeight2 = nEmphasisHeight / 2;
    4609                 :      14460 :     aOffset += Point( nEmphasisWidth2, nEmphasisHeight2 );
    4610                 :            : 
    4611                 :      14460 :     Point aOutPoint;
    4612         [ +  - ]:      14460 :     Rectangle aRectangle;
    4613                 :      84975 :     for( int nStart = 0;;)
    4614                 :            :     {
    4615                 :            :         sal_GlyphId nGlyphIndex;
    4616 [ +  - ][ +  + ]:      84975 :         if( !rSalLayout.GetNextGlyphs( 1, &nGlyphIndex, aOutPoint, nStart ) )
    4617                 :            :             break;
    4618                 :            : 
    4619 [ +  - ][ -  + ]:      70515 :         if( !mpGraphics->GetGlyphBoundRect( nGlyphIndex, aRectangle ) )
    4620                 :          0 :             continue;
    4621                 :            : 
    4622 [ +  - ][ +  + ]:      70515 :         if( !rSalLayout.IsSpacingGlyph( nGlyphIndex ) )
    4623                 :            :         {
    4624                 :      66998 :             Point aAdjPoint = aOffset;
    4625         [ +  - ]:      66998 :             aAdjPoint.X() += aRectangle.Left() + (aRectangle.GetWidth() - nEmphasisWidth) / 2;
    4626         [ +  + ]:      66998 :             if ( mpFontEntry->mnOrientation )
    4627                 :      41978 :                 ImplRotatePos( 0, 0, aAdjPoint.X(), aAdjPoint.Y(), mpFontEntry->mnOrientation );
    4628                 :      66998 :             aOutPoint += aAdjPoint;
    4629                 :      66998 :             aOutPoint -= Point( nEmphasisWidth2, nEmphasisHeight2 );
    4630                 :      66998 :             ImplDrawEmphasisMark( rSalLayout.DrawBase().X(),
    4631                 :      66998 :                                   aOutPoint.X(), aOutPoint.Y(),
    4632         [ +  - ]:      70515 :                                   aPolyPoly, bPolyLine, aRect1, aRect2 );
    4633                 :            :         }
    4634                 :            :     }
    4635                 :            : 
    4636         [ +  - ]:      14460 :     SetLineColor( aOldLineColor );
    4637         [ +  - ]:      14460 :     SetFillColor( aOldFillColor );
    4638         [ +  - ]:      14460 :     EnableMapMode( bOldMap );
    4639         [ +  - ]:      14460 :     mpMetaFile = pOldMetaFile;
    4640                 :      14460 : }
    4641                 :            : 
    4642                 :            : // -----------------------------------------------------------------------
    4643                 :            : 
    4644                 :          0 : bool OutputDevice::ImplDrawRotateText( SalLayout& rSalLayout )
    4645                 :            : {
    4646                 :          0 :     int nX = rSalLayout.DrawBase().X();
    4647                 :          0 :     int nY = rSalLayout.DrawBase().Y();
    4648                 :            : 
    4649         [ #  # ]:          0 :     Rectangle aBoundRect;
    4650                 :          0 :     rSalLayout.DrawBase() = Point( 0, 0 );
    4651                 :          0 :     rSalLayout.DrawOffset() = Point( 0, 0 );
    4652 [ #  # ][ #  # ]:          0 :     if( !rSalLayout.GetBoundRect( *mpGraphics, aBoundRect ) )
    4653                 :            :     {
    4654                 :            :         // guess vertical text extents if GetBoundRect failed
    4655         [ #  # ]:          0 :         int nRight = rSalLayout.GetTextWidth();
    4656                 :          0 :         int nTop = mpFontEntry->maMetric.mnAscent + mnEmphasisAscent;
    4657                 :          0 :         long nHeight = mpFontEntry->mnLineHeight + mnEmphasisAscent + mnEmphasisDescent;
    4658         [ #  # ]:          0 :         aBoundRect = Rectangle( 0, -nTop, nRight, nHeight - nTop );
    4659                 :            :     }
    4660                 :            : 
    4661                 :            :     // cache virtual device for rotation
    4662         [ #  # ]:          0 :     if ( !mpOutDevData )
    4663         [ #  # ]:          0 :         ImplInitOutDevData();
    4664         [ #  # ]:          0 :     if ( !mpOutDevData->mpRotateDev )
    4665 [ #  # ][ #  # ]:          0 :         mpOutDevData->mpRotateDev = new VirtualDevice( *this, 1 );
    4666                 :          0 :     VirtualDevice* pVDev = mpOutDevData->mpRotateDev;
    4667                 :            : 
    4668                 :            :     // size it accordingly
    4669 [ #  # ][ #  # ]:          0 :     if( !pVDev->SetOutputSizePixel( aBoundRect.GetSize() ) )
                 [ #  # ]
    4670                 :          0 :         return false;
    4671                 :            : 
    4672         [ #  # ]:          0 :     Font aFont( GetFont() );
    4673         [ #  # ]:          0 :     aFont.SetOrientation( 0 );
    4674         [ #  # ]:          0 :     aFont.SetSize( Size( mpFontEntry->maFontSelData.mnWidth, mpFontEntry->maFontSelData.mnHeight ) );
    4675         [ #  # ]:          0 :     pVDev->SetFont( aFont );
    4676         [ #  # ]:          0 :     pVDev->SetTextColor( Color( COL_BLACK ) );
    4677         [ #  # ]:          0 :     pVDev->SetTextFillColor();
    4678         [ #  # ]:          0 :     pVDev->ImplNewFont();
    4679         [ #  # ]:          0 :     pVDev->ImplInitFont();
    4680         [ #  # ]:          0 :     pVDev->ImplInitTextColor();
    4681                 :            : 
    4682                 :            :     // draw text into upper left corner
    4683                 :          0 :     rSalLayout.DrawBase() -= aBoundRect.TopLeft();
    4684         [ #  # ]:          0 :     rSalLayout.DrawText( *((OutputDevice*)pVDev)->mpGraphics );
    4685                 :            : 
    4686 [ #  # ][ #  # ]:          0 :     Bitmap aBmp = pVDev->GetBitmap( Point(), aBoundRect.GetSize() );
    4687 [ #  # ][ #  # ]:          0 :     if ( !aBmp || !aBmp.Rotate( mpFontEntry->mnOwnOrientation, COL_WHITE ) )
         [ #  # ][ #  # ]
           [ #  #  #  # ]
    4688                 :          0 :         return false;
    4689                 :            : 
    4690                 :            :     // calculate rotation offset
    4691         [ #  # ]:          0 :     Polygon aPoly( aBoundRect );
    4692         [ #  # ]:          0 :     aPoly.Rotate( Point(), mpFontEntry->mnOwnOrientation );
    4693         [ #  # ]:          0 :     Point aPoint = aPoly.GetBoundRect().TopLeft();
    4694                 :          0 :     aPoint += Point( nX, nY );
    4695                 :            : 
    4696                 :            :     // mask output with text colored bitmap
    4697                 :          0 :     GDIMetaFile* pOldMetaFile = mpMetaFile;
    4698                 :          0 :     long nOldOffX = mnOutOffX;
    4699                 :          0 :     long nOldOffY = mnOutOffY;
    4700                 :          0 :     sal_Bool bOldMap = mbMap;
    4701                 :            : 
    4702                 :          0 :     mnOutOffX   = 0L;
    4703                 :          0 :     mnOutOffY   = 0L;
    4704                 :          0 :     mpMetaFile  = NULL;
    4705         [ #  # ]:          0 :     EnableMapMode( sal_False );
    4706                 :            : 
    4707         [ #  # ]:          0 :     DrawMask( aPoint, aBmp, GetTextColor() );
    4708                 :            : 
    4709         [ #  # ]:          0 :     EnableMapMode( bOldMap );
    4710                 :          0 :     mnOutOffX   = nOldOffX;
    4711                 :          0 :     mnOutOffY   = nOldOffY;
    4712                 :          0 :     mpMetaFile  = pOldMetaFile;
    4713                 :            : 
    4714 [ #  # ][ #  # ]:          0 :     return true;
                 [ #  # ]
    4715                 :            : }
    4716                 :            : 
    4717                 :            : // -----------------------------------------------------------------------
    4718                 :            : 
    4719                 :     150376 : void OutputDevice::ImplDrawTextDirect( SalLayout& rSalLayout, sal_Bool bTextLines )
    4720                 :            : {
    4721         [ -  + ]:     150376 :     if( mpFontEntry->mnOwnOrientation )
    4722         [ #  # ]:          0 :         if( ImplDrawRotateText( rSalLayout ) )
    4723                 :     150376 :             return;
    4724                 :            : 
    4725                 :     150376 :     long nOldX = rSalLayout.DrawBase().X();
    4726 [ #  # ][ +  - ]:     150376 :     if( ! (mpPDFWriter && mpPDFWriter->isBuiltinFont(mpFontEntry->maFontSelData.mpFontData) ) )
                 [ -  + ]
    4727                 :            :     {
    4728         [ +  + ]:     150376 :         if( ImplHasMirroredGraphics() )
    4729                 :            :         {
    4730         [ +  - ]:        386 :             long w = meOutDevType == OUTDEV_VIRDEV ? mnOutWidth : mpGraphics->GetGraphicsWidth();
    4731                 :        386 :             long x = rSalLayout.DrawBase().X();
    4732                 :        386 :                rSalLayout.DrawBase().X() = w - 1 - x;
    4733         [ -  + ]:        386 :             if( !IsRTLEnabled() )
    4734                 :            :             {
    4735                 :          0 :                 OutputDevice *pOutDevRef = (OutputDevice *)this;
    4736                 :            :                 // mirror this window back
    4737                 :          0 :                 long devX = w-pOutDevRef->mnOutWidth-pOutDevRef->mnOutOffX;   // re-mirrored mnOutOffX
    4738                 :          0 :                 rSalLayout.DrawBase().X() = devX + ( pOutDevRef->mnOutWidth - 1 - (rSalLayout.DrawBase().X() - devX) ) ;
    4739                 :            :             }
    4740                 :            :         }
    4741         [ -  + ]:     149990 :         else if( IsRTLEnabled() )
    4742                 :            :         {
    4743                 :            :             //long w = meOutDevType == OUTDEV_VIRDEV ? mnOutWidth : mpGraphics->GetGraphicsWidth();
    4744                 :            :             //long x = rSalLayout.DrawBase().X();
    4745                 :          0 :             OutputDevice *pOutDevRef = (OutputDevice *)this;
    4746                 :            :             // mirror this window back
    4747                 :          0 :             long devX = pOutDevRef->mnOutOffX;   // re-mirrored mnOutOffX
    4748                 :          0 :             rSalLayout.DrawBase().X() = pOutDevRef->mnOutWidth - 1 - (rSalLayout.DrawBase().X() - devX) + devX;
    4749                 :            :         }
    4750                 :            : 
    4751                 :     150376 :         rSalLayout.DrawText( *mpGraphics );
    4752                 :            :     }
    4753                 :            : 
    4754                 :     150376 :     rSalLayout.DrawBase().X() = nOldX;
    4755                 :            : 
    4756         [ +  + ]:     150376 :     if( bTextLines )
    4757                 :            :         ImplDrawTextLines( rSalLayout,
    4758                 :            :             maFont.GetStrikeout(), maFont.GetUnderline(), maFont.GetOverline(),
    4759                 :      15446 :             maFont.IsWordLineMode(), ImplIsUnderlineAbove( maFont ) );
    4760                 :            : 
    4761                 :            :     // emphasis marks
    4762         [ +  + ]:     150376 :     if( maFont.GetEmphasisMark() & EMPHASISMARK_STYLE )
    4763                 :      14460 :         ImplDrawEmphasisMarks( rSalLayout );
    4764                 :            : }
    4765                 :            : 
    4766                 :            : // -----------------------------------------------------------------------
    4767                 :            : 
    4768                 :       6178 : void OutputDevice::ImplDrawSpecialText( SalLayout& rSalLayout )
    4769                 :            : {
    4770                 :       6178 :     Color       aOldColor           = GetTextColor();
    4771                 :       6178 :     Color       aOldTextLineColor   = GetTextLineColor();
    4772                 :       6178 :     Color       aOldOverlineColor   = GetOverlineColor();
    4773         [ +  - ]:       6178 :     FontRelief  eRelief             = maFont.GetRelief();
    4774                 :            : 
    4775                 :       6178 :     Point aOrigPos = rSalLayout.DrawBase();
    4776         [ +  + ]:       6178 :     if ( eRelief != RELIEF_NONE )
    4777                 :            :     {
    4778                 :       5797 :         Color   aReliefColor( COL_LIGHTGRAY );
    4779                 :       5797 :         Color   aTextColor( aOldColor );
    4780                 :            : 
    4781                 :       5797 :         Color   aTextLineColor( aOldTextLineColor );
    4782                 :       5797 :         Color   aOverlineColor( aOldOverlineColor );
    4783                 :            : 
    4784                 :            :         // we don't have a automatic color, so black is always drawn on white
    4785         [ +  + ]:       5797 :         if ( aTextColor.GetColor() == COL_BLACK )
    4786                 :       1788 :             aTextColor = Color( COL_WHITE );
    4787         [ +  + ]:       5797 :         if ( aTextLineColor.GetColor() == COL_BLACK )
    4788                 :       1390 :             aTextLineColor = Color( COL_WHITE );
    4789         [ +  + ]:       5797 :         if ( aOverlineColor.GetColor() == COL_BLACK )
    4790                 :       1390 :             aOverlineColor = Color( COL_WHITE );
    4791                 :            : 
    4792                 :            :         // relief-color is black for white text, in all other cases
    4793                 :            :         // we set this to LightGray
    4794         [ +  + ]:       5797 :         if ( aTextColor.GetColor() == COL_WHITE )
    4795                 :       1832 :             aReliefColor = Color( COL_BLACK );
    4796         [ +  - ]:       5797 :         SetTextLineColor( aReliefColor );
    4797         [ +  - ]:       5797 :         SetOverlineColor( aReliefColor );
    4798         [ +  - ]:       5797 :         SetTextColor( aReliefColor );
    4799         [ +  - ]:       5797 :         ImplInitTextColor();
    4800                 :            : 
    4801                 :            :         // calculate offset - for high resolution printers the offset
    4802                 :            :         // should be greater so that the effect is visible
    4803                 :       5797 :         long nOff = 1;
    4804                 :       5797 :         nOff += mnDPIX/300;
    4805                 :            : 
    4806         [ +  + ]:       5797 :         if ( eRelief == RELIEF_ENGRAVED )
    4807                 :       2746 :             nOff = -nOff;
    4808                 :       5797 :         rSalLayout.DrawOffset() += Point( nOff, nOff);
    4809         [ +  - ]:       5797 :         ImplDrawTextDirect( rSalLayout, mbTextLines );
    4810                 :       5797 :         rSalLayout.DrawOffset() -= Point( nOff, nOff);
    4811                 :            : 
    4812         [ +  - ]:       5797 :         SetTextLineColor( aTextLineColor );
    4813         [ +  - ]:       5797 :         SetOverlineColor( aOverlineColor );
    4814         [ +  - ]:       5797 :         SetTextColor( aTextColor );
    4815         [ +  - ]:       5797 :         ImplInitTextColor();
    4816         [ +  - ]:       5797 :         ImplDrawTextDirect( rSalLayout, mbTextLines );
    4817                 :            : 
    4818         [ +  - ]:       5797 :         SetTextLineColor( aOldTextLineColor );
    4819         [ +  - ]:       5797 :         SetOverlineColor( aOldOverlineColor );
    4820                 :            : 
    4821         [ +  + ]:       5797 :         if ( aTextColor != aOldColor )
    4822                 :            :         {
    4823         [ +  - ]:       1788 :             SetTextColor( aOldColor );
    4824         [ +  - ]:       5797 :             ImplInitTextColor();
    4825                 :            :         }
    4826                 :            :     }
    4827                 :            :     else
    4828                 :            :     {
    4829 [ +  - ][ +  + ]:        381 :         if ( maFont.IsShadow() )
    4830                 :            :         {
    4831                 :        317 :             long nOff = 1 + ((mpFontEntry->mnLineHeight-24)/24);
    4832 [ +  - ][ +  + ]:        317 :             if ( maFont.IsOutline() )
    4833                 :        252 :                 nOff++;
    4834         [ +  - ]:        317 :             SetTextLineColor();
    4835         [ +  - ]:        317 :             SetOverlineColor();
    4836 [ +  + ][ +  - ]:        564 :             if ( (GetTextColor().GetColor() == COL_BLACK)
                 [ +  - ]
    4837         [ +  - ]:        247 :             ||   (GetTextColor().GetLuminance() < 8) )
    4838         [ +  - ]:        317 :                 SetTextColor( Color( COL_LIGHTGRAY ) );
    4839                 :            :             else
    4840         [ #  # ]:          0 :                 SetTextColor( Color( COL_BLACK ) );
    4841         [ +  - ]:        317 :             ImplInitTextColor();
    4842                 :        317 :             rSalLayout.DrawBase() += Point( nOff, nOff );
    4843         [ +  - ]:        317 :             ImplDrawTextDirect( rSalLayout, mbTextLines );
    4844                 :        317 :             rSalLayout.DrawBase() -= Point( nOff, nOff );
    4845         [ +  - ]:        317 :             SetTextColor( aOldColor );
    4846         [ +  - ]:        317 :             SetTextLineColor( aOldTextLineColor );
    4847         [ +  - ]:        317 :             SetOverlineColor( aOldOverlineColor );
    4848         [ +  - ]:        317 :             ImplInitTextColor();
    4849                 :            : 
    4850 [ +  - ][ +  + ]:        317 :             if ( !maFont.IsOutline() )
    4851         [ +  - ]:         65 :                 ImplDrawTextDirect( rSalLayout, mbTextLines );
    4852                 :            :         }
    4853                 :            : 
    4854 [ +  - ][ +  + ]:        381 :         if ( maFont.IsOutline() )
    4855                 :            :         {
    4856                 :        316 :             rSalLayout.DrawBase() = aOrigPos + Point(-1,-1);
    4857         [ +  - ]:        316 :             ImplDrawTextDirect( rSalLayout, mbTextLines );
    4858                 :        316 :             rSalLayout.DrawBase() = aOrigPos + Point(+1,+1);
    4859         [ +  - ]:        316 :             ImplDrawTextDirect( rSalLayout, mbTextLines );
    4860                 :        316 :             rSalLayout.DrawBase() = aOrigPos + Point(-1,+0);
    4861         [ +  - ]:        316 :             ImplDrawTextDirect( rSalLayout, mbTextLines );
    4862                 :        316 :             rSalLayout.DrawBase() = aOrigPos + Point(-1,+1);
    4863         [ +  - ]:        316 :             ImplDrawTextDirect( rSalLayout, mbTextLines );
    4864                 :        316 :             rSalLayout.DrawBase() = aOrigPos + Point(+0,+1);
    4865         [ +  - ]:        316 :             ImplDrawTextDirect( rSalLayout, mbTextLines );
    4866                 :        316 :             rSalLayout.DrawBase() = aOrigPos + Point(+0,-1);
    4867         [ +  - ]:        316 :             ImplDrawTextDirect( rSalLayout, mbTextLines );
    4868                 :        316 :             rSalLayout.DrawBase() = aOrigPos + Point(+1,-1);
    4869         [ +  - ]:        316 :             ImplDrawTextDirect( rSalLayout, mbTextLines );
    4870                 :        316 :             rSalLayout.DrawBase() = aOrigPos + Point(+1,+0);
    4871         [ +  - ]:        316 :             ImplDrawTextDirect( rSalLayout, mbTextLines );
    4872                 :        316 :             rSalLayout.DrawBase() = aOrigPos;
    4873                 :            : 
    4874         [ +  - ]:        316 :             SetTextColor( Color( COL_WHITE ) );
    4875         [ +  - ]:        316 :             SetTextLineColor( Color( COL_WHITE ) );
    4876         [ +  - ]:        316 :             SetOverlineColor( Color( COL_WHITE ) );
    4877         [ +  - ]:        316 :             ImplInitTextColor();
    4878         [ +  - ]:        316 :             ImplDrawTextDirect( rSalLayout, mbTextLines );
    4879         [ +  - ]:        316 :             SetTextColor( aOldColor );
    4880         [ +  - ]:        316 :             SetTextLineColor( aOldTextLineColor );
    4881         [ +  - ]:        316 :             SetOverlineColor( aOldOverlineColor );
    4882         [ +  - ]:        316 :             ImplInitTextColor();
    4883                 :            :         }
    4884                 :            :     }
    4885                 :       6178 : }
    4886                 :            : 
    4887                 :            : // -----------------------------------------------------------------------
    4888                 :            : 
    4889                 :     143055 : void OutputDevice::ImplDrawText( SalLayout& rSalLayout )
    4890                 :            : {
    4891         [ +  + ]:     143055 :     if( mbInitClipRegion )
    4892                 :       8486 :         ImplInitClipRegion();
    4893         [ +  + ]:     143055 :     if( mbOutputClipped )
    4894                 :     143055 :         return;
    4895         [ +  + ]:     141734 :     if( mbInitTextColor )
    4896                 :      43737 :         ImplInitTextColor();
    4897                 :            : 
    4898                 :     141734 :     rSalLayout.DrawBase() += Point( mnTextOffX, mnTextOffY );
    4899                 :            : 
    4900         [ +  + ]:     141734 :     if( IsTextFillColor() )
    4901                 :       5844 :         ImplDrawTextBackground( rSalLayout );
    4902                 :            : 
    4903         [ +  + ]:     141734 :     if( mbTextSpecial )
    4904                 :       6178 :         ImplDrawSpecialText( rSalLayout );
    4905                 :            :     else
    4906                 :     135556 :         ImplDrawTextDirect( rSalLayout, mbTextLines );
    4907                 :            : }
    4908                 :            : 
    4909                 :            : // -----------------------------------------------------------------------
    4910                 :            : 
    4911                 :       2634 : long OutputDevice::ImplGetTextLines( ImplMultiTextLineInfo& rLineInfo,
    4912                 :            :                                      long nWidth, const XubString& rStr,
    4913                 :            :                                      sal_uInt16 nStyle, const ::vcl::ITextLayout& _rLayout )
    4914                 :            : {
    4915                 :            :     DBG_ASSERTWARNING( nWidth >= 0, "ImplGetTextLines: nWidth <= 0!" );
    4916                 :            : 
    4917         [ -  + ]:       2634 :     if ( nWidth <= 0 )
    4918                 :          0 :         nWidth = 1;
    4919                 :            : 
    4920                 :       2634 :     long nMaxLineWidth  = 0;
    4921                 :       2634 :     rLineInfo.Clear();
    4922 [ +  - ][ +  + ]:       2634 :     if ( rStr.Len() && (nWidth > 0) )
                 [ +  + ]
    4923                 :            :     {
    4924         [ +  - ]:       2397 :         ::rtl::OUString aText( rStr );
    4925                 :       2397 :         uno::Reference < i18n::XBreakIterator > xBI;
    4926                 :            :         // get service provider
    4927         [ +  - ]:       2397 :         uno::Reference< lang::XMultiServiceFactory > xSMgr( unohelper::GetMultiServiceFactory() );
    4928                 :            : 
    4929                 :       2397 :         uno::Reference< linguistic2::XHyphenator > xHyph;
    4930         [ +  - ]:       2397 :         if( xSMgr.is() )
    4931                 :            :         {
    4932 [ +  - ][ +  - ]:       2397 :             uno::Reference< linguistic2::XLinguServiceManager> xLinguMgr(xSMgr->createInstance(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.linguistic2.LinguServiceManager"))),uno::UNO_QUERY);
         [ +  - ][ +  - ]
    4933         [ +  + ]:       2397 :             if ( xLinguMgr.is() )
    4934                 :            :             {
    4935 [ +  - ][ +  - ]:       2393 :                 xHyph = xLinguMgr->getHyphenator();
                 [ +  - ]
    4936                 :       2397 :             }
    4937                 :            :         }
    4938                 :            : 
    4939 [ +  - ][ +  - ]:       2397 :         i18n::LineBreakHyphenationOptions aHyphOptions( xHyph, uno::Sequence <beans::PropertyValue>(), 1 );
                 [ +  - ]
    4940                 :       2397 :         i18n::LineBreakUserOptions aUserOptions;
    4941                 :            : 
    4942                 :       2397 :         xub_StrLen nPos = 0;
    4943                 :       2397 :         xub_StrLen nLen = rStr.Len();
    4944         [ +  + ]:       4801 :         while ( nPos < nLen )
    4945                 :            :         {
    4946                 :       2404 :             xub_StrLen nBreakPos = nPos;
    4947                 :            : 
    4948 [ +  + ][ +  - ]:      18828 :             while ( ( nBreakPos < nLen ) && ( rStr.GetChar( nBreakPos ) != _CR ) && ( rStr.GetChar( nBreakPos ) != _LF ) )
         [ +  - ][ +  + ]
    4949                 :      16424 :                 nBreakPos++;
    4950                 :            : 
    4951         [ +  - ]:       2404 :             long nLineWidth = _rLayout.GetTextWidth( rStr, nPos, nBreakPos-nPos );
    4952 [ +  + ][ +  + ]:       2404 :             if ( ( nLineWidth > nWidth ) && ( nStyle & TEXT_DRAW_WORDBREAK ) )
    4953                 :            :             {
    4954         [ +  - ]:          7 :                 if ( !xBI.is() )
    4955 [ +  - ][ +  - ]:          7 :                     xBI = vcl::unohelper::CreateBreakIterator();
    4956                 :            : 
    4957         [ +  - ]:          7 :                 if ( xBI.is() )
    4958                 :            :                 {
    4959 [ +  - ][ +  - ]:          7 :                     const com::sun::star::lang::Locale& rDefLocale(Application::GetSettings().GetUILocale());
    4960         [ +  - ]:          7 :                     xub_StrLen nSoftBreak = _rLayout.GetTextBreak( rStr, nWidth, nPos, nBreakPos - nPos );
    4961                 :            :                     DBG_ASSERT( nSoftBreak < nBreakPos, "Break?!" );
    4962                 :            :                     //aHyphOptions.hyphenIndex = nSoftBreak;
    4963 [ +  - ][ +  - ]:          7 :                     i18n::LineBreakResults aLBR = xBI->getLineBreak( aText, nSoftBreak, rDefLocale, nPos, aHyphOptions, aUserOptions );
    4964                 :          7 :                     nBreakPos = (xub_StrLen)aLBR.breakIndex;
    4965         [ +  + ]:          7 :                     if ( nBreakPos <= nPos )
    4966                 :          3 :                         nBreakPos = nSoftBreak;
    4967         [ -  + ]:          7 :                     if ( (nStyle & TEXT_DRAW_WORDBREAK_HYPHENATION) == TEXT_DRAW_WORDBREAK_HYPHENATION )
    4968                 :            :                     {
    4969                 :            :                         // Egal ob Trenner oder nicht: Das Wort nach dem Trenner durch
    4970                 :            :                         // die Silbentrennung jagen...
    4971                 :            :                         // nMaxBreakPos ist das letzte Zeichen was in die Zeile passt,
    4972                 :            :                         // nBreakPos ist der Wort-Anfang
    4973                 :            :                         // Ein Problem gibt es, wenn das Dok so schmal ist, dass ein Wort
    4974                 :            :                         // auf mehr als Zwei Zeilen gebrochen wird...
    4975         [ #  # ]:          0 :                         if ( xHyph.is() )
    4976                 :            :                         {
    4977                 :          0 :                             sal_Unicode cAlternateReplChar = 0;
    4978 [ #  # ][ #  # ]:          0 :                             i18n::Boundary aBoundary = xBI->getWordBoundary( aText, nBreakPos, rDefLocale, ::com::sun::star::i18n::WordType::DICTIONARY_WORD, sal_True );
    4979                 :            :                 //          sal_uInt16 nWordStart = nBreakPos;
    4980                 :            :                 //          sal_uInt16 nBreakPos_OLD = nBreakPos;
    4981                 :          0 :                             sal_uInt16 nWordStart = nPos;
    4982                 :          0 :                             sal_uInt16 nWordEnd = (sal_uInt16) aBoundary.endPos;
    4983                 :            :                             DBG_ASSERT( nWordEnd > nWordStart, "ImpBreakLine: Start >= End?" );
    4984                 :            : 
    4985                 :          0 :                             sal_uInt16 nWordLen = nWordEnd - nWordStart;
    4986 [ #  # ][ #  # ]:          0 :                             if ( ( nWordEnd >= nSoftBreak ) && ( nWordLen > 3 ) )
    4987                 :            :                             {
    4988                 :            :                                 // #104415# May happen, because getLineBreak may differ from getWordBoudary with DICTIONARY_WORD
    4989                 :            :                                 // DBG_ASSERT( nWordEnd >= nMaxBreakPos, "Hyph: Break?" );
    4990 [ #  # ][ #  # ]:          0 :                                 String aWord( aText, nWordStart, nWordLen );
                 [ #  # ]
    4991                 :          0 :                                 sal_uInt16 nMinTrail = static_cast<sal_uInt16>(nWordEnd-nSoftBreak+1);  //+1: Vor dem angeknacksten Buchstaben
    4992                 :          0 :                                 uno::Reference< linguistic2::XHyphenatedWord > xHyphWord;
    4993         [ #  # ]:          0 :                                 if (xHyph.is())
    4994 [ #  # ][ #  # ]:          0 :                                     xHyphWord = xHyph->hyphenate( aWord, rDefLocale, aWord.Len() - nMinTrail, uno::Sequence< beans::PropertyValue >() );
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    4995         [ #  # ]:          0 :                                 if (xHyphWord.is())
    4996                 :            :                                 {
    4997 [ #  # ][ #  # ]:          0 :                                     sal_Bool bAlternate = xHyphWord->isAlternativeSpelling();
    4998 [ #  # ][ #  # ]:          0 :                                     sal_uInt16 _nWordLen = 1 + xHyphWord->getHyphenPos();
    4999                 :            : 
    5000 [ #  # ][ #  # ]:          0 :                                     if ( ( _nWordLen >= 2 ) && ( (nWordStart+_nWordLen) >= ( 2 ) ) )
    5001                 :            :                                     {
    5002         [ #  # ]:          0 :                                         if ( !bAlternate )
    5003                 :            :                                         {
    5004                 :          0 :                                             nBreakPos = nWordStart + _nWordLen;
    5005                 :            :                                         }
    5006                 :            :                                         else
    5007                 :            :                                         {
    5008 [ #  # ][ #  # ]:          0 :                                             String aAlt( xHyphWord->getHyphenatedWord() );
                 [ #  # ]
    5009                 :            : 
    5010                 :            :                                             // Wir gehen von zwei Faellen aus, die nun
    5011                 :            :                                             // vorliegen koennen:
    5012                 :            :                                             // 1) packen wird zu pak-ken
    5013                 :            :                                             // 2) Schiffahrt wird zu Schiff-fahrt
    5014                 :            :                                             // In Fall 1 muss ein Zeichen ersetzt werden,
    5015                 :            :                                             // in Fall 2 wird ein Zeichen hinzugefuegt.
    5016                 :            :                                             // Die Identifikation wird erschwert durch Worte wie
    5017                 :            :                                             // "Schiffahrtsbrennesseln", da der Hyphenator alle
    5018                 :            :                                             // Position des Wortes auftrennt und "Schifffahrtsbrennnesseln"
    5019                 :            :                                             // ermittelt. Wir koennen also eigentlich nicht unmittelbar vom
    5020                 :            :                                             // Index des AlternativWord auf aWord schliessen.
    5021                 :            : 
    5022                 :            :                                             // Das ganze geraffel wird durch eine Funktion am
    5023                 :            :                                             // Hyphenator vereinfacht werden, sobald AMA sie einbaut...
    5024                 :          0 :                                             sal_uInt16 nAltStart = _nWordLen - 1;
    5025                 :          0 :                                             sal_uInt16 nTxtStart = nAltStart - (aAlt.Len() - aWord.Len());
    5026                 :          0 :                                             sal_uInt16 nTxtEnd = nTxtStart;
    5027                 :          0 :                                             sal_uInt16 nAltEnd = nAltStart;
    5028                 :            : 
    5029                 :            :                                             // Die Bereiche zwischen den nStart und nEnd ist
    5030                 :            :                                             // die Differenz zwischen Alternativ- und OriginalString.
    5031         [ #  # ]:          0 :                                             while( nTxtEnd < aWord.Len() && nAltEnd < aAlt.Len() &&
           [ #  #  #  # ]
                 [ #  # ]
    5032                 :          0 :                                                    aWord.GetChar(nTxtEnd) != aAlt.GetChar(nAltEnd) )
    5033                 :            :                                             {
    5034                 :          0 :                                                 ++nTxtEnd;
    5035                 :          0 :                                                 ++nAltEnd;
    5036                 :            :                                             }
    5037                 :            : 
    5038                 :            :                                             // Wenn ein Zeichen hinzugekommen ist, dann bemerken wir es jetzt:
    5039         [ #  # ]:          0 :                                             if( nAltEnd > nTxtEnd && nAltStart == nAltEnd &&
           [ #  #  #  # ]
                 [ #  # ]
    5040                 :          0 :                                                 aWord.GetChar( nTxtEnd ) == aAlt.GetChar(nAltEnd) )
    5041                 :            :                                             {
    5042                 :          0 :                                                 ++nAltEnd;
    5043                 :          0 :                                                 ++nTxtStart;
    5044                 :          0 :                                                 ++nTxtEnd;
    5045                 :            :                                             }
    5046                 :            : 
    5047                 :            :                                             DBG_ASSERT( ( nAltEnd - nAltStart ) == 1, "Alternate: Falsche Annahme!" );
    5048                 :            : 
    5049         [ #  # ]:          0 :                                             if ( nTxtEnd > nTxtStart )
    5050                 :          0 :                                                 cAlternateReplChar = aAlt.GetChar( nAltStart );
    5051                 :            : 
    5052                 :          0 :                                             nBreakPos = nWordStart + nTxtStart;
    5053         [ #  # ]:          0 :                                             if ( cAlternateReplChar )
    5054         [ #  # ]:          0 :                                                 nBreakPos++;
    5055                 :            :                                         }
    5056                 :            :                                     } // if (xHyphWord.is())
    5057         [ #  # ]:          0 :                                 } // if ( ( nWordEnd >= nSoftBreak ) && ( nWordLen > 3 ) )
    5058                 :            :                             } // if ( xHyph.is() )
    5059                 :            :                         } // if ( (nStyle & TEXT_DRAW_WORDBREAK_HYPHENATION) == TEXT_DRAW_WORDBREAK_HYPHENATION )
    5060                 :            :                     }
    5061 [ +  - ][ +  - ]:          7 :                     nLineWidth = _rLayout.GetTextWidth( rStr, nPos, nBreakPos-nPos );
    5062                 :            :                 }
    5063                 :            :                 else
    5064                 :            :                 {
    5065                 :            :                     // fallback to something really simple
    5066                 :          0 :                     sal_uInt16 nSpacePos = STRING_LEN;
    5067                 :          0 :                     long nW = 0;
    5068         [ #  # ]:          0 :                     do
    5069                 :            :                     {
    5070         [ #  # ]:          0 :                         nSpacePos = rStr.SearchBackward( sal_Unicode(' '), nSpacePos );
    5071         [ #  # ]:          0 :                         if( nSpacePos != STRING_NOTFOUND )
    5072                 :            :                         {
    5073         [ #  # ]:          0 :                             if( nSpacePos > nPos )
    5074                 :          0 :                                 nSpacePos--;
    5075         [ #  # ]:          0 :                             nW = _rLayout.GetTextWidth( rStr, nPos, nSpacePos-nPos );
    5076                 :            :                         }
    5077                 :            :                     } while( nW > nWidth );
    5078                 :            : 
    5079         [ #  # ]:          0 :                     if( nSpacePos != STRING_NOTFOUND )
    5080                 :            :                     {
    5081                 :          0 :                         nBreakPos = nSpacePos;
    5082         [ #  # ]:          0 :                         nLineWidth = _rLayout.GetTextWidth( rStr, nPos, nBreakPos-nPos );
    5083         [ #  # ]:          0 :                         if( nBreakPos < rStr.Len()-1 )
    5084                 :          0 :                             nBreakPos++;
    5085                 :            :                     }
    5086                 :            :                 }
    5087                 :            :             }
    5088                 :            : 
    5089         [ +  + ]:       2404 :             if ( nLineWidth > nMaxLineWidth )
    5090                 :       2397 :                 nMaxLineWidth = nLineWidth;
    5091                 :            : 
    5092 [ +  - ][ +  - ]:       2404 :             rLineInfo.AddLine( new ImplTextLineInfo( nLineWidth, nPos, nBreakPos-nPos ) );
    5093                 :            : 
    5094         [ -  + ]:       2404 :             if ( nBreakPos == nPos )
    5095                 :          0 :                 nBreakPos++;
    5096                 :       2404 :             nPos = nBreakPos;
    5097                 :            : 
    5098 [ +  - ][ -  + ]:       2404 :             if ( ( rStr.GetChar( nPos ) == _CR ) || ( rStr.GetChar( nPos ) == _LF ) )
                 [ -  + ]
    5099                 :            :             {
    5100                 :          0 :                 nPos++;
    5101                 :            :                 // CR/LF?
    5102 [ #  # ][ #  # ]:          0 :                 if ( ( nPos < nLen ) && ( rStr.GetChar( nPos ) == _LF ) && ( rStr.GetChar( nPos-1 ) == _CR ) )
         [ #  # ][ #  # ]
    5103                 :          0 :                     nPos++;
    5104                 :            :             }
    5105         [ +  - ]:       2397 :         }
    5106                 :            :     }
    5107                 :            : #ifdef DBG_UTIL
    5108                 :            :     for ( sal_uInt16 nL = 0; nL < rLineInfo.Count(); nL++ )
    5109                 :            :     {
    5110                 :            :         ImplTextLineInfo* pLine = rLineInfo.GetLine( nL );
    5111                 :            :         String aLine( rStr, pLine->GetIndex(), pLine->GetLen() );
    5112                 :            :         DBG_ASSERT( aLine.Search( _CR ) == STRING_NOTFOUND, "ImplGetTextLines - Found CR!" );
    5113                 :            :         DBG_ASSERT( aLine.Search( _LF ) == STRING_NOTFOUND, "ImplGetTextLines - Found LF!" );
    5114                 :            :     }
    5115                 :            : #endif
    5116                 :            : 
    5117                 :       2634 :     return nMaxLineWidth;
    5118                 :            : }
    5119                 :            : 
    5120                 :            : // =======================================================================
    5121                 :            : 
    5122                 :     147565 : void OutputDevice::SetAntialiasing( sal_uInt16 nMode )
    5123                 :            : {
    5124         [ +  + ]:     147565 :     if ( mnAntialiasing != nMode )
    5125                 :            :     {
    5126                 :       8481 :         mnAntialiasing = nMode;
    5127                 :       8481 :         mbInitFont = sal_True;
    5128                 :            : 
    5129         [ +  + ]:       8481 :         if(mpGraphics)
    5130                 :            :         {
    5131                 :       1128 :             mpGraphics->setAntiAliasB2DDraw(mnAntialiasing & ANTIALIASING_ENABLE_B2DDRAW);
    5132                 :            :         }
    5133                 :            :     }
    5134                 :            : 
    5135         [ -  + ]:     147565 :     if( mpAlphaVDev )
    5136                 :          0 :         mpAlphaVDev->SetAntialiasing( nMode );
    5137                 :     147565 : }
    5138                 :            : 
    5139                 :            : // -----------------------------------------------------------------------
    5140                 :            : 
    5141                 :    1148200 : void OutputDevice::SetFont( const Font& rNewFont )
    5142                 :            : {
    5143                 :            :     OSL_TRACE( "OutputDevice::SetFont()" );
    5144                 :            :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    5145                 :            :     DBG_CHKOBJ( &rNewFont, Font, NULL );
    5146                 :            : 
    5147         [ +  - ]:    1148200 :     Font aFont( rNewFont );
    5148 [ +  - ][ +  - ]:    1148200 :     aFont.SetLanguage(rNewFont.GetLanguage());
    5149         [ -  + ]:    1148200 :     if ( mnDrawMode & (DRAWMODE_BLACKTEXT | DRAWMODE_WHITETEXT | DRAWMODE_GRAYTEXT | DRAWMODE_GHOSTEDTEXT | DRAWMODE_SETTINGSTEXT |
    5150                 :            :                        DRAWMODE_BLACKFILL | DRAWMODE_WHITEFILL | DRAWMODE_GRAYFILL | DRAWMODE_NOFILL |
    5151                 :            :                        DRAWMODE_GHOSTEDFILL | DRAWMODE_SETTINGSFILL ) )
    5152                 :            :     {
    5153         [ #  # ]:          0 :         Color aTextColor( aFont.GetColor() );
    5154                 :            : 
    5155         [ #  # ]:          0 :         if ( mnDrawMode & DRAWMODE_BLACKTEXT )
    5156                 :          0 :             aTextColor = Color( COL_BLACK );
    5157         [ #  # ]:          0 :         else if ( mnDrawMode & DRAWMODE_WHITETEXT )
    5158                 :          0 :             aTextColor = Color( COL_WHITE );
    5159         [ #  # ]:          0 :         else if ( mnDrawMode & DRAWMODE_GRAYTEXT )
    5160                 :            :         {
    5161         [ #  # ]:          0 :             const sal_uInt8 cLum = aTextColor.GetLuminance();
    5162                 :          0 :             aTextColor = Color( cLum, cLum, cLum );
    5163                 :            :         }
    5164         [ #  # ]:          0 :         else if ( mnDrawMode & DRAWMODE_SETTINGSTEXT )
    5165                 :          0 :             aTextColor = GetSettings().GetStyleSettings().GetFontColor();
    5166                 :            : 
    5167         [ #  # ]:          0 :         if ( mnDrawMode & DRAWMODE_GHOSTEDTEXT )
    5168                 :            :         {
    5169                 :          0 :             aTextColor = Color( (aTextColor.GetRed() >> 1 ) | 0x80,
    5170                 :          0 :                                 (aTextColor.GetGreen() >> 1 ) | 0x80,
    5171                 :          0 :                                 (aTextColor.GetBlue() >> 1 ) | 0x80 );
    5172                 :            :         }
    5173                 :            : 
    5174         [ #  # ]:          0 :         aFont.SetColor( aTextColor );
    5175                 :            : 
    5176         [ #  # ]:          0 :         sal_Bool bTransFill = aFont.IsTransparent();
    5177         [ #  # ]:          0 :         if ( !bTransFill )
    5178                 :            :         {
    5179         [ #  # ]:          0 :             Color aTextFillColor( aFont.GetFillColor() );
    5180                 :            : 
    5181         [ #  # ]:          0 :             if ( mnDrawMode & DRAWMODE_BLACKFILL )
    5182                 :          0 :                 aTextFillColor = Color( COL_BLACK );
    5183         [ #  # ]:          0 :             else if ( mnDrawMode & DRAWMODE_WHITEFILL )
    5184                 :          0 :                 aTextFillColor = Color( COL_WHITE );
    5185         [ #  # ]:          0 :             else if ( mnDrawMode & DRAWMODE_GRAYFILL )
    5186                 :            :             {
    5187         [ #  # ]:          0 :                 const sal_uInt8 cLum = aTextFillColor.GetLuminance();
    5188                 :          0 :                 aTextFillColor = Color( cLum, cLum, cLum );
    5189                 :            :             }
    5190         [ #  # ]:          0 :             else if( mnDrawMode & DRAWMODE_SETTINGSFILL )
    5191                 :          0 :                 aTextFillColor = GetSettings().GetStyleSettings().GetWindowColor();
    5192         [ #  # ]:          0 :             else if ( mnDrawMode & DRAWMODE_NOFILL )
    5193                 :            :             {
    5194                 :          0 :                 aTextFillColor = Color( COL_TRANSPARENT );
    5195                 :          0 :                 bTransFill = sal_True;
    5196                 :            :             }
    5197                 :            : 
    5198 [ #  # ][ #  # ]:          0 :             if ( !bTransFill && (mnDrawMode & DRAWMODE_GHOSTEDFILL) )
    5199                 :            :             {
    5200                 :          0 :                 aTextFillColor = Color( (aTextFillColor.GetRed() >> 1) | 0x80,
    5201                 :          0 :                                         (aTextFillColor.GetGreen() >> 1) | 0x80,
    5202                 :          0 :                                         (aTextFillColor.GetBlue() >> 1) | 0x80 );
    5203                 :            :             }
    5204                 :            : 
    5205         [ #  # ]:          0 :             aFont.SetFillColor( aTextFillColor );
    5206                 :            :         }
    5207                 :            :     }
    5208                 :            : 
    5209         [ +  + ]:    1148200 :     if ( mpMetaFile )
    5210                 :            :     {
    5211 [ +  - ][ +  - ]:      81313 :         mpMetaFile->AddAction( new MetaFontAction( aFont ) );
                 [ +  - ]
    5212                 :            :         // the color and alignment actions don't belong here
    5213                 :            :         // TODO: get rid of them without breaking anything...
    5214 [ +  - ][ +  - ]:      81313 :         mpMetaFile->AddAction( new MetaTextAlignAction( aFont.GetAlign() ) );
         [ +  - ][ +  - ]
    5215 [ +  - ][ +  - ]:      81313 :         mpMetaFile->AddAction( new MetaTextFillColorAction( aFont.GetFillColor(), !aFont.IsTransparent() ) );
         [ +  - ][ +  - ]
                 [ +  - ]
    5216                 :            :     }
    5217                 :            : 
    5218 [ +  - ][ +  + ]:    1148200 :     if ( !maFont.IsSameInstance( aFont ) )
    5219                 :            :     {
    5220                 :            :         // Optimization MT/HDU: COL_TRANSPARENT means SetFont should ignore the font color,
    5221                 :            :         // because SetTextColor() is used for this.
    5222                 :            :         // #i28759# maTextColor might have been changed behind our back, commit then, too.
    5223 [ +  - ][ +  +  :    1305581 :         if( aFont.GetColor() != COL_TRANSPARENT
             +  +  -  + ]
                 [ +  - ]
           [ +  +  #  # ]
    5224 [ +  - ][ +  - ]:     242464 :         && (aFont.GetColor() != maFont.GetColor() || aFont.GetColor() != maTextColor ) )
                 [ +  - ]
    5225                 :            :         {
    5226         [ +  - ]:      67968 :             maTextColor = aFont.GetColor();
    5227                 :      67968 :             mbInitTextColor = sal_True;
    5228         [ +  + ]:      67968 :             if( mpMetaFile )
    5229 [ +  - ][ +  - ]:        825 :                 mpMetaFile->AddAction( new MetaTextColorAction( aFont.GetColor() ) );
         [ +  - ][ +  - ]
    5230                 :            :         }
    5231         [ +  - ]:    1063117 :         maFont      = aFont;
    5232                 :    1063117 :         mbNewFont   = sal_True;
    5233                 :            : 
    5234         [ +  + ]:    1063117 :         if( mpAlphaVDev )
    5235                 :            :         {
    5236                 :            :             // #i30463#
    5237                 :            :             // Since SetFont might change the text color, apply that only
    5238                 :            :             // selectively to alpha vdev (which normally paints opaque text
    5239                 :            :             // with COL_BLACK)
    5240 [ +  - ][ +  + ]:      22373 :             if( aFont.GetColor() != COL_TRANSPARENT )
    5241                 :            :             {
    5242         [ +  - ]:        169 :                 mpAlphaVDev->SetTextColor( COL_BLACK );
    5243         [ +  - ]:        169 :                 aFont.SetColor( COL_TRANSPARENT );
    5244                 :            :             }
    5245                 :            : 
    5246         [ +  - ]:      22373 :             mpAlphaVDev->SetFont( aFont );
    5247                 :            :         }
    5248         [ +  - ]:    1148200 :     }
    5249                 :    1148200 : }
    5250                 :            : 
    5251                 :            : // -----------------------------------------------------------------------
    5252                 :            : 
    5253                 :     937850 : void OutputDevice::SetLayoutMode( sal_uLong nTextLayoutMode )
    5254                 :            : {
    5255                 :            :     OSL_TRACE( "OutputDevice::SetTextLayoutMode()" );
    5256                 :            : 
    5257         [ +  + ]:     937850 :     if( mpMetaFile )
    5258         [ +  - ]:      25195 :         mpMetaFile->AddAction( new MetaLayoutModeAction( nTextLayoutMode ) );
    5259                 :            : 
    5260                 :     937850 :     mnTextLayoutMode = nTextLayoutMode;
    5261                 :            : 
    5262         [ +  + ]:     937850 :     if( mpAlphaVDev )
    5263                 :      43892 :         mpAlphaVDev->SetLayoutMode( nTextLayoutMode );
    5264                 :     937850 : }
    5265                 :            : 
    5266                 :            : // -----------------------------------------------------------------------
    5267                 :            : 
    5268                 :    1372721 : void OutputDevice::SetDigitLanguage( LanguageType eTextLanguage )
    5269                 :            : {
    5270                 :            :     OSL_TRACE( "OutputDevice::SetTextLanguage()" );
    5271                 :            : 
    5272         [ +  + ]:    1372721 :     if( mpMetaFile )
    5273         [ +  - ]:      31876 :         mpMetaFile->AddAction( new MetaTextLanguageAction( eTextLanguage ) );
    5274                 :            : 
    5275                 :    1372721 :     meTextLanguage = eTextLanguage;
    5276                 :            : 
    5277         [ +  + ]:    1372721 :     if( mpAlphaVDev )
    5278                 :      43092 :         mpAlphaVDev->SetDigitLanguage( eTextLanguage );
    5279                 :    1372721 : }
    5280                 :            : 
    5281                 :            : // -----------------------------------------------------------------------
    5282                 :            : 
    5283                 :     568703 : void OutputDevice::SetTextColor( const Color& rColor )
    5284                 :            : {
    5285                 :            :     OSL_TRACE( "OutputDevice::SetTextColor()" );
    5286                 :            :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    5287                 :            : 
    5288                 :     568703 :     Color aColor( rColor );
    5289                 :            : 
    5290         [ -  + ]:     568703 :     if ( mnDrawMode & ( DRAWMODE_BLACKTEXT | DRAWMODE_WHITETEXT |
    5291                 :            :                         DRAWMODE_GRAYTEXT | DRAWMODE_GHOSTEDTEXT |
    5292                 :            :                         DRAWMODE_SETTINGSTEXT ) )
    5293                 :            :     {
    5294         [ #  # ]:          0 :         if ( mnDrawMode & DRAWMODE_BLACKTEXT )
    5295                 :          0 :             aColor = Color( COL_BLACK );
    5296         [ #  # ]:          0 :         else if ( mnDrawMode & DRAWMODE_WHITETEXT )
    5297                 :          0 :             aColor = Color( COL_WHITE );
    5298         [ #  # ]:          0 :         else if ( mnDrawMode & DRAWMODE_GRAYTEXT )
    5299                 :            :         {
    5300         [ #  # ]:          0 :             const sal_uInt8 cLum = aColor.GetLuminance();
    5301                 :          0 :             aColor = Color( cLum, cLum, cLum );
    5302                 :            :         }
    5303         [ #  # ]:          0 :         else if ( mnDrawMode & DRAWMODE_SETTINGSTEXT )
    5304                 :          0 :             aColor = GetSettings().GetStyleSettings().GetFontColor();
    5305                 :            : 
    5306         [ #  # ]:          0 :         if ( mnDrawMode & DRAWMODE_GHOSTEDTEXT )
    5307                 :            :         {
    5308                 :          0 :             aColor = Color( (aColor.GetRed() >> 1) | 0x80,
    5309                 :          0 :                             (aColor.GetGreen() >> 1) | 0x80,
    5310                 :          0 :                             (aColor.GetBlue() >> 1) | 0x80 );
    5311                 :            :         }
    5312                 :            :     }
    5313                 :            : 
    5314         [ +  + ]:     568703 :     if ( mpMetaFile )
    5315 [ +  - ][ +  - ]:      84191 :         mpMetaFile->AddAction( new MetaTextColorAction( aColor ) );
                 [ +  - ]
    5316                 :            : 
    5317         [ +  + ]:     568703 :     if ( maTextColor != aColor )
    5318                 :            :     {
    5319                 :      26170 :         maTextColor = aColor;
    5320                 :      26170 :         mbInitTextColor = sal_True;
    5321                 :            :     }
    5322                 :            : 
    5323         [ +  + ]:     568703 :     if( mpAlphaVDev )
    5324         [ +  - ]:      30645 :         mpAlphaVDev->SetTextColor( COL_BLACK );
    5325                 :     568703 : }
    5326                 :            : 
    5327                 :            : // -----------------------------------------------------------------------
    5328                 :            : 
    5329                 :     197572 : void OutputDevice::SetTextFillColor()
    5330                 :            : {
    5331                 :            :     OSL_TRACE( "OutputDevice::SetTextFillColor()" );
    5332                 :            :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    5333                 :            : 
    5334         [ +  + ]:     197572 :     if ( mpMetaFile )
    5335 [ +  - ][ +  - ]:      11017 :         mpMetaFile->AddAction( new MetaTextFillColorAction( Color(), sal_False ) );
                 [ +  - ]
    5336                 :            : 
    5337 [ +  - ][ +  + ]:     197572 :     if ( maFont.GetColor() != Color( COL_TRANSPARENT ) )
    5338         [ +  - ]:       2226 :         maFont.SetFillColor( Color( COL_TRANSPARENT ) );
    5339         [ +  + ]:     197572 :     if ( !maFont.IsTransparent() )
    5340                 :         34 :         maFont.SetTransparent( sal_True );
    5341                 :            : 
    5342         [ +  + ]:     197572 :     if( mpAlphaVDev )
    5343                 :      32850 :         mpAlphaVDev->SetTextFillColor();
    5344                 :     197572 : }
    5345                 :            : 
    5346                 :            : // -----------------------------------------------------------------------
    5347                 :            : 
    5348                 :      22021 : void OutputDevice::SetTextFillColor( const Color& rColor )
    5349                 :            : {
    5350                 :            :     OSL_TRACE( "OutputDevice::SetTextFillColor()" );
    5351                 :            :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    5352                 :            : 
    5353                 :      22021 :     Color aColor( rColor );
    5354         [ +  + ]:      22021 :     sal_Bool bTransFill = ImplIsColorTransparent( aColor ) ? sal_True : sal_False;
    5355                 :            : 
    5356         [ +  + ]:      22021 :     if ( !bTransFill )
    5357                 :            :     {
    5358         [ -  + ]:      19057 :         if ( mnDrawMode & ( DRAWMODE_BLACKFILL | DRAWMODE_WHITEFILL |
    5359                 :            :                             DRAWMODE_GRAYFILL | DRAWMODE_NOFILL |
    5360                 :            :                             DRAWMODE_GHOSTEDFILL | DRAWMODE_SETTINGSFILL ) )
    5361                 :            :         {
    5362         [ #  # ]:          0 :             if ( mnDrawMode & DRAWMODE_BLACKFILL )
    5363                 :          0 :                 aColor = Color( COL_BLACK );
    5364         [ #  # ]:          0 :             else if ( mnDrawMode & DRAWMODE_WHITEFILL )
    5365                 :          0 :                 aColor = Color( COL_WHITE );
    5366         [ #  # ]:          0 :             else if ( mnDrawMode & DRAWMODE_GRAYFILL )
    5367                 :            :             {
    5368         [ #  # ]:          0 :                 const sal_uInt8 cLum = aColor.GetLuminance();
    5369                 :          0 :                 aColor = Color( cLum, cLum, cLum );
    5370                 :            :             }
    5371         [ #  # ]:          0 :             else if( mnDrawMode & DRAWMODE_SETTINGSFILL )
    5372                 :          0 :                 aColor = GetSettings().GetStyleSettings().GetWindowColor();
    5373         [ #  # ]:          0 :             else if ( mnDrawMode & DRAWMODE_NOFILL )
    5374                 :            :             {
    5375                 :          0 :                 aColor = Color( COL_TRANSPARENT );
    5376                 :          0 :                 bTransFill = sal_True;
    5377                 :            :             }
    5378                 :            : 
    5379 [ #  # ][ #  # ]:          0 :             if ( !bTransFill && (mnDrawMode & DRAWMODE_GHOSTEDFILL) )
    5380                 :            :             {
    5381                 :          0 :                 aColor = Color( (aColor.GetRed() >> 1) | 0x80,
    5382                 :          0 :                                 (aColor.GetGreen() >> 1) | 0x80,
    5383                 :          0 :                                 (aColor.GetBlue() >> 1) | 0x80 );
    5384                 :            :             }
    5385                 :            :         }
    5386                 :            :     }
    5387                 :            : 
    5388         [ +  + ]:      22021 :     if ( mpMetaFile )
    5389 [ +  - ][ +  - ]:       2662 :         mpMetaFile->AddAction( new MetaTextFillColorAction( aColor, sal_True ) );
                 [ +  - ]
    5390                 :            : 
    5391 [ +  - ][ +  + ]:      22021 :     if ( maFont.GetFillColor() != aColor )
    5392         [ +  - ]:      12969 :         maFont.SetFillColor( aColor );
    5393 [ +  - ][ +  + ]:      22021 :     if ( maFont.IsTransparent() != bTransFill )
    5394         [ +  - ]:      12836 :         maFont.SetTransparent( bTransFill );
    5395                 :            : 
    5396         [ +  + ]:      22021 :     if( mpAlphaVDev )
    5397         [ +  - ]:       2820 :         mpAlphaVDev->SetTextFillColor( COL_BLACK );
    5398                 :      22021 : }
    5399                 :            : 
    5400                 :            : // -----------------------------------------------------------------------
    5401                 :            : 
    5402                 :       9581 : Color OutputDevice::GetTextFillColor() const
    5403                 :            : {
    5404         [ +  + ]:       9581 :     if ( maFont.IsTransparent() )
    5405                 :       2844 :         return Color( COL_TRANSPARENT );
    5406                 :            :     else
    5407                 :       9581 :         return maFont.GetFillColor();
    5408                 :            : }
    5409                 :            : 
    5410                 :            : // -----------------------------------------------------------------------
    5411                 :            : 
    5412                 :     129636 : void OutputDevice::SetTextLineColor()
    5413                 :            : {
    5414                 :            :     OSL_TRACE( "OutputDevice::SetTextLineColor()" );
    5415                 :            :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    5416                 :            : 
    5417         [ +  + ]:     129636 :     if ( mpMetaFile )
    5418 [ +  - ][ +  - ]:      10762 :         mpMetaFile->AddAction( new MetaTextLineColorAction( Color(), sal_False ) );
                 [ +  - ]
    5419                 :            : 
    5420                 :     129636 :     maTextLineColor = Color( COL_TRANSPARENT );
    5421                 :            : 
    5422         [ +  + ]:     129636 :     if( mpAlphaVDev )
    5423                 :      21568 :         mpAlphaVDev->SetTextLineColor();
    5424                 :     129636 : }
    5425                 :            : 
    5426                 :            : // -----------------------------------------------------------------------
    5427                 :            : 
    5428                 :      30149 : void OutputDevice::SetTextLineColor( const Color& rColor )
    5429                 :            : {
    5430                 :            :     OSL_TRACE( "OutputDevice::SetTextLineColor()" );
    5431                 :            :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    5432                 :            : 
    5433                 :      30149 :     Color aColor( rColor );
    5434                 :            : 
    5435         [ -  + ]:      30149 :     if ( mnDrawMode & ( DRAWMODE_BLACKTEXT | DRAWMODE_WHITETEXT |
    5436                 :            :                         DRAWMODE_GRAYTEXT | DRAWMODE_GHOSTEDTEXT |
    5437                 :            :                         DRAWMODE_SETTINGSTEXT ) )
    5438                 :            :     {
    5439         [ #  # ]:          0 :         if ( mnDrawMode & DRAWMODE_BLACKTEXT )
    5440                 :          0 :             aColor = Color( COL_BLACK );
    5441         [ #  # ]:          0 :         else if ( mnDrawMode & DRAWMODE_WHITETEXT )
    5442                 :          0 :             aColor = Color( COL_WHITE );
    5443         [ #  # ]:          0 :         else if ( mnDrawMode & DRAWMODE_GRAYTEXT )
    5444                 :            :         {
    5445         [ #  # ]:          0 :             const sal_uInt8 cLum = aColor.GetLuminance();
    5446                 :          0 :             aColor = Color( cLum, cLum, cLum );
    5447                 :            :         }
    5448         [ #  # ]:          0 :         else if ( mnDrawMode & DRAWMODE_SETTINGSTEXT )
    5449                 :          0 :             aColor = GetSettings().GetStyleSettings().GetFontColor();
    5450                 :            : 
    5451   [ #  #  #  # ]:          0 :         if( (mnDrawMode & DRAWMODE_GHOSTEDTEXT)
                 [ #  # ]
    5452                 :          0 :         &&  (aColor.GetColor() != COL_TRANSPARENT) )
    5453                 :            :         {
    5454                 :          0 :             aColor = Color( (aColor.GetRed() >> 1) | 0x80,
    5455                 :          0 :                             (aColor.GetGreen() >> 1) | 0x80,
    5456                 :          0 :                             (aColor.GetBlue() >> 1) | 0x80 );
    5457                 :            :         }
    5458                 :            :     }
    5459                 :            : 
    5460         [ -  + ]:      30149 :     if ( mpMetaFile )
    5461 [ #  # ][ #  # ]:          0 :         mpMetaFile->AddAction( new MetaTextLineColorAction( aColor, sal_True ) );
                 [ #  # ]
    5462                 :            : 
    5463                 :      30149 :     maTextLineColor = aColor;
    5464                 :            : 
    5465         [ +  + ]:      30149 :     if( mpAlphaVDev )
    5466         [ +  - ]:       3336 :         mpAlphaVDev->SetTextLineColor( COL_BLACK );
    5467                 :      30149 : }
    5468                 :            : 
    5469                 :            : // -----------------------------------------------------------------------
    5470                 :            : 
    5471                 :     128980 : void OutputDevice::SetOverlineColor()
    5472                 :            : {
    5473                 :            :     OSL_TRACE( "OutputDevice::SetOverlineColor()" );
    5474                 :            :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    5475                 :            : 
    5476         [ +  + ]:     128980 :     if ( mpMetaFile )
    5477 [ +  - ][ +  - ]:      10762 :         mpMetaFile->AddAction( new MetaOverlineColorAction( Color(), sal_False ) );
                 [ +  - ]
    5478                 :            : 
    5479                 :     128980 :     maOverlineColor = Color( COL_TRANSPARENT );
    5480                 :            : 
    5481         [ +  + ]:     128980 :     if( mpAlphaVDev )
    5482                 :      21568 :         mpAlphaVDev->SetOverlineColor();
    5483                 :     128980 : }
    5484                 :            : 
    5485                 :            : // -----------------------------------------------------------------------
    5486                 :            : 
    5487                 :      28806 : void OutputDevice::SetOverlineColor( const Color& rColor )
    5488                 :            : {
    5489                 :            :     OSL_TRACE( "OutputDevice::SetOverlineColor()" );
    5490                 :            :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    5491                 :            : 
    5492                 :      28806 :     Color aColor( rColor );
    5493                 :            : 
    5494         [ -  + ]:      28806 :     if ( mnDrawMode & ( DRAWMODE_BLACKTEXT | DRAWMODE_WHITETEXT |
    5495                 :            :                         DRAWMODE_GRAYTEXT | DRAWMODE_GHOSTEDTEXT |
    5496                 :            :                         DRAWMODE_SETTINGSTEXT ) )
    5497                 :            :     {
    5498         [ #  # ]:          0 :         if ( mnDrawMode & DRAWMODE_BLACKTEXT )
    5499                 :          0 :             aColor = Color( COL_BLACK );
    5500         [ #  # ]:          0 :         else if ( mnDrawMode & DRAWMODE_WHITETEXT )
    5501                 :          0 :             aColor = Color( COL_WHITE );
    5502         [ #  # ]:          0 :         else if ( mnDrawMode & DRAWMODE_GRAYTEXT )
    5503                 :            :         {
    5504         [ #  # ]:          0 :             const sal_uInt8 cLum = aColor.GetLuminance();
    5505                 :          0 :             aColor = Color( cLum, cLum, cLum );
    5506                 :            :         }
    5507         [ #  # ]:          0 :         else if ( mnDrawMode & DRAWMODE_SETTINGSTEXT )
    5508                 :          0 :             aColor = GetSettings().GetStyleSettings().GetFontColor();
    5509                 :            : 
    5510   [ #  #  #  # ]:          0 :         if( (mnDrawMode & DRAWMODE_GHOSTEDTEXT)
                 [ #  # ]
    5511                 :          0 :         &&  (aColor.GetColor() != COL_TRANSPARENT) )
    5512                 :            :         {
    5513                 :          0 :             aColor = Color( (aColor.GetRed() >> 1) | 0x80,
    5514                 :          0 :                             (aColor.GetGreen() >> 1) | 0x80,
    5515                 :          0 :                             (aColor.GetBlue() >> 1) | 0x80 );
    5516                 :            :         }
    5517                 :            :     }
    5518                 :            : 
    5519         [ -  + ]:      28806 :     if ( mpMetaFile )
    5520 [ #  # ][ #  # ]:          0 :         mpMetaFile->AddAction( new MetaOverlineColorAction( aColor, sal_True ) );
                 [ #  # ]
    5521                 :            : 
    5522                 :      28806 :     maOverlineColor = aColor;
    5523                 :            : 
    5524         [ +  + ]:      28806 :     if( mpAlphaVDev )
    5525         [ +  - ]:       3336 :         mpAlphaVDev->SetOverlineColor( COL_BLACK );
    5526                 :      28806 : }
    5527                 :            : 
    5528                 :            : // -----------------------------------------------------------------------
    5529                 :            : 
    5530                 :            : 
    5531                 :     145042 : void OutputDevice::SetTextAlign( TextAlign eAlign )
    5532                 :            : {
    5533                 :            :     OSL_TRACE( "OutputDevice::SetTextAlign()" );
    5534                 :            :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    5535                 :            : 
    5536         [ +  + ]:     145042 :     if ( mpMetaFile )
    5537         [ +  - ]:      10762 :         mpMetaFile->AddAction( new MetaTextAlignAction( eAlign ) );
    5538                 :            : 
    5539         [ +  + ]:     145042 :     if ( maFont.GetAlign() != eAlign )
    5540                 :            :     {
    5541                 :       7736 :         maFont.SetAlign( eAlign );
    5542                 :       7736 :         mbNewFont = sal_True;
    5543                 :            :     }
    5544                 :            : 
    5545         [ +  + ]:     145042 :     if( mpAlphaVDev )
    5546                 :      32753 :         mpAlphaVDev->SetTextAlign( eAlign );
    5547                 :     145042 : }
    5548                 :            : 
    5549                 :            : // -----------------------------------------------------------------------
    5550                 :            : 
    5551                 :          0 : void OutputDevice::DrawTextLine( const Point& rPos, long nWidth,
    5552                 :            :                                  FontStrikeout eStrikeout,
    5553                 :            :                                  FontUnderline eUnderline,
    5554                 :            :                                  FontUnderline eOverline,
    5555                 :            :                                  sal_Bool bUnderlineAbove )
    5556                 :            : {
    5557                 :            :     OSL_TRACE( "OutputDevice::DrawTextLine()" );
    5558                 :            :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    5559                 :            : 
    5560         [ #  # ]:          0 :     if ( mpMetaFile )
    5561 [ #  # ][ #  # ]:          0 :         mpMetaFile->AddAction( new MetaTextLineAction( rPos, nWidth, eStrikeout, eUnderline, eOverline ) );
                 [ #  # ]
    5562                 :            : 
    5563 [ #  # ][ #  # ]:          0 :     if ( ((eUnderline == UNDERLINE_NONE) || (eUnderline == UNDERLINE_DONTKNOW)) &&
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    5564                 :            :          ((eOverline  == UNDERLINE_NONE) || (eOverline  == UNDERLINE_DONTKNOW)) &&
    5565                 :            :          ((eStrikeout == STRIKEOUT_NONE) || (eStrikeout == STRIKEOUT_DONTKNOW)) )
    5566                 :            :         return;
    5567                 :            : 
    5568 [ #  # ][ #  # ]:          0 :     if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
         [ #  # ][ #  # ]
    5569                 :            :         return;
    5570                 :            : 
    5571                 :            :     // we need a graphics
    5572 [ #  # ][ #  # ]:          0 :     if( !mpGraphics && !ImplGetGraphics() )
         [ #  # ][ #  # ]
    5573                 :            :         return;
    5574         [ #  # ]:          0 :     if( mbInitClipRegion )
    5575         [ #  # ]:          0 :         ImplInitClipRegion();
    5576         [ #  # ]:          0 :     if( mbOutputClipped )
    5577                 :            :         return;
    5578                 :            : 
    5579                 :            :     // initialize font if needed to get text offsets
    5580                 :            :     // TODO: only needed for mnTextOff!=(0,0)
    5581         [ #  # ]:          0 :     if( mbNewFont )
    5582 [ #  # ][ #  # ]:          0 :         if( !ImplNewFont() )
    5583                 :            :             return;
    5584         [ #  # ]:          0 :     if( mbInitFont )
    5585         [ #  # ]:          0 :         ImplInitFont();
    5586                 :            : 
    5587         [ #  # ]:          0 :     Point aPos = ImplLogicToDevicePixel( rPos );
    5588         [ #  # ]:          0 :     nWidth = ImplLogicWidthToDevicePixel( nWidth );
    5589                 :          0 :     aPos += Point( mnTextOffX, mnTextOffY );
    5590         [ #  # ]:          0 :     ImplDrawTextLine( aPos.X(), aPos.X(), 0, nWidth, eStrikeout, eUnderline, eOverline, bUnderlineAbove );
    5591                 :            : 
    5592         [ #  # ]:          0 :     if( mpAlphaVDev )
    5593         [ #  # ]:          0 :         mpAlphaVDev->DrawTextLine( rPos, nWidth, eStrikeout, eUnderline, eOverline, bUnderlineAbove );
    5594                 :            : }
    5595                 :            : 
    5596                 :            : // ------------------------------------------------------------------------
    5597                 :            : 
    5598                 :       3980 : void OutputDevice::DrawWaveLine( const Point& rStartPos, const Point& rEndPos,
    5599                 :            :                                  sal_uInt16 nStyle )
    5600                 :            : {
    5601                 :            :     OSL_TRACE( "OutputDevice::DrawWaveLine()" );
    5602                 :            :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    5603                 :            : 
    5604 [ +  - ][ +  - ]:       3980 :     if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
         [ -  + ][ +  - ]
    5605                 :            :         return;
    5606                 :            : 
    5607                 :            :     // we need a graphics
    5608         [ -  + ]:       3980 :     if( !mpGraphics )
    5609 [ #  # ][ #  # ]:          0 :         if( !ImplGetGraphics() )
    5610                 :            :             return;
    5611                 :            : 
    5612         [ +  + ]:       3980 :     if ( mbInitClipRegion )
    5613         [ +  - ]:        446 :         ImplInitClipRegion();
    5614         [ +  - ]:       3980 :     if ( mbOutputClipped )
    5615                 :            :         return;
    5616                 :            : 
    5617         [ -  + ]:       3980 :     if( mbNewFont )
    5618 [ #  # ][ #  # ]:          0 :         if( !ImplNewFont() )
    5619                 :            :             return;
    5620                 :            : 
    5621         [ +  - ]:       3980 :     Point   aStartPt = ImplLogicToDevicePixel( rStartPos );
    5622         [ +  - ]:       3980 :     Point   aEndPt = ImplLogicToDevicePixel( rEndPos );
    5623                 :       3980 :     long    nStartX = aStartPt.X();
    5624                 :       3980 :     long    nStartY = aStartPt.Y();
    5625                 :       3980 :     long    nEndX = aEndPt.X();
    5626                 :       3980 :     long    nEndY = aEndPt.Y();
    5627                 :       3980 :     short   nOrientation = 0;
    5628                 :            : 
    5629                 :            :     // when rotated
    5630 [ -  + ][ +  + ]:       3980 :     if ( (nStartY != nEndY) || (nStartX > nEndX) )
    5631                 :            :     {
    5632                 :        340 :         long nDX = nEndX - nStartX;
    5633         [ -  + ]:        340 :         double nO = atan2( -nEndY + nStartY, ((nDX == 0L) ? 0.000000001 : nDX) );
    5634                 :        340 :         nO /= F_PI1800;
    5635                 :        340 :         nOrientation = (short)nO;
    5636                 :        340 :         ImplRotatePos( nStartX, nStartY, nEndX, nEndY, -nOrientation );
    5637                 :            :     }
    5638                 :            : 
    5639                 :            :     long nWaveHeight;
    5640         [ +  + ]:       3980 :     if ( nStyle == WAVE_NORMAL )
    5641                 :            :     {
    5642                 :       3876 :         nWaveHeight = 3;
    5643                 :       3876 :         nStartY++;
    5644                 :       3876 :         nEndY++;
    5645                 :            :     }
    5646         [ +  + ]:        104 :     else if( nStyle == WAVE_SMALL )
    5647                 :            :     {
    5648                 :        100 :         nWaveHeight = 2;
    5649                 :        100 :         nStartY++;
    5650                 :        100 :         nEndY++;
    5651                 :            :     }
    5652                 :            :     else // WAVE_FLAT
    5653                 :          4 :         nWaveHeight = 1;
    5654                 :            : 
    5655                 :            :      // #109280# make sure the waveline does not exceed the descent to avoid paint problems
    5656                 :       3980 :      ImplFontEntry* pFontEntry = mpFontEntry;
    5657         [ -  + ]:       3980 :      if( nWaveHeight > pFontEntry->maMetric.mnWUnderlineSize )
    5658                 :          0 :          nWaveHeight = pFontEntry->maMetric.mnWUnderlineSize;
    5659                 :            : 
    5660                 :            :      ImplDrawWaveLine( nStartX, nStartY, 0, 0,
    5661                 :            :                       nEndX-nStartX, nWaveHeight, 1,
    5662         [ +  - ]:       3980 :                       nOrientation, GetLineColor() );
    5663         [ -  + ]:       3980 :     if( mpAlphaVDev )
    5664         [ #  # ]:       3980 :         mpAlphaVDev->DrawWaveLine( rStartPos, rEndPos, nStyle );
    5665                 :            : }
    5666                 :            : 
    5667                 :            : // -----------------------------------------------------------------------
    5668                 :            : 
    5669                 :     117327 : void OutputDevice::DrawText( const Point& rStartPt, const String& rStr,
    5670                 :            :                              xub_StrLen nIndex, xub_StrLen nLen,
    5671                 :            :                              MetricVector* pVector, String* pDisplayText
    5672                 :            :                              )
    5673                 :            : {
    5674 [ +  + ][ +  + ]:     117327 :     if( mpOutDevData && mpOutDevData->mpRecordLayout )
    5675                 :            :     {
    5676                 :       2424 :         pVector = &mpOutDevData->mpRecordLayout->m_aUnicodeBoundRects;
    5677                 :       2424 :         pDisplayText = &mpOutDevData->mpRecordLayout->m_aDisplayText;
    5678                 :            :     }
    5679                 :            : 
    5680                 :            :     OSL_TRACE( "OutputDevice::DrawText()" );
    5681                 :            :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    5682                 :            : 
    5683                 :            : #if OSL_DEBUG_LEVEL > 2
    5684                 :            :     fprintf( stderr, "   OutputDevice::DrawText(\"%s\")\n",
    5685                 :            :          OUStringToOString( rStr, RTL_TEXTENCODING_UTF8 ).getStr() );
    5686                 :            : #endif
    5687                 :            : 
    5688         [ +  + ]:     117327 :     if ( mpMetaFile )
    5689 [ +  - ][ +  - ]:       2577 :         mpMetaFile->AddAction( new MetaTextAction( rStartPt, rStr, nIndex, nLen ) );
                 [ +  - ]
    5690         [ +  + ]:     117327 :     if( pVector )
    5691                 :            :     {
    5692         [ +  - ]:       2476 :         Region aClip( GetClipRegion() );
    5693         [ +  - ]:       2476 :         if( meOutDevType == OUTDEV_WINDOW )
    5694 [ +  - ][ +  - ]:       2476 :             aClip.Intersect( Rectangle( Point(), GetOutputSize() ) );
                 [ +  - ]
    5695 [ +  + ][ +  - ]:       2476 :         if( mpOutDevData && mpOutDevData->mpRecordLayout )
    5696                 :            :         {
    5697         [ +  - ]:       2424 :             mpOutDevData->mpRecordLayout->m_aLineIndices.push_back( mpOutDevData->mpRecordLayout->m_aDisplayText.Len() );
    5698         [ +  - ]:       2424 :             aClip.Intersect( mpOutDevData->maRecordRect );
    5699                 :            :         }
    5700 [ +  - ][ +  - ]:       2476 :         if( ! aClip.IsNull() )
    5701                 :            :         {
    5702         [ +  - ]:       2476 :             MetricVector aTmp;
    5703         [ +  - ]:       2476 :             GetGlyphBoundRects( rStartPt, rStr, nIndex, nLen, nIndex, aTmp );
    5704                 :            : 
    5705                 :       2476 :             bool bInserted = false;
    5706 [ +  - ][ +  - ]:      11444 :             for( MetricVector::const_iterator it = aTmp.begin(); it != aTmp.end(); ++it, nIndex++ )
         [ +  - ][ +  + ]
    5707                 :            :             {
    5708                 :       8968 :                 bool bAppend = false;
    5709                 :            : 
    5710 [ +  - ][ +  - ]:       8968 :                 if( aClip.IsOver( *it ) )
                 [ +  + ]
    5711                 :       1846 :                     bAppend = true;
    5712 [ +  + ][ +  + ]:       7122 :                 else if( rStr.GetChar( nIndex ) == ' ' && bInserted )
                 [ +  + ]
    5713                 :            :                 {
    5714                 :        222 :                     MetricVector::const_iterator next = it;
    5715         [ +  - ]:        222 :                     ++next;
    5716 [ +  - ][ +  - ]:        222 :                     if( next != aTmp.end() && aClip.IsOver( *next ) )
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
           [ +  -  #  # ]
    5717                 :        222 :                         bAppend = true;
    5718                 :            :                 }
    5719                 :            : 
    5720         [ +  + ]:       8968 :                 if( bAppend )
    5721                 :            :                 {
    5722 [ +  - ][ +  - ]:       2068 :                     pVector->push_back( *it );
    5723         [ +  - ]:       2068 :                     if( pDisplayText )
    5724         [ +  - ]:       2068 :                         pDisplayText->Append( rStr.GetChar( nIndex ) );
    5725                 :       2068 :                     bInserted = true;
    5726                 :            :                 }
    5727                 :       2476 :             }
    5728                 :            :         }
    5729                 :            :         else
    5730                 :            :         {
    5731         [ #  # ]:          0 :             GetGlyphBoundRects( rStartPt, rStr, nIndex, nLen, nIndex, *pVector );
    5732         [ #  # ]:          0 :             if( pDisplayText )
    5733 [ #  # ][ #  # ]:          0 :                 pDisplayText->Append( rStr.Copy( nIndex, nLen ) );
                 [ #  # ]
    5734         [ +  - ]:       2476 :         }
    5735                 :            :     }
    5736                 :            : 
    5737 [ +  + ][ +  + ]:     117327 :     if ( !IsDeviceOutputNecessary() || pVector )
                 [ +  + ]
    5738                 :     117327 :         return;
    5739                 :            : 
    5740                 :     114849 :     SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen, rStartPt, 0, NULL, true );
    5741         [ +  + ]:     114849 :     if( pSalLayout )
    5742                 :            :     {
    5743                 :      95396 :         ImplDrawText( *pSalLayout );
    5744                 :      95396 :         pSalLayout->Release();
    5745                 :            :     }
    5746                 :            : 
    5747         [ +  + ]:     114849 :     if( mpAlphaVDev )
    5748                 :       3488 :         mpAlphaVDev->DrawText( rStartPt, rStr, nIndex, nLen, pVector, pDisplayText );
    5749                 :            : }
    5750                 :            : 
    5751                 :            : // -----------------------------------------------------------------------
    5752                 :            : 
    5753                 :     588038 : long OutputDevice::GetTextWidth( const String& rStr,
    5754                 :            :                                  xub_StrLen nIndex, xub_StrLen nLen ) const
    5755                 :            : {
    5756                 :            :     OSL_TRACE( "OutputDevice::GetTextWidth()" );
    5757                 :            :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    5758                 :            : 
    5759                 :     588038 :     long nWidth = GetTextArray( rStr, NULL, nIndex, nLen );
    5760                 :     588038 :     return nWidth;
    5761                 :            : }
    5762                 :            : 
    5763                 :            : // -----------------------------------------------------------------------
    5764                 :            : 
    5765                 :     711362 : long OutputDevice::GetTextHeight() const
    5766                 :            : {
    5767                 :            :     OSL_TRACE( "OutputDevice::GetTextHeight()" );
    5768                 :            :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    5769                 :            : 
    5770         [ +  + ]:     711362 :     if( mbNewFont )
    5771         [ -  + ]:     411452 :         if( !ImplNewFont() )
    5772                 :          0 :             return 0;
    5773         [ +  + ]:     711362 :     if( mbInitFont )
    5774         [ -  + ]:     367515 :         if( !ImplNewFont() )
    5775                 :          0 :             return 0;
    5776                 :            : 
    5777                 :     711362 :     long nHeight = mpFontEntry->mnLineHeight + mnEmphasisAscent + mnEmphasisDescent;
    5778                 :            : 
    5779         [ +  + ]:     711362 :     if ( mbMap )
    5780                 :     517845 :         nHeight = ImplDevicePixelToLogicHeight( nHeight );
    5781                 :            : 
    5782                 :     711362 :     return nHeight;
    5783                 :            : }
    5784                 :            : 
    5785                 :            : // -----------------------------------------------------------------------
    5786                 :            : 
    5787                 :      49891 : void OutputDevice::DrawTextArray( const Point& rStartPt, const String& rStr,
    5788                 :            :                                   const sal_Int32* pDXAry,
    5789                 :            :                                   xub_StrLen nIndex, xub_StrLen nLen )
    5790                 :            : {
    5791                 :            :     OSL_TRACE( "OutputDevice::DrawTextArray()" );
    5792                 :            :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    5793                 :            : 
    5794         [ +  + ]:      49891 :     if ( mpMetaFile )
    5795 [ +  - ][ +  - ]:       4466 :         mpMetaFile->AddAction( new MetaTextArrayAction( rStartPt, rStr, pDXAry, nIndex, nLen ) );
                 [ +  - ]
    5796                 :            : 
    5797         [ +  + ]:      49891 :     if ( !IsDeviceOutputNecessary() )
    5798                 :       4089 :         return;
    5799 [ -  + ][ #  # ]:      45802 :     if( !mpGraphics && !ImplGetGraphics() )
                 [ -  + ]
    5800                 :          0 :         return;
    5801         [ +  + ]:      45802 :     if( mbInitClipRegion )
    5802                 :       6687 :         ImplInitClipRegion();
    5803         [ +  + ]:      45802 :     if( mbOutputClipped )
    5804                 :        397 :         return;
    5805                 :            : 
    5806                 :      45405 :     SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen, rStartPt, 0, pDXAry, true );
    5807         [ +  + ]:      45405 :     if( pSalLayout )
    5808                 :            :     {
    5809                 :      44514 :         ImplDrawText( *pSalLayout );
    5810                 :      44514 :         pSalLayout->Release();
    5811                 :            :     }
    5812                 :            : 
    5813         [ +  + ]:      45405 :     if( mpAlphaVDev )
    5814                 :      49891 :         mpAlphaVDev->DrawTextArray( rStartPt, rStr, pDXAry, nIndex, nLen );
    5815                 :            : }
    5816                 :            : 
    5817                 :            : // -----------------------------------------------------------------------
    5818                 :            : 
    5819                 :     859066 : long OutputDevice::GetTextArray( const String& rStr, sal_Int32* pDXAry,
    5820                 :            :                                  xub_StrLen nIndex, xub_StrLen nLen ) const
    5821                 :            : {
    5822                 :            :     OSL_TRACE( "OutputDevice::GetTextArray()" );
    5823                 :            :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    5824                 :            : 
    5825         [ +  + ]:     859066 :     if( nIndex >= rStr.Len() )
    5826                 :     235179 :         return 0;
    5827         [ +  + ]:     623887 :     if( (sal_uLong)nIndex+nLen >= rStr.Len() )
    5828                 :     539486 :         nLen = rStr.Len() - nIndex;
    5829                 :            : 
    5830                 :            :     // do layout
    5831         [ +  - ]:     623887 :     SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen );
    5832         [ -  + ]:     623887 :     if( !pSalLayout )
    5833                 :          0 :         return 0;
    5834                 :            : 
    5835                 :     623887 :     long nWidth = pSalLayout->FillDXArray( pDXAry );
    5836                 :     623887 :     int nWidthFactor = pSalLayout->GetUnitsPerPixel();
    5837                 :     623887 :     pSalLayout->Release();
    5838                 :            : 
    5839                 :            :     // convert virtual char widths to virtual absolute positions
    5840         [ +  + ]:     623887 :     if( pDXAry )
    5841         [ +  + ]:    4013620 :         for( int i = 1; i < nLen; ++i )
    5842                 :    3746462 :             pDXAry[ i ] += pDXAry[ i-1 ];
    5843                 :            : 
    5844                 :            :     // convert from font units to logical units
    5845         [ +  + ]:     623887 :     if( mbMap )
    5846                 :            :     {
    5847         [ +  + ]:     358778 :         if( pDXAry )
    5848         [ +  + ]:    4279884 :             for( int i = 0; i < nLen; ++i )
    5849                 :    4013152 :                 pDXAry[i] = ImplDevicePixelToLogicWidth( pDXAry[i] );
    5850                 :     358778 :         nWidth = ImplDevicePixelToLogicWidth( nWidth );
    5851                 :            :     }
    5852                 :            : 
    5853         [ -  + ]:     623887 :     if( nWidthFactor > 1 )
    5854                 :            :     {
    5855         [ #  # ]:          0 :         if( pDXAry )
    5856         [ #  # ]:          0 :             for( int i = 0; i < nLen; ++i )
    5857                 :          0 :                 pDXAry[i] /= nWidthFactor;
    5858                 :          0 :         nWidth /= nWidthFactor;
    5859                 :            :     }
    5860                 :            : 
    5861                 :     859066 :     return nWidth;
    5862                 :            : }
    5863                 :            : 
    5864                 :            : // -----------------------------------------------------------------------
    5865                 :            : 
    5866                 :      19933 : bool OutputDevice::GetCaretPositions( const XubString& rStr, sal_Int32* pCaretXArray,
    5867                 :            :     xub_StrLen nIndex, xub_StrLen nLen,
    5868                 :            :     sal_Int32* pDXAry, long nLayoutWidth,
    5869                 :            :     sal_Bool bCellBreaking ) const
    5870                 :            : {
    5871                 :            :     OSL_TRACE( "OutputDevice::GetCaretPositions()" );
    5872                 :            :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    5873                 :            : 
    5874         [ -  + ]:      19933 :     if( nIndex >= rStr.Len() )
    5875                 :          0 :         return false;
    5876         [ +  - ]:      19933 :     if( (sal_uLong)nIndex+nLen >= rStr.Len() )
    5877                 :      19933 :         nLen = rStr.Len() - nIndex;
    5878                 :            : 
    5879                 :            :     // layout complex text
    5880                 :            :     SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen,
    5881         [ +  - ]:      19933 :         Point(0,0), nLayoutWidth, pDXAry );
    5882         [ -  + ]:      19933 :     if( !pSalLayout )
    5883                 :          0 :         return false;
    5884                 :            : 
    5885                 :      19933 :     int nWidthFactor = pSalLayout->GetUnitsPerPixel();
    5886                 :      19933 :     pSalLayout->GetCaretPositions( 2*nLen, pCaretXArray );
    5887                 :      19933 :     long nWidth = pSalLayout->GetTextWidth();
    5888                 :      19933 :     pSalLayout->Release();
    5889                 :            : 
    5890                 :            :     // fixup unknown caret positions
    5891                 :            :     int i;
    5892         [ +  + ]:      20183 :     for( i = 0; i < 2 * nLen; ++i )
    5893         [ +  + ]:      20167 :         if( pCaretXArray[ i ] >= 0 )
    5894                 :      19917 :             break;
    5895                 :      19933 :     long nXPos = pCaretXArray[ i ];
    5896         [ +  + ]:     245781 :     for( i = 0; i < 2 * nLen; ++i )
    5897                 :            :     {
    5898         [ +  + ]:     225848 :         if( pCaretXArray[ i ] >= 0 )
    5899                 :     225598 :             nXPos = pCaretXArray[ i ];
    5900                 :            :         else
    5901                 :        250 :             pCaretXArray[ i ] = nXPos;
    5902                 :            :     }
    5903                 :            : 
    5904                 :            :     // handle window mirroring
    5905         [ +  + ]:      19933 :     if( IsRTLEnabled() )
    5906                 :            :     {
    5907         [ +  + ]:        383 :         for( i = 0; i < 2 * nLen; ++i )
    5908                 :        298 :             pCaretXArray[i] = nWidth - pCaretXArray[i] - 1;
    5909                 :            :     }
    5910                 :            : 
    5911                 :            :     // convert from font units to logical units
    5912         [ -  + ]:      19933 :     if( mbMap )
    5913                 :            :     {
    5914         [ #  # ]:          0 :         for( i = 0; i < 2*nLen; ++i )
    5915                 :          0 :             pCaretXArray[i] = ImplDevicePixelToLogicWidth( pCaretXArray[i] );
    5916                 :            :     }
    5917                 :            : 
    5918         [ -  + ]:      19933 :     if( nWidthFactor != 1 )
    5919                 :            :     {
    5920         [ #  # ]:          0 :         for( i = 0; i < 2*nLen; ++i )
    5921                 :          0 :             pCaretXArray[i] /= nWidthFactor;
    5922                 :            :     }
    5923                 :            : 
    5924                 :            :     // if requested move caret position to cell limits
    5925                 :            :     if( bCellBreaking )
    5926                 :            :     {
    5927                 :            :         ; // TODO
    5928                 :            :     }
    5929                 :            : 
    5930                 :      19933 :     return true;
    5931                 :            : }
    5932                 :            : 
    5933                 :            : // -----------------------------------------------------------------------
    5934                 :            : 
    5935                 :      65257 : void OutputDevice::DrawStretchText( const Point& rStartPt, sal_uLong nWidth,
    5936                 :            :                                     const String& rStr,
    5937                 :            :                                     xub_StrLen nIndex, xub_StrLen nLen )
    5938                 :            : {
    5939                 :            :     OSL_TRACE( "OutputDevice::DrawStretchText()" );
    5940                 :            :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    5941                 :            : 
    5942         [ +  + ]:      65257 :     if ( mpMetaFile )
    5943 [ +  - ][ +  - ]:      62112 :         mpMetaFile->AddAction( new MetaStretchTextAction( rStartPt, nWidth, rStr, nIndex, nLen ) );
                 [ +  - ]
    5944                 :            : 
    5945         [ +  + ]:      65257 :     if ( !IsDeviceOutputNecessary() )
    5946                 :      65257 :         return;
    5947                 :            : 
    5948                 :       3145 :     SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen, rStartPt, nWidth, NULL, true );
    5949         [ +  - ]:       3145 :     if( pSalLayout )
    5950                 :            :     {
    5951                 :       3145 :         ImplDrawText( *pSalLayout );
    5952                 :       3145 :         pSalLayout->Release();
    5953                 :            :     }
    5954                 :            : 
    5955         [ -  + ]:       3145 :     if( mpAlphaVDev )
    5956                 :          0 :         mpAlphaVDev->DrawStretchText( rStartPt, nWidth, rStr, nIndex, nLen );
    5957                 :            : }
    5958                 :            : 
    5959                 :            : // -----------------------------------------------------------------------
    5960                 :            : 
    5961                 :     981170 : ImplLayoutArgs OutputDevice::ImplPrepareLayoutArgs( String& rStr,
    5962                 :            :                                        xub_StrLen nMinIndex, xub_StrLen nLen,
    5963                 :            :                                        long nPixelWidth, const sal_Int32* pDXArray ) const
    5964                 :            : {
    5965                 :            :     // get string length for calculating extents
    5966                 :     981170 :     xub_StrLen nEndIndex = rStr.Len();
    5967         [ +  + ]:     981170 :     if( (sal_uLong)nMinIndex + nLen < nEndIndex )
    5968                 :     152416 :         nEndIndex = nMinIndex + nLen;
    5969                 :            : 
    5970                 :            :     // don't bother if there is nothing to do
    5971         [ -  + ]:     981170 :     if( nEndIndex < nMinIndex )
    5972                 :          0 :         nEndIndex = nMinIndex;
    5973                 :            : 
    5974                 :     981170 :     int nLayoutFlags = 0;
    5975         [ +  + ]:     981170 :     if( mnTextLayoutMode & TEXT_LAYOUT_BIDI_RTL )
    5976                 :       3562 :         nLayoutFlags |= SAL_LAYOUT_BIDI_RTL;
    5977         [ +  + ]:     981170 :     if( mnTextLayoutMode & TEXT_LAYOUT_BIDI_STRONG )
    5978                 :     386400 :         nLayoutFlags |= SAL_LAYOUT_BIDI_STRONG;
    5979         [ +  + ]:     594770 :     else if( 0 == (mnTextLayoutMode & TEXT_LAYOUT_BIDI_RTL) )
    5980                 :            :     {
    5981                 :            :         // disable Bidi if no RTL hint and no RTL codes used
    5982                 :     591208 :         const xub_Unicode* pStr = rStr.GetBuffer() + nMinIndex;
    5983                 :     591208 :         const xub_Unicode* pEnd = rStr.GetBuffer() + nEndIndex;
    5984         [ +  + ]:    3706870 :         for( ; pStr < pEnd; ++pStr )
    5985 [ +  + ][ +  - ]:    3115662 :             if( ((*pStr >= 0x0580) && (*pStr < 0x0800))   // middle eastern scripts
         [ +  + ][ +  - ]
         [ +  + ][ -  + ]
    5986                 :            :             ||  ((*pStr >= 0xFB18) && (*pStr < 0xFE00))   // hebrew + arabic A presentation forms
    5987                 :            :             ||  ((*pStr >= 0xFE70) && (*pStr < 0xFEFF)) ) // arabic presentation forms B
    5988                 :          0 :                 break;
    5989         [ +  - ]:     591208 :         if( pStr >= pEnd )
    5990                 :     591208 :             nLayoutFlags |= SAL_LAYOUT_BIDI_STRONG;
    5991                 :            :     }
    5992                 :            : 
    5993         [ +  + ]:     981170 :     if( mbKerning )
    5994                 :     195118 :         nLayoutFlags |= SAL_LAYOUT_KERNING_PAIRS;
    5995         [ -  + ]:     981170 :     if( maFont.GetKerning() & KERNING_ASIAN )
    5996                 :          0 :         nLayoutFlags |= SAL_LAYOUT_KERNING_ASIAN;
    5997         [ -  + ]:     981170 :     if( maFont.IsVertical() )
    5998                 :          0 :         nLayoutFlags |= SAL_LAYOUT_VERTICAL;
    5999                 :            : 
    6000         [ -  + ]:     981170 :     if( mnTextLayoutMode & TEXT_LAYOUT_ENABLE_LIGATURES )
    6001                 :          0 :         nLayoutFlags |= SAL_LAYOUT_ENABLE_LIGATURES;
    6002         [ +  + ]:     981170 :     else if( mnTextLayoutMode & TEXT_LAYOUT_COMPLEX_DISABLED )
    6003                 :     212770 :         nLayoutFlags |= SAL_LAYOUT_COMPLEX_DISABLED;
    6004                 :            :     else
    6005                 :            :     {
    6006                 :            :         // disable CTL for non-CTL text
    6007                 :     768400 :         const sal_Unicode* pStr = rStr.GetBuffer() + nMinIndex;
    6008                 :     768400 :         const sal_Unicode* pEnd = rStr.GetBuffer() + nEndIndex;
    6009         [ +  + ]:   22011003 :         for( ; pStr < pEnd; ++pStr )
    6010 [ +  + ][ +  + ]:   21244004 :             if( ((*pStr >= 0x0300) && (*pStr < 0x0370))   // diacritical marks
         [ +  + ][ +  - ]
         [ +  + ][ +  - ]
         [ +  + ][ +  - ]
         [ +  + ][ +  - ]
         [ +  + ][ -  + ]
    6011                 :            :             ||  ((*pStr >= 0x0590) && (*pStr < 0x10A0))   // many CTL scripts
    6012                 :            :             ||  ((*pStr >= 0x1100) && (*pStr < 0x1200))   // hangul jamo
    6013                 :            :             ||  ((*pStr >= 0x1700) && (*pStr < 0x1900))   // many CTL scripts
    6014                 :            :             ||  ((*pStr >= 0xFB1D) && (*pStr < 0xFE00))   // middle east presentation
    6015                 :            :             ||  ((*pStr >= 0xFE70) && (*pStr < 0xFEFF)) ) // arabic presentation B
    6016                 :       1401 :                 break;
    6017         [ +  + ]:     768400 :         if( pStr >= pEnd )
    6018                 :     766999 :             nLayoutFlags |= SAL_LAYOUT_COMPLEX_DISABLED;
    6019                 :            :     }
    6020                 :            : 
    6021         [ +  + ]:     981170 :     if( meTextLanguage ) //TODO: (mnTextLayoutMode & TEXT_LAYOUT_SUBSTITUTE_DIGITS)
    6022                 :            :     {
    6023                 :            :         // disable character localization when no digits used
    6024                 :     488393 :         const sal_Unicode* pBase = rStr.GetBuffer();
    6025                 :     488393 :         const sal_Unicode* pStr = pBase + nMinIndex;
    6026                 :     488393 :         const sal_Unicode* pEnd = pBase + nEndIndex;
    6027         [ +  + ]:   19975118 :         for( ; pStr < pEnd; ++pStr )
    6028                 :            :         {
    6029                 :            :             // TODO: are there non-digit localizations?
    6030 [ +  + ][ +  + ]:   19486725 :             if( (*pStr >= '0') && (*pStr <= '9') )
    6031                 :            :             {
    6032                 :            :                 // translate characters to local preference
    6033                 :   10657779 :                 sal_UCS4 cChar = GetLocalizedChar( *pStr, meTextLanguage );
    6034         [ -  + ]:   10657779 :                 if( cChar != *pStr )
    6035                 :            :                     // TODO: are the localized digit surrogates?
    6036                 :            :                     rStr.SetChar( static_cast<sal_uInt16>(pStr - pBase),
    6037                 :          0 :                                  static_cast<sal_Unicode>(cChar) );
    6038                 :            :             }
    6039                 :            :         }
    6040                 :            :     }
    6041                 :            : 
    6042                 :            :     // right align for RTL text, DRAWPOS_REVERSED, RTL window style
    6043                 :     981170 :     bool bRightAlign = ((mnTextLayoutMode & TEXT_LAYOUT_BIDI_RTL) != 0);
    6044         [ +  + ]:     981170 :     if( mnTextLayoutMode & TEXT_LAYOUT_TEXTORIGIN_LEFT )
    6045                 :      34413 :         bRightAlign = false;
    6046         [ -  + ]:     946757 :     else if ( mnTextLayoutMode & TEXT_LAYOUT_TEXTORIGIN_RIGHT )
    6047                 :          0 :         bRightAlign = true;
    6048                 :            :     // SSA: hack for western office, ie text get right aligned
    6049                 :            :     //      for debugging purposes of mirrored UI
    6050                 :            :     //static const char* pEnv = getenv( "SAL_RTL_MIRRORTEXT" );
    6051                 :     981170 :     bool bRTLWindow = IsRTLEnabled();
    6052                 :     981170 :     bRightAlign ^= bRTLWindow;
    6053         [ +  + ]:     981170 :     if( bRightAlign )
    6054                 :        939 :         nLayoutFlags |= SAL_LAYOUT_RIGHT_ALIGN;
    6055                 :            : 
    6056                 :            :     // set layout options
    6057                 :     981170 :     ImplLayoutArgs aLayoutArgs( rStr.GetBuffer(), rStr.Len(), nMinIndex, nEndIndex, nLayoutFlags );
    6058                 :            : 
    6059         [ +  - ]:     981170 :     int nOrientation = mpFontEntry ? mpFontEntry->mnOrientation : 0;
    6060                 :     981170 :     aLayoutArgs.SetOrientation( nOrientation );
    6061                 :            : 
    6062                 :     981170 :     aLayoutArgs.SetLayoutWidth( nPixelWidth );
    6063                 :     981170 :     aLayoutArgs.SetDXArray( pDXArray );
    6064                 :            : 
    6065                 :     981170 :     return aLayoutArgs;
    6066                 :            : }
    6067                 :            : 
    6068                 :            : // -----------------------------------------------------------------------
    6069                 :            : 
    6070                 :    1001409 : SalLayout* OutputDevice::ImplLayout( const String& rOrigStr,
    6071                 :            :                                      xub_StrLen nMinIndex,
    6072                 :            :                                      xub_StrLen nLen,
    6073                 :            :                                      const Point& rLogicalPos,
    6074                 :            :                                      long nLogicalWidth,
    6075                 :            :                                      const sal_Int32* pDXArray,
    6076                 :            :                                      bool bFilter ) const
    6077                 :            : {
    6078                 :            :     // we need a graphics
    6079         [ +  + ]:    1001409 :     if( !mpGraphics )
    6080 [ +  - ][ -  + ]:        421 :         if( !ImplGetGraphics() )
    6081                 :          0 :             return NULL;
    6082                 :            : 
    6083                 :            :     // initialize font if needed
    6084         [ +  + ]:    1001409 :     if( mbNewFont )
    6085 [ +  - ][ -  + ]:     138244 :         if( !ImplNewFont() )
    6086                 :          0 :             return NULL;
    6087         [ +  + ]:    1001409 :     if( mbInitFont )
    6088         [ +  - ]:     176248 :         ImplInitFont();
    6089                 :            : 
    6090                 :            :     // check string index and length
    6091         [ +  + ]:    1001409 :     if( (unsigned)nMinIndex + nLen > rOrigStr.Len() )
    6092                 :            :     {
    6093                 :     184172 :         const int nNewLen = (int)rOrigStr.Len() - nMinIndex;
    6094         [ +  + ]:     184172 :         if( nNewLen <= 0 )
    6095                 :      13171 :             return NULL;
    6096                 :     171001 :         nLen = static_cast<xub_StrLen>(nNewLen);
    6097                 :            :     }
    6098                 :            : 
    6099         [ +  - ]:     988238 :     String aStr = rOrigStr;
    6100                 :            : 
    6101                 :            :     // filter out special markers
    6102         [ +  + ]:     988238 :     if( bFilter )
    6103                 :            :     {
    6104                 :     150228 :         xub_StrLen nCutStart, nCutStop, nOrgLen = nLen;
    6105         [ +  - ]:     150228 :         rtl::OUString aTmpStr(aStr);
    6106 [ +  - ][ +  - ]:     150228 :         bool bFiltered = mpGraphics->filterText( rOrigStr, aTmpStr, nMinIndex, nLen, nCutStart, nCutStop );
    6107         [ +  - ]:     150228 :         aStr = aTmpStr;
    6108         [ +  + ]:     150228 :         if( !nLen )
    6109                 :       7173 :             return NULL;
    6110                 :            : 
    6111 [ -  + ][ #  # ]:     143055 :         if( bFiltered && nCutStop != nCutStart && pDXArray )
                 [ #  # ]
    6112                 :            :         {
    6113         [ #  # ]:          0 :             if( !nLen )
    6114                 :          0 :                 pDXArray = NULL;
    6115                 :            :             else
    6116                 :            :             {
    6117                 :          0 :                 sal_Int32* pAry = (sal_Int32*)alloca(sizeof(sal_Int32)*nLen);
    6118         [ #  # ]:          0 :                 if( nCutStart > nMinIndex )
    6119                 :          0 :                     memcpy( pAry, pDXArray, sizeof(sal_Int32)*(nCutStart-nMinIndex) );
    6120                 :            :                 // note: nCutStart will never be smaller than nMinIndex
    6121                 :          0 :                 memcpy( pAry+nCutStart-nMinIndex,
    6122                 :          0 :                         pDXArray + nOrgLen - (nCutStop-nMinIndex),
    6123                 :          0 :                         sizeof(sal_Int32)*(nLen - (nCutStart-nMinIndex)) );
    6124                 :     143055 :                 pDXArray = pAry;
    6125                 :            :             }
    6126         [ +  + ]:     150228 :         }
    6127                 :            :     }
    6128                 :            : 
    6129                 :            :     // convert from logical units to physical units
    6130                 :            :     // recode string if needed
    6131         [ -  + ]:     981065 :     if( mpFontEntry->mpConversion )
    6132         [ #  # ]:          0 :         mpFontEntry->mpConversion->RecodeString( aStr, 0, aStr.Len() );
    6133                 :            : 
    6134                 :     981065 :     long nPixelWidth = nLogicalWidth;
    6135 [ +  + ][ +  - ]:     981065 :     if( nLogicalWidth && mbMap )
    6136         [ +  - ]:       3041 :         nPixelWidth = ImplLogicWidthToDevicePixel( nLogicalWidth );
    6137 [ +  + ][ +  + ]:     981065 :     if( pDXArray && mbMap )
    6138                 :            :     {
    6139                 :            :         // convert from logical units to font units using a temporary array
    6140                 :      36817 :         sal_Int32* pTempDXAry = (sal_Int32*)alloca( nLen * sizeof(sal_Int32) );
    6141                 :            :         // using base position for better rounding a.k.a. "dancing characters"
    6142         [ +  - ]:      36817 :         int nPixelXOfs = ImplLogicWidthToDevicePixel( rLogicalPos.X() );
    6143         [ +  + ]:    1529759 :         for( int i = 0; i < nLen; ++i )
    6144         [ +  - ]:    1492942 :             pTempDXAry[i] = ImplLogicWidthToDevicePixel( rLogicalPos.X() + pDXArray[i] ) - nPixelXOfs;
    6145                 :            : 
    6146                 :      36817 :         pDXArray = pTempDXAry;
    6147                 :            :     }
    6148                 :            : 
    6149         [ +  - ]:     981065 :     ImplLayoutArgs aLayoutArgs = ImplPrepareLayoutArgs( aStr, nMinIndex, nLen, nPixelWidth, pDXArray );
    6150                 :            : 
    6151                 :            :     // get matching layout object for base font
    6152                 :     981065 :     SalLayout* pSalLayout = NULL;
    6153         [ -  + ]:     981065 :     if( mpPDFWriter )
    6154         [ #  # ]:          0 :         pSalLayout = mpPDFWriter->GetTextLayout( aLayoutArgs, &mpFontEntry->maFontSelData );
    6155                 :            : 
    6156         [ +  - ]:     981065 :     if( !pSalLayout )
    6157         [ +  - ]:     981065 :         pSalLayout = mpGraphics->GetTextLayout( aLayoutArgs, 0 );
    6158                 :            : 
    6159                 :            :     // layout text
    6160 [ +  - ][ +  - ]:     981065 :     if( pSalLayout && !pSalLayout->LayoutText( aLayoutArgs ) )
         [ -  + ][ -  + ]
    6161                 :            :     {
    6162         [ #  # ]:          0 :         pSalLayout->Release();
    6163                 :          0 :         pSalLayout = NULL;
    6164                 :            :     }
    6165                 :            : 
    6166         [ -  + ]:     981065 :     if( !pSalLayout )
    6167                 :          0 :         return NULL;
    6168                 :            : 
    6169                 :            :     // do glyph fallback if needed
    6170                 :            :     // #105768# avoid fallback for very small font sizes
    6171         [ +  + ]:     981065 :     if( aLayoutArgs.NeedFallback() )
    6172 [ +  - ][ +  - ]:       9357 :         if( mpFontEntry && (mpFontEntry->maFontSelData.mnHeight >= 3) )
    6173         [ +  - ]:       9357 :             pSalLayout = ImplGlyphFallbackLayout( pSalLayout, aLayoutArgs );
    6174                 :            : 
    6175                 :            :     // position, justify, etc. the layout
    6176         [ +  - ]:     981065 :     pSalLayout->AdjustLayout( aLayoutArgs );
    6177         [ +  - ]:     981065 :     pSalLayout->DrawBase() = ImplLogicToDevicePixel( rLogicalPos );
    6178                 :            :     // adjust to right alignment if necessary
    6179         [ +  + ]:     981065 :     if( aLayoutArgs.mnFlags & SAL_LAYOUT_RIGHT_ALIGN )
    6180                 :            :     {
    6181                 :            :         long nRTLOffset;
    6182         [ +  + ]:        939 :         if( pDXArray )
    6183                 :         14 :             nRTLOffset = pDXArray[ nLen - 1 ];
    6184         [ -  + ]:        925 :         else if( nPixelWidth )
    6185                 :          0 :             nRTLOffset = nPixelWidth;
    6186                 :            :         else
    6187         [ +  - ]:        925 :             nRTLOffset = pSalLayout->GetTextWidth() / pSalLayout->GetUnitsPerPixel();
    6188                 :        939 :         pSalLayout->DrawOffset().X() = 1 - nRTLOffset;
    6189                 :            :     }
    6190                 :            : 
    6191         [ +  - ]:    1001409 :     return pSalLayout;
    6192                 :            : }
    6193                 :            : 
    6194                 :       9357 : SalLayout* OutputDevice::getFallbackFontThatFits(ImplFontEntry &rFallbackFont,
    6195                 :            :     FontSelectPattern &rFontSelData, int nFallbackLevel,
    6196                 :            :     ImplLayoutArgs& rLayoutArgs, const ImplFontMetricData& rOrigMetric) const
    6197                 :            : {
    6198         [ +  - ]:       9357 :     rFallbackFont.mnSetFontFlags = mpGraphics->SetFont( &rFontSelData, nFallbackLevel );
    6199                 :            : 
    6200                 :       9357 :     rLayoutArgs.ResetPos();
    6201         [ +  - ]:       9357 :     SalLayout* pFallback = mpGraphics->GetTextLayout( rLayoutArgs, nFallbackLevel );
    6202                 :            : 
    6203         [ -  + ]:       9357 :     if (!pFallback)
    6204                 :          0 :         return NULL;
    6205                 :            : 
    6206 [ +  - ][ -  + ]:       9357 :     if (!pFallback->LayoutText(rLayoutArgs))
    6207                 :            :     {
    6208                 :            :         // there is no need for a font that couldn't resolve anything
    6209         [ #  # ]:          0 :         pFallback->Release();
    6210                 :          0 :         return NULL;
    6211                 :            :     }
    6212                 :            : 
    6213         [ +  - ]:       9357 :     Rectangle aBoundRect;
    6214                 :       9357 :     bool bHaveBounding = false;
    6215         [ +  - ]:       9357 :     Rectangle aRectangle;
    6216                 :            : 
    6217         [ +  - ]:       9357 :     pFallback->AdjustLayout( rLayoutArgs );
    6218                 :            : 
    6219                 :            :     //All we care about here is getting the vertical bounds of this text and
    6220                 :            :     //make sure it will fit inside the available space
    6221                 :       9357 :     Point aPos;
    6222                 :      19011 :     for( int nStart = 0;;)
    6223                 :            :     {
    6224                 :            :         sal_GlyphId nLGlyph;
    6225 [ +  - ][ +  + ]:      19011 :         if( !pFallback->GetNextGlyphs( 1, &nLGlyph, aPos, nStart ) )
    6226                 :            :             break;
    6227                 :            : 
    6228                 :       9654 :         sal_GlyphId nFontTag = nFallbackLevel << GF_FONTSHIFT;
    6229                 :       9654 :         nLGlyph |= nFontTag;
    6230                 :            : 
    6231                 :            :         // get bounding rectangle of individual glyph
    6232 [ +  - ][ +  - ]:       9654 :         if( mpGraphics->GetGlyphBoundRect( nLGlyph, aRectangle ) )
    6233                 :            :         {
    6234                 :            :             // merge rectangle
    6235         [ +  - ]:       9654 :             aRectangle += aPos;
    6236         [ +  - ]:       9654 :             aBoundRect.Union( aRectangle );
    6237                 :       9654 :             bHaveBounding = true;
    6238                 :            :         }
    6239                 :            :     }
    6240                 :            : 
    6241                 :            :     //Shrink it down if it won't fit
    6242         [ +  - ]:       9357 :     if (bHaveBounding)
    6243                 :            :     {
    6244                 :       9357 :         long  nGlyphsAscent = -aBoundRect.Top();
    6245                 :            :         float fScaleTop = nGlyphsAscent > rOrigMetric.mnAscent ?
    6246         [ +  + ]:       9357 :             rOrigMetric.mnAscent/(float)nGlyphsAscent : 1;
    6247                 :       9357 :         long  nGlyphsDescent = aBoundRect.Bottom();
    6248                 :            :         float fScaleBottom = nGlyphsDescent > rOrigMetric.mnDescent ?
    6249         [ +  + ]:       9357 :             rOrigMetric.mnDescent/(float)nGlyphsDescent : 1;
    6250         [ +  + ]:       9357 :         float fScale = fScaleBottom < fScaleTop ? fScaleBottom : fScaleTop;
    6251         [ +  + ]:       9357 :         if (fScale < 1)
    6252                 :            :         {
    6253                 :       3393 :             long nOrigHeight = rFontSelData.mnHeight;
    6254                 :       3393 :             long nNewHeight = static_cast<int>(static_cast<float>(rFontSelData.mnHeight) * fScale);
    6255                 :            : 
    6256         [ -  + ]:       3393 :             if (nNewHeight == nOrigHeight)
    6257                 :          0 :                 --nNewHeight;
    6258                 :            : 
    6259         [ +  - ]:       3393 :             pFallback->Release();
    6260                 :            : 
    6261                 :       3393 :             rFontSelData.mnHeight = nNewHeight;
    6262         [ +  - ]:       3393 :             rFallbackFont.mnSetFontFlags = mpGraphics->SetFont( &rFontSelData, nFallbackLevel );
    6263                 :       3393 :             rFontSelData.mnHeight = nOrigHeight;
    6264                 :            : 
    6265                 :       3393 :             rLayoutArgs.ResetPos();
    6266         [ +  - ]:       3393 :             pFallback = mpGraphics->GetTextLayout( rLayoutArgs, nFallbackLevel );
    6267 [ +  - ][ +  - ]:       3393 :             if (pFallback && !pFallback->LayoutText(rLayoutArgs))
         [ -  + ][ -  + ]
    6268                 :            :             {
    6269         [ #  # ]:          0 :                 pFallback->Release();
    6270                 :          0 :                 pFallback = NULL;
    6271                 :            :             }
    6272                 :            :             SAL_WARN_IF(pFallback, "vcl.gdi", "we couldn't layout text with a smaller point size that worked with a bigger one");
    6273                 :            :         }
    6274                 :            :     }
    6275                 :       9357 :     return pFallback;
    6276                 :            : }
    6277                 :            : 
    6278                 :            : // -----------------------------------------------------------------------
    6279                 :            : 
    6280                 :       9357 : SalLayout* OutputDevice::ImplGlyphFallbackLayout( SalLayout* pSalLayout, ImplLayoutArgs& rLayoutArgs ) const
    6281                 :            : {
    6282                 :            :     // prepare multi level glyph fallback
    6283                 :       9357 :     MultiSalLayout* pMultiSalLayout = NULL;
    6284         [ +  - ]:       9357 :     ImplLayoutRuns aLayoutRuns = rLayoutArgs.maRuns;
    6285         [ +  - ]:       9357 :     rLayoutArgs.PrepareFallback();
    6286                 :       9357 :     rLayoutArgs.mnFlags |= SAL_LAYOUT_FOR_FALLBACK;
    6287                 :            : 
    6288                 :            :     // get list of unicodes that need glyph fallback
    6289                 :       9357 :     int nCharPos = -1;
    6290                 :       9357 :     bool bRTL = false;
    6291                 :       9357 :     rtl::OUStringBuffer aMissingCodeBuf;
    6292 [ +  - ][ +  + ]:      19011 :     while( rLayoutArgs.GetNextPos( &nCharPos, &bRTL) )
    6293         [ +  - ]:       9654 :         aMissingCodeBuf.append( rLayoutArgs.mpStr[ nCharPos ] );
    6294                 :       9357 :     rLayoutArgs.ResetPos();
    6295         [ +  - ]:       9357 :     rtl::OUString aMissingCodes = aMissingCodeBuf.makeStringAndClear();
    6296                 :            : 
    6297         [ +  - ]:       9357 :     FontSelectPattern aFontSelData = mpFontEntry->maFontSelData;
    6298                 :            : 
    6299         [ +  - ]:       9357 :     ImplFontMetricData aOrigMetric( aFontSelData );
    6300                 :            :     // TODO: use cached metric in fontentry
    6301         [ +  - ]:       9357 :     mpGraphics->GetFontMetric( &aOrigMetric );
    6302                 :            : 
    6303                 :            :     // when device specific font substitution may have been performed for
    6304                 :            :     // the originally selected font then make sure that a fallback to that
    6305                 :            :     // font is performed first
    6306                 :       9357 :     int nDevSpecificFallback = 0;
    6307 [ +  + ][ -  + ]:       9357 :     if( mpOutDevData && !mpOutDevData->maDevFontSubst.Empty() )
                 [ -  + ]
    6308                 :          0 :         nDevSpecificFallback = 1;
    6309                 :            : 
    6310                 :            :     // try if fallback fonts support the missing unicodes
    6311         [ +  - ]:       9357 :     for( int nFallbackLevel = 1; nFallbackLevel < MAX_FALLBACK; ++nFallbackLevel )
    6312                 :            :     {
    6313                 :            :         // find a font family suited for glyph fallback
    6314                 :            : #ifndef FONTFALLBACK_HOOKS_DISABLED
    6315                 :            :         // GetGlyphFallbackFont() needs a valid aFontSelData.mpFontEntry
    6316                 :            :         // if the system-specific glyph fallback is active
    6317                 :       9357 :         aFontSelData.mpFontEntry = mpFontEntry; // reset the fontentry to base-level
    6318                 :            : #endif
    6319                 :            :         ImplFontEntry* pFallbackFont = mpFontCache->GetGlyphFallbackFont( mpFontList,
    6320         [ +  - ]:       9357 :             aFontSelData, nFallbackLevel-nDevSpecificFallback, aMissingCodes );
    6321         [ -  + ]:       9357 :         if( !pFallbackFont )
    6322                 :          0 :             break;
    6323                 :            : 
    6324                 :       9357 :         aFontSelData.mpFontEntry = pFallbackFont;
    6325                 :       9357 :         aFontSelData.mpFontData = pFallbackFont->maFontSelData.mpFontData;
    6326 [ +  - ][ +  - ]:       9357 :         if( mpFontEntry && nFallbackLevel < MAX_FALLBACK-1)
    6327                 :            :         {
    6328                 :            :             // ignore fallback font if it is the same as the original font
    6329         [ -  + ]:       9357 :             if( mpFontEntry->maFontSelData.mpFontData == aFontSelData.mpFontData )
    6330                 :            :             {
    6331         [ #  # ]:          0 :                 mpFontCache->Release( pFallbackFont );
    6332                 :          0 :                 continue;
    6333                 :            :             }
    6334                 :            :         }
    6335                 :            : 
    6336                 :            :         // create and add glyph fallback layout to multilayout
    6337                 :            :         SalLayout* pFallback = getFallbackFontThatFits(*pFallbackFont, aFontSelData,
    6338         [ +  - ]:       9357 :             nFallbackLevel, rLayoutArgs, aOrigMetric);
    6339         [ +  - ]:       9357 :         if (pFallback)
    6340                 :            :         {
    6341         [ +  - ]:       9357 :             if( !pMultiSalLayout )
    6342 [ +  - ][ +  - ]:       9357 :                 pMultiSalLayout = new MultiSalLayout( *pSalLayout );
    6343                 :            :             pMultiSalLayout->AddFallback( *pFallback,
    6344         [ +  - ]:       9357 :                 rLayoutArgs.maRuns, aFontSelData.mpFontData );
    6345         [ -  + ]:       9357 :             if (nFallbackLevel == MAX_FALLBACK-1)
    6346         [ #  # ]:          0 :                 pMultiSalLayout->SetInComplete();
    6347                 :            :         }
    6348                 :            : 
    6349         [ +  - ]:       9357 :         mpFontCache->Release( pFallbackFont );
    6350                 :            : 
    6351                 :            :         // break when this fallback was sufficient
    6352 [ +  - ][ +  - ]:       9357 :         if( !rLayoutArgs.PrepareFallback() )
    6353                 :       9357 :             break;
    6354                 :            :     }
    6355                 :            : 
    6356 [ +  - ][ +  - ]:       9357 :     if( pMultiSalLayout && pMultiSalLayout->LayoutText( rLayoutArgs ) )
         [ +  - ][ +  - ]
    6357                 :       9357 :         pSalLayout = pMultiSalLayout;
    6358                 :            : 
    6359                 :            :     // restore orig font settings
    6360         [ +  - ]:       9357 :     pSalLayout->InitFont();
    6361         [ +  - ]:       9357 :     rLayoutArgs.maRuns = aLayoutRuns;
    6362                 :            : 
    6363 [ +  - ][ +  - ]:       9357 :     return pSalLayout;
    6364                 :            : }
    6365                 :            : 
    6366                 :            : // -----------------------------------------------------------------------
    6367                 :            : 
    6368                 :          0 : sal_Bool OutputDevice::GetTextIsRTL(
    6369                 :            :             const String& rString,
    6370                 :            :             xub_StrLen nIndex, xub_StrLen nLen ) const
    6371                 :            : {
    6372         [ #  # ]:          0 :     String aStr( rString );
    6373         [ #  # ]:          0 :     ImplLayoutArgs aArgs = ImplPrepareLayoutArgs( aStr, nIndex, nLen, 0, NULL );
    6374                 :          0 :     bool bRTL = false;
    6375                 :          0 :     int nCharPos = -1;
    6376         [ #  # ]:          0 :     aArgs.GetNextPos( &nCharPos, &bRTL );
    6377 [ #  # ][ #  # ]:          0 :     return (nCharPos != nIndex) ? sal_True : sal_False;
    6378                 :            : }
    6379                 :            : 
    6380                 :            : // -----------------------------------------------------------------------
    6381                 :            : 
    6382                 :      56357 : xub_StrLen OutputDevice::GetTextBreak( const String& rStr, long nTextWidth,
    6383                 :            :                                        xub_StrLen nIndex, xub_StrLen nLen,
    6384                 :            :                                        long nCharExtra, sal_Bool /*TODO: bCellBreaking*/ ) const
    6385                 :            : {
    6386                 :            :     OSL_TRACE( "OutputDevice::GetTextBreak()" );
    6387                 :            :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    6388                 :            : 
    6389         [ +  - ]:      56357 :     SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen );
    6390                 :      56357 :     xub_StrLen nRetVal = STRING_LEN;
    6391         [ +  - ]:      56357 :     if( pSalLayout )
    6392                 :            :     {
    6393                 :            :         // convert logical widths into layout units
    6394                 :            :         // NOTE: be very careful to avoid rounding errors for nCharExtra case
    6395                 :            :         // problem with rounding errors especially for small nCharExtras
    6396                 :            :         // TODO: remove when layout units have subpixel granularity
    6397                 :      56357 :         long nWidthFactor = pSalLayout->GetUnitsPerPixel();
    6398         [ +  - ]:      56357 :         long nSubPixelFactor = (nWidthFactor < 64 ) ? 64 : 1;
    6399                 :      56357 :         nTextWidth *= nWidthFactor * nSubPixelFactor;
    6400                 :      56357 :         long nTextPixelWidth = ImplLogicWidthToDevicePixel( nTextWidth );
    6401                 :      56357 :         long nExtraPixelWidth = 0;
    6402         [ +  + ]:      56357 :         if( nCharExtra != 0 )
    6403                 :            :         {
    6404                 :        240 :             nCharExtra *= nWidthFactor * nSubPixelFactor;
    6405                 :        240 :             nExtraPixelWidth = ImplLogicWidthToDevicePixel( nCharExtra );
    6406                 :            :         }
    6407                 :      56357 :         nRetVal = sal::static_int_cast<xub_StrLen>(pSalLayout->GetTextBreak( nTextPixelWidth, nExtraPixelWidth, nSubPixelFactor ));
    6408                 :            : 
    6409                 :      56357 :         pSalLayout->Release();
    6410                 :            :     }
    6411                 :            : 
    6412                 :      56357 :     return nRetVal;
    6413                 :            : }
    6414                 :            : 
    6415                 :            : // -----------------------------------------------------------------------
    6416                 :            : 
    6417                 :          0 : xub_StrLen OutputDevice::GetTextBreak( const String& rStr, long nTextWidth,
    6418                 :            :                                        sal_Unicode nHyphenatorChar, xub_StrLen& rHyphenatorPos,
    6419                 :            :                                        xub_StrLen nIndex, xub_StrLen nLen,
    6420                 :            :                                        long nCharExtra ) const
    6421                 :            : {
    6422                 :            :     OSL_TRACE( "OutputDevice::GetTextBreak()" );
    6423                 :            :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    6424                 :            : 
    6425                 :          0 :     rHyphenatorPos = STRING_LEN;
    6426                 :            : 
    6427         [ #  # ]:          0 :     SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen );
    6428         [ #  # ]:          0 :     if( !pSalLayout )
    6429                 :          0 :         return STRING_LEN;
    6430                 :            : 
    6431                 :            :     // convert logical widths into layout units
    6432                 :            :     // NOTE: be very careful to avoid rounding errors for nCharExtra case
    6433                 :            :     // problem with rounding errors especially for small nCharExtras
    6434                 :            :     // TODO: remove when layout units have subpixel granularity
    6435                 :          0 :     long nWidthFactor = pSalLayout->GetUnitsPerPixel();
    6436         [ #  # ]:          0 :     long nSubPixelFactor = (nWidthFactor < 64 ) ? 64 : 1;
    6437                 :            : 
    6438                 :          0 :     nTextWidth *= nWidthFactor * nSubPixelFactor;
    6439         [ #  # ]:          0 :     long nTextPixelWidth = ImplLogicWidthToDevicePixel( nTextWidth );
    6440                 :          0 :     long nExtraPixelWidth = 0;
    6441         [ #  # ]:          0 :     if( nCharExtra != 0 )
    6442                 :            :     {
    6443                 :          0 :         nCharExtra *= nWidthFactor * nSubPixelFactor;
    6444         [ #  # ]:          0 :         nExtraPixelWidth = ImplLogicWidthToDevicePixel( nCharExtra );
    6445                 :            :     }
    6446                 :            : 
    6447                 :            :     // calculate un-hyphenated break position
    6448         [ #  # ]:          0 :     xub_StrLen nRetVal = sal::static_int_cast<xub_StrLen>(pSalLayout->GetTextBreak( nTextPixelWidth, nExtraPixelWidth, nSubPixelFactor ));
    6449                 :            : 
    6450                 :            :     // calculate hyphenated break position
    6451                 :          0 :     rtl::OUString aHyphenatorStr(nHyphenatorChar);
    6452                 :          0 :     xub_StrLen nTempLen = 1;
    6453 [ #  # ][ #  # ]:          0 :     SalLayout* pHyphenatorLayout = ImplLayout( aHyphenatorStr, 0, nTempLen );
                 [ #  # ]
    6454         [ #  # ]:          0 :     if( pHyphenatorLayout )
    6455                 :            :     {
    6456                 :            :         // calculate subpixel width of hyphenation character
    6457         [ #  # ]:          0 :         long nHyphenatorPixelWidth = pHyphenatorLayout->GetTextWidth() * nSubPixelFactor;
    6458         [ #  # ]:          0 :         pHyphenatorLayout->Release();
    6459                 :            : 
    6460                 :            :         // calculate hyphenated break position
    6461                 :          0 :         nTextPixelWidth -= nHyphenatorPixelWidth;
    6462         [ #  # ]:          0 :         if( nExtraPixelWidth > 0 )
    6463                 :          0 :             nTextPixelWidth -= nExtraPixelWidth;
    6464                 :            : 
    6465         [ #  # ]:          0 :         rHyphenatorPos = sal::static_int_cast<xub_StrLen>(pSalLayout->GetTextBreak( nTextPixelWidth, nExtraPixelWidth, nSubPixelFactor ));
    6466                 :            : 
    6467         [ #  # ]:          0 :         if( rHyphenatorPos > nRetVal )
    6468                 :          0 :             rHyphenatorPos = nRetVal;
    6469                 :            :     }
    6470                 :            : 
    6471         [ #  # ]:          0 :     pSalLayout->Release();
    6472                 :          0 :     return nRetVal;
    6473                 :            : }
    6474                 :            : 
    6475                 :            : // -----------------------------------------------------------------------
    6476                 :            : 
    6477                 :       8738 : void OutputDevice::ImplDrawText( OutputDevice& rTargetDevice, const Rectangle& rRect,
    6478                 :            :                                  const String& rOrigStr, sal_uInt16 nStyle,
    6479                 :            :                                  MetricVector* pVector, String* pDisplayText,
    6480                 :            :                                  ::vcl::ITextLayout& _rLayout )
    6481                 :            : {
    6482                 :       8738 :     Color aOldTextColor;
    6483                 :       8738 :     Color aOldTextFillColor;
    6484                 :       8738 :     sal_Bool  bRestoreFillColor = false;
    6485 [ +  - ][ +  + ]:       8738 :     if ( (nStyle & TEXT_DRAW_DISABLE) && ! pVector )
    6486                 :            :     {
    6487                 :       1315 :         sal_Bool  bHighContrastBlack = sal_False;
    6488                 :       1315 :         sal_Bool  bHighContrastWhite = sal_False;
    6489                 :       1315 :         const StyleSettings& rStyleSettings( rTargetDevice.GetSettings().GetStyleSettings() );
    6490         [ -  + ]:       1315 :         if( rStyleSettings.GetHighContrastMode() )
    6491                 :            :         {
    6492                 :          0 :             Color aCol;
    6493         [ #  # ]:          0 :             if( rTargetDevice.IsBackground() )
    6494         [ #  # ]:          0 :                 aCol = rTargetDevice.GetBackground().GetColor();
    6495                 :            :             else
    6496                 :            :                 // best guess is the face color here
    6497                 :            :                 // but it may be totally wrong. the background color
    6498                 :            :                 // was typically already reset
    6499                 :          0 :                 aCol = rStyleSettings.GetFaceColor();
    6500                 :            : 
    6501         [ #  # ]:          0 :             bHighContrastBlack = aCol.IsDark();
    6502         [ #  # ]:          0 :             bHighContrastWhite = aCol.IsBright();
    6503                 :            :         }
    6504                 :            : 
    6505                 :       1315 :         aOldTextColor = rTargetDevice.GetTextColor();
    6506 [ -  + ][ +  - ]:       1315 :         if ( rTargetDevice.IsTextFillColor() )
    6507                 :            :         {
    6508                 :          0 :             bRestoreFillColor = sal_True;
    6509         [ #  # ]:          0 :             aOldTextFillColor = rTargetDevice.GetTextFillColor();
    6510                 :            :         }
    6511         [ -  + ]:       1315 :         if( bHighContrastBlack )
    6512         [ #  # ]:          0 :             rTargetDevice.SetTextColor( COL_GREEN );
    6513         [ -  + ]:       1315 :         else if( bHighContrastWhite )
    6514         [ #  # ]:          0 :             rTargetDevice.SetTextColor( COL_LIGHTGREEN );
    6515                 :            :         else
    6516                 :            :         {
    6517                 :            :             // draw disabled text always without shadow
    6518                 :            :             // as it fits better with native look
    6519                 :            :             /*
    6520                 :            :             SetTextColor( GetSettings().GetStyleSettings().GetLightColor() );
    6521                 :            :             Rectangle aRect = rRect;
    6522                 :            :             aRect.Move( 1, 1 );
    6523                 :            :             DrawText( aRect, rOrigStr, nStyle & ~TEXT_DRAW_DISABLE );
    6524                 :            :             */
    6525         [ +  - ]:       1315 :             rTargetDevice.SetTextColor( rTargetDevice.GetSettings().GetStyleSettings().GetDisableColor() );
    6526                 :            :         }
    6527                 :            :     }
    6528                 :            : 
    6529         [ +  - ]:       8738 :     long        nWidth          = rRect.GetWidth();
    6530         [ +  - ]:       8738 :     long        nHeight         = rRect.GetHeight();
    6531                 :            : 
    6532 [ +  + ][ -  + ]:       8738 :     if ( ((nWidth <= 0) || (nHeight <= 0)) && (nStyle & TEXT_DRAW_CLIP) )
                 [ +  - ]
    6533                 :       8738 :         return;
    6534                 :            : 
    6535                 :       8738 :     Point       aPos            = rRect.TopLeft();
    6536                 :            : 
    6537         [ +  - ]:       8738 :     long        nTextHeight     = rTargetDevice.GetTextHeight();
    6538         [ +  - ]:       8738 :     TextAlign   eAlign          = rTargetDevice.GetTextAlign();
    6539                 :       8738 :     xub_StrLen  nMnemonicPos    = STRING_NOTFOUND;
    6540                 :            : 
    6541         [ +  - ]:       8738 :     String aStr = rOrigStr;
    6542         [ +  + ]:       8738 :     if ( nStyle & TEXT_DRAW_MNEMONIC )
    6543 [ +  - ][ +  - ]:       1753 :         aStr = GetNonMnemonicString( aStr, nMnemonicPos );
                 [ +  - ]
    6544                 :            : 
    6545 [ +  - ][ +  + ]:       8738 :     const bool bDrawMnemonics = !(rTargetDevice.GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_NOMNEMONICS) && !pVector;
    6546                 :            : 
    6547                 :            :     // Mehrzeiligen Text behandeln wir anders
    6548         [ +  + ]:       8738 :     if ( nStyle & TEXT_DRAW_MULTILINE )
    6549                 :            :     {
    6550                 :            : 
    6551         [ +  - ]:       1771 :         XubString               aLastLine;
    6552         [ +  - ]:       1771 :         ImplMultiTextLineInfo   aMultiLineInfo;
    6553                 :            :         ImplTextLineInfo*       pLineInfo;
    6554                 :            :         xub_StrLen              i;
    6555                 :            :         xub_StrLen              nLines;
    6556                 :            :         xub_StrLen              nFormatLines;
    6557                 :            : 
    6558         [ +  - ]:       1771 :         if ( nTextHeight )
    6559                 :            :         {
    6560         [ +  - ]:       1771 :             long nMaxTextWidth = ImplGetTextLines( aMultiLineInfo, nWidth, aStr, nStyle, _rLayout );
    6561                 :       1771 :             nLines = (xub_StrLen)(nHeight/nTextHeight);
    6562                 :       1771 :             nFormatLines = aMultiLineInfo.Count();
    6563         [ +  + ]:       1771 :             if ( !nLines )
    6564                 :        166 :                 nLines = 1;
    6565         [ +  + ]:       1771 :             if ( nFormatLines > nLines )
    6566                 :            :             {
    6567         [ +  - ]:          3 :                 if ( nStyle & TEXT_DRAW_ENDELLIPSIS )
    6568                 :            :                 {
    6569                 :            :                     // Letzte Zeile zusammenbauen und kuerzen
    6570                 :          3 :                     nFormatLines = nLines-1;
    6571                 :            : 
    6572                 :          3 :                     pLineInfo = aMultiLineInfo.GetLine( nFormatLines );
    6573 [ +  - ][ +  - ]:          3 :                     aLastLine = convertLineEnd(aStr.Copy(pLineInfo->GetIndex()), LINEEND_LF);
         [ +  - ][ +  - ]
                 [ +  - ]
    6574                 :            :                     // Alle LineFeed's durch Spaces ersetzen
    6575                 :          3 :                     xub_StrLen nLastLineLen = aLastLine.Len();
    6576         [ +  + ]:         39 :                     for ( i = 0; i < nLastLineLen; i++ )
    6577                 :            :                     {
    6578         [ -  + ]:         36 :                         if ( aLastLine.GetChar( i ) == _LF )
    6579         [ #  # ]:          0 :                             aLastLine.SetChar( i, ' ' );
    6580                 :            :                     }
    6581 [ +  - ][ +  - ]:          3 :                     aLastLine = ImplGetEllipsisString( rTargetDevice, aLastLine, nWidth, nStyle, _rLayout );
                 [ +  - ]
    6582                 :          3 :                     nStyle &= ~(TEXT_DRAW_VCENTER | TEXT_DRAW_BOTTOM);
    6583                 :          3 :                     nStyle |= TEXT_DRAW_TOP;
    6584                 :            :                 }
    6585                 :            :             }
    6586                 :            :             else
    6587                 :            :             {
    6588         [ +  + ]:       1768 :                 if ( nMaxTextWidth <= nWidth )
    6589                 :       1741 :                     nStyle &= ~TEXT_DRAW_CLIP;
    6590                 :            :             }
    6591                 :            : 
    6592                 :            :             // Muss in der Hoehe geclippt werden?
    6593         [ +  + ]:       1771 :             if ( nFormatLines*nTextHeight > nHeight )
    6594                 :        163 :                 nStyle |= TEXT_DRAW_CLIP;
    6595                 :            : 
    6596                 :            :             // Clipping setzen
    6597         [ +  + ]:       1771 :             if ( nStyle & TEXT_DRAW_CLIP )
    6598                 :            :             {
    6599         [ +  - ]:        163 :                 rTargetDevice.Push( PUSH_CLIPREGION );
    6600         [ +  - ]:        163 :                 rTargetDevice.IntersectClipRegion( rRect );
    6601                 :            :             }
    6602                 :            : 
    6603                 :            :             // Vertikales Alignment
    6604         [ -  + ]:       1771 :             if ( nStyle & TEXT_DRAW_BOTTOM )
    6605                 :          0 :                 aPos.Y() += nHeight-(nFormatLines*nTextHeight);
    6606         [ +  + ]:       1771 :             else if ( nStyle & TEXT_DRAW_VCENTER )
    6607                 :       1522 :                 aPos.Y() += (nHeight-(nFormatLines*nTextHeight))/2;
    6608                 :            : 
    6609                 :            :             // Font Alignment
    6610         [ -  + ]:       1771 :             if ( eAlign == ALIGN_BOTTOM )
    6611                 :          0 :                 aPos.Y() += nTextHeight;
    6612         [ -  + ]:       1771 :             else if ( eAlign == ALIGN_BASELINE )
    6613 [ #  # ][ #  # ]:          0 :                 aPos.Y() += rTargetDevice.GetFontMetric().GetAscent();
                 [ #  # ]
    6614                 :            : 
    6615                 :            :             // Alle Zeilen ausgeben, bis auf die letzte
    6616         [ +  + ]:       3541 :             for ( i = 0; i < nFormatLines; i++ )
    6617                 :            :             {
    6618                 :       1770 :                 pLineInfo = aMultiLineInfo.GetLine( i );
    6619         [ -  + ]:       1770 :                 if ( nStyle & TEXT_DRAW_RIGHT )
    6620                 :          0 :                     aPos.X() += nWidth-pLineInfo->GetWidth();
    6621         [ +  + ]:       1770 :                 else if ( nStyle & TEXT_DRAW_CENTER )
    6622                 :        489 :                     aPos.X() += (nWidth-pLineInfo->GetWidth())/2;
    6623                 :       1770 :                 xub_StrLen nIndex   = pLineInfo->GetIndex();
    6624                 :       1770 :                 xub_StrLen nLineLen = pLineInfo->GetLen();
    6625         [ +  - ]:       1770 :                 _rLayout.DrawText( aPos, aStr, nIndex, nLineLen, pVector, pDisplayText );
    6626         [ +  + ]:       1770 :                 if ( bDrawMnemonics )
    6627                 :            :                 {
    6628 [ +  - ][ +  + ]:       1768 :                     if ( (nMnemonicPos >= nIndex) && (nMnemonicPos < nIndex+nLineLen) )
    6629                 :            :                     {
    6630                 :            :                         long        nMnemonicX;
    6631                 :            :                         long        nMnemonicY;
    6632                 :            :                         long        nMnemonicWidth;
    6633                 :            : 
    6634                 :         16 :                         sal_Int32* pCaretXArray = (sal_Int32*) alloca( 2 * sizeof(sal_Int32) * nLineLen );
    6635                 :            :                         /*sal_Bool bRet =*/ _rLayout.GetCaretPositions( aStr, pCaretXArray,
    6636         [ +  - ]:         16 :                                                 nIndex, nLineLen );
    6637                 :         16 :                         long lc_x1 = pCaretXArray[2*(nMnemonicPos - nIndex)];
    6638                 :         16 :                         long lc_x2 = pCaretXArray[2*(nMnemonicPos - nIndex)+1];
    6639         [ +  - ]:         16 :                         nMnemonicWidth = rTargetDevice.ImplLogicWidthToDevicePixel( ::abs((int)(lc_x1 - lc_x2)) );
    6640                 :            : 
    6641         [ +  - ]:         16 :                         Point       aTempPos = rTargetDevice.LogicToPixel( aPos );
    6642         [ +  - ]:         16 :                         nMnemonicX = rTargetDevice.GetOutOffXPixel() + aTempPos.X() + rTargetDevice.ImplLogicWidthToDevicePixel( Min( lc_x1, lc_x2 ) );
    6643 [ +  - ][ +  - ]:         16 :                         nMnemonicY = rTargetDevice.GetOutOffYPixel() + aTempPos.Y() + rTargetDevice.ImplLogicWidthToDevicePixel( rTargetDevice.GetFontMetric().GetAscent() );
         [ +  - ][ +  - ]
    6644         [ +  - ]:         16 :                         rTargetDevice.ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
    6645                 :            :                     }
    6646                 :            :                 }
    6647                 :       1770 :                 aPos.Y() += nTextHeight;
    6648                 :       1770 :                 aPos.X() = rRect.Left();
    6649                 :            :             }
    6650                 :            : 
    6651                 :            : 
    6652                 :            :             // Gibt es noch eine letzte Zeile, dann diese linksbuendig ausgeben,
    6653                 :            :             // da die Zeile gekuerzt wurde
    6654         [ +  + ]:       1771 :             if ( aLastLine.Len() )
    6655         [ +  - ]:          3 :                 _rLayout.DrawText( aPos, aLastLine, 0, STRING_LEN, pVector, pDisplayText );
    6656                 :            : 
    6657                 :            :             // Clipping zuruecksetzen
    6658         [ +  + ]:       1771 :             if ( nStyle & TEXT_DRAW_CLIP )
    6659         [ +  - ]:        163 :                 rTargetDevice.Pop();
    6660         [ +  - ]:       1771 :         }
    6661                 :            :     }
    6662                 :            :     else
    6663                 :            :     {
    6664         [ +  - ]:       6967 :         long nTextWidth = _rLayout.GetTextWidth( aStr, 0, STRING_LEN );
    6665                 :            : 
    6666                 :            :         // Evt. Text kuerzen
    6667         [ +  + ]:       6967 :         if ( nTextWidth > nWidth )
    6668                 :            :         {
    6669         [ -  + ]:        173 :             if ( nStyle & TEXT_DRAW_ELLIPSIS )
    6670                 :            :             {
    6671 [ #  # ][ #  # ]:          0 :                 aStr = ImplGetEllipsisString( rTargetDevice, aStr, nWidth, nStyle, _rLayout );
                 [ #  # ]
    6672                 :          0 :                 nStyle &= ~(TEXT_DRAW_CENTER | TEXT_DRAW_RIGHT);
    6673                 :          0 :                 nStyle |= TEXT_DRAW_LEFT;
    6674         [ #  # ]:          0 :                 nTextWidth = _rLayout.GetTextWidth( aStr, 0, aStr.Len() );
    6675                 :            :             }
    6676                 :            :         }
    6677                 :            :         else
    6678                 :            :         {
    6679         [ +  - ]:       6794 :             if ( nTextHeight <= nHeight )
    6680                 :       6794 :                 nStyle &= ~TEXT_DRAW_CLIP;
    6681                 :            :         }
    6682                 :            : 
    6683                 :            :         // horizontal text alignment
    6684         [ +  + ]:       6967 :         if ( nStyle & TEXT_DRAW_RIGHT )
    6685                 :        677 :             aPos.X() += nWidth-nTextWidth;
    6686         [ +  + ]:       6290 :         else if ( nStyle & TEXT_DRAW_CENTER )
    6687                 :        100 :             aPos.X() += (nWidth-nTextWidth)/2;
    6688                 :            : 
    6689                 :            :         // vertical font alignment
    6690         [ -  + ]:       6967 :         if ( eAlign == ALIGN_BOTTOM )
    6691                 :          0 :             aPos.Y() += nTextHeight;
    6692         [ -  + ]:       6967 :         else if ( eAlign == ALIGN_BASELINE )
    6693 [ #  # ][ #  # ]:          0 :             aPos.Y() += rTargetDevice.GetFontMetric().GetAscent();
                 [ #  # ]
    6694                 :            : 
    6695         [ -  + ]:       6967 :         if ( nStyle & TEXT_DRAW_BOTTOM )
    6696                 :          0 :             aPos.Y() += nHeight-nTextHeight;
    6697         [ +  + ]:       6967 :         else if ( nStyle & TEXT_DRAW_VCENTER )
    6698                 :       3246 :             aPos.Y() += (nHeight-nTextHeight)/2;
    6699                 :            : 
    6700                 :       6967 :         long        nMnemonicX = 0;
    6701                 :       6967 :         long        nMnemonicY = 0;
    6702                 :       6967 :         long        nMnemonicWidth = 0;
    6703         [ -  + ]:       6967 :         if ( nMnemonicPos != STRING_NOTFOUND )
    6704                 :            :         {
    6705                 :          0 :             sal_Int32* pCaretXArray = (sal_Int32*) alloca( 2 * sizeof(sal_Int32) * aStr.Len() );
    6706         [ #  # ]:          0 :             /*sal_Bool bRet =*/ _rLayout.GetCaretPositions( aStr, pCaretXArray, 0, aStr.Len() );
    6707                 :          0 :             long lc_x1 = pCaretXArray[2*(nMnemonicPos)];
    6708                 :          0 :             long lc_x2 = pCaretXArray[2*(nMnemonicPos)+1];
    6709         [ #  # ]:          0 :             nMnemonicWidth = rTargetDevice.ImplLogicWidthToDevicePixel( ::abs((int)(lc_x1 - lc_x2)) );
    6710                 :            : 
    6711         [ #  # ]:          0 :             Point aTempPos = rTargetDevice.LogicToPixel( aPos );
    6712         [ #  # ]:          0 :             nMnemonicX = rTargetDevice.GetOutOffXPixel() + aTempPos.X() + rTargetDevice.ImplLogicWidthToDevicePixel( Min(lc_x1, lc_x2) );
    6713 [ #  # ][ #  # ]:          0 :             nMnemonicY = rTargetDevice.GetOutOffYPixel() + aTempPos.Y() + rTargetDevice.ImplLogicWidthToDevicePixel( rTargetDevice.GetFontMetric().GetAscent() );
         [ #  # ][ #  # ]
    6714                 :            :         }
    6715                 :            : 
    6716         [ -  + ]:       6967 :         if ( nStyle & TEXT_DRAW_CLIP )
    6717                 :            :         {
    6718         [ #  # ]:          0 :             rTargetDevice.Push( PUSH_CLIPREGION );
    6719         [ #  # ]:          0 :             rTargetDevice.IntersectClipRegion( rRect );
    6720         [ #  # ]:          0 :             _rLayout.DrawText( aPos, aStr, 0, STRING_LEN, pVector, pDisplayText );
    6721         [ #  # ]:          0 :             if ( bDrawMnemonics )
    6722                 :            :             {
    6723         [ #  # ]:          0 :                 if ( nMnemonicPos != STRING_NOTFOUND )
    6724         [ #  # ]:          0 :                     rTargetDevice.ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
    6725                 :            :             }
    6726         [ #  # ]:          0 :             rTargetDevice.Pop();
    6727                 :            :         }
    6728                 :            :         else
    6729                 :            :         {
    6730         [ +  - ]:       6967 :             _rLayout.DrawText( aPos, aStr, 0, STRING_LEN, pVector, pDisplayText );
    6731         [ +  - ]:       6967 :             if ( bDrawMnemonics )
    6732                 :            :             {
    6733         [ -  + ]:       6967 :                 if ( nMnemonicPos != STRING_NOTFOUND )
    6734         [ #  # ]:          0 :                     rTargetDevice.ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
    6735                 :            :             }
    6736                 :            :         }
    6737                 :            :     }
    6738                 :            : 
    6739 [ +  + ][ +  - ]:       8738 :     if ( nStyle & TEXT_DRAW_DISABLE && !pVector )
    6740                 :            :     {
    6741         [ +  - ]:       1315 :         rTargetDevice.SetTextColor( aOldTextColor );
    6742         [ -  + ]:       1315 :         if ( bRestoreFillColor )
    6743         [ #  # ]:          0 :             rTargetDevice.SetTextFillColor( aOldTextFillColor );
    6744         [ +  - ]:       8738 :     }
    6745                 :            : }
    6746                 :            : 
    6747                 :            : // -----------------------------------------------------------------------
    6748                 :            : 
    6749                 :          0 : void OutputDevice::AddTextRectActions( const Rectangle& rRect,
    6750                 :            :                                        const String&    rOrigStr,
    6751                 :            :                                        sal_uInt16           nStyle,
    6752                 :            :                                        GDIMetaFile&     rMtf )
    6753                 :            : {
    6754                 :            :     OSL_TRACE( "OutputDevice::AddTextRectActions( const Rectangle& )" );
    6755                 :            :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    6756                 :            : 
    6757 [ #  # ][ #  # ]:          0 :     if ( !rOrigStr.Len() || rRect.IsEmpty() )
         [ #  # ][ #  # ]
    6758                 :            :         return;
    6759                 :            : 
    6760                 :            :     // we need a graphics
    6761 [ #  # ][ #  # ]:          0 :     if( !mpGraphics && !ImplGetGraphics() )
         [ #  # ][ #  # ]
    6762                 :            :         return;
    6763         [ #  # ]:          0 :     if( mbInitClipRegion )
    6764         [ #  # ]:          0 :         ImplInitClipRegion();
    6765                 :            : 
    6766                 :            :     // temporarily swap in passed mtf for action generation, and
    6767                 :            :     // disable output generation.
    6768                 :          0 :     const sal_Bool bOutputEnabled( IsOutputEnabled() );
    6769                 :          0 :     GDIMetaFile* pMtf = mpMetaFile;
    6770                 :            : 
    6771                 :          0 :     mpMetaFile = &rMtf;
    6772         [ #  # ]:          0 :     EnableOutput( sal_False );
    6773                 :            : 
    6774                 :            :     // #i47157# Factored out to ImplDrawTextRect(), to be shared
    6775                 :            :     // between us and DrawText()
    6776                 :          0 :     DefaultTextLayout aLayout( *this );
    6777         [ #  # ]:          0 :     ImplDrawText( *this, rRect, rOrigStr, nStyle, NULL, NULL, aLayout );
    6778                 :            : 
    6779                 :            :     // and restore again
    6780         [ #  # ]:          0 :     EnableOutput( bOutputEnabled );
    6781         [ #  # ]:          0 :     mpMetaFile = pMtf;
    6782                 :            : }
    6783                 :            : 
    6784                 :            : // -----------------------------------------------------------------------
    6785                 :            : 
    6786                 :      15279 : void OutputDevice::DrawText( const Rectangle& rRect, const String& rOrigStr, sal_uInt16 nStyle,
    6787                 :            :                              MetricVector* pVector, String* pDisplayText,
    6788                 :            :                              ::vcl::ITextLayout* _pTextLayout )
    6789                 :            : {
    6790 [ -  + ][ #  # ]:      15279 :     if( mpOutDevData && mpOutDevData->mpRecordLayout )
    6791                 :            :     {
    6792                 :          0 :         pVector = &mpOutDevData->mpRecordLayout->m_aUnicodeBoundRects;
    6793                 :          0 :         pDisplayText = &mpOutDevData->mpRecordLayout->m_aDisplayText;
    6794                 :            :     }
    6795                 :            : 
    6796                 :            :     OSL_TRACE( "OutputDevice::DrawText( const Rectangle& )" );
    6797                 :            :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    6798                 :            : 
    6799 [ +  + ][ +  - ]:      15279 :     bool bDecomposeTextRectAction = ( _pTextLayout != NULL ) && _pTextLayout->DecomposeTextRectAction();
                 [ +  - ]
    6800 [ +  + ][ +  + ]:      15279 :     if ( mpMetaFile && !bDecomposeTextRectAction )
    6801 [ +  - ][ +  - ]:       1421 :         mpMetaFile->AddAction( new MetaTextRectAction( rRect, rOrigStr, nStyle ) );
         [ +  - ][ +  - ]
    6802                 :            : 
    6803 [ +  + ][ +  - ]:      15279 :     if ( ( !IsDeviceOutputNecessary() && !pVector && !bDecomposeTextRectAction ) || !rOrigStr.Len() || rRect.IsEmpty() )
         [ -  + ][ +  + ]
         [ +  - ][ -  + ]
                 [ +  + ]
    6804                 :            :         return;
    6805                 :            : 
    6806                 :            :     // we need a graphics
    6807 [ +  + ][ +  - ]:       9649 :     if( !mpGraphics && !ImplGetGraphics() )
         [ -  + ][ +  - ]
    6808                 :            :         return;
    6809         [ +  + ]:       9649 :     if( mbInitClipRegion )
    6810         [ +  - ]:        583 :         ImplInitClipRegion();
    6811 [ +  + ][ +  + ]:       9649 :     if( mbOutputClipped && !bDecomposeTextRectAction )
    6812                 :            :         return;
    6813                 :            : 
    6814                 :            :     // temporarily disable mtf action generation (ImplDrawText _does_
    6815                 :            :     // create META_TEXT_ACTIONs otherwise)
    6816                 :       8738 :     GDIMetaFile* pMtf = mpMetaFile;
    6817         [ +  + ]:       8738 :     if ( !bDecomposeTextRectAction )
    6818                 :       8335 :         mpMetaFile = NULL;
    6819                 :            : 
    6820                 :            :     // #i47157# Factored out to ImplDrawText(), to be used also
    6821                 :            :     // from AddTextRectActions()
    6822                 :       8738 :     DefaultTextLayout aDefaultLayout( *this );
    6823 [ +  - ][ +  + ]:       8738 :     ImplDrawText( *this, rRect, rOrigStr, nStyle, pVector, pDisplayText, _pTextLayout ? *_pTextLayout : aDefaultLayout );
    6824                 :            : 
    6825                 :            :     // and enable again
    6826                 :       8738 :     mpMetaFile = pMtf;
    6827                 :            : 
    6828         [ +  + ]:       8738 :     if( mpAlphaVDev )
    6829 [ +  - ][ +  - ]:      15279 :         mpAlphaVDev->DrawText( rRect, rOrigStr, nStyle, pVector, pDisplayText );
    6830                 :            : }
    6831                 :            : 
    6832                 :            : // -----------------------------------------------------------------------
    6833                 :            : 
    6834                 :       2383 : Rectangle OutputDevice::GetTextRect( const Rectangle& rRect,
    6835                 :            :                                      const XubString& rStr, sal_uInt16 nStyle,
    6836                 :            :                                      TextRectInfo* pInfo,
    6837                 :            :                                      const ::vcl::ITextLayout* _pTextLayout ) const
    6838                 :            : {
    6839                 :            :     OSL_TRACE( "OutputDevice::GetTextRect()" );
    6840                 :            :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    6841                 :            : 
    6842                 :       2383 :     Rectangle           aRect = rRect;
    6843                 :            :     xub_StrLen          nLines;
    6844         [ +  - ]:       2383 :     long                nWidth = rRect.GetWidth();
    6845                 :            :     long                nMaxWidth;
    6846         [ +  - ]:       2383 :     long                nTextHeight = GetTextHeight();
    6847                 :            : 
    6848         [ +  - ]:       2383 :     String aStr = rStr;
    6849         [ +  + ]:       2383 :     if ( nStyle & TEXT_DRAW_MNEMONIC )
    6850 [ +  - ][ +  - ]:       1406 :         aStr = GetNonMnemonicString( aStr );
                 [ +  - ]
    6851                 :            : 
    6852         [ +  + ]:       2383 :     if ( nStyle & TEXT_DRAW_MULTILINE )
    6853                 :            :     {
    6854         [ +  - ]:        863 :         ImplMultiTextLineInfo   aMultiLineInfo;
    6855                 :            :         ImplTextLineInfo*       pLineInfo;
    6856                 :            :         xub_StrLen              nFormatLines;
    6857                 :            :         xub_StrLen              i;
    6858                 :            : 
    6859                 :        863 :         nMaxWidth = 0;
    6860                 :        863 :         DefaultTextLayout aDefaultLayout( *const_cast< OutputDevice* >( this ) );
    6861 [ +  - ][ +  - ]:        863 :         ImplGetTextLines( aMultiLineInfo, nWidth, aStr, nStyle, _pTextLayout ? *_pTextLayout : aDefaultLayout );
    6862                 :        863 :         nFormatLines = aMultiLineInfo.Count();
    6863         [ -  + ]:        863 :         if ( !nTextHeight )
    6864                 :          0 :             nTextHeight = 1;
    6865         [ +  - ]:        863 :         nLines = (sal_uInt16)(aRect.GetHeight()/nTextHeight);
    6866         [ -  + ]:        863 :         if ( pInfo )
    6867                 :          0 :             pInfo->mnLineCount = nFormatLines;
    6868         [ +  + ]:        863 :         if ( !nLines )
    6869                 :          8 :             nLines = 1;
    6870         [ +  - ]:        863 :         if ( nFormatLines <= nLines )
    6871                 :        863 :             nLines = nFormatLines;
    6872                 :            :         else
    6873                 :            :         {
    6874         [ #  # ]:          0 :             if ( !(nStyle & TEXT_DRAW_ENDELLIPSIS) )
    6875                 :          0 :                 nLines = nFormatLines;
    6876                 :            :             else
    6877                 :            :             {
    6878         [ #  # ]:          0 :                 if ( pInfo )
    6879                 :          0 :                     pInfo->mbEllipsis = sal_True;
    6880                 :          0 :                 nMaxWidth = nWidth;
    6881                 :            :             }
    6882                 :            :         }
    6883         [ -  + ]:        863 :         if ( pInfo )
    6884                 :            :         {
    6885                 :          0 :             sal_Bool bMaxWidth = nMaxWidth == 0;
    6886                 :          0 :             pInfo->mnMaxWidth = 0;
    6887         [ #  # ]:          0 :             for ( i = 0; i < nLines; i++ )
    6888                 :            :             {
    6889                 :          0 :                 pLineInfo = aMultiLineInfo.GetLine( i );
    6890 [ #  # ][ #  # ]:          0 :                 if ( bMaxWidth && (pLineInfo->GetWidth() > nMaxWidth) )
                 [ #  # ]
    6891                 :          0 :                     nMaxWidth = pLineInfo->GetWidth();
    6892         [ #  # ]:          0 :                 if ( pLineInfo->GetWidth() > pInfo->mnMaxWidth )
    6893                 :          0 :                     pInfo->mnMaxWidth = pLineInfo->GetWidth();
    6894                 :            :             }
    6895                 :            :         }
    6896         [ +  - ]:        863 :         else if ( !nMaxWidth )
    6897                 :            :         {
    6898         [ +  + ]:       1491 :             for ( i = 0; i < nLines; i++ )
    6899                 :            :             {
    6900                 :        628 :                 pLineInfo = aMultiLineInfo.GetLine( i );
    6901         [ +  + ]:        628 :                 if ( pLineInfo->GetWidth() > nMaxWidth )
    6902                 :        626 :                     nMaxWidth = pLineInfo->GetWidth();
    6903                 :            :             }
    6904         [ +  - ]:        863 :         }
    6905                 :            :     }
    6906                 :            :     else
    6907                 :            :     {
    6908                 :       1520 :         nLines      = 1;
    6909 [ -  + ][ #  # ]:       1520 :         nMaxWidth   = _pTextLayout ? _pTextLayout->GetTextWidth( aStr, 0, aStr.Len() ) : GetTextWidth( aStr );
                 [ +  - ]
    6910                 :            : 
    6911         [ -  + ]:       1520 :         if ( pInfo )
    6912                 :            :         {
    6913                 :          0 :             pInfo->mnLineCount  = 1;
    6914                 :          0 :             pInfo->mnMaxWidth   = nMaxWidth;
    6915                 :            :         }
    6916                 :            : 
    6917 [ +  + ][ -  + ]:       1520 :         if ( (nMaxWidth > nWidth) && (nStyle & TEXT_DRAW_ELLIPSIS) )
    6918                 :            :         {
    6919         [ #  # ]:          0 :             if ( pInfo )
    6920                 :          0 :                 pInfo->mbEllipsis = sal_True;
    6921                 :          0 :             nMaxWidth = nWidth;
    6922                 :            :         }
    6923                 :            :     }
    6924                 :            : 
    6925         [ -  + ]:       2383 :     if ( nStyle & TEXT_DRAW_RIGHT )
    6926                 :          0 :         aRect.Left() = aRect.Right()-nMaxWidth+1;
    6927         [ +  + ]:       2383 :     else if ( nStyle & TEXT_DRAW_CENTER )
    6928                 :            :     {
    6929                 :        243 :         aRect.Left() += (nWidth-nMaxWidth)/2;
    6930                 :        243 :         aRect.Right() = aRect.Left()+nMaxWidth-1;
    6931                 :            :     }
    6932                 :            :     else
    6933                 :       2140 :         aRect.Right() = aRect.Left()+nMaxWidth-1;
    6934                 :            : 
    6935         [ -  + ]:       2383 :     if ( nStyle & TEXT_DRAW_BOTTOM )
    6936                 :          0 :         aRect.Top() = aRect.Bottom()-(nTextHeight*nLines)+1;
    6937         [ +  + ]:       2383 :     else if ( nStyle & TEXT_DRAW_VCENTER )
    6938                 :            :     {
    6939         [ +  - ]:        885 :         aRect.Top()   += (aRect.GetHeight()-(nTextHeight*nLines))/2;
    6940                 :        885 :         aRect.Bottom() = aRect.Top()+(nTextHeight*nLines)-1;
    6941                 :            :     }
    6942                 :            :     else
    6943                 :       1498 :         aRect.Bottom() = aRect.Top()+(nTextHeight*nLines)-1;
    6944                 :            : 
    6945                 :       2383 :     aRect.Right()++; // #99188# get rid of rounding problems when using this rect later
    6946         [ +  - ]:       2383 :     return aRect;
    6947                 :            : }
    6948                 :            : 
    6949                 :            : // -----------------------------------------------------------------------
    6950                 :            : 
    6951                 :          0 : static sal_Bool ImplIsCharIn( xub_Unicode c, const sal_Char* pStr )
    6952                 :            : {
    6953         [ #  # ]:          0 :     while ( *pStr )
    6954                 :            :     {
    6955         [ #  # ]:          0 :         if ( *pStr == c )
    6956                 :          0 :             return sal_True;
    6957                 :          0 :         pStr++;
    6958                 :            :     }
    6959                 :            : 
    6960                 :          0 :     return sal_False;
    6961                 :            : }
    6962                 :            : 
    6963                 :            : // -----------------------------------------------------------------------
    6964                 :            : 
    6965                 :      13856 : String OutputDevice::GetEllipsisString( const String& rOrigStr, long nMaxWidth,
    6966                 :            :                                         sal_uInt16 nStyle ) const
    6967                 :            : {
    6968                 :            :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    6969                 :      13856 :     DefaultTextLayout aTextLayout( *const_cast< OutputDevice* >( this ) );
    6970 [ +  - ][ +  - ]:      13856 :     return ImplGetEllipsisString( *this, rOrigStr, nMaxWidth, nStyle, aTextLayout );
    6971                 :            : }
    6972                 :            : 
    6973                 :            : // -----------------------------------------------------------------------
    6974                 :            : 
    6975                 :      13859 : String OutputDevice::ImplGetEllipsisString( const OutputDevice& rTargetDevice, const XubString& rOrigStr, long nMaxWidth,
    6976                 :            :                                                sal_uInt16 nStyle, const ::vcl::ITextLayout& _rLayout )
    6977                 :            : {
    6978                 :            :     OSL_TRACE( "OutputDevice::ImplGetEllipsisString()" );
    6979                 :            : 
    6980                 :      13859 :     String aStr = rOrigStr;
    6981         [ +  - ]:      13859 :     xub_StrLen nIndex = _rLayout.GetTextBreak( aStr, nMaxWidth, 0, aStr.Len() );
    6982                 :            : 
    6983                 :            : 
    6984         [ +  + ]:      13859 :     if ( nIndex != STRING_LEN )
    6985                 :            :     {
    6986         [ -  + ]:          5 :         if( (nStyle & TEXT_DRAW_CENTERELLIPSIS) == TEXT_DRAW_CENTERELLIPSIS )
    6987                 :            :         {
    6988         [ #  # ]:          0 :             String aTmpStr( aStr );
    6989                 :          0 :             xub_StrLen nEraseChars = 4;
    6990 [ #  # ][ #  # ]:          0 :             while( nEraseChars < aStr.Len() && _rLayout.GetTextWidth( aTmpStr, 0, aTmpStr.Len() ) > nMaxWidth )
         [ #  # ][ #  # ]
    6991                 :            :             {
    6992         [ #  # ]:          0 :                 aTmpStr = aStr;
    6993                 :          0 :                 xub_StrLen i = (aTmpStr.Len() - nEraseChars)/2;
    6994         [ #  # ]:          0 :                 aTmpStr.Erase( i, nEraseChars++ );
    6995         [ #  # ]:          0 :                 aTmpStr.InsertAscii( "...", i );
    6996                 :            :             }
    6997 [ #  # ][ #  # ]:          0 :             aStr = aTmpStr;
    6998                 :            :         }
    6999         [ +  - ]:          5 :         else if ( nStyle & TEXT_DRAW_ENDELLIPSIS )
    7000                 :            :         {
    7001         [ +  - ]:          5 :             aStr.Erase( nIndex );
    7002         [ +  - ]:          5 :             if ( nIndex > 1 )
    7003                 :            :             {
    7004         [ +  - ]:          5 :                 aStr.AppendAscii( "..." );
    7005 [ +  - ][ +  - ]:         12 :                 while ( aStr.Len() && (_rLayout.GetTextWidth( aStr, 0, aStr.Len() ) > nMaxWidth) )
         [ +  + ][ +  + ]
    7006                 :            :                 {
    7007 [ -  + ][ #  # ]:          7 :                     if ( (nIndex > 1) || (nIndex == aStr.Len()) )
                 [ +  - ]
    7008                 :          7 :                         nIndex--;
    7009         [ +  - ]:          7 :                     aStr.Erase( nIndex, 1 );
    7010                 :            :                 }
    7011                 :            :             }
    7012                 :            : 
    7013 [ -  + ][ #  # ]:          5 :             if ( !aStr.Len() && (nStyle & TEXT_DRAW_CLIP) )
                 [ -  + ]
    7014         [ #  # ]:          0 :                 aStr += rOrigStr.GetChar( 0 );
    7015                 :            :         }
    7016         [ #  # ]:          0 :         else if ( nStyle & TEXT_DRAW_PATHELLIPSIS )
    7017                 :            :         {
    7018         [ #  # ]:          0 :             rtl::OUString aPath( rOrigStr );
    7019                 :          0 :             rtl::OUString aAbbreviatedPath;
    7020         [ #  # ]:          0 :             osl_abbreviateSystemPath( aPath.pData, &aAbbreviatedPath.pData, nIndex, NULL );
    7021         [ #  # ]:          0 :             aStr = aAbbreviatedPath;
    7022                 :            :         }
    7023         [ #  # ]:          0 :         else if ( nStyle & TEXT_DRAW_NEWSELLIPSIS )
    7024                 :            :         {
    7025                 :            :             static sal_Char const   pSepChars[] = ".";
    7026                 :            :             // Letztes Teilstueck ermitteln
    7027                 :          0 :             xub_StrLen nLastContent = aStr.Len();
    7028         [ #  # ]:          0 :             while ( nLastContent )
    7029                 :            :             {
    7030                 :          0 :                 nLastContent--;
    7031         [ #  # ]:          0 :                 if ( ImplIsCharIn( aStr.GetChar( nLastContent ), pSepChars ) )
    7032                 :          0 :                     break;
    7033                 :            :             }
    7034   [ #  #  #  # ]:          0 :             while ( nLastContent &&
                 [ #  # ]
    7035                 :          0 :                     ImplIsCharIn( aStr.GetChar( nLastContent-1 ), pSepChars ) )
    7036                 :          0 :                 nLastContent--;
    7037                 :            : 
    7038         [ #  # ]:          0 :             XubString aLastStr( aStr, nLastContent, aStr.Len() );
    7039         [ #  # ]:          0 :             XubString aTempLastStr1( RTL_CONSTASCII_USTRINGPARAM( "..." ) );
    7040         [ #  # ]:          0 :             aTempLastStr1 += aLastStr;
    7041 [ #  # ][ #  # ]:          0 :             if ( _rLayout.GetTextWidth( aTempLastStr1, 0, aTempLastStr1.Len() ) > nMaxWidth )
    7042 [ #  # ][ #  # ]:          0 :                 aStr = OutputDevice::ImplGetEllipsisString( rTargetDevice, aStr, nMaxWidth, nStyle | TEXT_DRAW_ENDELLIPSIS, _rLayout );
                 [ #  # ]
    7043                 :            :             else
    7044                 :            :             {
    7045                 :          0 :                 sal_uInt16 nFirstContent = 0;
    7046         [ #  # ]:          0 :                 while ( nFirstContent < nLastContent )
    7047                 :            :                 {
    7048                 :          0 :                     nFirstContent++;
    7049         [ #  # ]:          0 :                     if ( ImplIsCharIn( aStr.GetChar( nFirstContent ), pSepChars ) )
    7050                 :          0 :                         break;
    7051                 :            :                 }
    7052   [ #  #  #  # ]:          0 :                 while ( (nFirstContent < nLastContent) &&
                 [ #  # ]
    7053                 :          0 :                         ImplIsCharIn( aStr.GetChar( nFirstContent ), pSepChars ) )
    7054                 :          0 :                     nFirstContent++;
    7055                 :            : 
    7056         [ #  # ]:          0 :                 if ( nFirstContent >= nLastContent )
    7057 [ #  # ][ #  # ]:          0 :                     aStr = OutputDevice::ImplGetEllipsisString( rTargetDevice, aStr, nMaxWidth, nStyle | TEXT_DRAW_ENDELLIPSIS, _rLayout );
                 [ #  # ]
    7058                 :            :                 else
    7059                 :            :                 {
    7060         [ #  # ]:          0 :                     if ( nFirstContent > 4 )
    7061                 :          0 :                         nFirstContent = 4;
    7062         [ #  # ]:          0 :                     XubString aFirstStr( aStr, 0, nFirstContent );
    7063         [ #  # ]:          0 :                     aFirstStr.AppendAscii( "..." );
    7064         [ #  # ]:          0 :                     XubString aTempStr = aFirstStr;
    7065         [ #  # ]:          0 :                     aTempStr += aLastStr;
    7066 [ #  # ][ #  # ]:          0 :                     if ( _rLayout.GetTextWidth( aTempStr, 0, aTempStr.Len() ) > nMaxWidth )
    7067 [ #  # ][ #  # ]:          0 :                         aStr = OutputDevice::ImplGetEllipsisString( rTargetDevice, aStr, nMaxWidth, nStyle | TEXT_DRAW_ENDELLIPSIS, _rLayout );
                 [ #  # ]
    7068                 :            :                     else
    7069                 :            :                     {
    7070         [ #  # ]:          0 :                         do
    7071                 :            :                         {
    7072         [ #  # ]:          0 :                             aStr = aTempStr;
    7073         [ #  # ]:          0 :                             if( nLastContent > aStr.Len() )
    7074                 :          0 :                                 nLastContent = aStr.Len();
    7075         [ #  # ]:          0 :                             while ( nFirstContent < nLastContent )
    7076                 :            :                             {
    7077                 :          0 :                                 nLastContent--;
    7078         [ #  # ]:          0 :                                 if ( ImplIsCharIn( aStr.GetChar( nLastContent ), pSepChars ) )
    7079                 :          0 :                                     break;
    7080                 :            : 
    7081                 :            :                             }
    7082   [ #  #  #  # ]:          0 :                             while ( (nFirstContent < nLastContent) &&
                 [ #  # ]
    7083                 :          0 :                                     ImplIsCharIn( aStr.GetChar( nLastContent-1 ), pSepChars ) )
    7084                 :          0 :                                 nLastContent--;
    7085                 :            : 
    7086         [ #  # ]:          0 :                             if ( nFirstContent < nLastContent )
    7087                 :            :                             {
    7088         [ #  # ]:          0 :                                 XubString aTempLastStr( aStr, nLastContent, aStr.Len() );
    7089         [ #  # ]:          0 :                                 aTempStr = aFirstStr;
    7090         [ #  # ]:          0 :                                 aTempStr += aTempLastStr;
    7091 [ #  # ][ #  # ]:          0 :                                 if ( _rLayout.GetTextWidth( aTempStr, 0, aTempStr.Len() ) > nMaxWidth )
    7092 [ #  # ][ #  # ]:          0 :                                     break;
    7093                 :            :                             }
    7094                 :            :                         }
    7095                 :            :                         while ( nFirstContent < nLastContent );
    7096 [ #  # ][ #  # ]:          0 :                     }
    7097                 :            :                 }
    7098 [ #  # ][ #  # ]:          0 :             }
    7099                 :            :         }
    7100                 :            :     }
    7101                 :            : 
    7102                 :      13859 :     return aStr;
    7103                 :            : }
    7104                 :            : 
    7105                 :            : // -----------------------------------------------------------------------
    7106                 :            : 
    7107                 :      14264 : void OutputDevice::DrawCtrlText( const Point& rPos, const XubString& rStr,
    7108                 :            :                                  xub_StrLen nIndex, xub_StrLen nLen,
    7109                 :            :                                  sal_uInt16 nStyle, MetricVector* pVector, String* pDisplayText )
    7110                 :            : {
    7111                 :            :     OSL_TRACE( "OutputDevice::DrawCtrlText()" );
    7112                 :            :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    7113                 :            : 
    7114 [ +  - ][ -  + ]:      14264 :     if ( !IsDeviceOutputNecessary() || (nIndex >= rStr.Len()) )
                 [ +  - ]
    7115                 :            :         return;
    7116                 :            : 
    7117                 :            :     // better get graphics here because ImplDrawMnemonicLine() will not
    7118                 :            :     // we need a graphics
    7119 [ -  + ][ #  # ]:      14264 :     if( !mpGraphics && !ImplGetGraphics() )
         [ #  # ][ +  - ]
    7120                 :            :         return;
    7121         [ +  + ]:      14264 :     if( mbInitClipRegion )
    7122         [ +  - ]:       1712 :         ImplInitClipRegion();
    7123         [ +  - ]:      14264 :     if ( mbOutputClipped )
    7124                 :            :         return;
    7125                 :            : 
    7126         [ +  - ]:      14264 :     if( nIndex >= rStr.Len() )
    7127                 :            :         return;
    7128         [ +  - ]:      14264 :     if( (sal_uLong)nIndex+nLen >= rStr.Len() )
    7129                 :      14264 :         nLen = rStr.Len() - nIndex;
    7130                 :            : 
    7131         [ +  - ]:      14264 :     XubString   aStr = rStr;
    7132                 :      14264 :     xub_StrLen  nMnemonicPos = STRING_NOTFOUND;
    7133                 :            : 
    7134                 :      14264 :     long        nMnemonicX = 0;
    7135                 :      14264 :     long        nMnemonicY = 0;
    7136                 :      14264 :     long        nMnemonicWidth = 0;
    7137 [ +  + ][ +  - ]:      14264 :     if ( (nStyle & TEXT_DRAW_MNEMONIC) && nLen > 1 )
    7138                 :            :     {
    7139 [ +  - ][ +  - ]:      14104 :         aStr = GetNonMnemonicString( aStr, nMnemonicPos );
                 [ +  - ]
    7140         [ +  + ]:      14104 :         if ( nMnemonicPos != STRING_NOTFOUND )
    7141                 :            :         {
    7142         [ -  + ]:      13828 :             if( nMnemonicPos < nIndex )
    7143                 :          0 :                 --nIndex;
    7144         [ +  - ]:      13828 :             else if( nLen < STRING_LEN )
    7145                 :            :             {
    7146         [ +  - ]:      13828 :                 if( nMnemonicPos < (nIndex+nLen) )
    7147                 :      13828 :                     --nLen;
    7148                 :            :                 DBG_ASSERT( nMnemonicPos < (nIndex+nLen), "Mnemonic underline marker after last character" );
    7149                 :            :             }
    7150                 :      13828 :             sal_Bool bInvalidPos = sal_False;
    7151                 :            : 
    7152         [ -  + ]:      13828 :             if( nMnemonicPos >= nLen )
    7153                 :            :             {
    7154                 :            :                 // #106952#
    7155                 :            :                 // may occur in BiDi-Strings: the '~' is sometimes found behind the last char
    7156                 :            :                 // due to some strange BiDi text editors
    7157                 :            :                 // ->place the underline behind the string to indicate a failure
    7158                 :          0 :                 bInvalidPos = sal_True;
    7159                 :          0 :                 nMnemonicPos = nLen-1;
    7160                 :            :             }
    7161                 :            : 
    7162                 :      13828 :             sal_Int32* pCaretXArray = (sal_Int32*)alloca( 2 * sizeof(sal_Int32) * nLen );
    7163         [ +  - ]:      13828 :             /*sal_Bool bRet =*/ GetCaretPositions( aStr, pCaretXArray, nIndex, nLen );
    7164                 :      13828 :             long lc_x1 = pCaretXArray[ 2*(nMnemonicPos - nIndex) ];
    7165                 :      13828 :             long lc_x2 = pCaretXArray[ 2*(nMnemonicPos - nIndex)+1 ];
    7166                 :      13828 :             nMnemonicWidth = ::abs((int)(lc_x1 - lc_x2));
    7167                 :            : 
    7168 [ +  - ][ +  - ]:      13828 :             Point aTempPos( Min(lc_x1,lc_x2), GetFontMetric().GetAscent() );
                 [ +  - ]
    7169         [ -  + ]:      13828 :             if( bInvalidPos )  // #106952#, place behind the (last) character
    7170 [ #  # ][ #  # ]:          0 :                 aTempPos = Point( Max(lc_x1,lc_x2), GetFontMetric().GetAscent() );
                 [ #  # ]
    7171                 :            : 
    7172                 :      13828 :             aTempPos += rPos;
    7173         [ +  - ]:      13828 :             aTempPos = LogicToPixel( aTempPos );
    7174                 :      13828 :             nMnemonicX = mnOutOffX + aTempPos.X();
    7175                 :      13828 :             nMnemonicY = mnOutOffY + aTempPos.Y();
    7176                 :            :         }
    7177                 :            :     }
    7178                 :            : 
    7179 [ +  + ][ +  + ]:      14264 :     if ( nStyle & TEXT_DRAW_DISABLE && ! pVector )
    7180                 :            :     {
    7181                 :        158 :         Color aOldTextColor;
    7182                 :        158 :         Color aOldTextFillColor;
    7183                 :            :         sal_Bool  bRestoreFillColor;
    7184                 :        158 :         sal_Bool  bHighContrastBlack = sal_False;
    7185                 :        158 :         sal_Bool  bHighContrastWhite = sal_False;
    7186                 :        158 :         const StyleSettings& rStyleSettings( GetSettings().GetStyleSettings() );
    7187         [ -  + ]:        158 :         if( rStyleSettings.GetHighContrastMode() )
    7188                 :            :         {
    7189         [ #  # ]:          0 :             if( IsBackground() )
    7190                 :            :             {
    7191         [ #  # ]:          0 :                 Wallpaper aWall = GetBackground();
    7192         [ #  # ]:          0 :                 Color aCol = aWall.GetColor();
    7193         [ #  # ]:          0 :                 bHighContrastBlack = aCol.IsDark();
    7194 [ #  # ][ #  # ]:          0 :                 bHighContrastWhite = aCol.IsBright();
    7195                 :            :             }
    7196                 :            :         }
    7197                 :            : 
    7198                 :        158 :         aOldTextColor = GetTextColor();
    7199 [ -  + ][ +  - ]:        158 :         if ( IsTextFillColor() )
    7200                 :            :         {
    7201                 :          0 :             bRestoreFillColor = sal_True;
    7202         [ #  # ]:          0 :             aOldTextFillColor = GetTextFillColor();
    7203                 :            :         }
    7204                 :            :         else
    7205                 :        158 :             bRestoreFillColor = sal_False;
    7206                 :            : 
    7207         [ -  + ]:        158 :         if( bHighContrastBlack )
    7208         [ #  # ]:          0 :             SetTextColor( COL_GREEN );
    7209         [ -  + ]:        158 :         else if( bHighContrastWhite )
    7210         [ #  # ]:          0 :             SetTextColor( COL_LIGHTGREEN );
    7211                 :            :         else
    7212         [ +  - ]:        158 :             SetTextColor( GetSettings().GetStyleSettings().GetDisableColor() );
    7213                 :            : 
    7214         [ +  - ]:        158 :         DrawText( rPos, aStr, nIndex, nLen, pVector, pDisplayText );
    7215 [ +  - ][ +  - ]:        158 :         if ( !(GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_NOMNEMONICS) && !pVector )
                 [ +  - ]
    7216                 :            :         {
    7217         [ +  + ]:        158 :             if ( nMnemonicPos != STRING_NOTFOUND )
    7218         [ +  - ]:        148 :                 ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
    7219                 :            :         }
    7220         [ +  - ]:        158 :         SetTextColor( aOldTextColor );
    7221         [ -  + ]:        158 :         if ( bRestoreFillColor )
    7222         [ #  # ]:        158 :             SetTextFillColor( aOldTextFillColor );
    7223                 :            :     }
    7224                 :            :     else
    7225                 :            :     {
    7226         [ +  - ]:      14106 :         DrawText( rPos, aStr, nIndex, nLen, pVector, pDisplayText );
    7227 [ +  - ][ +  + ]:      14106 :         if ( !(GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_NOMNEMONICS) && !pVector )
                 [ +  + ]
    7228                 :            :         {
    7229         [ +  + ]:      14056 :             if ( nMnemonicPos != STRING_NOTFOUND )
    7230         [ +  - ]:      13630 :                 ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
    7231                 :            :         }
    7232                 :            :     }
    7233                 :            : 
    7234         [ -  + ]:      14264 :     if( mpAlphaVDev )
    7235 [ #  # ][ +  - ]:      14264 :         mpAlphaVDev->DrawCtrlText( rPos, rStr, nIndex, nLen, nStyle, pVector, pDisplayText );
    7236                 :            : }
    7237                 :            : 
    7238                 :            : // -----------------------------------------------------------------------
    7239                 :            : 
    7240                 :      15562 : long OutputDevice::GetCtrlTextWidth( const String& rStr,
    7241                 :            :                                      xub_StrLen nIndex, xub_StrLen nLen,
    7242                 :            :                                      sal_uInt16 nStyle ) const
    7243                 :            : {
    7244                 :            :     OSL_TRACE( "OutputDevice::GetCtrlTextSize()" );
    7245                 :            :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    7246                 :            : 
    7247         [ +  - ]:      15562 :     if ( nStyle & TEXT_DRAW_MNEMONIC )
    7248                 :            :     {
    7249                 :            :         xub_StrLen  nMnemonicPos;
    7250         [ +  - ]:      15562 :         XubString   aStr = GetNonMnemonicString( rStr, nMnemonicPos );
    7251         [ +  + ]:      15562 :         if ( nMnemonicPos != STRING_NOTFOUND )
    7252                 :            :         {
    7253         [ -  + ]:      11545 :             if ( nMnemonicPos < nIndex )
    7254                 :          0 :                 nIndex--;
    7255 [ -  + ][ #  # ]:      11545 :             else if ( (nLen < STRING_LEN) &&
                 [ #  # ]
    7256                 :            :                       (nMnemonicPos >= nIndex) && (nMnemonicPos < (sal_uLong)(nIndex+nLen)) )
    7257                 :          0 :                 nLen--;
    7258                 :            :         }
    7259 [ +  - ][ +  - ]:      15562 :         return GetTextWidth( aStr, nIndex, nLen );
    7260                 :            :     }
    7261                 :            :     else
    7262                 :      15562 :         return GetTextWidth( rStr, nIndex, nLen );
    7263                 :            : }
    7264                 :            : 
    7265                 :            : // -----------------------------------------------------------------------
    7266                 :            : 
    7267                 :      55819 : String OutputDevice::GetNonMnemonicString( const String& rStr, xub_StrLen& rMnemonicPos )
    7268                 :            : {
    7269                 :      55819 :     String   aStr    = rStr;
    7270                 :      55819 :     xub_StrLen  nLen    = aStr.Len();
    7271                 :      55819 :     xub_StrLen  i       = 0;
    7272                 :            : 
    7273                 :      55819 :     rMnemonicPos = STRING_NOTFOUND;
    7274         [ +  + ]:     373137 :     while ( i < nLen )
    7275                 :            :     {
    7276         [ +  + ]:     317318 :         if ( aStr.GetChar( i ) == '~' )
    7277                 :            :         {
    7278         [ +  - ]:      39549 :             if ( aStr.GetChar( i+1 ) != '~' )
    7279                 :            :             {
    7280         [ +  - ]:      39549 :                 if ( rMnemonicPos == STRING_NOTFOUND )
    7281                 :      39549 :                     rMnemonicPos = i;
    7282         [ +  - ]:      39549 :                 aStr.Erase( i, 1 );
    7283                 :      39549 :                 nLen--;
    7284                 :            :             }
    7285                 :            :             else
    7286                 :            :             {
    7287         [ #  # ]:          0 :                 aStr.Erase( i, 1 );
    7288                 :          0 :                 nLen--;
    7289                 :          0 :                 i++;
    7290                 :            :             }
    7291                 :            :         }
    7292                 :            :         else
    7293                 :     277769 :             i++;
    7294                 :            :     }
    7295                 :            : 
    7296                 :      55819 :     return aStr;
    7297                 :            : }
    7298                 :            : 
    7299                 :            : // -----------------------------------------------------------------------
    7300                 :            : 
    7301                 :     530635 : int OutputDevice::GetDevFontCount() const
    7302                 :            : {
    7303                 :            :     OSL_TRACE( "OutputDevice::GetDevFontCount()" );
    7304                 :            :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    7305                 :            : 
    7306         [ +  + ]:     530635 :     if( !mpGetDevFontList )
    7307                 :       2925 :         mpGetDevFontList = mpFontList->GetDevFontList();
    7308                 :     530635 :     return mpGetDevFontList->Count();
    7309                 :            : }
    7310                 :            : 
    7311                 :            : // -----------------------------------------------------------------------
    7312                 :            : 
    7313                 :     526410 : FontInfo OutputDevice::GetDevFont( int nDevFontIndex ) const
    7314                 :            : {
    7315                 :            :     OSL_TRACE( "OutputDevice::GetDevFont()" );
    7316                 :            :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    7317                 :            : 
    7318                 :     526410 :     FontInfo aFontInfo;
    7319                 :            : 
    7320         [ +  - ]:     526410 :     ImplInitFontList();
    7321                 :            : 
    7322         [ +  - ]:     526410 :     int nCount = GetDevFontCount();
    7323         [ +  - ]:     526410 :     if( nDevFontIndex < nCount )
    7324                 :            :     {
    7325         [ +  - ]:     526410 :         const PhysicalFontFace& rData = *mpGetDevFontList->Get( nDevFontIndex );
    7326 [ +  - ][ +  - ]:     526410 :         aFontInfo.SetName( rData.maName );
    7327         [ +  - ]:     526410 :         aFontInfo.SetStyleName( rData.maStyleName );
    7328 [ +  + ][ +  - ]:     526410 :         aFontInfo.SetCharSet( rData.mbSymbolFlag ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UNICODE );
    7329         [ +  - ]:     526410 :         aFontInfo.SetFamily( rData.meFamily );
    7330         [ +  - ]:     526410 :         aFontInfo.SetPitch( rData.mePitch );
    7331         [ +  - ]:     526410 :         aFontInfo.SetWeight( rData.meWeight );
    7332         [ +  - ]:     526410 :         aFontInfo.SetItalic( rData.meItalic );
    7333         [ +  - ]:     526410 :         aFontInfo.SetWidthType( rData.meWidthType );
    7334         [ +  - ]:     526410 :         if( rData.IsScalable() )
    7335                 :     526410 :             aFontInfo.mpImplMetric->mnMiscFlags |= ImplFontMetric::SCALABLE_FLAG;
    7336         [ +  + ]:     526410 :         if( rData.mbDevice )
    7337                 :       1798 :             aFontInfo.mpImplMetric->mnMiscFlags |= ImplFontMetric::DEVICE_FLAG;
    7338                 :            :     }
    7339                 :            : 
    7340                 :     526410 :     return aFontInfo;
    7341                 :            : }
    7342                 :            : 
    7343                 :            : // -----------------------------------------------------------------------
    7344                 :            : 
    7345                 :          0 : sal_Bool OutputDevice::AddTempDevFont( const String& rFileURL, const String& rFontName )
    7346                 :            : {
    7347                 :            :     OSL_TRACE( "OutputDevice::AddTempDevFont()" );
    7348                 :            :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    7349                 :            : 
    7350                 :          0 :     ImplInitFontList();
    7351                 :            : 
    7352 [ #  # ][ #  # ]:          0 :     if( !mpGraphics && !ImplGetGraphics() )
                 [ #  # ]
    7353                 :          0 :         return sal_False;
    7354                 :            : 
    7355 [ #  # ][ #  # ]:          0 :     bool bRC = mpGraphics->AddTempDevFont( mpFontList, rFileURL, rFontName );
    7356         [ #  # ]:          0 :     if( !bRC )
    7357                 :          0 :         return sal_False;
    7358                 :            : 
    7359         [ #  # ]:          0 :     if( mpAlphaVDev )
    7360                 :          0 :         mpAlphaVDev->AddTempDevFont( rFileURL, rFontName );
    7361                 :            : 
    7362                 :          0 :     mpFontCache->Invalidate();
    7363                 :          0 :     return sal_True;
    7364                 :            : }
    7365                 :            : 
    7366                 :            : // -----------------------------------------------------------------------
    7367                 :            : 
    7368                 :       1481 : int OutputDevice::GetDevFontSizeCount( const Font& rFont ) const
    7369                 :            : {
    7370                 :            :     OSL_TRACE( "OutputDevice::GetDevFontSizeCount()" );
    7371                 :            :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    7372                 :            : 
    7373         [ +  + ]:       1481 :     delete mpGetDevSizeList;
    7374                 :            : 
    7375                 :       1481 :     ImplInitFontList();
    7376                 :       1481 :     mpGetDevSizeList = mpFontList->GetDevSizeList( rFont.GetName() );
    7377                 :       1481 :     return mpGetDevSizeList->Count();
    7378                 :            : }
    7379                 :            : 
    7380                 :            : // -----------------------------------------------------------------------
    7381                 :            : 
    7382                 :          0 : Size OutputDevice::GetDevFontSize( const Font& rFont, int nSizeIndex ) const
    7383                 :            : {
    7384                 :            :     OSL_TRACE( "OutputDevice::GetDevFontSize()" );
    7385                 :            :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    7386                 :            : 
    7387                 :            :     // check range
    7388         [ #  # ]:          0 :     int nCount = GetDevFontSizeCount( rFont );
    7389         [ #  # ]:          0 :     if ( nSizeIndex >= nCount )
    7390                 :          0 :         return Size();
    7391                 :            : 
    7392                 :            :     // when mapping is enabled round to .5 points
    7393         [ #  # ]:          0 :     Size aSize( 0, mpGetDevSizeList->Get( nSizeIndex ) );
    7394         [ #  # ]:          0 :     if ( mbMap )
    7395                 :            :     {
    7396                 :          0 :         aSize.Height() *= 10;
    7397 [ #  # ][ #  # ]:          0 :         MapMode aMap( MAP_10TH_INCH, Point(), Fraction( 1, 72 ), Fraction( 1, 72 ) );
                 [ #  # ]
    7398         [ #  # ]:          0 :         aSize = PixelToLogic( aSize, aMap );
    7399                 :          0 :         aSize.Height() += 5;
    7400                 :          0 :         aSize.Height() /= 10;
    7401                 :          0 :         long nRound = aSize.Height() % 5;
    7402         [ #  # ]:          0 :         if ( nRound >= 3 )
    7403                 :          0 :             aSize.Height() += (5-nRound);
    7404                 :            :         else
    7405                 :          0 :             aSize.Height() -= nRound;
    7406                 :          0 :         aSize.Height() *= 10;
    7407         [ #  # ]:          0 :         aSize = LogicToPixel( aSize, aMap );
    7408         [ #  # ]:          0 :         aSize = PixelToLogic( aSize );
    7409                 :          0 :         aSize.Height() += 5;
    7410         [ #  # ]:          0 :         aSize.Height() /= 10;
    7411                 :            :     }
    7412                 :          0 :     return aSize;
    7413                 :            : }
    7414                 :            : 
    7415                 :            : // -----------------------------------------------------------------------
    7416                 :            : 
    7417                 :         45 : sal_Bool OutputDevice::IsFontAvailable( const String& rFontName ) const
    7418                 :            : {
    7419                 :            :     OSL_TRACE( "OutputDevice::IsFontAvailable()" );
    7420                 :            :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    7421                 :            : 
    7422                 :         45 :     ImplDevFontListData* pFound = mpFontList->FindFontFamily( rFontName );
    7423                 :         45 :     return (pFound != NULL);
    7424                 :            : }
    7425                 :            : 
    7426                 :            : // -----------------------------------------------------------------------
    7427                 :            : 
    7428                 :     509420 : FontMetric OutputDevice::GetFontMetric() const
    7429                 :            : {
    7430                 :            :     OSL_TRACE( "OutputDevice::GetFontMetric()" );
    7431                 :            :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    7432                 :            : 
    7433                 :     509420 :     FontMetric aMetric;
    7434 [ +  - ][ -  + ]:     509420 :     if( mbNewFont && !ImplNewFont() )
         [ -  + ][ +  + ]
    7435                 :          0 :         return aMetric;
    7436                 :            : 
    7437                 :     509420 :     ImplFontEntry*      pEntry = mpFontEntry;
    7438                 :     509420 :     ImplFontMetricData* pMetric = &(pEntry->maMetric);
    7439                 :            : 
    7440                 :            :     // prepare metric
    7441         [ +  - ]:     509420 :     aMetric.Font::operator=( maFont );
    7442                 :            : 
    7443                 :            :     // set aMetric with info from font
    7444 [ +  - ][ +  - ]:     509420 :     aMetric.SetName( maFont.GetName() );
                 [ +  - ]
    7445         [ +  - ]:     509420 :     aMetric.SetStyleName( pMetric->maStyleName );
    7446 [ +  - ][ +  - ]:     509420 :     aMetric.SetSize( PixelToLogic( Size( pMetric->mnWidth, pMetric->mnAscent+pMetric->mnDescent-pMetric->mnIntLeading ) ) );
    7447 [ +  + ][ +  - ]:     509420 :     aMetric.SetCharSet( pMetric->mbSymbolFlag ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UNICODE );
    7448         [ +  - ]:     509420 :     aMetric.SetFamily( pMetric->meFamily );
    7449         [ +  - ]:     509420 :     aMetric.SetPitch( pMetric->mePitch );
    7450         [ +  - ]:     509420 :     aMetric.SetWeight( pMetric->meWeight );
    7451         [ +  - ]:     509420 :     aMetric.SetItalic( pMetric->meItalic );
    7452         [ +  - ]:     509420 :     aMetric.SetWidthType( pMetric->meWidthType );
    7453         [ -  + ]:     509420 :     if ( pEntry->mnOwnOrientation )
    7454         [ #  # ]:          0 :         aMetric.SetOrientation( pEntry->mnOwnOrientation );
    7455                 :            :     else
    7456         [ +  - ]:     509420 :         aMetric.SetOrientation( pMetric->mnOrientation );
    7457         [ +  + ]:     509420 :     if( !pEntry->maMetric.mbKernableFont )
    7458 [ +  - ][ +  - ]:      45010 :          aMetric.SetKerning( maFont.GetKerning() & ~KERNING_FONTSPECIFIC );
    7459                 :            : 
    7460                 :            :     // set remaining metric fields
    7461                 :     509420 :     aMetric.mpImplMetric->mnMiscFlags   = 0;
    7462         [ +  + ]:     509420 :     if( pMetric->mbDevice )
    7463                 :     508823 :             aMetric.mpImplMetric->mnMiscFlags |= ImplFontMetric::DEVICE_FLAG;
    7464         [ +  - ]:     509420 :     if( pMetric->mbScalableFont )
    7465                 :     509420 :             aMetric.mpImplMetric->mnMiscFlags |= ImplFontMetric::SCALABLE_FLAG;
    7466         [ +  - ]:     509420 :     aMetric.mpImplMetric->mnAscent      = ImplDevicePixelToLogicHeight( pMetric->mnAscent+mnEmphasisAscent );
    7467         [ +  - ]:     509420 :     aMetric.mpImplMetric->mnDescent     = ImplDevicePixelToLogicHeight( pMetric->mnDescent+mnEmphasisDescent );
    7468         [ +  - ]:     509420 :     aMetric.mpImplMetric->mnIntLeading  = ImplDevicePixelToLogicHeight( pMetric->mnIntLeading+mnEmphasisAscent );
    7469         [ +  - ]:     509420 :     aMetric.mpImplMetric->mnExtLeading  = ImplDevicePixelToLogicHeight( pMetric->mnExtLeading );
    7470         [ +  - ]:     509420 :     aMetric.mpImplMetric->mnLineHeight  = ImplDevicePixelToLogicHeight( pMetric->mnAscent+pMetric->mnDescent+mnEmphasisAscent+mnEmphasisDescent );
    7471         [ +  - ]:     509420 :     aMetric.mpImplMetric->mnSlant       = ImplDevicePixelToLogicHeight( pMetric->mnSlant );
    7472                 :            : 
    7473                 :            : #ifdef UNX
    7474                 :            :     // backwards compatible line metrics after fixing #i60945#
    7475   [ +  +  -  + ]:    1003487 :     if( (meOutDevType == OUTDEV_VIRDEV)
                 [ -  + ]
    7476                 :     494067 :     &&  static_cast<const VirtualDevice*>(this)->ForceZeroExtleadBug() )
    7477                 :          0 :         aMetric.mpImplMetric->mnExtLeading = 0;
    7478                 :            : #endif
    7479                 :            : 
    7480                 :     509420 :     return aMetric;
    7481                 :            : }
    7482                 :            : 
    7483                 :            : // -----------------------------------------------------------------------
    7484                 :            : 
    7485                 :          0 : FontMetric OutputDevice::GetFontMetric( const Font& rFont ) const
    7486                 :            : {
    7487                 :            :     // select font, query metrics, select original font again
    7488         [ #  # ]:          0 :     Font aOldFont = GetFont();
    7489         [ #  # ]:          0 :     const_cast<OutputDevice*>(this)->SetFont( rFont );
    7490         [ #  # ]:          0 :     FontMetric aMetric( GetFontMetric() );
    7491         [ #  # ]:          0 :     const_cast<OutputDevice*>(this)->SetFont( aOldFont );
    7492         [ #  # ]:          0 :     return aMetric;
    7493                 :            : }
    7494                 :            : 
    7495                 :            : // -----------------------------------------------------------------------
    7496                 :            : 
    7497                 :            : /** OutputDevice::GetSysFontData
    7498                 :            :  *
    7499                 :            :  * @param nFallbacklevel Fallback font level (0 = best matching font)
    7500                 :            :  *
    7501                 :            :  * Retrieve detailed font information in platform independent structure
    7502                 :            :  *
    7503                 :            :  * @return SystemFontData
    7504                 :            :  **/
    7505                 :          0 : SystemFontData OutputDevice::GetSysFontData(int nFallbacklevel) const
    7506                 :            : {
    7507                 :          0 :     SystemFontData aSysFontData;
    7508                 :          0 :     aSysFontData.nSize = sizeof(aSysFontData);
    7509                 :            : 
    7510         [ #  # ]:          0 :     if (!mpGraphics) ImplGetGraphics();
    7511         [ #  # ]:          0 :     if (mpGraphics) aSysFontData = mpGraphics->GetSysFontData(nFallbacklevel);
    7512                 :            : 
    7513                 :          0 :     return aSysFontData;
    7514                 :            : }
    7515                 :            : 
    7516                 :            : 
    7517                 :            : // -----------------------------------------------------------------------
    7518                 :            : 
    7519                 :            : /** OutputDevice::GetSysTextLayoutData
    7520                 :            :  *
    7521                 :            :  * @param rStartPt Start point of the text
    7522                 :            :  * @param rStr Text string that will be transformed into layout of glyphs
    7523                 :            :  * @param nIndex Position in the string from where layout will be done
    7524                 :            :  * @param nLen Length of the string
    7525                 :            :  * @param pDXAry Custom layout adjustment data
    7526                 :            :  *
    7527                 :            :  * Export finalized glyph layout data as platform independent SystemTextLayoutData
    7528                 :            :  * (see vcl/inc/vcl/sysdata.hxx)
    7529                 :            :  *
    7530                 :            :  * Only parameters rStartPt and rStr are mandatory, the rest is optional
    7531                 :            :  * (default values will be used)
    7532                 :            :  *
    7533                 :            :  * @return SystemTextLayoutData
    7534                 :            :  **/
    7535                 :          0 : SystemTextLayoutData OutputDevice::GetSysTextLayoutData(const Point& rStartPt, const XubString& rStr, xub_StrLen nIndex, xub_StrLen nLen,
    7536                 :            :                                                         const sal_Int32* pDXAry) const
    7537                 :            : {
    7538                 :            :     OSL_TRACE( "OutputDevice::GetSysTextLayoutData()" );
    7539                 :            :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    7540                 :            : 
    7541         [ #  # ]:          0 :     SystemTextLayoutData aSysLayoutData;
    7542                 :          0 :     aSysLayoutData.nSize = sizeof(aSysLayoutData);
    7543         [ #  # ]:          0 :     aSysLayoutData.rGlyphData.reserve( 256 );
    7544                 :            : 
    7545         [ #  # ]:          0 :     if ( mpMetaFile )
    7546                 :            :     {
    7547         [ #  # ]:          0 :         if (pDXAry)
    7548 [ #  # ][ #  # ]:          0 :             mpMetaFile->AddAction( new MetaTextArrayAction( rStartPt, rStr, pDXAry, nIndex, nLen ) );
         [ #  # ][ #  # ]
    7549                 :            :         else
    7550 [ #  # ][ #  # ]:          0 :             mpMetaFile->AddAction( new MetaTextAction( rStartPt, rStr, nIndex, nLen ) );
         [ #  # ][ #  # ]
    7551                 :            :     }
    7552                 :            : 
    7553         [ #  # ]:          0 :     if ( !IsDeviceOutputNecessary() ) return aSysLayoutData;
    7554                 :            : 
    7555         [ #  # ]:          0 :     SalLayout* pLayout = ImplLayout( rStr, nIndex, nLen, rStartPt, 0, pDXAry, true );
    7556                 :            : 
    7557         [ #  # ]:          0 :     if ( !pLayout ) return aSysLayoutData;
    7558                 :            : 
    7559                 :            :     // setup glyphs
    7560                 :          0 :     Point aPos;
    7561                 :            :     sal_GlyphId aGlyphId;
    7562 [ #  # ][ #  # ]:          0 :     for( int nStart = 0; pLayout->GetNextGlyphs( 1, &aGlyphId, aPos, nStart ); )
    7563                 :            :     {
    7564                 :            :         // NOTE: Windows backend is producing unicode chars (ucs4), so on windows,
    7565                 :            :         //       ETO_GLYPH_INDEX is unusable, unless extra glyph conversion is made.
    7566                 :            : 
    7567                 :            :         SystemGlyphData aGlyph;
    7568                 :          0 :         aGlyph.index = static_cast<unsigned long> (aGlyphId & GF_IDXMASK);
    7569                 :          0 :         aGlyph.x = aPos.X();
    7570                 :          0 :         aGlyph.y = aPos.Y();
    7571                 :          0 :         int nLevel = (aGlyphId & GF_FONTMASK) >> GF_FONTSHIFT;
    7572         [ #  # ]:          0 :         aGlyph.fallbacklevel = nLevel < MAX_FALLBACK ? nLevel : 0;
    7573         [ #  # ]:          0 :         aSysLayoutData.rGlyphData.push_back(aGlyph);
    7574                 :            :     }
    7575                 :            : 
    7576                 :            :     // Get font data
    7577                 :          0 :     aSysLayoutData.orientation = pLayout->GetOrientation();
    7578                 :            : 
    7579         [ #  # ]:          0 :     pLayout->Release();
    7580                 :            : 
    7581                 :          0 :     return aSysLayoutData;
    7582                 :            : }
    7583                 :            : 
    7584                 :            : // -----------------------------------------------------------------------
    7585                 :            : 
    7586                 :            : 
    7587                 :          0 : long OutputDevice::GetMinKashida() const
    7588                 :            : {
    7589                 :            :     OSL_TRACE( "OutputDevice::GetMinKashida()" );
    7590                 :            :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    7591 [ #  # ][ #  # ]:          0 :     if( mbNewFont && !ImplNewFont() )
                 [ #  # ]
    7592                 :          0 :         return 0;
    7593                 :            : 
    7594                 :          0 :     ImplFontEntry*      pEntry = mpFontEntry;
    7595                 :          0 :     ImplFontMetricData* pMetric = &(pEntry->maMetric);
    7596                 :          0 :     return ImplDevicePixelToLogicWidth( pMetric->mnMinKashida );
    7597                 :            : }
    7598                 :            : 
    7599                 :            : // -----------------------------------------------------------------------
    7600                 :          0 : xub_StrLen OutputDevice::ValidateKashidas ( const String& rTxt,
    7601                 :            :                                             xub_StrLen nIdx, xub_StrLen nLen,
    7602                 :            :                                             xub_StrLen nKashCount,
    7603                 :            :                                             const xub_StrLen* pKashidaPos,
    7604                 :            :                                             xub_StrLen* pKashidaPosDropped ) const
    7605                 :            : {
    7606                 :            :    // do layout
    7607         [ #  # ]:          0 :     SalLayout* pSalLayout = ImplLayout( rTxt, nIdx, nLen );
    7608         [ #  # ]:          0 :     if( !pSalLayout )
    7609                 :          0 :         return 0;
    7610                 :          0 :     xub_StrLen nDropped = 0;
    7611         [ #  # ]:          0 :     for( int i = 0; i < nKashCount; ++i )
    7612                 :            :     {
    7613         [ #  # ]:          0 :         if( !pSalLayout->IsKashidaPosValid( pKashidaPos[ i ] ))
    7614                 :            :         {
    7615                 :          0 :             pKashidaPosDropped[ nDropped ] = pKashidaPos [ i ];
    7616                 :          0 :             ++nDropped;
    7617                 :            :         }
    7618                 :            :     }
    7619                 :          0 :     pSalLayout->Release();
    7620                 :          0 :     return nDropped;
    7621                 :            : }
    7622                 :            : 
    7623                 :            : 
    7624                 :            : 
    7625                 :            : // -----------------------------------------------------------------------
    7626                 :            : 
    7627                 :            : 
    7628                 :            : // TODO: best is to get rid of this method completely
    7629                 :          0 : sal_uLong OutputDevice::GetKerningPairCount() const
    7630                 :            : {
    7631                 :            :     OSL_TRACE( "OutputDevice::GetKerningPairCount()" );
    7632                 :            :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    7633                 :            : 
    7634 [ #  # ][ #  # ]:          0 :     if( mbNewFont && !ImplNewFont() )
                 [ #  # ]
    7635                 :          0 :         return 0;
    7636         [ #  # ]:          0 :     if( mbInitFont )
    7637                 :          0 :         ImplInitFont();
    7638                 :            : 
    7639 [ #  # ][ #  # ]:          0 :     if( mpPDFWriter && mpPDFWriter->isBuiltinFont( mpFontEntry->maFontSelData.mpFontData ) )
                 [ #  # ]
    7640                 :          0 :         return 0;
    7641                 :            : 
    7642                 :            :     // get the kerning pair count from the device layer
    7643                 :          0 :     int nKernPairs = mpGraphics->GetKernPairs( 0, NULL );
    7644                 :          0 :     return nKernPairs;
    7645                 :            : }
    7646                 :            : 
    7647                 :            : // -----------------------------------------------------------------------
    7648                 :            : 
    7649                 :          0 : inline bool CmpKernData( const KerningPair& a, const KerningPair& b )
    7650                 :            : {
    7651 [ #  # ][ #  # ]:          0 :     return (a.nChar1 < b.nChar1) || ((a.nChar1 == b.nChar1) && (a.nChar2 < b.nChar2));
                 [ #  # ]
    7652                 :            : }
    7653                 :            : 
    7654                 :            : // TODO: best is to get rid of this method completely
    7655                 :          0 : void OutputDevice::GetKerningPairs( sal_uLong nRequestedPairs, KerningPair* pKernPairs ) const
    7656                 :            : {
    7657                 :            :     OSL_TRACE( "OutputDevice::GetKerningPairs()" );
    7658                 :            :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    7659                 :            : 
    7660 [ #  # ][ #  # ]:          0 :     if( mbNewFont && !ImplNewFont() )
                 [ #  # ]
    7661                 :          0 :         return;
    7662         [ #  # ]:          0 :     if( mbInitFont )
    7663                 :          0 :         ImplInitFont();
    7664                 :            : 
    7665 [ #  # ][ #  # ]:          0 :     if( mpPDFWriter && mpPDFWriter->isBuiltinFont( mpFontEntry->maFontSelData.mpFontData ) )
                 [ #  # ]
    7666                 :          0 :         return;
    7667                 :            : 
    7668                 :            :     // get the kerning pairs directly from the device layer
    7669                 :          0 :     int nKernPairs = mpGraphics->GetKernPairs( nRequestedPairs, (ImplKernPairData*)pKernPairs );
    7670                 :            : 
    7671                 :            :     // sort kerning pairs
    7672                 :          0 :     std::sort( pKernPairs, pKernPairs+nKernPairs, CmpKernData );
    7673                 :            : }
    7674                 :            : 
    7675                 :            : // -----------------------------------------------------------------------
    7676                 :            : 
    7677                 :       2476 : sal_Bool OutputDevice::GetGlyphBoundRects( const Point& rOrigin, const String& rStr,
    7678                 :            :     int nIndex, int nLen, int nBase, MetricVector& rVector )
    7679                 :            : {
    7680                 :            :     OSL_TRACE( "OutputDevice::GetGlyphBoundRect_CTL()" );
    7681                 :            :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    7682                 :            : 
    7683                 :       2476 :     rVector.clear();
    7684                 :            : 
    7685         [ +  + ]:       2476 :     if( nLen == STRING_LEN )
    7686                 :       2424 :         nLen = rStr.Len() - nIndex;
    7687                 :            : 
    7688         [ +  - ]:       2476 :     Rectangle aRect;
    7689         [ +  + ]:      11444 :     for( int i = 0; i < nLen; i++ )
    7690                 :            :     {
    7691 [ +  - ][ -  + ]:       8968 :         if( !GetTextBoundRect( aRect, rStr, sal::static_int_cast<xub_StrLen>(nBase), sal::static_int_cast<xub_StrLen>(nIndex+i), 1 ) )
    7692                 :          0 :             break;
    7693         [ +  - ]:       8968 :         aRect.Move( rOrigin.X(), rOrigin.Y() );
    7694         [ +  - ]:       8968 :         rVector.push_back( aRect );
    7695                 :            :     }
    7696                 :            : 
    7697                 :       2476 :     return (nLen == (int)rVector.size());
    7698                 :            : }
    7699                 :            : 
    7700                 :            : // -----------------------------------------------------------------------
    7701                 :            : 
    7702                 :     125074 : sal_Bool OutputDevice::GetTextBoundRect( Rectangle& rRect,
    7703                 :            :     const String& rStr, xub_StrLen nBase, xub_StrLen nIndex, xub_StrLen nLen,
    7704                 :            :     sal_uLong nLayoutWidth, const sal_Int32* pDXAry ) const
    7705                 :            : {
    7706                 :            :     OSL_TRACE( "OutputDevice::GetTextBoundRect()" );
    7707                 :            :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    7708                 :            : 
    7709                 :     125074 :     sal_Bool bRet = sal_False;
    7710                 :     125074 :     rRect.SetEmpty();
    7711                 :            : 
    7712                 :     125074 :     SalLayout* pSalLayout = NULL;
    7713                 :     125074 :     const Point aPoint;
    7714                 :            :     // calculate offset when nBase!=nIndex
    7715                 :     125074 :     long nXOffset = 0;
    7716         [ +  + ]:     125074 :     if( nBase != nIndex )
    7717                 :            :     {
    7718                 :       7906 :         xub_StrLen nStart = Min( nBase, nIndex );
    7719                 :       7906 :         xub_StrLen nOfsLen = Max( nBase, nIndex ) - nStart;
    7720         [ +  - ]:       7906 :         pSalLayout = ImplLayout( rStr, nStart, nOfsLen, aPoint, nLayoutWidth, pDXAry );
    7721         [ +  - ]:       7906 :         if( pSalLayout )
    7722                 :            :         {
    7723         [ +  - ]:       7906 :             nXOffset = pSalLayout->GetTextWidth();
    7724                 :       7906 :             nXOffset /= pSalLayout->GetUnitsPerPixel();
    7725         [ +  - ]:       7906 :             pSalLayout->Release();
    7726                 :            :             // TODO: fix offset calculation for Bidi case
    7727         [ +  - ]:       7906 :             if( nBase < nIndex)
    7728                 :       7906 :                 nXOffset = -nXOffset;
    7729                 :            :         }
    7730                 :            :     }
    7731                 :            : 
    7732         [ +  - ]:     125074 :     pSalLayout = ImplLayout( rStr, nIndex, nLen, aPoint, nLayoutWidth, pDXAry );
    7733         [ +  - ]:     125074 :     Rectangle aPixelRect;
    7734         [ +  - ]:     125074 :     if( pSalLayout )
    7735                 :            :     {
    7736         [ +  - ]:     125074 :         bRet = pSalLayout->GetBoundRect( *mpGraphics, aPixelRect );
    7737                 :            : 
    7738         [ +  - ]:     125074 :         if( bRet )
    7739                 :            :         {
    7740                 :     125074 :             int nWidthFactor = pSalLayout->GetUnitsPerPixel();
    7741                 :            : 
    7742         [ -  + ]:     125074 :             if( nWidthFactor > 1 )
    7743                 :            :             {
    7744                 :          0 :                 double fFactor = 1.0 / nWidthFactor;
    7745                 :          0 :                 aPixelRect.Left()
    7746                 :          0 :                     = static_cast< long >(aPixelRect.Left() * fFactor);
    7747                 :          0 :                 aPixelRect.Right()
    7748                 :          0 :                     = static_cast< long >(aPixelRect.Right() * fFactor);
    7749                 :          0 :                 aPixelRect.Top()
    7750                 :          0 :                     = static_cast< long >(aPixelRect.Top() * fFactor);
    7751                 :          0 :                 aPixelRect.Bottom()
    7752                 :          0 :                     = static_cast< long >(aPixelRect.Bottom() * fFactor);
    7753                 :            :             }
    7754                 :            : 
    7755                 :     125074 :             Point aRotatedOfs( mnTextOffX, mnTextOffY );
    7756         [ +  - ]:     125074 :             aRotatedOfs -= pSalLayout->GetDrawPosition( Point( nXOffset, 0 ) );
    7757         [ +  - ]:     125074 :             aPixelRect += aRotatedOfs;
    7758         [ +  - ]:     125074 :             rRect = PixelToLogic( aPixelRect );
    7759         [ +  + ]:     125074 :             if( mbMap )
    7760         [ +  - ]:     125074 :                 rRect += Point( maMapRes.mnMapOfsX, maMapRes.mnMapOfsY );
    7761                 :            :         }
    7762                 :            : 
    7763         [ +  - ]:     125074 :         pSalLayout->Release();
    7764                 :            :     }
    7765                 :            : 
    7766 [ -  + ][ #  # ]:     125074 :     if( bRet || (OUTDEV_PRINTER == meOutDevType) || !mpFontEntry )
                 [ #  # ]
    7767                 :     125074 :         return bRet;
    7768                 :            : 
    7769                 :            :     // fall back to bitmap method to get the bounding rectangle,
    7770                 :            :     // so we need a monochrome virtual device with matching font
    7771         [ #  # ]:          0 :     VirtualDevice aVDev( 1 );
    7772         [ #  # ]:          0 :     Font aFont( GetFont() );
    7773         [ #  # ]:          0 :     aFont.SetShadow( sal_False );
    7774         [ #  # ]:          0 :     aFont.SetOutline( sal_False );
    7775         [ #  # ]:          0 :     aFont.SetRelief( RELIEF_NONE );
    7776         [ #  # ]:          0 :     aFont.SetOrientation( 0 );
    7777         [ #  # ]:          0 :     aFont.SetSize( Size( mpFontEntry->maFontSelData.mnWidth, mpFontEntry->maFontSelData.mnHeight ) );
    7778         [ #  # ]:          0 :     aVDev.SetFont( aFont );
    7779         [ #  # ]:          0 :     aVDev.SetTextAlign( ALIGN_TOP );
    7780                 :            : 
    7781                 :            :     // layout the text on the virtual device
    7782         [ #  # ]:          0 :     pSalLayout = aVDev.ImplLayout( rStr, nIndex, nLen, aPoint, nLayoutWidth, pDXAry );
    7783         [ #  # ]:          0 :     if( !pSalLayout )
    7784                 :          0 :         return false;
    7785                 :            : 
    7786                 :            :     // make the bitmap big enough
    7787                 :            :     // TODO: use factors when it would get too big
    7788         [ #  # ]:          0 :     long nWidth = pSalLayout->GetTextWidth();
    7789                 :          0 :     long nHeight = mpFontEntry->mnLineHeight + mnEmphasisAscent + mnEmphasisDescent;
    7790                 :          0 :     Point aOffset( nWidth/2, 8 );
    7791                 :          0 :     Size aOutSize( nWidth + 2*aOffset.X(), nHeight + 2*aOffset.Y() );
    7792 [ #  # ][ #  # ]:          0 :     if( !nWidth || !aVDev.SetOutputSizePixel( aOutSize ) )
         [ #  # ][ #  # ]
    7793                 :          0 :         return false;
    7794                 :            : 
    7795                 :            :     // draw text in black
    7796                 :          0 :     pSalLayout->DrawBase() = aOffset;
    7797         [ #  # ]:          0 :     aVDev.SetTextColor( Color( COL_BLACK ) );
    7798         [ #  # ]:          0 :     aVDev.SetTextFillColor();
    7799         [ #  # ]:          0 :     aVDev.ImplInitTextColor();
    7800         [ #  # ]:          0 :     aVDev.ImplDrawText( *pSalLayout );
    7801         [ #  # ]:          0 :     pSalLayout->Release();
    7802                 :            : 
    7803                 :            :     // find extents using the bitmap
    7804         [ #  # ]:          0 :     Bitmap aBmp = aVDev.GetBitmap( Point(), aOutSize );
    7805         [ #  # ]:          0 :     BitmapReadAccess* pAcc = aBmp.AcquireReadAccess();
    7806         [ #  # ]:          0 :     if( !pAcc )
    7807                 :          0 :         return sal_False;
    7808         [ #  # ]:          0 :     const BitmapColor aBlack( pAcc->GetBestMatchingColor( Color( COL_BLACK ) ) );
    7809                 :          0 :     const long nW = pAcc->Width();
    7810                 :          0 :     const long nH = pAcc->Height();
    7811                 :          0 :     long nLeft = 0;
    7812                 :          0 :     long nRight = 0;
    7813                 :            : 
    7814                 :            :     // find top left point
    7815                 :          0 :     long nTop = 0;
    7816         [ #  # ]:          0 :     for(; nTop < nH; ++nTop )
    7817                 :            :     {
    7818         [ #  # ]:          0 :         for( nLeft = 0; nLeft < nW; ++nLeft )
    7819 [ #  # ][ #  # ]:          0 :             if( pAcc->GetPixel( nTop, nLeft ) == aBlack )
    7820                 :          0 :                 break;
    7821         [ #  # ]:          0 :         if( nLeft < nW )
    7822                 :          0 :             break;
    7823                 :            :     }
    7824                 :            : 
    7825                 :            :     // find bottom right point
    7826                 :          0 :     long nBottom = nH;
    7827         [ #  # ]:          0 :     while( --nBottom >= nTop )
    7828                 :            :     {
    7829         [ #  # ]:          0 :         for( nRight = nW; --nRight >= 0; )
    7830 [ #  # ][ #  # ]:          0 :             if( pAcc->GetPixel( nBottom, nRight ) == aBlack )
    7831                 :          0 :                 break;
    7832         [ #  # ]:          0 :         if( nRight >= 0 )
    7833                 :          0 :             break;
    7834                 :            :     }
    7835         [ #  # ]:          0 :     if( nRight < nLeft )
    7836                 :            :     {
    7837                 :          0 :         long nX = nRight;
    7838                 :          0 :         nRight = nLeft;
    7839                 :          0 :         nLeft  = nX;
    7840                 :            :     }
    7841                 :            : 
    7842         [ #  # ]:          0 :     for( long nY = nTop; nY <= nBottom; ++nY )
    7843                 :            :     {
    7844                 :            :         // find leftmost point
    7845                 :            :         long nX;
    7846         [ #  # ]:          0 :         for( nX = 0; nX < nLeft; ++nX )
    7847 [ #  # ][ #  # ]:          0 :             if( pAcc->GetPixel( nY, nX ) == aBlack )
    7848                 :          0 :                 break;
    7849                 :          0 :         nLeft = nX;
    7850                 :            : 
    7851                 :            :         // find rightmost point
    7852         [ #  # ]:          0 :         for( nX = nW; --nX > nRight; )
    7853 [ #  # ][ #  # ]:          0 :             if( pAcc->GetPixel( nY, nX ) == aBlack )
    7854                 :          0 :                 break;
    7855                 :          0 :         nRight = nX;
    7856                 :            :     }
    7857                 :            : 
    7858         [ #  # ]:          0 :     aBmp.ReleaseAccess( pAcc );
    7859                 :            : 
    7860         [ #  # ]:          0 :     if( nTop <= nBottom )
    7861                 :            :     {
    7862                 :          0 :         Size aSize( nRight - nLeft + 1, nBottom - nTop + 1 );
    7863                 :          0 :         Point aTopLeft( nLeft, nTop );
    7864                 :          0 :         aTopLeft -= aOffset;
    7865                 :            :         // adjust to text alignment
    7866                 :          0 :         aTopLeft.Y()+= mnTextOffY - (mpFontEntry->maMetric.mnAscent + mnEmphasisAscent);
    7867                 :            :         // convert to logical coordinates
    7868         [ #  # ]:          0 :         aSize = PixelToLogic( aSize );
    7869         [ #  # ]:          0 :         aTopLeft.X() = ImplDevicePixelToLogicWidth( aTopLeft.X() );
    7870         [ #  # ]:          0 :         aTopLeft.Y() = ImplDevicePixelToLogicHeight( aTopLeft.Y() );
    7871         [ #  # ]:          0 :         rRect = Rectangle( aTopLeft, aSize );
    7872                 :          0 :         return sal_True;
    7873                 :            :     }
    7874                 :            : 
    7875 [ #  # ][ #  # ]:     125074 :     return sal_False;
                 [ #  # ]
    7876                 :            : }
    7877                 :            : 
    7878                 :            : // -----------------------------------------------------------------------
    7879                 :            : 
    7880                 :       1200 : sal_Bool OutputDevice::GetTextOutlines( ::basegfx::B2DPolyPolygonVector& rVector,
    7881                 :            :     const String& rStr, xub_StrLen nBase, xub_StrLen nIndex, xub_StrLen nLen,
    7882                 :            :     sal_Bool bOptimize, sal_uLong nTWidth, const sal_Int32* pDXArray ) const
    7883                 :            : {
    7884                 :            :     // the fonts need to be initialized
    7885         [ +  + ]:       1200 :     if( mbNewFont )
    7886         [ +  - ]:        903 :         ImplNewFont();
    7887         [ +  + ]:       1200 :     if( mbInitFont )
    7888         [ +  - ]:        217 :         ImplInitFont();
    7889         [ -  + ]:       1200 :     if( !mpFontEntry )
    7890                 :          0 :         return sal_False;
    7891                 :            : 
    7892                 :       1200 :     sal_Bool bRet = sal_False;
    7893                 :       1200 :     rVector.clear();
    7894         [ +  + ]:       1200 :     if( nLen == STRING_LEN )
    7895                 :        357 :         nLen = rStr.Len() - nIndex;
    7896         [ +  - ]:       1200 :     rVector.reserve( nLen );
    7897                 :            : 
    7898                 :            :     // we want to get the Rectangle in logical units, so to
    7899                 :            :     // avoid rounding errors we just size the font in logical units
    7900                 :       1200 :     sal_Bool bOldMap = mbMap;
    7901         [ +  + ]:       1200 :     if( bOldMap )
    7902                 :            :     {
    7903                 :        357 :         const_cast<OutputDevice&>(*this).mbMap = sal_False;
    7904                 :        357 :         const_cast<OutputDevice&>(*this).mbNewFont = sal_True;
    7905                 :            :     }
    7906                 :            : 
    7907                 :       1200 :     SalLayout* pSalLayout = NULL;
    7908                 :            : 
    7909                 :            :     // calculate offset when nBase!=nIndex
    7910                 :       1200 :     long nXOffset = 0;
    7911         [ -  + ]:       1200 :     if( nBase != nIndex )
    7912                 :            :     {
    7913                 :          0 :         xub_StrLen nStart = Min( nBase, nIndex );
    7914                 :          0 :         xub_StrLen nOfsLen = Max( nBase, nIndex ) - nStart;
    7915         [ #  # ]:          0 :         pSalLayout = ImplLayout( rStr, nStart, nOfsLen, Point(0,0), nTWidth, pDXArray );
    7916         [ #  # ]:          0 :         if( pSalLayout )
    7917                 :            :         {
    7918         [ #  # ]:          0 :             nXOffset = pSalLayout->GetTextWidth();
    7919         [ #  # ]:          0 :             pSalLayout->Release();
    7920                 :            :             // TODO: fix offset calculation for Bidi case
    7921         [ #  # ]:          0 :             if( nBase > nIndex)
    7922                 :          0 :                 nXOffset = -nXOffset;
    7923                 :            :         }
    7924                 :            :     }
    7925                 :            : 
    7926         [ +  - ]:       1200 :     pSalLayout = ImplLayout( rStr, nIndex, nLen, Point(0,0), nTWidth, pDXArray );
    7927         [ +  - ]:       1200 :     if( pSalLayout )
    7928                 :            :     {
    7929         [ +  - ]:       1200 :         bRet = pSalLayout->GetOutline( *mpGraphics, rVector );
    7930         [ +  + ]:       1200 :         if( bRet )
    7931                 :            :         {
    7932                 :            :             // transform polygon to pixel units
    7933         [ +  - ]:       1062 :             ::basegfx::B2DHomMatrix aMatrix;
    7934                 :            : 
    7935                 :       1062 :             int nWidthFactor = pSalLayout->GetUnitsPerPixel();
    7936         [ -  + ]:       1062 :             if( nXOffset | mnTextOffX | mnTextOffY )
    7937                 :            :             {
    7938                 :          0 :                 Point aRotatedOfs( mnTextOffX*nWidthFactor, mnTextOffY*nWidthFactor );
    7939         [ #  # ]:          0 :                 aRotatedOfs -= pSalLayout->GetDrawPosition( Point( nXOffset, 0 ) );
    7940         [ #  # ]:          0 :                 aMatrix.translate( aRotatedOfs.X(), aRotatedOfs.Y() );
    7941                 :            :             }
    7942                 :            : 
    7943         [ -  + ]:       1062 :             if( nWidthFactor > 1 )
    7944                 :            :             {
    7945                 :          0 :                 double fFactor = 1.0 / nWidthFactor;
    7946         [ #  # ]:          0 :                 aMatrix.scale( fFactor, fFactor );
    7947                 :            :             }
    7948                 :            : 
    7949 [ +  - ][ -  + ]:       1062 :             if( !aMatrix.isIdentity() )
    7950                 :            :             {
    7951                 :          0 :                 ::basegfx::B2DPolyPolygonVector::iterator aIt = rVector.begin();
    7952 [ #  # ][ #  # ]:          0 :                 for(; aIt != rVector.end(); ++aIt )
                 [ #  # ]
    7953 [ #  # ][ #  # ]:          0 :                     (*aIt).transform( aMatrix );
    7954         [ +  - ]:       1062 :             }
    7955                 :            :         }
    7956                 :            : 
    7957         [ +  - ]:       1200 :         pSalLayout->Release();
    7958                 :            :     }
    7959                 :            : 
    7960         [ +  + ]:       1200 :     if( bOldMap )
    7961                 :            :     {
    7962                 :            :         // restore original font size and map mode
    7963                 :        357 :         const_cast<OutputDevice&>(*this).mbMap = bOldMap;
    7964                 :        357 :         const_cast<OutputDevice&>(*this).mbNewFont = sal_True;
    7965                 :            :     }
    7966                 :            : 
    7967 [ +  + ][ +  - ]:       1200 :     if( bRet || (OUTDEV_PRINTER == meOutDevType) || !mpFontEntry )
                 [ -  + ]
    7968                 :       1062 :         return bRet;
    7969                 :            : 
    7970                 :            :     // fall back to bitmap conversion ------------------------------------------
    7971                 :            : 
    7972                 :            :     // Here, we can savely assume that the mapping between characters and glyphs
    7973                 :            :     // is one-to-one. This is most probably valid for the old bitmap fonts.
    7974                 :            : 
    7975                 :            :     // fall back to bitmap method to get the bounding rectangle,
    7976                 :            :     // so we need a monochrome virtual device with matching font
    7977         [ +  - ]:        138 :     pSalLayout = ImplLayout( rStr, nIndex, nLen, Point(0,0), nTWidth, pDXArray );
    7978         [ -  + ]:        138 :     if (pSalLayout == 0)
    7979                 :          0 :         return false;
    7980         [ +  - ]:        138 :     long nOrgWidth = pSalLayout->GetTextWidth();
    7981                 :            :     long nOrgHeight = mpFontEntry->mnLineHeight + mnEmphasisAscent
    7982                 :        138 :         + mnEmphasisDescent;
    7983         [ +  - ]:        138 :     pSalLayout->Release();
    7984                 :            : 
    7985         [ +  - ]:        138 :     VirtualDevice aVDev(1);
    7986                 :            : 
    7987         [ +  - ]:        138 :     Font aFont(GetFont());
    7988         [ +  - ]:        138 :     aFont.SetShadow(false);
    7989         [ +  - ]:        138 :     aFont.SetOutline(false);
    7990         [ +  - ]:        138 :     aFont.SetRelief(RELIEF_NONE);
    7991         [ +  - ]:        138 :     aFont.SetOrientation(0);
    7992         [ +  - ]:        138 :     if( bOptimize )
    7993                 :            :     {
    7994         [ +  - ]:        138 :         aFont.SetSize( Size( 0, GLYPH_FONT_HEIGHT ) );
    7995 [ +  - ][ +  - ]:        138 :         aVDev.SetMapMode( MAP_PIXEL );
                 [ +  - ]
    7996                 :            :     }
    7997         [ +  - ]:        138 :     aVDev.SetFont( aFont );
    7998         [ +  - ]:        138 :     aVDev.SetTextAlign( ALIGN_TOP );
    7999         [ +  - ]:        138 :     aVDev.SetTextColor( Color(COL_BLACK) );
    8000         [ +  - ]:        138 :     aVDev.SetTextFillColor();
    8001                 :            : 
    8002         [ +  - ]:        138 :     pSalLayout = aVDev.ImplLayout( rStr, nIndex, nLen, Point(0,0), nTWidth, pDXArray );
    8003         [ -  + ]:        138 :     if (pSalLayout == 0)
    8004                 :          0 :         return false;
    8005         [ +  - ]:        138 :     long nWidth = pSalLayout->GetTextWidth();
    8006                 :            :     long nHeight = ((OutputDevice*)&aVDev)->mpFontEntry->mnLineHeight + ((OutputDevice*)&aVDev)->mnEmphasisAscent
    8007                 :        138 :         + ((OutputDevice*)&aVDev)->mnEmphasisDescent;
    8008         [ +  - ]:        138 :     pSalLayout->Release();
    8009                 :            : 
    8010 [ +  + ][ -  + ]:        138 :     if( !nWidth || !nHeight )
    8011                 :         33 :         return sal_True;
    8012                 :        105 :     double fScaleX = static_cast< double >(nOrgWidth) / nWidth;
    8013                 :        105 :     double fScaleY = static_cast< double >(nOrgHeight) / nHeight;
    8014                 :            : 
    8015                 :            :     // calculate offset when nBase!=nIndex
    8016                 :            :     // TODO: fix offset calculation for Bidi case
    8017                 :        105 :     nXOffset = 0;
    8018         [ -  + ]:        105 :     if( nBase != nIndex )
    8019                 :            :     {
    8020         [ #  # ]:          0 :         xub_StrLen nStart  = ((nBase < nIndex) ? nBase : nIndex);
    8021         [ #  # ]:          0 :         xub_StrLen nLength = ((nBase > nIndex) ? nBase : nIndex) - nStart;
    8022         [ #  # ]:          0 :         pSalLayout = aVDev.ImplLayout( rStr, nStart, nLength, Point(0,0), nTWidth, pDXArray );
    8023         [ #  # ]:          0 :         if( pSalLayout )
    8024                 :            :         {
    8025         [ #  # ]:          0 :             nXOffset = pSalLayout->GetTextWidth();
    8026         [ #  # ]:          0 :             pSalLayout->Release();
    8027         [ #  # ]:          0 :             if( nBase > nIndex)
    8028                 :          0 :                 nXOffset = -nXOffset;
    8029                 :            :         }
    8030                 :            :     }
    8031                 :            : 
    8032                 :        105 :     bRet = true;
    8033                 :        105 :     bool bRTL = false;
    8034         [ +  - ]:        105 :     String aStr( rStr ); // prepare for e.g. localized digits
    8035         [ +  - ]:        105 :     ImplLayoutArgs aLayoutArgs = ImplPrepareLayoutArgs( aStr, nIndex, nLen, 0, NULL );
    8036 [ +  - ][ +  + ]:        210 :     for( int nCharPos = -1; aLayoutArgs.GetNextPos( &nCharPos, &bRTL);)
    8037                 :            :     {
    8038                 :        105 :         bool bSuccess = false;
    8039                 :            : 
    8040                 :            :         // draw character into virtual device
    8041         [ +  - ]:        105 :         pSalLayout = aVDev.ImplLayout( rStr, static_cast< xub_StrLen >(nCharPos), 1, Point(0,0), nTWidth, pDXArray );
    8042         [ -  + ]:        105 :         if (pSalLayout == 0)
    8043                 :          0 :             return false;
    8044         [ +  - ]:        105 :         long nCharWidth = pSalLayout->GetTextWidth();
    8045                 :            : 
    8046                 :        105 :         Point aOffset(nCharWidth / 2, 8);
    8047                 :        105 :         Size aSize(nCharWidth + 2 * aOffset.X(), nHeight + 2 * aOffset.Y());
    8048         [ +  - ]:        105 :         bSuccess = (bool)aVDev.SetOutputSizePixel(aSize);
    8049         [ +  - ]:        105 :         if( bSuccess )
    8050                 :            :         {
    8051                 :            :             // draw glyph into virtual device
    8052         [ +  - ]:        105 :             aVDev.Erase();
    8053                 :        105 :             pSalLayout->DrawBase() += aOffset;
    8054                 :        105 :             pSalLayout->DrawBase() += Point( ((OutputDevice*)&aVDev)->mnTextOffX, ((OutputDevice*)&aVDev)->mnTextOffY );
    8055         [ +  - ]:        105 :             pSalLayout->DrawText( *((OutputDevice*)&aVDev)->mpGraphics );
    8056         [ +  - ]:        105 :             pSalLayout->Release();
    8057                 :            : 
    8058                 :            :             // convert character image into outline
    8059         [ +  - ]:        105 :             Bitmap aBmp( aVDev.GetBitmap(Point(0, 0), aSize));
    8060                 :            : 
    8061         [ +  - ]:        105 :             PolyPolygon aPolyPoly;
    8062         [ +  - ]:        105 :             bool bVectorized = aBmp.Vectorize(aPolyPoly, BMP_VECTORIZE_OUTER | BMP_VECTORIZE_REDUCE_EDGES);
    8063         [ -  + ]:        105 :             if( !bVectorized )
    8064                 :          0 :                 bSuccess = false;
    8065                 :            :             else
    8066                 :            :             {
    8067                 :            :                 // convert units to logical width
    8068 [ +  - ][ -  + ]:        105 :                 for (sal_uInt16 j = 0; j < aPolyPoly.Count(); ++j)
    8069                 :            :                 {
    8070         [ #  # ]:          0 :                     Polygon& rPoly = aPolyPoly[j];
    8071 [ #  # ][ #  # ]:          0 :                     for (sal_uInt16 k = 0; k < rPoly.GetSize(); ++k)
    8072                 :            :                     {
    8073         [ #  # ]:          0 :                         Point& rPt = rPoly[k];
    8074                 :          0 :                         rPt -= aOffset;
    8075                 :          0 :                         int nPixelX = rPt.X() - ((OutputDevice&)aVDev).mnTextOffX + nXOffset;
    8076                 :          0 :                         int nPixelY = rPt.Y() - ((OutputDevice&)aVDev).mnTextOffY;
    8077         [ #  # ]:          0 :                         rPt.X() = ImplDevicePixelToLogicWidth( nPixelX );
    8078         [ #  # ]:          0 :                         rPt.Y() = ImplDevicePixelToLogicHeight( nPixelY );
    8079                 :            :                     }
    8080                 :            :                 }
    8081                 :            : 
    8082                 :            : 
    8083                 :            :                 // ignore "empty" glyphs:
    8084 [ +  - ][ -  + ]:        105 :                 if( aPolyPoly.Count() > 0 )
    8085                 :            :                 {
    8086                 :            :                     // convert  to B2DPolyPolygon
    8087                 :            :                     // TODO: get rid of intermediate tool's PolyPolygon
    8088         [ #  # ]:          0 :                     ::basegfx::B2DPolyPolygon aB2DPolyPoly = aPolyPoly.getB2DPolyPolygon();
    8089         [ #  # ]:          0 :                     ::basegfx::B2DHomMatrix aMatrix;
    8090         [ #  # ]:          0 :                     aMatrix.scale( fScaleX, fScaleY );
    8091         [ #  # ]:          0 :                     int nAngle = GetFont().GetOrientation();
    8092         [ #  # ]:          0 :                     if( nAngle )
    8093         [ #  # ]:          0 :                         aMatrix.rotate( nAngle * F_PI1800 );
    8094         [ #  # ]:          0 :                     aB2DPolyPoly.transform( aMatrix );
    8095 [ #  # ][ #  # ]:          0 :                     rVector.push_back( aB2DPolyPoly );
                 [ #  # ]
    8096                 :            :                 }
    8097 [ +  - ][ +  - ]:        105 :             }
    8098                 :            :         }
    8099                 :            : 
    8100                 :        105 :         nXOffset += nCharWidth;
    8101 [ +  - ][ +  - ]:        105 :         bRet = bRet && bSuccess;
    8102                 :            :     }
    8103                 :            : 
    8104 [ +  - ][ +  - ]:       1200 :     return bRet;
                 [ +  - ]
    8105                 :            : }
    8106                 :            : 
    8107                 :            : // -----------------------------------------------------------------------
    8108                 :            : 
    8109                 :        357 : sal_Bool OutputDevice::GetTextOutlines( PolyPolyVector& rResultVector,
    8110                 :            :     const String& rStr, xub_StrLen nBase, xub_StrLen nIndex,
    8111                 :            :     xub_StrLen nLen, sal_Bool bOptimize, sal_uLong nTWidth, const sal_Int32* pDXArray ) const
    8112                 :            : {
    8113                 :        357 :     rResultVector.clear();
    8114                 :            : 
    8115                 :            :     // get the basegfx polypolygon vector
    8116         [ +  - ]:        357 :     ::basegfx::B2DPolyPolygonVector aB2DPolyPolyVector;
    8117         [ -  + ]:        357 :     if( !GetTextOutlines( aB2DPolyPolyVector, rStr, nBase, nIndex, nLen,
    8118         [ +  - ]:        357 :                          bOptimize, nTWidth, pDXArray ) )
    8119                 :          0 :     return sal_False;
    8120                 :            : 
    8121                 :            :     // convert to a tool polypolygon vector
    8122         [ +  - ]:        357 :     rResultVector.reserve( aB2DPolyPolyVector.size() );
    8123         [ +  - ]:        357 :     ::basegfx::B2DPolyPolygonVector::const_iterator aIt = aB2DPolyPolyVector.begin();
    8124 [ +  - ][ +  - ]:        576 :     for(; aIt != aB2DPolyPolyVector.end(); ++aIt )
                 [ +  + ]
    8125 [ +  - ][ +  - ]:        219 :         rResultVector.push_back(PolyPolygon(*aIt)); // #i76339#
         [ +  - ][ +  - ]
    8126                 :            : 
    8127                 :        357 :     return sal_True;
    8128                 :            : }
    8129                 :            : 
    8130                 :            : // -----------------------------------------------------------------------
    8131                 :            : 
    8132                 :          0 : sal_Bool OutputDevice::GetTextOutline( PolyPolygon& rPolyPoly,
    8133                 :            :     const String& rStr, xub_StrLen nBase, xub_StrLen nIndex, xub_StrLen nLen,
    8134                 :            :     sal_Bool bOptimize, sal_uLong nTWidth, const sal_Int32* pDXArray ) const
    8135                 :            : {
    8136         [ #  # ]:          0 :     rPolyPoly.Clear();
    8137                 :            : 
    8138                 :            :     // get the basegfx polypolygon vector
    8139         [ #  # ]:          0 :     ::basegfx::B2DPolyPolygonVector aB2DPolyPolyVector;
    8140         [ #  # ]:          0 :     if( !GetTextOutlines( aB2DPolyPolyVector, rStr, nBase, nIndex, nLen,
    8141         [ #  # ]:          0 :                          bOptimize, nTWidth, pDXArray ) )
    8142                 :          0 :     return sal_False;
    8143                 :            : 
    8144                 :            :     // convert and merge into a tool polypolygon
    8145         [ #  # ]:          0 :     ::basegfx::B2DPolyPolygonVector::const_iterator aIt = aB2DPolyPolyVector.begin();
    8146 [ #  # ][ #  # ]:          0 :     for(; aIt != aB2DPolyPolyVector.end(); ++aIt )
                 [ #  # ]
    8147 [ #  # ][ #  # ]:          0 :         for( unsigned int i = 0; i < aIt->count(); ++i )
                 [ #  # ]
    8148 [ #  # ][ #  # ]:          0 :             rPolyPoly.Insert(Polygon((*aIt).getB2DPolygon( i ))); // #i76339#
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    8149                 :            : 
    8150                 :          0 :     return sal_True;
    8151                 :            : }
    8152                 :            : 
    8153                 :          2 : bool OutputDevice::GetFontCapabilities( FontCapabilities& rFontCapabilities ) const
    8154                 :            : {
    8155                 :            :     // we need a graphics
    8156 [ -  + ][ #  # ]:          2 :     if( !mpGraphics && !ImplGetGraphics() )
                 [ -  + ]
    8157                 :          0 :         return false;
    8158                 :            : 
    8159         [ -  + ]:          2 :     if( mbNewFont )
    8160                 :          0 :         ImplNewFont();
    8161         [ -  + ]:          2 :     if( mbInitFont )
    8162                 :          0 :         ImplInitFont();
    8163         [ -  + ]:          2 :     if( !mpFontEntry )
    8164                 :          0 :         return false;
    8165                 :            : 
    8166                 :          2 :     return mpGraphics->GetImplFontCapabilities(rFontCapabilities);
    8167                 :            : }
    8168                 :            : 
    8169                 :            : // -----------------------------------------------------------------------
    8170                 :            : 
    8171                 :       6520 : sal_Bool OutputDevice::GetFontCharMap( FontCharMap& rFontCharMap ) const
    8172                 :            : {
    8173                 :       6520 :     rFontCharMap.Reset();
    8174                 :            : 
    8175                 :            :     // we need a graphics
    8176 [ #  # ][ -  + ]:       6520 :     if( !mpGraphics && !ImplGetGraphics() )
                 [ -  + ]
    8177                 :          0 :         return sal_False;
    8178                 :            : 
    8179         [ +  + ]:       6520 :     if( mbNewFont )
    8180                 :       5527 :         ImplNewFont();
    8181         [ +  + ]:       6520 :     if( mbInitFont )
    8182                 :        159 :         ImplInitFont();
    8183         [ -  + ]:       6520 :     if( !mpFontEntry )
    8184                 :          0 :         return sal_False;
    8185                 :            : 
    8186                 :            : #ifdef ENABLE_IFC_CACHE    // a little font charmap cache helps considerably
    8187                 :            :     static const int NMAXITEMS = 16;
    8188                 :            :     static int nUsedItems = 0, nCurItem = 0;
    8189                 :            : 
    8190                 :            :     struct CharMapCacheItem { const PhysicalFontFace* mpFontData; FontCharMap maCharMap; };
    8191                 :            :     static CharMapCacheItem aCache[ NMAXITEMS ];
    8192                 :            : 
    8193                 :            :     const PhysicalFontFace* pFontData = mpFontEntry->maFontSelData.mpFontData;
    8194                 :            : 
    8195                 :            :     int i;
    8196                 :            :     for( i = nUsedItems; --i >= 0; )
    8197                 :            :         if( pFontData == aCache[i].mpFontData )
    8198                 :            :             break;
    8199                 :            :     if( i >= 0 )    // found in cache
    8200                 :            :     {
    8201                 :            :         rFontCharMap.Reset( aCache[i].maCharMap.mpImpl );
    8202                 :            :     }
    8203                 :            :     else            // need to cache
    8204                 :            : #endif // ENABLE_IFC_CACHE
    8205                 :            :     {
    8206                 :       6520 :         const ImplFontCharMap* pNewMap = mpGraphics->GetImplFontCharMap();
    8207                 :       6520 :         rFontCharMap.Reset( pNewMap );
    8208                 :            : 
    8209                 :            : #ifdef ENABLE_IFC_CACHE
    8210                 :            :         // manage cache round-robin and insert data
    8211                 :            :         CharMapCacheItem& rItem = aCache[ nCurItem ];
    8212                 :            :         rItem.mpFontData = pFontData;
    8213                 :            :         rItem.maCharMap.Reset( pNewMap );
    8214                 :            : 
    8215                 :            :         if( ++nCurItem >= NMAXITEMS )
    8216                 :            :             nCurItem = 0;
    8217                 :            : 
    8218                 :            :         if( ++nUsedItems >= NMAXITEMS )
    8219                 :            :             nUsedItems = NMAXITEMS;
    8220                 :            : #endif // ENABLE_IFC_CACHE
    8221                 :            :     }
    8222                 :            : 
    8223         [ -  + ]:       6520 :     if( rFontCharMap.IsDefaultMap() )
    8224                 :          0 :         return sal_False;
    8225                 :       6520 :     return sal_True;
    8226                 :            : }
    8227                 :            : 
    8228                 :            : // -----------------------------------------------------------------------
    8229                 :            : 
    8230                 :       4624 : xub_StrLen OutputDevice::HasGlyphs( const Font& rTempFont, const String& rStr,
    8231                 :            :     xub_StrLen nIndex, xub_StrLen nLen ) const
    8232                 :            : {
    8233         [ -  + ]:       4624 :     if( nIndex >= rStr.Len() )
    8234                 :          0 :         return nIndex;
    8235                 :       4624 :     xub_StrLen nEnd = nIndex + nLen;
    8236         [ +  + ]:       4624 :     if( (sal_uLong)nIndex+nLen > rStr.Len() )
    8237                 :        187 :         nEnd = rStr.Len();
    8238                 :            : 
    8239                 :            :     DBG_ASSERT( nIndex < nEnd, "StartPos >= EndPos?" );
    8240                 :            :     DBG_ASSERT( nEnd <= rStr.Len(), "String too short" );
    8241                 :            : 
    8242                 :            :     // to get the map temporarily set font
    8243         [ +  - ]:       4624 :     const Font aOrigFont = GetFont();
    8244         [ +  - ]:       4624 :     const_cast<OutputDevice&>(*this).SetFont( rTempFont );
    8245         [ +  - ]:       4624 :     FontCharMap aFontCharMap;
    8246         [ +  - ]:       4624 :     sal_Bool bRet = GetFontCharMap( aFontCharMap );
    8247         [ +  - ]:       4624 :     const_cast<OutputDevice&>(*this).SetFont( aOrigFont );
    8248                 :            : 
    8249                 :            :     // if fontmap is unknown assume it doesn't have the glyphs
    8250         [ -  + ]:       4624 :     if( bRet == sal_False )
    8251                 :          0 :         return nIndex;
    8252                 :            : 
    8253                 :       4624 :     const sal_Unicode* pStr = rStr.GetBuffer();
    8254         [ +  + ]:      14103 :     for( pStr += nIndex; nIndex < nEnd; ++pStr, ++nIndex )
    8255 [ +  - ][ +  + ]:      13904 :         if( ! aFontCharMap.HasChar( *pStr ) )
    8256                 :       4425 :             return nIndex;
    8257                 :            : 
    8258 [ +  - ][ +  - ]:       4624 :     return STRING_LEN;
    8259                 :            : }
    8260                 :            : 
    8261                 :            : // -----------------------------------------------------------------------
    8262                 :            : 
    8263                 :            : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10