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