1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
24 #include <osl/thread.h>
26 #include "unotools/atom.hxx"
28 #include "fontcache.hxx"
29 #include "fontsubset.hxx"
30 #include "impfont.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"
57 #if OSL_DEBUG_LEVEL > 1
58 #include <sys/times.h>
62 #include "sal/alloca.h"
66 #include <unordered_set>
68 #include "adobeenc.tab"
70 #ifdef CALLGRIND_COMPILE
71 #include <valgrind/callgrind.h>
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"
83 using namespace com::sun::star::uno
;
84 using namespace com::sun::star::beans
;
85 using namespace com::sun::star::lang
;
91 inline sal_uInt16
getUInt16BE( const sal_uInt8
*& pBuffer
)
93 sal_uInt16 nRet
= (sal_uInt16
)pBuffer
[1] |
94 (((sal_uInt16
)pBuffer
[0]) << 8);
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
;
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
;
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
;
132 eWeight
= WEIGHT_NORMAL
;
137 * PrintFont implementations
139 PrintFontManager::PrintFont::PrintFont( fonttype::type eType
) :
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 ),
157 m_bHaveVerticalSubstitutedGlyphs( false ),
158 m_bUserOverride( false )
162 PrintFontManager::PrintFont::~PrintFont()
167 PrintFontManager::Type1FontFile::~Type1FontFile()
171 PrintFontManager::TrueTypeFontFile::TrueTypeFontFile()
172 : PrintFont( fonttype::TrueType
)
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
)
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 ));
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 );
214 for( i
= 0; i
< nCharacters
; i
++ )
218 CharacterMetric
& rChar
= m_pMetrics
->m_aMetrics
[ nPage
*256 + i
];
219 rChar
.width
= pMetrics
[ i
].adv
;
220 rChar
.height
= m_aGlobalMetricX
.height
;
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 );
233 for( i
= 0; i
< nCharacters
; 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;
246 CloseTTFont( pTTFont
);
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() );
273 o_rFamilyName
= it
->second
;
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
)
287 freeFontInfo( pInfo
);
291 m_aEncodingVector
.clear();
292 m_aEncodingVectorPriority
.clear();
293 // fill in global info
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)
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 );
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() ) );
326 if( pInfo
->gfi
->italicAngle
> 0 )
327 m_eItalic
= ITALIC_OBLIQUE
;
328 else if( pInfo
->gfi
->italicAngle
< 0 )
329 m_eItalic
= ITALIC_NORMAL
;
331 m_eItalic
= ITALIC_NONE
;
334 OString
aWeight( pInfo
->gfi
->weight
);
335 m_eWeight
= parseWeight( aWeight
.toAsciiLowerCase() );
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" ) )
346 else if( !strcmp( pInfo
->gfi
->encodingScheme
, "ISO10646-1" ) )
349 m_aEncoding
= RTL_TEXTENCODING_UNICODE
;
351 else if( !strcmp( pInfo
->gfi
->encodingScheme
, "Symbol") )
353 else if( !strcmp( pInfo
->gfi
->encodingScheme
, "FontSpecific") )
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
[] =
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
) );
391 if( aToken
.equalsAscii( pEncs
[enc
] ) )
393 m_aEncoding
= aEncs
[ enc
];
394 m_bFontEncodingOnly
= true;
396 } while( nIndex
!= -1 );
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
);
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
++ )
417 if( pChar
[j
].name
[0] == 'Y' && pChar
[j
].name
[1] == 0 )
419 else if( pChar
[j
].name
[0] == 'Q' && pChar
[j
].name
[1] == 0 )
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
,
432 m_aEncoding
= RTL_TEXTENCODING_UNICODE
;
433 bFillEncodingvector
= false; // will be filled anyway, don't do the work twice
438 m_nAscend
= pInfo
->gfi
->fontBBox
.ury
;
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
448 m_nAscend
= pInfo
->gfi
->ascender
;
450 m_nDescend
= -pInfo
->gfi
->descender
;
452 m_nLeading
= m_nAscend
+ m_nDescend
- 1000;
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
;
479 for( i
= 0; i
< pInfo
->numOfChars
; i
++, pChar
++ )
481 if( nAdobeEncoding
== 4 )
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
)
491 m_aEncodingVector
[ *it
] = pChar
->code
;
492 if( pChar
->code
== -1 )
493 m_aNonEncoded
[ *it
] = pChar
->name
;
494 if( ! pUnicodes
[i
] ) // map the first
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
]);
513 if( m_aEncoding
== RTL_TEXTENCODING_UNICODE
)
515 pUnicodes
[i
] = (sal_Unicode
)pChar
->code
;
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();
534 // now fill in the character metrics
535 // parseAFM.cxx effectively only supports direction 0 (horizontal)
537 CharacterMetric aMetric
;
538 for( i
= 0; i
< pInfo
->numOfChars
; i
++, pChar
++ )
540 if( pChar
->code
== -1 && ! pChar
->name
)
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
)
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
)
581 m_pMetrics
->m_aMetrics
[ *it
] = aMetric
;
585 else if( nAdobeEncoding
== 1 || nAdobeEncoding
== 2 || nAdobeEncoding
== 4)
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
)
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
);
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
);
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
);
645 PrintFontManager
& PrintFontManager::get()
647 static PrintFontManager
* pManager
= NULL
;
650 static PrintFontManager theManager
;
651 pManager
= &theManager
;
652 pManager
->initialize();
658 * the PrintFontManager
661 PrintFontManager::PrintFontManager()
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();
686 for( std::unordered_map
< fontID
, PrintFont
* >::const_iterator it
= m_aFonts
.begin(); it
!= m_aFonts
.end(); ++it
)
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
)
701 std::unordered_map
< OString
, int, OStringHash
>::const_iterator it
702 ( m_aDirToAtom
.find( rDirectory
) );
703 if( it
!= m_aDirToAtom
.end() )
707 nAtom
= m_nNextDirAtom
++;
708 m_aDirToAtom
[ rDirectory
] = nAtom
;
709 m_aAtomToDir
[ nAtom
] = rDirectory
;
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
);
745 UNKNOWN
, TRUETYPE
, CFF
, TYPE1
748 bool PrintFontManager::analyzeFontFile( int nDirID
, const OString
& rFontFile
, ::std::list
< PrintFontManager::PrintFont
* >& rNewFonts
, const char *pFormat
) const
752 OString
aDir( getDirectory( nDirID
) );
754 OString
aFullPath( aDir
);
756 aFullPath
+= rFontFile
;
758 // #i1872# reject unreadable files
759 if( access( aFullPath
.getStr(), R_OK
) )
762 fontFormat eFormat
= UNKNOWN
;
765 if (!strcmp(pFormat
, "TrueType"))
767 else if (!strcmp(pFormat
, "CFF"))
769 else if (!strcmp(pFormat
, "Type 1"))
772 if (eFormat
== UNKNOWN
)
774 OString
aExt( rFontFile
.copy( rFontFile
.lastIndexOf( '.' )+1 ) );
775 if( aExt
.equalsIgnoreAsciiCase("pfb") || aExt
.equalsIgnoreAsciiCase("pfa") )
777 else if( aExt
.equalsIgnoreAsciiCase("ttf")
778 || aExt
.equalsIgnoreAsciiCase("ttc")
779 || aExt
.equalsIgnoreAsciiCase("tte") ) // #i33947# for Gaiji support
781 else if( aExt
.equalsIgnoreAsciiCase("otf") ) // check for TTF- and PS-OpenType too
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
);
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
;
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 ) )
826 rNewFonts
.push_back( pFont
);
831 else if (eFormat
== TRUETYPE
|| eFormat
== CFF
)
833 // get number of ttc entries
834 int nLength
= CountTTCFonts( aFullPath
.getStr() );
837 #if OSL_DEBUG_LEVEL > 1
838 fprintf( stderr
, "ttc: %s contains %d fonts\n", aFullPath
.getStr(), nLength
);
841 sal_uInt64 fileSize
= 0;
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
) )
879 rNewFonts
.push_back( pFont
);
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
) )
896 rNewFonts
.push_back( pFont
);
899 return ! rNewFonts
.empty();
902 fontID
PrintFontManager::findFontFileID( int nDirID
, const OString
& rFontFile
, int nFaceIndex
) const
906 std::unordered_map
< OString
, ::std::set
< fontID
>, OStringHash
>::const_iterator set_it
= m_aFontFileToFontID
.find( rFontFile
);
907 if( set_it
== m_aFontFileToFontID
.end() )
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() )
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
)
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
)
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() )
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() )
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
);
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
);
980 OUString
PrintFontManager::convertTrueTypeName( void* pRecord
)
982 NameRecord
* pNameRecord
= static_cast<NameRecord
*>(pRecord
);
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;
1013 aName
.append( aChar
);
1014 aChar
= aCode
& 0x00ff;
1016 aName
.append( aChar
);
1018 switch( pNameRecord
->encodingID
)
1021 aValue
= OStringToOUString( aName
.makeStringAndClear(), RTL_TEXTENCODING_MS_932
);
1024 aValue
= OStringToOUString( aName
.makeStringAndClear(), RTL_TEXTENCODING_MS_936
);
1027 aValue
= OStringToOUString( aName
.makeStringAndClear(), RTL_TEXTENCODING_MS_950
);
1030 aValue
= OStringToOUString( aName
.makeStringAndClear(), RTL_TEXTENCODING_MS_949
);
1033 aValue
= OStringToOUString( aName
.makeStringAndClear(), RTL_TEXTENCODING_MS_1361
);
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
)
1045 eEncoding
= RTL_TEXTENCODING_APPLE_ROMAN
;
1048 eEncoding
= RTL_TEXTENCODING_APPLE_JAPANESE
;
1051 eEncoding
= RTL_TEXTENCODING_APPLE_CHINTRAD
;
1054 eEncoding
= RTL_TEXTENCODING_APPLE_KOREAN
;
1057 eEncoding
= RTL_TEXTENCODING_APPLE_ARABIC
;
1060 eEncoding
= RTL_TEXTENCODING_APPLE_HEBREW
;
1063 eEncoding
= RTL_TEXTENCODING_APPLE_GREEK
;
1066 eEncoding
= RTL_TEXTENCODING_APPLE_CYRILLIC
;
1069 eEncoding
= RTL_TEXTENCODING_APPLE_DEVANAGARI
;
1072 eEncoding
= RTL_TEXTENCODING_APPLE_GURMUKHI
;
1075 eEncoding
= RTL_TEXTENCODING_APPLE_GUJARATI
;
1078 eEncoding
= RTL_TEXTENCODING_APPLE_THAI
;
1081 eEncoding
= RTL_TEXTENCODING_APPLE_CHINSIMP
;
1084 eEncoding
= RTL_TEXTENCODING_APPLE_CENTEURO
;
1086 case 32: //Uninterpreted
1087 eEncoding
= RTL_TEXTENCODING_UTF8
;
1090 SAL_WARN("vcl", "Unimplmented mac encoding " << pNameRecord
->encodingID
<< " to unicode conversion");
1093 if (eEncoding
!= RTL_TEXTENCODING_DONTKNOW
)
1094 aValue
= OStringToOUString(aName
, eEncoding
);
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
1106 bool isBadTNR(const OUString
&rName
, ::std::set
< OUString
>& rSet
)
1109 if ( rName
== "Berling Antiqua" )
1111 ::std::set
< OUString
>::iterator aEnd
= rSet
.end();
1112 ::std::set
< OUString
>::iterator aI
= rSet
.find("Times New Roman");
1123 void PrintFontManager::analyzeTrueTypeFamilyName( void* pTTFont
, ::std::list
< OUString
>& rNames
)
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
)
1142 if( pNameRecords
[i
].platformID
== 0 ) // Unicode
1144 else if( pNameRecords
[i
].platformID
== 3 )
1146 // this bases on the LanguageType actually being a Win LCID
1147 if (pNameRecords
[i
].languageID
== eLang
)
1149 else if( pNameRecords
[i
].languageID
== LANGUAGE_ENGLISH_US
)
1151 else if( pNameRecords
[i
].languageID
== LANGUAGE_ENGLISH
||
1152 pNameRecords
[i
].languageID
== LANGUAGE_ENGLISH_UK
)
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
)
1163 else if (aAppleId
== AppleLanguageId::ENGLISH
)
1168 OUString aName
= convertTrueTypeName( pNameRecords
+ i
);
1169 aSet
.insert( aName
);
1170 if (aName
.isEmpty())
1172 if( nMatch
> nLastMatch
|| isBadTNR(aName
, aSet
) )
1174 nLastMatch
= nMatch
;
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
);
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 );
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;
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;
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
;
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
;
1327 pFont
->m_nXMin
= aInfo
.xMin
;
1328 pFont
->m_nYMin
= aInfo
.yMin
;
1329 pFont
->m_nXMax
= aInfo
.xMax
;
1330 pFont
->m_nYMax
= aInfo
.yMax
;
1333 pTTFontFile
->m_nTypeFlags
= (unsigned int)aInfo
.typeFlags
;
1335 // get vertical substitutions flag
1336 pFont
->m_bHaveVerticalSubstitutedGlyphs
= DoesVerticalSubstitution( pTTFont
, 1 );
1338 CloseTTFont( pTTFont
);
1341 #if OSL_DEBUG_LEVEL > 1
1343 fprintf( stderr
, "could not OpenTTFont \"%s\"\n", aFile
.getStr() );
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();
1361 if( ! m_pFontCache
)
1363 #if OSL_DEBUG_LEVEL > 1
1364 fprintf( stderr
, "creating font cache ... " );
1367 aStart
= times( &tms
);
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
) );
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
;
1384 m_aFontDirectories
.clear();
1385 m_aPrivateFontDirectories
.clear();
1388 #if OSL_DEBUG_LEVEL > 1
1395 aStart
= times( &tms
);
1398 // first try fontconfig
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
);
1416 if ( aToken
.isEmpty() )
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
)
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() )
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() );
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
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() );
1474 if( ! m_pFontCache
->scanAdditionalFiles( aPath
) )
1480 #if OSL_DEBUG_LEVEL > 1
1481 aStep1
= times( &tms
);
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())
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
);
1506 m_pFontCache
->flush();
1508 #ifdef CALLGRIND_COMPILE
1509 CALLGRIND_DUMP_STATS();
1510 CALLGRIND_TOGGLE_COLLECT();
1514 void PrintFontManager::getFontList( ::std::list
< fontID
>& rFontIDs
)
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
);
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
);
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
);
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
);
1603 xMin
= pFont
->m_nXMin
;
1604 yMin
= pFont
->m_nYMin
;
1605 xMax
= pFont
->m_nXMax
;
1606 yMax
= pFont
->m_nYMax
;
1611 int PrintFontManager::getFontFaceNumber( fontID nFontID
) const
1614 PrintFont
* pFont
= getFont( nFontID
);
1615 if( pFont
&& pFont
->m_eType
== fonttype::TrueType
)
1616 nRet
= static_cast< TrueTypeFontFile
* >(pFont
)->m_nCollectionEntry
;
1622 FontFamily
PrintFontManager::matchFamilyName( const OUString
& rFamily
)
1626 sal_uInt16 mnLength
;
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 )
1678 if( nComparison
> 0 )
1679 nLower
= nCurrent
+ 1;
1681 return pHaystack
->meType
;
1684 return FAMILY_DONTKNOW
;
1687 OString
PrintFontManager::getAfmFile( PrintFont
* pFont
) const
1689 OString aMetricPath
;
1692 switch( pFont
->m_eType
)
1694 case fonttype::Type1
:
1696 Type1FontFile
* pPSFont
= static_cast< Type1FontFile
* >(pFont
);
1697 aMetricPath
= getDirectory( pPSFont
->m_nDirectory
);
1699 aMetricPath
+= pPSFont
->m_aMetricFile
;
1708 OString
PrintFontManager::getFontFile( PrintFont
* pFont
) const
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
);
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
);
1726 aPath
+= pTTFont
->m_aFontFile
;
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
);
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" );
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
)
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;
1834 bool PrintFontManager::getMetrics( fontID nFontID
, const sal_Unicode
* pString
, int nLen
, CharacterMetric
* pArray
, bool bVertical
) const
1836 PrintFont
* pFont
= getFont( nFontID
);
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
;
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
)
1881 PrintFont
* pFont
= getFont( nFontID
);
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
);
1922 // TODO: move most of this stuff into the central font-subsetting code
1923 bool PrintFontManager::createFontSubset(
1924 FontSubsetInfo
& rInfo
,
1926 const OUString
& rOutFile
,
1927 const sal_GlyphId
* pGlyphIds
,
1928 const sal_uInt8
* pNewEncoding
,
1934 PrintFont
* pFont
= getFont( nFont
);
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;
1945 // TODO: remove when Type1 subsetting gets implemented
1946 if( pFont
->m_eType
!= fonttype::TrueType
)
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
) );
1959 for( int i
= 0; i
< nGlyphs
; i
++ )
1961 if( pNewEncoding
[i
] == 0 )
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
;
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
)
1987 // prepare system name for write access for subset file target
1989 if( osl_File_E_None
!= osl_getSystemPathFromFileURL( rOutFile
.pData
, &aSysPath
.pData
) )
1991 const rtl_TextEncoding aEncoding
= osl_getThreadTextEncoding();
1992 const OString
aToFile( OUStringToOString( aSysPath
, aEncoding
) );
1994 // do CFF subsetting if possible
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
];
2005 // create subset file at requested path
2006 FILE* pOutFile
= fopen( aToFile
.getStr(), "wb" );
2009 CloseTTFont( pTTFont
);
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
);
2019 // cleanup before early return
2020 CloseTTFont( pTTFont
);
2024 // do TTF->Type42 or Type3 subsetting
2025 // fill in font info
2026 psp::PrintFontInfo aFontInfo
;
2027 if( ! getFontInfo( nFont
, aFontInfo
) )
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
,
2046 for( int i
= 0; i
< nGlyphs
; i
++ )
2047 pWidths
[pOldIndex
[i
]] = pMetrics
[i
].adv
;
2052 CloseTTFont( pTTFont
);
2056 bool bSuccess
= ( SF_OK
== CreateTTFromTTGlyphs( pTTFont
,
2064 CloseTTFont( pTTFont
);
2069 void PrintFontManager::getGlyphWidths( fontID nFont
,
2071 std::vector
< sal_Int32
>& rWidths
,
2072 std::map
< sal_Unicode
, sal_uInt32
>& rUnicodeEnc
)
2074 PrintFont
* pFont
= getFont( nFont
);
2076 (pFont
->m_eType
!= fonttype::TrueType
&& pFont
->m_eType
!= fonttype::Type1
) )
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
)
2085 int nGlyphs
= GetTTGlyphCount( pTTFont
);
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
,
2098 for( int i
= 0; i
< nGlyphs
; i
++ )
2099 rWidths
[i
] = pMetrics
[i
].adv
;
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
;
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
);
2121 #if 1 // TODO: remove when sal_Unicode covers all of unicode
2122 if( c
> (sal_Unicode
)~0 )
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
;
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();
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
)
2166 if( ! pFont
->m_aEncodingVector
.size() )
2167 pFont
->readAfmMetrics( m_pAtoms
, true, true );
2170 *pNonEncoded
= pFont
->m_aNonEncoded
.size() ? &pFont
->m_aNonEncoded
: NULL
;
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 )
2193 sal_Int32 nChars
= snprintf( (char*)aBuf
, sizeof( aBuf
), "uni%.4hX", aChar
);
2194 aRet
.push_back( OString( aBuf
, nChars
) );
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
);
2222 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */