LCOV - code coverage report
Current view: top level - vcl/generic/fontmanager - fontmanager.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 536 1115 48.1 %
Date: 2014-11-03 Functions: 36 53 67.9 %
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             : #include <unistd.h>
      21             : #include <sys/stat.h>
      22             : #include <dirent.h>
      23             : #include <stdlib.h>
      24             : #include <osl/thread.h>
      25             : 
      26             : #include "unotools/atom.hxx"
      27             : 
      28             : #include "fontcache.hxx"
      29             : #include "fontsubset.hxx"
      30             : #include "impfont.hxx"
      31             : #include "svdata.hxx"
      32             : #include "generic/geninst.h"
      33             : #include "fontmanager.hxx"
      34             : #include "vcl/strhelper.hxx"
      35             : #include "vcl/ppdparser.hxx"
      36             : #include <vcl/embeddedfontshelper.hxx>
      37             : 
      38             : #include "tools/urlobj.hxx"
      39             : #include "tools/stream.hxx"
      40             : #include "tools/debug.hxx"
      41             : 
      42             : #include "osl/file.hxx"
      43             : #include "osl/process.h"
      44             : 
      45             : #include "rtl/tencinfo.h"
      46             : #include "rtl/ustrbuf.hxx"
      47             : #include "rtl/strbuf.hxx"
      48             : 
      49             : #include <sal/macros.h>
      50             : 
      51             : #include "i18nlangtag/applelangid.hxx"
      52             : #include "i18nlangtag/mslangid.hxx"
      53             : 
      54             : #include "parseAFM.hxx"
      55             : #include "sft.hxx"
      56             : 
      57             : #if OSL_DEBUG_LEVEL > 1
      58             : #include <sys/times.h>
      59             : #include <stdio.h>
      60             : #endif
      61             : 
      62             : #include "sal/alloca.h"
      63             : 
      64             : #include <set>
      65             : #include <boost/unordered_set.hpp>
      66             : #include <algorithm>
      67             : 
      68             : #include "adobeenc.tab"
      69             : 
      70             : #ifdef CALLGRIND_COMPILE
      71             : #include <valgrind/callgrind.h>
      72             : #endif
      73             : 
      74             : #include <comphelper/processfactory.hxx>
      75             : #include <comphelper/string.hxx>
      76             : #include "com/sun/star/beans/XMaterialHolder.hpp"
      77             : #include "com/sun/star/beans/NamedValue.hpp"
      78             : 
      79             : using namespace vcl;
      80             : using namespace utl;
      81             : using namespace psp;
      82             : using namespace osl;
      83             : using namespace com::sun::star::uno;
      84             : using namespace com::sun::star::beans;
      85             : using namespace com::sun::star::lang;
      86             : 
      87             : using ::comphelper::string::getToken;
      88             : 
      89             : /*
      90             :  *  static helpers
      91             :  */
      92             : 
      93      116211 : inline sal_uInt16 getUInt16BE( const sal_uInt8*& pBuffer )
      94             : {
      95      116211 :     sal_uInt16 nRet = (sal_uInt16)pBuffer[1] |
      96      116211 :         (((sal_uInt16)pBuffer[0]) << 8);
      97      116211 :     pBuffer+=2;
      98      116211 :     return nRet;
      99             : }
     100             : 
     101        3386 : static FontWeight parseWeight( const OString& rWeight )
     102             : {
     103        3386 :     FontWeight eWeight = WEIGHT_DONTKNOW;
     104        3386 :     if (rWeight.indexOf("bold") != -1)
     105             :     {
     106        1440 :         if (rWeight.indexOf("emi") != -1) // semi, demi
     107           0 :             eWeight = WEIGHT_SEMIBOLD;
     108        1440 :         else if (rWeight.indexOf("ultra") != -1)
     109           0 :             eWeight = WEIGHT_ULTRABOLD;
     110             :         else
     111        1440 :             eWeight = WEIGHT_BOLD;
     112             :     }
     113        1946 :     else if (rWeight.indexOf("heavy") != -1)
     114           0 :         eWeight = WEIGHT_BOLD;
     115        1946 :     else if (rWeight.indexOf("light") != -1)
     116             :     {
     117           0 :         if (rWeight.indexOf("emi") != -1) // semi, demi
     118           0 :             eWeight = WEIGHT_SEMILIGHT;
     119           0 :         else if (rWeight.indexOf("ultra") != -1)
     120           0 :             eWeight = WEIGHT_ULTRALIGHT;
     121             :         else
     122           0 :             eWeight = WEIGHT_LIGHT;
     123             :     }
     124        1946 :     else if (rWeight.indexOf("black") != -1)
     125           0 :         eWeight = WEIGHT_BLACK;
     126        1946 :     else if (rWeight == "demi")
     127         144 :         eWeight = WEIGHT_SEMIBOLD;
     128        3460 :     else if ((rWeight == "book") ||
     129        1658 :              (rWeight == "semicondensed"))
     130         144 :         eWeight = WEIGHT_LIGHT;
     131        1658 :     else if ((rWeight == "medium") || (rWeight == "roman"))
     132         216 :         eWeight = WEIGHT_MEDIUM;
     133             :     else
     134        1442 :         eWeight = WEIGHT_NORMAL;
     135        3386 :     return eWeight;
     136             : }
     137             : 
     138             : /*
     139             :  *  PrintFont implementations
     140             :  */
     141       93024 : PrintFontManager::PrintFont::PrintFont( fonttype::type eType ) :
     142             :         m_eType( eType ),
     143             :         m_nFamilyName( 0 ),
     144             :         m_nPSName( 0 ),
     145             :         m_eItalic( ITALIC_DONTKNOW ),
     146             :         m_eWidth( WIDTH_DONTKNOW ),
     147             :         m_eWeight( WEIGHT_DONTKNOW ),
     148             :         m_ePitch( PITCH_DONTKNOW ),
     149             :         m_aEncoding( RTL_TEXTENCODING_DONTKNOW ),
     150             :         m_bFontEncodingOnly( false ),
     151             :         m_pMetrics( NULL ),
     152             :         m_nAscend( 0 ),
     153             :         m_nDescend( 0 ),
     154             :         m_nLeading( 0 ),
     155             :         m_nXMin( 0 ),
     156             :         m_nYMin( 0 ),
     157             :         m_nXMax( 0 ),
     158             :         m_nYMax( 0 ),
     159             :         m_bHaveVerticalSubstitutedGlyphs( false ),
     160       93024 :         m_bUserOverride( false )
     161             : {
     162       93024 : }
     163             : 
     164      186048 : PrintFontManager::PrintFont::~PrintFont()
     165             : {
     166       93024 :     delete m_pMetrics;
     167       93024 : }
     168             : 
     169       57528 : PrintFontManager::Type1FontFile::~Type1FontFile()
     170             : {
     171       57528 : }
     172             : 
     173       64260 : PrintFontManager::TrueTypeFontFile::TrueTypeFontFile()
     174             : :   PrintFont( fonttype::TrueType )
     175             : ,   m_nDirectory( 0 )
     176             : ,   m_nCollectionEntry( 0 )
     177       64260 : ,   m_nTypeFlags( TYPEFLAG_INVALID )
     178       64260 : {}
     179             : 
     180      128520 : PrintFontManager::TrueTypeFontFile::~TrueTypeFontFile()
     181             : {
     182      128520 : }
     183             : 
     184           0 : bool PrintFontManager::Type1FontFile::queryMetricPage( int /*nPage*/, MultiAtomProvider* pProvider )
     185             : {
     186           0 :     return readAfmMetrics( pProvider, false, false );
     187             : }
     188             : 
     189           0 : bool PrintFontManager::TrueTypeFontFile::queryMetricPage( int nPage, MultiAtomProvider* /*pProvider*/ )
     190             : {
     191           0 :     bool bSuccess = false;
     192             : 
     193           0 :     OString aFile( PrintFontManager::get().getFontFile( this ) );
     194             : 
     195           0 :     TrueTypeFont* pTTFont = NULL;
     196             : 
     197           0 :     if( OpenTTFontFile( aFile.getStr(), m_nCollectionEntry, &pTTFont ) == SF_OK )
     198             :     {
     199           0 :         if( ! m_pMetrics )
     200             :         {
     201           0 :             m_pMetrics = new PrintFontMetrics;
     202           0 :             memset (m_pMetrics->m_aPages, 0, sizeof(m_pMetrics->m_aPages));
     203             :         }
     204           0 :         m_pMetrics->m_aPages[ nPage/8 ] |= (1 << ( nPage & 7 ));
     205             :         int i;
     206             :         sal_uInt16 table[256], table_vert[256];
     207             : 
     208           0 :         for( i = 0; i < 256; i++ )
     209           0 :             table[ i ] = 256*nPage + i;
     210             : 
     211           0 :         int nCharacters = nPage < 255 ? 256 : 254;
     212           0 :         MapString( pTTFont, table, nCharacters, NULL, false );
     213           0 :         TTSimpleGlyphMetrics* pMetrics = GetTTSimpleCharMetrics( pTTFont, nPage*256, nCharacters, false );
     214           0 :         if( pMetrics )
     215             :         {
     216           0 :             for( i = 0; i < nCharacters; i++ )
     217             :             {
     218           0 :                 if( table[i] )
     219             :                 {
     220           0 :                     CharacterMetric& rChar = m_pMetrics->m_aMetrics[ nPage*256 + i ];
     221           0 :                     rChar.width = pMetrics[ i ].adv;
     222           0 :                     rChar.height = m_aGlobalMetricX.height;
     223             :                 }
     224             :             }
     225             : 
     226           0 :             free( pMetrics );
     227             :         }
     228             : 
     229           0 :         for( i = 0; i < 256; i++ )
     230           0 :             table_vert[ i ] = 256*nPage + i;
     231           0 :         MapString( pTTFont, table_vert, nCharacters, NULL, true );
     232           0 :         pMetrics = GetTTSimpleCharMetrics( pTTFont, nPage*256, nCharacters, true );
     233           0 :         if( pMetrics )
     234             :         {
     235           0 :             for( i = 0; i < nCharacters; i++ )
     236             :             {
     237           0 :                 if( table_vert[i] )
     238             :                 {
     239           0 :                     CharacterMetric& rChar = m_pMetrics->m_aMetrics[ nPage*256 + i + ( 1 << 16 ) ];
     240           0 :                     rChar.width = m_aGlobalMetricY.width;
     241           0 :                     rChar.height = pMetrics[ i ].adv;
     242           0 :                     if( table_vert[i] != table[i] )
     243           0 :                         m_pMetrics->m_bVerticalSubstitutions[ nPage*256 + i ] = true;
     244             :                 }
     245             :             }
     246           0 :             free( pMetrics );
     247             :         }
     248           0 :         CloseTTFont( pTTFont );
     249           0 :         bSuccess = true;
     250             :     }
     251           0 :     return bSuccess;
     252             : }
     253             : 
     254             : /* #i73387# There seem to be fonts with a rather unwell chosen family name
     255             : *  consider e.g. "Helvetica Narrow" which defines its family as "Helvetica"
     256             : *  It can really only be distinguished by its PSName and FullName. Both of
     257             : *  which are not user presentable in OOo. So replace it by something sensible.
     258             : *
     259             : *  If other fonts feature this behaviour, insert them to the map.
     260             : */
     261        3384 : static bool familyNameOverride( const OUString& i_rPSname, OUString& o_rFamilyName )
     262             : {
     263        3384 :     static boost::unordered_map< OUString, OUString, OUStringHash > aPSNameToFamily( 16 );
     264        3384 :     if( aPSNameToFamily.empty() ) // initialization
     265             :     {
     266          72 :         aPSNameToFamily[ "Helvetica-Narrow" ] = "Helvetica Narrow";
     267          72 :         aPSNameToFamily[ "Helvetica-Narrow-Bold" ] = "Helvetica Narrow";
     268          72 :         aPSNameToFamily[ "Helvetica-Narrow-BoldOblique" ] = "Helvetica Narrow";
     269          72 :         aPSNameToFamily[ "Helvetica-Narrow-Oblique" ] = "Helvetica Narrow";
     270             :     }
     271             :     boost::unordered_map<OUString,OUString,OUStringHash>::const_iterator it =
     272        3384 :        aPSNameToFamily.find( i_rPSname );
     273        3384 :     bool bReplaced = (it != aPSNameToFamily.end() );
     274        3384 :     if( bReplaced )
     275           0 :         o_rFamilyName = it->second;
     276        3384 :     return bReplaced;
     277             : };
     278             : 
     279        3386 : bool PrintFontManager::PrintFont::readAfmMetrics( MultiAtomProvider* pProvider, bool bFillEncodingvector, bool bOnlyGlobalAttributes )
     280             : {
     281        3386 :     PrintFontManager& rManager( PrintFontManager::get() );
     282        3386 :     const OString& rFileName = rManager.getAfmFile( this );
     283             : 
     284        3386 :     FontInfo* pInfo = NULL;
     285        3386 :     parseFile( rFileName.getStr(), &pInfo, P_ALL );
     286        3386 :     if( ! pInfo || ! pInfo->numOfChars )
     287             :     {
     288           0 :         if( pInfo )
     289           0 :             freeFontInfo( pInfo );
     290           0 :         return false;
     291             :     }
     292             : 
     293        3386 :     m_aEncodingVector.clear();
     294             :     // fill in global info
     295             : 
     296             :     // PSName
     297        6772 :     OUString aPSName( OStringToOUString( pInfo->gfi->fontName, RTL_TEXTENCODING_ISO_8859_1 ) );
     298        3386 :     m_nPSName = pProvider->getAtom( ATOM_PSNAME, aPSName, true );
     299             : 
     300             :     // family name (if not already set)
     301        6772 :     OUString aFamily;
     302        3386 :     if( ! m_nFamilyName )
     303             :     {
     304        3384 :         aFamily = OStringToOUString( pInfo->gfi->familyName, RTL_TEXTENCODING_ISO_8859_1 );
     305        3384 :         if( aFamily.isEmpty() )
     306             :         {
     307           0 :             aFamily = OStringToOUString( pInfo->gfi->fontName, RTL_TEXTENCODING_ISO_8859_1 );
     308           0 :             sal_Int32 nIndex  = 0;
     309           0 :             aFamily = aFamily.getToken( 0, '-', nIndex );
     310             :         }
     311        3384 :         familyNameOverride( aPSName, aFamily );
     312        3384 :         m_nFamilyName = pProvider->getAtom( ATOM_FAMILYNAME, aFamily, true );
     313             :     }
     314             :     else
     315           2 :         aFamily = pProvider->getString( ATOM_FAMILYNAME, m_nFamilyName );
     316             : 
     317             :     // style name: if fullname begins with family name
     318             :     // interpret the rest of fullname as style
     319        3386 :     if( m_aStyleName.isEmpty() && pInfo->gfi->fullName && *pInfo->gfi->fullName )
     320             :     {
     321        3384 :         OUString aFullName( OStringToOUString( pInfo->gfi->fullName, RTL_TEXTENCODING_ISO_8859_1 ) );
     322        3384 :         if( aFullName.startsWith( aFamily ) )
     323        3384 :             m_aStyleName = WhitespaceToSpace( aFullName.copy( aFamily.getLength() ) );
     324             :     }
     325             : 
     326             :     // italic
     327        3386 :     if( pInfo->gfi->italicAngle > 0 )
     328         288 :         m_eItalic = ITALIC_OBLIQUE;
     329        3098 :     else if( pInfo->gfi->italicAngle < 0 )
     330        1368 :         m_eItalic = ITALIC_NORMAL;
     331             :     else
     332        1730 :         m_eItalic = ITALIC_NONE;
     333             : 
     334             :     // weight
     335        6772 :     OString aWeight( pInfo->gfi->weight );
     336        3386 :     m_eWeight = parseWeight( aWeight.toAsciiLowerCase() );
     337             : 
     338             :     // pitch
     339        3386 :     m_ePitch = pInfo->gfi->isFixedPitch ? PITCH_FIXED : PITCH_VARIABLE;
     340             : 
     341             :     // encoding - only set if unknown
     342        3386 :     int nAdobeEncoding = 0;
     343        3386 :     if( pInfo->gfi->encodingScheme )
     344             :     {
     345        3386 :         if( !strcmp( pInfo->gfi->encodingScheme, "AdobeStandardEncoding" ) )
     346        3242 :             nAdobeEncoding = 1;
     347         144 :         else if( !strcmp( pInfo->gfi->encodingScheme, "ISO10646-1" ) )
     348             :         {
     349           0 :             nAdobeEncoding = 1;
     350           0 :             m_aEncoding = RTL_TEXTENCODING_UNICODE;
     351             :         }
     352         144 :         else if( !strcmp( pInfo->gfi->encodingScheme, "Symbol") )
     353           0 :             nAdobeEncoding = 2;
     354         144 :         else if( !strcmp( pInfo->gfi->encodingScheme, "FontSpecific") )
     355         144 :             nAdobeEncoding = 3;
     356             : 
     357        3386 :         if( m_aEncoding == RTL_TEXTENCODING_DONTKNOW )
     358             :             m_aEncoding = nAdobeEncoding == 1 ?
     359        3384 :                 RTL_TEXTENCODING_ADOBE_STANDARD : RTL_TEXTENCODING_SYMBOL;
     360             :     }
     361           0 :     else if( m_aEncoding == RTL_TEXTENCODING_DONTKNOW )
     362           0 :         m_aEncoding = RTL_TEXTENCODING_ADOBE_STANDARD;
     363             : 
     364             :     // try to parse the font name and decide whether it might be a
     365             :     // japanese font. Who invented this PITA ?
     366        6772 :     OUString aPSNameLastToken( aPSName.copy( aPSName.lastIndexOf( '-' )+1 ) );
     367        6772 :     if( aPSNameLastToken.equalsAscii( "H" )    ||
     368        3386 :         aPSNameLastToken.equalsAscii( "V" )  )
     369             :     {
     370             :         static const char* pEncs[] =
     371             :             {
     372             :                 "EUC",
     373             :                 "RKSJ",
     374             :                 "SJ"
     375             :             };
     376             :         static const rtl_TextEncoding aEncs[] =
     377             :             {
     378             :                 RTL_TEXTENCODING_EUC_JP,
     379             :                 RTL_TEXTENCODING_SHIFT_JIS,
     380             :                 RTL_TEXTENCODING_JIS_X_0208
     381             :             };
     382             : 
     383           0 :         for( unsigned int enc = 0; enc < SAL_N_ELEMENTS( aEncs ) && m_aEncoding == RTL_TEXTENCODING_DONTKNOW; enc++ )
     384             :         {
     385           0 :             sal_Int32 nIndex = 0, nOffset = 1;
     386           0 :             do
     387             :             {
     388           0 :                 OUString aToken( aPSName.getToken( nOffset, '-', nIndex ) );
     389           0 :                 if( nIndex == -1 )
     390           0 :                     break;
     391           0 :                 nOffset = 0;
     392           0 :                 if( aToken.equalsAscii( pEncs[enc] ) )
     393             :                 {
     394           0 :                     m_aEncoding = aEncs[ enc ];
     395           0 :                     m_bFontEncodingOnly = true;
     396           0 :                 }
     397           0 :             } while( nIndex != -1 );
     398             :         }
     399             : 
     400             :         // default is jis
     401           0 :         if( m_aEncoding == RTL_TEXTENCODING_DONTKNOW )
     402           0 :             m_aEncoding = RTL_TEXTENCODING_JIS_X_0208;
     403             : #if OSL_DEBUG_LEVEL > 1
     404             :         fprintf( stderr, "Encoding %d for %s\n", m_aEncoding, pInfo->gfi->fontName );
     405             : #endif
     406             :     }
     407             : 
     408             :     // #i37313# check if Fontspecific is not rather some character encoding
     409        3386 :     if( nAdobeEncoding == 3 && m_aEncoding == RTL_TEXTENCODING_SYMBOL )
     410             :     {
     411         144 :         bool bYFound = false;
     412         144 :         bool bQFound = false;
     413         144 :         CharMetricInfo* pChar = pInfo->cmi;
     414       28440 :         for( int j = 0; j < pInfo->numOfChars && ! (bYFound && bQFound); j++ )
     415             :         {
     416       28296 :             if( pChar[j].name )
     417             :             {
     418       28296 :                 if( pChar[j].name[0] == 'Y' && pChar[j].name[1] == 0 )
     419           0 :                     bYFound = true;
     420       28296 :                 else if( pChar[j].name[0] == 'Q' && pChar[j].name[1] == 0 )
     421           0 :                     bQFound = true;
     422             :             }
     423             :         }
     424         144 :         if( bQFound && bYFound )
     425             :         {
     426             :             #if OSL_DEBUG_LEVEL > 1
     427             :             fprintf( stderr, "setting FontSpecific font %s (file %s) to unicode\n",
     428             :                      pInfo->gfi->fontName,
     429             :                      rFileName.getStr()
     430             :                      );
     431             :             #endif
     432           0 :             nAdobeEncoding = 4;
     433           0 :             m_aEncoding = RTL_TEXTENCODING_UNICODE;
     434           0 :             bFillEncodingvector = false; // will be filled anyway, don't do the work twice
     435             :         }
     436             :     }
     437             : 
     438             :     // ascend
     439        3386 :     m_nAscend = pInfo->gfi->fontBBox.ury;
     440             : 
     441             :     // descend
     442             :     // descends have opposite sign of our definition
     443        3386 :     m_nDescend = -pInfo->gfi->fontBBox.lly;
     444             : 
     445             :     // fallback to ascender, descender
     446             :     // interesting: the BBox seems to describe Ascender and Descender better
     447             :     // as we understand it
     448        3386 :     if( m_nAscend == 0 )
     449           0 :         m_nAscend = pInfo->gfi->ascender;
     450        3386 :     if( m_nDescend == 0)
     451           0 :         m_nDescend = -pInfo->gfi->descender;
     452             : 
     453        3386 :     m_nLeading = m_nAscend + m_nDescend - 1000;
     454             : 
     455        3386 :     delete m_pMetrics;
     456        3386 :     m_pMetrics = new PrintFontMetrics;
     457             :     // mark all pages as queried (or clear if only global font info queiried)
     458        3386 :     memset( m_pMetrics->m_aPages, bOnlyGlobalAttributes ? 0 : 0xff, sizeof( m_pMetrics->m_aPages ) );
     459             : 
     460             :     m_aGlobalMetricX.width = m_aGlobalMetricY.width =
     461        3386 :         pInfo->gfi->charwidth ? pInfo->gfi->charwidth : pInfo->gfi->fontBBox.urx;
     462             :     m_aGlobalMetricX.height = m_aGlobalMetricY.height =
     463        3386 :         pInfo->gfi->capHeight ? pInfo->gfi->capHeight : pInfo->gfi->fontBBox.ury;
     464             : 
     465        3386 :     m_nXMin = pInfo->gfi->fontBBox.llx;
     466        3386 :     m_nYMin = pInfo->gfi->fontBBox.lly;
     467        3386 :     m_nXMax = pInfo->gfi->fontBBox.urx;
     468        3386 :     m_nYMax = pInfo->gfi->fontBBox.ury;
     469             : 
     470        3386 :     if( bFillEncodingvector || !bOnlyGlobalAttributes )
     471             :     {
     472             :         // fill in character metrics
     473             : 
     474             :         // first transform the character codes to unicode
     475             :         // note: this only works with single byte encodings
     476           2 :         sal_Unicode* pUnicodes = (sal_Unicode*)alloca( pInfo->numOfChars * sizeof(sal_Unicode));
     477           2 :         CharMetricInfo* pChar = pInfo->cmi;
     478             :         int i;
     479             : 
     480        1126 :         for( i = 0; i < pInfo->numOfChars; i++, pChar++ )
     481             :         {
     482        1124 :             if( nAdobeEncoding == 4 )
     483             :             {
     484           0 :                 if( pChar->name )
     485             :                 {
     486           0 :                     pUnicodes[i] = 0;
     487           0 :                     std::list< sal_Unicode > aCodes = rManager.getUnicodeFromAdobeName( pChar->name );
     488           0 :                     for( std::list< sal_Unicode >::const_iterator it = aCodes.begin(); it != aCodes.end(); ++it )
     489             :                     {
     490           0 :                         if( *it != 0 )
     491             :                         {
     492           0 :                             m_aEncodingVector[ *it ] = pChar->code;
     493           0 :                             if( pChar->code == -1 )
     494           0 :                                 m_aNonEncoded[ *it ] = pChar->name;
     495           0 :                             if( ! pUnicodes[i] ) // map the first
     496           0 :                                 pUnicodes[i] = *it;
     497             :                         }
     498           0 :                     }
     499             :                 }
     500             :             }
     501        1124 :             else if( pChar->code != -1 )
     502             :             {
     503         298 :                 if( nAdobeEncoding == 3 && m_aEncoding == RTL_TEXTENCODING_SYMBOL )
     504             :                 {
     505           0 :                     pUnicodes[i] = pChar->code + 0xf000;
     506           0 :                     if( bFillEncodingvector )
     507           0 :                         m_aEncodingVector[ pUnicodes[i] ] = pChar->code;
     508           0 :                     continue;
     509             :                 }
     510             : 
     511         298 :                 if( m_aEncoding == RTL_TEXTENCODING_UNICODE )
     512             :                 {
     513           0 :                     pUnicodes[i] = (sal_Unicode)pChar->code;
     514           0 :                     continue;
     515             :                 }
     516             : 
     517         298 :                 OStringBuffer aTranslate;
     518         298 :                 if( pChar->code & 0xff000000 )
     519           0 :                     aTranslate.append((char)(pChar->code >> 24));
     520         298 :                 if( pChar->code & 0xffff0000 )
     521           0 :                     aTranslate.append((char)((pChar->code & 0x00ff0000) >> 16));
     522         298 :                 if( pChar->code & 0xffffff00 )
     523           0 :                     aTranslate.append((char)((pChar->code & 0x0000ff00) >> 8 ));
     524         298 :                 aTranslate.append((char)(pChar->code & 0xff));
     525         596 :                 OUString aUni(OStringToOUString(aTranslate.makeStringAndClear(), m_aEncoding));
     526         596 :                 pUnicodes[i] = aUni.toChar();
     527             :             }
     528             :             else
     529         826 :                 pUnicodes[i] = 0;
     530             :         }
     531             : 
     532             :         // now fill in the character metrics
     533             :         // parseAFM.cxx effectively only supports direction 0 (horizontal)
     534           2 :         pChar = pInfo->cmi;
     535           2 :         CharacterMetric aMetric;
     536        1126 :         for( i = 0; i < pInfo->numOfChars; i++, pChar++ )
     537             :         {
     538        1124 :             if( pChar->code == -1 && ! pChar->name )
     539           0 :                 continue;
     540             : 
     541        1124 :             if( bFillEncodingvector && pChar->name )
     542             :             {
     543           0 :                 std::list< sal_Unicode > aCodes = rManager.getUnicodeFromAdobeName( pChar->name );
     544           0 :                 for( std::list< sal_Unicode >::const_iterator it = aCodes.begin(); it != aCodes.end(); ++it )
     545             :                 {
     546           0 :                     if( *it != 0 )
     547             :                     {
     548           0 :                         m_aEncodingVector[ *it ] = pChar->code;
     549           0 :                         if( pChar->code == -1 )
     550           0 :                             m_aNonEncoded[ *it ] = pChar->name;
     551             :                     }
     552           0 :                 }
     553             :             }
     554             : 
     555        1124 :             aMetric.width   = pChar->wx ? pChar->wx : pChar->charBBox.urx;
     556        1124 :             aMetric.height  = pChar->wy ? pChar->wy : pChar->charBBox.ury - pChar->charBBox.lly;
     557        1124 :             if( aMetric.width == 0 && aMetric.height == 0 )
     558             :                 // guess something for e.g. space
     559           0 :                 aMetric.width = m_aGlobalMetricX.width/4;
     560             : 
     561        1124 :             if( ( nAdobeEncoding == 0 ) ||
     562           0 :                 ( ( nAdobeEncoding == 3 ) && ( m_aEncoding != RTL_TEXTENCODING_SYMBOL ) ) )
     563             :             {
     564           0 :                 if( pChar->code != -1 )
     565             :                 {
     566           0 :                     m_pMetrics->m_aMetrics[ pUnicodes[i] ] = aMetric;
     567           0 :                     if( bFillEncodingvector )
     568           0 :                         m_aEncodingVector[ pUnicodes[i] ] = pChar->code;
     569             :                 }
     570           0 :                 else if( pChar->name )
     571             :                 {
     572           0 :                     std::list< sal_Unicode > aCodes = rManager.getUnicodeFromAdobeName( pChar->name );
     573           0 :                     for( std::list< sal_Unicode >::const_iterator it = aCodes.begin(); it != aCodes.end(); ++it )
     574             :                     {
     575           0 :                         if( *it != 0 )
     576           0 :                             m_pMetrics->m_aMetrics[ *it ] = aMetric;
     577           0 :                     }
     578           0 :                 }
     579             :             }
     580        1124 :             else if( nAdobeEncoding == 1 || nAdobeEncoding == 2 || nAdobeEncoding == 4)
     581             :             {
     582        1124 :                 if( pChar->name )
     583             :                 {
     584        1124 :                     std::list< sal_Unicode > aCodes = rManager.getUnicodeFromAdobeName( pChar->name );
     585        2270 :                     for( std::list< sal_Unicode >::const_iterator it = aCodes.begin(); it != aCodes.end(); ++it )
     586             :                     {
     587        1146 :                         if( *it != 0 )
     588        1146 :                             m_pMetrics->m_aMetrics[ *it ] = aMetric;
     589        1124 :                     }
     590             :                 }
     591           0 :                 else if( pChar->code != -1 )
     592             :                 {
     593             :                     ::std::pair< ::boost::unordered_multimap< sal_uInt8, sal_Unicode >::const_iterator,
     594             :                           ::boost::unordered_multimap< sal_uInt8, sal_Unicode >::const_iterator >
     595           0 :                           aCodes = rManager.getUnicodeFromAdobeCode( pChar->code );
     596           0 :                     while( aCodes.first != aCodes.second )
     597             :                     {
     598           0 :                         if( (*aCodes.first).second != 0 )
     599             :                         {
     600           0 :                             m_pMetrics->m_aMetrics[ (*aCodes.first).second ] = aMetric;
     601           0 :                             if( bFillEncodingvector )
     602           0 :                                 m_aEncodingVector[ (*aCodes.first).second ] = pChar->code;
     603             :                         }
     604           0 :                         ++aCodes.first;
     605             :                     }
     606        1124 :                 }
     607             :             }
     608           0 :             else if( nAdobeEncoding == 3 )
     609             :             {
     610           0 :                 if( pChar->code != -1 )
     611             :                 {
     612           0 :                     sal_Unicode code = 0xf000 + pChar->code;
     613           0 :                     m_pMetrics->m_aMetrics[ code ] = aMetric;
     614             :                     // maybe should try to find the name in the convtabs ?
     615           0 :                     if( bFillEncodingvector )
     616           0 :                         m_aEncodingVector[ code ] = pChar->code;
     617             :                 }
     618             :             }
     619             :         }
     620             :     }
     621             : 
     622        3386 :     freeFontInfo( pInfo );
     623        6772 :     return true;
     624             : }
     625             : 
     626             : /*
     627             :  *  one instance only
     628             :  */
     629      110570 : PrintFontManager& PrintFontManager::get()
     630             : {
     631             :     static PrintFontManager* pManager = NULL;
     632      110570 :     if( ! pManager )
     633             :     {
     634         306 :         static PrintFontManager theManager;
     635         306 :         pManager = &theManager;
     636         306 :         pManager->initialize();
     637             :     }
     638      110570 :     return *pManager;
     639             : }
     640             : 
     641             : /*
     642             :  *  the PrintFontManager
     643             :  */
     644             : 
     645         306 : PrintFontManager::PrintFontManager()
     646             :     : m_nNextFontID( 1 )
     647           0 :     , m_pAtoms( new MultiAtomProvider() )
     648             :     , m_nNextDirAtom( 1 )
     649         306 :     , m_pFontCache( NULL )
     650             : {
     651      321912 :     for( unsigned int i = 0; i < SAL_N_ELEMENTS( aAdobeCodes ); i++ )
     652             :     {
     653      321606 :         m_aUnicodeToAdobename.insert( ::boost::unordered_multimap< sal_Unicode, OString >::value_type( aAdobeCodes[i].aUnicode, aAdobeCodes[i].pAdobename ) );
     654      321606 :         m_aAdobenameToUnicode.insert( ::boost::unordered_multimap< OString, sal_Unicode, OStringHash >::value_type( aAdobeCodes[i].pAdobename, aAdobeCodes[i].aUnicode ) );
     655      321606 :         if( aAdobeCodes[i].aAdobeStandardCode )
     656             :         {
     657       46206 :             m_aUnicodeToAdobecode.insert( ::boost::unordered_multimap< sal_Unicode, sal_uInt8 >::value_type( aAdobeCodes[i].aUnicode, aAdobeCodes[i].aAdobeStandardCode ) );
     658       46206 :             m_aAdobecodeToUnicode.insert( ::boost::unordered_multimap< sal_uInt8, sal_Unicode >::value_type( aAdobeCodes[i].aAdobeStandardCode, aAdobeCodes[i].aUnicode ) );
     659             :         }
     660             :     }
     661             : 
     662         306 :     m_aFontInstallerTimer.SetTimeoutHdl(LINK(this, PrintFontManager, autoInstallFontLangSupport));
     663         306 :     m_aFontInstallerTimer.SetTimeout(5000);
     664         306 : }
     665             : 
     666         612 : PrintFontManager::~PrintFontManager()
     667             : {
     668         306 :     m_aFontInstallerTimer.Stop();
     669         306 :     deinitFontconfig();
     670       46818 :     for( ::boost::unordered_map< fontID, PrintFont* >::const_iterator it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
     671       46512 :         delete (*it).second;
     672         306 :     delete m_pAtoms;
     673         306 :     delete m_pFontCache;
     674         306 : }
     675             : 
     676       15968 : OString PrintFontManager::getDirectory( int nAtom ) const
     677             : {
     678       15968 :     ::boost::unordered_map< int, OString >::const_iterator it( m_aAtomToDir.find( nAtom ) );
     679       15968 :     return it != m_aAtomToDir.end() ? it->second : OString();
     680             : }
     681             : 
     682       61472 : int PrintFontManager::getDirectoryAtom( const OString& rDirectory, bool bCreate )
     683             : {
     684       61472 :     int nAtom = 0;
     685             :     ::boost::unordered_map< OString, int, OStringHash >::const_iterator it
     686       61472 :           ( m_aDirToAtom.find( rDirectory ) );
     687       61472 :     if( it != m_aDirToAtom.end() )
     688       59024 :         nAtom = it->second;
     689        2448 :     else if( bCreate )
     690             :     {
     691        2448 :         nAtom = m_nNextDirAtom++;
     692        2448 :         m_aDirToAtom[ rDirectory ] = nAtom;
     693        2448 :         m_aAtomToDir[ nAtom ] = rDirectory;
     694             :     }
     695       61472 :     return nAtom;
     696             : }
     697             : 
     698           0 : std::vector<fontID> PrintFontManager::addFontFile( const OString& rFileName )
     699             : {
     700           0 :     rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
     701           0 :     INetURLObject aPath( OStringToOUString( rFileName, aEncoding ), INetURLObject::FSYS_DETECT );
     702           0 :     OString aName( OUStringToOString( aPath.GetName( INetURLObject::DECODE_WITH_CHARSET, aEncoding ), aEncoding ) );
     703             :     OString aDir( OUStringToOString(
     704           0 :         INetURLObject::decode( aPath.GetPath(), '%', INetURLObject::DECODE_WITH_CHARSET, aEncoding ), aEncoding ) );
     705             : 
     706           0 :     int nDirID = getDirectoryAtom( aDir, true );
     707           0 :     std::vector<fontID> aFontIds = findFontFileIDs( nDirID, aName );
     708           0 :     if( aFontIds.empty() )
     709             :     {
     710           0 :         ::std::list< PrintFont* > aNewFonts;
     711           0 :         if( analyzeFontFile( nDirID, aName, aNewFonts ) )
     712             :         {
     713           0 :             for( ::std::list< PrintFont* >::iterator it = aNewFonts.begin();
     714           0 :                  it != aNewFonts.end(); ++it )
     715             :             {
     716           0 :                 fontID nFontId = m_nNextFontID++;
     717           0 :                 m_aFonts[nFontId] = *it;
     718           0 :                 m_aFontFileToFontID[ aName ].insert( nFontId );
     719           0 :                 m_pFontCache->updateFontCacheEntry( *it, true );
     720           0 :                 aFontIds.push_back(nFontId);
     721             :             }
     722           0 :         }
     723             :     }
     724           0 :     return aFontIds;
     725             : }
     726             : 
     727             : enum fontFormat
     728             : {
     729             :     UNKNOWN, TRUETYPE, CFF, TYPE1
     730             : };
     731             : 
     732       11862 : bool PrintFontManager::analyzeFontFile( int nDirID, const OString& rFontFile, ::std::list< PrintFontManager::PrintFont* >& rNewFonts, const char *pFormat ) const
     733             : {
     734       11862 :     rNewFonts.clear();
     735             : 
     736       11862 :     OString aDir( getDirectory( nDirID ) );
     737             : 
     738       23724 :     OString aFullPath( aDir );
     739       11862 :     aFullPath += "/";
     740       11862 :     aFullPath += rFontFile;
     741             : 
     742             :     // #i1872# reject unreadable files
     743       11862 :     if( access( aFullPath.getStr(), R_OK ) )
     744           0 :         return false;
     745             : 
     746       11862 :     fontFormat eFormat = UNKNOWN;
     747       11862 :     if (pFormat)
     748             :     {
     749       11862 :         if (!strcmp(pFormat, "TrueType"))
     750        7560 :             eFormat = TRUETYPE;
     751        4302 :         else if (!strcmp(pFormat, "CFF"))
     752           0 :             eFormat = CFF;
     753        4302 :         else if (!strcmp(pFormat, "Type 1"))
     754        4302 :             eFormat = TYPE1;
     755             :     }
     756       11862 :     if (eFormat == UNKNOWN)
     757             :     {
     758           0 :         OString aExt( rFontFile.copy( rFontFile.lastIndexOf( '.' )+1 ) );
     759           0 :         if( aExt.equalsIgnoreAsciiCase("pfb") || aExt.equalsIgnoreAsciiCase("pfa") )
     760           0 :             eFormat = TYPE1;
     761           0 :         else if( aExt.equalsIgnoreAsciiCase("ttf")
     762           0 :              ||  aExt.equalsIgnoreAsciiCase("ttc")
     763           0 :              ||  aExt.equalsIgnoreAsciiCase("tte") ) // #i33947# for Gaiji support
     764           0 :             eFormat = TRUETYPE;
     765           0 :         else if( aExt.equalsIgnoreAsciiCase("otf") ) // check for TTF- and PS-OpenType too
     766           0 :             eFormat = CFF;
     767             :     }
     768             : 
     769       11862 :     if (eFormat == TYPE1)
     770             :     {
     771             :         // check for corresponding afm metric
     772             :         // first look for an adjacent file
     773             :         static const char* pSuffix[] = { ".afm", ".AFM" };
     774             : 
     775        6138 :         for( unsigned int i = 0; i < SAL_N_ELEMENTS(pSuffix); i++ )
     776             :         {
     777             :             OString aName = OStringBuffer(
     778        5220 :                 rFontFile.copy(0, rFontFile.getLength() - 4)).
     779       10440 :                 append(pSuffix[i]).makeStringAndClear();
     780             : 
     781        7056 :             OStringBuffer aFilePath(aDir);
     782        5220 :             aFilePath.append('/').append(aName);
     783             : 
     784        7056 :             OString aAfmFile;
     785        5220 :             if( access( aFilePath.makeStringAndClear().getStr(), R_OK ) )
     786             :             {
     787             :                 // try in subdirectory afm instead
     788        1836 :                 aFilePath.append(aDir).append("/afm/").append(aName);
     789             : 
     790        1836 :                 if (!access(aFilePath.getStr(), R_OK))
     791           0 :                     aAfmFile = OString("afm/") + aName;
     792             :             }
     793             :             else
     794        3384 :                 aAfmFile = aName;
     795             : 
     796        5220 :             if( !aAfmFile.isEmpty() )
     797             :             {
     798        3384 :                 Type1FontFile* pFont = new Type1FontFile();
     799        3384 :                 pFont->m_nDirectory     = nDirID;
     800             : 
     801        3384 :                 pFont->m_aFontFile      = rFontFile;
     802        3384 :                 pFont->m_aMetricFile    = aAfmFile;
     803             : 
     804        3384 :                 if( ! pFont->readAfmMetrics( m_pAtoms, false, true ) )
     805             :                 {
     806           0 :                     delete pFont;
     807           0 :                     pFont = NULL;
     808             :                 }
     809        3384 :                 if( pFont )
     810        3384 :                     rNewFonts.push_back( pFont );
     811        3384 :                 break;
     812             :             }
     813        1836 :         }
     814             :     }
     815        7560 :     else if (eFormat == TRUETYPE || eFormat == CFF)
     816             :     {
     817             :         // get number of ttc entries
     818        7560 :         int nLength = CountTTCFonts( aFullPath.getStr() );
     819        7560 :         if( nLength )
     820             :         {
     821             : #if OSL_DEBUG_LEVEL > 1
     822             :             fprintf( stderr, "ttc: %s contains %d fonts\n", aFullPath.getStr(), nLength );
     823             : #endif
     824             : 
     825           0 :             sal_uInt64 fileSize = 0;
     826             : 
     827           0 :             OUString aURL;
     828           0 :             if (osl::File::getFileURLFromSystemPath(OStringToOUString(aFullPath, osl_getThreadTextEncoding()),
     829           0 :                 aURL) == osl::File::E_None)
     830             :             {
     831           0 :                 osl::File aFile(aURL);
     832           0 :                 if (aFile.open(osl_File_OpenFlag_Read | osl_File_OpenFlag_NoLock) == osl::File::E_None)
     833             :                 {
     834           0 :                     osl::DirectoryItem aItem;
     835           0 :                     osl::DirectoryItem::get( aURL, aItem );
     836           0 :                     osl::FileStatus aFileStatus( osl_FileStatus_Mask_FileSize );
     837           0 :                     aItem.getFileStatus( aFileStatus );
     838           0 :                     fileSize = aFileStatus.getFileSize();
     839           0 :                 }
     840             :             }
     841             : 
     842             :             //Feel free to calc the exact max possible number of fonts a file
     843             :             //could contain given its physical size. But this will clamp it to
     844             :             //a sane starting point
     845             :             //http://processingjs.nihongoresources.com/the_smallest_font/
     846             :             //https://github.com/grzegorzrolek/null-ttf
     847           0 :             const int nMaxFontsPossible = fileSize / 528;
     848           0 :             if (nLength > nMaxFontsPossible)
     849           0 :                 nLength = nMaxFontsPossible;
     850             : 
     851           0 :             for( int i = 0; i < nLength; i++ )
     852             :             {
     853           0 :                 TrueTypeFontFile* pFont     = new TrueTypeFontFile();
     854           0 :                 pFont->m_nDirectory         = nDirID;
     855           0 :                 pFont->m_aFontFile          = rFontFile;
     856           0 :                 pFont->m_nCollectionEntry   = i;
     857           0 :                 if( ! analyzeTrueTypeFile( pFont ) )
     858             :                 {
     859           0 :                     delete pFont;
     860           0 :                     pFont = NULL;
     861             :                 }
     862             :                 else
     863           0 :                     rNewFonts.push_back( pFont );
     864           0 :             }
     865             :         }
     866             :         else
     867             :         {
     868        7560 :             TrueTypeFontFile* pFont     = new TrueTypeFontFile();
     869        7560 :             pFont->m_nDirectory         = nDirID;
     870        7560 :             pFont->m_aFontFile          = rFontFile;
     871        7560 :             pFont->m_nCollectionEntry   = 0;
     872             : 
     873             :             // need to read the font anyway to get aliases inside the font file
     874        7560 :             if( ! analyzeTrueTypeFile( pFont ) )
     875             :             {
     876           0 :                 delete pFont;
     877           0 :                 pFont = NULL;
     878             :             }
     879             :             else
     880        7560 :                 rNewFonts.push_back( pFont );
     881             :         }
     882             :     }
     883       23724 :     return ! rNewFonts.empty();
     884             : }
     885             : 
     886       11342 : fontID PrintFontManager::findFontFileID( int nDirID, const OString& rFontFile, int nFaceIndex ) const
     887             : {
     888       11342 :     fontID nID = 0;
     889             : 
     890       11342 :     ::boost::unordered_map< OString, ::std::set< fontID >, OStringHash >::const_iterator set_it = m_aFontFileToFontID.find( rFontFile );
     891       11342 :     if( set_it == m_aFontFileToFontID.end() )
     892           0 :         return nID;
     893             : 
     894       22684 :     for( ::std::set< fontID >::const_iterator font_it = set_it->second.begin(); font_it != set_it->second.end() && ! nID; ++font_it )
     895             :     {
     896       11342 :         ::boost::unordered_map< fontID, PrintFont* >::const_iterator it = m_aFonts.find( *font_it );
     897       11342 :         if( it == m_aFonts.end() )
     898           0 :             continue;
     899       11342 :         switch( it->second->m_eType )
     900             :         {
     901             :             case fonttype::Type1:
     902             :             {
     903         600 :                 Type1FontFile* const pFont = static_cast< Type1FontFile* const >((*it).second);
     904        1200 :                 if( pFont->m_nDirectory == nDirID &&
     905         600 :                     pFont->m_aFontFile == rFontFile )
     906         600 :                     nID = it->first;
     907             :             }
     908         600 :             break;
     909             :             case fonttype::TrueType:
     910             :             {
     911       10742 :                 TrueTypeFontFile* const pFont = static_cast< TrueTypeFontFile* const >((*it).second);
     912       32226 :                 if( pFont->m_nDirectory == nDirID &&
     913       21484 :                     pFont->m_aFontFile == rFontFile && pFont->m_nCollectionEntry == nFaceIndex )
     914       10742 :                         nID = it->first;
     915             :             }
     916       10742 :             break;
     917             :             default:
     918           0 :                 break;
     919             :         }
     920             :     }
     921             : 
     922       11342 :     return nID;
     923             : }
     924             : 
     925           0 : std::vector<fontID> PrintFontManager::findFontFileIDs( int nDirID, const OString& rFontFile ) const
     926             : {
     927           0 :     std::vector<fontID> aIds;
     928             : 
     929           0 :     ::boost::unordered_map< OString, ::std::set< fontID >, OStringHash >::const_iterator set_it = m_aFontFileToFontID.find( rFontFile );
     930           0 :     if( set_it == m_aFontFileToFontID.end() )
     931           0 :         return aIds;
     932             : 
     933           0 :     for( ::std::set< fontID >::const_iterator font_it = set_it->second.begin(); font_it != set_it->second.end(); ++font_it )
     934             :     {
     935           0 :         ::boost::unordered_map< fontID, PrintFont* >::const_iterator it = m_aFonts.find( *font_it );
     936           0 :         if( it == m_aFonts.end() )
     937           0 :             continue;
     938           0 :         switch( it->second->m_eType )
     939             :         {
     940             :             case fonttype::Type1:
     941             :             {
     942           0 :                 Type1FontFile* const pFont = static_cast< Type1FontFile* const >((*it).second);
     943           0 :                 if( pFont->m_nDirectory == nDirID &&
     944           0 :                     pFont->m_aFontFile == rFontFile )
     945           0 :                     aIds.push_back(it->first);
     946             :             }
     947           0 :             break;
     948             :             case fonttype::TrueType:
     949             :             {
     950           0 :                 TrueTypeFontFile* const pFont = static_cast< TrueTypeFontFile* const >((*it).second);
     951           0 :                 if( pFont->m_nDirectory == nDirID &&
     952           0 :                     pFont->m_aFontFile == rFontFile )
     953           0 :                     aIds.push_back(it->first);
     954             :             }
     955           0 :             break;
     956             :             default:
     957           0 :                 break;
     958             :         }
     959             :     }
     960             : 
     961           0 :     return aIds;
     962             : }
     963             : 
     964       16078 : OUString PrintFontManager::convertTrueTypeName( void* pRecord ) const
     965             : {
     966       16078 :     NameRecord* pNameRecord = (NameRecord*)pRecord;
     967       16078 :     OUString aValue;
     968       16078 :     if(
     969       24117 :        ( pNameRecord->platformID == 3 && ( pNameRecord->encodingID == 0 || pNameRecord->encodingID == 1 ) )  // MS, Unicode
     970        8039 :        ||
     971        8039 :        ( pNameRecord->platformID == 0 ) // Apple, Unicode
     972             :        )
     973             :     {
     974        8039 :         OUStringBuffer aName( pNameRecord->slen/2 );
     975        8039 :         const sal_uInt8* pNameBuffer = pNameRecord->sptr;
     976      124250 :         for(int n = 0; n < pNameRecord->slen/2; n++ )
     977      116211 :             aName.append( (sal_Unicode)getUInt16BE( pNameBuffer ) );
     978        8039 :         aValue = aName.makeStringAndClear();
     979             :     }
     980        8039 :     else if( pNameRecord->platformID == 3 )
     981             :     {
     982           0 :         if( pNameRecord->encodingID >= 2 && pNameRecord->encodingID <= 6 )
     983             :         {
     984             :             /*
     985             :              *  and now for a special kind of madness:
     986             :              *  some fonts encode their byte value string as BE uint16
     987             :              *  (leading to stray zero bytes in the string)
     988             :              *  while others code two bytes as a uint16 and swap to BE
     989             :              */
     990           0 :             OStringBuffer aName;
     991           0 :             const sal_uInt8* pNameBuffer = pNameRecord->sptr;
     992           0 :             for(int n = 0; n < pNameRecord->slen/2; n++ )
     993             :             {
     994           0 :                 sal_Unicode aCode = (sal_Unicode)getUInt16BE( pNameBuffer );
     995           0 :                 sal_Char aChar = aCode >> 8;
     996           0 :                 if( aChar )
     997           0 :                     aName.append( aChar );
     998           0 :                 aChar = aCode & 0x00ff;
     999           0 :                 if( aChar )
    1000           0 :                     aName.append( aChar );
    1001             :             }
    1002           0 :             switch( pNameRecord->encodingID )
    1003             :             {
    1004             :                 case 2:
    1005           0 :                     aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_932 );
    1006           0 :                     break;
    1007             :                 case 3:
    1008           0 :                     aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_936 );
    1009           0 :                     break;
    1010             :                 case 4:
    1011           0 :                     aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_950 );
    1012           0 :                     break;
    1013             :                 case 5:
    1014           0 :                     aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_949 );
    1015           0 :                     break;
    1016             :                 case 6:
    1017           0 :                     aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_1361 );
    1018           0 :                     break;
    1019           0 :             }
    1020             :         }
    1021             :     }
    1022        8039 :     else if( pNameRecord->platformID == 1 )
    1023             :     {
    1024        8039 :         OString aName((const sal_Char*)(pNameRecord->sptr), pNameRecord->slen);
    1025        8039 :         rtl_TextEncoding eEncoding = RTL_TEXTENCODING_DONTKNOW;
    1026        8039 :         switch (pNameRecord->encodingID)
    1027             :         {
    1028             :             case 0:
    1029        8039 :                 eEncoding = RTL_TEXTENCODING_APPLE_ROMAN;
    1030        8039 :                 break;
    1031             :             case 1:
    1032           0 :                 eEncoding = RTL_TEXTENCODING_APPLE_JAPANESE;
    1033           0 :                 break;
    1034             :             case 2:
    1035           0 :                 eEncoding = RTL_TEXTENCODING_APPLE_CHINTRAD;
    1036           0 :                 break;
    1037             :             case 3:
    1038           0 :                 eEncoding = RTL_TEXTENCODING_APPLE_KOREAN;
    1039           0 :                 break;
    1040             :             case 4:
    1041           0 :                 eEncoding = RTL_TEXTENCODING_APPLE_ARABIC;
    1042           0 :                 break;
    1043             :             case 5:
    1044           0 :                 eEncoding = RTL_TEXTENCODING_APPLE_HEBREW;
    1045           0 :                 break;
    1046             :             case 6:
    1047           0 :                 eEncoding = RTL_TEXTENCODING_APPLE_GREEK;
    1048           0 :                 break;
    1049             :             case 7:
    1050           0 :                 eEncoding = RTL_TEXTENCODING_APPLE_CYRILLIC;
    1051           0 :                 break;
    1052             :             case 9:
    1053           0 :                 eEncoding = RTL_TEXTENCODING_APPLE_DEVANAGARI;
    1054           0 :                 break;
    1055             :             case 10:
    1056           0 :                 eEncoding = RTL_TEXTENCODING_APPLE_GURMUKHI;
    1057           0 :                 break;
    1058             :             case 11:
    1059           0 :                 eEncoding = RTL_TEXTENCODING_APPLE_GUJARATI;
    1060           0 :                 break;
    1061             :             case 21:
    1062           0 :                 eEncoding = RTL_TEXTENCODING_APPLE_THAI;
    1063           0 :                 break;
    1064             :             case 25:
    1065           0 :                 eEncoding = RTL_TEXTENCODING_APPLE_CHINSIMP;
    1066           0 :                 break;
    1067             :             case 29:
    1068           0 :                 eEncoding = RTL_TEXTENCODING_APPLE_CENTEURO;
    1069           0 :                 break;
    1070             :             case 32:    //Uninterpreted
    1071           0 :                 eEncoding = RTL_TEXTENCODING_UTF8;
    1072           0 :                 break;
    1073             :             default:
    1074             :                 SAL_WARN("vcl", "Unimplmented mac encoding " << pNameRecord->encodingID << " to unicode conversion");
    1075           0 :                 break;
    1076             :         }
    1077        8039 :         if (eEncoding != RTL_TEXTENCODING_DONTKNOW)
    1078        8039 :             aValue = OStringToOUString(aName, eEncoding);
    1079             :     }
    1080             : 
    1081       16078 :     return aValue;
    1082             : }
    1083             : 
    1084             : //fdo#33349.There exists an archaic Berling Antiqua font which has a "Times New
    1085             : //Roman" name field in it. We don't want the "Times New Roman" name to take
    1086             : //precedence in this case. We take Berling Antiqua as a higher priority name,
    1087             : //and erase the "Times New Roman" name
    1088             : namespace
    1089             : {
    1090           0 :     bool isBadTNR(const OUString &rName, ::std::set< OUString >& rSet)
    1091             :     {
    1092           0 :         bool bRet = false;
    1093           0 :         if ( rName == "Berling Antiqua" )
    1094             :         {
    1095           0 :             ::std::set< OUString >::iterator aEnd = rSet.end();
    1096           0 :             ::std::set< OUString >::iterator aI = rSet.find("Times New Roman");
    1097           0 :             if (aI != aEnd)
    1098             :             {
    1099           0 :                 bRet = true;
    1100           0 :                 rSet.erase(aI);
    1101             :             }
    1102             :         }
    1103           0 :         return bRet;
    1104             :     }
    1105             : }
    1106             : 
    1107        8039 : void PrintFontManager::analyzeTrueTypeFamilyName( void* pTTFont, ::std::list< OUString >& rNames ) const
    1108             : {
    1109        8039 :     OUString aFamily;
    1110             : 
    1111        8039 :     rNames.clear();
    1112       16078 :     ::std::set< OUString > aSet;
    1113             : 
    1114        8039 :     NameRecord* pNameRecords = NULL;
    1115        8039 :     int nNameRecords = GetTTNameRecords( (TrueTypeFont*)pTTFont, &pNameRecords );
    1116        8039 :     if( nNameRecords && pNameRecords )
    1117             :     {
    1118        8039 :         LanguageTag aSystem("");
    1119        8039 :         LanguageType eLang = aSystem.getLanguageType();
    1120        8039 :         int nLastMatch = -1;
    1121      535237 :         for( int i = 0; i < nNameRecords; i++ )
    1122             :         {
    1123      527198 :             if( pNameRecords[i].nameID != 1 || pNameRecords[i].sptr == NULL )
    1124     1022240 :                 continue;
    1125       16078 :             int nMatch = -1;
    1126       16078 :             if( pNameRecords[i].platformID == 0 ) // Unicode
    1127           0 :                 nMatch = 4000;
    1128       16078 :             else if( pNameRecords[i].platformID == 3 )
    1129             :             {
    1130             :                 // this bases on the LanguageType actually being a Win LCID
    1131        8039 :                 if (pNameRecords[i].languageID == eLang)
    1132        8039 :                     nMatch = 8000;
    1133           0 :                 else if( pNameRecords[i].languageID == LANGUAGE_ENGLISH_US )
    1134           0 :                     nMatch = 2000;
    1135           0 :                 else if( pNameRecords[i].languageID == LANGUAGE_ENGLISH ||
    1136           0 :                          pNameRecords[i].languageID == LANGUAGE_ENGLISH_UK )
    1137           0 :                     nMatch = 1500;
    1138             :                 else
    1139           0 :                     nMatch = 1000;
    1140             :             }
    1141        8039 :             else if (pNameRecords[i].platformID == 1)
    1142             :             {
    1143        8039 :                 LanguageTag aApple(makeLanguageTagFromAppleLanguageId(pNameRecords[i].languageID));
    1144        8039 :                 if (aApple == aSystem)
    1145           0 :                     nMatch = 8000;
    1146        8039 :                 else if (pNameRecords[i].languageID == APPLE_LANG_ENGLISH)
    1147        8039 :                     nMatch = 2000;
    1148             :                 else
    1149           0 :                     nMatch = 1000;
    1150             :             }
    1151       16078 :             OUString aName = convertTrueTypeName( pNameRecords + i );
    1152       16078 :             aSet.insert( aName );
    1153       16078 :             if (aName.isEmpty())
    1154           0 :                 continue;
    1155       16078 :             if( nMatch > nLastMatch || isBadTNR(aName, aSet) )
    1156             :             {
    1157       16078 :                 nLastMatch = nMatch;
    1158       16078 :                 aFamily = aName;
    1159             :             }
    1160       24117 :         }
    1161             :     }
    1162        8039 :     DisposeNameRecords( pNameRecords, nNameRecords );
    1163        8039 :     if( !aFamily.isEmpty() )
    1164             :     {
    1165        8039 :         rNames.push_front( aFamily );
    1166       16078 :         for( ::std::set< OUString >::const_iterator it = aSet.begin(); it != aSet.end(); ++it )
    1167        8039 :             if( *it != aFamily )
    1168           0 :                 rNames.push_back( *it );
    1169             :     }
    1170       16078 :     return;
    1171             : }
    1172             : 
    1173        8039 : bool PrintFontManager::analyzeTrueTypeFile( PrintFont* pFont ) const
    1174             : {
    1175        8039 :     bool bSuccess = false;
    1176        8039 :     rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
    1177        8039 :     OString aFile = getFontFile( pFont );
    1178        8039 :     TrueTypeFont* pTTFont = NULL;
    1179             : 
    1180        8039 :     TrueTypeFontFile* pTTFontFile = static_cast< TrueTypeFontFile* >(pFont);
    1181        8039 :     if( OpenTTFontFile( aFile.getStr(), pTTFontFile->m_nCollectionEntry, &pTTFont ) == SF_OK )
    1182             :     {
    1183             :         TTGlobalFontInfo aInfo;
    1184        8039 :         GetTTGlobalFontInfo( pTTFont, & aInfo );
    1185             : 
    1186        8039 :         ::std::list< OUString > aNames;
    1187        8039 :         analyzeTrueTypeFamilyName( pTTFont, aNames );
    1188             : 
    1189             :         // set family name from XLFD if possible
    1190        8039 :         if( ! pFont->m_nFamilyName )
    1191             :         {
    1192        7560 :             if( aNames.begin() != aNames.end() )
    1193             :             {
    1194        7560 :                 pFont->m_nFamilyName = m_pAtoms->getAtom( ATOM_FAMILYNAME, aNames.front(), true );
    1195        7560 :                 aNames.pop_front();
    1196             :             }
    1197             :             else
    1198             :             {
    1199             :                  sal_Int32   dotIndex;
    1200             : 
    1201             :                  // poor font does not have a family name
    1202             :                  // name it to file name minus the extension
    1203           0 :                  dotIndex = pTTFontFile->m_aFontFile.lastIndexOf( '.' );
    1204           0 :                  if ( dotIndex == -1 )
    1205           0 :                      dotIndex = pTTFontFile->m_aFontFile.getLength();
    1206             : 
    1207           0 :                  pFont->m_nFamilyName = m_pAtoms->getAtom( ATOM_FAMILYNAME, OStringToOUString( pTTFontFile->m_aFontFile.copy( 0, dotIndex ), aEncoding ), true );
    1208             :             }
    1209             :         }
    1210        8518 :         for( ::std::list< OUString >::iterator it = aNames.begin(); it != aNames.end(); ++it )
    1211             :         {
    1212         479 :             if( !it->isEmpty() )
    1213             :             {
    1214         479 :                 int nAlias = m_pAtoms->getAtom( ATOM_FAMILYNAME, *it, true );
    1215         479 :                 if( nAlias != pFont->m_nFamilyName )
    1216             :                 {
    1217           0 :                     std::list< int >::const_iterator al_it;
    1218           0 :                     for( al_it = pFont->m_aAliases.begin(); al_it != pFont->m_aAliases.end() && *al_it != nAlias; ++al_it )
    1219             :                         ;
    1220           0 :                     if( al_it == pFont->m_aAliases.end() )
    1221           0 :                         pFont->m_aAliases.push_back( nAlias );
    1222             :                 }
    1223             :             }
    1224             :         }
    1225             : 
    1226        8039 :         if( aInfo.usubfamily )
    1227           0 :             pFont->m_aStyleName = OUString( aInfo.usubfamily );
    1228             : 
    1229             :         SAL_WARN_IF( !aInfo.psname, "vcl", "No PostScript name in font:" << aFile.getStr() );
    1230             : 
    1231             :         OUString sPSName = aInfo.psname ?
    1232             :             OUString(aInfo.psname, rtl_str_getLength(aInfo.psname), aEncoding) :
    1233       16078 :             m_pAtoms->getString(ATOM_FAMILYNAME, pFont->m_nFamilyName); // poor font does not have a postscript name
    1234             : 
    1235        8039 :         pFont->m_nPSName = m_pAtoms->getAtom( ATOM_PSNAME, sPSName, true );
    1236             : 
    1237        8039 :         switch( aInfo.weight )
    1238             :         {
    1239           0 :             case FW_THIN:           pFont->m_eWeight = WEIGHT_THIN; break;
    1240         216 :             case FW_EXTRALIGHT: pFont->m_eWeight = WEIGHT_ULTRALIGHT; break;
    1241         144 :             case FW_LIGHT:          pFont->m_eWeight = WEIGHT_LIGHT; break;
    1242           0 :             case FW_MEDIUM:     pFont->m_eWeight = WEIGHT_MEDIUM; break;
    1243         288 :             case FW_SEMIBOLD:       pFont->m_eWeight = WEIGHT_SEMIBOLD; break;
    1244        2906 :             case FW_BOLD:           pFont->m_eWeight = WEIGHT_BOLD; break;
    1245           0 :             case FW_EXTRABOLD:      pFont->m_eWeight = WEIGHT_ULTRABOLD; break;
    1246         144 :             case FW_BLACK:          pFont->m_eWeight = WEIGHT_BLACK; break;
    1247             : 
    1248             :             case FW_NORMAL:
    1249        4341 :             default:        pFont->m_eWeight = WEIGHT_NORMAL; break;
    1250             :         }
    1251             : 
    1252        8039 :         switch( aInfo.width )
    1253             :         {
    1254           0 :             case FWIDTH_ULTRA_CONDENSED:    pFont->m_eWidth = WIDTH_ULTRA_CONDENSED; break;
    1255           0 :             case FWIDTH_EXTRA_CONDENSED:    pFont->m_eWidth = WIDTH_EXTRA_CONDENSED; break;
    1256         288 :             case FWIDTH_CONDENSED:          pFont->m_eWidth = WIDTH_CONDENSED; break;
    1257         576 :             case FWIDTH_SEMI_CONDENSED: pFont->m_eWidth = WIDTH_SEMI_CONDENSED; break;
    1258           0 :             case FWIDTH_SEMI_EXPANDED:      pFont->m_eWidth = WIDTH_SEMI_EXPANDED; break;
    1259           0 :             case FWIDTH_EXPANDED:           pFont->m_eWidth = WIDTH_EXPANDED; break;
    1260           0 :             case FWIDTH_EXTRA_EXPANDED: pFont->m_eWidth = WIDTH_EXTRA_EXPANDED; break;
    1261           0 :             case FWIDTH_ULTRA_EXPANDED: pFont->m_eWidth = WIDTH_ULTRA_EXPANDED; break;
    1262             : 
    1263             :             case FWIDTH_NORMAL:
    1264        7175 :             default:                        pFont->m_eWidth = WIDTH_NORMAL; break;
    1265             :         }
    1266             : 
    1267        8039 :         pFont->m_ePitch = aInfo.pitch ? PITCH_FIXED : PITCH_VARIABLE;
    1268        8039 :         pFont->m_eItalic = aInfo.italicAngle == 0 ? ITALIC_NONE : ( aInfo.italicAngle < 0 ? ITALIC_NORMAL : ITALIC_OBLIQUE );
    1269             :         // #104264# there are fonts that set italic angle 0 although they are
    1270             :         // italic; use macstyle bit here
    1271        8039 :         if( aInfo.italicAngle == 0 && (aInfo.macStyle & 2) )
    1272           0 :             pFont->m_eItalic = ITALIC_NORMAL;
    1273             : 
    1274        8039 :         pFont->m_aEncoding = aInfo.symbolEncoded ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UCS2;
    1275             : 
    1276        8039 :         pFont->m_aGlobalMetricY.width = pFont->m_aGlobalMetricX.width = aInfo.xMax - aInfo.xMin;
    1277        8039 :         pFont->m_aGlobalMetricY.height = pFont->m_aGlobalMetricX.height = aInfo.yMax - aInfo.yMin;
    1278             : 
    1279        8039 :         if( aInfo.winAscent && aInfo.winDescent )
    1280             :         {
    1281        8039 :             pFont->m_nAscend    = aInfo.winAscent;
    1282        8039 :             pFont->m_nDescend   = aInfo.winDescent;
    1283        8039 :             pFont->m_nLeading   = pFont->m_nAscend + pFont->m_nDescend - 1000;
    1284             :         }
    1285           0 :         else if( aInfo.typoAscender && aInfo.typoDescender )
    1286             :         {
    1287           0 :             pFont->m_nLeading   = aInfo.typoLineGap;
    1288           0 :             pFont->m_nAscend    = aInfo.typoAscender;
    1289           0 :             pFont->m_nDescend   = -aInfo.typoDescender;
    1290             :         }
    1291             :         else
    1292             :         {
    1293           0 :             pFont->m_nLeading   = aInfo.linegap;
    1294           0 :             pFont->m_nAscend    = aInfo.ascender;
    1295           0 :             pFont->m_nDescend   = -aInfo.descender;
    1296             :         }
    1297             : 
    1298             :         // last try: font bounding box
    1299        8039 :         if( pFont->m_nAscend == 0 )
    1300           0 :             pFont->m_nAscend = aInfo.yMax;
    1301        8039 :         if( pFont->m_nDescend == 0 )
    1302           0 :             pFont->m_nDescend = -aInfo.yMin;
    1303        8039 :         if( pFont->m_nLeading == 0 )
    1304         144 :             pFont->m_nLeading = 15 * (pFont->m_nAscend+pFont->m_nDescend) / 100;
    1305             : 
    1306        8039 :         if( pFont->m_nAscend )
    1307        8039 :             pFont->m_aGlobalMetricX.height = pFont->m_aGlobalMetricY.height = pFont->m_nAscend + pFont->m_nDescend;
    1308             : 
    1309             :         // get bounding box
    1310        8039 :         pFont->m_nXMin = aInfo.xMin;
    1311        8039 :         pFont->m_nYMin = aInfo.yMin;
    1312        8039 :         pFont->m_nXMax = aInfo.xMax;
    1313        8039 :         pFont->m_nYMax = aInfo.yMax;
    1314             : 
    1315             :         // get type flags
    1316        8039 :         pTTFontFile->m_nTypeFlags = (unsigned int)aInfo.typeFlags;
    1317             : 
    1318             :         // get vertical substitutions flag
    1319        8039 :         pFont->m_bHaveVerticalSubstitutedGlyphs = DoesVerticalSubstitution( pTTFont, 1 );
    1320             : 
    1321        8039 :         CloseTTFont( pTTFont );
    1322       16078 :         bSuccess = true;
    1323             :     }
    1324             : #if OSL_DEBUG_LEVEL > 1
    1325             :     else
    1326             :         fprintf( stderr, "could not OpenTTFont \"%s\"\n", aFile.getStr() );
    1327             : #endif
    1328             : 
    1329        8039 :     return bSuccess;
    1330             : }
    1331             : 
    1332         306 : static bool AreFCSubstitutionsEnabled()
    1333             : {
    1334         306 :     return (SalGenericInstance::FetchFontSubstitutionFlags() & 3) == 0;
    1335             : }
    1336             : 
    1337         306 : void PrintFontManager::initialize()
    1338             : {
    1339             :     #ifdef CALLGRIND_COMPILE
    1340             :     CALLGRIND_TOGGLE_COLLECT();
    1341             :     CALLGRIND_ZERO_STATS();
    1342             :     #endif
    1343             : 
    1344         306 :     if( ! m_pFontCache )
    1345             :     {
    1346             : #if OSL_DEBUG_LEVEL > 1
    1347             :         fprintf( stderr, "creating font cache ... " );
    1348             :         clock_t aStart;
    1349             :         struct tms tms;
    1350             :         aStart = times( &tms );
    1351             : #endif
    1352         306 :         m_pFontCache = new FontCache();
    1353             : #if OSL_DEBUG_LEVEL > 1
    1354             :         clock_t aStop = times( &tms );
    1355             :         fprintf( stderr, "done in %lf s\n", (double)(aStop - aStart)/(double)sysconf( _SC_CLK_TCK ) );
    1356             : #endif
    1357             :     }
    1358             : 
    1359             :     // initialize can be called more than once, e.g.
    1360             :     // gtk-fontconfig-timestamp changes to reflect new font installed and
    1361             :     // PrintFontManager::initialize called again
    1362             :     {
    1363         306 :         for( ::boost::unordered_map< fontID, PrintFont* >::const_iterator it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
    1364           0 :             delete (*it).second;
    1365         306 :         m_nNextFontID = 1;
    1366         306 :         m_aFonts.clear();
    1367         306 :         m_aFontDirectories.clear();
    1368         306 :         m_aPrivateFontDirectories.clear();
    1369             :     }
    1370             : 
    1371             : #if OSL_DEBUG_LEVEL > 1
    1372             :     clock_t aStart;
    1373             :     clock_t aStep1;
    1374             :     clock_t aStep2;
    1375             : 
    1376             :     struct tms tms;
    1377             : 
    1378             :     aStart = times( &tms );
    1379             : #endif
    1380             : 
    1381             :     // first try fontconfig
    1382         306 :     initFontconfig();
    1383             : 
    1384             :     // part one - look for downloadable fonts
    1385         306 :     rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
    1386         306 :     const OUString &rSalPrivatePath = psp::getFontPath();
    1387             : 
    1388             :     // search for the fonts in SAL_PRIVATE_FONTPATH first; those are
    1389             :     // the fonts installed with the office
    1390         306 :     if( !rSalPrivatePath.isEmpty() )
    1391             :     {
    1392         306 :         OString aPath = OUStringToOString( rSalPrivatePath, aEncoding );
    1393         306 :         const bool bAreFCSubstitutionsEnabled = AreFCSubstitutionsEnabled();
    1394         306 :         sal_Int32 nIndex = 0;
    1395         918 :         do
    1396             :         {
    1397         918 :             OString aToken = aPath.getToken( 0, ';', nIndex );
    1398         918 :             normPath( aToken );
    1399         918 :             if ( aToken.isEmpty() )
    1400             :             {
    1401           0 :                 continue;
    1402             :             }
    1403             :             // if registering an app-specific fontdir with fontconfig fails
    1404             :             // and fontconfig-based substitutions are enabled
    1405             :             // then trying to use these app-specific fonts doesn't make sense
    1406         918 :             if( !addFontconfigDir( aToken ) )
    1407           0 :                 if( bAreFCSubstitutionsEnabled )
    1408           0 :                     continue;
    1409         918 :             m_aFontDirectories.push_back( aToken );
    1410         918 :             m_aPrivateFontDirectories.push_back( getDirectoryAtom( aToken, true ) );
    1411        1224 :         } while( nIndex >= 0 );
    1412             :     }
    1413             : 
    1414             :     // protect against duplicate paths
    1415         612 :     boost::unordered_map< OString, int, OStringHash > visited_dirs;
    1416             : 
    1417             :     // Don't search directories that fontconfig already did
    1418         306 :     countFontconfigFonts( visited_dirs );
    1419             : 
    1420             :     // search for font files in each path
    1421         306 :     std::list< OString >::iterator dir_it;
    1422        1224 :     for( dir_it = m_aFontDirectories.begin(); dir_it != m_aFontDirectories.end(); ++dir_it )
    1423             :     {
    1424         918 :         OString aPath( *dir_it );
    1425             :         // see if we were here already
    1426         918 :         if( visited_dirs.find( aPath ) != visited_dirs.end() )
    1427         306 :             continue;
    1428         612 :         visited_dirs[ aPath ] = 1;
    1429             : 
    1430             :         // there may be ":unscaled" directories (see XFree86)
    1431             :         // it should be safe to ignore them since they should not
    1432             :         // contain any of our recognizeable fonts
    1433             : 
    1434             :         // ask the font cache whether it handles this directory
    1435        1224 :         std::list< PrintFont* > aCacheFonts;
    1436         612 :         if( m_pFontCache->listDirectory( aPath, aCacheFonts ) )
    1437             :         {
    1438             : #if OSL_DEBUG_LEVEL > 1
    1439             :             fprintf( stderr, "adding cache directory: %s\n", aPath.getStr() );
    1440             : #endif
    1441           0 :             for( ::std::list< PrintFont* >::iterator it = aCacheFonts.begin(); it != aCacheFonts.end(); ++it )
    1442             :             {
    1443           0 :                 fontID aFont = m_nNextFontID++;
    1444           0 :                 m_aFonts[ aFont ] = *it;
    1445           0 :                 if( (*it)->m_eType == fonttype::Type1 )
    1446           0 :                     m_aFontFileToFontID[ static_cast<Type1FontFile*>(*it)->m_aFontFile ].insert( aFont );
    1447           0 :                 else if( (*it)->m_eType == fonttype::TrueType )
    1448           0 :                     m_aFontFileToFontID[ static_cast<TrueTypeFontFile*>(*it)->m_aFontFile ].insert( aFont );
    1449             : #if OSL_DEBUG_LEVEL > 1
    1450             :                 else
    1451             :                     fprintf(stderr, "Un-cached type '%d'\n", (*it)->m_eType);
    1452             : #if OSL_DEBUG_LEVEL > 2
    1453             :                 fprintf( stderr, "adding cached font %d: %s\n", aFont, getFontFileSysPath( aFont ).getStr() );
    1454             : #endif
    1455             : #endif
    1456             :             }
    1457           0 :             if( ! m_pFontCache->scanAdditionalFiles( aPath ) )
    1458           0 :                 continue;
    1459             :         }
    1460             : 
    1461         612 :     }
    1462             : 
    1463             : #if OSL_DEBUG_LEVEL > 1
    1464             :     aStep1 = times( &tms );
    1465             : #endif
    1466             : 
    1467             :     // part three - fill in family styles
    1468         306 :     ::boost::unordered_map< fontID, PrintFont* >::iterator font_it;
    1469       46818 :     for (font_it = m_aFonts.begin(); font_it != m_aFonts.end(); ++font_it)
    1470             :     {
    1471             :         ::boost::unordered_map< int, FontFamily >::const_iterator it =
    1472       46512 :               m_aFamilyTypes.find( font_it->second->m_nFamilyName );
    1473       46512 :         if (it != m_aFamilyTypes.end())
    1474       31212 :             continue;
    1475             :         const OUString& rFamily =
    1476       15300 :             m_pAtoms->getString( ATOM_FAMILYNAME, font_it->second->m_nFamilyName);
    1477       15300 :         FontFamily eType = matchFamilyName( rFamily );
    1478       15300 :         m_aFamilyTypes[ font_it->second->m_nFamilyName ] = eType;
    1479             :     }
    1480             : 
    1481             : #if OSL_DEBUG_LEVEL > 1
    1482             :     aStep2 = times( &tms );
    1483             :     fprintf( stderr, "PrintFontManager::initialize: collected %" SAL_PRI_SIZET "u fonts\n", m_aFonts.size() );
    1484             :     double fTick = (double)sysconf( _SC_CLK_TCK );
    1485             :     fprintf( stderr, "Step 1 took %lf seconds\n", (double)(aStep1 - aStart)/fTick );
    1486             :     fprintf( stderr, "Step 2 took %lf seconds\n", (double)(aStep2 - aStep1)/fTick );
    1487             : #endif
    1488             : 
    1489         612 :     m_pFontCache->flush();
    1490             : 
    1491             :     #ifdef CALLGRIND_COMPILE
    1492             :     CALLGRIND_DUMP_STATS();
    1493             :     CALLGRIND_TOGGLE_COLLECT();
    1494             :     #endif
    1495         306 : }
    1496             : 
    1497        1092 : void PrintFontManager::getFontList( ::std::list< fontID >& rFontIDs )
    1498             : {
    1499        1092 :     rFontIDs.clear();
    1500        1092 :     boost::unordered_map< fontID, PrintFont* >::const_iterator it;
    1501             : 
    1502      167076 :     for( it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
    1503      165984 :         rFontIDs.push_back( it->first );
    1504        1092 : }
    1505             : 
    1506      177811 : void PrintFontManager::fillPrintFontInfo( PrintFont* pFont, FastPrintFontInfo& rInfo ) const
    1507             : {
    1508             :     ::boost::unordered_map< int, FontFamily >::const_iterator style_it =
    1509      177811 :           m_aFamilyTypes.find( pFont->m_nFamilyName );
    1510      177811 :     rInfo.m_eType           = pFont->m_eType;
    1511      177811 :     rInfo.m_aFamilyName     = m_pAtoms->getString( ATOM_FAMILYNAME, pFont->m_nFamilyName );
    1512      177811 :     rInfo.m_aStyleName      = pFont->m_aStyleName;
    1513      177811 :     rInfo.m_eFamilyStyle    = style_it != m_aFamilyTypes.end() ? style_it->second : FAMILY_DONTKNOW;
    1514      177811 :     rInfo.m_eItalic         = pFont->m_eItalic;
    1515      177811 :     rInfo.m_eWidth          = pFont->m_eWidth;
    1516      177811 :     rInfo.m_eWeight         = pFont->m_eWeight;
    1517      177811 :     rInfo.m_ePitch          = pFont->m_ePitch;
    1518      177811 :     rInfo.m_aEncoding       = pFont->m_aEncoding;
    1519             : 
    1520      177811 :     rInfo.m_bEmbeddable  = (pFont->m_eType == fonttype::Type1);
    1521      177811 :     rInfo.m_bSubsettable = (pFont->m_eType == fonttype::TrueType); // TODO: rename to SfntType
    1522             : 
    1523      177811 :     rInfo.m_aAliases.clear();
    1524      177811 :     for( ::std::list< int >::iterator it = pFont->m_aAliases.begin(); it != pFont->m_aAliases.end(); ++it )
    1525           0 :         rInfo.m_aAliases.push_back( m_pAtoms->getString( ATOM_FAMILYNAME, *it ) );
    1526      177811 : }
    1527             : 
    1528         485 : void PrintFontManager::fillPrintFontInfo( PrintFont* pFont, PrintFontInfo& rInfo ) const
    1529             : {
    1530        1455 :     if( ( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 ) ||
    1531         974 :         ! pFont->m_pMetrics || pFont->m_pMetrics->isEmpty()
    1532             :         )
    1533             :     {
    1534             :         // might be a truetype font not analyzed or type1 without metrics read
    1535         481 :         if( pFont->m_eType == fonttype::Type1 )
    1536           2 :             pFont->readAfmMetrics( m_pAtoms, false, false );
    1537         479 :         else if( pFont->m_eType == fonttype::TrueType )
    1538         479 :             analyzeTrueTypeFile( pFont );
    1539             :     }
    1540             : 
    1541         485 :     fillPrintFontInfo( pFont, static_cast< FastPrintFontInfo& >( rInfo ) );
    1542             : 
    1543         485 :     rInfo.m_nAscend         = pFont->m_nAscend;
    1544         485 :     rInfo.m_nDescend        = pFont->m_nDescend;
    1545         485 :     rInfo.m_nLeading        = pFont->m_nLeading;
    1546         485 :     rInfo.m_nWidth          = pFont->m_aGlobalMetricX.width < pFont->m_aGlobalMetricY.width ? pFont->m_aGlobalMetricY.width : pFont->m_aGlobalMetricX.width;
    1547         485 : }
    1548             : 
    1549         485 : bool PrintFontManager::getFontInfo( fontID nFontID, PrintFontInfo& rInfo ) const
    1550             : {
    1551         485 :     PrintFont* pFont = getFont( nFontID );
    1552         485 :     if( pFont )
    1553             :     {
    1554         485 :         rInfo.m_nID = nFontID;
    1555         485 :         fillPrintFontInfo( pFont, rInfo );
    1556             :     }
    1557         485 :     return pFont ? true : false;
    1558             : }
    1559             : 
    1560      177326 : bool PrintFontManager::getFontFastInfo( fontID nFontID, FastPrintFontInfo& rInfo ) const
    1561             : {
    1562      177326 :     PrintFont* pFont = getFont( nFontID );
    1563      177326 :     if( pFont )
    1564             :     {
    1565      177326 :         rInfo.m_nID = nFontID;
    1566      177326 :         fillPrintFontInfo( pFont, rInfo );
    1567             :     }
    1568      177326 :     return pFont ? true : false;
    1569             : }
    1570             : 
    1571           0 : bool PrintFontManager::getFontBoundingBox( fontID nFontID, int& xMin, int& yMin, int& xMax, int& yMax )
    1572             : {
    1573           0 :     bool bSuccess = false;
    1574           0 :     PrintFont* pFont = getFont( nFontID );
    1575           0 :     if( pFont )
    1576             :     {
    1577           0 :         if( pFont->m_nXMin == 0 && pFont->m_nYMin == 0 && pFont->m_nXMax == 0 && pFont->m_nYMax == 0 )
    1578             :         {
    1579             :             // might be a truetype font not analyzed or type1 without metrics read
    1580           0 :             if( pFont->m_eType == fonttype::Type1 )
    1581           0 :                 pFont->readAfmMetrics( m_pAtoms, false, true );
    1582           0 :             else if( pFont->m_eType == fonttype::TrueType )
    1583           0 :                 analyzeTrueTypeFile( pFont );
    1584             :         }
    1585           0 :         bSuccess = true;
    1586           0 :         xMin = pFont->m_nXMin;
    1587           0 :         yMin = pFont->m_nYMin;
    1588           0 :         xMax = pFont->m_nXMax;
    1589           0 :         yMax = pFont->m_nYMax;
    1590             :     }
    1591           0 :     return bSuccess;
    1592             : }
    1593             : 
    1594       47424 : int PrintFontManager::getFontFaceNumber( fontID nFontID ) const
    1595             : {
    1596       47424 :     int nRet = 0;
    1597       47424 :     PrintFont* pFont = getFont( nFontID );
    1598       47424 :     if( pFont && pFont->m_eType == fonttype::TrueType )
    1599       32760 :         nRet = static_cast< TrueTypeFontFile* >(pFont)->m_nCollectionEntry;
    1600       47424 :     if (nRet < 0)
    1601           0 :         nRet = 0;
    1602       47424 :     return nRet;
    1603             : }
    1604             : 
    1605       15300 : FontFamily PrintFontManager::matchFamilyName( const OUString& rFamily ) const
    1606             : {
    1607             :     typedef struct {
    1608             :         const char*  mpName;
    1609             :         sal_uInt16   mnLength;
    1610             :         FontFamily   meType;
    1611             :     } family_t;
    1612             : 
    1613             : #define InitializeClass( p, a ) p, sizeof(p) - 1, a
    1614             :     const family_t pFamilyMatch[] =  {
    1615             :         { InitializeClass( "arial",                  FAMILY_SWISS )  },
    1616             :         { InitializeClass( "arioso",                 FAMILY_SCRIPT ) },
    1617             :         { InitializeClass( "avant garde",            FAMILY_SWISS )  },
    1618             :         { InitializeClass( "avantgarde",             FAMILY_SWISS )  },
    1619             :         { InitializeClass( "bembo",                  FAMILY_ROMAN )  },
    1620             :         { InitializeClass( "bookman",                FAMILY_ROMAN )  },
    1621             :         { InitializeClass( "conga",                  FAMILY_ROMAN )  },
    1622             :         { InitializeClass( "courier",                FAMILY_MODERN ) },
    1623             :         { InitializeClass( "curl",                   FAMILY_SCRIPT ) },
    1624             :         { InitializeClass( "fixed",                  FAMILY_MODERN ) },
    1625             :         { InitializeClass( "gill",                   FAMILY_SWISS )  },
    1626             :         { InitializeClass( "helmet",                 FAMILY_MODERN ) },
    1627             :         { InitializeClass( "helvetica",              FAMILY_SWISS )  },
    1628             :         { InitializeClass( "international",          FAMILY_MODERN ) },
    1629             :         { InitializeClass( "lucida",                 FAMILY_SWISS )  },
    1630             :         { InitializeClass( "new century schoolbook", FAMILY_ROMAN )  },
    1631             :         { InitializeClass( "palatino",               FAMILY_ROMAN )  },
    1632             :         { InitializeClass( "roman",                  FAMILY_ROMAN )  },
    1633             :         { InitializeClass( "sans serif",             FAMILY_SWISS )  },
    1634             :         { InitializeClass( "sansserif",              FAMILY_SWISS )  },
    1635             :         { InitializeClass( "serf",                   FAMILY_ROMAN )  },
    1636             :         { InitializeClass( "serif",                  FAMILY_ROMAN )  },
    1637             :         { InitializeClass( "times",                  FAMILY_ROMAN )  },
    1638             :         { InitializeClass( "utopia",                 FAMILY_ROMAN )  },
    1639             :         { InitializeClass( "zapf chancery",          FAMILY_SCRIPT ) },
    1640             :         { InitializeClass( "zapfchancery",           FAMILY_SCRIPT ) }
    1641       15300 :     };
    1642             : 
    1643       15300 :     OString aFamily = OUStringToOString( rFamily, RTL_TEXTENCODING_ASCII_US );
    1644       15300 :     sal_uInt32 nLower = 0;
    1645       15300 :     sal_uInt32 nUpper = SAL_N_ELEMENTS(pFamilyMatch);
    1646             : 
    1647      102816 :     while( nLower < nUpper )
    1648             :     {
    1649       72522 :         sal_uInt32 nCurrent = (nLower + nUpper) / 2;
    1650       72522 :         const family_t* pHaystack = pFamilyMatch + nCurrent;
    1651             :         sal_Int32  nComparison =
    1652             :             rtl_str_compareIgnoreAsciiCase_WithLength
    1653             :             (
    1654             :              aFamily.getStr(), aFamily.getLength(),
    1655             :              pHaystack->mpName, pHaystack->mnLength
    1656       72522 :              );
    1657             : 
    1658       72522 :         if( nComparison < 0 )
    1659       38862 :             nUpper = nCurrent;
    1660             :         else
    1661       33660 :             if( nComparison > 0 )
    1662       33354 :                 nLower = nCurrent + 1;
    1663             :             else
    1664         306 :                 return pHaystack->meType;
    1665             :     }
    1666             : 
    1667       14994 :     return FAMILY_DONTKNOW;
    1668             : }
    1669             : 
    1670        3386 : OString PrintFontManager::getAfmFile( PrintFont* pFont ) const
    1671             : {
    1672        3386 :     OString aMetricPath;
    1673        3386 :     if( pFont )
    1674             :     {
    1675        3386 :         switch( pFont->m_eType )
    1676             :         {
    1677             :             case fonttype::Type1:
    1678             :             {
    1679        3386 :                 Type1FontFile* pPSFont = static_cast< Type1FontFile* >(pFont);
    1680        3386 :                 aMetricPath = getDirectory( pPSFont->m_nDirectory );
    1681        3386 :                 aMetricPath += "/";
    1682        3386 :                 aMetricPath += pPSFont->m_aMetricFile;
    1683             :             }
    1684        3386 :             break;
    1685           0 :             default: break;
    1686             :         }
    1687             :     }
    1688        3386 :     return aMetricPath;
    1689             : }
    1690             : 
    1691      137363 : OString PrintFontManager::getFontFile( PrintFont* pFont ) const
    1692             : {
    1693      137363 :     OString aPath;
    1694             : 
    1695      137363 :     if( pFont && pFont->m_eType == fonttype::Type1 )
    1696             :     {
    1697       14664 :         Type1FontFile* pPSFont = static_cast< Type1FontFile* >(pFont);
    1698       14664 :         ::boost::unordered_map< int, OString >::const_iterator it = m_aAtomToDir.find( pPSFont->m_nDirectory );
    1699       14664 :         aPath = it->second;
    1700       14664 :         aPath += "/";
    1701       14664 :         aPath += pPSFont->m_aFontFile;
    1702             :     }
    1703      122699 :     else if( pFont && pFont->m_eType == fonttype::TrueType )
    1704             :     {
    1705      122699 :         TrueTypeFontFile* pTTFont = static_cast< TrueTypeFontFile* >(pFont);
    1706      122699 :         ::boost::unordered_map< int, OString >::const_iterator it = m_aAtomToDir.find( pTTFont->m_nDirectory );
    1707      122699 :         aPath = it->second;
    1708      122699 :         aPath += "/";
    1709      122699 :         aPath += pTTFont->m_aFontFile;
    1710             :     }
    1711      137363 :     return aPath;
    1712             : }
    1713             : 
    1714           0 : const OUString& PrintFontManager::getPSName( fontID nFontID ) const
    1715             : {
    1716           0 :     PrintFont* pFont = getFont( nFontID );
    1717           0 :     if( pFont && pFont->m_nPSName == 0 )
    1718             :     {
    1719           0 :         if( pFont->m_eType == fonttype::TrueType )
    1720           0 :             analyzeTrueTypeFile( pFont );
    1721             :     }
    1722             : 
    1723           0 :     return m_pAtoms->getString( ATOM_PSNAME, pFont ? pFont->m_nPSName : INVALID_ATOM );
    1724             : }
    1725             : 
    1726           0 : int PrintFontManager::getFontAscend( fontID nFontID ) const
    1727             : {
    1728           0 :     PrintFont* pFont = getFont( nFontID );
    1729           0 :     if (pFont && pFont->m_nAscend == 0 && pFont->m_nDescend == 0)
    1730             :     {
    1731             :         // might be a truetype font not yet analyzed
    1732           0 :         if( pFont->m_eType == fonttype::TrueType )
    1733           0 :             analyzeTrueTypeFile( pFont );
    1734           0 :         else if( pFont->m_eType == fonttype::Type1 )
    1735           0 :             pFont->readAfmMetrics( m_pAtoms, false, true );
    1736             :     }
    1737           0 :     return pFont ? pFont->m_nAscend : 0;
    1738             : }
    1739             : 
    1740           0 : int PrintFontManager::getFontDescend( fontID nFontID ) const
    1741             : {
    1742           0 :     PrintFont* pFont = getFont( nFontID );
    1743           0 :     if (pFont && pFont->m_nAscend == 0 && pFont->m_nDescend == 0)
    1744             :     {
    1745             :         // might be a truetype font not yet analyzed
    1746           0 :         if( pFont->m_eType == fonttype::TrueType )
    1747           0 :             analyzeTrueTypeFile( pFont );
    1748           0 :         else if( pFont->m_eType == fonttype::Type1 )
    1749           0 :             pFont->readAfmMetrics( m_pAtoms, false, true );
    1750             :     }
    1751           0 :     return pFont ? pFont->m_nDescend : 0;
    1752             : }
    1753             : 
    1754           0 : void PrintFontManager::hasVerticalSubstitutions( fontID nFontID,
    1755             :     const sal_Unicode* pCharacters, int nCharacters, bool* pHasSubst ) const
    1756             : {
    1757           0 :     PrintFont* pFont = getFont( nFontID );
    1758           0 :     if (pFont && pFont->m_nAscend == 0 && pFont->m_nDescend == 0)
    1759             :     {
    1760             :         // might be a truetype font not yet analyzed
    1761           0 :         if( pFont->m_eType == fonttype::TrueType )
    1762           0 :             analyzeTrueTypeFile( pFont );
    1763             :     }
    1764             : 
    1765           0 :     if (!pFont || !pFont->m_bHaveVerticalSubstitutedGlyphs)
    1766           0 :         memset( pHasSubst, 0, sizeof(bool)*nCharacters );
    1767             :     else
    1768             :     {
    1769           0 :         for( int i = 0; i < nCharacters; i++ )
    1770             :         {
    1771           0 :             sal_Unicode code = pCharacters[i];
    1772           0 :             if( ! pFont->m_pMetrics ||
    1773           0 :                 ! ( pFont->m_pMetrics->m_aPages[ code >> 11 ] & ( 1 << ( ( code >> 8 ) & 7 ) ) ) )
    1774           0 :                 pFont->queryMetricPage( code >> 8, m_pAtoms );
    1775           0 :             ::boost::unordered_map< sal_Unicode, bool >::const_iterator it = pFont->m_pMetrics->m_bVerticalSubstitutions.find( code );
    1776           0 :             pHasSubst[i] = it != pFont->m_pMetrics->m_bVerticalSubstitutions.end();
    1777             :         }
    1778             :     }
    1779           0 : }
    1780             : 
    1781           0 : bool PrintFontManager::isFontDownloadingAllowedForPrinting( fontID nFont ) const
    1782             : {
    1783           0 :     static const char* pEnable = getenv( "PSPRINT_ENABLE_TTF_COPYRIGHTAWARENESS" );
    1784           0 :     bool bRet = true;
    1785             : 
    1786           0 :     if( pEnable && *pEnable )
    1787             :     {
    1788           0 :         PrintFont* pFont = getFont( nFont );
    1789           0 :         if( pFont && pFont->m_eType == fonttype::TrueType )
    1790             :         {
    1791           0 :             TrueTypeFontFile* pTTFontFile = static_cast<TrueTypeFontFile*>(pFont);
    1792           0 :             if( pTTFontFile->m_nTypeFlags & TYPEFLAG_INVALID )
    1793             :             {
    1794           0 :                 TrueTypeFont* pTTFont = NULL;
    1795           0 :                 OString aFile = getFontFile( pFont );
    1796           0 :                 if( OpenTTFontFile( aFile.getStr(), pTTFontFile->m_nCollectionEntry, &pTTFont ) == SF_OK )
    1797             :                 {
    1798             :                     // get type flags
    1799             :                     TTGlobalFontInfo aInfo;
    1800           0 :                     GetTTGlobalFontInfo( pTTFont, & aInfo );
    1801           0 :                     pTTFontFile->m_nTypeFlags = (unsigned int)aInfo.typeFlags;
    1802           0 :                     CloseTTFont( pTTFont );
    1803           0 :                 }
    1804             :             }
    1805             : 
    1806           0 :             unsigned int nCopyrightFlags = pTTFontFile->m_nTypeFlags & TYPEFLAG_COPYRIGHT_MASK;
    1807             : 
    1808             :             // http://www.microsoft.com/typography/tt/ttf_spec/ttch02.doc
    1809             :             // Font embedding is allowed if not restricted completely (only bit 1 set).
    1810             :             // Preview&Print (bit 2), Editable (bit 3) or Installable (==0) fonts are ok.
    1811           0 :             bRet = ( nCopyrightFlags & 0x02 ) != 0x02;
    1812             :         }
    1813             :     }
    1814           0 :     return bRet;
    1815             : }
    1816             : 
    1817           0 : bool PrintFontManager::getMetrics( fontID nFontID, const sal_Unicode* pString, int nLen, CharacterMetric* pArray, bool bVertical ) const
    1818             : {
    1819           0 :     PrintFont* pFont = getFont( nFontID );
    1820           0 :     if( ! pFont )
    1821           0 :         return false;
    1822             : 
    1823           0 :     if( ( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
    1824           0 :         || ! pFont->m_pMetrics || pFont->m_pMetrics->isEmpty()
    1825             :         )
    1826             :     {
    1827             :         // might be a font not yet analyzed
    1828           0 :         if( pFont->m_eType == fonttype::Type1 )
    1829           0 :             pFont->readAfmMetrics( m_pAtoms, false, false );
    1830           0 :         else if( pFont->m_eType == fonttype::TrueType )
    1831           0 :             analyzeTrueTypeFile( pFont );
    1832             :     }
    1833             : 
    1834           0 :     for( int i = 0; i < nLen; i++ )
    1835             :     {
    1836           0 :         if( ! pFont->m_pMetrics ||
    1837           0 :             ! ( pFont->m_pMetrics->m_aPages[ pString[i] >> 11 ] & ( 1 << ( ( pString[i] >> 8 ) & 7 ) ) ) )
    1838           0 :             pFont->queryMetricPage( pString[i] >> 8, m_pAtoms );
    1839           0 :         pArray[i].width = pArray[i].height = -1;
    1840           0 :         if( pFont->m_pMetrics )
    1841             :         {
    1842           0 :             int effectiveCode = pString[i];
    1843           0 :             effectiveCode |= bVertical ? 1 << 16 : 0;
    1844             :             ::boost::unordered_map< int, CharacterMetric >::const_iterator it =
    1845           0 :                   pFont->m_pMetrics->m_aMetrics.find( effectiveCode );
    1846             :         // if no vertical metrics are available assume rotated horizontal metrics
    1847           0 :         if( bVertical && (it == pFont->m_pMetrics->m_aMetrics.end()) )
    1848           0 :                   it = pFont->m_pMetrics->m_aMetrics.find( pString[i] );
    1849             :         // the character metrics are in it->second
    1850           0 :             if( it != pFont->m_pMetrics->m_aMetrics.end() )
    1851           0 :                 pArray[ i ] = it->second;
    1852             :         }
    1853             :     }
    1854             : 
    1855           0 :     return true;
    1856             : }
    1857             : 
    1858        8344 : bool PrintFontManager::getMetrics( fontID nFontID, sal_Unicode minCharacter, sal_Unicode maxCharacter, CharacterMetric* pArray, bool bVertical ) const
    1859             : {
    1860             :     OSL_PRECOND(minCharacter <= maxCharacter, "invalid char. range");
    1861        8344 :     if (minCharacter > maxCharacter)
    1862           0 :         return false;
    1863             : 
    1864        8344 :     PrintFont* pFont = getFont( nFontID );
    1865        8344 :     if( ! pFont )
    1866           0 :         return false;
    1867             : 
    1868       16688 :     if( ( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
    1869       16688 :         || ! pFont->m_pMetrics || pFont->m_pMetrics->isEmpty()
    1870             :         )
    1871             :     {
    1872             :         // might be a font not yet analyzed
    1873           0 :         if( pFont->m_eType == fonttype::Type1 )
    1874           0 :             pFont->readAfmMetrics( m_pAtoms, false, false );
    1875           0 :         else if( pFont->m_eType == fonttype::TrueType )
    1876           0 :             analyzeTrueTypeFile( pFont );
    1877             :     }
    1878             : 
    1879        8344 :     sal_Unicode code = minCharacter;
    1880        8344 :     do
    1881             :     {
    1882       16688 :         if( ! pFont->m_pMetrics ||
    1883        8344 :             ! ( pFont->m_pMetrics->m_aPages[ code >> 11 ] & ( 1 << ( ( code >> 8 ) & 7 ) ) ) )
    1884           0 :             pFont->queryMetricPage( code >> 8, m_pAtoms );
    1885        8344 :         pArray[ code - minCharacter ].width     = -1;
    1886        8344 :         pArray[ code - minCharacter ].height    = -1;
    1887        8344 :         if( pFont->m_pMetrics )
    1888             :         {
    1889        8344 :             int effectiveCode = code;
    1890        8344 :             effectiveCode |= bVertical ? 1 << 16 : 0;
    1891             :             ::boost::unordered_map< int, CharacterMetric >::const_iterator it =
    1892        8344 :                   pFont->m_pMetrics->m_aMetrics.find( effectiveCode );
    1893             :             // if no vertical metrics are available assume rotated horizontal metrics
    1894        8344 :             if( bVertical && (it == pFont->m_pMetrics->m_aMetrics.end()) )
    1895           0 :                 it = pFont->m_pMetrics->m_aMetrics.find( code );
    1896             :             // the character metrics are in it->second
    1897        8344 :             if( it != pFont->m_pMetrics->m_aMetrics.end() )
    1898        8344 :                 pArray[ code - minCharacter ] = it->second;
    1899             :         }
    1900        8344 :     } while( code++ != maxCharacter );
    1901             : 
    1902        8344 :     return true;
    1903             : }
    1904             : 
    1905             : // TODO: move most of this stuff into the central font-subsetting code
    1906           0 : bool PrintFontManager::createFontSubset(
    1907             :                                         FontSubsetInfo& rInfo,
    1908             :                                         fontID nFont,
    1909             :                                         const OUString& rOutFile,
    1910             :                                         sal_GlyphId* pGlyphIds,
    1911             :                                         sal_uInt8* pNewEncoding,
    1912             :                                         sal_Int32* pWidths,
    1913             :                                         int nGlyphs,
    1914             :                                         bool bVertical
    1915             :                                         )
    1916             : {
    1917           0 :     PrintFont* pFont = getFont( nFont );
    1918           0 :     if( !pFont )
    1919           0 :         return false;
    1920             : 
    1921           0 :     switch( pFont->m_eType )
    1922             :     {
    1923           0 :         case psp::fonttype::TrueType: rInfo.m_nFontType = FontSubsetInfo::SFNT_TTF; break;
    1924           0 :         case psp::fonttype::Type1: rInfo.m_nFontType = FontSubsetInfo::ANY_TYPE1; break;
    1925             :         default:
    1926           0 :             return false;
    1927             :     }
    1928             :     // TODO: remove when Type1 subsetting gets implemented
    1929           0 :     if( pFont->m_eType != fonttype::TrueType )
    1930           0 :         return false;
    1931             : 
    1932             :     // reshuffle array of requested glyphs to make sure glyph0==notdef
    1933             :     sal_uInt8  pEnc[256];
    1934             :     sal_uInt16 pGID[256];
    1935             :     sal_uInt8  pOldIndex[256];
    1936           0 :     memset( pEnc, 0, sizeof( pEnc ) );
    1937           0 :     memset( pGID, 0, sizeof( pGID ) );
    1938           0 :     memset( pOldIndex, 0, sizeof( pOldIndex ) );
    1939           0 :     if( nGlyphs > 256 )
    1940           0 :         return false;
    1941           0 :     int nChar = 1;
    1942           0 :     for( int i = 0; i < nGlyphs; i++ )
    1943             :     {
    1944           0 :         if( pNewEncoding[i] == 0 )
    1945             :         {
    1946           0 :             pOldIndex[ 0 ] = i;
    1947             :         }
    1948             :         else
    1949             :         {
    1950             :             DBG_ASSERT( !(pGlyphIds[i] & 0x007f0000), "overlong glyph id" );
    1951             :             DBG_ASSERT( (int)pNewEncoding[i] < nGlyphs, "encoding wrong" );
    1952             :             DBG_ASSERT( pEnc[pNewEncoding[i]] == 0 && pGID[pNewEncoding[i]] == 0, "duplicate encoded glyph" );
    1953           0 :             pEnc[ pNewEncoding[i] ] = pNewEncoding[i];
    1954           0 :             pGID[ pNewEncoding[i] ] = (sal_uInt16)pGlyphIds[ i ];
    1955           0 :             pOldIndex[ pNewEncoding[i] ] = i;
    1956           0 :             nChar++;
    1957             :         }
    1958             :     }
    1959           0 :     nGlyphs = nChar; // either input value or increased by one
    1960             : 
    1961             :     // prepare system name for read access for subset source file
    1962             :     // TODO: since this file is usually already mmapped there is no need to open it again
    1963           0 :     const OString aFromFile = getFontFile( pFont );
    1964             : 
    1965           0 :     TrueTypeFont* pTTFont = NULL; // TODO: rename to SfntFont
    1966           0 :     TrueTypeFontFile* pTTFontFile = static_cast< TrueTypeFontFile* >(pFont);
    1967           0 :     if( OpenTTFontFile( aFromFile.getStr(), pTTFontFile->m_nCollectionEntry, &pTTFont ) != SF_OK )
    1968           0 :         return false;
    1969             : 
    1970             :     // prepare system name for write access for subset file target
    1971           0 :     OUString aSysPath;
    1972           0 :     if( osl_File_E_None != osl_getSystemPathFromFileURL( rOutFile.pData, &aSysPath.pData ) )
    1973           0 :         return false;
    1974           0 :     const rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
    1975           0 :     const OString aToFile( OUStringToOString( aSysPath, aEncoding ) );
    1976             : 
    1977             :     // do CFF subsetting if possible
    1978           0 :     int nCffLength = 0;
    1979           0 :     const sal_uInt8* pCffBytes = NULL;
    1980           0 :     if( GetSfntTable( pTTFont, O_CFF, &pCffBytes, &nCffLength ) )
    1981             :     {
    1982           0 :         rInfo.LoadFont( FontSubsetInfo::CFF_FONT, pCffBytes, nCffLength );
    1983             : #if 1 // TODO: remove 16bit->long conversion when related methods handle non-16bit glyphids
    1984             :         sal_GlyphId aRequestedGlyphIds[256];
    1985           0 :         for( int i = 0; i < nGlyphs; ++i )
    1986           0 :             aRequestedGlyphIds[i] = pGID[i];
    1987             : #endif
    1988             :         // create subset file at requested path
    1989           0 :         FILE* pOutFile = fopen( aToFile.getStr(), "wb" );
    1990             :         // create font subset
    1991           0 :         const char* pGlyphSetName = NULL; // TODO: better name?
    1992             :         const bool bOK = rInfo.CreateFontSubset(
    1993             :             FontSubsetInfo::TYPE1_PFB,
    1994             :             pOutFile, pGlyphSetName,
    1995           0 :             aRequestedGlyphIds, pEnc, nGlyphs, pWidths );
    1996           0 :         fclose( pOutFile );
    1997             :         // cleanup before early return
    1998           0 :         CloseTTFont( pTTFont );
    1999           0 :         return bOK;
    2000             :     }
    2001             : 
    2002             :     // do TTF->Type42 or Type3 subsetting
    2003             :     // fill in font info
    2004           0 :     psp::PrintFontInfo aFontInfo;
    2005           0 :     if( ! getFontInfo( nFont, aFontInfo ) )
    2006           0 :         return false;
    2007             : 
    2008           0 :     rInfo.m_nAscent     = aFontInfo.m_nAscend;
    2009           0 :     rInfo.m_nDescent    = aFontInfo.m_nDescend;
    2010           0 :     rInfo.m_aPSName     = getPSName( nFont );
    2011             : 
    2012             :     int xMin, yMin, xMax, yMax;
    2013           0 :     getFontBoundingBox( nFont, xMin, yMin, xMax, yMax );
    2014           0 :     rInfo.m_aFontBBox   = Rectangle( Point( xMin, yMin ), Size( xMax-xMin, yMax-yMin ) );
    2015           0 :     rInfo.m_nCapHeight  = yMax; // Well ...
    2016             : 
    2017             :     // fill in glyph advance widths
    2018             :     TTSimpleGlyphMetrics* pMetrics = GetTTSimpleGlyphMetrics( pTTFont,
    2019             :                                                               pGID,
    2020             :                                                               nGlyphs,
    2021           0 :                                                               bVertical );
    2022           0 :     if( pMetrics )
    2023             :     {
    2024           0 :         for( int i = 0; i < nGlyphs; i++ )
    2025           0 :             pWidths[pOldIndex[i]] = pMetrics[i].adv;
    2026           0 :         free( pMetrics );
    2027             :     }
    2028             :     else
    2029             :     {
    2030           0 :         CloseTTFont( pTTFont );
    2031           0 :         return false;
    2032             :     }
    2033             : 
    2034             :     bool bSuccess = ( SF_OK == CreateTTFromTTGlyphs( pTTFont,
    2035             :                                                      aToFile.getStr(),
    2036             :                                                      pGID,
    2037             :                                                      pEnc,
    2038             :                                                      nGlyphs,
    2039             :                                                      0,
    2040             :                                                      NULL,
    2041           0 :                                                      0 ) );
    2042           0 :     CloseTTFont( pTTFont );
    2043             : 
    2044           0 :     return bSuccess;
    2045             : }
    2046             : 
    2047           0 : void PrintFontManager::getGlyphWidths( fontID nFont,
    2048             :                                        bool bVertical,
    2049             :                                        std::vector< sal_Int32 >& rWidths,
    2050             :                                        std::map< sal_Unicode, sal_uInt32 >& rUnicodeEnc )
    2051             : {
    2052           0 :     PrintFont* pFont = getFont( nFont );
    2053           0 :     if( !pFont ||
    2054           0 :         (pFont->m_eType != fonttype::TrueType && pFont->m_eType != fonttype::Type1) )
    2055           0 :         return;
    2056           0 :     if( pFont->m_eType == fonttype::TrueType )
    2057             :     {
    2058           0 :         TrueTypeFont* pTTFont = NULL;
    2059           0 :         TrueTypeFontFile* pTTFontFile = static_cast< TrueTypeFontFile* >(pFont);
    2060           0 :         OString aFromFile = getFontFile( pFont );
    2061           0 :         if( OpenTTFontFile( aFromFile.getStr(), pTTFontFile->m_nCollectionEntry, &pTTFont ) != SF_OK )
    2062           0 :             return;
    2063           0 :         int nGlyphs = GetTTGlyphCount( pTTFont );
    2064           0 :         if( nGlyphs > 0 )
    2065             :         {
    2066           0 :             rWidths.resize(nGlyphs);
    2067           0 :             std::vector<sal_uInt16> aGlyphIds(nGlyphs);
    2068           0 :             for( int i = 0; i < nGlyphs; i++ )
    2069           0 :                 aGlyphIds[i] = sal_uInt16(i);
    2070             :             TTSimpleGlyphMetrics* pMetrics = GetTTSimpleGlyphMetrics( pTTFont,
    2071           0 :                                                                       &aGlyphIds[0],
    2072             :                                                                       nGlyphs,
    2073           0 :                                                                       bVertical );
    2074           0 :             if( pMetrics )
    2075             :             {
    2076           0 :                 for( int i = 0; i< nGlyphs; i++ )
    2077           0 :                     rWidths[i] = pMetrics[i].adv;
    2078           0 :                 free( pMetrics );
    2079           0 :                 rUnicodeEnc.clear();
    2080             :             }
    2081             : 
    2082             :             // fill the unicode map
    2083             :             // TODO: isn't this map already available elsewhere in the fontmanager?
    2084           0 :             const sal_uInt8* pCmapData = NULL;
    2085           0 :             int nCmapSize = 0;
    2086           0 :             if( GetSfntTable( pTTFont, O_cmap, &pCmapData, &nCmapSize ) )
    2087             :             {
    2088           0 :                 CmapResult aCmapResult;
    2089           0 :                 if( ParseCMAP( pCmapData, nCmapSize, aCmapResult ) )
    2090             :                 {
    2091           0 :                     FontCharMapPtr pCharMap( new FontCharMap(aCmapResult) );
    2092           0 :                     for( sal_uInt32 cOld = 0;;)
    2093             :                     {
    2094             :                         // get next unicode covered by font
    2095           0 :                         const sal_uInt32 c = pCharMap->GetNextChar( cOld );
    2096           0 :                         if( c == cOld )
    2097           0 :                             break;
    2098           0 :                         cOld = c;
    2099             : #if 1 // TODO: remove when sal_Unicode covers all of unicode
    2100           0 :                         if( c > (sal_Unicode)~0 )
    2101           0 :                             break;
    2102             : #endif
    2103             :                         // get the matching glyph index
    2104           0 :                         const sal_GlyphId aGlyphId = pCharMap->GetGlyphIndex( c );
    2105             :                         // update the requested map
    2106           0 :                         rUnicodeEnc[ (sal_Unicode)c ] = aGlyphId;
    2107           0 :                     }
    2108             : 
    2109           0 :                     pCharMap = 0;
    2110             :                 }
    2111           0 :             }
    2112             :         }
    2113           0 :         CloseTTFont( pTTFont );
    2114             :     }
    2115           0 :     else if( pFont->m_eType == fonttype::Type1 )
    2116             :     {
    2117           0 :         if( ! pFont->m_aEncodingVector.size() )
    2118           0 :             pFont->readAfmMetrics( m_pAtoms, true, true );
    2119           0 :         if( pFont->m_pMetrics )
    2120             :         {
    2121           0 :             rUnicodeEnc.clear();
    2122           0 :             rWidths.clear();
    2123           0 :             rWidths.reserve( pFont->m_pMetrics->m_aMetrics.size() );
    2124           0 :             for( boost::unordered_map< int, CharacterMetric >::const_iterator it =
    2125           0 :                  pFont->m_pMetrics->m_aMetrics.begin();
    2126           0 :                  it != pFont->m_pMetrics->m_aMetrics.end(); ++it )
    2127             :             {
    2128           0 :                 if( (it->first & 0x00010000) == 0 || bVertical )
    2129             :                 {
    2130           0 :                     rUnicodeEnc[ sal_Unicode(it->first & 0x0000ffff) ] = sal_uInt32(rWidths.size());
    2131           0 :                     rWidths.push_back( it->second.width );
    2132             :                 }
    2133             :             }
    2134             :         }
    2135             :     }
    2136             : }
    2137             : 
    2138           0 : const std::map< sal_Unicode, sal_Int32 >* PrintFontManager::getEncodingMap( fontID nFont, const std::map< sal_Unicode, OString >** pNonEncoded ) const
    2139             : {
    2140           0 :     PrintFont* pFont = getFont( nFont );
    2141           0 :     if( !pFont || pFont->m_eType != fonttype::Type1 )
    2142           0 :         return NULL;
    2143             : 
    2144           0 :     if( ! pFont->m_aEncodingVector.size() )
    2145           0 :         pFont->readAfmMetrics( m_pAtoms, true, true );
    2146             : 
    2147           0 :     if( pNonEncoded )
    2148           0 :         *pNonEncoded = pFont->m_aNonEncoded.size() ? &pFont->m_aNonEncoded : NULL;
    2149             : 
    2150           0 :     return pFont->m_aEncodingVector.size() ? &pFont->m_aEncodingVector : NULL;
    2151             : }
    2152             : 
    2153           0 : std::list< OString > PrintFontManager::getAdobeNameFromUnicode( sal_Unicode aChar ) const
    2154             : {
    2155             :     std::pair< boost::unordered_multimap< sal_Unicode, OString >::const_iterator,
    2156             :         boost::unordered_multimap< sal_Unicode, OString >::const_iterator > range
    2157           0 :         =  m_aUnicodeToAdobename.equal_range( aChar );
    2158             : 
    2159           0 :     std::list< OString > aRet;
    2160           0 :     for( ; range.first != range.second; ++range.first )
    2161           0 :         aRet.push_back( range.first->second );
    2162             : 
    2163           0 :     if( aRet.begin() == aRet.end() && aChar != 0 )
    2164             :     {
    2165             :         sal_Char aBuf[8];
    2166           0 :         sal_Int32 nChars = snprintf( (char*)aBuf, sizeof( aBuf ), "uni%.4hX", aChar );
    2167           0 :         aRet.push_back( OString( aBuf, nChars ) );
    2168             :     }
    2169             : 
    2170           0 :     return aRet;
    2171             : }
    2172             : 
    2173        1124 : std::list< sal_Unicode >  PrintFontManager::getUnicodeFromAdobeName( const OString& rName ) const
    2174             : {
    2175             :     std::pair< boost::unordered_multimap< OString, sal_Unicode, OStringHash >::const_iterator,
    2176             :         boost::unordered_multimap< OString, sal_Unicode, OStringHash >::const_iterator > range
    2177        1124 :         =  m_aAdobenameToUnicode.equal_range( rName );
    2178             : 
    2179        1124 :     std::list< sal_Unicode > aRet;
    2180        2056 :     for( ; range.first != range.second; ++range.first )
    2181         932 :         aRet.push_back( range.first->second );
    2182             : 
    2183        1124 :     if( aRet.begin() == aRet.end() )
    2184             :     {
    2185         214 :         if( rName.getLength() == 7 && rName.startsWith( "uni" ) )
    2186             :         {
    2187         214 :             sal_Unicode aCode = (sal_Unicode)rName.copy( 3 ).toUInt32( 16 );
    2188         214 :             aRet.push_back( aCode );
    2189             :         }
    2190             :     }
    2191             : 
    2192        1124 :     return aRet;
    2193        1233 : }
    2194             : 
    2195             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10