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