LCOV - code coverage report
Current view: top level - vcl/source/outdev - font.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 809 1070 75.6 %
Date: 2014-11-03 Functions: 54 69 78.3 %
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             : 
      22             : #include <vcl/virdev.hxx>
      23             : #include <vcl/print.hxx>
      24             : #include <vcl/outdev.hxx>
      25             : #include <vcl/edit.hxx>
      26             : #include <vcl/settings.hxx>
      27             : #include <vcl/sysdata.hxx>
      28             : 
      29             : #include "sallayout.hxx"
      30             : #include "svdata.hxx"
      31             : 
      32             : #include "impfont.hxx"
      33             : #include "outdata.hxx"
      34             : #include "outfont.hxx"
      35             : 
      36             : #include "outdev.h"
      37             : #include "window.h"
      38             : 
      39             : #include "PhysicalFontCollection.hxx"
      40             : #include "PhysicalFontFace.hxx"
      41             : #include "PhysicalFontFamily.hxx"
      42             : 
      43             : #include "svids.hrc"
      44             : 
      45             : #include <config_graphite.h>
      46             : #if ENABLE_GRAPHITE
      47             : #include "graphite_features.hxx"
      48             : #endif
      49             : 
      50             : #include "../gdi/pdfwriter_impl.hxx"
      51             : 
      52             : #include <cmath>
      53             : #include <cstring>
      54             : 
      55             : #include <memory>
      56             : #include <algorithm>
      57             : 
      58             : using namespace ::com::sun::star;
      59             : using namespace ::com::sun::star::uno;
      60             : using namespace ::rtl;
      61             : using namespace ::utl;
      62             : using namespace ::vcl;
      63             : 
      64     1674144 : vcl::FontInfo OutputDevice::GetDevFont( int nDevFontIndex ) const
      65             : {
      66     1674144 :     vcl::FontInfo aFontInfo;
      67             : 
      68     1674144 :     ImplInitFontList();
      69             : 
      70     1674144 :     int nCount = GetDevFontCount();
      71     1674144 :     if( nDevFontIndex < nCount )
      72             :     {
      73     1674144 :         const PhysicalFontFace& rData = *mpGetDevFontList->Get( nDevFontIndex );
      74     1674144 :         aFontInfo.SetName( rData.GetFamilyName() );
      75     1674144 :         aFontInfo.SetStyleName( rData.GetStyleName() );
      76     1674144 :         aFontInfo.SetCharSet( rData.IsSymbolFont() ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UNICODE );
      77     1674144 :         aFontInfo.SetFamily( rData.GetFamilyType() );
      78     1674144 :         aFontInfo.SetPitch( rData.GetPitch() );
      79     1674144 :         aFontInfo.SetWeight( rData.GetWeight() );
      80     1674144 :         aFontInfo.SetItalic( rData.GetSlant() );
      81     1674144 :         aFontInfo.SetWidthType( rData.GetWidthType() );
      82     1674144 :         if( rData.IsScalable() )
      83     1674144 :             aFontInfo.mpImplMetric->mnMiscFlags |= ImplFontMetric::SCALABLE_FLAG;
      84     1674144 :         if( rData.mbDevice )
      85           0 :             aFontInfo.mpImplMetric->mnMiscFlags |= ImplFontMetric::DEVICE_FLAG;
      86             :     }
      87             : 
      88     1674144 :     return aFontInfo;
      89             : }
      90             : 
      91     1686012 : int OutputDevice::GetDevFontCount() const
      92             : {
      93     1686012 :     if( !mpGetDevFontList )
      94        8012 :         mpGetDevFontList = mpFontCollection->GetDevFontList();
      95     1686012 :     return mpGetDevFontList->Count();
      96             : }
      97             : 
      98          70 : bool OutputDevice::IsFontAvailable( const OUString& rFontName ) const
      99             : {
     100          70 :     PhysicalFontFamily* pFound = mpFontCollection->FindFontFamily( rFontName );
     101          70 :     return (pFound != NULL);
     102             : }
     103             : 
     104        2058 : int OutputDevice::GetDevFontSizeCount( const vcl::Font& rFont ) const
     105             : {
     106        2058 :     delete mpGetDevSizeList;
     107             : 
     108        2058 :     ImplInitFontList();
     109        2058 :     mpGetDevSizeList = mpFontCollection->GetDevSizeList( rFont.GetName() );
     110        2058 :     return mpGetDevSizeList->Count();
     111             : }
     112             : 
     113           0 : Size OutputDevice::GetDevFontSize( const vcl::Font& rFont, int nSizeIndex ) const
     114             : {
     115             :     // check range
     116           0 :     int nCount = GetDevFontSizeCount( rFont );
     117           0 :     if ( nSizeIndex >= nCount )
     118           0 :         return Size();
     119             : 
     120             :     // when mapping is enabled round to .5 points
     121           0 :     Size aSize( 0, mpGetDevSizeList->Get( nSizeIndex ) );
     122           0 :     if ( mbMap )
     123             :     {
     124           0 :         aSize.Height() *= 10;
     125           0 :         MapMode aMap( MAP_10TH_INCH, Point(), Fraction( 1, 72 ), Fraction( 1, 72 ) );
     126           0 :         aSize = PixelToLogic( aSize, aMap );
     127           0 :         aSize.Height() += 5;
     128           0 :         aSize.Height() /= 10;
     129           0 :         long nRound = aSize.Height() % 5;
     130           0 :         if ( nRound >= 3 )
     131           0 :             aSize.Height() += (5-nRound);
     132             :         else
     133           0 :             aSize.Height() -= nRound;
     134           0 :         aSize.Height() *= 10;
     135           0 :         aSize = LogicToPixel( aSize, aMap );
     136           0 :         aSize = PixelToLogic( aSize );
     137           0 :         aSize.Height() += 5;
     138           0 :         aSize.Height() /= 10;
     139             :     }
     140           0 :     return aSize;
     141             : }
     142             : 
     143           0 : bool OutputDevice::AddTempDevFont( const OUString& rFileURL, const OUString& rFontName )
     144             : {
     145           0 :     ImplInitFontList();
     146             : 
     147           0 :     if( !mpGraphics && !AcquireGraphics() )
     148           0 :         return false;
     149             : 
     150           0 :     bool bRC = mpGraphics->AddTempDevFont( mpFontCollection, rFileURL, rFontName );
     151           0 :     if( !bRC )
     152           0 :         return false;
     153             : 
     154           0 :     if( mpAlphaVDev )
     155           0 :         mpAlphaVDev->AddTempDevFont( rFileURL, rFontName );
     156             : 
     157           0 :     mpFontCache->Invalidate();
     158           0 :     return true;
     159             : }
     160             : 
     161      563210 : FontMetric OutputDevice::GetFontMetric() const
     162             : {
     163      563210 :     FontMetric aMetric;
     164      563210 :     if( mbNewFont && !ImplNewFont() )
     165           0 :         return aMetric;
     166             : 
     167      563210 :     ImplFontEntry*      pEntry = mpFontEntry;
     168      563210 :     ImplFontMetricData* pMetric = &(pEntry->maMetric);
     169             : 
     170             :     // prepare metric
     171      563210 :     aMetric.Font::operator=( maFont );
     172             : 
     173             :     // set aMetric with info from font
     174      563210 :     aMetric.SetName( maFont.GetName() );
     175      563210 :     aMetric.SetStyleName( pMetric->GetStyleName() );
     176      563210 :     aMetric.SetSize( PixelToLogic( Size( pMetric->mnWidth, pMetric->mnAscent+pMetric->mnDescent-pMetric->mnIntLeading ) ) );
     177      563210 :     aMetric.SetCharSet( pMetric->IsSymbolFont() ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UNICODE );
     178      563210 :     aMetric.SetFamily( pMetric->GetFamilyType() );
     179      563210 :     aMetric.SetPitch( pMetric->GetPitch() );
     180      563210 :     aMetric.SetWeight( pMetric->GetWeight() );
     181      563210 :     aMetric.SetItalic( pMetric->GetSlant() );
     182      563210 :     aMetric.SetWidthType( pMetric->GetWidthType() );
     183      563210 :     if ( pEntry->mnOwnOrientation )
     184           0 :         aMetric.SetOrientation( pEntry->mnOwnOrientation );
     185             :     else
     186      563210 :         aMetric.SetOrientation( pMetric->mnOrientation );
     187      563210 :     if( !pEntry->maMetric.mbKernableFont )
     188       88849 :          aMetric.SetKerning( maFont.GetKerning() & ~KERNING_FONTSPECIFIC );
     189             : 
     190             :     // set remaining metric fields
     191      563210 :     aMetric.mpImplMetric->mnMiscFlags   = 0;
     192      563210 :     if( pMetric->mbDevice )
     193      554826 :             aMetric.mpImplMetric->mnMiscFlags |= ImplFontMetric::DEVICE_FLAG;
     194      563210 :     if( pMetric->mbScalableFont )
     195      563210 :             aMetric.mpImplMetric->mnMiscFlags |= ImplFontMetric::SCALABLE_FLAG;
     196      563210 :     aMetric.mpImplMetric->mnAscent      = ImplDevicePixelToLogicHeight( pMetric->mnAscent+mnEmphasisAscent );
     197      563210 :     aMetric.mpImplMetric->mnDescent     = ImplDevicePixelToLogicHeight( pMetric->mnDescent+mnEmphasisDescent );
     198      563210 :     aMetric.mpImplMetric->mnIntLeading  = ImplDevicePixelToLogicHeight( pMetric->mnIntLeading+mnEmphasisAscent );
     199      563210 :     aMetric.mpImplMetric->mnExtLeading  = ImplDevicePixelToLogicHeight( GetFontExtLeading() );
     200      563210 :     aMetric.mpImplMetric->mnExtLeading  = ImplDevicePixelToLogicHeight( pMetric->mnExtLeading );
     201      563210 :     aMetric.mpImplMetric->mnLineHeight  = ImplDevicePixelToLogicHeight( pMetric->mnAscent+pMetric->mnDescent+mnEmphasisAscent+mnEmphasisDescent );
     202      563210 :     aMetric.mpImplMetric->mnSlant       = ImplDevicePixelToLogicHeight( pMetric->mnSlant );
     203             : 
     204             :     SAL_INFO("vcl.gdi.fontmetric", "OutputDevice::GetFontMetric:" << aMetric);
     205             : 
     206      563210 :     return aMetric;
     207             : }
     208             : 
     209           0 : FontMetric OutputDevice::GetFontMetric( const vcl::Font& rFont ) const
     210             : {
     211             :     // select font, query metrics, select original font again
     212           0 :     Font aOldFont = GetFont();
     213           0 :     const_cast<OutputDevice*>(this)->SetFont( rFont );
     214           0 :     FontMetric aMetric( GetFontMetric() );
     215           0 :     const_cast<OutputDevice*>(this)->SetFont( aOldFont );
     216           0 :     return aMetric;
     217             : }
     218             : 
     219       13910 : bool OutputDevice::GetFontCharMap( FontCharMapPtr& rFontCharMap ) const
     220             : {
     221             :     // we need a graphics
     222       13910 :     if( !mpGraphics && !AcquireGraphics() )
     223           0 :         return false;
     224             : 
     225       13910 :     if( mbNewFont )
     226       12878 :         ImplNewFont();
     227       13910 :     if( mbInitFont )
     228        2038 :         InitFont();
     229       13910 :     if( !mpFontEntry )
     230           0 :         return false;
     231             : 
     232       13910 :     FontCharMapPtr pFontCharMap ( mpGraphics->GetFontCharMap() );
     233       13910 :     if (!pFontCharMap)
     234             :     {
     235           0 :         FontCharMapPtr pDefaultMap( new FontCharMap() );
     236           0 :         rFontCharMap = pDefaultMap;
     237             :     }
     238             :     else
     239       13910 :         rFontCharMap = pFontCharMap;
     240             : 
     241       13910 :     if( rFontCharMap->IsDefaultMap() )
     242           0 :         return false;
     243       13910 :     return true;
     244             : }
     245             : 
     246        1712 : bool OutputDevice::GetFontCapabilities( FontCapabilities& rFontCapabilities ) const
     247             : {
     248             :     // we need a graphics
     249        1712 :     if( !mpGraphics && !AcquireGraphics() )
     250           0 :         return false;
     251             : 
     252        1712 :     if( mbNewFont )
     253           0 :         ImplNewFont();
     254        1712 :     if( mbInitFont )
     255           0 :         InitFont();
     256        1712 :     if( !mpFontEntry )
     257           0 :         return false;
     258             : 
     259        1712 :     return mpGraphics->GetFontCapabilities(rFontCapabilities);
     260             : }
     261             : 
     262           0 : SystemFontData OutputDevice::GetSysFontData(int nFallbacklevel) const
     263             : {
     264           0 :     SystemFontData aSysFontData;
     265           0 :     aSysFontData.nSize = sizeof(aSysFontData);
     266             : 
     267           0 :     if (!mpGraphics)
     268           0 :         (void) AcquireGraphics();
     269             : 
     270           0 :     if (mpGraphics)
     271           0 :         aSysFontData = mpGraphics->GetSysFontData(nFallbacklevel);
     272             : 
     273           0 :     return aSysFontData;
     274             : }
     275             : 
     276       10674 : void OutputDevice::ImplGetEmphasisMark( tools::PolyPolygon& rPolyPoly, bool& rPolyLine,
     277             :                                         Rectangle& rRect1, Rectangle& rRect2,
     278             :                                         long& rYOff, long& rWidth,
     279             :                                         FontEmphasisMark eEmphasis,
     280             :                                         long nHeight, short /*nOrient*/ )
     281             : {
     282             :     static const sal_uInt8 aAccentPolyFlags[24] =
     283             :     {
     284             :         0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 0, 2, 0, 2, 2
     285             :     };
     286             : 
     287             :     static const long aAccentPos[48] =
     288             :     {
     289             :          78,      0,
     290             :         348,     79,
     291             :         599,    235,
     292             :         843,    469,
     293             :         938,    574,
     294             :         990,    669,
     295             :         990,    773,
     296             :         990,    843,
     297             :         964,    895,
     298             :         921,    947,
     299             :         886,    982,
     300             :         860,    999,
     301             :         825,    999,
     302             :         764,    999,
     303             :         721,    964,
     304             :         686,    895,
     305             :         625,    791,
     306             :         556,    660,
     307             :         469,    504,
     308             :         400,    400,
     309             :         261,    252,
     310             :          61,     61,
     311             :           0,     27,
     312             :           9,      0
     313             :     };
     314             : 
     315       10674 :     rWidth      = 0;
     316       10674 :     rYOff       = 0;
     317       10674 :     rPolyLine   = false;
     318             : 
     319       10674 :     if ( !nHeight )
     320       10674 :         return;
     321             : 
     322       10674 :     FontEmphasisMark    nEmphasisStyle = eEmphasis & EMPHASISMARK_STYLE;
     323       10674 :     long                nDotSize = 0;
     324       10674 :     switch ( nEmphasisStyle )
     325             :     {
     326             :         case EMPHASISMARK_DOT:
     327             :             // Dot has 55% of the height
     328        2370 :             nDotSize = (nHeight*550)/1000;
     329        2370 :             if ( !nDotSize )
     330         268 :                 nDotSize = 1;
     331        2370 :             if ( nDotSize <= 2 )
     332        1274 :                 rRect1 = Rectangle( Point(), Size( nDotSize, nDotSize ) );
     333             :             else
     334             :             {
     335        1096 :                 long nRad = nDotSize/2;
     336        1096 :                 Polygon aPoly( Point( nRad, nRad ), nRad, nRad );
     337        1096 :                 rPolyPoly.Insert( aPoly );
     338             :             }
     339        2370 :             rYOff = ((nHeight*250)/1000)/2; // Center to the another EmphasisMarks
     340        2370 :             rWidth = nDotSize;
     341        2370 :             break;
     342             : 
     343             :         case EMPHASISMARK_CIRCLE:
     344             :             // Dot has 80% of the height
     345        3822 :             nDotSize = (nHeight*800)/1000;
     346        3822 :             if ( !nDotSize )
     347         224 :                 nDotSize = 1;
     348        3822 :             if ( nDotSize <= 2 )
     349         542 :                 rRect1 = Rectangle( Point(), Size( nDotSize, nDotSize ) );
     350             :             else
     351             :             {
     352        3280 :                 long nRad = nDotSize/2;
     353        3280 :                 Polygon aPoly( Point( nRad, nRad ), nRad, nRad );
     354        3280 :                 rPolyPoly.Insert( aPoly );
     355             :                 // BorderWidth is 15%
     356        3280 :                 long nBorder = (nDotSize*150)/1000;
     357        3280 :                 if ( nBorder <= 1 )
     358        2816 :                     rPolyLine = true;
     359             :                 else
     360             :                 {
     361             :                     Polygon aPoly2( Point( nRad, nRad ),
     362         464 :                                     nRad-nBorder, nRad-nBorder );
     363         464 :                     rPolyPoly.Insert( aPoly2 );
     364        3280 :                 }
     365             :             }
     366        3822 :             rWidth = nDotSize;
     367        3822 :             break;
     368             : 
     369             :         case EMPHASISMARK_DISC:
     370             :             // Dot has 80% of the height
     371        3834 :             nDotSize = (nHeight*800)/1000;
     372        3834 :             if ( !nDotSize )
     373           0 :                 nDotSize = 1;
     374        3834 :             if ( nDotSize <= 2 )
     375           0 :                 rRect1 = Rectangle( Point(), Size( nDotSize, nDotSize ) );
     376             :             else
     377             :             {
     378        3834 :                 long nRad = nDotSize/2;
     379        3834 :                 Polygon aPoly( Point( nRad, nRad ), nRad, nRad );
     380        3834 :                 rPolyPoly.Insert( aPoly );
     381             :             }
     382        3834 :             rWidth = nDotSize;
     383        3834 :             break;
     384             : 
     385             :         case EMPHASISMARK_ACCENT:
     386             :             // Dot has 80% of the height
     387         648 :             nDotSize = (nHeight*800)/1000;
     388         648 :             if ( !nDotSize )
     389           0 :                 nDotSize = 1;
     390         648 :             if ( nDotSize <= 2 )
     391             :             {
     392           0 :                 if ( nDotSize == 1 )
     393             :                 {
     394           0 :                     rRect1 = Rectangle( Point(), Size( nDotSize, nDotSize ) );
     395           0 :                     rWidth = nDotSize;
     396             :                 }
     397             :                 else
     398             :                 {
     399           0 :                     rRect1 = Rectangle( Point(), Size( 1, 1 ) );
     400           0 :                     rRect2 = Rectangle( Point( 1, 1 ), Size( 1, 1 ) );
     401             :                 }
     402             :             }
     403             :             else
     404             :             {
     405         648 :                 Polygon aPoly( sizeof( aAccentPos ) / sizeof( long ) / 2,
     406             :                                (const Point*)aAccentPos,
     407         648 :                                aAccentPolyFlags );
     408         648 :                 double dScale = ((double)nDotSize)/1000.0;
     409         648 :                 aPoly.Scale( dScale, dScale );
     410        1296 :                 Polygon aTemp;
     411         648 :                 aPoly.AdaptiveSubdivide( aTemp );
     412         648 :                 Rectangle aBoundRect = aTemp.GetBoundRect();
     413         648 :                 rWidth = aBoundRect.GetWidth();
     414         648 :                 nDotSize = aBoundRect.GetHeight();
     415        1296 :                 rPolyPoly.Insert( aTemp );
     416             :             }
     417         648 :             break;
     418             :     }
     419             : 
     420             :     // calculate position
     421       10674 :     long nOffY = 1+(mnDPIY/300); // one visible pixel space
     422       10674 :     long nSpaceY = nHeight-nDotSize;
     423       10674 :     if ( nSpaceY >= nOffY*2 )
     424        8672 :         rYOff += nOffY;
     425       10674 :     if ( !(eEmphasis & EMPHASISMARK_POS_BELOW) )
     426       10674 :         rYOff += nDotSize;
     427             : }
     428             : 
     429       66327 : FontEmphasisMark OutputDevice::ImplGetEmphasisMarkStyle( const vcl::Font& rFont )
     430             : {
     431       66327 :     FontEmphasisMark nEmphasisMark = rFont.GetEmphasisMark();
     432             : 
     433             :     // If no Position is set, then calculate the default position, which
     434             :     // depends on the language
     435       66327 :     if ( !(nEmphasisMark & (EMPHASISMARK_POS_ABOVE | EMPHASISMARK_POS_BELOW)) )
     436             :     {
     437       10252 :         LanguageType eLang = rFont.GetLanguage();
     438             :         // In Chinese Simplified the EmphasisMarks are below/left
     439       10252 :         if (MsLangId::isSimplifiedChinese(eLang))
     440           0 :             nEmphasisMark |= EMPHASISMARK_POS_BELOW;
     441             :         else
     442             :         {
     443       10252 :             eLang = rFont.GetCJKContextLanguage();
     444             :             // In Chinese Simplified the EmphasisMarks are below/left
     445       10252 :             if (MsLangId::isSimplifiedChinese(eLang))
     446           0 :                 nEmphasisMark |= EMPHASISMARK_POS_BELOW;
     447             :             else
     448       10252 :                 nEmphasisMark |= EMPHASISMARK_POS_ABOVE;
     449             :         }
     450             :     }
     451             : 
     452       66327 :     return nEmphasisMark;
     453             : }
     454             : 
     455       31504 : long OutputDevice::GetFontExtLeading() const
     456             : {
     457       31504 :     ImplFontEntry*      pEntry = mpFontEntry;
     458       31504 :     ImplFontMetricData* pMetric = &(pEntry->maMetric);
     459             : 
     460       31504 :     return pMetric->mnExtLeading;
     461             : }
     462             : 
     463         100 : void OutputDevice::ImplClearFontData( const bool bNewFontLists )
     464             : {
     465             :     // the currently selected logical font is no longer needed
     466         100 :     if ( mpFontEntry )
     467             :     {
     468           0 :         mpFontCache->Release( mpFontEntry );
     469           0 :         mpFontEntry = NULL;
     470             :     }
     471             : 
     472         100 :     mbInitFont = true;
     473         100 :     mbNewFont = true;
     474             : 
     475         100 :     if ( bNewFontLists )
     476             :     {
     477         100 :         if ( mpGetDevFontList )
     478             :         {
     479           0 :             delete mpGetDevFontList;
     480           0 :             mpGetDevFontList = NULL;
     481             :         }
     482         100 :         if ( mpGetDevSizeList )
     483             :         {
     484           0 :             delete mpGetDevSizeList;
     485           0 :             mpGetDevSizeList = NULL;
     486             :         }
     487             : 
     488             :         // release all physically selected fonts on this device
     489         100 :         if( AcquireGraphics() )
     490         100 :             mpGraphics->ReleaseFonts();
     491             :     }
     492             : 
     493             : //    if ( GetOutDevType() == OUTDEV_PRINTER || mpPDFWriter )
     494             :     {
     495         100 :         ImplSVData* pSVData = ImplGetSVData();
     496             : 
     497         100 :         if( mpFontCache && mpFontCache != pSVData->maGDIData.mpScreenFontCache )
     498         100 :             mpFontCache->Invalidate();
     499             : 
     500         100 :         if ( bNewFontLists )
     501             :         {
     502             :             // we need a graphics
     503         100 :             if ( AcquireGraphics() )
     504             :             {
     505         100 :                 if( mpFontCollection && mpFontCollection != pSVData->maGDIData.mpScreenFontList )
     506         100 :                     mpFontCollection->Clear();
     507             : 
     508         100 :                 if( mpPDFWriter )
     509             :                 {
     510           0 :                     if( mpFontCollection && mpFontCollection != pSVData->maGDIData.mpScreenFontList )
     511           0 :                         delete mpFontCollection;
     512           0 :                     if( mpFontCache && mpFontCache != pSVData->maGDIData.mpScreenFontCache )
     513           0 :                         delete mpFontCache;
     514           0 :                     mpFontCollection = 0;
     515           0 :                     mpFontCache = 0;
     516             :                 }
     517             :             }
     518             :         }
     519             :     }
     520             : 
     521             :     // also update child windows if needed
     522         100 :     if ( GetOutDevType() == OUTDEV_WINDOW )
     523             :     {
     524           0 :         vcl::Window* pChild = static_cast<vcl::Window*>(this)->mpWindowImpl->mpFirstChild;
     525           0 :         while ( pChild )
     526             :         {
     527           0 :             pChild->ImplClearFontData( true );
     528           0 :             pChild = pChild->mpWindowImpl->mpNext;
     529             :         }
     530             :     }
     531         100 : }
     532             : 
     533         100 : void OutputDevice::ImplRefreshFontData( const bool bNewFontLists )
     534             : {
     535             : //    if ( GetOutDevType() == OUTDEV_PRINTER || mpPDFWriter )
     536             :     {
     537         100 :         ImplSVData* pSVData = ImplGetSVData();
     538             : 
     539         100 :         if ( bNewFontLists )
     540             :         {
     541             :             // we need a graphics
     542         100 :             if ( AcquireGraphics() )
     543             :             {
     544         100 :                 if( mpPDFWriter )
     545             :                 {
     546           0 :                     mpFontCollection = pSVData->maGDIData.mpScreenFontList->Clone( true, true );
     547           0 :                     mpFontCache = new ImplFontCache();
     548             :                 }
     549             :                 else
     550             :                 {
     551         100 :                     mpGraphics->GetDevFontList( mpFontCollection );
     552             :                 }
     553             :             }
     554             :         }
     555             :     }
     556             : 
     557             :     // also update child windows if needed
     558         100 :     if ( GetOutDevType() == OUTDEV_WINDOW )
     559             :     {
     560           0 :         vcl::Window* pChild = static_cast<vcl::Window*>(this)->mpWindowImpl->mpFirstChild;
     561           0 :         while ( pChild )
     562             :         {
     563           0 :             pChild->ImplRefreshFontData( true );
     564           0 :             pChild = pChild->mpWindowImpl->mpNext;
     565             :         }
     566             :     }
     567         100 : }
     568             : 
     569         100 : void OutputDevice::ImplUpdateFontData( bool bNewFontLists )
     570             : {
     571         100 :     ImplClearFontData( bNewFontLists );
     572         100 :     ImplRefreshFontData( bNewFontLists );
     573         100 : }
     574             : 
     575           0 : void OutputDevice::ImplUpdateAllFontData( bool bNewFontLists )
     576             : {
     577           0 :     ImplSVData* pSVData = ImplGetSVData();
     578             : 
     579           0 :     ImplUpdateFontDataForAllFrames( &OutputDevice::ImplClearFontData, bNewFontLists );
     580             : 
     581             :     // clear global font lists to have them updated
     582           0 :     pSVData->maGDIData.mpScreenFontCache->Invalidate();
     583           0 :     if ( bNewFontLists )
     584             :     {
     585           0 :         pSVData->maGDIData.mpScreenFontList->Clear();
     586           0 :         vcl::Window * pFrame = pSVData->maWinData.mpFirstFrame;
     587           0 :         if ( pFrame )
     588             :         {
     589           0 :             if ( pFrame->AcquireGraphics() )
     590             :             {
     591             :                 // Stupid typecast here and somewhere ((OutputDevice*)&aVDev)->, because bug in .NET2002 compiler
     592           0 :                 OutputDevice *pDevice = (OutputDevice*)pFrame;
     593           0 :                 pDevice->mpGraphics->ClearDevFontCache();
     594           0 :                 pDevice->mpGraphics->GetDevFontList(pFrame->mpWindowImpl->mpFrameData->mpFontCollection);
     595             :             }
     596             :         }
     597             :     }
     598             : 
     599           0 :     ImplUpdateFontDataForAllFrames( &OutputDevice::ImplRefreshFontData, bNewFontLists );
     600           0 : }
     601             : 
     602           0 : void OutputDevice::ImplUpdateFontDataForAllFrames( const FontUpdateHandler_t pHdl, const bool bNewFontLists )
     603             : {
     604           0 :     ImplSVData* const pSVData = ImplGetSVData();
     605             : 
     606             :     // update all windows
     607           0 :     vcl::Window* pFrame = pSVData->maWinData.mpFirstFrame;
     608           0 :     while ( pFrame )
     609             :     {
     610           0 :         ( pFrame->*pHdl )( bNewFontLists );
     611             : 
     612           0 :         vcl::Window* pSysWin = pFrame->mpWindowImpl->mpFrameData->mpFirstOverlap;
     613           0 :         while ( pSysWin )
     614             :         {
     615           0 :             ( pSysWin->*pHdl )( bNewFontLists );
     616           0 :             pSysWin = pSysWin->mpWindowImpl->mpNextOverlap;
     617             :         }
     618             : 
     619           0 :         pFrame = pFrame->mpWindowImpl->mpFrameData->mpNextFrame;
     620             :     }
     621             : 
     622             :     // update all virtual devices
     623           0 :     VirtualDevice* pVirDev = pSVData->maGDIData.mpFirstVirDev;
     624           0 :     while ( pVirDev )
     625             :     {
     626           0 :         ( pVirDev->*pHdl )( bNewFontLists );
     627           0 :         pVirDev = pVirDev->mpNext;
     628             :     }
     629             : 
     630             :     // update all printers
     631           0 :     Printer* pPrinter = pSVData->maGDIData.mpFirstPrinter;
     632           0 :     while ( pPrinter )
     633             :     {
     634           0 :         ( pPrinter->*pHdl )( bNewFontLists );
     635           0 :         pPrinter = pPrinter->mpNext;
     636             :     }
     637           0 : }
     638             : 
     639         160 : void OutputDevice::BeginFontSubstitution()
     640             : {
     641         160 :     ImplSVData* pSVData = ImplGetSVData();
     642         160 :     pSVData->maGDIData.mbFontSubChanged = false;
     643         160 : }
     644             : 
     645         160 : void OutputDevice::EndFontSubstitution()
     646             : {
     647         160 :     ImplSVData* pSVData = ImplGetSVData();
     648         160 :     if ( pSVData->maGDIData.mbFontSubChanged )
     649             :     {
     650           0 :         ImplUpdateAllFontData( false );
     651             : 
     652           0 :         Application* pApp = GetpApp();
     653           0 :         DataChangedEvent aDCEvt( DATACHANGED_FONTSUBSTITUTION );
     654           0 :         pApp->DataChanged( aDCEvt );
     655           0 :         Application::NotifyAllWindows( aDCEvt );
     656           0 :         pSVData->maGDIData.mbFontSubChanged = false;
     657             :     }
     658         160 : }
     659             : 
     660           0 : void OutputDevice::AddFontSubstitute( const OUString& rFontName,
     661             :                                       const OUString& rReplaceFontName,
     662             :                                       sal_uInt16 nFlags )
     663             : {
     664           0 :     ImplDirectFontSubstitution*& rpSubst = ImplGetSVData()->maGDIData.mpDirectFontSubst;
     665           0 :     if( !rpSubst )
     666           0 :         rpSubst = new ImplDirectFontSubstitution();
     667           0 :     rpSubst->AddFontSubstitute( rFontName, rReplaceFontName, nFlags );
     668           0 :     ImplGetSVData()->maGDIData.mbFontSubChanged = true;
     669           0 : }
     670             : 
     671           0 : void ImplDirectFontSubstitution::AddFontSubstitute( const OUString& rFontName,
     672             :     const OUString& rSubstFontName, sal_uInt16 nFlags )
     673             : {
     674           0 :     maFontSubstList.push_back( ImplFontSubstEntry( rFontName, rSubstFontName, nFlags ) );
     675           0 : }
     676             : 
     677           0 : ImplFontSubstEntry::ImplFontSubstEntry( const OUString& rFontName,
     678             :     const OUString& rSubstFontName, sal_uInt16 nSubstFlags )
     679             : :   maName( rFontName )
     680             : ,   maReplaceName( rSubstFontName )
     681           0 : ,   mnFlags( nSubstFlags )
     682             : {
     683           0 :     maSearchName = GetEnglishSearchFontName( rFontName );
     684           0 :     maSearchReplaceName = GetEnglishSearchFontName( rSubstFontName );
     685           0 : }
     686             : 
     687           0 : void OutputDevice::RemoveFontSubstitute( sal_uInt16 n )
     688             : {
     689           0 :     ImplDirectFontSubstitution* pSubst = ImplGetSVData()->maGDIData.mpDirectFontSubst;
     690           0 :     if( pSubst )
     691           0 :         pSubst->RemoveFontSubstitute( n );
     692           0 : }
     693             : 
     694           0 : void ImplDirectFontSubstitution::RemoveFontSubstitute( int nIndex )
     695             : {
     696           0 :     FontSubstList::iterator it = maFontSubstList.begin();
     697           0 :     for( int nCount = 0; (it != maFontSubstList.end()) && (nCount++ != nIndex); ++it ) ;
     698           0 :     if( it != maFontSubstList.end() )
     699           0 :         maFontSubstList.erase( it );
     700           0 : }
     701             : 
     702         160 : sal_uInt16 OutputDevice::GetFontSubstituteCount()
     703             : {
     704         160 :     const ImplDirectFontSubstitution* pSubst = ImplGetSVData()->maGDIData.mpDirectFontSubst;
     705         160 :     if( !pSubst )
     706         160 :         return 0;
     707           0 :     int nCount =  pSubst->GetFontSubstituteCount();
     708           0 :     return (sal_uInt16)nCount;
     709             : }
     710             : 
     711           0 : bool ImplDirectFontSubstitution::FindFontSubstitute( OUString& rSubstName,
     712             :     const OUString& rSearchName, sal_uInt16 nFlags ) const
     713             : {
     714             :     // TODO: get rid of O(N) searches
     715           0 :     FontSubstList::const_iterator it = maFontSubstList.begin();
     716           0 :     for(; it != maFontSubstList.end(); ++it )
     717             :     {
     718           0 :         const ImplFontSubstEntry& rEntry = *it;
     719           0 :         if( ((rEntry.mnFlags & nFlags) || !nFlags)
     720           0 :         &&   (rEntry.maSearchName == rSearchName) )
     721             :         {
     722           0 :             rSubstName = rEntry.maSearchReplaceName;
     723           0 :             return true;
     724             :         }
     725             :     }
     726             : 
     727           0 :     return false;
     728             : }
     729             : 
     730       24584 : void ImplFontSubstitute( OUString& rFontName )
     731             : {
     732             :     // must be canonicalised
     733             :     assert( GetEnglishSearchFontName( rFontName ) == rFontName );
     734             : 
     735       24584 :     OUString aSubstFontName;
     736             : 
     737             :     // apply user-configurable font replacement (eg, from the list in Tools->Options)
     738       24584 :     const ImplDirectFontSubstitution* pSubst = ImplGetSVData()->maGDIData.mpDirectFontSubst;
     739       24584 :     if( pSubst && pSubst->FindFontSubstitute( aSubstFontName, rFontName, FONT_SUBSTITUTE_ALWAYS ) )
     740             :     {
     741           0 :         rFontName = aSubstFontName;
     742       24584 :         return;
     743       24584 :     }
     744             : }
     745             : 
     746             : //hidpi TODO: This routine has hard-coded font-sizes that break places such as DialControl
     747      298690 : Font OutputDevice::GetDefaultFont( sal_uInt16 nType, LanguageType eLang,
     748             :                                    sal_uLong nFlags, const OutputDevice* pOutDev )
     749             : {
     750      298690 :     if (!pOutDev) // default is NULL
     751      298690 :         pOutDev = Application::GetDefaultDevice();
     752             : 
     753             :     LanguageTag aLanguageTag(
     754      298658 :             ( eLang == LANGUAGE_NONE || eLang == LANGUAGE_SYSTEM || eLang == LANGUAGE_DONTKNOW ) ?
     755        1352 :             Application::GetSettings().GetUILanguageTag() :
     756      300042 :             LanguageTag( eLang ));
     757             : 
     758      298690 :     utl::DefaultFontConfiguration& rDefaults = utl::DefaultFontConfiguration::get();
     759      597380 :     OUString aDefault = rDefaults.getDefaultFont( aLanguageTag, nType );
     760      597380 :     OUString aSearch;
     761             : 
     762      298690 :     if( !aDefault.isEmpty() )
     763      288472 :         aSearch = aDefault;
     764             :     else
     765       10218 :         aSearch = rDefaults.getUserInterfaceFont( aLanguageTag ); // use the UI font as a fallback
     766             : 
     767      298690 :     Font aFont;
     768      298690 :     aFont.SetPitch( PITCH_VARIABLE );
     769             : 
     770      298690 :     switch ( nType )
     771             :     {
     772             :         case DEFAULTFONT_SANS_UNICODE:
     773             :         case DEFAULTFONT_UI_SANS:
     774           0 :             aFont.SetFamily( FAMILY_SWISS );
     775           0 :             break;
     776             : 
     777             :         case DEFAULTFONT_SANS:
     778             :         case DEFAULTFONT_LATIN_HEADING:
     779             :         case DEFAULTFONT_LATIN_SPREADSHEET:
     780             :         case DEFAULTFONT_LATIN_DISPLAY:
     781       13210 :             aFont.SetFamily( FAMILY_SWISS );
     782       13210 :             break;
     783             : 
     784             :         case DEFAULTFONT_SERIF:
     785             :         case DEFAULTFONT_LATIN_TEXT:
     786             :         case DEFAULTFONT_LATIN_PRESENTATION:
     787       87686 :             aFont.SetFamily( FAMILY_ROMAN );
     788       87686 :             break;
     789             : 
     790             :         case DEFAULTFONT_FIXED:
     791             :         case DEFAULTFONT_LATIN_FIXED:
     792             :         case DEFAULTFONT_UI_FIXED:
     793        1188 :             aFont.SetPitch( PITCH_FIXED );
     794        1188 :             aFont.SetFamily( FAMILY_MODERN );
     795        1188 :             break;
     796             : 
     797             :         case DEFAULTFONT_SYMBOL:
     798           0 :             aFont.SetCharSet( RTL_TEXTENCODING_SYMBOL );
     799           0 :             break;
     800             : 
     801             :         case DEFAULTFONT_CJK_TEXT:
     802             :         case DEFAULTFONT_CJK_PRESENTATION:
     803             :         case DEFAULTFONT_CJK_SPREADSHEET:
     804             :         case DEFAULTFONT_CJK_HEADING:
     805             :         case DEFAULTFONT_CJK_DISPLAY:
     806       98302 :             aFont.SetFamily( FAMILY_SYSTEM ); // don't care, but don't use font subst config later...
     807       98302 :             break;
     808             : 
     809             :         case DEFAULTFONT_CTL_TEXT:
     810             :         case DEFAULTFONT_CTL_PRESENTATION:
     811             :         case DEFAULTFONT_CTL_SPREADSHEET:
     812             :         case DEFAULTFONT_CTL_HEADING:
     813             :         case DEFAULTFONT_CTL_DISPLAY:
     814       98304 :             aFont.SetFamily( FAMILY_SYSTEM ); // don't care, but don't use font subst config later...
     815       98304 :             break;
     816             :     }
     817             : 
     818      298690 :     if ( !aSearch.isEmpty() )
     819             :     {
     820      298690 :         aFont.SetHeight( 12 ); // corresponds to nDefaultHeight
     821      298690 :         aFont.SetWeight( WEIGHT_NORMAL );
     822      298690 :         aFont.SetLanguage( eLang );
     823             : 
     824      298690 :         if ( aFont.GetCharSet() == RTL_TEXTENCODING_DONTKNOW )
     825      298690 :             aFont.SetCharSet( osl_getThreadTextEncoding() );
     826             : 
     827             :         // Should we only return available fonts on the given device
     828      298690 :         if ( pOutDev )
     829             :         {
     830      298690 :             pOutDev->ImplInitFontList();
     831             : 
     832             :             // Search Font in the FontList
     833      298690 :             OUString      aName;
     834      597380 :             OUString      aSearchName;
     835      298690 :             sal_Int32     nIndex = 0;
     836     2006652 :             do
     837             :             {
     838     2117976 :                 aSearchName = GetEnglishSearchFontName( GetNextFontToken( aSearch, nIndex ) );
     839             : 
     840     2117976 :                 PhysicalFontFamily* pFontFamily = pOutDev->mpFontCollection->ImplFindBySearchName( aSearchName );
     841     2117976 :                 if( pFontFamily )
     842             :                 {
     843      114258 :                     AddTokenFontName( aName, pFontFamily->GetFamilyName() );
     844      114258 :                     if( nFlags & DEFAULTFONT_FLAGS_ONLYONE )
     845      111324 :                         break;
     846             :                 }
     847             :             }
     848     2006652 :             while ( nIndex != -1 );
     849      597380 :             aFont.SetName( aName );
     850             :         }
     851             : 
     852             :         // No Name, than set all names
     853      298690 :         if ( aFont.GetName().isEmpty() )
     854             :         {
     855      186388 :             if ( nFlags & DEFAULTFONT_FLAGS_ONLYONE )
     856             :             {
     857      186388 :                 if( !pOutDev )
     858             :                 {
     859             :                     SAL_WARN ("vcl.gdi", "No default window has been set for the application - we really shouldn't be able to get here");
     860           0 :                     sal_Int32 nIndex = 0;
     861           0 :                     aFont.SetName( aSearch.getToken( 0, ';', nIndex ) );
     862             :                 }
     863             :                 else
     864             :                 {
     865      186388 :                     pOutDev->ImplInitFontList();
     866             : 
     867      186388 :                     aFont.SetName( aSearch );
     868             : 
     869             :                     // convert to pixel height
     870      186388 :                     Size aSize = pOutDev->ImplLogicToDevicePixel( aFont.GetSize() );
     871      186388 :                     if ( !aSize.Height() )
     872             :                     {
     873             :                         // use default pixel height only when logical height is zero
     874           0 :                         if ( aFont.GetHeight() )
     875           0 :                             aSize.Height() = 1;
     876             :                         else
     877           0 :                             aSize.Height() = (12*pOutDev->mnDPIY)/72;
     878             :                     }
     879             : 
     880             :                     // use default width only when logical width is zero
     881      186388 :                     if( (0 == aSize.Width()) && (0 != aFont.GetSize().Width()) )
     882           0 :                         aSize.Width() = 1;
     883             : 
     884             :                     // get the name of the first available font
     885      186388 :                     float fExactHeight = static_cast<float>(aSize.Height());
     886      186388 :                     ImplFontEntry* pEntry = pOutDev->mpFontCache->GetFontEntry( pOutDev->mpFontCollection, aFont, aSize, fExactHeight );
     887      186388 :                     if (pEntry)
     888             :                     {
     889      186388 :                         if( pEntry->maFontSelData.mpFontData )
     890      186388 :                             aFont.SetName( pEntry->maFontSelData.mpFontData->GetFamilyName() );
     891             :                         else
     892           0 :                             aFont.SetName( pEntry->maFontSelData.maTargetName );
     893             :                     }
     894             :                 }
     895             :             }
     896             :             else
     897           0 :                 aFont.SetName( aSearch );
     898             :         }
     899             :     }
     900             : 
     901             : #if OSL_DEBUG_LEVEL > 2
     902             :     const char* s = "DEFAULTFONT_SANS_UNKNOWN";
     903             :     switch ( nType )
     904             :     {
     905             :     case DEFAULTFONT_SANS_UNICODE:  s = "DEFAULTFONT_SANS_UNICODE"; break;
     906             :     case DEFAULTFONT_UI_SANS:   s = "DEFAULTFONT_UI_SANS"; break;
     907             : 
     908             :     case DEFAULTFONT_SANS:  s = "DEFAULTFONT_SANS"; break;
     909             :     case DEFAULTFONT_LATIN_HEADING: s = "DEFAULTFONT_LATIN_HEADING"; break;
     910             :     case DEFAULTFONT_LATIN_SPREADSHEET: s = "DEFAULTFONT_LATIN_SPREADSHEET"; break;
     911             :     case DEFAULTFONT_LATIN_DISPLAY: s = "DEFAULTFONT_LATIN_DISPLAY"; break;
     912             : 
     913             :     case DEFAULTFONT_SERIF: s = "DEFAULTFONT_SERIF"; break;
     914             :     case DEFAULTFONT_LATIN_TEXT:    s = "DEFAULTFONT_LATIN_TEXT"; break;
     915             :     case DEFAULTFONT_LATIN_PRESENTATION:    s = "DEFAULTFONT_LATIN_PRESENTATION"; break;
     916             : 
     917             :     case DEFAULTFONT_FIXED: s = "DEFAULTFONT_FIXED"; break;
     918             :     case DEFAULTFONT_LATIN_FIXED:   s = "DEFAULTFONT_LATIN_FIXED"; break;
     919             :     case DEFAULTFONT_UI_FIXED:  s = "DEFAULTFONT_UI_FIXED"; break;
     920             : 
     921             :     case DEFAULTFONT_SYMBOL:    s = "DEFAULTFONT_SYMBOL"; break;
     922             : 
     923             :     case DEFAULTFONT_CJK_TEXT:  s = "DEFAULTFONT_CJK_TEXT"; break;
     924             :     case DEFAULTFONT_CJK_PRESENTATION:  s = "DEFAULTFONT_CJK_PRESENTATION"; break;
     925             :     case DEFAULTFONT_CJK_SPREADSHEET:   s = "DEFAULTFONT_CJK_SPREADSHEET"; break;
     926             :     case DEFAULTFONT_CJK_HEADING:   s = "DEFAULTFONT_CJK_HEADING"; break;
     927             :     case DEFAULTFONT_CJK_DISPLAY:   s = "DEFAULTFONT_CJK_DISPLAY"; break;
     928             : 
     929             :     case DEFAULTFONT_CTL_TEXT:  s = "DEFAULTFONT_CTL_TEXT"; break;
     930             :     case DEFAULTFONT_CTL_PRESENTATION:  s = "DEFAULTFONT_CTL_PRESENTATION"; break;
     931             :     case DEFAULTFONT_CTL_SPREADSHEET:   s = "DEFAULTFONT_CTL_SPREADSHEET"; break;
     932             :     case DEFAULTFONT_CTL_HEADING:   s = "DEFAULTFONT_CTL_HEADING"; break;
     933             :     case DEFAULTFONT_CTL_DISPLAY:   s = "DEFAULTFONT_CTL_DISPLAY"; break;
     934             :     }
     935             :     fprintf( stderr, "   OutputDevice::GetDefaultFont() Type=\"%s\" lang=%d flags=%ld FontName=\"%s\"\n",
     936             :          s, eLang, nFlags,
     937             :          OUStringToOString( aFont.GetName(), RTL_TEXTENCODING_UTF8 ).getStr()
     938             :          );
     939             : #endif
     940             : 
     941      597380 :     return aFont;
     942             : }
     943             : 
     944       23884 : ImplFontEntry::ImplFontEntry( const FontSelectPattern& rFontSelData )
     945             :     : maFontSelData( rFontSelData )
     946             :     , maMetric( rFontSelData )
     947             :     , mpConversion( NULL )
     948             :     , mnLineHeight( 0 )
     949             :     , mnRefCount( 1 )
     950             :     , mnSetFontFlags( 0 )
     951             :     , mnOwnOrientation( 0 )
     952             :     , mnOrientation( 0 )
     953             :     , mbInit( false )
     954       23884 :     , mpUnicodeFallbackList( NULL )
     955             : {
     956       23884 :     maFontSelData.mpFontEntry = this;
     957       23884 : }
     958             : 
     959       46558 : ImplFontEntry::~ImplFontEntry()
     960             : {
     961       23279 :     delete mpUnicodeFallbackList;
     962       23279 : }
     963             : 
     964        4962 : size_t ImplFontEntry::GFBCacheKey_Hash::operator()( const GFBCacheKey& rData ) const
     965             : {
     966             :     boost::hash<sal_UCS4> a;
     967             :     boost::hash<int > b;
     968        4962 :     return a(rData.first) ^ b(rData.second);
     969             : }
     970             : 
     971         968 : void ImplFontEntry::AddFallbackForUnicode( sal_UCS4 cChar, FontWeight eWeight, const OUString& rFontName )
     972             : {
     973         968 :     if( !mpUnicodeFallbackList )
     974         182 :         mpUnicodeFallbackList = new UnicodeFallbackList;
     975         968 :     (*mpUnicodeFallbackList)[ GFBCacheKey(cChar,eWeight) ] = rFontName;
     976         968 : }
     977             : 
     978        3656 : bool ImplFontEntry::GetFallbackForUnicode( sal_UCS4 cChar, FontWeight eWeight, OUString* pFontName ) const
     979             : {
     980        3656 :     if( !mpUnicodeFallbackList )
     981         364 :         return false;
     982             : 
     983        3292 :     UnicodeFallbackList::const_iterator it = mpUnicodeFallbackList->find( GFBCacheKey(cChar,eWeight) );
     984        3292 :     if( it == mpUnicodeFallbackList->end() )
     985        1182 :         return false;
     986             : 
     987        2110 :     *pFontName = (*it).second;
     988        2110 :     return true;
     989             : }
     990             : 
     991         702 : void ImplFontEntry::IgnoreFallbackForUnicode( sal_UCS4 cChar, FontWeight eWeight, const OUString& rFontName )
     992             : {
     993             : //  DBG_ASSERT( mpUnicodeFallbackList, "ImplFontEntry::IgnoreFallbackForUnicode no list" );
     994         702 :     UnicodeFallbackList::iterator it = mpUnicodeFallbackList->find( GFBCacheKey(cChar,eWeight) );
     995             : //  DBG_ASSERT( it != mpUnicodeFallbackList->end(), "ImplFontEntry::IgnoreFallbackForUnicode no match" );
     996         702 :     if( it == mpUnicodeFallbackList->end() )
     997         702 :         return;
     998         702 :     if( (*it).second == rFontName )
     999         702 :         mpUnicodeFallbackList->erase( it );
    1000             : }
    1001             : 
    1002     1081795 : FontSelectPatternAttributes::FontSelectPatternAttributes( const vcl::Font& rFont,
    1003             :     const OUString& rSearchName, const Size& rSize, float fExactHeight )
    1004             :     : maSearchName( rSearchName )
    1005     1081795 :     , mnWidth( rSize.Width() )
    1006     1081795 :     , mnHeight( rSize.Height() )
    1007             :     , mfExactHeight( fExactHeight)
    1008     1081795 :     , mnOrientation( rFont.GetOrientation() )
    1009     1081795 :     , meLanguage( rFont.GetLanguage() )
    1010     1081795 :     , mbVertical( rFont.IsVertical() )
    1011             :     , mbNonAntialiased( false )
    1012     6490770 :     , mbEmbolden( false )
    1013             : {
    1014     1081795 :     maTargetName = GetFamilyName();
    1015             : 
    1016     1081795 :     rFont.GetFontAttributes( *this );
    1017             : 
    1018             :     // normalize orientation between 0 and 3600
    1019     1081795 :     if( 3600 <= (unsigned)mnOrientation )
    1020             :     {
    1021           0 :         if( mnOrientation >= 0 )
    1022           0 :             mnOrientation %= 3600;
    1023             :         else
    1024           0 :             mnOrientation = 3600 - (-mnOrientation % 3600);
    1025             :     }
    1026             : 
    1027             :     // normalize width and height
    1028     1081795 :     if( mnHeight < 0 )
    1029           0 :         mnHeight = -mnHeight;
    1030     1081795 :     if( mnWidth < 0 )
    1031           0 :         mnWidth = -mnWidth;
    1032     1081795 : }
    1033             : 
    1034     1081795 : FontSelectPattern::FontSelectPattern( const vcl::Font& rFont,
    1035             :     const OUString& rSearchName, const Size& rSize, float fExactHeight)
    1036             :     : FontSelectPatternAttributes(rFont, rSearchName, rSize, fExactHeight)
    1037             :     , mpFontData( NULL )
    1038     1081795 :     , mpFontEntry( NULL )
    1039             : {
    1040     1081795 : }
    1041             : 
    1042             : // NOTE: this ctor is still used on Windows. Do not remove.
    1043             : #ifdef WNT
    1044             : FontSelectPatternAttributes::FontSelectPatternAttributes( const PhysicalFontFace& rFontData,
    1045             :     const Size& rSize, float fExactHeight, int nOrientation, bool bVertical )
    1046             :     : ImplFontAttributes( rFontData )
    1047             :     , mnWidth( rSize.Width() )
    1048             :     , mnHeight( rSize.Height() )
    1049             :     , mfExactHeight( fExactHeight )
    1050             :     , mnOrientation( nOrientation )
    1051             :     , meLanguage( 0 )
    1052             :     , mbVertical( bVertical )
    1053             :     , mbNonAntialiased( false )
    1054             :     , mbEmbolden( false )
    1055             : {
    1056             :     maTargetName = maSearchName = GetFamilyName();
    1057             :     // NOTE: no normalization for width/height/orientation
    1058             : }
    1059             : 
    1060             : FontSelectPattern::FontSelectPattern( const PhysicalFontFace& rFontData,
    1061             :     const Size& rSize, float fExactHeight, int nOrientation, bool bVertical )
    1062             :     : FontSelectPatternAttributes(rFontData, rSize, fExactHeight, nOrientation, bVertical)
    1063             :     , mpFontData( &rFontData )
    1064             :     , mpFontEntry( NULL )
    1065             : {
    1066             : }
    1067             : #endif
    1068             : 
    1069        4401 : void FontSelectPattern::copyAttributes(const FontSelectPatternAttributes &rAttributes)
    1070             : {
    1071        4401 :     static_cast<FontSelectPatternAttributes&>(*this) = rAttributes;
    1072        4401 : }
    1073             : 
    1074     1134919 : size_t ImplFontCache::IFSD_Hash::operator()( const FontSelectPattern& rFSD ) const
    1075             : {
    1076     1134919 :     return rFSD.hashCode();
    1077             : }
    1078             : 
    1079     1134919 : size_t FontSelectPatternAttributes::hashCode() const
    1080             : {
    1081             :     // TODO: does it pay off to improve this hash function?
    1082             :     size_t nHash;
    1083             : #if ENABLE_GRAPHITE
    1084             :     // check for features and generate a unique hash if necessary
    1085     1134919 :     if (maTargetName.indexOf(grutils::GrFeatureParser::FEAT_PREFIX)
    1086             :         != -1)
    1087             :     {
    1088           0 :         nHash = maTargetName.hashCode();
    1089             :     }
    1090             :     else
    1091             : #endif
    1092             :     {
    1093     1134919 :         nHash = maSearchName.hashCode();
    1094             :     }
    1095     1134919 :     nHash += 11 * mnHeight;
    1096     1134919 :     nHash += 19 * GetWeight();
    1097     1134919 :     nHash += 29 * GetSlant();
    1098     1134919 :     nHash += 37 * mnOrientation;
    1099     1134919 :     nHash += 41 * meLanguage;
    1100     1134919 :     if( mbVertical )
    1101         122 :         nHash += 53;
    1102     1134919 :     return nHash;
    1103             : }
    1104             : 
    1105       92930 : bool FontSelectPatternAttributes::operator==(const FontSelectPatternAttributes& rOther) const
    1106             : {
    1107       92930 :     if (static_cast<const ImplFontAttributes&>(*this) != static_cast<const ImplFontAttributes&>(rOther))
    1108       71941 :         return false;
    1109             : 
    1110       20989 :     if (maTargetName != rOther.maTargetName)
    1111           0 :         return false;
    1112             : 
    1113       20989 :     if (maSearchName != rOther.maSearchName)
    1114           0 :         return false;
    1115             : 
    1116       20989 :     if (mnWidth != rOther.mnWidth)
    1117        1887 :         return false;
    1118             : 
    1119       19102 :     if (mnHeight != rOther.mnHeight)
    1120       13088 :         return false;
    1121             : 
    1122        6014 :     if (mfExactHeight != rOther.mfExactHeight)
    1123          18 :         return false;
    1124             : 
    1125        5996 :     if (mnOrientation != rOther.mnOrientation)
    1126         187 :         return false;
    1127             : 
    1128        5809 :     if (meLanguage != rOther.meLanguage)
    1129        1408 :         return false;
    1130             : 
    1131        4401 :     if (mbVertical != rOther.mbVertical)
    1132           0 :         return false;
    1133             : 
    1134        4401 :     if (mbNonAntialiased != rOther.mbNonAntialiased)
    1135           0 :         return false;
    1136             : 
    1137        4401 :     if (mbEmbolden != rOther.mbEmbolden)
    1138           0 :         return false;
    1139             : 
    1140        4401 :     if (maItalicMatrix != rOther.maItalicMatrix)
    1141           0 :         return false;
    1142             : 
    1143        4401 :     return true;
    1144             : }
    1145             : 
    1146     2168818 : bool ImplFontCache::IFSD_Equal::operator()(const FontSelectPattern& rA, const FontSelectPattern& rB) const
    1147             : {
    1148             :     // check normalized font family name
    1149     2168818 :     if( rA.maSearchName != rB.maSearchName )
    1150     1079019 :         return false;
    1151             : 
    1152             :     // check font transformation
    1153     1089799 :     if( (rA.mnHeight       != rB.mnHeight)
    1154     1089799 :     ||  (rA.mnWidth        != rB.mnWidth)
    1155     1075595 :     ||  (rA.mnOrientation  != rB.mnOrientation) )
    1156       14204 :         return false;
    1157             : 
    1158             :     // check mapping relevant attributes
    1159     1075595 :     if( (rA.mbVertical     != rB.mbVertical)
    1160     1075595 :     ||  (rA.meLanguage     != rB.meLanguage) )
    1161           0 :         return false;
    1162             : 
    1163             :     // check font face attributes
    1164     2151190 :     if( (rA.GetWeight()       != rB.GetWeight())
    1165     1075595 :     ||  (rA.GetSlant()       != rB.GetSlant())
    1166             : //  ||  (rA.meFamily       != rB.meFamily) // TODO: remove this mostly obsolete member
    1167     2151190 :     ||  (rA.GetPitch()     != rB.GetPitch()) )
    1168        6782 :         return false;
    1169             : 
    1170             :     // check style name
    1171     1068813 :     if( rA.GetStyleName() != rB.GetStyleName() )
    1172        7030 :         return false;
    1173             : 
    1174             :     // Symbol fonts may recode from one type to another So they are only
    1175             :     // safely equivalent for equal targets
    1176     1061783 :     if (
    1177     1064303 :         (rA.mpFontData && rA.mpFontData->IsSymbolFont()) ||
    1178        1144 :         (rB.mpFontData && rB.mpFontData->IsSymbolFont())
    1179             :        )
    1180             :     {
    1181        2520 :         if (rA.maTargetName != rB.maTargetName)
    1182         356 :             return false;
    1183             :     }
    1184             : 
    1185             : #if ENABLE_GRAPHITE
    1186             :     // check for features
    1187     2122854 :     if ((rA.maTargetName.indexOf(grutils::GrFeatureParser::FEAT_PREFIX)
    1188     1061427 :          != -1 ||
    1189     1061427 :          rB.maTargetName.indexOf(grutils::GrFeatureParser::FEAT_PREFIX)
    1190     1061427 :          != -1) && rA.maTargetName != rB.maTargetName)
    1191           0 :         return false;
    1192             : #endif
    1193             : 
    1194     1061427 :     if (rA.mbEmbolden != rB.mbEmbolden)
    1195           0 :         return false;
    1196             : 
    1197     1061427 :     if (rA.maItalicMatrix != rB.maItalicMatrix)
    1198           0 :         return false;
    1199             : 
    1200     1061427 :     return true;
    1201             : }
    1202             : 
    1203        7143 : ImplFontCache::ImplFontCache()
    1204             : :   mpFirstEntry( NULL ),
    1205        7143 :     mnRef0Count( 0 )
    1206        7143 : {}
    1207             : 
    1208       14190 : ImplFontCache::~ImplFontCache()
    1209             : {
    1210        7095 :     FontInstanceList::iterator it = maFontInstanceList.begin();
    1211       26674 :     for(; it != maFontInstanceList.end(); ++it )
    1212             :     {
    1213       19579 :         ImplFontEntry* pEntry = (*it).second;
    1214       19579 :         delete pEntry;
    1215             :     }
    1216        7095 : }
    1217             : 
    1218     1081795 : ImplFontEntry* ImplFontCache::GetFontEntry( PhysicalFontCollection* pFontList,
    1219             :     const vcl::Font& rFont, const Size& rSize, float fExactHeight )
    1220             : {
    1221     1081795 :     OUString aSearchName = rFont.GetName();
    1222             : 
    1223             :     // initialize internal font request object
    1224     2163590 :     FontSelectPattern aFontSelData( rFont, aSearchName, rSize, fExactHeight );
    1225     2163590 :     return GetFontEntry( pFontList, aFontSelData );
    1226             : }
    1227             : 
    1228     1085311 : ImplFontEntry* ImplFontCache::GetFontEntry( PhysicalFontCollection* pFontList,
    1229             :     FontSelectPattern& aFontSelData )
    1230             : {
    1231     1085311 :     const FontSelectPattern aFontSelDataOrig(aFontSelData);
    1232             :     // check if a directly matching logical font instance is already cached,
    1233             :     // the most recently used font usually has a hit rate of >50%
    1234     1085311 :     ImplFontEntry *pEntry = NULL;
    1235     1085311 :     PhysicalFontFamily* pFontFamily = NULL;
    1236             :     IFSD_Equal aIFSD_Equal;
    1237     1085311 :     if( mpFirstEntry && aIFSD_Equal( aFontSelData, mpFirstEntry->maFontSelData ) )
    1238           0 :         pEntry = mpFirstEntry;
    1239             :     else
    1240             :     {
    1241     1085311 :         FontInstanceList::iterator it = maFontInstanceList.find( aFontSelData );
    1242     1085311 :         if( it != maFontInstanceList.end() )
    1243     1061427 :             pEntry = (*it).second;
    1244             :     }
    1245             : 
    1246     1085311 :     if( !pEntry ) // no direct cache hit
    1247             :     {
    1248             :         // find the best matching logical font family and update font selector accordingly
    1249       23884 :         pFontFamily = pFontList->ImplFindByFont( aFontSelData );
    1250             :         DBG_ASSERT( (pFontFamily != NULL), "ImplFontCache::Get() No logical font found!" );
    1251       23884 :         if( pFontFamily )
    1252       23884 :             aFontSelData.maSearchName = pFontFamily->GetSearchName();
    1253             : 
    1254             :         // check if an indirectly matching logical font instance is already cached
    1255       23884 :         FontInstanceList::iterator it = maFontInstanceList.find( aFontSelData );
    1256       23884 :         if( it != maFontInstanceList.end() )
    1257             :         {
    1258             :             // we have an indirect cache hit
    1259           0 :             pEntry = (*it).second;
    1260             :         }
    1261             :     }
    1262             : 
    1263     1085311 :     PhysicalFontFace* pFontData = NULL;
    1264             : 
    1265     1085311 :     if (!pEntry && pFontFamily)// no cache hit => find the best matching physical font face
    1266             :     {
    1267       23884 :         bool bOrigWasSymbol = aFontSelData.mpFontData && aFontSelData.mpFontData->IsSymbolFont();
    1268       23884 :         pFontData = pFontFamily->FindBestFontFace( aFontSelData );
    1269       23884 :         aFontSelData.mpFontData = pFontData;
    1270       23884 :         bool bNewIsSymbol = aFontSelData.mpFontData && aFontSelData.mpFontData->IsSymbolFont();
    1271             : 
    1272       23884 :         if (bNewIsSymbol != bOrigWasSymbol)
    1273             :         {
    1274             :             // it is possible, though generally unlikely, that at this point we
    1275             :             // will attempt to use a symbol font as a last-ditch fallback for a
    1276             :             // non-symbol font request or vice versa, and by changing
    1277             :             // aFontSelData.mpFontData to/from a symbol font we may now find
    1278             :             // something in the cache that can be reused which previously
    1279             :             // wasn't a candidate
    1280        1840 :             FontInstanceList::iterator it = maFontInstanceList.find( aFontSelData );
    1281        1840 :             if( it != maFontInstanceList.end() )
    1282           0 :                 pEntry = (*it).second;
    1283             :         }
    1284             :     }
    1285             : 
    1286     1085311 :     if( pEntry ) // cache hit => use existing font instance
    1287             :     {
    1288             :         // increase the font instance's reference count
    1289     1061427 :         if( !pEntry->mnRefCount++ )
    1290      292746 :             --mnRef0Count;
    1291             :     }
    1292             : 
    1293     1085311 :     if (!pEntry && pFontData)// still no cache hit => create a new font instance
    1294             :     {
    1295             :         // create a new logical font instance from this physical font face
    1296       23884 :         pEntry = pFontData->CreateFontInstance( aFontSelData );
    1297             : 
    1298             :         // if we're subtituting from or to a symbol font we may need a symbol
    1299             :         // conversion table
    1300       23884 :         if( pFontData->IsSymbolFont() || aFontSelData.IsSymbolFont() )
    1301             :         {
    1302        1978 :             if( aFontSelData.maTargetName != aFontSelData.maSearchName )
    1303        1978 :                 pEntry->mpConversion = ConvertChar::GetRecodeData( aFontSelData.maTargetName, aFontSelData.maSearchName );
    1304             :         }
    1305             : 
    1306             : #ifdef MACOSX
    1307             :         //It might be better to dig out the font version of the target font
    1308             :         //to see if it's a modern re-coded apple symbol font in case that
    1309             :         //font shows up on a different platform
    1310             :         if (!pEntry->mpConversion &&
    1311             :             aFontSelData.maTargetName.equalsIgnoreAsciiCase("symbol") &&
    1312             :             aFontSelData.maSearchName.equalsIgnoreAsciiCase("symbol"))
    1313             :         {
    1314             :             pEntry->mpConversion = ConvertChar::GetRecodeData( OUString("Symbol"), OUString("AppleSymbol") );
    1315             :         }
    1316             : #endif
    1317             : 
    1318             :         // Add the new entry to the cache with the original FontSelectPattern,
    1319             :         // so that we can find it next time as a direct cache hit.
    1320       23884 :         maFontInstanceList[ aFontSelDataOrig ] = pEntry;
    1321             :     }
    1322             : 
    1323     1085311 :     mpFirstEntry = pEntry;
    1324     1085311 :     return pEntry;
    1325             : }
    1326             : 
    1327        4744 : ImplFontEntry* ImplFontCache::GetGlyphFallbackFont( PhysicalFontCollection* pFontCollection,
    1328             :     FontSelectPattern& rFontSelData, int nFallbackLevel, OUString& rMissingCodes )
    1329             : {
    1330             :     // get a candidate font for glyph fallback
    1331             :     // unless the previously selected font got a device specific substitution
    1332             :     // e.g. PsPrint Arial->Helvetica for udiaeresis when Helvetica doesn't support it
    1333        4744 :     if( nFallbackLevel >= 1)
    1334             :     {
    1335        4744 :         PhysicalFontFamily* pFallbackData = NULL;
    1336             : 
    1337             :         //fdo#33898 If someone has EUDC installed then they really want that to
    1338             :         //be used as the first-choice glyph fallback seeing as it's filled with
    1339             :         //private area codes with don't make any sense in any other font so
    1340             :         //prioritise it here if it's available. Ideally we would remove from
    1341             :         //rMissingCodes all the glyphs which it is able to resolve as an
    1342             :         //optimization, but that's tricky to achieve cross-platform without
    1343             :         //sufficient heavy-weight code that's likely to undo the value of the
    1344             :         //optimization
    1345        4744 :         if (nFallbackLevel == 1)
    1346        1938 :             pFallbackData = pFontCollection->FindFontFamily(OUString("EUDC"));
    1347        4744 :         if (!pFallbackData)
    1348        4744 :             pFallbackData = pFontCollection->GetGlyphFallbackFont(rFontSelData, rMissingCodes, nFallbackLevel-1);
    1349             :         // escape when there are no font candidates
    1350        4744 :         if( !pFallbackData  )
    1351        1228 :             return NULL;
    1352             :         // override the font name
    1353        3516 :         rFontSelData.SetFamilyName( pFallbackData->GetFamilyName() );
    1354             :         // clear the cached normalized name
    1355        3516 :         rFontSelData.maSearchName = "";
    1356             :     }
    1357             : 
    1358        3516 :     ImplFontEntry* pFallbackFont = GetFontEntry( pFontCollection, rFontSelData );
    1359        3516 :     return pFallbackFont;
    1360             : }
    1361             : 
    1362      898476 : void ImplFontCache::Release( ImplFontEntry* pEntry )
    1363             : {
    1364             :     static const int FONTCACHE_MAX = 50;
    1365             : 
    1366             :     DBG_ASSERT( (pEntry->mnRefCount > 0), "ImplFontCache::Release() - font refcount underflow" );
    1367      898476 :     if( --pEntry->mnRefCount > 0 )
    1368     1481171 :         return;
    1369             : 
    1370      315707 :     if( ++mnRef0Count < FONTCACHE_MAX )
    1371      315633 :         return;
    1372             : 
    1373             :     // remove unused entries from font instance cache
    1374          74 :     FontInstanceList::iterator it_next = maFontInstanceList.begin();
    1375        4324 :     while( it_next != maFontInstanceList.end() )
    1376             :     {
    1377        4176 :         FontInstanceList::iterator it = it_next++;
    1378        4176 :         ImplFontEntry* pFontEntry = (*it).second;
    1379        4176 :         if( pFontEntry->mnRefCount > 0 )
    1380         476 :             continue;
    1381             : 
    1382        3700 :         maFontInstanceList.erase( it );
    1383        3700 :         delete pFontEntry;
    1384        3700 :         --mnRef0Count;
    1385             :         DBG_ASSERT( (mnRef0Count>=0), "ImplFontCache::Release() - refcount0 underflow" );
    1386             : 
    1387        3700 :         if( mpFirstEntry == pFontEntry )
    1388          31 :             mpFirstEntry = NULL;
    1389             :     }
    1390             : 
    1391             :     DBG_ASSERT( (mnRef0Count==0), "ImplFontCache::Release() - refcount0 mismatch" );
    1392             : }
    1393             : 
    1394         100 : void ImplFontCache::Invalidate()
    1395             : {
    1396             :     // delete unreferenced entries
    1397         100 :     FontInstanceList::iterator it = maFontInstanceList.begin();
    1398         100 :     for(; it != maFontInstanceList.end(); ++it )
    1399             :     {
    1400           0 :         ImplFontEntry* pFontEntry = (*it).second;
    1401           0 :         if( pFontEntry->mnRefCount > 0 )
    1402           0 :             continue;
    1403             : 
    1404           0 :         delete pFontEntry;
    1405           0 :         --mnRef0Count;
    1406             :     }
    1407             : 
    1408             :     // #112304# make sure the font cache is really clean
    1409         100 :     mpFirstEntry = NULL;
    1410         100 :     maFontInstanceList.clear();
    1411             : 
    1412             :     DBG_ASSERT( (mnRef0Count==0), "ImplFontCache::Invalidate() - mnRef0Count non-zero" );
    1413         100 : }
    1414             : 
    1415     3056000 : void OutputDevice::ImplInitFontList() const
    1416             : {
    1417     3056000 :     if( !mpFontCollection->Count() )
    1418             :     {
    1419         312 :         if( mpGraphics || AcquireGraphics() )
    1420             :         {
    1421             :             SAL_INFO( "vcl.gdi", "OutputDevice::ImplInitFontList()" );
    1422         312 :             mpGraphics->GetDevFontList( mpFontCollection );
    1423             : 
    1424             :             // There is absolutely no way there should be no fonts available on the device
    1425         312 :             if( !mpFontCollection->Count() )
    1426             :             {
    1427           0 :                 OUString aError( "Application error: no fonts and no vcl resource found on your system" );
    1428           0 :                 ResMgr* pMgr = ImplGetResMgr();
    1429           0 :                 if( pMgr )
    1430             :                 {
    1431           0 :                     OUString aResStr(ResId(SV_ACCESSERROR_NO_FONTS, *pMgr).toString());
    1432           0 :                     if( !aResStr.isEmpty() )
    1433           0 :                         aError = aResStr;
    1434             :                 }
    1435           0 :                 Application::Abort( aError );
    1436             :             }
    1437             :         }
    1438             :     }
    1439     3056000 : }
    1440             : 
    1441      289719 : void OutputDevice::InitFont() const
    1442             : {
    1443             :     DBG_TESTSOLARMUTEX();
    1444             : 
    1445      289719 :     if (!mpFontEntry)
    1446      289719 :         return;
    1447             : 
    1448      289719 :     if ( mbInitFont )
    1449             :     {
    1450             :         // decide if antialiasing is appropriate
    1451      289719 :         bool bNonAntialiased = (GetAntialiasing() & ANTIALIASING_DISABLE_TEXT) != 0;
    1452      289719 :         const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
    1453      289719 :         bNonAntialiased |= ((rStyleSettings.GetDisplayOptions() & DISPLAY_OPTION_AA_DISABLE) != 0);
    1454      289719 :         bNonAntialiased |= (int(rStyleSettings.GetAntialiasingMinPixelHeight()) > mpFontEntry->maFontSelData.mnHeight);
    1455      289719 :         mpFontEntry->maFontSelData.mbNonAntialiased = bNonAntialiased;
    1456             : 
    1457             :         // select font in the device layers
    1458      289719 :         mpFontEntry->mnSetFontFlags = mpGraphics->SetFont( &(mpFontEntry->maFontSelData), 0 );
    1459      289719 :         mbInitFont = false;
    1460             :     }
    1461             : }
    1462             : 
    1463     1344787 : bool OutputDevice::ImplNewFont() const
    1464             : {
    1465             :     DBG_TESTSOLARMUTEX();
    1466             : 
    1467             :     // get correct font list on the PDF writer if necessary
    1468     1344787 :     if( mpPDFWriter )
    1469             :     {
    1470           0 :         const ImplSVData* pSVData = ImplGetSVData();
    1471           0 :         if( mpFontCollection == pSVData->maGDIData.mpScreenFontList
    1472           0 :         ||  mpFontCache == pSVData->maGDIData.mpScreenFontCache )
    1473           0 :             const_cast<OutputDevice&>(*this).ImplUpdateFontData( true );
    1474             :     }
    1475             : 
    1476     1344787 :     if ( !mbNewFont )
    1477      450067 :         return true;
    1478             : 
    1479             :     // we need a graphics
    1480      894720 :     if ( !mpGraphics && !AcquireGraphics() )
    1481           0 :         return false;
    1482      894720 :     SalGraphics* pGraphics = mpGraphics;
    1483      894720 :     ImplInitFontList();
    1484             : 
    1485             :     // convert to pixel height
    1486             :     // TODO: replace integer based aSize completely with subpixel accurate type
    1487      894720 :     float fExactHeight = ImplFloatLogicHeightToDevicePixel( static_cast<float>(maFont.GetHeight()) );
    1488      894720 :     Size aSize = ImplLogicToDevicePixel( maFont.GetSize() );
    1489      894720 :     if ( !aSize.Height() )
    1490             :     {
    1491             :         // use default pixel height only when logical height is zero
    1492         125 :         if ( maFont.GetSize().Height() )
    1493           0 :             aSize.Height() = 1;
    1494             :         else
    1495         125 :             aSize.Height() = (12*mnDPIY)/72;
    1496         125 :         fExactHeight =  static_cast<float>(aSize.Height());
    1497             :     }
    1498             : 
    1499             :     // select the default width only when logical width is zero
    1500      894720 :     if( (0 == aSize.Width()) && (0 != maFont.GetSize().Width()) )
    1501           0 :         aSize.Width() = 1;
    1502             : 
    1503             :     // get font entry
    1504      894720 :     ImplFontEntry* pOldEntry = mpFontEntry;
    1505      894720 :     mpFontEntry = mpFontCache->GetFontEntry( mpFontCollection, maFont, aSize, fExactHeight );
    1506      894720 :     if( pOldEntry )
    1507      739436 :         mpFontCache->Release( pOldEntry );
    1508             : 
    1509      894720 :     ImplFontEntry* pFontEntry = mpFontEntry;
    1510             : 
    1511      894720 :     if (!pFontEntry)
    1512           0 :         return false;
    1513             : 
    1514             :     // mark when lower layers need to get involved
    1515      894720 :     mbNewFont = false;
    1516      894720 :     if( pFontEntry != pOldEntry )
    1517      443254 :         mbInitFont = true;
    1518             : 
    1519             :     // select font when it has not been initialized yet
    1520      894720 :     if ( !pFontEntry->mbInit )
    1521             :     {
    1522       22771 :         InitFont();
    1523             : 
    1524             :         // get metric data from device layers
    1525       22771 :         if ( pGraphics )
    1526             :         {
    1527       22771 :             pFontEntry->mbInit = true;
    1528             : 
    1529       22771 :             pFontEntry->maMetric.mnOrientation  = sal::static_int_cast<short>(pFontEntry->maFontSelData.mnOrientation);
    1530       22771 :             pGraphics->GetFontMetric( &(pFontEntry->maMetric) );
    1531             : 
    1532       22771 :             pFontEntry->maMetric.ImplInitTextLineSize( this );
    1533       22771 :             pFontEntry->maMetric.ImplInitAboveTextLineSize();
    1534             : 
    1535       22771 :             pFontEntry->mnLineHeight = pFontEntry->maMetric.mnAscent + pFontEntry->maMetric.mnDescent;
    1536             : 
    1537       22771 :             SetFontOrientation( pFontEntry );
    1538             :         }
    1539             :     }
    1540             : 
    1541             :     // enable kerning array if requested
    1542      894720 :     if ( maFont.GetKerning() & KERNING_FONTSPECIFIC )
    1543             :     {
    1544             :         // TODO: test if physical font supports kerning and disable if not
    1545      297594 :         if( pFontEntry->maMetric.mbKernableFont )
    1546      201458 :             mbKerning = true;
    1547             :     }
    1548             :     else
    1549      597126 :         mbKerning = false;
    1550      894720 :     if ( maFont.GetKerning() & KERNING_ASIAN )
    1551           0 :         mbKerning = true;
    1552             : 
    1553             :     // calculate EmphasisArea
    1554      894720 :     mnEmphasisAscent = 0;
    1555      894720 :     mnEmphasisDescent = 0;
    1556      894720 :     if ( maFont.GetEmphasisMark() & EMPHASISMARK_STYLE )
    1557             :     {
    1558       55653 :         FontEmphasisMark    nEmphasisMark = ImplGetEmphasisMarkStyle( maFont );
    1559       55653 :         long                nEmphasisHeight = (pFontEntry->mnLineHeight*250)/1000;
    1560       55653 :         if ( nEmphasisHeight < 1 )
    1561           9 :             nEmphasisHeight = 1;
    1562       55653 :         if ( nEmphasisMark & EMPHASISMARK_POS_BELOW )
    1563          12 :             mnEmphasisDescent = nEmphasisHeight;
    1564             :         else
    1565       55641 :             mnEmphasisAscent = nEmphasisHeight;
    1566             :     }
    1567             : 
    1568             :     // calculate text offset depending on TextAlignment
    1569      894720 :     TextAlign eAlign = maFont.GetAlign();
    1570      894720 :     if ( eAlign == ALIGN_BASELINE )
    1571             :     {
    1572      709069 :         mnTextOffX = 0;
    1573      709069 :         mnTextOffY = 0;
    1574             :     }
    1575      185651 :     else if ( eAlign == ALIGN_TOP )
    1576             :     {
    1577      181974 :         mnTextOffX = 0;
    1578      181974 :         mnTextOffY = +pFontEntry->maMetric.mnAscent + mnEmphasisAscent;
    1579      181974 :         if ( pFontEntry->mnOrientation )
    1580             :         {
    1581       20140 :             Point aOriginPt(0, 0);
    1582       20140 :             aOriginPt.RotateAround( mnTextOffX, mnTextOffY, pFontEntry->mnOrientation );
    1583             :         }
    1584             :     }
    1585             :     else // eAlign == ALIGN_BOTTOM
    1586             :     {
    1587        3677 :         mnTextOffX = 0;
    1588        3677 :         mnTextOffY = -pFontEntry->maMetric.mnDescent + mnEmphasisDescent;
    1589        3677 :         if ( pFontEntry->mnOrientation )
    1590             :         {
    1591           0 :             Point aOriginPt(0, 0);
    1592           0 :             aOriginPt.RotateAround( mnTextOffX, mnTextOffY, pFontEntry->mnOrientation );
    1593             :         }
    1594             :     }
    1595             : 
    1596     1795291 :     mbTextLines     = ((maFont.GetUnderline() != UNDERLINE_NONE) && (maFont.GetUnderline() != UNDERLINE_DONTKNOW)) ||
    1597     2625682 :                       ((maFont.GetOverline()  != UNDERLINE_NONE) && (maFont.GetOverline()  != UNDERLINE_DONTKNOW)) ||
    1598     1719212 :                       ((maFont.GetStrikeout() != STRIKEOUT_NONE) && (maFont.GetStrikeout() != STRIKEOUT_DONTKNOW));
    1599     1753538 :     mbTextSpecial   = maFont.IsShadow() || maFont.IsOutline() ||
    1600     1753538 :                       (maFont.GetRelief() != RELIEF_NONE);
    1601             : 
    1602             : 
    1603             :     // #95414# fix for OLE objects which use scale factors very creatively
    1604      894720 :     if( mbMap && !aSize.Width() )
    1605             :     {
    1606      683008 :         int nOrigWidth = pFontEntry->maMetric.mnWidth;
    1607      683008 :         float fStretch = (float)maMapRes.mnMapScNumX * maMapRes.mnMapScDenomY;
    1608      683008 :         fStretch /= (float)maMapRes.mnMapScNumY * maMapRes.mnMapScDenomX;
    1609      683008 :         int nNewWidth = (int)(nOrigWidth * fStretch + 0.5);
    1610      683008 :         if( (nNewWidth != nOrigWidth) && (nNewWidth != 0) )
    1611             :         {
    1612         214 :             Size aOrigSize = maFont.GetSize();
    1613         214 :             const_cast<Font&>(maFont).SetSize( Size( nNewWidth, aSize.Height() ) );
    1614         214 :             mbMap = false;
    1615         214 :             mbNewFont = true;
    1616         214 :             ImplNewFont();  // recurse once using stretched width
    1617         214 :             mbMap = true;
    1618         214 :             const_cast<Font&>(maFont).SetSize( aOrigSize );
    1619             :         }
    1620             :     }
    1621             : 
    1622      894720 :     return true;
    1623             : }
    1624             : 
    1625       22286 : void OutputDevice::SetFontOrientation( ImplFontEntry* const pFontEntry ) const
    1626             : {
    1627       22286 :     if( pFontEntry->maFontSelData.mnOrientation && !pFontEntry->maMetric.mnOrientation )
    1628             :     {
    1629           0 :         pFontEntry->mnOwnOrientation = sal::static_int_cast<short>(pFontEntry->maFontSelData.mnOrientation);
    1630           0 :         pFontEntry->mnOrientation = pFontEntry->mnOwnOrientation;
    1631             :     }
    1632             :     else
    1633             :     {
    1634       22286 :         pFontEntry->mnOrientation = pFontEntry->maMetric.mnOrientation;
    1635             :     }
    1636       22286 : }
    1637             : 
    1638       92930 : bool ImplFontAttributes::operator==(const ImplFontAttributes& rOther) const
    1639             : {
    1640       92930 :     if (maName != rOther.maName)
    1641       49189 :         return false;
    1642             : 
    1643       43741 :     if (maStyleName != rOther.maStyleName)
    1644        1264 :         return false;
    1645             : 
    1646       42477 :     if (meWeight != rOther.meWeight)
    1647       12661 :         return false;
    1648             : 
    1649       29816 :     if (meItalic != rOther.meItalic)
    1650        3447 :         return false;
    1651             : 
    1652       26369 :     if (meFamily != rOther.meFamily)
    1653        4007 :         return false;
    1654             : 
    1655       22362 :     if (mePitch != rOther.mePitch)
    1656        1373 :         return false;
    1657             : 
    1658       20989 :     if (meWidthType != rOther.meWidthType)
    1659           0 :         return false;
    1660             : 
    1661       20989 :     if (mbSymbolFlag != rOther.mbSymbolFlag)
    1662           0 :         return false;
    1663             : 
    1664       20989 :     return true;
    1665             : }
    1666             : 
    1667       23884 : ImplFontMetricData::ImplFontMetricData( const FontSelectPattern& rFontSelData )
    1668             :     : ImplFontAttributes( rFontSelData )
    1669             :     , mnWidth ( rFontSelData.mnWidth)
    1670             :     , mnOrientation( (short)(rFontSelData.mnOrientation))
    1671             :     , mnAscent( 0 )
    1672             :     , mnDescent( 0 )
    1673             :     , mnIntLeading( 0 )
    1674             :     , mnExtLeading( 0 )
    1675             :     , mnSlant( 0 )
    1676             :     , mnMinKashida( 0 )
    1677             :     , meFamilyType(FAMILY_DONTKNOW)
    1678             :     , mbScalableFont(false)
    1679             :     , mnUnderlineSize( 0 )
    1680             :     , mnUnderlineOffset( 0 )
    1681             :     , mnBUnderlineSize( 0 )
    1682             :     , mnBUnderlineOffset( 0 )
    1683             :     , mnDUnderlineSize( 0 )
    1684             :     , mnDUnderlineOffset1( 0 )
    1685             :     , mnDUnderlineOffset2( 0 )
    1686             :     , mnWUnderlineSize( 0 )
    1687             :     , mnWUnderlineOffset( 0 )
    1688             :     , mnAboveUnderlineSize( 0 )
    1689             :     , mnAboveUnderlineOffset( 0 )
    1690             :     , mnAboveBUnderlineSize( 0 )
    1691             :     , mnAboveBUnderlineOffset( 0 )
    1692             :     , mnAboveDUnderlineSize( 0 )
    1693             :     , mnAboveDUnderlineOffset1( 0 )
    1694             :     , mnAboveDUnderlineOffset2( 0 )
    1695             :     , mnAboveWUnderlineSize( 0 )
    1696             :     , mnAboveWUnderlineOffset( 0 )
    1697             :     , mnStrikeoutSize( 0 )
    1698             :     , mnStrikeoutOffset( 0 )
    1699             :     , mnBStrikeoutSize( 0 )
    1700             :     , mnBStrikeoutOffset( 0 )
    1701             :     , mnDStrikeoutSize( 0 )
    1702             :     , mnDStrikeoutOffset1( 0 )
    1703       23884 :     , mnDStrikeoutOffset2( 0 )
    1704             : {
    1705             :     // intialize the used font name
    1706       23884 :     if( rFontSelData.mpFontData )
    1707             :     {
    1708       23884 :         SetFamilyName( rFontSelData.mpFontData->GetFamilyName() );
    1709       23884 :         SetStyleName( rFontSelData.mpFontData->GetStyleName() );
    1710       23884 :         mbDevice   = rFontSelData.mpFontData->mbDevice;
    1711       23884 :         mbKernableFont = true;
    1712             :     }
    1713             :     else
    1714             :     {
    1715           0 :         sal_Int32 nTokenPos = 0;
    1716           0 :         SetFamilyName( GetNextFontToken( rFontSelData.GetFamilyName(), nTokenPos ) );
    1717           0 :         SetStyleName( rFontSelData.GetStyleName() );
    1718           0 :         mbDevice   = false;
    1719           0 :         mbKernableFont = false;
    1720             :     }
    1721       23884 : }
    1722             : 
    1723       22771 : void ImplFontMetricData::ImplInitTextLineSize( const OutputDevice* pDev )
    1724             : {
    1725       22771 :     long nDescent = mnDescent;
    1726       22771 :     if ( nDescent <= 0 )
    1727             :     {
    1728           9 :         nDescent = mnAscent / 10;
    1729           9 :         if ( !nDescent )
    1730           9 :             nDescent = 1;
    1731             :     }
    1732             : 
    1733             :     // #i55341# for some fonts it is not a good idea to calculate
    1734             :     // their text line metrics from the real font descent
    1735             :     // => work around this problem just for these fonts
    1736       22771 :     if( 3*nDescent > mnAscent )
    1737        2343 :         nDescent = mnAscent / 3;
    1738             : 
    1739       22771 :     long nLineHeight = ((nDescent*25)+50) / 100;
    1740       22771 :     if ( !nLineHeight )
    1741         199 :         nLineHeight = 1;
    1742       22771 :     long nLineHeight2 = nLineHeight / 2;
    1743       22771 :     if ( !nLineHeight2 )
    1744        3735 :         nLineHeight2 = 1;
    1745             : 
    1746       22771 :     long nBLineHeight = ((nDescent*50)+50) / 100;
    1747       22771 :     if ( nBLineHeight == nLineHeight )
    1748        1006 :         nBLineHeight++;
    1749       22771 :     long nBLineHeight2 = nBLineHeight/2;
    1750       22771 :     if ( !nBLineHeight2 )
    1751          27 :         nBLineHeight2 = 1;
    1752             : 
    1753       22771 :     long n2LineHeight = ((nDescent*16)+50) / 100;
    1754       22771 :     if ( !n2LineHeight )
    1755        2969 :         n2LineHeight = 1;
    1756       22771 :     long n2LineDY = n2LineHeight;
    1757             :      /* #117909#
    1758             :       * add some pixels to minimum double line distance on higher resolution devices
    1759             :       */
    1760       22771 :     long nMin2LineDY = 1 + pDev->GetDPIY()/150;
    1761       22771 :     if ( n2LineDY < nMin2LineDY )
    1762       12386 :         n2LineDY = nMin2LineDY;
    1763       22771 :     long n2LineDY2 = n2LineDY/2;
    1764       22771 :     if ( !n2LineDY2 )
    1765        4400 :         n2LineDY2 = 1;
    1766             : 
    1767       22771 :     long nUnderlineOffset = mnDescent/2 + 1;
    1768       22771 :     long nStrikeoutOffset = -((mnAscent - mnIntLeading) / 3);
    1769             : 
    1770       22771 :     mnUnderlineSize        = nLineHeight;
    1771       22771 :     mnUnderlineOffset      = nUnderlineOffset - nLineHeight2;
    1772             : 
    1773       22771 :     mnBUnderlineSize       = nBLineHeight;
    1774       22771 :     mnBUnderlineOffset     = nUnderlineOffset - nBLineHeight2;
    1775             : 
    1776       22771 :     mnDUnderlineSize       = n2LineHeight;
    1777       22771 :     mnDUnderlineOffset1    = nUnderlineOffset - n2LineDY2 - n2LineHeight;
    1778       22771 :     mnDUnderlineOffset2    = mnDUnderlineOffset1 + n2LineDY + n2LineHeight;
    1779             : 
    1780       22771 :     long nWCalcSize = mnDescent;
    1781       22771 :     if ( nWCalcSize < 6 )
    1782             :     {
    1783        3709 :         if ( (nWCalcSize == 1) || (nWCalcSize == 2) )
    1784        1000 :             mnWUnderlineSize = nWCalcSize;
    1785             :         else
    1786        2709 :             mnWUnderlineSize = 3;
    1787             :     }
    1788             :     else
    1789       19062 :         mnWUnderlineSize = ((nWCalcSize*50)+50) / 100;
    1790             : 
    1791             :     // #109280# the following line assures that wavelnes are never placed below the descent, however
    1792             :     // for most fonts the waveline then is drawn into the text, so we better keep the old solution
    1793             :     // pFontEntry->maMetric.mnWUnderlineOffset     = pFontEntry->maMetric.mnDescent + 1 - pFontEntry->maMetric.mnWUnderlineSize;
    1794       22771 :     mnWUnderlineOffset     = nUnderlineOffset;
    1795             : 
    1796       22771 :     mnStrikeoutSize        = nLineHeight;
    1797       22771 :     mnStrikeoutOffset      = nStrikeoutOffset - nLineHeight2;
    1798             : 
    1799       22771 :     mnBStrikeoutSize       = nBLineHeight;
    1800       22771 :     mnBStrikeoutOffset     = nStrikeoutOffset - nBLineHeight2;
    1801             : 
    1802       22771 :     mnDStrikeoutSize       = n2LineHeight;
    1803       22771 :     mnDStrikeoutOffset1    = nStrikeoutOffset - n2LineDY2 - n2LineHeight;
    1804       22771 :     mnDStrikeoutOffset2    = mnDStrikeoutOffset1 + n2LineDY + n2LineHeight;
    1805       22771 : }
    1806             : 
    1807       22771 : void ImplFontMetricData::ImplInitAboveTextLineSize()
    1808             : {
    1809       22771 :     long nIntLeading = mnIntLeading;
    1810             :     // TODO: assess usage of nLeading below (changed in extleading CWS)
    1811             :     // if no leading is available, we assume 15% of the ascent
    1812       22771 :     if ( nIntLeading <= 0 )
    1813             :     {
    1814        6133 :         nIntLeading = mnAscent*15/100;
    1815        6133 :         if ( !nIntLeading )
    1816         227 :             nIntLeading = 1;
    1817             :     }
    1818             : 
    1819       22771 :     long nLineHeight = ((nIntLeading*25)+50) / 100;
    1820       22771 :     if ( !nLineHeight )
    1821        2618 :         nLineHeight = 1;
    1822             : 
    1823       22771 :     long nBLineHeight = ((nIntLeading*50)+50) / 100;
    1824       22771 :     if ( nBLineHeight == nLineHeight )
    1825        3774 :         nBLineHeight++;
    1826             : 
    1827       22771 :     long n2LineHeight = ((nIntLeading*16)+50) / 100;
    1828       22771 :     if ( !n2LineHeight )
    1829        4265 :         n2LineHeight = 1;
    1830             : 
    1831       22771 :     long nCeiling = -mnAscent;
    1832             : 
    1833       22771 :     mnAboveUnderlineSize       = nLineHeight;
    1834       22771 :     mnAboveUnderlineOffset     = nCeiling + (nIntLeading - nLineHeight + 1) / 2;
    1835             : 
    1836       22771 :     mnAboveBUnderlineSize      = nBLineHeight;
    1837       22771 :     mnAboveBUnderlineOffset    = nCeiling + (nIntLeading - nBLineHeight + 1) / 2;
    1838             : 
    1839       22771 :     mnAboveDUnderlineSize      = n2LineHeight;
    1840       22771 :     mnAboveDUnderlineOffset1   = nCeiling + (nIntLeading - 3*n2LineHeight + 1) / 2;
    1841       22771 :     mnAboveDUnderlineOffset2   = nCeiling + (nIntLeading +   n2LineHeight + 1) / 2;
    1842             : 
    1843       22771 :     long nWCalcSize = nIntLeading;
    1844       22771 :     if ( nWCalcSize < 6 )
    1845             :     {
    1846        5555 :         if ( (nWCalcSize == 1) || (nWCalcSize == 2) )
    1847        3774 :             mnAboveWUnderlineSize = nWCalcSize;
    1848             :         else
    1849        1781 :             mnAboveWUnderlineSize = 3;
    1850             :     }
    1851             :     else
    1852       17216 :         mnAboveWUnderlineSize = ((nWCalcSize*50)+50) / 100;
    1853             : 
    1854       22771 :     mnAboveWUnderlineOffset = nCeiling + (nIntLeading + 1) / 2;
    1855       22771 : }
    1856             : 
    1857       35178 : void OutputDevice::ImplDrawEmphasisMark( long nBaseX, long nX, long nY,
    1858             :                                          const tools::PolyPolygon& rPolyPoly, bool bPolyLine,
    1859             :                                          const Rectangle& rRect1, const Rectangle& rRect2 )
    1860             : {
    1861       35178 :     if( IsRTLEnabled() )
    1862             :         // --- RTL --- mirror at basex
    1863         668 :         nX = nBaseX - (nX - nBaseX - 1);
    1864             : 
    1865       35178 :     nX -= mnOutOffX;
    1866       35178 :     nY -= mnOutOffY;
    1867             : 
    1868       35178 :     if ( rPolyPoly.Count() )
    1869             :     {
    1870       29224 :         if ( bPolyLine )
    1871             :         {
    1872       10442 :             Polygon aPoly = rPolyPoly.GetObject( 0 );
    1873       10442 :             aPoly.Move( nX, nY );
    1874       10442 :             DrawPolyLine( aPoly );
    1875             :         }
    1876             :         else
    1877             :         {
    1878       18782 :             tools::PolyPolygon aPolyPoly = rPolyPoly;
    1879       18782 :             aPolyPoly.Move( nX, nY );
    1880       18782 :             DrawPolyPolygon( aPolyPoly );
    1881             :         }
    1882             :     }
    1883             : 
    1884       35178 :     if ( !rRect1.IsEmpty() )
    1885             :     {
    1886        5954 :         Rectangle aRect( Point( nX+rRect1.Left(),
    1887       11908 :                                 nY+rRect1.Top() ), rRect1.GetSize() );
    1888        5954 :         DrawRect( aRect );
    1889             :     }
    1890             : 
    1891       35178 :     if ( !rRect2.IsEmpty() )
    1892             :     {
    1893           0 :         Rectangle aRect( Point( nX+rRect2.Left(),
    1894           0 :                                 nY+rRect2.Top() ), rRect2.GetSize() );
    1895             : 
    1896           0 :         DrawRect( aRect );
    1897             :     }
    1898       35178 : }
    1899             : 
    1900       10674 : void OutputDevice::ImplDrawEmphasisMarks( SalLayout& rSalLayout )
    1901             : {
    1902       10674 :     Color               aOldLineColor   = GetLineColor();
    1903       10674 :     Color               aOldFillColor   = GetFillColor();
    1904       10674 :     bool                bOldMap         = mbMap;
    1905       10674 :     GDIMetaFile*        pOldMetaFile    = mpMetaFile;
    1906       10674 :     mpMetaFile = NULL;
    1907       10674 :     EnableMapMode( false );
    1908             : 
    1909       10674 :     FontEmphasisMark    nEmphasisMark = ImplGetEmphasisMarkStyle( maFont );
    1910       10674 :     tools::PolyPolygon         aPolyPoly;
    1911       10674 :     Rectangle           aRect1;
    1912       10674 :     Rectangle           aRect2;
    1913             :     long                nEmphasisYOff;
    1914             :     long                nEmphasisWidth;
    1915             :     long                nEmphasisHeight;
    1916             :     bool                bPolyLine;
    1917             : 
    1918       10674 :     if ( nEmphasisMark & EMPHASISMARK_POS_BELOW )
    1919           0 :         nEmphasisHeight = mnEmphasisDescent;
    1920             :     else
    1921       10674 :         nEmphasisHeight = mnEmphasisAscent;
    1922             : 
    1923             :     ImplGetEmphasisMark( aPolyPoly, bPolyLine,
    1924             :                          aRect1, aRect2,
    1925             :                          nEmphasisYOff, nEmphasisWidth,
    1926             :                          nEmphasisMark,
    1927       10674 :                          nEmphasisHeight, mpFontEntry->mnOrientation );
    1928             : 
    1929       10674 :     if ( bPolyLine )
    1930             :     {
    1931        2816 :         SetLineColor( GetTextColor() );
    1932        2816 :         SetFillColor();
    1933             :     }
    1934             :     else
    1935             :     {
    1936        7858 :         SetLineColor();
    1937        7858 :         SetFillColor( GetTextColor() );
    1938             :     }
    1939             : 
    1940       10674 :     Point aOffset = Point(0,0);
    1941             : 
    1942       10674 :     if ( nEmphasisMark & EMPHASISMARK_POS_BELOW )
    1943           0 :         aOffset.Y() += mpFontEntry->maMetric.mnDescent + nEmphasisYOff;
    1944             :     else
    1945       10674 :         aOffset.Y() -= mpFontEntry->maMetric.mnAscent + nEmphasisYOff;
    1946             : 
    1947       10674 :     long nEmphasisWidth2  = nEmphasisWidth / 2;
    1948       10674 :     long nEmphasisHeight2 = nEmphasisHeight / 2;
    1949       10674 :     aOffset += Point( nEmphasisWidth2, nEmphasisHeight2 );
    1950             : 
    1951       10674 :     Point aOutPoint;
    1952       10674 :     Rectangle aRectangle;
    1953       10674 :     for( int nStart = 0;;)
    1954             :     {
    1955             :         sal_GlyphId aGlyphId;
    1956       47524 :         if( !rSalLayout.GetNextGlyphs( 1, &aGlyphId, aOutPoint, nStart ) )
    1957       10674 :             break;
    1958             : 
    1959       36850 :         if( !mpGraphics->GetGlyphBoundRect( aGlyphId, aRectangle ) )
    1960           0 :             continue;
    1961             : 
    1962       36850 :         if( !rSalLayout.IsSpacingGlyph( aGlyphId ) )
    1963             :         {
    1964       35178 :             Point aAdjPoint = aOffset;
    1965       35178 :             aAdjPoint.X() += aRectangle.Left() + (aRectangle.GetWidth() - nEmphasisWidth) / 2;
    1966       35178 :             if ( mpFontEntry->mnOrientation )
    1967             :             {
    1968       24474 :                 Point aOriginPt(0, 0);
    1969       24474 :                 aOriginPt.RotateAround( aAdjPoint.X(), aAdjPoint.Y(), mpFontEntry->mnOrientation );
    1970             :             }
    1971       35178 :             aOutPoint += aAdjPoint;
    1972       35178 :             aOutPoint -= Point( nEmphasisWidth2, nEmphasisHeight2 );
    1973       35178 :             ImplDrawEmphasisMark( rSalLayout.DrawBase().X(),
    1974       70356 :                                   aOutPoint.X(), aOutPoint.Y(),
    1975      140712 :                                   aPolyPoly, bPolyLine, aRect1, aRect2 );
    1976             :         }
    1977       36850 :     }
    1978             : 
    1979       10674 :     SetLineColor( aOldLineColor );
    1980       10674 :     SetFillColor( aOldFillColor );
    1981       10674 :     EnableMapMode( bOldMap );
    1982       10674 :     mpMetaFile = pOldMetaFile;
    1983       10674 : }
    1984             : 
    1985         722 : SalLayout* OutputDevice::getFallbackFont(ImplFontEntry &rFallbackFont,
    1986             :     FontSelectPattern &rFontSelData, int nFallbackLevel,
    1987             :     ImplLayoutArgs& rLayoutArgs) const
    1988             : {
    1989         722 :     rFallbackFont.mnSetFontFlags = mpGraphics->SetFont( &rFontSelData, nFallbackLevel );
    1990             : 
    1991         722 :     rLayoutArgs.ResetPos();
    1992         722 :     SalLayout* pFallback = mpGraphics->GetTextLayout( rLayoutArgs, nFallbackLevel );
    1993             : 
    1994         722 :     if (!pFallback)
    1995           0 :         return NULL;
    1996             : 
    1997         722 :     if (!pFallback->LayoutText(rLayoutArgs))
    1998             :     {
    1999             :         // there is no need for a font that couldn't resolve anything
    2000           0 :         pFallback->Release();
    2001           0 :         return NULL;
    2002             :     }
    2003             : 
    2004         722 :     pFallback->AdjustLayout( rLayoutArgs );
    2005             : 
    2006         722 :     return pFallback;
    2007             : }
    2008             : 
    2009        1938 : SalLayout* OutputDevice::ImplGlyphFallbackLayout( SalLayout* pSalLayout, ImplLayoutArgs& rLayoutArgs ) const
    2010             : {
    2011             :     // This function relies on a valid mpFontEntry, if it doesn't exist bail out
    2012             :     // - we'd have crashed later on anyway. At least here we can catch the error in debug
    2013             :     // mode.
    2014        1938 :     if ( !mpFontEntry )
    2015             :     {
    2016             :         SAL_WARN ("vcl.gdi", "No font entry set in OutputDevice");
    2017             :         assert(mpFontEntry);
    2018           0 :         return NULL;
    2019             :     }
    2020             : 
    2021             :     // prepare multi level glyph fallback
    2022        1938 :     MultiSalLayout* pMultiSalLayout = NULL;
    2023        1938 :     ImplLayoutRuns aLayoutRuns = rLayoutArgs.maRuns;
    2024        1938 :     rLayoutArgs.PrepareFallback();
    2025        1938 :     rLayoutArgs.mnFlags |= SAL_LAYOUT_FOR_FALLBACK;
    2026             : 
    2027             :     // get list of unicodes that need glyph fallback
    2028        1938 :     int nCharPos = -1;
    2029        1938 :     bool bRTL = false;
    2030        3876 :     OUStringBuffer aMissingCodeBuf;
    2031        6116 :     while( rLayoutArgs.GetNextPos( &nCharPos, &bRTL) )
    2032        2240 :         aMissingCodeBuf.append( rLayoutArgs.mpStr[ nCharPos ] );
    2033        1938 :     rLayoutArgs.ResetPos();
    2034        3876 :     OUString aMissingCodes = aMissingCodeBuf.makeStringAndClear();
    2035             : 
    2036        3876 :     FontSelectPattern aFontSelData = mpFontEntry->maFontSelData;
    2037             : 
    2038             :     // try if fallback fonts support the missing unicodes
    2039        4766 :     for( int nFallbackLevel = 1; nFallbackLevel < MAX_FALLBACK; ++nFallbackLevel )
    2040             :     {
    2041             :         // find a font family suited for glyph fallback
    2042             : #ifndef FONTFALLBACK_HOOKS_DISABLED
    2043             :         // GetGlyphFallbackFont() needs a valid aFontSelData.mpFontEntry
    2044             :         // if the system-specific glyph fallback is active
    2045        4744 :         aFontSelData.mpFontEntry = mpFontEntry; // reset the fontentry to base-level
    2046             : #endif
    2047             :         ImplFontEntry* pFallbackFont = mpFontCache->GetGlyphFallbackFont( mpFontCollection,
    2048        4744 :             aFontSelData, nFallbackLevel, aMissingCodes );
    2049        4744 :         if( !pFallbackFont )
    2050        1228 :             break;
    2051             : 
    2052        3516 :         aFontSelData.mpFontEntry = pFallbackFont;
    2053        3516 :         aFontSelData.mpFontData = pFallbackFont->maFontSelData.mpFontData;
    2054        3516 :         if( nFallbackLevel < MAX_FALLBACK-1)
    2055             :         {
    2056             :             // ignore fallback font if it is the same as the original font
    2057        3494 :             if( mpFontEntry->maFontSelData.mpFontData == aFontSelData.mpFontData )
    2058             :             {
    2059        2794 :                 mpFontCache->Release( pFallbackFont );
    2060        2794 :                 continue;
    2061             :             }
    2062             :         }
    2063             : 
    2064             :         // create and add glyph fallback layout to multilayout
    2065             :         SalLayout* pFallback = getFallbackFont(*pFallbackFont, aFontSelData,
    2066         722 :             nFallbackLevel, rLayoutArgs);
    2067         722 :         if (pFallback)
    2068             :         {
    2069         722 :             if( !pMultiSalLayout )
    2070         714 :                 pMultiSalLayout = new MultiSalLayout( *pSalLayout );
    2071             :             pMultiSalLayout->AddFallback( *pFallback,
    2072         722 :                 rLayoutArgs.maRuns, aFontSelData.mpFontData );
    2073         722 :             if (nFallbackLevel == MAX_FALLBACK-1)
    2074          22 :                 pMultiSalLayout->SetInComplete();
    2075             :         }
    2076             : 
    2077         722 :         mpFontCache->Release( pFallbackFont );
    2078             : 
    2079             :         // break when this fallback was sufficient
    2080         722 :         if( !rLayoutArgs.PrepareFallback() )
    2081         688 :             break;
    2082             :     }
    2083             : 
    2084        1938 :     if( pMultiSalLayout && pMultiSalLayout->LayoutText( rLayoutArgs ) )
    2085         714 :         pSalLayout = pMultiSalLayout;
    2086             : 
    2087             :     // restore orig font settings
    2088        1938 :     pSalLayout->InitFont();
    2089        1938 :     rLayoutArgs.maRuns = aLayoutRuns;
    2090             : 
    2091        3876 :     return pSalLayout;
    2092             : }
    2093             : 
    2094           0 : long OutputDevice::GetMinKashida() const
    2095             : {
    2096           0 :     if( mbNewFont && !ImplNewFont() )
    2097           0 :         return 0;
    2098             : 
    2099           0 :     ImplFontEntry*      pEntry = mpFontEntry;
    2100           0 :     ImplFontMetricData* pMetric = &(pEntry->maMetric);
    2101           0 :     return ImplDevicePixelToLogicWidth( pMetric->mnMinKashida );
    2102             : }
    2103             : 
    2104           0 : sal_Int32 OutputDevice::ValidateKashidas ( const OUString& rTxt,
    2105             :                                             sal_Int32 nIdx, sal_Int32 nLen,
    2106             :                                             sal_Int32 nKashCount,
    2107             :                                             const sal_Int32* pKashidaPos,
    2108             :                                             sal_Int32* pKashidaPosDropped ) const
    2109             : {
    2110             :    // do layout
    2111           0 :     SalLayout* pSalLayout = ImplLayout( rTxt, nIdx, nLen );
    2112           0 :     if( !pSalLayout )
    2113           0 :         return 0;
    2114           0 :     sal_Int32 nDropped = 0;
    2115           0 :     for( int i = 0; i < nKashCount; ++i )
    2116             :     {
    2117           0 :         if( !pSalLayout->IsKashidaPosValid( pKashidaPos[ i ] ))
    2118             :         {
    2119           0 :             pKashidaPosDropped[ nDropped ] = pKashidaPos [ i ];
    2120           0 :             ++nDropped;
    2121             :         }
    2122             :     }
    2123           0 :     pSalLayout->Release();
    2124           0 :     return nDropped;
    2125             : }
    2126             : 
    2127        4974 : bool OutputDevice::GetGlyphBoundRects( const Point& rOrigin, const OUString& rStr,
    2128             :                                            int nIndex, int nLen, int nBase, MetricVector& rVector )
    2129             : {
    2130             : 
    2131        4974 :     rVector.clear();
    2132             : 
    2133        4974 :     if(nLen == 0x0FFFF)
    2134             :     {
    2135             :         SAL_INFO("sal.rtl.xub",
    2136             :                  "GetGlyphBoundRects Suspicious arguments nLen:" << nLen);
    2137             :     }
    2138             : 
    2139        4974 :     if( nIndex >= rStr.getLength() )
    2140        2870 :         return false;
    2141             : 
    2142        2104 :     if( nLen < 0 || nIndex + nLen >= rStr.getLength() )
    2143             :     {
    2144        2104 :         nLen = rStr.getLength() - nIndex;
    2145             :     }
    2146             : 
    2147        2104 :     Rectangle aRect;
    2148       28018 :     for( int i = 0; i < nLen; i++ )
    2149             :     {
    2150       25914 :         if( !GetTextBoundRect( aRect, rStr, nBase, nIndex + i, 1 ) )
    2151           0 :             break;
    2152       25914 :         aRect.Move( rOrigin.X(), rOrigin.Y() );
    2153       25914 :         rVector.push_back( aRect );
    2154             :     }
    2155             : 
    2156        2104 :     return (nLen == (int)rVector.size());
    2157             : }
    2158             : 
    2159       11114 : sal_Int32 OutputDevice::HasGlyphs( const vcl::Font& rTempFont, const OUString& rStr,
    2160             :     sal_Int32 nIndex, sal_Int32 nLen ) const
    2161             : {
    2162       11114 :     if( nIndex >= rStr.getLength() )
    2163           0 :         return nIndex;
    2164             :     sal_Int32 nEnd;
    2165       11114 :     if( nLen == -1 )
    2166       11114 :         nEnd = rStr.getLength();
    2167             :     else
    2168           0 :         nEnd = std::min( rStr.getLength(), nIndex + nLen );
    2169             : 
    2170             :     DBG_ASSERT( nIndex < nEnd, "StartPos >= EndPos?" );
    2171             :     DBG_ASSERT( nEnd <= rStr.getLength(), "String too short" );
    2172             : 
    2173             :     // to get the map temporarily set font
    2174       11114 :     const vcl::Font aOrigFont = GetFont();
    2175       11114 :     const_cast<OutputDevice&>(*this).SetFont( rTempFont );
    2176       22228 :     FontCharMapPtr pFontCharMap ( new FontCharMap() );
    2177       11114 :     bool bRet = GetFontCharMap( pFontCharMap );
    2178       11114 :     const_cast<OutputDevice&>(*this).SetFont( aOrigFont );
    2179             : 
    2180             :     // if fontmap is unknown assume it doesn't have the glyphs
    2181       11114 :     if( !bRet )
    2182           0 :         return nIndex;
    2183             : 
    2184       51382 :     for( sal_Int32 i = nIndex; nIndex < nEnd; ++i, ++nIndex )
    2185       48598 :         if( ! pFontCharMap->HasChar( rStr[i] ) )
    2186        8330 :             return nIndex;
    2187             : 
    2188        2784 :     pFontCharMap = 0;
    2189             : 
    2190       13898 :     return -1;
    2191        1233 : }
    2192             : 
    2193             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10