LCOV - code coverage report
Current view: top level - vcl/generic/glyphs - gcach_ftyp.cxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 641 929 69.0 %
Date: 2014-04-11 Functions: 57 64 89.1 %
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 "gcach_ftyp.hxx"
      21             : 
      22             : #include "vcl/svapp.hxx"
      23             : #include <outfont.hxx>
      24             : #include <impfont.hxx>
      25             : #include <config_features.h>
      26             : #include <config_graphite.h>
      27             : #if ENABLE_GRAPHITE
      28             : #  include <graphite_static.hxx>
      29             : #  include <graphite2/Font.h>
      30             : #  include <graphite_layout.hxx>
      31             : #endif
      32             : #include <unotools/fontdefs.hxx>
      33             : 
      34             : #include "tools/poly.hxx"
      35             : #include "basegfx/matrix/b2dhommatrix.hxx"
      36             : #include "basegfx/matrix/b2dhommatrixtools.hxx"
      37             : #include "basegfx/polygon/b2dpolypolygon.hxx"
      38             : 
      39             : #include "osl/file.hxx"
      40             : #include "osl/thread.hxx"
      41             : 
      42             : #include "langboost.hxx"
      43             : #include "PhysicalFontCollection.hxx"
      44             : #include "sft.hxx"
      45             : 
      46             : #include <ft2build.h>
      47             : #include FT_FREETYPE_H
      48             : #include FT_GLYPH_H
      49             : #include FT_OUTLINE_H
      50             : #include FT_SIZES_H
      51             : #include FT_SYNTHESIS_H
      52             : #include FT_TRUETYPE_TABLES_H
      53             : #include FT_TRUETYPE_TAGS_H
      54             : #include FT_TRUETYPE_IDS_H
      55             : 
      56             : #include "rtl/instance.hxx"
      57             : 
      58             : typedef const FT_Vector* FT_Vector_CPtr;
      59             : 
      60             : #include <vector>
      61             : 
      62             : // TODO: move file mapping stuff to OSL
      63             : #include <unistd.h>
      64             : #include <fcntl.h>
      65             : #include <sys/stat.h>
      66             : #include <sys/mman.h>
      67             : #include "fontmanager.hxx"
      68             : 
      69             : // the gamma table makes artificial bold look better for CJK glyphs
      70             : static unsigned char aGammaTable[257];
      71             : 
      72         136 : static void InitGammaTable()
      73             : {
      74             :     static const int M_MAX = 255;
      75             :     static const int M_X   = 128;
      76             :     static const int M_Y   = 208;
      77             : 
      78             :     int x, a;
      79       34952 :     for( x = 0; x < 256; x++)
      80             :     {
      81       34816 :         if ( x <= M_X )
      82       17544 :             a = ( x * M_Y + M_X / 2) / M_X;
      83             :         else
      84       17272 :             a = M_Y + ( ( x - M_X ) * ( M_MAX - M_Y ) +
      85       17272 :                 ( M_MAX - M_X ) / 2 ) / ( M_MAX - M_X );
      86             : 
      87       34816 :         aGammaTable[x] = (unsigned char)a;
      88             :     }
      89         136 : }
      90             : 
      91             : static FT_Library aLibFT = 0;
      92             : 
      93             : // enable linking with old FT versions
      94             : static int nFTVERSION = 0;
      95             : 
      96             : typedef ::boost::unordered_map<const char*, boost::shared_ptr<FtFontFile>, rtl::CStringHash, rtl::CStringEqual> FontFileList;
      97             : 
      98             : namespace { struct vclFontFileList : public rtl::Static< FontFileList, vclFontFileList > {}; }
      99             : 
     100             : // TODO: remove when the priorities are selected by UI
     101             : // if (AH==0) => disable autohinting
     102             : // if (AA==0) => disable antialiasing
     103             : // if (EB==0) => disable embedded bitmaps
     104             : // if (AA prio <= AH prio) => antialias + autohint
     105             : // if (AH<AA) => do not autohint when antialiasing
     106             : // if (EB<AH) => do not autohint for monochrome
     107             : static int nDefaultPrioEmbedded    = 2;
     108             : static int nDefaultPrioAutoHint    = 1;
     109             : static int nDefaultPrioAntiAlias   = 1;
     110             : 
     111             : // FreetypeManager
     112             : 
     113       27880 : FtFontFile::FtFontFile( const OString& rNativeFileName )
     114             : :   maNativeFileName( rNativeFileName ),
     115             :     mpFileMap( NULL ),
     116             :     mnFileSize( 0 ),
     117             :     mnRefCount( 0 ),
     118       27880 :     mnLangBoost( 0 )
     119             : {
     120             :     // boost font preference if UI language is mentioned in filename
     121       27880 :     int nPos = maNativeFileName.lastIndexOf( '_' );
     122       27880 :     if( nPos == -1 || maNativeFileName[nPos+1] == '.' )
     123       25568 :         mnLangBoost += 0x1000;     // no langinfo => good
     124             :     else
     125             :     {
     126             :         static const char* pLangBoost = NULL;
     127             :         static bool bOnce = true;
     128        2312 :         if( bOnce )
     129             :         {
     130         136 :             bOnce = false;
     131         136 :             pLangBoost = vcl::getLangBoost();
     132             :         }
     133             : 
     134        2312 :         if( pLangBoost && !strncasecmp( pLangBoost, &maNativeFileName.getStr()[nPos+1], 3 ) )
     135           0 :            mnLangBoost += 0x2000;     // matching langinfo => better
     136             :     }
     137       27880 : }
     138             : 
     139       28560 : FtFontFile* FtFontFile::FindFontFile( const OString& rNativeFileName )
     140             : {
     141             :     // font file already known? (e.g. for ttc, synthetic, aliased fonts)
     142       28560 :     const char* pFileName = rNativeFileName.getStr();
     143       28560 :     FontFileList &rFontFileList = vclFontFileList::get();
     144       28560 :     FontFileList::const_iterator it = rFontFileList.find( pFileName );
     145       28560 :     if( it != rFontFileList.end() )
     146         680 :         return it->second.get();
     147             : 
     148             :     // no => create new one
     149       27880 :     FtFontFile* pFontFile = new FtFontFile( rNativeFileName );
     150       27880 :     pFileName = pFontFile->maNativeFileName.getStr();
     151       27880 :     rFontFileList[pFileName].reset(pFontFile);
     152       27880 :     return pFontFile;
     153             : }
     154             : 
     155         569 : bool FtFontFile::Map()
     156             : {
     157         569 :     if( mnRefCount++ <= 0 )
     158             :     {
     159         569 :         const char* pFileName = maNativeFileName.getStr();
     160         569 :         int nFile = open( pFileName, O_RDONLY );
     161         569 :         if( nFile < 0 )
     162           0 :             return false;
     163             : 
     164             :         struct stat aStat;
     165         569 :         int nRet = fstat( nFile, &aStat );
     166         569 :         if (nRet < 0)
     167             :         {
     168           0 :             close (nFile);
     169           0 :             return false;
     170             :         }
     171         569 :         mnFileSize = aStat.st_size;
     172             :         mpFileMap = (const unsigned char*)
     173         569 :             mmap( NULL, mnFileSize, PROT_READ, MAP_SHARED, nFile, 0 );
     174         569 :         if( mpFileMap == MAP_FAILED )
     175           0 :             mpFileMap = NULL;
     176         569 :         close( nFile );
     177             :     }
     178             : 
     179         569 :     return (mpFileMap != NULL);
     180             : }
     181             : 
     182         569 : void FtFontFile::Unmap()
     183             : {
     184         569 :     if( (--mnRefCount > 0) || (mpFileMap == NULL) )
     185         569 :         return;
     186             : 
     187         569 :     munmap( (char*)mpFileMap, mnFileSize );
     188         569 :     mpFileMap = NULL;
     189             : }
     190             : 
     191             : #if ENABLE_GRAPHITE
     192             : // wrap FtFontInfo's table function
     193           0 : const void * graphiteFontTable(const void* appFaceHandle, unsigned int name, size_t *len)
     194             : {
     195           0 :     const FtFontInfo * pFontInfo = reinterpret_cast<const FtFontInfo*>(appFaceHandle);
     196             :     typedef union {
     197             :         char m_c[5];
     198             :         unsigned int m_id;
     199             :     } TableId;
     200             :     TableId tableId;
     201           0 :     tableId.m_id = name;
     202             : #ifndef OSL_BIGENDIAN
     203             :     TableId swapped;
     204           0 :     swapped.m_c[3] = tableId.m_c[0];
     205           0 :     swapped.m_c[2] = tableId.m_c[1];
     206           0 :     swapped.m_c[1] = tableId.m_c[2];
     207           0 :     swapped.m_c[0] = tableId.m_c[3];
     208           0 :     tableId.m_id = swapped.m_id;
     209             : #endif
     210           0 :     tableId.m_c[4] = '\0';
     211           0 :     sal_uLong nLength = 0;
     212           0 :     const void * pTable = static_cast<const void*>(pFontInfo->GetTable(tableId.m_c, &nLength));
     213           0 :     if (len) *len = static_cast<size_t>(nLength);
     214           0 :     return pTable;
     215             : }
     216             : #endif
     217             : 
     218       28560 : FtFontInfo::FtFontInfo( const ImplDevFontAttributes& rDevFontAttributes,
     219             :     const OString& rNativeFileName, int nFaceNum, sal_IntPtr nFontId, int nSynthetic)
     220             : :
     221             :     maFaceFT( NULL ),
     222       28560 :     mpFontFile( FtFontFile::FindFontFile( rNativeFileName ) ),
     223             :     mnFaceNum( nFaceNum ),
     224             :     mnRefCount( 0 ),
     225             :     mnSynthetic( nSynthetic ),
     226             : #if ENABLE_GRAPHITE
     227             :     mbCheckedGraphite(false),
     228             :     mpGraphiteFace(NULL),
     229             : #endif
     230             :     mnFontId( nFontId ),
     231             :     maDevFontAttributes( rDevFontAttributes ),
     232             :     mpFontCharMap( NULL ),
     233             :     mpChar2Glyph( NULL ),
     234       57120 :     mpGlyph2Char( NULL )
     235             : {
     236             :     // prefer font with low ID
     237       28560 :     maDevFontAttributes.mnQuality += 10000 - nFontId;
     238             :     // prefer font with matching file names
     239       28560 :     maDevFontAttributes.mnQuality += mpFontFile->GetLangBoost();
     240       28560 : }
     241             : 
     242       57120 : FtFontInfo::~FtFontInfo()
     243             : {
     244       28560 :     if( mpFontCharMap )
     245         160 :         mpFontCharMap->DeReference();
     246       28560 :     delete mpChar2Glyph;
     247       28560 :     delete mpGlyph2Char;
     248             : #if ENABLE_GRAPHITE
     249       28560 :     delete mpGraphiteFace;
     250             : #endif
     251       28560 : }
     252             : 
     253         566 : void FtFontInfo::InitHashes() const
     254             : {
     255             :     // TODO: avoid pointers when empty stl::hash_* objects become cheap
     256         566 :     mpChar2Glyph = new Int2IntMap();
     257         566 :     mpGlyph2Char = new Int2IntMap();
     258         566 : }
     259             : 
     260        3702 : FT_FaceRec_* FtFontInfo::GetFaceFT()
     261             : {
     262        3702 :     if (!maFaceFT && mpFontFile->Map())
     263             :     {
     264             :         FT_Error rc = FT_New_Memory_Face( aLibFT,
     265         569 :             (FT_Byte*)mpFontFile->GetBuffer(),
     266        1138 :             mpFontFile->GetFileSize(), mnFaceNum, &maFaceFT );
     267         569 :         if( (rc != FT_Err_Ok) || (maFaceFT->num_glyphs <= 0) )
     268           0 :             maFaceFT = NULL;
     269             :     }
     270             : 
     271        3702 :    ++mnRefCount;
     272        3702 :    return maFaceFT;
     273             : }
     274             : 
     275             : #if ENABLE_GRAPHITE
     276        2227 : GraphiteFaceWrapper * FtFontInfo::GetGraphiteFace()
     277             : {
     278        2227 :     if (mbCheckedGraphite)
     279        2183 :         return mpGraphiteFace;
     280             :     // test for graphite here so that it is cached most efficiently
     281          44 :     if (GetTable("Silf", 0))
     282             :     {
     283           0 :         static const char* pGraphiteCacheStr = getenv( "SAL_GRAPHITE_CACHE_SIZE" );
     284           0 :         int graphiteSegCacheSize = pGraphiteCacheStr ? (atoi(pGraphiteCacheStr)) : 0;
     285             :         gr_face * pGraphiteFace;
     286           0 :         if (graphiteSegCacheSize > 500)
     287           0 :             pGraphiteFace = gr_make_face_with_seg_cache(this, graphiteFontTable, graphiteSegCacheSize, gr_face_cacheCmap);
     288             :         else
     289           0 :             pGraphiteFace = gr_make_face(this, graphiteFontTable, gr_face_cacheCmap);
     290           0 :         if (pGraphiteFace)
     291           0 :             mpGraphiteFace = new GraphiteFaceWrapper(pGraphiteFace);
     292             :     }
     293          44 :     mbCheckedGraphite = true;
     294          44 :     return mpGraphiteFace;
     295             : }
     296             : #endif
     297             : 
     298        3702 : void FtFontInfo::ReleaseFaceFT()
     299             : {
     300        3702 :     if (--mnRefCount <= 0)
     301             :     {
     302         569 :         FT_Done_Face( maFaceFT );
     303         569 :         maFaceFT = NULL;
     304         569 :         mpFontFile->Unmap();
     305             :     }
     306        3702 : }
     307             : 
     308       32050 : static unsigned GetUInt( const unsigned char* p ) { return((p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3]);}
     309       13587 : static unsigned GetUShort( const unsigned char* p ){ return((p[0]<<8)+p[1]);}
     310             : //static signed GetSShort( const unsigned char* p ){ return((short)((p[0]<<8)+p[1]));}
     311             : 
     312             : static const sal_uInt32 T_true = 0x74727565;        /* 'true' */
     313             : static const sal_uInt32 T_ttcf = 0x74746366;        /* 'ttcf' */
     314             : static const sal_uInt32 T_otto = 0x4f54544f;        /* 'OTTO' */
     315             : 
     316       12565 : const unsigned char* FtFontInfo::GetTable( const char* pTag, sal_uLong* pLength ) const
     317             : {
     318       12565 :     const unsigned char* pBuffer = mpFontFile->GetBuffer();
     319       12565 :     int nFileSize = mpFontFile->GetFileSize();
     320       12565 :     if( !pBuffer || nFileSize<1024 )
     321           0 :         return NULL;
     322             : 
     323             :     // we currently handle TTF, TTC and OTF headers
     324       12565 :     unsigned nFormat = GetUInt( pBuffer );
     325             : 
     326       12565 :     const unsigned char* p = pBuffer + 12;
     327       12565 :     if( nFormat == T_ttcf )         // TTC_MAGIC
     328          32 :         p += GetUInt( p + 4 * mnFaceNum );
     329       12533 :     else if( nFormat != 0x00010000 && nFormat != T_true && nFormat != T_otto) // TTF_MAGIC and Apple TTF Magic and PS-OpenType font
     330         448 :         return NULL;
     331             : 
     332             :     // walk table directory until match
     333       12117 :     int nTables = GetUShort( p - 8 );
     334       12117 :     if( nTables >= 64 )  // something fishy?
     335           0 :         return NULL;
     336       83424 :     for( int i = 0; i < nTables; ++i, p+=16 )
     337             :     {
     338       80681 :         if( p[0]==pTag[0] && p[1]==pTag[1] && p[2]==pTag[2] && p[3]==pTag[3] )
     339             :         {
     340        9374 :             sal_uLong nLength = GetUInt( p + 12 );
     341        9374 :             if( pLength != NULL )
     342        9374 :                 *pLength = nLength;
     343        9374 :             const unsigned char* pTable = pBuffer + GetUInt( p + 8 );
     344        9374 :             if( (pTable + nLength) <= (mpFontFile->GetBuffer() + nFileSize) )
     345        9374 :                 return pTable;
     346             :         }
     347             :     }
     348             : 
     349        2743 :     return NULL;
     350             : }
     351             : 
     352       28980 : void FtFontInfo::AnnounceFont( PhysicalFontCollection* pFontCollection )
     353             : {
     354       28980 :     ImplFTSFontData* pFD = new ImplFTSFontData( this, maDevFontAttributes );
     355       28980 :     pFontCollection->Add( pFD );
     356       28980 : }
     357             : 
     358         136 : FreetypeManager::FreetypeManager()
     359         136 : :   mnMaxFontId( 0 )
     360             : {
     361         136 :     /*FT_Error rcFT =*/ FT_Init_FreeType( &aLibFT );
     362             : 
     363         136 :     FT_Int nMajor = 0, nMinor = 0, nPatch = 0;
     364         136 :     FT_Library_Version(aLibFT, &nMajor, &nMinor, &nPatch);
     365         136 :     nFTVERSION = nMajor * 1000 + nMinor * 100 + nPatch;
     366             : 
     367             :     // TODO: remove when the priorities are selected by UI
     368             :     char* pEnv;
     369         136 :     pEnv = ::getenv( "SAL_EMBEDDED_BITMAP_PRIORITY" );
     370         136 :     if( pEnv )
     371           0 :         nDefaultPrioEmbedded  = pEnv[0] - '0';
     372         136 :     pEnv = ::getenv( "SAL_ANTIALIASED_TEXT_PRIORITY" );
     373         136 :     if( pEnv )
     374           0 :         nDefaultPrioAntiAlias = pEnv[0] - '0';
     375         136 :     pEnv = ::getenv( "SAL_AUTOHINTING_PRIORITY" );
     376         136 :     if( pEnv )
     377           0 :         nDefaultPrioAutoHint  = pEnv[0] - '0';
     378             : 
     379         136 :     InitGammaTable();
     380         136 :     vclFontFileList::get();
     381         136 : }
     382             : 
     383     1128011 : FT_Face ServerFont::GetFtFace() const
     384             : {
     385     1128011 :     FT_Activate_Size( maSizeFT );
     386             : 
     387     1128011 :     return maFaceFT;
     388             : }
     389             : 
     390         272 : FreetypeManager::~FreetypeManager()
     391             : {
     392         136 :     ClearFontList();
     393         136 : }
     394             : 
     395       28980 : void FreetypeManager::AddFontFile( const OString& rNormalizedName,
     396             :     int nFaceNum, sal_IntPtr nFontId, const ImplDevFontAttributes& rDevFontAttr)
     397             : {
     398       28980 :     if( rNormalizedName.isEmpty() )
     399           0 :         return;
     400             : 
     401       28980 :     if( maFontList.find( nFontId ) != maFontList.end() )
     402         420 :         return;
     403             : 
     404             :     FtFontInfo* pFontInfo = new FtFontInfo( rDevFontAttr,
     405       28560 :         rNormalizedName, nFaceNum, nFontId, 0);
     406       28560 :     maFontList[ nFontId ] = pFontInfo;
     407       28560 :     if( mnMaxFontId < nFontId )
     408         136 :         mnMaxFontId = nFontId;
     409             : }
     410             : 
     411         138 : void FreetypeManager::AnnounceFonts( PhysicalFontCollection* pToAdd ) const
     412             : {
     413       29118 :     for( FontList::const_iterator it = maFontList.begin(); it != maFontList.end(); ++it )
     414             :     {
     415       28980 :         FtFontInfo* pFtFontInfo = it->second;
     416       28980 :         pFtFontInfo->AnnounceFont( pToAdd );
     417             :     }
     418         138 : }
     419             : 
     420         136 : void FreetypeManager::ClearFontList( )
     421             : {
     422       28696 :     for( FontList::iterator it = maFontList.begin(); it != maFontList.end(); ++it )
     423             :     {
     424       28560 :         FtFontInfo* pFtFontInfo = it->second;
     425       28560 :         delete pFtFontInfo;
     426             :     }
     427         136 :     maFontList.clear();
     428         136 : }
     429             : 
     430        3702 : ServerFont* FreetypeManager::CreateFont( const FontSelectPattern& rFSD )
     431             : {
     432        3702 :     FtFontInfo* pFontInfo = NULL;
     433             : 
     434             :     // find a FontInfo matching to the font id
     435        3702 :     sal_IntPtr nFontId = reinterpret_cast<sal_IntPtr>( rFSD.mpFontData );
     436        3702 :     FontList::iterator it = maFontList.find( nFontId );
     437        3702 :     if( it != maFontList.end() )
     438        3702 :         pFontInfo = it->second;
     439             : 
     440        3702 :     if( !pFontInfo )
     441           0 :         return NULL;
     442             : 
     443        3702 :     ServerFont* pNew = new ServerFont( rFSD, pFontInfo );
     444             : 
     445        3702 :     return pNew;
     446             : }
     447             : 
     448       28980 : ImplFTSFontData::ImplFTSFontData( FtFontInfo* pFI, const ImplDevFontAttributes& rDFA )
     449             : :   PhysicalFontFace( rDFA, IFTSFONT_MAGIC ),
     450       28980 :     mpFtFontInfo( pFI )
     451             : {
     452       28980 :     mbDevice        = false;
     453       28980 :     mbOrientation   = true;
     454       28980 : }
     455             : 
     456        8633 : ImplFontEntry* ImplFTSFontData::CreateFontInstance( FontSelectPattern& rFSD ) const
     457             : {
     458        8633 :     ImplServerFontEntry* pEntry = new ImplServerFontEntry( rFSD );
     459        8633 :     return pEntry;
     460             : }
     461             : 
     462             : // ServerFont
     463             : 
     464        3702 : ServerFont::ServerFont( const FontSelectPattern& rFSD, FtFontInfo* pFI )
     465             : :   maGlyphList( 0),
     466             :     maFontSelData(rFSD),
     467             :     mnRefCount(1),
     468             :     mnBytesUsed( sizeof(ServerFont) ),
     469             :     mpPrevGCFont( NULL ),
     470             :     mpNextGCFont( NULL ),
     471             :     mnCos( 0x10000),
     472             :     mnSin( 0 ),
     473             :     mbCollectedZW( false ),
     474             :     mnPrioEmbedded(nDefaultPrioEmbedded),
     475             :     mnPrioAntiAlias(nDefaultPrioAntiAlias),
     476             :     mnPrioAutoHint(nDefaultPrioAutoHint),
     477             :     mpFontInfo( pFI ),
     478             :     maFaceFT( NULL ),
     479             :     maSizeFT( NULL ),
     480             :     mbFaceOk( false ),
     481        3702 :     mpLayoutEngine( NULL )
     482             : {
     483             :     // TODO: move update of mpFontEntry into FontEntry class when
     484             :     // it becomes reponsible for the ServerFont instantiation
     485        3702 :     ((ImplServerFontEntry*)rFSD.mpFontEntry)->SetServerFont( this );
     486             : 
     487        3702 :     if( rFSD.mnOrientation != 0 )
     488             :     {
     489         149 :         const double dRad = rFSD.mnOrientation * ( F_2PI / 3600.0 );
     490         149 :         mnCos = static_cast<long>( 0x10000 * cos( dRad ) + 0.5 );
     491         149 :         mnSin = static_cast<long>( 0x10000 * sin( dRad ) + 0.5 );
     492             :     }
     493             : 
     494        3702 :     maFaceFT = pFI->GetFaceFT();
     495             : 
     496        3702 :     if( !maFaceFT )
     497           0 :         return;
     498             : 
     499             :     // set the pixel size of the font instance
     500        3702 :     mnWidth = rFSD.mnWidth;
     501        3702 :     if( !mnWidth )
     502        3280 :         mnWidth = rFSD.mnHeight;
     503        3702 :     mfStretch = (double)mnWidth / rFSD.mnHeight;
     504             :     // sanity check (e.g. #i66394#, #i66244#, #66537#)
     505        3702 :     if( (mnWidth < 0) || (mfStretch > +64.0) || (mfStretch < -64.0) )
     506           0 :         return;
     507             : 
     508        3702 :     FT_New_Size( maFaceFT, &maSizeFT );
     509        3702 :     FT_Activate_Size( maSizeFT );
     510        3702 :     FT_Error rc = FT_Set_Pixel_Sizes( maFaceFT, mnWidth, rFSD.mnHeight );
     511        3702 :     if( rc != FT_Err_Ok )
     512           0 :         return;
     513             : 
     514        3702 :     FT_Select_Charmap(maFaceFT, FT_ENCODING_UNICODE);
     515             : 
     516        3702 :     if( mpFontInfo->IsSymbolFont() )
     517             :     {
     518          17 :         FT_Encoding eEncoding = FT_ENCODING_MS_SYMBOL;
     519          17 :         if (!FT_IS_SFNT(maFaceFT))
     520          17 :             eEncoding = FT_ENCODING_ADOBE_CUSTOM; // freetype wants this for PS symbol fonts
     521             : 
     522          17 :         FT_Select_Charmap(maFaceFT, eEncoding);
     523             :     }
     524             : 
     525        3702 :     mbFaceOk = true;
     526             : 
     527        3702 :     ApplyGSUB( rFSD );
     528             : 
     529             :     // TODO: query GASP table for load flags
     530        3702 :     mnLoadFlags = FT_LOAD_DEFAULT;
     531             : #if 1 // #i97326# cairo sometimes uses FT_Set_Transform() on our FT_FACE
     532             :     // we are not using FT_Set_Transform() yet, so just ignore it for now
     533        3702 :     mnLoadFlags |= FT_LOAD_IGNORE_TRANSFORM;
     534             : #endif
     535             : 
     536        3702 :     mbArtItalic = (rFSD.GetSlant() != ITALIC_NONE && pFI->GetFontAttributes().GetSlant() == ITALIC_NONE);
     537        3702 :     mbArtBold = (rFSD.GetWeight() > WEIGHT_MEDIUM && pFI->GetFontAttributes().GetWeight() <= WEIGHT_MEDIUM);
     538        3702 :     mbUseGamma = false;
     539        3702 :     if( mbArtBold )
     540             :     {
     541             :         //static const int TT_CODEPAGE_RANGE_874  = (1L << 16); // Thai
     542             :         //static const int TT_CODEPAGE_RANGE_932  = (1L << 17); // JIS/Japan
     543             :         //static const int TT_CODEPAGE_RANGE_936  = (1L << 18); // Chinese: Simplified
     544             :         //static const int TT_CODEPAGE_RANGE_949  = (1L << 19); // Korean Wansung
     545             :         //static const int TT_CODEPAGE_RANGE_950  = (1L << 20); // Chinese: Traditional
     546             :         //static const int TT_CODEPAGE_RANGE_1361 = (1L << 21); // Korean Johab
     547             :         static const int TT_CODEPAGE_RANGES1_CJKT = 0x3F0000; // all of the above
     548           6 :         const TT_OS2* pOs2 = (const TT_OS2*)FT_Get_Sfnt_Table( maFaceFT, ft_sfnt_os2 );
     549           6 :         if ((pOs2) && (pOs2->ulCodePageRange1 & TT_CODEPAGE_RANGES1_CJKT )
     550           3 :         && rFSD.mnHeight < 20)
     551           1 :         mbUseGamma = true;
     552             :     }
     553             : 
     554        3702 :     if( ((mnCos != 0) && (mnSin != 0)) || (mnPrioEmbedded <= 0) )
     555          73 :         mnLoadFlags |= FT_LOAD_NO_BITMAP;
     556             : }
     557             : 
     558           0 : void ServerFont::SetFontOptions( boost::shared_ptr<ImplFontOptions> pFontOptions)
     559             : {
     560           0 :     mpFontOptions = pFontOptions;
     561             : 
     562           0 :     if (!mpFontOptions)
     563           0 :         return;
     564             : 
     565           0 :     FontAutoHint eHint = mpFontOptions->GetUseAutoHint();
     566           0 :     if( eHint == AUTOHINT_DONTKNOW )
     567           0 :         eHint = mbUseGamma ? AUTOHINT_TRUE : AUTOHINT_FALSE;
     568             : 
     569           0 :     if( eHint == AUTOHINT_TRUE )
     570           0 :         mnLoadFlags |= FT_LOAD_FORCE_AUTOHINT;
     571             : 
     572           0 :     if( (mnSin != 0) && (mnCos != 0) ) // hinting for 0/90/180/270 degrees only
     573           0 :         mnLoadFlags |= FT_LOAD_NO_HINTING;
     574           0 :     mnLoadFlags |= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH; //#88334#
     575             : 
     576           0 :     if( mpFontOptions->DontUseAntiAlias() )
     577           0 :       mnPrioAntiAlias = 0;
     578           0 :     if( mpFontOptions->DontUseEmbeddedBitmaps() )
     579           0 :       mnPrioEmbedded = 0;
     580           0 :     if( mpFontOptions->DontUseHinting() )
     581           0 :       mnPrioAutoHint = 0;
     582             : 
     583           0 :     if( mnPrioAutoHint <= 0 )
     584           0 :         mnLoadFlags |= FT_LOAD_NO_HINTING;
     585             : 
     586             : #if defined(FT_LOAD_TARGET_LIGHT) && defined(FT_LOAD_TARGET_NORMAL)
     587           0 :     if( !(mnLoadFlags & FT_LOAD_NO_HINTING) )
     588             :     {
     589           0 :        mnLoadFlags |= FT_LOAD_TARGET_NORMAL;
     590           0 :        switch( mpFontOptions->GetHintStyle() )
     591             :        {
     592             :            case HINT_NONE:
     593           0 :                 mnLoadFlags |= FT_LOAD_NO_HINTING;
     594           0 :                 break;
     595             :            case HINT_SLIGHT:
     596           0 :                 mnLoadFlags |= FT_LOAD_TARGET_LIGHT;
     597           0 :                 break;
     598             :            case HINT_MEDIUM:
     599           0 :                 break;
     600             :            case HINT_FULL:
     601             :            default:
     602           0 :                 break;
     603             :        }
     604             :     }
     605             : #endif
     606             : 
     607           0 :     if( mnPrioEmbedded <= 0 )
     608           0 :         mnLoadFlags |= FT_LOAD_NO_BITMAP;
     609             : }
     610             : 
     611           0 : boost::shared_ptr<ImplFontOptions> ServerFont::GetFontOptions() const
     612             : {
     613           0 :     return mpFontOptions;
     614             : }
     615             : 
     616           0 : const OString* ServerFont::GetFontFileName() const
     617             : {
     618           0 :     return mpFontInfo->GetFontFileName();
     619             : }
     620             : 
     621      192049 : bool ServerFont::TestFont() const
     622             : {
     623      192049 :     return mbFaceOk;
     624             : }
     625             : 
     626       11106 : ServerFont::~ServerFont()
     627             : {
     628        3702 :     if( mpLayoutEngine )
     629        2833 :         delete mpLayoutEngine;
     630             : 
     631        3702 :     if( maSizeFT )
     632        3702 :         FT_Done_Size( maSizeFT );
     633             : 
     634        3702 :     mpFontInfo->ReleaseFaceFT();
     635             : 
     636        3702 :     ReleaseFromGarbageCollect();
     637        7404 : }
     638             : 
     639        2833 : int ServerFont::GetEmUnits() const
     640             : {
     641        2833 :     return maFaceFT->units_per_EM;
     642             : }
     643             : 
     644        8243 : void ServerFont::FetchFontMetric( ImplFontMetricData& rTo, long& rFactor ) const
     645             : {
     646        8243 :     static_cast<ImplFontAttributes&>(rTo) = mpFontInfo->GetFontAttributes();
     647             : 
     648        8243 :     rTo.mbScalableFont  = true;
     649        8243 :     rTo.mbDevice        = true;
     650        8243 :     rTo.mbKernableFont  = FT_HAS_KERNING( maFaceFT ) != 0;
     651        8243 :     rTo.mnOrientation = GetFontSelData().mnOrientation;
     652             : 
     653             :     //Always consider [star]symbol as symbol fonts
     654        8243 :     if ( IsStarSymbol( rTo.GetFamilyName() ) )
     655         782 :         rTo.SetSymbolFlag( true );
     656             : 
     657        8243 :     FT_Activate_Size( maSizeFT );
     658             : 
     659        8243 :     rFactor = 0x100;
     660             : 
     661        8243 :     const TT_OS2* pOS2 = (const TT_OS2*)FT_Get_Sfnt_Table( maFaceFT, ft_sfnt_os2 );
     662        8243 :     const double fScale = (double)GetFontSelData().mnHeight / maFaceFT->units_per_EM;
     663             : 
     664        8243 :     rTo.mnAscent = 0;
     665        8243 :     rTo.mnDescent = 0;
     666        8243 :     rTo.mnExtLeading = 0;
     667        8243 :     rTo.mnSlant = 0;
     668        8243 :     rTo.mnWidth = mnWidth;
     669             : 
     670             :     // Calculating ascender and descender:
     671             :     // FreeType >= 2.4.6 does the right thing, so we just use what it gives us,
     672             :     // for earlier versions we emulate its behaviour;
     673             :     // take them from 'hhea' table,
     674             :     // if zero take them from 'OS/2' table,
     675             :     // if zero take them from FreeType's font metrics
     676        8243 :     if (nFTVERSION >= 2406)
     677             :     {
     678        8243 :         const FT_Size_Metrics& rMetrics = maFaceFT->size->metrics;
     679        8243 :         rTo.mnAscent = (rMetrics.ascender + 32) >> 6;
     680        8243 :         rTo.mnDescent = (-rMetrics.descender + 32) >> 6;
     681        8243 :         rTo.mnExtLeading = ((rMetrics.height + 32) >> 6) - (rTo.mnAscent + rTo.mnDescent);
     682             :     }
     683             :     else
     684             :     {
     685           0 :         const TT_HoriHeader* pHHea = (const TT_HoriHeader*)FT_Get_Sfnt_Table(maFaceFT, ft_sfnt_hhea);
     686           0 :         if (pHHea)
     687             :         {
     688           0 :             rTo.mnAscent = pHHea->Ascender * fScale + 0.5;
     689           0 :             rTo.mnDescent = -pHHea->Descender * fScale + 0.5;
     690           0 :             rTo.mnExtLeading = pHHea->Line_Gap * fScale + 0.5;
     691             :         }
     692             : 
     693           0 :         if (!(rTo.mnAscent || rTo.mnDescent))
     694             :         {
     695           0 :             if (pOS2 && (pOS2->version != 0xFFFF))
     696             :             {
     697           0 :                 if (pOS2->sTypoAscender || pOS2->sTypoDescender)
     698             :                 {
     699           0 :                     rTo.mnAscent = pOS2->sTypoAscender * fScale + 0.5;
     700           0 :                     rTo.mnDescent = -pOS2->sTypoDescender * fScale + 0.5;
     701           0 :                     rTo.mnExtLeading = pOS2->sTypoLineGap * fScale + 0.5;
     702             :                 }
     703             :                 else
     704             :                 {
     705           0 :                     rTo.mnAscent = pOS2->usWinAscent * fScale + 0.5;
     706           0 :                     rTo.mnDescent = pOS2->usWinDescent * fScale + 0.5;
     707           0 :                     rTo.mnExtLeading = 0;
     708             :                 }
     709             :             }
     710             :         }
     711             : 
     712           0 :         if (!(rTo.mnAscent || rTo.mnDescent))
     713             :         {
     714           0 :             const FT_Size_Metrics& rMetrics = maFaceFT->size->metrics;
     715           0 :             rTo.mnAscent = (rMetrics.ascender + 32) >> 6;
     716           0 :             rTo.mnDescent = (-rMetrics.descender + 32) >> 6;
     717           0 :             rTo.mnExtLeading = ((rMetrics.height + 32) >> 6) - (rTo.mnAscent + rTo.mnDescent);
     718             :         }
     719             :     }
     720             : 
     721        8243 :     rTo.mnIntLeading = rTo.mnAscent + rTo.mnDescent - (maFaceFT->units_per_EM * fScale + 0.5);
     722             : 
     723        8243 :     if( pOS2 && (pOS2->version != 0xFFFF) )
     724             :     {
     725             :         // map the panose info from the OS2 table to their VCL counterparts
     726        8042 :         switch( pOS2->panose[0] )
     727             :         {
     728           0 :             case 1: rTo.SetFamilyType( FAMILY_ROMAN ); break;
     729        7260 :             case 2: rTo.SetFamilyType( FAMILY_SWISS ); break;
     730           0 :             case 3: rTo.SetFamilyType( FAMILY_MODERN ); break;
     731           0 :             case 4: rTo.SetFamilyType( FAMILY_SCRIPT ); break;
     732         782 :             case 5: rTo.SetFamilyType( FAMILY_DECORATIVE ); break;
     733             :             // TODO: is it reasonable to override the attribute with DONTKNOW?
     734             :             case 0: // fall through
     735           0 :             default: rTo.meFamilyType = FAMILY_DONTKNOW; break;
     736             :         }
     737             : 
     738        8042 :         switch( pOS2->panose[3] )
     739             :         {
     740             :             case 2: // fall through
     741             :             case 3: // fall through
     742             :             case 4: // fall through
     743             :             case 5: // fall through
     744             :             case 6: // fall through
     745             :             case 7: // fall through
     746        7157 :             case 8: rTo.SetPitch( PITCH_VARIABLE ); break;
     747         102 :             case 9: rTo.SetPitch( PITCH_FIXED ); break;
     748             :             // TODO: is it reasonable to override the attribute with DONTKNOW?
     749             :             case 0: // fall through
     750             :             case 1: // fall through
     751         783 :             default: rTo.SetPitch( PITCH_DONTKNOW ); break;
     752             :         }
     753             :     }
     754             : 
     755             :     // initialize kashida width
     756             :     // TODO: what if there are different versions of this glyph available
     757        8243 :     const int nKashidaGlyphId = GetRawGlyphIndex( 0x0640 );
     758        8243 :     if( nKashidaGlyphId )
     759             :     {
     760        1125 :         GlyphData aGlyphData;
     761        1125 :         InitGlyphData( nKashidaGlyphId, aGlyphData );
     762        1125 :         rTo.mnMinKashida = aGlyphData.GetMetric().GetCharWidth();
     763             :     }
     764        8243 : }
     765             : 
     766       54068 : static inline void SplitGlyphFlags( const ServerFont& rFont, sal_GlyphId& rGlyphId, int& nGlyphFlags )
     767             : {
     768       54068 :     nGlyphFlags = rGlyphId & GF_FLAGMASK;
     769       54068 :     rGlyphId &= GF_IDXMASK;
     770             : 
     771       54068 :     if( rGlyphId & GF_ISCHAR )
     772           0 :         rGlyphId = rFont.GetRawGlyphIndex( rGlyphId );
     773       54068 : }
     774             : 
     775       54040 : int ServerFont::ApplyGlyphTransform( int nGlyphFlags,
     776             :     FT_Glyph pGlyphFT, bool bForBitmapProcessing ) const
     777             : {
     778       54040 :     int nAngle = GetFontSelData().mnOrientation;
     779             :     // shortcut most common case
     780       54040 :     if( !nAngle && !nGlyphFlags )
     781       52000 :         return nAngle;
     782             : 
     783        2040 :     const FT_Size_Metrics& rMetrics = maFaceFT->size->metrics;
     784             :     FT_Vector aVector;
     785             :     FT_Matrix aMatrix;
     786             : 
     787        2040 :     bool bStretched = false;
     788             : 
     789        2040 :     switch( nGlyphFlags & GF_ROTMASK )
     790             :     {
     791             :     default:    // straight
     792        2040 :         aVector.x = 0;
     793        2040 :         aVector.y = 0;
     794        2040 :         aMatrix.xx = +mnCos;
     795        2040 :         aMatrix.yy = +mnCos;
     796        2040 :         aMatrix.xy = -mnSin;
     797        2040 :         aMatrix.yx = +mnSin;
     798        2040 :         break;
     799             :     case GF_ROTL:    // left
     800           0 :         nAngle += 900;
     801           0 :         bStretched = (mfStretch != 1.0);
     802           0 :         aVector.x  = (FT_Pos)(+rMetrics.descender * mfStretch);
     803           0 :         aVector.y  = -rMetrics.ascender;
     804           0 :         aMatrix.xx = (FT_Pos)(-mnSin / mfStretch);
     805           0 :         aMatrix.yy = (FT_Pos)(-mnSin * mfStretch);
     806           0 :         aMatrix.xy = (FT_Pos)(-mnCos * mfStretch);
     807           0 :         aMatrix.yx = (FT_Pos)(+mnCos / mfStretch);
     808           0 :         break;
     809             :     case GF_ROTR:    // right
     810           0 :         nAngle -= 900;
     811           0 :         bStretched = (mfStretch != 1.0);
     812           0 :         aVector.x = -maFaceFT->glyph->metrics.horiAdvance;
     813           0 :         aVector.x += (FT_Pos)(rMetrics.descender * mnSin/65536.0);
     814           0 :         aVector.y  = (FT_Pos)(-rMetrics.descender * mfStretch * mnCos/65536.0);
     815           0 :         aMatrix.xx = (FT_Pos)(+mnSin / mfStretch);
     816           0 :         aMatrix.yy = (FT_Pos)(+mnSin * mfStretch);
     817           0 :         aMatrix.xy = (FT_Pos)(+mnCos * mfStretch);
     818           0 :         aMatrix.yx = (FT_Pos)(-mnCos / mfStretch);
     819           0 :         break;
     820             :     }
     821             : 
     822        4080 :     while( nAngle < 0 )
     823           0 :         nAngle += 3600;
     824             : 
     825        2040 :     if( pGlyphFT->format != FT_GLYPH_FORMAT_BITMAP )
     826             :     {
     827        2040 :         FT_Glyph_Transform( pGlyphFT, NULL, &aVector );
     828             : 
     829             :         // orthogonal transforms are better handled by bitmap operations
     830        2040 :         if( bStretched || (bForBitmapProcessing && (nAngle % 900) != 0) )
     831             :         {
     832             :             // apply non-orthogonal or stretch transformations
     833         463 :             FT_Glyph_Transform( pGlyphFT, &aMatrix, NULL );
     834         463 :             nAngle = 0;
     835             :         }
     836             :     }
     837             :     else
     838             :     {
     839             :         // FT<=2005 ignores transforms for bitmaps, so do it manually
     840           0 :         FT_BitmapGlyph pBmpGlyphFT = reinterpret_cast<FT_BitmapGlyph>(pGlyphFT);
     841           0 :         pBmpGlyphFT->left += (aVector.x + 32) >> 6;
     842           0 :         pBmpGlyphFT->top  += (aVector.y + 32) >> 6;
     843             :     }
     844             : 
     845        2040 :     return nAngle;
     846             : }
     847             : 
     848    15114202 : sal_GlyphId ServerFont::GetRawGlyphIndex(sal_UCS4 aChar, sal_UCS4 aVS) const
     849             : {
     850    15114202 :     if( mpFontInfo->IsSymbolFont() )
     851             :     {
     852         625 :         if( !FT_IS_SFNT( maFaceFT ) )
     853             :         {
     854         625 :             if( (aChar & 0xFF00) == 0xF000 )
     855         142 :                 aChar &= 0xFF;    // PS font symbol mapping
     856         483 :             else if( aChar > 0xFF )
     857         187 :                 return 0;
     858             :         }
     859             :     }
     860             : 
     861    15114015 :     int nGlyphIndex = 0;
     862             : #if HAVE_FT_FACE_GETCHARVARIANTINDEX
     863             :     // If asked, check first for variant glyph with the given Unicode variation
     864             :     // selector. This is quite uncommon so we don't bother with caching here.
     865             :     // Disabled for buggy FreeType versions:
     866             :     // https://bugzilla.mozilla.org/show_bug.cgi?id=618406#c8
     867    15114015 :     if (aVS && nFTVERSION >= 2404)
     868           0 :         nGlyphIndex = FT_Face_GetCharVariantIndex(maFaceFT, aChar, aVS);
     869             : #endif
     870             : 
     871    15114015 :     if (nGlyphIndex == 0)
     872             :     {
     873             :         // cache glyph indexes in font info to share between different sizes
     874    15114015 :         nGlyphIndex = mpFontInfo->GetGlyphIndex( aChar );
     875    15114015 :         if( nGlyphIndex < 0 )
     876             :         {
     877       14280 :             nGlyphIndex = FT_Get_Char_Index( maFaceFT, aChar );
     878       14280 :             if( !nGlyphIndex)
     879             :             {
     880             :                 // check if symbol aliasing helps
     881         367 :                 if( (aChar <= 0x00FF) && mpFontInfo->IsSymbolFont() )
     882           0 :                     nGlyphIndex = FT_Get_Char_Index( maFaceFT, aChar | 0xF000 );
     883             :             }
     884       14280 :             mpFontInfo->CacheGlyphIndex( aChar, nGlyphIndex );
     885             :         }
     886             :     }
     887             : 
     888    15114015 :     return sal_GlyphId( nGlyphIndex);
     889             : }
     890             : 
     891    15088830 : sal_GlyphId ServerFont::FixupGlyphIndex( sal_GlyphId aGlyphId, sal_UCS4 aChar ) const
     892             : {
     893    15088830 :     int nGlyphFlags = GF_NONE;
     894             : 
     895             :     // do glyph substitution if necessary
     896             :     // CJK vertical writing needs special treatment
     897    15088830 :     if( GetFontSelData().mbVertical )
     898             :     {
     899             :         // TODO: rethink when GSUB is used for non-vertical case
     900         256 :         GlyphSubstitution::const_iterator it = maGlyphSubstitution.find( aGlyphId );
     901         256 :         if( it == maGlyphSubstitution.end() )
     902             :         {
     903         256 :             sal_GlyphId nTemp = GetVerticalChar( aChar );
     904         256 :             if( nTemp ) // is substitution possible
     905           0 :                 nTemp = GetRawGlyphIndex( nTemp );
     906         256 :             if( nTemp ) // substitute manually if sensible
     907           0 :                 aGlyphId = nTemp | (GF_GSUB | GF_ROTL);
     908             :             else
     909         256 :                 nGlyphFlags |= GetVerticalFlags( aChar );
     910             :         }
     911             :         else
     912             :         {
     913             :             // for vertical GSUB also compensate for nOrientation=2700
     914           0 :             aGlyphId = (*it).second;
     915           0 :             nGlyphFlags |= GF_GSUB | GF_ROTL;
     916             :         }
     917             :     }
     918             : 
     919    15088830 :     if( aGlyphId != 0 )
     920    15088017 :         aGlyphId |= nGlyphFlags;
     921             : 
     922    15088830 :     return aGlyphId;
     923             : }
     924             : 
     925           0 : sal_GlyphId ServerFont::GetGlyphIndex( sal_UCS4 aChar ) const
     926             : {
     927           0 :     sal_GlyphId aGlyphId = GetRawGlyphIndex( aChar );
     928           0 :     aGlyphId = FixupGlyphIndex( aGlyphId, aChar );
     929           0 :     return aGlyphId;
     930             : }
     931             : 
     932       43402 : static int lcl_GetCharWidth( FT_FaceRec_* pFaceFT, double fStretch, int nGlyphFlags )
     933             : {
     934       43402 :     int nCharWidth = pFaceFT->glyph->metrics.horiAdvance;
     935             : 
     936       43402 :     if( nGlyphFlags & GF_ROTMASK )  // for bVertical rotated glyphs
     937             :     {
     938           0 :         const FT_Size_Metrics& rMetrics = pFaceFT->size->metrics;
     939           0 :         nCharWidth = (int)((rMetrics.height + rMetrics.descender) * fStretch);
     940             :     }
     941             : 
     942       43402 :     return (nCharWidth + 32) >> 6;
     943             : }
     944             : 
     945       43423 : void ServerFont::InitGlyphData( sal_GlyphId aGlyphId, GlyphData& rGD ) const
     946             : {
     947       43423 :     FT_Activate_Size( maSizeFT );
     948             : 
     949             :     int nGlyphFlags;
     950       43423 :     SplitGlyphFlags( *this, aGlyphId, nGlyphFlags );
     951             : 
     952       43423 :     int nLoadFlags = mnLoadFlags;
     953             : 
     954             : //  if( mbArtItalic )
     955             : //      nLoadFlags |= FT_LOAD_NO_BITMAP;
     956             : 
     957       43423 :     FT_Error rc = FT_Load_Glyph( maFaceFT, aGlyphId, nLoadFlags );
     958             : 
     959       43423 :     if( rc != FT_Err_Ok )
     960             :     {
     961             :         // we get here e.g. when a PS font lacks the default glyph
     962           0 :         rGD.SetCharWidth( 0 );
     963           0 :         rGD.SetDelta( 0, 0 );
     964           0 :         rGD.SetOffset( 0, 0 );
     965           0 :         rGD.SetSize( Size( 0, 0 ) );
     966       43423 :         return;
     967             :     }
     968             : 
     969       43423 :     const bool bOriginallyZeroWidth = (maFaceFT->glyph->metrics.horiAdvance == 0);
     970       43423 :     if (mbArtBold)
     971           7 :         FT_GlyphSlot_Embolden(maFaceFT->glyph);
     972             : 
     973       43423 :     const int nCharWidth = bOriginallyZeroWidth ? 0 : lcl_GetCharWidth( maFaceFT, mfStretch, nGlyphFlags );
     974       43423 :     rGD.SetCharWidth( nCharWidth );
     975             : 
     976             :     FT_Glyph pGlyphFT;
     977       43423 :     rc = FT_Get_Glyph( maFaceFT->glyph, &pGlyphFT );
     978             : 
     979       43423 :     ApplyGlyphTransform( nGlyphFlags, pGlyphFT, false );
     980       43423 :     rGD.SetDelta( (pGlyphFT->advance.x + 0x8000) >> 16, -((pGlyphFT->advance.y + 0x8000) >> 16) );
     981             : 
     982             :     FT_BBox aBbox;
     983       43423 :     FT_Glyph_Get_CBox( pGlyphFT, FT_GLYPH_BBOX_PIXELS, &aBbox );
     984       43423 :     if( aBbox.yMin > aBbox.yMax )   // circumvent freetype bug
     985             :     {
     986           0 :         int t=aBbox.yMin; aBbox.yMin=aBbox.yMax, aBbox.yMax=t;
     987             :     }
     988             : 
     989       43423 :     rGD.SetOffset( aBbox.xMin, -aBbox.yMax );
     990       43423 :     rGD.SetSize( Size( (aBbox.xMax-aBbox.xMin+1), (aBbox.yMax-aBbox.yMin) ) );
     991             : 
     992       43423 :     FT_Done_Glyph( pGlyphFT );
     993             : }
     994             : 
     995           0 : bool ServerFont::GetAntialiasAdvice( void ) const
     996             : {
     997           0 :     if( GetFontSelData().mbNonAntialiased || (mnPrioAntiAlias<=0) )
     998           0 :         return false;
     999           0 :     bool bAdviseAA = true;
    1000             :     // TODO: also use GASP info
    1001           0 :     return bAdviseAA;
    1002             : }
    1003             : 
    1004           1 : bool ServerFont::GetGlyphBitmap1( sal_GlyphId aGlyphId, RawBitmap& rRawBitmap ) const
    1005             : {
    1006           1 :     FT_Activate_Size( maSizeFT );
    1007             : 
    1008             :     int nGlyphFlags;
    1009           1 :     SplitGlyphFlags( *this, aGlyphId, nGlyphFlags );
    1010             : 
    1011           1 :     FT_Int nLoadFlags = mnLoadFlags;
    1012             :     // #i70930# force mono-hinting for monochrome text
    1013           1 :     nLoadFlags &= ~0xF0000;
    1014           1 :     nLoadFlags |= FT_LOAD_TARGET_MONO;
    1015             : 
    1016           1 :     if( mbArtItalic )
    1017           0 :         nLoadFlags |= FT_LOAD_NO_BITMAP;
    1018             : 
    1019             :     // for 0/90/180/270 degree fonts enable hinting even if not advisable
    1020             :     // non-hinted and non-antialiased bitmaps just look too ugly
    1021           1 :     if( (mnCos==0 || mnSin==0) && (mnPrioAutoHint > 0) )
    1022           1 :         nLoadFlags &= ~FT_LOAD_NO_HINTING;
    1023             : 
    1024           1 :     if( mnPrioEmbedded <= mnPrioAutoHint )
    1025           0 :         nLoadFlags |= FT_LOAD_NO_BITMAP;
    1026             : 
    1027           1 :     FT_Error rc = FT_Load_Glyph( maFaceFT, aGlyphId, nLoadFlags );
    1028             : 
    1029           1 :     if( rc != FT_Err_Ok )
    1030           0 :         return false;
    1031             : 
    1032           1 :     if (mbArtBold)
    1033           0 :         FT_GlyphSlot_Embolden(maFaceFT->glyph);
    1034             : 
    1035             :     FT_Glyph pGlyphFT;
    1036           1 :     rc = FT_Get_Glyph( maFaceFT->glyph, &pGlyphFT );
    1037           1 :     if( rc != FT_Err_Ok )
    1038           0 :         return false;
    1039             : 
    1040           1 :     int nAngle = ApplyGlyphTransform( nGlyphFlags, pGlyphFT, true );
    1041             : 
    1042           1 :     if( mbArtItalic )
    1043             :     {
    1044             :         FT_Matrix aMatrix;
    1045           0 :         aMatrix.xx = aMatrix.yy = 0x10000L;
    1046           0 :         aMatrix.xy = 0x6000L, aMatrix.yx = 0;
    1047           0 :         FT_Glyph_Transform( pGlyphFT, &aMatrix, NULL );
    1048             :     }
    1049             : 
    1050             :     // Check for zero area bounding boxes as this crashes some versions of FT.
    1051             :     // This also provides a handy short cut as much of the code following
    1052             :     //  becomes an expensive nop when a glyph covers no pixels.
    1053             :     FT_BBox cbox;
    1054           1 :     FT_Glyph_Get_CBox(pGlyphFT, ft_glyph_bbox_unscaled, &cbox);
    1055             : 
    1056           1 :     if( (cbox.xMax - cbox.xMin) == 0 || (cbox.yMax - cbox.yMin == 0) )
    1057             :     {
    1058           0 :         nAngle = 0;
    1059           0 :         memset(&rRawBitmap, 0, sizeof rRawBitmap);
    1060           0 :         FT_Done_Glyph( pGlyphFT );
    1061           0 :         return true;
    1062             :     }
    1063             : 
    1064           1 :     if( pGlyphFT->format != FT_GLYPH_FORMAT_BITMAP )
    1065             :     {
    1066           1 :         if( pGlyphFT->format == FT_GLYPH_FORMAT_OUTLINE )
    1067           1 :             ((FT_OutlineGlyphRec*)pGlyphFT)->outline.flags |= FT_OUTLINE_HIGH_PRECISION;
    1068           1 :         FT_Render_Mode nRenderMode = FT_RENDER_MODE_MONO;
    1069             : 
    1070           1 :         rc = FT_Glyph_To_Bitmap( &pGlyphFT, nRenderMode, NULL, true );
    1071           1 :         if( rc != FT_Err_Ok )
    1072             :         {
    1073           0 :             FT_Done_Glyph( pGlyphFT );
    1074           0 :             return false;
    1075             :         }
    1076             :     }
    1077             : 
    1078           1 :     const FT_BitmapGlyph pBmpGlyphFT = reinterpret_cast<const FT_BitmapGlyph>(pGlyphFT);
    1079             :     // NOTE: autohinting in FT<=2.0.2 miscalculates the offsets below by +-1
    1080           1 :     rRawBitmap.mnXOffset        = +pBmpGlyphFT->left;
    1081           1 :     rRawBitmap.mnYOffset        = -pBmpGlyphFT->top;
    1082             : 
    1083           1 :     const FT_Bitmap& rBitmapFT  = pBmpGlyphFT->bitmap;
    1084           1 :     rRawBitmap.mnHeight         = rBitmapFT.rows;
    1085           1 :     rRawBitmap.mnBitCount       = 1;
    1086           1 :     rRawBitmap.mnWidth          = rBitmapFT.width;
    1087           1 :     rRawBitmap.mnScanlineSize   = rBitmapFT.pitch;
    1088             : 
    1089           1 :     const sal_uLong nNeededSize = rRawBitmap.mnScanlineSize * rRawBitmap.mnHeight;
    1090             : 
    1091           1 :     if( rRawBitmap.mnAllocated < nNeededSize )
    1092             :     {
    1093           1 :         rRawBitmap.mnAllocated = 2*nNeededSize;
    1094           1 :         rRawBitmap.mpBits.reset(new unsigned char[ rRawBitmap.mnAllocated ]);
    1095             :     }
    1096             : 
    1097           1 :     if (!mbArtBold)
    1098             :     {
    1099           1 :         memcpy( rRawBitmap.mpBits.get(), rBitmapFT.buffer, nNeededSize );
    1100             :     }
    1101             :     else
    1102             :     {
    1103           0 :         memset( rRawBitmap.mpBits.get(), 0, nNeededSize );
    1104           0 :         const unsigned char* pSrcLine = rBitmapFT.buffer;
    1105           0 :         unsigned char* pDstLine = rRawBitmap.mpBits.get();
    1106           0 :         for( int h = rRawBitmap.mnHeight; --h >= 0; )
    1107             :         {
    1108           0 :             memcpy( pDstLine, pSrcLine, rBitmapFT.pitch );
    1109           0 :             pDstLine += rRawBitmap.mnScanlineSize;
    1110           0 :             pSrcLine += rBitmapFT.pitch;
    1111             :         }
    1112             : 
    1113           0 :         unsigned char* p = rRawBitmap.mpBits.get();
    1114           0 :         for( sal_uLong y=0; y < rRawBitmap.mnHeight; y++ )
    1115             :         {
    1116           0 :             unsigned char nLastByte = 0;
    1117           0 :             for( sal_uLong x=0; x < rRawBitmap.mnScanlineSize; x++ )
    1118             :             {
    1119           0 :             unsigned char nTmp = p[x] << 7;
    1120           0 :             p[x] |= (p[x] >> 1) | nLastByte;
    1121           0 :             nLastByte = nTmp;
    1122             :             }
    1123           0 :             p += rRawBitmap.mnScanlineSize;
    1124             :         }
    1125             :     }
    1126             : 
    1127           1 :     FT_Done_Glyph( pGlyphFT );
    1128             : 
    1129             :     // special case for 0/90/180/270 degree orientation
    1130           1 :     switch( nAngle )
    1131             :     {
    1132             :         case  -900:
    1133             :         case  +900:
    1134             :         case +1800:
    1135             :         case +2700:
    1136           0 :             rRawBitmap.Rotate( nAngle );
    1137           0 :             break;
    1138             :     }
    1139             : 
    1140           1 :     return true;
    1141             : }
    1142             : 
    1143        9253 : bool ServerFont::GetGlyphBitmap8( sal_GlyphId aGlyphId, RawBitmap& rRawBitmap ) const
    1144             : {
    1145        9253 :     FT_Activate_Size( maSizeFT );
    1146             : 
    1147             :     int nGlyphFlags;
    1148        9253 :     SplitGlyphFlags( *this, aGlyphId, nGlyphFlags );
    1149             : 
    1150        9253 :     FT_Int nLoadFlags = mnLoadFlags;
    1151             : 
    1152        9253 :     if( mbArtItalic )
    1153           1 :         nLoadFlags |= FT_LOAD_NO_BITMAP;
    1154             : 
    1155        9253 :     if( (nGlyphFlags & GF_UNHINTED) || (mnPrioAutoHint < mnPrioAntiAlias) )
    1156           0 :         nLoadFlags |= FT_LOAD_NO_HINTING;
    1157             : 
    1158        9253 :     if( mnPrioEmbedded <= mnPrioAntiAlias )
    1159           0 :         nLoadFlags |= FT_LOAD_NO_BITMAP;
    1160             : 
    1161        9253 :     FT_Error rc = FT_Load_Glyph( maFaceFT, aGlyphId, nLoadFlags );
    1162             : 
    1163        9253 :     if( rc != FT_Err_Ok )
    1164           0 :         return false;
    1165             : 
    1166        9253 :     if (mbArtBold)
    1167           2 :         FT_GlyphSlot_Embolden(maFaceFT->glyph);
    1168             : 
    1169             :     FT_Glyph pGlyphFT;
    1170        9253 :     rc = FT_Get_Glyph( maFaceFT->glyph, &pGlyphFT );
    1171        9253 :     if( rc != FT_Err_Ok )
    1172           0 :         return false;
    1173             : 
    1174        9253 :     int nAngle = ApplyGlyphTransform( nGlyphFlags, pGlyphFT, true );
    1175             : 
    1176        9253 :     if( mbArtItalic )
    1177             :     {
    1178             :         FT_Matrix aMatrix;
    1179           1 :         aMatrix.xx = aMatrix.yy = 0x10000L;
    1180           1 :         aMatrix.xy = 0x6000L, aMatrix.yx = 0;
    1181           1 :         FT_Glyph_Transform( pGlyphFT, &aMatrix, NULL );
    1182             :     }
    1183             : 
    1184        9253 :     if( pGlyphFT->format == FT_GLYPH_FORMAT_OUTLINE )
    1185        9251 :         ((FT_OutlineGlyph)pGlyphFT)->outline.flags |= FT_OUTLINE_HIGH_PRECISION;
    1186             : 
    1187        9253 :     bool bEmbedded = (pGlyphFT->format == FT_GLYPH_FORMAT_BITMAP);
    1188        9253 :     if( !bEmbedded )
    1189             :     {
    1190        9251 :         rc = FT_Glyph_To_Bitmap( &pGlyphFT, FT_RENDER_MODE_NORMAL, NULL, true );
    1191        9251 :         if( rc != FT_Err_Ok )
    1192             :         {
    1193           0 :             FT_Done_Glyph( pGlyphFT );
    1194           0 :             return false;
    1195             :         }
    1196             :     }
    1197             : 
    1198        9253 :     const FT_BitmapGlyph pBmpGlyphFT = reinterpret_cast<const FT_BitmapGlyph>(pGlyphFT);
    1199        9253 :     rRawBitmap.mnXOffset        = +pBmpGlyphFT->left;
    1200        9253 :     rRawBitmap.mnYOffset        = -pBmpGlyphFT->top;
    1201             : 
    1202        9253 :     const FT_Bitmap& rBitmapFT  = pBmpGlyphFT->bitmap;
    1203        9253 :     rRawBitmap.mnHeight         = rBitmapFT.rows;
    1204        9253 :     rRawBitmap.mnWidth          = rBitmapFT.width;
    1205        9253 :     rRawBitmap.mnBitCount       = 8;
    1206        9253 :     rRawBitmap.mnScanlineSize   = bEmbedded ? rBitmapFT.width : rBitmapFT.pitch;
    1207        9253 :     rRawBitmap.mnScanlineSize = (rRawBitmap.mnScanlineSize + 3) & -4;
    1208             : 
    1209        9253 :     const sal_uLong nNeededSize = rRawBitmap.mnScanlineSize * rRawBitmap.mnHeight;
    1210        9253 :     if( rRawBitmap.mnAllocated < nNeededSize )
    1211             :     {
    1212        8938 :         rRawBitmap.mnAllocated = 2*nNeededSize;
    1213        8938 :         rRawBitmap.mpBits.reset(new unsigned char[ rRawBitmap.mnAllocated ]);
    1214             :     }
    1215             : 
    1216        9253 :     const unsigned char* pSrc = rBitmapFT.buffer;
    1217        9253 :     unsigned char* pDest = rRawBitmap.mpBits.get();
    1218        9253 :     if( !bEmbedded )
    1219             :     {
    1220      116906 :         for( int y = rRawBitmap.mnHeight, x; --y >= 0 ; )
    1221             :         {
    1222     1190028 :             for( x = 0; x < rBitmapFT.width; ++x )
    1223     1091624 :                 *(pDest++) = *(pSrc++);
    1224      254548 :             for(; x < int(rRawBitmap.mnScanlineSize); ++x )
    1225      156144 :                 *(pDest++) = 0;
    1226             :         }
    1227             :     }
    1228             :     else
    1229             :     {
    1230          28 :         for( int y = rRawBitmap.mnHeight, x; --y >= 0 ; )
    1231             :         {
    1232          24 :             unsigned char nSrc = 0;
    1233         336 :             for( x = 0; x < rBitmapFT.width; ++x, nSrc+=nSrc )
    1234             :             {
    1235         312 :                 if( (x & 7) == 0 )
    1236          48 :                     nSrc = *(pSrc++);
    1237         312 :                 *(pDest++) = (0x7F - nSrc) >> 8;
    1238             :             }
    1239          96 :             for(; x < int(rRawBitmap.mnScanlineSize); ++x )
    1240          72 :                 *(pDest++) = 0;
    1241             :         }
    1242             :     }
    1243             : 
    1244        9253 :     if( !bEmbedded && mbUseGamma )
    1245             :     {
    1246           0 :         unsigned char* p = rRawBitmap.mpBits.get();
    1247           0 :         for( sal_uLong y=0; y < rRawBitmap.mnHeight; y++ )
    1248             :         {
    1249           0 :             for( sal_uLong x=0; x < rRawBitmap.mnWidth; x++ )
    1250             :             {
    1251           0 :                 p[x] = aGammaTable[ p[x] ];
    1252             :             }
    1253           0 :             p += rRawBitmap.mnScanlineSize;
    1254             :         }
    1255             :     }
    1256             : 
    1257        9253 :     FT_Done_Glyph( pGlyphFT );
    1258             : 
    1259             :     // special case for 0/90/180/270 degree orientation
    1260        9253 :     switch( nAngle )
    1261             :     {
    1262             :         case  -900:
    1263             :         case  +900:
    1264             :         case +1800:
    1265             :         case +2700:
    1266         348 :             rRawBitmap.Rotate( nAngle );
    1267         348 :             break;
    1268             :     }
    1269             : 
    1270        9253 :     return true;
    1271             : }
    1272             : 
    1273             : // determine unicode ranges in font
    1274             : 
    1275        5100 : const ImplFontCharMap* ServerFont::GetImplFontCharMap( void ) const
    1276             : {
    1277        5100 :     const ImplFontCharMap* pIFCMap = mpFontInfo->GetImplFontCharMap();
    1278        5100 :     return pIFCMap;
    1279             : }
    1280             : 
    1281        5100 : const ImplFontCharMap* FtFontInfo::GetImplFontCharMap( void )
    1282             : {
    1283             :     // check if the charmap is already cached
    1284        5100 :     if( mpFontCharMap )
    1285        4940 :         return mpFontCharMap;
    1286             : 
    1287             :     // get the charmap and cache it
    1288         160 :     CmapResult aCmapResult;
    1289         160 :     bool bOK = GetFontCodeRanges( aCmapResult );
    1290         160 :     if( bOK )
    1291         160 :         mpFontCharMap = new ImplFontCharMap( aCmapResult );
    1292             :     else
    1293           0 :                mpFontCharMap = ImplFontCharMap::GetDefaultMap();
    1294         160 :     mpFontCharMap->AddReference();
    1295         160 :     return mpFontCharMap;
    1296             : }
    1297             : 
    1298             : // TODO: merge into method GetFontCharMap()
    1299         160 : bool FtFontInfo::GetFontCodeRanges( CmapResult& rResult ) const
    1300             : {
    1301         160 :     rResult.mbSymbolic = IsSymbolFont();
    1302             : 
    1303             :     // TODO: is the full CmapResult needed on platforms calling this?
    1304         160 :     if( FT_IS_SFNT( maFaceFT ) )
    1305             :     {
    1306         160 :         sal_uLong nLength = 0;
    1307         160 :         const unsigned char* pCmap = GetTable( "cmap", &nLength );
    1308         160 :         if( pCmap && (nLength > 0) )
    1309         160 :             if( ParseCMAP( pCmap, nLength, rResult ) )
    1310         160 :                 return true;
    1311             :     }
    1312             : 
    1313             :     typedef std::vector<sal_uInt32> U32Vector;
    1314           0 :     U32Vector aCodes;
    1315             : 
    1316             :     // FT's coverage is available since FT>=2.1.0 (OOo-baseline>=2.1.4 => ok)
    1317           0 :     aCodes.reserve( 0x1000 );
    1318             :     FT_UInt nGlyphIndex;
    1319           0 :     for( sal_uInt32 cCode = FT_Get_First_Char( maFaceFT, &nGlyphIndex );; )
    1320             :     {
    1321           0 :         if( !nGlyphIndex )
    1322           0 :             break;
    1323           0 :         aCodes.push_back( cCode );  // first code inside range
    1324           0 :         sal_uInt32 cNext = cCode;
    1325           0 :         do cNext = FT_Get_Next_Char( maFaceFT, cCode, &nGlyphIndex ); while( cNext == ++cCode );
    1326           0 :         aCodes.push_back( cCode );  // first code outside range
    1327           0 :         cCode = cNext;
    1328           0 :     }
    1329             : 
    1330           0 :     const int nCount = aCodes.size();
    1331           0 :     if( !nCount) {
    1332           0 :         if( !rResult.mbSymbolic )
    1333           0 :             return false;
    1334             : 
    1335             :         // we usually get here for Type1 symbol fonts
    1336           0 :         aCodes.push_back( 0xF020 );
    1337           0 :         aCodes.push_back( 0xF100 );
    1338             :     }
    1339             : 
    1340           0 :     sal_uInt32* pCodes = new sal_uInt32[ nCount ];
    1341           0 :     for( int i = 0; i < nCount; ++i )
    1342           0 :         pCodes[i] = aCodes[i];
    1343           0 :     rResult.mpRangeCodes = pCodes;
    1344           0 :     rResult.mnRangeCount = nCount / 2;
    1345           0 :     return true;
    1346             : }
    1347             : 
    1348         522 : bool ServerFont::GetFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const
    1349             : {
    1350         522 :     bool bRet = false;
    1351             : 
    1352         522 :     sal_uLong nLength = 0;
    1353             :     // load GSUB table
    1354         522 :     const FT_Byte* pGSUB = mpFontInfo->GetTable("GSUB", &nLength);
    1355         522 :     if (pGSUB)
    1356         522 :         vcl::getTTScripts(rFontCapabilities.maGSUBScriptTags, pGSUB, nLength);
    1357             : 
    1358             :     // load OS/2 table
    1359         522 :     const FT_Byte* pOS2 = mpFontInfo->GetTable("OS/2", &nLength);
    1360         522 :     if (pOS2)
    1361             :     {
    1362             :         bRet = vcl::getTTCoverage(
    1363             :             rFontCapabilities.maUnicodeRange,
    1364             :             rFontCapabilities.maCodePageRange,
    1365         522 :             pOS2, nLength);
    1366             :     }
    1367             : 
    1368         522 :     return bRet;
    1369             : }
    1370             : 
    1371             : // outline stuff
    1372             : 
    1373             : class PolyArgs
    1374             : {
    1375             : public:
    1376             :                 PolyArgs( PolyPolygon& rPolyPoly, sal_uInt16 nMaxPoints );
    1377             :                 ~PolyArgs();
    1378             : 
    1379             :     void        AddPoint( long nX, long nY, PolyFlags);
    1380             :     void        ClosePolygon();
    1381             : 
    1382       16683 :     long        GetPosX() const { return maPosition.x;}
    1383       16683 :     long        GetPosY() const { return maPosition.y;}
    1384             : 
    1385             : private:
    1386             :     PolyPolygon& mrPolyPoly;
    1387             : 
    1388             :     Point*      mpPointAry;
    1389             :     sal_uInt8*       mpFlagAry;
    1390             : 
    1391             :     FT_Vector   maPosition;
    1392             :     sal_uInt16      mnMaxPoints;
    1393             :     sal_uInt16      mnPoints;
    1394             :     sal_uInt16      mnPoly;
    1395             :     bool        bHasOffline;
    1396             : };
    1397             : 
    1398        1363 : PolyArgs::PolyArgs( PolyPolygon& rPolyPoly, sal_uInt16 nMaxPoints )
    1399             : :   mrPolyPoly(rPolyPoly),
    1400             :     mnMaxPoints(nMaxPoints),
    1401             :     mnPoints(0),
    1402             :     mnPoly(0),
    1403        1363 :     bHasOffline(false)
    1404             : {
    1405        1363 :     mpPointAry  = new Point[ mnMaxPoints ];
    1406        1363 :     mpFlagAry   = new sal_uInt8 [ mnMaxPoints ];
    1407        1363 :     maPosition.x = maPosition.y = 0;
    1408        1363 : }
    1409             : 
    1410        1363 : PolyArgs::~PolyArgs()
    1411             : {
    1412        1363 :     delete[] mpFlagAry;
    1413        1363 :     delete[] mpPointAry;
    1414        1363 : }
    1415             : 
    1416       61412 : void PolyArgs::AddPoint( long nX, long nY, PolyFlags aFlag )
    1417             : {
    1418             :     DBG_ASSERT( (mnPoints < mnMaxPoints), "FTGlyphOutline: AddPoint overflow!" );
    1419       61412 :     if( mnPoints >= mnMaxPoints )
    1420       61412 :         return;
    1421             : 
    1422       61412 :     maPosition.x = nX;
    1423       61412 :     maPosition.y = nY;
    1424       61412 :     mpPointAry[ mnPoints ] = Point( nX, nY );
    1425       61412 :     mpFlagAry[ mnPoints++ ]= aFlag;
    1426       61412 :     bHasOffline |= (aFlag != POLY_NORMAL);
    1427             : }
    1428             : 
    1429        3565 : void PolyArgs::ClosePolygon()
    1430             : {
    1431        3565 :     if( !mnPoly++ )
    1432        4928 :         return;
    1433             : 
    1434             :     // freetype seems to always close the polygon with an ON_CURVE point
    1435             :     // PolyPoly wants to close the polygon itself => remove last point
    1436             :     DBG_ASSERT( (mnPoints >= 2), "FTGlyphOutline: PolyFinishNum failed!" );
    1437        2202 :     --mnPoints;
    1438             :     DBG_ASSERT( (mpPointAry[0]==mpPointAry[mnPoints]), "FTGlyphOutline: PolyFinishEq failed!" );
    1439             :     DBG_ASSERT( (mpFlagAry[0]==POLY_NORMAL), "FTGlyphOutline: PolyFinishFE failed!" );
    1440             :     DBG_ASSERT( (mpFlagAry[mnPoints]==POLY_NORMAL), "FTGlyphOutline: PolyFinishFS failed!" );
    1441             : 
    1442        2202 :     Polygon aPoly( mnPoints, mpPointAry, (bHasOffline ? mpFlagAry : NULL) );
    1443             : 
    1444             :     // #i35928#
    1445             :     // This may be a invalid polygons, e.g. the last point is a control point.
    1446             :     // So close the polygon (and add the first point again) if the last point
    1447             :     // is a control point or different from first.
    1448             :     // #i48298#
    1449             :     // Now really duplicating the first point, to close or correct the
    1450             :     // polygon. Also no longer duplicating the flags, but enforcing
    1451             :     // POLY_NORMAL for the newly added last point.
    1452        2202 :     const sal_uInt16 nPolySize(aPoly.GetSize());
    1453        2202 :     if(nPolySize)
    1454             :     {
    1455        5883 :         if((aPoly.HasFlags() && POLY_CONTROL == aPoly.GetFlags(nPolySize - 1))
    1456        3384 :             || (aPoly.GetPoint(nPolySize - 1) != aPoly.GetPoint(0)))
    1457             :         {
    1458        2161 :             aPoly.SetSize(nPolySize + 1);
    1459        2161 :             aPoly.SetPoint(aPoly.GetPoint(0), nPolySize);
    1460             : 
    1461        2161 :             if(aPoly.HasFlags())
    1462             :             {
    1463        1472 :                 aPoly.SetFlags(nPolySize, POLY_NORMAL);
    1464             :             }
    1465             :         }
    1466             :     }
    1467             : 
    1468        2202 :     mrPolyPoly.Insert( aPoly );
    1469        2202 :     mnPoints = 0;
    1470        2202 :     bHasOffline = false;
    1471             : }
    1472             : 
    1473             : extern "C" {
    1474             : 
    1475             : // TODO: wait till all compilers accept that calling conventions
    1476             : // for functions are the same independent of implementation constness,
    1477             : // then uncomment the const-tokens in the function interfaces below
    1478        2202 : static int FT_move_to( FT_Vector_CPtr p0, void* vpPolyArgs )
    1479             : {
    1480        2202 :     PolyArgs& rA = *reinterpret_cast<PolyArgs*>(vpPolyArgs);
    1481             : 
    1482             :     // move_to implies a new polygon => finish old polygon first
    1483        2202 :     rA.ClosePolygon();
    1484             : 
    1485        2202 :     rA.AddPoint( p0->x, p0->y, POLY_NORMAL );
    1486        2202 :     return 0;
    1487             : }
    1488             : 
    1489        9161 : static int FT_line_to( FT_Vector_CPtr p1, void* vpPolyArgs )
    1490             : {
    1491        9161 :     PolyArgs& rA = *reinterpret_cast<PolyArgs*>(vpPolyArgs);
    1492        9161 :     rA.AddPoint( p1->x, p1->y, POLY_NORMAL );
    1493        9161 :     return 0;
    1494             : }
    1495             : 
    1496       16683 : static int FT_conic_to( FT_Vector_CPtr p1, FT_Vector_CPtr p2, void* vpPolyArgs )
    1497             : {
    1498       16683 :     PolyArgs& rA = *reinterpret_cast<PolyArgs*>(vpPolyArgs);
    1499             : 
    1500             :     // VCL's Polygon only knows cubic beziers
    1501       16683 :     const long nX1 = (2 * rA.GetPosX() + 4 * p1->x + 3) / 6;
    1502       16683 :     const long nY1 = (2 * rA.GetPosY() + 4 * p1->y + 3) / 6;
    1503       16683 :     rA.AddPoint( nX1, nY1, POLY_CONTROL );
    1504             : 
    1505       16683 :     const long nX2 = (2 * p2->x + 4 * p1->x + 3) / 6;
    1506       16683 :     const long nY2 = (2 * p2->y + 4 * p1->y + 3) / 6;
    1507       16683 :     rA.AddPoint( nX2, nY2, POLY_CONTROL );
    1508             : 
    1509       16683 :     rA.AddPoint( p2->x, p2->y, POLY_NORMAL );
    1510       16683 :     return 0;
    1511             : }
    1512             : 
    1513           0 : static int FT_cubic_to( FT_Vector_CPtr p1, FT_Vector_CPtr p2, FT_Vector_CPtr p3, void* vpPolyArgs )
    1514             : {
    1515           0 :     PolyArgs& rA = *reinterpret_cast<PolyArgs*>(vpPolyArgs);
    1516           0 :     rA.AddPoint( p1->x, p1->y, POLY_CONTROL );
    1517           0 :     rA.AddPoint( p2->x, p2->y, POLY_CONTROL );
    1518           0 :     rA.AddPoint( p3->x, p3->y, POLY_NORMAL );
    1519           0 :     return 0;
    1520             : }
    1521             : 
    1522             : } // extern "C"
    1523             : 
    1524        1391 : bool ServerFont::GetGlyphOutline( sal_GlyphId aGlyphId,
    1525             :     ::basegfx::B2DPolyPolygon& rB2DPolyPoly ) const
    1526             : {
    1527        1391 :     if( maSizeFT )
    1528        1391 :         FT_Activate_Size( maSizeFT );
    1529             : 
    1530        1391 :     rB2DPolyPoly.clear();
    1531             : 
    1532             :     int nGlyphFlags;
    1533        1391 :     SplitGlyphFlags( *this, aGlyphId, nGlyphFlags );
    1534             : 
    1535        1391 :     FT_Int nLoadFlags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_TRANSFORM;
    1536             : 
    1537             : #ifdef FT_LOAD_TARGET_LIGHT
    1538             :     // enable "light hinting" if available
    1539        1391 :     nLoadFlags |= FT_LOAD_TARGET_LIGHT;
    1540             : #endif
    1541             : 
    1542        1391 :     FT_Error rc = FT_Load_Glyph( maFaceFT, aGlyphId, nLoadFlags );
    1543        1391 :     if( rc != FT_Err_Ok )
    1544           0 :         return false;
    1545             : 
    1546        1391 :     if (mbArtBold)
    1547           0 :         FT_GlyphSlot_Embolden(maFaceFT->glyph);
    1548             : 
    1549             :     FT_Glyph pGlyphFT;
    1550        1391 :     rc = FT_Get_Glyph( maFaceFT->glyph, &pGlyphFT );
    1551        1391 :     if( rc != FT_Err_Ok )
    1552           0 :         return false;
    1553             : 
    1554        1391 :     if( pGlyphFT->format != FT_GLYPH_FORMAT_OUTLINE )
    1555             :     {
    1556           0 :         FT_Done_Glyph( pGlyphFT );
    1557           0 :         return false;
    1558             :     }
    1559             : 
    1560        1391 :     if( mbArtItalic )
    1561             :     {
    1562             :         FT_Matrix aMatrix;
    1563           0 :         aMatrix.xx = aMatrix.yy = 0x10000L;
    1564           0 :         aMatrix.xy = 0x6000L, aMatrix.yx = 0;
    1565           0 :         FT_Glyph_Transform( pGlyphFT, &aMatrix, NULL );
    1566             :     }
    1567             : 
    1568        1391 :     FT_Outline& rOutline = reinterpret_cast<FT_OutlineGlyphRec*>(pGlyphFT)->outline;
    1569        1391 :     if( !rOutline.n_points )    // blank glyphs are ok
    1570             :     {
    1571          28 :         FT_Done_Glyph( pGlyphFT );
    1572          28 :         return true;
    1573             :     }
    1574             : 
    1575        1363 :     long nMaxPoints = 1 + rOutline.n_points * 3;
    1576        1363 :     PolyPolygon aToolPolyPolygon;
    1577        2726 :     PolyArgs aPolyArg( aToolPolyPolygon, nMaxPoints );
    1578             : 
    1579        1363 :     /*int nAngle =*/ ApplyGlyphTransform( nGlyphFlags, pGlyphFT, false );
    1580             : 
    1581             :     FT_Outline_Funcs aFuncs;
    1582        1363 :     aFuncs.move_to  = &FT_move_to;
    1583        1363 :     aFuncs.line_to  = &FT_line_to;
    1584        1363 :     aFuncs.conic_to = &FT_conic_to;
    1585        1363 :     aFuncs.cubic_to = &FT_cubic_to;
    1586        1363 :     aFuncs.shift    = 0;
    1587        1363 :     aFuncs.delta    = 0;
    1588        1363 :     rc = FT_Outline_Decompose( &rOutline, &aFuncs, (void*)&aPolyArg );
    1589        1363 :     aPolyArg.ClosePolygon();    // close last polygon
    1590        1363 :     FT_Done_Glyph( pGlyphFT );
    1591             : 
    1592             :     // convert to basegfx polypolygon
    1593             :     // TODO: get rid of the intermediate tools polypolygon
    1594        1363 :     rB2DPolyPoly = aToolPolyPolygon.getB2DPolyPolygon();
    1595        1363 :     rB2DPolyPoly.transform(basegfx::tools::createScaleB2DHomMatrix( +1.0/(1<<6), -1.0/(1<<6) ));
    1596             : 
    1597        2726 :     return true;
    1598             : }
    1599             : 
    1600        3702 : bool ServerFont::ApplyGSUB( const FontSelectPattern& rFSD )
    1601             : {
    1602             : #define MKTAG(s) ((((((s[0]<<8)+s[1])<<8)+s[2])<<8)+s[3])
    1603             : 
    1604             :     typedef std::vector<sal_uLong> ReqFeatureTagList;
    1605        3702 :     ReqFeatureTagList aReqFeatureTagList;
    1606        3702 :     if( rFSD.mbVertical )
    1607           5 :         aReqFeatureTagList.push_back( MKTAG("vert") );
    1608        3702 :     sal_uLong nRequestedScript = 0;     //MKTAG("hani");//### TODO: where to get script?
    1609        3702 :     sal_uLong nRequestedLangsys = 0;    //MKTAG("ZHT"); //### TODO: where to get langsys?
    1610             :     // TODO: request more features depending on script and language system
    1611             : 
    1612        3702 :     if( aReqFeatureTagList.empty()) // nothing to do
    1613        3697 :         return true;
    1614             : 
    1615             :     // load GSUB table into memory
    1616           5 :     sal_uLong nLength = 0;
    1617           5 :     const FT_Byte* const pGsubBase = mpFontInfo->GetTable( "GSUB", &nLength );
    1618           5 :     if( !pGsubBase )
    1619           0 :         return false;
    1620             : 
    1621             :     // parse GSUB header
    1622           5 :     const FT_Byte* pGsubHeader = pGsubBase;
    1623           5 :     const sal_uInt16 nOfsScriptList     = GetUShort( pGsubHeader+4 );
    1624           5 :     const sal_uInt16 nOfsFeatureTable   = GetUShort( pGsubHeader+6 );
    1625           5 :     const sal_uInt16 nOfsLookupList     = GetUShort( pGsubHeader+8 );
    1626           5 :     pGsubHeader += 10;
    1627             : 
    1628             :     typedef std::vector<sal_uInt16> UshortList;
    1629          10 :     UshortList aFeatureIndexList;
    1630             : 
    1631             :     // parse Script Table
    1632           5 :     const FT_Byte* pScriptHeader = pGsubBase + nOfsScriptList;
    1633           5 :     const sal_uInt16 nCntScript = GetUShort( pScriptHeader+0 );
    1634           5 :     pScriptHeader += 2;
    1635          20 :     for( sal_uInt16 nScriptIndex = 0; nScriptIndex < nCntScript; ++nScriptIndex )
    1636             :     {
    1637          15 :         const sal_uLong nScriptTag      = GetUInt( pScriptHeader+0 ); // e.g. hani/arab/kana/hang
    1638          15 :         const sal_uInt16 nOfsScriptTable= GetUShort( pScriptHeader+4 );
    1639          15 :         pScriptHeader += 6;
    1640          15 :         if( (nScriptTag != nRequestedScript) && (nRequestedScript != 0) )
    1641           0 :             continue;
    1642             : 
    1643          15 :         const FT_Byte* pScriptTable     = pGsubBase + nOfsScriptList + nOfsScriptTable;
    1644          15 :         const sal_uInt16 nDefaultLangsysOfs = GetUShort( pScriptTable+0 );
    1645          15 :         const sal_uInt16 nCntLangSystem     = GetUShort( pScriptTable+2 );
    1646          15 :         pScriptTable += 4;
    1647          15 :         sal_uInt16 nLangsysOffset = 0;
    1648             : 
    1649          15 :         for( sal_uInt16 nLangsysIndex = 0; nLangsysIndex < nCntLangSystem; ++nLangsysIndex )
    1650             :         {
    1651          10 :             const sal_uLong nTag    = GetUInt( pScriptTable+0 );    // e.g. KOR/ZHS/ZHT/JAN
    1652          10 :             const sal_uInt16 nOffset= GetUShort( pScriptTable+4 );
    1653          10 :             pScriptTable += 6;
    1654          10 :             if( (nTag != nRequestedLangsys) && (nRequestedLangsys != 0) )
    1655           0 :                 continue;
    1656          10 :             nLangsysOffset = nOffset;
    1657          10 :             break;
    1658             :         }
    1659             : 
    1660          15 :         if( (nDefaultLangsysOfs != 0) && (nDefaultLangsysOfs != nLangsysOffset) )
    1661             :         {
    1662          15 :             const FT_Byte* pLangSys = pGsubBase + nOfsScriptList + nOfsScriptTable + nDefaultLangsysOfs;
    1663          15 :             const sal_uInt16 nReqFeatureIdx = GetUShort( pLangSys+2 );
    1664          15 :             const sal_uInt16 nCntFeature    = GetUShort( pLangSys+4 );
    1665          15 :             pLangSys += 6;
    1666          15 :             aFeatureIndexList.push_back( nReqFeatureIdx );
    1667         325 :             for( sal_uInt16 i = 0; i < nCntFeature; ++i )
    1668             :             {
    1669         310 :                 const sal_uInt16 nFeatureIndex = GetUShort( pLangSys );
    1670         310 :                 pLangSys += 2;
    1671         310 :                 aFeatureIndexList.push_back( nFeatureIndex );
    1672             :             }
    1673             :         }
    1674             : 
    1675          15 :         if( nLangsysOffset != 0 )
    1676             :         {
    1677          10 :             const FT_Byte* pLangSys = pGsubBase + nOfsScriptList + nOfsScriptTable + nLangsysOffset;
    1678          10 :             const sal_uInt16 nReqFeatureIdx = GetUShort( pLangSys+2 );
    1679          10 :             const sal_uInt16 nCntFeature    = GetUShort( pLangSys+4 );
    1680          10 :             pLangSys += 6;
    1681          10 :             aFeatureIndexList.push_back( nReqFeatureIdx );
    1682         155 :             for( sal_uInt16 i = 0; i < nCntFeature; ++i )
    1683             :             {
    1684         145 :                 const sal_uInt16 nFeatureIndex = GetUShort( pLangSys );
    1685         145 :                 pLangSys += 2;
    1686         145 :                 aFeatureIndexList.push_back( nFeatureIndex );
    1687             :             }
    1688             :         }
    1689             :     }
    1690             : 
    1691           5 :     if( aFeatureIndexList.empty() )
    1692           0 :         return true;
    1693             : 
    1694          10 :     UshortList aLookupIndexList;
    1695          10 :     UshortList aLookupOffsetList;
    1696             : 
    1697             :     // parse Feature Table
    1698           5 :     const FT_Byte* pFeatureHeader = pGsubBase + nOfsFeatureTable;
    1699           5 :     const sal_uInt16 nCntFeature = GetUShort( pFeatureHeader );
    1700           5 :     pFeatureHeader += 2;
    1701         685 :     for( sal_uInt16 nFeatureIndex = 0; nFeatureIndex < nCntFeature; ++nFeatureIndex )
    1702             :     {
    1703         680 :         const sal_uLong nTag    = GetUInt( pFeatureHeader+0 ); // e.g. locl/vert/trad/smpl/liga/fina/...
    1704         680 :         const sal_uInt16 nOffset= GetUShort( pFeatureHeader+4 );
    1705         680 :         pFeatureHeader += 6;
    1706             : 
    1707             :         // short circuit some feature lookups
    1708         680 :         if( aFeatureIndexList[0] != nFeatureIndex ) // required feature?
    1709             :         {
    1710         680 :             const int nRequested = std::count( aFeatureIndexList.begin(), aFeatureIndexList.end(), nFeatureIndex);
    1711         680 :             if( !nRequested )  // ignore features that are not requested
    1712         905 :                 continue;
    1713         455 :             const int nAvailable = std::count( aReqFeatureTagList.begin(), aReqFeatureTagList.end(), nTag);
    1714         455 :             if( !nAvailable )  // some fonts don't provide features they request!
    1715         455 :                 continue;
    1716             :         }
    1717             : 
    1718           0 :         const FT_Byte* pFeatureTable = pGsubBase + nOfsFeatureTable + nOffset;
    1719           0 :         const sal_uInt16 nCntLookups = GetUShort( pFeatureTable+0 );
    1720           0 :         pFeatureTable += 2;
    1721           0 :         for( sal_uInt16 i = 0; i < nCntLookups; ++i )
    1722             :         {
    1723           0 :             const sal_uInt16 nLookupIndex = GetUShort( pFeatureTable );
    1724           0 :             pFeatureTable += 2;
    1725           0 :             aLookupIndexList.push_back( nLookupIndex );
    1726             :         }
    1727           0 :         if( nCntLookups == 0 ) //### hack needed by Mincho/Gothic/Mingliu/Simsun/...
    1728           0 :             aLookupIndexList.push_back( 0 );
    1729             :     }
    1730             : 
    1731             :     // parse Lookup List
    1732           5 :     const FT_Byte* pLookupHeader = pGsubBase + nOfsLookupList;
    1733           5 :     const sal_uInt16 nCntLookupTable = GetUShort( pLookupHeader );
    1734           5 :     pLookupHeader += 2;
    1735         205 :     for( sal_uInt16 nLookupIdx = 0; nLookupIdx < nCntLookupTable; ++nLookupIdx )
    1736             :     {
    1737         200 :         const sal_uInt16 nOffset = GetUShort( pLookupHeader );
    1738         200 :         pLookupHeader += 2;
    1739         200 :         if( std::count( aLookupIndexList.begin(), aLookupIndexList.end(), nLookupIdx ) )
    1740           0 :             aLookupOffsetList.push_back( nOffset );
    1741             :     }
    1742             : 
    1743           5 :     UshortList::const_iterator lookup_it = aLookupOffsetList.begin();
    1744           5 :     for(; lookup_it != aLookupOffsetList.end(); ++lookup_it )
    1745             :     {
    1746           0 :         const sal_uInt16 nOfsLookupTable = *lookup_it;
    1747           0 :         const FT_Byte* pLookupTable = pGsubBase + nOfsLookupList + nOfsLookupTable;
    1748           0 :         const sal_uInt16 eLookupType        = GetUShort( pLookupTable+0 );
    1749           0 :         const sal_uInt16 nCntLookupSubtable = GetUShort( pLookupTable+4 );
    1750           0 :         pLookupTable += 6;
    1751             : 
    1752             :         // TODO: switch( eLookupType )
    1753           0 :         if( eLookupType != 1 )  // TODO: once we go beyond SingleSubst
    1754           0 :             continue;
    1755             : 
    1756           0 :         for( sal_uInt16 nSubTableIdx = 0; nSubTableIdx < nCntLookupSubtable; ++nSubTableIdx )
    1757             :         {
    1758           0 :             const sal_uInt16 nOfsSubLookupTable = GetUShort( pLookupTable );
    1759           0 :             pLookupTable += 2;
    1760           0 :             const FT_Byte* pSubLookup = pGsubBase + nOfsLookupList + nOfsLookupTable + nOfsSubLookupTable;
    1761             : 
    1762           0 :             const sal_uInt16 nFmtSubstitution   = GetUShort( pSubLookup+0 );
    1763           0 :             const sal_uInt16 nOfsCoverage       = GetUShort( pSubLookup+2 );
    1764           0 :             pSubLookup += 4;
    1765             : 
    1766             :             typedef std::pair<sal_uInt16,sal_uInt16> GlyphSubst;
    1767             :             typedef std::vector<GlyphSubst> SubstVector;
    1768           0 :             SubstVector aSubstVector;
    1769             : 
    1770           0 :             const FT_Byte* pCoverage    = pGsubBase + nOfsLookupList + nOfsLookupTable + nOfsSubLookupTable + nOfsCoverage;
    1771           0 :             const sal_uInt16 nFmtCoverage   = GetUShort( pCoverage+0 );
    1772           0 :             pCoverage += 2;
    1773           0 :             switch( nFmtCoverage )
    1774             :             {
    1775             :                 case 1:         // Coverage Format 1
    1776             :                     {
    1777           0 :                         const sal_uInt16 nCntGlyph = GetUShort( pCoverage );
    1778           0 :                         pCoverage += 2;
    1779           0 :                         aSubstVector.reserve( nCntGlyph );
    1780           0 :                         for( sal_uInt16 i = 0; i < nCntGlyph; ++i )
    1781             :                         {
    1782           0 :                             const sal_uInt16 nGlyphId = GetUShort( pCoverage );
    1783           0 :                             pCoverage += 2;
    1784           0 :                             aSubstVector.push_back( GlyphSubst( nGlyphId, 0 ) );
    1785             :                         }
    1786             :                     }
    1787           0 :                     break;
    1788             : 
    1789             :                 case 2:         // Coverage Format 2
    1790             :                     {
    1791           0 :                         const sal_uInt16 nCntRange = GetUShort( pCoverage );
    1792           0 :                         pCoverage += 2;
    1793           0 :                         for( int i = nCntRange; --i >= 0; )
    1794             :                         {
    1795           0 :                             const sal_uInt32 nGlyph0 = GetUShort( pCoverage+0 );
    1796           0 :                             const sal_uInt32 nGlyph1 = GetUShort( pCoverage+2 );
    1797           0 :                             const sal_uInt16 nCovIdx = GetUShort( pCoverage+4 );
    1798           0 :                             pCoverage += 6;
    1799           0 :                             for( sal_uInt32 j = nGlyph0; j <= nGlyph1; ++j )
    1800           0 :                                 aSubstVector.push_back( GlyphSubst( static_cast<sal_uInt16>(j + nCovIdx), 0 ) );
    1801             :                         }
    1802             :                     }
    1803           0 :                     break;
    1804             :             }
    1805             : 
    1806           0 :             SubstVector::iterator it( aSubstVector.begin() );
    1807             : 
    1808           0 :             switch( nFmtSubstitution )
    1809             :             {
    1810             :                 case 1:     // Single Substitution Format 1
    1811             :                     {
    1812           0 :                         const sal_uInt16 nDeltaGlyphId = GetUShort( pSubLookup );
    1813           0 :                         pSubLookup += 2;
    1814           0 :                         for(; it != aSubstVector.end(); ++it )
    1815           0 :                             (*it).second = (*it).first + nDeltaGlyphId;
    1816             :                     }
    1817           0 :                     break;
    1818             : 
    1819             :                 case 2:     // Single Substitution Format 2
    1820             :                     {
    1821           0 :                         const sal_uInt16 nCntGlyph = GetUShort( pSubLookup );
    1822           0 :                         pSubLookup += 2;
    1823           0 :                         for( int i = nCntGlyph; (it != aSubstVector.end()) && (--i>=0); ++it )
    1824             :                         {
    1825           0 :                             const sal_uInt16 nGlyphId = GetUShort( pSubLookup );
    1826           0 :                             pSubLookup += 2;
    1827           0 :                             (*it).second = nGlyphId;
    1828             :                         }
    1829             :                     }
    1830           0 :                     break;
    1831             :             }
    1832             : 
    1833             :             DBG_ASSERT( (it == aSubstVector.end()), "lookup<->coverage table mismatch" );
    1834             :             // now apply the glyph substitutions that have been collected in this subtable
    1835           0 :             for( it = aSubstVector.begin(); it != aSubstVector.end(); ++it )
    1836           0 :                 maGlyphSubstitution[ (*it).first ] =  (*it).second;
    1837           0 :         }
    1838             :     }
    1839             : 
    1840        3707 :     return true;
    1841             : }
    1842             : 
    1843       11312 : const unsigned char* ServerFont::GetTable(const char* pName, sal_uLong* pLength)
    1844             : {
    1845       11312 :     return mpFontInfo->GetTable( pName, pLength );
    1846             : }
    1847             : 
    1848             : #if ENABLE_GRAPHITE
    1849        2227 : GraphiteFaceWrapper* ServerFont::GetGraphiteFace() const
    1850             : {
    1851        2227 :     return mpFontInfo->GetGraphiteFace();
    1852         516 : }
    1853             : #endif
    1854             : 
    1855             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10