LCOV - code coverage report
Current view: top level - libreoffice/vcl/generic/fontmanager - fontmanager.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 487 1508 32.3 %
Date: 2012-12-27 Functions: 31 71 43.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       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/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      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 .
      18             :  */
      19             : 
      20             : 
      21             : #include <unistd.h>
      22             : #include <sys/stat.h>
      23             : #include <dirent.h>
      24             : #include <stdlib.h>
      25             : #include <osl/thread.h>
      26             : 
      27             : #include "unotools/atom.hxx"
      28             : 
      29             : #include "fontcache.hxx"
      30             : #include "fontsubset.hxx"
      31             : #include "impfont.hxx"
      32             : #include "svdata.hxx"
      33             : #include "generic/geninst.h"
      34             : #include "vcl/fontmanager.hxx"
      35             : #include "vcl/strhelper.hxx"
      36             : #include "vcl/ppdparser.hxx"
      37             : #include <vcl/temporaryfonts.hxx>
      38             : 
      39             : #include "tools/urlobj.hxx"
      40             : #include "tools/stream.hxx"
      41             : #include "tools/debug.hxx"
      42             : 
      43             : #include "osl/file.hxx"
      44             : #include "osl/process.h"
      45             : 
      46             : #include "rtl/tencinfo.h"
      47             : #include "rtl/ustrbuf.hxx"
      48             : #include "rtl/strbuf.hxx"
      49             : 
      50             : #include <sal/macros.h>
      51             : 
      52             : #include "i18npool/mslangid.hxx"
      53             : 
      54             : 
      55             : #include "parseAFM.hxx"
      56             : #include "sft.hxx"
      57             : 
      58             : #if OSL_DEBUG_LEVEL > 1
      59             : #include <sys/times.h>
      60             : #include <stdio.h>
      61             : #endif
      62             : 
      63             : #include "sal/alloca.h"
      64             : 
      65             : #include <set>
      66             : #include <boost/unordered_set.hpp>
      67             : #include <algorithm>
      68             : 
      69             : #include "adobeenc.tab" // get encoding table for AFM metrics
      70             : 
      71             : #ifdef CALLGRIND_COMPILE
      72             : #include <valgrind/callgrind.h>
      73             : #endif
      74             : 
      75             : #include <comphelper/processfactory.hxx>
      76             : #include <comphelper/string.hxx>
      77             : #include "com/sun/star/beans/XMaterialHolder.hpp"
      78             : #include "com/sun/star/beans/NamedValue.hpp"
      79             : 
      80             : #define PRINTER_METRICDIR "fontmetric"
      81             : 
      82             : using namespace vcl;
      83             : using namespace utl;
      84             : using namespace psp;
      85             : using namespace osl;
      86             : using namespace com::sun::star::uno;
      87             : using namespace com::sun::star::beans;
      88             : using namespace com::sun::star::lang;
      89             : 
      90             : using ::comphelper::string::getToken;
      91             : using ::rtl::OUString;
      92             : using ::rtl::OString;
      93             : using ::rtl::OStringHash;
      94             : using ::rtl::OStringBuffer;
      95             : using ::rtl::OUStringBuffer;
      96             : using ::rtl::OUStringHash;
      97             : using ::rtl::OStringToOUString;
      98             : using ::rtl::OUStringToOString;
      99             : 
     100             : /*
     101             :  *  static helpers
     102             :  */
     103             : 
     104        2356 : inline sal_uInt16 getUInt16BE( const sal_uInt8*& pBuffer )
     105             : {
     106        2356 :     sal_uInt16 nRet = (sal_uInt16)pBuffer[1] |
     107        2356 :         (((sal_uInt16)pBuffer[0]) << 8);
     108        2356 :     pBuffer+=2;
     109        2356 :     return nRet;
     110             : }
     111             : 
     112           0 : inline sal_uInt32 getUInt32BE( const sal_uInt8*& pBuffer )
     113             : {
     114           0 :     sal_uInt32 nRet = (((sal_uInt32)pBuffer[0]) << 24) |
     115           0 :                       (((sal_uInt32)pBuffer[1]) << 16) |
     116           0 :                       (((sal_uInt32)pBuffer[2]) << 8)  |
     117           0 :                       (((sal_uInt32)pBuffer[3]) );
     118           0 :     pBuffer += 4;
     119           0 :     return nRet;
     120             : }
     121             : 
     122             : // -------------------------------------------------------------------------
     123             : 
     124          70 : static FontWeight parseWeight( const rtl::OString& rWeight )
     125             : {
     126          70 :     FontWeight eWeight = WEIGHT_DONTKNOW;
     127          70 :     if (rWeight.indexOfL(RTL_CONSTASCII_STRINGPARAM("bold") ) != -1)
     128             :     {
     129          28 :         if (rWeight.indexOfL(RTL_CONSTASCII_STRINGPARAM("emi")) != -1) // semi, demi
     130           0 :             eWeight = WEIGHT_SEMIBOLD;
     131          28 :         else if (rWeight.indexOfL(RTL_CONSTASCII_STRINGPARAM("ultra")) != -1)
     132           0 :             eWeight = WEIGHT_ULTRABOLD;
     133             :         else
     134          28 :             eWeight = WEIGHT_BOLD;
     135             :     }
     136          42 :     else if (rWeight.indexOfL(RTL_CONSTASCII_STRINGPARAM("heavy")) != -1)
     137           0 :         eWeight = WEIGHT_BOLD;
     138          42 :     else if (rWeight.indexOfL(RTL_CONSTASCII_STRINGPARAM("light")) != -1)
     139             :     {
     140           0 :         if (rWeight.indexOfL(RTL_CONSTASCII_STRINGPARAM("emi")) != -1) // semi, demi
     141           0 :             eWeight = WEIGHT_SEMILIGHT;
     142           0 :         else if (rWeight.indexOfL(RTL_CONSTASCII_STRINGPARAM("ultra")) != -1)
     143           0 :             eWeight = WEIGHT_ULTRALIGHT;
     144             :         else
     145           0 :             eWeight = WEIGHT_LIGHT;
     146             :     }
     147          42 :     else if (rWeight.indexOfL(RTL_CONSTASCII_STRINGPARAM("black")) != -1)
     148           0 :         eWeight = WEIGHT_BLACK;
     149          42 :     else if (rWeight.equalsL(RTL_CONSTASCII_STRINGPARAM("demi")))
     150           4 :         eWeight = WEIGHT_SEMIBOLD;
     151          72 :     else if (rWeight.equalsL(RTL_CONSTASCII_STRINGPARAM("book")) ||
     152          34 :              rWeight.equalsL(RTL_CONSTASCII_STRINGPARAM("semicondensed")))
     153           4 :         eWeight = WEIGHT_LIGHT;
     154          34 :     else if (rWeight.equalsL(RTL_CONSTASCII_STRINGPARAM("medium")) || rWeight.equalsL(RTL_CONSTASCII_STRINGPARAM("roman")))
     155           6 :         eWeight = WEIGHT_MEDIUM;
     156             :     else
     157          28 :         eWeight = WEIGHT_NORMAL;
     158          70 :     return eWeight;
     159             : }
     160             : 
     161             : /*
     162             :  *  PrintFont implementations
     163             :  */
     164        4920 : PrintFontManager::PrintFont::PrintFont( fonttype::type eType ) :
     165             :         m_eType( eType ),
     166             :         m_nFamilyName( 0 ),
     167             :         m_nPSName( 0 ),
     168             :         m_eItalic( ITALIC_DONTKNOW ),
     169             :         m_eWidth( WIDTH_DONTKNOW ),
     170             :         m_eWeight( WEIGHT_DONTKNOW ),
     171             :         m_ePitch( PITCH_DONTKNOW ),
     172             :         m_aEncoding( RTL_TEXTENCODING_DONTKNOW ),
     173             :         m_bFontEncodingOnly( false ),
     174             :         m_pMetrics( NULL ),
     175             :         m_nAscend( 0 ),
     176             :         m_nDescend( 0 ),
     177             :         m_nLeading( 0 ),
     178             :         m_nXMin( 0 ),
     179             :         m_nYMin( 0 ),
     180             :         m_nXMax( 0 ),
     181             :         m_nYMax( 0 ),
     182             :         m_bHaveVerticalSubstitutedGlyphs( false ),
     183        4920 :         m_bUserOverride( false )
     184             : {
     185        4920 : }
     186             : 
     187             : // -------------------------------------------------------------------------
     188             : 
     189        9840 : PrintFontManager::PrintFont::~PrintFont()
     190             : {
     191        4920 :     if( m_pMetrics )
     192          70 :         delete m_pMetrics;
     193        4920 : }
     194             : 
     195             : // -------------------------------------------------------------------------
     196             : 
     197        2800 : PrintFontManager::Type1FontFile::~Type1FontFile()
     198             : {
     199        2800 : }
     200             : 
     201             : // -------------------------------------------------------------------------
     202             : 
     203        3520 : PrintFontManager::TrueTypeFontFile::TrueTypeFontFile()
     204             : :   PrintFont( fonttype::TrueType )
     205             : ,   m_nDirectory( 0 )
     206             : ,   m_nCollectionEntry( 0 )
     207        3520 : ,   m_nTypeFlags( TYPEFLAG_INVALID )
     208        3520 : {}
     209             : 
     210             : // -------------------------------------------------------------------------
     211             : 
     212        7040 : PrintFontManager::TrueTypeFontFile::~TrueTypeFontFile()
     213             : {
     214        7040 : }
     215             : 
     216             : // -------------------------------------------------------------------------
     217             : 
     218           0 : PrintFontManager::BuiltinFont::~BuiltinFont()
     219             : {
     220           0 : }
     221             : 
     222             : // -------------------------------------------------------------------------
     223             : 
     224           0 : bool PrintFontManager::Type1FontFile::queryMetricPage( int /*nPage*/, MultiAtomProvider* pProvider )
     225             : {
     226           0 :     return readAfmMetrics( PrintFontManager::get().getAfmFile( this ), pProvider, false, false );
     227             : }
     228             : 
     229             : // -------------------------------------------------------------------------
     230             : 
     231           0 : bool PrintFontManager::BuiltinFont::queryMetricPage( int /*nPage*/, MultiAtomProvider* pProvider )
     232             : {
     233           0 :     return readAfmMetrics( PrintFontManager::get().getAfmFile( this ), pProvider, false, false );
     234             : }
     235             : 
     236             : // -------------------------------------------------------------------------
     237             : 
     238           0 : bool PrintFontManager::TrueTypeFontFile::queryMetricPage( int nPage, MultiAtomProvider* pProvider )
     239             : {
     240           0 :     bool bSuccess = false;
     241             : 
     242           0 :     rtl::OString aFile( PrintFontManager::get().getFontFile( this ) );
     243             : 
     244           0 :     TrueTypeFont* pTTFont = NULL;
     245             : 
     246           0 :     if( OpenTTFontFile( aFile.getStr(), m_nCollectionEntry, &pTTFont ) == SF_OK )
     247             :     {
     248           0 :         if( ! m_pMetrics )
     249             :         {
     250           0 :             m_pMetrics = new PrintFontMetrics;
     251           0 :             memset (m_pMetrics->m_aPages, 0, sizeof(m_pMetrics->m_aPages));
     252             :         }
     253           0 :         m_pMetrics->m_aPages[ nPage/8 ] |= (1 << ( nPage & 7 ));
     254             :         int i;
     255             :         sal_uInt16 table[256], table_vert[256];
     256             : 
     257           0 :         for( i = 0; i < 256; i++ )
     258           0 :             table[ i ] = 256*nPage + i;
     259             : 
     260           0 :         int nCharacters = nPage < 255 ? 256 : 254;
     261           0 :         MapString( pTTFont, table, nCharacters, NULL, 0 );
     262           0 :         TTSimpleGlyphMetrics* pMetrics = GetTTSimpleCharMetrics( pTTFont, nPage*256, nCharacters, 0 );
     263           0 :         if( pMetrics )
     264             :         {
     265           0 :             for( i = 0; i < nCharacters; i++ )
     266             :             {
     267           0 :                 if( table[i] )
     268             :                 {
     269           0 :                     CharacterMetric& rChar = m_pMetrics->m_aMetrics[ nPage*256 + i ];
     270           0 :                     rChar.width = pMetrics[ i ].adv;
     271           0 :                     rChar.height = m_aGlobalMetricX.height;
     272             :                 }
     273             :             }
     274             : 
     275           0 :             free( pMetrics );
     276             :         }
     277             : 
     278           0 :         for( i = 0; i < 256; i++ )
     279           0 :             table_vert[ i ] = 256*nPage + i;
     280           0 :         MapString( pTTFont, table_vert, nCharacters, NULL, 1 );
     281           0 :         pMetrics = GetTTSimpleCharMetrics( pTTFont, nPage*256, nCharacters, 1 );
     282           0 :         if( pMetrics )
     283             :         {
     284           0 :             for( i = 0; i < nCharacters; i++ )
     285             :             {
     286           0 :                 if( table_vert[i] )
     287             :                 {
     288           0 :                     CharacterMetric& rChar = m_pMetrics->m_aMetrics[ nPage*256 + i + ( 1 << 16 ) ];
     289           0 :                     rChar.width = m_aGlobalMetricY.width;
     290           0 :                     rChar.height = pMetrics[ i ].adv;
     291           0 :                     if( table_vert[i] != table[i] )
     292           0 :                         m_pMetrics->m_bVerticalSubstitutions[ nPage*256 + i ] = 1;
     293             :                 }
     294             :             }
     295           0 :             free( pMetrics );
     296             :         }
     297             : 
     298           0 :         if( ! m_pMetrics->m_bKernPairsQueried )
     299             :         {
     300           0 :             m_pMetrics->m_bKernPairsQueried = true;
     301             :             // this is really a hack
     302             :             // in future MapString/KernGlyphs should be used
     303             :             // but vcl is not in a state where that could be used
     304             :             // so currently we get kernpairs by accessing the raw data
     305           0 :             struct _TrueTypeFont* pImplTTFont = (struct _TrueTypeFont*)pTTFont;
     306             : 
     307             :             //-----------------------------------------------------------------
     308             :             // Kerning:  KT_MICROSOFT
     309             :             //-----------------------------------------------------------------
     310           0 :             if( pImplTTFont->nkern && pImplTTFont->kerntype == KT_MICROSOFT )
     311             :             {
     312             :                 // create a glyph -> character mapping
     313           0 :                 ::boost::unordered_map< sal_uInt16, sal_Unicode > aGlyphMap;
     314           0 :                 ::boost::unordered_map< sal_uInt16, sal_Unicode >::iterator left, right;
     315           0 :                 for( i = 21; i < 0xfffd; i++ )
     316             :                 {
     317           0 :                     sal_uInt16 nGlyph = MapChar( pTTFont, (sal_Unicode)i, 0 ); // kerning for horz only
     318           0 :                     if( nGlyph != 0 )
     319           0 :                         aGlyphMap[ nGlyph ] = (sal_Unicode)i;
     320             :                 }
     321             : 
     322             : 
     323           0 :                 KernPair aPair;
     324           0 :                 for( i = 0; i < (int)pImplTTFont->nkern; i++ )
     325             :                 {
     326           0 :                     const sal_uInt8* pTable = pImplTTFont->kerntables[i];
     327             : 
     328           0 :                     /*sal_uInt16 nVersion     =*/ getUInt16BE( pTable );
     329           0 :                     /*sal_uInt16 nLength      =*/ getUInt16BE( pTable );
     330           0 :                     sal_uInt16 nCoverage    = getUInt16BE( pTable );
     331             : 
     332           0 :                     aPair.kern_x    = 0;
     333           0 :                     aPair.kern_y    = 0;
     334           0 :                     switch( nCoverage >> 8 )
     335             :                     {
     336             :                         case 0:
     337             :                         {
     338           0 :                             sal_uInt16 nPairs = getUInt16BE( pTable );
     339           0 :                             pTable += 6;
     340           0 :                             for( int n = 0; n < nPairs; n++ )
     341             :                             {
     342           0 :                                 sal_uInt16 nLeftGlyph   = getUInt16BE( pTable );
     343           0 :                                 sal_uInt16 nRightGlyph  = getUInt16BE( pTable );
     344           0 :                                 sal_Int16 nKern         = (sal_Int16)getUInt16BE( pTable );
     345             : 
     346           0 :                                 left = aGlyphMap.find( nLeftGlyph );
     347           0 :                                 right = aGlyphMap.find( nRightGlyph );
     348           0 :                                 if( left != aGlyphMap.end() && right != aGlyphMap.end() )
     349             :                                 {
     350           0 :                                     aPair.first     = left->second;
     351           0 :                                     aPair.second    = right->second;
     352           0 :                                     switch( nCoverage & 1 )
     353             :                                     {
     354             :                                         case 1:
     355           0 :                                             aPair.kern_x = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
     356           0 :                                             m_pMetrics->m_aXKernPairs.push_back( aPair );
     357           0 :                                             break;
     358             :                                         case 0:
     359           0 :                                             aPair.kern_y = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
     360           0 :                                             m_pMetrics->m_aYKernPairs.push_back( aPair );
     361           0 :                                             break;
     362             :                                     }
     363             :                                 }
     364             :                             }
     365             :                         }
     366           0 :                         break;
     367             : 
     368             :                         case 2:
     369             :                         {
     370           0 :                             const sal_uInt8* pSubTable = pTable;
     371           0 :                             /*sal_uInt16 nRowWidth    =*/ getUInt16BE( pTable );
     372           0 :                             sal_uInt16 nOfLeft      = getUInt16BE( pTable );
     373           0 :                             sal_uInt16 nOfRight     = getUInt16BE( pTable );
     374           0 :                             /*sal_uInt16 nOfArray     =*/ getUInt16BE( pTable );
     375           0 :                             const sal_uInt8* pTmp = pSubTable + nOfLeft;
     376           0 :                             sal_uInt16 nFirstLeft   = getUInt16BE( pTmp );
     377           0 :                             sal_uInt16 nLastLeft    = getUInt16BE( pTmp ) + nFirstLeft - 1;
     378           0 :                             pTmp = pSubTable + nOfRight;
     379           0 :                             sal_uInt16 nFirstRight  = getUInt16BE( pTmp );
     380           0 :                             sal_uInt16 nLastRight   = getUInt16BE( pTmp ) + nFirstRight -1;
     381             : 
     382             :                             // int nPairs = (int)(nLastLeft-nFirstLeft+1)*(int)(nLastRight-nFirstRight+1);
     383           0 :                             for( aPair.first = nFirstLeft; aPair.first < nLastLeft; aPair.first++ )
     384             :                             {
     385           0 :                                 for( aPair.second = 0; aPair.second < nLastRight; aPair.second++ )
     386             :                                 {
     387           0 :                                     sal_Int16 nKern = (sal_Int16)getUInt16BE( pTmp );
     388           0 :                                     switch( nCoverage & 1 )
     389             :                                     {
     390             :                                         case 1:
     391           0 :                                             aPair.kern_x = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
     392           0 :                                             m_pMetrics->m_aXKernPairs.push_back( aPair );
     393           0 :                                             break;
     394             :                                         case 0:
     395           0 :                                             aPair.kern_y = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
     396           0 :                                             m_pMetrics->m_aYKernPairs.push_back( aPair );
     397           0 :                                             break;
     398             :                                     }
     399             :                                 }
     400             :                             }
     401             :                         }
     402           0 :                         break;
     403             :                     }
     404           0 :                 }
     405             :             }
     406             : 
     407             :             //-----------------------------------------------------------------
     408             :             // Kerning:  KT_APPLE_NEW
     409             :             //-----------------------------------------------------------------
     410           0 :             if( pImplTTFont->nkern && pImplTTFont->kerntype == KT_APPLE_NEW )
     411             :             {
     412             :                 // create a glyph -> character mapping
     413           0 :                 ::boost::unordered_map< sal_uInt16, sal_Unicode > aGlyphMap;
     414           0 :                 ::boost::unordered_map< sal_uInt16, sal_Unicode >::iterator left, right;
     415           0 :                 for( i = 21; i < 0xfffd; i++ )
     416             :                 {
     417           0 :                     sal_uInt16 nGlyph = MapChar( pTTFont, (sal_Unicode)i, 0 ); // kerning for horz only
     418           0 :                     if( nGlyph != 0 )
     419           0 :                         aGlyphMap[ nGlyph ] = (sal_Unicode)i;
     420             :                 }
     421             : 
     422             :                 // Loop through each of the 'kern' subtables
     423           0 :                 KernPair aPair;
     424           0 :                 for( i = 0; (unsigned int)i < pImplTTFont->nkern; i++ )
     425             :                 {
     426           0 :                     const sal_uInt8* pTable = pImplTTFont->kerntables[i];
     427             : 
     428           0 :                     /*sal_uInt32 nLength      =*/ getUInt32BE( pTable );
     429           0 :                     sal_uInt16 nCoverage    = getUInt16BE( pTable );
     430           0 :                     /*sal_uInt16 nTupleIndex  =*/ getUInt16BE( pTable );
     431             : 
     432             :                     // Get kerning type
     433             :                     // sal_Bool bKernVertical     = nCoverage & 0x8000;
     434             :                     // sal_Bool bKernCrossStream  = nCoverage & 0x4000;
     435             :                     // sal_Bool bKernVariation    = nCoverage & 0x2000;
     436             : 
     437             :                     // Kerning sub-table format, 0 through 3
     438           0 :                     sal_uInt8 nSubTableFormat  = nCoverage & 0x00FF;
     439             : 
     440           0 :                     aPair.kern_x    = 0;
     441           0 :                     aPair.kern_y    = 0;
     442           0 :                     switch( nSubTableFormat )
     443             :                     {
     444             :                         case 0:
     445             :                         {
     446             :                             // Grab the # of kern pairs but skip over the:
     447             :                             //   searchRange
     448             :                             //   entrySelector
     449             :                             //   rangeShift
     450           0 :                             sal_uInt16 nPairs = getUInt16BE( pTable );
     451           0 :                             pTable += 6;
     452             : 
     453           0 :                             for( int n = 0; n < nPairs; n++ )
     454             :                             {
     455           0 :                                 sal_uInt16 nLeftGlyph   = getUInt16BE( pTable );
     456           0 :                                 sal_uInt16 nRightGlyph  = getUInt16BE( pTable );
     457           0 :                                 sal_Int16  nKern         = (sal_Int16)getUInt16BE( pTable );
     458             : 
     459           0 :                                 left = aGlyphMap.find( nLeftGlyph );
     460           0 :                                 right = aGlyphMap.find( nRightGlyph );
     461           0 :                                 if( left != aGlyphMap.end() && right != aGlyphMap.end() )
     462             :                                 {
     463           0 :                                     aPair.first     = left->second;
     464           0 :                                     aPair.second    = right->second;
     465             : 
     466             :                                     // Only support horizontal kerning for now
     467           0 :                                     aPair.kern_x = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
     468           0 :                                     aPair.kern_y = 0;
     469           0 :                                     m_pMetrics->m_aXKernPairs.push_back( aPair );
     470             :                                 }
     471             :                             }
     472             :                         }
     473           0 :                         break;
     474             : 
     475             :                         case 2:
     476             :                         {
     477           0 :                             const sal_uInt8* pSubTable = pTable;
     478           0 :                             /*sal_uInt16 nRowWidth    =*/ getUInt16BE( pTable );
     479           0 :                             sal_uInt16 nOfLeft      = getUInt16BE( pTable );
     480           0 :                             sal_uInt16 nOfRight     = getUInt16BE( pTable );
     481           0 :                             /*sal_uInt16 nOfArray     =*/ getUInt16BE( pTable );
     482           0 :                             const sal_uInt8* pTmp = pSubTable + nOfLeft;
     483           0 :                             sal_uInt16 nFirstLeft   = getUInt16BE( pTmp );
     484           0 :                             sal_uInt16 nLastLeft    = getUInt16BE( pTmp ) + nFirstLeft - 1;
     485           0 :                             pTmp = pSubTable + nOfRight;
     486           0 :                             sal_uInt16 nFirstRight  = getUInt16BE( pTmp );
     487           0 :                             sal_uInt16 nLastRight   = getUInt16BE( pTmp ) + nFirstRight -1;
     488             : 
     489           0 :                             for( aPair.first = nFirstLeft; aPair.first < nLastLeft; aPair.first++ )
     490             :                             {
     491           0 :                                 for( aPair.second = 0; aPair.second < nLastRight; aPair.second++ )
     492             :                                 {
     493           0 :                                     sal_Int16 nKern = (sal_Int16)getUInt16BE( pTmp );
     494           0 :                                     switch( nCoverage & 1 )
     495             :                                     {
     496             :                                         case 1:
     497           0 :                                             aPair.kern_x = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
     498           0 :                                             m_pMetrics->m_aXKernPairs.push_back( aPair );
     499           0 :                                             break;
     500             :                                         case 0:
     501           0 :                                             aPair.kern_y = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
     502           0 :                                             m_pMetrics->m_aYKernPairs.push_back( aPair );
     503           0 :                                             break;
     504             :                                     }
     505             :                                 }
     506             :                             }
     507             :                         }
     508           0 :                         break;
     509             : 
     510             :                         default:
     511           0 :                             fprintf( stderr, "Found unsupported Apple-style kern subtable type %d.\n", nSubTableFormat );
     512           0 :                             break;
     513             :                     }
     514           0 :                 }
     515             :             }
     516             : 
     517             : #if OSL_DEBUG_LEVEL > 1
     518             :             fprintf( stderr, "found %" SAL_PRI_SIZET "u/%" SAL_PRI_SIZET "u kern pairs for %s\n",
     519             :                      m_pMetrics->m_aXKernPairs.size(),
     520             :                      m_pMetrics->m_aYKernPairs.size(),
     521             :                      OUStringToOString( pProvider->getString( ATOM_FAMILYNAME, m_nFamilyName ), RTL_TEXTENCODING_MS_1252 ).getStr() );
     522             : #else
     523             :             (void) pProvider; /* avoid warnings */
     524             : #endif
     525             :         }
     526             : 
     527           0 :         CloseTTFont( pTTFont );
     528           0 :         bSuccess = true;
     529             :     }
     530           0 :     return bSuccess;
     531             : }
     532             : 
     533             : // -------------------------------------------------------------------------
     534             : 
     535             : /* #i73387# There seem to be fonts with a rather unwell chosen family name
     536             : *  consider e.g. "Helvetica Narrow" which defines its family as "Helvetica"
     537             : *  It can really only be distinguished by its PSName and FullName. Both of
     538             : *  which are not user presentable in OOo. So replace it by something sensible.
     539             : *
     540             : *  If other fonts feature this behaviour, insert them to the map.
     541             : */
     542          70 : static bool familyNameOverride( const OUString& i_rPSname, OUString& o_rFamilyName )
     543             : {
     544          70 :     static boost::unordered_map< OUString, OUString, OUStringHash > aPSNameToFamily( 16 );
     545          70 :     if( aPSNameToFamily.empty() ) // initialization
     546             :     {
     547           4 :         aPSNameToFamily[ OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica-Narrow" ) ) ] =
     548           6 :                          OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica Narrow" ) );
     549           4 :         aPSNameToFamily[ OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica-Narrow-Bold" ) ) ] =
     550           6 :                          OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica Narrow" ) );
     551           4 :         aPSNameToFamily[ OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica-Narrow-BoldOblique" ) ) ] =
     552           6 :                          OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica Narrow" ) );
     553           4 :         aPSNameToFamily[ OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica-Narrow-Oblique" ) ) ] =
     554           6 :                          OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica Narrow" ) );
     555             :     }
     556             :     boost::unordered_map<OUString,OUString,OUStringHash>::const_iterator it =
     557          70 :        aPSNameToFamily.find( i_rPSname );
     558          70 :     bool bReplaced = (it != aPSNameToFamily.end() );
     559          70 :     if( bReplaced )
     560           0 :         o_rFamilyName = it->second;
     561          70 :     return bReplaced;
     562             : };
     563             : 
     564          70 : bool PrintFontManager::PrintFont::readAfmMetrics( const OString& rFileName, MultiAtomProvider* pProvider, bool bFillEncodingvector, bool bOnlyGlobalAttributes )
     565             : {
     566          70 :     PrintFontManager& rManager( PrintFontManager::get() );
     567             : 
     568          70 :     FontInfo* pInfo = NULL;
     569          70 :     parseFile( rFileName.getStr(), &pInfo, P_ALL );
     570          70 :     if( ! pInfo || ! pInfo->numOfChars )
     571             :     {
     572           0 :         if( pInfo )
     573           0 :             freeFontInfo( pInfo );
     574           0 :         return false;
     575             :     }
     576             : 
     577          70 :     m_aEncodingVector.clear();
     578             :     // fill in global info
     579             : 
     580             :     // PSName
     581          70 :     OUString aPSName( OStringToOUString( pInfo->gfi->fontName, RTL_TEXTENCODING_ISO_8859_1 ) );
     582          70 :     m_nPSName = pProvider->getAtom( ATOM_PSNAME, aPSName, sal_True );
     583             : 
     584             :     // family name (if not already set)
     585          70 :     OUString aFamily;
     586          70 :     if( ! m_nFamilyName )
     587             :     {
     588          70 :         aFamily = OStringToOUString( pInfo->gfi->familyName, RTL_TEXTENCODING_ISO_8859_1 );
     589          70 :         if( aFamily.isEmpty() )
     590             :         {
     591           0 :             aFamily = OStringToOUString( pInfo->gfi->fontName, RTL_TEXTENCODING_ISO_8859_1 );
     592           0 :             sal_Int32 nIndex  = 0;
     593           0 :             aFamily = aFamily.getToken( 0, '-', nIndex );
     594             :         }
     595          70 :         familyNameOverride( aPSName, aFamily );
     596          70 :         m_nFamilyName = pProvider->getAtom( ATOM_FAMILYNAME, aFamily, sal_True );
     597             :     }
     598             :     else
     599           0 :         aFamily = pProvider->getString( ATOM_FAMILYNAME, m_nFamilyName );
     600             : 
     601             :     // style name: if fullname begins with family name
     602             :     // interpret the rest of fullname as style
     603          70 :     if( m_aStyleName.isEmpty() && pInfo->gfi->fullName && *pInfo->gfi->fullName )
     604             :     {
     605          70 :         OUString aFullName( OStringToOUString( pInfo->gfi->fullName, RTL_TEXTENCODING_ISO_8859_1 ) );
     606          70 :         if( aFullName.indexOf( aFamily ) == 0 )
     607          70 :             m_aStyleName = WhitespaceToSpace( aFullName.copy( aFamily.getLength() ) );
     608             :     }
     609             : 
     610             :     // italic
     611          70 :     if( pInfo->gfi->italicAngle > 0 )
     612           0 :         m_eItalic = ITALIC_OBLIQUE;
     613          70 :     else if( pInfo->gfi->italicAngle < 0 )
     614          34 :         m_eItalic = ITALIC_NORMAL;
     615             :     else
     616          36 :         m_eItalic = ITALIC_NONE;
     617             : 
     618             :     // weight
     619          70 :     rtl::OString aWeight( pInfo->gfi->weight );
     620          70 :     m_eWeight = parseWeight( aWeight.toAsciiLowerCase() );
     621             : 
     622             :     // pitch
     623          70 :     m_ePitch = pInfo->gfi->isFixedPitch ? PITCH_FIXED : PITCH_VARIABLE;
     624             : 
     625             :     // encoding - only set if unknown
     626          70 :     int nAdobeEncoding = 0;
     627          70 :     if( pInfo->gfi->encodingScheme )
     628             :     {
     629          70 :         if( !strcmp( pInfo->gfi->encodingScheme, "AdobeStandardEncoding" ) )
     630          66 :             nAdobeEncoding = 1;
     631           4 :         else if( !strcmp( pInfo->gfi->encodingScheme, "ISO10646-1" ) )
     632             :         {
     633           0 :             nAdobeEncoding = 1;
     634           0 :             m_aEncoding = RTL_TEXTENCODING_UNICODE;
     635             :         }
     636           4 :         else if( !strcmp( pInfo->gfi->encodingScheme, "Symbol") )
     637           0 :             nAdobeEncoding = 2;
     638           4 :         else if( !strcmp( pInfo->gfi->encodingScheme, "FontSpecific") )
     639           4 :             nAdobeEncoding = 3;
     640             : 
     641          70 :         if( m_aEncoding == RTL_TEXTENCODING_DONTKNOW )
     642             :             m_aEncoding = nAdobeEncoding == 1 ?
     643          70 :                 RTL_TEXTENCODING_ADOBE_STANDARD : RTL_TEXTENCODING_SYMBOL;
     644             :     }
     645           0 :     else if( m_aEncoding == RTL_TEXTENCODING_DONTKNOW )
     646           0 :         m_aEncoding = RTL_TEXTENCODING_ADOBE_STANDARD;
     647             : 
     648             :     // try to parse the font name and decide whether it might be a
     649             :     // japanese font. Who invented this PITA ?
     650          70 :     OUString aPSNameLastToken( aPSName.copy( aPSName.lastIndexOf( '-' )+1 ) );
     651         140 :     if( ! aPSNameLastToken.compareToAscii( "H" )    ||
     652          70 :         ! aPSNameLastToken.compareToAscii( "V" )  )
     653             :     {
     654             :         static const char* pEncs[] =
     655             :             {
     656             :                 "EUC",
     657             :                 "RKSJ",
     658             :                 "SJ"
     659             :             };
     660             :         static const rtl_TextEncoding aEncs[] =
     661             :             {
     662             :                 RTL_TEXTENCODING_EUC_JP,
     663             :                 RTL_TEXTENCODING_SHIFT_JIS,
     664             :                 RTL_TEXTENCODING_JIS_X_0208
     665             :             };
     666             : 
     667           0 :         for( unsigned int enc = 0; enc < SAL_N_ELEMENTS( aEncs ) && m_aEncoding == RTL_TEXTENCODING_DONTKNOW; enc++ )
     668             :         {
     669           0 :             sal_Int32 nIndex = 0, nOffset = 1;
     670           0 :             do
     671             :             {
     672           0 :                 OUString aToken( aPSName.getToken( nOffset, '-', nIndex ) );
     673           0 :                 if( nIndex == -1 )
     674             :                     break;
     675           0 :                 nOffset = 0;
     676           0 :                 if( ! aToken.compareToAscii( pEncs[enc] ) )
     677             :                 {
     678           0 :                     m_aEncoding = aEncs[ enc ];
     679           0 :                     m_bFontEncodingOnly = true;
     680           0 :                 }
     681             :             } while( nIndex != -1 );
     682             :         }
     683             : 
     684             :         // default is jis
     685           0 :         if( m_aEncoding == RTL_TEXTENCODING_DONTKNOW )
     686           0 :             m_aEncoding = RTL_TEXTENCODING_JIS_X_0208;
     687             : #if OSL_DEBUG_LEVEL > 1
     688             :         fprintf( stderr, "Encoding %d for %s\n", m_aEncoding, pInfo->gfi->fontName );
     689             : #endif
     690             :     }
     691             : 
     692             :     // hack for GB encoded builtin fonts posing as FontSpecific
     693          70 :     if( m_eType == fonttype::Builtin && ( nAdobeEncoding == 3 || nAdobeEncoding == 0 ) )
     694             :     {
     695           0 :         int nLen = aFamily.getLength();
     696           0 :         if( nLen > 2 &&
     697           0 :             aFamily.getStr()[ nLen-2 ] == 'G' &&
     698           0 :             aFamily.getStr()[ nLen-1 ] == 'B' &&
     699             :             pInfo->numOfChars > 255 )
     700             :         {
     701           0 :             m_aEncoding = RTL_TEXTENCODING_GBK;
     702           0 :             m_bFontEncodingOnly = true;
     703             : #if OSL_DEBUG_LEVEL > 1
     704             :             fprintf( stderr, "found builtin font %s with GBK encoding\n", pInfo->gfi->fontName );
     705             : #endif
     706             :         }
     707             :     }
     708             : 
     709             :     // #i37313# check if Fontspecific is not rather some character encoding
     710          70 :     if( nAdobeEncoding == 3 && m_aEncoding == RTL_TEXTENCODING_SYMBOL )
     711             :     {
     712           4 :         bool bYFound = false;
     713           4 :         bool bQFound = false;
     714           4 :         CharMetricInfo* pChar = pInfo->cmi;
     715         790 :         for( int j = 0; j < pInfo->numOfChars && ! (bYFound && bQFound); j++ )
     716             :         {
     717         786 :             if( pChar[j].name )
     718             :             {
     719         786 :                 if( pChar[j].name[0] == 'Y' && pChar[j].name[1] == 0 )
     720           0 :                     bYFound = true;
     721         786 :                 else if( pChar[j].name[0] == 'Q' && pChar[j].name[1] == 0 )
     722           0 :                     bQFound = true;
     723             :             }
     724             :         }
     725           4 :         if( bQFound && bYFound )
     726             :         {
     727             :             #if OSL_DEBUG_LEVEL > 1
     728             :             fprintf( stderr, "setting FontSpecific font %s (file %s) to unicode\n",
     729             :                      pInfo->gfi->fontName,
     730             :                      rFileName.getStr()
     731             :                      );
     732             :             #endif
     733           0 :             nAdobeEncoding = 4;
     734           0 :             m_aEncoding = RTL_TEXTENCODING_UNICODE;
     735           0 :             bFillEncodingvector = false; // will be filled anyway, don't do the work twice
     736             :         }
     737             :     }
     738             : 
     739             :     // ascend
     740          70 :     m_nAscend = pInfo->gfi->fontBBox.ury;
     741             : 
     742             :     // descend
     743             :     // descends have opposite sign of our definition
     744          70 :     m_nDescend = -pInfo->gfi->fontBBox.lly;
     745             : 
     746             :     // fallback to ascender, descender
     747             :     // interesting: the BBox seems to describe Ascender and Descender better
     748             :     // as we understand it
     749          70 :     if( m_nAscend == 0 )
     750           0 :         m_nAscend = pInfo->gfi->ascender;
     751          70 :     if( m_nDescend == 0)
     752           0 :         m_nDescend = -pInfo->gfi->descender;
     753             : 
     754          70 :     m_nLeading = m_nAscend + m_nDescend - 1000;
     755             : 
     756          70 :     if( m_pMetrics )
     757           0 :         delete m_pMetrics;
     758          70 :     m_pMetrics = new PrintFontMetrics;
     759             :     // mark all pages as queried (or clear if only global font info queiried)
     760          70 :     memset( m_pMetrics->m_aPages, bOnlyGlobalAttributes ? 0 : 0xff, sizeof( m_pMetrics->m_aPages ) );
     761             : 
     762             :     m_aGlobalMetricX.width = m_aGlobalMetricY.width =
     763          70 :         pInfo->gfi->charwidth ? pInfo->gfi->charwidth : pInfo->gfi->fontBBox.urx;
     764             :     m_aGlobalMetricX.height = m_aGlobalMetricY.height =
     765          70 :         pInfo->gfi->capHeight ? pInfo->gfi->capHeight : pInfo->gfi->fontBBox.ury;
     766             : 
     767          70 :     m_nXMin = pInfo->gfi->fontBBox.llx;
     768          70 :     m_nYMin = pInfo->gfi->fontBBox.lly;
     769          70 :     m_nXMax = pInfo->gfi->fontBBox.urx;
     770          70 :     m_nYMax = pInfo->gfi->fontBBox.ury;
     771             : 
     772          70 :     if( bFillEncodingvector || !bOnlyGlobalAttributes )
     773             :     {
     774             :         // fill in character metrics
     775             : 
     776             :         // first transform the character codes to unicode
     777             :         // note: this only works with single byte encodings
     778           0 :         sal_Unicode* pUnicodes = (sal_Unicode*)alloca( pInfo->numOfChars * sizeof(sal_Unicode));
     779           0 :         CharMetricInfo* pChar = pInfo->cmi;
     780             :         int i;
     781             : 
     782           0 :         for( i = 0; i < pInfo->numOfChars; i++, pChar++ )
     783             :         {
     784           0 :             if( nAdobeEncoding == 4 )
     785             :             {
     786           0 :                 if( pChar->name )
     787             :                 {
     788           0 :                     pUnicodes[i] = 0;
     789           0 :                     std::list< sal_Unicode > aCodes = rManager.getUnicodeFromAdobeName( pChar->name );
     790           0 :                     for( std::list< sal_Unicode >::const_iterator it = aCodes.begin(); it != aCodes.end(); ++it )
     791             :                     {
     792           0 :                         if( *it != 0 )
     793             :                         {
     794           0 :                             m_aEncodingVector[ *it ] = pChar->code;
     795           0 :                             if( pChar->code == -1 )
     796           0 :                                 m_aNonEncoded[ *it ] = pChar->name;
     797           0 :                             if( ! pUnicodes[i] ) // map the first
     798           0 :                                 pUnicodes[i] = *it;
     799             :                         }
     800           0 :                     }
     801             :                 }
     802             :             }
     803           0 :             else if( pChar->code != -1 )
     804             :             {
     805           0 :                 if( nAdobeEncoding == 3 && m_aEncoding == RTL_TEXTENCODING_SYMBOL )
     806             :                 {
     807           0 :                     pUnicodes[i] = pChar->code + 0xf000;
     808           0 :                     if( bFillEncodingvector )
     809           0 :                         m_aEncodingVector[ pUnicodes[i] ] = pChar->code;
     810           0 :                     continue;
     811             :                 }
     812             : 
     813           0 :                 if( m_aEncoding == RTL_TEXTENCODING_UNICODE )
     814             :                 {
     815           0 :                     pUnicodes[i] = (sal_Unicode)pChar->code;
     816           0 :                     continue;
     817             :                 }
     818             : 
     819           0 :                 rtl::OStringBuffer aTranslate;
     820           0 :                 if( pChar->code & 0xff000000 )
     821           0 :                     aTranslate.append((char)(pChar->code >> 24));
     822           0 :                 if( pChar->code & 0xffff0000 )
     823           0 :                     aTranslate.append((char)((pChar->code & 0x00ff0000) >> 16));
     824           0 :                 if( pChar->code & 0xffffff00 )
     825           0 :                     aTranslate.append((char)((pChar->code & 0x0000ff00) >> 8 ));
     826           0 :                 aTranslate.append((char)(pChar->code & 0xff));
     827           0 :                 rtl::OUString aUni(rtl::OStringToOUString(aTranslate.makeStringAndClear(), m_aEncoding));
     828           0 :                 pUnicodes[i] = aUni.toChar();
     829             :             }
     830             :             else
     831           0 :                 pUnicodes[i] = 0;
     832             :         }
     833             : 
     834             :         // now fill in the character metrics
     835             :         // parseAFM.cxx effectively only supports direction 0 (horizontal)
     836           0 :         pChar = pInfo->cmi;
     837           0 :         CharacterMetric aMetric;
     838           0 :         for( i = 0; i < pInfo->numOfChars; i++, pChar++ )
     839             :         {
     840           0 :             if( pChar->code == -1 && ! pChar->name )
     841           0 :                 continue;
     842             : 
     843           0 :             if( bFillEncodingvector && pChar->name )
     844             :             {
     845           0 :                 std::list< sal_Unicode > aCodes = rManager.getUnicodeFromAdobeName( pChar->name );
     846           0 :                 for( std::list< sal_Unicode >::const_iterator it = aCodes.begin(); it != aCodes.end(); ++it )
     847             :                 {
     848           0 :                     if( *it != 0 )
     849             :                     {
     850           0 :                         m_aEncodingVector[ *it ] = pChar->code;
     851           0 :                         if( pChar->code == -1 )
     852           0 :                             m_aNonEncoded[ *it ] = pChar->name;
     853             :                     }
     854           0 :                 }
     855             :             }
     856             : 
     857           0 :             aMetric.width   = pChar->wx ? pChar->wx : pChar->charBBox.urx;
     858           0 :             aMetric.height  = pChar->wy ? pChar->wy : pChar->charBBox.ury - pChar->charBBox.lly;
     859           0 :             if( aMetric.width == 0 && aMetric.height == 0 )
     860             :                 // guess something for e.g. space
     861           0 :                 aMetric.width = m_aGlobalMetricX.width/4;
     862             : 
     863           0 :             if( ( nAdobeEncoding == 0 ) ||
     864             :                 ( ( nAdobeEncoding == 3 ) && ( m_aEncoding != RTL_TEXTENCODING_SYMBOL ) ) )
     865             :             {
     866           0 :                 if( pChar->code != -1 )
     867             :                 {
     868           0 :                     m_pMetrics->m_aMetrics[ pUnicodes[i] ] = aMetric;
     869           0 :                     if( bFillEncodingvector )
     870           0 :                         m_aEncodingVector[ pUnicodes[i] ] = pChar->code;
     871             :                 }
     872           0 :                 else if( pChar->name )
     873             :                 {
     874           0 :                     std::list< sal_Unicode > aCodes = rManager.getUnicodeFromAdobeName( pChar->name );
     875           0 :                     for( std::list< sal_Unicode >::const_iterator it = aCodes.begin(); it != aCodes.end(); ++it )
     876             :                     {
     877           0 :                         if( *it != 0 )
     878           0 :                             m_pMetrics->m_aMetrics[ *it ] = aMetric;
     879           0 :                     }
     880           0 :                 }
     881             :             }
     882           0 :             else if( nAdobeEncoding == 1 || nAdobeEncoding == 2 || nAdobeEncoding == 4)
     883             :             {
     884           0 :                 if( pChar->name )
     885             :                 {
     886           0 :                     std::list< sal_Unicode > aCodes = rManager.getUnicodeFromAdobeName( pChar->name );
     887           0 :                     for( std::list< sal_Unicode >::const_iterator it = aCodes.begin(); it != aCodes.end(); ++it )
     888             :                     {
     889           0 :                         if( *it != 0 )
     890           0 :                             m_pMetrics->m_aMetrics[ *it ] = aMetric;
     891           0 :                     }
     892             :                 }
     893           0 :                 else if( pChar->code != -1 )
     894             :                 {
     895             :                     ::std::pair< ::boost::unordered_multimap< sal_uInt8, sal_Unicode >::const_iterator,
     896             :                           ::boost::unordered_multimap< sal_uInt8, sal_Unicode >::const_iterator >
     897           0 :                           aCodes = rManager.getUnicodeFromAdobeCode( pChar->code );
     898           0 :                     while( aCodes.first != aCodes.second )
     899             :                     {
     900           0 :                         if( (*aCodes.first).second != 0 )
     901             :                         {
     902           0 :                             m_pMetrics->m_aMetrics[ (*aCodes.first).second ] = aMetric;
     903           0 :                             if( bFillEncodingvector )
     904           0 :                                 m_aEncodingVector[ (*aCodes.first).second ] = pChar->code;
     905             :                         }
     906           0 :                         ++aCodes.first;
     907             :                     }
     908           0 :                 }
     909             :             }
     910           0 :             else if( nAdobeEncoding == 3 )
     911             :             {
     912           0 :                 if( pChar->code != -1 )
     913             :                 {
     914           0 :                     sal_Unicode code = 0xf000 + pChar->code;
     915           0 :                     m_pMetrics->m_aMetrics[ code ] = aMetric;
     916             :                     // maybe should try to find the name in the convtabs ?
     917           0 :                     if( bFillEncodingvector )
     918           0 :                         m_aEncodingVector[ code ] = pChar->code;
     919             :                 }
     920             :             }
     921             :         }
     922             : 
     923           0 :         m_pMetrics->m_aXKernPairs.clear();
     924           0 :         m_pMetrics->m_aYKernPairs.clear();
     925             : 
     926             :         // now fill in the kern pairs
     927             :         // parseAFM.cxx effectively only supports direction 0 (horizontal)
     928           0 :         PairKernData* pKern = pInfo->pkd;
     929           0 :         KernPair aPair;
     930           0 :         for( i = 0; i < pInfo->numOfPairs; i++, pKern++ )
     931             :         {
     932             :             // #i37703# broken kern table
     933           0 :             if( ! pKern->name1 || ! pKern->name2 )
     934           0 :                 continue;
     935             : 
     936           0 :             aPair.first = 0;
     937           0 :             aPair.second = 0;
     938             :             // currently we have to find the adobe character names
     939             :             // in the already parsed character metrics to find
     940             :             // the corresponding UCS2 code which is a bit dangerous
     941             :             // since the character names are not required
     942             :             // in the metric descriptions
     943           0 :             pChar = pInfo->cmi;
     944           0 :             for( int j = 0;
     945             :                  j < pInfo->numOfChars && ( aPair.first == 0 || aPair.second == 0 );
     946             :                  j++, pChar++ )
     947             :             {
     948           0 :                 if( pChar->code != -1 )
     949             :                 {
     950           0 :                     if( ! strcmp( pKern->name1, pChar->name ? pChar->name : "" ) )
     951           0 :                         aPair.first = pUnicodes[ j ];
     952           0 :                     if( ! strcmp( pKern->name2, pChar->name ? pChar->name : "" ) )
     953           0 :                         aPair.second = pUnicodes[ j ];
     954             :                 }
     955             :             }
     956           0 :             if( aPair.first && aPair.second )
     957             :             {
     958           0 :                 aPair.kern_x = pKern->xamt;
     959           0 :                 aPair.kern_y = pKern->yamt;
     960           0 :                 m_pMetrics->m_aXKernPairs.push_back( aPair );
     961             :             }
     962             :         }
     963           0 :         m_pMetrics->m_bKernPairsQueried = true;
     964             :     }
     965             : 
     966          70 :     freeFontInfo( pInfo );
     967          70 :     return true;
     968             : }
     969             : 
     970             : /*
     971             :  *  one instance only
     972             :  */
     973        4118 : PrintFontManager& PrintFontManager::get()
     974             : {
     975             :     static PrintFontManager* pManager = NULL;
     976        4118 :     if( ! pManager )
     977             :     {
     978          20 :         static PrintFontManager theManager;
     979          20 :         pManager = &theManager;
     980          20 :         pManager->initialize();
     981             :     }
     982        4118 :     return *pManager;
     983             : }
     984             : 
     985             : // -------------------------------------------------------------------------
     986             : 
     987             : /*
     988             :  *  the PrintFontManager
     989             :  */
     990             : 
     991          20 : PrintFontManager::PrintFontManager()
     992             :     : m_nNextFontID( 1 )
     993           0 :     , m_pAtoms( new MultiAtomProvider() )
     994             :     , m_nNextDirAtom( 1 )
     995          20 :     , m_pFontCache( NULL )
     996             : {
     997       21040 :     for( unsigned int i = 0; i < SAL_N_ELEMENTS( aAdobeCodes ); i++ )
     998             :     {
     999       21020 :         m_aUnicodeToAdobename.insert( ::boost::unordered_multimap< sal_Unicode, ::rtl::OString >::value_type( aAdobeCodes[i].aUnicode, aAdobeCodes[i].pAdobename ) );
    1000       21020 :         m_aAdobenameToUnicode.insert( ::boost::unordered_multimap< ::rtl::OString, sal_Unicode, ::rtl::OStringHash >::value_type( aAdobeCodes[i].pAdobename, aAdobeCodes[i].aUnicode ) );
    1001       21020 :         if( aAdobeCodes[i].aAdobeStandardCode )
    1002             :         {
    1003        3020 :             m_aUnicodeToAdobecode.insert( ::boost::unordered_multimap< sal_Unicode, sal_uInt8 >::value_type( aAdobeCodes[i].aUnicode, aAdobeCodes[i].aAdobeStandardCode ) );
    1004        3020 :             m_aAdobecodeToUnicode.insert( ::boost::unordered_multimap< sal_uInt8, sal_Unicode >::value_type( aAdobeCodes[i].aAdobeStandardCode, aAdobeCodes[i].aUnicode ) );
    1005             :         }
    1006             :     }
    1007             : 
    1008          20 :     m_aFontInstallerTimer.SetTimeoutHdl(LINK(this, PrintFontManager, autoInstallFontLangSupport));
    1009          20 :     m_aFontInstallerTimer.SetTimeout(5000);
    1010          20 : }
    1011             : 
    1012             : // -------------------------------------------------------------------------
    1013             : 
    1014          40 : PrintFontManager::~PrintFontManager()
    1015             : {
    1016          20 :     m_aFontInstallerTimer.Stop();
    1017          20 :     deinitFontconfig();
    1018        2300 :     for( ::boost::unordered_map< fontID, PrintFont* >::const_iterator it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
    1019        2280 :         delete (*it).second;
    1020          20 :     delete m_pAtoms;
    1021          20 :     if( m_pFontCache )
    1022          20 :         delete m_pFontCache;
    1023          20 : }
    1024             : 
    1025             : // -------------------------------------------------------------------------
    1026             : 
    1027         451 : OString PrintFontManager::getDirectory( int nAtom ) const
    1028             : {
    1029         451 :     ::boost::unordered_map< int, OString >::const_iterator it( m_aAtomToDir.find( nAtom ) );
    1030         451 :     return it != m_aAtomToDir.end() ? it->second : OString();
    1031             : }
    1032             : 
    1033             : // -------------------------------------------------------------------------
    1034             : 
    1035        6874 : int PrintFontManager::getDirectoryAtom( const OString& rDirectory, bool bCreate )
    1036             : {
    1037        6874 :     int nAtom = 0;
    1038             :     ::boost::unordered_map< OString, int, OStringHash >::const_iterator it
    1039        6874 :           ( m_aDirToAtom.find( rDirectory ) );
    1040        6874 :     if( it != m_aDirToAtom.end() )
    1041        6215 :         nAtom = it->second;
    1042         659 :     else if( bCreate )
    1043             :     {
    1044         638 :         nAtom = m_nNextDirAtom++;
    1045         638 :         m_aDirToAtom[ rDirectory ] = nAtom;
    1046         638 :         m_aAtomToDir[ nAtom ] = rDirectory;
    1047             :     }
    1048        6874 :     return nAtom;
    1049             : }
    1050             : 
    1051             : // -------------------------------------------------------------------------
    1052             : 
    1053           0 : std::vector<fontID> PrintFontManager::addFontFile( const ::rtl::OString& rFileName )
    1054             : {
    1055           0 :     rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
    1056           0 :     INetURLObject aPath( OStringToOUString( rFileName, aEncoding ), INET_PROT_FILE, INetURLObject::ENCODE_ALL );
    1057           0 :     OString aName( OUStringToOString( aPath.GetName(), aEncoding ) );
    1058           0 :     OString aDir( OUStringToOString( aPath.GetPath(), aEncoding ) );
    1059             : 
    1060           0 :     int nDirID = getDirectoryAtom( aDir, true );
    1061           0 :     std::vector<fontID> aFontIds = findFontFileIDs( nDirID, aName );
    1062           0 :     if( aFontIds.empty() )
    1063             :     {
    1064           0 :         ::std::list< PrintFont* > aNewFonts;
    1065           0 :         if( analyzeFontFile( nDirID, aName, aNewFonts ) )
    1066             :         {
    1067           0 :             for( ::std::list< PrintFont* >::iterator it = aNewFonts.begin();
    1068           0 :                  it != aNewFonts.end(); ++it )
    1069             :             {
    1070           0 :                 fontID nFontId = m_nNextFontID++;
    1071           0 :                 m_aFonts[nFontId] = *it;
    1072           0 :                 m_aFontFileToFontID[ aName ].insert( nFontId );
    1073           0 :                 m_pFontCache->updateFontCacheEntry( *it, true );
    1074           0 :                 aFontIds.push_back(nFontId);
    1075             :             }
    1076           0 :         }
    1077             :     }
    1078           0 :     return aFontIds;
    1079             : }
    1080             : 
    1081             : enum fontFormat
    1082             : {
    1083             :     UNKNOWN, TRUETYPE, CFF, TYPE1, AFM
    1084             : };
    1085             : 
    1086         298 : bool PrintFontManager::analyzeFontFile( int nDirID, const OString& rFontFile, ::std::list< PrintFontManager::PrintFont* >& rNewFonts, const char *pFormat ) const
    1087             : {
    1088         298 :     rNewFonts.clear();
    1089             : 
    1090         298 :     OString aDir( getDirectory( nDirID ) );
    1091             : 
    1092         298 :     OString aFullPath( aDir );
    1093         298 :     aFullPath += "/";
    1094         298 :     aFullPath += rFontFile;
    1095             : 
    1096             :     // #i1872# reject unreadable files
    1097         298 :     if( access( aFullPath.getStr(), R_OK ) )
    1098           0 :         return false;
    1099             : 
    1100         298 :     fontFormat eFormat = UNKNOWN;
    1101         298 :     if (pFormat)
    1102             :     {
    1103         298 :         if (!strcmp(pFormat, "TrueType"))
    1104         136 :             eFormat = TRUETYPE;
    1105         162 :         else if (!strcmp(pFormat, "CFF"))
    1106          12 :             eFormat = CFF;
    1107         150 :         else if (!strcmp(pFormat, "Type 1"))
    1108         150 :             eFormat = TYPE1;
    1109             :     }
    1110         298 :     if (eFormat == UNKNOWN)
    1111             :     {
    1112           0 :         rtl::OString aExt( rFontFile.copy( rFontFile.lastIndexOf( '.' )+1 ) );
    1113           0 :         if( aExt.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("pfb")) || aExt.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("pfa")) )
    1114           0 :             eFormat = TYPE1;
    1115           0 :         else if( aExt.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("afm")))
    1116           0 :             eFormat = AFM;
    1117           0 :         else if( aExt.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("ttf"))
    1118           0 :              ||  aExt.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("ttc"))
    1119           0 :              ||  aExt.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("tte")) ) // #i33947# for Gaiji support
    1120           0 :             eFormat = TRUETYPE;
    1121           0 :         else if( aExt.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("otf")) ) // check for TTF- and PS-OpenType too
    1122           0 :             eFormat = CFF;
    1123             :     }
    1124             : 
    1125         298 :     if (eFormat == TYPE1)
    1126             :     {
    1127             :         // check for corresponding afm metric
    1128             :         // first look for an adjacent file
    1129             :         static const char* pSuffix[] = { ".afm", ".AFM" };
    1130             : 
    1131         310 :         for( unsigned int i = 0; i < SAL_N_ELEMENTS(pSuffix); i++ )
    1132             :         {
    1133             :             rtl::OString aName = rtl::OStringBuffer(
    1134         230 :                 rFontFile.copy(0, rFontFile.getLength() - 4)).
    1135         460 :                 append(pSuffix[i]).makeStringAndClear();
    1136             : 
    1137         230 :             rtl::OStringBuffer aFilePath(aDir);
    1138         230 :             aFilePath.append('/').append(aName);
    1139             : 
    1140         230 :             rtl::OString aAfmFile;
    1141         230 :             if( access( aFilePath.makeStringAndClear().getStr(), R_OK ) )
    1142             :             {
    1143             :                 // try in subdirectory afm instead
    1144         160 :                 aFilePath.append(aDir).append(RTL_CONSTASCII_STRINGPARAM("/afm/")).append(aName);
    1145             : 
    1146         160 :                 if (!access(aFilePath.getStr(), R_OK))
    1147           0 :                     aAfmFile = rtl::OString(RTL_CONSTASCII_STRINGPARAM("afm/")) + aName;
    1148             :             }
    1149             :             else
    1150          70 :                 aAfmFile = aName;
    1151             : 
    1152         230 :             if( !aAfmFile.isEmpty() )
    1153             :             {
    1154          70 :                 Type1FontFile* pFont = new Type1FontFile();
    1155          70 :                 pFont->m_nDirectory     = nDirID;
    1156             : 
    1157          70 :                 pFont->m_aFontFile      = rFontFile;
    1158          70 :                 pFont->m_aMetricFile    = aAfmFile;
    1159             : 
    1160          70 :                 if( ! pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, true ) )
    1161             :                 {
    1162           0 :                     delete pFont;
    1163           0 :                     pFont = NULL;
    1164             :                 }
    1165          70 :                 if( pFont )
    1166          70 :                     rNewFonts.push_back( pFont );
    1167             :                 break;
    1168             :             }
    1169         230 :         }
    1170             :     }
    1171         148 :     else if (eFormat == AFM)
    1172             :     {
    1173           0 :         rtl::OStringBuffer aFilePath(aDir);
    1174           0 :         aFilePath.append('/').append(rFontFile);
    1175           0 :         BuiltinFont* pFont = new BuiltinFont();
    1176           0 :         pFont->m_nDirectory     = nDirID;
    1177           0 :         pFont->m_aMetricFile    = rFontFile;
    1178           0 :         if( pFont->readAfmMetrics( aFilePath.makeStringAndClear(), m_pAtoms,
    1179           0 :             false, true ) )
    1180             :         {
    1181           0 :             rNewFonts.push_back( pFont );
    1182             :         }
    1183             :         else
    1184           0 :             delete pFont;
    1185             :     }
    1186         148 :     else if (eFormat == TRUETYPE || eFormat == CFF)
    1187             :     {
    1188             :         // get number of ttc entries
    1189         148 :         int nLength = CountTTCFonts( aFullPath.getStr() );
    1190         148 :         if( nLength )
    1191             :         {
    1192             : #if OSL_DEBUG_LEVEL > 1
    1193             :             fprintf( stderr, "ttc: %s contains %d fonts\n", aFullPath.getStr(), nLength );
    1194             : #endif
    1195          18 :             for( int i = 0; i < nLength; i++ )
    1196             :             {
    1197          14 :                 TrueTypeFontFile* pFont     = new TrueTypeFontFile();
    1198          14 :                 pFont->m_nDirectory         = nDirID;
    1199          14 :                 pFont->m_aFontFile          = rFontFile;
    1200          14 :                 pFont->m_nCollectionEntry   = i;
    1201          14 :                 if( ! analyzeTrueTypeFile( pFont ) )
    1202             :                 {
    1203           0 :                     delete pFont;
    1204           0 :                     pFont = NULL;
    1205             :                 }
    1206             :                 else
    1207          14 :                     rNewFonts.push_back( pFont );
    1208             :             }
    1209             :         }
    1210             :         else
    1211             :         {
    1212         144 :             TrueTypeFontFile* pFont     = new TrueTypeFontFile();
    1213         144 :             pFont->m_nDirectory         = nDirID;
    1214         144 :             pFont->m_aFontFile          = rFontFile;
    1215         144 :             pFont->m_nCollectionEntry   = 0;
    1216             : 
    1217             :             // need to read the font anyway to get aliases inside the font file
    1218         144 :             if( ! analyzeTrueTypeFile( pFont ) )
    1219             :             {
    1220           0 :                 delete pFont;
    1221           0 :                 pFont = NULL;
    1222             :             }
    1223             :             else
    1224         144 :                 rNewFonts.push_back( pFont );
    1225             :         }
    1226             :     }
    1227         298 :     return ! rNewFonts.empty();
    1228             : }
    1229             : 
    1230             : // -------------------------------------------------------------------------
    1231             : 
    1232           0 : fontID PrintFontManager::findFontBuiltinID( int nPSNameAtom ) const
    1233             : {
    1234           0 :     fontID nID = 0;
    1235           0 :     ::boost::unordered_map< fontID, PrintFont* >::const_iterator it;
    1236           0 :     for( it = m_aFonts.begin(); nID == 0 && it != m_aFonts.end(); ++it )
    1237             :     {
    1238           0 :         if( it->second->m_eType == fonttype::Builtin &&
    1239           0 :             it->second->m_nPSName == nPSNameAtom )
    1240           0 :             nID = it->first;
    1241             :     }
    1242           0 :     return nID;
    1243             : }
    1244             : 
    1245             : // -------------------------------------------------------------------------
    1246             : 
    1247        3852 : fontID PrintFontManager::findFontFileID( int nDirID, const OString& rFontFile, int nFaceIndex ) const
    1248             : {
    1249        3852 :     fontID nID = 0;
    1250             : 
    1251        3852 :     ::boost::unordered_map< OString, ::std::set< fontID >, OStringHash >::const_iterator set_it = m_aFontFileToFontID.find( rFontFile );
    1252        3852 :     if( set_it == m_aFontFileToFontID.end() )
    1253           0 :         return nID;
    1254             : 
    1255        8448 :     for( ::std::set< fontID >::const_iterator font_it = set_it->second.begin(); font_it != set_it->second.end() && ! nID; ++font_it )
    1256             :     {
    1257        4596 :         ::boost::unordered_map< fontID, PrintFont* >::const_iterator it = m_aFonts.find( *font_it );
    1258        4596 :         if( it == m_aFonts.end() )
    1259           0 :             continue;
    1260        4596 :         switch( it->second->m_eType )
    1261             :         {
    1262             :             case fonttype::Type1:
    1263             :             {
    1264           6 :                 Type1FontFile* const pFont = static_cast< Type1FontFile* const >((*it).second);
    1265          12 :                 if( pFont->m_nDirectory == nDirID &&
    1266           6 :                     pFont->m_aFontFile == rFontFile )
    1267           6 :                     nID = it->first;
    1268             :             }
    1269           6 :             break;
    1270             :             case fonttype::TrueType:
    1271             :             {
    1272        4590 :                 TrueTypeFontFile* const pFont = static_cast< TrueTypeFontFile* const >((*it).second);
    1273        9180 :                 if( pFont->m_nDirectory == nDirID &&
    1274        4590 :                     pFont->m_aFontFile == rFontFile && pFont->m_nCollectionEntry == nFaceIndex )
    1275        3846 :                         nID = it->first;
    1276             :             }
    1277        4590 :             break;
    1278             :             case fonttype::Builtin:
    1279           0 :                 if( static_cast<const BuiltinFont*>((*it).second)->m_nDirectory == nDirID &&
    1280           0 :                     static_cast<const BuiltinFont*>((*it).second)->m_aMetricFile == rFontFile )
    1281           0 :                     nID = it->first;
    1282           0 :                 break;
    1283             :             default:
    1284           0 :                 break;
    1285             :         }
    1286             :     }
    1287             : 
    1288        3852 :     return nID;
    1289             : }
    1290             : 
    1291           0 : std::vector<fontID> PrintFontManager::findFontFileIDs( int nDirID, const OString& rFontFile ) const
    1292             : {
    1293           0 :     std::vector<fontID> aIds;
    1294             : 
    1295           0 :     ::boost::unordered_map< OString, ::std::set< fontID >, OStringHash >::const_iterator set_it = m_aFontFileToFontID.find( rFontFile );
    1296           0 :     if( set_it == m_aFontFileToFontID.end() )
    1297             :         return aIds;
    1298             : 
    1299           0 :     for( ::std::set< fontID >::const_iterator font_it = set_it->second.begin(); font_it != set_it->second.end(); ++font_it )
    1300             :     {
    1301           0 :         ::boost::unordered_map< fontID, PrintFont* >::const_iterator it = m_aFonts.find( *font_it );
    1302           0 :         if( it == m_aFonts.end() )
    1303           0 :             continue;
    1304           0 :         switch( it->second->m_eType )
    1305             :         {
    1306             :             case fonttype::Type1:
    1307             :             {
    1308           0 :                 Type1FontFile* const pFont = static_cast< Type1FontFile* const >((*it).second);
    1309           0 :                 if( pFont->m_nDirectory == nDirID &&
    1310           0 :                     pFont->m_aFontFile == rFontFile )
    1311           0 :                     aIds.push_back(it->first);
    1312             :             }
    1313           0 :             break;
    1314             :             case fonttype::TrueType:
    1315             :             {
    1316           0 :                 TrueTypeFontFile* const pFont = static_cast< TrueTypeFontFile* const >((*it).second);
    1317           0 :                 if( pFont->m_nDirectory == nDirID &&
    1318           0 :                     pFont->m_aFontFile == rFontFile )
    1319           0 :                     aIds.push_back(it->first);
    1320             :             }
    1321           0 :             break;
    1322             :             case fonttype::Builtin:
    1323           0 :                 if( static_cast<const BuiltinFont*>((*it).second)->m_nDirectory == nDirID &&
    1324           0 :                     static_cast<const BuiltinFont*>((*it).second)->m_aMetricFile == rFontFile )
    1325           0 :                     aIds.push_back(it->first);
    1326           0 :                 break;
    1327             :             default:
    1328           0 :                 break;
    1329             :         }
    1330             :     }
    1331             : 
    1332           0 :     return aIds;
    1333             : }
    1334             : 
    1335             : // -------------------------------------------------------------------------
    1336             : 
    1337         366 : OUString PrintFontManager::convertTrueTypeName( void* pRecord ) const
    1338             : {
    1339         366 :     NameRecord* pNameRecord = (NameRecord*)pRecord;
    1340         366 :     OUString aValue;
    1341         366 :     if(
    1342             :        ( pNameRecord->platformID == 3 && ( pNameRecord->encodingID == 0 || pNameRecord->encodingID == 1 ) )  // MS, Unicode
    1343             :        ||
    1344             :        ( pNameRecord->platformID == 0 ) // Apple, Unicode
    1345             :        )
    1346             :     {
    1347         196 :         OUStringBuffer aName( pNameRecord->slen/2 );
    1348         196 :         const sal_uInt8* pNameBuffer = pNameRecord->sptr;
    1349        2552 :         for(int n = 0; n < pNameRecord->slen/2; n++ )
    1350        2356 :             aName.append( (sal_Unicode)getUInt16BE( pNameBuffer ) );
    1351         196 :         aValue = aName.makeStringAndClear();
    1352             :     }
    1353         170 :     else if( pNameRecord->platformID == 3 )
    1354             :     {
    1355           0 :         if( pNameRecord->encodingID >= 2 && pNameRecord->encodingID <= 6 )
    1356             :         {
    1357             :             /*
    1358             :              *  and now for a special kind of madness:
    1359             :              *  some fonts encode their byte value string as BE uint16
    1360             :              *  (leading to stray zero bytes in the string)
    1361             :              *  while others code two bytes as a uint16 and swap to BE
    1362             :              */
    1363           0 :             OStringBuffer aName;
    1364           0 :             const sal_uInt8* pNameBuffer = pNameRecord->sptr;
    1365           0 :             for(int n = 0; n < pNameRecord->slen/2; n++ )
    1366             :             {
    1367           0 :                 sal_Unicode aCode = (sal_Unicode)getUInt16BE( pNameBuffer );
    1368           0 :                 sal_Char aChar = aCode >> 8;
    1369           0 :                 if( aChar )
    1370           0 :                     aName.append( aChar );
    1371           0 :                 aChar = aCode & 0x00ff;
    1372           0 :                 if( aChar )
    1373           0 :                     aName.append( aChar );
    1374             :             }
    1375           0 :             switch( pNameRecord->encodingID )
    1376             :             {
    1377             :                 case 2:
    1378           0 :                     aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_932 );
    1379           0 :                     break;
    1380             :                 case 3:
    1381           0 :                     aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_936 );
    1382           0 :                     break;
    1383             :                 case 4:
    1384           0 :                     aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_950 );
    1385           0 :                     break;
    1386             :                 case 5:
    1387           0 :                     aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_949 );
    1388           0 :                     break;
    1389             :                 case 6:
    1390           0 :                     aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_1361 );
    1391           0 :                     break;
    1392           0 :             }
    1393             :         }
    1394             :     }
    1395         366 :     return aValue;
    1396             : }
    1397             : 
    1398             : //fdo#33349.There exists an archaic Berling Antiqua font which has a "Times New
    1399             : //Roman" name field in it. We don't want the "Times New Roman" name to take
    1400             : //precedence in this case. We take Berling Antiqua as a higher priority name,
    1401             : //and erase the "Times New Roman" name
    1402             : namespace
    1403             : {
    1404         202 :     bool isBadTNR(const OUString &rName, ::std::set< OUString >& rSet)
    1405             :     {
    1406         202 :         bool bRet = false;
    1407         202 :         if ( rName == "Berling Antiqua" )
    1408             :         {
    1409           0 :             ::std::set< OUString >::iterator aEnd = rSet.end();
    1410           0 :             ::std::set< OUString >::iterator aI = rSet.find(OUString(RTL_CONSTASCII_USTRINGPARAM("Times New Roman")));
    1411           0 :             if (aI != aEnd)
    1412             :             {
    1413           0 :                 bRet = true;
    1414           0 :                 rSet.erase(aI);
    1415             :             }
    1416             :         }
    1417         202 :         return bRet;
    1418             :     }
    1419             : }
    1420             : 
    1421             : // -------------------------------------------------------------------------
    1422             : 
    1423         158 : void PrintFontManager::analyzeTrueTypeFamilyName( void* pTTFont, ::std::list< OUString >& rNames ) const
    1424             : {
    1425         158 :     OUString aFamily;
    1426             : 
    1427         158 :     rNames.clear();
    1428         158 :     ::std::set< OUString > aSet;
    1429             : 
    1430         158 :     NameRecord* pNameRecords = NULL;
    1431         158 :     int nNameRecords = GetTTNameRecords( (TrueTypeFont*)pTTFont, &pNameRecords );
    1432         158 :     if( nNameRecords && pNameRecords )
    1433             :     {
    1434         158 :         LanguageType aLang = MsLangId::getSystemLanguage();
    1435         158 :         int nLastMatch = -1;
    1436        4638 :         for( int i = 0; i < nNameRecords; i++ )
    1437             :         {
    1438        4480 :             if( pNameRecords[i].nameID != 1 || pNameRecords[i].sptr == NULL )
    1439        4114 :                 continue;
    1440         366 :             int nMatch = -1;
    1441         366 :             if( pNameRecords[i].platformID == 0 ) // Unicode
    1442           0 :                 nMatch = 4000;
    1443         366 :             else if( pNameRecords[i].platformID == 3 )
    1444             :             {
    1445             :                 // this bases on the LanguageType actually being a Win LCID
    1446         196 :                 if( pNameRecords[i].languageID == aLang )
    1447         158 :                     nMatch = 8000;
    1448          38 :                 else if( pNameRecords[i].languageID == LANGUAGE_ENGLISH_US )
    1449           0 :                     nMatch = 2000;
    1450          76 :                 else if( pNameRecords[i].languageID == LANGUAGE_ENGLISH ||
    1451          38 :                          pNameRecords[i].languageID == LANGUAGE_ENGLISH_UK )
    1452           0 :                     nMatch = 1500;
    1453             :                 else
    1454          38 :                     nMatch = 1000;
    1455             :             }
    1456         366 :             OUString aName = convertTrueTypeName( pNameRecords + i );
    1457         366 :             aSet.insert( aName );
    1458         366 :             if( nMatch > nLastMatch || isBadTNR(aName, aSet) )
    1459             :             {
    1460         164 :                 nLastMatch = nMatch;
    1461         164 :                 aFamily = aName;
    1462             :             }
    1463         366 :         }
    1464         158 :         DisposeNameRecords( pNameRecords, nNameRecords );
    1465             :     }
    1466         158 :     if( !aFamily.isEmpty() )
    1467             :     {
    1468         158 :         rNames.push_front( aFamily );
    1469         494 :         for( ::std::set< OUString >::const_iterator it = aSet.begin(); it != aSet.end(); ++it )
    1470         336 :             if( *it != aFamily )
    1471         178 :                 rNames.push_back( *it );
    1472             :     }
    1473         158 :     return;
    1474             : }
    1475             : 
    1476             : // -------------------------------------------------------------------------
    1477             : 
    1478         158 : bool PrintFontManager::analyzeTrueTypeFile( PrintFont* pFont ) const
    1479             : {
    1480         158 :     bool bSuccess = false;
    1481         158 :     rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
    1482         158 :     rtl::OString aFile = getFontFile( pFont );
    1483         158 :     TrueTypeFont* pTTFont = NULL;
    1484             : 
    1485         158 :     TrueTypeFontFile* pTTFontFile = static_cast< TrueTypeFontFile* >(pFont);
    1486         158 :     if( OpenTTFontFile( aFile.getStr(), pTTFontFile->m_nCollectionEntry, &pTTFont ) == SF_OK )
    1487             :     {
    1488             :         TTGlobalFontInfo aInfo;
    1489         158 :         GetTTGlobalFontInfo( pTTFont, & aInfo );
    1490             : 
    1491         158 :         ::std::list< OUString > aNames;
    1492         158 :         analyzeTrueTypeFamilyName( pTTFont, aNames );
    1493             : 
    1494             :         // set family name from XLFD if possible
    1495         158 :         if( ! pFont->m_nFamilyName )
    1496             :         {
    1497         158 :             if( aNames.begin() != aNames.end() )
    1498             :             {
    1499         158 :                 pFont->m_nFamilyName = m_pAtoms->getAtom( ATOM_FAMILYNAME, aNames.front(), sal_True );
    1500         158 :                 aNames.pop_front();
    1501             :             }
    1502             :             else
    1503             :             {
    1504             :                  sal_Int32   dotIndex;
    1505             : 
    1506             :                  // poor font does not have a family name
    1507             :                  // name it to file name minus the extension
    1508           0 :                  dotIndex = pTTFontFile->m_aFontFile.lastIndexOf( '.' );
    1509           0 :                  if ( dotIndex == -1 )
    1510           0 :                      dotIndex = pTTFontFile->m_aFontFile.getLength();
    1511             : 
    1512           0 :                  pFont->m_nFamilyName = m_pAtoms->getAtom( ATOM_FAMILYNAME, OStringToOUString( pTTFontFile->m_aFontFile.copy( 0, dotIndex ), aEncoding ), sal_True );
    1513             :             }
    1514             :         }
    1515         336 :         for( ::std::list< OUString >::iterator it = aNames.begin(); it != aNames.end(); ++it )
    1516             :         {
    1517         178 :             if( !it->isEmpty() )
    1518             :             {
    1519          20 :                 int nAlias = m_pAtoms->getAtom( ATOM_FAMILYNAME, *it, sal_True );
    1520          20 :                 if( nAlias != pFont->m_nFamilyName )
    1521             :                 {
    1522          20 :                     std::list< int >::const_iterator al_it;
    1523          20 :                     for( al_it = pFont->m_aAliases.begin(); al_it != pFont->m_aAliases.end() && *al_it != nAlias; ++al_it )
    1524             :                         ;
    1525          20 :                     if( al_it == pFont->m_aAliases.end() )
    1526          20 :                         pFont->m_aAliases.push_back( nAlias );
    1527             :                 }
    1528             :             }
    1529             :         }
    1530             : 
    1531         158 :         if( aInfo.usubfamily )
    1532           0 :             pFont->m_aStyleName = OUString( aInfo.usubfamily );
    1533             : 
    1534             :         SAL_WARN_IF( !aInfo.psname, "vcl", "No PostScript name in font:" << aFile.getStr() );
    1535             : 
    1536             :         rtl::OUString sPSName = aInfo.psname ?
    1537             :             rtl::OUString(aInfo.psname, rtl_str_getLength(aInfo.psname), aEncoding) :
    1538         158 :             m_pAtoms->getString(ATOM_FAMILYNAME, pFont->m_nFamilyName); // poor font does not have a postscript name
    1539             : 
    1540         158 :         pFont->m_nPSName = m_pAtoms->getAtom( ATOM_PSNAME, sPSName, sal_True );
    1541             : 
    1542         158 :         switch( aInfo.weight )
    1543             :         {
    1544           0 :             case FW_THIN:           pFont->m_eWeight = WEIGHT_THIN; break;
    1545           2 :             case FW_EXTRALIGHT: pFont->m_eWeight = WEIGHT_ULTRALIGHT; break;
    1546           8 :             case FW_LIGHT:          pFont->m_eWeight = WEIGHT_LIGHT; break;
    1547          10 :             case FW_MEDIUM:     pFont->m_eWeight = WEIGHT_MEDIUM; break;
    1548           2 :             case FW_SEMIBOLD:       pFont->m_eWeight = WEIGHT_SEMIBOLD; break;
    1549          52 :             case FW_BOLD:           pFont->m_eWeight = WEIGHT_BOLD; break;
    1550           0 :             case FW_EXTRABOLD:      pFont->m_eWeight = WEIGHT_ULTRABOLD; break;
    1551           0 :             case FW_BLACK:          pFont->m_eWeight = WEIGHT_BLACK; break;
    1552             : 
    1553             :             case FW_NORMAL:
    1554          84 :             default:        pFont->m_eWeight = WEIGHT_NORMAL; break;
    1555             :         }
    1556             : 
    1557         158 :         switch( aInfo.width )
    1558             :         {
    1559           0 :             case FWIDTH_ULTRA_CONDENSED:    pFont->m_eWidth = WIDTH_ULTRA_CONDENSED; break;
    1560           0 :             case FWIDTH_EXTRA_CONDENSED:    pFont->m_eWidth = WIDTH_EXTRA_CONDENSED; break;
    1561           4 :             case FWIDTH_CONDENSED:          pFont->m_eWidth = WIDTH_CONDENSED; break;
    1562          16 :             case FWIDTH_SEMI_CONDENSED: pFont->m_eWidth = WIDTH_SEMI_CONDENSED; break;
    1563           0 :             case FWIDTH_SEMI_EXPANDED:      pFont->m_eWidth = WIDTH_SEMI_EXPANDED; break;
    1564           0 :             case FWIDTH_EXPANDED:           pFont->m_eWidth = WIDTH_EXPANDED; break;
    1565           0 :             case FWIDTH_EXTRA_EXPANDED: pFont->m_eWidth = WIDTH_EXTRA_EXPANDED; break;
    1566           0 :             case FWIDTH_ULTRA_EXPANDED: pFont->m_eWidth = WIDTH_ULTRA_EXPANDED; break;
    1567             : 
    1568             :             case FWIDTH_NORMAL:
    1569         138 :             default:                        pFont->m_eWidth = WIDTH_NORMAL; break;
    1570             :         }
    1571             : 
    1572         158 :         pFont->m_ePitch = aInfo.pitch ? PITCH_FIXED : PITCH_VARIABLE;
    1573         158 :         pFont->m_eItalic = aInfo.italicAngle == 0 ? ITALIC_NONE : ( aInfo.italicAngle < 0 ? ITALIC_NORMAL : ITALIC_OBLIQUE );
    1574             :         // #104264# there are fonts that set italic angle 0 although they are
    1575             :         // italic; use macstyle bit here
    1576         158 :         if( aInfo.italicAngle == 0 && (aInfo.macStyle & 2) )
    1577           0 :             pFont->m_eItalic = ITALIC_NORMAL;
    1578             : 
    1579         158 :         pFont->m_aEncoding = aInfo.symbolEncoded ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UCS2;
    1580             : 
    1581         158 :         pFont->m_aGlobalMetricY.width = pFont->m_aGlobalMetricX.width = aInfo.xMax - aInfo.xMin;
    1582         158 :         pFont->m_aGlobalMetricY.height = pFont->m_aGlobalMetricX.height = aInfo.yMax - aInfo.yMin;
    1583             : 
    1584         158 :         if( aInfo.winAscent && aInfo.winDescent )
    1585             :         {
    1586         158 :             pFont->m_nAscend    = aInfo.winAscent;
    1587         158 :             pFont->m_nDescend   = aInfo.winDescent;
    1588         158 :             pFont->m_nLeading   = pFont->m_nAscend + pFont->m_nDescend - 1000;
    1589             :         }
    1590           0 :         else if( aInfo.typoAscender && aInfo.typoDescender )
    1591             :         {
    1592           0 :             pFont->m_nLeading   = aInfo.typoLineGap;
    1593           0 :             pFont->m_nAscend    = aInfo.typoAscender;
    1594           0 :             pFont->m_nDescend   = -aInfo.typoDescender;
    1595             :         }
    1596             :         else
    1597             :         {
    1598           0 :             pFont->m_nLeading   = aInfo.linegap;
    1599           0 :             pFont->m_nAscend    = aInfo.ascender;
    1600           0 :             pFont->m_nDescend   = -aInfo.descender;
    1601             :         }
    1602             : 
    1603             :         // last try: font bounding box
    1604         158 :         if( pFont->m_nAscend == 0 )
    1605           0 :             pFont->m_nAscend = aInfo.yMax;
    1606         158 :         if( pFont->m_nDescend == 0 )
    1607           0 :             pFont->m_nDescend = -aInfo.yMin;
    1608         158 :         if( pFont->m_nLeading == 0 )
    1609           0 :             pFont->m_nLeading = 15 * (pFont->m_nAscend+pFont->m_nDescend) / 100;
    1610             : 
    1611         158 :         if( pFont->m_nAscend )
    1612         158 :             pFont->m_aGlobalMetricX.height = pFont->m_aGlobalMetricY.height = pFont->m_nAscend + pFont->m_nDescend;
    1613             : 
    1614             :         // get bounding box
    1615         158 :         pFont->m_nXMin = aInfo.xMin;
    1616         158 :         pFont->m_nYMin = aInfo.yMin;
    1617         158 :         pFont->m_nXMax = aInfo.xMax;
    1618         158 :         pFont->m_nYMax = aInfo.yMax;
    1619             : 
    1620             :         // get type flags
    1621         158 :         pTTFontFile->m_nTypeFlags = (unsigned int)aInfo.typeFlags;
    1622             : 
    1623             :         // get vertical substitutions flag
    1624         158 :         pFont->m_bHaveVerticalSubstitutedGlyphs = DoesVerticalSubstitution( pTTFont, 1 );
    1625             : 
    1626         158 :         CloseTTFont( pTTFont );
    1627         158 :         bSuccess = true;
    1628             :     }
    1629             : #if OSL_DEBUG_LEVEL > 1
    1630             :     else
    1631             :         fprintf( stderr, "could not OpenTTFont \"%s\"\n", aFile.getStr() );
    1632             : #endif
    1633             : 
    1634         158 :     return bSuccess;
    1635             : }
    1636             : 
    1637          20 : static bool AreFCSubstitutionsEnabled()
    1638             : {
    1639          20 :     return (SalGenericInstance::FetchFontSubstitutionFlags() & 3) == 0;
    1640             : }
    1641             : 
    1642          20 : void PrintFontManager::initialize()
    1643             : {
    1644             :     #ifdef CALLGRIND_COMPILE
    1645             :     CALLGRIND_TOGGLE_COLLECT();
    1646             :     CALLGRIND_ZERO_STATS();
    1647             :     #endif
    1648             : 
    1649             :     long aDirEntBuffer[ (sizeof(struct dirent)+_PC_NAME_MAX)+1 ];
    1650             : 
    1651          20 :     if( ! m_pFontCache )
    1652             :     {
    1653             : #if OSL_DEBUG_LEVEL > 1
    1654             :         fprintf( stderr, "creating font cache ... " );
    1655             :         clock_t aStart;
    1656             :         struct tms tms;
    1657             :         aStart = times( &tms );
    1658             : #endif
    1659          20 :         m_pFontCache = new FontCache();
    1660             : #if OSL_DEBUG_LEVEL > 1
    1661             :         clock_t aStop = times( &tms );
    1662             :         fprintf( stderr, "done in %lf s\n", (double)(aStop - aStart)/(double)sysconf( _SC_CLK_TCK ) );
    1663             : #endif
    1664             :     }
    1665             : 
    1666             :     // initialize can be called more than once, e.g.
    1667             :     // gtk-fontconfig-timestamp changes to reflect new font installed and
    1668             :     // PrintFontManager::initialize called again
    1669             :     {
    1670          20 :         for( ::boost::unordered_map< fontID, PrintFont* >::const_iterator it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
    1671           0 :             delete (*it).second;
    1672          20 :         m_nNextFontID = 1;
    1673          20 :         m_aFonts.clear();
    1674          20 :         m_aFontDirectories.clear();
    1675          20 :         m_aPrivateFontDirectories.clear();
    1676          20 :         m_aOverrideFonts.clear();
    1677             :     }
    1678             : 
    1679             : #if OSL_DEBUG_LEVEL > 1
    1680             :     clock_t aStart;
    1681             :     clock_t aStep1;
    1682             :     clock_t aStep2;
    1683             :     clock_t aStep3;
    1684             :     int nBuiltinFonts = 0;
    1685             :     int nCached = 0;
    1686             : 
    1687             :     struct tms tms;
    1688             : 
    1689             :     aStart = times( &tms );
    1690             : #endif
    1691             : 
    1692             :     // first try fontconfig
    1693          20 :     initFontconfig();
    1694             : 
    1695             :     // part one - look for downloadable fonts
    1696          20 :     rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
    1697          20 :     const ::rtl::OUString &rSalPrivatePath = psp::getFontPath();
    1698             : 
    1699             :     // search for the fonts in SAL_PRIVATE_FONTPATH first; those are
    1700             :     // the fonts installed with the office
    1701          20 :     if( !rSalPrivatePath.isEmpty() )
    1702             :     {
    1703          20 :         OString aPath = rtl::OUStringToOString( rSalPrivatePath, aEncoding );
    1704          20 :         const bool bAreFCSubstitutionsEnabled = AreFCSubstitutionsEnabled();
    1705          20 :         sal_Int32 nIndex = 0;
    1706          60 :         do
    1707             :         {
    1708          60 :             OString aToken = aPath.getToken( 0, ';', nIndex );
    1709          60 :             normPath( aToken );
    1710          60 :             if ( aToken.isEmpty() )
    1711             :             {
    1712           1 :                 continue;
    1713             :             }
    1714             :             // if registering an app-specific fontdir with fontconfig fails
    1715             :             // and fontconfig-based substitutions are enabled
    1716             :             // then trying to use these app-specific fonts doesn't make sense
    1717          59 :             if( !addFontconfigDir( aToken ) )
    1718           0 :                 if( bAreFCSubstitutionsEnabled )
    1719           0 :                     continue;
    1720          59 :             m_aFontDirectories.push_back( aToken );
    1721          59 :             m_aPrivateFontDirectories.push_back( getDirectoryAtom( aToken, true ) );
    1722          20 :         } while( nIndex >= 0 );
    1723             :     }
    1724             : 
    1725             :     // protect against duplicate paths
    1726          20 :     boost::unordered_map< OString, int, OStringHash > visited_dirs;
    1727             : 
    1728             :     // Don't search directories that fontconfig already did
    1729          20 :     countFontconfigFonts( visited_dirs );
    1730             : 
    1731             :     // search for font files in each path
    1732          20 :     std::list< OString >::iterator dir_it;
    1733          79 :     for( dir_it = m_aFontDirectories.begin(); dir_it != m_aFontDirectories.end(); ++dir_it )
    1734             :     {
    1735          59 :         OString aPath( *dir_it );
    1736             :         // see if we were here already
    1737          59 :         if( visited_dirs.find( aPath ) != visited_dirs.end() )
    1738           0 :             continue;
    1739          59 :         visited_dirs[ aPath ] = 1;
    1740             : 
    1741             :         // there may be ":unscaled" directories (see XFree86)
    1742             :         // it should be safe to ignore them since they should not
    1743             :         // contain any of our recognizeable fonts
    1744             : 
    1745             :         // ask the font cache whether it handles this directory
    1746          59 :         std::list< PrintFont* > aCacheFonts;
    1747          59 :         if( m_pFontCache->listDirectory( aPath, aCacheFonts ) )
    1748             :         {
    1749             : #if OSL_DEBUG_LEVEL > 1
    1750             :             fprintf( stderr, "adding cache directory: %s\n", aPath.getStr() );
    1751             : #endif
    1752           0 :             for( ::std::list< PrintFont* >::iterator it = aCacheFonts.begin(); it != aCacheFonts.end(); ++it )
    1753             :             {
    1754           0 :                 fontID aFont = m_nNextFontID++;
    1755           0 :                 m_aFonts[ aFont ] = *it;
    1756           0 :                 if( (*it)->m_eType == fonttype::Type1 )
    1757           0 :                     m_aFontFileToFontID[ static_cast<Type1FontFile*>(*it)->m_aFontFile ].insert( aFont );
    1758           0 :                 else if( (*it)->m_eType == fonttype::TrueType )
    1759           0 :                     m_aFontFileToFontID[ static_cast<TrueTypeFontFile*>(*it)->m_aFontFile ].insert( aFont );
    1760           0 :                 else if( (*it)->m_eType == fonttype::Builtin )
    1761           0 :                     m_aFontFileToFontID[ static_cast<BuiltinFont*>(*it)->m_aMetricFile ].insert( aFont );
    1762             : #if OSL_DEBUG_LEVEL > 1
    1763             :                 if( (*it)->m_eType == fonttype::Builtin )
    1764             :                     nBuiltinFonts++;
    1765             :                 nCached++;
    1766             : #if OSL_DEBUG_LEVEL > 2
    1767             :                 fprintf( stderr, "adding cached font %d: %s\n", aFont, getFontFileSysPath( aFont ).getStr() );
    1768             : #endif
    1769             : #endif
    1770             :             }
    1771           0 :             if( ! m_pFontCache->scanAdditionalFiles( aPath ) )
    1772           0 :                 continue;
    1773             :         }
    1774             : 
    1775          59 :     }
    1776             : 
    1777             : #if OSL_DEBUG_LEVEL > 1
    1778             :     aStep1 = times( &tms );
    1779             : #endif
    1780             : 
    1781             :     // part two - look for metrics for builtin printer fonts
    1782          20 :     std::list< OUString > aMetricDirs;
    1783          20 :     psp::getPrinterPathList( aMetricDirs, PRINTER_METRICDIR );
    1784             : 
    1785          59 :     for( std::list< OUString >::const_iterator met_dir_it = aMetricDirs.begin(); met_dir_it != aMetricDirs.end(); ++met_dir_it )
    1786             :     {
    1787          39 :         OString aDir = OUStringToOString( *met_dir_it, aEncoding );
    1788             : 
    1789             :         // ask the font cache whether it handles this directory
    1790          39 :         std::list< PrintFont* > aCacheFonts;
    1791             : 
    1792          39 :         if( m_pFontCache->listDirectory( aDir, aCacheFonts ) )
    1793             :         {
    1794             : #if OSL_DEBUG_LEVEL > 1
    1795             :             fprintf( stderr, "adding cache directory: %s\n", aDir.getStr() );
    1796             : #endif
    1797          18 :             for( ::std::list< PrintFont* >::iterator it = aCacheFonts.begin(); it != aCacheFonts.end(); ++it )
    1798             :             {
    1799           0 :                 fontID aFont = m_nNextFontID++;
    1800           0 :                 m_aFonts[ aFont ] = *it;
    1801           0 :                 if( (*it)->m_eType == fonttype::Type1 )
    1802           0 :                     m_aFontFileToFontID[ static_cast<Type1FontFile*>(*it)->m_aFontFile ].insert( aFont );
    1803           0 :                 else if( (*it)->m_eType == fonttype::TrueType )
    1804           0 :                     m_aFontFileToFontID[ static_cast<TrueTypeFontFile*>(*it)->m_aFontFile ].insert( aFont );
    1805           0 :                 else if( (*it)->m_eType == fonttype::Builtin )
    1806           0 :                     m_aFontFileToFontID[ static_cast<BuiltinFont*>(*it)->m_aMetricFile ].insert( aFont );
    1807             : #if OSL_DEBUG_LEVEL > 1
    1808             :                 if( (*it)->m_eType == fonttype::Builtin )
    1809             :                     nBuiltinFonts++;
    1810             :                 nCached++;
    1811             : #if OSL_DEBUG_LEVEL > 2
    1812             :                 fprintf( stderr, "adding cached font %d: from %s\n", aFont,
    1813             :                          getFontFileSysPath( aFont ).getStr() );
    1814             : #endif
    1815             : #endif
    1816             :             }
    1817          18 :             continue;
    1818             :         }
    1819             : 
    1820          21 :         DIR* pDIR = opendir( aDir.getStr() );
    1821          21 :         if( pDIR )
    1822             :         {
    1823           1 :             struct dirent* pDirEntry = (struct dirent*)aDirEntBuffer;
    1824           1 :             int nDirID = getDirectoryAtom( aDir, true );
    1825           1 :             int nDirFonts = 0;
    1826             : 
    1827           5 :             while( ! readdir_r( pDIR, (struct dirent*)aDirEntBuffer, &pDirEntry ) && pDirEntry )
    1828             :             {
    1829           3 :                 rtl::OStringBuffer aFile(aDir);
    1830           3 :                 aFile.append('/').append(pDirEntry->d_name);
    1831             :                 struct stat aStat;
    1832           3 :                 if( ! stat( aFile.getStr(), &aStat )
    1833             :                     && S_ISREG( aStat.st_mode )
    1834             :                     )
    1835             :                 {
    1836           1 :                     OString aFileName( pDirEntry->d_name, strlen( pDirEntry->d_name ) );
    1837           1 :                     OString aExt( aFileName.copy( aFileName.lastIndexOf( '.' )+1 ) );
    1838           1 :                     if( aExt.equalsIgnoreAsciiCase( "afm" ) )
    1839             :                     {
    1840           0 :                         ::std::list< PrintFont* > aNewFonts;
    1841             : 
    1842           0 :                         analyzeFontFile( nDirID, aFileName, aNewFonts );
    1843           0 :                         for( ::std::list< PrintFont* >::iterator it = aNewFonts.begin(); it != aNewFonts.end(); ++it )
    1844             :                         {
    1845           0 :                             if( findFontBuiltinID( (*it)->m_nPSName ) == 0 )
    1846             :                             {
    1847           0 :                                 m_aFontFileToFontID[ aFileName ].insert( m_nNextFontID );
    1848           0 :                                 m_aFonts[ m_nNextFontID++ ] = *it;
    1849           0 :                                 m_pFontCache->updateFontCacheEntry( *it, false );
    1850             : #if OSL_DEBUG_LEVEL > 2
    1851             :                                 nBuiltinFonts++;
    1852             : #endif
    1853             :                             }
    1854             :                             else
    1855           0 :                                 delete *it;
    1856           0 :                         }
    1857           1 :                     }
    1858             :                 }
    1859           3 :             }
    1860           1 :             closedir( pDIR );
    1861           1 :             if( ! nDirFonts )
    1862           1 :                 m_pFontCache->markEmptyDir( nDirID );
    1863             :         }
    1864          39 :     }
    1865             : 
    1866             : #if OSL_DEBUG_LEVEL > 1
    1867             :     aStep2 = times( &tms );
    1868             : #endif
    1869             : 
    1870             :     // part three - fill in family styles
    1871          20 :     ::boost::unordered_map< fontID, PrintFont* >::iterator font_it;
    1872        2300 :     for (font_it = m_aFonts.begin(); font_it != m_aFonts.end(); ++font_it)
    1873             :     {
    1874             :         ::boost::unordered_map< int, FontFamily >::const_iterator it =
    1875        2280 :               m_aFamilyTypes.find( font_it->second->m_nFamilyName );
    1876        2280 :         if (it != m_aFamilyTypes.end())
    1877        1240 :             continue;
    1878             :         const ::rtl::OUString& rFamily =
    1879        1040 :             m_pAtoms->getString( ATOM_FAMILYNAME, font_it->second->m_nFamilyName);
    1880        1040 :         FontFamily eType = matchFamilyName( rFamily );
    1881        1040 :         m_aFamilyTypes[ font_it->second->m_nFamilyName ] = eType;
    1882             :     }
    1883             : 
    1884             : #if OSL_DEBUG_LEVEL > 1
    1885             :     aStep3 = times( &tms );
    1886             :     fprintf( stderr, "PrintFontManager::initialize: collected %" SAL_PRI_SIZET "u fonts (%d builtin, %d cached)\n", m_aFonts.size(), nBuiltinFonts, nCached );
    1887             :     double fTick = (double)sysconf( _SC_CLK_TCK );
    1888             :     fprintf( stderr, "Step 1 took %lf seconds\n", (double)(aStep1 - aStart)/fTick );
    1889             :     fprintf( stderr, "Step 2 took %lf seconds\n", (double)(aStep2 - aStep1)/fTick );
    1890             :     fprintf( stderr, "Step 3 took %lf seconds\n", (double)(aStep3 - aStep2)/fTick );
    1891             : #endif
    1892             : 
    1893          20 :     m_pFontCache->flush();
    1894             : 
    1895             :     #ifdef CALLGRIND_COMPILE
    1896             :     CALLGRIND_DUMP_STATS();
    1897             :     CALLGRIND_TOGGLE_COLLECT();
    1898             :     #endif
    1899          20 : }
    1900             : 
    1901             : // -------------------------------------------------------------------------
    1902             : inline bool
    1903           0 : equalPitch (FontPitch from, FontPitch to)
    1904             : {
    1905           0 :     return from == to;
    1906             : }
    1907             : 
    1908             : inline bool
    1909           0 : equalWeight (FontWeight from, FontWeight to)
    1910             : {
    1911           0 :     return from > to ? (from - to) <= 3 : (to - from) <= 3;
    1912             : }
    1913             : 
    1914             : inline bool
    1915           0 : equalItalic (FontItalic from, FontItalic to)
    1916             : {
    1917           0 :     if ( (from == ITALIC_NORMAL) || (from == ITALIC_OBLIQUE) )
    1918           0 :         return (to == ITALIC_NORMAL) || (to == ITALIC_OBLIQUE);
    1919           0 :     return to == from;
    1920             : }
    1921             : inline bool
    1922           0 : equalEncoding (rtl_TextEncoding from, rtl_TextEncoding to)
    1923             : {
    1924           0 :     if ((from == RTL_TEXTENCODING_ISO_8859_1) || (from == RTL_TEXTENCODING_MS_1252))
    1925           0 :         return (to == RTL_TEXTENCODING_ISO_8859_1) || (to == RTL_TEXTENCODING_MS_1252);
    1926           0 :     return from == to;
    1927             : }
    1928             : 
    1929             : namespace {
    1930           0 :     struct BuiltinFontIdentifier
    1931             :     {
    1932             :         OUString            aFamily;
    1933             :         FontItalic          eItalic;
    1934             :         FontWeight          eWeight;
    1935             :         FontPitch           ePitch;
    1936             :         rtl_TextEncoding    aEncoding;
    1937             : 
    1938           0 :         BuiltinFontIdentifier( const OUString& rFam,
    1939             :                                FontItalic eIt,
    1940             :                                FontWeight eWg,
    1941             :                                FontPitch ePt,
    1942             :                                rtl_TextEncoding enc ) :
    1943             :             aFamily( rFam ),
    1944             :             eItalic( eIt ),
    1945             :             eWeight( eWg ),
    1946             :             ePitch( ePt ),
    1947           0 :             aEncoding( enc )
    1948           0 :         {}
    1949             : 
    1950           0 :         bool operator==( const BuiltinFontIdentifier& rRight ) const
    1951             :         {
    1952           0 :             return equalItalic( eItalic, rRight.eItalic ) &&
    1953           0 :                    equalWeight( eWeight, rRight.eWeight ) &&
    1954           0 :                    equalPitch( ePitch, rRight.ePitch ) &&
    1955           0 :                    equalEncoding( aEncoding, rRight.aEncoding ) &&
    1956           0 :                    aFamily.equalsIgnoreAsciiCase( rRight.aFamily );
    1957             :         }
    1958             :     };
    1959             : 
    1960             :     struct BuiltinFontIdentifierHash
    1961             :     {
    1962           0 :         size_t operator()( const BuiltinFontIdentifier& rFont ) const
    1963             :         {
    1964           0 :             return rFont.aFamily.hashCode() ^ rFont.eItalic ^ rFont.eWeight ^ rFont.ePitch ^ rFont.aEncoding;
    1965             :         }
    1966             :     };
    1967             : }
    1968             : 
    1969          23 : void PrintFontManager::getFontList( ::std::list< fontID >& rFontIDs, const PPDParser* pParser, bool bUseOverrideMetrics )
    1970             : {
    1971          23 :     rFontIDs.clear();
    1972          23 :     boost::unordered_map< fontID, PrintFont* >::const_iterator it;
    1973             : 
    1974             :     /*
    1975             :     * Note: there are two easy steps making this faster:
    1976             :     * first: insert the printer builtins first, then the not builtins,
    1977             :     * if they do not match.
    1978             :     * drawback: this would change the sequence of fonts; this could have
    1979             :     * subtle, unknown consequences in vcl font matching
    1980             :     * second: instead of comparing attributes to see whether a softfont
    1981             :     * is duplicate to a builtin one could simply compare the PSName (which is
    1982             :     * supposed to be unique), which at this point is just an int.
    1983             :     * drawback: this could change which fonts are listed; especially TrueType
    1984             :     * fonts often have a rather dubious PSName, so this could change the
    1985             :     * font list not so subtle.
    1986             :     * Until getFontList for a printer becomes a performance issue (which is
    1987             :     * currently not the case), best stay with the current algorithm.
    1988             :     */
    1989             : 
    1990             :     // fill sets of printer supported fonts
    1991          23 :     if( pParser )
    1992             :     {
    1993           0 :         std::set<int> aBuiltinPSNames;
    1994             :         boost::unordered_set< BuiltinFontIdentifier,
    1995             :                        BuiltinFontIdentifierHash
    1996           0 :                        > aBuiltinFonts;
    1997             : 
    1998           0 :         std::map<int, fontID > aOverridePSNames;
    1999           0 :         if( bUseOverrideMetrics )
    2000             :         {
    2001           0 :             readOverrideMetrics();
    2002           0 :             for( std::vector<fontID>::const_iterator over = m_aOverrideFonts.begin();
    2003           0 :                  over != m_aOverrideFonts.end(); ++over )
    2004             :             {
    2005           0 :                 boost::unordered_map<fontID,PrintFont*>::const_iterator font_it = m_aFonts.find( *over );
    2006             :                 DBG_ASSERT( font_it != m_aFonts.end(), "override to nonexistant font" );
    2007           0 :                 if( font_it != m_aFonts.end() )
    2008           0 :                     aOverridePSNames[ font_it->second->m_nPSName ] = *over;
    2009             :             }
    2010             :         }
    2011             : 
    2012           0 :         int nFonts = pParser->getFonts();
    2013           0 :         for( int i = 0; i < nFonts; i++ )
    2014           0 :             aBuiltinPSNames.insert( m_pAtoms->getAtom( ATOM_PSNAME, pParser->getFont( i ) ) );
    2015           0 :         for( it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
    2016             :         {
    2017           0 :             PrintFont* pFont = it->second;
    2018           0 :             if( it->second->m_eType == fonttype::Builtin &&
    2019           0 :                 aBuiltinPSNames.find( pFont->m_nPSName ) != aBuiltinPSNames.end() )
    2020             :             {
    2021           0 :                 bool bInsert = true;
    2022           0 :                 if( bUseOverrideMetrics )
    2023             :                 {
    2024             :                     // in override case only use the override fonts, not their counterparts
    2025           0 :                     std::map<int,fontID>::const_iterator over = aOverridePSNames.find( pFont->m_nPSName );
    2026           0 :                     if( over != aOverridePSNames.end() && over->second != it->first )
    2027           0 :                         bInsert = false;
    2028             :                 }
    2029             :                 else
    2030             :                 {
    2031             :                     // do not insert override fonts in non override case
    2032           0 :                     if( std::find( m_aOverrideFonts.begin(), m_aOverrideFonts.end(), it->first ) != m_aOverrideFonts.end() )
    2033           0 :                         bInsert = false;
    2034             :                 }
    2035           0 :                 if( bInsert )
    2036             :                 {
    2037             :                     aBuiltinFonts.insert( BuiltinFontIdentifier(
    2038           0 :                         m_pAtoms->getString( ATOM_FAMILYNAME, pFont->m_nFamilyName ),
    2039             :                         pFont->m_eItalic,
    2040             :                         pFont->m_eWeight,
    2041             :                         pFont->m_ePitch,
    2042             :                         pFont->m_aEncoding
    2043           0 :                         ) );
    2044             :                 }
    2045             :             }
    2046             :         }
    2047           0 :         for( it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
    2048             :         {
    2049           0 :             PrintFont* pFont = it->second;
    2050           0 :             if( it->second->m_eType == fonttype::Builtin )
    2051             :             {
    2052           0 :                 if( aBuiltinPSNames.find( pFont->m_nPSName ) != aBuiltinPSNames.end() )
    2053             :                 {
    2054           0 :                     bool bInsert = true;
    2055           0 :                     if( bUseOverrideMetrics )
    2056             :                     {
    2057             :                         // in override case only use the override fonts, not their counterparts
    2058           0 :                         std::map<int,fontID>::const_iterator over = aOverridePSNames.find( pFont->m_nPSName );
    2059           0 :                         if( over != aOverridePSNames.end() && over->second != it->first )
    2060           0 :                             bInsert = false;
    2061             :                     }
    2062             :                     else
    2063             :                     {
    2064             :                         // do not insert override fonts in non override case
    2065           0 :                         if( std::find( m_aOverrideFonts.begin(), m_aOverrideFonts.end(), it->first ) != m_aOverrideFonts.end() )
    2066           0 :                             bInsert = false;
    2067             :                     }
    2068           0 :                     if( bInsert )
    2069           0 :                         rFontIDs.push_back( it->first );
    2070             :                 }
    2071             :             }
    2072           0 :             else if( aBuiltinFonts.find( BuiltinFontIdentifier(
    2073           0 :                 m_pAtoms->getString( ATOM_FAMILYNAME, pFont->m_nFamilyName ),
    2074             :                 pFont->m_eItalic,
    2075             :                 pFont->m_eWeight,
    2076             :                 pFont->m_ePitch,
    2077             :                 pFont->m_aEncoding
    2078           0 :                 ) ) == aBuiltinFonts.end() )
    2079             :             {
    2080           0 :                 rFontIDs.push_back( it->first );
    2081             :             }
    2082           0 :         }
    2083             :     }
    2084             :     else // no specific printer
    2085             :     {
    2086        2645 :         for( it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
    2087        2622 :             rFontIDs.push_back( it->first );
    2088             :     }
    2089          23 : }
    2090             : 
    2091             : // -------------------------------------------------------------------------
    2092             : 
    2093        6474 : void PrintFontManager::fillPrintFontInfo( PrintFont* pFont, FastPrintFontInfo& rInfo ) const
    2094             : {
    2095             :     ::boost::unordered_map< int, FontFamily >::const_iterator style_it =
    2096        6474 :           m_aFamilyTypes.find( pFont->m_nFamilyName );
    2097        6474 :     rInfo.m_eType           = pFont->m_eType;
    2098        6474 :     rInfo.m_aFamilyName     = m_pAtoms->getString( ATOM_FAMILYNAME, pFont->m_nFamilyName );
    2099        6474 :     rInfo.m_aStyleName      = pFont->m_aStyleName;
    2100        6474 :     rInfo.m_eFamilyStyle    = style_it != m_aFamilyTypes.end() ? style_it->second : FAMILY_DONTKNOW;
    2101        6474 :     rInfo.m_eItalic         = pFont->m_eItalic;
    2102        6474 :     rInfo.m_eWidth          = pFont->m_eWidth;
    2103        6474 :     rInfo.m_eWeight         = pFont->m_eWeight;
    2104        6474 :     rInfo.m_ePitch          = pFont->m_ePitch;
    2105        6474 :     rInfo.m_aEncoding       = pFont->m_aEncoding;
    2106             : 
    2107        6474 :     rInfo.m_bEmbeddable  = (pFont->m_eType == fonttype::Type1);
    2108        6474 :     rInfo.m_bSubsettable = (pFont->m_eType == fonttype::TrueType); // TODO: rename to SfntType
    2109             : 
    2110        6474 :     rInfo.m_aAliases.clear();
    2111        7610 :     for( ::std::list< int >::iterator it = pFont->m_aAliases.begin(); it != pFont->m_aAliases.end(); ++it )
    2112        1136 :         rInfo.m_aAliases.push_back( m_pAtoms->getString( ATOM_FAMILYNAME, *it ) );
    2113        6474 : }
    2114             : 
    2115             : // -------------------------------------------------------------------------
    2116             : 
    2117           0 : void PrintFontManager::fillPrintFontInfo( PrintFont* pFont, PrintFontInfo& rInfo ) const
    2118             : {
    2119           0 :     if( ( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 ) ||
    2120           0 :         ! pFont->m_pMetrics || pFont->m_pMetrics->isEmpty()
    2121             :         )
    2122             :     {
    2123             :         // might be a truetype font not analyzed or type1 without metrics read
    2124           0 :         if( pFont->m_eType == fonttype::Type1 )
    2125           0 :             pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, false );
    2126           0 :         else if( pFont->m_eType == fonttype::TrueType )
    2127           0 :             analyzeTrueTypeFile( pFont );
    2128             :     }
    2129             : 
    2130           0 :     fillPrintFontInfo( pFont, static_cast< FastPrintFontInfo& >( rInfo ) );
    2131             : 
    2132           0 :     rInfo.m_nAscend         = pFont->m_nAscend;
    2133           0 :     rInfo.m_nDescend        = pFont->m_nDescend;
    2134           0 :     rInfo.m_nLeading        = pFont->m_nLeading;
    2135           0 :     rInfo.m_nWidth          = pFont->m_aGlobalMetricX.width < pFont->m_aGlobalMetricY.width ? pFont->m_aGlobalMetricY.width : pFont->m_aGlobalMetricX.width;
    2136           0 : }
    2137             : 
    2138             : // -------------------------------------------------------------------------
    2139             : 
    2140           0 : void PrintFontManager::getFontListWithFastInfo( ::std::list< FastPrintFontInfo >& rFonts, const PPDParser* pParser, bool bUseOverrideMetrics )
    2141             : {
    2142           0 :     rFonts.clear();
    2143           0 :     ::std::list< fontID > aFontList;
    2144           0 :     getFontList( aFontList, pParser, bUseOverrideMetrics );
    2145             : 
    2146           0 :     ::std::list< fontID >::iterator it;
    2147           0 :     for( it = aFontList.begin(); it != aFontList.end(); ++it )
    2148             :     {
    2149           0 :         FastPrintFontInfo aInfo;
    2150           0 :         aInfo.m_nID = *it;
    2151           0 :         fillPrintFontInfo( getFont( *it ), aInfo );
    2152           0 :         rFonts.push_back( aInfo );
    2153           0 :     }
    2154           0 : }
    2155             : 
    2156             : // -------------------------------------------------------------------------
    2157             : 
    2158           0 : bool PrintFontManager::getFontInfo( fontID nFontID, PrintFontInfo& rInfo ) const
    2159             : {
    2160           0 :     PrintFont* pFont = getFont( nFontID );
    2161           0 :     if( pFont )
    2162             :     {
    2163           0 :         rInfo.m_nID = nFontID;
    2164           0 :         fillPrintFontInfo( pFont, rInfo );
    2165             :     }
    2166           0 :     return pFont ? true : false;
    2167             : }
    2168             : 
    2169             : // -------------------------------------------------------------------------
    2170             : 
    2171        6474 : bool PrintFontManager::getFontFastInfo( fontID nFontID, FastPrintFontInfo& rInfo ) const
    2172             : {
    2173        6474 :     PrintFont* pFont = getFont( nFontID );
    2174        6474 :     if( pFont )
    2175             :     {
    2176        6474 :         rInfo.m_nID = nFontID;
    2177        6474 :         fillPrintFontInfo( pFont, rInfo );
    2178             :     }
    2179        6474 :     return pFont ? true : false;
    2180             : }
    2181             : 
    2182             : // -------------------------------------------------------------------------
    2183             : 
    2184           0 : bool PrintFontManager::getFontBoundingBox( fontID nFontID, int& xMin, int& yMin, int& xMax, int& yMax )
    2185             : {
    2186           0 :     bool bSuccess = false;
    2187           0 :     PrintFont* pFont = getFont( nFontID );
    2188           0 :     if( pFont )
    2189             :     {
    2190           0 :         if( pFont->m_nXMin == 0 && pFont->m_nYMin == 0 && pFont->m_nXMax == 0 && pFont->m_nYMax == 0 )
    2191             :         {
    2192             :             // might be a truetype font not analyzed or type1 without metrics read
    2193           0 :             if( pFont->m_eType == fonttype::Type1 || pFont->m_eType == fonttype::Builtin )
    2194           0 :                 pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, true );
    2195           0 :             else if( pFont->m_eType == fonttype::TrueType )
    2196           0 :                 analyzeTrueTypeFile( pFont );
    2197             :         }
    2198           0 :         bSuccess = true;
    2199           0 :         xMin = pFont->m_nXMin;
    2200           0 :         yMin = pFont->m_nYMin;
    2201           0 :         xMax = pFont->m_nXMax;
    2202           0 :         yMax = pFont->m_nYMax;
    2203             :     }
    2204           0 :     return bSuccess;
    2205             : }
    2206             : 
    2207             : // -------------------------------------------------------------------------
    2208             : 
    2209        2622 : int PrintFontManager::getFontFaceNumber( fontID nFontID ) const
    2210             : {
    2211        2622 :     int nRet = 0;
    2212        2622 :     PrintFont* pFont = getFont( nFontID );
    2213        2622 :     if( pFont && pFont->m_eType == fonttype::TrueType )
    2214        1817 :         nRet = static_cast< TrueTypeFontFile* >(pFont)->m_nCollectionEntry;
    2215        2622 :     if (nRet < 0)
    2216           0 :         nRet = 0;
    2217        2622 :     return nRet;
    2218             : }
    2219             : 
    2220             : // -------------------------------------------------------------------------
    2221             : 
    2222             : 
    2223        1040 : FontFamily PrintFontManager::matchFamilyName( const ::rtl::OUString& rFamily ) const
    2224             : {
    2225             :     typedef struct {
    2226             :         const char*  mpName;
    2227             :         sal_uInt16   mnLength;
    2228             :         FontFamily   meType;
    2229             :     } family_t;
    2230             : 
    2231             : #define InitializeClass( p, a ) p, sizeof(p) - 1, a
    2232             :     const family_t pFamilyMatch[] =  {
    2233             :         { InitializeClass( "arial",                  FAMILY_SWISS )  },
    2234             :         { InitializeClass( "arioso",                 FAMILY_SCRIPT ) },
    2235             :         { InitializeClass( "avant garde",            FAMILY_SWISS )  },
    2236             :         { InitializeClass( "avantgarde",             FAMILY_SWISS )  },
    2237             :         { InitializeClass( "bembo",                  FAMILY_ROMAN )  },
    2238             :         { InitializeClass( "bookman",                FAMILY_ROMAN )  },
    2239             :         { InitializeClass( "conga",                  FAMILY_ROMAN )  },
    2240             :         { InitializeClass( "courier",                FAMILY_MODERN ) },
    2241             :         { InitializeClass( "curl",                   FAMILY_SCRIPT ) },
    2242             :         { InitializeClass( "fixed",                  FAMILY_MODERN ) },
    2243             :         { InitializeClass( "gill",                   FAMILY_SWISS )  },
    2244             :         { InitializeClass( "helmet",                 FAMILY_MODERN ) },
    2245             :         { InitializeClass( "helvetica",              FAMILY_SWISS )  },
    2246             :         { InitializeClass( "international",          FAMILY_MODERN ) },
    2247             :         { InitializeClass( "lucida",                 FAMILY_SWISS )  },
    2248             :         { InitializeClass( "new century schoolbook", FAMILY_ROMAN )  },
    2249             :         { InitializeClass( "palatino",               FAMILY_ROMAN )  },
    2250             :         { InitializeClass( "roman",                  FAMILY_ROMAN )  },
    2251             :         { InitializeClass( "sans serif",             FAMILY_SWISS )  },
    2252             :         { InitializeClass( "sansserif",              FAMILY_SWISS )  },
    2253             :         { InitializeClass( "serf",                   FAMILY_ROMAN )  },
    2254             :         { InitializeClass( "serif",                  FAMILY_ROMAN )  },
    2255             :         { InitializeClass( "times",                  FAMILY_ROMAN )  },
    2256             :         { InitializeClass( "utopia",                 FAMILY_ROMAN )  },
    2257             :         { InitializeClass( "zapf chancery",          FAMILY_SCRIPT ) },
    2258             :         { InitializeClass( "zapfchancery",           FAMILY_SCRIPT ) }
    2259        1040 :     };
    2260             : 
    2261        1040 :     rtl::OString aFamily = rtl::OUStringToOString( rFamily, RTL_TEXTENCODING_ASCII_US );
    2262        1040 :     sal_uInt32 nLower = 0;
    2263        1040 :     sal_uInt32 nUpper = SAL_N_ELEMENTS(pFamilyMatch);
    2264             : 
    2265        7160 :     while( nLower < nUpper )
    2266             :     {
    2267        5080 :         sal_uInt32 nCurrent = (nLower + nUpper) / 2;
    2268        5080 :         const family_t* pHaystack = pFamilyMatch + nCurrent;
    2269             :         sal_Int32  nComparison =
    2270             :             rtl_str_compareIgnoreAsciiCase_WithLength
    2271             :             (
    2272             :              aFamily.getStr(), aFamily.getLength(),
    2273             :              pHaystack->mpName, pHaystack->mnLength
    2274        5080 :              );
    2275             : 
    2276        5080 :         if( nComparison < 0 )
    2277        3280 :             nUpper = nCurrent;
    2278             :         else
    2279        1800 :             if( nComparison > 0 )
    2280        1800 :                 nLower = nCurrent + 1;
    2281             :             else
    2282           0 :                 return pHaystack->meType;
    2283             :     }
    2284             : 
    2285        1040 :     return FAMILY_DONTKNOW;
    2286             : }
    2287             : 
    2288             : // -------------------------------------------------------------------------
    2289             : 
    2290          70 : OString PrintFontManager::getAfmFile( PrintFont* pFont ) const
    2291             : {
    2292          70 :     OString aMetricPath;
    2293          70 :     if( pFont )
    2294             :     {
    2295          70 :         switch( pFont->m_eType )
    2296             :         {
    2297             :             case fonttype::Type1:
    2298             :             {
    2299          70 :                 Type1FontFile* pPSFont = static_cast< Type1FontFile* >(pFont);
    2300          70 :                 aMetricPath = getDirectory( pPSFont->m_nDirectory );
    2301          70 :                 aMetricPath += "/";
    2302          70 :                 aMetricPath += pPSFont->m_aMetricFile;
    2303             :             }
    2304          70 :             break;
    2305             :             case fonttype::Builtin:
    2306             :             {
    2307           0 :                 BuiltinFont* pBuiltinFont = static_cast< BuiltinFont* >(pFont);
    2308           0 :                 aMetricPath = getDirectory( pBuiltinFont->m_nDirectory );
    2309           0 :                 aMetricPath += "/";
    2310           0 :                 aMetricPath += pBuiltinFont->m_aMetricFile;
    2311             :             }
    2312           0 :             break;
    2313           0 :             default: break;
    2314             :         }
    2315             :     }
    2316          70 :     return aMetricPath;
    2317             : }
    2318             : 
    2319             : // -------------------------------------------------------------------------
    2320             : 
    2321        2780 : OString PrintFontManager::getFontFile( PrintFont* pFont ) const
    2322             : {
    2323        2780 :     OString aPath;
    2324             : 
    2325        2780 :     if( pFont && pFont->m_eType == fonttype::Type1 )
    2326             :     {
    2327         805 :         Type1FontFile* pPSFont = static_cast< Type1FontFile* >(pFont);
    2328         805 :         ::boost::unordered_map< int, OString >::const_iterator it = m_aAtomToDir.find( pPSFont->m_nDirectory );
    2329         805 :         aPath = it->second;
    2330         805 :         aPath += "/";
    2331         805 :         aPath += pPSFont->m_aFontFile;
    2332             :     }
    2333        1975 :     else if( pFont && pFont->m_eType == fonttype::TrueType )
    2334             :     {
    2335        1975 :         TrueTypeFontFile* pTTFont = static_cast< TrueTypeFontFile* >(pFont);
    2336        1975 :         ::boost::unordered_map< int, OString >::const_iterator it = m_aAtomToDir.find( pTTFont->m_nDirectory );
    2337        1975 :         aPath = it->second;
    2338        1975 :         aPath += "/";
    2339        1975 :         aPath += pTTFont->m_aFontFile;
    2340             :     }
    2341        2780 :     return aPath;
    2342             : }
    2343             : 
    2344             : // -------------------------------------------------------------------------
    2345             : 
    2346           0 : const ::rtl::OUString& PrintFontManager::getPSName( fontID nFontID ) const
    2347             : {
    2348           0 :     PrintFont* pFont = getFont( nFontID );
    2349           0 :     if( pFont && pFont->m_nPSName == 0 )
    2350             :     {
    2351           0 :         if( pFont->m_eType == fonttype::TrueType )
    2352           0 :             analyzeTrueTypeFile( pFont );
    2353             :     }
    2354             : 
    2355           0 :     return m_pAtoms->getString( ATOM_PSNAME, pFont ? pFont->m_nPSName : INVALID_ATOM );
    2356             : }
    2357             : 
    2358             : // -------------------------------------------------------------------------
    2359             : 
    2360           0 : int PrintFontManager::getFontAscend( fontID nFontID ) const
    2361             : {
    2362           0 :     PrintFont* pFont = getFont( nFontID );
    2363           0 :     if( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
    2364             :     {
    2365             :         // might be a truetype font not yet analyzed
    2366           0 :         if( pFont->m_eType == fonttype::TrueType )
    2367           0 :             analyzeTrueTypeFile( pFont );
    2368           0 :         else if( pFont->m_eType == fonttype::Type1 || pFont->m_eType == fonttype::Builtin )
    2369           0 :             pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, true );
    2370             :     }
    2371           0 :     return pFont->m_nAscend;
    2372             : }
    2373             : 
    2374             : // -------------------------------------------------------------------------
    2375             : 
    2376           0 : int PrintFontManager::getFontDescend( fontID nFontID ) const
    2377             : {
    2378           0 :     PrintFont* pFont = getFont( nFontID );
    2379           0 :     if( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
    2380             :     {
    2381             :         // might be a truetype font not yet analyzed
    2382           0 :         if( pFont->m_eType == fonttype::TrueType )
    2383           0 :             analyzeTrueTypeFile( pFont );
    2384           0 :         else if( pFont->m_eType == fonttype::Type1 || pFont->m_eType == fonttype::Builtin )
    2385           0 :             pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, true );
    2386             :     }
    2387           0 :     return pFont->m_nDescend;
    2388             : }
    2389             : 
    2390             : // -------------------------------------------------------------------------
    2391             : 
    2392           0 : void PrintFontManager::hasVerticalSubstitutions( fontID nFontID,
    2393             :     const sal_Unicode* pCharacters, int nCharacters, bool* pHasSubst ) const
    2394             : {
    2395           0 :     PrintFont* pFont = getFont( nFontID );
    2396           0 :     if( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
    2397             :     {
    2398             :         // might be a truetype font not yet analyzed
    2399           0 :         if( pFont->m_eType == fonttype::TrueType )
    2400           0 :             analyzeTrueTypeFile( pFont );
    2401             :     }
    2402             : 
    2403           0 :     if( ! pFont->m_bHaveVerticalSubstitutedGlyphs )
    2404           0 :         memset( pHasSubst, 0, sizeof(bool)*nCharacters );
    2405             :     else
    2406             :     {
    2407           0 :         for( int i = 0; i < nCharacters; i++ )
    2408             :         {
    2409           0 :             sal_Unicode code = pCharacters[i];
    2410           0 :             if( ! pFont->m_pMetrics ||
    2411           0 :                 ! ( pFont->m_pMetrics->m_aPages[ code >> 11 ] & ( 1 << ( ( code >> 8 ) & 7 ) ) ) )
    2412           0 :                 pFont->queryMetricPage( code >> 8, m_pAtoms );
    2413           0 :             ::boost::unordered_map< sal_Unicode, bool >::const_iterator it = pFont->m_pMetrics->m_bVerticalSubstitutions.find( code );
    2414           0 :             pHasSubst[i] = it != pFont->m_pMetrics->m_bVerticalSubstitutions.end();
    2415             :         }
    2416             :     }
    2417           0 : }
    2418             : 
    2419             : // -------------------------------------------------------------------------
    2420             : 
    2421           0 : const ::std::list< KernPair >& PrintFontManager::getKernPairs( fontID nFontID, bool bVertical ) const
    2422             : {
    2423           0 :     static ::std::list< KernPair > aEmpty;
    2424             : 
    2425           0 :     PrintFont* pFont = getFont( nFontID );
    2426           0 :     if( ! pFont )
    2427           0 :         return aEmpty;
    2428             : 
    2429           0 :     if( ! pFont->m_pMetrics || ! pFont->m_pMetrics->m_bKernPairsQueried )
    2430           0 :         pFont->queryMetricPage( 0, m_pAtoms );
    2431           0 :     if( ! pFont->m_pMetrics || ! pFont->m_pMetrics->m_bKernPairsQueried )
    2432           0 :         return aEmpty;
    2433           0 :     return bVertical ? pFont->m_pMetrics->m_aYKernPairs : pFont->m_pMetrics->m_aXKernPairs;
    2434             : }
    2435             : 
    2436             : // -------------------------------------------------------------------------
    2437             : 
    2438           0 : bool PrintFontManager::isFontDownloadingAllowed( fontID nFont ) const
    2439             : {
    2440           0 :     static const char* pEnable = getenv( "PSPRINT_ENABLE_TTF_COPYRIGHTAWARENESS" );
    2441           0 :     bool bRet = true;
    2442             : 
    2443           0 :     if( pEnable && *pEnable )
    2444             :     {
    2445           0 :         PrintFont* pFont = getFont( nFont );
    2446           0 :         if( pFont && pFont->m_eType == fonttype::TrueType )
    2447             :         {
    2448           0 :             TrueTypeFontFile* pTTFontFile = static_cast<TrueTypeFontFile*>(pFont);
    2449           0 :             if( pTTFontFile->m_nTypeFlags & TYPEFLAG_INVALID )
    2450             :             {
    2451           0 :                 TrueTypeFont* pTTFont = NULL;
    2452           0 :                 rtl::OString aFile = getFontFile( pFont );
    2453           0 :                 if( OpenTTFontFile( aFile.getStr(), pTTFontFile->m_nCollectionEntry, &pTTFont ) == SF_OK )
    2454             :                 {
    2455             :                     // get type flags
    2456             :                     TTGlobalFontInfo aInfo;
    2457           0 :                     GetTTGlobalFontInfo( pTTFont, & aInfo );
    2458           0 :                     pTTFontFile->m_nTypeFlags = (unsigned int)aInfo.typeFlags;
    2459           0 :                     CloseTTFont( pTTFont );
    2460           0 :                 }
    2461             :             }
    2462             : 
    2463           0 :             unsigned int nCopyrightFlags = pTTFontFile->m_nTypeFlags & TYPEFLAG_COPYRIGHT_MASK;
    2464             : 
    2465             :             // font embedding is allowed if either
    2466             :             //   no restriction at all (bit 1 clear)
    2467             :             //   printing allowed (bit 1 set, bit 2 set )
    2468           0 :             bRet = ! ( nCopyrightFlags & 0x02 ) || ( nCopyrightFlags & 0x04 );
    2469             :         }
    2470             :     }
    2471           0 :     return bRet;
    2472             : }
    2473             : 
    2474             : // -------------------------------------------------------------------------
    2475             : 
    2476           0 : bool PrintFontManager::getMetrics( fontID nFontID, const sal_Unicode* pString, int nLen, CharacterMetric* pArray, bool bVertical ) const
    2477             : {
    2478           0 :     PrintFont* pFont = getFont( nFontID );
    2479           0 :     if( ! pFont )
    2480           0 :         return false;
    2481             : 
    2482           0 :     if( ( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
    2483           0 :         || ! pFont->m_pMetrics || pFont->m_pMetrics->isEmpty()
    2484             :         )
    2485             :     {
    2486             :         // might be a font not yet analyzed
    2487           0 :         if( pFont->m_eType == fonttype::Type1 || pFont->m_eType == fonttype::Builtin )
    2488           0 :             pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, false );
    2489           0 :         else if( pFont->m_eType == fonttype::TrueType )
    2490           0 :             analyzeTrueTypeFile( pFont );
    2491             :     }
    2492             : 
    2493           0 :     for( int i = 0; i < nLen; i++ )
    2494             :     {
    2495           0 :         if( ! pFont->m_pMetrics ||
    2496           0 :             ! ( pFont->m_pMetrics->m_aPages[ pString[i] >> 11 ] & ( 1 << ( ( pString[i] >> 8 ) & 7 ) ) ) )
    2497           0 :             pFont->queryMetricPage( pString[i] >> 8, m_pAtoms );
    2498           0 :         pArray[i].width = pArray[i].height = -1;
    2499           0 :         if( pFont->m_pMetrics )
    2500             :         {
    2501           0 :             int effectiveCode = pString[i];
    2502           0 :             effectiveCode |= bVertical ? 1 << 16 : 0;
    2503             :             ::boost::unordered_map< int, CharacterMetric >::const_iterator it =
    2504           0 :                   pFont->m_pMetrics->m_aMetrics.find( effectiveCode );
    2505             :         // if no vertical metrics are available assume rotated horizontal metrics
    2506           0 :         if( bVertical && (it == pFont->m_pMetrics->m_aMetrics.end()) )
    2507           0 :                   it = pFont->m_pMetrics->m_aMetrics.find( pString[i] );
    2508             :         // the character metrics are in it->second
    2509           0 :             if( it != pFont->m_pMetrics->m_aMetrics.end() )
    2510           0 :                 pArray[ i ] = it->second;
    2511             :         }
    2512             :     }
    2513             : 
    2514           0 :     return true;
    2515             : }
    2516             : 
    2517             : // -------------------------------------------------------------------------
    2518             : 
    2519           0 : bool PrintFontManager::getMetrics( fontID nFontID, sal_Unicode minCharacter, sal_Unicode maxCharacter, CharacterMetric* pArray, bool bVertical ) const
    2520             : {
    2521             :     OSL_PRECOND(minCharacter <= maxCharacter, "invalid char. range");
    2522           0 :     if (minCharacter > maxCharacter)
    2523           0 :         return false;
    2524             : 
    2525           0 :     PrintFont* pFont = getFont( nFontID );
    2526           0 :     if( ! pFont )
    2527           0 :         return false;
    2528             : 
    2529           0 :     if( ( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
    2530           0 :         || ! pFont->m_pMetrics || pFont->m_pMetrics->isEmpty()
    2531             :         )
    2532             :     {
    2533             :         // might be a font not yet analyzed
    2534           0 :         if( pFont->m_eType == fonttype::Type1 || pFont->m_eType == fonttype::Builtin )
    2535           0 :             pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, false );
    2536           0 :         else if( pFont->m_eType == fonttype::TrueType )
    2537           0 :             analyzeTrueTypeFile( pFont );
    2538             :     }
    2539             : 
    2540           0 :     sal_Unicode code = minCharacter;
    2541           0 :     do
    2542             :     {
    2543           0 :         if( ! pFont->m_pMetrics ||
    2544           0 :             ! ( pFont->m_pMetrics->m_aPages[ code >> 11 ] & ( 1 << ( ( code >> 8 ) & 7 ) ) ) )
    2545           0 :             pFont->queryMetricPage( code >> 8, m_pAtoms );
    2546           0 :         pArray[ code - minCharacter ].width     = -1;
    2547           0 :         pArray[ code - minCharacter ].height    = -1;
    2548           0 :         if( pFont->m_pMetrics )
    2549             :         {
    2550           0 :             int effectiveCode = code;
    2551           0 :             effectiveCode |= bVertical ? 1 << 16 : 0;
    2552             :             ::boost::unordered_map< int, CharacterMetric >::const_iterator it =
    2553           0 :                   pFont->m_pMetrics->m_aMetrics.find( effectiveCode );
    2554             :             // if no vertical metrics are available assume rotated horizontal metrics
    2555           0 :             if( bVertical && (it == pFont->m_pMetrics->m_aMetrics.end()) )
    2556           0 :                 it = pFont->m_pMetrics->m_aMetrics.find( code );
    2557             :             // the character metrics are in it->second
    2558           0 :             if( it != pFont->m_pMetrics->m_aMetrics.end() )
    2559           0 :                 pArray[ code - minCharacter ] = it->second;
    2560             :         }
    2561             :     } while( code++ != maxCharacter );
    2562             : 
    2563           0 :     return true;
    2564             : }
    2565             : 
    2566             : // -------------------------------------------------------------------------
    2567             : 
    2568             : // TODO: move most of this stuff into the central font-subsetting code
    2569           0 : bool PrintFontManager::createFontSubset(
    2570             :                                         FontSubsetInfo& rInfo,
    2571             :                                         fontID nFont,
    2572             :                                         const OUString& rOutFile,
    2573             :                                         sal_Int32* pGlyphIDs,
    2574             :                                         sal_uInt8* pNewEncoding,
    2575             :                                         sal_Int32* pWidths,
    2576             :                                         int nGlyphs,
    2577             :                                         bool bVertical
    2578             :                                         )
    2579             : {
    2580           0 :     PrintFont* pFont = getFont( nFont );
    2581           0 :     if( !pFont )
    2582           0 :         return false;
    2583             : 
    2584           0 :     switch( pFont->m_eType )
    2585             :     {
    2586           0 :         case psp::fonttype::TrueType: rInfo.m_nFontType = FontSubsetInfo::SFNT_TTF; break;
    2587           0 :         case psp::fonttype::Type1: rInfo.m_nFontType = FontSubsetInfo::ANY_TYPE1; break;
    2588             :         default:
    2589           0 :             return false;
    2590             :     }
    2591             :     // TODO: remove when Type1 subsetting gets implemented
    2592           0 :     if( pFont->m_eType != fonttype::TrueType )
    2593           0 :         return false;
    2594             : 
    2595             :     // reshuffle array of requested glyphs to make sure glyph0==notdef
    2596             :     sal_uInt8  pEnc[256];
    2597             :     sal_uInt16 pGID[256];
    2598             :     sal_uInt8  pOldIndex[256];
    2599           0 :     memset( pEnc, 0, sizeof( pEnc ) );
    2600           0 :     memset( pGID, 0, sizeof( pGID ) );
    2601           0 :     memset( pOldIndex, 0, sizeof( pOldIndex ) );
    2602           0 :     if( nGlyphs > 256 )
    2603           0 :         return false;
    2604           0 :     int nChar = 1;
    2605           0 :     for( int i = 0; i < nGlyphs; i++ )
    2606             :     {
    2607           0 :         if( pNewEncoding[i] == 0 )
    2608             :         {
    2609           0 :             pOldIndex[ 0 ] = i;
    2610             :         }
    2611             :         else
    2612             :         {
    2613             :             DBG_ASSERT( !(pGlyphIDs[i] & 0x007f0000), "overlong glyph id" );
    2614             :             DBG_ASSERT( (int)pNewEncoding[i] < nGlyphs, "encoding wrong" );
    2615             :             DBG_ASSERT( pEnc[pNewEncoding[i]] == 0 && pGID[pNewEncoding[i]] == 0, "duplicate encoded glyph" );
    2616           0 :             pEnc[ pNewEncoding[i] ] = pNewEncoding[i];
    2617           0 :             pGID[ pNewEncoding[i] ] = (sal_uInt16)pGlyphIDs[ i ];
    2618           0 :             pOldIndex[ pNewEncoding[i] ] = i;
    2619           0 :             nChar++;
    2620             :         }
    2621             :     }
    2622           0 :     nGlyphs = nChar; // either input value or increased by one
    2623             : 
    2624             :     // prepare system name for read access for subset source file
    2625             :     // TODO: since this file is usually already mmapped there is no need to open it again
    2626           0 :     const rtl::OString aFromFile = getFontFile( pFont );
    2627             : 
    2628           0 :     TrueTypeFont* pTTFont = NULL; // TODO: rename to SfntFont
    2629           0 :     TrueTypeFontFile* pTTFontFile = static_cast< TrueTypeFontFile* >(pFont);
    2630           0 :     if( OpenTTFontFile( aFromFile.getStr(), pTTFontFile->m_nCollectionEntry, &pTTFont ) != SF_OK )
    2631           0 :         return false;
    2632             : 
    2633             :     // prepare system name for write access for subset file target
    2634           0 :     OUString aSysPath;
    2635           0 :     if( osl_File_E_None != osl_getSystemPathFromFileURL( rOutFile.pData, &aSysPath.pData ) )
    2636           0 :         return false;
    2637           0 :     const rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
    2638           0 :     const rtl::OString aToFile( OUStringToOString( aSysPath, aEncoding ) );
    2639             : 
    2640             :     // do CFF subsetting if possible
    2641           0 :     int nCffLength = 0;
    2642           0 :     const sal_uInt8* pCffBytes = NULL;
    2643           0 :     if( GetSfntTable( pTTFont, O_CFF, &pCffBytes, &nCffLength ) )
    2644             :     {
    2645           0 :         rInfo.LoadFont( FontSubsetInfo::CFF_FONT, pCffBytes, nCffLength );
    2646             : #if 1 // TODO: remove 16bit->long conversion when related methods handle non-16bit glyphids
    2647             :         long aRequestedGlyphs[256];
    2648           0 :         for( int i = 0; i < nGlyphs; ++i )
    2649           0 :             aRequestedGlyphs[i] = pGID[i];
    2650             : #endif
    2651             :         // create subset file at requested path
    2652           0 :         FILE* pOutFile = fopen( aToFile.getStr(), "wb" );
    2653             :         // create font subset
    2654           0 :         const char* pGlyphSetName = NULL; // TODO: better name?
    2655             :         const bool bOK = rInfo.CreateFontSubset(
    2656             :             FontSubsetInfo::TYPE1_PFB,
    2657             :             pOutFile, pGlyphSetName,
    2658           0 :             aRequestedGlyphs, pEnc, nGlyphs, pWidths );
    2659           0 :         fclose( pOutFile );
    2660             :         // cleanup before early return
    2661           0 :         CloseTTFont( pTTFont );
    2662           0 :         return bOK;
    2663             :     }
    2664             : 
    2665             :     // do TTF->Type42 or Type3 subsetting
    2666             :     // fill in font info
    2667           0 :     psp::PrintFontInfo aFontInfo;
    2668           0 :     if( ! getFontInfo( nFont, aFontInfo ) )
    2669           0 :         return false;
    2670             : 
    2671           0 :     rInfo.m_nAscent     = aFontInfo.m_nAscend;
    2672           0 :     rInfo.m_nDescent    = aFontInfo.m_nDescend;
    2673           0 :     rInfo.m_aPSName     = getPSName( nFont );
    2674             : 
    2675             :     int xMin, yMin, xMax, yMax;
    2676           0 :     getFontBoundingBox( nFont, xMin, yMin, xMax, yMax );
    2677           0 :     rInfo.m_aFontBBox   = Rectangle( Point( xMin, yMin ), Size( xMax-xMin, yMax-yMin ) );
    2678           0 :     rInfo.m_nCapHeight  = yMax; // Well ...
    2679             : 
    2680             :     // fill in glyph advance widths
    2681             :     TTSimpleGlyphMetrics* pMetrics = GetTTSimpleGlyphMetrics( pTTFont,
    2682             :                                                               pGID,
    2683             :                                                               nGlyphs,
    2684           0 :                                                               bVertical ? 1 : 0 );
    2685           0 :     if( pMetrics )
    2686             :     {
    2687           0 :         for( int i = 0; i < nGlyphs; i++ )
    2688           0 :             pWidths[pOldIndex[i]] = pMetrics[i].adv;
    2689           0 :         free( pMetrics );
    2690             :     }
    2691             :     else
    2692             :     {
    2693           0 :         CloseTTFont( pTTFont );
    2694           0 :         return false;
    2695             :     }
    2696             : 
    2697             :     bool bSuccess = ( SF_OK == CreateTTFromTTGlyphs( pTTFont,
    2698             :                                                      aToFile.getStr(),
    2699             :                                                      pGID,
    2700             :                                                      pEnc,
    2701             :                                                      nGlyphs,
    2702             :                                                      0,
    2703             :                                                      NULL,
    2704           0 :                                                      0 ) );
    2705           0 :     CloseTTFont( pTTFont );
    2706             : 
    2707           0 :     return bSuccess;
    2708             : }
    2709             : 
    2710           0 : void PrintFontManager::getGlyphWidths( fontID nFont,
    2711             :                                        bool bVertical,
    2712             :                                        std::vector< sal_Int32 >& rWidths,
    2713             :                                        std::map< sal_Unicode, sal_uInt32 >& rUnicodeEnc )
    2714             : {
    2715           0 :     PrintFont* pFont = getFont( nFont );
    2716           0 :     if( !pFont ||
    2717             :         (pFont->m_eType != fonttype::TrueType && pFont->m_eType != fonttype::Type1) )
    2718           0 :         return;
    2719           0 :     if( pFont->m_eType == fonttype::TrueType )
    2720             :     {
    2721           0 :         TrueTypeFont* pTTFont = NULL;
    2722           0 :         TrueTypeFontFile* pTTFontFile = static_cast< TrueTypeFontFile* >(pFont);
    2723           0 :         rtl::OString aFromFile = getFontFile( pFont );
    2724           0 :         if( OpenTTFontFile( aFromFile.getStr(), pTTFontFile->m_nCollectionEntry, &pTTFont ) != SF_OK )
    2725             :             return;
    2726           0 :         int nGlyphs = GetTTGlyphCount( pTTFont );
    2727           0 :         if( nGlyphs > 0 )
    2728             :         {
    2729           0 :             rWidths.resize(nGlyphs);
    2730           0 :             std::vector<sal_uInt16> aGlyphIds(nGlyphs);
    2731           0 :             for( int i = 0; i < nGlyphs; i++ )
    2732           0 :                 aGlyphIds[i] = sal_uInt16(i);
    2733             :             TTSimpleGlyphMetrics* pMetrics = GetTTSimpleGlyphMetrics( pTTFont,
    2734           0 :                                                                       &aGlyphIds[0],
    2735             :                                                                       nGlyphs,
    2736           0 :                                                                       bVertical ? 1 : 0 );
    2737           0 :             if( pMetrics )
    2738             :             {
    2739           0 :                 for( int i = 0; i< nGlyphs; i++ )
    2740           0 :                     rWidths[i] = pMetrics[i].adv;
    2741           0 :                 free( pMetrics );
    2742           0 :                 rUnicodeEnc.clear();
    2743             :             }
    2744             : 
    2745             :             // fill the unicode map
    2746             :             // TODO: isn't this map already available elsewhere in the fontmanager?
    2747           0 :             const sal_uInt8* pCmapData = NULL;
    2748           0 :             int nCmapSize = 0;
    2749           0 :             if( GetSfntTable( pTTFont, O_cmap, &pCmapData, &nCmapSize ) )
    2750             :             {
    2751           0 :                 CmapResult aCmapResult;
    2752           0 :                 if( ParseCMAP( pCmapData, nCmapSize, aCmapResult ) )
    2753             :                 {
    2754           0 :                     const ImplFontCharMap aCharMap( aCmapResult );
    2755           0 :                     for( sal_uInt32 cOld = 0;;)
    2756             :                     {
    2757             :                         // get next unicode covered by font
    2758           0 :                         const sal_uInt32 c = aCharMap.GetNextChar( cOld );
    2759           0 :                         if( c == cOld )
    2760           0 :                             break;
    2761           0 :                         cOld = c;
    2762             : #if 1 // TODO: remove when sal_Unicode covers all of unicode
    2763           0 :                         if( c > (sal_Unicode)~0 )
    2764           0 :                             break;
    2765             : #endif
    2766             :                         // get the matching glyph index
    2767           0 :                         const sal_uInt32 nGlyphId = aCharMap.GetGlyphIndex( c );
    2768             :                         // update the requested map
    2769           0 :                         rUnicodeEnc[ (sal_Unicode)c ] = nGlyphId;
    2770           0 :                     }
    2771             :                 }
    2772           0 :             }
    2773             :         }
    2774           0 :         CloseTTFont( pTTFont );
    2775             :     }
    2776           0 :     else if( pFont->m_eType == fonttype::Type1 )
    2777             :     {
    2778           0 :         if( ! pFont->m_aEncodingVector.size() )
    2779           0 :             pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, true, true );
    2780           0 :         if( pFont->m_pMetrics )
    2781             :         {
    2782           0 :             rUnicodeEnc.clear();
    2783           0 :             rWidths.clear();
    2784           0 :             rWidths.reserve( pFont->m_pMetrics->m_aMetrics.size() );
    2785           0 :             for( boost::unordered_map< int, CharacterMetric >::const_iterator it =
    2786           0 :                  pFont->m_pMetrics->m_aMetrics.begin();
    2787           0 :                  it != pFont->m_pMetrics->m_aMetrics.end(); ++it )
    2788             :             {
    2789           0 :                 if( (it->first & 0x00010000) == 0 || bVertical )
    2790             :                 {
    2791           0 :                     rUnicodeEnc[ sal_Unicode(it->first & 0x0000ffff) ] = sal_uInt32(rWidths.size());
    2792           0 :                     rWidths.push_back( it->second.width );
    2793             :                 }
    2794             :             }
    2795             :         }
    2796             :     }
    2797             : }
    2798             : 
    2799             : // -------------------------------------------------------------------------
    2800             : 
    2801           0 : const std::map< sal_Unicode, sal_Int32 >* PrintFontManager::getEncodingMap( fontID nFont, const std::map< sal_Unicode, rtl::OString >** pNonEncoded ) const
    2802             : {
    2803           0 :     PrintFont* pFont = getFont( nFont );
    2804           0 :     if( !pFont ||
    2805             :         (pFont->m_eType != fonttype::Type1 && pFont->m_eType != fonttype::Builtin)
    2806             :         )
    2807           0 :         return NULL;
    2808             : 
    2809           0 :     if( ! pFont->m_aEncodingVector.size() )
    2810           0 :         pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, true, true );
    2811             : 
    2812           0 :     if( pNonEncoded )
    2813           0 :         *pNonEncoded = pFont->m_aNonEncoded.size() ? &pFont->m_aNonEncoded : NULL;
    2814             : 
    2815           0 :     return pFont->m_aEncodingVector.size() ? &pFont->m_aEncodingVector : NULL;
    2816             : }
    2817             : 
    2818             : // -------------------------------------------------------------------------
    2819             : 
    2820           0 : std::list< OString > PrintFontManager::getAdobeNameFromUnicode( sal_Unicode aChar ) const
    2821             : {
    2822             :     std::pair< boost::unordered_multimap< sal_Unicode, rtl::OString >::const_iterator,
    2823             :         boost::unordered_multimap< sal_Unicode, rtl::OString >::const_iterator > range
    2824           0 :         =  m_aUnicodeToAdobename.equal_range( aChar );
    2825             : 
    2826           0 :     std::list< OString > aRet;
    2827           0 :     for( ; range.first != range.second; ++range.first )
    2828           0 :         aRet.push_back( range.first->second );
    2829             : 
    2830           0 :     if( aRet.begin() == aRet.end() && aChar != 0 )
    2831             :     {
    2832             :         sal_Char aBuf[8];
    2833           0 :         sal_Int32 nChars = snprintf( (char*)aBuf, sizeof( aBuf ), "uni%.4hX", aChar );
    2834           0 :         aRet.push_back( OString( aBuf, nChars ) );
    2835             :     }
    2836             : 
    2837           0 :     return aRet;
    2838             : }
    2839             : 
    2840             : // -------------------------------------------------------------------------
    2841           0 : std::list< sal_Unicode >  PrintFontManager::getUnicodeFromAdobeName( const rtl::OString& rName ) const
    2842             : {
    2843             :     std::pair< boost::unordered_multimap< rtl::OString, sal_Unicode, rtl::OStringHash >::const_iterator,
    2844             :         boost::unordered_multimap< rtl::OString, sal_Unicode, rtl::OStringHash >::const_iterator > range
    2845           0 :         =  m_aAdobenameToUnicode.equal_range( rName );
    2846             : 
    2847           0 :     std::list< sal_Unicode > aRet;
    2848           0 :     for( ; range.first != range.second; ++range.first )
    2849           0 :         aRet.push_back( range.first->second );
    2850             : 
    2851           0 :     if( aRet.begin() == aRet.end() )
    2852             :     {
    2853           0 :         if( rName.getLength() == 7 && rName.indexOf( "uni" ) == 0 )
    2854             :         {
    2855           0 :             sal_Unicode aCode = (sal_Unicode)rName.copy( 3 ).toInt32( 16 );
    2856           0 :             aRet.push_back( aCode );
    2857             :         }
    2858             :     }
    2859             : 
    2860           0 :     return aRet;
    2861             : }
    2862             : 
    2863             : // -------------------------------------------------------------------------
    2864             : namespace
    2865             : {
    2866           0 :     OUString getString( const Any& rAny )
    2867             :     {
    2868           0 :         OUString aStr;
    2869           0 :         rAny >>= aStr;
    2870           0 :         return aStr;
    2871             :     }
    2872           0 :     bool getBool( const Any& rAny )
    2873             :     {
    2874           0 :         sal_Bool bBool = sal_False;
    2875           0 :         rAny >>= bBool;
    2876           0 :         return static_cast<bool>(bBool);
    2877             :     }
    2878           0 :     sal_Int32 getInt( const Any& rAny )
    2879             :     {
    2880           0 :         sal_Int32 n = 0;
    2881           0 :         rAny >>= n;
    2882           0 :         return n;
    2883             :     }
    2884             : }
    2885           0 : bool PrintFontManager::readOverrideMetrics()
    2886             : {
    2887           0 :     if( ! m_aOverrideFonts.empty() )
    2888           0 :         return false;
    2889             : 
    2890           0 :     css::uno::Reference< XMultiServiceFactory > xFact( comphelper::getProcessServiceFactory() );
    2891           0 :     if( !xFact.is() )
    2892           0 :         return false;
    2893             :     css::uno::Reference< XMaterialHolder > xMat(
    2894           0 :                 xFact->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.psprint.CompatMetricOverride" ) ) ),
    2895           0 :                 UNO_QUERY );
    2896           0 :     if( !xMat.is() )
    2897           0 :         return false;
    2898             : 
    2899           0 :     Any aAny( xMat->getMaterial() );
    2900           0 :     Sequence< Any > aOverrideFonts;
    2901           0 :     if( ! (aAny >>= aOverrideFonts ) )
    2902           0 :         return false;
    2903           0 :     sal_Int32 nFonts = aOverrideFonts.getLength();
    2904           0 :     for( sal_Int32 i = 0; i < nFonts; i++ )
    2905             :     {
    2906           0 :         Sequence< NamedValue > aMetrics;
    2907           0 :         if( ! (aOverrideFonts.getConstArray()[i] >>= aMetrics) )
    2908           0 :             continue;
    2909           0 :         BuiltinFont* pFont = new BuiltinFont();
    2910           0 :         pFont->m_nDirectory = 0;
    2911           0 :         pFont->m_bUserOverride = false;
    2912           0 :         pFont->m_pMetrics = new PrintFontMetrics;
    2913           0 :         memset( pFont->m_pMetrics->m_aPages, 0xff, sizeof( pFont->m_pMetrics->m_aPages ) );
    2914           0 :         pFont->m_pMetrics->m_bKernPairsQueried = true;
    2915           0 :         sal_Int32 nProps = aMetrics.getLength();
    2916           0 :         const NamedValue* pProps = aMetrics.getConstArray();
    2917           0 :         for( sal_Int32 n = 0; n < nProps; n++ )
    2918             :         {
    2919           0 :             if ( pProps[n].Name == "FamilyName" )
    2920             :                 pFont->m_nFamilyName = m_pAtoms->getAtom( ATOM_FAMILYNAME,
    2921           0 :                                                           getString(pProps[n].Value),
    2922           0 :                                                           sal_True );
    2923           0 :             else if ( pProps[n].Name == "PSName" )
    2924             :                 pFont->m_nPSName = m_pAtoms->getAtom( ATOM_PSNAME,
    2925           0 :                                                       getString(pProps[n].Value),
    2926           0 :                                                       sal_True );
    2927           0 :             else if ( pProps[n].Name == "StyleName" )
    2928           0 :                 pFont->m_aStyleName = getString(pProps[n].Value);
    2929           0 :             else if ( pProps[n].Name == "Italic" )
    2930           0 :                 pFont->m_eItalic = static_cast<FontItalic>(getInt(pProps[n].Value));
    2931           0 :             else if ( pProps[n].Name == "Width" )
    2932           0 :                 pFont->m_eWidth = static_cast<FontWidth>(getInt(pProps[n].Value));
    2933           0 :             else if ( pProps[n].Name == "Weight" )
    2934           0 :                 pFont->m_eWeight = static_cast<FontWeight>(getInt(pProps[n].Value));
    2935           0 :             else if ( pProps[n].Name == "Pitch" )
    2936           0 :                 pFont->m_ePitch = static_cast<FontPitch>(getInt(pProps[n].Value));
    2937           0 :             else if ( pProps[n].Name == "Encoding" )
    2938           0 :                 pFont->m_aEncoding = static_cast<rtl_TextEncoding>(getInt(pProps[n].Value));
    2939           0 :             else if ( pProps[n].Name == "FontEncodingOnly" )
    2940           0 :                 pFont->m_bFontEncodingOnly = getBool(pProps[n].Value);
    2941           0 :             else if ( pProps[n].Name == "GlobalMetricXWidth" )
    2942           0 :                 pFont->m_aGlobalMetricX.width = getInt(pProps[n].Value);
    2943           0 :             else if ( pProps[n].Name == "GlobalMetricXHeight" )
    2944           0 :                 pFont->m_aGlobalMetricX.height = getInt(pProps[n].Value);
    2945           0 :             else if ( pProps[n].Name == "GlobalMetricYWidth" )
    2946           0 :                 pFont->m_aGlobalMetricY.width = getInt(pProps[n].Value);
    2947           0 :             else if ( pProps[n].Name == "GlobalMetricYHeight" )
    2948           0 :                 pFont->m_aGlobalMetricY.height = getInt(pProps[n].Value);
    2949           0 :             else if ( pProps[n].Name == "Ascend" )
    2950           0 :                 pFont->m_nAscend = getInt(pProps[n].Value);
    2951           0 :             else if ( pProps[n].Name == "Descend" )
    2952           0 :                 pFont->m_nDescend = getInt(pProps[n].Value);
    2953           0 :             else if ( pProps[n].Name == "Leading" )
    2954           0 :                 pFont->m_nLeading = getInt(pProps[n].Value);
    2955           0 :             else if ( pProps[n].Name == "XMin" )
    2956           0 :                 pFont->m_nXMin = getInt(pProps[n].Value);
    2957           0 :             else if ( pProps[n].Name == "YMin" )
    2958           0 :                 pFont->m_nYMin = getInt(pProps[n].Value);
    2959           0 :             else if ( pProps[n].Name == "XMax" )
    2960           0 :                 pFont->m_nXMax = getInt(pProps[n].Value);
    2961           0 :             else if ( pProps[n].Name == "YMax" )
    2962           0 :                 pFont->m_nYMax = getInt(pProps[n].Value);
    2963           0 :             else if ( pProps[n].Name == "VerticalSubstitutes" )
    2964           0 :                 pFont->m_bHaveVerticalSubstitutedGlyphs = getBool(pProps[n].Value);
    2965           0 :             else if ( pProps[n].Name == "EncodingVector" )
    2966             :             {
    2967           0 :                 Sequence< NamedValue > aEncoding;
    2968           0 :                 pProps[n].Value >>= aEncoding;
    2969           0 :                 sal_Int32 nEnc = aEncoding.getLength();
    2970           0 :                 const NamedValue* pEnc = aEncoding.getConstArray();
    2971           0 :                 for( sal_Int32 m = 0; m < nEnc; m++ )
    2972             :                 {
    2973           0 :                     sal_Unicode cCode = *pEnc[m].Name.getStr();
    2974           0 :                     sal_Int32 nGlyph = getInt(pEnc[m].Value);
    2975           0 :                     pFont->m_aEncodingVector[ cCode ] = nGlyph;
    2976           0 :                 }
    2977             :             }
    2978           0 :             else if ( pProps[n].Name == "NonEncoded" )
    2979             :             {
    2980           0 :                 Sequence< NamedValue > aEncoding;
    2981           0 :                 pProps[n].Value >>= aEncoding;
    2982           0 :                 sal_Int32 nEnc = aEncoding.getLength();
    2983           0 :                 const NamedValue* pEnc = aEncoding.getConstArray();
    2984           0 :                 for( sal_Int32 m = 0; m < nEnc; m++ )
    2985             :                 {
    2986           0 :                     sal_Unicode cCode = *pEnc[m].Name.getStr();
    2987           0 :                     OUString aGlyphName( getString(pEnc[m].Value) );
    2988           0 :                     pFont->m_aNonEncoded[ cCode ] = OUStringToOString(aGlyphName,RTL_TEXTENCODING_ASCII_US);
    2989           0 :                 }
    2990             :             }
    2991           0 :             else if ( pProps[n].Name == "CharacterMetrics" )
    2992             :             {
    2993             :                 // fill pFont->m_pMetrics->m_aMetrics
    2994             :                 // expect triples of int: int -> CharacterMetric.{ width, height }
    2995           0 :                 Sequence< sal_Int32 > aSeq;
    2996           0 :                 pProps[n].Value >>= aSeq;
    2997           0 :                 sal_Int32 nInts = aSeq.getLength();
    2998           0 :                 const sal_Int32* pInts = aSeq.getConstArray();
    2999           0 :                 for( sal_Int32 m = 0; m < nInts; m+=3 )
    3000             :                 {
    3001           0 :                     pFont->m_pMetrics->m_aMetrics[ pInts[m] ].width = static_cast<short int>(pInts[m+1]);
    3002           0 :                     pFont->m_pMetrics->m_aMetrics[ pInts[m] ].height = static_cast<short int>(pInts[m+2]);
    3003           0 :                 }
    3004             :             }
    3005           0 :             else if ( pProps[n].Name == "XKernPairs" )
    3006             :             {
    3007             :                 // fill pFont->m_pMetrics->m_aXKernPairs
    3008             :                 // expection name: <unicode1><unicode2> value: ((height << 16)| width)
    3009           0 :                 Sequence< NamedValue > aKern;
    3010           0 :                 pProps[n].Value >>= aKern;
    3011           0 :                 KernPair aPair;
    3012           0 :                 const NamedValue* pVals = aKern.getConstArray();
    3013           0 :                 int nPairs = aKern.getLength();
    3014           0 :                 for( int m = 0; m < nPairs; m++ )
    3015             :                 {
    3016           0 :                     if( pVals[m].Name.getLength() == 2 )
    3017             :                     {
    3018           0 :                         aPair.first = pVals[m].Name.getStr()[0];
    3019           0 :                         aPair.second = pVals[m].Name.getStr()[1];
    3020           0 :                         sal_Int32 nKern = getInt( pVals[m].Value );
    3021           0 :                         aPair.kern_x = static_cast<short int>(nKern & 0xffff);
    3022           0 :                         aPair.kern_y = static_cast<short int>((sal_uInt32(nKern) >> 16) & 0xffff);
    3023           0 :                         pFont->m_pMetrics->m_aXKernPairs.push_back( aPair );
    3024             :                     }
    3025           0 :                 }
    3026             :             }
    3027             :         }
    3028             :         // sanity check
    3029           0 :         if( pFont->m_nPSName                        &&
    3030             :             pFont->m_nFamilyName                    &&
    3031           0 :             ! pFont->m_pMetrics->m_aMetrics.empty() )
    3032             :         {
    3033           0 :             m_aOverrideFonts.push_back( m_nNextFontID );
    3034           0 :             m_aFonts[ m_nNextFontID++ ] = pFont;
    3035             :         }
    3036             :         else
    3037             :         {
    3038             :             DBG_ASSERT( 0, "override font failed" );
    3039           0 :             delete pFont;
    3040             :         }
    3041           0 :     }
    3042             : 
    3043           0 :     return true;
    3044             : }
    3045             : 
    3046             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10