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