1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_vcl.hxx"
26
27 #include <unistd.h>
28 #include <sys/stat.h>
29 #include <dirent.h>
30 #include <stdlib.h>
31 #include <osl/thread.h>
32
33 #include "unotools/atom.hxx"
34
35 #include "fontcache.hxx"
36 #include "fontsubset.hxx"
37 #include "impfont.hxx"
38 #include "svdata.hxx"
39 #include "salinst.hxx"
40 #include "vcl/fontmanager.hxx"
41 #include "vcl/strhelper.hxx"
42 #include "vcl/ppdparser.hxx"
43
44 #include "tools/urlobj.hxx"
45 #include "tools/stream.hxx"
46 #include "tools/debug.hxx"
47 #include "tools/config.hxx"
48
49 #include "osl/file.hxx"
50 #include "osl/process.h"
51
52 #include "rtl/tencinfo.h"
53 #include "rtl/ustrbuf.hxx"
54 #include "rtl/strbuf.hxx"
55
56 #include "i18npool/mslangid.hxx"
57
58
59 #include "parseAFM.hxx"
60 #include "sft.hxx"
61
62 #if OSL_DEBUG_LEVEL > 1
63 #include <sys/times.h>
64 #include <stdio.h>
65 #endif
66
67 #include "sal/alloca.h"
68
69 #include <set>
70 #include <hash_set>
71 #include <algorithm>
72
73 #include "adobeenc.tab" // get encoding table for AFM metrics
74
75 #ifdef CALLGRIND_COMPILE
76 #include <valgrind/callgrind.h>
77 #endif
78
79 #include "comphelper/processfactory.hxx"
80 #include "com/sun/star/beans/XMaterialHolder.hpp"
81 #include "com/sun/star/beans/NamedValue.hpp"
82
83 #define PRINTER_METRICDIR "fontmetric"
84
85 namespace {
86
87 namespace css = com::sun::star;
88
89 }
90
91 using namespace vcl;
92 using namespace utl;
93 using namespace psp;
94 using namespace osl;
95 using namespace rtl;
96 using namespace com::sun::star::uno;
97 using namespace com::sun::star::beans;
98 using namespace com::sun::star::lang;
99
100 /*
101 * static helpers
102 */
103
getUInt16BE(const sal_uInt8 * & pBuffer)104 inline sal_uInt16 getUInt16BE( const sal_uInt8*& pBuffer )
105 {
106 sal_uInt16 nRet = (sal_uInt16)pBuffer[1] |
107 (((sal_uInt16)pBuffer[0]) << 8);
108 pBuffer+=2;
109 return nRet;
110 }
111
getUInt32BE(const sal_uInt8 * & pBuffer)112 inline sal_uInt32 getUInt32BE( const sal_uInt8*& pBuffer )
113 {
114 sal_uInt32 nRet = (((sal_uInt32)pBuffer[0]) << 24) |
115 (((sal_uInt32)pBuffer[1]) << 16) |
116 (((sal_uInt32)pBuffer[2]) << 8) |
117 (((sal_uInt32)pBuffer[3]) );
118 pBuffer += 4;
119 return nRet;
120 }
121
parseItalic(const ByteString & rItalic)122 static italic::type parseItalic( const ByteString& rItalic )
123 {
124 italic::type eItalic = italic::Unknown;
125 if( rItalic.EqualsIgnoreCaseAscii( "i" ) )
126 eItalic = italic::Italic;
127 else if( rItalic.EqualsIgnoreCaseAscii( "o" ) )
128 eItalic = italic::Oblique;
129 else
130 eItalic = italic::Upright;
131 return eItalic;
132 }
133
134 // -------------------------------------------------------------------------
135
parseWeight(const ByteString & rWeight)136 static weight::type parseWeight( const ByteString& rWeight )
137 {
138 weight::type eWeight = weight::Unknown;
139 if( rWeight.Search( "bold" ) != STRING_NOTFOUND )
140 {
141 if( rWeight.Search( "emi" ) != STRING_NOTFOUND ) // semi, demi
142 eWeight = weight::SemiBold;
143 else if( rWeight.Search( "ultra" ) != STRING_NOTFOUND )
144 eWeight = weight::UltraBold;
145 else
146 eWeight = weight::Bold;
147 }
148 else if( rWeight.Search( "heavy" ) != STRING_NOTFOUND )
149 eWeight = weight::Bold;
150 else if( rWeight.Search( "light" ) != STRING_NOTFOUND )
151 {
152 if( rWeight.Search( "emi" ) != STRING_NOTFOUND ) // semi, demi
153 eWeight = weight::SemiLight;
154 else if( rWeight.Search( "ultra" ) != STRING_NOTFOUND )
155 eWeight = weight::UltraLight;
156 else
157 eWeight = weight::Light;
158 }
159 else if( rWeight.Search( "black" ) != STRING_NOTFOUND )
160 eWeight = weight::Black;
161 else if( rWeight.Equals( "demi" ) )
162 eWeight = weight::SemiBold;
163 else if( rWeight.Equals( "book" ) ||
164 rWeight.Equals( "semicondensed" ) )
165 eWeight = weight::Light;
166 else if( rWeight.Equals( "medium" ) || rWeight.Equals( "roman" ) )
167 eWeight = weight::Medium;
168 else
169 eWeight = weight::Normal;
170 return eWeight;
171 }
172
173 // -------------------------------------------------------------------------
174
parseWidth(const ByteString & rWidth)175 static width::type parseWidth( const ByteString& rWidth )
176 {
177 width::type eWidth = width::Unknown;
178 if( rWidth.Equals( "bold" ) ||
179 rWidth.Equals( "semiexpanded" ) )
180 eWidth = width::SemiExpanded;
181 else if( rWidth.Equals( "condensed" ) ||
182 rWidth.Equals( "narrow" ) )
183 eWidth = width::Condensed;
184 else if( rWidth.Equals( "double wide" ) ||
185 rWidth.Equals( "extraexpanded" ) ||
186 rWidth.Equals( "ultraexpanded" ) )
187 eWidth = width::UltraExpanded;
188 else if( rWidth.Equals( "expanded" ) ||
189 rWidth.Equals( "wide" ) )
190 eWidth = width::Expanded;
191 else if( rWidth.Equals( "extracondensed" ) )
192 eWidth = width::ExtraCondensed;
193 else if( rWidth.Equals( "semicondensed" ) )
194 eWidth = width::SemiCondensed;
195 else if( rWidth.Equals( "ultracondensed" ) )
196 eWidth = width::UltraCondensed;
197 else
198 eWidth = width::Normal;
199
200 return eWidth;
201 }
202
203 // -------------------------------------------------------------------------
operator <(const PrintFontManager::XLFDEntry & rRight) const204 bool PrintFontManager::XLFDEntry::operator<(const PrintFontManager::XLFDEntry& rRight) const
205 {
206 sal_Int32 nCmp = 0;
207 if( (nMask & MaskFamily) && (rRight.nMask & MaskFamily) )
208 {
209 nCmp = rtl_str_compareIgnoreAsciiCase_WithLength( aFamily.pData->buffer,
210 aFamily.pData->length,
211 rRight.aFamily.pData->buffer,
212 rRight.aFamily.pData->length );
213 if( nCmp != 0 )
214 return nCmp < 0;
215 }
216
217 if( (nMask & MaskFoundry) && (rRight.nMask & MaskFoundry) )
218 {
219 nCmp = rtl_str_compareIgnoreAsciiCase_WithLength( aFoundry.pData->buffer,
220 aFoundry.pData->length,
221 rRight.aFoundry.pData->buffer,
222 rRight.aFoundry.pData->length );
223 if( nCmp != 0 )
224 return nCmp < 0;
225 }
226
227 if( (nMask & MaskItalic) && (rRight.nMask & MaskItalic) )
228 {
229 if( eItalic != rRight.eItalic )
230 return (int)eItalic < (int)rRight.eItalic;
231 }
232
233 if( (nMask & MaskWeight) && (rRight.nMask & MaskWeight) )
234 {
235 if( eWeight != rRight.eWeight )
236 return (int)eWeight < (int)rRight.eWeight;
237 }
238
239 if( (nMask & MaskWidth) && (rRight.nMask & MaskWidth) )
240 {
241 if( eWidth != rRight.eWidth )
242 return (int)eWidth < (int)rRight.eWidth;
243 }
244
245 if( (nMask & MaskPitch) && (rRight.nMask & MaskPitch) )
246 {
247 if( ePitch != rRight.ePitch )
248 return (int)ePitch < (int)rRight.ePitch;
249 }
250
251 if( (nMask & MaskAddStyle) && (rRight.nMask & MaskAddStyle) )
252 {
253 nCmp = rtl_str_compareIgnoreAsciiCase_WithLength( aAddStyle.pData->buffer,
254 aAddStyle.pData->length,
255 rRight.aAddStyle.pData->buffer,
256 rRight.aAddStyle.pData->length );
257 if( nCmp != 0 )
258 return nCmp < 0;
259 }
260
261 if( (nMask & MaskEncoding) && (rRight.nMask & MaskEncoding) )
262 {
263 if( aEncoding != rRight.aEncoding )
264 return aEncoding < rRight.aEncoding;
265 }
266
267 return false;
268 }
269
operator ==(const PrintFontManager::XLFDEntry & rRight) const270 bool PrintFontManager::XLFDEntry::operator==(const PrintFontManager::XLFDEntry& rRight) const
271 {
272 sal_Int32 nCmp = 0;
273 if( (nMask & MaskFamily) && (rRight.nMask & MaskFamily) )
274 {
275 nCmp = rtl_str_compareIgnoreAsciiCase_WithLength( aFamily.pData->buffer,
276 aFamily.pData->length,
277 rRight.aFamily.pData->buffer,
278 rRight.aFamily.pData->length );
279 if( nCmp != 0 )
280 return false;
281 }
282
283 if( (nMask & MaskFoundry) && (rRight.nMask & MaskFoundry) )
284 {
285 nCmp = rtl_str_compareIgnoreAsciiCase_WithLength( aFoundry.pData->buffer,
286 aFoundry.pData->length,
287 rRight.aFoundry.pData->buffer,
288 rRight.aFoundry.pData->length );
289 if( nCmp != 0 )
290 return false;
291 }
292
293 if( (nMask & MaskItalic) && (rRight.nMask & MaskItalic) )
294 {
295 if( eItalic != rRight.eItalic )
296 return false;
297 }
298
299 if( (nMask & MaskWeight) && (rRight.nMask & MaskWeight) )
300 {
301 if( eWeight != rRight.eWeight )
302 return false;
303 }
304
305 if( (nMask & MaskWidth) && (rRight.nMask & MaskWidth) )
306 {
307 if( eWidth != rRight.eWidth )
308 return false;
309 }
310
311 if( (nMask & MaskPitch) && (rRight.nMask & MaskPitch) )
312 {
313 if( ePitch != rRight.ePitch )
314 return false;
315 }
316
317 if( (nMask & MaskAddStyle) && (rRight.nMask & MaskAddStyle) )
318 {
319 nCmp = rtl_str_compareIgnoreAsciiCase_WithLength( aAddStyle.pData->buffer,
320 aAddStyle.pData->length,
321 rRight.aAddStyle.pData->buffer,
322 rRight.aAddStyle.pData->length );
323 if( nCmp != 0 )
324 return false;
325 }
326
327 if( (nMask & MaskEncoding) && (rRight.nMask & MaskEncoding) )
328 {
329 if( aEncoding != rRight.aEncoding )
330 return false;
331 }
332
333 return true;
334 }
335
336 /*
337 * PrintFont implementations
338 */
PrintFont(fonttype::type eType)339 PrintFontManager::PrintFont::PrintFont( fonttype::type eType ) :
340 m_eType( eType ),
341 m_nFamilyName( 0 ),
342 m_nPSName( 0 ),
343 m_eItalic( italic::Unknown ),
344 m_eWidth( width::Unknown ),
345 m_eWeight( weight::Unknown ),
346 m_ePitch( pitch::Unknown ),
347 m_aEncoding( RTL_TEXTENCODING_DONTKNOW ),
348 m_bFontEncodingOnly( false ),
349 m_pMetrics( NULL ),
350 m_nAscend( 0 ),
351 m_nDescend( 0 ),
352 m_nLeading( 0 ),
353 m_nXMin( 0 ),
354 m_nYMin( 0 ),
355 m_nXMax( 0 ),
356 m_nYMax( 0 ),
357 m_bHaveVerticalSubstitutedGlyphs( false ),
358 m_bUserOverride( false )
359 {
360 }
361
362 // -------------------------------------------------------------------------
363
~PrintFont()364 PrintFontManager::PrintFont::~PrintFont()
365 {
366 if( m_pMetrics )
367 delete m_pMetrics;
368 }
369
370 // -------------------------------------------------------------------------
371
~Type1FontFile()372 PrintFontManager::Type1FontFile::~Type1FontFile()
373 {
374 }
375
376 // -------------------------------------------------------------------------
377
TrueTypeFontFile()378 PrintFontManager::TrueTypeFontFile::TrueTypeFontFile()
379 : PrintFont( fonttype::TrueType )
380 , m_nDirectory( 0 )
381 , m_nCollectionEntry(-1)
382 , m_nTypeFlags( TYPEFLAG_INVALID )
383 {}
384
385 // -------------------------------------------------------------------------
386
~TrueTypeFontFile()387 PrintFontManager::TrueTypeFontFile::~TrueTypeFontFile()
388 {
389 }
390
391 // -------------------------------------------------------------------------
392
~BuiltinFont()393 PrintFontManager::BuiltinFont::~BuiltinFont()
394 {
395 }
396
397 // -------------------------------------------------------------------------
398
queryMetricPage(int,MultiAtomProvider * pProvider)399 bool PrintFontManager::Type1FontFile::queryMetricPage( int /*nPage*/, MultiAtomProvider* pProvider )
400 {
401 return readAfmMetrics( PrintFontManager::get().getAfmFile( this ), pProvider, false, false );
402 }
403
404 // -------------------------------------------------------------------------
405
queryMetricPage(int,MultiAtomProvider * pProvider)406 bool PrintFontManager::BuiltinFont::queryMetricPage( int /*nPage*/, MultiAtomProvider* pProvider )
407 {
408 return readAfmMetrics( PrintFontManager::get().getAfmFile( this ), pProvider, false, false );
409 }
410
411 // -------------------------------------------------------------------------
412
queryMetricPage(int nPage,MultiAtomProvider * pProvider)413 bool PrintFontManager::TrueTypeFontFile::queryMetricPage( int nPage, MultiAtomProvider* pProvider )
414 {
415 bool bSuccess = false;
416
417 ByteString aFile( PrintFontManager::get().getFontFile( this ) );
418
419 TrueTypeFont* pTTFont = NULL;
420
421 if( OpenTTFontFile( aFile.GetBuffer(), m_nCollectionEntry < 0 ? 0 : m_nCollectionEntry, &pTTFont ) == SF_OK )
422 {
423 if( ! m_pMetrics )
424 {
425 m_pMetrics = new PrintFontMetrics;
426 memset (m_pMetrics->m_aPages, 0, sizeof(m_pMetrics->m_aPages));
427 }
428 m_pMetrics->m_aPages[ nPage/8 ] |= (1 << ( nPage & 7 ));
429 int i;
430 sal_uInt16 table[256], table_vert[256];
431
432 for( i = 0; i < 256; i++ )
433 table[ i ] = 256*nPage + i;
434
435 int nCharacters = nPage < 255 ? 256 : 254;
436 MapString( pTTFont, table, nCharacters, NULL, 0 );
437 TTSimpleGlyphMetrics* pMetrics = GetTTSimpleCharMetrics( pTTFont, nPage*256, nCharacters, 0 );
438 if( pMetrics )
439 {
440 for( i = 0; i < nCharacters; i++ )
441 {
442 if( table[i] )
443 {
444 CharacterMetric& rChar = m_pMetrics->m_aMetrics[ nPage*256 + i ];
445 rChar.width = pMetrics[ i ].adv;
446 rChar.height = m_aGlobalMetricX.height;
447 }
448 }
449
450 free( pMetrics );
451 }
452
453 for( i = 0; i < 256; i++ )
454 table_vert[ i ] = 256*nPage + i;
455 MapString( pTTFont, table_vert, nCharacters, NULL, 1 );
456 pMetrics = GetTTSimpleCharMetrics( pTTFont, nPage*256, nCharacters, 1 );
457 if( pMetrics )
458 {
459 for( i = 0; i < nCharacters; i++ )
460 {
461 if( table_vert[i] )
462 {
463 CharacterMetric& rChar = m_pMetrics->m_aMetrics[ nPage*256 + i + ( 1 << 16 ) ];
464 rChar.width = m_aGlobalMetricY.width;
465 rChar.height = pMetrics[ i ].adv;
466 if( table_vert[i] != table[i] )
467 m_pMetrics->m_bVerticalSubstitutions[ nPage*256 + i ] = 1;
468 }
469 }
470 free( pMetrics );
471 }
472
473 if( ! m_pMetrics->m_bKernPairsQueried )
474 {
475 m_pMetrics->m_bKernPairsQueried = true;
476 // this is really a hack
477 // in future MapString/KernGlyphs should be used
478 // but vcl is not in a state where that could be used
479 // so currently we get kernpairs by accessing the raw data
480 struct _TrueTypeFont* pImplTTFont = (struct _TrueTypeFont*)pTTFont;
481
482 //-----------------------------------------------------------------
483 // Kerning: KT_MICROSOFT
484 //-----------------------------------------------------------------
485 if( pImplTTFont->nkern && pImplTTFont->kerntype == KT_MICROSOFT )
486 {
487 // create a glyph -> character mapping
488 ::std::hash_map< sal_uInt16, sal_Unicode > aGlyphMap;
489 ::std::hash_map< sal_uInt16, sal_Unicode >::iterator left, right;
490 for( i = 21; i < 0xfffd; i++ )
491 {
492 sal_uInt16 nGlyph = MapChar( pTTFont, (sal_Unicode)i, 0 ); // kerning for horz only
493 if( nGlyph != 0 )
494 aGlyphMap[ nGlyph ] = (sal_Unicode)i;
495 }
496
497
498 KernPair aPair;
499 for( i = 0; i < (int)pImplTTFont->nkern; i++ )
500 {
501 const sal_uInt8* pTable = pImplTTFont->kerntables[i];
502
503 /*sal_uInt16 nVersion =*/ getUInt16BE( pTable );
504 /*sal_uInt16 nLength =*/ getUInt16BE( pTable );
505 sal_uInt16 nCoverage = getUInt16BE( pTable );
506
507 aPair.kern_x = 0;
508 aPair.kern_y = 0;
509 switch( nCoverage >> 8 )
510 {
511 case 0:
512 {
513 sal_uInt16 nPairs = getUInt16BE( pTable );
514 pTable += 6;
515 for( int n = 0; n < nPairs; n++ )
516 {
517 sal_uInt16 nLeftGlyph = getUInt16BE( pTable );
518 sal_uInt16 nRightGlyph = getUInt16BE( pTable );
519 sal_Int16 nKern = (sal_Int16)getUInt16BE( pTable );
520
521 left = aGlyphMap.find( nLeftGlyph );
522 right = aGlyphMap.find( nRightGlyph );
523 if( left != aGlyphMap.end() && right != aGlyphMap.end() )
524 {
525 aPair.first = left->second;
526 aPair.second = right->second;
527 switch( nCoverage & 1 )
528 {
529 case 1:
530 aPair.kern_x = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
531 m_pMetrics->m_aXKernPairs.push_back( aPair );
532 break;
533 case 0:
534 aPair.kern_y = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
535 m_pMetrics->m_aYKernPairs.push_back( aPair );
536 break;
537 }
538 }
539 }
540 }
541 break;
542
543 case 2:
544 {
545 const sal_uInt8* pSubTable = pTable;
546 /*sal_uInt16 nRowWidth =*/ getUInt16BE( pTable );
547 sal_uInt16 nOfLeft = getUInt16BE( pTable );
548 sal_uInt16 nOfRight = getUInt16BE( pTable );
549 /*sal_uInt16 nOfArray =*/ getUInt16BE( pTable );
550 const sal_uInt8* pTmp = pSubTable + nOfLeft;
551 sal_uInt16 nFirstLeft = getUInt16BE( pTmp );
552 sal_uInt16 nLastLeft = getUInt16BE( pTmp ) + nFirstLeft - 1;
553 pTmp = pSubTable + nOfRight;
554 sal_uInt16 nFirstRight = getUInt16BE( pTmp );
555 sal_uInt16 nLastRight = getUInt16BE( pTmp ) + nFirstRight -1;
556
557 // int nPairs = (int)(nLastLeft-nFirstLeft+1)*(int)(nLastRight-nFirstRight+1);
558 for( aPair.first = nFirstLeft; aPair.first < nLastLeft; aPair.first++ )
559 {
560 for( aPair.second = 0; aPair.second < nLastRight; aPair.second++ )
561 {
562 sal_Int16 nKern = (sal_Int16)getUInt16BE( pTmp );
563 switch( nCoverage & 1 )
564 {
565 case 1:
566 aPair.kern_x = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
567 m_pMetrics->m_aXKernPairs.push_back( aPair );
568 break;
569 case 0:
570 aPair.kern_y = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
571 m_pMetrics->m_aYKernPairs.push_back( aPair );
572 break;
573 }
574 }
575 }
576 }
577 break;
578 }
579 }
580 }
581
582 //-----------------------------------------------------------------
583 // Kerning: KT_APPLE_NEW
584 //-----------------------------------------------------------------
585 if( pImplTTFont->nkern && pImplTTFont->kerntype == KT_APPLE_NEW )
586 {
587 // create a glyph -> character mapping
588 ::std::hash_map< sal_uInt16, sal_Unicode > aGlyphMap;
589 ::std::hash_map< sal_uInt16, sal_Unicode >::iterator left, right;
590 for( i = 21; i < 0xfffd; i++ )
591 {
592 sal_uInt16 nGlyph = MapChar( pTTFont, (sal_Unicode)i, 0 ); // kerning for horz only
593 if( nGlyph != 0 )
594 aGlyphMap[ nGlyph ] = (sal_Unicode)i;
595 }
596
597 // Loop through each of the 'kern' subtables
598 KernPair aPair;
599 for( i = 0; (unsigned int)i < pImplTTFont->nkern; i++ )
600 {
601 const sal_uInt8* pTable = pImplTTFont->kerntables[i];
602
603 /*sal_uInt32 nLength =*/ getUInt32BE( pTable );
604 sal_uInt16 nCoverage = getUInt16BE( pTable );
605 /*sal_uInt16 nTupleIndex =*/ getUInt16BE( pTable );
606
607 // Get kerning type
608 // sal_Bool bKernVertical = nCoverage & 0x8000;
609 // sal_Bool bKernCrossStream = nCoverage & 0x4000;
610 // sal_Bool bKernVariation = nCoverage & 0x2000;
611
612 // Kerning sub-table format, 0 through 3
613 sal_uInt8 nSubTableFormat = nCoverage & 0x00FF;
614
615 aPair.kern_x = 0;
616 aPair.kern_y = 0;
617 switch( nSubTableFormat )
618 {
619 case 0:
620 {
621 // Grab the # of kern pairs but skip over the:
622 // searchRange
623 // entrySelector
624 // rangeShift
625 sal_uInt16 nPairs = getUInt16BE( pTable );
626 pTable += 6;
627
628 for( int n = 0; n < nPairs; n++ )
629 {
630 sal_uInt16 nLeftGlyph = getUInt16BE( pTable );
631 sal_uInt16 nRightGlyph = getUInt16BE( pTable );
632 sal_Int16 nKern = (sal_Int16)getUInt16BE( pTable );
633
634 left = aGlyphMap.find( nLeftGlyph );
635 right = aGlyphMap.find( nRightGlyph );
636 if( left != aGlyphMap.end() && right != aGlyphMap.end() )
637 {
638 aPair.first = left->second;
639 aPair.second = right->second;
640
641 // Only support horizontal kerning for now
642 aPair.kern_x = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
643 aPair.kern_y = 0;
644 m_pMetrics->m_aXKernPairs.push_back( aPair );
645
646 /* switch( nCoverage & 1 )
647 {
648 case 1:
649 aPair.kern_x = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
650 m_pMetrics->m_aXKernPairs.push_back( aPair );
651 break;
652 case 0:
653 aPair.kern_y = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
654 m_pMetrics->m_aYKernPairs.push_back( aPair );
655 break;
656 }
657 */
658 }
659 }
660 }
661 break;
662
663 case 2:
664 {
665 const sal_uInt8* pSubTable = pTable;
666 /*sal_uInt16 nRowWidth =*/ getUInt16BE( pTable );
667 sal_uInt16 nOfLeft = getUInt16BE( pTable );
668 sal_uInt16 nOfRight = getUInt16BE( pTable );
669 /*sal_uInt16 nOfArray =*/ getUInt16BE( pTable );
670 const sal_uInt8* pTmp = pSubTable + nOfLeft;
671 sal_uInt16 nFirstLeft = getUInt16BE( pTmp );
672 sal_uInt16 nLastLeft = getUInt16BE( pTmp ) + nFirstLeft - 1;
673 pTmp = pSubTable + nOfRight;
674 sal_uInt16 nFirstRight = getUInt16BE( pTmp );
675 sal_uInt16 nLastRight = getUInt16BE( pTmp ) + nFirstRight -1;
676
677 for( aPair.first = nFirstLeft; aPair.first < nLastLeft; aPair.first++ )
678 {
679 for( aPair.second = 0; aPair.second < nLastRight; aPair.second++ )
680 {
681 sal_Int16 nKern = (sal_Int16)getUInt16BE( pTmp );
682 switch( nCoverage & 1 )
683 {
684 case 1:
685 aPair.kern_x = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
686 m_pMetrics->m_aXKernPairs.push_back( aPair );
687 break;
688 case 0:
689 aPair.kern_y = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
690 m_pMetrics->m_aYKernPairs.push_back( aPair );
691 break;
692 }
693 }
694 }
695 }
696 break;
697
698 default:
699 fprintf( stderr, "Found unsupported Apple-style kern subtable type %d.\n", nSubTableFormat );
700 break;
701 }
702 }
703 }
704
705 #if OSL_DEBUG_LEVEL > 1
706 fprintf( stderr, "found %d/%d kern pairs for %s\n",
707 m_pMetrics->m_aXKernPairs.size(),
708 m_pMetrics->m_aYKernPairs.size(),
709 OUStringToOString( pProvider->getString( ATOM_FAMILYNAME, m_nFamilyName ), RTL_TEXTENCODING_MS_1252 ).getStr() );
710 #else
711 (void) pProvider; /* avoid warnings */
712 #endif
713 }
714
715 CloseTTFont( pTTFont );
716 bSuccess = true;
717 }
718 return bSuccess;
719 }
720
721 // -------------------------------------------------------------------------
722
723 /* #i73387# There seem to be fonts with a rather unwell chosen family name
724 * consider e.g. "Helvetica Narrow" which defines its family as "Helvetica"
725 * It can really only be distinguished by its PSName and FullName. Both of
726 * which are not user presentable in OOo. So replace it by something sensible.
727 *
728 * If other fonts feature this behaviour, insert them to the map.
729 */
familyNameOverride(const OUString & i_rPSname,OUString & o_rFamilyName)730 static bool familyNameOverride( const OUString& i_rPSname, OUString& o_rFamilyName )
731 {
732 static std::hash_map< OUString, OUString, OUStringHash > aPSNameToFamily( 16 );
733 if( aPSNameToFamily.empty() ) // initialization
734 {
735 aPSNameToFamily[ OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica-Narrow" ) ) ] =
736 OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica Narrow" ) );
737 aPSNameToFamily[ OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica-Narrow-Bold" ) ) ] =
738 OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica Narrow" ) );
739 aPSNameToFamily[ OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica-Narrow-BoldOblique" ) ) ] =
740 OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica Narrow" ) );
741 aPSNameToFamily[ OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica-Narrow-Oblique" ) ) ] =
742 OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica Narrow" ) );
743 }
744 std::hash_map<OUString,OUString,OUStringHash>::const_iterator it =
745 aPSNameToFamily.find( i_rPSname );
746 bool bReplaced = (it != aPSNameToFamily.end() );
747 if( bReplaced )
748 o_rFamilyName = it->second;
749 return bReplaced;
750 };
751
readAfmMetrics(const OString & rFileName,MultiAtomProvider * pProvider,bool bFillEncodingvector,bool bOnlyGlobalAttributes)752 bool PrintFontManager::PrintFont::readAfmMetrics( const OString& rFileName, MultiAtomProvider* pProvider, bool bFillEncodingvector, bool bOnlyGlobalAttributes )
753 {
754 PrintFontManager& rManager( PrintFontManager::get() );
755
756 int i;
757 FontInfo* pInfo = NULL;
758 parseFile( rFileName.getStr(), &pInfo, P_ALL );
759 if( ! pInfo || ! pInfo->numOfChars )
760 {
761 if( pInfo )
762 freeFontInfo( pInfo );
763 return false;
764 }
765
766 m_aEncodingVector.clear();
767 // fill in global info
768
769 // PSName
770 OUString aPSName( OStringToOUString( pInfo->gfi->fontName, RTL_TEXTENCODING_ISO_8859_1 ) );
771 m_nPSName = pProvider->getAtom( ATOM_PSNAME, aPSName, sal_True );
772
773 // family name (if not already set)
774 OUString aFamily;
775 if( ! m_nFamilyName )
776 {
777 aFamily = OStringToOUString( pInfo->gfi->familyName, RTL_TEXTENCODING_ISO_8859_1 );
778 if( ! aFamily.getLength() )
779 {
780 aFamily = OStringToOUString( pInfo->gfi->fontName, RTL_TEXTENCODING_ISO_8859_1 );
781 sal_Int32 nIndex = 0;
782 aFamily = aFamily.getToken( 0, '-', nIndex );
783 }
784 familyNameOverride( aPSName, aFamily );
785 m_nFamilyName = pProvider->getAtom( ATOM_FAMILYNAME, aFamily, sal_True );
786 }
787 else
788 aFamily = pProvider->getString( ATOM_FAMILYNAME, m_nFamilyName );
789
790 // style name: if fullname begins with family name
791 // interpret the rest of fullname as style
792 if( ! m_aStyleName.getLength() && pInfo->gfi->fullName && *pInfo->gfi->fullName )
793 {
794 OUString aFullName( OStringToOUString( pInfo->gfi->fullName, RTL_TEXTENCODING_ISO_8859_1 ) );
795 if( aFullName.indexOf( aFamily ) == 0 )
796 m_aStyleName = WhitespaceToSpace( aFullName.copy( aFamily.getLength() ) );
797 }
798
799 // italic
800 if( pInfo->gfi->italicAngle > 0 )
801 m_eItalic = italic::Oblique;
802 else if( pInfo->gfi->italicAngle < 0 )
803 m_eItalic = italic::Italic;
804 else
805 m_eItalic = italic::Upright;
806
807 // weight
808 ByteString aLowerWeight( pInfo->gfi->weight );
809 aLowerWeight.ToLowerAscii();
810 m_eWeight = parseWeight( aLowerWeight );
811
812 // pitch
813 m_ePitch = pInfo->gfi->isFixedPitch ? pitch::Fixed : pitch::Variable;
814
815 // encoding - only set if unknown
816 int nAdobeEncoding = 0;
817 if( pInfo->gfi->encodingScheme )
818 {
819 if( !strcmp( pInfo->gfi->encodingScheme, "AdobeStandardEncoding" ) )
820 nAdobeEncoding = 1;
821 else if( !strcmp( pInfo->gfi->encodingScheme, "ISO10646-1" ) )
822 {
823 nAdobeEncoding = 1;
824 m_aEncoding = RTL_TEXTENCODING_UNICODE;
825 }
826 else if( !strcmp( pInfo->gfi->encodingScheme, "Symbol") )
827 nAdobeEncoding = 2;
828 else if( !strcmp( pInfo->gfi->encodingScheme, "FontSpecific") )
829 nAdobeEncoding = 3;
830
831 if( m_aEncoding == RTL_TEXTENCODING_DONTKNOW )
832 m_aEncoding = nAdobeEncoding == 1 ?
833 RTL_TEXTENCODING_ADOBE_STANDARD : RTL_TEXTENCODING_SYMBOL;
834 }
835 else if( m_aEncoding == RTL_TEXTENCODING_DONTKNOW )
836 m_aEncoding = RTL_TEXTENCODING_ADOBE_STANDARD;
837
838 // try to parse the font name and decide whether it might be a
839 // japanese font. Who invented this PITA ?
840 OUString aPSNameLastToken( aPSName.copy( aPSName.lastIndexOf( '-' )+1 ) );
841 if( ! aPSNameLastToken.compareToAscii( "H" ) ||
842 ! aPSNameLastToken.compareToAscii( "V" ) )
843 {
844 static const char* pEncs[] =
845 {
846 "EUC",
847 "RKSJ",
848 "SJ"
849 };
850 static const rtl_TextEncoding aEncs[] =
851 {
852 RTL_TEXTENCODING_EUC_JP,
853 RTL_TEXTENCODING_SHIFT_JIS,
854 RTL_TEXTENCODING_JIS_X_0208
855 };
856
857 for( unsigned int enc = 0; enc < sizeof( aEncs )/sizeof(aEncs[0]) && m_aEncoding == RTL_TEXTENCODING_DONTKNOW; enc++ )
858 {
859 sal_Int32 nIndex = 0, nOffset = 1;
860 do
861 {
862 OUString aToken( aPSName.getToken( nOffset, '-', nIndex ) );
863 if( nIndex == -1 )
864 break;
865 nOffset = 0;
866 if( ! aToken.compareToAscii( pEncs[enc] ) )
867 {
868 m_aEncoding = aEncs[ enc ];
869 m_bFontEncodingOnly = true;
870 }
871 } while( nIndex != -1 );
872 }
873
874 // default is jis
875 if( m_aEncoding == RTL_TEXTENCODING_DONTKNOW )
876 m_aEncoding = RTL_TEXTENCODING_JIS_X_0208;
877 #if OSL_DEBUG_LEVEL > 1
878 fprintf( stderr, "Encoding %d for %s\n", m_aEncoding, pInfo->gfi->fontName );
879 #endif
880 }
881
882 // hack for GB encoded builtin fonts posing as FontSpecific
883 if( m_eType == fonttype::Builtin && ( nAdobeEncoding == 3 || nAdobeEncoding == 0 ) )
884 {
885 int nLen = aFamily.getLength();
886 if( nLen > 2 &&
887 aFamily.getStr()[ nLen-2 ] == 'G' &&
888 aFamily.getStr()[ nLen-1 ] == 'B' &&
889 pInfo->numOfChars > 255 )
890 {
891 m_aEncoding = RTL_TEXTENCODING_GBK;
892 m_bFontEncodingOnly = true;
893 #if OSL_DEBUG_LEVEL > 1
894 fprintf( stderr, "found builtin font %s with GBK encoding\n", pInfo->gfi->fontName );
895 #endif
896 }
897 }
898
899 // #i37313# check if Fontspecific is not rather some character encoding
900 if( nAdobeEncoding == 3 && m_aEncoding == RTL_TEXTENCODING_SYMBOL )
901 {
902 bool bYFound = false;
903 bool bQFound = false;
904 CharMetricInfo* pChar = pInfo->cmi;
905 for( int j = 0; j < pInfo->numOfChars && ! (bYFound && bQFound); j++ )
906 {
907 if( pChar[j].name )
908 {
909 if( pChar[j].name[0] == 'Y' && pChar[j].name[1] == 0 )
910 bYFound = true;
911 else if( pChar[j].name[0] == 'Q' && pChar[j].name[1] == 0 )
912 bQFound = true;
913 }
914 }
915 if( bQFound && bYFound )
916 {
917 #if OSL_DEBUG_LEVEL > 1
918 fprintf( stderr, "setting FontSpecific font %s (file %s) to unicode\n",
919 pInfo->gfi->fontName,
920 rFileName.getStr()
921 );
922 #endif
923 nAdobeEncoding = 4;
924 m_aEncoding = RTL_TEXTENCODING_UNICODE;
925 bFillEncodingvector = false; // will be filled anyway, don't do the work twice
926 }
927 }
928
929 // ascend
930 m_nAscend = pInfo->gfi->fontBBox.ury;
931
932 // descend
933 // descends have opposite sign of our definition
934 m_nDescend = -pInfo->gfi->fontBBox.lly;
935
936 // fallback to ascender, descender
937 // interesting: the BBox seems to describe Ascender and Descender better
938 // as we understand it
939 if( m_nAscend == 0 )
940 m_nAscend = pInfo->gfi->ascender;
941 if( m_nDescend == 0)
942 m_nDescend = -pInfo->gfi->descender;
943
944 m_nLeading = m_nAscend + m_nDescend - 1000;
945
946 if( m_pMetrics )
947 delete m_pMetrics;
948 m_pMetrics = new PrintFontMetrics;
949 // mark all pages as queried (or clear if only global font info queiried)
950 memset( m_pMetrics->m_aPages, bOnlyGlobalAttributes ? 0 : 0xff, sizeof( m_pMetrics->m_aPages ) );
951
952 m_aGlobalMetricX.width = m_aGlobalMetricY.width =
953 pInfo->gfi->charwidth ? pInfo->gfi->charwidth : pInfo->gfi->fontBBox.urx;
954 m_aGlobalMetricX.height = m_aGlobalMetricY.height =
955 pInfo->gfi->capHeight ? pInfo->gfi->capHeight : pInfo->gfi->fontBBox.ury;
956
957 m_nXMin = pInfo->gfi->fontBBox.llx;
958 m_nYMin = pInfo->gfi->fontBBox.lly;
959 m_nXMax = pInfo->gfi->fontBBox.urx;
960 m_nYMax = pInfo->gfi->fontBBox.ury;
961
962 if( bFillEncodingvector || !bOnlyGlobalAttributes )
963 {
964 // fill in character metrics
965
966 // first transform the character codes to unicode
967 // note: this only works with single byte encodings
968 sal_Unicode* pUnicodes = (sal_Unicode*)alloca( pInfo->numOfChars * sizeof(sal_Unicode));
969 CharMetricInfo* pChar = pInfo->cmi;
970
971 for( i = 0; i < pInfo->numOfChars; i++, pChar++ )
972 {
973 if( nAdobeEncoding == 4 )
974 {
975 if( pChar->name )
976 {
977 pUnicodes[i] = 0;
978 std::list< sal_Unicode > aCodes = rManager.getUnicodeFromAdobeName( pChar->name );
979 for( std::list< sal_Unicode >::const_iterator it = aCodes.begin(); it != aCodes.end(); ++it )
980 {
981 if( *it != 0 )
982 {
983 m_aEncodingVector[ *it ] = pChar->code;
984 if( pChar->code == -1 )
985 m_aNonEncoded[ *it ] = pChar->name;
986 if( ! pUnicodes[i] ) // map the first
987 pUnicodes[i] = *it;
988 }
989 }
990 }
991 }
992 else if( pChar->code != -1 )
993 {
994 if( nAdobeEncoding == 3 && m_aEncoding == RTL_TEXTENCODING_SYMBOL )
995 {
996 pUnicodes[i] = pChar->code + 0xf000;
997 if( bFillEncodingvector )
998 m_aEncodingVector[ pUnicodes[i] ] = pChar->code;
999 continue;
1000 }
1001
1002 if( m_aEncoding == RTL_TEXTENCODING_UNICODE )
1003 {
1004 pUnicodes[i] = (sal_Unicode)pChar->code;
1005 continue;
1006 }
1007
1008 ByteString aTranslate;
1009 if( pChar->code & 0xff000000 )
1010 aTranslate += (char)(pChar->code >> 24 );
1011 if( pChar->code & 0xffff0000 )
1012 aTranslate += (char)((pChar->code & 0x00ff0000) >> 16 );
1013 if( pChar->code & 0xffffff00 )
1014 aTranslate += (char)((pChar->code & 0x0000ff00) >> 8 );
1015 aTranslate += (char)(pChar->code & 0xff);
1016 String aUni( aTranslate, m_aEncoding );
1017 pUnicodes[i] = *aUni.GetBuffer();
1018 }
1019 else
1020 pUnicodes[i] = 0;
1021 }
1022
1023 // now fill in the character metrics
1024 // parseAFM.cxx effectively only supports direction 0 (horizontal)
1025 pChar = pInfo->cmi;
1026 CharacterMetric aMetric;
1027 for( i = 0; i < pInfo->numOfChars; i++, pChar++ )
1028 {
1029 if( pChar->code == -1 && ! pChar->name )
1030 continue;
1031
1032 if( bFillEncodingvector && pChar->name )
1033 {
1034 std::list< sal_Unicode > aCodes = rManager.getUnicodeFromAdobeName( pChar->name );
1035 for( std::list< sal_Unicode >::const_iterator it = aCodes.begin(); it != aCodes.end(); ++it )
1036 {
1037 if( *it != 0 )
1038 {
1039 m_aEncodingVector[ *it ] = pChar->code;
1040 if( pChar->code == -1 )
1041 m_aNonEncoded[ *it ] = pChar->name;
1042 }
1043 }
1044 }
1045
1046 aMetric.width = pChar->wx ? pChar->wx : pChar->charBBox.urx;
1047 aMetric.height = pChar->wy ? pChar->wy : pChar->charBBox.ury - pChar->charBBox.lly;
1048 if( aMetric.width == 0 && aMetric.height == 0 )
1049 // guess something for e.g. space
1050 aMetric.width = m_aGlobalMetricX.width/4;
1051
1052 if( ( nAdobeEncoding == 0 ) ||
1053 ( ( nAdobeEncoding == 3 ) && ( m_aEncoding != RTL_TEXTENCODING_SYMBOL ) ) )
1054 {
1055 if( pChar->code != -1 )
1056 {
1057 m_pMetrics->m_aMetrics[ pUnicodes[i] ] = aMetric;
1058 if( bFillEncodingvector )
1059 m_aEncodingVector[ pUnicodes[i] ] = pChar->code;
1060 }
1061 else if( pChar->name )
1062 {
1063 std::list< sal_Unicode > aCodes = rManager.getUnicodeFromAdobeName( pChar->name );
1064 for( std::list< sal_Unicode >::const_iterator it = aCodes.begin(); it != aCodes.end(); ++it )
1065 {
1066 if( *it != 0 )
1067 m_pMetrics->m_aMetrics[ *it ] = aMetric;
1068 }
1069 }
1070 }
1071 else if( nAdobeEncoding == 1 || nAdobeEncoding == 2 || nAdobeEncoding == 4)
1072 {
1073 if( pChar->name )
1074 {
1075 std::list< sal_Unicode > aCodes = rManager.getUnicodeFromAdobeName( pChar->name );
1076 for( std::list< sal_Unicode >::const_iterator it = aCodes.begin(); it != aCodes.end(); ++it )
1077 {
1078 if( *it != 0 )
1079 m_pMetrics->m_aMetrics[ *it ] = aMetric;
1080 }
1081 }
1082 else if( pChar->code != -1 )
1083 {
1084 ::std::pair< ::std::hash_multimap< sal_uInt8, sal_Unicode >::const_iterator,
1085 ::std::hash_multimap< sal_uInt8, sal_Unicode >::const_iterator >
1086 aCodes = rManager.getUnicodeFromAdobeCode( pChar->code );
1087 while( aCodes.first != aCodes.second )
1088 {
1089 if( (*aCodes.first).second != 0 )
1090 {
1091 m_pMetrics->m_aMetrics[ (*aCodes.first).second ] = aMetric;
1092 if( bFillEncodingvector )
1093 m_aEncodingVector[ (*aCodes.first).second ] = pChar->code;
1094 }
1095 ++aCodes.first;
1096 }
1097 }
1098 }
1099 else if( nAdobeEncoding == 3 )
1100 {
1101 if( pChar->code != -1 )
1102 {
1103 sal_Unicode code = 0xf000 + pChar->code;
1104 m_pMetrics->m_aMetrics[ code ] = aMetric;
1105 // maybe should try to find the name in the convtabs ?
1106 if( bFillEncodingvector )
1107 m_aEncodingVector[ code ] = pChar->code;
1108 }
1109 }
1110 }
1111
1112 m_pMetrics->m_aXKernPairs.clear();
1113 m_pMetrics->m_aYKernPairs.clear();
1114
1115 // now fill in the kern pairs
1116 // parseAFM.cxx effectively only supports direction 0 (horizontal)
1117 PairKernData* pKern = pInfo->pkd;
1118 KernPair aPair;
1119 for( i = 0; i < pInfo->numOfPairs; i++, pKern++ )
1120 {
1121 // #i37703# broken kern table
1122 if( ! pKern->name1 || ! pKern->name2 )
1123 continue;
1124
1125 aPair.first = 0;
1126 aPair.second = 0;
1127 // currently we have to find the adobe character names
1128 // in the already parsed character metrics to find
1129 // the corresponding UCS2 code which is a bit dangerous
1130 // since the character names are not required
1131 // in the metric descriptions
1132 pChar = pInfo->cmi;
1133 for( int j = 0;
1134 j < pInfo->numOfChars && ( aPair.first == 0 || aPair.second == 0 );
1135 j++, pChar++ )
1136 {
1137 if( pChar->code != -1 )
1138 {
1139 if( ! strcmp( pKern->name1, pChar->name ? pChar->name : "" ) )
1140 aPair.first = pUnicodes[ j ];
1141 if( ! strcmp( pKern->name2, pChar->name ? pChar->name : "" ) )
1142 aPair.second = pUnicodes[ j ];
1143 }
1144 }
1145 if( aPair.first && aPair.second )
1146 {
1147 aPair.kern_x = pKern->xamt;
1148 aPair.kern_y = pKern->yamt;
1149 m_pMetrics->m_aXKernPairs.push_back( aPair );
1150 }
1151 }
1152 m_pMetrics->m_bKernPairsQueried = true;
1153 }
1154
1155 freeFontInfo( pInfo );
1156 return true;
1157 }
1158
1159 // -------------------------------------------------------------------------
1160
1161 OString PrintFontManager::s_aEmptyOString;
1162
1163 /*
1164 * one instance only
1165 */
get()1166 PrintFontManager& PrintFontManager::get()
1167 {
1168 static PrintFontManager* theManager = NULL;
1169 if( ! theManager )
1170 {
1171 theManager = new PrintFontManager();
1172 theManager->initialize();
1173 }
1174 return *theManager;
1175 }
1176
1177 // -------------------------------------------------------------------------
1178
1179 /*
1180 * the PrintFontManager
1181 */
1182
PrintFontManager()1183 PrintFontManager::PrintFontManager() :
1184 m_nNextFontID( 1 ),
1185 m_pAtoms( new MultiAtomProvider() ),
1186 m_nNextDirAtom( 1 ),
1187 m_pFontCache( NULL ),
1188 m_bFontconfigSuccess( false )
1189 {
1190 for( unsigned int i = 0; i < sizeof( aAdobeCodes )/sizeof( aAdobeCodes[0] ); i++ )
1191 {
1192 m_aUnicodeToAdobename.insert( ::std::hash_multimap< sal_Unicode, ::rtl::OString >::value_type( aAdobeCodes[i].aUnicode, aAdobeCodes[i].pAdobename ) );
1193 m_aAdobenameToUnicode.insert( ::std::hash_multimap< ::rtl::OString, sal_Unicode, ::rtl::OStringHash >::value_type( aAdobeCodes[i].pAdobename, aAdobeCodes[i].aUnicode ) );
1194 if( aAdobeCodes[i].aAdobeStandardCode )
1195 {
1196 m_aUnicodeToAdobecode.insert( ::std::hash_multimap< sal_Unicode, sal_uInt8 >::value_type( aAdobeCodes[i].aUnicode, aAdobeCodes[i].aAdobeStandardCode ) );
1197 m_aAdobecodeToUnicode.insert( ::std::hash_multimap< sal_uInt8, sal_Unicode >::value_type( aAdobeCodes[i].aAdobeStandardCode, aAdobeCodes[i].aUnicode ) );
1198 }
1199 #if 0
1200 m_aUnicodeToAdobename[ aAdobeCodes[i].aUnicode ] = aAdobeCodes[i].pAdobename;
1201 m_aAdobenameToUnicode[ aAdobeCodes[i].pAdobename ] = aAdobeCodes[i].aUnicode;
1202 if( aAdobeCodes[i].aAdobeStandardCode )
1203 {
1204 m_aUnicodeToAdobecode[ aAdobeCodes[i].aUnicode ] = aAdobeCodes[i].aAdobeStandardCode;
1205 m_aAdobecodeToUnicode[ aAdobeCodes[i].aAdobeStandardCode ] = aAdobeCodes[i].aUnicode;
1206 }
1207 #endif
1208 }
1209 }
1210
1211 // -------------------------------------------------------------------------
1212
~PrintFontManager()1213 PrintFontManager::~PrintFontManager()
1214 {
1215 deinitFontconfig();
1216 for( ::std::hash_map< fontID, PrintFont* >::const_iterator it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
1217 delete (*it).second;
1218 delete m_pAtoms;
1219 if( m_pFontCache )
1220 delete m_pFontCache;
1221 }
1222
1223 // -------------------------------------------------------------------------
1224
getDirectory(int nAtom) const1225 const OString& PrintFontManager::getDirectory( int nAtom ) const
1226 {
1227 ::std::hash_map< int, OString >::const_iterator it( m_aAtomToDir.find( nAtom ) );
1228 return it != m_aAtomToDir.end() ? it->second : s_aEmptyOString;
1229 }
1230
1231 // -------------------------------------------------------------------------
1232
getDirectoryAtom(const OString & rDirectory,bool bCreate)1233 int PrintFontManager::getDirectoryAtom( const OString& rDirectory, bool bCreate )
1234 {
1235 int nAtom = 0;
1236 ::std::hash_map< OString, int, OStringHash >::const_iterator it
1237 ( m_aDirToAtom.find( rDirectory ) );
1238 if( it != m_aDirToAtom.end() )
1239 nAtom = it->second;
1240 else if( bCreate )
1241 {
1242 nAtom = m_nNextDirAtom++;
1243 m_aDirToAtom[ rDirectory ] = nAtom;
1244 m_aAtomToDir[ nAtom ] = rDirectory;
1245 }
1246 return nAtom;
1247 }
1248
1249 // -------------------------------------------------------------------------
1250
addFontFile(const::rtl::OString & rFileName,int)1251 int PrintFontManager::addFontFile( const ::rtl::OString& rFileName, int /*nFaceNum*/ )
1252 {
1253 rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
1254 INetURLObject aPath( OStringToOUString( rFileName, aEncoding ), INET_PROT_FILE, INetURLObject::ENCODE_ALL );
1255 OString aName( OUStringToOString( aPath.GetName(), aEncoding ) );
1256 OString aDir( OUStringToOString( aPath.GetPath(), aEncoding ) );
1257
1258 int nDirID = getDirectoryAtom( aDir, true );
1259 fontID nFontId = findFontFileID( nDirID, aName );
1260 if( !nFontId )
1261 {
1262 ::std::list< PrintFont* > aNewFonts;
1263 if( analyzeFontFile( nDirID, aName, ::std::list<OString>(), aNewFonts ) )
1264 {
1265 for( ::std::list< PrintFont* >::iterator it = aNewFonts.begin();
1266 it != aNewFonts.end(); ++it )
1267 {
1268 m_aFonts[ nFontId = m_nNextFontID++ ] = *it;
1269 m_aFontFileToFontID[ aName ].insert( nFontId );
1270 m_pFontCache->updateFontCacheEntry( *it, true );
1271 }
1272 }
1273 }
1274 return nFontId;
1275 }
1276
1277 // -------------------------------------------------------------------------
1278
analyzeFontFile(int nDirID,const OString & rFontFile,const::std::list<OString> & rXLFDs,::std::list<PrintFontManager::PrintFont * > & rNewFonts) const1279 bool PrintFontManager::analyzeFontFile( int nDirID, const OString& rFontFile, const ::std::list<OString>& rXLFDs, ::std::list< PrintFontManager::PrintFont* >& rNewFonts ) const
1280 {
1281 rNewFonts.clear();
1282
1283 OString aDir( getDirectory( nDirID ) );
1284
1285 OString aFullPath( aDir );
1286 aFullPath += "/";
1287 aFullPath += rFontFile;
1288
1289 // #i1872# reject unreadable files
1290 if( access( aFullPath.getStr(), R_OK ) )
1291 return false;
1292
1293 ByteString aExt( rFontFile.copy( rFontFile.lastIndexOf( '.' )+1 ) );
1294 if( aExt.EqualsIgnoreCaseAscii( "pfb" ) || aExt.EqualsIgnoreCaseAscii( "pfa" ) )
1295 {
1296 // check for corresponding afm metric
1297 // first look for an adjacent file
1298 static const char* pSuffix[] = { ".afm", ".AFM" };
1299
1300 for( unsigned int i = 0; i < sizeof(pSuffix)/sizeof(pSuffix[0]); i++ )
1301 {
1302 ByteString aName( rFontFile );
1303 aName.Erase( aName.Len()-4 );
1304 aName.Append( pSuffix[i] );
1305
1306 ByteString aFilePath( aDir );
1307 aFilePath.Append( '/' );
1308 aFilePath.Append( aName );
1309
1310 ByteString aAfmFile;
1311 if( access( aFilePath.GetBuffer(), R_OK ) )
1312 {
1313 // try in subdirectory afm instead
1314 aFilePath = aDir;
1315 aFilePath.Append( "/afm/" );
1316 aFilePath.Append( aName );
1317
1318 if( ! access( aFilePath.GetBuffer(), R_OK ) )
1319 {
1320 aAfmFile = "afm/";
1321 aAfmFile += aName;
1322 }
1323 }
1324 else
1325 aAfmFile = aName;
1326
1327 if( aAfmFile.Len() )
1328 {
1329 Type1FontFile* pFont = new Type1FontFile();
1330 pFont->m_nDirectory = nDirID;
1331
1332 pFont->m_aFontFile = rFontFile;
1333 pFont->m_aMetricFile = aAfmFile;
1334
1335 if( ! pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, true ) )
1336 {
1337 delete pFont;
1338 pFont = NULL;
1339 }
1340 if( pFont && rXLFDs.size() )
1341 getFontAttributesFromXLFD( pFont, rXLFDs );
1342 if( pFont )
1343 rNewFonts.push_back( pFont );
1344 break;
1345 }
1346 }
1347 }
1348 else if( aExt.EqualsIgnoreCaseAscii( "afm" ) )
1349 {
1350 ByteString aFilePath( aDir );
1351 aFilePath.Append( '/' );
1352 aFilePath.Append( ByteString( rFontFile ) );
1353 BuiltinFont* pFont = new BuiltinFont();
1354 pFont->m_nDirectory = nDirID;
1355 pFont->m_aMetricFile = rFontFile;
1356 if( pFont->readAfmMetrics( aFilePath, m_pAtoms, false, true ) )
1357 rNewFonts.push_back( pFont );
1358 else
1359 delete pFont;
1360 }
1361 else if( aExt.EqualsIgnoreCaseAscii( "ttf" )
1362 || aExt.EqualsIgnoreCaseAscii( "tte" ) // #i33947# for Gaiji support
1363 || aExt.EqualsIgnoreCaseAscii( "otf" ) ) // check for TTF- and PS-OpenType too
1364 {
1365 TrueTypeFontFile* pFont = new TrueTypeFontFile();
1366 pFont->m_nDirectory = nDirID;
1367 pFont->m_aFontFile = rFontFile;
1368 pFont->m_nCollectionEntry = -1;
1369
1370 if( rXLFDs.size() )
1371 getFontAttributesFromXLFD( pFont, rXLFDs );
1372 // need to read the font anyway to get aliases inside the font file
1373 if( ! analyzeTrueTypeFile( pFont ) )
1374 {
1375 delete pFont;
1376 pFont = NULL;
1377 }
1378 else
1379 rNewFonts.push_back( pFont );
1380 }
1381 else if( aExt.EqualsIgnoreCaseAscii( "ttc" ) )
1382 {
1383 // get number of ttc entries
1384 int nLength = CountTTCFonts( aFullPath.getStr() );
1385 if( nLength )
1386 {
1387 #if OSL_DEBUG_LEVEL > 1
1388 fprintf( stderr, "%s contains %d fonts\n", aFullPath.getStr(), nLength );
1389 #endif
1390 for( int i = 0; i < nLength; i++ )
1391 {
1392 TrueTypeFontFile* pFont = new TrueTypeFontFile();
1393 pFont->m_nDirectory = nDirID;
1394 pFont->m_aFontFile = rFontFile;
1395 pFont->m_nCollectionEntry = i;
1396 if( nLength == 1 )
1397 getFontAttributesFromXLFD( pFont, rXLFDs );
1398 if( ! analyzeTrueTypeFile( pFont ) )
1399 {
1400 delete pFont;
1401 pFont = NULL;
1402 }
1403 else
1404 rNewFonts.push_back( pFont );
1405 }
1406 }
1407 #if OSL_DEBUG_LEVEL > 1
1408 else
1409 fprintf( stderr, "CountTTCFonts( \"%s/%s\" ) failed\n", getDirectory(nDirID).getStr(), rFontFile.getStr() );
1410 #endif
1411 }
1412 return ! rNewFonts.empty();
1413 }
1414
1415 // -------------------------------------------------------------------------
1416
findFontBuiltinID(int nPSNameAtom) const1417 fontID PrintFontManager::findFontBuiltinID( int nPSNameAtom ) const
1418 {
1419 fontID nID = 0;
1420 ::std::hash_map< fontID, PrintFont* >::const_iterator it;
1421 for( it = m_aFonts.begin(); nID == 0 && it != m_aFonts.end(); ++it )
1422 {
1423 if( it->second->m_eType == fonttype::Builtin &&
1424 it->second->m_nPSName == nPSNameAtom )
1425 nID = it->first;
1426 }
1427 return nID;
1428 }
1429
1430 // -------------------------------------------------------------------------
1431
findFontFileID(int nDirID,const OString & rFontFile) const1432 fontID PrintFontManager::findFontFileID( int nDirID, const OString& rFontFile ) const
1433 {
1434 fontID nID = 0;
1435
1436 ::std::hash_map< OString, ::std::set< fontID >, OStringHash >::const_iterator set_it = m_aFontFileToFontID.find( rFontFile );
1437 if( set_it != m_aFontFileToFontID.end() )
1438 {
1439 for( ::std::set< fontID >::const_iterator font_it = set_it->second.begin(); font_it != set_it->second.end() && ! nID; ++font_it )
1440 {
1441 ::std::hash_map< fontID, PrintFont* >::const_iterator it = m_aFonts.find( *font_it );
1442 if( it != m_aFonts.end() )
1443 {
1444 switch( it->second->m_eType )
1445 {
1446 case fonttype::Type1:
1447 {
1448 Type1FontFile* const pFont = static_cast< Type1FontFile* const >((*it).second);
1449 if( pFont->m_nDirectory == nDirID &&
1450 pFont->m_aFontFile == rFontFile )
1451 nID = it->first;
1452 }
1453 break;
1454 case fonttype::TrueType:
1455 {
1456 TrueTypeFontFile* const pFont = static_cast< TrueTypeFontFile* const >((*it).second);
1457 if( pFont->m_nDirectory == nDirID &&
1458 pFont->m_aFontFile == rFontFile )
1459 nID = it->first;
1460 }
1461 break;
1462 case fonttype::Builtin:
1463 if( static_cast<const BuiltinFont*>((*it).second)->m_nDirectory == nDirID &&
1464 static_cast<const BuiltinFont*>((*it).second)->m_aMetricFile == rFontFile )
1465 nID = it->first;
1466 break;
1467 default:
1468 break;
1469 }
1470 }
1471 }
1472 }
1473 return nID;
1474 }
1475
1476 // -------------------------------------------------------------------------
1477
parseXLFD(const OString & rXLFD,XLFDEntry & rEntry)1478 bool PrintFontManager::parseXLFD( const OString& rXLFD, XLFDEntry& rEntry )
1479 {
1480 sal_Int32 nIndex = 0;
1481 OString aFoundry = WhitespaceToSpace( rXLFD.getToken( 1, '-', nIndex ) );
1482 if( nIndex < 0 ) return false;
1483 OString aFamilyXLFD = WhitespaceToSpace( rXLFD.getToken( 0, '-', nIndex ) );
1484 if( nIndex < 0 ) return false;
1485 OString aWeight = rXLFD.getToken( 0, '-', nIndex ).toAsciiLowerCase();
1486 if( nIndex < 0 ) return false;
1487 OString aSlant = rXLFD.getToken( 0, '-', nIndex ).toAsciiLowerCase();
1488 if( nIndex < 0 ) return false;
1489 OString aWidth = rXLFD.getToken( 0, '-', nIndex ).toAsciiLowerCase();
1490 if( nIndex < 0 ) return false;
1491 OString aAddStyle = rXLFD.getToken( 0, '-', nIndex ).toAsciiLowerCase();
1492 if( nIndex < 0 ) return false;
1493 OString aPitch = rXLFD.getToken( 4, '-', nIndex ).toAsciiLowerCase();
1494 if( nIndex < 0 ) return false;
1495 OString aRegEnc = WhitespaceToSpace( rXLFD.getToken( 1, '-', nIndex ).toAsciiLowerCase() );
1496 if( nIndex < 0 ) return false;
1497 OString aEnc = WhitespaceToSpace( rXLFD.getToken( 0, '-', nIndex ).toAsciiLowerCase() );
1498
1499 // capitalize words
1500 sal_Int32 nFamIndex = 0;
1501 OStringBuffer aFamilyName;
1502 while( nFamIndex >= 0 )
1503 {
1504 OString aToken = aFamilyXLFD.getToken( 0, ' ', nFamIndex );
1505 sal_Char aFirst = aToken.toChar();
1506 if( aFirst >= 'a' && aFirst <= 'z' )
1507 aFirst = aFirst - 'a' + 'A';
1508 OStringBuffer aNewToken( aToken.getLength() );
1509 aNewToken.append( aToken );
1510 aNewToken.setCharAt( 0, aFirst );
1511 if( aFamilyName.getLength() > 0 )
1512 aFamilyName.append( ' ' );
1513 aFamilyName.append( aNewToken.makeStringAndClear() );
1514 }
1515
1516 rEntry.aFoundry = aFoundry;
1517 rEntry.aFamily = aFamilyName.makeStringAndClear();
1518 rEntry.aAddStyle = aAddStyle;
1519 // evaluate weight
1520 rEntry.eWeight = parseWeight( aWeight );
1521 // evaluate slant
1522 rEntry.eItalic = parseItalic( aSlant );
1523 // evaluate width
1524 rEntry.eWidth = parseWidth( aWidth );
1525
1526 // evaluate pitch
1527 if( aPitch.toChar() == 'c' || aPitch.toChar() == 'm' )
1528 rEntry.ePitch = pitch::Fixed;
1529 else
1530 rEntry.ePitch = pitch::Variable;
1531
1532 OString aToken = aEnc.toAsciiLowerCase();
1533 // get encoding
1534 if( aAddStyle.indexOf( "symbol" ) != -1 )
1535 rEntry.aEncoding = RTL_TEXTENCODING_SYMBOL;
1536 else
1537 {
1538 if( aToken.equals( "symbol" ) )
1539 rEntry.aEncoding = RTL_TEXTENCODING_SYMBOL;
1540 else
1541 {
1542 OStringBuffer aCharset( aRegEnc.getLength() + aEnc.getLength() + 1 );
1543 aCharset.append( aRegEnc );
1544 aCharset.append( '-' );
1545 aCharset.append( aEnc );
1546 rEntry.aEncoding = rtl_getTextEncodingFromUnixCharset( aCharset.getStr() );
1547 }
1548 }
1549
1550 // set correct mask flags
1551 rEntry.nMask = 0;
1552 if( rEntry.aFoundry != "*" ) rEntry.nMask |= XLFDEntry::MaskFoundry;
1553 if( rEntry.aFamily != "*" ) rEntry.nMask |= XLFDEntry::MaskFamily;
1554 if( rEntry.aAddStyle != "*" ) rEntry.nMask |= XLFDEntry::MaskAddStyle;
1555 if( aWeight != "*" ) rEntry.nMask |= XLFDEntry::MaskWeight;
1556 if( aSlant != "*" ) rEntry.nMask |= XLFDEntry::MaskItalic;
1557 if( aWidth != "*" ) rEntry.nMask |= XLFDEntry::MaskWidth;
1558 if( aPitch != "*" ) rEntry.nMask |= XLFDEntry::MaskPitch;
1559 if( aRegEnc != "*" && aEnc != "*" ) rEntry.nMask |= XLFDEntry::MaskEncoding;
1560
1561 return true;
1562 }
1563
1564 // -------------------------------------------------------------------------
1565
parseXLFD_appendAliases(const std::list<OString> & rXLFDs,std::list<XLFDEntry> & rEntries) const1566 void PrintFontManager::parseXLFD_appendAliases( const std::list< OString >& rXLFDs, std::list< XLFDEntry >& rEntries ) const
1567 {
1568 for( std::list< OString >::const_iterator it = rXLFDs.begin(); it != rXLFDs.end(); ++it )
1569 {
1570 XLFDEntry aEntry;
1571 if( ! parseXLFD(*it, aEntry) )
1572 continue;
1573 rEntries.push_back( aEntry );
1574 std::map< XLFDEntry, std::list< XLFDEntry > >::const_iterator alias_it =
1575 m_aXLFD_Aliases.find( aEntry );
1576 if( alias_it != m_aXLFD_Aliases.end() )
1577 {
1578 rEntries.insert( rEntries.end(), alias_it->second.begin(), alias_it->second.end() );
1579 }
1580 }
1581 }
1582
1583 // -------------------------------------------------------------------------
1584
getFontAttributesFromXLFD(PrintFont * pFont,const std::list<OString> & rXLFDs) const1585 void PrintFontManager::getFontAttributesFromXLFD( PrintFont* pFont, const std::list< OString >& rXLFDs ) const
1586 {
1587 bool bFamilyName = false;
1588
1589 std::list< XLFDEntry > aXLFDs;
1590
1591 parseXLFD_appendAliases( rXLFDs, aXLFDs );
1592
1593 for( std::list< XLFDEntry >::const_iterator it = aXLFDs.begin();
1594 it != aXLFDs.end(); ++it )
1595 {
1596 // set family name or alias
1597 int nFam =
1598 m_pAtoms->getAtom( ATOM_FAMILYNAME,
1599 OStringToOUString( it->aFamily, it->aAddStyle.indexOf( "utf8" ) != -1 ? RTL_TEXTENCODING_UTF8 : RTL_TEXTENCODING_ISO_8859_1 ),
1600 sal_True );
1601 if( ! bFamilyName )
1602 {
1603 bFamilyName = true;
1604 pFont->m_nFamilyName = nFam;
1605 switch( pFont->m_eType )
1606 {
1607 case fonttype::Type1:
1608 static_cast<Type1FontFile*>(pFont)->m_aXLFD = rXLFDs.front();
1609 break;
1610 case fonttype::TrueType:
1611 static_cast<TrueTypeFontFile*>(pFont)->m_aXLFD = rXLFDs.front();
1612 break;
1613 default:
1614 break;
1615 }
1616 }
1617 else
1618 {
1619 // make sure that aliases are unique
1620 if( nFam != pFont->m_nFamilyName )
1621 {
1622 std::list< int >::const_iterator al_it;
1623 for( al_it = pFont->m_aAliases.begin(); al_it != pFont->m_aAliases.end() && *al_it != nFam; ++al_it )
1624 ;
1625 if( al_it == pFont->m_aAliases.end() )
1626 pFont->m_aAliases.push_back( nFam );
1627
1628 }
1629 // for the rest of the attributes there can only be one value;
1630 // we'll trust the first one
1631 continue;
1632 }
1633
1634 // fill in weight
1635 pFont->m_eWeight = it->eWeight;
1636 // fill in slant
1637 pFont->m_eItalic = it->eItalic;
1638 // fill in width
1639 pFont->m_eWidth = it->eWidth;
1640 // fill in pitch
1641 pFont->m_ePitch = it->ePitch;
1642 // fill in encoding
1643 pFont->m_aEncoding = it->aEncoding;
1644 }
1645
1646 // handle iso8859-1 as ms1252 to fill the "gap" starting at 0x80
1647 if( pFont->m_aEncoding == RTL_TEXTENCODING_ISO_8859_1 )
1648 pFont->m_aEncoding = RTL_TEXTENCODING_MS_1252;
1649 if( rXLFDs.begin() != rXLFDs.end() )
1650 {
1651 switch( pFont->m_eType )
1652 {
1653 case fonttype::Type1:
1654 static_cast<Type1FontFile*>(pFont)->m_aXLFD = rXLFDs.front();
1655 break;
1656 case fonttype::TrueType:
1657 static_cast<TrueTypeFontFile*>(pFont)->m_aXLFD = rXLFDs.front();
1658 break;
1659 default: break;
1660 }
1661 }
1662 }
1663
1664 // -------------------------------------------------------------------------
1665
getXLFD(PrintFont * pFont) const1666 OString PrintFontManager::getXLFD( PrintFont* pFont ) const
1667 {
1668 if( pFont->m_eType == fonttype::Type1 )
1669 {
1670 if( static_cast<Type1FontFile*>(pFont)->m_aXLFD.getLength() )
1671 return static_cast<Type1FontFile*>(pFont)->m_aXLFD;
1672 }
1673 if( pFont->m_eType == fonttype::TrueType )
1674 {
1675 if( static_cast<TrueTypeFontFile*>(pFont)->m_aXLFD.getLength() )
1676 return static_cast<TrueTypeFontFile*>(pFont)->m_aXLFD;
1677 }
1678
1679 OStringBuffer aXLFD( 128 );
1680
1681 aXLFD.append( "-misc-" );
1682 ByteString aFamily( String( m_pAtoms->getString( ATOM_FAMILYNAME, pFont->m_nFamilyName ) ), RTL_TEXTENCODING_UTF8 );
1683 aFamily.SearchAndReplaceAll( '-',' ' );
1684 aFamily.SearchAndReplaceAll( '?',' ' );
1685 aFamily.SearchAndReplaceAll( '*',' ' );
1686 aXLFD.append( OString( aFamily ) );
1687 aXLFD.append( '-' );
1688 switch( pFont->m_eWeight )
1689 {
1690 case weight::Thin: aXLFD.append("thin");break;
1691 case weight::UltraLight: aXLFD.append("ultralight");break;
1692 case weight::Light: aXLFD.append("light");break;
1693 case weight::SemiLight: aXLFD.append("semilight");break;
1694 case weight::Normal: aXLFD.append("normal");break;
1695 case weight::Medium: aXLFD.append("medium");break;
1696 case weight::SemiBold: aXLFD.append("semibold");break;
1697 case weight::Bold: aXLFD.append("bold");break;
1698 case weight::UltraBold: aXLFD.append("ultrabold");break;
1699 case weight::Black: aXLFD.append("black");break;
1700 default: break;
1701 }
1702 aXLFD.append('-');
1703 switch( pFont->m_eItalic )
1704 {
1705 case italic::Upright: aXLFD.append('r');break;
1706 case italic::Oblique: aXLFD.append('o');break;
1707 case italic::Italic: aXLFD.append('i');break;
1708 default: break;
1709 }
1710 aXLFD.append('-');
1711 switch( pFont->m_eWidth )
1712 {
1713 case width::UltraCondensed: aXLFD.append("ultracondensed");break;
1714 case width::ExtraCondensed: aXLFD.append("extracondensed");break;
1715 case width::Condensed: aXLFD.append("condensed");break;
1716 case width::SemiCondensed: aXLFD.append("semicondensed");break;
1717 case width::Normal: aXLFD.append("normal");break;
1718 case width::SemiExpanded: aXLFD.append("semiexpanded");break;
1719 case width::Expanded: aXLFD.append("expanded");break;
1720 case width::ExtraExpanded: aXLFD.append("extraexpanded");break;
1721 case width::UltraExpanded: aXLFD.append("ultraexpanded");break;
1722 default: break;
1723 }
1724 aXLFD.append("-utf8-0-0-0-0-");
1725 aXLFD.append( pFont->m_ePitch == pitch::Fixed ? "m" : "p" );
1726 aXLFD.append("-0-");
1727 const char* pEnc = rtl_getBestUnixCharsetFromTextEncoding( pFont->m_aEncoding );
1728 if( ! pEnc )
1729 {
1730 if( pFont->m_aEncoding == RTL_TEXTENCODING_ADOBE_STANDARD )
1731 pEnc = "adobe-standard";
1732 else
1733 pEnc = "iso8859-1";
1734 }
1735 aXLFD .append( pEnc );
1736
1737 return aXLFD.makeStringAndClear();
1738 }
1739
1740 // -------------------------------------------------------------------------
1741
convertTrueTypeName(void * pRecord) const1742 OUString PrintFontManager::convertTrueTypeName( void* pRecord ) const
1743 {
1744 NameRecord* pNameRecord = (NameRecord*)pRecord;
1745 OUString aValue;
1746 if(
1747 ( pNameRecord->platformID == 3 && ( pNameRecord->encodingID == 0 || pNameRecord->encodingID == 1 ) ) // MS, Unicode
1748 ||
1749 ( pNameRecord->platformID == 0 ) // Apple, Unicode
1750 )
1751 {
1752 OUStringBuffer aName( pNameRecord->slen/2 );
1753 const sal_uInt8* pNameBuffer = pNameRecord->sptr;
1754 for(int n = 0; n < pNameRecord->slen/2; n++ )
1755 aName.append( (sal_Unicode)getUInt16BE( pNameBuffer ) );
1756 aValue = aName.makeStringAndClear();
1757 }
1758 else if( pNameRecord->platformID == 3 )
1759 {
1760 if( pNameRecord->encodingID >= 2 && pNameRecord->encodingID <= 6 )
1761 {
1762 /*
1763 * and now for a special kind of madness:
1764 * some fonts encode their byte value string as BE uint16
1765 * (leading to stray zero bytes in the string)
1766 * while others code two bytes as a uint16 and swap to BE
1767 */
1768 OStringBuffer aName;
1769 const sal_uInt8* pNameBuffer = pNameRecord->sptr;
1770 for(int n = 0; n < pNameRecord->slen/2; n++ )
1771 {
1772 sal_Unicode aCode = (sal_Unicode)getUInt16BE( pNameBuffer );
1773 sal_Char aChar = aCode >> 8;
1774 if( aChar )
1775 aName.append( aChar );
1776 aChar = aCode & 0x00ff;
1777 if( aChar )
1778 aName.append( aChar );
1779 }
1780 switch( pNameRecord->encodingID )
1781 {
1782 case 2:
1783 aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_932 );
1784 break;
1785 case 3:
1786 aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_936 );
1787 break;
1788 case 4:
1789 aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_950 );
1790 break;
1791 case 5:
1792 aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_949 );
1793 break;
1794 case 6:
1795 aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_1361 );
1796 break;
1797 }
1798 }
1799 }
1800 return aValue;
1801 }
1802
1803 // -------------------------------------------------------------------------
1804
analyzeTrueTypeFamilyName(void * pTTFont,::std::list<OUString> & rNames) const1805 void PrintFontManager::analyzeTrueTypeFamilyName( void* pTTFont, ::std::list< OUString >& rNames ) const
1806 {
1807 OUString aFamily;
1808
1809 rNames.clear();
1810 ::std::set< OUString > aSet;
1811
1812 NameRecord* pNameRecords = NULL;
1813 int nNameRecords = GetTTNameRecords( (TrueTypeFont*)pTTFont, &pNameRecords );
1814 if( nNameRecords && pNameRecords )
1815 {
1816 LanguageType aLang = MsLangId::getSystemLanguage();
1817 int nLastMatch = -1;
1818 for( int i = 0; i < nNameRecords; i++ )
1819 {
1820 if( pNameRecords[i].nameID != 1 || pNameRecords[i].sptr == NULL )
1821 continue;
1822 int nMatch = -1;
1823 if( pNameRecords[i].platformID == 0 ) // Unicode
1824 nMatch = 4000;
1825 else if( pNameRecords[i].platformID == 3 )
1826 {
1827 // this bases on the LanguageType actually being a Win LCID
1828 if( pNameRecords[i].languageID == aLang )
1829 nMatch = 8000;
1830 else if( pNameRecords[i].languageID == LANGUAGE_ENGLISH_US )
1831 nMatch = 2000;
1832 else if( pNameRecords[i].languageID == LANGUAGE_ENGLISH ||
1833 pNameRecords[i].languageID == LANGUAGE_ENGLISH_UK )
1834 nMatch = 1500;
1835 else
1836 nMatch = 1000;
1837 }
1838 OUString aName = convertTrueTypeName( pNameRecords + i );
1839 aSet.insert( aName );
1840 if( nMatch > nLastMatch )
1841 {
1842 nLastMatch = nMatch;
1843 aFamily = aName;
1844 }
1845 }
1846 DisposeNameRecords( pNameRecords, nNameRecords );
1847 }
1848 if( aFamily.getLength() )
1849 {
1850 rNames.push_front( aFamily );
1851 for( ::std::set< OUString >::const_iterator it = aSet.begin(); it != aSet.end(); ++it )
1852 if( *it != aFamily )
1853 rNames.push_back( *it );
1854 }
1855 return;
1856 }
1857
1858 // -------------------------------------------------------------------------
1859
analyzeTrueTypeFile(PrintFont * pFont) const1860 bool PrintFontManager::analyzeTrueTypeFile( PrintFont* pFont ) const
1861 {
1862 bool bSuccess = false;
1863 rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
1864 ByteString aFile = getFontFile( pFont );
1865 TrueTypeFont* pTTFont = NULL;
1866
1867 TrueTypeFontFile* pTTFontFile = static_cast< TrueTypeFontFile* >(pFont);
1868 if( OpenTTFontFile( aFile.GetBuffer(), pTTFontFile->m_nCollectionEntry < 0 ? 0 : pTTFontFile->m_nCollectionEntry, &pTTFont ) == SF_OK )
1869 {
1870 TTGlobalFontInfo aInfo;
1871 GetTTGlobalFontInfo( pTTFont, & aInfo );
1872
1873 ::std::list< OUString > aNames;
1874 analyzeTrueTypeFamilyName( pTTFont, aNames );
1875
1876 // set family name from XLFD if possible
1877 if( ! pFont->m_nFamilyName )
1878 {
1879 if( aNames.begin() != aNames.end() )
1880 {
1881 pFont->m_nFamilyName = m_pAtoms->getAtom( ATOM_FAMILYNAME, aNames.front(), sal_True );
1882 aNames.pop_front();
1883 }
1884 else
1885 {
1886 sal_Int32 dotIndex;
1887
1888 // poor font does not have a family name
1889 // name it to file name minus the extension
1890 dotIndex = pTTFontFile->m_aFontFile.lastIndexOf( '.' );
1891 if ( dotIndex == -1 )
1892 dotIndex = pTTFontFile->m_aFontFile.getLength();
1893
1894 pFont->m_nFamilyName = m_pAtoms->getAtom( ATOM_FAMILYNAME, OStringToOUString( pTTFontFile->m_aFontFile.copy( 0, dotIndex ), aEncoding ), sal_True );
1895 }
1896 }
1897 for( ::std::list< OUString >::iterator it = aNames.begin(); it != aNames.end(); ++it )
1898 {
1899 if( it->getLength() )
1900 {
1901 int nAlias = m_pAtoms->getAtom( ATOM_FAMILYNAME, *it, sal_True );
1902 if( nAlias != pFont->m_nFamilyName )
1903 {
1904 std::list< int >::const_iterator al_it;
1905 for( al_it = pFont->m_aAliases.begin(); al_it != pFont->m_aAliases.end() && *al_it != nAlias; ++al_it )
1906 ;
1907 if( al_it == pFont->m_aAliases.end() )
1908 pFont->m_aAliases.push_back( nAlias );
1909 }
1910 }
1911 }
1912
1913 if( aInfo.usubfamily )
1914 pFont->m_aStyleName = OUString( aInfo.usubfamily );
1915
1916 pFont->m_nPSName = m_pAtoms->getAtom( ATOM_PSNAME, String( ByteString( aInfo.psname ), aEncoding ), sal_True );
1917 switch( aInfo.weight )
1918 {
1919 case FW_THIN: pFont->m_eWeight = weight::Thin; break;
1920 case FW_EXTRALIGHT: pFont->m_eWeight = weight::UltraLight; break;
1921 case FW_LIGHT: pFont->m_eWeight = weight::Light; break;
1922 case FW_MEDIUM: pFont->m_eWeight = weight::Medium; break;
1923 case FW_SEMIBOLD: pFont->m_eWeight = weight::SemiBold; break;
1924 case FW_BOLD: pFont->m_eWeight = weight::Bold; break;
1925 case FW_EXTRABOLD: pFont->m_eWeight = weight::UltraBold; break;
1926 case FW_BLACK: pFont->m_eWeight = weight::Black; break;
1927
1928 case FW_NORMAL:
1929 default: pFont->m_eWeight = weight::Normal; break;
1930 }
1931
1932 switch( aInfo.width )
1933 {
1934 case FWIDTH_ULTRA_CONDENSED: pFont->m_eWidth = width::UltraCondensed; break;
1935 case FWIDTH_EXTRA_CONDENSED: pFont->m_eWidth = width::ExtraCondensed; break;
1936 case FWIDTH_CONDENSED: pFont->m_eWidth = width::Condensed; break;
1937 case FWIDTH_SEMI_CONDENSED: pFont->m_eWidth = width::SemiCondensed; break;
1938 case FWIDTH_SEMI_EXPANDED: pFont->m_eWidth = width::SemiExpanded; break;
1939 case FWIDTH_EXPANDED: pFont->m_eWidth = width::Expanded; break;
1940 case FWIDTH_EXTRA_EXPANDED: pFont->m_eWidth = width::ExtraExpanded; break;
1941 case FWIDTH_ULTRA_EXPANDED: pFont->m_eWidth = width::UltraExpanded; break;
1942
1943 case FWIDTH_NORMAL:
1944 default: pFont->m_eWidth = width::Normal; break;
1945 }
1946
1947 pFont->m_ePitch = aInfo.pitch ? pitch::Fixed : pitch::Variable;
1948 pFont->m_eItalic = aInfo.italicAngle == 0 ? italic::Upright : ( aInfo.italicAngle < 0 ? italic::Italic : italic::Oblique );
1949 // #104264# there are fonts that set italic angle 0 although they are
1950 // italic; use macstyle bit here
1951 if( aInfo.italicAngle == 0 && (aInfo.macStyle & 2) )
1952 pFont->m_eItalic = italic::Italic;
1953
1954 pFont->m_aEncoding = aInfo.symbolEncoded ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UCS2;
1955
1956 pFont->m_aGlobalMetricY.width = pFont->m_aGlobalMetricX.width = aInfo.xMax - aInfo.xMin;
1957 pFont->m_aGlobalMetricY.height = pFont->m_aGlobalMetricX.height = aInfo.yMax - aInfo.yMin;
1958
1959 if( aInfo.winAscent && aInfo.winDescent )
1960 {
1961 pFont->m_nAscend = aInfo.winAscent;
1962 pFont->m_nDescend = aInfo.winDescent;
1963 pFont->m_nLeading = pFont->m_nAscend + pFont->m_nDescend - 1000;
1964 }
1965 else if( aInfo.typoAscender && aInfo.typoDescender )
1966 {
1967 pFont->m_nLeading = aInfo.typoLineGap;
1968 pFont->m_nAscend = aInfo.typoAscender;
1969 pFont->m_nDescend = -aInfo.typoDescender;
1970 }
1971 else
1972 {
1973 pFont->m_nLeading = aInfo.linegap;
1974 pFont->m_nAscend = aInfo.ascender;
1975 pFont->m_nDescend = -aInfo.descender;
1976 }
1977
1978 // last try: font bounding box
1979 if( pFont->m_nAscend == 0 )
1980 pFont->m_nAscend = aInfo.yMax;
1981 if( pFont->m_nDescend == 0 )
1982 pFont->m_nDescend = -aInfo.yMin;
1983 if( pFont->m_nLeading == 0 )
1984 pFont->m_nLeading = 15 * (pFont->m_nAscend+pFont->m_nDescend) / 100;
1985
1986 if( pFont->m_nAscend )
1987 pFont->m_aGlobalMetricX.height = pFont->m_aGlobalMetricY.height = pFont->m_nAscend + pFont->m_nDescend;
1988
1989 // get bounding box
1990 pFont->m_nXMin = aInfo.xMin;
1991 pFont->m_nYMin = aInfo.yMin;
1992 pFont->m_nXMax = aInfo.xMax;
1993 pFont->m_nYMax = aInfo.yMax;
1994
1995 // get type flags
1996 pTTFontFile->m_nTypeFlags = (unsigned int)aInfo.typeFlags;
1997
1998 // get vertical substitutions flag
1999 pFont->m_bHaveVerticalSubstitutedGlyphs = DoesVerticalSubstitution( pTTFont, 1 );
2000
2001 CloseTTFont( pTTFont );
2002 bSuccess = true;
2003 }
2004 #if OSL_DEBUG_LEVEL > 1
2005 else
2006 fprintf( stderr, "could not OpenTTFont \"%s\"\n", aFile.GetBuffer() );
2007 #endif
2008
2009 return bSuccess;
2010 }
2011
2012 // -------------------------------------------------------------------------
2013
initFontsAlias()2014 void PrintFontManager::initFontsAlias()
2015 {
2016 m_aXLFD_Aliases.clear();
2017 rtl_TextEncoding aEnc = osl_getThreadTextEncoding();
2018 for( std::list< OString >::const_iterator dir_it = m_aFontDirectories.begin();
2019 dir_it != m_aFontDirectories.end(); ++dir_it )
2020 {
2021 OStringBuffer aDirName(512);
2022 aDirName.append( *dir_it );
2023 aDirName.append( "/fonts.alias" );
2024 SvFileStream aStream( OStringToOUString( aDirName.makeStringAndClear(), aEnc ), STREAM_READ );
2025 if( ! aStream.IsOpen() )
2026 continue;
2027
2028 do
2029 {
2030 ByteString aLine;
2031 aStream.ReadLine( aLine );
2032
2033 // get the alias and the pattern it gets translated to
2034 ByteString aAlias = GetCommandLineToken( 0, aLine );
2035 ByteString aMap = GetCommandLineToken( 1, aLine );
2036
2037 // remove eventual quotes
2038 aAlias.EraseLeadingChars( '"' );
2039 aAlias.EraseTrailingChars( '"' );
2040 aMap.EraseLeadingChars( '"' );
2041 aMap.EraseTrailingChars( '"' );
2042
2043 XLFDEntry aAliasEntry, aMapEntry;
2044 parseXLFD( aAlias, aAliasEntry );
2045 parseXLFD( aMap, aMapEntry );
2046
2047 if( aAliasEntry.nMask && aMapEntry.nMask )
2048 m_aXLFD_Aliases[ aMapEntry ].push_back( aAliasEntry );
2049 } while( ! aStream.IsEof() );
2050 }
2051 }
2052
2053 // code stolen from vcl's RegisterFontSubstitutors()
2054 // TODO: use that method once psprint gets merged into vcl
AreFCSubstitutionsEnabled()2055 static bool AreFCSubstitutionsEnabled()
2056 {
2057 // init font substitution defaults
2058 int nDisableBits = 0;
2059 #ifdef SOLARIS
2060 // TODO: check the OS version and fc-data maintenance level
2061 nDisableBits = 1; // disable "font fallback" here on default
2062 #endif
2063 // apply the environment variable if any
2064 const char* pEnvStr = ::getenv( "SAL_DISABLE_FC_SUBST" );
2065 if( pEnvStr )
2066 {
2067 //
2068 if( (*pEnvStr >= '0') && (*pEnvStr <= '9') )
2069 nDisableBits = (*pEnvStr - '0');
2070 else
2071 nDisableBits = ~0U; // no specific bits set: disable all
2072 }
2073
2074 return ((nDisableBits & 3) == 0);
2075 }
2076
initialize()2077 void PrintFontManager::initialize()
2078 {
2079 #ifdef CALLGRIND_COMPILE
2080 CALLGRIND_TOGGLE_COLLECT();
2081 CALLGRIND_ZERO_STATS();
2082 #endif
2083
2084 long aDirEntBuffer[ (sizeof(struct dirent)+_PC_NAME_MAX)+1 ];
2085
2086 if( ! m_pFontCache )
2087 {
2088 #if OSL_DEBUG_LEVEL > 1
2089 fprintf( stderr, "creating font cache ... " );
2090 clock_t aStart;
2091 struct tms tms;
2092 aStart = times( &tms );
2093 #endif
2094 m_pFontCache = new FontCache();
2095 #if OSL_DEBUG_LEVEL > 1
2096 clock_t aStop = times( &tms );
2097 fprintf( stderr, "done in %lf s\n", (double)(aStop - aStart)/(double)sysconf( _SC_CLK_TCK ) );
2098 #endif
2099 }
2100
2101 // initialize may be called twice in the future
2102 {
2103 for( ::std::hash_map< fontID, PrintFont* >::const_iterator it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
2104 delete (*it).second;
2105 m_nNextFontID = 1;
2106 m_aFonts.clear();
2107 m_aFontDirectories.clear();
2108 m_aPrivateFontDirectories.clear();
2109 m_aOverrideFonts.clear();
2110 }
2111
2112 #if OSL_DEBUG_LEVEL > 1
2113 clock_t aStart;
2114 clock_t aStep1;
2115 clock_t aStep2;
2116 clock_t aStep3;
2117 int nBuiltinFonts = 0;
2118 int nCached = 0;
2119
2120 struct tms tms;
2121
2122 aStart = times( &tms );
2123 #endif
2124
2125 // first try fontconfig
2126 m_bFontconfigSuccess = initFontconfig();
2127
2128 // part one - look for downloadable fonts
2129 rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
2130 const ::rtl::OUString &rSalPrivatePath = psp::getFontPath();
2131
2132 // search for the fonts in SAL_PRIVATE_FONTPATH first; those are
2133 // the fonts installed with the office
2134 if( rSalPrivatePath.getLength() )
2135 {
2136 OString aPath = rtl::OUStringToOString( rSalPrivatePath, aEncoding );
2137 const bool bAreFCSubstitutionsEnabled = AreFCSubstitutionsEnabled();
2138 sal_Int32 nIndex = 0;
2139 do
2140 {
2141 OString aToken = aPath.getToken( 0, ';', nIndex );
2142 normPath( aToken );
2143 // if registering an app-specific fontdir with fontconfig fails
2144 // and fontconfig-based substitutions are enabled
2145 // then trying to use these app-specific fonts doesn't make sense
2146 if( m_bFontconfigSuccess && !addFontconfigDir( aToken ) )
2147 if( bAreFCSubstitutionsEnabled )
2148 continue;
2149 m_aFontDirectories.push_back( aToken );
2150 m_aPrivateFontDirectories.push_back( getDirectoryAtom( aToken, true ) );
2151 } while( nIndex >= 0 );
2152 }
2153
2154 // protect against duplicate paths
2155 std::hash_map< OString, int, OStringHash > visited_dirs;
2156
2157 // now that all global and local font dirs are known to fontconfig
2158 // check that there are fonts actually managed by fontconfig
2159 // also don't search directories that fontconfig already did
2160 if( m_bFontconfigSuccess )
2161 m_bFontconfigSuccess = (countFontconfigFonts( visited_dirs ) > 0);
2162
2163 // don't search through many directories fontconfig already told us about
2164 if( ! m_bFontconfigSuccess )
2165 ImplGetSVData()->mpDefInst->FillFontPathList( m_aFontDirectories );
2166
2167 // fill XLFD aliases from fonts.alias files
2168 initFontsAlias();
2169
2170 // search for font files in each path
2171 std::list< OString >::iterator dir_it;
2172 for( dir_it = m_aFontDirectories.begin(); dir_it != m_aFontDirectories.end(); ++dir_it )
2173 {
2174 OString aPath( *dir_it );
2175 // see if we were here already
2176 if( visited_dirs.find( aPath ) != visited_dirs.end() )
2177 continue;
2178 visited_dirs[ aPath ] = 1;
2179
2180 // there may be ":unscaled" directories (see XFree86)
2181 // it should be safe to ignore them since they should not
2182 // contain any of our recognizeable fonts
2183
2184 // ask the font cache whether it handles this directory
2185 std::list< PrintFont* > aCacheFonts;
2186 if( m_pFontCache->listDirectory( aPath, aCacheFonts ) )
2187 {
2188 #if OSL_DEBUG_LEVEL > 1
2189 fprintf( stderr, "adding cache directory: %s\n", aPath.getStr() );
2190 #endif
2191 for( ::std::list< PrintFont* >::iterator it = aCacheFonts.begin(); it != aCacheFonts.end(); ++it )
2192 {
2193 fontID aFont = m_nNextFontID++;
2194 m_aFonts[ aFont ] = *it;
2195 if( (*it)->m_eType == fonttype::Type1 )
2196 m_aFontFileToFontID[ static_cast<Type1FontFile*>(*it)->m_aFontFile ].insert( aFont );
2197 else if( (*it)->m_eType == fonttype::TrueType )
2198 m_aFontFileToFontID[ static_cast<TrueTypeFontFile*>(*it)->m_aFontFile ].insert( aFont );
2199 else if( (*it)->m_eType == fonttype::Builtin )
2200 m_aFontFileToFontID[ static_cast<BuiltinFont*>(*it)->m_aMetricFile ].insert( aFont );
2201 #if OSL_DEBUG_LEVEL > 1
2202 if( (*it)->m_eType == fonttype::Builtin )
2203 nBuiltinFonts++;
2204 nCached++;
2205 #if OSL_DEBUG_LEVEL > 2
2206 fprintf( stderr, "adding cached font %d: \"%s\" from %s\n", aFont,
2207 OUStringToOString( getFontFamily( aFont ), RTL_TEXTENCODING_MS_1252 ).getStr(),
2208 getFontFileSysPath( aFont ).getStr() );
2209 #endif
2210 #endif
2211 }
2212 if( ! m_pFontCache->scanAdditionalFiles( aPath ) )
2213 continue;
2214 }
2215
2216 DIR* pDIR = opendir( aPath.getStr() );
2217 struct dirent* pEntry = (struct dirent*)aDirEntBuffer;
2218 if( pDIR )
2219 {
2220 // read fonts.dir if possible
2221 ::std::hash_map< OString, ::std::list<OString>, OStringHash > aFontsDir;
2222 int nDirID = getDirectoryAtom( aPath, true );
2223 // #i38367# no fonts.dir in our own directories anymore
2224 std::list< int >::const_iterator priv_dir;
2225 for( priv_dir = m_aPrivateFontDirectories.begin();
2226 priv_dir != m_aPrivateFontDirectories.end() && *priv_dir != nDirID;
2227 ++priv_dir )
2228 ;
2229
2230 if( priv_dir == m_aPrivateFontDirectories.end() )
2231 {
2232 ByteString aGccDummy( aPath );
2233 String aFontsDirPath( aGccDummy, aEncoding );
2234 aFontsDirPath.AppendAscii( "/fonts.dir" );
2235 SvFileStream aStream( aFontsDirPath, STREAM_READ );
2236 if( aStream.IsOpen() )
2237 {
2238 ByteString aLine;
2239 while( ! aStream.IsEof() )
2240 {
2241 aStream.ReadLine( aLine );
2242 ByteString aFileName( GetCommandLineToken( 0, aLine ) );
2243 ByteString aXLFD( aLine.Copy( aFileName.Len() ) );
2244 if( aFileName.Len() && aXLFD.Len() )
2245 aFontsDir[ aFileName ].push_back(aXLFD);
2246 }
2247 }
2248 }
2249
2250 int nDirFonts = 0;
2251 while( ! readdir_r( pDIR, (struct dirent*)aDirEntBuffer, &pEntry ) && pEntry )
2252 {
2253 OString aFileName( pEntry->d_name );
2254 // ignore .afm files here
2255 if( aFileName.getLength() > 3 &&
2256 aFileName.lastIndexOf( ".afm" ) == aFileName.getLength()-4 )
2257 continue;
2258
2259 struct stat aStat;
2260 ByteString aFilePath( aPath );
2261 aFilePath.Append( '/' );
2262 aFilePath.Append( ByteString( aFileName ) );
2263 if( ! stat( aFilePath.GetBuffer(), &aStat ) &&
2264 S_ISREG( aStat.st_mode ) )
2265 {
2266 if( findFontFileID( nDirID, aFileName ) == 0 )
2267 {
2268 ::std::list<OString> aXLFDs;
2269 ::std::hash_map< OString, ::std::list<OString>, OStringHash >::const_iterator it =
2270 aFontsDir.find( aFileName );
2271 if( it != aFontsDir.end() )
2272 aXLFDs = (*it).second;
2273
2274 // fill in font attributes from XLFD rather
2275 // than reading every file
2276 ::std::list< PrintFont* > aNewFonts;
2277 if( analyzeFontFile( nDirID, aFileName, aXLFDs, aNewFonts ) )
2278 {
2279 for( ::std::list< PrintFont* >::iterator font_it = aNewFonts.begin(); font_it != aNewFonts.end(); ++font_it )
2280 {
2281 fontID aFont = m_nNextFontID++;
2282 m_aFonts[ aFont ] = *font_it;
2283 m_aFontFileToFontID[ aFileName ].insert( aFont );
2284 m_pFontCache->updateFontCacheEntry( *font_it, false );
2285 nDirFonts++;
2286 #if OSL_DEBUG_LEVEL > 2
2287 fprintf( stderr, "adding font %d: \"%s\" from %s\n", aFont,
2288 OUStringToOString( getFontFamily( aFont ), RTL_TEXTENCODING_MS_1252 ).getStr(),
2289 getFontFileSysPath( aFont ).getStr() );
2290 #endif
2291 }
2292 }
2293 }
2294 }
2295 }
2296 closedir( pDIR );
2297 m_pFontCache->updateDirTimestamp( nDirID );
2298 if( ! nDirFonts )
2299 m_pFontCache->markEmptyDir( nDirID );
2300 }
2301 }
2302
2303 #if OSL_DEBUG_LEVEL > 1
2304 aStep1 = times( &tms );
2305 #endif
2306
2307 // part two - look for metrics for builtin printer fonts
2308 std::list< OUString > aMetricDirs;
2309 psp::getPrinterPathList( aMetricDirs, PRINTER_METRICDIR );
2310
2311 std::list< OString > aEmptyFontsDir;
2312 for( std::list< OUString >::const_iterator met_dir_it = aMetricDirs.begin(); met_dir_it != aMetricDirs.end(); ++met_dir_it )
2313 {
2314 OString aDir = OUStringToOString( *met_dir_it, aEncoding );
2315
2316 // ask the font cache whether it handles this directory
2317 std::list< PrintFont* > aCacheFonts;
2318
2319 if( m_pFontCache->listDirectory( aDir, aCacheFonts ) )
2320 {
2321 #if OSL_DEBUG_LEVEL > 1
2322 fprintf( stderr, "adding cache directory: %s\n", aDir.getStr() );
2323 #endif
2324 for( ::std::list< PrintFont* >::iterator it = aCacheFonts.begin(); it != aCacheFonts.end(); ++it )
2325 {
2326 fontID aFont = m_nNextFontID++;
2327 m_aFonts[ aFont ] = *it;
2328 if( (*it)->m_eType == fonttype::Type1 )
2329 m_aFontFileToFontID[ static_cast<Type1FontFile*>(*it)->m_aFontFile ].insert( aFont );
2330 else if( (*it)->m_eType == fonttype::TrueType )
2331 m_aFontFileToFontID[ static_cast<TrueTypeFontFile*>(*it)->m_aFontFile ].insert( aFont );
2332 else if( (*it)->m_eType == fonttype::Builtin )
2333 m_aFontFileToFontID[ static_cast<BuiltinFont*>(*it)->m_aMetricFile ].insert( aFont );
2334 #if OSL_DEBUG_LEVEL > 1
2335 if( (*it)->m_eType == fonttype::Builtin )
2336 nBuiltinFonts++;
2337 nCached++;
2338 #if OSL_DEBUG_LEVEL > 2
2339 fprintf( stderr, "adding cached font %d: \"%s\" from %s\n", aFont,
2340 OUStringToOString( getFontFamily( aFont ), RTL_TEXTENCODING_MS_1252 ).getStr(),
2341 getFontFileSysPath( aFont ).getStr() );
2342 #endif
2343 #endif
2344 }
2345 continue;
2346 }
2347
2348 DIR* pDIR = opendir( aDir.getStr() );
2349 if( pDIR )
2350 {
2351 struct dirent* pDirEntry = (struct dirent*)aDirEntBuffer;
2352 int nDirID = getDirectoryAtom( aDir, true );
2353 int nDirFonts = 0;
2354
2355 while( ! readdir_r( pDIR, (struct dirent*)aDirEntBuffer, &pDirEntry ) && pDirEntry )
2356 {
2357 ByteString aFile( aDir );
2358 aFile += '/';
2359 aFile += pDirEntry->d_name;
2360 struct stat aStat;
2361 if( ! stat( aFile.GetBuffer(), &aStat )
2362 && S_ISREG( aStat.st_mode )
2363 )
2364 {
2365 OString aFileName( pDirEntry->d_name, strlen( pDirEntry->d_name ) );
2366 OString aExt( aFileName.copy( aFileName.lastIndexOf( '.' )+1 ) );
2367 if( aExt.equalsIgnoreAsciiCase( "afm" ) )
2368 {
2369 ::std::list< PrintFont* > aNewFonts;
2370
2371 analyzeFontFile( nDirID, aFileName, aEmptyFontsDir, aNewFonts );
2372 for( ::std::list< PrintFont* >::iterator it = aNewFonts.begin(); it != aNewFonts.end(); ++it )
2373 {
2374 if( findFontBuiltinID( (*it)->m_nPSName ) == 0 )
2375 {
2376 m_aFontFileToFontID[ aFileName ].insert( m_nNextFontID );
2377 m_aFonts[ m_nNextFontID++ ] = *it;
2378 m_pFontCache->updateFontCacheEntry( *it, false );
2379 #if OSL_DEBUG_LEVEL > 2
2380 nBuiltinFonts++;
2381 #endif
2382 }
2383 else
2384 delete *it;
2385 }
2386 }
2387 }
2388 }
2389 closedir( pDIR );
2390 if( ! nDirFonts )
2391 m_pFontCache->markEmptyDir( nDirID );
2392 }
2393 }
2394
2395 #if OSL_DEBUG_LEVEL > 1
2396 aStep2 = times( &tms );
2397 #endif
2398
2399 // part three - fill in family styles
2400 ::std::hash_map< fontID, PrintFont* >::iterator font_it;
2401 for (font_it = m_aFonts.begin(); font_it != m_aFonts.end(); ++font_it)
2402 {
2403 ::std::hash_map< int, family::type >::const_iterator it =
2404 m_aFamilyTypes.find( font_it->second->m_nFamilyName );
2405 if (it != m_aFamilyTypes.end())
2406 continue;
2407 const ::rtl::OUString& rFamily =
2408 m_pAtoms->getString( ATOM_FAMILYNAME, font_it->second->m_nFamilyName);
2409 family::type eType = matchFamilyName( rFamily );
2410 m_aFamilyTypes[ font_it->second->m_nFamilyName ] = eType;
2411 }
2412
2413 #if OSL_DEBUG_LEVEL > 1
2414 aStep3 = times( &tms );
2415 fprintf( stderr, "PrintFontManager::initialize: collected %d fonts (%d builtin, %d cached)\n", m_aFonts.size(), nBuiltinFonts, nCached );
2416 double fTick = (double)sysconf( _SC_CLK_TCK );
2417 fprintf( stderr, "Step 1 took %lf seconds\n", (double)(aStep1 - aStart)/fTick );
2418 fprintf( stderr, "Step 2 took %lf seconds\n", (double)(aStep2 - aStep1)/fTick );
2419 fprintf( stderr, "Step 3 took %lf seconds\n", (double)(aStep3 - aStep2)/fTick );
2420 #endif
2421
2422 m_pFontCache->flush();
2423
2424 #ifdef CALLGRIND_COMPILE
2425 CALLGRIND_DUMP_STATS();
2426 CALLGRIND_TOGGLE_COLLECT();
2427 #endif
2428 }
2429
2430 // -------------------------------------------------------------------------
2431 inline bool
equalPitch(psp::pitch::type from,psp::pitch::type to)2432 equalPitch (psp::pitch::type from, psp::pitch::type to)
2433 {
2434 return from == to;
2435 }
2436
2437 inline bool
equalWeight(psp::weight::type from,psp::weight::type to)2438 equalWeight (psp::weight::type from, psp::weight::type to)
2439 {
2440 return from > to ? (from - to) <= 3 : (to - from) <= 3;
2441 }
2442
2443 inline bool
equalItalic(psp::italic::type from,psp::italic::type to)2444 equalItalic (psp::italic::type from, psp::italic::type to)
2445 {
2446 if ( (from == psp::italic::Italic) || (from == psp::italic::Oblique) )
2447 return (to == psp::italic::Italic) || (to == psp::italic::Oblique);
2448 return to == from;
2449 }
2450 inline bool
equalEncoding(rtl_TextEncoding from,rtl_TextEncoding to)2451 equalEncoding (rtl_TextEncoding from, rtl_TextEncoding to)
2452 {
2453 if ((from == RTL_TEXTENCODING_ISO_8859_1) || (from == RTL_TEXTENCODING_MS_1252))
2454 return (to == RTL_TEXTENCODING_ISO_8859_1) || (to == RTL_TEXTENCODING_MS_1252);
2455 return from == to;
2456 }
2457
2458 namespace {
2459 struct BuiltinFontIdentifier
2460 {
2461 OUString aFamily;
2462 italic::type eItalic;
2463 weight::type eWeight;
2464 pitch::type ePitch;
2465 rtl_TextEncoding aEncoding;
2466
BuiltinFontIdentifier__anon3ae420d50211::BuiltinFontIdentifier2467 BuiltinFontIdentifier( const OUString& rFam,
2468 italic::type eIt,
2469 weight::type eWg,
2470 pitch::type ePt,
2471 rtl_TextEncoding enc ) :
2472 aFamily( rFam ),
2473 eItalic( eIt ),
2474 eWeight( eWg ),
2475 ePitch( ePt ),
2476 aEncoding( enc )
2477 {}
2478
operator ==__anon3ae420d50211::BuiltinFontIdentifier2479 bool operator==( const BuiltinFontIdentifier& rRight ) const
2480 {
2481 return equalItalic( eItalic, rRight.eItalic ) &&
2482 equalWeight( eWeight, rRight.eWeight ) &&
2483 equalPitch( ePitch, rRight.ePitch ) &&
2484 equalEncoding( aEncoding, rRight.aEncoding ) &&
2485 aFamily.equalsIgnoreAsciiCase( rRight.aFamily );
2486 }
2487 };
2488
2489 struct BuiltinFontIdentifierHash
2490 {
operator ()__anon3ae420d50211::BuiltinFontIdentifierHash2491 size_t operator()( const BuiltinFontIdentifier& rFont ) const
2492 {
2493 return rFont.aFamily.hashCode() ^ rFont.eItalic ^ rFont.eWeight ^ rFont.ePitch ^ rFont.aEncoding;
2494 }
2495 };
2496 }
2497
getFontList(::std::list<fontID> & rFontIDs,const PPDParser * pParser,bool bUseOverrideMetrics)2498 void PrintFontManager::getFontList( ::std::list< fontID >& rFontIDs, const PPDParser* pParser, bool bUseOverrideMetrics )
2499 {
2500 rFontIDs.clear();
2501 std::hash_map< fontID, PrintFont* >::const_iterator it;
2502
2503 /*
2504 * Note: there are two easy steps making this faster:
2505 * first: insert the printer builtins first, then the not builtins,
2506 * if they do not match.
2507 * drawback: this would change the sequence of fonts; this could have
2508 * subtle, unknown consequences in vcl font matching
2509 * second: instead of comparing attributes to see whether a softfont
2510 * is duplicate to a builtin one could simply compare the PSName (which is
2511 * supposed to be unique), which at this point is just an int.
2512 * drawback: this could change which fonts are listed; especially TrueType
2513 * fonts often have a rather dubious PSName, so this could change the
2514 * font list not so subtle.
2515 * Until getFontList for a printer becomes a performance issue (which is
2516 * currently not the case), best stay with the current algorithm.
2517 */
2518
2519 // fill sets of printer supported fonts
2520 if( pParser )
2521 {
2522 std::set<int> aBuiltinPSNames;
2523 std::hash_set< BuiltinFontIdentifier,
2524 BuiltinFontIdentifierHash
2525 > aBuiltinFonts;
2526
2527 std::map<int, fontID > aOverridePSNames;
2528 if( bUseOverrideMetrics )
2529 {
2530 readOverrideMetrics();
2531 for( std::vector<fontID>::const_iterator over = m_aOverrideFonts.begin();
2532 over != m_aOverrideFonts.end(); ++over )
2533 {
2534 std::hash_map<fontID,PrintFont*>::const_iterator font_it = m_aFonts.find( *over );
2535 DBG_ASSERT( font_it != m_aFonts.end(), "override to nonexistant font" );
2536 if( font_it != m_aFonts.end() )
2537 aOverridePSNames[ font_it->second->m_nPSName ] = *over;
2538 }
2539 }
2540
2541 int nFonts = pParser->getFonts();
2542 for( int i = 0; i < nFonts; i++ )
2543 aBuiltinPSNames.insert( m_pAtoms->getAtom( ATOM_PSNAME, pParser->getFont( i ) ) );
2544 for( it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
2545 {
2546 PrintFont* pFont = it->second;
2547 if( it->second->m_eType == fonttype::Builtin &&
2548 aBuiltinPSNames.find( pFont->m_nPSName ) != aBuiltinPSNames.end() )
2549 {
2550 bool bInsert = true;
2551 if( bUseOverrideMetrics )
2552 {
2553 // in override case only use the override fonts, not their counterparts
2554 std::map<int,fontID>::const_iterator over = aOverridePSNames.find( pFont->m_nPSName );
2555 if( over != aOverridePSNames.end() && over->second != it->first )
2556 bInsert = false;
2557 }
2558 else
2559 {
2560 // do not insert override fonts in non override case
2561 if( std::find( m_aOverrideFonts.begin(), m_aOverrideFonts.end(), it->first ) != m_aOverrideFonts.end() )
2562 bInsert = false;
2563 }
2564 if( bInsert )
2565 {
2566 aBuiltinFonts.insert( BuiltinFontIdentifier(
2567 m_pAtoms->getString( ATOM_FAMILYNAME, pFont->m_nFamilyName ),
2568 pFont->m_eItalic,
2569 pFont->m_eWeight,
2570 pFont->m_ePitch,
2571 pFont->m_aEncoding
2572 ) );
2573 }
2574 }
2575 }
2576 for( it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
2577 {
2578 PrintFont* pFont = it->second;
2579 if( it->second->m_eType == fonttype::Builtin )
2580 {
2581 if( aBuiltinPSNames.find( pFont->m_nPSName ) != aBuiltinPSNames.end() )
2582 {
2583 bool bInsert = true;
2584 if( bUseOverrideMetrics )
2585 {
2586 // in override case only use the override fonts, not their counterparts
2587 std::map<int,fontID>::const_iterator over = aOverridePSNames.find( pFont->m_nPSName );
2588 if( over != aOverridePSNames.end() && over->second != it->first )
2589 bInsert = false;
2590 }
2591 else
2592 {
2593 // do not insert override fonts in non override case
2594 if( std::find( m_aOverrideFonts.begin(), m_aOverrideFonts.end(), it->first ) != m_aOverrideFonts.end() )
2595 bInsert = false;
2596 }
2597 if( bInsert )
2598 rFontIDs.push_back( it->first );
2599 }
2600 }
2601 else if( aBuiltinFonts.find( BuiltinFontIdentifier(
2602 m_pAtoms->getString( ATOM_FAMILYNAME, pFont->m_nFamilyName ),
2603 pFont->m_eItalic,
2604 pFont->m_eWeight,
2605 pFont->m_ePitch,
2606 pFont->m_aEncoding
2607 ) ) == aBuiltinFonts.end() )
2608 {
2609 rFontIDs.push_back( it->first );
2610 }
2611 }
2612 }
2613 else // no specific printer
2614 {
2615 for( it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
2616 rFontIDs.push_back( it->first );
2617 }
2618 }
2619
2620 // -------------------------------------------------------------------------
2621
fillPrintFontInfo(PrintFont * pFont,FastPrintFontInfo & rInfo) const2622 void PrintFontManager::fillPrintFontInfo( PrintFont* pFont, FastPrintFontInfo& rInfo ) const
2623 {
2624 ::std::hash_map< int, family::type >::const_iterator style_it =
2625 m_aFamilyTypes.find( pFont->m_nFamilyName );
2626 rInfo.m_eType = pFont->m_eType;
2627 rInfo.m_aFamilyName = m_pAtoms->getString( ATOM_FAMILYNAME, pFont->m_nFamilyName );
2628 rInfo.m_aStyleName = pFont->m_aStyleName;
2629 rInfo.m_eFamilyStyle = style_it != m_aFamilyTypes.end() ? style_it->second : family::Unknown;
2630 rInfo.m_eItalic = pFont->m_eItalic;
2631 rInfo.m_eWidth = pFont->m_eWidth;
2632 rInfo.m_eWeight = pFont->m_eWeight;
2633 rInfo.m_ePitch = pFont->m_ePitch;
2634 rInfo.m_aEncoding = pFont->m_aEncoding;
2635
2636 rInfo.m_bEmbeddable = (pFont->m_eType == fonttype::Type1);
2637 rInfo.m_bSubsettable = (pFont->m_eType == fonttype::TrueType); // TODO: rename to SfntType
2638
2639 rInfo.m_aAliases.clear();
2640 for( ::std::list< int >::iterator it = pFont->m_aAliases.begin(); it != pFont->m_aAliases.end(); ++it )
2641 rInfo.m_aAliases.push_back( m_pAtoms->getString( ATOM_FAMILYNAME, *it ) );
2642 }
2643
2644 // -------------------------------------------------------------------------
2645
fillPrintFontInfo(PrintFont * pFont,PrintFontInfo & rInfo) const2646 void PrintFontManager::fillPrintFontInfo( PrintFont* pFont, PrintFontInfo& rInfo ) const
2647 {
2648 if( ( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 ) ||
2649 ! pFont->m_pMetrics || pFont->m_pMetrics->isEmpty()
2650 )
2651 {
2652 // might be a truetype font not analyzed or type1 without metrics read
2653 if( pFont->m_eType == fonttype::Type1 )
2654 pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, false );
2655 else if( pFont->m_eType == fonttype::TrueType )
2656 analyzeTrueTypeFile( pFont );
2657 }
2658
2659 fillPrintFontInfo( pFont, static_cast< FastPrintFontInfo& >( rInfo ) );
2660
2661 rInfo.m_nAscend = pFont->m_nAscend;
2662 rInfo.m_nDescend = pFont->m_nDescend;
2663 rInfo.m_nLeading = pFont->m_nLeading;
2664 rInfo.m_nWidth = pFont->m_aGlobalMetricX.width < pFont->m_aGlobalMetricY.width ? pFont->m_aGlobalMetricY.width : pFont->m_aGlobalMetricX.width;
2665 }
2666
2667 // -------------------------------------------------------------------------
2668
getFontListWithInfo(::std::list<PrintFontInfo> & rFonts,const PPDParser * pParser,bool bUseOverrideMetrics)2669 void PrintFontManager::getFontListWithInfo( ::std::list< PrintFontInfo >& rFonts, const PPDParser* pParser, bool bUseOverrideMetrics )
2670 {
2671 rFonts.clear();
2672 ::std::list< fontID > aFontList;
2673 getFontList( aFontList, pParser, bUseOverrideMetrics );
2674
2675 ::std::list< fontID >::iterator it;
2676 for( it = aFontList.begin(); it != aFontList.end(); ++it )
2677 {
2678 PrintFontInfo aInfo;
2679 aInfo.m_nID = *it;
2680 fillPrintFontInfo( getFont( *it ), aInfo );
2681 rFonts.push_back( aInfo );
2682 }
2683 }
2684
2685 // -------------------------------------------------------------------------
2686
getFontListWithFastInfo(::std::list<FastPrintFontInfo> & rFonts,const PPDParser * pParser,bool bUseOverrideMetrics)2687 void PrintFontManager::getFontListWithFastInfo( ::std::list< FastPrintFontInfo >& rFonts, const PPDParser* pParser, bool bUseOverrideMetrics )
2688 {
2689 rFonts.clear();
2690 ::std::list< fontID > aFontList;
2691 getFontList( aFontList, pParser, bUseOverrideMetrics );
2692
2693 ::std::list< fontID >::iterator it;
2694 for( it = aFontList.begin(); it != aFontList.end(); ++it )
2695 {
2696 FastPrintFontInfo aInfo;
2697 aInfo.m_nID = *it;
2698 fillPrintFontInfo( getFont( *it ), aInfo );
2699 rFonts.push_back( aInfo );
2700 }
2701 }
2702
2703 // -------------------------------------------------------------------------
2704
getFontInfo(fontID nFontID,PrintFontInfo & rInfo) const2705 bool PrintFontManager::getFontInfo( fontID nFontID, PrintFontInfo& rInfo ) const
2706 {
2707 PrintFont* pFont = getFont( nFontID );
2708 if( pFont )
2709 {
2710 rInfo.m_nID = nFontID;
2711 fillPrintFontInfo( pFont, rInfo );
2712 }
2713 return pFont ? true : false;
2714 }
2715
2716 // -------------------------------------------------------------------------
2717
getFontFastInfo(fontID nFontID,FastPrintFontInfo & rInfo) const2718 bool PrintFontManager::getFontFastInfo( fontID nFontID, FastPrintFontInfo& rInfo ) const
2719 {
2720 PrintFont* pFont = getFont( nFontID );
2721 if( pFont )
2722 {
2723 rInfo.m_nID = nFontID;
2724 fillPrintFontInfo( pFont, rInfo );
2725 }
2726 return pFont ? true : false;
2727 }
2728
2729 // -------------------------------------------------------------------------
2730
getFontBoundingBox(fontID nFontID,int & xMin,int & yMin,int & xMax,int & yMax)2731 bool PrintFontManager::getFontBoundingBox( fontID nFontID, int& xMin, int& yMin, int& xMax, int& yMax )
2732 {
2733 bool bSuccess = false;
2734 PrintFont* pFont = getFont( nFontID );
2735 if( pFont )
2736 {
2737 if( pFont->m_nXMin == 0 && pFont->m_nYMin == 0 && pFont->m_nXMax == 0 && pFont->m_nYMax == 0 )
2738 {
2739 // might be a truetype font not analyzed or type1 without metrics read
2740 if( pFont->m_eType == fonttype::Type1 || pFont->m_eType == fonttype::Builtin )
2741 pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, true );
2742 else if( pFont->m_eType == fonttype::TrueType )
2743 analyzeTrueTypeFile( pFont );
2744 }
2745 bSuccess = true;
2746 xMin = pFont->m_nXMin;
2747 yMin = pFont->m_nYMin;
2748 xMax = pFont->m_nXMax;
2749 yMax = pFont->m_nYMax;
2750 }
2751 return bSuccess;
2752 }
2753
2754 // -------------------------------------------------------------------------
2755
getFontFaceNumber(fontID nFontID) const2756 int PrintFontManager::getFontFaceNumber( fontID nFontID ) const
2757 {
2758 int nRet = -1;
2759 PrintFont* pFont = getFont( nFontID );
2760 if( pFont && pFont->m_eType == fonttype::TrueType )
2761 nRet = static_cast< TrueTypeFontFile* >(pFont)->m_nCollectionEntry;
2762 return nRet;
2763 }
2764
2765 // -------------------------------------------------------------------------
2766
2767
matchFamilyName(const::rtl::OUString & rFamily) const2768 family::type PrintFontManager::matchFamilyName( const ::rtl::OUString& rFamily ) const
2769 {
2770 typedef struct {
2771 const char* mpName;
2772 sal_uInt16 mnLength;
2773 family::type meType;
2774 } family_t;
2775
2776 #define InitializeClass( p, a ) p, sizeof(p) - 1, a
2777 const family_t pFamilyMatch[] = {
2778 { InitializeClass( "arial", family::Swiss ) },
2779 { InitializeClass( "arioso", family::Script ) },
2780 { InitializeClass( "avant garde", family::Swiss ) },
2781 { InitializeClass( "avantgarde", family::Swiss ) },
2782 { InitializeClass( "bembo", family::Roman ) },
2783 { InitializeClass( "bookman", family::Roman ) },
2784 { InitializeClass( "conga", family::Roman ) },
2785 { InitializeClass( "courier", family::Modern ) },
2786 { InitializeClass( "curl", family::Script ) },
2787 { InitializeClass( "fixed", family::Modern ) },
2788 { InitializeClass( "gill", family::Swiss ) },
2789 { InitializeClass( "helmet", family::Modern ) },
2790 { InitializeClass( "helvetica", family::Swiss ) },
2791 { InitializeClass( "international", family::Modern ) },
2792 { InitializeClass( "lucida", family::Swiss ) },
2793 { InitializeClass( "new century schoolbook", family::Roman ) },
2794 { InitializeClass( "palatino", family::Roman ) },
2795 { InitializeClass( "roman", family::Roman ) },
2796 { InitializeClass( "sans serif", family::Swiss ) },
2797 { InitializeClass( "sansserif", family::Swiss ) },
2798 { InitializeClass( "serf", family::Roman ) },
2799 { InitializeClass( "serif", family::Roman ) },
2800 { InitializeClass( "times", family::Roman ) },
2801 { InitializeClass( "utopia", family::Roman ) },
2802 { InitializeClass( "zapf chancery", family::Script ) },
2803 { InitializeClass( "zapfchancery", family::Script ) }
2804 };
2805
2806 rtl::OString aFamily = rtl::OUStringToOString( rFamily, RTL_TEXTENCODING_ASCII_US );
2807 sal_uInt32 nLower = 0;
2808 sal_uInt32 nUpper = sizeof(pFamilyMatch) / sizeof(pFamilyMatch[0]);
2809
2810 while( nLower < nUpper )
2811 {
2812 sal_uInt32 nCurrent = (nLower + nUpper) / 2;
2813 const family_t* pHaystack = pFamilyMatch + nCurrent;
2814 sal_Int32 nComparison =
2815 rtl_str_compareIgnoreAsciiCase_WithLength
2816 (
2817 aFamily.getStr(), aFamily.getLength(),
2818 pHaystack->mpName, pHaystack->mnLength
2819 );
2820
2821 if( nComparison < 0 )
2822 nUpper = nCurrent;
2823 else
2824 if( nComparison > 0 )
2825 nLower = nCurrent + 1;
2826 else
2827 return pHaystack->meType;
2828 }
2829
2830 return family::Unknown;
2831 }
2832
2833 // -------------------------------------------------------------------------
2834
getFontFamilyType(fontID nFontID) const2835 family::type PrintFontManager::getFontFamilyType( fontID nFontID ) const
2836 {
2837 PrintFont* pFont = getFont( nFontID );
2838 if( !pFont )
2839 return family::Unknown;
2840
2841 ::std::hash_map< int, family::type >::const_iterator it =
2842 m_aFamilyTypes.find( pFont->m_nFamilyName );
2843 return (it != m_aFamilyTypes.end()) ? it->second : family::Unknown;
2844 }
2845
2846
2847 // -------------------------------------------------------------------------
2848
getFontFamily(fontID nFontID) const2849 const ::rtl::OUString& PrintFontManager::getFontFamily( fontID nFontID ) const
2850 {
2851 PrintFont* pFont = getFont( nFontID );
2852 return m_pAtoms->getString( ATOM_FAMILYNAME, pFont ? pFont->m_nFamilyName : INVALID_ATOM );
2853 }
2854
2855 // -------------------------------------------------------------------------
2856
getAfmFile(PrintFont * pFont) const2857 OString PrintFontManager::getAfmFile( PrintFont* pFont ) const
2858 {
2859 OString aMetricPath;
2860 if( pFont )
2861 {
2862 switch( pFont->m_eType )
2863 {
2864 case fonttype::Type1:
2865 {
2866 Type1FontFile* pPSFont = static_cast< Type1FontFile* >(pFont);
2867 aMetricPath = getDirectory( pPSFont->m_nDirectory );
2868 aMetricPath += "/";
2869 aMetricPath += pPSFont->m_aMetricFile;
2870 }
2871 break;
2872 case fonttype::Builtin:
2873 {
2874 BuiltinFont* pBuiltinFont = static_cast< BuiltinFont* >(pFont);
2875 aMetricPath = getDirectory( pBuiltinFont->m_nDirectory );
2876 aMetricPath += "/";
2877 aMetricPath += pBuiltinFont->m_aMetricFile;
2878 }
2879 break;
2880 default: break;
2881 }
2882 }
2883 return aMetricPath;
2884 }
2885
2886 // -------------------------------------------------------------------------
2887
getFontFile(PrintFont * pFont) const2888 OString PrintFontManager::getFontFile( PrintFont* pFont ) const
2889 {
2890 OString aPath;
2891
2892 if( pFont && pFont->m_eType == fonttype::Type1 )
2893 {
2894 Type1FontFile* pPSFont = static_cast< Type1FontFile* >(pFont);
2895 ::std::hash_map< int, OString >::const_iterator it = m_aAtomToDir.find( pPSFont->m_nDirectory );
2896 aPath = it->second;
2897 aPath += "/";
2898 aPath += pPSFont->m_aFontFile;
2899 }
2900 else if( pFont && pFont->m_eType == fonttype::TrueType )
2901 {
2902 TrueTypeFontFile* pTTFont = static_cast< TrueTypeFontFile* >(pFont);
2903 ::std::hash_map< int, OString >::const_iterator it = m_aAtomToDir.find( pTTFont->m_nDirectory );
2904 aPath = it->second;
2905 aPath += "/";
2906 aPath += pTTFont->m_aFontFile;
2907 }
2908 return aPath;
2909 }
2910
2911 // -------------------------------------------------------------------------
2912
getPSName(fontID nFontID) const2913 const ::rtl::OUString& PrintFontManager::getPSName( fontID nFontID ) const
2914 {
2915 PrintFont* pFont = getFont( nFontID );
2916 if( pFont && pFont->m_nPSName == 0 )
2917 {
2918 if( pFont->m_eType == fonttype::TrueType )
2919 analyzeTrueTypeFile( pFont );
2920 }
2921
2922 return m_pAtoms->getString( ATOM_PSNAME, pFont ? pFont->m_nPSName : INVALID_ATOM );
2923 }
2924
2925 // -------------------------------------------------------------------------
2926
getGlobalFontMetric(fontID nFontID,bool bHorizontal) const2927 const CharacterMetric& PrintFontManager::getGlobalFontMetric( fontID nFontID, bool bHorizontal ) const
2928 {
2929 static CharacterMetric aMetric;
2930 PrintFont* pFont = getFont( nFontID );
2931 return pFont ? ( bHorizontal ? pFont->m_aGlobalMetricX : pFont->m_aGlobalMetricY ) : aMetric;
2932 }
2933
2934 // -------------------------------------------------------------------------
2935
getFontAscend(fontID nFontID) const2936 int PrintFontManager::getFontAscend( fontID nFontID ) const
2937 {
2938 PrintFont* pFont = getFont( nFontID );
2939 if( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
2940 {
2941 // might be a truetype font not yet analyzed
2942 if( pFont->m_eType == fonttype::TrueType )
2943 analyzeTrueTypeFile( pFont );
2944 else if( pFont->m_eType == fonttype::Type1 || pFont->m_eType == fonttype::Builtin )
2945 pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, true );
2946 }
2947 return pFont->m_nAscend;
2948 }
2949
2950 // -------------------------------------------------------------------------
2951
getFontDescend(fontID nFontID) const2952 int PrintFontManager::getFontDescend( fontID nFontID ) const
2953 {
2954 PrintFont* pFont = getFont( nFontID );
2955 if( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
2956 {
2957 // might be a truetype font not yet analyzed
2958 if( pFont->m_eType == fonttype::TrueType )
2959 analyzeTrueTypeFile( pFont );
2960 else if( pFont->m_eType == fonttype::Type1 || pFont->m_eType == fonttype::Builtin )
2961 pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, true );
2962 }
2963 return pFont->m_nDescend;
2964 }
2965
2966 // -------------------------------------------------------------------------
2967
getFontLeading(fontID nFontID) const2968 int PrintFontManager::getFontLeading( fontID nFontID ) const
2969 {
2970 PrintFont* pFont = getFont( nFontID );
2971 if( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
2972 {
2973 // might be a truetype font not yet analyzed
2974 if( pFont->m_eType == fonttype::TrueType )
2975 analyzeTrueTypeFile( pFont );
2976 }
2977 return pFont->m_nLeading;
2978 }
2979
2980 // -------------------------------------------------------------------------
2981
hasVerticalSubstitutions(fontID nFontID) const2982 bool PrintFontManager::hasVerticalSubstitutions( fontID nFontID ) const
2983 {
2984 PrintFont* pFont = getFont( nFontID );
2985 if( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
2986 {
2987 // might be a truetype font not yet analyzed
2988 if( pFont->m_eType == fonttype::TrueType )
2989 analyzeTrueTypeFile( pFont );
2990 }
2991 return pFont->m_bHaveVerticalSubstitutedGlyphs;
2992 }
2993
2994 // -------------------------------------------------------------------------
2995
hasVerticalSubstitutions(fontID nFontID,const sal_Unicode * pCharacters,int nCharacters,bool * pHasSubst) const2996 void PrintFontManager::hasVerticalSubstitutions( fontID nFontID,
2997 const sal_Unicode* pCharacters, int nCharacters, bool* pHasSubst ) const
2998 {
2999 PrintFont* pFont = getFont( nFontID );
3000 if( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
3001 {
3002 // might be a truetype font not yet analyzed
3003 if( pFont->m_eType == fonttype::TrueType )
3004 analyzeTrueTypeFile( pFont );
3005 }
3006
3007 if( ! pFont->m_bHaveVerticalSubstitutedGlyphs )
3008 memset( pHasSubst, 0, sizeof(bool)*nCharacters );
3009 else
3010 {
3011 for( int i = 0; i < nCharacters; i++ )
3012 {
3013 sal_Unicode code = pCharacters[i];
3014 if( ! pFont->m_pMetrics ||
3015 ! ( pFont->m_pMetrics->m_aPages[ code >> 11 ] & ( 1 << ( ( code >> 8 ) & 7 ) ) ) )
3016 pFont->queryMetricPage( code >> 8, m_pAtoms );
3017 ::std::hash_map< sal_Unicode, bool >::const_iterator it = pFont->m_pMetrics->m_bVerticalSubstitutions.find( code );
3018 pHasSubst[i] = it != pFont->m_pMetrics->m_bVerticalSubstitutions.end();
3019 }
3020 }
3021 }
3022
3023 // -------------------------------------------------------------------------
3024
getFontXLFD(fontID nFontID) const3025 OUString PrintFontManager::getFontXLFD( fontID nFontID ) const
3026 {
3027 PrintFont* pFont = getFont( nFontID );
3028 OUString aRet;
3029 if( pFont )
3030 {
3031 ByteString aXLFD( getXLFD( pFont ) );
3032 rtl_TextEncoding aEncoding = aXLFD.GetToken( 6, '-' ).Search( "utf8" ) != STRING_NOTFOUND ? RTL_TEXTENCODING_UTF8 : RTL_TEXTENCODING_ISO_8859_1;
3033 aRet = OStringToOUString( aXLFD, aEncoding );
3034 }
3035 return aRet;
3036 }
3037
3038 // -------------------------------------------------------------------------
3039
getKernPairs(fontID nFontID,bool bVertical) const3040 const ::std::list< KernPair >& PrintFontManager::getKernPairs( fontID nFontID, bool bVertical ) const
3041 {
3042 static ::std::list< KernPair > aEmpty;
3043
3044 PrintFont* pFont = getFont( nFontID );
3045 if( ! pFont )
3046 return aEmpty;
3047
3048 if( ! pFont->m_pMetrics || ! pFont->m_pMetrics->m_bKernPairsQueried )
3049 pFont->queryMetricPage( 0, m_pAtoms );
3050 if( ! pFont->m_pMetrics || ! pFont->m_pMetrics->m_bKernPairsQueried )
3051 return aEmpty;
3052 return bVertical ? pFont->m_pMetrics->m_aYKernPairs : pFont->m_pMetrics->m_aXKernPairs;
3053 }
3054
3055 // -------------------------------------------------------------------------
3056
isFontDownloadingAllowed(fontID nFont) const3057 bool PrintFontManager::isFontDownloadingAllowed( fontID nFont ) const
3058 {
3059 static const char* pEnable = getenv( "PSPRINT_ENABLE_TTF_COPYRIGHTAWARENESS" );
3060 bool bRet = true;
3061
3062 if( pEnable && *pEnable )
3063 {
3064 PrintFont* pFont = getFont( nFont );
3065 if( pFont && pFont->m_eType == fonttype::TrueType )
3066 {
3067 TrueTypeFontFile* pTTFontFile = static_cast<TrueTypeFontFile*>(pFont);
3068 if( pTTFontFile->m_nTypeFlags & TYPEFLAG_INVALID )
3069 {
3070 TrueTypeFont* pTTFont = NULL;
3071 ByteString aFile = getFontFile( pFont );
3072 if( OpenTTFontFile( aFile.GetBuffer(), pTTFontFile->m_nCollectionEntry < 0 ? 0 : pTTFontFile->m_nCollectionEntry, &pTTFont ) == SF_OK )
3073 {
3074 // get type flags
3075 TTGlobalFontInfo aInfo;
3076 GetTTGlobalFontInfo( pTTFont, & aInfo );
3077 pTTFontFile->m_nTypeFlags = (unsigned int)aInfo.typeFlags;
3078 CloseTTFont( pTTFont );
3079 }
3080 }
3081
3082 unsigned int nCopyrightFlags = pTTFontFile->m_nTypeFlags & TYPEFLAG_COPYRIGHT_MASK;
3083
3084 // font embedding is allowed if either
3085 // no restriction at all (bit 1 clear)
3086 // printing allowed (bit 1 set, bit 2 set )
3087 bRet = ! ( nCopyrightFlags & 0x02 ) || ( nCopyrightFlags & 0x04 );
3088 }
3089 }
3090 return bRet;
3091 }
3092
3093 // -------------------------------------------------------------------------
3094
getMetrics(fontID nFontID,const sal_Unicode * pString,int nLen,CharacterMetric * pArray,bool bVertical) const3095 bool PrintFontManager::getMetrics( fontID nFontID, const sal_Unicode* pString, int nLen, CharacterMetric* pArray, bool bVertical ) const
3096 {
3097 PrintFont* pFont = getFont( nFontID );
3098 if( ! pFont )
3099 return false;
3100
3101 if( ( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
3102 || ! pFont->m_pMetrics || pFont->m_pMetrics->isEmpty()
3103 )
3104 {
3105 // might be a font not yet analyzed
3106 if( pFont->m_eType == fonttype::Type1 || pFont->m_eType == fonttype::Builtin )
3107 pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, false );
3108 else if( pFont->m_eType == fonttype::TrueType )
3109 analyzeTrueTypeFile( pFont );
3110 }
3111
3112 for( int i = 0; i < nLen; i++ )
3113 {
3114 if( ! pFont->m_pMetrics ||
3115 ! ( pFont->m_pMetrics->m_aPages[ pString[i] >> 11 ] & ( 1 << ( ( pString[i] >> 8 ) & 7 ) ) ) )
3116 pFont->queryMetricPage( pString[i] >> 8, m_pAtoms );
3117 pArray[i].width = pArray[i].height = -1;
3118 if( pFont->m_pMetrics )
3119 {
3120 int effectiveCode = pString[i];
3121 effectiveCode |= bVertical ? 1 << 16 : 0;
3122 ::std::hash_map< int, CharacterMetric >::const_iterator it =
3123 pFont->m_pMetrics->m_aMetrics.find( effectiveCode );
3124 // if no vertical metrics are available assume rotated horizontal metrics
3125 if( bVertical && (it == pFont->m_pMetrics->m_aMetrics.end()) )
3126 it = pFont->m_pMetrics->m_aMetrics.find( pString[i] );
3127 // the character metrics are in it->second
3128 if( it != pFont->m_pMetrics->m_aMetrics.end() )
3129 pArray[ i ] = it->second;
3130 }
3131 }
3132
3133 return true;
3134 }
3135
3136 // -------------------------------------------------------------------------
3137
getMetrics(fontID nFontID,sal_Unicode minCharacter,sal_Unicode maxCharacter,CharacterMetric * pArray,bool bVertical) const3138 bool PrintFontManager::getMetrics( fontID nFontID, sal_Unicode minCharacter, sal_Unicode maxCharacter, CharacterMetric* pArray, bool bVertical ) const
3139 {
3140 PrintFont* pFont = getFont( nFontID );
3141 if( ! pFont )
3142 return false;
3143
3144 if( ( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
3145 || ! pFont->m_pMetrics || pFont->m_pMetrics->isEmpty()
3146 )
3147 {
3148 // might be a font not yet analyzed
3149 if( pFont->m_eType == fonttype::Type1 || pFont->m_eType == fonttype::Builtin )
3150 pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, false );
3151 else if( pFont->m_eType == fonttype::TrueType )
3152 analyzeTrueTypeFile( pFont );
3153 }
3154
3155 sal_Unicode code = minCharacter;
3156 do
3157 {
3158 if( ! pFont->m_pMetrics ||
3159 ! ( pFont->m_pMetrics->m_aPages[ code >> 11 ] & ( 1 << ( ( code >> 8 ) & 7 ) ) ) )
3160 pFont->queryMetricPage( code >> 8, m_pAtoms );
3161 pArray[ code - minCharacter ].width = -1;
3162 pArray[ code - minCharacter ].height = -1;
3163 if( pFont->m_pMetrics )
3164 {
3165 int effectiveCode = code;
3166 effectiveCode |= bVertical ? 1 << 16 : 0;
3167 ::std::hash_map< int, CharacterMetric >::const_iterator it =
3168 pFont->m_pMetrics->m_aMetrics.find( effectiveCode );
3169 // if no vertical metrics are available assume rotated horizontal metrics
3170 if( bVertical && (it == pFont->m_pMetrics->m_aMetrics.end()) )
3171 it = pFont->m_pMetrics->m_aMetrics.find( code );
3172 // the character metrics are in it->second
3173 if( it != pFont->m_pMetrics->m_aMetrics.end() )
3174 pArray[ code - minCharacter ] = it->second;
3175 }
3176 } while( code++ != maxCharacter );
3177
3178 return true;
3179 }
3180
3181 // -------------------------------------------------------------------------
3182
createWriteablePath(const ByteString & rPath)3183 static bool createWriteablePath( const ByteString& rPath )
3184 {
3185 bool bSuccess = false;
3186
3187 if( access( rPath.GetBuffer(), W_OK ) )
3188 {
3189 int nPos = rPath.SearchBackward( '/' );
3190 if( nPos != STRING_NOTFOUND )
3191 while( nPos > 0 && rPath.GetChar( nPos ) == '/' )
3192 nPos--;
3193
3194 if( nPos != STRING_NOTFOUND && nPos != 0 && createWriteablePath( rPath.Copy( 0, nPos+1 ) ) )
3195 {
3196 bSuccess = mkdir( rPath.GetBuffer(), 0777 ) ? false : true;
3197 }
3198 }
3199 else
3200 bSuccess = true;
3201
3202 return bSuccess;
3203 }
3204
3205
3206 // -------------------------------------------------------------------------
3207
importFonts(const::std::list<OString> & rFiles,bool bLinkOnly,ImportFontCallback * pCallback)3208 int PrintFontManager::importFonts( const ::std::list< OString >& rFiles, bool bLinkOnly, ImportFontCallback* pCallback )
3209 {
3210 int nSuccess = 0;
3211
3212 // find a directory with write access
3213 rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
3214 bool bCanWrite = false;
3215 int nDirID = 0;
3216 INetURLObject aDir;
3217 for( ::std::list< int >::const_iterator dir_it = m_aPrivateFontDirectories.begin();
3218 ! bCanWrite && dir_it != m_aPrivateFontDirectories.end(); ++dir_it )
3219 {
3220 // check if we can create files in that directory
3221 ByteString aDirPath = getDirectory( *dir_it );
3222 if( createWriteablePath( aDirPath ) )
3223 {
3224 aDir = INetURLObject( OStringToOUString( aDirPath, aEncoding ), INET_PROT_FILE, INetURLObject::ENCODE_ALL );
3225 nDirID = *dir_it;
3226 bCanWrite = true;
3227 }
3228 }
3229 if( bCanWrite )
3230 {
3231 for( ::std::list< OString >::const_iterator font_it = rFiles.begin();
3232 font_it != rFiles.end(); ++font_it )
3233 {
3234 INetURLObject aFrom( OStringToOUString( *font_it, aEncoding ), INET_PROT_FILE, INetURLObject::ENCODE_ALL );
3235 INetURLObject aTo( aDir );
3236 aTo.Append( aFrom.GetName() );
3237
3238 if( pCallback )
3239 pCallback->progress( aTo.PathToFileName() );
3240
3241 if( pCallback && pCallback->isCanceled() )
3242 break;
3243
3244 if( ! access( ByteString( String(aTo.PathToFileName()), aEncoding ).GetBuffer(), F_OK ) )
3245 {
3246 if( ! ( pCallback ? pCallback->queryOverwriteFile( aTo.PathToFileName() ) : false ) )
3247 continue;
3248 }
3249 // look for afm if necessary
3250 OUString aAfmCopied;
3251 FileBase::RC nError;
3252 if( aFrom.getExtension().equalsIgnoreAsciiCaseAscii( "pfa" ) ||
3253 aFrom.getExtension().equalsIgnoreAsciiCaseAscii( "pfb" ) )
3254 {
3255 INetURLObject aFromAfm( aFrom );
3256 aFromAfm.setExtension( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "afm" ) ) );
3257 if( access( ByteString( String(aFromAfm.PathToFileName()), aEncoding ).GetBuffer(), F_OK ) )
3258 {
3259 aFromAfm.setExtension( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "AFM" ) ) );
3260 if( access( ByteString( String(aFromAfm.PathToFileName()), aEncoding ).GetBuffer(), F_OK ) )
3261 {
3262 aFromAfm.removeSegment();
3263 aFromAfm.Append( String( RTL_CONSTASCII_USTRINGPARAM( "afm" ) ) );
3264 aFromAfm.Append( aTo.GetName() );
3265 aFromAfm.setExtension( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "afm" ) ) );
3266 if( access( ByteString( String(aFromAfm.PathToFileName()), aEncoding ).GetBuffer(), F_OK ) )
3267 {
3268 aFromAfm.setExtension( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "AFM" ) ) );
3269 if( access( ByteString( String(aFromAfm.PathToFileName()), aEncoding ).GetBuffer(), F_OK ) )
3270 {
3271 // give up
3272 if( pCallback )
3273 pCallback->importFontFailed( aTo.PathToFileName(), ImportFontCallback::NoAfmMetric );
3274 continue;
3275 }
3276 }
3277 }
3278 }
3279 INetURLObject aToAfm( aTo );
3280 aToAfm.setExtension( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "afm" ) ) );
3281 OUString aFromPath, aToPath;
3282 if( bLinkOnly )
3283 {
3284 ByteString aLinkFromPath( String(aFromAfm.PathToFileName()),
3285 aEncoding );
3286 ByteString aLinkToPath( String(aToAfm.PathToFileName()),
3287 aEncoding );
3288 nError = (FileBase::RC)symlink( aLinkFromPath.GetBuffer(), aLinkToPath.GetBuffer() );
3289 }
3290 else
3291 nError = File::copy( aFromAfm.GetMainURL(INetURLObject::DECODE_TO_IURI), aToAfm.GetMainURL(INetURLObject::DECODE_TO_IURI) );
3292 if( nError )
3293 {
3294 if( pCallback )
3295 pCallback->importFontFailed( aTo.PathToFileName(), ImportFontCallback::AfmCopyFailed );
3296 continue;
3297 }
3298 aAfmCopied = aToPath;
3299 }
3300 if( bLinkOnly )
3301 {
3302 ByteString aFromPath( String(aFrom.PathToFileName()),
3303 aEncoding );
3304 ByteString aToPath( String(aTo.PathToFileName()), aEncoding );
3305 nError = (FileBase::RC)symlink( aFromPath.GetBuffer(),
3306 aToPath.GetBuffer() );
3307 }
3308 else
3309 nError = File::copy( aFrom.GetMainURL(INetURLObject::DECODE_TO_IURI), aTo.GetMainURL(INetURLObject::DECODE_TO_IURI) );
3310 // copy font file
3311 if( nError )
3312 {
3313 if( aAfmCopied.getLength() )
3314 File::remove( aAfmCopied );
3315 if( pCallback )
3316 pCallback->importFontFailed( aTo.PathToFileName(), ImportFontCallback::FontCopyFailed );
3317 continue;
3318 }
3319
3320 ::std::list< PrintFont* > aNewFonts;
3321 ::std::list< PrintFont* >::iterator it;
3322 if( analyzeFontFile( nDirID, OUStringToOString( aTo.GetName(), aEncoding ), ::std::list<OString>(), aNewFonts ) )
3323 {
3324 // remove all fonts for the same file
3325 // discarding their font ids
3326 ::std::hash_map< fontID, PrintFont* >::iterator current, next;
3327 current = m_aFonts.begin();
3328 OString aFileName( OUStringToOString( aTo.GetName(), aEncoding ) );
3329 while( current != m_aFonts.end() )
3330 {
3331 bool bRemove = false;
3332 switch( current->second->m_eType )
3333 {
3334 case fonttype::Type1:
3335 if( static_cast<Type1FontFile*>(current->second)->m_aFontFile == aFileName )
3336 bRemove = true;
3337 break;
3338 case fonttype::TrueType:
3339 if( static_cast<TrueTypeFontFile*>(current->second)->m_aFontFile == aFileName )
3340 bRemove = true;
3341 break;
3342 default: break;
3343 }
3344 if( bRemove )
3345 {
3346 next = current;
3347 ++next;
3348 m_aFontFileToFontID[ aFileName ].erase( current->first );
3349 delete current->second;
3350 m_aFonts.erase( current );
3351 current = next;
3352 }
3353 else
3354 ++current;
3355 }
3356
3357 DBG_ASSERT( !findFontFileID( nDirID, aFileName ), "not all fonts removed for file" );
3358
3359 nSuccess++;
3360 for( it = aNewFonts.begin(); it != aNewFonts.end(); ++it )
3361 {
3362 m_aFontFileToFontID[ aFileName ].insert( m_nNextFontID );
3363 m_aFonts[ m_nNextFontID++ ] = *it;
3364 m_pFontCache->updateFontCacheEntry( *it, false );
3365 }
3366 }
3367 }
3368
3369 m_pFontCache->updateDirTimestamp( nDirID );
3370 m_pFontCache->flush();
3371 }
3372 else if( pCallback )
3373 pCallback->importFontsFailed( ImportFontCallback::NoWritableDirectory );
3374
3375 return nSuccess;
3376 }
3377
3378 // -------------------------------------------------------------------------
3379
checkImportPossible() const3380 bool PrintFontManager::checkImportPossible() const
3381 {
3382 bool bSuccess = false;
3383
3384 // find a directory with write access
3385 ByteString aDir;
3386 for( std::list< int >::const_iterator dir_it = m_aPrivateFontDirectories.begin();
3387 dir_it != m_aPrivateFontDirectories.end(); ++dir_it )
3388 {
3389 aDir = getDirectory( *dir_it );
3390 if( createWriteablePath( aDir ) )
3391 {
3392 bSuccess = true;
3393 break;
3394 }
3395 }
3396
3397 #if OSL_DEBUG_LEVEL > 1
3398 if( bSuccess )
3399 fprintf( stderr, "found writable %s\n", aDir.GetBuffer() );
3400 #endif
3401
3402 return bSuccess;
3403 }
3404
3405 // -------------------------------------------------------------------------
3406
checkChangeFontPropertiesPossible(fontID) const3407 bool PrintFontManager::checkChangeFontPropertiesPossible( fontID /*nFontID*/ ) const
3408 {
3409 // since font properties are changed in the font cache file only nowadays
3410 // they can always be changed
3411 return true;
3412 }
3413
3414 // -------------------------------------------------------------------------
3415
changeFontProperties(fontID nFontID,const::rtl::OUString & rXLFD)3416 bool PrintFontManager::changeFontProperties( fontID nFontID, const ::rtl::OUString& rXLFD )
3417 {
3418 ByteString aXLFD( OUStringToOString( rXLFD, RTL_TEXTENCODING_UTF8 ) );
3419 ByteString aAddStyle = aXLFD.GetToken( '-', 6 );
3420 if( aAddStyle.Search( "utf8" ) == STRING_NOTFOUND )
3421 {
3422 aAddStyle.Append( aAddStyle.Len() ? ";utf8" : "utf8" );
3423 aXLFD.SetToken( 6, ';', aAddStyle );
3424 }
3425 PrintFont* pFont = getFont( nFontID );
3426 std::list< OString > aDummyList;
3427 aDummyList.push_back( aXLFD );
3428 getFontAttributesFromXLFD( pFont, aDummyList );
3429 pFont->m_bUserOverride = true;
3430 m_pFontCache->updateFontCacheEntry( pFont, true );
3431
3432 return true;
3433 }
3434
3435 // -------------------------------------------------------------------------
3436
3437 bool PrintFontManager::
getImportableFontProperties(const OString & rFile,::std::list<FastPrintFontInfo> & rFontProps)3438 getImportableFontProperties(
3439 const OString& rFile,
3440 ::std::list< FastPrintFontInfo >& rFontProps
3441 )
3442 {
3443 rFontProps.clear();
3444 int nIndex = rFile.lastIndexOf( '/' );
3445 OString aDir, aFile( rFile.copy( nIndex+1 ) );
3446 if( nIndex != -1 )
3447 aDir = rFile.copy( 0, nIndex );
3448 int nDirID = getDirectoryAtom( aDir, true );
3449 ::std::list< PrintFont* > aFonts;
3450 bool bRet = analyzeFontFile( nDirID, aFile, ::std::list<OString>(), aFonts );
3451 while( aFonts.begin() != aFonts.end() )
3452 {
3453 PrintFont* pFont = aFonts.front();
3454 aFonts.pop_front();
3455 FastPrintFontInfo aInfo;
3456 fillPrintFontInfo( pFont, aInfo );
3457 rFontProps.push_back( aInfo );
3458 delete pFont;
3459 }
3460 return bRet;
3461 }
3462
3463 // -------------------------------------------------------------------------
3464
getFileDuplicates(fontID nFont,::std::list<fontID> & rFonts) const3465 bool PrintFontManager::getFileDuplicates( fontID nFont, ::std::list< fontID >& rFonts ) const
3466 {
3467 bool bRet = false;
3468
3469 rFonts.clear();
3470
3471 PrintFont* pSearchFont = getFont( nFont );
3472 if( ! pSearchFont ||
3473 pSearchFont->m_eType != fonttype::TrueType ||
3474 static_cast<TrueTypeFontFile*>(pSearchFont)->m_nCollectionEntry == -1
3475 )
3476 return false;
3477
3478 OString aFile( getFontFileSysPath( nFont ) );
3479 if( ! aFile.getLength() )
3480 return false;
3481
3482 for( ::std::hash_map< fontID, PrintFont* >::const_iterator it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
3483 {
3484 if( nFont != it->first )
3485 {
3486 OString aCompFile( getFontFile( it->second ) );
3487 if( aCompFile == aFile )
3488 {
3489 rFonts.push_back( it->first );
3490 bRet = true;
3491 }
3492 }
3493 }
3494 return bRet;
3495 }
3496
3497 // -------------------------------------------------------------------------
3498
removeFonts(const::std::list<fontID> & rFonts)3499 bool PrintFontManager::removeFonts( const ::std::list< fontID >& rFonts )
3500 {
3501 bool bRet = true;
3502 ::std::list< fontID > aDuplicates;
3503 for( ::std::list< fontID >::const_iterator it = rFonts.begin(); it != rFonts.end(); ++it )
3504 {
3505 ::std::hash_map< fontID, PrintFont* >::const_iterator haveFont = m_aFonts.find( *it );
3506 if( haveFont == m_aFonts.end() )
3507 continue;
3508
3509 PrintFont* pFont = haveFont->second;
3510 bool bRemoveDuplicates = getFileDuplicates( *it, aDuplicates );
3511 ByteString aFile( getFontFile( pFont ) );
3512 if( aFile.Len() )
3513 {
3514 #if OSL_DEBUG_LEVEL > 1
3515 fprintf( stderr, "try unlink( \"%s\" ) ... ", aFile.GetBuffer() );
3516 #endif
3517 if( unlink( aFile.GetBuffer() ) )
3518 {
3519 bRet = false;
3520 #if OSL_DEBUG_LEVEL > 1
3521 fprintf( stderr, "failed\n" );
3522 #endif
3523 continue;
3524 }
3525 #if OSL_DEBUG_LEVEL > 1
3526 fprintf( stderr, "succeeded\n" );
3527 #endif
3528 OString aAfm( getAfmFile( pFont ) );
3529 if( aAfm.getLength() )
3530 {
3531 #if OSL_DEBUG_LEVEL > 1
3532 fprintf( stderr, "unlink( \"%s\" )\n", aAfm.getStr() );
3533 #endif
3534 unlink( aAfm.getStr() );
3535 }
3536 m_aFonts.erase( *it );
3537 delete pFont;
3538 if( bRemoveDuplicates )
3539 {
3540 for( ::std::list< fontID >::iterator dup = aDuplicates.begin(); dup != aDuplicates.end(); ++dup )
3541 {
3542 m_aFontFileToFontID[ aFile ].erase( *dup );
3543 PrintFont* pDup = m_aFonts[ *dup ];
3544 m_aFonts.erase( *dup );
3545 delete pDup;
3546 }
3547 }
3548 }
3549 }
3550 return bRet;
3551 }
3552
3553 // -------------------------------------------------------------------------
3554
isPrivateFontFile(fontID nFont) const3555 bool PrintFontManager::isPrivateFontFile( fontID nFont ) const
3556 {
3557 bool bRet = false;
3558 int nDirID = -1;
3559 PrintFont* pFont = getFont( nFont );
3560 if( pFont )
3561 {
3562 switch( pFont->m_eType )
3563 {
3564 case fonttype::Type1: nDirID = static_cast< Type1FontFile* >(pFont)->m_nDirectory;break;
3565 case fonttype::TrueType: nDirID = static_cast< TrueTypeFontFile* >(pFont)->m_nDirectory;break;
3566 default: break;
3567 }
3568 }
3569 if( nDirID != -1 )
3570 {
3571 for( ::std::list< int >::const_iterator it = m_aPrivateFontDirectories.begin(); it != m_aPrivateFontDirectories.end(); ++it )
3572 {
3573 if( nDirID == *it )
3574 {
3575 bRet = true;
3576 break;
3577 }
3578 }
3579 }
3580 return bRet;
3581 }
3582
3583 // -------------------------------------------------------------------------
3584
getAlternativeFamilyNames(fontID nFont,::std::list<OUString> & rNames) const3585 bool PrintFontManager::getAlternativeFamilyNames( fontID nFont, ::std::list< OUString >& rNames ) const
3586 {
3587 rNames.clear();
3588
3589 PrintFont* pFont = getFont( nFont );
3590 if( pFont && pFont->m_eType == fonttype::TrueType )
3591 {
3592 TrueTypeFontFile* pTTFontFile = static_cast< TrueTypeFontFile* >(pFont);
3593 ByteString aFile( getFontFile( pFont ) );
3594 TrueTypeFont* pTTFont;
3595 if( OpenTTFontFile( aFile.GetBuffer(), pTTFontFile->m_nCollectionEntry < 0 ? 0 : pTTFontFile->m_nCollectionEntry, &pTTFont ) == SF_OK )
3596 {
3597 NameRecord* pNameRecords = NULL;
3598 int nNameRecords = GetTTNameRecords( pTTFont, &pNameRecords );
3599 for( int i = 0; i < nNameRecords; i++ )
3600 {
3601 if( pNameRecords[i].nameID != 1 ) // family name
3602 continue;
3603
3604 OUString aFamily( convertTrueTypeName( pNameRecords+i ) );
3605 if( aFamily.getLength()
3606 &&
3607 m_pAtoms->getAtom( ATOM_FAMILYNAME, aFamily, sal_True ) != pFont->m_nFamilyName
3608 )
3609 {
3610 rNames.push_back( aFamily );
3611 }
3612 }
3613
3614 if( nNameRecords )
3615 DisposeNameRecords( pNameRecords, nNameRecords );
3616 CloseTTFont( pTTFont );
3617 }
3618 }
3619 return rNames.begin() != rNames.end();
3620 }
3621
3622 // -------------------------------------------------------------------------
3623
3624 // TODO: move most of this stuff into the central font-subsetting code
createFontSubset(FontSubsetInfo & rInfo,fontID nFont,const OUString & rOutFile,sal_GlyphId * pGlyphIds,sal_uInt8 * pNewEncoding,sal_Int32 * pWidths,int nGlyphs,bool bVertical)3625 bool PrintFontManager::createFontSubset(
3626 FontSubsetInfo& rInfo,
3627 fontID nFont,
3628 const OUString& rOutFile,
3629 sal_GlyphId* pGlyphIds,
3630 sal_uInt8* pNewEncoding,
3631 sal_Int32* pWidths,
3632 int nGlyphs,
3633 bool bVertical
3634 )
3635 {
3636 PrintFont* pFont = getFont( nFont );
3637 if( !pFont )
3638 return false;
3639
3640 switch( pFont->m_eType )
3641 {
3642 case psp::fonttype::TrueType: rInfo.m_nFontType = FontSubsetInfo::SFNT_TTF; break;
3643 case psp::fonttype::Type1: rInfo.m_nFontType = FontSubsetInfo::ANY_TYPE1; break;
3644 default:
3645 return false;
3646 }
3647 // TODO: remove when Type1 subsetting gets implemented
3648 if( pFont->m_eType != fonttype::TrueType )
3649 return false;
3650
3651 // reshuffle array of requested glyphs to make sure glyph0==notdef
3652 sal_uInt8 pEnc[256];
3653 sal_uInt16 pGID[256];
3654 sal_uInt8 pOldIndex[256];
3655 memset( pEnc, 0, sizeof( pEnc ) );
3656 memset( pGID, 0, sizeof( pGID ) );
3657 memset( pOldIndex, 0, sizeof( pOldIndex ) );
3658 if( nGlyphs > 256 )
3659 return false;
3660 int nChar = 1;
3661 for( int i = 0; i < nGlyphs; i++ )
3662 {
3663 if( pNewEncoding[i] == 0 )
3664 {
3665 pOldIndex[ 0 ] = i;
3666 }
3667 else
3668 {
3669 DBG_ASSERT( !(pGlyphIds[i] & 0x007f0000), "overlong glyph id" );
3670 DBG_ASSERT( (int)pNewEncoding[i] < nGlyphs, "encoding wrong" );
3671 DBG_ASSERT( pEnc[pNewEncoding[i]] == 0 && pGID[pNewEncoding[i]] == 0, "duplicate encoded glyph" );
3672 pEnc[ pNewEncoding[i] ] = pNewEncoding[i];
3673 pGID[ pNewEncoding[i] ] = (sal_uInt16)pGlyphIds[ i ];
3674 pOldIndex[ pNewEncoding[i] ] = i;
3675 nChar++;
3676 }
3677 }
3678 nGlyphs = nChar; // either input value or increased by one
3679
3680 // prepare system name for read access for subset source file
3681 // TODO: since this file is usually already mmapped there is no need to open it again
3682 const ByteString aFromFile = getFontFile( pFont );
3683
3684 TrueTypeFont* pTTFont = NULL; // TODO: rename to SfntFont
3685 TrueTypeFontFile* pTTFontFile = static_cast< TrueTypeFontFile* >(pFont);
3686 if( OpenTTFontFile( aFromFile.GetBuffer(), pTTFontFile->m_nCollectionEntry < 0 ? 0 : pTTFontFile->m_nCollectionEntry, &pTTFont ) != SF_OK )
3687 return false;
3688
3689 // prepare system name for write access for subset file target
3690 OUString aSysPath;
3691 if( osl_File_E_None != osl_getSystemPathFromFileURL( rOutFile.pData, &aSysPath.pData ) )
3692 return false;
3693 const rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
3694 const ByteString aToFile( OUStringToOString( aSysPath, aEncoding ) );
3695
3696 // do CFF subsetting if possible
3697 int nCffLength = 0;
3698 const sal_uInt8* pCffBytes = NULL;
3699 if( GetSfntTable( pTTFont, O_CFF, &pCffBytes, &nCffLength ) )
3700 {
3701 rInfo.LoadFont( FontSubsetInfo::CFF_FONT, pCffBytes, nCffLength );
3702 #if 1 // TODO: remove 16bit->long conversion when related methods handle non-16bit glyphids
3703 sal_GlyphId aRequestedGlyphIds[256];
3704 for( int i = 0; i < nGlyphs; ++i )
3705 aRequestedGlyphIds[i] = pGID[i];
3706 #endif
3707 // create subset file at requested path
3708 FILE* pOutFile = fopen( aToFile.GetBuffer(), "wb" );
3709 // create font subset
3710 const char* pGlyphSetName = NULL; // TODO: better name?
3711 const bool bOK = rInfo.CreateFontSubset(
3712 FontSubsetInfo::TYPE1_PFB,
3713 pOutFile, pGlyphSetName,
3714 aRequestedGlyphIds, pEnc, nGlyphs, pWidths );
3715 fclose( pOutFile );
3716 // cleanup before early return
3717 CloseTTFont( pTTFont );
3718 return bOK;
3719 }
3720
3721 // do TTF->Type42 or Type3 subsetting
3722 // fill in font info
3723 psp::PrintFontInfo aFontInfo;
3724 if( ! getFontInfo( nFont, aFontInfo ) )
3725 return false;
3726
3727 rInfo.m_nAscent = aFontInfo.m_nAscend;
3728 rInfo.m_nDescent = aFontInfo.m_nDescend;
3729 rInfo.m_aPSName = getPSName( nFont );
3730
3731 int xMin, yMin, xMax, yMax;
3732 getFontBoundingBox( nFont, xMin, yMin, xMax, yMax );
3733 rInfo.m_aFontBBox = Rectangle( Point( xMin, yMin ), Size( xMax-xMin, yMax-yMin ) );
3734 rInfo.m_nCapHeight = yMax; // Well ...
3735
3736 // fill in glyph advance widths
3737 TTSimpleGlyphMetrics* pMetrics = GetTTSimpleGlyphMetrics( pTTFont,
3738 pGID,
3739 nGlyphs,
3740 bVertical ? 1 : 0 );
3741 if( pMetrics )
3742 {
3743 for( int i = 0; i < nGlyphs; i++ )
3744 pWidths[pOldIndex[i]] = pMetrics[i].adv;
3745 free( pMetrics );
3746 }
3747 else
3748 {
3749 CloseTTFont( pTTFont );
3750 return false;
3751 }
3752
3753 bool bSuccess = ( SF_OK == CreateTTFromTTGlyphs( pTTFont,
3754 aToFile.GetBuffer(),
3755 pGID,
3756 pEnc,
3757 nGlyphs,
3758 0,
3759 NULL,
3760 0 ) );
3761 CloseTTFont( pTTFont );
3762
3763 return bSuccess;
3764 }
3765
getGlyphWidths(fontID nFont,bool bVertical,std::vector<sal_Int32> & rWidths,std::map<sal_Unicode,sal_uInt32> & rUnicodeEnc)3766 void PrintFontManager::getGlyphWidths( fontID nFont,
3767 bool bVertical,
3768 std::vector< sal_Int32 >& rWidths,
3769 std::map< sal_Unicode, sal_uInt32 >& rUnicodeEnc )
3770 {
3771 PrintFont* pFont = getFont( nFont );
3772 if( !pFont ||
3773 (pFont->m_eType != fonttype::TrueType && pFont->m_eType != fonttype::Type1) )
3774 return;
3775 if( pFont->m_eType == fonttype::TrueType )
3776 {
3777 TrueTypeFont* pTTFont = NULL;
3778 TrueTypeFontFile* pTTFontFile = static_cast< TrueTypeFontFile* >(pFont);
3779 ByteString aFromFile = getFontFile( pFont );
3780 if( OpenTTFontFile( aFromFile.GetBuffer(), pTTFontFile->m_nCollectionEntry < 0 ? 0 : pTTFontFile->m_nCollectionEntry, &pTTFont ) != SF_OK )
3781 return;
3782 int nGlyphs = GetTTGlyphCount( pTTFont );
3783 if( nGlyphs > 0 )
3784 {
3785 rWidths.resize(nGlyphs);
3786 std::vector<sal_uInt16> aGlyphIds(nGlyphs);
3787 for( int i = 0; i < nGlyphs; i++ )
3788 aGlyphIds[i] = sal_uInt16(i);
3789 TTSimpleGlyphMetrics* pMetrics = GetTTSimpleGlyphMetrics( pTTFont,
3790 &aGlyphIds[0],
3791 nGlyphs,
3792 bVertical ? 1 : 0 );
3793 if( pMetrics )
3794 {
3795 for( int i = 0; i< nGlyphs; i++ )
3796 rWidths[i] = pMetrics[i].adv;
3797 free( pMetrics );
3798 rUnicodeEnc.clear();
3799 }
3800
3801 // fill the unicode map
3802 // TODO: isn't this map already available elsewhere in the fontmanager?
3803 const sal_uInt8* pCmapData = NULL;
3804 int nCmapSize = 0;
3805 if( GetSfntTable( pTTFont, O_cmap, &pCmapData, &nCmapSize ) )
3806 {
3807 CmapResult aCmapResult;
3808 if( ParseCMAP( pCmapData, nCmapSize, aCmapResult ) )
3809 {
3810 const ImplFontCharMap aCharMap( aCmapResult );
3811 for( sal_uInt32 cOld = 0;;)
3812 {
3813 // get next unicode covered by font
3814 const sal_uInt32 c = aCharMap.GetNextChar( cOld );
3815 if( c == cOld )
3816 break;
3817 cOld = c;
3818 #if 1 // TODO: remove when sal_Unicode covers all of unicode
3819 if( c > (sal_Unicode)~0 )
3820 break;
3821 #endif
3822 // get the matching glyph index
3823 const sal_GlyphId aGlyphId = aCharMap.GetGlyphIndex( c );
3824 // update the requested map
3825 rUnicodeEnc[ (sal_Unicode)c ] = aGlyphId;
3826 }
3827 }
3828 }
3829 }
3830 CloseTTFont( pTTFont );
3831 }
3832 else if( pFont->m_eType == fonttype::Type1 )
3833 {
3834 if( ! pFont->m_aEncodingVector.size() )
3835 pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, true, true );
3836 if( pFont->m_pMetrics )
3837 {
3838 rUnicodeEnc.clear();
3839 rWidths.clear();
3840 rWidths.reserve( pFont->m_pMetrics->m_aMetrics.size() );
3841 for( std::hash_map< int, CharacterMetric >::const_iterator it =
3842 pFont->m_pMetrics->m_aMetrics.begin();
3843 it != pFont->m_pMetrics->m_aMetrics.end(); ++it )
3844 {
3845 if( (it->first & 0x00010000) == 0 || bVertical )
3846 {
3847 rUnicodeEnc[ sal_Unicode(it->first & 0x0000ffff) ] = sal_uInt32(rWidths.size());
3848 rWidths.push_back( it->second.width );
3849 }
3850 }
3851 }
3852 }
3853 }
3854
3855 // -------------------------------------------------------------------------
3856
getEncodingMap(fontID nFont,const std::map<sal_Unicode,rtl::OString> ** pNonEncoded) const3857 const std::map< sal_Unicode, sal_Int32 >* PrintFontManager::getEncodingMap( fontID nFont, const std::map< sal_Unicode, rtl::OString >** pNonEncoded ) const
3858 {
3859 PrintFont* pFont = getFont( nFont );
3860 if( !pFont ||
3861 (pFont->m_eType != fonttype::Type1 && pFont->m_eType != fonttype::Builtin)
3862 )
3863 return NULL;
3864
3865 if( ! pFont->m_aEncodingVector.size() )
3866 pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, true, true );
3867
3868 if( pNonEncoded )
3869 *pNonEncoded = pFont->m_aNonEncoded.size() ? &pFont->m_aNonEncoded : NULL;
3870
3871 return pFont->m_aEncodingVector.size() ? &pFont->m_aEncodingVector : NULL;
3872 }
3873
3874 // -------------------------------------------------------------------------
3875
getAdobeNameFromUnicode(sal_Unicode aChar) const3876 std::list< OString > PrintFontManager::getAdobeNameFromUnicode( sal_Unicode aChar ) const
3877 {
3878 std::pair< std::hash_multimap< sal_Unicode, rtl::OString >::const_iterator,
3879 std::hash_multimap< sal_Unicode, rtl::OString >::const_iterator > range
3880 = m_aUnicodeToAdobename.equal_range( aChar );
3881
3882 std::list< OString > aRet;
3883 for( ; range.first != range.second; ++range.first )
3884 aRet.push_back( range.first->second );
3885
3886 if( aRet.begin() == aRet.end() && aChar != 0 )
3887 {
3888 sal_Char aBuf[8];
3889 sal_Int32 nChars = snprintf( (char*)aBuf, sizeof( aBuf ), "uni%.4hX", aChar );
3890 aRet.push_back( OString( aBuf, nChars ) );
3891 }
3892
3893 return aRet;
3894 }
3895
3896 // -------------------------------------------------------------------------
getUnicodeFromAdobeName(const rtl::OString & rName) const3897 std::list< sal_Unicode > PrintFontManager::getUnicodeFromAdobeName( const rtl::OString& rName ) const
3898 {
3899 std::pair< std::hash_multimap< rtl::OString, sal_Unicode, rtl::OStringHash >::const_iterator,
3900 std::hash_multimap< rtl::OString, sal_Unicode, rtl::OStringHash >::const_iterator > range
3901 = m_aAdobenameToUnicode.equal_range( rName );
3902
3903 std::list< sal_Unicode > aRet;
3904 for( ; range.first != range.second; ++range.first )
3905 aRet.push_back( range.first->second );
3906
3907 if( aRet.begin() == aRet.end() )
3908 {
3909 if( rName.getLength() == 7 && rName.indexOf( "uni" ) == 0 )
3910 {
3911 sal_Unicode aCode = (sal_Unicode)rName.copy( 3 ).toInt32( 16 );
3912 aRet.push_back( aCode );
3913 }
3914 }
3915
3916 return aRet;
3917 }
3918
3919 // -------------------------------------------------------------------------
3920 namespace
3921 {
getString(const Any & rAny)3922 OUString getString( const Any& rAny )
3923 {
3924 OUString aStr;
3925 rAny >>= aStr;
3926 return aStr;
3927 }
getBool(const Any & rAny)3928 bool getBool( const Any& rAny )
3929 {
3930 sal_Bool bBool = sal_False;
3931 rAny >>= bBool;
3932 return static_cast<bool>(bBool);
3933 }
getInt(const Any & rAny)3934 sal_Int32 getInt( const Any& rAny )
3935 {
3936 sal_Int32 n = 0;
3937 rAny >>= n;
3938 return n;
3939 }
3940 }
readOverrideMetrics()3941 bool PrintFontManager::readOverrideMetrics()
3942 {
3943 if( ! m_aOverrideFonts.empty() )
3944 return false;
3945
3946 css::uno::Reference< XMultiServiceFactory > xFact( comphelper::getProcessServiceFactory() );
3947 if( !xFact.is() )
3948 return false;
3949 css::uno::Reference< XMaterialHolder > xMat(
3950 xFact->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.psprint.CompatMetricOverride" ) ) ),
3951 UNO_QUERY );
3952 if( !xMat.is() )
3953 return false;
3954
3955 Any aAny( xMat->getMaterial() );
3956 Sequence< Any > aOverrideFonts;
3957 if( ! (aAny >>= aOverrideFonts ) )
3958 return false;
3959 sal_Int32 nFonts = aOverrideFonts.getLength();
3960 for( sal_Int32 i = 0; i < nFonts; i++ )
3961 {
3962 Sequence< NamedValue > aMetrics;
3963 if( ! (aOverrideFonts.getConstArray()[i] >>= aMetrics) )
3964 continue;
3965 BuiltinFont* pFont = new BuiltinFont();
3966 pFont->m_nDirectory = 0;
3967 pFont->m_bUserOverride = false;
3968 pFont->m_pMetrics = new PrintFontMetrics;
3969 memset( pFont->m_pMetrics->m_aPages, 0xff, sizeof( pFont->m_pMetrics->m_aPages ) );
3970 pFont->m_pMetrics->m_bKernPairsQueried = true;
3971 sal_Int32 nProps = aMetrics.getLength();
3972 const NamedValue* pProps = aMetrics.getConstArray();
3973 for( sal_Int32 n = 0; n < nProps; n++ )
3974 {
3975 if( pProps[n].Name.equalsAscii( "FamilyName" ) )
3976 pFont->m_nFamilyName = m_pAtoms->getAtom( ATOM_FAMILYNAME,
3977 getString(pProps[n].Value),
3978 sal_True );
3979 else if( pProps[n].Name.equalsAscii( "PSName" ) )
3980 pFont->m_nPSName = m_pAtoms->getAtom( ATOM_PSNAME,
3981 getString(pProps[n].Value),
3982 sal_True );
3983 else if( pProps[n].Name.equalsAscii( "StyleName" ) )
3984 pFont->m_aStyleName = getString(pProps[n].Value);
3985 else if( pProps[n].Name.equalsAscii( "Italic" ) )
3986 pFont->m_eItalic = static_cast<italic::type>(getInt(pProps[n].Value));
3987 else if( pProps[n].Name.equalsAscii( "Width" ) )
3988 pFont->m_eWidth = static_cast<width::type>(getInt(pProps[n].Value));
3989 else if( pProps[n].Name.equalsAscii( "Weight" ) )
3990 pFont->m_eWeight = static_cast<weight::type>(getInt(pProps[n].Value));
3991 else if( pProps[n].Name.equalsAscii( "Pitch" ) )
3992 pFont->m_ePitch = static_cast<pitch::type>(getInt(pProps[n].Value));
3993 else if( pProps[n].Name.equalsAscii( "Encoding" ) )
3994 pFont->m_aEncoding = static_cast<rtl_TextEncoding>(getInt(pProps[n].Value));
3995 else if( pProps[n].Name.equalsAscii( "FontEncodingOnly" ) )
3996 pFont->m_bFontEncodingOnly = getBool(pProps[n].Value);
3997 else if( pProps[n].Name.equalsAscii( "GlobalMetricXWidth" ) )
3998 pFont->m_aGlobalMetricX.width = getInt(pProps[n].Value);
3999 else if( pProps[n].Name.equalsAscii( "GlobalMetricXHeight" ) )
4000 pFont->m_aGlobalMetricX.height = getInt(pProps[n].Value);
4001 else if( pProps[n].Name.equalsAscii( "GlobalMetricYWidth" ) )
4002 pFont->m_aGlobalMetricY.width = getInt(pProps[n].Value);
4003 else if( pProps[n].Name.equalsAscii( "GlobalMetricYHeight" ) )
4004 pFont->m_aGlobalMetricY.height = getInt(pProps[n].Value);
4005 else if( pProps[n].Name.equalsAscii( "Ascend" ) )
4006 pFont->m_nAscend = getInt(pProps[n].Value);
4007 else if( pProps[n].Name.equalsAscii( "Descend" ) )
4008 pFont->m_nDescend = getInt(pProps[n].Value);
4009 else if( pProps[n].Name.equalsAscii( "Leading" ) )
4010 pFont->m_nLeading = getInt(pProps[n].Value);
4011 else if( pProps[n].Name.equalsAscii( "XMin" ) )
4012 pFont->m_nXMin = getInt(pProps[n].Value);
4013 else if( pProps[n].Name.equalsAscii( "YMin" ) )
4014 pFont->m_nYMin = getInt(pProps[n].Value);
4015 else if( pProps[n].Name.equalsAscii( "XMax" ) )
4016 pFont->m_nXMax = getInt(pProps[n].Value);
4017 else if( pProps[n].Name.equalsAscii( "YMax" ) )
4018 pFont->m_nYMax = getInt(pProps[n].Value);
4019 else if( pProps[n].Name.equalsAscii( "VerticalSubstitutes" ) )
4020 pFont->m_bHaveVerticalSubstitutedGlyphs = getBool(pProps[n].Value);
4021 else if( pProps[n].Name.equalsAscii( "EncodingVector" ) )
4022 {
4023 Sequence< NamedValue > aEncoding;
4024 pProps[n].Value >>= aEncoding;
4025 sal_Int32 nEnc = aEncoding.getLength();
4026 const NamedValue* pEnc = aEncoding.getConstArray();
4027 for( sal_Int32 m = 0; m < nEnc; m++ )
4028 {
4029 sal_Unicode cCode = *pEnc[m].Name.getStr();
4030 sal_Int32 nGlyph = getInt(pEnc[m].Value);
4031 pFont->m_aEncodingVector[ cCode ] = nGlyph;
4032 }
4033 }
4034 else if( pProps[n].Name.equalsAscii( "NonEncoded" ) )
4035 {
4036 Sequence< NamedValue > aEncoding;
4037 pProps[n].Value >>= aEncoding;
4038 sal_Int32 nEnc = aEncoding.getLength();
4039 const NamedValue* pEnc = aEncoding.getConstArray();
4040 for( sal_Int32 m = 0; m < nEnc; m++ )
4041 {
4042 sal_Unicode cCode = *pEnc[m].Name.getStr();
4043 OUString aGlyphName( getString(pEnc[m].Value) );
4044 pFont->m_aNonEncoded[ cCode ] = OUStringToOString(aGlyphName,RTL_TEXTENCODING_ASCII_US);
4045 }
4046 }
4047 else if( pProps[n].Name.equalsAscii( "CharacterMetrics" ) )
4048 {
4049 // fill pFont->m_pMetrics->m_aMetrics
4050 // expect triples of int: int -> CharacterMetric.{ width, height }
4051 Sequence< sal_Int32 > aSeq;
4052 pProps[n].Value >>= aSeq;
4053 sal_Int32 nInts = aSeq.getLength();
4054 const sal_Int32* pInts = aSeq.getConstArray();
4055 for( sal_Int32 m = 0; m < nInts; m+=3 )
4056 {
4057 pFont->m_pMetrics->m_aMetrics[ pInts[m] ].width = static_cast<short int>(pInts[m+1]);
4058 pFont->m_pMetrics->m_aMetrics[ pInts[m] ].height = static_cast<short int>(pInts[m+2]);
4059 }
4060 }
4061 else if( pProps[n].Name.equalsAscii( "XKernPairs" ) )
4062 {
4063 // fill pFont->m_pMetrics->m_aXKernPairs
4064 // expection name: <unicode1><unicode2> value: ((height << 16)| width)
4065 Sequence< NamedValue > aKern;
4066 pProps[n].Value >>= aKern;
4067 KernPair aPair;
4068 const NamedValue* pVals = aKern.getConstArray();
4069 int nPairs = aKern.getLength();
4070 for( int m = 0; m < nPairs; m++ )
4071 {
4072 if( pVals[m].Name.getLength() == 2 )
4073 {
4074 aPair.first = pVals[m].Name.getStr()[0];
4075 aPair.second = pVals[m].Name.getStr()[1];
4076 sal_Int32 nKern = getInt( pVals[m].Value );
4077 aPair.kern_x = static_cast<short int>(nKern & 0xffff);
4078 aPair.kern_y = static_cast<short int>((sal_uInt32(nKern) >> 16) & 0xffff);
4079 pFont->m_pMetrics->m_aXKernPairs.push_back( aPair );
4080 }
4081 }
4082 }
4083 }
4084 // sanity check
4085 if( pFont->m_nPSName &&
4086 pFont->m_nFamilyName &&
4087 ! pFont->m_pMetrics->m_aMetrics.empty() )
4088 {
4089 m_aOverrideFonts.push_back( m_nNextFontID );
4090 m_aFonts[ m_nNextFontID++ ] = pFont;
4091 }
4092 else
4093 {
4094 DBG_ASSERT( 0, "override font failed" );
4095 delete pFont;
4096 }
4097 }
4098
4099 return true;
4100 }
4101