Bump version to 4.1-6
[LibreOffice.git] / vcl / generic / fontmanager / fontmanager.cxx
blob5e92170c075e247f4a96430e861b95364fe1fdfa
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <unistd.h>
21 #include <sys/stat.h>
22 #include <dirent.h>
23 #include <stdlib.h>
24 #include <osl/thread.h>
26 #include "unotools/atom.hxx"
28 #include "fontcache.hxx"
29 #include "fontsubset.hxx"
30 #include "impfont.hxx"
31 #include "svdata.hxx"
32 #include "generic/geninst.h"
33 #include "vcl/fontmanager.hxx"
34 #include "vcl/strhelper.hxx"
35 #include "vcl/ppdparser.hxx"
36 #include <vcl/embeddedfontshelper.hxx>
38 #include "tools/urlobj.hxx"
39 #include "tools/stream.hxx"
40 #include "tools/debug.hxx"
42 #include "osl/file.hxx"
43 #include "osl/process.h"
45 #include "rtl/tencinfo.h"
46 #include "rtl/ustrbuf.hxx"
47 #include "rtl/strbuf.hxx"
49 #include <sal/macros.h>
51 #include "i18nlangtag/mslangid.hxx"
54 #include "parseAFM.hxx"
55 #include "sft.hxx"
57 #if OSL_DEBUG_LEVEL > 1
58 #include <sys/times.h>
59 #include <stdio.h>
60 #endif
62 #include "sal/alloca.h"
64 #include <set>
65 #include <boost/unordered_set.hpp>
66 #include <algorithm>
68 #include "adobeenc.tab" // get encoding table for AFM metrics
70 #ifdef CALLGRIND_COMPILE
71 #include <valgrind/callgrind.h>
72 #endif
74 #include <comphelper/processfactory.hxx>
75 #include <comphelper/string.hxx>
76 #include "com/sun/star/beans/XMaterialHolder.hpp"
77 #include "com/sun/star/beans/NamedValue.hpp"
79 #define PRINTER_METRICDIR "fontmetric"
81 using namespace vcl;
82 using namespace utl;
83 using namespace psp;
84 using namespace osl;
85 using namespace com::sun::star::uno;
86 using namespace com::sun::star::beans;
87 using namespace com::sun::star::lang;
89 using ::comphelper::string::getToken;
92 * static helpers
95 inline sal_uInt16 getUInt16BE( const sal_uInt8*& pBuffer )
97 sal_uInt16 nRet = (sal_uInt16)pBuffer[1] |
98 (((sal_uInt16)pBuffer[0]) << 8);
99 pBuffer+=2;
100 return nRet;
103 inline sal_uInt32 getUInt32BE( const sal_uInt8*& pBuffer )
105 sal_uInt32 nRet = (((sal_uInt32)pBuffer[0]) << 24) |
106 (((sal_uInt32)pBuffer[1]) << 16) |
107 (((sal_uInt32)pBuffer[2]) << 8) |
108 (((sal_uInt32)pBuffer[3]) );
109 pBuffer += 4;
110 return nRet;
113 // -------------------------------------------------------------------------
115 static FontWeight parseWeight( const OString& rWeight )
117 FontWeight eWeight = WEIGHT_DONTKNOW;
118 if (rWeight.indexOf("bold") != -1)
120 if (rWeight.indexOf("emi") != -1) // semi, demi
121 eWeight = WEIGHT_SEMIBOLD;
122 else if (rWeight.indexOf("ultra") != -1)
123 eWeight = WEIGHT_ULTRABOLD;
124 else
125 eWeight = WEIGHT_BOLD;
127 else if (rWeight.indexOf("heavy") != -1)
128 eWeight = WEIGHT_BOLD;
129 else if (rWeight.indexOf("light") != -1)
131 if (rWeight.indexOf("emi") != -1) // semi, demi
132 eWeight = WEIGHT_SEMILIGHT;
133 else if (rWeight.indexOf("ultra") != -1)
134 eWeight = WEIGHT_ULTRALIGHT;
135 else
136 eWeight = WEIGHT_LIGHT;
138 else if (rWeight.indexOf("black") != -1)
139 eWeight = WEIGHT_BLACK;
140 else if (rWeight == "demi")
141 eWeight = WEIGHT_SEMIBOLD;
142 else if ((rWeight == "book") ||
143 (rWeight == "semicondensed"))
144 eWeight = WEIGHT_LIGHT;
145 else if ((rWeight == "medium") || (rWeight == "roman"))
146 eWeight = WEIGHT_MEDIUM;
147 else
148 eWeight = WEIGHT_NORMAL;
149 return eWeight;
153 * PrintFont implementations
155 PrintFontManager::PrintFont::PrintFont( fonttype::type eType ) :
156 m_eType( eType ),
157 m_nFamilyName( 0 ),
158 m_nPSName( 0 ),
159 m_eItalic( ITALIC_DONTKNOW ),
160 m_eWidth( WIDTH_DONTKNOW ),
161 m_eWeight( WEIGHT_DONTKNOW ),
162 m_ePitch( PITCH_DONTKNOW ),
163 m_aEncoding( RTL_TEXTENCODING_DONTKNOW ),
164 m_bFontEncodingOnly( false ),
165 m_pMetrics( NULL ),
166 m_nAscend( 0 ),
167 m_nDescend( 0 ),
168 m_nLeading( 0 ),
169 m_nXMin( 0 ),
170 m_nYMin( 0 ),
171 m_nXMax( 0 ),
172 m_nYMax( 0 ),
173 m_bHaveVerticalSubstitutedGlyphs( false ),
174 m_bUserOverride( false )
178 // -------------------------------------------------------------------------
180 PrintFontManager::PrintFont::~PrintFont()
182 delete m_pMetrics;
185 // -------------------------------------------------------------------------
187 PrintFontManager::Type1FontFile::~Type1FontFile()
191 // -------------------------------------------------------------------------
193 PrintFontManager::TrueTypeFontFile::TrueTypeFontFile()
194 : PrintFont( fonttype::TrueType )
195 , m_nDirectory( 0 )
196 , m_nCollectionEntry( 0 )
197 , m_nTypeFlags( TYPEFLAG_INVALID )
200 // -------------------------------------------------------------------------
202 PrintFontManager::TrueTypeFontFile::~TrueTypeFontFile()
206 // -------------------------------------------------------------------------
208 PrintFontManager::BuiltinFont::~BuiltinFont()
212 // -------------------------------------------------------------------------
214 bool PrintFontManager::Type1FontFile::queryMetricPage( int /*nPage*/, MultiAtomProvider* pProvider )
216 return readAfmMetrics( pProvider, false, false );
219 // -------------------------------------------------------------------------
221 bool PrintFontManager::BuiltinFont::queryMetricPage( int /*nPage*/, MultiAtomProvider* pProvider )
223 return readAfmMetrics( pProvider, false, false );
226 // -------------------------------------------------------------------------
228 bool PrintFontManager::TrueTypeFontFile::queryMetricPage( int nPage, MultiAtomProvider* pProvider )
230 bool bSuccess = false;
232 OString aFile( PrintFontManager::get().getFontFile( this ) );
234 TrueTypeFont* pTTFont = NULL;
236 if( OpenTTFontFile( aFile.getStr(), m_nCollectionEntry, &pTTFont ) == SF_OK )
238 if( ! m_pMetrics )
240 m_pMetrics = new PrintFontMetrics;
241 memset (m_pMetrics->m_aPages, 0, sizeof(m_pMetrics->m_aPages));
243 m_pMetrics->m_aPages[ nPage/8 ] |= (1 << ( nPage & 7 ));
244 int i;
245 sal_uInt16 table[256], table_vert[256];
247 for( i = 0; i < 256; i++ )
248 table[ i ] = 256*nPage + i;
250 int nCharacters = nPage < 255 ? 256 : 254;
251 MapString( pTTFont, table, nCharacters, NULL, 0 );
252 TTSimpleGlyphMetrics* pMetrics = GetTTSimpleCharMetrics( pTTFont, nPage*256, nCharacters, 0 );
253 if( pMetrics )
255 for( i = 0; i < nCharacters; i++ )
257 if( table[i] )
259 CharacterMetric& rChar = m_pMetrics->m_aMetrics[ nPage*256 + i ];
260 rChar.width = pMetrics[ i ].adv;
261 rChar.height = m_aGlobalMetricX.height;
265 free( pMetrics );
268 for( i = 0; i < 256; i++ )
269 table_vert[ i ] = 256*nPage + i;
270 MapString( pTTFont, table_vert, nCharacters, NULL, 1 );
271 pMetrics = GetTTSimpleCharMetrics( pTTFont, nPage*256, nCharacters, 1 );
272 if( pMetrics )
274 for( i = 0; i < nCharacters; i++ )
276 if( table_vert[i] )
278 CharacterMetric& rChar = m_pMetrics->m_aMetrics[ nPage*256 + i + ( 1 << 16 ) ];
279 rChar.width = m_aGlobalMetricY.width;
280 rChar.height = pMetrics[ i ].adv;
281 if( table_vert[i] != table[i] )
282 m_pMetrics->m_bVerticalSubstitutions[ nPage*256 + i ] = 1;
285 free( pMetrics );
288 if( ! m_pMetrics->m_bKernPairsQueried )
290 m_pMetrics->m_bKernPairsQueried = true;
291 // this is really a hack
292 // in future MapString/KernGlyphs should be used
293 // but vcl is not in a state where that could be used
294 // so currently we get kernpairs by accessing the raw data
295 struct _TrueTypeFont* pImplTTFont = (struct _TrueTypeFont*)pTTFont;
297 //-----------------------------------------------------------------
298 // Kerning: KT_MICROSOFT
299 //-----------------------------------------------------------------
300 if( pImplTTFont->nkern && pImplTTFont->kerntype == KT_MICROSOFT )
302 // create a glyph -> character mapping
303 ::boost::unordered_map< sal_uInt16, sal_Unicode > aGlyphMap;
304 ::boost::unordered_map< sal_uInt16, sal_Unicode >::iterator left, right;
305 for( i = 21; i < 0xfffd; i++ )
307 sal_uInt16 nGlyph = MapChar( pTTFont, (sal_Unicode)i, 0 ); // kerning for horz only
308 if( nGlyph != 0 )
309 aGlyphMap[ nGlyph ] = (sal_Unicode)i;
313 KernPair aPair;
314 for( i = 0; i < (int)pImplTTFont->nkern; i++ )
316 const sal_uInt8* pTable = pImplTTFont->kerntables[i];
318 /*sal_uInt16 nVersion =*/ getUInt16BE( pTable );
319 /*sal_uInt16 nLength =*/ getUInt16BE( pTable );
320 sal_uInt16 nCoverage = getUInt16BE( pTable );
322 aPair.kern_x = 0;
323 aPair.kern_y = 0;
324 switch( nCoverage >> 8 )
326 case 0:
328 sal_uInt16 nPairs = getUInt16BE( pTable );
329 pTable += 6;
330 for( int n = 0; n < nPairs; n++ )
332 sal_uInt16 nLeftGlyph = getUInt16BE( pTable );
333 sal_uInt16 nRightGlyph = getUInt16BE( pTable );
334 sal_Int16 nKern = (sal_Int16)getUInt16BE( pTable );
336 left = aGlyphMap.find( nLeftGlyph );
337 right = aGlyphMap.find( nRightGlyph );
338 if( left != aGlyphMap.end() && right != aGlyphMap.end() )
340 aPair.first = left->second;
341 aPair.second = right->second;
342 switch( nCoverage & 1 )
344 case 1:
345 aPair.kern_x = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
346 m_pMetrics->m_aXKernPairs.push_back( aPair );
347 break;
348 case 0:
349 aPair.kern_y = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
350 m_pMetrics->m_aYKernPairs.push_back( aPair );
351 break;
356 break;
358 case 2:
360 const sal_uInt8* pSubTable = pTable;
361 /*sal_uInt16 nRowWidth =*/ getUInt16BE( pTable );
362 sal_uInt16 nOfLeft = getUInt16BE( pTable );
363 sal_uInt16 nOfRight = getUInt16BE( pTable );
364 /*sal_uInt16 nOfArray =*/ getUInt16BE( pTable );
365 const sal_uInt8* pTmp = pSubTable + nOfLeft;
366 sal_uInt16 nFirstLeft = getUInt16BE( pTmp );
367 sal_uInt16 nLastLeft = getUInt16BE( pTmp ) + nFirstLeft - 1;
368 pTmp = pSubTable + nOfRight;
369 sal_uInt16 nFirstRight = getUInt16BE( pTmp );
370 sal_uInt16 nLastRight = getUInt16BE( pTmp ) + nFirstRight -1;
372 // int nPairs = (int)(nLastLeft-nFirstLeft+1)*(int)(nLastRight-nFirstRight+1);
373 for( aPair.first = nFirstLeft; aPair.first < nLastLeft; aPair.first++ )
375 for( aPair.second = 0; aPair.second < nLastRight; aPair.second++ )
377 sal_Int16 nKern = (sal_Int16)getUInt16BE( pTmp );
378 switch( nCoverage & 1 )
380 case 1:
381 aPair.kern_x = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
382 m_pMetrics->m_aXKernPairs.push_back( aPair );
383 break;
384 case 0:
385 aPair.kern_y = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
386 m_pMetrics->m_aYKernPairs.push_back( aPair );
387 break;
392 break;
397 //-----------------------------------------------------------------
398 // Kerning: KT_APPLE_NEW
399 //-----------------------------------------------------------------
400 if( pImplTTFont->nkern && pImplTTFont->kerntype == KT_APPLE_NEW )
402 // create a glyph -> character mapping
403 ::boost::unordered_map< sal_uInt16, sal_Unicode > aGlyphMap;
404 ::boost::unordered_map< sal_uInt16, sal_Unicode >::iterator left, right;
405 for( i = 21; i < 0xfffd; i++ )
407 sal_uInt16 nGlyph = MapChar( pTTFont, (sal_Unicode)i, 0 ); // kerning for horz only
408 if( nGlyph != 0 )
409 aGlyphMap[ nGlyph ] = (sal_Unicode)i;
412 // Loop through each of the 'kern' subtables
413 KernPair aPair;
414 for( i = 0; (unsigned int)i < pImplTTFont->nkern; i++ )
416 const sal_uInt8* pTable = pImplTTFont->kerntables[i];
418 /*sal_uInt32 nLength =*/ getUInt32BE( pTable );
419 sal_uInt16 nCoverage = getUInt16BE( pTable );
420 /*sal_uInt16 nTupleIndex =*/ getUInt16BE( pTable );
422 // Get kerning type
423 // sal_Bool bKernVertical = nCoverage & 0x8000;
424 // sal_Bool bKernCrossStream = nCoverage & 0x4000;
425 // sal_Bool bKernVariation = nCoverage & 0x2000;
427 // Kerning sub-table format, 0 through 3
428 sal_uInt8 nSubTableFormat = nCoverage & 0x00FF;
430 aPair.kern_x = 0;
431 aPair.kern_y = 0;
432 switch( nSubTableFormat )
434 case 0:
436 // Grab the # of kern pairs but skip over the:
437 // searchRange
438 // entrySelector
439 // rangeShift
440 sal_uInt16 nPairs = getUInt16BE( pTable );
441 pTable += 6;
443 for( int n = 0; n < nPairs; n++ )
445 sal_uInt16 nLeftGlyph = getUInt16BE( pTable );
446 sal_uInt16 nRightGlyph = getUInt16BE( pTable );
447 sal_Int16 nKern = (sal_Int16)getUInt16BE( pTable );
449 left = aGlyphMap.find( nLeftGlyph );
450 right = aGlyphMap.find( nRightGlyph );
451 if( left != aGlyphMap.end() && right != aGlyphMap.end() )
453 aPair.first = left->second;
454 aPair.second = right->second;
456 // Only support horizontal kerning for now
457 aPair.kern_x = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
458 aPair.kern_y = 0;
459 m_pMetrics->m_aXKernPairs.push_back( aPair );
463 break;
465 case 2:
467 const sal_uInt8* pSubTable = pTable;
468 /*sal_uInt16 nRowWidth =*/ getUInt16BE( pTable );
469 sal_uInt16 nOfLeft = getUInt16BE( pTable );
470 sal_uInt16 nOfRight = getUInt16BE( pTable );
471 /*sal_uInt16 nOfArray =*/ getUInt16BE( pTable );
472 const sal_uInt8* pTmp = pSubTable + nOfLeft;
473 sal_uInt16 nFirstLeft = getUInt16BE( pTmp );
474 sal_uInt16 nLastLeft = getUInt16BE( pTmp ) + nFirstLeft - 1;
475 pTmp = pSubTable + nOfRight;
476 sal_uInt16 nFirstRight = getUInt16BE( pTmp );
477 sal_uInt16 nLastRight = getUInt16BE( pTmp ) + nFirstRight -1;
479 for( aPair.first = nFirstLeft; aPair.first < nLastLeft; aPair.first++ )
481 for( aPair.second = 0; aPair.second < nLastRight; aPair.second++ )
483 sal_Int16 nKern = (sal_Int16)getUInt16BE( pTmp );
484 switch( nCoverage & 1 )
486 case 1:
487 aPair.kern_x = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
488 m_pMetrics->m_aXKernPairs.push_back( aPair );
489 break;
490 case 0:
491 aPair.kern_y = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
492 m_pMetrics->m_aYKernPairs.push_back( aPair );
493 break;
498 break;
500 default:
501 fprintf( stderr, "Found unsupported Apple-style kern subtable type %d.\n", nSubTableFormat );
502 break;
507 #if OSL_DEBUG_LEVEL > 1
508 fprintf( stderr, "found %" SAL_PRI_SIZET "u/%" SAL_PRI_SIZET "u kern pairs for %s\n",
509 m_pMetrics->m_aXKernPairs.size(),
510 m_pMetrics->m_aYKernPairs.size(),
511 OUStringToOString( pProvider->getString( ATOM_FAMILYNAME, m_nFamilyName ), RTL_TEXTENCODING_MS_1252 ).getStr() );
512 #else
513 (void) pProvider; /* avoid warnings */
514 #endif
517 CloseTTFont( pTTFont );
518 bSuccess = true;
520 return bSuccess;
523 // -------------------------------------------------------------------------
525 /* #i73387# There seem to be fonts with a rather unwell chosen family name
526 * consider e.g. "Helvetica Narrow" which defines its family as "Helvetica"
527 * It can really only be distinguished by its PSName and FullName. Both of
528 * which are not user presentable in OOo. So replace it by something sensible.
530 * If other fonts feature this behaviour, insert them to the map.
532 static bool familyNameOverride( const OUString& i_rPSname, OUString& o_rFamilyName )
534 static boost::unordered_map< OUString, OUString, OUStringHash > aPSNameToFamily( 16 );
535 if( aPSNameToFamily.empty() ) // initialization
537 aPSNameToFamily[ "Helvetica-Narrow" ] = "Helvetica Narrow";
538 aPSNameToFamily[ "Helvetica-Narrow-Bold" ] = "Helvetica Narrow";
539 aPSNameToFamily[ "Helvetica-Narrow-BoldOblique" ] = "Helvetica Narrow";
540 aPSNameToFamily[ "Helvetica-Narrow-Oblique" ] = "Helvetica Narrow";
542 boost::unordered_map<OUString,OUString,OUStringHash>::const_iterator it =
543 aPSNameToFamily.find( i_rPSname );
544 bool bReplaced = (it != aPSNameToFamily.end() );
545 if( bReplaced )
546 o_rFamilyName = it->second;
547 return bReplaced;
550 bool PrintFontManager::PrintFont::readAfmMetrics( MultiAtomProvider* pProvider, bool bFillEncodingvector, bool bOnlyGlobalAttributes )
552 PrintFontManager& rManager( PrintFontManager::get() );
553 const OString& rFileName = rManager.getAfmFile( this );
555 FontInfo* pInfo = NULL;
556 parseFile( rFileName.getStr(), &pInfo, P_ALL );
557 if( ! pInfo || ! pInfo->numOfChars )
559 if( pInfo )
560 freeFontInfo( pInfo );
561 return false;
564 m_aEncodingVector.clear();
565 // fill in global info
567 // PSName
568 OUString aPSName( OStringToOUString( pInfo->gfi->fontName, RTL_TEXTENCODING_ISO_8859_1 ) );
569 m_nPSName = pProvider->getAtom( ATOM_PSNAME, aPSName, sal_True );
571 // family name (if not already set)
572 OUString aFamily;
573 if( ! m_nFamilyName )
575 aFamily = OStringToOUString( pInfo->gfi->familyName, RTL_TEXTENCODING_ISO_8859_1 );
576 if( aFamily.isEmpty() )
578 aFamily = OStringToOUString( pInfo->gfi->fontName, RTL_TEXTENCODING_ISO_8859_1 );
579 sal_Int32 nIndex = 0;
580 aFamily = aFamily.getToken( 0, '-', nIndex );
582 familyNameOverride( aPSName, aFamily );
583 m_nFamilyName = pProvider->getAtom( ATOM_FAMILYNAME, aFamily, sal_True );
585 else
586 aFamily = pProvider->getString( ATOM_FAMILYNAME, m_nFamilyName );
588 // style name: if fullname begins with family name
589 // interpret the rest of fullname as style
590 if( m_aStyleName.isEmpty() && pInfo->gfi->fullName && *pInfo->gfi->fullName )
592 OUString aFullName( OStringToOUString( pInfo->gfi->fullName, RTL_TEXTENCODING_ISO_8859_1 ) );
593 if( aFullName.indexOf( aFamily ) == 0 )
594 m_aStyleName = WhitespaceToSpace( aFullName.copy( aFamily.getLength() ) );
597 // italic
598 if( pInfo->gfi->italicAngle > 0 )
599 m_eItalic = ITALIC_OBLIQUE;
600 else if( pInfo->gfi->italicAngle < 0 )
601 m_eItalic = ITALIC_NORMAL;
602 else
603 m_eItalic = ITALIC_NONE;
605 // weight
606 OString aWeight( pInfo->gfi->weight );
607 m_eWeight = parseWeight( aWeight.toAsciiLowerCase() );
609 // pitch
610 m_ePitch = pInfo->gfi->isFixedPitch ? PITCH_FIXED : PITCH_VARIABLE;
612 // encoding - only set if unknown
613 int nAdobeEncoding = 0;
614 if( pInfo->gfi->encodingScheme )
616 if( !strcmp( pInfo->gfi->encodingScheme, "AdobeStandardEncoding" ) )
617 nAdobeEncoding = 1;
618 else if( !strcmp( pInfo->gfi->encodingScheme, "ISO10646-1" ) )
620 nAdobeEncoding = 1;
621 m_aEncoding = RTL_TEXTENCODING_UNICODE;
623 else if( !strcmp( pInfo->gfi->encodingScheme, "Symbol") )
624 nAdobeEncoding = 2;
625 else if( !strcmp( pInfo->gfi->encodingScheme, "FontSpecific") )
626 nAdobeEncoding = 3;
628 if( m_aEncoding == RTL_TEXTENCODING_DONTKNOW )
629 m_aEncoding = nAdobeEncoding == 1 ?
630 RTL_TEXTENCODING_ADOBE_STANDARD : RTL_TEXTENCODING_SYMBOL;
632 else if( m_aEncoding == RTL_TEXTENCODING_DONTKNOW )
633 m_aEncoding = RTL_TEXTENCODING_ADOBE_STANDARD;
635 // try to parse the font name and decide whether it might be a
636 // japanese font. Who invented this PITA ?
637 OUString aPSNameLastToken( aPSName.copy( aPSName.lastIndexOf( '-' )+1 ) );
638 if( ! aPSNameLastToken.compareToAscii( "H" ) ||
639 ! aPSNameLastToken.compareToAscii( "V" ) )
641 static const char* pEncs[] =
643 "EUC",
644 "RKSJ",
645 "SJ"
647 static const rtl_TextEncoding aEncs[] =
649 RTL_TEXTENCODING_EUC_JP,
650 RTL_TEXTENCODING_SHIFT_JIS,
651 RTL_TEXTENCODING_JIS_X_0208
654 for( unsigned int enc = 0; enc < SAL_N_ELEMENTS( aEncs ) && m_aEncoding == RTL_TEXTENCODING_DONTKNOW; enc++ )
656 sal_Int32 nIndex = 0, nOffset = 1;
659 OUString aToken( aPSName.getToken( nOffset, '-', nIndex ) );
660 if( nIndex == -1 )
661 break;
662 nOffset = 0;
663 if( ! aToken.compareToAscii( pEncs[enc] ) )
665 m_aEncoding = aEncs[ enc ];
666 m_bFontEncodingOnly = true;
668 } while( nIndex != -1 );
671 // default is jis
672 if( m_aEncoding == RTL_TEXTENCODING_DONTKNOW )
673 m_aEncoding = RTL_TEXTENCODING_JIS_X_0208;
674 #if OSL_DEBUG_LEVEL > 1
675 fprintf( stderr, "Encoding %d for %s\n", m_aEncoding, pInfo->gfi->fontName );
676 #endif
679 // hack for GB encoded builtin fonts posing as FontSpecific
680 if( m_eType == fonttype::Builtin && ( nAdobeEncoding == 3 || nAdobeEncoding == 0 ) )
682 int nLen = aFamily.getLength();
683 if( nLen > 2 &&
684 aFamily.getStr()[ nLen-2 ] == 'G' &&
685 aFamily.getStr()[ nLen-1 ] == 'B' &&
686 pInfo->numOfChars > 255 )
688 m_aEncoding = RTL_TEXTENCODING_GBK;
689 m_bFontEncodingOnly = true;
690 #if OSL_DEBUG_LEVEL > 1
691 fprintf( stderr, "found builtin font %s with GBK encoding\n", pInfo->gfi->fontName );
692 #endif
696 // #i37313# check if Fontspecific is not rather some character encoding
697 if( nAdobeEncoding == 3 && m_aEncoding == RTL_TEXTENCODING_SYMBOL )
699 bool bYFound = false;
700 bool bQFound = false;
701 CharMetricInfo* pChar = pInfo->cmi;
702 for( int j = 0; j < pInfo->numOfChars && ! (bYFound && bQFound); j++ )
704 if( pChar[j].name )
706 if( pChar[j].name[0] == 'Y' && pChar[j].name[1] == 0 )
707 bYFound = true;
708 else if( pChar[j].name[0] == 'Q' && pChar[j].name[1] == 0 )
709 bQFound = true;
712 if( bQFound && bYFound )
714 #if OSL_DEBUG_LEVEL > 1
715 fprintf( stderr, "setting FontSpecific font %s (file %s) to unicode\n",
716 pInfo->gfi->fontName,
717 rFileName.getStr()
719 #endif
720 nAdobeEncoding = 4;
721 m_aEncoding = RTL_TEXTENCODING_UNICODE;
722 bFillEncodingvector = false; // will be filled anyway, don't do the work twice
726 // ascend
727 m_nAscend = pInfo->gfi->fontBBox.ury;
729 // descend
730 // descends have opposite sign of our definition
731 m_nDescend = -pInfo->gfi->fontBBox.lly;
733 // fallback to ascender, descender
734 // interesting: the BBox seems to describe Ascender and Descender better
735 // as we understand it
736 if( m_nAscend == 0 )
737 m_nAscend = pInfo->gfi->ascender;
738 if( m_nDescend == 0)
739 m_nDescend = -pInfo->gfi->descender;
741 m_nLeading = m_nAscend + m_nDescend - 1000;
743 delete m_pMetrics;
744 m_pMetrics = new PrintFontMetrics;
745 // mark all pages as queried (or clear if only global font info queiried)
746 memset( m_pMetrics->m_aPages, bOnlyGlobalAttributes ? 0 : 0xff, sizeof( m_pMetrics->m_aPages ) );
748 m_aGlobalMetricX.width = m_aGlobalMetricY.width =
749 pInfo->gfi->charwidth ? pInfo->gfi->charwidth : pInfo->gfi->fontBBox.urx;
750 m_aGlobalMetricX.height = m_aGlobalMetricY.height =
751 pInfo->gfi->capHeight ? pInfo->gfi->capHeight : pInfo->gfi->fontBBox.ury;
753 m_nXMin = pInfo->gfi->fontBBox.llx;
754 m_nYMin = pInfo->gfi->fontBBox.lly;
755 m_nXMax = pInfo->gfi->fontBBox.urx;
756 m_nYMax = pInfo->gfi->fontBBox.ury;
758 if( bFillEncodingvector || !bOnlyGlobalAttributes )
760 // fill in character metrics
762 // first transform the character codes to unicode
763 // note: this only works with single byte encodings
764 sal_Unicode* pUnicodes = (sal_Unicode*)alloca( pInfo->numOfChars * sizeof(sal_Unicode));
765 CharMetricInfo* pChar = pInfo->cmi;
766 int i;
768 for( i = 0; i < pInfo->numOfChars; i++, pChar++ )
770 if( nAdobeEncoding == 4 )
772 if( pChar->name )
774 pUnicodes[i] = 0;
775 std::list< sal_Unicode > aCodes = rManager.getUnicodeFromAdobeName( pChar->name );
776 for( std::list< sal_Unicode >::const_iterator it = aCodes.begin(); it != aCodes.end(); ++it )
778 if( *it != 0 )
780 m_aEncodingVector[ *it ] = pChar->code;
781 if( pChar->code == -1 )
782 m_aNonEncoded[ *it ] = pChar->name;
783 if( ! pUnicodes[i] ) // map the first
784 pUnicodes[i] = *it;
789 else if( pChar->code != -1 )
791 if( nAdobeEncoding == 3 && m_aEncoding == RTL_TEXTENCODING_SYMBOL )
793 pUnicodes[i] = pChar->code + 0xf000;
794 if( bFillEncodingvector )
795 m_aEncodingVector[ pUnicodes[i] ] = pChar->code;
796 continue;
799 if( m_aEncoding == RTL_TEXTENCODING_UNICODE )
801 pUnicodes[i] = (sal_Unicode)pChar->code;
802 continue;
805 OStringBuffer aTranslate;
806 if( pChar->code & 0xff000000 )
807 aTranslate.append((char)(pChar->code >> 24));
808 if( pChar->code & 0xffff0000 )
809 aTranslate.append((char)((pChar->code & 0x00ff0000) >> 16));
810 if( pChar->code & 0xffffff00 )
811 aTranslate.append((char)((pChar->code & 0x0000ff00) >> 8 ));
812 aTranslate.append((char)(pChar->code & 0xff));
813 OUString aUni(OStringToOUString(aTranslate.makeStringAndClear(), m_aEncoding));
814 pUnicodes[i] = aUni.toChar();
816 else
817 pUnicodes[i] = 0;
820 // now fill in the character metrics
821 // parseAFM.cxx effectively only supports direction 0 (horizontal)
822 pChar = pInfo->cmi;
823 CharacterMetric aMetric;
824 for( i = 0; i < pInfo->numOfChars; i++, pChar++ )
826 if( pChar->code == -1 && ! pChar->name )
827 continue;
829 if( bFillEncodingvector && pChar->name )
831 std::list< sal_Unicode > aCodes = rManager.getUnicodeFromAdobeName( pChar->name );
832 for( std::list< sal_Unicode >::const_iterator it = aCodes.begin(); it != aCodes.end(); ++it )
834 if( *it != 0 )
836 m_aEncodingVector[ *it ] = pChar->code;
837 if( pChar->code == -1 )
838 m_aNonEncoded[ *it ] = pChar->name;
843 aMetric.width = pChar->wx ? pChar->wx : pChar->charBBox.urx;
844 aMetric.height = pChar->wy ? pChar->wy : pChar->charBBox.ury - pChar->charBBox.lly;
845 if( aMetric.width == 0 && aMetric.height == 0 )
846 // guess something for e.g. space
847 aMetric.width = m_aGlobalMetricX.width/4;
849 if( ( nAdobeEncoding == 0 ) ||
850 ( ( nAdobeEncoding == 3 ) && ( m_aEncoding != RTL_TEXTENCODING_SYMBOL ) ) )
852 if( pChar->code != -1 )
854 m_pMetrics->m_aMetrics[ pUnicodes[i] ] = aMetric;
855 if( bFillEncodingvector )
856 m_aEncodingVector[ pUnicodes[i] ] = pChar->code;
858 else if( pChar->name )
860 std::list< sal_Unicode > aCodes = rManager.getUnicodeFromAdobeName( pChar->name );
861 for( std::list< sal_Unicode >::const_iterator it = aCodes.begin(); it != aCodes.end(); ++it )
863 if( *it != 0 )
864 m_pMetrics->m_aMetrics[ *it ] = aMetric;
868 else if( nAdobeEncoding == 1 || nAdobeEncoding == 2 || nAdobeEncoding == 4)
870 if( pChar->name )
872 std::list< sal_Unicode > aCodes = rManager.getUnicodeFromAdobeName( pChar->name );
873 for( std::list< sal_Unicode >::const_iterator it = aCodes.begin(); it != aCodes.end(); ++it )
875 if( *it != 0 )
876 m_pMetrics->m_aMetrics[ *it ] = aMetric;
879 else if( pChar->code != -1 )
881 ::std::pair< ::boost::unordered_multimap< sal_uInt8, sal_Unicode >::const_iterator,
882 ::boost::unordered_multimap< sal_uInt8, sal_Unicode >::const_iterator >
883 aCodes = rManager.getUnicodeFromAdobeCode( pChar->code );
884 while( aCodes.first != aCodes.second )
886 if( (*aCodes.first).second != 0 )
888 m_pMetrics->m_aMetrics[ (*aCodes.first).second ] = aMetric;
889 if( bFillEncodingvector )
890 m_aEncodingVector[ (*aCodes.first).second ] = pChar->code;
892 ++aCodes.first;
896 else if( nAdobeEncoding == 3 )
898 if( pChar->code != -1 )
900 sal_Unicode code = 0xf000 + pChar->code;
901 m_pMetrics->m_aMetrics[ code ] = aMetric;
902 // maybe should try to find the name in the convtabs ?
903 if( bFillEncodingvector )
904 m_aEncodingVector[ code ] = pChar->code;
909 m_pMetrics->m_aXKernPairs.clear();
910 m_pMetrics->m_aYKernPairs.clear();
912 // now fill in the kern pairs
913 // parseAFM.cxx effectively only supports direction 0 (horizontal)
914 PairKernData* pKern = pInfo->pkd;
915 KernPair aPair;
916 for( i = 0; i < pInfo->numOfPairs; i++, pKern++ )
918 // #i37703# broken kern table
919 if( ! pKern->name1 || ! pKern->name2 )
920 continue;
922 aPair.first = 0;
923 aPair.second = 0;
924 // currently we have to find the adobe character names
925 // in the already parsed character metrics to find
926 // the corresponding UCS2 code which is a bit dangerous
927 // since the character names are not required
928 // in the metric descriptions
929 pChar = pInfo->cmi;
930 for( int j = 0;
931 j < pInfo->numOfChars && ( aPair.first == 0 || aPair.second == 0 );
932 j++, pChar++ )
934 if( pChar->code != -1 )
936 if( ! strcmp( pKern->name1, pChar->name ? pChar->name : "" ) )
937 aPair.first = pUnicodes[ j ];
938 if( ! strcmp( pKern->name2, pChar->name ? pChar->name : "" ) )
939 aPair.second = pUnicodes[ j ];
942 if( aPair.first && aPair.second )
944 aPair.kern_x = pKern->xamt;
945 aPair.kern_y = pKern->yamt;
946 m_pMetrics->m_aXKernPairs.push_back( aPair );
949 m_pMetrics->m_bKernPairsQueried = true;
952 freeFontInfo( pInfo );
953 return true;
957 * one instance only
959 PrintFontManager& PrintFontManager::get()
961 static PrintFontManager* pManager = NULL;
962 if( ! pManager )
964 static PrintFontManager theManager;
965 pManager = &theManager;
966 pManager->initialize();
968 return *pManager;
971 // -------------------------------------------------------------------------
974 * the PrintFontManager
977 PrintFontManager::PrintFontManager()
978 : m_nNextFontID( 1 )
979 , m_pAtoms( new MultiAtomProvider() )
980 , m_nNextDirAtom( 1 )
981 , m_pFontCache( NULL )
983 for( unsigned int i = 0; i < SAL_N_ELEMENTS( aAdobeCodes ); i++ )
985 m_aUnicodeToAdobename.insert( ::boost::unordered_multimap< sal_Unicode, OString >::value_type( aAdobeCodes[i].aUnicode, aAdobeCodes[i].pAdobename ) );
986 m_aAdobenameToUnicode.insert( ::boost::unordered_multimap< OString, sal_Unicode, OStringHash >::value_type( aAdobeCodes[i].pAdobename, aAdobeCodes[i].aUnicode ) );
987 if( aAdobeCodes[i].aAdobeStandardCode )
989 m_aUnicodeToAdobecode.insert( ::boost::unordered_multimap< sal_Unicode, sal_uInt8 >::value_type( aAdobeCodes[i].aUnicode, aAdobeCodes[i].aAdobeStandardCode ) );
990 m_aAdobecodeToUnicode.insert( ::boost::unordered_multimap< sal_uInt8, sal_Unicode >::value_type( aAdobeCodes[i].aAdobeStandardCode, aAdobeCodes[i].aUnicode ) );
994 m_aFontInstallerTimer.SetTimeoutHdl(LINK(this, PrintFontManager, autoInstallFontLangSupport));
995 m_aFontInstallerTimer.SetTimeout(5000);
998 // -------------------------------------------------------------------------
1000 PrintFontManager::~PrintFontManager()
1002 m_aFontInstallerTimer.Stop();
1003 deinitFontconfig();
1004 for( ::boost::unordered_map< fontID, PrintFont* >::const_iterator it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
1005 delete (*it).second;
1006 delete m_pAtoms;
1007 delete m_pFontCache;
1010 // -------------------------------------------------------------------------
1012 OString PrintFontManager::getDirectory( int nAtom ) const
1014 ::boost::unordered_map< int, OString >::const_iterator it( m_aAtomToDir.find( nAtom ) );
1015 return it != m_aAtomToDir.end() ? it->second : OString();
1018 // -------------------------------------------------------------------------
1020 int PrintFontManager::getDirectoryAtom( const OString& rDirectory, bool bCreate )
1022 int nAtom = 0;
1023 ::boost::unordered_map< OString, int, OStringHash >::const_iterator it
1024 ( m_aDirToAtom.find( rDirectory ) );
1025 if( it != m_aDirToAtom.end() )
1026 nAtom = it->second;
1027 else if( bCreate )
1029 nAtom = m_nNextDirAtom++;
1030 m_aDirToAtom[ rDirectory ] = nAtom;
1031 m_aAtomToDir[ nAtom ] = rDirectory;
1033 return nAtom;
1036 // -------------------------------------------------------------------------
1038 std::vector<fontID> PrintFontManager::addFontFile( const OString& rFileName )
1040 rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
1041 INetURLObject aPath( OStringToOUString( rFileName, aEncoding ), INetURLObject::FSYS_DETECT );
1042 OString aName( OUStringToOString( aPath.GetName( INetURLObject::DECODE_WITH_CHARSET, aEncoding ), aEncoding ) );
1043 OString aDir( OUStringToOString(
1044 INetURLObject::decode( aPath.GetPath(), '%', INetURLObject::DECODE_WITH_CHARSET, aEncoding ), aEncoding ) );
1046 int nDirID = getDirectoryAtom( aDir, true );
1047 std::vector<fontID> aFontIds = findFontFileIDs( nDirID, aName );
1048 if( aFontIds.empty() )
1050 ::std::list< PrintFont* > aNewFonts;
1051 if( analyzeFontFile( nDirID, aName, aNewFonts ) )
1053 for( ::std::list< PrintFont* >::iterator it = aNewFonts.begin();
1054 it != aNewFonts.end(); ++it )
1056 fontID nFontId = m_nNextFontID++;
1057 m_aFonts[nFontId] = *it;
1058 m_aFontFileToFontID[ aName ].insert( nFontId );
1059 m_pFontCache->updateFontCacheEntry( *it, true );
1060 aFontIds.push_back(nFontId);
1064 return aFontIds;
1067 enum fontFormat
1069 UNKNOWN, TRUETYPE, CFF, TYPE1, AFM
1072 bool PrintFontManager::analyzeFontFile( int nDirID, const OString& rFontFile, ::std::list< PrintFontManager::PrintFont* >& rNewFonts, const char *pFormat ) const
1074 rNewFonts.clear();
1076 OString aDir( getDirectory( nDirID ) );
1078 OString aFullPath( aDir );
1079 aFullPath += "/";
1080 aFullPath += rFontFile;
1082 // #i1872# reject unreadable files
1083 if( access( aFullPath.getStr(), R_OK ) )
1084 return false;
1086 fontFormat eFormat = UNKNOWN;
1087 if (pFormat)
1089 if (!strcmp(pFormat, "TrueType"))
1090 eFormat = TRUETYPE;
1091 else if (!strcmp(pFormat, "CFF"))
1092 eFormat = CFF;
1093 else if (!strcmp(pFormat, "Type 1"))
1094 eFormat = TYPE1;
1096 if (eFormat == UNKNOWN)
1098 OString aExt( rFontFile.copy( rFontFile.lastIndexOf( '.' )+1 ) );
1099 if( aExt.equalsIgnoreAsciiCase("pfb") || aExt.equalsIgnoreAsciiCase("pfa") )
1100 eFormat = TYPE1;
1101 else if( aExt.equalsIgnoreAsciiCase("afm"))
1102 eFormat = AFM;
1103 else if( aExt.equalsIgnoreAsciiCase("ttf")
1104 || aExt.equalsIgnoreAsciiCase("ttc")
1105 || aExt.equalsIgnoreAsciiCase("tte") ) // #i33947# for Gaiji support
1106 eFormat = TRUETYPE;
1107 else if( aExt.equalsIgnoreAsciiCase("otf") ) // check for TTF- and PS-OpenType too
1108 eFormat = CFF;
1111 if (eFormat == TYPE1)
1113 // check for corresponding afm metric
1114 // first look for an adjacent file
1115 static const char* pSuffix[] = { ".afm", ".AFM" };
1117 for( unsigned int i = 0; i < SAL_N_ELEMENTS(pSuffix); i++ )
1119 OString aName = OStringBuffer(
1120 rFontFile.copy(0, rFontFile.getLength() - 4)).
1121 append(pSuffix[i]).makeStringAndClear();
1123 OStringBuffer aFilePath(aDir);
1124 aFilePath.append('/').append(aName);
1126 OString aAfmFile;
1127 if( access( aFilePath.makeStringAndClear().getStr(), R_OK ) )
1129 // try in subdirectory afm instead
1130 aFilePath.append(aDir).append("/afm/").append(aName);
1132 if (!access(aFilePath.getStr(), R_OK))
1133 aAfmFile = OString("afm/") + aName;
1135 else
1136 aAfmFile = aName;
1138 if( !aAfmFile.isEmpty() )
1140 Type1FontFile* pFont = new Type1FontFile();
1141 pFont->m_nDirectory = nDirID;
1143 pFont->m_aFontFile = rFontFile;
1144 pFont->m_aMetricFile = aAfmFile;
1146 if( ! pFont->readAfmMetrics( m_pAtoms, false, true ) )
1148 delete pFont;
1149 pFont = NULL;
1151 if( pFont )
1152 rNewFonts.push_back( pFont );
1153 break;
1157 else if (eFormat == AFM)
1159 BuiltinFont* pFont = new BuiltinFont();
1160 pFont->m_nDirectory = nDirID;
1161 pFont->m_aMetricFile = rFontFile;
1162 if( pFont->readAfmMetrics( m_pAtoms, false, true ) )
1164 rNewFonts.push_back( pFont );
1166 else
1167 delete pFont;
1169 else if (eFormat == TRUETYPE || eFormat == CFF)
1171 // get number of ttc entries
1172 int nLength = CountTTCFonts( aFullPath.getStr() );
1173 if( nLength )
1175 #if OSL_DEBUG_LEVEL > 1
1176 fprintf( stderr, "ttc: %s contains %d fonts\n", aFullPath.getStr(), nLength );
1177 #endif
1179 sal_uInt64 fileSize = 0;
1181 OUString aURL;
1182 if (osl::File::getFileURLFromSystemPath(OStringToOUString(aFullPath, osl_getThreadTextEncoding()),
1183 aURL) == osl::File::E_None)
1185 osl::File aFile(aURL);
1186 if (aFile.open(osl_File_OpenFlag_Read | osl_File_OpenFlag_NoLock) == osl::File::E_None)
1188 osl::DirectoryItem aItem;
1189 osl::DirectoryItem::get( aURL, aItem );
1190 osl::FileStatus aFileStatus( osl_FileStatus_Mask_FileSize );
1191 aItem.getFileStatus( aFileStatus );
1192 fileSize = aFileStatus.getFileSize();
1196 //Feel free to calc the exact max possible number of fonts a file
1197 //could contain given its physical size. But this will clamp it to
1198 //a sane starting point
1199 //http://processingjs.nihongoresources.com/the_smallest_font/
1200 //https://github.com/grzegorzrolek/null-ttf
1201 int nMaxFontsPossible = fileSize / 528;
1203 nLength = std::min(nLength, nMaxFontsPossible);
1205 for( int i = 0; i < nLength; i++ )
1207 TrueTypeFontFile* pFont = new TrueTypeFontFile();
1208 pFont->m_nDirectory = nDirID;
1209 pFont->m_aFontFile = rFontFile;
1210 pFont->m_nCollectionEntry = i;
1211 if( ! analyzeTrueTypeFile( pFont ) )
1213 delete pFont;
1214 pFont = NULL;
1216 else
1217 rNewFonts.push_back( pFont );
1220 else
1222 TrueTypeFontFile* pFont = new TrueTypeFontFile();
1223 pFont->m_nDirectory = nDirID;
1224 pFont->m_aFontFile = rFontFile;
1225 pFont->m_nCollectionEntry = 0;
1227 // need to read the font anyway to get aliases inside the font file
1228 if( ! analyzeTrueTypeFile( pFont ) )
1230 delete pFont;
1231 pFont = NULL;
1233 else
1234 rNewFonts.push_back( pFont );
1237 return ! rNewFonts.empty();
1240 // -------------------------------------------------------------------------
1242 fontID PrintFontManager::findFontBuiltinID( int nPSNameAtom ) const
1244 fontID nID = 0;
1245 ::boost::unordered_map< fontID, PrintFont* >::const_iterator it;
1246 for( it = m_aFonts.begin(); nID == 0 && it != m_aFonts.end(); ++it )
1248 if( it->second->m_eType == fonttype::Builtin &&
1249 it->second->m_nPSName == nPSNameAtom )
1250 nID = it->first;
1252 return nID;
1255 // -------------------------------------------------------------------------
1257 fontID PrintFontManager::findFontFileID( int nDirID, const OString& rFontFile, int nFaceIndex ) const
1259 fontID nID = 0;
1261 ::boost::unordered_map< OString, ::std::set< fontID >, OStringHash >::const_iterator set_it = m_aFontFileToFontID.find( rFontFile );
1262 if( set_it == m_aFontFileToFontID.end() )
1263 return nID;
1265 for( ::std::set< fontID >::const_iterator font_it = set_it->second.begin(); font_it != set_it->second.end() && ! nID; ++font_it )
1267 ::boost::unordered_map< fontID, PrintFont* >::const_iterator it = m_aFonts.find( *font_it );
1268 if( it == m_aFonts.end() )
1269 continue;
1270 switch( it->second->m_eType )
1272 case fonttype::Type1:
1274 Type1FontFile* const pFont = static_cast< Type1FontFile* const >((*it).second);
1275 if( pFont->m_nDirectory == nDirID &&
1276 pFont->m_aFontFile == rFontFile )
1277 nID = it->first;
1279 break;
1280 case fonttype::TrueType:
1282 TrueTypeFontFile* const pFont = static_cast< TrueTypeFontFile* const >((*it).second);
1283 if( pFont->m_nDirectory == nDirID &&
1284 pFont->m_aFontFile == rFontFile && pFont->m_nCollectionEntry == nFaceIndex )
1285 nID = it->first;
1287 break;
1288 case fonttype::Builtin:
1289 if( static_cast<const BuiltinFont*>((*it).second)->m_nDirectory == nDirID &&
1290 static_cast<const BuiltinFont*>((*it).second)->m_aMetricFile == rFontFile )
1291 nID = it->first;
1292 break;
1293 default:
1294 break;
1298 return nID;
1301 std::vector<fontID> PrintFontManager::findFontFileIDs( int nDirID, const OString& rFontFile ) const
1303 std::vector<fontID> aIds;
1305 ::boost::unordered_map< OString, ::std::set< fontID >, OStringHash >::const_iterator set_it = m_aFontFileToFontID.find( rFontFile );
1306 if( set_it == m_aFontFileToFontID.end() )
1307 return aIds;
1309 for( ::std::set< fontID >::const_iterator font_it = set_it->second.begin(); font_it != set_it->second.end(); ++font_it )
1311 ::boost::unordered_map< fontID, PrintFont* >::const_iterator it = m_aFonts.find( *font_it );
1312 if( it == m_aFonts.end() )
1313 continue;
1314 switch( it->second->m_eType )
1316 case fonttype::Type1:
1318 Type1FontFile* const pFont = static_cast< Type1FontFile* const >((*it).second);
1319 if( pFont->m_nDirectory == nDirID &&
1320 pFont->m_aFontFile == rFontFile )
1321 aIds.push_back(it->first);
1323 break;
1324 case fonttype::TrueType:
1326 TrueTypeFontFile* const pFont = static_cast< TrueTypeFontFile* const >((*it).second);
1327 if( pFont->m_nDirectory == nDirID &&
1328 pFont->m_aFontFile == rFontFile )
1329 aIds.push_back(it->first);
1331 break;
1332 case fonttype::Builtin:
1333 if( static_cast<const BuiltinFont*>((*it).second)->m_nDirectory == nDirID &&
1334 static_cast<const BuiltinFont*>((*it).second)->m_aMetricFile == rFontFile )
1335 aIds.push_back(it->first);
1336 break;
1337 default:
1338 break;
1342 return aIds;
1345 // -------------------------------------------------------------------------
1347 OUString PrintFontManager::convertTrueTypeName( void* pRecord ) const
1349 NameRecord* pNameRecord = (NameRecord*)pRecord;
1350 OUString aValue;
1352 ( pNameRecord->platformID == 3 && ( pNameRecord->encodingID == 0 || pNameRecord->encodingID == 1 ) ) // MS, Unicode
1354 ( pNameRecord->platformID == 0 ) // Apple, Unicode
1357 OUStringBuffer aName( pNameRecord->slen/2 );
1358 const sal_uInt8* pNameBuffer = pNameRecord->sptr;
1359 for(int n = 0; n < pNameRecord->slen/2; n++ )
1360 aName.append( (sal_Unicode)getUInt16BE( pNameBuffer ) );
1361 aValue = aName.makeStringAndClear();
1363 else if( pNameRecord->platformID == 3 )
1365 if( pNameRecord->encodingID >= 2 && pNameRecord->encodingID <= 6 )
1368 * and now for a special kind of madness:
1369 * some fonts encode their byte value string as BE uint16
1370 * (leading to stray zero bytes in the string)
1371 * while others code two bytes as a uint16 and swap to BE
1373 OStringBuffer aName;
1374 const sal_uInt8* pNameBuffer = pNameRecord->sptr;
1375 for(int n = 0; n < pNameRecord->slen/2; n++ )
1377 sal_Unicode aCode = (sal_Unicode)getUInt16BE( pNameBuffer );
1378 sal_Char aChar = aCode >> 8;
1379 if( aChar )
1380 aName.append( aChar );
1381 aChar = aCode & 0x00ff;
1382 if( aChar )
1383 aName.append( aChar );
1385 switch( pNameRecord->encodingID )
1387 case 2:
1388 aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_932 );
1389 break;
1390 case 3:
1391 aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_936 );
1392 break;
1393 case 4:
1394 aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_950 );
1395 break;
1396 case 5:
1397 aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_949 );
1398 break;
1399 case 6:
1400 aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_1361 );
1401 break;
1405 return aValue;
1408 //fdo#33349.There exists an archaic Berling Antiqua font which has a "Times New
1409 //Roman" name field in it. We don't want the "Times New Roman" name to take
1410 //precedence in this case. We take Berling Antiqua as a higher priority name,
1411 //and erase the "Times New Roman" name
1412 namespace
1414 bool isBadTNR(const OUString &rName, ::std::set< OUString >& rSet)
1416 bool bRet = false;
1417 if ( rName == "Berling Antiqua" )
1419 ::std::set< OUString >::iterator aEnd = rSet.end();
1420 ::std::set< OUString >::iterator aI = rSet.find("Times New Roman");
1421 if (aI != aEnd)
1423 bRet = true;
1424 rSet.erase(aI);
1427 return bRet;
1431 // -------------------------------------------------------------------------
1433 void PrintFontManager::analyzeTrueTypeFamilyName( void* pTTFont, ::std::list< OUString >& rNames ) const
1435 OUString aFamily;
1437 rNames.clear();
1438 ::std::set< OUString > aSet;
1440 NameRecord* pNameRecords = NULL;
1441 int nNameRecords = GetTTNameRecords( (TrueTypeFont*)pTTFont, &pNameRecords );
1442 if( nNameRecords && pNameRecords )
1444 LanguageType aLang = MsLangId::getSystemLanguage();
1445 int nLastMatch = -1;
1446 for( int i = 0; i < nNameRecords; i++ )
1448 if( pNameRecords[i].nameID != 1 || pNameRecords[i].sptr == NULL )
1449 continue;
1450 int nMatch = -1;
1451 if( pNameRecords[i].platformID == 0 ) // Unicode
1452 nMatch = 4000;
1453 else if( pNameRecords[i].platformID == 3 )
1455 // this bases on the LanguageType actually being a Win LCID
1456 if( pNameRecords[i].languageID == aLang )
1457 nMatch = 8000;
1458 else if( pNameRecords[i].languageID == LANGUAGE_ENGLISH_US )
1459 nMatch = 2000;
1460 else if( pNameRecords[i].languageID == LANGUAGE_ENGLISH ||
1461 pNameRecords[i].languageID == LANGUAGE_ENGLISH_UK )
1462 nMatch = 1500;
1463 else
1464 nMatch = 1000;
1466 OUString aName = convertTrueTypeName( pNameRecords + i );
1467 aSet.insert( aName );
1468 if( nMatch > nLastMatch || isBadTNR(aName, aSet) )
1470 nLastMatch = nMatch;
1471 aFamily = aName;
1474 DisposeNameRecords( pNameRecords, nNameRecords );
1476 if( !aFamily.isEmpty() )
1478 rNames.push_front( aFamily );
1479 for( ::std::set< OUString >::const_iterator it = aSet.begin(); it != aSet.end(); ++it )
1480 if( *it != aFamily )
1481 rNames.push_back( *it );
1483 return;
1486 // -------------------------------------------------------------------------
1488 bool PrintFontManager::analyzeTrueTypeFile( PrintFont* pFont ) const
1490 bool bSuccess = false;
1491 rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
1492 OString aFile = getFontFile( pFont );
1493 TrueTypeFont* pTTFont = NULL;
1495 TrueTypeFontFile* pTTFontFile = static_cast< TrueTypeFontFile* >(pFont);
1496 if( OpenTTFontFile( aFile.getStr(), pTTFontFile->m_nCollectionEntry, &pTTFont ) == SF_OK )
1498 TTGlobalFontInfo aInfo;
1499 GetTTGlobalFontInfo( pTTFont, & aInfo );
1501 ::std::list< OUString > aNames;
1502 analyzeTrueTypeFamilyName( pTTFont, aNames );
1504 // set family name from XLFD if possible
1505 if( ! pFont->m_nFamilyName )
1507 if( aNames.begin() != aNames.end() )
1509 pFont->m_nFamilyName = m_pAtoms->getAtom( ATOM_FAMILYNAME, aNames.front(), sal_True );
1510 aNames.pop_front();
1512 else
1514 sal_Int32 dotIndex;
1516 // poor font does not have a family name
1517 // name it to file name minus the extension
1518 dotIndex = pTTFontFile->m_aFontFile.lastIndexOf( '.' );
1519 if ( dotIndex == -1 )
1520 dotIndex = pTTFontFile->m_aFontFile.getLength();
1522 pFont->m_nFamilyName = m_pAtoms->getAtom( ATOM_FAMILYNAME, OStringToOUString( pTTFontFile->m_aFontFile.copy( 0, dotIndex ), aEncoding ), sal_True );
1525 for( ::std::list< OUString >::iterator it = aNames.begin(); it != aNames.end(); ++it )
1527 if( !it->isEmpty() )
1529 int nAlias = m_pAtoms->getAtom( ATOM_FAMILYNAME, *it, sal_True );
1530 if( nAlias != pFont->m_nFamilyName )
1532 std::list< int >::const_iterator al_it;
1533 for( al_it = pFont->m_aAliases.begin(); al_it != pFont->m_aAliases.end() && *al_it != nAlias; ++al_it )
1535 if( al_it == pFont->m_aAliases.end() )
1536 pFont->m_aAliases.push_back( nAlias );
1541 if( aInfo.usubfamily )
1542 pFont->m_aStyleName = OUString( aInfo.usubfamily );
1544 SAL_WARN_IF( !aInfo.psname, "vcl", "No PostScript name in font:" << aFile.getStr() );
1546 OUString sPSName = aInfo.psname ?
1547 OUString(aInfo.psname, rtl_str_getLength(aInfo.psname), aEncoding) :
1548 m_pAtoms->getString(ATOM_FAMILYNAME, pFont->m_nFamilyName); // poor font does not have a postscript name
1550 pFont->m_nPSName = m_pAtoms->getAtom( ATOM_PSNAME, sPSName, sal_True );
1552 switch( aInfo.weight )
1554 case FW_THIN: pFont->m_eWeight = WEIGHT_THIN; break;
1555 case FW_EXTRALIGHT: pFont->m_eWeight = WEIGHT_ULTRALIGHT; break;
1556 case FW_LIGHT: pFont->m_eWeight = WEIGHT_LIGHT; break;
1557 case FW_MEDIUM: pFont->m_eWeight = WEIGHT_MEDIUM; break;
1558 case FW_SEMIBOLD: pFont->m_eWeight = WEIGHT_SEMIBOLD; break;
1559 case FW_BOLD: pFont->m_eWeight = WEIGHT_BOLD; break;
1560 case FW_EXTRABOLD: pFont->m_eWeight = WEIGHT_ULTRABOLD; break;
1561 case FW_BLACK: pFont->m_eWeight = WEIGHT_BLACK; break;
1563 case FW_NORMAL:
1564 default: pFont->m_eWeight = WEIGHT_NORMAL; break;
1567 switch( aInfo.width )
1569 case FWIDTH_ULTRA_CONDENSED: pFont->m_eWidth = WIDTH_ULTRA_CONDENSED; break;
1570 case FWIDTH_EXTRA_CONDENSED: pFont->m_eWidth = WIDTH_EXTRA_CONDENSED; break;
1571 case FWIDTH_CONDENSED: pFont->m_eWidth = WIDTH_CONDENSED; break;
1572 case FWIDTH_SEMI_CONDENSED: pFont->m_eWidth = WIDTH_SEMI_CONDENSED; break;
1573 case FWIDTH_SEMI_EXPANDED: pFont->m_eWidth = WIDTH_SEMI_EXPANDED; break;
1574 case FWIDTH_EXPANDED: pFont->m_eWidth = WIDTH_EXPANDED; break;
1575 case FWIDTH_EXTRA_EXPANDED: pFont->m_eWidth = WIDTH_EXTRA_EXPANDED; break;
1576 case FWIDTH_ULTRA_EXPANDED: pFont->m_eWidth = WIDTH_ULTRA_EXPANDED; break;
1578 case FWIDTH_NORMAL:
1579 default: pFont->m_eWidth = WIDTH_NORMAL; break;
1582 pFont->m_ePitch = aInfo.pitch ? PITCH_FIXED : PITCH_VARIABLE;
1583 pFont->m_eItalic = aInfo.italicAngle == 0 ? ITALIC_NONE : ( aInfo.italicAngle < 0 ? ITALIC_NORMAL : ITALIC_OBLIQUE );
1584 // #104264# there are fonts that set italic angle 0 although they are
1585 // italic; use macstyle bit here
1586 if( aInfo.italicAngle == 0 && (aInfo.macStyle & 2) )
1587 pFont->m_eItalic = ITALIC_NORMAL;
1589 pFont->m_aEncoding = aInfo.symbolEncoded ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UCS2;
1591 pFont->m_aGlobalMetricY.width = pFont->m_aGlobalMetricX.width = aInfo.xMax - aInfo.xMin;
1592 pFont->m_aGlobalMetricY.height = pFont->m_aGlobalMetricX.height = aInfo.yMax - aInfo.yMin;
1594 if( aInfo.winAscent && aInfo.winDescent )
1596 pFont->m_nAscend = aInfo.winAscent;
1597 pFont->m_nDescend = aInfo.winDescent;
1598 pFont->m_nLeading = pFont->m_nAscend + pFont->m_nDescend - 1000;
1600 else if( aInfo.typoAscender && aInfo.typoDescender )
1602 pFont->m_nLeading = aInfo.typoLineGap;
1603 pFont->m_nAscend = aInfo.typoAscender;
1604 pFont->m_nDescend = -aInfo.typoDescender;
1606 else
1608 pFont->m_nLeading = aInfo.linegap;
1609 pFont->m_nAscend = aInfo.ascender;
1610 pFont->m_nDescend = -aInfo.descender;
1613 // last try: font bounding box
1614 if( pFont->m_nAscend == 0 )
1615 pFont->m_nAscend = aInfo.yMax;
1616 if( pFont->m_nDescend == 0 )
1617 pFont->m_nDescend = -aInfo.yMin;
1618 if( pFont->m_nLeading == 0 )
1619 pFont->m_nLeading = 15 * (pFont->m_nAscend+pFont->m_nDescend) / 100;
1621 if( pFont->m_nAscend )
1622 pFont->m_aGlobalMetricX.height = pFont->m_aGlobalMetricY.height = pFont->m_nAscend + pFont->m_nDescend;
1624 // get bounding box
1625 pFont->m_nXMin = aInfo.xMin;
1626 pFont->m_nYMin = aInfo.yMin;
1627 pFont->m_nXMax = aInfo.xMax;
1628 pFont->m_nYMax = aInfo.yMax;
1630 // get type flags
1631 pTTFontFile->m_nTypeFlags = (unsigned int)aInfo.typeFlags;
1633 // get vertical substitutions flag
1634 pFont->m_bHaveVerticalSubstitutedGlyphs = DoesVerticalSubstitution( pTTFont, 1 );
1636 CloseTTFont( pTTFont );
1637 bSuccess = true;
1639 #if OSL_DEBUG_LEVEL > 1
1640 else
1641 fprintf( stderr, "could not OpenTTFont \"%s\"\n", aFile.getStr() );
1642 #endif
1644 return bSuccess;
1647 static bool AreFCSubstitutionsEnabled()
1649 return (SalGenericInstance::FetchFontSubstitutionFlags() & 3) == 0;
1652 void PrintFontManager::initialize()
1654 #ifdef CALLGRIND_COMPILE
1655 CALLGRIND_TOGGLE_COLLECT();
1656 CALLGRIND_ZERO_STATS();
1657 #endif
1659 long aDirEntBuffer[ (sizeof(struct dirent)+PATH_MAX)+1 ];
1661 if( ! m_pFontCache )
1663 #if OSL_DEBUG_LEVEL > 1
1664 fprintf( stderr, "creating font cache ... " );
1665 clock_t aStart;
1666 struct tms tms;
1667 aStart = times( &tms );
1668 #endif
1669 m_pFontCache = new FontCache();
1670 #if OSL_DEBUG_LEVEL > 1
1671 clock_t aStop = times( &tms );
1672 fprintf( stderr, "done in %lf s\n", (double)(aStop - aStart)/(double)sysconf( _SC_CLK_TCK ) );
1673 #endif
1676 // initialize can be called more than once, e.g.
1677 // gtk-fontconfig-timestamp changes to reflect new font installed and
1678 // PrintFontManager::initialize called again
1680 for( ::boost::unordered_map< fontID, PrintFont* >::const_iterator it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
1681 delete (*it).second;
1682 m_nNextFontID = 1;
1683 m_aFonts.clear();
1684 m_aFontDirectories.clear();
1685 m_aPrivateFontDirectories.clear();
1688 #if OSL_DEBUG_LEVEL > 1
1689 clock_t aStart;
1690 clock_t aStep1;
1691 clock_t aStep2;
1692 clock_t aStep3;
1693 int nBuiltinFonts = 0;
1694 int nCached = 0;
1696 struct tms tms;
1698 aStart = times( &tms );
1699 #endif
1701 // first try fontconfig
1702 initFontconfig();
1704 // part one - look for downloadable fonts
1705 rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
1706 const OUString &rSalPrivatePath = psp::getFontPath();
1708 // search for the fonts in SAL_PRIVATE_FONTPATH first; those are
1709 // the fonts installed with the office
1710 if( !rSalPrivatePath.isEmpty() )
1712 OString aPath = OUStringToOString( rSalPrivatePath, aEncoding );
1713 const bool bAreFCSubstitutionsEnabled = AreFCSubstitutionsEnabled();
1714 sal_Int32 nIndex = 0;
1717 OString aToken = aPath.getToken( 0, ';', nIndex );
1718 normPath( aToken );
1719 if ( aToken.isEmpty() )
1721 continue;
1723 // if registering an app-specific fontdir with fontconfig fails
1724 // and fontconfig-based substitutions are enabled
1725 // then trying to use these app-specific fonts doesn't make sense
1726 if( !addFontconfigDir( aToken ) )
1727 if( bAreFCSubstitutionsEnabled )
1728 continue;
1729 m_aFontDirectories.push_back( aToken );
1730 m_aPrivateFontDirectories.push_back( getDirectoryAtom( aToken, true ) );
1731 } while( nIndex >= 0 );
1734 // protect against duplicate paths
1735 boost::unordered_map< OString, int, OStringHash > visited_dirs;
1737 // Don't search directories that fontconfig already did
1738 countFontconfigFonts( visited_dirs );
1740 // search for font files in each path
1741 std::list< OString >::iterator dir_it;
1742 for( dir_it = m_aFontDirectories.begin(); dir_it != m_aFontDirectories.end(); ++dir_it )
1744 OString aPath( *dir_it );
1745 // see if we were here already
1746 if( visited_dirs.find( aPath ) != visited_dirs.end() )
1747 continue;
1748 visited_dirs[ aPath ] = 1;
1750 // there may be ":unscaled" directories (see XFree86)
1751 // it should be safe to ignore them since they should not
1752 // contain any of our recognizeable fonts
1754 // ask the font cache whether it handles this directory
1755 std::list< PrintFont* > aCacheFonts;
1756 if( m_pFontCache->listDirectory( aPath, aCacheFonts ) )
1758 #if OSL_DEBUG_LEVEL > 1
1759 fprintf( stderr, "adding cache directory: %s\n", aPath.getStr() );
1760 #endif
1761 for( ::std::list< PrintFont* >::iterator it = aCacheFonts.begin(); it != aCacheFonts.end(); ++it )
1763 fontID aFont = m_nNextFontID++;
1764 m_aFonts[ aFont ] = *it;
1765 if( (*it)->m_eType == fonttype::Type1 )
1766 m_aFontFileToFontID[ static_cast<Type1FontFile*>(*it)->m_aFontFile ].insert( aFont );
1767 else if( (*it)->m_eType == fonttype::TrueType )
1768 m_aFontFileToFontID[ static_cast<TrueTypeFontFile*>(*it)->m_aFontFile ].insert( aFont );
1769 else if( (*it)->m_eType == fonttype::Builtin )
1770 m_aFontFileToFontID[ static_cast<BuiltinFont*>(*it)->m_aMetricFile ].insert( aFont );
1771 #if OSL_DEBUG_LEVEL > 1
1772 else
1773 fprintf(stderr, "Un-cached type '%d'\n", (*it)->m_eType);
1774 if( (*it)->m_eType == fonttype::Builtin )
1775 nBuiltinFonts++;
1776 nCached++;
1777 #if OSL_DEBUG_LEVEL > 2
1778 fprintf( stderr, "adding cached font %d: %s\n", aFont, getFontFileSysPath( aFont ).getStr() );
1779 #endif
1780 #endif
1782 if( ! m_pFontCache->scanAdditionalFiles( aPath ) )
1783 continue;
1788 #if OSL_DEBUG_LEVEL > 1
1789 aStep1 = times( &tms );
1790 #endif
1792 // part two - look for metrics for builtin printer fonts
1793 std::list< OUString > aMetricDirs;
1794 psp::getPrinterPathList( aMetricDirs, PRINTER_METRICDIR );
1796 for( std::list< OUString >::const_iterator met_dir_it = aMetricDirs.begin(); met_dir_it != aMetricDirs.end(); ++met_dir_it )
1798 OString aDir = OUStringToOString( *met_dir_it, aEncoding );
1800 // ask the font cache whether it handles this directory
1801 std::list< PrintFont* > aCacheFonts;
1803 if( m_pFontCache->listDirectory( aDir, aCacheFonts ) )
1805 #if OSL_DEBUG_LEVEL > 1
1806 fprintf( stderr, "adding cache directory: %s\n", aDir.getStr() );
1807 #endif
1808 for( ::std::list< PrintFont* >::iterator it = aCacheFonts.begin(); it != aCacheFonts.end(); ++it )
1810 fontID aFont = m_nNextFontID++;
1811 m_aFonts[ aFont ] = *it;
1812 if( (*it)->m_eType == fonttype::Type1 )
1813 m_aFontFileToFontID[ static_cast<Type1FontFile*>(*it)->m_aFontFile ].insert( aFont );
1814 else if( (*it)->m_eType == fonttype::TrueType )
1815 m_aFontFileToFontID[ static_cast<TrueTypeFontFile*>(*it)->m_aFontFile ].insert( aFont );
1816 else if( (*it)->m_eType == fonttype::Builtin )
1817 m_aFontFileToFontID[ static_cast<BuiltinFont*>(*it)->m_aMetricFile ].insert( aFont );
1818 #if OSL_DEBUG_LEVEL > 1
1819 if( (*it)->m_eType == fonttype::Builtin )
1820 nBuiltinFonts++;
1821 nCached++;
1822 #if OSL_DEBUG_LEVEL > 2
1823 fprintf( stderr, "adding cached font %d: from %s\n", aFont,
1824 getFontFileSysPath( aFont ).getStr() );
1825 #endif
1826 #endif
1828 continue;
1831 DIR* pDIR = opendir( aDir.getStr() );
1832 if( pDIR )
1834 struct dirent* pDirEntry = (struct dirent*)aDirEntBuffer;
1835 int nDirID = getDirectoryAtom( aDir, true );
1836 int nDirFonts = 0;
1838 while( ! readdir_r( pDIR, (struct dirent*)aDirEntBuffer, &pDirEntry ) && pDirEntry )
1840 OStringBuffer aFile(aDir);
1841 aFile.append('/').append(pDirEntry->d_name);
1842 struct stat aStat;
1843 if( ! stat( aFile.getStr(), &aStat )
1844 && S_ISREG( aStat.st_mode )
1847 OString aFileName( pDirEntry->d_name, strlen( pDirEntry->d_name ) );
1848 OString aExt( aFileName.copy( aFileName.lastIndexOf( '.' )+1 ) );
1849 if( aExt.equalsIgnoreAsciiCase( "afm" ) )
1851 ::std::list< PrintFont* > aNewFonts;
1853 analyzeFontFile( nDirID, aFileName, aNewFonts );
1854 for( ::std::list< PrintFont* >::iterator it = aNewFonts.begin(); it != aNewFonts.end(); ++it )
1856 if( findFontBuiltinID( (*it)->m_nPSName ) == 0 )
1858 m_aFontFileToFontID[ aFileName ].insert( m_nNextFontID );
1859 m_aFonts[ m_nNextFontID++ ] = *it;
1860 m_pFontCache->updateFontCacheEntry( *it, false );
1861 #if OSL_DEBUG_LEVEL > 2
1862 nBuiltinFonts++;
1863 #endif
1865 else
1866 delete *it;
1871 closedir( pDIR );
1872 if( ! nDirFonts )
1873 m_pFontCache->markEmptyDir( nDirID );
1877 #if OSL_DEBUG_LEVEL > 1
1878 aStep2 = times( &tms );
1879 #endif
1881 // part three - fill in family styles
1882 ::boost::unordered_map< fontID, PrintFont* >::iterator font_it;
1883 for (font_it = m_aFonts.begin(); font_it != m_aFonts.end(); ++font_it)
1885 ::boost::unordered_map< int, FontFamily >::const_iterator it =
1886 m_aFamilyTypes.find( font_it->second->m_nFamilyName );
1887 if (it != m_aFamilyTypes.end())
1888 continue;
1889 const OUString& rFamily =
1890 m_pAtoms->getString( ATOM_FAMILYNAME, font_it->second->m_nFamilyName);
1891 FontFamily eType = matchFamilyName( rFamily );
1892 m_aFamilyTypes[ font_it->second->m_nFamilyName ] = eType;
1895 #if OSL_DEBUG_LEVEL > 1
1896 aStep3 = times( &tms );
1897 fprintf( stderr, "PrintFontManager::initialize: collected %" SAL_PRI_SIZET "u fonts (%d builtin, %d cached)\n", m_aFonts.size(), nBuiltinFonts, nCached );
1898 double fTick = (double)sysconf( _SC_CLK_TCK );
1899 fprintf( stderr, "Step 1 took %lf seconds\n", (double)(aStep1 - aStart)/fTick );
1900 fprintf( stderr, "Step 2 took %lf seconds\n", (double)(aStep2 - aStep1)/fTick );
1901 fprintf( stderr, "Step 3 took %lf seconds\n", (double)(aStep3 - aStep2)/fTick );
1902 #endif
1904 m_pFontCache->flush();
1906 #ifdef CALLGRIND_COMPILE
1907 CALLGRIND_DUMP_STATS();
1908 CALLGRIND_TOGGLE_COLLECT();
1909 #endif
1912 // -------------------------------------------------------------------------
1913 inline bool
1914 equalPitch (FontPitch from, FontPitch to)
1916 return from == to;
1919 inline bool
1920 equalWeight (FontWeight from, FontWeight to)
1922 return from > to ? (from - to) <= 3 : (to - from) <= 3;
1925 inline bool
1926 equalItalic (FontItalic from, FontItalic to)
1928 if ( (from == ITALIC_NORMAL) || (from == ITALIC_OBLIQUE) )
1929 return (to == ITALIC_NORMAL) || (to == ITALIC_OBLIQUE);
1930 return to == from;
1932 inline bool
1933 equalEncoding (rtl_TextEncoding from, rtl_TextEncoding to)
1935 if ((from == RTL_TEXTENCODING_ISO_8859_1) || (from == RTL_TEXTENCODING_MS_1252))
1936 return (to == RTL_TEXTENCODING_ISO_8859_1) || (to == RTL_TEXTENCODING_MS_1252);
1937 return from == to;
1940 namespace {
1941 struct BuiltinFontIdentifier
1943 OUString aFamily;
1944 FontItalic eItalic;
1945 FontWeight eWeight;
1946 FontPitch ePitch;
1947 rtl_TextEncoding aEncoding;
1949 BuiltinFontIdentifier( const OUString& rFam,
1950 FontItalic eIt,
1951 FontWeight eWg,
1952 FontPitch ePt,
1953 rtl_TextEncoding enc ) :
1954 aFamily( rFam ),
1955 eItalic( eIt ),
1956 eWeight( eWg ),
1957 ePitch( ePt ),
1958 aEncoding( enc )
1961 bool operator==( const BuiltinFontIdentifier& rRight ) const
1963 return equalItalic( eItalic, rRight.eItalic ) &&
1964 equalWeight( eWeight, rRight.eWeight ) &&
1965 equalPitch( ePitch, rRight.ePitch ) &&
1966 equalEncoding( aEncoding, rRight.aEncoding ) &&
1967 aFamily.equalsIgnoreAsciiCase( rRight.aFamily );
1971 struct BuiltinFontIdentifierHash
1973 size_t operator()( const BuiltinFontIdentifier& rFont ) const
1975 return rFont.aFamily.hashCode() ^ rFont.eItalic ^ rFont.eWeight ^ rFont.ePitch ^ rFont.aEncoding;
1980 void PrintFontManager::getFontList( ::std::list< fontID >& rFontIDs, const PPDParser* pParser )
1982 rFontIDs.clear();
1983 boost::unordered_map< fontID, PrintFont* >::const_iterator it;
1986 * Note: there are two easy steps making this faster:
1987 * first: insert the printer builtins first, then the not builtins,
1988 * if they do not match.
1989 * drawback: this would change the sequence of fonts; this could have
1990 * subtle, unknown consequences in vcl font matching
1991 * second: instead of comparing attributes to see whether a softfont
1992 * is duplicate to a builtin one could simply compare the PSName (which is
1993 * supposed to be unique), which at this point is just an int.
1994 * drawback: this could change which fonts are listed; especially TrueType
1995 * fonts often have a rather dubious PSName, so this could change the
1996 * font list not so subtle.
1997 * Until getFontList for a printer becomes a performance issue (which is
1998 * currently not the case), best stay with the current algorithm.
2001 // fill sets of printer supported fonts
2002 if( pParser )
2004 std::set<int> aBuiltinPSNames;
2005 boost::unordered_set< BuiltinFontIdentifier,
2006 BuiltinFontIdentifierHash
2007 > aBuiltinFonts;
2009 int nFonts = pParser->getFonts();
2010 for( int i = 0; i < nFonts; i++ )
2011 aBuiltinPSNames.insert( m_pAtoms->getAtom( ATOM_PSNAME, pParser->getFont( i ) ) );
2012 for( it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
2014 PrintFont* pFont = it->second;
2015 if( it->second->m_eType == fonttype::Builtin &&
2016 aBuiltinPSNames.find( pFont->m_nPSName ) != aBuiltinPSNames.end() )
2018 aBuiltinFonts.insert( BuiltinFontIdentifier(
2019 m_pAtoms->getString( ATOM_FAMILYNAME, pFont->m_nFamilyName ),
2020 pFont->m_eItalic,
2021 pFont->m_eWeight,
2022 pFont->m_ePitch,
2023 pFont->m_aEncoding
2024 ) );
2027 for( it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
2029 PrintFont* pFont = it->second;
2030 if( it->second->m_eType == fonttype::Builtin )
2032 if( aBuiltinPSNames.find( pFont->m_nPSName ) != aBuiltinPSNames.end() )
2034 rFontIDs.push_back( it->first );
2037 else if( aBuiltinFonts.find( BuiltinFontIdentifier(
2038 m_pAtoms->getString( ATOM_FAMILYNAME, pFont->m_nFamilyName ),
2039 pFont->m_eItalic,
2040 pFont->m_eWeight,
2041 pFont->m_ePitch,
2042 pFont->m_aEncoding
2043 ) ) == aBuiltinFonts.end() )
2045 rFontIDs.push_back( it->first );
2049 else // no specific printer
2051 for( it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
2052 rFontIDs.push_back( it->first );
2056 // -------------------------------------------------------------------------
2058 void PrintFontManager::fillPrintFontInfo( PrintFont* pFont, FastPrintFontInfo& rInfo ) const
2060 ::boost::unordered_map< int, FontFamily >::const_iterator style_it =
2061 m_aFamilyTypes.find( pFont->m_nFamilyName );
2062 rInfo.m_eType = pFont->m_eType;
2063 rInfo.m_aFamilyName = m_pAtoms->getString( ATOM_FAMILYNAME, pFont->m_nFamilyName );
2064 rInfo.m_aStyleName = pFont->m_aStyleName;
2065 rInfo.m_eFamilyStyle = style_it != m_aFamilyTypes.end() ? style_it->second : FAMILY_DONTKNOW;
2066 rInfo.m_eItalic = pFont->m_eItalic;
2067 rInfo.m_eWidth = pFont->m_eWidth;
2068 rInfo.m_eWeight = pFont->m_eWeight;
2069 rInfo.m_ePitch = pFont->m_ePitch;
2070 rInfo.m_aEncoding = pFont->m_aEncoding;
2072 rInfo.m_bEmbeddable = (pFont->m_eType == fonttype::Type1);
2073 rInfo.m_bSubsettable = (pFont->m_eType == fonttype::TrueType); // TODO: rename to SfntType
2075 rInfo.m_aAliases.clear();
2076 for( ::std::list< int >::iterator it = pFont->m_aAliases.begin(); it != pFont->m_aAliases.end(); ++it )
2077 rInfo.m_aAliases.push_back( m_pAtoms->getString( ATOM_FAMILYNAME, *it ) );
2080 // -------------------------------------------------------------------------
2082 void PrintFontManager::fillPrintFontInfo( PrintFont* pFont, PrintFontInfo& rInfo ) const
2084 if( ( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 ) ||
2085 ! pFont->m_pMetrics || pFont->m_pMetrics->isEmpty()
2088 // might be a truetype font not analyzed or type1 without metrics read
2089 if( pFont->m_eType == fonttype::Type1 )
2090 pFont->readAfmMetrics( m_pAtoms, false, false );
2091 else if( pFont->m_eType == fonttype::TrueType )
2092 analyzeTrueTypeFile( pFont );
2095 fillPrintFontInfo( pFont, static_cast< FastPrintFontInfo& >( rInfo ) );
2097 rInfo.m_nAscend = pFont->m_nAscend;
2098 rInfo.m_nDescend = pFont->m_nDescend;
2099 rInfo.m_nLeading = pFont->m_nLeading;
2100 rInfo.m_nWidth = pFont->m_aGlobalMetricX.width < pFont->m_aGlobalMetricY.width ? pFont->m_aGlobalMetricY.width : pFont->m_aGlobalMetricX.width;
2103 // -------------------------------------------------------------------------
2105 void PrintFontManager::getFontListWithFastInfo( ::std::list< FastPrintFontInfo >& rFonts, const PPDParser* pParser )
2107 rFonts.clear();
2108 ::std::list< fontID > aFontList;
2109 getFontList( aFontList, pParser );
2111 ::std::list< fontID >::iterator it;
2112 for( it = aFontList.begin(); it != aFontList.end(); ++it )
2114 FastPrintFontInfo aInfo;
2115 aInfo.m_nID = *it;
2116 fillPrintFontInfo( getFont( *it ), aInfo );
2117 rFonts.push_back( aInfo );
2121 // -------------------------------------------------------------------------
2123 bool PrintFontManager::getFontInfo( fontID nFontID, PrintFontInfo& rInfo ) const
2125 PrintFont* pFont = getFont( nFontID );
2126 if( pFont )
2128 rInfo.m_nID = nFontID;
2129 fillPrintFontInfo( pFont, rInfo );
2131 return pFont ? true : false;
2134 // -------------------------------------------------------------------------
2136 bool PrintFontManager::getFontFastInfo( fontID nFontID, FastPrintFontInfo& rInfo ) const
2138 PrintFont* pFont = getFont( nFontID );
2139 if( pFont )
2141 rInfo.m_nID = nFontID;
2142 fillPrintFontInfo( pFont, rInfo );
2144 return pFont ? true : false;
2147 // -------------------------------------------------------------------------
2149 bool PrintFontManager::getFontBoundingBox( fontID nFontID, int& xMin, int& yMin, int& xMax, int& yMax )
2151 bool bSuccess = false;
2152 PrintFont* pFont = getFont( nFontID );
2153 if( pFont )
2155 if( pFont->m_nXMin == 0 && pFont->m_nYMin == 0 && pFont->m_nXMax == 0 && pFont->m_nYMax == 0 )
2157 // might be a truetype font not analyzed or type1 without metrics read
2158 if( pFont->m_eType == fonttype::Type1 || pFont->m_eType == fonttype::Builtin )
2159 pFont->readAfmMetrics( m_pAtoms, false, true );
2160 else if( pFont->m_eType == fonttype::TrueType )
2161 analyzeTrueTypeFile( pFont );
2163 bSuccess = true;
2164 xMin = pFont->m_nXMin;
2165 yMin = pFont->m_nYMin;
2166 xMax = pFont->m_nXMax;
2167 yMax = pFont->m_nYMax;
2169 return bSuccess;
2172 // -------------------------------------------------------------------------
2174 int PrintFontManager::getFontFaceNumber( fontID nFontID ) const
2176 int nRet = 0;
2177 PrintFont* pFont = getFont( nFontID );
2178 if( pFont && pFont->m_eType == fonttype::TrueType )
2179 nRet = static_cast< TrueTypeFontFile* >(pFont)->m_nCollectionEntry;
2180 if (nRet < 0)
2181 nRet = 0;
2182 return nRet;
2185 // -------------------------------------------------------------------------
2188 FontFamily PrintFontManager::matchFamilyName( const OUString& rFamily ) const
2190 typedef struct {
2191 const char* mpName;
2192 sal_uInt16 mnLength;
2193 FontFamily meType;
2194 } family_t;
2196 #define InitializeClass( p, a ) p, sizeof(p) - 1, a
2197 const family_t pFamilyMatch[] = {
2198 { InitializeClass( "arial", FAMILY_SWISS ) },
2199 { InitializeClass( "arioso", FAMILY_SCRIPT ) },
2200 { InitializeClass( "avant garde", FAMILY_SWISS ) },
2201 { InitializeClass( "avantgarde", FAMILY_SWISS ) },
2202 { InitializeClass( "bembo", FAMILY_ROMAN ) },
2203 { InitializeClass( "bookman", FAMILY_ROMAN ) },
2204 { InitializeClass( "conga", FAMILY_ROMAN ) },
2205 { InitializeClass( "courier", FAMILY_MODERN ) },
2206 { InitializeClass( "curl", FAMILY_SCRIPT ) },
2207 { InitializeClass( "fixed", FAMILY_MODERN ) },
2208 { InitializeClass( "gill", FAMILY_SWISS ) },
2209 { InitializeClass( "helmet", FAMILY_MODERN ) },
2210 { InitializeClass( "helvetica", FAMILY_SWISS ) },
2211 { InitializeClass( "international", FAMILY_MODERN ) },
2212 { InitializeClass( "lucida", FAMILY_SWISS ) },
2213 { InitializeClass( "new century schoolbook", FAMILY_ROMAN ) },
2214 { InitializeClass( "palatino", FAMILY_ROMAN ) },
2215 { InitializeClass( "roman", FAMILY_ROMAN ) },
2216 { InitializeClass( "sans serif", FAMILY_SWISS ) },
2217 { InitializeClass( "sansserif", FAMILY_SWISS ) },
2218 { InitializeClass( "serf", FAMILY_ROMAN ) },
2219 { InitializeClass( "serif", FAMILY_ROMAN ) },
2220 { InitializeClass( "times", FAMILY_ROMAN ) },
2221 { InitializeClass( "utopia", FAMILY_ROMAN ) },
2222 { InitializeClass( "zapf chancery", FAMILY_SCRIPT ) },
2223 { InitializeClass( "zapfchancery", FAMILY_SCRIPT ) }
2226 OString aFamily = OUStringToOString( rFamily, RTL_TEXTENCODING_ASCII_US );
2227 sal_uInt32 nLower = 0;
2228 sal_uInt32 nUpper = SAL_N_ELEMENTS(pFamilyMatch);
2230 while( nLower < nUpper )
2232 sal_uInt32 nCurrent = (nLower + nUpper) / 2;
2233 const family_t* pHaystack = pFamilyMatch + nCurrent;
2234 sal_Int32 nComparison =
2235 rtl_str_compareIgnoreAsciiCase_WithLength
2237 aFamily.getStr(), aFamily.getLength(),
2238 pHaystack->mpName, pHaystack->mnLength
2241 if( nComparison < 0 )
2242 nUpper = nCurrent;
2243 else
2244 if( nComparison > 0 )
2245 nLower = nCurrent + 1;
2246 else
2247 return pHaystack->meType;
2250 return FAMILY_DONTKNOW;
2253 // -------------------------------------------------------------------------
2255 OString PrintFontManager::getAfmFile( PrintFont* pFont ) const
2257 OString aMetricPath;
2258 if( pFont )
2260 switch( pFont->m_eType )
2262 case fonttype::Type1:
2264 Type1FontFile* pPSFont = static_cast< Type1FontFile* >(pFont);
2265 aMetricPath = getDirectory( pPSFont->m_nDirectory );
2266 aMetricPath += "/";
2267 aMetricPath += pPSFont->m_aMetricFile;
2269 break;
2270 case fonttype::Builtin:
2272 BuiltinFont* pBuiltinFont = static_cast< BuiltinFont* >(pFont);
2273 aMetricPath = getDirectory( pBuiltinFont->m_nDirectory );
2274 aMetricPath += "/";
2275 aMetricPath += pBuiltinFont->m_aMetricFile;
2277 break;
2278 default: break;
2281 return aMetricPath;
2284 // -------------------------------------------------------------------------
2286 OString PrintFontManager::getFontFile( PrintFont* pFont ) const
2288 OString aPath;
2290 if( pFont && pFont->m_eType == fonttype::Type1 )
2292 Type1FontFile* pPSFont = static_cast< Type1FontFile* >(pFont);
2293 ::boost::unordered_map< int, OString >::const_iterator it = m_aAtomToDir.find( pPSFont->m_nDirectory );
2294 aPath = it->second;
2295 aPath += "/";
2296 aPath += pPSFont->m_aFontFile;
2298 else if( pFont && pFont->m_eType == fonttype::TrueType )
2300 TrueTypeFontFile* pTTFont = static_cast< TrueTypeFontFile* >(pFont);
2301 ::boost::unordered_map< int, OString >::const_iterator it = m_aAtomToDir.find( pTTFont->m_nDirectory );
2302 aPath = it->second;
2303 aPath += "/";
2304 aPath += pTTFont->m_aFontFile;
2306 return aPath;
2309 // -------------------------------------------------------------------------
2311 const OUString& PrintFontManager::getPSName( fontID nFontID ) const
2313 PrintFont* pFont = getFont( nFontID );
2314 if( pFont && pFont->m_nPSName == 0 )
2316 if( pFont->m_eType == fonttype::TrueType )
2317 analyzeTrueTypeFile( pFont );
2320 return m_pAtoms->getString( ATOM_PSNAME, pFont ? pFont->m_nPSName : INVALID_ATOM );
2323 // -------------------------------------------------------------------------
2325 int PrintFontManager::getFontAscend( fontID nFontID ) const
2327 PrintFont* pFont = getFont( nFontID );
2328 if( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
2330 // might be a truetype font not yet analyzed
2331 if( pFont->m_eType == fonttype::TrueType )
2332 analyzeTrueTypeFile( pFont );
2333 else if( pFont->m_eType == fonttype::Type1 || pFont->m_eType == fonttype::Builtin )
2334 pFont->readAfmMetrics( m_pAtoms, false, true );
2336 return pFont->m_nAscend;
2339 // -------------------------------------------------------------------------
2341 int PrintFontManager::getFontDescend( fontID nFontID ) const
2343 PrintFont* pFont = getFont( nFontID );
2344 if( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
2346 // might be a truetype font not yet analyzed
2347 if( pFont->m_eType == fonttype::TrueType )
2348 analyzeTrueTypeFile( pFont );
2349 else if( pFont->m_eType == fonttype::Type1 || pFont->m_eType == fonttype::Builtin )
2350 pFont->readAfmMetrics( m_pAtoms, false, true );
2352 return pFont->m_nDescend;
2355 // -------------------------------------------------------------------------
2357 void PrintFontManager::hasVerticalSubstitutions( fontID nFontID,
2358 const sal_Unicode* pCharacters, int nCharacters, bool* pHasSubst ) const
2360 PrintFont* pFont = getFont( nFontID );
2361 if( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
2363 // might be a truetype font not yet analyzed
2364 if( pFont->m_eType == fonttype::TrueType )
2365 analyzeTrueTypeFile( pFont );
2368 if( ! pFont->m_bHaveVerticalSubstitutedGlyphs )
2369 memset( pHasSubst, 0, sizeof(bool)*nCharacters );
2370 else
2372 for( int i = 0; i < nCharacters; i++ )
2374 sal_Unicode code = pCharacters[i];
2375 if( ! pFont->m_pMetrics ||
2376 ! ( pFont->m_pMetrics->m_aPages[ code >> 11 ] & ( 1 << ( ( code >> 8 ) & 7 ) ) ) )
2377 pFont->queryMetricPage( code >> 8, m_pAtoms );
2378 ::boost::unordered_map< sal_Unicode, bool >::const_iterator it = pFont->m_pMetrics->m_bVerticalSubstitutions.find( code );
2379 pHasSubst[i] = it != pFont->m_pMetrics->m_bVerticalSubstitutions.end();
2384 // -------------------------------------------------------------------------
2386 const ::std::list< KernPair >& PrintFontManager::getKernPairs( fontID nFontID, bool bVertical ) const
2388 static ::std::list< KernPair > aEmpty;
2390 PrintFont* pFont = getFont( nFontID );
2391 if( ! pFont )
2392 return aEmpty;
2394 if( ! pFont->m_pMetrics || ! pFont->m_pMetrics->m_bKernPairsQueried )
2395 pFont->queryMetricPage( 0, m_pAtoms );
2396 if( ! pFont->m_pMetrics || ! pFont->m_pMetrics->m_bKernPairsQueried )
2397 return aEmpty;
2398 return bVertical ? pFont->m_pMetrics->m_aYKernPairs : pFont->m_pMetrics->m_aXKernPairs;
2401 // -------------------------------------------------------------------------
2403 bool PrintFontManager::isFontDownloadingAllowedForPrinting( fontID nFont ) const
2405 static const char* pEnable = getenv( "PSPRINT_ENABLE_TTF_COPYRIGHTAWARENESS" );
2406 bool bRet = true;
2408 if( pEnable && *pEnable )
2410 PrintFont* pFont = getFont( nFont );
2411 if( pFont && pFont->m_eType == fonttype::TrueType )
2413 TrueTypeFontFile* pTTFontFile = static_cast<TrueTypeFontFile*>(pFont);
2414 if( pTTFontFile->m_nTypeFlags & TYPEFLAG_INVALID )
2416 TrueTypeFont* pTTFont = NULL;
2417 OString aFile = getFontFile( pFont );
2418 if( OpenTTFontFile( aFile.getStr(), pTTFontFile->m_nCollectionEntry, &pTTFont ) == SF_OK )
2420 // get type flags
2421 TTGlobalFontInfo aInfo;
2422 GetTTGlobalFontInfo( pTTFont, & aInfo );
2423 pTTFontFile->m_nTypeFlags = (unsigned int)aInfo.typeFlags;
2424 CloseTTFont( pTTFont );
2428 unsigned int nCopyrightFlags = pTTFontFile->m_nTypeFlags & TYPEFLAG_COPYRIGHT_MASK;
2430 // http://www.microsoft.com/typography/tt/ttf_spec/ttch02.doc
2431 // Font embedding is allowed if not restricted completely (only bit 1 set).
2432 // Preview&Print (bit 2), Editable (bit 3) or Installable (==0) fonts are ok.
2433 bRet = ( nCopyrightFlags & 0x02 ) != 0x02;
2436 return bRet;
2439 // -------------------------------------------------------------------------
2441 bool PrintFontManager::getMetrics( fontID nFontID, const sal_Unicode* pString, int nLen, CharacterMetric* pArray, bool bVertical ) const
2443 PrintFont* pFont = getFont( nFontID );
2444 if( ! pFont )
2445 return false;
2447 if( ( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
2448 || ! pFont->m_pMetrics || pFont->m_pMetrics->isEmpty()
2451 // might be a font not yet analyzed
2452 if( pFont->m_eType == fonttype::Type1 || pFont->m_eType == fonttype::Builtin )
2453 pFont->readAfmMetrics( m_pAtoms, false, false );
2454 else if( pFont->m_eType == fonttype::TrueType )
2455 analyzeTrueTypeFile( pFont );
2458 for( int i = 0; i < nLen; i++ )
2460 if( ! pFont->m_pMetrics ||
2461 ! ( pFont->m_pMetrics->m_aPages[ pString[i] >> 11 ] & ( 1 << ( ( pString[i] >> 8 ) & 7 ) ) ) )
2462 pFont->queryMetricPage( pString[i] >> 8, m_pAtoms );
2463 pArray[i].width = pArray[i].height = -1;
2464 if( pFont->m_pMetrics )
2466 int effectiveCode = pString[i];
2467 effectiveCode |= bVertical ? 1 << 16 : 0;
2468 ::boost::unordered_map< int, CharacterMetric >::const_iterator it =
2469 pFont->m_pMetrics->m_aMetrics.find( effectiveCode );
2470 // if no vertical metrics are available assume rotated horizontal metrics
2471 if( bVertical && (it == pFont->m_pMetrics->m_aMetrics.end()) )
2472 it = pFont->m_pMetrics->m_aMetrics.find( pString[i] );
2473 // the character metrics are in it->second
2474 if( it != pFont->m_pMetrics->m_aMetrics.end() )
2475 pArray[ i ] = it->second;
2479 return true;
2482 // -------------------------------------------------------------------------
2484 bool PrintFontManager::getMetrics( fontID nFontID, sal_Unicode minCharacter, sal_Unicode maxCharacter, CharacterMetric* pArray, bool bVertical ) const
2486 OSL_PRECOND(minCharacter <= maxCharacter, "invalid char. range");
2487 if (minCharacter > maxCharacter)
2488 return false;
2490 PrintFont* pFont = getFont( nFontID );
2491 if( ! pFont )
2492 return false;
2494 if( ( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
2495 || ! pFont->m_pMetrics || pFont->m_pMetrics->isEmpty()
2498 // might be a font not yet analyzed
2499 if( pFont->m_eType == fonttype::Type1 || pFont->m_eType == fonttype::Builtin )
2500 pFont->readAfmMetrics( m_pAtoms, false, false );
2501 else if( pFont->m_eType == fonttype::TrueType )
2502 analyzeTrueTypeFile( pFont );
2505 sal_Unicode code = minCharacter;
2508 if( ! pFont->m_pMetrics ||
2509 ! ( pFont->m_pMetrics->m_aPages[ code >> 11 ] & ( 1 << ( ( code >> 8 ) & 7 ) ) ) )
2510 pFont->queryMetricPage( code >> 8, m_pAtoms );
2511 pArray[ code - minCharacter ].width = -1;
2512 pArray[ code - minCharacter ].height = -1;
2513 if( pFont->m_pMetrics )
2515 int effectiveCode = code;
2516 effectiveCode |= bVertical ? 1 << 16 : 0;
2517 ::boost::unordered_map< int, CharacterMetric >::const_iterator it =
2518 pFont->m_pMetrics->m_aMetrics.find( effectiveCode );
2519 // if no vertical metrics are available assume rotated horizontal metrics
2520 if( bVertical && (it == pFont->m_pMetrics->m_aMetrics.end()) )
2521 it = pFont->m_pMetrics->m_aMetrics.find( code );
2522 // the character metrics are in it->second
2523 if( it != pFont->m_pMetrics->m_aMetrics.end() )
2524 pArray[ code - minCharacter ] = it->second;
2526 } while( code++ != maxCharacter );
2528 return true;
2531 // -------------------------------------------------------------------------
2533 // TODO: move most of this stuff into the central font-subsetting code
2534 bool PrintFontManager::createFontSubset(
2535 FontSubsetInfo& rInfo,
2536 fontID nFont,
2537 const OUString& rOutFile,
2538 sal_Int32* pGlyphIDs,
2539 sal_uInt8* pNewEncoding,
2540 sal_Int32* pWidths,
2541 int nGlyphs,
2542 bool bVertical
2545 PrintFont* pFont = getFont( nFont );
2546 if( !pFont )
2547 return false;
2549 switch( pFont->m_eType )
2551 case psp::fonttype::TrueType: rInfo.m_nFontType = FontSubsetInfo::SFNT_TTF; break;
2552 case psp::fonttype::Type1: rInfo.m_nFontType = FontSubsetInfo::ANY_TYPE1; break;
2553 default:
2554 return false;
2556 // TODO: remove when Type1 subsetting gets implemented
2557 if( pFont->m_eType != fonttype::TrueType )
2558 return false;
2560 // reshuffle array of requested glyphs to make sure glyph0==notdef
2561 sal_uInt8 pEnc[256];
2562 sal_uInt16 pGID[256];
2563 sal_uInt8 pOldIndex[256];
2564 memset( pEnc, 0, sizeof( pEnc ) );
2565 memset( pGID, 0, sizeof( pGID ) );
2566 memset( pOldIndex, 0, sizeof( pOldIndex ) );
2567 if( nGlyphs > 256 )
2568 return false;
2569 int nChar = 1;
2570 for( int i = 0; i < nGlyphs; i++ )
2572 if( pNewEncoding[i] == 0 )
2574 pOldIndex[ 0 ] = i;
2576 else
2578 DBG_ASSERT( !(pGlyphIDs[i] & 0x007f0000), "overlong glyph id" );
2579 DBG_ASSERT( (int)pNewEncoding[i] < nGlyphs, "encoding wrong" );
2580 DBG_ASSERT( pEnc[pNewEncoding[i]] == 0 && pGID[pNewEncoding[i]] == 0, "duplicate encoded glyph" );
2581 pEnc[ pNewEncoding[i] ] = pNewEncoding[i];
2582 pGID[ pNewEncoding[i] ] = (sal_uInt16)pGlyphIDs[ i ];
2583 pOldIndex[ pNewEncoding[i] ] = i;
2584 nChar++;
2587 nGlyphs = nChar; // either input value or increased by one
2589 // prepare system name for read access for subset source file
2590 // TODO: since this file is usually already mmapped there is no need to open it again
2591 const OString aFromFile = getFontFile( pFont );
2593 TrueTypeFont* pTTFont = NULL; // TODO: rename to SfntFont
2594 TrueTypeFontFile* pTTFontFile = static_cast< TrueTypeFontFile* >(pFont);
2595 if( OpenTTFontFile( aFromFile.getStr(), pTTFontFile->m_nCollectionEntry, &pTTFont ) != SF_OK )
2596 return false;
2598 // prepare system name for write access for subset file target
2599 OUString aSysPath;
2600 if( osl_File_E_None != osl_getSystemPathFromFileURL( rOutFile.pData, &aSysPath.pData ) )
2601 return false;
2602 const rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
2603 const OString aToFile( OUStringToOString( aSysPath, aEncoding ) );
2605 // do CFF subsetting if possible
2606 int nCffLength = 0;
2607 const sal_uInt8* pCffBytes = NULL;
2608 if( GetSfntTable( pTTFont, O_CFF, &pCffBytes, &nCffLength ) )
2610 rInfo.LoadFont( FontSubsetInfo::CFF_FONT, pCffBytes, nCffLength );
2611 #if 1 // TODO: remove 16bit->long conversion when related methods handle non-16bit glyphids
2612 long aRequestedGlyphs[256];
2613 for( int i = 0; i < nGlyphs; ++i )
2614 aRequestedGlyphs[i] = pGID[i];
2615 #endif
2616 // create subset file at requested path
2617 FILE* pOutFile = fopen( aToFile.getStr(), "wb" );
2618 // create font subset
2619 const char* pGlyphSetName = NULL; // TODO: better name?
2620 const bool bOK = rInfo.CreateFontSubset(
2621 FontSubsetInfo::TYPE1_PFB,
2622 pOutFile, pGlyphSetName,
2623 aRequestedGlyphs, pEnc, nGlyphs, pWidths );
2624 fclose( pOutFile );
2625 // cleanup before early return
2626 CloseTTFont( pTTFont );
2627 return bOK;
2630 // do TTF->Type42 or Type3 subsetting
2631 // fill in font info
2632 psp::PrintFontInfo aFontInfo;
2633 if( ! getFontInfo( nFont, aFontInfo ) )
2634 return false;
2636 rInfo.m_nAscent = aFontInfo.m_nAscend;
2637 rInfo.m_nDescent = aFontInfo.m_nDescend;
2638 rInfo.m_aPSName = getPSName( nFont );
2640 int xMin, yMin, xMax, yMax;
2641 getFontBoundingBox( nFont, xMin, yMin, xMax, yMax );
2642 rInfo.m_aFontBBox = Rectangle( Point( xMin, yMin ), Size( xMax-xMin, yMax-yMin ) );
2643 rInfo.m_nCapHeight = yMax; // Well ...
2645 // fill in glyph advance widths
2646 TTSimpleGlyphMetrics* pMetrics = GetTTSimpleGlyphMetrics( pTTFont,
2647 pGID,
2648 nGlyphs,
2649 bVertical ? 1 : 0 );
2650 if( pMetrics )
2652 for( int i = 0; i < nGlyphs; i++ )
2653 pWidths[pOldIndex[i]] = pMetrics[i].adv;
2654 free( pMetrics );
2656 else
2658 CloseTTFont( pTTFont );
2659 return false;
2662 bool bSuccess = ( SF_OK == CreateTTFromTTGlyphs( pTTFont,
2663 aToFile.getStr(),
2664 pGID,
2665 pEnc,
2666 nGlyphs,
2668 NULL,
2669 0 ) );
2670 CloseTTFont( pTTFont );
2672 return bSuccess;
2675 void PrintFontManager::getGlyphWidths( fontID nFont,
2676 bool bVertical,
2677 std::vector< sal_Int32 >& rWidths,
2678 std::map< sal_Unicode, sal_uInt32 >& rUnicodeEnc )
2680 PrintFont* pFont = getFont( nFont );
2681 if( !pFont ||
2682 (pFont->m_eType != fonttype::TrueType && pFont->m_eType != fonttype::Type1) )
2683 return;
2684 if( pFont->m_eType == fonttype::TrueType )
2686 TrueTypeFont* pTTFont = NULL;
2687 TrueTypeFontFile* pTTFontFile = static_cast< TrueTypeFontFile* >(pFont);
2688 OString aFromFile = getFontFile( pFont );
2689 if( OpenTTFontFile( aFromFile.getStr(), pTTFontFile->m_nCollectionEntry, &pTTFont ) != SF_OK )
2690 return;
2691 int nGlyphs = GetTTGlyphCount( pTTFont );
2692 if( nGlyphs > 0 )
2694 rWidths.resize(nGlyphs);
2695 std::vector<sal_uInt16> aGlyphIds(nGlyphs);
2696 for( int i = 0; i < nGlyphs; i++ )
2697 aGlyphIds[i] = sal_uInt16(i);
2698 TTSimpleGlyphMetrics* pMetrics = GetTTSimpleGlyphMetrics( pTTFont,
2699 &aGlyphIds[0],
2700 nGlyphs,
2701 bVertical ? 1 : 0 );
2702 if( pMetrics )
2704 for( int i = 0; i< nGlyphs; i++ )
2705 rWidths[i] = pMetrics[i].adv;
2706 free( pMetrics );
2707 rUnicodeEnc.clear();
2710 // fill the unicode map
2711 // TODO: isn't this map already available elsewhere in the fontmanager?
2712 const sal_uInt8* pCmapData = NULL;
2713 int nCmapSize = 0;
2714 if( GetSfntTable( pTTFont, O_cmap, &pCmapData, &nCmapSize ) )
2716 CmapResult aCmapResult;
2717 if( ParseCMAP( pCmapData, nCmapSize, aCmapResult ) )
2719 const ImplFontCharMap aCharMap( aCmapResult );
2720 for( sal_uInt32 cOld = 0;;)
2722 // get next unicode covered by font
2723 const sal_uInt32 c = aCharMap.GetNextChar( cOld );
2724 if( c == cOld )
2725 break;
2726 cOld = c;
2727 #if 1 // TODO: remove when sal_Unicode covers all of unicode
2728 if( c > (sal_Unicode)~0 )
2729 break;
2730 #endif
2731 // get the matching glyph index
2732 const sal_uInt32 nGlyphId = aCharMap.GetGlyphIndex( c );
2733 // update the requested map
2734 rUnicodeEnc[ (sal_Unicode)c ] = nGlyphId;
2739 CloseTTFont( pTTFont );
2741 else if( pFont->m_eType == fonttype::Type1 )
2743 if( ! pFont->m_aEncodingVector.size() )
2744 pFont->readAfmMetrics( m_pAtoms, true, true );
2745 if( pFont->m_pMetrics )
2747 rUnicodeEnc.clear();
2748 rWidths.clear();
2749 rWidths.reserve( pFont->m_pMetrics->m_aMetrics.size() );
2750 for( boost::unordered_map< int, CharacterMetric >::const_iterator it =
2751 pFont->m_pMetrics->m_aMetrics.begin();
2752 it != pFont->m_pMetrics->m_aMetrics.end(); ++it )
2754 if( (it->first & 0x00010000) == 0 || bVertical )
2756 rUnicodeEnc[ sal_Unicode(it->first & 0x0000ffff) ] = sal_uInt32(rWidths.size());
2757 rWidths.push_back( it->second.width );
2764 // -------------------------------------------------------------------------
2766 const std::map< sal_Unicode, sal_Int32 >* PrintFontManager::getEncodingMap( fontID nFont, const std::map< sal_Unicode, OString >** pNonEncoded ) const
2768 PrintFont* pFont = getFont( nFont );
2769 if( !pFont ||
2770 (pFont->m_eType != fonttype::Type1 && pFont->m_eType != fonttype::Builtin)
2772 return NULL;
2774 if( ! pFont->m_aEncodingVector.size() )
2775 pFont->readAfmMetrics( m_pAtoms, true, true );
2777 if( pNonEncoded )
2778 *pNonEncoded = pFont->m_aNonEncoded.size() ? &pFont->m_aNonEncoded : NULL;
2780 return pFont->m_aEncodingVector.size() ? &pFont->m_aEncodingVector : NULL;
2783 // -------------------------------------------------------------------------
2785 std::list< OString > PrintFontManager::getAdobeNameFromUnicode( sal_Unicode aChar ) const
2787 std::pair< boost::unordered_multimap< sal_Unicode, OString >::const_iterator,
2788 boost::unordered_multimap< sal_Unicode, OString >::const_iterator > range
2789 = m_aUnicodeToAdobename.equal_range( aChar );
2791 std::list< OString > aRet;
2792 for( ; range.first != range.second; ++range.first )
2793 aRet.push_back( range.first->second );
2795 if( aRet.begin() == aRet.end() && aChar != 0 )
2797 sal_Char aBuf[8];
2798 sal_Int32 nChars = snprintf( (char*)aBuf, sizeof( aBuf ), "uni%.4hX", aChar );
2799 aRet.push_back( OString( aBuf, nChars ) );
2802 return aRet;
2805 // -------------------------------------------------------------------------
2806 std::list< sal_Unicode > PrintFontManager::getUnicodeFromAdobeName( const OString& rName ) const
2808 std::pair< boost::unordered_multimap< OString, sal_Unicode, OStringHash >::const_iterator,
2809 boost::unordered_multimap< OString, sal_Unicode, OStringHash >::const_iterator > range
2810 = m_aAdobenameToUnicode.equal_range( rName );
2812 std::list< sal_Unicode > aRet;
2813 for( ; range.first != range.second; ++range.first )
2814 aRet.push_back( range.first->second );
2816 if( aRet.begin() == aRet.end() )
2818 if( rName.getLength() == 7 && rName.indexOf( "uni" ) == 0 )
2820 sal_Unicode aCode = (sal_Unicode)rName.copy( 3 ).toInt32( 16 );
2821 aRet.push_back( aCode );
2825 return aRet;
2828 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */