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