LCOV - code coverage report
Current view: top level - vcl/generic/fontmanager - fontconfig.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 519 586 88.6 %
Date: 2015-06-13 12:38:46 Functions: 33 33 100.0 %
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 "fontcache.hxx"
      21             : #include "impfont.hxx"
      22             : #include "fontmanager.hxx"
      23             : #include <vcl/svapp.hxx>
      24             : #include <vcl/sysdata.hxx>
      25             : #include <vcl/vclenum.hxx>
      26             : #include <vcl/wrkwin.hxx>
      27             : #include "outfont.hxx"
      28             : #include <i18nlangtag/languagetag.hxx>
      29             : #include <i18nutil/unicode.hxx>
      30             : #include <rtl/strbuf.hxx>
      31             : #include <unicode/uchar.h>
      32             : #include <unicode/uscript.h>
      33             : 
      34             : using namespace psp;
      35             : 
      36             : #include <fontconfig/fontconfig.h>
      37             : #include <ft2build.h>
      38             : #include <fontconfig/fcfreetype.h>
      39             : 
      40             : #if defined(ENABLE_DBUS) && defined(ENABLE_PACKAGEKIT)
      41             : #include <dbus/dbus-glib.h>
      42             : #endif
      43             : 
      44             : #include <cstdio>
      45             : #include <cstdarg>
      46             : 
      47             : #include "unotools/atom.hxx"
      48             : 
      49             : #include "osl/module.h"
      50             : #include "osl/thread.h"
      51             : #include "osl/process.h"
      52             : 
      53             : #include "rtl/ustrbuf.hxx"
      54             : 
      55             : #include "sal/alloca.h"
      56             : 
      57             : #include <utility>
      58             : #include <algorithm>
      59             : 
      60             : using namespace osl;
      61             : 
      62             : namespace
      63             : {
      64             :     typedef std::pair<FcChar8*, FcChar8*> lang_and_element;
      65             : }
      66             : 
      67             : class FontCfgWrapper
      68             : {
      69             :     FcFontSet* m_pOutlineSet;
      70             : 
      71             :     void addFontSet( FcSetName );
      72             : 
      73             :     FontCfgWrapper();
      74             :     ~FontCfgWrapper();
      75             : 
      76             : public:
      77             :     static FontCfgWrapper& get();
      78             :     static void release();
      79             : 
      80             :     FcFontSet* getFontSet();
      81             : 
      82             :     void clear();
      83             : 
      84             : public:
      85             :     FcResult LocalizedElementFromPattern(FcPattern* pPattern, FcChar8 **family,
      86             :                                          const char *elementtype, const char *elementlangtype);
      87             : //to-do, make private and add some cleanish accessor methods
      88             :     std::unordered_map< OString, OString, OStringHash > m_aFontNameToLocalized;
      89             :     std::unordered_map< OString, OString, OStringHash > m_aLocalizedToCanonical;
      90             : private:
      91             :     void cacheLocalizedFontNames(const FcChar8 *origfontname, const FcChar8 *bestfontname, const std::vector< lang_and_element > &lang_and_elements);
      92             : 
      93             :     LanguageTag* m_pLanguageTag;
      94             : };
      95             : 
      96         205 : FontCfgWrapper::FontCfgWrapper()
      97             :     :
      98             :         m_pOutlineSet( NULL ),
      99         205 :         m_pLanguageTag( NULL )
     100             : {
     101         205 :     FcInit();
     102         205 : }
     103             : 
     104         410 : void FontCfgWrapper::addFontSet( FcSetName eSetName )
     105             : {
     106             :     /*
     107             :       add only acceptable outlined fonts to our config,
     108             :       for future fontconfig use
     109             :     */
     110         410 :     FcFontSet* pOrig = FcConfigGetFonts( FcConfigGetCurrent(), eSetName );
     111         410 :     if( !pOrig )
     112         410 :         return;
     113             : 
     114             :     // filter the font sets to remove obsolete faces
     115      230830 :     for( int i = 0; i < pOrig->nfont; ++i )
     116             :     {
     117      230420 :         FcPattern* pPattern = pOrig->fonts[i];
     118             :         // #i115131# ignore non-outline fonts
     119      230420 :         FcBool bOutline = FcFalse;
     120      230420 :         FcResult eOutRes = FcPatternGetBool( pPattern, FC_OUTLINE, 0, &bOutline );
     121      230420 :         if( (eOutRes != FcResultMatch) || (bOutline == FcFalse) )
     122      175275 :             continue;
     123       55145 :         FcPatternReference( pPattern );
     124       55145 :         FcFontSetAdd( m_pOutlineSet, pPattern );
     125             :     }
     126             : 
     127             :     // TODO?: FcFontSetDestroy( pOrig );
     128             : }
     129             : 
     130             : namespace
     131             : {
     132      646775 :     int compareFontNames(const FcPattern *a, const FcPattern *b)
     133             :     {
     134      646775 :         FcChar8 *pNameA=NULL, *pNameB=NULL;
     135             : 
     136      646775 :         bool nHaveA = FcPatternGetString(a, FC_FAMILY, 0, &pNameA) == FcResultMatch;
     137      646775 :         bool nHaveB = FcPatternGetString(b, FC_FAMILY, 0, &pNameB) == FcResultMatch;
     138             : 
     139      646775 :         if (nHaveA && nHaveB)
     140      646775 :             return strcmp(reinterpret_cast<const char*>(pNameA), reinterpret_cast<const char*>(pNameB));
     141             : 
     142           0 :         return int(nHaveA) - int(nHaveB);
     143             :     }
     144             : 
     145             :     //Sort fonts so that fonts with the same family name are side-by-side, with
     146             :     //those with higher version numbers first
     147             :     class SortFont : public ::std::binary_function< const FcPattern*, const FcPattern*, bool >
     148             :     {
     149             :     public:
     150      468835 :         bool operator()(const FcPattern *a, const FcPattern *b)
     151             :         {
     152      468835 :             int comp = compareFontNames(a, b);
     153      468835 :             if (comp != 0)
     154      389705 :                 return comp < 0;
     155             : 
     156       79130 :             int nVersionA=0, nVersionB=0;
     157             : 
     158       79130 :             bool nHaveA = FcPatternGetInteger(a, FC_FONTVERSION, 0, &nVersionA) == FcResultMatch;
     159       79130 :             bool nHaveB = FcPatternGetInteger(b, FC_FONTVERSION, 0, &nVersionB) == FcResultMatch;
     160             : 
     161       79130 :             if (nHaveA && nHaveB)
     162       79130 :                 return nVersionA > nVersionB;
     163             : 
     164           0 :             return nHaveA > nHaveB;
     165             :         }
     166             :     };
     167             : 
     168             :     //See fdo#30729 for where an old opensymbol installed system-wide can
     169             :     //clobber the new opensymbol installed locally
     170             : 
     171             :     //See if this font is a duplicate with equal attributes which has already been
     172             :     //inserted, or if it an older version of an inserted fonts. Depends on FcFontSet
     173             :     //on being sorted with SortFont
     174       55145 :     bool isPreviouslyDuplicateOrObsoleted(FcFontSet *pFSet, int i)
     175             :     {
     176       55145 :         const FcPattern *a = pFSet->fonts[i];
     177             : 
     178       55145 :         FcPattern* pTestPatternA = FcPatternDuplicate(a);
     179       55145 :         FcPatternDel(pTestPatternA, FC_FILE);
     180       55145 :         FcPatternDel(pTestPatternA, FC_CHARSET);
     181       55145 :         FcPatternDel(pTestPatternA, FC_CAPABILITY);
     182       55145 :         FcPatternDel(pTestPatternA, FC_FONTVERSION);
     183       55145 :         FcPatternDel(pTestPatternA, FC_LANG);
     184             : 
     185       55145 :         bool bIsDup(false);
     186             : 
     187             :         // fdo#66715: loop for case of several font files for same font
     188      185525 :         for (int j = i - 1; 0 <= j && !bIsDup; --j)
     189             :         {
     190      177940 :             const FcPattern *b = pFSet->fonts[j];
     191             : 
     192      177940 :             if (compareFontNames(a, b) != 0)
     193       47560 :                 break;
     194             : 
     195      130380 :             FcPattern* pTestPatternB = FcPatternDuplicate(b);
     196      130380 :             FcPatternDel(pTestPatternB, FC_FILE);
     197      130380 :             FcPatternDel(pTestPatternB, FC_CHARSET);
     198      130380 :             FcPatternDel(pTestPatternB, FC_CAPABILITY);
     199      130380 :             FcPatternDel(pTestPatternB, FC_FONTVERSION);
     200      130380 :             FcPatternDel(pTestPatternB, FC_LANG);
     201             : 
     202      130380 :             bIsDup = FcPatternEqual(pTestPatternA, pTestPatternB);
     203             : 
     204      130380 :             FcPatternDestroy(pTestPatternB);
     205             :         }
     206             : 
     207       55145 :         FcPatternDestroy(pTestPatternA);
     208             : 
     209       55145 :         return bIsDup;
     210             :     }
     211             : }
     212             : 
     213       11572 : FcFontSet* FontCfgWrapper::getFontSet()
     214             : {
     215       11572 :     if( !m_pOutlineSet )
     216             :     {
     217         205 :         m_pOutlineSet = FcFontSetCreate();
     218         205 :         addFontSet( FcSetSystem );
     219         205 :         if( FcGetVersion() > 20400 ) // #i85462# prevent crashes
     220         205 :             addFontSet( FcSetApplication );
     221             : 
     222         205 :         ::std::sort(m_pOutlineSet->fonts,m_pOutlineSet->fonts+m_pOutlineSet->nfont,SortFont());
     223             :     }
     224             : 
     225       11572 :     return m_pOutlineSet;
     226             : }
     227             : 
     228         410 : FontCfgWrapper::~FontCfgWrapper()
     229             : {
     230         205 :     clear();
     231             :     //To-Do: get gtk vclplug smoketest to pass
     232             :     //FcFini();
     233         205 : }
     234             : 
     235             : static FontCfgWrapper* pOneInstance = NULL;
     236             : 
     237       11777 : FontCfgWrapper& FontCfgWrapper::get()
     238             : {
     239       11777 :     if( ! pOneInstance )
     240         205 :         pOneInstance = new FontCfgWrapper();
     241       11777 :     return *pOneInstance;
     242             : }
     243             : 
     244         205 : void FontCfgWrapper::release()
     245             : {
     246         205 :     if( pOneInstance )
     247             :     {
     248         205 :         delete pOneInstance;
     249         205 :         pOneInstance = NULL;
     250             :     }
     251         205 : }
     252             : 
     253             : namespace
     254             : {
     255             :     static FcChar8* bestname(const std::vector<lang_and_element> &elements, const LanguageTag & rLangTag);
     256             : 
     257       84050 :     FcChar8* bestname(const std::vector<lang_and_element> &elements, const LanguageTag & rLangTag)
     258             :     {
     259       84050 :         FcChar8* candidate = elements.begin()->second;
     260             :         /* FIXME-BCP47: once fontconfig supports language tags this
     261             :          * language-territory stuff needs to be changed! */
     262             :         SAL_INFO_IF( !rLangTag.isIsoLocale(), "i18n", "localizedsorter::bestname - not an ISO locale");
     263       84050 :         OString sLangMatch(OUStringToOString(rLangTag.getLanguage().toAsciiLowerCase(), RTL_TEXTENCODING_UTF8));
     264      168100 :         OString sFullMatch = sLangMatch;
     265       84050 :         sFullMatch += OString('-');
     266       84050 :         sFullMatch += OUStringToOString(rLangTag.getCountry().toAsciiLowerCase(), RTL_TEXTENCODING_UTF8);
     267             : 
     268       84050 :         std::vector<lang_and_element>::const_iterator aEnd = elements.end();
     269       84050 :         bool alreadyclosematch = false;
     270       84050 :         bool found_fallback_englishname = false;
     271      181015 :         for( std::vector<lang_and_element>::const_iterator aIter = elements.begin(); aIter != aEnd; ++aIter )
     272             :         {
     273       96965 :             const char *pLang = reinterpret_cast<const char*>(aIter->first);
     274       96965 :             if( rtl_str_compare( pLang, sFullMatch.getStr() ) == 0)
     275             :             {
     276             :                 // both language and country match
     277           0 :                 candidate = aIter->second;
     278           0 :                 break;
     279             :             }
     280       96965 :             else if( alreadyclosematch )
     281             :             {
     282             :                 // current candidate matches lang of lang-TERRITORY
     283             :                 // override candidate only if there is a full match
     284       11275 :                 continue;
     285             :             }
     286       85690 :             else if( rtl_str_compare( pLang, sLangMatch.getStr()) == 0)
     287             :             {
     288             :                 // just the language matches
     289       83230 :                 candidate = aIter->second;
     290       83230 :                 alreadyclosematch = true;
     291             :             }
     292        2460 :             else if( found_fallback_englishname )
     293             :             {
     294             :                 // already found an english fallback, don't override candidate
     295             :                 // unless there is a better language match
     296           0 :                 continue;
     297             :             }
     298        2460 :             else if( rtl_str_compare( pLang, "en") == 0)
     299             :             {
     300             :                 // select a fallback candidate of the first english element
     301             :                 // name
     302           0 :                 candidate = aIter->second;
     303           0 :                 found_fallback_englishname = true;
     304             :             }
     305             :         }
     306      168100 :         return candidate;
     307             :     }
     308             : }
     309             : 
     310             : //Set up maps to quickly map between a fonts best UI name and all the rest of its names, and vice versa
     311       42025 : void FontCfgWrapper::cacheLocalizedFontNames(const FcChar8 *origfontname, const FcChar8 *bestfontname,
     312             :     const std::vector< lang_and_element > &lang_and_elements)
     313             : {
     314       42025 :     std::vector<lang_and_element>::const_iterator aEnd = lang_and_elements.end();
     315       90815 :     for (std::vector<lang_and_element>::const_iterator aIter = lang_and_elements.begin(); aIter != aEnd; ++aIter)
     316             :     {
     317       48790 :         const char *candidate = reinterpret_cast<const char*>(aIter->second);
     318       48790 :         if (rtl_str_compare(candidate, reinterpret_cast<const char*>(bestfontname)) != 0)
     319        6765 :             m_aFontNameToLocalized[OString(candidate)] = OString(reinterpret_cast<const char*>(bestfontname));
     320             :     }
     321       42025 :     if (rtl_str_compare(reinterpret_cast<const char*>(origfontname), reinterpret_cast<const char*>(bestfontname)) != 0)
     322        1025 :         m_aLocalizedToCanonical[OString(reinterpret_cast<const char*>(bestfontname))] = OString(reinterpret_cast<const char*>(origfontname));
     323       42025 : }
     324             : 
     325      110290 : FcResult FontCfgWrapper::LocalizedElementFromPattern(FcPattern* pPattern, FcChar8 **element,
     326             :                                                      const char *elementtype, const char *elementlangtype)
     327             : {                                                /* e. g.:      ^ FC_FAMILY              ^ FC_FAMILYLANG */
     328             :     FcChar8 *origelement;
     329      110290 :     FcResult eElementRes = FcPatternGetString( pPattern, elementtype, 0, &origelement );
     330      110290 :     *element = origelement;
     331             : 
     332      110290 :     if( eElementRes == FcResultMatch)
     333             :     {
     334      110290 :         FcChar8* elementlang = NULL;
     335      110290 :         if (FcPatternGetString( pPattern, elementlangtype, 0, &elementlang ) == FcResultMatch)
     336             :         {
     337       84050 :             std::vector< lang_and_element > lang_and_elements;
     338       84050 :             lang_and_elements.push_back(lang_and_element(elementlang, *element));
     339       84050 :             int k = 1;
     340             :             while (true)
     341             :             {
     342       96965 :                 if (FcPatternGetString( pPattern, elementlangtype, k, &elementlang ) != FcResultMatch)
     343       84050 :                     break;
     344       12915 :                 if (FcPatternGetString( pPattern, elementtype, k, element ) != FcResultMatch)
     345           0 :                     break;
     346       12915 :                 lang_and_elements.push_back(lang_and_element(elementlang, *element));
     347       12915 :                 ++k;
     348             :             }
     349             : 
     350             :             //possible to-do, sort by UILocale instead of process locale
     351       84050 :             if (!m_pLanguageTag)
     352             :             {
     353         205 :                 rtl_Locale* pLoc = NULL;
     354         205 :                 osl_getProcessLocale(&pLoc);
     355         205 :                 m_pLanguageTag = new LanguageTag(*pLoc);
     356             :             }
     357       84050 :             *element = bestname(lang_and_elements, *m_pLanguageTag);
     358             : 
     359             :             //if this element is a fontname, map the other names to this best-name
     360       84050 :             if (rtl_str_compare(elementtype, FC_FAMILY) == 0)
     361       42025 :                 cacheLocalizedFontNames(origelement, *element, lang_and_elements);
     362             :         }
     363             :     }
     364             : 
     365      110290 :     return eElementRes;
     366             : }
     367             : 
     368         410 : void FontCfgWrapper::clear()
     369             : {
     370         410 :     m_aFontNameToLocalized.clear();
     371         410 :     m_aLocalizedToCanonical.clear();
     372         410 :     if( m_pOutlineSet )
     373             :     {
     374         205 :         FcFontSetDestroy( m_pOutlineSet );
     375         205 :         m_pOutlineSet = NULL;
     376             :     }
     377         410 :     delete m_pLanguageTag;
     378         410 :     m_pLanguageTag = NULL;
     379         410 : }
     380             : 
     381             : /*
     382             :  * PrintFontManager::initFontconfig
     383             :  */
     384         205 : void PrintFontManager::initFontconfig()
     385             : {
     386         205 :     FontCfgWrapper& rWrapper = FontCfgWrapper::get();
     387         205 :     rWrapper.clear();
     388         205 : }
     389             : 
     390             : namespace
     391             : {
     392       59494 :     FontWeight convertWeight(int weight)
     393             :     {
     394             :         // set weight
     395       59494 :         if( weight <= FC_WEIGHT_THIN )
     396           0 :             return WEIGHT_THIN;
     397       59494 :         else if( weight <= FC_WEIGHT_ULTRALIGHT )
     398         642 :             return WEIGHT_ULTRALIGHT;
     399       58852 :         else if( weight <= FC_WEIGHT_LIGHT )
     400         820 :             return WEIGHT_LIGHT;
     401       58032 :         else if( weight <= FC_WEIGHT_BOOK )
     402         410 :             return WEIGHT_SEMILIGHT;
     403       57622 :         else if( weight <= FC_WEIGHT_NORMAL )
     404       29455 :             return WEIGHT_NORMAL;
     405       28167 :         else if( weight <= FC_WEIGHT_MEDIUM )
     406        5802 :             return WEIGHT_MEDIUM;
     407       22365 :         else if( weight <= FC_WEIGHT_SEMIBOLD )
     408        2050 :             return WEIGHT_SEMIBOLD;
     409       20315 :         else if( weight <= FC_WEIGHT_BOLD )
     410       19905 :             return WEIGHT_BOLD;
     411         410 :         else if( weight <= FC_WEIGHT_ULTRABOLD )
     412           0 :             return WEIGHT_ULTRABOLD;
     413         410 :         return WEIGHT_BLACK;
     414             :     }
     415             : 
     416       59494 :     FontItalic convertSlant(int slant)
     417             :     {
     418             :         // set italic
     419       59494 :         if( slant == FC_SLANT_ITALIC )
     420       15992 :             return ITALIC_NORMAL;
     421       43502 :         else if( slant == FC_SLANT_OBLIQUE )
     422        4746 :             return ITALIC_OBLIQUE;
     423       38756 :         return ITALIC_NONE;
     424             :     }
     425             : 
     426       17067 :     FontPitch convertSpacing(int spacing)
     427             :     {
     428             :         // set pitch
     429       17067 :         if( spacing == FC_MONO || spacing == FC_CHARCELL )
     430        7538 :             return PITCH_FIXED;
     431        9529 :         return PITCH_VARIABLE;
     432             :     }
     433             : 
     434             :     // translation: fontconfig enum -> vcl enum
     435       59494 :     FontWidth convertWidth(int width)
     436             :     {
     437       59494 :         if (width == FC_WIDTH_ULTRACONDENSED)
     438           0 :             return WIDTH_ULTRA_CONDENSED;
     439       59494 :         else if (width == FC_WIDTH_EXTRACONDENSED)
     440           0 :             return WIDTH_EXTRA_CONDENSED;
     441       59494 :         else if (width == FC_WIDTH_CONDENSED)
     442        1658 :             return WIDTH_CONDENSED;
     443       57836 :         else if (width == FC_WIDTH_SEMICONDENSED)
     444        1640 :             return WIDTH_SEMI_CONDENSED;
     445       56196 :         else if (width == FC_WIDTH_SEMIEXPANDED)
     446           0 :             return WIDTH_SEMI_EXPANDED;
     447       56196 :         else if (width == FC_WIDTH_EXPANDED)
     448           0 :             return WIDTH_EXPANDED;
     449       56196 :         else if (width == FC_WIDTH_EXTRAEXPANDED)
     450           0 :             return WIDTH_EXTRA_EXPANDED;
     451       56196 :         else if (width == FC_WIDTH_ULTRAEXPANDED)
     452           0 :             return WIDTH_ULTRA_EXPANDED;
     453       56196 :         return WIDTH_NORMAL;
     454             :     }
     455             : }
     456             : 
     457             : //FontConfig doesn't come with a way to remove an element from a FontSet as far
     458             : //as I can see
     459         205 : static void lcl_FcFontSetRemove(FcFontSet* pFSet, int i)
     460             : {
     461         205 :     FcPatternDestroy(pFSet->fonts[i]);
     462             : 
     463         205 :     int nTail = pFSet->nfont - (i + 1);
     464         205 :     --pFSet->nfont;
     465         205 :     if (!nTail)
     466         205 :         return;
     467         205 :     memmove(pFSet->fonts + i, pFSet->fonts + i + 1, nTail*sizeof(FcPattern*));
     468             : }
     469             : 
     470         205 : void PrintFontManager::countFontconfigFonts( std::unordered_map<OString, int, OStringHash>& o_rVisitedPaths )
     471             : {
     472             : #if OSL_DEBUG_LEVEL > 1
     473             :     int nFonts = 0;
     474             : #endif
     475         205 :     FontCfgWrapper& rWrapper = FontCfgWrapper::get();
     476             : 
     477         205 :     FcFontSet* pFSet = rWrapper.getFontSet();
     478         205 :     if( pFSet )
     479             :     {
     480             : #if OSL_DEBUG_LEVEL > 1
     481             :         fprintf( stderr, "found %d entries in fontconfig fontset\n", pFSet->nfont );
     482             : #endif
     483       55350 :         for( int i = 0; i < pFSet->nfont; i++ )
     484             :         {
     485       55145 :             FcChar8* file = NULL;
     486       55145 :             FcChar8* family = NULL;
     487       55145 :             FcChar8* style = NULL;
     488       55145 :             FcChar8* format = NULL;
     489       55145 :             int slant = 0;
     490       55145 :             int weight = 0;
     491       55145 :             int width = 0;
     492       55145 :             int spacing = 0;
     493       55145 :             int nCollectionEntry = -1;
     494       55145 :             FcBool outline = false;
     495             : 
     496       55145 :             FcResult eFileRes         = FcPatternGetString(pFSet->fonts[i], FC_FILE, 0, &file);
     497       55145 :             FcResult eFamilyRes       = rWrapper.LocalizedElementFromPattern( pFSet->fonts[i], &family, FC_FAMILY, FC_FAMILYLANG );
     498       55145 :             FcResult eStyleRes        = rWrapper.LocalizedElementFromPattern( pFSet->fonts[i], &style, FC_STYLE, FC_STYLELANG );
     499       55145 :             FcResult eSlantRes        = FcPatternGetInteger(pFSet->fonts[i], FC_SLANT, 0, &slant);
     500       55145 :             FcResult eWeightRes       = FcPatternGetInteger(pFSet->fonts[i], FC_WEIGHT, 0, &weight);
     501       55145 :             FcResult eWidthRes        = FcPatternGetInteger(pFSet->fonts[i], FC_WIDTH, 0, &width);
     502       55145 :             FcResult eSpacRes         = FcPatternGetInteger(pFSet->fonts[i], FC_SPACING, 0, &spacing);
     503       55145 :             FcResult eOutRes          = FcPatternGetBool(pFSet->fonts[i], FC_OUTLINE, 0, &outline);
     504       55145 :             FcResult eIndexRes        = FcPatternGetInteger(pFSet->fonts[i], FC_INDEX, 0, &nCollectionEntry);
     505       55145 :             FcResult eFormatRes       = FcPatternGetString(pFSet->fonts[i], FC_FONTFORMAT, 0, &format);
     506             : 
     507       55145 :             if( eFileRes != FcResultMatch || eFamilyRes != FcResultMatch || eOutRes != FcResultMatch )
     508        6970 :                 continue;
     509             : 
     510             : #if (OSL_DEBUG_LEVEL > 2)
     511             :             fprintf( stderr, "found font \"%s\" in file %s\n"
     512             :                      "   weight = %d, slant = %d, style = \"%s\"\n"
     513             :                      "   width = %d, spacing = %d, outline = %d, format %s\n"
     514             :                      , family, file
     515             :                      , eWeightRes == FcResultMatch ? weight : -1
     516             :                      , eSpacRes == FcResultMatch ? slant : -1
     517             :                      , eStyleRes == FcResultMatch ? (const char*) style : "<nil>"
     518             :                      , eWeightRes == FcResultMatch ? width : -1
     519             :                      , eSpacRes == FcResultMatch ? spacing : -1
     520             :                      , eOutRes == FcResultMatch ? outline : -1
     521             :                      , eFormatRes == FcResultMatch ? (const char*)format : "<unknown>"
     522             :                      );
     523             : #endif
     524             : 
     525             : //            OSL_ASSERT(eOutRes != FcResultMatch || outline);
     526             : 
     527             :             // only outline fonts are usable to psprint anyway
     528       55145 :             if( eOutRes == FcResultMatch && ! outline )
     529           0 :                 continue;
     530             : 
     531       55145 :             if (isPreviouslyDuplicateOrObsoleted(pFSet, i))
     532             :             {
     533             : #if OSL_DEBUG_LEVEL > 2
     534             :                 fprintf(stderr, "Ditching %s as duplicate/obsolete\n", file);
     535             : #endif
     536        6765 :                 continue;
     537             :             }
     538             : 
     539             :             // see if this font is already cached
     540             :             // update attributes
     541       48380 :             std::list< PrintFont* > aFonts;
     542       96555 :             OString aDir, aBase, aOrgPath( reinterpret_cast<char*>(file) );
     543       48380 :             splitPath( aOrgPath, aDir, aBase );
     544             : 
     545       48380 :             o_rVisitedPaths[aDir] = 1;
     546             : 
     547       48380 :             int nDirID = getDirectoryAtom( aDir, true );
     548       48380 :             if( ! m_pFontCache->getFontCacheFile( nDirID, aBase, aFonts ) )
     549             :             {
     550             : #if OSL_DEBUG_LEVEL > 2
     551             :                 fprintf( stderr, "file %s not cached\n", aBase.getStr() );
     552             : #endif
     553             :                 // not known, analyze font file to get attributes
     554             :                 // not described by fontconfig (e.g. alias names, PSName)
     555       13777 :                 if (eFormatRes != FcResultMatch)
     556           0 :                     format = NULL;
     557       13777 :                 analyzeFontFile( nDirID, aBase, aFonts, reinterpret_cast<char*>(format) );
     558             : #if OSL_DEBUG_LEVEL > 1
     559             :                 if( aFonts.empty() )
     560             :                     fprintf( stderr, "Warning: file \"%s\" is unusable to psprint\n", aOrgPath.getStr() );
     561             : #endif
     562             :             }
     563       48380 :             if( aFonts.empty() )
     564             :             {
     565             :                 //remove font, reuse index
     566             :                 //we want to remove unusable fonts here, in case there is a usable font
     567             :                 //which duplicates the properties of the unusable one
     568             : 
     569             :                 //not removing the unusable font will risk the usable font being rejected
     570             :                 //as a duplicate by isPreviouslyDuplicateOrObsoleted
     571         205 :                 lcl_FcFontSetRemove(pFSet, i--);
     572         205 :                 continue;
     573             :             }
     574             : 
     575       48175 :             int nFamilyName = m_pAtoms->getAtom( ATOM_FAMILYNAME, OStringToOUString( OString( reinterpret_cast<char*>(family) ), RTL_TEXTENCODING_UTF8 ), true );
     576       48175 :             PrintFont* pUpdate = aFonts.front();
     577       48175 :             std::list<PrintFont*>::const_iterator second_font = aFonts.begin();
     578       48175 :             ++second_font;
     579       48175 :             if( second_font != aFonts.end() ) // more than one font
     580             :             {
     581             :                 // a collection entry, get the correct index
     582         410 :                 if( eIndexRes == FcResultMatch && nCollectionEntry != -1 )
     583             :                 {
     584         615 :                     for( std::list< PrintFont* >::iterator it = aFonts.begin(); it != aFonts.end(); ++it )
     585             :                     {
     586        1230 :                         if( (*it)->m_eType == fonttype::TrueType &&
     587         615 :                             static_cast<TrueTypeFontFile*>(*it)->m_nCollectionEntry == nCollectionEntry )
     588             :                         {
     589         410 :                             pUpdate = *it;
     590         410 :                             break;
     591             :                         }
     592             :                     }
     593             :                     // update collection entry
     594             :                     // additional entries will be created in the cache
     595             :                     // if this is a new index (that is if the loop above
     596             :                     // ran to the end of the list)
     597         410 :                     if( pUpdate->m_eType == fonttype::TrueType ) // sanity check, this should always be the case here
     598         410 :                         static_cast<TrueTypeFontFile*>(pUpdate)->m_nCollectionEntry = nCollectionEntry;
     599             :                 }
     600             :                 else
     601             :                 {
     602             : #if OSL_DEBUG_LEVEL > 1
     603             :                     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 );
     604             : #endif
     605             :                     // we have found more than one font in this file
     606             :                     // but fontconfig will not tell us which index is meant
     607             :                     // -> something is in disorder, do not use this font
     608           0 :                     pUpdate = NULL;
     609             :                 }
     610             :             }
     611             : 
     612       48175 :             if( pUpdate )
     613             :             {
     614             :                 // set family name
     615       48175 :                 if( pUpdate->m_nFamilyName != nFamilyName )
     616             :                 {
     617             :                 }
     618       48175 :                 if( eWeightRes == FcResultMatch )
     619       48175 :                     pUpdate->m_eWeight = convertWeight(weight);
     620       48175 :                 if( eWidthRes == FcResultMatch )
     621       48175 :                     pUpdate->m_eWidth = convertWidth(width);
     622       48175 :                 if( eSpacRes == FcResultMatch )
     623        7585 :                     pUpdate->m_ePitch = convertSpacing(spacing);
     624       48175 :                 if( eSlantRes == FcResultMatch )
     625       48175 :                     pUpdate->m_eItalic = convertSlant(slant);
     626       48175 :                 if( eStyleRes == FcResultMatch )
     627             :                 {
     628       48175 :                     pUpdate->m_aStyleName = OStringToOUString( OString( reinterpret_cast<char*>(style) ), RTL_TEXTENCODING_UTF8 );
     629             :                 }
     630             : 
     631             :                 // update font cache
     632       48175 :                 m_pFontCache->updateFontCacheEntry( pUpdate, false );
     633             :                 // sort into known fonts
     634       48175 :                 fontID aFont = m_nNextFontID++;
     635       48175 :                 m_aFonts[ aFont ] = pUpdate;
     636       48175 :                 m_aFontFileToFontID[ aBase ].insert( aFont );
     637             : #if OSL_DEBUG_LEVEL > 1
     638             :                 nFonts++;
     639             : #endif
     640             : #if OSL_DEBUG_LEVEL > 2
     641             :                 fprintf( stderr, "inserted font %s as fontID %d\n", family, aFont );
     642             : #endif
     643             :             }
     644             :             // clean up the fonts we did not put into the list
     645       96760 :             for( std::list< PrintFont* >::iterator it = aFonts.begin(); it != aFonts.end(); ++it )
     646             :             {
     647       48585 :                 if( *it != pUpdate )
     648             :                 {
     649         410 :                     m_pFontCache->updateFontCacheEntry( *it, false ); // prepare a cache entry for a collection item
     650         410 :                     delete *it;
     651             :                 }
     652             :             }
     653       48175 :         }
     654             :     }
     655             : 
     656             :     // how does one get rid of the config ?
     657             : #if OSL_DEBUG_LEVEL > 1
     658             :     fprintf( stderr, "inserted %d fonts from fontconfig\n", nFonts );
     659             : #endif
     660         205 : }
     661             : 
     662         205 : void PrintFontManager::deinitFontconfig()
     663             : {
     664         205 :     FontCfgWrapper::release();
     665         205 : }
     666             : 
     667         615 : bool PrintFontManager::addFontconfigDir( const OString& rDirName )
     668             : {
     669             :     // workaround for a stability problems in older FC versions
     670             :     // when handling application specific fonts
     671         615 :     const int nVersion = FcGetVersion();
     672         615 :     if( nVersion <= 20400 )
     673           0 :         return false;
     674         615 :     const char* pDirName = rDirName.getStr();
     675         615 :     bool bDirOk = (FcConfigAppFontAddDir(FcConfigGetCurrent(), reinterpret_cast<FcChar8 const *>(pDirName) ) == FcTrue);
     676             : 
     677             : #if OSL_DEBUG_LEVEL > 1
     678             :     fprintf( stderr, "FcConfigAppFontAddDir( \"%s\") => %d\n", pDirName, bDirOk );
     679             : #endif
     680             : 
     681         615 :     if( !bDirOk )
     682           0 :         return false;
     683             : 
     684             :     // load dir-specific fc-config file too if available
     685         615 :     const OString aConfFileName = rDirName + "/fc_local.conf";
     686         615 :     FILE* pCfgFile = fopen( aConfFileName.getStr(), "rb" );
     687         615 :     if( pCfgFile )
     688             :     {
     689         205 :         fclose( pCfgFile);
     690             :         bool bCfgOk = FcConfigParseAndLoad(FcConfigGetCurrent(),
     691         205 :                         reinterpret_cast<FcChar8 const *>(aConfFileName.getStr()), FcTrue);
     692         205 :         if( !bCfgOk )
     693           0 :             fprintf( stderr, "FcConfigParseAndLoad( \"%s\") => %d\n", aConfFileName.getStr(), bCfgOk );
     694             :     }
     695             : 
     696         615 :     return true;
     697             : }
     698             : 
     699       11367 : static void addtopattern(FcPattern *pPattern,
     700             :     FontItalic eItalic, FontWeight eWeight, FontWidth eWidth, FontPitch ePitch)
     701             : {
     702       11367 :     if( eItalic != ITALIC_DONTKNOW )
     703             :     {
     704       11367 :         int nSlant = FC_SLANT_ROMAN;
     705       11367 :         switch( eItalic )
     706             :         {
     707             :             case ITALIC_NORMAL:
     708         529 :                 nSlant = FC_SLANT_ITALIC;
     709         529 :                 break;
     710             :             case ITALIC_OBLIQUE:
     711         115 :                 nSlant = FC_SLANT_OBLIQUE;
     712         115 :                 break;
     713             :             default:
     714       10723 :                 break;
     715             :         }
     716       11367 :         FcPatternAddInteger(pPattern, FC_SLANT, nSlant);
     717             :     }
     718       11367 :     if( eWeight != WEIGHT_DONTKNOW )
     719             :     {
     720       11171 :         int nWeight = FC_WEIGHT_NORMAL;
     721       11171 :         switch( eWeight )
     722             :         {
     723          92 :             case WEIGHT_THIN:           nWeight = FC_WEIGHT_THIN;break;
     724          12 :             case WEIGHT_ULTRALIGHT:     nWeight = FC_WEIGHT_ULTRALIGHT;break;
     725          45 :             case WEIGHT_LIGHT:          nWeight = FC_WEIGHT_LIGHT;break;
     726           7 :             case WEIGHT_SEMILIGHT:      nWeight = FC_WEIGHT_BOOK;break;
     727        5385 :             case WEIGHT_NORMAL:         nWeight = FC_WEIGHT_NORMAL;break;
     728        3752 :             case WEIGHT_MEDIUM:         nWeight = FC_WEIGHT_MEDIUM;break;
     729           0 :             case WEIGHT_SEMIBOLD:       nWeight = FC_WEIGHT_SEMIBOLD;break;
     730        1733 :             case WEIGHT_BOLD:           nWeight = FC_WEIGHT_BOLD;break;
     731          98 :             case WEIGHT_ULTRABOLD:      nWeight = FC_WEIGHT_ULTRABOLD;break;
     732          47 :             case WEIGHT_BLACK:          nWeight = FC_WEIGHT_BLACK;break;
     733             :             default:
     734           0 :                 break;
     735             :         }
     736       11171 :         FcPatternAddInteger(pPattern, FC_WEIGHT, nWeight);
     737             :     }
     738       11367 :     if( eWidth != WIDTH_DONTKNOW )
     739             :     {
     740        5403 :         int nWidth = FC_WIDTH_NORMAL;
     741        5403 :         switch( eWidth )
     742             :         {
     743           0 :             case WIDTH_ULTRA_CONDENSED: nWidth = FC_WIDTH_ULTRACONDENSED;break;
     744           0 :             case WIDTH_EXTRA_CONDENSED: nWidth = FC_WIDTH_EXTRACONDENSED;break;
     745           0 :             case WIDTH_CONDENSED:       nWidth = FC_WIDTH_CONDENSED;break;
     746           0 :             case WIDTH_SEMI_CONDENSED:  nWidth = FC_WIDTH_SEMICONDENSED;break;
     747        5403 :             case WIDTH_NORMAL:          nWidth = FC_WIDTH_NORMAL;break;
     748           0 :             case WIDTH_SEMI_EXPANDED:   nWidth = FC_WIDTH_SEMIEXPANDED;break;
     749           0 :             case WIDTH_EXPANDED:        nWidth = FC_WIDTH_EXPANDED;break;
     750           0 :             case WIDTH_EXTRA_EXPANDED:  nWidth = FC_WIDTH_EXTRAEXPANDED;break;
     751           0 :             case WIDTH_ULTRA_EXPANDED:  nWidth = FC_WIDTH_ULTRAEXPANDED;break;
     752             :             default:
     753           0 :                 break;
     754             :         }
     755        5403 :         FcPatternAddInteger(pPattern, FC_WIDTH, nWidth);
     756             :     }
     757       11367 :     if( ePitch != PITCH_DONTKNOW )
     758             :     {
     759        9479 :         int nSpacing = FC_PROPORTIONAL;
     760        9479 :         switch( ePitch )
     761             :         {
     762          63 :             case PITCH_FIXED:           nSpacing = FC_MONO;break;
     763        8950 :             case PITCH_VARIABLE:        nSpacing = FC_PROPORTIONAL;break;
     764             :             default:
     765         466 :                 break;
     766             :         }
     767        9479 :         FcPatternAddInteger(pPattern, FC_SPACING, nSpacing);
     768        9479 :         if (nSpacing == FC_MONO)
     769          63 :             FcPatternAddString(pPattern, FC_FAMILY, reinterpret_cast<FcChar8 const *>("monospace"));
     770             :     }
     771       11367 : }
     772             : 
     773             : namespace
     774             : {
     775             :     //Someday fontconfig will hopefully use bcp47, see fdo#19869
     776             :     //In the meantime try something that will fit to workaround fdo#35118
     777       11344 :     OString mapToFontConfigLangTag(const LanguageTag &rLangTag)
     778             :     {
     779             : #if defined(FC_VERSION) && (FC_VERSION >= 20492)
     780       11344 :         std::shared_ptr<FcStrSet> xLangSet(FcGetLangs(), FcStrSetDestroy);
     781       22688 :         OString sLangAttrib;
     782             : 
     783       11344 :         sLangAttrib = OUStringToOString(rLangTag.getBcp47(), RTL_TEXTENCODING_UTF8).toAsciiLowerCase();
     784       11344 :         if (FcStrSetMember(xLangSet.get(), reinterpret_cast<const FcChar8*>(sLangAttrib.getStr())))
     785             :         {
     786        3830 :             return sLangAttrib;
     787             :         }
     788             : 
     789        7514 :         sLangAttrib = OUStringToOString(rLangTag.getLanguageAndScript(), RTL_TEXTENCODING_UTF8).toAsciiLowerCase();
     790        7514 :         if (FcStrSetMember(xLangSet.get(), reinterpret_cast<const FcChar8*>(sLangAttrib.getStr())))
     791             :         {
     792        7450 :             return sLangAttrib;
     793             :         }
     794             : 
     795         128 :         OString sLang = OUStringToOString(rLangTag.getLanguage(), RTL_TEXTENCODING_UTF8).toAsciiLowerCase();
     796         128 :         OString sRegion = OUStringToOString(rLangTag.getCountry(), RTL_TEXTENCODING_UTF8).toAsciiLowerCase();
     797             : 
     798          64 :         if (!sRegion.isEmpty())
     799             :         {
     800           0 :             sLangAttrib = sLang + OString('-') + sRegion;
     801           0 :             if (FcStrSetMember(xLangSet.get(), reinterpret_cast<const FcChar8*>(sLangAttrib.getStr())))
     802             :             {
     803           0 :                 return sLangAttrib;
     804             :             }
     805             :         }
     806             : 
     807          64 :         if (FcStrSetMember(xLangSet.get(), reinterpret_cast<const FcChar8*>(sLang.getStr())))
     808             :         {
     809           0 :             return sLang;
     810             :         }
     811             : 
     812       11408 :         return OString();
     813             : #else
     814             :         OString sLangAttrib = OUStringToOString(rLangTag.getLanguageAndScript(), RTL_TEXTENCODING_UTF8).toAsciiLowerCase();
     815             :         if (sLangAttrib.equalsIgnoreAsciiCase("pa-in"))
     816             :             sLangAttrib = "pa";
     817             :         return sLangAttrib;
     818             : #endif
     819             :     }
     820             : 
     821             :     //returns true if the given code-point couldn't possibly be in rLangTag.
     822        5613 :     bool isImpossibleCodePointForLang(const LanguageTag &rLangTag, sal_uInt32 currentChar)
     823             :     {
     824             :         //a non-default script is set, lets believe it
     825        5613 :         if (rLangTag.hasScript())
     826           0 :             return false;
     827             : 
     828        5613 :         int32_t script = u_getIntPropertyValue(currentChar, UCHAR_SCRIPT);
     829        5613 :         UScriptCode eScript = static_cast<UScriptCode>(script);
     830        5613 :         bool bIsImpossible = false;
     831        5613 :         OUString sLang = rLangTag.getLanguage();
     832        5613 :         switch (eScript)
     833             :         {
     834             :             //http://en.wiktionary.org/wiki/Category:Oriya_script_languages
     835             :             case USCRIPT_ORIYA:
     836             :                 bIsImpossible =
     837           0 :                     sLang != "or" &&
     838           0 :                     sLang != "kxv";
     839           0 :                 break;
     840             :             //http://en.wiktionary.org/wiki/Category:Telugu_script_languages
     841             :             case USCRIPT_TELUGU:
     842             :                 bIsImpossible =
     843           0 :                     sLang != "te" &&
     844           0 :                     sLang != "gon" &&
     845           0 :                     sLang != "kfc";
     846           0 :                 break;
     847             :             //http://en.wiktionary.org/wiki/Category:Bengali_script_languages
     848             :             case USCRIPT_BENGALI:
     849             :                 bIsImpossible =
     850           0 :                     sLang != "bn" &&
     851           0 :                     sLang != "as" &&
     852           0 :                     sLang != "bpy" &&
     853           0 :                     sLang != "ctg" &&
     854           0 :                     sLang != "sa";
     855           0 :                 break;
     856             :             default:
     857        5613 :                 break;
     858             :         }
     859             :         SAL_WARN_IF(bIsImpossible, "vcl", "In glyph fallback throwing away the language property of "
     860             :             << sLang << " because the detected script for '0x"
     861             :             << OUString::number(currentChar, 16)
     862             :             << "' is " << uscript_getName(eScript)
     863             :             << " and that language doesn't make sense. Autodetecting instead.");
     864        5613 :         return bIsImpossible;
     865             :     }
     866             : 
     867          14 :     LanguageTag getExemplarLangTagForCodePoint(sal_uInt32 currentChar)
     868             :     {
     869          14 :         int32_t script = u_getIntPropertyValue(currentChar, UCHAR_SCRIPT);
     870          14 :         UScriptCode eScript = static_cast<UScriptCode>(script);
     871          14 :         OStringBuffer aBuf(unicode::getExemplarLanguageForUScriptCode(eScript));
     872          14 :         const char* pScriptCode = uscript_getShortName(eScript);
     873          14 :         if (pScriptCode)
     874          14 :             aBuf.append('-').append(pScriptCode);
     875          14 :         return LanguageTag(OStringToOUString(aBuf.makeStringAndClear(), RTL_TEXTENCODING_UTF8));
     876             :     }
     877             : 
     878             : #if defined(ENABLE_DBUS) && defined(ENABLE_PACKAGEKIT)
     879             :     guint get_xid_for_dbus()
     880             :     {
     881             :         const vcl::Window *pTopWindow = Application::IsHeadlessModeEnabled() ? NULL : Application::GetActiveTopWindow();
     882             :         const SystemEnvData* pEnvData = pTopWindow ? pTopWindow->GetSystemData() : NULL;
     883             :         return pEnvData ? pEnvData->aWindow : 0;
     884             :     }
     885             : #endif
     886             : }
     887             : 
     888             : #if defined(ENABLE_DBUS) && defined(ENABLE_PACKAGEKIT)
     889             : IMPL_LINK_NOARG_TYPED(PrintFontManager, autoInstallFontLangSupport, Timer *, void)
     890             : {
     891             :     guint xid = get_xid_for_dbus();
     892             : 
     893             :     if (!xid)
     894             :         return;
     895             : 
     896             :     GError *error = NULL;
     897             :     /* get the DBUS session connection */
     898             :     DBusGConnection *session_connection = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
     899             :     if (error != NULL)
     900             :     {
     901             :         g_debug ("DBUS cannot connect : %s", error->message);
     902             :         g_error_free (error);
     903             :         return;
     904             :     }
     905             : 
     906             :     /* get the proxy with gnome-session-manager */
     907             :     DBusGProxy *proxy = dbus_g_proxy_new_for_name(session_connection,
     908             :                                        "org.freedesktop.PackageKit",
     909             :                                        "/org/freedesktop/PackageKit",
     910             :                                        "org.freedesktop.PackageKit.Modify");
     911             :     if (proxy == NULL)
     912             :     {
     913             :         g_debug("Could not get DBUS proxy: org.freedesktop.PackageKit");
     914             :         return;
     915             :     }
     916             : 
     917             :     gchar **fonts = static_cast<gchar**>(g_malloc((m_aCurrentRequests.size() + 1) * sizeof(gchar*)));
     918             :     gchar **font = fonts;
     919             :     for (std::vector<OString>::const_iterator aI = m_aCurrentRequests.begin(); aI != m_aCurrentRequests.end(); ++aI)
     920             :         *font++ = const_cast<gchar*>(aI->getStr());
     921             :     *font = NULL;
     922             :     gboolean res = dbus_g_proxy_call(proxy, "InstallFontconfigResources", &error,
     923             :                  G_TYPE_UINT, xid, /* xid */
     924             :                  G_TYPE_STRV, fonts, /* data */
     925             :                  G_TYPE_STRING, "hide-finished", /* interaction */
     926             :                  G_TYPE_INVALID,
     927             :                  G_TYPE_INVALID);
     928             :     /* check the return value */
     929             :     if (!res)
     930             :        g_debug("InstallFontconfigResources method failed");
     931             : 
     932             :     /* check the error value */
     933             :     if (error != NULL)
     934             :     {
     935             :         g_debug("InstallFontconfigResources problem : %s", error->message);
     936             :         g_error_free(error);
     937             :     }
     938             : 
     939             :     g_free(fonts);
     940             :     g_object_unref(G_OBJECT (proxy));
     941             :     m_aCurrentRequests.clear();
     942             : }
     943             : #endif
     944             : 
     945       11319 : bool PrintFontManager::Substitute( FontSelectPattern &rPattern, OUString& rMissingCodes )
     946             : {
     947       11319 :     bool bRet = false;
     948             : 
     949       11319 :     FontCfgWrapper& rWrapper = FontCfgWrapper::get();
     950             : 
     951             :     // build pattern argument for fontconfig query
     952       11319 :     FcPattern* pPattern = FcPatternCreate();
     953             : 
     954             :     // Prefer scalable fonts
     955       11319 :     FcPatternAddBool(pPattern, FC_SCALABLE, FcTrue);
     956             : 
     957       11319 :     const OString aTargetName = OUStringToOString( rPattern.maTargetName, RTL_TEXTENCODING_UTF8 );
     958       11319 :     const FcChar8* pTargetNameUtf8 = reinterpret_cast<FcChar8 const *>(aTargetName.getStr());
     959       11319 :     FcPatternAddString(pPattern, FC_FAMILY, pTargetNameUtf8);
     960             : 
     961       22638 :     LanguageTag aLangTag(rPattern.meLanguage);
     962       22638 :     OString aLangAttrib = mapToFontConfigLangTag(aLangTag);
     963             : 
     964             :     // Add required Unicode characters, if any
     965       11319 :     if ( !rMissingCodes.isEmpty() )
     966             :     {
     967        5417 :         FcCharSet *unicodes = FcCharSetCreate();
     968       16461 :         for( sal_Int32 nStrIndex = 0; nStrIndex < rMissingCodes.getLength(); )
     969             :         {
     970             :             // also handle unicode surrogates
     971        5627 :             const sal_uInt32 nCode = rMissingCodes.iterateCodePoints( &nStrIndex );
     972        5627 :             FcCharSetAddChar( unicodes, nCode );
     973             :             //if the codepoint is impossible for this lang tag, then clear it
     974             :             //and autodetect something useful
     975        5627 :             if (!aLangAttrib.isEmpty() && isImpossibleCodePointForLang(aLangTag, nCode))
     976           0 :                 aLangAttrib.clear();
     977             :             //#i105784#/rhbz#527719  improve selection of fallback font
     978        5627 :             if (aLangAttrib.isEmpty())
     979             :             {
     980          14 :                 aLangTag = getExemplarLangTagForCodePoint(nCode);
     981          14 :                 aLangAttrib = mapToFontConfigLangTag(aLangTag);
     982             :             }
     983             :         }
     984        5417 :         FcPatternAddCharSet(pPattern, FC_CHARSET, unicodes);
     985        5417 :         FcCharSetDestroy(unicodes);
     986             :     }
     987             : 
     988       11319 :     if (!aLangAttrib.isEmpty())
     989       11269 :         FcPatternAddString(pPattern, FC_LANG, reinterpret_cast<FcChar8 const *>(aLangAttrib.getStr()));
     990             : 
     991             :     addtopattern(pPattern, rPattern.GetSlant(), rPattern.GetWeight(),
     992       11319 :         rPattern.GetWidthType(), rPattern.GetPitch());
     993             : 
     994             :     // query fontconfig for a substitute
     995       11319 :     FcConfigSubstitute(FcConfigGetCurrent(), pPattern, FcMatchPattern);
     996       11319 :     FcDefaultSubstitute(pPattern);
     997             : 
     998             :     // process the result of the fontconfig query
     999       11319 :     FcResult eResult = FcResultNoMatch;
    1000       11319 :     FcFontSet* pFontSet = rWrapper.getFontSet();
    1001       11319 :     FcPattern* pResult = FcFontSetMatch(FcConfigGetCurrent(), &pFontSet, 1, pPattern, &eResult);
    1002       11319 :     FcPatternDestroy( pPattern );
    1003             : 
    1004       11319 :     FcFontSet*  pSet = NULL;
    1005       11319 :     if( pResult )
    1006             :     {
    1007       11319 :         pSet = FcFontSetCreate();
    1008             :         // info: destroying the pSet destroys pResult implicitly
    1009             :         // since pResult was "added" to pSet
    1010       11319 :         FcFontSetAdd( pSet, pResult );
    1011             :     }
    1012             : 
    1013       11319 :     if( pSet )
    1014             :     {
    1015       11319 :         if( pSet->nfont > 0 )
    1016             :         {
    1017             :             //extract the closest match
    1018       11319 :             FcChar8* file = NULL;
    1019       11319 :             FcResult eFileRes = FcPatternGetString(pSet->fonts[0], FC_FILE, 0, &file);
    1020       11319 :             int nCollectionEntry = 0;
    1021       11319 :             FcResult eIndexRes = FcPatternGetInteger(pSet->fonts[0], FC_INDEX, 0, &nCollectionEntry);
    1022       11319 :             if (eIndexRes != FcResultMatch)
    1023           0 :                 nCollectionEntry = 0;
    1024       11319 :             if( eFileRes == FcResultMatch )
    1025             :             {
    1026       22638 :                 OString aDir, aBase, aOrgPath( reinterpret_cast<char*>(file) );
    1027       11319 :                 splitPath( aOrgPath, aDir, aBase );
    1028       11319 :                 int nDirID = getDirectoryAtom( aDir, true );
    1029       11319 :                 fontID aFont = findFontFileID( nDirID, aBase, nCollectionEntry );
    1030       11319 :                 if( aFont > 0 )
    1031             :                 {
    1032       11319 :                     FastPrintFontInfo aInfo;
    1033       11319 :                     bRet = getFontFastInfo( aFont, aInfo );
    1034       11319 :                     rPattern.maSearchName = aInfo.m_aFamilyName;
    1035       11319 :                 }
    1036             :             }
    1037             : 
    1038             :             SAL_WARN_IF(!bRet, "vcl", "no FC_FILE found, falling back to name search");
    1039             : 
    1040       11319 :             if (!bRet)
    1041             :             {
    1042           0 :                 FcChar8* family = NULL;
    1043           0 :                 FcResult eFamilyRes = FcPatternGetString( pSet->fonts[0], FC_FAMILY, 0, &family );
    1044             : 
    1045             :                 // get the family name
    1046           0 :                 if( eFamilyRes == FcResultMatch )
    1047             :                 {
    1048           0 :                     OString sFamily(reinterpret_cast<char*>(family));
    1049             :                     std::unordered_map< OString, OString, OStringHash >::const_iterator aI =
    1050           0 :                         rWrapper.m_aFontNameToLocalized.find(sFamily);
    1051           0 :                     if (aI != rWrapper.m_aFontNameToLocalized.end())
    1052           0 :                         sFamily = aI->second;
    1053           0 :                     rPattern.maSearchName = OStringToOUString( sFamily, RTL_TEXTENCODING_UTF8 );
    1054           0 :                     bRet = true;
    1055             :                 }
    1056             :             }
    1057             : 
    1058       11319 :             if (bRet)
    1059             :             {
    1060       11319 :                 int val = 0;
    1061       11319 :                 if (FcResultMatch == FcPatternGetInteger(pSet->fonts[0], FC_WEIGHT, 0, &val))
    1062       11319 :                     rPattern.SetWeight( convertWeight(val) );
    1063       11319 :                 if (FcResultMatch == FcPatternGetInteger(pSet->fonts[0], FC_SLANT, 0, &val))
    1064       11319 :                     rPattern.SetItalic( convertSlant(val) );
    1065       11319 :                 if (FcResultMatch == FcPatternGetInteger(pSet->fonts[0], FC_SPACING, 0, &val))
    1066        9482 :                     rPattern.SetPitch ( convertSpacing(val) );
    1067       11319 :                 if (FcResultMatch == FcPatternGetInteger(pSet->fonts[0], FC_WIDTH, 0, &val))
    1068       11319 :                     rPattern.SetWidthType ( convertWidth(val) );
    1069             :                 FcBool bEmbolden;
    1070       11319 :                 if (FcResultMatch == FcPatternGetBool(pSet->fonts[0], FC_EMBOLDEN, 0, &bEmbolden))
    1071           7 :                     rPattern.mbEmbolden = bEmbolden;
    1072       11319 :                 FcMatrix *pMatrix = 0;
    1073       11319 :                 if (FcResultMatch == FcPatternGetMatrix(pSet->fonts[0], FC_MATRIX, 0, &pMatrix))
    1074             :                 {
    1075           2 :                     rPattern.maItalicMatrix.xx = pMatrix->xx;
    1076           2 :                     rPattern.maItalicMatrix.xy = pMatrix->xy;
    1077           2 :                     rPattern.maItalicMatrix.yx = pMatrix->yx;
    1078           2 :                     rPattern.maItalicMatrix.yy = pMatrix->yy;
    1079             :                 }
    1080             :             }
    1081             : 
    1082             :             // update rMissingCodes by removing resolved unicodes
    1083       11319 :             if( !rMissingCodes.isEmpty() )
    1084             :             {
    1085        5417 :                 sal_uInt32* pRemainingCodes = static_cast<sal_uInt32*>(alloca( rMissingCodes.getLength() * sizeof(sal_uInt32) ));
    1086        5417 :                 int nRemainingLen = 0;
    1087             :                 FcCharSet* unicodes;
    1088        5417 :                 if (!FcPatternGetCharSet(pSet->fonts[0], FC_CHARSET, 0, &unicodes))
    1089             :                 {
    1090       16461 :                     for( sal_Int32 nStrIndex = 0; nStrIndex < rMissingCodes.getLength(); )
    1091             :                     {
    1092             :                         // also handle unicode surrogates
    1093        5627 :                         const sal_uInt32 nCode = rMissingCodes.iterateCodePoints( &nStrIndex );
    1094        5627 :                         if (FcCharSetHasChar(unicodes, nCode) != FcTrue)
    1095        5103 :                             pRemainingCodes[ nRemainingLen++ ] = nCode;
    1096             :                     }
    1097             :                 }
    1098        5417 :                 OUString sStillMissing(pRemainingCodes, nRemainingLen);
    1099             : #if defined(ENABLE_DBUS) && defined(ENABLE_PACKAGEKIT)
    1100             :                 if (get_xid_for_dbus())
    1101             :                 {
    1102             :                     if (sStillMissing == rMissingCodes) //replaced nothing
    1103             :                     {
    1104             :                         //It'd be better if we could ask packagekit using the
    1105             :                         //missing codepoints or some such rather than using
    1106             :                         //"language" as a proxy to how fontconfig considers
    1107             :                         //scripts to default to a given language.
    1108             :                         for (sal_Int32 i = 0; i < nRemainingLen; ++i)
    1109             :                         {
    1110             :                             LanguageTag aOurTag = getExemplarLangTagForCodePoint(pRemainingCodes[i]);
    1111             :                             OString sTag = OUStringToOString(aOurTag.getBcp47(), RTL_TEXTENCODING_UTF8);
    1112             :                             if (m_aPreviousLangSupportRequests.find(sTag) != m_aPreviousLangSupportRequests.end())
    1113             :                                 continue;
    1114             :                             m_aPreviousLangSupportRequests.insert(sTag);
    1115             :                             sTag = mapToFontConfigLangTag(aOurTag);
    1116             :                             if (!sTag.isEmpty() && m_aPreviousLangSupportRequests.find(sTag) == m_aPreviousLangSupportRequests.end())
    1117             :                             {
    1118             :                                 OString sReq = OString(":lang=") + sTag;
    1119             :                                 m_aCurrentRequests.push_back(sReq);
    1120             :                                 m_aPreviousLangSupportRequests.insert(sTag);
    1121             :                             }
    1122             :                         }
    1123             :                     }
    1124             :                     if (!m_aCurrentRequests.empty())
    1125             :                     {
    1126             :                         m_aFontInstallerTimer.Stop();
    1127             :                         m_aFontInstallerTimer.Start();
    1128             :                     }
    1129             :                 }
    1130             : #endif
    1131        5417 :                 rMissingCodes = sStillMissing;
    1132             :             }
    1133             :         }
    1134             : 
    1135       11319 :         FcFontSetDestroy( pSet );
    1136             :     }
    1137             : 
    1138       22638 :     return bRet;
    1139             : }
    1140             : 
    1141             : class FontConfigFontOptions : public ImplFontOptions
    1142             : {
    1143             : public:
    1144          37 :     FontConfigFontOptions() : mpPattern(0) {}
    1145          38 :     virtual ~FontConfigFontOptions()
    1146          38 :     {
    1147          19 :         FcPatternDestroy(mpPattern);
    1148          38 :     }
    1149           1 :     virtual void *GetPattern(void * face, bool bEmbolden, bool /*bVerticalLayout*/) const SAL_OVERRIDE
    1150             :     {
    1151             :         FcValue value;
    1152           1 :         value.type = FcTypeFTFace;
    1153           1 :         value.u.f = face;
    1154           1 :         FcPatternDel(mpPattern, FC_FT_FACE);
    1155           1 :         FcPatternAdd (mpPattern, FC_FT_FACE, value, FcTrue);
    1156           1 :         FcPatternDel(mpPattern, FC_EMBOLDEN);
    1157           1 :         FcPatternAddBool(mpPattern, FC_EMBOLDEN, bEmbolden ? FcTrue : FcFalse);
    1158             : #if 0
    1159             :         FcPatternDel(mpPattern, FC_VERTICAL_LAYOUT);
    1160             :         FcPatternAddBool(mpPattern, FC_VERTICAL_LAYOUT, bVerticalLayout ? FcTrue : FcFalse);
    1161             : #endif
    1162           1 :         return mpPattern;
    1163             :     }
    1164             :     FcPattern* mpPattern;
    1165             : };
    1166             : 
    1167          37 : ImplFontOptions* PrintFontManager::getFontOptions(
    1168             :     const FastPrintFontInfo& rInfo, int nSize, void (*subcallback)(void*))
    1169             : {
    1170          37 :     FontCfgWrapper& rWrapper = FontCfgWrapper::get();
    1171             : 
    1172          37 :     FontConfigFontOptions* pOptions = NULL;
    1173          37 :     FcConfig* pConfig = FcConfigGetCurrent();
    1174          37 :     FcPattern* pPattern = FcPatternCreate();
    1175             : 
    1176          37 :     OString sFamily = OUStringToOString( rInfo.m_aFamilyName, RTL_TEXTENCODING_UTF8 );
    1177             : 
    1178          37 :     std::unordered_map< OString, OString, OStringHash >::const_iterator aI = rWrapper.m_aLocalizedToCanonical.find(sFamily);
    1179          37 :     if (aI != rWrapper.m_aLocalizedToCanonical.end())
    1180           0 :         sFamily = aI->second;
    1181          37 :     if( !sFamily.isEmpty() )
    1182          37 :         FcPatternAddString(pPattern, FC_FAMILY, reinterpret_cast<FcChar8 const *>(sFamily.getStr()));
    1183             : 
    1184          37 :     addtopattern(pPattern, rInfo.m_eItalic, rInfo.m_eWeight, rInfo.m_eWidth, rInfo.m_ePitch);
    1185          37 :     FcPatternAddDouble(pPattern, FC_PIXEL_SIZE, nSize);
    1186             : 
    1187          37 :     FcBool embitmap = true, antialias = true, autohint = true, hinting = true;
    1188          37 :     int hintstyle = FC_HINT_FULL;
    1189             : 
    1190          37 :     FcConfigSubstitute(pConfig, pPattern, FcMatchPattern);
    1191          37 :     if (subcallback)
    1192          37 :         subcallback(pPattern);
    1193          37 :     FcDefaultSubstitute(pPattern);
    1194             : 
    1195          37 :     FcResult eResult = FcResultNoMatch;
    1196          37 :     FcFontSet* pFontSet = rWrapper.getFontSet();
    1197          37 :     FcPattern* pResult = FcFontSetMatch( pConfig, &pFontSet, 1, pPattern, &eResult );
    1198          37 :     if( pResult )
    1199             :     {
    1200             :         FcResult eEmbeddedBitmap = FcPatternGetBool(pResult,
    1201          37 :             FC_EMBEDDED_BITMAP, 0, &embitmap);
    1202             :         FcResult eAntialias = FcPatternGetBool(pResult,
    1203          37 :             FC_ANTIALIAS, 0, &antialias);
    1204             :         FcResult eAutoHint = FcPatternGetBool(pResult,
    1205          37 :             FC_AUTOHINT, 0, &autohint);
    1206             :         FcResult eHinting = FcPatternGetBool(pResult,
    1207          37 :             FC_HINTING, 0, &hinting);
    1208             :         (void) FcPatternGetInteger(pResult,
    1209          37 :             FC_HINT_STYLE, 0, &hintstyle);
    1210             : 
    1211          37 :         pOptions = new FontConfigFontOptions;
    1212             : 
    1213          37 :         pOptions->mpPattern = pResult;
    1214             : 
    1215          37 :         if( eEmbeddedBitmap == FcResultMatch )
    1216          37 :             pOptions->meEmbeddedBitmap = embitmap ? EMBEDDEDBITMAP_TRUE : EMBEDDEDBITMAP_FALSE;
    1217          37 :         if( eAntialias == FcResultMatch )
    1218          37 :             pOptions->meAntiAlias = antialias ? ANTIALIAS_TRUE : ANTIALIAS_FALSE;
    1219          37 :         if( eAutoHint == FcResultMatch )
    1220          37 :             pOptions->meAutoHint = autohint ? AUTOHINT_TRUE : AUTOHINT_FALSE;
    1221          37 :         if( eHinting == FcResultMatch )
    1222          37 :             pOptions->meHinting = hinting ? HINTING_TRUE : HINTING_FALSE;
    1223          37 :         switch (hintstyle)
    1224             :         {
    1225           0 :             case FC_HINT_NONE:   pOptions->meHintStyle = HINT_NONE; break;
    1226           0 :             case FC_HINT_SLIGHT: pOptions->meHintStyle = HINT_SLIGHT; break;
    1227           0 :             case FC_HINT_MEDIUM: pOptions->meHintStyle = HINT_MEDIUM; break;
    1228             :             default: // fall through
    1229          37 :             case FC_HINT_FULL:   pOptions->meHintStyle = HINT_FULL; break;
    1230             :         }
    1231             :     }
    1232             : 
    1233             :     // cleanup
    1234          37 :     FcPatternDestroy( pPattern );
    1235             : 
    1236          37 :     return pOptions;
    1237             : }
    1238             : 
    1239          11 : bool PrintFontManager::matchFont( FastPrintFontInfo& rInfo, const com::sun::star::lang::Locale& rLocale )
    1240             : {
    1241          11 :     FontCfgWrapper& rWrapper = FontCfgWrapper::get();
    1242             : 
    1243          11 :     FcConfig* pConfig = FcConfigGetCurrent();
    1244          11 :     FcPattern* pPattern = FcPatternCreate();
    1245             : 
    1246             :     // populate pattern with font characteristics
    1247          11 :     const LanguageTag aLangTag(rLocale);
    1248          22 :     const OString aLangAttrib = mapToFontConfigLangTag(aLangTag);
    1249          11 :     if (!aLangAttrib.isEmpty())
    1250          11 :         FcPatternAddString(pPattern, FC_LANG, reinterpret_cast<FcChar8 const *>(aLangAttrib.getStr()));
    1251             : 
    1252          22 :     OString aFamily = OUStringToOString( rInfo.m_aFamilyName, RTL_TEXTENCODING_UTF8 );
    1253          11 :     if( !aFamily.isEmpty() )
    1254          11 :         FcPatternAddString(pPattern, FC_FAMILY, reinterpret_cast<FcChar8 const *>(aFamily.getStr()));
    1255             : 
    1256          11 :     addtopattern(pPattern, rInfo.m_eItalic, rInfo.m_eWeight, rInfo.m_eWidth, rInfo.m_ePitch);
    1257             : 
    1258          11 :     FcConfigSubstitute(pConfig, pPattern, FcMatchPattern);
    1259          11 :     FcDefaultSubstitute(pPattern);
    1260          11 :     FcResult eResult = FcResultNoMatch;
    1261          11 :     FcFontSet *pFontSet = rWrapper.getFontSet();
    1262          11 :     FcPattern* pResult = FcFontSetMatch(pConfig, &pFontSet, 1, pPattern, &eResult);
    1263          11 :     bool bSuccess = false;
    1264          11 :     if( pResult )
    1265             :     {
    1266          11 :         FcFontSet* pSet = FcFontSetCreate();
    1267          11 :         FcFontSetAdd( pSet, pResult );
    1268          11 :         if( pSet->nfont > 0 )
    1269             :         {
    1270             :             //extract the closest match
    1271          11 :             FcChar8* file = NULL;
    1272          11 :             FcResult eFileRes = FcPatternGetString(pSet->fonts[0], FC_FILE, 0, &file);
    1273          11 :             int nCollectionEntry = 0;
    1274          11 :             FcResult eIndexRes = FcPatternGetInteger(pSet->fonts[0], FC_INDEX, 0, &nCollectionEntry);
    1275          11 :             if (eIndexRes != FcResultMatch)
    1276           0 :                 nCollectionEntry = 0;
    1277          11 :             if( eFileRes == FcResultMatch )
    1278             :             {
    1279          22 :                 OString aDir, aBase, aOrgPath( reinterpret_cast<char*>(file) );
    1280          11 :                 splitPath( aOrgPath, aDir, aBase );
    1281          11 :                 int nDirID = getDirectoryAtom( aDir, true );
    1282          11 :                 fontID aFont = findFontFileID( nDirID, aBase, nCollectionEntry );
    1283          11 :                 if( aFont > 0 )
    1284          22 :                     bSuccess = getFontFastInfo( aFont, rInfo );
    1285             :             }
    1286             :         }
    1287             :         // info: destroying the pSet destroys pResult implicitly
    1288             :         // since pResult was "added" to pSet
    1289          11 :         FcFontSetDestroy( pSet );
    1290             :     }
    1291             : 
    1292             :     // cleanup
    1293          11 :     FcPatternDestroy( pPattern );
    1294             : 
    1295          22 :     return bSuccess;
    1296             : }
    1297             : 
    1298             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11