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 : #include "gcach_ftyp.hxx"
21 :
22 : #include "vcl/svapp.hxx"
23 : #include <outfont.hxx>
24 : #include <impfont.hxx>
25 : #include <config_features.h>
26 : #include <config_graphite.h>
27 : #if ENABLE_GRAPHITE
28 : # include <graphite_static.hxx>
29 : # include <graphite2/Font.h>
30 : # include <graphite_layout.hxx>
31 : #endif
32 : #include <unotools/fontdefs.hxx>
33 :
34 : #include "tools/poly.hxx"
35 : #include "basegfx/matrix/b2dhommatrix.hxx"
36 : #include "basegfx/matrix/b2dhommatrixtools.hxx"
37 : #include "basegfx/polygon/b2dpolypolygon.hxx"
38 :
39 : #include "osl/file.hxx"
40 : #include "osl/thread.hxx"
41 :
42 : #include "langboost.hxx"
43 : #include "PhysicalFontCollection.hxx"
44 : #include "sft.hxx"
45 :
46 : #include <ft2build.h>
47 : #include FT_FREETYPE_H
48 : #include FT_GLYPH_H
49 : #include FT_OUTLINE_H
50 : #include FT_SIZES_H
51 : #include FT_SYNTHESIS_H
52 : #include FT_TRUETYPE_TABLES_H
53 : #include FT_TRUETYPE_TAGS_H
54 : #include FT_TRUETYPE_IDS_H
55 :
56 : #include "rtl/instance.hxx"
57 :
58 : typedef const FT_Vector* FT_Vector_CPtr;
59 :
60 : #include <vector>
61 :
62 : // TODO: move file mapping stuff to OSL
63 : #include <unistd.h>
64 : #include <fcntl.h>
65 : #include <sys/stat.h>
66 : #include <sys/mman.h>
67 : #include "fontmanager.hxx"
68 :
69 : // the gamma table makes artificial bold look better for CJK glyphs
70 : static unsigned char aGammaTable[257];
71 :
72 136 : static void InitGammaTable()
73 : {
74 : static const int M_MAX = 255;
75 : static const int M_X = 128;
76 : static const int M_Y = 208;
77 :
78 : int x, a;
79 34952 : for( x = 0; x < 256; x++)
80 : {
81 34816 : if ( x <= M_X )
82 17544 : a = ( x * M_Y + M_X / 2) / M_X;
83 : else
84 17272 : a = M_Y + ( ( x - M_X ) * ( M_MAX - M_Y ) +
85 17272 : ( M_MAX - M_X ) / 2 ) / ( M_MAX - M_X );
86 :
87 34816 : aGammaTable[x] = (unsigned char)a;
88 : }
89 136 : }
90 :
91 : static FT_Library aLibFT = 0;
92 :
93 : // enable linking with old FT versions
94 : static int nFTVERSION = 0;
95 :
96 : typedef ::boost::unordered_map<const char*, boost::shared_ptr<FtFontFile>, rtl::CStringHash, rtl::CStringEqual> FontFileList;
97 :
98 : namespace { struct vclFontFileList : public rtl::Static< FontFileList, vclFontFileList > {}; }
99 :
100 : // TODO: remove when the priorities are selected by UI
101 : // if (AH==0) => disable autohinting
102 : // if (AA==0) => disable antialiasing
103 : // if (EB==0) => disable embedded bitmaps
104 : // if (AA prio <= AH prio) => antialias + autohint
105 : // if (AH<AA) => do not autohint when antialiasing
106 : // if (EB<AH) => do not autohint for monochrome
107 : static int nDefaultPrioEmbedded = 2;
108 : static int nDefaultPrioAutoHint = 1;
109 : static int nDefaultPrioAntiAlias = 1;
110 :
111 : // FreetypeManager
112 :
113 27880 : FtFontFile::FtFontFile( const OString& rNativeFileName )
114 : : maNativeFileName( rNativeFileName ),
115 : mpFileMap( NULL ),
116 : mnFileSize( 0 ),
117 : mnRefCount( 0 ),
118 27880 : mnLangBoost( 0 )
119 : {
120 : // boost font preference if UI language is mentioned in filename
121 27880 : int nPos = maNativeFileName.lastIndexOf( '_' );
122 27880 : if( nPos == -1 || maNativeFileName[nPos+1] == '.' )
123 25568 : mnLangBoost += 0x1000; // no langinfo => good
124 : else
125 : {
126 : static const char* pLangBoost = NULL;
127 : static bool bOnce = true;
128 2312 : if( bOnce )
129 : {
130 136 : bOnce = false;
131 136 : pLangBoost = vcl::getLangBoost();
132 : }
133 :
134 2312 : if( pLangBoost && !strncasecmp( pLangBoost, &maNativeFileName.getStr()[nPos+1], 3 ) )
135 0 : mnLangBoost += 0x2000; // matching langinfo => better
136 : }
137 27880 : }
138 :
139 28560 : FtFontFile* FtFontFile::FindFontFile( const OString& rNativeFileName )
140 : {
141 : // font file already known? (e.g. for ttc, synthetic, aliased fonts)
142 28560 : const char* pFileName = rNativeFileName.getStr();
143 28560 : FontFileList &rFontFileList = vclFontFileList::get();
144 28560 : FontFileList::const_iterator it = rFontFileList.find( pFileName );
145 28560 : if( it != rFontFileList.end() )
146 680 : return it->second.get();
147 :
148 : // no => create new one
149 27880 : FtFontFile* pFontFile = new FtFontFile( rNativeFileName );
150 27880 : pFileName = pFontFile->maNativeFileName.getStr();
151 27880 : rFontFileList[pFileName].reset(pFontFile);
152 27880 : return pFontFile;
153 : }
154 :
155 569 : bool FtFontFile::Map()
156 : {
157 569 : if( mnRefCount++ <= 0 )
158 : {
159 569 : const char* pFileName = maNativeFileName.getStr();
160 569 : int nFile = open( pFileName, O_RDONLY );
161 569 : if( nFile < 0 )
162 0 : return false;
163 :
164 : struct stat aStat;
165 569 : int nRet = fstat( nFile, &aStat );
166 569 : if (nRet < 0)
167 : {
168 0 : close (nFile);
169 0 : return false;
170 : }
171 569 : mnFileSize = aStat.st_size;
172 : mpFileMap = (const unsigned char*)
173 569 : mmap( NULL, mnFileSize, PROT_READ, MAP_SHARED, nFile, 0 );
174 569 : if( mpFileMap == MAP_FAILED )
175 0 : mpFileMap = NULL;
176 569 : close( nFile );
177 : }
178 :
179 569 : return (mpFileMap != NULL);
180 : }
181 :
182 569 : void FtFontFile::Unmap()
183 : {
184 569 : if( (--mnRefCount > 0) || (mpFileMap == NULL) )
185 569 : return;
186 :
187 569 : munmap( (char*)mpFileMap, mnFileSize );
188 569 : mpFileMap = NULL;
189 : }
190 :
191 : #if ENABLE_GRAPHITE
192 : // wrap FtFontInfo's table function
193 0 : const void * graphiteFontTable(const void* appFaceHandle, unsigned int name, size_t *len)
194 : {
195 0 : const FtFontInfo * pFontInfo = reinterpret_cast<const FtFontInfo*>(appFaceHandle);
196 : typedef union {
197 : char m_c[5];
198 : unsigned int m_id;
199 : } TableId;
200 : TableId tableId;
201 0 : tableId.m_id = name;
202 : #ifndef OSL_BIGENDIAN
203 : TableId swapped;
204 0 : swapped.m_c[3] = tableId.m_c[0];
205 0 : swapped.m_c[2] = tableId.m_c[1];
206 0 : swapped.m_c[1] = tableId.m_c[2];
207 0 : swapped.m_c[0] = tableId.m_c[3];
208 0 : tableId.m_id = swapped.m_id;
209 : #endif
210 0 : tableId.m_c[4] = '\0';
211 0 : sal_uLong nLength = 0;
212 0 : const void * pTable = static_cast<const void*>(pFontInfo->GetTable(tableId.m_c, &nLength));
213 0 : if (len) *len = static_cast<size_t>(nLength);
214 0 : return pTable;
215 : }
216 : #endif
217 :
218 28560 : FtFontInfo::FtFontInfo( const ImplDevFontAttributes& rDevFontAttributes,
219 : const OString& rNativeFileName, int nFaceNum, sal_IntPtr nFontId, int nSynthetic)
220 : :
221 : maFaceFT( NULL ),
222 28560 : mpFontFile( FtFontFile::FindFontFile( rNativeFileName ) ),
223 : mnFaceNum( nFaceNum ),
224 : mnRefCount( 0 ),
225 : mnSynthetic( nSynthetic ),
226 : #if ENABLE_GRAPHITE
227 : mbCheckedGraphite(false),
228 : mpGraphiteFace(NULL),
229 : #endif
230 : mnFontId( nFontId ),
231 : maDevFontAttributes( rDevFontAttributes ),
232 : mpFontCharMap( NULL ),
233 : mpChar2Glyph( NULL ),
234 57120 : mpGlyph2Char( NULL )
235 : {
236 : // prefer font with low ID
237 28560 : maDevFontAttributes.mnQuality += 10000 - nFontId;
238 : // prefer font with matching file names
239 28560 : maDevFontAttributes.mnQuality += mpFontFile->GetLangBoost();
240 28560 : }
241 :
242 57120 : FtFontInfo::~FtFontInfo()
243 : {
244 28560 : if( mpFontCharMap )
245 160 : mpFontCharMap->DeReference();
246 28560 : delete mpChar2Glyph;
247 28560 : delete mpGlyph2Char;
248 : #if ENABLE_GRAPHITE
249 28560 : delete mpGraphiteFace;
250 : #endif
251 28560 : }
252 :
253 566 : void FtFontInfo::InitHashes() const
254 : {
255 : // TODO: avoid pointers when empty stl::hash_* objects become cheap
256 566 : mpChar2Glyph = new Int2IntMap();
257 566 : mpGlyph2Char = new Int2IntMap();
258 566 : }
259 :
260 3702 : FT_FaceRec_* FtFontInfo::GetFaceFT()
261 : {
262 3702 : if (!maFaceFT && mpFontFile->Map())
263 : {
264 : FT_Error rc = FT_New_Memory_Face( aLibFT,
265 569 : (FT_Byte*)mpFontFile->GetBuffer(),
266 1138 : mpFontFile->GetFileSize(), mnFaceNum, &maFaceFT );
267 569 : if( (rc != FT_Err_Ok) || (maFaceFT->num_glyphs <= 0) )
268 0 : maFaceFT = NULL;
269 : }
270 :
271 3702 : ++mnRefCount;
272 3702 : return maFaceFT;
273 : }
274 :
275 : #if ENABLE_GRAPHITE
276 2227 : GraphiteFaceWrapper * FtFontInfo::GetGraphiteFace()
277 : {
278 2227 : if (mbCheckedGraphite)
279 2183 : return mpGraphiteFace;
280 : // test for graphite here so that it is cached most efficiently
281 44 : if (GetTable("Silf", 0))
282 : {
283 0 : static const char* pGraphiteCacheStr = getenv( "SAL_GRAPHITE_CACHE_SIZE" );
284 0 : int graphiteSegCacheSize = pGraphiteCacheStr ? (atoi(pGraphiteCacheStr)) : 0;
285 : gr_face * pGraphiteFace;
286 0 : if (graphiteSegCacheSize > 500)
287 0 : pGraphiteFace = gr_make_face_with_seg_cache(this, graphiteFontTable, graphiteSegCacheSize, gr_face_cacheCmap);
288 : else
289 0 : pGraphiteFace = gr_make_face(this, graphiteFontTable, gr_face_cacheCmap);
290 0 : if (pGraphiteFace)
291 0 : mpGraphiteFace = new GraphiteFaceWrapper(pGraphiteFace);
292 : }
293 44 : mbCheckedGraphite = true;
294 44 : return mpGraphiteFace;
295 : }
296 : #endif
297 :
298 3702 : void FtFontInfo::ReleaseFaceFT()
299 : {
300 3702 : if (--mnRefCount <= 0)
301 : {
302 569 : FT_Done_Face( maFaceFT );
303 569 : maFaceFT = NULL;
304 569 : mpFontFile->Unmap();
305 : }
306 3702 : }
307 :
308 32050 : static unsigned GetUInt( const unsigned char* p ) { return((p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3]);}
309 13587 : static unsigned GetUShort( const unsigned char* p ){ return((p[0]<<8)+p[1]);}
310 : //static signed GetSShort( const unsigned char* p ){ return((short)((p[0]<<8)+p[1]));}
311 :
312 : static const sal_uInt32 T_true = 0x74727565; /* 'true' */
313 : static const sal_uInt32 T_ttcf = 0x74746366; /* 'ttcf' */
314 : static const sal_uInt32 T_otto = 0x4f54544f; /* 'OTTO' */
315 :
316 12565 : const unsigned char* FtFontInfo::GetTable( const char* pTag, sal_uLong* pLength ) const
317 : {
318 12565 : const unsigned char* pBuffer = mpFontFile->GetBuffer();
319 12565 : int nFileSize = mpFontFile->GetFileSize();
320 12565 : if( !pBuffer || nFileSize<1024 )
321 0 : return NULL;
322 :
323 : // we currently handle TTF, TTC and OTF headers
324 12565 : unsigned nFormat = GetUInt( pBuffer );
325 :
326 12565 : const unsigned char* p = pBuffer + 12;
327 12565 : if( nFormat == T_ttcf ) // TTC_MAGIC
328 32 : p += GetUInt( p + 4 * mnFaceNum );
329 12533 : else if( nFormat != 0x00010000 && nFormat != T_true && nFormat != T_otto) // TTF_MAGIC and Apple TTF Magic and PS-OpenType font
330 448 : return NULL;
331 :
332 : // walk table directory until match
333 12117 : int nTables = GetUShort( p - 8 );
334 12117 : if( nTables >= 64 ) // something fishy?
335 0 : return NULL;
336 83424 : for( int i = 0; i < nTables; ++i, p+=16 )
337 : {
338 80681 : if( p[0]==pTag[0] && p[1]==pTag[1] && p[2]==pTag[2] && p[3]==pTag[3] )
339 : {
340 9374 : sal_uLong nLength = GetUInt( p + 12 );
341 9374 : if( pLength != NULL )
342 9374 : *pLength = nLength;
343 9374 : const unsigned char* pTable = pBuffer + GetUInt( p + 8 );
344 9374 : if( (pTable + nLength) <= (mpFontFile->GetBuffer() + nFileSize) )
345 9374 : return pTable;
346 : }
347 : }
348 :
349 2743 : return NULL;
350 : }
351 :
352 28980 : void FtFontInfo::AnnounceFont( PhysicalFontCollection* pFontCollection )
353 : {
354 28980 : ImplFTSFontData* pFD = new ImplFTSFontData( this, maDevFontAttributes );
355 28980 : pFontCollection->Add( pFD );
356 28980 : }
357 :
358 136 : FreetypeManager::FreetypeManager()
359 136 : : mnMaxFontId( 0 )
360 : {
361 136 : /*FT_Error rcFT =*/ FT_Init_FreeType( &aLibFT );
362 :
363 136 : FT_Int nMajor = 0, nMinor = 0, nPatch = 0;
364 136 : FT_Library_Version(aLibFT, &nMajor, &nMinor, &nPatch);
365 136 : nFTVERSION = nMajor * 1000 + nMinor * 100 + nPatch;
366 :
367 : // TODO: remove when the priorities are selected by UI
368 : char* pEnv;
369 136 : pEnv = ::getenv( "SAL_EMBEDDED_BITMAP_PRIORITY" );
370 136 : if( pEnv )
371 0 : nDefaultPrioEmbedded = pEnv[0] - '0';
372 136 : pEnv = ::getenv( "SAL_ANTIALIASED_TEXT_PRIORITY" );
373 136 : if( pEnv )
374 0 : nDefaultPrioAntiAlias = pEnv[0] - '0';
375 136 : pEnv = ::getenv( "SAL_AUTOHINTING_PRIORITY" );
376 136 : if( pEnv )
377 0 : nDefaultPrioAutoHint = pEnv[0] - '0';
378 :
379 136 : InitGammaTable();
380 136 : vclFontFileList::get();
381 136 : }
382 :
383 1128011 : FT_Face ServerFont::GetFtFace() const
384 : {
385 1128011 : FT_Activate_Size( maSizeFT );
386 :
387 1128011 : return maFaceFT;
388 : }
389 :
390 272 : FreetypeManager::~FreetypeManager()
391 : {
392 136 : ClearFontList();
393 136 : }
394 :
395 28980 : void FreetypeManager::AddFontFile( const OString& rNormalizedName,
396 : int nFaceNum, sal_IntPtr nFontId, const ImplDevFontAttributes& rDevFontAttr)
397 : {
398 28980 : if( rNormalizedName.isEmpty() )
399 0 : return;
400 :
401 28980 : if( maFontList.find( nFontId ) != maFontList.end() )
402 420 : return;
403 :
404 : FtFontInfo* pFontInfo = new FtFontInfo( rDevFontAttr,
405 28560 : rNormalizedName, nFaceNum, nFontId, 0);
406 28560 : maFontList[ nFontId ] = pFontInfo;
407 28560 : if( mnMaxFontId < nFontId )
408 136 : mnMaxFontId = nFontId;
409 : }
410 :
411 138 : void FreetypeManager::AnnounceFonts( PhysicalFontCollection* pToAdd ) const
412 : {
413 29118 : for( FontList::const_iterator it = maFontList.begin(); it != maFontList.end(); ++it )
414 : {
415 28980 : FtFontInfo* pFtFontInfo = it->second;
416 28980 : pFtFontInfo->AnnounceFont( pToAdd );
417 : }
418 138 : }
419 :
420 136 : void FreetypeManager::ClearFontList( )
421 : {
422 28696 : for( FontList::iterator it = maFontList.begin(); it != maFontList.end(); ++it )
423 : {
424 28560 : FtFontInfo* pFtFontInfo = it->second;
425 28560 : delete pFtFontInfo;
426 : }
427 136 : maFontList.clear();
428 136 : }
429 :
430 3702 : ServerFont* FreetypeManager::CreateFont( const FontSelectPattern& rFSD )
431 : {
432 3702 : FtFontInfo* pFontInfo = NULL;
433 :
434 : // find a FontInfo matching to the font id
435 3702 : sal_IntPtr nFontId = reinterpret_cast<sal_IntPtr>( rFSD.mpFontData );
436 3702 : FontList::iterator it = maFontList.find( nFontId );
437 3702 : if( it != maFontList.end() )
438 3702 : pFontInfo = it->second;
439 :
440 3702 : if( !pFontInfo )
441 0 : return NULL;
442 :
443 3702 : ServerFont* pNew = new ServerFont( rFSD, pFontInfo );
444 :
445 3702 : return pNew;
446 : }
447 :
448 28980 : ImplFTSFontData::ImplFTSFontData( FtFontInfo* pFI, const ImplDevFontAttributes& rDFA )
449 : : PhysicalFontFace( rDFA, IFTSFONT_MAGIC ),
450 28980 : mpFtFontInfo( pFI )
451 : {
452 28980 : mbDevice = false;
453 28980 : mbOrientation = true;
454 28980 : }
455 :
456 8633 : ImplFontEntry* ImplFTSFontData::CreateFontInstance( FontSelectPattern& rFSD ) const
457 : {
458 8633 : ImplServerFontEntry* pEntry = new ImplServerFontEntry( rFSD );
459 8633 : return pEntry;
460 : }
461 :
462 : // ServerFont
463 :
464 3702 : ServerFont::ServerFont( const FontSelectPattern& rFSD, FtFontInfo* pFI )
465 : : maGlyphList( 0),
466 : maFontSelData(rFSD),
467 : mnRefCount(1),
468 : mnBytesUsed( sizeof(ServerFont) ),
469 : mpPrevGCFont( NULL ),
470 : mpNextGCFont( NULL ),
471 : mnCos( 0x10000),
472 : mnSin( 0 ),
473 : mbCollectedZW( false ),
474 : mnPrioEmbedded(nDefaultPrioEmbedded),
475 : mnPrioAntiAlias(nDefaultPrioAntiAlias),
476 : mnPrioAutoHint(nDefaultPrioAutoHint),
477 : mpFontInfo( pFI ),
478 : maFaceFT( NULL ),
479 : maSizeFT( NULL ),
480 : mbFaceOk( false ),
481 3702 : mpLayoutEngine( NULL )
482 : {
483 : // TODO: move update of mpFontEntry into FontEntry class when
484 : // it becomes reponsible for the ServerFont instantiation
485 3702 : ((ImplServerFontEntry*)rFSD.mpFontEntry)->SetServerFont( this );
486 :
487 3702 : if( rFSD.mnOrientation != 0 )
488 : {
489 149 : const double dRad = rFSD.mnOrientation * ( F_2PI / 3600.0 );
490 149 : mnCos = static_cast<long>( 0x10000 * cos( dRad ) + 0.5 );
491 149 : mnSin = static_cast<long>( 0x10000 * sin( dRad ) + 0.5 );
492 : }
493 :
494 3702 : maFaceFT = pFI->GetFaceFT();
495 :
496 3702 : if( !maFaceFT )
497 0 : return;
498 :
499 : // set the pixel size of the font instance
500 3702 : mnWidth = rFSD.mnWidth;
501 3702 : if( !mnWidth )
502 3280 : mnWidth = rFSD.mnHeight;
503 3702 : mfStretch = (double)mnWidth / rFSD.mnHeight;
504 : // sanity check (e.g. #i66394#, #i66244#, #66537#)
505 3702 : if( (mnWidth < 0) || (mfStretch > +64.0) || (mfStretch < -64.0) )
506 0 : return;
507 :
508 3702 : FT_New_Size( maFaceFT, &maSizeFT );
509 3702 : FT_Activate_Size( maSizeFT );
510 3702 : FT_Error rc = FT_Set_Pixel_Sizes( maFaceFT, mnWidth, rFSD.mnHeight );
511 3702 : if( rc != FT_Err_Ok )
512 0 : return;
513 :
514 3702 : FT_Select_Charmap(maFaceFT, FT_ENCODING_UNICODE);
515 :
516 3702 : if( mpFontInfo->IsSymbolFont() )
517 : {
518 17 : FT_Encoding eEncoding = FT_ENCODING_MS_SYMBOL;
519 17 : if (!FT_IS_SFNT(maFaceFT))
520 17 : eEncoding = FT_ENCODING_ADOBE_CUSTOM; // freetype wants this for PS symbol fonts
521 :
522 17 : FT_Select_Charmap(maFaceFT, eEncoding);
523 : }
524 :
525 3702 : mbFaceOk = true;
526 :
527 3702 : ApplyGSUB( rFSD );
528 :
529 : // TODO: query GASP table for load flags
530 3702 : mnLoadFlags = FT_LOAD_DEFAULT;
531 : #if 1 // #i97326# cairo sometimes uses FT_Set_Transform() on our FT_FACE
532 : // we are not using FT_Set_Transform() yet, so just ignore it for now
533 3702 : mnLoadFlags |= FT_LOAD_IGNORE_TRANSFORM;
534 : #endif
535 :
536 3702 : mbArtItalic = (rFSD.GetSlant() != ITALIC_NONE && pFI->GetFontAttributes().GetSlant() == ITALIC_NONE);
537 3702 : mbArtBold = (rFSD.GetWeight() > WEIGHT_MEDIUM && pFI->GetFontAttributes().GetWeight() <= WEIGHT_MEDIUM);
538 3702 : mbUseGamma = false;
539 3702 : if( mbArtBold )
540 : {
541 : //static const int TT_CODEPAGE_RANGE_874 = (1L << 16); // Thai
542 : //static const int TT_CODEPAGE_RANGE_932 = (1L << 17); // JIS/Japan
543 : //static const int TT_CODEPAGE_RANGE_936 = (1L << 18); // Chinese: Simplified
544 : //static const int TT_CODEPAGE_RANGE_949 = (1L << 19); // Korean Wansung
545 : //static const int TT_CODEPAGE_RANGE_950 = (1L << 20); // Chinese: Traditional
546 : //static const int TT_CODEPAGE_RANGE_1361 = (1L << 21); // Korean Johab
547 : static const int TT_CODEPAGE_RANGES1_CJKT = 0x3F0000; // all of the above
548 6 : const TT_OS2* pOs2 = (const TT_OS2*)FT_Get_Sfnt_Table( maFaceFT, ft_sfnt_os2 );
549 6 : if ((pOs2) && (pOs2->ulCodePageRange1 & TT_CODEPAGE_RANGES1_CJKT )
550 3 : && rFSD.mnHeight < 20)
551 1 : mbUseGamma = true;
552 : }
553 :
554 3702 : if( ((mnCos != 0) && (mnSin != 0)) || (mnPrioEmbedded <= 0) )
555 73 : mnLoadFlags |= FT_LOAD_NO_BITMAP;
556 : }
557 :
558 0 : void ServerFont::SetFontOptions( boost::shared_ptr<ImplFontOptions> pFontOptions)
559 : {
560 0 : mpFontOptions = pFontOptions;
561 :
562 0 : if (!mpFontOptions)
563 0 : return;
564 :
565 0 : FontAutoHint eHint = mpFontOptions->GetUseAutoHint();
566 0 : if( eHint == AUTOHINT_DONTKNOW )
567 0 : eHint = mbUseGamma ? AUTOHINT_TRUE : AUTOHINT_FALSE;
568 :
569 0 : if( eHint == AUTOHINT_TRUE )
570 0 : mnLoadFlags |= FT_LOAD_FORCE_AUTOHINT;
571 :
572 0 : if( (mnSin != 0) && (mnCos != 0) ) // hinting for 0/90/180/270 degrees only
573 0 : mnLoadFlags |= FT_LOAD_NO_HINTING;
574 0 : mnLoadFlags |= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH; //#88334#
575 :
576 0 : if( mpFontOptions->DontUseAntiAlias() )
577 0 : mnPrioAntiAlias = 0;
578 0 : if( mpFontOptions->DontUseEmbeddedBitmaps() )
579 0 : mnPrioEmbedded = 0;
580 0 : if( mpFontOptions->DontUseHinting() )
581 0 : mnPrioAutoHint = 0;
582 :
583 0 : if( mnPrioAutoHint <= 0 )
584 0 : mnLoadFlags |= FT_LOAD_NO_HINTING;
585 :
586 : #if defined(FT_LOAD_TARGET_LIGHT) && defined(FT_LOAD_TARGET_NORMAL)
587 0 : if( !(mnLoadFlags & FT_LOAD_NO_HINTING) )
588 : {
589 0 : mnLoadFlags |= FT_LOAD_TARGET_NORMAL;
590 0 : switch( mpFontOptions->GetHintStyle() )
591 : {
592 : case HINT_NONE:
593 0 : mnLoadFlags |= FT_LOAD_NO_HINTING;
594 0 : break;
595 : case HINT_SLIGHT:
596 0 : mnLoadFlags |= FT_LOAD_TARGET_LIGHT;
597 0 : break;
598 : case HINT_MEDIUM:
599 0 : break;
600 : case HINT_FULL:
601 : default:
602 0 : break;
603 : }
604 : }
605 : #endif
606 :
607 0 : if( mnPrioEmbedded <= 0 )
608 0 : mnLoadFlags |= FT_LOAD_NO_BITMAP;
609 : }
610 :
611 0 : boost::shared_ptr<ImplFontOptions> ServerFont::GetFontOptions() const
612 : {
613 0 : return mpFontOptions;
614 : }
615 :
616 0 : const OString* ServerFont::GetFontFileName() const
617 : {
618 0 : return mpFontInfo->GetFontFileName();
619 : }
620 :
621 192049 : bool ServerFont::TestFont() const
622 : {
623 192049 : return mbFaceOk;
624 : }
625 :
626 11106 : ServerFont::~ServerFont()
627 : {
628 3702 : if( mpLayoutEngine )
629 2833 : delete mpLayoutEngine;
630 :
631 3702 : if( maSizeFT )
632 3702 : FT_Done_Size( maSizeFT );
633 :
634 3702 : mpFontInfo->ReleaseFaceFT();
635 :
636 3702 : ReleaseFromGarbageCollect();
637 7404 : }
638 :
639 2833 : int ServerFont::GetEmUnits() const
640 : {
641 2833 : return maFaceFT->units_per_EM;
642 : }
643 :
644 8243 : void ServerFont::FetchFontMetric( ImplFontMetricData& rTo, long& rFactor ) const
645 : {
646 8243 : static_cast<ImplFontAttributes&>(rTo) = mpFontInfo->GetFontAttributes();
647 :
648 8243 : rTo.mbScalableFont = true;
649 8243 : rTo.mbDevice = true;
650 8243 : rTo.mbKernableFont = FT_HAS_KERNING( maFaceFT ) != 0;
651 8243 : rTo.mnOrientation = GetFontSelData().mnOrientation;
652 :
653 : //Always consider [star]symbol as symbol fonts
654 8243 : if ( IsStarSymbol( rTo.GetFamilyName() ) )
655 782 : rTo.SetSymbolFlag( true );
656 :
657 8243 : FT_Activate_Size( maSizeFT );
658 :
659 8243 : rFactor = 0x100;
660 :
661 8243 : const TT_OS2* pOS2 = (const TT_OS2*)FT_Get_Sfnt_Table( maFaceFT, ft_sfnt_os2 );
662 8243 : const double fScale = (double)GetFontSelData().mnHeight / maFaceFT->units_per_EM;
663 :
664 8243 : rTo.mnAscent = 0;
665 8243 : rTo.mnDescent = 0;
666 8243 : rTo.mnExtLeading = 0;
667 8243 : rTo.mnSlant = 0;
668 8243 : rTo.mnWidth = mnWidth;
669 :
670 : // Calculating ascender and descender:
671 : // FreeType >= 2.4.6 does the right thing, so we just use what it gives us,
672 : // for earlier versions we emulate its behaviour;
673 : // take them from 'hhea' table,
674 : // if zero take them from 'OS/2' table,
675 : // if zero take them from FreeType's font metrics
676 8243 : if (nFTVERSION >= 2406)
677 : {
678 8243 : const FT_Size_Metrics& rMetrics = maFaceFT->size->metrics;
679 8243 : rTo.mnAscent = (rMetrics.ascender + 32) >> 6;
680 8243 : rTo.mnDescent = (-rMetrics.descender + 32) >> 6;
681 8243 : rTo.mnExtLeading = ((rMetrics.height + 32) >> 6) - (rTo.mnAscent + rTo.mnDescent);
682 : }
683 : else
684 : {
685 0 : const TT_HoriHeader* pHHea = (const TT_HoriHeader*)FT_Get_Sfnt_Table(maFaceFT, ft_sfnt_hhea);
686 0 : if (pHHea)
687 : {
688 0 : rTo.mnAscent = pHHea->Ascender * fScale + 0.5;
689 0 : rTo.mnDescent = -pHHea->Descender * fScale + 0.5;
690 0 : rTo.mnExtLeading = pHHea->Line_Gap * fScale + 0.5;
691 : }
692 :
693 0 : if (!(rTo.mnAscent || rTo.mnDescent))
694 : {
695 0 : if (pOS2 && (pOS2->version != 0xFFFF))
696 : {
697 0 : if (pOS2->sTypoAscender || pOS2->sTypoDescender)
698 : {
699 0 : rTo.mnAscent = pOS2->sTypoAscender * fScale + 0.5;
700 0 : rTo.mnDescent = -pOS2->sTypoDescender * fScale + 0.5;
701 0 : rTo.mnExtLeading = pOS2->sTypoLineGap * fScale + 0.5;
702 : }
703 : else
704 : {
705 0 : rTo.mnAscent = pOS2->usWinAscent * fScale + 0.5;
706 0 : rTo.mnDescent = pOS2->usWinDescent * fScale + 0.5;
707 0 : rTo.mnExtLeading = 0;
708 : }
709 : }
710 : }
711 :
712 0 : if (!(rTo.mnAscent || rTo.mnDescent))
713 : {
714 0 : const FT_Size_Metrics& rMetrics = maFaceFT->size->metrics;
715 0 : rTo.mnAscent = (rMetrics.ascender + 32) >> 6;
716 0 : rTo.mnDescent = (-rMetrics.descender + 32) >> 6;
717 0 : rTo.mnExtLeading = ((rMetrics.height + 32) >> 6) - (rTo.mnAscent + rTo.mnDescent);
718 : }
719 : }
720 :
721 8243 : rTo.mnIntLeading = rTo.mnAscent + rTo.mnDescent - (maFaceFT->units_per_EM * fScale + 0.5);
722 :
723 8243 : if( pOS2 && (pOS2->version != 0xFFFF) )
724 : {
725 : // map the panose info from the OS2 table to their VCL counterparts
726 8042 : switch( pOS2->panose[0] )
727 : {
728 0 : case 1: rTo.SetFamilyType( FAMILY_ROMAN ); break;
729 7260 : case 2: rTo.SetFamilyType( FAMILY_SWISS ); break;
730 0 : case 3: rTo.SetFamilyType( FAMILY_MODERN ); break;
731 0 : case 4: rTo.SetFamilyType( FAMILY_SCRIPT ); break;
732 782 : case 5: rTo.SetFamilyType( FAMILY_DECORATIVE ); break;
733 : // TODO: is it reasonable to override the attribute with DONTKNOW?
734 : case 0: // fall through
735 0 : default: rTo.meFamilyType = FAMILY_DONTKNOW; break;
736 : }
737 :
738 8042 : switch( pOS2->panose[3] )
739 : {
740 : case 2: // fall through
741 : case 3: // fall through
742 : case 4: // fall through
743 : case 5: // fall through
744 : case 6: // fall through
745 : case 7: // fall through
746 7157 : case 8: rTo.SetPitch( PITCH_VARIABLE ); break;
747 102 : case 9: rTo.SetPitch( PITCH_FIXED ); break;
748 : // TODO: is it reasonable to override the attribute with DONTKNOW?
749 : case 0: // fall through
750 : case 1: // fall through
751 783 : default: rTo.SetPitch( PITCH_DONTKNOW ); break;
752 : }
753 : }
754 :
755 : // initialize kashida width
756 : // TODO: what if there are different versions of this glyph available
757 8243 : const int nKashidaGlyphId = GetRawGlyphIndex( 0x0640 );
758 8243 : if( nKashidaGlyphId )
759 : {
760 1125 : GlyphData aGlyphData;
761 1125 : InitGlyphData( nKashidaGlyphId, aGlyphData );
762 1125 : rTo.mnMinKashida = aGlyphData.GetMetric().GetCharWidth();
763 : }
764 8243 : }
765 :
766 54068 : static inline void SplitGlyphFlags( const ServerFont& rFont, sal_GlyphId& rGlyphId, int& nGlyphFlags )
767 : {
768 54068 : nGlyphFlags = rGlyphId & GF_FLAGMASK;
769 54068 : rGlyphId &= GF_IDXMASK;
770 :
771 54068 : if( rGlyphId & GF_ISCHAR )
772 0 : rGlyphId = rFont.GetRawGlyphIndex( rGlyphId );
773 54068 : }
774 :
775 54040 : int ServerFont::ApplyGlyphTransform( int nGlyphFlags,
776 : FT_Glyph pGlyphFT, bool bForBitmapProcessing ) const
777 : {
778 54040 : int nAngle = GetFontSelData().mnOrientation;
779 : // shortcut most common case
780 54040 : if( !nAngle && !nGlyphFlags )
781 52000 : return nAngle;
782 :
783 2040 : const FT_Size_Metrics& rMetrics = maFaceFT->size->metrics;
784 : FT_Vector aVector;
785 : FT_Matrix aMatrix;
786 :
787 2040 : bool bStretched = false;
788 :
789 2040 : switch( nGlyphFlags & GF_ROTMASK )
790 : {
791 : default: // straight
792 2040 : aVector.x = 0;
793 2040 : aVector.y = 0;
794 2040 : aMatrix.xx = +mnCos;
795 2040 : aMatrix.yy = +mnCos;
796 2040 : aMatrix.xy = -mnSin;
797 2040 : aMatrix.yx = +mnSin;
798 2040 : break;
799 : case GF_ROTL: // left
800 0 : nAngle += 900;
801 0 : bStretched = (mfStretch != 1.0);
802 0 : aVector.x = (FT_Pos)(+rMetrics.descender * mfStretch);
803 0 : aVector.y = -rMetrics.ascender;
804 0 : aMatrix.xx = (FT_Pos)(-mnSin / mfStretch);
805 0 : aMatrix.yy = (FT_Pos)(-mnSin * mfStretch);
806 0 : aMatrix.xy = (FT_Pos)(-mnCos * mfStretch);
807 0 : aMatrix.yx = (FT_Pos)(+mnCos / mfStretch);
808 0 : break;
809 : case GF_ROTR: // right
810 0 : nAngle -= 900;
811 0 : bStretched = (mfStretch != 1.0);
812 0 : aVector.x = -maFaceFT->glyph->metrics.horiAdvance;
813 0 : aVector.x += (FT_Pos)(rMetrics.descender * mnSin/65536.0);
814 0 : aVector.y = (FT_Pos)(-rMetrics.descender * mfStretch * mnCos/65536.0);
815 0 : aMatrix.xx = (FT_Pos)(+mnSin / mfStretch);
816 0 : aMatrix.yy = (FT_Pos)(+mnSin * mfStretch);
817 0 : aMatrix.xy = (FT_Pos)(+mnCos * mfStretch);
818 0 : aMatrix.yx = (FT_Pos)(-mnCos / mfStretch);
819 0 : break;
820 : }
821 :
822 4080 : while( nAngle < 0 )
823 0 : nAngle += 3600;
824 :
825 2040 : if( pGlyphFT->format != FT_GLYPH_FORMAT_BITMAP )
826 : {
827 2040 : FT_Glyph_Transform( pGlyphFT, NULL, &aVector );
828 :
829 : // orthogonal transforms are better handled by bitmap operations
830 2040 : if( bStretched || (bForBitmapProcessing && (nAngle % 900) != 0) )
831 : {
832 : // apply non-orthogonal or stretch transformations
833 463 : FT_Glyph_Transform( pGlyphFT, &aMatrix, NULL );
834 463 : nAngle = 0;
835 : }
836 : }
837 : else
838 : {
839 : // FT<=2005 ignores transforms for bitmaps, so do it manually
840 0 : FT_BitmapGlyph pBmpGlyphFT = reinterpret_cast<FT_BitmapGlyph>(pGlyphFT);
841 0 : pBmpGlyphFT->left += (aVector.x + 32) >> 6;
842 0 : pBmpGlyphFT->top += (aVector.y + 32) >> 6;
843 : }
844 :
845 2040 : return nAngle;
846 : }
847 :
848 15114202 : sal_GlyphId ServerFont::GetRawGlyphIndex(sal_UCS4 aChar, sal_UCS4 aVS) const
849 : {
850 15114202 : if( mpFontInfo->IsSymbolFont() )
851 : {
852 625 : if( !FT_IS_SFNT( maFaceFT ) )
853 : {
854 625 : if( (aChar & 0xFF00) == 0xF000 )
855 142 : aChar &= 0xFF; // PS font symbol mapping
856 483 : else if( aChar > 0xFF )
857 187 : return 0;
858 : }
859 : }
860 :
861 15114015 : int nGlyphIndex = 0;
862 : #if HAVE_FT_FACE_GETCHARVARIANTINDEX
863 : // If asked, check first for variant glyph with the given Unicode variation
864 : // selector. This is quite uncommon so we don't bother with caching here.
865 : // Disabled for buggy FreeType versions:
866 : // https://bugzilla.mozilla.org/show_bug.cgi?id=618406#c8
867 15114015 : if (aVS && nFTVERSION >= 2404)
868 0 : nGlyphIndex = FT_Face_GetCharVariantIndex(maFaceFT, aChar, aVS);
869 : #endif
870 :
871 15114015 : if (nGlyphIndex == 0)
872 : {
873 : // cache glyph indexes in font info to share between different sizes
874 15114015 : nGlyphIndex = mpFontInfo->GetGlyphIndex( aChar );
875 15114015 : if( nGlyphIndex < 0 )
876 : {
877 14280 : nGlyphIndex = FT_Get_Char_Index( maFaceFT, aChar );
878 14280 : if( !nGlyphIndex)
879 : {
880 : // check if symbol aliasing helps
881 367 : if( (aChar <= 0x00FF) && mpFontInfo->IsSymbolFont() )
882 0 : nGlyphIndex = FT_Get_Char_Index( maFaceFT, aChar | 0xF000 );
883 : }
884 14280 : mpFontInfo->CacheGlyphIndex( aChar, nGlyphIndex );
885 : }
886 : }
887 :
888 15114015 : return sal_GlyphId( nGlyphIndex);
889 : }
890 :
891 15088830 : sal_GlyphId ServerFont::FixupGlyphIndex( sal_GlyphId aGlyphId, sal_UCS4 aChar ) const
892 : {
893 15088830 : int nGlyphFlags = GF_NONE;
894 :
895 : // do glyph substitution if necessary
896 : // CJK vertical writing needs special treatment
897 15088830 : if( GetFontSelData().mbVertical )
898 : {
899 : // TODO: rethink when GSUB is used for non-vertical case
900 256 : GlyphSubstitution::const_iterator it = maGlyphSubstitution.find( aGlyphId );
901 256 : if( it == maGlyphSubstitution.end() )
902 : {
903 256 : sal_GlyphId nTemp = GetVerticalChar( aChar );
904 256 : if( nTemp ) // is substitution possible
905 0 : nTemp = GetRawGlyphIndex( nTemp );
906 256 : if( nTemp ) // substitute manually if sensible
907 0 : aGlyphId = nTemp | (GF_GSUB | GF_ROTL);
908 : else
909 256 : nGlyphFlags |= GetVerticalFlags( aChar );
910 : }
911 : else
912 : {
913 : // for vertical GSUB also compensate for nOrientation=2700
914 0 : aGlyphId = (*it).second;
915 0 : nGlyphFlags |= GF_GSUB | GF_ROTL;
916 : }
917 : }
918 :
919 15088830 : if( aGlyphId != 0 )
920 15088017 : aGlyphId |= nGlyphFlags;
921 :
922 15088830 : return aGlyphId;
923 : }
924 :
925 0 : sal_GlyphId ServerFont::GetGlyphIndex( sal_UCS4 aChar ) const
926 : {
927 0 : sal_GlyphId aGlyphId = GetRawGlyphIndex( aChar );
928 0 : aGlyphId = FixupGlyphIndex( aGlyphId, aChar );
929 0 : return aGlyphId;
930 : }
931 :
932 43402 : static int lcl_GetCharWidth( FT_FaceRec_* pFaceFT, double fStretch, int nGlyphFlags )
933 : {
934 43402 : int nCharWidth = pFaceFT->glyph->metrics.horiAdvance;
935 :
936 43402 : if( nGlyphFlags & GF_ROTMASK ) // for bVertical rotated glyphs
937 : {
938 0 : const FT_Size_Metrics& rMetrics = pFaceFT->size->metrics;
939 0 : nCharWidth = (int)((rMetrics.height + rMetrics.descender) * fStretch);
940 : }
941 :
942 43402 : return (nCharWidth + 32) >> 6;
943 : }
944 :
945 43423 : void ServerFont::InitGlyphData( sal_GlyphId aGlyphId, GlyphData& rGD ) const
946 : {
947 43423 : FT_Activate_Size( maSizeFT );
948 :
949 : int nGlyphFlags;
950 43423 : SplitGlyphFlags( *this, aGlyphId, nGlyphFlags );
951 :
952 43423 : int nLoadFlags = mnLoadFlags;
953 :
954 : // if( mbArtItalic )
955 : // nLoadFlags |= FT_LOAD_NO_BITMAP;
956 :
957 43423 : FT_Error rc = FT_Load_Glyph( maFaceFT, aGlyphId, nLoadFlags );
958 :
959 43423 : if( rc != FT_Err_Ok )
960 : {
961 : // we get here e.g. when a PS font lacks the default glyph
962 0 : rGD.SetCharWidth( 0 );
963 0 : rGD.SetDelta( 0, 0 );
964 0 : rGD.SetOffset( 0, 0 );
965 0 : rGD.SetSize( Size( 0, 0 ) );
966 43423 : return;
967 : }
968 :
969 43423 : const bool bOriginallyZeroWidth = (maFaceFT->glyph->metrics.horiAdvance == 0);
970 43423 : if (mbArtBold)
971 7 : FT_GlyphSlot_Embolden(maFaceFT->glyph);
972 :
973 43423 : const int nCharWidth = bOriginallyZeroWidth ? 0 : lcl_GetCharWidth( maFaceFT, mfStretch, nGlyphFlags );
974 43423 : rGD.SetCharWidth( nCharWidth );
975 :
976 : FT_Glyph pGlyphFT;
977 43423 : rc = FT_Get_Glyph( maFaceFT->glyph, &pGlyphFT );
978 :
979 43423 : ApplyGlyphTransform( nGlyphFlags, pGlyphFT, false );
980 43423 : rGD.SetDelta( (pGlyphFT->advance.x + 0x8000) >> 16, -((pGlyphFT->advance.y + 0x8000) >> 16) );
981 :
982 : FT_BBox aBbox;
983 43423 : FT_Glyph_Get_CBox( pGlyphFT, FT_GLYPH_BBOX_PIXELS, &aBbox );
984 43423 : if( aBbox.yMin > aBbox.yMax ) // circumvent freetype bug
985 : {
986 0 : int t=aBbox.yMin; aBbox.yMin=aBbox.yMax, aBbox.yMax=t;
987 : }
988 :
989 43423 : rGD.SetOffset( aBbox.xMin, -aBbox.yMax );
990 43423 : rGD.SetSize( Size( (aBbox.xMax-aBbox.xMin+1), (aBbox.yMax-aBbox.yMin) ) );
991 :
992 43423 : FT_Done_Glyph( pGlyphFT );
993 : }
994 :
995 0 : bool ServerFont::GetAntialiasAdvice( void ) const
996 : {
997 0 : if( GetFontSelData().mbNonAntialiased || (mnPrioAntiAlias<=0) )
998 0 : return false;
999 0 : bool bAdviseAA = true;
1000 : // TODO: also use GASP info
1001 0 : return bAdviseAA;
1002 : }
1003 :
1004 1 : bool ServerFont::GetGlyphBitmap1( sal_GlyphId aGlyphId, RawBitmap& rRawBitmap ) const
1005 : {
1006 1 : FT_Activate_Size( maSizeFT );
1007 :
1008 : int nGlyphFlags;
1009 1 : SplitGlyphFlags( *this, aGlyphId, nGlyphFlags );
1010 :
1011 1 : FT_Int nLoadFlags = mnLoadFlags;
1012 : // #i70930# force mono-hinting for monochrome text
1013 1 : nLoadFlags &= ~0xF0000;
1014 1 : nLoadFlags |= FT_LOAD_TARGET_MONO;
1015 :
1016 1 : if( mbArtItalic )
1017 0 : nLoadFlags |= FT_LOAD_NO_BITMAP;
1018 :
1019 : // for 0/90/180/270 degree fonts enable hinting even if not advisable
1020 : // non-hinted and non-antialiased bitmaps just look too ugly
1021 1 : if( (mnCos==0 || mnSin==0) && (mnPrioAutoHint > 0) )
1022 1 : nLoadFlags &= ~FT_LOAD_NO_HINTING;
1023 :
1024 1 : if( mnPrioEmbedded <= mnPrioAutoHint )
1025 0 : nLoadFlags |= FT_LOAD_NO_BITMAP;
1026 :
1027 1 : FT_Error rc = FT_Load_Glyph( maFaceFT, aGlyphId, nLoadFlags );
1028 :
1029 1 : if( rc != FT_Err_Ok )
1030 0 : return false;
1031 :
1032 1 : if (mbArtBold)
1033 0 : FT_GlyphSlot_Embolden(maFaceFT->glyph);
1034 :
1035 : FT_Glyph pGlyphFT;
1036 1 : rc = FT_Get_Glyph( maFaceFT->glyph, &pGlyphFT );
1037 1 : if( rc != FT_Err_Ok )
1038 0 : return false;
1039 :
1040 1 : int nAngle = ApplyGlyphTransform( nGlyphFlags, pGlyphFT, true );
1041 :
1042 1 : if( mbArtItalic )
1043 : {
1044 : FT_Matrix aMatrix;
1045 0 : aMatrix.xx = aMatrix.yy = 0x10000L;
1046 0 : aMatrix.xy = 0x6000L, aMatrix.yx = 0;
1047 0 : FT_Glyph_Transform( pGlyphFT, &aMatrix, NULL );
1048 : }
1049 :
1050 : // Check for zero area bounding boxes as this crashes some versions of FT.
1051 : // This also provides a handy short cut as much of the code following
1052 : // becomes an expensive nop when a glyph covers no pixels.
1053 : FT_BBox cbox;
1054 1 : FT_Glyph_Get_CBox(pGlyphFT, ft_glyph_bbox_unscaled, &cbox);
1055 :
1056 1 : if( (cbox.xMax - cbox.xMin) == 0 || (cbox.yMax - cbox.yMin == 0) )
1057 : {
1058 0 : nAngle = 0;
1059 0 : memset(&rRawBitmap, 0, sizeof rRawBitmap);
1060 0 : FT_Done_Glyph( pGlyphFT );
1061 0 : return true;
1062 : }
1063 :
1064 1 : if( pGlyphFT->format != FT_GLYPH_FORMAT_BITMAP )
1065 : {
1066 1 : if( pGlyphFT->format == FT_GLYPH_FORMAT_OUTLINE )
1067 1 : ((FT_OutlineGlyphRec*)pGlyphFT)->outline.flags |= FT_OUTLINE_HIGH_PRECISION;
1068 1 : FT_Render_Mode nRenderMode = FT_RENDER_MODE_MONO;
1069 :
1070 1 : rc = FT_Glyph_To_Bitmap( &pGlyphFT, nRenderMode, NULL, true );
1071 1 : if( rc != FT_Err_Ok )
1072 : {
1073 0 : FT_Done_Glyph( pGlyphFT );
1074 0 : return false;
1075 : }
1076 : }
1077 :
1078 1 : const FT_BitmapGlyph pBmpGlyphFT = reinterpret_cast<const FT_BitmapGlyph>(pGlyphFT);
1079 : // NOTE: autohinting in FT<=2.0.2 miscalculates the offsets below by +-1
1080 1 : rRawBitmap.mnXOffset = +pBmpGlyphFT->left;
1081 1 : rRawBitmap.mnYOffset = -pBmpGlyphFT->top;
1082 :
1083 1 : const FT_Bitmap& rBitmapFT = pBmpGlyphFT->bitmap;
1084 1 : rRawBitmap.mnHeight = rBitmapFT.rows;
1085 1 : rRawBitmap.mnBitCount = 1;
1086 1 : rRawBitmap.mnWidth = rBitmapFT.width;
1087 1 : rRawBitmap.mnScanlineSize = rBitmapFT.pitch;
1088 :
1089 1 : const sal_uLong nNeededSize = rRawBitmap.mnScanlineSize * rRawBitmap.mnHeight;
1090 :
1091 1 : if( rRawBitmap.mnAllocated < nNeededSize )
1092 : {
1093 1 : rRawBitmap.mnAllocated = 2*nNeededSize;
1094 1 : rRawBitmap.mpBits.reset(new unsigned char[ rRawBitmap.mnAllocated ]);
1095 : }
1096 :
1097 1 : if (!mbArtBold)
1098 : {
1099 1 : memcpy( rRawBitmap.mpBits.get(), rBitmapFT.buffer, nNeededSize );
1100 : }
1101 : else
1102 : {
1103 0 : memset( rRawBitmap.mpBits.get(), 0, nNeededSize );
1104 0 : const unsigned char* pSrcLine = rBitmapFT.buffer;
1105 0 : unsigned char* pDstLine = rRawBitmap.mpBits.get();
1106 0 : for( int h = rRawBitmap.mnHeight; --h >= 0; )
1107 : {
1108 0 : memcpy( pDstLine, pSrcLine, rBitmapFT.pitch );
1109 0 : pDstLine += rRawBitmap.mnScanlineSize;
1110 0 : pSrcLine += rBitmapFT.pitch;
1111 : }
1112 :
1113 0 : unsigned char* p = rRawBitmap.mpBits.get();
1114 0 : for( sal_uLong y=0; y < rRawBitmap.mnHeight; y++ )
1115 : {
1116 0 : unsigned char nLastByte = 0;
1117 0 : for( sal_uLong x=0; x < rRawBitmap.mnScanlineSize; x++ )
1118 : {
1119 0 : unsigned char nTmp = p[x] << 7;
1120 0 : p[x] |= (p[x] >> 1) | nLastByte;
1121 0 : nLastByte = nTmp;
1122 : }
1123 0 : p += rRawBitmap.mnScanlineSize;
1124 : }
1125 : }
1126 :
1127 1 : FT_Done_Glyph( pGlyphFT );
1128 :
1129 : // special case for 0/90/180/270 degree orientation
1130 1 : switch( nAngle )
1131 : {
1132 : case -900:
1133 : case +900:
1134 : case +1800:
1135 : case +2700:
1136 0 : rRawBitmap.Rotate( nAngle );
1137 0 : break;
1138 : }
1139 :
1140 1 : return true;
1141 : }
1142 :
1143 9253 : bool ServerFont::GetGlyphBitmap8( sal_GlyphId aGlyphId, RawBitmap& rRawBitmap ) const
1144 : {
1145 9253 : FT_Activate_Size( maSizeFT );
1146 :
1147 : int nGlyphFlags;
1148 9253 : SplitGlyphFlags( *this, aGlyphId, nGlyphFlags );
1149 :
1150 9253 : FT_Int nLoadFlags = mnLoadFlags;
1151 :
1152 9253 : if( mbArtItalic )
1153 1 : nLoadFlags |= FT_LOAD_NO_BITMAP;
1154 :
1155 9253 : if( (nGlyphFlags & GF_UNHINTED) || (mnPrioAutoHint < mnPrioAntiAlias) )
1156 0 : nLoadFlags |= FT_LOAD_NO_HINTING;
1157 :
1158 9253 : if( mnPrioEmbedded <= mnPrioAntiAlias )
1159 0 : nLoadFlags |= FT_LOAD_NO_BITMAP;
1160 :
1161 9253 : FT_Error rc = FT_Load_Glyph( maFaceFT, aGlyphId, nLoadFlags );
1162 :
1163 9253 : if( rc != FT_Err_Ok )
1164 0 : return false;
1165 :
1166 9253 : if (mbArtBold)
1167 2 : FT_GlyphSlot_Embolden(maFaceFT->glyph);
1168 :
1169 : FT_Glyph pGlyphFT;
1170 9253 : rc = FT_Get_Glyph( maFaceFT->glyph, &pGlyphFT );
1171 9253 : if( rc != FT_Err_Ok )
1172 0 : return false;
1173 :
1174 9253 : int nAngle = ApplyGlyphTransform( nGlyphFlags, pGlyphFT, true );
1175 :
1176 9253 : if( mbArtItalic )
1177 : {
1178 : FT_Matrix aMatrix;
1179 1 : aMatrix.xx = aMatrix.yy = 0x10000L;
1180 1 : aMatrix.xy = 0x6000L, aMatrix.yx = 0;
1181 1 : FT_Glyph_Transform( pGlyphFT, &aMatrix, NULL );
1182 : }
1183 :
1184 9253 : if( pGlyphFT->format == FT_GLYPH_FORMAT_OUTLINE )
1185 9251 : ((FT_OutlineGlyph)pGlyphFT)->outline.flags |= FT_OUTLINE_HIGH_PRECISION;
1186 :
1187 9253 : bool bEmbedded = (pGlyphFT->format == FT_GLYPH_FORMAT_BITMAP);
1188 9253 : if( !bEmbedded )
1189 : {
1190 9251 : rc = FT_Glyph_To_Bitmap( &pGlyphFT, FT_RENDER_MODE_NORMAL, NULL, true );
1191 9251 : if( rc != FT_Err_Ok )
1192 : {
1193 0 : FT_Done_Glyph( pGlyphFT );
1194 0 : return false;
1195 : }
1196 : }
1197 :
1198 9253 : const FT_BitmapGlyph pBmpGlyphFT = reinterpret_cast<const FT_BitmapGlyph>(pGlyphFT);
1199 9253 : rRawBitmap.mnXOffset = +pBmpGlyphFT->left;
1200 9253 : rRawBitmap.mnYOffset = -pBmpGlyphFT->top;
1201 :
1202 9253 : const FT_Bitmap& rBitmapFT = pBmpGlyphFT->bitmap;
1203 9253 : rRawBitmap.mnHeight = rBitmapFT.rows;
1204 9253 : rRawBitmap.mnWidth = rBitmapFT.width;
1205 9253 : rRawBitmap.mnBitCount = 8;
1206 9253 : rRawBitmap.mnScanlineSize = bEmbedded ? rBitmapFT.width : rBitmapFT.pitch;
1207 9253 : rRawBitmap.mnScanlineSize = (rRawBitmap.mnScanlineSize + 3) & -4;
1208 :
1209 9253 : const sal_uLong nNeededSize = rRawBitmap.mnScanlineSize * rRawBitmap.mnHeight;
1210 9253 : if( rRawBitmap.mnAllocated < nNeededSize )
1211 : {
1212 8938 : rRawBitmap.mnAllocated = 2*nNeededSize;
1213 8938 : rRawBitmap.mpBits.reset(new unsigned char[ rRawBitmap.mnAllocated ]);
1214 : }
1215 :
1216 9253 : const unsigned char* pSrc = rBitmapFT.buffer;
1217 9253 : unsigned char* pDest = rRawBitmap.mpBits.get();
1218 9253 : if( !bEmbedded )
1219 : {
1220 116906 : for( int y = rRawBitmap.mnHeight, x; --y >= 0 ; )
1221 : {
1222 1190028 : for( x = 0; x < rBitmapFT.width; ++x )
1223 1091624 : *(pDest++) = *(pSrc++);
1224 254548 : for(; x < int(rRawBitmap.mnScanlineSize); ++x )
1225 156144 : *(pDest++) = 0;
1226 : }
1227 : }
1228 : else
1229 : {
1230 28 : for( int y = rRawBitmap.mnHeight, x; --y >= 0 ; )
1231 : {
1232 24 : unsigned char nSrc = 0;
1233 336 : for( x = 0; x < rBitmapFT.width; ++x, nSrc+=nSrc )
1234 : {
1235 312 : if( (x & 7) == 0 )
1236 48 : nSrc = *(pSrc++);
1237 312 : *(pDest++) = (0x7F - nSrc) >> 8;
1238 : }
1239 96 : for(; x < int(rRawBitmap.mnScanlineSize); ++x )
1240 72 : *(pDest++) = 0;
1241 : }
1242 : }
1243 :
1244 9253 : if( !bEmbedded && mbUseGamma )
1245 : {
1246 0 : unsigned char* p = rRawBitmap.mpBits.get();
1247 0 : for( sal_uLong y=0; y < rRawBitmap.mnHeight; y++ )
1248 : {
1249 0 : for( sal_uLong x=0; x < rRawBitmap.mnWidth; x++ )
1250 : {
1251 0 : p[x] = aGammaTable[ p[x] ];
1252 : }
1253 0 : p += rRawBitmap.mnScanlineSize;
1254 : }
1255 : }
1256 :
1257 9253 : FT_Done_Glyph( pGlyphFT );
1258 :
1259 : // special case for 0/90/180/270 degree orientation
1260 9253 : switch( nAngle )
1261 : {
1262 : case -900:
1263 : case +900:
1264 : case +1800:
1265 : case +2700:
1266 348 : rRawBitmap.Rotate( nAngle );
1267 348 : break;
1268 : }
1269 :
1270 9253 : return true;
1271 : }
1272 :
1273 : // determine unicode ranges in font
1274 :
1275 5100 : const ImplFontCharMap* ServerFont::GetImplFontCharMap( void ) const
1276 : {
1277 5100 : const ImplFontCharMap* pIFCMap = mpFontInfo->GetImplFontCharMap();
1278 5100 : return pIFCMap;
1279 : }
1280 :
1281 5100 : const ImplFontCharMap* FtFontInfo::GetImplFontCharMap( void )
1282 : {
1283 : // check if the charmap is already cached
1284 5100 : if( mpFontCharMap )
1285 4940 : return mpFontCharMap;
1286 :
1287 : // get the charmap and cache it
1288 160 : CmapResult aCmapResult;
1289 160 : bool bOK = GetFontCodeRanges( aCmapResult );
1290 160 : if( bOK )
1291 160 : mpFontCharMap = new ImplFontCharMap( aCmapResult );
1292 : else
1293 0 : mpFontCharMap = ImplFontCharMap::GetDefaultMap();
1294 160 : mpFontCharMap->AddReference();
1295 160 : return mpFontCharMap;
1296 : }
1297 :
1298 : // TODO: merge into method GetFontCharMap()
1299 160 : bool FtFontInfo::GetFontCodeRanges( CmapResult& rResult ) const
1300 : {
1301 160 : rResult.mbSymbolic = IsSymbolFont();
1302 :
1303 : // TODO: is the full CmapResult needed on platforms calling this?
1304 160 : if( FT_IS_SFNT( maFaceFT ) )
1305 : {
1306 160 : sal_uLong nLength = 0;
1307 160 : const unsigned char* pCmap = GetTable( "cmap", &nLength );
1308 160 : if( pCmap && (nLength > 0) )
1309 160 : if( ParseCMAP( pCmap, nLength, rResult ) )
1310 160 : return true;
1311 : }
1312 :
1313 : typedef std::vector<sal_uInt32> U32Vector;
1314 0 : U32Vector aCodes;
1315 :
1316 : // FT's coverage is available since FT>=2.1.0 (OOo-baseline>=2.1.4 => ok)
1317 0 : aCodes.reserve( 0x1000 );
1318 : FT_UInt nGlyphIndex;
1319 0 : for( sal_uInt32 cCode = FT_Get_First_Char( maFaceFT, &nGlyphIndex );; )
1320 : {
1321 0 : if( !nGlyphIndex )
1322 0 : break;
1323 0 : aCodes.push_back( cCode ); // first code inside range
1324 0 : sal_uInt32 cNext = cCode;
1325 0 : do cNext = FT_Get_Next_Char( maFaceFT, cCode, &nGlyphIndex ); while( cNext == ++cCode );
1326 0 : aCodes.push_back( cCode ); // first code outside range
1327 0 : cCode = cNext;
1328 0 : }
1329 :
1330 0 : const int nCount = aCodes.size();
1331 0 : if( !nCount) {
1332 0 : if( !rResult.mbSymbolic )
1333 0 : return false;
1334 :
1335 : // we usually get here for Type1 symbol fonts
1336 0 : aCodes.push_back( 0xF020 );
1337 0 : aCodes.push_back( 0xF100 );
1338 : }
1339 :
1340 0 : sal_uInt32* pCodes = new sal_uInt32[ nCount ];
1341 0 : for( int i = 0; i < nCount; ++i )
1342 0 : pCodes[i] = aCodes[i];
1343 0 : rResult.mpRangeCodes = pCodes;
1344 0 : rResult.mnRangeCount = nCount / 2;
1345 0 : return true;
1346 : }
1347 :
1348 522 : bool ServerFont::GetFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const
1349 : {
1350 522 : bool bRet = false;
1351 :
1352 522 : sal_uLong nLength = 0;
1353 : // load GSUB table
1354 522 : const FT_Byte* pGSUB = mpFontInfo->GetTable("GSUB", &nLength);
1355 522 : if (pGSUB)
1356 522 : vcl::getTTScripts(rFontCapabilities.maGSUBScriptTags, pGSUB, nLength);
1357 :
1358 : // load OS/2 table
1359 522 : const FT_Byte* pOS2 = mpFontInfo->GetTable("OS/2", &nLength);
1360 522 : if (pOS2)
1361 : {
1362 : bRet = vcl::getTTCoverage(
1363 : rFontCapabilities.maUnicodeRange,
1364 : rFontCapabilities.maCodePageRange,
1365 522 : pOS2, nLength);
1366 : }
1367 :
1368 522 : return bRet;
1369 : }
1370 :
1371 : // outline stuff
1372 :
1373 : class PolyArgs
1374 : {
1375 : public:
1376 : PolyArgs( PolyPolygon& rPolyPoly, sal_uInt16 nMaxPoints );
1377 : ~PolyArgs();
1378 :
1379 : void AddPoint( long nX, long nY, PolyFlags);
1380 : void ClosePolygon();
1381 :
1382 16683 : long GetPosX() const { return maPosition.x;}
1383 16683 : long GetPosY() const { return maPosition.y;}
1384 :
1385 : private:
1386 : PolyPolygon& mrPolyPoly;
1387 :
1388 : Point* mpPointAry;
1389 : sal_uInt8* mpFlagAry;
1390 :
1391 : FT_Vector maPosition;
1392 : sal_uInt16 mnMaxPoints;
1393 : sal_uInt16 mnPoints;
1394 : sal_uInt16 mnPoly;
1395 : bool bHasOffline;
1396 : };
1397 :
1398 1363 : PolyArgs::PolyArgs( PolyPolygon& rPolyPoly, sal_uInt16 nMaxPoints )
1399 : : mrPolyPoly(rPolyPoly),
1400 : mnMaxPoints(nMaxPoints),
1401 : mnPoints(0),
1402 : mnPoly(0),
1403 1363 : bHasOffline(false)
1404 : {
1405 1363 : mpPointAry = new Point[ mnMaxPoints ];
1406 1363 : mpFlagAry = new sal_uInt8 [ mnMaxPoints ];
1407 1363 : maPosition.x = maPosition.y = 0;
1408 1363 : }
1409 :
1410 1363 : PolyArgs::~PolyArgs()
1411 : {
1412 1363 : delete[] mpFlagAry;
1413 1363 : delete[] mpPointAry;
1414 1363 : }
1415 :
1416 61412 : void PolyArgs::AddPoint( long nX, long nY, PolyFlags aFlag )
1417 : {
1418 : DBG_ASSERT( (mnPoints < mnMaxPoints), "FTGlyphOutline: AddPoint overflow!" );
1419 61412 : if( mnPoints >= mnMaxPoints )
1420 61412 : return;
1421 :
1422 61412 : maPosition.x = nX;
1423 61412 : maPosition.y = nY;
1424 61412 : mpPointAry[ mnPoints ] = Point( nX, nY );
1425 61412 : mpFlagAry[ mnPoints++ ]= aFlag;
1426 61412 : bHasOffline |= (aFlag != POLY_NORMAL);
1427 : }
1428 :
1429 3565 : void PolyArgs::ClosePolygon()
1430 : {
1431 3565 : if( !mnPoly++ )
1432 4928 : return;
1433 :
1434 : // freetype seems to always close the polygon with an ON_CURVE point
1435 : // PolyPoly wants to close the polygon itself => remove last point
1436 : DBG_ASSERT( (mnPoints >= 2), "FTGlyphOutline: PolyFinishNum failed!" );
1437 2202 : --mnPoints;
1438 : DBG_ASSERT( (mpPointAry[0]==mpPointAry[mnPoints]), "FTGlyphOutline: PolyFinishEq failed!" );
1439 : DBG_ASSERT( (mpFlagAry[0]==POLY_NORMAL), "FTGlyphOutline: PolyFinishFE failed!" );
1440 : DBG_ASSERT( (mpFlagAry[mnPoints]==POLY_NORMAL), "FTGlyphOutline: PolyFinishFS failed!" );
1441 :
1442 2202 : Polygon aPoly( mnPoints, mpPointAry, (bHasOffline ? mpFlagAry : NULL) );
1443 :
1444 : // #i35928#
1445 : // This may be a invalid polygons, e.g. the last point is a control point.
1446 : // So close the polygon (and add the first point again) if the last point
1447 : // is a control point or different from first.
1448 : // #i48298#
1449 : // Now really duplicating the first point, to close or correct the
1450 : // polygon. Also no longer duplicating the flags, but enforcing
1451 : // POLY_NORMAL for the newly added last point.
1452 2202 : const sal_uInt16 nPolySize(aPoly.GetSize());
1453 2202 : if(nPolySize)
1454 : {
1455 5883 : if((aPoly.HasFlags() && POLY_CONTROL == aPoly.GetFlags(nPolySize - 1))
1456 3384 : || (aPoly.GetPoint(nPolySize - 1) != aPoly.GetPoint(0)))
1457 : {
1458 2161 : aPoly.SetSize(nPolySize + 1);
1459 2161 : aPoly.SetPoint(aPoly.GetPoint(0), nPolySize);
1460 :
1461 2161 : if(aPoly.HasFlags())
1462 : {
1463 1472 : aPoly.SetFlags(nPolySize, POLY_NORMAL);
1464 : }
1465 : }
1466 : }
1467 :
1468 2202 : mrPolyPoly.Insert( aPoly );
1469 2202 : mnPoints = 0;
1470 2202 : bHasOffline = false;
1471 : }
1472 :
1473 : extern "C" {
1474 :
1475 : // TODO: wait till all compilers accept that calling conventions
1476 : // for functions are the same independent of implementation constness,
1477 : // then uncomment the const-tokens in the function interfaces below
1478 2202 : static int FT_move_to( FT_Vector_CPtr p0, void* vpPolyArgs )
1479 : {
1480 2202 : PolyArgs& rA = *reinterpret_cast<PolyArgs*>(vpPolyArgs);
1481 :
1482 : // move_to implies a new polygon => finish old polygon first
1483 2202 : rA.ClosePolygon();
1484 :
1485 2202 : rA.AddPoint( p0->x, p0->y, POLY_NORMAL );
1486 2202 : return 0;
1487 : }
1488 :
1489 9161 : static int FT_line_to( FT_Vector_CPtr p1, void* vpPolyArgs )
1490 : {
1491 9161 : PolyArgs& rA = *reinterpret_cast<PolyArgs*>(vpPolyArgs);
1492 9161 : rA.AddPoint( p1->x, p1->y, POLY_NORMAL );
1493 9161 : return 0;
1494 : }
1495 :
1496 16683 : static int FT_conic_to( FT_Vector_CPtr p1, FT_Vector_CPtr p2, void* vpPolyArgs )
1497 : {
1498 16683 : PolyArgs& rA = *reinterpret_cast<PolyArgs*>(vpPolyArgs);
1499 :
1500 : // VCL's Polygon only knows cubic beziers
1501 16683 : const long nX1 = (2 * rA.GetPosX() + 4 * p1->x + 3) / 6;
1502 16683 : const long nY1 = (2 * rA.GetPosY() + 4 * p1->y + 3) / 6;
1503 16683 : rA.AddPoint( nX1, nY1, POLY_CONTROL );
1504 :
1505 16683 : const long nX2 = (2 * p2->x + 4 * p1->x + 3) / 6;
1506 16683 : const long nY2 = (2 * p2->y + 4 * p1->y + 3) / 6;
1507 16683 : rA.AddPoint( nX2, nY2, POLY_CONTROL );
1508 :
1509 16683 : rA.AddPoint( p2->x, p2->y, POLY_NORMAL );
1510 16683 : return 0;
1511 : }
1512 :
1513 0 : static int FT_cubic_to( FT_Vector_CPtr p1, FT_Vector_CPtr p2, FT_Vector_CPtr p3, void* vpPolyArgs )
1514 : {
1515 0 : PolyArgs& rA = *reinterpret_cast<PolyArgs*>(vpPolyArgs);
1516 0 : rA.AddPoint( p1->x, p1->y, POLY_CONTROL );
1517 0 : rA.AddPoint( p2->x, p2->y, POLY_CONTROL );
1518 0 : rA.AddPoint( p3->x, p3->y, POLY_NORMAL );
1519 0 : return 0;
1520 : }
1521 :
1522 : } // extern "C"
1523 :
1524 1391 : bool ServerFont::GetGlyphOutline( sal_GlyphId aGlyphId,
1525 : ::basegfx::B2DPolyPolygon& rB2DPolyPoly ) const
1526 : {
1527 1391 : if( maSizeFT )
1528 1391 : FT_Activate_Size( maSizeFT );
1529 :
1530 1391 : rB2DPolyPoly.clear();
1531 :
1532 : int nGlyphFlags;
1533 1391 : SplitGlyphFlags( *this, aGlyphId, nGlyphFlags );
1534 :
1535 1391 : FT_Int nLoadFlags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_TRANSFORM;
1536 :
1537 : #ifdef FT_LOAD_TARGET_LIGHT
1538 : // enable "light hinting" if available
1539 1391 : nLoadFlags |= FT_LOAD_TARGET_LIGHT;
1540 : #endif
1541 :
1542 1391 : FT_Error rc = FT_Load_Glyph( maFaceFT, aGlyphId, nLoadFlags );
1543 1391 : if( rc != FT_Err_Ok )
1544 0 : return false;
1545 :
1546 1391 : if (mbArtBold)
1547 0 : FT_GlyphSlot_Embolden(maFaceFT->glyph);
1548 :
1549 : FT_Glyph pGlyphFT;
1550 1391 : rc = FT_Get_Glyph( maFaceFT->glyph, &pGlyphFT );
1551 1391 : if( rc != FT_Err_Ok )
1552 0 : return false;
1553 :
1554 1391 : if( pGlyphFT->format != FT_GLYPH_FORMAT_OUTLINE )
1555 : {
1556 0 : FT_Done_Glyph( pGlyphFT );
1557 0 : return false;
1558 : }
1559 :
1560 1391 : if( mbArtItalic )
1561 : {
1562 : FT_Matrix aMatrix;
1563 0 : aMatrix.xx = aMatrix.yy = 0x10000L;
1564 0 : aMatrix.xy = 0x6000L, aMatrix.yx = 0;
1565 0 : FT_Glyph_Transform( pGlyphFT, &aMatrix, NULL );
1566 : }
1567 :
1568 1391 : FT_Outline& rOutline = reinterpret_cast<FT_OutlineGlyphRec*>(pGlyphFT)->outline;
1569 1391 : if( !rOutline.n_points ) // blank glyphs are ok
1570 : {
1571 28 : FT_Done_Glyph( pGlyphFT );
1572 28 : return true;
1573 : }
1574 :
1575 1363 : long nMaxPoints = 1 + rOutline.n_points * 3;
1576 1363 : PolyPolygon aToolPolyPolygon;
1577 2726 : PolyArgs aPolyArg( aToolPolyPolygon, nMaxPoints );
1578 :
1579 1363 : /*int nAngle =*/ ApplyGlyphTransform( nGlyphFlags, pGlyphFT, false );
1580 :
1581 : FT_Outline_Funcs aFuncs;
1582 1363 : aFuncs.move_to = &FT_move_to;
1583 1363 : aFuncs.line_to = &FT_line_to;
1584 1363 : aFuncs.conic_to = &FT_conic_to;
1585 1363 : aFuncs.cubic_to = &FT_cubic_to;
1586 1363 : aFuncs.shift = 0;
1587 1363 : aFuncs.delta = 0;
1588 1363 : rc = FT_Outline_Decompose( &rOutline, &aFuncs, (void*)&aPolyArg );
1589 1363 : aPolyArg.ClosePolygon(); // close last polygon
1590 1363 : FT_Done_Glyph( pGlyphFT );
1591 :
1592 : // convert to basegfx polypolygon
1593 : // TODO: get rid of the intermediate tools polypolygon
1594 1363 : rB2DPolyPoly = aToolPolyPolygon.getB2DPolyPolygon();
1595 1363 : rB2DPolyPoly.transform(basegfx::tools::createScaleB2DHomMatrix( +1.0/(1<<6), -1.0/(1<<6) ));
1596 :
1597 2726 : return true;
1598 : }
1599 :
1600 3702 : bool ServerFont::ApplyGSUB( const FontSelectPattern& rFSD )
1601 : {
1602 : #define MKTAG(s) ((((((s[0]<<8)+s[1])<<8)+s[2])<<8)+s[3])
1603 :
1604 : typedef std::vector<sal_uLong> ReqFeatureTagList;
1605 3702 : ReqFeatureTagList aReqFeatureTagList;
1606 3702 : if( rFSD.mbVertical )
1607 5 : aReqFeatureTagList.push_back( MKTAG("vert") );
1608 3702 : sal_uLong nRequestedScript = 0; //MKTAG("hani");//### TODO: where to get script?
1609 3702 : sal_uLong nRequestedLangsys = 0; //MKTAG("ZHT"); //### TODO: where to get langsys?
1610 : // TODO: request more features depending on script and language system
1611 :
1612 3702 : if( aReqFeatureTagList.empty()) // nothing to do
1613 3697 : return true;
1614 :
1615 : // load GSUB table into memory
1616 5 : sal_uLong nLength = 0;
1617 5 : const FT_Byte* const pGsubBase = mpFontInfo->GetTable( "GSUB", &nLength );
1618 5 : if( !pGsubBase )
1619 0 : return false;
1620 :
1621 : // parse GSUB header
1622 5 : const FT_Byte* pGsubHeader = pGsubBase;
1623 5 : const sal_uInt16 nOfsScriptList = GetUShort( pGsubHeader+4 );
1624 5 : const sal_uInt16 nOfsFeatureTable = GetUShort( pGsubHeader+6 );
1625 5 : const sal_uInt16 nOfsLookupList = GetUShort( pGsubHeader+8 );
1626 5 : pGsubHeader += 10;
1627 :
1628 : typedef std::vector<sal_uInt16> UshortList;
1629 10 : UshortList aFeatureIndexList;
1630 :
1631 : // parse Script Table
1632 5 : const FT_Byte* pScriptHeader = pGsubBase + nOfsScriptList;
1633 5 : const sal_uInt16 nCntScript = GetUShort( pScriptHeader+0 );
1634 5 : pScriptHeader += 2;
1635 20 : for( sal_uInt16 nScriptIndex = 0; nScriptIndex < nCntScript; ++nScriptIndex )
1636 : {
1637 15 : const sal_uLong nScriptTag = GetUInt( pScriptHeader+0 ); // e.g. hani/arab/kana/hang
1638 15 : const sal_uInt16 nOfsScriptTable= GetUShort( pScriptHeader+4 );
1639 15 : pScriptHeader += 6;
1640 15 : if( (nScriptTag != nRequestedScript) && (nRequestedScript != 0) )
1641 0 : continue;
1642 :
1643 15 : const FT_Byte* pScriptTable = pGsubBase + nOfsScriptList + nOfsScriptTable;
1644 15 : const sal_uInt16 nDefaultLangsysOfs = GetUShort( pScriptTable+0 );
1645 15 : const sal_uInt16 nCntLangSystem = GetUShort( pScriptTable+2 );
1646 15 : pScriptTable += 4;
1647 15 : sal_uInt16 nLangsysOffset = 0;
1648 :
1649 15 : for( sal_uInt16 nLangsysIndex = 0; nLangsysIndex < nCntLangSystem; ++nLangsysIndex )
1650 : {
1651 10 : const sal_uLong nTag = GetUInt( pScriptTable+0 ); // e.g. KOR/ZHS/ZHT/JAN
1652 10 : const sal_uInt16 nOffset= GetUShort( pScriptTable+4 );
1653 10 : pScriptTable += 6;
1654 10 : if( (nTag != nRequestedLangsys) && (nRequestedLangsys != 0) )
1655 0 : continue;
1656 10 : nLangsysOffset = nOffset;
1657 10 : break;
1658 : }
1659 :
1660 15 : if( (nDefaultLangsysOfs != 0) && (nDefaultLangsysOfs != nLangsysOffset) )
1661 : {
1662 15 : const FT_Byte* pLangSys = pGsubBase + nOfsScriptList + nOfsScriptTable + nDefaultLangsysOfs;
1663 15 : const sal_uInt16 nReqFeatureIdx = GetUShort( pLangSys+2 );
1664 15 : const sal_uInt16 nCntFeature = GetUShort( pLangSys+4 );
1665 15 : pLangSys += 6;
1666 15 : aFeatureIndexList.push_back( nReqFeatureIdx );
1667 325 : for( sal_uInt16 i = 0; i < nCntFeature; ++i )
1668 : {
1669 310 : const sal_uInt16 nFeatureIndex = GetUShort( pLangSys );
1670 310 : pLangSys += 2;
1671 310 : aFeatureIndexList.push_back( nFeatureIndex );
1672 : }
1673 : }
1674 :
1675 15 : if( nLangsysOffset != 0 )
1676 : {
1677 10 : const FT_Byte* pLangSys = pGsubBase + nOfsScriptList + nOfsScriptTable + nLangsysOffset;
1678 10 : const sal_uInt16 nReqFeatureIdx = GetUShort( pLangSys+2 );
1679 10 : const sal_uInt16 nCntFeature = GetUShort( pLangSys+4 );
1680 10 : pLangSys += 6;
1681 10 : aFeatureIndexList.push_back( nReqFeatureIdx );
1682 155 : for( sal_uInt16 i = 0; i < nCntFeature; ++i )
1683 : {
1684 145 : const sal_uInt16 nFeatureIndex = GetUShort( pLangSys );
1685 145 : pLangSys += 2;
1686 145 : aFeatureIndexList.push_back( nFeatureIndex );
1687 : }
1688 : }
1689 : }
1690 :
1691 5 : if( aFeatureIndexList.empty() )
1692 0 : return true;
1693 :
1694 10 : UshortList aLookupIndexList;
1695 10 : UshortList aLookupOffsetList;
1696 :
1697 : // parse Feature Table
1698 5 : const FT_Byte* pFeatureHeader = pGsubBase + nOfsFeatureTable;
1699 5 : const sal_uInt16 nCntFeature = GetUShort( pFeatureHeader );
1700 5 : pFeatureHeader += 2;
1701 685 : for( sal_uInt16 nFeatureIndex = 0; nFeatureIndex < nCntFeature; ++nFeatureIndex )
1702 : {
1703 680 : const sal_uLong nTag = GetUInt( pFeatureHeader+0 ); // e.g. locl/vert/trad/smpl/liga/fina/...
1704 680 : const sal_uInt16 nOffset= GetUShort( pFeatureHeader+4 );
1705 680 : pFeatureHeader += 6;
1706 :
1707 : // short circuit some feature lookups
1708 680 : if( aFeatureIndexList[0] != nFeatureIndex ) // required feature?
1709 : {
1710 680 : const int nRequested = std::count( aFeatureIndexList.begin(), aFeatureIndexList.end(), nFeatureIndex);
1711 680 : if( !nRequested ) // ignore features that are not requested
1712 905 : continue;
1713 455 : const int nAvailable = std::count( aReqFeatureTagList.begin(), aReqFeatureTagList.end(), nTag);
1714 455 : if( !nAvailable ) // some fonts don't provide features they request!
1715 455 : continue;
1716 : }
1717 :
1718 0 : const FT_Byte* pFeatureTable = pGsubBase + nOfsFeatureTable + nOffset;
1719 0 : const sal_uInt16 nCntLookups = GetUShort( pFeatureTable+0 );
1720 0 : pFeatureTable += 2;
1721 0 : for( sal_uInt16 i = 0; i < nCntLookups; ++i )
1722 : {
1723 0 : const sal_uInt16 nLookupIndex = GetUShort( pFeatureTable );
1724 0 : pFeatureTable += 2;
1725 0 : aLookupIndexList.push_back( nLookupIndex );
1726 : }
1727 0 : if( nCntLookups == 0 ) //### hack needed by Mincho/Gothic/Mingliu/Simsun/...
1728 0 : aLookupIndexList.push_back( 0 );
1729 : }
1730 :
1731 : // parse Lookup List
1732 5 : const FT_Byte* pLookupHeader = pGsubBase + nOfsLookupList;
1733 5 : const sal_uInt16 nCntLookupTable = GetUShort( pLookupHeader );
1734 5 : pLookupHeader += 2;
1735 205 : for( sal_uInt16 nLookupIdx = 0; nLookupIdx < nCntLookupTable; ++nLookupIdx )
1736 : {
1737 200 : const sal_uInt16 nOffset = GetUShort( pLookupHeader );
1738 200 : pLookupHeader += 2;
1739 200 : if( std::count( aLookupIndexList.begin(), aLookupIndexList.end(), nLookupIdx ) )
1740 0 : aLookupOffsetList.push_back( nOffset );
1741 : }
1742 :
1743 5 : UshortList::const_iterator lookup_it = aLookupOffsetList.begin();
1744 5 : for(; lookup_it != aLookupOffsetList.end(); ++lookup_it )
1745 : {
1746 0 : const sal_uInt16 nOfsLookupTable = *lookup_it;
1747 0 : const FT_Byte* pLookupTable = pGsubBase + nOfsLookupList + nOfsLookupTable;
1748 0 : const sal_uInt16 eLookupType = GetUShort( pLookupTable+0 );
1749 0 : const sal_uInt16 nCntLookupSubtable = GetUShort( pLookupTable+4 );
1750 0 : pLookupTable += 6;
1751 :
1752 : // TODO: switch( eLookupType )
1753 0 : if( eLookupType != 1 ) // TODO: once we go beyond SingleSubst
1754 0 : continue;
1755 :
1756 0 : for( sal_uInt16 nSubTableIdx = 0; nSubTableIdx < nCntLookupSubtable; ++nSubTableIdx )
1757 : {
1758 0 : const sal_uInt16 nOfsSubLookupTable = GetUShort( pLookupTable );
1759 0 : pLookupTable += 2;
1760 0 : const FT_Byte* pSubLookup = pGsubBase + nOfsLookupList + nOfsLookupTable + nOfsSubLookupTable;
1761 :
1762 0 : const sal_uInt16 nFmtSubstitution = GetUShort( pSubLookup+0 );
1763 0 : const sal_uInt16 nOfsCoverage = GetUShort( pSubLookup+2 );
1764 0 : pSubLookup += 4;
1765 :
1766 : typedef std::pair<sal_uInt16,sal_uInt16> GlyphSubst;
1767 : typedef std::vector<GlyphSubst> SubstVector;
1768 0 : SubstVector aSubstVector;
1769 :
1770 0 : const FT_Byte* pCoverage = pGsubBase + nOfsLookupList + nOfsLookupTable + nOfsSubLookupTable + nOfsCoverage;
1771 0 : const sal_uInt16 nFmtCoverage = GetUShort( pCoverage+0 );
1772 0 : pCoverage += 2;
1773 0 : switch( nFmtCoverage )
1774 : {
1775 : case 1: // Coverage Format 1
1776 : {
1777 0 : const sal_uInt16 nCntGlyph = GetUShort( pCoverage );
1778 0 : pCoverage += 2;
1779 0 : aSubstVector.reserve( nCntGlyph );
1780 0 : for( sal_uInt16 i = 0; i < nCntGlyph; ++i )
1781 : {
1782 0 : const sal_uInt16 nGlyphId = GetUShort( pCoverage );
1783 0 : pCoverage += 2;
1784 0 : aSubstVector.push_back( GlyphSubst( nGlyphId, 0 ) );
1785 : }
1786 : }
1787 0 : break;
1788 :
1789 : case 2: // Coverage Format 2
1790 : {
1791 0 : const sal_uInt16 nCntRange = GetUShort( pCoverage );
1792 0 : pCoverage += 2;
1793 0 : for( int i = nCntRange; --i >= 0; )
1794 : {
1795 0 : const sal_uInt32 nGlyph0 = GetUShort( pCoverage+0 );
1796 0 : const sal_uInt32 nGlyph1 = GetUShort( pCoverage+2 );
1797 0 : const sal_uInt16 nCovIdx = GetUShort( pCoverage+4 );
1798 0 : pCoverage += 6;
1799 0 : for( sal_uInt32 j = nGlyph0; j <= nGlyph1; ++j )
1800 0 : aSubstVector.push_back( GlyphSubst( static_cast<sal_uInt16>(j + nCovIdx), 0 ) );
1801 : }
1802 : }
1803 0 : break;
1804 : }
1805 :
1806 0 : SubstVector::iterator it( aSubstVector.begin() );
1807 :
1808 0 : switch( nFmtSubstitution )
1809 : {
1810 : case 1: // Single Substitution Format 1
1811 : {
1812 0 : const sal_uInt16 nDeltaGlyphId = GetUShort( pSubLookup );
1813 0 : pSubLookup += 2;
1814 0 : for(; it != aSubstVector.end(); ++it )
1815 0 : (*it).second = (*it).first + nDeltaGlyphId;
1816 : }
1817 0 : break;
1818 :
1819 : case 2: // Single Substitution Format 2
1820 : {
1821 0 : const sal_uInt16 nCntGlyph = GetUShort( pSubLookup );
1822 0 : pSubLookup += 2;
1823 0 : for( int i = nCntGlyph; (it != aSubstVector.end()) && (--i>=0); ++it )
1824 : {
1825 0 : const sal_uInt16 nGlyphId = GetUShort( pSubLookup );
1826 0 : pSubLookup += 2;
1827 0 : (*it).second = nGlyphId;
1828 : }
1829 : }
1830 0 : break;
1831 : }
1832 :
1833 : DBG_ASSERT( (it == aSubstVector.end()), "lookup<->coverage table mismatch" );
1834 : // now apply the glyph substitutions that have been collected in this subtable
1835 0 : for( it = aSubstVector.begin(); it != aSubstVector.end(); ++it )
1836 0 : maGlyphSubstitution[ (*it).first ] = (*it).second;
1837 0 : }
1838 : }
1839 :
1840 3707 : return true;
1841 : }
1842 :
1843 11312 : const unsigned char* ServerFont::GetTable(const char* pName, sal_uLong* pLength)
1844 : {
1845 11312 : return mpFontInfo->GetTable( pName, pLength );
1846 : }
1847 :
1848 : #if ENABLE_GRAPHITE
1849 2227 : GraphiteFaceWrapper* ServerFont::GetGraphiteFace() const
1850 : {
1851 2227 : return mpFontInfo->GetGraphiteFace();
1852 516 : }
1853 : #endif
1854 :
1855 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|