Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 :
21 : #include <unistd.h>
22 : #include <sys/stat.h>
23 : #include <dirent.h>
24 : #include <stdlib.h>
25 : #include <osl/thread.h>
26 :
27 : #include "unotools/atom.hxx"
28 :
29 : #include "fontcache.hxx"
30 : #include "fontsubset.hxx"
31 : #include "impfont.hxx"
32 : #include "svdata.hxx"
33 : #include "generic/geninst.h"
34 : #include "vcl/fontmanager.hxx"
35 : #include "vcl/strhelper.hxx"
36 : #include "vcl/ppdparser.hxx"
37 : #include <vcl/temporaryfonts.hxx>
38 :
39 : #include "tools/urlobj.hxx"
40 : #include "tools/stream.hxx"
41 : #include "tools/debug.hxx"
42 :
43 : #include "osl/file.hxx"
44 : #include "osl/process.h"
45 :
46 : #include "rtl/tencinfo.h"
47 : #include "rtl/ustrbuf.hxx"
48 : #include "rtl/strbuf.hxx"
49 :
50 : #include <sal/macros.h>
51 :
52 : #include "i18npool/mslangid.hxx"
53 :
54 :
55 : #include "parseAFM.hxx"
56 : #include "sft.hxx"
57 :
58 : #if OSL_DEBUG_LEVEL > 1
59 : #include <sys/times.h>
60 : #include <stdio.h>
61 : #endif
62 :
63 : #include "sal/alloca.h"
64 :
65 : #include <set>
66 : #include <boost/unordered_set.hpp>
67 : #include <algorithm>
68 :
69 : #include "adobeenc.tab" // get encoding table for AFM metrics
70 :
71 : #ifdef CALLGRIND_COMPILE
72 : #include <valgrind/callgrind.h>
73 : #endif
74 :
75 : #include <comphelper/processfactory.hxx>
76 : #include <comphelper/string.hxx>
77 : #include "com/sun/star/beans/XMaterialHolder.hpp"
78 : #include "com/sun/star/beans/NamedValue.hpp"
79 :
80 : #define PRINTER_METRICDIR "fontmetric"
81 :
82 : using namespace vcl;
83 : using namespace utl;
84 : using namespace psp;
85 : using namespace osl;
86 : using namespace com::sun::star::uno;
87 : using namespace com::sun::star::beans;
88 : using namespace com::sun::star::lang;
89 :
90 : using ::comphelper::string::getToken;
91 : using ::rtl::OUString;
92 : using ::rtl::OString;
93 : using ::rtl::OStringHash;
94 : using ::rtl::OStringBuffer;
95 : using ::rtl::OUStringBuffer;
96 : using ::rtl::OUStringHash;
97 : using ::rtl::OStringToOUString;
98 : using ::rtl::OUStringToOString;
99 :
100 : /*
101 : * static helpers
102 : */
103 :
104 2356 : inline sal_uInt16 getUInt16BE( const sal_uInt8*& pBuffer )
105 : {
106 2356 : sal_uInt16 nRet = (sal_uInt16)pBuffer[1] |
107 2356 : (((sal_uInt16)pBuffer[0]) << 8);
108 2356 : pBuffer+=2;
109 2356 : return nRet;
110 : }
111 :
112 0 : inline sal_uInt32 getUInt32BE( const sal_uInt8*& pBuffer )
113 : {
114 0 : sal_uInt32 nRet = (((sal_uInt32)pBuffer[0]) << 24) |
115 0 : (((sal_uInt32)pBuffer[1]) << 16) |
116 0 : (((sal_uInt32)pBuffer[2]) << 8) |
117 0 : (((sal_uInt32)pBuffer[3]) );
118 0 : pBuffer += 4;
119 0 : return nRet;
120 : }
121 :
122 : // -------------------------------------------------------------------------
123 :
124 70 : static FontWeight parseWeight( const rtl::OString& rWeight )
125 : {
126 70 : FontWeight eWeight = WEIGHT_DONTKNOW;
127 70 : if (rWeight.indexOfL(RTL_CONSTASCII_STRINGPARAM("bold") ) != -1)
128 : {
129 28 : if (rWeight.indexOfL(RTL_CONSTASCII_STRINGPARAM("emi")) != -1) // semi, demi
130 0 : eWeight = WEIGHT_SEMIBOLD;
131 28 : else if (rWeight.indexOfL(RTL_CONSTASCII_STRINGPARAM("ultra")) != -1)
132 0 : eWeight = WEIGHT_ULTRABOLD;
133 : else
134 28 : eWeight = WEIGHT_BOLD;
135 : }
136 42 : else if (rWeight.indexOfL(RTL_CONSTASCII_STRINGPARAM("heavy")) != -1)
137 0 : eWeight = WEIGHT_BOLD;
138 42 : else if (rWeight.indexOfL(RTL_CONSTASCII_STRINGPARAM("light")) != -1)
139 : {
140 0 : if (rWeight.indexOfL(RTL_CONSTASCII_STRINGPARAM("emi")) != -1) // semi, demi
141 0 : eWeight = WEIGHT_SEMILIGHT;
142 0 : else if (rWeight.indexOfL(RTL_CONSTASCII_STRINGPARAM("ultra")) != -1)
143 0 : eWeight = WEIGHT_ULTRALIGHT;
144 : else
145 0 : eWeight = WEIGHT_LIGHT;
146 : }
147 42 : else if (rWeight.indexOfL(RTL_CONSTASCII_STRINGPARAM("black")) != -1)
148 0 : eWeight = WEIGHT_BLACK;
149 42 : else if (rWeight.equalsL(RTL_CONSTASCII_STRINGPARAM("demi")))
150 4 : eWeight = WEIGHT_SEMIBOLD;
151 72 : else if (rWeight.equalsL(RTL_CONSTASCII_STRINGPARAM("book")) ||
152 34 : rWeight.equalsL(RTL_CONSTASCII_STRINGPARAM("semicondensed")))
153 4 : eWeight = WEIGHT_LIGHT;
154 34 : else if (rWeight.equalsL(RTL_CONSTASCII_STRINGPARAM("medium")) || rWeight.equalsL(RTL_CONSTASCII_STRINGPARAM("roman")))
155 6 : eWeight = WEIGHT_MEDIUM;
156 : else
157 28 : eWeight = WEIGHT_NORMAL;
158 70 : return eWeight;
159 : }
160 :
161 : /*
162 : * PrintFont implementations
163 : */
164 4920 : PrintFontManager::PrintFont::PrintFont( fonttype::type eType ) :
165 : m_eType( eType ),
166 : m_nFamilyName( 0 ),
167 : m_nPSName( 0 ),
168 : m_eItalic( ITALIC_DONTKNOW ),
169 : m_eWidth( WIDTH_DONTKNOW ),
170 : m_eWeight( WEIGHT_DONTKNOW ),
171 : m_ePitch( PITCH_DONTKNOW ),
172 : m_aEncoding( RTL_TEXTENCODING_DONTKNOW ),
173 : m_bFontEncodingOnly( false ),
174 : m_pMetrics( NULL ),
175 : m_nAscend( 0 ),
176 : m_nDescend( 0 ),
177 : m_nLeading( 0 ),
178 : m_nXMin( 0 ),
179 : m_nYMin( 0 ),
180 : m_nXMax( 0 ),
181 : m_nYMax( 0 ),
182 : m_bHaveVerticalSubstitutedGlyphs( false ),
183 4920 : m_bUserOverride( false )
184 : {
185 4920 : }
186 :
187 : // -------------------------------------------------------------------------
188 :
189 9840 : PrintFontManager::PrintFont::~PrintFont()
190 : {
191 4920 : if( m_pMetrics )
192 70 : delete m_pMetrics;
193 4920 : }
194 :
195 : // -------------------------------------------------------------------------
196 :
197 2800 : PrintFontManager::Type1FontFile::~Type1FontFile()
198 : {
199 2800 : }
200 :
201 : // -------------------------------------------------------------------------
202 :
203 3520 : PrintFontManager::TrueTypeFontFile::TrueTypeFontFile()
204 : : PrintFont( fonttype::TrueType )
205 : , m_nDirectory( 0 )
206 : , m_nCollectionEntry( 0 )
207 3520 : , m_nTypeFlags( TYPEFLAG_INVALID )
208 3520 : {}
209 :
210 : // -------------------------------------------------------------------------
211 :
212 7040 : PrintFontManager::TrueTypeFontFile::~TrueTypeFontFile()
213 : {
214 7040 : }
215 :
216 : // -------------------------------------------------------------------------
217 :
218 0 : PrintFontManager::BuiltinFont::~BuiltinFont()
219 : {
220 0 : }
221 :
222 : // -------------------------------------------------------------------------
223 :
224 0 : bool PrintFontManager::Type1FontFile::queryMetricPage( int /*nPage*/, MultiAtomProvider* pProvider )
225 : {
226 0 : return readAfmMetrics( PrintFontManager::get().getAfmFile( this ), pProvider, false, false );
227 : }
228 :
229 : // -------------------------------------------------------------------------
230 :
231 0 : bool PrintFontManager::BuiltinFont::queryMetricPage( int /*nPage*/, MultiAtomProvider* pProvider )
232 : {
233 0 : return readAfmMetrics( PrintFontManager::get().getAfmFile( this ), pProvider, false, false );
234 : }
235 :
236 : // -------------------------------------------------------------------------
237 :
238 0 : bool PrintFontManager::TrueTypeFontFile::queryMetricPage( int nPage, MultiAtomProvider* pProvider )
239 : {
240 0 : bool bSuccess = false;
241 :
242 0 : rtl::OString aFile( PrintFontManager::get().getFontFile( this ) );
243 :
244 0 : TrueTypeFont* pTTFont = NULL;
245 :
246 0 : if( OpenTTFontFile( aFile.getStr(), m_nCollectionEntry, &pTTFont ) == SF_OK )
247 : {
248 0 : if( ! m_pMetrics )
249 : {
250 0 : m_pMetrics = new PrintFontMetrics;
251 0 : memset (m_pMetrics->m_aPages, 0, sizeof(m_pMetrics->m_aPages));
252 : }
253 0 : m_pMetrics->m_aPages[ nPage/8 ] |= (1 << ( nPage & 7 ));
254 : int i;
255 : sal_uInt16 table[256], table_vert[256];
256 :
257 0 : for( i = 0; i < 256; i++ )
258 0 : table[ i ] = 256*nPage + i;
259 :
260 0 : int nCharacters = nPage < 255 ? 256 : 254;
261 0 : MapString( pTTFont, table, nCharacters, NULL, 0 );
262 0 : TTSimpleGlyphMetrics* pMetrics = GetTTSimpleCharMetrics( pTTFont, nPage*256, nCharacters, 0 );
263 0 : if( pMetrics )
264 : {
265 0 : for( i = 0; i < nCharacters; i++ )
266 : {
267 0 : if( table[i] )
268 : {
269 0 : CharacterMetric& rChar = m_pMetrics->m_aMetrics[ nPage*256 + i ];
270 0 : rChar.width = pMetrics[ i ].adv;
271 0 : rChar.height = m_aGlobalMetricX.height;
272 : }
273 : }
274 :
275 0 : free( pMetrics );
276 : }
277 :
278 0 : for( i = 0; i < 256; i++ )
279 0 : table_vert[ i ] = 256*nPage + i;
280 0 : MapString( pTTFont, table_vert, nCharacters, NULL, 1 );
281 0 : pMetrics = GetTTSimpleCharMetrics( pTTFont, nPage*256, nCharacters, 1 );
282 0 : if( pMetrics )
283 : {
284 0 : for( i = 0; i < nCharacters; i++ )
285 : {
286 0 : if( table_vert[i] )
287 : {
288 0 : CharacterMetric& rChar = m_pMetrics->m_aMetrics[ nPage*256 + i + ( 1 << 16 ) ];
289 0 : rChar.width = m_aGlobalMetricY.width;
290 0 : rChar.height = pMetrics[ i ].adv;
291 0 : if( table_vert[i] != table[i] )
292 0 : m_pMetrics->m_bVerticalSubstitutions[ nPage*256 + i ] = 1;
293 : }
294 : }
295 0 : free( pMetrics );
296 : }
297 :
298 0 : if( ! m_pMetrics->m_bKernPairsQueried )
299 : {
300 0 : m_pMetrics->m_bKernPairsQueried = true;
301 : // this is really a hack
302 : // in future MapString/KernGlyphs should be used
303 : // but vcl is not in a state where that could be used
304 : // so currently we get kernpairs by accessing the raw data
305 0 : struct _TrueTypeFont* pImplTTFont = (struct _TrueTypeFont*)pTTFont;
306 :
307 : //-----------------------------------------------------------------
308 : // Kerning: KT_MICROSOFT
309 : //-----------------------------------------------------------------
310 0 : if( pImplTTFont->nkern && pImplTTFont->kerntype == KT_MICROSOFT )
311 : {
312 : // create a glyph -> character mapping
313 0 : ::boost::unordered_map< sal_uInt16, sal_Unicode > aGlyphMap;
314 0 : ::boost::unordered_map< sal_uInt16, sal_Unicode >::iterator left, right;
315 0 : for( i = 21; i < 0xfffd; i++ )
316 : {
317 0 : sal_uInt16 nGlyph = MapChar( pTTFont, (sal_Unicode)i, 0 ); // kerning for horz only
318 0 : if( nGlyph != 0 )
319 0 : aGlyphMap[ nGlyph ] = (sal_Unicode)i;
320 : }
321 :
322 :
323 0 : KernPair aPair;
324 0 : for( i = 0; i < (int)pImplTTFont->nkern; i++ )
325 : {
326 0 : const sal_uInt8* pTable = pImplTTFont->kerntables[i];
327 :
328 0 : /*sal_uInt16 nVersion =*/ getUInt16BE( pTable );
329 0 : /*sal_uInt16 nLength =*/ getUInt16BE( pTable );
330 0 : sal_uInt16 nCoverage = getUInt16BE( pTable );
331 :
332 0 : aPair.kern_x = 0;
333 0 : aPair.kern_y = 0;
334 0 : switch( nCoverage >> 8 )
335 : {
336 : case 0:
337 : {
338 0 : sal_uInt16 nPairs = getUInt16BE( pTable );
339 0 : pTable += 6;
340 0 : for( int n = 0; n < nPairs; n++ )
341 : {
342 0 : sal_uInt16 nLeftGlyph = getUInt16BE( pTable );
343 0 : sal_uInt16 nRightGlyph = getUInt16BE( pTable );
344 0 : sal_Int16 nKern = (sal_Int16)getUInt16BE( pTable );
345 :
346 0 : left = aGlyphMap.find( nLeftGlyph );
347 0 : right = aGlyphMap.find( nRightGlyph );
348 0 : if( left != aGlyphMap.end() && right != aGlyphMap.end() )
349 : {
350 0 : aPair.first = left->second;
351 0 : aPair.second = right->second;
352 0 : switch( nCoverage & 1 )
353 : {
354 : case 1:
355 0 : aPair.kern_x = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
356 0 : m_pMetrics->m_aXKernPairs.push_back( aPair );
357 0 : break;
358 : case 0:
359 0 : aPair.kern_y = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
360 0 : m_pMetrics->m_aYKernPairs.push_back( aPair );
361 0 : break;
362 : }
363 : }
364 : }
365 : }
366 0 : break;
367 :
368 : case 2:
369 : {
370 0 : const sal_uInt8* pSubTable = pTable;
371 0 : /*sal_uInt16 nRowWidth =*/ getUInt16BE( pTable );
372 0 : sal_uInt16 nOfLeft = getUInt16BE( pTable );
373 0 : sal_uInt16 nOfRight = getUInt16BE( pTable );
374 0 : /*sal_uInt16 nOfArray =*/ getUInt16BE( pTable );
375 0 : const sal_uInt8* pTmp = pSubTable + nOfLeft;
376 0 : sal_uInt16 nFirstLeft = getUInt16BE( pTmp );
377 0 : sal_uInt16 nLastLeft = getUInt16BE( pTmp ) + nFirstLeft - 1;
378 0 : pTmp = pSubTable + nOfRight;
379 0 : sal_uInt16 nFirstRight = getUInt16BE( pTmp );
380 0 : sal_uInt16 nLastRight = getUInt16BE( pTmp ) + nFirstRight -1;
381 :
382 : // int nPairs = (int)(nLastLeft-nFirstLeft+1)*(int)(nLastRight-nFirstRight+1);
383 0 : for( aPair.first = nFirstLeft; aPair.first < nLastLeft; aPair.first++ )
384 : {
385 0 : for( aPair.second = 0; aPair.second < nLastRight; aPair.second++ )
386 : {
387 0 : sal_Int16 nKern = (sal_Int16)getUInt16BE( pTmp );
388 0 : switch( nCoverage & 1 )
389 : {
390 : case 1:
391 0 : aPair.kern_x = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
392 0 : m_pMetrics->m_aXKernPairs.push_back( aPair );
393 0 : break;
394 : case 0:
395 0 : aPair.kern_y = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
396 0 : m_pMetrics->m_aYKernPairs.push_back( aPair );
397 0 : break;
398 : }
399 : }
400 : }
401 : }
402 0 : break;
403 : }
404 0 : }
405 : }
406 :
407 : //-----------------------------------------------------------------
408 : // Kerning: KT_APPLE_NEW
409 : //-----------------------------------------------------------------
410 0 : if( pImplTTFont->nkern && pImplTTFont->kerntype == KT_APPLE_NEW )
411 : {
412 : // create a glyph -> character mapping
413 0 : ::boost::unordered_map< sal_uInt16, sal_Unicode > aGlyphMap;
414 0 : ::boost::unordered_map< sal_uInt16, sal_Unicode >::iterator left, right;
415 0 : for( i = 21; i < 0xfffd; i++ )
416 : {
417 0 : sal_uInt16 nGlyph = MapChar( pTTFont, (sal_Unicode)i, 0 ); // kerning for horz only
418 0 : if( nGlyph != 0 )
419 0 : aGlyphMap[ nGlyph ] = (sal_Unicode)i;
420 : }
421 :
422 : // Loop through each of the 'kern' subtables
423 0 : KernPair aPair;
424 0 : for( i = 0; (unsigned int)i < pImplTTFont->nkern; i++ )
425 : {
426 0 : const sal_uInt8* pTable = pImplTTFont->kerntables[i];
427 :
428 0 : /*sal_uInt32 nLength =*/ getUInt32BE( pTable );
429 0 : sal_uInt16 nCoverage = getUInt16BE( pTable );
430 0 : /*sal_uInt16 nTupleIndex =*/ getUInt16BE( pTable );
431 :
432 : // Get kerning type
433 : // sal_Bool bKernVertical = nCoverage & 0x8000;
434 : // sal_Bool bKernCrossStream = nCoverage & 0x4000;
435 : // sal_Bool bKernVariation = nCoverage & 0x2000;
436 :
437 : // Kerning sub-table format, 0 through 3
438 0 : sal_uInt8 nSubTableFormat = nCoverage & 0x00FF;
439 :
440 0 : aPair.kern_x = 0;
441 0 : aPair.kern_y = 0;
442 0 : switch( nSubTableFormat )
443 : {
444 : case 0:
445 : {
446 : // Grab the # of kern pairs but skip over the:
447 : // searchRange
448 : // entrySelector
449 : // rangeShift
450 0 : sal_uInt16 nPairs = getUInt16BE( pTable );
451 0 : pTable += 6;
452 :
453 0 : for( int n = 0; n < nPairs; n++ )
454 : {
455 0 : sal_uInt16 nLeftGlyph = getUInt16BE( pTable );
456 0 : sal_uInt16 nRightGlyph = getUInt16BE( pTable );
457 0 : sal_Int16 nKern = (sal_Int16)getUInt16BE( pTable );
458 :
459 0 : left = aGlyphMap.find( nLeftGlyph );
460 0 : right = aGlyphMap.find( nRightGlyph );
461 0 : if( left != aGlyphMap.end() && right != aGlyphMap.end() )
462 : {
463 0 : aPair.first = left->second;
464 0 : aPair.second = right->second;
465 :
466 : // Only support horizontal kerning for now
467 0 : aPair.kern_x = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
468 0 : aPair.kern_y = 0;
469 0 : m_pMetrics->m_aXKernPairs.push_back( aPair );
470 : }
471 : }
472 : }
473 0 : break;
474 :
475 : case 2:
476 : {
477 0 : const sal_uInt8* pSubTable = pTable;
478 0 : /*sal_uInt16 nRowWidth =*/ getUInt16BE( pTable );
479 0 : sal_uInt16 nOfLeft = getUInt16BE( pTable );
480 0 : sal_uInt16 nOfRight = getUInt16BE( pTable );
481 0 : /*sal_uInt16 nOfArray =*/ getUInt16BE( pTable );
482 0 : const sal_uInt8* pTmp = pSubTable + nOfLeft;
483 0 : sal_uInt16 nFirstLeft = getUInt16BE( pTmp );
484 0 : sal_uInt16 nLastLeft = getUInt16BE( pTmp ) + nFirstLeft - 1;
485 0 : pTmp = pSubTable + nOfRight;
486 0 : sal_uInt16 nFirstRight = getUInt16BE( pTmp );
487 0 : sal_uInt16 nLastRight = getUInt16BE( pTmp ) + nFirstRight -1;
488 :
489 0 : for( aPair.first = nFirstLeft; aPair.first < nLastLeft; aPair.first++ )
490 : {
491 0 : for( aPair.second = 0; aPair.second < nLastRight; aPair.second++ )
492 : {
493 0 : sal_Int16 nKern = (sal_Int16)getUInt16BE( pTmp );
494 0 : switch( nCoverage & 1 )
495 : {
496 : case 1:
497 0 : aPair.kern_x = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
498 0 : m_pMetrics->m_aXKernPairs.push_back( aPair );
499 0 : break;
500 : case 0:
501 0 : aPair.kern_y = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
502 0 : m_pMetrics->m_aYKernPairs.push_back( aPair );
503 0 : break;
504 : }
505 : }
506 : }
507 : }
508 0 : break;
509 :
510 : default:
511 0 : fprintf( stderr, "Found unsupported Apple-style kern subtable type %d.\n", nSubTableFormat );
512 0 : break;
513 : }
514 0 : }
515 : }
516 :
517 : #if OSL_DEBUG_LEVEL > 1
518 : fprintf( stderr, "found %" SAL_PRI_SIZET "u/%" SAL_PRI_SIZET "u kern pairs for %s\n",
519 : m_pMetrics->m_aXKernPairs.size(),
520 : m_pMetrics->m_aYKernPairs.size(),
521 : OUStringToOString( pProvider->getString( ATOM_FAMILYNAME, m_nFamilyName ), RTL_TEXTENCODING_MS_1252 ).getStr() );
522 : #else
523 : (void) pProvider; /* avoid warnings */
524 : #endif
525 : }
526 :
527 0 : CloseTTFont( pTTFont );
528 0 : bSuccess = true;
529 : }
530 0 : return bSuccess;
531 : }
532 :
533 : // -------------------------------------------------------------------------
534 :
535 : /* #i73387# There seem to be fonts with a rather unwell chosen family name
536 : * consider e.g. "Helvetica Narrow" which defines its family as "Helvetica"
537 : * It can really only be distinguished by its PSName and FullName. Both of
538 : * which are not user presentable in OOo. So replace it by something sensible.
539 : *
540 : * If other fonts feature this behaviour, insert them to the map.
541 : */
542 70 : static bool familyNameOverride( const OUString& i_rPSname, OUString& o_rFamilyName )
543 : {
544 70 : static boost::unordered_map< OUString, OUString, OUStringHash > aPSNameToFamily( 16 );
545 70 : if( aPSNameToFamily.empty() ) // initialization
546 : {
547 4 : aPSNameToFamily[ OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica-Narrow" ) ) ] =
548 6 : OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica Narrow" ) );
549 4 : aPSNameToFamily[ OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica-Narrow-Bold" ) ) ] =
550 6 : OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica Narrow" ) );
551 4 : aPSNameToFamily[ OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica-Narrow-BoldOblique" ) ) ] =
552 6 : OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica Narrow" ) );
553 4 : aPSNameToFamily[ OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica-Narrow-Oblique" ) ) ] =
554 6 : OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica Narrow" ) );
555 : }
556 : boost::unordered_map<OUString,OUString,OUStringHash>::const_iterator it =
557 70 : aPSNameToFamily.find( i_rPSname );
558 70 : bool bReplaced = (it != aPSNameToFamily.end() );
559 70 : if( bReplaced )
560 0 : o_rFamilyName = it->second;
561 70 : return bReplaced;
562 : };
563 :
564 70 : bool PrintFontManager::PrintFont::readAfmMetrics( const OString& rFileName, MultiAtomProvider* pProvider, bool bFillEncodingvector, bool bOnlyGlobalAttributes )
565 : {
566 70 : PrintFontManager& rManager( PrintFontManager::get() );
567 :
568 70 : FontInfo* pInfo = NULL;
569 70 : parseFile( rFileName.getStr(), &pInfo, P_ALL );
570 70 : if( ! pInfo || ! pInfo->numOfChars )
571 : {
572 0 : if( pInfo )
573 0 : freeFontInfo( pInfo );
574 0 : return false;
575 : }
576 :
577 70 : m_aEncodingVector.clear();
578 : // fill in global info
579 :
580 : // PSName
581 70 : OUString aPSName( OStringToOUString( pInfo->gfi->fontName, RTL_TEXTENCODING_ISO_8859_1 ) );
582 70 : m_nPSName = pProvider->getAtom( ATOM_PSNAME, aPSName, sal_True );
583 :
584 : // family name (if not already set)
585 70 : OUString aFamily;
586 70 : if( ! m_nFamilyName )
587 : {
588 70 : aFamily = OStringToOUString( pInfo->gfi->familyName, RTL_TEXTENCODING_ISO_8859_1 );
589 70 : if( aFamily.isEmpty() )
590 : {
591 0 : aFamily = OStringToOUString( pInfo->gfi->fontName, RTL_TEXTENCODING_ISO_8859_1 );
592 0 : sal_Int32 nIndex = 0;
593 0 : aFamily = aFamily.getToken( 0, '-', nIndex );
594 : }
595 70 : familyNameOverride( aPSName, aFamily );
596 70 : m_nFamilyName = pProvider->getAtom( ATOM_FAMILYNAME, aFamily, sal_True );
597 : }
598 : else
599 0 : aFamily = pProvider->getString( ATOM_FAMILYNAME, m_nFamilyName );
600 :
601 : // style name: if fullname begins with family name
602 : // interpret the rest of fullname as style
603 70 : if( m_aStyleName.isEmpty() && pInfo->gfi->fullName && *pInfo->gfi->fullName )
604 : {
605 70 : OUString aFullName( OStringToOUString( pInfo->gfi->fullName, RTL_TEXTENCODING_ISO_8859_1 ) );
606 70 : if( aFullName.indexOf( aFamily ) == 0 )
607 70 : m_aStyleName = WhitespaceToSpace( aFullName.copy( aFamily.getLength() ) );
608 : }
609 :
610 : // italic
611 70 : if( pInfo->gfi->italicAngle > 0 )
612 0 : m_eItalic = ITALIC_OBLIQUE;
613 70 : else if( pInfo->gfi->italicAngle < 0 )
614 34 : m_eItalic = ITALIC_NORMAL;
615 : else
616 36 : m_eItalic = ITALIC_NONE;
617 :
618 : // weight
619 70 : rtl::OString aWeight( pInfo->gfi->weight );
620 70 : m_eWeight = parseWeight( aWeight.toAsciiLowerCase() );
621 :
622 : // pitch
623 70 : m_ePitch = pInfo->gfi->isFixedPitch ? PITCH_FIXED : PITCH_VARIABLE;
624 :
625 : // encoding - only set if unknown
626 70 : int nAdobeEncoding = 0;
627 70 : if( pInfo->gfi->encodingScheme )
628 : {
629 70 : if( !strcmp( pInfo->gfi->encodingScheme, "AdobeStandardEncoding" ) )
630 66 : nAdobeEncoding = 1;
631 4 : else if( !strcmp( pInfo->gfi->encodingScheme, "ISO10646-1" ) )
632 : {
633 0 : nAdobeEncoding = 1;
634 0 : m_aEncoding = RTL_TEXTENCODING_UNICODE;
635 : }
636 4 : else if( !strcmp( pInfo->gfi->encodingScheme, "Symbol") )
637 0 : nAdobeEncoding = 2;
638 4 : else if( !strcmp( pInfo->gfi->encodingScheme, "FontSpecific") )
639 4 : nAdobeEncoding = 3;
640 :
641 70 : if( m_aEncoding == RTL_TEXTENCODING_DONTKNOW )
642 : m_aEncoding = nAdobeEncoding == 1 ?
643 70 : RTL_TEXTENCODING_ADOBE_STANDARD : RTL_TEXTENCODING_SYMBOL;
644 : }
645 0 : else if( m_aEncoding == RTL_TEXTENCODING_DONTKNOW )
646 0 : m_aEncoding = RTL_TEXTENCODING_ADOBE_STANDARD;
647 :
648 : // try to parse the font name and decide whether it might be a
649 : // japanese font. Who invented this PITA ?
650 70 : OUString aPSNameLastToken( aPSName.copy( aPSName.lastIndexOf( '-' )+1 ) );
651 140 : if( ! aPSNameLastToken.compareToAscii( "H" ) ||
652 70 : ! aPSNameLastToken.compareToAscii( "V" ) )
653 : {
654 : static const char* pEncs[] =
655 : {
656 : "EUC",
657 : "RKSJ",
658 : "SJ"
659 : };
660 : static const rtl_TextEncoding aEncs[] =
661 : {
662 : RTL_TEXTENCODING_EUC_JP,
663 : RTL_TEXTENCODING_SHIFT_JIS,
664 : RTL_TEXTENCODING_JIS_X_0208
665 : };
666 :
667 0 : for( unsigned int enc = 0; enc < SAL_N_ELEMENTS( aEncs ) && m_aEncoding == RTL_TEXTENCODING_DONTKNOW; enc++ )
668 : {
669 0 : sal_Int32 nIndex = 0, nOffset = 1;
670 0 : do
671 : {
672 0 : OUString aToken( aPSName.getToken( nOffset, '-', nIndex ) );
673 0 : if( nIndex == -1 )
674 : break;
675 0 : nOffset = 0;
676 0 : if( ! aToken.compareToAscii( pEncs[enc] ) )
677 : {
678 0 : m_aEncoding = aEncs[ enc ];
679 0 : m_bFontEncodingOnly = true;
680 0 : }
681 : } while( nIndex != -1 );
682 : }
683 :
684 : // default is jis
685 0 : if( m_aEncoding == RTL_TEXTENCODING_DONTKNOW )
686 0 : m_aEncoding = RTL_TEXTENCODING_JIS_X_0208;
687 : #if OSL_DEBUG_LEVEL > 1
688 : fprintf( stderr, "Encoding %d for %s\n", m_aEncoding, pInfo->gfi->fontName );
689 : #endif
690 : }
691 :
692 : // hack for GB encoded builtin fonts posing as FontSpecific
693 70 : if( m_eType == fonttype::Builtin && ( nAdobeEncoding == 3 || nAdobeEncoding == 0 ) )
694 : {
695 0 : int nLen = aFamily.getLength();
696 0 : if( nLen > 2 &&
697 0 : aFamily.getStr()[ nLen-2 ] == 'G' &&
698 0 : aFamily.getStr()[ nLen-1 ] == 'B' &&
699 : pInfo->numOfChars > 255 )
700 : {
701 0 : m_aEncoding = RTL_TEXTENCODING_GBK;
702 0 : m_bFontEncodingOnly = true;
703 : #if OSL_DEBUG_LEVEL > 1
704 : fprintf( stderr, "found builtin font %s with GBK encoding\n", pInfo->gfi->fontName );
705 : #endif
706 : }
707 : }
708 :
709 : // #i37313# check if Fontspecific is not rather some character encoding
710 70 : if( nAdobeEncoding == 3 && m_aEncoding == RTL_TEXTENCODING_SYMBOL )
711 : {
712 4 : bool bYFound = false;
713 4 : bool bQFound = false;
714 4 : CharMetricInfo* pChar = pInfo->cmi;
715 790 : for( int j = 0; j < pInfo->numOfChars && ! (bYFound && bQFound); j++ )
716 : {
717 786 : if( pChar[j].name )
718 : {
719 786 : if( pChar[j].name[0] == 'Y' && pChar[j].name[1] == 0 )
720 0 : bYFound = true;
721 786 : else if( pChar[j].name[0] == 'Q' && pChar[j].name[1] == 0 )
722 0 : bQFound = true;
723 : }
724 : }
725 4 : if( bQFound && bYFound )
726 : {
727 : #if OSL_DEBUG_LEVEL > 1
728 : fprintf( stderr, "setting FontSpecific font %s (file %s) to unicode\n",
729 : pInfo->gfi->fontName,
730 : rFileName.getStr()
731 : );
732 : #endif
733 0 : nAdobeEncoding = 4;
734 0 : m_aEncoding = RTL_TEXTENCODING_UNICODE;
735 0 : bFillEncodingvector = false; // will be filled anyway, don't do the work twice
736 : }
737 : }
738 :
739 : // ascend
740 70 : m_nAscend = pInfo->gfi->fontBBox.ury;
741 :
742 : // descend
743 : // descends have opposite sign of our definition
744 70 : m_nDescend = -pInfo->gfi->fontBBox.lly;
745 :
746 : // fallback to ascender, descender
747 : // interesting: the BBox seems to describe Ascender and Descender better
748 : // as we understand it
749 70 : if( m_nAscend == 0 )
750 0 : m_nAscend = pInfo->gfi->ascender;
751 70 : if( m_nDescend == 0)
752 0 : m_nDescend = -pInfo->gfi->descender;
753 :
754 70 : m_nLeading = m_nAscend + m_nDescend - 1000;
755 :
756 70 : if( m_pMetrics )
757 0 : delete m_pMetrics;
758 70 : m_pMetrics = new PrintFontMetrics;
759 : // mark all pages as queried (or clear if only global font info queiried)
760 70 : memset( m_pMetrics->m_aPages, bOnlyGlobalAttributes ? 0 : 0xff, sizeof( m_pMetrics->m_aPages ) );
761 :
762 : m_aGlobalMetricX.width = m_aGlobalMetricY.width =
763 70 : pInfo->gfi->charwidth ? pInfo->gfi->charwidth : pInfo->gfi->fontBBox.urx;
764 : m_aGlobalMetricX.height = m_aGlobalMetricY.height =
765 70 : pInfo->gfi->capHeight ? pInfo->gfi->capHeight : pInfo->gfi->fontBBox.ury;
766 :
767 70 : m_nXMin = pInfo->gfi->fontBBox.llx;
768 70 : m_nYMin = pInfo->gfi->fontBBox.lly;
769 70 : m_nXMax = pInfo->gfi->fontBBox.urx;
770 70 : m_nYMax = pInfo->gfi->fontBBox.ury;
771 :
772 70 : if( bFillEncodingvector || !bOnlyGlobalAttributes )
773 : {
774 : // fill in character metrics
775 :
776 : // first transform the character codes to unicode
777 : // note: this only works with single byte encodings
778 0 : sal_Unicode* pUnicodes = (sal_Unicode*)alloca( pInfo->numOfChars * sizeof(sal_Unicode));
779 0 : CharMetricInfo* pChar = pInfo->cmi;
780 : int i;
781 :
782 0 : for( i = 0; i < pInfo->numOfChars; i++, pChar++ )
783 : {
784 0 : if( nAdobeEncoding == 4 )
785 : {
786 0 : if( pChar->name )
787 : {
788 0 : pUnicodes[i] = 0;
789 0 : std::list< sal_Unicode > aCodes = rManager.getUnicodeFromAdobeName( pChar->name );
790 0 : for( std::list< sal_Unicode >::const_iterator it = aCodes.begin(); it != aCodes.end(); ++it )
791 : {
792 0 : if( *it != 0 )
793 : {
794 0 : m_aEncodingVector[ *it ] = pChar->code;
795 0 : if( pChar->code == -1 )
796 0 : m_aNonEncoded[ *it ] = pChar->name;
797 0 : if( ! pUnicodes[i] ) // map the first
798 0 : pUnicodes[i] = *it;
799 : }
800 0 : }
801 : }
802 : }
803 0 : else if( pChar->code != -1 )
804 : {
805 0 : if( nAdobeEncoding == 3 && m_aEncoding == RTL_TEXTENCODING_SYMBOL )
806 : {
807 0 : pUnicodes[i] = pChar->code + 0xf000;
808 0 : if( bFillEncodingvector )
809 0 : m_aEncodingVector[ pUnicodes[i] ] = pChar->code;
810 0 : continue;
811 : }
812 :
813 0 : if( m_aEncoding == RTL_TEXTENCODING_UNICODE )
814 : {
815 0 : pUnicodes[i] = (sal_Unicode)pChar->code;
816 0 : continue;
817 : }
818 :
819 0 : rtl::OStringBuffer aTranslate;
820 0 : if( pChar->code & 0xff000000 )
821 0 : aTranslate.append((char)(pChar->code >> 24));
822 0 : if( pChar->code & 0xffff0000 )
823 0 : aTranslate.append((char)((pChar->code & 0x00ff0000) >> 16));
824 0 : if( pChar->code & 0xffffff00 )
825 0 : aTranslate.append((char)((pChar->code & 0x0000ff00) >> 8 ));
826 0 : aTranslate.append((char)(pChar->code & 0xff));
827 0 : rtl::OUString aUni(rtl::OStringToOUString(aTranslate.makeStringAndClear(), m_aEncoding));
828 0 : pUnicodes[i] = aUni.toChar();
829 : }
830 : else
831 0 : pUnicodes[i] = 0;
832 : }
833 :
834 : // now fill in the character metrics
835 : // parseAFM.cxx effectively only supports direction 0 (horizontal)
836 0 : pChar = pInfo->cmi;
837 0 : CharacterMetric aMetric;
838 0 : for( i = 0; i < pInfo->numOfChars; i++, pChar++ )
839 : {
840 0 : if( pChar->code == -1 && ! pChar->name )
841 0 : continue;
842 :
843 0 : if( bFillEncodingvector && pChar->name )
844 : {
845 0 : std::list< sal_Unicode > aCodes = rManager.getUnicodeFromAdobeName( pChar->name );
846 0 : for( std::list< sal_Unicode >::const_iterator it = aCodes.begin(); it != aCodes.end(); ++it )
847 : {
848 0 : if( *it != 0 )
849 : {
850 0 : m_aEncodingVector[ *it ] = pChar->code;
851 0 : if( pChar->code == -1 )
852 0 : m_aNonEncoded[ *it ] = pChar->name;
853 : }
854 0 : }
855 : }
856 :
857 0 : aMetric.width = pChar->wx ? pChar->wx : pChar->charBBox.urx;
858 0 : aMetric.height = pChar->wy ? pChar->wy : pChar->charBBox.ury - pChar->charBBox.lly;
859 0 : if( aMetric.width == 0 && aMetric.height == 0 )
860 : // guess something for e.g. space
861 0 : aMetric.width = m_aGlobalMetricX.width/4;
862 :
863 0 : if( ( nAdobeEncoding == 0 ) ||
864 : ( ( nAdobeEncoding == 3 ) && ( m_aEncoding != RTL_TEXTENCODING_SYMBOL ) ) )
865 : {
866 0 : if( pChar->code != -1 )
867 : {
868 0 : m_pMetrics->m_aMetrics[ pUnicodes[i] ] = aMetric;
869 0 : if( bFillEncodingvector )
870 0 : m_aEncodingVector[ pUnicodes[i] ] = pChar->code;
871 : }
872 0 : else if( pChar->name )
873 : {
874 0 : std::list< sal_Unicode > aCodes = rManager.getUnicodeFromAdobeName( pChar->name );
875 0 : for( std::list< sal_Unicode >::const_iterator it = aCodes.begin(); it != aCodes.end(); ++it )
876 : {
877 0 : if( *it != 0 )
878 0 : m_pMetrics->m_aMetrics[ *it ] = aMetric;
879 0 : }
880 0 : }
881 : }
882 0 : else if( nAdobeEncoding == 1 || nAdobeEncoding == 2 || nAdobeEncoding == 4)
883 : {
884 0 : if( pChar->name )
885 : {
886 0 : std::list< sal_Unicode > aCodes = rManager.getUnicodeFromAdobeName( pChar->name );
887 0 : for( std::list< sal_Unicode >::const_iterator it = aCodes.begin(); it != aCodes.end(); ++it )
888 : {
889 0 : if( *it != 0 )
890 0 : m_pMetrics->m_aMetrics[ *it ] = aMetric;
891 0 : }
892 : }
893 0 : else if( pChar->code != -1 )
894 : {
895 : ::std::pair< ::boost::unordered_multimap< sal_uInt8, sal_Unicode >::const_iterator,
896 : ::boost::unordered_multimap< sal_uInt8, sal_Unicode >::const_iterator >
897 0 : aCodes = rManager.getUnicodeFromAdobeCode( pChar->code );
898 0 : while( aCodes.first != aCodes.second )
899 : {
900 0 : if( (*aCodes.first).second != 0 )
901 : {
902 0 : m_pMetrics->m_aMetrics[ (*aCodes.first).second ] = aMetric;
903 0 : if( bFillEncodingvector )
904 0 : m_aEncodingVector[ (*aCodes.first).second ] = pChar->code;
905 : }
906 0 : ++aCodes.first;
907 : }
908 0 : }
909 : }
910 0 : else if( nAdobeEncoding == 3 )
911 : {
912 0 : if( pChar->code != -1 )
913 : {
914 0 : sal_Unicode code = 0xf000 + pChar->code;
915 0 : m_pMetrics->m_aMetrics[ code ] = aMetric;
916 : // maybe should try to find the name in the convtabs ?
917 0 : if( bFillEncodingvector )
918 0 : m_aEncodingVector[ code ] = pChar->code;
919 : }
920 : }
921 : }
922 :
923 0 : m_pMetrics->m_aXKernPairs.clear();
924 0 : m_pMetrics->m_aYKernPairs.clear();
925 :
926 : // now fill in the kern pairs
927 : // parseAFM.cxx effectively only supports direction 0 (horizontal)
928 0 : PairKernData* pKern = pInfo->pkd;
929 0 : KernPair aPair;
930 0 : for( i = 0; i < pInfo->numOfPairs; i++, pKern++ )
931 : {
932 : // #i37703# broken kern table
933 0 : if( ! pKern->name1 || ! pKern->name2 )
934 0 : continue;
935 :
936 0 : aPair.first = 0;
937 0 : aPair.second = 0;
938 : // currently we have to find the adobe character names
939 : // in the already parsed character metrics to find
940 : // the corresponding UCS2 code which is a bit dangerous
941 : // since the character names are not required
942 : // in the metric descriptions
943 0 : pChar = pInfo->cmi;
944 0 : for( int j = 0;
945 : j < pInfo->numOfChars && ( aPair.first == 0 || aPair.second == 0 );
946 : j++, pChar++ )
947 : {
948 0 : if( pChar->code != -1 )
949 : {
950 0 : if( ! strcmp( pKern->name1, pChar->name ? pChar->name : "" ) )
951 0 : aPair.first = pUnicodes[ j ];
952 0 : if( ! strcmp( pKern->name2, pChar->name ? pChar->name : "" ) )
953 0 : aPair.second = pUnicodes[ j ];
954 : }
955 : }
956 0 : if( aPair.first && aPair.second )
957 : {
958 0 : aPair.kern_x = pKern->xamt;
959 0 : aPair.kern_y = pKern->yamt;
960 0 : m_pMetrics->m_aXKernPairs.push_back( aPair );
961 : }
962 : }
963 0 : m_pMetrics->m_bKernPairsQueried = true;
964 : }
965 :
966 70 : freeFontInfo( pInfo );
967 70 : return true;
968 : }
969 :
970 : /*
971 : * one instance only
972 : */
973 4118 : PrintFontManager& PrintFontManager::get()
974 : {
975 : static PrintFontManager* pManager = NULL;
976 4118 : if( ! pManager )
977 : {
978 20 : static PrintFontManager theManager;
979 20 : pManager = &theManager;
980 20 : pManager->initialize();
981 : }
982 4118 : return *pManager;
983 : }
984 :
985 : // -------------------------------------------------------------------------
986 :
987 : /*
988 : * the PrintFontManager
989 : */
990 :
991 20 : PrintFontManager::PrintFontManager()
992 : : m_nNextFontID( 1 )
993 0 : , m_pAtoms( new MultiAtomProvider() )
994 : , m_nNextDirAtom( 1 )
995 20 : , m_pFontCache( NULL )
996 : {
997 21040 : for( unsigned int i = 0; i < SAL_N_ELEMENTS( aAdobeCodes ); i++ )
998 : {
999 21020 : m_aUnicodeToAdobename.insert( ::boost::unordered_multimap< sal_Unicode, ::rtl::OString >::value_type( aAdobeCodes[i].aUnicode, aAdobeCodes[i].pAdobename ) );
1000 21020 : m_aAdobenameToUnicode.insert( ::boost::unordered_multimap< ::rtl::OString, sal_Unicode, ::rtl::OStringHash >::value_type( aAdobeCodes[i].pAdobename, aAdobeCodes[i].aUnicode ) );
1001 21020 : if( aAdobeCodes[i].aAdobeStandardCode )
1002 : {
1003 3020 : m_aUnicodeToAdobecode.insert( ::boost::unordered_multimap< sal_Unicode, sal_uInt8 >::value_type( aAdobeCodes[i].aUnicode, aAdobeCodes[i].aAdobeStandardCode ) );
1004 3020 : m_aAdobecodeToUnicode.insert( ::boost::unordered_multimap< sal_uInt8, sal_Unicode >::value_type( aAdobeCodes[i].aAdobeStandardCode, aAdobeCodes[i].aUnicode ) );
1005 : }
1006 : }
1007 :
1008 20 : m_aFontInstallerTimer.SetTimeoutHdl(LINK(this, PrintFontManager, autoInstallFontLangSupport));
1009 20 : m_aFontInstallerTimer.SetTimeout(5000);
1010 20 : }
1011 :
1012 : // -------------------------------------------------------------------------
1013 :
1014 40 : PrintFontManager::~PrintFontManager()
1015 : {
1016 20 : m_aFontInstallerTimer.Stop();
1017 20 : deinitFontconfig();
1018 2300 : for( ::boost::unordered_map< fontID, PrintFont* >::const_iterator it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
1019 2280 : delete (*it).second;
1020 20 : delete m_pAtoms;
1021 20 : if( m_pFontCache )
1022 20 : delete m_pFontCache;
1023 20 : }
1024 :
1025 : // -------------------------------------------------------------------------
1026 :
1027 451 : OString PrintFontManager::getDirectory( int nAtom ) const
1028 : {
1029 451 : ::boost::unordered_map< int, OString >::const_iterator it( m_aAtomToDir.find( nAtom ) );
1030 451 : return it != m_aAtomToDir.end() ? it->second : OString();
1031 : }
1032 :
1033 : // -------------------------------------------------------------------------
1034 :
1035 6874 : int PrintFontManager::getDirectoryAtom( const OString& rDirectory, bool bCreate )
1036 : {
1037 6874 : int nAtom = 0;
1038 : ::boost::unordered_map< OString, int, OStringHash >::const_iterator it
1039 6874 : ( m_aDirToAtom.find( rDirectory ) );
1040 6874 : if( it != m_aDirToAtom.end() )
1041 6215 : nAtom = it->second;
1042 659 : else if( bCreate )
1043 : {
1044 638 : nAtom = m_nNextDirAtom++;
1045 638 : m_aDirToAtom[ rDirectory ] = nAtom;
1046 638 : m_aAtomToDir[ nAtom ] = rDirectory;
1047 : }
1048 6874 : return nAtom;
1049 : }
1050 :
1051 : // -------------------------------------------------------------------------
1052 :
1053 0 : std::vector<fontID> PrintFontManager::addFontFile( const ::rtl::OString& rFileName )
1054 : {
1055 0 : rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
1056 0 : INetURLObject aPath( OStringToOUString( rFileName, aEncoding ), INET_PROT_FILE, INetURLObject::ENCODE_ALL );
1057 0 : OString aName( OUStringToOString( aPath.GetName(), aEncoding ) );
1058 0 : OString aDir( OUStringToOString( aPath.GetPath(), aEncoding ) );
1059 :
1060 0 : int nDirID = getDirectoryAtom( aDir, true );
1061 0 : std::vector<fontID> aFontIds = findFontFileIDs( nDirID, aName );
1062 0 : if( aFontIds.empty() )
1063 : {
1064 0 : ::std::list< PrintFont* > aNewFonts;
1065 0 : if( analyzeFontFile( nDirID, aName, aNewFonts ) )
1066 : {
1067 0 : for( ::std::list< PrintFont* >::iterator it = aNewFonts.begin();
1068 0 : it != aNewFonts.end(); ++it )
1069 : {
1070 0 : fontID nFontId = m_nNextFontID++;
1071 0 : m_aFonts[nFontId] = *it;
1072 0 : m_aFontFileToFontID[ aName ].insert( nFontId );
1073 0 : m_pFontCache->updateFontCacheEntry( *it, true );
1074 0 : aFontIds.push_back(nFontId);
1075 : }
1076 0 : }
1077 : }
1078 0 : return aFontIds;
1079 : }
1080 :
1081 : enum fontFormat
1082 : {
1083 : UNKNOWN, TRUETYPE, CFF, TYPE1, AFM
1084 : };
1085 :
1086 298 : bool PrintFontManager::analyzeFontFile( int nDirID, const OString& rFontFile, ::std::list< PrintFontManager::PrintFont* >& rNewFonts, const char *pFormat ) const
1087 : {
1088 298 : rNewFonts.clear();
1089 :
1090 298 : OString aDir( getDirectory( nDirID ) );
1091 :
1092 298 : OString aFullPath( aDir );
1093 298 : aFullPath += "/";
1094 298 : aFullPath += rFontFile;
1095 :
1096 : // #i1872# reject unreadable files
1097 298 : if( access( aFullPath.getStr(), R_OK ) )
1098 0 : return false;
1099 :
1100 298 : fontFormat eFormat = UNKNOWN;
1101 298 : if (pFormat)
1102 : {
1103 298 : if (!strcmp(pFormat, "TrueType"))
1104 136 : eFormat = TRUETYPE;
1105 162 : else if (!strcmp(pFormat, "CFF"))
1106 12 : eFormat = CFF;
1107 150 : else if (!strcmp(pFormat, "Type 1"))
1108 150 : eFormat = TYPE1;
1109 : }
1110 298 : if (eFormat == UNKNOWN)
1111 : {
1112 0 : rtl::OString aExt( rFontFile.copy( rFontFile.lastIndexOf( '.' )+1 ) );
1113 0 : if( aExt.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("pfb")) || aExt.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("pfa")) )
1114 0 : eFormat = TYPE1;
1115 0 : else if( aExt.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("afm")))
1116 0 : eFormat = AFM;
1117 0 : else if( aExt.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("ttf"))
1118 0 : || aExt.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("ttc"))
1119 0 : || aExt.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("tte")) ) // #i33947# for Gaiji support
1120 0 : eFormat = TRUETYPE;
1121 0 : else if( aExt.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("otf")) ) // check for TTF- and PS-OpenType too
1122 0 : eFormat = CFF;
1123 : }
1124 :
1125 298 : if (eFormat == TYPE1)
1126 : {
1127 : // check for corresponding afm metric
1128 : // first look for an adjacent file
1129 : static const char* pSuffix[] = { ".afm", ".AFM" };
1130 :
1131 310 : for( unsigned int i = 0; i < SAL_N_ELEMENTS(pSuffix); i++ )
1132 : {
1133 : rtl::OString aName = rtl::OStringBuffer(
1134 230 : rFontFile.copy(0, rFontFile.getLength() - 4)).
1135 460 : append(pSuffix[i]).makeStringAndClear();
1136 :
1137 230 : rtl::OStringBuffer aFilePath(aDir);
1138 230 : aFilePath.append('/').append(aName);
1139 :
1140 230 : rtl::OString aAfmFile;
1141 230 : if( access( aFilePath.makeStringAndClear().getStr(), R_OK ) )
1142 : {
1143 : // try in subdirectory afm instead
1144 160 : aFilePath.append(aDir).append(RTL_CONSTASCII_STRINGPARAM("/afm/")).append(aName);
1145 :
1146 160 : if (!access(aFilePath.getStr(), R_OK))
1147 0 : aAfmFile = rtl::OString(RTL_CONSTASCII_STRINGPARAM("afm/")) + aName;
1148 : }
1149 : else
1150 70 : aAfmFile = aName;
1151 :
1152 230 : if( !aAfmFile.isEmpty() )
1153 : {
1154 70 : Type1FontFile* pFont = new Type1FontFile();
1155 70 : pFont->m_nDirectory = nDirID;
1156 :
1157 70 : pFont->m_aFontFile = rFontFile;
1158 70 : pFont->m_aMetricFile = aAfmFile;
1159 :
1160 70 : if( ! pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, true ) )
1161 : {
1162 0 : delete pFont;
1163 0 : pFont = NULL;
1164 : }
1165 70 : if( pFont )
1166 70 : rNewFonts.push_back( pFont );
1167 : break;
1168 : }
1169 230 : }
1170 : }
1171 148 : else if (eFormat == AFM)
1172 : {
1173 0 : rtl::OStringBuffer aFilePath(aDir);
1174 0 : aFilePath.append('/').append(rFontFile);
1175 0 : BuiltinFont* pFont = new BuiltinFont();
1176 0 : pFont->m_nDirectory = nDirID;
1177 0 : pFont->m_aMetricFile = rFontFile;
1178 0 : if( pFont->readAfmMetrics( aFilePath.makeStringAndClear(), m_pAtoms,
1179 0 : false, true ) )
1180 : {
1181 0 : rNewFonts.push_back( pFont );
1182 : }
1183 : else
1184 0 : delete pFont;
1185 : }
1186 148 : else if (eFormat == TRUETYPE || eFormat == CFF)
1187 : {
1188 : // get number of ttc entries
1189 148 : int nLength = CountTTCFonts( aFullPath.getStr() );
1190 148 : if( nLength )
1191 : {
1192 : #if OSL_DEBUG_LEVEL > 1
1193 : fprintf( stderr, "ttc: %s contains %d fonts\n", aFullPath.getStr(), nLength );
1194 : #endif
1195 18 : for( int i = 0; i < nLength; i++ )
1196 : {
1197 14 : TrueTypeFontFile* pFont = new TrueTypeFontFile();
1198 14 : pFont->m_nDirectory = nDirID;
1199 14 : pFont->m_aFontFile = rFontFile;
1200 14 : pFont->m_nCollectionEntry = i;
1201 14 : if( ! analyzeTrueTypeFile( pFont ) )
1202 : {
1203 0 : delete pFont;
1204 0 : pFont = NULL;
1205 : }
1206 : else
1207 14 : rNewFonts.push_back( pFont );
1208 : }
1209 : }
1210 : else
1211 : {
1212 144 : TrueTypeFontFile* pFont = new TrueTypeFontFile();
1213 144 : pFont->m_nDirectory = nDirID;
1214 144 : pFont->m_aFontFile = rFontFile;
1215 144 : pFont->m_nCollectionEntry = 0;
1216 :
1217 : // need to read the font anyway to get aliases inside the font file
1218 144 : if( ! analyzeTrueTypeFile( pFont ) )
1219 : {
1220 0 : delete pFont;
1221 0 : pFont = NULL;
1222 : }
1223 : else
1224 144 : rNewFonts.push_back( pFont );
1225 : }
1226 : }
1227 298 : return ! rNewFonts.empty();
1228 : }
1229 :
1230 : // -------------------------------------------------------------------------
1231 :
1232 0 : fontID PrintFontManager::findFontBuiltinID( int nPSNameAtom ) const
1233 : {
1234 0 : fontID nID = 0;
1235 0 : ::boost::unordered_map< fontID, PrintFont* >::const_iterator it;
1236 0 : for( it = m_aFonts.begin(); nID == 0 && it != m_aFonts.end(); ++it )
1237 : {
1238 0 : if( it->second->m_eType == fonttype::Builtin &&
1239 0 : it->second->m_nPSName == nPSNameAtom )
1240 0 : nID = it->first;
1241 : }
1242 0 : return nID;
1243 : }
1244 :
1245 : // -------------------------------------------------------------------------
1246 :
1247 3852 : fontID PrintFontManager::findFontFileID( int nDirID, const OString& rFontFile, int nFaceIndex ) const
1248 : {
1249 3852 : fontID nID = 0;
1250 :
1251 3852 : ::boost::unordered_map< OString, ::std::set< fontID >, OStringHash >::const_iterator set_it = m_aFontFileToFontID.find( rFontFile );
1252 3852 : if( set_it == m_aFontFileToFontID.end() )
1253 0 : return nID;
1254 :
1255 8448 : for( ::std::set< fontID >::const_iterator font_it = set_it->second.begin(); font_it != set_it->second.end() && ! nID; ++font_it )
1256 : {
1257 4596 : ::boost::unordered_map< fontID, PrintFont* >::const_iterator it = m_aFonts.find( *font_it );
1258 4596 : if( it == m_aFonts.end() )
1259 0 : continue;
1260 4596 : switch( it->second->m_eType )
1261 : {
1262 : case fonttype::Type1:
1263 : {
1264 6 : Type1FontFile* const pFont = static_cast< Type1FontFile* const >((*it).second);
1265 12 : if( pFont->m_nDirectory == nDirID &&
1266 6 : pFont->m_aFontFile == rFontFile )
1267 6 : nID = it->first;
1268 : }
1269 6 : break;
1270 : case fonttype::TrueType:
1271 : {
1272 4590 : TrueTypeFontFile* const pFont = static_cast< TrueTypeFontFile* const >((*it).second);
1273 9180 : if( pFont->m_nDirectory == nDirID &&
1274 4590 : pFont->m_aFontFile == rFontFile && pFont->m_nCollectionEntry == nFaceIndex )
1275 3846 : nID = it->first;
1276 : }
1277 4590 : break;
1278 : case fonttype::Builtin:
1279 0 : if( static_cast<const BuiltinFont*>((*it).second)->m_nDirectory == nDirID &&
1280 0 : static_cast<const BuiltinFont*>((*it).second)->m_aMetricFile == rFontFile )
1281 0 : nID = it->first;
1282 0 : break;
1283 : default:
1284 0 : break;
1285 : }
1286 : }
1287 :
1288 3852 : return nID;
1289 : }
1290 :
1291 0 : std::vector<fontID> PrintFontManager::findFontFileIDs( int nDirID, const OString& rFontFile ) const
1292 : {
1293 0 : std::vector<fontID> aIds;
1294 :
1295 0 : ::boost::unordered_map< OString, ::std::set< fontID >, OStringHash >::const_iterator set_it = m_aFontFileToFontID.find( rFontFile );
1296 0 : if( set_it == m_aFontFileToFontID.end() )
1297 : return aIds;
1298 :
1299 0 : for( ::std::set< fontID >::const_iterator font_it = set_it->second.begin(); font_it != set_it->second.end(); ++font_it )
1300 : {
1301 0 : ::boost::unordered_map< fontID, PrintFont* >::const_iterator it = m_aFonts.find( *font_it );
1302 0 : if( it == m_aFonts.end() )
1303 0 : continue;
1304 0 : switch( it->second->m_eType )
1305 : {
1306 : case fonttype::Type1:
1307 : {
1308 0 : Type1FontFile* const pFont = static_cast< Type1FontFile* const >((*it).second);
1309 0 : if( pFont->m_nDirectory == nDirID &&
1310 0 : pFont->m_aFontFile == rFontFile )
1311 0 : aIds.push_back(it->first);
1312 : }
1313 0 : break;
1314 : case fonttype::TrueType:
1315 : {
1316 0 : TrueTypeFontFile* const pFont = static_cast< TrueTypeFontFile* const >((*it).second);
1317 0 : if( pFont->m_nDirectory == nDirID &&
1318 0 : pFont->m_aFontFile == rFontFile )
1319 0 : aIds.push_back(it->first);
1320 : }
1321 0 : break;
1322 : case fonttype::Builtin:
1323 0 : if( static_cast<const BuiltinFont*>((*it).second)->m_nDirectory == nDirID &&
1324 0 : static_cast<const BuiltinFont*>((*it).second)->m_aMetricFile == rFontFile )
1325 0 : aIds.push_back(it->first);
1326 0 : break;
1327 : default:
1328 0 : break;
1329 : }
1330 : }
1331 :
1332 0 : return aIds;
1333 : }
1334 :
1335 : // -------------------------------------------------------------------------
1336 :
1337 366 : OUString PrintFontManager::convertTrueTypeName( void* pRecord ) const
1338 : {
1339 366 : NameRecord* pNameRecord = (NameRecord*)pRecord;
1340 366 : OUString aValue;
1341 366 : if(
1342 : ( pNameRecord->platformID == 3 && ( pNameRecord->encodingID == 0 || pNameRecord->encodingID == 1 ) ) // MS, Unicode
1343 : ||
1344 : ( pNameRecord->platformID == 0 ) // Apple, Unicode
1345 : )
1346 : {
1347 196 : OUStringBuffer aName( pNameRecord->slen/2 );
1348 196 : const sal_uInt8* pNameBuffer = pNameRecord->sptr;
1349 2552 : for(int n = 0; n < pNameRecord->slen/2; n++ )
1350 2356 : aName.append( (sal_Unicode)getUInt16BE( pNameBuffer ) );
1351 196 : aValue = aName.makeStringAndClear();
1352 : }
1353 170 : else if( pNameRecord->platformID == 3 )
1354 : {
1355 0 : if( pNameRecord->encodingID >= 2 && pNameRecord->encodingID <= 6 )
1356 : {
1357 : /*
1358 : * and now for a special kind of madness:
1359 : * some fonts encode their byte value string as BE uint16
1360 : * (leading to stray zero bytes in the string)
1361 : * while others code two bytes as a uint16 and swap to BE
1362 : */
1363 0 : OStringBuffer aName;
1364 0 : const sal_uInt8* pNameBuffer = pNameRecord->sptr;
1365 0 : for(int n = 0; n < pNameRecord->slen/2; n++ )
1366 : {
1367 0 : sal_Unicode aCode = (sal_Unicode)getUInt16BE( pNameBuffer );
1368 0 : sal_Char aChar = aCode >> 8;
1369 0 : if( aChar )
1370 0 : aName.append( aChar );
1371 0 : aChar = aCode & 0x00ff;
1372 0 : if( aChar )
1373 0 : aName.append( aChar );
1374 : }
1375 0 : switch( pNameRecord->encodingID )
1376 : {
1377 : case 2:
1378 0 : aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_932 );
1379 0 : break;
1380 : case 3:
1381 0 : aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_936 );
1382 0 : break;
1383 : case 4:
1384 0 : aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_950 );
1385 0 : break;
1386 : case 5:
1387 0 : aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_949 );
1388 0 : break;
1389 : case 6:
1390 0 : aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_1361 );
1391 0 : break;
1392 0 : }
1393 : }
1394 : }
1395 366 : return aValue;
1396 : }
1397 :
1398 : //fdo#33349.There exists an archaic Berling Antiqua font which has a "Times New
1399 : //Roman" name field in it. We don't want the "Times New Roman" name to take
1400 : //precedence in this case. We take Berling Antiqua as a higher priority name,
1401 : //and erase the "Times New Roman" name
1402 : namespace
1403 : {
1404 202 : bool isBadTNR(const OUString &rName, ::std::set< OUString >& rSet)
1405 : {
1406 202 : bool bRet = false;
1407 202 : if ( rName == "Berling Antiqua" )
1408 : {
1409 0 : ::std::set< OUString >::iterator aEnd = rSet.end();
1410 0 : ::std::set< OUString >::iterator aI = rSet.find(OUString(RTL_CONSTASCII_USTRINGPARAM("Times New Roman")));
1411 0 : if (aI != aEnd)
1412 : {
1413 0 : bRet = true;
1414 0 : rSet.erase(aI);
1415 : }
1416 : }
1417 202 : return bRet;
1418 : }
1419 : }
1420 :
1421 : // -------------------------------------------------------------------------
1422 :
1423 158 : void PrintFontManager::analyzeTrueTypeFamilyName( void* pTTFont, ::std::list< OUString >& rNames ) const
1424 : {
1425 158 : OUString aFamily;
1426 :
1427 158 : rNames.clear();
1428 158 : ::std::set< OUString > aSet;
1429 :
1430 158 : NameRecord* pNameRecords = NULL;
1431 158 : int nNameRecords = GetTTNameRecords( (TrueTypeFont*)pTTFont, &pNameRecords );
1432 158 : if( nNameRecords && pNameRecords )
1433 : {
1434 158 : LanguageType aLang = MsLangId::getSystemLanguage();
1435 158 : int nLastMatch = -1;
1436 4638 : for( int i = 0; i < nNameRecords; i++ )
1437 : {
1438 4480 : if( pNameRecords[i].nameID != 1 || pNameRecords[i].sptr == NULL )
1439 4114 : continue;
1440 366 : int nMatch = -1;
1441 366 : if( pNameRecords[i].platformID == 0 ) // Unicode
1442 0 : nMatch = 4000;
1443 366 : else if( pNameRecords[i].platformID == 3 )
1444 : {
1445 : // this bases on the LanguageType actually being a Win LCID
1446 196 : if( pNameRecords[i].languageID == aLang )
1447 158 : nMatch = 8000;
1448 38 : else if( pNameRecords[i].languageID == LANGUAGE_ENGLISH_US )
1449 0 : nMatch = 2000;
1450 76 : else if( pNameRecords[i].languageID == LANGUAGE_ENGLISH ||
1451 38 : pNameRecords[i].languageID == LANGUAGE_ENGLISH_UK )
1452 0 : nMatch = 1500;
1453 : else
1454 38 : nMatch = 1000;
1455 : }
1456 366 : OUString aName = convertTrueTypeName( pNameRecords + i );
1457 366 : aSet.insert( aName );
1458 366 : if( nMatch > nLastMatch || isBadTNR(aName, aSet) )
1459 : {
1460 164 : nLastMatch = nMatch;
1461 164 : aFamily = aName;
1462 : }
1463 366 : }
1464 158 : DisposeNameRecords( pNameRecords, nNameRecords );
1465 : }
1466 158 : if( !aFamily.isEmpty() )
1467 : {
1468 158 : rNames.push_front( aFamily );
1469 494 : for( ::std::set< OUString >::const_iterator it = aSet.begin(); it != aSet.end(); ++it )
1470 336 : if( *it != aFamily )
1471 178 : rNames.push_back( *it );
1472 : }
1473 158 : return;
1474 : }
1475 :
1476 : // -------------------------------------------------------------------------
1477 :
1478 158 : bool PrintFontManager::analyzeTrueTypeFile( PrintFont* pFont ) const
1479 : {
1480 158 : bool bSuccess = false;
1481 158 : rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
1482 158 : rtl::OString aFile = getFontFile( pFont );
1483 158 : TrueTypeFont* pTTFont = NULL;
1484 :
1485 158 : TrueTypeFontFile* pTTFontFile = static_cast< TrueTypeFontFile* >(pFont);
1486 158 : if( OpenTTFontFile( aFile.getStr(), pTTFontFile->m_nCollectionEntry, &pTTFont ) == SF_OK )
1487 : {
1488 : TTGlobalFontInfo aInfo;
1489 158 : GetTTGlobalFontInfo( pTTFont, & aInfo );
1490 :
1491 158 : ::std::list< OUString > aNames;
1492 158 : analyzeTrueTypeFamilyName( pTTFont, aNames );
1493 :
1494 : // set family name from XLFD if possible
1495 158 : if( ! pFont->m_nFamilyName )
1496 : {
1497 158 : if( aNames.begin() != aNames.end() )
1498 : {
1499 158 : pFont->m_nFamilyName = m_pAtoms->getAtom( ATOM_FAMILYNAME, aNames.front(), sal_True );
1500 158 : aNames.pop_front();
1501 : }
1502 : else
1503 : {
1504 : sal_Int32 dotIndex;
1505 :
1506 : // poor font does not have a family name
1507 : // name it to file name minus the extension
1508 0 : dotIndex = pTTFontFile->m_aFontFile.lastIndexOf( '.' );
1509 0 : if ( dotIndex == -1 )
1510 0 : dotIndex = pTTFontFile->m_aFontFile.getLength();
1511 :
1512 0 : pFont->m_nFamilyName = m_pAtoms->getAtom( ATOM_FAMILYNAME, OStringToOUString( pTTFontFile->m_aFontFile.copy( 0, dotIndex ), aEncoding ), sal_True );
1513 : }
1514 : }
1515 336 : for( ::std::list< OUString >::iterator it = aNames.begin(); it != aNames.end(); ++it )
1516 : {
1517 178 : if( !it->isEmpty() )
1518 : {
1519 20 : int nAlias = m_pAtoms->getAtom( ATOM_FAMILYNAME, *it, sal_True );
1520 20 : if( nAlias != pFont->m_nFamilyName )
1521 : {
1522 20 : std::list< int >::const_iterator al_it;
1523 20 : for( al_it = pFont->m_aAliases.begin(); al_it != pFont->m_aAliases.end() && *al_it != nAlias; ++al_it )
1524 : ;
1525 20 : if( al_it == pFont->m_aAliases.end() )
1526 20 : pFont->m_aAliases.push_back( nAlias );
1527 : }
1528 : }
1529 : }
1530 :
1531 158 : if( aInfo.usubfamily )
1532 0 : pFont->m_aStyleName = OUString( aInfo.usubfamily );
1533 :
1534 : SAL_WARN_IF( !aInfo.psname, "vcl", "No PostScript name in font:" << aFile.getStr() );
1535 :
1536 : rtl::OUString sPSName = aInfo.psname ?
1537 : rtl::OUString(aInfo.psname, rtl_str_getLength(aInfo.psname), aEncoding) :
1538 158 : m_pAtoms->getString(ATOM_FAMILYNAME, pFont->m_nFamilyName); // poor font does not have a postscript name
1539 :
1540 158 : pFont->m_nPSName = m_pAtoms->getAtom( ATOM_PSNAME, sPSName, sal_True );
1541 :
1542 158 : switch( aInfo.weight )
1543 : {
1544 0 : case FW_THIN: pFont->m_eWeight = WEIGHT_THIN; break;
1545 2 : case FW_EXTRALIGHT: pFont->m_eWeight = WEIGHT_ULTRALIGHT; break;
1546 8 : case FW_LIGHT: pFont->m_eWeight = WEIGHT_LIGHT; break;
1547 10 : case FW_MEDIUM: pFont->m_eWeight = WEIGHT_MEDIUM; break;
1548 2 : case FW_SEMIBOLD: pFont->m_eWeight = WEIGHT_SEMIBOLD; break;
1549 52 : case FW_BOLD: pFont->m_eWeight = WEIGHT_BOLD; break;
1550 0 : case FW_EXTRABOLD: pFont->m_eWeight = WEIGHT_ULTRABOLD; break;
1551 0 : case FW_BLACK: pFont->m_eWeight = WEIGHT_BLACK; break;
1552 :
1553 : case FW_NORMAL:
1554 84 : default: pFont->m_eWeight = WEIGHT_NORMAL; break;
1555 : }
1556 :
1557 158 : switch( aInfo.width )
1558 : {
1559 0 : case FWIDTH_ULTRA_CONDENSED: pFont->m_eWidth = WIDTH_ULTRA_CONDENSED; break;
1560 0 : case FWIDTH_EXTRA_CONDENSED: pFont->m_eWidth = WIDTH_EXTRA_CONDENSED; break;
1561 4 : case FWIDTH_CONDENSED: pFont->m_eWidth = WIDTH_CONDENSED; break;
1562 16 : case FWIDTH_SEMI_CONDENSED: pFont->m_eWidth = WIDTH_SEMI_CONDENSED; break;
1563 0 : case FWIDTH_SEMI_EXPANDED: pFont->m_eWidth = WIDTH_SEMI_EXPANDED; break;
1564 0 : case FWIDTH_EXPANDED: pFont->m_eWidth = WIDTH_EXPANDED; break;
1565 0 : case FWIDTH_EXTRA_EXPANDED: pFont->m_eWidth = WIDTH_EXTRA_EXPANDED; break;
1566 0 : case FWIDTH_ULTRA_EXPANDED: pFont->m_eWidth = WIDTH_ULTRA_EXPANDED; break;
1567 :
1568 : case FWIDTH_NORMAL:
1569 138 : default: pFont->m_eWidth = WIDTH_NORMAL; break;
1570 : }
1571 :
1572 158 : pFont->m_ePitch = aInfo.pitch ? PITCH_FIXED : PITCH_VARIABLE;
1573 158 : pFont->m_eItalic = aInfo.italicAngle == 0 ? ITALIC_NONE : ( aInfo.italicAngle < 0 ? ITALIC_NORMAL : ITALIC_OBLIQUE );
1574 : // #104264# there are fonts that set italic angle 0 although they are
1575 : // italic; use macstyle bit here
1576 158 : if( aInfo.italicAngle == 0 && (aInfo.macStyle & 2) )
1577 0 : pFont->m_eItalic = ITALIC_NORMAL;
1578 :
1579 158 : pFont->m_aEncoding = aInfo.symbolEncoded ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UCS2;
1580 :
1581 158 : pFont->m_aGlobalMetricY.width = pFont->m_aGlobalMetricX.width = aInfo.xMax - aInfo.xMin;
1582 158 : pFont->m_aGlobalMetricY.height = pFont->m_aGlobalMetricX.height = aInfo.yMax - aInfo.yMin;
1583 :
1584 158 : if( aInfo.winAscent && aInfo.winDescent )
1585 : {
1586 158 : pFont->m_nAscend = aInfo.winAscent;
1587 158 : pFont->m_nDescend = aInfo.winDescent;
1588 158 : pFont->m_nLeading = pFont->m_nAscend + pFont->m_nDescend - 1000;
1589 : }
1590 0 : else if( aInfo.typoAscender && aInfo.typoDescender )
1591 : {
1592 0 : pFont->m_nLeading = aInfo.typoLineGap;
1593 0 : pFont->m_nAscend = aInfo.typoAscender;
1594 0 : pFont->m_nDescend = -aInfo.typoDescender;
1595 : }
1596 : else
1597 : {
1598 0 : pFont->m_nLeading = aInfo.linegap;
1599 0 : pFont->m_nAscend = aInfo.ascender;
1600 0 : pFont->m_nDescend = -aInfo.descender;
1601 : }
1602 :
1603 : // last try: font bounding box
1604 158 : if( pFont->m_nAscend == 0 )
1605 0 : pFont->m_nAscend = aInfo.yMax;
1606 158 : if( pFont->m_nDescend == 0 )
1607 0 : pFont->m_nDescend = -aInfo.yMin;
1608 158 : if( pFont->m_nLeading == 0 )
1609 0 : pFont->m_nLeading = 15 * (pFont->m_nAscend+pFont->m_nDescend) / 100;
1610 :
1611 158 : if( pFont->m_nAscend )
1612 158 : pFont->m_aGlobalMetricX.height = pFont->m_aGlobalMetricY.height = pFont->m_nAscend + pFont->m_nDescend;
1613 :
1614 : // get bounding box
1615 158 : pFont->m_nXMin = aInfo.xMin;
1616 158 : pFont->m_nYMin = aInfo.yMin;
1617 158 : pFont->m_nXMax = aInfo.xMax;
1618 158 : pFont->m_nYMax = aInfo.yMax;
1619 :
1620 : // get type flags
1621 158 : pTTFontFile->m_nTypeFlags = (unsigned int)aInfo.typeFlags;
1622 :
1623 : // get vertical substitutions flag
1624 158 : pFont->m_bHaveVerticalSubstitutedGlyphs = DoesVerticalSubstitution( pTTFont, 1 );
1625 :
1626 158 : CloseTTFont( pTTFont );
1627 158 : bSuccess = true;
1628 : }
1629 : #if OSL_DEBUG_LEVEL > 1
1630 : else
1631 : fprintf( stderr, "could not OpenTTFont \"%s\"\n", aFile.getStr() );
1632 : #endif
1633 :
1634 158 : return bSuccess;
1635 : }
1636 :
1637 20 : static bool AreFCSubstitutionsEnabled()
1638 : {
1639 20 : return (SalGenericInstance::FetchFontSubstitutionFlags() & 3) == 0;
1640 : }
1641 :
1642 20 : void PrintFontManager::initialize()
1643 : {
1644 : #ifdef CALLGRIND_COMPILE
1645 : CALLGRIND_TOGGLE_COLLECT();
1646 : CALLGRIND_ZERO_STATS();
1647 : #endif
1648 :
1649 : long aDirEntBuffer[ (sizeof(struct dirent)+_PC_NAME_MAX)+1 ];
1650 :
1651 20 : if( ! m_pFontCache )
1652 : {
1653 : #if OSL_DEBUG_LEVEL > 1
1654 : fprintf( stderr, "creating font cache ... " );
1655 : clock_t aStart;
1656 : struct tms tms;
1657 : aStart = times( &tms );
1658 : #endif
1659 20 : m_pFontCache = new FontCache();
1660 : #if OSL_DEBUG_LEVEL > 1
1661 : clock_t aStop = times( &tms );
1662 : fprintf( stderr, "done in %lf s\n", (double)(aStop - aStart)/(double)sysconf( _SC_CLK_TCK ) );
1663 : #endif
1664 : }
1665 :
1666 : // initialize can be called more than once, e.g.
1667 : // gtk-fontconfig-timestamp changes to reflect new font installed and
1668 : // PrintFontManager::initialize called again
1669 : {
1670 20 : for( ::boost::unordered_map< fontID, PrintFont* >::const_iterator it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
1671 0 : delete (*it).second;
1672 20 : m_nNextFontID = 1;
1673 20 : m_aFonts.clear();
1674 20 : m_aFontDirectories.clear();
1675 20 : m_aPrivateFontDirectories.clear();
1676 20 : m_aOverrideFonts.clear();
1677 : }
1678 :
1679 : #if OSL_DEBUG_LEVEL > 1
1680 : clock_t aStart;
1681 : clock_t aStep1;
1682 : clock_t aStep2;
1683 : clock_t aStep3;
1684 : int nBuiltinFonts = 0;
1685 : int nCached = 0;
1686 :
1687 : struct tms tms;
1688 :
1689 : aStart = times( &tms );
1690 : #endif
1691 :
1692 : // first try fontconfig
1693 20 : initFontconfig();
1694 :
1695 : // part one - look for downloadable fonts
1696 20 : rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
1697 20 : const ::rtl::OUString &rSalPrivatePath = psp::getFontPath();
1698 :
1699 : // search for the fonts in SAL_PRIVATE_FONTPATH first; those are
1700 : // the fonts installed with the office
1701 20 : if( !rSalPrivatePath.isEmpty() )
1702 : {
1703 20 : OString aPath = rtl::OUStringToOString( rSalPrivatePath, aEncoding );
1704 20 : const bool bAreFCSubstitutionsEnabled = AreFCSubstitutionsEnabled();
1705 20 : sal_Int32 nIndex = 0;
1706 60 : do
1707 : {
1708 60 : OString aToken = aPath.getToken( 0, ';', nIndex );
1709 60 : normPath( aToken );
1710 60 : if ( aToken.isEmpty() )
1711 : {
1712 1 : continue;
1713 : }
1714 : // if registering an app-specific fontdir with fontconfig fails
1715 : // and fontconfig-based substitutions are enabled
1716 : // then trying to use these app-specific fonts doesn't make sense
1717 59 : if( !addFontconfigDir( aToken ) )
1718 0 : if( bAreFCSubstitutionsEnabled )
1719 0 : continue;
1720 59 : m_aFontDirectories.push_back( aToken );
1721 59 : m_aPrivateFontDirectories.push_back( getDirectoryAtom( aToken, true ) );
1722 20 : } while( nIndex >= 0 );
1723 : }
1724 :
1725 : // protect against duplicate paths
1726 20 : boost::unordered_map< OString, int, OStringHash > visited_dirs;
1727 :
1728 : // Don't search directories that fontconfig already did
1729 20 : countFontconfigFonts( visited_dirs );
1730 :
1731 : // search for font files in each path
1732 20 : std::list< OString >::iterator dir_it;
1733 79 : for( dir_it = m_aFontDirectories.begin(); dir_it != m_aFontDirectories.end(); ++dir_it )
1734 : {
1735 59 : OString aPath( *dir_it );
1736 : // see if we were here already
1737 59 : if( visited_dirs.find( aPath ) != visited_dirs.end() )
1738 0 : continue;
1739 59 : visited_dirs[ aPath ] = 1;
1740 :
1741 : // there may be ":unscaled" directories (see XFree86)
1742 : // it should be safe to ignore them since they should not
1743 : // contain any of our recognizeable fonts
1744 :
1745 : // ask the font cache whether it handles this directory
1746 59 : std::list< PrintFont* > aCacheFonts;
1747 59 : if( m_pFontCache->listDirectory( aPath, aCacheFonts ) )
1748 : {
1749 : #if OSL_DEBUG_LEVEL > 1
1750 : fprintf( stderr, "adding cache directory: %s\n", aPath.getStr() );
1751 : #endif
1752 0 : for( ::std::list< PrintFont* >::iterator it = aCacheFonts.begin(); it != aCacheFonts.end(); ++it )
1753 : {
1754 0 : fontID aFont = m_nNextFontID++;
1755 0 : m_aFonts[ aFont ] = *it;
1756 0 : if( (*it)->m_eType == fonttype::Type1 )
1757 0 : m_aFontFileToFontID[ static_cast<Type1FontFile*>(*it)->m_aFontFile ].insert( aFont );
1758 0 : else if( (*it)->m_eType == fonttype::TrueType )
1759 0 : m_aFontFileToFontID[ static_cast<TrueTypeFontFile*>(*it)->m_aFontFile ].insert( aFont );
1760 0 : else if( (*it)->m_eType == fonttype::Builtin )
1761 0 : m_aFontFileToFontID[ static_cast<BuiltinFont*>(*it)->m_aMetricFile ].insert( aFont );
1762 : #if OSL_DEBUG_LEVEL > 1
1763 : if( (*it)->m_eType == fonttype::Builtin )
1764 : nBuiltinFonts++;
1765 : nCached++;
1766 : #if OSL_DEBUG_LEVEL > 2
1767 : fprintf( stderr, "adding cached font %d: %s\n", aFont, getFontFileSysPath( aFont ).getStr() );
1768 : #endif
1769 : #endif
1770 : }
1771 0 : if( ! m_pFontCache->scanAdditionalFiles( aPath ) )
1772 0 : continue;
1773 : }
1774 :
1775 59 : }
1776 :
1777 : #if OSL_DEBUG_LEVEL > 1
1778 : aStep1 = times( &tms );
1779 : #endif
1780 :
1781 : // part two - look for metrics for builtin printer fonts
1782 20 : std::list< OUString > aMetricDirs;
1783 20 : psp::getPrinterPathList( aMetricDirs, PRINTER_METRICDIR );
1784 :
1785 59 : for( std::list< OUString >::const_iterator met_dir_it = aMetricDirs.begin(); met_dir_it != aMetricDirs.end(); ++met_dir_it )
1786 : {
1787 39 : OString aDir = OUStringToOString( *met_dir_it, aEncoding );
1788 :
1789 : // ask the font cache whether it handles this directory
1790 39 : std::list< PrintFont* > aCacheFonts;
1791 :
1792 39 : if( m_pFontCache->listDirectory( aDir, aCacheFonts ) )
1793 : {
1794 : #if OSL_DEBUG_LEVEL > 1
1795 : fprintf( stderr, "adding cache directory: %s\n", aDir.getStr() );
1796 : #endif
1797 18 : for( ::std::list< PrintFont* >::iterator it = aCacheFonts.begin(); it != aCacheFonts.end(); ++it )
1798 : {
1799 0 : fontID aFont = m_nNextFontID++;
1800 0 : m_aFonts[ aFont ] = *it;
1801 0 : if( (*it)->m_eType == fonttype::Type1 )
1802 0 : m_aFontFileToFontID[ static_cast<Type1FontFile*>(*it)->m_aFontFile ].insert( aFont );
1803 0 : else if( (*it)->m_eType == fonttype::TrueType )
1804 0 : m_aFontFileToFontID[ static_cast<TrueTypeFontFile*>(*it)->m_aFontFile ].insert( aFont );
1805 0 : else if( (*it)->m_eType == fonttype::Builtin )
1806 0 : m_aFontFileToFontID[ static_cast<BuiltinFont*>(*it)->m_aMetricFile ].insert( aFont );
1807 : #if OSL_DEBUG_LEVEL > 1
1808 : if( (*it)->m_eType == fonttype::Builtin )
1809 : nBuiltinFonts++;
1810 : nCached++;
1811 : #if OSL_DEBUG_LEVEL > 2
1812 : fprintf( stderr, "adding cached font %d: from %s\n", aFont,
1813 : getFontFileSysPath( aFont ).getStr() );
1814 : #endif
1815 : #endif
1816 : }
1817 18 : continue;
1818 : }
1819 :
1820 21 : DIR* pDIR = opendir( aDir.getStr() );
1821 21 : if( pDIR )
1822 : {
1823 1 : struct dirent* pDirEntry = (struct dirent*)aDirEntBuffer;
1824 1 : int nDirID = getDirectoryAtom( aDir, true );
1825 1 : int nDirFonts = 0;
1826 :
1827 5 : while( ! readdir_r( pDIR, (struct dirent*)aDirEntBuffer, &pDirEntry ) && pDirEntry )
1828 : {
1829 3 : rtl::OStringBuffer aFile(aDir);
1830 3 : aFile.append('/').append(pDirEntry->d_name);
1831 : struct stat aStat;
1832 3 : if( ! stat( aFile.getStr(), &aStat )
1833 : && S_ISREG( aStat.st_mode )
1834 : )
1835 : {
1836 1 : OString aFileName( pDirEntry->d_name, strlen( pDirEntry->d_name ) );
1837 1 : OString aExt( aFileName.copy( aFileName.lastIndexOf( '.' )+1 ) );
1838 1 : if( aExt.equalsIgnoreAsciiCase( "afm" ) )
1839 : {
1840 0 : ::std::list< PrintFont* > aNewFonts;
1841 :
1842 0 : analyzeFontFile( nDirID, aFileName, aNewFonts );
1843 0 : for( ::std::list< PrintFont* >::iterator it = aNewFonts.begin(); it != aNewFonts.end(); ++it )
1844 : {
1845 0 : if( findFontBuiltinID( (*it)->m_nPSName ) == 0 )
1846 : {
1847 0 : m_aFontFileToFontID[ aFileName ].insert( m_nNextFontID );
1848 0 : m_aFonts[ m_nNextFontID++ ] = *it;
1849 0 : m_pFontCache->updateFontCacheEntry( *it, false );
1850 : #if OSL_DEBUG_LEVEL > 2
1851 : nBuiltinFonts++;
1852 : #endif
1853 : }
1854 : else
1855 0 : delete *it;
1856 0 : }
1857 1 : }
1858 : }
1859 3 : }
1860 1 : closedir( pDIR );
1861 1 : if( ! nDirFonts )
1862 1 : m_pFontCache->markEmptyDir( nDirID );
1863 : }
1864 39 : }
1865 :
1866 : #if OSL_DEBUG_LEVEL > 1
1867 : aStep2 = times( &tms );
1868 : #endif
1869 :
1870 : // part three - fill in family styles
1871 20 : ::boost::unordered_map< fontID, PrintFont* >::iterator font_it;
1872 2300 : for (font_it = m_aFonts.begin(); font_it != m_aFonts.end(); ++font_it)
1873 : {
1874 : ::boost::unordered_map< int, FontFamily >::const_iterator it =
1875 2280 : m_aFamilyTypes.find( font_it->second->m_nFamilyName );
1876 2280 : if (it != m_aFamilyTypes.end())
1877 1240 : continue;
1878 : const ::rtl::OUString& rFamily =
1879 1040 : m_pAtoms->getString( ATOM_FAMILYNAME, font_it->second->m_nFamilyName);
1880 1040 : FontFamily eType = matchFamilyName( rFamily );
1881 1040 : m_aFamilyTypes[ font_it->second->m_nFamilyName ] = eType;
1882 : }
1883 :
1884 : #if OSL_DEBUG_LEVEL > 1
1885 : aStep3 = times( &tms );
1886 : fprintf( stderr, "PrintFontManager::initialize: collected %" SAL_PRI_SIZET "u fonts (%d builtin, %d cached)\n", m_aFonts.size(), nBuiltinFonts, nCached );
1887 : double fTick = (double)sysconf( _SC_CLK_TCK );
1888 : fprintf( stderr, "Step 1 took %lf seconds\n", (double)(aStep1 - aStart)/fTick );
1889 : fprintf( stderr, "Step 2 took %lf seconds\n", (double)(aStep2 - aStep1)/fTick );
1890 : fprintf( stderr, "Step 3 took %lf seconds\n", (double)(aStep3 - aStep2)/fTick );
1891 : #endif
1892 :
1893 20 : m_pFontCache->flush();
1894 :
1895 : #ifdef CALLGRIND_COMPILE
1896 : CALLGRIND_DUMP_STATS();
1897 : CALLGRIND_TOGGLE_COLLECT();
1898 : #endif
1899 20 : }
1900 :
1901 : // -------------------------------------------------------------------------
1902 : inline bool
1903 0 : equalPitch (FontPitch from, FontPitch to)
1904 : {
1905 0 : return from == to;
1906 : }
1907 :
1908 : inline bool
1909 0 : equalWeight (FontWeight from, FontWeight to)
1910 : {
1911 0 : return from > to ? (from - to) <= 3 : (to - from) <= 3;
1912 : }
1913 :
1914 : inline bool
1915 0 : equalItalic (FontItalic from, FontItalic to)
1916 : {
1917 0 : if ( (from == ITALIC_NORMAL) || (from == ITALIC_OBLIQUE) )
1918 0 : return (to == ITALIC_NORMAL) || (to == ITALIC_OBLIQUE);
1919 0 : return to == from;
1920 : }
1921 : inline bool
1922 0 : equalEncoding (rtl_TextEncoding from, rtl_TextEncoding to)
1923 : {
1924 0 : if ((from == RTL_TEXTENCODING_ISO_8859_1) || (from == RTL_TEXTENCODING_MS_1252))
1925 0 : return (to == RTL_TEXTENCODING_ISO_8859_1) || (to == RTL_TEXTENCODING_MS_1252);
1926 0 : return from == to;
1927 : }
1928 :
1929 : namespace {
1930 0 : struct BuiltinFontIdentifier
1931 : {
1932 : OUString aFamily;
1933 : FontItalic eItalic;
1934 : FontWeight eWeight;
1935 : FontPitch ePitch;
1936 : rtl_TextEncoding aEncoding;
1937 :
1938 0 : BuiltinFontIdentifier( const OUString& rFam,
1939 : FontItalic eIt,
1940 : FontWeight eWg,
1941 : FontPitch ePt,
1942 : rtl_TextEncoding enc ) :
1943 : aFamily( rFam ),
1944 : eItalic( eIt ),
1945 : eWeight( eWg ),
1946 : ePitch( ePt ),
1947 0 : aEncoding( enc )
1948 0 : {}
1949 :
1950 0 : bool operator==( const BuiltinFontIdentifier& rRight ) const
1951 : {
1952 0 : return equalItalic( eItalic, rRight.eItalic ) &&
1953 0 : equalWeight( eWeight, rRight.eWeight ) &&
1954 0 : equalPitch( ePitch, rRight.ePitch ) &&
1955 0 : equalEncoding( aEncoding, rRight.aEncoding ) &&
1956 0 : aFamily.equalsIgnoreAsciiCase( rRight.aFamily );
1957 : }
1958 : };
1959 :
1960 : struct BuiltinFontIdentifierHash
1961 : {
1962 0 : size_t operator()( const BuiltinFontIdentifier& rFont ) const
1963 : {
1964 0 : return rFont.aFamily.hashCode() ^ rFont.eItalic ^ rFont.eWeight ^ rFont.ePitch ^ rFont.aEncoding;
1965 : }
1966 : };
1967 : }
1968 :
1969 23 : void PrintFontManager::getFontList( ::std::list< fontID >& rFontIDs, const PPDParser* pParser, bool bUseOverrideMetrics )
1970 : {
1971 23 : rFontIDs.clear();
1972 23 : boost::unordered_map< fontID, PrintFont* >::const_iterator it;
1973 :
1974 : /*
1975 : * Note: there are two easy steps making this faster:
1976 : * first: insert the printer builtins first, then the not builtins,
1977 : * if they do not match.
1978 : * drawback: this would change the sequence of fonts; this could have
1979 : * subtle, unknown consequences in vcl font matching
1980 : * second: instead of comparing attributes to see whether a softfont
1981 : * is duplicate to a builtin one could simply compare the PSName (which is
1982 : * supposed to be unique), which at this point is just an int.
1983 : * drawback: this could change which fonts are listed; especially TrueType
1984 : * fonts often have a rather dubious PSName, so this could change the
1985 : * font list not so subtle.
1986 : * Until getFontList for a printer becomes a performance issue (which is
1987 : * currently not the case), best stay with the current algorithm.
1988 : */
1989 :
1990 : // fill sets of printer supported fonts
1991 23 : if( pParser )
1992 : {
1993 0 : std::set<int> aBuiltinPSNames;
1994 : boost::unordered_set< BuiltinFontIdentifier,
1995 : BuiltinFontIdentifierHash
1996 0 : > aBuiltinFonts;
1997 :
1998 0 : std::map<int, fontID > aOverridePSNames;
1999 0 : if( bUseOverrideMetrics )
2000 : {
2001 0 : readOverrideMetrics();
2002 0 : for( std::vector<fontID>::const_iterator over = m_aOverrideFonts.begin();
2003 0 : over != m_aOverrideFonts.end(); ++over )
2004 : {
2005 0 : boost::unordered_map<fontID,PrintFont*>::const_iterator font_it = m_aFonts.find( *over );
2006 : DBG_ASSERT( font_it != m_aFonts.end(), "override to nonexistant font" );
2007 0 : if( font_it != m_aFonts.end() )
2008 0 : aOverridePSNames[ font_it->second->m_nPSName ] = *over;
2009 : }
2010 : }
2011 :
2012 0 : int nFonts = pParser->getFonts();
2013 0 : for( int i = 0; i < nFonts; i++ )
2014 0 : aBuiltinPSNames.insert( m_pAtoms->getAtom( ATOM_PSNAME, pParser->getFont( i ) ) );
2015 0 : for( it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
2016 : {
2017 0 : PrintFont* pFont = it->second;
2018 0 : if( it->second->m_eType == fonttype::Builtin &&
2019 0 : aBuiltinPSNames.find( pFont->m_nPSName ) != aBuiltinPSNames.end() )
2020 : {
2021 0 : bool bInsert = true;
2022 0 : if( bUseOverrideMetrics )
2023 : {
2024 : // in override case only use the override fonts, not their counterparts
2025 0 : std::map<int,fontID>::const_iterator over = aOverridePSNames.find( pFont->m_nPSName );
2026 0 : if( over != aOverridePSNames.end() && over->second != it->first )
2027 0 : bInsert = false;
2028 : }
2029 : else
2030 : {
2031 : // do not insert override fonts in non override case
2032 0 : if( std::find( m_aOverrideFonts.begin(), m_aOverrideFonts.end(), it->first ) != m_aOverrideFonts.end() )
2033 0 : bInsert = false;
2034 : }
2035 0 : if( bInsert )
2036 : {
2037 : aBuiltinFonts.insert( BuiltinFontIdentifier(
2038 0 : m_pAtoms->getString( ATOM_FAMILYNAME, pFont->m_nFamilyName ),
2039 : pFont->m_eItalic,
2040 : pFont->m_eWeight,
2041 : pFont->m_ePitch,
2042 : pFont->m_aEncoding
2043 0 : ) );
2044 : }
2045 : }
2046 : }
2047 0 : for( it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
2048 : {
2049 0 : PrintFont* pFont = it->second;
2050 0 : if( it->second->m_eType == fonttype::Builtin )
2051 : {
2052 0 : if( aBuiltinPSNames.find( pFont->m_nPSName ) != aBuiltinPSNames.end() )
2053 : {
2054 0 : bool bInsert = true;
2055 0 : if( bUseOverrideMetrics )
2056 : {
2057 : // in override case only use the override fonts, not their counterparts
2058 0 : std::map<int,fontID>::const_iterator over = aOverridePSNames.find( pFont->m_nPSName );
2059 0 : if( over != aOverridePSNames.end() && over->second != it->first )
2060 0 : bInsert = false;
2061 : }
2062 : else
2063 : {
2064 : // do not insert override fonts in non override case
2065 0 : if( std::find( m_aOverrideFonts.begin(), m_aOverrideFonts.end(), it->first ) != m_aOverrideFonts.end() )
2066 0 : bInsert = false;
2067 : }
2068 0 : if( bInsert )
2069 0 : rFontIDs.push_back( it->first );
2070 : }
2071 : }
2072 0 : else if( aBuiltinFonts.find( BuiltinFontIdentifier(
2073 0 : m_pAtoms->getString( ATOM_FAMILYNAME, pFont->m_nFamilyName ),
2074 : pFont->m_eItalic,
2075 : pFont->m_eWeight,
2076 : pFont->m_ePitch,
2077 : pFont->m_aEncoding
2078 0 : ) ) == aBuiltinFonts.end() )
2079 : {
2080 0 : rFontIDs.push_back( it->first );
2081 : }
2082 0 : }
2083 : }
2084 : else // no specific printer
2085 : {
2086 2645 : for( it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
2087 2622 : rFontIDs.push_back( it->first );
2088 : }
2089 23 : }
2090 :
2091 : // -------------------------------------------------------------------------
2092 :
2093 6474 : void PrintFontManager::fillPrintFontInfo( PrintFont* pFont, FastPrintFontInfo& rInfo ) const
2094 : {
2095 : ::boost::unordered_map< int, FontFamily >::const_iterator style_it =
2096 6474 : m_aFamilyTypes.find( pFont->m_nFamilyName );
2097 6474 : rInfo.m_eType = pFont->m_eType;
2098 6474 : rInfo.m_aFamilyName = m_pAtoms->getString( ATOM_FAMILYNAME, pFont->m_nFamilyName );
2099 6474 : rInfo.m_aStyleName = pFont->m_aStyleName;
2100 6474 : rInfo.m_eFamilyStyle = style_it != m_aFamilyTypes.end() ? style_it->second : FAMILY_DONTKNOW;
2101 6474 : rInfo.m_eItalic = pFont->m_eItalic;
2102 6474 : rInfo.m_eWidth = pFont->m_eWidth;
2103 6474 : rInfo.m_eWeight = pFont->m_eWeight;
2104 6474 : rInfo.m_ePitch = pFont->m_ePitch;
2105 6474 : rInfo.m_aEncoding = pFont->m_aEncoding;
2106 :
2107 6474 : rInfo.m_bEmbeddable = (pFont->m_eType == fonttype::Type1);
2108 6474 : rInfo.m_bSubsettable = (pFont->m_eType == fonttype::TrueType); // TODO: rename to SfntType
2109 :
2110 6474 : rInfo.m_aAliases.clear();
2111 7610 : for( ::std::list< int >::iterator it = pFont->m_aAliases.begin(); it != pFont->m_aAliases.end(); ++it )
2112 1136 : rInfo.m_aAliases.push_back( m_pAtoms->getString( ATOM_FAMILYNAME, *it ) );
2113 6474 : }
2114 :
2115 : // -------------------------------------------------------------------------
2116 :
2117 0 : void PrintFontManager::fillPrintFontInfo( PrintFont* pFont, PrintFontInfo& rInfo ) const
2118 : {
2119 0 : if( ( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 ) ||
2120 0 : ! pFont->m_pMetrics || pFont->m_pMetrics->isEmpty()
2121 : )
2122 : {
2123 : // might be a truetype font not analyzed or type1 without metrics read
2124 0 : if( pFont->m_eType == fonttype::Type1 )
2125 0 : pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, false );
2126 0 : else if( pFont->m_eType == fonttype::TrueType )
2127 0 : analyzeTrueTypeFile( pFont );
2128 : }
2129 :
2130 0 : fillPrintFontInfo( pFont, static_cast< FastPrintFontInfo& >( rInfo ) );
2131 :
2132 0 : rInfo.m_nAscend = pFont->m_nAscend;
2133 0 : rInfo.m_nDescend = pFont->m_nDescend;
2134 0 : rInfo.m_nLeading = pFont->m_nLeading;
2135 0 : rInfo.m_nWidth = pFont->m_aGlobalMetricX.width < pFont->m_aGlobalMetricY.width ? pFont->m_aGlobalMetricY.width : pFont->m_aGlobalMetricX.width;
2136 0 : }
2137 :
2138 : // -------------------------------------------------------------------------
2139 :
2140 0 : void PrintFontManager::getFontListWithFastInfo( ::std::list< FastPrintFontInfo >& rFonts, const PPDParser* pParser, bool bUseOverrideMetrics )
2141 : {
2142 0 : rFonts.clear();
2143 0 : ::std::list< fontID > aFontList;
2144 0 : getFontList( aFontList, pParser, bUseOverrideMetrics );
2145 :
2146 0 : ::std::list< fontID >::iterator it;
2147 0 : for( it = aFontList.begin(); it != aFontList.end(); ++it )
2148 : {
2149 0 : FastPrintFontInfo aInfo;
2150 0 : aInfo.m_nID = *it;
2151 0 : fillPrintFontInfo( getFont( *it ), aInfo );
2152 0 : rFonts.push_back( aInfo );
2153 0 : }
2154 0 : }
2155 :
2156 : // -------------------------------------------------------------------------
2157 :
2158 0 : bool PrintFontManager::getFontInfo( fontID nFontID, PrintFontInfo& rInfo ) const
2159 : {
2160 0 : PrintFont* pFont = getFont( nFontID );
2161 0 : if( pFont )
2162 : {
2163 0 : rInfo.m_nID = nFontID;
2164 0 : fillPrintFontInfo( pFont, rInfo );
2165 : }
2166 0 : return pFont ? true : false;
2167 : }
2168 :
2169 : // -------------------------------------------------------------------------
2170 :
2171 6474 : bool PrintFontManager::getFontFastInfo( fontID nFontID, FastPrintFontInfo& rInfo ) const
2172 : {
2173 6474 : PrintFont* pFont = getFont( nFontID );
2174 6474 : if( pFont )
2175 : {
2176 6474 : rInfo.m_nID = nFontID;
2177 6474 : fillPrintFontInfo( pFont, rInfo );
2178 : }
2179 6474 : return pFont ? true : false;
2180 : }
2181 :
2182 : // -------------------------------------------------------------------------
2183 :
2184 0 : bool PrintFontManager::getFontBoundingBox( fontID nFontID, int& xMin, int& yMin, int& xMax, int& yMax )
2185 : {
2186 0 : bool bSuccess = false;
2187 0 : PrintFont* pFont = getFont( nFontID );
2188 0 : if( pFont )
2189 : {
2190 0 : if( pFont->m_nXMin == 0 && pFont->m_nYMin == 0 && pFont->m_nXMax == 0 && pFont->m_nYMax == 0 )
2191 : {
2192 : // might be a truetype font not analyzed or type1 without metrics read
2193 0 : if( pFont->m_eType == fonttype::Type1 || pFont->m_eType == fonttype::Builtin )
2194 0 : pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, true );
2195 0 : else if( pFont->m_eType == fonttype::TrueType )
2196 0 : analyzeTrueTypeFile( pFont );
2197 : }
2198 0 : bSuccess = true;
2199 0 : xMin = pFont->m_nXMin;
2200 0 : yMin = pFont->m_nYMin;
2201 0 : xMax = pFont->m_nXMax;
2202 0 : yMax = pFont->m_nYMax;
2203 : }
2204 0 : return bSuccess;
2205 : }
2206 :
2207 : // -------------------------------------------------------------------------
2208 :
2209 2622 : int PrintFontManager::getFontFaceNumber( fontID nFontID ) const
2210 : {
2211 2622 : int nRet = 0;
2212 2622 : PrintFont* pFont = getFont( nFontID );
2213 2622 : if( pFont && pFont->m_eType == fonttype::TrueType )
2214 1817 : nRet = static_cast< TrueTypeFontFile* >(pFont)->m_nCollectionEntry;
2215 2622 : if (nRet < 0)
2216 0 : nRet = 0;
2217 2622 : return nRet;
2218 : }
2219 :
2220 : // -------------------------------------------------------------------------
2221 :
2222 :
2223 1040 : FontFamily PrintFontManager::matchFamilyName( const ::rtl::OUString& rFamily ) const
2224 : {
2225 : typedef struct {
2226 : const char* mpName;
2227 : sal_uInt16 mnLength;
2228 : FontFamily meType;
2229 : } family_t;
2230 :
2231 : #define InitializeClass( p, a ) p, sizeof(p) - 1, a
2232 : const family_t pFamilyMatch[] = {
2233 : { InitializeClass( "arial", FAMILY_SWISS ) },
2234 : { InitializeClass( "arioso", FAMILY_SCRIPT ) },
2235 : { InitializeClass( "avant garde", FAMILY_SWISS ) },
2236 : { InitializeClass( "avantgarde", FAMILY_SWISS ) },
2237 : { InitializeClass( "bembo", FAMILY_ROMAN ) },
2238 : { InitializeClass( "bookman", FAMILY_ROMAN ) },
2239 : { InitializeClass( "conga", FAMILY_ROMAN ) },
2240 : { InitializeClass( "courier", FAMILY_MODERN ) },
2241 : { InitializeClass( "curl", FAMILY_SCRIPT ) },
2242 : { InitializeClass( "fixed", FAMILY_MODERN ) },
2243 : { InitializeClass( "gill", FAMILY_SWISS ) },
2244 : { InitializeClass( "helmet", FAMILY_MODERN ) },
2245 : { InitializeClass( "helvetica", FAMILY_SWISS ) },
2246 : { InitializeClass( "international", FAMILY_MODERN ) },
2247 : { InitializeClass( "lucida", FAMILY_SWISS ) },
2248 : { InitializeClass( "new century schoolbook", FAMILY_ROMAN ) },
2249 : { InitializeClass( "palatino", FAMILY_ROMAN ) },
2250 : { InitializeClass( "roman", FAMILY_ROMAN ) },
2251 : { InitializeClass( "sans serif", FAMILY_SWISS ) },
2252 : { InitializeClass( "sansserif", FAMILY_SWISS ) },
2253 : { InitializeClass( "serf", FAMILY_ROMAN ) },
2254 : { InitializeClass( "serif", FAMILY_ROMAN ) },
2255 : { InitializeClass( "times", FAMILY_ROMAN ) },
2256 : { InitializeClass( "utopia", FAMILY_ROMAN ) },
2257 : { InitializeClass( "zapf chancery", FAMILY_SCRIPT ) },
2258 : { InitializeClass( "zapfchancery", FAMILY_SCRIPT ) }
2259 1040 : };
2260 :
2261 1040 : rtl::OString aFamily = rtl::OUStringToOString( rFamily, RTL_TEXTENCODING_ASCII_US );
2262 1040 : sal_uInt32 nLower = 0;
2263 1040 : sal_uInt32 nUpper = SAL_N_ELEMENTS(pFamilyMatch);
2264 :
2265 7160 : while( nLower < nUpper )
2266 : {
2267 5080 : sal_uInt32 nCurrent = (nLower + nUpper) / 2;
2268 5080 : const family_t* pHaystack = pFamilyMatch + nCurrent;
2269 : sal_Int32 nComparison =
2270 : rtl_str_compareIgnoreAsciiCase_WithLength
2271 : (
2272 : aFamily.getStr(), aFamily.getLength(),
2273 : pHaystack->mpName, pHaystack->mnLength
2274 5080 : );
2275 :
2276 5080 : if( nComparison < 0 )
2277 3280 : nUpper = nCurrent;
2278 : else
2279 1800 : if( nComparison > 0 )
2280 1800 : nLower = nCurrent + 1;
2281 : else
2282 0 : return pHaystack->meType;
2283 : }
2284 :
2285 1040 : return FAMILY_DONTKNOW;
2286 : }
2287 :
2288 : // -------------------------------------------------------------------------
2289 :
2290 70 : OString PrintFontManager::getAfmFile( PrintFont* pFont ) const
2291 : {
2292 70 : OString aMetricPath;
2293 70 : if( pFont )
2294 : {
2295 70 : switch( pFont->m_eType )
2296 : {
2297 : case fonttype::Type1:
2298 : {
2299 70 : Type1FontFile* pPSFont = static_cast< Type1FontFile* >(pFont);
2300 70 : aMetricPath = getDirectory( pPSFont->m_nDirectory );
2301 70 : aMetricPath += "/";
2302 70 : aMetricPath += pPSFont->m_aMetricFile;
2303 : }
2304 70 : break;
2305 : case fonttype::Builtin:
2306 : {
2307 0 : BuiltinFont* pBuiltinFont = static_cast< BuiltinFont* >(pFont);
2308 0 : aMetricPath = getDirectory( pBuiltinFont->m_nDirectory );
2309 0 : aMetricPath += "/";
2310 0 : aMetricPath += pBuiltinFont->m_aMetricFile;
2311 : }
2312 0 : break;
2313 0 : default: break;
2314 : }
2315 : }
2316 70 : return aMetricPath;
2317 : }
2318 :
2319 : // -------------------------------------------------------------------------
2320 :
2321 2780 : OString PrintFontManager::getFontFile( PrintFont* pFont ) const
2322 : {
2323 2780 : OString aPath;
2324 :
2325 2780 : if( pFont && pFont->m_eType == fonttype::Type1 )
2326 : {
2327 805 : Type1FontFile* pPSFont = static_cast< Type1FontFile* >(pFont);
2328 805 : ::boost::unordered_map< int, OString >::const_iterator it = m_aAtomToDir.find( pPSFont->m_nDirectory );
2329 805 : aPath = it->second;
2330 805 : aPath += "/";
2331 805 : aPath += pPSFont->m_aFontFile;
2332 : }
2333 1975 : else if( pFont && pFont->m_eType == fonttype::TrueType )
2334 : {
2335 1975 : TrueTypeFontFile* pTTFont = static_cast< TrueTypeFontFile* >(pFont);
2336 1975 : ::boost::unordered_map< int, OString >::const_iterator it = m_aAtomToDir.find( pTTFont->m_nDirectory );
2337 1975 : aPath = it->second;
2338 1975 : aPath += "/";
2339 1975 : aPath += pTTFont->m_aFontFile;
2340 : }
2341 2780 : return aPath;
2342 : }
2343 :
2344 : // -------------------------------------------------------------------------
2345 :
2346 0 : const ::rtl::OUString& PrintFontManager::getPSName( fontID nFontID ) const
2347 : {
2348 0 : PrintFont* pFont = getFont( nFontID );
2349 0 : if( pFont && pFont->m_nPSName == 0 )
2350 : {
2351 0 : if( pFont->m_eType == fonttype::TrueType )
2352 0 : analyzeTrueTypeFile( pFont );
2353 : }
2354 :
2355 0 : return m_pAtoms->getString( ATOM_PSNAME, pFont ? pFont->m_nPSName : INVALID_ATOM );
2356 : }
2357 :
2358 : // -------------------------------------------------------------------------
2359 :
2360 0 : int PrintFontManager::getFontAscend( fontID nFontID ) const
2361 : {
2362 0 : PrintFont* pFont = getFont( nFontID );
2363 0 : if( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
2364 : {
2365 : // might be a truetype font not yet analyzed
2366 0 : if( pFont->m_eType == fonttype::TrueType )
2367 0 : analyzeTrueTypeFile( pFont );
2368 0 : else if( pFont->m_eType == fonttype::Type1 || pFont->m_eType == fonttype::Builtin )
2369 0 : pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, true );
2370 : }
2371 0 : return pFont->m_nAscend;
2372 : }
2373 :
2374 : // -------------------------------------------------------------------------
2375 :
2376 0 : int PrintFontManager::getFontDescend( fontID nFontID ) const
2377 : {
2378 0 : PrintFont* pFont = getFont( nFontID );
2379 0 : if( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
2380 : {
2381 : // might be a truetype font not yet analyzed
2382 0 : if( pFont->m_eType == fonttype::TrueType )
2383 0 : analyzeTrueTypeFile( pFont );
2384 0 : else if( pFont->m_eType == fonttype::Type1 || pFont->m_eType == fonttype::Builtin )
2385 0 : pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, true );
2386 : }
2387 0 : return pFont->m_nDescend;
2388 : }
2389 :
2390 : // -------------------------------------------------------------------------
2391 :
2392 0 : void PrintFontManager::hasVerticalSubstitutions( fontID nFontID,
2393 : const sal_Unicode* pCharacters, int nCharacters, bool* pHasSubst ) const
2394 : {
2395 0 : PrintFont* pFont = getFont( nFontID );
2396 0 : if( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
2397 : {
2398 : // might be a truetype font not yet analyzed
2399 0 : if( pFont->m_eType == fonttype::TrueType )
2400 0 : analyzeTrueTypeFile( pFont );
2401 : }
2402 :
2403 0 : if( ! pFont->m_bHaveVerticalSubstitutedGlyphs )
2404 0 : memset( pHasSubst, 0, sizeof(bool)*nCharacters );
2405 : else
2406 : {
2407 0 : for( int i = 0; i < nCharacters; i++ )
2408 : {
2409 0 : sal_Unicode code = pCharacters[i];
2410 0 : if( ! pFont->m_pMetrics ||
2411 0 : ! ( pFont->m_pMetrics->m_aPages[ code >> 11 ] & ( 1 << ( ( code >> 8 ) & 7 ) ) ) )
2412 0 : pFont->queryMetricPage( code >> 8, m_pAtoms );
2413 0 : ::boost::unordered_map< sal_Unicode, bool >::const_iterator it = pFont->m_pMetrics->m_bVerticalSubstitutions.find( code );
2414 0 : pHasSubst[i] = it != pFont->m_pMetrics->m_bVerticalSubstitutions.end();
2415 : }
2416 : }
2417 0 : }
2418 :
2419 : // -------------------------------------------------------------------------
2420 :
2421 0 : const ::std::list< KernPair >& PrintFontManager::getKernPairs( fontID nFontID, bool bVertical ) const
2422 : {
2423 0 : static ::std::list< KernPair > aEmpty;
2424 :
2425 0 : PrintFont* pFont = getFont( nFontID );
2426 0 : if( ! pFont )
2427 0 : return aEmpty;
2428 :
2429 0 : if( ! pFont->m_pMetrics || ! pFont->m_pMetrics->m_bKernPairsQueried )
2430 0 : pFont->queryMetricPage( 0, m_pAtoms );
2431 0 : if( ! pFont->m_pMetrics || ! pFont->m_pMetrics->m_bKernPairsQueried )
2432 0 : return aEmpty;
2433 0 : return bVertical ? pFont->m_pMetrics->m_aYKernPairs : pFont->m_pMetrics->m_aXKernPairs;
2434 : }
2435 :
2436 : // -------------------------------------------------------------------------
2437 :
2438 0 : bool PrintFontManager::isFontDownloadingAllowed( fontID nFont ) const
2439 : {
2440 0 : static const char* pEnable = getenv( "PSPRINT_ENABLE_TTF_COPYRIGHTAWARENESS" );
2441 0 : bool bRet = true;
2442 :
2443 0 : if( pEnable && *pEnable )
2444 : {
2445 0 : PrintFont* pFont = getFont( nFont );
2446 0 : if( pFont && pFont->m_eType == fonttype::TrueType )
2447 : {
2448 0 : TrueTypeFontFile* pTTFontFile = static_cast<TrueTypeFontFile*>(pFont);
2449 0 : if( pTTFontFile->m_nTypeFlags & TYPEFLAG_INVALID )
2450 : {
2451 0 : TrueTypeFont* pTTFont = NULL;
2452 0 : rtl::OString aFile = getFontFile( pFont );
2453 0 : if( OpenTTFontFile( aFile.getStr(), pTTFontFile->m_nCollectionEntry, &pTTFont ) == SF_OK )
2454 : {
2455 : // get type flags
2456 : TTGlobalFontInfo aInfo;
2457 0 : GetTTGlobalFontInfo( pTTFont, & aInfo );
2458 0 : pTTFontFile->m_nTypeFlags = (unsigned int)aInfo.typeFlags;
2459 0 : CloseTTFont( pTTFont );
2460 0 : }
2461 : }
2462 :
2463 0 : unsigned int nCopyrightFlags = pTTFontFile->m_nTypeFlags & TYPEFLAG_COPYRIGHT_MASK;
2464 :
2465 : // font embedding is allowed if either
2466 : // no restriction at all (bit 1 clear)
2467 : // printing allowed (bit 1 set, bit 2 set )
2468 0 : bRet = ! ( nCopyrightFlags & 0x02 ) || ( nCopyrightFlags & 0x04 );
2469 : }
2470 : }
2471 0 : return bRet;
2472 : }
2473 :
2474 : // -------------------------------------------------------------------------
2475 :
2476 0 : bool PrintFontManager::getMetrics( fontID nFontID, const sal_Unicode* pString, int nLen, CharacterMetric* pArray, bool bVertical ) const
2477 : {
2478 0 : PrintFont* pFont = getFont( nFontID );
2479 0 : if( ! pFont )
2480 0 : return false;
2481 :
2482 0 : if( ( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
2483 0 : || ! pFont->m_pMetrics || pFont->m_pMetrics->isEmpty()
2484 : )
2485 : {
2486 : // might be a font not yet analyzed
2487 0 : if( pFont->m_eType == fonttype::Type1 || pFont->m_eType == fonttype::Builtin )
2488 0 : pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, false );
2489 0 : else if( pFont->m_eType == fonttype::TrueType )
2490 0 : analyzeTrueTypeFile( pFont );
2491 : }
2492 :
2493 0 : for( int i = 0; i < nLen; i++ )
2494 : {
2495 0 : if( ! pFont->m_pMetrics ||
2496 0 : ! ( pFont->m_pMetrics->m_aPages[ pString[i] >> 11 ] & ( 1 << ( ( pString[i] >> 8 ) & 7 ) ) ) )
2497 0 : pFont->queryMetricPage( pString[i] >> 8, m_pAtoms );
2498 0 : pArray[i].width = pArray[i].height = -1;
2499 0 : if( pFont->m_pMetrics )
2500 : {
2501 0 : int effectiveCode = pString[i];
2502 0 : effectiveCode |= bVertical ? 1 << 16 : 0;
2503 : ::boost::unordered_map< int, CharacterMetric >::const_iterator it =
2504 0 : pFont->m_pMetrics->m_aMetrics.find( effectiveCode );
2505 : // if no vertical metrics are available assume rotated horizontal metrics
2506 0 : if( bVertical && (it == pFont->m_pMetrics->m_aMetrics.end()) )
2507 0 : it = pFont->m_pMetrics->m_aMetrics.find( pString[i] );
2508 : // the character metrics are in it->second
2509 0 : if( it != pFont->m_pMetrics->m_aMetrics.end() )
2510 0 : pArray[ i ] = it->second;
2511 : }
2512 : }
2513 :
2514 0 : return true;
2515 : }
2516 :
2517 : // -------------------------------------------------------------------------
2518 :
2519 0 : bool PrintFontManager::getMetrics( fontID nFontID, sal_Unicode minCharacter, sal_Unicode maxCharacter, CharacterMetric* pArray, bool bVertical ) const
2520 : {
2521 : OSL_PRECOND(minCharacter <= maxCharacter, "invalid char. range");
2522 0 : if (minCharacter > maxCharacter)
2523 0 : return false;
2524 :
2525 0 : PrintFont* pFont = getFont( nFontID );
2526 0 : if( ! pFont )
2527 0 : return false;
2528 :
2529 0 : if( ( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
2530 0 : || ! pFont->m_pMetrics || pFont->m_pMetrics->isEmpty()
2531 : )
2532 : {
2533 : // might be a font not yet analyzed
2534 0 : if( pFont->m_eType == fonttype::Type1 || pFont->m_eType == fonttype::Builtin )
2535 0 : pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, false );
2536 0 : else if( pFont->m_eType == fonttype::TrueType )
2537 0 : analyzeTrueTypeFile( pFont );
2538 : }
2539 :
2540 0 : sal_Unicode code = minCharacter;
2541 0 : do
2542 : {
2543 0 : if( ! pFont->m_pMetrics ||
2544 0 : ! ( pFont->m_pMetrics->m_aPages[ code >> 11 ] & ( 1 << ( ( code >> 8 ) & 7 ) ) ) )
2545 0 : pFont->queryMetricPage( code >> 8, m_pAtoms );
2546 0 : pArray[ code - minCharacter ].width = -1;
2547 0 : pArray[ code - minCharacter ].height = -1;
2548 0 : if( pFont->m_pMetrics )
2549 : {
2550 0 : int effectiveCode = code;
2551 0 : effectiveCode |= bVertical ? 1 << 16 : 0;
2552 : ::boost::unordered_map< int, CharacterMetric >::const_iterator it =
2553 0 : pFont->m_pMetrics->m_aMetrics.find( effectiveCode );
2554 : // if no vertical metrics are available assume rotated horizontal metrics
2555 0 : if( bVertical && (it == pFont->m_pMetrics->m_aMetrics.end()) )
2556 0 : it = pFont->m_pMetrics->m_aMetrics.find( code );
2557 : // the character metrics are in it->second
2558 0 : if( it != pFont->m_pMetrics->m_aMetrics.end() )
2559 0 : pArray[ code - minCharacter ] = it->second;
2560 : }
2561 : } while( code++ != maxCharacter );
2562 :
2563 0 : return true;
2564 : }
2565 :
2566 : // -------------------------------------------------------------------------
2567 :
2568 : // TODO: move most of this stuff into the central font-subsetting code
2569 0 : bool PrintFontManager::createFontSubset(
2570 : FontSubsetInfo& rInfo,
2571 : fontID nFont,
2572 : const OUString& rOutFile,
2573 : sal_Int32* pGlyphIDs,
2574 : sal_uInt8* pNewEncoding,
2575 : sal_Int32* pWidths,
2576 : int nGlyphs,
2577 : bool bVertical
2578 : )
2579 : {
2580 0 : PrintFont* pFont = getFont( nFont );
2581 0 : if( !pFont )
2582 0 : return false;
2583 :
2584 0 : switch( pFont->m_eType )
2585 : {
2586 0 : case psp::fonttype::TrueType: rInfo.m_nFontType = FontSubsetInfo::SFNT_TTF; break;
2587 0 : case psp::fonttype::Type1: rInfo.m_nFontType = FontSubsetInfo::ANY_TYPE1; break;
2588 : default:
2589 0 : return false;
2590 : }
2591 : // TODO: remove when Type1 subsetting gets implemented
2592 0 : if( pFont->m_eType != fonttype::TrueType )
2593 0 : return false;
2594 :
2595 : // reshuffle array of requested glyphs to make sure glyph0==notdef
2596 : sal_uInt8 pEnc[256];
2597 : sal_uInt16 pGID[256];
2598 : sal_uInt8 pOldIndex[256];
2599 0 : memset( pEnc, 0, sizeof( pEnc ) );
2600 0 : memset( pGID, 0, sizeof( pGID ) );
2601 0 : memset( pOldIndex, 0, sizeof( pOldIndex ) );
2602 0 : if( nGlyphs > 256 )
2603 0 : return false;
2604 0 : int nChar = 1;
2605 0 : for( int i = 0; i < nGlyphs; i++ )
2606 : {
2607 0 : if( pNewEncoding[i] == 0 )
2608 : {
2609 0 : pOldIndex[ 0 ] = i;
2610 : }
2611 : else
2612 : {
2613 : DBG_ASSERT( !(pGlyphIDs[i] & 0x007f0000), "overlong glyph id" );
2614 : DBG_ASSERT( (int)pNewEncoding[i] < nGlyphs, "encoding wrong" );
2615 : DBG_ASSERT( pEnc[pNewEncoding[i]] == 0 && pGID[pNewEncoding[i]] == 0, "duplicate encoded glyph" );
2616 0 : pEnc[ pNewEncoding[i] ] = pNewEncoding[i];
2617 0 : pGID[ pNewEncoding[i] ] = (sal_uInt16)pGlyphIDs[ i ];
2618 0 : pOldIndex[ pNewEncoding[i] ] = i;
2619 0 : nChar++;
2620 : }
2621 : }
2622 0 : nGlyphs = nChar; // either input value or increased by one
2623 :
2624 : // prepare system name for read access for subset source file
2625 : // TODO: since this file is usually already mmapped there is no need to open it again
2626 0 : const rtl::OString aFromFile = getFontFile( pFont );
2627 :
2628 0 : TrueTypeFont* pTTFont = NULL; // TODO: rename to SfntFont
2629 0 : TrueTypeFontFile* pTTFontFile = static_cast< TrueTypeFontFile* >(pFont);
2630 0 : if( OpenTTFontFile( aFromFile.getStr(), pTTFontFile->m_nCollectionEntry, &pTTFont ) != SF_OK )
2631 0 : return false;
2632 :
2633 : // prepare system name for write access for subset file target
2634 0 : OUString aSysPath;
2635 0 : if( osl_File_E_None != osl_getSystemPathFromFileURL( rOutFile.pData, &aSysPath.pData ) )
2636 0 : return false;
2637 0 : const rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
2638 0 : const rtl::OString aToFile( OUStringToOString( aSysPath, aEncoding ) );
2639 :
2640 : // do CFF subsetting if possible
2641 0 : int nCffLength = 0;
2642 0 : const sal_uInt8* pCffBytes = NULL;
2643 0 : if( GetSfntTable( pTTFont, O_CFF, &pCffBytes, &nCffLength ) )
2644 : {
2645 0 : rInfo.LoadFont( FontSubsetInfo::CFF_FONT, pCffBytes, nCffLength );
2646 : #if 1 // TODO: remove 16bit->long conversion when related methods handle non-16bit glyphids
2647 : long aRequestedGlyphs[256];
2648 0 : for( int i = 0; i < nGlyphs; ++i )
2649 0 : aRequestedGlyphs[i] = pGID[i];
2650 : #endif
2651 : // create subset file at requested path
2652 0 : FILE* pOutFile = fopen( aToFile.getStr(), "wb" );
2653 : // create font subset
2654 0 : const char* pGlyphSetName = NULL; // TODO: better name?
2655 : const bool bOK = rInfo.CreateFontSubset(
2656 : FontSubsetInfo::TYPE1_PFB,
2657 : pOutFile, pGlyphSetName,
2658 0 : aRequestedGlyphs, pEnc, nGlyphs, pWidths );
2659 0 : fclose( pOutFile );
2660 : // cleanup before early return
2661 0 : CloseTTFont( pTTFont );
2662 0 : return bOK;
2663 : }
2664 :
2665 : // do TTF->Type42 or Type3 subsetting
2666 : // fill in font info
2667 0 : psp::PrintFontInfo aFontInfo;
2668 0 : if( ! getFontInfo( nFont, aFontInfo ) )
2669 0 : return false;
2670 :
2671 0 : rInfo.m_nAscent = aFontInfo.m_nAscend;
2672 0 : rInfo.m_nDescent = aFontInfo.m_nDescend;
2673 0 : rInfo.m_aPSName = getPSName( nFont );
2674 :
2675 : int xMin, yMin, xMax, yMax;
2676 0 : getFontBoundingBox( nFont, xMin, yMin, xMax, yMax );
2677 0 : rInfo.m_aFontBBox = Rectangle( Point( xMin, yMin ), Size( xMax-xMin, yMax-yMin ) );
2678 0 : rInfo.m_nCapHeight = yMax; // Well ...
2679 :
2680 : // fill in glyph advance widths
2681 : TTSimpleGlyphMetrics* pMetrics = GetTTSimpleGlyphMetrics( pTTFont,
2682 : pGID,
2683 : nGlyphs,
2684 0 : bVertical ? 1 : 0 );
2685 0 : if( pMetrics )
2686 : {
2687 0 : for( int i = 0; i < nGlyphs; i++ )
2688 0 : pWidths[pOldIndex[i]] = pMetrics[i].adv;
2689 0 : free( pMetrics );
2690 : }
2691 : else
2692 : {
2693 0 : CloseTTFont( pTTFont );
2694 0 : return false;
2695 : }
2696 :
2697 : bool bSuccess = ( SF_OK == CreateTTFromTTGlyphs( pTTFont,
2698 : aToFile.getStr(),
2699 : pGID,
2700 : pEnc,
2701 : nGlyphs,
2702 : 0,
2703 : NULL,
2704 0 : 0 ) );
2705 0 : CloseTTFont( pTTFont );
2706 :
2707 0 : return bSuccess;
2708 : }
2709 :
2710 0 : void PrintFontManager::getGlyphWidths( fontID nFont,
2711 : bool bVertical,
2712 : std::vector< sal_Int32 >& rWidths,
2713 : std::map< sal_Unicode, sal_uInt32 >& rUnicodeEnc )
2714 : {
2715 0 : PrintFont* pFont = getFont( nFont );
2716 0 : if( !pFont ||
2717 : (pFont->m_eType != fonttype::TrueType && pFont->m_eType != fonttype::Type1) )
2718 0 : return;
2719 0 : if( pFont->m_eType == fonttype::TrueType )
2720 : {
2721 0 : TrueTypeFont* pTTFont = NULL;
2722 0 : TrueTypeFontFile* pTTFontFile = static_cast< TrueTypeFontFile* >(pFont);
2723 0 : rtl::OString aFromFile = getFontFile( pFont );
2724 0 : if( OpenTTFontFile( aFromFile.getStr(), pTTFontFile->m_nCollectionEntry, &pTTFont ) != SF_OK )
2725 : return;
2726 0 : int nGlyphs = GetTTGlyphCount( pTTFont );
2727 0 : if( nGlyphs > 0 )
2728 : {
2729 0 : rWidths.resize(nGlyphs);
2730 0 : std::vector<sal_uInt16> aGlyphIds(nGlyphs);
2731 0 : for( int i = 0; i < nGlyphs; i++ )
2732 0 : aGlyphIds[i] = sal_uInt16(i);
2733 : TTSimpleGlyphMetrics* pMetrics = GetTTSimpleGlyphMetrics( pTTFont,
2734 0 : &aGlyphIds[0],
2735 : nGlyphs,
2736 0 : bVertical ? 1 : 0 );
2737 0 : if( pMetrics )
2738 : {
2739 0 : for( int i = 0; i< nGlyphs; i++ )
2740 0 : rWidths[i] = pMetrics[i].adv;
2741 0 : free( pMetrics );
2742 0 : rUnicodeEnc.clear();
2743 : }
2744 :
2745 : // fill the unicode map
2746 : // TODO: isn't this map already available elsewhere in the fontmanager?
2747 0 : const sal_uInt8* pCmapData = NULL;
2748 0 : int nCmapSize = 0;
2749 0 : if( GetSfntTable( pTTFont, O_cmap, &pCmapData, &nCmapSize ) )
2750 : {
2751 0 : CmapResult aCmapResult;
2752 0 : if( ParseCMAP( pCmapData, nCmapSize, aCmapResult ) )
2753 : {
2754 0 : const ImplFontCharMap aCharMap( aCmapResult );
2755 0 : for( sal_uInt32 cOld = 0;;)
2756 : {
2757 : // get next unicode covered by font
2758 0 : const sal_uInt32 c = aCharMap.GetNextChar( cOld );
2759 0 : if( c == cOld )
2760 0 : break;
2761 0 : cOld = c;
2762 : #if 1 // TODO: remove when sal_Unicode covers all of unicode
2763 0 : if( c > (sal_Unicode)~0 )
2764 0 : break;
2765 : #endif
2766 : // get the matching glyph index
2767 0 : const sal_uInt32 nGlyphId = aCharMap.GetGlyphIndex( c );
2768 : // update the requested map
2769 0 : rUnicodeEnc[ (sal_Unicode)c ] = nGlyphId;
2770 0 : }
2771 : }
2772 0 : }
2773 : }
2774 0 : CloseTTFont( pTTFont );
2775 : }
2776 0 : else if( pFont->m_eType == fonttype::Type1 )
2777 : {
2778 0 : if( ! pFont->m_aEncodingVector.size() )
2779 0 : pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, true, true );
2780 0 : if( pFont->m_pMetrics )
2781 : {
2782 0 : rUnicodeEnc.clear();
2783 0 : rWidths.clear();
2784 0 : rWidths.reserve( pFont->m_pMetrics->m_aMetrics.size() );
2785 0 : for( boost::unordered_map< int, CharacterMetric >::const_iterator it =
2786 0 : pFont->m_pMetrics->m_aMetrics.begin();
2787 0 : it != pFont->m_pMetrics->m_aMetrics.end(); ++it )
2788 : {
2789 0 : if( (it->first & 0x00010000) == 0 || bVertical )
2790 : {
2791 0 : rUnicodeEnc[ sal_Unicode(it->first & 0x0000ffff) ] = sal_uInt32(rWidths.size());
2792 0 : rWidths.push_back( it->second.width );
2793 : }
2794 : }
2795 : }
2796 : }
2797 : }
2798 :
2799 : // -------------------------------------------------------------------------
2800 :
2801 0 : const std::map< sal_Unicode, sal_Int32 >* PrintFontManager::getEncodingMap( fontID nFont, const std::map< sal_Unicode, rtl::OString >** pNonEncoded ) const
2802 : {
2803 0 : PrintFont* pFont = getFont( nFont );
2804 0 : if( !pFont ||
2805 : (pFont->m_eType != fonttype::Type1 && pFont->m_eType != fonttype::Builtin)
2806 : )
2807 0 : return NULL;
2808 :
2809 0 : if( ! pFont->m_aEncodingVector.size() )
2810 0 : pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, true, true );
2811 :
2812 0 : if( pNonEncoded )
2813 0 : *pNonEncoded = pFont->m_aNonEncoded.size() ? &pFont->m_aNonEncoded : NULL;
2814 :
2815 0 : return pFont->m_aEncodingVector.size() ? &pFont->m_aEncodingVector : NULL;
2816 : }
2817 :
2818 : // -------------------------------------------------------------------------
2819 :
2820 0 : std::list< OString > PrintFontManager::getAdobeNameFromUnicode( sal_Unicode aChar ) const
2821 : {
2822 : std::pair< boost::unordered_multimap< sal_Unicode, rtl::OString >::const_iterator,
2823 : boost::unordered_multimap< sal_Unicode, rtl::OString >::const_iterator > range
2824 0 : = m_aUnicodeToAdobename.equal_range( aChar );
2825 :
2826 0 : std::list< OString > aRet;
2827 0 : for( ; range.first != range.second; ++range.first )
2828 0 : aRet.push_back( range.first->second );
2829 :
2830 0 : if( aRet.begin() == aRet.end() && aChar != 0 )
2831 : {
2832 : sal_Char aBuf[8];
2833 0 : sal_Int32 nChars = snprintf( (char*)aBuf, sizeof( aBuf ), "uni%.4hX", aChar );
2834 0 : aRet.push_back( OString( aBuf, nChars ) );
2835 : }
2836 :
2837 0 : return aRet;
2838 : }
2839 :
2840 : // -------------------------------------------------------------------------
2841 0 : std::list< sal_Unicode > PrintFontManager::getUnicodeFromAdobeName( const rtl::OString& rName ) const
2842 : {
2843 : std::pair< boost::unordered_multimap< rtl::OString, sal_Unicode, rtl::OStringHash >::const_iterator,
2844 : boost::unordered_multimap< rtl::OString, sal_Unicode, rtl::OStringHash >::const_iterator > range
2845 0 : = m_aAdobenameToUnicode.equal_range( rName );
2846 :
2847 0 : std::list< sal_Unicode > aRet;
2848 0 : for( ; range.first != range.second; ++range.first )
2849 0 : aRet.push_back( range.first->second );
2850 :
2851 0 : if( aRet.begin() == aRet.end() )
2852 : {
2853 0 : if( rName.getLength() == 7 && rName.indexOf( "uni" ) == 0 )
2854 : {
2855 0 : sal_Unicode aCode = (sal_Unicode)rName.copy( 3 ).toInt32( 16 );
2856 0 : aRet.push_back( aCode );
2857 : }
2858 : }
2859 :
2860 0 : return aRet;
2861 : }
2862 :
2863 : // -------------------------------------------------------------------------
2864 : namespace
2865 : {
2866 0 : OUString getString( const Any& rAny )
2867 : {
2868 0 : OUString aStr;
2869 0 : rAny >>= aStr;
2870 0 : return aStr;
2871 : }
2872 0 : bool getBool( const Any& rAny )
2873 : {
2874 0 : sal_Bool bBool = sal_False;
2875 0 : rAny >>= bBool;
2876 0 : return static_cast<bool>(bBool);
2877 : }
2878 0 : sal_Int32 getInt( const Any& rAny )
2879 : {
2880 0 : sal_Int32 n = 0;
2881 0 : rAny >>= n;
2882 0 : return n;
2883 : }
2884 : }
2885 0 : bool PrintFontManager::readOverrideMetrics()
2886 : {
2887 0 : if( ! m_aOverrideFonts.empty() )
2888 0 : return false;
2889 :
2890 0 : css::uno::Reference< XMultiServiceFactory > xFact( comphelper::getProcessServiceFactory() );
2891 0 : if( !xFact.is() )
2892 0 : return false;
2893 : css::uno::Reference< XMaterialHolder > xMat(
2894 0 : xFact->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.psprint.CompatMetricOverride" ) ) ),
2895 0 : UNO_QUERY );
2896 0 : if( !xMat.is() )
2897 0 : return false;
2898 :
2899 0 : Any aAny( xMat->getMaterial() );
2900 0 : Sequence< Any > aOverrideFonts;
2901 0 : if( ! (aAny >>= aOverrideFonts ) )
2902 0 : return false;
2903 0 : sal_Int32 nFonts = aOverrideFonts.getLength();
2904 0 : for( sal_Int32 i = 0; i < nFonts; i++ )
2905 : {
2906 0 : Sequence< NamedValue > aMetrics;
2907 0 : if( ! (aOverrideFonts.getConstArray()[i] >>= aMetrics) )
2908 0 : continue;
2909 0 : BuiltinFont* pFont = new BuiltinFont();
2910 0 : pFont->m_nDirectory = 0;
2911 0 : pFont->m_bUserOverride = false;
2912 0 : pFont->m_pMetrics = new PrintFontMetrics;
2913 0 : memset( pFont->m_pMetrics->m_aPages, 0xff, sizeof( pFont->m_pMetrics->m_aPages ) );
2914 0 : pFont->m_pMetrics->m_bKernPairsQueried = true;
2915 0 : sal_Int32 nProps = aMetrics.getLength();
2916 0 : const NamedValue* pProps = aMetrics.getConstArray();
2917 0 : for( sal_Int32 n = 0; n < nProps; n++ )
2918 : {
2919 0 : if ( pProps[n].Name == "FamilyName" )
2920 : pFont->m_nFamilyName = m_pAtoms->getAtom( ATOM_FAMILYNAME,
2921 0 : getString(pProps[n].Value),
2922 0 : sal_True );
2923 0 : else if ( pProps[n].Name == "PSName" )
2924 : pFont->m_nPSName = m_pAtoms->getAtom( ATOM_PSNAME,
2925 0 : getString(pProps[n].Value),
2926 0 : sal_True );
2927 0 : else if ( pProps[n].Name == "StyleName" )
2928 0 : pFont->m_aStyleName = getString(pProps[n].Value);
2929 0 : else if ( pProps[n].Name == "Italic" )
2930 0 : pFont->m_eItalic = static_cast<FontItalic>(getInt(pProps[n].Value));
2931 0 : else if ( pProps[n].Name == "Width" )
2932 0 : pFont->m_eWidth = static_cast<FontWidth>(getInt(pProps[n].Value));
2933 0 : else if ( pProps[n].Name == "Weight" )
2934 0 : pFont->m_eWeight = static_cast<FontWeight>(getInt(pProps[n].Value));
2935 0 : else if ( pProps[n].Name == "Pitch" )
2936 0 : pFont->m_ePitch = static_cast<FontPitch>(getInt(pProps[n].Value));
2937 0 : else if ( pProps[n].Name == "Encoding" )
2938 0 : pFont->m_aEncoding = static_cast<rtl_TextEncoding>(getInt(pProps[n].Value));
2939 0 : else if ( pProps[n].Name == "FontEncodingOnly" )
2940 0 : pFont->m_bFontEncodingOnly = getBool(pProps[n].Value);
2941 0 : else if ( pProps[n].Name == "GlobalMetricXWidth" )
2942 0 : pFont->m_aGlobalMetricX.width = getInt(pProps[n].Value);
2943 0 : else if ( pProps[n].Name == "GlobalMetricXHeight" )
2944 0 : pFont->m_aGlobalMetricX.height = getInt(pProps[n].Value);
2945 0 : else if ( pProps[n].Name == "GlobalMetricYWidth" )
2946 0 : pFont->m_aGlobalMetricY.width = getInt(pProps[n].Value);
2947 0 : else if ( pProps[n].Name == "GlobalMetricYHeight" )
2948 0 : pFont->m_aGlobalMetricY.height = getInt(pProps[n].Value);
2949 0 : else if ( pProps[n].Name == "Ascend" )
2950 0 : pFont->m_nAscend = getInt(pProps[n].Value);
2951 0 : else if ( pProps[n].Name == "Descend" )
2952 0 : pFont->m_nDescend = getInt(pProps[n].Value);
2953 0 : else if ( pProps[n].Name == "Leading" )
2954 0 : pFont->m_nLeading = getInt(pProps[n].Value);
2955 0 : else if ( pProps[n].Name == "XMin" )
2956 0 : pFont->m_nXMin = getInt(pProps[n].Value);
2957 0 : else if ( pProps[n].Name == "YMin" )
2958 0 : pFont->m_nYMin = getInt(pProps[n].Value);
2959 0 : else if ( pProps[n].Name == "XMax" )
2960 0 : pFont->m_nXMax = getInt(pProps[n].Value);
2961 0 : else if ( pProps[n].Name == "YMax" )
2962 0 : pFont->m_nYMax = getInt(pProps[n].Value);
2963 0 : else if ( pProps[n].Name == "VerticalSubstitutes" )
2964 0 : pFont->m_bHaveVerticalSubstitutedGlyphs = getBool(pProps[n].Value);
2965 0 : else if ( pProps[n].Name == "EncodingVector" )
2966 : {
2967 0 : Sequence< NamedValue > aEncoding;
2968 0 : pProps[n].Value >>= aEncoding;
2969 0 : sal_Int32 nEnc = aEncoding.getLength();
2970 0 : const NamedValue* pEnc = aEncoding.getConstArray();
2971 0 : for( sal_Int32 m = 0; m < nEnc; m++ )
2972 : {
2973 0 : sal_Unicode cCode = *pEnc[m].Name.getStr();
2974 0 : sal_Int32 nGlyph = getInt(pEnc[m].Value);
2975 0 : pFont->m_aEncodingVector[ cCode ] = nGlyph;
2976 0 : }
2977 : }
2978 0 : else if ( pProps[n].Name == "NonEncoded" )
2979 : {
2980 0 : Sequence< NamedValue > aEncoding;
2981 0 : pProps[n].Value >>= aEncoding;
2982 0 : sal_Int32 nEnc = aEncoding.getLength();
2983 0 : const NamedValue* pEnc = aEncoding.getConstArray();
2984 0 : for( sal_Int32 m = 0; m < nEnc; m++ )
2985 : {
2986 0 : sal_Unicode cCode = *pEnc[m].Name.getStr();
2987 0 : OUString aGlyphName( getString(pEnc[m].Value) );
2988 0 : pFont->m_aNonEncoded[ cCode ] = OUStringToOString(aGlyphName,RTL_TEXTENCODING_ASCII_US);
2989 0 : }
2990 : }
2991 0 : else if ( pProps[n].Name == "CharacterMetrics" )
2992 : {
2993 : // fill pFont->m_pMetrics->m_aMetrics
2994 : // expect triples of int: int -> CharacterMetric.{ width, height }
2995 0 : Sequence< sal_Int32 > aSeq;
2996 0 : pProps[n].Value >>= aSeq;
2997 0 : sal_Int32 nInts = aSeq.getLength();
2998 0 : const sal_Int32* pInts = aSeq.getConstArray();
2999 0 : for( sal_Int32 m = 0; m < nInts; m+=3 )
3000 : {
3001 0 : pFont->m_pMetrics->m_aMetrics[ pInts[m] ].width = static_cast<short int>(pInts[m+1]);
3002 0 : pFont->m_pMetrics->m_aMetrics[ pInts[m] ].height = static_cast<short int>(pInts[m+2]);
3003 0 : }
3004 : }
3005 0 : else if ( pProps[n].Name == "XKernPairs" )
3006 : {
3007 : // fill pFont->m_pMetrics->m_aXKernPairs
3008 : // expection name: <unicode1><unicode2> value: ((height << 16)| width)
3009 0 : Sequence< NamedValue > aKern;
3010 0 : pProps[n].Value >>= aKern;
3011 0 : KernPair aPair;
3012 0 : const NamedValue* pVals = aKern.getConstArray();
3013 0 : int nPairs = aKern.getLength();
3014 0 : for( int m = 0; m < nPairs; m++ )
3015 : {
3016 0 : if( pVals[m].Name.getLength() == 2 )
3017 : {
3018 0 : aPair.first = pVals[m].Name.getStr()[0];
3019 0 : aPair.second = pVals[m].Name.getStr()[1];
3020 0 : sal_Int32 nKern = getInt( pVals[m].Value );
3021 0 : aPair.kern_x = static_cast<short int>(nKern & 0xffff);
3022 0 : aPair.kern_y = static_cast<short int>((sal_uInt32(nKern) >> 16) & 0xffff);
3023 0 : pFont->m_pMetrics->m_aXKernPairs.push_back( aPair );
3024 : }
3025 0 : }
3026 : }
3027 : }
3028 : // sanity check
3029 0 : if( pFont->m_nPSName &&
3030 : pFont->m_nFamilyName &&
3031 0 : ! pFont->m_pMetrics->m_aMetrics.empty() )
3032 : {
3033 0 : m_aOverrideFonts.push_back( m_nNextFontID );
3034 0 : m_aFonts[ m_nNextFontID++ ] = pFont;
3035 : }
3036 : else
3037 : {
3038 : DBG_ASSERT( 0, "override font failed" );
3039 0 : delete pFont;
3040 : }
3041 0 : }
3042 :
3043 0 : return true;
3044 : }
3045 :
3046 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|