LCOV - code coverage report
Current view: top level - vcl/generic/glyphs - gcach_ftyp.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 597 906 65.9 %
Date: 2015-06-13 12:38:46 Functions: 56 62 90.3 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.11