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