xref: /aoo42x/main/vcl/source/glyphs/gcach_ftyp.cxx (revision d9933d30)
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;
NEXT_U16(CPU8 & p)92 inline sal_uInt16 NEXT_U16( CPU8& p ) { p+=2; return (p[-2]<<8)|p[-1]; }
NEXT_S16(CPU8 & p)93 inline sal_Int16  NEXT_S16( CPU8& p ) { return (sal_Int16)NEXT_U16(p); }
NEXT_U32(CPU8 & 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 
InitGammaTable()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 
FtFontFile(const::rtl::OString & rNativeFileName)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 
FindFontFile(const::rtl::OString & rNativeFileName)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 
Map()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 
Unmap()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 
FtFontInfo(const ImplDevFontAttributes & rDevFontAttributes,const::rtl::OString & rNativeFileName,int nFaceNum,sal_IntPtr nFontId,int nSynthetic,const ExtraKernInfo * pExtraKernInfo)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 
~FtFontInfo()316 FtFontInfo::~FtFontInfo()
317 {
318     if( mpFontCharMap )
319         mpFontCharMap->DeReference();
320     delete mpExtraKernInfo;
321     delete mpChar2Glyph;
322     delete mpGlyph2Char;
323 }
324 
InitHashes() const325 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 
GetFaceFT()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 
ReleaseFaceFT(FT_FaceRec_ * pFaceFT)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 
HasExtraKerning() const366 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 
GetExtraKernPairs(ImplKernPairData ** ppKernPairs) const378 int FtFontInfo::GetExtraKernPairs( ImplKernPairData** ppKernPairs ) const
379 {
380     if( !mpExtraKernInfo )
381         return 0;
382     return mpExtraKernInfo->GetUnscaledKernPairs( ppKernPairs );
383 }
384 
385 // -----------------------------------------------------------------------
386 
GetExtraGlyphKernValue(int nLeftGlyph,int nRightGlyph) const387 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 
GetUInt(const unsigned char * p)400 static unsigned GetUInt( const unsigned char* p ) { return((p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3]);}
GetUShort(const unsigned char * p)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 
GetTable(const char * pTag,sal_uLong * pLength) const406 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 
AnnounceFont(ImplDevFontList * pFontList)443 void FtFontInfo::AnnounceFont( ImplDevFontList* pFontList )
444 {
445     ImplFTSFontData* pFD = new ImplFTSFontData( this, maDevFontAttributes );
446     pFontList->Add( pFD );
447 }
448 
449 // =======================================================================
450 
FreetypeManager()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 
GetFtFace() const510 void* FreetypeServerFont::GetFtFace() const
511 {
512     if( maSizeFT )
513         pFTActivateSize( maSizeFT );
514 
515     return maFaceFT;
516 }
517 
518 // -----------------------------------------------------------------------
519 
~FreetypeManager()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 
AddFontFile(const rtl::OString & rNormalizedName,int nFaceNum,sal_IntPtr nFontId,const ImplDevFontAttributes & rDevFontAttr,const ExtraKernInfo * pExtraKernInfo)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 
AddFontDir(const String & rUrlName)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 
AnnounceFonts(ImplDevFontList * pToAdd) const646 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 
ClearFontList()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 
CreateFont(const ImplFontSelectData & rFSD)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 
ImplFTSFontData(FtFontInfo * pFI,const ImplDevFontAttributes & rDFA)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 
CreateFontInstance(ImplFontSelectData & rFSD) const699 ImplFontEntry* ImplFTSFontData::CreateFontInstance( ImplFontSelectData& rFSD ) const
700 {
701     ImplServerFontEntry* pEntry = new ImplServerFontEntry( rFSD );
702     return pEntry;
703 }
704 
705 // =======================================================================
706 // FreetypeServerFont
707 // =======================================================================
708 
FreetypeServerFont(const ImplFontSelectData & rFSD,FtFontInfo * pFI)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, vt=%d, sy=%d) => %d\n",
725         pFI->GetFontFileName()->getStr(), rFSD.mnHeight, rFSD.mnWidth, rFSD.mbVertical, 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 
SetFontOptions(const ImplFontOptions & rFontOptions)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 
TestFont() const919 bool FreetypeServerFont::TestFont() const
920 {
921     return mbFaceOk;
922 }
923 
924 // -----------------------------------------------------------------------
925 
~FreetypeServerFont()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 
GetEmUnits() const942 int FreetypeServerFont::GetEmUnits() const
943 {
944     return maFaceFT->units_per_EM;
945 }
946 
947 // -----------------------------------------------------------------------
948 
FetchFontMetric(ImplFontMetricData & rTo,long & rFactor) const949 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 
SplitGlyphFlags(const FreetypeServerFont & rFont,sal_GlyphId & rGlyphId,int & nGlyphFlags)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 
ApplyGlyphTransform(int nGlyphFlags,FT_Glyph pGlyphFT,bool bForBitmapProcessing) const1094 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 
GetRawGlyphIndex(sal_UCS4 aChar) const1177 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 
FixupGlyphIndex(sal_GlyphId aGlyphId,sal_UCS4 aChar) const1240 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 
GetGlyphIndex(sal_UCS4 aChar) const1288 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 
lcl_GetCharWidth(FT_FaceRec_ * pFaceFT,double fStretch,int nGlyphFlags)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 
InitGlyphData(sal_GlyphId aGlyphId,GlyphData & rGD) const1316 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     if( rc != FT_Err_Ok )
1365     {
1366         // we get here e.g. when a PS font lacks the default glyph
1367         rGD.SetCharWidth( 0 );
1368         rGD.SetDelta( 0, 0 );
1369         rGD.SetOffset( 0, 0 );
1370         rGD.SetSize( Size( 0, 0 ) );
1371         return;
1372     }
1373 
1374     ApplyGlyphTransform( nGlyphFlags, pGlyphFT, false );
1375     if( mbArtBold && pFTEmbolden && (nFTVERSION < 2200) ) // #i71094# workaround staircase bug
1376         pGlyphFT->advance.y = 0;
1377     rGD.SetDelta( (pGlyphFT->advance.x + 0x8000) >> 16, -((pGlyphFT->advance.y + 0x8000) >> 16) );
1378 
1379     FT_BBox aBbox;
1380     FT_Glyph_Get_CBox( pGlyphFT, FT_GLYPH_BBOX_PIXELS, &aBbox );
1381     if( aBbox.yMin > aBbox.yMax )   // circumvent freetype bug
1382     {
1383         int t=aBbox.yMin; aBbox.yMin=aBbox.yMax, aBbox.yMax=t;
1384     }
1385 
1386     rGD.SetOffset( aBbox.xMin, -aBbox.yMax );
1387     rGD.SetSize( Size( (aBbox.xMax-aBbox.xMin+1), (aBbox.yMax-aBbox.yMin) ) );
1388 
1389     FT_Done_Glyph( pGlyphFT );
1390 }
1391 
1392 // -----------------------------------------------------------------------
1393 
GetAntialiasAdvice(void) const1394 bool FreetypeServerFont::GetAntialiasAdvice( void ) const
1395 {
1396     if( GetFontSelData().mbNonAntialiased || (mnPrioAntiAlias<=0) )
1397         return false;
1398     bool bAdviseAA = true;
1399     // TODO: also use GASP info
1400     return bAdviseAA;
1401 }
1402 
1403 // -----------------------------------------------------------------------
1404 
GetGlyphBitmap1(sal_GlyphId aGlyphId,RawBitmap & rRawBitmap) const1405 bool FreetypeServerFont::GetGlyphBitmap1( sal_GlyphId aGlyphId, RawBitmap& rRawBitmap ) const
1406 {
1407     if( maSizeFT )
1408         pFTActivateSize( maSizeFT );
1409 
1410     int nGlyphFlags;
1411     SplitGlyphFlags( *this, aGlyphId, nGlyphFlags );
1412 
1413     FT_Int nLoadFlags = mnLoadFlags;
1414     // #i70930# force mono-hinting for monochrome text
1415     if( nFTVERSION >= 2110 ) //#i71947# unless it looks worse
1416     {
1417         nLoadFlags &= ~0xF0000;
1418         nLoadFlags |= FT_LOAD_TARGET_MONO;
1419     }
1420 
1421     if( mbArtItalic )
1422         nLoadFlags |= FT_LOAD_NO_BITMAP;
1423 
1424 #if (FTVERSION >= 2002)
1425     // for 0/90/180/270 degree fonts enable hinting even if not advisable
1426     // non-hinted and non-antialiased bitmaps just look too ugly
1427     if( (mnCos==0 || mnSin==0) && (mnPrioAutoHint > 0) )
1428         nLoadFlags &= ~FT_LOAD_NO_HINTING;
1429 #endif
1430 
1431     if( mnPrioEmbedded <= mnPrioAutoHint )
1432         nLoadFlags |= FT_LOAD_NO_BITMAP;
1433 
1434     FT_Error rc = -1;
1435 #if (FTVERSION <= 2008)
1436     // #88364# freetype<=2005 prefers autohinting to embedded bitmaps
1437     // => first we have to try without hinting
1438     if( (nLoadFlags & (FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP)) == 0 )
1439     {
1440         rc = FT_Load_Glyph( maFaceFT, aGlyphId, nLoadFlags|FT_LOAD_NO_HINTING );
1441         if( (rc==FT_Err_Ok) && (maFaceFT->glyph->format != FT_GLYPH_FORMAT_BITMAP) )
1442             rc = -1; // mark as "loading embedded bitmap" was unsuccessful
1443         nLoadFlags |= FT_LOAD_NO_BITMAP;
1444     }
1445 
1446     if( rc != FT_Err_Ok )
1447 #endif
1448         rc = FT_Load_Glyph( maFaceFT, aGlyphId, nLoadFlags );
1449     if( rc != FT_Err_Ok )
1450         return false;
1451 
1452     if( mbArtBold && pFTEmbolden )
1453         (*pFTEmbolden)( maFaceFT->glyph );
1454 
1455     FT_Glyph pGlyphFT;
1456     rc = FT_Get_Glyph( maFaceFT->glyph, &pGlyphFT );
1457     if( rc != FT_Err_Ok )
1458         return false;
1459 
1460     int nAngle = ApplyGlyphTransform( nGlyphFlags, pGlyphFT, true );
1461 
1462     if( mbArtItalic )
1463     {
1464         FT_Matrix aMatrix;
1465         aMatrix.xx = aMatrix.yy = 0x10000L;
1466         if( nFTVERSION >= 2102 )    // Freetype 2.1.2 API swapped xy with yx
1467             aMatrix.xy = 0x6000L, aMatrix.yx = 0;
1468         else
1469             aMatrix.yx = 0x6000L, aMatrix.xy = 0;
1470         FT_Glyph_Transform( pGlyphFT, &aMatrix, NULL );
1471     }
1472 
1473     // Check for zero area bounding boxes as this crashes some versions of FT.
1474     // This also provides a handy short cut as much of the code following
1475     //  becomes an expensive nop when a glyph covers no pixels.
1476     FT_BBox cbox;
1477     FT_Glyph_Get_CBox(pGlyphFT, ft_glyph_bbox_unscaled, &cbox);
1478 
1479     if( (cbox.xMax - cbox.xMin) == 0 || (cbox.yMax - cbox.yMin == 0) )
1480     {
1481         nAngle = 0;
1482         memset(&rRawBitmap, 0, sizeof rRawBitmap);
1483         FT_Done_Glyph( pGlyphFT );
1484         return true;
1485     }
1486 
1487     if( pGlyphFT->format != FT_GLYPH_FORMAT_BITMAP )
1488     {
1489         if( pGlyphFT->format == FT_GLYPH_FORMAT_OUTLINE )
1490             ((FT_OutlineGlyphRec*)pGlyphFT)->outline.flags |= FT_OUTLINE_HIGH_PRECISION;
1491         // #i15743# freetype API 2.1.3 changed the FT_RENDER_MODE_MONO constant
1492         FT_Render_Mode nRenderMode = (FT_Render_Mode)((nFTVERSION<2103) ? 1 : FT_RENDER_MODE_MONO);
1493 
1494         rc = FT_Glyph_To_Bitmap( &pGlyphFT, nRenderMode, NULL, sal_True );
1495         if( rc != FT_Err_Ok )
1496         {
1497             FT_Done_Glyph( pGlyphFT );
1498             return false;
1499         }
1500     }
1501 
1502     const FT_BitmapGlyph pBmpGlyphFT = reinterpret_cast<const FT_BitmapGlyph>(pGlyphFT);
1503     // NOTE: autohinting in FT<=2.0.2 miscalculates the offsets below by +-1
1504     rRawBitmap.mnXOffset        = +pBmpGlyphFT->left;
1505     rRawBitmap.mnYOffset        = -pBmpGlyphFT->top;
1506 
1507     const FT_Bitmap& rBitmapFT  = pBmpGlyphFT->bitmap;
1508     rRawBitmap.mnHeight         = rBitmapFT.rows;
1509     rRawBitmap.mnBitCount       = 1;
1510     if( mbArtBold && !pFTEmbolden )
1511     {
1512         rRawBitmap.mnWidth = rBitmapFT.width + 1;
1513         int nLineBytes = (rRawBitmap.mnWidth + 7) >> 3;
1514         rRawBitmap.mnScanlineSize  = (nLineBytes > rBitmapFT.pitch) ? nLineBytes : rBitmapFT.pitch;
1515     }
1516     else
1517     {
1518         rRawBitmap.mnWidth          = rBitmapFT.width;
1519         rRawBitmap.mnScanlineSize   = rBitmapFT.pitch;
1520     }
1521 
1522     const sal_uLong nNeededSize = rRawBitmap.mnScanlineSize * rRawBitmap.mnHeight;
1523 
1524     if( rRawBitmap.mnAllocated < nNeededSize )
1525     {
1526         delete[] rRawBitmap.mpBits;
1527         rRawBitmap.mnAllocated = 2*nNeededSize;
1528         rRawBitmap.mpBits = new unsigned char[ rRawBitmap.mnAllocated ];
1529     }
1530 
1531     if( !mbArtBold || pFTEmbolden )
1532     {
1533         memcpy( rRawBitmap.mpBits, rBitmapFT.buffer, nNeededSize );
1534     }
1535     else
1536     {
1537         memset( rRawBitmap.mpBits, 0, nNeededSize );
1538         const unsigned char* pSrcLine = rBitmapFT.buffer;
1539         unsigned char* pDstLine = rRawBitmap.mpBits;
1540         for( int h = rRawBitmap.mnHeight; --h >= 0; )
1541         {
1542             memcpy( pDstLine, pSrcLine, rBitmapFT.pitch );
1543             pDstLine += rRawBitmap.mnScanlineSize;
1544             pSrcLine += rBitmapFT.pitch;
1545         }
1546 
1547         unsigned char* p = rRawBitmap.mpBits;
1548         for( sal_uLong y=0; y < rRawBitmap.mnHeight; y++ )
1549         {
1550             unsigned char nLastByte = 0;
1551             for( sal_uLong x=0; x < rRawBitmap.mnScanlineSize; x++ )
1552             {
1553             unsigned char nTmp = p[x] << 7;
1554             p[x] |= (p[x] >> 1) | nLastByte;
1555             nLastByte = nTmp;
1556             }
1557             p += rRawBitmap.mnScanlineSize;
1558         }
1559     }
1560 
1561     FT_Done_Glyph( pGlyphFT );
1562 
1563     // special case for 0/90/180/270 degree orientation
1564     switch( nAngle )
1565     {
1566         case  -900:
1567         case  +900:
1568         case +1800:
1569         case +2700:
1570             rRawBitmap.Rotate( nAngle );
1571             break;
1572     }
1573 
1574     return true;
1575 }
1576 
1577 // -----------------------------------------------------------------------
1578 
GetGlyphBitmap8(sal_GlyphId aGlyphId,RawBitmap & rRawBitmap) const1579 bool FreetypeServerFont::GetGlyphBitmap8( sal_GlyphId aGlyphId, RawBitmap& rRawBitmap ) const
1580 {
1581     if( maSizeFT )
1582         pFTActivateSize( maSizeFT );
1583 
1584     int nGlyphFlags;
1585     SplitGlyphFlags( *this, aGlyphId, nGlyphFlags );
1586 
1587     FT_Int nLoadFlags = mnLoadFlags;
1588 
1589     if( mbArtItalic )
1590         nLoadFlags |= FT_LOAD_NO_BITMAP;
1591 
1592 #if (FTVERSION <= 2004) && !defined(TT_CONFIG_OPTION_BYTECODE_INTERPRETER)
1593     // autohinting in FT<=2.0.4 makes antialiased glyphs look worse
1594     nLoadFlags |= FT_LOAD_NO_HINTING;
1595 #else
1596     if( (nGlyphFlags & GF_UNHINTED) || (mnPrioAutoHint < mnPrioAntiAlias) )
1597         nLoadFlags |= FT_LOAD_NO_HINTING;
1598 #endif
1599 
1600     if( mnPrioEmbedded <= mnPrioAntiAlias )
1601         nLoadFlags |= FT_LOAD_NO_BITMAP;
1602 
1603     FT_Error rc = -1;
1604 #if (FTVERSION <= 2008)
1605     // #88364# freetype<=2005 prefers autohinting to embedded bitmaps
1606     // => first we have to try without hinting
1607     if( (nLoadFlags & (FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP)) == 0 )
1608     {
1609         rc = FT_Load_Glyph( maFaceFT, aGlyphId, nLoadFlags|FT_LOAD_NO_HINTING );
1610         if( (rc==FT_Err_Ok) && (maFaceFT->glyph->format != FT_GLYPH_FORMAT_BITMAP) )
1611             rc = -1; // mark as "loading embedded bitmap" was unsuccessful
1612         nLoadFlags |= FT_LOAD_NO_BITMAP;
1613     }
1614 
1615     if( rc != FT_Err_Ok )
1616 #endif
1617         rc = FT_Load_Glyph( maFaceFT, aGlyphId, nLoadFlags );
1618 
1619     if( rc != FT_Err_Ok )
1620         return false;
1621 
1622     if( mbArtBold && pFTEmbolden )
1623         (*pFTEmbolden)( maFaceFT->glyph );
1624 
1625     FT_Glyph pGlyphFT;
1626     rc = FT_Get_Glyph( maFaceFT->glyph, &pGlyphFT );
1627     if( rc != FT_Err_Ok )
1628         return false;
1629 
1630     int nAngle = ApplyGlyphTransform( nGlyphFlags, pGlyphFT, true );
1631 
1632     if( mbArtItalic )
1633     {
1634         FT_Matrix aMatrix;
1635         aMatrix.xx = aMatrix.yy = 0x10000L;
1636         if( nFTVERSION >= 2102 )    // Freetype 2.1.2 API swapped xy with yx
1637             aMatrix.xy = 0x6000L, aMatrix.yx = 0;
1638         else
1639             aMatrix.yx = 0x6000L, aMatrix.xy = 0;
1640         FT_Glyph_Transform( pGlyphFT, &aMatrix, NULL );
1641     }
1642 
1643     if( pGlyphFT->format == FT_GLYPH_FORMAT_OUTLINE )
1644         ((FT_OutlineGlyph)pGlyphFT)->outline.flags |= FT_OUTLINE_HIGH_PRECISION;
1645 
1646     bool bEmbedded = (pGlyphFT->format == FT_GLYPH_FORMAT_BITMAP);
1647     if( !bEmbedded )
1648     {
1649         rc = FT_Glyph_To_Bitmap( &pGlyphFT, FT_RENDER_MODE_NORMAL, NULL, sal_True );
1650         if( rc != FT_Err_Ok )
1651         {
1652             FT_Done_Glyph( pGlyphFT );
1653             return false;
1654         }
1655     }
1656 
1657     const FT_BitmapGlyph pBmpGlyphFT = reinterpret_cast<const FT_BitmapGlyph>(pGlyphFT);
1658     rRawBitmap.mnXOffset        = +pBmpGlyphFT->left;
1659     rRawBitmap.mnYOffset        = -pBmpGlyphFT->top;
1660 
1661     const FT_Bitmap& rBitmapFT  = pBmpGlyphFT->bitmap;
1662     rRawBitmap.mnHeight         = rBitmapFT.rows;
1663     rRawBitmap.mnWidth          = rBitmapFT.width;
1664     rRawBitmap.mnBitCount       = 8;
1665     rRawBitmap.mnScanlineSize   = bEmbedded ? rBitmapFT.width : rBitmapFT.pitch;
1666     if( mbArtBold && !pFTEmbolden )
1667     {
1668         ++rRawBitmap.mnWidth;
1669             ++rRawBitmap.mnScanlineSize;
1670     }
1671     rRawBitmap.mnScanlineSize = (rRawBitmap.mnScanlineSize + 3) & -4;
1672 
1673     const sal_uLong nNeededSize = rRawBitmap.mnScanlineSize * rRawBitmap.mnHeight;
1674     if( rRawBitmap.mnAllocated < nNeededSize )
1675     {
1676         delete[] rRawBitmap.mpBits;
1677         rRawBitmap.mnAllocated = 2*nNeededSize;
1678         rRawBitmap.mpBits = new unsigned char[ rRawBitmap.mnAllocated ];
1679     }
1680 
1681     const unsigned char* pSrc = rBitmapFT.buffer;
1682     unsigned char* pDest = rRawBitmap.mpBits;
1683     if( !bEmbedded )
1684     {
1685         for( int y = rRawBitmap.mnHeight, x; --y >= 0 ; )
1686         {
1687             for( x = 0; x < rBitmapFT.width; ++x )
1688                 *(pDest++) = *(pSrc++);
1689             for(; x < int(rRawBitmap.mnScanlineSize); ++x )
1690                 *(pDest++) = 0;
1691         }
1692     }
1693     else
1694     {
1695         for( int y = rRawBitmap.mnHeight, x; --y >= 0 ; )
1696         {
1697             unsigned char nSrc = 0;
1698             for( x = 0; x < rBitmapFT.width; ++x, nSrc+=nSrc )
1699             {
1700                 if( (x & 7) == 0 )
1701                     nSrc = *(pSrc++);
1702                 *(pDest++) = (0x7F - nSrc) >> 8;
1703             }
1704             for(; x < int(rRawBitmap.mnScanlineSize); ++x )
1705                 *(pDest++) = 0;
1706         }
1707     }
1708 
1709     if( mbArtBold && !pFTEmbolden )
1710     {
1711         // overlay with glyph image shifted by one left pixel
1712         unsigned char* p = rRawBitmap.mpBits;
1713         for( sal_uLong y=0; y < rRawBitmap.mnHeight; y++ )
1714         {
1715             unsigned char nLastByte = 0;
1716             for( sal_uLong x=0; x < rRawBitmap.mnWidth; x++ )
1717             {
1718                 unsigned char nTmp = p[x];
1719                 p[x] |= p[x] | nLastByte;
1720                 nLastByte = nTmp;
1721             }
1722             p += rRawBitmap.mnScanlineSize;
1723         }
1724     }
1725 
1726     if( !bEmbedded && mbUseGamma )
1727     {
1728         unsigned char* p = rRawBitmap.mpBits;
1729         for( sal_uLong y=0; y < rRawBitmap.mnHeight; y++ )
1730         {
1731             for( sal_uLong x=0; x < rRawBitmap.mnWidth; x++ )
1732             {
1733                 p[x] = aGammaTable[ p[x] ];
1734             }
1735             p += rRawBitmap.mnScanlineSize;
1736         }
1737     }
1738 
1739     FT_Done_Glyph( pGlyphFT );
1740 
1741     // special case for 0/90/180/270 degree orientation
1742     switch( nAngle )
1743     {
1744         case  -900:
1745         case  +900:
1746         case +1800:
1747         case +2700:
1748             rRawBitmap.Rotate( nAngle );
1749             break;
1750     }
1751 
1752     return true;
1753 }
1754 
1755 // -----------------------------------------------------------------------
1756 // determine unicode ranges in font
1757 // -----------------------------------------------------------------------
1758 
GetImplFontCharMap(void) const1759 const ImplFontCharMap* FreetypeServerFont::GetImplFontCharMap( void ) const
1760 {
1761 	const ImplFontCharMap* pIFCMap = mpFontInfo->GetImplFontCharMap();
1762 	return pIFCMap;
1763 }
1764 
GetImplFontCharMap(void)1765 const ImplFontCharMap* FtFontInfo::GetImplFontCharMap( void )
1766 {
1767 	// check if the charmap is already cached
1768 	if( mpFontCharMap )
1769 		return mpFontCharMap;
1770 
1771 	// get the charmap and cache it
1772 	CmapResult aCmapResult;
1773 	bool bOK = GetFontCodeRanges( aCmapResult );
1774 	if( bOK )
1775 		mpFontCharMap = new ImplFontCharMap( aCmapResult );
1776 	else
1777        		mpFontCharMap = ImplFontCharMap::GetDefaultMap();
1778 	mpFontCharMap->AddReference();
1779 	return mpFontCharMap;
1780 }
1781 
1782 // TODO: merge into method GetFontCharMap()
GetFontCodeRanges(CmapResult & rResult) const1783 bool FtFontInfo::GetFontCodeRanges( CmapResult& rResult ) const
1784 {
1785     rResult.mbSymbolic = IsSymbolFont();
1786 
1787     // TODO: is the full CmapResult needed on platforms calling this?
1788     if( FT_IS_SFNT( maFaceFT ) )
1789     {
1790         sal_uLong nLength = 0;
1791         const unsigned char* pCmap = GetTable( "cmap", &nLength );
1792         if( pCmap && (nLength > 0) )
1793             if( ParseCMAP( pCmap, nLength, rResult ) )
1794                 return true;
1795     }
1796 
1797     typedef std::vector<sal_uInt32> U32Vector;
1798     U32Vector aCodes;
1799 
1800     // FT's coverage is available since FT>=2.1.0 (OOo-baseline>=2.1.4 => ok)
1801     aCodes.reserve( 0x1000 );
1802     FT_UInt nGlyphIndex;
1803     for( sal_uInt32 cCode = FT_Get_First_Char( maFaceFT, &nGlyphIndex );; )
1804     {
1805         if( !nGlyphIndex )
1806             break;
1807         aCodes.push_back( cCode );	// first code inside range
1808         sal_uInt32 cNext = cCode;
1809         do cNext = FT_Get_Next_Char( maFaceFT, cCode, &nGlyphIndex ); while( cNext == ++cCode );
1810         aCodes.push_back( cCode );	// first code outside range
1811         cCode = cNext;
1812     }
1813 
1814     const int nCount = aCodes.size();
1815     if( !nCount) {
1816         if( !rResult.mbSymbolic )
1817             return false;
1818 
1819         // we usually get here for Type1 symbol fonts
1820         aCodes.push_back( 0xF020 );
1821         aCodes.push_back( 0xF100 );
1822     }
1823 
1824     sal_uInt32* pCodes = new sal_uInt32[ nCount ];
1825     for( int i = 0; i < nCount; ++i )
1826         pCodes[i] = aCodes[i];
1827     rResult.mpRangeCodes = pCodes;
1828     rResult.mnRangeCount = nCount / 2;
1829     return true;
1830 }
1831 
1832 // -----------------------------------------------------------------------
1833 // kerning stuff
1834 // -----------------------------------------------------------------------
1835 
GetGlyphKernValue(int nGlyphLeft,int nGlyphRight) const1836 int FreetypeServerFont::GetGlyphKernValue( int nGlyphLeft, int nGlyphRight ) const
1837 {
1838     // if no kerning info is available from Freetype
1839     // then we may have to use extra info provided by e.g. psprint
1840     if( !FT_HAS_KERNING( maFaceFT ) || !FT_IS_SFNT( maFaceFT ) )
1841     {
1842         int nKernVal = mpFontInfo->GetExtraGlyphKernValue( nGlyphLeft, nGlyphRight );
1843         if( !nKernVal )
1844             return 0;
1845         // scale the kern value to match the font size
1846         const ImplFontSelectData& rFSD = GetFontSelData();
1847         nKernVal *= rFSD.mnWidth ? rFSD.mnWidth : rFSD.mnHeight;
1848         return (nKernVal + 500) / 1000;
1849     }
1850 
1851     // when font faces of different sizes share the same maFaceFT
1852     // then we have to make sure that it uses the correct maSizeFT
1853     if( maSizeFT )
1854         pFTActivateSize( maSizeFT );
1855 
1856     // use Freetype's kerning info
1857     FT_Vector aKernVal;
1858     FT_Error rcFT = FT_Get_Kerning( maFaceFT, nGlyphLeft, nGlyphRight,
1859                 FT_KERNING_DEFAULT, &aKernVal );
1860     int nResult = (rcFT == FT_Err_Ok) ? (aKernVal.x + 32) >> 6 : 0;
1861     return nResult;
1862 }
1863 
1864 // -----------------------------------------------------------------------
1865 
GetKernPairs(ImplKernPairData ** ppKernPairs) const1866 sal_uLong FreetypeServerFont::GetKernPairs( ImplKernPairData** ppKernPairs ) const
1867 {
1868     // if no kerning info is available in the font file
1869     *ppKernPairs = NULL;
1870     if( !FT_HAS_KERNING( maFaceFT ) || !FT_IS_SFNT( maFaceFT ) )
1871     {
1872         // then we have may have extra kerning info from e.g. psprint
1873         int nCount = mpFontInfo->GetExtraKernPairs( ppKernPairs );
1874         // scale the kern values to match the font size
1875         const ImplFontSelectData& rFSD = GetFontSelData();
1876         int nFontWidth = rFSD.mnWidth ? rFSD.mnWidth : rFSD.mnHeight;
1877         ImplKernPairData* pKernPair = *ppKernPairs;
1878         for( int i = nCount; --i >= 0; ++pKernPair )
1879         {
1880             long& rVal = pKernPair->mnKern;
1881             rVal = ((rVal * nFontWidth) + 500) / 1000;
1882         }
1883         return nCount;
1884     }
1885 
1886     // when font faces of different sizes share the same maFaceFT
1887     // then we have to make sure that it uses the correct maSizeFT
1888     if( maSizeFT )
1889         pFTActivateSize( maSizeFT );
1890 
1891     // first figure out which glyph pairs are involved in kerning
1892     sal_uLong nKernLength = 0;
1893     const FT_Byte* const pKern = mpFontInfo->GetTable( "kern", &nKernLength );
1894     if( !pKern )
1895         return 0;
1896 
1897     // combine TTF/OTF tables from the font file to build a vector of
1898     // unicode kerning pairs using Freetype's glyph kerning calculation
1899     // for the kerning value
1900 
1901     // TODO: is it worth to share the glyph->unicode mapping between
1902     // different instances of the same font face?
1903 
1904     typedef std::vector<ImplKernPairData> KernVector;
1905     KernVector aKernGlyphVector;
1906     ImplKernPairData aKernPair;
1907     aKernPair.mnKern = 0; // To prevent "is used uninitialized" warning...
1908 
1909     const FT_Byte* pBuffer = pKern;
1910     sal_uLong nVersion = GetUShort( pBuffer+0 );
1911     sal_uInt16 nTableCnt = GetUShort( pBuffer+2 );
1912 
1913     // Microsoft/Old TrueType style kern table
1914     if ( nVersion == 0 )
1915     {
1916         pBuffer += 4;
1917 
1918         for( sal_uInt16 nTableIdx = 0; nTableIdx < nTableCnt; ++nTableIdx )
1919         {
1920             // sal_uInt16 nSubVersion  = GetUShort( pBuffer+0 );
1921             // sal_uInt16 nSubLength   = GetUShort( pBuffer+2 );
1922             sal_uInt16 nSubCoverage = GetUShort( pBuffer+4 );
1923             pBuffer += 6;
1924             if( (nSubCoverage&0x03) != 0x01 )   // no interest in minimum info here
1925                 continue;
1926             switch( nSubCoverage >> 8 )
1927             {
1928                 case 0: // version 0, kerning format 0
1929                 {
1930                     sal_uInt16 nPairs = GetUShort( pBuffer );
1931                     pBuffer += 8;   // skip search hints
1932                     aKernGlyphVector.reserve( aKernGlyphVector.size() + nPairs );
1933                     for( int i = 0; i < nPairs; ++i )
1934                     {
1935                         aKernPair.mnChar1 = GetUShort( pBuffer+0 );
1936                         aKernPair.mnChar2 = GetUShort( pBuffer+2 );
1937                         //long nUnscaledKern= GetSShort( pBuffer );
1938                         pBuffer += 6;
1939                         aKernGlyphVector.push_back( aKernPair );
1940                     }
1941                 }
1942                 break;
1943 
1944                 case 2: // version 0, kerning format 2
1945                 {
1946                     const FT_Byte* pSubTable = pBuffer;
1947                     //sal_uInt16 nRowWidth  = GetUShort( pBuffer+0 );
1948                     sal_uInt16 nOfsLeft     = GetUShort( pBuffer+2 );
1949                     sal_uInt16 nOfsRight    = GetUShort( pBuffer+4 );
1950                     sal_uInt16 nOfsArray    = GetUShort( pBuffer+6 );
1951                     pBuffer += 8;
1952 
1953                     const FT_Byte* pTmp = pSubTable + nOfsLeft;
1954                     sal_uInt16 nFirstLeft   = GetUShort( pTmp+0 );
1955                     sal_uInt16 nLastLeft    = GetUShort( pTmp+2 ) + nFirstLeft - 1;
1956 
1957                     pTmp = pSubTable + nOfsRight;
1958                     sal_uInt16 nFirstRight  = GetUShort( pTmp+0 );
1959                     sal_uInt16 nLastRight   = GetUShort( pTmp+2 ) + nFirstRight - 1;
1960 
1961                     sal_uLong nPairs = (sal_uLong)(nLastLeft - nFirstLeft + 1) * (nLastRight - nFirstRight + 1);
1962                     aKernGlyphVector.reserve( aKernGlyphVector.size() + nPairs );
1963 
1964                     pTmp = pSubTable + nOfsArray;
1965                     for( int nLeft = nFirstLeft; nLeft < nLastLeft; ++nLeft )
1966                     {
1967                         aKernPair.mnChar1 = nLeft;
1968                         for( int nRight = 0; nRight < nLastRight; ++nRight )
1969                         {
1970                             if( GetUShort( pTmp ) != 0 )
1971                             {
1972                                 aKernPair.mnChar2 = nRight;
1973                                 aKernGlyphVector.push_back( aKernPair );
1974                             }
1975                             pTmp += 2;
1976                         }
1977                     }
1978                 }
1979                 break;
1980             }
1981         }
1982     }
1983 
1984     // Apple New style kern table
1985     pBuffer = pKern;
1986     nVersion = NEXT_U32( pBuffer );
1987     nTableCnt = NEXT_U32( pBuffer );
1988     if ( nVersion == 0x00010000 )
1989     {
1990         for( sal_uInt16 nTableIdx = 0; nTableIdx < nTableCnt; ++nTableIdx )
1991         {
1992             /*sal_uLong  nLength  =*/ NEXT_U32( pBuffer );
1993             sal_uInt16 nCoverage   = NEXT_U16( pBuffer );
1994             /*sal_uInt16 nTupleIndex =*/ NEXT_U16( pBuffer );
1995 
1996             // Kerning sub-table format, 0 through 3
1997             sal_uInt8 nSubTableFormat  = nCoverage & 0x00FF;
1998 
1999             switch( nSubTableFormat )
2000             {
2001                 case 0: // version 0, kerning format 0
2002                 {
2003                     sal_uInt16 nPairs = NEXT_U16( pBuffer );
2004                     pBuffer += 6;   // skip search hints
2005                     aKernGlyphVector.reserve( aKernGlyphVector.size() + nPairs );
2006                     for( int i = 0; i < nPairs; ++i )
2007                     {
2008                         aKernPair.mnChar1 = NEXT_U16( pBuffer );
2009                         aKernPair.mnChar2 = NEXT_U16( pBuffer );
2010                         /*long nUnscaledKern=*/ NEXT_S16( pBuffer );
2011                         aKernGlyphVector.push_back( aKernPair );
2012                     }
2013                 }
2014                 break;
2015 
2016                 case 2:	// version 0, kerning format 2
2017                 {
2018                     const FT_Byte* pSubTable = pBuffer;
2019                     /*sal_uInt16 nRowWidth	=*/ NEXT_U16( pBuffer );
2020                     sal_uInt16 nOfsLeft     = NEXT_U16( pBuffer );
2021                     sal_uInt16 nOfsRight    = NEXT_U16( pBuffer );
2022                     sal_uInt16 nOfsArray    = NEXT_U16( pBuffer );
2023 
2024                     const FT_Byte* pTmp = pSubTable + nOfsLeft;
2025                     sal_uInt16 nFirstLeft   = NEXT_U16( pTmp );
2026                     sal_uInt16 nLastLeft    = NEXT_U16( pTmp ) + nFirstLeft - 1;
2027 
2028                     pTmp = pSubTable + nOfsRight;
2029                     sal_uInt16 nFirstRight  = NEXT_U16( pTmp );
2030                     sal_uInt16 nLastRight   = NEXT_U16( pTmp ) + nFirstRight - 1;
2031 
2032                     sal_uLong nPairs = (sal_uLong)(nLastLeft - nFirstLeft + 1) * (nLastRight - nFirstRight + 1);
2033                     aKernGlyphVector.reserve( aKernGlyphVector.size() + nPairs );
2034 
2035                     pTmp = pSubTable + nOfsArray;
2036                     for( int nLeft = nFirstLeft; nLeft < nLastLeft; ++nLeft )
2037                     {
2038                         aKernPair.mnChar1 = nLeft;
2039                         for( int nRight = 0; nRight < nLastRight; ++nRight )
2040                         {
2041                             if( NEXT_S16( pTmp ) != 0 )
2042                             {
2043                                 aKernPair.mnChar2 = nRight;
2044                                 aKernGlyphVector.push_back( aKernPair );
2045                             }
2046                         }
2047                     }
2048                 }
2049                 break;
2050 
2051                 default:
2052                     fprintf( stderr, "gcach_ftyp.cxx:  Found unsupported Apple-style kern subtable type %d.\n", nSubTableFormat );
2053                     break;
2054             }
2055         }
2056     }
2057 
2058     // now create VCL's ImplKernPairData[] format for all glyph pairs
2059     sal_uLong nKernCount = aKernGlyphVector.size();
2060     if( nKernCount )
2061     {
2062         // prepare glyphindex to character mapping
2063         // TODO: this is needed to support VCL's existing kerning infrastructure,
2064         // eliminate it up by redesigning kerning infrastructure to work with glyph indizes
2065         typedef std::hash_multimap<sal_uInt16,sal_Unicode> Cmap;
2066         Cmap aCmap;
2067         for( sal_Unicode aChar = 0x0020; aChar < 0xFFFE; ++aChar )
2068         {
2069             sal_uInt16 nGlyphIndex = GetGlyphIndex( aChar );
2070             if( nGlyphIndex )
2071                 aCmap.insert( Cmap::value_type( nGlyphIndex, aChar ) );
2072         }
2073 
2074         // translate both glyph indizes in kerning pairs to characters
2075         // problem is that these are 1:n mappings...
2076         KernVector aKernCharVector;
2077         aKernCharVector.reserve( nKernCount );
2078         KernVector::iterator it;
2079         for( it = aKernGlyphVector.begin(); it != aKernGlyphVector.end(); ++it )
2080         {
2081             FT_Vector aKernVal;
2082             FT_Error rcFT = FT_Get_Kerning( maFaceFT, it->mnChar1, it->mnChar2,
2083                 FT_KERNING_DEFAULT, &aKernVal );
2084             aKernPair.mnKern = aKernVal.x >> 6;
2085             if( (aKernPair.mnKern == 0) || (rcFT != FT_Err_Ok) )
2086                 continue;
2087 
2088             typedef std::pair<Cmap::iterator,Cmap::iterator> CPair;
2089             const CPair p1 = aCmap.equal_range( it->mnChar1 );
2090             const CPair p2 = aCmap.equal_range( it->mnChar2 );
2091             for( Cmap::const_iterator i1 = p1.first; i1 != p1.second; ++i1 )
2092             {
2093                 aKernPair.mnChar1 = (*i1).second;
2094                 for( Cmap::const_iterator i2 = p2.first; i2 != p2.second; ++i2 )
2095                 {
2096                     aKernPair.mnChar2 = (*i2).second;
2097                     aKernCharVector.push_back( aKernPair );
2098                 }
2099             }
2100         }
2101 
2102         // now move the resulting vector into VCL's ImplKernPairData[] format
2103         nKernCount = aKernCharVector.size();
2104         ImplKernPairData* pTo = new ImplKernPairData[ nKernCount ];
2105         *ppKernPairs = pTo;
2106         for( it = aKernCharVector.begin(); it != aKernCharVector.end(); ++it, ++pTo )
2107         {
2108             pTo->mnChar1 = it->mnChar1;
2109             pTo->mnChar2 = it->mnChar2;
2110             pTo->mnKern = it->mnKern;
2111         }
2112     }
2113 
2114     return nKernCount;
2115 }
2116 
2117 // -----------------------------------------------------------------------
2118 // outline stuff
2119 // -----------------------------------------------------------------------
2120 
2121 class PolyArgs
2122 {
2123 public:
2124                 PolyArgs( PolyPolygon& rPolyPoly, sal_uInt16 nMaxPoints );
2125                 ~PolyArgs();
2126 
2127     void        AddPoint( long nX, long nY, PolyFlags);
2128     void        ClosePolygon();
2129 
GetPosX() const2130     long        GetPosX() const { return maPosition.x;}
GetPosY() const2131     long        GetPosY() const { return maPosition.y;}
2132 
2133 private:
2134     PolyPolygon& mrPolyPoly;
2135 
2136     Point*      mpPointAry;
2137     sal_uInt8*       mpFlagAry;
2138 
2139     FT_Vector   maPosition;
2140     sal_uInt16      mnMaxPoints;
2141     sal_uInt16      mnPoints;
2142     sal_uInt16      mnPoly;
2143     long        mnHeight;
2144     bool        bHasOffline;
2145 };
2146 
2147 // -----------------------------------------------------------------------
2148 
PolyArgs(PolyPolygon & rPolyPoly,sal_uInt16 nMaxPoints)2149 PolyArgs::PolyArgs( PolyPolygon& rPolyPoly, sal_uInt16 nMaxPoints )
2150 :   mrPolyPoly(rPolyPoly),
2151     mnMaxPoints(nMaxPoints),
2152     mnPoints(0),
2153     mnPoly(0),
2154     bHasOffline(false)
2155 {
2156     mpPointAry  = new Point[ mnMaxPoints ];
2157     mpFlagAry   = new sal_uInt8 [ mnMaxPoints ];
2158 }
2159 
2160 // -----------------------------------------------------------------------
2161 
2162 
~PolyArgs()2163 PolyArgs::~PolyArgs()
2164 {
2165     delete[] mpFlagAry;
2166     delete[] mpPointAry;
2167 }
2168 
2169 // -----------------------------------------------------------------------
2170 
AddPoint(long nX,long nY,PolyFlags aFlag)2171 void PolyArgs::AddPoint( long nX, long nY, PolyFlags aFlag )
2172 {
2173     DBG_ASSERT( (mnPoints < mnMaxPoints), "FTGlyphOutline: AddPoint overflow!" );
2174     if( mnPoints >= mnMaxPoints )
2175         return;
2176 
2177     maPosition.x = nX;
2178     maPosition.y = nY;
2179     mpPointAry[ mnPoints ] = Point( nX, nY );
2180     mpFlagAry[ mnPoints++ ]= aFlag;
2181     bHasOffline |= (aFlag != POLY_NORMAL);
2182 }
2183 
2184 // -----------------------------------------------------------------------
2185 
ClosePolygon()2186 void PolyArgs::ClosePolygon()
2187 {
2188     if( !mnPoly++ )
2189         return;
2190 
2191     // freetype seems to always close the polygon with an ON_CURVE point
2192     // PolyPoly wants to close the polygon itself => remove last point
2193     DBG_ASSERT( (mnPoints >= 2), "FTGlyphOutline: PolyFinishNum failed!" );
2194     --mnPoints;
2195     DBG_ASSERT( (mpPointAry[0]==mpPointAry[mnPoints]), "FTGlyphOutline: PolyFinishEq failed!" );
2196     DBG_ASSERT( (mpFlagAry[0]==POLY_NORMAL), "FTGlyphOutline: PolyFinishFE failed!" );
2197     DBG_ASSERT( (mpFlagAry[mnPoints]==POLY_NORMAL), "FTGlyphOutline: PolyFinishFS failed!" );
2198 
2199     Polygon aPoly( mnPoints, mpPointAry, (bHasOffline ? mpFlagAry : NULL) );
2200 
2201 	// #i35928#
2202 	// This may be a invalid polygons, e.g. the last point is a control point.
2203 	// So close the polygon (and add the first point again) if the last point
2204 	// is a control point or different from first.
2205     // #i48298#
2206     // Now really duplicating the first point, to close or correct the
2207     // polygon. Also no longer duplicating the flags, but enforcing
2208     // POLY_NORMAL for the newly added last point.
2209     const sal_uInt16 nPolySize(aPoly.GetSize());
2210     if(nPolySize)
2211     {
2212         if((aPoly.HasFlags() && POLY_CONTROL == aPoly.GetFlags(nPolySize - 1))
2213             || (aPoly.GetPoint(nPolySize - 1) != aPoly.GetPoint(0)))
2214         {
2215             aPoly.SetSize(nPolySize + 1);
2216             aPoly.SetPoint(aPoly.GetPoint(0), nPolySize);
2217 
2218             if(aPoly.HasFlags())
2219             {
2220                 aPoly.SetFlags(nPolySize, POLY_NORMAL);
2221             }
2222         }
2223     }
2224 
2225     mrPolyPoly.Insert( aPoly );
2226     mnPoints = 0;
2227     bHasOffline = false;
2228 }
2229 
2230 // -----------------------------------------------------------------------
2231 
2232 extern "C" {
2233 
2234 // TODO: wait till all compilers accept that calling conventions
2235 // for functions are the same independent of implementation constness,
2236 // then uncomment the const-tokens in the function interfaces below
FT_move_to(FT_Vector_CPtr p0,void * vpPolyArgs)2237 static int FT_move_to( FT_Vector_CPtr p0, void* vpPolyArgs )
2238 {
2239     PolyArgs& rA = *reinterpret_cast<PolyArgs*>(vpPolyArgs);
2240 
2241     // move_to implies a new polygon => finish old polygon first
2242     rA.ClosePolygon();
2243 
2244     rA.AddPoint( p0->x, p0->y, POLY_NORMAL );
2245     return 0;
2246 }
2247 
FT_line_to(FT_Vector_CPtr p1,void * vpPolyArgs)2248 static int FT_line_to( FT_Vector_CPtr p1, void* vpPolyArgs )
2249 {
2250     PolyArgs& rA = *reinterpret_cast<PolyArgs*>(vpPolyArgs);
2251     rA.AddPoint( p1->x, p1->y, POLY_NORMAL );
2252     return 0;
2253 }
2254 
FT_conic_to(FT_Vector_CPtr p1,FT_Vector_CPtr p2,void * vpPolyArgs)2255 static int FT_conic_to( FT_Vector_CPtr p1, FT_Vector_CPtr p2, void* vpPolyArgs )
2256 {
2257     PolyArgs& rA = *reinterpret_cast<PolyArgs*>(vpPolyArgs);
2258 
2259     // VCL's Polygon only knows cubic beziers
2260     const long nX1 = (2 * rA.GetPosX() + 4 * p1->x + 3) / 6;
2261     const long nY1 = (2 * rA.GetPosY() + 4 * p1->y + 3) / 6;
2262     rA.AddPoint( nX1, nY1, POLY_CONTROL );
2263 
2264     const long nX2 = (2 * p2->x + 4 * p1->x + 3) / 6;
2265     const long nY2 = (2 * p2->y + 4 * p1->y + 3) / 6;
2266     rA.AddPoint( nX2, nY2, POLY_CONTROL );
2267 
2268     rA.AddPoint( p2->x, p2->y, POLY_NORMAL );
2269     return 0;
2270 }
2271 
FT_cubic_to(FT_Vector_CPtr p1,FT_Vector_CPtr p2,FT_Vector_CPtr p3,void * vpPolyArgs)2272 static int FT_cubic_to( FT_Vector_CPtr p1, FT_Vector_CPtr p2, FT_Vector_CPtr p3, void* vpPolyArgs )
2273 {
2274     PolyArgs& rA = *reinterpret_cast<PolyArgs*>(vpPolyArgs);
2275     rA.AddPoint( p1->x, p1->y, POLY_CONTROL );
2276     rA.AddPoint( p2->x, p2->y, POLY_CONTROL );
2277     rA.AddPoint( p3->x, p3->y, POLY_NORMAL );
2278     return 0;
2279 }
2280 
2281 } // extern "C"
2282 
2283 // -----------------------------------------------------------------------
2284 
GetGlyphOutline(sal_GlyphId aGlyphId,::basegfx::B2DPolyPolygon & rB2DPolyPoly) const2285 bool FreetypeServerFont::GetGlyphOutline( sal_GlyphId aGlyphId,
2286     ::basegfx::B2DPolyPolygon& rB2DPolyPoly ) const
2287 {
2288     if( maSizeFT )
2289         pFTActivateSize( maSizeFT );
2290 
2291     rB2DPolyPoly.clear();
2292 
2293     int nGlyphFlags;
2294     SplitGlyphFlags( *this, aGlyphId, nGlyphFlags );
2295 
2296     FT_Int nLoadFlags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_TRANSFORM;
2297 
2298 #ifdef FT_LOAD_TARGET_LIGHT
2299     // enable "light hinting" if available
2300     if( nFTVERSION >= 2103 )
2301         nLoadFlags |= FT_LOAD_TARGET_LIGHT;
2302 #endif
2303 
2304     FT_Error rc = FT_Load_Glyph( maFaceFT, aGlyphId, nLoadFlags );
2305     if( rc != FT_Err_Ok )
2306         return false;
2307 
2308     if( mbArtBold && pFTEmbolden )
2309         (*pFTEmbolden)( maFaceFT->glyph );
2310 
2311     FT_Glyph pGlyphFT;
2312     rc = FT_Get_Glyph( maFaceFT->glyph, &pGlyphFT );
2313     if( rc != FT_Err_Ok )
2314         return false;
2315 
2316     if( pGlyphFT->format != FT_GLYPH_FORMAT_OUTLINE )
2317         return false;
2318 
2319     if( mbArtItalic )
2320     {
2321         FT_Matrix aMatrix;
2322         aMatrix.xx = aMatrix.yy = 0x10000L;
2323         if( nFTVERSION >= 2102 )    // Freetype 2.1.2 API swapped xy with yx
2324             aMatrix.xy = 0x6000L, aMatrix.yx = 0;
2325         else
2326             aMatrix.yx = 0x6000L, aMatrix.xy = 0;
2327         FT_Glyph_Transform( pGlyphFT, &aMatrix, NULL );
2328     }
2329 
2330     FT_Outline& rOutline = reinterpret_cast<FT_OutlineGlyphRec*>(pGlyphFT)->outline;
2331     if( !rOutline.n_points )    // blank glyphs are ok
2332         return true;
2333 
2334     long nMaxPoints = 1 + rOutline.n_points * 3;
2335     PolyPolygon aToolPolyPolygon;
2336     PolyArgs aPolyArg( aToolPolyPolygon, nMaxPoints );
2337 
2338     /*int nAngle =*/ ApplyGlyphTransform( nGlyphFlags, pGlyphFT, false );
2339 
2340     FT_Outline_Funcs aFuncs;
2341     aFuncs.move_to  = &FT_move_to;
2342     aFuncs.line_to  = &FT_line_to;
2343     aFuncs.conic_to = &FT_conic_to;
2344     aFuncs.cubic_to = &FT_cubic_to;
2345     aFuncs.shift    = 0;
2346     aFuncs.delta    = 0;
2347     rc = FT_Outline_Decompose( &rOutline, &aFuncs, (void*)&aPolyArg );
2348     aPolyArg.ClosePolygon();    // close last polygon
2349     FT_Done_Glyph( pGlyphFT );
2350 
2351     // convert to basegfx polypolygon
2352     // TODO: get rid of the intermediate tools polypolygon
2353     rB2DPolyPoly = aToolPolyPolygon.getB2DPolyPolygon();
2354 	rB2DPolyPoly.transform(basegfx::tools::createScaleB2DHomMatrix( +1.0/(1<<6), -1.0/(1<<6) ));
2355 
2356     return true;
2357 }
2358 
2359 // -----------------------------------------------------------------------
2360 
ApplyGSUB(const ImplFontSelectData & rFSD)2361 bool FreetypeServerFont::ApplyGSUB( const ImplFontSelectData& rFSD )
2362 {
2363 #define MKTAG(s) ((((((s[0]<<8)+s[1])<<8)+s[2])<<8)+s[3])
2364 
2365     typedef std::vector<sal_uLong> ReqFeatureTagList;
2366     ReqFeatureTagList aReqFeatureTagList;
2367     if( rFSD.mbVertical )
2368         aReqFeatureTagList.push_back( MKTAG("vert") );
2369     sal_uLong nRequestedScript = 0;     //MKTAG("hani");//### TODO: where to get script?
2370     sal_uLong nRequestedLangsys = 0;    //MKTAG("ZHT"); //### TODO: where to get langsys?
2371     // TODO: request more features depending on script and language system
2372 
2373     if( aReqFeatureTagList.size() == 0) // nothing to do
2374         return true;
2375 
2376     // load GSUB table into memory
2377     sal_uLong nLength = 0;
2378     const FT_Byte* const pGsubBase = mpFontInfo->GetTable( "GSUB", &nLength );
2379     if( !pGsubBase )
2380         return false;
2381 
2382     // parse GSUB header
2383     const FT_Byte* pGsubHeader = pGsubBase;
2384     const sal_uInt16 nOfsScriptList     = GetUShort( pGsubHeader+4 );
2385     const sal_uInt16 nOfsFeatureTable   = GetUShort( pGsubHeader+6 );
2386     const sal_uInt16 nOfsLookupList     = GetUShort( pGsubHeader+8 );
2387     pGsubHeader += 10;
2388 
2389     typedef std::vector<sal_uInt16> UshortList;
2390     UshortList aFeatureIndexList;
2391     UshortList aFeatureOffsetList;
2392 
2393     // parse Script Table
2394     const FT_Byte* pScriptHeader = pGsubBase + nOfsScriptList;
2395     const sal_uInt16 nCntScript = GetUShort( pScriptHeader+0 );
2396     pScriptHeader += 2;
2397     for( sal_uInt16 nScriptIndex = 0; nScriptIndex < nCntScript; ++nScriptIndex )
2398     {
2399         const sal_uLong nScriptTag      = GetUInt( pScriptHeader+0 ); // e.g. hani/arab/kana/hang
2400         const sal_uInt16 nOfsScriptTable= GetUShort( pScriptHeader+4 );
2401         pScriptHeader += 6; //###
2402         if( (nScriptTag != nRequestedScript) && (nRequestedScript != 0) )
2403             continue;
2404 
2405         const FT_Byte* pScriptTable     = pGsubBase + nOfsScriptList + nOfsScriptTable;
2406         const sal_uInt16 nDefaultLangsysOfs = GetUShort( pScriptTable+0 );
2407         const sal_uInt16 nCntLangSystem     = GetUShort( pScriptTable+2 );
2408         pScriptTable += 4;
2409         sal_uInt16 nLangsysOffset = 0;
2410 
2411         for( sal_uInt16 nLangsysIndex = 0; nLangsysIndex < nCntLangSystem; ++nLangsysIndex )
2412         {
2413             const sal_uLong nTag    = GetUInt( pScriptTable+0 );    // e.g. KOR/ZHS/ZHT/JAN
2414             const sal_uInt16 nOffset= GetUShort( pScriptTable+4 );
2415             pScriptTable += 6;
2416             if( (nTag != nRequestedLangsys) && (nRequestedLangsys != 0) )
2417                 continue;
2418             nLangsysOffset = nOffset;
2419             break;
2420         }
2421 
2422         if( (nDefaultLangsysOfs != 0) && (nDefaultLangsysOfs != nLangsysOffset) )
2423         {
2424             const FT_Byte* pLangSys = pGsubBase + nOfsScriptList + nOfsScriptTable + nDefaultLangsysOfs;
2425             const sal_uInt16 nReqFeatureIdx = GetUShort( pLangSys+2 );
2426             const sal_uInt16 nCntFeature    = GetUShort( pLangSys+4 );
2427             pLangSys += 6;
2428             aFeatureIndexList.push_back( nReqFeatureIdx );
2429             for( sal_uInt16 i = 0; i < nCntFeature; ++i )
2430             {
2431                 const sal_uInt16 nFeatureIndex = GetUShort( pLangSys );
2432                 pLangSys += 2;
2433                 aFeatureIndexList.push_back( nFeatureIndex );
2434             }
2435         }
2436 
2437         if( nLangsysOffset != 0 )
2438         {
2439             const FT_Byte* pLangSys = pGsubBase + nOfsScriptList + nOfsScriptTable + nLangsysOffset;
2440             const sal_uInt16 nReqFeatureIdx = GetUShort( pLangSys+2 );
2441             const sal_uInt16 nCntFeature    = GetUShort( pLangSys+4 );
2442             pLangSys += 6;
2443             aFeatureIndexList.push_back( nReqFeatureIdx );
2444             for( sal_uInt16 i = 0; i < nCntFeature; ++i )
2445             {
2446                 const sal_uInt16 nFeatureIndex = GetUShort( pLangSys );
2447                 pLangSys += 2;
2448                 aFeatureIndexList.push_back( nFeatureIndex );
2449             }
2450         }
2451     }
2452 
2453     if( !aFeatureIndexList.size() )
2454         return true;
2455 
2456     UshortList aLookupIndexList;
2457     UshortList aLookupOffsetList;
2458 
2459     // parse Feature Table
2460     const FT_Byte* pFeatureHeader = pGsubBase + nOfsFeatureTable;
2461     const sal_uInt16 nCntFeature = GetUShort( pFeatureHeader );
2462     pFeatureHeader += 2;
2463     for( sal_uInt16 nFeatureIndex = 0; nFeatureIndex < nCntFeature; ++nFeatureIndex )
2464     {
2465         const sal_uLong nTag    = GetUInt( pFeatureHeader+0 ); // e.g. locl/vert/trad/smpl/liga/fina/...
2466         const sal_uInt16 nOffset= GetUShort( pFeatureHeader+4 );
2467         pFeatureHeader += 6;
2468 
2469         // short circuit some feature lookups
2470         if( aFeatureIndexList[0] != nFeatureIndex ) // required feature?
2471         {
2472             const int nRequested = std::count( aFeatureIndexList.begin(), aFeatureIndexList.end(), nFeatureIndex);
2473             if( !nRequested )  // ignore features that are not requested
2474                 continue;
2475             const int nAvailable = std::count( aReqFeatureTagList.begin(), aReqFeatureTagList.end(), nTag);
2476             if( !nAvailable )  // some fonts don't provide features they request!
2477                 continue;
2478         }
2479 
2480         const FT_Byte* pFeatureTable = pGsubBase + nOfsFeatureTable + nOffset;
2481         pFeatureTable += 2; // ignore FeatureParams
2482         const sal_uInt16 nCntLookups = GetUShort( pFeatureTable+0 );
2483         pFeatureTable += 2;
2484         for( sal_uInt16 i = 0; i < nCntLookups; ++i )
2485         {
2486             const sal_uInt16 nLookupIndex = GetUShort( pFeatureTable );
2487             pFeatureTable += 2;
2488             aLookupIndexList.push_back( nLookupIndex );
2489         }
2490         if( nCntLookups == 0 ) //### hack needed by Mincho/Gothic/Mingliu/Simsun/...
2491             aLookupIndexList.push_back( 0 );
2492     }
2493 
2494     // parse Lookup List
2495     const FT_Byte* pLookupHeader = pGsubBase + nOfsLookupList;
2496     const sal_uInt16 nCntLookupTable = GetUShort( pLookupHeader );
2497     pLookupHeader += 2;
2498     for( sal_uInt16 nLookupIdx = 0; nLookupIdx < nCntLookupTable; ++nLookupIdx )
2499     {
2500         const sal_uInt16 nOffset = GetUShort( pLookupHeader );
2501         pLookupHeader += 2;
2502         if( std::count( aLookupIndexList.begin(), aLookupIndexList.end(), nLookupIdx ) )
2503             aLookupOffsetList.push_back( nOffset );
2504     }
2505 
2506     UshortList::const_iterator lookup_it = aLookupOffsetList.begin();
2507     for(; lookup_it != aLookupOffsetList.end(); ++lookup_it )
2508     {
2509         const sal_uInt16 nOfsLookupTable = *lookup_it;
2510         const FT_Byte* pLookupTable = pGsubBase + nOfsLookupList + nOfsLookupTable;
2511         const sal_uInt16 eLookupType        = GetUShort( pLookupTable+0 );
2512         const sal_uInt16 nCntLookupSubtable = GetUShort( pLookupTable+4 );
2513         pLookupTable += 6;
2514 
2515         // TODO: switch( eLookupType )
2516         if( eLookupType != 1 )  // TODO: once we go beyond SingleSubst
2517             continue;
2518 
2519         for( sal_uInt16 nSubTableIdx = 0; nSubTableIdx < nCntLookupSubtable; ++nSubTableIdx )
2520         {
2521             const sal_uInt16 nOfsSubLookupTable = GetUShort( pLookupTable );
2522             pLookupTable += 2;
2523             const FT_Byte* pSubLookup = pGsubBase + nOfsLookupList + nOfsLookupTable + nOfsSubLookupTable;
2524 
2525             const sal_uInt16 nFmtSubstitution   = GetUShort( pSubLookup+0 );
2526             const sal_uInt16 nOfsCoverage       = GetUShort( pSubLookup+2 );
2527             pSubLookup += 4;
2528 
2529             typedef std::pair<sal_uInt16,sal_uInt16> GlyphSubst;
2530             typedef std::vector<GlyphSubst> SubstVector;
2531             SubstVector aSubstVector;
2532 
2533             const FT_Byte* pCoverage    = pGsubBase + nOfsLookupList + nOfsLookupTable + nOfsSubLookupTable + nOfsCoverage;
2534             const sal_uInt16 nFmtCoverage   = GetUShort( pCoverage+0 );
2535             pCoverage += 2;
2536             switch( nFmtCoverage )
2537             {
2538                 case 1:         // Coverage Format 1
2539                     {
2540                         const sal_uInt16 nCntGlyph = GetUShort( pCoverage );
2541                         pCoverage += 2;
2542                         aSubstVector.reserve( nCntGlyph );
2543                         for( sal_uInt16 i = 0; i < nCntGlyph; ++i )
2544                         {
2545                             const sal_uInt16 nGlyphId = GetUShort( pCoverage );
2546                             pCoverage += 2;
2547                             aSubstVector.push_back( GlyphSubst( nGlyphId, 0 ) );
2548                         }
2549                     }
2550                     break;
2551 
2552                 case 2:         // Coverage Format 2
2553                     {
2554                         const sal_uInt16 nCntRange = GetUShort( pCoverage );
2555                         pCoverage += 2;
2556                         for( int i = nCntRange; --i >= 0; )
2557                         {
2558                             const sal_uInt32 nGlyph0 = GetUShort( pCoverage+0 );
2559                             const sal_uInt32 nGlyph1 = GetUShort( pCoverage+2 );
2560                             const sal_uInt16 nCovIdx = GetUShort( pCoverage+4 );
2561                             pCoverage += 6;
2562                             for( sal_uInt32 j = nGlyph0; j <= nGlyph1; ++j )
2563                                 aSubstVector.push_back( GlyphSubst( static_cast<sal_uInt16>(j + nCovIdx), 0 ) );
2564                         }
2565                     }
2566                     break;
2567             }
2568 
2569             SubstVector::iterator it( aSubstVector.begin() );
2570 
2571             switch( nFmtSubstitution )
2572             {
2573                 case 1:     // Single Substitution Format 1
2574                     {
2575                         const sal_uInt16 nDeltaGlyphId = GetUShort( pSubLookup );
2576                         pSubLookup += 2;
2577                         for(; it != aSubstVector.end(); ++it )
2578                             (*it).second = (*it).first + nDeltaGlyphId;
2579                     }
2580                     break;
2581 
2582                 case 2:     // Single Substitution Format 2
2583                     {
2584                         const sal_uInt16 nCntGlyph = GetUShort( pSubLookup );
2585                         pSubLookup += 2;
2586                         for( int i = nCntGlyph; (it != aSubstVector.end()) && (--i>=0); ++it )
2587                         {
2588                             const sal_uInt16 nGlyphId = GetUShort( pSubLookup );
2589                             pSubLookup += 2;
2590                             (*it).second = nGlyphId;
2591                         }
2592                     }
2593                     break;
2594             }
2595 
2596             DBG_ASSERT( (it == aSubstVector.end()), "lookup<->coverage table mismatch" );
2597             // now apply the glyph substitutions that have been collected in this subtable
2598             for( it = aSubstVector.begin(); it != aSubstVector.end(); ++it )
2599                 maGlyphSubstitution[ (*it).first ] =  (*it).second;
2600         }
2601     }
2602 
2603     return true;
2604 }
2605 
2606 // =======================================================================
2607 
2608