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

Generated by: LCOV version 1.11