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

Generated by: LCOV version 1.11