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