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

Generated by: LCOV version 1.10