LCOV - code coverage report
Current view: top level - vcl/generic/fontmanager - fontconfig.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 366 524 69.8 %
Date: 2012-08-25 Functions: 24 30 80.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 306 693 44.2 %

           Branch data     Line data    Source code
       1                 :            : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2                 :            : /*************************************************************************
       3                 :            :  *
       4                 :            :  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       5                 :            :  *
       6                 :            :  * Copyright 2000, 2010 Oracle and/or its affiliates.
       7                 :            :  *
       8                 :            :  * OpenOffice.org - a multi-platform office productivity suite
       9                 :            :  *
      10                 :            :  * This file is part of OpenOffice.org.
      11                 :            :  *
      12                 :            :  * OpenOffice.org is free software: you can redistribute it and/or modify
      13                 :            :  * it under the terms of the GNU Lesser General Public License version 3
      14                 :            :  * only, as published by the Free Software Foundation.
      15                 :            :  *
      16                 :            :  * OpenOffice.org is distributed in the hope that it will be useful,
      17                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      18                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      19                 :            :  * GNU Lesser General Public License version 3 for more details
      20                 :            :  * (a copy is included in the LICENSE file that accompanied this code).
      21                 :            :  *
      22                 :            :  * You should have received a copy of the GNU Lesser General Public License
      23                 :            :  * version 3 along with OpenOffice.org.  If not, see
      24                 :            :  * <http://www.openoffice.org/license.html>
      25                 :            :  * for a copy of the LGPLv3 License.
      26                 :            :  *
      27                 :            :  ************************************************************************/
      28                 :            : 
      29                 :            : 
      30                 :            : #include "fontcache.hxx"
      31                 :            : #include "impfont.hxx"
      32                 :            : #include "vcl/fontmanager.hxx"
      33                 :            : #include "vcl/vclenum.hxx"
      34                 :            : #include "outfont.hxx"
      35                 :            : #include <i18npool/mslangid.hxx>
      36                 :            : 
      37                 :            : using namespace psp;
      38                 :            : 
      39                 :            : #include <fontconfig/fontconfig.h>
      40                 :            : #include <ft2build.h>
      41                 :            : #include <fontconfig/fcfreetype.h>
      42                 :            : // allow compile on baseline (currently with fontconfig 2.2.0)
      43                 :            : #ifndef FC_WEIGHT_BOOK      // TODO: remove when baseline moves to fc>=2.2.1
      44                 :            :     #define FC_WEIGHT_BOOK 75
      45                 :            : #endif
      46                 :            : #ifndef FC_EMBEDDED_BITMAP  // TODO: remove when baseline moves to fc>=2.3.92
      47                 :            :     #define FC_EMBEDDED_BITMAP "embeddedbitmap"
      48                 :            : #endif
      49                 :            : #ifndef FC_FAMILYLANG       // TODO: remove when baseline moves to fc>=2.2.97
      50                 :            :     #define FC_FAMILYLANG "familylang"
      51                 :            : #endif
      52                 :            : #ifndef FC_CAPABILITY       // TODO: remove when baseline moves to fc>=2.2.97
      53                 :            :     #define FC_CAPABILITY "capability"
      54                 :            : #endif
      55                 :            : #ifndef FC_STYLELANG        // TODO: remove when baseline moves to fc>=2.2.97
      56                 :            :     #define FC_STYLELANG "stylelang"
      57                 :            : #endif
      58                 :            : #ifndef FC_HINT_STYLE       // TODO: remove when baseline moves to fc>=2.2.91
      59                 :            :     #define FC_HINT_STYLE  "hintstyle"
      60                 :            :     #define FC_HINT_NONE   0
      61                 :            :     #define FC_HINT_SLIGHT 1
      62                 :            :     #define FC_HINT_MEDIUM 2
      63                 :            :     #define FC_HINT_FULL   3
      64                 :            : #endif
      65                 :            : #ifndef FC_FT_FACE
      66                 :            :     #define FC_FT_FACE "ftface"
      67                 :            : #endif
      68                 :            : #ifndef FC_EMBOLDEN
      69                 :            :     #define FC_EMBOLDEN "embolden"
      70                 :            : #endif
      71                 :            : #ifndef FC_MATRIX
      72                 :            :     #define FC_MATRIX "matrix"
      73                 :            : #endif
      74                 :            : #ifndef FC_FONTFORMAT
      75                 :            :     #define FC_FONTFORMAT "fontformat"
      76                 :            : #endif
      77                 :            : 
      78                 :            : #include <cstdio>
      79                 :            : #include <cstdarg>
      80                 :            : 
      81                 :            : #include "unotools/atom.hxx"
      82                 :            : 
      83                 :            : #include "osl/module.h"
      84                 :            : #include "osl/thread.h"
      85                 :            : #include "osl/process.h"
      86                 :            : 
      87                 :            : #include "rtl/ustrbuf.hxx"
      88                 :            : #include "rtl/locale.hxx"
      89                 :            : 
      90                 :            : #include "sal/alloca.h"
      91                 :            : 
      92                 :            : #include <utility>
      93                 :            : #include <algorithm>
      94                 :            : 
      95                 :            : using namespace osl;
      96                 :            : using ::rtl::OUString;
      97                 :            : using ::rtl::OUStringBuffer;
      98                 :            : using ::rtl::OString;
      99                 :            : 
     100                 :            : namespace
     101                 :            : {
     102                 :            :     typedef std::pair<FcChar8*, FcChar8*> lang_and_element;
     103                 :            : }
     104                 :            : 
     105                 :            : class FontCfgWrapper
     106                 :            : {
     107                 :            :     FcFontSet* m_pOutlineSet;
     108                 :            : 
     109                 :            :     void addFontSet( FcSetName );
     110                 :            : 
     111                 :            :     FontCfgWrapper();
     112                 :            :     ~FontCfgWrapper();
     113                 :            : 
     114                 :            : public:
     115                 :            :     static FontCfgWrapper& get();
     116                 :            :     static void release();
     117                 :            : 
     118                 :            :     FcFontSet* getFontSet();
     119                 :            : 
     120                 :            : public:
     121                 :            :     FcResult LocalizedElementFromPattern(FcPattern* pPattern, FcChar8 **family,
     122                 :            :                                          const char *elementtype, const char *elementlangtype);
     123                 :            : //to-do, make private and add some cleanish accessor methods
     124                 :            :     boost::unordered_map< rtl::OString, rtl::OString, rtl::OStringHash > m_aFontNameToLocalized;
     125                 :            :     boost::unordered_map< rtl::OString, rtl::OString, rtl::OStringHash > m_aLocalizedToCanonical;
     126                 :            : private:
     127                 :            :     void cacheLocalizedFontNames(const FcChar8 *origfontname, const FcChar8 *bestfontname, const std::vector< lang_and_element > &lang_and_elements);
     128                 :            : };
     129                 :            : 
     130                 :        236 : FontCfgWrapper::FontCfgWrapper()
     131 [ +  - ][ +  - ]:        236 :     : m_pOutlineSet( NULL )
     132                 :            : {
     133         [ +  - ]:        236 :     FcInit();
     134                 :        236 : }
     135                 :            : 
     136                 :        472 : void FontCfgWrapper::addFontSet( FcSetName eSetName )
     137                 :            : {
     138                 :            :     /*
     139                 :            :       add only acceptable outlined fonts to our config,
     140                 :            :       for future fontconfig use
     141                 :            :     */
     142                 :        472 :     FcFontSet* pOrig = FcConfigGetFonts( FcConfigGetCurrent(), eSetName );
     143         [ +  + ]:        472 :     if( !pOrig )
     144                 :        472 :         return;
     145                 :            : 
     146                 :            :     // filter the font sets to remove obsolete faces
     147         [ +  + ]:      37007 :     for( int i = 0; i < pOrig->nfont; ++i )
     148                 :            :     {
     149                 :      36538 :         FcPattern* pPattern = pOrig->fonts[i];
     150                 :            :         // #i115131# ignore non-outline fonts
     151                 :      36538 :         FcBool bOutline = FcFalse;
     152         [ +  - ]:      36538 :         FcResult eOutRes = FcPatternGetBool( pPattern, FC_OUTLINE, 0, &bOutline );
     153 [ +  - ][ -  + ]:      36538 :         if( (eOutRes != FcResultMatch) || (bOutline == FcFalse) )
     154                 :          0 :             continue;
     155         [ +  - ]:      36538 :         FcPatternReference( pPattern );
     156         [ +  - ]:      36538 :         FcFontSetAdd( m_pOutlineSet, pPattern );
     157                 :            :     }
     158                 :            : 
     159                 :            :     // TODO?: FcFontSetDestroy( pOrig );
     160                 :            : }
     161                 :            : 
     162                 :            : namespace
     163                 :            : {
     164                 :     315732 :     int compareFontNames(const FcPattern *a, const FcPattern *b)
     165                 :            :     {
     166                 :     315732 :         FcChar8 *pNameA=NULL, *pNameB=NULL;
     167                 :            : 
     168         [ +  - ]:     315732 :         int nHaveA = FcPatternGetString(a, FC_FAMILY, 0, &pNameA) == FcResultMatch;
     169         [ +  - ]:     315732 :         int nHaveB = FcPatternGetString(b, FC_FAMILY, 0, &pNameB) == FcResultMatch;
     170                 :            : 
     171 [ +  - ][ +  - ]:     315732 :         if (nHaveA && nHaveB)
     172                 :     315732 :             return strcmp((const char*)pNameA, (const char*)pNameB);
     173                 :            : 
     174                 :     315732 :         return nHaveA - nHaveB;
     175                 :            :     }
     176                 :            : 
     177                 :            :     //Sort fonts so that fonts with the same family name are side-by-side, with
     178                 :            :     //those with higher version numbers first
     179                 :            :     class SortFont : public ::std::binary_function< const FcPattern*, const FcPattern*, bool >
     180                 :            :     {
     181                 :            :     public:
     182                 :     279430 :         bool operator()(const FcPattern *a, const FcPattern *b)
     183                 :            :         {
     184         [ +  - ]:     279430 :             int comp = compareFontNames(a, b);
     185         [ +  + ]:     279430 :             if (comp != 0)
     186                 :     232382 :                 return comp < 0;
     187                 :            : 
     188                 :      47048 :             int nVersionA=0, nVersionB=0;
     189                 :            : 
     190         [ +  - ]:      47048 :             int nHaveA = FcPatternGetInteger(a, FC_FONTVERSION, 0, &nVersionA) == FcResultMatch;
     191         [ +  - ]:      47048 :             int nHaveB = FcPatternGetInteger(b, FC_FONTVERSION, 0, &nVersionB) == FcResultMatch;
     192                 :            : 
     193 [ +  - ][ +  - ]:      47048 :             if (nHaveA && nHaveB)
     194                 :      47048 :                 return nVersionA > nVersionB;
     195                 :            : 
     196                 :     279430 :             return nHaveA > nHaveB;
     197                 :            :         }
     198                 :            :     };
     199                 :            : 
     200                 :            :     //See fdo#30729 for where an old opensymbol installed system-wide can
     201                 :            :     //clobber the new opensymbol installed locally
     202                 :            :     //
     203                 :            :     //See if this font is a duplicate with equal attributes which has already been
     204                 :            :     //inserted, or if it an older version of an inserted fonts. Depends on FcFontSet
     205                 :            :     //on being sorted with SortFont
     206                 :      36538 :     bool isPreviouslyDuplicateOrObsoleted(FcFontSet *pFSet, int i)
     207                 :            :     {
     208         [ +  + ]:      36538 :         if (i == 0)
     209                 :        236 :             return false;
     210                 :            : 
     211                 :      36302 :         const FcPattern *a = pFSet->fonts[i];
     212                 :      36302 :         const FcPattern *b = pFSet->fonts[i-1];
     213                 :            : 
     214         [ +  + ]:      36302 :         if (compareFontNames(a, b) != 0)
     215                 :      12984 :             return false;
     216                 :            : 
     217                 :      23318 :         FcPattern* pTestPatternA = FcPatternDuplicate(a);
     218                 :      23318 :         FcPatternDel(pTestPatternA, FC_FILE);
     219                 :      23318 :         FcPatternDel(pTestPatternA, FC_CHARSET);
     220                 :      23318 :         FcPatternDel(pTestPatternA, FC_CAPABILITY);
     221                 :      23318 :         FcPatternDel(pTestPatternA, FC_FONTVERSION);
     222                 :            : 
     223                 :      23318 :         FcPattern* pTestPatternB = FcPatternDuplicate(b);
     224                 :      23318 :         FcPatternDel(pTestPatternB, FC_FILE);
     225                 :      23318 :         FcPatternDel(pTestPatternB, FC_CHARSET);
     226                 :      23318 :         FcPatternDel(pTestPatternB, FC_CAPABILITY);
     227                 :      23318 :         FcPatternDel(pTestPatternB, FC_FONTVERSION);
     228                 :            : 
     229                 :      23318 :         bool bIsDup = FcPatternEqual(pTestPatternA, pTestPatternB);
     230                 :            : 
     231                 :      23318 :         FcPatternDestroy(pTestPatternB);
     232                 :      23318 :         FcPatternDestroy(pTestPatternA);
     233                 :            : 
     234                 :      36538 :         return bIsDup;
     235                 :            :     }
     236                 :            : }
     237                 :            : 
     238                 :       8985 : FcFontSet* FontCfgWrapper::getFontSet()
     239                 :            : {
     240         [ +  + ]:       8985 :     if( !m_pOutlineSet )
     241                 :            :     {
     242                 :        236 :         m_pOutlineSet = FcFontSetCreate();
     243                 :        236 :         addFontSet( FcSetSystem );
     244         [ +  - ]:        236 :         if( FcGetVersion() > 20400 ) // #i85462# prevent crashes
     245                 :        236 :             addFontSet( FcSetApplication );
     246                 :            : 
     247         [ +  - ]:        236 :         ::std::sort(m_pOutlineSet->fonts,m_pOutlineSet->fonts+m_pOutlineSet->nfont,SortFont());
     248                 :            :     }
     249                 :            : 
     250                 :       8985 :     return m_pOutlineSet;
     251                 :            : }
     252                 :            : 
     253         [ +  - ]:        236 : FontCfgWrapper::~FontCfgWrapper()
     254                 :            : {
     255         [ +  - ]:        236 :     if( m_pOutlineSet )
     256         [ +  - ]:        236 :         FcFontSetDestroy( m_pOutlineSet );
     257                 :            :     //To-Do: get gtk vclplug smoketest to pass
     258                 :            :     //FcFini();
     259                 :        236 : }
     260                 :            : 
     261                 :            : static FontCfgWrapper* pOneInstance = NULL;
     262                 :            : 
     263                 :       9221 : FontCfgWrapper& FontCfgWrapper::get()
     264                 :            : {
     265         [ +  + ]:       9221 :     if( ! pOneInstance )
     266         [ +  - ]:        236 :         pOneInstance = new FontCfgWrapper();
     267                 :       9221 :     return *pOneInstance;
     268                 :            : }
     269                 :            : 
     270                 :        236 : void FontCfgWrapper::release()
     271                 :            : {
     272         [ +  - ]:        236 :     if( pOneInstance )
     273                 :            :     {
     274         [ +  - ]:        236 :         delete pOneInstance;
     275                 :        236 :         pOneInstance = NULL;
     276                 :            :     }
     277                 :        236 : }
     278                 :            : 
     279                 :            : namespace
     280                 :            : {
     281                 :            :     class localizedsorter
     282                 :            :     {
     283                 :            :             rtl::OLocale maLoc;
     284                 :            :         public:
     285                 :      54668 :             localizedsorter(rtl_Locale* pLoc) : maLoc(pLoc) {}
     286                 :            :             FcChar8* bestname(const std::vector<lang_and_element> &elements);
     287                 :            :     };
     288                 :            : 
     289                 :      54668 :     FcChar8* localizedsorter::bestname(const std::vector<lang_and_element> &elements)
     290                 :            :     {
     291         [ +  - ]:      54668 :         FcChar8* candidate = elements.begin()->second;
     292         [ +  - ]:      54668 :         rtl::OString sLangMatch(rtl::OUStringToOString(maLoc.getLanguage().toAsciiLowerCase(), RTL_TEXTENCODING_UTF8));
     293                 :      54668 :         rtl::OString sFullMatch = sLangMatch;
     294                 :      54668 :         sFullMatch += OString('-');
     295         [ +  - ]:      54668 :         sFullMatch += rtl::OUStringToOString(maLoc.getCountry().toAsciiLowerCase(), RTL_TEXTENCODING_UTF8);
     296                 :            : 
     297                 :      54668 :         std::vector<lang_and_element>::const_iterator aEnd = elements.end();
     298                 :      54668 :         bool alreadyclosematch = false;
     299                 :      54668 :         bool found_fallback_englishname = false;
     300 [ +  - ][ +  - ]:     119338 :         for( std::vector<lang_and_element>::const_iterator aIter = elements.begin(); aIter != aEnd; ++aIter )
                 [ +  + ]
     301                 :            :         {
     302         [ +  - ]:      64670 :             const char *pLang = (const char*)aIter->first;
     303         [ -  + ]:      64670 :             if( rtl_str_compare( pLang, sFullMatch.getStr() ) == 0)
     304                 :            :             {
     305                 :            :                 // both language and country match
     306         [ #  # ]:          0 :                 candidate = aIter->second;
     307                 :          0 :                 break;
     308                 :            :             }
     309         [ +  + ]:      64670 :             else if( alreadyclosematch )
     310                 :            :             {
     311                 :            :                 // current candidate matches lang of lang-TERRITORY
     312                 :            :                 // override candidate only if there is a full match
     313                 :       9294 :                 continue;
     314                 :            :             }
     315         [ +  + ]:      55376 :             else if( rtl_str_compare( pLang, sLangMatch.getStr()) == 0)
     316                 :            :             {
     317                 :            :                 // just the language matches
     318         [ +  - ]:      53960 :                 candidate = aIter->second;
     319                 :      53960 :                 alreadyclosematch = true;
     320                 :            :             }
     321         [ -  + ]:       1416 :             else if( found_fallback_englishname )
     322                 :            :             {
     323                 :            :                 // already found an english fallback, don't override candidate
     324                 :            :                 // unless there is a better language match
     325                 :          0 :                 continue;
     326                 :            :             }
     327         [ -  + ]:       1416 :             else if( rtl_str_compare( pLang, "en") == 0)
     328                 :            :             {
     329                 :            :                 // select a fallback candidate of the first english element
     330                 :            :                 // name
     331         [ #  # ]:          0 :                 candidate = aIter->second;
     332                 :          0 :                 found_fallback_englishname = true;
     333                 :            :             }
     334                 :            :         }
     335                 :      54668 :         return candidate;
     336                 :            :     }
     337                 :            : }
     338                 :            : 
     339                 :            : //Set up maps to quickly map between a fonts best UI name and all the rest of its names, and vice versa
     340                 :      27334 : void FontCfgWrapper::cacheLocalizedFontNames(const FcChar8 *origfontname, const FcChar8 *bestfontname,
     341                 :            :     const std::vector< lang_and_element > &lang_and_elements)
     342                 :            : {
     343                 :      27334 :     std::vector<lang_and_element>::const_iterator aEnd = lang_and_elements.end();
     344 [ +  - ][ +  - ]:      61046 :     for (std::vector<lang_and_element>::const_iterator aIter = lang_and_elements.begin(); aIter != aEnd; ++aIter)
                 [ +  + ]
     345                 :            :     {
     346         [ +  - ]:      33712 :         const char *candidate = (const char*)(aIter->second);
     347         [ +  + ]:      33712 :         if (rtl_str_compare(candidate, (const char*)bestfontname) != 0)
     348         [ +  - ]:       6378 :             m_aFontNameToLocalized[OString(candidate)] = OString((const char*)bestfontname);
     349                 :            :     }
     350         [ +  + ]:      27334 :     if (rtl_str_compare((const char*)origfontname, (const char*)bestfontname) != 0)
     351         [ +  - ]:        708 :         m_aLocalizedToCanonical[OString((const char*)bestfontname)] = OString((const char*)origfontname);
     352                 :      27334 : }
     353                 :            : 
     354                 :      73076 : FcResult FontCfgWrapper::LocalizedElementFromPattern(FcPattern* pPattern, FcChar8 **element,
     355                 :            :                                                      const char *elementtype, const char *elementlangtype)
     356                 :            : {                                                /* e. g.:      ^ FC_FAMILY              ^ FC_FAMILYLANG */
     357                 :            :     FcChar8 *origelement;
     358         [ +  - ]:      73076 :     FcResult eElementRes = FcPatternGetString( pPattern, elementtype, 0, &origelement );
     359                 :      73076 :     *element = origelement;
     360                 :            : 
     361         [ +  - ]:      73076 :     if( eElementRes == FcResultMatch)
     362                 :            :     {
     363                 :      73076 :         FcChar8* elementlang = NULL;
     364 [ +  - ][ +  + ]:      73076 :         if (FcPatternGetString( pPattern, elementlangtype, 0, &elementlang ) == FcResultMatch)
     365                 :            :         {
     366         [ +  - ]:      54668 :             std::vector< lang_and_element > lang_and_elements;
     367 [ +  - ][ +  - ]:      54668 :             lang_and_elements.push_back(lang_and_element(elementlang, *element));
     368                 :      54668 :             int k = 1;
     369                 :      10002 :             while (1)
     370                 :            :             {
     371 [ +  - ][ +  + ]:      64670 :                 if (FcPatternGetString( pPattern, elementlangtype, k, &elementlang ) != FcResultMatch)
     372                 :      54668 :                     break;
     373 [ +  - ][ -  + ]:      10002 :                 if (FcPatternGetString( pPattern, elementtype, k, element ) != FcResultMatch)
     374                 :          0 :                     break;
     375 [ +  - ][ +  - ]:      10002 :                 lang_and_elements.push_back(lang_and_element(elementlang, *element));
     376                 :      10002 :                 ++k;
     377                 :            :             }
     378                 :            : 
     379                 :            :             //possible to-do, sort by UILocale instead of process locale
     380                 :            :             rtl_Locale* pLoc;
     381         [ +  - ]:      54668 :             osl_getProcessLocale(&pLoc);
     382                 :      54668 :             localizedsorter aSorter(pLoc);
     383         [ +  - ]:      54668 :             *element = aSorter.bestname(lang_and_elements);
     384                 :            : 
     385                 :            :             //if this element is a fontname, map the other names to this best-name
     386         [ +  + ]:      54668 :             if (rtl_str_compare(elementtype, FC_FAMILY) == 0)
     387         [ +  - ]:      73076 :                 cacheLocalizedFontNames(origelement, *element, lang_and_elements);
     388                 :            :         }
     389                 :            :     }
     390                 :            : 
     391                 :      73076 :     return eElementRes;
     392                 :            : }
     393                 :            : 
     394                 :            : /*
     395                 :            :  * PrintFontManager::initFontconfig
     396                 :            :  */
     397                 :        236 : void PrintFontManager::initFontconfig()
     398                 :            : {
     399                 :        236 :     FontCfgWrapper::get();
     400                 :        236 : }
     401                 :            : 
     402                 :            : namespace
     403                 :            : {
     404                 :      43711 :     FontWeight convertWeight(int weight)
     405                 :            :     {
     406                 :            :         // set weight
     407         [ -  + ]:      43711 :         if( weight <= FC_WEIGHT_THIN )
     408                 :          0 :             return WEIGHT_THIN;
     409         [ +  + ]:      43711 :         else if( weight <= FC_WEIGHT_ULTRALIGHT )
     410                 :        822 :             return WEIGHT_ULTRALIGHT;
     411         [ +  + ]:      42889 :         else if( weight <= FC_WEIGHT_LIGHT )
     412                 :        950 :             return WEIGHT_LIGHT;
     413         [ +  + ]:      41939 :         else if( weight <= FC_WEIGHT_BOOK )
     414                 :        472 :             return WEIGHT_SEMILIGHT;
     415         [ +  + ]:      41467 :         else if( weight <= FC_WEIGHT_NORMAL )
     416                 :      23299 :             return WEIGHT_NORMAL;
     417         [ +  + ]:      18168 :         else if( weight <= FC_WEIGHT_MEDIUM )
     418                 :       2303 :             return WEIGHT_MEDIUM;
     419         [ +  + ]:      15865 :         else if( weight <= FC_WEIGHT_SEMIBOLD )
     420                 :       1024 :             return WEIGHT_SEMIBOLD;
     421         [ +  - ]:      14841 :         else if( weight <= FC_WEIGHT_BOLD )
     422                 :      14841 :             return WEIGHT_BOLD;
     423         [ #  # ]:          0 :         else if( weight <= FC_WEIGHT_ULTRABOLD )
     424                 :          0 :             return WEIGHT_ULTRABOLD;
     425                 :      43711 :         return WEIGHT_BLACK;
     426                 :            :     }
     427                 :            : 
     428                 :      43711 :     FontItalic convertSlant(int slant)
     429                 :            :     {
     430                 :            :         // set italic
     431         [ +  + ]:      43711 :         if( slant == FC_SLANT_ITALIC )
     432                 :       9723 :             return ITALIC_NORMAL;
     433         [ +  + ]:      33988 :         else if( slant == FC_SLANT_OBLIQUE )
     434                 :       4233 :             return ITALIC_OBLIQUE;
     435                 :      43711 :         return ITALIC_NONE;
     436                 :            :     }
     437                 :            : 
     438                 :       7660 :     FontPitch convertSpacing(int spacing)
     439                 :            :     {
     440                 :            :         // set pitch
     441 [ +  + ][ -  + ]:       7660 :         if( spacing == FC_MONO || spacing == FC_CHARCELL )
     442                 :       3663 :             return PITCH_FIXED;
     443                 :       7660 :         return PITCH_VARIABLE;
     444                 :            :     }
     445                 :            : 
     446                 :            :     // translation: fontconfig enum -> vcl enum
     447                 :       8749 :     FontWidth convertWidth(int width)
     448                 :            :     {
     449         [ -  + ]:       8749 :         if (width == FC_WIDTH_ULTRACONDENSED)
     450                 :          0 :             return WIDTH_ULTRA_CONDENSED;
     451         [ -  + ]:       8749 :         else if (width == FC_WIDTH_EXTRACONDENSED)
     452                 :          0 :             return WIDTH_EXTRA_CONDENSED;
     453         [ -  + ]:       8749 :         else if (width == FC_WIDTH_CONDENSED)
     454                 :          0 :             return WIDTH_CONDENSED;
     455         [ -  + ]:       8749 :         else if (width == FC_WIDTH_SEMICONDENSED)
     456                 :          0 :             return WIDTH_SEMI_CONDENSED;
     457         [ -  + ]:       8749 :         else if (width == FC_WIDTH_SEMIEXPANDED)
     458                 :          0 :             return WIDTH_SEMI_EXPANDED;
     459         [ -  + ]:       8749 :         else if (width == FC_WIDTH_EXPANDED)
     460                 :          0 :             return WIDTH_EXPANDED;
     461         [ -  + ]:       8749 :         else if (width == FC_WIDTH_EXTRAEXPANDED)
     462                 :          0 :             return WIDTH_EXTRA_EXPANDED;
     463         [ -  + ]:       8749 :         else if (width == FC_WIDTH_ULTRAEXPANDED)
     464                 :          0 :             return WIDTH_ULTRA_EXPANDED;
     465                 :       8749 :         return WIDTH_NORMAL;
     466                 :            :     }
     467                 :            : }
     468                 :            : 
     469                 :            : //FontConfig doesn't come with a way to remove an element from a FontSet as far
     470                 :            : //as I can see
     471                 :        944 : static void lcl_FcFontSetRemove(FcFontSet* pFSet, int i)
     472                 :            : {
     473                 :        944 :     FcPatternDestroy(pFSet->fonts[i]);
     474                 :            : 
     475                 :        944 :     int nTail = pFSet->nfont - (i + 1);
     476                 :        944 :     --pFSet->nfont;
     477         [ -  + ]:        944 :     if (!nTail)
     478                 :        944 :         return;
     479                 :        944 :     memmove(pFSet->fonts + i, pFSet->fonts + i + 1, nTail*sizeof(FcPattern*));
     480                 :            : }
     481                 :            : 
     482                 :        236 : void PrintFontManager::countFontconfigFonts( boost::unordered_map<rtl::OString, int, rtl::OStringHash>& o_rVisitedPaths )
     483                 :            : {
     484                 :            : #if OSL_DEBUG_LEVEL > 1
     485                 :            :     int nFonts = 0;
     486                 :            : #endif
     487                 :        236 :     FontCfgWrapper& rWrapper = FontCfgWrapper::get();
     488                 :            : 
     489                 :        236 :     FcFontSet* pFSet = rWrapper.getFontSet();
     490         [ +  - ]:        236 :     if( pFSet )
     491                 :            :     {
     492                 :            : #if OSL_DEBUG_LEVEL > 1
     493                 :            :         fprintf( stderr, "found %d entries in fontconfig fontset\n", pFSet->nfont );
     494                 :            : #endif
     495         [ +  + ]:      36774 :         for( int i = 0; i < pFSet->nfont; i++ )
     496                 :            :         {
     497                 :      36538 :             FcChar8* file = NULL;
     498                 :      36538 :             FcChar8* family = NULL;
     499                 :      36538 :             FcChar8* style = NULL;
     500                 :      36538 :             FcChar8* format = NULL;
     501                 :      36538 :             int slant = 0;
     502                 :      36538 :             int weight = 0;
     503                 :      36538 :             int spacing = 0;
     504                 :      36538 :             int nCollectionEntry = -1;
     505                 :      36538 :             FcBool outline = false;
     506                 :            : 
     507         [ +  - ]:      36538 :             FcResult eFileRes         = FcPatternGetString(pFSet->fonts[i], FC_FILE, 0, &file);
     508         [ +  - ]:      36538 :             FcResult eFamilyRes       = rWrapper.LocalizedElementFromPattern( pFSet->fonts[i], &family, FC_FAMILY, FC_FAMILYLANG );
     509         [ +  - ]:      36538 :             FcResult eStyleRes        = rWrapper.LocalizedElementFromPattern( pFSet->fonts[i], &style, FC_STYLE, FC_STYLELANG );
     510         [ +  - ]:      36538 :             FcResult eSlantRes        = FcPatternGetInteger(pFSet->fonts[i], FC_SLANT, 0, &slant);
     511         [ +  - ]:      36538 :             FcResult eWeightRes       = FcPatternGetInteger(pFSet->fonts[i], FC_WEIGHT, 0, &weight);
     512         [ +  - ]:      36538 :             FcResult eSpacRes         = FcPatternGetInteger(pFSet->fonts[i], FC_SPACING, 0, &spacing);
     513         [ +  - ]:      36538 :             FcResult eOutRes          = FcPatternGetBool(pFSet->fonts[i], FC_OUTLINE, 0, &outline);
     514         [ +  - ]:      36538 :             FcResult eIndexRes        = FcPatternGetInteger(pFSet->fonts[i], FC_INDEX, 0, &nCollectionEntry);
     515         [ +  - ]:      36538 :             FcResult eFormatRes       = FcPatternGetString(pFSet->fonts[i], FC_FONTFORMAT, 0, &format);
     516                 :            : 
     517 [ +  - ][ +  - ]:      36538 :             if( eFileRes != FcResultMatch || eFamilyRes != FcResultMatch || eOutRes != FcResultMatch )
                 [ -  + ]
     518                 :          0 :                 continue;
     519                 :            : 
     520                 :            : #if (OSL_DEBUG_LEVEL > 2)
     521                 :            :             fprintf( stderr, "found font \"%s\" in file %s\n"
     522                 :            :                      "   weight = %d, slant = %d, style = \"%s\"\n"
     523                 :            :                      "   spacing = %d, outline = %d, format %s\n"
     524                 :            :                      , family, file
     525                 :            :                      , eWeightRes == FcResultMatch ? weight : -1
     526                 :            :                      , eSpacRes == FcResultMatch ? slant : -1
     527                 :            :                      , eStyleRes == FcResultMatch ? (const char*) style : "<nil>"
     528                 :            :                      , eSpacRes == FcResultMatch ? spacing : -1
     529                 :            :                      , eOutRes == FcResultMatch ? outline : -1
     530                 :            :                      , eFormatRes == FcResultMatch ? (const char*)format : "<unknown>"
     531                 :            :                      );
     532                 :            : #endif
     533                 :            : 
     534                 :            : //            OSL_ASSERT(eOutRes != FcResultMatch || outline);
     535                 :            : 
     536                 :            :             // only outline fonts are usable to psprint anyway
     537 [ +  - ][ -  + ]:      36538 :             if( eOutRes == FcResultMatch && ! outline )
     538                 :          0 :                 continue;
     539                 :            : 
     540 [ +  - ][ +  + ]:      36538 :             if (isPreviouslyDuplicateOrObsoleted(pFSet, i))
     541                 :            :             {
     542                 :            : #if OSL_DEBUG_LEVEL > 2
     543                 :            :                 fprintf(stderr, "Ditching %s as duplicate/obsolete\n", file);
     544                 :            : #endif
     545                 :        632 :                 continue;
     546                 :            :             }
     547                 :            : 
     548                 :            :             // see if this font is already cached
     549                 :            :             // update attributes
     550         [ +  - ]:      35906 :             std::list< PrintFont* > aFonts;
     551                 :      35906 :             OString aDir, aBase, aOrgPath( (sal_Char*)file );
     552         [ +  - ]:      35906 :             splitPath( aOrgPath, aDir, aBase );
     553                 :            : 
     554         [ +  - ]:      35906 :             o_rVisitedPaths[aDir] = 1;
     555                 :            : 
     556         [ +  - ]:      35906 :             int nDirID = getDirectoryAtom( aDir, true );
     557 [ +  - ][ +  + ]:      35906 :             if( ! m_pFontCache->getFontCacheFile( nDirID, aBase, aFonts ) )
     558                 :            :             {
     559                 :            : #if OSL_DEBUG_LEVEL > 2
     560                 :            :                 fprintf( stderr, "file %s not cached\n", aBase.getStr() );
     561                 :            : #endif
     562                 :            :                 // not known, analyze font file to get attributes
     563                 :            :                 // not described by fontconfig (e.g. alias names, PSName)
     564         [ -  + ]:      11191 :                 if (eFormatRes != FcResultMatch)
     565                 :          0 :                     format = NULL;
     566         [ +  - ]:      11191 :                 analyzeFontFile( nDirID, aBase, aFonts, (const char*)format );
     567                 :            : #if OSL_DEBUG_LEVEL > 1
     568                 :            :                 if( aFonts.empty() )
     569                 :            :                     fprintf( stderr, "Warning: file \"%s\" is unusable to psprint\n", aOrgPath.getStr() );
     570                 :            : #endif
     571                 :            :             }
     572         [ +  + ]:      35906 :             if( aFonts.empty() )
     573                 :            :             {
     574                 :            :                 //remove font, reuse index
     575                 :            :                 //we want to remove unusable fonts here, in case there is a usable font
     576                 :            :                 //which duplicates the properties of the unusable one
     577                 :            :                 //
     578                 :            :                 //not removing the unusable font will risk the usable font being rejected
     579                 :            :                 //as a duplicate by isPreviouslyDuplicateOrObsoleted
     580         [ +  - ]:        944 :                 lcl_FcFontSetRemove(pFSet, i--);
     581                 :        944 :                 continue;
     582                 :            :             }
     583                 :            : 
     584 [ +  - ][ +  - ]:      34962 :             int nFamilyName = m_pAtoms->getAtom( ATOM_FAMILYNAME, OStringToOUString( OString( (sal_Char*)family ), RTL_TEXTENCODING_UTF8 ), sal_True );
     585         [ +  - ]:      34962 :             PrintFont* pUpdate = aFonts.front();
     586         [ +  - ]:      34962 :             std::list<PrintFont*>::const_iterator second_font = aFonts.begin();
     587         [ +  - ]:      34962 :             ++second_font;
     588 [ +  - ][ +  - ]:      34962 :             if( second_font != aFonts.end() ) // more than one font
                 [ +  + ]
     589                 :            :             {
     590                 :            :                 // a collection entry, get the correct index
     591 [ +  - ][ +  - ]:       1652 :                 if( eIndexRes == FcResultMatch && nCollectionEntry != -1 )
     592                 :            :                 {
     593 [ +  - ][ +  - ]:       3776 :                     for( std::list< PrintFont* >::iterator it = aFonts.begin(); it != aFonts.end(); ++it )
                 [ +  - ]
     594                 :            :                     {
     595 [ +  - ][ +  - ]:       7552 :                         if( (*it)->m_eType == fonttype::TrueType &&
         [ +  + ][ +  + ]
     596         [ +  - ]:       3776 :                             static_cast<TrueTypeFontFile*>(*it)->m_nCollectionEntry == nCollectionEntry )
     597                 :            :                         {
     598         [ +  - ]:       1652 :                             pUpdate = *it;
     599                 :       1652 :                             break;
     600                 :            :                         }
     601                 :            :                     }
     602                 :            :                     // update collection entry
     603                 :            :                     // additional entries will be created in the cache
     604                 :            :                     // if this is a new index (that is if the loop above
     605                 :            :                     // ran to the end of the list)
     606         [ +  - ]:       1652 :                     if( pUpdate->m_eType == fonttype::TrueType ) // sanity check, this should always be the case here
     607                 :       1652 :                         static_cast<TrueTypeFontFile*>(pUpdate)->m_nCollectionEntry = nCollectionEntry;
     608                 :            :                 }
     609                 :            :                 else
     610                 :            :                 {
     611                 :            : #if OSL_DEBUG_LEVEL > 1
     612                 :            :                     fprintf( stderr, "multiple fonts for file, but no index in fontconfig pattern ! (index res = %d collection entry = %d\nfile will not be used\n", eIndexRes, nCollectionEntry );
     613                 :            : #endif
     614                 :            :                     // we have found more than one font in this file
     615                 :            :                     // but fontconfig will not tell us which index is meant
     616                 :            :                     // -> something is in disorder, do not use this font
     617                 :       1652 :                     pUpdate = NULL;
     618                 :            :                 }
     619                 :            :             }
     620                 :            : 
     621         [ +  - ]:      34962 :             if( pUpdate )
     622                 :            :             {
     623                 :            :                 // set family name
     624                 :      34962 :                 if( pUpdate->m_nFamilyName != nFamilyName )
     625                 :            :                 {
     626                 :            :                 }
     627         [ +  - ]:      34962 :                 if( eWeightRes == FcResultMatch )
     628                 :      34962 :                     pUpdate->m_eWeight = convertWeight(weight);
     629         [ +  + ]:      34962 :                 if( eSpacRes == FcResultMatch )
     630                 :       3544 :                     pUpdate->m_ePitch = convertSpacing(spacing);
     631         [ +  - ]:      34962 :                 if( eSlantRes == FcResultMatch )
     632                 :      34962 :                     pUpdate->m_eItalic = convertSlant(slant);
     633         [ +  - ]:      34962 :                 if( eStyleRes == FcResultMatch )
     634                 :            :                 {
     635         [ +  - ]:      34962 :                     pUpdate->m_aStyleName = OStringToOUString( OString( (sal_Char*)style ), RTL_TEXTENCODING_UTF8 );
     636                 :            :                 }
     637                 :            : 
     638                 :            :                 // update font cache
     639         [ +  - ]:      34962 :                 m_pFontCache->updateFontCacheEntry( pUpdate, false );
     640                 :            :                 // sort into known fonts
     641                 :      34962 :                 fontID aFont = m_nNextFontID++;
     642         [ +  - ]:      34962 :                 m_aFonts[ aFont ] = pUpdate;
     643 [ +  - ][ +  - ]:      34962 :                 m_aFontFileToFontID[ aBase ].insert( aFont );
     644                 :            : #if OSL_DEBUG_LEVEL > 1
     645                 :            :                 nFonts++;
     646                 :            : #endif
     647                 :            : #if OSL_DEBUG_LEVEL > 2
     648                 :            :                 fprintf( stderr, "inserted font %s as fontID %d\n", family, aFont );
     649                 :            : #endif
     650                 :            :             }
     651                 :            :             // clean up the fonts we did not put into the list
     652 [ +  - ][ +  - ]:      74172 :             for( std::list< PrintFont* >::iterator it = aFonts.begin(); it != aFonts.end(); ++it )
                 [ +  + ]
     653                 :            :             {
     654 [ +  - ][ +  + ]:      39210 :                 if( *it != pUpdate )
     655                 :            :                 {
     656 [ +  - ][ +  - ]:       4248 :                     m_pFontCache->updateFontCacheEntry( *it, false ); // prepare a cache entry for a collection item
     657 [ +  - ][ +  - ]:       4248 :                     delete *it;
                 [ +  - ]
     658                 :            :                 }
     659                 :            :             }
     660 [ +  + ][ +  + ]:      36538 :         }
         [ +  + ][ +  + ]
     661                 :            :     }
     662                 :            : 
     663                 :            :     // how does one get rid of the config ?
     664                 :            : #if OSL_DEBUG_LEVEL > 1
     665                 :            :     fprintf( stderr, "inserted %d fonts from fontconfig\n", nFonts );
     666                 :            : #endif
     667                 :        236 : }
     668                 :            : 
     669                 :        236 : void PrintFontManager::deinitFontconfig()
     670                 :            : {
     671                 :        236 :     FontCfgWrapper::release();
     672                 :        236 : }
     673                 :            : 
     674                 :        549 : bool PrintFontManager::addFontconfigDir( const rtl::OString& rDirName )
     675                 :            : {
     676                 :            :     // workaround for a stability problems in older FC versions
     677                 :            :     // when handling application specifc fonts
     678         [ +  - ]:        549 :     const int nVersion = FcGetVersion();
     679         [ -  + ]:        549 :     if( nVersion <= 20400 )
     680                 :          0 :         return false;
     681                 :        549 :     const char* pDirName = (const char*)rDirName.getStr();
     682 [ +  - ][ +  - ]:        549 :     bool bDirOk = (FcConfigAppFontAddDir(FcConfigGetCurrent(), (FcChar8*)pDirName ) == FcTrue);
     683                 :            : 
     684                 :            : #if OSL_DEBUG_LEVEL > 1
     685                 :            :     fprintf( stderr, "FcConfigAppFontAddDir( \"%s\") => %d\n", pDirName, bDirOk );
     686                 :            : #endif
     687                 :            : 
     688         [ -  + ]:        549 :     if( !bDirOk )
     689                 :          0 :         return false;
     690                 :            : 
     691                 :            :     // load dir-specific fc-config file too if available
     692                 :        549 :     const rtl::OString aConfFileName = rDirName + "/fc_local.conf";
     693         [ +  - ]:        549 :     FILE* pCfgFile = fopen( aConfFileName.getStr(), "rb" );
     694         [ +  + ]:        549 :     if( pCfgFile )
     695                 :            :     {
     696         [ +  - ]:        158 :         fclose( pCfgFile);
     697                 :            :         bool bCfgOk = FcConfigParseAndLoad(FcConfigGetCurrent(),
     698 [ +  - ][ +  - ]:        158 :                         (FcChar8*)aConfFileName.getStr(), FcTrue);
     699         [ -  + ]:        158 :         if( !bCfgOk )
     700         [ #  # ]:          0 :             fprintf( stderr, "FcConfigParseAndLoad( \"%s\") => %d\n", aConfFileName.getStr(), bCfgOk );
     701                 :            :     }
     702                 :            : 
     703                 :        549 :     return true;
     704                 :            : }
     705                 :            : 
     706                 :       8749 : static void addtopattern(FcPattern *pPattern,
     707                 :            :     FontItalic eItalic, FontWeight eWeight, FontWidth eWidth, FontPitch ePitch)
     708                 :            : {
     709         [ +  - ]:       8749 :     if( eItalic != ITALIC_DONTKNOW )
     710                 :            :     {
     711                 :       8749 :         int nSlant = FC_SLANT_ROMAN;
     712      [ +  +  + ]:       8749 :         switch( eItalic )
     713                 :            :         {
     714                 :            :             case ITALIC_NORMAL:
     715                 :        494 :                 nSlant = FC_SLANT_ITALIC;
     716                 :        494 :                 break;
     717                 :            :             case ITALIC_OBLIQUE:
     718                 :        302 :                 nSlant = FC_SLANT_OBLIQUE;
     719                 :        302 :                 break;
     720                 :            :             default:
     721                 :       7953 :                 break;
     722                 :            :         }
     723                 :       8749 :         FcPatternAddInteger(pPattern, FC_SLANT, nSlant);
     724                 :            :     }
     725         [ +  + ]:       8749 :     if( eWeight != WEIGHT_DONTKNOW )
     726                 :            :     {
     727                 :       5868 :         int nWeight = FC_WEIGHT_NORMAL;
     728   [ +  +  +  +  :       5868 :         switch( eWeight )
          +  -  -  +  +  
                   +  - ]
     729                 :            :         {
     730                 :        601 :             case WEIGHT_THIN:           nWeight = FC_WEIGHT_THIN;break;
     731                 :         22 :             case WEIGHT_ULTRALIGHT:     nWeight = FC_WEIGHT_ULTRALIGHT;break;
     732                 :        101 :             case WEIGHT_LIGHT:          nWeight = FC_WEIGHT_LIGHT;break;
     733                 :         19 :             case WEIGHT_SEMILIGHT:      nWeight = FC_WEIGHT_BOOK;break;
     734                 :       3522 :             case WEIGHT_NORMAL:         nWeight = FC_WEIGHT_NORMAL;break;
     735                 :          0 :             case WEIGHT_MEDIUM:         nWeight = FC_WEIGHT_MEDIUM;break;
     736                 :          0 :             case WEIGHT_SEMIBOLD:       nWeight = FC_WEIGHT_SEMIBOLD;break;
     737                 :        997 :             case WEIGHT_BOLD:           nWeight = FC_WEIGHT_BOLD;break;
     738                 :        463 :             case WEIGHT_ULTRABOLD:      nWeight = FC_WEIGHT_ULTRABOLD;break;
     739                 :        143 :             case WEIGHT_BLACK:          nWeight = FC_WEIGHT_BLACK;break;
     740                 :            :             default:
     741                 :          0 :                 break;
     742                 :            :         }
     743                 :       5868 :         FcPatternAddInteger(pPattern, FC_WEIGHT, nWeight);
     744                 :            :     }
     745         [ -  + ]:       8749 :     if( eWidth != WIDTH_DONTKNOW )
     746                 :            :     {
     747                 :          0 :         int nWidth = FC_WIDTH_NORMAL;
     748   [ #  #  #  #  :          0 :         switch( eWidth )
          #  #  #  #  #  
                      # ]
     749                 :            :         {
     750                 :          0 :             case WIDTH_ULTRA_CONDENSED: nWidth = FC_WIDTH_ULTRACONDENSED;break;
     751                 :          0 :             case WIDTH_EXTRA_CONDENSED: nWidth = FC_WIDTH_EXTRACONDENSED;break;
     752                 :          0 :             case WIDTH_CONDENSED:       nWidth = FC_WIDTH_CONDENSED;break;
     753                 :          0 :             case WIDTH_SEMI_CONDENSED:  nWidth = FC_WIDTH_SEMICONDENSED;break;
     754                 :          0 :             case WIDTH_NORMAL:          nWidth = FC_WIDTH_NORMAL;break;
     755                 :          0 :             case WIDTH_SEMI_EXPANDED:   nWidth = FC_WIDTH_SEMIEXPANDED;break;
     756                 :          0 :             case WIDTH_EXPANDED:        nWidth = FC_WIDTH_EXPANDED;break;
     757                 :          0 :             case WIDTH_EXTRA_EXPANDED:  nWidth = FC_WIDTH_EXTRAEXPANDED;break;
     758                 :          0 :             case WIDTH_ULTRA_EXPANDED:  nWidth = FC_WIDTH_ULTRACONDENSED;break;
     759                 :            :             default:
     760                 :          0 :                 break;
     761                 :            :         }
     762                 :          0 :         FcPatternAddInteger(pPattern, FC_WIDTH, nWidth);
     763                 :            :     }
     764         [ +  + ]:       8749 :     if( ePitch != PITCH_DONTKNOW )
     765                 :            :     {
     766                 :       4113 :         int nSpacing = FC_PROPORTIONAL;
     767      [ +  +  + ]:       4113 :         switch( ePitch )
     768                 :            :         {
     769                 :        116 :             case PITCH_FIXED:           nSpacing = FC_MONO;break;
     770                 :       2604 :             case PITCH_VARIABLE:        nSpacing = FC_PROPORTIONAL;break;
     771                 :            :             default:
     772                 :       1393 :                 break;
     773                 :            :         }
     774                 :       4113 :         FcPatternAddInteger(pPattern, FC_SPACING, nSpacing);
     775         [ +  + ]:       4113 :         if (nSpacing == FC_MONO)
     776                 :        116 :             FcPatternAddString(pPattern, FC_FAMILY, (FcChar8*)"monospace");
     777                 :            :     }
     778                 :       8749 : }
     779                 :            : 
     780                 :       8749 : bool PrintFontManager::Substitute( FontSelectPattern &rPattern, rtl::OUString& rMissingCodes )
     781                 :            : {
     782                 :       8749 :     bool bRet = false;
     783                 :            : 
     784         [ +  - ]:       8749 :     FontCfgWrapper& rWrapper = FontCfgWrapper::get();
     785                 :            : 
     786                 :            :     // build pattern argument for fontconfig query
     787         [ +  - ]:       8749 :     FcPattern* pPattern = FcPatternCreate();
     788                 :            : 
     789                 :            :     // Prefer scalable fonts
     790         [ +  - ]:       8749 :     FcPatternAddBool(pPattern, FC_SCALABLE, FcTrue);
     791                 :            : 
     792 [ +  - ][ +  - ]:       8749 :     const rtl::OString aTargetName = rtl::OUStringToOString( rPattern.maTargetName, RTL_TEXTENCODING_UTF8 );
     793                 :       8749 :     const FcChar8* pTargetNameUtf8 = (FcChar8*)aTargetName.getStr();
     794         [ +  - ]:       8749 :     FcPatternAddString(pPattern, FC_FAMILY, pTargetNameUtf8);
     795                 :            : 
     796         [ +  - ]:       8749 :     const rtl::OString aLangAttrib = MsLangId::convertLanguageToIsoByteString(rPattern.meLanguage);
     797         [ +  + ]:       8749 :     if( !aLangAttrib.isEmpty() )
     798                 :            :     {
     799                 :            :         const FcChar8* pLangAttribUtf8;
     800         [ -  + ]:       3539 :         if (aLangAttrib.equalsIgnoreAsciiCase(OString(RTL_CONSTASCII_STRINGPARAM("pa-in"))))
     801                 :          0 :             pLangAttribUtf8 = (FcChar8*)"pa";
     802                 :            :         else
     803                 :       3539 :             pLangAttribUtf8 = (FcChar8*)aLangAttrib.getStr();
     804         [ +  - ]:       3539 :         FcPatternAddString(pPattern, FC_LANG, pLangAttribUtf8);
     805                 :            :     }
     806                 :            : 
     807                 :            :     // Add required Unicode characters, if any
     808         [ +  + ]:       8749 :     if ( !rMissingCodes.isEmpty() )
     809                 :            :     {
     810         [ +  - ]:       3570 :        FcCharSet *unicodes = FcCharSetCreate();
     811         [ +  + ]:       7173 :        for( sal_Int32 nStrIndex = 0; nStrIndex < rMissingCodes.getLength(); )
     812                 :            :        {
     813                 :            :            // also handle unicode surrogates
     814         [ +  - ]:       3603 :            const sal_uInt32 nCode = rMissingCodes.iterateCodePoints( &nStrIndex );
     815         [ +  - ]:       3603 :            FcCharSetAddChar( unicodes, nCode );
     816                 :            :        }
     817         [ +  - ]:       3570 :        FcPatternAddCharSet(pPattern, FC_CHARSET, unicodes);
     818         [ +  - ]:       3570 :        FcCharSetDestroy(unicodes);
     819                 :            :     }
     820                 :            : 
     821                 :            :     addtopattern(pPattern, rPattern.meItalic, rPattern.meWeight,
     822         [ +  - ]:       8749 :         rPattern.meWidthType, rPattern.mePitch);
     823                 :            : 
     824                 :            :     // query fontconfig for a substitute
     825 [ +  - ][ +  - ]:       8749 :     FcConfigSubstitute(FcConfigGetCurrent(), pPattern, FcMatchPattern);
     826         [ +  - ]:       8749 :     FcDefaultSubstitute(pPattern);
     827                 :            : 
     828                 :            :     // process the result of the fontconfig query
     829                 :       8749 :     FcResult eResult = FcResultNoMatch;
     830         [ +  - ]:       8749 :     FcFontSet* pFontSet = rWrapper.getFontSet();
     831 [ +  - ][ +  - ]:       8749 :     FcPattern* pResult = FcFontSetMatch(FcConfigGetCurrent(), &pFontSet, 1, pPattern, &eResult);
     832         [ +  - ]:       8749 :     FcPatternDestroy( pPattern );
     833                 :            : 
     834                 :       8749 :     FcFontSet*  pSet = NULL;
     835         [ +  - ]:       8749 :     if( pResult )
     836                 :            :     {
     837         [ +  - ]:       8749 :         pSet = FcFontSetCreate();
     838                 :            :         // info: destroying the pSet destroys pResult implicitly
     839                 :            :         // since pResult was "added" to pSet
     840         [ +  - ]:       8749 :         FcFontSetAdd( pSet, pResult );
     841                 :            :     }
     842                 :            : 
     843         [ +  - ]:       8749 :     if( pSet )
     844                 :            :     {
     845         [ +  - ]:       8749 :         if( pSet->nfont > 0 )
     846                 :            :         {
     847                 :            :             //extract the closest match
     848                 :       8749 :             FcChar8* file = NULL;
     849         [ +  - ]:       8749 :             FcResult eFileRes = FcPatternGetString(pSet->fonts[0], FC_FILE, 0, &file);
     850                 :       8749 :             int nCollectionEntry = 0;
     851         [ +  - ]:       8749 :             FcResult eIndexRes = FcPatternGetInteger(pSet->fonts[0], FC_INDEX, 0, &nCollectionEntry);
     852         [ -  + ]:       8749 :             if (eIndexRes != FcResultMatch)
     853                 :          0 :                 nCollectionEntry = 0;
     854         [ +  - ]:       8749 :             if( eFileRes == FcResultMatch )
     855                 :            :             {
     856                 :       8749 :                 OString aDir, aBase, aOrgPath( (sal_Char*)file );
     857         [ +  - ]:       8749 :                 splitPath( aOrgPath, aDir, aBase );
     858         [ +  - ]:       8749 :                 int nDirID = getDirectoryAtom( aDir, true );
     859         [ +  - ]:       8749 :                 fontID aFont = findFontFileID( nDirID, aBase, nCollectionEntry );
     860         [ +  - ]:       8749 :                 if( aFont > 0 )
     861                 :            :                 {
     862         [ +  - ]:       8749 :                     FastPrintFontInfo aInfo;
     863         [ +  - ]:       8749 :                     bRet = getFontFastInfo( aFont, aInfo );
     864         [ +  - ]:       8749 :                     rPattern.maSearchName = aInfo.m_aFamilyName;
     865                 :       8749 :                 }
     866                 :            :             }
     867                 :            : 
     868                 :            :             SAL_WARN_IF(!bRet, "vcl", "no FC_FILE found, falling back to name search");
     869                 :            : 
     870         [ -  + ]:       8749 :             if (!bRet)
     871                 :            :             {
     872                 :          0 :                 FcChar8* family = NULL;
     873         [ #  # ]:          0 :                 FcResult eFamilyRes = FcPatternGetString( pSet->fonts[0], FC_FAMILY, 0, &family );
     874                 :            : 
     875                 :            :                 // get the family name
     876         [ #  # ]:          0 :                 if( eFamilyRes == FcResultMatch )
     877                 :            :                 {
     878                 :          0 :                     OString sFamily((sal_Char*)family);
     879                 :            :                     boost::unordered_map< rtl::OString, rtl::OString, rtl::OStringHash >::const_iterator aI =
     880         [ #  # ]:          0 :                         rWrapper.m_aFontNameToLocalized.find(sFamily);
     881 [ #  # ][ #  # ]:          0 :                     if (aI != rWrapper.m_aFontNameToLocalized.end())
     882         [ #  # ]:          0 :                         sFamily = aI->second;
     883 [ #  # ][ #  # ]:          0 :                     rPattern.maSearchName = rtl::OStringToOUString( sFamily, RTL_TEXTENCODING_UTF8 );
     884                 :          0 :                     bRet = true;
     885                 :            :                 }
     886                 :            :             }
     887                 :            : 
     888         [ +  - ]:       8749 :             if (bRet)
     889                 :            :             {
     890                 :       8749 :                 int val = 0;
     891 [ +  - ][ +  - ]:       8749 :                 if (FcResultMatch == FcPatternGetInteger(pSet->fonts[0], FC_WEIGHT, 0, &val))
     892                 :       8749 :                     rPattern.meWeight = convertWeight(val);
     893 [ +  - ][ +  - ]:       8749 :                 if (FcResultMatch == FcPatternGetInteger(pSet->fonts[0], FC_SLANT, 0, &val))
     894                 :       8749 :                     rPattern.meItalic = convertSlant(val);
     895 [ +  - ][ +  + ]:       8749 :                 if (FcResultMatch == FcPatternGetInteger(pSet->fonts[0], FC_SPACING, 0, &val))
     896                 :       4116 :                     rPattern.mePitch = convertSpacing(val);
     897 [ +  - ][ +  - ]:       8749 :                 if (FcResultMatch == FcPatternGetInteger(pSet->fonts[0], FC_WIDTH, 0, &val))
     898                 :       8749 :                     rPattern.meWidthType = convertWidth(val);
     899                 :            :                 FcBool bEmbolden;
     900 [ +  - ][ -  + ]:       8749 :                 if (FcResultMatch == FcPatternGetBool(pSet->fonts[0], FC_EMBOLDEN, 0, &bEmbolden))
     901                 :          0 :                     rPattern.mbEmbolden = bEmbolden;
     902                 :       8749 :                 FcMatrix *pMatrix = 0;
     903 [ +  - ][ -  + ]:       8749 :                 if (FcResultMatch == FcPatternGetMatrix(pSet->fonts[0], FC_MATRIX, 0, &pMatrix))
     904                 :            :                 {
     905                 :          0 :                     rPattern.maItalicMatrix.xx = pMatrix->xx;
     906                 :          0 :                     rPattern.maItalicMatrix.xy = pMatrix->xy;
     907                 :          0 :                     rPattern.maItalicMatrix.yx = pMatrix->yx;
     908                 :       8749 :                     rPattern.maItalicMatrix.yy = pMatrix->yy;
     909                 :            :                 }
     910                 :            :             }
     911                 :            : 
     912                 :            :             // update rMissingCodes by removing resolved unicodes
     913         [ +  + ]:       8749 :             if( !rMissingCodes.isEmpty() )
     914                 :            :             {
     915                 :       3570 :                 sal_uInt32* pRemainingCodes = (sal_uInt32*)alloca( rMissingCodes.getLength() * sizeof(sal_uInt32) );
     916                 :       3570 :                 int nRemainingLen = 0;
     917                 :            :                 FcCharSet* unicodes;
     918 [ +  - ][ +  - ]:       3570 :                 if (!FcPatternGetCharSet(pSet->fonts[0], FC_CHARSET, 0, &unicodes))
     919                 :            :                 {
     920         [ +  + ]:       7173 :                     for( sal_Int32 nStrIndex = 0; nStrIndex < rMissingCodes.getLength(); )
     921                 :            :                     {
     922                 :            :                         // also handle unicode surrogates
     923         [ +  - ]:       3603 :                         const sal_uInt32 nCode = rMissingCodes.iterateCodePoints( &nStrIndex );
     924 [ +  - ][ -  + ]:       3603 :                         if (FcCharSetHasChar(unicodes, nCode) != FcTrue)
     925                 :          0 :                             pRemainingCodes[ nRemainingLen++ ] = nCode;
     926                 :            :                     }
     927                 :            :                 }
     928         [ +  - ]:       8749 :                 rMissingCodes = OUString( pRemainingCodes, nRemainingLen );
     929                 :            :             }
     930                 :            :         }
     931                 :            : 
     932         [ +  - ]:       8749 :         FcFontSetDestroy( pSet );
     933                 :            :     }
     934                 :            : 
     935                 :       8749 :     return bRet;
     936                 :            : }
     937                 :            : 
     938                 :            : class FontConfigFontOptions : public ImplFontOptions
     939                 :            : {
     940                 :            : public:
     941                 :          0 :     FontConfigFontOptions() : mpPattern(0) {}
     942                 :          0 :     ~FontConfigFontOptions()
     943                 :          0 :     {
     944         [ #  # ]:          0 :         FcPatternDestroy(mpPattern);
     945         [ #  # ]:          0 :     }
     946                 :          0 :     virtual void *GetPattern(void * face, bool bEmbolden, bool /*bVerticalLayout*/) const
     947                 :            :     {
     948                 :            :         FcValue value;
     949                 :          0 :         value.type = FcTypeFTFace;
     950                 :          0 :         value.u.f = face;
     951         [ #  # ]:          0 :         FcPatternDel(mpPattern, FC_FT_FACE);
     952         [ #  # ]:          0 :         FcPatternAdd (mpPattern, FC_FT_FACE, value, FcTrue);
     953         [ #  # ]:          0 :         FcPatternDel(mpPattern, FC_EMBOLDEN);
     954 [ #  # ][ #  # ]:          0 :         FcPatternAddBool(mpPattern, FC_EMBOLDEN, bEmbolden ? FcTrue : FcFalse);
     955                 :            : #if 0
     956                 :            :         FcPatternDel(mpPattern, FC_VERTICAL_LAYOUT);
     957                 :            :         FcPatternAddBool(mpPattern, FC_VERTICAL_LAYOUT, bVerticalLayout ? FcTrue : FcFalse);
     958                 :            : #endif
     959                 :          0 :         return mpPattern;
     960                 :            :     }
     961                 :            :     FcPattern* mpPattern;
     962                 :            : };
     963                 :            : 
     964                 :          0 : ImplFontOptions* PrintFontManager::getFontOptions(
     965                 :            :     const FastPrintFontInfo& rInfo, int nSize, void (*subcallback)(void*)) const
     966                 :            : {
     967         [ #  # ]:          0 :     FontCfgWrapper& rWrapper = FontCfgWrapper::get();
     968                 :            : 
     969                 :          0 :     FontConfigFontOptions* pOptions = NULL;
     970         [ #  # ]:          0 :     FcConfig* pConfig = FcConfigGetCurrent();
     971         [ #  # ]:          0 :     FcPattern* pPattern = FcPatternCreate();
     972                 :            : 
     973         [ #  # ]:          0 :     OString sFamily = OUStringToOString( rInfo.m_aFamilyName, RTL_TEXTENCODING_UTF8 );
     974                 :            : 
     975         [ #  # ]:          0 :     boost::unordered_map< rtl::OString, rtl::OString, rtl::OStringHash >::const_iterator aI = rWrapper.m_aLocalizedToCanonical.find(sFamily);
     976 [ #  # ][ #  # ]:          0 :     if (aI != rWrapper.m_aLocalizedToCanonical.end())
     977         [ #  # ]:          0 :         sFamily = aI->second;
     978         [ #  # ]:          0 :     if( !sFamily.isEmpty() )
     979         [ #  # ]:          0 :         FcPatternAddString(pPattern, FC_FAMILY, (FcChar8*)sFamily.getStr());
     980                 :            : 
     981         [ #  # ]:          0 :     addtopattern(pPattern, rInfo.m_eItalic, rInfo.m_eWeight, rInfo.m_eWidth, rInfo.m_ePitch);
     982         [ #  # ]:          0 :     FcPatternAddDouble(pPattern, FC_PIXEL_SIZE, nSize);
     983                 :            : 
     984                 :          0 :     FcBool embitmap = true, antialias = true, autohint = true, hinting = true;
     985                 :          0 :     int hintstyle = FC_HINT_FULL;
     986                 :            : 
     987         [ #  # ]:          0 :     FcConfigSubstitute(pConfig, pPattern, FcMatchPattern);
     988         [ #  # ]:          0 :     if (subcallback)
     989         [ #  # ]:          0 :         subcallback(pPattern);
     990         [ #  # ]:          0 :     FcDefaultSubstitute(pPattern);
     991                 :            : 
     992                 :          0 :     FcResult eResult = FcResultNoMatch;
     993         [ #  # ]:          0 :     FcFontSet* pFontSet = rWrapper.getFontSet();
     994         [ #  # ]:          0 :     FcPattern* pResult = FcFontSetMatch( pConfig, &pFontSet, 1, pPattern, &eResult );
     995         [ #  # ]:          0 :     if( pResult )
     996                 :            :     {
     997                 :            :         FcResult eEmbeddedBitmap = FcPatternGetBool(pResult,
     998         [ #  # ]:          0 :             FC_EMBEDDED_BITMAP, 0, &embitmap);
     999                 :            :         FcResult eAntialias = FcPatternGetBool(pResult,
    1000         [ #  # ]:          0 :             FC_ANTIALIAS, 0, &antialias);
    1001                 :            :         FcResult eAutoHint = FcPatternGetBool(pResult,
    1002         [ #  # ]:          0 :             FC_AUTOHINT, 0, &autohint);
    1003                 :            :         FcResult eHinting = FcPatternGetBool(pResult,
    1004         [ #  # ]:          0 :             FC_HINTING, 0, &hinting);
    1005                 :            :         /*FcResult eHintStyle =*/ FcPatternGetInteger(pResult,
    1006         [ #  # ]:          0 :             FC_HINT_STYLE, 0, &hintstyle);
    1007                 :            : 
    1008         [ #  # ]:          0 :         pOptions = new FontConfigFontOptions;
    1009                 :            : 
    1010                 :          0 :         pOptions->mpPattern = pResult;
    1011                 :            : 
    1012         [ #  # ]:          0 :         if( eEmbeddedBitmap == FcResultMatch )
    1013         [ #  # ]:          0 :             pOptions->meEmbeddedBitmap = embitmap ? EMBEDDEDBITMAP_TRUE : EMBEDDEDBITMAP_FALSE;
    1014         [ #  # ]:          0 :         if( eAntialias == FcResultMatch )
    1015         [ #  # ]:          0 :             pOptions->meAntiAlias = antialias ? ANTIALIAS_TRUE : ANTIALIAS_FALSE;
    1016         [ #  # ]:          0 :         if( eAutoHint == FcResultMatch )
    1017         [ #  # ]:          0 :             pOptions->meAutoHint = autohint ? AUTOHINT_TRUE : AUTOHINT_FALSE;
    1018         [ #  # ]:          0 :         if( eHinting == FcResultMatch )
    1019         [ #  # ]:          0 :             pOptions->meHinting = hinting ? HINTING_TRUE : HINTING_FALSE;
    1020   [ #  #  #  # ]:          0 :         switch (hintstyle)
    1021                 :            :         {
    1022                 :          0 :             case FC_HINT_NONE:   pOptions->meHintStyle = HINT_NONE; break;
    1023                 :          0 :             case FC_HINT_SLIGHT: pOptions->meHintStyle = HINT_SLIGHT; break;
    1024                 :          0 :             case FC_HINT_MEDIUM: pOptions->meHintStyle = HINT_MEDIUM; break;
    1025                 :            :             default: // fall through
    1026                 :          0 :             case FC_HINT_FULL:   pOptions->meHintStyle = HINT_FULL; break;
    1027                 :            :         }
    1028                 :            :     }
    1029                 :            : 
    1030                 :            :     // cleanup
    1031         [ #  # ]:          0 :     FcPatternDestroy( pPattern );
    1032                 :            : 
    1033                 :          0 :     return pOptions;
    1034                 :            : }
    1035                 :            : 
    1036                 :          0 : bool PrintFontManager::matchFont( FastPrintFontInfo& rInfo, const com::sun::star::lang::Locale& rLocale )
    1037                 :            : {
    1038         [ #  # ]:          0 :     FontCfgWrapper& rWrapper = FontCfgWrapper::get();
    1039                 :            : 
    1040         [ #  # ]:          0 :     FcConfig* pConfig = FcConfigGetCurrent();
    1041         [ #  # ]:          0 :     FcPattern* pPattern = FcPatternCreate();
    1042                 :            : 
    1043                 :          0 :     OString aLangAttrib;
    1044                 :            :     // populate pattern with font characteristics
    1045         [ #  # ]:          0 :     if( !rLocale.Language.isEmpty() )
    1046                 :            :     {
    1047                 :          0 :         OUStringBuffer aLang(6);
    1048         [ #  # ]:          0 :         aLang.append( rLocale.Language );
    1049         [ #  # ]:          0 :         if( !rLocale.Country.isEmpty() )
    1050                 :            :         {
    1051         [ #  # ]:          0 :             aLang.append( sal_Unicode('-') );
    1052         [ #  # ]:          0 :             aLang.append( rLocale.Country );
    1053                 :            :         }
    1054 [ #  # ][ #  # ]:          0 :         aLangAttrib = OUStringToOString( aLang.makeStringAndClear(), RTL_TEXTENCODING_UTF8 );
    1055                 :            :     }
    1056         [ #  # ]:          0 :     if( !aLangAttrib.isEmpty() )
    1057         [ #  # ]:          0 :         FcPatternAddString(pPattern, FC_LANG, (FcChar8*)aLangAttrib.getStr());
    1058                 :            : 
    1059         [ #  # ]:          0 :     OString aFamily = OUStringToOString( rInfo.m_aFamilyName, RTL_TEXTENCODING_UTF8 );
    1060         [ #  # ]:          0 :     if( !aFamily.isEmpty() )
    1061         [ #  # ]:          0 :         FcPatternAddString(pPattern, FC_FAMILY, (FcChar8*)aFamily.getStr());
    1062                 :            : 
    1063         [ #  # ]:          0 :     addtopattern(pPattern, rInfo.m_eItalic, rInfo.m_eWeight, rInfo.m_eWidth, rInfo.m_ePitch);
    1064                 :            : 
    1065         [ #  # ]:          0 :     FcConfigSubstitute(pConfig, pPattern, FcMatchPattern);
    1066         [ #  # ]:          0 :     FcDefaultSubstitute(pPattern);
    1067                 :          0 :     FcResult eResult = FcResultNoMatch;
    1068         [ #  # ]:          0 :     FcFontSet *pFontSet = rWrapper.getFontSet();
    1069         [ #  # ]:          0 :     FcPattern* pResult = FcFontSetMatch(pConfig, &pFontSet, 1, pPattern, &eResult);
    1070                 :          0 :     bool bSuccess = false;
    1071         [ #  # ]:          0 :     if( pResult )
    1072                 :            :     {
    1073         [ #  # ]:          0 :         FcFontSet* pSet = FcFontSetCreate();
    1074         [ #  # ]:          0 :         FcFontSetAdd( pSet, pResult );
    1075         [ #  # ]:          0 :         if( pSet->nfont > 0 )
    1076                 :            :         {
    1077                 :            :             //extract the closest match
    1078                 :          0 :             FcChar8* file = NULL;
    1079         [ #  # ]:          0 :             FcResult eFileRes = FcPatternGetString(pSet->fonts[0], FC_FILE, 0, &file);
    1080                 :          0 :             int nCollectionEntry = 0;
    1081         [ #  # ]:          0 :             FcResult eIndexRes = FcPatternGetInteger(pSet->fonts[0], FC_INDEX, 0, &nCollectionEntry);
    1082         [ #  # ]:          0 :             if (eIndexRes != FcResultMatch)
    1083                 :          0 :                 nCollectionEntry = 0;
    1084         [ #  # ]:          0 :             if( eFileRes == FcResultMatch )
    1085                 :            :             {
    1086                 :          0 :                 OString aDir, aBase, aOrgPath( (sal_Char*)file );
    1087         [ #  # ]:          0 :                 splitPath( aOrgPath, aDir, aBase );
    1088         [ #  # ]:          0 :                 int nDirID = getDirectoryAtom( aDir, true );
    1089         [ #  # ]:          0 :                 fontID aFont = findFontFileID( nDirID, aBase, nCollectionEntry );
    1090         [ #  # ]:          0 :                 if( aFont > 0 )
    1091         [ #  # ]:          0 :                     bSuccess = getFontFastInfo( aFont, rInfo );
    1092                 :            :             }
    1093                 :            :         }
    1094                 :            :         // info: destroying the pSet destroys pResult implicitly
    1095                 :            :         // since pResult was "added" to pSet
    1096         [ #  # ]:          0 :         FcFontSetDestroy( pSet );
    1097                 :            :     }
    1098                 :            : 
    1099                 :            :     // cleanup
    1100         [ #  # ]:          0 :     FcPatternDestroy( pPattern );
    1101                 :            : 
    1102                 :          0 :     return bSuccess;
    1103                 :            : }
    1104                 :            : 
    1105                 :            : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10