LCOV - code coverage report
Current view: top level - usr/local/src/libreoffice/vcl/source/gdi - outdev3.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 2654 4158 63.8 %
Date: 2013-07-09 Functions: 138 172 80.2 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include "i18nlangtag/mslangid.hxx"
      21             : #include "i18nlangtag/languagetag.hxx"
      22             : 
      23             : #include "rtl/tencinfo.h"
      24             : #include "rtl/logfile.hxx"
      25             : 
      26             : #include "tools/debug.hxx"
      27             : #include "tools/poly.hxx"
      28             : 
      29             : #include "basegfx/polygon/b2dpolygon.hxx"
      30             : #include "basegfx/polygon/b2dpolypolygon.hxx"
      31             : #include "basegfx/matrix/b2dhommatrix.hxx"
      32             : 
      33             : #include "vcl/metric.hxx"
      34             : #include "vcl/metaact.hxx"
      35             : #include "vcl/gdimtf.hxx"
      36             : #include "vcl/virdev.hxx"
      37             : #include "vcl/print.hxx"
      38             : #include "vcl/event.hxx"
      39             : #include "vcl/window.hxx"
      40             : #include "vcl/svapp.hxx"
      41             : #include "vcl/bmpacc.hxx"
      42             : #include "vcl/outdev.hxx"
      43             : #include "vcl/edit.hxx"
      44             : // declare system types in sysdata.hxx
      45             : #include <svsys.h>
      46             : #include "vcl/sysdata.hxx"
      47             : #include "vcl/unohelp.hxx"
      48             : #include "vcl/controllayout.hxx"
      49             : 
      50             : #include "salgdi.hxx"
      51             : #include "sallayout.hxx"
      52             : #include "svdata.hxx"
      53             : #include "impfont.hxx"
      54             : #include "outdata.hxx"
      55             : #include "outfont.hxx"
      56             : #include "outdev.h"
      57             : #include "textlayout.hxx"
      58             : #include "svids.hrc"
      59             : #include "window.h"
      60             : 
      61             : #include "unotools/fontcvt.hxx"
      62             : #include "unotools/fontcfg.hxx"
      63             : 
      64             : #include "osl/file.h"
      65             : 
      66             : #include <config_graphite.h>
      67             : #if ENABLE_GRAPHITE
      68             : #include "graphite_features.hxx"
      69             : #endif
      70             : 
      71             : #include "pdfwriter_impl.hxx"
      72             : 
      73             : #include "com/sun/star/beans/PropertyValues.hpp"
      74             : #include "com/sun/star/i18n/XBreakIterator.hpp"
      75             : #include "com/sun/star/i18n/WordType.hpp"
      76             : #include "com/sun/star/linguistic2/LinguServiceManager.hpp"
      77             : #include <comphelper/processfactory.hxx>
      78             : 
      79             : #if defined UNX
      80             : #define GLYPH_FONT_HEIGHT   128
      81             : #else
      82             : #define GLYPH_FONT_HEIGHT   256
      83             : #endif
      84             : 
      85             : #include "sal/alloca.h"
      86             : 
      87             : #include <cmath>
      88             : #include <cstring>
      89             : 
      90             : #include <memory>
      91             : #include <algorithm>
      92             : 
      93             : 
      94             : DBG_NAMEEX( OutputDevice )
      95             : DBG_NAMEEX( Font )
      96             : 
      97             : using namespace ::com::sun::star;
      98             : using namespace ::com::sun::star::uno;
      99             : using namespace ::rtl;
     100             : using namespace ::vcl;
     101             : using namespace ::utl;
     102             : 
     103             : #define TEXT_DRAW_ELLIPSIS  (TEXT_DRAW_ENDELLIPSIS | TEXT_DRAW_PATHELLIPSIS | TEXT_DRAW_NEWSELLIPSIS)
     104             : 
     105             : #define UNDERLINE_LAST      UNDERLINE_BOLDWAVE
     106             : #define STRIKEOUT_LAST      STRIKEOUT_X
     107             : 
     108       87389 : static void ImplRotatePos( long nOriginX, long nOriginY, long& rX, long& rY,
     109             :                            int nOrientation )
     110             : {
     111       87389 :     if ( (nOrientation >= 0) && !(nOrientation % 900) )
     112             :     {
     113        4631 :         if ( (nOrientation >= 3600) )
     114           0 :             nOrientation %= 3600;
     115             : 
     116        4631 :         if ( nOrientation )
     117             :         {
     118        4631 :             rX -= nOriginX;
     119        4631 :             rY -= nOriginY;
     120             : 
     121        4631 :             if ( nOrientation == 900 )
     122             :             {
     123        1496 :                 long nTemp = rX;
     124        1496 :                 rX = rY;
     125        1496 :                 rY = -nTemp;
     126             :             }
     127        3135 :             else if ( nOrientation == 1800 )
     128             :             {
     129           0 :                 rX = -rX;
     130           0 :                 rY = -rY;
     131             :             }
     132             :             else /* ( nOrientation == 2700 ) */
     133             :             {
     134        3135 :                 long nTemp = rX;
     135        3135 :                 rX = -rY;
     136        3135 :                 rY = nTemp;
     137             :             }
     138             : 
     139        4631 :             rX += nOriginX;
     140        4631 :             rY += nOriginY;
     141        4631 :         }
     142             :     }
     143             :     else
     144             :     {
     145       82758 :         double nRealOrientation = nOrientation*F_PI1800;
     146       82758 :         double nCos = cos( nRealOrientation );
     147       82758 :         double nSin = sin( nRealOrientation );
     148             : 
     149             :         // Translation...
     150       82758 :         long nX = rX-nOriginX;
     151       82758 :         long nY = rY-nOriginY;
     152             : 
     153             :         // Rotation...
     154       82758 :         rX = +((long)(nCos*nX + nSin*nY)) + nOriginX;
     155       82758 :         rY = -((long)(nSin*nX - nCos*nY)) + nOriginY;
     156             :     }
     157       87389 : }
     158             : 
     159           3 : void OutputDevice::ImplUpdateFontData( bool bNewFontLists )
     160             : {
     161             :     // the currently selected logical font is no longer needed
     162           3 :     if ( mpFontEntry )
     163             :     {
     164           0 :         mpFontCache->Release( mpFontEntry );
     165           0 :         mpFontEntry = NULL;
     166             :     }
     167             : 
     168           3 :     mbInitFont = true;
     169           3 :     mbNewFont = true;
     170             : 
     171           3 :     if ( bNewFontLists )
     172             :     {
     173           3 :         if ( mpGetDevFontList )
     174             :         {
     175           0 :             delete mpGetDevFontList;
     176           0 :             mpGetDevFontList = NULL;
     177             :         }
     178           3 :         if ( mpGetDevSizeList )
     179             :         {
     180           0 :             delete mpGetDevSizeList;
     181           0 :             mpGetDevSizeList = NULL;
     182             :         }
     183             : 
     184             :         // release all physically selected fonts on this device
     185           3 :         if( ImplGetGraphics() )
     186           3 :             mpGraphics->ReleaseFonts();
     187             :     }
     188             : 
     189             : //    if ( GetOutDevType() == OUTDEV_PRINTER || mpPDFWriter )
     190             :     {
     191           3 :         ImplSVData* pSVData = ImplGetSVData();
     192             : 
     193           3 :         if( mpFontCache && mpFontCache != pSVData->maGDIData.mpScreenFontCache )
     194           3 :             mpFontCache->Invalidate();
     195             : 
     196           3 :         if ( bNewFontLists )
     197             :         {
     198             :             // we need a graphics
     199           3 :             if ( ImplGetGraphics() )
     200             :             {
     201           3 :                 if( mpFontList && mpFontList != pSVData->maGDIData.mpScreenFontList )
     202           3 :                     mpFontList->Clear();
     203             : 
     204           3 :                 if( mpPDFWriter )
     205             :                 {
     206           0 :                     if( mpFontList && mpFontList != pSVData->maGDIData.mpScreenFontList )
     207           0 :                         delete mpFontList;
     208           0 :                     if( mpFontCache && mpFontCache != pSVData->maGDIData.mpScreenFontCache )
     209           0 :                         delete mpFontCache;
     210           0 :                     mpFontList = pSVData->maGDIData.mpScreenFontList->Clone( true, true );
     211           0 :                     mpFontCache = new ImplFontCache( sal_False );
     212             :                 }
     213             :                 else
     214             :                 {
     215           3 :                     if( mpOutDevData )
     216           0 :                         mpOutDevData->maDevFontSubst.Clear();
     217           3 :                     mpGraphics->GetDevFontList( mpFontList );
     218           3 :                     mpGraphics->GetDevFontSubstList( this );
     219             :                 }
     220             :             }
     221             :         }
     222             :     }
     223             : 
     224             :     // also update child windows if needed
     225           3 :     if ( GetOutDevType() == OUTDEV_WINDOW )
     226             :     {
     227           0 :         Window* pChild = ((Window*)this)->mpWindowImpl->mpFirstChild;
     228           0 :         while ( pChild )
     229             :         {
     230           0 :             pChild->ImplUpdateFontData( true );
     231           0 :             pChild = pChild->mpWindowImpl->mpNext;
     232             :         }
     233             :     }
     234           3 : }
     235             : 
     236           0 : void OutputDevice::ImplUpdateAllFontData( bool bNewFontLists )
     237             : {
     238           0 :     ImplSVData* pSVData = ImplGetSVData();
     239             : 
     240             :     // update all windows
     241           0 :     Window* pFrame = pSVData->maWinData.mpFirstFrame;
     242           0 :     while ( pFrame )
     243             :     {
     244           0 :         pFrame->ImplUpdateFontData( bNewFontLists );
     245             : 
     246           0 :         Window* pSysWin = pFrame->mpWindowImpl->mpFrameData->mpFirstOverlap;
     247           0 :         while ( pSysWin )
     248             :         {
     249           0 :             pSysWin->ImplUpdateFontData( bNewFontLists );
     250           0 :             pSysWin = pSysWin->mpWindowImpl->mpNextOverlap;
     251             :         }
     252             : 
     253           0 :         pFrame = pFrame->mpWindowImpl->mpFrameData->mpNextFrame;
     254             :     }
     255             : 
     256             :     // update all virtual devices
     257           0 :     VirtualDevice* pVirDev = pSVData->maGDIData.mpFirstVirDev;
     258           0 :     while ( pVirDev )
     259             :     {
     260           0 :         pVirDev->ImplUpdateFontData( bNewFontLists );
     261           0 :         pVirDev = pVirDev->mpNext;
     262             :     }
     263             : 
     264             :     // update all printers
     265           0 :     Printer* pPrinter = pSVData->maGDIData.mpFirstPrinter;
     266           0 :     while ( pPrinter )
     267             :     {
     268           0 :         pPrinter->ImplUpdateFontData( bNewFontLists );
     269           0 :         pPrinter = pPrinter->mpNext;
     270             :     }
     271             : 
     272             :     // clear global font lists to have them updated
     273           0 :     pSVData->maGDIData.mpScreenFontCache->Invalidate();
     274           0 :     if ( bNewFontLists )
     275             :     {
     276           0 :         pSVData->maGDIData.mpScreenFontList->Clear();
     277           0 :         pFrame = pSVData->maWinData.mpFirstFrame;
     278           0 :         if ( pFrame )
     279             :         {
     280           0 :             if ( pFrame->ImplGetGraphics() )
     281             :             {
     282             :                 // Stupid typecast here and somewhere ((OutputDevice*)&aVDev)->, because bug in .NET2002 compiler
     283           0 :                 OutputDevice *pDevice = (OutputDevice*)pFrame;
     284           0 :                 pDevice->mpGraphics->ClearDevFontCache();
     285           0 :                 pDevice->mpGraphics->GetDevFontList(pFrame->mpWindowImpl->mpFrameData->mpFontList);
     286             :             }
     287             :         }
     288             :     }
     289           0 : }
     290             : 
     291             : // TODO: remove this method when the CWS-gfbfcfg dust has settled
     292          94 : void ImplFreeOutDevFontData()
     293          94 : {}
     294             : 
     295          83 : void OutputDevice::BeginFontSubstitution()
     296             : {
     297          83 :     ImplSVData* pSVData = ImplGetSVData();
     298          83 :     pSVData->maGDIData.mbFontSubChanged = sal_False;
     299          83 : }
     300             : 
     301          83 : void OutputDevice::EndFontSubstitution()
     302             : {
     303          83 :     ImplSVData* pSVData = ImplGetSVData();
     304          83 :     if ( pSVData->maGDIData.mbFontSubChanged )
     305             :     {
     306           0 :         ImplUpdateAllFontData( false );
     307             : 
     308           0 :         Application* pApp = GetpApp();
     309           0 :         DataChangedEvent aDCEvt( DATACHANGED_FONTSUBSTITUTION );
     310           0 :         pApp->DataChanged( aDCEvt );
     311           0 :         pApp->NotifyAllWindows( aDCEvt );
     312           0 :         pSVData->maGDIData.mbFontSubChanged = sal_False;
     313             :     }
     314          83 : }
     315             : 
     316           0 : void OutputDevice::AddFontSubstitute( const OUString& rFontName,
     317             :                                       const OUString& rReplaceFontName,
     318             :                                       sal_uInt16 nFlags )
     319             : {
     320           0 :     ImplDirectFontSubstitution*& rpSubst = ImplGetSVData()->maGDIData.mpDirectFontSubst;
     321           0 :     if( !rpSubst )
     322           0 :         rpSubst = new ImplDirectFontSubstitution();
     323           0 :     rpSubst->AddFontSubstitute( rFontName, rReplaceFontName, nFlags );
     324           0 :     ImplGetSVData()->maGDIData.mbFontSubChanged = sal_True;
     325           0 : }
     326             : 
     327           0 : void ImplDirectFontSubstitution::AddFontSubstitute( const String& rFontName,
     328             :     const String& rSubstFontName, sal_uInt16 nFlags )
     329             : {
     330           0 :     maFontSubstList.push_back( ImplFontSubstEntry( rFontName, rSubstFontName, nFlags ) );
     331           0 : }
     332             : 
     333           0 : ImplFontSubstEntry::ImplFontSubstEntry( const OUString& rFontName,
     334             :     const OUString& rSubstFontName, sal_uInt16 nSubstFlags )
     335             : :   maName( rFontName )
     336             : ,   maReplaceName( rSubstFontName )
     337           0 : ,   mnFlags( nSubstFlags )
     338             : {
     339           0 :     maSearchName        = rFontName;
     340           0 :     maSearchReplaceName = rSubstFontName;
     341           0 :     GetEnglishSearchFontName( maSearchName );
     342           0 :     GetEnglishSearchFontName( maSearchReplaceName );
     343           0 : }
     344             : 
     345           0 : void OutputDevice::ImplAddDevFontSubstitute( const OUString& rFontName,
     346             :                                              const OUString& rReplaceFontName,
     347             :                                              sal_uInt16 nFlags )
     348             : {
     349           0 :     ImplInitOutDevData();
     350           0 :     mpOutDevData->maDevFontSubst.AddFontSubstitute( rFontName, rReplaceFontName, nFlags );
     351           0 : }
     352             : 
     353           0 : void OutputDevice::RemoveFontSubstitute( sal_uInt16 n )
     354             : {
     355           0 :     ImplDirectFontSubstitution* pSubst = ImplGetSVData()->maGDIData.mpDirectFontSubst;
     356           0 :     if( pSubst )
     357           0 :         pSubst->RemoveFontSubstitute( n );
     358           0 : }
     359             : 
     360           0 : void ImplDirectFontSubstitution::RemoveFontSubstitute( int nIndex )
     361             : {
     362           0 :     FontSubstList::iterator it = maFontSubstList.begin();
     363           0 :     for( int nCount = 0; (it != maFontSubstList.end()) && (nCount++ != nIndex); ++it ) ;
     364           0 :     if( it != maFontSubstList.end() )
     365           0 :         maFontSubstList.erase( it );
     366           0 : }
     367             : 
     368          83 : sal_uInt16 OutputDevice::GetFontSubstituteCount()
     369             : {
     370          83 :     const ImplDirectFontSubstitution* pSubst = ImplGetSVData()->maGDIData.mpDirectFontSubst;
     371          83 :     if( !pSubst )
     372          83 :         return 0;
     373           0 :     int nCount =  pSubst->GetFontSubstituteCount();
     374           0 :     return (sal_uInt16)nCount;
     375             : }
     376             : 
     377       22608 : bool ImplDirectFontSubstitution::FindFontSubstitute( String& rSubstName,
     378             :     const String& rSearchName, sal_uInt16 nFlags ) const
     379             : {
     380             :     // TODO: get rid of O(N) searches
     381       22608 :     FontSubstList::const_iterator it = maFontSubstList.begin();
     382       22608 :     for(; it != maFontSubstList.end(); ++it )
     383             :     {
     384           0 :         const ImplFontSubstEntry& rEntry = *it;
     385           0 :         if( ((rEntry.mnFlags & nFlags) || !nFlags)
     386           0 :         &&   (rEntry.maSearchName == rSearchName) )
     387             :         {
     388           0 :             rSubstName = rEntry.maSearchReplaceName;
     389           0 :             return true;
     390             :         }
     391             :     }
     392             : 
     393       22608 :     return false;
     394             : }
     395             : 
     396      816751 : static void ImplFontSubstitute( OUString& rFontName,
     397             :     sal_uInt16 nFlags, ImplDirectFontSubstitution* pDevSpecific )
     398             : {
     399             : #ifdef DBG_UTIL
     400             :     OUString aTempName = rFontName;
     401             :     GetEnglishSearchFontName( aTempName );
     402             :     DBG_ASSERT( aTempName == rFontName, "ImplFontSubstitute() called without a searchname" );
     403             : #endif
     404             : 
     405      816751 :     String aSubstFontName;
     406             : 
     407             :     // apply user-configurable font replacement (eg, from the list in Tools->Options)
     408      816751 :     const ImplDirectFontSubstitution* pSubst = ImplGetSVData()->maGDIData.mpDirectFontSubst;
     409      816751 :     if( pSubst && pSubst->FindFontSubstitute( aSubstFontName, rFontName, FONT_SUBSTITUTE_ALWAYS ) )
     410             :     {
     411           0 :         rFontName = aSubstFontName;
     412           0 :         return;
     413             :     }
     414             : 
     415             :     // apply device specific font replacement (e.g. to use printer builtin fonts)
     416      816751 :     if( !pDevSpecific )
     417      794143 :         return;
     418             : 
     419       22608 :     if( pDevSpecific->FindFontSubstitute( aSubstFontName, rFontName, nFlags ) )
     420             :     {
     421           0 :         rFontName = aSubstFontName;
     422           0 :         return;
     423       22608 :     }
     424             : }
     425             : 
     426       54181 : Font OutputDevice::GetDefaultFont( sal_uInt16 nType, LanguageType eLang,
     427             :                                    sal_uLong nFlags, const OutputDevice* pOutDev )
     428             : {
     429       54181 :     com::sun::star::lang::Locale aLocale;
     430       54181 :     if( eLang == LANGUAGE_NONE || eLang == LANGUAGE_SYSTEM || eLang == LANGUAGE_DONTKNOW )
     431             :     {
     432         403 :         aLocale = Application::GetSettings().GetUILanguageTag().getLocale();
     433             :     }
     434             :     else
     435             :     {
     436       53778 :         aLocale = LanguageTag( eLang ).getLocale();
     437             :     }
     438             : 
     439       54181 :     utl::DefaultFontConfiguration& rDefaults = utl::DefaultFontConfiguration::get();
     440      108362 :     String aSearch = rDefaults.getUserInterfaceFont( aLocale ); // ensure a fallback
     441      108362 :     String aDefault = rDefaults.getDefaultFont( aLocale, nType );
     442       54181 :     if( aDefault.Len() )
     443       52086 :         aSearch = aDefault;
     444             : 
     445       54181 :     Font aFont;
     446       54181 :     aFont.SetPitch( PITCH_VARIABLE );
     447             : 
     448       54181 :     switch ( nType )
     449             :     {
     450             :         case DEFAULTFONT_SANS_UNICODE:
     451             :         case DEFAULTFONT_UI_SANS:
     452           0 :             aFont.SetFamily( FAMILY_SWISS );
     453           0 :             break;
     454             : 
     455             :         case DEFAULTFONT_SANS:
     456             :         case DEFAULTFONT_LATIN_HEADING:
     457             :         case DEFAULTFONT_LATIN_SPREADSHEET:
     458             :         case DEFAULTFONT_LATIN_DISPLAY:
     459        2738 :             aFont.SetFamily( FAMILY_SWISS );
     460        2738 :             break;
     461             : 
     462             :         case DEFAULTFONT_SERIF:
     463             :         case DEFAULTFONT_LATIN_TEXT:
     464             :         case DEFAULTFONT_LATIN_PRESENTATION:
     465       15685 :             aFont.SetFamily( FAMILY_ROMAN );
     466       15685 :             break;
     467             : 
     468             :         case DEFAULTFONT_FIXED:
     469             :         case DEFAULTFONT_LATIN_FIXED:
     470             :         case DEFAULTFONT_UI_FIXED:
     471         297 :             aFont.SetPitch( PITCH_FIXED );
     472         297 :             aFont.SetFamily( FAMILY_MODERN );
     473         297 :             break;
     474             : 
     475             :         case DEFAULTFONT_SYMBOL:
     476           0 :             aFont.SetCharSet( RTL_TEXTENCODING_SYMBOL );
     477           0 :             break;
     478             : 
     479             :         case DEFAULTFONT_CJK_TEXT:
     480             :         case DEFAULTFONT_CJK_PRESENTATION:
     481             :         case DEFAULTFONT_CJK_SPREADSHEET:
     482             :         case DEFAULTFONT_CJK_HEADING:
     483             :         case DEFAULTFONT_CJK_DISPLAY:
     484       17730 :             aFont.SetFamily( FAMILY_SYSTEM ); // don't care, but don't use font subst config later...
     485       17730 :             break;
     486             : 
     487             :         case DEFAULTFONT_CTL_TEXT:
     488             :         case DEFAULTFONT_CTL_PRESENTATION:
     489             :         case DEFAULTFONT_CTL_SPREADSHEET:
     490             :         case DEFAULTFONT_CTL_HEADING:
     491             :         case DEFAULTFONT_CTL_DISPLAY:
     492       17731 :             aFont.SetFamily( FAMILY_SYSTEM ); // don't care, but don't use font subst config later...
     493       17731 :             break;
     494             :     }
     495             : 
     496       54181 :     if ( aSearch.Len() )
     497             :     {
     498       54181 :         aFont.SetHeight( 12 ); // corresponds to nDefaultHeight
     499       54181 :         aFont.SetWeight( WEIGHT_NORMAL );
     500       54181 :         aFont.SetLanguage( eLang );
     501             : 
     502       54181 :         if ( aFont.GetCharSet() == RTL_TEXTENCODING_DONTKNOW )
     503       54181 :             aFont.SetCharSet( osl_getThreadTextEncoding() );
     504             : 
     505             :         // Should we only return available fonts on the given device
     506       54181 :         if ( pOutDev )
     507             :         {
     508           0 :             pOutDev->ImplInitFontList();
     509             : 
     510             :             // Search Font in the FontList
     511           0 :             OUString      aName;
     512           0 :             OUString      aSearchName;
     513           0 :             sal_Int32     nIndex = 0;
     514           0 :             do
     515             :             {
     516           0 :                 aSearchName = GetNextFontToken( aSearch, nIndex );
     517           0 :                 GetEnglishSearchFontName( aSearchName );
     518           0 :                 ImplDevFontListData* pFontFamily = pOutDev->mpFontList->ImplFindBySearchName( aSearchName );
     519           0 :                 if( pFontFamily )
     520             :                 {
     521           0 :                     AddTokenFontName( aName, pFontFamily->GetFamilyName() );
     522           0 :                     if( nFlags & DEFAULTFONT_FLAGS_ONLYONE )
     523           0 :                         break;
     524             :                 }
     525             :             }
     526           0 :             while ( nIndex != -1 );
     527           0 :             aFont.SetName( aName );
     528             :         }
     529             : 
     530             :         // No Name, than set all names
     531       54181 :         if ( !aFont.GetName().Len() )
     532             :         {
     533       54181 :             if ( nFlags & DEFAULTFONT_FLAGS_ONLYONE )
     534             :             {
     535             : 
     536       53937 :                 if( !pOutDev )
     537       53937 :                     pOutDev = (const OutputDevice *)ImplGetSVData()->mpDefaultWin;
     538       53937 :                 if( !pOutDev )
     539             :                 {
     540         326 :                     sal_Int32 nIndex = 0;
     541         326 :                     aFont.SetName( aSearch.GetToken( 0, ';', nIndex ) );
     542             :                 }
     543             :                 else
     544             :                 {
     545       53611 :                     pOutDev->ImplInitFontList();
     546             : 
     547       53611 :                     aFont.SetName( aSearch );
     548             : 
     549             :                     // convert to pixel height
     550       53611 :                     Size aSize = pOutDev->ImplLogicToDevicePixel( aFont.GetSize() );
     551       53611 :                     if ( !aSize.Height() )
     552             :                     {
     553             :                         // use default pixel height only when logical height is zero
     554           0 :                         if ( aFont.GetHeight() )
     555           0 :                             aSize.Height() = 1;
     556             :                         else
     557           0 :                             aSize.Height() = (12*pOutDev->mnDPIY)/72;
     558             :                     }
     559             : 
     560             :                     // use default width only when logical width is zero
     561       53611 :                     if( (0 == aSize.Width()) && (0 != aFont.GetSize().Width()) )
     562           0 :                         aSize.Width() = 1;
     563             : 
     564             :                     // get the name of the first available font
     565       53611 :                     float fExactHeight = static_cast<float>(aSize.Height());
     566       53611 :                     ImplFontEntry* pEntry = pOutDev->mpFontCache->GetFontEntry( pOutDev->mpFontList, aFont, aSize, fExactHeight, pOutDev->mpOutDevData ? &pOutDev->mpOutDevData->maDevFontSubst : NULL );
     567       53611 :                     if (pEntry)
     568             :                     {
     569       53611 :                         if( pEntry->maFontSelData.mpFontData )
     570       53611 :                             aFont.SetName( pEntry->maFontSelData.mpFontData->GetFamilyName() );
     571             :                         else
     572           0 :                             aFont.SetName( pEntry->maFontSelData.maTargetName );
     573             :                     }
     574             :                 }
     575             :             }
     576             :             else
     577         244 :                 aFont.SetName( aSearch );
     578             :         }
     579             :     }
     580             : 
     581             : #if OSL_DEBUG_LEVEL > 2
     582             :     const char* s = "DEFAULTFONT_SANS_UNKNOWN";
     583             :     switch ( nType )
     584             :     {
     585             :     case DEFAULTFONT_SANS_UNICODE:  s = "DEFAULTFONT_SANS_UNICODE"; break;
     586             :     case DEFAULTFONT_UI_SANS:   s = "DEFAULTFONT_UI_SANS"; break;
     587             : 
     588             :     case DEFAULTFONT_SANS:  s = "DEFAULTFONT_SANS"; break;
     589             :     case DEFAULTFONT_LATIN_HEADING: s = "DEFAULTFONT_LATIN_HEADING"; break;
     590             :     case DEFAULTFONT_LATIN_SPREADSHEET: s = "DEFAULTFONT_LATIN_SPREADSHEET"; break;
     591             :     case DEFAULTFONT_LATIN_DISPLAY: s = "DEFAULTFONT_LATIN_DISPLAY"; break;
     592             : 
     593             :     case DEFAULTFONT_SERIF: s = "DEFAULTFONT_SERIF"; break;
     594             :     case DEFAULTFONT_LATIN_TEXT:    s = "DEFAULTFONT_LATIN_TEXT"; break;
     595             :     case DEFAULTFONT_LATIN_PRESENTATION:    s = "DEFAULTFONT_LATIN_PRESENTATION"; break;
     596             : 
     597             :     case DEFAULTFONT_FIXED: s = "DEFAULTFONT_FIXED"; break;
     598             :     case DEFAULTFONT_LATIN_FIXED:   s = "DEFAULTFONT_LATIN_FIXED"; break;
     599             :     case DEFAULTFONT_UI_FIXED:  s = "DEFAULTFONT_UI_FIXED"; break;
     600             : 
     601             :     case DEFAULTFONT_SYMBOL:    s = "DEFAULTFONT_SYMBOL"; break;
     602             : 
     603             :     case DEFAULTFONT_CJK_TEXT:  s = "DEFAULTFONT_CJK_TEXT"; break;
     604             :     case DEFAULTFONT_CJK_PRESENTATION:  s = "DEFAULTFONT_CJK_PRESENTATION"; break;
     605             :     case DEFAULTFONT_CJK_SPREADSHEET:   s = "DEFAULTFONT_CJK_SPREADSHEET"; break;
     606             :     case DEFAULTFONT_CJK_HEADING:   s = "DEFAULTFONT_CJK_HEADING"; break;
     607             :     case DEFAULTFONT_CJK_DISPLAY:   s = "DEFAULTFONT_CJK_DISPLAY"; break;
     608             : 
     609             :     case DEFAULTFONT_CTL_TEXT:  s = "DEFAULTFONT_CTL_TEXT"; break;
     610             :     case DEFAULTFONT_CTL_PRESENTATION:  s = "DEFAULTFONT_CTL_PRESENTATION"; break;
     611             :     case DEFAULTFONT_CTL_SPREADSHEET:   s = "DEFAULTFONT_CTL_SPREADSHEET"; break;
     612             :     case DEFAULTFONT_CTL_HEADING:   s = "DEFAULTFONT_CTL_HEADING"; break;
     613             :     case DEFAULTFONT_CTL_DISPLAY:   s = "DEFAULTFONT_CTL_DISPLAY"; break;
     614             :     }
     615             :     fprintf( stderr, "   OutputDevice::GetDefaultFont() Type=\"%s\" lang=%d flags=%ld FontName=\"%s\"\n",
     616             :          s, eLang, nFlags,
     617             :          OUStringToOString( aFont.GetName(), RTL_TEXTENCODING_UTF8 ).getStr()
     618             :          );
     619             : #endif
     620             : 
     621      108362 :     return aFont;
     622             : }
     623             : 
     624           0 : static unsigned ImplIsCJKFont( const String& rFontName )
     625             : {
     626             :     // Test, if Fontname includes CJK characters --> In this case we
     627             :     // mention that it is a CJK font
     628           0 :     const sal_Unicode* pStr = rFontName.GetBuffer();
     629           0 :     while ( *pStr )
     630             :     {
     631             :         // japanese
     632           0 :         if ( ((*pStr >= 0x3040) && (*pStr <= 0x30FF)) ||
     633           0 :              ((*pStr >= 0x3190) && (*pStr <= 0x319F)) )
     634           0 :             return IMPL_FONT_ATTR_CJK|IMPL_FONT_ATTR_CJK_JP;
     635             : 
     636             :         // korean
     637           0 :         if ( ((*pStr >= 0xAC00) && (*pStr <= 0xD7AF)) ||
     638           0 :              ((*pStr >= 0x3130) && (*pStr <= 0x318F)) ||
     639           0 :              ((*pStr >= 0x1100) && (*pStr <= 0x11FF)) )
     640           0 :             return IMPL_FONT_ATTR_CJK|IMPL_FONT_ATTR_CJK_KR;
     641             : 
     642             :         // chinese
     643           0 :         if ( ((*pStr >= 0x3400) && (*pStr <= 0x9FFF)) )
     644           0 :             return IMPL_FONT_ATTR_CJK|IMPL_FONT_ATTR_CJK_TC|IMPL_FONT_ATTR_CJK_SC;
     645             : 
     646             :         // cjk
     647           0 :         if ( ((*pStr >= 0x3000) && (*pStr <= 0xD7AF)) ||
     648           0 :              ((*pStr >= 0xFF00) && (*pStr <= 0xFFEE)) )
     649           0 :             return IMPL_FONT_ATTR_CJK;
     650             : 
     651           0 :         pStr++;
     652             :     }
     653             : 
     654           0 :     return 0;
     655             : }
     656             : 
     657           0 : static void ImplCalcType( sal_uLong& rType, FontWeight& rWeight, FontWidth& rWidth,
     658             :                           FontFamily eFamily, const FontNameAttr* pFontAttr )
     659             : {
     660           0 :     if ( eFamily != FAMILY_DONTKNOW )
     661             :     {
     662           0 :         if ( eFamily == FAMILY_SWISS )
     663           0 :             rType |= IMPL_FONT_ATTR_SANSSERIF;
     664           0 :         else if ( eFamily == FAMILY_ROMAN )
     665           0 :             rType |= IMPL_FONT_ATTR_SERIF;
     666           0 :         else if ( eFamily == FAMILY_SCRIPT )
     667           0 :             rType |= IMPL_FONT_ATTR_SCRIPT;
     668           0 :         else if ( eFamily == FAMILY_MODERN )
     669           0 :             rType |= IMPL_FONT_ATTR_FIXED;
     670           0 :         else if ( eFamily == FAMILY_DECORATIVE )
     671           0 :             rType |= IMPL_FONT_ATTR_DECORATIVE;
     672             :     }
     673             : 
     674           0 :     if ( pFontAttr )
     675             :     {
     676           0 :         rType |= pFontAttr->Type;
     677             : 
     678           0 :         if ( ((rWeight == WEIGHT_DONTKNOW) || (rWeight == WEIGHT_NORMAL)) &&
     679           0 :              (pFontAttr->Weight != WEIGHT_DONTKNOW) )
     680           0 :             rWeight = pFontAttr->Weight;
     681           0 :         if ( ((rWidth == WIDTH_DONTKNOW) || (rWidth == WIDTH_NORMAL)) &&
     682           0 :              (pFontAttr->Width != WIDTH_DONTKNOW) )
     683           0 :             rWidth = pFontAttr->Width;
     684             :     }
     685           0 : }
     686             : 
     687       40249 : PhysicalFontFace::PhysicalFontFace( const ImplDevFontAttributes& rDFA, int nMagic )
     688             : :   ImplDevFontAttributes( rDFA ),
     689             :     mnWidth(0),
     690             :     mnHeight(0),
     691             :     mnMagic( nMagic ),
     692       40249 :     mpNext( NULL )
     693             : {
     694             :     // StarSymbol is a unicode font, but it still deserves the symbol flag
     695       40249 :     if( !IsSymbolFont() )
     696       39675 :         if ( IsStarSymbol( GetFamilyName() ) )
     697         371 :             SetSymbolFlag( true );
     698       40249 : }
     699             : 
     700      372315 : sal_Int32 PhysicalFontFace::CompareIgnoreSize( const PhysicalFontFace& rOther ) const
     701             : {
     702             :     // compare their width, weight, italic and style name
     703      372315 :     if( GetWidthType() < rOther.GetWidthType() )
     704           0 :         return COMPARE_LESS;
     705      372315 :     else if( GetWidthType() > rOther.GetWidthType() )
     706           0 :         return COMPARE_GREATER;
     707             : 
     708      372315 :     if( GetWeight() < rOther.GetWeight() )
     709        6278 :         return COMPARE_LESS;
     710      366037 :     else if( GetWeight() > rOther.GetWeight() )
     711      204121 :         return COMPARE_GREATER;
     712             : 
     713      161916 :     if( GetSlant() < rOther.GetSlant() )
     714        5876 :         return COMPARE_LESS;
     715      156040 :     else if( GetSlant() > rOther.GetSlant() )
     716      149660 :         return COMPARE_GREATER;
     717             : 
     718        6380 :     sal_Int32 eCompare = GetFamilyName().compareTo( rOther.GetFamilyName() );
     719        6380 :     return eCompare;
     720             : }
     721             : 
     722      230876 : sal_Int32 PhysicalFontFace::CompareWithSize( const PhysicalFontFace& rOther ) const
     723             : {
     724      230876 :     sal_Int32 eCompare = CompareIgnoreSize( rOther );
     725      230876 :     if( eCompare != COMPARE_EQUAL )
     726      224496 :         return eCompare;
     727             : 
     728        6380 :     if( mnHeight < rOther.mnHeight )
     729           0 :         return COMPARE_LESS;
     730        6380 :     else if( mnHeight > rOther.mnHeight )
     731           0 :         return COMPARE_GREATER;
     732             : 
     733        6380 :     if( mnWidth < rOther.mnWidth )
     734           0 :         return COMPARE_LESS;
     735        6380 :     else if( mnWidth > rOther.mnWidth )
     736           0 :         return COMPARE_GREATER;
     737             : 
     738        6380 :     return COMPARE_EQUAL;
     739             : }
     740             : 
     741             : struct FontMatchStatus
     742             : {
     743             : public:
     744             :     int                 mnFaceMatch;
     745             :     int                 mnHeightMatch;
     746             :     int                 mnWidthMatch;
     747             :     const sal_Unicode*  mpTargetStyleName;
     748             : };
     749             : 
     750       16872 : bool PhysicalFontFace::IsBetterMatch( const FontSelectPattern& rFSD, FontMatchStatus& rStatus ) const
     751             : {
     752       16872 :     int nMatch = 0;
     753             : 
     754       16872 :     const OUString& rFontName = rFSD.maTargetName;
     755       16872 :     if( rFontName.equalsIgnoreAsciiCase( GetFamilyName() ) )
     756        6848 :         nMatch += 240000;
     757             : 
     758       50616 :     if( rStatus.mpTargetStyleName
     759       33744 :     &&  GetStyleName().equalsIgnoreAsciiCase( rStatus.mpTargetStyleName ) )
     760           0 :         nMatch += 120000;
     761             : 
     762       16872 :     if( (rFSD.GetPitch() != PITCH_DONTKNOW) && (rFSD.GetPitch() == GetPitch()) )
     763       10514 :         nMatch += 20000;
     764             : 
     765             :     // prefer NORMAL font width
     766             :     // TODO: change when the upper layers can tell their width preference
     767       16872 :     if( GetWidthType() == WIDTH_NORMAL )
     768       16672 :         nMatch += 400;
     769         200 :     else if( (GetWidthType() == WIDTH_SEMI_EXPANDED) || (GetWidthType() == WIDTH_SEMI_CONDENSED) )
     770           0 :         nMatch += 300;
     771             : 
     772       16872 :     if( rFSD.GetWeight() != WEIGHT_DONTKNOW )
     773             :     {
     774             :         // if not bold or requiring emboldening prefer light fonts to bold fonts
     775       16680 :         FontWeight ePatternWeight = rFSD.mbEmbolden ? WEIGHT_NORMAL : rFSD.GetWeight();
     776             : 
     777       16680 :         int nReqWeight = (int)ePatternWeight;
     778       16680 :         if ( ePatternWeight > WEIGHT_MEDIUM )
     779        2976 :             nReqWeight += 100;
     780             : 
     781       16680 :         int nGivenWeight = (int)GetWeight();
     782       16680 :         if( GetWeight() > WEIGHT_MEDIUM )
     783        8340 :             nGivenWeight += 100;
     784             : 
     785       16680 :         int nWeightDiff = nReqWeight - nGivenWeight;
     786             : 
     787       16680 :         if ( nWeightDiff == 0 )
     788        8326 :             nMatch += 1000;
     789        8354 :         else if ( nWeightDiff == +1 || nWeightDiff == -1 )
     790           0 :             nMatch += 700;
     791        8354 :         else if ( nWeightDiff < +50 && nWeightDiff > -50)
     792          14 :             nMatch += 200;
     793             :     }
     794             :     else // requested weight == WEIGHT_DONTKNOW
     795             :     {
     796             :         // prefer NORMAL font weight
     797             :         // TODO: change when the upper layers can tell their weight preference
     798         192 :         if( GetWeight() == WEIGHT_NORMAL )
     799          96 :             nMatch += 450;
     800          96 :         else if( GetWeight() == WEIGHT_MEDIUM )
     801           0 :             nMatch += 350;
     802          96 :         else if( (GetWeight() == WEIGHT_SEMILIGHT) || (GetWeight() == WEIGHT_SEMIBOLD) )
     803           0 :             nMatch += 200;
     804          96 :         else if( GetWeight() == WEIGHT_LIGHT )
     805           0 :             nMatch += 150;
     806             :     }
     807             : 
     808             :     // if requiring custom matrix to fake italic, prefer upright font
     809       16872 :     FontItalic ePatternItalic = rFSD.maItalicMatrix != ItalicMatrix() ? ITALIC_NONE : rFSD.GetSlant();
     810             : 
     811       16872 :     if ( ePatternItalic == ITALIC_NONE )
     812             :     {
     813       14972 :         if( GetSlant() == ITALIC_NONE )
     814        7486 :             nMatch += 900;
     815             :     }
     816             :     else
     817             :     {
     818        1900 :         if( ePatternItalic == GetSlant() )
     819         922 :             nMatch += 900;
     820         978 :         else if( GetSlant() != ITALIC_NONE )
     821          28 :             nMatch += 600;
     822             :     }
     823             : 
     824       16872 :     if( mbDevice )
     825           0 :         nMatch += 1;
     826             : 
     827       16872 :     int nHeightMatch = 0;
     828       16872 :     int nWidthMatch = 0;
     829             : 
     830       16872 :     if( IsScalable() )
     831             :     {
     832       16872 :         if( rFSD.mnOrientation != 0 )
     833         760 :             nMatch += 80;
     834       16112 :         else if( rFSD.mnWidth != 0 )
     835         732 :             nMatch += 25;
     836             :         else
     837       15380 :             nMatch += 5;
     838             :     }
     839             :     else
     840             :     {
     841           0 :         if( rFSD.mnHeight == mnHeight )
     842             :         {
     843           0 :             nMatch += 20;
     844           0 :             if( rFSD.mnWidth == mnWidth )
     845           0 :                 nMatch += 10;
     846             :         }
     847             :         else
     848             :         {
     849             :             // for non-scalable fonts the size difference is very important
     850             :             // prefer the smaller font face because of clipping/overlapping issues
     851           0 :             int nHeightDiff = (rFSD.mnHeight - mnHeight) * 1000;
     852           0 :             nHeightMatch = (nHeightDiff >= 0) ? -nHeightDiff : 100+nHeightDiff;
     853           0 :             if( rFSD.mnHeight )
     854           0 :                 nHeightMatch /= rFSD.mnHeight;
     855             : 
     856           0 :             if( (rFSD.mnWidth != 0) && (mnWidth != 0) && (rFSD.mnWidth != mnWidth) )
     857             :             {
     858           0 :                 int nWidthDiff = (rFSD.mnWidth - mnWidth) * 100;
     859           0 :                 nWidthMatch = (nWidthDiff >= 0) ? -nWidthDiff : +nWidthDiff;
     860             :             }
     861             :         }
     862             :     }
     863             : 
     864       16872 :     if( rStatus.mnFaceMatch > nMatch )
     865       11167 :         return false;
     866        5705 :     else if( rStatus.mnFaceMatch < nMatch )
     867             :     {
     868        5705 :         rStatus.mnFaceMatch      = nMatch;
     869        5705 :         rStatus.mnHeightMatch    = nHeightMatch;
     870        5705 :         rStatus.mnWidthMatch     = nWidthMatch;
     871        5705 :         return true;
     872             :     }
     873             : 
     874             :     // when two fonts are still competing prefer the
     875             :     // one with the best matching height
     876           0 :     if( rStatus.mnHeightMatch > nHeightMatch )
     877           0 :         return false;
     878           0 :     else if( rStatus.mnHeightMatch < nHeightMatch )
     879             :     {
     880           0 :         rStatus.mnHeightMatch    = nHeightMatch;
     881           0 :         rStatus.mnWidthMatch     = nWidthMatch;
     882           0 :         return true;
     883             :     }
     884             : 
     885           0 :     if( rStatus.mnWidthMatch > nWidthMatch )
     886           0 :         return false;
     887             : 
     888           0 :     rStatus.mnWidthMatch = nWidthMatch;
     889           0 :     return true;
     890             : }
     891             : 
     892        4892 : ImplFontEntry::ImplFontEntry( const FontSelectPattern& rFontSelData )
     893             : :   maFontSelData( rFontSelData ),
     894             :     maMetric( rFontSelData ),
     895             :     mpConversion( NULL ),
     896             :     mnRefCount( 1 ),
     897             :     mnSetFontFlags( 0 ),
     898             :     mnOwnOrientation( 0 ),
     899             :     mnOrientation( 0 ),
     900             :     mbInit( false ),
     901        4892 :     mpUnicodeFallbackList( NULL )
     902             : {
     903        4892 :     maFontSelData.mpFontEntry = this;
     904        4892 : }
     905             : 
     906        7804 : ImplFontEntry::~ImplFontEntry()
     907             : {
     908        3902 :     delete mpUnicodeFallbackList;
     909        3902 : }
     910             : 
     911        1052 : size_t ImplFontEntry::GFBCacheKey_Hash::operator()( const GFBCacheKey& rData ) const
     912             : {
     913             :     boost::hash<sal_UCS4> a;
     914             :     boost::hash<int > b;
     915        1052 :     return a(rData.first) ^ b(rData.second);
     916             : }
     917             : 
     918          75 : inline void ImplFontEntry::AddFallbackForUnicode( sal_UCS4 cChar, FontWeight eWeight, const String& rFontName )
     919             : {
     920          75 :     if( !mpUnicodeFallbackList )
     921          52 :         mpUnicodeFallbackList = new UnicodeFallbackList;
     922          75 :     (*mpUnicodeFallbackList)[ GFBCacheKey(cChar,eWeight) ] = rFontName;
     923          75 : }
     924             : 
     925        1081 : inline bool ImplFontEntry::GetFallbackForUnicode( sal_UCS4 cChar, FontWeight eWeight, OUString* pFontName ) const
     926             : {
     927        1081 :     if( !mpUnicodeFallbackList )
     928         104 :         return false;
     929             : 
     930         977 :     UnicodeFallbackList::const_iterator it = mpUnicodeFallbackList->find( GFBCacheKey(cChar,eWeight) );
     931         977 :     if( it == mpUnicodeFallbackList->end() )
     932          39 :         return false;
     933             : 
     934         938 :     *pFontName = (*it).second;
     935         938 :     return true;
     936             : }
     937             : 
     938           0 : inline void ImplFontEntry::IgnoreFallbackForUnicode( sal_UCS4 cChar, FontWeight eWeight, const String& rFontName )
     939             : {
     940             : //  DBG_ASSERT( mpUnicodeFallbackList, "ImplFontEntry::IgnoreFallbackForUnicode no list" );
     941           0 :     UnicodeFallbackList::iterator it = mpUnicodeFallbackList->find( GFBCacheKey(cChar,eWeight) );
     942             : //  DBG_ASSERT( it != mpUnicodeFallbackList->end(), "ImplFontEntry::IgnoreFallbackForUnicode no match" );
     943           0 :     if( it == mpUnicodeFallbackList->end() )
     944           0 :         return;
     945           0 :     if( (*it).second == rFontName )
     946           0 :         mpUnicodeFallbackList->erase( it );
     947             : }
     948             : 
     949       93254 : ImplDevFontListData::ImplDevFontListData( const String& rSearchName )
     950             : :   mpFirst( NULL ),
     951             :     maSearchName( rSearchName ),
     952             :     mnTypeFaces( 0 ),
     953             :     mnMatchType( 0 ),
     954             :     meMatchWeight( WEIGHT_DONTKNOW ),
     955             :     meMatchWidth( WIDTH_DONTKNOW ),
     956             :     meFamily( FAMILY_DONTKNOW ),
     957             :     mePitch( PITCH_DONTKNOW ),
     958       93254 :     mnMinQuality( -1 )
     959       93254 : {}
     960             : 
     961      178620 : ImplDevFontListData::~ImplDevFontListData()
     962             : {
     963             :     // release all physical font faces
     964      377287 :     while( mpFirst )
     965             :     {
     966      198667 :         PhysicalFontFace* pFace = mpFirst;
     967      198667 :         mpFirst = pFace->GetNextFace();
     968      198667 :         delete pFace;
     969             :     }
     970       89310 : }
     971             : 
     972      213340 : bool ImplDevFontListData::AddFontFace( PhysicalFontFace* pNewData )
     973             : {
     974      213340 :     pNewData->mpNext = NULL;
     975             : 
     976      213340 :     if( !mpFirst )
     977             :     {
     978       93254 :         maName         = pNewData->GetFamilyName();
     979       93254 :         maMapNames     = pNewData->maMapNames;
     980       93254 :         meFamily       = pNewData->GetFamilyType();
     981       93254 :         mePitch        = pNewData->GetPitch();
     982       93254 :         mnMinQuality   = pNewData->mnQuality;
     983             :     }
     984             :     else
     985             :     {
     986      120086 :         if( meFamily == FAMILY_DONTKNOW )
     987      114578 :             meFamily = pNewData->GetFamilyType();
     988      120086 :         if( mePitch == PITCH_DONTKNOW )
     989           0 :             mePitch = pNewData->GetPitch();
     990      120086 :         if( mnMinQuality > pNewData->mnQuality )
     991       45663 :             mnMinQuality = pNewData->mnQuality;
     992             :     }
     993             : 
     994             :     // set attributes for attribute based font matching
     995      213340 :     if( pNewData->IsScalable() )
     996      213340 :         mnTypeFaces |= IMPL_DEVFONT_SCALABLE;
     997             : 
     998      213340 :     if( pNewData->IsSymbolFont() )
     999        4632 :         mnTypeFaces |= IMPL_DEVFONT_SYMBOL;
    1000             :     else
    1001      208708 :         mnTypeFaces |= IMPL_DEVFONT_NONESYMBOL;
    1002             : 
    1003      213340 :     if( pNewData->GetWeight() != WEIGHT_DONTKNOW )
    1004             :     {
    1005      213340 :         if( pNewData->GetWeight() >= WEIGHT_SEMIBOLD )
    1006       82692 :             mnTypeFaces |= IMPL_DEVFONT_BOLD;
    1007      130648 :         else if( pNewData->GetWeight() <= WEIGHT_SEMILIGHT )
    1008       10536 :             mnTypeFaces |= IMPL_DEVFONT_LIGHT;
    1009             :         else
    1010      120112 :             mnTypeFaces |= IMPL_DEVFONT_NORMAL;
    1011             :     }
    1012             : 
    1013      213340 :     if( pNewData->GetSlant() == ITALIC_NONE )
    1014      137858 :         mnTypeFaces |= IMPL_DEVFONT_NONEITALIC;
    1015      150964 :     else if( (pNewData->GetSlant() == ITALIC_NORMAL)
    1016       75482 :          ||  (pNewData->GetSlant() == ITALIC_OBLIQUE) )
    1017       75482 :         mnTypeFaces |= IMPL_DEVFONT_ITALIC;
    1018             : 
    1019      213340 :     if( (meMatchWeight == WEIGHT_DONTKNOW)
    1020           0 :     ||  (meMatchWidth  == WIDTH_DONTKNOW)
    1021           0 :     ||  (mnMatchType   == 0) )
    1022             :     {
    1023             :         // TODO: is it cheaper to calc matching attributes now or on demand?
    1024             :         // calc matching attributes if other entries are already initialized
    1025             : 
    1026             :         // Do lazy, quite expensive, not needed in start-up!
    1027             :         // const FontSubstConfiguration& rFontSubst = *FontSubstConfiguration::get();
    1028             :         // InitMatchData( rFontSubst, maSearchName );
    1029             :         // mbMatchData=true; // Somewhere else???
    1030             :     }
    1031             : 
    1032             :     // reassign name (sharing saves memory)
    1033      213340 :     if( pNewData->GetFamilyName() == GetFamilyName() )
    1034      213340 :         pNewData->SetFamilyName( GetFamilyName() );
    1035             : 
    1036             :     // insert new physical font face into linked list
    1037             :     // TODO: get rid of linear search?
    1038             :     PhysicalFontFace* pData;
    1039      213340 :     PhysicalFontFace** ppHere = &mpFirst;
    1040      425682 :     for(; (pData=*ppHere) != NULL; ppHere=&pData->mpNext )
    1041             :     {
    1042      230876 :         sal_Int32 eComp = pNewData->CompareWithSize( *pData );
    1043      230876 :         if( eComp == COMPARE_GREATER )
    1044      212342 :             continue;
    1045       18534 :         if( eComp == COMPARE_LESS )
    1046       12154 :             break;
    1047             : 
    1048             :         // ignore duplicate if its quality is worse
    1049        6380 :         if( pNewData->mnQuality < pData->mnQuality )
    1050        3364 :             return false;
    1051             : 
    1052             :         // keep the device font if its quality is good enough
    1053        3016 :         if( (pNewData->mnQuality == pData->mnQuality)
    1054        3016 :         &&  (pData->mbDevice || !pNewData->mbDevice) )
    1055        3016 :             return false;
    1056             : 
    1057             :         // replace existing font face with a better one
    1058           0 :         pNewData->mpNext = pData->mpNext;
    1059           0 :         *ppHere = pNewData;
    1060           0 :         delete pData;
    1061           0 :         return true;
    1062             :     }
    1063             : 
    1064             :     // insert into or append to list of physical font faces
    1065      206960 :     pNewData->mpNext = pData;
    1066      206960 :     *ppHere = pNewData;
    1067      206960 :     return true;
    1068             : }
    1069             : 
    1070             : // get font attributes using the normalized font family name
    1071           0 : void ImplDevFontListData::InitMatchData( const utl::FontSubstConfiguration& rFontSubst,
    1072             :     const String& rSearchName )
    1073             : {
    1074           0 :     OUString aShortName;
    1075           0 :     OUString aMatchFamilyName(maMatchFamilyName);
    1076             :     // get font attributes from the decorated font name
    1077             :     rFontSubst.getMapName( rSearchName, aShortName, aMatchFamilyName,
    1078           0 :                             meMatchWeight, meMatchWidth, mnMatchType );
    1079           0 :     maMatchFamilyName = aMatchFamilyName;
    1080           0 :     const FontNameAttr* pFontAttr = rFontSubst.getSubstInfo( rSearchName );
    1081             :     // eventually use the stripped name
    1082           0 :     if( !pFontAttr )
    1083           0 :         if( aShortName != rSearchName )
    1084           0 :             pFontAttr = rFontSubst.getSubstInfo( aShortName );
    1085           0 :     ImplCalcType( mnMatchType, meMatchWeight, meMatchWidth, meFamily, pFontAttr );
    1086           0 :     mnMatchType |= ImplIsCJKFont( maName );
    1087           0 : }
    1088             : 
    1089        4892 : PhysicalFontFace* ImplDevFontListData::FindBestFontFace( const FontSelectPattern& rFSD ) const
    1090             : {
    1091        4892 :     if( !mpFirst )
    1092           0 :         return NULL;
    1093        4892 :     if( !mpFirst->GetNextFace() )
    1094         674 :         return mpFirst;
    1095             : 
    1096             :     // FontName+StyleName should map to FamilyName+StyleName
    1097        4218 :     const String& rSearchName = rFSD.maTargetName;
    1098        4218 :     const sal_Unicode* pTargetStyleName = NULL;
    1099        8436 :     if( (rSearchName.Len() > maSearchName.Len())
    1100        4218 :     &&   rSearchName.Equals( maSearchName, 0, maSearchName.Len() ) )
    1101           0 :         pTargetStyleName = rSearchName.GetBuffer() + maSearchName.Len() + 1;
    1102             : 
    1103             :     // TODO: linear search improve!
    1104        4218 :     PhysicalFontFace* pFontFace = mpFirst;
    1105        4218 :     PhysicalFontFace* pBestFontFace = pFontFace;
    1106        4218 :     FontMatchStatus aFontMatchStatus = {0,0,0, pTargetStyleName};
    1107       21090 :     for(; pFontFace; pFontFace = pFontFace->GetNextFace() )
    1108       16872 :         if( pFontFace->IsBetterMatch( rFSD, aFontMatchStatus ) )
    1109        5705 :             pBestFontFace = pFontFace;
    1110             : 
    1111        4218 :     return pBestFontFace;
    1112             : }
    1113             : 
    1114             : // update device font list with unique font faces, with uniqueness
    1115             : // meaning different font attributes, but not different fonts sizes
    1116      114212 : void ImplDevFontListData::UpdateDevFontList( ImplGetDevFontList& rDevFontList ) const
    1117             : {
    1118      114212 :     PhysicalFontFace* pPrevFace = NULL;
    1119      369863 :     for( PhysicalFontFace* pFace = mpFirst; pFace; pFace = pFace->GetNextFace() )
    1120             :     {
    1121      255651 :         if( !pPrevFace || pFace->CompareIgnoreSize( *pPrevFace ) )
    1122      255651 :             rDevFontList.Add( pFace );
    1123      255651 :         pPrevFace = pFace;
    1124             :     }
    1125      114212 : }
    1126             : 
    1127         772 : void ImplDevFontListData::GetFontHeights( std::set<int>& rHeights ) const
    1128             : {
    1129             :     // add all available font heights
    1130        3860 :     for( const PhysicalFontFace* pFace = mpFirst; pFace; pFace = pFace->GetNextFace() )
    1131        3088 :         rHeights.insert( pFace->GetHeight() );
    1132         772 : }
    1133             : 
    1134       78601 : void ImplDevFontListData::UpdateCloneFontList( ImplDevFontList& rDevFontList,
    1135             :     bool bScalable, bool bEmbeddable ) const
    1136             : {
    1137      251692 :     for( PhysicalFontFace* pFace = mpFirst; pFace; pFace = pFace->GetNextFace() )
    1138             :     {
    1139      173091 :         if( bScalable && !pFace->IsScalable() )
    1140           0 :             continue;
    1141      173091 :         if( bEmbeddable && !pFace->IsEmbeddable() && !pFace->IsSubsettable() )
    1142           0 :             continue;
    1143             : 
    1144      173091 :         PhysicalFontFace* pClonedFace = pFace->Clone();
    1145      173091 :         rDevFontList.Add( pClonedFace );
    1146             :     }
    1147       78601 : }
    1148             : 
    1149        1461 : ImplDevFontList::ImplDevFontList()
    1150             : :   mbMatchData( false )
    1151             : ,   mbMapNames( false )
    1152             : ,   mpPreMatchHook( NULL )
    1153             : ,   mpFallbackHook( NULL )
    1154             : ,   mpFallbackList( NULL )
    1155        1461 : ,   mnFallbackCount( -1 )
    1156        1461 : {}
    1157             : 
    1158        4137 : ImplDevFontList::~ImplDevFontList()
    1159             : {
    1160        1379 :     Clear();
    1161        2758 : }
    1162             : 
    1163         207 : void ImplDevFontList::SetPreMatchHook( ImplPreMatchFontSubstitution* pHook )
    1164             : {
    1165         207 :     mpPreMatchHook = pHook;
    1166         207 : }
    1167             : 
    1168         207 : void ImplDevFontList::SetFallbackHook( ImplGlyphFallbackFontSubstitution* pHook )
    1169             : {
    1170         207 :     mpFallbackHook = pHook;
    1171         207 : }
    1172             : 
    1173        2667 : void ImplDevFontList::Clear()
    1174             : {
    1175             :     // remove fallback lists
    1176        2667 :     delete[] mpFallbackList;
    1177        2667 :     mpFallbackList = NULL;
    1178        2667 :     mnFallbackCount = -1;
    1179             : 
    1180             :     // clear all entries in the device font list
    1181        2667 :     DevFontList::iterator it = maDevFontList.begin();
    1182       91977 :     for(; it != maDevFontList.end(); ++it )
    1183             :     {
    1184       89310 :         ImplDevFontListData* pEntry = (*it).second;
    1185       89310 :         delete pEntry;
    1186             :     }
    1187             : 
    1188        2667 :     maDevFontList.clear();
    1189             : 
    1190             :     // match data must be recalculated too
    1191        2667 :     mbMatchData = false;
    1192        2667 : }
    1193             : 
    1194          27 : void ImplDevFontList::InitGenericGlyphFallback( void ) const
    1195             : {
    1196             :     // normalized family names of fonts suited for glyph fallback
    1197             :     // if a font is available related fonts can be ignored
    1198             :     // TODO: implement dynamic lists
    1199             :     static const char* aGlyphFallbackList[] = {
    1200             :         // empty strings separate the names of unrelated fonts
    1201             :         "eudc", "",
    1202             :         "arialunicodems", "cyberbit", "code2000", "",
    1203             :         "andalesansui", "",
    1204             :         "starsymbol", "opensymbol", "",
    1205             :         "msmincho", "fzmingti", "fzheiti", "ipamincho", "sazanamimincho", "kochimincho", "",
    1206             :         "sunbatang", "sundotum", "baekmukdotum", "gulim", "batang", "dotum", "",
    1207             :         "hgmincholightj", "msunglightsc", "msunglighttc", "hymyeongjolightk", "",
    1208             :         "tahoma", "dejavusans", "timesnewroman", "liberationsans", "",
    1209             :         "shree", "mangal", "",
    1210             :         "raavi", "shruti", "tunga", "",
    1211             :         "latha", "gautami", "kartika", "vrinda", "",
    1212             :         "shayyalmt", "naskmt", "scheherazade", "",
    1213             :         "david", "nachlieli", "lucidagrande", "",
    1214             :         "norasi", "angsanaupc", "",
    1215             :         "khmerossystem", "",
    1216             :         "muktinarrow", "",
    1217             :         "phetsarathot", "",
    1218             :         "padauk", "pinlonmyanmar", "",
    1219             :         "iskoolapota", "lklug", "",
    1220             :         0
    1221             :     };
    1222             : 
    1223          27 :     bool bHasEudc = false;
    1224          27 :     int nMaxLevel = 0;
    1225          27 :     int nBestQuality = 0;
    1226          27 :     ImplDevFontListData** pFallbackList = NULL;
    1227        1890 :     for( const char** ppNames = &aGlyphFallbackList[0];; ++ppNames )
    1228             :     {
    1229             :         // advance to next sub-list when end-of-sublist marker
    1230        1890 :         if( !**ppNames ) // #i46456# check for empty string, i.e., deref string itself not only ptr to it
    1231             :         {
    1232         513 :             if( nBestQuality > 0 )
    1233         135 :                 if( ++nMaxLevel >= MAX_FALLBACK )
    1234          27 :                     break;
    1235         513 :             if( !ppNames[1] )
    1236          27 :                 break;
    1237         486 :             nBestQuality = 0;
    1238        2187 :             continue;
    1239             :         }
    1240             : 
    1241             :         // test if the glyph fallback candidate font is available and scalable
    1242        1377 :         String aTokenName( *ppNames, RTL_TEXTENCODING_UTF8 );
    1243        1377 :         ImplDevFontListData* pFallbackFont = FindFontFamily( aTokenName );
    1244        1377 :         if( !pFallbackFont )
    1245        1215 :             continue;
    1246         162 :         if( !pFallbackFont->IsScalable() )
    1247           0 :             continue;
    1248             : 
    1249             :         // keep the best font of the glyph fallback sub-list
    1250         162 :         if( nBestQuality < pFallbackFont->GetMinQuality() )
    1251             :         {
    1252         135 :             nBestQuality = pFallbackFont->GetMinQuality();
    1253             :             // store available glyph fallback fonts
    1254         135 :             if( !pFallbackList )
    1255          27 :                 pFallbackList = new ImplDevFontListData*[ MAX_FALLBACK ];
    1256         135 :             pFallbackList[ nMaxLevel ] = pFallbackFont;
    1257         135 :             if( !bHasEudc && !nMaxLevel )
    1258          27 :                 bHasEudc = !strncmp( *ppNames, "eudc", 5 );
    1259             :         }
    1260        2025 :     }
    1261             : 
    1262             : #ifdef SAL_FONTENUM_STABLE_ON_PLATFORM // #i113472#
    1263             :     // sort the list of fonts for glyph fallback by quality (highest first)
    1264             :     // #i33947# keep the EUDC font at the front of the list
    1265             :     // an insertion sort is good enough for this short list
    1266             :     const int nSortStart = bHasEudc ? 1 : 0;
    1267             :     for( int i = nSortStart+1, j; i < nMaxLevel; ++i )
    1268             :     {
    1269             :         ImplDevFontListData* pTestFont = pFallbackList[ i ];
    1270             :         int nTestQuality = pTestFont->GetMinQuality();
    1271             :         for( j = i; --j >= nSortStart; )
    1272             :             if( nTestQuality > pFallbackList[j]->GetMinQuality() )
    1273             :                 pFallbackList[ j+1 ] = pFallbackList[ j ];
    1274             :             else
    1275             :                 break;
    1276             :         pFallbackList[ j+1 ] = pTestFont;
    1277             :     }
    1278             : #endif
    1279             : 
    1280          27 :     mnFallbackCount = nMaxLevel;
    1281          27 :     mpFallbackList  = pFallbackList;
    1282          27 : }
    1283             : 
    1284       12835 : ImplDevFontListData* ImplDevFontList::GetGlyphFallbackFont( FontSelectPattern& rFontSelData,
    1285             :     OUString& rMissingCodes, int nFallbackLevel ) const
    1286             : {
    1287       12835 :     ImplDevFontListData* pFallbackData = NULL;
    1288             : 
    1289             :     // find a matching font candidate for platform specific glyph fallback
    1290       12835 :     if( mpFallbackHook )
    1291             :     {
    1292             :         // check cache for the first matching entry
    1293             :         // to avoid calling the expensive fallback hook (#i83491#)
    1294       12835 :         sal_UCS4 cChar = 0;
    1295       12835 :         bool bCached = true;
    1296       12835 :         sal_Int32 nStrIndex = 0;
    1297       26573 :         while( nStrIndex < rMissingCodes.getLength() )
    1298             :         {
    1299        1005 :             cChar = rMissingCodes.iterateCodePoints( &nStrIndex );
    1300        1005 :             bCached = rFontSelData.mpFontEntry->GetFallbackForUnicode( cChar, rFontSelData.GetWeight(), &rFontSelData.maSearchName );
    1301             :             // ignore entries which don't have a fallback
    1302        1005 :             if( !bCached || !rFontSelData.maSearchName.isEmpty() )
    1303         102 :                 break;
    1304             :         }
    1305             : 
    1306       12835 :         if( bCached )
    1307             :         {
    1308             :             // there is a matching fallback in the cache
    1309             :             // so update rMissingCodes with codepoints not yet resolved by this fallback
    1310       12767 :             int nRemainingLength = 0;
    1311       12767 :             sal_UCS4* pRemainingCodes = (sal_UCS4*)alloca( rMissingCodes.getLength() * sizeof(sal_UCS4) );
    1312       12767 :             OUString aFontName;
    1313       25534 :             while( nStrIndex < rMissingCodes.getLength() )
    1314             :             {
    1315           0 :                 cChar = rMissingCodes.iterateCodePoints( &nStrIndex );
    1316           0 :                 bCached = rFontSelData.mpFontEntry->GetFallbackForUnicode( cChar, rFontSelData.GetWeight(), &aFontName );
    1317           0 :                 if( !bCached || (rFontSelData.maSearchName != aFontName) )
    1318           0 :                     pRemainingCodes[ nRemainingLength++ ] = cChar;
    1319             :             }
    1320       12767 :             rMissingCodes = OUString( pRemainingCodes, nRemainingLength );
    1321             :         }
    1322             :         else
    1323             :         {
    1324          68 :             OUString aOldMissingCodes = rMissingCodes;
    1325             :             // call the hook to query the best matching glyph fallback font
    1326          68 :             if( mpFallbackHook->FindFontSubstitute( rFontSelData, rMissingCodes ) )
    1327             :                 // apply outdev3.cxx specific fontname normalization
    1328          10 :                 GetEnglishSearchFontName( rFontSelData.maSearchName );
    1329             :             else
    1330          58 :                 rFontSelData.maSearchName = OUString();
    1331             : 
    1332             :             // See fdo#32665 for an example. FreeSerif that has glyphs in normal
    1333             :             // font, but not in the italic or bold version
    1334          68 :             bool bSubSetOfFontRequiresPropertyFaking = rFontSelData.mbEmbolden || rFontSelData.maItalicMatrix != ItalicMatrix();
    1335             : 
    1336             :             // Cache the result even if there was no match, unless its from part of a font for which the properties need
    1337             :             // to be faked. We need to rework this cache to take into account that fontconfig can return different fonts
    1338             :             // for different input sizes, weights, etc. Basically the cache is way to naive
    1339          76 :             if (!bSubSetOfFontRequiresPropertyFaking)
    1340             :             {
    1341             :                 for(;;)
    1342             :                 {
    1343          76 :                      if( !rFontSelData.mpFontEntry->GetFallbackForUnicode( cChar, rFontSelData.GetWeight(), &rFontSelData.maSearchName ) )
    1344          75 :                          rFontSelData.mpFontEntry->AddFallbackForUnicode( cChar, rFontSelData.GetWeight(), rFontSelData.maSearchName );
    1345          76 :                      if( nStrIndex >= aOldMissingCodes.getLength() )
    1346          68 :                          break;
    1347           8 :                      cChar = aOldMissingCodes.iterateCodePoints( &nStrIndex );
    1348             :                 }
    1349          68 :                 if( !rFontSelData.maSearchName.isEmpty() )
    1350             :                 {
    1351             :                     // remove cache entries that were still not resolved
    1352          20 :                     for( nStrIndex = 0; nStrIndex < rMissingCodes.getLength(); )
    1353             :                     {
    1354           0 :                         cChar = rMissingCodes.iterateCodePoints( &nStrIndex );
    1355           0 :                         rFontSelData.mpFontEntry->IgnoreFallbackForUnicode( cChar, rFontSelData.GetWeight(), rFontSelData.maSearchName );
    1356             :                     }
    1357             :                 }
    1358          68 :             }
    1359             :         }
    1360             : 
    1361             :         // find the matching device font
    1362       12835 :         if( !rFontSelData.maSearchName.isEmpty() )
    1363       11874 :             pFallbackData = FindFontFamily( rFontSelData.maSearchName );
    1364             :     }
    1365             : 
    1366             :     // else find a matching font candidate for generic glyph fallback
    1367       12835 :     if( !pFallbackData )
    1368             :     {
    1369             :         // initialize font candidates for generic glyph fallback if needed
    1370         961 :         if( mnFallbackCount < 0 )
    1371          27 :             InitGenericGlyphFallback();
    1372             :         // TODO: adjust nFallbackLevel by number of levels resolved by the fallback hook
    1373         961 :         if( nFallbackLevel < mnFallbackCount )
    1374         961 :             pFallbackData = mpFallbackList[ nFallbackLevel ];
    1375             :     }
    1376             : 
    1377       12835 :     return pFallbackData;
    1378             : }
    1379             : 
    1380      213340 : void ImplDevFontList::Add( PhysicalFontFace* pNewData )
    1381             : {
    1382      213340 :     OUString aSearchName = pNewData->GetFamilyName();
    1383      213340 :     GetEnglishSearchFontName( aSearchName );
    1384             : 
    1385      213340 :     DevFontList::const_iterator it = maDevFontList.find( aSearchName );
    1386      213340 :     ImplDevFontListData* pFoundData = NULL;
    1387      213340 :     if( it != maDevFontList.end() )
    1388      120086 :         pFoundData = (*it).second;
    1389             : 
    1390      213340 :     if( !pFoundData )
    1391             :     {
    1392       93254 :         pFoundData = new ImplDevFontListData( aSearchName );
    1393       93254 :         maDevFontList[ aSearchName ] = pFoundData;
    1394             :     }
    1395             : 
    1396      213340 :     bool bKeepNewData = pFoundData->AddFontFace( pNewData );
    1397             : 
    1398      213340 :     if( !bKeepNewData )
    1399        6380 :         delete pNewData;
    1400      213340 : }
    1401             : 
    1402             : // find the font from the normalized font family name
    1403     1163743 : ImplDevFontListData* ImplDevFontList::ImplFindBySearchName( const OUString& rSearchName ) const
    1404             : {
    1405             : #ifdef DEBUG
    1406             :     OUString aTempName = rSearchName;
    1407             :     GetEnglishSearchFontName( aTempName );
    1408             :     DBG_ASSERT( aTempName == rSearchName, "ImplDevFontList::ImplFindBySearchName() called with non-normalized name" );
    1409             : #endif
    1410             : 
    1411     1163743 :     DevFontList::const_iterator it = maDevFontList.find( rSearchName );
    1412     1163743 :     if( it == maDevFontList.end() )
    1413      335944 :         return NULL;
    1414             : 
    1415      827799 :     ImplDevFontListData* pFoundData = (*it).second;
    1416      827799 :     return pFoundData;
    1417             : }
    1418             : 
    1419           0 : ImplDevFontListData* ImplDevFontList::ImplFindByAliasName(const OUString& rSearchName,
    1420             :     const OUString& rShortName) const
    1421             : {
    1422             :     // short circuit for impossible font name alias
    1423           0 :     if (rSearchName.isEmpty())
    1424           0 :         return NULL;
    1425             : 
    1426             :     // short circuit if no alias names are available
    1427           0 :     if (!mbMapNames)
    1428           0 :         return NULL;
    1429             : 
    1430             :     // use the font's alias names to find the font
    1431             :     // TODO: get rid of linear search
    1432           0 :     DevFontList::const_iterator it = maDevFontList.begin();
    1433           0 :     while( it != maDevFontList.end() )
    1434             :     {
    1435           0 :         ImplDevFontListData* pData = (*it).second;
    1436           0 :         if( pData->maMapNames.isEmpty() )
    1437           0 :             continue;
    1438             : 
    1439             :         // if one alias name matches we found a matching font
    1440           0 :         OUString aTempName;
    1441           0 :         sal_Int32 nIndex = 0;
    1442           0 :         do
    1443             :         {
    1444           0 :            aTempName = GetNextFontToken( pData->maMapNames, nIndex );
    1445             :            // Test, if the Font name match with one of the mapping names
    1446           0 :            if ( (aTempName == rSearchName) || (aTempName == rShortName) )
    1447           0 :               return pData;
    1448             :         }
    1449           0 :         while ( nIndex != -1 );
    1450           0 :      }
    1451             : 
    1452           0 :      return NULL;
    1453             : }
    1454             : 
    1455       15003 : ImplDevFontListData* ImplDevFontList::FindFontFamily( const String& rFontName ) const
    1456             : {
    1457             :     // normalize the font family name and
    1458       15003 :     OUString aName = rFontName;
    1459       15003 :     GetEnglishSearchFontName( aName );
    1460       15003 :     ImplDevFontListData* pFound = ImplFindBySearchName( aName );
    1461       15003 :     return pFound;
    1462             : }
    1463             : 
    1464           0 : ImplDevFontListData* ImplDevFontList::ImplFindByTokenNames(const OUString& rTokenStr) const
    1465             : {
    1466           0 :     ImplDevFontListData* pFoundData = NULL;
    1467             : 
    1468             :     // use normalized font name tokens to find the font
    1469           0 :     for( sal_Int32 nTokenPos = 0; nTokenPos != -1; )
    1470             :     {
    1471           0 :         OUString aSearchName = GetNextFontToken( rTokenStr, nTokenPos );
    1472           0 :         if( aSearchName.isEmpty() )
    1473           0 :             continue;
    1474           0 :         GetEnglishSearchFontName( aSearchName );
    1475           0 :         pFoundData = ImplFindBySearchName( aSearchName );
    1476           0 :         if( pFoundData )
    1477           0 :             break;
    1478           0 :     }
    1479             : 
    1480           0 :     return pFoundData;
    1481             : }
    1482             : 
    1483        1761 : ImplDevFontListData* ImplDevFontList::ImplFindBySubstFontAttr( const utl::FontNameAttr& rFontAttr ) const
    1484             : {
    1485        1761 :     ImplDevFontListData* pFoundData = NULL;
    1486             : 
    1487             :     // use the font substitutions suggested by the FontNameAttr to find the font
    1488        1761 :     ::std::vector< OUString >::const_iterator it = rFontAttr.Substitutions.begin();
    1489         151 :     for(; it != rFontAttr.Substitutions.end(); ++it )
    1490             :     {
    1491        1912 :         OUString aSearchName( *it );
    1492        1912 :         GetEnglishSearchFontName( aSearchName );
    1493             : 
    1494        1912 :         pFoundData = ImplFindBySearchName( aSearchName );
    1495        1912 :         if( pFoundData )
    1496        1761 :             return pFoundData;
    1497         151 :     }
    1498             : 
    1499             :     // use known attributes from the configuration to find a matching substitute
    1500           0 :     const sal_uLong nSearchType = rFontAttr.Type;
    1501           0 :     if( nSearchType != 0 )
    1502             :     {
    1503           0 :         const FontWeight eSearchWeight = rFontAttr.Weight;
    1504           0 :         const FontWidth  eSearchWidth  = rFontAttr.Width;
    1505           0 :         const FontItalic eSearchSlant  = ITALIC_DONTKNOW;
    1506           0 :         const String aSearchName;
    1507             :         pFoundData = ImplFindByAttributes( nSearchType,
    1508           0 :             eSearchWeight, eSearchWidth, eSearchSlant, aSearchName );
    1509           0 :         if( pFoundData )
    1510           0 :             return pFoundData;
    1511             :     }
    1512             : 
    1513           0 :     return NULL;
    1514             : }
    1515             : 
    1516           0 : void ImplDevFontList::InitMatchData() const
    1517             : {
    1518             :     // short circuit if already done
    1519           0 :     if( mbMatchData )
    1520           0 :         return;
    1521           0 :     mbMatchData = true;
    1522             : 
    1523             :     // calculate MatchData for all entries
    1524           0 :     const FontSubstConfiguration& rFontSubst = FontSubstConfiguration::get();
    1525             : 
    1526           0 :     DevFontList::const_iterator it = maDevFontList.begin();
    1527           0 :     for(; it != maDevFontList.end(); ++it )
    1528             :     {
    1529           0 :         const String& rSearchName = (*it).first;
    1530           0 :         ImplDevFontListData* pEntry = (*it).second;
    1531             : 
    1532           0 :         pEntry->InitMatchData( rFontSubst, rSearchName );
    1533             :     }
    1534             : }
    1535             : 
    1536           0 : ImplDevFontListData* ImplDevFontList::ImplFindByAttributes( sal_uLong nSearchType,
    1537             :     FontWeight eSearchWeight, FontWidth eSearchWidth,
    1538             :     FontItalic eSearchItalic, const OUString& rSearchFamilyName ) const
    1539             : {
    1540           0 :     if( (eSearchItalic != ITALIC_NONE) && (eSearchItalic != ITALIC_DONTKNOW) )
    1541           0 :         nSearchType |= IMPL_FONT_ATTR_ITALIC;
    1542             : 
    1543             :     // don't bother to match attributes if the attributes aren't worth matching
    1544           0 :     if( !nSearchType
    1545           0 :     && ((eSearchWeight == WEIGHT_DONTKNOW) || (eSearchWeight == WEIGHT_NORMAL))
    1546           0 :     && ((eSearchWidth == WIDTH_DONTKNOW) || (eSearchWidth == WIDTH_NORMAL)) )
    1547           0 :         return NULL;
    1548             : 
    1549           0 :     InitMatchData();
    1550           0 :     ImplDevFontListData* pFoundData = NULL;
    1551             : 
    1552             :     long    nTestMatch;
    1553           0 :     long    nBestMatch = 40000;
    1554           0 :     sal_uLong   nBestType = 0;
    1555             : 
    1556           0 :     DevFontList::const_iterator it = maDevFontList.begin();
    1557           0 :     for(; it != maDevFontList.end(); ++it )
    1558             :     {
    1559           0 :         ImplDevFontListData* pData = (*it).second;
    1560             : 
    1561             :         // Get all information about the matching font
    1562           0 :         sal_uLong       nMatchType  = pData->mnMatchType;
    1563           0 :         FontWeight  eMatchWeight= pData->meMatchWeight;
    1564           0 :         FontWidth   eMatchWidth = pData->meMatchWidth;
    1565             : 
    1566             :         // Calculate Match Value
    1567             :         // 1000000000
    1568             :         //  100000000
    1569             :         //   10000000   CJK, CTL, None-Latin, Symbol
    1570             :         //    1000000   FamilyName, Script, Fixed, -Special, -Decorative,
    1571             :         //              Titling, Capitals, Outline, Shadow
    1572             :         //     100000   Match FamilyName, Serif, SansSerif, Italic,
    1573             :         //              Width, Weight
    1574             :         //      10000   Scalable, Standard, Default,
    1575             :         //              full, Normal, Knownfont,
    1576             :         //              Otherstyle, +Special, +Decorative,
    1577             :         //       1000   Typewriter, Rounded, Gothic, Schollbook
    1578             :         //        100
    1579           0 :         nTestMatch = 0;
    1580             : 
    1581             :         // test CJK script attributes
    1582           0 :         if ( nSearchType & IMPL_FONT_ATTR_CJK )
    1583             :         {
    1584             :             // Matching language
    1585           0 :             if( 0 == ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_CJK_ALLLANG) )
    1586           0 :                 nTestMatch += 10000000*3;
    1587           0 :             if( nMatchType & IMPL_FONT_ATTR_CJK )
    1588           0 :                 nTestMatch += 10000000*2;
    1589           0 :             if( nMatchType & IMPL_FONT_ATTR_FULL )
    1590           0 :                 nTestMatch += 10000000;
    1591             :         }
    1592           0 :         else if ( nMatchType & IMPL_FONT_ATTR_CJK )
    1593           0 :             nTestMatch -= 10000000;
    1594             : 
    1595             :         // test CTL script attributes
    1596           0 :         if( nSearchType & IMPL_FONT_ATTR_CTL )
    1597             :         {
    1598           0 :             if( nMatchType & IMPL_FONT_ATTR_CTL )
    1599           0 :                 nTestMatch += 10000000*2;
    1600           0 :             if( nMatchType & IMPL_FONT_ATTR_FULL )
    1601           0 :                 nTestMatch += 10000000;
    1602             :         }
    1603           0 :         else if ( nMatchType & IMPL_FONT_ATTR_CTL )
    1604           0 :             nTestMatch -= 10000000;
    1605             : 
    1606             :         // test LATIN script attributes
    1607           0 :         if( nSearchType & IMPL_FONT_ATTR_NONELATIN )
    1608             :         {
    1609           0 :             if( nMatchType & IMPL_FONT_ATTR_NONELATIN )
    1610           0 :                 nTestMatch += 10000000*2;
    1611           0 :             if( nMatchType & IMPL_FONT_ATTR_FULL )
    1612           0 :                 nTestMatch += 10000000;
    1613             :         }
    1614             : 
    1615             :         // test SYMBOL attributes
    1616           0 :         if ( nSearchType & IMPL_FONT_ATTR_SYMBOL )
    1617             :         {
    1618           0 :             const String& rSearchName = it->first;
    1619             :             // prefer some special known symbol fonts
    1620           0 :             if ( rSearchName.EqualsAscii( "starsymbol" ) )
    1621           0 :                 nTestMatch += 10000000*6+(10000*3);
    1622           0 :             else if ( rSearchName.EqualsAscii( "opensymbol" ) )
    1623           0 :                 nTestMatch += 10000000*6;
    1624           0 :             else if ( rSearchName.EqualsAscii( "starbats" )
    1625           0 :             ||        rSearchName.EqualsAscii( "wingdings" )
    1626           0 :             ||        rSearchName.EqualsAscii( "monotypesorts" )
    1627           0 :             ||        rSearchName.EqualsAscii( "dingbats" )
    1628           0 :             ||        rSearchName.EqualsAscii( "zapfdingbats" ) )
    1629           0 :                 nTestMatch += 10000000*5;
    1630           0 :             else if ( pData->mnTypeFaces & IMPL_DEVFONT_SYMBOL )
    1631           0 :                 nTestMatch += 10000000*4;
    1632             :             else
    1633             :             {
    1634           0 :                 if( nMatchType & IMPL_FONT_ATTR_SYMBOL )
    1635           0 :                     nTestMatch += 10000000*2;
    1636           0 :                 if( nMatchType & IMPL_FONT_ATTR_FULL )
    1637           0 :                     nTestMatch += 10000000;
    1638             :             }
    1639             :         }
    1640           0 :         else if ( (pData->mnTypeFaces & (IMPL_DEVFONT_SYMBOL | IMPL_DEVFONT_NONESYMBOL)) == IMPL_DEVFONT_SYMBOL )
    1641           0 :             nTestMatch -= 10000000;
    1642           0 :         else if ( nMatchType & IMPL_FONT_ATTR_SYMBOL )
    1643           0 :             nTestMatch -= 10000;
    1644             : 
    1645             :         // match stripped family name
    1646           0 :         if( !rSearchFamilyName.isEmpty() && (rSearchFamilyName.equals(pData->maMatchFamilyName)) )
    1647           0 :             nTestMatch += 1000000*3;
    1648             : 
    1649             :         // match ALLSCRIPT? attribute
    1650           0 :         if( nSearchType & IMPL_FONT_ATTR_ALLSCRIPT )
    1651             :         {
    1652           0 :             if( nMatchType & IMPL_FONT_ATTR_ALLSCRIPT )
    1653           0 :                 nTestMatch += 1000000*2;
    1654           0 :             if( nSearchType & IMPL_FONT_ATTR_ALLSUBSCRIPT )
    1655             :             {
    1656           0 :                 if( 0 == ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_ALLSUBSCRIPT) )
    1657           0 :                     nTestMatch += 1000000*2;
    1658           0 :                 if( 0 != ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_BRUSHSCRIPT) )
    1659           0 :                     nTestMatch -= 1000000;
    1660             :             }
    1661             :         }
    1662           0 :         else if( nMatchType & IMPL_FONT_ATTR_ALLSCRIPT )
    1663           0 :             nTestMatch -= 1000000;
    1664             : 
    1665             :         // test MONOSPACE+TYPEWRITER attributes
    1666           0 :         if( nSearchType & IMPL_FONT_ATTR_FIXED )
    1667             :         {
    1668           0 :             if( nMatchType & IMPL_FONT_ATTR_FIXED )
    1669           0 :                 nTestMatch += 1000000*2;
    1670             :             // a typewriter attribute is even better
    1671           0 :             if( 0 == ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_TYPEWRITER) )
    1672           0 :                 nTestMatch += 10000*2;
    1673             :         }
    1674           0 :         else if( nMatchType & IMPL_FONT_ATTR_FIXED )
    1675           0 :             nTestMatch -= 1000000;
    1676             : 
    1677             :         // test SPECIAL attribute
    1678           0 :         if( nSearchType & IMPL_FONT_ATTR_SPECIAL )
    1679             :         {
    1680           0 :             if( nMatchType & IMPL_FONT_ATTR_SPECIAL )
    1681           0 :                 nTestMatch += 10000;
    1682           0 :             else if( !(nSearchType & IMPL_FONT_ATTR_ALLSERIFSTYLE) )
    1683             :             {
    1684           0 :                  if( nMatchType & IMPL_FONT_ATTR_SERIF )
    1685           0 :                      nTestMatch += 1000*2;
    1686           0 :                  else if( nMatchType & IMPL_FONT_ATTR_SANSSERIF )
    1687           0 :                      nTestMatch += 1000;
    1688             :              }
    1689             :         }
    1690           0 :         else if( (nMatchType & IMPL_FONT_ATTR_SPECIAL) && !(nSearchType & IMPL_FONT_ATTR_SYMBOL) )
    1691           0 :             nTestMatch -= 1000000;
    1692             : 
    1693             :         // test DECORATIVE attribute
    1694           0 :         if( nSearchType & IMPL_FONT_ATTR_DECORATIVE )
    1695             :         {
    1696           0 :             if( nMatchType & IMPL_FONT_ATTR_DECORATIVE )
    1697           0 :                 nTestMatch += 10000;
    1698           0 :             else if( !(nSearchType & IMPL_FONT_ATTR_ALLSERIFSTYLE) )
    1699             :             {
    1700           0 :                 if( nMatchType & IMPL_FONT_ATTR_SERIF )
    1701           0 :                     nTestMatch += 1000*2;
    1702           0 :                 else if ( nMatchType & IMPL_FONT_ATTR_SANSSERIF )
    1703           0 :                     nTestMatch += 1000;
    1704             :             }
    1705             :         }
    1706           0 :         else if( nMatchType & IMPL_FONT_ATTR_DECORATIVE )
    1707           0 :             nTestMatch -= 1000000;
    1708             : 
    1709             :         // test TITLE+CAPITALS attributes
    1710           0 :         if( nSearchType & (IMPL_FONT_ATTR_TITLING | IMPL_FONT_ATTR_CAPITALS) )
    1711             :         {
    1712           0 :             if( nMatchType & (IMPL_FONT_ATTR_TITLING | IMPL_FONT_ATTR_CAPITALS) )
    1713           0 :                 nTestMatch += 1000000*2;
    1714           0 :             if( 0 == ((nSearchType^nMatchType) & (IMPL_FONT_ATTR_TITLING | IMPL_FONT_ATTR_CAPITALS)))
    1715           0 :                 nTestMatch += 1000000;
    1716           0 :             else if( (nMatchType & (IMPL_FONT_ATTR_TITLING | IMPL_FONT_ATTR_CAPITALS))
    1717           0 :             &&       (nMatchType & (IMPL_FONT_ATTR_STANDARD | IMPL_FONT_ATTR_DEFAULT)) )
    1718           0 :                 nTestMatch += 1000000;
    1719             :         }
    1720           0 :         else if( nMatchType & (IMPL_FONT_ATTR_TITLING | IMPL_FONT_ATTR_CAPITALS) )
    1721           0 :             nTestMatch -= 1000000;
    1722             : 
    1723             :         // test OUTLINE+SHADOW attributes
    1724           0 :         if( nSearchType & (IMPL_FONT_ATTR_OUTLINE | IMPL_FONT_ATTR_SHADOW) )
    1725             :         {
    1726           0 :             if( nMatchType & (IMPL_FONT_ATTR_OUTLINE | IMPL_FONT_ATTR_SHADOW) )
    1727           0 :                 nTestMatch += 1000000*2;
    1728           0 :             if( 0 == ((nSearchType ^ nMatchType) & (IMPL_FONT_ATTR_OUTLINE | IMPL_FONT_ATTR_SHADOW)) )
    1729           0 :                 nTestMatch += 1000000;
    1730           0 :             else if( (nMatchType & (IMPL_FONT_ATTR_OUTLINE | IMPL_FONT_ATTR_SHADOW))
    1731           0 :             &&       (nMatchType & (IMPL_FONT_ATTR_STANDARD | IMPL_FONT_ATTR_DEFAULT)) )
    1732           0 :                 nTestMatch += 1000000;
    1733             :         }
    1734           0 :         else if ( nMatchType & (IMPL_FONT_ATTR_OUTLINE | IMPL_FONT_ATTR_SHADOW) )
    1735           0 :             nTestMatch -= 1000000;
    1736             : 
    1737             :         // test font name substrings
    1738             :         // TODO: calculate name matching score using e.g. Levenstein distance
    1739           0 :         if( (rSearchFamilyName.getLength() >= 4) && (pData->maMatchFamilyName.Len() >= 4)
    1740           0 :         &&    ((rSearchFamilyName.indexOf( pData->maMatchFamilyName ) != -1)
    1741           0 :             || (pData->maMatchFamilyName.Search( rSearchFamilyName ) != STRING_NOTFOUND)) )
    1742           0 :                     nTestMatch += 5000;
    1743             : 
    1744             :         // test SERIF attribute
    1745           0 :         if( nSearchType & IMPL_FONT_ATTR_SERIF )
    1746             :         {
    1747           0 :             if( nMatchType & IMPL_FONT_ATTR_SERIF )
    1748           0 :                 nTestMatch += 1000000*2;
    1749           0 :             else if( nMatchType & IMPL_FONT_ATTR_SANSSERIF )
    1750           0 :                 nTestMatch -= 1000000;
    1751             :         }
    1752             : 
    1753             :         // test SANSERIF attribute
    1754           0 :         if( nSearchType & IMPL_FONT_ATTR_SANSSERIF )
    1755             :         {
    1756           0 :             if( nMatchType & IMPL_FONT_ATTR_SANSSERIF )
    1757           0 :                 nTestMatch += 1000000;
    1758           0 :             else if ( nMatchType & IMPL_FONT_ATTR_SERIF )
    1759           0 :                 nTestMatch -= 1000000;
    1760             :         }
    1761             : 
    1762             :         // test ITALIC attribute
    1763           0 :         if( nSearchType & IMPL_FONT_ATTR_ITALIC )
    1764             :         {
    1765           0 :             if( pData->mnTypeFaces & IMPL_DEVFONT_ITALIC )
    1766           0 :                 nTestMatch += 1000000*3;
    1767           0 :             if( nMatchType & IMPL_FONT_ATTR_ITALIC )
    1768           0 :                 nTestMatch += 1000000;
    1769             :         }
    1770           0 :         else if( !(nSearchType & IMPL_FONT_ATTR_ALLSCRIPT)
    1771           0 :             &&  ((nMatchType & IMPL_FONT_ATTR_ITALIC)
    1772           0 :                 || !(pData->mnTypeFaces & IMPL_DEVFONT_NONEITALIC)) )
    1773           0 :             nTestMatch -= 1000000*2;
    1774             : 
    1775             :         // test WIDTH attribute
    1776           0 :         if( (eSearchWidth != WIDTH_DONTKNOW) && (eSearchWidth != WIDTH_NORMAL) )
    1777             :         {
    1778           0 :             if( eSearchWidth < WIDTH_NORMAL )
    1779             :             {
    1780           0 :                 if( eSearchWidth == eMatchWidth )
    1781           0 :                     nTestMatch += 1000000*3;
    1782           0 :                 else if( (eMatchWidth < WIDTH_NORMAL) && (eMatchWidth != WIDTH_DONTKNOW) )
    1783           0 :                     nTestMatch += 1000000;
    1784             :             }
    1785             :             else
    1786             :             {
    1787           0 :                 if( eSearchWidth == eMatchWidth )
    1788           0 :                     nTestMatch += 1000000*3;
    1789           0 :                 else if( eMatchWidth > WIDTH_NORMAL )
    1790           0 :                     nTestMatch += 1000000;
    1791             :             }
    1792             :         }
    1793           0 :         else if( (eMatchWidth != WIDTH_DONTKNOW) && (eMatchWidth != WIDTH_NORMAL) )
    1794           0 :             nTestMatch -= 1000000;
    1795             : 
    1796             :         // test WEIGHT attribute
    1797           0 :         if( (eSearchWeight != WEIGHT_DONTKNOW) && (eSearchWeight != WEIGHT_NORMAL) && (eSearchWeight != WEIGHT_MEDIUM) )
    1798             :         {
    1799           0 :             if( eSearchWeight < WEIGHT_NORMAL )
    1800             :             {
    1801           0 :                 if( pData->mnTypeFaces & IMPL_DEVFONT_LIGHT )
    1802           0 :                     nTestMatch += 1000000;
    1803           0 :                 if( (eMatchWeight < WEIGHT_NORMAL) && (eMatchWeight != WEIGHT_DONTKNOW) )
    1804           0 :                     nTestMatch += 1000000;
    1805             :             }
    1806             :             else
    1807             :             {
    1808           0 :                 if( pData->mnTypeFaces & IMPL_DEVFONT_BOLD )
    1809           0 :                     nTestMatch += 1000000;
    1810           0 :                 if( eMatchWeight > WEIGHT_BOLD )
    1811           0 :                     nTestMatch += 1000000;
    1812             :             }
    1813             :         }
    1814           0 :         else if( ((eMatchWeight != WEIGHT_DONTKNOW) && (eMatchWeight != WEIGHT_NORMAL) && (eMatchWeight != WEIGHT_MEDIUM))
    1815           0 :             || !(pData->mnTypeFaces & IMPL_DEVFONT_NORMAL) )
    1816           0 :             nTestMatch -= 1000000;
    1817             : 
    1818             :         // prefer scalable fonts
    1819           0 :         if( pData->mnTypeFaces & IMPL_DEVFONT_SCALABLE )
    1820           0 :             nTestMatch += 10000*4;
    1821             :         else
    1822           0 :             nTestMatch -= 10000*4;
    1823             : 
    1824             :         // test STANDARD+DEFAULT+FULL+NORMAL attributes
    1825           0 :         if( nMatchType & IMPL_FONT_ATTR_STANDARD )
    1826           0 :             nTestMatch += 10000*2;
    1827           0 :         if( nMatchType & IMPL_FONT_ATTR_DEFAULT )
    1828           0 :             nTestMatch += 10000;
    1829           0 :         if( nMatchType & IMPL_FONT_ATTR_FULL )
    1830           0 :             nTestMatch += 10000;
    1831           0 :         if( nMatchType & IMPL_FONT_ATTR_NORMAL )
    1832           0 :             nTestMatch += 10000;
    1833             : 
    1834             :         // test OTHERSTYLE attribute
    1835           0 :         if( ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_OTHERSTYLE) != 0 )
    1836             :         {
    1837           0 :             nTestMatch -= 10000;
    1838             :         }
    1839             : 
    1840             :         // test ROUNDED attribute
    1841           0 :         if( 0 == ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_ROUNDED) )
    1842           0 :             nTestMatch += 1000;
    1843             : 
    1844             :         // test TYPEWRITER attribute
    1845           0 :         if( 0 == ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_TYPEWRITER) )
    1846           0 :             nTestMatch += 1000;
    1847             : 
    1848             :         // test GOTHIC attribute
    1849           0 :         if( nSearchType & IMPL_FONT_ATTR_GOTHIC )
    1850             :         {
    1851           0 :             if( nMatchType & IMPL_FONT_ATTR_GOTHIC )
    1852           0 :                 nTestMatch += 1000*3;
    1853           0 :             if( nMatchType & IMPL_FONT_ATTR_SANSSERIF )
    1854           0 :                 nTestMatch += 1000*2;
    1855             :         }
    1856             : 
    1857             :         // test SCHOOLBOOK attribute
    1858           0 :         if( nSearchType & IMPL_FONT_ATTR_SCHOOLBOOK )
    1859             :         {
    1860           0 :             if( nMatchType & IMPL_FONT_ATTR_SCHOOLBOOK )
    1861           0 :                 nTestMatch += 1000*3;
    1862           0 :             if( nMatchType & IMPL_FONT_ATTR_SERIF )
    1863           0 :                 nTestMatch += 1000*2;
    1864             :         }
    1865             : 
    1866             :         // compare with best matching font yet
    1867           0 :         if ( nTestMatch > nBestMatch )
    1868             :         {
    1869           0 :             pFoundData  = pData;
    1870           0 :             nBestMatch  = nTestMatch;
    1871           0 :             nBestType   = nMatchType;
    1872             :         }
    1873           0 :         else if( nTestMatch == nBestMatch )
    1874             :         {
    1875             :             // some fonts are more suitable defaults
    1876           0 :             if( nMatchType & IMPL_FONT_ATTR_DEFAULT )
    1877             :             {
    1878           0 :                 pFoundData  = pData;
    1879           0 :                 nBestType   = nMatchType;
    1880             :             }
    1881           0 :             else if( (nMatchType & IMPL_FONT_ATTR_STANDARD) &&
    1882           0 :                     !(nBestType & IMPL_FONT_ATTR_DEFAULT) )
    1883             :             {
    1884           0 :                  pFoundData  = pData;
    1885           0 :                  nBestType   = nMatchType;
    1886             :             }
    1887             :         }
    1888             :     }
    1889             : 
    1890           0 :     return pFoundData;
    1891             : }
    1892             : 
    1893           0 : ImplDevFontListData* ImplDevFontList::FindDefaultFont() const
    1894             : {
    1895             :     // try to find one of the default fonts of the
    1896             :     // UNICODE, SANSSERIF, SERIF or FIXED default font lists
    1897           0 :     const DefaultFontConfiguration& rDefaults = DefaultFontConfiguration::get();
    1898           0 :     com::sun::star::lang::Locale aLocale( OUString( "en" ), OUString(), OUString() );
    1899           0 :     String aFontname = rDefaults.getDefaultFont( aLocale, DEFAULTFONT_SANS_UNICODE );
    1900           0 :     ImplDevFontListData* pFoundData = ImplFindByTokenNames( aFontname );
    1901           0 :     if( pFoundData )
    1902           0 :         return pFoundData;
    1903             : 
    1904           0 :     aFontname = rDefaults.getDefaultFont( aLocale, DEFAULTFONT_SANS );
    1905           0 :     pFoundData = ImplFindByTokenNames( aFontname );
    1906           0 :     if( pFoundData )
    1907           0 :         return pFoundData;
    1908             : 
    1909           0 :     aFontname = rDefaults.getDefaultFont( aLocale, DEFAULTFONT_SERIF );
    1910           0 :     pFoundData = ImplFindByTokenNames( aFontname );
    1911           0 :     if( pFoundData )
    1912           0 :         return pFoundData;
    1913             : 
    1914           0 :     aFontname = rDefaults.getDefaultFont( aLocale, DEFAULTFONT_FIXED );
    1915           0 :     pFoundData = ImplFindByTokenNames( aFontname );
    1916           0 :     if( pFoundData )
    1917           0 :         return pFoundData;
    1918             : 
    1919             :     // now try to find a reasonable non-symbol font
    1920             : 
    1921           0 :     InitMatchData();
    1922             : 
    1923           0 :     DevFontList::const_iterator it = maDevFontList.begin();
    1924           0 :     for(; it !=  maDevFontList.end(); ++it )
    1925             :     {
    1926           0 :         ImplDevFontListData* pData = (*it).second;
    1927           0 :         if( pData->mnMatchType & IMPL_FONT_ATTR_SYMBOL )
    1928           0 :             continue;
    1929           0 :         pFoundData = pData;
    1930           0 :         if( pData->mnMatchType & (IMPL_FONT_ATTR_DEFAULT|IMPL_FONT_ATTR_STANDARD) )
    1931           0 :             break;
    1932             :     }
    1933           0 :     if( pFoundData )
    1934           0 :         return pFoundData;
    1935             : 
    1936             :     // finding any font is better than finding no font at all
    1937           0 :     it = maDevFontList.begin();
    1938           0 :     if( it !=  maDevFontList.end() )
    1939           0 :         pFoundData = (*it).second;
    1940             : 
    1941           0 :     return pFoundData;
    1942             : }
    1943             : 
    1944        1233 : ImplDevFontList* ImplDevFontList::Clone( bool bScalable, bool bEmbeddable ) const
    1945             : {
    1946        1233 :     ImplDevFontList* pClonedList = new ImplDevFontList;
    1947        1233 :     pClonedList->mbMapNames     = mbMapNames;
    1948        1233 :     pClonedList->mpPreMatchHook = mpPreMatchHook;
    1949        1233 :     pClonedList->mpFallbackHook = mpFallbackHook;
    1950             : 
    1951             :     // TODO: clone the config-font attributes too?
    1952        1233 :     pClonedList->mbMatchData    = false;
    1953             : 
    1954        1233 :     DevFontList::const_iterator it = maDevFontList.begin();
    1955       79834 :     for(; it != maDevFontList.end(); ++it )
    1956             :     {
    1957       78601 :         const ImplDevFontListData* pFontFace = (*it).second;
    1958       78601 :         pFontFace->UpdateCloneFontList( *pClonedList, bScalable, bEmbeddable );
    1959             :     }
    1960             : 
    1961        1233 :     return pClonedList;
    1962             : }
    1963             : 
    1964        1741 : ImplGetDevFontList* ImplDevFontList::GetDevFontList() const
    1965             : {
    1966        1741 :     ImplGetDevFontList* pGetDevFontList = new ImplGetDevFontList;
    1967             : 
    1968        1741 :     DevFontList::const_iterator it = maDevFontList.begin();
    1969      115953 :     for(; it != maDevFontList.end(); ++it )
    1970             :     {
    1971      114212 :         const ImplDevFontListData* pFontFamily = (*it).second;
    1972      114212 :         pFontFamily->UpdateDevFontList( *pGetDevFontList );
    1973             :     }
    1974             : 
    1975        1741 :     return pGetDevFontList;
    1976             : }
    1977             : 
    1978         777 : ImplGetDevSizeList* ImplDevFontList::GetDevSizeList( const String& rFontName ) const
    1979             : {
    1980         777 :     ImplGetDevSizeList* pGetDevSizeList = new ImplGetDevSizeList( rFontName );
    1981             : 
    1982         777 :     ImplDevFontListData* pFontFamily = FindFontFamily( rFontName );
    1983         777 :     if( pFontFamily != NULL )
    1984             :     {
    1985         772 :         std::set<int> rHeights;
    1986         772 :         pFontFamily->GetFontHeights( rHeights );
    1987             : 
    1988         772 :         std::set<int>::const_iterator it = rHeights.begin();
    1989         772 :         for(; it != rHeights.begin(); ++it )
    1990         772 :             pGetDevSizeList->Add( *it );
    1991             :     }
    1992             : 
    1993         777 :     return pGetDevSizeList;
    1994             : }
    1995             : 
    1996      802155 : FontSelectPatternAttributes::FontSelectPatternAttributes( const Font& rFont,
    1997             :     const String& rSearchName, const Size& rSize, float fExactHeight )
    1998             :     : maSearchName( rSearchName )
    1999      802155 :     , mnWidth( rSize.Width() )
    2000      802155 :     , mnHeight( rSize.Height() )
    2001             :     , mfExactHeight( fExactHeight)
    2002      802155 :     , mnOrientation( rFont.GetOrientation() )
    2003      802155 :     , meLanguage( rFont.GetLanguage() )
    2004      802155 :     , mbVertical( rFont.IsVertical() )
    2005             :     , mbNonAntialiased( false )
    2006     4812930 :     , mbEmbolden( false )
    2007             : {
    2008      802155 :     maTargetName = GetFamilyName();
    2009             : 
    2010      802155 :     rFont.GetFontAttributes( *this );
    2011             : 
    2012             :     // normalize orientation between 0 and 3600
    2013      802155 :     if( 3600 <= (unsigned)mnOrientation )
    2014             :     {
    2015           0 :         if( mnOrientation >= 0 )
    2016           0 :             mnOrientation %= 3600;
    2017             :         else
    2018           0 :             mnOrientation = 3600 - (-mnOrientation % 3600);
    2019             :     }
    2020             : 
    2021             :     // normalize width and height
    2022      802155 :     if( mnHeight < 0 )
    2023           0 :         mnHeight = -mnHeight;
    2024      802155 :     if( mnWidth < 0 )
    2025           0 :         mnWidth = -mnWidth;
    2026      802155 : }
    2027             : 
    2028      802155 : FontSelectPattern::FontSelectPattern( const Font& rFont,
    2029             :     const String& rSearchName, const Size& rSize, float fExactHeight)
    2030             :     : FontSelectPatternAttributes(rFont, rSearchName, rSize, fExactHeight)
    2031             :     , mpFontData( NULL )
    2032      802155 :     , mpFontEntry( NULL )
    2033             : {
    2034      802155 : }
    2035             : 
    2036             : // NOTE: this ctor is still used on Windows. Do not remove.
    2037           0 : FontSelectPatternAttributes::FontSelectPatternAttributes( const PhysicalFontFace& rFontData,
    2038             :     const Size& rSize, float fExactHeight, int nOrientation, bool bVertical )
    2039             :     : ImplFontAttributes( rFontData )
    2040           0 :     , mnWidth( rSize.Width() )
    2041           0 :     , mnHeight( rSize.Height() )
    2042             :     , mfExactHeight( fExactHeight )
    2043             :     , mnOrientation( nOrientation )
    2044             :     , meLanguage( 0 )
    2045             :     , mbVertical( bVertical )
    2046             :     , mbNonAntialiased( false )
    2047           0 :     , mbEmbolden( false )
    2048             : {
    2049           0 :     maTargetName = maSearchName = GetFamilyName();
    2050             :     // NOTE: no normalization for width/height/orientation
    2051           0 : }
    2052             : 
    2053             : #ifdef WNT
    2054             : FontSelectPattern::FontSelectPattern( const PhysicalFontFace& rFontData,
    2055             :     const Size& rSize, float fExactHeight, int nOrientation, bool bVertical )
    2056             :     : FontSelectPatternAttributes(rFontData, rSize, fExactHeight, nOrientation, bVertical)
    2057             :     , mpFontData( &rFontData )
    2058             :     , mpFontEntry( NULL )
    2059             : {
    2060             : }
    2061             : #endif
    2062             : 
    2063      315848 : void FontSelectPattern::copyAttributes(const FontSelectPatternAttributes &rAttributes)
    2064             : {
    2065      315848 :     static_cast<FontSelectPatternAttributes&>(*this) = rAttributes;
    2066      315848 : }
    2067             : 
    2068     1635410 : size_t ImplFontCache::IFSD_Hash::operator()( const FontSelectPattern& rFSD ) const
    2069             : {
    2070     1635410 :     return rFSD.hashCode();
    2071             : }
    2072             : 
    2073     1635410 : size_t FontSelectPatternAttributes::hashCode() const
    2074             : {
    2075             :     // TODO: does it pay off to improve this hash function?
    2076             :     static FontNameHash aFontNameHash;
    2077     1635410 :     size_t nHash = aFontNameHash( maSearchName );
    2078             : #if ENABLE_GRAPHITE
    2079             :     // check for features and generate a unique hash if necessary
    2080     1635410 :     if (maTargetName.indexOf(grutils::GrFeatureParser::FEAT_PREFIX)
    2081             :         != -1)
    2082             :     {
    2083           0 :         nHash = aFontNameHash( maTargetName );
    2084             :     }
    2085             : #endif
    2086     1635410 :     nHash += 11 * mnHeight;
    2087     1635410 :     nHash += 19 * GetWeight();
    2088     1635410 :     nHash += 29 * GetSlant();
    2089     1635410 :     nHash += 37 * mnOrientation;
    2090     1635410 :     nHash += 41 * meLanguage;
    2091     1635410 :     if( mbVertical )
    2092           3 :         nHash += 53;
    2093     1635410 :     return nHash;
    2094             : }
    2095             : 
    2096      596348 : bool FontSelectPatternAttributes::operator==(const FontSelectPatternAttributes& rOther) const
    2097             : {
    2098      596348 :     if (static_cast<const ImplFontAttributes&>(*this) != static_cast<const ImplFontAttributes&>(rOther))
    2099      227401 :         return false;
    2100             : 
    2101      368947 :     if (maTargetName != rOther.maTargetName)
    2102           0 :         return false;
    2103             : 
    2104      368947 :     if (maSearchName != rOther.maSearchName)
    2105           0 :         return false;
    2106             : 
    2107      368947 :     if (mnWidth != rOther.mnWidth)
    2108       24939 :         return false;
    2109             : 
    2110      344008 :     if (mnHeight != rOther.mnHeight)
    2111       23241 :         return false;
    2112             : 
    2113      320767 :     if (mfExactHeight != rOther.mfExactHeight)
    2114         559 :         return false;
    2115             : 
    2116      320208 :     if (mnOrientation != rOther.mnOrientation)
    2117        2783 :         return false;
    2118             : 
    2119      317425 :     if (meLanguage != rOther.meLanguage)
    2120        1577 :         return false;
    2121             : 
    2122      315848 :     if (mbVertical != rOther.mbVertical)
    2123           0 :         return false;
    2124             : 
    2125      315848 :     if (mbNonAntialiased != rOther.mbNonAntialiased)
    2126           0 :         return false;
    2127             : 
    2128      315848 :     if (mbEmbolden != rOther.mbEmbolden)
    2129           0 :         return false;
    2130             : 
    2131      315848 :     if (maItalicMatrix != rOther.maItalicMatrix)
    2132           0 :         return false;
    2133             : 
    2134      315848 :     return true;
    2135             : }
    2136             : 
    2137     1644229 : bool ImplFontCache::IFSD_Equal::operator()(const FontSelectPattern& rA, const FontSelectPattern& rB) const
    2138             : {
    2139             :     // check normalized font family name
    2140     1644229 :     if( rA.maSearchName != rB.maSearchName )
    2141      813750 :         return false;
    2142             : 
    2143             :     // check font transformation
    2144      830479 :     if( (rA.mnHeight       != rB.mnHeight)
    2145      830479 :     ||  (rA.mnWidth        != rB.mnWidth)
    2146      817874 :     ||  (rA.mnOrientation  != rB.mnOrientation) )
    2147       12605 :         return false;
    2148             : 
    2149             :     // check mapping relevant attributes
    2150      817874 :     if( (rA.mbVertical     != rB.mbVertical)
    2151      817874 :     ||  (rA.meLanguage     != rB.meLanguage) )
    2152           0 :         return false;
    2153             : 
    2154             :     // check font face attributes
    2155     1635748 :     if( (rA.GetWeight()       != rB.GetWeight())
    2156      817874 :     ||  (rA.GetSlant()       != rB.GetSlant())
    2157             : //  ||  (rA.meFamily       != rB.meFamily) // TODO: remove this mostly obsolete member
    2158     1635748 :     ||  (rA.GetPitch()     != rB.GetPitch()) )
    2159        3959 :         return false;
    2160             : 
    2161             :     // check style name
    2162      813915 :     if( rA.GetStyleName() != rB.GetStyleName() )
    2163        3817 :         return false;
    2164             : 
    2165             :     // Symbol fonts may recode from one type to another So they are only
    2166             :     // safely equivalent for equal targets
    2167      810098 :     if (
    2168      831332 :         (rA.mpFontData && rA.mpFontData->IsSymbolFont()) ||
    2169      797349 :         (rB.mpFontData && rB.mpFontData->IsSymbolFont())
    2170             :        )
    2171             :     {
    2172       21234 :         if (rA.maTargetName != rB.maTargetName)
    2173           0 :             return false;
    2174             :     }
    2175             : 
    2176             : #if ENABLE_GRAPHITE
    2177             :     // check for features
    2178     1620196 :     if ((rA.maTargetName.indexOf(grutils::GrFeatureParser::FEAT_PREFIX)
    2179      810098 :          != -1 ||
    2180      810098 :          rB.maTargetName.indexOf(grutils::GrFeatureParser::FEAT_PREFIX)
    2181      810098 :          != -1) && rA.maTargetName != rB.maTargetName)
    2182           0 :         return false;
    2183             : #endif
    2184             : 
    2185      810098 :     if (rA.mbEmbolden != rB.mbEmbolden)
    2186           0 :         return false;
    2187             : 
    2188      810098 :     if (rA.maItalicMatrix != rB.maItalicMatrix)
    2189           0 :         return false;
    2190             : 
    2191      810098 :     return true;
    2192             : }
    2193             : 
    2194        1461 : ImplFontCache::ImplFontCache( bool bPrinter )
    2195             : :   mpFirstEntry( NULL ),
    2196             :     mnRef0Count( 0 ),
    2197        1461 :     mbPrinter( bPrinter )
    2198        1461 : {}
    2199             : 
    2200        2758 : ImplFontCache::~ImplFontCache()
    2201             : {
    2202        1379 :     FontInstanceList::iterator it = maFontInstanceList.begin();
    2203        4781 :     for(; it != maFontInstanceList.end(); ++it )
    2204             :     {
    2205        3402 :         ImplFontEntry* pEntry = (*it).second;
    2206        3402 :         delete pEntry;
    2207             :     }
    2208        1379 : }
    2209             : 
    2210      802155 : ImplFontEntry* ImplFontCache::GetFontEntry( ImplDevFontList* pFontList,
    2211             :     const Font& rFont, const Size& rSize, float fExactHeight, ImplDirectFontSubstitution* pDevSpecific )
    2212             : {
    2213      802155 :     String aSearchName = rFont.GetName();
    2214             : 
    2215             :     // initialize internal font request object
    2216     1604310 :     FontSelectPattern aFontSelData( rFont, aSearchName, rSize, fExactHeight );
    2217     1604310 :     return GetFontEntry( pFontList, aFontSelData, pDevSpecific );
    2218             : }
    2219             : 
    2220      814990 : ImplFontEntry* ImplFontCache::GetFontEntry( ImplDevFontList* pFontList,
    2221             :     FontSelectPattern& aFontSelData, ImplDirectFontSubstitution* pDevSpecific )
    2222             : {
    2223             :     // check if a directly matching logical font instance is already cached,
    2224             :     // the most recently used font usually has a hit rate of >50%
    2225      814990 :     ImplFontEntry *pEntry = NULL;
    2226      814990 :     ImplDevFontListData* pFontFamily = NULL;
    2227             :     IFSD_Equal aIFSD_Equal;
    2228      814990 :     if( mpFirstEntry && aIFSD_Equal( aFontSelData, mpFirstEntry->maFontSelData ) )
    2229           0 :         pEntry = mpFirstEntry;
    2230             :     else
    2231             :     {
    2232      814990 :         FontInstanceList::iterator it = maFontInstanceList.find( aFontSelData );
    2233      814990 :         if( it != maFontInstanceList.end() )
    2234           0 :             pEntry = (*it).second;
    2235             :     }
    2236             : 
    2237      814990 :     if( !pEntry ) // no direct cache hit
    2238             :     {
    2239             :         // find the best matching logical font family and update font selector accordingly
    2240      814990 :         pFontFamily = pFontList->ImplFindByFont( aFontSelData, mbPrinter, pDevSpecific );
    2241             :         DBG_ASSERT( (pFontFamily != NULL), "ImplFontCache::Get() No logical font found!" );
    2242      814990 :         if( pFontFamily )
    2243      814990 :             aFontSelData.maSearchName = pFontFamily->GetSearchName();
    2244             : 
    2245             :         // check if an indirectly matching logical font instance is already cached
    2246      814990 :         FontInstanceList::iterator it = maFontInstanceList.find( aFontSelData );
    2247      814990 :         if( it != maFontInstanceList.end() )
    2248             :         {
    2249             :             // we have an indirect cache hit
    2250      810098 :             pEntry = (*it).second;
    2251             :         }
    2252             :     }
    2253             : 
    2254      814990 :     PhysicalFontFace* pFontData = NULL;
    2255             : 
    2256      814990 :     if (!pEntry && pFontFamily)// no cache hit => find the best matching physical font face
    2257             :     {
    2258        4892 :         bool bOrigWasSymbol = aFontSelData.mpFontData && aFontSelData.mpFontData->IsSymbolFont();
    2259        4892 :         pFontData = pFontFamily->FindBestFontFace( aFontSelData );
    2260        4892 :         aFontSelData.mpFontData = pFontData;
    2261        4892 :         bool bNewIsSymbol = aFontSelData.mpFontData && aFontSelData.mpFontData->IsSymbolFont();
    2262             : 
    2263        4892 :         if (bNewIsSymbol != bOrigWasSymbol)
    2264             :         {
    2265             :             // it is possible, though generally unlikely, that at this point we
    2266             :             // will attempt to use a symbol font as a last-ditch fallback for a
    2267             :             // non-symbol font request or vice versa, and by changing
    2268             :             // aFontSelData.mpFontData to/from a symbol font we may now find
    2269             :             // something in the cache that can be reused which previously
    2270             :             // wasn't a candidate
    2271         538 :             FontInstanceList::iterator it = maFontInstanceList.find( aFontSelData );
    2272         538 :             if( it != maFontInstanceList.end() )
    2273           0 :                 pEntry = (*it).second;
    2274             :         }
    2275             :     }
    2276             : 
    2277      814990 :     if( pEntry ) // cache hit => use existing font instance
    2278             :     {
    2279             :         // increase the font instance's reference count
    2280      810098 :         if( !pEntry->mnRefCount++ )
    2281      287349 :             --mnRef0Count;
    2282             :     }
    2283             : 
    2284      814990 :     if (!pEntry && pFontData)// still no cache hit => create a new font instance
    2285             :     {
    2286             :         // create a new logical font instance from this physical font face
    2287        4892 :         pEntry = pFontData->CreateFontInstance( aFontSelData );
    2288             : 
    2289             :         // if we're subtituting from or to a symbol font we may need a symbol
    2290             :         // conversion table
    2291        4892 :         if( pFontData->IsSymbolFont() || aFontSelData.IsSymbolFont() )
    2292             :         {
    2293         496 :             if( aFontSelData.maTargetName != aFontSelData.maSearchName )
    2294         496 :                 pEntry->mpConversion = ConvertChar::GetRecodeData( aFontSelData.maTargetName, aFontSelData.maSearchName );
    2295             : #ifdef MACOSX
    2296             :             //It might be better to dig out the font version of the target font
    2297             :             //to see if it's a modern re-coded apple symbol font in case that
    2298             :             //font shows up on a different platform
    2299             :             if (!pEntry->mpConversion &&
    2300             :                 aFontSelData.maTargetName.equalsIgnoreAsciiCase("symbol") &&
    2301             :                 aFontSelData.maSearchName.equalsIgnoreAsciiCase("symbol"))
    2302             :             {
    2303             :                 pEntry->mpConversion = ConvertChar::GetRecodeData( OUString("Symbol"), OUString("AppleSymbol") );
    2304             :             }
    2305             : #endif
    2306             :         }
    2307             : 
    2308             :         // add the new entry to the cache
    2309        4892 :         maFontInstanceList[ aFontSelData ] = pEntry;
    2310             :     }
    2311             : 
    2312      814990 :     mpFirstEntry = pEntry;
    2313      814990 :     return pEntry;
    2314             : }
    2315             : 
    2316             : namespace
    2317             : {
    2318      330070 :     OUString stripCharSetFromName(OUString aName)
    2319             :     {
    2320             :         // I worry that someone will have a font which *does* have
    2321             :         // e.g. "Greek" legitimately at the end of its name :-(
    2322             :         const char*suffixes[] =
    2323             :         {
    2324             :             " baltic",
    2325             :             " ce",
    2326             :             " cyr",
    2327             :             " greek",
    2328             :             " tur",
    2329             :             " (arabic)",
    2330             :             " (hebrew)",
    2331             :             " (thai)",
    2332             :             " (vietnamese)"
    2333      330070 :         };
    2334             : 
    2335             :         // These can be crazily piled up, e.g. Times New Roman CYR Greek
    2336      330070 :         bool bFinished = false;
    2337      990217 :         while (!bFinished)
    2338             :         {
    2339      330077 :             bFinished = true;
    2340     3300770 :             for (size_t i = 0; i < SAL_N_ELEMENTS(suffixes); ++i)
    2341             :             {
    2342     2970693 :                 size_t nLen = strlen(suffixes[i]);
    2343     2970693 :                 if (aName.endsWithIgnoreAsciiCaseAsciiL(suffixes[i], nLen))
    2344             :                 {
    2345           7 :                     bFinished = false;
    2346           7 :                     aName = aName.copy(0, aName.getLength() - nLen);
    2347             :                 }
    2348             :             }
    2349             :         }
    2350      330070 :         return aName;
    2351             :     }
    2352             : }
    2353             : 
    2354      814990 : ImplDevFontListData* ImplDevFontList::ImplFindByFont( FontSelectPattern& rFSD,
    2355             :     bool bPrinter, ImplDirectFontSubstitution* pDevSpecific ) const
    2356             : {
    2357             :     // give up if no fonts are available
    2358      814990 :     if( !Count() )
    2359           0 :         return NULL;
    2360             : 
    2361             :     // test if a font in the token list is available
    2362             :     // substitute the font if this was requested
    2363      814990 :     sal_uInt16 nSubstFlags = FONT_SUBSTITUTE_ALWAYS;
    2364      814990 :     if ( bPrinter )
    2365         514 :         nSubstFlags |= FONT_SUBSTITUTE_SCREENONLY;
    2366             : 
    2367      814990 :     bool bMultiToken = false;
    2368      814990 :     sal_Int32 nTokenPos = 0;
    2369      814990 :     OUString& aSearchName = rFSD.maSearchName; // TODO: get rid of reference
    2370             :     for(;;)
    2371             :     {
    2372      814990 :         rFSD.maTargetName = GetNextFontToken( rFSD.GetFamilyName(), nTokenPos );
    2373      814990 :         aSearchName = rFSD.maTargetName;
    2374             : 
    2375             : #if ENABLE_GRAPHITE
    2376             :         // Until features are properly supported, they are appended to the
    2377             :         // font name, so we need to strip them off so the font is found.
    2378      814990 :         sal_Int32 nFeat = aSearchName.indexOf(grutils::GrFeatureParser::FEAT_PREFIX);
    2379      814990 :         String aOrigName = rFSD.maTargetName;
    2380      814990 :         String aBaseFontName(aSearchName, 0, (nFeat != -1)?nFeat:aSearchName.getLength());
    2381      814990 :         if (nFeat != -1 && -1 !=
    2382           0 :             aSearchName.indexOf(grutils::GrFeatureParser::FEAT_ID_VALUE_SEPARATOR, nFeat))
    2383             :         {
    2384           0 :             aSearchName = aBaseFontName;
    2385           0 :             rFSD.maTargetName = aBaseFontName;
    2386             :         }
    2387             : 
    2388             : #endif
    2389             : 
    2390      814990 :         GetEnglishSearchFontName( aSearchName );
    2391      814990 :         ImplFontSubstitute( aSearchName, nSubstFlags, pDevSpecific );
    2392             :         // #114999# special emboldening for Ricoh fonts
    2393             :         // TODO: smarter check for special cases by using PreMatch infrastructure?
    2394     1629980 :         if( (rFSD.GetWeight() > WEIGHT_MEDIUM)
    2395      814990 :         &&  aSearchName.startsWithIgnoreAsciiCase( "hg" ) )
    2396             :         {
    2397           0 :             OUString aBoldName;
    2398           0 :             if( aSearchName.startsWithIgnoreAsciiCase( "hggothicb" ) )
    2399           0 :                 aBoldName = OUString("hggothice");
    2400           0 :             else if( aSearchName.startsWithIgnoreAsciiCase( "hgpgothicb" ) )
    2401           0 :                 aBoldName = OUString("hgpgothice");
    2402           0 :             else if( aSearchName.startsWithIgnoreAsciiCase( "hgminchol" ) )
    2403           0 :                 aBoldName = OUString("hgminchob");
    2404           0 :             else if( aSearchName.startsWithIgnoreAsciiCase( "hgpminchol" ) )
    2405           0 :                 aBoldName = OUString("hgpminchob");
    2406           0 :             else if( aSearchName.equalsIgnoreAsciiCase( "hgminchob" ) )
    2407           0 :                 aBoldName = OUString("hgminchoe");
    2408           0 :             else if( aSearchName.equalsIgnoreAsciiCase( "hgpminchob" ) )
    2409           0 :                 aBoldName = OUString("hgpminchoe");
    2410             : 
    2411           0 :             if( !aBoldName.isEmpty() && ImplFindBySearchName( aBoldName ) )
    2412             :             {
    2413             :                 // the other font is available => use it
    2414           0 :                 aSearchName = aBoldName;
    2415             :                 // prevent synthetic emboldening of bold version
    2416           0 :                 rFSD.SetWeight(WEIGHT_DONTKNOW);
    2417           0 :             }
    2418             :         }
    2419             : 
    2420             : #if ENABLE_GRAPHITE
    2421             :         // restore the features to make the font selection data unique
    2422      814990 :         rFSD.maTargetName = aOrigName;
    2423             : #endif
    2424             :         // check if the current font name token or its substitute is valid
    2425      814990 :         ImplDevFontListData* pFoundData = ImplFindBySearchName( aSearchName );
    2426      814990 :         if( pFoundData )
    2427      484920 :             return pFoundData;
    2428             : 
    2429             :         // some systems provide special customization
    2430             :         // e.g. they suggest "serif" as UI-font, but this name cannot be used directly
    2431             :         //      because the system wants to map it to another font first, e.g. "Helvetica"
    2432             : #if ENABLE_GRAPHITE
    2433             :         // use the target name to search in the prematch hook
    2434      330070 :         rFSD.maTargetName = aBaseFontName;
    2435             : #endif
    2436             : 
    2437             :         // Related: fdo#49271 RTF files often contain weird-ass
    2438             :         // Win 3.1/Win95 style fontnames which attempt to put the
    2439             :         // charset encoding into the filename
    2440             :         // http://www.webcenter.ru/~kazarn/eng/fonts_ttf.htm
    2441      330070 :         OUString sStrippedName = stripCharSetFromName(rFSD.maTargetName);
    2442      330070 :         if (!sStrippedName.equals(rFSD.maTargetName))
    2443             :         {
    2444           7 :             rFSD.maTargetName = sStrippedName;
    2445           7 :             aSearchName = rFSD.maTargetName;
    2446           7 :             GetEnglishSearchFontName(aSearchName);
    2447           7 :             pFoundData = ImplFindBySearchName(aSearchName);
    2448           7 :             if( pFoundData )
    2449           0 :                 return pFoundData;
    2450             :         }
    2451             : 
    2452      330070 :         if( mpPreMatchHook )
    2453             :         {
    2454      330070 :             if( mpPreMatchHook->FindFontSubstitute( rFSD ) )
    2455      328309 :                 GetEnglishSearchFontName( aSearchName );
    2456             :         }
    2457             : #if ENABLE_GRAPHITE
    2458             :         // the prematch hook uses the target name to search, but we now need
    2459             :         // to restore the features to make the font selection data unique
    2460      330070 :         rFSD.maTargetName = aOrigName;
    2461             : #endif
    2462      330070 :         pFoundData = ImplFindBySearchName( aSearchName );
    2463      330070 :         if( pFoundData )
    2464      328309 :             return pFoundData;
    2465             : 
    2466             :         // break after last font name token was checked unsuccessfully
    2467        1761 :         if( nTokenPos == -1)
    2468        1761 :             break;
    2469           0 :         bMultiToken = true;
    2470           0 :     }
    2471             : 
    2472             :     // if the first font was not available find the next available font in
    2473             :     // the semicolon separated list of font names. A font is also considered
    2474             :     // available when there is a matching entry in the Tools->Options->Fonts
    2475             :     // dialog witho neither ALWAYS nor SCREENONLY flags set and the substitution
    2476             :     // font is available
    2477        5283 :     for( nTokenPos = 0; nTokenPos != -1; )
    2478             :     {
    2479        1761 :         if( bMultiToken )
    2480             :         {
    2481           0 :             rFSD.maTargetName = GetNextFontToken( rFSD.GetFamilyName(), nTokenPos );
    2482           0 :             aSearchName = rFSD.maTargetName;
    2483           0 :             GetEnglishSearchFontName( aSearchName );
    2484             :         }
    2485             :         else
    2486        1761 :             nTokenPos = -1;
    2487        1761 :         if( mpPreMatchHook )
    2488        1761 :             if( mpPreMatchHook->FindFontSubstitute( rFSD ) )
    2489           0 :                 GetEnglishSearchFontName( aSearchName );
    2490        1761 :         ImplFontSubstitute( aSearchName, nSubstFlags, pDevSpecific );
    2491        1761 :         ImplDevFontListData* pFoundData = ImplFindBySearchName( aSearchName );
    2492        1761 :         if( pFoundData )
    2493           0 :             return pFoundData;
    2494             :     }
    2495             : 
    2496             :     // if no font with a directly matching name is available use the
    2497             :     // first font name token and get its attributes to find a replacement
    2498        1761 :     if ( bMultiToken )
    2499             :     {
    2500           0 :         nTokenPos = 0;
    2501           0 :         rFSD.maTargetName = GetNextFontToken( rFSD.GetFamilyName(), nTokenPos );
    2502           0 :         aSearchName = rFSD.maTargetName;
    2503           0 :         GetEnglishSearchFontName( aSearchName );
    2504             :     }
    2505             : 
    2506        1761 :     OUString      aSearchShortName;
    2507        3522 :     OUString      aSearchFamilyName;
    2508        1761 :     FontWeight  eSearchWeight   = rFSD.GetWeight();
    2509        1761 :     FontWidth   eSearchWidth    = rFSD.GetWidthType();
    2510        1761 :     sal_uLong   nSearchType     = 0;
    2511             :     FontSubstConfiguration::getMapName( aSearchName, aSearchShortName, aSearchFamilyName,
    2512        1761 :                                         eSearchWeight, eSearchWidth, nSearchType );
    2513             : 
    2514             :     // note: the search name was already translated to english (if possible)
    2515             :     // use the font's shortened name if needed
    2516        1761 :     if ( aSearchShortName != aSearchName )
    2517             :     {
    2518           0 :        ImplDevFontListData* pFoundData = ImplFindBySearchName( aSearchShortName );
    2519           0 :        if( pFoundData )
    2520             :        {
    2521             : #ifdef UNX
    2522             :             /* #96738# don't use mincho as an replacement for "MS Mincho" on X11: Mincho is
    2523             :             a korean bitmap font that is not suitable here. Use the font replacement table,
    2524             :             that automatically leads to the desired "HG Mincho Light J". Same story for
    2525             :             MS Gothic, there are thai and korean "Gothic" fonts, so we even prefer Andale */
    2526           0 :             static OUString aMS_Mincho( "msmincho" );
    2527           0 :             static OUString aMS_Gothic( "msgothic" );
    2528           0 :             if ((aSearchName != aMS_Mincho) && (aSearchName != aMS_Gothic))
    2529             :                 // TODO: add heuristic to only throw out the fake ms* fonts
    2530             : #endif
    2531             :             {
    2532           0 :                 return pFoundData;
    2533             :             }
    2534             :         }
    2535             :     }
    2536             : 
    2537             :     // use font fallback
    2538        1761 :     const FontNameAttr* pFontAttr = NULL;
    2539        1761 :     if( !aSearchName.isEmpty() )
    2540             :     {
    2541             :         // get fallback info using FontSubstConfiguration and
    2542             :         // the target name, it's shortened name and family name in that order
    2543        1761 :         const FontSubstConfiguration& rFontSubst = FontSubstConfiguration::get();
    2544        1761 :         pFontAttr = rFontSubst.getSubstInfo( aSearchName );
    2545        1761 :         if ( !pFontAttr && (aSearchShortName != aSearchName) )
    2546           0 :             pFontAttr = rFontSubst.getSubstInfo( aSearchShortName );
    2547        1761 :         if ( !pFontAttr && (aSearchFamilyName != aSearchShortName) )
    2548           0 :             pFontAttr = rFontSubst.getSubstInfo( aSearchFamilyName );
    2549             : 
    2550             :         // try the font substitutions suggested by the fallback info
    2551        1761 :         if( pFontAttr )
    2552             :         {
    2553        1761 :             ImplDevFontListData* pFoundData = ImplFindBySubstFontAttr( *pFontAttr );
    2554        1761 :             if( pFoundData )
    2555        1761 :                 return pFoundData;
    2556             :         }
    2557             :     }
    2558             : 
    2559             :     // if a target symbol font is not available use a default symbol font
    2560           0 :     if( rFSD.IsSymbolFont() )
    2561             :     {
    2562           0 :         com::sun::star::lang::Locale aDefaultLocale( OUString( "en" ), OUString(), OUString() );
    2563           0 :         aSearchName = DefaultFontConfiguration::get().getDefaultFont( aDefaultLocale, DEFAULTFONT_SYMBOL );
    2564           0 :         ImplDevFontListData* pFoundData = ImplFindByTokenNames( aSearchName );
    2565           0 :         if( pFoundData )
    2566           0 :             return pFoundData;
    2567             :     }
    2568             : 
    2569             :     // now try the other font name tokens
    2570           0 :     while( nTokenPos != -1 )
    2571             :     {
    2572           0 :         rFSD.maTargetName = GetNextFontToken( rFSD.GetFamilyName(), nTokenPos );
    2573           0 :         if( rFSD.maTargetName.isEmpty() )
    2574           0 :             continue;
    2575             : 
    2576           0 :         aSearchName = rFSD.maTargetName;
    2577           0 :         GetEnglishSearchFontName( aSearchName );
    2578             : 
    2579           0 :         OUString      aTempShortName;
    2580           0 :         OUString      aTempFamilyName;
    2581           0 :         sal_uLong   nTempType   = 0;
    2582           0 :         FontWeight  eTempWeight = rFSD.GetWeight();
    2583           0 :         FontWidth   eTempWidth  = WIDTH_DONTKNOW;
    2584             :         FontSubstConfiguration::getMapName( aSearchName, aTempShortName, aTempFamilyName,
    2585           0 :                                             eTempWeight, eTempWidth, nTempType );
    2586             : 
    2587             :         // use a shortend token name if available
    2588           0 :         if( aTempShortName != aSearchName )
    2589             :         {
    2590           0 :             ImplDevFontListData* pFoundData = ImplFindBySearchName( aTempShortName );
    2591           0 :             if( pFoundData )
    2592           0 :                 return pFoundData;
    2593             :         }
    2594             : 
    2595             :         // use a font name from font fallback list to determine font attributes
    2596             :         // get fallback info using FontSubstConfiguration and
    2597             :         // the target name, it's shortened name and family name in that order
    2598           0 :         const FontSubstConfiguration& rFontSubst = FontSubstConfiguration::get();
    2599           0 :         const FontNameAttr* pTempFontAttr = rFontSubst.getSubstInfo( aSearchName );
    2600           0 :         if ( !pTempFontAttr && (aTempShortName != aSearchName) )
    2601           0 :             pTempFontAttr = rFontSubst.getSubstInfo( aTempShortName );
    2602           0 :         if ( !pTempFontAttr && (aTempFamilyName != aTempShortName) )
    2603           0 :             pTempFontAttr = rFontSubst.getSubstInfo( aTempFamilyName );
    2604             : 
    2605             :         // try the font substitutions suggested by the fallback info
    2606           0 :         if( pTempFontAttr )
    2607             :         {
    2608           0 :             ImplDevFontListData* pFoundData = ImplFindBySubstFontAttr( *pTempFontAttr );
    2609           0 :             if( pFoundData )
    2610           0 :                 return pFoundData;
    2611           0 :             if( !pFontAttr )
    2612           0 :                 pFontAttr = pTempFontAttr;
    2613             :         }
    2614           0 :     }
    2615             : 
    2616             :     // if still needed use the alias names of the installed fonts
    2617           0 :     if( mbMapNames )
    2618             :     {
    2619           0 :         ImplDevFontListData* pFoundData = ImplFindByAliasName( rFSD.maTargetName, aSearchShortName );
    2620           0 :         if( pFoundData )
    2621           0 :             return pFoundData;
    2622             :     }
    2623             : 
    2624             :     // if still needed use the font request's attributes to find a good match
    2625           0 :     if (MsLangId::isSimplifiedChinese(rFSD.meLanguage))
    2626           0 :         nSearchType |= IMPL_FONT_ATTR_CJK | IMPL_FONT_ATTR_CJK_SC;
    2627           0 :     else if (MsLangId::isTraditionalChinese(rFSD.meLanguage))
    2628           0 :         nSearchType |= IMPL_FONT_ATTR_CJK | IMPL_FONT_ATTR_CJK_TC;
    2629           0 :     else if (MsLangId::isKorean(rFSD.meLanguage))
    2630           0 :         nSearchType |= IMPL_FONT_ATTR_CJK | IMPL_FONT_ATTR_CJK_KR;
    2631           0 :     else if (rFSD.meLanguage == LANGUAGE_JAPANESE)
    2632           0 :         nSearchType |= IMPL_FONT_ATTR_CJK | IMPL_FONT_ATTR_CJK_JP;
    2633             :     else
    2634             :     {
    2635           0 :         nSearchType |= ImplIsCJKFont( rFSD.GetFamilyName() );
    2636           0 :         if( rFSD.IsSymbolFont() )
    2637           0 :             nSearchType |= IMPL_FONT_ATTR_SYMBOL;
    2638             :     }
    2639             : 
    2640           0 :     ImplCalcType( nSearchType, eSearchWeight, eSearchWidth, rFSD.GetFamilyType(), pFontAttr );
    2641             :     ImplDevFontListData* pFoundData = ImplFindByAttributes( nSearchType,
    2642           0 :         eSearchWeight, eSearchWidth, rFSD.GetSlant(), aSearchFamilyName );
    2643             : 
    2644           0 :     if( pFoundData )
    2645             :     {
    2646             :         // overwrite font selection attributes using info from the typeface flags
    2647           0 :         if( (eSearchWeight >= WEIGHT_BOLD)
    2648           0 :         &&  (eSearchWeight > rFSD.GetWeight())
    2649           0 :         &&  (pFoundData->mnTypeFaces & IMPL_DEVFONT_BOLD) )
    2650           0 :             rFSD.SetWeight( eSearchWeight );
    2651           0 :         else if( (eSearchWeight < WEIGHT_NORMAL)
    2652           0 :         &&  (eSearchWeight < rFSD.GetWeight())
    2653           0 :         &&  (eSearchWeight != WEIGHT_DONTKNOW)
    2654           0 :         &&  (pFoundData->mnTypeFaces & IMPL_DEVFONT_LIGHT) )
    2655           0 :             rFSD.SetWeight( eSearchWeight );
    2656             : 
    2657           0 :         if( (nSearchType & IMPL_FONT_ATTR_ITALIC)
    2658           0 :         &&  ((rFSD.GetSlant() == ITALIC_DONTKNOW) || (rFSD.GetSlant() == ITALIC_NONE))
    2659           0 :         &&  (pFoundData->mnTypeFaces & IMPL_DEVFONT_ITALIC) )
    2660           0 :             rFSD.SetItalic( ITALIC_NORMAL );
    2661             :     }
    2662             :     else
    2663             :     {
    2664             :         // if still needed fall back to default fonts
    2665           0 :         pFoundData = FindDefaultFont();
    2666             :     }
    2667             : 
    2668        1761 :     return pFoundData;
    2669             : }
    2670             : 
    2671       12835 : ImplFontEntry* ImplFontCache::GetGlyphFallbackFont( ImplDevFontList* pFontList,
    2672             :     FontSelectPattern& rFontSelData, int nFallbackLevel, OUString& rMissingCodes )
    2673             : {
    2674             :     // get a candidate font for glyph fallback
    2675             :     // unless the previously selected font got a device specific substitution
    2676             :     // e.g. PsPrint Arial->Helvetica for udiaeresis when Helvetica doesn't support it
    2677       12835 :     if( nFallbackLevel >= 1)
    2678             :     {
    2679       12835 :         ImplDevFontListData* pFallbackData = NULL;
    2680             : 
    2681             :         //fdo#33898 If someone has EUDC installed then they really want that to
    2682             :         //be used as the first-choice glyph fallback seeing as it's filled with
    2683             :         //private area codes with don't make any sense in any other font so
    2684             :         //prioritise it here if it's available. Ideally we would remove from
    2685             :         //rMissingCodes all the glyphs which it is able to resolve as an
    2686             :         //optimization, but that's tricky to achieve cross-platform without
    2687             :         //sufficient heavy-weight code that's likely to undo the value of the
    2688             :         //optimization
    2689       12835 :         if (nFallbackLevel == 1)
    2690         947 :             pFallbackData = pFontList->FindFontFamily(OUString("EUDC"));
    2691       12835 :         if (!pFallbackData)
    2692       12835 :             pFallbackData = pFontList->GetGlyphFallbackFont(rFontSelData, rMissingCodes, nFallbackLevel-1);
    2693             :         // escape when there are no font candidates
    2694       12835 :         if( !pFallbackData  )
    2695           0 :             return NULL;
    2696             :         // override the font name
    2697       12835 :         rFontSelData.SetFamilyName( pFallbackData->GetFamilyName() );
    2698             :         // clear the cached normalized name
    2699       12835 :         rFontSelData.maSearchName = String();
    2700             :     }
    2701             : 
    2702             :     // get device font without doing device specific substitutions
    2703       12835 :     ImplFontEntry* pFallbackFont = GetFontEntry( pFontList, rFontSelData, NULL );
    2704       12835 :     return pFallbackFont;
    2705             : }
    2706             : 
    2707      761299 : void ImplFontCache::Release( ImplFontEntry* pEntry )
    2708             : {
    2709             :     static const int FONTCACHE_MAX = 50;
    2710             : 
    2711             :     DBG_ASSERT( (pEntry->mnRefCount > 0), "ImplFontCache::Release() - font refcount underflow" );
    2712      761299 :     if( --pEntry->mnRefCount > 0 )
    2713     1230916 :         return;
    2714             : 
    2715      291672 :     if( ++mnRef0Count < FONTCACHE_MAX )
    2716      291662 :         return;
    2717             : 
    2718             :     // remove unused entries from font instance cache
    2719          10 :     FontInstanceList::iterator it_next = maFontInstanceList.begin();
    2720         630 :     while( it_next != maFontInstanceList.end() )
    2721             :     {
    2722         610 :         FontInstanceList::iterator it = it_next++;
    2723         610 :         ImplFontEntry* pFontEntry = (*it).second;
    2724         610 :         if( pFontEntry->mnRefCount > 0 )
    2725         110 :             continue;
    2726             : 
    2727         500 :         maFontInstanceList.erase( it );
    2728         500 :         delete pFontEntry;
    2729         500 :         --mnRef0Count;
    2730             :         DBG_ASSERT( (mnRef0Count>=0), "ImplFontCache::Release() - refcount0 underflow" );
    2731             : 
    2732         500 :         if( mpFirstEntry == pFontEntry )
    2733           5 :             mpFirstEntry = NULL;
    2734             :     }
    2735             : 
    2736             :     DBG_ASSERT( (mnRef0Count==0), "ImplFontCache::Release() - refcount0 mismatch" );
    2737             : }
    2738             : 
    2739           3 : void ImplFontCache::Invalidate()
    2740             : {
    2741             :     // delete unreferenced entries
    2742           3 :     FontInstanceList::iterator it = maFontInstanceList.begin();
    2743           3 :     for(; it != maFontInstanceList.end(); ++it )
    2744             :     {
    2745           0 :         ImplFontEntry* pFontEntry = (*it).second;
    2746           0 :         if( pFontEntry->mnRefCount > 0 )
    2747           0 :             continue;
    2748             : 
    2749           0 :         delete pFontEntry;
    2750           0 :         --mnRef0Count;
    2751             :     }
    2752             : 
    2753             :     // #112304# make sure the font cache is really clean
    2754           3 :     mpFirstEntry = NULL;
    2755           3 :     maFontInstanceList.clear();
    2756             : 
    2757             :     DBG_ASSERT( (mnRef0Count==0), "ImplFontCache::Invalidate() - mnRef0Count non-zero" );
    2758           3 : }
    2759             : 
    2760        1438 : ImplMultiTextLineInfo::ImplMultiTextLineInfo()
    2761             : {
    2762        1438 :     mpLines = new PImplTextLineInfo[MULTITEXTLINEINFO_RESIZE];
    2763        1438 :     mnLines = 0;
    2764        1438 :     mnSize  = MULTITEXTLINEINFO_RESIZE;
    2765        1438 : }
    2766             : 
    2767             : 
    2768        1438 : ImplMultiTextLineInfo::~ImplMultiTextLineInfo()
    2769             : {
    2770        2757 :     for ( xub_StrLen i = 0; i < mnLines; i++ )
    2771        1319 :         delete mpLines[i];
    2772        1438 :     delete [] mpLines;
    2773        1438 : }
    2774             : 
    2775        1319 : void ImplMultiTextLineInfo::AddLine( ImplTextLineInfo* pLine )
    2776             : {
    2777        1319 :     if ( mnSize == mnLines )
    2778             :     {
    2779           0 :         mnSize += MULTITEXTLINEINFO_RESIZE;
    2780           0 :         PImplTextLineInfo* pNewLines = new PImplTextLineInfo[mnSize];
    2781           0 :         memcpy( pNewLines, mpLines, mnLines*sizeof(PImplTextLineInfo) );
    2782           0 :         mpLines = pNewLines;
    2783             :     }
    2784             : 
    2785        1319 :     mpLines[mnLines] = pLine;
    2786        1319 :     mnLines++;
    2787        1319 : }
    2788             : 
    2789        1438 : void ImplMultiTextLineInfo::Clear()
    2790             : {
    2791        1438 :     for ( xub_StrLen i = 0; i < mnLines; i++ )
    2792           0 :         delete mpLines[i];
    2793        1438 :     mnLines = 0;
    2794        1438 : }
    2795             : 
    2796       41982 : FontEmphasisMark OutputDevice::ImplGetEmphasisMarkStyle( const Font& rFont )
    2797             : {
    2798       41982 :     FontEmphasisMark nEmphasisMark = rFont.GetEmphasisMark();
    2799             : 
    2800             :     // If no Position is set, then calculate the default position, which
    2801             :     // depends on the language
    2802       41982 :     if ( !(nEmphasisMark & (EMPHASISMARK_POS_ABOVE | EMPHASISMARK_POS_BELOW)) )
    2803             :     {
    2804        5714 :         LanguageType eLang = rFont.GetLanguage();
    2805             :         // In Chinese Simplified the EmphasisMarks are below/left
    2806        5714 :         if (MsLangId::isSimplifiedChinese(eLang))
    2807           0 :             nEmphasisMark |= EMPHASISMARK_POS_BELOW;
    2808             :         else
    2809             :         {
    2810        5714 :             eLang = rFont.GetCJKContextLanguage();
    2811             :             // In Chinese Simplified the EmphasisMarks are below/left
    2812        5714 :             if (MsLangId::isSimplifiedChinese(eLang))
    2813           0 :                 nEmphasisMark |= EMPHASISMARK_POS_BELOW;
    2814             :             else
    2815        5714 :                 nEmphasisMark |= EMPHASISMARK_POS_ABOVE;
    2816             :         }
    2817             :     }
    2818             : 
    2819       41982 :     return nEmphasisMark;
    2820             : }
    2821             : 
    2822        8739 : sal_Bool OutputDevice::ImplIsUnderlineAbove( const Font& rFont )
    2823             : {
    2824        8739 :     if ( !rFont.IsVertical() )
    2825        8739 :         return sal_False;
    2826             : 
    2827           0 :     if( (LANGUAGE_JAPANESE == rFont.GetLanguage())
    2828           0 :     ||  (LANGUAGE_JAPANESE == rFont.GetCJKContextLanguage()) )
    2829             :         // the underline is right for Japanese only
    2830           0 :         return sal_True;
    2831             : 
    2832           0 :     return sal_False;
    2833             : }
    2834             : 
    2835     1171395 : void OutputDevice::ImplInitFontList() const
    2836             : {
    2837     1171395 :     if( ! mpFontList->Count() )
    2838             :     {
    2839         127 :         if( mpGraphics || ImplGetGraphics() )
    2840             :         {
    2841             :             RTL_LOGFILE_CONTEXT( aLog, "OutputDevice::ImplInitFontList()" );
    2842         127 :             mpGraphics->GetDevFontList( mpFontList );
    2843             :         }
    2844             :     }
    2845     1171395 :     if( meOutDevType == OUTDEV_WINDOW && ! mpFontList->Count() )
    2846             :     {
    2847           0 :         String aError( "Application error: no fonts and no vcl resource found on your system" );
    2848           0 :         ResMgr* pMgr = ImplGetResMgr();
    2849           0 :         if( pMgr )
    2850             :         {
    2851           0 :             String aResStr(ResId(SV_ACCESSERROR_NO_FONTS, *pMgr).toString());
    2852           0 :             if( aResStr.Len() )
    2853           0 :                 aError = aResStr;
    2854             :         }
    2855           0 :         Application::Abort( aError );
    2856             :     }
    2857     1171395 : }
    2858             : 
    2859      182134 : void OutputDevice::ImplInitFont() const
    2860             : {
    2861             :     DBG_TESTSOLARMUTEX();
    2862             : 
    2863      182134 :     if (!mpFontEntry)
    2864      182134 :         return;
    2865             : 
    2866      182134 :     if ( mbInitFont )
    2867             :     {
    2868      182134 :         if ( meOutDevType != OUTDEV_PRINTER )
    2869             :         {
    2870             :             // decide if antialiasing is appropriate
    2871      181870 :             bool bNonAntialiased = (GetAntialiasing() & ANTIALIASING_DISABLE_TEXT) != 0;
    2872      181870 :             const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
    2873      181870 :             bNonAntialiased |= ((rStyleSettings.GetDisplayOptions() & DISPLAY_OPTION_AA_DISABLE) != 0);
    2874      181870 :             bNonAntialiased |= (int(rStyleSettings.GetAntialiasingMinPixelHeight()) > mpFontEntry->maFontSelData.mnHeight);
    2875      181870 :             mpFontEntry->maFontSelData.mbNonAntialiased = bNonAntialiased;
    2876             :         }
    2877             : 
    2878             :         // select font in the device layers
    2879      182134 :         mpFontEntry->mnSetFontFlags = mpGraphics->SetFont( &(mpFontEntry->maFontSelData), 0 );
    2880      182134 :         mbInitFont = false;
    2881             :     }
    2882             : }
    2883             : 
    2884       31506 : void OutputDevice::ImplInitTextColor()
    2885             : {
    2886             :     DBG_TESTSOLARMUTEX();
    2887             : 
    2888       31506 :     if ( mbInitTextColor )
    2889             :     {
    2890       29044 :         mpGraphics->SetTextColor( ImplColorToSal( GetTextColor() ) );
    2891       29044 :         mbInitTextColor = sal_False;
    2892             :     }
    2893       31506 : }
    2894             : 
    2895     1233152 : bool OutputDevice::ImplNewFont() const
    2896             : {
    2897             :     DBG_TESTSOLARMUTEX();
    2898             : 
    2899             :     // get correct font list on the PDF writer if necessary
    2900     1233152 :     if( mpPDFWriter )
    2901             :     {
    2902           0 :         const ImplSVData* pSVData = ImplGetSVData();
    2903           0 :         if( mpFontList == pSVData->maGDIData.mpScreenFontList
    2904           0 :         ||  mpFontCache == pSVData->maGDIData.mpScreenFontCache )
    2905           0 :             const_cast<OutputDevice&>(*this).ImplUpdateFontData( true );
    2906             :     }
    2907             : 
    2908     1233152 :     if ( !mbNewFont )
    2909      485004 :         return true;
    2910             : 
    2911             :     // we need a graphics
    2912      748148 :     if ( !mpGraphics && !ImplGetGraphics() )
    2913           0 :         return false;
    2914      748148 :     SalGraphics* pGraphics = mpGraphics;
    2915      748148 :     ImplInitFontList();
    2916             : 
    2917             :     // convert to pixel height
    2918             :     // TODO: replace integer based aSize completely with subpixel accurate type
    2919      748148 :     float fExactHeight = ImplFloatLogicHeightToDevicePixel( static_cast<float>(maFont.GetHeight()) );
    2920      748148 :     Size aSize = ImplLogicToDevicePixel( maFont.GetSize() );
    2921      748148 :     if ( !aSize.Height() )
    2922             :     {
    2923             :         // use default pixel height only when logical height is zero
    2924          51 :         if ( maFont.GetSize().Height() )
    2925           0 :             aSize.Height() = 1;
    2926             :         else
    2927          51 :             aSize.Height() = (12*mnDPIY)/72;
    2928          51 :         fExactHeight =  static_cast<float>(aSize.Height());
    2929             :     }
    2930             : 
    2931             :     // select the default width only when logical width is zero
    2932      748148 :     if( (0 == aSize.Width()) && (0 != maFont.GetSize().Width()) )
    2933           0 :         aSize.Width() = 1;
    2934             : 
    2935             :     // get font entry
    2936      748148 :     ImplDirectFontSubstitution* pDevSpecificSubst = NULL;
    2937      748148 :     if( mpOutDevData )
    2938       22598 :         pDevSpecificSubst = &mpOutDevData->maDevFontSubst;
    2939      748148 :     ImplFontEntry* pOldEntry = mpFontEntry;
    2940      748148 :     mpFontEntry = mpFontCache->GetFontEntry( mpFontList, maFont, aSize, fExactHeight, pDevSpecificSubst );
    2941      748148 :     if( pOldEntry )
    2942      701155 :         mpFontCache->Release( pOldEntry );
    2943             : 
    2944      748148 :     ImplFontEntry* pFontEntry = mpFontEntry;
    2945             : 
    2946      748148 :     if (!pFontEntry)
    2947           0 :         return false;
    2948             : 
    2949             :     // mark when lower layers need to get involved
    2950      748148 :     mbNewFont = sal_False;
    2951      748148 :     if( pFontEntry != pOldEntry )
    2952      352180 :         mbInitFont = sal_True;
    2953             : 
    2954             :     // select font when it has not been initialized yet
    2955      748148 :     if ( !pFontEntry->mbInit )
    2956             :     {
    2957        4294 :         ImplInitFont();
    2958             : 
    2959             :         // get metric data from device layers
    2960        4294 :         if ( pGraphics )
    2961             :         {
    2962        4294 :             pFontEntry->mbInit = true;
    2963             : 
    2964        4294 :             pFontEntry->maMetric.mnOrientation  = sal::static_int_cast<short>(pFontEntry->maFontSelData.mnOrientation);
    2965        4294 :             pGraphics->GetFontMetric( &(pFontEntry->maMetric) );
    2966             : 
    2967        4294 :             pFontEntry->maMetric.ImplInitTextLineSize( this );
    2968        4294 :             pFontEntry->maMetric.ImplInitAboveTextLineSize();
    2969             : 
    2970        4294 :             pFontEntry->mnLineHeight = pFontEntry->maMetric.mnAscent + pFontEntry->maMetric.mnDescent;
    2971             : 
    2972        4294 :             if( pFontEntry->maFontSelData.mnOrientation
    2973         223 :             && !pFontEntry->maMetric.mnOrientation
    2974           0 :             && (meOutDevType != OUTDEV_PRINTER) )
    2975             :             {
    2976           0 :                 pFontEntry->mnOwnOrientation = sal::static_int_cast<short>(pFontEntry->maFontSelData.mnOrientation);
    2977           0 :                 pFontEntry->mnOrientation = pFontEntry->mnOwnOrientation;
    2978             :             }
    2979             :             else
    2980        4294 :                 pFontEntry->mnOrientation = pFontEntry->maMetric.mnOrientation;
    2981             :         }
    2982             :     }
    2983             : 
    2984             :     // enable kerning array if requested
    2985      748148 :     if ( maFont.GetKerning() & KERNING_FONTSPECIFIC )
    2986             :     {
    2987             :         // TODO: test if physical font supports kerning and disable if not
    2988       53652 :         if( pFontEntry->maMetric.mbKernableFont )
    2989       53022 :             mbKerning = true;
    2990             :     }
    2991             :     else
    2992      694496 :         mbKerning = false;
    2993      748148 :     if ( maFont.GetKerning() & KERNING_ASIAN )
    2994           0 :         mbKerning = true;
    2995             : 
    2996             :     // calculate EmphasisArea
    2997      748148 :     mnEmphasisAscent = 0;
    2998      748148 :     mnEmphasisDescent = 0;
    2999      748148 :     if ( maFont.GetEmphasisMark() & EMPHASISMARK_STYLE )
    3000             :     {
    3001       33958 :         FontEmphasisMark    nEmphasisMark = ImplGetEmphasisMarkStyle( maFont );
    3002       33958 :         long                nEmphasisHeight = (pFontEntry->mnLineHeight*250)/1000;
    3003       33958 :         if ( nEmphasisHeight < 1 )
    3004           5 :             nEmphasisHeight = 1;
    3005       33958 :         if ( nEmphasisMark & EMPHASISMARK_POS_BELOW )
    3006           0 :             mnEmphasisDescent = nEmphasisHeight;
    3007             :         else
    3008       33958 :             mnEmphasisAscent = nEmphasisHeight;
    3009             :     }
    3010             : 
    3011             :     // calculate text offset depending on TextAlignment
    3012      748148 :     TextAlign eAlign = maFont.GetAlign();
    3013      748148 :     if ( eAlign == ALIGN_BASELINE )
    3014             :     {
    3015      701278 :         mnTextOffX = 0;
    3016      701278 :         mnTextOffY = 0;
    3017             :     }
    3018       46870 :     else if ( eAlign == ALIGN_TOP )
    3019             :     {
    3020       45473 :         mnTextOffX = 0;
    3021       45473 :         mnTextOffY = +pFontEntry->maMetric.mnAscent + mnEmphasisAscent;
    3022       45473 :         if ( pFontEntry->mnOrientation )
    3023        4937 :             ImplRotatePos( 0, 0, mnTextOffX, mnTextOffY, pFontEntry->mnOrientation );
    3024             :     }
    3025             :     else // eAlign == ALIGN_BOTTOM
    3026             :     {
    3027        1397 :         mnTextOffX = 0;
    3028        1397 :         mnTextOffY = -pFontEntry->maMetric.mnDescent + mnEmphasisDescent;
    3029        1397 :         if ( pFontEntry->mnOrientation )
    3030           0 :             ImplRotatePos( 0, 0, mnTextOffX, mnTextOffY, pFontEntry->mnOrientation );
    3031             :     }
    3032             : 
    3033     1499509 :     mbTextLines     = ((maFont.GetUnderline() != UNDERLINE_NONE) && (maFont.GetUnderline() != UNDERLINE_DONTKNOW)) ||
    3034     2217360 :                       ((maFont.GetOverline()  != UNDERLINE_NONE) && (maFont.GetOverline()  != UNDERLINE_DONTKNOW)) ||
    3035     1461802 :                       ((maFont.GetStrikeout() != STRIKEOUT_NONE) && (maFont.GetStrikeout() != STRIKEOUT_DONTKNOW));
    3036     1473127 :     mbTextSpecial   = maFont.IsShadow() || maFont.IsOutline() ||
    3037     1473127 :                       (maFont.GetRelief() != RELIEF_NONE);
    3038             : 
    3039             :     // #95414# fix for OLE objects which use scale factors very creatively
    3040      748148 :     if( mbMap && !aSize.Width() )
    3041             :     {
    3042      677739 :         int nOrigWidth = pFontEntry->maMetric.mnWidth;
    3043      677739 :         float fStretch = (float)maMapRes.mnMapScNumX * maMapRes.mnMapScDenomY;
    3044      677739 :         fStretch /= (float)maMapRes.mnMapScNumY * maMapRes.mnMapScDenomX;
    3045      677739 :         int nNewWidth = (int)(nOrigWidth * fStretch + 0.5);
    3046      677739 :         if( (nNewWidth != nOrigWidth) && (nNewWidth != 0) )
    3047             :         {
    3048           8 :             Size aOrigSize = maFont.GetSize();
    3049           8 :             const_cast<Font&>(maFont).SetSize( Size( nNewWidth, aSize.Height() ) );
    3050           8 :             mbMap = sal_False;
    3051           8 :             mbNewFont = sal_True;
    3052           8 :             ImplNewFont();  // recurse once using stretched width
    3053           8 :             mbMap = sal_True;
    3054           8 :             const_cast<Font&>(maFont).SetSize( aOrigSize );
    3055             :         }
    3056             :     }
    3057             : 
    3058      748148 :     return true;
    3059             : }
    3060             : 
    3061       54009 : void OutputDevice::ImplDrawTextRect( long nBaseX, long nBaseY,
    3062             :                                      long nDistX, long nDistY, long nWidth, long nHeight )
    3063             : {
    3064       54009 :     long nX = nDistX;
    3065       54009 :     long nY = nDistY;
    3066             : 
    3067       54009 :     short nOrientation = mpFontEntry->mnOrientation;
    3068       54009 :     if ( nOrientation )
    3069             :     {
    3070             :         // Rotate rect without rounding problems for 90 degree rotations
    3071       22708 :         if ( !(nOrientation % 900) )
    3072             :         {
    3073       15826 :             if ( nOrientation == 900 )
    3074             :             {
    3075           0 :                 long nTemp = nX;
    3076           0 :                 nX = nY;
    3077           0 :                 nY = -nTemp;
    3078           0 :                 nTemp = nWidth;
    3079           0 :                 nWidth = nHeight;
    3080           0 :                 nHeight = nTemp;
    3081           0 :                 nY -= nHeight;
    3082             :             }
    3083       15826 :             else if ( nOrientation == 1800 )
    3084             :             {
    3085           0 :                 nX = -nX;
    3086           0 :                 nY = -nY;
    3087           0 :                 nX -= nWidth;
    3088           0 :                 nY -= nHeight;
    3089             :             }
    3090             :             else /* ( nOrientation == 2700 ) */
    3091             :             {
    3092       15826 :                 long nTemp = nX;
    3093       15826 :                 nX = -nY;
    3094       15826 :                 nY = nTemp;
    3095       15826 :                 nTemp = nWidth;
    3096       15826 :                 nWidth = nHeight;
    3097       15826 :                 nHeight = nTemp;
    3098       15826 :                 nX -= nWidth;
    3099             :             }
    3100             :         }
    3101             :         else
    3102             :         {
    3103        6882 :             nX += nBaseX;
    3104        6882 :             nY += nBaseY;
    3105             :             // inflate because polygons are drawn smaller
    3106        6882 :             Rectangle aRect( Point( nX, nY ), Size( nWidth+1, nHeight+1 ) );
    3107        6882 :             Polygon   aPoly( aRect );
    3108        6882 :             aPoly.Rotate( Point( nBaseX, nBaseY ), mpFontEntry->mnOrientation );
    3109        6882 :             ImplDrawPolygon( aPoly );
    3110       60891 :             return;
    3111             :         }
    3112             :     }
    3113             : 
    3114       47127 :     nX += nBaseX;
    3115       47127 :     nY += nBaseY;
    3116       47127 :     mpGraphics->DrawRect( nX, nY, nWidth, nHeight, this );
    3117             : }
    3118             : 
    3119        3327 : void OutputDevice::ImplDrawTextBackground( const SalLayout& rSalLayout )
    3120             : {
    3121        3327 :     const long nWidth = rSalLayout.GetTextWidth() / rSalLayout.GetUnitsPerPixel();
    3122        3327 :     const Point aBase = rSalLayout.DrawBase();
    3123        3327 :     const long nX = aBase.X();
    3124        3327 :     const long nY = aBase.Y();
    3125             : 
    3126        3327 :     if ( mbLineColor || mbInitLineColor )
    3127             :     {
    3128        3306 :         mpGraphics->SetLineColor();
    3129        3306 :         mbInitLineColor = sal_True;
    3130             :     }
    3131        3327 :     mpGraphics->SetFillColor( ImplColorToSal( GetTextFillColor() ) );
    3132        3327 :     mbInitFillColor = sal_True;
    3133             : 
    3134        3327 :     ImplDrawTextRect( nX, nY, 0, -(mpFontEntry->maMetric.mnAscent + mnEmphasisAscent),
    3135             :                       nWidth,
    3136        6654 :                       mpFontEntry->mnLineHeight+mnEmphasisAscent+mnEmphasisDescent );
    3137        3327 : }
    3138             : 
    3139           0 : Rectangle OutputDevice::ImplGetTextBoundRect( const SalLayout& rSalLayout )
    3140             : {
    3141           0 :     Point aPoint = rSalLayout.GetDrawPosition();
    3142           0 :     long nX = aPoint.X();
    3143           0 :     long nY = aPoint.Y();
    3144             : 
    3145           0 :     long nWidth = rSalLayout.GetTextWidth();
    3146           0 :     long nHeight = mpFontEntry->mnLineHeight + mnEmphasisAscent + mnEmphasisDescent;
    3147             : 
    3148           0 :     nY -= mpFontEntry->maMetric.mnAscent + mnEmphasisAscent;
    3149             : 
    3150           0 :     if ( mpFontEntry->mnOrientation )
    3151             :     {
    3152           0 :         long nBaseX = nX, nBaseY = nY;
    3153           0 :         if ( !(mpFontEntry->mnOrientation % 900) )
    3154             :         {
    3155           0 :             long nX2 = nX+nWidth;
    3156           0 :             long nY2 = nY+nHeight;
    3157           0 :             ImplRotatePos( nBaseX, nBaseY, nX, nY, mpFontEntry->mnOrientation );
    3158           0 :             ImplRotatePos( nBaseX, nBaseY, nX2, nY2, mpFontEntry->mnOrientation );
    3159           0 :             nWidth = nX2-nX;
    3160           0 :             nHeight = nY2-nY;
    3161             :         }
    3162             :         else
    3163             :         {
    3164             :             // inflate by +1+1 because polygons are drawn smaller
    3165           0 :             Rectangle aRect( Point( nX, nY ), Size( nWidth+1, nHeight+1 ) );
    3166           0 :             Polygon   aPoly( aRect );
    3167           0 :             aPoly.Rotate( Point( nBaseX, nBaseY ), mpFontEntry->mnOrientation );
    3168           0 :             return aPoly.GetBoundRect();
    3169             :         }
    3170             :     }
    3171             : 
    3172           0 :     return Rectangle( Point( nX, nY ), Size( nWidth, nHeight ) );
    3173             : }
    3174             : 
    3175           0 : void OutputDevice::ImplInitTextLineSize()
    3176             : {
    3177           0 :     mpFontEntry->maMetric.ImplInitTextLineSize( this );
    3178           0 : }
    3179             : 
    3180           0 : void OutputDevice::ImplInitAboveTextLineSize()
    3181             : {
    3182           0 :     mpFontEntry->maMetric.ImplInitAboveTextLineSize();
    3183           0 : }
    3184             : 
    3185      596348 : bool ImplFontAttributes::operator==(const ImplFontAttributes& rOther) const
    3186             : {
    3187      596348 :     if (maName != rOther.maName)
    3188      193635 :         return false;
    3189             : 
    3190      402713 :     if (maStyleName != rOther.maStyleName)
    3191        1912 :         return false;
    3192             : 
    3193      400801 :     if (meWeight != rOther.meWeight)
    3194       16559 :         return false;
    3195             : 
    3196      384242 :     if (meItalic != rOther.meItalic)
    3197        3198 :         return false;
    3198             : 
    3199      381044 :     if (meFamily != rOther.meFamily)
    3200       11718 :         return false;
    3201             : 
    3202      369326 :     if (mePitch != rOther.mePitch)
    3203         379 :         return false;
    3204             : 
    3205      368947 :     if (meWidthType != rOther.meWidthType)
    3206           0 :         return false;
    3207             : 
    3208      368947 :     if (mbSymbolFlag != rOther.mbSymbolFlag)
    3209           0 :         return false;
    3210             : 
    3211      368947 :     return true;
    3212             : }
    3213             : 
    3214        4892 : ImplFontMetricData::ImplFontMetricData( const FontSelectPattern& rFontSelData )
    3215        4892 : :   ImplFontAttributes( rFontSelData )
    3216             : {
    3217             :     // initialize the members provided by the font request
    3218        4892 :     mnWidth        = rFontSelData.mnWidth;
    3219        4892 :     mnSlant        = rFontSelData.GetSlant();
    3220        4892 :     mnOrientation  = sal::static_int_cast<short>(rFontSelData.mnOrientation);
    3221             : 
    3222             :     // intialize the used font name
    3223        4892 :     if( rFontSelData.mpFontData )
    3224             :     {
    3225        4892 :         SetFamilyName( rFontSelData.mpFontData->GetFamilyName() );
    3226        4892 :         SetStyleName( rFontSelData.mpFontData->GetStyleName() );
    3227        4892 :         mbDevice   = rFontSelData.mpFontData->mbDevice;
    3228        4892 :         mbKernableFont = true;
    3229             :     }
    3230             :     else
    3231             :     {
    3232           0 :         sal_Int32 nTokenPos = 0;
    3233           0 :         SetFamilyName( GetNextFontToken( rFontSelData.GetFamilyName(), nTokenPos ) );
    3234           0 :         SetStyleName( rFontSelData.GetStyleName() );
    3235           0 :         mbDevice   = false;
    3236           0 :         mbKernableFont = false;
    3237             :     }
    3238             : 
    3239             :     // reset metrics that are usually measured for the font instance
    3240        4892 :     mnAscent       = 0;
    3241        4892 :     mnDescent      = 0;
    3242        4892 :     mnIntLeading   = 0;
    3243        4892 :     mnExtLeading   = 0;
    3244        4892 :     mnMinKashida   = 0;
    3245             : 
    3246             :     // reset metrics that are usually derived from the measurements
    3247        4892 :     mnUnderlineSize            = 0;
    3248        4892 :     mnUnderlineOffset          = 0;
    3249        4892 :     mnBUnderlineSize           = 0;
    3250        4892 :     mnBUnderlineOffset         = 0;
    3251        4892 :     mnDUnderlineSize           = 0;
    3252        4892 :     mnDUnderlineOffset1        = 0;
    3253        4892 :     mnDUnderlineOffset2        = 0;
    3254        4892 :     mnWUnderlineSize           = 0;
    3255        4892 :     mnWUnderlineOffset         = 0;
    3256        4892 :     mnAboveUnderlineSize       = 0;
    3257        4892 :     mnAboveUnderlineOffset     = 0;
    3258        4892 :     mnAboveBUnderlineSize      = 0;
    3259        4892 :     mnAboveBUnderlineOffset    = 0;
    3260        4892 :     mnAboveDUnderlineSize      = 0;
    3261        4892 :     mnAboveDUnderlineOffset1   = 0;
    3262        4892 :     mnAboveDUnderlineOffset2   = 0;
    3263        4892 :     mnAboveWUnderlineSize      = 0;
    3264        4892 :     mnAboveWUnderlineOffset    = 0;
    3265        4892 :     mnStrikeoutSize            = 0;
    3266        4892 :     mnStrikeoutOffset          = 0;
    3267        4892 :     mnBStrikeoutSize           = 0;
    3268        4892 :     mnBStrikeoutOffset         = 0;
    3269        4892 :     mnDStrikeoutSize           = 0;
    3270        4892 :     mnDStrikeoutOffset1        = 0;
    3271        4892 :     mnDStrikeoutOffset2        = 0;
    3272        4892 : }
    3273             : 
    3274        4294 : void ImplFontMetricData::ImplInitTextLineSize( const OutputDevice* pDev )
    3275             : {
    3276        4294 :     long nDescent = mnDescent;
    3277        4294 :     if ( nDescent <= 0 )
    3278             :     {
    3279           8 :         nDescent = mnAscent / 10;
    3280           8 :         if ( !nDescent )
    3281           8 :             nDescent = 1;
    3282             :     }
    3283             : 
    3284             :     // #i55341# for some fonts it is not a good idea to calculate
    3285             :     // their text line metrics from the real font descent
    3286             :     // => work around this problem just for these fonts
    3287        4294 :     if( 3*nDescent > mnAscent )
    3288         536 :         nDescent = mnAscent / 3;
    3289             : 
    3290        4294 :     long nLineHeight = ((nDescent*25)+50) / 100;
    3291        4294 :     if ( !nLineHeight )
    3292          84 :         nLineHeight = 1;
    3293        4294 :     long nLineHeight2 = nLineHeight / 2;
    3294        4294 :     if ( !nLineHeight2 )
    3295         945 :         nLineHeight2 = 1;
    3296             : 
    3297        4294 :     long nBLineHeight = ((nDescent*50)+50) / 100;
    3298        4294 :     if ( nBLineHeight == nLineHeight )
    3299         347 :         nBLineHeight++;
    3300        4294 :     long nBLineHeight2 = nBLineHeight/2;
    3301        4294 :     if ( !nBLineHeight2 )
    3302          11 :         nBLineHeight2 = 1;
    3303             : 
    3304        4294 :     long n2LineHeight = ((nDescent*16)+50) / 100;
    3305        4294 :     if ( !n2LineHeight )
    3306         826 :         n2LineHeight = 1;
    3307        4294 :     long n2LineDY = n2LineHeight;
    3308             :      /* #117909#
    3309             :       * add some pixels to minimum double line distance on higher resolution devices
    3310             :       */
    3311        4294 :     long nMin2LineDY = 1 + pDev->ImplGetDPIY()/150;
    3312        4294 :     if ( n2LineDY < nMin2LineDY )
    3313        2041 :         n2LineDY = nMin2LineDY;
    3314        4294 :     long n2LineDY2 = n2LineDY/2;
    3315        4294 :     if ( !n2LineDY2 )
    3316        1079 :         n2LineDY2 = 1;
    3317             : 
    3318        4294 :     long nUnderlineOffset = mnDescent/2 + 1;
    3319        4294 :     long nStrikeoutOffset = -((mnAscent - mnIntLeading) / 3);
    3320             : 
    3321        4294 :     mnUnderlineSize        = nLineHeight;
    3322        4294 :     mnUnderlineOffset      = nUnderlineOffset - nLineHeight2;
    3323             : 
    3324        4294 :     mnBUnderlineSize       = nBLineHeight;
    3325        4294 :     mnBUnderlineOffset     = nUnderlineOffset - nBLineHeight2;
    3326             : 
    3327        4294 :     mnDUnderlineSize       = n2LineHeight;
    3328        4294 :     mnDUnderlineOffset1    = nUnderlineOffset - n2LineDY2 - n2LineHeight;
    3329        4294 :     mnDUnderlineOffset2    = mnDUnderlineOffset1 + n2LineDY + n2LineHeight;
    3330             : 
    3331        4294 :     long nWCalcSize = mnDescent;
    3332        4294 :     if ( nWCalcSize < 6 )
    3333             :     {
    3334         944 :         if ( (nWCalcSize == 1) || (nWCalcSize == 2) )
    3335         348 :             mnWUnderlineSize = nWCalcSize;
    3336             :         else
    3337         596 :             mnWUnderlineSize = 3;
    3338             :     }
    3339             :     else
    3340        3350 :         mnWUnderlineSize = ((nWCalcSize*50)+50) / 100;
    3341             : 
    3342             :     // #109280# the following line assures that wavelnes are never placed below the descent, however
    3343             :     // for most fonts the waveline then is drawn into the text, so we better keep the old solution
    3344             :     // pFontEntry->maMetric.mnWUnderlineOffset     = pFontEntry->maMetric.mnDescent + 1 - pFontEntry->maMetric.mnWUnderlineSize;
    3345        4294 :     mnWUnderlineOffset     = nUnderlineOffset;
    3346             : 
    3347        4294 :     mnStrikeoutSize        = nLineHeight;
    3348        4294 :     mnStrikeoutOffset      = nStrikeoutOffset - nLineHeight2;
    3349             : 
    3350        4294 :     mnBStrikeoutSize       = nBLineHeight;
    3351        4294 :     mnBStrikeoutOffset     = nStrikeoutOffset - nBLineHeight2;
    3352             : 
    3353        4294 :     mnDStrikeoutSize       = n2LineHeight;
    3354        4294 :     mnDStrikeoutOffset1    = nStrikeoutOffset - n2LineDY2 - n2LineHeight;
    3355        4294 :     mnDStrikeoutOffset2    = mnDStrikeoutOffset1 + n2LineDY + n2LineHeight;
    3356        4294 : }
    3357             : 
    3358        4294 : void ImplFontMetricData::ImplInitAboveTextLineSize()
    3359             : {
    3360        4294 :     long nIntLeading = mnIntLeading;
    3361             :     // TODO: assess usage of nLeading below (changed in extleading CWS)
    3362             :     // if no leading is available, we assume 15% of the ascent
    3363        4294 :     if ( nIntLeading <= 0 )
    3364             :     {
    3365         505 :         nIntLeading = mnAscent*15/100;
    3366         505 :         if ( !nIntLeading )
    3367          81 :             nIntLeading = 1;
    3368             :     }
    3369             : 
    3370        4294 :     long nLineHeight = ((nIntLeading*25)+50) / 100;
    3371        4294 :     if ( !nLineHeight )
    3372         690 :         nLineHeight = 1;
    3373             : 
    3374        4294 :     long nBLineHeight = ((nIntLeading*50)+50) / 100;
    3375        4294 :     if ( nBLineHeight == nLineHeight )
    3376         975 :         nBLineHeight++;
    3377             : 
    3378        4294 :     long n2LineHeight = ((nIntLeading*16)+50) / 100;
    3379        4294 :     if ( !n2LineHeight )
    3380        1081 :         n2LineHeight = 1;
    3381             : 
    3382        4294 :     long nCeiling = -mnAscent;
    3383             : 
    3384        4294 :     mnAboveUnderlineSize       = nLineHeight;
    3385        4294 :     mnAboveUnderlineOffset     = nCeiling + (nIntLeading - nLineHeight + 1) / 2;
    3386             : 
    3387        4294 :     mnAboveBUnderlineSize      = nBLineHeight;
    3388        4294 :     mnAboveBUnderlineOffset    = nCeiling + (nIntLeading - nBLineHeight + 1) / 2;
    3389             : 
    3390        4294 :     mnAboveDUnderlineSize      = n2LineHeight;
    3391        4294 :     mnAboveDUnderlineOffset1   = nCeiling + (nIntLeading - 3*n2LineHeight + 1) / 2;
    3392        4294 :     mnAboveDUnderlineOffset2   = nCeiling + (nIntLeading +   n2LineHeight + 1) / 2;
    3393             : 
    3394        4294 :     long nWCalcSize = nIntLeading;
    3395        4294 :     if ( nWCalcSize < 6 )
    3396             :     {
    3397        1331 :         if ( (nWCalcSize == 1) || (nWCalcSize == 2) )
    3398         975 :             mnAboveWUnderlineSize = nWCalcSize;
    3399             :         else
    3400         356 :             mnAboveWUnderlineSize = 3;
    3401             :     }
    3402             :     else
    3403        2963 :         mnAboveWUnderlineSize = ((nWCalcSize*50)+50) / 100;
    3404             : 
    3405        4294 :     mnAboveWUnderlineOffset = nCeiling + (nIntLeading + 1) / 2;
    3406        4294 : }
    3407             : 
    3408      102665 : static void ImplDrawWavePixel( long nOriginX, long nOriginY,
    3409             :                                long nCurX, long nCurY,
    3410             :                                short nOrientation,
    3411             :                                SalGraphics* pGraphics,
    3412             :                                OutputDevice* pOutDev,
    3413             :                                bool bDrawPixAsRect,
    3414             : 
    3415             :                                long nPixWidth, long nPixHeight )
    3416             : {
    3417      102665 :     if ( nOrientation )
    3418       61692 :         ImplRotatePos( nOriginX, nOriginY, nCurX, nCurY, nOrientation );
    3419             : 
    3420      102665 :     if ( bDrawPixAsRect )
    3421             :     {
    3422             : 
    3423       61692 :         pGraphics->DrawRect( nCurX, nCurY, nPixWidth, nPixHeight, pOutDev );
    3424             :     }
    3425             :     else
    3426             :     {
    3427       40973 :         pGraphics->DrawPixel( nCurX, nCurY, pOutDev );
    3428             :     }
    3429      102665 : }
    3430             : 
    3431        1617 : void OutputDevice::ImplDrawWaveLine( long nBaseX, long nBaseY,
    3432             :                                      long nDistX, long nDistY,
    3433             :                                      long nWidth, long nHeight,
    3434             :                                      long nLineWidth, short nOrientation,
    3435             :                                      const Color& rColor )
    3436             : {
    3437        1617 :     if ( !nHeight )
    3438        1617 :         return;
    3439             : 
    3440        1617 :     long nStartX = nBaseX + nDistX;
    3441        1617 :     long nStartY = nBaseY + nDistY;
    3442             : 
    3443             :     // If the height is 1 pixel, it's enough ouput a line
    3444        1617 :     if ( (nLineWidth == 1) && (nHeight == 1) )
    3445             :     {
    3446           1 :         mpGraphics->SetLineColor( ImplColorToSal( rColor ) );
    3447           1 :         mbInitLineColor = sal_True;
    3448             : 
    3449           1 :         long nEndX = nStartX+nWidth;
    3450           1 :         long nEndY = nStartY;
    3451           1 :         if ( nOrientation )
    3452             :         {
    3453           0 :             ImplRotatePos( nBaseX, nBaseY, nStartX, nStartY, nOrientation );
    3454           0 :             ImplRotatePos( nBaseX, nBaseY, nEndX, nEndY, nOrientation );
    3455             :         }
    3456           1 :         mpGraphics->DrawLine( nStartX, nStartY, nEndX, nEndY, this );
    3457             :     }
    3458             :     else
    3459             :     {
    3460        1616 :         long    nCurX = nStartX;
    3461        1616 :         long    nCurY = nStartY;
    3462        1616 :         long    nDiffX = 2;
    3463        1616 :         long    nDiffY = nHeight-1;
    3464        1616 :         long    nCount = nWidth;
    3465        1616 :         long    nOffY = -1;
    3466             :         long    nFreq;
    3467             :         long    i;
    3468             :         long    nPixWidth;
    3469             :         long    nPixHeight;
    3470             :         bool    bDrawPixAsRect;
    3471             :         // On printers that ouput pixel via DrawRect()
    3472        1616 :         if ( (GetOutDevType() == OUTDEV_PRINTER) || (nLineWidth > 1) )
    3473             :         {
    3474        1006 :             if ( mbLineColor || mbInitLineColor )
    3475             :             {
    3476         978 :                 mpGraphics->SetLineColor();
    3477         978 :                 mbInitLineColor = sal_True;
    3478             :             }
    3479        1006 :             mpGraphics->SetFillColor( ImplColorToSal( rColor ) );
    3480        1006 :             mbInitFillColor = sal_True;
    3481        1006 :             bDrawPixAsRect  = true;
    3482        1006 :             nPixWidth       = nLineWidth;
    3483        1006 :             nPixHeight      = ((nLineWidth*mnDPIX)+(mnDPIY/2))/mnDPIY;
    3484             :         }
    3485             :         else
    3486             :         {
    3487         610 :             mpGraphics->SetLineColor( ImplColorToSal( rColor ) );
    3488         610 :             mbInitLineColor = sal_True;
    3489         610 :             nPixWidth       = 1;
    3490         610 :             nPixHeight      = 1;
    3491         610 :             bDrawPixAsRect  = false;
    3492             :         }
    3493             : 
    3494        1616 :         if ( !nDiffY )
    3495             :         {
    3496           0 :             while ( nWidth )
    3497             :             {
    3498             :                 ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
    3499             :                                    mpGraphics, this,
    3500           0 :                                    bDrawPixAsRect, nPixWidth, nPixHeight );
    3501           0 :                 nCurX++;
    3502           0 :                 nWidth--;
    3503             :             }
    3504             :         }
    3505             :         else
    3506             :         {
    3507        1616 :             nCurY += nDiffY;
    3508        1616 :             nFreq = nCount / (nDiffX+nDiffY);
    3509       21781 :             while ( nFreq-- )
    3510             :             {
    3511       80896 :                 for( i = nDiffY; i; --i )
    3512             :                 {
    3513             :                     ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
    3514             :                                        mpGraphics, this,
    3515       62347 :                                        bDrawPixAsRect, nPixWidth, nPixHeight );
    3516       62347 :                     nCurX++;
    3517       62347 :                     nCurY += nOffY;
    3518             :                 }
    3519       55647 :                 for( i = nDiffX; i; --i )
    3520             :                 {
    3521             :                     ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
    3522             :                                        mpGraphics, this,
    3523       37098 :                                        bDrawPixAsRect, nPixWidth, nPixHeight );
    3524       37098 :                     nCurX++;
    3525             :                 }
    3526       18549 :                 nOffY = -nOffY;
    3527             :             }
    3528        1616 :             nFreq = nCount % (nDiffX+nDiffY);
    3529        1616 :             if ( nFreq )
    3530             :             {
    3531        3907 :                 for( i = nDiffY; i && nFreq; --i, --nFreq )
    3532             :                 {
    3533             :                     ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
    3534             :                                        mpGraphics, this,
    3535        2986 :                                        bDrawPixAsRect, nPixWidth, nPixHeight );
    3536        2986 :                     nCurX++;
    3537        2986 :                     nCurY += nOffY;
    3538             : 
    3539             :                 }
    3540        1155 :                 for( i = nDiffX; i && nFreq; --i, --nFreq )
    3541             :                 {
    3542             :                     ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
    3543             :                                        mpGraphics, this,
    3544         234 :                                        bDrawPixAsRect, nPixWidth, nPixHeight );
    3545         234 :                     nCurX++;
    3546             :                 }
    3547             :             }
    3548             :         }
    3549             : 
    3550             :     }
    3551             : }
    3552             : 
    3553        1006 : void OutputDevice::ImplDrawWaveTextLine( long nBaseX, long nBaseY,
    3554             :                                          long nDistX, long nDistY, long nWidth,
    3555             :                                          FontUnderline eTextLine,
    3556             :                                          Color aColor,
    3557             :                                          sal_Bool bIsAbove )
    3558             : {
    3559        1006 :     ImplFontEntry*  pFontEntry = mpFontEntry;
    3560             :     long            nLineHeight;
    3561             :     long            nLinePos;
    3562             : 
    3563        1006 :     if ( bIsAbove )
    3564             :     {
    3565           0 :         nLineHeight = pFontEntry->maMetric.mnAboveWUnderlineSize;
    3566           0 :         nLinePos = pFontEntry->maMetric.mnAboveWUnderlineOffset;
    3567             :     }
    3568             :     else
    3569             :     {
    3570        1006 :         nLineHeight = pFontEntry->maMetric.mnWUnderlineSize;
    3571        1006 :         nLinePos = pFontEntry->maMetric.mnWUnderlineOffset;
    3572             :     }
    3573        1006 :     if ( (eTextLine == UNDERLINE_SMALLWAVE) && (nLineHeight > 3) )
    3574           0 :         nLineHeight = 3;
    3575        1006 :     long nLineWidth = (mnDPIX/300);
    3576        1006 :     if ( !nLineWidth )
    3577        1006 :         nLineWidth = 1;
    3578        1006 :     if ( eTextLine == UNDERLINE_BOLDWAVE )
    3579        1006 :         nLineWidth *= 2;
    3580        1006 :     nLinePos += nDistY - (nLineHeight / 2);
    3581        1006 :     long nLineWidthHeight = ((nLineWidth*mnDPIX)+(mnDPIY/2))/mnDPIY;
    3582        1006 :     if ( eTextLine == UNDERLINE_DOUBLEWAVE )
    3583             :     {
    3584           0 :         long nOrgLineHeight = nLineHeight;
    3585           0 :         nLineHeight /= 3;
    3586           0 :         if ( nLineHeight < 2 )
    3587             :         {
    3588           0 :             if ( nOrgLineHeight > 1 )
    3589           0 :                 nLineHeight = 2;
    3590             :             else
    3591           0 :                 nLineHeight = 1;
    3592             :         }
    3593           0 :         long nLineDY = nOrgLineHeight-(nLineHeight*2);
    3594           0 :         if ( nLineDY < nLineWidthHeight )
    3595           0 :             nLineDY = nLineWidthHeight;
    3596           0 :         long nLineDY2 = nLineDY/2;
    3597           0 :         if ( !nLineDY2 )
    3598           0 :             nLineDY2 = 1;
    3599             : 
    3600           0 :         nLinePos -= nLineWidthHeight-nLineDY2;
    3601             :         ImplDrawWaveLine( nBaseX, nBaseY, nDistX, nLinePos, nWidth, nLineHeight,
    3602           0 :                           nLineWidth, mpFontEntry->mnOrientation, aColor );
    3603           0 :         nLinePos += nLineWidthHeight+nLineDY;
    3604             :         ImplDrawWaveLine( nBaseX, nBaseY, nDistX, nLinePos, nWidth, nLineHeight,
    3605           0 :                           nLineWidth, mpFontEntry->mnOrientation, aColor );
    3606             :     }
    3607             :     else
    3608             :     {
    3609        1006 :         nLinePos -= nLineWidthHeight/2;
    3610             :         ImplDrawWaveLine( nBaseX, nBaseY, nDistX, nLinePos, nWidth, nLineHeight,
    3611        1006 :                           nLineWidth, mpFontEntry->mnOrientation, aColor );
    3612             :     }
    3613        1006 : }
    3614             : 
    3615       31670 : void OutputDevice::ImplDrawStraightTextLine( long nBaseX, long nBaseY,
    3616             :                                              long nDistX, long nDistY, long nWidth,
    3617             :                                              FontUnderline eTextLine,
    3618             :                                              Color aColor,
    3619             :                                              sal_Bool bIsAbove )
    3620             : {
    3621       31670 :     ImplFontEntry*  pFontEntry = mpFontEntry;
    3622       31670 :     long            nLineHeight = 0;
    3623       31670 :     long            nLinePos  = 0;
    3624       31670 :     long            nLinePos2 = 0;
    3625             : 
    3626       31670 :     const long nY = nDistY;
    3627             : 
    3628       31670 :     if ( eTextLine > UNDERLINE_LAST )
    3629         458 :         eTextLine = UNDERLINE_SINGLE;
    3630             : 
    3631       31670 :     switch ( eTextLine )
    3632             :     {
    3633             :         case UNDERLINE_SINGLE:
    3634             :         case UNDERLINE_DOTTED:
    3635             :         case UNDERLINE_DASH:
    3636             :         case UNDERLINE_LONGDASH:
    3637             :         case UNDERLINE_DASHDOT:
    3638             :         case UNDERLINE_DASHDOTDOT:
    3639       15370 :             if ( bIsAbove )
    3640             :             {
    3641        3154 :                 nLineHeight = pFontEntry->maMetric.mnAboveUnderlineSize;
    3642        3154 :                 nLinePos    = nY + pFontEntry->maMetric.mnAboveUnderlineOffset;
    3643             :             }
    3644             :             else
    3645             :             {
    3646       12216 :                 nLineHeight = pFontEntry->maMetric.mnUnderlineSize;
    3647       12216 :                 nLinePos    = nY + pFontEntry->maMetric.mnUnderlineOffset;
    3648             :             }
    3649       15370 :             break;
    3650             :         case UNDERLINE_BOLD:
    3651             :         case UNDERLINE_BOLDDOTTED:
    3652             :         case UNDERLINE_BOLDDASH:
    3653             :         case UNDERLINE_BOLDLONGDASH:
    3654             :         case UNDERLINE_BOLDDASHDOT:
    3655             :         case UNDERLINE_BOLDDASHDOTDOT:
    3656         630 :             if ( bIsAbove )
    3657             :             {
    3658           0 :                 nLineHeight = pFontEntry->maMetric.mnAboveBUnderlineSize;
    3659           0 :                 nLinePos    = nY + pFontEntry->maMetric.mnAboveBUnderlineOffset;
    3660             :             }
    3661             :             else
    3662             :             {
    3663         630 :                 nLineHeight = pFontEntry->maMetric.mnBUnderlineSize;
    3664         630 :                 nLinePos    = nY + pFontEntry->maMetric.mnBUnderlineOffset;
    3665             :             }
    3666         630 :             break;
    3667             :         case UNDERLINE_DOUBLE:
    3668        3458 :             if ( bIsAbove )
    3669             :             {
    3670        1486 :                 nLineHeight = pFontEntry->maMetric.mnAboveDUnderlineSize;
    3671        1486 :                 nLinePos    = nY + pFontEntry->maMetric.mnAboveDUnderlineOffset1;
    3672        1486 :                 nLinePos2   = nY + pFontEntry->maMetric.mnAboveDUnderlineOffset2;
    3673             :             }
    3674             :             else
    3675             :             {
    3676        1972 :                 nLineHeight = pFontEntry->maMetric.mnDUnderlineSize;
    3677        1972 :                 nLinePos    = nY + pFontEntry->maMetric.mnDUnderlineOffset1;
    3678        1972 :                 nLinePos2   = nY + pFontEntry->maMetric.mnDUnderlineOffset2;
    3679             :             }
    3680        3458 :             break;
    3681             :         default:
    3682       12212 :             break;
    3683             :     }
    3684             : 
    3685       31670 :     if ( nLineHeight )
    3686             :     {
    3687       19452 :         if ( mbLineColor || mbInitLineColor )
    3688             :         {
    3689       17988 :             mpGraphics->SetLineColor();
    3690       17988 :             mbInitLineColor = sal_True;
    3691             :         }
    3692       19452 :         mpGraphics->SetFillColor( ImplColorToSal( aColor ) );
    3693       19452 :         mbInitFillColor = sal_True;
    3694             : 
    3695       19452 :         long nLeft = nDistX;
    3696             : 
    3697       19452 :         switch ( eTextLine )
    3698             :         {
    3699             :             case UNDERLINE_SINGLE:
    3700             :             case UNDERLINE_BOLD:
    3701       13880 :                 ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight );
    3702       13880 :                 break;
    3703             :             case UNDERLINE_DOUBLE:
    3704        3458 :                 ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos,  nWidth, nLineHeight );
    3705        3458 :                 ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos2, nWidth, nLineHeight );
    3706        3458 :                 break;
    3707             :             case UNDERLINE_DOTTED:
    3708             :             case UNDERLINE_BOLDDOTTED:
    3709             :                 {
    3710        1004 :                     long nDotWidth = nLineHeight*mnDPIY;
    3711        1004 :                     nDotWidth += mnDPIY/2;
    3712        1004 :                     nDotWidth /= mnDPIY;
    3713        1004 :                     long nTempWidth = nDotWidth;
    3714        1004 :                     long nEnd = nLeft+nWidth;
    3715       20732 :                     while ( nLeft < nEnd )
    3716             :                     {
    3717       18724 :                         if ( nLeft+nTempWidth > nEnd )
    3718         254 :                             nTempWidth = nEnd-nLeft;
    3719       18724 :                         ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempWidth, nLineHeight );
    3720       18724 :                         nLeft += nDotWidth*2;
    3721             :                     }
    3722             :                 }
    3723        1004 :                 break;
    3724             :             case UNDERLINE_DASH:
    3725             :             case UNDERLINE_LONGDASH:
    3726             :             case UNDERLINE_BOLDDASH:
    3727             :             case UNDERLINE_BOLDLONGDASH:
    3728             :                 {
    3729         486 :                     long nDotWidth = nLineHeight*mnDPIY;
    3730         486 :                     nDotWidth += mnDPIY/2;
    3731         486 :                     nDotWidth /= mnDPIY;
    3732             :                     long nMinDashWidth;
    3733             :                     long nMinSpaceWidth;
    3734             :                     long nSpaceWidth;
    3735             :                     long nDashWidth;
    3736         486 :                     if ( (eTextLine == UNDERLINE_LONGDASH) ||
    3737             :                          (eTextLine == UNDERLINE_BOLDLONGDASH) )
    3738             :                     {
    3739         292 :                         nMinDashWidth = nDotWidth*6;
    3740         292 :                         nMinSpaceWidth = nDotWidth*2;
    3741         292 :                         nDashWidth = 200;
    3742         292 :                         nSpaceWidth = 100;
    3743             :                     }
    3744             :                     else
    3745             :                     {
    3746         194 :                         nMinDashWidth = nDotWidth*4;
    3747         194 :                         nMinSpaceWidth = (nDotWidth*150)/100;
    3748         194 :                         nDashWidth = 100;
    3749         194 :                         nSpaceWidth = 50;
    3750             :                     }
    3751         486 :                     nDashWidth = ((nDashWidth*mnDPIX)+1270)/2540;
    3752         486 :                     nSpaceWidth = ((nSpaceWidth*mnDPIX)+1270)/2540;
    3753             :                     // DashWidth will be increased if the line is getting too thick
    3754             :                     // in proportion to the line's length
    3755         486 :                     if ( nDashWidth < nMinDashWidth )
    3756         372 :                         nDashWidth = nMinDashWidth;
    3757         486 :                     if ( nSpaceWidth < nMinSpaceWidth )
    3758         372 :                         nSpaceWidth = nMinSpaceWidth;
    3759         486 :                     long nTempWidth = nDashWidth;
    3760         486 :                     long nEnd = nLeft+nWidth;
    3761        1470 :                     while ( nLeft < nEnd )
    3762             :                     {
    3763         498 :                         if ( nLeft+nTempWidth > nEnd )
    3764         474 :                             nTempWidth = nEnd-nLeft;
    3765         498 :                         ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempWidth, nLineHeight );
    3766         498 :                         nLeft += nDashWidth+nSpaceWidth;
    3767             :                     }
    3768             :                 }
    3769         486 :                 break;
    3770             :             case UNDERLINE_DASHDOT:
    3771             :             case UNDERLINE_BOLDDASHDOT:
    3772             :                 {
    3773           0 :                     long nDotWidth = nLineHeight*mnDPIY;
    3774           0 :                     nDotWidth += mnDPIY/2;
    3775           0 :                     nDotWidth /= mnDPIY;
    3776           0 :                     long nDashWidth = ((100*mnDPIX)+1270)/2540;
    3777           0 :                     long nMinDashWidth = nDotWidth*4;
    3778             :                     // DashWidth will be increased if the line is getting too thick
    3779             :                     // in proportion to the line's length
    3780           0 :                     if ( nDashWidth < nMinDashWidth )
    3781           0 :                         nDashWidth = nMinDashWidth;
    3782           0 :                     long nTempDotWidth = nDotWidth;
    3783           0 :                     long nTempDashWidth = nDashWidth;
    3784           0 :                     long nEnd = nLeft+nWidth;
    3785           0 :                     while ( nLeft < nEnd )
    3786             :                     {
    3787           0 :                         if ( nLeft+nTempDotWidth > nEnd )
    3788           0 :                             nTempDotWidth = nEnd-nLeft;
    3789           0 :                         ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDotWidth, nLineHeight );
    3790           0 :                         nLeft += nDotWidth*2;
    3791           0 :                         if ( nLeft > nEnd )
    3792           0 :                             break;
    3793           0 :                         if ( nLeft+nTempDashWidth > nEnd )
    3794           0 :                             nTempDashWidth = nEnd-nLeft;
    3795           0 :                         ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDashWidth, nLineHeight );
    3796           0 :                         nLeft += nDashWidth+nDotWidth;
    3797             :                     }
    3798             :                 }
    3799           0 :                 break;
    3800             :             case UNDERLINE_DASHDOTDOT:
    3801             :             case UNDERLINE_BOLDDASHDOTDOT:
    3802             :                 {
    3803         624 :                     long nDotWidth = nLineHeight*mnDPIY;
    3804         624 :                     nDotWidth += mnDPIY/2;
    3805         624 :                     nDotWidth /= mnDPIY;
    3806         624 :                     long nDashWidth = ((100*mnDPIX)+1270)/2540;
    3807         624 :                     long nMinDashWidth = nDotWidth*4;
    3808             :                     // DashWidth will be increased if the line is getting too thick
    3809             :                     // in proportion to the line's length
    3810         624 :                     if ( nDashWidth < nMinDashWidth )
    3811         624 :                         nDashWidth = nMinDashWidth;
    3812         624 :                     long nTempDotWidth = nDotWidth;
    3813         624 :                     long nTempDashWidth = nDashWidth;
    3814         624 :                     long nEnd = nLeft+nWidth;
    3815        2350 :                     while ( nLeft < nEnd )
    3816             :                     {
    3817        1342 :                         if ( nLeft+nTempDotWidth > nEnd )
    3818          26 :                             nTempDotWidth = nEnd-nLeft;
    3819        1342 :                         ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDotWidth, nLineHeight );
    3820        1342 :                         nLeft += nDotWidth*2;
    3821        1342 :                         if ( nLeft > nEnd )
    3822         120 :                             break;
    3823        1222 :                         if ( nLeft+nTempDotWidth > nEnd )
    3824          74 :                             nTempDotWidth = nEnd-nLeft;
    3825        1222 :                         ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDotWidth, nLineHeight );
    3826        1222 :                         nLeft += nDotWidth*2;
    3827        1222 :                         if ( nLeft > nEnd )
    3828         120 :                             break;
    3829        1102 :                         if ( nLeft+nTempDashWidth > nEnd )
    3830         272 :                             nTempDashWidth = nEnd-nLeft;
    3831        1102 :                         ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDashWidth, nLineHeight );
    3832        1102 :                         nLeft += nDashWidth+nDotWidth;
    3833             :                     }
    3834             :                 }
    3835         624 :                 break;
    3836             :             default:
    3837           0 :                 break;
    3838             :         }
    3839             :     }
    3840       31670 : }
    3841             : 
    3842       15470 : void OutputDevice::ImplDrawStrikeoutLine( long nBaseX, long nBaseY,
    3843             :                                           long nDistX, long nDistY, long nWidth,
    3844             :                                           FontStrikeout eStrikeout,
    3845             :                                           Color aColor )
    3846             : {
    3847       15470 :     ImplFontEntry*  pFontEntry = mpFontEntry;
    3848       15470 :     long            nLineHeight = 0;
    3849       15470 :     long            nLinePos  = 0;
    3850       15470 :     long            nLinePos2 = 0;
    3851             : 
    3852       15470 :     long nY = nDistY;
    3853             : 
    3854       15470 :     if ( eStrikeout > STRIKEOUT_LAST )
    3855        1542 :         eStrikeout = STRIKEOUT_SINGLE;
    3856             : 
    3857       15470 :     switch ( eStrikeout )
    3858             :     {
    3859             :         case STRIKEOUT_SINGLE:
    3860        3694 :             nLineHeight = pFontEntry->maMetric.mnStrikeoutSize;
    3861        3694 :             nLinePos    = nY + pFontEntry->maMetric.mnStrikeoutOffset;
    3862        3694 :             break;
    3863             :         case STRIKEOUT_BOLD:
    3864         170 :             nLineHeight = pFontEntry->maMetric.mnBStrikeoutSize;
    3865         170 :             nLinePos    = nY + pFontEntry->maMetric.mnBStrikeoutOffset;
    3866         170 :             break;
    3867             :         case STRIKEOUT_DOUBLE:
    3868        1567 :             nLineHeight = pFontEntry->maMetric.mnDStrikeoutSize;
    3869        1567 :             nLinePos    = nY + pFontEntry->maMetric.mnDStrikeoutOffset1;
    3870        1567 :             nLinePos2   = nY + pFontEntry->maMetric.mnDStrikeoutOffset2;
    3871        1567 :             break;
    3872             :         default:
    3873       10039 :             break;
    3874             :     }
    3875             : 
    3876       15470 :     if ( nLineHeight )
    3877             :     {
    3878        5431 :         if ( mbLineColor || mbInitLineColor )
    3879             :         {
    3880        4893 :             mpGraphics->SetLineColor();
    3881        4893 :             mbInitLineColor = sal_True;
    3882             :         }
    3883        5431 :         mpGraphics->SetFillColor( ImplColorToSal( aColor ) );
    3884        5431 :         mbInitFillColor = sal_True;
    3885             : 
    3886        5431 :         const long& nLeft = nDistX;
    3887             : 
    3888        5431 :         switch ( eStrikeout )
    3889             :         {
    3890             :             case STRIKEOUT_SINGLE:
    3891             :             case STRIKEOUT_BOLD:
    3892        3864 :                 ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight );
    3893        3864 :                 break;
    3894             :             case STRIKEOUT_DOUBLE:
    3895        1567 :                 ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight );
    3896        1567 :                 ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos2, nWidth, nLineHeight );
    3897        1567 :                 break;
    3898             :             default:
    3899           0 :                 break;
    3900             :         }
    3901             :     }
    3902       15470 : }
    3903             : 
    3904         868 : void OutputDevice::ImplDrawStrikeoutChar( long nBaseX, long nBaseY,
    3905             :                                           long nDistX, long nDistY, long nWidth,
    3906             :                                           FontStrikeout eStrikeout,
    3907             :                                           Color aColor )
    3908             : {
    3909             :     // See qadevOOo/testdocs/StrikeThrough.odt for examples if you need
    3910             :     // to tweak this
    3911         868 :     if (!nWidth)
    3912          40 :         return;
    3913             : 
    3914             :     // prepare string for strikeout measurement
    3915             :     static char cStrikeoutChar;
    3916         868 :     if ( eStrikeout == STRIKEOUT_SLASH )
    3917         316 :         cStrikeoutChar = '/';
    3918             :     else // ( eStrikeout == STRIKEOUT_X )
    3919         552 :         cStrikeoutChar = 'X';
    3920             :     static const int nTestStrLen = 4;
    3921             :     static const int nMaxStrikeStrLen = 2048;
    3922             :     sal_Unicode aChars[nMaxStrikeStrLen+1]; // +1 for valgrind...
    3923        4340 :     for( int i = 0; i < nTestStrLen; ++i)
    3924        3472 :         aChars[i] = cStrikeoutChar;
    3925         868 :     const OUString aStrikeoutTest(aChars, nTestStrLen);
    3926             : 
    3927             :     // calculate approximation of strikeout atom size
    3928         868 :     long nStrikeoutWidth = 0;
    3929         868 :     SalLayout* pLayout = ImplLayout( aStrikeoutTest, 0, nTestStrLen );
    3930         868 :     if( pLayout )
    3931             :     {
    3932         868 :         nStrikeoutWidth = pLayout->GetTextWidth() / (nTestStrLen * pLayout->GetUnitsPerPixel());
    3933         868 :         pLayout->Release();
    3934             :     }
    3935         868 :     if( nStrikeoutWidth <= 0 ) // sanity check
    3936          40 :         return;
    3937             : 
    3938         828 :     int nStrikeStrLen = (nWidth+(nStrikeoutWidth-1)) / nStrikeoutWidth;
    3939         828 :     if( nStrikeStrLen > nMaxStrikeStrLen )
    3940           0 :         nStrikeStrLen = nMaxStrikeStrLen;
    3941             : 
    3942             :     // build the strikeout string
    3943        4560 :     for( int i = nTestStrLen; i < nStrikeStrLen; ++i)
    3944        3732 :         aChars[i] = cStrikeoutChar;
    3945        1656 :     const OUString aStrikeoutText(aChars, nStrikeStrLen);
    3946             : 
    3947         828 :     if( mpFontEntry->mnOrientation )
    3948         828 :         ImplRotatePos( 0, 0, nDistX, nDistY, mpFontEntry->mnOrientation );
    3949         828 :     nBaseX += nDistX;
    3950         828 :     nBaseY += nDistY;
    3951             : 
    3952             :     // strikeout text has to be left aligned
    3953         828 :     sal_uLong nOrigTLM = mnTextLayoutMode;
    3954         828 :     mnTextLayoutMode = TEXT_LAYOUT_BIDI_STRONG | TEXT_LAYOUT_COMPLEX_DISABLED;
    3955         828 :     pLayout = ImplLayout( aStrikeoutText, 0, STRING_LEN );
    3956         828 :     mnTextLayoutMode = nOrigTLM;
    3957             : 
    3958         828 :     if( !pLayout )
    3959           0 :         return;
    3960             : 
    3961             :     // draw the strikeout text
    3962         828 :     const Color aOldColor = GetTextColor();
    3963         828 :     SetTextColor( aColor );
    3964         828 :     ImplInitTextColor();
    3965             : 
    3966         828 :     pLayout->DrawBase() = Point( nBaseX+mnTextOffX, nBaseY+mnTextOffY );
    3967             : 
    3968         828 :     Rectangle aPixelRect;
    3969         828 :     aPixelRect.Left() = nBaseX+mnTextOffX;
    3970         828 :     aPixelRect.Right() = aPixelRect.Left()+nWidth;
    3971         828 :     aPixelRect.Bottom() = nBaseY+mpFontEntry->maMetric.mnDescent;
    3972         828 :     aPixelRect.Top() = nBaseY-mpFontEntry->maMetric.mnAscent;
    3973             : 
    3974         828 :     if (mpFontEntry->mnOrientation)
    3975             :     {
    3976         828 :         Polygon aPoly( aPixelRect );
    3977         828 :         aPoly.Rotate( Point(nBaseX+mnTextOffX, nBaseY+mnTextOffY), mpFontEntry->mnOrientation);
    3978         828 :         aPixelRect = aPoly.GetBoundRect();
    3979             :     }
    3980             : 
    3981         828 :     Push( PUSH_CLIPREGION );
    3982         828 :     IntersectClipRegion( PixelToLogic(aPixelRect) );
    3983         828 :     if( mbInitClipRegion )
    3984         828 :         ImplInitClipRegion();
    3985             : 
    3986         828 :     pLayout->DrawText( *mpGraphics );
    3987             : 
    3988         828 :     pLayout->Release();
    3989         828 :     Pop();
    3990             : 
    3991         828 :     SetTextColor( aOldColor );
    3992        1656 :     ImplInitTextColor();
    3993             : }
    3994             : 
    3995       16350 : void OutputDevice::ImplDrawTextLine( long nX, long nY,
    3996             :                                      long nDistX, long nWidth,
    3997             :                                      FontStrikeout eStrikeout,
    3998             :                                      FontUnderline eUnderline,
    3999             :                                      FontUnderline eOverline,
    4000             :                                      sal_Bool bUnderlineAbove )
    4001             : {
    4002       16350 :     if ( !nWidth )
    4003       16362 :         return;
    4004             : 
    4005       16338 :     Color           aStrikeoutColor = GetTextColor();
    4006       16338 :     Color           aUnderlineColor = GetTextLineColor();
    4007       16338 :     Color           aOverlineColor  = GetOverlineColor();
    4008       16338 :     bool            bStrikeoutDone = false;
    4009       16338 :     bool            bUnderlineDone = false;
    4010       16338 :     bool            bOverlineDone  = false;
    4011             : 
    4012       16338 :     if ( IsRTLEnabled() )
    4013             :     {
    4014             :         // --- RTL --- mirror at basex
    4015         104 :         long nXAdd = nWidth - nDistX;
    4016         104 :         if( mpFontEntry->mnOrientation )
    4017         104 :             nXAdd = FRound( nXAdd * cos( mpFontEntry->mnOrientation * F_PI1800 ) );
    4018         104 :         nX += nXAdd - 1;
    4019             :     }
    4020             : 
    4021       16338 :     if ( !IsTextLineColor() )
    4022        8977 :         aUnderlineColor = GetTextColor();
    4023             : 
    4024       16338 :     if ( !IsOverlineColor() )
    4025        9560 :         aOverlineColor = GetTextColor();
    4026             : 
    4027       16338 :     if ( (eUnderline == UNDERLINE_SMALLWAVE) ||
    4028       16338 :          (eUnderline == UNDERLINE_WAVE) ||
    4029       16338 :          (eUnderline == UNDERLINE_DOUBLEWAVE) ||
    4030             :          (eUnderline == UNDERLINE_BOLDWAVE) )
    4031             :     {
    4032        1006 :         ImplDrawWaveTextLine( nX, nY, nDistX, 0, nWidth, eUnderline, aUnderlineColor, bUnderlineAbove );
    4033        1006 :         bUnderlineDone = true;
    4034             :     }
    4035       16338 :     if ( (eOverline == UNDERLINE_SMALLWAVE) ||
    4036       16338 :          (eOverline == UNDERLINE_WAVE) ||
    4037       16338 :          (eOverline == UNDERLINE_DOUBLEWAVE) ||
    4038             :          (eOverline == UNDERLINE_BOLDWAVE) )
    4039             :     {
    4040           0 :         ImplDrawWaveTextLine( nX, nY, nDistX, 0, nWidth, eOverline, aOverlineColor, sal_True );
    4041           0 :         bOverlineDone = true;
    4042             :     }
    4043             : 
    4044       16338 :     if ( (eStrikeout == STRIKEOUT_SLASH) ||
    4045             :          (eStrikeout == STRIKEOUT_X) )
    4046             :     {
    4047         868 :         ImplDrawStrikeoutChar( nX, nY, nDistX, 0, nWidth, eStrikeout, aStrikeoutColor );
    4048         868 :         bStrikeoutDone = true;
    4049             :     }
    4050             : 
    4051       16338 :     if ( !bUnderlineDone )
    4052       15332 :         ImplDrawStraightTextLine( nX, nY, nDistX, 0, nWidth, eUnderline, aUnderlineColor, bUnderlineAbove );
    4053             : 
    4054       16338 :     if ( !bOverlineDone )
    4055       16338 :         ImplDrawStraightTextLine( nX, nY, nDistX, 0, nWidth, eOverline, aOverlineColor, sal_True );
    4056             : 
    4057       16338 :     if ( !bStrikeoutDone )
    4058       15470 :         ImplDrawStrikeoutLine( nX, nY, nDistX, 0, nWidth, eStrikeout, aStrikeoutColor );
    4059             : }
    4060             : 
    4061        8739 : void OutputDevice::ImplDrawTextLines( SalLayout& rSalLayout,
    4062             :     FontStrikeout eStrikeout, FontUnderline eUnderline, FontUnderline eOverline, sal_Bool bWordLine, sal_Bool bUnderlineAbove )
    4063             : {
    4064        8739 :     if( bWordLine )
    4065             :     {
    4066             :         // draw everything relative to the layout base point
    4067        4501 :         const Point aStartPt = rSalLayout.DrawBase();
    4068             : 
    4069             :         // calculate distance of each word from the base point
    4070        4501 :         Point aPos;
    4071        4501 :         sal_Int32 nDist = 0, nWidth = 0, nAdvance=0;
    4072        4501 :         for( int nStart = 0;;)
    4073             :         {
    4074             :             // iterate through the layouted glyphs
    4075             :             sal_GlyphId nGlyphIndex;
    4076       23142 :             if( !rSalLayout.GetNextGlyphs( 1, &nGlyphIndex, aPos, nStart, &nAdvance ) )
    4077        4501 :                 break;
    4078             : 
    4079             :             // calculate the boundaries of each word
    4080       18641 :             if( !rSalLayout.IsSpacingGlyph( nGlyphIndex ) )
    4081             :             {
    4082       17771 :                 if( !nWidth )
    4083             :                 {
    4084             :                     // get the distance to the base point (as projected to baseline)
    4085        4913 :                     nDist = aPos.X() - aStartPt.X();
    4086        4913 :                     if( mpFontEntry->mnOrientation )
    4087             :                     {
    4088        1760 :                         const long nDY = aPos.Y() - aStartPt.Y();
    4089        1760 :                         const double fRad = mpFontEntry->mnOrientation * F_PI1800;
    4090        1760 :                         nDist = FRound( nDist*cos(fRad) - nDY*sin(fRad) );
    4091             :                     }
    4092             :                 }
    4093             : 
    4094             :                 // update the length of the textline
    4095       17771 :                 nWidth += nAdvance;
    4096             :             }
    4097         870 :             else if( nWidth > 0 )
    4098             :             {
    4099             :                 // draw the textline for each word
    4100             :                 ImplDrawTextLine( aStartPt.X(), aStartPt.Y(), nDist, nWidth,
    4101         814 :                     eStrikeout, eUnderline, eOverline, bUnderlineAbove );
    4102         814 :                 nWidth = 0;
    4103             :             }
    4104       18641 :         }
    4105             : 
    4106             :         // draw textline for the last word
    4107        4501 :         if( nWidth > 0 )
    4108             :         {
    4109             :             ImplDrawTextLine( aStartPt.X(), aStartPt.Y(), nDist, nWidth,
    4110        4099 :                 eStrikeout, eUnderline, eOverline, bUnderlineAbove );
    4111             :         }
    4112             :     }
    4113             :     else
    4114             :     {
    4115        4238 :         Point aStartPt = rSalLayout.GetDrawPosition();
    4116        4238 :         int nWidth = rSalLayout.GetTextWidth() / rSalLayout.GetUnitsPerPixel();
    4117        8476 :         ImplDrawTextLine( aStartPt.X(), aStartPt.Y(), 0, nWidth,
    4118       12714 :             eStrikeout, eUnderline, eOverline, bUnderlineAbove );
    4119             :     }
    4120        8739 : }
    4121             : 
    4122        7199 : void OutputDevice::ImplDrawMnemonicLine( long nX, long nY, long nWidth )
    4123             : {
    4124        7199 :     long nBaseX = nX;
    4125        7199 :     if( /*ImplHasMirroredGraphics() &&*/ IsRTLEnabled() )
    4126             :     {
    4127             :         // --- RTL ---
    4128             :         // add some strange offset
    4129           0 :         nX += 2;
    4130             :         // revert the hack that will be done later in ImplDrawTextLine
    4131           0 :         nX = nBaseX - nWidth - (nX - nBaseX - 1);
    4132             :     }
    4133             : 
    4134        7199 :     ImplDrawTextLine( nX, nY, 0, nWidth, STRIKEOUT_NONE, UNDERLINE_SINGLE, UNDERLINE_NONE, sal_False );
    4135        7199 : }
    4136             : 
    4137        8024 : void OutputDevice::ImplGetEmphasisMark( PolyPolygon& rPolyPoly, sal_Bool& rPolyLine,
    4138             :                                         Rectangle& rRect1, Rectangle& rRect2,
    4139             :                                         long& rYOff, long& rWidth,
    4140             :                                         FontEmphasisMark eEmphasis,
    4141             :                                         long nHeight, short /*nOrient*/ )
    4142             : {
    4143             :     static const sal_uInt8 aAccentPolyFlags[24] =
    4144             :     {
    4145             :         0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 0, 2, 0, 2, 2
    4146             :     };
    4147             : 
    4148             :     static const long aAccentPos[48] =
    4149             :     {
    4150             :          78,      0,
    4151             :         348,     79,
    4152             :         599,    235,
    4153             :         843,    469,
    4154             :         938,    574,
    4155             :         990,    669,
    4156             :         990,    773,
    4157             :         990,    843,
    4158             :         964,    895,
    4159             :         921,    947,
    4160             :         886,    982,
    4161             :         860,    999,
    4162             :         825,    999,
    4163             :         764,    999,
    4164             :         721,    964,
    4165             :         686,    895,
    4166             :         625,    791,
    4167             :         556,    660,
    4168             :         469,    504,
    4169             :         400,    400,
    4170             :         261,    252,
    4171             :          61,     61,
    4172             :           0,     27,
    4173             :           9,      0
    4174             :     };
    4175             : 
    4176        8024 :     rWidth      = 0;
    4177        8024 :     rYOff       = 0;
    4178        8024 :     rPolyLine   = sal_False;
    4179             : 
    4180        8024 :     if ( !nHeight )
    4181        8024 :         return;
    4182             : 
    4183        8024 :     FontEmphasisMark    nEmphasisStyle = eEmphasis & EMPHASISMARK_STYLE;
    4184        8024 :     long                nDotSize = 0;
    4185        8024 :     switch ( nEmphasisStyle )
    4186             :     {
    4187             :         case EMPHASISMARK_DOT:
    4188             :             // Dot has 55% of the height
    4189        2608 :             nDotSize = (nHeight*550)/1000;
    4190        2608 :             if ( !nDotSize )
    4191         194 :                 nDotSize = 1;
    4192        2608 :             if ( nDotSize <= 2 )
    4193        1198 :                 rRect1 = Rectangle( Point(), Size( nDotSize, nDotSize ) );
    4194             :             else
    4195             :             {
    4196        1410 :                 long nRad = nDotSize/2;
    4197        1410 :                 Polygon aPoly( Point( nRad, nRad ), nRad, nRad );
    4198        1410 :                 rPolyPoly.Insert( aPoly );
    4199             :             }
    4200        2608 :             rYOff = ((nHeight*250)/1000)/2; // Center to the another EmphasisMarks
    4201        2608 :             rWidth = nDotSize;
    4202        2608 :             break;
    4203             : 
    4204             :         case EMPHASISMARK_CIRCLE:
    4205             :             // Dot has 80% of the height
    4206        3244 :             nDotSize = (nHeight*800)/1000;
    4207        3244 :             if ( !nDotSize )
    4208         102 :                 nDotSize = 1;
    4209        3244 :             if ( nDotSize <= 2 )
    4210         102 :                 rRect1 = Rectangle( Point(), Size( nDotSize, nDotSize ) );
    4211             :             else
    4212             :             {
    4213        3142 :                 long nRad = nDotSize/2;
    4214        3142 :                 Polygon aPoly( Point( nRad, nRad ), nRad, nRad );
    4215        3142 :                 rPolyPoly.Insert( aPoly );
    4216             :                 // BorderWidth is 15%
    4217        3142 :                 long nBorder = (nDotSize*150)/1000;
    4218        3142 :                 if ( nBorder <= 1 )
    4219        3142 :                     rPolyLine = sal_True;
    4220             :                 else
    4221             :                 {
    4222             :                     Polygon aPoly2( Point( nRad, nRad ),
    4223           0 :                                     nRad-nBorder, nRad-nBorder );
    4224           0 :                     rPolyPoly.Insert( aPoly2 );
    4225        3142 :                 }
    4226             :             }
    4227        3244 :             rWidth = nDotSize;
    4228        3244 :             break;
    4229             : 
    4230             :         case EMPHASISMARK_DISC:
    4231             :             // Dot has 80% of the height
    4232        2002 :             nDotSize = (nHeight*800)/1000;
    4233        2002 :             if ( !nDotSize )
    4234           0 :                 nDotSize = 1;
    4235        2002 :             if ( nDotSize <= 2 )
    4236           0 :                 rRect1 = Rectangle( Point(), Size( nDotSize, nDotSize ) );
    4237             :             else
    4238             :             {
    4239        2002 :                 long nRad = nDotSize/2;
    4240        2002 :                 Polygon aPoly( Point( nRad, nRad ), nRad, nRad );
    4241        2002 :                 rPolyPoly.Insert( aPoly );
    4242             :             }
    4243        2002 :             rWidth = nDotSize;
    4244        2002 :             break;
    4245             : 
    4246             :         case EMPHASISMARK_ACCENT:
    4247             :             // Dot has 80% of the height
    4248         170 :             nDotSize = (nHeight*800)/1000;
    4249         170 :             if ( !nDotSize )
    4250           0 :                 nDotSize = 1;
    4251         170 :             if ( nDotSize <= 2 )
    4252             :             {
    4253           0 :                 if ( nDotSize == 1 )
    4254             :                 {
    4255           0 :                     rRect1 = Rectangle( Point(), Size( nDotSize, nDotSize ) );
    4256           0 :                     rWidth = nDotSize;
    4257             :                 }
    4258             :                 else
    4259             :                 {
    4260           0 :                     rRect1 = Rectangle( Point(), Size( 1, 1 ) );
    4261           0 :                     rRect2 = Rectangle( Point( 1, 1 ), Size( 1, 1 ) );
    4262             :                 }
    4263             :             }
    4264             :             else
    4265             :             {
    4266         170 :                 Polygon aPoly( sizeof( aAccentPos ) / sizeof( long ) / 2,
    4267             :                                (const Point*)aAccentPos,
    4268         170 :                                aAccentPolyFlags );
    4269         170 :                 double dScale = ((double)nDotSize)/1000.0;
    4270         170 :                 aPoly.Scale( dScale, dScale );
    4271         340 :                 Polygon aTemp;
    4272         170 :                 aPoly.AdaptiveSubdivide( aTemp );
    4273         170 :                 Rectangle aBoundRect = aTemp.GetBoundRect();
    4274         170 :                 rWidth = aBoundRect.GetWidth();
    4275         170 :                 nDotSize = aBoundRect.GetHeight();
    4276         340 :                 rPolyPoly.Insert( aTemp );
    4277             :             }
    4278         170 :             break;
    4279             :     }
    4280             : 
    4281             :     // calculate position
    4282        8024 :     long nOffY = 1+(mnDPIY/300); // one visible pixel space
    4283        8024 :     long nSpaceY = nHeight-nDotSize;
    4284        8024 :     if ( nSpaceY >= nOffY*2 )
    4285        7308 :         rYOff += nOffY;
    4286        8024 :     if ( !(eEmphasis & EMPHASISMARK_POS_BELOW) )
    4287        8024 :         rYOff += nDotSize;
    4288             : }
    4289             : 
    4290       33282 : void OutputDevice::ImplDrawEmphasisMark( long nBaseX, long nX, long nY,
    4291             :                                          const PolyPolygon& rPolyPoly, sal_Bool bPolyLine,
    4292             :                                          const Rectangle& rRect1, const Rectangle& rRect2 )
    4293             : {
    4294       33282 :     if( IsRTLEnabled() )
    4295             :         // --- RTL --- mirror at basex
    4296         316 :         nX = nBaseX - (nX - nBaseX - 1);
    4297             : 
    4298       33282 :     nX -= mnOutOffX;
    4299       33282 :     nY -= mnOutOffY;
    4300             : 
    4301       33282 :     if ( rPolyPoly.Count() )
    4302             :     {
    4303       27744 :         if ( bPolyLine )
    4304             :         {
    4305       12542 :             Polygon aPoly = rPolyPoly.GetObject( 0 );
    4306       12542 :             aPoly.Move( nX, nY );
    4307       12542 :             DrawPolyLine( aPoly );
    4308             :         }
    4309             :         else
    4310             :         {
    4311       15202 :             PolyPolygon aPolyPoly = rPolyPoly;
    4312       15202 :             aPolyPoly.Move( nX, nY );
    4313       15202 :             DrawPolyPolygon( aPolyPoly );
    4314             :         }
    4315             :     }
    4316             : 
    4317       33282 :     if ( !rRect1.IsEmpty() )
    4318             :     {
    4319        5538 :         Rectangle aRect( Point( nX+rRect1.Left(),
    4320       11076 :                                 nY+rRect1.Top() ), rRect1.GetSize() );
    4321        5538 :         DrawRect( aRect );
    4322             :     }
    4323             : 
    4324       33282 :     if ( !rRect2.IsEmpty() )
    4325             :     {
    4326           0 :         Rectangle aRect( Point( nX+rRect2.Left(),
    4327           0 :                                 nY+rRect2.Top() ), rRect2.GetSize() );
    4328             : 
    4329           0 :         DrawRect( aRect );
    4330             :     }
    4331       33282 : }
    4332             : 
    4333        8024 : void OutputDevice::ImplDrawEmphasisMarks( SalLayout& rSalLayout )
    4334             : {
    4335        8024 :     Color               aOldLineColor   = GetLineColor();
    4336        8024 :     Color               aOldFillColor   = GetFillColor();
    4337        8024 :     sal_Bool                bOldMap         = mbMap;
    4338        8024 :     GDIMetaFile*        pOldMetaFile    = mpMetaFile;
    4339        8024 :     mpMetaFile = NULL;
    4340        8024 :     EnableMapMode( sal_False );
    4341             : 
    4342        8024 :     FontEmphasisMark    nEmphasisMark = ImplGetEmphasisMarkStyle( maFont );
    4343        8024 :     PolyPolygon         aPolyPoly;
    4344        8024 :     Rectangle           aRect1;
    4345        8024 :     Rectangle           aRect2;
    4346             :     long                nEmphasisYOff;
    4347             :     long                nEmphasisWidth;
    4348             :     long                nEmphasisHeight;
    4349             :     sal_Bool                bPolyLine;
    4350             : 
    4351        8024 :     if ( nEmphasisMark & EMPHASISMARK_POS_BELOW )
    4352           0 :         nEmphasisHeight = mnEmphasisDescent;
    4353             :     else
    4354        8024 :         nEmphasisHeight = mnEmphasisAscent;
    4355             : 
    4356             :     ImplGetEmphasisMark( aPolyPoly, bPolyLine,
    4357             :                          aRect1, aRect2,
    4358             :                          nEmphasisYOff, nEmphasisWidth,
    4359             :                          nEmphasisMark,
    4360        8024 :                          nEmphasisHeight, mpFontEntry->mnOrientation );
    4361             : 
    4362        8024 :     if ( bPolyLine )
    4363             :     {
    4364        3142 :         SetLineColor( GetTextColor() );
    4365        3142 :         SetFillColor();
    4366             :     }
    4367             :     else
    4368             :     {
    4369        4882 :         SetLineColor();
    4370        4882 :         SetFillColor( GetTextColor() );
    4371             :     }
    4372             : 
    4373        8024 :     Point aOffset = Point(0,0);
    4374             : 
    4375        8024 :     if ( nEmphasisMark & EMPHASISMARK_POS_BELOW )
    4376           0 :         aOffset.Y() += mpFontEntry->maMetric.mnDescent + nEmphasisYOff;
    4377             :     else
    4378        8024 :         aOffset.Y() -= mpFontEntry->maMetric.mnAscent + nEmphasisYOff;
    4379             : 
    4380        8024 :     long nEmphasisWidth2  = nEmphasisWidth / 2;
    4381        8024 :     long nEmphasisHeight2 = nEmphasisHeight / 2;
    4382        8024 :     aOffset += Point( nEmphasisWidth2, nEmphasisHeight2 );
    4383             : 
    4384        8024 :     Point aOutPoint;
    4385        8024 :     Rectangle aRectangle;
    4386        8024 :     for( int nStart = 0;;)
    4387             :     {
    4388             :         sal_GlyphId nGlyphIndex;
    4389       43041 :         if( !rSalLayout.GetNextGlyphs( 1, &nGlyphIndex, aOutPoint, nStart ) )
    4390        8024 :             break;
    4391             : 
    4392       35017 :         if( !mpGraphics->GetGlyphBoundRect( nGlyphIndex, aRectangle ) )
    4393           0 :             continue;
    4394             : 
    4395       35017 :         if( !rSalLayout.IsSpacingGlyph( nGlyphIndex ) )
    4396             :         {
    4397       33282 :             Point aAdjPoint = aOffset;
    4398       33282 :             aAdjPoint.X() += aRectangle.Left() + (aRectangle.GetWidth() - nEmphasisWidth) / 2;
    4399       33282 :             if ( mpFontEntry->mnOrientation )
    4400       19932 :                 ImplRotatePos( 0, 0, aAdjPoint.X(), aAdjPoint.Y(), mpFontEntry->mnOrientation );
    4401       33282 :             aOutPoint += aAdjPoint;
    4402       33282 :             aOutPoint -= Point( nEmphasisWidth2, nEmphasisHeight2 );
    4403       33282 :             ImplDrawEmphasisMark( rSalLayout.DrawBase().X(),
    4404       66564 :                                   aOutPoint.X(), aOutPoint.Y(),
    4405      133128 :                                   aPolyPoly, bPolyLine, aRect1, aRect2 );
    4406             :         }
    4407       35017 :     }
    4408             : 
    4409        8024 :     SetLineColor( aOldLineColor );
    4410        8024 :     SetFillColor( aOldFillColor );
    4411        8024 :     EnableMapMode( bOldMap );
    4412        8024 :     mpMetaFile = pOldMetaFile;
    4413        8024 : }
    4414             : 
    4415           0 : bool OutputDevice::ImplDrawRotateText( SalLayout& rSalLayout )
    4416             : {
    4417           0 :     int nX = rSalLayout.DrawBase().X();
    4418           0 :     int nY = rSalLayout.DrawBase().Y();
    4419             : 
    4420           0 :     Rectangle aBoundRect;
    4421           0 :     rSalLayout.DrawBase() = Point( 0, 0 );
    4422           0 :     rSalLayout.DrawOffset() = Point( 0, 0 );
    4423           0 :     if( !rSalLayout.GetBoundRect( *mpGraphics, aBoundRect ) )
    4424             :     {
    4425             :         // guess vertical text extents if GetBoundRect failed
    4426           0 :         int nRight = rSalLayout.GetTextWidth();
    4427           0 :         int nTop = mpFontEntry->maMetric.mnAscent + mnEmphasisAscent;
    4428           0 :         long nHeight = mpFontEntry->mnLineHeight + mnEmphasisAscent + mnEmphasisDescent;
    4429           0 :         aBoundRect = Rectangle( 0, -nTop, nRight, nHeight - nTop );
    4430             :     }
    4431             : 
    4432             :     // cache virtual device for rotation
    4433           0 :     if ( !mpOutDevData )
    4434           0 :         ImplInitOutDevData();
    4435           0 :     if ( !mpOutDevData->mpRotateDev )
    4436           0 :         mpOutDevData->mpRotateDev = new VirtualDevice( *this, 1 );
    4437           0 :     VirtualDevice* pVDev = mpOutDevData->mpRotateDev;
    4438             : 
    4439             :     // size it accordingly
    4440           0 :     if( !pVDev->SetOutputSizePixel( aBoundRect.GetSize() ) )
    4441           0 :         return false;
    4442             : 
    4443           0 :     Font aFont( GetFont() );
    4444           0 :     aFont.SetOrientation( 0 );
    4445           0 :     aFont.SetSize( Size( mpFontEntry->maFontSelData.mnWidth, mpFontEntry->maFontSelData.mnHeight ) );
    4446           0 :     pVDev->SetFont( aFont );
    4447           0 :     pVDev->SetTextColor( Color( COL_BLACK ) );
    4448           0 :     pVDev->SetTextFillColor();
    4449           0 :     pVDev->ImplNewFont();
    4450           0 :     pVDev->ImplInitFont();
    4451           0 :     pVDev->ImplInitTextColor();
    4452             : 
    4453             :     // draw text into upper left corner
    4454           0 :     rSalLayout.DrawBase() -= aBoundRect.TopLeft();
    4455           0 :     rSalLayout.DrawText( *((OutputDevice*)pVDev)->mpGraphics );
    4456             : 
    4457           0 :     Bitmap aBmp = pVDev->GetBitmap( Point(), aBoundRect.GetSize() );
    4458           0 :     if ( !aBmp || !aBmp.Rotate( mpFontEntry->mnOwnOrientation, COL_WHITE ) )
    4459           0 :         return false;
    4460             : 
    4461             :     // calculate rotation offset
    4462           0 :     Polygon aPoly( aBoundRect );
    4463           0 :     aPoly.Rotate( Point(), mpFontEntry->mnOwnOrientation );
    4464           0 :     Point aPoint = aPoly.GetBoundRect().TopLeft();
    4465           0 :     aPoint += Point( nX, nY );
    4466             : 
    4467             :     // mask output with text colored bitmap
    4468           0 :     GDIMetaFile* pOldMetaFile = mpMetaFile;
    4469           0 :     long nOldOffX = mnOutOffX;
    4470           0 :     long nOldOffY = mnOutOffY;
    4471           0 :     sal_Bool bOldMap = mbMap;
    4472             : 
    4473           0 :     mnOutOffX   = 0L;
    4474           0 :     mnOutOffY   = 0L;
    4475           0 :     mpMetaFile  = NULL;
    4476           0 :     EnableMapMode( sal_False );
    4477             : 
    4478           0 :     DrawMask( aPoint, aBmp, GetTextColor() );
    4479             : 
    4480           0 :     EnableMapMode( bOldMap );
    4481           0 :     mnOutOffX   = nOldOffX;
    4482           0 :     mnOutOffY   = nOldOffY;
    4483           0 :     mpMetaFile  = pOldMetaFile;
    4484             : 
    4485           0 :     return true;
    4486             : }
    4487             : 
    4488       90487 : void OutputDevice::ImplDrawTextDirect( SalLayout& rSalLayout, sal_Bool bTextLines )
    4489             : {
    4490       90487 :     if( mpFontEntry->mnOwnOrientation )
    4491           0 :         if( ImplDrawRotateText( rSalLayout ) )
    4492       90487 :             return;
    4493             : 
    4494       90487 :     long nOldX = rSalLayout.DrawBase().X();
    4495       90487 :     if( ImplHasMirroredGraphics() )
    4496             :     {
    4497         195 :         long w = meOutDevType == OUTDEV_VIRDEV ? mnOutWidth : mpGraphics->GetGraphicsWidth();
    4498         195 :         long x = rSalLayout.DrawBase().X();
    4499         195 :            rSalLayout.DrawBase().X() = w - 1 - x;
    4500         195 :         if( !IsRTLEnabled() )
    4501             :         {
    4502           0 :             OutputDevice *pOutDevRef = (OutputDevice *)this;
    4503             :             // mirror this window back
    4504           0 :             long devX = w-pOutDevRef->mnOutWidth-pOutDevRef->mnOutOffX;   // re-mirrored mnOutOffX
    4505           0 :             rSalLayout.DrawBase().X() = devX + ( pOutDevRef->mnOutWidth - 1 - (rSalLayout.DrawBase().X() - devX) ) ;
    4506             :         }
    4507             :     }
    4508       90292 :     else if( IsRTLEnabled() )
    4509             :     {
    4510           0 :         OutputDevice *pOutDevRef = (OutputDevice *)this;
    4511             : 
    4512             :         // mirror this window back
    4513           0 :         long devX = pOutDevRef->mnOutOffX;   // re-mirrored mnOutOffX
    4514           0 :         rSalLayout.DrawBase().X() = pOutDevRef->mnOutWidth - 1 - (rSalLayout.DrawBase().X() - devX) + devX;
    4515             :     }
    4516             : 
    4517       90487 :     rSalLayout.DrawText( *mpGraphics );
    4518             : 
    4519       90487 :     rSalLayout.DrawBase().X() = nOldX;
    4520             : 
    4521       90487 :     if( bTextLines )
    4522             :         ImplDrawTextLines( rSalLayout,
    4523             :             maFont.GetStrikeout(), maFont.GetUnderline(), maFont.GetOverline(),
    4524        8739 :             maFont.IsWordLineMode(), ImplIsUnderlineAbove( maFont ) );
    4525             : 
    4526             :     // emphasis marks
    4527       90487 :     if( maFont.GetEmphasisMark() & EMPHASISMARK_STYLE )
    4528        8024 :         ImplDrawEmphasisMarks( rSalLayout );
    4529             : }
    4530             : 
    4531        3482 : void OutputDevice::ImplDrawSpecialText( SalLayout& rSalLayout )
    4532             : {
    4533        3482 :     Color       aOldColor           = GetTextColor();
    4534        3482 :     Color       aOldTextLineColor   = GetTextLineColor();
    4535        3482 :     Color       aOldOverlineColor   = GetOverlineColor();
    4536        3482 :     FontRelief  eRelief             = maFont.GetRelief();
    4537             : 
    4538        3482 :     Point aOrigPos = rSalLayout.DrawBase();
    4539        3482 :     if ( eRelief != RELIEF_NONE )
    4540             :     {
    4541        3261 :         Color   aReliefColor( COL_LIGHTGRAY );
    4542        3261 :         Color   aTextColor( aOldColor );
    4543             : 
    4544        3261 :         Color   aTextLineColor( aOldTextLineColor );
    4545        3261 :         Color   aOverlineColor( aOldOverlineColor );
    4546             : 
    4547             :         // we don't have a automatic color, so black is always drawn on white
    4548        3261 :         if ( aTextColor.GetColor() == COL_BLACK )
    4549         806 :             aTextColor = Color( COL_WHITE );
    4550        3261 :         if ( aTextLineColor.GetColor() == COL_BLACK )
    4551         646 :             aTextLineColor = Color( COL_WHITE );
    4552        3261 :         if ( aOverlineColor.GetColor() == COL_BLACK )
    4553         646 :             aOverlineColor = Color( COL_WHITE );
    4554             : 
    4555             :         // relief-color is black for white text, in all other cases
    4556             :         // we set this to LightGray
    4557        3261 :         if ( aTextColor.GetColor() == COL_WHITE )
    4558         837 :             aReliefColor = Color( COL_BLACK );
    4559        3261 :         SetTextLineColor( aReliefColor );
    4560        3261 :         SetOverlineColor( aReliefColor );
    4561        3261 :         SetTextColor( aReliefColor );
    4562        3261 :         ImplInitTextColor();
    4563             : 
    4564             :         // calculate offset - for high resolution printers the offset
    4565             :         // should be greater so that the effect is visible
    4566        3261 :         long nOff = 1;
    4567        3261 :         nOff += mnDPIX/300;
    4568             : 
    4569        3261 :         if ( eRelief == RELIEF_ENGRAVED )
    4570        1143 :             nOff = -nOff;
    4571        3261 :         rSalLayout.DrawOffset() += Point( nOff, nOff);
    4572        3261 :         ImplDrawTextDirect( rSalLayout, mbTextLines );
    4573        3261 :         rSalLayout.DrawOffset() -= Point( nOff, nOff);
    4574             : 
    4575        3261 :         SetTextLineColor( aTextLineColor );
    4576        3261 :         SetOverlineColor( aOverlineColor );
    4577        3261 :         SetTextColor( aTextColor );
    4578        3261 :         ImplInitTextColor();
    4579        3261 :         ImplDrawTextDirect( rSalLayout, mbTextLines );
    4580             : 
    4581        3261 :         SetTextLineColor( aOldTextLineColor );
    4582        3261 :         SetOverlineColor( aOldOverlineColor );
    4583             : 
    4584        3261 :         if ( aTextColor != aOldColor )
    4585             :         {
    4586         806 :             SetTextColor( aOldColor );
    4587         806 :             ImplInitTextColor();
    4588             :         }
    4589             :     }
    4590             :     else
    4591             :     {
    4592         221 :         if ( maFont.IsShadow() )
    4593             :         {
    4594         179 :             long nOff = 1 + ((mpFontEntry->mnLineHeight-24)/24);
    4595         179 :             if ( maFont.IsOutline() )
    4596         136 :                 nOff++;
    4597         179 :             SetTextLineColor();
    4598         179 :             SetOverlineColor();
    4599         358 :             if ( (GetTextColor().GetColor() == COL_BLACK)
    4600         179 :             ||   (GetTextColor().GetLuminance() < 8) )
    4601         179 :                 SetTextColor( Color( COL_LIGHTGRAY ) );
    4602             :             else
    4603           0 :                 SetTextColor( Color( COL_BLACK ) );
    4604         179 :             ImplInitTextColor();
    4605         179 :             rSalLayout.DrawBase() += Point( nOff, nOff );
    4606         179 :             ImplDrawTextDirect( rSalLayout, mbTextLines );
    4607         179 :             rSalLayout.DrawBase() -= Point( nOff, nOff );
    4608         179 :             SetTextColor( aOldColor );
    4609         179 :             SetTextLineColor( aOldTextLineColor );
    4610         179 :             SetOverlineColor( aOldOverlineColor );
    4611         179 :             ImplInitTextColor();
    4612             : 
    4613         179 :             if ( !maFont.IsOutline() )
    4614          43 :                 ImplDrawTextDirect( rSalLayout, mbTextLines );
    4615             :         }
    4616             : 
    4617         221 :         if ( maFont.IsOutline() )
    4618             :         {
    4619         178 :             rSalLayout.DrawBase() = aOrigPos + Point(-1,-1);
    4620         178 :             ImplDrawTextDirect( rSalLayout, mbTextLines );
    4621         178 :             rSalLayout.DrawBase() = aOrigPos + Point(+1,+1);
    4622         178 :             ImplDrawTextDirect( rSalLayout, mbTextLines );
    4623         178 :             rSalLayout.DrawBase() = aOrigPos + Point(-1,+0);
    4624         178 :             ImplDrawTextDirect( rSalLayout, mbTextLines );
    4625         178 :             rSalLayout.DrawBase() = aOrigPos + Point(-1,+1);
    4626         178 :             ImplDrawTextDirect( rSalLayout, mbTextLines );
    4627         178 :             rSalLayout.DrawBase() = aOrigPos + Point(+0,+1);
    4628         178 :             ImplDrawTextDirect( rSalLayout, mbTextLines );
    4629         178 :             rSalLayout.DrawBase() = aOrigPos + Point(+0,-1);
    4630         178 :             ImplDrawTextDirect( rSalLayout, mbTextLines );
    4631         178 :             rSalLayout.DrawBase() = aOrigPos + Point(+1,-1);
    4632         178 :             ImplDrawTextDirect( rSalLayout, mbTextLines );
    4633         178 :             rSalLayout.DrawBase() = aOrigPos + Point(+1,+0);
    4634         178 :             ImplDrawTextDirect( rSalLayout, mbTextLines );
    4635         178 :             rSalLayout.DrawBase() = aOrigPos;
    4636             : 
    4637         178 :             SetTextColor( Color( COL_WHITE ) );
    4638         178 :             SetTextLineColor( Color( COL_WHITE ) );
    4639         178 :             SetOverlineColor( Color( COL_WHITE ) );
    4640         178 :             ImplInitTextColor();
    4641         178 :             ImplDrawTextDirect( rSalLayout, mbTextLines );
    4642         178 :             SetTextColor( aOldColor );
    4643         178 :             SetTextLineColor( aOldTextLineColor );
    4644         178 :             SetOverlineColor( aOldOverlineColor );
    4645         178 :             ImplInitTextColor();
    4646             :         }
    4647             :     }
    4648        3482 : }
    4649             : 
    4650       86968 : void OutputDevice::ImplDrawText( SalLayout& rSalLayout )
    4651             : {
    4652       86968 :     if( mbInitClipRegion )
    4653        4714 :         ImplInitClipRegion();
    4654       86968 :     if( mbOutputClipped )
    4655       88313 :         return;
    4656       85623 :     if( mbInitTextColor )
    4657       21807 :         ImplInitTextColor();
    4658             : 
    4659       85623 :     rSalLayout.DrawBase() += Point( mnTextOffX, mnTextOffY );
    4660             : 
    4661       85623 :     if( IsTextFillColor() )
    4662        3327 :         ImplDrawTextBackground( rSalLayout );
    4663             : 
    4664       85623 :     if( mbTextSpecial )
    4665        3482 :         ImplDrawSpecialText( rSalLayout );
    4666             :     else
    4667       82141 :         ImplDrawTextDirect( rSalLayout, mbTextLines );
    4668             : }
    4669             : 
    4670        1438 : long OutputDevice::ImplGetTextLines( ImplMultiTextLineInfo& rLineInfo,
    4671             :                                      long nWidth, const OUString& rStr,
    4672             :                                      sal_uInt16 nStyle, const ::vcl::ITextLayout& _rLayout )
    4673             : {
    4674             :     DBG_ASSERTWARNING( nWidth >= 0, "ImplGetTextLines: nWidth <= 0!" );
    4675             : 
    4676        1438 :     if ( nWidth <= 0 )
    4677           0 :         nWidth = 1;
    4678             : 
    4679        1438 :     long nMaxLineWidth  = 0;
    4680        1438 :     rLineInfo.Clear();
    4681        1438 :     if ( !rStr.isEmpty() && (nWidth > 0) )
    4682             :     {
    4683        1317 :         OUString aText( rStr );
    4684        2634 :         uno::Reference < i18n::XBreakIterator > xBI;
    4685             :         // get service provider
    4686        2634 :         uno::Reference< uno::XComponentContext > xContext( comphelper::getProcessComponentContext() );
    4687             : 
    4688        2634 :         uno::Reference< linguistic2::XLinguServiceManager2> xLinguMgr = linguistic2::LinguServiceManager::create(xContext);
    4689        2634 :         uno::Reference< linguistic2::XHyphenator > xHyph = xLinguMgr->getHyphenator();
    4690             : 
    4691        2634 :         i18n::LineBreakHyphenationOptions aHyphOptions( xHyph, uno::Sequence <beans::PropertyValue>(), 1 );
    4692        2634 :         i18n::LineBreakUserOptions aUserOptions;
    4693             : 
    4694        1317 :         sal_Int32 nPos = 0;
    4695        1317 :         sal_Int32 nLen = rStr.getLength();
    4696        3953 :         while ( nPos < nLen )
    4697             :         {
    4698        1319 :             sal_Int32 nBreakPos = nPos;
    4699             : 
    4700       11831 :             while ( ( nBreakPos < nLen ) && ( rStr[ nBreakPos ] != '\r' ) && ( rStr[ nBreakPos ] != '\n' ) )
    4701        9193 :                 nBreakPos++;
    4702             : 
    4703        1319 :             long nLineWidth = _rLayout.GetTextWidth( rStr, nPos, nBreakPos-nPos );
    4704        1319 :             if ( ( nLineWidth > nWidth ) && ( nStyle & TEXT_DRAW_WORDBREAK ) )
    4705             :             {
    4706           2 :                 if ( !xBI.is() )
    4707           2 :                     xBI = vcl::unohelper::CreateBreakIterator();
    4708             : 
    4709           2 :                 if ( xBI.is() )
    4710             :                 {
    4711           2 :                     const com::sun::star::lang::Locale& rDefLocale(Application::GetSettings().GetUILanguageTag().getLocale());
    4712           2 :                     xub_StrLen nSoftBreak = _rLayout.GetTextBreak( rStr, nWidth, nPos, nBreakPos - nPos );
    4713             :                     DBG_ASSERT( nSoftBreak < nBreakPos, "Break?!" );
    4714           2 :                     i18n::LineBreakResults aLBR = xBI->getLineBreak( aText, nSoftBreak, rDefLocale, nPos, aHyphOptions, aUserOptions );
    4715           2 :                     nBreakPos = (xub_StrLen)aLBR.breakIndex;
    4716           2 :                     if ( nBreakPos <= nPos )
    4717           0 :                         nBreakPos = nSoftBreak;
    4718           2 :                     if ( (nStyle & TEXT_DRAW_WORDBREAK_HYPHENATION) == TEXT_DRAW_WORDBREAK_HYPHENATION )
    4719             :                     {
    4720             :                         // Whether hyphen or not: Put the word after the hyphen through
    4721             :                         // word boundary.
    4722             :                         //
    4723             :                         // nMaxBreakPos the last char that fits into the line
    4724             :                         // nBreakPos is the word's start
    4725             :                         //
    4726             :                         // We run into a problem if the doc is so narrow, that a word
    4727             :                         // is broken into more than two lines ...
    4728           0 :                         if ( xHyph.is() )
    4729             :                         {
    4730           0 :                             sal_Unicode cAlternateReplChar = 0;
    4731           0 :                             i18n::Boundary aBoundary = xBI->getWordBoundary( aText, nBreakPos, rDefLocale, ::com::sun::star::i18n::WordType::DICTIONARY_WORD, sal_True );
    4732           0 :                             sal_Int32 nWordStart = nPos;
    4733           0 :                             sal_Int32 nWordEnd = (sal_Int32) aBoundary.endPos;
    4734             :                             DBG_ASSERT( nWordEnd > nWordStart, "ImpBreakLine: Start >= End?" );
    4735             : 
    4736           0 :                             sal_Int32 nWordLen = nWordEnd - nWordStart;
    4737           0 :                             if ( ( nWordEnd >= nSoftBreak ) && ( nWordLen > 3 ) )
    4738             :                             {
    4739             :                                 // #104415# May happen, because getLineBreak may differ from getWordBoudary with DICTIONARY_WORD
    4740             :                                 // DBG_ASSERT( nWordEnd >= nMaxBreakPos, "Hyph: Break?" );
    4741           0 :                                 String aWord( aText, nWordStart, nWordLen );
    4742           0 :                                 sal_uInt16 nMinTrail = static_cast<sal_uInt16>(nWordEnd-nSoftBreak+1);  //+1: Before the "broken off" char
    4743           0 :                                 uno::Reference< linguistic2::XHyphenatedWord > xHyphWord;
    4744           0 :                                 if (xHyph.is())
    4745           0 :                                     xHyphWord = xHyph->hyphenate( aWord, rDefLocale, aWord.Len() - nMinTrail, uno::Sequence< beans::PropertyValue >() );
    4746           0 :                                 if (xHyphWord.is())
    4747             :                                 {
    4748           0 :                                     sal_Bool bAlternate = xHyphWord->isAlternativeSpelling();
    4749           0 :                                     sal_uInt16 _nWordLen = 1 + xHyphWord->getHyphenPos();
    4750             : 
    4751           0 :                                     if ( ( _nWordLen >= 2 ) && ( (nWordStart+_nWordLen) >= ( 2 ) ) )
    4752             :                                     {
    4753           0 :                                         if ( !bAlternate )
    4754             :                                         {
    4755           0 :                                             nBreakPos = nWordStart + _nWordLen;
    4756             :                                         }
    4757             :                                         else
    4758             :                                         {
    4759           0 :                                             String aAlt( xHyphWord->getHyphenatedWord() );
    4760             : 
    4761             :                                             // We can have two cases:
    4762             :                                             // 1) "packen" turns into "pak-ken"
    4763             :                                             // 2) "Schiffahrt" turns into "Schiff-fahrt"
    4764             :                                             //
    4765             :                                             // In case 1 we need to replace a char
    4766             :                                             // In case 2 we add a char
    4767             :                                             //
    4768             :                                             // Correct recognition is made harder by words such as
    4769             :                                             // "Schiffahrtsbrennesseln", as the Hyphenator splits all
    4770             :                                             // positions of the word and comes up with "Schifffahrtsbrennnesseln"
    4771             :                                             // Thus, we cannot infer the aWord from the AlternativWord's
    4772             :                                             // index.
    4773             :                                             // TODO: The whole junk will be made easier by a function in
    4774             :                                             // the Hyphenator, as soon as AMA adds it.
    4775           0 :                                             sal_uInt16 nAltStart = _nWordLen - 1;
    4776           0 :                                             sal_uInt16 nTxtStart = nAltStart - (aAlt.Len() - aWord.Len());
    4777           0 :                                             sal_uInt16 nTxtEnd = nTxtStart;
    4778           0 :                                             sal_uInt16 nAltEnd = nAltStart;
    4779             : 
    4780             :                                             // The area between nStart and nEnd is the difference
    4781             :                                             // between AlternativString and OriginalString
    4782           0 :                                             while( nTxtEnd < aWord.Len() && nAltEnd < aAlt.Len() &&
    4783           0 :                                                    aWord.GetChar(nTxtEnd) != aAlt.GetChar(nAltEnd) )
    4784             :                                             {
    4785           0 :                                                 ++nTxtEnd;
    4786           0 :                                                 ++nAltEnd;
    4787             :                                             }
    4788             : 
    4789             :                                             // If a char was added, we notice it now:
    4790           0 :                                             if( nAltEnd > nTxtEnd && nAltStart == nAltEnd &&
    4791           0 :                                                 aWord.GetChar( nTxtEnd ) == aAlt.GetChar(nAltEnd) )
    4792             :                                             {
    4793           0 :                                                 ++nAltEnd;
    4794           0 :                                                 ++nTxtStart;
    4795           0 :                                                 ++nTxtEnd;
    4796             :                                             }
    4797             : 
    4798             :                                             DBG_ASSERT( ( nAltEnd - nAltStart ) == 1, "Alternate: Wrong assumption!" );
    4799             : 
    4800           0 :                                             if ( nTxtEnd > nTxtStart )
    4801           0 :                                                 cAlternateReplChar = aAlt.GetChar( nAltStart );
    4802             : 
    4803           0 :                                             nBreakPos = nWordStart + nTxtStart;
    4804           0 :                                             if ( cAlternateReplChar )
    4805           0 :                                                 nBreakPos++;
    4806             :                                         }
    4807             :                                     }
    4808           0 :                                 }
    4809             :                             }
    4810             :                         }
    4811             :                     }
    4812           2 :                     nLineWidth = _rLayout.GetTextWidth( rStr, nPos, nBreakPos-nPos );
    4813             :                 }
    4814             :                 else
    4815             :                 {
    4816             :                     // fallback to something really simple
    4817           0 :                     sal_Int32 nSpacePos = rStr.getLength();
    4818           0 :                     long nW = 0;
    4819           0 :                     do
    4820             :                     {
    4821           0 :                         nSpacePos = rStr.lastIndexOf( sal_Unicode(' '), nSpacePos );
    4822           0 :                         if( nSpacePos != -1 )
    4823             :                         {
    4824           0 :                             if( nSpacePos > nPos )
    4825           0 :                                 nSpacePos--;
    4826           0 :                             nW = _rLayout.GetTextWidth( rStr, nPos, nSpacePos-nPos );
    4827             :                         }
    4828             :                     } while( nW > nWidth );
    4829             : 
    4830           0 :                     if( nSpacePos != -1 )
    4831             :                     {
    4832           0 :                         nBreakPos = nSpacePos;
    4833           0 :                         nLineWidth = _rLayout.GetTextWidth( rStr, nPos, nBreakPos-nPos );
    4834           0 :                         if( nBreakPos < rStr.getLength()-1 )
    4835           0 :                             nBreakPos++;
    4836             :                     }
    4837             :                 }
    4838             :             }
    4839             : 
    4840        1319 :             if ( nLineWidth > nMaxLineWidth )
    4841        1317 :                 nMaxLineWidth = nLineWidth;
    4842             : 
    4843        1319 :             rLineInfo.AddLine( new ImplTextLineInfo( nLineWidth, nPos, nBreakPos-nPos ) );
    4844             : 
    4845        1319 :             if ( nBreakPos == nPos )
    4846           0 :                 nBreakPos++;
    4847        1319 :             nPos = nBreakPos;
    4848             : 
    4849        1319 :             if ( ( rStr[ nPos ] == '\r' ) || ( rStr[ nPos ] == '\n' ) )
    4850             :             {
    4851           0 :                 nPos++;
    4852             :                 // CR/LF?
    4853           0 :                 if ( ( nPos < nLen ) && ( rStr[ nPos ] == '\n' ) && ( rStr[ nPos-1 ] == '\r' ) )
    4854           0 :                     nPos++;
    4855             :             }
    4856        1317 :         }
    4857             :     }
    4858             : #ifdef DBG_UTIL
    4859             :     for ( sal_uInt16 nL = 0; nL < rLineInfo.Count(); nL++ )
    4860             :     {
    4861             :         ImplTextLineInfo* pLine = rLineInfo.GetLine( nL );
    4862             :         String aLine( rStr, pLine->GetIndex(), pLine->GetLen() );
    4863             :         DBG_ASSERT( aLine.Search( '\r' ) == STRING_NOTFOUND, "ImplGetTextLines - Found CR!" );
    4864             :         DBG_ASSERT( aLine.Search( '\n' ) == STRING_NOTFOUND, "ImplGetTextLines - Found LF!" );
    4865             :     }
    4866             : #endif
    4867             : 
    4868        1438 :     return nMaxLineWidth;
    4869             : }
    4870             : 
    4871       78886 : void OutputDevice::SetAntialiasing( sal_uInt16 nMode )
    4872             : {
    4873       78886 :     if ( mnAntialiasing != nMode )
    4874             :     {
    4875        4095 :         mnAntialiasing = nMode;
    4876        4095 :         mbInitFont = sal_True;
    4877             : 
    4878        4095 :         if(mpGraphics)
    4879             :         {
    4880           4 :             mpGraphics->setAntiAliasB2DDraw(mnAntialiasing & ANTIALIASING_ENABLE_B2DDRAW);
    4881             :         }
    4882             :     }
    4883             : 
    4884       78886 :     if( mpAlphaVDev )
    4885           0 :         mpAlphaVDev->SetAntialiasing( nMode );
    4886       78886 : }
    4887             : 
    4888      934245 : void OutputDevice::SetFont( const Font& rNewFont )
    4889             : {
    4890             :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    4891             :     DBG_CHKOBJ( &rNewFont, Font, NULL );
    4892             : 
    4893      934245 :     Font aFont( rNewFont );
    4894      934245 :     aFont.SetLanguage(rNewFont.GetLanguage());
    4895      934245 :     if ( mnDrawMode & (DRAWMODE_BLACKTEXT | DRAWMODE_WHITETEXT | DRAWMODE_GRAYTEXT | DRAWMODE_GHOSTEDTEXT | DRAWMODE_SETTINGSTEXT |
    4896             :                        DRAWMODE_BLACKFILL | DRAWMODE_WHITEFILL | DRAWMODE_GRAYFILL | DRAWMODE_NOFILL |
    4897             :                        DRAWMODE_GHOSTEDFILL | DRAWMODE_SETTINGSFILL ) )
    4898             :     {
    4899           0 :         Color aTextColor( aFont.GetColor() );
    4900             : 
    4901           0 :         if ( mnDrawMode & DRAWMODE_BLACKTEXT )
    4902           0 :             aTextColor = Color( COL_BLACK );
    4903           0 :         else if ( mnDrawMode & DRAWMODE_WHITETEXT )
    4904           0 :             aTextColor = Color( COL_WHITE );
    4905           0 :         else if ( mnDrawMode & DRAWMODE_GRAYTEXT )
    4906             :         {
    4907           0 :             const sal_uInt8 cLum = aTextColor.GetLuminance();
    4908           0 :             aTextColor = Color( cLum, cLum, cLum );
    4909             :         }
    4910           0 :         else if ( mnDrawMode & DRAWMODE_SETTINGSTEXT )
    4911           0 :             aTextColor = GetSettings().GetStyleSettings().GetFontColor();
    4912             : 
    4913           0 :         if ( mnDrawMode & DRAWMODE_GHOSTEDTEXT )
    4914             :         {
    4915           0 :             aTextColor = Color( (aTextColor.GetRed() >> 1 ) | 0x80,
    4916           0 :                                 (aTextColor.GetGreen() >> 1 ) | 0x80,
    4917           0 :                                 (aTextColor.GetBlue() >> 1 ) | 0x80 );
    4918             :         }
    4919             : 
    4920           0 :         aFont.SetColor( aTextColor );
    4921             : 
    4922           0 :         sal_Bool bTransFill = aFont.IsTransparent();
    4923           0 :         if ( !bTransFill )
    4924             :         {
    4925           0 :             Color aTextFillColor( aFont.GetFillColor() );
    4926             : 
    4927           0 :             if ( mnDrawMode & DRAWMODE_BLACKFILL )
    4928           0 :                 aTextFillColor = Color( COL_BLACK );
    4929           0 :             else if ( mnDrawMode & DRAWMODE_WHITEFILL )
    4930           0 :                 aTextFillColor = Color( COL_WHITE );
    4931           0 :             else if ( mnDrawMode & DRAWMODE_GRAYFILL )
    4932             :             {
    4933           0 :                 const sal_uInt8 cLum = aTextFillColor.GetLuminance();
    4934           0 :                 aTextFillColor = Color( cLum, cLum, cLum );
    4935             :             }
    4936           0 :             else if( mnDrawMode & DRAWMODE_SETTINGSFILL )
    4937           0 :                 aTextFillColor = GetSettings().GetStyleSettings().GetWindowColor();
    4938           0 :             else if ( mnDrawMode & DRAWMODE_NOFILL )
    4939             :             {
    4940           0 :                 aTextFillColor = Color( COL_TRANSPARENT );
    4941           0 :                 bTransFill = sal_True;
    4942             :             }
    4943             : 
    4944           0 :             if ( !bTransFill && (mnDrawMode & DRAWMODE_GHOSTEDFILL) )
    4945             :             {
    4946           0 :                 aTextFillColor = Color( (aTextFillColor.GetRed() >> 1) | 0x80,
    4947           0 :                                         (aTextFillColor.GetGreen() >> 1) | 0x80,
    4948           0 :                                         (aTextFillColor.GetBlue() >> 1) | 0x80 );
    4949             :             }
    4950             : 
    4951           0 :             aFont.SetFillColor( aTextFillColor );
    4952             :         }
    4953             :     }
    4954             : 
    4955      934245 :     if ( mpMetaFile )
    4956             :     {
    4957       31708 :         mpMetaFile->AddAction( new MetaFontAction( aFont ) );
    4958             :         // the color and alignment actions don't belong here
    4959             :         // TODO: get rid of them without breaking anything...
    4960       31708 :         mpMetaFile->AddAction( new MetaTextAlignAction( aFont.GetAlign() ) );
    4961       31708 :         mpMetaFile->AddAction( new MetaTextFillColorAction( aFont.GetFillColor(), !aFont.IsTransparent() ) );
    4962             :     }
    4963             : 
    4964      934245 :     if ( !maFont.IsSameInstance( aFont ) )
    4965             :     {
    4966             :         // Optimization MT/HDU: COL_TRANSPARENT means SetFont should ignore the font color,
    4967             :         // because SetTextColor() is used for this.
    4968             :         // #i28759# maTextColor might have been changed behind our back, commit then, too.
    4969     2659590 :         if( aFont.GetColor() != COL_TRANSPARENT
    4970     2659590 :         && (aFont.GetColor() != maFont.GetColor() || aFont.GetColor() != maTextColor ) )
    4971             :         {
    4972      123904 :             maTextColor = aFont.GetColor();
    4973      123904 :             mbInitTextColor = sal_True;
    4974      123904 :             if( mpMetaFile )
    4975         508 :                 mpMetaFile->AddAction( new MetaTextColorAction( aFont.GetColor() ) );
    4976             :         }
    4977      886530 :         maFont      = aFont;
    4978      886530 :         mbNewFont   = sal_True;
    4979             : 
    4980      886530 :         if( mpAlphaVDev )
    4981             :         {
    4982             :             // #i30463#
    4983             :             // Since SetFont might change the text color, apply that only
    4984             :             // selectively to alpha vdev (which normally paints opaque text
    4985             :             // with COL_BLACK)
    4986       10998 :             if( aFont.GetColor() != COL_TRANSPARENT )
    4987             :             {
    4988          57 :                 mpAlphaVDev->SetTextColor( COL_BLACK );
    4989          57 :                 aFont.SetColor( COL_TRANSPARENT );
    4990             :             }
    4991             : 
    4992       10998 :             mpAlphaVDev->SetFont( aFont );
    4993             :         }
    4994      934245 :     }
    4995      934245 : }
    4996             : 
    4997      641772 : void OutputDevice::SetLayoutMode( sal_uLong nTextLayoutMode )
    4998             : {
    4999      641772 :     if( mpMetaFile )
    5000       11027 :         mpMetaFile->AddAction( new MetaLayoutModeAction( nTextLayoutMode ) );
    5001             : 
    5002      641772 :     mnTextLayoutMode = nTextLayoutMode;
    5003             : 
    5004      641772 :     if( mpAlphaVDev )
    5005       21582 :         mpAlphaVDev->SetLayoutMode( nTextLayoutMode );
    5006      641772 : }
    5007             : 
    5008     1016258 : void OutputDevice::SetDigitLanguage( LanguageType eTextLanguage )
    5009             : {
    5010     1016258 :     if( mpMetaFile )
    5011       13680 :         mpMetaFile->AddAction( new MetaTextLanguageAction( eTextLanguage ) );
    5012             : 
    5013     1016258 :     meTextLanguage = eTextLanguage;
    5014             : 
    5015     1016258 :     if( mpAlphaVDev )
    5016       21203 :         mpAlphaVDev->SetDigitLanguage( eTextLanguage );
    5017     1016258 : }
    5018             : 
    5019      278986 : void OutputDevice::SetTextColor( const Color& rColor )
    5020             : {
    5021             :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    5022             : 
    5023      278986 :     Color aColor( rColor );
    5024             : 
    5025      278986 :     if ( mnDrawMode & ( DRAWMODE_BLACKTEXT | DRAWMODE_WHITETEXT |
    5026             :                         DRAWMODE_GRAYTEXT | DRAWMODE_GHOSTEDTEXT |
    5027             :                         DRAWMODE_SETTINGSTEXT ) )
    5028             :     {
    5029           0 :         if ( mnDrawMode & DRAWMODE_BLACKTEXT )
    5030           0 :             aColor = Color( COL_BLACK );
    5031           0 :         else if ( mnDrawMode & DRAWMODE_WHITETEXT )
    5032           0 :             aColor = Color( COL_WHITE );
    5033           0 :         else if ( mnDrawMode & DRAWMODE_GRAYTEXT )
    5034             :         {
    5035           0 :             const sal_uInt8 cLum = aColor.GetLuminance();
    5036           0 :             aColor = Color( cLum, cLum, cLum );
    5037             :         }
    5038           0 :         else if ( mnDrawMode & DRAWMODE_SETTINGSTEXT )
    5039           0 :             aColor = GetSettings().GetStyleSettings().GetFontColor();
    5040             : 
    5041           0 :         if ( mnDrawMode & DRAWMODE_GHOSTEDTEXT )
    5042             :         {
    5043           0 :             aColor = Color( (aColor.GetRed() >> 1) | 0x80,
    5044           0 :                             (aColor.GetGreen() >> 1) | 0x80,
    5045           0 :                             (aColor.GetBlue() >> 1) | 0x80 );
    5046             :         }
    5047             :     }
    5048             : 
    5049      278986 :     if ( mpMetaFile )
    5050       33024 :         mpMetaFile->AddAction( new MetaTextColorAction( aColor ) );
    5051             : 
    5052      278986 :     if ( maTextColor != aColor )
    5053             :     {
    5054       15784 :         maTextColor = aColor;
    5055       15784 :         mbInitTextColor = sal_True;
    5056             :     }
    5057             : 
    5058      278986 :     if( mpAlphaVDev )
    5059       15041 :         mpAlphaVDev->SetTextColor( COL_BLACK );
    5060      278986 : }
    5061             : 
    5062      100442 : void OutputDevice::SetTextFillColor()
    5063             : {
    5064             :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    5065             : 
    5066      100442 :     if ( mpMetaFile )
    5067        5469 :         mpMetaFile->AddAction( new MetaTextFillColorAction( Color(), sal_False ) );
    5068             : 
    5069      100442 :     if ( maFont.GetColor() != Color( COL_TRANSPARENT ) )
    5070        1615 :         maFont.SetFillColor( Color( COL_TRANSPARENT ) );
    5071      100442 :     if ( !maFont.IsTransparent() )
    5072           8 :         maFont.SetTransparent( sal_True );
    5073             : 
    5074      100442 :     if( mpAlphaVDev )
    5075       16113 :         mpAlphaVDev->SetTextFillColor();
    5076      100442 : }
    5077             : 
    5078       11935 : void OutputDevice::SetTextFillColor( const Color& rColor )
    5079             : {
    5080             :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    5081             : 
    5082       11935 :     Color aColor( rColor );
    5083       11935 :     sal_Bool bTransFill = ImplIsColorTransparent( aColor ) ? sal_True : sal_False;
    5084             : 
    5085       11935 :     if ( !bTransFill )
    5086             :     {
    5087       10180 :         if ( mnDrawMode & ( DRAWMODE_BLACKFILL | DRAWMODE_WHITEFILL |
    5088             :                             DRAWMODE_GRAYFILL | DRAWMODE_NOFILL |
    5089             :                             DRAWMODE_GHOSTEDFILL | DRAWMODE_SETTINGSFILL ) )
    5090             :         {
    5091           0 :             if ( mnDrawMode & DRAWMODE_BLACKFILL )
    5092           0 :                 aColor = Color( COL_BLACK );
    5093           0 :             else if ( mnDrawMode & DRAWMODE_WHITEFILL )
    5094           0 :                 aColor = Color( COL_WHITE );
    5095           0 :             else if ( mnDrawMode & DRAWMODE_GRAYFILL )
    5096             :             {
    5097           0 :                 const sal_uInt8 cLum = aColor.GetLuminance();
    5098           0 :                 aColor = Color( cLum, cLum, cLum );
    5099             :             }
    5100           0 :             else if( mnDrawMode & DRAWMODE_SETTINGSFILL )
    5101           0 :                 aColor = GetSettings().GetStyleSettings().GetWindowColor();
    5102           0 :             else if ( mnDrawMode & DRAWMODE_NOFILL )
    5103             :             {
    5104           0 :                 aColor = Color( COL_TRANSPARENT );
    5105           0 :                 bTransFill = sal_True;
    5106             :             }
    5107             : 
    5108           0 :             if ( !bTransFill && (mnDrawMode & DRAWMODE_GHOSTEDFILL) )
    5109             :             {
    5110           0 :                 aColor = Color( (aColor.GetRed() >> 1) | 0x80,
    5111           0 :                                 (aColor.GetGreen() >> 1) | 0x80,
    5112           0 :                                 (aColor.GetBlue() >> 1) | 0x80 );
    5113             :             }
    5114             :         }
    5115             :     }
    5116             : 
    5117       11935 :     if ( mpMetaFile )
    5118        1291 :         mpMetaFile->AddAction( new MetaTextFillColorAction( aColor, sal_True ) );
    5119             : 
    5120       11935 :     if ( maFont.GetFillColor() != aColor )
    5121        7053 :         maFont.SetFillColor( aColor );
    5122       11935 :     if ( maFont.IsTransparent() != bTransFill )
    5123        6957 :         maFont.SetTransparent( bTransFill );
    5124             : 
    5125       11935 :     if( mpAlphaVDev )
    5126        1377 :         mpAlphaVDev->SetTextFillColor( COL_BLACK );
    5127       11935 : }
    5128             : 
    5129       16656 : Color OutputDevice::GetTextFillColor() const
    5130             : {
    5131       16656 :     if ( maFont.IsTransparent() )
    5132       12899 :         return Color( COL_TRANSPARENT );
    5133             :     else
    5134        3757 :         return maFont.GetFillColor();
    5135             : }
    5136             : 
    5137       66262 : void OutputDevice::SetTextLineColor()
    5138             : {
    5139             :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    5140             : 
    5141       66262 :     if ( mpMetaFile )
    5142        5293 :         mpMetaFile->AddAction( new MetaTextLineColorAction( Color(), sal_False ) );
    5143             : 
    5144       66262 :     maTextLineColor = Color( COL_TRANSPARENT );
    5145             : 
    5146       66262 :     if( mpAlphaVDev )
    5147       10617 :         mpAlphaVDev->SetTextLineColor();
    5148       66262 : }
    5149             : 
    5150       18644 : void OutputDevice::SetTextLineColor( const Color& rColor )
    5151             : {
    5152             :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    5153             : 
    5154       18644 :     Color aColor( rColor );
    5155             : 
    5156       18644 :     if ( mnDrawMode & ( DRAWMODE_BLACKTEXT | DRAWMODE_WHITETEXT |
    5157             :                         DRAWMODE_GRAYTEXT | DRAWMODE_GHOSTEDTEXT |
    5158             :                         DRAWMODE_SETTINGSTEXT ) )
    5159             :     {
    5160           0 :         if ( mnDrawMode & DRAWMODE_BLACKTEXT )
    5161           0 :             aColor = Color( COL_BLACK );
    5162           0 :         else if ( mnDrawMode & DRAWMODE_WHITETEXT )
    5163           0 :             aColor = Color( COL_WHITE );
    5164           0 :         else if ( mnDrawMode & DRAWMODE_GRAYTEXT )
    5165             :         {
    5166           0 :             const sal_uInt8 cLum = aColor.GetLuminance();
    5167           0 :             aColor = Color( cLum, cLum, cLum );
    5168             :         }
    5169           0 :         else if ( mnDrawMode & DRAWMODE_SETTINGSTEXT )
    5170           0 :             aColor = GetSettings().GetStyleSettings().GetFontColor();
    5171             : 
    5172           0 :         if( (mnDrawMode & DRAWMODE_GHOSTEDTEXT)
    5173           0 :         &&  (aColor.GetColor() != COL_TRANSPARENT) )
    5174             :         {
    5175           0 :             aColor = Color( (aColor.GetRed() >> 1) | 0x80,
    5176           0 :                             (aColor.GetGreen() >> 1) | 0x80,
    5177           0 :                             (aColor.GetBlue() >> 1) | 0x80 );
    5178             :         }
    5179             :     }
    5180             : 
    5181       18644 :     if ( mpMetaFile )
    5182           1 :         mpMetaFile->AddAction( new MetaTextLineColorAction( aColor, sal_True ) );
    5183             : 
    5184       18644 :     maTextLineColor = aColor;
    5185             : 
    5186       18644 :     if( mpAlphaVDev )
    5187        1569 :         mpAlphaVDev->SetTextLineColor( COL_BLACK );
    5188       18644 : }
    5189             : 
    5190       65853 : void OutputDevice::SetOverlineColor()
    5191             : {
    5192             :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    5193             : 
    5194       65853 :     if ( mpMetaFile )
    5195        5293 :         mpMetaFile->AddAction( new MetaOverlineColorAction( Color(), sal_False ) );
    5196             : 
    5197       65853 :     maOverlineColor = Color( COL_TRANSPARENT );
    5198             : 
    5199       65853 :     if( mpAlphaVDev )
    5200       10617 :         mpAlphaVDev->SetOverlineColor();
    5201       65853 : }
    5202             : 
    5203       17576 : void OutputDevice::SetOverlineColor( const Color& rColor )
    5204             : {
    5205             :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    5206             : 
    5207       17576 :     Color aColor( rColor );
    5208             : 
    5209       17576 :     if ( mnDrawMode & ( DRAWMODE_BLACKTEXT | DRAWMODE_WHITETEXT |
    5210             :                         DRAWMODE_GRAYTEXT | DRAWMODE_GHOSTEDTEXT |
    5211             :                         DRAWMODE_SETTINGSTEXT ) )
    5212             :     {
    5213           0 :         if ( mnDrawMode & DRAWMODE_BLACKTEXT )
    5214           0 :             aColor = Color( COL_BLACK );
    5215           0 :         else if ( mnDrawMode & DRAWMODE_WHITETEXT )
    5216           0 :             aColor = Color( COL_WHITE );
    5217           0 :         else if ( mnDrawMode & DRAWMODE_GRAYTEXT )
    5218             :         {
    5219           0 :             const sal_uInt8 cLum = aColor.GetLuminance();
    5220           0 :             aColor = Color( cLum, cLum, cLum );
    5221             :         }
    5222           0 :         else if ( mnDrawMode & DRAWMODE_SETTINGSTEXT )
    5223           0 :             aColor = GetSettings().GetStyleSettings().GetFontColor();
    5224             : 
    5225           0 :         if( (mnDrawMode & DRAWMODE_GHOSTEDTEXT)
    5226           0 :         &&  (aColor.GetColor() != COL_TRANSPARENT) )
    5227             :         {
    5228           0 :             aColor = Color( (aColor.GetRed() >> 1) | 0x80,
    5229           0 :                             (aColor.GetGreen() >> 1) | 0x80,
    5230           0 :                             (aColor.GetBlue() >> 1) | 0x80 );
    5231             :         }
    5232             :     }
    5233             : 
    5234       17576 :     if ( mpMetaFile )
    5235           1 :         mpMetaFile->AddAction( new MetaOverlineColorAction( aColor, sal_True ) );
    5236             : 
    5237       17576 :     maOverlineColor = aColor;
    5238             : 
    5239       17576 :     if( mpAlphaVDev )
    5240        1569 :         mpAlphaVDev->SetOverlineColor( COL_BLACK );
    5241       17576 : }
    5242             : 
    5243       69851 : void OutputDevice::SetTextAlign( TextAlign eAlign )
    5244             : {
    5245             :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    5246             : 
    5247       69851 :     if ( mpMetaFile )
    5248        5381 :         mpMetaFile->AddAction( new MetaTextAlignAction( eAlign ) );
    5249             : 
    5250       69851 :     if ( maFont.GetAlign() != eAlign )
    5251             :     {
    5252         822 :         maFont.SetAlign( eAlign );
    5253         822 :         mbNewFont = sal_True;
    5254             :     }
    5255             : 
    5256       69851 :     if( mpAlphaVDev )
    5257       16111 :         mpAlphaVDev->SetTextAlign( eAlign );
    5258       69851 : }
    5259             : 
    5260           0 : void OutputDevice::DrawTextLine( const Point& rPos, long nWidth,
    5261             :                                  FontStrikeout eStrikeout,
    5262             :                                  FontUnderline eUnderline,
    5263             :                                  FontUnderline eOverline,
    5264             :                                  sal_Bool bUnderlineAbove )
    5265             : {
    5266             :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    5267             : 
    5268           0 :     if ( mpMetaFile )
    5269           0 :         mpMetaFile->AddAction( new MetaTextLineAction( rPos, nWidth, eStrikeout, eUnderline, eOverline ) );
    5270             : 
    5271           0 :     if ( ((eUnderline == UNDERLINE_NONE) || (eUnderline == UNDERLINE_DONTKNOW)) &&
    5272           0 :          ((eOverline  == UNDERLINE_NONE) || (eOverline  == UNDERLINE_DONTKNOW)) &&
    5273           0 :          ((eStrikeout == STRIKEOUT_NONE) || (eStrikeout == STRIKEOUT_DONTKNOW)) )
    5274           0 :         return;
    5275             : 
    5276           0 :     if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
    5277           0 :         return;
    5278             : 
    5279             :     // we need a graphics
    5280           0 :     if( !mpGraphics && !ImplGetGraphics() )
    5281           0 :         return;
    5282           0 :     if( mbInitClipRegion )
    5283           0 :         ImplInitClipRegion();
    5284           0 :     if( mbOutputClipped )
    5285           0 :         return;
    5286             : 
    5287             :     // initialize font if needed to get text offsets
    5288             :     // TODO: only needed for mnTextOff!=(0,0)
    5289           0 :     if( mbNewFont )
    5290           0 :         if( !ImplNewFont() )
    5291           0 :             return;
    5292           0 :     if( mbInitFont )
    5293           0 :         ImplInitFont();
    5294             : 
    5295           0 :     Point aPos = ImplLogicToDevicePixel( rPos );
    5296           0 :     nWidth = ImplLogicWidthToDevicePixel( nWidth );
    5297           0 :     aPos += Point( mnTextOffX, mnTextOffY );
    5298           0 :     ImplDrawTextLine( aPos.X(), aPos.X(), 0, nWidth, eStrikeout, eUnderline, eOverline, bUnderlineAbove );
    5299             : 
    5300           0 :     if( mpAlphaVDev )
    5301           0 :         mpAlphaVDev->DrawTextLine( rPos, nWidth, eStrikeout, eUnderline, eOverline, bUnderlineAbove );
    5302             : }
    5303             : 
    5304         611 : void OutputDevice::DrawWaveLine( const Point& rStartPos, const Point& rEndPos,
    5305             :                                  sal_uInt16 nStyle )
    5306             : {
    5307             :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    5308             : 
    5309         611 :     if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
    5310           0 :         return;
    5311             : 
    5312             :     // we need a graphics
    5313         611 :     if( !mpGraphics )
    5314           0 :         if( !ImplGetGraphics() )
    5315           0 :             return;
    5316             : 
    5317         611 :     if ( mbInitClipRegion )
    5318          32 :         ImplInitClipRegion();
    5319         611 :     if ( mbOutputClipped )
    5320           0 :         return;
    5321             : 
    5322         611 :     if( mbNewFont )
    5323           0 :         if( !ImplNewFont() )
    5324           0 :             return;
    5325             : 
    5326         611 :     Point   aStartPt = ImplLogicToDevicePixel( rStartPos );
    5327         611 :     Point   aEndPt = ImplLogicToDevicePixel( rEndPos );
    5328         611 :     long    nStartX = aStartPt.X();
    5329         611 :     long    nStartY = aStartPt.Y();
    5330         611 :     long    nEndX = aEndPt.X();
    5331         611 :     long    nEndY = aEndPt.Y();
    5332         611 :     short   nOrientation = 0;
    5333             : 
    5334             :     // when rotated
    5335         611 :     if ( (nStartY != nEndY) || (nStartX > nEndX) )
    5336             :     {
    5337           0 :         long nDX = nEndX - nStartX;
    5338           0 :         double nO = atan2( -nEndY + nStartY, ((nDX == 0L) ? 0.000000001 : nDX) );
    5339           0 :         nO /= F_PI1800;
    5340           0 :         nOrientation = (short)nO;
    5341           0 :         ImplRotatePos( nStartX, nStartY, nEndX, nEndY, -nOrientation );
    5342             :     }
    5343             : 
    5344             :     long nWaveHeight;
    5345         611 :     if ( nStyle == WAVE_NORMAL )
    5346             :     {
    5347         580 :         nWaveHeight = 3;
    5348         580 :         nStartY++;
    5349         580 :         nEndY++;
    5350             :     }
    5351          31 :     else if( nStyle == WAVE_SMALL )
    5352             :     {
    5353          30 :         nWaveHeight = 2;
    5354          30 :         nStartY++;
    5355          30 :         nEndY++;
    5356             :     }
    5357             :     else // WAVE_FLAT
    5358           1 :         nWaveHeight = 1;
    5359             : 
    5360             :      // #109280# make sure the waveline does not exceed the descent to avoid paint problems
    5361         611 :      ImplFontEntry* pFontEntry = mpFontEntry;
    5362         611 :      if( nWaveHeight > pFontEntry->maMetric.mnWUnderlineSize )
    5363           0 :          nWaveHeight = pFontEntry->maMetric.mnWUnderlineSize;
    5364             : 
    5365             :      ImplDrawWaveLine( nStartX, nStartY, 0, 0,
    5366             :                       nEndX-nStartX, nWaveHeight, 1,
    5367         611 :                       nOrientation, GetLineColor() );
    5368         611 :     if( mpAlphaVDev )
    5369           0 :         mpAlphaVDev->DrawWaveLine( rStartPos, rEndPos, nStyle );
    5370             : }
    5371             : 
    5372       81043 : void OutputDevice::DrawText( const Point& rStartPt, const String& rStr,
    5373             :                              xub_StrLen nIndex, xub_StrLen nLen,
    5374             :                              MetricVector* pVector, OUString* pDisplayText
    5375             :                              )
    5376             : {
    5377       81043 :     if( mpOutDevData && mpOutDevData->mpRecordLayout )
    5378             :     {
    5379        2844 :         pVector = &mpOutDevData->mpRecordLayout->m_aUnicodeBoundRects;
    5380        2844 :         pDisplayText = &mpOutDevData->mpRecordLayout->m_aDisplayText;
    5381             :     }
    5382             : 
    5383             :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    5384             : 
    5385             : #if OSL_DEBUG_LEVEL > 2
    5386             :     fprintf( stderr, "   OutputDevice::DrawText(\"%s\")\n",
    5387             :          OUStringToOString( rStr, RTL_TEXTENCODING_UTF8 ).getStr() );
    5388             : #endif
    5389             : 
    5390       81043 :     if ( mpMetaFile )
    5391        1247 :         mpMetaFile->AddAction( new MetaTextAction( rStartPt, rStr, nIndex, nLen ) );
    5392       81043 :     if( pVector )
    5393             :     {
    5394        2870 :         Region aClip( GetClipRegion() );
    5395        2870 :         if( meOutDevType == OUTDEV_WINDOW )
    5396        2870 :             aClip.Intersect( Rectangle( Point(), GetOutputSize() ) );
    5397        2870 :         if( mpOutDevData && mpOutDevData->mpRecordLayout )
    5398             :         {
    5399        2844 :             mpOutDevData->mpRecordLayout->m_aLineIndices.push_back( mpOutDevData->mpRecordLayout->m_aDisplayText.getLength() );
    5400        2844 :             aClip.Intersect( mpOutDevData->maRecordRect );
    5401             :         }
    5402        2870 :         if( ! aClip.IsNull() )
    5403             :         {
    5404        2870 :             MetricVector aTmp;
    5405        2870 :             GetGlyphBoundRects( rStartPt, rStr, nIndex, nLen, nIndex, aTmp );
    5406             : 
    5407        2870 :             bool bInserted = false;
    5408       18517 :             for( MetricVector::const_iterator it = aTmp.begin(); it != aTmp.end(); ++it, nIndex++ )
    5409             :             {
    5410       15647 :                 bool bAppend = false;
    5411             : 
    5412       15647 :                 if( aClip.IsOver( *it ) )
    5413        5400 :                     bAppend = true;
    5414       10247 :                 else if( rStr.GetChar( nIndex ) == ' ' && bInserted )
    5415             :                 {
    5416         717 :                     MetricVector::const_iterator next = it;
    5417         717 :                     ++next;
    5418         717 :                     if( next != aTmp.end() && aClip.IsOver( *next ) )
    5419         717 :                         bAppend = true;
    5420             :                 }
    5421             : 
    5422       15647 :                 if( bAppend )
    5423             :                 {
    5424        6117 :                     pVector->push_back( *it );
    5425        6117 :                     if( pDisplayText )
    5426        6117 :                         *pDisplayText += OUString(rStr.GetChar( nIndex ));
    5427        6117 :                     bInserted = true;
    5428             :                 }
    5429        2870 :             }
    5430             :         }
    5431             :         else
    5432             :         {
    5433           0 :             GetGlyphBoundRects( rStartPt, rStr, nIndex, nLen, nIndex, *pVector );
    5434           0 :             if( pDisplayText )
    5435           0 :                 *pDisplayText += rStr.Copy( nIndex, nLen );
    5436        2870 :         }
    5437             :     }
    5438             : 
    5439       81043 :     if ( !IsDeviceOutputNecessary() || pVector )
    5440       84812 :         return;
    5441             : 
    5442       77274 :     SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen, rStartPt, 0, NULL, true );
    5443       77274 :     if( pSalLayout )
    5444             :     {
    5445       66360 :         ImplDrawText( *pSalLayout );
    5446       66360 :         pSalLayout->Release();
    5447             :     }
    5448             : 
    5449       77274 :     if( mpAlphaVDev )
    5450        1660 :         mpAlphaVDev->DrawText( rStartPt, rStr, nIndex, nLen, pVector, pDisplayText );
    5451             : }
    5452             : 
    5453      621342 : long OutputDevice::GetTextWidth( const OUString& rStr, sal_Int32 nIndex, sal_Int32 nLen ) const
    5454             : {
    5455             :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    5456             : 
    5457      621342 :     long nWidth = GetTextArray( rStr, NULL, nIndex, nLen );
    5458             : 
    5459      621342 :     return nWidth;
    5460             : }
    5461             : 
    5462      684896 : long OutputDevice::GetTextHeight() const
    5463             : {
    5464             :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    5465             : 
    5466      684896 :     if( mbNewFont )
    5467      493578 :         if( !ImplNewFont() )
    5468           0 :             return 0;
    5469      684896 :     if( mbInitFont )
    5470      485004 :         if( !ImplNewFont() )
    5471           0 :             return 0;
    5472             : 
    5473      684896 :     long nHeight = mpFontEntry->mnLineHeight + mnEmphasisAscent + mnEmphasisDescent;
    5474             : 
    5475      684896 :     if ( mbMap )
    5476      549268 :         nHeight = ImplDevicePixelToLogicHeight( nHeight );
    5477             : 
    5478      684896 :     return nHeight;
    5479             : }
    5480             : 
    5481          72 : float OutputDevice::approximate_char_width() const
    5482             : {
    5483          72 :     return GetTextWidth("aemnnxEM") / 8.0;
    5484             : }
    5485             : 
    5486       20828 : void OutputDevice::DrawTextArray( const Point& rStartPt, const String& rStr,
    5487             :                                   const sal_Int32* pDXAry,
    5488             :                                   xub_StrLen nIndex, xub_StrLen nLen )
    5489             : {
    5490             :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    5491             : 
    5492       20828 :     if ( mpMetaFile )
    5493         472 :         mpMetaFile->AddAction( new MetaTextArrayAction( rStartPt, rStr, pDXAry, nIndex, nLen ) );
    5494             : 
    5495       20828 :     if ( !IsDeviceOutputNecessary() )
    5496         294 :         return;
    5497       20534 :     if( !mpGraphics && !ImplGetGraphics() )
    5498           0 :         return;
    5499       20534 :     if( mbInitClipRegion )
    5500        3637 :         ImplInitClipRegion();
    5501       20534 :     if( mbOutputClipped )
    5502         198 :         return;
    5503             : 
    5504       20336 :     SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen, rStartPt, 0, pDXAry, true );
    5505       20336 :     if( pSalLayout )
    5506             :     {
    5507       19593 :         ImplDrawText( *pSalLayout );
    5508       19593 :         pSalLayout->Release();
    5509             :     }
    5510             : 
    5511       20336 :     if( mpAlphaVDev )
    5512         178 :         mpAlphaVDev->DrawTextArray( rStartPt, rStr, pDXAry, nIndex, nLen );
    5513             : }
    5514             : 
    5515      838538 : long OutputDevice::GetTextArray( const OUString& rStr, sal_Int32* pDXAry,
    5516             :                                  sal_Int32 nIndex, sal_Int32 nLen ) const
    5517             : {
    5518             :     // MEM: default nLen = STRING_LENGTH
    5519             :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    5520             : 
    5521      838538 :     if( nIndex >= rStr.getLength() )
    5522      326694 :         return 0;
    5523             : 
    5524      511844 :     if( nLen < 0 || nIndex+nLen >= rStr.getLength() )
    5525      470631 :         nLen = rStr.getLength() - nIndex;
    5526             : 
    5527             :     // do layout
    5528      511844 :     SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen );
    5529      511844 :     if( !pSalLayout )
    5530           2 :         return 0;
    5531             : 
    5532      511842 :     long nWidth = pSalLayout->FillDXArray( pDXAry );
    5533      511842 :     int nWidthFactor = pSalLayout->GetUnitsPerPixel();
    5534      511842 :     pSalLayout->Release();
    5535             : 
    5536             :     // convert virtual char widths to virtual absolute positions
    5537      511842 :     if( pDXAry )
    5538     2088461 :         for( int i = 1; i < nLen; ++i )
    5539     1874537 :             pDXAry[ i ] += pDXAry[ i-1 ];
    5540             : 
    5541             :     // convert from font units to logical units
    5542      511842 :     if( mbMap )
    5543             :     {
    5544      256219 :         if( pDXAry )
    5545     2301318 :             for( int i = 0; i < nLen; ++i )
    5546     2087684 :                 pDXAry[i] = ImplDevicePixelToLogicWidth( pDXAry[i] );
    5547      256219 :         nWidth = ImplDevicePixelToLogicWidth( nWidth );
    5548             :     }
    5549             : 
    5550      511842 :     if( nWidthFactor > 1 )
    5551             :     {
    5552           0 :         if( pDXAry )
    5553           0 :             for( int i = 0; i < nLen; ++i )
    5554           0 :                 pDXAry[i] /= nWidthFactor;
    5555           0 :         nWidth /= nWidthFactor;
    5556             :     }
    5557             : 
    5558      511842 :     return nWidth;
    5559             : }
    5560             : 
    5561       10937 : bool OutputDevice::GetCaretPositions( const OUString& rStr, sal_Int32* pCaretXArray,
    5562             :     sal_Int32 nIndex, sal_Int32 nLen,
    5563             :     sal_Int32* pDXAry, long nLayoutWidth,
    5564             :     sal_Bool bCellBreaking ) const
    5565             : {
    5566             :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    5567             : 
    5568       10937 :     if( nIndex >= rStr.getLength() )
    5569           0 :         return false;
    5570       10937 :     if( nIndex+nLen >= rStr.getLength() )
    5571       10937 :         nLen = rStr.getLength() - nIndex;
    5572             : 
    5573             :     // layout complex text
    5574             :     SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen,
    5575       10937 :         Point(0,0), nLayoutWidth, pDXAry );
    5576       10937 :     if( !pSalLayout )
    5577           0 :         return false;
    5578             : 
    5579       10937 :     int nWidthFactor = pSalLayout->GetUnitsPerPixel();
    5580       10937 :     pSalLayout->GetCaretPositions( 2*nLen, pCaretXArray );
    5581       10937 :     long nWidth = pSalLayout->GetTextWidth();
    5582       10937 :     pSalLayout->Release();
    5583             : 
    5584             :     // fixup unknown caret positions
    5585             :     int i;
    5586       11035 :     for( i = 0; i < 2 * nLen; ++i )
    5587       11026 :         if( pCaretXArray[ i ] >= 0 )
    5588       10928 :             break;
    5589       10937 :     long nXPos = pCaretXArray[ i ];
    5590      148243 :     for( i = 0; i < 2 * nLen; ++i )
    5591             :     {
    5592      137306 :         if( pCaretXArray[ i ] >= 0 )
    5593      137208 :             nXPos = pCaretXArray[ i ];
    5594             :         else
    5595          98 :             pCaretXArray[ i ] = nXPos;
    5596             :     }
    5597             : 
    5598             :     // handle window mirroring
    5599       10937 :     if( IsRTLEnabled() )
    5600             :     {
    5601         173 :         for( i = 0; i < 2 * nLen; ++i )
    5602         134 :             pCaretXArray[i] = nWidth - pCaretXArray[i] - 1;
    5603             :     }
    5604             : 
    5605             :     // convert from font units to logical units
    5606       10937 :     if( mbMap )
    5607             :     {
    5608           0 :         for( i = 0; i < 2*nLen; ++i )
    5609           0 :             pCaretXArray[i] = ImplDevicePixelToLogicWidth( pCaretXArray[i] );
    5610             :     }
    5611             : 
    5612       10937 :     if( nWidthFactor != 1 )
    5613             :     {
    5614           0 :         for( i = 0; i < 2*nLen; ++i )
    5615           0 :             pCaretXArray[i] /= nWidthFactor;
    5616             :     }
    5617             : 
    5618             :     // if requested move caret position to cell limits
    5619             :     if( bCellBreaking )
    5620             :     {
    5621             :         ; // FIXME
    5622             :     }
    5623             : 
    5624       10937 :     return true;
    5625             : }
    5626             : 
    5627       25370 : void OutputDevice::DrawStretchText( const Point& rStartPt, sal_uLong nWidth,
    5628             :                                     const String& rStr,
    5629             :                                     xub_StrLen nIndex, xub_StrLen nLen )
    5630             : {
    5631             :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    5632             : 
    5633       25370 :     if ( mpMetaFile )
    5634       24356 :         mpMetaFile->AddAction( new MetaStretchTextAction( rStartPt, nWidth, rStr, nIndex, nLen ) );
    5635             : 
    5636       25370 :     if ( !IsDeviceOutputNecessary() )
    5637       49726 :         return;
    5638             : 
    5639        1014 :     SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen, rStartPt, nWidth, NULL, true );
    5640        1014 :     if( pSalLayout )
    5641             :     {
    5642        1014 :         ImplDrawText( *pSalLayout );
    5643        1014 :         pSalLayout->Release();
    5644             :     }
    5645             : 
    5646        1014 :     if( mpAlphaVDev )
    5647           0 :         mpAlphaVDev->DrawStretchText( rStartPt, nWidth, rStr, nIndex, nLen );
    5648             : }
    5649             : 
    5650      727237 : ImplLayoutArgs OutputDevice::ImplPrepareLayoutArgs( OUString& rStr,
    5651             :                                        const sal_Int32 nMinIndex, const sal_Int32 nLen,
    5652             :                                        long nPixelWidth, const sal_Int32* pDXArray ) const
    5653             : {
    5654             :     // get string length for calculating extents
    5655      727237 :     sal_Int32 nEndIndex = rStr.getLength();
    5656      727237 :     if( nMinIndex + nLen < nEndIndex )
    5657       93609 :         nEndIndex = nMinIndex + nLen;
    5658             : 
    5659             :     // don't bother if there is nothing to do
    5660      727237 :     if( nEndIndex < nMinIndex )
    5661           0 :         nEndIndex = nMinIndex;
    5662             : 
    5663      727237 :     int nLayoutFlags = 0;
    5664      727237 :     if( mnTextLayoutMode & TEXT_LAYOUT_BIDI_RTL )
    5665        2716 :         nLayoutFlags |= SAL_LAYOUT_BIDI_RTL;
    5666      727237 :     if( mnTextLayoutMode & TEXT_LAYOUT_BIDI_STRONG )
    5667      266742 :         nLayoutFlags |= SAL_LAYOUT_BIDI_STRONG;
    5668      460495 :     else if( 0 == (mnTextLayoutMode & TEXT_LAYOUT_BIDI_RTL) )
    5669             :     {
    5670             :         // disable Bidi if no RTL hint and no RTL codes used
    5671      457780 :         const sal_Unicode* pStr = rStr.getStr() + nMinIndex;
    5672      457780 :         const sal_Unicode* pEnd = rStr.getStr() + nEndIndex;
    5673     3679123 :         for( ; pStr < pEnd; ++pStr )
    5674     3221345 :             if( ((*pStr >= 0x0580) && (*pStr < 0x0800))   // middle eastern scripts
    5675     3221343 :             ||  ((*pStr >= 0xFB18) && (*pStr < 0xFE00))   // hebrew + arabic A presentation forms
    5676     3221343 :             ||  ((*pStr >= 0xFE70) && (*pStr < 0xFEFF)) ) // arabic presentation forms B
    5677             :                 break;
    5678      457780 :         if( pStr >= pEnd )
    5679      457778 :             nLayoutFlags |= SAL_LAYOUT_BIDI_STRONG;
    5680             :     }
    5681             : 
    5682      727237 :     if( mbKerning )
    5683       87426 :         nLayoutFlags |= SAL_LAYOUT_KERNING_PAIRS;
    5684      727237 :     if( maFont.GetKerning() & KERNING_ASIAN )
    5685           0 :         nLayoutFlags |= SAL_LAYOUT_KERNING_ASIAN;
    5686      727237 :     if( maFont.IsVertical() )
    5687          23 :         nLayoutFlags |= SAL_LAYOUT_VERTICAL;
    5688             : 
    5689      727237 :     if( mnTextLayoutMode & TEXT_LAYOUT_ENABLE_LIGATURES )
    5690           0 :         nLayoutFlags |= SAL_LAYOUT_ENABLE_LIGATURES;
    5691      727237 :     else if( mnTextLayoutMode & TEXT_LAYOUT_COMPLEX_DISABLED )
    5692      191141 :         nLayoutFlags |= SAL_LAYOUT_COMPLEX_DISABLED;
    5693             :     else
    5694             :     {
    5695             :         // disable CTL for non-CTL text
    5696      536096 :         const sal_Unicode* pStr = rStr.getStr() + nMinIndex;
    5697      536096 :         const sal_Unicode* pEnd = rStr.getStr() + nEndIndex;
    5698    11691892 :         for( ; pStr < pEnd; ++pStr )
    5699    11155799 :             if( ((*pStr >= 0x0300) && (*pStr < 0x0370))   // diacritical marks
    5700    11155799 :             ||  ((*pStr >= 0x0590) && (*pStr < 0x10A0))   // many CTL scripts
    5701    11155796 :             ||  ((*pStr >= 0x1100) && (*pStr < 0x1200))   // hangul jamo
    5702    11155796 :             ||  ((*pStr >= 0x1700) && (*pStr < 0x1900))   // many CTL scripts
    5703    11155796 :             ||  ((*pStr >= 0xFB1D) && (*pStr < 0xFE00))   // middle east presentation
    5704    11155796 :             ||  ((*pStr >= 0xFE70) && (*pStr < 0xFEFF))   // arabic presentation B
    5705    11155796 :             ||  ((*pStr >= 0xFE00) && (*pStr < 0xFE10))   // variation selectors in BMP
    5706    11155796 :             ||  ((pStr + 1 < pEnd) && (pStr[0] == 0xDB40) && (0xDD00 <= pStr[1]) && (pStr[1] < 0xDEF0)) // variation selector supplement
    5707             :             )
    5708             :                 break;
    5709      536096 :         if( pStr >= pEnd )
    5710      536093 :             nLayoutFlags |= SAL_LAYOUT_COMPLEX_DISABLED;
    5711             :     }
    5712             : 
    5713      727237 :     if( meTextLanguage ) //TODO: (mnTextLayoutMode & TEXT_LAYOUT_SUBSTITUTE_DIGITS)
    5714             :     {
    5715             :         // disable character localization when no digits used
    5716      317922 :         const sal_Unicode* pBase = rStr.getStr();
    5717      317922 :         const sal_Unicode* pStr = pBase + nMinIndex;
    5718      317922 :         const sal_Unicode* pEnd = pBase + nEndIndex;
    5719      317922 :         OUStringBuffer sTmpStr(rStr);
    5720     9161769 :         for( ; pStr < pEnd; ++pStr )
    5721             :         {
    5722             :             // TODO: are there non-digit localizations?
    5723     8843847 :             if( (*pStr >= '0') && (*pStr <= '9') )
    5724             :             {
    5725             :                 // translate characters to local preference
    5726     4795756 :                 sal_UCS4 cChar = GetLocalizedChar( *pStr, meTextLanguage );
    5727     4795756 :                 if( cChar != *pStr )
    5728             :                     // TODO: are the localized digit surrogates?
    5729           0 :                     sTmpStr[pStr - pBase] = cChar;
    5730             :             }
    5731             :         }
    5732      317922 :         rStr = sTmpStr.makeStringAndClear();
    5733             :     }
    5734             : 
    5735             :     // right align for RTL text, DRAWPOS_REVERSED, RTL window style
    5736      727237 :     bool bRightAlign = ((mnTextLayoutMode & TEXT_LAYOUT_BIDI_RTL) != 0);
    5737      727237 :     if( mnTextLayoutMode & TEXT_LAYOUT_TEXTORIGIN_LEFT )
    5738       19946 :         bRightAlign = false;
    5739      707291 :     else if ( mnTextLayoutMode & TEXT_LAYOUT_TEXTORIGIN_RIGHT )
    5740           0 :         bRightAlign = true;
    5741             :     // SSA: hack for western office, ie text get right aligned
    5742             :     //      for debugging purposes of mirrored UI
    5743      727237 :     bool bRTLWindow = IsRTLEnabled();
    5744      727237 :     bRightAlign ^= bRTLWindow;
    5745      727237 :     if( bRightAlign )
    5746         498 :         nLayoutFlags |= SAL_LAYOUT_RIGHT_ALIGN;
    5747             : 
    5748             :     // set layout options
    5749      727237 :     ImplLayoutArgs aLayoutArgs( rStr.getStr(), rStr.getLength(), nMinIndex, nEndIndex, nLayoutFlags, maFont.GetLanguage() );
    5750             : 
    5751      727237 :     int nOrientation = mpFontEntry ? mpFontEntry->mnOrientation : 0;
    5752      727237 :     aLayoutArgs.SetOrientation( nOrientation );
    5753             : 
    5754      727237 :     aLayoutArgs.SetLayoutWidth( nPixelWidth );
    5755      727237 :     aLayoutArgs.SetDXArray( pDXArray );
    5756             : 
    5757      727237 :     return aLayoutArgs;
    5758             : }
    5759             : 
    5760      738893 : SalLayout* OutputDevice::ImplLayout( const OUString& rOrigStr, sal_Int32 nMinIndex, sal_Int32 nLen,
    5761             :                                      const Point& rLogicalPos, long nLogicalWidth, const sal_Int32* pDXArray,
    5762             :                                      bool bFilter ) const
    5763             : {
    5764             :     // we need a graphics
    5765      738893 :     if( !mpGraphics )
    5766         221 :         if( !ImplGetGraphics() )
    5767           2 :             return NULL;
    5768             : 
    5769             :     // initialize font if needed
    5770      738891 :     if( mbNewFont )
    5771       65094 :         if( !ImplNewFont() )
    5772           0 :             return NULL;
    5773      738891 :     if( mbInitFont )
    5774      177129 :         ImplInitFont();
    5775             : 
    5776             :     // check string index and length
    5777      738891 :     if( -1 == nLen || nMinIndex + nLen > rOrigStr.getLength() )
    5778             :     {
    5779      112030 :         const sal_Int32 nNewLen = rOrigStr.getLength() - nMinIndex;
    5780      112030 :         if( nNewLen <= 0 )
    5781        6908 :             return NULL;
    5782      105122 :         nLen = nNewLen;
    5783             :     }
    5784             : 
    5785      731983 :     OUString aStr = rOrigStr;
    5786             : 
    5787             :     // filter out special markers
    5788      731983 :     if( bFilter )
    5789             :     {
    5790       91716 :         sal_Int32 nCutStart, nCutStop, nOrgLen = nLen;
    5791       91716 :         bool bFiltered = mpGraphics->filterText( rOrigStr, aStr, nMinIndex, nLen, nCutStart, nCutStop );
    5792       91716 :         if( !nLen )
    5793        4749 :             return NULL;
    5794             : 
    5795       86967 :         if( bFiltered && nCutStop != nCutStart && pDXArray )
    5796             :         {
    5797           0 :             if( !nLen )
    5798           0 :                 pDXArray = NULL;
    5799             :             else
    5800             :             {
    5801           0 :                 sal_Int32* pAry = (sal_Int32*)alloca(sizeof(sal_Int32)*nLen);
    5802           0 :                 if( nCutStart > nMinIndex )
    5803           0 :                     memcpy( pAry, pDXArray, sizeof(sal_Int32)*(nCutStart-nMinIndex) );
    5804             :                 // note: nCutStart will never be smaller than nMinIndex
    5805           0 :                 memcpy( pAry+nCutStart-nMinIndex,
    5806           0 :                         pDXArray + nOrgLen - (nCutStop-nMinIndex),
    5807           0 :                         sizeof(sal_Int32)*(nLen - (nCutStart-nMinIndex)) );
    5808           0 :                 pDXArray = pAry;
    5809             :             }
    5810             :         }
    5811             :     }
    5812             : 
    5813             :     // convert from logical units to physical units
    5814             :     // recode string if needed
    5815      727234 :     if( mpFontEntry->mpConversion ) {
    5816         139 :         mpFontEntry->mpConversion->RecodeString( aStr, 0, aStr.getLength() );
    5817             :     }
    5818             : 
    5819      727234 :     long nPixelWidth = nLogicalWidth;
    5820      727234 :     if( nLogicalWidth && mbMap )
    5821        1011 :         nPixelWidth = ImplLogicWidthToDevicePixel( nLogicalWidth );
    5822      727234 :     if( pDXArray && mbMap )
    5823             :     {
    5824             :         // convert from logical units to font units using a temporary array
    5825       13126 :         sal_Int32* pTempDXAry = (sal_Int32*)alloca( nLen * sizeof(sal_Int32) );
    5826             :         // using base position for better rounding a.k.a. "dancing characters"
    5827       13126 :         int nPixelXOfs = ImplLogicWidthToDevicePixel( rLogicalPos.X() );
    5828      611353 :         for( int i = 0; i < nLen; ++i )
    5829      598227 :             pTempDXAry[i] = ImplLogicWidthToDevicePixel( rLogicalPos.X() + pDXArray[i] ) - nPixelXOfs;
    5830             : 
    5831       13126 :         pDXArray = pTempDXAry;
    5832             :     }
    5833             : 
    5834     1454468 :     ImplLayoutArgs aLayoutArgs = ImplPrepareLayoutArgs( aStr, nMinIndex, nLen, nPixelWidth, pDXArray );
    5835             : 
    5836             : #ifdef MACOSX
    5837             :     // CoreText layouts are immutable and already contain the text color
    5838             :     // so we need to provide the color already for the layout request
    5839             :     // even if this layout will never be drawn
    5840             :     if( mbInitTextColor )
    5841             :         const_cast<OutputDevice&>(*this).ImplInitTextColor();
    5842             : #endif
    5843             : 
    5844             :     // get matching layout object for base font
    5845      727234 :     SalLayout* pSalLayout = mpGraphics->GetTextLayout( aLayoutArgs, 0 );
    5846             : 
    5847             :     // layout text
    5848      727234 :     if( pSalLayout && !pSalLayout->LayoutText( aLayoutArgs ) )
    5849             :     {
    5850           0 :         pSalLayout->Release();
    5851           0 :         pSalLayout = NULL;
    5852             :     }
    5853             : 
    5854      727234 :     if( !pSalLayout )
    5855           0 :         return NULL;
    5856             : 
    5857             :     // do glyph fallback if needed
    5858             :     // #105768# avoid fallback for very small font sizes
    5859      727234 :     if( aLayoutArgs.NeedFallback() )
    5860         947 :         if( mpFontEntry && (mpFontEntry->maFontSelData.mnHeight >= 3) )
    5861         947 :             pSalLayout = ImplGlyphFallbackLayout( pSalLayout, aLayoutArgs );
    5862             : 
    5863             :     // position, justify, etc. the layout
    5864      727234 :     pSalLayout->AdjustLayout( aLayoutArgs );
    5865      727234 :     pSalLayout->DrawBase() = ImplLogicToDevicePixel( rLogicalPos );
    5866             :     // adjust to right alignment if necessary
    5867      727234 :     if( aLayoutArgs.mnFlags & SAL_LAYOUT_RIGHT_ALIGN )
    5868             :     {
    5869             :         long nRTLOffset;
    5870         498 :         if( pDXArray )
    5871           6 :             nRTLOffset = pDXArray[ nLen - 1 ];
    5872         492 :         else if( nPixelWidth )
    5873           0 :             nRTLOffset = nPixelWidth;
    5874             :         else
    5875         492 :             nRTLOffset = pSalLayout->GetTextWidth() / pSalLayout->GetUnitsPerPixel();
    5876         498 :         pSalLayout->DrawOffset().X() = 1 - nRTLOffset;
    5877             :     }
    5878             : 
    5879     1459217 :     return pSalLayout;
    5880             : }
    5881             : 
    5882         947 : SalLayout* OutputDevice::getFallbackFont(ImplFontEntry &rFallbackFont,
    5883             :     FontSelectPattern &rFontSelData, int nFallbackLevel,
    5884             :     ImplLayoutArgs& rLayoutArgs) const
    5885             : {
    5886         947 :     rFallbackFont.mnSetFontFlags = mpGraphics->SetFont( &rFontSelData, nFallbackLevel );
    5887             : 
    5888         947 :     rLayoutArgs.ResetPos();
    5889         947 :     SalLayout* pFallback = mpGraphics->GetTextLayout( rLayoutArgs, nFallbackLevel );
    5890             : 
    5891         947 :     if (!pFallback)
    5892           0 :         return NULL;
    5893             : 
    5894         947 :     if (!pFallback->LayoutText(rLayoutArgs))
    5895             :     {
    5896             :         // there is no need for a font that couldn't resolve anything
    5897           0 :         pFallback->Release();
    5898           0 :         return NULL;
    5899             :     }
    5900             : 
    5901         947 :     pFallback->AdjustLayout( rLayoutArgs );
    5902             : 
    5903         947 :     return pFallback;
    5904             : }
    5905             : 
    5906         947 : SalLayout* OutputDevice::ImplGlyphFallbackLayout( SalLayout* pSalLayout, ImplLayoutArgs& rLayoutArgs ) const
    5907             : {
    5908             :     // prepare multi level glyph fallback
    5909         947 :     MultiSalLayout* pMultiSalLayout = NULL;
    5910         947 :     ImplLayoutRuns aLayoutRuns = rLayoutArgs.maRuns;
    5911         947 :     rLayoutArgs.PrepareFallback();
    5912         947 :     rLayoutArgs.mnFlags |= SAL_LAYOUT_FOR_FALLBACK;
    5913             : 
    5914             :     // get list of unicodes that need glyph fallback
    5915         947 :     int nCharPos = -1;
    5916         947 :     bool bRTL = false;
    5917        1894 :     OUStringBuffer aMissingCodeBuf;
    5918        2849 :     while( rLayoutArgs.GetNextPos( &nCharPos, &bRTL) )
    5919         955 :         aMissingCodeBuf.append( rLayoutArgs.mpStr[ nCharPos ] );
    5920         947 :     rLayoutArgs.ResetPos();
    5921        1894 :     OUString aMissingCodes = aMissingCodeBuf.makeStringAndClear();
    5922             : 
    5923        1894 :     FontSelectPattern aFontSelData = mpFontEntry->maFontSelData;
    5924             : 
    5925             :     // when device specific font substitution may have been performed for
    5926             :     // the originally selected font then make sure that a fallback to that
    5927             :     // font is performed first
    5928         947 :     int nDevSpecificFallback = 0;
    5929         947 :     if( mpOutDevData && !mpOutDevData->maDevFontSubst.Empty() )
    5930           0 :         nDevSpecificFallback = 1;
    5931             : 
    5932             :     // try if fallback fonts support the missing unicodes
    5933       13680 :     for( int nFallbackLevel = 1; nFallbackLevel < MAX_FALLBACK; ++nFallbackLevel )
    5934             :     {
    5935             :         // find a font family suited for glyph fallback
    5936             : #ifndef FONTFALLBACK_HOOKS_DISABLED
    5937             :         // GetGlyphFallbackFont() needs a valid aFontSelData.mpFontEntry
    5938             :         // if the system-specific glyph fallback is active
    5939       12835 :         aFontSelData.mpFontEntry = mpFontEntry; // reset the fontentry to base-level
    5940             : #endif
    5941             :         ImplFontEntry* pFallbackFont = mpFontCache->GetGlyphFallbackFont( mpFontList,
    5942       12835 :             aFontSelData, nFallbackLevel-nDevSpecificFallback, aMissingCodes );
    5943       12835 :         if( !pFallbackFont )
    5944           0 :             break;
    5945             : 
    5946       12835 :         aFontSelData.mpFontEntry = pFallbackFont;
    5947       12835 :         aFontSelData.mpFontData = pFallbackFont->maFontSelData.mpFontData;
    5948       12835 :         if( mpFontEntry && nFallbackLevel < MAX_FALLBACK-1)
    5949             :         {
    5950             :             // ignore fallback font if it is the same as the original font
    5951       11990 :             if( mpFontEntry->maFontSelData.mpFontData == aFontSelData.mpFontData )
    5952             :             {
    5953       11888 :                 mpFontCache->Release( pFallbackFont );
    5954       11888 :                 continue;
    5955             :             }
    5956             :         }
    5957             : 
    5958             :         // create and add glyph fallback layout to multilayout
    5959             :         SalLayout* pFallback = getFallbackFont(*pFallbackFont, aFontSelData,
    5960         947 :             nFallbackLevel, rLayoutArgs);
    5961         947 :         if (pFallback)
    5962             :         {
    5963         947 :             if( !pMultiSalLayout )
    5964         947 :                 pMultiSalLayout = new MultiSalLayout( *pSalLayout );
    5965             :             pMultiSalLayout->AddFallback( *pFallback,
    5966         947 :                 rLayoutArgs.maRuns, aFontSelData.mpFontData );
    5967         947 :             if (nFallbackLevel == MAX_FALLBACK-1)
    5968         845 :                 pMultiSalLayout->SetInComplete();
    5969             :         }
    5970             : 
    5971         947 :         mpFontCache->Release( pFallbackFont );
    5972             : 
    5973             :         // break when this fallback was sufficient
    5974         947 :         if( !rLayoutArgs.PrepareFallback() )
    5975         102 :             break;
    5976             :     }
    5977             : 
    5978         947 :     if( pMultiSalLayout && pMultiSalLayout->LayoutText( rLayoutArgs ) )
    5979         947 :         pSalLayout = pMultiSalLayout;
    5980             : 
    5981             :     // restore orig font settings
    5982         947 :     pSalLayout->InitFont();
    5983         947 :     rLayoutArgs.maRuns = aLayoutRuns;
    5984             : 
    5985        1894 :     return pSalLayout;
    5986             : }
    5987             : 
    5988           1 : sal_Bool OutputDevice::GetTextIsRTL( const OUString& rString, sal_Int32 nIndex, sal_Int32 nLen ) const
    5989             : {
    5990           1 :     OUString aStr( rString );
    5991           2 :     ImplLayoutArgs aArgs = ImplPrepareLayoutArgs( aStr, nIndex, nLen, 0, NULL );
    5992           1 :     bool bRTL = false;
    5993           1 :     int nCharPos = -1;
    5994           1 :     aArgs.GetNextPos( &nCharPos, &bRTL );
    5995           2 :     return (nCharPos != nIndex) ? sal_True : sal_False;
    5996             : }
    5997             : 
    5998       25448 : xub_StrLen OutputDevice::GetTextBreak( const OUString& rStr, long nTextWidth,
    5999             :                                        sal_Int32 nIndex, sal_Int32 nLen,
    6000             :                                        long nCharExtra, sal_Bool /*TODO: bCellBreaking*/ ) const
    6001             : {
    6002             :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    6003             : 
    6004       25448 :     SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen );
    6005       25448 :     xub_StrLen nRetVal = STRING_LEN;
    6006       25448 :     if( pSalLayout )
    6007             :     {
    6008             :         // convert logical widths into layout units
    6009             :         // NOTE: be very careful to avoid rounding errors for nCharExtra case
    6010             :         // problem with rounding errors especially for small nCharExtras
    6011             :         // TODO: remove when layout units have subpixel granularity
    6012       25448 :         long nWidthFactor = pSalLayout->GetUnitsPerPixel();
    6013       25448 :         long nSubPixelFactor = (nWidthFactor < 64 ) ? 64 : 1;
    6014       25448 :         nTextWidth *= nWidthFactor * nSubPixelFactor;
    6015       25448 :         long nTextPixelWidth = ImplLogicWidthToDevicePixel( nTextWidth );
    6016       25448 :         long nExtraPixelWidth = 0;
    6017       25448 :         if( nCharExtra != 0 )
    6018             :         {
    6019         120 :             nCharExtra *= nWidthFactor * nSubPixelFactor;
    6020         120 :             nExtraPixelWidth = ImplLogicWidthToDevicePixel( nCharExtra );
    6021             :         }
    6022       25448 :         nRetVal = sal::static_int_cast<xub_StrLen>(pSalLayout->GetTextBreak( nTextPixelWidth, nExtraPixelWidth, nSubPixelFactor ));
    6023             : 
    6024       25448 :         pSalLayout->Release();
    6025             :     }
    6026             : 
    6027       25448 :     return nRetVal;
    6028             : }
    6029             : 
    6030           0 : xub_StrLen OutputDevice::GetTextBreak( const OUString& rStr, long nTextWidth,
    6031             :                                        sal_Unicode nHyphenatorChar, sal_Int32& rHyphenatorPos,
    6032             :                                        sal_Int32 nIndex, sal_Int32 nLen,
    6033             :                                        long nCharExtra ) const
    6034             : {
    6035             :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    6036             : 
    6037           0 :     rHyphenatorPos = STRING_LEN;
    6038             : 
    6039           0 :     SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen );
    6040           0 :     if( !pSalLayout )
    6041           0 :         return STRING_LEN;
    6042             : 
    6043             :     // convert logical widths into layout units
    6044             :     // NOTE: be very careful to avoid rounding errors for nCharExtra case
    6045             :     // problem with rounding errors especially for small nCharExtras
    6046             :     // TODO: remove when layout units have subpixel granularity
    6047           0 :     long nWidthFactor = pSalLayout->GetUnitsPerPixel();
    6048           0 :     long nSubPixelFactor = (nWidthFactor < 64 ) ? 64 : 1;
    6049             : 
    6050           0 :     nTextWidth *= nWidthFactor * nSubPixelFactor;
    6051           0 :     long nTextPixelWidth = ImplLogicWidthToDevicePixel( nTextWidth );
    6052           0 :     long nExtraPixelWidth = 0;
    6053           0 :     if( nCharExtra != 0 )
    6054             :     {
    6055           0 :         nCharExtra *= nWidthFactor * nSubPixelFactor;
    6056           0 :         nExtraPixelWidth = ImplLogicWidthToDevicePixel( nCharExtra );
    6057             :     }
    6058             : 
    6059             :     // calculate un-hyphenated break position
    6060           0 :     xub_StrLen nRetVal = sal::static_int_cast<xub_StrLen>(pSalLayout->GetTextBreak( nTextPixelWidth, nExtraPixelWidth, nSubPixelFactor ));
    6061             : 
    6062             :     // calculate hyphenated break position
    6063           0 :     OUString aHyphenatorStr(nHyphenatorChar);
    6064           0 :     sal_Int32 nTempLen = 1;
    6065           0 :     SalLayout* pHyphenatorLayout = ImplLayout( aHyphenatorStr, 0, nTempLen );
    6066           0 :     if( pHyphenatorLayout )
    6067             :     {
    6068             :         // calculate subpixel width of hyphenation character
    6069           0 :         long nHyphenatorPixelWidth = pHyphenatorLayout->GetTextWidth() * nSubPixelFactor;
    6070           0 :         pHyphenatorLayout->Release();
    6071             : 
    6072             :         // calculate hyphenated break position
    6073           0 :         nTextPixelWidth -= nHyphenatorPixelWidth;
    6074           0 :         if( nExtraPixelWidth > 0 )
    6075           0 :             nTextPixelWidth -= nExtraPixelWidth;
    6076             : 
    6077             :         // why does this return "int" and use STRING_LEN for errors???
    6078             :         xub_StrLen nTmp = sal::static_int_cast<xub_StrLen>(
    6079           0 :             pSalLayout->GetTextBreak(nTextPixelWidth, nExtraPixelWidth, nSubPixelFactor));
    6080             : 
    6081           0 :         nTmp = std::min(nTmp, nRetVal);
    6082             : 
    6083             :         // TODO: remove nTmp when GetTextBreak sal_Int32
    6084           0 :         rHyphenatorPos = (nTmp == STRING_LEN) ? -1 : nTmp;
    6085             :     }
    6086             : 
    6087           0 :     pSalLayout->Release();
    6088           0 :     return nRetVal;
    6089             : }
    6090             : 
    6091        4045 : void OutputDevice::ImplDrawText( OutputDevice& rTargetDevice, const Rectangle& rRect,
    6092             :                                  const String& rOrigStr, sal_uInt16 nStyle,
    6093             :                                  MetricVector* pVector, OUString* pDisplayText,
    6094             :                                  ::vcl::ITextLayout& _rLayout )
    6095             : {
    6096        4045 :     Color aOldTextColor;
    6097        4045 :     Color aOldTextFillColor;
    6098        4045 :     bool  bRestoreFillColor = false;
    6099        4045 :     if ( (nStyle & TEXT_DRAW_DISABLE) && ! pVector )
    6100             :     {
    6101         656 :         sal_Bool  bHighContrastBlack = sal_False;
    6102         656 :         sal_Bool  bHighContrastWhite = sal_False;
    6103         656 :         const StyleSettings& rStyleSettings( rTargetDevice.GetSettings().GetStyleSettings() );
    6104         656 :         if( rStyleSettings.GetHighContrastMode() )
    6105             :         {
    6106           0 :             Color aCol;
    6107           0 :             if( rTargetDevice.IsBackground() )
    6108           0 :                 aCol = rTargetDevice.GetBackground().GetColor();
    6109             :             else
    6110             :                 // best guess is the face color here
    6111             :                 // but it may be totally wrong. the background color
    6112             :                 // was typically already reset
    6113           0 :                 aCol = rStyleSettings.GetFaceColor();
    6114             : 
    6115           0 :             bHighContrastBlack = aCol.IsDark();
    6116           0 :             bHighContrastWhite = aCol.IsBright();
    6117             :         }
    6118             : 
    6119         656 :         aOldTextColor = rTargetDevice.GetTextColor();
    6120         656 :         if ( rTargetDevice.IsTextFillColor() )
    6121             :         {
    6122           0 :             bRestoreFillColor = true;
    6123           0 :             aOldTextFillColor = rTargetDevice.GetTextFillColor();
    6124             :         }
    6125         656 :         if( bHighContrastBlack )
    6126           0 :             rTargetDevice.SetTextColor( COL_GREEN );
    6127         656 :         else if( bHighContrastWhite )
    6128           0 :             rTargetDevice.SetTextColor( COL_LIGHTGREEN );
    6129             :         else
    6130             :         {
    6131             :             // draw disabled text always without shadow
    6132             :             // as it fits better with native look
    6133         656 :             rTargetDevice.SetTextColor( rTargetDevice.GetSettings().GetStyleSettings().GetDisableColor() );
    6134             :         }
    6135             :     }
    6136             : 
    6137        4045 :     long        nWidth          = rRect.GetWidth();
    6138        4045 :     long        nHeight         = rRect.GetHeight();
    6139             : 
    6140        4045 :     if ( ((nWidth <= 0) || (nHeight <= 0)) && (nStyle & TEXT_DRAW_CLIP) )
    6141        4045 :         return;
    6142             : 
    6143        4045 :     Point       aPos            = rRect.TopLeft();
    6144             : 
    6145        4045 :     long        nTextHeight     = rTargetDevice.GetTextHeight();
    6146        4045 :     TextAlign   eAlign          = rTargetDevice.GetTextAlign();
    6147        4045 :     xub_StrLen  nMnemonicPos    = STRING_NOTFOUND;
    6148             : 
    6149        4045 :     String aStr = rOrigStr;
    6150        4045 :     if ( nStyle & TEXT_DRAW_MNEMONIC )
    6151         916 :         aStr = GetNonMnemonicString( aStr, nMnemonicPos );
    6152             : 
    6153        4045 :     const bool bDrawMnemonics = !(rTargetDevice.GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_NOMNEMONICS) && !pVector;
    6154             : 
    6155             :     // We treat multiline text differently
    6156        4045 :     if ( nStyle & TEXT_DRAW_MULTILINE )
    6157             :     {
    6158             : 
    6159         934 :         XubString               aLastLine;
    6160        1868 :         ImplMultiTextLineInfo   aMultiLineInfo;
    6161             :         ImplTextLineInfo*       pLineInfo;
    6162             :         xub_StrLen              i;
    6163             :         xub_StrLen              nLines;
    6164             :         xub_StrLen              nFormatLines;
    6165             : 
    6166         934 :         if ( nTextHeight )
    6167             :         {
    6168         934 :             long nMaxTextWidth = ImplGetTextLines( aMultiLineInfo, nWidth, aStr, nStyle, _rLayout );
    6169         934 :             nLines = (xub_StrLen)(nHeight/nTextHeight);
    6170         934 :             nFormatLines = aMultiLineInfo.Count();
    6171         934 :             if ( !nLines )
    6172          75 :                 nLines = 1;
    6173         934 :             if ( nFormatLines > nLines )
    6174             :             {
    6175           0 :                 if ( nStyle & TEXT_DRAW_ENDELLIPSIS )
    6176             :                 {
    6177             :                     // Create last line and shorten it
    6178           0 :                     nFormatLines = nLines-1;
    6179             : 
    6180           0 :                     pLineInfo = aMultiLineInfo.GetLine( nFormatLines );
    6181           0 :                     aLastLine = convertLineEnd(aStr.Copy(pLineInfo->GetIndex()), LINEEND_LF);
    6182             :                     // Replace all LineFeeds with Spaces
    6183           0 :                     xub_StrLen nLastLineLen = aLastLine.Len();
    6184           0 :                     for ( i = 0; i < nLastLineLen; i++ )
    6185             :                     {
    6186           0 :                         if ( aLastLine.GetChar( i ) == '\n' )
    6187           0 :                             aLastLine.SetChar( i, ' ' );
    6188             :                     }
    6189           0 :                     aLastLine = ImplGetEllipsisString( rTargetDevice, aLastLine, nWidth, nStyle, _rLayout );
    6190           0 :                     nStyle &= ~(TEXT_DRAW_VCENTER | TEXT_DRAW_BOTTOM);
    6191           0 :                     nStyle |= TEXT_DRAW_TOP;
    6192             :                 }
    6193             :             }
    6194             :             else
    6195             :             {
    6196         934 :                 if ( nMaxTextWidth <= nWidth )
    6197         924 :                     nStyle &= ~TEXT_DRAW_CLIP;
    6198             :             }
    6199             : 
    6200             :             // Do we need to clip the height?
    6201         934 :             if ( nFormatLines*nTextHeight > nHeight )
    6202          75 :                 nStyle |= TEXT_DRAW_CLIP;
    6203             : 
    6204             :             // Set clipping
    6205         934 :             if ( nStyle & TEXT_DRAW_CLIP )
    6206             :             {
    6207          75 :                 rTargetDevice.Push( PUSH_CLIPREGION );
    6208          75 :                 rTargetDevice.IntersectClipRegion( rRect );
    6209             :             }
    6210             : 
    6211             :             // Vertical alignment
    6212         934 :             if ( nStyle & TEXT_DRAW_BOTTOM )
    6213           0 :                 aPos.Y() += nHeight-(nFormatLines*nTextHeight);
    6214         934 :             else if ( nStyle & TEXT_DRAW_VCENTER )
    6215         814 :                 aPos.Y() += (nHeight-(nFormatLines*nTextHeight))/2;
    6216             : 
    6217             :             // Font alignment
    6218         934 :             if ( eAlign == ALIGN_BOTTOM )
    6219           0 :                 aPos.Y() += nTextHeight;
    6220         934 :             else if ( eAlign == ALIGN_BASELINE )
    6221           0 :                 aPos.Y() += rTargetDevice.GetFontMetric().GetAscent();
    6222             : 
    6223             :             // Output all lines except for the last one
    6224        1869 :             for ( i = 0; i < nFormatLines; i++ )
    6225             :             {
    6226         935 :                 pLineInfo = aMultiLineInfo.GetLine( i );
    6227         935 :                 if ( nStyle & TEXT_DRAW_RIGHT )
    6228           0 :                     aPos.X() += nWidth-pLineInfo->GetWidth();
    6229         935 :                 else if ( nStyle & TEXT_DRAW_CENTER )
    6230         298 :                     aPos.X() += (nWidth-pLineInfo->GetWidth())/2;
    6231         935 :                 xub_StrLen nIndex   = pLineInfo->GetIndex();
    6232         935 :                 xub_StrLen nLineLen = pLineInfo->GetLen();
    6233         935 :                 _rLayout.DrawText( aPos, aStr, nIndex, nLineLen, pVector, pDisplayText );
    6234         935 :                 if ( bDrawMnemonics )
    6235             :                 {
    6236         934 :                     if ( (nMnemonicPos >= nIndex) && (nMnemonicPos < nIndex+nLineLen) )
    6237             :                     {
    6238             :                         long        nMnemonicX;
    6239             :                         long        nMnemonicY;
    6240             :                         long        nMnemonicWidth;
    6241             : 
    6242          70 :                         sal_Int32* pCaretXArray = (sal_Int32*) alloca( 2 * sizeof(sal_Int32) * nLineLen );
    6243             :                         /*sal_Bool bRet =*/ _rLayout.GetCaretPositions( aStr, pCaretXArray,
    6244          70 :                                                 nIndex, nLineLen );
    6245          70 :                         long lc_x1 = pCaretXArray[2*(nMnemonicPos - nIndex)];
    6246          70 :                         long lc_x2 = pCaretXArray[2*(nMnemonicPos - nIndex)+1];
    6247          70 :                         nMnemonicWidth = rTargetDevice.ImplLogicWidthToDevicePixel( ::abs((int)(lc_x1 - lc_x2)) );
    6248             : 
    6249          70 :                         Point       aTempPos = rTargetDevice.LogicToPixel( aPos );
    6250          70 :                         nMnemonicX = rTargetDevice.GetOutOffXPixel() + aTempPos.X() + rTargetDevice.ImplLogicWidthToDevicePixel( std::min( lc_x1, lc_x2 ) );
    6251          70 :                         nMnemonicY = rTargetDevice.GetOutOffYPixel() + aTempPos.Y() + rTargetDevice.ImplLogicWidthToDevicePixel( rTargetDevice.GetFontMetric().GetAscent() );
    6252          70 :                         rTargetDevice.ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
    6253             :                     }
    6254             :                 }
    6255         935 :                 aPos.Y() += nTextHeight;
    6256         935 :                 aPos.X() = rRect.Left();
    6257             :             }
    6258             : 
    6259             : 
    6260             :             // If there still is a last line, we output it left-aligned as the line would be clipped
    6261         934 :             if ( aLastLine.Len() )
    6262           0 :                 _rLayout.DrawText( aPos, aLastLine, 0, STRING_LEN, pVector, pDisplayText );
    6263             : 
    6264             :             // Reset clipping
    6265         934 :             if ( nStyle & TEXT_DRAW_CLIP )
    6266          75 :                 rTargetDevice.Pop();
    6267         934 :         }
    6268             :     }
    6269             :     else
    6270             :     {
    6271        3111 :         long nTextWidth = _rLayout.GetTextWidth( aStr, 0, -1 );
    6272             : 
    6273             :         // Clip text if needed
    6274        3111 :         if ( nTextWidth > nWidth )
    6275             :         {
    6276          76 :             if ( nStyle & TEXT_DRAW_ELLIPSIS )
    6277             :             {
    6278           0 :                 aStr = ImplGetEllipsisString( rTargetDevice, aStr, nWidth, nStyle, _rLayout );
    6279           0 :                 nStyle &= ~(TEXT_DRAW_CENTER | TEXT_DRAW_RIGHT);
    6280           0 :                 nStyle |= TEXT_DRAW_LEFT;
    6281           0 :                 nTextWidth = _rLayout.GetTextWidth( aStr, 0, aStr.Len() );
    6282             :             }
    6283             :         }
    6284             :         else
    6285             :         {
    6286        3035 :             if ( nTextHeight <= nHeight )
    6287        3035 :                 nStyle &= ~TEXT_DRAW_CLIP;
    6288             :         }
    6289             : 
    6290             :         // horizontal text alignment
    6291        3111 :         if ( nStyle & TEXT_DRAW_RIGHT )
    6292         334 :             aPos.X() += nWidth-nTextWidth;
    6293        2777 :         else if ( nStyle & TEXT_DRAW_CENTER )
    6294          56 :             aPos.X() += (nWidth-nTextWidth)/2;
    6295             : 
    6296             :         // vertical font alignment
    6297        3111 :         if ( eAlign == ALIGN_BOTTOM )
    6298           0 :             aPos.Y() += nTextHeight;
    6299        3111 :         else if ( eAlign == ALIGN_BASELINE )
    6300           0 :             aPos.Y() += rTargetDevice.GetFontMetric().GetAscent();
    6301             : 
    6302        3111 :         if ( nStyle & TEXT_DRAW_BOTTOM )
    6303           0 :             aPos.Y() += nHeight-nTextHeight;
    6304        3111 :         else if ( nStyle & TEXT_DRAW_VCENTER )
    6305         933 :             aPos.Y() += (nHeight-nTextHeight)/2;
    6306             : 
    6307        3111 :         long nMnemonicX = 0;
    6308        3111 :         long nMnemonicY = 0;
    6309        3111 :         long nMnemonicWidth = 0;
    6310        3111 :         if ( nMnemonicPos != STRING_NOTFOUND )
    6311             :         {
    6312           0 :             sal_Int32* pCaretXArray = (sal_Int32*) alloca( 2 * sizeof(sal_Int32) * aStr.Len() );
    6313           0 :             /*sal_Bool bRet =*/ _rLayout.GetCaretPositions( aStr, pCaretXArray, 0, aStr.Len() );
    6314           0 :             long lc_x1 = pCaretXArray[2*(nMnemonicPos)];
    6315           0 :             long lc_x2 = pCaretXArray[2*(nMnemonicPos)+1];
    6316           0 :             nMnemonicWidth = rTargetDevice.ImplLogicWidthToDevicePixel( ::abs((int)(lc_x1 - lc_x2)) );
    6317             : 
    6318           0 :             Point aTempPos = rTargetDevice.LogicToPixel( aPos );
    6319           0 :             nMnemonicX = rTargetDevice.GetOutOffXPixel() + aTempPos.X() + rTargetDevice.ImplLogicWidthToDevicePixel( std::min(lc_x1, lc_x2) );
    6320           0 :             nMnemonicY = rTargetDevice.GetOutOffYPixel() + aTempPos.Y() + rTargetDevice.ImplLogicWidthToDevicePixel( rTargetDevice.GetFontMetric().GetAscent() );
    6321             :         }
    6322             : 
    6323        3111 :         if ( nStyle & TEXT_DRAW_CLIP )
    6324             :         {
    6325           0 :             rTargetDevice.Push( PUSH_CLIPREGION );
    6326           0 :             rTargetDevice.IntersectClipRegion( rRect );
    6327           0 :             _rLayout.DrawText( aPos, aStr, 0, STRING_LEN, pVector, pDisplayText );
    6328           0 :             if ( bDrawMnemonics )
    6329             :             {
    6330           0 :                 if ( nMnemonicPos != STRING_NOTFOUND )
    6331           0 :                     rTargetDevice.ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
    6332             :             }
    6333           0 :             rTargetDevice.Pop();
    6334             :         }
    6335             :         else
    6336             :         {
    6337        3111 :             _rLayout.DrawText( aPos, aStr, 0, STRING_LEN, pVector, pDisplayText );
    6338        3111 :             if ( bDrawMnemonics )
    6339             :             {
    6340        3111 :                 if ( nMnemonicPos != STRING_NOTFOUND )
    6341           0 :                     rTargetDevice.ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
    6342             :             }
    6343             :         }
    6344             :     }
    6345             : 
    6346        4045 :     if ( nStyle & TEXT_DRAW_DISABLE && !pVector )
    6347             :     {
    6348         656 :         rTargetDevice.SetTextColor( aOldTextColor );
    6349         656 :         if ( bRestoreFillColor )
    6350           0 :             rTargetDevice.SetTextFillColor( aOldTextFillColor );
    6351        4045 :     }
    6352             : }
    6353             : 
    6354           0 : void OutputDevice::AddTextRectActions( const Rectangle& rRect,
    6355             :                                        const String&    rOrigStr,
    6356             :                                        sal_uInt16           nStyle,
    6357             :                                        GDIMetaFile&     rMtf )
    6358             : {
    6359             :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    6360             : 
    6361           0 :     if ( !rOrigStr.Len() || rRect.IsEmpty() )
    6362           0 :         return;
    6363             : 
    6364             :     // we need a graphics
    6365           0 :     if( !mpGraphics && !ImplGetGraphics() )
    6366           0 :         return;
    6367           0 :     if( mbInitClipRegion )
    6368           0 :         ImplInitClipRegion();
    6369             : 
    6370             :     // temporarily swap in passed mtf for action generation, and
    6371             :     // disable output generation.
    6372           0 :     const sal_Bool bOutputEnabled( IsOutputEnabled() );
    6373           0 :     GDIMetaFile* pMtf = mpMetaFile;
    6374             : 
    6375           0 :     mpMetaFile = &rMtf;
    6376           0 :     EnableOutput( sal_False );
    6377             : 
    6378             :     // #i47157# Factored out to ImplDrawTextRect(), to be shared
    6379             :     // between us and DrawText()
    6380           0 :     DefaultTextLayout aLayout( *this );
    6381           0 :     ImplDrawText( *this, rRect, rOrigStr, nStyle, NULL, NULL, aLayout );
    6382             : 
    6383             :     // and restore again
    6384           0 :     EnableOutput( bOutputEnabled );
    6385           0 :     mpMetaFile = pMtf;
    6386             : }
    6387             : 
    6388        5915 : void OutputDevice::DrawText( const Rectangle& rRect, const String& rOrigStr, sal_uInt16 nStyle,
    6389             :                              MetricVector* pVector, OUString* pDisplayText,
    6390             :                              ::vcl::ITextLayout* _pTextLayout )
    6391             : {
    6392        5915 :     if( mpOutDevData && mpOutDevData->mpRecordLayout )
    6393             :     {
    6394           0 :         pVector = &mpOutDevData->mpRecordLayout->m_aUnicodeBoundRects;
    6395           0 :         pDisplayText = &mpOutDevData->mpRecordLayout->m_aDisplayText;
    6396             :     }
    6397             : 
    6398             :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    6399             : 
    6400        5915 :     bool bDecomposeTextRectAction = ( _pTextLayout != NULL ) && _pTextLayout->DecomposeTextRectAction();
    6401        5915 :     if ( mpMetaFile && !bDecomposeTextRectAction )
    6402         653 :         mpMetaFile->AddAction( new MetaTextRectAction( rRect, rOrigStr, nStyle ) );
    6403             : 
    6404        5915 :     if ( ( !IsDeviceOutputNecessary() && !pVector && !bDecomposeTextRectAction ) || !rOrigStr.Len() || rRect.IsEmpty() )
    6405        3324 :         return;
    6406             : 
    6407             :     // we need a graphics
    6408        4461 :     if( !mpGraphics && !ImplGetGraphics() )
    6409           0 :         return;
    6410        4461 :     if( mbInitClipRegion )
    6411         316 :         ImplInitClipRegion();
    6412        4461 :     if( mbOutputClipped && !bDecomposeTextRectAction )
    6413         416 :         return;
    6414             : 
    6415             :     // temporarily disable mtf action generation (ImplDrawText _does_
    6416             :     // create META_TEXT_ACTIONs otherwise)
    6417        4045 :     GDIMetaFile* pMtf = mpMetaFile;
    6418        4045 :     if ( !bDecomposeTextRectAction )
    6419        3855 :         mpMetaFile = NULL;
    6420             : 
    6421             :     // #i47157# Factored out to ImplDrawText(), to be used also
    6422             :     // from AddTextRectActions()
    6423        4045 :     DefaultTextLayout aDefaultLayout( *this );
    6424        4045 :     ImplDrawText( *this, rRect, rOrigStr, nStyle, pVector, pDisplayText, _pTextLayout ? *_pTextLayout : aDefaultLayout );
    6425             : 
    6426             :     // and enable again
    6427        4045 :     mpMetaFile = pMtf;
    6428             : 
    6429        4045 :     if( mpAlphaVDev )
    6430         413 :         mpAlphaVDev->DrawText( rRect, rOrigStr, nStyle, pVector, pDisplayText );
    6431             : }
    6432             : 
    6433        1225 : Rectangle OutputDevice::GetTextRect( const Rectangle& rRect,
    6434             :                                      const XubString& rStr, sal_uInt16 nStyle,
    6435             :                                      TextRectInfo* pInfo,
    6436             :                                      const ::vcl::ITextLayout* _pTextLayout ) const
    6437             : {
    6438             :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    6439             : 
    6440        1225 :     Rectangle           aRect = rRect;
    6441             :     xub_StrLen          nLines;
    6442        1225 :     long                nWidth = rRect.GetWidth();
    6443             :     long                nMaxWidth;
    6444        1225 :     long                nTextHeight = GetTextHeight();
    6445             : 
    6446        1225 :     String aStr = rStr;
    6447        1225 :     if ( nStyle & TEXT_DRAW_MNEMONIC )
    6448         738 :         aStr = GetNonMnemonicString( aStr );
    6449             : 
    6450        1225 :     if ( nStyle & TEXT_DRAW_MULTILINE )
    6451             :     {
    6452         504 :         ImplMultiTextLineInfo   aMultiLineInfo;
    6453             :         ImplTextLineInfo*       pLineInfo;
    6454             :         xub_StrLen              nFormatLines;
    6455             :         xub_StrLen              i;
    6456             : 
    6457         504 :         nMaxWidth = 0;
    6458        1008 :         DefaultTextLayout aDefaultLayout( *const_cast< OutputDevice* >( this ) );
    6459         504 :         ImplGetTextLines( aMultiLineInfo, nWidth, aStr, nStyle, _pTextLayout ? *_pTextLayout : aDefaultLayout );
    6460         504 :         nFormatLines = aMultiLineInfo.Count();
    6461         504 :         if ( !nTextHeight )
    6462           0 :             nTextHeight = 1;
    6463         504 :         nLines = (sal_uInt16)(aRect.GetHeight()/nTextHeight);
    6464         504 :         if ( pInfo )
    6465           0 :             pInfo->mnLineCount = nFormatLines;
    6466         504 :         if ( !nLines )
    6467           4 :             nLines = 1;
    6468         504 :         if ( nFormatLines <= nLines )
    6469         504 :             nLines = nFormatLines;
    6470             :         else
    6471             :         {
    6472           0 :             if ( !(nStyle & TEXT_DRAW_ENDELLIPSIS) )
    6473           0 :                 nLines = nFormatLines;
    6474             :             else
    6475             :             {
    6476           0 :                 if ( pInfo )
    6477           0 :                     pInfo->mbEllipsis = sal_True;
    6478           0 :                 nMaxWidth = nWidth;
    6479             :             }
    6480             :         }
    6481         504 :         if ( pInfo )
    6482             :         {
    6483           0 :             bool bMaxWidth = nMaxWidth == 0;
    6484           0 :             pInfo->mnMaxWidth = 0;
    6485           0 :             for ( i = 0; i < nLines; i++ )
    6486             :             {
    6487           0 :                 pLineInfo = aMultiLineInfo.GetLine( i );
    6488           0 :                 if ( bMaxWidth && (pLineInfo->GetWidth() > nMaxWidth) )
    6489           0 :                     nMaxWidth = pLineInfo->GetWidth();
    6490           0 :                 if ( pLineInfo->GetWidth() > pInfo->mnMaxWidth )
    6491           0 :                     pInfo->mnMaxWidth = pLineInfo->GetWidth();
    6492             :             }
    6493             :         }
    6494         504 :         else if ( !nMaxWidth )
    6495             :         {
    6496         888 :             for ( i = 0; i < nLines; i++ )
    6497             :             {
    6498         384 :                 pLineInfo = aMultiLineInfo.GetLine( i );
    6499         384 :                 if ( pLineInfo->GetWidth() > nMaxWidth )
    6500         383 :                     nMaxWidth = pLineInfo->GetWidth();
    6501             :             }
    6502         504 :         }
    6503             :     }
    6504             :     else
    6505             :     {
    6506         721 :         nLines      = 1;
    6507         721 :         nMaxWidth   = _pTextLayout ? _pTextLayout->GetTextWidth( aStr, 0, aStr.Len() ) : GetTextWidth( aStr );
    6508             : 
    6509         721 :         if ( pInfo )
    6510             :         {
    6511           0 :             pInfo->mnLineCount  = 1;
    6512           0 :             pInfo->mnMaxWidth   = nMaxWidth;
    6513             :         }
    6514             : 
    6515         721 :         if ( (nMaxWidth > nWidth) && (nStyle & TEXT_DRAW_ELLIPSIS) )
    6516             :         {
    6517           0 :             if ( pInfo )
    6518           0 :                 pInfo->mbEllipsis = sal_True;
    6519           0 :             nMaxWidth = nWidth;
    6520             :         }
    6521             :     }
    6522             : 
    6523        1225 :     if ( nStyle & TEXT_DRAW_RIGHT )
    6524           0 :         aRect.Left() = aRect.Right()-nMaxWidth+1;
    6525        1225 :     else if ( nStyle & TEXT_DRAW_CENTER )
    6526             :     {
    6527         175 :         aRect.Left() += (nWidth-nMaxWidth)/2;
    6528         175 :         aRect.Right() = aRect.Left()+nMaxWidth-1;
    6529             :     }
    6530             :     else
    6531        1050 :         aRect.Right() = aRect.Left()+nMaxWidth-1;
    6532             : 
    6533        1225 :     if ( nStyle & TEXT_DRAW_BOTTOM )
    6534           0 :         aRect.Top() = aRect.Bottom()-(nTextHeight*nLines)+1;
    6535        1225 :     else if ( nStyle & TEXT_DRAW_VCENTER )
    6536             :     {
    6537         495 :         aRect.Top()   += (aRect.GetHeight()-(nTextHeight*nLines))/2;
    6538         495 :         aRect.Bottom() = aRect.Top()+(nTextHeight*nLines)-1;
    6539             :     }
    6540             :     else
    6541         730 :         aRect.Bottom() = aRect.Top()+(nTextHeight*nLines)-1;
    6542             : 
    6543             :     // #99188# get rid of rounding problems when using this rect later
    6544        1225 :     if (nStyle & TEXT_DRAW_RIGHT)
    6545           0 :         aRect.Left()--;
    6546             :     else
    6547        1225 :         aRect.Right()++;
    6548        1225 :     return aRect;
    6549             : }
    6550             : 
    6551           0 : static bool ImplIsCharIn( sal_Unicode c, const sal_Char* pStr )
    6552             : {
    6553           0 :     while ( *pStr )
    6554             :     {
    6555           0 :         if ( *pStr == c )
    6556           0 :             return true;
    6557           0 :         pStr++;
    6558             :     }
    6559             : 
    6560           0 :     return false;
    6561             : }
    6562             : 
    6563        7171 : OUString OutputDevice::GetEllipsisString( const OUString& rOrigStr, long nMaxWidth,
    6564             :                                         sal_uInt16 nStyle ) const
    6565             : {
    6566             :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    6567        7171 :     DefaultTextLayout aTextLayout( *const_cast< OutputDevice* >( this ) );
    6568        7171 :     return ImplGetEllipsisString( *this, rOrigStr, nMaxWidth, nStyle, aTextLayout );
    6569             : }
    6570             : 
    6571        7171 : OUString OutputDevice::ImplGetEllipsisString( const OutputDevice& rTargetDevice, const OUString& rOrigStr, long nMaxWidth,
    6572             :                                                sal_uInt16 nStyle, const ::vcl::ITextLayout& _rLayout )
    6573             : {
    6574        7171 :     OUString aStr = rOrigStr;
    6575        7171 :     sal_Int32 nIndex = _rLayout.GetTextBreak( aStr, nMaxWidth, 0, aStr.getLength() );
    6576             : 
    6577        7171 :     if ( nIndex != STRING_LEN )
    6578             :     {
    6579           4 :         if( (nStyle & TEXT_DRAW_CENTERELLIPSIS) == TEXT_DRAW_CENTERELLIPSIS )
    6580             :         {
    6581           0 :             OUStringBuffer aTmpStr( aStr );
    6582           0 :             sal_Int32 nEraseChars = 4;
    6583           0 :             while( nEraseChars < aStr.getLength() && _rLayout.GetTextWidth( aTmpStr.toString(), 0, aTmpStr.getLength() ) > nMaxWidth )
    6584             :             {
    6585           0 :                 aTmpStr = OUStringBuffer(aStr);
    6586           0 :                 sal_Int32 i = (aTmpStr.getLength() - nEraseChars)/2;
    6587           0 :                 aTmpStr.remove(i, nEraseChars++);
    6588           0 :                 aTmpStr.insert(i, "...");
    6589             :             }
    6590           0 :             aStr = aTmpStr.makeStringAndClear();
    6591             :         }
    6592           4 :         else if ( nStyle & TEXT_DRAW_ENDELLIPSIS )
    6593             :         {
    6594           4 :             aStr = aStr.copy(0, nIndex);
    6595           4 :             if ( nIndex > 1 )
    6596             :             {
    6597           4 :                 aStr += "...";
    6598          14 :                 while ( !aStr.isEmpty() && (_rLayout.GetTextWidth( aStr, 0, aStr.getLength() ) > nMaxWidth) )
    6599             :                 {
    6600           6 :                     if ( (nIndex > 1) || (nIndex == aStr.getLength()) )
    6601           4 :                         nIndex--;
    6602           6 :                     aStr = aStr.replaceAt( nIndex, 1, "");
    6603             :                 }
    6604             :             }
    6605             : 
    6606           4 :             if ( aStr.isEmpty() && (nStyle & TEXT_DRAW_CLIP) )
    6607           0 :                 aStr += OUString(rOrigStr[ 0 ]);
    6608             :         }
    6609           0 :         else if ( nStyle & TEXT_DRAW_PATHELLIPSIS )
    6610             :         {
    6611           0 :             OUString aPath( rOrigStr );
    6612           0 :             OUString aAbbreviatedPath;
    6613           0 :             osl_abbreviateSystemPath( aPath.pData, &aAbbreviatedPath.pData, nIndex, NULL );
    6614           0 :             aStr = aAbbreviatedPath;
    6615             :         }
    6616           0 :         else if ( nStyle & TEXT_DRAW_NEWSELLIPSIS )
    6617             :         {
    6618             :             static sal_Char const   pSepChars[] = ".";
    6619             :             // Determine last section
    6620           0 :             sal_Int32 nLastContent = aStr.getLength();
    6621           0 :             while ( nLastContent )
    6622             :             {
    6623           0 :                 nLastContent--;
    6624           0 :                 if ( ImplIsCharIn( aStr[ nLastContent ], pSepChars ) )
    6625           0 :                     break;
    6626             :             }
    6627           0 :             while ( nLastContent &&
    6628           0 :                     ImplIsCharIn( aStr[ nLastContent-1 ], pSepChars ) )
    6629           0 :                 nLastContent--;
    6630             : 
    6631           0 :             OUString aLastStr = aStr.copy(nLastContent);
    6632           0 :             OUString aTempLastStr1( "..." );
    6633           0 :             aTempLastStr1 += aLastStr;
    6634           0 :             if ( _rLayout.GetTextWidth( aTempLastStr1, 0, aTempLastStr1.getLength() ) > nMaxWidth )
    6635           0 :                 aStr = OutputDevice::ImplGetEllipsisString( rTargetDevice, aStr, nMaxWidth, nStyle | TEXT_DRAW_ENDELLIPSIS, _rLayout );
    6636             :             else
    6637             :             {
    6638           0 :                 sal_Int32 nFirstContent = 0;
    6639           0 :                 while ( nFirstContent < nLastContent )
    6640             :                 {
    6641           0 :                     nFirstContent++;
    6642           0 :                     if ( ImplIsCharIn( aStr[ nFirstContent ], pSepChars ) )
    6643           0 :                         break;
    6644             :                 }
    6645           0 :                 while ( (nFirstContent < nLastContent) &&
    6646           0 :                         ImplIsCharIn( aStr[ nFirstContent ], pSepChars ) )
    6647           0 :                     nFirstContent++;
    6648             :                 // MEM continue here
    6649           0 :                 if ( nFirstContent >= nLastContent )
    6650           0 :                     aStr = OutputDevice::ImplGetEllipsisString( rTargetDevice, aStr, nMaxWidth, nStyle | TEXT_DRAW_ENDELLIPSIS, _rLayout );
    6651             :                 else
    6652             :                 {
    6653           0 :                     if ( nFirstContent > 4 )
    6654           0 :                         nFirstContent = 4;
    6655           0 :                     OUString aFirstStr = aStr.copy( 0, nFirstContent );
    6656           0 :                     aFirstStr += "...";
    6657           0 :                     OUString aTempStr = aFirstStr + aLastStr;
    6658           0 :                     if ( _rLayout.GetTextWidth( aTempStr, 0, aTempStr.getLength() ) > nMaxWidth )
    6659           0 :                         aStr = OutputDevice::ImplGetEllipsisString( rTargetDevice, aStr, nMaxWidth, nStyle | TEXT_DRAW_ENDELLIPSIS, _rLayout );
    6660             :                     else
    6661             :                     {
    6662           0 :                         do
    6663             :                         {
    6664           0 :                             aStr = aTempStr;
    6665           0 :                             if( nLastContent > aStr.getLength() )
    6666           0 :                                 nLastContent = aStr.getLength();
    6667           0 :                             while ( nFirstContent < nLastContent )
    6668             :                             {
    6669           0 :                                 nLastContent--;
    6670           0 :                                 if ( ImplIsCharIn( aStr[ nLastContent ], pSepChars ) )
    6671           0 :                                     break;
    6672             : 
    6673             :                             }
    6674           0 :                             while ( (nFirstContent < nLastContent) &&
    6675           0 :                                     ImplIsCharIn( aStr[ nLastContent-1 ], pSepChars ) )
    6676           0 :                                 nLastContent--;
    6677             : 
    6678           0 :                             if ( nFirstContent < nLastContent )
    6679             :                             {
    6680           0 :                                 OUString aTempLastStr = aStr.copy( nLastContent );
    6681           0 :                                 aTempStr = aFirstStr + aTempLastStr;
    6682             : 
    6683           0 :                                 if ( _rLayout.GetTextWidth( aTempStr, 0, aTempStr.getLength() ) > nMaxWidth )
    6684           0 :                                     break;
    6685             :                             }
    6686             :                         }
    6687             :                         while ( nFirstContent < nLastContent );
    6688           0 :                     }
    6689             :                 }
    6690           0 :             }
    6691             :         }
    6692             :     }
    6693             : 
    6694        7171 :     return aStr;
    6695             : }
    6696             : 
    6697        7448 : void OutputDevice::DrawCtrlText( const Point& rPos, const XubString& rStr,
    6698             :                                  xub_StrLen nIndex, xub_StrLen nLen,
    6699             :                                  sal_uInt16 nStyle, MetricVector* pVector, OUString* pDisplayText )
    6700             : {
    6701             :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    6702             : 
    6703        7448 :     if ( !IsDeviceOutputNecessary() || (nIndex >= rStr.Len()) )
    6704           0 :         return;
    6705             : 
    6706             :     // better get graphics here because ImplDrawMnemonicLine() will not
    6707             :     // we need a graphics
    6708        7448 :     if( !mpGraphics && !ImplGetGraphics() )
    6709           0 :         return;
    6710        7448 :     if( mbInitClipRegion )
    6711         978 :         ImplInitClipRegion();
    6712        7448 :     if ( mbOutputClipped )
    6713           0 :         return;
    6714             : 
    6715        7448 :     if( nIndex >= rStr.Len() )
    6716           0 :         return;
    6717        7448 :     if( (sal_uLong)nIndex+nLen >= rStr.Len() )
    6718        7448 :         nLen = rStr.Len() - nIndex;
    6719             : 
    6720        7448 :     XubString   aStr = rStr;
    6721        7448 :     xub_StrLen  nMnemonicPos = STRING_NOTFOUND;
    6722             : 
    6723        7448 :     long        nMnemonicX = 0;
    6724        7448 :     long        nMnemonicY = 0;
    6725        7448 :     long        nMnemonicWidth = 0;
    6726        7448 :     if ( (nStyle & TEXT_DRAW_MNEMONIC) && nLen > 1 )
    6727             :     {
    6728        7272 :         aStr = GetNonMnemonicString( aStr, nMnemonicPos );
    6729        7272 :         if ( nMnemonicPos != STRING_NOTFOUND )
    6730             :         {
    6731        7154 :             if( nMnemonicPos < nIndex )
    6732           0 :                 --nIndex;
    6733        7154 :             else if( nLen < STRING_LEN )
    6734             :             {
    6735        7154 :                 if( nMnemonicPos < (nIndex+nLen) )
    6736        7154 :                     --nLen;
    6737             :                 DBG_ASSERT( nMnemonicPos < (nIndex+nLen), "Mnemonic underline marker after last character" );
    6738             :             }
    6739        7154 :             bool bInvalidPos = false;
    6740             : 
    6741        7154 :             if( nMnemonicPos >= nLen )
    6742             :             {
    6743             :                 // #106952#
    6744             :                 // may occur in BiDi-Strings: the '~' is sometimes found behind the last char
    6745             :                 // due to some strange BiDi text editors
    6746             :                 // -> place the underline behind the string to indicate a failure
    6747           0 :                 bInvalidPos = true;
    6748           0 :                 nMnemonicPos = nLen-1;
    6749             :             }
    6750             : 
    6751        7154 :             sal_Int32* pCaretXArray = (sal_Int32*)alloca( 2 * sizeof(sal_Int32) * nLen );
    6752        7154 :             /*sal_Bool bRet =*/ GetCaretPositions( aStr, pCaretXArray, nIndex, nLen );
    6753        7154 :             long lc_x1 = pCaretXArray[ 2*(nMnemonicPos - nIndex) ];
    6754        7154 :             long lc_x2 = pCaretXArray[ 2*(nMnemonicPos - nIndex)+1 ];
    6755        7154 :             nMnemonicWidth = ::abs((int)(lc_x1 - lc_x2));
    6756             : 
    6757        7154 :             Point aTempPos( std::min(lc_x1,lc_x2), GetFontMetric().GetAscent() );
    6758        7154 :             if( bInvalidPos )  // #106952#, place behind the (last) character
    6759           0 :                 aTempPos = Point( std::max(lc_x1,lc_x2), GetFontMetric().GetAscent() );
    6760             : 
    6761        7154 :             aTempPos += rPos;
    6762        7154 :             aTempPos = LogicToPixel( aTempPos );
    6763        7154 :             nMnemonicX = mnOutOffX + aTempPos.X();
    6764        7154 :             nMnemonicY = mnOutOffY + aTempPos.Y();
    6765             :         }
    6766             :     }
    6767             : 
    6768        7448 :     if ( nStyle & TEXT_DRAW_DISABLE && ! pVector )
    6769             :     {
    6770          98 :         Color aOldTextColor;
    6771          98 :         Color aOldTextFillColor;
    6772             :         bool  bRestoreFillColor;
    6773          98 :         sal_Bool  bHighContrastBlack = sal_False;
    6774          98 :         sal_Bool  bHighContrastWhite = sal_False;
    6775          98 :         const StyleSettings& rStyleSettings( GetSettings().GetStyleSettings() );
    6776          98 :         if( rStyleSettings.GetHighContrastMode() )
    6777             :         {
    6778           0 :             if( IsBackground() )
    6779             :             {
    6780           0 :                 Wallpaper aWall = GetBackground();
    6781           0 :                 Color aCol = aWall.GetColor();
    6782           0 :                 bHighContrastBlack = aCol.IsDark();
    6783           0 :                 bHighContrastWhite = aCol.IsBright();
    6784             :             }
    6785             :         }
    6786             : 
    6787          98 :         aOldTextColor = GetTextColor();
    6788          98 :         if ( IsTextFillColor() )
    6789             :         {
    6790           0 :             bRestoreFillColor = true;
    6791           0 :             aOldTextFillColor = GetTextFillColor();
    6792             :         }
    6793             :         else
    6794          98 :             bRestoreFillColor = false;
    6795             : 
    6796          98 :         if( bHighContrastBlack )
    6797           0 :             SetTextColor( COL_GREEN );
    6798          98 :         else if( bHighContrastWhite )
    6799           0 :             SetTextColor( COL_LIGHTGREEN );
    6800             :         else
    6801          98 :             SetTextColor( GetSettings().GetStyleSettings().GetDisableColor() );
    6802             : 
    6803          98 :         DrawText( rPos, aStr, nIndex, nLen, pVector, pDisplayText );
    6804          98 :         if ( !(GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_NOMNEMONICS) && !pVector )
    6805             :         {
    6806          98 :             if ( nMnemonicPos != STRING_NOTFOUND )
    6807          74 :                 ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
    6808             :         }
    6809          98 :         SetTextColor( aOldTextColor );
    6810          98 :         if ( bRestoreFillColor )
    6811           0 :             SetTextFillColor( aOldTextFillColor );
    6812             :     }
    6813             :     else
    6814             :     {
    6815        7350 :         DrawText( rPos, aStr, nIndex, nLen, pVector, pDisplayText );
    6816        7350 :         if ( !(GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_NOMNEMONICS) && !pVector )
    6817             :         {
    6818        7325 :             if ( nMnemonicPos != STRING_NOTFOUND )
    6819        7055 :                 ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
    6820             :         }
    6821             :     }
    6822             : 
    6823        7448 :     if( mpAlphaVDev )
    6824           0 :         mpAlphaVDev->DrawCtrlText( rPos, rStr, nIndex, nLen, nStyle, pVector, pDisplayText );
    6825             : }
    6826             : 
    6827        7791 : long OutputDevice::GetCtrlTextWidth( const String& rStr,
    6828             :                                      xub_StrLen nIndex, xub_StrLen nLen,
    6829             :                                      sal_uInt16 nStyle ) const
    6830             : {
    6831             :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    6832             : 
    6833        7791 :     if ( nStyle & TEXT_DRAW_MNEMONIC )
    6834             :     {
    6835             :         xub_StrLen  nMnemonicPos;
    6836        7791 :         XubString   aStr = GetNonMnemonicString( rStr, nMnemonicPos );
    6837        7791 :         if ( nMnemonicPos != STRING_NOTFOUND )
    6838             :         {
    6839        6236 :             if ( nMnemonicPos < nIndex )
    6840           0 :                 nIndex--;
    6841        6236 :             else if ( (nLen < STRING_LEN) &&
    6842           0 :                       (nMnemonicPos >= nIndex) && (nMnemonicPos < (sal_uLong)(nIndex+nLen)) )
    6843           0 :                 nLen--;
    6844             :         }
    6845        7791 :         return GetTextWidth( aStr, nIndex, nLen );
    6846             :     }
    6847             :     else
    6848           0 :         return GetTextWidth( rStr, nIndex, nLen );
    6849             : }
    6850             : 
    6851       28490 : String OutputDevice::GetNonMnemonicString( const String& rStr, xub_StrLen& rMnemonicPos )
    6852             : {
    6853       28490 :     String   aStr    = rStr;
    6854       28490 :     xub_StrLen  nLen    = aStr.Len();
    6855       28490 :     xub_StrLen  i       = 0;
    6856             : 
    6857       28490 :     rMnemonicPos = STRING_NOTFOUND;
    6858      215038 :     while ( i < nLen )
    6859             :     {
    6860      158058 :         if ( aStr.GetChar( i ) == '~' )
    6861             :         {
    6862       20842 :             if ( aStr.GetChar( i+1 ) != '~' )
    6863             :             {
    6864       20842 :                 if ( rMnemonicPos == STRING_NOTFOUND )
    6865       20842 :                     rMnemonicPos = i;
    6866       20842 :                 aStr.Erase( i, 1 );
    6867       20842 :                 nLen--;
    6868             :             }
    6869             :             else
    6870             :             {
    6871           0 :                 aStr.Erase( i, 1 );
    6872           0 :                 nLen--;
    6873           0 :                 i++;
    6874             :             }
    6875             :         }
    6876             :         else
    6877      137216 :             i++;
    6878             :     }
    6879             : 
    6880       28490 :     return aStr;
    6881             : }
    6882             : 
    6883      371381 : int OutputDevice::GetDevFontCount() const
    6884             : {
    6885             :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    6886             : 
    6887      371381 :     if( !mpGetDevFontList )
    6888        1741 :         mpGetDevFontList = mpFontList->GetDevFontList();
    6889      371381 :     return mpGetDevFontList->Count();
    6890             : }
    6891             : 
    6892      368859 : FontInfo OutputDevice::GetDevFont( int nDevFontIndex ) const
    6893             : {
    6894             :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    6895             : 
    6896      368859 :     FontInfo aFontInfo;
    6897             : 
    6898      368859 :     ImplInitFontList();
    6899             : 
    6900      368859 :     int nCount = GetDevFontCount();
    6901      368859 :     if( nDevFontIndex < nCount )
    6902             :     {
    6903      368859 :         const PhysicalFontFace& rData = *mpGetDevFontList->Get( nDevFontIndex );
    6904      368859 :         aFontInfo.SetName( rData.GetFamilyName() );
    6905      368859 :         aFontInfo.SetStyleName( rData.GetStyleName() );
    6906      368859 :         aFontInfo.SetCharSet( rData.IsSymbolFont() ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UNICODE );
    6907      368859 :         aFontInfo.SetFamily( rData.GetFamilyType() );
    6908      368859 :         aFontInfo.SetPitch( rData.GetPitch() );
    6909      368859 :         aFontInfo.SetWeight( rData.GetWeight() );
    6910      368859 :         aFontInfo.SetItalic( rData.GetSlant() );
    6911      368859 :         aFontInfo.SetWidthType( rData.GetWidthType() );
    6912      368859 :         if( rData.IsScalable() )
    6913      368859 :             aFontInfo.mpImplMetric->mnMiscFlags |= ImplFontMetric::SCALABLE_FLAG;
    6914      368859 :         if( rData.mbDevice )
    6915        1674 :             aFontInfo.mpImplMetric->mnMiscFlags |= ImplFontMetric::DEVICE_FLAG;
    6916             :     }
    6917             : 
    6918      368859 :     return aFontInfo;
    6919             : }
    6920             : 
    6921           0 : sal_Bool OutputDevice::AddTempDevFont( const String& rFileURL, const String& rFontName )
    6922             : {
    6923             :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    6924             : 
    6925           0 :     ImplInitFontList();
    6926             : 
    6927           0 :     if( !mpGraphics && !ImplGetGraphics() )
    6928           0 :         return sal_False;
    6929             : 
    6930           0 :     bool bRC = mpGraphics->AddTempDevFont( mpFontList, rFileURL, rFontName );
    6931           0 :     if( !bRC )
    6932           0 :         return sal_False;
    6933             : 
    6934           0 :     if( mpAlphaVDev )
    6935           0 :         mpAlphaVDev->AddTempDevFont( rFileURL, rFontName );
    6936             : 
    6937           0 :     mpFontCache->Invalidate();
    6938           0 :     return sal_True;
    6939             : }
    6940             : 
    6941         777 : int OutputDevice::GetDevFontSizeCount( const Font& rFont ) const
    6942             : {
    6943             :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    6944             : 
    6945         777 :     delete mpGetDevSizeList;
    6946             : 
    6947         777 :     ImplInitFontList();
    6948         777 :     mpGetDevSizeList = mpFontList->GetDevSizeList( rFont.GetName() );
    6949         777 :     return mpGetDevSizeList->Count();
    6950             : }
    6951             : 
    6952           0 : Size OutputDevice::GetDevFontSize( const Font& rFont, int nSizeIndex ) const
    6953             : {
    6954             :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    6955             : 
    6956             :     // check range
    6957           0 :     int nCount = GetDevFontSizeCount( rFont );
    6958           0 :     if ( nSizeIndex >= nCount )
    6959           0 :         return Size();
    6960             : 
    6961             :     // when mapping is enabled round to .5 points
    6962           0 :     Size aSize( 0, mpGetDevSizeList->Get( nSizeIndex ) );
    6963           0 :     if ( mbMap )
    6964             :     {
    6965           0 :         aSize.Height() *= 10;
    6966           0 :         MapMode aMap( MAP_10TH_INCH, Point(), Fraction( 1, 72 ), Fraction( 1, 72 ) );
    6967           0 :         aSize = PixelToLogic( aSize, aMap );
    6968           0 :         aSize.Height() += 5;
    6969           0 :         aSize.Height() /= 10;
    6970           0 :         long nRound = aSize.Height() % 5;
    6971           0 :         if ( nRound >= 3 )
    6972           0 :             aSize.Height() += (5-nRound);
    6973             :         else
    6974           0 :             aSize.Height() -= nRound;
    6975           0 :         aSize.Height() *= 10;
    6976           0 :         aSize = LogicToPixel( aSize, aMap );
    6977           0 :         aSize = PixelToLogic( aSize );
    6978           0 :         aSize.Height() += 5;
    6979           0 :         aSize.Height() /= 10;
    6980             :     }
    6981           0 :     return aSize;
    6982             : }
    6983             : 
    6984          28 : sal_Bool OutputDevice::IsFontAvailable( const String& rFontName ) const
    6985             : {
    6986             :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    6987             : 
    6988          28 :     ImplDevFontListData* pFound = mpFontList->FindFontFamily( rFontName );
    6989          28 :     return (pFound != NULL);
    6990             : }
    6991             : 
    6992      552138 : FontMetric OutputDevice::GetFontMetric() const
    6993             : {
    6994             :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    6995             : 
    6996      552138 :     FontMetric aMetric;
    6997      552138 :     if( mbNewFont && !ImplNewFont() )
    6998           0 :         return aMetric;
    6999             : 
    7000      552138 :     ImplFontEntry*      pEntry = mpFontEntry;
    7001      552138 :     ImplFontMetricData* pMetric = &(pEntry->maMetric);
    7002             : 
    7003             :     // prepare metric
    7004      552138 :     aMetric.Font::operator=( maFont );
    7005             : 
    7006             :     // set aMetric with info from font
    7007      552138 :     aMetric.SetName( maFont.GetName() );
    7008      552138 :     aMetric.SetStyleName( pMetric->GetStyleName() );
    7009      552138 :     aMetric.SetSize( PixelToLogic( Size( pMetric->mnWidth, pMetric->mnAscent+pMetric->mnDescent-pMetric->mnIntLeading ) ) );
    7010      552138 :     aMetric.SetCharSet( pMetric->IsSymbolFont() ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UNICODE );
    7011      552138 :     aMetric.SetFamily( pMetric->GetFamilyType() );
    7012      552138 :     aMetric.SetPitch( pMetric->GetPitch() );
    7013      552138 :     aMetric.SetWeight( pMetric->GetWeight() );
    7014      552138 :     aMetric.SetItalic( pMetric->GetSlant() );
    7015      552138 :     aMetric.SetWidthType( pMetric->GetWidthType() );
    7016      552138 :     if ( pEntry->mnOwnOrientation )
    7017           0 :         aMetric.SetOrientation( pEntry->mnOwnOrientation );
    7018             :     else
    7019      552138 :         aMetric.SetOrientation( pMetric->mnOrientation );
    7020      552138 :     if( !pEntry->maMetric.mbKernableFont )
    7021        9508 :          aMetric.SetKerning( maFont.GetKerning() & ~KERNING_FONTSPECIFIC );
    7022             : 
    7023             :     // set remaining metric fields
    7024      552138 :     aMetric.mpImplMetric->mnMiscFlags   = 0;
    7025      552138 :     if( pMetric->mbDevice )
    7026      551633 :             aMetric.mpImplMetric->mnMiscFlags |= ImplFontMetric::DEVICE_FLAG;
    7027      552138 :     if( pMetric->mbScalableFont )
    7028      552138 :             aMetric.mpImplMetric->mnMiscFlags |= ImplFontMetric::SCALABLE_FLAG;
    7029      552138 :     aMetric.mpImplMetric->mnAscent      = ImplDevicePixelToLogicHeight( pMetric->mnAscent+mnEmphasisAscent );
    7030      552138 :     aMetric.mpImplMetric->mnDescent     = ImplDevicePixelToLogicHeight( pMetric->mnDescent+mnEmphasisDescent );
    7031      552138 :     aMetric.mpImplMetric->mnIntLeading  = ImplDevicePixelToLogicHeight( pMetric->mnIntLeading+mnEmphasisAscent );
    7032      552138 :     aMetric.mpImplMetric->mnExtLeading  = ImplDevicePixelToLogicHeight( pMetric->mnExtLeading );
    7033      552138 :     aMetric.mpImplMetric->mnLineHeight  = ImplDevicePixelToLogicHeight( pMetric->mnAscent+pMetric->mnDescent+mnEmphasisAscent+mnEmphasisDescent );
    7034      552138 :     aMetric.mpImplMetric->mnSlant       = ImplDevicePixelToLogicHeight( pMetric->mnSlant );
    7035             : 
    7036             : #ifdef UNX
    7037             :     // backwards compatible line metrics after fixing #i60945#
    7038     1104276 :     if( (meOutDevType == OUTDEV_VIRDEV)
    7039      552138 :     &&  static_cast<const VirtualDevice*>(this)->ForceZeroExtleadBug() )
    7040           0 :         aMetric.mpImplMetric->mnExtLeading = 0;
    7041             : #endif
    7042             : 
    7043      552138 :     return aMetric;
    7044             : }
    7045             : 
    7046           0 : FontMetric OutputDevice::GetFontMetric( const Font& rFont ) const
    7047             : {
    7048             :     // select font, query metrics, select original font again
    7049           0 :     Font aOldFont = GetFont();
    7050           0 :     const_cast<OutputDevice*>(this)->SetFont( rFont );
    7051           0 :     FontMetric aMetric( GetFontMetric() );
    7052           0 :     const_cast<OutputDevice*>(this)->SetFont( aOldFont );
    7053           0 :     return aMetric;
    7054             : }
    7055             : 
    7056             : /** OutputDevice::GetSysFontData
    7057             :  *
    7058             :  * @param nFallbacklevel Fallback font level (0 = best matching font)
    7059             :  *
    7060             :  * Retrieve detailed font information in platform independent structure
    7061             :  *
    7062             :  * @return SystemFontData
    7063             :  **/
    7064           0 : SystemFontData OutputDevice::GetSysFontData(int nFallbacklevel) const
    7065             : {
    7066           0 :     SystemFontData aSysFontData;
    7067           0 :     aSysFontData.nSize = sizeof(aSysFontData);
    7068             : 
    7069           0 :     if (!mpGraphics) ImplGetGraphics();
    7070           0 :     if (mpGraphics) aSysFontData = mpGraphics->GetSysFontData(nFallbacklevel);
    7071             : 
    7072           0 :     return aSysFontData;
    7073             : }
    7074             : 
    7075             : /** OutputDevice::GetSysTextLayoutData
    7076             :  *
    7077             :  * @param rStartPt Start point of the text
    7078             :  * @param rStr Text string that will be transformed into layout of glyphs
    7079             :  * @param nIndex Position in the string from where layout will be done
    7080             :  * @param nLen Length of the string
    7081             :  * @param pDXAry Custom layout adjustment data
    7082             :  *
    7083             :  * Export finalized glyph layout data as platform independent SystemTextLayoutData
    7084             :  * (see vcl/inc/vcl/sysdata.hxx)
    7085             :  *
    7086             :  * Only parameters rStartPt and rStr are mandatory, the rest is optional
    7087             :  * (default values will be used)
    7088             :  *
    7089             :  * @return SystemTextLayoutData
    7090             :  **/
    7091           0 : SystemTextLayoutData OutputDevice::GetSysTextLayoutData(const Point& rStartPt, const XubString& rStr, xub_StrLen nIndex, xub_StrLen nLen,
    7092             :                                                         const sal_Int32* pDXAry) const
    7093             : {
    7094             :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    7095             : 
    7096           0 :     SystemTextLayoutData aSysLayoutData;
    7097           0 :     aSysLayoutData.nSize = sizeof(aSysLayoutData);
    7098           0 :     aSysLayoutData.rGlyphData.reserve( 256 );
    7099           0 :     aSysLayoutData.orientation = 0;
    7100             : 
    7101           0 :     if ( mpMetaFile )
    7102             :     {
    7103           0 :         if (pDXAry)
    7104           0 :             mpMetaFile->AddAction( new MetaTextArrayAction( rStartPt, rStr, pDXAry, nIndex, nLen ) );
    7105             :         else
    7106           0 :             mpMetaFile->AddAction( new MetaTextAction( rStartPt, rStr, nIndex, nLen ) );
    7107             :     }
    7108             : 
    7109           0 :     if ( !IsDeviceOutputNecessary() ) return aSysLayoutData;
    7110             : 
    7111           0 :     SalLayout* pLayout = ImplLayout( rStr, nIndex, nLen, rStartPt, 0, pDXAry, true );
    7112             : 
    7113           0 :     if ( !pLayout ) return aSysLayoutData;
    7114             : 
    7115             :     // setup glyphs
    7116           0 :     Point aPos;
    7117             :     sal_GlyphId aGlyphId;
    7118           0 :     for( int nStart = 0; pLayout->GetNextGlyphs( 1, &aGlyphId, aPos, nStart ); )
    7119             :     {
    7120             :         // NOTE: Windows backend is producing unicode chars (ucs4), so on windows,
    7121             :         //       ETO_GLYPH_INDEX is unusable, unless extra glyph conversion is made.
    7122             : 
    7123             :         SystemGlyphData aGlyph;
    7124           0 :         aGlyph.index = static_cast<unsigned long> (aGlyphId & GF_IDXMASK);
    7125           0 :         aGlyph.x = aPos.X();
    7126           0 :         aGlyph.y = aPos.Y();
    7127           0 :         int nLevel = (aGlyphId & GF_FONTMASK) >> GF_FONTSHIFT;
    7128           0 :         aGlyph.fallbacklevel = nLevel < MAX_FALLBACK ? nLevel : 0;
    7129           0 :         aSysLayoutData.rGlyphData.push_back(aGlyph);
    7130             :     }
    7131             : 
    7132             :     // Get font data
    7133           0 :     aSysLayoutData.orientation = pLayout->GetOrientation();
    7134             : 
    7135           0 :     pLayout->Release();
    7136             : 
    7137           0 :     return aSysLayoutData;
    7138             : }
    7139             : 
    7140           0 : long OutputDevice::GetMinKashida() const
    7141             : {
    7142             :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    7143           0 :     if( mbNewFont && !ImplNewFont() )
    7144           0 :         return 0;
    7145             : 
    7146           0 :     ImplFontEntry*      pEntry = mpFontEntry;
    7147           0 :     ImplFontMetricData* pMetric = &(pEntry->maMetric);
    7148           0 :     return ImplDevicePixelToLogicWidth( pMetric->mnMinKashida );
    7149             : }
    7150             : 
    7151           0 : xub_StrLen OutputDevice::ValidateKashidas ( const String& rTxt,
    7152             :                                             xub_StrLen nIdx, xub_StrLen nLen,
    7153             :                                             xub_StrLen nKashCount,
    7154             :                                             const xub_StrLen* pKashidaPos,
    7155             :                                             xub_StrLen* pKashidaPosDropped ) const
    7156             : {
    7157             :    // do layout
    7158           0 :     SalLayout* pSalLayout = ImplLayout( rTxt, nIdx, nLen );
    7159           0 :     if( !pSalLayout )
    7160           0 :         return 0;
    7161           0 :     xub_StrLen nDropped = 0;
    7162           0 :     for( int i = 0; i < nKashCount; ++i )
    7163             :     {
    7164           0 :         if( !pSalLayout->IsKashidaPosValid( pKashidaPos[ i ] ))
    7165             :         {
    7166           0 :             pKashidaPosDropped[ nDropped ] = pKashidaPos [ i ];
    7167           0 :             ++nDropped;
    7168             :         }
    7169             :     }
    7170           0 :     pSalLayout->Release();
    7171           0 :     return nDropped;
    7172             : }
    7173             : 
    7174        2870 : sal_Bool OutputDevice::GetGlyphBoundRects( const Point& rOrigin, const String& rStr,
    7175             :     int nIndex, int nLen, int nBase, MetricVector& rVector )
    7176             : {
    7177             :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    7178             : 
    7179        2870 :     rVector.clear();
    7180             : 
    7181        2870 :     if( nLen == STRING_LEN )
    7182        2844 :         nLen = rStr.Len() - nIndex;
    7183             : 
    7184        2870 :     Rectangle aRect;
    7185       18517 :     for( int i = 0; i < nLen; i++ )
    7186             :     {
    7187       15647 :         if( !GetTextBoundRect( aRect, rStr, sal::static_int_cast<xub_StrLen>(nBase), sal::static_int_cast<xub_StrLen>(nIndex+i), 1 ) )
    7188           0 :             break;
    7189       15647 :         aRect.Move( rOrigin.X(), rOrigin.Y() );
    7190       15647 :         rVector.push_back( aRect );
    7191             :     }
    7192             : 
    7193        2870 :     return (nLen == (int)rVector.size());
    7194             : }
    7195             : 
    7196       75485 : sal_Bool OutputDevice::GetTextBoundRect( Rectangle& rRect,
    7197             :     const String& rStr, xub_StrLen nBase, xub_StrLen nIndex, xub_StrLen nLen,
    7198             :     sal_uLong nLayoutWidth, const sal_Int32* pDXAry ) const
    7199             : {
    7200             :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    7201             : 
    7202       75485 :     sal_Bool bRet = sal_False;
    7203       75485 :     rRect.SetEmpty();
    7204             : 
    7205       75485 :     SalLayout* pSalLayout = NULL;
    7206       75485 :     const Point aPoint;
    7207             :     // calculate offset when nBase!=nIndex
    7208       75485 :     long nXOffset = 0;
    7209       75485 :     if( nBase != nIndex )
    7210             :     {
    7211       14436 :         xub_StrLen nStart = std::min( nBase, nIndex );
    7212       14436 :         xub_StrLen nOfsLen = std::max( nBase, nIndex ) - nStart;
    7213       14436 :         pSalLayout = ImplLayout( rStr, nStart, nOfsLen, aPoint, nLayoutWidth, pDXAry );
    7214       14436 :         if( pSalLayout )
    7215             :         {
    7216       14436 :             nXOffset = pSalLayout->GetTextWidth();
    7217       14436 :             nXOffset /= pSalLayout->GetUnitsPerPixel();
    7218       14436 :             pSalLayout->Release();
    7219             :             // TODO: fix offset calculation for Bidi case
    7220       14436 :             if( nBase < nIndex)
    7221       14436 :                 nXOffset = -nXOffset;
    7222             :         }
    7223             :     }
    7224             : 
    7225       75485 :     pSalLayout = ImplLayout( rStr, nIndex, nLen, aPoint, nLayoutWidth, pDXAry );
    7226       75485 :     Rectangle aPixelRect;
    7227       75485 :     if( pSalLayout )
    7228             :     {
    7229       75485 :         bRet = pSalLayout->GetBoundRect( *mpGraphics, aPixelRect );
    7230             : 
    7231       75485 :         if( bRet )
    7232             :         {
    7233       75484 :             int nWidthFactor = pSalLayout->GetUnitsPerPixel();
    7234             : 
    7235       75484 :             if( nWidthFactor > 1 )
    7236             :             {
    7237           0 :                 double fFactor = 1.0 / nWidthFactor;
    7238           0 :                 aPixelRect.Left()
    7239           0 :                     = static_cast< long >(aPixelRect.Left() * fFactor);
    7240           0 :                 aPixelRect.Right()
    7241           0 :                     = static_cast< long >(aPixelRect.Right() * fFactor);
    7242           0 :                 aPixelRect.Top()
    7243           0 :                     = static_cast< long >(aPixelRect.Top() * fFactor);
    7244           0 :                 aPixelRect.Bottom()
    7245           0 :                     = static_cast< long >(aPixelRect.Bottom() * fFactor);
    7246             :             }
    7247             : 
    7248       75484 :             Point aRotatedOfs( mnTextOffX, mnTextOffY );
    7249       75484 :             aRotatedOfs -= pSalLayout->GetDrawPosition( Point( nXOffset, 0 ) );
    7250       75484 :             aPixelRect += aRotatedOfs;
    7251       75484 :             rRect = PixelToLogic( aPixelRect );
    7252       75484 :             if( mbMap )
    7253        5675 :                 rRect += Point( maMapRes.mnMapOfsX, maMapRes.mnMapOfsY );
    7254             :         }
    7255             : 
    7256       75485 :         pSalLayout->Release();
    7257             :     }
    7258             : 
    7259       75485 :     if( bRet || (OUTDEV_PRINTER == meOutDevType) || !mpFontEntry )
    7260       75484 :         return bRet;
    7261             : 
    7262             :     // fall back to bitmap method to get the bounding rectangle,
    7263             :     // so we need a monochrome virtual device with matching font
    7264           1 :     VirtualDevice aVDev( 1 );
    7265           2 :     Font aFont( GetFont() );
    7266           1 :     aFont.SetShadow( sal_False );
    7267           1 :     aFont.SetOutline( sal_False );
    7268           1 :     aFont.SetRelief( RELIEF_NONE );
    7269           1 :     aFont.SetOrientation( 0 );
    7270           1 :     aFont.SetSize( Size( mpFontEntry->maFontSelData.mnWidth, mpFontEntry->maFontSelData.mnHeight ) );
    7271           1 :     aVDev.SetFont( aFont );
    7272           1 :     aVDev.SetTextAlign( ALIGN_TOP );
    7273             : 
    7274             :     // layout the text on the virtual device
    7275           1 :     pSalLayout = aVDev.ImplLayout( rStr, nIndex, nLen, aPoint, nLayoutWidth, pDXAry );
    7276           1 :     if( !pSalLayout )
    7277           0 :         return false;
    7278             : 
    7279             :     // make the bitmap big enough
    7280             :     // TODO: use factors when it would get too big
    7281           1 :     long nWidth = pSalLayout->GetTextWidth();
    7282           1 :     long nHeight = mpFontEntry->mnLineHeight + mnEmphasisAscent + mnEmphasisDescent;
    7283           1 :     Point aOffset( nWidth/2, 8 );
    7284           1 :     Size aOutSize( nWidth + 2*aOffset.X(), nHeight + 2*aOffset.Y() );
    7285           1 :     if( !nWidth || !aVDev.SetOutputSizePixel( aOutSize ) )
    7286           0 :         return false;
    7287             : 
    7288             :     // draw text in black
    7289           1 :     pSalLayout->DrawBase() = aOffset;
    7290           1 :     aVDev.SetTextColor( Color( COL_BLACK ) );
    7291           1 :     aVDev.SetTextFillColor();
    7292           1 :     aVDev.ImplInitTextColor();
    7293           1 :     aVDev.ImplDrawText( *pSalLayout );
    7294           1 :     pSalLayout->Release();
    7295             : 
    7296             :     // find extents using the bitmap
    7297           2 :     Bitmap aBmp = aVDev.GetBitmap( Point(), aOutSize );
    7298           1 :     BitmapReadAccess* pAcc = aBmp.AcquireReadAccess();
    7299           1 :     if( !pAcc )
    7300           0 :         return sal_False;
    7301           2 :     const BitmapColor aBlack( pAcc->GetBestMatchingColor( Color( COL_BLACK ) ) );
    7302           1 :     const long nW = pAcc->Width();
    7303           1 :     const long nH = pAcc->Height();
    7304           1 :     long nLeft = 0;
    7305           1 :     long nRight = 0;
    7306             : 
    7307             :     // find top left point
    7308           1 :     long nTop = 0;
    7309        1782 :     for(; nTop < nH; ++nTop )
    7310             :     {
    7311     3130998 :         for( nLeft = 0; nLeft < nW; ++nLeft )
    7312     3129217 :             if( pAcc->GetPixel( nTop, nLeft ) == aBlack )
    7313           0 :                 break;
    7314        1781 :         if( nLeft < nW )
    7315           0 :             break;
    7316             :     }
    7317             : 
    7318             :     // find bottom right point
    7319           1 :     long nBottom = nH;
    7320           2 :     while( --nBottom >= nTop )
    7321             :     {
    7322           0 :         for( nRight = nW; --nRight >= 0; )
    7323           0 :             if( pAcc->GetPixel( nBottom, nRight ) == aBlack )
    7324           0 :                 break;
    7325           0 :         if( nRight >= 0 )
    7326           0 :             break;
    7327             :     }
    7328           1 :     if( nRight < nLeft )
    7329             :     {
    7330           1 :         long nX = nRight;
    7331           1 :         nRight = nLeft;
    7332           1 :         nLeft  = nX;
    7333             :     }
    7334             : 
    7335           1 :     for( long nY = nTop; nY <= nBottom; ++nY )
    7336             :     {
    7337             :         // find leftmost point
    7338             :         long nX;
    7339           0 :         for( nX = 0; nX < nLeft; ++nX )
    7340           0 :             if( pAcc->GetPixel( nY, nX ) == aBlack )
    7341           0 :                 break;
    7342           0 :         nLeft = nX;
    7343             : 
    7344             :         // find rightmost point
    7345           0 :         for( nX = nW; --nX > nRight; )
    7346           0 :             if( pAcc->GetPixel( nY, nX ) == aBlack )
    7347           0 :                 break;
    7348           0 :         nRight = nX;
    7349             :     }
    7350             : 
    7351           1 :     aBmp.ReleaseAccess( pAcc );
    7352             : 
    7353           1 :     if( nTop <= nBottom )
    7354             :     {
    7355           0 :         Size aSize( nRight - nLeft + 1, nBottom - nTop + 1 );
    7356           0 :         Point aTopLeft( nLeft, nTop );
    7357           0 :         aTopLeft -= aOffset;
    7358             :         // adjust to text alignment
    7359           0 :         aTopLeft.Y()+= mnTextOffY - (mpFontEntry->maMetric.mnAscent + mnEmphasisAscent);
    7360             :         // convert to logical coordinates
    7361           0 :         aSize = PixelToLogic( aSize );
    7362           0 :         aTopLeft.X() = ImplDevicePixelToLogicWidth( aTopLeft.X() );
    7363           0 :         aTopLeft.Y() = ImplDevicePixelToLogicHeight( aTopLeft.Y() );
    7364           0 :         rRect = Rectangle( aTopLeft, aSize );
    7365           0 :         return sal_True;
    7366             :     }
    7367             : 
    7368           2 :     return sal_False;
    7369             : }
    7370             : 
    7371         416 : sal_Bool OutputDevice::GetTextOutlines( ::basegfx::B2DPolyPolygonVector& rVector,
    7372             :     const String& rStr, xub_StrLen nBase, xub_StrLen nIndex, xub_StrLen nLen,
    7373             :     sal_Bool bOptimize, sal_uLong nTWidth, const sal_Int32* pDXArray ) const
    7374             : {
    7375             :     // the fonts need to be initialized
    7376         416 :     if( mbNewFont )
    7377         305 :         ImplNewFont();
    7378         416 :     if( mbInitFont )
    7379          94 :         ImplInitFont();
    7380         416 :     if( !mpFontEntry )
    7381           0 :         return sal_False;
    7382             : 
    7383         416 :     sal_Bool bRet = sal_False;
    7384         416 :     rVector.clear();
    7385         416 :     if( nLen == STRING_LEN )
    7386         125 :         nLen = rStr.Len() - nIndex;
    7387         416 :     rVector.reserve( nLen );
    7388             : 
    7389             :     // we want to get the Rectangle in logical units, so to
    7390             :     // avoid rounding errors we just size the font in logical units
    7391         416 :     sal_Bool bOldMap = mbMap;
    7392         416 :     if( bOldMap )
    7393             :     {
    7394         125 :         const_cast<OutputDevice&>(*this).mbMap = sal_False;
    7395         125 :         const_cast<OutputDevice&>(*this).mbNewFont = sal_True;
    7396             :     }
    7397             : 
    7398         416 :     SalLayout* pSalLayout = NULL;
    7399             : 
    7400             :     // calculate offset when nBase!=nIndex
    7401         416 :     long nXOffset = 0;
    7402         416 :     if( nBase != nIndex )
    7403             :     {
    7404           0 :         xub_StrLen nStart = std::min( nBase, nIndex );
    7405           0 :         xub_StrLen nOfsLen = std::max( nBase, nIndex ) - nStart;
    7406           0 :         pSalLayout = ImplLayout( rStr, nStart, nOfsLen, Point(0,0), nTWidth, pDXArray );
    7407           0 :         if( pSalLayout )
    7408             :         {
    7409           0 :             nXOffset = pSalLayout->GetTextWidth();
    7410           0 :             pSalLayout->Release();
    7411             :             // TODO: fix offset calculation for Bidi case
    7412           0 :             if( nBase > nIndex)
    7413           0 :                 nXOffset = -nXOffset;
    7414             :         }
    7415             :     }
    7416             : 
    7417         416 :     pSalLayout = ImplLayout( rStr, nIndex, nLen, Point(0,0), nTWidth, pDXArray );
    7418         416 :     if( pSalLayout )
    7419             :     {
    7420         416 :         bRet = pSalLayout->GetOutline( *mpGraphics, rVector );
    7421         416 :         if( bRet )
    7422             :         {
    7423             :             // transform polygon to pixel units
    7424         414 :             ::basegfx::B2DHomMatrix aMatrix;
    7425             : 
    7426         414 :             int nWidthFactor = pSalLayout->GetUnitsPerPixel();
    7427         414 :             if( nXOffset | mnTextOffX | mnTextOffY )
    7428             :             {
    7429           0 :                 Point aRotatedOfs( mnTextOffX*nWidthFactor, mnTextOffY*nWidthFactor );
    7430           0 :                 aRotatedOfs -= pSalLayout->GetDrawPosition( Point( nXOffset, 0 ) );
    7431           0 :                 aMatrix.translate( aRotatedOfs.X(), aRotatedOfs.Y() );
    7432             :             }
    7433             : 
    7434         414 :             if( nWidthFactor > 1 )
    7435             :             {
    7436           0 :                 double fFactor = 1.0 / nWidthFactor;
    7437           0 :                 aMatrix.scale( fFactor, fFactor );
    7438             :             }
    7439             : 
    7440         414 :             if( !aMatrix.isIdentity() )
    7441             :             {
    7442           0 :                 ::basegfx::B2DPolyPolygonVector::iterator aIt = rVector.begin();
    7443           0 :                 for(; aIt != rVector.end(); ++aIt )
    7444           0 :                     (*aIt).transform( aMatrix );
    7445         414 :             }
    7446             :         }
    7447             : 
    7448         416 :         pSalLayout->Release();
    7449             :     }
    7450             : 
    7451         416 :     if( bOldMap )
    7452             :     {
    7453             :         // restore original font size and map mode
    7454         125 :         const_cast<OutputDevice&>(*this).mbMap = bOldMap;
    7455         125 :         const_cast<OutputDevice&>(*this).mbNewFont = sal_True;
    7456             :     }
    7457             : 
    7458         416 :     if( bRet || (OUTDEV_PRINTER == meOutDevType) || !mpFontEntry )
    7459         414 :         return bRet;
    7460             : 
    7461             :     // fall back to bitmap conversion
    7462             :     // Here, we can savely assume that the mapping between characters and glyphs
    7463             :     // is one-to-one. This is most probably valid for the old bitmap fonts.
    7464             :     // fall back to bitmap method to get the bounding rectangle,
    7465             :     // so we need a monochrome virtual device with matching font
    7466           2 :     pSalLayout = ImplLayout( rStr, nIndex, nLen, Point(0,0), nTWidth, pDXArray );
    7467           2 :     if (pSalLayout == 0)
    7468           0 :         return false;
    7469           2 :     long nOrgWidth = pSalLayout->GetTextWidth();
    7470           2 :     long nOrgHeight = mpFontEntry->mnLineHeight + mnEmphasisAscent
    7471           2 :         + mnEmphasisDescent;
    7472           2 :     pSalLayout->Release();
    7473             : 
    7474           2 :     VirtualDevice aVDev(1);
    7475             : 
    7476           4 :     Font aFont(GetFont());
    7477           2 :     aFont.SetShadow(false);
    7478           2 :     aFont.SetOutline(false);
    7479           2 :     aFont.SetRelief(RELIEF_NONE);
    7480           2 :     aFont.SetOrientation(0);
    7481           2 :     if( bOptimize )
    7482             :     {
    7483           2 :         aFont.SetSize( Size( 0, GLYPH_FONT_HEIGHT ) );
    7484           2 :         aVDev.SetMapMode( MAP_PIXEL );
    7485             :     }
    7486           2 :     aVDev.SetFont( aFont );
    7487           2 :     aVDev.SetTextAlign( ALIGN_TOP );
    7488           2 :     aVDev.SetTextColor( Color(COL_BLACK) );
    7489           2 :     aVDev.SetTextFillColor();
    7490             : 
    7491           2 :     pSalLayout = aVDev.ImplLayout( rStr, nIndex, nLen, Point(0,0), nTWidth, pDXArray );
    7492           2 :     if (pSalLayout == 0)
    7493           0 :         return false;
    7494           2 :     long nWidth = pSalLayout->GetTextWidth();
    7495           2 :     long nHeight = ((OutputDevice*)&aVDev)->mpFontEntry->mnLineHeight + ((OutputDevice*)&aVDev)->mnEmphasisAscent
    7496           2 :         + ((OutputDevice*)&aVDev)->mnEmphasisDescent;
    7497           2 :     pSalLayout->Release();
    7498             : 
    7499           2 :     if( !nWidth || !nHeight )
    7500           0 :         return sal_True;
    7501           2 :     double fScaleX = static_cast< double >(nOrgWidth) / nWidth;
    7502           2 :     double fScaleY = static_cast< double >(nOrgHeight) / nHeight;
    7503             : 
    7504             :     // calculate offset when nBase!=nIndex
    7505             :     // TODO: fix offset calculation for Bidi case
    7506           2 :     nXOffset = 0;
    7507           2 :     if( nBase != nIndex )
    7508             :     {
    7509           0 :         xub_StrLen nStart  = ((nBase < nIndex) ? nBase : nIndex);
    7510           0 :         xub_StrLen nLength = ((nBase > nIndex) ? nBase : nIndex) - nStart;
    7511           0 :         pSalLayout = aVDev.ImplLayout( rStr, nStart, nLength, Point(0,0), nTWidth, pDXArray );
    7512           0 :         if( pSalLayout )
    7513             :         {
    7514           0 :             nXOffset = pSalLayout->GetTextWidth();
    7515           0 :             pSalLayout->Release();
    7516           0 :             if( nBase > nIndex)
    7517           0 :                 nXOffset = -nXOffset;
    7518             :         }
    7519             :     }
    7520             : 
    7521           2 :     bRet = true;
    7522           2 :     bool bRTL = false;
    7523           4 :     OUString aStr( rStr ); // prepare for e.g. localized digits
    7524           2 :     sal_Int32 nIndex2 = nIndex; // only needed until nIndex is sal_Int32
    7525           2 :     sal_Int32 nLen2 = nLen; // only needed until nLen is sal_Int32
    7526           4 :     ImplLayoutArgs aLayoutArgs = ImplPrepareLayoutArgs( aStr, nIndex2, nLen2, 0, NULL );
    7527           6 :     for( int nCharPos = -1; aLayoutArgs.GetNextPos( &nCharPos, &bRTL);)
    7528             :     {
    7529           2 :         bool bSuccess = false;
    7530             : 
    7531             :         // draw character into virtual device
    7532           2 :         pSalLayout = aVDev.ImplLayout( rStr, static_cast< xub_StrLen >(nCharPos), 1, Point(0,0), nTWidth, pDXArray );
    7533           2 :         if (pSalLayout == 0)
    7534           0 :             return false;
    7535           2 :         long nCharWidth = pSalLayout->GetTextWidth();
    7536             : 
    7537           2 :         Point aOffset(nCharWidth / 2, 8);
    7538           2 :         Size aSize(nCharWidth + 2 * aOffset.X(), nHeight + 2 * aOffset.Y());
    7539           2 :         bSuccess = (bool)aVDev.SetOutputSizePixel(aSize);
    7540           2 :         if( bSuccess )
    7541             :         {
    7542             :             // draw glyph into virtual device
    7543           2 :             aVDev.Erase();
    7544           2 :             pSalLayout->DrawBase() += aOffset;
    7545           2 :             pSalLayout->DrawBase() += Point( ((OutputDevice*)&aVDev)->mnTextOffX, ((OutputDevice*)&aVDev)->mnTextOffY );
    7546           2 :             pSalLayout->DrawText( *((OutputDevice*)&aVDev)->mpGraphics );
    7547           2 :             pSalLayout->Release();
    7548             : 
    7549             :             // convert character image into outline
    7550           2 :             Bitmap aBmp( aVDev.GetBitmap(Point(0, 0), aSize));
    7551             : 
    7552           4 :             PolyPolygon aPolyPoly;
    7553           2 :             bool bVectorized = aBmp.Vectorize(aPolyPoly, BMP_VECTORIZE_OUTER | BMP_VECTORIZE_REDUCE_EDGES);
    7554           2 :             if( !bVectorized )
    7555           0 :                 bSuccess = false;
    7556             :             else
    7557             :             {
    7558             :                 // convert units to logical width
    7559           2 :                 for (sal_uInt16 j = 0; j < aPolyPoly.Count(); ++j)
    7560             :                 {
    7561           0 :                     Polygon& rPoly = aPolyPoly[j];
    7562           0 :                     for (sal_uInt16 k = 0; k < rPoly.GetSize(); ++k)
    7563             :                     {
    7564           0 :                         Point& rPt = rPoly[k];
    7565           0 :                         rPt -= aOffset;
    7566           0 :                         int nPixelX = rPt.X() - ((OutputDevice&)aVDev).mnTextOffX + nXOffset;
    7567           0 :                         int nPixelY = rPt.Y() - ((OutputDevice&)aVDev).mnTextOffY;
    7568           0 :                         rPt.X() = ImplDevicePixelToLogicWidth( nPixelX );
    7569           0 :                         rPt.Y() = ImplDevicePixelToLogicHeight( nPixelY );
    7570             :                     }
    7571             :                 }
    7572             : 
    7573             : 
    7574             :                 // ignore "empty" glyphs:
    7575           2 :                 if( aPolyPoly.Count() > 0 )
    7576             :                 {
    7577             :                     // convert  to B2DPolyPolygon
    7578             :                     // TODO: get rid of intermediate tool's PolyPolygon
    7579           0 :                     ::basegfx::B2DPolyPolygon aB2DPolyPoly = aPolyPoly.getB2DPolyPolygon();
    7580           0 :                     ::basegfx::B2DHomMatrix aMatrix;
    7581           0 :                     aMatrix.scale( fScaleX, fScaleY );
    7582           0 :                     int nAngle = GetFont().GetOrientation();
    7583           0 :                     if( nAngle )
    7584           0 :                         aMatrix.rotate( nAngle * F_PI1800 );
    7585           0 :                     aB2DPolyPoly.transform( aMatrix );
    7586           0 :                     rVector.push_back( aB2DPolyPoly );
    7587             :                 }
    7588           2 :             }
    7589             :         }
    7590             : 
    7591           2 :         nXOffset += nCharWidth;
    7592           2 :         bRet = bRet && bSuccess;
    7593             :     }
    7594             : 
    7595           4 :     return bRet;
    7596             : }
    7597             : 
    7598         125 : sal_Bool OutputDevice::GetTextOutlines( PolyPolyVector& rResultVector,
    7599             :     const String& rStr, xub_StrLen nBase, xub_StrLen nIndex,
    7600             :     xub_StrLen nLen, sal_Bool bOptimize, sal_uLong nTWidth, const sal_Int32* pDXArray ) const
    7601             : {
    7602         125 :     rResultVector.clear();
    7603             : 
    7604             :     // get the basegfx polypolygon vector
    7605         125 :     ::basegfx::B2DPolyPolygonVector aB2DPolyPolyVector;
    7606         125 :     if( !GetTextOutlines( aB2DPolyPolyVector, rStr, nBase, nIndex, nLen,
    7607         125 :                          bOptimize, nTWidth, pDXArray ) )
    7608           0 :         return sal_False;
    7609             : 
    7610             :     // convert to a tool polypolygon vector
    7611         125 :     rResultVector.reserve( aB2DPolyPolyVector.size() );
    7612         125 :     ::basegfx::B2DPolyPolygonVector::const_iterator aIt = aB2DPolyPolyVector.begin();
    7613         248 :     for(; aIt != aB2DPolyPolyVector.end(); ++aIt )
    7614         123 :         rResultVector.push_back(PolyPolygon(*aIt)); // #i76339#
    7615             : 
    7616         125 :     return sal_True;
    7617             : }
    7618             : 
    7619           0 : sal_Bool OutputDevice::GetTextOutline( PolyPolygon& rPolyPoly,
    7620             :     const String& rStr, xub_StrLen nBase, xub_StrLen nIndex, xub_StrLen nLen,
    7621             :     sal_Bool bOptimize, sal_uLong nTWidth, const sal_Int32* pDXArray ) const
    7622             : {
    7623           0 :     rPolyPoly.Clear();
    7624             : 
    7625             :     // get the basegfx polypolygon vector
    7626           0 :     ::basegfx::B2DPolyPolygonVector aB2DPolyPolyVector;
    7627           0 :     if( !GetTextOutlines( aB2DPolyPolyVector, rStr, nBase, nIndex, nLen,
    7628           0 :                          bOptimize, nTWidth, pDXArray ) )
    7629           0 :         return sal_False;
    7630             : 
    7631             :     // convert and merge into a tool polypolygon
    7632           0 :     ::basegfx::B2DPolyPolygonVector::const_iterator aIt = aB2DPolyPolyVector.begin();
    7633           0 :     for(; aIt != aB2DPolyPolyVector.end(); ++aIt )
    7634           0 :         for( unsigned int i = 0; i < aIt->count(); ++i )
    7635           0 :             rPolyPoly.Insert(Polygon((*aIt).getB2DPolygon( i ))); // #i76339#
    7636             : 
    7637           0 :     return sal_True;
    7638             : }
    7639             : 
    7640         517 : bool OutputDevice::GetFontCapabilities( FontCapabilities& rFontCapabilities ) const
    7641             : {
    7642             :     // we need a graphics
    7643         517 :     if( !mpGraphics && !ImplGetGraphics() )
    7644           0 :         return false;
    7645             : 
    7646         517 :     if( mbNewFont )
    7647           0 :         ImplNewFont();
    7648         517 :     if( mbInitFont )
    7649           0 :         ImplInitFont();
    7650         517 :     if( !mpFontEntry )
    7651           0 :         return false;
    7652             : 
    7653         517 :     return mpGraphics->GetImplFontCapabilities(rFontCapabilities);
    7654             : }
    7655             : 
    7656        4273 : sal_Bool OutputDevice::GetFontCharMap( FontCharMap& rFontCharMap ) const
    7657             : {
    7658        4273 :     rFontCharMap.Reset();
    7659             : 
    7660             :     // we need a graphics
    7661        4273 :     if( !mpGraphics && !ImplGetGraphics() )
    7662           0 :         return sal_False;
    7663             : 
    7664        4273 :     if( mbNewFont )
    7665        3929 :         ImplNewFont();
    7666        4273 :     if( mbInitFont )
    7667         617 :         ImplInitFont();
    7668        4273 :     if( !mpFontEntry )
    7669           0 :         return sal_False;
    7670             : 
    7671             : #ifdef ENABLE_IFC_CACHE // a little font charmap cache helps considerably
    7672             :     static const int NMAXITEMS = 16;
    7673             :     static int nUsedItems = 0, nCurItem = 0;
    7674             : 
    7675             :     struct CharMapCacheItem { const PhysicalFontFace* mpFontData; FontCharMap maCharMap; };
    7676             :     static CharMapCacheItem aCache[ NMAXITEMS ];
    7677             : 
    7678             :     const PhysicalFontFace* pFontData = mpFontEntry->maFontSelData.mpFontData;
    7679             : 
    7680             :     int i;
    7681             :     for( i = nUsedItems; --i >= 0; )
    7682             :         if( pFontData == aCache[i].mpFontData )
    7683             :             break;
    7684             :     if( i >= 0 ) // found in cache
    7685             :     {
    7686             :         rFontCharMap.Reset( aCache[i].maCharMap.mpImpl );
    7687             :     }
    7688             :     else // need to cache
    7689             : #endif // ENABLE_IFC_CACHE
    7690             :     {
    7691        4273 :         const ImplFontCharMap* pNewMap = mpGraphics->GetImplFontCharMap();
    7692        4273 :         rFontCharMap.Reset( pNewMap );
    7693             : 
    7694             : #ifdef ENABLE_IFC_CACHE
    7695             :         // manage cache round-robin and insert data
    7696             :         CharMapCacheItem& rItem = aCache[ nCurItem ];
    7697             :         rItem.mpFontData = pFontData;
    7698             :         rItem.maCharMap.Reset( pNewMap );
    7699             : 
    7700             :         if( ++nCurItem >= NMAXITEMS )
    7701             :             nCurItem = 0;
    7702             : 
    7703             :         if( ++nUsedItems >= NMAXITEMS )
    7704             :             nUsedItems = NMAXITEMS;
    7705             : #endif // ENABLE_IFC_CACHE
    7706             :     }
    7707             : 
    7708        4273 :     if( rFontCharMap.IsDefaultMap() )
    7709           0 :         return sal_False;
    7710        4273 :     return sal_True;
    7711             : }
    7712             : 
    7713        3144 : xub_StrLen OutputDevice::HasGlyphs( const Font& rTempFont, const String& rStr,
    7714             :     xub_StrLen nIndex, xub_StrLen nLen ) const
    7715             : {
    7716        3144 :     if( nIndex >= rStr.Len() )
    7717           0 :         return nIndex;
    7718        3144 :     xub_StrLen nEnd = nIndex + nLen;
    7719        3144 :     if( (sal_uLong)nIndex+nLen > rStr.Len() )
    7720         615 :         nEnd = rStr.Len();
    7721             : 
    7722             :     DBG_ASSERT( nIndex < nEnd, "StartPos >= EndPos?" );
    7723             :     DBG_ASSERT( nEnd <= rStr.Len(), "String too short" );
    7724             : 
    7725             :     // to get the map temporarily set font
    7726        3144 :     const Font aOrigFont = GetFont();
    7727        3144 :     const_cast<OutputDevice&>(*this).SetFont( rTempFont );
    7728        6288 :     FontCharMap aFontCharMap;
    7729        3144 :     sal_Bool bRet = GetFontCharMap( aFontCharMap );
    7730        3144 :     const_cast<OutputDevice&>(*this).SetFont( aOrigFont );
    7731             : 
    7732             :     // if fontmap is unknown assume it doesn't have the glyphs
    7733        3144 :     if( bRet == sal_False )
    7734           0 :         return nIndex;
    7735             : 
    7736        3144 :     const sal_Unicode* pStr = rStr.GetBuffer();
    7737       16295 :     for( pStr += nIndex; nIndex < nEnd; ++pStr, ++nIndex )
    7738       15648 :         if( ! aFontCharMap.HasChar( *pStr ) )
    7739        2497 :             return nIndex;
    7740             : 
    7741        3791 :     return STRING_LEN;
    7742         465 : }
    7743             : 
    7744             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10