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