LCOV - code coverage report
Current view: top level - libreoffice/vcl/generic/fontmanager - fontconfig.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 379 547 69.3 %
Date: 2012-12-17 Functions: 27 35 77.1 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10