fdo#74697 Add Bluez 5 support for impress remote.
[LibreOffice.git] / vcl / generic / glyphs / gcach_ftyp.cxx
blob854433bbbcf5ece3222df5810e764b0f5a20702b
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #ifdef WNT
22 #include <svsys.h>
23 #undef CreateFont
24 #endif
26 #include "gcach_ftyp.hxx"
28 #include "vcl/svapp.hxx"
29 #include <outfont.hxx>
30 #include <impfont.hxx>
31 #include <config_graphite.h>
32 #if ENABLE_GRAPHITE
33 #include <graphite2/Font.h>
34 #include <graphite_layout.hxx>
35 #endif
37 #include "tools/poly.hxx"
38 #include "basegfx/matrix/b2dhommatrix.hxx"
39 #include "basegfx/matrix/b2dhommatrixtools.hxx"
40 #include "basegfx/polygon/b2dpolypolygon.hxx"
42 #include "osl/file.hxx"
43 #include "osl/thread.hxx"
45 #include "langboost.hxx"
46 #include "sft.hxx"
48 #include <ft2build.h>
49 #include FT_FREETYPE_H
50 #include FT_GLYPH_H
51 #include FT_OUTLINE_H
52 #include FT_TRUETYPE_TABLES_H
53 #include FT_TRUETYPE_TAGS_H
54 #include FT_TRUETYPE_IDS_H
56 #ifdef ANDROID
57 #include FT_SIZES_H
58 #include FT_SYNTHESIS_H
59 #endif
61 #ifndef FT_RENDER_MODE_MONO // happens in the MACOSX build
62 #define FT_RENDER_MODE_MONO ft_render_mode_mono
63 #endif
64 #include "rtl/instance.hxx"
66 #define FTVERSION (1000*FREETYPE_MAJOR + 100*FREETYPE_MINOR + FREETYPE_PATCH)
68 #if FTVERSION >= 2200
69 typedef const FT_Vector* FT_Vector_CPtr;
70 #else // FTVERSION < 2200
71 typedef FT_Vector* FT_Vector_CPtr;
72 #endif
74 #include <vector>
76 // TODO: move file mapping stuff to OSL
77 #if defined(UNX)
78 // PORTERS: dlfcn is used for getting symbols from FT versions newer than baseline
79 #include <dlfcn.h>
80 #include <unistd.h>
81 #include <fcntl.h>
82 #include <sys/stat.h>
83 #include <sys/mman.h>
84 #include "vcl/fontmanager.hxx"
85 #elif defined(WNT)
86 #include <io.h>
87 #define strncasecmp strnicmp
88 #endif
90 typedef const unsigned char* CPU8;
91 inline sal_uInt16 NEXT_U16( CPU8& p ) { p+=2; return (p[-2]<<8)|p[-1]; }
92 inline sal_Int16 NEXT_S16( CPU8& p ) { return (sal_Int16)NEXT_U16(p); }
93 inline sal_uInt32 NEXT_U32( CPU8& p ) { p+=4; return (p[-4]<<24)|(p[-3]<<16)|(p[-2]<<8)|p[-1]; }
94 //inline sal_Int32 NEXT_S32( U8*& p ) { return (sal_Int32)NEXT_U32(p); }
96 // -----------------------------------------------------------------------
98 // the gamma table makes artificial bold look better for CJK glyphs
99 static unsigned char aGammaTable[257];
101 static void InitGammaTable()
103 static const int M_MAX = 255;
104 static const int M_X = 128;
105 static const int M_Y = 208;
107 int x, a;
108 for( x = 0; x < 256; x++)
110 if ( x <= M_X )
111 a = ( x * M_Y + M_X / 2) / M_X;
112 else
113 a = M_Y + ( ( x - M_X ) * ( M_MAX - M_Y ) +
114 ( M_MAX - M_X ) / 2 ) / ( M_MAX - M_X );
116 aGammaTable[x] = (unsigned char)a;
120 // -----------------------------------------------------------------------
122 static FT_Library aLibFT = 0;
124 // #110607# enable linking with old FT versions
125 static int nFTVERSION = 0;
126 static FT_Error (*pFTNewSize)(FT_Face,FT_Size*);
127 static FT_Error (*pFTActivateSize)(FT_Size);
128 static FT_Error (*pFTDoneSize)(FT_Size);
129 void (*pFTEmbolden)(FT_GlyphSlot);
130 static FT_UInt (*pFT_Face_GetCharVariantIndex)(FT_Face, FT_ULong, FT_ULong);
131 static bool bEnableSizeFT = false;
133 typedef ::boost::unordered_map<const char*, boost::shared_ptr<FtFontFile>, rtl::CStringHash, rtl::CStringEqual> FontFileList;
135 namespace { struct vclFontFileList : public rtl::Static< FontFileList, vclFontFileList > {}; }
137 // -----------------------------------------------------------------------
139 // TODO: remove when the priorities are selected by UI
140 // if (AH==0) => disable autohinting
141 // if (AA==0) => disable antialiasing
142 // if (EB==0) => disable embedded bitmaps
143 // if (AA prio <= AH prio) => antialias + autohint
144 // if (AH<AA) => do not autohint when antialiasing
145 // if (EB<AH) => do not autohint for monochrome
146 static int nDefaultPrioEmbedded = 2;
147 static int nDefaultPrioAutoHint = 1;
148 static int nDefaultPrioAntiAlias = 1;
150 // =======================================================================
151 // FreetypeManager
152 // =======================================================================
154 FtFontFile::FtFontFile( const OString& rNativeFileName )
155 : maNativeFileName( rNativeFileName ),
156 mpFileMap( NULL ),
157 mnFileSize( 0 ),
158 mnRefCount( 0 ),
159 mnLangBoost( 0 )
161 // boost font preference if UI language is mentioned in filename
162 int nPos = maNativeFileName.lastIndexOf( '_' );
163 if( nPos == -1 || maNativeFileName[nPos+1] == '.' )
164 mnLangBoost += 0x1000; // no langinfo => good
165 else
167 static const char* pLangBoost = NULL;
168 static bool bOnce = true;
169 if( bOnce )
171 bOnce = false;
172 pLangBoost = vcl::getLangBoost();
175 if( pLangBoost && !strncasecmp( pLangBoost, &maNativeFileName.getStr()[nPos+1], 3 ) )
176 mnLangBoost += 0x2000; // matching langinfo => better
180 // -----------------------------------------------------------------------
182 FtFontFile* FtFontFile::FindFontFile( const OString& rNativeFileName )
184 // font file already known? (e.g. for ttc, synthetic, aliased fonts)
185 const char* pFileName = rNativeFileName.getStr();
186 FontFileList &rFontFileList = vclFontFileList::get();
187 FontFileList::const_iterator it = rFontFileList.find( pFileName );
188 if( it != rFontFileList.end() )
189 return it->second.get();
191 // no => create new one
192 FtFontFile* pFontFile = new FtFontFile( rNativeFileName );
193 pFileName = pFontFile->maNativeFileName.getStr();
194 rFontFileList[pFileName].reset(pFontFile);
195 return pFontFile;
198 // -----------------------------------------------------------------------
200 bool FtFontFile::Map()
202 if( mnRefCount++ <= 0 )
204 const char* pFileName = maNativeFileName.getStr();
205 #if defined(UNX)
206 int nFile = open( pFileName, O_RDONLY );
207 if( nFile < 0 )
208 return false;
210 struct stat aStat;
211 fstat( nFile, &aStat );
212 mnFileSize = aStat.st_size;
213 mpFileMap = (const unsigned char*)
214 mmap( NULL, mnFileSize, PROT_READ, MAP_SHARED, nFile, 0 );
215 if( mpFileMap == MAP_FAILED )
216 mpFileMap = NULL;
217 close( nFile );
218 #elif defined(WNT)
219 void* pFileDesc = ::CreateFile( pFileName, GENERIC_READ, FILE_SHARE_READ,
220 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 );
221 if( pFileDesc == INVALID_HANDLE_VALUE)
222 return false;
224 mnFileSize = ::GetFileSize( pFileDesc, NULL );
225 HANDLE aHandle = ::CreateFileMapping( pFileDesc, NULL, PAGE_READONLY, 0, mnFileSize, "TTF" );
226 mpFileMap = (const unsigned char*)::MapViewOfFile( aHandle, FILE_MAP_READ, 0, 0, mnFileSize );
227 ::CloseHandle( pFileDesc );
228 #else
229 FILE* pFile = fopen( pFileName, "rb" );
230 if( !pFile )
231 return false;
233 struct stat aStat;
234 stat( pFileName, &aStat );
235 mnFileSize = aStat.st_size;
236 mpFileMap = new unsigned char[ mnFileSize ];
237 if( mnFileSize != fread( mpFileMap, 1, mnFileSize, pFile ) )
239 delete[] mpFileMap;
240 mpFileMap = NULL;
242 fclose( pFile );
243 #endif
246 return (mpFileMap != NULL);
249 // -----------------------------------------------------------------------
251 void FtFontFile::Unmap()
253 if( (--mnRefCount > 0) || (mpFileMap == NULL) )
254 return;
256 #if defined(UNX)
257 munmap( (char*)mpFileMap, mnFileSize );
258 #elif defined(WNT)
259 UnmapViewOfFile( (LPCVOID)mpFileMap );
260 #else
261 delete[] mpFileMap;
262 #endif
264 mpFileMap = NULL;
267 #if ENABLE_GRAPHITE
268 // wrap FtFontInfo's table function
269 const void * graphiteFontTable(const void* appFaceHandle, unsigned int name, size_t *len)
271 const FtFontInfo * pFontInfo = reinterpret_cast<const FtFontInfo*>(appFaceHandle);
272 typedef union {
273 char m_c[5];
274 unsigned int m_id;
275 } TableId;
276 TableId tableId;
277 tableId.m_id = name;
278 #ifndef OSL_BIGENDIAN
279 TableId swapped;
280 swapped.m_c[3] = tableId.m_c[0];
281 swapped.m_c[2] = tableId.m_c[1];
282 swapped.m_c[1] = tableId.m_c[2];
283 swapped.m_c[0] = tableId.m_c[3];
284 tableId.m_id = swapped.m_id;
285 #endif
286 tableId.m_c[4] = '\0';
287 sal_uLong nLength = 0;
288 const void * pTable = static_cast<const void*>(pFontInfo->GetTable(tableId.m_c, &nLength));
289 if (len) *len = static_cast<size_t>(nLength);
290 return pTable;
292 #endif
294 // =======================================================================
296 FtFontInfo::FtFontInfo( const ImplDevFontAttributes& rDevFontAttributes,
297 const OString& rNativeFileName, int nFaceNum, sal_IntPtr nFontId, int nSynthetic,
298 const ExtraKernInfo* pExtraKernInfo )
300 maFaceFT( NULL ),
301 mpFontFile( FtFontFile::FindFontFile( rNativeFileName ) ),
302 mnFaceNum( nFaceNum ),
303 mnRefCount( 0 ),
304 mnSynthetic( nSynthetic ),
305 #if ENABLE_GRAPHITE
306 mbCheckedGraphite(false),
307 mpGraphiteFace(NULL),
308 #endif
309 mnFontId( nFontId ),
310 maDevFontAttributes( rDevFontAttributes ),
311 mpFontCharMap( NULL ),
312 mpChar2Glyph( NULL ),
313 mpGlyph2Char( NULL ),
314 mpExtraKernInfo( pExtraKernInfo )
316 // prefer font with low ID
317 maDevFontAttributes.mnQuality += 10000 - nFontId;
318 // prefer font with matching file names
319 maDevFontAttributes.mnQuality += mpFontFile->GetLangBoost();
320 // prefer font with more external info
321 if( pExtraKernInfo )
322 maDevFontAttributes.mnQuality += 100;
325 // -----------------------------------------------------------------------
327 FtFontInfo::~FtFontInfo()
329 if( mpFontCharMap )
330 mpFontCharMap->DeReference();
331 delete mpExtraKernInfo;
332 delete mpChar2Glyph;
333 delete mpGlyph2Char;
334 #if ENABLE_GRAPHITE
335 delete mpGraphiteFace;
336 #endif
339 void FtFontInfo::InitHashes() const
341 // TODO: avoid pointers when empty stl::hash_* objects become cheap
342 mpChar2Glyph = new Int2IntMap();
343 mpGlyph2Char = new Int2IntMap();
346 // -----------------------------------------------------------------------
348 FT_FaceRec_* FtFontInfo::GetFaceFT()
350 // get faceFT once/multiple depending on availability of SizeFT APIs
351 if( (mnRefCount++ <= 0) || !bEnableSizeFT )
353 if( !mpFontFile->Map() )
354 return NULL;
355 FT_Error rc = FT_New_Memory_Face( aLibFT,
356 (FT_Byte*)mpFontFile->GetBuffer(),
357 mpFontFile->GetFileSize(), mnFaceNum, &maFaceFT );
358 if( (rc != FT_Err_Ok) || (maFaceFT->num_glyphs <= 0) )
359 maFaceFT = NULL;
362 return maFaceFT;
365 #if ENABLE_GRAPHITE
366 GraphiteFaceWrapper * FtFontInfo::GetGraphiteFace()
368 if (mbCheckedGraphite)
369 return mpGraphiteFace;
370 // test for graphite here so that it is cached most efficiently
371 if (GetTable("Silf", 0))
373 static const char* pGraphiteCacheStr = getenv( "SAL_GRAPHITE_CACHE_SIZE" );
374 int graphiteSegCacheSize = pGraphiteCacheStr ? (atoi(pGraphiteCacheStr)) : 0;
375 gr_face * pGraphiteFace;
376 if (graphiteSegCacheSize > 500)
377 pGraphiteFace = gr_make_face_with_seg_cache(this, graphiteFontTable, graphiteSegCacheSize, gr_face_cacheCmap);
378 else
379 pGraphiteFace = gr_make_face(this, graphiteFontTable, gr_face_cacheCmap);
380 if (pGraphiteFace)
381 mpGraphiteFace = new GraphiteFaceWrapper(pGraphiteFace);
383 mbCheckedGraphite = true;
384 return mpGraphiteFace;
386 #endif
388 // -----------------------------------------------------------------------
390 void FtFontInfo::ReleaseFaceFT( FT_FaceRec_* pFaceFT )
392 // release last/each depending on SizeFT availability
393 if( (--mnRefCount <= 0) || !bEnableSizeFT )
395 FT_Done_Face( pFaceFT );
396 maFaceFT = NULL;
397 mpFontFile->Unmap();
401 // -----------------------------------------------------------------------
403 bool FtFontInfo::HasExtraKerning() const
405 if( !mpExtraKernInfo )
406 return false;
407 // TODO: how to enable the line below without getting #i29881# back?
408 // on the other hand being too optimistic doesn't cause problems
409 // return mpExtraKernInfo->HasKernPairs();
410 return true;
413 // -----------------------------------------------------------------------
415 int FtFontInfo::GetExtraKernPairs( ImplKernPairData** ppKernPairs ) const
417 if( !mpExtraKernInfo )
418 return 0;
419 return mpExtraKernInfo->GetUnscaledKernPairs( ppKernPairs );
422 // -----------------------------------------------------------------------
424 static unsigned GetUInt( const unsigned char* p ) { return((p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3]);}
425 static unsigned GetUShort( const unsigned char* p ){ return((p[0]<<8)+p[1]);}
426 //static signed GetSShort( const unsigned char* p ){ return((short)((p[0]<<8)+p[1]));}
428 static const sal_uInt32 T_true = 0x74727565; /* 'true' */
429 static const sal_uInt32 T_ttcf = 0x74746366; /* 'ttcf' */
430 static const sal_uInt32 T_otto = 0x4f54544f; /* 'OTTO' */
432 const unsigned char* FtFontInfo::GetTable( const char* pTag, sal_uLong* pLength ) const
434 const unsigned char* pBuffer = mpFontFile->GetBuffer();
435 int nFileSize = mpFontFile->GetFileSize();
436 if( !pBuffer || nFileSize<1024 )
437 return NULL;
439 // we currently handle TTF, TTC and OTF headers
440 unsigned nFormat = GetUInt( pBuffer );
442 const unsigned char* p = pBuffer + 12;
443 if( nFormat == T_ttcf ) // TTC_MAGIC
444 p += GetUInt( p + 4 * mnFaceNum );
445 else if( nFormat != 0x00010000 && nFormat != T_true && nFormat != T_otto) // TTF_MAGIC and Apple TTF Magic and PS-OpenType font
446 return NULL;
448 // walk table directory until match
449 int nTables = GetUShort( p - 8 );
450 if( nTables >= 64 ) // something fishy?
451 return NULL;
452 for( int i = 0; i < nTables; ++i, p+=16 )
454 if( p[0]==pTag[0] && p[1]==pTag[1] && p[2]==pTag[2] && p[3]==pTag[3] )
456 sal_uLong nLength = GetUInt( p + 12 );
457 if( pLength != NULL )
458 *pLength = nLength;
459 const unsigned char* pTable = pBuffer + GetUInt( p + 8 );
460 if( (pTable + nLength) <= (mpFontFile->GetBuffer() + nFileSize) )
461 return pTable;
465 return NULL;
468 // -----------------------------------------------------------------------
470 void FtFontInfo::AnnounceFont( ImplDevFontList* pFontList )
472 ImplFTSFontData* pFD = new ImplFTSFontData( this, maDevFontAttributes );
473 pFontList->Add( pFD );
476 // =======================================================================
478 FreetypeManager::FreetypeManager()
479 : mnMaxFontId( 0 )
481 /*FT_Error rcFT =*/ FT_Init_FreeType( &aLibFT );
483 #ifdef ANDROID
484 // For Android we use the bundled static libfreetype.a, and we
485 // want to avoid accidentally finding the FT_* symbols in the
486 // system FreeType code (which *is* present in a system library,
487 // libskia.so, but is not a public API, and in fact does crash the
488 // app if used).
489 pFTNewSize = FT_New_Size;
490 pFTActivateSize = FT_Activate_Size;
491 pFTDoneSize = FT_Done_Size;
492 pFTEmbolden = FT_GlyphSlot_Embolden;
493 pFT_Face_GetCharVariantIndex = FT_Face_GetCharVariantIndex;
494 nFTVERSION = FTVERSION;
495 #else
496 #ifdef RTLD_DEFAULT // true if a good dlfcn.h header was included
497 // Get version of freetype library to enable workarounds.
498 // Freetype <= 2.0.9 does not have FT_Library_Version().
499 // Using dl_sym() instead of osl_getSymbol() because latter
500 // isn't designed to work with oslModule=NULL
501 void (*pFTLibraryVersion)(FT_Library library,
502 FT_Int *amajor, FT_Int *aminor, FT_Int *apatch);
503 pFTLibraryVersion = (void (*)(FT_Library library,
504 FT_Int *amajor, FT_Int *aminor, FT_Int *apatch))(sal_IntPtr)dlsym( RTLD_DEFAULT, "FT_Library_Version" );
506 pFTNewSize = (FT_Error(*)(FT_Face,FT_Size*))(sal_IntPtr)dlsym( RTLD_DEFAULT, "FT_New_Size" );
507 pFTActivateSize = (FT_Error(*)(FT_Size))(sal_IntPtr)dlsym( RTLD_DEFAULT, "FT_Activate_Size" );
508 pFTDoneSize = (FT_Error(*)(FT_Size))(sal_IntPtr)dlsym( RTLD_DEFAULT, "FT_Done_Size" );
509 pFTEmbolden = (void(*)(FT_GlyphSlot))(sal_IntPtr)dlsym( RTLD_DEFAULT, "FT_GlyphSlot_Embolden" );
510 pFT_Face_GetCharVariantIndex = (FT_UInt(*)(FT_Face, FT_ULong, FT_ULong))(sal_IntPtr)dlsym( RTLD_DEFAULT, "FT_Face_GetCharVariantIndex" );
512 bEnableSizeFT = (pFTNewSize!=NULL) && (pFTActivateSize!=NULL) && (pFTDoneSize!=NULL);
514 FT_Int nMajor = 0, nMinor = 0, nPatch = 0;
515 if( pFTLibraryVersion )
516 pFTLibraryVersion( aLibFT, &nMajor, &nMinor, &nPatch );
517 nFTVERSION = nMajor * 1000 + nMinor * 100 + nPatch;
519 // disable artificial emboldening with the Freetype API for older versions
520 if( nFTVERSION < 2110 )
521 pFTEmbolden = NULL;
522 // disable FT_Face_GetCharVariantIndex for older versions
523 // https://bugzilla.mozilla.org/show_bug.cgi?id=618406#c8
524 if( nFTVERSION < 2404 )
525 pFT_Face_GetCharVariantIndex = NULL;
527 #else // RTLD_DEFAULT
528 // assume systems where dlsym is not possible use supplied library
529 nFTVERSION = FTVERSION;
530 #endif
531 #endif
532 // TODO: remove when the priorities are selected by UI
533 char* pEnv;
534 pEnv = ::getenv( "SAL_EMBEDDED_BITMAP_PRIORITY" );
535 if( pEnv )
536 nDefaultPrioEmbedded = pEnv[0] - '0';
537 pEnv = ::getenv( "SAL_ANTIALIASED_TEXT_PRIORITY" );
538 if( pEnv )
539 nDefaultPrioAntiAlias = pEnv[0] - '0';
540 pEnv = ::getenv( "SAL_AUTOHINTING_PRIORITY" );
541 if( pEnv )
542 nDefaultPrioAutoHint = pEnv[0] - '0';
544 InitGammaTable();
545 vclFontFileList::get();
548 // -----------------------------------------------------------------------
550 FT_Face ServerFont::GetFtFace() const
552 if( maSizeFT )
553 pFTActivateSize( maSizeFT );
555 return maFaceFT;
558 // -----------------------------------------------------------------------
560 FreetypeManager::~FreetypeManager()
562 ClearFontList();
565 // -----------------------------------------------------------------------
567 void FreetypeManager::AddFontFile( const OString& rNormalizedName,
568 int nFaceNum, sal_IntPtr nFontId, const ImplDevFontAttributes& rDevFontAttr,
569 const ExtraKernInfo* pExtraKernInfo )
571 if( rNormalizedName.isEmpty() )
572 return;
574 if( maFontList.find( nFontId ) != maFontList.end() )
575 return;
577 FtFontInfo* pFontInfo = new FtFontInfo( rDevFontAttr,
578 rNormalizedName, nFaceNum, nFontId, 0, pExtraKernInfo );
579 maFontList[ nFontId ] = pFontInfo;
580 if( mnMaxFontId < nFontId )
581 mnMaxFontId = nFontId;
584 // -----------------------------------------------------------------------
586 void FreetypeManager::AnnounceFonts( ImplDevFontList* pToAdd ) const
588 for( FontList::const_iterator it = maFontList.begin(); it != maFontList.end(); ++it )
590 FtFontInfo* pFtFontInfo = it->second;
591 pFtFontInfo->AnnounceFont( pToAdd );
595 // -----------------------------------------------------------------------
597 void FreetypeManager::ClearFontList( )
599 for( FontList::iterator it = maFontList.begin(); it != maFontList.end(); ++it )
601 FtFontInfo* pFtFontInfo = it->second;
602 delete pFtFontInfo;
604 maFontList.clear();
607 // -----------------------------------------------------------------------
609 ServerFont* FreetypeManager::CreateFont( const FontSelectPattern& rFSD )
611 FtFontInfo* pFontInfo = NULL;
613 // find a FontInfo matching to the font id
614 sal_IntPtr nFontId = reinterpret_cast<sal_IntPtr>( rFSD.mpFontData );
615 FontList::iterator it = maFontList.find( nFontId );
616 if( it != maFontList.end() )
617 pFontInfo = it->second;
619 if( !pFontInfo )
620 return NULL;
622 ServerFont* pNew = new ServerFont( rFSD, pFontInfo );
624 return pNew;
627 // =======================================================================
629 ImplFTSFontData::ImplFTSFontData( FtFontInfo* pFI, const ImplDevFontAttributes& rDFA )
630 : PhysicalFontFace( rDFA, IFTSFONT_MAGIC ),
631 mpFtFontInfo( pFI )
633 mbDevice = false;
634 mbOrientation = true;
637 // -----------------------------------------------------------------------
639 ImplFontEntry* ImplFTSFontData::CreateFontInstance( FontSelectPattern& rFSD ) const
641 ImplServerFontEntry* pEntry = new ImplServerFontEntry( rFSD );
642 return pEntry;
645 // =======================================================================
646 // ServerFont
647 // =======================================================================
649 ServerFont::ServerFont( const FontSelectPattern& rFSD, FtFontInfo* pFI )
650 : maGlyphList( 0),
651 maFontSelData(rFSD),
652 mnExtInfo(0),
653 mnRefCount(1),
654 mnBytesUsed( sizeof(ServerFont) ),
655 mpPrevGCFont( NULL ),
656 mpNextGCFont( NULL ),
657 mnCos( 0x10000),
658 mnSin( 0 ),
659 mbCollectedZW( false ),
660 mnPrioEmbedded(nDefaultPrioEmbedded),
661 mnPrioAntiAlias(nDefaultPrioAntiAlias),
662 mnPrioAutoHint(nDefaultPrioAutoHint),
663 mpFontInfo( pFI ),
664 maFaceFT( NULL ),
665 maSizeFT( NULL ),
666 mbFaceOk( false ),
667 maRecodeConverter( NULL ),
668 mpLayoutEngine( NULL )
670 // TODO: move update of mpFontEntry into FontEntry class when
671 // it becomes reponsible for the ServerFont instantiation
672 ((ImplServerFontEntry*)rFSD.mpFontEntry)->SetServerFont( this );
674 if( rFSD.mnOrientation != 0 )
676 const double dRad = rFSD.mnOrientation * ( F_2PI / 3600.0 );
677 mnCos = static_cast<long>( 0x10000 * cos( dRad ) + 0.5 );
678 mnSin = static_cast<long>( 0x10000 * sin( dRad ) + 0.5 );
681 maFaceFT = pFI->GetFaceFT();
683 if( !maFaceFT )
684 return;
686 // set the pixel size of the font instance
687 mnWidth = rFSD.mnWidth;
688 if( !mnWidth )
689 mnWidth = rFSD.mnHeight;
690 mfStretch = (double)mnWidth / rFSD.mnHeight;
691 // sanity check (e.g. #i66394#, #i66244#, #66537#)
692 if( (mnWidth < 0) || (mfStretch > +64.0) || (mfStretch < -64.0) )
693 return;
695 // perf: use maSizeFT if available
696 if( bEnableSizeFT )
698 pFTNewSize( maFaceFT, &maSizeFT );
699 pFTActivateSize( maSizeFT );
701 FT_Error rc = FT_Set_Pixel_Sizes( maFaceFT, mnWidth, rFSD.mnHeight );
702 if( rc != FT_Err_Ok )
703 return;
705 // prepare for font encodings other than unicode or symbol
706 FT_Encoding eEncoding = FT_ENCODING_UNICODE;
707 if( mpFontInfo->IsSymbolFont() )
709 if( FT_IS_SFNT( maFaceFT ) )
710 eEncoding = ft_encoding_symbol;
711 else
712 eEncoding = FT_ENCODING_ADOBE_CUSTOM; // freetype wants this for PS symbol fonts
714 rc = FT_Select_Charmap( maFaceFT, eEncoding );
715 // no standard encoding applies => we need an encoding converter
716 if( rc != FT_Err_Ok )
718 rtl_TextEncoding eRecodeFrom = RTL_TEXTENCODING_UNICODE;
719 for( int i = maFaceFT->num_charmaps; --i >= 0; )
721 const FT_CharMap aCM = maFaceFT->charmaps[i];
722 if( aCM->platform_id == TT_PLATFORM_MICROSOFT )
724 switch( aCM->encoding_id )
726 case TT_MS_ID_SJIS:
727 eEncoding = FT_ENCODING_SJIS;
728 eRecodeFrom = RTL_TEXTENCODING_SHIFT_JIS;
729 break;
730 case TT_MS_ID_GB2312:
731 eEncoding = FT_ENCODING_GB2312;
732 eRecodeFrom = RTL_TEXTENCODING_GB_2312;
733 break;
734 case TT_MS_ID_BIG_5:
735 eEncoding = FT_ENCODING_BIG5;
736 eRecodeFrom = RTL_TEXTENCODING_BIG5;
737 break;
738 case TT_MS_ID_WANSUNG:
739 eEncoding = FT_ENCODING_WANSUNG;
740 eRecodeFrom = RTL_TEXTENCODING_MS_949;
741 break;
742 case TT_MS_ID_JOHAB:
743 eEncoding = FT_ENCODING_JOHAB;
744 eRecodeFrom = RTL_TEXTENCODING_MS_1361;
745 break;
748 else if( aCM->platform_id == TT_PLATFORM_MACINTOSH )
750 switch( aCM->encoding_id )
752 case TT_MAC_ID_ROMAN:
753 eEncoding = FT_ENCODING_APPLE_ROMAN;
754 eRecodeFrom = RTL_TEXTENCODING_UNICODE; // TODO: use better match
755 break;
756 // TODO: add other encodings when Mac-only
757 // non-unicode fonts show up
760 else if( aCM->platform_id == TT_PLATFORM_ADOBE )
762 switch( aCM->encoding_id )
764 #ifdef TT_ADOBE_ID_LATIN1
765 case TT_ADOBE_ID_LATIN1: // better unicode than nothing
766 eEncoding = FT_ENCODING_ADOBE_LATIN_1;
767 eRecodeFrom = RTL_TEXTENCODING_ISO_8859_1;
768 break;
769 #endif // TT_ADOBE_ID_LATIN1
770 case TT_ADOBE_ID_STANDARD: // better unicode than nothing
771 eEncoding = FT_ENCODING_ADOBE_STANDARD;
772 eRecodeFrom = RTL_TEXTENCODING_UNICODE; // TODO: use better match
773 break;
778 if( FT_Err_Ok != FT_Select_Charmap( maFaceFT, eEncoding ) )
779 return;
781 if( eRecodeFrom != RTL_TEXTENCODING_UNICODE )
782 maRecodeConverter = rtl_createUnicodeToTextConverter( eRecodeFrom );
785 mbFaceOk = true;
787 ApplyGSUB( rFSD );
789 // TODO: query GASP table for load flags
790 mnLoadFlags = FT_LOAD_DEFAULT;
791 #if 1 // #i97326# cairo sometimes uses FT_Set_Transform() on our FT_FACE
792 // we are not using FT_Set_Transform() yet, so just ignore it for now
793 mnLoadFlags |= FT_LOAD_IGNORE_TRANSFORM;
794 #endif
796 mbArtItalic = (rFSD.GetSlant() != ITALIC_NONE && pFI->GetFontAttributes().GetSlant() == ITALIC_NONE);
797 mbArtBold = (rFSD.GetWeight() > WEIGHT_MEDIUM && pFI->GetFontAttributes().GetWeight() <= WEIGHT_MEDIUM);
798 mbUseGamma = false;
799 if( mbArtBold )
801 //static const int TT_CODEPAGE_RANGE_874 = (1L << 16); // Thai
802 //static const int TT_CODEPAGE_RANGE_932 = (1L << 17); // JIS/Japan
803 //static const int TT_CODEPAGE_RANGE_936 = (1L << 18); // Chinese: Simplified
804 //static const int TT_CODEPAGE_RANGE_949 = (1L << 19); // Korean Wansung
805 //static const int TT_CODEPAGE_RANGE_950 = (1L << 20); // Chinese: Traditional
806 //static const int TT_CODEPAGE_RANGE_1361 = (1L << 21); // Korean Johab
807 static const int TT_CODEPAGE_RANGES1_CJKT = 0x3F0000; // all of the above
808 const TT_OS2* pOs2 = (const TT_OS2*)FT_Get_Sfnt_Table( maFaceFT, ft_sfnt_os2 );
809 if ((pOs2) && (pOs2->ulCodePageRange1 & TT_CODEPAGE_RANGES1_CJKT )
810 && rFSD.mnHeight < 20)
811 mbUseGamma = true;
814 if( ((mnCos != 0) && (mnSin != 0)) || (mnPrioEmbedded <= 0) )
815 mnLoadFlags |= FT_LOAD_NO_BITMAP;
818 void ServerFont::SetFontOptions( boost::shared_ptr<ImplFontOptions> pFontOptions)
820 mpFontOptions = pFontOptions;
822 if (!mpFontOptions)
823 return;
825 FontAutoHint eHint = mpFontOptions->GetUseAutoHint();
826 if( eHint == AUTOHINT_DONTKNOW )
827 eHint = mbUseGamma ? AUTOHINT_TRUE : AUTOHINT_FALSE;
829 if( eHint == AUTOHINT_TRUE )
830 mnLoadFlags |= FT_LOAD_FORCE_AUTOHINT;
832 if( (mnSin != 0) && (mnCos != 0) ) // hinting for 0/90/180/270 degrees only
833 mnLoadFlags |= FT_LOAD_NO_HINTING;
834 mnLoadFlags |= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH; //#88334#
836 if( mpFontOptions->DontUseAntiAlias() )
837 mnPrioAntiAlias = 0;
838 if( mpFontOptions->DontUseEmbeddedBitmaps() )
839 mnPrioEmbedded = 0;
840 if( mpFontOptions->DontUseHinting() )
841 mnPrioAutoHint = 0;
843 if( mnPrioAutoHint <= 0 )
844 mnLoadFlags |= FT_LOAD_NO_HINTING;
846 #if defined(FT_LOAD_TARGET_LIGHT) && defined(FT_LOAD_TARGET_NORMAL)
847 if( !(mnLoadFlags & FT_LOAD_NO_HINTING) )
849 mnLoadFlags |= FT_LOAD_TARGET_NORMAL;
850 switch( mpFontOptions->GetHintStyle() )
852 case HINT_NONE:
853 mnLoadFlags |= FT_LOAD_NO_HINTING;
854 break;
855 case HINT_SLIGHT:
856 mnLoadFlags |= FT_LOAD_TARGET_LIGHT;
857 break;
858 case HINT_MEDIUM:
859 break;
860 case HINT_FULL:
861 default:
862 break;
865 #endif
867 if( mnPrioEmbedded <= 0 )
868 mnLoadFlags |= FT_LOAD_NO_BITMAP;
871 boost::shared_ptr<ImplFontOptions> ServerFont::GetFontOptions() const
873 return mpFontOptions;
876 const OString* ServerFont::GetFontFileName() const
878 return mpFontInfo->GetFontFileName();
881 bool ServerFont::TestFont() const
883 return mbFaceOk;
886 // -----------------------------------------------------------------------
888 ServerFont::~ServerFont()
890 if( mpLayoutEngine )
891 delete mpLayoutEngine;
893 if( maRecodeConverter )
894 rtl_destroyUnicodeToTextConverter( maRecodeConverter );
896 if( maSizeFT )
897 pFTDoneSize( maSizeFT );
899 mpFontInfo->ReleaseFaceFT( maFaceFT );
901 ReleaseFromGarbageCollect();
904 // -----------------------------------------------------------------------
906 int ServerFont::GetEmUnits() const
908 return maFaceFT->units_per_EM;
911 // -----------------------------------------------------------------------
913 void ServerFont::FetchFontMetric( ImplFontMetricData& rTo, long& rFactor ) const
915 static_cast<ImplFontAttributes&>(rTo) = mpFontInfo->GetFontAttributes();
917 rTo.mbScalableFont = true;
918 rTo.mbDevice = true;
919 rTo.mbKernableFont = (FT_HAS_KERNING( maFaceFT ) != 0) || mpFontInfo->HasExtraKerning();
920 rTo.mnOrientation = GetFontSelData().mnOrientation;
922 //Always consider [star]symbol as symbol fonts
923 if (
924 (rTo.GetFamilyName() == "OpenSymbol" ) ||
925 (rTo.GetFamilyName() == "StarSymbol" )
928 rTo.SetSymbolFlag( true );
931 if( maSizeFT )
932 pFTActivateSize( maSizeFT );
934 rFactor = 0x100;
936 const TT_OS2* pOS2 = (const TT_OS2*)FT_Get_Sfnt_Table( maFaceFT, ft_sfnt_os2 );
937 const double fScale = (double)GetFontSelData().mnHeight / maFaceFT->units_per_EM;
939 rTo.mnAscent = 0;
940 rTo.mnDescent = 0;
941 rTo.mnExtLeading = 0;
942 rTo.mnSlant = 0;
943 rTo.mnWidth = mnWidth;
945 // Calculating ascender and descender:
946 // FreeType >= 2.4.6 does the right thing, so we just use what it gives us,
947 // for earlier versions we emulate its behaviour;
948 // take them from 'hhea' table,
949 // if zero take them from 'OS/2' table,
950 // if zero take them from FreeType's font metrics
951 if (nFTVERSION >= 2406)
953 const FT_Size_Metrics& rMetrics = maFaceFT->size->metrics;
954 rTo.mnAscent = (rMetrics.ascender + 32) >> 6;
955 rTo.mnDescent = (-rMetrics.descender + 32) >> 6;
956 rTo.mnExtLeading = ((rMetrics.height + 32) >> 6) - (rTo.mnAscent + rTo.mnDescent);
958 else
960 const TT_HoriHeader* pHHea = (const TT_HoriHeader*)FT_Get_Sfnt_Table(maFaceFT, ft_sfnt_hhea);
961 if (pHHea)
963 rTo.mnAscent = pHHea->Ascender * fScale + 0.5;
964 rTo.mnDescent = -pHHea->Descender * fScale + 0.5;
965 rTo.mnExtLeading = pHHea->Line_Gap * fScale + 0.5;
968 if (!(rTo.mnAscent || rTo.mnDescent))
970 if (pOS2 && (pOS2->version != 0xFFFF))
972 if (pOS2->sTypoAscender || pOS2->sTypoDescender)
974 rTo.mnAscent = pOS2->sTypoAscender * fScale + 0.5;
975 rTo.mnDescent = -pOS2->sTypoDescender * fScale + 0.5;
976 rTo.mnExtLeading = pOS2->sTypoLineGap * fScale + 0.5;
978 else
980 rTo.mnAscent = pOS2->usWinAscent * fScale + 0.5;
981 rTo.mnDescent = pOS2->usWinDescent * fScale + 0.5;
982 rTo.mnExtLeading = 0;
987 if (!(rTo.mnAscent || rTo.mnDescent))
989 const FT_Size_Metrics& rMetrics = maFaceFT->size->metrics;
990 rTo.mnAscent = (rMetrics.ascender + 32) >> 6;
991 rTo.mnDescent = (-rMetrics.descender + 32) >> 6;
992 rTo.mnExtLeading = ((rMetrics.height + 32) >> 6) - (rTo.mnAscent + rTo.mnDescent);
996 rTo.mnIntLeading = rTo.mnAscent + rTo.mnDescent - (maFaceFT->units_per_EM * fScale + 0.5);
998 if( pOS2 && (pOS2->version != 0xFFFF) )
1000 // map the panose info from the OS2 table to their VCL counterparts
1001 switch( pOS2->panose[0] )
1003 case 1: rTo.SetFamilyType( FAMILY_ROMAN ); break;
1004 case 2: rTo.SetFamilyType( FAMILY_SWISS ); break;
1005 case 3: rTo.SetFamilyType( FAMILY_MODERN ); break;
1006 case 4: rTo.SetFamilyType( FAMILY_SCRIPT ); break;
1007 case 5: rTo.SetFamilyType( FAMILY_DECORATIVE ); break;
1008 // TODO: is it reasonable to override the attribute with DONTKNOW?
1009 case 0: // fall through
1010 default: rTo.meFamilyType = FAMILY_DONTKNOW; break;
1013 switch( pOS2->panose[3] )
1015 case 2: // fall through
1016 case 3: // fall through
1017 case 4: // fall through
1018 case 5: // fall through
1019 case 6: // fall through
1020 case 7: // fall through
1021 case 8: rTo.SetPitch( PITCH_VARIABLE ); break;
1022 case 9: rTo.SetPitch( PITCH_FIXED ); break;
1023 // TODO: is it reasonable to override the attribute with DONTKNOW?
1024 case 0: // fall through
1025 case 1: // fall through
1026 default: rTo.SetPitch( PITCH_DONTKNOW ); break;
1030 // initialize kashida width
1031 // TODO: what if there are different versions of this glyph available
1032 const int nKashidaGlyphId = GetRawGlyphIndex( 0x0640 );
1033 if( nKashidaGlyphId )
1035 GlyphData aGlyphData;
1036 InitGlyphData( nKashidaGlyphId, aGlyphData );
1037 rTo.mnMinKashida = aGlyphData.GetMetric().GetCharWidth();
1041 // -----------------------------------------------------------------------
1043 static inline void SplitGlyphFlags( const ServerFont& rFont, int& nGlyphIndex, int& nGlyphFlags )
1045 nGlyphFlags = nGlyphIndex & GF_FLAGMASK;
1046 nGlyphIndex &= GF_IDXMASK;
1048 if( nGlyphIndex & GF_ISCHAR )
1049 nGlyphIndex = rFont.GetRawGlyphIndex( nGlyphIndex );
1052 // -----------------------------------------------------------------------
1054 int ServerFont::ApplyGlyphTransform( int nGlyphFlags,
1055 FT_Glyph pGlyphFT, bool bForBitmapProcessing ) const
1057 int nAngle = GetFontSelData().mnOrientation;
1058 // shortcut most common case
1059 if( !nAngle && !nGlyphFlags )
1060 return nAngle;
1062 const FT_Size_Metrics& rMetrics = maFaceFT->size->metrics;
1063 FT_Vector aVector;
1064 FT_Matrix aMatrix;
1066 bool bStretched = false;
1068 switch( nGlyphFlags & GF_ROTMASK )
1070 default: // straight
1071 aVector.x = 0;
1072 aVector.y = 0;
1073 aMatrix.xx = +mnCos;
1074 aMatrix.yy = +mnCos;
1075 aMatrix.xy = -mnSin;
1076 aMatrix.yx = +mnSin;
1077 break;
1078 case GF_ROTL: // left
1079 nAngle += 900;
1080 bStretched = (mfStretch != 1.0);
1081 aVector.x = (FT_Pos)(+rMetrics.descender * mfStretch);
1082 aVector.y = -rMetrics.ascender;
1083 aMatrix.xx = (FT_Pos)(-mnSin / mfStretch);
1084 aMatrix.yy = (FT_Pos)(-mnSin * mfStretch);
1085 aMatrix.xy = (FT_Pos)(-mnCos * mfStretch);
1086 aMatrix.yx = (FT_Pos)(+mnCos / mfStretch);
1087 break;
1088 case GF_ROTR: // right
1089 nAngle -= 900;
1090 bStretched = (mfStretch != 1.0);
1091 aVector.x = -maFaceFT->glyph->metrics.horiAdvance;
1092 aVector.x += (FT_Pos)(rMetrics.descender * mnSin/65536.0);
1093 aVector.y = (FT_Pos)(-rMetrics.descender * mfStretch * mnCos/65536.0);
1094 aMatrix.xx = (FT_Pos)(+mnSin / mfStretch);
1095 aMatrix.yy = (FT_Pos)(+mnSin * mfStretch);
1096 aMatrix.xy = (FT_Pos)(+mnCos * mfStretch);
1097 aMatrix.yx = (FT_Pos)(-mnCos / mfStretch);
1098 break;
1101 while( nAngle < 0 )
1102 nAngle += 3600;
1104 if( pGlyphFT->format != FT_GLYPH_FORMAT_BITMAP )
1106 FT_Glyph_Transform( pGlyphFT, NULL, &aVector );
1108 // orthogonal transforms are better handled by bitmap operations
1109 if( bStretched || (bForBitmapProcessing && (nAngle % 900) != 0) )
1111 // apply non-orthogonal or stretch transformations
1112 FT_Glyph_Transform( pGlyphFT, &aMatrix, NULL );
1113 nAngle = 0;
1116 else
1118 // FT<=2005 ignores transforms for bitmaps, so do it manually
1119 FT_BitmapGlyph pBmpGlyphFT = reinterpret_cast<FT_BitmapGlyph>(pGlyphFT);
1120 pBmpGlyphFT->left += (aVector.x + 32) >> 6;
1121 pBmpGlyphFT->top += (aVector.y + 32) >> 6;
1124 return nAngle;
1127 // -----------------------------------------------------------------------
1129 int ServerFont::GetRawGlyphIndex(sal_UCS4 aChar, sal_UCS4 aVS) const
1131 if( mpFontInfo->IsSymbolFont() )
1133 if( !FT_IS_SFNT( maFaceFT ) )
1135 if( (aChar & 0xFF00) == 0xF000 )
1136 aChar &= 0xFF; // PS font symbol mapping
1137 else if( aChar > 0xFF )
1138 return 0;
1142 // if needed recode from unicode to font encoding
1143 if( maRecodeConverter )
1145 sal_Char aTempArray[8];
1146 sal_Size nTempSize;
1147 sal_uInt32 nCvtInfo;
1149 // assume that modern UCS4 fonts have unicode CMAPs
1150 // => no encoding remapping to unicode is needed
1151 if( aChar > 0xFFFF )
1152 return 0;
1154 sal_Unicode aUCS2Char = static_cast<sal_Unicode>(aChar);
1155 rtl_UnicodeToTextContext aContext = rtl_createUnicodeToTextContext( maRecodeConverter );
1156 int nChars = rtl_convertUnicodeToText( maRecodeConverter, aContext,
1157 &aUCS2Char, 1, aTempArray, sizeof(aTempArray),
1158 RTL_UNICODETOTEXT_FLAGS_UNDEFINED_QUESTIONMARK
1159 | RTL_UNICODETOTEXT_FLAGS_INVALID_QUESTIONMARK,
1160 &nCvtInfo, &nTempSize );
1161 rtl_destroyUnicodeToTextContext( maRecodeConverter, aContext );
1163 aChar = 0;
1164 for( int i = 0; i < nChars; ++i )
1165 aChar = aChar*256 + (aTempArray[i] & 0xFF);
1168 int nGlyphIndex = 0;
1169 // If asked, check first for variant glyph with the given Unicode variation
1170 // selector. This is quite uncommon so we don't bother with caching here.
1171 if (aVS && pFT_Face_GetCharVariantIndex)
1172 nGlyphIndex = (*pFT_Face_GetCharVariantIndex)(maFaceFT, aChar, aVS);
1174 if (nGlyphIndex == 0)
1176 // cache glyph indexes in font info to share between different sizes
1177 nGlyphIndex = mpFontInfo->GetGlyphIndex( aChar );
1178 if( nGlyphIndex < 0 )
1180 nGlyphIndex = FT_Get_Char_Index( maFaceFT, aChar );
1181 if( !nGlyphIndex)
1183 // check if symbol aliasing helps
1184 if( (aChar <= 0x00FF) && mpFontInfo->IsSymbolFont() )
1185 nGlyphIndex = FT_Get_Char_Index( maFaceFT, aChar | 0xF000 );
1187 mpFontInfo->CacheGlyphIndex( aChar, nGlyphIndex );
1191 return nGlyphIndex;
1194 // -----------------------------------------------------------------------
1196 int ServerFont::FixupGlyphIndex( int nGlyphIndex, sal_UCS4 aChar ) const
1198 int nGlyphFlags = GF_NONE;
1200 // do glyph substitution if necessary
1201 // CJK vertical writing needs special treatment
1202 if( GetFontSelData().mbVertical )
1204 // TODO: rethink when GSUB is used for non-vertical case
1205 GlyphSubstitution::const_iterator it = maGlyphSubstitution.find( nGlyphIndex );
1206 if( it == maGlyphSubstitution.end() )
1208 int nTemp = GetVerticalChar( aChar );
1209 if( nTemp ) // is substitution possible
1210 nTemp = GetRawGlyphIndex( nTemp );
1211 if( nTemp ) // substitute manually if sensible
1212 nGlyphIndex = nTemp | (GF_GSUB | GF_ROTL);
1213 else
1214 nGlyphFlags |= GetVerticalFlags( aChar );
1216 else
1218 // for vertical GSUB also compensate for nOrientation=2700
1219 nGlyphIndex = (*it).second;
1220 nGlyphFlags |= GF_GSUB | GF_ROTL;
1224 if( nGlyphIndex != 0 )
1225 nGlyphIndex |= nGlyphFlags;
1227 return nGlyphIndex;
1231 // -----------------------------------------------------------------------
1233 int ServerFont::GetGlyphIndex( sal_UCS4 aChar ) const
1235 int nGlyphIndex = GetRawGlyphIndex( aChar );
1236 nGlyphIndex = FixupGlyphIndex( nGlyphIndex, aChar );
1237 return nGlyphIndex;
1240 // -----------------------------------------------------------------------
1242 static int lcl_GetCharWidth( FT_FaceRec_* pFaceFT, double fStretch, int nGlyphFlags )
1244 int nCharWidth = pFaceFT->glyph->metrics.horiAdvance;
1246 if( nGlyphFlags & GF_ROTMASK ) // for bVertical rotated glyphs
1248 const FT_Size_Metrics& rMetrics = pFaceFT->size->metrics;
1249 nCharWidth = (int)((rMetrics.height + rMetrics.descender) * fStretch);
1252 return (nCharWidth + 32) >> 6;
1255 // -----------------------------------------------------------------------
1257 void ServerFont::InitGlyphData( int nGlyphIndex, GlyphData& rGD ) const
1259 if( maSizeFT )
1260 pFTActivateSize( maSizeFT );
1262 int nGlyphFlags;
1263 SplitGlyphFlags( *this, nGlyphIndex, nGlyphFlags );
1265 int nLoadFlags = mnLoadFlags;
1267 // if( mbArtItalic )
1268 // nLoadFlags |= FT_LOAD_NO_BITMAP;
1270 FT_Error rc = -1;
1271 rc = FT_Load_Glyph( maFaceFT, nGlyphIndex, nLoadFlags );
1273 if( rc != FT_Err_Ok )
1275 // we get here e.g. when a PS font lacks the default glyph
1276 rGD.SetCharWidth( 0 );
1277 rGD.SetDelta( 0, 0 );
1278 rGD.SetOffset( 0, 0 );
1279 rGD.SetSize( Size( 0, 0 ) );
1280 return;
1283 const bool bOriginallyZeroWidth = (maFaceFT->glyph->metrics.horiAdvance == 0);
1284 if( mbArtBold && pFTEmbolden )
1285 (*pFTEmbolden)( maFaceFT->glyph );
1287 const int nCharWidth = bOriginallyZeroWidth ? 0 : lcl_GetCharWidth( maFaceFT, mfStretch, nGlyphFlags );
1288 rGD.SetCharWidth( nCharWidth );
1290 FT_Glyph pGlyphFT;
1291 rc = FT_Get_Glyph( maFaceFT->glyph, &pGlyphFT );
1293 ApplyGlyphTransform( nGlyphFlags, pGlyphFT, false );
1294 if( mbArtBold && pFTEmbolden && (nFTVERSION < 2200) ) // #i71094# workaround staircase bug
1295 pGlyphFT->advance.y = 0;
1296 rGD.SetDelta( (pGlyphFT->advance.x + 0x8000) >> 16, -((pGlyphFT->advance.y + 0x8000) >> 16) );
1298 FT_BBox aBbox;
1299 FT_Glyph_Get_CBox( pGlyphFT, FT_GLYPH_BBOX_PIXELS, &aBbox );
1300 if( aBbox.yMin > aBbox.yMax ) // circumvent freetype bug
1302 int t=aBbox.yMin; aBbox.yMin=aBbox.yMax, aBbox.yMax=t;
1305 rGD.SetOffset( aBbox.xMin, -aBbox.yMax );
1306 rGD.SetSize( Size( (aBbox.xMax-aBbox.xMin+1), (aBbox.yMax-aBbox.yMin) ) );
1308 FT_Done_Glyph( pGlyphFT );
1311 // -----------------------------------------------------------------------
1313 bool ServerFont::GetAntialiasAdvice( void ) const
1315 if( GetFontSelData().mbNonAntialiased || (mnPrioAntiAlias<=0) )
1316 return false;
1317 bool bAdviseAA = true;
1318 // TODO: also use GASP info
1319 return bAdviseAA;
1322 // -----------------------------------------------------------------------
1324 bool ServerFont::GetGlyphBitmap1( int nGlyphIndex, RawBitmap& rRawBitmap ) const
1326 if( maSizeFT )
1327 pFTActivateSize( maSizeFT );
1329 int nGlyphFlags;
1330 SplitGlyphFlags( *this, nGlyphIndex, nGlyphFlags );
1332 FT_Int nLoadFlags = mnLoadFlags;
1333 // #i70930# force mono-hinting for monochrome text
1334 if( nFTVERSION >= 2110 ) //#i71947# unless it looks worse
1336 nLoadFlags &= ~0xF0000;
1337 nLoadFlags |= FT_LOAD_TARGET_MONO;
1340 if( mbArtItalic )
1341 nLoadFlags |= FT_LOAD_NO_BITMAP;
1343 // for 0/90/180/270 degree fonts enable hinting even if not advisable
1344 // non-hinted and non-antialiased bitmaps just look too ugly
1345 if( (mnCos==0 || mnSin==0) && (mnPrioAutoHint > 0) )
1346 nLoadFlags &= ~FT_LOAD_NO_HINTING;
1348 if( mnPrioEmbedded <= mnPrioAutoHint )
1349 nLoadFlags |= FT_LOAD_NO_BITMAP;
1351 FT_Error rc = -1;
1352 rc = FT_Load_Glyph( maFaceFT, nGlyphIndex, nLoadFlags );
1354 if( rc != FT_Err_Ok )
1355 return false;
1357 if( mbArtBold && pFTEmbolden )
1358 (*pFTEmbolden)( maFaceFT->glyph );
1360 FT_Glyph pGlyphFT;
1361 rc = FT_Get_Glyph( maFaceFT->glyph, &pGlyphFT );
1362 if( rc != FT_Err_Ok )
1363 return false;
1365 int nAngle = ApplyGlyphTransform( nGlyphFlags, pGlyphFT, true );
1367 if( mbArtItalic )
1369 FT_Matrix aMatrix;
1370 aMatrix.xx = aMatrix.yy = 0x10000L;
1371 aMatrix.xy = 0x6000L, aMatrix.yx = 0;
1372 FT_Glyph_Transform( pGlyphFT, &aMatrix, NULL );
1375 // Check for zero area bounding boxes as this crashes some versions of FT.
1376 // This also provides a handy short cut as much of the code following
1377 // becomes an expensive nop when a glyph covers no pixels.
1378 FT_BBox cbox;
1379 FT_Glyph_Get_CBox(pGlyphFT, ft_glyph_bbox_unscaled, &cbox);
1381 if( (cbox.xMax - cbox.xMin) == 0 || (cbox.yMax - cbox.yMin == 0) )
1383 nAngle = 0;
1384 memset(&rRawBitmap, 0, sizeof rRawBitmap);
1385 FT_Done_Glyph( pGlyphFT );
1386 return true;
1389 if( pGlyphFT->format != FT_GLYPH_FORMAT_BITMAP )
1391 if( pGlyphFT->format == FT_GLYPH_FORMAT_OUTLINE )
1392 ((FT_OutlineGlyphRec*)pGlyphFT)->outline.flags |= FT_OUTLINE_HIGH_PRECISION;
1393 FT_Render_Mode nRenderMode = FT_RENDER_MODE_MONO;
1395 rc = FT_Glyph_To_Bitmap( &pGlyphFT, nRenderMode, NULL, sal_True );
1396 if( rc != FT_Err_Ok )
1398 FT_Done_Glyph( pGlyphFT );
1399 return false;
1403 const FT_BitmapGlyph pBmpGlyphFT = reinterpret_cast<const FT_BitmapGlyph>(pGlyphFT);
1404 // NOTE: autohinting in FT<=2.0.2 miscalculates the offsets below by +-1
1405 rRawBitmap.mnXOffset = +pBmpGlyphFT->left;
1406 rRawBitmap.mnYOffset = -pBmpGlyphFT->top;
1408 const FT_Bitmap& rBitmapFT = pBmpGlyphFT->bitmap;
1409 rRawBitmap.mnHeight = rBitmapFT.rows;
1410 rRawBitmap.mnBitCount = 1;
1411 if( mbArtBold && !pFTEmbolden )
1413 rRawBitmap.mnWidth = rBitmapFT.width + 1;
1414 int nLineBytes = (rRawBitmap.mnWidth + 7) >> 3;
1415 rRawBitmap.mnScanlineSize = (nLineBytes > rBitmapFT.pitch) ? nLineBytes : rBitmapFT.pitch;
1417 else
1419 rRawBitmap.mnWidth = rBitmapFT.width;
1420 rRawBitmap.mnScanlineSize = rBitmapFT.pitch;
1423 const sal_uLong nNeededSize = rRawBitmap.mnScanlineSize * rRawBitmap.mnHeight;
1425 if( rRawBitmap.mnAllocated < nNeededSize )
1427 delete[] rRawBitmap.mpBits;
1428 rRawBitmap.mnAllocated = 2*nNeededSize;
1429 rRawBitmap.mpBits = new unsigned char[ rRawBitmap.mnAllocated ];
1432 if( !mbArtBold || pFTEmbolden )
1434 memcpy( rRawBitmap.mpBits, rBitmapFT.buffer, nNeededSize );
1436 else
1438 memset( rRawBitmap.mpBits, 0, nNeededSize );
1439 const unsigned char* pSrcLine = rBitmapFT.buffer;
1440 unsigned char* pDstLine = rRawBitmap.mpBits;
1441 for( int h = rRawBitmap.mnHeight; --h >= 0; )
1443 memcpy( pDstLine, pSrcLine, rBitmapFT.pitch );
1444 pDstLine += rRawBitmap.mnScanlineSize;
1445 pSrcLine += rBitmapFT.pitch;
1448 unsigned char* p = rRawBitmap.mpBits;
1449 for( sal_uLong y=0; y < rRawBitmap.mnHeight; y++ )
1451 unsigned char nLastByte = 0;
1452 for( sal_uLong x=0; x < rRawBitmap.mnScanlineSize; x++ )
1454 unsigned char nTmp = p[x] << 7;
1455 p[x] |= (p[x] >> 1) | nLastByte;
1456 nLastByte = nTmp;
1458 p += rRawBitmap.mnScanlineSize;
1462 FT_Done_Glyph( pGlyphFT );
1464 // special case for 0/90/180/270 degree orientation
1465 switch( nAngle )
1467 case -900:
1468 case +900:
1469 case +1800:
1470 case +2700:
1471 rRawBitmap.Rotate( nAngle );
1472 break;
1475 return true;
1478 // -----------------------------------------------------------------------
1480 bool ServerFont::GetGlyphBitmap8( int nGlyphIndex, RawBitmap& rRawBitmap ) const
1482 if( maSizeFT )
1483 pFTActivateSize( maSizeFT );
1485 int nGlyphFlags;
1486 SplitGlyphFlags( *this, nGlyphIndex, nGlyphFlags );
1488 FT_Int nLoadFlags = mnLoadFlags;
1490 if( mbArtItalic )
1491 nLoadFlags |= FT_LOAD_NO_BITMAP;
1493 if( (nGlyphFlags & GF_UNHINTED) || (mnPrioAutoHint < mnPrioAntiAlias) )
1494 nLoadFlags |= FT_LOAD_NO_HINTING;
1496 if( mnPrioEmbedded <= mnPrioAntiAlias )
1497 nLoadFlags |= FT_LOAD_NO_BITMAP;
1499 FT_Error rc = -1;
1500 rc = FT_Load_Glyph( maFaceFT, nGlyphIndex, nLoadFlags );
1502 if( rc != FT_Err_Ok )
1503 return false;
1505 if( mbArtBold && pFTEmbolden )
1506 (*pFTEmbolden)( maFaceFT->glyph );
1508 FT_Glyph pGlyphFT;
1509 rc = FT_Get_Glyph( maFaceFT->glyph, &pGlyphFT );
1510 if( rc != FT_Err_Ok )
1511 return false;
1513 int nAngle = ApplyGlyphTransform( nGlyphFlags, pGlyphFT, true );
1515 if( mbArtItalic )
1517 FT_Matrix aMatrix;
1518 aMatrix.xx = aMatrix.yy = 0x10000L;
1519 aMatrix.xy = 0x6000L, aMatrix.yx = 0;
1520 FT_Glyph_Transform( pGlyphFT, &aMatrix, NULL );
1523 if( pGlyphFT->format == FT_GLYPH_FORMAT_OUTLINE )
1524 ((FT_OutlineGlyph)pGlyphFT)->outline.flags |= FT_OUTLINE_HIGH_PRECISION;
1526 bool bEmbedded = (pGlyphFT->format == FT_GLYPH_FORMAT_BITMAP);
1527 if( !bEmbedded )
1529 rc = FT_Glyph_To_Bitmap( &pGlyphFT, FT_RENDER_MODE_NORMAL, NULL, sal_True );
1530 if( rc != FT_Err_Ok )
1532 FT_Done_Glyph( pGlyphFT );
1533 return false;
1537 const FT_BitmapGlyph pBmpGlyphFT = reinterpret_cast<const FT_BitmapGlyph>(pGlyphFT);
1538 rRawBitmap.mnXOffset = +pBmpGlyphFT->left;
1539 rRawBitmap.mnYOffset = -pBmpGlyphFT->top;
1541 const FT_Bitmap& rBitmapFT = pBmpGlyphFT->bitmap;
1542 rRawBitmap.mnHeight = rBitmapFT.rows;
1543 rRawBitmap.mnWidth = rBitmapFT.width;
1544 rRawBitmap.mnBitCount = 8;
1545 rRawBitmap.mnScanlineSize = bEmbedded ? rBitmapFT.width : rBitmapFT.pitch;
1546 if( mbArtBold && !pFTEmbolden )
1548 ++rRawBitmap.mnWidth;
1549 ++rRawBitmap.mnScanlineSize;
1551 rRawBitmap.mnScanlineSize = (rRawBitmap.mnScanlineSize + 3) & -4;
1553 const sal_uLong nNeededSize = rRawBitmap.mnScanlineSize * rRawBitmap.mnHeight;
1554 if( rRawBitmap.mnAllocated < nNeededSize )
1556 delete[] rRawBitmap.mpBits;
1557 rRawBitmap.mnAllocated = 2*nNeededSize;
1558 rRawBitmap.mpBits = new unsigned char[ rRawBitmap.mnAllocated ];
1561 const unsigned char* pSrc = rBitmapFT.buffer;
1562 unsigned char* pDest = rRawBitmap.mpBits;
1563 if( !bEmbedded )
1565 for( int y = rRawBitmap.mnHeight, x; --y >= 0 ; )
1567 for( x = 0; x < rBitmapFT.width; ++x )
1568 *(pDest++) = *(pSrc++);
1569 for(; x < int(rRawBitmap.mnScanlineSize); ++x )
1570 *(pDest++) = 0;
1573 else
1575 for( int y = rRawBitmap.mnHeight, x; --y >= 0 ; )
1577 unsigned char nSrc = 0;
1578 for( x = 0; x < rBitmapFT.width; ++x, nSrc+=nSrc )
1580 if( (x & 7) == 0 )
1581 nSrc = *(pSrc++);
1582 *(pDest++) = (0x7F - nSrc) >> 8;
1584 for(; x < int(rRawBitmap.mnScanlineSize); ++x )
1585 *(pDest++) = 0;
1589 if( mbArtBold && !pFTEmbolden )
1591 // overlay with glyph image shifted by one left pixel
1592 unsigned char* p = rRawBitmap.mpBits;
1593 for( sal_uLong y=0; y < rRawBitmap.mnHeight; y++ )
1595 unsigned char nLastByte = 0;
1596 for( sal_uLong x=0; x < rRawBitmap.mnWidth; x++ )
1598 unsigned char nTmp = p[x];
1599 p[x] |= p[x] | nLastByte;
1600 nLastByte = nTmp;
1602 p += rRawBitmap.mnScanlineSize;
1606 if( !bEmbedded && mbUseGamma )
1608 unsigned char* p = rRawBitmap.mpBits;
1609 for( sal_uLong y=0; y < rRawBitmap.mnHeight; y++ )
1611 for( sal_uLong x=0; x < rRawBitmap.mnWidth; x++ )
1613 p[x] = aGammaTable[ p[x] ];
1615 p += rRawBitmap.mnScanlineSize;
1619 FT_Done_Glyph( pGlyphFT );
1621 // special case for 0/90/180/270 degree orientation
1622 switch( nAngle )
1624 case -900:
1625 case +900:
1626 case +1800:
1627 case +2700:
1628 rRawBitmap.Rotate( nAngle );
1629 break;
1632 return true;
1635 // -----------------------------------------------------------------------
1636 // determine unicode ranges in font
1637 // -----------------------------------------------------------------------
1639 const ImplFontCharMap* ServerFont::GetImplFontCharMap( void ) const
1641 const ImplFontCharMap* pIFCMap = mpFontInfo->GetImplFontCharMap();
1642 return pIFCMap;
1645 const ImplFontCharMap* FtFontInfo::GetImplFontCharMap( void )
1647 // check if the charmap is already cached
1648 if( mpFontCharMap )
1649 return mpFontCharMap;
1651 // get the charmap and cache it
1652 CmapResult aCmapResult;
1653 bool bOK = GetFontCodeRanges( aCmapResult );
1654 if( bOK )
1655 mpFontCharMap = new ImplFontCharMap( aCmapResult );
1656 else
1657 mpFontCharMap = ImplFontCharMap::GetDefaultMap();
1658 mpFontCharMap->AddReference();
1659 return mpFontCharMap;
1662 // TODO: merge into method GetFontCharMap()
1663 bool FtFontInfo::GetFontCodeRanges( CmapResult& rResult ) const
1665 rResult.mbSymbolic = IsSymbolFont();
1667 // TODO: is the full CmapResult needed on platforms calling this?
1668 if( FT_IS_SFNT( maFaceFT ) )
1670 sal_uLong nLength = 0;
1671 const unsigned char* pCmap = GetTable( "cmap", &nLength );
1672 if( pCmap && (nLength > 0) )
1673 if( ParseCMAP( pCmap, nLength, rResult ) )
1674 return true;
1677 typedef std::vector<sal_uInt32> U32Vector;
1678 U32Vector aCodes;
1680 // FT's coverage is available since FT>=2.1.0 (OOo-baseline>=2.1.4 => ok)
1681 aCodes.reserve( 0x1000 );
1682 FT_UInt nGlyphIndex;
1683 for( sal_uInt32 cCode = FT_Get_First_Char( maFaceFT, &nGlyphIndex );; )
1685 if( !nGlyphIndex )
1686 break;
1687 aCodes.push_back( cCode ); // first code inside range
1688 sal_uInt32 cNext = cCode;
1689 do cNext = FT_Get_Next_Char( maFaceFT, cCode, &nGlyphIndex ); while( cNext == ++cCode );
1690 aCodes.push_back( cCode ); // first code outside range
1691 cCode = cNext;
1694 const int nCount = aCodes.size();
1695 if( !nCount) {
1696 if( !rResult.mbSymbolic )
1697 return false;
1699 // we usually get here for Type1 symbol fonts
1700 aCodes.push_back( 0xF020 );
1701 aCodes.push_back( 0xF100 );
1704 sal_uInt32* pCodes = new sal_uInt32[ nCount ];
1705 for( int i = 0; i < nCount; ++i )
1706 pCodes[i] = aCodes[i];
1707 rResult.mpRangeCodes = pCodes;
1708 rResult.mnRangeCount = nCount / 2;
1709 return true;
1712 bool ServerFont::GetFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const
1714 bool bRet = false;
1716 sal_uLong nLength = 0;
1717 // load GSUB table
1718 const FT_Byte* pGSUB = mpFontInfo->GetTable("GSUB", &nLength);
1719 if (pGSUB)
1720 vcl::getTTScripts(rFontCapabilities.maGSUBScriptTags, pGSUB, nLength);
1722 // load OS/2 table
1723 const FT_Byte* pOS2 = mpFontInfo->GetTable("OS/2", &nLength);
1724 if (pOS2)
1726 bRet = vcl::getTTCoverage(
1727 rFontCapabilities.maUnicodeRange,
1728 rFontCapabilities.maCodePageRange,
1729 pOS2, nLength);
1732 return bRet;
1735 // -----------------------------------------------------------------------
1737 sal_uLong ServerFont::GetKernPairs( ImplKernPairData** ppKernPairs ) const
1739 // if no kerning info is available in the font file
1740 *ppKernPairs = NULL;
1741 if( !FT_HAS_KERNING( maFaceFT ) || !FT_IS_SFNT( maFaceFT ) )
1743 // then we have may have extra kerning info from e.g. psprint
1744 int nCount = mpFontInfo->GetExtraKernPairs( ppKernPairs );
1745 // scale the kern values to match the font size
1746 const FontSelectPattern& rFSD = GetFontSelData();
1747 int nFontWidth = rFSD.mnWidth ? rFSD.mnWidth : rFSD.mnHeight;
1748 ImplKernPairData* pKernPair = *ppKernPairs;
1749 for( int i = nCount; --i >= 0; ++pKernPair )
1751 long& rVal = pKernPair->mnKern;
1752 rVal = ((rVal * nFontWidth) + 500) / 1000;
1754 return nCount;
1757 // when font faces of different sizes share the same maFaceFT
1758 // then we have to make sure that it uses the correct maSizeFT
1759 if( maSizeFT )
1760 pFTActivateSize( maSizeFT );
1762 // first figure out which glyph pairs are involved in kerning
1763 sal_uLong nKernLength = 0;
1764 const FT_Byte* const pKern = mpFontInfo->GetTable( "kern", &nKernLength );
1765 if( !pKern )
1766 return 0;
1768 // combine TTF/OTF tables from the font file to build a vector of
1769 // unicode kerning pairs using Freetype's glyph kerning calculation
1770 // for the kerning value
1772 // TODO: is it worth to share the glyph->unicode mapping between
1773 // different instances of the same font face?
1775 typedef std::vector<ImplKernPairData> KernVector;
1776 KernVector aKernGlyphVector;
1777 ImplKernPairData aKernPair;
1778 aKernPair.mnKern = 0; // To prevent "is used uninitialized" warning...
1780 const FT_Byte* pBuffer = pKern;
1781 sal_uLong nVersion = GetUShort( pBuffer+0 );
1782 sal_uInt16 nTableCnt = GetUShort( pBuffer+2 );
1784 // Microsoft/Old TrueType style kern table
1785 if ( nVersion == 0 )
1787 pBuffer += 4;
1789 for( sal_uInt16 nTableIdx = 0; nTableIdx < nTableCnt; ++nTableIdx )
1791 // sal_uInt16 nSubVersion = GetUShort( pBuffer+0 );
1792 // sal_uInt16 nSubLength = GetUShort( pBuffer+2 );
1793 sal_uInt16 nSubCoverage = GetUShort( pBuffer+4 );
1794 pBuffer += 6;
1795 if( (nSubCoverage&0x03) != 0x01 ) // no interest in minimum info here
1796 continue;
1797 switch( nSubCoverage >> 8 )
1799 case 0: // version 0, kerning format 0
1801 sal_uInt16 nPairs = GetUShort( pBuffer );
1802 pBuffer += 8; // skip search hints
1803 aKernGlyphVector.reserve( aKernGlyphVector.size() + nPairs );
1804 for( int i = 0; i < nPairs; ++i )
1806 aKernPair.mnChar1 = GetUShort( pBuffer+0 );
1807 aKernPair.mnChar2 = GetUShort( pBuffer+2 );
1808 //long nUnscaledKern= GetSShort( pBuffer );
1809 pBuffer += 6;
1810 aKernGlyphVector.push_back( aKernPair );
1813 break;
1815 case 2: // version 0, kerning format 2
1817 const FT_Byte* pSubTable = pBuffer;
1818 //sal_uInt16 nRowWidth = GetUShort( pBuffer+0 );
1819 sal_uInt16 nOfsLeft = GetUShort( pBuffer+2 );
1820 sal_uInt16 nOfsRight = GetUShort( pBuffer+4 );
1821 sal_uInt16 nOfsArray = GetUShort( pBuffer+6 );
1822 pBuffer += 8;
1824 const FT_Byte* pTmp = pSubTable + nOfsLeft;
1825 sal_uInt16 nFirstLeft = GetUShort( pTmp+0 );
1826 sal_uInt16 nLastLeft = GetUShort( pTmp+2 ) + nFirstLeft - 1;
1828 pTmp = pSubTable + nOfsRight;
1829 sal_uInt16 nFirstRight = GetUShort( pTmp+0 );
1830 sal_uInt16 nLastRight = GetUShort( pTmp+2 ) + nFirstRight - 1;
1832 sal_uLong nPairs = (sal_uLong)(nLastLeft - nFirstLeft + 1) * (nLastRight - nFirstRight + 1);
1833 aKernGlyphVector.reserve( aKernGlyphVector.size() + nPairs );
1835 pTmp = pSubTable + nOfsArray;
1836 for( int nLeft = nFirstLeft; nLeft < nLastLeft; ++nLeft )
1838 aKernPair.mnChar1 = nLeft;
1839 for( int nRight = 0; nRight < nLastRight; ++nRight )
1841 if( GetUShort( pTmp ) != 0 )
1843 aKernPair.mnChar2 = nRight;
1844 aKernGlyphVector.push_back( aKernPair );
1846 pTmp += 2;
1850 break;
1855 // Apple New style kern table
1856 pBuffer = pKern;
1857 nVersion = NEXT_U32( pBuffer );
1858 nTableCnt = NEXT_U32( pBuffer );
1859 if ( nVersion == 0x00010000 )
1861 for( sal_uInt16 nTableIdx = 0; nTableIdx < nTableCnt; ++nTableIdx )
1863 /*sal_uLong nLength =*/ NEXT_U32( pBuffer );
1864 sal_uInt16 nCoverage = NEXT_U16( pBuffer );
1865 /*sal_uInt16 nTupleIndex =*/ NEXT_U16( pBuffer );
1867 // Kerning sub-table format, 0 through 3
1868 sal_uInt8 nSubTableFormat = nCoverage & 0x00FF;
1870 switch( nSubTableFormat )
1872 case 0: // version 0, kerning format 0
1874 sal_uInt16 nPairs = NEXT_U16( pBuffer );
1875 pBuffer += 6; // skip search hints
1876 aKernGlyphVector.reserve( aKernGlyphVector.size() + nPairs );
1877 for( int i = 0; i < nPairs; ++i )
1879 aKernPair.mnChar1 = NEXT_U16( pBuffer );
1880 aKernPair.mnChar2 = NEXT_U16( pBuffer );
1881 /*long nUnscaledKern=*/ NEXT_S16( pBuffer );
1882 aKernGlyphVector.push_back( aKernPair );
1885 break;
1887 case 2: // version 0, kerning format 2
1889 const FT_Byte* pSubTable = pBuffer;
1890 /*sal_uInt16 nRowWidth =*/ NEXT_U16( pBuffer );
1891 sal_uInt16 nOfsLeft = NEXT_U16( pBuffer );
1892 sal_uInt16 nOfsRight = NEXT_U16( pBuffer );
1893 sal_uInt16 nOfsArray = NEXT_U16( pBuffer );
1895 const FT_Byte* pTmp = pSubTable + nOfsLeft;
1896 sal_uInt16 nFirstLeft = NEXT_U16( pTmp );
1897 sal_uInt16 nLastLeft = NEXT_U16( pTmp ) + nFirstLeft - 1;
1899 pTmp = pSubTable + nOfsRight;
1900 sal_uInt16 nFirstRight = NEXT_U16( pTmp );
1901 sal_uInt16 nLastRight = NEXT_U16( pTmp ) + nFirstRight - 1;
1903 sal_uLong nPairs = (sal_uLong)(nLastLeft - nFirstLeft + 1) * (nLastRight - nFirstRight + 1);
1904 aKernGlyphVector.reserve( aKernGlyphVector.size() + nPairs );
1906 pTmp = pSubTable + nOfsArray;
1907 for( int nLeft = nFirstLeft; nLeft < nLastLeft; ++nLeft )
1909 aKernPair.mnChar1 = nLeft;
1910 for( int nRight = 0; nRight < nLastRight; ++nRight )
1912 if( NEXT_S16( pTmp ) != 0 )
1914 aKernPair.mnChar2 = nRight;
1915 aKernGlyphVector.push_back( aKernPair );
1920 break;
1922 default:
1923 fprintf( stderr, "gcach_ftyp.cxx: Found unsupported Apple-style kern subtable type %d.\n", nSubTableFormat );
1924 break;
1929 // now create VCL's ImplKernPairData[] format for all glyph pairs
1930 sal_uLong nKernCount = aKernGlyphVector.size();
1931 if( nKernCount )
1933 // prepare glyphindex to character mapping
1934 // TODO: this is needed to support VCL's existing kerning infrastructure,
1935 // eliminate it up by redesigning kerning infrastructure to work with glyph indizes
1936 typedef boost::unordered_multimap<sal_uInt16,sal_Unicode> Cmap;
1937 Cmap aCmap;
1938 for( sal_Unicode aChar = 0x0020; aChar < 0xFFFE; ++aChar )
1940 sal_uInt16 nGlyphIndex = GetGlyphIndex( aChar );
1941 if( nGlyphIndex )
1942 aCmap.insert( Cmap::value_type( nGlyphIndex, aChar ) );
1945 // translate both glyph indizes in kerning pairs to characters
1946 // problem is that these are 1:n mappings...
1947 KernVector aKernCharVector;
1948 aKernCharVector.reserve( nKernCount );
1949 KernVector::iterator it;
1950 for( it = aKernGlyphVector.begin(); it != aKernGlyphVector.end(); ++it )
1952 FT_Vector aKernVal;
1953 FT_Error rcFT = FT_Get_Kerning( maFaceFT, it->mnChar1, it->mnChar2,
1954 FT_KERNING_DEFAULT, &aKernVal );
1955 aKernPair.mnKern = aKernVal.x >> 6;
1956 if( (aKernPair.mnKern == 0) || (rcFT != FT_Err_Ok) )
1957 continue;
1959 typedef std::pair<Cmap::iterator,Cmap::iterator> CPair;
1960 const CPair p1 = aCmap.equal_range( it->mnChar1 );
1961 const CPair p2 = aCmap.equal_range( it->mnChar2 );
1962 for( Cmap::const_iterator i1 = p1.first; i1 != p1.second; ++i1 )
1964 aKernPair.mnChar1 = (*i1).second;
1965 for( Cmap::const_iterator i2 = p2.first; i2 != p2.second; ++i2 )
1967 aKernPair.mnChar2 = (*i2).second;
1968 aKernCharVector.push_back( aKernPair );
1973 // now move the resulting vector into VCL's ImplKernPairData[] format
1974 nKernCount = aKernCharVector.size();
1975 ImplKernPairData* pTo = new ImplKernPairData[ nKernCount ];
1976 *ppKernPairs = pTo;
1977 for( it = aKernCharVector.begin(); it != aKernCharVector.end(); ++it, ++pTo )
1979 pTo->mnChar1 = it->mnChar1;
1980 pTo->mnChar2 = it->mnChar2;
1981 pTo->mnKern = it->mnKern;
1985 return nKernCount;
1988 // -----------------------------------------------------------------------
1989 // outline stuff
1990 // -----------------------------------------------------------------------
1992 class PolyArgs
1994 public:
1995 PolyArgs( PolyPolygon& rPolyPoly, sal_uInt16 nMaxPoints );
1996 ~PolyArgs();
1998 void AddPoint( long nX, long nY, PolyFlags);
1999 void ClosePolygon();
2001 long GetPosX() const { return maPosition.x;}
2002 long GetPosY() const { return maPosition.y;}
2004 private:
2005 PolyPolygon& mrPolyPoly;
2007 Point* mpPointAry;
2008 sal_uInt8* mpFlagAry;
2010 FT_Vector maPosition;
2011 sal_uInt16 mnMaxPoints;
2012 sal_uInt16 mnPoints;
2013 sal_uInt16 mnPoly;
2014 bool bHasOffline;
2017 // -----------------------------------------------------------------------
2019 PolyArgs::PolyArgs( PolyPolygon& rPolyPoly, sal_uInt16 nMaxPoints )
2020 : mrPolyPoly(rPolyPoly),
2021 mnMaxPoints(nMaxPoints),
2022 mnPoints(0),
2023 mnPoly(0),
2024 bHasOffline(false)
2026 mpPointAry = new Point[ mnMaxPoints ];
2027 mpFlagAry = new sal_uInt8 [ mnMaxPoints ];
2030 // -----------------------------------------------------------------------
2033 PolyArgs::~PolyArgs()
2035 delete[] mpFlagAry;
2036 delete[] mpPointAry;
2039 // -----------------------------------------------------------------------
2041 void PolyArgs::AddPoint( long nX, long nY, PolyFlags aFlag )
2043 DBG_ASSERT( (mnPoints < mnMaxPoints), "FTGlyphOutline: AddPoint overflow!" );
2044 if( mnPoints >= mnMaxPoints )
2045 return;
2047 maPosition.x = nX;
2048 maPosition.y = nY;
2049 mpPointAry[ mnPoints ] = Point( nX, nY );
2050 mpFlagAry[ mnPoints++ ]= aFlag;
2051 bHasOffline |= (aFlag != POLY_NORMAL);
2054 // -----------------------------------------------------------------------
2056 void PolyArgs::ClosePolygon()
2058 if( !mnPoly++ )
2059 return;
2061 // freetype seems to always close the polygon with an ON_CURVE point
2062 // PolyPoly wants to close the polygon itself => remove last point
2063 DBG_ASSERT( (mnPoints >= 2), "FTGlyphOutline: PolyFinishNum failed!" );
2064 --mnPoints;
2065 DBG_ASSERT( (mpPointAry[0]==mpPointAry[mnPoints]), "FTGlyphOutline: PolyFinishEq failed!" );
2066 DBG_ASSERT( (mpFlagAry[0]==POLY_NORMAL), "FTGlyphOutline: PolyFinishFE failed!" );
2067 DBG_ASSERT( (mpFlagAry[mnPoints]==POLY_NORMAL), "FTGlyphOutline: PolyFinishFS failed!" );
2069 Polygon aPoly( mnPoints, mpPointAry, (bHasOffline ? mpFlagAry : NULL) );
2071 // #i35928#
2072 // This may be a invalid polygons, e.g. the last point is a control point.
2073 // So close the polygon (and add the first point again) if the last point
2074 // is a control point or different from first.
2075 // #i48298#
2076 // Now really duplicating the first point, to close or correct the
2077 // polygon. Also no longer duplicating the flags, but enforcing
2078 // POLY_NORMAL for the newly added last point.
2079 const sal_uInt16 nPolySize(aPoly.GetSize());
2080 if(nPolySize)
2082 if((aPoly.HasFlags() && POLY_CONTROL == aPoly.GetFlags(nPolySize - 1))
2083 || (aPoly.GetPoint(nPolySize - 1) != aPoly.GetPoint(0)))
2085 aPoly.SetSize(nPolySize + 1);
2086 aPoly.SetPoint(aPoly.GetPoint(0), nPolySize);
2088 if(aPoly.HasFlags())
2090 aPoly.SetFlags(nPolySize, POLY_NORMAL);
2095 mrPolyPoly.Insert( aPoly );
2096 mnPoints = 0;
2097 bHasOffline = false;
2100 // -----------------------------------------------------------------------
2102 extern "C" {
2104 // TODO: wait till all compilers accept that calling conventions
2105 // for functions are the same independent of implementation constness,
2106 // then uncomment the const-tokens in the function interfaces below
2107 static int FT_move_to( FT_Vector_CPtr p0, void* vpPolyArgs )
2109 PolyArgs& rA = *reinterpret_cast<PolyArgs*>(vpPolyArgs);
2111 // move_to implies a new polygon => finish old polygon first
2112 rA.ClosePolygon();
2114 rA.AddPoint( p0->x, p0->y, POLY_NORMAL );
2115 return 0;
2118 static int FT_line_to( FT_Vector_CPtr p1, void* vpPolyArgs )
2120 PolyArgs& rA = *reinterpret_cast<PolyArgs*>(vpPolyArgs);
2121 rA.AddPoint( p1->x, p1->y, POLY_NORMAL );
2122 return 0;
2125 static int FT_conic_to( FT_Vector_CPtr p1, FT_Vector_CPtr p2, void* vpPolyArgs )
2127 PolyArgs& rA = *reinterpret_cast<PolyArgs*>(vpPolyArgs);
2129 // VCL's Polygon only knows cubic beziers
2130 const long nX1 = (2 * rA.GetPosX() + 4 * p1->x + 3) / 6;
2131 const long nY1 = (2 * rA.GetPosY() + 4 * p1->y + 3) / 6;
2132 rA.AddPoint( nX1, nY1, POLY_CONTROL );
2134 const long nX2 = (2 * p2->x + 4 * p1->x + 3) / 6;
2135 const long nY2 = (2 * p2->y + 4 * p1->y + 3) / 6;
2136 rA.AddPoint( nX2, nY2, POLY_CONTROL );
2138 rA.AddPoint( p2->x, p2->y, POLY_NORMAL );
2139 return 0;
2142 static int FT_cubic_to( FT_Vector_CPtr p1, FT_Vector_CPtr p2, FT_Vector_CPtr p3, void* vpPolyArgs )
2144 PolyArgs& rA = *reinterpret_cast<PolyArgs*>(vpPolyArgs);
2145 rA.AddPoint( p1->x, p1->y, POLY_CONTROL );
2146 rA.AddPoint( p2->x, p2->y, POLY_CONTROL );
2147 rA.AddPoint( p3->x, p3->y, POLY_NORMAL );
2148 return 0;
2151 } // extern "C"
2153 // -----------------------------------------------------------------------
2155 bool ServerFont::GetGlyphOutline( int nGlyphIndex,
2156 ::basegfx::B2DPolyPolygon& rB2DPolyPoly ) const
2158 if( maSizeFT )
2159 pFTActivateSize( maSizeFT );
2161 rB2DPolyPoly.clear();
2163 int nGlyphFlags;
2164 SplitGlyphFlags( *this, nGlyphIndex, nGlyphFlags );
2166 FT_Int nLoadFlags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_TRANSFORM;
2168 #ifdef FT_LOAD_TARGET_LIGHT
2169 // enable "light hinting" if available
2170 nLoadFlags |= FT_LOAD_TARGET_LIGHT;
2171 #endif
2173 FT_Error rc = FT_Load_Glyph( maFaceFT, nGlyphIndex, nLoadFlags );
2174 if( rc != FT_Err_Ok )
2175 return false;
2177 if( mbArtBold && pFTEmbolden )
2178 (*pFTEmbolden)( maFaceFT->glyph );
2180 FT_Glyph pGlyphFT;
2181 rc = FT_Get_Glyph( maFaceFT->glyph, &pGlyphFT );
2182 if( rc != FT_Err_Ok )
2183 return false;
2185 if( pGlyphFT->format != FT_GLYPH_FORMAT_OUTLINE )
2186 return false;
2188 if( mbArtItalic )
2190 FT_Matrix aMatrix;
2191 aMatrix.xx = aMatrix.yy = 0x10000L;
2192 aMatrix.xy = 0x6000L, aMatrix.yx = 0;
2193 FT_Glyph_Transform( pGlyphFT, &aMatrix, NULL );
2196 FT_Outline& rOutline = reinterpret_cast<FT_OutlineGlyphRec*>(pGlyphFT)->outline;
2197 if( !rOutline.n_points ) // blank glyphs are ok
2198 return true;
2200 long nMaxPoints = 1 + rOutline.n_points * 3;
2201 PolyPolygon aToolPolyPolygon;
2202 PolyArgs aPolyArg( aToolPolyPolygon, nMaxPoints );
2204 /*int nAngle =*/ ApplyGlyphTransform( nGlyphFlags, pGlyphFT, false );
2206 FT_Outline_Funcs aFuncs;
2207 aFuncs.move_to = &FT_move_to;
2208 aFuncs.line_to = &FT_line_to;
2209 aFuncs.conic_to = &FT_conic_to;
2210 aFuncs.cubic_to = &FT_cubic_to;
2211 aFuncs.shift = 0;
2212 aFuncs.delta = 0;
2213 rc = FT_Outline_Decompose( &rOutline, &aFuncs, (void*)&aPolyArg );
2214 aPolyArg.ClosePolygon(); // close last polygon
2215 FT_Done_Glyph( pGlyphFT );
2217 // convert to basegfx polypolygon
2218 // TODO: get rid of the intermediate tools polypolygon
2219 rB2DPolyPoly = aToolPolyPolygon.getB2DPolyPolygon();
2220 rB2DPolyPoly.transform(basegfx::tools::createScaleB2DHomMatrix( +1.0/(1<<6), -1.0/(1<<6) ));
2222 return true;
2225 // -----------------------------------------------------------------------
2227 bool ServerFont::ApplyGSUB( const FontSelectPattern& rFSD )
2229 #define MKTAG(s) ((((((s[0]<<8)+s[1])<<8)+s[2])<<8)+s[3])
2231 typedef std::vector<sal_uLong> ReqFeatureTagList;
2232 ReqFeatureTagList aReqFeatureTagList;
2233 if( rFSD.mbVertical )
2234 aReqFeatureTagList.push_back( MKTAG("vert") );
2235 sal_uLong nRequestedScript = 0; //MKTAG("hani");//### TODO: where to get script?
2236 sal_uLong nRequestedLangsys = 0; //MKTAG("ZHT"); //### TODO: where to get langsys?
2237 // TODO: request more features depending on script and language system
2239 if( aReqFeatureTagList.empty()) // nothing to do
2240 return true;
2242 // load GSUB table into memory
2243 sal_uLong nLength = 0;
2244 const FT_Byte* const pGsubBase = mpFontInfo->GetTable( "GSUB", &nLength );
2245 if( !pGsubBase )
2246 return false;
2248 // parse GSUB header
2249 const FT_Byte* pGsubHeader = pGsubBase;
2250 const sal_uInt16 nOfsScriptList = GetUShort( pGsubHeader+4 );
2251 const sal_uInt16 nOfsFeatureTable = GetUShort( pGsubHeader+6 );
2252 const sal_uInt16 nOfsLookupList = GetUShort( pGsubHeader+8 );
2253 pGsubHeader += 10;
2255 typedef std::vector<sal_uInt16> UshortList;
2256 UshortList aFeatureIndexList;
2258 // parse Script Table
2259 const FT_Byte* pScriptHeader = pGsubBase + nOfsScriptList;
2260 const sal_uInt16 nCntScript = GetUShort( pScriptHeader+0 );
2261 pScriptHeader += 2;
2262 for( sal_uInt16 nScriptIndex = 0; nScriptIndex < nCntScript; ++nScriptIndex )
2264 const sal_uLong nScriptTag = GetUInt( pScriptHeader+0 ); // e.g. hani/arab/kana/hang
2265 const sal_uInt16 nOfsScriptTable= GetUShort( pScriptHeader+4 );
2266 pScriptHeader += 6; //###
2267 if( (nScriptTag != nRequestedScript) && (nRequestedScript != 0) )
2268 continue;
2270 const FT_Byte* pScriptTable = pGsubBase + nOfsScriptList + nOfsScriptTable;
2271 const sal_uInt16 nDefaultLangsysOfs = GetUShort( pScriptTable+0 );
2272 const sal_uInt16 nCntLangSystem = GetUShort( pScriptTable+2 );
2273 pScriptTable += 4;
2274 sal_uInt16 nLangsysOffset = 0;
2276 for( sal_uInt16 nLangsysIndex = 0; nLangsysIndex < nCntLangSystem; ++nLangsysIndex )
2278 const sal_uLong nTag = GetUInt( pScriptTable+0 ); // e.g. KOR/ZHS/ZHT/JAN
2279 const sal_uInt16 nOffset= GetUShort( pScriptTable+4 );
2280 pScriptTable += 6;
2281 if( (nTag != nRequestedLangsys) && (nRequestedLangsys != 0) )
2282 continue;
2283 nLangsysOffset = nOffset;
2284 break;
2287 if( (nDefaultLangsysOfs != 0) && (nDefaultLangsysOfs != nLangsysOffset) )
2289 const FT_Byte* pLangSys = pGsubBase + nOfsScriptList + nOfsScriptTable + nDefaultLangsysOfs;
2290 const sal_uInt16 nReqFeatureIdx = GetUShort( pLangSys+2 );
2291 const sal_uInt16 nCntFeature = GetUShort( pLangSys+4 );
2292 pLangSys += 6;
2293 aFeatureIndexList.push_back( nReqFeatureIdx );
2294 for( sal_uInt16 i = 0; i < nCntFeature; ++i )
2296 const sal_uInt16 nFeatureIndex = GetUShort( pLangSys );
2297 pLangSys += 2;
2298 aFeatureIndexList.push_back( nFeatureIndex );
2302 if( nLangsysOffset != 0 )
2304 const FT_Byte* pLangSys = pGsubBase + nOfsScriptList + nOfsScriptTable + nLangsysOffset;
2305 const sal_uInt16 nReqFeatureIdx = GetUShort( pLangSys+2 );
2306 const sal_uInt16 nCntFeature = GetUShort( pLangSys+4 );
2307 pLangSys += 6;
2308 aFeatureIndexList.push_back( nReqFeatureIdx );
2309 for( sal_uInt16 i = 0; i < nCntFeature; ++i )
2311 const sal_uInt16 nFeatureIndex = GetUShort( pLangSys );
2312 pLangSys += 2;
2313 aFeatureIndexList.push_back( nFeatureIndex );
2318 if( aFeatureIndexList.empty() )
2319 return true;
2321 UshortList aLookupIndexList;
2322 UshortList aLookupOffsetList;
2324 // parse Feature Table
2325 const FT_Byte* pFeatureHeader = pGsubBase + nOfsFeatureTable;
2326 const sal_uInt16 nCntFeature = GetUShort( pFeatureHeader );
2327 pFeatureHeader += 2;
2328 for( sal_uInt16 nFeatureIndex = 0; nFeatureIndex < nCntFeature; ++nFeatureIndex )
2330 const sal_uLong nTag = GetUInt( pFeatureHeader+0 ); // e.g. locl/vert/trad/smpl/liga/fina/...
2331 const sal_uInt16 nOffset= GetUShort( pFeatureHeader+4 );
2332 pFeatureHeader += 6;
2334 // short circuit some feature lookups
2335 if( aFeatureIndexList[0] != nFeatureIndex ) // required feature?
2337 const int nRequested = std::count( aFeatureIndexList.begin(), aFeatureIndexList.end(), nFeatureIndex);
2338 if( !nRequested ) // ignore features that are not requested
2339 continue;
2340 const int nAvailable = std::count( aReqFeatureTagList.begin(), aReqFeatureTagList.end(), nTag);
2341 if( !nAvailable ) // some fonts don't provide features they request!
2342 continue;
2345 const FT_Byte* pFeatureTable = pGsubBase + nOfsFeatureTable + nOffset;
2346 const sal_uInt16 nCntLookups = GetUShort( pFeatureTable+0 );
2347 pFeatureTable += 2;
2348 for( sal_uInt16 i = 0; i < nCntLookups; ++i )
2350 const sal_uInt16 nLookupIndex = GetUShort( pFeatureTable );
2351 pFeatureTable += 2;
2352 aLookupIndexList.push_back( nLookupIndex );
2354 if( nCntLookups == 0 ) //### hack needed by Mincho/Gothic/Mingliu/Simsun/...
2355 aLookupIndexList.push_back( 0 );
2358 // parse Lookup List
2359 const FT_Byte* pLookupHeader = pGsubBase + nOfsLookupList;
2360 const sal_uInt16 nCntLookupTable = GetUShort( pLookupHeader );
2361 pLookupHeader += 2;
2362 for( sal_uInt16 nLookupIdx = 0; nLookupIdx < nCntLookupTable; ++nLookupIdx )
2364 const sal_uInt16 nOffset = GetUShort( pLookupHeader );
2365 pLookupHeader += 2;
2366 if( std::count( aLookupIndexList.begin(), aLookupIndexList.end(), nLookupIdx ) )
2367 aLookupOffsetList.push_back( nOffset );
2370 UshortList::const_iterator lookup_it = aLookupOffsetList.begin();
2371 for(; lookup_it != aLookupOffsetList.end(); ++lookup_it )
2373 const sal_uInt16 nOfsLookupTable = *lookup_it;
2374 const FT_Byte* pLookupTable = pGsubBase + nOfsLookupList + nOfsLookupTable;
2375 const sal_uInt16 eLookupType = GetUShort( pLookupTable+0 );
2376 const sal_uInt16 nCntLookupSubtable = GetUShort( pLookupTable+4 );
2377 pLookupTable += 6;
2379 // TODO: switch( eLookupType )
2380 if( eLookupType != 1 ) // TODO: once we go beyond SingleSubst
2381 continue;
2383 for( sal_uInt16 nSubTableIdx = 0; nSubTableIdx < nCntLookupSubtable; ++nSubTableIdx )
2385 const sal_uInt16 nOfsSubLookupTable = GetUShort( pLookupTable );
2386 pLookupTable += 2;
2387 const FT_Byte* pSubLookup = pGsubBase + nOfsLookupList + nOfsLookupTable + nOfsSubLookupTable;
2389 const sal_uInt16 nFmtSubstitution = GetUShort( pSubLookup+0 );
2390 const sal_uInt16 nOfsCoverage = GetUShort( pSubLookup+2 );
2391 pSubLookup += 4;
2393 typedef std::pair<sal_uInt16,sal_uInt16> GlyphSubst;
2394 typedef std::vector<GlyphSubst> SubstVector;
2395 SubstVector aSubstVector;
2397 const FT_Byte* pCoverage = pGsubBase + nOfsLookupList + nOfsLookupTable + nOfsSubLookupTable + nOfsCoverage;
2398 const sal_uInt16 nFmtCoverage = GetUShort( pCoverage+0 );
2399 pCoverage += 2;
2400 switch( nFmtCoverage )
2402 case 1: // Coverage Format 1
2404 const sal_uInt16 nCntGlyph = GetUShort( pCoverage );
2405 pCoverage += 2;
2406 aSubstVector.reserve( nCntGlyph );
2407 for( sal_uInt16 i = 0; i < nCntGlyph; ++i )
2409 const sal_uInt16 nGlyphId = GetUShort( pCoverage );
2410 pCoverage += 2;
2411 aSubstVector.push_back( GlyphSubst( nGlyphId, 0 ) );
2414 break;
2416 case 2: // Coverage Format 2
2418 const sal_uInt16 nCntRange = GetUShort( pCoverage );
2419 pCoverage += 2;
2420 for( int i = nCntRange; --i >= 0; )
2422 const sal_uInt32 nGlyph0 = GetUShort( pCoverage+0 );
2423 const sal_uInt32 nGlyph1 = GetUShort( pCoverage+2 );
2424 const sal_uInt16 nCovIdx = GetUShort( pCoverage+4 );
2425 pCoverage += 6;
2426 for( sal_uInt32 j = nGlyph0; j <= nGlyph1; ++j )
2427 aSubstVector.push_back( GlyphSubst( static_cast<sal_uInt16>(j + nCovIdx), 0 ) );
2430 break;
2433 SubstVector::iterator it( aSubstVector.begin() );
2435 switch( nFmtSubstitution )
2437 case 1: // Single Substitution Format 1
2439 const sal_uInt16 nDeltaGlyphId = GetUShort( pSubLookup );
2440 pSubLookup += 2;
2441 for(; it != aSubstVector.end(); ++it )
2442 (*it).second = (*it).first + nDeltaGlyphId;
2444 break;
2446 case 2: // Single Substitution Format 2
2448 const sal_uInt16 nCntGlyph = GetUShort( pSubLookup );
2449 pSubLookup += 2;
2450 for( int i = nCntGlyph; (it != aSubstVector.end()) && (--i>=0); ++it )
2452 const sal_uInt16 nGlyphId = GetUShort( pSubLookup );
2453 pSubLookup += 2;
2454 (*it).second = nGlyphId;
2457 break;
2460 DBG_ASSERT( (it == aSubstVector.end()), "lookup<->coverage table mismatch" );
2461 // now apply the glyph substitutions that have been collected in this subtable
2462 for( it = aSubstVector.begin(); it != aSubstVector.end(); ++it )
2463 maGlyphSubstitution[ (*it).first ] = (*it).second;
2467 return true;
2470 const unsigned char* ServerFont::GetTable(const char* pName, sal_uLong* pLength)
2472 return mpFontInfo->GetTable( pName, pLength );
2475 #if ENABLE_GRAPHITE
2476 GraphiteFaceWrapper* ServerFont::GetGraphiteFace() const
2478 return mpFontInfo->GetGraphiteFace();
2480 #endif
2482 // =======================================================================
2484 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */