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