Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <unistd.h>
21 : #include <sys/stat.h>
22 : #include <dirent.h>
23 : #include <stdlib.h>
24 : #include <osl/thread.h>
25 :
26 : #include "unotools/atom.hxx"
27 :
28 : #include "fontcache.hxx"
29 : #include "fontsubset.hxx"
30 : #include "impfont.hxx"
31 : #include "svdata.hxx"
32 : #include "generic/geninst.h"
33 : #include "fontmanager.hxx"
34 : #include "vcl/strhelper.hxx"
35 : #include "vcl/ppdparser.hxx"
36 : #include <vcl/embeddedfontshelper.hxx>
37 :
38 : #include "tools/urlobj.hxx"
39 : #include "tools/stream.hxx"
40 : #include "tools/debug.hxx"
41 :
42 : #include "osl/file.hxx"
43 : #include "osl/process.h"
44 :
45 : #include "rtl/tencinfo.h"
46 : #include "rtl/ustrbuf.hxx"
47 : #include "rtl/strbuf.hxx"
48 :
49 : #include <sal/macros.h>
50 :
51 : #include "i18nlangtag/applelangid.hxx"
52 : #include "i18nlangtag/mslangid.hxx"
53 :
54 : #include "parseAFM.hxx"
55 : #include "sft.hxx"
56 :
57 : #if OSL_DEBUG_LEVEL > 1
58 : #include <sys/times.h>
59 : #include <stdio.h>
60 : #endif
61 :
62 : #include "sal/alloca.h"
63 :
64 : #include <algorithm>
65 : #include <set>
66 : #include <unordered_set>
67 :
68 : #include "adobeenc.tab"
69 :
70 : #ifdef CALLGRIND_COMPILE
71 : #include <valgrind/callgrind.h>
72 : #endif
73 :
74 : #include <comphelper/processfactory.hxx>
75 : #include <comphelper/string.hxx>
76 : #include "com/sun/star/beans/XMaterialHolder.hpp"
77 : #include "com/sun/star/beans/NamedValue.hpp"
78 :
79 : using namespace vcl;
80 : using namespace utl;
81 : using namespace psp;
82 : using namespace osl;
83 : using namespace com::sun::star::uno;
84 : using namespace com::sun::star::beans;
85 : using namespace com::sun::star::lang;
86 :
87 : /*
88 : * static helpers
89 : */
90 :
91 189538 : inline sal_uInt16 getUInt16BE( const sal_uInt8*& pBuffer )
92 : {
93 189538 : sal_uInt16 nRet = (sal_uInt16)pBuffer[1] |
94 189538 : (((sal_uInt16)pBuffer[0]) << 8);
95 189538 : pBuffer+=2;
96 189538 : return nRet;
97 : }
98 :
99 3655 : static FontWeight parseWeight( const OString& rWeight )
100 : {
101 3655 : FontWeight eWeight = WEIGHT_DONTKNOW;
102 3655 : if (rWeight.indexOf("bold") != -1)
103 : {
104 1624 : if (rWeight.indexOf("emi") != -1) // semi, demi
105 0 : eWeight = WEIGHT_SEMIBOLD;
106 1624 : else if (rWeight.indexOf("ultra") != -1)
107 0 : eWeight = WEIGHT_ULTRABOLD;
108 : else
109 1624 : eWeight = WEIGHT_BOLD;
110 : }
111 2031 : else if (rWeight.indexOf("heavy") != -1)
112 0 : eWeight = WEIGHT_BOLD;
113 2031 : else if (rWeight.indexOf("light") != -1)
114 : {
115 0 : if (rWeight.indexOf("emi") != -1) // semi, demi
116 0 : eWeight = WEIGHT_SEMILIGHT;
117 0 : else if (rWeight.indexOf("ultra") != -1)
118 0 : eWeight = WEIGHT_ULTRALIGHT;
119 : else
120 0 : eWeight = WEIGHT_LIGHT;
121 : }
122 2031 : else if (rWeight.indexOf("black") != -1)
123 0 : eWeight = WEIGHT_BLACK;
124 2031 : else if (rWeight == "demi")
125 116 : eWeight = WEIGHT_SEMIBOLD;
126 3714 : else if ((rWeight == "book") ||
127 1799 : (rWeight == "semicondensed"))
128 116 : eWeight = WEIGHT_LIGHT;
129 1799 : else if ((rWeight == "medium") || (rWeight == "roman"))
130 174 : eWeight = WEIGHT_MEDIUM;
131 : else
132 1625 : eWeight = WEIGHT_NORMAL;
133 3655 : return eWeight;
134 : }
135 :
136 : /*
137 : * PrintFont implementations
138 : */
139 96760 : PrintFontManager::PrintFont::PrintFont( fonttype::type eType ) :
140 : m_eType( eType ),
141 : m_nFamilyName( 0 ),
142 : m_nPSName( 0 ),
143 : m_eItalic( ITALIC_DONTKNOW ),
144 : m_eWidth( WIDTH_DONTKNOW ),
145 : m_eWeight( WEIGHT_DONTKNOW ),
146 : m_ePitch( PITCH_DONTKNOW ),
147 : m_aEncoding( RTL_TEXTENCODING_DONTKNOW ),
148 : m_bFontEncodingOnly( false ),
149 : m_pMetrics( NULL ),
150 : m_nAscend( 0 ),
151 : m_nDescend( 0 ),
152 : m_nLeading( 0 ),
153 : m_nXMin( 0 ),
154 : m_nYMin( 0 ),
155 : m_nXMax( 0 ),
156 : m_nYMax( 0 ),
157 : m_bHaveVerticalSubstitutedGlyphs( false ),
158 96760 : m_bUserOverride( false )
159 : {
160 96760 : }
161 :
162 193520 : PrintFontManager::PrintFont::~PrintFont()
163 : {
164 96760 : delete m_pMetrics;
165 96760 : }
166 :
167 51660 : PrintFontManager::Type1FontFile::~Type1FontFile()
168 : {
169 51660 : }
170 :
171 70930 : PrintFontManager::TrueTypeFontFile::TrueTypeFontFile()
172 : : PrintFont( fonttype::TrueType )
173 : , m_nDirectory( 0 )
174 : , m_nCollectionEntry( 0 )
175 70930 : , m_nTypeFlags( TYPEFLAG_INVALID )
176 70930 : {}
177 :
178 141860 : PrintFontManager::TrueTypeFontFile::~TrueTypeFontFile()
179 : {
180 141860 : }
181 :
182 0 : bool PrintFontManager::Type1FontFile::queryMetricPage( int /*nPage*/, MultiAtomProvider* pProvider )
183 : {
184 0 : return readAfmMetrics( pProvider, false, false );
185 : }
186 :
187 0 : bool PrintFontManager::TrueTypeFontFile::queryMetricPage( int nPage, MultiAtomProvider* /*pProvider*/ )
188 : {
189 0 : bool bSuccess = false;
190 :
191 0 : OString aFile( PrintFontManager::get().getFontFile( this ) );
192 :
193 0 : TrueTypeFont* pTTFont = NULL;
194 :
195 0 : if( OpenTTFontFile( aFile.getStr(), m_nCollectionEntry, &pTTFont ) == SF_OK )
196 : {
197 0 : if( ! m_pMetrics )
198 : {
199 0 : m_pMetrics = new PrintFontMetrics;
200 0 : memset (m_pMetrics->m_aPages, 0, sizeof(m_pMetrics->m_aPages));
201 : }
202 0 : m_pMetrics->m_aPages[ nPage/8 ] |= (1 << ( nPage & 7 ));
203 : int i;
204 : sal_uInt16 table[256], table_vert[256];
205 :
206 0 : for( i = 0; i < 256; i++ )
207 0 : table[ i ] = 256*nPage + i;
208 :
209 0 : int nCharacters = nPage < 255 ? 256 : 254;
210 0 : MapString( pTTFont, table, nCharacters, NULL, false );
211 0 : TTSimpleGlyphMetrics* pMetrics = GetTTSimpleCharMetrics( pTTFont, nPage*256, nCharacters, false );
212 0 : if( pMetrics )
213 : {
214 0 : for( i = 0; i < nCharacters; i++ )
215 : {
216 0 : if( table[i] )
217 : {
218 0 : CharacterMetric& rChar = m_pMetrics->m_aMetrics[ nPage*256 + i ];
219 0 : rChar.width = pMetrics[ i ].adv;
220 0 : rChar.height = m_aGlobalMetricX.height;
221 : }
222 : }
223 :
224 0 : free( pMetrics );
225 : }
226 :
227 0 : for( i = 0; i < 256; i++ )
228 0 : table_vert[ i ] = 256*nPage + i;
229 0 : MapString( pTTFont, table_vert, nCharacters, NULL, true );
230 0 : pMetrics = GetTTSimpleCharMetrics( pTTFont, nPage*256, nCharacters, true );
231 0 : if( pMetrics )
232 : {
233 0 : for( i = 0; i < nCharacters; i++ )
234 : {
235 0 : if( table_vert[i] )
236 : {
237 0 : CharacterMetric& rChar = m_pMetrics->m_aMetrics[ nPage*256 + i + ( 1 << 16 ) ];
238 0 : rChar.width = m_aGlobalMetricY.width;
239 0 : rChar.height = pMetrics[ i ].adv;
240 0 : if( table_vert[i] != table[i] )
241 0 : m_pMetrics->m_bVerticalSubstitutions[ nPage*256 + i ] = true;
242 : }
243 : }
244 0 : free( pMetrics );
245 : }
246 0 : CloseTTFont( pTTFont );
247 0 : bSuccess = true;
248 : }
249 0 : return bSuccess;
250 : }
251 :
252 : /* #i73387# There seem to be fonts with a rather unwell chosen family name
253 : * consider e.g. "Helvetica Narrow" which defines its family as "Helvetica"
254 : * It can really only be distinguished by its PSName and FullName. Both of
255 : * which are not user presentable in OOo. So replace it by something sensible.
256 : *
257 : * If other fonts feature this behaviour, insert them to the map.
258 : */
259 3654 : static bool familyNameOverride( const OUString& i_rPSname, OUString& o_rFamilyName )
260 : {
261 3654 : static std::unordered_map< OUString, OUString, OUStringHash > aPSNameToFamily( 16 );
262 3654 : if( aPSNameToFamily.empty() ) // initialization
263 : {
264 58 : aPSNameToFamily[ "Helvetica-Narrow" ] = "Helvetica Narrow";
265 58 : aPSNameToFamily[ "Helvetica-Narrow-Bold" ] = "Helvetica Narrow";
266 58 : aPSNameToFamily[ "Helvetica-Narrow-BoldOblique" ] = "Helvetica Narrow";
267 58 : aPSNameToFamily[ "Helvetica-Narrow-Oblique" ] = "Helvetica Narrow";
268 : }
269 : std::unordered_map<OUString,OUString,OUStringHash>::const_iterator it =
270 3654 : aPSNameToFamily.find( i_rPSname );
271 3654 : bool bReplaced = (it != aPSNameToFamily.end() );
272 3654 : if( bReplaced )
273 0 : o_rFamilyName = it->second;
274 3654 : return bReplaced;
275 : };
276 :
277 3655 : bool PrintFontManager::PrintFont::readAfmMetrics( MultiAtomProvider* pProvider, bool bFillEncodingvector, bool bOnlyGlobalAttributes )
278 : {
279 3655 : PrintFontManager& rManager( PrintFontManager::get() );
280 3655 : const OString& rFileName = rManager.getAfmFile( this );
281 :
282 3655 : FontInfo* pInfo = NULL;
283 3655 : parseFile( rFileName.getStr(), &pInfo, P_ALL );
284 3655 : if( ! pInfo || ! pInfo->numOfChars )
285 : {
286 0 : if( pInfo )
287 0 : freeFontInfo( pInfo );
288 0 : return false;
289 : }
290 :
291 3655 : m_aEncodingVector.clear();
292 3655 : m_aEncodingVectorPriority.clear();
293 : // fill in global info
294 :
295 : // PSName
296 7310 : OUString aPSName( OStringToOUString( pInfo->gfi->fontName, RTL_TEXTENCODING_ISO_8859_1 ) );
297 3655 : m_nPSName = pProvider->getAtom( ATOM_PSNAME, aPSName, true );
298 :
299 : // family name (if not already set)
300 7310 : OUString aFamily;
301 3655 : if( ! m_nFamilyName )
302 : {
303 3654 : aFamily = OStringToOUString( pInfo->gfi->familyName, RTL_TEXTENCODING_ISO_8859_1 );
304 3654 : if( aFamily.isEmpty() )
305 : {
306 0 : aFamily = OStringToOUString( pInfo->gfi->fontName, RTL_TEXTENCODING_ISO_8859_1 );
307 0 : sal_Int32 nIndex = 0;
308 0 : aFamily = aFamily.getToken( 0, '-', nIndex );
309 : }
310 3654 : familyNameOverride( aPSName, aFamily );
311 3654 : m_nFamilyName = pProvider->getAtom( ATOM_FAMILYNAME, aFamily, true );
312 : }
313 : else
314 1 : aFamily = pProvider->getString( ATOM_FAMILYNAME, m_nFamilyName );
315 :
316 : // style name: if fullname begins with family name
317 : // interpret the rest of fullname as style
318 3655 : if( m_aStyleName.isEmpty() && pInfo->gfi->fullName && *pInfo->gfi->fullName )
319 : {
320 3654 : OUString aFullName( OStringToOUString( pInfo->gfi->fullName, RTL_TEXTENCODING_ISO_8859_1 ) );
321 3654 : if( aFullName.startsWith( aFamily ) )
322 3654 : m_aStyleName = WhitespaceToSpace( aFullName.copy( aFamily.getLength() ) );
323 : }
324 :
325 : // italic
326 3655 : if( pInfo->gfi->italicAngle > 0 )
327 232 : m_eItalic = ITALIC_OBLIQUE;
328 3423 : else if( pInfo->gfi->italicAngle < 0 )
329 1566 : m_eItalic = ITALIC_NORMAL;
330 : else
331 1857 : m_eItalic = ITALIC_NONE;
332 :
333 : // weight
334 7310 : OString aWeight( pInfo->gfi->weight );
335 3655 : m_eWeight = parseWeight( aWeight.toAsciiLowerCase() );
336 :
337 : // pitch
338 3655 : m_ePitch = pInfo->gfi->isFixedPitch ? PITCH_FIXED : PITCH_VARIABLE;
339 :
340 : // encoding - only set if unknown
341 3655 : int nAdobeEncoding = 0;
342 3655 : if( pInfo->gfi->encodingScheme )
343 : {
344 3655 : if( !strcmp( pInfo->gfi->encodingScheme, "AdobeStandardEncoding" ) )
345 2843 : nAdobeEncoding = 1;
346 812 : else if( !strcmp( pInfo->gfi->encodingScheme, "ISO10646-1" ) )
347 : {
348 0 : nAdobeEncoding = 1;
349 0 : m_aEncoding = RTL_TEXTENCODING_UNICODE;
350 : }
351 812 : else if( !strcmp( pInfo->gfi->encodingScheme, "Symbol") )
352 0 : nAdobeEncoding = 2;
353 812 : else if( !strcmp( pInfo->gfi->encodingScheme, "FontSpecific") )
354 812 : nAdobeEncoding = 3;
355 :
356 3655 : if( m_aEncoding == RTL_TEXTENCODING_DONTKNOW )
357 : m_aEncoding = nAdobeEncoding == 1 ?
358 3654 : RTL_TEXTENCODING_ADOBE_STANDARD : RTL_TEXTENCODING_SYMBOL;
359 : }
360 0 : else if( m_aEncoding == RTL_TEXTENCODING_DONTKNOW )
361 0 : m_aEncoding = RTL_TEXTENCODING_ADOBE_STANDARD;
362 :
363 : // try to parse the font name and decide whether it might be a
364 : // japanese font. Who invented this PITA ?
365 7310 : OUString aPSNameLastToken( aPSName.copy( aPSName.lastIndexOf( '-' )+1 ) );
366 7310 : if( aPSNameLastToken == "H" ||
367 3655 : aPSNameLastToken == "V" )
368 : {
369 : static const char* pEncs[] =
370 : {
371 : "EUC",
372 : "RKSJ",
373 : "SJ"
374 : };
375 : static const rtl_TextEncoding aEncs[] =
376 : {
377 : RTL_TEXTENCODING_EUC_JP,
378 : RTL_TEXTENCODING_SHIFT_JIS,
379 : RTL_TEXTENCODING_JIS_X_0208
380 : };
381 :
382 0 : for( unsigned int enc = 0; enc < SAL_N_ELEMENTS( aEncs ) && m_aEncoding == RTL_TEXTENCODING_DONTKNOW; enc++ )
383 : {
384 0 : sal_Int32 nIndex = 0, nOffset = 1;
385 0 : do
386 : {
387 0 : OUString aToken( aPSName.getToken( nOffset, '-', nIndex ) );
388 0 : if( nIndex == -1 )
389 0 : break;
390 0 : nOffset = 0;
391 0 : if( aToken.equalsAscii( pEncs[enc] ) )
392 : {
393 0 : m_aEncoding = aEncs[ enc ];
394 0 : m_bFontEncodingOnly = true;
395 0 : }
396 0 : } while( nIndex != -1 );
397 : }
398 :
399 : // default is jis
400 0 : if( m_aEncoding == RTL_TEXTENCODING_DONTKNOW )
401 0 : m_aEncoding = RTL_TEXTENCODING_JIS_X_0208;
402 : #if OSL_DEBUG_LEVEL > 1
403 : fprintf( stderr, "Encoding %d for %s\n", m_aEncoding, pInfo->gfi->fontName );
404 : #endif
405 : }
406 :
407 : // #i37313# check if Fontspecific is not rather some character encoding
408 3655 : if( nAdobeEncoding == 3 && m_aEncoding == RTL_TEXTENCODING_SYMBOL )
409 : {
410 812 : bool bYFound = false;
411 812 : bool bQFound = false;
412 812 : CharMetricInfo* pChar = pInfo->cmi;
413 63974 : for( int j = 0; j < pInfo->numOfChars && ! (bYFound && bQFound); j++ )
414 : {
415 63162 : if( pChar[j].name )
416 : {
417 63162 : if( pChar[j].name[0] == 'Y' && pChar[j].name[1] == 0 )
418 696 : bYFound = true;
419 62466 : else if( pChar[j].name[0] == 'Q' && pChar[j].name[1] == 0 )
420 696 : bQFound = true;
421 : }
422 : }
423 812 : if( bQFound && bYFound )
424 : {
425 : #if OSL_DEBUG_LEVEL > 1
426 : fprintf( stderr, "setting FontSpecific font %s (file %s) to unicode\n",
427 : pInfo->gfi->fontName,
428 : rFileName.getStr()
429 : );
430 : #endif
431 696 : nAdobeEncoding = 4;
432 696 : m_aEncoding = RTL_TEXTENCODING_UNICODE;
433 696 : bFillEncodingvector = false; // will be filled anyway, don't do the work twice
434 : }
435 : }
436 :
437 : // ascend
438 3655 : m_nAscend = pInfo->gfi->fontBBox.ury;
439 :
440 : // descend
441 : // descends have opposite sign of our definition
442 3655 : m_nDescend = -pInfo->gfi->fontBBox.lly;
443 :
444 : // fallback to ascender, descender
445 : // interesting: the BBox seems to describe Ascender and Descender better
446 : // as we understand it
447 3655 : if( m_nAscend == 0 )
448 0 : m_nAscend = pInfo->gfi->ascender;
449 3655 : if( m_nDescend == 0)
450 0 : m_nDescend = -pInfo->gfi->descender;
451 :
452 3655 : m_nLeading = m_nAscend + m_nDescend - 1000;
453 :
454 3655 : delete m_pMetrics;
455 3655 : m_pMetrics = new PrintFontMetrics;
456 : // mark all pages as queried (or clear if only global font info queiried)
457 3655 : memset( m_pMetrics->m_aPages, bOnlyGlobalAttributes ? 0 : 0xff, sizeof( m_pMetrics->m_aPages ) );
458 :
459 : m_aGlobalMetricX.width = m_aGlobalMetricY.width =
460 3655 : pInfo->gfi->charwidth ? pInfo->gfi->charwidth : pInfo->gfi->fontBBox.urx;
461 : m_aGlobalMetricX.height = m_aGlobalMetricY.height =
462 3655 : pInfo->gfi->capHeight ? pInfo->gfi->capHeight : pInfo->gfi->fontBBox.ury;
463 :
464 3655 : m_nXMin = pInfo->gfi->fontBBox.llx;
465 3655 : m_nYMin = pInfo->gfi->fontBBox.lly;
466 3655 : m_nXMax = pInfo->gfi->fontBBox.urx;
467 3655 : m_nYMax = pInfo->gfi->fontBBox.ury;
468 :
469 3655 : if( bFillEncodingvector || !bOnlyGlobalAttributes )
470 : {
471 : // fill in character metrics
472 :
473 : // first transform the character codes to unicode
474 : // note: this only works with single byte encodings
475 1 : sal_Unicode* pUnicodes = static_cast<sal_Unicode*>(alloca( pInfo->numOfChars * sizeof(sal_Unicode)));
476 1 : CharMetricInfo* pChar = pInfo->cmi;
477 : int i;
478 :
479 563 : for( i = 0; i < pInfo->numOfChars; i++, pChar++ )
480 : {
481 562 : if( nAdobeEncoding == 4 )
482 : {
483 0 : if( pChar->name )
484 : {
485 0 : pUnicodes[i] = 0;
486 0 : std::list< sal_Unicode > aCodes = rManager.getUnicodeFromAdobeName( pChar->name );
487 0 : for( std::list< sal_Unicode >::const_iterator it = aCodes.begin(); it != aCodes.end(); ++it )
488 : {
489 0 : if( *it != 0 )
490 : {
491 0 : m_aEncodingVector[ *it ] = pChar->code;
492 0 : if( pChar->code == -1 )
493 0 : m_aNonEncoded[ *it ] = pChar->name;
494 0 : if( ! pUnicodes[i] ) // map the first
495 0 : pUnicodes[i] = *it;
496 : }
497 0 : }
498 : }
499 : }
500 562 : else if( pChar->code != -1 )
501 : {
502 149 : if( nAdobeEncoding == 3 && m_aEncoding == RTL_TEXTENCODING_SYMBOL )
503 : {
504 0 : pUnicodes[i] = pChar->code + 0xf000;
505 0 : if( bFillEncodingvector )
506 : {
507 0 : m_aEncodingVector[ pUnicodes[i] ] = pChar->code;
508 0 : m_aEncodingVectorPriority.insert(pUnicodes[i]);
509 : }
510 0 : continue;
511 : }
512 :
513 149 : if( m_aEncoding == RTL_TEXTENCODING_UNICODE )
514 : {
515 0 : pUnicodes[i] = (sal_Unicode)pChar->code;
516 0 : continue;
517 : }
518 :
519 149 : OStringBuffer aTranslate;
520 149 : if( pChar->code & 0xff000000 )
521 0 : aTranslate.append((char)(pChar->code >> 24));
522 149 : if( pChar->code & 0xffff0000 )
523 0 : aTranslate.append((char)((pChar->code & 0x00ff0000) >> 16));
524 149 : if( pChar->code & 0xffffff00 )
525 0 : aTranslate.append((char)((pChar->code & 0x0000ff00) >> 8 ));
526 149 : aTranslate.append((char)(pChar->code & 0xff));
527 298 : OUString aUni(OStringToOUString(aTranslate.makeStringAndClear(), m_aEncoding));
528 298 : pUnicodes[i] = aUni.toChar();
529 : }
530 : else
531 413 : pUnicodes[i] = 0;
532 : }
533 :
534 : // now fill in the character metrics
535 : // parseAFM.cxx effectively only supports direction 0 (horizontal)
536 1 : pChar = pInfo->cmi;
537 1 : CharacterMetric aMetric;
538 563 : for( i = 0; i < pInfo->numOfChars; i++, pChar++ )
539 : {
540 562 : if( pChar->code == -1 && ! pChar->name )
541 0 : continue;
542 :
543 562 : if( bFillEncodingvector && pChar->name )
544 : {
545 0 : std::list< sal_Unicode > aCodes = rManager.getUnicodeFromAdobeName( pChar->name );
546 0 : for( std::list< sal_Unicode >::const_iterator it = aCodes.begin(); it != aCodes.end(); ++it )
547 : {
548 0 : if( *it != 0 )
549 : {
550 0 : m_aEncodingVector[ *it ] = pChar->code;
551 0 : if( pChar->code == -1 )
552 0 : m_aNonEncoded[ *it ] = pChar->name;
553 : }
554 0 : }
555 : }
556 :
557 562 : aMetric.width = pChar->wx ? pChar->wx : pChar->charBBox.urx;
558 562 : aMetric.height = pChar->wy ? pChar->wy : pChar->charBBox.ury - pChar->charBBox.lly;
559 562 : if( aMetric.width == 0 && aMetric.height == 0 )
560 : // guess something for e.g. space
561 0 : aMetric.width = m_aGlobalMetricX.width/4;
562 :
563 562 : if( ( nAdobeEncoding == 0 ) ||
564 0 : ( ( nAdobeEncoding == 3 ) && ( m_aEncoding != RTL_TEXTENCODING_SYMBOL ) ) )
565 : {
566 0 : if( pChar->code != -1 )
567 : {
568 0 : m_pMetrics->m_aMetrics[ pUnicodes[i] ] = aMetric;
569 0 : if( bFillEncodingvector )
570 : {
571 0 : m_aEncodingVector[ pUnicodes[i] ] = pChar->code;
572 0 : m_aEncodingVectorPriority.insert(pUnicodes[i]);
573 : }
574 : }
575 0 : else if( pChar->name )
576 : {
577 0 : std::list< sal_Unicode > aCodes = rManager.getUnicodeFromAdobeName( pChar->name );
578 0 : for( std::list< sal_Unicode >::const_iterator it = aCodes.begin(); it != aCodes.end(); ++it )
579 : {
580 0 : if( *it != 0 )
581 0 : m_pMetrics->m_aMetrics[ *it ] = aMetric;
582 0 : }
583 0 : }
584 : }
585 562 : else if( nAdobeEncoding == 1 || nAdobeEncoding == 2 || nAdobeEncoding == 4)
586 : {
587 562 : if( pChar->name )
588 : {
589 562 : std::list< sal_Unicode > aCodes = rManager.getUnicodeFromAdobeName( pChar->name );
590 1135 : for( std::list< sal_Unicode >::const_iterator it = aCodes.begin(); it != aCodes.end(); ++it )
591 : {
592 573 : if( *it != 0 )
593 573 : m_pMetrics->m_aMetrics[ *it ] = aMetric;
594 562 : }
595 : }
596 0 : else if( pChar->code != -1 )
597 : {
598 : ::std::pair< std::unordered_multimap< sal_uInt8, sal_Unicode >::const_iterator,
599 : std::unordered_multimap< sal_uInt8, sal_Unicode >::const_iterator >
600 0 : aCodes = rManager.getUnicodeFromAdobeCode( pChar->code );
601 0 : bool bFirst = true;
602 0 : while( aCodes.first != aCodes.second )
603 : {
604 0 : if( (*aCodes.first).second != 0 )
605 : {
606 0 : m_pMetrics->m_aMetrics[ (*aCodes.first).second ] = aMetric;
607 0 : if( bFillEncodingvector )
608 : {
609 0 : m_aEncodingVector[ (*aCodes.first).second ] = pChar->code;
610 0 : if (bFirst) // arbitrarily prefer the first one
611 : {
612 0 : m_aEncodingVectorPriority.insert((*aCodes.first).second);
613 0 : bFirst = false;
614 : }
615 : }
616 : }
617 0 : ++aCodes.first;
618 : }
619 562 : }
620 : }
621 0 : else if( nAdobeEncoding == 3 )
622 : {
623 0 : if( pChar->code != -1 )
624 : {
625 0 : sal_Unicode code = 0xf000 + pChar->code;
626 0 : m_pMetrics->m_aMetrics[ code ] = aMetric;
627 : // maybe should try to find the name in the convtabs ?
628 0 : if( bFillEncodingvector )
629 : {
630 0 : m_aEncodingVector[ code ] = pChar->code;
631 0 : m_aEncodingVectorPriority.insert(code);
632 : }
633 : }
634 : }
635 : }
636 : }
637 :
638 3655 : freeFontInfo( pInfo );
639 7310 : return true;
640 : }
641 :
642 : /*
643 : * one instance only
644 : */
645 108183 : PrintFontManager& PrintFontManager::get()
646 : {
647 : static PrintFontManager* pManager = NULL;
648 108183 : if( ! pManager )
649 : {
650 205 : static PrintFontManager theManager;
651 205 : pManager = &theManager;
652 205 : pManager->initialize();
653 : }
654 108183 : return *pManager;
655 : }
656 :
657 : /*
658 : * the PrintFontManager
659 : */
660 :
661 205 : PrintFontManager::PrintFontManager()
662 : : m_nNextFontID( 1 )
663 0 : , m_pAtoms( new MultiAtomProvider() )
664 : , m_nNextDirAtom( 1 )
665 205 : , m_pFontCache( NULL )
666 : {
667 215660 : for( unsigned int i = 0; i < SAL_N_ELEMENTS( aAdobeCodes ); i++ )
668 : {
669 215455 : m_aUnicodeToAdobename.insert( std::unordered_multimap< sal_Unicode, OString >::value_type( aAdobeCodes[i].aUnicode, aAdobeCodes[i].pAdobename ) );
670 215455 : m_aAdobenameToUnicode.insert( std::unordered_multimap< OString, sal_Unicode, OStringHash >::value_type( aAdobeCodes[i].pAdobename, aAdobeCodes[i].aUnicode ) );
671 215455 : if( aAdobeCodes[i].aAdobeStandardCode )
672 : {
673 30955 : m_aUnicodeToAdobecode.insert( std::unordered_multimap< sal_Unicode, sal_uInt8 >::value_type( aAdobeCodes[i].aUnicode, aAdobeCodes[i].aAdobeStandardCode ) );
674 30955 : m_aAdobecodeToUnicode.insert( std::unordered_multimap< sal_uInt8, sal_Unicode >::value_type( aAdobeCodes[i].aAdobeStandardCode, aAdobeCodes[i].aUnicode ) );
675 : }
676 : }
677 :
678 : #if defined(ENABLE_DBUS) && defined(ENABLE_PACKAGEKIT)
679 : m_aFontInstallerTimer.SetTimeoutHdl(LINK(this, PrintFontManager, autoInstallFontLangSupport));
680 : m_aFontInstallerTimer.SetTimeout(5000);
681 : #endif
682 205 : }
683 :
684 410 : PrintFontManager::~PrintFontManager()
685 : {
686 205 : m_aFontInstallerTimer.Stop();
687 205 : deinitFontconfig();
688 48380 : for( std::unordered_map< fontID, PrintFont* >::const_iterator it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
689 48175 : delete (*it).second;
690 205 : delete m_pAtoms;
691 205 : delete m_pFontCache;
692 205 : }
693 :
694 18824 : OString PrintFontManager::getDirectory( int nAtom ) const
695 : {
696 18824 : std::unordered_map< int, OString >::const_iterator it( m_aAtomToDir.find( nAtom ) );
697 18824 : return it != m_aAtomToDir.end() ? it->second : OString();
698 : }
699 :
700 62499 : int PrintFontManager::getDirectoryAtom( const OString& rDirectory, bool bCreate )
701 : {
702 62499 : int nAtom = 0;
703 : std::unordered_map< OString, int, OStringHash >::const_iterator it
704 62499 : ( m_aDirToAtom.find( rDirectory ) );
705 62499 : if( it != m_aDirToAtom.end() )
706 59629 : nAtom = it->second;
707 2870 : else if( bCreate )
708 : {
709 2870 : nAtom = m_nNextDirAtom++;
710 2870 : m_aDirToAtom[ rDirectory ] = nAtom;
711 2870 : m_aAtomToDir[ nAtom ] = rDirectory;
712 : }
713 62499 : return nAtom;
714 : }
715 :
716 0 : std::vector<fontID> PrintFontManager::addFontFile( const OString& rFileName )
717 : {
718 0 : rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
719 0 : INetURLObject aPath( OStringToOUString( rFileName, aEncoding ), INetURLObject::FSYS_DETECT );
720 0 : OString aName( OUStringToOString( aPath.GetName( INetURLObject::DECODE_WITH_CHARSET, aEncoding ), aEncoding ) );
721 : OString aDir( OUStringToOString(
722 0 : INetURLObject::decode( aPath.GetPath(), INetURLObject::DECODE_WITH_CHARSET, aEncoding ), aEncoding ) );
723 :
724 0 : int nDirID = getDirectoryAtom( aDir, true );
725 0 : std::vector<fontID> aFontIds = findFontFileIDs( nDirID, aName );
726 0 : if( aFontIds.empty() )
727 : {
728 0 : ::std::list< PrintFont* > aNewFonts;
729 0 : if( analyzeFontFile( nDirID, aName, aNewFonts ) )
730 : {
731 0 : for( ::std::list< PrintFont* >::iterator it = aNewFonts.begin();
732 0 : it != aNewFonts.end(); ++it )
733 : {
734 0 : fontID nFontId = m_nNextFontID++;
735 0 : m_aFonts[nFontId] = *it;
736 0 : m_aFontFileToFontID[ aName ].insert( nFontId );
737 0 : m_pFontCache->updateFontCacheEntry( *it, true );
738 0 : aFontIds.push_back(nFontId);
739 : }
740 0 : }
741 : }
742 0 : return aFontIds;
743 : }
744 :
745 : enum fontFormat
746 : {
747 : UNKNOWN, TRUETYPE, CFF, TYPE1
748 : };
749 :
750 13777 : bool PrintFontManager::analyzeFontFile( int nDirID, const OString& rFontFile, ::std::list< PrintFontManager::PrintFont* >& rNewFonts, const char *pFormat ) const
751 : {
752 13777 : rNewFonts.clear();
753 :
754 13777 : OString aDir( getDirectory( nDirID ) );
755 :
756 27554 : OString aFullPath( aDir );
757 13777 : aFullPath += "/";
758 13777 : aFullPath += rFontFile;
759 :
760 : // #i1872# reject unreadable files
761 13777 : if( access( aFullPath.getStr(), R_OK ) )
762 0 : return false;
763 :
764 13777 : fontFormat eFormat = UNKNOWN;
765 13777 : if (pFormat)
766 : {
767 13777 : if (!strcmp(pFormat, "TrueType"))
768 9860 : eFormat = TRUETYPE;
769 3917 : else if (!strcmp(pFormat, "CFF"))
770 58 : eFormat = CFF;
771 3859 : else if (!strcmp(pFormat, "Type 1"))
772 3859 : eFormat = TYPE1;
773 : }
774 13777 : if (eFormat == UNKNOWN)
775 : {
776 0 : OString aExt( rFontFile.copy( rFontFile.lastIndexOf( '.' )+1 ) );
777 0 : if( aExt.equalsIgnoreAsciiCase("pfb") || aExt.equalsIgnoreAsciiCase("pfa") )
778 0 : eFormat = TYPE1;
779 0 : else if( aExt.equalsIgnoreAsciiCase("ttf")
780 0 : || aExt.equalsIgnoreAsciiCase("ttc")
781 0 : || aExt.equalsIgnoreAsciiCase("tte") ) // #i33947# for Gaiji support
782 0 : eFormat = TRUETYPE;
783 0 : else if( aExt.equalsIgnoreAsciiCase("otf") ) // check for TTF- and PS-OpenType too
784 0 : eFormat = CFF;
785 : }
786 :
787 13777 : if (eFormat == TYPE1)
788 : {
789 : // check for corresponding afm metric
790 : // first look for an adjacent file
791 : static const char* pSuffix[] = { ".afm", ".AFM" };
792 :
793 4269 : for( unsigned int i = 0; i < SAL_N_ELEMENTS(pSuffix); i++ )
794 : {
795 : OString aName = OStringBuffer(
796 4064 : rFontFile.copy(0, rFontFile.getLength() - 4)).
797 8128 : append(pSuffix[i]).makeStringAndClear();
798 :
799 4474 : OStringBuffer aFilePath(aDir);
800 4064 : aFilePath.append('/').append(aName);
801 :
802 4474 : OString aAfmFile;
803 4064 : if( access( aFilePath.makeStringAndClear().getStr(), R_OK ) )
804 : {
805 : // try in subdirectory afm instead
806 410 : aFilePath.append(aDir).append("/afm/").append(aName);
807 :
808 410 : if (!access(aFilePath.getStr(), R_OK))
809 0 : aAfmFile = OString("afm/") + aName;
810 : }
811 : else
812 3654 : aAfmFile = aName;
813 :
814 4064 : if( !aAfmFile.isEmpty() )
815 : {
816 3654 : Type1FontFile* pFont = new Type1FontFile();
817 3654 : pFont->m_nDirectory = nDirID;
818 :
819 3654 : pFont->m_aFontFile = rFontFile;
820 3654 : pFont->m_aMetricFile = aAfmFile;
821 :
822 3654 : if( ! pFont->readAfmMetrics( m_pAtoms, false, true ) )
823 : {
824 0 : delete pFont;
825 0 : pFont = NULL;
826 : }
827 3654 : if( pFont )
828 3654 : rNewFonts.push_back( pFont );
829 3654 : break;
830 : }
831 410 : }
832 : }
833 9918 : else if (eFormat == TRUETYPE || eFormat == CFF)
834 : {
835 : // get number of ttc entries
836 9918 : int nLength = CountTTCFonts( aFullPath.getStr() );
837 9918 : if (nLength > 0)
838 : {
839 : #if OSL_DEBUG_LEVEL > 1
840 : fprintf( stderr, "ttc: %s contains %d fonts\n", aFullPath.getStr(), nLength );
841 : #endif
842 :
843 58 : sal_uInt64 fileSize = 0;
844 :
845 58 : OUString aURL;
846 174 : if (osl::File::getFileURLFromSystemPath(OStringToOUString(aFullPath, osl_getThreadTextEncoding()),
847 116 : aURL) == osl::File::E_None)
848 : {
849 58 : osl::File aFile(aURL);
850 58 : if (aFile.open(osl_File_OpenFlag_Read | osl_File_OpenFlag_NoLock) == osl::File::E_None)
851 : {
852 58 : osl::DirectoryItem aItem;
853 58 : osl::DirectoryItem::get( aURL, aItem );
854 116 : osl::FileStatus aFileStatus( osl_FileStatus_Mask_FileSize );
855 58 : aItem.getFileStatus( aFileStatus );
856 116 : fileSize = aFileStatus.getFileSize();
857 58 : }
858 : }
859 :
860 : //Feel free to calc the exact max possible number of fonts a file
861 : //could contain given its physical size. But this will clamp it to
862 : //a sane starting point
863 : //http://processingjs.nihongoresources.com/the_smallest_font/
864 : //https://github.com/grzegorzrolek/null-ttf
865 58 : const int nMaxFontsPossible = fileSize / 528;
866 58 : if (nLength > nMaxFontsPossible)
867 0 : nLength = nMaxFontsPossible;
868 :
869 174 : for( int i = 0; i < nLength; i++ )
870 : {
871 116 : TrueTypeFontFile* pFont = new TrueTypeFontFile();
872 116 : pFont->m_nDirectory = nDirID;
873 116 : pFont->m_aFontFile = rFontFile;
874 116 : pFont->m_nCollectionEntry = i;
875 116 : if( ! analyzeTrueTypeFile( pFont ) )
876 : {
877 0 : delete pFont;
878 0 : pFont = NULL;
879 : }
880 : else
881 116 : rNewFonts.push_back( pFont );
882 58 : }
883 : }
884 : else
885 : {
886 9860 : TrueTypeFontFile* pFont = new TrueTypeFontFile();
887 9860 : pFont->m_nDirectory = nDirID;
888 9860 : pFont->m_aFontFile = rFontFile;
889 9860 : pFont->m_nCollectionEntry = 0;
890 :
891 : // need to read the font anyway to get aliases inside the font file
892 9860 : if( ! analyzeTrueTypeFile( pFont ) )
893 : {
894 0 : delete pFont;
895 0 : pFont = NULL;
896 : }
897 : else
898 9860 : rNewFonts.push_back( pFont );
899 : }
900 : }
901 27554 : return ! rNewFonts.empty();
902 : }
903 :
904 11330 : fontID PrintFontManager::findFontFileID( int nDirID, const OString& rFontFile, int nFaceIndex ) const
905 : {
906 11330 : fontID nID = 0;
907 :
908 11330 : std::unordered_map< OString, ::std::set< fontID >, OStringHash >::const_iterator set_it = m_aFontFileToFontID.find( rFontFile );
909 11330 : if( set_it == m_aFontFileToFontID.end() )
910 0 : return nID;
911 :
912 22660 : for( ::std::set< fontID >::const_iterator font_it = set_it->second.begin(); font_it != set_it->second.end() && ! nID; ++font_it )
913 : {
914 11330 : std::unordered_map< fontID, PrintFont* >::const_iterator it = m_aFonts.find( *font_it );
915 11330 : if( it == m_aFonts.end() )
916 0 : continue;
917 11330 : switch( it->second->m_eType )
918 : {
919 : case fonttype::Type1:
920 : {
921 226 : Type1FontFile* const pFont = static_cast< Type1FontFile* const >((*it).second);
922 452 : if( pFont->m_nDirectory == nDirID &&
923 226 : pFont->m_aFontFile == rFontFile )
924 226 : nID = it->first;
925 : }
926 226 : break;
927 : case fonttype::TrueType:
928 : {
929 11104 : TrueTypeFontFile* const pFont = static_cast< TrueTypeFontFile* const >((*it).second);
930 33312 : if( pFont->m_nDirectory == nDirID &&
931 22208 : pFont->m_aFontFile == rFontFile && pFont->m_nCollectionEntry == nFaceIndex )
932 11104 : nID = it->first;
933 : }
934 11104 : break;
935 : default:
936 0 : break;
937 : }
938 : }
939 :
940 11330 : return nID;
941 : }
942 :
943 0 : std::vector<fontID> PrintFontManager::findFontFileIDs( int nDirID, const OString& rFontFile ) const
944 : {
945 0 : std::vector<fontID> aIds;
946 :
947 0 : std::unordered_map< OString, ::std::set< fontID >, OStringHash >::const_iterator set_it = m_aFontFileToFontID.find( rFontFile );
948 0 : if( set_it == m_aFontFileToFontID.end() )
949 0 : return aIds;
950 :
951 0 : for( ::std::set< fontID >::const_iterator font_it = set_it->second.begin(); font_it != set_it->second.end(); ++font_it )
952 : {
953 0 : std::unordered_map< fontID, PrintFont* >::const_iterator it = m_aFonts.find( *font_it );
954 0 : if( it == m_aFonts.end() )
955 0 : continue;
956 0 : switch( it->second->m_eType )
957 : {
958 : case fonttype::Type1:
959 : {
960 0 : Type1FontFile* const pFont = static_cast< Type1FontFile* const >((*it).second);
961 0 : if( pFont->m_nDirectory == nDirID &&
962 0 : pFont->m_aFontFile == rFontFile )
963 0 : aIds.push_back(it->first);
964 : }
965 0 : break;
966 : case fonttype::TrueType:
967 : {
968 0 : TrueTypeFontFile* const pFont = static_cast< TrueTypeFontFile* const >((*it).second);
969 0 : if( pFont->m_nDirectory == nDirID &&
970 0 : pFont->m_aFontFile == rFontFile )
971 0 : aIds.push_back(it->first);
972 : }
973 0 : break;
974 : default:
975 0 : break;
976 : }
977 : }
978 :
979 0 : return aIds;
980 : }
981 :
982 22576 : OUString PrintFontManager::convertTrueTypeName( void* pRecord )
983 : {
984 22576 : NameRecord* pNameRecord = static_cast<NameRecord*>(pRecord);
985 22576 : OUString aValue;
986 22576 : if(
987 33516 : ( pNameRecord->platformID == 3 && ( pNameRecord->encodingID == 0 || pNameRecord->encodingID == 1 ) ) // MS, Unicode
988 11636 : ||
989 11636 : ( pNameRecord->platformID == 0 ) // Apple, Unicode
990 : )
991 : {
992 12332 : OUStringBuffer aName( pNameRecord->slen/2 );
993 12332 : const sal_uInt8* pNameBuffer = pNameRecord->sptr;
994 201870 : for(int n = 0; n < pNameRecord->slen/2; n++ )
995 189538 : aName.append( (sal_Unicode)getUInt16BE( pNameBuffer ) );
996 12332 : aValue = aName.makeStringAndClear();
997 : }
998 10244 : else if( pNameRecord->platformID == 3 )
999 : {
1000 0 : if( pNameRecord->encodingID >= 2 && pNameRecord->encodingID <= 6 )
1001 : {
1002 : /*
1003 : * and now for a special kind of madness:
1004 : * some fonts encode their byte value string as BE uint16
1005 : * (leading to stray zero bytes in the string)
1006 : * while others code two bytes as a uint16 and swap to BE
1007 : */
1008 0 : OStringBuffer aName;
1009 0 : const sal_uInt8* pNameBuffer = pNameRecord->sptr;
1010 0 : for(int n = 0; n < pNameRecord->slen/2; n++ )
1011 : {
1012 0 : sal_Unicode aCode = (sal_Unicode)getUInt16BE( pNameBuffer );
1013 0 : sal_Char aChar = aCode >> 8;
1014 0 : if( aChar )
1015 0 : aName.append( aChar );
1016 0 : aChar = aCode & 0x00ff;
1017 0 : if( aChar )
1018 0 : aName.append( aChar );
1019 : }
1020 0 : switch( pNameRecord->encodingID )
1021 : {
1022 : case 2:
1023 0 : aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_932 );
1024 0 : break;
1025 : case 3:
1026 0 : aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_936 );
1027 0 : break;
1028 : case 4:
1029 0 : aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_950 );
1030 0 : break;
1031 : case 5:
1032 0 : aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_949 );
1033 0 : break;
1034 : case 6:
1035 0 : aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_1361 );
1036 0 : break;
1037 0 : }
1038 : }
1039 : }
1040 10244 : else if( pNameRecord->platformID == 1 )
1041 : {
1042 10244 : OString aName(reinterpret_cast<char*>(pNameRecord->sptr), pNameRecord->slen);
1043 10244 : rtl_TextEncoding eEncoding = RTL_TEXTENCODING_DONTKNOW;
1044 10244 : switch (pNameRecord->encodingID)
1045 : {
1046 : case 0:
1047 10244 : eEncoding = RTL_TEXTENCODING_APPLE_ROMAN;
1048 10244 : break;
1049 : case 1:
1050 0 : eEncoding = RTL_TEXTENCODING_APPLE_JAPANESE;
1051 0 : break;
1052 : case 2:
1053 0 : eEncoding = RTL_TEXTENCODING_APPLE_CHINTRAD;
1054 0 : break;
1055 : case 3:
1056 0 : eEncoding = RTL_TEXTENCODING_APPLE_KOREAN;
1057 0 : break;
1058 : case 4:
1059 0 : eEncoding = RTL_TEXTENCODING_APPLE_ARABIC;
1060 0 : break;
1061 : case 5:
1062 0 : eEncoding = RTL_TEXTENCODING_APPLE_HEBREW;
1063 0 : break;
1064 : case 6:
1065 0 : eEncoding = RTL_TEXTENCODING_APPLE_GREEK;
1066 0 : break;
1067 : case 7:
1068 0 : eEncoding = RTL_TEXTENCODING_APPLE_CYRILLIC;
1069 0 : break;
1070 : case 9:
1071 0 : eEncoding = RTL_TEXTENCODING_APPLE_DEVANAGARI;
1072 0 : break;
1073 : case 10:
1074 0 : eEncoding = RTL_TEXTENCODING_APPLE_GURMUKHI;
1075 0 : break;
1076 : case 11:
1077 0 : eEncoding = RTL_TEXTENCODING_APPLE_GUJARATI;
1078 0 : break;
1079 : case 21:
1080 0 : eEncoding = RTL_TEXTENCODING_APPLE_THAI;
1081 0 : break;
1082 : case 25:
1083 0 : eEncoding = RTL_TEXTENCODING_APPLE_CHINSIMP;
1084 0 : break;
1085 : case 29:
1086 0 : eEncoding = RTL_TEXTENCODING_APPLE_CENTEURO;
1087 0 : break;
1088 : case 32: //Uninterpreted
1089 0 : eEncoding = RTL_TEXTENCODING_UTF8;
1090 0 : break;
1091 : default:
1092 : SAL_WARN("vcl", "Unimplmented mac encoding " << pNameRecord->encodingID << " to unicode conversion");
1093 0 : break;
1094 : }
1095 10244 : if (eEncoding != RTL_TEXTENCODING_DONTKNOW)
1096 10244 : aValue = OStringToOUString(aName, eEncoding);
1097 : }
1098 :
1099 22576 : return aValue;
1100 : }
1101 :
1102 : //fdo#33349.There exists an archaic Berling Antiqua font which has a "Times New
1103 : //Roman" name field in it. We don't want the "Times New Roman" name to take
1104 : //precedence in this case. We take Berling Antiqua as a higher priority name,
1105 : //and erase the "Times New Roman" name
1106 : namespace
1107 : {
1108 2204 : bool isBadTNR(const OUString &rName, ::std::set< OUString >& rSet)
1109 : {
1110 2204 : bool bRet = false;
1111 2204 : if ( rName == "Berling Antiqua" )
1112 : {
1113 0 : ::std::set< OUString >::iterator aEnd = rSet.end();
1114 0 : ::std::set< OUString >::iterator aI = rSet.find("Times New Roman");
1115 0 : if (aI != aEnd)
1116 : {
1117 0 : bRet = true;
1118 0 : rSet.erase(aI);
1119 : }
1120 : }
1121 2204 : return bRet;
1122 : }
1123 : }
1124 :
1125 10244 : void PrintFontManager::analyzeTrueTypeFamilyName( void* pTTFont, ::std::list< OUString >& rNames )
1126 : {
1127 10244 : OUString aFamily;
1128 :
1129 10244 : rNames.clear();
1130 20488 : ::std::set< OUString > aSet;
1131 :
1132 10244 : NameRecord* pNameRecords = NULL;
1133 10244 : int nNameRecords = GetTTNameRecords( static_cast<TrueTypeFont*>(pTTFont), &pNameRecords );
1134 10244 : if( nNameRecords && pNameRecords )
1135 : {
1136 10244 : LanguageTag aSystem("");
1137 10244 : LanguageType eLang = aSystem.getLanguageType();
1138 10244 : int nLastMatch = -1;
1139 543932 : for( int i = 0; i < nNameRecords; i++ )
1140 : {
1141 533688 : if( pNameRecords[i].nameID != 1 || pNameRecords[i].sptr == NULL )
1142 1022224 : continue;
1143 22576 : int nMatch = -1;
1144 22576 : if( pNameRecords[i].platformID == 0 ) // Unicode
1145 1392 : nMatch = 4000;
1146 21184 : else if( pNameRecords[i].platformID == 3 )
1147 : {
1148 : // this bases on the LanguageType actually being a Win LCID
1149 10940 : if (pNameRecords[i].languageID == eLang)
1150 10128 : nMatch = 8000;
1151 812 : else if( pNameRecords[i].languageID == LANGUAGE_ENGLISH_US )
1152 0 : nMatch = 2000;
1153 1624 : else if( pNameRecords[i].languageID == LANGUAGE_ENGLISH ||
1154 812 : pNameRecords[i].languageID == LANGUAGE_ENGLISH_UK )
1155 0 : nMatch = 1500;
1156 : else
1157 812 : nMatch = 1000;
1158 : }
1159 10244 : else if (pNameRecords[i].platformID == 1)
1160 : {
1161 10244 : AppleLanguageId aAppleId = static_cast<AppleLanguageId>(pNameRecords[i].languageID);
1162 10244 : LanguageTag aApple(makeLanguageTagFromAppleLanguageId(aAppleId));
1163 10244 : if (aApple == aSystem)
1164 0 : nMatch = 8000;
1165 10244 : else if (aAppleId == AppleLanguageId::ENGLISH)
1166 10244 : nMatch = 2000;
1167 : else
1168 0 : nMatch = 1000;
1169 : }
1170 22576 : OUString aName = convertTrueTypeName( pNameRecords + i );
1171 22576 : aSet.insert( aName );
1172 22576 : if (aName.isEmpty())
1173 0 : continue;
1174 22576 : if( nMatch > nLastMatch || isBadTNR(aName, aSet) )
1175 : {
1176 20372 : nLastMatch = nMatch;
1177 20372 : aFamily = aName;
1178 : }
1179 32820 : }
1180 : }
1181 10244 : DisposeNameRecords( pNameRecords, nNameRecords );
1182 10244 : if( !aFamily.isEmpty() )
1183 : {
1184 10244 : rNames.push_front( aFamily );
1185 20894 : for( ::std::set< OUString >::const_iterator it = aSet.begin(); it != aSet.end(); ++it )
1186 10650 : if( *it != aFamily )
1187 406 : rNames.push_back( *it );
1188 : }
1189 20488 : return;
1190 : }
1191 :
1192 10244 : bool PrintFontManager::analyzeTrueTypeFile( PrintFont* pFont ) const
1193 : {
1194 10244 : bool bSuccess = false;
1195 10244 : rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
1196 10244 : OString aFile = getFontFile( pFont );
1197 10244 : TrueTypeFont* pTTFont = NULL;
1198 :
1199 10244 : TrueTypeFontFile* pTTFontFile = static_cast< TrueTypeFontFile* >(pFont);
1200 10244 : if( OpenTTFontFile( aFile.getStr(), pTTFontFile->m_nCollectionEntry, &pTTFont ) == SF_OK )
1201 : {
1202 : TTGlobalFontInfo aInfo;
1203 10244 : GetTTGlobalFontInfo( pTTFont, & aInfo );
1204 :
1205 10244 : ::std::list< OUString > aNames;
1206 10244 : analyzeTrueTypeFamilyName( pTTFont, aNames );
1207 :
1208 : // set family name from XLFD if possible
1209 10244 : if( ! pFont->m_nFamilyName )
1210 : {
1211 9976 : if( aNames.begin() != aNames.end() )
1212 : {
1213 9976 : pFont->m_nFamilyName = m_pAtoms->getAtom( ATOM_FAMILYNAME, aNames.front(), true );
1214 9976 : aNames.pop_front();
1215 : }
1216 : else
1217 : {
1218 : sal_Int32 dotIndex;
1219 :
1220 : // poor font does not have a family name
1221 : // name it to file name minus the extension
1222 0 : dotIndex = pTTFontFile->m_aFontFile.lastIndexOf( '.' );
1223 0 : if ( dotIndex == -1 )
1224 0 : dotIndex = pTTFontFile->m_aFontFile.getLength();
1225 :
1226 0 : pFont->m_nFamilyName = m_pAtoms->getAtom( ATOM_FAMILYNAME, OStringToOUString( pTTFontFile->m_aFontFile.copy( 0, dotIndex ), aEncoding ), true );
1227 : }
1228 : }
1229 10918 : for( ::std::list< OUString >::iterator it = aNames.begin(); it != aNames.end(); ++it )
1230 : {
1231 674 : if( !it->isEmpty() )
1232 : {
1233 674 : int nAlias = m_pAtoms->getAtom( ATOM_FAMILYNAME, *it, true );
1234 674 : if( nAlias != pFont->m_nFamilyName )
1235 : {
1236 406 : std::list< int >::const_iterator al_it;
1237 406 : for( al_it = pFont->m_aAliases.begin(); al_it != pFont->m_aAliases.end() && *al_it != nAlias; ++al_it )
1238 : ;
1239 406 : if( al_it == pFont->m_aAliases.end() )
1240 406 : pFont->m_aAliases.push_back( nAlias );
1241 : }
1242 : }
1243 : }
1244 :
1245 10244 : if( aInfo.usubfamily )
1246 0 : pFont->m_aStyleName = OUString( aInfo.usubfamily );
1247 :
1248 : SAL_WARN_IF( !aInfo.psname, "vcl", "No PostScript name in font:" << aFile.getStr() );
1249 :
1250 : OUString sPSName = aInfo.psname ?
1251 : OUString(aInfo.psname, rtl_str_getLength(aInfo.psname), aEncoding) :
1252 20488 : m_pAtoms->getString(ATOM_FAMILYNAME, pFont->m_nFamilyName); // poor font does not have a postscript name
1253 :
1254 10244 : pFont->m_nPSName = m_pAtoms->getAtom( ATOM_PSNAME, sPSName, true );
1255 :
1256 10244 : switch( aInfo.weight )
1257 : {
1258 0 : case FW_THIN: pFont->m_eWeight = WEIGHT_THIN; break;
1259 174 : case FW_EXTRALIGHT: pFont->m_eWeight = WEIGHT_ULTRALIGHT; break;
1260 232 : case FW_LIGHT: pFont->m_eWeight = WEIGHT_LIGHT; break;
1261 290 : case FW_MEDIUM: pFont->m_eWeight = WEIGHT_MEDIUM; break;
1262 464 : case FW_SEMIBOLD: pFont->m_eWeight = WEIGHT_SEMIBOLD; break;
1263 3493 : case FW_BOLD: pFont->m_eWeight = WEIGHT_BOLD; break;
1264 0 : case FW_EXTRABOLD: pFont->m_eWeight = WEIGHT_ULTRABOLD; break;
1265 116 : case FW_BLACK: pFont->m_eWeight = WEIGHT_BLACK; break;
1266 :
1267 : case FW_NORMAL:
1268 5475 : default: pFont->m_eWeight = WEIGHT_NORMAL; break;
1269 : }
1270 :
1271 10244 : switch( aInfo.width )
1272 : {
1273 0 : case FWIDTH_ULTRA_CONDENSED: pFont->m_eWidth = WIDTH_ULTRA_CONDENSED; break;
1274 0 : case FWIDTH_EXTRA_CONDENSED: pFont->m_eWidth = WIDTH_EXTRA_CONDENSED; break;
1275 232 : case FWIDTH_CONDENSED: pFont->m_eWidth = WIDTH_CONDENSED; break;
1276 464 : case FWIDTH_SEMI_CONDENSED: pFont->m_eWidth = WIDTH_SEMI_CONDENSED; break;
1277 0 : case FWIDTH_SEMI_EXPANDED: pFont->m_eWidth = WIDTH_SEMI_EXPANDED; break;
1278 0 : case FWIDTH_EXPANDED: pFont->m_eWidth = WIDTH_EXPANDED; break;
1279 0 : case FWIDTH_EXTRA_EXPANDED: pFont->m_eWidth = WIDTH_EXTRA_EXPANDED; break;
1280 0 : case FWIDTH_ULTRA_EXPANDED: pFont->m_eWidth = WIDTH_ULTRA_EXPANDED; break;
1281 :
1282 : case FWIDTH_NORMAL:
1283 9548 : default: pFont->m_eWidth = WIDTH_NORMAL; break;
1284 : }
1285 :
1286 10244 : pFont->m_ePitch = aInfo.pitch ? PITCH_FIXED : PITCH_VARIABLE;
1287 10244 : pFont->m_eItalic = aInfo.italicAngle == 0 ? ITALIC_NONE : ( aInfo.italicAngle < 0 ? ITALIC_NORMAL : ITALIC_OBLIQUE );
1288 : // #104264# there are fonts that set italic angle 0 although they are
1289 : // italic; use macstyle bit here
1290 10244 : if( aInfo.italicAngle == 0 && (aInfo.macStyle & 2) )
1291 348 : pFont->m_eItalic = ITALIC_NORMAL;
1292 :
1293 10244 : pFont->m_aEncoding = aInfo.symbolEncoded ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UCS2;
1294 :
1295 10244 : pFont->m_aGlobalMetricY.width = pFont->m_aGlobalMetricX.width = aInfo.xMax - aInfo.xMin;
1296 10244 : pFont->m_aGlobalMetricY.height = pFont->m_aGlobalMetricX.height = aInfo.yMax - aInfo.yMin;
1297 :
1298 10244 : if( aInfo.winAscent && aInfo.winDescent )
1299 : {
1300 10186 : pFont->m_nAscend = aInfo.winAscent;
1301 10186 : pFont->m_nDescend = aInfo.winDescent;
1302 10186 : pFont->m_nLeading = pFont->m_nAscend + pFont->m_nDescend - 1000;
1303 : }
1304 58 : else if( aInfo.typoAscender && aInfo.typoDescender )
1305 : {
1306 0 : pFont->m_nLeading = aInfo.typoLineGap;
1307 0 : pFont->m_nAscend = aInfo.typoAscender;
1308 0 : pFont->m_nDescend = -aInfo.typoDescender;
1309 : }
1310 : else
1311 : {
1312 58 : pFont->m_nLeading = aInfo.linegap;
1313 58 : pFont->m_nAscend = aInfo.ascender;
1314 58 : pFont->m_nDescend = -aInfo.descender;
1315 : }
1316 :
1317 : // last try: font bounding box
1318 10244 : if( pFont->m_nAscend == 0 )
1319 0 : pFont->m_nAscend = aInfo.yMax;
1320 10244 : if( pFont->m_nDescend == 0 )
1321 58 : pFont->m_nDescend = -aInfo.yMin;
1322 10244 : if( pFont->m_nLeading == 0 )
1323 290 : pFont->m_nLeading = 15 * (pFont->m_nAscend+pFont->m_nDescend) / 100;
1324 :
1325 10244 : if( pFont->m_nAscend )
1326 10244 : pFont->m_aGlobalMetricX.height = pFont->m_aGlobalMetricY.height = pFont->m_nAscend + pFont->m_nDescend;
1327 :
1328 : // get bounding box
1329 10244 : pFont->m_nXMin = aInfo.xMin;
1330 10244 : pFont->m_nYMin = aInfo.yMin;
1331 10244 : pFont->m_nXMax = aInfo.xMax;
1332 10244 : pFont->m_nYMax = aInfo.yMax;
1333 :
1334 : // get type flags
1335 10244 : pTTFontFile->m_nTypeFlags = (unsigned int)aInfo.typeFlags;
1336 :
1337 : // get vertical substitutions flag
1338 10244 : pFont->m_bHaveVerticalSubstitutedGlyphs = DoesVerticalSubstitution( pTTFont, 1 );
1339 :
1340 10244 : CloseTTFont( pTTFont );
1341 20488 : bSuccess = true;
1342 : }
1343 : else
1344 : SAL_WARN("vcl", "Could not OpenTTFont \"" << aFile.getStr() << "\"\n");
1345 :
1346 10244 : return bSuccess;
1347 : }
1348 :
1349 205 : static bool AreFCSubstitutionsEnabled()
1350 : {
1351 205 : return (SalGenericInstance::FetchFontSubstitutionFlags() & 3) == 0;
1352 : }
1353 :
1354 205 : void PrintFontManager::initialize()
1355 : {
1356 : #ifdef CALLGRIND_COMPILE
1357 : CALLGRIND_TOGGLE_COLLECT();
1358 : CALLGRIND_ZERO_STATS();
1359 : #endif
1360 :
1361 205 : if( ! m_pFontCache )
1362 : {
1363 : #if OSL_DEBUG_LEVEL > 1
1364 : fprintf( stderr, "creating font cache ... " );
1365 : clock_t aStart;
1366 : struct tms tms;
1367 : aStart = times( &tms );
1368 : #endif
1369 205 : m_pFontCache = new FontCache();
1370 : #if OSL_DEBUG_LEVEL > 1
1371 : clock_t aStop = times( &tms );
1372 : fprintf( stderr, "done in %lf s\n", (double)(aStop - aStart)/(double)sysconf( _SC_CLK_TCK ) );
1373 : #endif
1374 : }
1375 :
1376 : // initialize can be called more than once, e.g.
1377 : // gtk-fontconfig-timestamp changes to reflect new font installed and
1378 : // PrintFontManager::initialize called again
1379 : {
1380 205 : for( std::unordered_map< fontID, PrintFont* >::const_iterator it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
1381 0 : delete (*it).second;
1382 205 : m_nNextFontID = 1;
1383 205 : m_aFonts.clear();
1384 205 : m_aFontDirectories.clear();
1385 205 : m_aPrivateFontDirectories.clear();
1386 : }
1387 :
1388 : #if OSL_DEBUG_LEVEL > 1
1389 : clock_t aStart;
1390 : clock_t aStep1;
1391 : clock_t aStep2;
1392 :
1393 : struct tms tms;
1394 :
1395 : aStart = times( &tms );
1396 : #endif
1397 :
1398 : // first try fontconfig
1399 205 : initFontconfig();
1400 :
1401 : // part one - look for downloadable fonts
1402 205 : rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
1403 205 : const OUString &rSalPrivatePath = psp::getFontPath();
1404 :
1405 : // search for the fonts in SAL_PRIVATE_FONTPATH first; those are
1406 : // the fonts installed with the office
1407 205 : if( !rSalPrivatePath.isEmpty() )
1408 : {
1409 205 : OString aPath = OUStringToOString( rSalPrivatePath, aEncoding );
1410 205 : const bool bAreFCSubstitutionsEnabled = AreFCSubstitutionsEnabled();
1411 205 : sal_Int32 nIndex = 0;
1412 615 : do
1413 : {
1414 615 : OString aToken = aPath.getToken( 0, ';', nIndex );
1415 615 : normPath( aToken );
1416 615 : if ( aToken.isEmpty() )
1417 : {
1418 0 : continue;
1419 : }
1420 : // if registering an app-specific fontdir with fontconfig fails
1421 : // and fontconfig-based substitutions are enabled
1422 : // then trying to use these app-specific fonts doesn't make sense
1423 615 : if( !addFontconfigDir( aToken ) )
1424 0 : if( bAreFCSubstitutionsEnabled )
1425 0 : continue;
1426 615 : m_aFontDirectories.push_back( aToken );
1427 615 : m_aPrivateFontDirectories.push_back( getDirectoryAtom( aToken, true ) );
1428 820 : } while( nIndex >= 0 );
1429 : }
1430 :
1431 : // protect against duplicate paths
1432 410 : std::unordered_map< OString, int, OStringHash > visited_dirs;
1433 :
1434 : // Don't search directories that fontconfig already did
1435 205 : countFontconfigFonts( visited_dirs );
1436 :
1437 : // search for font files in each path
1438 205 : std::list< OString >::iterator dir_it;
1439 820 : for( dir_it = m_aFontDirectories.begin(); dir_it != m_aFontDirectories.end(); ++dir_it )
1440 : {
1441 615 : OString aPath( *dir_it );
1442 : // see if we were here already
1443 615 : if( visited_dirs.find( aPath ) != visited_dirs.end() )
1444 205 : continue;
1445 410 : visited_dirs[ aPath ] = 1;
1446 :
1447 : // there may be ":unscaled" directories (see XFree86)
1448 : // it should be safe to ignore them since they should not
1449 : // contain any of our recognizeable fonts
1450 :
1451 : // ask the font cache whether it handles this directory
1452 820 : std::list< PrintFont* > aCacheFonts;
1453 410 : if( m_pFontCache->listDirectory( aPath, aCacheFonts ) )
1454 : {
1455 : #if OSL_DEBUG_LEVEL > 1
1456 : fprintf( stderr, "adding cache directory: %s\n", aPath.getStr() );
1457 : #endif
1458 0 : for( ::std::list< PrintFont* >::iterator it = aCacheFonts.begin(); it != aCacheFonts.end(); ++it )
1459 : {
1460 0 : fontID aFont = m_nNextFontID++;
1461 0 : m_aFonts[ aFont ] = *it;
1462 0 : if( (*it)->m_eType == fonttype::Type1 )
1463 0 : m_aFontFileToFontID[ static_cast<Type1FontFile*>(*it)->m_aFontFile ].insert( aFont );
1464 0 : else if( (*it)->m_eType == fonttype::TrueType )
1465 0 : m_aFontFileToFontID[ static_cast<TrueTypeFontFile*>(*it)->m_aFontFile ].insert( aFont );
1466 : #if OSL_DEBUG_LEVEL > 1
1467 : else
1468 : fprintf(stderr, "Un-cached type '%d'\n", (*it)->m_eType);
1469 : #if OSL_DEBUG_LEVEL > 2
1470 : fprintf( stderr, "adding cached font %d: %s\n", aFont, getFontFileSysPath( aFont ).getStr() );
1471 : #endif
1472 : #endif
1473 : }
1474 0 : if( ! m_pFontCache->scanAdditionalFiles( aPath ) )
1475 0 : continue;
1476 : }
1477 :
1478 410 : }
1479 :
1480 : #if OSL_DEBUG_LEVEL > 1
1481 : aStep1 = times( &tms );
1482 : #endif
1483 :
1484 : // part three - fill in family styles
1485 205 : std::unordered_map< fontID, PrintFont* >::iterator font_it;
1486 48380 : for (font_it = m_aFonts.begin(); font_it != m_aFonts.end(); ++font_it)
1487 : {
1488 : std::unordered_map< int, FontFamily >::const_iterator it =
1489 48175 : m_aFamilyTypes.find( font_it->second->m_nFamilyName );
1490 48175 : if (it != m_aFamilyTypes.end())
1491 30545 : continue;
1492 : const OUString& rFamily =
1493 17630 : m_pAtoms->getString( ATOM_FAMILYNAME, font_it->second->m_nFamilyName);
1494 17630 : FontFamily eType = matchFamilyName( rFamily );
1495 17630 : m_aFamilyTypes[ font_it->second->m_nFamilyName ] = eType;
1496 : }
1497 :
1498 : #if OSL_DEBUG_LEVEL > 1
1499 : aStep2 = times( &tms );
1500 : fprintf( stderr, "PrintFontManager::initialize: collected %" SAL_PRI_SIZET "u fonts\n", m_aFonts.size() );
1501 : double fTick = (double)sysconf( _SC_CLK_TCK );
1502 : fprintf( stderr, "Step 1 took %lf seconds\n", (double)(aStep1 - aStart)/fTick );
1503 : fprintf( stderr, "Step 2 took %lf seconds\n", (double)(aStep2 - aStep1)/fTick );
1504 : #endif
1505 :
1506 410 : m_pFontCache->flush();
1507 :
1508 : #ifdef CALLGRIND_COMPILE
1509 : CALLGRIND_DUMP_STATS();
1510 : CALLGRIND_TOGGLE_COLLECT();
1511 : #endif
1512 205 : }
1513 :
1514 859 : void PrintFontManager::getFontList( ::std::list< fontID >& rFontIDs )
1515 : {
1516 859 : rFontIDs.clear();
1517 859 : std::unordered_map< fontID, PrintFont* >::const_iterator it;
1518 :
1519 202724 : for( it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
1520 201865 : rFontIDs.push_back( it->first );
1521 859 : }
1522 :
1523 213466 : void PrintFontManager::fillPrintFontInfo( PrintFont* pFont, FastPrintFontInfo& rInfo ) const
1524 : {
1525 : std::unordered_map< int, FontFamily >::const_iterator style_it =
1526 213466 : m_aFamilyTypes.find( pFont->m_nFamilyName );
1527 213466 : rInfo.m_eType = pFont->m_eType;
1528 213466 : rInfo.m_aFamilyName = m_pAtoms->getString( ATOM_FAMILYNAME, pFont->m_nFamilyName );
1529 213466 : rInfo.m_aStyleName = pFont->m_aStyleName;
1530 213466 : rInfo.m_eFamilyStyle = style_it != m_aFamilyTypes.end() ? style_it->second : FAMILY_DONTKNOW;
1531 213466 : rInfo.m_eItalic = pFont->m_eItalic;
1532 213466 : rInfo.m_eWidth = pFont->m_eWidth;
1533 213466 : rInfo.m_eWeight = pFont->m_eWeight;
1534 213466 : rInfo.m_ePitch = pFont->m_ePitch;
1535 213466 : rInfo.m_aEncoding = pFont->m_aEncoding;
1536 :
1537 213466 : rInfo.m_bEmbeddable = (pFont->m_eType == fonttype::Type1);
1538 213466 : rInfo.m_bSubsettable = (pFont->m_eType == fonttype::TrueType); // TODO: rename to SfntType
1539 :
1540 213466 : rInfo.m_aAliases.clear();
1541 223626 : for( ::std::list< int >::iterator it = pFont->m_aAliases.begin(); it != pFont->m_aAliases.end(); ++it )
1542 10160 : rInfo.m_aAliases.push_back( m_pAtoms->getString( ATOM_FAMILYNAME, *it ) );
1543 213466 : }
1544 :
1545 271 : void PrintFontManager::fillPrintFontInfo( PrintFont* pFont, PrintFontInfo& rInfo ) const
1546 : {
1547 813 : if( ( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 ) ||
1548 544 : ! pFont->m_pMetrics || pFont->m_pMetrics->isEmpty()
1549 : )
1550 : {
1551 : // might be a truetype font not analyzed or type1 without metrics read
1552 269 : if( pFont->m_eType == fonttype::Type1 )
1553 1 : pFont->readAfmMetrics( m_pAtoms, false, false );
1554 268 : else if( pFont->m_eType == fonttype::TrueType )
1555 268 : analyzeTrueTypeFile( pFont );
1556 : }
1557 :
1558 271 : fillPrintFontInfo( pFont, static_cast< FastPrintFontInfo& >( rInfo ) );
1559 :
1560 271 : rInfo.m_nAscend = pFont->m_nAscend;
1561 271 : rInfo.m_nDescend = pFont->m_nDescend;
1562 271 : rInfo.m_nLeading = pFont->m_nLeading;
1563 271 : rInfo.m_nWidth = pFont->m_aGlobalMetricX.width < pFont->m_aGlobalMetricY.width ? pFont->m_aGlobalMetricY.width : pFont->m_aGlobalMetricX.width;
1564 271 : }
1565 :
1566 271 : bool PrintFontManager::getFontInfo( fontID nFontID, PrintFontInfo& rInfo ) const
1567 : {
1568 271 : PrintFont* pFont = getFont( nFontID );
1569 271 : if( pFont )
1570 : {
1571 271 : rInfo.m_nID = nFontID;
1572 271 : fillPrintFontInfo( pFont, rInfo );
1573 : }
1574 271 : return pFont != nullptr;
1575 : }
1576 :
1577 213195 : bool PrintFontManager::getFontFastInfo( fontID nFontID, FastPrintFontInfo& rInfo ) const
1578 : {
1579 213195 : PrintFont* pFont = getFont( nFontID );
1580 213195 : if( pFont )
1581 : {
1582 213195 : rInfo.m_nID = nFontID;
1583 213195 : fillPrintFontInfo( pFont, rInfo );
1584 : }
1585 213195 : return pFont != nullptr;
1586 : }
1587 :
1588 0 : bool PrintFontManager::getFontBoundingBox( fontID nFontID, int& xMin, int& yMin, int& xMax, int& yMax )
1589 : {
1590 0 : bool bSuccess = false;
1591 0 : PrintFont* pFont = getFont( nFontID );
1592 0 : if( pFont )
1593 : {
1594 0 : if( pFont->m_nXMin == 0 && pFont->m_nYMin == 0 && pFont->m_nXMax == 0 && pFont->m_nYMax == 0 )
1595 : {
1596 : // might be a truetype font not analyzed or type1 without metrics read
1597 0 : if( pFont->m_eType == fonttype::Type1 )
1598 0 : pFont->readAfmMetrics( m_pAtoms, false, true );
1599 0 : else if( pFont->m_eType == fonttype::TrueType )
1600 0 : analyzeTrueTypeFile( pFont );
1601 : }
1602 0 : bSuccess = true;
1603 0 : xMin = pFont->m_nXMin;
1604 0 : yMin = pFont->m_nYMin;
1605 0 : xMax = pFont->m_nXMax;
1606 0 : yMax = pFont->m_nYMax;
1607 : }
1608 0 : return bSuccess;
1609 : }
1610 :
1611 85540 : int PrintFontManager::getFontFaceNumber( fontID nFontID ) const
1612 : {
1613 85540 : int nRet = 0;
1614 85540 : PrintFont* pFont = getFont( nFontID );
1615 85540 : if( pFont && pFont->m_eType == fonttype::TrueType )
1616 62608 : nRet = static_cast< TrueTypeFontFile* >(pFont)->m_nCollectionEntry;
1617 85540 : if (nRet < 0)
1618 0 : nRet = 0;
1619 85540 : return nRet;
1620 : }
1621 :
1622 17630 : FontFamily PrintFontManager::matchFamilyName( const OUString& rFamily )
1623 : {
1624 : typedef struct {
1625 : const char* mpName;
1626 : sal_uInt16 mnLength;
1627 : FontFamily meType;
1628 : } family_t;
1629 :
1630 : #define InitializeClass( p, a ) p, sizeof(p) - 1, a
1631 : const family_t pFamilyMatch[] = {
1632 : { InitializeClass( "arial", FAMILY_SWISS ) },
1633 : { InitializeClass( "arioso", FAMILY_SCRIPT ) },
1634 : { InitializeClass( "avant garde", FAMILY_SWISS ) },
1635 : { InitializeClass( "avantgarde", FAMILY_SWISS ) },
1636 : { InitializeClass( "bembo", FAMILY_ROMAN ) },
1637 : { InitializeClass( "bookman", FAMILY_ROMAN ) },
1638 : { InitializeClass( "conga", FAMILY_ROMAN ) },
1639 : { InitializeClass( "courier", FAMILY_MODERN ) },
1640 : { InitializeClass( "curl", FAMILY_SCRIPT ) },
1641 : { InitializeClass( "fixed", FAMILY_MODERN ) },
1642 : { InitializeClass( "gill", FAMILY_SWISS ) },
1643 : { InitializeClass( "helmet", FAMILY_MODERN ) },
1644 : { InitializeClass( "helvetica", FAMILY_SWISS ) },
1645 : { InitializeClass( "international", FAMILY_MODERN ) },
1646 : { InitializeClass( "lucida", FAMILY_SWISS ) },
1647 : { InitializeClass( "new century schoolbook", FAMILY_ROMAN ) },
1648 : { InitializeClass( "palatino", FAMILY_ROMAN ) },
1649 : { InitializeClass( "roman", FAMILY_ROMAN ) },
1650 : { InitializeClass( "sans serif", FAMILY_SWISS ) },
1651 : { InitializeClass( "sansserif", FAMILY_SWISS ) },
1652 : { InitializeClass( "serf", FAMILY_ROMAN ) },
1653 : { InitializeClass( "serif", FAMILY_ROMAN ) },
1654 : { InitializeClass( "times", FAMILY_ROMAN ) },
1655 : { InitializeClass( "utopia", FAMILY_ROMAN ) },
1656 : { InitializeClass( "zapf chancery", FAMILY_SCRIPT ) },
1657 : { InitializeClass( "zapfchancery", FAMILY_SCRIPT ) }
1658 17630 : };
1659 :
1660 17630 : OString aFamily = OUStringToOString( rFamily, RTL_TEXTENCODING_ASCII_US );
1661 17630 : sal_uInt32 nLower = 0;
1662 17630 : sal_uInt32 nUpper = SAL_N_ELEMENTS(pFamilyMatch);
1663 :
1664 120335 : while( nLower < nUpper )
1665 : {
1666 85485 : sal_uInt32 nCurrent = (nLower + nUpper) / 2;
1667 85485 : const family_t* pHaystack = pFamilyMatch + nCurrent;
1668 : sal_Int32 nComparison =
1669 : rtl_str_compareIgnoreAsciiCase_WithLength
1670 : (
1671 : aFamily.getStr(), aFamily.getLength(),
1672 : pHaystack->mpName, pHaystack->mnLength
1673 85485 : );
1674 :
1675 85485 : if( nComparison < 0 )
1676 50635 : nUpper = nCurrent;
1677 : else
1678 34850 : if( nComparison > 0 )
1679 34440 : nLower = nCurrent + 1;
1680 : else
1681 410 : return pHaystack->meType;
1682 : }
1683 :
1684 17220 : return FAMILY_DONTKNOW;
1685 : }
1686 :
1687 3655 : OString PrintFontManager::getAfmFile( PrintFont* pFont ) const
1688 : {
1689 3655 : OString aMetricPath;
1690 3655 : if( pFont )
1691 : {
1692 3655 : switch( pFont->m_eType )
1693 : {
1694 : case fonttype::Type1:
1695 : {
1696 3655 : Type1FontFile* pPSFont = static_cast< Type1FontFile* >(pFont);
1697 3655 : aMetricPath = getDirectory( pPSFont->m_nDirectory );
1698 3655 : aMetricPath += "/";
1699 3655 : aMetricPath += pPSFont->m_aMetricFile;
1700 : }
1701 3655 : break;
1702 0 : default: break;
1703 : }
1704 : }
1705 3655 : return aMetricPath;
1706 : }
1707 :
1708 180924 : OString PrintFontManager::getFontFile( PrintFont* pFont ) const
1709 : {
1710 180924 : OString aPath;
1711 :
1712 180924 : if( pFont && pFont->m_eType == fonttype::Type1 )
1713 : {
1714 22932 : Type1FontFile* pPSFont = static_cast< Type1FontFile* >(pFont);
1715 22932 : std::unordered_map< int, OString >::const_iterator it = m_aAtomToDir.find( pPSFont->m_nDirectory );
1716 22932 : aPath = it->second;
1717 22932 : aPath += "/";
1718 22932 : aPath += pPSFont->m_aFontFile;
1719 : }
1720 157992 : else if( pFont && pFont->m_eType == fonttype::TrueType )
1721 : {
1722 157992 : TrueTypeFontFile* pTTFont = static_cast< TrueTypeFontFile* >(pFont);
1723 157992 : std::unordered_map< int, OString >::const_iterator it = m_aAtomToDir.find( pTTFont->m_nDirectory );
1724 157992 : aPath = it->second;
1725 157992 : aPath += "/";
1726 157992 : aPath += pTTFont->m_aFontFile;
1727 : }
1728 180924 : return aPath;
1729 : }
1730 :
1731 0 : const OUString& PrintFontManager::getPSName( fontID nFontID ) const
1732 : {
1733 0 : PrintFont* pFont = getFont( nFontID );
1734 0 : if( pFont && pFont->m_nPSName == 0 )
1735 : {
1736 0 : if( pFont->m_eType == fonttype::TrueType )
1737 0 : analyzeTrueTypeFile( pFont );
1738 : }
1739 :
1740 0 : return m_pAtoms->getString( ATOM_PSNAME, pFont ? pFont->m_nPSName : INVALID_ATOM );
1741 : }
1742 :
1743 0 : int PrintFontManager::getFontAscend( fontID nFontID ) const
1744 : {
1745 0 : PrintFont* pFont = getFont( nFontID );
1746 0 : if (pFont && pFont->m_nAscend == 0 && pFont->m_nDescend == 0)
1747 : {
1748 : // might be a truetype font not yet analyzed
1749 0 : if( pFont->m_eType == fonttype::TrueType )
1750 0 : analyzeTrueTypeFile( pFont );
1751 0 : else if( pFont->m_eType == fonttype::Type1 )
1752 0 : pFont->readAfmMetrics( m_pAtoms, false, true );
1753 : }
1754 0 : return pFont ? pFont->m_nAscend : 0;
1755 : }
1756 :
1757 0 : int PrintFontManager::getFontDescend( fontID nFontID ) const
1758 : {
1759 0 : PrintFont* pFont = getFont( nFontID );
1760 0 : if (pFont && pFont->m_nAscend == 0 && pFont->m_nDescend == 0)
1761 : {
1762 : // might be a truetype font not yet analyzed
1763 0 : if( pFont->m_eType == fonttype::TrueType )
1764 0 : analyzeTrueTypeFile( pFont );
1765 0 : else if( pFont->m_eType == fonttype::Type1 )
1766 0 : pFont->readAfmMetrics( m_pAtoms, false, true );
1767 : }
1768 0 : return pFont ? pFont->m_nDescend : 0;
1769 : }
1770 :
1771 0 : void PrintFontManager::hasVerticalSubstitutions( fontID nFontID,
1772 : const sal_Unicode* pCharacters, int nCharacters, bool* pHasSubst ) const
1773 : {
1774 0 : PrintFont* pFont = getFont( nFontID );
1775 0 : if (pFont && pFont->m_nAscend == 0 && pFont->m_nDescend == 0)
1776 : {
1777 : // might be a truetype font not yet analyzed
1778 0 : if( pFont->m_eType == fonttype::TrueType )
1779 0 : analyzeTrueTypeFile( pFont );
1780 : }
1781 :
1782 0 : if (!pFont || !pFont->m_bHaveVerticalSubstitutedGlyphs)
1783 0 : memset( pHasSubst, 0, sizeof(bool)*nCharacters );
1784 : else
1785 : {
1786 0 : for( int i = 0; i < nCharacters; i++ )
1787 : {
1788 0 : sal_Unicode code = pCharacters[i];
1789 0 : if( ! pFont->m_pMetrics ||
1790 0 : ! ( pFont->m_pMetrics->m_aPages[ code >> 11 ] & ( 1 << ( ( code >> 8 ) & 7 ) ) ) )
1791 0 : pFont->queryMetricPage( code >> 8, m_pAtoms );
1792 0 : std::unordered_map< sal_Unicode, bool >::const_iterator it = pFont->m_pMetrics->m_bVerticalSubstitutions.find( code );
1793 0 : pHasSubst[i] = it != pFont->m_pMetrics->m_bVerticalSubstitutions.end();
1794 : }
1795 : }
1796 0 : }
1797 :
1798 0 : bool PrintFontManager::isFontDownloadingAllowedForPrinting( fontID nFont ) const
1799 : {
1800 0 : static const char* pEnable = getenv( "PSPRINT_ENABLE_TTF_COPYRIGHTAWARENESS" );
1801 0 : bool bRet = true;
1802 :
1803 0 : if( pEnable && *pEnable )
1804 : {
1805 0 : PrintFont* pFont = getFont( nFont );
1806 0 : if( pFont && pFont->m_eType == fonttype::TrueType )
1807 : {
1808 0 : TrueTypeFontFile* pTTFontFile = static_cast<TrueTypeFontFile*>(pFont);
1809 0 : if( pTTFontFile->m_nTypeFlags & TYPEFLAG_INVALID )
1810 : {
1811 0 : TrueTypeFont* pTTFont = NULL;
1812 0 : OString aFile = getFontFile( pFont );
1813 0 : if( OpenTTFontFile( aFile.getStr(), pTTFontFile->m_nCollectionEntry, &pTTFont ) == SF_OK )
1814 : {
1815 : // get type flags
1816 : TTGlobalFontInfo aInfo;
1817 0 : GetTTGlobalFontInfo( pTTFont, & aInfo );
1818 0 : pTTFontFile->m_nTypeFlags = (unsigned int)aInfo.typeFlags;
1819 0 : CloseTTFont( pTTFont );
1820 0 : }
1821 : }
1822 :
1823 0 : unsigned int nCopyrightFlags = pTTFontFile->m_nTypeFlags & TYPEFLAG_COPYRIGHT_MASK;
1824 :
1825 : // http://www.microsoft.com/typography/tt/ttf_spec/ttch02.doc
1826 : // Font embedding is allowed if not restricted completely (only bit 1 set).
1827 : // Preview&Print (bit 2), Editable (bit 3) or Installable (==0) fonts are ok.
1828 0 : bRet = ( nCopyrightFlags & 0x02 ) != 0x02;
1829 : }
1830 : }
1831 0 : return bRet;
1832 : }
1833 :
1834 0 : bool PrintFontManager::getMetrics( fontID nFontID, const sal_Unicode* pString, int nLen, CharacterMetric* pArray, bool bVertical ) const
1835 : {
1836 0 : PrintFont* pFont = getFont( nFontID );
1837 0 : if( ! pFont )
1838 0 : return false;
1839 :
1840 0 : if( ( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
1841 0 : || ! pFont->m_pMetrics || pFont->m_pMetrics->isEmpty()
1842 : )
1843 : {
1844 : // might be a font not yet analyzed
1845 0 : if( pFont->m_eType == fonttype::Type1 )
1846 0 : pFont->readAfmMetrics( m_pAtoms, false, false );
1847 0 : else if( pFont->m_eType == fonttype::TrueType )
1848 0 : analyzeTrueTypeFile( pFont );
1849 : }
1850 :
1851 0 : for( int i = 0; i < nLen; i++ )
1852 : {
1853 0 : if( ! pFont->m_pMetrics ||
1854 0 : ! ( pFont->m_pMetrics->m_aPages[ pString[i] >> 11 ] & ( 1 << ( ( pString[i] >> 8 ) & 7 ) ) ) )
1855 0 : pFont->queryMetricPage( pString[i] >> 8, m_pAtoms );
1856 0 : pArray[i].width = pArray[i].height = -1;
1857 0 : if( pFont->m_pMetrics )
1858 : {
1859 0 : int effectiveCode = pString[i];
1860 0 : effectiveCode |= bVertical ? 1 << 16 : 0;
1861 : std::unordered_map< int, CharacterMetric >::const_iterator it =
1862 0 : pFont->m_pMetrics->m_aMetrics.find( effectiveCode );
1863 : // if no vertical metrics are available assume rotated horizontal metrics
1864 0 : if( bVertical && (it == pFont->m_pMetrics->m_aMetrics.end()) )
1865 0 : it = pFont->m_pMetrics->m_aMetrics.find( pString[i] );
1866 : // the character metrics are in it->second
1867 0 : if( it != pFont->m_pMetrics->m_aMetrics.end() )
1868 0 : pArray[ i ] = it->second;
1869 : }
1870 : }
1871 :
1872 0 : return true;
1873 : }
1874 :
1875 4172 : bool PrintFontManager::getMetrics( fontID nFontID, sal_Unicode minCharacter, sal_Unicode maxCharacter, CharacterMetric* pArray, bool bVertical ) const
1876 : {
1877 : OSL_PRECOND(minCharacter <= maxCharacter, "invalid char. range");
1878 4172 : if (minCharacter > maxCharacter)
1879 0 : return false;
1880 :
1881 4172 : PrintFont* pFont = getFont( nFontID );
1882 4172 : if( ! pFont )
1883 0 : return false;
1884 :
1885 8344 : if( ( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
1886 8344 : || ! pFont->m_pMetrics || pFont->m_pMetrics->isEmpty()
1887 : )
1888 : {
1889 : // might be a font not yet analyzed
1890 0 : if( pFont->m_eType == fonttype::Type1 )
1891 0 : pFont->readAfmMetrics( m_pAtoms, false, false );
1892 0 : else if( pFont->m_eType == fonttype::TrueType )
1893 0 : analyzeTrueTypeFile( pFont );
1894 : }
1895 :
1896 4172 : sal_Unicode code = minCharacter;
1897 4172 : do
1898 : {
1899 8344 : if( ! pFont->m_pMetrics ||
1900 4172 : ! ( pFont->m_pMetrics->m_aPages[ code >> 11 ] & ( 1 << ( ( code >> 8 ) & 7 ) ) ) )
1901 0 : pFont->queryMetricPage( code >> 8, m_pAtoms );
1902 4172 : pArray[ code - minCharacter ].width = -1;
1903 4172 : pArray[ code - minCharacter ].height = -1;
1904 4172 : if( pFont->m_pMetrics )
1905 : {
1906 4172 : int effectiveCode = code;
1907 4172 : effectiveCode |= bVertical ? 1 << 16 : 0;
1908 : std::unordered_map< int, CharacterMetric >::const_iterator it =
1909 4172 : pFont->m_pMetrics->m_aMetrics.find( effectiveCode );
1910 : // if no vertical metrics are available assume rotated horizontal metrics
1911 4172 : if( bVertical && (it == pFont->m_pMetrics->m_aMetrics.end()) )
1912 0 : it = pFont->m_pMetrics->m_aMetrics.find( code );
1913 : // the character metrics are in it->second
1914 4172 : if( it != pFont->m_pMetrics->m_aMetrics.end() )
1915 4172 : pArray[ code - minCharacter ] = it->second;
1916 : }
1917 4172 : } while( code++ != maxCharacter );
1918 :
1919 4172 : return true;
1920 : }
1921 :
1922 : // TODO: move most of this stuff into the central font-subsetting code
1923 0 : bool PrintFontManager::createFontSubset(
1924 : FontSubsetInfo& rInfo,
1925 : fontID nFont,
1926 : const OUString& rOutFile,
1927 : const sal_GlyphId* pGlyphIds,
1928 : const sal_uInt8* pNewEncoding,
1929 : sal_Int32* pWidths,
1930 : int nGlyphs,
1931 : bool bVertical
1932 : )
1933 : {
1934 0 : PrintFont* pFont = getFont( nFont );
1935 0 : if( !pFont )
1936 0 : return false;
1937 :
1938 0 : switch( pFont->m_eType )
1939 : {
1940 0 : case psp::fonttype::TrueType: rInfo.m_nFontType = FontSubsetInfo::SFNT_TTF; break;
1941 0 : case psp::fonttype::Type1: rInfo.m_nFontType = FontSubsetInfo::ANY_TYPE1; break;
1942 : default:
1943 0 : return false;
1944 : }
1945 : // TODO: remove when Type1 subsetting gets implemented
1946 0 : if( pFont->m_eType != fonttype::TrueType )
1947 0 : return false;
1948 :
1949 : // reshuffle array of requested glyphs to make sure glyph0==notdef
1950 : sal_uInt8 pEnc[256];
1951 : sal_uInt16 pGID[256];
1952 : sal_uInt8 pOldIndex[256];
1953 0 : memset( pEnc, 0, sizeof( pEnc ) );
1954 0 : memset( pGID, 0, sizeof( pGID ) );
1955 0 : memset( pOldIndex, 0, sizeof( pOldIndex ) );
1956 0 : if( nGlyphs > 256 )
1957 0 : return false;
1958 0 : int nChar = 1;
1959 0 : for( int i = 0; i < nGlyphs; i++ )
1960 : {
1961 0 : if( pNewEncoding[i] == 0 )
1962 : {
1963 0 : pOldIndex[ 0 ] = i;
1964 : }
1965 : else
1966 : {
1967 : DBG_ASSERT( !(pGlyphIds[i] & 0x007f0000), "overlong glyph id" );
1968 : DBG_ASSERT( (int)pNewEncoding[i] < nGlyphs, "encoding wrong" );
1969 : DBG_ASSERT( pEnc[pNewEncoding[i]] == 0 && pGID[pNewEncoding[i]] == 0, "duplicate encoded glyph" );
1970 0 : pEnc[ pNewEncoding[i] ] = pNewEncoding[i];
1971 0 : pGID[ pNewEncoding[i] ] = (sal_uInt16)pGlyphIds[ i ];
1972 0 : pOldIndex[ pNewEncoding[i] ] = i;
1973 0 : nChar++;
1974 : }
1975 : }
1976 0 : nGlyphs = nChar; // either input value or increased by one
1977 :
1978 : // prepare system name for read access for subset source file
1979 : // TODO: since this file is usually already mmapped there is no need to open it again
1980 0 : const OString aFromFile = getFontFile( pFont );
1981 :
1982 0 : TrueTypeFont* pTTFont = NULL; // TODO: rename to SfntFont
1983 0 : TrueTypeFontFile* pTTFontFile = static_cast< TrueTypeFontFile* >(pFont);
1984 0 : if( OpenTTFontFile( aFromFile.getStr(), pTTFontFile->m_nCollectionEntry, &pTTFont ) != SF_OK )
1985 0 : return false;
1986 :
1987 : // prepare system name for write access for subset file target
1988 0 : OUString aSysPath;
1989 0 : if( osl_File_E_None != osl_getSystemPathFromFileURL( rOutFile.pData, &aSysPath.pData ) )
1990 0 : return false;
1991 0 : const rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
1992 0 : const OString aToFile( OUStringToOString( aSysPath, aEncoding ) );
1993 :
1994 : // do CFF subsetting if possible
1995 0 : int nCffLength = 0;
1996 0 : const sal_uInt8* pCffBytes = NULL;
1997 0 : if( GetSfntTable( pTTFont, O_CFF, &pCffBytes, &nCffLength ) )
1998 : {
1999 0 : rInfo.LoadFont( FontSubsetInfo::CFF_FONT, pCffBytes, nCffLength );
2000 : #if 1 // TODO: remove 16bit->long conversion when related methods handle non-16bit glyphids
2001 : sal_GlyphId aRequestedGlyphIds[256];
2002 0 : for( int i = 0; i < nGlyphs; ++i )
2003 0 : aRequestedGlyphIds[i] = pGID[i];
2004 : #endif
2005 : // create subset file at requested path
2006 0 : FILE* pOutFile = fopen( aToFile.getStr(), "wb" );
2007 0 : if (!pOutFile)
2008 : {
2009 0 : CloseTTFont( pTTFont );
2010 0 : return false;
2011 : }
2012 : // create font subset
2013 0 : const char* pGlyphSetName = NULL; // TODO: better name?
2014 : const bool bOK = rInfo.CreateFontSubset(
2015 : FontSubsetInfo::TYPE1_PFB,
2016 : pOutFile, pGlyphSetName,
2017 0 : aRequestedGlyphIds, pEnc, nGlyphs, pWidths );
2018 0 : fclose( pOutFile );
2019 : // cleanup before early return
2020 0 : CloseTTFont( pTTFont );
2021 0 : return bOK;
2022 : }
2023 :
2024 : // do TTF->Type42 or Type3 subsetting
2025 : // fill in font info
2026 0 : psp::PrintFontInfo aFontInfo;
2027 0 : if( ! getFontInfo( nFont, aFontInfo ) )
2028 0 : return false;
2029 :
2030 0 : rInfo.m_nAscent = aFontInfo.m_nAscend;
2031 0 : rInfo.m_nDescent = aFontInfo.m_nDescend;
2032 0 : rInfo.m_aPSName = getPSName( nFont );
2033 :
2034 : int xMin, yMin, xMax, yMax;
2035 0 : getFontBoundingBox( nFont, xMin, yMin, xMax, yMax );
2036 0 : rInfo.m_aFontBBox = Rectangle( Point( xMin, yMin ), Size( xMax-xMin, yMax-yMin ) );
2037 0 : rInfo.m_nCapHeight = yMax; // Well ...
2038 :
2039 : // fill in glyph advance widths
2040 : TTSimpleGlyphMetrics* pMetrics = GetTTSimpleGlyphMetrics( pTTFont,
2041 : pGID,
2042 : nGlyphs,
2043 0 : bVertical );
2044 0 : if( pMetrics )
2045 : {
2046 0 : for( int i = 0; i < nGlyphs; i++ )
2047 0 : pWidths[pOldIndex[i]] = pMetrics[i].adv;
2048 0 : free( pMetrics );
2049 : }
2050 : else
2051 : {
2052 0 : CloseTTFont( pTTFont );
2053 0 : return false;
2054 : }
2055 :
2056 : bool bSuccess = ( SF_OK == CreateTTFromTTGlyphs( pTTFont,
2057 : aToFile.getStr(),
2058 : pGID,
2059 : pEnc,
2060 : nGlyphs,
2061 : 0,
2062 : NULL,
2063 0 : 0 ) );
2064 0 : CloseTTFont( pTTFont );
2065 :
2066 0 : return bSuccess;
2067 : }
2068 :
2069 0 : void PrintFontManager::getGlyphWidths( fontID nFont,
2070 : bool bVertical,
2071 : std::vector< sal_Int32 >& rWidths,
2072 : std::map< sal_Unicode, sal_uInt32 >& rUnicodeEnc )
2073 : {
2074 0 : PrintFont* pFont = getFont( nFont );
2075 0 : if( !pFont ||
2076 0 : (pFont->m_eType != fonttype::TrueType && pFont->m_eType != fonttype::Type1) )
2077 0 : return;
2078 0 : if( pFont->m_eType == fonttype::TrueType )
2079 : {
2080 0 : TrueTypeFont* pTTFont = NULL;
2081 0 : TrueTypeFontFile* pTTFontFile = static_cast< TrueTypeFontFile* >(pFont);
2082 0 : OString aFromFile = getFontFile( pFont );
2083 0 : if( OpenTTFontFile( aFromFile.getStr(), pTTFontFile->m_nCollectionEntry, &pTTFont ) != SF_OK )
2084 0 : return;
2085 0 : int nGlyphs = GetTTGlyphCount( pTTFont );
2086 0 : if( nGlyphs > 0 )
2087 : {
2088 0 : rWidths.resize(nGlyphs);
2089 0 : std::vector<sal_uInt16> aGlyphIds(nGlyphs);
2090 0 : for( int i = 0; i < nGlyphs; i++ )
2091 0 : aGlyphIds[i] = sal_uInt16(i);
2092 : TTSimpleGlyphMetrics* pMetrics = GetTTSimpleGlyphMetrics( pTTFont,
2093 0 : &aGlyphIds[0],
2094 : nGlyphs,
2095 0 : bVertical );
2096 0 : if( pMetrics )
2097 : {
2098 0 : for( int i = 0; i< nGlyphs; i++ )
2099 0 : rWidths[i] = pMetrics[i].adv;
2100 0 : free( pMetrics );
2101 0 : rUnicodeEnc.clear();
2102 : }
2103 :
2104 : // fill the unicode map
2105 : // TODO: isn't this map already available elsewhere in the fontmanager?
2106 0 : const sal_uInt8* pCmapData = NULL;
2107 0 : int nCmapSize = 0;
2108 0 : if( GetSfntTable( pTTFont, O_cmap, &pCmapData, &nCmapSize ) )
2109 : {
2110 0 : CmapResult aCmapResult;
2111 0 : if( ParseCMAP( pCmapData, nCmapSize, aCmapResult ) )
2112 : {
2113 0 : FontCharMapPtr pCharMap( new FontCharMap(aCmapResult) );
2114 0 : for( sal_uInt32 cOld = 0;;)
2115 : {
2116 : // get next unicode covered by font
2117 0 : const sal_uInt32 c = pCharMap->GetNextChar( cOld );
2118 0 : if( c == cOld )
2119 0 : break;
2120 0 : cOld = c;
2121 : #if 1 // TODO: remove when sal_Unicode covers all of unicode
2122 0 : if( c > (sal_Unicode)~0 )
2123 0 : break;
2124 : #endif
2125 : // get the matching glyph index
2126 0 : const sal_GlyphId aGlyphId = pCharMap->GetGlyphIndex( c );
2127 : // update the requested map
2128 0 : rUnicodeEnc[ (sal_Unicode)c ] = aGlyphId;
2129 0 : }
2130 :
2131 0 : pCharMap = 0;
2132 : }
2133 0 : }
2134 : }
2135 0 : CloseTTFont( pTTFont );
2136 : }
2137 0 : else if( pFont->m_eType == fonttype::Type1 )
2138 : {
2139 0 : if( ! pFont->m_aEncodingVector.size() )
2140 0 : pFont->readAfmMetrics( m_pAtoms, true, true );
2141 0 : if( pFont->m_pMetrics )
2142 : {
2143 0 : rUnicodeEnc.clear();
2144 0 : rWidths.clear();
2145 0 : rWidths.reserve( pFont->m_pMetrics->m_aMetrics.size() );
2146 0 : for( std::unordered_map< int, CharacterMetric >::const_iterator it =
2147 0 : pFont->m_pMetrics->m_aMetrics.begin();
2148 0 : it != pFont->m_pMetrics->m_aMetrics.end(); ++it )
2149 : {
2150 0 : if( (it->first & 0x00010000) == 0 || bVertical )
2151 : {
2152 0 : rUnicodeEnc[ sal_Unicode(it->first & 0x0000ffff) ] = sal_uInt32(rWidths.size());
2153 0 : rWidths.push_back( it->second.width );
2154 : }
2155 : }
2156 : }
2157 : }
2158 : }
2159 :
2160 0 : const std::map< sal_Unicode, sal_Int32 >* PrintFontManager::getEncodingMap( fontID nFont, const std::map< sal_Unicode, OString >** pNonEncoded, std::set<sal_Unicode> const** ppPriority ) const
2161 : {
2162 0 : PrintFont* pFont = getFont( nFont );
2163 0 : if( !pFont || pFont->m_eType != fonttype::Type1 )
2164 0 : return NULL;
2165 :
2166 0 : if( ! pFont->m_aEncodingVector.size() )
2167 0 : pFont->readAfmMetrics( m_pAtoms, true, true );
2168 :
2169 0 : if( pNonEncoded )
2170 0 : *pNonEncoded = pFont->m_aNonEncoded.size() ? &pFont->m_aNonEncoded : NULL;
2171 :
2172 0 : if (ppPriority)
2173 : {
2174 0 : *ppPriority = &pFont->m_aEncodingVectorPriority;
2175 : }
2176 :
2177 0 : return pFont->m_aEncodingVector.size() ? &pFont->m_aEncodingVector : NULL;
2178 : }
2179 :
2180 0 : std::list< OString > PrintFontManager::getAdobeNameFromUnicode( sal_Unicode aChar ) const
2181 : {
2182 : std::pair< std::unordered_multimap< sal_Unicode, OString >::const_iterator,
2183 : std::unordered_multimap< sal_Unicode, OString >::const_iterator > range
2184 0 : = m_aUnicodeToAdobename.equal_range( aChar );
2185 :
2186 0 : std::list< OString > aRet;
2187 0 : for( ; range.first != range.second; ++range.first )
2188 0 : aRet.push_back( range.first->second );
2189 :
2190 0 : if( aRet.begin() == aRet.end() && aChar != 0 )
2191 : {
2192 : sal_Char aBuf[8];
2193 0 : sal_Int32 nChars = snprintf( aBuf, sizeof( aBuf ), "uni%.4hX", aChar );
2194 0 : aRet.push_back( OString( aBuf, nChars ) );
2195 : }
2196 :
2197 0 : return aRet;
2198 : }
2199 :
2200 562 : std::list< sal_Unicode > PrintFontManager::getUnicodeFromAdobeName( const OString& rName ) const
2201 : {
2202 : std::pair< std::unordered_multimap< OString, sal_Unicode, OStringHash >::const_iterator,
2203 : std::unordered_multimap< OString, sal_Unicode, OStringHash >::const_iterator > range
2204 562 : = m_aAdobenameToUnicode.equal_range( rName );
2205 :
2206 562 : std::list< sal_Unicode > aRet;
2207 1028 : for( ; range.first != range.second; ++range.first )
2208 466 : aRet.push_back( range.first->second );
2209 :
2210 562 : if( aRet.begin() == aRet.end() )
2211 : {
2212 107 : if( rName.getLength() == 7 && rName.startsWith( "uni" ) )
2213 : {
2214 107 : sal_Unicode aCode = (sal_Unicode)rName.copy( 3 ).toUInt32( 16 );
2215 107 : aRet.push_back( aCode );
2216 : }
2217 : }
2218 :
2219 562 : return aRet;
2220 801 : }
2221 :
2222 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|