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