LCOV - code coverage report
Current view: top level - vcl/source/gdi - outdev3.cxx (source / functions) Hit Total Coverage
Test: commit e02a6cb2c3e2b23b203b422e4e0680877f232636 Lines: 8 3233 0.2 %
Date: 2014-04-14 Functions: 4 136 2.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include "i18nlangtag/mslangid.hxx"
      21             : #include "i18nlangtag/languagetag.hxx"
      22             : 
      23             : #include "rtl/tencinfo.h"
      24             : #include "rtl/logfile.hxx"
      25             : 
      26             : #include "tools/debug.hxx"
      27             : #include "tools/poly.hxx"
      28             : 
      29             : #include "basegfx/polygon/b2dpolygon.hxx"
      30             : #include "basegfx/polygon/b2dpolypolygon.hxx"
      31             : #include "basegfx/matrix/b2dhommatrix.hxx"
      32             : 
      33             : #include "vcl/metric.hxx"
      34             : #include "vcl/metaact.hxx"
      35             : #include "vcl/gdimtf.hxx"
      36             : #include "vcl/virdev.hxx"
      37             : #include "vcl/print.hxx"
      38             : #include "vcl/event.hxx"
      39             : #include "vcl/window.hxx"
      40             : #include "vcl/svapp.hxx"
      41             : #include "vcl/bmpacc.hxx"
      42             : #include "vcl/outdev.hxx"
      43             : #include "vcl/edit.hxx"
      44             : #include <vcl/settings.hxx>
      45             : // declare system types in sysdata.hxx
      46             : #include <svsys.h>
      47             : #include "vcl/sysdata.hxx"
      48             : #include "vcl/unohelp.hxx"
      49             : #include "vcl/controllayout.hxx"
      50             : 
      51             : #include "salgdi.hxx"
      52             : #include "sallayout.hxx"
      53             : #include "svdata.hxx"
      54             : #include "impfont.hxx"
      55             : #include "outdata.hxx"
      56             : #include "outfont.hxx"
      57             : #include "outdev.h"
      58             : #include "PhysicalFontCollection.hxx"
      59             : #include "PhysicalFontFace.hxx"
      60             : #include "PhysicalFontFamily.hxx"
      61             : 
      62             : #include "textlayout.hxx"
      63             : #include "svids.hrc"
      64             : #include "window.h"
      65             : 
      66             : #include "unotools/fontcvt.hxx"
      67             : #include "unotools/fontcfg.hxx"
      68             : 
      69             : #include "osl/file.h"
      70             : 
      71             : #include <config_graphite.h>
      72             : #if ENABLE_GRAPHITE
      73             : #include "graphite_features.hxx"
      74             : #endif
      75             : 
      76             : #include "pdfwriter_impl.hxx"
      77             : 
      78             : #include "com/sun/star/beans/PropertyValues.hpp"
      79             : #include "com/sun/star/i18n/XBreakIterator.hpp"
      80             : #include "com/sun/star/i18n/WordType.hpp"
      81             : #include "com/sun/star/linguistic2/LinguServiceManager.hpp"
      82             : #include <comphelper/processfactory.hxx>
      83             : 
      84             : #if defined UNX
      85             : #define GLYPH_FONT_HEIGHT   128
      86             : #else
      87             : #define GLYPH_FONT_HEIGHT   256
      88             : #endif
      89             : 
      90             : #include "sal/alloca.h"
      91             : 
      92             : #include <cmath>
      93             : #include <cstring>
      94             : 
      95             : #include <memory>
      96             : #include <algorithm>
      97             : 
      98             : using namespace ::com::sun::star;
      99             : using namespace ::com::sun::star::uno;
     100             : using namespace ::rtl;
     101             : using namespace ::vcl;
     102             : using namespace ::utl;
     103             : 
     104             : #define TEXT_DRAW_ELLIPSIS  (TEXT_DRAW_ENDELLIPSIS | TEXT_DRAW_PATHELLIPSIS | TEXT_DRAW_NEWSELLIPSIS)
     105             : 
     106             : #define UNDERLINE_LAST      UNDERLINE_BOLDWAVE
     107             : #define STRIKEOUT_LAST      STRIKEOUT_X
     108             : 
     109           0 : static void ImplRotatePos( long nOriginX, long nOriginY, long& rX, long& rY,
     110             :                            int nOrientation )
     111             : {
     112           0 :     if ( (nOrientation >= 0) && !(nOrientation % 900) )
     113             :     {
     114           0 :         if ( (nOrientation >= 3600) )
     115           0 :             nOrientation %= 3600;
     116             : 
     117           0 :         if ( nOrientation )
     118             :         {
     119           0 :             rX -= nOriginX;
     120           0 :             rY -= nOriginY;
     121             : 
     122           0 :             if ( nOrientation == 900 )
     123             :             {
     124           0 :                 long nTemp = rX;
     125           0 :                 rX = rY;
     126           0 :                 rY = -nTemp;
     127             :             }
     128           0 :             else if ( nOrientation == 1800 )
     129             :             {
     130           0 :                 rX = -rX;
     131           0 :                 rY = -rY;
     132             :             }
     133             :             else /* ( nOrientation == 2700 ) */
     134             :             {
     135           0 :                 long nTemp = rX;
     136           0 :                 rX = -rY;
     137           0 :                 rY = nTemp;
     138             :             }
     139             : 
     140           0 :             rX += nOriginX;
     141           0 :             rY += nOriginY;
     142           0 :         }
     143             :     }
     144             :     else
     145             :     {
     146           0 :         double nRealOrientation = nOrientation*F_PI1800;
     147           0 :         double nCos = cos( nRealOrientation );
     148           0 :         double nSin = sin( nRealOrientation );
     149             : 
     150             :         // Translation...
     151           0 :         long nX = rX-nOriginX;
     152           0 :         long nY = rY-nOriginY;
     153             : 
     154             :         // Rotation...
     155           0 :         rX = +((long)(nCos*nX + nSin*nY)) + nOriginX;
     156           0 :         rY = -((long)(nSin*nX - nCos*nY)) + nOriginY;
     157             :     }
     158           0 : }
     159             : 
     160           0 : void OutputDevice::ImplClearFontData( const bool bNewFontLists )
     161             : {
     162             :     // the currently selected logical font is no longer needed
     163           0 :     if ( mpFontEntry )
     164             :     {
     165           0 :         mpFontCache->Release( mpFontEntry );
     166           0 :         mpFontEntry = NULL;
     167             :     }
     168             : 
     169           0 :     mbInitFont = true;
     170           0 :     mbNewFont = true;
     171             : 
     172           0 :     if ( bNewFontLists )
     173             :     {
     174           0 :         if ( mpGetDevFontList )
     175             :         {
     176           0 :             delete mpGetDevFontList;
     177           0 :             mpGetDevFontList = NULL;
     178             :         }
     179           0 :         if ( mpGetDevSizeList )
     180             :         {
     181           0 :             delete mpGetDevSizeList;
     182           0 :             mpGetDevSizeList = NULL;
     183             :         }
     184             : 
     185             :         // release all physically selected fonts on this device
     186           0 :         if( ImplGetGraphics() )
     187           0 :             mpGraphics->ReleaseFonts();
     188             :     }
     189             : 
     190             : //    if ( GetOutDevType() == OUTDEV_PRINTER || mpPDFWriter )
     191             :     {
     192           0 :         ImplSVData* pSVData = ImplGetSVData();
     193             : 
     194           0 :         if( mpFontCache && mpFontCache != pSVData->maGDIData.mpScreenFontCache )
     195           0 :             mpFontCache->Invalidate();
     196             : 
     197           0 :         if ( bNewFontLists )
     198             :         {
     199             :             // we need a graphics
     200           0 :             if ( ImplGetGraphics() )
     201             :             {
     202           0 :                 if( mpFontCollection && mpFontCollection != pSVData->maGDIData.mpScreenFontList )
     203           0 :                     mpFontCollection->Clear();
     204             : 
     205           0 :                 if( mpPDFWriter )
     206             :                 {
     207           0 :                     if( mpFontCollection && mpFontCollection != pSVData->maGDIData.mpScreenFontList )
     208           0 :                         delete mpFontCollection;
     209           0 :                     if( mpFontCache && mpFontCache != pSVData->maGDIData.mpScreenFontCache )
     210           0 :                         delete mpFontCache;
     211           0 :                     mpFontCollection = 0;
     212           0 :                     mpFontCache = 0;
     213             :                 }
     214             :             }
     215             :         }
     216             :     }
     217             : 
     218             :     // also update child windows if needed
     219           0 :     if ( GetOutDevType() == OUTDEV_WINDOW )
     220             :     {
     221           0 :         Window* pChild = ((Window*)this)->mpWindowImpl->mpFirstChild;
     222           0 :         while ( pChild )
     223             :         {
     224           0 :             pChild->ImplClearFontData( true );
     225           0 :             pChild = pChild->mpWindowImpl->mpNext;
     226             :         }
     227             :     }
     228           0 : }
     229             : 
     230           0 : void OutputDevice::ImplRefreshFontData( const bool bNewFontLists )
     231             : {
     232             : //    if ( GetOutDevType() == OUTDEV_PRINTER || mpPDFWriter )
     233             :     {
     234           0 :         ImplSVData* pSVData = ImplGetSVData();
     235             : 
     236           0 :         if ( bNewFontLists )
     237             :         {
     238             :             // we need a graphics
     239           0 :             if ( ImplGetGraphics() )
     240             :             {
     241           0 :                 if( mpPDFWriter )
     242             :                 {
     243           0 :                     mpFontCollection = pSVData->maGDIData.mpScreenFontList->Clone( true, true );
     244           0 :                     mpFontCache = new ImplFontCache();
     245             :                 }
     246             :                 else
     247             :                 {
     248           0 :                     mpGraphics->GetDevFontList( mpFontCollection );
     249             :                 }
     250             :             }
     251             :         }
     252             :     }
     253             : 
     254             :     // also update child windows if needed
     255           0 :     if ( GetOutDevType() == OUTDEV_WINDOW )
     256             :     {
     257           0 :         Window* pChild = ((Window*)this)->mpWindowImpl->mpFirstChild;
     258           0 :         while ( pChild )
     259             :         {
     260           0 :             pChild->ImplRefreshFontData( true );
     261           0 :             pChild = pChild->mpWindowImpl->mpNext;
     262             :         }
     263             :     }
     264           0 : }
     265             : 
     266           0 : void OutputDevice::ImplUpdateFontData( bool bNewFontLists )
     267             : {
     268           0 :     ImplClearFontData( bNewFontLists );
     269           0 :     ImplRefreshFontData( bNewFontLists );
     270           0 : }
     271             : 
     272           0 : void OutputDevice::ImplUpdateAllFontData( bool bNewFontLists )
     273             : {
     274           0 :     ImplSVData* pSVData = ImplGetSVData();
     275             : 
     276           0 :     ImplUpdateFontDataForAllFrames( &OutputDevice::ImplClearFontData, bNewFontLists );
     277             : 
     278             :     // clear global font lists to have them updated
     279           0 :     pSVData->maGDIData.mpScreenFontCache->Invalidate();
     280           0 :     if ( bNewFontLists )
     281             :     {
     282           0 :         pSVData->maGDIData.mpScreenFontList->Clear();
     283           0 :         Window * pFrame = pSVData->maWinData.mpFirstFrame;
     284           0 :         if ( pFrame )
     285             :         {
     286           0 :             if ( pFrame->ImplGetGraphics() )
     287             :             {
     288             :                 // Stupid typecast here and somewhere ((OutputDevice*)&aVDev)->, because bug in .NET2002 compiler
     289           0 :                 OutputDevice *pDevice = (OutputDevice*)pFrame;
     290           0 :                 pDevice->mpGraphics->ClearDevFontCache();
     291           0 :                 pDevice->mpGraphics->GetDevFontList(pFrame->mpWindowImpl->mpFrameData->mpFontCollection);
     292             :             }
     293             :         }
     294             :     }
     295             : 
     296           0 :     ImplUpdateFontDataForAllFrames( &OutputDevice::ImplRefreshFontData, bNewFontLists );
     297           0 : }
     298             : 
     299           0 : void OutputDevice::ImplUpdateFontDataForAllFrames( const FontUpdateHandler_t pHdl, const bool bNewFontLists )
     300             : {
     301           0 :     ImplSVData* const pSVData = ImplGetSVData();
     302             : 
     303             :     // update all windows
     304           0 :     Window* pFrame = pSVData->maWinData.mpFirstFrame;
     305           0 :     while ( pFrame )
     306             :     {
     307           0 :         ( pFrame->*pHdl )( bNewFontLists );
     308             : 
     309           0 :         Window* pSysWin = pFrame->mpWindowImpl->mpFrameData->mpFirstOverlap;
     310           0 :         while ( pSysWin )
     311             :         {
     312           0 :             ( pSysWin->*pHdl )( bNewFontLists );
     313           0 :             pSysWin = pSysWin->mpWindowImpl->mpNextOverlap;
     314             :         }
     315             : 
     316           0 :         pFrame = pFrame->mpWindowImpl->mpFrameData->mpNextFrame;
     317             :     }
     318             : 
     319             :     // update all virtual devices
     320           0 :     VirtualDevice* pVirDev = pSVData->maGDIData.mpFirstVirDev;
     321           0 :     while ( pVirDev )
     322             :     {
     323           0 :         ( pVirDev->*pHdl )( bNewFontLists );
     324           0 :         pVirDev = pVirDev->mpNext;
     325             :     }
     326             : 
     327             :     // update all printers
     328           0 :     Printer* pPrinter = pSVData->maGDIData.mpFirstPrinter;
     329           0 :     while ( pPrinter )
     330             :     {
     331           0 :         ( pPrinter->*pHdl )( bNewFontLists );
     332           0 :         pPrinter = pPrinter->mpNext;
     333             :     }
     334           0 : }
     335             : 
     336           0 : void OutputDevice::BeginFontSubstitution()
     337             : {
     338           0 :     ImplSVData* pSVData = ImplGetSVData();
     339           0 :     pSVData->maGDIData.mbFontSubChanged = false;
     340           0 : }
     341             : 
     342           0 : void OutputDevice::EndFontSubstitution()
     343             : {
     344           0 :     ImplSVData* pSVData = ImplGetSVData();
     345           0 :     if ( pSVData->maGDIData.mbFontSubChanged )
     346             :     {
     347           0 :         ImplUpdateAllFontData( false );
     348             : 
     349           0 :         Application* pApp = GetpApp();
     350           0 :         DataChangedEvent aDCEvt( DATACHANGED_FONTSUBSTITUTION );
     351           0 :         pApp->DataChanged( aDCEvt );
     352           0 :         pApp->NotifyAllWindows( aDCEvt );
     353           0 :         pSVData->maGDIData.mbFontSubChanged = false;
     354             :     }
     355           0 : }
     356             : 
     357           0 : void OutputDevice::AddFontSubstitute( const OUString& rFontName,
     358             :                                       const OUString& rReplaceFontName,
     359             :                                       sal_uInt16 nFlags )
     360             : {
     361           0 :     ImplDirectFontSubstitution*& rpSubst = ImplGetSVData()->maGDIData.mpDirectFontSubst;
     362           0 :     if( !rpSubst )
     363           0 :         rpSubst = new ImplDirectFontSubstitution();
     364           0 :     rpSubst->AddFontSubstitute( rFontName, rReplaceFontName, nFlags );
     365           0 :     ImplGetSVData()->maGDIData.mbFontSubChanged = true;
     366           0 : }
     367             : 
     368           0 : void ImplDirectFontSubstitution::AddFontSubstitute( const OUString& rFontName,
     369             :     const OUString& rSubstFontName, sal_uInt16 nFlags )
     370             : {
     371           0 :     maFontSubstList.push_back( ImplFontSubstEntry( rFontName, rSubstFontName, nFlags ) );
     372           0 : }
     373             : 
     374           0 : ImplFontSubstEntry::ImplFontSubstEntry( const OUString& rFontName,
     375             :     const OUString& rSubstFontName, sal_uInt16 nSubstFlags )
     376             : :   maName( rFontName )
     377             : ,   maReplaceName( rSubstFontName )
     378           0 : ,   mnFlags( nSubstFlags )
     379             : {
     380           0 :     maSearchName        = rFontName;
     381           0 :     maSearchReplaceName = rSubstFontName;
     382           0 :     GetEnglishSearchFontName( maSearchName );
     383           0 :     GetEnglishSearchFontName( maSearchReplaceName );
     384           0 : }
     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           0 : void ImplDirectFontSubstitution::RemoveFontSubstitute( int nIndex )
     394             : {
     395           0 :     FontSubstList::iterator it = maFontSubstList.begin();
     396           0 :     for( int nCount = 0; (it != maFontSubstList.end()) && (nCount++ != nIndex); ++it ) ;
     397           0 :     if( it != maFontSubstList.end() )
     398           0 :         maFontSubstList.erase( it );
     399           0 : }
     400             : 
     401           0 : sal_uInt16 OutputDevice::GetFontSubstituteCount()
     402             : {
     403           0 :     const ImplDirectFontSubstitution* pSubst = ImplGetSVData()->maGDIData.mpDirectFontSubst;
     404           0 :     if( !pSubst )
     405           0 :         return 0;
     406           0 :     int nCount =  pSubst->GetFontSubstituteCount();
     407           0 :     return (sal_uInt16)nCount;
     408             : }
     409             : 
     410           0 : bool ImplDirectFontSubstitution::FindFontSubstitute( OUString& rSubstName,
     411             :     const OUString& rSearchName, sal_uInt16 nFlags ) const
     412             : {
     413             :     // TODO: get rid of O(N) searches
     414           0 :     FontSubstList::const_iterator it = maFontSubstList.begin();
     415           0 :     for(; it != maFontSubstList.end(); ++it )
     416             :     {
     417           0 :         const ImplFontSubstEntry& rEntry = *it;
     418           0 :         if( ((rEntry.mnFlags & nFlags) || !nFlags)
     419           0 :         &&   (rEntry.maSearchName == rSearchName) )
     420             :         {
     421           0 :             rSubstName = rEntry.maSearchReplaceName;
     422           0 :             return true;
     423             :         }
     424             :     }
     425             : 
     426           0 :     return false;
     427             : }
     428             : 
     429           0 : void ImplFontSubstitute( OUString& rFontName )
     430             : {
     431             : #ifdef DBG_UTIL
     432             :     OUString aTempName = rFontName;
     433             :     GetEnglishSearchFontName( aTempName );
     434             :     DBG_ASSERT( aTempName == rFontName, "ImplFontSubstitute() called without a searchname" );
     435             : #endif
     436             : 
     437           0 :     OUString aSubstFontName;
     438             : 
     439             :     // apply user-configurable font replacement (eg, from the list in Tools->Options)
     440           0 :     const ImplDirectFontSubstitution* pSubst = ImplGetSVData()->maGDIData.mpDirectFontSubst;
     441           0 :     if( pSubst && pSubst->FindFontSubstitute( aSubstFontName, rFontName, FONT_SUBSTITUTE_ALWAYS ) )
     442             :     {
     443           0 :         rFontName = aSubstFontName;
     444           0 :         return;
     445           0 :     }
     446             : }
     447             : 
     448             : //hidpi TODO: This routine has hard-coded font-sizes that break places such as DialControl
     449           0 : Font OutputDevice::GetDefaultFont( sal_uInt16 nType, LanguageType eLang,
     450             :                                    sal_uLong nFlags, const OutputDevice* pOutDev )
     451             : {
     452           0 :     if (!pOutDev) // default is NULL
     453           0 :         pOutDev = Application::GetDefaultDevice();
     454             : 
     455             :     LanguageTag aLanguageTag(
     456           0 :             ( eLang == LANGUAGE_NONE || eLang == LANGUAGE_SYSTEM || eLang == LANGUAGE_DONTKNOW ) ?
     457           0 :             Application::GetSettings().GetUILanguageTag() :
     458           0 :             LanguageTag( eLang ));
     459             : 
     460           0 :     utl::DefaultFontConfiguration& rDefaults = utl::DefaultFontConfiguration::get();
     461           0 :     OUString aDefault = rDefaults.getDefaultFont( aLanguageTag, nType );
     462           0 :     OUString aSearch;
     463             : 
     464           0 :     if( !aDefault.isEmpty() )
     465           0 :         aSearch = aDefault;
     466             :     else
     467           0 :         aSearch = rDefaults.getUserInterfaceFont( aLanguageTag ); // use the UI font as a fallback
     468             : 
     469           0 :     Font aFont;
     470           0 :     aFont.SetPitch( PITCH_VARIABLE );
     471             : 
     472           0 :     switch ( nType )
     473             :     {
     474             :         case DEFAULTFONT_SANS_UNICODE:
     475             :         case DEFAULTFONT_UI_SANS:
     476           0 :             aFont.SetFamily( FAMILY_SWISS );
     477           0 :             break;
     478             : 
     479             :         case DEFAULTFONT_SANS:
     480             :         case DEFAULTFONT_LATIN_HEADING:
     481             :         case DEFAULTFONT_LATIN_SPREADSHEET:
     482             :         case DEFAULTFONT_LATIN_DISPLAY:
     483           0 :             aFont.SetFamily( FAMILY_SWISS );
     484           0 :             break;
     485             : 
     486             :         case DEFAULTFONT_SERIF:
     487             :         case DEFAULTFONT_LATIN_TEXT:
     488             :         case DEFAULTFONT_LATIN_PRESENTATION:
     489           0 :             aFont.SetFamily( FAMILY_ROMAN );
     490           0 :             break;
     491             : 
     492             :         case DEFAULTFONT_FIXED:
     493             :         case DEFAULTFONT_LATIN_FIXED:
     494             :         case DEFAULTFONT_UI_FIXED:
     495           0 :             aFont.SetPitch( PITCH_FIXED );
     496           0 :             aFont.SetFamily( FAMILY_MODERN );
     497           0 :             break;
     498             : 
     499             :         case DEFAULTFONT_SYMBOL:
     500           0 :             aFont.SetCharSet( RTL_TEXTENCODING_SYMBOL );
     501           0 :             break;
     502             : 
     503             :         case DEFAULTFONT_CJK_TEXT:
     504             :         case DEFAULTFONT_CJK_PRESENTATION:
     505             :         case DEFAULTFONT_CJK_SPREADSHEET:
     506             :         case DEFAULTFONT_CJK_HEADING:
     507             :         case DEFAULTFONT_CJK_DISPLAY:
     508           0 :             aFont.SetFamily( FAMILY_SYSTEM ); // don't care, but don't use font subst config later...
     509           0 :             break;
     510             : 
     511             :         case DEFAULTFONT_CTL_TEXT:
     512             :         case DEFAULTFONT_CTL_PRESENTATION:
     513             :         case DEFAULTFONT_CTL_SPREADSHEET:
     514             :         case DEFAULTFONT_CTL_HEADING:
     515             :         case DEFAULTFONT_CTL_DISPLAY:
     516           0 :             aFont.SetFamily( FAMILY_SYSTEM ); // don't care, but don't use font subst config later...
     517           0 :             break;
     518             :     }
     519             : 
     520           0 :     if ( !aSearch.isEmpty() )
     521             :     {
     522           0 :         aFont.SetHeight( 12 ); // corresponds to nDefaultHeight
     523           0 :         aFont.SetWeight( WEIGHT_NORMAL );
     524           0 :         aFont.SetLanguage( eLang );
     525             : 
     526           0 :         if ( aFont.GetCharSet() == RTL_TEXTENCODING_DONTKNOW )
     527           0 :             aFont.SetCharSet( osl_getThreadTextEncoding() );
     528             : 
     529             :         // Should we only return available fonts on the given device
     530           0 :         if ( pOutDev )
     531             :         {
     532           0 :             pOutDev->ImplInitFontList();
     533             : 
     534             :             // Search Font in the FontList
     535           0 :             OUString      aName;
     536           0 :             OUString      aSearchName;
     537           0 :             sal_Int32     nIndex = 0;
     538           0 :             do
     539             :             {
     540           0 :                 aSearchName = GetNextFontToken( aSearch, nIndex );
     541           0 :                 GetEnglishSearchFontName( aSearchName );
     542           0 :                 PhysicalFontFamily* pFontFamily = pOutDev->mpFontCollection->ImplFindBySearchName( aSearchName );
     543           0 :                 if( pFontFamily )
     544             :                 {
     545           0 :                     AddTokenFontName( aName, pFontFamily->GetFamilyName() );
     546           0 :                     if( nFlags & DEFAULTFONT_FLAGS_ONLYONE )
     547           0 :                         break;
     548             :                 }
     549             :             }
     550           0 :             while ( nIndex != -1 );
     551           0 :             aFont.SetName( aName );
     552             :         }
     553             : 
     554             :         // No Name, than set all names
     555           0 :         if ( aFont.GetName().isEmpty() )
     556             :         {
     557           0 :             if ( nFlags & DEFAULTFONT_FLAGS_ONLYONE )
     558             :             {
     559           0 :                 if( !pOutDev )
     560             :                 {
     561             :                     SAL_WARN ("vcl.gdi", "No default window has been set for the application - we really shouldn't be able to get here");
     562           0 :                     sal_Int32 nIndex = 0;
     563           0 :                     aFont.SetName( aSearch.getToken( 0, ';', nIndex ) );
     564             :                 }
     565             :                 else
     566             :                 {
     567           0 :                     pOutDev->ImplInitFontList();
     568             : 
     569           0 :                     aFont.SetName( aSearch );
     570             : 
     571             :                     // convert to pixel height
     572           0 :                     Size aSize = pOutDev->ImplLogicToDevicePixel( aFont.GetSize() );
     573           0 :                     if ( !aSize.Height() )
     574             :                     {
     575             :                         // use default pixel height only when logical height is zero
     576           0 :                         if ( aFont.GetHeight() )
     577           0 :                             aSize.Height() = 1;
     578             :                         else
     579           0 :                             aSize.Height() = (12*pOutDev->mnDPIY)/72;
     580             :                     }
     581             : 
     582             :                     // use default width only when logical width is zero
     583           0 :                     if( (0 == aSize.Width()) && (0 != aFont.GetSize().Width()) )
     584           0 :                         aSize.Width() = 1;
     585             : 
     586             :                     // get the name of the first available font
     587           0 :                     float fExactHeight = static_cast<float>(aSize.Height());
     588           0 :                     ImplFontEntry* pEntry = pOutDev->mpFontCache->GetFontEntry( pOutDev->mpFontCollection, aFont, aSize, fExactHeight );
     589           0 :                     if (pEntry)
     590             :                     {
     591           0 :                         if( pEntry->maFontSelData.mpFontData )
     592           0 :                             aFont.SetName( pEntry->maFontSelData.mpFontData->GetFamilyName() );
     593             :                         else
     594           0 :                             aFont.SetName( pEntry->maFontSelData.maTargetName );
     595             :                     }
     596             :                 }
     597             :             }
     598             :             else
     599           0 :                 aFont.SetName( aSearch );
     600             :         }
     601             :     }
     602             : 
     603             : #if OSL_DEBUG_LEVEL > 2
     604             :     const char* s = "DEFAULTFONT_SANS_UNKNOWN";
     605             :     switch ( nType )
     606             :     {
     607             :     case DEFAULTFONT_SANS_UNICODE:  s = "DEFAULTFONT_SANS_UNICODE"; break;
     608             :     case DEFAULTFONT_UI_SANS:   s = "DEFAULTFONT_UI_SANS"; break;
     609             : 
     610             :     case DEFAULTFONT_SANS:  s = "DEFAULTFONT_SANS"; break;
     611             :     case DEFAULTFONT_LATIN_HEADING: s = "DEFAULTFONT_LATIN_HEADING"; break;
     612             :     case DEFAULTFONT_LATIN_SPREADSHEET: s = "DEFAULTFONT_LATIN_SPREADSHEET"; break;
     613             :     case DEFAULTFONT_LATIN_DISPLAY: s = "DEFAULTFONT_LATIN_DISPLAY"; break;
     614             : 
     615             :     case DEFAULTFONT_SERIF: s = "DEFAULTFONT_SERIF"; break;
     616             :     case DEFAULTFONT_LATIN_TEXT:    s = "DEFAULTFONT_LATIN_TEXT"; break;
     617             :     case DEFAULTFONT_LATIN_PRESENTATION:    s = "DEFAULTFONT_LATIN_PRESENTATION"; break;
     618             : 
     619             :     case DEFAULTFONT_FIXED: s = "DEFAULTFONT_FIXED"; break;
     620             :     case DEFAULTFONT_LATIN_FIXED:   s = "DEFAULTFONT_LATIN_FIXED"; break;
     621             :     case DEFAULTFONT_UI_FIXED:  s = "DEFAULTFONT_UI_FIXED"; break;
     622             : 
     623             :     case DEFAULTFONT_SYMBOL:    s = "DEFAULTFONT_SYMBOL"; break;
     624             : 
     625             :     case DEFAULTFONT_CJK_TEXT:  s = "DEFAULTFONT_CJK_TEXT"; break;
     626             :     case DEFAULTFONT_CJK_PRESENTATION:  s = "DEFAULTFONT_CJK_PRESENTATION"; break;
     627             :     case DEFAULTFONT_CJK_SPREADSHEET:   s = "DEFAULTFONT_CJK_SPREADSHEET"; break;
     628             :     case DEFAULTFONT_CJK_HEADING:   s = "DEFAULTFONT_CJK_HEADING"; break;
     629             :     case DEFAULTFONT_CJK_DISPLAY:   s = "DEFAULTFONT_CJK_DISPLAY"; break;
     630             : 
     631             :     case DEFAULTFONT_CTL_TEXT:  s = "DEFAULTFONT_CTL_TEXT"; break;
     632             :     case DEFAULTFONT_CTL_PRESENTATION:  s = "DEFAULTFONT_CTL_PRESENTATION"; break;
     633             :     case DEFAULTFONT_CTL_SPREADSHEET:   s = "DEFAULTFONT_CTL_SPREADSHEET"; break;
     634             :     case DEFAULTFONT_CTL_HEADING:   s = "DEFAULTFONT_CTL_HEADING"; break;
     635             :     case DEFAULTFONT_CTL_DISPLAY:   s = "DEFAULTFONT_CTL_DISPLAY"; break;
     636             :     }
     637             :     fprintf( stderr, "   OutputDevice::GetDefaultFont() Type=\"%s\" lang=%d flags=%ld FontName=\"%s\"\n",
     638             :          s, eLang, nFlags,
     639             :          OUStringToOString( aFont.GetName(), RTL_TEXTENCODING_UTF8 ).getStr()
     640             :          );
     641             : #endif
     642             : 
     643           0 :     return aFont;
     644             : }
     645             : 
     646           0 : ImplFontEntry::ImplFontEntry( const FontSelectPattern& rFontSelData )
     647             :     : maFontSelData( rFontSelData )
     648             :     , maMetric( rFontSelData )
     649             :     , mpConversion( NULL )
     650             :     , mnLineHeight( 0 )
     651             :     , mnRefCount( 1 )
     652             :     , mnSetFontFlags( 0 )
     653             :     , mnOwnOrientation( 0 )
     654             :     , mnOrientation( 0 )
     655             :     , mbInit( false )
     656           0 :     , mpUnicodeFallbackList( NULL )
     657             : {
     658           0 :     maFontSelData.mpFontEntry = this;
     659           0 : }
     660             : 
     661           0 : ImplFontEntry::~ImplFontEntry()
     662             : {
     663           0 :     delete mpUnicodeFallbackList;
     664           0 : }
     665             : 
     666           0 : size_t ImplFontEntry::GFBCacheKey_Hash::operator()( const GFBCacheKey& rData ) const
     667             : {
     668             :     boost::hash<sal_UCS4> a;
     669             :     boost::hash<int > b;
     670           0 :     return a(rData.first) ^ b(rData.second);
     671             : }
     672             : 
     673           0 : void ImplFontEntry::AddFallbackForUnicode( sal_UCS4 cChar, FontWeight eWeight, const OUString& rFontName )
     674             : {
     675           0 :     if( !mpUnicodeFallbackList )
     676           0 :         mpUnicodeFallbackList = new UnicodeFallbackList;
     677           0 :     (*mpUnicodeFallbackList)[ GFBCacheKey(cChar,eWeight) ] = rFontName;
     678           0 : }
     679             : 
     680           0 : bool ImplFontEntry::GetFallbackForUnicode( sal_UCS4 cChar, FontWeight eWeight, OUString* pFontName ) const
     681             : {
     682           0 :     if( !mpUnicodeFallbackList )
     683           0 :         return false;
     684             : 
     685           0 :     UnicodeFallbackList::const_iterator it = mpUnicodeFallbackList->find( GFBCacheKey(cChar,eWeight) );
     686           0 :     if( it == mpUnicodeFallbackList->end() )
     687           0 :         return false;
     688             : 
     689           0 :     *pFontName = (*it).second;
     690           0 :     return true;
     691             : }
     692             : 
     693           0 : void ImplFontEntry::IgnoreFallbackForUnicode( sal_UCS4 cChar, FontWeight eWeight, const OUString& rFontName )
     694             : {
     695             : //  DBG_ASSERT( mpUnicodeFallbackList, "ImplFontEntry::IgnoreFallbackForUnicode no list" );
     696           0 :     UnicodeFallbackList::iterator it = mpUnicodeFallbackList->find( GFBCacheKey(cChar,eWeight) );
     697             : //  DBG_ASSERT( it != mpUnicodeFallbackList->end(), "ImplFontEntry::IgnoreFallbackForUnicode no match" );
     698           0 :     if( it == mpUnicodeFallbackList->end() )
     699           0 :         return;
     700           0 :     if( (*it).second == rFontName )
     701           0 :         mpUnicodeFallbackList->erase( it );
     702             : }
     703             : 
     704           0 : FontSelectPatternAttributes::FontSelectPatternAttributes( const Font& rFont,
     705             :     const OUString& rSearchName, const Size& rSize, float fExactHeight )
     706             :     : maSearchName( rSearchName )
     707           0 :     , mnWidth( rSize.Width() )
     708           0 :     , mnHeight( rSize.Height() )
     709             :     , mfExactHeight( fExactHeight)
     710           0 :     , mnOrientation( rFont.GetOrientation() )
     711           0 :     , meLanguage( rFont.GetLanguage() )
     712           0 :     , mbVertical( rFont.IsVertical() )
     713             :     , mbNonAntialiased( false )
     714           0 :     , mbEmbolden( false )
     715             : {
     716           0 :     maTargetName = GetFamilyName();
     717             : 
     718           0 :     rFont.GetFontAttributes( *this );
     719             : 
     720             :     // normalize orientation between 0 and 3600
     721           0 :     if( 3600 <= (unsigned)mnOrientation )
     722             :     {
     723           0 :         if( mnOrientation >= 0 )
     724           0 :             mnOrientation %= 3600;
     725             :         else
     726           0 :             mnOrientation = 3600 - (-mnOrientation % 3600);
     727             :     }
     728             : 
     729             :     // normalize width and height
     730           0 :     if( mnHeight < 0 )
     731           0 :         mnHeight = -mnHeight;
     732           0 :     if( mnWidth < 0 )
     733           0 :         mnWidth = -mnWidth;
     734           0 : }
     735             : 
     736           0 : FontSelectPattern::FontSelectPattern( const Font& rFont,
     737             :     const OUString& rSearchName, const Size& rSize, float fExactHeight)
     738             :     : FontSelectPatternAttributes(rFont, rSearchName, rSize, fExactHeight)
     739             :     , mpFontData( NULL )
     740           0 :     , mpFontEntry( NULL )
     741             : {
     742           0 : }
     743             : 
     744             : // NOTE: this ctor is still used on Windows. Do not remove.
     745             : #ifdef WNT
     746             : FontSelectPatternAttributes::FontSelectPatternAttributes( const PhysicalFontFace& rFontData,
     747             :     const Size& rSize, float fExactHeight, int nOrientation, bool bVertical )
     748             :     : ImplFontAttributes( rFontData )
     749             :     , mnWidth( rSize.Width() )
     750             :     , mnHeight( rSize.Height() )
     751             :     , mfExactHeight( fExactHeight )
     752             :     , mnOrientation( nOrientation )
     753             :     , meLanguage( 0 )
     754             :     , mbVertical( bVertical )
     755             :     , mbNonAntialiased( false )
     756             :     , mbEmbolden( false )
     757             : {
     758             :     maTargetName = maSearchName = GetFamilyName();
     759             :     // NOTE: no normalization for width/height/orientation
     760             : }
     761             : 
     762             : FontSelectPattern::FontSelectPattern( const PhysicalFontFace& rFontData,
     763             :     const Size& rSize, float fExactHeight, int nOrientation, bool bVertical )
     764             :     : FontSelectPatternAttributes(rFontData, rSize, fExactHeight, nOrientation, bVertical)
     765             :     , mpFontData( &rFontData )
     766             :     , mpFontEntry( NULL )
     767             : {
     768             : }
     769             : #endif
     770             : 
     771           0 : void FontSelectPattern::copyAttributes(const FontSelectPatternAttributes &rAttributes)
     772             : {
     773           0 :     static_cast<FontSelectPatternAttributes&>(*this) = rAttributes;
     774           0 : }
     775             : 
     776           0 : size_t ImplFontCache::IFSD_Hash::operator()( const FontSelectPattern& rFSD ) const
     777             : {
     778           0 :     return rFSD.hashCode();
     779             : }
     780             : 
     781           0 : size_t FontSelectPatternAttributes::hashCode() const
     782             : {
     783             :     // TODO: does it pay off to improve this hash function?
     784             :     static FontNameHash aFontNameHash;
     785           0 :     size_t nHash = aFontNameHash( maSearchName );
     786             : #if ENABLE_GRAPHITE
     787             :     // check for features and generate a unique hash if necessary
     788           0 :     if (maTargetName.indexOf(grutils::GrFeatureParser::FEAT_PREFIX)
     789             :         != -1)
     790             :     {
     791           0 :         nHash = aFontNameHash( maTargetName );
     792             :     }
     793             : #endif
     794           0 :     nHash += 11 * mnHeight;
     795           0 :     nHash += 19 * GetWeight();
     796           0 :     nHash += 29 * GetSlant();
     797           0 :     nHash += 37 * mnOrientation;
     798           0 :     nHash += 41 * meLanguage;
     799           0 :     if( mbVertical )
     800           0 :         nHash += 53;
     801           0 :     return nHash;
     802             : }
     803             : 
     804           0 : bool FontSelectPatternAttributes::operator==(const FontSelectPatternAttributes& rOther) const
     805             : {
     806           0 :     if (static_cast<const ImplFontAttributes&>(*this) != static_cast<const ImplFontAttributes&>(rOther))
     807           0 :         return false;
     808             : 
     809           0 :     if (maTargetName != rOther.maTargetName)
     810           0 :         return false;
     811             : 
     812           0 :     if (maSearchName != rOther.maSearchName)
     813           0 :         return false;
     814             : 
     815           0 :     if (mnWidth != rOther.mnWidth)
     816           0 :         return false;
     817             : 
     818           0 :     if (mnHeight != rOther.mnHeight)
     819           0 :         return false;
     820             : 
     821           0 :     if (mfExactHeight != rOther.mfExactHeight)
     822           0 :         return false;
     823             : 
     824           0 :     if (mnOrientation != rOther.mnOrientation)
     825           0 :         return false;
     826             : 
     827           0 :     if (meLanguage != rOther.meLanguage)
     828           0 :         return false;
     829             : 
     830           0 :     if (mbVertical != rOther.mbVertical)
     831           0 :         return false;
     832             : 
     833           0 :     if (mbNonAntialiased != rOther.mbNonAntialiased)
     834           0 :         return false;
     835             : 
     836           0 :     if (mbEmbolden != rOther.mbEmbolden)
     837           0 :         return false;
     838             : 
     839           0 :     if (maItalicMatrix != rOther.maItalicMatrix)
     840           0 :         return false;
     841             : 
     842           0 :     return true;
     843             : }
     844             : 
     845           0 : bool ImplFontCache::IFSD_Equal::operator()(const FontSelectPattern& rA, const FontSelectPattern& rB) const
     846             : {
     847             :     // check normalized font family name
     848           0 :     if( rA.maSearchName != rB.maSearchName )
     849           0 :         return false;
     850             : 
     851             :     // check font transformation
     852           0 :     if( (rA.mnHeight       != rB.mnHeight)
     853           0 :     ||  (rA.mnWidth        != rB.mnWidth)
     854           0 :     ||  (rA.mnOrientation  != rB.mnOrientation) )
     855           0 :         return false;
     856             : 
     857             :     // check mapping relevant attributes
     858           0 :     if( (rA.mbVertical     != rB.mbVertical)
     859           0 :     ||  (rA.meLanguage     != rB.meLanguage) )
     860           0 :         return false;
     861             : 
     862             :     // check font face attributes
     863           0 :     if( (rA.GetWeight()       != rB.GetWeight())
     864           0 :     ||  (rA.GetSlant()       != rB.GetSlant())
     865             : //  ||  (rA.meFamily       != rB.meFamily) // TODO: remove this mostly obsolete member
     866           0 :     ||  (rA.GetPitch()     != rB.GetPitch()) )
     867           0 :         return false;
     868             : 
     869             :     // check style name
     870           0 :     if( rA.GetStyleName() != rB.GetStyleName() )
     871           0 :         return false;
     872             : 
     873             :     // Symbol fonts may recode from one type to another So they are only
     874             :     // safely equivalent for equal targets
     875           0 :     if (
     876           0 :         (rA.mpFontData && rA.mpFontData->IsSymbolFont()) ||
     877           0 :         (rB.mpFontData && rB.mpFontData->IsSymbolFont())
     878             :        )
     879             :     {
     880           0 :         if (rA.maTargetName != rB.maTargetName)
     881           0 :             return false;
     882             :     }
     883             : 
     884             : #if ENABLE_GRAPHITE
     885             :     // check for features
     886           0 :     if ((rA.maTargetName.indexOf(grutils::GrFeatureParser::FEAT_PREFIX)
     887           0 :          != -1 ||
     888           0 :          rB.maTargetName.indexOf(grutils::GrFeatureParser::FEAT_PREFIX)
     889           0 :          != -1) && rA.maTargetName != rB.maTargetName)
     890           0 :         return false;
     891             : #endif
     892             : 
     893           0 :     if (rA.mbEmbolden != rB.mbEmbolden)
     894           0 :         return false;
     895             : 
     896           0 :     if (rA.maItalicMatrix != rB.maItalicMatrix)
     897           0 :         return false;
     898             : 
     899           0 :     return true;
     900             : }
     901             : 
     902           1 : ImplFontCache::ImplFontCache()
     903             : :   mpFirstEntry( NULL ),
     904           1 :     mnRef0Count( 0 )
     905           1 : {}
     906             : 
     907           2 : ImplFontCache::~ImplFontCache()
     908             : {
     909           1 :     FontInstanceList::iterator it = maFontInstanceList.begin();
     910           1 :     for(; it != maFontInstanceList.end(); ++it )
     911             :     {
     912           0 :         ImplFontEntry* pEntry = (*it).second;
     913           0 :         delete pEntry;
     914             :     }
     915           1 : }
     916             : 
     917           0 : ImplFontEntry* ImplFontCache::GetFontEntry( PhysicalFontCollection* pFontList,
     918             :     const Font& rFont, const Size& rSize, float fExactHeight )
     919             : {
     920           0 :     OUString aSearchName = rFont.GetName();
     921             : 
     922             :     // initialize internal font request object
     923           0 :     FontSelectPattern aFontSelData( rFont, aSearchName, rSize, fExactHeight );
     924           0 :     return GetFontEntry( pFontList, aFontSelData );
     925             : }
     926             : 
     927           0 : ImplFontEntry* ImplFontCache::GetFontEntry( PhysicalFontCollection* pFontList,
     928             :     FontSelectPattern& aFontSelData )
     929             : {
     930             :     // check if a directly matching logical font instance is already cached,
     931             :     // the most recently used font usually has a hit rate of >50%
     932           0 :     ImplFontEntry *pEntry = NULL;
     933           0 :     PhysicalFontFamily* pFontFamily = NULL;
     934             :     IFSD_Equal aIFSD_Equal;
     935           0 :     if( mpFirstEntry && aIFSD_Equal( aFontSelData, mpFirstEntry->maFontSelData ) )
     936           0 :         pEntry = mpFirstEntry;
     937             :     else
     938             :     {
     939           0 :         FontInstanceList::iterator it = maFontInstanceList.find( aFontSelData );
     940           0 :         if( it != maFontInstanceList.end() )
     941           0 :             pEntry = (*it).second;
     942             :     }
     943             : 
     944           0 :     if( !pEntry ) // no direct cache hit
     945             :     {
     946             :         // find the best matching logical font family and update font selector accordingly
     947           0 :         pFontFamily = pFontList->ImplFindByFont( aFontSelData );
     948             :         DBG_ASSERT( (pFontFamily != NULL), "ImplFontCache::Get() No logical font found!" );
     949           0 :         if( pFontFamily )
     950           0 :             aFontSelData.maSearchName = pFontFamily->GetSearchName();
     951             : 
     952             :         // check if an indirectly matching logical font instance is already cached
     953           0 :         FontInstanceList::iterator it = maFontInstanceList.find( aFontSelData );
     954           0 :         if( it != maFontInstanceList.end() )
     955             :         {
     956             :             // we have an indirect cache hit
     957           0 :             pEntry = (*it).second;
     958             :         }
     959             :     }
     960             : 
     961           0 :     PhysicalFontFace* pFontData = NULL;
     962             : 
     963           0 :     if (!pEntry && pFontFamily)// no cache hit => find the best matching physical font face
     964             :     {
     965           0 :         bool bOrigWasSymbol = aFontSelData.mpFontData && aFontSelData.mpFontData->IsSymbolFont();
     966           0 :         pFontData = pFontFamily->FindBestFontFace( aFontSelData );
     967           0 :         aFontSelData.mpFontData = pFontData;
     968           0 :         bool bNewIsSymbol = aFontSelData.mpFontData && aFontSelData.mpFontData->IsSymbolFont();
     969             : 
     970           0 :         if (bNewIsSymbol != bOrigWasSymbol)
     971             :         {
     972             :             // it is possible, though generally unlikely, that at this point we
     973             :             // will attempt to use a symbol font as a last-ditch fallback for a
     974             :             // non-symbol font request or vice versa, and by changing
     975             :             // aFontSelData.mpFontData to/from a symbol font we may now find
     976             :             // something in the cache that can be reused which previously
     977             :             // wasn't a candidate
     978           0 :             FontInstanceList::iterator it = maFontInstanceList.find( aFontSelData );
     979           0 :             if( it != maFontInstanceList.end() )
     980           0 :                 pEntry = (*it).second;
     981             :         }
     982             :     }
     983             : 
     984           0 :     if( pEntry ) // cache hit => use existing font instance
     985             :     {
     986             :         // increase the font instance's reference count
     987           0 :         if( !pEntry->mnRefCount++ )
     988           0 :             --mnRef0Count;
     989             :     }
     990             : 
     991           0 :     if (!pEntry && pFontData)// still no cache hit => create a new font instance
     992             :     {
     993             :         // create a new logical font instance from this physical font face
     994           0 :         pEntry = pFontData->CreateFontInstance( aFontSelData );
     995             : 
     996             :         // if we're subtituting from or to a symbol font we may need a symbol
     997             :         // conversion table
     998           0 :         if( pFontData->IsSymbolFont() || aFontSelData.IsSymbolFont() )
     999             :         {
    1000           0 :             if( aFontSelData.maTargetName != aFontSelData.maSearchName )
    1001           0 :                 pEntry->mpConversion = ConvertChar::GetRecodeData( aFontSelData.maTargetName, aFontSelData.maSearchName );
    1002             :         }
    1003             : 
    1004             : #ifdef MACOSX
    1005             :         //It might be better to dig out the font version of the target font
    1006             :         //to see if it's a modern re-coded apple symbol font in case that
    1007             :         //font shows up on a different platform
    1008             :         if (!pEntry->mpConversion &&
    1009             :             aFontSelData.maTargetName.equalsIgnoreAsciiCase("symbol") &&
    1010             :             aFontSelData.maSearchName.equalsIgnoreAsciiCase("symbol"))
    1011             :         {
    1012             :             pEntry->mpConversion = ConvertChar::GetRecodeData( OUString("Symbol"), OUString("AppleSymbol") );
    1013             :         }
    1014             : #endif
    1015             : 
    1016             :         // add the new entry to the cache
    1017           0 :         maFontInstanceList[ aFontSelData ] = pEntry;
    1018             :     }
    1019             : 
    1020           0 :     mpFirstEntry = pEntry;
    1021           0 :     return pEntry;
    1022             : }
    1023             : 
    1024           0 : ImplFontEntry* ImplFontCache::GetGlyphFallbackFont( PhysicalFontCollection* pFontCollection,
    1025             :     FontSelectPattern& rFontSelData, int nFallbackLevel, OUString& rMissingCodes )
    1026             : {
    1027             :     // get a candidate font for glyph fallback
    1028             :     // unless the previously selected font got a device specific substitution
    1029             :     // e.g. PsPrint Arial->Helvetica for udiaeresis when Helvetica doesn't support it
    1030           0 :     if( nFallbackLevel >= 1)
    1031             :     {
    1032           0 :         PhysicalFontFamily* pFallbackData = NULL;
    1033             : 
    1034             :         //fdo#33898 If someone has EUDC installed then they really want that to
    1035             :         //be used as the first-choice glyph fallback seeing as it's filled with
    1036             :         //private area codes with don't make any sense in any other font so
    1037             :         //prioritise it here if it's available. Ideally we would remove from
    1038             :         //rMissingCodes all the glyphs which it is able to resolve as an
    1039             :         //optimization, but that's tricky to achieve cross-platform without
    1040             :         //sufficient heavy-weight code that's likely to undo the value of the
    1041             :         //optimization
    1042           0 :         if (nFallbackLevel == 1)
    1043           0 :             pFallbackData = pFontCollection->FindFontFamily(OUString("EUDC"));
    1044           0 :         if (!pFallbackData)
    1045           0 :             pFallbackData = pFontCollection->GetGlyphFallbackFont(rFontSelData, rMissingCodes, nFallbackLevel-1);
    1046             :         // escape when there are no font candidates
    1047           0 :         if( !pFallbackData  )
    1048           0 :             return NULL;
    1049             :         // override the font name
    1050           0 :         rFontSelData.SetFamilyName( pFallbackData->GetFamilyName() );
    1051             :         // clear the cached normalized name
    1052           0 :         rFontSelData.maSearchName = "";
    1053             :     }
    1054             : 
    1055           0 :     ImplFontEntry* pFallbackFont = GetFontEntry( pFontCollection, rFontSelData );
    1056           0 :     return pFallbackFont;
    1057             : }
    1058             : 
    1059           0 : void ImplFontCache::Release( ImplFontEntry* pEntry )
    1060             : {
    1061             :     static const int FONTCACHE_MAX = 50;
    1062             : 
    1063             :     DBG_ASSERT( (pEntry->mnRefCount > 0), "ImplFontCache::Release() - font refcount underflow" );
    1064           0 :     if( --pEntry->mnRefCount > 0 )
    1065           0 :         return;
    1066             : 
    1067           0 :     if( ++mnRef0Count < FONTCACHE_MAX )
    1068           0 :         return;
    1069             : 
    1070             :     // remove unused entries from font instance cache
    1071           0 :     FontInstanceList::iterator it_next = maFontInstanceList.begin();
    1072           0 :     while( it_next != maFontInstanceList.end() )
    1073             :     {
    1074           0 :         FontInstanceList::iterator it = it_next++;
    1075           0 :         ImplFontEntry* pFontEntry = (*it).second;
    1076           0 :         if( pFontEntry->mnRefCount > 0 )
    1077           0 :             continue;
    1078             : 
    1079           0 :         maFontInstanceList.erase( it );
    1080           0 :         delete pFontEntry;
    1081           0 :         --mnRef0Count;
    1082             :         DBG_ASSERT( (mnRef0Count>=0), "ImplFontCache::Release() - refcount0 underflow" );
    1083             : 
    1084           0 :         if( mpFirstEntry == pFontEntry )
    1085           0 :             mpFirstEntry = NULL;
    1086             :     }
    1087             : 
    1088             :     DBG_ASSERT( (mnRef0Count==0), "ImplFontCache::Release() - refcount0 mismatch" );
    1089             : }
    1090             : 
    1091           0 : void ImplFontCache::Invalidate()
    1092             : {
    1093             :     // delete unreferenced entries
    1094           0 :     FontInstanceList::iterator it = maFontInstanceList.begin();
    1095           0 :     for(; it != maFontInstanceList.end(); ++it )
    1096             :     {
    1097           0 :         ImplFontEntry* pFontEntry = (*it).second;
    1098           0 :         if( pFontEntry->mnRefCount > 0 )
    1099           0 :             continue;
    1100             : 
    1101           0 :         delete pFontEntry;
    1102           0 :         --mnRef0Count;
    1103             :     }
    1104             : 
    1105             :     // #112304# make sure the font cache is really clean
    1106           0 :     mpFirstEntry = NULL;
    1107           0 :     maFontInstanceList.clear();
    1108             : 
    1109             :     DBG_ASSERT( (mnRef0Count==0), "ImplFontCache::Invalidate() - mnRef0Count non-zero" );
    1110           0 : }
    1111             : 
    1112           0 : ImplMultiTextLineInfo::ImplMultiTextLineInfo()
    1113             : {
    1114           0 :     mpLines = new PImplTextLineInfo[MULTITEXTLINEINFO_RESIZE];
    1115           0 :     mnLines = 0;
    1116           0 :     mnSize  = MULTITEXTLINEINFO_RESIZE;
    1117           0 : }
    1118             : 
    1119           0 : ImplMultiTextLineInfo::~ImplMultiTextLineInfo()
    1120             : {
    1121           0 :     for( sal_Int32 i = 0; i < mnLines; i++ )
    1122           0 :         delete mpLines[i];
    1123           0 :     delete [] mpLines;
    1124           0 : }
    1125             : 
    1126           0 : void ImplMultiTextLineInfo::AddLine( ImplTextLineInfo* pLine )
    1127             : {
    1128           0 :     if ( mnSize == mnLines )
    1129             :     {
    1130           0 :         mnSize += MULTITEXTLINEINFO_RESIZE;
    1131           0 :         PImplTextLineInfo* pNewLines = new PImplTextLineInfo[mnSize];
    1132           0 :         memcpy( pNewLines, mpLines, mnLines*sizeof(PImplTextLineInfo) );
    1133           0 :         mpLines = pNewLines;
    1134             :     }
    1135             : 
    1136           0 :     mpLines[mnLines] = pLine;
    1137           0 :     mnLines++;
    1138           0 : }
    1139             : 
    1140           0 : void ImplMultiTextLineInfo::Clear()
    1141             : {
    1142           0 :     for( sal_Int32 i = 0; i < mnLines; i++ )
    1143           0 :         delete mpLines[i];
    1144           0 :     mnLines = 0;
    1145           0 : }
    1146             : 
    1147           0 : FontEmphasisMark OutputDevice::ImplGetEmphasisMarkStyle( const Font& rFont )
    1148             : {
    1149           0 :     FontEmphasisMark nEmphasisMark = rFont.GetEmphasisMark();
    1150             : 
    1151             :     // If no Position is set, then calculate the default position, which
    1152             :     // depends on the language
    1153           0 :     if ( !(nEmphasisMark & (EMPHASISMARK_POS_ABOVE | EMPHASISMARK_POS_BELOW)) )
    1154             :     {
    1155           0 :         LanguageType eLang = rFont.GetLanguage();
    1156             :         // In Chinese Simplified the EmphasisMarks are below/left
    1157           0 :         if (MsLangId::isSimplifiedChinese(eLang))
    1158           0 :             nEmphasisMark |= EMPHASISMARK_POS_BELOW;
    1159             :         else
    1160             :         {
    1161           0 :             eLang = rFont.GetCJKContextLanguage();
    1162             :             // In Chinese Simplified the EmphasisMarks are below/left
    1163           0 :             if (MsLangId::isSimplifiedChinese(eLang))
    1164           0 :                 nEmphasisMark |= EMPHASISMARK_POS_BELOW;
    1165             :             else
    1166           0 :                 nEmphasisMark |= EMPHASISMARK_POS_ABOVE;
    1167             :         }
    1168             :     }
    1169             : 
    1170           0 :     return nEmphasisMark;
    1171             : }
    1172             : 
    1173           0 : bool OutputDevice::ImplIsUnderlineAbove( const Font& rFont )
    1174             : {
    1175           0 :     if ( !rFont.IsVertical() )
    1176           0 :         return false;
    1177             : 
    1178           0 :     if( (LANGUAGE_JAPANESE == rFont.GetLanguage())
    1179           0 :     ||  (LANGUAGE_JAPANESE == rFont.GetCJKContextLanguage()) )
    1180             :         // the underline is right for Japanese only
    1181           0 :         return true;
    1182             : 
    1183           0 :     return false;
    1184             : }
    1185             : 
    1186           0 : void OutputDevice::ImplInitFontList() const
    1187             : {
    1188           0 :     if( !mpFontCollection->Count() )
    1189             :     {
    1190           0 :         if( mpGraphics || ImplGetGraphics() )
    1191             :         {
    1192             :             SAL_INFO( "vcl.gdi", "OutputDevice::ImplInitFontList()" );
    1193           0 :             mpGraphics->GetDevFontList( mpFontCollection );
    1194             : 
    1195             :             // There is absolutely no way there should be no fonts available on the device
    1196           0 :             if( !mpFontCollection->Count() )
    1197             :             {
    1198           0 :                 OUString aError( "Application error: no fonts and no vcl resource found on your system" );
    1199           0 :                 ResMgr* pMgr = ImplGetResMgr();
    1200           0 :                 if( pMgr )
    1201             :                 {
    1202           0 :                     OUString aResStr(ResId(SV_ACCESSERROR_NO_FONTS, *pMgr).toString());
    1203           0 :                     if( !aResStr.isEmpty() )
    1204           0 :                         aError = aResStr;
    1205             :                 }
    1206           0 :                 Application::Abort( aError );
    1207             :             }
    1208             :         }
    1209             :     }
    1210           0 : }
    1211             : 
    1212           0 : void OutputDevice::ImplInitFont() const
    1213             : {
    1214             :     DBG_TESTSOLARMUTEX();
    1215             : 
    1216           0 :     if (!mpFontEntry)
    1217           0 :         return;
    1218             : 
    1219           0 :     if ( mbInitFont )
    1220             :     {
    1221           0 :         if ( meOutDevType != OUTDEV_PRINTER )
    1222             :         {
    1223             :             // decide if antialiasing is appropriate
    1224           0 :             bool bNonAntialiased = (GetAntialiasing() & ANTIALIASING_DISABLE_TEXT) != 0;
    1225           0 :             const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
    1226           0 :             bNonAntialiased |= ((rStyleSettings.GetDisplayOptions() & DISPLAY_OPTION_AA_DISABLE) != 0);
    1227           0 :             bNonAntialiased |= (int(rStyleSettings.GetAntialiasingMinPixelHeight()) > mpFontEntry->maFontSelData.mnHeight);
    1228           0 :             mpFontEntry->maFontSelData.mbNonAntialiased = bNonAntialiased;
    1229             :         }
    1230             : 
    1231             :         // select font in the device layers
    1232           0 :         mpFontEntry->mnSetFontFlags = mpGraphics->SetFont( &(mpFontEntry->maFontSelData), 0 );
    1233           0 :         mbInitFont = false;
    1234             :     }
    1235             : }
    1236             : 
    1237           0 : void OutputDevice::ImplInitTextColor()
    1238             : {
    1239             :     DBG_TESTSOLARMUTEX();
    1240             : 
    1241           0 :     if ( mbInitTextColor )
    1242             :     {
    1243           0 :         mpGraphics->SetTextColor( ImplColorToSal( GetTextColor() ) );
    1244           0 :         mbInitTextColor = false;
    1245             :     }
    1246           0 : }
    1247             : 
    1248           0 : bool OutputDevice::ImplNewFont() const
    1249             : {
    1250             :     DBG_TESTSOLARMUTEX();
    1251             : 
    1252             :     // get correct font list on the PDF writer if necessary
    1253           0 :     if( mpPDFWriter )
    1254             :     {
    1255           0 :         const ImplSVData* pSVData = ImplGetSVData();
    1256           0 :         if( mpFontCollection == pSVData->maGDIData.mpScreenFontList
    1257           0 :         ||  mpFontCache == pSVData->maGDIData.mpScreenFontCache )
    1258           0 :             const_cast<OutputDevice&>(*this).ImplUpdateFontData( true );
    1259             :     }
    1260             : 
    1261           0 :     if ( !mbNewFont )
    1262           0 :         return true;
    1263             : 
    1264             :     // we need a graphics
    1265           0 :     if ( !mpGraphics && !ImplGetGraphics() )
    1266           0 :         return false;
    1267           0 :     SalGraphics* pGraphics = mpGraphics;
    1268           0 :     ImplInitFontList();
    1269             : 
    1270             :     // convert to pixel height
    1271             :     // TODO: replace integer based aSize completely with subpixel accurate type
    1272           0 :     float fExactHeight = ImplFloatLogicHeightToDevicePixel( static_cast<float>(maFont.GetHeight()) );
    1273           0 :     Size aSize = ImplLogicToDevicePixel( maFont.GetSize() );
    1274           0 :     if ( !aSize.Height() )
    1275             :     {
    1276             :         // use default pixel height only when logical height is zero
    1277           0 :         if ( maFont.GetSize().Height() )
    1278           0 :             aSize.Height() = 1;
    1279             :         else
    1280           0 :             aSize.Height() = (12*mnDPIY)/72;
    1281           0 :         fExactHeight =  static_cast<float>(aSize.Height());
    1282             :     }
    1283             : 
    1284             :     // select the default width only when logical width is zero
    1285           0 :     if( (0 == aSize.Width()) && (0 != maFont.GetSize().Width()) )
    1286           0 :         aSize.Width() = 1;
    1287             : 
    1288             :     // get font entry
    1289           0 :     ImplFontEntry* pOldEntry = mpFontEntry;
    1290           0 :     mpFontEntry = mpFontCache->GetFontEntry( mpFontCollection, maFont, aSize, fExactHeight );
    1291           0 :     if( pOldEntry )
    1292           0 :         mpFontCache->Release( pOldEntry );
    1293             : 
    1294           0 :     ImplFontEntry* pFontEntry = mpFontEntry;
    1295             : 
    1296           0 :     if (!pFontEntry)
    1297           0 :         return false;
    1298             : 
    1299             :     // mark when lower layers need to get involved
    1300           0 :     mbNewFont = false;
    1301           0 :     if( pFontEntry != pOldEntry )
    1302           0 :         mbInitFont = true;
    1303             : 
    1304             :     // select font when it has not been initialized yet
    1305           0 :     if ( !pFontEntry->mbInit )
    1306             :     {
    1307           0 :         ImplInitFont();
    1308             : 
    1309             :         // get metric data from device layers
    1310           0 :         if ( pGraphics )
    1311             :         {
    1312           0 :             pFontEntry->mbInit = true;
    1313             : 
    1314           0 :             pFontEntry->maMetric.mnOrientation  = sal::static_int_cast<short>(pFontEntry->maFontSelData.mnOrientation);
    1315           0 :             pGraphics->GetFontMetric( &(pFontEntry->maMetric) );
    1316             : 
    1317           0 :             pFontEntry->maMetric.ImplInitTextLineSize( this );
    1318           0 :             pFontEntry->maMetric.ImplInitAboveTextLineSize();
    1319             : 
    1320           0 :             pFontEntry->mnLineHeight = pFontEntry->maMetric.mnAscent + pFontEntry->maMetric.mnDescent;
    1321             : 
    1322           0 :             if( pFontEntry->maFontSelData.mnOrientation
    1323           0 :             && !pFontEntry->maMetric.mnOrientation
    1324           0 :             && (meOutDevType != OUTDEV_PRINTER) )
    1325             :             {
    1326           0 :                 pFontEntry->mnOwnOrientation = sal::static_int_cast<short>(pFontEntry->maFontSelData.mnOrientation);
    1327           0 :                 pFontEntry->mnOrientation = pFontEntry->mnOwnOrientation;
    1328             :             }
    1329             :             else
    1330           0 :                 pFontEntry->mnOrientation = pFontEntry->maMetric.mnOrientation;
    1331             :         }
    1332             :     }
    1333             : 
    1334             :     // enable kerning array if requested
    1335           0 :     if ( maFont.GetKerning() & KERNING_FONTSPECIFIC )
    1336             :     {
    1337             :         // TODO: test if physical font supports kerning and disable if not
    1338           0 :         if( pFontEntry->maMetric.mbKernableFont )
    1339           0 :             mbKerning = true;
    1340             :     }
    1341             :     else
    1342           0 :         mbKerning = false;
    1343           0 :     if ( maFont.GetKerning() & KERNING_ASIAN )
    1344           0 :         mbKerning = true;
    1345             : 
    1346             :     // calculate EmphasisArea
    1347           0 :     mnEmphasisAscent = 0;
    1348           0 :     mnEmphasisDescent = 0;
    1349           0 :     if ( maFont.GetEmphasisMark() & EMPHASISMARK_STYLE )
    1350             :     {
    1351           0 :         FontEmphasisMark    nEmphasisMark = ImplGetEmphasisMarkStyle( maFont );
    1352           0 :         long                nEmphasisHeight = (pFontEntry->mnLineHeight*250)/1000;
    1353           0 :         if ( nEmphasisHeight < 1 )
    1354           0 :             nEmphasisHeight = 1;
    1355           0 :         if ( nEmphasisMark & EMPHASISMARK_POS_BELOW )
    1356           0 :             mnEmphasisDescent = nEmphasisHeight;
    1357             :         else
    1358           0 :             mnEmphasisAscent = nEmphasisHeight;
    1359             :     }
    1360             : 
    1361             :     // calculate text offset depending on TextAlignment
    1362           0 :     TextAlign eAlign = maFont.GetAlign();
    1363           0 :     if ( eAlign == ALIGN_BASELINE )
    1364             :     {
    1365           0 :         mnTextOffX = 0;
    1366           0 :         mnTextOffY = 0;
    1367             :     }
    1368           0 :     else if ( eAlign == ALIGN_TOP )
    1369             :     {
    1370           0 :         mnTextOffX = 0;
    1371           0 :         mnTextOffY = +pFontEntry->maMetric.mnAscent + mnEmphasisAscent;
    1372           0 :         if ( pFontEntry->mnOrientation )
    1373           0 :             ImplRotatePos( 0, 0, mnTextOffX, mnTextOffY, pFontEntry->mnOrientation );
    1374             :     }
    1375             :     else // eAlign == ALIGN_BOTTOM
    1376             :     {
    1377           0 :         mnTextOffX = 0;
    1378           0 :         mnTextOffY = -pFontEntry->maMetric.mnDescent + mnEmphasisDescent;
    1379           0 :         if ( pFontEntry->mnOrientation )
    1380           0 :             ImplRotatePos( 0, 0, mnTextOffX, mnTextOffY, pFontEntry->mnOrientation );
    1381             :     }
    1382             : 
    1383           0 :     mbTextLines     = ((maFont.GetUnderline() != UNDERLINE_NONE) && (maFont.GetUnderline() != UNDERLINE_DONTKNOW)) ||
    1384           0 :                       ((maFont.GetOverline()  != UNDERLINE_NONE) && (maFont.GetOverline()  != UNDERLINE_DONTKNOW)) ||
    1385           0 :                       ((maFont.GetStrikeout() != STRIKEOUT_NONE) && (maFont.GetStrikeout() != STRIKEOUT_DONTKNOW));
    1386           0 :     mbTextSpecial   = maFont.IsShadow() || maFont.IsOutline() ||
    1387           0 :                       (maFont.GetRelief() != RELIEF_NONE);
    1388             : 
    1389             :     // #95414# fix for OLE objects which use scale factors very creatively
    1390           0 :     if( mbMap && !aSize.Width() )
    1391             :     {
    1392           0 :         int nOrigWidth = pFontEntry->maMetric.mnWidth;
    1393           0 :         float fStretch = (float)maMapRes.mnMapScNumX * maMapRes.mnMapScDenomY;
    1394           0 :         fStretch /= (float)maMapRes.mnMapScNumY * maMapRes.mnMapScDenomX;
    1395           0 :         int nNewWidth = (int)(nOrigWidth * fStretch + 0.5);
    1396           0 :         if( (nNewWidth != nOrigWidth) && (nNewWidth != 0) )
    1397             :         {
    1398           0 :             Size aOrigSize = maFont.GetSize();
    1399           0 :             const_cast<Font&>(maFont).SetSize( Size( nNewWidth, aSize.Height() ) );
    1400           0 :             mbMap = false;
    1401           0 :             mbNewFont = true;
    1402           0 :             ImplNewFont();  // recurse once using stretched width
    1403           0 :             mbMap = true;
    1404           0 :             const_cast<Font&>(maFont).SetSize( aOrigSize );
    1405             :         }
    1406             :     }
    1407             : 
    1408           0 :     return true;
    1409             : }
    1410             : 
    1411           0 : void OutputDevice::ImplDrawTextRect( long nBaseX, long nBaseY,
    1412             :                                      long nDistX, long nDistY, long nWidth, long nHeight )
    1413             : {
    1414           0 :     long nX = nDistX;
    1415           0 :     long nY = nDistY;
    1416             : 
    1417           0 :     short nOrientation = mpFontEntry->mnOrientation;
    1418           0 :     if ( nOrientation )
    1419             :     {
    1420             :         // Rotate rect without rounding problems for 90 degree rotations
    1421           0 :         if ( !(nOrientation % 900) )
    1422             :         {
    1423           0 :             if ( nOrientation == 900 )
    1424             :             {
    1425           0 :                 long nTemp = nX;
    1426           0 :                 nX = nY;
    1427           0 :                 nY = -nTemp;
    1428           0 :                 nTemp = nWidth;
    1429           0 :                 nWidth = nHeight;
    1430           0 :                 nHeight = nTemp;
    1431           0 :                 nY -= nHeight;
    1432             :             }
    1433           0 :             else if ( nOrientation == 1800 )
    1434             :             {
    1435           0 :                 nX = -nX;
    1436           0 :                 nY = -nY;
    1437           0 :                 nX -= nWidth;
    1438           0 :                 nY -= nHeight;
    1439             :             }
    1440             :             else /* ( nOrientation == 2700 ) */
    1441             :             {
    1442           0 :                 long nTemp = nX;
    1443           0 :                 nX = -nY;
    1444           0 :                 nY = nTemp;
    1445           0 :                 nTemp = nWidth;
    1446           0 :                 nWidth = nHeight;
    1447           0 :                 nHeight = nTemp;
    1448           0 :                 nX -= nWidth;
    1449             :             }
    1450             :         }
    1451             :         else
    1452             :         {
    1453           0 :             nX += nBaseX;
    1454           0 :             nY += nBaseY;
    1455             :             // inflate because polygons are drawn smaller
    1456           0 :             Rectangle aRect( Point( nX, nY ), Size( nWidth+1, nHeight+1 ) );
    1457           0 :             Polygon   aPoly( aRect );
    1458           0 :             aPoly.Rotate( Point( nBaseX, nBaseY ), mpFontEntry->mnOrientation );
    1459           0 :             ImplDrawPolygon( aPoly );
    1460           0 :             return;
    1461             :         }
    1462             :     }
    1463             : 
    1464           0 :     nX += nBaseX;
    1465           0 :     nY += nBaseY;
    1466           0 :     mpGraphics->DrawRect( nX, nY, nWidth, nHeight, this );
    1467             : }
    1468             : 
    1469           0 : void OutputDevice::ImplDrawTextBackground( const SalLayout& rSalLayout )
    1470             : {
    1471           0 :     const long nWidth = rSalLayout.GetTextWidth() / rSalLayout.GetUnitsPerPixel();
    1472           0 :     const Point aBase = rSalLayout.DrawBase();
    1473           0 :     const long nX = aBase.X();
    1474           0 :     const long nY = aBase.Y();
    1475             : 
    1476           0 :     if ( mbLineColor || mbInitLineColor )
    1477             :     {
    1478           0 :         mpGraphics->SetLineColor();
    1479           0 :         mbInitLineColor = true;
    1480             :     }
    1481           0 :     mpGraphics->SetFillColor( ImplColorToSal( GetTextFillColor() ) );
    1482           0 :     mbInitFillColor = true;
    1483             : 
    1484           0 :     ImplDrawTextRect( nX, nY, 0, -(mpFontEntry->maMetric.mnAscent + mnEmphasisAscent),
    1485             :                       nWidth,
    1486           0 :                       mpFontEntry->mnLineHeight+mnEmphasisAscent+mnEmphasisDescent );
    1487           0 : }
    1488             : 
    1489           0 : Rectangle OutputDevice::ImplGetTextBoundRect( const SalLayout& rSalLayout )
    1490             : {
    1491           0 :     Point aPoint = rSalLayout.GetDrawPosition();
    1492           0 :     long nX = aPoint.X();
    1493           0 :     long nY = aPoint.Y();
    1494             : 
    1495           0 :     long nWidth = rSalLayout.GetTextWidth();
    1496           0 :     long nHeight = mpFontEntry->mnLineHeight + mnEmphasisAscent + mnEmphasisDescent;
    1497             : 
    1498           0 :     nY -= mpFontEntry->maMetric.mnAscent + mnEmphasisAscent;
    1499             : 
    1500           0 :     if ( mpFontEntry->mnOrientation )
    1501             :     {
    1502           0 :         long nBaseX = nX, nBaseY = nY;
    1503           0 :         if ( !(mpFontEntry->mnOrientation % 900) )
    1504             :         {
    1505           0 :             long nX2 = nX+nWidth;
    1506           0 :             long nY2 = nY+nHeight;
    1507           0 :             ImplRotatePos( nBaseX, nBaseY, nX, nY, mpFontEntry->mnOrientation );
    1508           0 :             ImplRotatePos( nBaseX, nBaseY, nX2, nY2, mpFontEntry->mnOrientation );
    1509           0 :             nWidth = nX2-nX;
    1510           0 :             nHeight = nY2-nY;
    1511             :         }
    1512             :         else
    1513             :         {
    1514             :             // inflate by +1+1 because polygons are drawn smaller
    1515           0 :             Rectangle aRect( Point( nX, nY ), Size( nWidth+1, nHeight+1 ) );
    1516           0 :             Polygon   aPoly( aRect );
    1517           0 :             aPoly.Rotate( Point( nBaseX, nBaseY ), mpFontEntry->mnOrientation );
    1518           0 :             return aPoly.GetBoundRect();
    1519             :         }
    1520             :     }
    1521             : 
    1522           0 :     return Rectangle( Point( nX, nY ), Size( nWidth, nHeight ) );
    1523             : }
    1524             : 
    1525           0 : void OutputDevice::ImplInitTextLineSize()
    1526             : {
    1527           0 :     mpFontEntry->maMetric.ImplInitTextLineSize( this );
    1528           0 : }
    1529             : 
    1530           0 : void OutputDevice::ImplInitAboveTextLineSize()
    1531             : {
    1532           0 :     mpFontEntry->maMetric.ImplInitAboveTextLineSize();
    1533           0 : }
    1534             : 
    1535           0 : bool ImplFontAttributes::operator==(const ImplFontAttributes& rOther) const
    1536             : {
    1537           0 :     if (maName != rOther.maName)
    1538           0 :         return false;
    1539             : 
    1540           0 :     if (maStyleName != rOther.maStyleName)
    1541           0 :         return false;
    1542             : 
    1543           0 :     if (meWeight != rOther.meWeight)
    1544           0 :         return false;
    1545             : 
    1546           0 :     if (meItalic != rOther.meItalic)
    1547           0 :         return false;
    1548             : 
    1549           0 :     if (meFamily != rOther.meFamily)
    1550           0 :         return false;
    1551             : 
    1552           0 :     if (mePitch != rOther.mePitch)
    1553           0 :         return false;
    1554             : 
    1555           0 :     if (meWidthType != rOther.meWidthType)
    1556           0 :         return false;
    1557             : 
    1558           0 :     if (mbSymbolFlag != rOther.mbSymbolFlag)
    1559           0 :         return false;
    1560             : 
    1561           0 :     return true;
    1562             : }
    1563             : 
    1564           0 : ImplFontMetricData::ImplFontMetricData( const FontSelectPattern& rFontSelData )
    1565             :     : ImplFontAttributes( rFontSelData )
    1566             :     , mnWidth ( rFontSelData.mnWidth)
    1567             :     , mnOrientation( (short)(rFontSelData.mnOrientation))
    1568             :     , mnAscent( 0 )
    1569             :     , mnDescent( 0 )
    1570             :     , mnIntLeading( 0 )
    1571             :     , mnExtLeading( 0 )
    1572             :     , mnSlant( 0 )
    1573             :     , mnMinKashida( 0 )
    1574             :     , mnUnderlineSize( 0 )
    1575             :     , mnUnderlineOffset( 0 )
    1576             :     , mnBUnderlineSize( 0 )
    1577             :     , mnBUnderlineOffset( 0 )
    1578             :     , mnDUnderlineSize( 0 )
    1579             :     , mnDUnderlineOffset1( 0 )
    1580             :     , mnDUnderlineOffset2( 0 )
    1581             :     , mnWUnderlineSize( 0 )
    1582             :     , mnWUnderlineOffset( 0 )
    1583             :     , mnAboveUnderlineSize( 0 )
    1584             :     , mnAboveUnderlineOffset( 0 )
    1585             :     , mnAboveBUnderlineSize( 0 )
    1586             :     , mnAboveBUnderlineOffset( 0 )
    1587             :     , mnAboveDUnderlineSize( 0 )
    1588             :     , mnAboveDUnderlineOffset1( 0 )
    1589             :     , mnAboveDUnderlineOffset2( 0 )
    1590             :     , mnAboveWUnderlineSize( 0 )
    1591             :     , mnAboveWUnderlineOffset( 0 )
    1592             :     , mnStrikeoutSize( 0 )
    1593             :     , mnStrikeoutOffset( 0 )
    1594             :     , mnBStrikeoutSize( 0 )
    1595             :     , mnBStrikeoutOffset( 0 )
    1596             :     , mnDStrikeoutSize( 0 )
    1597             :     , mnDStrikeoutOffset1( 0 )
    1598           0 :     , mnDStrikeoutOffset2( 0 )
    1599             : {
    1600             :     // intialize the used font name
    1601           0 :     if( rFontSelData.mpFontData )
    1602             :     {
    1603           0 :         SetFamilyName( rFontSelData.mpFontData->GetFamilyName() );
    1604           0 :         SetStyleName( rFontSelData.mpFontData->GetStyleName() );
    1605           0 :         mbDevice   = rFontSelData.mpFontData->mbDevice;
    1606           0 :         mbKernableFont = true;
    1607             :     }
    1608             :     else
    1609             :     {
    1610           0 :         sal_Int32 nTokenPos = 0;
    1611           0 :         SetFamilyName( GetNextFontToken( rFontSelData.GetFamilyName(), nTokenPos ) );
    1612           0 :         SetStyleName( rFontSelData.GetStyleName() );
    1613           0 :         mbDevice   = false;
    1614           0 :         mbKernableFont = false;
    1615             :     }
    1616           0 : }
    1617             : 
    1618           0 : void ImplFontMetricData::ImplInitTextLineSize( const OutputDevice* pDev )
    1619             : {
    1620           0 :     long nDescent = mnDescent;
    1621           0 :     if ( nDescent <= 0 )
    1622             :     {
    1623           0 :         nDescent = mnAscent / 10;
    1624           0 :         if ( !nDescent )
    1625           0 :             nDescent = 1;
    1626             :     }
    1627             : 
    1628             :     // #i55341# for some fonts it is not a good idea to calculate
    1629             :     // their text line metrics from the real font descent
    1630             :     // => work around this problem just for these fonts
    1631           0 :     if( 3*nDescent > mnAscent )
    1632           0 :         nDescent = mnAscent / 3;
    1633             : 
    1634           0 :     long nLineHeight = ((nDescent*25)+50) / 100;
    1635           0 :     if ( !nLineHeight )
    1636           0 :         nLineHeight = 1;
    1637           0 :     long nLineHeight2 = nLineHeight / 2;
    1638           0 :     if ( !nLineHeight2 )
    1639           0 :         nLineHeight2 = 1;
    1640             : 
    1641           0 :     long nBLineHeight = ((nDescent*50)+50) / 100;
    1642           0 :     if ( nBLineHeight == nLineHeight )
    1643           0 :         nBLineHeight++;
    1644           0 :     long nBLineHeight2 = nBLineHeight/2;
    1645           0 :     if ( !nBLineHeight2 )
    1646           0 :         nBLineHeight2 = 1;
    1647             : 
    1648           0 :     long n2LineHeight = ((nDescent*16)+50) / 100;
    1649           0 :     if ( !n2LineHeight )
    1650           0 :         n2LineHeight = 1;
    1651           0 :     long n2LineDY = n2LineHeight;
    1652             :      /* #117909#
    1653             :       * add some pixels to minimum double line distance on higher resolution devices
    1654             :       */
    1655           0 :     long nMin2LineDY = 1 + pDev->ImplGetDPIY()/150;
    1656           0 :     if ( n2LineDY < nMin2LineDY )
    1657           0 :         n2LineDY = nMin2LineDY;
    1658           0 :     long n2LineDY2 = n2LineDY/2;
    1659           0 :     if ( !n2LineDY2 )
    1660           0 :         n2LineDY2 = 1;
    1661             : 
    1662           0 :     long nUnderlineOffset = mnDescent/2 + 1;
    1663           0 :     long nStrikeoutOffset = -((mnAscent - mnIntLeading) / 3);
    1664             : 
    1665           0 :     mnUnderlineSize        = nLineHeight;
    1666           0 :     mnUnderlineOffset      = nUnderlineOffset - nLineHeight2;
    1667             : 
    1668           0 :     mnBUnderlineSize       = nBLineHeight;
    1669           0 :     mnBUnderlineOffset     = nUnderlineOffset - nBLineHeight2;
    1670             : 
    1671           0 :     mnDUnderlineSize       = n2LineHeight;
    1672           0 :     mnDUnderlineOffset1    = nUnderlineOffset - n2LineDY2 - n2LineHeight;
    1673           0 :     mnDUnderlineOffset2    = mnDUnderlineOffset1 + n2LineDY + n2LineHeight;
    1674             : 
    1675           0 :     long nWCalcSize = mnDescent;
    1676           0 :     if ( nWCalcSize < 6 )
    1677             :     {
    1678           0 :         if ( (nWCalcSize == 1) || (nWCalcSize == 2) )
    1679           0 :             mnWUnderlineSize = nWCalcSize;
    1680             :         else
    1681           0 :             mnWUnderlineSize = 3;
    1682             :     }
    1683             :     else
    1684           0 :         mnWUnderlineSize = ((nWCalcSize*50)+50) / 100;
    1685             : 
    1686             :     // #109280# the following line assures that wavelnes are never placed below the descent, however
    1687             :     // for most fonts the waveline then is drawn into the text, so we better keep the old solution
    1688             :     // pFontEntry->maMetric.mnWUnderlineOffset     = pFontEntry->maMetric.mnDescent + 1 - pFontEntry->maMetric.mnWUnderlineSize;
    1689           0 :     mnWUnderlineOffset     = nUnderlineOffset;
    1690             : 
    1691           0 :     mnStrikeoutSize        = nLineHeight;
    1692           0 :     mnStrikeoutOffset      = nStrikeoutOffset - nLineHeight2;
    1693             : 
    1694           0 :     mnBStrikeoutSize       = nBLineHeight;
    1695           0 :     mnBStrikeoutOffset     = nStrikeoutOffset - nBLineHeight2;
    1696             : 
    1697           0 :     mnDStrikeoutSize       = n2LineHeight;
    1698           0 :     mnDStrikeoutOffset1    = nStrikeoutOffset - n2LineDY2 - n2LineHeight;
    1699           0 :     mnDStrikeoutOffset2    = mnDStrikeoutOffset1 + n2LineDY + n2LineHeight;
    1700           0 : }
    1701             : 
    1702           0 : void ImplFontMetricData::ImplInitAboveTextLineSize()
    1703             : {
    1704           0 :     long nIntLeading = mnIntLeading;
    1705             :     // TODO: assess usage of nLeading below (changed in extleading CWS)
    1706             :     // if no leading is available, we assume 15% of the ascent
    1707           0 :     if ( nIntLeading <= 0 )
    1708             :     {
    1709           0 :         nIntLeading = mnAscent*15/100;
    1710           0 :         if ( !nIntLeading )
    1711           0 :             nIntLeading = 1;
    1712             :     }
    1713             : 
    1714           0 :     long nLineHeight = ((nIntLeading*25)+50) / 100;
    1715           0 :     if ( !nLineHeight )
    1716           0 :         nLineHeight = 1;
    1717             : 
    1718           0 :     long nBLineHeight = ((nIntLeading*50)+50) / 100;
    1719           0 :     if ( nBLineHeight == nLineHeight )
    1720           0 :         nBLineHeight++;
    1721             : 
    1722           0 :     long n2LineHeight = ((nIntLeading*16)+50) / 100;
    1723           0 :     if ( !n2LineHeight )
    1724           0 :         n2LineHeight = 1;
    1725             : 
    1726           0 :     long nCeiling = -mnAscent;
    1727             : 
    1728           0 :     mnAboveUnderlineSize       = nLineHeight;
    1729           0 :     mnAboveUnderlineOffset     = nCeiling + (nIntLeading - nLineHeight + 1) / 2;
    1730             : 
    1731           0 :     mnAboveBUnderlineSize      = nBLineHeight;
    1732           0 :     mnAboveBUnderlineOffset    = nCeiling + (nIntLeading - nBLineHeight + 1) / 2;
    1733             : 
    1734           0 :     mnAboveDUnderlineSize      = n2LineHeight;
    1735           0 :     mnAboveDUnderlineOffset1   = nCeiling + (nIntLeading - 3*n2LineHeight + 1) / 2;
    1736           0 :     mnAboveDUnderlineOffset2   = nCeiling + (nIntLeading +   n2LineHeight + 1) / 2;
    1737             : 
    1738           0 :     long nWCalcSize = nIntLeading;
    1739           0 :     if ( nWCalcSize < 6 )
    1740             :     {
    1741           0 :         if ( (nWCalcSize == 1) || (nWCalcSize == 2) )
    1742           0 :             mnAboveWUnderlineSize = nWCalcSize;
    1743             :         else
    1744           0 :             mnAboveWUnderlineSize = 3;
    1745             :     }
    1746             :     else
    1747           0 :         mnAboveWUnderlineSize = ((nWCalcSize*50)+50) / 100;
    1748             : 
    1749           0 :     mnAboveWUnderlineOffset = nCeiling + (nIntLeading + 1) / 2;
    1750           0 : }
    1751             : 
    1752           0 : static void ImplDrawWavePixel( long nOriginX, long nOriginY,
    1753             :                                long nCurX, long nCurY,
    1754             :                                short nOrientation,
    1755             :                                SalGraphics* pGraphics,
    1756             :                                OutputDevice* pOutDev,
    1757             :                                bool bDrawPixAsRect,
    1758             : 
    1759             :                                long nPixWidth, long nPixHeight )
    1760             : {
    1761           0 :     if ( nOrientation )
    1762           0 :         ImplRotatePos( nOriginX, nOriginY, nCurX, nCurY, nOrientation );
    1763             : 
    1764           0 :     if ( bDrawPixAsRect )
    1765             :     {
    1766             : 
    1767           0 :         pGraphics->DrawRect( nCurX, nCurY, nPixWidth, nPixHeight, pOutDev );
    1768             :     }
    1769             :     else
    1770             :     {
    1771           0 :         pGraphics->DrawPixel( nCurX, nCurY, pOutDev );
    1772             :     }
    1773           0 : }
    1774             : 
    1775           0 : void OutputDevice::ImplDrawWaveLine( long nBaseX, long nBaseY,
    1776             :                                      long nDistX, long nDistY,
    1777             :                                      long nWidth, long nHeight,
    1778             :                                      long nLineWidth, short nOrientation,
    1779             :                                      const Color& rColor )
    1780             : {
    1781           0 :     if ( !nHeight )
    1782           0 :         return;
    1783             : 
    1784           0 :     long nStartX = nBaseX + nDistX;
    1785           0 :     long nStartY = nBaseY + nDistY;
    1786             : 
    1787             :     // If the height is 1 pixel, it's enough ouput a line
    1788           0 :     if ( (nLineWidth == 1) && (nHeight == 1) )
    1789             :     {
    1790           0 :         mpGraphics->SetLineColor( ImplColorToSal( rColor ) );
    1791           0 :         mbInitLineColor = true;
    1792             : 
    1793           0 :         long nEndX = nStartX+nWidth;
    1794           0 :         long nEndY = nStartY;
    1795           0 :         if ( nOrientation )
    1796             :         {
    1797           0 :             ImplRotatePos( nBaseX, nBaseY, nStartX, nStartY, nOrientation );
    1798           0 :             ImplRotatePos( nBaseX, nBaseY, nEndX, nEndY, nOrientation );
    1799             :         }
    1800           0 :         mpGraphics->DrawLine( nStartX, nStartY, nEndX, nEndY, this );
    1801             :     }
    1802             :     else
    1803             :     {
    1804           0 :         long    nCurX = nStartX;
    1805           0 :         long    nCurY = nStartY;
    1806           0 :         long    nDiffX = 2;
    1807           0 :         long    nDiffY = nHeight-1;
    1808           0 :         long    nCount = nWidth;
    1809           0 :         long    nOffY = -1;
    1810             :         long    nFreq;
    1811             :         long    i;
    1812             :         long    nPixWidth;
    1813             :         long    nPixHeight;
    1814             :         bool    bDrawPixAsRect;
    1815             :         // On printers that ouput pixel via DrawRect()
    1816           0 :         if ( (GetOutDevType() == OUTDEV_PRINTER) || (nLineWidth > 1) )
    1817             :         {
    1818           0 :             if ( mbLineColor || mbInitLineColor )
    1819             :             {
    1820           0 :                 mpGraphics->SetLineColor();
    1821           0 :                 mbInitLineColor = true;
    1822             :             }
    1823           0 :             mpGraphics->SetFillColor( ImplColorToSal( rColor ) );
    1824           0 :             mbInitFillColor = true;
    1825           0 :             bDrawPixAsRect  = true;
    1826           0 :             nPixWidth       = nLineWidth;
    1827           0 :             nPixHeight      = ((nLineWidth*mnDPIX)+(mnDPIY/2))/mnDPIY;
    1828             :         }
    1829             :         else
    1830             :         {
    1831           0 :             mpGraphics->SetLineColor( ImplColorToSal( rColor ) );
    1832           0 :             mbInitLineColor = true;
    1833           0 :             nPixWidth       = 1;
    1834           0 :             nPixHeight      = 1;
    1835           0 :             bDrawPixAsRect  = false;
    1836             :         }
    1837             : 
    1838           0 :         if ( !nDiffY )
    1839             :         {
    1840           0 :             while ( nWidth )
    1841             :             {
    1842             :                 ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
    1843             :                                    mpGraphics, this,
    1844           0 :                                    bDrawPixAsRect, nPixWidth, nPixHeight );
    1845           0 :                 nCurX++;
    1846           0 :                 nWidth--;
    1847             :             }
    1848             :         }
    1849             :         else
    1850             :         {
    1851           0 :             nCurY += nDiffY;
    1852           0 :             nFreq = nCount / (nDiffX+nDiffY);
    1853           0 :             while ( nFreq-- )
    1854             :             {
    1855           0 :                 for( i = nDiffY; i; --i )
    1856             :                 {
    1857             :                     ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
    1858             :                                        mpGraphics, this,
    1859           0 :                                        bDrawPixAsRect, nPixWidth, nPixHeight );
    1860           0 :                     nCurX++;
    1861           0 :                     nCurY += nOffY;
    1862             :                 }
    1863           0 :                 for( i = nDiffX; i; --i )
    1864             :                 {
    1865             :                     ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
    1866             :                                        mpGraphics, this,
    1867           0 :                                        bDrawPixAsRect, nPixWidth, nPixHeight );
    1868           0 :                     nCurX++;
    1869             :                 }
    1870           0 :                 nOffY = -nOffY;
    1871             :             }
    1872           0 :             nFreq = nCount % (nDiffX+nDiffY);
    1873           0 :             if ( nFreq )
    1874             :             {
    1875           0 :                 for( i = nDiffY; i && nFreq; --i, --nFreq )
    1876             :                 {
    1877             :                     ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
    1878             :                                        mpGraphics, this,
    1879           0 :                                        bDrawPixAsRect, nPixWidth, nPixHeight );
    1880           0 :                     nCurX++;
    1881           0 :                     nCurY += nOffY;
    1882             : 
    1883             :                 }
    1884           0 :                 for( i = nDiffX; i && nFreq; --i, --nFreq )
    1885             :                 {
    1886             :                     ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
    1887             :                                        mpGraphics, this,
    1888           0 :                                        bDrawPixAsRect, nPixWidth, nPixHeight );
    1889           0 :                     nCurX++;
    1890             :                 }
    1891             :             }
    1892             :         }
    1893             : 
    1894             :     }
    1895             : }
    1896             : 
    1897           0 : void OutputDevice::ImplDrawWaveTextLine( long nBaseX, long nBaseY,
    1898             :                                          long nDistX, long nDistY, long nWidth,
    1899             :                                          FontUnderline eTextLine,
    1900             :                                          Color aColor,
    1901             :                                          bool bIsAbove )
    1902             : {
    1903           0 :     ImplFontEntry*  pFontEntry = mpFontEntry;
    1904             :     long            nLineHeight;
    1905             :     long            nLinePos;
    1906             : 
    1907           0 :     if ( bIsAbove )
    1908             :     {
    1909           0 :         nLineHeight = pFontEntry->maMetric.mnAboveWUnderlineSize;
    1910           0 :         nLinePos = pFontEntry->maMetric.mnAboveWUnderlineOffset;
    1911             :     }
    1912             :     else
    1913             :     {
    1914           0 :         nLineHeight = pFontEntry->maMetric.mnWUnderlineSize;
    1915           0 :         nLinePos = pFontEntry->maMetric.mnWUnderlineOffset;
    1916             :     }
    1917           0 :     if ( (eTextLine == UNDERLINE_SMALLWAVE) && (nLineHeight > 3) )
    1918           0 :         nLineHeight = 3;
    1919           0 :     long nLineWidth = (mnDPIX/300);
    1920           0 :     if ( !nLineWidth )
    1921           0 :         nLineWidth = 1;
    1922           0 :     if ( eTextLine == UNDERLINE_BOLDWAVE )
    1923           0 :         nLineWidth *= 2;
    1924           0 :     nLinePos += nDistY - (nLineHeight / 2);
    1925           0 :     long nLineWidthHeight = ((nLineWidth*mnDPIX)+(mnDPIY/2))/mnDPIY;
    1926           0 :     if ( eTextLine == UNDERLINE_DOUBLEWAVE )
    1927             :     {
    1928           0 :         long nOrgLineHeight = nLineHeight;
    1929           0 :         nLineHeight /= 3;
    1930           0 :         if ( nLineHeight < 2 )
    1931             :         {
    1932           0 :             if ( nOrgLineHeight > 1 )
    1933           0 :                 nLineHeight = 2;
    1934             :             else
    1935           0 :                 nLineHeight = 1;
    1936             :         }
    1937           0 :         long nLineDY = nOrgLineHeight-(nLineHeight*2);
    1938           0 :         if ( nLineDY < nLineWidthHeight )
    1939           0 :             nLineDY = nLineWidthHeight;
    1940           0 :         long nLineDY2 = nLineDY/2;
    1941           0 :         if ( !nLineDY2 )
    1942           0 :             nLineDY2 = 1;
    1943             : 
    1944           0 :         nLinePos -= nLineWidthHeight-nLineDY2;
    1945             :         ImplDrawWaveLine( nBaseX, nBaseY, nDistX, nLinePos, nWidth, nLineHeight,
    1946           0 :                           nLineWidth, mpFontEntry->mnOrientation, aColor );
    1947           0 :         nLinePos += nLineWidthHeight+nLineDY;
    1948             :         ImplDrawWaveLine( nBaseX, nBaseY, nDistX, nLinePos, nWidth, nLineHeight,
    1949           0 :                           nLineWidth, mpFontEntry->mnOrientation, aColor );
    1950             :     }
    1951             :     else
    1952             :     {
    1953           0 :         nLinePos -= nLineWidthHeight/2;
    1954             :         ImplDrawWaveLine( nBaseX, nBaseY, nDistX, nLinePos, nWidth, nLineHeight,
    1955           0 :                           nLineWidth, mpFontEntry->mnOrientation, aColor );
    1956             :     }
    1957           0 : }
    1958             : 
    1959           0 : void OutputDevice::ImplDrawStraightTextLine( long nBaseX, long nBaseY,
    1960             :                                              long nDistX, long nDistY, long nWidth,
    1961             :                                              FontUnderline eTextLine,
    1962             :                                              Color aColor,
    1963             :                                              bool bIsAbove )
    1964             : {
    1965           0 :     ImplFontEntry*  pFontEntry = mpFontEntry;
    1966           0 :     long            nLineHeight = 0;
    1967           0 :     long            nLinePos  = 0;
    1968           0 :     long            nLinePos2 = 0;
    1969             : 
    1970           0 :     const long nY = nDistY;
    1971             : 
    1972           0 :     if ( eTextLine > UNDERLINE_LAST )
    1973           0 :         eTextLine = UNDERLINE_SINGLE;
    1974             : 
    1975           0 :     switch ( eTextLine )
    1976             :     {
    1977             :         case UNDERLINE_SINGLE:
    1978             :         case UNDERLINE_DOTTED:
    1979             :         case UNDERLINE_DASH:
    1980             :         case UNDERLINE_LONGDASH:
    1981             :         case UNDERLINE_DASHDOT:
    1982             :         case UNDERLINE_DASHDOTDOT:
    1983           0 :             if ( bIsAbove )
    1984             :             {
    1985           0 :                 nLineHeight = pFontEntry->maMetric.mnAboveUnderlineSize;
    1986           0 :                 nLinePos    = nY + pFontEntry->maMetric.mnAboveUnderlineOffset;
    1987             :             }
    1988             :             else
    1989             :             {
    1990           0 :                 nLineHeight = pFontEntry->maMetric.mnUnderlineSize;
    1991           0 :                 nLinePos    = nY + pFontEntry->maMetric.mnUnderlineOffset;
    1992             :             }
    1993           0 :             break;
    1994             :         case UNDERLINE_BOLD:
    1995             :         case UNDERLINE_BOLDDOTTED:
    1996             :         case UNDERLINE_BOLDDASH:
    1997             :         case UNDERLINE_BOLDLONGDASH:
    1998             :         case UNDERLINE_BOLDDASHDOT:
    1999             :         case UNDERLINE_BOLDDASHDOTDOT:
    2000           0 :             if ( bIsAbove )
    2001             :             {
    2002           0 :                 nLineHeight = pFontEntry->maMetric.mnAboveBUnderlineSize;
    2003           0 :                 nLinePos    = nY + pFontEntry->maMetric.mnAboveBUnderlineOffset;
    2004             :             }
    2005             :             else
    2006             :             {
    2007           0 :                 nLineHeight = pFontEntry->maMetric.mnBUnderlineSize;
    2008           0 :                 nLinePos    = nY + pFontEntry->maMetric.mnBUnderlineOffset;
    2009             :             }
    2010           0 :             break;
    2011             :         case UNDERLINE_DOUBLE:
    2012           0 :             if ( bIsAbove )
    2013             :             {
    2014           0 :                 nLineHeight = pFontEntry->maMetric.mnAboveDUnderlineSize;
    2015           0 :                 nLinePos    = nY + pFontEntry->maMetric.mnAboveDUnderlineOffset1;
    2016           0 :                 nLinePos2   = nY + pFontEntry->maMetric.mnAboveDUnderlineOffset2;
    2017             :             }
    2018             :             else
    2019             :             {
    2020           0 :                 nLineHeight = pFontEntry->maMetric.mnDUnderlineSize;
    2021           0 :                 nLinePos    = nY + pFontEntry->maMetric.mnDUnderlineOffset1;
    2022           0 :                 nLinePos2   = nY + pFontEntry->maMetric.mnDUnderlineOffset2;
    2023             :             }
    2024           0 :             break;
    2025             :         default:
    2026           0 :             break;
    2027             :     }
    2028             : 
    2029           0 :     if ( nLineHeight )
    2030             :     {
    2031           0 :         if ( mbLineColor || mbInitLineColor )
    2032             :         {
    2033           0 :             mpGraphics->SetLineColor();
    2034           0 :             mbInitLineColor = true;
    2035             :         }
    2036           0 :         mpGraphics->SetFillColor( ImplColorToSal( aColor ) );
    2037           0 :         mbInitFillColor = true;
    2038             : 
    2039           0 :         long nLeft = nDistX;
    2040             : 
    2041           0 :         switch ( eTextLine )
    2042             :         {
    2043             :             case UNDERLINE_SINGLE:
    2044             :             case UNDERLINE_BOLD:
    2045           0 :                 ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight );
    2046           0 :                 break;
    2047             :             case UNDERLINE_DOUBLE:
    2048           0 :                 ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos,  nWidth, nLineHeight );
    2049           0 :                 ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos2, nWidth, nLineHeight );
    2050           0 :                 break;
    2051             :             case UNDERLINE_DOTTED:
    2052             :             case UNDERLINE_BOLDDOTTED:
    2053             :                 {
    2054           0 :                     long nDotWidth = nLineHeight*mnDPIY;
    2055           0 :                     nDotWidth += mnDPIY/2;
    2056           0 :                     nDotWidth /= mnDPIY;
    2057           0 :                     long nTempWidth = nDotWidth;
    2058           0 :                     long nEnd = nLeft+nWidth;
    2059           0 :                     while ( nLeft < nEnd )
    2060             :                     {
    2061           0 :                         if ( nLeft+nTempWidth > nEnd )
    2062           0 :                             nTempWidth = nEnd-nLeft;
    2063           0 :                         ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempWidth, nLineHeight );
    2064           0 :                         nLeft += nDotWidth*2;
    2065             :                     }
    2066             :                 }
    2067           0 :                 break;
    2068             :             case UNDERLINE_DASH:
    2069             :             case UNDERLINE_LONGDASH:
    2070             :             case UNDERLINE_BOLDDASH:
    2071             :             case UNDERLINE_BOLDLONGDASH:
    2072             :                 {
    2073           0 :                     long nDotWidth = nLineHeight*mnDPIY;
    2074           0 :                     nDotWidth += mnDPIY/2;
    2075           0 :                     nDotWidth /= mnDPIY;
    2076             :                     long nMinDashWidth;
    2077             :                     long nMinSpaceWidth;
    2078             :                     long nSpaceWidth;
    2079             :                     long nDashWidth;
    2080           0 :                     if ( (eTextLine == UNDERLINE_LONGDASH) ||
    2081             :                          (eTextLine == UNDERLINE_BOLDLONGDASH) )
    2082             :                     {
    2083           0 :                         nMinDashWidth = nDotWidth*6;
    2084           0 :                         nMinSpaceWidth = nDotWidth*2;
    2085           0 :                         nDashWidth = 200;
    2086           0 :                         nSpaceWidth = 100;
    2087             :                     }
    2088             :                     else
    2089             :                     {
    2090           0 :                         nMinDashWidth = nDotWidth*4;
    2091           0 :                         nMinSpaceWidth = (nDotWidth*150)/100;
    2092           0 :                         nDashWidth = 100;
    2093           0 :                         nSpaceWidth = 50;
    2094             :                     }
    2095           0 :                     nDashWidth = ((nDashWidth*mnDPIX)+1270)/2540;
    2096           0 :                     nSpaceWidth = ((nSpaceWidth*mnDPIX)+1270)/2540;
    2097             :                     // DashWidth will be increased if the line is getting too thick
    2098             :                     // in proportion to the line's length
    2099           0 :                     if ( nDashWidth < nMinDashWidth )
    2100           0 :                         nDashWidth = nMinDashWidth;
    2101           0 :                     if ( nSpaceWidth < nMinSpaceWidth )
    2102           0 :                         nSpaceWidth = nMinSpaceWidth;
    2103           0 :                     long nTempWidth = nDashWidth;
    2104           0 :                     long nEnd = nLeft+nWidth;
    2105           0 :                     while ( nLeft < nEnd )
    2106             :                     {
    2107           0 :                         if ( nLeft+nTempWidth > nEnd )
    2108           0 :                             nTempWidth = nEnd-nLeft;
    2109           0 :                         ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempWidth, nLineHeight );
    2110           0 :                         nLeft += nDashWidth+nSpaceWidth;
    2111             :                     }
    2112             :                 }
    2113           0 :                 break;
    2114             :             case UNDERLINE_DASHDOT:
    2115             :             case UNDERLINE_BOLDDASHDOT:
    2116             :                 {
    2117           0 :                     long nDotWidth = nLineHeight*mnDPIY;
    2118           0 :                     nDotWidth += mnDPIY/2;
    2119           0 :                     nDotWidth /= mnDPIY;
    2120           0 :                     long nDashWidth = ((100*mnDPIX)+1270)/2540;
    2121           0 :                     long nMinDashWidth = nDotWidth*4;
    2122             :                     // DashWidth will be increased if the line is getting too thick
    2123             :                     // in proportion to the line's length
    2124           0 :                     if ( nDashWidth < nMinDashWidth )
    2125           0 :                         nDashWidth = nMinDashWidth;
    2126           0 :                     long nTempDotWidth = nDotWidth;
    2127           0 :                     long nTempDashWidth = nDashWidth;
    2128           0 :                     long nEnd = nLeft+nWidth;
    2129           0 :                     while ( nLeft < nEnd )
    2130             :                     {
    2131           0 :                         if ( nLeft+nTempDotWidth > nEnd )
    2132           0 :                             nTempDotWidth = nEnd-nLeft;
    2133           0 :                         ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDotWidth, nLineHeight );
    2134           0 :                         nLeft += nDotWidth*2;
    2135           0 :                         if ( nLeft > nEnd )
    2136           0 :                             break;
    2137           0 :                         if ( nLeft+nTempDashWidth > nEnd )
    2138           0 :                             nTempDashWidth = nEnd-nLeft;
    2139           0 :                         ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDashWidth, nLineHeight );
    2140           0 :                         nLeft += nDashWidth+nDotWidth;
    2141             :                     }
    2142             :                 }
    2143           0 :                 break;
    2144             :             case UNDERLINE_DASHDOTDOT:
    2145             :             case UNDERLINE_BOLDDASHDOTDOT:
    2146             :                 {
    2147           0 :                     long nDotWidth = nLineHeight*mnDPIY;
    2148           0 :                     nDotWidth += mnDPIY/2;
    2149           0 :                     nDotWidth /= mnDPIY;
    2150           0 :                     long nDashWidth = ((100*mnDPIX)+1270)/2540;
    2151           0 :                     long nMinDashWidth = nDotWidth*4;
    2152             :                     // DashWidth will be increased if the line is getting too thick
    2153             :                     // in proportion to the line's length
    2154           0 :                     if ( nDashWidth < nMinDashWidth )
    2155           0 :                         nDashWidth = nMinDashWidth;
    2156           0 :                     long nTempDotWidth = nDotWidth;
    2157           0 :                     long nTempDashWidth = nDashWidth;
    2158           0 :                     long nEnd = nLeft+nWidth;
    2159           0 :                     while ( nLeft < nEnd )
    2160             :                     {
    2161           0 :                         if ( nLeft+nTempDotWidth > nEnd )
    2162           0 :                             nTempDotWidth = nEnd-nLeft;
    2163           0 :                         ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDotWidth, nLineHeight );
    2164           0 :                         nLeft += nDotWidth*2;
    2165           0 :                         if ( nLeft > nEnd )
    2166           0 :                             break;
    2167           0 :                         if ( nLeft+nTempDotWidth > nEnd )
    2168           0 :                             nTempDotWidth = nEnd-nLeft;
    2169           0 :                         ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDotWidth, nLineHeight );
    2170           0 :                         nLeft += nDotWidth*2;
    2171           0 :                         if ( nLeft > nEnd )
    2172           0 :                             break;
    2173           0 :                         if ( nLeft+nTempDashWidth > nEnd )
    2174           0 :                             nTempDashWidth = nEnd-nLeft;
    2175           0 :                         ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDashWidth, nLineHeight );
    2176           0 :                         nLeft += nDashWidth+nDotWidth;
    2177             :                     }
    2178             :                 }
    2179           0 :                 break;
    2180             :             default:
    2181           0 :                 break;
    2182             :         }
    2183             :     }
    2184           0 : }
    2185             : 
    2186           0 : void OutputDevice::ImplDrawStrikeoutLine( long nBaseX, long nBaseY,
    2187             :                                           long nDistX, long nDistY, long nWidth,
    2188             :                                           FontStrikeout eStrikeout,
    2189             :                                           Color aColor )
    2190             : {
    2191           0 :     ImplFontEntry*  pFontEntry = mpFontEntry;
    2192           0 :     long            nLineHeight = 0;
    2193           0 :     long            nLinePos  = 0;
    2194           0 :     long            nLinePos2 = 0;
    2195             : 
    2196           0 :     long nY = nDistY;
    2197             : 
    2198           0 :     if ( eStrikeout > STRIKEOUT_LAST )
    2199           0 :         eStrikeout = STRIKEOUT_SINGLE;
    2200             : 
    2201           0 :     switch ( eStrikeout )
    2202             :     {
    2203             :         case STRIKEOUT_SINGLE:
    2204           0 :             nLineHeight = pFontEntry->maMetric.mnStrikeoutSize;
    2205           0 :             nLinePos    = nY + pFontEntry->maMetric.mnStrikeoutOffset;
    2206           0 :             break;
    2207             :         case STRIKEOUT_BOLD:
    2208           0 :             nLineHeight = pFontEntry->maMetric.mnBStrikeoutSize;
    2209           0 :             nLinePos    = nY + pFontEntry->maMetric.mnBStrikeoutOffset;
    2210           0 :             break;
    2211             :         case STRIKEOUT_DOUBLE:
    2212           0 :             nLineHeight = pFontEntry->maMetric.mnDStrikeoutSize;
    2213           0 :             nLinePos    = nY + pFontEntry->maMetric.mnDStrikeoutOffset1;
    2214           0 :             nLinePos2   = nY + pFontEntry->maMetric.mnDStrikeoutOffset2;
    2215           0 :             break;
    2216             :         default:
    2217           0 :             break;
    2218             :     }
    2219             : 
    2220           0 :     if ( nLineHeight )
    2221             :     {
    2222           0 :         if ( mbLineColor || mbInitLineColor )
    2223             :         {
    2224           0 :             mpGraphics->SetLineColor();
    2225           0 :             mbInitLineColor = true;
    2226             :         }
    2227           0 :         mpGraphics->SetFillColor( ImplColorToSal( aColor ) );
    2228           0 :         mbInitFillColor = true;
    2229             : 
    2230           0 :         const long& nLeft = nDistX;
    2231             : 
    2232           0 :         switch ( eStrikeout )
    2233             :         {
    2234             :             case STRIKEOUT_SINGLE:
    2235             :             case STRIKEOUT_BOLD:
    2236           0 :                 ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight );
    2237           0 :                 break;
    2238             :             case STRIKEOUT_DOUBLE:
    2239           0 :                 ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight );
    2240           0 :                 ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos2, nWidth, nLineHeight );
    2241           0 :                 break;
    2242             :             default:
    2243           0 :                 break;
    2244             :         }
    2245             :     }
    2246           0 : }
    2247             : 
    2248           0 : void OutputDevice::ImplDrawStrikeoutChar( long nBaseX, long nBaseY,
    2249             :                                           long nDistX, long nDistY, long nWidth,
    2250             :                                           FontStrikeout eStrikeout,
    2251             :                                           Color aColor )
    2252             : {
    2253             :     // See qadevOOo/testdocs/StrikeThrough.odt for examples if you need
    2254             :     // to tweak this
    2255           0 :     if (!nWidth)
    2256           0 :         return;
    2257             : 
    2258             :     // prepare string for strikeout measurement
    2259             :     static char cStrikeoutChar;
    2260           0 :     if ( eStrikeout == STRIKEOUT_SLASH )
    2261           0 :         cStrikeoutChar = '/';
    2262             :     else // ( eStrikeout == STRIKEOUT_X )
    2263           0 :         cStrikeoutChar = 'X';
    2264             :     static const int nTestStrLen = 4;
    2265             :     static const int nMaxStrikeStrLen = 2048;
    2266             :     sal_Unicode aChars[nMaxStrikeStrLen+1]; // +1 for valgrind...
    2267           0 :     for( int i = 0; i < nTestStrLen; ++i)
    2268           0 :         aChars[i] = cStrikeoutChar;
    2269           0 :     const OUString aStrikeoutTest(aChars, nTestStrLen);
    2270             : 
    2271             :     // calculate approximation of strikeout atom size
    2272           0 :     long nStrikeoutWidth = 0;
    2273           0 :     SalLayout* pLayout = ImplLayout( aStrikeoutTest, 0, nTestStrLen );
    2274           0 :     if( pLayout )
    2275             :     {
    2276           0 :         nStrikeoutWidth = pLayout->GetTextWidth() / (nTestStrLen * pLayout->GetUnitsPerPixel());
    2277           0 :         pLayout->Release();
    2278             :     }
    2279           0 :     if( nStrikeoutWidth <= 0 ) // sanity check
    2280           0 :         return;
    2281             : 
    2282           0 :     int nStrikeStrLen = (nWidth+(nStrikeoutWidth-1)) / nStrikeoutWidth;
    2283           0 :     if( nStrikeStrLen > nMaxStrikeStrLen )
    2284           0 :         nStrikeStrLen = nMaxStrikeStrLen;
    2285             : 
    2286             :     // build the strikeout string
    2287           0 :     for( int i = nTestStrLen; i < nStrikeStrLen; ++i)
    2288           0 :         aChars[i] = cStrikeoutChar;
    2289           0 :     const OUString aStrikeoutText(aChars, nStrikeStrLen);
    2290             : 
    2291           0 :     if( mpFontEntry->mnOrientation )
    2292           0 :         ImplRotatePos( 0, 0, nDistX, nDistY, mpFontEntry->mnOrientation );
    2293           0 :     nBaseX += nDistX;
    2294           0 :     nBaseY += nDistY;
    2295             : 
    2296             :     // strikeout text has to be left aligned
    2297           0 :     sal_uLong nOrigTLM = mnTextLayoutMode;
    2298           0 :     mnTextLayoutMode = TEXT_LAYOUT_BIDI_STRONG | TEXT_LAYOUT_COMPLEX_DISABLED;
    2299           0 :     pLayout = ImplLayout( aStrikeoutText, 0, aStrikeoutText.getLength() );
    2300           0 :     mnTextLayoutMode = nOrigTLM;
    2301             : 
    2302           0 :     if( !pLayout )
    2303           0 :         return;
    2304             : 
    2305             :     // draw the strikeout text
    2306           0 :     const Color aOldColor = GetTextColor();
    2307           0 :     SetTextColor( aColor );
    2308           0 :     ImplInitTextColor();
    2309             : 
    2310           0 :     pLayout->DrawBase() = Point( nBaseX+mnTextOffX, nBaseY+mnTextOffY );
    2311             : 
    2312           0 :     Rectangle aPixelRect;
    2313           0 :     aPixelRect.Left() = nBaseX+mnTextOffX;
    2314           0 :     aPixelRect.Right() = aPixelRect.Left()+nWidth;
    2315           0 :     aPixelRect.Bottom() = nBaseY+mpFontEntry->maMetric.mnDescent;
    2316           0 :     aPixelRect.Top() = nBaseY-mpFontEntry->maMetric.mnAscent;
    2317             : 
    2318           0 :     if (mpFontEntry->mnOrientation)
    2319             :     {
    2320           0 :         Polygon aPoly( aPixelRect );
    2321           0 :         aPoly.Rotate( Point(nBaseX+mnTextOffX, nBaseY+mnTextOffY), mpFontEntry->mnOrientation);
    2322           0 :         aPixelRect = aPoly.GetBoundRect();
    2323             :     }
    2324             : 
    2325           0 :     Push( PUSH_CLIPREGION );
    2326           0 :     IntersectClipRegion( PixelToLogic(aPixelRect) );
    2327           0 :     if( mbInitClipRegion )
    2328           0 :         ImplInitClipRegion();
    2329             : 
    2330           0 :     pLayout->DrawText( *mpGraphics );
    2331             : 
    2332           0 :     pLayout->Release();
    2333           0 :     Pop();
    2334             : 
    2335           0 :     SetTextColor( aOldColor );
    2336           0 :     ImplInitTextColor();
    2337             : }
    2338             : 
    2339           0 : void OutputDevice::ImplDrawTextLine( long nX, long nY,
    2340             :                                      long nDistX, long nWidth,
    2341             :                                      FontStrikeout eStrikeout,
    2342             :                                      FontUnderline eUnderline,
    2343             :                                      FontUnderline eOverline,
    2344             :                                      bool bUnderlineAbove )
    2345             : {
    2346           0 :     if ( !nWidth )
    2347           0 :         return;
    2348             : 
    2349           0 :     Color           aStrikeoutColor = GetTextColor();
    2350           0 :     Color           aUnderlineColor = GetTextLineColor();
    2351           0 :     Color           aOverlineColor  = GetOverlineColor();
    2352           0 :     bool            bStrikeoutDone = false;
    2353           0 :     bool            bUnderlineDone = false;
    2354           0 :     bool            bOverlineDone  = false;
    2355             : 
    2356           0 :     if ( IsRTLEnabled() )
    2357             :     {
    2358             :         // --- RTL --- mirror at basex
    2359           0 :         long nXAdd = nWidth - nDistX;
    2360           0 :         if( mpFontEntry->mnOrientation )
    2361           0 :             nXAdd = FRound( nXAdd * cos( mpFontEntry->mnOrientation * F_PI1800 ) );
    2362           0 :         nX += nXAdd - 1;
    2363             :     }
    2364             : 
    2365           0 :     if ( !IsTextLineColor() )
    2366           0 :         aUnderlineColor = GetTextColor();
    2367             : 
    2368           0 :     if ( !IsOverlineColor() )
    2369           0 :         aOverlineColor = GetTextColor();
    2370             : 
    2371           0 :     if ( (eUnderline == UNDERLINE_SMALLWAVE) ||
    2372           0 :          (eUnderline == UNDERLINE_WAVE) ||
    2373           0 :          (eUnderline == UNDERLINE_DOUBLEWAVE) ||
    2374             :          (eUnderline == UNDERLINE_BOLDWAVE) )
    2375             :     {
    2376           0 :         ImplDrawWaveTextLine( nX, nY, nDistX, 0, nWidth, eUnderline, aUnderlineColor, bUnderlineAbove );
    2377           0 :         bUnderlineDone = true;
    2378             :     }
    2379           0 :     if ( (eOverline == UNDERLINE_SMALLWAVE) ||
    2380           0 :          (eOverline == UNDERLINE_WAVE) ||
    2381           0 :          (eOverline == UNDERLINE_DOUBLEWAVE) ||
    2382             :          (eOverline == UNDERLINE_BOLDWAVE) )
    2383             :     {
    2384           0 :         ImplDrawWaveTextLine( nX, nY, nDistX, 0, nWidth, eOverline, aOverlineColor, true );
    2385           0 :         bOverlineDone = true;
    2386             :     }
    2387             : 
    2388           0 :     if ( (eStrikeout == STRIKEOUT_SLASH) ||
    2389             :          (eStrikeout == STRIKEOUT_X) )
    2390             :     {
    2391           0 :         ImplDrawStrikeoutChar( nX, nY, nDistX, 0, nWidth, eStrikeout, aStrikeoutColor );
    2392           0 :         bStrikeoutDone = true;
    2393             :     }
    2394             : 
    2395           0 :     if ( !bUnderlineDone )
    2396           0 :         ImplDrawStraightTextLine( nX, nY, nDistX, 0, nWidth, eUnderline, aUnderlineColor, bUnderlineAbove );
    2397             : 
    2398           0 :     if ( !bOverlineDone )
    2399           0 :         ImplDrawStraightTextLine( nX, nY, nDistX, 0, nWidth, eOverline, aOverlineColor, true );
    2400             : 
    2401           0 :     if ( !bStrikeoutDone )
    2402           0 :         ImplDrawStrikeoutLine( nX, nY, nDistX, 0, nWidth, eStrikeout, aStrikeoutColor );
    2403             : }
    2404             : 
    2405           0 : void OutputDevice::ImplDrawTextLines( SalLayout& rSalLayout,
    2406             :     FontStrikeout eStrikeout, FontUnderline eUnderline, FontUnderline eOverline, bool bWordLine, bool bUnderlineAbove )
    2407             : {
    2408           0 :     if( bWordLine )
    2409             :     {
    2410             :         // draw everything relative to the layout base point
    2411           0 :         const Point aStartPt = rSalLayout.DrawBase();
    2412             : 
    2413             :         // calculate distance of each word from the base point
    2414           0 :         Point aPos;
    2415           0 :         sal_Int32 nDist = 0, nWidth = 0, nAdvance=0;
    2416           0 :         for( int nStart = 0;;)
    2417             :         {
    2418             :             // iterate through the layouted glyphs
    2419             :             sal_GlyphId aGlyphId;
    2420           0 :             if( !rSalLayout.GetNextGlyphs( 1, &aGlyphId, aPos, nStart, &nAdvance ) )
    2421           0 :                 break;
    2422             : 
    2423             :             // calculate the boundaries of each word
    2424           0 :             if( !rSalLayout.IsSpacingGlyph( aGlyphId ) )
    2425             :             {
    2426           0 :                 if( !nWidth )
    2427             :                 {
    2428             :                     // get the distance to the base point (as projected to baseline)
    2429           0 :                     nDist = aPos.X() - aStartPt.X();
    2430           0 :                     if( mpFontEntry->mnOrientation )
    2431             :                     {
    2432           0 :                         const long nDY = aPos.Y() - aStartPt.Y();
    2433           0 :                         const double fRad = mpFontEntry->mnOrientation * F_PI1800;
    2434           0 :                         nDist = FRound( nDist*cos(fRad) - nDY*sin(fRad) );
    2435             :                     }
    2436             :                 }
    2437             : 
    2438             :                 // update the length of the textline
    2439           0 :                 nWidth += nAdvance;
    2440             :             }
    2441           0 :             else if( nWidth > 0 )
    2442             :             {
    2443             :                 // draw the textline for each word
    2444             :                 ImplDrawTextLine( aStartPt.X(), aStartPt.Y(), nDist, nWidth,
    2445           0 :                     eStrikeout, eUnderline, eOverline, bUnderlineAbove );
    2446           0 :                 nWidth = 0;
    2447             :             }
    2448           0 :         }
    2449             : 
    2450             :         // draw textline for the last word
    2451           0 :         if( nWidth > 0 )
    2452             :         {
    2453             :             ImplDrawTextLine( aStartPt.X(), aStartPt.Y(), nDist, nWidth,
    2454           0 :                 eStrikeout, eUnderline, eOverline, bUnderlineAbove );
    2455             :         }
    2456             :     }
    2457             :     else
    2458             :     {
    2459           0 :         Point aStartPt = rSalLayout.GetDrawPosition();
    2460           0 :         int nWidth = rSalLayout.GetTextWidth() / rSalLayout.GetUnitsPerPixel();
    2461           0 :         ImplDrawTextLine( aStartPt.X(), aStartPt.Y(), 0, nWidth,
    2462           0 :             eStrikeout, eUnderline, eOverline, bUnderlineAbove );
    2463             :     }
    2464           0 : }
    2465             : 
    2466           0 : void OutputDevice::ImplDrawMnemonicLine( long nX, long nY, long nWidth )
    2467             : {
    2468           0 :     long nBaseX = nX;
    2469           0 :     if( /*HasMirroredGraphics() &&*/ IsRTLEnabled() )
    2470             :     {
    2471             :         // --- RTL ---
    2472             :         // add some strange offset
    2473           0 :         nX += 2;
    2474             :         // revert the hack that will be done later in ImplDrawTextLine
    2475           0 :         nX = nBaseX - nWidth - (nX - nBaseX - 1);
    2476             :     }
    2477             : 
    2478           0 :     ImplDrawTextLine( nX, nY, 0, nWidth, STRIKEOUT_NONE, UNDERLINE_SINGLE, UNDERLINE_NONE, false );
    2479           0 : }
    2480             : 
    2481           0 : void OutputDevice::ImplGetEmphasisMark( PolyPolygon& rPolyPoly, bool& rPolyLine,
    2482             :                                         Rectangle& rRect1, Rectangle& rRect2,
    2483             :                                         long& rYOff, long& rWidth,
    2484             :                                         FontEmphasisMark eEmphasis,
    2485             :                                         long nHeight, short /*nOrient*/ )
    2486             : {
    2487             :     static const sal_uInt8 aAccentPolyFlags[24] =
    2488             :     {
    2489             :         0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 0, 2, 0, 2, 2
    2490             :     };
    2491             : 
    2492             :     static const long aAccentPos[48] =
    2493             :     {
    2494             :          78,      0,
    2495             :         348,     79,
    2496             :         599,    235,
    2497             :         843,    469,
    2498             :         938,    574,
    2499             :         990,    669,
    2500             :         990,    773,
    2501             :         990,    843,
    2502             :         964,    895,
    2503             :         921,    947,
    2504             :         886,    982,
    2505             :         860,    999,
    2506             :         825,    999,
    2507             :         764,    999,
    2508             :         721,    964,
    2509             :         686,    895,
    2510             :         625,    791,
    2511             :         556,    660,
    2512             :         469,    504,
    2513             :         400,    400,
    2514             :         261,    252,
    2515             :          61,     61,
    2516             :           0,     27,
    2517             :           9,      0
    2518             :     };
    2519             : 
    2520           0 :     rWidth      = 0;
    2521           0 :     rYOff       = 0;
    2522           0 :     rPolyLine   = false;
    2523             : 
    2524           0 :     if ( !nHeight )
    2525           0 :         return;
    2526             : 
    2527           0 :     FontEmphasisMark    nEmphasisStyle = eEmphasis & EMPHASISMARK_STYLE;
    2528           0 :     long                nDotSize = 0;
    2529           0 :     switch ( nEmphasisStyle )
    2530             :     {
    2531             :         case EMPHASISMARK_DOT:
    2532             :             // Dot has 55% of the height
    2533           0 :             nDotSize = (nHeight*550)/1000;
    2534           0 :             if ( !nDotSize )
    2535           0 :                 nDotSize = 1;
    2536           0 :             if ( nDotSize <= 2 )
    2537           0 :                 rRect1 = Rectangle( Point(), Size( nDotSize, nDotSize ) );
    2538             :             else
    2539             :             {
    2540           0 :                 long nRad = nDotSize/2;
    2541           0 :                 Polygon aPoly( Point( nRad, nRad ), nRad, nRad );
    2542           0 :                 rPolyPoly.Insert( aPoly );
    2543             :             }
    2544           0 :             rYOff = ((nHeight*250)/1000)/2; // Center to the another EmphasisMarks
    2545           0 :             rWidth = nDotSize;
    2546           0 :             break;
    2547             : 
    2548             :         case EMPHASISMARK_CIRCLE:
    2549             :             // Dot has 80% of the height
    2550           0 :             nDotSize = (nHeight*800)/1000;
    2551           0 :             if ( !nDotSize )
    2552           0 :                 nDotSize = 1;
    2553           0 :             if ( nDotSize <= 2 )
    2554           0 :                 rRect1 = Rectangle( Point(), Size( nDotSize, nDotSize ) );
    2555             :             else
    2556             :             {
    2557           0 :                 long nRad = nDotSize/2;
    2558           0 :                 Polygon aPoly( Point( nRad, nRad ), nRad, nRad );
    2559           0 :                 rPolyPoly.Insert( aPoly );
    2560             :                 // BorderWidth is 15%
    2561           0 :                 long nBorder = (nDotSize*150)/1000;
    2562           0 :                 if ( nBorder <= 1 )
    2563           0 :                     rPolyLine = true;
    2564             :                 else
    2565             :                 {
    2566             :                     Polygon aPoly2( Point( nRad, nRad ),
    2567           0 :                                     nRad-nBorder, nRad-nBorder );
    2568           0 :                     rPolyPoly.Insert( aPoly2 );
    2569           0 :                 }
    2570             :             }
    2571           0 :             rWidth = nDotSize;
    2572           0 :             break;
    2573             : 
    2574             :         case EMPHASISMARK_DISC:
    2575             :             // Dot has 80% of the height
    2576           0 :             nDotSize = (nHeight*800)/1000;
    2577           0 :             if ( !nDotSize )
    2578           0 :                 nDotSize = 1;
    2579           0 :             if ( nDotSize <= 2 )
    2580           0 :                 rRect1 = Rectangle( Point(), Size( nDotSize, nDotSize ) );
    2581             :             else
    2582             :             {
    2583           0 :                 long nRad = nDotSize/2;
    2584           0 :                 Polygon aPoly( Point( nRad, nRad ), nRad, nRad );
    2585           0 :                 rPolyPoly.Insert( aPoly );
    2586             :             }
    2587           0 :             rWidth = nDotSize;
    2588           0 :             break;
    2589             : 
    2590             :         case EMPHASISMARK_ACCENT:
    2591             :             // Dot has 80% of the height
    2592           0 :             nDotSize = (nHeight*800)/1000;
    2593           0 :             if ( !nDotSize )
    2594           0 :                 nDotSize = 1;
    2595           0 :             if ( nDotSize <= 2 )
    2596             :             {
    2597           0 :                 if ( nDotSize == 1 )
    2598             :                 {
    2599           0 :                     rRect1 = Rectangle( Point(), Size( nDotSize, nDotSize ) );
    2600           0 :                     rWidth = nDotSize;
    2601             :                 }
    2602             :                 else
    2603             :                 {
    2604           0 :                     rRect1 = Rectangle( Point(), Size( 1, 1 ) );
    2605           0 :                     rRect2 = Rectangle( Point( 1, 1 ), Size( 1, 1 ) );
    2606             :                 }
    2607             :             }
    2608             :             else
    2609             :             {
    2610           0 :                 Polygon aPoly( sizeof( aAccentPos ) / sizeof( long ) / 2,
    2611             :                                (const Point*)aAccentPos,
    2612           0 :                                aAccentPolyFlags );
    2613           0 :                 double dScale = ((double)nDotSize)/1000.0;
    2614           0 :                 aPoly.Scale( dScale, dScale );
    2615           0 :                 Polygon aTemp;
    2616           0 :                 aPoly.AdaptiveSubdivide( aTemp );
    2617           0 :                 Rectangle aBoundRect = aTemp.GetBoundRect();
    2618           0 :                 rWidth = aBoundRect.GetWidth();
    2619           0 :                 nDotSize = aBoundRect.GetHeight();
    2620           0 :                 rPolyPoly.Insert( aTemp );
    2621             :             }
    2622           0 :             break;
    2623             :     }
    2624             : 
    2625             :     // calculate position
    2626           0 :     long nOffY = 1+(mnDPIY/300); // one visible pixel space
    2627           0 :     long nSpaceY = nHeight-nDotSize;
    2628           0 :     if ( nSpaceY >= nOffY*2 )
    2629           0 :         rYOff += nOffY;
    2630           0 :     if ( !(eEmphasis & EMPHASISMARK_POS_BELOW) )
    2631           0 :         rYOff += nDotSize;
    2632             : }
    2633             : 
    2634           0 : void OutputDevice::ImplDrawEmphasisMark( long nBaseX, long nX, long nY,
    2635             :                                          const PolyPolygon& rPolyPoly, bool bPolyLine,
    2636             :                                          const Rectangle& rRect1, const Rectangle& rRect2 )
    2637             : {
    2638           0 :     if( IsRTLEnabled() )
    2639             :         // --- RTL --- mirror at basex
    2640           0 :         nX = nBaseX - (nX - nBaseX - 1);
    2641             : 
    2642           0 :     nX -= mnOutOffX;
    2643           0 :     nY -= mnOutOffY;
    2644             : 
    2645           0 :     if ( rPolyPoly.Count() )
    2646             :     {
    2647           0 :         if ( bPolyLine )
    2648             :         {
    2649           0 :             Polygon aPoly = rPolyPoly.GetObject( 0 );
    2650           0 :             aPoly.Move( nX, nY );
    2651           0 :             DrawPolyLine( aPoly );
    2652             :         }
    2653             :         else
    2654             :         {
    2655           0 :             PolyPolygon aPolyPoly = rPolyPoly;
    2656           0 :             aPolyPoly.Move( nX, nY );
    2657           0 :             DrawPolyPolygon( aPolyPoly );
    2658             :         }
    2659             :     }
    2660             : 
    2661           0 :     if ( !rRect1.IsEmpty() )
    2662             :     {
    2663           0 :         Rectangle aRect( Point( nX+rRect1.Left(),
    2664           0 :                                 nY+rRect1.Top() ), rRect1.GetSize() );
    2665           0 :         DrawRect( aRect );
    2666             :     }
    2667             : 
    2668           0 :     if ( !rRect2.IsEmpty() )
    2669             :     {
    2670           0 :         Rectangle aRect( Point( nX+rRect2.Left(),
    2671           0 :                                 nY+rRect2.Top() ), rRect2.GetSize() );
    2672             : 
    2673           0 :         DrawRect( aRect );
    2674             :     }
    2675           0 : }
    2676             : 
    2677           0 : void OutputDevice::ImplDrawEmphasisMarks( SalLayout& rSalLayout )
    2678             : {
    2679           0 :     Color               aOldLineColor   = GetLineColor();
    2680           0 :     Color               aOldFillColor   = GetFillColor();
    2681           0 :     bool                bOldMap         = mbMap;
    2682           0 :     GDIMetaFile*        pOldMetaFile    = mpMetaFile;
    2683           0 :     mpMetaFile = NULL;
    2684           0 :     EnableMapMode( false );
    2685             : 
    2686           0 :     FontEmphasisMark    nEmphasisMark = ImplGetEmphasisMarkStyle( maFont );
    2687           0 :     PolyPolygon         aPolyPoly;
    2688           0 :     Rectangle           aRect1;
    2689           0 :     Rectangle           aRect2;
    2690             :     long                nEmphasisYOff;
    2691             :     long                nEmphasisWidth;
    2692             :     long                nEmphasisHeight;
    2693             :     bool                bPolyLine;
    2694             : 
    2695           0 :     if ( nEmphasisMark & EMPHASISMARK_POS_BELOW )
    2696           0 :         nEmphasisHeight = mnEmphasisDescent;
    2697             :     else
    2698           0 :         nEmphasisHeight = mnEmphasisAscent;
    2699             : 
    2700             :     ImplGetEmphasisMark( aPolyPoly, bPolyLine,
    2701             :                          aRect1, aRect2,
    2702             :                          nEmphasisYOff, nEmphasisWidth,
    2703             :                          nEmphasisMark,
    2704           0 :                          nEmphasisHeight, mpFontEntry->mnOrientation );
    2705             : 
    2706           0 :     if ( bPolyLine )
    2707             :     {
    2708           0 :         SetLineColor( GetTextColor() );
    2709           0 :         SetFillColor();
    2710             :     }
    2711             :     else
    2712             :     {
    2713           0 :         SetLineColor();
    2714           0 :         SetFillColor( GetTextColor() );
    2715             :     }
    2716             : 
    2717           0 :     Point aOffset = Point(0,0);
    2718             : 
    2719           0 :     if ( nEmphasisMark & EMPHASISMARK_POS_BELOW )
    2720           0 :         aOffset.Y() += mpFontEntry->maMetric.mnDescent + nEmphasisYOff;
    2721             :     else
    2722           0 :         aOffset.Y() -= mpFontEntry->maMetric.mnAscent + nEmphasisYOff;
    2723             : 
    2724           0 :     long nEmphasisWidth2  = nEmphasisWidth / 2;
    2725           0 :     long nEmphasisHeight2 = nEmphasisHeight / 2;
    2726           0 :     aOffset += Point( nEmphasisWidth2, nEmphasisHeight2 );
    2727             : 
    2728           0 :     Point aOutPoint;
    2729           0 :     Rectangle aRectangle;
    2730           0 :     for( int nStart = 0;;)
    2731             :     {
    2732             :         sal_GlyphId aGlyphId;
    2733           0 :         if( !rSalLayout.GetNextGlyphs( 1, &aGlyphId, aOutPoint, nStart ) )
    2734           0 :             break;
    2735             : 
    2736           0 :         if( !mpGraphics->GetGlyphBoundRect( aGlyphId, aRectangle ) )
    2737           0 :             continue;
    2738             : 
    2739           0 :         if( !rSalLayout.IsSpacingGlyph( aGlyphId ) )
    2740             :         {
    2741           0 :             Point aAdjPoint = aOffset;
    2742           0 :             aAdjPoint.X() += aRectangle.Left() + (aRectangle.GetWidth() - nEmphasisWidth) / 2;
    2743           0 :             if ( mpFontEntry->mnOrientation )
    2744           0 :                 ImplRotatePos( 0, 0, aAdjPoint.X(), aAdjPoint.Y(), mpFontEntry->mnOrientation );
    2745           0 :             aOutPoint += aAdjPoint;
    2746           0 :             aOutPoint -= Point( nEmphasisWidth2, nEmphasisHeight2 );
    2747           0 :             ImplDrawEmphasisMark( rSalLayout.DrawBase().X(),
    2748           0 :                                   aOutPoint.X(), aOutPoint.Y(),
    2749           0 :                                   aPolyPoly, bPolyLine, aRect1, aRect2 );
    2750             :         }
    2751           0 :     }
    2752             : 
    2753           0 :     SetLineColor( aOldLineColor );
    2754           0 :     SetFillColor( aOldFillColor );
    2755           0 :     EnableMapMode( bOldMap );
    2756           0 :     mpMetaFile = pOldMetaFile;
    2757           0 : }
    2758             : 
    2759           0 : bool OutputDevice::ImplDrawRotateText( SalLayout& rSalLayout )
    2760             : {
    2761           0 :     int nX = rSalLayout.DrawBase().X();
    2762           0 :     int nY = rSalLayout.DrawBase().Y();
    2763             : 
    2764           0 :     Rectangle aBoundRect;
    2765           0 :     rSalLayout.DrawBase() = Point( 0, 0 );
    2766           0 :     rSalLayout.DrawOffset() = Point( 0, 0 );
    2767           0 :     if( !rSalLayout.GetBoundRect( *mpGraphics, aBoundRect ) )
    2768             :     {
    2769             :         // guess vertical text extents if GetBoundRect failed
    2770           0 :         int nRight = rSalLayout.GetTextWidth();
    2771           0 :         int nTop = mpFontEntry->maMetric.mnAscent + mnEmphasisAscent;
    2772           0 :         long nHeight = mpFontEntry->mnLineHeight + mnEmphasisAscent + mnEmphasisDescent;
    2773           0 :         aBoundRect = Rectangle( 0, -nTop, nRight, nHeight - nTop );
    2774             :     }
    2775             : 
    2776             :     // cache virtual device for rotation
    2777           0 :     if ( !mpOutDevData )
    2778           0 :         ImplInitOutDevData();
    2779           0 :     if ( !mpOutDevData->mpRotateDev )
    2780           0 :         mpOutDevData->mpRotateDev = new VirtualDevice( *this, 1 );
    2781           0 :     VirtualDevice* pVDev = mpOutDevData->mpRotateDev;
    2782             : 
    2783             :     // size it accordingly
    2784           0 :     if( !pVDev->SetOutputSizePixel( aBoundRect.GetSize() ) )
    2785           0 :         return false;
    2786             : 
    2787           0 :     Font aFont( GetFont() );
    2788           0 :     aFont.SetOrientation( 0 );
    2789           0 :     aFont.SetSize( Size( mpFontEntry->maFontSelData.mnWidth, mpFontEntry->maFontSelData.mnHeight ) );
    2790           0 :     pVDev->SetFont( aFont );
    2791           0 :     pVDev->SetTextColor( Color( COL_BLACK ) );
    2792           0 :     pVDev->SetTextFillColor();
    2793           0 :     pVDev->ImplNewFont();
    2794           0 :     pVDev->ImplInitFont();
    2795           0 :     pVDev->ImplInitTextColor();
    2796             : 
    2797             :     // draw text into upper left corner
    2798           0 :     rSalLayout.DrawBase() -= aBoundRect.TopLeft();
    2799           0 :     rSalLayout.DrawText( *((OutputDevice*)pVDev)->mpGraphics );
    2800             : 
    2801           0 :     Bitmap aBmp = pVDev->GetBitmap( Point(), aBoundRect.GetSize() );
    2802           0 :     if ( !aBmp || !aBmp.Rotate( mpFontEntry->mnOwnOrientation, COL_WHITE ) )
    2803           0 :         return false;
    2804             : 
    2805             :     // calculate rotation offset
    2806           0 :     Polygon aPoly( aBoundRect );
    2807           0 :     aPoly.Rotate( Point(), mpFontEntry->mnOwnOrientation );
    2808           0 :     Point aPoint = aPoly.GetBoundRect().TopLeft();
    2809           0 :     aPoint += Point( nX, nY );
    2810             : 
    2811             :     // mask output with text colored bitmap
    2812           0 :     GDIMetaFile* pOldMetaFile = mpMetaFile;
    2813           0 :     long nOldOffX = mnOutOffX;
    2814           0 :     long nOldOffY = mnOutOffY;
    2815           0 :     bool bOldMap = mbMap;
    2816             : 
    2817           0 :     mnOutOffX   = 0L;
    2818           0 :     mnOutOffY   = 0L;
    2819           0 :     mpMetaFile  = NULL;
    2820           0 :     EnableMapMode( false );
    2821             : 
    2822           0 :     DrawMask( aPoint, aBmp, GetTextColor() );
    2823             : 
    2824           0 :     EnableMapMode( bOldMap );
    2825           0 :     mnOutOffX   = nOldOffX;
    2826           0 :     mnOutOffY   = nOldOffY;
    2827           0 :     mpMetaFile  = pOldMetaFile;
    2828             : 
    2829           0 :     return true;
    2830             : }
    2831             : 
    2832           0 : bool OutputDevice::ImplDrawTextDirect( SalLayout& rSalLayout, bool bTextLines, sal_uInt32 flags )
    2833             : {
    2834           0 :     if( mpFontEntry->mnOwnOrientation )
    2835           0 :         if( ImplDrawRotateText( rSalLayout ) )
    2836           0 :             return true;
    2837             : 
    2838           0 :     long nOldX = rSalLayout.DrawBase().X();
    2839           0 :     if( HasMirroredGraphics() )
    2840             :     {
    2841           0 :         long w = meOutDevType == OUTDEV_VIRDEV ? mnOutWidth : mpGraphics->GetGraphicsWidth();
    2842           0 :         long x = rSalLayout.DrawBase().X();
    2843           0 :            rSalLayout.DrawBase().X() = w - 1 - x;
    2844           0 :         if( !IsRTLEnabled() )
    2845             :         {
    2846           0 :             OutputDevice *pOutDevRef = (OutputDevice *)this;
    2847             :             // mirror this window back
    2848           0 :             long devX = w-pOutDevRef->mnOutWidth-pOutDevRef->mnOutOffX;   // re-mirrored mnOutOffX
    2849           0 :             rSalLayout.DrawBase().X() = devX + ( pOutDevRef->mnOutWidth - 1 - (rSalLayout.DrawBase().X() - devX) ) ;
    2850             :         }
    2851             :     }
    2852           0 :     else if( IsRTLEnabled() )
    2853             :     {
    2854           0 :         OutputDevice *pOutDevRef = (OutputDevice *)this;
    2855             : 
    2856             :         // mirror this window back
    2857           0 :         long devX = pOutDevRef->mnOutOffX;   // re-mirrored mnOutOffX
    2858           0 :         rSalLayout.DrawBase().X() = pOutDevRef->mnOutWidth - 1 - (rSalLayout.DrawBase().X() - devX) + devX;
    2859             :     }
    2860             : 
    2861           0 :     if(flags)
    2862             :     {
    2863           0 :         if( ! rSalLayout.DrawTextSpecial( *mpGraphics, flags ))
    2864             :         {
    2865           0 :             rSalLayout.DrawBase().X() = nOldX;
    2866           0 :             return false;
    2867             :         }
    2868             :     }
    2869             :     else
    2870             :     {
    2871           0 :         rSalLayout.DrawText( *mpGraphics );
    2872             :     }
    2873           0 :     rSalLayout.DrawBase().X() = nOldX;
    2874             : 
    2875           0 :     if( bTextLines )
    2876             :         ImplDrawTextLines( rSalLayout,
    2877             :             maFont.GetStrikeout(), maFont.GetUnderline(), maFont.GetOverline(),
    2878           0 :             maFont.IsWordLineMode(), ImplIsUnderlineAbove( maFont ) );
    2879             : 
    2880             :     // emphasis marks
    2881           0 :     if( maFont.GetEmphasisMark() & EMPHASISMARK_STYLE )
    2882           0 :         ImplDrawEmphasisMarks( rSalLayout );
    2883             : 
    2884           0 :     return true;
    2885             : }
    2886             : 
    2887           0 : void OutputDevice::ImplDrawSpecialText( SalLayout& rSalLayout )
    2888             : {
    2889           0 :     Color       aOldColor           = GetTextColor();
    2890           0 :     Color       aOldTextLineColor   = GetTextLineColor();
    2891           0 :     Color       aOldOverlineColor   = GetOverlineColor();
    2892           0 :     FontRelief  eRelief             = maFont.GetRelief();
    2893             : 
    2894           0 :     Point aOrigPos = rSalLayout.DrawBase();
    2895           0 :     if ( eRelief != RELIEF_NONE )
    2896             :     {
    2897           0 :         Color   aReliefColor( COL_LIGHTGRAY );
    2898           0 :         Color   aTextColor( aOldColor );
    2899             : 
    2900           0 :         Color   aTextLineColor( aOldTextLineColor );
    2901           0 :         Color   aOverlineColor( aOldOverlineColor );
    2902             : 
    2903             :         // we don't have a automatic color, so black is always drawn on white
    2904           0 :         if ( aTextColor.GetColor() == COL_BLACK )
    2905           0 :             aTextColor = Color( COL_WHITE );
    2906           0 :         if ( aTextLineColor.GetColor() == COL_BLACK )
    2907           0 :             aTextLineColor = Color( COL_WHITE );
    2908           0 :         if ( aOverlineColor.GetColor() == COL_BLACK )
    2909           0 :             aOverlineColor = Color( COL_WHITE );
    2910             : 
    2911             :         // relief-color is black for white text, in all other cases
    2912             :         // we set this to LightGray
    2913           0 :         if ( aTextColor.GetColor() == COL_WHITE )
    2914           0 :             aReliefColor = Color( COL_BLACK );
    2915           0 :         SetTextLineColor( aReliefColor );
    2916           0 :         SetOverlineColor( aReliefColor );
    2917           0 :         SetTextColor( aReliefColor );
    2918           0 :         ImplInitTextColor();
    2919             : 
    2920             :         // calculate offset - for high resolution printers the offset
    2921             :         // should be greater so that the effect is visible
    2922           0 :         long nOff = 1;
    2923           0 :         nOff += mnDPIX/300;
    2924             : 
    2925           0 :         if ( eRelief == RELIEF_ENGRAVED )
    2926           0 :             nOff = -nOff;
    2927           0 :         rSalLayout.DrawOffset() += Point( nOff, nOff);
    2928           0 :         ImplDrawTextDirect( rSalLayout, mbTextLines );
    2929           0 :         rSalLayout.DrawOffset() -= Point( nOff, nOff);
    2930             : 
    2931           0 :         SetTextLineColor( aTextLineColor );
    2932           0 :         SetOverlineColor( aOverlineColor );
    2933           0 :         SetTextColor( aTextColor );
    2934           0 :         ImplInitTextColor();
    2935           0 :         ImplDrawTextDirect( rSalLayout, mbTextLines );
    2936             : 
    2937           0 :         SetTextLineColor( aOldTextLineColor );
    2938           0 :         SetOverlineColor( aOldOverlineColor );
    2939             : 
    2940           0 :         if ( aTextColor != aOldColor )
    2941             :         {
    2942           0 :             SetTextColor( aOldColor );
    2943           0 :             ImplInitTextColor();
    2944             :         }
    2945             :     }
    2946             :     else
    2947             :     {
    2948           0 :         if ( maFont.IsShadow() )
    2949             :         {
    2950           0 :             long nOff = 1 + ((mpFontEntry->mnLineHeight-24)/24);
    2951           0 :             if ( maFont.IsOutline() )
    2952           0 :                 nOff++;
    2953           0 :             SetTextLineColor();
    2954           0 :             SetOverlineColor();
    2955           0 :             if ( (GetTextColor().GetColor() == COL_BLACK)
    2956           0 :             ||   (GetTextColor().GetLuminance() < 8) )
    2957           0 :                 SetTextColor( Color( COL_LIGHTGRAY ) );
    2958             :             else
    2959           0 :                 SetTextColor( Color( COL_BLACK ) );
    2960           0 :             ImplInitTextColor();
    2961           0 :             rSalLayout.DrawBase() += Point( nOff, nOff );
    2962           0 :             ImplDrawTextDirect( rSalLayout, mbTextLines );
    2963           0 :             rSalLayout.DrawBase() -= Point( nOff, nOff );
    2964           0 :             SetTextColor( aOldColor );
    2965           0 :             SetTextLineColor( aOldTextLineColor );
    2966           0 :             SetOverlineColor( aOldOverlineColor );
    2967           0 :             ImplInitTextColor();
    2968             : 
    2969           0 :             if ( !maFont.IsOutline() )
    2970           0 :                 ImplDrawTextDirect( rSalLayout, mbTextLines );
    2971             :         }
    2972             : 
    2973           0 :         if ( maFont.IsOutline() )
    2974             :         {
    2975           0 :             if(! ImplDrawTextDirect( rSalLayout, mbTextLines, DRAWTEXT_F_OUTLINE))
    2976             :             {
    2977           0 :                 rSalLayout.DrawBase() = aOrigPos + Point(-1,-1);
    2978           0 :                 ImplDrawTextDirect( rSalLayout, mbTextLines );
    2979           0 :                 rSalLayout.DrawBase() = aOrigPos + Point(+1,+1);
    2980           0 :                 ImplDrawTextDirect( rSalLayout, mbTextLines );
    2981           0 :                 rSalLayout.DrawBase() = aOrigPos + Point(-1,+0);
    2982           0 :                 ImplDrawTextDirect( rSalLayout, mbTextLines );
    2983           0 :                 rSalLayout.DrawBase() = aOrigPos + Point(-1,+1);
    2984           0 :                 ImplDrawTextDirect( rSalLayout, mbTextLines );
    2985           0 :                 rSalLayout.DrawBase() = aOrigPos + Point(+0,+1);
    2986           0 :                 ImplDrawTextDirect( rSalLayout, mbTextLines );
    2987           0 :                 rSalLayout.DrawBase() = aOrigPos + Point(+0,-1);
    2988           0 :                 ImplDrawTextDirect( rSalLayout, mbTextLines );
    2989           0 :                 rSalLayout.DrawBase() = aOrigPos + Point(+1,-1);
    2990           0 :                 ImplDrawTextDirect( rSalLayout, mbTextLines );
    2991           0 :                 rSalLayout.DrawBase() = aOrigPos + Point(+1,+0);
    2992           0 :                 ImplDrawTextDirect( rSalLayout, mbTextLines );
    2993           0 :                 rSalLayout.DrawBase() = aOrigPos;
    2994             : 
    2995           0 :                 SetTextColor( Color( COL_WHITE ) );
    2996           0 :                 SetTextLineColor( Color( COL_WHITE ) );
    2997           0 :                 SetOverlineColor( Color( COL_WHITE ) );
    2998           0 :                 ImplInitTextColor();
    2999           0 :                 ImplDrawTextDirect( rSalLayout, mbTextLines );
    3000           0 :                 SetTextColor( aOldColor );
    3001           0 :                 SetTextLineColor( aOldTextLineColor );
    3002           0 :                 SetOverlineColor( aOldOverlineColor );
    3003           0 :                 ImplInitTextColor();
    3004             :             }
    3005             :         }
    3006             :     }
    3007           0 : }
    3008             : 
    3009           0 : void OutputDevice::ImplDrawText( SalLayout& rSalLayout )
    3010             : {
    3011           0 :     if( mbInitClipRegion )
    3012           0 :         ImplInitClipRegion();
    3013           0 :     if( mbOutputClipped )
    3014           0 :         return;
    3015           0 :     if( mbInitTextColor )
    3016           0 :         ImplInitTextColor();
    3017             : 
    3018           0 :     rSalLayout.DrawBase() += Point( mnTextOffX, mnTextOffY );
    3019             : 
    3020           0 :     if( IsTextFillColor() )
    3021           0 :         ImplDrawTextBackground( rSalLayout );
    3022             : 
    3023           0 :     if( mbTextSpecial )
    3024           0 :         ImplDrawSpecialText( rSalLayout );
    3025             :     else
    3026           0 :         ImplDrawTextDirect( rSalLayout, mbTextLines );
    3027             : }
    3028             : 
    3029           0 : long OutputDevice::ImplGetTextLines( ImplMultiTextLineInfo& rLineInfo,
    3030             :                                      long nWidth, const OUString& rStr,
    3031             :                                      sal_uInt16 nStyle, const ::vcl::ITextLayout& _rLayout )
    3032             : {
    3033             :     DBG_ASSERTWARNING( nWidth >= 0, "ImplGetTextLines: nWidth <= 0!" );
    3034             : 
    3035           0 :     if ( nWidth <= 0 )
    3036           0 :         nWidth = 1;
    3037             : 
    3038           0 :     long nMaxLineWidth  = 0;
    3039           0 :     rLineInfo.Clear();
    3040           0 :     if ( !rStr.isEmpty() && (nWidth > 0) )
    3041             :     {
    3042           0 :         uno::Reference < i18n::XBreakIterator > xBI;
    3043             :         // get service provider
    3044           0 :         uno::Reference< uno::XComponentContext > xContext( comphelper::getProcessComponentContext() );
    3045             : 
    3046           0 :         bool bHyphenate = (nStyle & TEXT_DRAW_WORDBREAK_HYPHENATION)
    3047           0 :             == TEXT_DRAW_WORDBREAK_HYPHENATION;
    3048           0 :         uno::Reference< linguistic2::XHyphenator > xHyph;
    3049           0 :         if ( bHyphenate )
    3050             :         {
    3051           0 :             uno::Reference< linguistic2::XLinguServiceManager2> xLinguMgr = linguistic2::LinguServiceManager::create(xContext);
    3052           0 :             xHyph = xLinguMgr->getHyphenator();
    3053             :         }
    3054             : 
    3055           0 :         sal_Int32 nPos = 0;
    3056           0 :         sal_Int32 nLen = rStr.getLength();
    3057           0 :         while ( nPos < nLen )
    3058             :         {
    3059           0 :             sal_Int32 nBreakPos = nPos;
    3060             : 
    3061           0 :             while ( ( nBreakPos < nLen ) && ( rStr[ nBreakPos ] != '\r' ) && ( rStr[ nBreakPos ] != '\n' ) )
    3062           0 :                 nBreakPos++;
    3063             : 
    3064           0 :             long nLineWidth = _rLayout.GetTextWidth( rStr, nPos, nBreakPos-nPos );
    3065           0 :             if ( ( nLineWidth > nWidth ) && ( nStyle & TEXT_DRAW_WORDBREAK ) )
    3066             :             {
    3067           0 :                 if ( !xBI.is() )
    3068           0 :                     xBI = vcl::unohelper::CreateBreakIterator();
    3069             : 
    3070           0 :                 if ( xBI.is() )
    3071             :                 {
    3072           0 :                     const com::sun::star::lang::Locale& rDefLocale(Application::GetSettings().GetUILanguageTag().getLocale());
    3073           0 :                     sal_Int32 nSoftBreak = _rLayout.GetTextBreak( rStr, nWidth, nPos, nBreakPos - nPos );
    3074             :                     DBG_ASSERT( nSoftBreak < nBreakPos, "Break?!" );
    3075           0 :                     i18n::LineBreakHyphenationOptions aHyphOptions( xHyph, uno::Sequence <beans::PropertyValue>(), 1 );
    3076           0 :                     i18n::LineBreakUserOptions aUserOptions;
    3077           0 :                     i18n::LineBreakResults aLBR = xBI->getLineBreak( rStr, nSoftBreak, rDefLocale, nPos, aHyphOptions, aUserOptions );
    3078           0 :                     nBreakPos = aLBR.breakIndex;
    3079           0 :                     if ( nBreakPos <= nPos )
    3080           0 :                         nBreakPos = nSoftBreak;
    3081           0 :                     if ( bHyphenate )
    3082             :                     {
    3083             :                         // Whether hyphen or not: Put the word after the hyphen through
    3084             :                         // word boundary.
    3085             : 
    3086             :                         // nMaxBreakPos the last char that fits into the line
    3087             :                         // nBreakPos is the word's start
    3088             : 
    3089             :                         // We run into a problem if the doc is so narrow, that a word
    3090             :                         // is broken into more than two lines ...
    3091           0 :                         if ( xHyph.is() )
    3092             :                         {
    3093           0 :                             sal_Unicode cAlternateReplChar = 0;
    3094           0 :                             i18n::Boundary aBoundary = xBI->getWordBoundary( rStr, nBreakPos, rDefLocale, ::com::sun::star::i18n::WordType::DICTIONARY_WORD, sal_True );
    3095           0 :                             sal_Int32 nWordStart = nPos;
    3096           0 :                             sal_Int32 nWordEnd = aBoundary.endPos;
    3097             :                             DBG_ASSERT( nWordEnd > nWordStart, "ImpBreakLine: Start >= End?" );
    3098             : 
    3099           0 :                             sal_Int32 nWordLen = nWordEnd - nWordStart;
    3100           0 :                             if ( ( nWordEnd >= nSoftBreak ) && ( nWordLen > 3 ) )
    3101             :                             {
    3102             :                                 // #104415# May happen, because getLineBreak may differ from getWordBoudary with DICTIONARY_WORD
    3103             :                                 // DBG_ASSERT( nWordEnd >= nMaxBreakPos, "Hyph: Break?" );
    3104           0 :                                 OUString aWord = rStr.copy( nWordStart, nWordLen );
    3105           0 :                                 sal_Int32 nMinTrail = nWordEnd-nSoftBreak+1;  //+1: Before the "broken off" char
    3106           0 :                                 uno::Reference< linguistic2::XHyphenatedWord > xHyphWord;
    3107           0 :                                 if (xHyph.is())
    3108           0 :                                     xHyphWord = xHyph->hyphenate( aWord, rDefLocale, aWord.getLength() - nMinTrail, uno::Sequence< beans::PropertyValue >() );
    3109           0 :                                 if (xHyphWord.is())
    3110             :                                 {
    3111           0 :                                     bool bAlternate = xHyphWord->isAlternativeSpelling();
    3112           0 :                                     sal_Int32 _nWordLen = 1 + xHyphWord->getHyphenPos();
    3113             : 
    3114           0 :                                     if ( ( _nWordLen >= 2 ) && ( (nWordStart+_nWordLen) >= ( 2 ) ) )
    3115             :                                     {
    3116           0 :                                         if ( !bAlternate )
    3117             :                                         {
    3118           0 :                                             nBreakPos = nWordStart + _nWordLen;
    3119             :                                         }
    3120             :                                         else
    3121             :                                         {
    3122           0 :                                             OUString aAlt( xHyphWord->getHyphenatedWord() );
    3123             : 
    3124             :                                             // We can have two cases:
    3125             :                                             // 1) "packen" turns into "pak-ken"
    3126             :                                             // 2) "Schiffahrt" turns into "Schiff-fahrt"
    3127             : 
    3128             :                                             // In case 1 we need to replace a char
    3129             :                                             // In case 2 we add a char
    3130             : 
    3131             :                                             // Correct recognition is made harder by words such as
    3132             :                                             // "Schiffahrtsbrennesseln", as the Hyphenator splits all
    3133             :                                             // positions of the word and comes up with "Schifffahrtsbrennnesseln"
    3134             :                                             // Thus, we cannot infer the aWord from the AlternativWord's
    3135             :                                             // index.
    3136             :                                             // TODO: The whole junk will be made easier by a function in
    3137             :                                             // the Hyphenator, as soon as AMA adds it.
    3138           0 :                                             sal_Int32 nAltStart = _nWordLen - 1;
    3139           0 :                                             sal_Int32 nTxtStart = nAltStart - (aAlt.getLength() - aWord.getLength());
    3140           0 :                                             sal_Int32 nTxtEnd = nTxtStart;
    3141           0 :                                             sal_Int32 nAltEnd = nAltStart;
    3142             : 
    3143             :                                             // The area between nStart and nEnd is the difference
    3144             :                                             // between AlternativString and OriginalString
    3145           0 :                                             while( nTxtEnd < aWord.getLength() && nAltEnd < aAlt.getLength() &&
    3146           0 :                                                    aWord[nTxtEnd] != aAlt[nAltEnd] )
    3147             :                                             {
    3148           0 :                                                 ++nTxtEnd;
    3149           0 :                                                 ++nAltEnd;
    3150             :                                             }
    3151             : 
    3152             :                                             // If a char was added, we notice it now:
    3153           0 :                                             if( nAltEnd > nTxtEnd && nAltStart == nAltEnd &&
    3154           0 :                                                 aWord[ nTxtEnd ] == aAlt[nAltEnd] )
    3155             :                                             {
    3156           0 :                                                 ++nAltEnd;
    3157           0 :                                                 ++nTxtStart;
    3158           0 :                                                 ++nTxtEnd;
    3159             :                                             }
    3160             : 
    3161             :                                             DBG_ASSERT( ( nAltEnd - nAltStart ) == 1, "Alternate: Wrong assumption!" );
    3162             : 
    3163           0 :                                             if ( nTxtEnd > nTxtStart )
    3164           0 :                                                 cAlternateReplChar = aAlt[ nAltStart ];
    3165             : 
    3166           0 :                                             nBreakPos = nWordStart + nTxtStart;
    3167           0 :                                             if ( cAlternateReplChar )
    3168           0 :                                                 nBreakPos++;
    3169             :                                         }
    3170             :                                     }
    3171           0 :                                 }
    3172             :                             }
    3173             :                         }
    3174             :                     }
    3175           0 :                     nLineWidth = _rLayout.GetTextWidth( rStr, nPos, nBreakPos-nPos );
    3176             :                 }
    3177             :                 else
    3178             :                 {
    3179             :                     // fallback to something really simple
    3180           0 :                     sal_Int32 nSpacePos = rStr.getLength();
    3181           0 :                     long nW = 0;
    3182           0 :                     do
    3183             :                     {
    3184           0 :                         nSpacePos = rStr.lastIndexOf( ' ', nSpacePos );
    3185           0 :                         if( nSpacePos != -1 )
    3186             :                         {
    3187           0 :                             if( nSpacePos > nPos )
    3188           0 :                                 nSpacePos--;
    3189           0 :                             nW = _rLayout.GetTextWidth( rStr, nPos, nSpacePos-nPos );
    3190             :                         }
    3191             :                     } while( nW > nWidth );
    3192             : 
    3193           0 :                     if( nSpacePos != -1 )
    3194             :                     {
    3195           0 :                         nBreakPos = nSpacePos;
    3196           0 :                         nLineWidth = _rLayout.GetTextWidth( rStr, nPos, nBreakPos-nPos );
    3197           0 :                         if( nBreakPos < rStr.getLength()-1 )
    3198           0 :                             nBreakPos++;
    3199             :                     }
    3200             :                 }
    3201             :             }
    3202             : 
    3203           0 :             if ( nLineWidth > nMaxLineWidth )
    3204           0 :                 nMaxLineWidth = nLineWidth;
    3205             : 
    3206           0 :             rLineInfo.AddLine( new ImplTextLineInfo( nLineWidth, nPos, nBreakPos-nPos ) );
    3207             : 
    3208           0 :             if ( nBreakPos == nPos )
    3209           0 :                 nBreakPos++;
    3210           0 :             nPos = nBreakPos;
    3211             : 
    3212           0 :             if ( nPos < nLen && ( ( rStr[ nPos ] == '\r' ) || ( rStr[ nPos ] == '\n' ) ) )
    3213             :             {
    3214           0 :                 nPos++;
    3215             :                 // CR/LF?
    3216           0 :                 if ( ( nPos < nLen ) && ( rStr[ nPos ] == '\n' ) && ( rStr[ nPos-1 ] == '\r' ) )
    3217           0 :                     nPos++;
    3218             :             }
    3219           0 :         }
    3220             :     }
    3221             : #ifdef DBG_UTIL
    3222             :     for ( sal_uInt16 nL = 0; nL < rLineInfo.Count(); nL++ )
    3223             :     {
    3224             :         ImplTextLineInfo* pLine = rLineInfo.GetLine( nL );
    3225             :         OUString aLine = rStr.copy( pLine->GetIndex(), pLine->GetLen() );
    3226             :         DBG_ASSERT( aLine.indexOf( '\r' ) == -1, "ImplGetTextLines - Found CR!" );
    3227             :         DBG_ASSERT( aLine.indexOf( '\n' ) == -1, "ImplGetTextLines - Found LF!" );
    3228             :     }
    3229             : #endif
    3230             : 
    3231           0 :     return nMaxLineWidth;
    3232             : }
    3233             : 
    3234           0 : void OutputDevice::SetAntialiasing( sal_uInt16 nMode )
    3235             : {
    3236           0 :     if ( mnAntialiasing != nMode )
    3237             :     {
    3238           0 :         mnAntialiasing = nMode;
    3239           0 :         mbInitFont = true;
    3240             : 
    3241           0 :         if(mpGraphics)
    3242             :         {
    3243           0 :             mpGraphics->setAntiAliasB2DDraw(mnAntialiasing & ANTIALIASING_ENABLE_B2DDRAW);
    3244             :         }
    3245             :     }
    3246             : 
    3247           0 :     if( mpAlphaVDev )
    3248           0 :         mpAlphaVDev->SetAntialiasing( nMode );
    3249           0 : }
    3250             : 
    3251           0 : void OutputDevice::SetFont( const Font& rNewFont )
    3252             : {
    3253             : 
    3254           0 :     Font aFont( rNewFont );
    3255           0 :     aFont.SetLanguage(rNewFont.GetLanguage());
    3256           0 :     if ( mnDrawMode & (DRAWMODE_BLACKTEXT | DRAWMODE_WHITETEXT | DRAWMODE_GRAYTEXT | DRAWMODE_GHOSTEDTEXT | DRAWMODE_SETTINGSTEXT |
    3257             :                        DRAWMODE_BLACKFILL | DRAWMODE_WHITEFILL | DRAWMODE_GRAYFILL | DRAWMODE_NOFILL |
    3258             :                        DRAWMODE_GHOSTEDFILL | DRAWMODE_SETTINGSFILL ) )
    3259             :     {
    3260           0 :         Color aTextColor( aFont.GetColor() );
    3261             : 
    3262           0 :         if ( mnDrawMode & DRAWMODE_BLACKTEXT )
    3263           0 :             aTextColor = Color( COL_BLACK );
    3264           0 :         else if ( mnDrawMode & DRAWMODE_WHITETEXT )
    3265           0 :             aTextColor = Color( COL_WHITE );
    3266           0 :         else if ( mnDrawMode & DRAWMODE_GRAYTEXT )
    3267             :         {
    3268           0 :             const sal_uInt8 cLum = aTextColor.GetLuminance();
    3269           0 :             aTextColor = Color( cLum, cLum, cLum );
    3270             :         }
    3271           0 :         else if ( mnDrawMode & DRAWMODE_SETTINGSTEXT )
    3272           0 :             aTextColor = GetSettings().GetStyleSettings().GetFontColor();
    3273             : 
    3274           0 :         if ( mnDrawMode & DRAWMODE_GHOSTEDTEXT )
    3275             :         {
    3276           0 :             aTextColor = Color( (aTextColor.GetRed() >> 1 ) | 0x80,
    3277           0 :                                 (aTextColor.GetGreen() >> 1 ) | 0x80,
    3278           0 :                                 (aTextColor.GetBlue() >> 1 ) | 0x80 );
    3279             :         }
    3280             : 
    3281           0 :         aFont.SetColor( aTextColor );
    3282             : 
    3283           0 :         bool bTransFill = aFont.IsTransparent();
    3284           0 :         if ( !bTransFill )
    3285             :         {
    3286           0 :             Color aTextFillColor( aFont.GetFillColor() );
    3287             : 
    3288           0 :             if ( mnDrawMode & DRAWMODE_BLACKFILL )
    3289           0 :                 aTextFillColor = Color( COL_BLACK );
    3290           0 :             else if ( mnDrawMode & DRAWMODE_WHITEFILL )
    3291           0 :                 aTextFillColor = Color( COL_WHITE );
    3292           0 :             else if ( mnDrawMode & DRAWMODE_GRAYFILL )
    3293             :             {
    3294           0 :                 const sal_uInt8 cLum = aTextFillColor.GetLuminance();
    3295           0 :                 aTextFillColor = Color( cLum, cLum, cLum );
    3296             :             }
    3297           0 :             else if( mnDrawMode & DRAWMODE_SETTINGSFILL )
    3298           0 :                 aTextFillColor = GetSettings().GetStyleSettings().GetWindowColor();
    3299           0 :             else if ( mnDrawMode & DRAWMODE_NOFILL )
    3300             :             {
    3301           0 :                 aTextFillColor = Color( COL_TRANSPARENT );
    3302           0 :                 bTransFill = true;
    3303             :             }
    3304             : 
    3305           0 :             if ( !bTransFill && (mnDrawMode & DRAWMODE_GHOSTEDFILL) )
    3306             :             {
    3307           0 :                 aTextFillColor = Color( (aTextFillColor.GetRed() >> 1) | 0x80,
    3308           0 :                                         (aTextFillColor.GetGreen() >> 1) | 0x80,
    3309           0 :                                         (aTextFillColor.GetBlue() >> 1) | 0x80 );
    3310             :             }
    3311             : 
    3312           0 :             aFont.SetFillColor( aTextFillColor );
    3313             :         }
    3314             :     }
    3315             : 
    3316           0 :     if ( mpMetaFile )
    3317             :     {
    3318           0 :         mpMetaFile->AddAction( new MetaFontAction( aFont ) );
    3319             :         // the color and alignment actions don't belong here
    3320             :         // TODO: get rid of them without breaking anything...
    3321           0 :         mpMetaFile->AddAction( new MetaTextAlignAction( aFont.GetAlign() ) );
    3322           0 :         mpMetaFile->AddAction( new MetaTextFillColorAction( aFont.GetFillColor(), !aFont.IsTransparent() ) );
    3323             :     }
    3324             : 
    3325           0 :     if ( !maFont.IsSameInstance( aFont ) )
    3326             :     {
    3327             :         // Optimization MT/HDU: COL_TRANSPARENT means SetFont should ignore the font color,
    3328             :         // because SetTextColor() is used for this.
    3329             :         // #i28759# maTextColor might have been changed behind our back, commit then, too.
    3330           0 :         if( aFont.GetColor() != COL_TRANSPARENT
    3331           0 :         && (aFont.GetColor() != maFont.GetColor() || aFont.GetColor() != maTextColor ) )
    3332             :         {
    3333           0 :             maTextColor = aFont.GetColor();
    3334           0 :             mbInitTextColor = true;
    3335           0 :             if( mpMetaFile )
    3336           0 :                 mpMetaFile->AddAction( new MetaTextColorAction( aFont.GetColor() ) );
    3337             :         }
    3338           0 :         maFont      = aFont;
    3339           0 :         mbNewFont   = true;
    3340             : 
    3341           0 :         if( mpAlphaVDev )
    3342             :         {
    3343             :             // #i30463#
    3344             :             // Since SetFont might change the text color, apply that only
    3345             :             // selectively to alpha vdev (which normally paints opaque text
    3346             :             // with COL_BLACK)
    3347           0 :             if( aFont.GetColor() != COL_TRANSPARENT )
    3348             :             {
    3349           0 :                 mpAlphaVDev->SetTextColor( COL_BLACK );
    3350           0 :                 aFont.SetColor( COL_TRANSPARENT );
    3351             :             }
    3352             : 
    3353           0 :             mpAlphaVDev->SetFont( aFont );
    3354             :         }
    3355           0 :     }
    3356           0 : }
    3357             : 
    3358           0 : void OutputDevice::SetLayoutMode( sal_uLong nTextLayoutMode )
    3359             : {
    3360           0 :     if( mpMetaFile )
    3361           0 :         mpMetaFile->AddAction( new MetaLayoutModeAction( nTextLayoutMode ) );
    3362             : 
    3363           0 :     mnTextLayoutMode = nTextLayoutMode;
    3364             : 
    3365           0 :     if( mpAlphaVDev )
    3366           0 :         mpAlphaVDev->SetLayoutMode( nTextLayoutMode );
    3367           0 : }
    3368             : 
    3369           0 : void OutputDevice::SetDigitLanguage( LanguageType eTextLanguage )
    3370             : {
    3371           0 :     if( mpMetaFile )
    3372           0 :         mpMetaFile->AddAction( new MetaTextLanguageAction( eTextLanguage ) );
    3373             : 
    3374           0 :     meTextLanguage = eTextLanguage;
    3375             : 
    3376           0 :     if( mpAlphaVDev )
    3377           0 :         mpAlphaVDev->SetDigitLanguage( eTextLanguage );
    3378           0 : }
    3379             : 
    3380           0 : void OutputDevice::SetTextColor( const Color& rColor )
    3381             : {
    3382             : 
    3383           0 :     Color aColor( rColor );
    3384             : 
    3385           0 :     if ( mnDrawMode & ( DRAWMODE_BLACKTEXT | DRAWMODE_WHITETEXT |
    3386             :                         DRAWMODE_GRAYTEXT | DRAWMODE_GHOSTEDTEXT |
    3387             :                         DRAWMODE_SETTINGSTEXT ) )
    3388             :     {
    3389           0 :         if ( mnDrawMode & DRAWMODE_BLACKTEXT )
    3390           0 :             aColor = Color( COL_BLACK );
    3391           0 :         else if ( mnDrawMode & DRAWMODE_WHITETEXT )
    3392           0 :             aColor = Color( COL_WHITE );
    3393           0 :         else if ( mnDrawMode & DRAWMODE_GRAYTEXT )
    3394             :         {
    3395           0 :             const sal_uInt8 cLum = aColor.GetLuminance();
    3396           0 :             aColor = Color( cLum, cLum, cLum );
    3397             :         }
    3398           0 :         else if ( mnDrawMode & DRAWMODE_SETTINGSTEXT )
    3399           0 :             aColor = GetSettings().GetStyleSettings().GetFontColor();
    3400             : 
    3401           0 :         if ( mnDrawMode & DRAWMODE_GHOSTEDTEXT )
    3402             :         {
    3403           0 :             aColor = Color( (aColor.GetRed() >> 1) | 0x80,
    3404           0 :                             (aColor.GetGreen() >> 1) | 0x80,
    3405           0 :                             (aColor.GetBlue() >> 1) | 0x80 );
    3406             :         }
    3407             :     }
    3408             : 
    3409           0 :     if ( mpMetaFile )
    3410           0 :         mpMetaFile->AddAction( new MetaTextColorAction( aColor ) );
    3411             : 
    3412           0 :     if ( maTextColor != aColor )
    3413             :     {
    3414           0 :         maTextColor = aColor;
    3415           0 :         mbInitTextColor = true;
    3416             :     }
    3417             : 
    3418           0 :     if( mpAlphaVDev )
    3419           0 :         mpAlphaVDev->SetTextColor( COL_BLACK );
    3420           0 : }
    3421             : 
    3422           0 : void OutputDevice::SetTextFillColor()
    3423             : {
    3424             : 
    3425           0 :     if ( mpMetaFile )
    3426           0 :         mpMetaFile->AddAction( new MetaTextFillColorAction( Color(), false ) );
    3427             : 
    3428           0 :     if ( maFont.GetColor() != Color( COL_TRANSPARENT ) )
    3429           0 :         maFont.SetFillColor( Color( COL_TRANSPARENT ) );
    3430           0 :     if ( !maFont.IsTransparent() )
    3431           0 :         maFont.SetTransparent( true );
    3432             : 
    3433           0 :     if( mpAlphaVDev )
    3434           0 :         mpAlphaVDev->SetTextFillColor();
    3435           0 : }
    3436             : 
    3437           0 : void OutputDevice::SetTextFillColor( const Color& rColor )
    3438             : {
    3439             : 
    3440           0 :     Color aColor( rColor );
    3441           0 :     bool bTransFill = ImplIsColorTransparent( aColor ) ? sal_True : sal_False;
    3442             : 
    3443           0 :     if ( !bTransFill )
    3444             :     {
    3445           0 :         if ( mnDrawMode & ( DRAWMODE_BLACKFILL | DRAWMODE_WHITEFILL |
    3446             :                             DRAWMODE_GRAYFILL | DRAWMODE_NOFILL |
    3447             :                             DRAWMODE_GHOSTEDFILL | DRAWMODE_SETTINGSFILL ) )
    3448             :         {
    3449           0 :             if ( mnDrawMode & DRAWMODE_BLACKFILL )
    3450           0 :                 aColor = Color( COL_BLACK );
    3451           0 :             else if ( mnDrawMode & DRAWMODE_WHITEFILL )
    3452           0 :                 aColor = Color( COL_WHITE );
    3453           0 :             else if ( mnDrawMode & DRAWMODE_GRAYFILL )
    3454             :             {
    3455           0 :                 const sal_uInt8 cLum = aColor.GetLuminance();
    3456           0 :                 aColor = Color( cLum, cLum, cLum );
    3457             :             }
    3458           0 :             else if( mnDrawMode & DRAWMODE_SETTINGSFILL )
    3459           0 :                 aColor = GetSettings().GetStyleSettings().GetWindowColor();
    3460           0 :             else if ( mnDrawMode & DRAWMODE_NOFILL )
    3461             :             {
    3462           0 :                 aColor = Color( COL_TRANSPARENT );
    3463           0 :                 bTransFill = true;
    3464             :             }
    3465             : 
    3466           0 :             if ( !bTransFill && (mnDrawMode & DRAWMODE_GHOSTEDFILL) )
    3467             :             {
    3468           0 :                 aColor = Color( (aColor.GetRed() >> 1) | 0x80,
    3469           0 :                                 (aColor.GetGreen() >> 1) | 0x80,
    3470           0 :                                 (aColor.GetBlue() >> 1) | 0x80 );
    3471             :             }
    3472             :         }
    3473             :     }
    3474             : 
    3475           0 :     if ( mpMetaFile )
    3476           0 :         mpMetaFile->AddAction( new MetaTextFillColorAction( aColor, true ) );
    3477             : 
    3478           0 :     if ( maFont.GetFillColor() != aColor )
    3479           0 :         maFont.SetFillColor( aColor );
    3480           0 :     if ( maFont.IsTransparent() != bTransFill )
    3481           0 :         maFont.SetTransparent( bTransFill );
    3482             : 
    3483           0 :     if( mpAlphaVDev )
    3484           0 :         mpAlphaVDev->SetTextFillColor( COL_BLACK );
    3485           0 : }
    3486             : 
    3487           0 : Color OutputDevice::GetTextFillColor() const
    3488             : {
    3489           0 :     if ( maFont.IsTransparent() )
    3490           0 :         return Color( COL_TRANSPARENT );
    3491             :     else
    3492           0 :         return maFont.GetFillColor();
    3493             : }
    3494             : 
    3495           0 : void OutputDevice::SetTextLineColor()
    3496             : {
    3497             : 
    3498           0 :     if ( mpMetaFile )
    3499           0 :         mpMetaFile->AddAction( new MetaTextLineColorAction( Color(), false ) );
    3500             : 
    3501           0 :     maTextLineColor = Color( COL_TRANSPARENT );
    3502             : 
    3503           0 :     if( mpAlphaVDev )
    3504           0 :         mpAlphaVDev->SetTextLineColor();
    3505           0 : }
    3506             : 
    3507           0 : void OutputDevice::SetTextLineColor( const Color& rColor )
    3508             : {
    3509             : 
    3510           0 :     Color aColor( rColor );
    3511             : 
    3512           0 :     if ( mnDrawMode & ( DRAWMODE_BLACKTEXT | DRAWMODE_WHITETEXT |
    3513             :                         DRAWMODE_GRAYTEXT | DRAWMODE_GHOSTEDTEXT |
    3514             :                         DRAWMODE_SETTINGSTEXT ) )
    3515             :     {
    3516           0 :         if ( mnDrawMode & DRAWMODE_BLACKTEXT )
    3517           0 :             aColor = Color( COL_BLACK );
    3518           0 :         else if ( mnDrawMode & DRAWMODE_WHITETEXT )
    3519           0 :             aColor = Color( COL_WHITE );
    3520           0 :         else if ( mnDrawMode & DRAWMODE_GRAYTEXT )
    3521             :         {
    3522           0 :             const sal_uInt8 cLum = aColor.GetLuminance();
    3523           0 :             aColor = Color( cLum, cLum, cLum );
    3524             :         }
    3525           0 :         else if ( mnDrawMode & DRAWMODE_SETTINGSTEXT )
    3526           0 :             aColor = GetSettings().GetStyleSettings().GetFontColor();
    3527             : 
    3528           0 :         if( (mnDrawMode & DRAWMODE_GHOSTEDTEXT)
    3529           0 :         &&  (aColor.GetColor() != COL_TRANSPARENT) )
    3530             :         {
    3531           0 :             aColor = Color( (aColor.GetRed() >> 1) | 0x80,
    3532           0 :                             (aColor.GetGreen() >> 1) | 0x80,
    3533           0 :                             (aColor.GetBlue() >> 1) | 0x80 );
    3534             :         }
    3535             :     }
    3536             : 
    3537           0 :     if ( mpMetaFile )
    3538           0 :         mpMetaFile->AddAction( new MetaTextLineColorAction( aColor, true ) );
    3539             : 
    3540           0 :     maTextLineColor = aColor;
    3541             : 
    3542           0 :     if( mpAlphaVDev )
    3543           0 :         mpAlphaVDev->SetTextLineColor( COL_BLACK );
    3544           0 : }
    3545             : 
    3546           0 : void OutputDevice::SetOverlineColor()
    3547             : {
    3548             : 
    3549           0 :     if ( mpMetaFile )
    3550           0 :         mpMetaFile->AddAction( new MetaOverlineColorAction( Color(), false ) );
    3551             : 
    3552           0 :     maOverlineColor = Color( COL_TRANSPARENT );
    3553             : 
    3554           0 :     if( mpAlphaVDev )
    3555           0 :         mpAlphaVDev->SetOverlineColor();
    3556           0 : }
    3557             : 
    3558           0 : void OutputDevice::SetOverlineColor( const Color& rColor )
    3559             : {
    3560             : 
    3561           0 :     Color aColor( rColor );
    3562             : 
    3563           0 :     if ( mnDrawMode & ( DRAWMODE_BLACKTEXT | DRAWMODE_WHITETEXT |
    3564             :                         DRAWMODE_GRAYTEXT | DRAWMODE_GHOSTEDTEXT |
    3565             :                         DRAWMODE_SETTINGSTEXT ) )
    3566             :     {
    3567           0 :         if ( mnDrawMode & DRAWMODE_BLACKTEXT )
    3568           0 :             aColor = Color( COL_BLACK );
    3569           0 :         else if ( mnDrawMode & DRAWMODE_WHITETEXT )
    3570           0 :             aColor = Color( COL_WHITE );
    3571           0 :         else if ( mnDrawMode & DRAWMODE_GRAYTEXT )
    3572             :         {
    3573           0 :             const sal_uInt8 cLum = aColor.GetLuminance();
    3574           0 :             aColor = Color( cLum, cLum, cLum );
    3575             :         }
    3576           0 :         else if ( mnDrawMode & DRAWMODE_SETTINGSTEXT )
    3577           0 :             aColor = GetSettings().GetStyleSettings().GetFontColor();
    3578             : 
    3579           0 :         if( (mnDrawMode & DRAWMODE_GHOSTEDTEXT)
    3580           0 :         &&  (aColor.GetColor() != COL_TRANSPARENT) )
    3581             :         {
    3582           0 :             aColor = Color( (aColor.GetRed() >> 1) | 0x80,
    3583           0 :                             (aColor.GetGreen() >> 1) | 0x80,
    3584           0 :                             (aColor.GetBlue() >> 1) | 0x80 );
    3585             :         }
    3586             :     }
    3587             : 
    3588           0 :     if ( mpMetaFile )
    3589           0 :         mpMetaFile->AddAction( new MetaOverlineColorAction( aColor, true ) );
    3590             : 
    3591           0 :     maOverlineColor = aColor;
    3592             : 
    3593           0 :     if( mpAlphaVDev )
    3594           0 :         mpAlphaVDev->SetOverlineColor( COL_BLACK );
    3595           0 : }
    3596             : 
    3597           0 : void OutputDevice::SetTextAlign( TextAlign eAlign )
    3598             : {
    3599             : 
    3600           0 :     if ( mpMetaFile )
    3601           0 :         mpMetaFile->AddAction( new MetaTextAlignAction( eAlign ) );
    3602             : 
    3603           0 :     if ( maFont.GetAlign() != eAlign )
    3604             :     {
    3605           0 :         maFont.SetAlign( eAlign );
    3606           0 :         mbNewFont = true;
    3607             :     }
    3608             : 
    3609           0 :     if( mpAlphaVDev )
    3610           0 :         mpAlphaVDev->SetTextAlign( eAlign );
    3611           0 : }
    3612             : 
    3613           0 : void OutputDevice::DrawTextLine( const Point& rPos, long nWidth,
    3614             :                                  FontStrikeout eStrikeout,
    3615             :                                  FontUnderline eUnderline,
    3616             :                                  FontUnderline eOverline,
    3617             :                                  bool bUnderlineAbove )
    3618             : {
    3619             : 
    3620           0 :     if ( mpMetaFile )
    3621           0 :         mpMetaFile->AddAction( new MetaTextLineAction( rPos, nWidth, eStrikeout, eUnderline, eOverline ) );
    3622             : 
    3623           0 :     if ( ((eUnderline == UNDERLINE_NONE) || (eUnderline == UNDERLINE_DONTKNOW)) &&
    3624           0 :          ((eOverline  == UNDERLINE_NONE) || (eOverline  == UNDERLINE_DONTKNOW)) &&
    3625           0 :          ((eStrikeout == STRIKEOUT_NONE) || (eStrikeout == STRIKEOUT_DONTKNOW)) )
    3626           0 :         return;
    3627             : 
    3628           0 :     if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
    3629           0 :         return;
    3630             : 
    3631             :     // we need a graphics
    3632           0 :     if( !mpGraphics && !ImplGetGraphics() )
    3633           0 :         return;
    3634           0 :     if( mbInitClipRegion )
    3635           0 :         ImplInitClipRegion();
    3636           0 :     if( mbOutputClipped )
    3637           0 :         return;
    3638             : 
    3639             :     // initialize font if needed to get text offsets
    3640             :     // TODO: only needed for mnTextOff!=(0,0)
    3641           0 :     if( mbNewFont )
    3642           0 :         if( !ImplNewFont() )
    3643           0 :             return;
    3644           0 :     if( mbInitFont )
    3645           0 :         ImplInitFont();
    3646             : 
    3647           0 :     Point aPos = ImplLogicToDevicePixel( rPos );
    3648           0 :     nWidth = ImplLogicWidthToDevicePixel( nWidth );
    3649           0 :     aPos += Point( mnTextOffX, mnTextOffY );
    3650           0 :     ImplDrawTextLine( aPos.X(), aPos.X(), 0, nWidth, eStrikeout, eUnderline, eOverline, bUnderlineAbove );
    3651             : 
    3652           0 :     if( mpAlphaVDev )
    3653           0 :         mpAlphaVDev->DrawTextLine( rPos, nWidth, eStrikeout, eUnderline, eOverline, bUnderlineAbove );
    3654             : }
    3655             : 
    3656           0 : void OutputDevice::DrawWaveLine( const Point& rStartPos, const Point& rEndPos )
    3657             : {
    3658             : 
    3659           0 :     if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
    3660           0 :         return;
    3661             : 
    3662             :     // we need a graphics
    3663           0 :     if( !mpGraphics )
    3664           0 :         if( !ImplGetGraphics() )
    3665           0 :             return;
    3666             : 
    3667           0 :     if ( mbInitClipRegion )
    3668           0 :         ImplInitClipRegion();
    3669           0 :     if ( mbOutputClipped )
    3670           0 :         return;
    3671             : 
    3672           0 :     if( mbNewFont )
    3673           0 :         if( !ImplNewFont() )
    3674           0 :             return;
    3675             : 
    3676           0 :     Point   aStartPt = ImplLogicToDevicePixel( rStartPos );
    3677           0 :     Point   aEndPt = ImplLogicToDevicePixel( rEndPos );
    3678           0 :     long    nStartX = aStartPt.X();
    3679           0 :     long    nStartY = aStartPt.Y();
    3680           0 :     long    nEndX = aEndPt.X();
    3681           0 :     long    nEndY = aEndPt.Y();
    3682           0 :     short   nOrientation = 0;
    3683             : 
    3684             :     // when rotated
    3685           0 :     if ( (nStartY != nEndY) || (nStartX > nEndX) )
    3686             :     {
    3687           0 :         long nDX = nEndX - nStartX;
    3688           0 :         double nO = atan2( -nEndY + nStartY, ((nDX == 0L) ? 0.000000001 : nDX) );
    3689           0 :         nO /= F_PI1800;
    3690           0 :         nOrientation = (short)nO;
    3691           0 :         ImplRotatePos( nStartX, nStartY, nEndX, nEndY, -nOrientation );
    3692             :     }
    3693             : 
    3694             :     long nWaveHeight;
    3695             : 
    3696           0 :     nWaveHeight = 3;
    3697           0 :     nStartY++;
    3698           0 :     nEndY++;
    3699             : 
    3700           0 :     if (mnDPIScaleFactor > 1)
    3701             :     {
    3702           0 :         nWaveHeight *= mnDPIScaleFactor;
    3703             : 
    3704           0 :         nStartY += mnDPIScaleFactor - 1; // Shift down additional pixel(s) to create more visual separation.
    3705             : 
    3706             :         // odd heights look better than even
    3707           0 :         if (mnDPIScaleFactor % 2 == 0)
    3708             :         {
    3709           0 :             nWaveHeight--;
    3710             :         }
    3711             :     }
    3712             : 
    3713             :     // #109280# make sure the waveline does not exceed the descent to avoid paint problems
    3714           0 :     ImplFontEntry* pFontEntry = mpFontEntry;
    3715           0 :     if( nWaveHeight > pFontEntry->maMetric.mnWUnderlineSize )
    3716           0 :         nWaveHeight = pFontEntry->maMetric.mnWUnderlineSize;
    3717             : 
    3718             :     ImplDrawWaveLine(nStartX, nStartY, 0, 0,
    3719             :             nEndX-nStartX, nWaveHeight,
    3720           0 :             mnDPIScaleFactor, nOrientation, GetLineColor());
    3721             : 
    3722           0 :     if( mpAlphaVDev )
    3723           0 :         mpAlphaVDev->DrawWaveLine( rStartPos, rEndPos );
    3724             : }
    3725             : 
    3726           0 : void OutputDevice::DrawText( const Point& rStartPt, const OUString& rStr,
    3727             :                              sal_Int32 nIndex, sal_Int32 nLen,
    3728             :                              MetricVector* pVector, OUString* pDisplayText
    3729             :                              )
    3730             : {
    3731           0 :     if(nLen == 0x0FFFF)
    3732             :     {
    3733             :         SAL_INFO("sal.rtl.xub",
    3734             :                  "GetTextOutlines Suspicious arguments nLen:" << nLen);
    3735             :     }
    3736           0 :     if( (nLen < 0) || (nIndex + nLen >= rStr.getLength()))
    3737             :     {
    3738           0 :         nLen = rStr.getLength() - nIndex;
    3739             :     }
    3740             : 
    3741           0 :     if( mpOutDevData && mpOutDevData->mpRecordLayout )
    3742             :     {
    3743           0 :         pVector = &mpOutDevData->mpRecordLayout->m_aUnicodeBoundRects;
    3744           0 :         pDisplayText = &mpOutDevData->mpRecordLayout->m_aDisplayText;
    3745             :     }
    3746             : 
    3747             : #if OSL_DEBUG_LEVEL > 2
    3748             :     fprintf( stderr, "   OutputDevice::DrawText(\"%s\")\n",
    3749             :          OUStringToOString( rStr, RTL_TEXTENCODING_UTF8 ).getStr() );
    3750             : #endif
    3751             : 
    3752           0 :     if ( mpMetaFile )
    3753           0 :         mpMetaFile->AddAction( new MetaTextAction( rStartPt, rStr, nIndex, nLen ) );
    3754           0 :     if( pVector )
    3755             :     {
    3756           0 :         Region aClip( GetClipRegion() );
    3757           0 :         if( meOutDevType == OUTDEV_WINDOW )
    3758           0 :             aClip.Intersect( Rectangle( Point(), GetOutputSize() ) );
    3759           0 :         if( mpOutDevData && mpOutDevData->mpRecordLayout )
    3760             :         {
    3761           0 :             mpOutDevData->mpRecordLayout->m_aLineIndices.push_back( mpOutDevData->mpRecordLayout->m_aDisplayText.getLength() );
    3762           0 :             aClip.Intersect( mpOutDevData->maRecordRect );
    3763             :         }
    3764           0 :         if( ! aClip.IsNull() )
    3765             :         {
    3766           0 :             MetricVector aTmp;
    3767           0 :             GetGlyphBoundRects( rStartPt, rStr, nIndex, nLen, nIndex, aTmp );
    3768             : 
    3769           0 :             bool bInserted = false;
    3770           0 :             for( MetricVector::const_iterator it = aTmp.begin(); it != aTmp.end(); ++it, nIndex++ )
    3771             :             {
    3772           0 :                 bool bAppend = false;
    3773             : 
    3774           0 :                 if( aClip.IsOver( *it ) )
    3775           0 :                     bAppend = true;
    3776           0 :                 else if( rStr[ nIndex ] == ' ' && bInserted )
    3777             :                 {
    3778           0 :                     MetricVector::const_iterator next = it;
    3779           0 :                     ++next;
    3780           0 :                     if( next != aTmp.end() && aClip.IsOver( *next ) )
    3781           0 :                         bAppend = true;
    3782             :                 }
    3783             : 
    3784           0 :                 if( bAppend )
    3785             :                 {
    3786           0 :                     pVector->push_back( *it );
    3787           0 :                     if( pDisplayText )
    3788           0 :                         *pDisplayText += OUString(rStr[ nIndex ]);
    3789           0 :                     bInserted = true;
    3790             :                 }
    3791           0 :             }
    3792             :         }
    3793             :         else
    3794             :         {
    3795           0 :             GetGlyphBoundRects( rStartPt, rStr, nIndex, nLen, nIndex, *pVector );
    3796           0 :             if( pDisplayText )
    3797           0 :                 *pDisplayText += rStr.copy( nIndex, nLen );
    3798           0 :         }
    3799             :     }
    3800             : 
    3801           0 :     if ( !IsDeviceOutputNecessary() || pVector )
    3802           0 :         return;
    3803             : 
    3804           0 :     SalLayout* pSalLayout = ImplLayout(rStr, nIndex, nLen, rStartPt, 0, NULL);
    3805           0 :     if( pSalLayout )
    3806             :     {
    3807           0 :         ImplDrawText( *pSalLayout );
    3808           0 :         pSalLayout->Release();
    3809             :     }
    3810             : 
    3811           0 :     if( mpAlphaVDev )
    3812           0 :         mpAlphaVDev->DrawText( rStartPt, rStr, nIndex, nLen, pVector, pDisplayText );
    3813             : }
    3814             : 
    3815           0 : long OutputDevice::GetTextWidth( const OUString& rStr, sal_Int32 nIndex, sal_Int32 nLen ) const
    3816             : {
    3817             : 
    3818           0 :     long nWidth = GetTextArray( rStr, NULL, nIndex, nLen );
    3819             : 
    3820           0 :     return nWidth;
    3821             : }
    3822             : 
    3823           0 : long OutputDevice::GetTextHeight() const
    3824             : {
    3825             : 
    3826           0 :     if( mbNewFont )
    3827           0 :         if( !ImplNewFont() )
    3828           0 :             return 0;
    3829           0 :     if( mbInitFont )
    3830           0 :         if( !ImplNewFont() )
    3831           0 :             return 0;
    3832             : 
    3833           0 :     long nHeight = mpFontEntry->mnLineHeight + mnEmphasisAscent + mnEmphasisDescent;
    3834             : 
    3835           0 :     if ( mbMap )
    3836           0 :         nHeight = ImplDevicePixelToLogicHeight( nHeight );
    3837             : 
    3838           0 :     return nHeight;
    3839             : }
    3840             : 
    3841           0 : float OutputDevice::approximate_char_width() const
    3842             : {
    3843           0 :     return GetTextWidth("aemnnxEM") / 8.0;
    3844             : }
    3845             : 
    3846           0 : void OutputDevice::DrawTextArray( const Point& rStartPt, const OUString& rStr,
    3847             :                                   const sal_Int32* pDXAry,
    3848             :                                   sal_Int32 nIndex, sal_Int32 nLen )
    3849             : {
    3850           0 :     if(nLen == 0x0FFFF)
    3851             :     {
    3852             :         SAL_INFO("sal.rtl.xub",
    3853             :                  "DrawTextArray Suspicious arguments nLen:" << nLen);
    3854             :     }
    3855           0 :     if( nLen < 0 || nIndex + nLen >= rStr.getLength() )
    3856             :     {
    3857           0 :         nLen = rStr.getLength() - nIndex;
    3858             :     }
    3859           0 :     if ( mpMetaFile )
    3860           0 :         mpMetaFile->AddAction( new MetaTextArrayAction( rStartPt, rStr, pDXAry, nIndex, nLen ) );
    3861             : 
    3862           0 :     if ( !IsDeviceOutputNecessary() )
    3863           0 :         return;
    3864           0 :     if( !mpGraphics && !ImplGetGraphics() )
    3865           0 :         return;
    3866           0 :     if( mbInitClipRegion )
    3867           0 :         ImplInitClipRegion();
    3868           0 :     if( mbOutputClipped )
    3869           0 :         return;
    3870             : 
    3871           0 :     SalLayout* pSalLayout = ImplLayout(rStr, nIndex, nLen, rStartPt, 0, pDXAry);
    3872           0 :     if( pSalLayout )
    3873             :     {
    3874           0 :         ImplDrawText( *pSalLayout );
    3875           0 :         pSalLayout->Release();
    3876             :     }
    3877             : 
    3878           0 :     if( mpAlphaVDev )
    3879           0 :         mpAlphaVDev->DrawTextArray( rStartPt, rStr, pDXAry, nIndex, nLen );
    3880             : }
    3881             : 
    3882           0 : long OutputDevice::GetTextArray( const OUString& rStr, sal_Int32* pDXAry,
    3883             :                                  sal_Int32 nIndex, sal_Int32 nLen ) const
    3884             : {
    3885           0 :     if(nLen == 0x0FFFF)
    3886             :     {
    3887             :         SAL_INFO("sal.rtl.xub",
    3888             :                  "GetTextArray Suspicious arguments nLen:" << nLen);
    3889             :     }
    3890             : 
    3891           0 :     if( nIndex >= rStr.getLength() )
    3892           0 :         return 0;
    3893             : 
    3894           0 :     if( nLen < 0 || nIndex + nLen >= rStr.getLength() )
    3895             :     {
    3896           0 :         nLen = rStr.getLength() - nIndex;
    3897             :     }
    3898             :     // do layout
    3899           0 :     SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen );
    3900           0 :     if( !pSalLayout )
    3901           0 :         return 0;
    3902             : 
    3903           0 :     long nWidth = pSalLayout->FillDXArray( pDXAry );
    3904           0 :     int nWidthFactor = pSalLayout->GetUnitsPerPixel();
    3905           0 :     pSalLayout->Release();
    3906             : 
    3907             :     // convert virtual char widths to virtual absolute positions
    3908           0 :     if( pDXAry )
    3909           0 :         for( int i = 1; i < nLen; ++i )
    3910           0 :             pDXAry[ i ] += pDXAry[ i-1 ];
    3911             : 
    3912             :     // convert from font units to logical units
    3913           0 :     if( mbMap )
    3914             :     {
    3915           0 :         if( pDXAry )
    3916           0 :             for( int i = 0; i < nLen; ++i )
    3917           0 :                 pDXAry[i] = ImplDevicePixelToLogicWidth( pDXAry[i] );
    3918           0 :         nWidth = ImplDevicePixelToLogicWidth( nWidth );
    3919             :     }
    3920             : 
    3921           0 :     if( nWidthFactor > 1 )
    3922             :     {
    3923           0 :         if( pDXAry )
    3924           0 :             for( int i = 0; i < nLen; ++i )
    3925           0 :                 pDXAry[i] /= nWidthFactor;
    3926           0 :         nWidth /= nWidthFactor;
    3927             :     }
    3928             : 
    3929           0 :     return nWidth;
    3930             : }
    3931             : 
    3932           0 : bool OutputDevice::GetCaretPositions( const OUString& rStr, sal_Int32* pCaretXArray,
    3933             :     sal_Int32 nIndex, sal_Int32 nLen,
    3934             :     sal_Int32* pDXAry, long nLayoutWidth,
    3935             :     bool bCellBreaking ) const
    3936             : {
    3937             : 
    3938           0 :     if( nIndex >= rStr.getLength() )
    3939           0 :         return false;
    3940           0 :     if( nIndex+nLen >= rStr.getLength() )
    3941           0 :         nLen = rStr.getLength() - nIndex;
    3942             : 
    3943             :     // layout complex text
    3944             :     SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen,
    3945           0 :         Point(0,0), nLayoutWidth, pDXAry );
    3946           0 :     if( !pSalLayout )
    3947           0 :         return false;
    3948             : 
    3949           0 :     int nWidthFactor = pSalLayout->GetUnitsPerPixel();
    3950           0 :     pSalLayout->GetCaretPositions( 2*nLen, pCaretXArray );
    3951           0 :     long nWidth = pSalLayout->GetTextWidth();
    3952           0 :     pSalLayout->Release();
    3953             : 
    3954             :     // fixup unknown caret positions
    3955             :     int i;
    3956           0 :     for( i = 0; i < 2 * nLen; ++i )
    3957           0 :         if( pCaretXArray[ i ] >= 0 )
    3958           0 :             break;
    3959           0 :     long nXPos = pCaretXArray[ i ];
    3960           0 :     for( i = 0; i < 2 * nLen; ++i )
    3961             :     {
    3962           0 :         if( pCaretXArray[ i ] >= 0 )
    3963           0 :             nXPos = pCaretXArray[ i ];
    3964             :         else
    3965           0 :             pCaretXArray[ i ] = nXPos;
    3966             :     }
    3967             : 
    3968             :     // handle window mirroring
    3969           0 :     if( IsRTLEnabled() )
    3970             :     {
    3971           0 :         for( i = 0; i < 2 * nLen; ++i )
    3972           0 :             pCaretXArray[i] = nWidth - pCaretXArray[i] - 1;
    3973             :     }
    3974             : 
    3975             :     // convert from font units to logical units
    3976           0 :     if( mbMap )
    3977             :     {
    3978           0 :         for( i = 0; i < 2*nLen; ++i )
    3979           0 :             pCaretXArray[i] = ImplDevicePixelToLogicWidth( pCaretXArray[i] );
    3980             :     }
    3981             : 
    3982           0 :     if( nWidthFactor != 1 )
    3983             :     {
    3984           0 :         for( i = 0; i < 2*nLen; ++i )
    3985           0 :             pCaretXArray[i] /= nWidthFactor;
    3986             :     }
    3987             : 
    3988             :     // if requested move caret position to cell limits
    3989             :     if( bCellBreaking )
    3990             :     {
    3991             :         ; // FIXME
    3992             :     }
    3993             : 
    3994           0 :     return true;
    3995             : }
    3996             : 
    3997           0 : void OutputDevice::DrawStretchText( const Point& rStartPt, sal_uLong nWidth,
    3998             :                                     const OUString& rStr,
    3999             :                                     sal_Int32 nIndex, sal_Int32 nLen )
    4000             : {
    4001           0 :     if(nIndex < 0 || nIndex == 0x0FFFF || nLen == 0x0FFFF)
    4002             :     {
    4003             :         SAL_INFO("sal.rtl.xub",
    4004             :                  "DrawStretchText Suspicious arguments nIndex:" << nIndex << " nLen:" << nLen);
    4005             :     }
    4006           0 :     if( (nLen < 0) || (nIndex + nLen >= rStr.getLength()))
    4007             :     {
    4008           0 :         nLen = rStr.getLength() - nIndex;
    4009             :     }
    4010             : 
    4011           0 :     if ( mpMetaFile )
    4012           0 :         mpMetaFile->AddAction( new MetaStretchTextAction( rStartPt, nWidth, rStr, nIndex, nLen ) );
    4013             : 
    4014           0 :     if ( !IsDeviceOutputNecessary() )
    4015           0 :         return;
    4016             : 
    4017           0 :     SalLayout* pSalLayout = ImplLayout(rStr, nIndex, nLen, rStartPt, nWidth, NULL);
    4018           0 :     if( pSalLayout )
    4019             :     {
    4020           0 :         ImplDrawText( *pSalLayout );
    4021           0 :         pSalLayout->Release();
    4022             :     }
    4023             : 
    4024           0 :     if( mpAlphaVDev )
    4025           0 :         mpAlphaVDev->DrawStretchText( rStartPt, nWidth, rStr, nIndex, nLen );
    4026             : }
    4027             : 
    4028           0 : ImplLayoutArgs OutputDevice::ImplPrepareLayoutArgs( OUString& rStr,
    4029             :                                        const sal_Int32 nMinIndex, const sal_Int32 nLen,
    4030             :                                        long nPixelWidth, const sal_Int32* pDXArray ) const
    4031             : {
    4032             :     assert(nMinIndex >= 0);
    4033             :     assert(nLen >= 0);
    4034             : 
    4035             :     // get string length for calculating extents
    4036           0 :     sal_Int32 nEndIndex = rStr.getLength();
    4037           0 :     if( nMinIndex + nLen < nEndIndex )
    4038           0 :         nEndIndex = nMinIndex + nLen;
    4039             : 
    4040             :     // don't bother if there is nothing to do
    4041           0 :     if( nEndIndex < nMinIndex )
    4042           0 :         nEndIndex = nMinIndex;
    4043             : 
    4044           0 :     int nLayoutFlags = 0;
    4045           0 :     if( mnTextLayoutMode & TEXT_LAYOUT_BIDI_RTL )
    4046           0 :         nLayoutFlags |= SAL_LAYOUT_BIDI_RTL;
    4047           0 :     if( mnTextLayoutMode & TEXT_LAYOUT_BIDI_STRONG )
    4048           0 :         nLayoutFlags |= SAL_LAYOUT_BIDI_STRONG;
    4049           0 :     else if( 0 == (mnTextLayoutMode & TEXT_LAYOUT_BIDI_RTL) )
    4050             :     {
    4051             :         // disable Bidi if no RTL hint and no RTL codes used
    4052           0 :         const sal_Unicode* pStr = rStr.getStr() + nMinIndex;
    4053           0 :         const sal_Unicode* pEnd = rStr.getStr() + nEndIndex;
    4054           0 :         for( ; pStr < pEnd; ++pStr )
    4055           0 :             if( ((*pStr >= 0x0580) && (*pStr < 0x0800))   // middle eastern scripts
    4056           0 :             ||  ((*pStr >= 0xFB18) && (*pStr < 0xFE00))   // hebrew + arabic A presentation forms
    4057           0 :             ||  ((*pStr >= 0xFE70) && (*pStr < 0xFEFF)) ) // arabic presentation forms B
    4058             :                 break;
    4059           0 :         if( pStr >= pEnd )
    4060           0 :             nLayoutFlags |= SAL_LAYOUT_BIDI_STRONG;
    4061             :     }
    4062             : 
    4063           0 :     if( mbKerning )
    4064           0 :         nLayoutFlags |= SAL_LAYOUT_KERNING_PAIRS;
    4065           0 :     if( maFont.GetKerning() & KERNING_ASIAN )
    4066           0 :         nLayoutFlags |= SAL_LAYOUT_KERNING_ASIAN;
    4067           0 :     if( maFont.IsVertical() )
    4068           0 :         nLayoutFlags |= SAL_LAYOUT_VERTICAL;
    4069             : 
    4070           0 :     if( mnTextLayoutMode & TEXT_LAYOUT_ENABLE_LIGATURES )
    4071           0 :         nLayoutFlags |= SAL_LAYOUT_ENABLE_LIGATURES;
    4072           0 :     else if( mnTextLayoutMode & TEXT_LAYOUT_COMPLEX_DISABLED )
    4073           0 :         nLayoutFlags |= SAL_LAYOUT_COMPLEX_DISABLED;
    4074             :     else
    4075             :     {
    4076             :         // disable CTL for non-CTL text
    4077           0 :         const sal_Unicode* pStr = rStr.getStr() + nMinIndex;
    4078           0 :         const sal_Unicode* pEnd = rStr.getStr() + nEndIndex;
    4079           0 :         for( ; pStr < pEnd; ++pStr )
    4080           0 :             if( ((*pStr >= 0x0300) && (*pStr < 0x0370))   // diacritical marks
    4081           0 :             ||  ((*pStr >= 0x0590) && (*pStr < 0x10A0))   // many CTL scripts
    4082           0 :             ||  ((*pStr >= 0x1100) && (*pStr < 0x1200))   // hangul jamo
    4083           0 :             ||  ((*pStr >= 0x1700) && (*pStr < 0x1900))   // many CTL scripts
    4084           0 :             ||  ((*pStr >= 0xFB1D) && (*pStr < 0xFE00))   // middle east presentation
    4085           0 :             ||  ((*pStr >= 0xFE70) && (*pStr < 0xFEFF))   // arabic presentation B
    4086           0 :             ||  ((*pStr >= 0xFE00) && (*pStr < 0xFE10))   // variation selectors in BMP
    4087           0 :             ||  ((pStr + 1 < pEnd) && (pStr[0] == 0xDB40) && (0xDD00 <= pStr[1]) && (pStr[1] < 0xDEF0)) // variation selector supplement
    4088             :             )
    4089             :                 break;
    4090           0 :         if( pStr >= pEnd )
    4091           0 :             nLayoutFlags |= SAL_LAYOUT_COMPLEX_DISABLED;
    4092             :     }
    4093             : 
    4094           0 :     if( meTextLanguage ) //TODO: (mnTextLayoutMode & TEXT_LAYOUT_SUBSTITUTE_DIGITS)
    4095             :     {
    4096             :         // disable character localization when no digits used
    4097           0 :         const sal_Unicode* pBase = rStr.getStr();
    4098           0 :         const sal_Unicode* pStr = pBase + nMinIndex;
    4099           0 :         const sal_Unicode* pEnd = pBase + nEndIndex;
    4100           0 :         OUStringBuffer sTmpStr(rStr);
    4101           0 :         for( ; pStr < pEnd; ++pStr )
    4102             :         {
    4103             :             // TODO: are there non-digit localizations?
    4104           0 :             if( (*pStr >= '0') && (*pStr <= '9') )
    4105             :             {
    4106             :                 // translate characters to local preference
    4107           0 :                 sal_UCS4 cChar = GetLocalizedChar( *pStr, meTextLanguage );
    4108           0 :                 if( cChar != *pStr )
    4109             :                     // TODO: are the localized digit surrogates?
    4110           0 :                     sTmpStr[pStr - pBase] = cChar;
    4111             :             }
    4112             :         }
    4113           0 :         rStr = sTmpStr.makeStringAndClear();
    4114             :     }
    4115             : 
    4116             :     // right align for RTL text, DRAWPOS_REVERSED, RTL window style
    4117           0 :     bool bRightAlign = ((mnTextLayoutMode & TEXT_LAYOUT_BIDI_RTL) != 0);
    4118           0 :     if( mnTextLayoutMode & TEXT_LAYOUT_TEXTORIGIN_LEFT )
    4119           0 :         bRightAlign = false;
    4120           0 :     else if ( mnTextLayoutMode & TEXT_LAYOUT_TEXTORIGIN_RIGHT )
    4121           0 :         bRightAlign = true;
    4122             :     // SSA: hack for western office, ie text get right aligned
    4123             :     //      for debugging purposes of mirrored UI
    4124           0 :     bool bRTLWindow = IsRTLEnabled();
    4125           0 :     bRightAlign ^= bRTLWindow;
    4126           0 :     if( bRightAlign )
    4127           0 :         nLayoutFlags |= SAL_LAYOUT_RIGHT_ALIGN;
    4128             : 
    4129             :     // set layout options
    4130           0 :     ImplLayoutArgs aLayoutArgs( rStr.getStr(), rStr.getLength(), nMinIndex, nEndIndex, nLayoutFlags, maFont.GetLanguageTag() );
    4131             : 
    4132           0 :     int nOrientation = mpFontEntry ? mpFontEntry->mnOrientation : 0;
    4133           0 :     aLayoutArgs.SetOrientation( nOrientation );
    4134             : 
    4135           0 :     aLayoutArgs.SetLayoutWidth( nPixelWidth );
    4136           0 :     aLayoutArgs.SetDXArray( pDXArray );
    4137             : 
    4138           0 :     return aLayoutArgs;
    4139             : }
    4140             : 
    4141           0 : SalLayout* OutputDevice::ImplLayout(const OUString& rOrigStr,
    4142             :     sal_Int32 nMinIndex, sal_Int32 nLen,
    4143             :     const Point& rLogicalPos, long nLogicalWidth,
    4144             :     const sal_Int32* pDXArray) const
    4145             : {
    4146             :     // we need a graphics
    4147           0 :     if( !mpGraphics )
    4148           0 :         if( !ImplGetGraphics() )
    4149           0 :             return NULL;
    4150             : 
    4151             :     // initialize font if needed
    4152           0 :     if( mbNewFont )
    4153           0 :         if( !ImplNewFont() )
    4154           0 :             return NULL;
    4155           0 :     if( mbInitFont )
    4156           0 :         ImplInitFont();
    4157             : 
    4158             :     // check string index and length
    4159           0 :     if( -1 == nLen || nMinIndex + nLen > rOrigStr.getLength() )
    4160             :     {
    4161           0 :         const sal_Int32 nNewLen = rOrigStr.getLength() - nMinIndex;
    4162           0 :         if( nNewLen <= 0 )
    4163           0 :             return NULL;
    4164           0 :         nLen = nNewLen;
    4165             :     }
    4166             : 
    4167           0 :     OUString aStr = rOrigStr;
    4168             : 
    4169             :     // convert from logical units to physical units
    4170             :     // recode string if needed
    4171           0 :     if( mpFontEntry->mpConversion ) {
    4172           0 :         mpFontEntry->mpConversion->RecodeString( aStr, 0, aStr.getLength() );
    4173             :     }
    4174             : 
    4175           0 :     long nPixelWidth = nLogicalWidth;
    4176           0 :     if( nLogicalWidth && mbMap )
    4177           0 :         nPixelWidth = ImplLogicWidthToDevicePixel( nLogicalWidth );
    4178           0 :     if( pDXArray && mbMap )
    4179             :     {
    4180             :         // convert from logical units to font units using a temporary array
    4181           0 :         sal_Int32* pTempDXAry = (sal_Int32*)alloca( nLen * sizeof(sal_Int32) );
    4182             :         // using base position for better rounding a.k.a. "dancing characters"
    4183           0 :         int nPixelXOfs = ImplLogicWidthToDevicePixel( rLogicalPos.X() );
    4184           0 :         for( int i = 0; i < nLen; ++i )
    4185           0 :             pTempDXAry[i] = ImplLogicWidthToDevicePixel( rLogicalPos.X() + pDXArray[i] ) - nPixelXOfs;
    4186             : 
    4187           0 :         pDXArray = pTempDXAry;
    4188             :     }
    4189             : 
    4190           0 :     ImplLayoutArgs aLayoutArgs = ImplPrepareLayoutArgs( aStr, nMinIndex, nLen, nPixelWidth, pDXArray );
    4191             : 
    4192             : #if defined(MACOSX) || defined(IOS)
    4193             :     // CoreText layouts are immutable and already contain the text color
    4194             :     // so we need to provide the color already for the layout request
    4195             :     // even if this layout will never be drawn
    4196             :     if( mbInitTextColor )
    4197             :         const_cast<OutputDevice&>(*this).ImplInitTextColor();
    4198             : #endif
    4199             : 
    4200             :     // get matching layout object for base font
    4201           0 :     SalLayout* pSalLayout = mpGraphics->GetTextLayout( aLayoutArgs, 0 );
    4202             : 
    4203             :     // layout text
    4204           0 :     if( pSalLayout && !pSalLayout->LayoutText( aLayoutArgs ) )
    4205             :     {
    4206           0 :         pSalLayout->Release();
    4207           0 :         pSalLayout = NULL;
    4208             :     }
    4209             : 
    4210           0 :     if( !pSalLayout )
    4211           0 :         return NULL;
    4212             : 
    4213             :     // do glyph fallback if needed
    4214             :     // #105768# avoid fallback for very small font sizes
    4215           0 :     if (aLayoutArgs.NeedFallback() && mpFontEntry->maFontSelData.mnHeight >= 3)
    4216           0 :         pSalLayout = ImplGlyphFallbackLayout(pSalLayout, aLayoutArgs);
    4217             : 
    4218             :     // position, justify, etc. the layout
    4219           0 :     pSalLayout->AdjustLayout( aLayoutArgs );
    4220           0 :     pSalLayout->DrawBase() = ImplLogicToDevicePixel( rLogicalPos );
    4221             :     // adjust to right alignment if necessary
    4222           0 :     if( aLayoutArgs.mnFlags & SAL_LAYOUT_RIGHT_ALIGN )
    4223             :     {
    4224             :         long nRTLOffset;
    4225           0 :         if( pDXArray )
    4226           0 :             nRTLOffset = pDXArray[ nLen - 1 ];
    4227           0 :         else if( nPixelWidth )
    4228           0 :             nRTLOffset = nPixelWidth;
    4229             :         else
    4230           0 :             nRTLOffset = pSalLayout->GetTextWidth() / pSalLayout->GetUnitsPerPixel();
    4231           0 :         pSalLayout->DrawOffset().X() = 1 - nRTLOffset;
    4232             :     }
    4233             : 
    4234           0 :     return pSalLayout;
    4235             : }
    4236             : 
    4237           0 : SalLayout* OutputDevice::getFallbackFont(ImplFontEntry &rFallbackFont,
    4238             :     FontSelectPattern &rFontSelData, int nFallbackLevel,
    4239             :     ImplLayoutArgs& rLayoutArgs) const
    4240             : {
    4241           0 :     rFallbackFont.mnSetFontFlags = mpGraphics->SetFont( &rFontSelData, nFallbackLevel );
    4242             : 
    4243           0 :     rLayoutArgs.ResetPos();
    4244           0 :     SalLayout* pFallback = mpGraphics->GetTextLayout( rLayoutArgs, nFallbackLevel );
    4245             : 
    4246           0 :     if (!pFallback)
    4247           0 :         return NULL;
    4248             : 
    4249           0 :     if (!pFallback->LayoutText(rLayoutArgs))
    4250             :     {
    4251             :         // there is no need for a font that couldn't resolve anything
    4252           0 :         pFallback->Release();
    4253           0 :         return NULL;
    4254             :     }
    4255             : 
    4256           0 :     pFallback->AdjustLayout( rLayoutArgs );
    4257             : 
    4258           0 :     return pFallback;
    4259             : }
    4260             : 
    4261           0 : SalLayout* OutputDevice::ImplGlyphFallbackLayout( SalLayout* pSalLayout, ImplLayoutArgs& rLayoutArgs ) const
    4262             : {
    4263             :     // prepare multi level glyph fallback
    4264           0 :     MultiSalLayout* pMultiSalLayout = NULL;
    4265           0 :     ImplLayoutRuns aLayoutRuns = rLayoutArgs.maRuns;
    4266           0 :     rLayoutArgs.PrepareFallback();
    4267           0 :     rLayoutArgs.mnFlags |= SAL_LAYOUT_FOR_FALLBACK;
    4268             : 
    4269             :     // get list of unicodes that need glyph fallback
    4270           0 :     int nCharPos = -1;
    4271           0 :     bool bRTL = false;
    4272           0 :     OUStringBuffer aMissingCodeBuf;
    4273           0 :     while( rLayoutArgs.GetNextPos( &nCharPos, &bRTL) )
    4274           0 :         aMissingCodeBuf.append( rLayoutArgs.mpStr[ nCharPos ] );
    4275           0 :     rLayoutArgs.ResetPos();
    4276           0 :     OUString aMissingCodes = aMissingCodeBuf.makeStringAndClear();
    4277             : 
    4278           0 :     FontSelectPattern aFontSelData = mpFontEntry->maFontSelData;
    4279             : 
    4280             :     // try if fallback fonts support the missing unicodes
    4281           0 :     for( int nFallbackLevel = 1; nFallbackLevel < MAX_FALLBACK; ++nFallbackLevel )
    4282             :     {
    4283             :         // find a font family suited for glyph fallback
    4284             : #ifndef FONTFALLBACK_HOOKS_DISABLED
    4285             :         // GetGlyphFallbackFont() needs a valid aFontSelData.mpFontEntry
    4286             :         // if the system-specific glyph fallback is active
    4287           0 :         aFontSelData.mpFontEntry = mpFontEntry; // reset the fontentry to base-level
    4288             : #endif
    4289             :         ImplFontEntry* pFallbackFont = mpFontCache->GetGlyphFallbackFont( mpFontCollection,
    4290           0 :             aFontSelData, nFallbackLevel, aMissingCodes );
    4291           0 :         if( !pFallbackFont )
    4292           0 :             break;
    4293             : 
    4294           0 :         aFontSelData.mpFontEntry = pFallbackFont;
    4295           0 :         aFontSelData.mpFontData = pFallbackFont->maFontSelData.mpFontData;
    4296           0 :         if( mpFontEntry && nFallbackLevel < MAX_FALLBACK-1)
    4297             :         {
    4298             :             // ignore fallback font if it is the same as the original font
    4299           0 :             if( mpFontEntry->maFontSelData.mpFontData == aFontSelData.mpFontData )
    4300             :             {
    4301           0 :                 mpFontCache->Release( pFallbackFont );
    4302           0 :                 continue;
    4303             :             }
    4304             :         }
    4305             : 
    4306             :         // create and add glyph fallback layout to multilayout
    4307             :         SalLayout* pFallback = getFallbackFont(*pFallbackFont, aFontSelData,
    4308           0 :             nFallbackLevel, rLayoutArgs);
    4309           0 :         if (pFallback)
    4310             :         {
    4311           0 :             if( !pMultiSalLayout )
    4312           0 :                 pMultiSalLayout = new MultiSalLayout( *pSalLayout );
    4313             :             pMultiSalLayout->AddFallback( *pFallback,
    4314           0 :                 rLayoutArgs.maRuns, aFontSelData.mpFontData );
    4315           0 :             if (nFallbackLevel == MAX_FALLBACK-1)
    4316           0 :                 pMultiSalLayout->SetInComplete();
    4317             :         }
    4318             : 
    4319           0 :         mpFontCache->Release( pFallbackFont );
    4320             : 
    4321             :         // break when this fallback was sufficient
    4322           0 :         if( !rLayoutArgs.PrepareFallback() )
    4323           0 :             break;
    4324             :     }
    4325             : 
    4326           0 :     if( pMultiSalLayout && pMultiSalLayout->LayoutText( rLayoutArgs ) )
    4327           0 :         pSalLayout = pMultiSalLayout;
    4328             : 
    4329             :     // restore orig font settings
    4330           0 :     pSalLayout->InitFont();
    4331           0 :     rLayoutArgs.maRuns = aLayoutRuns;
    4332             : 
    4333           0 :     return pSalLayout;
    4334             : }
    4335             : 
    4336           0 : bool OutputDevice::GetTextIsRTL( const OUString& rString, sal_Int32 nIndex, sal_Int32 nLen ) const
    4337             : {
    4338           0 :     OUString aStr( rString );
    4339           0 :     ImplLayoutArgs aArgs = ImplPrepareLayoutArgs( aStr, nIndex, nLen, 0, NULL );
    4340           0 :     bool bRTL = false;
    4341           0 :     int nCharPos = -1;
    4342           0 :     aArgs.GetNextPos( &nCharPos, &bRTL );
    4343           0 :     return (nCharPos != nIndex) ? sal_True : sal_False;
    4344             : }
    4345             : 
    4346           0 : sal_Int32 OutputDevice::GetTextBreak( const OUString& rStr, long nTextWidth,
    4347             :                                        sal_Int32 nIndex, sal_Int32 nLen,
    4348             :                                        long nCharExtra ) const
    4349             : {
    4350           0 :     SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen );
    4351           0 :     sal_Int32 nRetVal = -1;
    4352           0 :     if( pSalLayout )
    4353             :     {
    4354             :         // convert logical widths into layout units
    4355             :         // NOTE: be very careful to avoid rounding errors for nCharExtra case
    4356             :         // problem with rounding errors especially for small nCharExtras
    4357             :         // TODO: remove when layout units have subpixel granularity
    4358           0 :         long nWidthFactor = pSalLayout->GetUnitsPerPixel();
    4359           0 :         long nSubPixelFactor = (nWidthFactor < 64 ) ? 64 : 1;
    4360           0 :         nTextWidth *= nWidthFactor * nSubPixelFactor;
    4361           0 :         long nTextPixelWidth = ImplLogicWidthToDevicePixel( nTextWidth );
    4362           0 :         long nExtraPixelWidth = 0;
    4363           0 :         if( nCharExtra != 0 )
    4364             :         {
    4365           0 :             nCharExtra *= nWidthFactor * nSubPixelFactor;
    4366           0 :             nExtraPixelWidth = ImplLogicWidthToDevicePixel( nCharExtra );
    4367             :         }
    4368           0 :         nRetVal = pSalLayout->GetTextBreak( nTextPixelWidth, nExtraPixelWidth, nSubPixelFactor );
    4369             : 
    4370           0 :         pSalLayout->Release();
    4371             :     }
    4372             : 
    4373           0 :     return nRetVal;
    4374             : }
    4375             : 
    4376           0 : sal_Int32 OutputDevice::GetTextBreak( const OUString& rStr, long nTextWidth,
    4377             :                                        sal_Unicode nHyphenChar, sal_Int32& rHyphenPos,
    4378             :                                        sal_Int32 nIndex, sal_Int32 nLen,
    4379             :                                        long nCharExtra ) const
    4380             : {
    4381           0 :     rHyphenPos = -1;
    4382             : 
    4383           0 :     SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen );
    4384           0 :     sal_Int32 nRetVal = -1;
    4385           0 :     if( pSalLayout )
    4386             :     {
    4387             :         // convert logical widths into layout units
    4388             :         // NOTE: be very careful to avoid rounding errors for nCharExtra case
    4389             :         // problem with rounding errors especially for small nCharExtras
    4390             :         // TODO: remove when layout units have subpixel granularity
    4391           0 :         long nWidthFactor = pSalLayout->GetUnitsPerPixel();
    4392           0 :         long nSubPixelFactor = (nWidthFactor < 64 ) ? 64 : 1;
    4393             : 
    4394           0 :         nTextWidth *= nWidthFactor * nSubPixelFactor;
    4395           0 :         long nTextPixelWidth = ImplLogicWidthToDevicePixel( nTextWidth );
    4396           0 :         long nExtraPixelWidth = 0;
    4397           0 :         if( nCharExtra != 0 )
    4398             :         {
    4399           0 :             nCharExtra *= nWidthFactor * nSubPixelFactor;
    4400           0 :             nExtraPixelWidth = ImplLogicWidthToDevicePixel( nCharExtra );
    4401             :         }
    4402             : 
    4403             :         // calculate un-hyphenated break position
    4404           0 :         nRetVal = pSalLayout->GetTextBreak( nTextPixelWidth, nExtraPixelWidth, nSubPixelFactor );
    4405             : 
    4406             :         // calculate hyphenated break position
    4407           0 :         OUString aHyphenStr(nHyphenChar);
    4408           0 :         sal_Int32 nTempLen = 1;
    4409           0 :         SalLayout* pHyphenLayout = ImplLayout( aHyphenStr, 0, nTempLen );
    4410           0 :         if( pHyphenLayout )
    4411             :         {
    4412             :             // calculate subpixel width of hyphenation character
    4413           0 :             long nHyphenPixelWidth = pHyphenLayout->GetTextWidth() * nSubPixelFactor;
    4414           0 :             pHyphenLayout->Release();
    4415             : 
    4416             :             // calculate hyphenated break position
    4417           0 :             nTextPixelWidth -= nHyphenPixelWidth;
    4418           0 :             if( nExtraPixelWidth > 0 )
    4419           0 :                 nTextPixelWidth -= nExtraPixelWidth;
    4420             : 
    4421           0 :             rHyphenPos = pSalLayout->GetTextBreak(nTextPixelWidth, nExtraPixelWidth, nSubPixelFactor);
    4422             : 
    4423           0 :             if( rHyphenPos > nRetVal )
    4424           0 :                 rHyphenPos = nRetVal;
    4425             :         }
    4426             : 
    4427           0 :         pSalLayout->Release();
    4428             :     }
    4429             : 
    4430           0 :     return nRetVal;
    4431             : }
    4432             : 
    4433           0 : void OutputDevice::ImplDrawText( OutputDevice& rTargetDevice, const Rectangle& rRect,
    4434             :                                  const OUString& rOrigStr, sal_uInt16 nStyle,
    4435             :                                  MetricVector* pVector, OUString* pDisplayText,
    4436             :                                  ::vcl::ITextLayout& _rLayout )
    4437             : {
    4438           0 :     Color aOldTextColor;
    4439           0 :     Color aOldTextFillColor;
    4440           0 :     bool  bRestoreFillColor = false;
    4441           0 :     if ( (nStyle & TEXT_DRAW_DISABLE) && ! pVector )
    4442             :     {
    4443           0 :         bool  bHighContrastBlack = false;
    4444           0 :         bool  bHighContrastWhite = false;
    4445           0 :         const StyleSettings& rStyleSettings( rTargetDevice.GetSettings().GetStyleSettings() );
    4446           0 :         if( rStyleSettings.GetHighContrastMode() )
    4447             :         {
    4448           0 :             Color aCol;
    4449           0 :             if( rTargetDevice.IsBackground() )
    4450           0 :                 aCol = rTargetDevice.GetBackground().GetColor();
    4451             :             else
    4452             :                 // best guess is the face color here
    4453             :                 // but it may be totally wrong. the background color
    4454             :                 // was typically already reset
    4455           0 :                 aCol = rStyleSettings.GetFaceColor();
    4456             : 
    4457           0 :             bHighContrastBlack = aCol.IsDark();
    4458           0 :             bHighContrastWhite = aCol.IsBright();
    4459             :         }
    4460             : 
    4461           0 :         aOldTextColor = rTargetDevice.GetTextColor();
    4462           0 :         if ( rTargetDevice.IsTextFillColor() )
    4463             :         {
    4464           0 :             bRestoreFillColor = true;
    4465           0 :             aOldTextFillColor = rTargetDevice.GetTextFillColor();
    4466             :         }
    4467           0 :         if( bHighContrastBlack )
    4468           0 :             rTargetDevice.SetTextColor( COL_GREEN );
    4469           0 :         else if( bHighContrastWhite )
    4470           0 :             rTargetDevice.SetTextColor( COL_LIGHTGREEN );
    4471             :         else
    4472             :         {
    4473             :             // draw disabled text always without shadow
    4474             :             // as it fits better with native look
    4475           0 :             rTargetDevice.SetTextColor( rTargetDevice.GetSettings().GetStyleSettings().GetDisableColor() );
    4476             :         }
    4477             :     }
    4478             : 
    4479           0 :     long        nWidth          = rRect.GetWidth();
    4480           0 :     long        nHeight         = rRect.GetHeight();
    4481             : 
    4482           0 :     if ( ((nWidth <= 0) || (nHeight <= 0)) && (nStyle & TEXT_DRAW_CLIP) )
    4483           0 :         return;
    4484             : 
    4485           0 :     Point       aPos            = rRect.TopLeft();
    4486             : 
    4487           0 :     long        nTextHeight     = rTargetDevice.GetTextHeight();
    4488           0 :     TextAlign   eAlign          = rTargetDevice.GetTextAlign();
    4489           0 :     sal_Int32   nMnemonicPos    = -1;
    4490             : 
    4491           0 :     OUString aStr = rOrigStr;
    4492           0 :     if ( nStyle & TEXT_DRAW_MNEMONIC )
    4493           0 :         aStr = GetNonMnemonicString( aStr, nMnemonicPos );
    4494             : 
    4495           0 :     const bool bDrawMnemonics = !(rTargetDevice.GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_NOMNEMONICS) && !pVector;
    4496             : 
    4497             :     // We treat multiline text differently
    4498           0 :     if ( nStyle & TEXT_DRAW_MULTILINE )
    4499             :     {
    4500             : 
    4501           0 :         OUString                aLastLine;
    4502           0 :         ImplMultiTextLineInfo   aMultiLineInfo;
    4503             :         ImplTextLineInfo*       pLineInfo;
    4504             :         sal_Int32               i;
    4505             :         sal_Int32               nLines;
    4506             :         sal_Int32               nFormatLines;
    4507             : 
    4508           0 :         if ( nTextHeight )
    4509             :         {
    4510           0 :             long nMaxTextWidth = ImplGetTextLines( aMultiLineInfo, nWidth, aStr, nStyle, _rLayout );
    4511           0 :             nLines = (sal_Int32)(nHeight/nTextHeight);
    4512           0 :             nFormatLines = aMultiLineInfo.Count();
    4513           0 :             if ( !nLines )
    4514           0 :                 nLines = 1;
    4515           0 :             if ( nFormatLines > nLines )
    4516             :             {
    4517           0 :                 if ( nStyle & TEXT_DRAW_ENDELLIPSIS )
    4518             :                 {
    4519             :                     // Create last line and shorten it
    4520           0 :                     nFormatLines = nLines-1;
    4521             : 
    4522           0 :                     pLineInfo = aMultiLineInfo.GetLine( nFormatLines );
    4523           0 :                     aLastLine = convertLineEnd(aStr.copy(pLineInfo->GetIndex()), LINEEND_LF);
    4524             :                     // Replace all LineFeeds with Spaces
    4525           0 :                     OUStringBuffer aLastLineBuffer(aLastLine);
    4526           0 :                     sal_Int32 nLastLineLen = aLastLineBuffer.getLength();
    4527           0 :                     for ( i = 0; i < nLastLineLen; i++ )
    4528             :                     {
    4529           0 :                         if ( aLastLineBuffer[ i ] == '\n' )
    4530           0 :                             aLastLineBuffer[ i ] = ' ';
    4531             :                     }
    4532           0 :                     aLastLine = aLastLineBuffer.makeStringAndClear();
    4533           0 :                     aLastLine = ImplGetEllipsisString( rTargetDevice, aLastLine, nWidth, nStyle, _rLayout );
    4534           0 :                     nStyle &= ~(TEXT_DRAW_VCENTER | TEXT_DRAW_BOTTOM);
    4535           0 :                     nStyle |= TEXT_DRAW_TOP;
    4536             :                 }
    4537             :             }
    4538             :             else
    4539             :             {
    4540           0 :                 if ( nMaxTextWidth <= nWidth )
    4541           0 :                     nStyle &= ~TEXT_DRAW_CLIP;
    4542             :             }
    4543             : 
    4544             :             // Do we need to clip the height?
    4545           0 :             if ( nFormatLines*nTextHeight > nHeight )
    4546           0 :                 nStyle |= TEXT_DRAW_CLIP;
    4547             : 
    4548             :             // Set clipping
    4549           0 :             if ( nStyle & TEXT_DRAW_CLIP )
    4550             :             {
    4551           0 :                 rTargetDevice.Push( PUSH_CLIPREGION );
    4552           0 :                 rTargetDevice.IntersectClipRegion( rRect );
    4553             :             }
    4554             : 
    4555             :             // Vertical alignment
    4556           0 :             if ( nStyle & TEXT_DRAW_BOTTOM )
    4557           0 :                 aPos.Y() += nHeight-(nFormatLines*nTextHeight);
    4558           0 :             else if ( nStyle & TEXT_DRAW_VCENTER )
    4559           0 :                 aPos.Y() += (nHeight-(nFormatLines*nTextHeight))/2;
    4560             : 
    4561             :             // Font alignment
    4562           0 :             if ( eAlign == ALIGN_BOTTOM )
    4563           0 :                 aPos.Y() += nTextHeight;
    4564           0 :             else if ( eAlign == ALIGN_BASELINE )
    4565           0 :                 aPos.Y() += rTargetDevice.GetFontMetric().GetAscent();
    4566             : 
    4567             :             // Output all lines except for the last one
    4568           0 :             for ( i = 0; i < nFormatLines; i++ )
    4569             :             {
    4570           0 :                 pLineInfo = aMultiLineInfo.GetLine( i );
    4571           0 :                 if ( nStyle & TEXT_DRAW_RIGHT )
    4572           0 :                     aPos.X() += nWidth-pLineInfo->GetWidth();
    4573           0 :                 else if ( nStyle & TEXT_DRAW_CENTER )
    4574           0 :                     aPos.X() += (nWidth-pLineInfo->GetWidth())/2;
    4575           0 :                 sal_Int32 nIndex   = pLineInfo->GetIndex();
    4576           0 :                 sal_Int32 nLineLen = pLineInfo->GetLen();
    4577           0 :                 _rLayout.DrawText( aPos, aStr, nIndex, nLineLen, pVector, pDisplayText );
    4578           0 :                 if ( bDrawMnemonics )
    4579             :                 {
    4580           0 :                     if ( (nMnemonicPos >= nIndex) && (nMnemonicPos < nIndex+nLineLen) )
    4581             :                     {
    4582             :                         long        nMnemonicX;
    4583             :                         long        nMnemonicY;
    4584             :                         long        nMnemonicWidth;
    4585             : 
    4586           0 :                         sal_Int32* pCaretXArray = (sal_Int32*) alloca( 2 * sizeof(sal_Int32) * nLineLen );
    4587             :                         /*sal_Bool bRet =*/ _rLayout.GetCaretPositions( aStr, pCaretXArray,
    4588           0 :                                                 nIndex, nLineLen );
    4589           0 :                         long lc_x1 = pCaretXArray[2*(nMnemonicPos - nIndex)];
    4590           0 :                         long lc_x2 = pCaretXArray[2*(nMnemonicPos - nIndex)+1];
    4591           0 :                         nMnemonicWidth = rTargetDevice.ImplLogicWidthToDevicePixel( ::abs((int)(lc_x1 - lc_x2)) );
    4592             : 
    4593           0 :                         Point       aTempPos = rTargetDevice.LogicToPixel( aPos );
    4594           0 :                         nMnemonicX = rTargetDevice.GetOutOffXPixel() + aTempPos.X() + rTargetDevice.ImplLogicWidthToDevicePixel( std::min( lc_x1, lc_x2 ) );
    4595           0 :                         nMnemonicY = rTargetDevice.GetOutOffYPixel() + aTempPos.Y() + rTargetDevice.ImplLogicWidthToDevicePixel( rTargetDevice.GetFontMetric().GetAscent() );
    4596           0 :                         rTargetDevice.ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
    4597             :                     }
    4598             :                 }
    4599           0 :                 aPos.Y() += nTextHeight;
    4600           0 :                 aPos.X() = rRect.Left();
    4601             :             }
    4602             : 
    4603             :             // If there still is a last line, we output it left-aligned as the line would be clipped
    4604           0 :             if ( !aLastLine.isEmpty() )
    4605           0 :                 _rLayout.DrawText( aPos, aLastLine, 0, aLastLine.getLength(), pVector, pDisplayText );
    4606             : 
    4607             :             // Reset clipping
    4608           0 :             if ( nStyle & TEXT_DRAW_CLIP )
    4609           0 :                 rTargetDevice.Pop();
    4610           0 :         }
    4611             :     }
    4612             :     else
    4613             :     {
    4614           0 :         long nTextWidth = _rLayout.GetTextWidth( aStr, 0, -1 );
    4615             : 
    4616             :         // Clip text if needed
    4617           0 :         if ( nTextWidth > nWidth )
    4618             :         {
    4619           0 :             if ( nStyle & TEXT_DRAW_ELLIPSIS )
    4620             :             {
    4621           0 :                 aStr = ImplGetEllipsisString( rTargetDevice, aStr, nWidth, nStyle, _rLayout );
    4622           0 :                 nStyle &= ~(TEXT_DRAW_CENTER | TEXT_DRAW_RIGHT);
    4623           0 :                 nStyle |= TEXT_DRAW_LEFT;
    4624           0 :                 nTextWidth = _rLayout.GetTextWidth( aStr, 0, aStr.getLength() );
    4625             :             }
    4626             :         }
    4627             :         else
    4628             :         {
    4629           0 :             if ( nTextHeight <= nHeight )
    4630           0 :                 nStyle &= ~TEXT_DRAW_CLIP;
    4631             :         }
    4632             : 
    4633             :         // horizontal text alignment
    4634           0 :         if ( nStyle & TEXT_DRAW_RIGHT )
    4635           0 :             aPos.X() += nWidth-nTextWidth;
    4636           0 :         else if ( nStyle & TEXT_DRAW_CENTER )
    4637           0 :             aPos.X() += (nWidth-nTextWidth)/2;
    4638             : 
    4639             :         // vertical font alignment
    4640           0 :         if ( eAlign == ALIGN_BOTTOM )
    4641           0 :             aPos.Y() += nTextHeight;
    4642           0 :         else if ( eAlign == ALIGN_BASELINE )
    4643           0 :             aPos.Y() += rTargetDevice.GetFontMetric().GetAscent();
    4644             : 
    4645           0 :         if ( nStyle & TEXT_DRAW_BOTTOM )
    4646           0 :             aPos.Y() += nHeight-nTextHeight;
    4647           0 :         else if ( nStyle & TEXT_DRAW_VCENTER )
    4648           0 :             aPos.Y() += (nHeight-nTextHeight)/2;
    4649             : 
    4650           0 :         long nMnemonicX = 0;
    4651           0 :         long nMnemonicY = 0;
    4652           0 :         long nMnemonicWidth = 0;
    4653           0 :         if ( nMnemonicPos != -1 )
    4654             :         {
    4655           0 :             sal_Int32* pCaretXArray = (sal_Int32*) alloca( 2 * sizeof(sal_Int32) * aStr.getLength() );
    4656           0 :             /*sal_Bool bRet =*/ _rLayout.GetCaretPositions( aStr, pCaretXArray, 0, aStr.getLength() );
    4657           0 :             long lc_x1 = pCaretXArray[2*(nMnemonicPos)];
    4658           0 :             long lc_x2 = pCaretXArray[2*(nMnemonicPos)+1];
    4659           0 :             nMnemonicWidth = rTargetDevice.ImplLogicWidthToDevicePixel( ::abs((int)(lc_x1 - lc_x2)) );
    4660             : 
    4661           0 :             Point aTempPos = rTargetDevice.LogicToPixel( aPos );
    4662           0 :             nMnemonicX = rTargetDevice.GetOutOffXPixel() + aTempPos.X() + rTargetDevice.ImplLogicWidthToDevicePixel( std::min(lc_x1, lc_x2) );
    4663           0 :             nMnemonicY = rTargetDevice.GetOutOffYPixel() + aTempPos.Y() + rTargetDevice.ImplLogicWidthToDevicePixel( rTargetDevice.GetFontMetric().GetAscent() );
    4664             :         }
    4665             : 
    4666           0 :         if ( nStyle & TEXT_DRAW_CLIP )
    4667             :         {
    4668           0 :             rTargetDevice.Push( PUSH_CLIPREGION );
    4669           0 :             rTargetDevice.IntersectClipRegion( rRect );
    4670           0 :             _rLayout.DrawText( aPos, aStr, 0, aStr.getLength(), pVector, pDisplayText );
    4671           0 :             if ( bDrawMnemonics )
    4672             :             {
    4673           0 :                 if ( nMnemonicPos != -1 )
    4674           0 :                     rTargetDevice.ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
    4675             :             }
    4676           0 :             rTargetDevice.Pop();
    4677             :         }
    4678             :         else
    4679             :         {
    4680           0 :             _rLayout.DrawText( aPos, aStr, 0, aStr.getLength(), pVector, pDisplayText );
    4681           0 :             if ( bDrawMnemonics )
    4682             :             {
    4683           0 :                 if ( nMnemonicPos != -1 )
    4684           0 :                     rTargetDevice.ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
    4685             :             }
    4686             :         }
    4687             :     }
    4688             : 
    4689           0 :     if ( nStyle & TEXT_DRAW_DISABLE && !pVector )
    4690             :     {
    4691           0 :         rTargetDevice.SetTextColor( aOldTextColor );
    4692           0 :         if ( bRestoreFillColor )
    4693           0 :             rTargetDevice.SetTextFillColor( aOldTextFillColor );
    4694           0 :     }
    4695             : }
    4696             : 
    4697           0 : void OutputDevice::AddTextRectActions( const Rectangle& rRect,
    4698             :                                        const OUString&  rOrigStr,
    4699             :                                        sal_uInt16       nStyle,
    4700             :                                        GDIMetaFile&     rMtf )
    4701             : {
    4702             : 
    4703           0 :     if ( rOrigStr.isEmpty() || rRect.IsEmpty() )
    4704           0 :         return;
    4705             : 
    4706             :     // we need a graphics
    4707           0 :     if( !mpGraphics && !ImplGetGraphics() )
    4708           0 :         return;
    4709           0 :     if( mbInitClipRegion )
    4710           0 :         ImplInitClipRegion();
    4711             : 
    4712             :     // temporarily swap in passed mtf for action generation, and
    4713             :     // disable output generation.
    4714           0 :     const bool bOutputEnabled( IsOutputEnabled() );
    4715           0 :     GDIMetaFile* pMtf = mpMetaFile;
    4716             : 
    4717           0 :     mpMetaFile = &rMtf;
    4718           0 :     EnableOutput( false );
    4719             : 
    4720             :     // #i47157# Factored out to ImplDrawTextRect(), to be shared
    4721             :     // between us and DrawText()
    4722           0 :     DefaultTextLayout aLayout( *this );
    4723           0 :     ImplDrawText( *this, rRect, rOrigStr, nStyle, NULL, NULL, aLayout );
    4724             : 
    4725             :     // and restore again
    4726           0 :     EnableOutput( bOutputEnabled );
    4727           0 :     mpMetaFile = pMtf;
    4728             : }
    4729             : 
    4730           0 : void OutputDevice::DrawText( const Rectangle& rRect, const OUString& rOrigStr, sal_uInt16 nStyle,
    4731             :                              MetricVector* pVector, OUString* pDisplayText,
    4732             :                              ::vcl::ITextLayout* _pTextLayout )
    4733             : {
    4734           0 :     if( mpOutDevData && mpOutDevData->mpRecordLayout )
    4735             :     {
    4736           0 :         pVector = &mpOutDevData->mpRecordLayout->m_aUnicodeBoundRects;
    4737           0 :         pDisplayText = &mpOutDevData->mpRecordLayout->m_aDisplayText;
    4738             :     }
    4739             : 
    4740           0 :     bool bDecomposeTextRectAction = ( _pTextLayout != NULL ) && _pTextLayout->DecomposeTextRectAction();
    4741           0 :     if ( mpMetaFile && !bDecomposeTextRectAction )
    4742           0 :         mpMetaFile->AddAction( new MetaTextRectAction( rRect, rOrigStr, nStyle ) );
    4743             : 
    4744           0 :     if ( ( !IsDeviceOutputNecessary() && !pVector && !bDecomposeTextRectAction ) || rOrigStr.isEmpty() || rRect.IsEmpty() )
    4745           0 :         return;
    4746             : 
    4747             :     // we need a graphics
    4748           0 :     if( !mpGraphics && !ImplGetGraphics() )
    4749           0 :         return;
    4750           0 :     if( mbInitClipRegion )
    4751           0 :         ImplInitClipRegion();
    4752           0 :     if( mbOutputClipped && !bDecomposeTextRectAction )
    4753           0 :         return;
    4754             : 
    4755             :     // temporarily disable mtf action generation (ImplDrawText _does_
    4756             :     // create META_TEXT_ACTIONs otherwise)
    4757           0 :     GDIMetaFile* pMtf = mpMetaFile;
    4758           0 :     if ( !bDecomposeTextRectAction )
    4759           0 :         mpMetaFile = NULL;
    4760             : 
    4761             :     // #i47157# Factored out to ImplDrawText(), to be used also
    4762             :     // from AddTextRectActions()
    4763           0 :     DefaultTextLayout aDefaultLayout( *this );
    4764           0 :     ImplDrawText( *this, rRect, rOrigStr, nStyle, pVector, pDisplayText, _pTextLayout ? *_pTextLayout : aDefaultLayout );
    4765             : 
    4766             :     // and enable again
    4767           0 :     mpMetaFile = pMtf;
    4768             : 
    4769           0 :     if( mpAlphaVDev )
    4770           0 :         mpAlphaVDev->DrawText( rRect, rOrigStr, nStyle, pVector, pDisplayText );
    4771             : }
    4772             : 
    4773           0 : Rectangle OutputDevice::GetTextRect( const Rectangle& rRect,
    4774             :                                      const OUString& rStr, sal_uInt16 nStyle,
    4775             :                                      TextRectInfo* pInfo,
    4776             :                                      const ::vcl::ITextLayout* _pTextLayout ) const
    4777             : {
    4778             : 
    4779           0 :     Rectangle           aRect = rRect;
    4780             :     sal_Int32           nLines;
    4781           0 :     long                nWidth = rRect.GetWidth();
    4782             :     long                nMaxWidth;
    4783           0 :     long                nTextHeight = GetTextHeight();
    4784             : 
    4785           0 :     OUString aStr = rStr;
    4786           0 :     if ( nStyle & TEXT_DRAW_MNEMONIC )
    4787           0 :         aStr = GetNonMnemonicString( aStr );
    4788             : 
    4789           0 :     if ( nStyle & TEXT_DRAW_MULTILINE )
    4790             :     {
    4791           0 :         ImplMultiTextLineInfo   aMultiLineInfo;
    4792             :         ImplTextLineInfo*       pLineInfo;
    4793             :         sal_Int32               nFormatLines;
    4794             :         sal_Int32               i;
    4795             : 
    4796           0 :         nMaxWidth = 0;
    4797           0 :         DefaultTextLayout aDefaultLayout( *const_cast< OutputDevice* >( this ) );
    4798           0 :         ImplGetTextLines( aMultiLineInfo, nWidth, aStr, nStyle, _pTextLayout ? *_pTextLayout : aDefaultLayout );
    4799           0 :         nFormatLines = aMultiLineInfo.Count();
    4800           0 :         if ( !nTextHeight )
    4801           0 :             nTextHeight = 1;
    4802           0 :         nLines = (sal_uInt16)(aRect.GetHeight()/nTextHeight);
    4803           0 :         if ( pInfo )
    4804           0 :             pInfo->mnLineCount = nFormatLines;
    4805           0 :         if ( !nLines )
    4806           0 :             nLines = 1;
    4807           0 :         if ( nFormatLines <= nLines )
    4808           0 :             nLines = nFormatLines;
    4809             :         else
    4810             :         {
    4811           0 :             if ( !(nStyle & TEXT_DRAW_ENDELLIPSIS) )
    4812           0 :                 nLines = nFormatLines;
    4813             :             else
    4814             :             {
    4815           0 :                 if ( pInfo )
    4816           0 :                     pInfo->mbEllipsis = true;
    4817           0 :                 nMaxWidth = nWidth;
    4818             :             }
    4819             :         }
    4820           0 :         if ( pInfo )
    4821             :         {
    4822           0 :             bool bMaxWidth = nMaxWidth == 0;
    4823           0 :             pInfo->mnMaxWidth = 0;
    4824           0 :             for ( i = 0; i < nLines; i++ )
    4825             :             {
    4826           0 :                 pLineInfo = aMultiLineInfo.GetLine( i );
    4827           0 :                 if ( bMaxWidth && (pLineInfo->GetWidth() > nMaxWidth) )
    4828           0 :                     nMaxWidth = pLineInfo->GetWidth();
    4829           0 :                 if ( pLineInfo->GetWidth() > pInfo->mnMaxWidth )
    4830           0 :                     pInfo->mnMaxWidth = pLineInfo->GetWidth();
    4831             :             }
    4832             :         }
    4833           0 :         else if ( !nMaxWidth )
    4834             :         {
    4835           0 :             for ( i = 0; i < nLines; i++ )
    4836             :             {
    4837           0 :                 pLineInfo = aMultiLineInfo.GetLine( i );
    4838           0 :                 if ( pLineInfo->GetWidth() > nMaxWidth )
    4839           0 :                     nMaxWidth = pLineInfo->GetWidth();
    4840             :             }
    4841           0 :         }
    4842             :     }
    4843             :     else
    4844             :     {
    4845           0 :         nLines      = 1;
    4846           0 :         nMaxWidth   = _pTextLayout ? _pTextLayout->GetTextWidth( aStr, 0, aStr.getLength() ) : GetTextWidth( aStr );
    4847             : 
    4848           0 :         if ( pInfo )
    4849             :         {
    4850           0 :             pInfo->mnLineCount  = 1;
    4851           0 :             pInfo->mnMaxWidth   = nMaxWidth;
    4852             :         }
    4853             : 
    4854           0 :         if ( (nMaxWidth > nWidth) && (nStyle & TEXT_DRAW_ELLIPSIS) )
    4855             :         {
    4856           0 :             if ( pInfo )
    4857           0 :                 pInfo->mbEllipsis = true;
    4858           0 :             nMaxWidth = nWidth;
    4859             :         }
    4860             :     }
    4861             : 
    4862           0 :     if ( nStyle & TEXT_DRAW_RIGHT )
    4863           0 :         aRect.Left() = aRect.Right()-nMaxWidth+1;
    4864           0 :     else if ( nStyle & TEXT_DRAW_CENTER )
    4865             :     {
    4866           0 :         aRect.Left() += (nWidth-nMaxWidth)/2;
    4867           0 :         aRect.Right() = aRect.Left()+nMaxWidth-1;
    4868             :     }
    4869             :     else
    4870           0 :         aRect.Right() = aRect.Left()+nMaxWidth-1;
    4871             : 
    4872           0 :     if ( nStyle & TEXT_DRAW_BOTTOM )
    4873           0 :         aRect.Top() = aRect.Bottom()-(nTextHeight*nLines)+1;
    4874           0 :     else if ( nStyle & TEXT_DRAW_VCENTER )
    4875             :     {
    4876           0 :         aRect.Top()   += (aRect.GetHeight()-(nTextHeight*nLines))/2;
    4877           0 :         aRect.Bottom() = aRect.Top()+(nTextHeight*nLines)-1;
    4878             :     }
    4879             :     else
    4880           0 :         aRect.Bottom() = aRect.Top()+(nTextHeight*nLines)-1;
    4881             : 
    4882             :     // #99188# get rid of rounding problems when using this rect later
    4883           0 :     if (nStyle & TEXT_DRAW_RIGHT)
    4884           0 :         aRect.Left()--;
    4885             :     else
    4886           0 :         aRect.Right()++;
    4887           0 :     return aRect;
    4888             : }
    4889             : 
    4890           0 : static bool ImplIsCharIn( sal_Unicode c, const sal_Char* pStr )
    4891             : {
    4892           0 :     while ( *pStr )
    4893             :     {
    4894           0 :         if ( *pStr == c )
    4895           0 :             return true;
    4896           0 :         pStr++;
    4897             :     }
    4898             : 
    4899           0 :     return false;
    4900             : }
    4901             : 
    4902           0 : OUString OutputDevice::GetEllipsisString( const OUString& rOrigStr, long nMaxWidth,
    4903             :                                         sal_uInt16 nStyle ) const
    4904             : {
    4905           0 :     DefaultTextLayout aTextLayout( *const_cast< OutputDevice* >( this ) );
    4906           0 :     return ImplGetEllipsisString( *this, rOrigStr, nMaxWidth, nStyle, aTextLayout );
    4907             : }
    4908             : 
    4909           0 : OUString OutputDevice::ImplGetEllipsisString( const OutputDevice& rTargetDevice, const OUString& rOrigStr, long nMaxWidth,
    4910             :                                                sal_uInt16 nStyle, const ::vcl::ITextLayout& _rLayout )
    4911             : {
    4912           0 :     OUString aStr = rOrigStr;
    4913           0 :     sal_Int32 nIndex = _rLayout.GetTextBreak( aStr, nMaxWidth, 0, aStr.getLength() );
    4914             : 
    4915           0 :     if ( nIndex != -1 )
    4916             :     {
    4917           0 :         if( (nStyle & TEXT_DRAW_CENTERELLIPSIS) == TEXT_DRAW_CENTERELLIPSIS )
    4918             :         {
    4919           0 :             OUStringBuffer aTmpStr( aStr );
    4920           0 :             sal_Int32 nEraseChars = 4;
    4921           0 :             while( nEraseChars < aStr.getLength() && _rLayout.GetTextWidth( aTmpStr.toString(), 0, aTmpStr.getLength() ) > nMaxWidth )
    4922             :             {
    4923           0 :                 aTmpStr = OUStringBuffer(aStr);
    4924           0 :                 sal_Int32 i = (aTmpStr.getLength() - nEraseChars)/2;
    4925           0 :                 aTmpStr.remove(i, nEraseChars++);
    4926           0 :                 aTmpStr.insert(i, "...");
    4927             :             }
    4928           0 :             aStr = aTmpStr.makeStringAndClear();
    4929             :         }
    4930           0 :         else if ( nStyle & TEXT_DRAW_ENDELLIPSIS )
    4931             :         {
    4932           0 :             aStr = aStr.copy(0, nIndex);
    4933           0 :             if ( nIndex > 1 )
    4934             :             {
    4935           0 :                 aStr += "...";
    4936           0 :                 while ( !aStr.isEmpty() && (_rLayout.GetTextWidth( aStr, 0, aStr.getLength() ) > nMaxWidth) )
    4937             :                 {
    4938           0 :                     if ( (nIndex > 1) || (nIndex == aStr.getLength()) )
    4939           0 :                         nIndex--;
    4940           0 :                     aStr = aStr.replaceAt( nIndex, 1, "");
    4941             :                 }
    4942             :             }
    4943             : 
    4944           0 :             if ( aStr.isEmpty() && (nStyle & TEXT_DRAW_CLIP) )
    4945           0 :                 aStr += OUString(rOrigStr[ 0 ]);
    4946             :         }
    4947           0 :         else if ( nStyle & TEXT_DRAW_PATHELLIPSIS )
    4948             :         {
    4949           0 :             OUString aPath( rOrigStr );
    4950           0 :             OUString aAbbreviatedPath;
    4951           0 :             osl_abbreviateSystemPath( aPath.pData, &aAbbreviatedPath.pData, nIndex, NULL );
    4952           0 :             aStr = aAbbreviatedPath;
    4953             :         }
    4954           0 :         else if ( nStyle & TEXT_DRAW_NEWSELLIPSIS )
    4955             :         {
    4956             :             static sal_Char const   pSepChars[] = ".";
    4957             :             // Determine last section
    4958           0 :             sal_Int32 nLastContent = aStr.getLength();
    4959           0 :             while ( nLastContent )
    4960             :             {
    4961           0 :                 nLastContent--;
    4962           0 :                 if ( ImplIsCharIn( aStr[ nLastContent ], pSepChars ) )
    4963           0 :                     break;
    4964             :             }
    4965           0 :             while ( nLastContent &&
    4966           0 :                     ImplIsCharIn( aStr[ nLastContent-1 ], pSepChars ) )
    4967           0 :                 nLastContent--;
    4968             : 
    4969           0 :             OUString aLastStr = aStr.copy(nLastContent);
    4970           0 :             OUString aTempLastStr1( "..." );
    4971           0 :             aTempLastStr1 += aLastStr;
    4972           0 :             if ( _rLayout.GetTextWidth( aTempLastStr1, 0, aTempLastStr1.getLength() ) > nMaxWidth )
    4973           0 :                 aStr = OutputDevice::ImplGetEllipsisString( rTargetDevice, aStr, nMaxWidth, nStyle | TEXT_DRAW_ENDELLIPSIS, _rLayout );
    4974             :             else
    4975             :             {
    4976           0 :                 sal_Int32 nFirstContent = 0;
    4977           0 :                 while ( nFirstContent < nLastContent )
    4978             :                 {
    4979           0 :                     nFirstContent++;
    4980           0 :                     if ( ImplIsCharIn( aStr[ nFirstContent ], pSepChars ) )
    4981           0 :                         break;
    4982             :                 }
    4983           0 :                 while ( (nFirstContent < nLastContent) &&
    4984           0 :                         ImplIsCharIn( aStr[ nFirstContent ], pSepChars ) )
    4985           0 :                     nFirstContent++;
    4986             :                 // MEM continue here
    4987           0 :                 if ( nFirstContent >= nLastContent )
    4988           0 :                     aStr = OutputDevice::ImplGetEllipsisString( rTargetDevice, aStr, nMaxWidth, nStyle | TEXT_DRAW_ENDELLIPSIS, _rLayout );
    4989             :                 else
    4990             :                 {
    4991           0 :                     if ( nFirstContent > 4 )
    4992           0 :                         nFirstContent = 4;
    4993           0 :                     OUString aFirstStr = aStr.copy( 0, nFirstContent );
    4994           0 :                     aFirstStr += "...";
    4995           0 :                     OUString aTempStr = aFirstStr + aLastStr;
    4996           0 :                     if ( _rLayout.GetTextWidth( aTempStr, 0, aTempStr.getLength() ) > nMaxWidth )
    4997           0 :                         aStr = OutputDevice::ImplGetEllipsisString( rTargetDevice, aStr, nMaxWidth, nStyle | TEXT_DRAW_ENDELLIPSIS, _rLayout );
    4998             :                     else
    4999             :                     {
    5000           0 :                         do
    5001             :                         {
    5002           0 :                             aStr = aTempStr;
    5003           0 :                             if( nLastContent > aStr.getLength() )
    5004           0 :                                 nLastContent = aStr.getLength();
    5005           0 :                             while ( nFirstContent < nLastContent )
    5006             :                             {
    5007           0 :                                 nLastContent--;
    5008           0 :                                 if ( ImplIsCharIn( aStr[ nLastContent ], pSepChars ) )
    5009           0 :                                     break;
    5010             : 
    5011             :                             }
    5012           0 :                             while ( (nFirstContent < nLastContent) &&
    5013           0 :                                     ImplIsCharIn( aStr[ nLastContent-1 ], pSepChars ) )
    5014           0 :                                 nLastContent--;
    5015             : 
    5016           0 :                             if ( nFirstContent < nLastContent )
    5017             :                             {
    5018           0 :                                 OUString aTempLastStr = aStr.copy( nLastContent );
    5019           0 :                                 aTempStr = aFirstStr + aTempLastStr;
    5020             : 
    5021           0 :                                 if ( _rLayout.GetTextWidth( aTempStr, 0, aTempStr.getLength() ) > nMaxWidth )
    5022           0 :                                     break;
    5023             :                             }
    5024             :                         }
    5025             :                         while ( nFirstContent < nLastContent );
    5026           0 :                     }
    5027             :                 }
    5028           0 :             }
    5029             :         }
    5030             :     }
    5031             : 
    5032           0 :     return aStr;
    5033             : }
    5034             : 
    5035           0 : void OutputDevice::DrawCtrlText( const Point& rPos, const OUString& rStr,
    5036             :                                  sal_Int32 nIndex, sal_Int32 nLen,
    5037             :                                  sal_uInt16 nStyle, MetricVector* pVector, OUString* pDisplayText )
    5038             : {
    5039             : 
    5040           0 :     if(nLen == 0x0FFFF)
    5041             :     {
    5042             :         SAL_INFO("sal.rtl.xub",
    5043             :                  "DrawCtrlText Suspicious arguments nLen:" << nLen);
    5044             :     }
    5045           0 :     if( (nLen < 0) || (nIndex + nLen >= rStr.getLength()))
    5046             :     {
    5047           0 :         nLen = rStr.getLength() - nIndex;
    5048             :     }
    5049             : 
    5050           0 :     if ( !IsDeviceOutputNecessary() || (nIndex >= rStr.getLength()) )
    5051           0 :         return;
    5052             : 
    5053             :     // better get graphics here because ImplDrawMnemonicLine() will not
    5054             :     // we need a graphics
    5055           0 :     if( !mpGraphics && !ImplGetGraphics() )
    5056           0 :         return;
    5057           0 :     if( mbInitClipRegion )
    5058           0 :         ImplInitClipRegion();
    5059           0 :     if ( mbOutputClipped )
    5060           0 :         return;
    5061             : 
    5062           0 :     if( nIndex >= rStr.getLength() )
    5063           0 :         return;
    5064             : 
    5065           0 :     if( (nLen < 0) || (nIndex + nLen >= rStr.getLength()))
    5066             :     {
    5067           0 :         nLen = rStr.getLength() - nIndex;
    5068             :     }
    5069           0 :     OUString   aStr = rStr;
    5070           0 :     sal_Int32  nMnemonicPos = -1;
    5071             : 
    5072           0 :     long        nMnemonicX = 0;
    5073           0 :     long        nMnemonicY = 0;
    5074           0 :     long        nMnemonicWidth = 0;
    5075           0 :     if ( (nStyle & TEXT_DRAW_MNEMONIC) && nLen > 1 )
    5076             :     {
    5077           0 :         aStr = GetNonMnemonicString( aStr, nMnemonicPos );
    5078           0 :         if ( nMnemonicPos != -1 )
    5079             :         {
    5080           0 :             if( nMnemonicPos < nIndex )
    5081             :             {
    5082           0 :                 --nIndex;
    5083             :             }
    5084             :             else
    5085             :             {
    5086           0 :                 if( nMnemonicPos < (nIndex+nLen) )
    5087           0 :                     --nLen;
    5088             :                 DBG_ASSERT( nMnemonicPos < (nIndex+nLen), "Mnemonic underline marker after last character" );
    5089             :             }
    5090           0 :             bool bInvalidPos = false;
    5091             : 
    5092           0 :             if( nMnemonicPos >= nLen )
    5093             :             {
    5094             :                 // #106952#
    5095             :                 // may occur in BiDi-Strings: the '~' is sometimes found behind the last char
    5096             :                 // due to some strange BiDi text editors
    5097             :                 // -> place the underline behind the string to indicate a failure
    5098           0 :                 bInvalidPos = true;
    5099           0 :                 nMnemonicPos = nLen-1;
    5100             :             }
    5101             : 
    5102           0 :             sal_Int32* pCaretXArray = (sal_Int32*)alloca( 2 * sizeof(sal_Int32) * nLen );
    5103           0 :             /*sal_Bool bRet =*/ GetCaretPositions( aStr, pCaretXArray, nIndex, nLen );
    5104           0 :             long lc_x1 = pCaretXArray[ 2*(nMnemonicPos - nIndex) ];
    5105           0 :             long lc_x2 = pCaretXArray[ 2*(nMnemonicPos - nIndex)+1 ];
    5106           0 :             nMnemonicWidth = ::abs((int)(lc_x1 - lc_x2));
    5107             : 
    5108           0 :             Point aTempPos( std::min(lc_x1,lc_x2), GetFontMetric().GetAscent() );
    5109           0 :             if( bInvalidPos )  // #106952#, place behind the (last) character
    5110           0 :                 aTempPos = Point( std::max(lc_x1,lc_x2), GetFontMetric().GetAscent() );
    5111             : 
    5112           0 :             aTempPos += rPos;
    5113           0 :             aTempPos = LogicToPixel( aTempPos );
    5114           0 :             nMnemonicX = mnOutOffX + aTempPos.X();
    5115           0 :             nMnemonicY = mnOutOffY + aTempPos.Y();
    5116             :         }
    5117             :     }
    5118             : 
    5119           0 :     if ( nStyle & TEXT_DRAW_DISABLE && ! pVector )
    5120             :     {
    5121           0 :         Color aOldTextColor;
    5122           0 :         Color aOldTextFillColor;
    5123             :         bool  bRestoreFillColor;
    5124           0 :         bool  bHighContrastBlack = false;
    5125           0 :         bool  bHighContrastWhite = false;
    5126           0 :         const StyleSettings& rStyleSettings( GetSettings().GetStyleSettings() );
    5127           0 :         if( rStyleSettings.GetHighContrastMode() )
    5128             :         {
    5129           0 :             if( IsBackground() )
    5130             :             {
    5131           0 :                 Wallpaper aWall = GetBackground();
    5132           0 :                 Color aCol = aWall.GetColor();
    5133           0 :                 bHighContrastBlack = aCol.IsDark();
    5134           0 :                 bHighContrastWhite = aCol.IsBright();
    5135             :             }
    5136             :         }
    5137             : 
    5138           0 :         aOldTextColor = GetTextColor();
    5139           0 :         if ( IsTextFillColor() )
    5140             :         {
    5141           0 :             bRestoreFillColor = true;
    5142           0 :             aOldTextFillColor = GetTextFillColor();
    5143             :         }
    5144             :         else
    5145           0 :             bRestoreFillColor = false;
    5146             : 
    5147           0 :         if( bHighContrastBlack )
    5148           0 :             SetTextColor( COL_GREEN );
    5149           0 :         else if( bHighContrastWhite )
    5150           0 :             SetTextColor( COL_LIGHTGREEN );
    5151             :         else
    5152           0 :             SetTextColor( GetSettings().GetStyleSettings().GetDisableColor() );
    5153             : 
    5154           0 :         DrawText( rPos, aStr, nIndex, nLen, pVector, pDisplayText );
    5155           0 :         if ( !(GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_NOMNEMONICS) && !pVector )
    5156             :         {
    5157           0 :             if ( nMnemonicPos != -1 )
    5158           0 :                 ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
    5159             :         }
    5160           0 :         SetTextColor( aOldTextColor );
    5161           0 :         if ( bRestoreFillColor )
    5162           0 :             SetTextFillColor( aOldTextFillColor );
    5163             :     }
    5164             :     else
    5165             :     {
    5166           0 :         DrawText( rPos, aStr, nIndex, nLen, pVector, pDisplayText );
    5167           0 :         if ( !(GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_NOMNEMONICS) && !pVector )
    5168             :         {
    5169           0 :             if ( nMnemonicPos != -1 )
    5170           0 :                 ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
    5171             :         }
    5172             :     }
    5173             : 
    5174           0 :     if( mpAlphaVDev )
    5175           0 :         mpAlphaVDev->DrawCtrlText( rPos, rStr, nIndex, nLen, nStyle, pVector, pDisplayText );
    5176             : }
    5177             : 
    5178           0 : long OutputDevice::GetCtrlTextWidth( const OUString& rStr,
    5179             :                                      sal_Int32 nIndex, sal_Int32 nLen,
    5180             :                                      sal_uInt16 nStyle ) const
    5181             : {
    5182           0 :     if(nLen == 0x0FFFF)
    5183             :     {
    5184             :         SAL_INFO("sal.rtl.xub",
    5185             :                  "GetCtrlTextWidth Suspicious arguments nLen:" << nLen);
    5186             :     }
    5187             :     /* defensive code */
    5188           0 :     if( (nLen < 0) || (nIndex + nLen >= rStr.getLength()))
    5189             :     {
    5190           0 :         nLen = rStr.getLength() - nIndex;
    5191             :     }
    5192             : 
    5193           0 :     if ( nStyle & TEXT_DRAW_MNEMONIC )
    5194             :     {
    5195             :         sal_Int32  nMnemonicPos;
    5196           0 :         OUString   aStr = GetNonMnemonicString( rStr, nMnemonicPos );
    5197           0 :         if ( nMnemonicPos != -1 )
    5198             :         {
    5199           0 :             if ( nMnemonicPos < nIndex )
    5200           0 :                 nIndex--;
    5201           0 :             else if ( (nMnemonicPos >= nIndex) && ((sal_uLong)nMnemonicPos < (sal_uLong)(nIndex+nLen)) )
    5202           0 :                 nLen--;
    5203             :         }
    5204           0 :         return GetTextWidth( aStr, nIndex, nLen );
    5205             :     }
    5206             :     else
    5207           0 :         return GetTextWidth( rStr, nIndex, nLen );
    5208             : }
    5209             : 
    5210           0 : OUString OutputDevice::GetNonMnemonicString( const OUString& rStr, sal_Int32& rMnemonicPos )
    5211             : {
    5212           0 :     OUString   aStr    = rStr;
    5213           0 :     sal_Int32  nLen    = aStr.getLength();
    5214           0 :     sal_Int32  i       = 0;
    5215             : 
    5216           0 :     rMnemonicPos = -1;
    5217           0 :     while ( i < nLen )
    5218             :     {
    5219           0 :         if ( aStr[ i ] == '~' )
    5220             :         {
    5221           0 :             if ( nLen <= i+1 )
    5222           0 :                 break;
    5223             : 
    5224           0 :             if ( aStr[ i+1 ] != '~' )
    5225             :             {
    5226           0 :                 if ( rMnemonicPos == -1 )
    5227           0 :                     rMnemonicPos = i;
    5228           0 :                 aStr = aStr.replaceAt( i, 1, "" );
    5229           0 :                 nLen--;
    5230             :             }
    5231             :             else
    5232             :             {
    5233           0 :                 aStr = aStr.replaceAt( i, 1, "" );
    5234           0 :                 nLen--;
    5235           0 :                 i++;
    5236             :             }
    5237             :         }
    5238             :         else
    5239           0 :             i++;
    5240             :     }
    5241             : 
    5242           0 :     return aStr;
    5243             : }
    5244             : 
    5245           0 : int OutputDevice::GetDevFontCount() const
    5246             : {
    5247             : 
    5248           0 :     if( !mpGetDevFontList )
    5249           0 :         mpGetDevFontList = mpFontCollection->GetDevFontList();
    5250           0 :     return mpGetDevFontList->Count();
    5251             : }
    5252             : 
    5253           0 : FontInfo OutputDevice::GetDevFont( int nDevFontIndex ) const
    5254             : {
    5255             : 
    5256           0 :     FontInfo aFontInfo;
    5257             : 
    5258           0 :     ImplInitFontList();
    5259             : 
    5260           0 :     int nCount = GetDevFontCount();
    5261           0 :     if( nDevFontIndex < nCount )
    5262             :     {
    5263           0 :         const PhysicalFontFace& rData = *mpGetDevFontList->Get( nDevFontIndex );
    5264           0 :         aFontInfo.SetName( rData.GetFamilyName() );
    5265           0 :         aFontInfo.SetStyleName( rData.GetStyleName() );
    5266           0 :         aFontInfo.SetCharSet( rData.IsSymbolFont() ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UNICODE );
    5267           0 :         aFontInfo.SetFamily( rData.GetFamilyType() );
    5268           0 :         aFontInfo.SetPitch( rData.GetPitch() );
    5269           0 :         aFontInfo.SetWeight( rData.GetWeight() );
    5270           0 :         aFontInfo.SetItalic( rData.GetSlant() );
    5271           0 :         aFontInfo.SetWidthType( rData.GetWidthType() );
    5272           0 :         if( rData.IsScalable() )
    5273           0 :             aFontInfo.mpImplMetric->mnMiscFlags |= ImplFontMetric::SCALABLE_FLAG;
    5274           0 :         if( rData.mbDevice )
    5275           0 :             aFontInfo.mpImplMetric->mnMiscFlags |= ImplFontMetric::DEVICE_FLAG;
    5276             :     }
    5277             : 
    5278           0 :     return aFontInfo;
    5279             : }
    5280             : 
    5281           0 : bool OutputDevice::AddTempDevFont( const OUString& rFileURL, const OUString& rFontName )
    5282             : {
    5283             : 
    5284           0 :     ImplInitFontList();
    5285             : 
    5286           0 :     if( !mpGraphics && !ImplGetGraphics() )
    5287           0 :         return false;
    5288             : 
    5289           0 :     bool bRC = mpGraphics->AddTempDevFont( mpFontCollection, rFileURL, rFontName );
    5290           0 :     if( !bRC )
    5291           0 :         return false;
    5292             : 
    5293           0 :     if( mpAlphaVDev )
    5294           0 :         mpAlphaVDev->AddTempDevFont( rFileURL, rFontName );
    5295             : 
    5296           0 :     mpFontCache->Invalidate();
    5297           0 :     return true;
    5298             : }
    5299             : 
    5300           0 : int OutputDevice::GetDevFontSizeCount( const Font& rFont ) const
    5301             : {
    5302             : 
    5303           0 :     delete mpGetDevSizeList;
    5304             : 
    5305           0 :     ImplInitFontList();
    5306           0 :     mpGetDevSizeList = mpFontCollection->GetDevSizeList( rFont.GetName() );
    5307           0 :     return mpGetDevSizeList->Count();
    5308             : }
    5309             : 
    5310           0 : Size OutputDevice::GetDevFontSize( const Font& rFont, int nSizeIndex ) const
    5311             : {
    5312             : 
    5313             :     // check range
    5314           0 :     int nCount = GetDevFontSizeCount( rFont );
    5315           0 :     if ( nSizeIndex >= nCount )
    5316           0 :         return Size();
    5317             : 
    5318             :     // when mapping is enabled round to .5 points
    5319           0 :     Size aSize( 0, mpGetDevSizeList->Get( nSizeIndex ) );
    5320           0 :     if ( mbMap )
    5321             :     {
    5322           0 :         aSize.Height() *= 10;
    5323           0 :         MapMode aMap( MAP_10TH_INCH, Point(), Fraction( 1, 72 ), Fraction( 1, 72 ) );
    5324           0 :         aSize = PixelToLogic( aSize, aMap );
    5325           0 :         aSize.Height() += 5;
    5326           0 :         aSize.Height() /= 10;
    5327           0 :         long nRound = aSize.Height() % 5;
    5328           0 :         if ( nRound >= 3 )
    5329           0 :             aSize.Height() += (5-nRound);
    5330             :         else
    5331           0 :             aSize.Height() -= nRound;
    5332           0 :         aSize.Height() *= 10;
    5333           0 :         aSize = LogicToPixel( aSize, aMap );
    5334           0 :         aSize = PixelToLogic( aSize );
    5335           0 :         aSize.Height() += 5;
    5336           0 :         aSize.Height() /= 10;
    5337             :     }
    5338           0 :     return aSize;
    5339             : }
    5340             : 
    5341           0 : bool OutputDevice::IsFontAvailable( const OUString& rFontName ) const
    5342             : {
    5343             : 
    5344           0 :     PhysicalFontFamily* pFound = mpFontCollection->FindFontFamily( rFontName );
    5345           0 :     return (pFound != NULL);
    5346             : }
    5347             : 
    5348           0 : FontMetric OutputDevice::GetFontMetric() const
    5349             : {
    5350             : 
    5351           0 :     FontMetric aMetric;
    5352           0 :     if( mbNewFont && !ImplNewFont() )
    5353           0 :         return aMetric;
    5354             : 
    5355           0 :     ImplFontEntry*      pEntry = mpFontEntry;
    5356           0 :     ImplFontMetricData* pMetric = &(pEntry->maMetric);
    5357             : 
    5358             :     // prepare metric
    5359           0 :     aMetric.Font::operator=( maFont );
    5360             : 
    5361             :     // set aMetric with info from font
    5362           0 :     aMetric.SetName( maFont.GetName() );
    5363           0 :     aMetric.SetStyleName( pMetric->GetStyleName() );
    5364           0 :     aMetric.SetSize( PixelToLogic( Size( pMetric->mnWidth, pMetric->mnAscent+pMetric->mnDescent-pMetric->mnIntLeading ) ) );
    5365           0 :     aMetric.SetCharSet( pMetric->IsSymbolFont() ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UNICODE );
    5366           0 :     aMetric.SetFamily( pMetric->GetFamilyType() );
    5367           0 :     aMetric.SetPitch( pMetric->GetPitch() );
    5368           0 :     aMetric.SetWeight( pMetric->GetWeight() );
    5369           0 :     aMetric.SetItalic( pMetric->GetSlant() );
    5370           0 :     aMetric.SetWidthType( pMetric->GetWidthType() );
    5371           0 :     if ( pEntry->mnOwnOrientation )
    5372           0 :         aMetric.SetOrientation( pEntry->mnOwnOrientation );
    5373             :     else
    5374           0 :         aMetric.SetOrientation( pMetric->mnOrientation );
    5375           0 :     if( !pEntry->maMetric.mbKernableFont )
    5376           0 :          aMetric.SetKerning( maFont.GetKerning() & ~KERNING_FONTSPECIFIC );
    5377             : 
    5378             :     // set remaining metric fields
    5379           0 :     aMetric.mpImplMetric->mnMiscFlags   = 0;
    5380           0 :     if( pMetric->mbDevice )
    5381           0 :             aMetric.mpImplMetric->mnMiscFlags |= ImplFontMetric::DEVICE_FLAG;
    5382           0 :     if( pMetric->mbScalableFont )
    5383           0 :             aMetric.mpImplMetric->mnMiscFlags |= ImplFontMetric::SCALABLE_FLAG;
    5384           0 :     aMetric.mpImplMetric->mnAscent      = ImplDevicePixelToLogicHeight( pMetric->mnAscent+mnEmphasisAscent );
    5385           0 :     aMetric.mpImplMetric->mnDescent     = ImplDevicePixelToLogicHeight( pMetric->mnDescent+mnEmphasisDescent );
    5386           0 :     aMetric.mpImplMetric->mnIntLeading  = ImplDevicePixelToLogicHeight( pMetric->mnIntLeading+mnEmphasisAscent );
    5387           0 :     aMetric.mpImplMetric->mnExtLeading  = ImplDevicePixelToLogicHeight( pMetric->mnExtLeading );
    5388           0 :     aMetric.mpImplMetric->mnLineHeight  = ImplDevicePixelToLogicHeight( pMetric->mnAscent+pMetric->mnDescent+mnEmphasisAscent+mnEmphasisDescent );
    5389           0 :     aMetric.mpImplMetric->mnSlant       = ImplDevicePixelToLogicHeight( pMetric->mnSlant );
    5390             : 
    5391             : #ifdef UNX
    5392             :     // backwards compatible line metrics after fixing #i60945#
    5393           0 :     if( (meOutDevType == OUTDEV_VIRDEV)
    5394           0 :     &&  static_cast<const VirtualDevice*>(this)->ForceZeroExtleadBug() )
    5395           0 :         aMetric.mpImplMetric->mnExtLeading = 0;
    5396             : #endif
    5397             : 
    5398           0 :     return aMetric;
    5399             : }
    5400             : 
    5401           0 : FontMetric OutputDevice::GetFontMetric( const Font& rFont ) const
    5402             : {
    5403             :     // select font, query metrics, select original font again
    5404           0 :     Font aOldFont = GetFont();
    5405           0 :     const_cast<OutputDevice*>(this)->SetFont( rFont );
    5406           0 :     FontMetric aMetric( GetFontMetric() );
    5407           0 :     const_cast<OutputDevice*>(this)->SetFont( aOldFont );
    5408           0 :     return aMetric;
    5409             : }
    5410             : 
    5411             : /** OutputDevice::GetSysFontData
    5412             :  *
    5413             :  * @param nFallbacklevel Fallback font level (0 = best matching font)
    5414             :  *
    5415             :  * Retrieve detailed font information in platform independent structure
    5416             :  *
    5417             :  * @return SystemFontData
    5418             :  **/
    5419           0 : SystemFontData OutputDevice::GetSysFontData(int nFallbacklevel) const
    5420             : {
    5421           0 :     SystemFontData aSysFontData;
    5422           0 :     aSysFontData.nSize = sizeof(aSysFontData);
    5423             : 
    5424           0 :     if (!mpGraphics) ImplGetGraphics();
    5425           0 :     if (mpGraphics) aSysFontData = mpGraphics->GetSysFontData(nFallbacklevel);
    5426             : 
    5427           0 :     return aSysFontData;
    5428             : }
    5429             : 
    5430             : /** OutputDevice::GetSysTextLayoutData
    5431             :  *
    5432             :  * @param rStartPt Start point of the text
    5433             :  * @param rStr Text string that will be transformed into layout of glyphs
    5434             :  * @param nIndex Position in the string from where layout will be done
    5435             :  * @param nLen Length of the string
    5436             :  * @param pDXAry Custom layout adjustment data
    5437             :  *
    5438             :  * Export finalized glyph layout data as platform independent SystemTextLayoutData
    5439             :  * (see vcl/inc/vcl/sysdata.hxx)
    5440             :  *
    5441             :  * Only parameters rStartPt and rStr are mandatory, the rest is optional
    5442             :  * (default values will be used)
    5443             :  *
    5444             :  * @return SystemTextLayoutData
    5445             :  **/
    5446           0 : SystemTextLayoutData OutputDevice::GetSysTextLayoutData(const Point& rStartPt, const OUString& rStr, sal_Int32 nIndex, sal_Int32 nLen,
    5447             :                                                         const sal_Int32* pDXAry) const
    5448             : {
    5449           0 :     if(nLen == 0x0FFFF)
    5450             :     {
    5451             :         SAL_INFO("sal.rtl.xub",
    5452             :                  "GetSysTextLayoutData Suspicious arguments nLen:" << nLen);
    5453             :     }
    5454           0 :     if( (nLen < 0) || (nIndex + nLen >= rStr.getLength()))
    5455             :     {
    5456           0 :         nLen = rStr.getLength() - nIndex;
    5457             :     }
    5458             : 
    5459           0 :     SystemTextLayoutData aSysLayoutData;
    5460           0 :     aSysLayoutData.nSize = sizeof(aSysLayoutData);
    5461           0 :     aSysLayoutData.rGlyphData.reserve( 256 );
    5462           0 :     aSysLayoutData.orientation = 0;
    5463             : 
    5464           0 :     if ( mpMetaFile )
    5465             :     {
    5466           0 :         if (pDXAry)
    5467           0 :             mpMetaFile->AddAction( new MetaTextArrayAction( rStartPt, rStr, pDXAry, nIndex, nLen ) );
    5468             :         else
    5469           0 :             mpMetaFile->AddAction( new MetaTextAction( rStartPt, rStr, nIndex, nLen ) );
    5470             :     }
    5471             : 
    5472           0 :     if ( !IsDeviceOutputNecessary() ) return aSysLayoutData;
    5473             : 
    5474           0 :     SalLayout* pLayout = ImplLayout(rStr, nIndex, nLen, rStartPt, 0, pDXAry);
    5475             : 
    5476           0 :     if ( !pLayout ) return aSysLayoutData;
    5477             : 
    5478             :     // setup glyphs
    5479           0 :     Point aPos;
    5480             :     sal_GlyphId aGlyphId;
    5481           0 :     for( int nStart = 0; pLayout->GetNextGlyphs( 1, &aGlyphId, aPos, nStart ); )
    5482             :     {
    5483             :         // NOTE: Windows backend is producing unicode chars (ucs4), so on windows,
    5484             :         //       ETO_GLYPH_INDEX is unusable, unless extra glyph conversion is made.
    5485             : 
    5486             :         SystemGlyphData aGlyph;
    5487           0 :         aGlyph.index = static_cast<unsigned long> (aGlyphId & GF_IDXMASK);
    5488           0 :         aGlyph.x = aPos.X();
    5489           0 :         aGlyph.y = aPos.Y();
    5490           0 :         int nLevel = (aGlyphId & GF_FONTMASK) >> GF_FONTSHIFT;
    5491           0 :         aGlyph.fallbacklevel = nLevel < MAX_FALLBACK ? nLevel : 0;
    5492           0 :         aSysLayoutData.rGlyphData.push_back(aGlyph);
    5493             :     }
    5494             : 
    5495             :     // Get font data
    5496           0 :     aSysLayoutData.orientation = pLayout->GetOrientation();
    5497             : 
    5498           0 :     pLayout->Release();
    5499             : 
    5500           0 :     return aSysLayoutData;
    5501             : }
    5502             : 
    5503           0 : long OutputDevice::GetMinKashida() const
    5504             : {
    5505           0 :     if( mbNewFont && !ImplNewFont() )
    5506           0 :         return 0;
    5507             : 
    5508           0 :     ImplFontEntry*      pEntry = mpFontEntry;
    5509           0 :     ImplFontMetricData* pMetric = &(pEntry->maMetric);
    5510           0 :     return ImplDevicePixelToLogicWidth( pMetric->mnMinKashida );
    5511             : }
    5512             : 
    5513           0 : sal_Int32 OutputDevice::ValidateKashidas ( const OUString& rTxt,
    5514             :                                             sal_Int32 nIdx, sal_Int32 nLen,
    5515             :                                             sal_Int32 nKashCount,
    5516             :                                             const sal_Int32* pKashidaPos,
    5517             :                                             sal_Int32* pKashidaPosDropped ) const
    5518             : {
    5519             :    // do layout
    5520           0 :     SalLayout* pSalLayout = ImplLayout( rTxt, nIdx, nLen );
    5521           0 :     if( !pSalLayout )
    5522           0 :         return 0;
    5523           0 :     sal_Int32 nDropped = 0;
    5524           0 :     for( int i = 0; i < nKashCount; ++i )
    5525             :     {
    5526           0 :         if( !pSalLayout->IsKashidaPosValid( pKashidaPos[ i ] ))
    5527             :         {
    5528           0 :             pKashidaPosDropped[ nDropped ] = pKashidaPos [ i ];
    5529           0 :             ++nDropped;
    5530             :         }
    5531             :     }
    5532           0 :     pSalLayout->Release();
    5533           0 :     return nDropped;
    5534             : }
    5535             : 
    5536           0 : bool OutputDevice::GetGlyphBoundRects( const Point& rOrigin, const OUString& rStr,
    5537             :                                            int nIndex, int nLen, int nBase, MetricVector& rVector )
    5538             : {
    5539             : 
    5540           0 :     rVector.clear();
    5541             : 
    5542           0 :     if(nLen == 0x0FFFF)
    5543             :     {
    5544             :         SAL_INFO("sal.rtl.xub",
    5545             :                  "GetGlyphBoundRects Suspicious arguments nLen:" << nLen);
    5546             :     }
    5547             : 
    5548           0 :     if( nIndex >= rStr.getLength() )
    5549           0 :         return false;
    5550             : 
    5551           0 :     if( nLen < 0 || nIndex + nLen >= rStr.getLength() )
    5552             :     {
    5553           0 :         nLen = rStr.getLength() - nIndex;
    5554             :     }
    5555             : 
    5556           0 :     Rectangle aRect;
    5557           0 :     for( int i = 0; i < nLen; i++ )
    5558             :     {
    5559           0 :         if( !GetTextBoundRect( aRect, rStr, nBase, nIndex + i, 1 ) )
    5560           0 :             break;
    5561           0 :         aRect.Move( rOrigin.X(), rOrigin.Y() );
    5562           0 :         rVector.push_back( aRect );
    5563             :     }
    5564             : 
    5565           0 :     return (nLen == (int)rVector.size());
    5566             : }
    5567             : 
    5568           0 : bool OutputDevice::GetTextBoundRect( Rectangle& rRect,
    5569             :                                          const OUString& rStr, sal_Int32 nBase,
    5570             :                                          sal_Int32 nIndex, sal_Int32 nLen,
    5571             :                                          sal_uLong nLayoutWidth, const sal_Int32* pDXAry ) const
    5572             : {
    5573           0 :     if(nLen == 0x0FFFF)
    5574             :     {
    5575             :         SAL_INFO("sal.rtl.xub",
    5576             :                  "GetTextBoundRect Suspicious arguments nLen:" << nLen);
    5577             :     }
    5578             : 
    5579           0 :     bool bRet = false;
    5580           0 :     rRect.SetEmpty();
    5581             : 
    5582           0 :     SalLayout* pSalLayout = NULL;
    5583           0 :     const Point aPoint;
    5584             :     // calculate offset when nBase!=nIndex
    5585           0 :     long nXOffset = 0;
    5586           0 :     if( nBase != nIndex )
    5587             :     {
    5588           0 :         sal_Int32 nStart = std::min( nBase, nIndex );
    5589           0 :         sal_Int32 nOfsLen = std::max( nBase, nIndex ) - nStart;
    5590           0 :         pSalLayout = ImplLayout( rStr, nStart, nOfsLen, aPoint, nLayoutWidth, pDXAry );
    5591           0 :         if( pSalLayout )
    5592             :         {
    5593           0 :             nXOffset = pSalLayout->GetTextWidth();
    5594           0 :             nXOffset /= pSalLayout->GetUnitsPerPixel();
    5595           0 :             pSalLayout->Release();
    5596             :             // TODO: fix offset calculation for Bidi case
    5597           0 :             if( nBase < nIndex)
    5598           0 :                 nXOffset = -nXOffset;
    5599             :         }
    5600             :     }
    5601             : 
    5602           0 :     pSalLayout = ImplLayout( rStr, nIndex, nLen, aPoint, nLayoutWidth, pDXAry );
    5603           0 :     Rectangle aPixelRect;
    5604           0 :     if( pSalLayout )
    5605             :     {
    5606           0 :         bRet = pSalLayout->GetBoundRect( *mpGraphics, aPixelRect );
    5607             : 
    5608           0 :         if( bRet )
    5609             :         {
    5610           0 :             int nWidthFactor = pSalLayout->GetUnitsPerPixel();
    5611             : 
    5612           0 :             if( nWidthFactor > 1 )
    5613             :             {
    5614           0 :                 double fFactor = 1.0 / nWidthFactor;
    5615           0 :                 aPixelRect.Left()
    5616           0 :                     = static_cast< long >(aPixelRect.Left() * fFactor);
    5617           0 :                 aPixelRect.Right()
    5618           0 :                     = static_cast< long >(aPixelRect.Right() * fFactor);
    5619           0 :                 aPixelRect.Top()
    5620           0 :                     = static_cast< long >(aPixelRect.Top() * fFactor);
    5621           0 :                 aPixelRect.Bottom()
    5622           0 :                     = static_cast< long >(aPixelRect.Bottom() * fFactor);
    5623             :             }
    5624             : 
    5625           0 :             Point aRotatedOfs( mnTextOffX, mnTextOffY );
    5626           0 :             aRotatedOfs -= pSalLayout->GetDrawPosition( Point( nXOffset, 0 ) );
    5627           0 :             aPixelRect += aRotatedOfs;
    5628           0 :             rRect = PixelToLogic( aPixelRect );
    5629           0 :             if( mbMap )
    5630           0 :                 rRect += Point( maMapRes.mnMapOfsX, maMapRes.mnMapOfsY );
    5631             :         }
    5632             : 
    5633           0 :         pSalLayout->Release();
    5634             :     }
    5635             : 
    5636           0 :     if( bRet || (OUTDEV_PRINTER == meOutDevType) || !mpFontEntry )
    5637           0 :         return bRet;
    5638             : 
    5639             :     // fall back to bitmap method to get the bounding rectangle,
    5640             :     // so we need a monochrome virtual device with matching font
    5641           0 :     VirtualDevice aVDev( 1 );
    5642           0 :     Font aFont( GetFont() );
    5643           0 :     aFont.SetShadow( false );
    5644           0 :     aFont.SetOutline( false );
    5645           0 :     aFont.SetRelief( RELIEF_NONE );
    5646           0 :     aFont.SetOrientation( 0 );
    5647           0 :     aFont.SetSize( Size( mpFontEntry->maFontSelData.mnWidth, mpFontEntry->maFontSelData.mnHeight ) );
    5648           0 :     aVDev.SetFont( aFont );
    5649           0 :     aVDev.SetTextAlign( ALIGN_TOP );
    5650             : 
    5651             :     // layout the text on the virtual device
    5652           0 :     pSalLayout = aVDev.ImplLayout( rStr, nIndex, nLen, aPoint, nLayoutWidth, pDXAry );
    5653           0 :     if( !pSalLayout )
    5654           0 :         return false;
    5655             : 
    5656             :     // make the bitmap big enough
    5657             :     // TODO: use factors when it would get too big
    5658           0 :     long nWidth = pSalLayout->GetTextWidth();
    5659           0 :     long nHeight = mpFontEntry->mnLineHeight + mnEmphasisAscent + mnEmphasisDescent;
    5660           0 :     Point aOffset( nWidth/2, 8 );
    5661           0 :     Size aOutSize( nWidth + 2*aOffset.X(), nHeight + 2*aOffset.Y() );
    5662           0 :     if( !nWidth || !aVDev.SetOutputSizePixel( aOutSize ) )
    5663           0 :         return false;
    5664             : 
    5665             :     // draw text in black
    5666           0 :     pSalLayout->DrawBase() = aOffset;
    5667           0 :     aVDev.SetTextColor( Color( COL_BLACK ) );
    5668           0 :     aVDev.SetTextFillColor();
    5669           0 :     aVDev.ImplInitTextColor();
    5670           0 :     aVDev.ImplDrawText( *pSalLayout );
    5671           0 :     pSalLayout->Release();
    5672             : 
    5673             :     // find extents using the bitmap
    5674           0 :     Bitmap aBmp = aVDev.GetBitmap( Point(), aOutSize );
    5675           0 :     BitmapReadAccess* pAcc = aBmp.AcquireReadAccess();
    5676           0 :     if( !pAcc )
    5677           0 :         return false;
    5678           0 :     const BitmapColor aBlack( pAcc->GetBestMatchingColor( Color( COL_BLACK ) ) );
    5679           0 :     const long nW = pAcc->Width();
    5680           0 :     const long nH = pAcc->Height();
    5681           0 :     long nLeft = 0;
    5682           0 :     long nRight = 0;
    5683             : 
    5684             :     // find top left point
    5685           0 :     long nTop = 0;
    5686           0 :     for(; nTop < nH; ++nTop )
    5687             :     {
    5688           0 :         for( nLeft = 0; nLeft < nW; ++nLeft )
    5689           0 :             if( pAcc->GetPixel( nTop, nLeft ) == aBlack )
    5690           0 :                 break;
    5691           0 :         if( nLeft < nW )
    5692           0 :             break;
    5693             :     }
    5694             : 
    5695             :     // find bottom right point
    5696           0 :     long nBottom = nH;
    5697           0 :     while( --nBottom >= nTop )
    5698             :     {
    5699           0 :         for( nRight = nW; --nRight >= 0; )
    5700           0 :             if( pAcc->GetPixel( nBottom, nRight ) == aBlack )
    5701           0 :                 break;
    5702           0 :         if( nRight >= 0 )
    5703           0 :             break;
    5704             :     }
    5705           0 :     if( nRight < nLeft )
    5706             :     {
    5707           0 :         long nX = nRight;
    5708           0 :         nRight = nLeft;
    5709           0 :         nLeft  = nX;
    5710             :     }
    5711             : 
    5712           0 :     for( long nY = nTop; nY <= nBottom; ++nY )
    5713             :     {
    5714             :         // find leftmost point
    5715             :         long nX;
    5716           0 :         for( nX = 0; nX < nLeft; ++nX )
    5717           0 :             if( pAcc->GetPixel( nY, nX ) == aBlack )
    5718           0 :                 break;
    5719           0 :         nLeft = nX;
    5720             : 
    5721             :         // find rightmost point
    5722           0 :         for( nX = nW; --nX > nRight; )
    5723           0 :             if( pAcc->GetPixel( nY, nX ) == aBlack )
    5724           0 :                 break;
    5725           0 :         nRight = nX;
    5726             :     }
    5727             : 
    5728           0 :     aBmp.ReleaseAccess( pAcc );
    5729             : 
    5730           0 :     if( nTop <= nBottom )
    5731             :     {
    5732           0 :         Size aSize( nRight - nLeft + 1, nBottom - nTop + 1 );
    5733           0 :         Point aTopLeft( nLeft, nTop );
    5734           0 :         aTopLeft -= aOffset;
    5735             :         // adjust to text alignment
    5736           0 :         aTopLeft.Y()+= mnTextOffY - (mpFontEntry->maMetric.mnAscent + mnEmphasisAscent);
    5737             :         // convert to logical coordinates
    5738           0 :         aSize = PixelToLogic( aSize );
    5739           0 :         aTopLeft.X() = ImplDevicePixelToLogicWidth( aTopLeft.X() );
    5740           0 :         aTopLeft.Y() = ImplDevicePixelToLogicHeight( aTopLeft.Y() );
    5741           0 :         rRect = Rectangle( aTopLeft, aSize );
    5742           0 :         return true;
    5743             :     }
    5744             : 
    5745           0 :     return false;
    5746             : }
    5747             : 
    5748           0 : bool OutputDevice::GetTextOutlines( ::basegfx::B2DPolyPolygonVector& rVector,
    5749             :                                         const OUString& rStr, sal_Int32 nBase,
    5750             :                                         sal_Int32 nIndex, sal_Int32 nLen,
    5751             :                                         bool bOptimize, sal_uLong nLayoutWidth, const sal_Int32* pDXArray ) const
    5752             : {
    5753           0 :     if(nLen == 0x0FFFF)
    5754             :     {
    5755             :         SAL_INFO("sal.rtl.xub",
    5756             :                  "GetTextOutlines Suspicious arguments nLen:" << nLen);
    5757             :     }
    5758             :     // the fonts need to be initialized
    5759           0 :     if( mbNewFont )
    5760           0 :         ImplNewFont();
    5761           0 :     if( mbInitFont )
    5762           0 :         ImplInitFont();
    5763           0 :     if( !mpFontEntry )
    5764           0 :         return false;
    5765             : 
    5766           0 :     bool bRet = false;
    5767           0 :     rVector.clear();
    5768           0 :     if( nLen < 0 )
    5769             :     {
    5770           0 :         nLen = rStr.getLength() - nIndex;
    5771             :     }
    5772           0 :     rVector.reserve( nLen );
    5773             : 
    5774             :     // we want to get the Rectangle in logical units, so to
    5775             :     // avoid rounding errors we just size the font in logical units
    5776           0 :     bool bOldMap = mbMap;
    5777           0 :     if( bOldMap )
    5778             :     {
    5779           0 :         const_cast<OutputDevice&>(*this).mbMap = false;
    5780           0 :         const_cast<OutputDevice&>(*this).mbNewFont = true;
    5781             :     }
    5782             : 
    5783           0 :     SalLayout* pSalLayout = NULL;
    5784             : 
    5785             :     // calculate offset when nBase!=nIndex
    5786           0 :     long nXOffset = 0;
    5787           0 :     if( nBase != nIndex )
    5788             :     {
    5789           0 :         sal_Int32 nStart = std::min( nBase, nIndex );
    5790           0 :         sal_Int32 nOfsLen = std::max( nBase, nIndex ) - nStart;
    5791           0 :         pSalLayout = ImplLayout( rStr, nStart, nOfsLen, Point(0,0), nLayoutWidth, pDXArray );
    5792           0 :         if( pSalLayout )
    5793             :         {
    5794           0 :             nXOffset = pSalLayout->GetTextWidth();
    5795           0 :             pSalLayout->Release();
    5796             :             // TODO: fix offset calculation for Bidi case
    5797           0 :             if( nBase > nIndex)
    5798           0 :                 nXOffset = -nXOffset;
    5799             :         }
    5800             :     }
    5801             : 
    5802           0 :     pSalLayout = ImplLayout( rStr, nIndex, nLen, Point(0,0), nLayoutWidth, pDXArray );
    5803           0 :     if( pSalLayout )
    5804             :     {
    5805           0 :         bRet = pSalLayout->GetOutline( *mpGraphics, rVector );
    5806           0 :         if( bRet )
    5807             :         {
    5808             :             // transform polygon to pixel units
    5809           0 :             ::basegfx::B2DHomMatrix aMatrix;
    5810             : 
    5811           0 :             int nWidthFactor = pSalLayout->GetUnitsPerPixel();
    5812           0 :             if( nXOffset | mnTextOffX | mnTextOffY )
    5813             :             {
    5814           0 :                 Point aRotatedOfs( mnTextOffX*nWidthFactor, mnTextOffY*nWidthFactor );
    5815           0 :                 aRotatedOfs -= pSalLayout->GetDrawPosition( Point( nXOffset, 0 ) );
    5816           0 :                 aMatrix.translate( aRotatedOfs.X(), aRotatedOfs.Y() );
    5817             :             }
    5818             : 
    5819           0 :             if( nWidthFactor > 1 )
    5820             :             {
    5821           0 :                 double fFactor = 1.0 / nWidthFactor;
    5822           0 :                 aMatrix.scale( fFactor, fFactor );
    5823             :             }
    5824             : 
    5825           0 :             if( !aMatrix.isIdentity() )
    5826             :             {
    5827           0 :                 ::basegfx::B2DPolyPolygonVector::iterator aIt = rVector.begin();
    5828           0 :                 for(; aIt != rVector.end(); ++aIt )
    5829           0 :                     (*aIt).transform( aMatrix );
    5830           0 :             }
    5831             :         }
    5832             : 
    5833           0 :         pSalLayout->Release();
    5834             :     }
    5835             : 
    5836           0 :     if( bOldMap )
    5837             :     {
    5838             :         // restore original font size and map mode
    5839           0 :         const_cast<OutputDevice&>(*this).mbMap = bOldMap;
    5840           0 :         const_cast<OutputDevice&>(*this).mbNewFont = true;
    5841             :     }
    5842             : 
    5843           0 :     if( bRet || (OUTDEV_PRINTER == meOutDevType) || !mpFontEntry )
    5844           0 :         return bRet;
    5845             : 
    5846             :     // fall back to bitmap conversion
    5847             :     // Here, we can savely assume that the mapping between characters and glyphs
    5848             :     // is one-to-one. This is most probably valid for the old bitmap fonts.
    5849             :     // fall back to bitmap method to get the bounding rectangle,
    5850             :     // so we need a monochrome virtual device with matching font
    5851           0 :     pSalLayout = ImplLayout( rStr, nIndex, nLen, Point(0,0), nLayoutWidth, pDXArray );
    5852           0 :     if (pSalLayout == 0)
    5853           0 :         return false;
    5854           0 :     long nOrgWidth = pSalLayout->GetTextWidth();
    5855           0 :     long nOrgHeight = mpFontEntry->mnLineHeight + mnEmphasisAscent
    5856           0 :         + mnEmphasisDescent;
    5857           0 :     pSalLayout->Release();
    5858             : 
    5859           0 :     VirtualDevice aVDev(1);
    5860             : 
    5861           0 :     Font aFont(GetFont());
    5862           0 :     aFont.SetShadow(false);
    5863           0 :     aFont.SetOutline(false);
    5864           0 :     aFont.SetRelief(RELIEF_NONE);
    5865           0 :     aFont.SetOrientation(0);
    5866           0 :     if( bOptimize )
    5867             :     {
    5868           0 :         aFont.SetSize( Size( 0, GLYPH_FONT_HEIGHT ) );
    5869           0 :         aVDev.SetMapMode( MAP_PIXEL );
    5870             :     }
    5871           0 :     aVDev.SetFont( aFont );
    5872           0 :     aVDev.SetTextAlign( ALIGN_TOP );
    5873           0 :     aVDev.SetTextColor( Color(COL_BLACK) );
    5874           0 :     aVDev.SetTextFillColor();
    5875             : 
    5876           0 :     pSalLayout = aVDev.ImplLayout( rStr, nIndex, nLen, Point(0,0), nLayoutWidth, pDXArray );
    5877           0 :     if (pSalLayout == 0)
    5878           0 :         return false;
    5879           0 :     long nWidth = pSalLayout->GetTextWidth();
    5880           0 :     long nHeight = ((OutputDevice*)&aVDev)->mpFontEntry->mnLineHeight + ((OutputDevice*)&aVDev)->mnEmphasisAscent
    5881           0 :         + ((OutputDevice*)&aVDev)->mnEmphasisDescent;
    5882           0 :     pSalLayout->Release();
    5883             : 
    5884           0 :     if( !nWidth || !nHeight )
    5885           0 :         return true;
    5886           0 :     double fScaleX = static_cast< double >(nOrgWidth) / nWidth;
    5887           0 :     double fScaleY = static_cast< double >(nOrgHeight) / nHeight;
    5888             : 
    5889             :     // calculate offset when nBase!=nIndex
    5890             :     // TODO: fix offset calculation for Bidi case
    5891           0 :     nXOffset = 0;
    5892           0 :     if( nBase != nIndex )
    5893             :     {
    5894           0 :         sal_Int32 nStart  = ((nBase < nIndex) ? nBase : nIndex);
    5895           0 :         sal_Int32 nLength = ((nBase > nIndex) ? nBase : nIndex) - nStart;
    5896           0 :         pSalLayout = aVDev.ImplLayout( rStr, nStart, nLength, Point(0,0), nLayoutWidth, pDXArray );
    5897           0 :         if( pSalLayout )
    5898             :         {
    5899           0 :             nXOffset = pSalLayout->GetTextWidth();
    5900           0 :             pSalLayout->Release();
    5901           0 :             if( nBase > nIndex)
    5902           0 :                 nXOffset = -nXOffset;
    5903             :         }
    5904             :     }
    5905             : 
    5906           0 :     bRet = true;
    5907           0 :     bool bRTL = false;
    5908           0 :     OUString aStr( rStr ); // prepare for e.g. localized digits
    5909           0 :     sal_Int32 nIndex2 = nIndex; // only needed until nIndex is sal_Int32
    5910           0 :     sal_Int32 nLen2 = nLen; // only needed until nLen is sal_Int32
    5911           0 :     ImplLayoutArgs aLayoutArgs = ImplPrepareLayoutArgs( aStr, nIndex2, nLen2, 0, NULL );
    5912           0 :     for( int nCharPos = -1; aLayoutArgs.GetNextPos( &nCharPos, &bRTL);)
    5913             :     {
    5914           0 :         bool bSuccess = false;
    5915             : 
    5916             :         // draw character into virtual device
    5917           0 :         pSalLayout = aVDev.ImplLayout( rStr, nCharPos, 1, Point(0,0), nLayoutWidth, pDXArray );
    5918           0 :         if (pSalLayout == 0)
    5919           0 :             return false;
    5920           0 :         long nCharWidth = pSalLayout->GetTextWidth();
    5921             : 
    5922           0 :         Point aOffset(nCharWidth / 2, 8);
    5923           0 :         Size aSize(nCharWidth + 2 * aOffset.X(), nHeight + 2 * aOffset.Y());
    5924           0 :         bSuccess = (bool)aVDev.SetOutputSizePixel(aSize);
    5925           0 :         if( bSuccess )
    5926             :         {
    5927             :             // draw glyph into virtual device
    5928           0 :             aVDev.Erase();
    5929           0 :             pSalLayout->DrawBase() += aOffset;
    5930           0 :             pSalLayout->DrawBase() += Point( ((OutputDevice*)&aVDev)->mnTextOffX, ((OutputDevice*)&aVDev)->mnTextOffY );
    5931           0 :             pSalLayout->DrawText( *((OutputDevice*)&aVDev)->mpGraphics );
    5932           0 :             pSalLayout->Release();
    5933             : 
    5934             :             // convert character image into outline
    5935           0 :             Bitmap aBmp( aVDev.GetBitmap(Point(0, 0), aSize));
    5936             : 
    5937           0 :             PolyPolygon aPolyPoly;
    5938           0 :             bool bVectorized = aBmp.Vectorize(aPolyPoly, BMP_VECTORIZE_OUTER | BMP_VECTORIZE_REDUCE_EDGES);
    5939           0 :             if( !bVectorized )
    5940           0 :                 bSuccess = false;
    5941             :             else
    5942             :             {
    5943             :                 // convert units to logical width
    5944           0 :                 for (sal_uInt16 j = 0; j < aPolyPoly.Count(); ++j)
    5945             :                 {
    5946           0 :                     Polygon& rPoly = aPolyPoly[j];
    5947           0 :                     for (sal_uInt16 k = 0; k < rPoly.GetSize(); ++k)
    5948             :                     {
    5949           0 :                         Point& rPt = rPoly[k];
    5950           0 :                         rPt -= aOffset;
    5951           0 :                         int nPixelX = rPt.X() - ((OutputDevice&)aVDev).mnTextOffX + nXOffset;
    5952           0 :                         int nPixelY = rPt.Y() - ((OutputDevice&)aVDev).mnTextOffY;
    5953           0 :                         rPt.X() = ImplDevicePixelToLogicWidth( nPixelX );
    5954           0 :                         rPt.Y() = ImplDevicePixelToLogicHeight( nPixelY );
    5955             :                     }
    5956             :                 }
    5957             : 
    5958             :                 // ignore "empty" glyphs:
    5959           0 :                 if( aPolyPoly.Count() > 0 )
    5960             :                 {
    5961             :                     // convert  to B2DPolyPolygon
    5962             :                     // TODO: get rid of intermediate tool's PolyPolygon
    5963           0 :                     ::basegfx::B2DPolyPolygon aB2DPolyPoly = aPolyPoly.getB2DPolyPolygon();
    5964           0 :                     ::basegfx::B2DHomMatrix aMatrix;
    5965           0 :                     aMatrix.scale( fScaleX, fScaleY );
    5966           0 :                     int nAngle = GetFont().GetOrientation();
    5967           0 :                     if( nAngle )
    5968           0 :                         aMatrix.rotate( nAngle * F_PI1800 );
    5969           0 :                     aB2DPolyPoly.transform( aMatrix );
    5970           0 :                     rVector.push_back( aB2DPolyPoly );
    5971             :                 }
    5972           0 :             }
    5973             :         }
    5974             : 
    5975           0 :         nXOffset += nCharWidth;
    5976           0 :         bRet = bRet && bSuccess;
    5977             :     }
    5978             : 
    5979           0 :     return bRet;
    5980             : }
    5981             : 
    5982           0 : bool OutputDevice::GetTextOutlines( PolyPolyVector& rResultVector,
    5983             :                                         const OUString& rStr, sal_Int32 nBase,
    5984             :                                         sal_Int32 nIndex, sal_Int32 nLen, bool bOptimize,
    5985             :                                         sal_uLong nTWidth, const sal_Int32* pDXArray ) const
    5986             : {
    5987           0 :     if(nLen == 0x0FFFF)
    5988             :     {
    5989             :         SAL_INFO("sal.rtl.xub",
    5990             :                  "GetTextOutlines Suspicious arguments  nLen:" << nLen);
    5991             :     }
    5992             : 
    5993           0 :     rResultVector.clear();
    5994             : 
    5995             :     // get the basegfx polypolygon vector
    5996           0 :     ::basegfx::B2DPolyPolygonVector aB2DPolyPolyVector;
    5997           0 :     if( !GetTextOutlines( aB2DPolyPolyVector, rStr, nBase, nIndex, nLen,
    5998           0 :                          bOptimize, nTWidth, pDXArray ) )
    5999           0 :         return false;
    6000             : 
    6001             :     // convert to a tool polypolygon vector
    6002           0 :     rResultVector.reserve( aB2DPolyPolyVector.size() );
    6003           0 :     ::basegfx::B2DPolyPolygonVector::const_iterator aIt = aB2DPolyPolyVector.begin();
    6004           0 :     for(; aIt != aB2DPolyPolyVector.end(); ++aIt )
    6005           0 :         rResultVector.push_back(PolyPolygon(*aIt)); // #i76339#
    6006             : 
    6007           0 :     return true;
    6008             : }
    6009             : 
    6010           0 : bool OutputDevice::GetTextOutline( PolyPolygon& rPolyPoly, const OUString& rStr,
    6011             :                                        sal_Int32 nBase, sal_Int32 nIndex, sal_Int32 nLen,
    6012             :                                        bool bOptimize, sal_uLong nTWidth, const sal_Int32* pDXArray ) const
    6013             : {
    6014           0 :     if(nLen == 0x0FFFF)
    6015             :     {
    6016             :         SAL_INFO("sal.rtl.xub",
    6017             :                  "GetTextOutline Suspicious arguments nLen:" << nLen);
    6018             :     }
    6019           0 :     rPolyPoly.Clear();
    6020             : 
    6021             :     // get the basegfx polypolygon vector
    6022           0 :     ::basegfx::B2DPolyPolygonVector aB2DPolyPolyVector;
    6023           0 :     if( !GetTextOutlines( aB2DPolyPolyVector, rStr, nBase, nIndex, nLen,
    6024           0 :                          bOptimize, nTWidth, pDXArray ) )
    6025           0 :         return false;
    6026             : 
    6027             :     // convert and merge into a tool polypolygon
    6028           0 :     ::basegfx::B2DPolyPolygonVector::const_iterator aIt = aB2DPolyPolyVector.begin();
    6029           0 :     for(; aIt != aB2DPolyPolyVector.end(); ++aIt )
    6030           0 :         for( unsigned int i = 0; i < aIt->count(); ++i )
    6031           0 :             rPolyPoly.Insert(Polygon((*aIt).getB2DPolygon( i ))); // #i76339#
    6032             : 
    6033           0 :     return true;
    6034             : }
    6035             : 
    6036           0 : bool OutputDevice::GetFontCapabilities( FontCapabilities& rFontCapabilities ) const
    6037             : {
    6038             :     // we need a graphics
    6039           0 :     if( !mpGraphics && !ImplGetGraphics() )
    6040           0 :         return false;
    6041             : 
    6042           0 :     if( mbNewFont )
    6043           0 :         ImplNewFont();
    6044           0 :     if( mbInitFont )
    6045           0 :         ImplInitFont();
    6046           0 :     if( !mpFontEntry )
    6047           0 :         return false;
    6048             : 
    6049           0 :     return mpGraphics->GetImplFontCapabilities(rFontCapabilities);
    6050             : }
    6051             : 
    6052           0 : bool OutputDevice::GetFontCharMap( FontCharMap& rFontCharMap ) const
    6053             : {
    6054           0 :     rFontCharMap.Reset();
    6055             : 
    6056             :     // we need a graphics
    6057           0 :     if( !mpGraphics && !ImplGetGraphics() )
    6058           0 :         return false;
    6059             : 
    6060           0 :     if( mbNewFont )
    6061           0 :         ImplNewFont();
    6062           0 :     if( mbInitFont )
    6063           0 :         ImplInitFont();
    6064           0 :     if( !mpFontEntry )
    6065           0 :         return false;
    6066             : 
    6067             : #ifdef ENABLE_IFC_CACHE // a little font charmap cache helps considerably
    6068             :     static const int NMAXITEMS = 16;
    6069             :     static int nUsedItems = 0, nCurItem = 0;
    6070             : 
    6071             :     struct CharMapCacheItem { const PhysicalFontFace* mpFontData; FontCharMap maCharMap; };
    6072             :     static CharMapCacheItem aCache[ NMAXITEMS ];
    6073             : 
    6074             :     const PhysicalFontFace* pFontData = mpFontEntry->maFontSelData.mpFontData;
    6075             : 
    6076             :     int i;
    6077             :     for( i = nUsedItems; --i >= 0; )
    6078             :         if( pFontData == aCache[i].mpFontData )
    6079             :             break;
    6080             :     if( i >= 0 ) // found in cache
    6081             :     {
    6082             :         rFontCharMap.Reset( aCache[i].maCharMap.mpImpl );
    6083             :     }
    6084             :     else // need to cache
    6085             : #endif // ENABLE_IFC_CACHE
    6086             :     {
    6087           0 :         const ImplFontCharMap* pNewMap = mpGraphics->GetImplFontCharMap();
    6088           0 :         rFontCharMap.Reset( pNewMap );
    6089             : 
    6090             : #ifdef ENABLE_IFC_CACHE
    6091             :         // manage cache round-robin and insert data
    6092             :         CharMapCacheItem& rItem = aCache[ nCurItem ];
    6093             :         rItem.mpFontData = pFontData;
    6094             :         rItem.maCharMap.Reset( pNewMap );
    6095             : 
    6096             :         if( ++nCurItem >= NMAXITEMS )
    6097             :             nCurItem = 0;
    6098             : 
    6099             :         if( ++nUsedItems >= NMAXITEMS )
    6100             :             nUsedItems = NMAXITEMS;
    6101             : #endif // ENABLE_IFC_CACHE
    6102             :     }
    6103             : 
    6104           0 :     if( rFontCharMap.IsDefaultMap() )
    6105           0 :         return false;
    6106           0 :     return true;
    6107             : }
    6108             : 
    6109           0 : sal_Int32 OutputDevice::HasGlyphs( const Font& rTempFont, const OUString& rStr,
    6110             :     sal_Int32 nIndex, sal_Int32 nLen ) const
    6111             : {
    6112           0 :     if( nIndex >= rStr.getLength() )
    6113           0 :         return nIndex;
    6114             :     sal_Int32 nEnd;
    6115           0 :     if( nLen == -1 )
    6116           0 :         nEnd = rStr.getLength();
    6117             :     else
    6118           0 :         nEnd = std::min( rStr.getLength(), nIndex + nLen );
    6119             : 
    6120             :     DBG_ASSERT( nIndex < nEnd, "StartPos >= EndPos?" );
    6121             :     DBG_ASSERT( nEnd <= rStr.getLength(), "String too short" );
    6122             : 
    6123             :     // to get the map temporarily set font
    6124           0 :     const Font aOrigFont = GetFont();
    6125           0 :     const_cast<OutputDevice&>(*this).SetFont( rTempFont );
    6126           0 :     FontCharMap aFontCharMap;
    6127           0 :     bool bRet = GetFontCharMap( aFontCharMap );
    6128           0 :     const_cast<OutputDevice&>(*this).SetFont( aOrigFont );
    6129             : 
    6130             :     // if fontmap is unknown assume it doesn't have the glyphs
    6131           0 :     if( !bRet )
    6132           0 :         return nIndex;
    6133             : 
    6134           0 :     for( sal_Int32 i = nIndex; nIndex < nEnd; ++i, ++nIndex )
    6135           0 :         if( ! aFontCharMap.HasChar( rStr[i] ) )
    6136           0 :             return nIndex;
    6137             : 
    6138           0 :     return -1;
    6139           3 : }
    6140             : 
    6141             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10