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