1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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"
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"
52 #include FT_FREETYPE_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
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
69 #define FTVERSION (1000*FREETYPE_MAJOR + 100*FREETYPE_MINOR + FREETYPE_PATCH)
72 typedef const FT_Vector
* FT_Vector_CPtr
;
73 #else // FTVERSION < 2200
74 typedef FT_Vector
* FT_Vector_CPtr
;
79 // TODO: move file mapping stuff to OSL
82 // PORTERS: dlfcn is used for code dependend on FT version
89 #include "vcl/fontmanager.hxx"
92 #define strncasecmp strnicmp
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;
117 for( x
= 0; x
< 256; x
++)
120 a
= ( x
* M_Y
+ M_X
/ 2) / M_X
;
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 // =======================================================================
160 // =======================================================================
162 FtFontFile::FtFontFile( const ::rtl::OString
& rNativeFileName
)
163 : maNativeFileName( rNativeFileName
),
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
175 static const char* pLangBoost
= NULL
;
176 static bool bOnce
= true;
180 LanguageType aLang
= Application::GetSettings().GetUILanguage();
183 case LANGUAGE_JAPANESE
:
186 case LANGUAGE_CHINESE
:
187 case LANGUAGE_CHINESE_SIMPLIFIED
:
188 case LANGUAGE_CHINESE_SINGAPORE
:
191 case LANGUAGE_CHINESE_TRADITIONAL
:
192 case LANGUAGE_CHINESE_HONGKONG
:
193 case LANGUAGE_CHINESE_MACAU
:
196 case LANGUAGE_KOREAN
:
197 case LANGUAGE_KOREAN_JOHAB
:
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() )
219 // no => create new one
220 FtFontFile
* pFontFile
= new FtFontFile( rNativeFileName
);
221 pFileName
= pFontFile
->maNativeFileName
.getStr();
222 rFontFileList
[ pFileName
] = pFontFile
;
226 // -----------------------------------------------------------------------
228 bool FtFontFile::Map()
230 if( mnRefCount
++ <= 0 )
232 const char* pFileName
= maNativeFileName
.getStr();
234 int nFile
= open( pFileName
, O_RDONLY
);
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
)
247 void* pFileDesc
= ::CreateFile( pFileName
, GENERIC_READ
, FILE_SHARE_READ
,
248 NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, 0 );
249 if( pFileDesc
== INVALID_HANDLE_VALUE
)
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
);
257 FILE* pFile
= fopen( pFileName
, "rb" );
262 stat( pFileName
, &aStat
);
263 mnFileSize
= aStat
.st_size
;
264 mpFileMap
= new unsigned char[ mnFileSize
];
265 if( mnFileSize
!= fread( mpFileMap
, 1, mnFileSize
, pFile
) )
274 return (mpFileMap
!= NULL
);
277 // -----------------------------------------------------------------------
279 void FtFontFile::Unmap()
281 if( (--mnRefCount
> 0) || (mpFileMap
== NULL
) )
285 munmap( (char*)mpFileMap
, mnFileSize
);
287 UnmapViewOfFile( (LPCVOID
)mpFileMap
);
295 // =======================================================================
297 FtFontInfo::FtFontInfo( const ImplDevFontAttributes
& rDevFontAttributes
,
298 const ::rtl::OString
& rNativeFileName
, int nFaceNum
, sal_IntPtr nFontId
, int nSynthetic
,
299 const ExtraKernInfo
* pExtraKernInfo
)
302 mpFontFile( FtFontFile::FindFontFile( rNativeFileName
) ),
303 mnFaceNum( nFaceNum
),
305 mnSynthetic( nSynthetic
),
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
318 maDevFontAttributes
.mnQuality
+= 100;
321 // -----------------------------------------------------------------------
323 FtFontInfo::~FtFontInfo()
325 delete mpExtraKernInfo
;
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() )
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) )
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
);
369 // -----------------------------------------------------------------------
371 bool FtFontInfo::HasExtraKerning() const
373 if( !mpExtraKernInfo
)
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();
381 // -----------------------------------------------------------------------
383 int FtFontInfo::GetExtraKernPairs( ImplKernPairData
** ppKernPairs
) const
385 if( !mpExtraKernInfo
)
387 return mpExtraKernInfo
->GetUnscaledKernPairs( ppKernPairs
);
390 // -----------------------------------------------------------------------
392 int FtFontInfo::GetExtraGlyphKernValue( int nLeftGlyph
, int nRightGlyph
) const
394 if( !mpExtraKernInfo
)
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 )
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
426 // walk table directory until match
427 int nTables
= GetUShort( p
- 8 );
428 if( nTables
>= 64 ) // something fishy?
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
)
437 const unsigned char* pTable
= pBuffer
+ GetUInt( p
+ 8 );
438 if( (pTable
+ nLength
) <= (mpFontFile
->GetBuffer() + nFileSize
) )
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 )
492 #else // RTLD_DEFAULT
493 // assume systems where dlsym is not possible use supplied library
494 nFTVERSION
= FTVERSION
;
497 // TODO: remove when the priorities are selected by UI
499 pEnv
= ::getenv( "SAL_EMBEDDED_BITMAP_PRIORITY" );
501 nDefaultPrioEmbedded
= pEnv
[0] - '0';
502 pEnv
= ::getenv( "SAL_ANTIALIASED_TEXT_PRIORITY" );
504 nDefaultPrioAntiAlias
= pEnv
[0] - '0';
505 pEnv
= ::getenv( "SAL_AUTOHINTING_PRIORITY" );
507 nDefaultPrioAutoHint
= pEnv
[0] - '0';
512 // -----------------------------------------------------------------------
514 void* FreetypeServerFont::GetFtFace() const
517 pFTActivateSize( maSizeFT
);
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() )
541 if( maFontList
.find( nFontId
) != maFontList
.end() )
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
)
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
) )
582 if( !FT_IS_SCALABLE( aFaceFT
) ) // ignore non-scalabale fonts
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
)
604 if( (aCM
->platform_id
== TT_PLATFORM_MICROSOFT
)
605 && (aCM
->encoding_id
== TT_MS_ID_SYMBOL_CS
) )
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
;
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
);
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
;
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
;
674 FreetypeServerFont
* pNew
= new FreetypeServerFont( rFSD
, pFontInfo
);
679 // =======================================================================
681 ImplFTSFontData::ImplFTSFontData( FtFontInfo
* pFI
, const ImplDevFontAttributes
& rDFA
)
682 : ImplFontData( rDFA
, IFTSFONT_MAGIC
),
686 mbOrientation
= true;
689 // -----------------------------------------------------------------------
691 ImplFontEntry
* ImplFTSFontData::CreateFontInstance( ImplFontSelectData
& rFSD
) const
693 ImplServerFontEntry
* pEntry
= new ImplServerFontEntry( rFSD
);
697 // =======================================================================
698 // FreetypeServerFont
699 // =======================================================================
701 FreetypeServerFont::FreetypeServerFont( const ImplFontSelectData
& rFSD
, FtFontInfo
* pFI
)
702 : ServerFont( rFSD
),
703 mnPrioEmbedded(nDefaultPrioEmbedded
),
704 mnPrioAntiAlias(nDefaultPrioAntiAlias
),
709 maRecodeConverter( NULL
),
710 mpLayoutEngine( NULL
)
712 maFaceFT
= pFI
->GetFaceFT();
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 );
722 // set the pixel size of the font instance
723 mnWidth
= rFSD
.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) )
731 // perf: use maSizeFT if available
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
)
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
;
748 if( FT_IS_SFNT( maFaceFT
) )
749 eEncoding
= ft_encoding_symbol
;
751 eEncoding
= FT_ENCODING_ADOBE_CUSTOM
; // freetype wants this for PS symbol fonts
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
)
767 eEncoding
= FT_ENCODING_SJIS
;
768 eRecodeFrom
= RTL_TEXTENCODING_SHIFT_JIS
;
770 case TT_MS_ID_GB2312
:
771 eEncoding
= FT_ENCODING_GB2312
;
772 eRecodeFrom
= RTL_TEXTENCODING_GB_2312
;
775 eEncoding
= FT_ENCODING_BIG5
;
776 eRecodeFrom
= RTL_TEXTENCODING_BIG5
;
778 case TT_MS_ID_WANSUNG
:
779 eEncoding
= FT_ENCODING_WANSUNG
;
780 eRecodeFrom
= RTL_TEXTENCODING_MS_949
;
783 eEncoding
= FT_ENCODING_JOHAB
;
784 eRecodeFrom
= RTL_TEXTENCODING_MS_1361
;
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
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
;
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
818 if( FT_Err_Ok
!= FT_Select_Charmap( maFaceFT
, eEncoding
) )
821 if( eRecodeFrom
!= RTL_TEXTENCODING_UNICODE
)
822 maRecodeConverter
= rtl_createUnicodeToTextConverter( eRecodeFrom
);
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
;
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)
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())
862 if (mpFontInfo
->DontUseEmbeddedBitmaps())
865 #if (FTVERSION >= 2005) || defined(TT_CONFIG_OPTION_BYTECODE_INTERPRETER)
866 if( nDefaultPrioAutoHint
<= 0 )
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
;
876 if( ((mnCos
!= 0) && (mnSin
!= 0)) || (mnPrioEmbedded
<= 0) )
877 mnLoadFlags
|= FT_LOAD_NO_BITMAP
;
880 // -----------------------------------------------------------------------
882 bool FreetypeServerFont::TestFont() const
887 // -----------------------------------------------------------------------
889 FreetypeServerFont::~FreetypeServerFont()
892 delete mpLayoutEngine
;
894 if( maRecodeConverter
)
895 rtl_destroyUnicodeToTextConverter( maRecodeConverter
);
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;
918 rTo
.mbKernableFont
= (FT_HAS_KERNING( maFaceFT
) != 0) || mpFontInfo
->HasExtraKerning();
919 rTo
.mnOrientation
= GetFontSelData().mnOrientation
;
921 //Always consider [star]symbol as symbol fonts
923 (rTo
.GetFamilyName().EqualsAscii("OpenSymbol")) ||
924 (rTo
.GetFamilyName().EqualsAscii("StarSymbol"))
927 rTo
.mbSymbolFlag
= true;
931 pFTActivateSize( maSizeFT
);
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;
942 rTo
.mnDescent
= (-rMetrics
.descender
+ 32) >> 6;
944 rTo
.mnIntLeading
= ((rMetrics
.height
+ 32) >> 6) - (rTo
.mnAscent
+ rTo
.mnDescent
);
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
-
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
;
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
)
1065 const FT_Size_Metrics
& rMetrics
= maFaceFT
->size
->metrics
;
1069 bool bStretched
= false;
1071 switch( nGlyphFlags
& GF_ROTMASK
)
1073 default: // straight
1076 aMatrix
.xx
= +mnCos
;
1077 aMatrix
.yy
= +mnCos
;
1078 aMatrix
.xy
= -mnSin
;
1079 aMatrix
.yx
= +mnSin
;
1081 case GF_ROTL
: // left
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
);
1091 case GF_ROTR
: // right
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
);
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
;
1122 // apply non-orthogonal or stretch transformations
1123 FT_Glyph_Transform( pGlyphFT
, &aMatrix
, NULL
);
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;
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 )
1153 // if needed recode from unicode to font encoding
1154 if( maRecodeConverter
)
1156 sal_Char aTempArray
[8];
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 )
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
);
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
);
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
1192 nGlyphIndex
= psp::PrintFontManager::get().FreeTypeCharIndex( maFaceFT
, aChar
);
1195 mpFontInfo
->CacheGlyphIndex( aChar
, 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
);
1221 nGlyphFlags
|= GetVerticalFlags( aChar
);
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
;
1240 if( nGlyphIndex
!= 0 )
1241 nGlyphIndex
|= nGlyphFlags
;
1247 // -----------------------------------------------------------------------
1249 int FreetypeServerFont::GetGlyphIndex( sal_UCS4 aChar
) const
1251 int nGlyphIndex
= GetRawGlyphIndex( aChar
);
1252 nGlyphIndex
= FixupGlyphIndex( nGlyphIndex
, aChar
);
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
);
1268 nCharWidth
= (int)((rMetrics
.height
+ rMetrics
.descender
) * fStretch
);
1272 return (nCharWidth
+ 32) >> 6;
1275 // -----------------------------------------------------------------------
1277 void FreetypeServerFont::InitGlyphData( int nGlyphIndex
, GlyphData
& rGD
) const
1280 pFTActivateSize( maSizeFT
);
1283 SplitGlyphFlags( *this, nGlyphIndex
, nGlyphFlags
);
1285 int nLoadFlags
= mnLoadFlags
;
1287 // if( mbArtItalic )
1288 // nLoadFlags |= FT_LOAD_NO_BITMAP;
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
)
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 ) );
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
);
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) );
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) )
1350 bool bAdviseAA
= true;
1351 // TODO: also use GASP info
1355 // -----------------------------------------------------------------------
1357 bool FreetypeServerFont::GetGlyphBitmap1( int nGlyphIndex
, RawBitmap
& rRawBitmap
) const
1360 pFTActivateSize( maSizeFT
);
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
;
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
;
1383 if( mnPrioEmbedded
<= nDefaultPrioAutoHint
)
1384 nLoadFlags
|= FT_LOAD_NO_BITMAP
;
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
)
1400 rc
= FT_Load_Glyph( maFaceFT
, nGlyphIndex
, nLoadFlags
);
1401 if( rc
!= FT_Err_Ok
)
1404 if( mbArtBold
&& pFTEmbolden
)
1405 (*pFTEmbolden
)( maFaceFT
->glyph
);
1408 rc
= FT_Get_Glyph( maFaceFT
->glyph
, &pGlyphFT
);
1409 if( rc
!= FT_Err_Ok
)
1412 int nAngle
= ApplyGlyphTransform( nGlyphFlags
, pGlyphFT
, true );
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;
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.
1429 FT_Glyph_Get_CBox(pGlyphFT
, ft_glyph_bbox_unscaled
, &cbox
);
1431 if( (cbox
.xMax
- cbox
.xMin
) == 0 || (cbox
.yMax
- cbox
.yMin
== 0) )
1434 memset(&rRawBitmap
, 0, sizeof rRawBitmap
);
1435 FT_Done_Glyph( pGlyphFT
);
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
);
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
;
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
);
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
;
1509 p
+= rRawBitmap
.mnScanlineSize
;
1513 FT_Done_Glyph( pGlyphFT
);
1515 // special case for 0/90/180/270 degree orientation
1522 rRawBitmap
.Rotate( nAngle
);
1529 // -----------------------------------------------------------------------
1531 bool FreetypeServerFont::GetGlyphBitmap8( int nGlyphIndex
, RawBitmap
& rRawBitmap
) const
1534 pFTActivateSize( maSizeFT
);
1537 SplitGlyphFlags( *this, nGlyphIndex
, nGlyphFlags
);
1539 FT_Int nLoadFlags
= mnLoadFlags
;
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
;
1548 if( (nGlyphFlags
& GF_UNHINTED
) || (nDefaultPrioAutoHint
< mnPrioAntiAlias
) )
1549 nLoadFlags
|= FT_LOAD_NO_HINTING
;
1552 if( mnPrioEmbedded
<= mnPrioAntiAlias
)
1553 nLoadFlags
|= FT_LOAD_NO_BITMAP
;
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
)
1569 rc
= FT_Load_Glyph( maFaceFT
, nGlyphIndex
, nLoadFlags
);
1571 if( rc
!= FT_Err_Ok
)
1574 if( mbArtBold
&& pFTEmbolden
)
1575 (*pFTEmbolden
)( maFaceFT
->glyph
);
1578 rc
= FT_Get_Glyph( maFaceFT
->glyph
, &pGlyphFT
);
1579 if( rc
!= FT_Err_Ok
)
1582 int nAngle
= ApplyGlyphTransform( nGlyphFlags
, pGlyphFT
, true );
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;
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
);
1601 rc
= FT_Glyph_To_Bitmap( &pGlyphFT
, FT_RENDER_MODE_NORMAL
, NULL
, TRUE
);
1602 if( rc
!= FT_Err_Ok
)
1604 FT_Done_Glyph( pGlyphFT
);
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
;
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
)
1647 for( int y
= rRawBitmap
.mnHeight
, x
; --y
>= 0 ; )
1649 unsigned char nSrc
= 0;
1650 for( x
= 0; x
< rBitmapFT
.width
; ++x
, nSrc
+=nSrc
)
1654 *(pDest
++) = (0x7F - nSrc
) >> 8;
1656 for(; x
< int(rRawBitmap
.mnScanlineSize
); ++x
)
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
;
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
1700 rRawBitmap
.Rotate( nAngle
);
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
) )
1720 const unsigned char* pCmap
= mpFontInfo
->GetTable( "cmap", &nLength
);
1721 if( pCmap
&& (nLength
> 0) )
1722 if( ParseCMAP( pCmap
, nLength
, rResult
) )
1726 typedef std::vector
<sal_uInt32
> U32Vector
;
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
);; )
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
1743 const int nCount
= aCodes
.size();
1745 if( !rResult
.mbSymbolic
)
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;
1761 // -----------------------------------------------------------------------
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
);
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
1783 pFTActivateSize( maSizeFT
);
1785 // use Freetype's kerning info
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;
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;
1815 // when font faces of different sizes share the same maFaceFT
1816 // then we have to make sure that it uses the correct 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
);
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 )
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 );
1853 if( (nSubCoverage
&0x03) != 0x01 ) // no interest in minimum info here
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 );
1868 aKernGlyphVector
.push_back( aKernPair
);
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 );
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
);
1913 // Apple New style kern table
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
);
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
);
1981 fprintf( stderr
, "gcach_ftyp.cxx: Found unsupported Apple-style kern subtable type %d.\n", nSubTableFormat
);
1987 // now create VCL's ImplKernPairData[] format for all glyph pairs
1988 ULONG nKernCount
= aKernGlyphVector
.size();
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
;
1996 for( sal_Unicode aChar
= 0x0020; aChar
< 0xFFFE; ++aChar
)
1998 USHORT nGlyphIndex
= GetGlyphIndex( aChar
);
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
)
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
) )
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
];
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
;
2046 // -----------------------------------------------------------------------
2048 // -----------------------------------------------------------------------
2053 PolyArgs( PolyPolygon
& rPolyPoly
, USHORT nMaxPoints
);
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
;}
2063 PolyPolygon
& mrPolyPoly
;
2068 FT_Vector maPosition
;
2076 // -----------------------------------------------------------------------
2078 PolyArgs::PolyArgs( PolyPolygon
& rPolyPoly
, USHORT nMaxPoints
)
2079 : mrPolyPoly(rPolyPoly
),
2080 mnMaxPoints(nMaxPoints
),
2085 mpPointAry
= new Point
[ mnMaxPoints
];
2086 mpFlagAry
= new BYTE
[ mnMaxPoints
];
2089 // -----------------------------------------------------------------------
2092 PolyArgs::~PolyArgs()
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
)
2108 mpPointAry
[ mnPoints
] = Point( nX
, nY
);
2109 mpFlagAry
[ mnPoints
++ ]= aFlag
;
2110 bHasOffline
|= (aFlag
!= POLY_NORMAL
);
2113 // -----------------------------------------------------------------------
2115 void PolyArgs::ClosePolygon()
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!" );
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
) );
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.
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());
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
);
2156 bHasOffline
= false;
2159 // -----------------------------------------------------------------------
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
2173 rA
.AddPoint( p0
->x
, p0
->y
, POLY_NORMAL
);
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
);
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
);
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
);
2212 // -----------------------------------------------------------------------
2214 bool FreetypeServerFont::GetGlyphOutline( int nGlyphIndex
,
2215 ::basegfx::B2DPolyPolygon
& rB2DPolyPoly
) const
2218 pFTActivateSize( maSizeFT
);
2220 rB2DPolyPoly
.clear();
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
;
2233 FT_Error rc
= FT_Load_Glyph( maFaceFT
, nGlyphIndex
, nLoadFlags
);
2234 if( rc
!= FT_Err_Ok
)
2237 if( mbArtBold
&& pFTEmbolden
)
2238 (*pFTEmbolden
)( maFaceFT
->glyph
);
2241 rc
= FT_Get_Glyph( maFaceFT
->glyph
, &pGlyphFT
);
2242 if( rc
!= FT_Err_Ok
)
2245 if( pGlyphFT
->format
!= FT_GLYPH_FORMAT_OUTLINE
)
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;
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
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
;
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
);
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
2307 // load GSUB table into memory
2309 const FT_Byte
* const pGsubBase
= mpFontInfo
->GetTable( "GSUB", &nLength
);
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 );
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 );
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) )
2336 const FT_Byte
* pScriptTable
= pGsubBase
+ nOfsScriptList
+ nOfsScriptTable
;
2337 const USHORT nDefaultLangsysOfs
= GetUShort( pScriptTable
+0 );
2338 const USHORT nCntLangSystem
= GetUShort( pScriptTable
+2 );
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 );
2347 if( (nTag
!= nRequestedLangsys
) && (nRequestedLangsys
!= 0) )
2349 nLangsysOffset
= nOffset
;
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 );
2359 aFeatureIndexList
.push_back( nReqFeatureIdx
);
2360 for( USHORT i
= 0; i
< nCntFeature
; ++i
)
2362 const USHORT nFeatureIndex
= GetUShort( pLangSys
);
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 );
2374 aFeatureIndexList
.push_back( nReqFeatureIdx
);
2375 for( USHORT i
= 0; i
< nCntFeature
; ++i
)
2377 const USHORT nFeatureIndex
= GetUShort( pLangSys
);
2379 aFeatureIndexList
.push_back( nFeatureIndex
);
2384 if( !aFeatureIndexList
.size() )
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
2406 const int nAvailable
= std::count( aReqFeatureTagList
.begin(), aReqFeatureTagList
.end(), nTag
);
2407 if( !nAvailable
) // some fonts don't provide features they request!
2411 const FT_Byte
* pFeatureTable
= pGsubBase
+ nOfsFeatureTable
+ nOffset
;
2412 const USHORT nCntLookups
= GetUShort( pFeatureTable
+0 );
2414 for( USHORT i
= 0; i
< nCntLookups
; ++i
)
2416 const USHORT nLookupIndex
= GetUShort( pFeatureTable
);
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
);
2428 for( USHORT nLookupIdx
= 0; nLookupIdx
< nCntLookupTable
; ++nLookupIdx
)
2430 const USHORT nOffset
= GetUShort( pLookupHeader
);
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 );
2445 // TODO: switch( eLookupType )
2446 if( eLookupType
!= 1 ) // TODO: once we go beyond SingleSubst
2449 for( USHORT nSubTableIdx
= 0; nSubTableIdx
< nCntLookupSubtable
; ++nSubTableIdx
)
2451 const USHORT nOfsSubLookupTable
= GetUShort( pLookupTable
);
2453 const FT_Byte
* pSubLookup
= pGsubBase
+ nOfsLookupList
+ nOfsLookupTable
+ nOfsSubLookupTable
;
2455 const USHORT nFmtSubstitution
= GetUShort( pSubLookup
+0 );
2456 const USHORT nOfsCoverage
= GetUShort( pSubLookup
+2 );
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 );
2466 switch( nFmtCoverage
)
2468 case 1: // Coverage Format 1
2470 const USHORT nCntGlyph
= GetUShort( pCoverage
);
2472 aSubstVector
.reserve( nCntGlyph
);
2473 for( USHORT i
= 0; i
< nCntGlyph
; ++i
)
2475 const USHORT nGlyphId
= GetUShort( pCoverage
);
2477 aSubstVector
.push_back( GlyphSubst( nGlyphId
, 0 ) );
2482 case 2: // Coverage Format 2
2484 const USHORT nCntRange
= GetUShort( pCoverage
);
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 );
2492 for( USHORT j
= nGlyph0
; j
<= nGlyph1
; ++j
)
2493 aSubstVector
.push_back( GlyphSubst( j
+ nCovIdx
, 0 ) );
2499 SubstVector::iterator
it( aSubstVector
.begin() );
2501 switch( nFmtSubstitution
)
2503 case 1: // Single Substitution Format 1
2505 const USHORT nDeltaGlyphId
= GetUShort( pSubLookup
);
2507 for(; it
!= aSubstVector
.end(); ++it
)
2508 (*it
).second
= (*it
).first
+ nDeltaGlyphId
;
2512 case 2: // Single Substitution Format 2
2514 const USHORT nCntGlyph
= GetUShort( pSubLookup
);
2516 for( int i
= nCntGlyph
; (it
!= aSubstVector
.end()) && (--i
>=0); ++it
)
2518 const USHORT nGlyphId
= GetUShort( pSubLookup
);
2520 (*it
).second
= nGlyphId
;
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
;
2536 // =======================================================================