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