LCOV - code coverage report
Current view: top level - libreoffice/vcl/source/gdi - outdev3.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 1937 4132 46.9 %
Date: 2012-12-17 Functions: 124 170 72.9 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10