merge the formfield patch from ooo-build
[ooovba.git] / vcl / source / glyphs / gcach_ftyp.cxx
blob2c4a19dce53101386e8a314f676e6f803fc63b17
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_vcl.hxx"
31 #ifdef WNT
32 #include <svsys.h>
33 #undef CreateFont
34 #endif
36 #include "gcach_ftyp.hxx"
38 #include "vcl/svapp.hxx"
39 #include "vcl/outfont.hxx"
40 #include "vcl/impfont.hxx"
41 #include "vcl/bitmap.hxx"
42 #include "vcl/bmpacc.hxx"
44 #include "tools/poly.hxx"
45 #include "basegfx/matrix/b2dhommatrix.hxx"
46 #include "basegfx/polygon/b2dpolypolygon.hxx"
48 #include "osl/file.hxx"
49 #include "osl/thread.hxx"
51 #include <ft2build.h>
52 #include FT_FREETYPE_H
53 #include FT_GLYPH_H
54 #include FT_OUTLINE_H
55 #include FT_TRUETYPE_TABLES_H
56 #include FT_TRUETYPE_TAGS_H
57 #include FT_TRUETYPE_IDS_H
59 #ifndef FT_RENDER_MODE_MONO // happens in the MACOSX build
60 #define FT_RENDER_MODE_MONO ft_render_mode_mono
61 #endif
62 #include "rtl/instance.hxx"
64 #ifndef FREETYPE_PATCH
65 // VERSION_MINOR in freetype.h is too coarse
66 // if patch-level is not available we need to fine-tune the version ourselves
67 #define FTVERSION 2005
68 #else
69 #define FTVERSION (1000*FREETYPE_MAJOR + 100*FREETYPE_MINOR + FREETYPE_PATCH)
70 #endif
71 #if FTVERSION >= 2200
72 typedef const FT_Vector* FT_Vector_CPtr;
73 #else // FTVERSION < 2200
74 typedef FT_Vector* FT_Vector_CPtr;
75 #endif
77 #include <vector>
79 // TODO: move file mapping stuff to OSL
80 #if defined(UNX)
81 #if !defined(HPUX)
82 // PORTERS: dlfcn is used for code dependend on FT version
83 #include <dlfcn.h>
84 #endif
85 #include <unistd.h>
86 #include <fcntl.h>
87 #include <sys/stat.h>
88 #include <sys/mman.h>
89 #include "vcl/fontmanager.hxx"
90 #elif defined(WNT)
91 #include <io.h>
92 #define strncasecmp strnicmp
93 #endif
95 #include "vcl/svapp.hxx"
96 #include "vcl/settings.hxx"
97 #include "i18npool/lang.h"
99 typedef const unsigned char* CPU8;
100 inline sal_uInt16 NEXT_U16( CPU8& p ) { p+=2; return (p[-2]<<8)|p[-1]; }
101 inline sal_Int16 NEXT_S16( CPU8& p ) { return (sal_Int16)NEXT_U16(p); }
102 inline sal_uInt32 NEXT_U32( CPU8& p ) { p+=4; return (p[-4]<<24)|(p[-3]<<16)|(p[-2]<<8)|p[-1]; }
103 //inline sal_Int32 NEXT_S32( U8*& p ) { return (sal_Int32)NEXT_U32(p); }
105 // -----------------------------------------------------------------------
107 // the gamma table makes artificial bold look better for CJK glyphs
108 static unsigned char aGammaTable[257];
110 static void InitGammaTable()
112 static const int M_MAX = 255;
113 static const int M_X = 128;
114 static const int M_Y = 208;
116 int x, a;
117 for( x = 0; x < 256; x++)
119 if ( x <= M_X )
120 a = ( x * M_Y + M_X / 2) / M_X;
121 else
122 a = M_Y + ( ( x - M_X ) * ( M_MAX - M_Y ) +
123 ( M_MAX - M_X ) / 2 ) / ( M_MAX - M_X );
125 aGammaTable[x] = (unsigned char)a;
129 // -----------------------------------------------------------------------
131 static FT_Library aLibFT = 0;
133 // #110607# enable linking with old FT versions
134 static int nFTVERSION = 0;
135 static FT_Error (*pFTNewSize)(FT_Face,FT_Size*);
136 static FT_Error (*pFTActivateSize)(FT_Size);
137 static FT_Error (*pFTDoneSize)(FT_Size);
138 static FT_Error (*pFTEmbolden)(FT_GlyphSlot);
139 static bool bEnableSizeFT = false;
141 struct EqStr{ bool operator()(const char* a, const char* b) const { return !strcmp(a,b); } };
142 typedef ::std::hash_map<const char*,FtFontFile*,::std::hash<const char*>, EqStr> FontFileList;
143 namespace { struct vclFontFileList : public rtl::Static< FontFileList, vclFontFileList > {}; }
145 // -----------------------------------------------------------------------
147 // TODO: remove when the priorities are selected by UI
148 // if (AH==0) => disable autohinting
149 // if (AA==0) => disable antialiasing
150 // if (EB==0) => disable embedded bitmaps
151 // if (AA prio <= AH prio) => antialias + autohint
152 // if (AH<AA) => do not autohint when antialiasing
153 // if (EB<AH) => do not autohint for monochrome
154 static int nDefaultPrioEmbedded = 2;
155 static int nDefaultPrioAutoHint = 1;
156 static int nDefaultPrioAntiAlias = 1;
158 // =======================================================================
159 // FreetypeManager
160 // =======================================================================
162 FtFontFile::FtFontFile( const ::rtl::OString& rNativeFileName )
163 : maNativeFileName( rNativeFileName ),
164 mpFileMap( NULL ),
165 mnFileSize( 0 ),
166 mnRefCount( 0 ),
167 mnLangBoost( 0 )
169 // boost font preference if UI language is mentioned in filename
170 int nPos = maNativeFileName.lastIndexOf( '_' );
171 if( nPos == -1 || maNativeFileName[nPos+1] == '.' )
172 mnLangBoost += 0x1000; // no langinfo => good
173 else
175 static const char* pLangBoost = NULL;
176 static bool bOnce = true;
177 if( bOnce )
179 bOnce = false;
180 LanguageType aLang = Application::GetSettings().GetUILanguage();
181 switch( aLang )
183 case LANGUAGE_JAPANESE:
184 pLangBoost = "jan";
185 break;
186 case LANGUAGE_CHINESE:
187 case LANGUAGE_CHINESE_SIMPLIFIED:
188 case LANGUAGE_CHINESE_SINGAPORE:
189 pLangBoost = "zhs";
190 break;
191 case LANGUAGE_CHINESE_TRADITIONAL:
192 case LANGUAGE_CHINESE_HONGKONG:
193 case LANGUAGE_CHINESE_MACAU:
194 pLangBoost = "zht";
195 break;
196 case LANGUAGE_KOREAN:
197 case LANGUAGE_KOREAN_JOHAB:
198 pLangBoost = "kor";
199 break;
203 if( pLangBoost && !strncasecmp( pLangBoost, &maNativeFileName.getStr()[nPos+1], 3 ) )
204 mnLangBoost += 0x2000; // matching langinfo => better
208 // -----------------------------------------------------------------------
210 FtFontFile* FtFontFile::FindFontFile( const ::rtl::OString& rNativeFileName )
212 // font file already known? (e.g. for ttc, synthetic, aliased fonts)
213 const char* pFileName = rNativeFileName.getStr();
214 FontFileList &rFontFileList = vclFontFileList::get();
215 FontFileList::const_iterator it = rFontFileList.find( pFileName );
216 if( it != rFontFileList.end() )
217 return (*it).second;
219 // no => create new one
220 FtFontFile* pFontFile = new FtFontFile( rNativeFileName );
221 pFileName = pFontFile->maNativeFileName.getStr();
222 rFontFileList[ pFileName ] = pFontFile;
223 return pFontFile;
226 // -----------------------------------------------------------------------
228 bool FtFontFile::Map()
230 if( mnRefCount++ <= 0 )
232 const char* pFileName = maNativeFileName.getStr();
233 #if defined(UNX)
234 int nFile = open( pFileName, O_RDONLY );
235 if( nFile < 0 )
236 return false;
238 struct stat aStat;
239 fstat( nFile, &aStat );
240 mnFileSize = aStat.st_size;
241 mpFileMap = (const unsigned char*)
242 mmap( NULL, mnFileSize, PROT_READ, MAP_SHARED, nFile, 0 );
243 if( mpFileMap == MAP_FAILED )
244 mpFileMap = NULL;
245 close( nFile );
246 #elif defined(WNT)
247 void* pFileDesc = ::CreateFile( pFileName, GENERIC_READ, FILE_SHARE_READ,
248 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 );
249 if( pFileDesc == INVALID_HANDLE_VALUE)
250 return false;
252 mnFileSize = ::GetFileSize( pFileDesc, NULL );
253 HANDLE aHandle = ::CreateFileMapping( pFileDesc, NULL, PAGE_READONLY, 0, mnFileSize, "TTF" );
254 mpFileMap = (const unsigned char*)::MapViewOfFile( aHandle, FILE_MAP_READ, 0, 0, mnFileSize );
255 ::CloseHandle( pFileDesc );
256 #else
257 FILE* pFile = fopen( pFileName, "rb" );
258 if( !pFile )
259 return false;
261 struct stat aStat;
262 stat( pFileName, &aStat );
263 mnFileSize = aStat.st_size;
264 mpFileMap = new unsigned char[ mnFileSize ];
265 if( mnFileSize != fread( mpFileMap, 1, mnFileSize, pFile ) )
267 delete[] mpFileMap;
268 mpFileMap = NULL;
270 fclose( pFile );
271 #endif
274 return (mpFileMap != NULL);
277 // -----------------------------------------------------------------------
279 void FtFontFile::Unmap()
281 if( (--mnRefCount > 0) || (mpFileMap == NULL) )
282 return;
284 #if defined(UNX)
285 munmap( (char*)mpFileMap, mnFileSize );
286 #elif defined(WNT)
287 UnmapViewOfFile( (LPCVOID)mpFileMap );
288 #else
289 delete[] mpFileMap;
290 #endif
292 mpFileMap = NULL;
295 // =======================================================================
297 FtFontInfo::FtFontInfo( const ImplDevFontAttributes& rDevFontAttributes,
298 const ::rtl::OString& rNativeFileName, int nFaceNum, sal_IntPtr nFontId, int nSynthetic,
299 const ExtraKernInfo* pExtraKernInfo )
301 maFaceFT( NULL ),
302 mpFontFile( FtFontFile::FindFontFile( rNativeFileName ) ),
303 mnFaceNum( nFaceNum ),
304 mnRefCount( 0 ),
305 mnSynthetic( nSynthetic ),
306 mnFontId( nFontId ),
307 maDevFontAttributes( rDevFontAttributes ),
308 mpChar2Glyph( NULL ),
309 mpGlyph2Char( NULL ),
310 mpExtraKernInfo( pExtraKernInfo )
312 // prefer font with low ID
313 maDevFontAttributes.mnQuality += 10000 - nFontId;
314 // prefer font with matching file names
315 maDevFontAttributes.mnQuality += mpFontFile->GetLangBoost();
316 // prefer font with more external info
317 if( pExtraKernInfo )
318 maDevFontAttributes.mnQuality += 100;
321 // -----------------------------------------------------------------------
323 FtFontInfo::~FtFontInfo()
325 delete mpExtraKernInfo;
326 delete mpChar2Glyph;
327 delete mpGlyph2Char;
330 void FtFontInfo::InitHashes() const
332 // TODO: avoid pointers when empty stl::hash_* objects become cheap
333 mpChar2Glyph = new Int2IntMap();
334 mpGlyph2Char = new Int2IntMap();
337 // -----------------------------------------------------------------------
339 FT_FaceRec_* FtFontInfo::GetFaceFT()
341 // get faceFT once/multiple depending on availability of SizeFT APIs
342 if( (mnRefCount++ <= 0) || !bEnableSizeFT )
344 if( !mpFontFile->Map() )
345 return NULL;
346 FT_Error rc = FT_New_Memory_Face( aLibFT,
347 (FT_Byte*)mpFontFile->GetBuffer(),
348 mpFontFile->GetFileSize(), mnFaceNum, &maFaceFT );
349 if( (rc != FT_Err_Ok) || (maFaceFT->num_glyphs <= 0) )
350 maFaceFT = NULL;
353 return maFaceFT;
356 // -----------------------------------------------------------------------
358 void FtFontInfo::ReleaseFaceFT( FT_FaceRec_* pFaceFT )
360 // release last/each depending on SizeFT availability
361 if( (--mnRefCount <= 0) || !bEnableSizeFT )
363 FT_Done_Face( pFaceFT );
364 maFaceFT = NULL;
365 mpFontFile->Unmap();
369 // -----------------------------------------------------------------------
371 bool FtFontInfo::HasExtraKerning() const
373 if( !mpExtraKernInfo )
374 return false;
375 // TODO: how to enable the line below without getting #i29881# back?
376 // on the other hand being to optimistic doesn't cause problems
377 // return mpExtraKernInfo->HasKernPairs();
378 return true;
381 // -----------------------------------------------------------------------
383 int FtFontInfo::GetExtraKernPairs( ImplKernPairData** ppKernPairs ) const
385 if( !mpExtraKernInfo )
386 return 0;
387 return mpExtraKernInfo->GetUnscaledKernPairs( ppKernPairs );
390 // -----------------------------------------------------------------------
392 int FtFontInfo::GetExtraGlyphKernValue( int nLeftGlyph, int nRightGlyph ) const
394 if( !mpExtraKernInfo )
395 return 0;
396 if( !mpGlyph2Char )
397 return 0;
398 sal_Unicode cLeftChar = (*mpGlyph2Char)[ nLeftGlyph ];
399 sal_Unicode cRightChar = (*mpGlyph2Char)[ nRightGlyph ];
400 return mpExtraKernInfo->GetUnscaledKernValue( cLeftChar, cRightChar );
403 // -----------------------------------------------------------------------
405 static unsigned GetUInt( const unsigned char* p ) { return((p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3]);}
406 static unsigned GetUShort( const unsigned char* p ){ return((p[0]<<8)+p[1]);}
407 //static signed GetSShort( const unsigned char* p ){ return((short)((p[0]<<8)+p[1]));}
409 // -----------------------------------------------------------------------
411 const unsigned char* FtFontInfo::GetTable( const char* pTag, ULONG* pLength ) const
413 const unsigned char* pBuffer = mpFontFile->GetBuffer();
414 int nFileSize = mpFontFile->GetFileSize();
415 if( !pBuffer || nFileSize<1024 )
416 return NULL;
418 // we currently only handle TTF and TTC headers
419 unsigned nFormat = GetUInt( pBuffer );
420 const unsigned char* p = pBuffer + 12;
421 if( nFormat == 0x74746366 ) // TTC_MAGIC
422 p += GetUInt( p + 4 * mnFaceNum );
423 else if( (nFormat!=0x00010000) && (nFormat!=0x74727565) ) // TTF_MAGIC and Apple TTF Magic
424 return NULL;
426 // walk table directory until match
427 int nTables = GetUShort( p - 8 );
428 if( nTables >= 64 ) // something fishy?
429 return NULL;
430 for( int i = 0; i < nTables; ++i, p+=16 )
432 if( p[0]==pTag[0] && p[1]==pTag[1] && p[2]==pTag[2] && p[3]==pTag[3] )
434 ULONG nLength = GetUInt( p + 12 );
435 if( pLength != NULL )
436 *pLength = nLength;
437 const unsigned char* pTable = pBuffer + GetUInt( p + 8 );
438 if( (pTable + nLength) <= (mpFontFile->GetBuffer() + nFileSize) )
439 return pTable;
443 return NULL;
446 // -----------------------------------------------------------------------
448 void FtFontInfo::AnnounceFont( ImplDevFontList* pFontList )
450 ImplFTSFontData* pFD = new ImplFTSFontData( this, maDevFontAttributes );
451 pFontList->Add( pFD );
454 // =======================================================================
456 FreetypeManager::FreetypeManager()
457 : mnMaxFontId( 0 ), mnNextFontId( 0x1000 )
459 /*FT_Error rcFT =*/ FT_Init_FreeType( &aLibFT );
461 #ifdef RTLD_DEFAULT // true if a good dlfcn.h header was included
462 // Get version of freetype library to enable workarounds.
463 // Freetype <= 2.0.9 does not have FT_Library_Version().
464 // Using dl_sym() instead of osl_getSymbol() because latter
465 // isn't designed to work with oslModule=NULL
466 void (*pFTLibraryVersion)(FT_Library library,
467 FT_Int *amajor, FT_Int *aminor, FT_Int *apatch);
468 pFTLibraryVersion = (void (*)(FT_Library library,
469 FT_Int *amajor, FT_Int *aminor, FT_Int *apatch))(sal_IntPtr)dlsym( RTLD_DEFAULT, "FT_Library_Version" );
471 pFTNewSize = (FT_Error(*)(FT_Face,FT_Size*))(sal_IntPtr)dlsym( RTLD_DEFAULT, "FT_New_Size" );
472 pFTActivateSize = (FT_Error(*)(FT_Size))(sal_IntPtr)dlsym( RTLD_DEFAULT, "FT_Activate_Size" );
473 pFTDoneSize = (FT_Error(*)(FT_Size))(sal_IntPtr)dlsym( RTLD_DEFAULT, "FT_Done_Size" );
474 pFTEmbolden = (FT_Error(*)(FT_GlyphSlot))(sal_IntPtr)dlsym( RTLD_DEFAULT, "FT_GlyphSlot_Embolden" );
476 bEnableSizeFT = (pFTNewSize!=NULL) && (pFTActivateSize!=NULL) && (pFTDoneSize!=NULL);
478 FT_Int nMajor = 0, nMinor = 0, nPatch = 0;
479 if( pFTLibraryVersion )
480 pFTLibraryVersion( aLibFT, &nMajor, &nMinor, &nPatch );
481 nFTVERSION = nMajor * 1000 + nMinor * 100 + nPatch;
483 // disable embedded bitmaps for Freetype-2.1.3 unless explicitly
484 // requested by env var below because it crashes StarOffice on RH9
485 // reason: double free in freetype's embedded bitmap handling
486 if( nFTVERSION == 2103 )
487 nDefaultPrioEmbedded = 0;
488 // disable artificial emboldening with the Freetype API for older versions
489 if( nFTVERSION < 2110 )
490 pFTEmbolden = NULL;
492 #else // RTLD_DEFAULT
493 // assume systems where dlsym is not possible use supplied library
494 nFTVERSION = FTVERSION;
495 #endif
497 // TODO: remove when the priorities are selected by UI
498 char* pEnv;
499 pEnv = ::getenv( "SAL_EMBEDDED_BITMAP_PRIORITY" );
500 if( pEnv )
501 nDefaultPrioEmbedded = pEnv[0] - '0';
502 pEnv = ::getenv( "SAL_ANTIALIASED_TEXT_PRIORITY" );
503 if( pEnv )
504 nDefaultPrioAntiAlias = pEnv[0] - '0';
505 pEnv = ::getenv( "SAL_AUTOHINTING_PRIORITY" );
506 if( pEnv )
507 nDefaultPrioAutoHint = pEnv[0] - '0';
509 InitGammaTable();
512 // -----------------------------------------------------------------------
514 void* FreetypeServerFont::GetFtFace() const
516 if( maSizeFT )
517 pFTActivateSize( maSizeFT );
519 return maFaceFT;
522 // -----------------------------------------------------------------------
524 FreetypeManager::~FreetypeManager()
526 // This crashes on Solaris 10
527 // TODO: check which versions have this problem
529 // FT_Error rcFT = FT_Done_FreeType( aLibFT );
532 // -----------------------------------------------------------------------
534 void FreetypeManager::AddFontFile( const rtl::OString& rNormalizedName,
535 int nFaceNum, sal_IntPtr nFontId, const ImplDevFontAttributes& rDevFontAttr,
536 const ExtraKernInfo* pExtraKernInfo )
538 if( !rNormalizedName.getLength() )
539 return;
541 if( maFontList.find( nFontId ) != maFontList.end() )
542 return;
544 FtFontInfo* pFontInfo = new FtFontInfo( rDevFontAttr,
545 rNormalizedName, nFaceNum, nFontId, 0, pExtraKernInfo );
546 maFontList[ nFontId ] = pFontInfo;
547 if( mnMaxFontId < nFontId )
548 mnMaxFontId = nFontId;
551 // -----------------------------------------------------------------------
553 long FreetypeManager::AddFontDir( const String& rUrlName )
555 osl::Directory aDir( rUrlName );
556 osl::FileBase::RC rcOSL = aDir.open();
557 if( rcOSL != osl::FileBase::E_None )
558 return 0;
560 long nCount = 0;
562 osl::DirectoryItem aDirItem;
563 rtl_TextEncoding theEncoding = osl_getThreadTextEncoding();
564 while( (rcOSL = aDir.getNextItem( aDirItem, 20 )) == osl::FileBase::E_None )
566 osl::FileStatus aFileStatus( FileStatusMask_FileURL );
567 rcOSL = aDirItem.getFileStatus( aFileStatus );
569 ::rtl::OUString aUSytemPath;
570 OSL_VERIFY( osl::FileBase::E_None
571 == osl::FileBase::getSystemPathFromFileURL( aFileStatus.getFileURL(), aUSytemPath ));
572 ::rtl::OString aCFileName = rtl::OUStringToOString( aUSytemPath, theEncoding );
573 const char* pszFontFileName = aCFileName.getStr();
575 FT_FaceRec_* aFaceFT = NULL;
576 for( int nFaceNum = 0, nMaxFaces = 1; nFaceNum < nMaxFaces; ++nFaceNum )
578 FT_Error rcFT = FT_New_Face( aLibFT, pszFontFileName, nFaceNum, &aFaceFT );
579 if( (rcFT != FT_Err_Ok) || (aFaceFT == NULL) )
580 break;
582 if( !FT_IS_SCALABLE( aFaceFT ) ) // ignore non-scalabale fonts
583 continue;
585 nMaxFaces = aFaceFT->num_faces;
587 ImplDevFontAttributes aDFA;
589 // TODO: prefer unicode names if available
590 // TODO: prefer locale specific names if available?
591 if ( aFaceFT->family_name )
592 aDFA.maName = String::CreateFromAscii( aFaceFT->family_name );
594 if ( aFaceFT->style_name )
595 aDFA.maStyleName = String::CreateFromAscii( aFaceFT->style_name );
597 aDFA.mbSymbolFlag = false;
598 for( int i = aFaceFT->num_charmaps; --i >= 0; )
600 const FT_CharMap aCM = aFaceFT->charmaps[i];
601 #if (FTVERSION < 2000)
602 if( aCM->encoding == FT_ENCODING_NONE )
603 #else
604 if( (aCM->platform_id == TT_PLATFORM_MICROSOFT)
605 && (aCM->encoding_id == TT_MS_ID_SYMBOL_CS) )
606 #endif
607 aDFA.mbSymbolFlag = true;
610 // TODO: extract better font characterization data from font
611 aDFA.meFamily = FAMILY_DONTKNOW;
612 aDFA.mePitch = FT_IS_FIXED_WIDTH( aFaceFT ) ? PITCH_FIXED : PITCH_VARIABLE;
613 aDFA.meWidthType = WIDTH_DONTKNOW;
614 aDFA.meWeight = FT_STYLE_FLAG_BOLD & aFaceFT->style_flags ? WEIGHT_BOLD : WEIGHT_NORMAL;
615 aDFA.meItalic = FT_STYLE_FLAG_ITALIC & aFaceFT->style_flags ? ITALIC_NORMAL : ITALIC_NONE;
617 aDFA.mnQuality = 0;
618 aDFA.mbOrientation= true;
619 aDFA.mbDevice = true;
620 aDFA.mbSubsettable= false;
621 aDFA.mbEmbeddable = false;
623 aDFA.meEmbeddedBitmap = EMBEDDEDBITMAP_DONTKNOW;
624 aDFA.meAntiAlias = ANTIALIAS_DONTKNOW;
626 FT_Done_Face( aFaceFT );
627 AddFontFile( aCFileName, nFaceNum, ++mnNextFontId, aDFA, NULL );
628 ++nCount;
632 aDir.close();
633 return nCount;
636 // -----------------------------------------------------------------------
638 void FreetypeManager::AnnounceFonts( ImplDevFontList* pToAdd ) const
640 for( FontList::const_iterator it = maFontList.begin(); it != maFontList.end(); ++it )
642 FtFontInfo* pFtFontInfo = it->second;
643 pFtFontInfo->AnnounceFont( pToAdd );
647 // -----------------------------------------------------------------------
649 void FreetypeManager::ClearFontList( )
651 for( FontList::iterator it = maFontList.begin(); it != maFontList.end(); ++it )
653 FtFontInfo* pFtFontInfo = it->second;
654 delete pFtFontInfo;
656 maFontList.clear();
659 // -----------------------------------------------------------------------
661 FreetypeServerFont* FreetypeManager::CreateFont( const ImplFontSelectData& rFSD )
663 FtFontInfo* pFontInfo = NULL;
665 // find a FontInfo matching to the font id
666 sal_IntPtr nFontId = reinterpret_cast<sal_IntPtr>( rFSD.mpFontData );
667 FontList::iterator it = maFontList.find( nFontId );
668 if( it != maFontList.end() )
669 pFontInfo = it->second;
671 if( !pFontInfo )
672 return NULL;
674 FreetypeServerFont* pNew = new FreetypeServerFont( rFSD, pFontInfo );
676 return pNew;
679 // =======================================================================
681 ImplFTSFontData::ImplFTSFontData( FtFontInfo* pFI, const ImplDevFontAttributes& rDFA )
682 : ImplFontData( rDFA, IFTSFONT_MAGIC ),
683 mpFtFontInfo( pFI )
685 mbDevice = false;
686 mbOrientation = true;
689 // -----------------------------------------------------------------------
691 ImplFontEntry* ImplFTSFontData::CreateFontInstance( ImplFontSelectData& rFSD ) const
693 ImplServerFontEntry* pEntry = new ImplServerFontEntry( rFSD );
694 return pEntry;
697 // =======================================================================
698 // FreetypeServerFont
699 // =======================================================================
701 FreetypeServerFont::FreetypeServerFont( const ImplFontSelectData& rFSD, FtFontInfo* pFI )
702 : ServerFont( rFSD ),
703 mnPrioEmbedded(nDefaultPrioEmbedded),
704 mnPrioAntiAlias(nDefaultPrioAntiAlias),
705 mpFontInfo( pFI ),
706 maFaceFT( NULL ),
707 maSizeFT( NULL ),
708 mbFaceOk( false ),
709 maRecodeConverter( NULL ),
710 mpLayoutEngine( NULL )
712 maFaceFT = pFI->GetFaceFT();
714 #ifdef HDU_DEBUG
715 fprintf( stderr, "FTSF::FTSF(\"%s\", h=%d, w=%d, sy=%d) => %d\n",
716 pFI->GetFontFileName()->getStr(), rFSD.mnHeight, rFSD.mnWidth, pFI->IsSymbolFont(), maFaceFT!=0 );
717 #endif
719 if( !maFaceFT )
720 return;
722 // set the pixel size of the font instance
723 mnWidth = rFSD.mnWidth;
724 if( !mnWidth )
725 mnWidth = rFSD.mnHeight;
726 mfStretch = (double)mnWidth / rFSD.mnHeight;
727 // sanity check (e.g. #i66394#, #i66244#, #66537#)
728 if( (mnWidth < 0) || (mfStretch > +64.0) || (mfStretch < -64.0) )
729 return;
731 // perf: use maSizeFT if available
732 if( bEnableSizeFT )
734 pFTNewSize( maFaceFT, &maSizeFT );
735 pFTActivateSize( maSizeFT );
737 FT_Error rc = FT_Set_Pixel_Sizes( maFaceFT, mnWidth, rFSD.mnHeight );
738 if( rc != FT_Err_Ok )
739 return;
741 // prepare for font encodings other than unicode or symbol
742 FT_Encoding eEncoding = FT_ENCODING_UNICODE;
743 if( mpFontInfo->IsSymbolFont() )
745 #if (FTVERSION < 2000)
746 eEncoding = FT_ENCODING_NONE;
747 #else
748 if( FT_IS_SFNT( maFaceFT ) )
749 eEncoding = ft_encoding_symbol;
750 else
751 eEncoding = FT_ENCODING_ADOBE_CUSTOM; // freetype wants this for PS symbol fonts
752 #endif
754 rc = FT_Select_Charmap( maFaceFT, eEncoding );
755 // no standard encoding applies => we need an encoding converter
756 if( rc != FT_Err_Ok )
758 rtl_TextEncoding eRecodeFrom = RTL_TEXTENCODING_UNICODE;
759 for( int i = maFaceFT->num_charmaps; --i >= 0; )
761 const FT_CharMap aCM = maFaceFT->charmaps[i];
762 if( aCM->platform_id == TT_PLATFORM_MICROSOFT )
764 switch( aCM->encoding_id )
766 case TT_MS_ID_SJIS:
767 eEncoding = FT_ENCODING_SJIS;
768 eRecodeFrom = RTL_TEXTENCODING_SHIFT_JIS;
769 break;
770 case TT_MS_ID_GB2312:
771 eEncoding = FT_ENCODING_GB2312;
772 eRecodeFrom = RTL_TEXTENCODING_GB_2312;
773 break;
774 case TT_MS_ID_BIG_5:
775 eEncoding = FT_ENCODING_BIG5;
776 eRecodeFrom = RTL_TEXTENCODING_BIG5;
777 break;
778 case TT_MS_ID_WANSUNG:
779 eEncoding = FT_ENCODING_WANSUNG;
780 eRecodeFrom = RTL_TEXTENCODING_MS_949;
781 break;
782 case TT_MS_ID_JOHAB:
783 eEncoding = FT_ENCODING_JOHAB;
784 eRecodeFrom = RTL_TEXTENCODING_MS_1361;
785 break;
788 else if( aCM->platform_id == TT_PLATFORM_MACINTOSH )
790 switch( aCM->encoding_id )
792 case TT_MAC_ID_ROMAN:
793 eEncoding = FT_ENCODING_APPLE_ROMAN;
794 eRecodeFrom = RTL_TEXTENCODING_UNICODE; // TODO: use better match
795 break;
796 // TODO: add other encodings when Mac-only
797 // non-unicode fonts show up
800 else if( aCM->platform_id == TT_PLATFORM_ADOBE )
802 switch( aCM->encoding_id )
804 #ifdef TT_ADOBE_ID_LATIN1
805 case TT_ADOBE_ID_LATIN1: // better unicode than nothing
806 eEncoding = FT_ENCODING_ADOBE_LATIN_1;
807 eRecodeFrom = RTL_TEXTENCODING_ISO_8859_1;
808 break;
809 #endif // TT_ADOBE_ID_LATIN1
810 case TT_ADOBE_ID_STANDARD: // better unicode than nothing
811 eEncoding = FT_ENCODING_ADOBE_STANDARD;
812 eRecodeFrom = RTL_TEXTENCODING_UNICODE; // TODO: use better match
813 break;
818 if( FT_Err_Ok != FT_Select_Charmap( maFaceFT, eEncoding ) )
819 return;
821 if( eRecodeFrom != RTL_TEXTENCODING_UNICODE )
822 maRecodeConverter = rtl_createUnicodeToTextConverter( eRecodeFrom );
825 mbFaceOk = true;
827 ApplyGSUB( rFSD );
829 // TODO: query GASP table for load flags
830 mnLoadFlags = FT_LOAD_DEFAULT;
831 #if 1 // #i97326# cairo sometimes uses FT_Set_Transform() on our FT_FACE
832 // we are not using FT_Set_Transform() yet, so just ignore it for now
833 mnLoadFlags |= FT_LOAD_IGNORE_TRANSFORM;
834 #endif
836 mbArtItalic = (rFSD.meItalic != ITALIC_NONE && pFI->GetFontAttributes().GetSlant() == ITALIC_NONE);
837 mbArtBold = (rFSD.meWeight > WEIGHT_MEDIUM && pFI->GetFontAttributes().GetWeight() <= WEIGHT_MEDIUM);
839 //static const int TT_CODEPAGE_RANGE_874 = (1L << 16); // Thai
840 //static const int TT_CODEPAGE_RANGE_932 = (1L << 17); // JIS/Japan
841 //static const int TT_CODEPAGE_RANGE_936 = (1L << 18); // Chinese: Simplified
842 //static const int TT_CODEPAGE_RANGE_949 = (1L << 19); // Korean Wansung
843 //static const int TT_CODEPAGE_RANGE_950 = (1L << 20); // Chinese: Traditional
844 //static const int TT_CODEPAGE_RANGE_1361 = (1L << 21); // Korean Johab
845 static const int TT_CODEPAGE_RANGES1_CJKT = 0x3F0000; // all of the above
846 const TT_OS2* pOs2 = (const TT_OS2*)FT_Get_Sfnt_Table( maFaceFT, ft_sfnt_os2 );
847 if ((pOs2) && (pOs2->ulCodePageRange1 & TT_CODEPAGE_RANGES1_CJKT )
848 && rFSD.mnHeight < 20)
849 mbUseGamma = true;
850 else
851 mbUseGamma = false;
853 if (mbUseGamma)
854 mnLoadFlags |= FT_LOAD_FORCE_AUTOHINT;
856 if( (mnSin != 0) && (mnCos != 0) ) // hinting for 0/90/180/270 degrees only
857 mnLoadFlags |= FT_LOAD_NO_HINTING;
858 mnLoadFlags |= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH; //#88334#
860 if (mpFontInfo->DontUseAntiAlias())
861 mnPrioAntiAlias = 0;
862 if (mpFontInfo->DontUseEmbeddedBitmaps())
863 mnPrioEmbedded = 0;
865 #if (FTVERSION >= 2005) || defined(TT_CONFIG_OPTION_BYTECODE_INTERPRETER)
866 if( nDefaultPrioAutoHint <= 0 )
867 #endif
868 mnLoadFlags |= FT_LOAD_NO_HINTING;
870 #ifdef FT_LOAD_TARGET_LIGHT
871 // enable "light hinting" if available
872 if( !(mnLoadFlags & FT_LOAD_NO_HINTING) && (nFTVERSION >= 2103))
873 mnLoadFlags |= FT_LOAD_TARGET_LIGHT;
874 #endif
876 if( ((mnCos != 0) && (mnSin != 0)) || (mnPrioEmbedded <= 0) )
877 mnLoadFlags |= FT_LOAD_NO_BITMAP;
880 // -----------------------------------------------------------------------
882 bool FreetypeServerFont::TestFont() const
884 return mbFaceOk;
887 // -----------------------------------------------------------------------
889 FreetypeServerFont::~FreetypeServerFont()
891 if( mpLayoutEngine )
892 delete mpLayoutEngine;
894 if( maRecodeConverter )
895 rtl_destroyUnicodeToTextConverter( maRecodeConverter );
897 if( maSizeFT )
898 pFTDoneSize( maSizeFT );
900 mpFontInfo->ReleaseFaceFT( maFaceFT );
903 // -----------------------------------------------------------------------
905 int FreetypeServerFont::GetEmUnits() const
907 return maFaceFT->units_per_EM;
910 // -----------------------------------------------------------------------
912 void FreetypeServerFont::FetchFontMetric( ImplFontMetricData& rTo, long& rFactor ) const
914 static_cast<ImplFontAttributes&>(rTo) = mpFontInfo->GetFontAttributes();
916 rTo.mbScalableFont = true;
917 rTo.mbDevice = true;
918 rTo.mbKernableFont = (FT_HAS_KERNING( maFaceFT ) != 0) || mpFontInfo->HasExtraKerning();
919 rTo.mnOrientation = GetFontSelData().mnOrientation;
921 //Always consider [star]symbol as symbol fonts
922 if (
923 (rTo.GetFamilyName().EqualsAscii("OpenSymbol")) ||
924 (rTo.GetFamilyName().EqualsAscii("StarSymbol"))
927 rTo.mbSymbolFlag = true;
930 if( maSizeFT )
931 pFTActivateSize( maSizeFT );
933 rFactor = 0x100;
935 rTo.mnWidth = mnWidth;
937 const FT_Size_Metrics& rMetrics = maFaceFT->size->metrics;
938 rTo.mnAscent = (+rMetrics.ascender + 32) >> 6;
939 #if (FTVERSION < 2000)
940 rTo.mnDescent = (+rMetrics.descender + 32) >> 6;
941 #else
942 rTo.mnDescent = (-rMetrics.descender + 32) >> 6;
943 #endif
944 rTo.mnIntLeading = ((rMetrics.height + 32) >> 6) - (rTo.mnAscent + rTo.mnDescent);
945 rTo.mnSlant = 0;
947 const TT_OS2* pOS2 = (const TT_OS2*)FT_Get_Sfnt_Table( maFaceFT, ft_sfnt_os2 );
948 const TT_HoriHeader* pHHEA = (const TT_HoriHeader*)FT_Get_Sfnt_Table( maFaceFT, ft_sfnt_hhea );
949 if( pOS2 && (pOS2->version != 0xFFFF) )
951 // map the panose info from the OS2 table to their VCL counterparts
952 switch( pOS2->panose[0] )
954 case 1: rTo.meFamily = FAMILY_ROMAN; break;
955 case 2: rTo.meFamily = FAMILY_SWISS; break;
956 case 3: rTo.meFamily = FAMILY_MODERN; break;
957 case 4: rTo.meFamily = FAMILY_SCRIPT; break;
958 case 5: rTo.meFamily = FAMILY_DECORATIVE; break;
959 // TODO: is it reasonable to override the attribute with DONTKNOW?
960 case 0: // fall through
961 default: rTo.meFamilyType = FAMILY_DONTKNOW; break;
964 switch( pOS2->panose[3] )
966 case 2: // fall through
967 case 3: // fall through
968 case 4: // fall through
969 case 5: // fall through
970 case 6: // fall through
971 case 7: // fall through
972 case 8: rTo.mePitch = PITCH_VARIABLE; break;
973 case 9: rTo.mePitch = PITCH_FIXED; break;
974 // TODO: is it reasonable to override the attribute with DONTKNOW?
975 case 0: // fall through
976 case 1: // fall through
977 default: rTo.mePitch = PITCH_DONTKNOW; break;
980 // #108862# sanity check, some fonts treat descent as signed !!!
981 int nDescent = pOS2->usWinDescent;
982 if( nDescent > 5*maFaceFT->units_per_EM )
983 nDescent = (short)pOS2->usWinDescent; // interpret it as signed!
985 const double fScale = (double)GetFontSelData().mnHeight / maFaceFT->units_per_EM;
986 if( pOS2->usWinAscent || pOS2->usWinDescent ) // #i30551#
988 rTo.mnAscent = (long)( +pOS2->usWinAscent * fScale + 0.5 );
989 rTo.mnDescent = (long)( +nDescent * fScale + 0.5 );
990 rTo.mnIntLeading = (long)( (+pOS2->usWinAscent + pOS2->usWinDescent - maFaceFT->units_per_EM) * fScale + 0.5 );
992 rTo.mnExtLeading = 0;
993 if( (pHHEA != NULL) && (pOS2->usWinAscent || pOS2->usWinDescent) )
995 int nExtLeading = pHHEA->Line_Gap;
996 nExtLeading -= (pOS2->usWinAscent + pOS2->usWinDescent);
997 nExtLeading += (pHHEA->Ascender - pHHEA->Descender);
998 if( nExtLeading > 0 )
999 rTo.mnExtLeading = (long)(nExtLeading * fScale + 0.5);
1002 // Check for CJK capabilities of the current font
1003 // #107888# workaround for Asian...
1004 // TODO: remove when ExtLeading fully implemented
1005 BOOL bCJKCapable = ((pOS2->ulUnicodeRange2 & 0x2DF00000) != 0);
1007 if ( bCJKCapable && (pOS2->usWinAscent || pOS2->usWinDescent) )
1009 rTo.mnIntLeading += rTo.mnExtLeading;
1011 // #109280# The line height for Asian fonts is too small.
1012 // Therefore we add half of the external leading to the
1013 // ascent, the other half is added to the descent.
1014 const long nHalfTmpExtLeading = rTo.mnExtLeading / 2;
1015 const long nOtherHalfTmpExtLeading = rTo.mnExtLeading -
1016 nHalfTmpExtLeading;
1018 // #110641# external leading for Asian fonts.
1019 // The factor 0.3 has been verified during experiments.
1020 const long nCJKExtLeading = (long)(0.30 * (rTo.mnAscent + rTo.mnDescent));
1022 if ( nCJKExtLeading > rTo.mnExtLeading )
1023 rTo.mnExtLeading = nCJKExtLeading - rTo.mnExtLeading;
1024 else
1025 rTo.mnExtLeading = 0;
1027 rTo.mnAscent += nHalfTmpExtLeading;
1028 rTo.mnDescent += nOtherHalfTmpExtLeading;
1032 // initialize kashida width
1033 // TODO: what if there are different versions of this glyph available
1034 rTo.mnMinKashida = rTo.mnAscent / 4; // a reasonable default
1035 const int nKashidaGlyphId = GetRawGlyphIndex( 0x0640 );
1036 if( nKashidaGlyphId )
1038 GlyphData aGlyphData;
1039 InitGlyphData( nKashidaGlyphId, aGlyphData );
1040 rTo.mnMinKashida = aGlyphData.GetMetric().GetCharWidth();
1044 // -----------------------------------------------------------------------
1046 static inline void SplitGlyphFlags( const FreetypeServerFont& rFont, int& nGlyphIndex, int& nGlyphFlags )
1048 nGlyphFlags = nGlyphIndex & GF_FLAGMASK;
1049 nGlyphIndex &= GF_IDXMASK;
1051 if( nGlyphIndex & GF_ISCHAR )
1052 nGlyphIndex = rFont.GetRawGlyphIndex( nGlyphIndex );
1055 // -----------------------------------------------------------------------
1057 int FreetypeServerFont::ApplyGlyphTransform( int nGlyphFlags,
1058 FT_Glyph pGlyphFT, bool bForBitmapProcessing ) const
1060 int nAngle = GetFontSelData().mnOrientation;
1061 // shortcut most common case
1062 if( !nAngle && !nGlyphFlags )
1063 return nAngle;
1065 const FT_Size_Metrics& rMetrics = maFaceFT->size->metrics;
1066 FT_Vector aVector;
1067 FT_Matrix aMatrix;
1069 bool bStretched = false;
1071 switch( nGlyphFlags & GF_ROTMASK )
1073 default: // straight
1074 aVector.x = 0;
1075 aVector.y = 0;
1076 aMatrix.xx = +mnCos;
1077 aMatrix.yy = +mnCos;
1078 aMatrix.xy = -mnSin;
1079 aMatrix.yx = +mnSin;
1080 break;
1081 case GF_ROTL: // left
1082 nAngle += 900;
1083 bStretched = (mfStretch != 1.0);
1084 aVector.x = (FT_Pos)(+rMetrics.descender * mfStretch);
1085 aVector.y = -rMetrics.ascender;
1086 aMatrix.xx = (FT_Pos)(-mnSin / mfStretch);
1087 aMatrix.yy = (FT_Pos)(-mnSin * mfStretch);
1088 aMatrix.xy = (FT_Pos)(-mnCos * mfStretch);
1089 aMatrix.yx = (FT_Pos)(+mnCos / mfStretch);
1090 break;
1091 case GF_ROTR: // right
1092 nAngle -= 900;
1093 bStretched = (mfStretch != 1.0);
1094 aVector.x = -maFaceFT->glyph->metrics.horiAdvance;
1095 aVector.x += (FT_Pos)(rMetrics.descender * mnSin/65536.0);
1096 aVector.y = (FT_Pos)(-rMetrics.descender * mfStretch * mnCos/65536.0);
1097 aMatrix.xx = (FT_Pos)(+mnSin / mfStretch);
1098 aMatrix.yy = (FT_Pos)(+mnSin * mfStretch);
1099 aMatrix.xy = (FT_Pos)(+mnCos * mfStretch);
1100 aMatrix.yx = (FT_Pos)(-mnCos / mfStretch);
1101 break;
1104 while( nAngle < 0 )
1105 nAngle += 3600;
1107 if( pGlyphFT->format != FT_GLYPH_FORMAT_BITMAP )
1109 FT_Glyph_Transform( pGlyphFT, NULL, &aVector );
1111 // orthogonal transforms are better handled by bitmap operations
1112 if( bStretched || (bForBitmapProcessing && (nAngle % 900) != 0) )
1114 // workaround for compatibility with older FT versions
1115 if( nFTVERSION < 2102 )
1117 FT_Fixed t = aMatrix.xy;
1118 aMatrix.xy = aMatrix.yx;
1119 aMatrix.yx = t;
1122 // apply non-orthogonal or stretch transformations
1123 FT_Glyph_Transform( pGlyphFT, &aMatrix, NULL );
1124 nAngle = 0;
1127 else
1129 // FT<=2005 ignores transforms for bitmaps, so do it manually
1130 FT_BitmapGlyph pBmpGlyphFT = reinterpret_cast<FT_BitmapGlyph>(pGlyphFT);
1131 pBmpGlyphFT->left += (aVector.x + 32) >> 6;
1132 pBmpGlyphFT->top += (aVector.y + 32) >> 6;
1135 return nAngle;
1138 // -----------------------------------------------------------------------
1140 int FreetypeServerFont::GetRawGlyphIndex( sal_UCS4 aChar ) const
1142 if( mpFontInfo->IsSymbolFont() )
1144 if( !FT_IS_SFNT( maFaceFT ) )
1146 if( (aChar & 0xFF00) == 0xF000 )
1147 aChar &= 0xFF; // PS font symbol mapping
1148 else if( aChar > 0xFF )
1149 return 0;
1153 // if needed recode from unicode to font encoding
1154 if( maRecodeConverter )
1156 sal_Char aTempArray[8];
1157 sal_Size nTempSize;
1158 sal_uInt32 nCvtInfo;
1160 // assume that modern UCS4 fonts have unicode CMAPs
1161 // => no encoding remapping to unicode is needed
1162 if( aChar > 0xFFFF )
1163 return 0;
1165 sal_Unicode aUCS2Char = static_cast<sal_Unicode>(aChar);
1166 rtl_UnicodeToTextContext aContext = rtl_createUnicodeToTextContext( maRecodeConverter );
1167 int nChars = rtl_convertUnicodeToText( maRecodeConverter, aContext,
1168 &aUCS2Char, 1, aTempArray, sizeof(aTempArray),
1169 RTL_UNICODETOTEXT_FLAGS_UNDEFINED_QUESTIONMARK
1170 | RTL_UNICODETOTEXT_FLAGS_INVALID_QUESTIONMARK,
1171 &nCvtInfo, &nTempSize );
1172 rtl_destroyUnicodeToTextContext( maRecodeConverter, aContext );
1174 aChar = 0;
1175 for( int i = 0; i < nChars; ++i )
1176 aChar = aChar*256 + (aTempArray[i] & 0xFF);
1179 // cache glyph indexes in font info to share between different sizes
1180 int nGlyphIndex = mpFontInfo->GetGlyphIndex( aChar );
1181 if( nGlyphIndex < 0 )
1183 nGlyphIndex = FT_Get_Char_Index( maFaceFT, aChar );
1184 if( !nGlyphIndex)
1186 // check if symbol aliasing helps
1187 if( (aChar <= 0x00FF) && mpFontInfo->IsSymbolFont() )
1188 nGlyphIndex = FT_Get_Char_Index( maFaceFT, aChar | 0xF000 );
1189 #if 0 // disabled for now because it introduced ae bad side-effect (#i88376#)
1190 // Finally try the postscript name table
1191 if (!nGlyphIndex)
1192 nGlyphIndex = psp::PrintFontManager::get().FreeTypeCharIndex( maFaceFT, aChar );
1193 #endif
1195 mpFontInfo->CacheGlyphIndex( aChar, nGlyphIndex );
1198 return nGlyphIndex;
1201 // -----------------------------------------------------------------------
1203 int FreetypeServerFont::FixupGlyphIndex( int nGlyphIndex, sal_UCS4 aChar ) const
1205 int nGlyphFlags = GF_NONE;
1207 // do glyph substitution if necessary
1208 // CJK vertical writing needs special treatment
1209 if( GetFontSelData().mbVertical )
1211 // TODO: rethink when GSUB is used for non-vertical case
1212 GlyphSubstitution::const_iterator it = maGlyphSubstitution.find( nGlyphIndex );
1213 if( it == maGlyphSubstitution.end() )
1215 int nTemp = GetVerticalChar( aChar );
1216 if( nTemp ) // is substitution possible
1217 nTemp = GetRawGlyphIndex( nTemp );
1218 if( nTemp ) // substitute manually if sensible
1219 nGlyphIndex = nTemp | (GF_GSUB | GF_ROTL);
1220 else
1221 nGlyphFlags |= GetVerticalFlags( aChar );
1223 else
1225 // for vertical GSUB also compensate for nOrientation=2700
1226 nGlyphIndex = (*it).second;
1227 nGlyphFlags |= GF_GSUB | GF_ROTL;
1231 #if !defined(TT_CONFIG_OPTION_BYTECODE_INTERPRETER)
1232 // #95556# autohinting not yet optimized for non-western glyph styles
1233 if( !(mnLoadFlags & (FT_LOAD_NO_HINTING | FT_LOAD_FORCE_AUTOHINT) )
1234 && ( (aChar >= 0x0600 && aChar < 0x1E00) // south-east asian + arabic
1235 ||(aChar >= 0x2900 && aChar < 0xD800) // CJKV
1236 ||(aChar >= 0xF800) ) ) // presentation + symbols
1237 nGlyphFlags |= GF_UNHINTED;
1238 #endif
1240 if( nGlyphIndex != 0 )
1241 nGlyphIndex |= nGlyphFlags;
1243 return nGlyphIndex;
1247 // -----------------------------------------------------------------------
1249 int FreetypeServerFont::GetGlyphIndex( sal_UCS4 aChar ) const
1251 int nGlyphIndex = GetRawGlyphIndex( aChar );
1252 nGlyphIndex = FixupGlyphIndex( nGlyphIndex, aChar );
1253 return nGlyphIndex;
1256 // -----------------------------------------------------------------------
1258 static int lcl_GetCharWidth( FT_FaceRec_* pFaceFT, double fStretch, int nGlyphFlags )
1260 int nCharWidth = pFaceFT->glyph->metrics.horiAdvance;
1262 if( nGlyphFlags & GF_ROTMASK ) // for bVertical rotated glyphs
1264 const FT_Size_Metrics& rMetrics = pFaceFT->size->metrics;
1265 #if (FTVERSION < 2000)
1266 nCharWidth = (int)((rMetrics.height - rMetrics.descender) * fStretch);
1267 #else
1268 nCharWidth = (int)((rMetrics.height + rMetrics.descender) * fStretch);
1269 #endif
1272 return (nCharWidth + 32) >> 6;
1275 // -----------------------------------------------------------------------
1277 void FreetypeServerFont::InitGlyphData( int nGlyphIndex, GlyphData& rGD ) const
1279 if( maSizeFT )
1280 pFTActivateSize( maSizeFT );
1282 int nGlyphFlags;
1283 SplitGlyphFlags( *this, nGlyphIndex, nGlyphFlags );
1285 int nLoadFlags = mnLoadFlags;
1287 // if( mbArtItalic )
1288 // nLoadFlags |= FT_LOAD_NO_BITMAP;
1290 FT_Error rc = -1;
1291 #if (FTVERSION <= 2008)
1292 // #88364# freetype<=2005 prefers autohinting to embedded bitmaps
1293 // => first we have to try without hinting
1294 if( (nLoadFlags & (FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP)) == 0 )
1296 rc = FT_Load_Glyph( maFaceFT, nGlyphIndex, nLoadFlags|FT_LOAD_NO_HINTING );
1297 if( (rc==FT_Err_Ok) && (maFaceFT->glyph->format!=FT_GLYPH_FORMAT_BITMAP) )
1298 rc = -1; // mark as "loading embedded bitmap" was unsuccessful
1299 nLoadFlags |= FT_LOAD_NO_BITMAP;
1302 if( rc != FT_Err_Ok )
1303 #endif
1304 rc = FT_Load_Glyph( maFaceFT, nGlyphIndex, nLoadFlags );
1306 if( rc != FT_Err_Ok )
1308 // we get here e.g. when a PS font lacks the default glyph
1309 rGD.SetCharWidth( 0 );
1310 rGD.SetDelta( 0, 0 );
1311 rGD.SetOffset( 0, 0 );
1312 rGD.SetSize( Size( 0, 0 ) );
1313 return;
1316 const bool bOriginallyZeroWidth = (maFaceFT->glyph->metrics.horiAdvance == 0);
1317 if( mbArtBold && pFTEmbolden )
1318 (*pFTEmbolden)( maFaceFT->glyph );
1320 const int nCharWidth = bOriginallyZeroWidth ? 0 : lcl_GetCharWidth( maFaceFT, mfStretch, nGlyphFlags );
1321 rGD.SetCharWidth( nCharWidth );
1323 FT_Glyph pGlyphFT;
1324 rc = FT_Get_Glyph( maFaceFT->glyph, &pGlyphFT );
1326 ApplyGlyphTransform( nGlyphFlags, pGlyphFT, false );
1327 if( mbArtBold && pFTEmbolden && (nFTVERSION < 2200) ) // #i71094# workaround staircase bug
1328 pGlyphFT->advance.y = 0;
1329 rGD.SetDelta( (pGlyphFT->advance.x + 0x8000) >> 16, -((pGlyphFT->advance.y + 0x8000) >> 16) );
1331 FT_BBox aBbox;
1332 FT_Glyph_Get_CBox( pGlyphFT, FT_GLYPH_BBOX_PIXELS, &aBbox );
1333 if( aBbox.yMin > aBbox.yMax ) // circumvent freetype bug
1335 int t=aBbox.yMin; aBbox.yMin=aBbox.yMax, aBbox.yMax=t;
1338 rGD.SetOffset( aBbox.xMin, -aBbox.yMax );
1339 rGD.SetSize( Size( (aBbox.xMax-aBbox.xMin+1), (aBbox.yMax-aBbox.yMin) ) );
1341 FT_Done_Glyph( pGlyphFT );
1344 // -----------------------------------------------------------------------
1346 bool FreetypeServerFont::GetAntialiasAdvice( void ) const
1348 if( GetFontSelData().mbNonAntialiased || (mnPrioAntiAlias<=0) )
1349 return false;
1350 bool bAdviseAA = true;
1351 // TODO: also use GASP info
1352 return bAdviseAA;
1355 // -----------------------------------------------------------------------
1357 bool FreetypeServerFont::GetGlyphBitmap1( int nGlyphIndex, RawBitmap& rRawBitmap ) const
1359 if( maSizeFT )
1360 pFTActivateSize( maSizeFT );
1362 int nGlyphFlags;
1363 SplitGlyphFlags( *this, nGlyphIndex, nGlyphFlags );
1365 FT_Int nLoadFlags = mnLoadFlags;
1366 // #i70930# force mono-hinting for monochrome text
1367 if( nFTVERSION >= 2110 ) //#i71947# unless it looks worse
1369 nLoadFlags &= ~0xF0000;
1370 nLoadFlags |= FT_LOAD_TARGET_MONO;
1373 if( mbArtItalic )
1374 nLoadFlags |= FT_LOAD_NO_BITMAP;
1376 #if (FTVERSION >= 2002)
1377 // for 0/90/180/270 degree fonts enable autohinting even if not advisable
1378 // non-hinted and non-antialiased bitmaps just look too ugly
1379 if( (mnCos==0 || mnSin==0) && (nDefaultPrioAutoHint > 0) )
1380 nLoadFlags &= ~FT_LOAD_NO_HINTING;
1381 #endif
1383 if( mnPrioEmbedded <= nDefaultPrioAutoHint )
1384 nLoadFlags |= FT_LOAD_NO_BITMAP;
1386 FT_Error rc = -1;
1387 #if (FTVERSION <= 2008)
1388 // #88364# freetype<=2005 prefers autohinting to embedded bitmaps
1389 // => first we have to try without hinting
1390 if( (nLoadFlags & (FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP)) == 0 )
1392 rc = FT_Load_Glyph( maFaceFT, nGlyphIndex, nLoadFlags|FT_LOAD_NO_HINTING );
1393 if( (rc==FT_Err_Ok) && (maFaceFT->glyph->format != FT_GLYPH_FORMAT_BITMAP) )
1394 rc = -1; // mark as "loading embedded bitmap" was unsuccessful
1395 nLoadFlags |= FT_LOAD_NO_BITMAP;
1398 if( rc != FT_Err_Ok )
1399 #endif
1400 rc = FT_Load_Glyph( maFaceFT, nGlyphIndex, nLoadFlags );
1401 if( rc != FT_Err_Ok )
1402 return false;
1404 if( mbArtBold && pFTEmbolden )
1405 (*pFTEmbolden)( maFaceFT->glyph );
1407 FT_Glyph pGlyphFT;
1408 rc = FT_Get_Glyph( maFaceFT->glyph, &pGlyphFT );
1409 if( rc != FT_Err_Ok )
1410 return false;
1412 int nAngle = ApplyGlyphTransform( nGlyphFlags, pGlyphFT, true );
1414 if( mbArtItalic )
1416 FT_Matrix aMatrix;
1417 aMatrix.xx = aMatrix.yy = 0x10000L;
1418 if( nFTVERSION >= 2102 ) // Freetype 2.1.2 API swapped xy with yx
1419 aMatrix.xy = 0x6000L, aMatrix.yx = 0;
1420 else
1421 aMatrix.yx = 0x6000L, aMatrix.xy = 0;
1422 FT_Glyph_Transform( pGlyphFT, &aMatrix, NULL );
1425 // Check for zero area bounding boxes as this crashes some versions of FT.
1426 // This also provides a handy short cut as much of the code following
1427 // becomes an expensive nop when a glyph covers no pixels.
1428 FT_BBox cbox;
1429 FT_Glyph_Get_CBox(pGlyphFT, ft_glyph_bbox_unscaled, &cbox);
1431 if( (cbox.xMax - cbox.xMin) == 0 || (cbox.yMax - cbox.yMin == 0) )
1433 nAngle = 0;
1434 memset(&rRawBitmap, 0, sizeof rRawBitmap);
1435 FT_Done_Glyph( pGlyphFT );
1436 return true;
1439 if( pGlyphFT->format != FT_GLYPH_FORMAT_BITMAP )
1441 if( pGlyphFT->format == FT_GLYPH_FORMAT_OUTLINE )
1442 ((FT_OutlineGlyphRec*)pGlyphFT)->outline.flags |= FT_OUTLINE_HIGH_PRECISION;
1443 // #i15743# freetype API 2.1.3 changed the FT_RENDER_MODE_MONO constant
1444 FT_Render_Mode nRenderMode = (FT_Render_Mode)((nFTVERSION<2103) ? 1 : FT_RENDER_MODE_MONO);
1446 rc = FT_Glyph_To_Bitmap( &pGlyphFT, nRenderMode, NULL, TRUE );
1447 if( rc != FT_Err_Ok )
1449 FT_Done_Glyph( pGlyphFT );
1450 return false;
1454 const FT_BitmapGlyph pBmpGlyphFT = reinterpret_cast<const FT_BitmapGlyph>(pGlyphFT);
1455 // NOTE: autohinting in FT<=2.0.2 miscalculates the offsets below by +-1
1456 rRawBitmap.mnXOffset = +pBmpGlyphFT->left;
1457 rRawBitmap.mnYOffset = -pBmpGlyphFT->top;
1459 const FT_Bitmap& rBitmapFT = pBmpGlyphFT->bitmap;
1460 rRawBitmap.mnHeight = rBitmapFT.rows;
1461 rRawBitmap.mnBitCount = 1;
1462 if( mbArtBold && !pFTEmbolden )
1464 rRawBitmap.mnWidth = rBitmapFT.width + 1;
1465 int nLineBytes = (rRawBitmap.mnWidth + 7) >> 3;
1466 rRawBitmap.mnScanlineSize = (nLineBytes > rBitmapFT.pitch) ? nLineBytes : rBitmapFT.pitch;
1468 else
1470 rRawBitmap.mnWidth = rBitmapFT.width;
1471 rRawBitmap.mnScanlineSize = rBitmapFT.pitch;
1474 const ULONG nNeededSize = rRawBitmap.mnScanlineSize * rRawBitmap.mnHeight;
1476 if( rRawBitmap.mnAllocated < nNeededSize )
1478 delete[] rRawBitmap.mpBits;
1479 rRawBitmap.mnAllocated = 2*nNeededSize;
1480 rRawBitmap.mpBits = new unsigned char[ rRawBitmap.mnAllocated ];
1483 if( !mbArtBold || pFTEmbolden )
1485 memcpy( rRawBitmap.mpBits, rBitmapFT.buffer, nNeededSize );
1487 else
1489 memset( rRawBitmap.mpBits, 0, nNeededSize );
1490 const unsigned char* pSrcLine = rBitmapFT.buffer;
1491 unsigned char* pDstLine = rRawBitmap.mpBits;
1492 for( int h = rRawBitmap.mnHeight; --h >= 0; )
1494 memcpy( pDstLine, pSrcLine, rBitmapFT.pitch );
1495 pDstLine += rRawBitmap.mnScanlineSize;
1496 pSrcLine += rBitmapFT.pitch;
1499 unsigned char* p = rRawBitmap.mpBits;
1500 for( ULONG y=0; y < rRawBitmap.mnHeight; y++ )
1502 unsigned char nLastByte = 0;
1503 for( ULONG x=0; x < rRawBitmap.mnScanlineSize; x++ )
1505 unsigned char nTmp = p[x] << 7;
1506 p[x] |= (p[x] >> 1) | nLastByte;
1507 nLastByte = nTmp;
1509 p += rRawBitmap.mnScanlineSize;
1513 FT_Done_Glyph( pGlyphFT );
1515 // special case for 0/90/180/270 degree orientation
1516 switch( nAngle )
1518 case -900:
1519 case +900:
1520 case +1800:
1521 case +2700:
1522 rRawBitmap.Rotate( nAngle );
1523 break;
1526 return true;
1529 // -----------------------------------------------------------------------
1531 bool FreetypeServerFont::GetGlyphBitmap8( int nGlyphIndex, RawBitmap& rRawBitmap ) const
1533 if( maSizeFT )
1534 pFTActivateSize( maSizeFT );
1536 int nGlyphFlags;
1537 SplitGlyphFlags( *this, nGlyphIndex, nGlyphFlags );
1539 FT_Int nLoadFlags = mnLoadFlags;
1541 if( mbArtItalic )
1542 nLoadFlags |= FT_LOAD_NO_BITMAP;
1544 #if (FTVERSION <= 2004) && !defined(TT_CONFIG_OPTION_BYTECODE_INTERPRETER)
1545 // autohinting in FT<=2.0.4 makes antialiased glyphs look worse
1546 nLoadFlags |= FT_LOAD_NO_HINTING;
1547 #else
1548 if( (nGlyphFlags & GF_UNHINTED) || (nDefaultPrioAutoHint < mnPrioAntiAlias) )
1549 nLoadFlags |= FT_LOAD_NO_HINTING;
1550 #endif
1552 if( mnPrioEmbedded <= mnPrioAntiAlias )
1553 nLoadFlags |= FT_LOAD_NO_BITMAP;
1555 FT_Error rc = -1;
1556 #if (FTVERSION <= 2008)
1557 // #88364# freetype<=2005 prefers autohinting to embedded bitmaps
1558 // => first we have to try without hinting
1559 if( (nLoadFlags & (FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP)) == 0 )
1561 rc = FT_Load_Glyph( maFaceFT, nGlyphIndex, nLoadFlags|FT_LOAD_NO_HINTING );
1562 if( (rc==FT_Err_Ok) && (maFaceFT->glyph->format != FT_GLYPH_FORMAT_BITMAP) )
1563 rc = -1; // mark as "loading embedded bitmap" was unsuccessful
1564 nLoadFlags |= FT_LOAD_NO_BITMAP;
1567 if( rc != FT_Err_Ok )
1568 #endif
1569 rc = FT_Load_Glyph( maFaceFT, nGlyphIndex, nLoadFlags );
1571 if( rc != FT_Err_Ok )
1572 return false;
1574 if( mbArtBold && pFTEmbolden )
1575 (*pFTEmbolden)( maFaceFT->glyph );
1577 FT_Glyph pGlyphFT;
1578 rc = FT_Get_Glyph( maFaceFT->glyph, &pGlyphFT );
1579 if( rc != FT_Err_Ok )
1580 return false;
1582 int nAngle = ApplyGlyphTransform( nGlyphFlags, pGlyphFT, true );
1584 if( mbArtItalic )
1586 FT_Matrix aMatrix;
1587 aMatrix.xx = aMatrix.yy = 0x10000L;
1588 if( nFTVERSION >= 2102 ) // Freetype 2.1.2 API swapped xy with yx
1589 aMatrix.xy = 0x6000L, aMatrix.yx = 0;
1590 else
1591 aMatrix.yx = 0x6000L, aMatrix.xy = 0;
1592 FT_Glyph_Transform( pGlyphFT, &aMatrix, NULL );
1595 if( pGlyphFT->format == FT_GLYPH_FORMAT_OUTLINE )
1596 ((FT_OutlineGlyph)pGlyphFT)->outline.flags |= FT_OUTLINE_HIGH_PRECISION;
1598 bool bEmbedded = (pGlyphFT->format == FT_GLYPH_FORMAT_BITMAP);
1599 if( !bEmbedded )
1601 rc = FT_Glyph_To_Bitmap( &pGlyphFT, FT_RENDER_MODE_NORMAL, NULL, TRUE );
1602 if( rc != FT_Err_Ok )
1604 FT_Done_Glyph( pGlyphFT );
1605 return false;
1609 const FT_BitmapGlyph pBmpGlyphFT = reinterpret_cast<const FT_BitmapGlyph>(pGlyphFT);
1610 rRawBitmap.mnXOffset = +pBmpGlyphFT->left;
1611 rRawBitmap.mnYOffset = -pBmpGlyphFT->top;
1613 const FT_Bitmap& rBitmapFT = pBmpGlyphFT->bitmap;
1614 rRawBitmap.mnHeight = rBitmapFT.rows;
1615 rRawBitmap.mnWidth = rBitmapFT.width;
1616 rRawBitmap.mnBitCount = 8;
1617 rRawBitmap.mnScanlineSize = bEmbedded ? rBitmapFT.width : rBitmapFT.pitch;
1618 if( mbArtBold && !pFTEmbolden )
1620 ++rRawBitmap.mnWidth;
1621 ++rRawBitmap.mnScanlineSize;
1623 rRawBitmap.mnScanlineSize = (rRawBitmap.mnScanlineSize + 3) & -4;
1625 const ULONG nNeededSize = rRawBitmap.mnScanlineSize * rRawBitmap.mnHeight;
1626 if( rRawBitmap.mnAllocated < nNeededSize )
1628 delete[] rRawBitmap.mpBits;
1629 rRawBitmap.mnAllocated = 2*nNeededSize;
1630 rRawBitmap.mpBits = new unsigned char[ rRawBitmap.mnAllocated ];
1633 const unsigned char* pSrc = rBitmapFT.buffer;
1634 unsigned char* pDest = rRawBitmap.mpBits;
1635 if( !bEmbedded )
1637 for( int y = rRawBitmap.mnHeight, x; --y >= 0 ; )
1639 for( x = 0; x < rBitmapFT.width; ++x )
1640 *(pDest++) = *(pSrc++);
1641 for(; x < int(rRawBitmap.mnScanlineSize); ++x )
1642 *(pDest++) = 0;
1645 else
1647 for( int y = rRawBitmap.mnHeight, x; --y >= 0 ; )
1649 unsigned char nSrc = 0;
1650 for( x = 0; x < rBitmapFT.width; ++x, nSrc+=nSrc )
1652 if( (x & 7) == 0 )
1653 nSrc = *(pSrc++);
1654 *(pDest++) = (0x7F - nSrc) >> 8;
1656 for(; x < int(rRawBitmap.mnScanlineSize); ++x )
1657 *(pDest++) = 0;
1661 if( mbArtBold && !pFTEmbolden )
1663 // overlay with glyph image shifted by one left pixel
1664 unsigned char* p = rRawBitmap.mpBits;
1665 for( ULONG y=0; y < rRawBitmap.mnHeight; y++ )
1667 unsigned char nLastByte = 0;
1668 for( ULONG x=0; x < rRawBitmap.mnWidth; x++ )
1670 unsigned char nTmp = p[x];
1671 p[x] |= p[x] | nLastByte;
1672 nLastByte = nTmp;
1674 p += rRawBitmap.mnScanlineSize;
1678 if( !bEmbedded && mbUseGamma )
1680 unsigned char* p = rRawBitmap.mpBits;
1681 for( ULONG y=0; y < rRawBitmap.mnHeight; y++ )
1683 for( ULONG x=0; x < rRawBitmap.mnWidth; x++ )
1685 p[x] = aGammaTable[ p[x] ];
1687 p += rRawBitmap.mnScanlineSize;
1691 FT_Done_Glyph( pGlyphFT );
1693 // special case for 0/90/180/270 degree orientation
1694 switch( nAngle )
1696 case -900:
1697 case +900:
1698 case +1800:
1699 case +2700:
1700 rRawBitmap.Rotate( nAngle );
1701 break;
1704 return true;
1707 // -----------------------------------------------------------------------
1708 // determine unicode ranges in font
1709 // -----------------------------------------------------------------------
1711 // TODO: replace with GetFontCharMap()
1712 bool FreetypeServerFont::GetFontCodeRanges( CmapResult& rResult ) const
1714 rResult.mbSymbolic = mpFontInfo->IsSymbolFont();
1716 // TODO: is the full CmapResult needed on platforms calling this?
1717 if( FT_IS_SFNT( maFaceFT ) )
1719 ULONG nLength = 0;
1720 const unsigned char* pCmap = mpFontInfo->GetTable( "cmap", &nLength );
1721 if( pCmap && (nLength > 0) )
1722 if( ParseCMAP( pCmap, nLength, rResult ) )
1723 return true;
1726 typedef std::vector<sal_uInt32> U32Vector;
1727 U32Vector aCodes;
1729 // FT's coverage is available since FT>=2.1.0 (OOo-baseline>=2.1.4 => ok)
1730 aCodes.reserve( 0x1000 );
1731 FT_UInt nGlyphIndex;
1732 for( sal_uInt32 cCode = FT_Get_First_Char( maFaceFT, &nGlyphIndex );; )
1734 if( !nGlyphIndex )
1735 break;
1736 aCodes.push_back( cCode ); // first code inside range
1737 sal_uInt32 cNext = cCode;
1738 do cNext = FT_Get_Next_Char( maFaceFT, cCode, &nGlyphIndex ); while( cNext == ++cCode );
1739 aCodes.push_back( cCode ); // first code outside range
1740 cCode = cNext;
1743 const int nCount = aCodes.size();
1744 if( !nCount) {
1745 if( !rResult.mbSymbolic )
1746 return false;
1748 // we usually get here for Type1 symbol fonts
1749 aCodes.push_back( 0xF020 );
1750 aCodes.push_back( 0xF100 );
1753 sal_uInt32* pCodes = new sal_uInt32[ nCount ];
1754 for( int i = 0; i < nCount; ++i )
1755 pCodes[i] = aCodes[i];
1756 rResult.mpRangeCodes = pCodes;
1757 rResult.mnRangeCount = nCount / 2;
1758 return true;
1761 // -----------------------------------------------------------------------
1762 // kerning stuff
1763 // -----------------------------------------------------------------------
1765 int FreetypeServerFont::GetGlyphKernValue( int nGlyphLeft, int nGlyphRight ) const
1767 // if no kerning info is available from Freetype
1768 // then we may have to use extra info provided by e.g. psprint
1769 if( !FT_HAS_KERNING( maFaceFT ) || !FT_IS_SFNT( maFaceFT ) )
1771 int nKernVal = mpFontInfo->GetExtraGlyphKernValue( nGlyphLeft, nGlyphRight );
1772 if( !nKernVal )
1773 return 0;
1774 // scale the kern value to match the font size
1775 const ImplFontSelectData& rFSD = GetFontSelData();
1776 nKernVal *= rFSD.mnWidth ? rFSD.mnWidth : rFSD.mnHeight;
1777 return (nKernVal + 500) / 1000;
1780 // when font faces of different sizes share the same maFaceFT
1781 // then we have to make sure that it uses the correct maSizeFT
1782 if( maSizeFT )
1783 pFTActivateSize( maSizeFT );
1785 // use Freetype's kerning info
1786 FT_Vector aKernVal;
1787 FT_Error rcFT = FT_Get_Kerning( maFaceFT, nGlyphLeft, nGlyphRight,
1788 FT_KERNING_DEFAULT, &aKernVal );
1789 int nResult = (rcFT == FT_Err_Ok) ? (aKernVal.x + 32) >> 6 : 0;
1790 return nResult;
1793 // -----------------------------------------------------------------------
1795 ULONG FreetypeServerFont::GetKernPairs( ImplKernPairData** ppKernPairs ) const
1797 // if no kerning info is available in the font file
1798 *ppKernPairs = NULL;
1799 if( !FT_HAS_KERNING( maFaceFT ) || !FT_IS_SFNT( maFaceFT ) )
1801 // then we have may have extra kerning info from e.g. psprint
1802 int nCount = mpFontInfo->GetExtraKernPairs( ppKernPairs );
1803 // scale the kern values to match the font size
1804 const ImplFontSelectData& rFSD = GetFontSelData();
1805 int nFontWidth = rFSD.mnWidth ? rFSD.mnWidth : rFSD.mnHeight;
1806 ImplKernPairData* pKernPair = *ppKernPairs;
1807 for( int i = nCount; --i >= 0; ++pKernPair )
1809 long& rVal = pKernPair->mnKern;
1810 rVal = ((rVal * nFontWidth) + 500) / 1000;
1812 return nCount;
1815 // when font faces of different sizes share the same maFaceFT
1816 // then we have to make sure that it uses the correct maSizeFT
1817 if( maSizeFT )
1818 pFTActivateSize( maSizeFT );
1820 // first figure out which glyph pairs are involved in kerning
1821 ULONG nKernLength = 0;
1822 const FT_Byte* const pKern = mpFontInfo->GetTable( "kern", &nKernLength );
1823 if( !pKern )
1824 return 0;
1826 // combine TTF/OTF tables from the font file to build a vector of
1827 // unicode kerning pairs using Freetype's glyph kerning calculation
1828 // for the kerning value
1830 // TODO: is it worth to share the glyph->unicode mapping between
1831 // different instances of the same font face?
1833 typedef std::vector<ImplKernPairData> KernVector;
1834 KernVector aKernGlyphVector;
1835 ImplKernPairData aKernPair;
1836 aKernPair.mnKern = 0; // To prevent "is used uninitialized" warning...
1838 const FT_Byte* pBuffer = pKern;
1839 ULONG nVersion = GetUShort( pBuffer+0 );
1840 USHORT nTableCnt = GetUShort( pBuffer+2 );
1842 // Microsoft/Old TrueType style kern table
1843 if ( nVersion == 0 )
1845 pBuffer += 4;
1847 for( USHORT nTableIdx = 0; nTableIdx < nTableCnt; ++nTableIdx )
1849 // USHORT nSubVersion = GetUShort( pBuffer+0 );
1850 // USHORT nSubLength = GetUShort( pBuffer+2 );
1851 USHORT nSubCoverage = GetUShort( pBuffer+4 );
1852 pBuffer += 6;
1853 if( (nSubCoverage&0x03) != 0x01 ) // no interest in minimum info here
1854 continue;
1855 switch( nSubCoverage >> 8 )
1857 case 0: // version 0, kerning format 0
1859 USHORT nPairs = GetUShort( pBuffer );
1860 pBuffer += 8; // skip search hints
1861 aKernGlyphVector.reserve( aKernGlyphVector.size() + nPairs );
1862 for( int i = 0; i < nPairs; ++i )
1864 aKernPair.mnChar1 = GetUShort( pBuffer+0 );
1865 aKernPair.mnChar2 = GetUShort( pBuffer+2 );
1866 //long nUnscaledKern= GetSShort( pBuffer );
1867 pBuffer += 6;
1868 aKernGlyphVector.push_back( aKernPair );
1871 break;
1873 case 2: // version 0, kerning format 2
1875 const FT_Byte* pSubTable = pBuffer;
1876 //USHORT nRowWidth = GetUShort( pBuffer+0 );
1877 USHORT nOfsLeft = GetUShort( pBuffer+2 );
1878 USHORT nOfsRight = GetUShort( pBuffer+4 );
1879 USHORT nOfsArray = GetUShort( pBuffer+6 );
1880 pBuffer += 8;
1882 const FT_Byte* pTmp = pSubTable + nOfsLeft;
1883 USHORT nFirstLeft = GetUShort( pTmp+0 );
1884 USHORT nLastLeft = GetUShort( pTmp+2 ) + nFirstLeft - 1;
1886 pTmp = pSubTable + nOfsRight;
1887 USHORT nFirstRight = GetUShort( pTmp+0 );
1888 USHORT nLastRight = GetUShort( pTmp+2 ) + nFirstRight - 1;
1890 ULONG nPairs = (ULONG)(nLastLeft - nFirstLeft + 1) * (nLastRight - nFirstRight + 1);
1891 aKernGlyphVector.reserve( aKernGlyphVector.size() + nPairs );
1893 pTmp = pSubTable + nOfsArray;
1894 for( int nLeft = nFirstLeft; nLeft < nLastLeft; ++nLeft )
1896 aKernPair.mnChar1 = nLeft;
1897 for( int nRight = 0; nRight < nLastRight; ++nRight )
1899 if( GetUShort( pTmp ) != 0 )
1901 aKernPair.mnChar2 = nRight;
1902 aKernGlyphVector.push_back( aKernPair );
1904 pTmp += 2;
1908 break;
1913 // Apple New style kern table
1914 pBuffer = pKern;
1915 nVersion = NEXT_U32( pBuffer );
1916 nTableCnt = NEXT_U32( pBuffer );
1917 if ( nVersion == 0x00010000 )
1919 for( USHORT nTableIdx = 0; nTableIdx < nTableCnt; ++nTableIdx )
1921 /*ULONG nLength =*/ NEXT_U32( pBuffer );
1922 USHORT nCoverage = NEXT_U16( pBuffer );
1923 /*USHORT nTupleIndex =*/ NEXT_U16( pBuffer );
1925 // Kerning sub-table format, 0 through 3
1926 sal_uInt8 nSubTableFormat = nCoverage & 0x00FF;
1928 switch( nSubTableFormat )
1930 case 0: // version 0, kerning format 0
1932 USHORT nPairs = NEXT_U16( pBuffer );
1933 pBuffer += 6; // skip search hints
1934 aKernGlyphVector.reserve( aKernGlyphVector.size() + nPairs );
1935 for( int i = 0; i < nPairs; ++i )
1937 aKernPair.mnChar1 = NEXT_U16( pBuffer );
1938 aKernPair.mnChar2 = NEXT_U16( pBuffer );
1939 /*long nUnscaledKern=*/ NEXT_S16( pBuffer );
1940 aKernGlyphVector.push_back( aKernPair );
1943 break;
1945 case 2: // version 0, kerning format 2
1947 const FT_Byte* pSubTable = pBuffer;
1948 /*USHORT nRowWidth =*/ NEXT_U16( pBuffer );
1949 USHORT nOfsLeft = NEXT_U16( pBuffer );
1950 USHORT nOfsRight = NEXT_U16( pBuffer );
1951 USHORT nOfsArray = NEXT_U16( pBuffer );
1953 const FT_Byte* pTmp = pSubTable + nOfsLeft;
1954 USHORT nFirstLeft = NEXT_U16( pTmp );
1955 USHORT nLastLeft = NEXT_U16( pTmp ) + nFirstLeft - 1;
1957 pTmp = pSubTable + nOfsRight;
1958 USHORT nFirstRight = NEXT_U16( pTmp );
1959 USHORT nLastRight = NEXT_U16( pTmp ) + nFirstRight - 1;
1961 ULONG nPairs = (ULONG)(nLastLeft - nFirstLeft + 1) * (nLastRight - nFirstRight + 1);
1962 aKernGlyphVector.reserve( aKernGlyphVector.size() + nPairs );
1964 pTmp = pSubTable + nOfsArray;
1965 for( int nLeft = nFirstLeft; nLeft < nLastLeft; ++nLeft )
1967 aKernPair.mnChar1 = nLeft;
1968 for( int nRight = 0; nRight < nLastRight; ++nRight )
1970 if( NEXT_S16( pTmp ) != 0 )
1972 aKernPair.mnChar2 = nRight;
1973 aKernGlyphVector.push_back( aKernPair );
1978 break;
1980 default:
1981 fprintf( stderr, "gcach_ftyp.cxx: Found unsupported Apple-style kern subtable type %d.\n", nSubTableFormat );
1982 break;
1987 // now create VCL's ImplKernPairData[] format for all glyph pairs
1988 ULONG nKernCount = aKernGlyphVector.size();
1989 if( nKernCount )
1991 // prepare glyphindex to character mapping
1992 // TODO: this is needed to support VCL's existing kerning infrastructure,
1993 // eliminate it up by redesigning kerning infrastructure to work with glyph indizes
1994 typedef std::hash_multimap<USHORT,sal_Unicode> Cmap;
1995 Cmap aCmap;
1996 for( sal_Unicode aChar = 0x0020; aChar < 0xFFFE; ++aChar )
1998 USHORT nGlyphIndex = GetGlyphIndex( aChar );
1999 if( nGlyphIndex )
2000 aCmap.insert( Cmap::value_type( nGlyphIndex, aChar ) );
2003 // translate both glyph indizes in kerning pairs to characters
2004 // problem is that these are 1:n mappings...
2005 KernVector aKernCharVector;
2006 aKernCharVector.reserve( nKernCount );
2007 KernVector::iterator it;
2008 for( it = aKernGlyphVector.begin(); it != aKernGlyphVector.end(); ++it )
2010 FT_Vector aKernVal;
2011 FT_Error rcFT = FT_Get_Kerning( maFaceFT, it->mnChar1, it->mnChar2,
2012 FT_KERNING_DEFAULT, &aKernVal );
2013 aKernPair.mnKern = aKernVal.x >> 6;
2014 if( (aKernPair.mnKern == 0) || (rcFT != FT_Err_Ok) )
2015 continue;
2017 typedef std::pair<Cmap::iterator,Cmap::iterator> CPair;
2018 const CPair p1 = aCmap.equal_range( it->mnChar1 );
2019 const CPair p2 = aCmap.equal_range( it->mnChar2 );
2020 for( Cmap::const_iterator i1 = p1.first; i1 != p1.second; ++i1 )
2022 aKernPair.mnChar1 = (*i1).second;
2023 for( Cmap::const_iterator i2 = p2.first; i2 != p2.second; ++i2 )
2025 aKernPair.mnChar2 = (*i2).second;
2026 aKernCharVector.push_back( aKernPair );
2031 // now move the resulting vector into VCL's ImplKernPairData[] format
2032 nKernCount = aKernCharVector.size();
2033 ImplKernPairData* pTo = new ImplKernPairData[ nKernCount ];
2034 *ppKernPairs = pTo;
2035 for( it = aKernCharVector.begin(); it != aKernCharVector.end(); ++it, ++pTo )
2037 pTo->mnChar1 = it->mnChar1;
2038 pTo->mnChar2 = it->mnChar2;
2039 pTo->mnKern = it->mnKern;
2043 return nKernCount;
2046 // -----------------------------------------------------------------------
2047 // outline stuff
2048 // -----------------------------------------------------------------------
2050 class PolyArgs
2052 public:
2053 PolyArgs( PolyPolygon& rPolyPoly, USHORT nMaxPoints );
2054 ~PolyArgs();
2056 void AddPoint( long nX, long nY, PolyFlags);
2057 void ClosePolygon();
2059 long GetPosX() const { return maPosition.x;}
2060 long GetPosY() const { return maPosition.y;}
2062 private:
2063 PolyPolygon& mrPolyPoly;
2065 Point* mpPointAry;
2066 BYTE* mpFlagAry;
2068 FT_Vector maPosition;
2069 USHORT mnMaxPoints;
2070 USHORT mnPoints;
2071 USHORT mnPoly;
2072 long mnHeight;
2073 bool bHasOffline;
2076 // -----------------------------------------------------------------------
2078 PolyArgs::PolyArgs( PolyPolygon& rPolyPoly, USHORT nMaxPoints )
2079 : mrPolyPoly(rPolyPoly),
2080 mnMaxPoints(nMaxPoints),
2081 mnPoints(0),
2082 mnPoly(0),
2083 bHasOffline(false)
2085 mpPointAry = new Point[ mnMaxPoints ];
2086 mpFlagAry = new BYTE [ mnMaxPoints ];
2089 // -----------------------------------------------------------------------
2092 PolyArgs::~PolyArgs()
2094 delete[] mpFlagAry;
2095 delete[] mpPointAry;
2098 // -----------------------------------------------------------------------
2100 void PolyArgs::AddPoint( long nX, long nY, PolyFlags aFlag )
2102 DBG_ASSERT( (mnPoints < mnMaxPoints), "FTGlyphOutline: AddPoint overflow!" );
2103 if( mnPoints >= mnMaxPoints )
2104 return;
2106 maPosition.x = nX;
2107 maPosition.y = nY;
2108 mpPointAry[ mnPoints ] = Point( nX, nY );
2109 mpFlagAry[ mnPoints++ ]= aFlag;
2110 bHasOffline |= (aFlag != POLY_NORMAL);
2113 // -----------------------------------------------------------------------
2115 void PolyArgs::ClosePolygon()
2117 if( !mnPoly++ )
2118 return;
2120 // freetype seems to always close the polygon with an ON_CURVE point
2121 // PolyPoly wants to close the polygon itself => remove last point
2122 DBG_ASSERT( (mnPoints >= 2), "FTGlyphOutline: PolyFinishNum failed!" );
2123 --mnPoints;
2124 DBG_ASSERT( (mpPointAry[0]==mpPointAry[mnPoints]), "FTGlyphOutline: PolyFinishEq failed!" );
2125 DBG_ASSERT( (mpFlagAry[0]==POLY_NORMAL), "FTGlyphOutline: PolyFinishFE failed!" );
2126 DBG_ASSERT( (mpFlagAry[mnPoints]==POLY_NORMAL), "FTGlyphOutline: PolyFinishFS failed!" );
2128 Polygon aPoly( mnPoints, mpPointAry, (bHasOffline ? mpFlagAry : NULL) );
2130 // #i35928#
2131 // This may be a invalid polygons, e.g. the last point is a control point.
2132 // So close the polygon (and add the first point again) if the last point
2133 // is a control point or different from first.
2134 // #i48298#
2135 // Now really duplicating the first point, to close or correct the
2136 // polygon. Also no longer duplicating the flags, but enforcing
2137 // POLY_NORMAL for the newly added last point.
2138 const sal_uInt16 nPolySize(aPoly.GetSize());
2139 if(nPolySize)
2141 if((aPoly.HasFlags() && POLY_CONTROL == aPoly.GetFlags(nPolySize - 1))
2142 || (aPoly.GetPoint(nPolySize - 1) != aPoly.GetPoint(0)))
2144 aPoly.SetSize(nPolySize + 1);
2145 aPoly.SetPoint(aPoly.GetPoint(0), nPolySize);
2147 if(aPoly.HasFlags())
2149 aPoly.SetFlags(nPolySize, POLY_NORMAL);
2154 mrPolyPoly.Insert( aPoly );
2155 mnPoints = 0;
2156 bHasOffline = false;
2159 // -----------------------------------------------------------------------
2161 extern "C" {
2163 // TODO: wait till all compilers accept that calling conventions
2164 // for functions are the same independent of implementation constness,
2165 // then uncomment the const-tokens in the function interfaces below
2166 static int FT_move_to( FT_Vector_CPtr p0, void* vpPolyArgs )
2168 PolyArgs& rA = *reinterpret_cast<PolyArgs*>(vpPolyArgs);
2170 // move_to implies a new polygon => finish old polygon first
2171 rA.ClosePolygon();
2173 rA.AddPoint( p0->x, p0->y, POLY_NORMAL );
2174 return 0;
2177 static int FT_line_to( FT_Vector_CPtr p1, void* vpPolyArgs )
2179 PolyArgs& rA = *reinterpret_cast<PolyArgs*>(vpPolyArgs);
2180 rA.AddPoint( p1->x, p1->y, POLY_NORMAL );
2181 return 0;
2184 static int FT_conic_to( FT_Vector_CPtr p1, FT_Vector_CPtr p2, void* vpPolyArgs )
2186 PolyArgs& rA = *reinterpret_cast<PolyArgs*>(vpPolyArgs);
2188 // VCL's Polygon only knows cubic beziers
2189 const long nX1 = (2 * rA.GetPosX() + 4 * p1->x + 3) / 6;
2190 const long nY1 = (2 * rA.GetPosY() + 4 * p1->y + 3) / 6;
2191 rA.AddPoint( nX1, nY1, POLY_CONTROL );
2193 const long nX2 = (2 * p2->x + 4 * p1->x + 3) / 6;
2194 const long nY2 = (2 * p2->y + 4 * p1->y + 3) / 6;
2195 rA.AddPoint( nX2, nY2, POLY_CONTROL );
2197 rA.AddPoint( p2->x, p2->y, POLY_NORMAL );
2198 return 0;
2201 static int FT_cubic_to( FT_Vector_CPtr p1, FT_Vector_CPtr p2, FT_Vector_CPtr p3, void* vpPolyArgs )
2203 PolyArgs& rA = *reinterpret_cast<PolyArgs*>(vpPolyArgs);
2204 rA.AddPoint( p1->x, p1->y, POLY_CONTROL );
2205 rA.AddPoint( p2->x, p2->y, POLY_CONTROL );
2206 rA.AddPoint( p3->x, p3->y, POLY_NORMAL );
2207 return 0;
2210 } // extern "C"
2212 // -----------------------------------------------------------------------
2214 bool FreetypeServerFont::GetGlyphOutline( int nGlyphIndex,
2215 ::basegfx::B2DPolyPolygon& rB2DPolyPoly ) const
2217 if( maSizeFT )
2218 pFTActivateSize( maSizeFT );
2220 rB2DPolyPoly.clear();
2222 int nGlyphFlags;
2223 SplitGlyphFlags( *this, nGlyphIndex, nGlyphFlags );
2225 FT_Int nLoadFlags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_TRANSFORM;
2227 #ifdef FT_LOAD_TARGET_LIGHT
2228 // enable "light hinting" if available
2229 if( nFTVERSION >= 2103 )
2230 nLoadFlags |= FT_LOAD_TARGET_LIGHT;
2231 #endif
2233 FT_Error rc = FT_Load_Glyph( maFaceFT, nGlyphIndex, nLoadFlags );
2234 if( rc != FT_Err_Ok )
2235 return false;
2237 if( mbArtBold && pFTEmbolden )
2238 (*pFTEmbolden)( maFaceFT->glyph );
2240 FT_Glyph pGlyphFT;
2241 rc = FT_Get_Glyph( maFaceFT->glyph, &pGlyphFT );
2242 if( rc != FT_Err_Ok )
2243 return false;
2245 if( pGlyphFT->format != FT_GLYPH_FORMAT_OUTLINE )
2246 return false;
2248 if( mbArtItalic )
2250 FT_Matrix aMatrix;
2251 aMatrix.xx = aMatrix.yy = 0x10000L;
2252 if( nFTVERSION >= 2102 ) // Freetype 2.1.2 API swapped xy with yx
2253 aMatrix.xy = 0x6000L, aMatrix.yx = 0;
2254 else
2255 aMatrix.yx = 0x6000L, aMatrix.xy = 0;
2256 FT_Glyph_Transform( pGlyphFT, &aMatrix, NULL );
2259 FT_Outline& rOutline = reinterpret_cast<FT_OutlineGlyphRec*>(pGlyphFT)->outline;
2260 if( !rOutline.n_points ) // blank glyphs are ok
2261 return true;
2263 long nMaxPoints = 1 + rOutline.n_points * 3;
2264 PolyPolygon aToolPolyPolygon;
2265 PolyArgs aPolyArg( aToolPolyPolygon, nMaxPoints );
2267 /*int nAngle =*/ ApplyGlyphTransform( nGlyphFlags, pGlyphFT, false );
2269 FT_Outline_Funcs aFuncs;
2270 aFuncs.move_to = &FT_move_to;
2271 aFuncs.line_to = &FT_line_to;
2272 aFuncs.conic_to = &FT_conic_to;
2273 aFuncs.cubic_to = &FT_cubic_to;
2274 aFuncs.shift = 0;
2275 aFuncs.delta = 0;
2276 rc = FT_Outline_Decompose( &rOutline, &aFuncs, (void*)&aPolyArg );
2277 aPolyArg.ClosePolygon(); // close last polygon
2278 FT_Done_Glyph( pGlyphFT );
2280 // convert to basegfx polypolygon
2281 // TODO: get rid of the intermediate tools polypolygon
2282 rB2DPolyPoly = aToolPolyPolygon.getB2DPolyPolygon();
2283 ::basegfx::B2DHomMatrix aMatrix;
2284 aMatrix.scale( +1.0/(1<<6), -1.0/(1<<6) );
2285 rB2DPolyPoly.transform( aMatrix );
2287 return true;
2290 // -----------------------------------------------------------------------
2292 bool FreetypeServerFont::ApplyGSUB( const ImplFontSelectData& rFSD )
2294 #define MKTAG(s) ((((((s[0]<<8)+s[1])<<8)+s[2])<<8)+s[3])
2296 typedef std::vector<ULONG> ReqFeatureTagList;
2297 ReqFeatureTagList aReqFeatureTagList;
2298 if( rFSD.mbVertical )
2299 aReqFeatureTagList.push_back( MKTAG("vert") );
2300 ULONG nRequestedScript = 0; //MKTAG("hani");//### TODO: where to get script?
2301 ULONG nRequestedLangsys = 0; //MKTAG("ZHT"); //### TODO: where to get langsys?
2302 // TODO: request more features depending on script and language system
2304 if( aReqFeatureTagList.size() == 0) // nothing to do
2305 return true;
2307 // load GSUB table into memory
2308 ULONG nLength = 0;
2309 const FT_Byte* const pGsubBase = mpFontInfo->GetTable( "GSUB", &nLength );
2310 if( !pGsubBase )
2311 return false;
2313 // parse GSUB header
2314 const FT_Byte* pGsubHeader = pGsubBase;
2315 const USHORT nOfsScriptList = GetUShort( pGsubHeader+4 );
2316 const USHORT nOfsFeatureTable = GetUShort( pGsubHeader+6 );
2317 const USHORT nOfsLookupList = GetUShort( pGsubHeader+8 );
2318 pGsubHeader += 10;
2320 typedef std::vector<USHORT> UshortList;
2321 UshortList aFeatureIndexList;
2322 UshortList aFeatureOffsetList;
2324 // parse Script Table
2325 const FT_Byte* pScriptHeader = pGsubBase + nOfsScriptList;
2326 const USHORT nCntScript = GetUShort( pScriptHeader+0 );
2327 pScriptHeader += 2;
2328 for( USHORT nScriptIndex = 0; nScriptIndex < nCntScript; ++nScriptIndex )
2330 const ULONG nScriptTag = GetUInt( pScriptHeader+0 ); // e.g. hani/arab/kana/hang
2331 const USHORT nOfsScriptTable= GetUShort( pScriptHeader+4 );
2332 pScriptHeader += 6; //###
2333 if( (nScriptTag != nRequestedScript) && (nRequestedScript != 0) )
2334 continue;
2336 const FT_Byte* pScriptTable = pGsubBase + nOfsScriptList + nOfsScriptTable;
2337 const USHORT nDefaultLangsysOfs = GetUShort( pScriptTable+0 );
2338 const USHORT nCntLangSystem = GetUShort( pScriptTable+2 );
2339 pScriptTable += 4;
2340 USHORT nLangsysOffset = 0;
2342 for( USHORT nLangsysIndex = 0; nLangsysIndex < nCntLangSystem; ++nLangsysIndex )
2344 const ULONG nTag = GetUInt( pScriptTable+0 ); // e.g. KOR/ZHS/ZHT/JAN
2345 const USHORT nOffset= GetUShort( pScriptTable+4 );
2346 pScriptTable += 6;
2347 if( (nTag != nRequestedLangsys) && (nRequestedLangsys != 0) )
2348 continue;
2349 nLangsysOffset = nOffset;
2350 break;
2353 if( (nDefaultLangsysOfs != 0) && (nDefaultLangsysOfs != nLangsysOffset) )
2355 const FT_Byte* pLangSys = pGsubBase + nOfsScriptList + nOfsScriptTable + nDefaultLangsysOfs;
2356 const USHORT nReqFeatureIdx = GetUShort( pLangSys+2 );
2357 const USHORT nCntFeature = GetUShort( pLangSys+4 );
2358 pLangSys += 6;
2359 aFeatureIndexList.push_back( nReqFeatureIdx );
2360 for( USHORT i = 0; i < nCntFeature; ++i )
2362 const USHORT nFeatureIndex = GetUShort( pLangSys );
2363 pLangSys += 2;
2364 aFeatureIndexList.push_back( nFeatureIndex );
2368 if( nLangsysOffset != 0 )
2370 const FT_Byte* pLangSys = pGsubBase + nOfsScriptList + nOfsScriptTable + nLangsysOffset;
2371 const USHORT nReqFeatureIdx = GetUShort( pLangSys+2 );
2372 const USHORT nCntFeature = GetUShort( pLangSys+4 );
2373 pLangSys += 6;
2374 aFeatureIndexList.push_back( nReqFeatureIdx );
2375 for( USHORT i = 0; i < nCntFeature; ++i )
2377 const USHORT nFeatureIndex = GetUShort( pLangSys );
2378 pLangSys += 2;
2379 aFeatureIndexList.push_back( nFeatureIndex );
2384 if( !aFeatureIndexList.size() )
2385 return true;
2387 UshortList aLookupIndexList;
2388 UshortList aLookupOffsetList;
2390 // parse Feature Table
2391 const FT_Byte* pFeatureHeader = pGsubBase + nOfsFeatureTable;
2392 const USHORT nCntFeature = GetUShort( pFeatureHeader );
2393 pFeatureHeader += 2;
2394 for( USHORT nFeatureIndex = 0; nFeatureIndex < nCntFeature; ++nFeatureIndex )
2396 const ULONG nTag = GetUInt( pFeatureHeader+0 ); // e.g. locl/vert/trad/smpl/liga/fina/...
2397 const USHORT nOffset= GetUShort( pFeatureHeader+4 );
2398 pFeatureHeader += 6;
2400 // short circuit some feature lookups
2401 if( aFeatureIndexList[0] != nFeatureIndex ) // required feature?
2403 const int nRequested = std::count( aFeatureIndexList.begin(), aFeatureIndexList.end(), nFeatureIndex);
2404 if( !nRequested ) // ignore features that are not requested
2405 continue;
2406 const int nAvailable = std::count( aReqFeatureTagList.begin(), aReqFeatureTagList.end(), nTag);
2407 if( !nAvailable ) // some fonts don't provide features they request!
2408 continue;
2411 const FT_Byte* pFeatureTable = pGsubBase + nOfsFeatureTable + nOffset;
2412 const USHORT nCntLookups = GetUShort( pFeatureTable+0 );
2413 pFeatureTable += 2;
2414 for( USHORT i = 0; i < nCntLookups; ++i )
2416 const USHORT nLookupIndex = GetUShort( pFeatureTable );
2417 pFeatureTable += 2;
2418 aLookupIndexList.push_back( nLookupIndex );
2420 if( nCntLookups == 0 ) //### hack needed by Mincho/Gothic/Mingliu/Simsun/...
2421 aLookupIndexList.push_back( 0 );
2424 // parse Lookup List
2425 const FT_Byte* pLookupHeader = pGsubBase + nOfsLookupList;
2426 const USHORT nCntLookupTable = GetUShort( pLookupHeader );
2427 pLookupHeader += 2;
2428 for( USHORT nLookupIdx = 0; nLookupIdx < nCntLookupTable; ++nLookupIdx )
2430 const USHORT nOffset = GetUShort( pLookupHeader );
2431 pLookupHeader += 2;
2432 if( std::count( aLookupIndexList.begin(), aLookupIndexList.end(), nLookupIdx ) )
2433 aLookupOffsetList.push_back( nOffset );
2436 UshortList::const_iterator lookup_it = aLookupOffsetList.begin();
2437 for(; lookup_it != aLookupOffsetList.end(); ++lookup_it )
2439 const USHORT nOfsLookupTable = *lookup_it;
2440 const FT_Byte* pLookupTable = pGsubBase + nOfsLookupList + nOfsLookupTable;
2441 const USHORT eLookupType = GetUShort( pLookupTable+0 );
2442 const USHORT nCntLookupSubtable = GetUShort( pLookupTable+4 );
2443 pLookupTable += 6;
2445 // TODO: switch( eLookupType )
2446 if( eLookupType != 1 ) // TODO: once we go beyond SingleSubst
2447 continue;
2449 for( USHORT nSubTableIdx = 0; nSubTableIdx < nCntLookupSubtable; ++nSubTableIdx )
2451 const USHORT nOfsSubLookupTable = GetUShort( pLookupTable );
2452 pLookupTable += 2;
2453 const FT_Byte* pSubLookup = pGsubBase + nOfsLookupList + nOfsLookupTable + nOfsSubLookupTable;
2455 const USHORT nFmtSubstitution = GetUShort( pSubLookup+0 );
2456 const USHORT nOfsCoverage = GetUShort( pSubLookup+2 );
2457 pSubLookup += 4;
2459 typedef std::pair<USHORT,USHORT> GlyphSubst;
2460 typedef std::vector<GlyphSubst> SubstVector;
2461 SubstVector aSubstVector;
2463 const FT_Byte* pCoverage = pGsubBase + nOfsLookupList + nOfsLookupTable + nOfsSubLookupTable + nOfsCoverage;
2464 const USHORT nFmtCoverage = GetUShort( pCoverage+0 );
2465 pCoverage += 2;
2466 switch( nFmtCoverage )
2468 case 1: // Coverage Format 1
2470 const USHORT nCntGlyph = GetUShort( pCoverage );
2471 pCoverage += 2;
2472 aSubstVector.reserve( nCntGlyph );
2473 for( USHORT i = 0; i < nCntGlyph; ++i )
2475 const USHORT nGlyphId = GetUShort( pCoverage );
2476 pCoverage += 2;
2477 aSubstVector.push_back( GlyphSubst( nGlyphId, 0 ) );
2480 break;
2482 case 2: // Coverage Format 2
2484 const USHORT nCntRange = GetUShort( pCoverage );
2485 pCoverage += 2;
2486 for( int i = nCntRange; --i >= 0; )
2488 const USHORT nGlyph0 = GetUShort( pCoverage+0 );
2489 const USHORT nGlyph1 = GetUShort( pCoverage+2 );
2490 const USHORT nCovIdx = GetUShort( pCoverage+4 );
2491 pCoverage += 6;
2492 for( USHORT j = nGlyph0; j <= nGlyph1; ++j )
2493 aSubstVector.push_back( GlyphSubst( j + nCovIdx, 0 ) );
2496 break;
2499 SubstVector::iterator it( aSubstVector.begin() );
2501 switch( nFmtSubstitution )
2503 case 1: // Single Substitution Format 1
2505 const USHORT nDeltaGlyphId = GetUShort( pSubLookup );
2506 pSubLookup += 2;
2507 for(; it != aSubstVector.end(); ++it )
2508 (*it).second = (*it).first + nDeltaGlyphId;
2510 break;
2512 case 2: // Single Substitution Format 2
2514 const USHORT nCntGlyph = GetUShort( pSubLookup );
2515 pSubLookup += 2;
2516 for( int i = nCntGlyph; (it != aSubstVector.end()) && (--i>=0); ++it )
2518 const USHORT nGlyphId = GetUShort( pSubLookup );
2519 pSubLookup += 2;
2520 (*it).second = nGlyphId;
2523 break;
2526 DBG_ASSERT( (it == aSubstVector.end()), "lookup<->coverage table mismatch" );
2527 // now apply the glyph substitutions that have been collected in this subtable
2528 for( it = aSubstVector.begin(); it != aSubstVector.end(); ++it )
2529 maGlyphSubstitution[ (*it).first ] = (*it).second;
2533 return true;
2536 // =======================================================================