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