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