Branch libreoffice-5-0-4
[LibreOffice.git] / vcl / generic / fontmanager / fontmanager.cxx
blob87027d41e8cb1835fe425c53e230b4a641189e3c
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 "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/applelangid.hxx"
52 #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 <algorithm>
65 #include <set>
66 #include <unordered_set>
68 #include "adobeenc.tab"
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 using namespace vcl;
80 using namespace utl;
81 using namespace psp;
82 using namespace osl;
83 using namespace com::sun::star::uno;
84 using namespace com::sun::star::beans;
85 using namespace com::sun::star::lang;
88 * static helpers
91 inline sal_uInt16 getUInt16BE( const sal_uInt8*& pBuffer )
93 sal_uInt16 nRet = (sal_uInt16)pBuffer[1] |
94 (((sal_uInt16)pBuffer[0]) << 8);
95 pBuffer+=2;
96 return nRet;
99 static FontWeight parseWeight( const OString& rWeight )
101 FontWeight eWeight = WEIGHT_DONTKNOW;
102 if (rWeight.indexOf("bold") != -1)
104 if (rWeight.indexOf("emi") != -1) // semi, demi
105 eWeight = WEIGHT_SEMIBOLD;
106 else if (rWeight.indexOf("ultra") != -1)
107 eWeight = WEIGHT_ULTRABOLD;
108 else
109 eWeight = WEIGHT_BOLD;
111 else if (rWeight.indexOf("heavy") != -1)
112 eWeight = WEIGHT_BOLD;
113 else if (rWeight.indexOf("light") != -1)
115 if (rWeight.indexOf("emi") != -1) // semi, demi
116 eWeight = WEIGHT_SEMILIGHT;
117 else if (rWeight.indexOf("ultra") != -1)
118 eWeight = WEIGHT_ULTRALIGHT;
119 else
120 eWeight = WEIGHT_LIGHT;
122 else if (rWeight.indexOf("black") != -1)
123 eWeight = WEIGHT_BLACK;
124 else if (rWeight == "demi")
125 eWeight = WEIGHT_SEMIBOLD;
126 else if ((rWeight == "book") ||
127 (rWeight == "semicondensed"))
128 eWeight = WEIGHT_LIGHT;
129 else if ((rWeight == "medium") || (rWeight == "roman"))
130 eWeight = WEIGHT_MEDIUM;
131 else
132 eWeight = WEIGHT_NORMAL;
133 return eWeight;
137 * PrintFont implementations
139 PrintFontManager::PrintFont::PrintFont( fonttype::type eType ) :
140 m_eType( eType ),
141 m_nFamilyName( 0 ),
142 m_nPSName( 0 ),
143 m_eItalic( ITALIC_DONTKNOW ),
144 m_eWidth( WIDTH_DONTKNOW ),
145 m_eWeight( WEIGHT_DONTKNOW ),
146 m_ePitch( PITCH_DONTKNOW ),
147 m_aEncoding( RTL_TEXTENCODING_DONTKNOW ),
148 m_bFontEncodingOnly( false ),
149 m_pMetrics( NULL ),
150 m_nAscend( 0 ),
151 m_nDescend( 0 ),
152 m_nLeading( 0 ),
153 m_nXMin( 0 ),
154 m_nYMin( 0 ),
155 m_nXMax( 0 ),
156 m_nYMax( 0 ),
157 m_bHaveVerticalSubstitutedGlyphs( false ),
158 m_bUserOverride( false )
162 PrintFontManager::PrintFont::~PrintFont()
164 delete m_pMetrics;
167 PrintFontManager::Type1FontFile::~Type1FontFile()
171 PrintFontManager::TrueTypeFontFile::TrueTypeFontFile()
172 : PrintFont( fonttype::TrueType )
173 , m_nDirectory( 0 )
174 , m_nCollectionEntry( 0 )
175 , m_nTypeFlags( TYPEFLAG_INVALID )
178 PrintFontManager::TrueTypeFontFile::~TrueTypeFontFile()
182 bool PrintFontManager::Type1FontFile::queryMetricPage( int /*nPage*/, MultiAtomProvider* pProvider )
184 return readAfmMetrics( pProvider, false, false );
187 bool PrintFontManager::TrueTypeFontFile::queryMetricPage( int nPage, MultiAtomProvider* /*pProvider*/ )
189 bool bSuccess = false;
191 OString aFile( PrintFontManager::get().getFontFile( this ) );
193 TrueTypeFont* pTTFont = NULL;
195 if( OpenTTFontFile( aFile.getStr(), m_nCollectionEntry, &pTTFont ) == SF_OK )
197 if( ! m_pMetrics )
199 m_pMetrics = new PrintFontMetrics;
200 memset (m_pMetrics->m_aPages, 0, sizeof(m_pMetrics->m_aPages));
202 m_pMetrics->m_aPages[ nPage/8 ] |= (1 << ( nPage & 7 ));
203 int i;
204 sal_uInt16 table[256], table_vert[256];
206 for( i = 0; i < 256; i++ )
207 table[ i ] = 256*nPage + i;
209 int nCharacters = nPage < 255 ? 256 : 254;
210 MapString( pTTFont, table, nCharacters, NULL, false );
211 TTSimpleGlyphMetrics* pMetrics = GetTTSimpleCharMetrics( pTTFont, nPage*256, nCharacters, false );
212 if( pMetrics )
214 for( i = 0; i < nCharacters; i++ )
216 if( table[i] )
218 CharacterMetric& rChar = m_pMetrics->m_aMetrics[ nPage*256 + i ];
219 rChar.width = pMetrics[ i ].adv;
220 rChar.height = m_aGlobalMetricX.height;
224 free( pMetrics );
227 for( i = 0; i < 256; i++ )
228 table_vert[ i ] = 256*nPage + i;
229 MapString( pTTFont, table_vert, nCharacters, NULL, true );
230 pMetrics = GetTTSimpleCharMetrics( pTTFont, nPage*256, nCharacters, true );
231 if( pMetrics )
233 for( i = 0; i < nCharacters; i++ )
235 if( table_vert[i] )
237 CharacterMetric& rChar = m_pMetrics->m_aMetrics[ nPage*256 + i + ( 1 << 16 ) ];
238 rChar.width = m_aGlobalMetricY.width;
239 rChar.height = pMetrics[ i ].adv;
240 if( table_vert[i] != table[i] )
241 m_pMetrics->m_bVerticalSubstitutions[ nPage*256 + i ] = true;
244 free( pMetrics );
246 CloseTTFont( pTTFont );
247 bSuccess = true;
249 return bSuccess;
252 /* #i73387# There seem to be fonts with a rather unwell chosen family name
253 * consider e.g. "Helvetica Narrow" which defines its family as "Helvetica"
254 * It can really only be distinguished by its PSName and FullName. Both of
255 * which are not user presentable in OOo. So replace it by something sensible.
257 * If other fonts feature this behaviour, insert them to the map.
259 static bool familyNameOverride( const OUString& i_rPSname, OUString& o_rFamilyName )
261 static std::unordered_map< OUString, OUString, OUStringHash > aPSNameToFamily( 16 );
262 if( aPSNameToFamily.empty() ) // initialization
264 aPSNameToFamily[ "Helvetica-Narrow" ] = "Helvetica Narrow";
265 aPSNameToFamily[ "Helvetica-Narrow-Bold" ] = "Helvetica Narrow";
266 aPSNameToFamily[ "Helvetica-Narrow-BoldOblique" ] = "Helvetica Narrow";
267 aPSNameToFamily[ "Helvetica-Narrow-Oblique" ] = "Helvetica Narrow";
269 std::unordered_map<OUString,OUString,OUStringHash>::const_iterator it =
270 aPSNameToFamily.find( i_rPSname );
271 bool bReplaced = (it != aPSNameToFamily.end() );
272 if( bReplaced )
273 o_rFamilyName = it->second;
274 return bReplaced;
277 bool PrintFontManager::PrintFont::readAfmMetrics( MultiAtomProvider* pProvider, bool bFillEncodingvector, bool bOnlyGlobalAttributes )
279 PrintFontManager& rManager( PrintFontManager::get() );
280 const OString& rFileName = rManager.getAfmFile( this );
282 FontInfo* pInfo = NULL;
283 parseFile( rFileName.getStr(), &pInfo, P_ALL );
284 if( ! pInfo || ! pInfo->numOfChars )
286 if( pInfo )
287 freeFontInfo( pInfo );
288 return false;
291 m_aEncodingVector.clear();
292 m_aEncodingVectorPriority.clear();
293 // fill in global info
295 // PSName
296 OUString aPSName( OStringToOUString( pInfo->gfi->fontName, RTL_TEXTENCODING_ISO_8859_1 ) );
297 m_nPSName = pProvider->getAtom( ATOM_PSNAME, aPSName, true );
299 // family name (if not already set)
300 OUString aFamily;
301 if( ! m_nFamilyName )
303 aFamily = OStringToOUString( pInfo->gfi->familyName, RTL_TEXTENCODING_ISO_8859_1 );
304 if( aFamily.isEmpty() )
306 aFamily = OStringToOUString( pInfo->gfi->fontName, RTL_TEXTENCODING_ISO_8859_1 );
307 sal_Int32 nIndex = 0;
308 aFamily = aFamily.getToken( 0, '-', nIndex );
310 familyNameOverride( aPSName, aFamily );
311 m_nFamilyName = pProvider->getAtom( ATOM_FAMILYNAME, aFamily, true );
313 else
314 aFamily = pProvider->getString( ATOM_FAMILYNAME, m_nFamilyName );
316 // style name: if fullname begins with family name
317 // interpret the rest of fullname as style
318 if( m_aStyleName.isEmpty() && pInfo->gfi->fullName && *pInfo->gfi->fullName )
320 OUString aFullName( OStringToOUString( pInfo->gfi->fullName, RTL_TEXTENCODING_ISO_8859_1 ) );
321 if( aFullName.startsWith( aFamily ) )
322 m_aStyleName = WhitespaceToSpace( aFullName.copy( aFamily.getLength() ) );
325 // italic
326 if( pInfo->gfi->italicAngle > 0 )
327 m_eItalic = ITALIC_OBLIQUE;
328 else if( pInfo->gfi->italicAngle < 0 )
329 m_eItalic = ITALIC_NORMAL;
330 else
331 m_eItalic = ITALIC_NONE;
333 // weight
334 OString aWeight( pInfo->gfi->weight );
335 m_eWeight = parseWeight( aWeight.toAsciiLowerCase() );
337 // pitch
338 m_ePitch = pInfo->gfi->isFixedPitch ? PITCH_FIXED : PITCH_VARIABLE;
340 // encoding - only set if unknown
341 int nAdobeEncoding = 0;
342 if( pInfo->gfi->encodingScheme )
344 if( !strcmp( pInfo->gfi->encodingScheme, "AdobeStandardEncoding" ) )
345 nAdobeEncoding = 1;
346 else if( !strcmp( pInfo->gfi->encodingScheme, "ISO10646-1" ) )
348 nAdobeEncoding = 1;
349 m_aEncoding = RTL_TEXTENCODING_UNICODE;
351 else if( !strcmp( pInfo->gfi->encodingScheme, "Symbol") )
352 nAdobeEncoding = 2;
353 else if( !strcmp( pInfo->gfi->encodingScheme, "FontSpecific") )
354 nAdobeEncoding = 3;
356 if( m_aEncoding == RTL_TEXTENCODING_DONTKNOW )
357 m_aEncoding = nAdobeEncoding == 1 ?
358 RTL_TEXTENCODING_ADOBE_STANDARD : RTL_TEXTENCODING_SYMBOL;
360 else if( m_aEncoding == RTL_TEXTENCODING_DONTKNOW )
361 m_aEncoding = RTL_TEXTENCODING_ADOBE_STANDARD;
363 // try to parse the font name and decide whether it might be a
364 // japanese font. Who invented this PITA ?
365 OUString aPSNameLastToken( aPSName.copy( aPSName.lastIndexOf( '-' )+1 ) );
366 if( aPSNameLastToken == "H" ||
367 aPSNameLastToken == "V" )
369 static const char* pEncs[] =
371 "EUC",
372 "RKSJ",
373 "SJ"
375 static const rtl_TextEncoding aEncs[] =
377 RTL_TEXTENCODING_EUC_JP,
378 RTL_TEXTENCODING_SHIFT_JIS,
379 RTL_TEXTENCODING_JIS_X_0208
382 for( unsigned int enc = 0; enc < SAL_N_ELEMENTS( aEncs ) && m_aEncoding == RTL_TEXTENCODING_DONTKNOW; enc++ )
384 sal_Int32 nIndex = 0, nOffset = 1;
387 OUString aToken( aPSName.getToken( nOffset, '-', nIndex ) );
388 if( nIndex == -1 )
389 break;
390 nOffset = 0;
391 if( aToken.equalsAscii( pEncs[enc] ) )
393 m_aEncoding = aEncs[ enc ];
394 m_bFontEncodingOnly = true;
396 } while( nIndex != -1 );
399 // default is jis
400 if( m_aEncoding == RTL_TEXTENCODING_DONTKNOW )
401 m_aEncoding = RTL_TEXTENCODING_JIS_X_0208;
402 #if OSL_DEBUG_LEVEL > 1
403 fprintf( stderr, "Encoding %d for %s\n", m_aEncoding, pInfo->gfi->fontName );
404 #endif
407 // #i37313# check if Fontspecific is not rather some character encoding
408 if( nAdobeEncoding == 3 && m_aEncoding == RTL_TEXTENCODING_SYMBOL )
410 bool bYFound = false;
411 bool bQFound = false;
412 CharMetricInfo* pChar = pInfo->cmi;
413 for( int j = 0; j < pInfo->numOfChars && ! (bYFound && bQFound); j++ )
415 if( pChar[j].name )
417 if( pChar[j].name[0] == 'Y' && pChar[j].name[1] == 0 )
418 bYFound = true;
419 else if( pChar[j].name[0] == 'Q' && pChar[j].name[1] == 0 )
420 bQFound = true;
423 if( bQFound && bYFound )
425 #if OSL_DEBUG_LEVEL > 1
426 fprintf( stderr, "setting FontSpecific font %s (file %s) to unicode\n",
427 pInfo->gfi->fontName,
428 rFileName.getStr()
430 #endif
431 nAdobeEncoding = 4;
432 m_aEncoding = RTL_TEXTENCODING_UNICODE;
433 bFillEncodingvector = false; // will be filled anyway, don't do the work twice
437 // ascend
438 m_nAscend = pInfo->gfi->fontBBox.ury;
440 // descend
441 // descends have opposite sign of our definition
442 m_nDescend = -pInfo->gfi->fontBBox.lly;
444 // fallback to ascender, descender
445 // interesting: the BBox seems to describe Ascender and Descender better
446 // as we understand it
447 if( m_nAscend == 0 )
448 m_nAscend = pInfo->gfi->ascender;
449 if( m_nDescend == 0)
450 m_nDescend = -pInfo->gfi->descender;
452 m_nLeading = m_nAscend + m_nDescend - 1000;
454 delete m_pMetrics;
455 m_pMetrics = new PrintFontMetrics;
456 // mark all pages as queried (or clear if only global font info queiried)
457 memset( m_pMetrics->m_aPages, bOnlyGlobalAttributes ? 0 : 0xff, sizeof( m_pMetrics->m_aPages ) );
459 m_aGlobalMetricX.width = m_aGlobalMetricY.width =
460 pInfo->gfi->charwidth ? pInfo->gfi->charwidth : pInfo->gfi->fontBBox.urx;
461 m_aGlobalMetricX.height = m_aGlobalMetricY.height =
462 pInfo->gfi->capHeight ? pInfo->gfi->capHeight : pInfo->gfi->fontBBox.ury;
464 m_nXMin = pInfo->gfi->fontBBox.llx;
465 m_nYMin = pInfo->gfi->fontBBox.lly;
466 m_nXMax = pInfo->gfi->fontBBox.urx;
467 m_nYMax = pInfo->gfi->fontBBox.ury;
469 if( bFillEncodingvector || !bOnlyGlobalAttributes )
471 // fill in character metrics
473 // first transform the character codes to unicode
474 // note: this only works with single byte encodings
475 sal_Unicode* pUnicodes = static_cast<sal_Unicode*>(alloca( pInfo->numOfChars * sizeof(sal_Unicode)));
476 CharMetricInfo* pChar = pInfo->cmi;
477 int i;
479 for( i = 0; i < pInfo->numOfChars; i++, pChar++ )
481 if( nAdobeEncoding == 4 )
483 if( pChar->name )
485 pUnicodes[i] = 0;
486 std::list< sal_Unicode > aCodes = rManager.getUnicodeFromAdobeName( pChar->name );
487 for( std::list< sal_Unicode >::const_iterator it = aCodes.begin(); it != aCodes.end(); ++it )
489 if( *it != 0 )
491 m_aEncodingVector[ *it ] = pChar->code;
492 if( pChar->code == -1 )
493 m_aNonEncoded[ *it ] = pChar->name;
494 if( ! pUnicodes[i] ) // map the first
495 pUnicodes[i] = *it;
500 else if( pChar->code != -1 )
502 if( nAdobeEncoding == 3 && m_aEncoding == RTL_TEXTENCODING_SYMBOL )
504 pUnicodes[i] = pChar->code + 0xf000;
505 if( bFillEncodingvector )
507 m_aEncodingVector[ pUnicodes[i] ] = pChar->code;
508 m_aEncodingVectorPriority.insert(pUnicodes[i]);
510 continue;
513 if( m_aEncoding == RTL_TEXTENCODING_UNICODE )
515 pUnicodes[i] = (sal_Unicode)pChar->code;
516 continue;
519 OStringBuffer aTranslate;
520 if( pChar->code & 0xff000000 )
521 aTranslate.append((char)(pChar->code >> 24));
522 if( pChar->code & 0xffff0000 )
523 aTranslate.append((char)((pChar->code & 0x00ff0000) >> 16));
524 if( pChar->code & 0xffffff00 )
525 aTranslate.append((char)((pChar->code & 0x0000ff00) >> 8 ));
526 aTranslate.append((char)(pChar->code & 0xff));
527 OUString aUni(OStringToOUString(aTranslate.makeStringAndClear(), m_aEncoding));
528 pUnicodes[i] = aUni.toChar();
530 else
531 pUnicodes[i] = 0;
534 // now fill in the character metrics
535 // parseAFM.cxx effectively only supports direction 0 (horizontal)
536 pChar = pInfo->cmi;
537 CharacterMetric aMetric;
538 for( i = 0; i < pInfo->numOfChars; i++, pChar++ )
540 if( pChar->code == -1 && ! pChar->name )
541 continue;
543 if( bFillEncodingvector && pChar->name )
545 std::list< sal_Unicode > aCodes = rManager.getUnicodeFromAdobeName( pChar->name );
546 for( std::list< sal_Unicode >::const_iterator it = aCodes.begin(); it != aCodes.end(); ++it )
548 if( *it != 0 )
550 m_aEncodingVector[ *it ] = pChar->code;
551 if( pChar->code == -1 )
552 m_aNonEncoded[ *it ] = pChar->name;
557 aMetric.width = pChar->wx ? pChar->wx : pChar->charBBox.urx;
558 aMetric.height = pChar->wy ? pChar->wy : pChar->charBBox.ury - pChar->charBBox.lly;
559 if( aMetric.width == 0 && aMetric.height == 0 )
560 // guess something for e.g. space
561 aMetric.width = m_aGlobalMetricX.width/4;
563 if( ( nAdobeEncoding == 0 ) ||
564 ( ( nAdobeEncoding == 3 ) && ( m_aEncoding != RTL_TEXTENCODING_SYMBOL ) ) )
566 if( pChar->code != -1 )
568 m_pMetrics->m_aMetrics[ pUnicodes[i] ] = aMetric;
569 if( bFillEncodingvector )
571 m_aEncodingVector[ pUnicodes[i] ] = pChar->code;
572 m_aEncodingVectorPriority.insert(pUnicodes[i]);
575 else if( pChar->name )
577 std::list< sal_Unicode > aCodes = rManager.getUnicodeFromAdobeName( pChar->name );
578 for( std::list< sal_Unicode >::const_iterator it = aCodes.begin(); it != aCodes.end(); ++it )
580 if( *it != 0 )
581 m_pMetrics->m_aMetrics[ *it ] = aMetric;
585 else if( nAdobeEncoding == 1 || nAdobeEncoding == 2 || nAdobeEncoding == 4)
587 if( pChar->name )
589 std::list< sal_Unicode > aCodes = rManager.getUnicodeFromAdobeName( pChar->name );
590 for( std::list< sal_Unicode >::const_iterator it = aCodes.begin(); it != aCodes.end(); ++it )
592 if( *it != 0 )
593 m_pMetrics->m_aMetrics[ *it ] = aMetric;
596 else if( pChar->code != -1 )
598 ::std::pair< std::unordered_multimap< sal_uInt8, sal_Unicode >::const_iterator,
599 std::unordered_multimap< sal_uInt8, sal_Unicode >::const_iterator >
600 aCodes = rManager.getUnicodeFromAdobeCode( pChar->code );
601 bool bFirst = true;
602 while( aCodes.first != aCodes.second )
604 if( (*aCodes.first).second != 0 )
606 m_pMetrics->m_aMetrics[ (*aCodes.first).second ] = aMetric;
607 if( bFillEncodingvector )
609 m_aEncodingVector[ (*aCodes.first).second ] = pChar->code;
610 if (bFirst) // arbitrarily prefer the first one
612 m_aEncodingVectorPriority.insert((*aCodes.first).second);
613 bFirst = false;
617 ++aCodes.first;
621 else if( nAdobeEncoding == 3 )
623 if( pChar->code != -1 )
625 sal_Unicode code = 0xf000 + pChar->code;
626 m_pMetrics->m_aMetrics[ code ] = aMetric;
627 // maybe should try to find the name in the convtabs ?
628 if( bFillEncodingvector )
630 m_aEncodingVector[ code ] = pChar->code;
631 m_aEncodingVectorPriority.insert(code);
638 freeFontInfo( pInfo );
639 return true;
643 * one instance only
645 PrintFontManager& PrintFontManager::get()
647 static PrintFontManager* pManager = NULL;
648 if( ! pManager )
650 static PrintFontManager theManager;
651 pManager = &theManager;
652 pManager->initialize();
654 return *pManager;
658 * the PrintFontManager
661 PrintFontManager::PrintFontManager()
662 : m_nNextFontID( 1 )
663 , m_pAtoms( new MultiAtomProvider() )
664 , m_nNextDirAtom( 1 )
665 , m_pFontCache( NULL )
667 for( unsigned int i = 0; i < SAL_N_ELEMENTS( aAdobeCodes ); i++ )
669 m_aUnicodeToAdobename.insert( std::unordered_multimap< sal_Unicode, OString >::value_type( aAdobeCodes[i].aUnicode, aAdobeCodes[i].pAdobename ) );
670 m_aAdobenameToUnicode.insert( std::unordered_multimap< OString, sal_Unicode, OStringHash >::value_type( aAdobeCodes[i].pAdobename, aAdobeCodes[i].aUnicode ) );
671 if( aAdobeCodes[i].aAdobeStandardCode )
673 m_aUnicodeToAdobecode.insert( std::unordered_multimap< sal_Unicode, sal_uInt8 >::value_type( aAdobeCodes[i].aUnicode, aAdobeCodes[i].aAdobeStandardCode ) );
674 m_aAdobecodeToUnicode.insert( std::unordered_multimap< sal_uInt8, sal_Unicode >::value_type( aAdobeCodes[i].aAdobeStandardCode, aAdobeCodes[i].aUnicode ) );
678 m_aFontInstallerTimer.SetTimeoutHdl(LINK(this, PrintFontManager, autoInstallFontLangSupport));
679 m_aFontInstallerTimer.SetTimeout(5000);
682 PrintFontManager::~PrintFontManager()
684 m_aFontInstallerTimer.Stop();
685 deinitFontconfig();
686 for( std::unordered_map< fontID, PrintFont* >::const_iterator it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
687 delete (*it).second;
688 delete m_pAtoms;
689 delete m_pFontCache;
692 OString PrintFontManager::getDirectory( int nAtom ) const
694 std::unordered_map< int, OString >::const_iterator it( m_aAtomToDir.find( nAtom ) );
695 return it != m_aAtomToDir.end() ? it->second : OString();
698 int PrintFontManager::getDirectoryAtom( const OString& rDirectory, bool bCreate )
700 int nAtom = 0;
701 std::unordered_map< OString, int, OStringHash >::const_iterator it
702 ( m_aDirToAtom.find( rDirectory ) );
703 if( it != m_aDirToAtom.end() )
704 nAtom = it->second;
705 else if( bCreate )
707 nAtom = m_nNextDirAtom++;
708 m_aDirToAtom[ rDirectory ] = nAtom;
709 m_aAtomToDir[ nAtom ] = rDirectory;
711 return nAtom;
714 std::vector<fontID> PrintFontManager::addFontFile( const OString& rFileName )
716 rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
717 INetURLObject aPath( OStringToOUString( rFileName, aEncoding ), INetURLObject::FSYS_DETECT );
718 OString aName( OUStringToOString( aPath.GetName( INetURLObject::DECODE_WITH_CHARSET, aEncoding ), aEncoding ) );
719 OString aDir( OUStringToOString(
720 INetURLObject::decode( aPath.GetPath(), INetURLObject::DECODE_WITH_CHARSET, aEncoding ), aEncoding ) );
722 int nDirID = getDirectoryAtom( aDir, true );
723 std::vector<fontID> aFontIds = findFontFileIDs( nDirID, aName );
724 if( aFontIds.empty() )
726 ::std::list< PrintFont* > aNewFonts;
727 if( analyzeFontFile( nDirID, aName, aNewFonts ) )
729 for( ::std::list< PrintFont* >::iterator it = aNewFonts.begin();
730 it != aNewFonts.end(); ++it )
732 fontID nFontId = m_nNextFontID++;
733 m_aFonts[nFontId] = *it;
734 m_aFontFileToFontID[ aName ].insert( nFontId );
735 m_pFontCache->updateFontCacheEntry( *it, true );
736 aFontIds.push_back(nFontId);
740 return aFontIds;
743 enum fontFormat
745 UNKNOWN, TRUETYPE, CFF, TYPE1
748 bool PrintFontManager::analyzeFontFile( int nDirID, const OString& rFontFile, ::std::list< PrintFontManager::PrintFont* >& rNewFonts, const char *pFormat ) const
750 rNewFonts.clear();
752 OString aDir( getDirectory( nDirID ) );
754 OString aFullPath( aDir );
755 aFullPath += "/";
756 aFullPath += rFontFile;
758 // #i1872# reject unreadable files
759 if( access( aFullPath.getStr(), R_OK ) )
760 return false;
762 fontFormat eFormat = UNKNOWN;
763 if (pFormat)
765 if (!strcmp(pFormat, "TrueType"))
766 eFormat = TRUETYPE;
767 else if (!strcmp(pFormat, "CFF"))
768 eFormat = CFF;
769 else if (!strcmp(pFormat, "Type 1"))
770 eFormat = TYPE1;
772 if (eFormat == UNKNOWN)
774 OString aExt( rFontFile.copy( rFontFile.lastIndexOf( '.' )+1 ) );
775 if( aExt.equalsIgnoreAsciiCase("pfb") || aExt.equalsIgnoreAsciiCase("pfa") )
776 eFormat = TYPE1;
777 else if( aExt.equalsIgnoreAsciiCase("ttf")
778 || aExt.equalsIgnoreAsciiCase("ttc")
779 || aExt.equalsIgnoreAsciiCase("tte") ) // #i33947# for Gaiji support
780 eFormat = TRUETYPE;
781 else if( aExt.equalsIgnoreAsciiCase("otf") ) // check for TTF- and PS-OpenType too
782 eFormat = CFF;
785 if (eFormat == TYPE1)
787 // check for corresponding afm metric
788 // first look for an adjacent file
789 static const char* pSuffix[] = { ".afm", ".AFM" };
791 for( unsigned int i = 0; i < SAL_N_ELEMENTS(pSuffix); i++ )
793 OString aName = OStringBuffer(
794 rFontFile.copy(0, rFontFile.getLength() - 4)).
795 append(pSuffix[i]).makeStringAndClear();
797 OStringBuffer aFilePath(aDir);
798 aFilePath.append('/').append(aName);
800 OString aAfmFile;
801 if( access( aFilePath.makeStringAndClear().getStr(), R_OK ) )
803 // try in subdirectory afm instead
804 aFilePath.append(aDir).append("/afm/").append(aName);
806 if (!access(aFilePath.getStr(), R_OK))
807 aAfmFile = OString("afm/") + aName;
809 else
810 aAfmFile = aName;
812 if( !aAfmFile.isEmpty() )
814 Type1FontFile* pFont = new Type1FontFile();
815 pFont->m_nDirectory = nDirID;
817 pFont->m_aFontFile = rFontFile;
818 pFont->m_aMetricFile = aAfmFile;
820 if( ! pFont->readAfmMetrics( m_pAtoms, false, true ) )
822 delete pFont;
823 pFont = NULL;
825 if( pFont )
826 rNewFonts.push_back( pFont );
827 break;
831 else if (eFormat == TRUETYPE || eFormat == CFF)
833 // get number of ttc entries
834 int nLength = CountTTCFonts( aFullPath.getStr() );
835 if (nLength > 0)
837 #if OSL_DEBUG_LEVEL > 1
838 fprintf( stderr, "ttc: %s contains %d fonts\n", aFullPath.getStr(), nLength );
839 #endif
841 sal_uInt64 fileSize = 0;
843 OUString aURL;
844 if (osl::File::getFileURLFromSystemPath(OStringToOUString(aFullPath, osl_getThreadTextEncoding()),
845 aURL) == osl::File::E_None)
847 osl::File aFile(aURL);
848 if (aFile.open(osl_File_OpenFlag_Read | osl_File_OpenFlag_NoLock) == osl::File::E_None)
850 osl::DirectoryItem aItem;
851 osl::DirectoryItem::get( aURL, aItem );
852 osl::FileStatus aFileStatus( osl_FileStatus_Mask_FileSize );
853 aItem.getFileStatus( aFileStatus );
854 fileSize = aFileStatus.getFileSize();
858 //Feel free to calc the exact max possible number of fonts a file
859 //could contain given its physical size. But this will clamp it to
860 //a sane starting point
861 //http://processingjs.nihongoresources.com/the_smallest_font/
862 //https://github.com/grzegorzrolek/null-ttf
863 const int nMaxFontsPossible = fileSize / 528;
864 if (nLength > nMaxFontsPossible)
865 nLength = nMaxFontsPossible;
867 for( int i = 0; i < nLength; i++ )
869 TrueTypeFontFile* pFont = new TrueTypeFontFile();
870 pFont->m_nDirectory = nDirID;
871 pFont->m_aFontFile = rFontFile;
872 pFont->m_nCollectionEntry = i;
873 if( ! analyzeTrueTypeFile( pFont ) )
875 delete pFont;
876 pFont = NULL;
878 else
879 rNewFonts.push_back( pFont );
882 else
884 TrueTypeFontFile* pFont = new TrueTypeFontFile();
885 pFont->m_nDirectory = nDirID;
886 pFont->m_aFontFile = rFontFile;
887 pFont->m_nCollectionEntry = 0;
889 // need to read the font anyway to get aliases inside the font file
890 if( ! analyzeTrueTypeFile( pFont ) )
892 delete pFont;
893 pFont = NULL;
895 else
896 rNewFonts.push_back( pFont );
899 return ! rNewFonts.empty();
902 fontID PrintFontManager::findFontFileID( int nDirID, const OString& rFontFile, int nFaceIndex ) const
904 fontID nID = 0;
906 std::unordered_map< OString, ::std::set< fontID >, OStringHash >::const_iterator set_it = m_aFontFileToFontID.find( rFontFile );
907 if( set_it == m_aFontFileToFontID.end() )
908 return nID;
910 for( ::std::set< fontID >::const_iterator font_it = set_it->second.begin(); font_it != set_it->second.end() && ! nID; ++font_it )
912 std::unordered_map< fontID, PrintFont* >::const_iterator it = m_aFonts.find( *font_it );
913 if( it == m_aFonts.end() )
914 continue;
915 switch( it->second->m_eType )
917 case fonttype::Type1:
919 Type1FontFile* const pFont = static_cast< Type1FontFile* const >((*it).second);
920 if( pFont->m_nDirectory == nDirID &&
921 pFont->m_aFontFile == rFontFile )
922 nID = it->first;
924 break;
925 case fonttype::TrueType:
927 TrueTypeFontFile* const pFont = static_cast< TrueTypeFontFile* const >((*it).second);
928 if( pFont->m_nDirectory == nDirID &&
929 pFont->m_aFontFile == rFontFile && pFont->m_nCollectionEntry == nFaceIndex )
930 nID = it->first;
932 break;
933 default:
934 break;
938 return nID;
941 std::vector<fontID> PrintFontManager::findFontFileIDs( int nDirID, const OString& rFontFile ) const
943 std::vector<fontID> aIds;
945 std::unordered_map< OString, ::std::set< fontID >, OStringHash >::const_iterator set_it = m_aFontFileToFontID.find( rFontFile );
946 if( set_it == m_aFontFileToFontID.end() )
947 return aIds;
949 for( ::std::set< fontID >::const_iterator font_it = set_it->second.begin(); font_it != set_it->second.end(); ++font_it )
951 std::unordered_map< fontID, PrintFont* >::const_iterator it = m_aFonts.find( *font_it );
952 if( it == m_aFonts.end() )
953 continue;
954 switch( it->second->m_eType )
956 case fonttype::Type1:
958 Type1FontFile* const pFont = static_cast< Type1FontFile* const >((*it).second);
959 if( pFont->m_nDirectory == nDirID &&
960 pFont->m_aFontFile == rFontFile )
961 aIds.push_back(it->first);
963 break;
964 case fonttype::TrueType:
966 TrueTypeFontFile* const pFont = static_cast< TrueTypeFontFile* const >((*it).second);
967 if( pFont->m_nDirectory == nDirID &&
968 pFont->m_aFontFile == rFontFile )
969 aIds.push_back(it->first);
971 break;
972 default:
973 break;
977 return aIds;
980 OUString PrintFontManager::convertTrueTypeName( void* pRecord )
982 NameRecord* pNameRecord = static_cast<NameRecord*>(pRecord);
983 OUString aValue;
985 ( pNameRecord->platformID == 3 && ( pNameRecord->encodingID == 0 || pNameRecord->encodingID == 1 ) ) // MS, Unicode
987 ( pNameRecord->platformID == 0 ) // Apple, Unicode
990 OUStringBuffer aName( pNameRecord->slen/2 );
991 const sal_uInt8* pNameBuffer = pNameRecord->sptr;
992 for(int n = 0; n < pNameRecord->slen/2; n++ )
993 aName.append( (sal_Unicode)getUInt16BE( pNameBuffer ) );
994 aValue = aName.makeStringAndClear();
996 else if( pNameRecord->platformID == 3 )
998 if( pNameRecord->encodingID >= 2 && pNameRecord->encodingID <= 6 )
1001 * and now for a special kind of madness:
1002 * some fonts encode their byte value string as BE uint16
1003 * (leading to stray zero bytes in the string)
1004 * while others code two bytes as a uint16 and swap to BE
1006 OStringBuffer aName;
1007 const sal_uInt8* pNameBuffer = pNameRecord->sptr;
1008 for(int n = 0; n < pNameRecord->slen/2; n++ )
1010 sal_Unicode aCode = (sal_Unicode)getUInt16BE( pNameBuffer );
1011 sal_Char aChar = aCode >> 8;
1012 if( aChar )
1013 aName.append( aChar );
1014 aChar = aCode & 0x00ff;
1015 if( aChar )
1016 aName.append( aChar );
1018 switch( pNameRecord->encodingID )
1020 case 2:
1021 aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_932 );
1022 break;
1023 case 3:
1024 aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_936 );
1025 break;
1026 case 4:
1027 aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_950 );
1028 break;
1029 case 5:
1030 aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_949 );
1031 break;
1032 case 6:
1033 aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_1361 );
1034 break;
1038 else if( pNameRecord->platformID == 1 )
1040 OString aName(reinterpret_cast<char*>(pNameRecord->sptr), pNameRecord->slen);
1041 rtl_TextEncoding eEncoding = RTL_TEXTENCODING_DONTKNOW;
1042 switch (pNameRecord->encodingID)
1044 case 0:
1045 eEncoding = RTL_TEXTENCODING_APPLE_ROMAN;
1046 break;
1047 case 1:
1048 eEncoding = RTL_TEXTENCODING_APPLE_JAPANESE;
1049 break;
1050 case 2:
1051 eEncoding = RTL_TEXTENCODING_APPLE_CHINTRAD;
1052 break;
1053 case 3:
1054 eEncoding = RTL_TEXTENCODING_APPLE_KOREAN;
1055 break;
1056 case 4:
1057 eEncoding = RTL_TEXTENCODING_APPLE_ARABIC;
1058 break;
1059 case 5:
1060 eEncoding = RTL_TEXTENCODING_APPLE_HEBREW;
1061 break;
1062 case 6:
1063 eEncoding = RTL_TEXTENCODING_APPLE_GREEK;
1064 break;
1065 case 7:
1066 eEncoding = RTL_TEXTENCODING_APPLE_CYRILLIC;
1067 break;
1068 case 9:
1069 eEncoding = RTL_TEXTENCODING_APPLE_DEVANAGARI;
1070 break;
1071 case 10:
1072 eEncoding = RTL_TEXTENCODING_APPLE_GURMUKHI;
1073 break;
1074 case 11:
1075 eEncoding = RTL_TEXTENCODING_APPLE_GUJARATI;
1076 break;
1077 case 21:
1078 eEncoding = RTL_TEXTENCODING_APPLE_THAI;
1079 break;
1080 case 25:
1081 eEncoding = RTL_TEXTENCODING_APPLE_CHINSIMP;
1082 break;
1083 case 29:
1084 eEncoding = RTL_TEXTENCODING_APPLE_CENTEURO;
1085 break;
1086 case 32: //Uninterpreted
1087 eEncoding = RTL_TEXTENCODING_UTF8;
1088 break;
1089 default:
1090 SAL_WARN("vcl", "Unimplmented mac encoding " << pNameRecord->encodingID << " to unicode conversion");
1091 break;
1093 if (eEncoding != RTL_TEXTENCODING_DONTKNOW)
1094 aValue = OStringToOUString(aName, eEncoding);
1097 return aValue;
1100 //fdo#33349.There exists an archaic Berling Antiqua font which has a "Times New
1101 //Roman" name field in it. We don't want the "Times New Roman" name to take
1102 //precedence in this case. We take Berling Antiqua as a higher priority name,
1103 //and erase the "Times New Roman" name
1104 namespace
1106 bool isBadTNR(const OUString &rName, ::std::set< OUString >& rSet)
1108 bool bRet = false;
1109 if ( rName == "Berling Antiqua" )
1111 ::std::set< OUString >::iterator aEnd = rSet.end();
1112 ::std::set< OUString >::iterator aI = rSet.find("Times New Roman");
1113 if (aI != aEnd)
1115 bRet = true;
1116 rSet.erase(aI);
1119 return bRet;
1123 void PrintFontManager::analyzeTrueTypeFamilyName( void* pTTFont, ::std::list< OUString >& rNames )
1125 OUString aFamily;
1127 rNames.clear();
1128 ::std::set< OUString > aSet;
1130 NameRecord* pNameRecords = NULL;
1131 int nNameRecords = GetTTNameRecords( static_cast<TrueTypeFont*>(pTTFont), &pNameRecords );
1132 if( nNameRecords && pNameRecords )
1134 LanguageTag aSystem("");
1135 LanguageType eLang = aSystem.getLanguageType();
1136 int nLastMatch = -1;
1137 for( int i = 0; i < nNameRecords; i++ )
1139 if( pNameRecords[i].nameID != 1 || pNameRecords[i].sptr == NULL )
1140 continue;
1141 int nMatch = -1;
1142 if( pNameRecords[i].platformID == 0 ) // Unicode
1143 nMatch = 4000;
1144 else if( pNameRecords[i].platformID == 3 )
1146 // this bases on the LanguageType actually being a Win LCID
1147 if (pNameRecords[i].languageID == eLang)
1148 nMatch = 8000;
1149 else if( pNameRecords[i].languageID == LANGUAGE_ENGLISH_US )
1150 nMatch = 2000;
1151 else if( pNameRecords[i].languageID == LANGUAGE_ENGLISH ||
1152 pNameRecords[i].languageID == LANGUAGE_ENGLISH_UK )
1153 nMatch = 1500;
1154 else
1155 nMatch = 1000;
1157 else if (pNameRecords[i].platformID == 1)
1159 AppleLanguageId aAppleId = static_cast<AppleLanguageId>(pNameRecords[i].languageID);
1160 LanguageTag aApple(makeLanguageTagFromAppleLanguageId(aAppleId));
1161 if (aApple == aSystem)
1162 nMatch = 8000;
1163 else if (aAppleId == AppleLanguageId::ENGLISH)
1164 nMatch = 2000;
1165 else
1166 nMatch = 1000;
1168 OUString aName = convertTrueTypeName( pNameRecords + i );
1169 aSet.insert( aName );
1170 if (aName.isEmpty())
1171 continue;
1172 if( nMatch > nLastMatch || isBadTNR(aName, aSet) )
1174 nLastMatch = nMatch;
1175 aFamily = aName;
1179 DisposeNameRecords( pNameRecords, nNameRecords );
1180 if( !aFamily.isEmpty() )
1182 rNames.push_front( aFamily );
1183 for( ::std::set< OUString >::const_iterator it = aSet.begin(); it != aSet.end(); ++it )
1184 if( *it != aFamily )
1185 rNames.push_back( *it );
1187 return;
1190 bool PrintFontManager::analyzeTrueTypeFile( PrintFont* pFont ) const
1192 bool bSuccess = false;
1193 rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
1194 OString aFile = getFontFile( pFont );
1195 TrueTypeFont* pTTFont = NULL;
1197 TrueTypeFontFile* pTTFontFile = static_cast< TrueTypeFontFile* >(pFont);
1198 if( OpenTTFontFile( aFile.getStr(), pTTFontFile->m_nCollectionEntry, &pTTFont ) == SF_OK )
1200 TTGlobalFontInfo aInfo;
1201 GetTTGlobalFontInfo( pTTFont, & aInfo );
1203 ::std::list< OUString > aNames;
1204 analyzeTrueTypeFamilyName( pTTFont, aNames );
1206 // set family name from XLFD if possible
1207 if( ! pFont->m_nFamilyName )
1209 if( aNames.begin() != aNames.end() )
1211 pFont->m_nFamilyName = m_pAtoms->getAtom( ATOM_FAMILYNAME, aNames.front(), true );
1212 aNames.pop_front();
1214 else
1216 sal_Int32 dotIndex;
1218 // poor font does not have a family name
1219 // name it to file name minus the extension
1220 dotIndex = pTTFontFile->m_aFontFile.lastIndexOf( '.' );
1221 if ( dotIndex == -1 )
1222 dotIndex = pTTFontFile->m_aFontFile.getLength();
1224 pFont->m_nFamilyName = m_pAtoms->getAtom( ATOM_FAMILYNAME, OStringToOUString( pTTFontFile->m_aFontFile.copy( 0, dotIndex ), aEncoding ), true );
1227 for( ::std::list< OUString >::iterator it = aNames.begin(); it != aNames.end(); ++it )
1229 if( !it->isEmpty() )
1231 int nAlias = m_pAtoms->getAtom( ATOM_FAMILYNAME, *it, true );
1232 if( nAlias != pFont->m_nFamilyName )
1234 std::list< int >::const_iterator al_it;
1235 for( al_it = pFont->m_aAliases.begin(); al_it != pFont->m_aAliases.end() && *al_it != nAlias; ++al_it )
1237 if( al_it == pFont->m_aAliases.end() )
1238 pFont->m_aAliases.push_back( nAlias );
1243 if( aInfo.usubfamily )
1244 pFont->m_aStyleName = OUString( aInfo.usubfamily );
1246 SAL_WARN_IF( !aInfo.psname, "vcl", "No PostScript name in font:" << aFile.getStr() );
1248 OUString sPSName = aInfo.psname ?
1249 OUString(aInfo.psname, rtl_str_getLength(aInfo.psname), aEncoding) :
1250 m_pAtoms->getString(ATOM_FAMILYNAME, pFont->m_nFamilyName); // poor font does not have a postscript name
1252 pFont->m_nPSName = m_pAtoms->getAtom( ATOM_PSNAME, sPSName, true );
1254 switch( aInfo.weight )
1256 case FW_THIN: pFont->m_eWeight = WEIGHT_THIN; break;
1257 case FW_EXTRALIGHT: pFont->m_eWeight = WEIGHT_ULTRALIGHT; break;
1258 case FW_LIGHT: pFont->m_eWeight = WEIGHT_LIGHT; break;
1259 case FW_MEDIUM: pFont->m_eWeight = WEIGHT_MEDIUM; break;
1260 case FW_SEMIBOLD: pFont->m_eWeight = WEIGHT_SEMIBOLD; break;
1261 case FW_BOLD: pFont->m_eWeight = WEIGHT_BOLD; break;
1262 case FW_EXTRABOLD: pFont->m_eWeight = WEIGHT_ULTRABOLD; break;
1263 case FW_BLACK: pFont->m_eWeight = WEIGHT_BLACK; break;
1265 case FW_NORMAL:
1266 default: pFont->m_eWeight = WEIGHT_NORMAL; break;
1269 switch( aInfo.width )
1271 case FWIDTH_ULTRA_CONDENSED: pFont->m_eWidth = WIDTH_ULTRA_CONDENSED; break;
1272 case FWIDTH_EXTRA_CONDENSED: pFont->m_eWidth = WIDTH_EXTRA_CONDENSED; break;
1273 case FWIDTH_CONDENSED: pFont->m_eWidth = WIDTH_CONDENSED; break;
1274 case FWIDTH_SEMI_CONDENSED: pFont->m_eWidth = WIDTH_SEMI_CONDENSED; break;
1275 case FWIDTH_SEMI_EXPANDED: pFont->m_eWidth = WIDTH_SEMI_EXPANDED; break;
1276 case FWIDTH_EXPANDED: pFont->m_eWidth = WIDTH_EXPANDED; break;
1277 case FWIDTH_EXTRA_EXPANDED: pFont->m_eWidth = WIDTH_EXTRA_EXPANDED; break;
1278 case FWIDTH_ULTRA_EXPANDED: pFont->m_eWidth = WIDTH_ULTRA_EXPANDED; break;
1280 case FWIDTH_NORMAL:
1281 default: pFont->m_eWidth = WIDTH_NORMAL; break;
1284 pFont->m_ePitch = aInfo.pitch ? PITCH_FIXED : PITCH_VARIABLE;
1285 pFont->m_eItalic = aInfo.italicAngle == 0 ? ITALIC_NONE : ( aInfo.italicAngle < 0 ? ITALIC_NORMAL : ITALIC_OBLIQUE );
1286 // #104264# there are fonts that set italic angle 0 although they are
1287 // italic; use macstyle bit here
1288 if( aInfo.italicAngle == 0 && (aInfo.macStyle & 2) )
1289 pFont->m_eItalic = ITALIC_NORMAL;
1291 pFont->m_aEncoding = aInfo.symbolEncoded ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UCS2;
1293 pFont->m_aGlobalMetricY.width = pFont->m_aGlobalMetricX.width = aInfo.xMax - aInfo.xMin;
1294 pFont->m_aGlobalMetricY.height = pFont->m_aGlobalMetricX.height = aInfo.yMax - aInfo.yMin;
1296 if( aInfo.winAscent && aInfo.winDescent )
1298 pFont->m_nAscend = aInfo.winAscent;
1299 pFont->m_nDescend = aInfo.winDescent;
1300 pFont->m_nLeading = pFont->m_nAscend + pFont->m_nDescend - 1000;
1302 else if( aInfo.typoAscender && aInfo.typoDescender )
1304 pFont->m_nLeading = aInfo.typoLineGap;
1305 pFont->m_nAscend = aInfo.typoAscender;
1306 pFont->m_nDescend = -aInfo.typoDescender;
1308 else
1310 pFont->m_nLeading = aInfo.linegap;
1311 pFont->m_nAscend = aInfo.ascender;
1312 pFont->m_nDescend = -aInfo.descender;
1315 // last try: font bounding box
1316 if( pFont->m_nAscend == 0 )
1317 pFont->m_nAscend = aInfo.yMax;
1318 if( pFont->m_nDescend == 0 )
1319 pFont->m_nDescend = -aInfo.yMin;
1320 if( pFont->m_nLeading == 0 )
1321 pFont->m_nLeading = 15 * (pFont->m_nAscend+pFont->m_nDescend) / 100;
1323 if( pFont->m_nAscend )
1324 pFont->m_aGlobalMetricX.height = pFont->m_aGlobalMetricY.height = pFont->m_nAscend + pFont->m_nDescend;
1326 // get bounding box
1327 pFont->m_nXMin = aInfo.xMin;
1328 pFont->m_nYMin = aInfo.yMin;
1329 pFont->m_nXMax = aInfo.xMax;
1330 pFont->m_nYMax = aInfo.yMax;
1332 // get type flags
1333 pTTFontFile->m_nTypeFlags = (unsigned int)aInfo.typeFlags;
1335 // get vertical substitutions flag
1336 pFont->m_bHaveVerticalSubstitutedGlyphs = DoesVerticalSubstitution( pTTFont, 1 );
1338 CloseTTFont( pTTFont );
1339 bSuccess = true;
1341 #if OSL_DEBUG_LEVEL > 1
1342 else
1343 fprintf( stderr, "could not OpenTTFont \"%s\"\n", aFile.getStr() );
1344 #endif
1346 return bSuccess;
1349 static bool AreFCSubstitutionsEnabled()
1351 return (SalGenericInstance::FetchFontSubstitutionFlags() & 3) == 0;
1354 void PrintFontManager::initialize()
1356 #ifdef CALLGRIND_COMPILE
1357 CALLGRIND_TOGGLE_COLLECT();
1358 CALLGRIND_ZERO_STATS();
1359 #endif
1361 if( ! m_pFontCache )
1363 #if OSL_DEBUG_LEVEL > 1
1364 fprintf( stderr, "creating font cache ... " );
1365 clock_t aStart;
1366 struct tms tms;
1367 aStart = times( &tms );
1368 #endif
1369 m_pFontCache = new FontCache();
1370 #if OSL_DEBUG_LEVEL > 1
1371 clock_t aStop = times( &tms );
1372 fprintf( stderr, "done in %lf s\n", (double)(aStop - aStart)/(double)sysconf( _SC_CLK_TCK ) );
1373 #endif
1376 // initialize can be called more than once, e.g.
1377 // gtk-fontconfig-timestamp changes to reflect new font installed and
1378 // PrintFontManager::initialize called again
1380 for( std::unordered_map< fontID, PrintFont* >::const_iterator it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
1381 delete (*it).second;
1382 m_nNextFontID = 1;
1383 m_aFonts.clear();
1384 m_aFontDirectories.clear();
1385 m_aPrivateFontDirectories.clear();
1388 #if OSL_DEBUG_LEVEL > 1
1389 clock_t aStart;
1390 clock_t aStep1;
1391 clock_t aStep2;
1393 struct tms tms;
1395 aStart = times( &tms );
1396 #endif
1398 // first try fontconfig
1399 initFontconfig();
1401 // part one - look for downloadable fonts
1402 rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
1403 const OUString &rSalPrivatePath = psp::getFontPath();
1405 // search for the fonts in SAL_PRIVATE_FONTPATH first; those are
1406 // the fonts installed with the office
1407 if( !rSalPrivatePath.isEmpty() )
1409 OString aPath = OUStringToOString( rSalPrivatePath, aEncoding );
1410 const bool bAreFCSubstitutionsEnabled = AreFCSubstitutionsEnabled();
1411 sal_Int32 nIndex = 0;
1414 OString aToken = aPath.getToken( 0, ';', nIndex );
1415 normPath( aToken );
1416 if ( aToken.isEmpty() )
1418 continue;
1420 // if registering an app-specific fontdir with fontconfig fails
1421 // and fontconfig-based substitutions are enabled
1422 // then trying to use these app-specific fonts doesn't make sense
1423 if( !addFontconfigDir( aToken ) )
1424 if( bAreFCSubstitutionsEnabled )
1425 continue;
1426 m_aFontDirectories.push_back( aToken );
1427 m_aPrivateFontDirectories.push_back( getDirectoryAtom( aToken, true ) );
1428 } while( nIndex >= 0 );
1431 // protect against duplicate paths
1432 std::unordered_map< OString, int, OStringHash > visited_dirs;
1434 // Don't search directories that fontconfig already did
1435 countFontconfigFonts( visited_dirs );
1437 // search for font files in each path
1438 std::list< OString >::iterator dir_it;
1439 for( dir_it = m_aFontDirectories.begin(); dir_it != m_aFontDirectories.end(); ++dir_it )
1441 OString aPath( *dir_it );
1442 // see if we were here already
1443 if( visited_dirs.find( aPath ) != visited_dirs.end() )
1444 continue;
1445 visited_dirs[ aPath ] = 1;
1447 // there may be ":unscaled" directories (see XFree86)
1448 // it should be safe to ignore them since they should not
1449 // contain any of our recognizeable fonts
1451 // ask the font cache whether it handles this directory
1452 std::list< PrintFont* > aCacheFonts;
1453 if( m_pFontCache->listDirectory( aPath, aCacheFonts ) )
1455 #if OSL_DEBUG_LEVEL > 1
1456 fprintf( stderr, "adding cache directory: %s\n", aPath.getStr() );
1457 #endif
1458 for( ::std::list< PrintFont* >::iterator it = aCacheFonts.begin(); it != aCacheFonts.end(); ++it )
1460 fontID aFont = m_nNextFontID++;
1461 m_aFonts[ aFont ] = *it;
1462 if( (*it)->m_eType == fonttype::Type1 )
1463 m_aFontFileToFontID[ static_cast<Type1FontFile*>(*it)->m_aFontFile ].insert( aFont );
1464 else if( (*it)->m_eType == fonttype::TrueType )
1465 m_aFontFileToFontID[ static_cast<TrueTypeFontFile*>(*it)->m_aFontFile ].insert( aFont );
1466 #if OSL_DEBUG_LEVEL > 1
1467 else
1468 fprintf(stderr, "Un-cached type '%d'\n", (*it)->m_eType);
1469 #if OSL_DEBUG_LEVEL > 2
1470 fprintf( stderr, "adding cached font %d: %s\n", aFont, getFontFileSysPath( aFont ).getStr() );
1471 #endif
1472 #endif
1474 if( ! m_pFontCache->scanAdditionalFiles( aPath ) )
1475 continue;
1480 #if OSL_DEBUG_LEVEL > 1
1481 aStep1 = times( &tms );
1482 #endif
1484 // part three - fill in family styles
1485 std::unordered_map< fontID, PrintFont* >::iterator font_it;
1486 for (font_it = m_aFonts.begin(); font_it != m_aFonts.end(); ++font_it)
1488 std::unordered_map< int, FontFamily >::const_iterator it =
1489 m_aFamilyTypes.find( font_it->second->m_nFamilyName );
1490 if (it != m_aFamilyTypes.end())
1491 continue;
1492 const OUString& rFamily =
1493 m_pAtoms->getString( ATOM_FAMILYNAME, font_it->second->m_nFamilyName);
1494 FontFamily eType = matchFamilyName( rFamily );
1495 m_aFamilyTypes[ font_it->second->m_nFamilyName ] = eType;
1498 #if OSL_DEBUG_LEVEL > 1
1499 aStep2 = times( &tms );
1500 fprintf( stderr, "PrintFontManager::initialize: collected %" SAL_PRI_SIZET "u fonts\n", m_aFonts.size() );
1501 double fTick = (double)sysconf( _SC_CLK_TCK );
1502 fprintf( stderr, "Step 1 took %lf seconds\n", (double)(aStep1 - aStart)/fTick );
1503 fprintf( stderr, "Step 2 took %lf seconds\n", (double)(aStep2 - aStep1)/fTick );
1504 #endif
1506 m_pFontCache->flush();
1508 #ifdef CALLGRIND_COMPILE
1509 CALLGRIND_DUMP_STATS();
1510 CALLGRIND_TOGGLE_COLLECT();
1511 #endif
1514 void PrintFontManager::getFontList( ::std::list< fontID >& rFontIDs )
1516 rFontIDs.clear();
1517 std::unordered_map< fontID, PrintFont* >::const_iterator it;
1519 for( it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
1520 rFontIDs.push_back( it->first );
1523 void PrintFontManager::fillPrintFontInfo( PrintFont* pFont, FastPrintFontInfo& rInfo ) const
1525 std::unordered_map< int, FontFamily >::const_iterator style_it =
1526 m_aFamilyTypes.find( pFont->m_nFamilyName );
1527 rInfo.m_eType = pFont->m_eType;
1528 rInfo.m_aFamilyName = m_pAtoms->getString( ATOM_FAMILYNAME, pFont->m_nFamilyName );
1529 rInfo.m_aStyleName = pFont->m_aStyleName;
1530 rInfo.m_eFamilyStyle = style_it != m_aFamilyTypes.end() ? style_it->second : FAMILY_DONTKNOW;
1531 rInfo.m_eItalic = pFont->m_eItalic;
1532 rInfo.m_eWidth = pFont->m_eWidth;
1533 rInfo.m_eWeight = pFont->m_eWeight;
1534 rInfo.m_ePitch = pFont->m_ePitch;
1535 rInfo.m_aEncoding = pFont->m_aEncoding;
1537 rInfo.m_bEmbeddable = (pFont->m_eType == fonttype::Type1);
1538 rInfo.m_bSubsettable = (pFont->m_eType == fonttype::TrueType); // TODO: rename to SfntType
1540 rInfo.m_aAliases.clear();
1541 for( ::std::list< int >::iterator it = pFont->m_aAliases.begin(); it != pFont->m_aAliases.end(); ++it )
1542 rInfo.m_aAliases.push_back( m_pAtoms->getString( ATOM_FAMILYNAME, *it ) );
1545 void PrintFontManager::fillPrintFontInfo( PrintFont* pFont, PrintFontInfo& rInfo ) const
1547 if( ( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 ) ||
1548 ! pFont->m_pMetrics || pFont->m_pMetrics->isEmpty()
1551 // might be a truetype font not analyzed or type1 without metrics read
1552 if( pFont->m_eType == fonttype::Type1 )
1553 pFont->readAfmMetrics( m_pAtoms, false, false );
1554 else if( pFont->m_eType == fonttype::TrueType )
1555 analyzeTrueTypeFile( pFont );
1558 fillPrintFontInfo( pFont, static_cast< FastPrintFontInfo& >( rInfo ) );
1560 rInfo.m_nAscend = pFont->m_nAscend;
1561 rInfo.m_nDescend = pFont->m_nDescend;
1562 rInfo.m_nLeading = pFont->m_nLeading;
1563 rInfo.m_nWidth = pFont->m_aGlobalMetricX.width < pFont->m_aGlobalMetricY.width ? pFont->m_aGlobalMetricY.width : pFont->m_aGlobalMetricX.width;
1566 bool PrintFontManager::getFontInfo( fontID nFontID, PrintFontInfo& rInfo ) const
1568 PrintFont* pFont = getFont( nFontID );
1569 if( pFont )
1571 rInfo.m_nID = nFontID;
1572 fillPrintFontInfo( pFont, rInfo );
1574 return pFont != nullptr;
1577 bool PrintFontManager::getFontFastInfo( fontID nFontID, FastPrintFontInfo& rInfo ) const
1579 PrintFont* pFont = getFont( nFontID );
1580 if( pFont )
1582 rInfo.m_nID = nFontID;
1583 fillPrintFontInfo( pFont, rInfo );
1585 return pFont != nullptr;
1588 bool PrintFontManager::getFontBoundingBox( fontID nFontID, int& xMin, int& yMin, int& xMax, int& yMax )
1590 bool bSuccess = false;
1591 PrintFont* pFont = getFont( nFontID );
1592 if( pFont )
1594 if( pFont->m_nXMin == 0 && pFont->m_nYMin == 0 && pFont->m_nXMax == 0 && pFont->m_nYMax == 0 )
1596 // might be a truetype font not analyzed or type1 without metrics read
1597 if( pFont->m_eType == fonttype::Type1 )
1598 pFont->readAfmMetrics( m_pAtoms, false, true );
1599 else if( pFont->m_eType == fonttype::TrueType )
1600 analyzeTrueTypeFile( pFont );
1602 bSuccess = true;
1603 xMin = pFont->m_nXMin;
1604 yMin = pFont->m_nYMin;
1605 xMax = pFont->m_nXMax;
1606 yMax = pFont->m_nYMax;
1608 return bSuccess;
1611 int PrintFontManager::getFontFaceNumber( fontID nFontID ) const
1613 int nRet = 0;
1614 PrintFont* pFont = getFont( nFontID );
1615 if( pFont && pFont->m_eType == fonttype::TrueType )
1616 nRet = static_cast< TrueTypeFontFile* >(pFont)->m_nCollectionEntry;
1617 if (nRet < 0)
1618 nRet = 0;
1619 return nRet;
1622 FontFamily PrintFontManager::matchFamilyName( const OUString& rFamily )
1624 typedef struct {
1625 const char* mpName;
1626 sal_uInt16 mnLength;
1627 FontFamily meType;
1628 } family_t;
1630 #define InitializeClass( p, a ) p, sizeof(p) - 1, a
1631 const family_t pFamilyMatch[] = {
1632 { InitializeClass( "arial", FAMILY_SWISS ) },
1633 { InitializeClass( "arioso", FAMILY_SCRIPT ) },
1634 { InitializeClass( "avant garde", FAMILY_SWISS ) },
1635 { InitializeClass( "avantgarde", FAMILY_SWISS ) },
1636 { InitializeClass( "bembo", FAMILY_ROMAN ) },
1637 { InitializeClass( "bookman", FAMILY_ROMAN ) },
1638 { InitializeClass( "conga", FAMILY_ROMAN ) },
1639 { InitializeClass( "courier", FAMILY_MODERN ) },
1640 { InitializeClass( "curl", FAMILY_SCRIPT ) },
1641 { InitializeClass( "fixed", FAMILY_MODERN ) },
1642 { InitializeClass( "gill", FAMILY_SWISS ) },
1643 { InitializeClass( "helmet", FAMILY_MODERN ) },
1644 { InitializeClass( "helvetica", FAMILY_SWISS ) },
1645 { InitializeClass( "international", FAMILY_MODERN ) },
1646 { InitializeClass( "lucida", FAMILY_SWISS ) },
1647 { InitializeClass( "new century schoolbook", FAMILY_ROMAN ) },
1648 { InitializeClass( "palatino", FAMILY_ROMAN ) },
1649 { InitializeClass( "roman", FAMILY_ROMAN ) },
1650 { InitializeClass( "sans serif", FAMILY_SWISS ) },
1651 { InitializeClass( "sansserif", FAMILY_SWISS ) },
1652 { InitializeClass( "serf", FAMILY_ROMAN ) },
1653 { InitializeClass( "serif", FAMILY_ROMAN ) },
1654 { InitializeClass( "times", FAMILY_ROMAN ) },
1655 { InitializeClass( "utopia", FAMILY_ROMAN ) },
1656 { InitializeClass( "zapf chancery", FAMILY_SCRIPT ) },
1657 { InitializeClass( "zapfchancery", FAMILY_SCRIPT ) }
1660 OString aFamily = OUStringToOString( rFamily, RTL_TEXTENCODING_ASCII_US );
1661 sal_uInt32 nLower = 0;
1662 sal_uInt32 nUpper = SAL_N_ELEMENTS(pFamilyMatch);
1664 while( nLower < nUpper )
1666 sal_uInt32 nCurrent = (nLower + nUpper) / 2;
1667 const family_t* pHaystack = pFamilyMatch + nCurrent;
1668 sal_Int32 nComparison =
1669 rtl_str_compareIgnoreAsciiCase_WithLength
1671 aFamily.getStr(), aFamily.getLength(),
1672 pHaystack->mpName, pHaystack->mnLength
1675 if( nComparison < 0 )
1676 nUpper = nCurrent;
1677 else
1678 if( nComparison > 0 )
1679 nLower = nCurrent + 1;
1680 else
1681 return pHaystack->meType;
1684 return FAMILY_DONTKNOW;
1687 OString PrintFontManager::getAfmFile( PrintFont* pFont ) const
1689 OString aMetricPath;
1690 if( pFont )
1692 switch( pFont->m_eType )
1694 case fonttype::Type1:
1696 Type1FontFile* pPSFont = static_cast< Type1FontFile* >(pFont);
1697 aMetricPath = getDirectory( pPSFont->m_nDirectory );
1698 aMetricPath += "/";
1699 aMetricPath += pPSFont->m_aMetricFile;
1701 break;
1702 default: break;
1705 return aMetricPath;
1708 OString PrintFontManager::getFontFile( PrintFont* pFont ) const
1710 OString aPath;
1712 if( pFont && pFont->m_eType == fonttype::Type1 )
1714 Type1FontFile* pPSFont = static_cast< Type1FontFile* >(pFont);
1715 std::unordered_map< int, OString >::const_iterator it = m_aAtomToDir.find( pPSFont->m_nDirectory );
1716 aPath = it->second;
1717 aPath += "/";
1718 aPath += pPSFont->m_aFontFile;
1720 else if( pFont && pFont->m_eType == fonttype::TrueType )
1722 TrueTypeFontFile* pTTFont = static_cast< TrueTypeFontFile* >(pFont);
1723 std::unordered_map< int, OString >::const_iterator it = m_aAtomToDir.find( pTTFont->m_nDirectory );
1724 aPath = it->second;
1725 aPath += "/";
1726 aPath += pTTFont->m_aFontFile;
1728 return aPath;
1731 const OUString& PrintFontManager::getPSName( fontID nFontID ) const
1733 PrintFont* pFont = getFont( nFontID );
1734 if( pFont && pFont->m_nPSName == 0 )
1736 if( pFont->m_eType == fonttype::TrueType )
1737 analyzeTrueTypeFile( pFont );
1740 return m_pAtoms->getString( ATOM_PSNAME, pFont ? pFont->m_nPSName : INVALID_ATOM );
1743 int PrintFontManager::getFontAscend( fontID nFontID ) const
1745 PrintFont* pFont = getFont( nFontID );
1746 if (pFont && pFont->m_nAscend == 0 && pFont->m_nDescend == 0)
1748 // might be a truetype font not yet analyzed
1749 if( pFont->m_eType == fonttype::TrueType )
1750 analyzeTrueTypeFile( pFont );
1751 else if( pFont->m_eType == fonttype::Type1 )
1752 pFont->readAfmMetrics( m_pAtoms, false, true );
1754 return pFont ? pFont->m_nAscend : 0;
1757 int PrintFontManager::getFontDescend( fontID nFontID ) const
1759 PrintFont* pFont = getFont( nFontID );
1760 if (pFont && pFont->m_nAscend == 0 && pFont->m_nDescend == 0)
1762 // might be a truetype font not yet analyzed
1763 if( pFont->m_eType == fonttype::TrueType )
1764 analyzeTrueTypeFile( pFont );
1765 else if( pFont->m_eType == fonttype::Type1 )
1766 pFont->readAfmMetrics( m_pAtoms, false, true );
1768 return pFont ? pFont->m_nDescend : 0;
1771 void PrintFontManager::hasVerticalSubstitutions( fontID nFontID,
1772 const sal_Unicode* pCharacters, int nCharacters, bool* pHasSubst ) const
1774 PrintFont* pFont = getFont( nFontID );
1775 if (pFont && pFont->m_nAscend == 0 && pFont->m_nDescend == 0)
1777 // might be a truetype font not yet analyzed
1778 if( pFont->m_eType == fonttype::TrueType )
1779 analyzeTrueTypeFile( pFont );
1782 if (!pFont || !pFont->m_bHaveVerticalSubstitutedGlyphs)
1783 memset( pHasSubst, 0, sizeof(bool)*nCharacters );
1784 else
1786 for( int i = 0; i < nCharacters; i++ )
1788 sal_Unicode code = pCharacters[i];
1789 if( ! pFont->m_pMetrics ||
1790 ! ( pFont->m_pMetrics->m_aPages[ code >> 11 ] & ( 1 << ( ( code >> 8 ) & 7 ) ) ) )
1791 pFont->queryMetricPage( code >> 8, m_pAtoms );
1792 std::unordered_map< sal_Unicode, bool >::const_iterator it = pFont->m_pMetrics->m_bVerticalSubstitutions.find( code );
1793 pHasSubst[i] = it != pFont->m_pMetrics->m_bVerticalSubstitutions.end();
1798 bool PrintFontManager::isFontDownloadingAllowedForPrinting( fontID nFont ) const
1800 static const char* pEnable = getenv( "PSPRINT_ENABLE_TTF_COPYRIGHTAWARENESS" );
1801 bool bRet = true;
1803 if( pEnable && *pEnable )
1805 PrintFont* pFont = getFont( nFont );
1806 if( pFont && pFont->m_eType == fonttype::TrueType )
1808 TrueTypeFontFile* pTTFontFile = static_cast<TrueTypeFontFile*>(pFont);
1809 if( pTTFontFile->m_nTypeFlags & TYPEFLAG_INVALID )
1811 TrueTypeFont* pTTFont = NULL;
1812 OString aFile = getFontFile( pFont );
1813 if( OpenTTFontFile( aFile.getStr(), pTTFontFile->m_nCollectionEntry, &pTTFont ) == SF_OK )
1815 // get type flags
1816 TTGlobalFontInfo aInfo;
1817 GetTTGlobalFontInfo( pTTFont, & aInfo );
1818 pTTFontFile->m_nTypeFlags = (unsigned int)aInfo.typeFlags;
1819 CloseTTFont( pTTFont );
1823 unsigned int nCopyrightFlags = pTTFontFile->m_nTypeFlags & TYPEFLAG_COPYRIGHT_MASK;
1825 // http://www.microsoft.com/typography/tt/ttf_spec/ttch02.doc
1826 // Font embedding is allowed if not restricted completely (only bit 1 set).
1827 // Preview&Print (bit 2), Editable (bit 3) or Installable (==0) fonts are ok.
1828 bRet = ( nCopyrightFlags & 0x02 ) != 0x02;
1831 return bRet;
1834 bool PrintFontManager::getMetrics( fontID nFontID, const sal_Unicode* pString, int nLen, CharacterMetric* pArray, bool bVertical ) const
1836 PrintFont* pFont = getFont( nFontID );
1837 if( ! pFont )
1838 return false;
1840 if( ( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
1841 || ! pFont->m_pMetrics || pFont->m_pMetrics->isEmpty()
1844 // might be a font not yet analyzed
1845 if( pFont->m_eType == fonttype::Type1 )
1846 pFont->readAfmMetrics( m_pAtoms, false, false );
1847 else if( pFont->m_eType == fonttype::TrueType )
1848 analyzeTrueTypeFile( pFont );
1851 for( int i = 0; i < nLen; i++ )
1853 if( ! pFont->m_pMetrics ||
1854 ! ( pFont->m_pMetrics->m_aPages[ pString[i] >> 11 ] & ( 1 << ( ( pString[i] >> 8 ) & 7 ) ) ) )
1855 pFont->queryMetricPage( pString[i] >> 8, m_pAtoms );
1856 pArray[i].width = pArray[i].height = -1;
1857 if( pFont->m_pMetrics )
1859 int effectiveCode = pString[i];
1860 effectiveCode |= bVertical ? 1 << 16 : 0;
1861 std::unordered_map< int, CharacterMetric >::const_iterator it =
1862 pFont->m_pMetrics->m_aMetrics.find( effectiveCode );
1863 // if no vertical metrics are available assume rotated horizontal metrics
1864 if( bVertical && (it == pFont->m_pMetrics->m_aMetrics.end()) )
1865 it = pFont->m_pMetrics->m_aMetrics.find( pString[i] );
1866 // the character metrics are in it->second
1867 if( it != pFont->m_pMetrics->m_aMetrics.end() )
1868 pArray[ i ] = it->second;
1872 return true;
1875 bool PrintFontManager::getMetrics( fontID nFontID, sal_Unicode minCharacter, sal_Unicode maxCharacter, CharacterMetric* pArray, bool bVertical ) const
1877 OSL_PRECOND(minCharacter <= maxCharacter, "invalid char. range");
1878 if (minCharacter > maxCharacter)
1879 return false;
1881 PrintFont* pFont = getFont( nFontID );
1882 if( ! pFont )
1883 return false;
1885 if( ( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
1886 || ! pFont->m_pMetrics || pFont->m_pMetrics->isEmpty()
1889 // might be a font not yet analyzed
1890 if( pFont->m_eType == fonttype::Type1 )
1891 pFont->readAfmMetrics( m_pAtoms, false, false );
1892 else if( pFont->m_eType == fonttype::TrueType )
1893 analyzeTrueTypeFile( pFont );
1896 sal_Unicode code = minCharacter;
1899 if( ! pFont->m_pMetrics ||
1900 ! ( pFont->m_pMetrics->m_aPages[ code >> 11 ] & ( 1 << ( ( code >> 8 ) & 7 ) ) ) )
1901 pFont->queryMetricPage( code >> 8, m_pAtoms );
1902 pArray[ code - minCharacter ].width = -1;
1903 pArray[ code - minCharacter ].height = -1;
1904 if( pFont->m_pMetrics )
1906 int effectiveCode = code;
1907 effectiveCode |= bVertical ? 1 << 16 : 0;
1908 std::unordered_map< int, CharacterMetric >::const_iterator it =
1909 pFont->m_pMetrics->m_aMetrics.find( effectiveCode );
1910 // if no vertical metrics are available assume rotated horizontal metrics
1911 if( bVertical && (it == pFont->m_pMetrics->m_aMetrics.end()) )
1912 it = pFont->m_pMetrics->m_aMetrics.find( code );
1913 // the character metrics are in it->second
1914 if( it != pFont->m_pMetrics->m_aMetrics.end() )
1915 pArray[ code - minCharacter ] = it->second;
1917 } while( code++ != maxCharacter );
1919 return true;
1922 // TODO: move most of this stuff into the central font-subsetting code
1923 bool PrintFontManager::createFontSubset(
1924 FontSubsetInfo& rInfo,
1925 fontID nFont,
1926 const OUString& rOutFile,
1927 const sal_GlyphId* pGlyphIds,
1928 const sal_uInt8* pNewEncoding,
1929 sal_Int32* pWidths,
1930 int nGlyphs,
1931 bool bVertical
1934 PrintFont* pFont = getFont( nFont );
1935 if( !pFont )
1936 return false;
1938 switch( pFont->m_eType )
1940 case psp::fonttype::TrueType: rInfo.m_nFontType = FontSubsetInfo::SFNT_TTF; break;
1941 case psp::fonttype::Type1: rInfo.m_nFontType = FontSubsetInfo::ANY_TYPE1; break;
1942 default:
1943 return false;
1945 // TODO: remove when Type1 subsetting gets implemented
1946 if( pFont->m_eType != fonttype::TrueType )
1947 return false;
1949 // reshuffle array of requested glyphs to make sure glyph0==notdef
1950 sal_uInt8 pEnc[256];
1951 sal_uInt16 pGID[256];
1952 sal_uInt8 pOldIndex[256];
1953 memset( pEnc, 0, sizeof( pEnc ) );
1954 memset( pGID, 0, sizeof( pGID ) );
1955 memset( pOldIndex, 0, sizeof( pOldIndex ) );
1956 if( nGlyphs > 256 )
1957 return false;
1958 int nChar = 1;
1959 for( int i = 0; i < nGlyphs; i++ )
1961 if( pNewEncoding[i] == 0 )
1963 pOldIndex[ 0 ] = i;
1965 else
1967 DBG_ASSERT( !(pGlyphIds[i] & 0x007f0000), "overlong glyph id" );
1968 DBG_ASSERT( (int)pNewEncoding[i] < nGlyphs, "encoding wrong" );
1969 DBG_ASSERT( pEnc[pNewEncoding[i]] == 0 && pGID[pNewEncoding[i]] == 0, "duplicate encoded glyph" );
1970 pEnc[ pNewEncoding[i] ] = pNewEncoding[i];
1971 pGID[ pNewEncoding[i] ] = (sal_uInt16)pGlyphIds[ i ];
1972 pOldIndex[ pNewEncoding[i] ] = i;
1973 nChar++;
1976 nGlyphs = nChar; // either input value or increased by one
1978 // prepare system name for read access for subset source file
1979 // TODO: since this file is usually already mmapped there is no need to open it again
1980 const OString aFromFile = getFontFile( pFont );
1982 TrueTypeFont* pTTFont = NULL; // TODO: rename to SfntFont
1983 TrueTypeFontFile* pTTFontFile = static_cast< TrueTypeFontFile* >(pFont);
1984 if( OpenTTFontFile( aFromFile.getStr(), pTTFontFile->m_nCollectionEntry, &pTTFont ) != SF_OK )
1985 return false;
1987 // prepare system name for write access for subset file target
1988 OUString aSysPath;
1989 if( osl_File_E_None != osl_getSystemPathFromFileURL( rOutFile.pData, &aSysPath.pData ) )
1990 return false;
1991 const rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
1992 const OString aToFile( OUStringToOString( aSysPath, aEncoding ) );
1994 // do CFF subsetting if possible
1995 int nCffLength = 0;
1996 const sal_uInt8* pCffBytes = NULL;
1997 if( GetSfntTable( pTTFont, O_CFF, &pCffBytes, &nCffLength ) )
1999 rInfo.LoadFont( FontSubsetInfo::CFF_FONT, pCffBytes, nCffLength );
2000 #if 1 // TODO: remove 16bit->long conversion when related methods handle non-16bit glyphids
2001 sal_GlyphId aRequestedGlyphIds[256];
2002 for( int i = 0; i < nGlyphs; ++i )
2003 aRequestedGlyphIds[i] = pGID[i];
2004 #endif
2005 // create subset file at requested path
2006 FILE* pOutFile = fopen( aToFile.getStr(), "wb" );
2007 if (!pOutFile)
2009 CloseTTFont( pTTFont );
2010 return false;
2012 // create font subset
2013 const char* pGlyphSetName = NULL; // TODO: better name?
2014 const bool bOK = rInfo.CreateFontSubset(
2015 FontSubsetInfo::TYPE1_PFB,
2016 pOutFile, pGlyphSetName,
2017 aRequestedGlyphIds, pEnc, nGlyphs, pWidths );
2018 fclose( pOutFile );
2019 // cleanup before early return
2020 CloseTTFont( pTTFont );
2021 return bOK;
2024 // do TTF->Type42 or Type3 subsetting
2025 // fill in font info
2026 psp::PrintFontInfo aFontInfo;
2027 if( ! getFontInfo( nFont, aFontInfo ) )
2028 return false;
2030 rInfo.m_nAscent = aFontInfo.m_nAscend;
2031 rInfo.m_nDescent = aFontInfo.m_nDescend;
2032 rInfo.m_aPSName = getPSName( nFont );
2034 int xMin, yMin, xMax, yMax;
2035 getFontBoundingBox( nFont, xMin, yMin, xMax, yMax );
2036 rInfo.m_aFontBBox = Rectangle( Point( xMin, yMin ), Size( xMax-xMin, yMax-yMin ) );
2037 rInfo.m_nCapHeight = yMax; // Well ...
2039 // fill in glyph advance widths
2040 TTSimpleGlyphMetrics* pMetrics = GetTTSimpleGlyphMetrics( pTTFont,
2041 pGID,
2042 nGlyphs,
2043 bVertical );
2044 if( pMetrics )
2046 for( int i = 0; i < nGlyphs; i++ )
2047 pWidths[pOldIndex[i]] = pMetrics[i].adv;
2048 free( pMetrics );
2050 else
2052 CloseTTFont( pTTFont );
2053 return false;
2056 bool bSuccess = ( SF_OK == CreateTTFromTTGlyphs( pTTFont,
2057 aToFile.getStr(),
2058 pGID,
2059 pEnc,
2060 nGlyphs,
2062 NULL,
2063 0 ) );
2064 CloseTTFont( pTTFont );
2066 return bSuccess;
2069 void PrintFontManager::getGlyphWidths( fontID nFont,
2070 bool bVertical,
2071 std::vector< sal_Int32 >& rWidths,
2072 std::map< sal_Unicode, sal_uInt32 >& rUnicodeEnc )
2074 PrintFont* pFont = getFont( nFont );
2075 if( !pFont ||
2076 (pFont->m_eType != fonttype::TrueType && pFont->m_eType != fonttype::Type1) )
2077 return;
2078 if( pFont->m_eType == fonttype::TrueType )
2080 TrueTypeFont* pTTFont = NULL;
2081 TrueTypeFontFile* pTTFontFile = static_cast< TrueTypeFontFile* >(pFont);
2082 OString aFromFile = getFontFile( pFont );
2083 if( OpenTTFontFile( aFromFile.getStr(), pTTFontFile->m_nCollectionEntry, &pTTFont ) != SF_OK )
2084 return;
2085 int nGlyphs = GetTTGlyphCount( pTTFont );
2086 if( nGlyphs > 0 )
2088 rWidths.resize(nGlyphs);
2089 std::vector<sal_uInt16> aGlyphIds(nGlyphs);
2090 for( int i = 0; i < nGlyphs; i++ )
2091 aGlyphIds[i] = sal_uInt16(i);
2092 TTSimpleGlyphMetrics* pMetrics = GetTTSimpleGlyphMetrics( pTTFont,
2093 &aGlyphIds[0],
2094 nGlyphs,
2095 bVertical );
2096 if( pMetrics )
2098 for( int i = 0; i< nGlyphs; i++ )
2099 rWidths[i] = pMetrics[i].adv;
2100 free( pMetrics );
2101 rUnicodeEnc.clear();
2104 // fill the unicode map
2105 // TODO: isn't this map already available elsewhere in the fontmanager?
2106 const sal_uInt8* pCmapData = NULL;
2107 int nCmapSize = 0;
2108 if( GetSfntTable( pTTFont, O_cmap, &pCmapData, &nCmapSize ) )
2110 CmapResult aCmapResult;
2111 if( ParseCMAP( pCmapData, nCmapSize, aCmapResult ) )
2113 FontCharMapPtr pCharMap( new FontCharMap(aCmapResult) );
2114 for( sal_uInt32 cOld = 0;;)
2116 // get next unicode covered by font
2117 const sal_uInt32 c = pCharMap->GetNextChar( cOld );
2118 if( c == cOld )
2119 break;
2120 cOld = c;
2121 #if 1 // TODO: remove when sal_Unicode covers all of unicode
2122 if( c > (sal_Unicode)~0 )
2123 break;
2124 #endif
2125 // get the matching glyph index
2126 const sal_GlyphId aGlyphId = pCharMap->GetGlyphIndex( c );
2127 // update the requested map
2128 rUnicodeEnc[ (sal_Unicode)c ] = aGlyphId;
2131 pCharMap = 0;
2135 CloseTTFont( pTTFont );
2137 else if( pFont->m_eType == fonttype::Type1 )
2139 if( ! pFont->m_aEncodingVector.size() )
2140 pFont->readAfmMetrics( m_pAtoms, true, true );
2141 if( pFont->m_pMetrics )
2143 rUnicodeEnc.clear();
2144 rWidths.clear();
2145 rWidths.reserve( pFont->m_pMetrics->m_aMetrics.size() );
2146 for( std::unordered_map< int, CharacterMetric >::const_iterator it =
2147 pFont->m_pMetrics->m_aMetrics.begin();
2148 it != pFont->m_pMetrics->m_aMetrics.end(); ++it )
2150 if( (it->first & 0x00010000) == 0 || bVertical )
2152 rUnicodeEnc[ sal_Unicode(it->first & 0x0000ffff) ] = sal_uInt32(rWidths.size());
2153 rWidths.push_back( it->second.width );
2160 const std::map< sal_Unicode, sal_Int32 >* PrintFontManager::getEncodingMap( fontID nFont, const std::map< sal_Unicode, OString >** pNonEncoded, std::set<sal_Unicode> const** ppPriority ) const
2162 PrintFont* pFont = getFont( nFont );
2163 if( !pFont || pFont->m_eType != fonttype::Type1 )
2164 return NULL;
2166 if( ! pFont->m_aEncodingVector.size() )
2167 pFont->readAfmMetrics( m_pAtoms, true, true );
2169 if( pNonEncoded )
2170 *pNonEncoded = pFont->m_aNonEncoded.size() ? &pFont->m_aNonEncoded : NULL;
2172 if (ppPriority)
2174 *ppPriority = &pFont->m_aEncodingVectorPriority;
2177 return pFont->m_aEncodingVector.size() ? &pFont->m_aEncodingVector : NULL;
2180 std::list< OString > PrintFontManager::getAdobeNameFromUnicode( sal_Unicode aChar ) const
2182 std::pair< std::unordered_multimap< sal_Unicode, OString >::const_iterator,
2183 std::unordered_multimap< sal_Unicode, OString >::const_iterator > range
2184 = m_aUnicodeToAdobename.equal_range( aChar );
2186 std::list< OString > aRet;
2187 for( ; range.first != range.second; ++range.first )
2188 aRet.push_back( range.first->second );
2190 if( aRet.begin() == aRet.end() && aChar != 0 )
2192 sal_Char aBuf[8];
2193 sal_Int32 nChars = snprintf( (char*)aBuf, sizeof( aBuf ), "uni%.4hX", aChar );
2194 aRet.push_back( OString( aBuf, nChars ) );
2197 return aRet;
2200 std::list< sal_Unicode > PrintFontManager::getUnicodeFromAdobeName( const OString& rName ) const
2202 std::pair< std::unordered_multimap< OString, sal_Unicode, OStringHash >::const_iterator,
2203 std::unordered_multimap< OString, sal_Unicode, OStringHash >::const_iterator > range
2204 = m_aAdobenameToUnicode.equal_range( rName );
2206 std::list< sal_Unicode > aRet;
2207 for( ; range.first != range.second; ++range.first )
2208 aRet.push_back( range.first->second );
2210 if( aRet.begin() == aRet.end() )
2212 if( rName.getLength() == 7 && rName.startsWith( "uni" ) )
2214 sal_Unicode aCode = (sal_Unicode)rName.copy( 3 ).toUInt32( 16 );
2215 aRet.push_back( aCode );
2219 return aRet;
2222 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */