LCOV - code coverage report
Current view: top level - usr/local/src/libreoffice/vcl/generic/glyphs - gcach_ftyp.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 667 1164 57.3 %
Date: 2013-07-09 Functions: 58 70 82.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : 
      21             : #ifdef WNT
      22             : #include <svsys.h>
      23             : #undef CreateFont
      24             : #endif
      25             : 
      26             : #include "gcach_ftyp.hxx"
      27             : 
      28             : #include "vcl/svapp.hxx"
      29             : #include <outfont.hxx>
      30             : #include <impfont.hxx>
      31             : #include <config_graphite.h>
      32             : #if ENABLE_GRAPHITE
      33             : #include <graphite2/Font.h>
      34             : #include <graphite_layout.hxx>
      35             : #endif
      36             : #include <unotools/fontdefs.hxx>
      37             : 
      38             : #include "tools/poly.hxx"
      39             : #include "basegfx/matrix/b2dhommatrix.hxx"
      40             : #include "basegfx/matrix/b2dhommatrixtools.hxx"
      41             : #include "basegfx/polygon/b2dpolypolygon.hxx"
      42             : 
      43             : #include "osl/file.hxx"
      44             : #include "osl/thread.hxx"
      45             : 
      46             : #include "langboost.hxx"
      47             : #include "sft.hxx"
      48             : 
      49             : #include <ft2build.h>
      50             : #include FT_FREETYPE_H
      51             : #include FT_GLYPH_H
      52             : #include FT_OUTLINE_H
      53             : #include FT_TRUETYPE_TABLES_H
      54             : #include FT_TRUETYPE_TAGS_H
      55             : #include FT_TRUETYPE_IDS_H
      56             : 
      57             : #ifdef ANDROID
      58             : #include FT_SIZES_H
      59             : #include FT_SYNTHESIS_H
      60             : #endif
      61             : 
      62             : #ifndef FT_RENDER_MODE_MONO  // happens in the MACOSX build
      63             :     #define FT_RENDER_MODE_MONO ft_render_mode_mono
      64             : #endif
      65             : #include "rtl/instance.hxx"
      66             : 
      67             : #define FTVERSION (1000*FREETYPE_MAJOR + 100*FREETYPE_MINOR + FREETYPE_PATCH)
      68             : 
      69             : #if FTVERSION >= 2200
      70             : typedef const FT_Vector* FT_Vector_CPtr;
      71             : #else // FTVERSION < 2200
      72             : typedef FT_Vector* FT_Vector_CPtr;
      73             : #endif
      74             : 
      75             : #include <vector>
      76             : 
      77             : // TODO: move file mapping stuff to OSL
      78             : #if defined(UNX)
      79             :     // PORTERS: dlfcn is used for getting symbols from FT versions newer than baseline
      80             :     #include <dlfcn.h>
      81             :     #include <unistd.h>
      82             :     #include <fcntl.h>
      83             :     #include <sys/stat.h>
      84             :     #include <sys/mman.h>
      85             :     #include "vcl/fontmanager.hxx"
      86             : #elif defined(WNT)
      87             :     #include <io.h>
      88             :     #define strncasecmp strnicmp
      89             : #endif
      90             : 
      91             : typedef const unsigned char* CPU8;
      92           0 : inline sal_uInt16 NEXT_U16( CPU8& p ) { p+=2; return (p[-2]<<8)|p[-1]; }
      93           0 : inline sal_Int16  NEXT_S16( CPU8& p ) { return (sal_Int16)NEXT_U16(p); }
      94           0 : inline sal_uInt32 NEXT_U32( CPU8& p ) { p+=4; return (p[-4]<<24)|(p[-3]<<16)|(p[-2]<<8)|p[-1]; }
      95             : //inline sal_Int32 NEXT_S32( U8*& p ) { return (sal_Int32)NEXT_U32(p); }
      96             : 
      97             : // -----------------------------------------------------------------------
      98             : 
      99             : // the gamma table makes artificial bold look better for CJK glyphs
     100             : static unsigned char aGammaTable[257];
     101             : 
     102         125 : static void InitGammaTable()
     103             : {
     104             :     static const int M_MAX = 255;
     105             :     static const int M_X   = 128;
     106             :     static const int M_Y   = 208;
     107             : 
     108             :     int x, a;
     109       32125 :     for( x = 0; x < 256; x++)
     110             :     {
     111       32000 :         if ( x <= M_X )
     112       16125 :             a = ( x * M_Y + M_X / 2) / M_X;
     113             :         else
     114       15875 :             a = M_Y + ( ( x - M_X ) * ( M_MAX - M_Y ) +
     115       15875 :                 ( M_MAX - M_X ) / 2 ) / ( M_MAX - M_X );
     116             : 
     117       32000 :         aGammaTable[x] = (unsigned char)a;
     118             :     }
     119         125 : }
     120             : 
     121             : // -----------------------------------------------------------------------
     122             : 
     123             : static FT_Library aLibFT = 0;
     124             : 
     125             : // #110607# enable linking with old FT versions
     126             : static int nFTVERSION = 0;
     127             : static FT_Error (*pFTNewSize)(FT_Face,FT_Size*);
     128             : static FT_Error (*pFTActivateSize)(FT_Size);
     129             : static FT_Error (*pFTDoneSize)(FT_Size);
     130             : void (*pFTEmbolden)(FT_GlyphSlot);
     131             : static FT_UInt (*pFT_Face_GetCharVariantIndex)(FT_Face, FT_ULong, FT_ULong);
     132             : static bool bEnableSizeFT = false;
     133             : 
     134             : typedef ::boost::unordered_map<const char*, boost::shared_ptr<FtFontFile>, rtl::CStringHash, rtl::CStringEqual> FontFileList;
     135             : 
     136             : namespace { struct vclFontFileList : public rtl::Static< FontFileList, vclFontFileList > {}; }
     137             : 
     138             : // -----------------------------------------------------------------------
     139             : 
     140             : // TODO: remove when the priorities are selected by UI
     141             : // if (AH==0) => disable autohinting
     142             : // if (AA==0) => disable antialiasing
     143             : // if (EB==0) => disable embedded bitmaps
     144             : // if (AA prio <= AH prio) => antialias + autohint
     145             : // if (AH<AA) => do not autohint when antialiasing
     146             : // if (EB<AH) => do not autohint for monochrome
     147             : static int nDefaultPrioEmbedded    = 2;
     148             : static int nDefaultPrioAutoHint    = 1;
     149             : static int nDefaultPrioAntiAlias   = 1;
     150             : 
     151             : // =======================================================================
     152             : // FreetypeManager
     153             : // =======================================================================
     154             : 
     155       21130 : FtFontFile::FtFontFile( const OString& rNativeFileName )
     156             : :   maNativeFileName( rNativeFileName ),
     157             :     mpFileMap( NULL ),
     158             :     mnFileSize( 0 ),
     159             :     mnRefCount( 0 ),
     160       21130 :     mnLangBoost( 0 )
     161             : {
     162             :     // boost font preference if UI language is mentioned in filename
     163       21130 :     int nPos = maNativeFileName.lastIndexOf( '_' );
     164       21130 :     if( nPos == -1 || maNativeFileName[nPos+1] == '.' )
     165       19579 :         mnLangBoost += 0x1000;     // no langinfo => good
     166             :     else
     167             :     {
     168             :         static const char* pLangBoost = NULL;
     169             :         static bool bOnce = true;
     170        1551 :         if( bOnce )
     171             :         {
     172         125 :             bOnce = false;
     173         125 :             pLangBoost = vcl::getLangBoost();
     174             :         }
     175             : 
     176        1551 :         if( pLangBoost && !strncasecmp( pLangBoost, &maNativeFileName.getStr()[nPos+1], 3 ) )
     177           0 :            mnLangBoost += 0x2000;     // matching langinfo => better
     178             :     }
     179       21130 : }
     180             : 
     181             : // -----------------------------------------------------------------------
     182             : 
     183       21755 : FtFontFile* FtFontFile::FindFontFile( const OString& rNativeFileName )
     184             : {
     185             :     // font file already known? (e.g. for ttc, synthetic, aliased fonts)
     186       21755 :     const char* pFileName = rNativeFileName.getStr();
     187       21755 :     FontFileList &rFontFileList = vclFontFileList::get();
     188       21755 :     FontFileList::const_iterator it = rFontFileList.find( pFileName );
     189       21755 :     if( it != rFontFileList.end() )
     190         625 :         return it->second.get();
     191             : 
     192             :     // no => create new one
     193       21130 :     FtFontFile* pFontFile = new FtFontFile( rNativeFileName );
     194       21130 :     pFileName = pFontFile->maNativeFileName.getStr();
     195       21130 :     rFontFileList[pFileName].reset(pFontFile);
     196       21130 :     return pFontFile;
     197             : }
     198             : 
     199             : // -----------------------------------------------------------------------
     200             : 
     201         397 : bool FtFontFile::Map()
     202             : {
     203         397 :     if( mnRefCount++ <= 0 )
     204             :     {
     205         397 :         const char* pFileName = maNativeFileName.getStr();
     206             : #if defined(UNX)
     207         397 :         int nFile = open( pFileName, O_RDONLY );
     208         397 :         if( nFile < 0 )
     209           0 :             return false;
     210             : 
     211             :         struct stat aStat;
     212         397 :         fstat( nFile, &aStat );
     213         397 :         mnFileSize = aStat.st_size;
     214             :         mpFileMap = (const unsigned char*)
     215         397 :             mmap( NULL, mnFileSize, PROT_READ, MAP_SHARED, nFile, 0 );
     216         397 :         if( mpFileMap == MAP_FAILED )
     217           0 :             mpFileMap = NULL;
     218         397 :         close( nFile );
     219             : #elif defined(WNT)
     220             :         void* pFileDesc = ::CreateFile( pFileName, GENERIC_READ, FILE_SHARE_READ,
     221             :                         NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 );
     222             :         if( pFileDesc == INVALID_HANDLE_VALUE)
     223             :             return false;
     224             : 
     225             :         mnFileSize = ::GetFileSize( pFileDesc, NULL );
     226             :         HANDLE aHandle = ::CreateFileMapping( pFileDesc, NULL, PAGE_READONLY, 0, mnFileSize, "TTF" );
     227             :         mpFileMap = (const unsigned char*)::MapViewOfFile( aHandle, FILE_MAP_READ, 0, 0, mnFileSize );
     228             :         ::CloseHandle( pFileDesc );
     229             : #else
     230             :         FILE* pFile = fopen( pFileName, "rb" );
     231             :         if( !pFile )
     232             :             return false;
     233             : 
     234             :         struct stat aStat;
     235             :         stat( pFileName, &aStat );
     236             :         mnFileSize = aStat.st_size;
     237             :         mpFileMap = new unsigned char[ mnFileSize ];
     238             :         if( mnFileSize != fread( mpFileMap, 1, mnFileSize, pFile ) )
     239             :         {
     240             :             delete[] mpFileMap;
     241             :             mpFileMap = NULL;
     242             :         }
     243             :         fclose( pFile );
     244             : #endif
     245             :     }
     246             : 
     247         397 :     return (mpFileMap != NULL);
     248             : }
     249             : 
     250             : // -----------------------------------------------------------------------
     251             : 
     252         397 : void FtFontFile::Unmap()
     253             : {
     254         397 :     if( (--mnRefCount > 0) || (mpFileMap == NULL) )
     255         397 :         return;
     256             : 
     257             : #if defined(UNX)
     258         397 :     munmap( (char*)mpFileMap, mnFileSize );
     259             : #elif defined(WNT)
     260             :     UnmapViewOfFile( (LPCVOID)mpFileMap );
     261             : #else
     262             :     delete[] mpFileMap;
     263             : #endif
     264             : 
     265         397 :     mpFileMap = NULL;
     266             : }
     267             : 
     268             : #if ENABLE_GRAPHITE
     269             : // wrap FtFontInfo's table function
     270           0 : const void * graphiteFontTable(const void* appFaceHandle, unsigned int name, size_t *len)
     271             : {
     272           0 :     const FtFontInfo * pFontInfo = reinterpret_cast<const FtFontInfo*>(appFaceHandle);
     273             :     typedef union {
     274             :         char m_c[5];
     275             :         unsigned int m_id;
     276             :     } TableId;
     277             :     TableId tableId;
     278           0 :     tableId.m_id = name;
     279             : #ifndef WORDS_BIGENDIAN
     280             :     TableId swapped;
     281           0 :     swapped.m_c[3] = tableId.m_c[0];
     282           0 :     swapped.m_c[2] = tableId.m_c[1];
     283           0 :     swapped.m_c[1] = tableId.m_c[2];
     284           0 :     swapped.m_c[0] = tableId.m_c[3];
     285           0 :     tableId.m_id = swapped.m_id;
     286             : #endif
     287           0 :     tableId.m_c[4] = '\0';
     288           0 :     sal_uLong nLength = 0;
     289           0 :     const void * pTable = static_cast<const void*>(pFontInfo->GetTable(tableId.m_c, &nLength));
     290           0 :     if (len) *len = static_cast<size_t>(nLength);
     291           0 :     return pTable;
     292             : }
     293             : #endif
     294             : 
     295             : // =======================================================================
     296             : 
     297       21755 : FtFontInfo::FtFontInfo( const ImplDevFontAttributes& rDevFontAttributes,
     298             :     const OString& rNativeFileName, int nFaceNum, sal_IntPtr nFontId, int nSynthetic,
     299             :     const ExtraKernInfo* pExtraKernInfo )
     300             : :
     301             :     maFaceFT( NULL ),
     302       21755 :     mpFontFile( FtFontFile::FindFontFile( rNativeFileName ) ),
     303             :     mnFaceNum( nFaceNum ),
     304             :     mnRefCount( 0 ),
     305             :     mnSynthetic( nSynthetic ),
     306             : #if ENABLE_GRAPHITE
     307             :     mbCheckedGraphite(false),
     308             :     mpGraphiteFace(NULL),
     309             : #endif
     310             :     mnFontId( nFontId ),
     311             :     maDevFontAttributes( rDevFontAttributes ),
     312             :     mpFontCharMap( NULL ),
     313             :     mpChar2Glyph( NULL ),
     314             :     mpGlyph2Char( NULL ),
     315       43510 :     mpExtraKernInfo( pExtraKernInfo )
     316             : {
     317             :     // prefer font with low ID
     318       21755 :     maDevFontAttributes.mnQuality += 10000 - nFontId;
     319             :     // prefer font with matching file names
     320       21755 :     maDevFontAttributes.mnQuality += mpFontFile->GetLangBoost();
     321             :     // prefer font with more external info
     322       21755 :     if( pExtraKernInfo )
     323        5875 :         maDevFontAttributes.mnQuality += 100;
     324       21755 : }
     325             : 
     326             : // -----------------------------------------------------------------------
     327             : 
     328       43510 : FtFontInfo::~FtFontInfo()
     329             : {
     330       21755 :     if( mpFontCharMap )
     331         140 :         mpFontCharMap->DeReference();
     332       21755 :     delete mpExtraKernInfo;
     333       21755 :     delete mpChar2Glyph;
     334       21755 :     delete mpGlyph2Char;
     335             : #if ENABLE_GRAPHITE
     336       21755 :     delete mpGraphiteFace;
     337             : #endif
     338       21755 : }
     339             : 
     340         397 : void FtFontInfo::InitHashes() const
     341             : {
     342             :     // TODO: avoid pointers when empty stl::hash_* objects become cheap
     343         397 :     mpChar2Glyph = new Int2IntMap();
     344         397 :     mpGlyph2Char = new Int2IntMap();
     345         397 : }
     346             : 
     347             : // -----------------------------------------------------------------------
     348             : 
     349        2350 : FT_FaceRec_* FtFontInfo::GetFaceFT()
     350             : {
     351             :     // get faceFT once/multiple depending on availability of SizeFT APIs
     352        2350 :     if( (mnRefCount++ <= 0) || !bEnableSizeFT )
     353             :     {
     354         397 :         if( !mpFontFile->Map() )
     355           0 :             return NULL;
     356             :         FT_Error rc = FT_New_Memory_Face( aLibFT,
     357         397 :             (FT_Byte*)mpFontFile->GetBuffer(),
     358         794 :             mpFontFile->GetFileSize(), mnFaceNum, &maFaceFT );
     359         397 :         if( (rc != FT_Err_Ok) || (maFaceFT->num_glyphs <= 0) )
     360           0 :             maFaceFT = NULL;
     361             :     }
     362             : 
     363        2350 :    return maFaceFT;
     364             : }
     365             : 
     366             : #if ENABLE_GRAPHITE
     367        1051 : GraphiteFaceWrapper * FtFontInfo::GetGraphiteFace()
     368             : {
     369        1051 :     if (mbCheckedGraphite)
     370        1039 :         return mpGraphiteFace;
     371             :     // test for graphite here so that it is cached most efficiently
     372          12 :     if (GetTable("Silf", 0))
     373             :     {
     374           0 :         static const char* pGraphiteCacheStr = getenv( "SAL_GRAPHITE_CACHE_SIZE" );
     375           0 :         int graphiteSegCacheSize = pGraphiteCacheStr ? (atoi(pGraphiteCacheStr)) : 0;
     376             :         gr_face * pGraphiteFace;
     377           0 :         if (graphiteSegCacheSize > 500)
     378           0 :             pGraphiteFace = gr_make_face_with_seg_cache(this, graphiteFontTable, graphiteSegCacheSize, gr_face_cacheCmap);
     379             :         else
     380           0 :             pGraphiteFace = gr_make_face(this, graphiteFontTable, gr_face_cacheCmap);
     381           0 :         if (pGraphiteFace)
     382           0 :             mpGraphiteFace = new GraphiteFaceWrapper(pGraphiteFace);
     383             :     }
     384          12 :     mbCheckedGraphite = true;
     385          12 :     return mpGraphiteFace;
     386             : }
     387             : #endif
     388             : 
     389             : // -----------------------------------------------------------------------
     390             : 
     391        2350 : void FtFontInfo::ReleaseFaceFT( FT_FaceRec_* pFaceFT )
     392             : {
     393             :     // release last/each depending on SizeFT availability
     394        2350 :     if( (--mnRefCount <= 0) || !bEnableSizeFT )
     395             :     {
     396         397 :         FT_Done_Face( pFaceFT );
     397         397 :         maFaceFT = NULL;
     398         397 :         mpFontFile->Unmap();
     399             :     }
     400        2350 : }
     401             : 
     402             : // -----------------------------------------------------------------------
     403             : 
     404         633 : bool FtFontInfo::HasExtraKerning() const
     405             : {
     406         633 :     if( !mpExtraKernInfo )
     407         583 :         return false;
     408             :     // TODO: how to enable the line below without getting #i29881# back?
     409             :     // on the other hand being too optimistic doesn't cause problems
     410             :     // return mpExtraKernInfo->HasKernPairs();
     411          50 :     return true;
     412             : }
     413             : 
     414             : // -----------------------------------------------------------------------
     415             : 
     416           0 : int FtFontInfo::GetExtraKernPairs( ImplKernPairData** ppKernPairs ) const
     417             : {
     418           0 :     if( !mpExtraKernInfo )
     419           0 :         return 0;
     420           0 :     return mpExtraKernInfo->GetUnscaledKernPairs( ppKernPairs );
     421             : }
     422             : 
     423             : // -----------------------------------------------------------------------
     424             : 
     425       20549 : static unsigned GetUInt( const unsigned char* p ) { return((p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3]);}
     426        7973 : static unsigned GetUShort( const unsigned char* p ){ return((p[0]<<8)+p[1]);}
     427             : //static signed GetSShort( const unsigned char* p ){ return((short)((p[0]<<8)+p[1]));}
     428             : 
     429             : static const sal_uInt32 T_true = 0x74727565;        /* 'true' */
     430             : static const sal_uInt32 T_ttcf = 0x74746366;        /* 'ttcf' */
     431             : static const sal_uInt32 T_otto = 0x4f54544f;        /* 'OTTO' */
     432             : 
     433        8051 : const unsigned char* FtFontInfo::GetTable( const char* pTag, sal_uLong* pLength ) const
     434             : {
     435        8051 :     const unsigned char* pBuffer = mpFontFile->GetBuffer();
     436        8051 :     int nFileSize = mpFontFile->GetFileSize();
     437        8051 :     if( !pBuffer || nFileSize<1024 )
     438           0 :         return NULL;
     439             : 
     440             :     // we currently handle TTF, TTC and OTF headers
     441        8051 :     unsigned nFormat = GetUInt( pBuffer );
     442             : 
     443        8051 :     const unsigned char* p = pBuffer + 12;
     444        8051 :     if( nFormat == T_ttcf )         // TTC_MAGIC
     445           8 :         p += GetUInt( p + 4 * mnFaceNum );
     446        8043 :     else if( nFormat != 0x00010000 && nFormat != T_true && nFormat != T_otto) // TTF_MAGIC and Apple TTF Magic and PS-OpenType font
     447         108 :         return NULL;
     448             : 
     449             :     // walk table directory until match
     450        7943 :     int nTables = GetUShort( p - 8 );
     451        7943 :     if( nTables >= 64 )  // something fishy?
     452           0 :         return NULL;
     453       54394 :     for( int i = 0; i < nTables; ++i, p+=16 )
     454             :     {
     455       52693 :         if( p[0]==pTag[0] && p[1]==pTag[1] && p[2]==pTag[2] && p[3]==pTag[3] )
     456             :         {
     457        6242 :             sal_uLong nLength = GetUInt( p + 12 );
     458        6242 :             if( pLength != NULL )
     459        6242 :                 *pLength = nLength;
     460        6242 :             const unsigned char* pTable = pBuffer + GetUInt( p + 8 );
     461        6242 :             if( (pTable + nLength) <= (mpFontFile->GetBuffer() + nFileSize) )
     462        6242 :                 return pTable;
     463             :         }
     464             :     }
     465             : 
     466        1701 :     return NULL;
     467             : }
     468             : 
     469             : // -----------------------------------------------------------------------
     470             : 
     471       22009 : void FtFontInfo::AnnounceFont( ImplDevFontList* pFontList )
     472             : {
     473       22009 :     ImplFTSFontData* pFD = new ImplFTSFontData( this, maDevFontAttributes );
     474       22009 :     pFontList->Add( pFD );
     475       22009 : }
     476             : 
     477             : // =======================================================================
     478             : 
     479         125 : FreetypeManager::FreetypeManager()
     480         125 : :   mnMaxFontId( 0 )
     481             : {
     482         125 :     /*FT_Error rcFT =*/ FT_Init_FreeType( &aLibFT );
     483             : 
     484             : #ifdef ANDROID
     485             :     // For Android we use the bundled static libfreetype.a, and we
     486             :     // want to avoid accidentally finding the FT_* symbols in the
     487             :     // system FreeType code (which *is* present in a system library,
     488             :     // libskia.so, but is not a public API, and in fact does crash the
     489             :     // app if used).
     490             :     pFTNewSize = FT_New_Size;
     491             :     pFTActivateSize = FT_Activate_Size;
     492             :     pFTDoneSize = FT_Done_Size;
     493             :     pFTEmbolden = FT_GlyphSlot_Embolden;
     494             :     pFT_Face_GetCharVariantIndex = FT_Face_GetCharVariantIndex;
     495             :     nFTVERSION = FTVERSION;
     496             : #else
     497             : #ifdef RTLD_DEFAULT // true if a good dlfcn.h header was included
     498             :     // Get version of freetype library to enable workarounds.
     499             :     // Freetype <= 2.0.9 does not have FT_Library_Version().
     500             :     // Using dl_sym() instead of osl_getSymbol() because latter
     501             :     // isn't designed to work with oslModule=NULL
     502             :     void (*pFTLibraryVersion)(FT_Library library,
     503             :         FT_Int *amajor, FT_Int *aminor, FT_Int *apatch);
     504             :     pFTLibraryVersion = (void (*)(FT_Library library,
     505         125 :         FT_Int *amajor, FT_Int *aminor, FT_Int *apatch))(sal_IntPtr)dlsym( RTLD_DEFAULT, "FT_Library_Version" );
     506             : 
     507         125 :     pFTNewSize      = (FT_Error(*)(FT_Face,FT_Size*))(sal_IntPtr)dlsym( RTLD_DEFAULT, "FT_New_Size" );
     508         125 :     pFTActivateSize = (FT_Error(*)(FT_Size))(sal_IntPtr)dlsym( RTLD_DEFAULT, "FT_Activate_Size" );
     509         125 :     pFTDoneSize     = (FT_Error(*)(FT_Size))(sal_IntPtr)dlsym( RTLD_DEFAULT, "FT_Done_Size" );
     510         125 :     pFTEmbolden     = (void(*)(FT_GlyphSlot))(sal_IntPtr)dlsym( RTLD_DEFAULT, "FT_GlyphSlot_Embolden" );
     511         125 :     pFT_Face_GetCharVariantIndex = (FT_UInt(*)(FT_Face, FT_ULong, FT_ULong))(sal_IntPtr)dlsym( RTLD_DEFAULT, "FT_Face_GetCharVariantIndex" );
     512             : 
     513         125 :     bEnableSizeFT = (pFTNewSize!=NULL) && (pFTActivateSize!=NULL) && (pFTDoneSize!=NULL);
     514             : 
     515         125 :     FT_Int nMajor = 0, nMinor = 0, nPatch = 0;
     516         125 :     if( pFTLibraryVersion )
     517         125 :         pFTLibraryVersion( aLibFT, &nMajor, &nMinor, &nPatch );
     518         125 :     nFTVERSION = nMajor * 1000 + nMinor * 100 + nPatch;
     519             : 
     520             :     // disable artificial emboldening with the Freetype API for older versions
     521         125 :     if( nFTVERSION < 2110 )
     522           0 :         pFTEmbolden = NULL;
     523             :     // disable FT_Face_GetCharVariantIndex for older versions
     524             :     // https://bugzilla.mozilla.org/show_bug.cgi?id=618406#c8
     525         125 :     if( nFTVERSION < 2404 )
     526           0 :         pFT_Face_GetCharVariantIndex = NULL;
     527             : 
     528             : #else // RTLD_DEFAULT
     529             :     // assume systems where dlsym is not possible use supplied library
     530             :     nFTVERSION = FTVERSION;
     531             : #endif
     532             : #endif
     533             :     // TODO: remove when the priorities are selected by UI
     534             :     char* pEnv;
     535         125 :     pEnv = ::getenv( "SAL_EMBEDDED_BITMAP_PRIORITY" );
     536         125 :     if( pEnv )
     537           0 :         nDefaultPrioEmbedded  = pEnv[0] - '0';
     538         125 :     pEnv = ::getenv( "SAL_ANTIALIASED_TEXT_PRIORITY" );
     539         125 :     if( pEnv )
     540           0 :         nDefaultPrioAntiAlias = pEnv[0] - '0';
     541         125 :     pEnv = ::getenv( "SAL_AUTOHINTING_PRIORITY" );
     542         125 :     if( pEnv )
     543           0 :         nDefaultPrioAutoHint  = pEnv[0] - '0';
     544             : 
     545         125 :     InitGammaTable();
     546         125 :     vclFontFileList::get();
     547         125 : }
     548             : 
     549             : // -----------------------------------------------------------------------
     550             : 
     551      738063 : FT_Face ServerFont::GetFtFace() const
     552             : {
     553      738063 :     if( maSizeFT )
     554      738063 :         pFTActivateSize( maSizeFT );
     555             : 
     556      738063 :     return maFaceFT;
     557             : }
     558             : 
     559             : // -----------------------------------------------------------------------
     560             : 
     561         250 : FreetypeManager::~FreetypeManager()
     562             : {
     563         125 :     ClearFontList();
     564         125 : }
     565             : 
     566             : // -----------------------------------------------------------------------
     567             : 
     568       22009 : void FreetypeManager::AddFontFile( const OString& rNormalizedName,
     569             :     int nFaceNum, sal_IntPtr nFontId, const ImplDevFontAttributes& rDevFontAttr,
     570             :     const ExtraKernInfo* pExtraKernInfo )
     571             : {
     572       22009 :     if( rNormalizedName.isEmpty() )
     573           0 :         return;
     574             : 
     575       22009 :     if( maFontList.find( nFontId ) != maFontList.end() )
     576         254 :         return;
     577             : 
     578             :     FtFontInfo* pFontInfo = new FtFontInfo( rDevFontAttr,
     579       21755 :         rNormalizedName, nFaceNum, nFontId, 0, pExtraKernInfo );
     580       21755 :     maFontList[ nFontId ] = pFontInfo;
     581       21755 :     if( mnMaxFontId < nFontId )
     582         125 :         mnMaxFontId = nFontId;
     583             : }
     584             : 
     585             : // -----------------------------------------------------------------------
     586             : 
     587         127 : void FreetypeManager::AnnounceFonts( ImplDevFontList* pToAdd ) const
     588             : {
     589       22136 :     for( FontList::const_iterator it = maFontList.begin(); it != maFontList.end(); ++it )
     590             :     {
     591       22009 :         FtFontInfo* pFtFontInfo = it->second;
     592       22009 :         pFtFontInfo->AnnounceFont( pToAdd );
     593             :     }
     594         127 : }
     595             : 
     596             : // -----------------------------------------------------------------------
     597             : 
     598         125 : void FreetypeManager::ClearFontList( )
     599             : {
     600       21880 :     for( FontList::iterator it = maFontList.begin(); it != maFontList.end(); ++it )
     601             :     {
     602       21755 :         FtFontInfo* pFtFontInfo = it->second;
     603       21755 :         delete pFtFontInfo;
     604             :     }
     605         125 :     maFontList.clear();
     606         125 : }
     607             : 
     608             : // -----------------------------------------------------------------------
     609             : 
     610        2350 : ServerFont* FreetypeManager::CreateFont( const FontSelectPattern& rFSD )
     611             : {
     612        2350 :     FtFontInfo* pFontInfo = NULL;
     613             : 
     614             :     // find a FontInfo matching to the font id
     615        2350 :     sal_IntPtr nFontId = reinterpret_cast<sal_IntPtr>( rFSD.mpFontData );
     616        2350 :     FontList::iterator it = maFontList.find( nFontId );
     617        2350 :     if( it != maFontList.end() )
     618        2350 :         pFontInfo = it->second;
     619             : 
     620        2350 :     if( !pFontInfo )
     621           0 :         return NULL;
     622             : 
     623        2350 :     ServerFont* pNew = new ServerFont( rFSD, pFontInfo );
     624             : 
     625        2350 :     return pNew;
     626             : }
     627             : 
     628             : // =======================================================================
     629             : 
     630       22009 : ImplFTSFontData::ImplFTSFontData( FtFontInfo* pFI, const ImplDevFontAttributes& rDFA )
     631             : :   PhysicalFontFace( rDFA, IFTSFONT_MAGIC ),
     632       22009 :     mpFtFontInfo( pFI )
     633             : {
     634       22009 :     mbDevice        = false;
     635       22009 :     mbOrientation   = true;
     636       22009 : }
     637             : 
     638             : // -----------------------------------------------------------------------
     639             : 
     640        4828 : ImplFontEntry* ImplFTSFontData::CreateFontInstance( FontSelectPattern& rFSD ) const
     641             : {
     642        4828 :     ImplServerFontEntry* pEntry = new ImplServerFontEntry( rFSD );
     643        4828 :     return pEntry;
     644             : }
     645             : 
     646             : // =======================================================================
     647             : // ServerFont
     648             : // =======================================================================
     649             : 
     650        2350 : ServerFont::ServerFont( const FontSelectPattern& rFSD, FtFontInfo* pFI )
     651             : :   maGlyphList( 0),
     652             :     maFontSelData(rFSD),
     653             :     mnExtInfo(0),
     654             :     mnRefCount(1),
     655             :     mnBytesUsed( sizeof(ServerFont) ),
     656             :     mpPrevGCFont( NULL ),
     657             :     mpNextGCFont( NULL ),
     658             :     mnCos( 0x10000),
     659             :     mnSin( 0 ),
     660             :     mbCollectedZW( false ),
     661             :     mnPrioEmbedded(nDefaultPrioEmbedded),
     662             :     mnPrioAntiAlias(nDefaultPrioAntiAlias),
     663             :     mnPrioAutoHint(nDefaultPrioAutoHint),
     664             :     mpFontInfo( pFI ),
     665             :     maFaceFT( NULL ),
     666             :     maSizeFT( NULL ),
     667             :     mbFaceOk( false ),
     668             :     maRecodeConverter( NULL ),
     669        2350 :     mpLayoutEngine( NULL )
     670             : {
     671             :     // TODO: move update of mpFontEntry into FontEntry class when
     672             :     // it becomes reponsible for the ServerFont instantiation
     673        2350 :     ((ImplServerFontEntry*)rFSD.mpFontEntry)->SetServerFont( this );
     674             : 
     675        2350 :     if( rFSD.mnOrientation != 0 )
     676             :     {
     677         123 :         const double dRad = rFSD.mnOrientation * ( F_2PI / 3600.0 );
     678         123 :         mnCos = static_cast<long>( 0x10000 * cos( dRad ) + 0.5 );
     679         123 :         mnSin = static_cast<long>( 0x10000 * sin( dRad ) + 0.5 );
     680             :     }
     681             : 
     682        2350 :     maFaceFT = pFI->GetFaceFT();
     683             : 
     684        2350 :     if( !maFaceFT )
     685           0 :         return;
     686             : 
     687             :     // set the pixel size of the font instance
     688        2350 :     mnWidth = rFSD.mnWidth;
     689        2350 :     if( !mnWidth )
     690        1992 :         mnWidth = rFSD.mnHeight;
     691        2350 :     mfStretch = (double)mnWidth / rFSD.mnHeight;
     692             :     // sanity check (e.g. #i66394#, #i66244#, #66537#)
     693        2350 :     if( (mnWidth < 0) || (mfStretch > +64.0) || (mfStretch < -64.0) )
     694           0 :         return;
     695             : 
     696             :     // perf: use maSizeFT if available
     697        2350 :     if( bEnableSizeFT )
     698             :     {
     699        2350 :         pFTNewSize( maFaceFT, &maSizeFT );
     700        2350 :         pFTActivateSize( maSizeFT );
     701             :     }
     702        2350 :     FT_Error rc = FT_Set_Pixel_Sizes( maFaceFT, mnWidth, rFSD.mnHeight );
     703        2350 :     if( rc != FT_Err_Ok )
     704           0 :         return;
     705             : 
     706             :     // prepare for font encodings other than unicode or symbol
     707        2350 :     FT_Encoding eEncoding = FT_ENCODING_UNICODE;
     708        2350 :     if( mpFontInfo->IsSymbolFont() )
     709             :     {
     710           0 :         if( FT_IS_SFNT( maFaceFT ) )
     711           0 :             eEncoding = ft_encoding_symbol;
     712             :         else
     713           0 :             eEncoding = FT_ENCODING_ADOBE_CUSTOM; // freetype wants this for PS symbol fonts
     714             :     }
     715        2350 :     rc = FT_Select_Charmap( maFaceFT, eEncoding );
     716             :     // no standard encoding applies => we need an encoding converter
     717        2350 :     if( rc != FT_Err_Ok )
     718             :     {
     719           0 :         rtl_TextEncoding eRecodeFrom = RTL_TEXTENCODING_UNICODE;
     720           0 :         for( int i = maFaceFT->num_charmaps; --i >= 0; )
     721             :         {
     722           0 :             const FT_CharMap aCM = maFaceFT->charmaps[i];
     723           0 :             if( aCM->platform_id == TT_PLATFORM_MICROSOFT )
     724             :             {
     725           0 :                 switch( aCM->encoding_id )
     726             :                 {
     727             :                     case TT_MS_ID_SJIS:
     728           0 :                         eEncoding = FT_ENCODING_SJIS;
     729           0 :                         eRecodeFrom = RTL_TEXTENCODING_SHIFT_JIS;
     730           0 :                         break;
     731             :                     case TT_MS_ID_GB2312:
     732           0 :                         eEncoding = FT_ENCODING_GB2312;
     733           0 :                         eRecodeFrom = RTL_TEXTENCODING_GB_2312;
     734           0 :                         break;
     735             :                     case TT_MS_ID_BIG_5:
     736           0 :                         eEncoding = FT_ENCODING_BIG5;
     737           0 :                         eRecodeFrom = RTL_TEXTENCODING_BIG5;
     738           0 :                         break;
     739             :                     case TT_MS_ID_WANSUNG:
     740           0 :                         eEncoding = FT_ENCODING_WANSUNG;
     741           0 :                         eRecodeFrom = RTL_TEXTENCODING_MS_949;
     742           0 :                         break;
     743             :                     case TT_MS_ID_JOHAB:
     744           0 :                         eEncoding = FT_ENCODING_JOHAB;
     745           0 :                         eRecodeFrom = RTL_TEXTENCODING_MS_1361;
     746           0 :                         break;
     747             :                 }
     748             :             }
     749           0 :             else if( aCM->platform_id == TT_PLATFORM_MACINTOSH )
     750             :             {
     751           0 :                 switch( aCM->encoding_id )
     752             :                 {
     753             :                     case TT_MAC_ID_ROMAN:
     754           0 :                         eEncoding = FT_ENCODING_APPLE_ROMAN;
     755           0 :                         eRecodeFrom = RTL_TEXTENCODING_UNICODE; // TODO: use better match
     756           0 :                         break;
     757             :                     // TODO: add other encodings when Mac-only
     758             :                     //       non-unicode fonts show up
     759             :                 }
     760             :             }
     761           0 :             else if( aCM->platform_id == TT_PLATFORM_ADOBE )
     762             :             {
     763           0 :                 switch( aCM->encoding_id )
     764             :                 {
     765             : #ifdef TT_ADOBE_ID_LATIN1
     766             :                     case TT_ADOBE_ID_LATIN1:   // better unicode than nothing
     767             :                         eEncoding = FT_ENCODING_ADOBE_LATIN_1;
     768             :                         eRecodeFrom = RTL_TEXTENCODING_ISO_8859_1;
     769             :                         break;
     770             : #endif // TT_ADOBE_ID_LATIN1
     771             :                     case TT_ADOBE_ID_STANDARD:   // better unicode than nothing
     772           0 :                         eEncoding = FT_ENCODING_ADOBE_STANDARD;
     773           0 :                         eRecodeFrom = RTL_TEXTENCODING_UNICODE; // TODO: use better match
     774           0 :                         break;
     775             :                 }
     776             :             }
     777             :         }
     778             : 
     779           0 :         if( FT_Err_Ok != FT_Select_Charmap( maFaceFT, eEncoding ) )
     780           0 :             return;
     781             : 
     782           0 :         if( eRecodeFrom != RTL_TEXTENCODING_UNICODE )
     783           0 :             maRecodeConverter = rtl_createUnicodeToTextConverter( eRecodeFrom );
     784             :     }
     785             : 
     786        2350 :     mbFaceOk = true;
     787             : 
     788        2350 :     ApplyGSUB( rFSD );
     789             : 
     790             :     // TODO: query GASP table for load flags
     791        2350 :     mnLoadFlags = FT_LOAD_DEFAULT;
     792             : #if 1 // #i97326# cairo sometimes uses FT_Set_Transform() on our FT_FACE
     793             :     // we are not using FT_Set_Transform() yet, so just ignore it for now
     794        2350 :     mnLoadFlags |= FT_LOAD_IGNORE_TRANSFORM;
     795             : #endif
     796             : 
     797        2350 :     mbArtItalic = (rFSD.GetSlant() != ITALIC_NONE && pFI->GetFontAttributes().GetSlant() == ITALIC_NONE);
     798        2350 :     mbArtBold = (rFSD.GetWeight() > WEIGHT_MEDIUM && pFI->GetFontAttributes().GetWeight() <= WEIGHT_MEDIUM);
     799        2350 :     mbUseGamma = false;
     800        2350 :     if( mbArtBold )
     801             :     {
     802             :         //static const int TT_CODEPAGE_RANGE_874  = (1L << 16); // Thai
     803             :         //static const int TT_CODEPAGE_RANGE_932  = (1L << 17); // JIS/Japan
     804             :         //static const int TT_CODEPAGE_RANGE_936  = (1L << 18); // Chinese: Simplified
     805             :         //static const int TT_CODEPAGE_RANGE_949  = (1L << 19); // Korean Wansung
     806             :         //static const int TT_CODEPAGE_RANGE_950  = (1L << 20); // Chinese: Traditional
     807             :         //static const int TT_CODEPAGE_RANGE_1361 = (1L << 21); // Korean Johab
     808             :         static const int TT_CODEPAGE_RANGES1_CJKT = 0x3F0000; // all of the above
     809           2 :         const TT_OS2* pOs2 = (const TT_OS2*)FT_Get_Sfnt_Table( maFaceFT, ft_sfnt_os2 );
     810           2 :         if ((pOs2) && (pOs2->ulCodePageRange1 & TT_CODEPAGE_RANGES1_CJKT )
     811           1 :         && rFSD.mnHeight < 20)
     812           1 :         mbUseGamma = true;
     813             :     }
     814             : 
     815        2350 :     if( ((mnCos != 0) && (mnSin != 0)) || (mnPrioEmbedded <= 0) )
     816          60 :         mnLoadFlags |= FT_LOAD_NO_BITMAP;
     817             : }
     818             : 
     819           0 : void ServerFont::SetFontOptions( boost::shared_ptr<ImplFontOptions> pFontOptions)
     820             : {
     821           0 :     mpFontOptions = pFontOptions;
     822             : 
     823           0 :     if (!mpFontOptions)
     824           0 :         return;
     825             : 
     826           0 :     FontAutoHint eHint = mpFontOptions->GetUseAutoHint();
     827           0 :     if( eHint == AUTOHINT_DONTKNOW )
     828           0 :         eHint = mbUseGamma ? AUTOHINT_TRUE : AUTOHINT_FALSE;
     829             : 
     830           0 :     if( eHint == AUTOHINT_TRUE )
     831           0 :         mnLoadFlags |= FT_LOAD_FORCE_AUTOHINT;
     832             : 
     833           0 :     if( (mnSin != 0) && (mnCos != 0) ) // hinting for 0/90/180/270 degrees only
     834           0 :         mnLoadFlags |= FT_LOAD_NO_HINTING;
     835           0 :     mnLoadFlags |= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH; //#88334#
     836             : 
     837           0 :     if( mpFontOptions->DontUseAntiAlias() )
     838           0 :       mnPrioAntiAlias = 0;
     839           0 :     if( mpFontOptions->DontUseEmbeddedBitmaps() )
     840           0 :       mnPrioEmbedded = 0;
     841           0 :     if( mpFontOptions->DontUseHinting() )
     842           0 :       mnPrioAutoHint = 0;
     843             : 
     844           0 :     if( mnPrioAutoHint <= 0 )
     845           0 :         mnLoadFlags |= FT_LOAD_NO_HINTING;
     846             : 
     847             : #if defined(FT_LOAD_TARGET_LIGHT) && defined(FT_LOAD_TARGET_NORMAL)
     848           0 :     if( !(mnLoadFlags & FT_LOAD_NO_HINTING) )
     849             :     {
     850           0 :        mnLoadFlags |= FT_LOAD_TARGET_NORMAL;
     851           0 :        switch( mpFontOptions->GetHintStyle() )
     852             :        {
     853             :            case HINT_NONE:
     854           0 :                 mnLoadFlags |= FT_LOAD_NO_HINTING;
     855           0 :                 break;
     856             :            case HINT_SLIGHT:
     857           0 :                 mnLoadFlags |= FT_LOAD_TARGET_LIGHT;
     858           0 :                 break;
     859             :            case HINT_MEDIUM:
     860           0 :                 break;
     861             :            case HINT_FULL:
     862             :            default:
     863           0 :                 break;
     864             :        }
     865             :     }
     866             : #endif
     867             : 
     868           0 :     if( mnPrioEmbedded <= 0 )
     869           0 :         mnLoadFlags |= FT_LOAD_NO_BITMAP;
     870             : }
     871             : 
     872           0 : boost::shared_ptr<ImplFontOptions> ServerFont::GetFontOptions() const
     873             : {
     874           0 :     return mpFontOptions;
     875             : }
     876             : 
     877           0 : const OString* ServerFont::GetFontFileName() const
     878             : {
     879           0 :     return mpFontInfo->GetFontFileName();
     880             : }
     881             : 
     882      183081 : bool ServerFont::TestFont() const
     883             : {
     884      183081 :     return mbFaceOk;
     885             : }
     886             : 
     887             : // -----------------------------------------------------------------------
     888             : 
     889        7050 : ServerFont::~ServerFont()
     890             : {
     891        2350 :     if( mpLayoutEngine )
     892        1716 :         delete mpLayoutEngine;
     893             : 
     894        2350 :     if( maRecodeConverter )
     895           0 :         rtl_destroyUnicodeToTextConverter( maRecodeConverter );
     896             : 
     897        2350 :     if( maSizeFT )
     898        2350 :         pFTDoneSize( maSizeFT );
     899             : 
     900        2350 :     mpFontInfo->ReleaseFaceFT( maFaceFT );
     901             : 
     902        2350 :     ReleaseFromGarbageCollect();
     903        4700 : }
     904             : 
     905             :  // -----------------------------------------------------------------------
     906             : 
     907        1716 : int ServerFont::GetEmUnits() const
     908             : {
     909        1716 :     return maFaceFT->units_per_EM;
     910             : }
     911             : 
     912             : // -----------------------------------------------------------------------
     913             : 
     914        4230 : void ServerFont::FetchFontMetric( ImplFontMetricData& rTo, long& rFactor ) const
     915             : {
     916        4230 :     static_cast<ImplFontAttributes&>(rTo) = mpFontInfo->GetFontAttributes();
     917             : 
     918        4230 :     rTo.mbScalableFont  = true;
     919        4230 :     rTo.mbDevice        = true;
     920        4230 :     rTo.mbKernableFont  = (FT_HAS_KERNING( maFaceFT ) != 0) || mpFontInfo->HasExtraKerning();
     921        4230 :     rTo.mnOrientation = GetFontSelData().mnOrientation;
     922             : 
     923             :     //Always consider [star]symbol as symbol fonts
     924        4230 :     if ( IsStarSymbol( rTo.GetFamilyName() ) )
     925         488 :         rTo.SetSymbolFlag( true );
     926             : 
     927        4230 :     if( maSizeFT )
     928        4230 :         pFTActivateSize( maSizeFT );
     929             : 
     930        4230 :     rFactor = 0x100;
     931             : 
     932        4230 :     const TT_OS2* pOS2 = (const TT_OS2*)FT_Get_Sfnt_Table( maFaceFT, ft_sfnt_os2 );
     933        4230 :     const double fScale = (double)GetFontSelData().mnHeight / maFaceFT->units_per_EM;
     934             : 
     935        4230 :     rTo.mnAscent = 0;
     936        4230 :     rTo.mnDescent = 0;
     937        4230 :     rTo.mnExtLeading = 0;
     938        4230 :     rTo.mnSlant = 0;
     939        4230 :     rTo.mnWidth = mnWidth;
     940             : 
     941             :     // Calculating ascender and descender:
     942             :     // FreeType >= 2.4.6 does the right thing, so we just use what it gives us,
     943             :     // for earlier versions we emulate its behaviour;
     944             :     // take them from 'hhea' table,
     945             :     // if zero take them from 'OS/2' table,
     946             :     // if zero take them from FreeType's font metrics
     947        4230 :     if (nFTVERSION >= 2406)
     948             :     {
     949        4230 :         const FT_Size_Metrics& rMetrics = maFaceFT->size->metrics;
     950        4230 :         rTo.mnAscent = (rMetrics.ascender + 32) >> 6;
     951        4230 :         rTo.mnDescent = (-rMetrics.descender + 32) >> 6;
     952        4230 :         rTo.mnExtLeading = ((rMetrics.height + 32) >> 6) - (rTo.mnAscent + rTo.mnDescent);
     953             :     }
     954             :     else
     955             :     {
     956           0 :         const TT_HoriHeader* pHHea = (const TT_HoriHeader*)FT_Get_Sfnt_Table(maFaceFT, ft_sfnt_hhea);
     957           0 :         if (pHHea)
     958             :         {
     959           0 :             rTo.mnAscent = pHHea->Ascender * fScale + 0.5;
     960           0 :             rTo.mnDescent = -pHHea->Descender * fScale + 0.5;
     961           0 :             rTo.mnExtLeading = pHHea->Line_Gap * fScale + 0.5;
     962             :         }
     963             : 
     964           0 :         if (!(rTo.mnAscent || rTo.mnDescent))
     965             :         {
     966           0 :             if (pOS2 && (pOS2->version != 0xFFFF))
     967             :             {
     968           0 :                 if (pOS2->sTypoAscender || pOS2->sTypoDescender)
     969             :                 {
     970           0 :                     rTo.mnAscent = pOS2->sTypoAscender * fScale + 0.5;
     971           0 :                     rTo.mnDescent = -pOS2->sTypoDescender * fScale + 0.5;
     972           0 :                     rTo.mnExtLeading = pOS2->sTypoLineGap * fScale + 0.5;
     973             :                 }
     974             :                 else
     975             :                 {
     976           0 :                     rTo.mnAscent = pOS2->usWinAscent * fScale + 0.5;
     977           0 :                     rTo.mnDescent = pOS2->usWinDescent * fScale + 0.5;
     978           0 :                     rTo.mnExtLeading = 0;
     979             :                 }
     980             :             }
     981             :         }
     982             : 
     983           0 :         if (!(rTo.mnAscent || rTo.mnDescent))
     984             :         {
     985           0 :             const FT_Size_Metrics& rMetrics = maFaceFT->size->metrics;
     986           0 :             rTo.mnAscent = (rMetrics.ascender + 32) >> 6;
     987           0 :             rTo.mnDescent = (-rMetrics.descender + 32) >> 6;
     988           0 :             rTo.mnExtLeading = ((rMetrics.height + 32) >> 6) - (rTo.mnAscent + rTo.mnDescent);
     989             :         }
     990             :     }
     991             : 
     992        4230 :     rTo.mnIntLeading = rTo.mnAscent + rTo.mnDescent - (maFaceFT->units_per_EM * fScale + 0.5);
     993             : 
     994        4230 :     if( pOS2 && (pOS2->version != 0xFFFF) )
     995             :     {
     996             :         // map the panose info from the OS2 table to their VCL counterparts
     997        4180 :         switch( pOS2->panose[0] )
     998             :         {
     999           0 :             case 1: rTo.SetFamilyType( FAMILY_ROMAN ); break;
    1000        3692 :             case 2: rTo.SetFamilyType( FAMILY_SWISS ); break;
    1001           0 :             case 3: rTo.SetFamilyType( FAMILY_MODERN ); break;
    1002           0 :             case 4: rTo.SetFamilyType( FAMILY_SCRIPT ); break;
    1003         488 :             case 5: rTo.SetFamilyType( FAMILY_DECORATIVE ); break;
    1004             :             // TODO: is it reasonable to override the attribute with DONTKNOW?
    1005             :             case 0: // fall through
    1006           0 :             default: rTo.meFamilyType = FAMILY_DONTKNOW; break;
    1007             :         }
    1008             : 
    1009        4180 :         switch( pOS2->panose[3] )
    1010             :         {
    1011             :             case 2: // fall through
    1012             :             case 3: // fall through
    1013             :             case 4: // fall through
    1014             :             case 5: // fall through
    1015             :             case 6: // fall through
    1016             :             case 7: // fall through
    1017        3603 :             case 8: rTo.SetPitch( PITCH_VARIABLE ); break;
    1018          88 :             case 9: rTo.SetPitch( PITCH_FIXED ); break;
    1019             :             // TODO: is it reasonable to override the attribute with DONTKNOW?
    1020             :             case 0: // fall through
    1021             :             case 1: // fall through
    1022         489 :             default: rTo.SetPitch( PITCH_DONTKNOW ); break;
    1023             :         }
    1024             :     }
    1025             : 
    1026             :     // initialize kashida width
    1027             :     // TODO: what if there are different versions of this glyph available
    1028        4230 :     const int nKashidaGlyphId = GetRawGlyphIndex( 0x0640 );
    1029        4230 :     if( nKashidaGlyphId )
    1030             :     {
    1031         886 :         GlyphData aGlyphData;
    1032         886 :         InitGlyphData( nKashidaGlyphId, aGlyphData );
    1033         886 :         rTo.mnMinKashida = aGlyphData.GetMetric().GetCharWidth();
    1034             :     }
    1035        4230 : }
    1036             : 
    1037             : // -----------------------------------------------------------------------
    1038             : 
    1039      931638 : static inline void SplitGlyphFlags( const ServerFont& rFont, int& nGlyphIndex, int& nGlyphFlags )
    1040             : {
    1041      931638 :     nGlyphFlags = nGlyphIndex & GF_FLAGMASK;
    1042      931638 :     nGlyphIndex &= GF_IDXMASK;
    1043             : 
    1044      931638 :     if( nGlyphIndex & GF_ISCHAR )
    1045           0 :         nGlyphIndex = rFont.GetRawGlyphIndex( nGlyphIndex );
    1046      931638 : }
    1047             : 
    1048             : // -----------------------------------------------------------------------
    1049             : 
    1050      931613 : int ServerFont::ApplyGlyphTransform( int nGlyphFlags,
    1051             :     FT_Glyph pGlyphFT, bool bForBitmapProcessing ) const
    1052             : {
    1053      931613 :     int nAngle = GetFontSelData().mnOrientation;
    1054             :     // shortcut most common case
    1055      931613 :     if( !nAngle && !nGlyphFlags )
    1056      895388 :         return nAngle;
    1057             : 
    1058       36225 :     const FT_Size_Metrics& rMetrics = maFaceFT->size->metrics;
    1059             :     FT_Vector aVector;
    1060             :     FT_Matrix aMatrix;
    1061             : 
    1062       36225 :     bool bStretched = false;
    1063             : 
    1064       36225 :     switch( nGlyphFlags & GF_ROTMASK )
    1065             :     {
    1066             :     default:    // straight
    1067       36225 :         aVector.x = 0;
    1068       36225 :         aVector.y = 0;
    1069       36225 :         aMatrix.xx = +mnCos;
    1070       36225 :         aMatrix.yy = +mnCos;
    1071       36225 :         aMatrix.xy = -mnSin;
    1072       36225 :         aMatrix.yx = +mnSin;
    1073       36225 :         break;
    1074             :     case GF_ROTL:    // left
    1075           0 :         nAngle += 900;
    1076           0 :         bStretched = (mfStretch != 1.0);
    1077           0 :         aVector.x  = (FT_Pos)(+rMetrics.descender * mfStretch);
    1078           0 :         aVector.y  = -rMetrics.ascender;
    1079           0 :         aMatrix.xx = (FT_Pos)(-mnSin / mfStretch);
    1080           0 :         aMatrix.yy = (FT_Pos)(-mnSin * mfStretch);
    1081           0 :         aMatrix.xy = (FT_Pos)(-mnCos * mfStretch);
    1082           0 :         aMatrix.yx = (FT_Pos)(+mnCos / mfStretch);
    1083           0 :         break;
    1084             :     case GF_ROTR:    // right
    1085           0 :         nAngle -= 900;
    1086           0 :         bStretched = (mfStretch != 1.0);
    1087           0 :         aVector.x = -maFaceFT->glyph->metrics.horiAdvance;
    1088           0 :         aVector.x += (FT_Pos)(rMetrics.descender * mnSin/65536.0);
    1089           0 :         aVector.y  = (FT_Pos)(-rMetrics.descender * mfStretch * mnCos/65536.0);
    1090           0 :         aMatrix.xx = (FT_Pos)(+mnSin / mfStretch);
    1091           0 :         aMatrix.yy = (FT_Pos)(+mnSin * mfStretch);
    1092           0 :         aMatrix.xy = (FT_Pos)(+mnCos * mfStretch);
    1093           0 :         aMatrix.yx = (FT_Pos)(-mnCos / mfStretch);
    1094           0 :         break;
    1095             :     }
    1096             : 
    1097       72450 :     while( nAngle < 0 )
    1098           0 :         nAngle += 3600;
    1099             : 
    1100       36225 :     if( pGlyphFT->format != FT_GLYPH_FORMAT_BITMAP )
    1101             :     {
    1102       36225 :         FT_Glyph_Transform( pGlyphFT, NULL, &aVector );
    1103             : 
    1104             :         // orthogonal transforms are better handled by bitmap operations
    1105       36225 :         if( bStretched || (bForBitmapProcessing && (nAngle % 900) != 0) )
    1106             :         {
    1107             :             // apply non-orthogonal or stretch transformations
    1108       24462 :             FT_Glyph_Transform( pGlyphFT, &aMatrix, NULL );
    1109       24462 :             nAngle = 0;
    1110             :         }
    1111             :     }
    1112             :     else
    1113             :     {
    1114             :         // FT<=2005 ignores transforms for bitmaps, so do it manually
    1115           0 :         FT_BitmapGlyph pBmpGlyphFT = reinterpret_cast<FT_BitmapGlyph>(pGlyphFT);
    1116           0 :         pBmpGlyphFT->left += (aVector.x + 32) >> 6;
    1117           0 :         pBmpGlyphFT->top  += (aVector.y + 32) >> 6;
    1118             :     }
    1119             : 
    1120       36225 :     return nAngle;
    1121             : }
    1122             : 
    1123             : // -----------------------------------------------------------------------
    1124             : 
    1125    12067047 : int ServerFont::GetRawGlyphIndex(sal_UCS4 aChar, sal_UCS4 aVS) const
    1126             : {
    1127    12067047 :     if( mpFontInfo->IsSymbolFont() )
    1128             :     {
    1129           0 :         if( !FT_IS_SFNT( maFaceFT ) )
    1130             :         {
    1131           0 :             if( (aChar & 0xFF00) == 0xF000 )
    1132           0 :                 aChar &= 0xFF;    // PS font symbol mapping
    1133           0 :             else if( aChar > 0xFF )
    1134           0 :                 return 0;
    1135             :         }
    1136             :     }
    1137             : 
    1138             :     // if needed recode from unicode to font encoding
    1139    12067047 :     if( maRecodeConverter )
    1140             :     {
    1141             :         sal_Char aTempArray[8];
    1142             :         sal_Size nTempSize;
    1143             :         sal_uInt32 nCvtInfo;
    1144             : 
    1145             :         // assume that modern UCS4 fonts have unicode CMAPs
    1146             :     // => no encoding remapping to unicode is needed
    1147           0 :         if( aChar > 0xFFFF )
    1148           0 :             return 0;
    1149             : 
    1150           0 :         sal_Unicode aUCS2Char = static_cast<sal_Unicode>(aChar);
    1151           0 :         rtl_UnicodeToTextContext aContext = rtl_createUnicodeToTextContext( maRecodeConverter );
    1152             :         int nChars = rtl_convertUnicodeToText( maRecodeConverter, aContext,
    1153             :             &aUCS2Char, 1, aTempArray, sizeof(aTempArray),
    1154             :             RTL_UNICODETOTEXT_FLAGS_UNDEFINED_QUESTIONMARK
    1155             :             | RTL_UNICODETOTEXT_FLAGS_INVALID_QUESTIONMARK,
    1156           0 :             &nCvtInfo, &nTempSize );
    1157           0 :         rtl_destroyUnicodeToTextContext( maRecodeConverter, aContext );
    1158             : 
    1159           0 :         aChar = 0;
    1160           0 :         for( int i = 0; i < nChars; ++i )
    1161           0 :             aChar = aChar*256 + (aTempArray[i] & 0xFF);
    1162             :     }
    1163             : 
    1164    12067047 :     int nGlyphIndex = 0;
    1165             :     // If asked, check first for variant glyph with the given Unicode variation
    1166             :     // selector. This is quite uncommon so we don't bother with caching here.
    1167    12067047 :     if (aVS && pFT_Face_GetCharVariantIndex)
    1168           0 :         nGlyphIndex = (*pFT_Face_GetCharVariantIndex)(maFaceFT, aChar, aVS);
    1169             : 
    1170    12067047 :     if (nGlyphIndex == 0)
    1171             :     {
    1172             :         // cache glyph indexes in font info to share between different sizes
    1173    12067047 :         nGlyphIndex = mpFontInfo->GetGlyphIndex( aChar );
    1174    12067047 :         if( nGlyphIndex < 0 )
    1175             :         {
    1176        9915 :             nGlyphIndex = FT_Get_Char_Index( maFaceFT, aChar );
    1177        9915 :             if( !nGlyphIndex)
    1178             :             {
    1179             :                 // check if symbol aliasing helps
    1180         239 :                 if( (aChar <= 0x00FF) && mpFontInfo->IsSymbolFont() )
    1181           0 :                     nGlyphIndex = FT_Get_Char_Index( maFaceFT, aChar | 0xF000 );
    1182             :             }
    1183        9915 :             mpFontInfo->CacheGlyphIndex( aChar, nGlyphIndex );
    1184             :         }
    1185             :     }
    1186             : 
    1187    12067047 :     return nGlyphIndex;
    1188             : }
    1189             : 
    1190             : // -----------------------------------------------------------------------
    1191             : 
    1192    12057051 : int ServerFont::FixupGlyphIndex( int nGlyphIndex, sal_UCS4 aChar ) const
    1193             : {
    1194    12057051 :     int nGlyphFlags = GF_NONE;
    1195             : 
    1196             :     // do glyph substitution if necessary
    1197             :     // CJK vertical writing needs special treatment
    1198    12057051 :     if( GetFontSelData().mbVertical )
    1199             :     {
    1200             :         // TODO: rethink when GSUB is used for non-vertical case
    1201         395 :         GlyphSubstitution::const_iterator it = maGlyphSubstitution.find( nGlyphIndex );
    1202         395 :         if( it == maGlyphSubstitution.end() )
    1203             :         {
    1204         395 :             int nTemp = GetVerticalChar( aChar );
    1205         395 :             if( nTemp ) // is substitution possible
    1206           0 :                 nTemp = GetRawGlyphIndex( nTemp );
    1207         395 :             if( nTemp ) // substitute manually if sensible
    1208           0 :                 nGlyphIndex = nTemp | (GF_GSUB | GF_ROTL);
    1209             :             else
    1210         395 :                 nGlyphFlags |= GetVerticalFlags( aChar );
    1211             :         }
    1212             :         else
    1213             :         {
    1214             :             // for vertical GSUB also compensate for nOrientation=2700
    1215           0 :             nGlyphIndex = (*it).second;
    1216           0 :             nGlyphFlags |= GF_GSUB | GF_ROTL;
    1217             :         }
    1218             :     }
    1219             : 
    1220    12057051 :     if( nGlyphIndex != 0 )
    1221    12056096 :         nGlyphIndex |= nGlyphFlags;
    1222             : 
    1223    12057051 :     return nGlyphIndex;
    1224             : }
    1225             : 
    1226             : 
    1227             : // -----------------------------------------------------------------------
    1228             : 
    1229           0 : int ServerFont::GetGlyphIndex( sal_UCS4 aChar ) const
    1230             : {
    1231           0 :     int nGlyphIndex = GetRawGlyphIndex( aChar );
    1232           0 :     nGlyphIndex = FixupGlyphIndex( nGlyphIndex, aChar );
    1233           0 :     return nGlyphIndex;
    1234             : }
    1235             : 
    1236             : // -----------------------------------------------------------------------
    1237             : 
    1238       25294 : static int lcl_GetCharWidth( FT_FaceRec_* pFaceFT, double fStretch, int nGlyphFlags )
    1239             : {
    1240       25294 :     int nCharWidth = pFaceFT->glyph->metrics.horiAdvance;
    1241             : 
    1242       25294 :     if( nGlyphFlags & GF_ROTMASK )  // for bVertical rotated glyphs
    1243             :     {
    1244           0 :         const FT_Size_Metrics& rMetrics = pFaceFT->size->metrics;
    1245           0 :         nCharWidth = (int)((rMetrics.height + rMetrics.descender) * fStretch);
    1246             :     }
    1247             : 
    1248       25294 :     return (nCharWidth + 32) >> 6;
    1249             : }
    1250             : 
    1251             : // -----------------------------------------------------------------------
    1252             : 
    1253       25311 : void ServerFont::InitGlyphData( int nGlyphIndex, GlyphData& rGD ) const
    1254             : {
    1255       25311 :     if( maSizeFT )
    1256       25311 :         pFTActivateSize( maSizeFT );
    1257             : 
    1258             :     int nGlyphFlags;
    1259       25311 :     SplitGlyphFlags( *this, nGlyphIndex, nGlyphFlags );
    1260             : 
    1261       25311 :     int nLoadFlags = mnLoadFlags;
    1262             : 
    1263             : //  if( mbArtItalic )
    1264             : //      nLoadFlags |= FT_LOAD_NO_BITMAP;
    1265             : 
    1266       25311 :     FT_Error rc = -1;
    1267       25311 :     rc = FT_Load_Glyph( maFaceFT, nGlyphIndex, nLoadFlags );
    1268             : 
    1269       25311 :     if( rc != FT_Err_Ok )
    1270             :     {
    1271             :         // we get here e.g. when a PS font lacks the default glyph
    1272           3 :         rGD.SetCharWidth( 0 );
    1273           3 :         rGD.SetDelta( 0, 0 );
    1274           3 :         rGD.SetOffset( 0, 0 );
    1275           3 :         rGD.SetSize( Size( 0, 0 ) );
    1276       25314 :         return;
    1277             :     }
    1278             : 
    1279       25308 :     const bool bOriginallyZeroWidth = (maFaceFT->glyph->metrics.horiAdvance == 0);
    1280       25308 :     if( mbArtBold && pFTEmbolden )
    1281           4 :         (*pFTEmbolden)( maFaceFT->glyph );
    1282             : 
    1283       25308 :     const int nCharWidth = bOriginallyZeroWidth ? 0 : lcl_GetCharWidth( maFaceFT, mfStretch, nGlyphFlags );
    1284       25308 :     rGD.SetCharWidth( nCharWidth );
    1285             : 
    1286             :     FT_Glyph pGlyphFT;
    1287       25308 :     rc = FT_Get_Glyph( maFaceFT->glyph, &pGlyphFT );
    1288             : 
    1289       25308 :     ApplyGlyphTransform( nGlyphFlags, pGlyphFT, false );
    1290       25308 :     if( mbArtBold && pFTEmbolden && (nFTVERSION < 2200) ) // #i71094# workaround staircase bug
    1291           0 :         pGlyphFT->advance.y = 0;
    1292       25308 :     rGD.SetDelta( (pGlyphFT->advance.x + 0x8000) >> 16, -((pGlyphFT->advance.y + 0x8000) >> 16) );
    1293             : 
    1294             :     FT_BBox aBbox;
    1295       25308 :     FT_Glyph_Get_CBox( pGlyphFT, FT_GLYPH_BBOX_PIXELS, &aBbox );
    1296       25308 :     if( aBbox.yMin > aBbox.yMax )   // circumvent freetype bug
    1297             :     {
    1298           0 :         int t=aBbox.yMin; aBbox.yMin=aBbox.yMax, aBbox.yMax=t;
    1299             :     }
    1300             : 
    1301       25308 :     rGD.SetOffset( aBbox.xMin, -aBbox.yMax );
    1302       25308 :     rGD.SetSize( Size( (aBbox.xMax-aBbox.xMin+1), (aBbox.yMax-aBbox.yMin) ) );
    1303             : 
    1304       25308 :     FT_Done_Glyph( pGlyphFT );
    1305             : }
    1306             : 
    1307             : // -----------------------------------------------------------------------
    1308             : 
    1309           0 : bool ServerFont::GetAntialiasAdvice( void ) const
    1310             : {
    1311           0 :     if( GetFontSelData().mbNonAntialiased || (mnPrioAntiAlias<=0) )
    1312           0 :         return false;
    1313           0 :     bool bAdviseAA = true;
    1314             :     // TODO: also use GASP info
    1315           0 :     return bAdviseAA;
    1316             : }
    1317             : 
    1318             : // -----------------------------------------------------------------------
    1319             : 
    1320           4 : bool ServerFont::GetGlyphBitmap1( int nGlyphIndex, RawBitmap& rRawBitmap ) const
    1321             : {
    1322           4 :     if( maSizeFT )
    1323           4 :         pFTActivateSize( maSizeFT );
    1324             : 
    1325             :     int nGlyphFlags;
    1326           4 :     SplitGlyphFlags( *this, nGlyphIndex, nGlyphFlags );
    1327             : 
    1328           4 :     FT_Int nLoadFlags = mnLoadFlags;
    1329             :     // #i70930# force mono-hinting for monochrome text
    1330           4 :     if( nFTVERSION >= 2110 ) //#i71947# unless it looks worse
    1331             :     {
    1332           4 :         nLoadFlags &= ~0xF0000;
    1333           4 :         nLoadFlags |= FT_LOAD_TARGET_MONO;
    1334             :     }
    1335             : 
    1336           4 :     if( mbArtItalic )
    1337           0 :         nLoadFlags |= FT_LOAD_NO_BITMAP;
    1338             : 
    1339             :     // for 0/90/180/270 degree fonts enable hinting even if not advisable
    1340             :     // non-hinted and non-antialiased bitmaps just look too ugly
    1341           4 :     if( (mnCos==0 || mnSin==0) && (mnPrioAutoHint > 0) )
    1342           4 :         nLoadFlags &= ~FT_LOAD_NO_HINTING;
    1343             : 
    1344           4 :     if( mnPrioEmbedded <= mnPrioAutoHint )
    1345           0 :         nLoadFlags |= FT_LOAD_NO_BITMAP;
    1346             : 
    1347           4 :     FT_Error rc = -1;
    1348           4 :     rc = FT_Load_Glyph( maFaceFT, nGlyphIndex, nLoadFlags );
    1349             : 
    1350           4 :     if( rc != FT_Err_Ok )
    1351           1 :         return false;
    1352             : 
    1353           3 :     if( mbArtBold && pFTEmbolden )
    1354           0 :         (*pFTEmbolden)( maFaceFT->glyph );
    1355             : 
    1356             :     FT_Glyph pGlyphFT;
    1357           3 :     rc = FT_Get_Glyph( maFaceFT->glyph, &pGlyphFT );
    1358           3 :     if( rc != FT_Err_Ok )
    1359           0 :         return false;
    1360             : 
    1361           3 :     int nAngle = ApplyGlyphTransform( nGlyphFlags, pGlyphFT, true );
    1362             : 
    1363           3 :     if( mbArtItalic )
    1364             :     {
    1365             :         FT_Matrix aMatrix;
    1366           0 :         aMatrix.xx = aMatrix.yy = 0x10000L;
    1367           0 :         aMatrix.xy = 0x6000L, aMatrix.yx = 0;
    1368           0 :         FT_Glyph_Transform( pGlyphFT, &aMatrix, NULL );
    1369             :     }
    1370             : 
    1371             :     // Check for zero area bounding boxes as this crashes some versions of FT.
    1372             :     // This also provides a handy short cut as much of the code following
    1373             :     //  becomes an expensive nop when a glyph covers no pixels.
    1374             :     FT_BBox cbox;
    1375           3 :     FT_Glyph_Get_CBox(pGlyphFT, ft_glyph_bbox_unscaled, &cbox);
    1376             : 
    1377           3 :     if( (cbox.xMax - cbox.xMin) == 0 || (cbox.yMax - cbox.yMin == 0) )
    1378             :     {
    1379           0 :         nAngle = 0;
    1380           0 :         memset(&rRawBitmap, 0, sizeof rRawBitmap);
    1381           0 :         FT_Done_Glyph( pGlyphFT );
    1382           0 :         return true;
    1383             :     }
    1384             : 
    1385           3 :     if( pGlyphFT->format != FT_GLYPH_FORMAT_BITMAP )
    1386             :     {
    1387           3 :         if( pGlyphFT->format == FT_GLYPH_FORMAT_OUTLINE )
    1388           3 :             ((FT_OutlineGlyphRec*)pGlyphFT)->outline.flags |= FT_OUTLINE_HIGH_PRECISION;
    1389           3 :         FT_Render_Mode nRenderMode = FT_RENDER_MODE_MONO;
    1390             : 
    1391           3 :         rc = FT_Glyph_To_Bitmap( &pGlyphFT, nRenderMode, NULL, sal_True );
    1392           3 :         if( rc != FT_Err_Ok )
    1393             :         {
    1394           0 :             FT_Done_Glyph( pGlyphFT );
    1395           0 :             return false;
    1396             :         }
    1397             :     }
    1398             : 
    1399           3 :     const FT_BitmapGlyph pBmpGlyphFT = reinterpret_cast<const FT_BitmapGlyph>(pGlyphFT);
    1400             :     // NOTE: autohinting in FT<=2.0.2 miscalculates the offsets below by +-1
    1401           3 :     rRawBitmap.mnXOffset        = +pBmpGlyphFT->left;
    1402           3 :     rRawBitmap.mnYOffset        = -pBmpGlyphFT->top;
    1403             : 
    1404           3 :     const FT_Bitmap& rBitmapFT  = pBmpGlyphFT->bitmap;
    1405           3 :     rRawBitmap.mnHeight         = rBitmapFT.rows;
    1406           3 :     rRawBitmap.mnBitCount       = 1;
    1407           3 :     if( mbArtBold && !pFTEmbolden )
    1408             :     {
    1409           0 :         rRawBitmap.mnWidth = rBitmapFT.width + 1;
    1410           0 :         int nLineBytes = (rRawBitmap.mnWidth + 7) >> 3;
    1411           0 :         rRawBitmap.mnScanlineSize  = (nLineBytes > rBitmapFT.pitch) ? nLineBytes : rBitmapFT.pitch;
    1412             :     }
    1413             :     else
    1414             :     {
    1415           3 :         rRawBitmap.mnWidth          = rBitmapFT.width;
    1416           3 :         rRawBitmap.mnScanlineSize   = rBitmapFT.pitch;
    1417             :     }
    1418             : 
    1419           3 :     const sal_uLong nNeededSize = rRawBitmap.mnScanlineSize * rRawBitmap.mnHeight;
    1420             : 
    1421           3 :     if( rRawBitmap.mnAllocated < nNeededSize )
    1422             :     {
    1423           3 :         delete[] rRawBitmap.mpBits;
    1424           3 :         rRawBitmap.mnAllocated = 2*nNeededSize;
    1425           3 :         rRawBitmap.mpBits = new unsigned char[ rRawBitmap.mnAllocated ];
    1426             :     }
    1427             : 
    1428           3 :     if( !mbArtBold || pFTEmbolden )
    1429             :     {
    1430           3 :         memcpy( rRawBitmap.mpBits, rBitmapFT.buffer, nNeededSize );
    1431             :     }
    1432             :     else
    1433             :     {
    1434           0 :         memset( rRawBitmap.mpBits, 0, nNeededSize );
    1435           0 :         const unsigned char* pSrcLine = rBitmapFT.buffer;
    1436           0 :         unsigned char* pDstLine = rRawBitmap.mpBits;
    1437           0 :         for( int h = rRawBitmap.mnHeight; --h >= 0; )
    1438             :         {
    1439           0 :             memcpy( pDstLine, pSrcLine, rBitmapFT.pitch );
    1440           0 :             pDstLine += rRawBitmap.mnScanlineSize;
    1441           0 :             pSrcLine += rBitmapFT.pitch;
    1442             :         }
    1443             : 
    1444           0 :         unsigned char* p = rRawBitmap.mpBits;
    1445           0 :         for( sal_uLong y=0; y < rRawBitmap.mnHeight; y++ )
    1446             :         {
    1447           0 :             unsigned char nLastByte = 0;
    1448           0 :             for( sal_uLong x=0; x < rRawBitmap.mnScanlineSize; x++ )
    1449             :             {
    1450           0 :             unsigned char nTmp = p[x] << 7;
    1451           0 :             p[x] |= (p[x] >> 1) | nLastByte;
    1452           0 :             nLastByte = nTmp;
    1453             :             }
    1454           0 :             p += rRawBitmap.mnScanlineSize;
    1455             :         }
    1456             :     }
    1457             : 
    1458           3 :     FT_Done_Glyph( pGlyphFT );
    1459             : 
    1460             :     // special case for 0/90/180/270 degree orientation
    1461           3 :     switch( nAngle )
    1462             :     {
    1463             :         case  -900:
    1464             :         case  +900:
    1465             :         case +1800:
    1466             :         case +2700:
    1467           0 :             rRawBitmap.Rotate( nAngle );
    1468           0 :             break;
    1469             :     }
    1470             : 
    1471           3 :     return true;
    1472             : }
    1473             : 
    1474             : // -----------------------------------------------------------------------
    1475             : 
    1476      905369 : bool ServerFont::GetGlyphBitmap8( int nGlyphIndex, RawBitmap& rRawBitmap ) const
    1477             : {
    1478      905369 :     if( maSizeFT )
    1479      905369 :         pFTActivateSize( maSizeFT );
    1480             : 
    1481             :     int nGlyphFlags;
    1482      905369 :     SplitGlyphFlags( *this, nGlyphIndex, nGlyphFlags );
    1483             : 
    1484      905369 :     FT_Int nLoadFlags = mnLoadFlags;
    1485             : 
    1486      905369 :     if( mbArtItalic )
    1487           0 :         nLoadFlags |= FT_LOAD_NO_BITMAP;
    1488             : 
    1489      905369 :     if( (nGlyphFlags & GF_UNHINTED) || (mnPrioAutoHint < mnPrioAntiAlias) )
    1490           0 :         nLoadFlags |= FT_LOAD_NO_HINTING;
    1491             : 
    1492      905369 :     if( mnPrioEmbedded <= mnPrioAntiAlias )
    1493           0 :         nLoadFlags |= FT_LOAD_NO_BITMAP;
    1494             : 
    1495      905369 :     FT_Error rc = -1;
    1496      905369 :     rc = FT_Load_Glyph( maFaceFT, nGlyphIndex, nLoadFlags );
    1497             : 
    1498      905369 :     if( rc != FT_Err_Ok )
    1499           2 :         return false;
    1500             : 
    1501      905367 :     if( mbArtBold && pFTEmbolden )
    1502           4 :         (*pFTEmbolden)( maFaceFT->glyph );
    1503             : 
    1504             :     FT_Glyph pGlyphFT;
    1505      905367 :     rc = FT_Get_Glyph( maFaceFT->glyph, &pGlyphFT );
    1506      905367 :     if( rc != FT_Err_Ok )
    1507           0 :         return false;
    1508             : 
    1509      905367 :     int nAngle = ApplyGlyphTransform( nGlyphFlags, pGlyphFT, true );
    1510             : 
    1511      905367 :     if( mbArtItalic )
    1512             :     {
    1513             :         FT_Matrix aMatrix;
    1514           0 :         aMatrix.xx = aMatrix.yy = 0x10000L;
    1515           0 :         aMatrix.xy = 0x6000L, aMatrix.yx = 0;
    1516           0 :         FT_Glyph_Transform( pGlyphFT, &aMatrix, NULL );
    1517             :     }
    1518             : 
    1519      905367 :     if( pGlyphFT->format == FT_GLYPH_FORMAT_OUTLINE )
    1520      905363 :         ((FT_OutlineGlyph)pGlyphFT)->outline.flags |= FT_OUTLINE_HIGH_PRECISION;
    1521             : 
    1522      905367 :     bool bEmbedded = (pGlyphFT->format == FT_GLYPH_FORMAT_BITMAP);
    1523      905367 :     if( !bEmbedded )
    1524             :     {
    1525      905363 :         rc = FT_Glyph_To_Bitmap( &pGlyphFT, FT_RENDER_MODE_NORMAL, NULL, sal_True );
    1526      905363 :         if( rc != FT_Err_Ok )
    1527             :         {
    1528           0 :             FT_Done_Glyph( pGlyphFT );
    1529           0 :             return false;
    1530             :         }
    1531             :     }
    1532             : 
    1533      905367 :     const FT_BitmapGlyph pBmpGlyphFT = reinterpret_cast<const FT_BitmapGlyph>(pGlyphFT);
    1534      905367 :     rRawBitmap.mnXOffset        = +pBmpGlyphFT->left;
    1535      905367 :     rRawBitmap.mnYOffset        = -pBmpGlyphFT->top;
    1536             : 
    1537      905367 :     const FT_Bitmap& rBitmapFT  = pBmpGlyphFT->bitmap;
    1538      905367 :     rRawBitmap.mnHeight         = rBitmapFT.rows;
    1539      905367 :     rRawBitmap.mnWidth          = rBitmapFT.width;
    1540      905367 :     rRawBitmap.mnBitCount       = 8;
    1541      905367 :     rRawBitmap.mnScanlineSize   = bEmbedded ? rBitmapFT.width : rBitmapFT.pitch;
    1542      905367 :     if( mbArtBold && !pFTEmbolden )
    1543             :     {
    1544           0 :         ++rRawBitmap.mnWidth;
    1545           0 :             ++rRawBitmap.mnScanlineSize;
    1546             :     }
    1547      905367 :     rRawBitmap.mnScanlineSize = (rRawBitmap.mnScanlineSize + 3) & -4;
    1548             : 
    1549      905367 :     const sal_uLong nNeededSize = rRawBitmap.mnScanlineSize * rRawBitmap.mnHeight;
    1550      905367 :     if( rRawBitmap.mnAllocated < nNeededSize )
    1551             :     {
    1552      825815 :         delete[] rRawBitmap.mpBits;
    1553      825815 :         rRawBitmap.mnAllocated = 2*nNeededSize;
    1554      825815 :         rRawBitmap.mpBits = new unsigned char[ rRawBitmap.mnAllocated ];
    1555             :     }
    1556             : 
    1557      905367 :     const unsigned char* pSrc = rBitmapFT.buffer;
    1558      905367 :     unsigned char* pDest = rRawBitmap.mpBits;
    1559      905367 :     if( !bEmbedded )
    1560             :     {
    1561    10034986 :         for( int y = rRawBitmap.mnHeight, x; --y >= 0 ; )
    1562             :         {
    1563    74472359 :             for( x = 0; x < rBitmapFT.width; ++x )
    1564    66248099 :                 *(pDest++) = *(pSrc++);
    1565    18033749 :             for(; x < int(rRawBitmap.mnScanlineSize); ++x )
    1566     9809489 :                 *(pDest++) = 0;
    1567             :         }
    1568             :     }
    1569             :     else
    1570             :     {
    1571          56 :         for( int y = rRawBitmap.mnHeight, x; --y >= 0 ; )
    1572             :         {
    1573          48 :             unsigned char nSrc = 0;
    1574         672 :             for( x = 0; x < rBitmapFT.width; ++x, nSrc+=nSrc )
    1575             :             {
    1576         624 :                 if( (x & 7) == 0 )
    1577          96 :                     nSrc = *(pSrc++);
    1578         624 :                 *(pDest++) = (0x7F - nSrc) >> 8;
    1579             :             }
    1580         192 :             for(; x < int(rRawBitmap.mnScanlineSize); ++x )
    1581         144 :                 *(pDest++) = 0;
    1582             :         }
    1583             :     }
    1584             : 
    1585      905367 :     if( mbArtBold && !pFTEmbolden )
    1586             :     {
    1587             :         // overlay with glyph image shifted by one left pixel
    1588           0 :         unsigned char* p = rRawBitmap.mpBits;
    1589           0 :         for( sal_uLong y=0; y < rRawBitmap.mnHeight; y++ )
    1590             :         {
    1591           0 :             unsigned char nLastByte = 0;
    1592           0 :             for( sal_uLong x=0; x < rRawBitmap.mnWidth; x++ )
    1593             :             {
    1594           0 :                 unsigned char nTmp = p[x];
    1595           0 :                 p[x] |= p[x] | nLastByte;
    1596           0 :                 nLastByte = nTmp;
    1597             :             }
    1598           0 :             p += rRawBitmap.mnScanlineSize;
    1599             :         }
    1600             :     }
    1601             : 
    1602      905367 :     if( !bEmbedded && mbUseGamma )
    1603             :     {
    1604           0 :         unsigned char* p = rRawBitmap.mpBits;
    1605           0 :         for( sal_uLong y=0; y < rRawBitmap.mnHeight; y++ )
    1606             :         {
    1607           0 :             for( sal_uLong x=0; x < rRawBitmap.mnWidth; x++ )
    1608             :             {
    1609           0 :                 p[x] = aGammaTable[ p[x] ];
    1610             :             }
    1611           0 :             p += rRawBitmap.mnScanlineSize;
    1612             :         }
    1613             :     }
    1614             : 
    1615      905367 :     FT_Done_Glyph( pGlyphFT );
    1616             : 
    1617             :     // special case for 0/90/180/270 degree orientation
    1618      905367 :     switch( nAngle )
    1619             :     {
    1620             :         case  -900:
    1621             :         case  +900:
    1622             :         case +1800:
    1623             :         case +2700:
    1624       10618 :             rRawBitmap.Rotate( nAngle );
    1625       10618 :             break;
    1626             :     }
    1627             : 
    1628      905367 :     return true;
    1629             : }
    1630             : 
    1631             : // -----------------------------------------------------------------------
    1632             : // determine unicode ranges in font
    1633             : // -----------------------------------------------------------------------
    1634             : 
    1635        4273 : const ImplFontCharMap* ServerFont::GetImplFontCharMap( void ) const
    1636             : {
    1637        4273 :     const ImplFontCharMap* pIFCMap = mpFontInfo->GetImplFontCharMap();
    1638        4273 :     return pIFCMap;
    1639             : }
    1640             : 
    1641        4273 : const ImplFontCharMap* FtFontInfo::GetImplFontCharMap( void )
    1642             : {
    1643             :     // check if the charmap is already cached
    1644        4273 :     if( mpFontCharMap )
    1645        4133 :         return mpFontCharMap;
    1646             : 
    1647             :     // get the charmap and cache it
    1648         140 :     CmapResult aCmapResult;
    1649         140 :     bool bOK = GetFontCodeRanges( aCmapResult );
    1650         140 :     if( bOK )
    1651         140 :         mpFontCharMap = new ImplFontCharMap( aCmapResult );
    1652             :     else
    1653           0 :                mpFontCharMap = ImplFontCharMap::GetDefaultMap();
    1654         140 :     mpFontCharMap->AddReference();
    1655         140 :     return mpFontCharMap;
    1656             : }
    1657             : 
    1658             : // TODO: merge into method GetFontCharMap()
    1659         140 : bool FtFontInfo::GetFontCodeRanges( CmapResult& rResult ) const
    1660             : {
    1661         140 :     rResult.mbSymbolic = IsSymbolFont();
    1662             : 
    1663             :     // TODO: is the full CmapResult needed on platforms calling this?
    1664         140 :     if( FT_IS_SFNT( maFaceFT ) )
    1665             :     {
    1666         140 :         sal_uLong nLength = 0;
    1667         140 :         const unsigned char* pCmap = GetTable( "cmap", &nLength );
    1668         140 :         if( pCmap && (nLength > 0) )
    1669         140 :             if( ParseCMAP( pCmap, nLength, rResult ) )
    1670         140 :                 return true;
    1671             :     }
    1672             : 
    1673             :     typedef std::vector<sal_uInt32> U32Vector;
    1674           0 :     U32Vector aCodes;
    1675             : 
    1676             :     // FT's coverage is available since FT>=2.1.0 (OOo-baseline>=2.1.4 => ok)
    1677           0 :     aCodes.reserve( 0x1000 );
    1678             :     FT_UInt nGlyphIndex;
    1679           0 :     for( sal_uInt32 cCode = FT_Get_First_Char( maFaceFT, &nGlyphIndex );; )
    1680             :     {
    1681           0 :         if( !nGlyphIndex )
    1682           0 :             break;
    1683           0 :         aCodes.push_back( cCode );  // first code inside range
    1684           0 :         sal_uInt32 cNext = cCode;
    1685           0 :         do cNext = FT_Get_Next_Char( maFaceFT, cCode, &nGlyphIndex ); while( cNext == ++cCode );
    1686           0 :         aCodes.push_back( cCode );  // first code outside range
    1687           0 :         cCode = cNext;
    1688           0 :     }
    1689             : 
    1690           0 :     const int nCount = aCodes.size();
    1691           0 :     if( !nCount) {
    1692           0 :         if( !rResult.mbSymbolic )
    1693           0 :             return false;
    1694             : 
    1695             :         // we usually get here for Type1 symbol fonts
    1696           0 :         aCodes.push_back( 0xF020 );
    1697           0 :         aCodes.push_back( 0xF100 );
    1698             :     }
    1699             : 
    1700           0 :     sal_uInt32* pCodes = new sal_uInt32[ nCount ];
    1701           0 :     for( int i = 0; i < nCount; ++i )
    1702           0 :         pCodes[i] = aCodes[i];
    1703           0 :     rResult.mpRangeCodes = pCodes;
    1704           0 :     rResult.mnRangeCount = nCount / 2;
    1705           0 :     return true;
    1706             : }
    1707             : 
    1708         517 : bool ServerFont::GetFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const
    1709             : {
    1710         517 :     bool bRet = false;
    1711             : 
    1712         517 :     sal_uLong nLength = 0;
    1713             :     // load GSUB table
    1714         517 :     const FT_Byte* pGSUB = mpFontInfo->GetTable("GSUB", &nLength);
    1715         517 :     if (pGSUB)
    1716         517 :         vcl::getTTScripts(rFontCapabilities.maGSUBScriptTags, pGSUB, nLength);
    1717             : 
    1718             :     // load OS/2 table
    1719         517 :     const FT_Byte* pOS2 = mpFontInfo->GetTable("OS/2", &nLength);
    1720         517 :     if (pOS2)
    1721             :     {
    1722             :         bRet = vcl::getTTCoverage(
    1723             :             rFontCapabilities.maUnicodeRange,
    1724             :             rFontCapabilities.maCodePageRange,
    1725         517 :             pOS2, nLength);
    1726             :     }
    1727             : 
    1728         517 :     return bRet;
    1729             : }
    1730             : 
    1731             : // -----------------------------------------------------------------------
    1732             : 
    1733           0 : sal_uLong ServerFont::GetKernPairs( ImplKernPairData** ppKernPairs ) const
    1734             : {
    1735             :     // if no kerning info is available in the font file
    1736           0 :     *ppKernPairs = NULL;
    1737           0 :     if( !FT_HAS_KERNING( maFaceFT ) || !FT_IS_SFNT( maFaceFT ) )
    1738             :     {
    1739             :         // then we have may have extra kerning info from e.g. psprint
    1740           0 :         int nCount = mpFontInfo->GetExtraKernPairs( ppKernPairs );
    1741             :         // scale the kern values to match the font size
    1742           0 :         const FontSelectPattern& rFSD = GetFontSelData();
    1743           0 :         int nFontWidth = rFSD.mnWidth ? rFSD.mnWidth : rFSD.mnHeight;
    1744           0 :         ImplKernPairData* pKernPair = *ppKernPairs;
    1745           0 :         for( int i = nCount; --i >= 0; ++pKernPair )
    1746             :         {
    1747           0 :             long& rVal = pKernPair->mnKern;
    1748           0 :             rVal = ((rVal * nFontWidth) + 500) / 1000;
    1749             :         }
    1750           0 :         return nCount;
    1751             :     }
    1752             : 
    1753             :     // when font faces of different sizes share the same maFaceFT
    1754             :     // then we have to make sure that it uses the correct maSizeFT
    1755           0 :     if( maSizeFT )
    1756           0 :         pFTActivateSize( maSizeFT );
    1757             : 
    1758             :     // first figure out which glyph pairs are involved in kerning
    1759           0 :     sal_uLong nKernLength = 0;
    1760           0 :     const FT_Byte* const pKern = mpFontInfo->GetTable( "kern", &nKernLength );
    1761           0 :     if( !pKern )
    1762           0 :         return 0;
    1763             : 
    1764             :     // combine TTF/OTF tables from the font file to build a vector of
    1765             :     // unicode kerning pairs using Freetype's glyph kerning calculation
    1766             :     // for the kerning value
    1767             : 
    1768             :     // TODO: is it worth to share the glyph->unicode mapping between
    1769             :     // different instances of the same font face?
    1770             : 
    1771             :     typedef std::vector<ImplKernPairData> KernVector;
    1772           0 :     KernVector aKernGlyphVector;
    1773             :     ImplKernPairData aKernPair;
    1774           0 :     aKernPair.mnKern = 0; // To prevent "is used uninitialized" warning...
    1775             : 
    1776           0 :     const FT_Byte* pBuffer = pKern;
    1777           0 :     sal_uLong nVersion = GetUShort( pBuffer+0 );
    1778           0 :     sal_uInt16 nTableCnt = GetUShort( pBuffer+2 );
    1779             : 
    1780             :     // Microsoft/Old TrueType style kern table
    1781           0 :     if ( nVersion == 0 )
    1782             :     {
    1783           0 :         pBuffer += 4;
    1784             : 
    1785           0 :         for( sal_uInt16 nTableIdx = 0; nTableIdx < nTableCnt; ++nTableIdx )
    1786             :         {
    1787             :             // sal_uInt16 nSubVersion  = GetUShort( pBuffer+0 );
    1788             :             // sal_uInt16 nSubLength   = GetUShort( pBuffer+2 );
    1789           0 :             sal_uInt16 nSubCoverage = GetUShort( pBuffer+4 );
    1790           0 :             pBuffer += 6;
    1791           0 :             if( (nSubCoverage&0x03) != 0x01 )   // no interest in minimum info here
    1792           0 :                 continue;
    1793           0 :             switch( nSubCoverage >> 8 )
    1794             :             {
    1795             :                 case 0: // version 0, kerning format 0
    1796             :                 {
    1797           0 :                     sal_uInt16 nPairs = GetUShort( pBuffer );
    1798           0 :                     pBuffer += 8;   // skip search hints
    1799           0 :                     aKernGlyphVector.reserve( aKernGlyphVector.size() + nPairs );
    1800           0 :                     for( int i = 0; i < nPairs; ++i )
    1801             :                     {
    1802           0 :                         aKernPair.mnChar1 = GetUShort( pBuffer+0 );
    1803           0 :                         aKernPair.mnChar2 = GetUShort( pBuffer+2 );
    1804             :                         //long nUnscaledKern= GetSShort( pBuffer );
    1805           0 :                         pBuffer += 6;
    1806           0 :                         aKernGlyphVector.push_back( aKernPair );
    1807             :                     }
    1808             :                 }
    1809           0 :                 break;
    1810             : 
    1811             :                 case 2: // version 0, kerning format 2
    1812             :                 {
    1813           0 :                     const FT_Byte* pSubTable = pBuffer;
    1814             :                     //sal_uInt16 nRowWidth  = GetUShort( pBuffer+0 );
    1815           0 :                     sal_uInt16 nOfsLeft     = GetUShort( pBuffer+2 );
    1816           0 :                     sal_uInt16 nOfsRight    = GetUShort( pBuffer+4 );
    1817           0 :                     sal_uInt16 nOfsArray    = GetUShort( pBuffer+6 );
    1818           0 :                     pBuffer += 8;
    1819             : 
    1820           0 :                     const FT_Byte* pTmp = pSubTable + nOfsLeft;
    1821           0 :                     sal_uInt16 nFirstLeft   = GetUShort( pTmp+0 );
    1822           0 :                     sal_uInt16 nLastLeft    = GetUShort( pTmp+2 ) + nFirstLeft - 1;
    1823             : 
    1824           0 :                     pTmp = pSubTable + nOfsRight;
    1825           0 :                     sal_uInt16 nFirstRight  = GetUShort( pTmp+0 );
    1826           0 :                     sal_uInt16 nLastRight   = GetUShort( pTmp+2 ) + nFirstRight - 1;
    1827             : 
    1828           0 :                     sal_uLong nPairs = (sal_uLong)(nLastLeft - nFirstLeft + 1) * (nLastRight - nFirstRight + 1);
    1829           0 :                     aKernGlyphVector.reserve( aKernGlyphVector.size() + nPairs );
    1830             : 
    1831           0 :                     pTmp = pSubTable + nOfsArray;
    1832           0 :                     for( int nLeft = nFirstLeft; nLeft < nLastLeft; ++nLeft )
    1833             :                     {
    1834           0 :                         aKernPair.mnChar1 = nLeft;
    1835           0 :                         for( int nRight = 0; nRight < nLastRight; ++nRight )
    1836             :                         {
    1837           0 :                             if( GetUShort( pTmp ) != 0 )
    1838             :                             {
    1839           0 :                                 aKernPair.mnChar2 = nRight;
    1840           0 :                                 aKernGlyphVector.push_back( aKernPair );
    1841             :                             }
    1842           0 :                             pTmp += 2;
    1843             :                         }
    1844             :                     }
    1845             :                 }
    1846           0 :                 break;
    1847             :             }
    1848             :         }
    1849             :     }
    1850             : 
    1851             :     // Apple New style kern table
    1852           0 :     pBuffer = pKern;
    1853           0 :     nVersion = NEXT_U32( pBuffer );
    1854           0 :     nTableCnt = NEXT_U32( pBuffer );
    1855           0 :     if ( nVersion == 0x00010000 )
    1856             :     {
    1857           0 :         for( sal_uInt16 nTableIdx = 0; nTableIdx < nTableCnt; ++nTableIdx )
    1858             :         {
    1859           0 :             /*sal_uLong  nLength  =*/ NEXT_U32( pBuffer );
    1860           0 :             sal_uInt16 nCoverage   = NEXT_U16( pBuffer );
    1861           0 :             /*sal_uInt16 nTupleIndex =*/ NEXT_U16( pBuffer );
    1862             : 
    1863             :             // Kerning sub-table format, 0 through 3
    1864           0 :             sal_uInt8 nSubTableFormat  = nCoverage & 0x00FF;
    1865             : 
    1866           0 :             switch( nSubTableFormat )
    1867             :             {
    1868             :                 case 0: // version 0, kerning format 0
    1869             :                 {
    1870           0 :                     sal_uInt16 nPairs = NEXT_U16( pBuffer );
    1871           0 :                     pBuffer += 6;   // skip search hints
    1872           0 :                     aKernGlyphVector.reserve( aKernGlyphVector.size() + nPairs );
    1873           0 :                     for( int i = 0; i < nPairs; ++i )
    1874             :                     {
    1875           0 :                         aKernPair.mnChar1 = NEXT_U16( pBuffer );
    1876           0 :                         aKernPair.mnChar2 = NEXT_U16( pBuffer );
    1877           0 :                         /*long nUnscaledKern=*/ NEXT_S16( pBuffer );
    1878           0 :                         aKernGlyphVector.push_back( aKernPair );
    1879             :                     }
    1880             :                 }
    1881           0 :                 break;
    1882             : 
    1883             :                 case 2: // version 0, kerning format 2
    1884             :                 {
    1885           0 :                     const FT_Byte* pSubTable = pBuffer;
    1886           0 :                     /*sal_uInt16 nRowWidth  =*/ NEXT_U16( pBuffer );
    1887           0 :                     sal_uInt16 nOfsLeft     = NEXT_U16( pBuffer );
    1888           0 :                     sal_uInt16 nOfsRight    = NEXT_U16( pBuffer );
    1889           0 :                     sal_uInt16 nOfsArray    = NEXT_U16( pBuffer );
    1890             : 
    1891           0 :                     const FT_Byte* pTmp = pSubTable + nOfsLeft;
    1892           0 :                     sal_uInt16 nFirstLeft   = NEXT_U16( pTmp );
    1893           0 :                     sal_uInt16 nLastLeft    = NEXT_U16( pTmp ) + nFirstLeft - 1;
    1894             : 
    1895           0 :                     pTmp = pSubTable + nOfsRight;
    1896           0 :                     sal_uInt16 nFirstRight  = NEXT_U16( pTmp );
    1897           0 :                     sal_uInt16 nLastRight   = NEXT_U16( pTmp ) + nFirstRight - 1;
    1898             : 
    1899           0 :                     sal_uLong nPairs = (sal_uLong)(nLastLeft - nFirstLeft + 1) * (nLastRight - nFirstRight + 1);
    1900           0 :                     aKernGlyphVector.reserve( aKernGlyphVector.size() + nPairs );
    1901             : 
    1902           0 :                     pTmp = pSubTable + nOfsArray;
    1903           0 :                     for( int nLeft = nFirstLeft; nLeft < nLastLeft; ++nLeft )
    1904             :                     {
    1905           0 :                         aKernPair.mnChar1 = nLeft;
    1906           0 :                         for( int nRight = 0; nRight < nLastRight; ++nRight )
    1907             :                         {
    1908           0 :                             if( NEXT_S16( pTmp ) != 0 )
    1909             :                             {
    1910           0 :                                 aKernPair.mnChar2 = nRight;
    1911           0 :                                 aKernGlyphVector.push_back( aKernPair );
    1912             :                             }
    1913             :                         }
    1914             :                     }
    1915             :                 }
    1916           0 :                 break;
    1917             : 
    1918             :                 default:
    1919           0 :                     fprintf( stderr, "gcach_ftyp.cxx:  Found unsupported Apple-style kern subtable type %d.\n", nSubTableFormat );
    1920           0 :                     break;
    1921             :             }
    1922             :         }
    1923             :     }
    1924             : 
    1925             :     // now create VCL's ImplKernPairData[] format for all glyph pairs
    1926           0 :     sal_uLong nKernCount = aKernGlyphVector.size();
    1927           0 :     if( nKernCount )
    1928             :     {
    1929             :         // prepare glyphindex to character mapping
    1930             :         // TODO: this is needed to support VCL's existing kerning infrastructure,
    1931             :         // eliminate it up by redesigning kerning infrastructure to work with glyph indizes
    1932             :         typedef boost::unordered_multimap<sal_uInt16,sal_Unicode> Cmap;
    1933           0 :         Cmap aCmap;
    1934           0 :         for( sal_Unicode aChar = 0x0020; aChar < 0xFFFE; ++aChar )
    1935             :         {
    1936           0 :             sal_uInt16 nGlyphIndex = GetGlyphIndex( aChar );
    1937           0 :             if( nGlyphIndex )
    1938           0 :                 aCmap.insert( Cmap::value_type( nGlyphIndex, aChar ) );
    1939             :         }
    1940             : 
    1941             :         // translate both glyph indizes in kerning pairs to characters
    1942             :         // problem is that these are 1:n mappings...
    1943           0 :         KernVector aKernCharVector;
    1944           0 :         aKernCharVector.reserve( nKernCount );
    1945           0 :         KernVector::iterator it;
    1946           0 :         for( it = aKernGlyphVector.begin(); it != aKernGlyphVector.end(); ++it )
    1947             :         {
    1948             :             FT_Vector aKernVal;
    1949           0 :             FT_Error rcFT = FT_Get_Kerning( maFaceFT, it->mnChar1, it->mnChar2,
    1950           0 :                 FT_KERNING_DEFAULT, &aKernVal );
    1951           0 :             aKernPair.mnKern = aKernVal.x >> 6;
    1952           0 :             if( (aKernPair.mnKern == 0) || (rcFT != FT_Err_Ok) )
    1953           0 :                 continue;
    1954             : 
    1955             :             typedef std::pair<Cmap::iterator,Cmap::iterator> CPair;
    1956           0 :             const CPair p1 = aCmap.equal_range( it->mnChar1 );
    1957           0 :             const CPair p2 = aCmap.equal_range( it->mnChar2 );
    1958           0 :             for( Cmap::const_iterator i1 = p1.first; i1 != p1.second; ++i1 )
    1959             :             {
    1960           0 :                 aKernPair.mnChar1 = (*i1).second;
    1961           0 :                 for( Cmap::const_iterator i2 = p2.first; i2 != p2.second; ++i2 )
    1962             :                 {
    1963           0 :                     aKernPair.mnChar2 = (*i2).second;
    1964           0 :                     aKernCharVector.push_back( aKernPair );
    1965             :                 }
    1966             :             }
    1967             :         }
    1968             : 
    1969             :         // now move the resulting vector into VCL's ImplKernPairData[] format
    1970           0 :         nKernCount = aKernCharVector.size();
    1971           0 :         ImplKernPairData* pTo = new ImplKernPairData[ nKernCount ];
    1972           0 :         *ppKernPairs = pTo;
    1973           0 :         for( it = aKernCharVector.begin(); it != aKernCharVector.end(); ++it, ++pTo )
    1974             :         {
    1975           0 :             pTo->mnChar1 = it->mnChar1;
    1976           0 :             pTo->mnChar2 = it->mnChar2;
    1977           0 :             pTo->mnKern = it->mnKern;
    1978           0 :         }
    1979             :     }
    1980             : 
    1981           0 :     return nKernCount;
    1982             : }
    1983             : 
    1984             : // -----------------------------------------------------------------------
    1985             : // outline stuff
    1986             : // -----------------------------------------------------------------------
    1987             : 
    1988             : class PolyArgs
    1989             : {
    1990             : public:
    1991             :                 PolyArgs( PolyPolygon& rPolyPoly, sal_uInt16 nMaxPoints );
    1992             :                 ~PolyArgs();
    1993             : 
    1994             :     void        AddPoint( long nX, long nY, PolyFlags);
    1995             :     void        ClosePolygon();
    1996             : 
    1997        8954 :     long        GetPosX() const { return maPosition.x;}
    1998        8954 :     long        GetPosY() const { return maPosition.y;}
    1999             : 
    2000             : private:
    2001             :     PolyPolygon& mrPolyPoly;
    2002             : 
    2003             :     Point*      mpPointAry;
    2004             :     sal_uInt8*       mpFlagAry;
    2005             : 
    2006             :     FT_Vector   maPosition;
    2007             :     sal_uInt16      mnMaxPoints;
    2008             :     sal_uInt16      mnPoints;
    2009             :     sal_uInt16      mnPoly;
    2010             :     bool        bHasOffline;
    2011             : };
    2012             : 
    2013             : // -----------------------------------------------------------------------
    2014             : 
    2015         935 : PolyArgs::PolyArgs( PolyPolygon& rPolyPoly, sal_uInt16 nMaxPoints )
    2016             : :   mrPolyPoly(rPolyPoly),
    2017             :     mnMaxPoints(nMaxPoints),
    2018             :     mnPoints(0),
    2019             :     mnPoly(0),
    2020         935 :     bHasOffline(false)
    2021             : {
    2022         935 :     mpPointAry  = new Point[ mnMaxPoints ];
    2023         935 :     mpFlagAry   = new sal_uInt8 [ mnMaxPoints ];
    2024         935 : }
    2025             : 
    2026             : // -----------------------------------------------------------------------
    2027             : 
    2028             : 
    2029         935 : PolyArgs::~PolyArgs()
    2030             : {
    2031         935 :     delete[] mpFlagAry;
    2032         935 :     delete[] mpPointAry;
    2033         935 : }
    2034             : 
    2035             : // -----------------------------------------------------------------------
    2036             : 
    2037       34937 : void PolyArgs::AddPoint( long nX, long nY, PolyFlags aFlag )
    2038             : {
    2039             :     DBG_ASSERT( (mnPoints < mnMaxPoints), "FTGlyphOutline: AddPoint overflow!" );
    2040       34937 :     if( mnPoints >= mnMaxPoints )
    2041       34937 :         return;
    2042             : 
    2043       34937 :     maPosition.x = nX;
    2044       34937 :     maPosition.y = nY;
    2045       34937 :     mpPointAry[ mnPoints ] = Point( nX, nY );
    2046       34937 :     mpFlagAry[ mnPoints++ ]= aFlag;
    2047       34937 :     bHasOffline |= (aFlag != POLY_NORMAL);
    2048             : }
    2049             : 
    2050             : // -----------------------------------------------------------------------
    2051             : 
    2052        2421 : void PolyArgs::ClosePolygon()
    2053             : {
    2054        2421 :     if( !mnPoly++ )
    2055        3356 :         return;
    2056             : 
    2057             :     // freetype seems to always close the polygon with an ON_CURVE point
    2058             :     // PolyPoly wants to close the polygon itself => remove last point
    2059             :     DBG_ASSERT( (mnPoints >= 2), "FTGlyphOutline: PolyFinishNum failed!" );
    2060        1486 :     --mnPoints;
    2061             :     DBG_ASSERT( (mpPointAry[0]==mpPointAry[mnPoints]), "FTGlyphOutline: PolyFinishEq failed!" );
    2062             :     DBG_ASSERT( (mpFlagAry[0]==POLY_NORMAL), "FTGlyphOutline: PolyFinishFE failed!" );
    2063             :     DBG_ASSERT( (mpFlagAry[mnPoints]==POLY_NORMAL), "FTGlyphOutline: PolyFinishFS failed!" );
    2064             : 
    2065        1486 :     Polygon aPoly( mnPoints, mpPointAry, (bHasOffline ? mpFlagAry : NULL) );
    2066             : 
    2067             :     // #i35928#
    2068             :     // This may be a invalid polygons, e.g. the last point is a control point.
    2069             :     // So close the polygon (and add the first point again) if the last point
    2070             :     // is a control point or different from first.
    2071             :     // #i48298#
    2072             :     // Now really duplicating the first point, to close or correct the
    2073             :     // polygon. Also no longer duplicating the flags, but enforcing
    2074             :     // POLY_NORMAL for the newly added last point.
    2075        1486 :     const sal_uInt16 nPolySize(aPoly.GetSize());
    2076        1486 :     if(nPolySize)
    2077             :     {
    2078        3891 :         if((aPoly.HasFlags() && POLY_CONTROL == aPoly.GetFlags(nPolySize - 1))
    2079        2292 :             || (aPoly.GetPoint(nPolySize - 1) != aPoly.GetPoint(0)))
    2080             :         {
    2081        1486 :             aPoly.SetSize(nPolySize + 1);
    2082        1486 :             aPoly.SetPoint(aPoly.GetPoint(0), nPolySize);
    2083             : 
    2084        1486 :             if(aPoly.HasFlags())
    2085             :             {
    2086         919 :                 aPoly.SetFlags(nPolySize, POLY_NORMAL);
    2087             :             }
    2088             :         }
    2089             :     }
    2090             : 
    2091        1486 :     mrPolyPoly.Insert( aPoly );
    2092        1486 :     mnPoints = 0;
    2093        1486 :     bHasOffline = false;
    2094             : }
    2095             : 
    2096             : // -----------------------------------------------------------------------
    2097             : 
    2098             : extern "C" {
    2099             : 
    2100             : // TODO: wait till all compilers accept that calling conventions
    2101             : // for functions are the same independent of implementation constness,
    2102             : // then uncomment the const-tokens in the function interfaces below
    2103        1486 : static int FT_move_to( FT_Vector_CPtr p0, void* vpPolyArgs )
    2104             : {
    2105        1486 :     PolyArgs& rA = *reinterpret_cast<PolyArgs*>(vpPolyArgs);
    2106             : 
    2107             :     // move_to implies a new polygon => finish old polygon first
    2108        1486 :     rA.ClosePolygon();
    2109             : 
    2110        1486 :     rA.AddPoint( p0->x, p0->y, POLY_NORMAL );
    2111        1486 :     return 0;
    2112             : }
    2113             : 
    2114        6589 : static int FT_line_to( FT_Vector_CPtr p1, void* vpPolyArgs )
    2115             : {
    2116        6589 :     PolyArgs& rA = *reinterpret_cast<PolyArgs*>(vpPolyArgs);
    2117        6589 :     rA.AddPoint( p1->x, p1->y, POLY_NORMAL );
    2118        6589 :     return 0;
    2119             : }
    2120             : 
    2121        8954 : static int FT_conic_to( FT_Vector_CPtr p1, FT_Vector_CPtr p2, void* vpPolyArgs )
    2122             : {
    2123        8954 :     PolyArgs& rA = *reinterpret_cast<PolyArgs*>(vpPolyArgs);
    2124             : 
    2125             :     // VCL's Polygon only knows cubic beziers
    2126        8954 :     const long nX1 = (2 * rA.GetPosX() + 4 * p1->x + 3) / 6;
    2127        8954 :     const long nY1 = (2 * rA.GetPosY() + 4 * p1->y + 3) / 6;
    2128        8954 :     rA.AddPoint( nX1, nY1, POLY_CONTROL );
    2129             : 
    2130        8954 :     const long nX2 = (2 * p2->x + 4 * p1->x + 3) / 6;
    2131        8954 :     const long nY2 = (2 * p2->y + 4 * p1->y + 3) / 6;
    2132        8954 :     rA.AddPoint( nX2, nY2, POLY_CONTROL );
    2133             : 
    2134        8954 :     rA.AddPoint( p2->x, p2->y, POLY_NORMAL );
    2135        8954 :     return 0;
    2136             : }
    2137             : 
    2138           0 : static int FT_cubic_to( FT_Vector_CPtr p1, FT_Vector_CPtr p2, FT_Vector_CPtr p3, void* vpPolyArgs )
    2139             : {
    2140           0 :     PolyArgs& rA = *reinterpret_cast<PolyArgs*>(vpPolyArgs);
    2141           0 :     rA.AddPoint( p1->x, p1->y, POLY_CONTROL );
    2142           0 :     rA.AddPoint( p2->x, p2->y, POLY_CONTROL );
    2143           0 :     rA.AddPoint( p3->x, p3->y, POLY_NORMAL );
    2144           0 :     return 0;
    2145             : }
    2146             : 
    2147             : } // extern "C"
    2148             : 
    2149             : // -----------------------------------------------------------------------
    2150             : 
    2151         954 : bool ServerFont::GetGlyphOutline( int nGlyphIndex,
    2152             :     ::basegfx::B2DPolyPolygon& rB2DPolyPoly ) const
    2153             : {
    2154         954 :     if( maSizeFT )
    2155         954 :         pFTActivateSize( maSizeFT );
    2156             : 
    2157         954 :     rB2DPolyPoly.clear();
    2158             : 
    2159             :     int nGlyphFlags;
    2160         954 :     SplitGlyphFlags( *this, nGlyphIndex, nGlyphFlags );
    2161             : 
    2162         954 :     FT_Int nLoadFlags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_TRANSFORM;
    2163             : 
    2164             : #ifdef FT_LOAD_TARGET_LIGHT
    2165             :     // enable "light hinting" if available
    2166         954 :     nLoadFlags |= FT_LOAD_TARGET_LIGHT;
    2167             : #endif
    2168             : 
    2169         954 :     FT_Error rc = FT_Load_Glyph( maFaceFT, nGlyphIndex, nLoadFlags );
    2170         954 :     if( rc != FT_Err_Ok )
    2171           2 :         return false;
    2172             : 
    2173         952 :     if( mbArtBold && pFTEmbolden )
    2174           0 :         (*pFTEmbolden)( maFaceFT->glyph );
    2175             : 
    2176             :     FT_Glyph pGlyphFT;
    2177         952 :     rc = FT_Get_Glyph( maFaceFT->glyph, &pGlyphFT );
    2178         952 :     if( rc != FT_Err_Ok )
    2179           0 :         return false;
    2180             : 
    2181         952 :     if( pGlyphFT->format != FT_GLYPH_FORMAT_OUTLINE )
    2182             :     {
    2183           0 :         FT_Done_Glyph( pGlyphFT );
    2184           0 :         return false;
    2185             :     }
    2186             : 
    2187         952 :     if( mbArtItalic )
    2188             :     {
    2189             :         FT_Matrix aMatrix;
    2190           0 :         aMatrix.xx = aMatrix.yy = 0x10000L;
    2191           0 :         aMatrix.xy = 0x6000L, aMatrix.yx = 0;
    2192           0 :         FT_Glyph_Transform( pGlyphFT, &aMatrix, NULL );
    2193             :     }
    2194             : 
    2195         952 :     FT_Outline& rOutline = reinterpret_cast<FT_OutlineGlyphRec*>(pGlyphFT)->outline;
    2196         952 :     if( !rOutline.n_points )    // blank glyphs are ok
    2197             :     {
    2198          17 :         FT_Done_Glyph( pGlyphFT );
    2199          17 :         return true;
    2200             :     }
    2201             : 
    2202         935 :     long nMaxPoints = 1 + rOutline.n_points * 3;
    2203         935 :     PolyPolygon aToolPolyPolygon;
    2204        1870 :     PolyArgs aPolyArg( aToolPolyPolygon, nMaxPoints );
    2205             : 
    2206         935 :     /*int nAngle =*/ ApplyGlyphTransform( nGlyphFlags, pGlyphFT, false );
    2207             : 
    2208             :     FT_Outline_Funcs aFuncs;
    2209         935 :     aFuncs.move_to  = &FT_move_to;
    2210         935 :     aFuncs.line_to  = &FT_line_to;
    2211         935 :     aFuncs.conic_to = &FT_conic_to;
    2212         935 :     aFuncs.cubic_to = &FT_cubic_to;
    2213         935 :     aFuncs.shift    = 0;
    2214         935 :     aFuncs.delta    = 0;
    2215         935 :     rc = FT_Outline_Decompose( &rOutline, &aFuncs, (void*)&aPolyArg );
    2216         935 :     aPolyArg.ClosePolygon();    // close last polygon
    2217         935 :     FT_Done_Glyph( pGlyphFT );
    2218             : 
    2219             :     // convert to basegfx polypolygon
    2220             :     // TODO: get rid of the intermediate tools polypolygon
    2221         935 :     rB2DPolyPoly = aToolPolyPolygon.getB2DPolyPolygon();
    2222         935 :     rB2DPolyPoly.transform(basegfx::tools::createScaleB2DHomMatrix( +1.0/(1<<6), -1.0/(1<<6) ));
    2223             : 
    2224        1870 :     return true;
    2225             : }
    2226             : 
    2227             : // -----------------------------------------------------------------------
    2228             : 
    2229        2350 : bool ServerFont::ApplyGSUB( const FontSelectPattern& rFSD )
    2230             : {
    2231             : #define MKTAG(s) ((((((s[0]<<8)+s[1])<<8)+s[2])<<8)+s[3])
    2232             : 
    2233             :     typedef std::vector<sal_uLong> ReqFeatureTagList;
    2234        2350 :     ReqFeatureTagList aReqFeatureTagList;
    2235        2350 :     if( rFSD.mbVertical )
    2236           1 :         aReqFeatureTagList.push_back( MKTAG("vert") );
    2237        2350 :     sal_uLong nRequestedScript = 0;     //MKTAG("hani");//### TODO: where to get script?
    2238        2350 :     sal_uLong nRequestedLangsys = 0;    //MKTAG("ZHT"); //### TODO: where to get langsys?
    2239             :     // TODO: request more features depending on script and language system
    2240             : 
    2241        2350 :     if( aReqFeatureTagList.empty()) // nothing to do
    2242        2349 :         return true;
    2243             : 
    2244             :     // load GSUB table into memory
    2245           1 :     sal_uLong nLength = 0;
    2246           1 :     const FT_Byte* const pGsubBase = mpFontInfo->GetTable( "GSUB", &nLength );
    2247           1 :     if( !pGsubBase )
    2248           0 :         return false;
    2249             : 
    2250             :     // parse GSUB header
    2251           1 :     const FT_Byte* pGsubHeader = pGsubBase;
    2252           1 :     const sal_uInt16 nOfsScriptList     = GetUShort( pGsubHeader+4 );
    2253           1 :     const sal_uInt16 nOfsFeatureTable   = GetUShort( pGsubHeader+6 );
    2254           1 :     const sal_uInt16 nOfsLookupList     = GetUShort( pGsubHeader+8 );
    2255           1 :     pGsubHeader += 10;
    2256             : 
    2257             :     typedef std::vector<sal_uInt16> UshortList;
    2258           2 :     UshortList aFeatureIndexList;
    2259             : 
    2260             :     // parse Script Table
    2261           1 :     const FT_Byte* pScriptHeader = pGsubBase + nOfsScriptList;
    2262           1 :     const sal_uInt16 nCntScript = GetUShort( pScriptHeader+0 );
    2263           1 :     pScriptHeader += 2;
    2264           5 :     for( sal_uInt16 nScriptIndex = 0; nScriptIndex < nCntScript; ++nScriptIndex )
    2265             :     {
    2266           4 :         const sal_uLong nScriptTag      = GetUInt( pScriptHeader+0 ); // e.g. hani/arab/kana/hang
    2267           4 :         const sal_uInt16 nOfsScriptTable= GetUShort( pScriptHeader+4 );
    2268           4 :         pScriptHeader += 6; //###
    2269           4 :         if( (nScriptTag != nRequestedScript) && (nRequestedScript != 0) )
    2270           0 :             continue;
    2271             : 
    2272           4 :         const FT_Byte* pScriptTable     = pGsubBase + nOfsScriptList + nOfsScriptTable;
    2273           4 :         const sal_uInt16 nDefaultLangsysOfs = GetUShort( pScriptTable+0 );
    2274           4 :         const sal_uInt16 nCntLangSystem     = GetUShort( pScriptTable+2 );
    2275           4 :         pScriptTable += 4;
    2276           4 :         sal_uInt16 nLangsysOffset = 0;
    2277             : 
    2278           4 :         for( sal_uInt16 nLangsysIndex = 0; nLangsysIndex < nCntLangSystem; ++nLangsysIndex )
    2279             :         {
    2280           1 :             const sal_uLong nTag    = GetUInt( pScriptTable+0 );    // e.g. KOR/ZHS/ZHT/JAN
    2281           1 :             const sal_uInt16 nOffset= GetUShort( pScriptTable+4 );
    2282           1 :             pScriptTable += 6;
    2283           1 :             if( (nTag != nRequestedLangsys) && (nRequestedLangsys != 0) )
    2284           0 :                 continue;
    2285           1 :             nLangsysOffset = nOffset;
    2286           1 :             break;
    2287             :         }
    2288             : 
    2289           4 :         if( (nDefaultLangsysOfs != 0) && (nDefaultLangsysOfs != nLangsysOffset) )
    2290             :         {
    2291           3 :             const FT_Byte* pLangSys = pGsubBase + nOfsScriptList + nOfsScriptTable + nDefaultLangsysOfs;
    2292           3 :             const sal_uInt16 nReqFeatureIdx = GetUShort( pLangSys+2 );
    2293           3 :             const sal_uInt16 nCntFeature    = GetUShort( pLangSys+4 );
    2294           3 :             pLangSys += 6;
    2295           3 :             aFeatureIndexList.push_back( nReqFeatureIdx );
    2296           3 :             for( sal_uInt16 i = 0; i < nCntFeature; ++i )
    2297             :             {
    2298           0 :                 const sal_uInt16 nFeatureIndex = GetUShort( pLangSys );
    2299           0 :                 pLangSys += 2;
    2300           0 :                 aFeatureIndexList.push_back( nFeatureIndex );
    2301             :             }
    2302             :         }
    2303             : 
    2304           4 :         if( nLangsysOffset != 0 )
    2305             :         {
    2306           1 :             const FT_Byte* pLangSys = pGsubBase + nOfsScriptList + nOfsScriptTable + nLangsysOffset;
    2307           1 :             const sal_uInt16 nReqFeatureIdx = GetUShort( pLangSys+2 );
    2308           1 :             const sal_uInt16 nCntFeature    = GetUShort( pLangSys+4 );
    2309           1 :             pLangSys += 6;
    2310           1 :             aFeatureIndexList.push_back( nReqFeatureIdx );
    2311           2 :             for( sal_uInt16 i = 0; i < nCntFeature; ++i )
    2312             :             {
    2313           1 :                 const sal_uInt16 nFeatureIndex = GetUShort( pLangSys );
    2314           1 :                 pLangSys += 2;
    2315           1 :                 aFeatureIndexList.push_back( nFeatureIndex );
    2316             :             }
    2317             :         }
    2318             :     }
    2319             : 
    2320           1 :     if( aFeatureIndexList.empty() )
    2321           0 :         return true;
    2322             : 
    2323           2 :     UshortList aLookupIndexList;
    2324           2 :     UshortList aLookupOffsetList;
    2325             : 
    2326             :     // parse Feature Table
    2327           1 :     const FT_Byte* pFeatureHeader = pGsubBase + nOfsFeatureTable;
    2328           1 :     const sal_uInt16 nCntFeature = GetUShort( pFeatureHeader );
    2329           1 :     pFeatureHeader += 2;
    2330           2 :     for( sal_uInt16 nFeatureIndex = 0; nFeatureIndex < nCntFeature; ++nFeatureIndex )
    2331             :     {
    2332           1 :         const sal_uLong nTag    = GetUInt( pFeatureHeader+0 ); // e.g. locl/vert/trad/smpl/liga/fina/...
    2333           1 :         const sal_uInt16 nOffset= GetUShort( pFeatureHeader+4 );
    2334           1 :         pFeatureHeader += 6;
    2335             : 
    2336             :         // short circuit some feature lookups
    2337           1 :         if( aFeatureIndexList[0] != nFeatureIndex ) // required feature?
    2338             :         {
    2339           1 :             const int nRequested = std::count( aFeatureIndexList.begin(), aFeatureIndexList.end(), nFeatureIndex);
    2340           1 :             if( !nRequested )  // ignore features that are not requested
    2341           1 :                 continue;
    2342           1 :             const int nAvailable = std::count( aReqFeatureTagList.begin(), aReqFeatureTagList.end(), nTag);
    2343           1 :             if( !nAvailable )  // some fonts don't provide features they request!
    2344           1 :                 continue;
    2345             :         }
    2346             : 
    2347           0 :         const FT_Byte* pFeatureTable = pGsubBase + nOfsFeatureTable + nOffset;
    2348           0 :         const sal_uInt16 nCntLookups = GetUShort( pFeatureTable+0 );
    2349           0 :         pFeatureTable += 2;
    2350           0 :         for( sal_uInt16 i = 0; i < nCntLookups; ++i )
    2351             :         {
    2352           0 :             const sal_uInt16 nLookupIndex = GetUShort( pFeatureTable );
    2353           0 :             pFeatureTable += 2;
    2354           0 :             aLookupIndexList.push_back( nLookupIndex );
    2355             :         }
    2356           0 :         if( nCntLookups == 0 ) //### hack needed by Mincho/Gothic/Mingliu/Simsun/...
    2357           0 :             aLookupIndexList.push_back( 0 );
    2358             :     }
    2359             : 
    2360             :     // parse Lookup List
    2361           1 :     const FT_Byte* pLookupHeader = pGsubBase + nOfsLookupList;
    2362           1 :     const sal_uInt16 nCntLookupTable = GetUShort( pLookupHeader );
    2363           1 :     pLookupHeader += 2;
    2364           2 :     for( sal_uInt16 nLookupIdx = 0; nLookupIdx < nCntLookupTable; ++nLookupIdx )
    2365             :     {
    2366           1 :         const sal_uInt16 nOffset = GetUShort( pLookupHeader );
    2367           1 :         pLookupHeader += 2;
    2368           1 :         if( std::count( aLookupIndexList.begin(), aLookupIndexList.end(), nLookupIdx ) )
    2369           0 :             aLookupOffsetList.push_back( nOffset );
    2370             :     }
    2371             : 
    2372           1 :     UshortList::const_iterator lookup_it = aLookupOffsetList.begin();
    2373           1 :     for(; lookup_it != aLookupOffsetList.end(); ++lookup_it )
    2374             :     {
    2375           0 :         const sal_uInt16 nOfsLookupTable = *lookup_it;
    2376           0 :         const FT_Byte* pLookupTable = pGsubBase + nOfsLookupList + nOfsLookupTable;
    2377           0 :         const sal_uInt16 eLookupType        = GetUShort( pLookupTable+0 );
    2378           0 :         const sal_uInt16 nCntLookupSubtable = GetUShort( pLookupTable+4 );
    2379           0 :         pLookupTable += 6;
    2380             : 
    2381             :         // TODO: switch( eLookupType )
    2382           0 :         if( eLookupType != 1 )  // TODO: once we go beyond SingleSubst
    2383           0 :             continue;
    2384             : 
    2385           0 :         for( sal_uInt16 nSubTableIdx = 0; nSubTableIdx < nCntLookupSubtable; ++nSubTableIdx )
    2386             :         {
    2387           0 :             const sal_uInt16 nOfsSubLookupTable = GetUShort( pLookupTable );
    2388           0 :             pLookupTable += 2;
    2389           0 :             const FT_Byte* pSubLookup = pGsubBase + nOfsLookupList + nOfsLookupTable + nOfsSubLookupTable;
    2390             : 
    2391           0 :             const sal_uInt16 nFmtSubstitution   = GetUShort( pSubLookup+0 );
    2392           0 :             const sal_uInt16 nOfsCoverage       = GetUShort( pSubLookup+2 );
    2393           0 :             pSubLookup += 4;
    2394             : 
    2395             :             typedef std::pair<sal_uInt16,sal_uInt16> GlyphSubst;
    2396             :             typedef std::vector<GlyphSubst> SubstVector;
    2397           0 :             SubstVector aSubstVector;
    2398             : 
    2399           0 :             const FT_Byte* pCoverage    = pGsubBase + nOfsLookupList + nOfsLookupTable + nOfsSubLookupTable + nOfsCoverage;
    2400           0 :             const sal_uInt16 nFmtCoverage   = GetUShort( pCoverage+0 );
    2401           0 :             pCoverage += 2;
    2402           0 :             switch( nFmtCoverage )
    2403             :             {
    2404             :                 case 1:         // Coverage Format 1
    2405             :                     {
    2406           0 :                         const sal_uInt16 nCntGlyph = GetUShort( pCoverage );
    2407           0 :                         pCoverage += 2;
    2408           0 :                         aSubstVector.reserve( nCntGlyph );
    2409           0 :                         for( sal_uInt16 i = 0; i < nCntGlyph; ++i )
    2410             :                         {
    2411           0 :                             const sal_uInt16 nGlyphId = GetUShort( pCoverage );
    2412           0 :                             pCoverage += 2;
    2413           0 :                             aSubstVector.push_back( GlyphSubst( nGlyphId, 0 ) );
    2414             :                         }
    2415             :                     }
    2416           0 :                     break;
    2417             : 
    2418             :                 case 2:         // Coverage Format 2
    2419             :                     {
    2420           0 :                         const sal_uInt16 nCntRange = GetUShort( pCoverage );
    2421           0 :                         pCoverage += 2;
    2422           0 :                         for( int i = nCntRange; --i >= 0; )
    2423             :                         {
    2424           0 :                             const sal_uInt32 nGlyph0 = GetUShort( pCoverage+0 );
    2425           0 :                             const sal_uInt32 nGlyph1 = GetUShort( pCoverage+2 );
    2426           0 :                             const sal_uInt16 nCovIdx = GetUShort( pCoverage+4 );
    2427           0 :                             pCoverage += 6;
    2428           0 :                             for( sal_uInt32 j = nGlyph0; j <= nGlyph1; ++j )
    2429           0 :                                 aSubstVector.push_back( GlyphSubst( static_cast<sal_uInt16>(j + nCovIdx), 0 ) );
    2430             :                         }
    2431             :                     }
    2432           0 :                     break;
    2433             :             }
    2434             : 
    2435           0 :             SubstVector::iterator it( aSubstVector.begin() );
    2436             : 
    2437           0 :             switch( nFmtSubstitution )
    2438             :             {
    2439             :                 case 1:     // Single Substitution Format 1
    2440             :                     {
    2441           0 :                         const sal_uInt16 nDeltaGlyphId = GetUShort( pSubLookup );
    2442           0 :                         pSubLookup += 2;
    2443           0 :                         for(; it != aSubstVector.end(); ++it )
    2444           0 :                             (*it).second = (*it).first + nDeltaGlyphId;
    2445             :                     }
    2446           0 :                     break;
    2447             : 
    2448             :                 case 2:     // Single Substitution Format 2
    2449             :                     {
    2450           0 :                         const sal_uInt16 nCntGlyph = GetUShort( pSubLookup );
    2451           0 :                         pSubLookup += 2;
    2452           0 :                         for( int i = nCntGlyph; (it != aSubstVector.end()) && (--i>=0); ++it )
    2453             :                         {
    2454           0 :                             const sal_uInt16 nGlyphId = GetUShort( pSubLookup );
    2455           0 :                             pSubLookup += 2;
    2456           0 :                             (*it).second = nGlyphId;
    2457             :                         }
    2458             :                     }
    2459           0 :                     break;
    2460             :             }
    2461             : 
    2462             :             DBG_ASSERT( (it == aSubstVector.end()), "lookup<->coverage table mismatch" );
    2463             :             // now apply the glyph substitutions that have been collected in this subtable
    2464           0 :             for( it = aSubstVector.begin(); it != aSubstVector.end(); ++it )
    2465           0 :                 maGlyphSubstitution[ (*it).first ] =  (*it).second;
    2466           0 :         }
    2467             :     }
    2468             : 
    2469        2351 :     return true;
    2470             : }
    2471             : 
    2472        6864 : const unsigned char* ServerFont::GetTable(const char* pName, sal_uLong* pLength)
    2473             : {
    2474        6864 :     return mpFontInfo->GetTable( pName, pLength );
    2475             : }
    2476             : 
    2477             : #if ENABLE_GRAPHITE
    2478        1051 : GraphiteFaceWrapper* ServerFont::GetGraphiteFace() const
    2479             : {
    2480        1051 :     return mpFontInfo->GetGraphiteFace();
    2481         465 : }
    2482             : #endif
    2483             : 
    2484             : // =======================================================================
    2485             : 
    2486             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10