LCOV - code coverage report
Current view: top level - libreoffice/vcl/generic/glyphs - gcach_ftyp.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 608 1188 51.2 %
Date: 2012-12-17 Functions: 52 70 74.3 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10