/************************************************************************* * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * Copyright 2000, 2010 Oracle and/or its affiliates. * * OpenOffice.org - a multi-platform office productivity suite * * This file is part of OpenOffice.org. * * OpenOffice.org is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 * only, as published by the Free Software Foundation. * * OpenOffice.org is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License version 3 for more details * (a copy is included in the LICENSE file that accompanied this code). * * You should have received a copy of the GNU Lesser General Public License * version 3 along with OpenOffice.org. If not, see * * for a copy of the LGPLv3 License. * ************************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_vcl.hxx" #include "vcl/fontmanager.hxx" #include "vcl/fontcache.hxx" #include "vcl/impfont.hxx" using namespace psp; #ifdef ENABLE_FONTCONFIG #include #include #include // allow compile on baseline (currently with fontconfig 2.2.0) #ifndef FC_WEIGHT_BOOK // TODO: remove when baseline moves to fc>=2.2.1 #define FC_WEIGHT_BOOK 75 #endif #ifndef FC_EMBEDDED_BITMAP // TODO: remove when baseline moves to fc>=2.3.92 #define FC_EMBEDDED_BITMAP "embeddedbitmap" #endif #ifndef FC_FAMILYLANG // TODO: remove when baseline moves to fc>=2.2.97 #define FC_FAMILYLANG "familylang" #endif #ifndef FC_HINT_STYLE // TODO: remove when baseline moves to fc>=2.2.91 #define FC_HINT_STYLE "hintstyle" #define FC_HINT_NONE 0 #define FC_HINT_SLIGHT 1 #define FC_HINT_MEDIUM 2 #define FC_HINT_FULL 3 #endif #else typedef void FcConfig; typedef void FcObjectSet; typedef void FcPattern; typedef void FcFontSet; typedef void FcCharSet; typedef int FcResult; typedef int FcBool; typedef int FcMatchKind; typedef char FcChar8; typedef int FcChar32; typedef unsigned int FT_UInt; typedef void* FT_Face; typedef int FcSetName; #endif #include #include #include "unotools/atom.hxx" #include "osl/module.h" #include "osl/thread.h" #include "osl/process.h" #include "rtl/ustrbuf.hxx" #include "rtl/locale.hxx" #include "sal/alloca.h" #include #include using namespace osl; using namespace rtl; class FontCfgWrapper { oslModule m_pLib; FcFontSet* m_pOutlineSet; int m_nFcVersion; FcBool (*m_pFcInit)(); int (*m_pFcGetVersion)(); FcConfig* (*m_pFcConfigGetCurrent)(); FcObjectSet* (*m_pFcObjectSetVaBuild)(const char*,va_list); void (*m_pFcObjectSetDestroy)(FcObjectSet* pSet); FcPattern* (*m_pFcPatternCreate)(); void (*m_pFcPatternDestroy)(FcPattern*); FcFontSet* (*m_pFcFontList)(FcConfig*,FcPattern*,FcObjectSet*); FcFontSet* (*m_pFcConfigGetFonts)(FcConfig*,FcSetName); FcFontSet* (*m_pFcFontSetCreate)(); FcCharSet* (*m_pFcCharSetCreate)(); FcBool (*m_pFcCharSetAddChar)(FcCharSet *, FcChar32); FcBool (*m_pFcCharSetHasChar)(FcCharSet *, FcChar32); void (*m_pFcCharSetDestroy)(FcCharSet*); void (*m_pFcFontSetDestroy)(FcFontSet*); FcBool (*m_pFcFontSetAdd)(FcFontSet*,FcPattern*); void (*m_pFcPatternReference)(FcPattern*); FcResult (*m_pFcPatternGetCharSet)(const FcPattern*,const char*,int,FcCharSet**); FcResult (*m_pFcPatternGetString)(const FcPattern*,const char*,int,FcChar8**); FcResult (*m_pFcPatternGetInteger)(const FcPattern*,const char*,int,int*); FcResult (*m_pFcPatternGetDouble)(const FcPattern*,const char*,int,double*); FcResult (*m_pFcPatternGetBool)(const FcPattern*,const char*,int,FcBool*); void (*m_pFcDefaultSubstitute)(FcPattern *); FcPattern* (*m_pFcFontSetMatch)(FcConfig*,FcFontSet**, int, FcPattern*,FcResult*); FcPattern* (*m_pFcFontMatch)(FcConfig*,FcPattern*,FcResult*); FcBool (*m_pFcConfigAppFontAddFile)(FcConfig*, const FcChar8*); FcBool (*m_pFcConfigAppFontAddDir)(FcConfig*, const FcChar8*); FcBool (*m_pFcConfigParseAndLoad)(FcConfig*,const FcChar8*,FcBool); FcBool (*m_pFcConfigSubstitute)(FcConfig*,FcPattern*,FcMatchKind); FcPattern* (*m_pFcPatternDuplicate)(const FcPattern*); FcBool (*m_pFcPatternAddInteger)(FcPattern*,const char*,int); FcBool (*m_pFcPatternAddDouble)(FcPattern*,const char*,double); FcBool (*m_pFcPatternAddBool)(FcPattern*,const char*,FcBool); FcBool (*m_pFcPatternAddCharSet)(FcPattern*,const char*,const FcCharSet*); FcBool (*m_pFcPatternAddString)(FcPattern*,const char*,const FcChar8*); FcBool (*m_pFcPatternDel)(FcPattern*,const char*); FT_UInt (*m_pFcFreeTypeCharIndex)(FT_Face,FcChar32); oslGenericFunction loadSymbol( const char* ); void addFontSet( FcSetName ); FontCfgWrapper(); ~FontCfgWrapper(); public: static FontCfgWrapper& get(); static void release(); bool isValid() const { return m_pLib != NULL;} FcFontSet* getFontSet(); FcBool FcInit() { return m_pFcInit(); } int FcGetVersion() { return m_pFcGetVersion(); } FcConfig* FcConfigGetCurrent() { return m_pFcConfigGetCurrent(); } FcObjectSet* FcObjectSetBuild( const char* first, ... ) { va_list ap; va_start( ap, first ); FcObjectSet* pSet = m_pFcObjectSetVaBuild( first, ap ); va_end( ap ); return pSet; } void FcObjectSetDestroy( FcObjectSet* pSet ) { m_pFcObjectSetDestroy( pSet ); } FcPattern* FcPatternCreate() { return m_pFcPatternCreate(); } void FcPatternDestroy( FcPattern* pPattern ) { m_pFcPatternDestroy( pPattern ); } FcFontSet* FcFontList( FcConfig* pConfig, FcPattern* pPattern, FcObjectSet* pSet ) { return m_pFcFontList( pConfig, pPattern, pSet ); } FcFontSet* FcConfigGetFonts( FcConfig* pConfig, FcSetName eSet) { return m_pFcConfigGetFonts( pConfig, eSet ); } FcFontSet* FcFontSetCreate() { return m_pFcFontSetCreate(); } FcCharSet* FcCharSetCreate() { return m_pFcCharSetCreate(); } FcBool FcCharSetAddChar(FcCharSet *fcs, FcChar32 ucs4) { return m_pFcCharSetAddChar(fcs, ucs4); } FcBool FcCharSetHasChar(FcCharSet *fcs, FcChar32 ucs4) { return m_pFcCharSetHasChar(fcs, ucs4); } void FcCharSetDestroy( FcCharSet* pSet ) { m_pFcCharSetDestroy( pSet );} void FcFontSetDestroy( FcFontSet* pSet ) { m_pFcFontSetDestroy( pSet );} FcBool FcFontSetAdd( FcFontSet* pSet, FcPattern* pPattern ) { return m_pFcFontSetAdd( pSet, pPattern ); } void FcPatternReference( FcPattern* pPattern ) { m_pFcPatternReference( pPattern ); } FcResult FcPatternGetCharSet( const FcPattern* pPattern, const char* object, int n, FcCharSet** s ) { return m_pFcPatternGetCharSet( pPattern, object, n, s ); } FcResult FcPatternGetString( const FcPattern* pPattern, const char* object, int n, FcChar8** s ) { return m_pFcPatternGetString( pPattern, object, n, s ); } FcResult FcPatternGetInteger( const FcPattern* pPattern, const char* object, int n, int* s ) { return m_pFcPatternGetInteger( pPattern, object, n, s ); } FcResult FcPatternGetDouble( const FcPattern* pPattern, const char* object, int n, double* s ) { return m_pFcPatternGetDouble( pPattern, object, n, s ); } FcResult FcPatternGetBool( const FcPattern* pPattern, const char* object, int n, FcBool* s ) { return m_pFcPatternGetBool( pPattern, object, n, s ); } FcBool FcConfigAppFontAddFile( FcConfig* pConfig, const FcChar8* pFileName ) { return m_pFcConfigAppFontAddFile( pConfig, pFileName ); } FcBool FcConfigAppFontAddDir(FcConfig* pConfig, const FcChar8* pDirName ) { return m_pFcConfigAppFontAddDir( pConfig, pDirName ); } FcBool FcConfigParseAndLoad( FcConfig* pConfig, const FcChar8* pFileName, FcBool bComplain ) { return m_pFcConfigParseAndLoad( pConfig, pFileName, bComplain ); } void FcDefaultSubstitute( FcPattern* pPattern ) { m_pFcDefaultSubstitute( pPattern ); } FcPattern* FcFontSetMatch( FcConfig* pConfig, FcFontSet **ppFontSet, int nset, FcPattern* pPattern, FcResult* pResult ) { return m_pFcFontSetMatch ? m_pFcFontSetMatch( pConfig, ppFontSet, nset, pPattern, pResult ) : 0; } FcPattern* FcFontMatch( FcConfig* pConfig, FcPattern* pPattern, FcResult* pResult ) { return m_pFcFontMatch( pConfig, pPattern, pResult ); } FcBool FcConfigSubstitute( FcConfig* pConfig, FcPattern* pPattern, FcMatchKind eKind ) { return m_pFcConfigSubstitute( pConfig, pPattern, eKind ); } FcPattern* FcPatternDuplicate( const FcPattern* pPattern ) const { return m_pFcPatternDuplicate( pPattern ); } FcBool FcPatternAddInteger( FcPattern* pPattern, const char* pObject, int nValue ) { return m_pFcPatternAddInteger( pPattern, pObject, nValue ); } FcBool FcPatternAddDouble( FcPattern* pPattern, const char* pObject, double nValue ) { return m_pFcPatternAddDouble( pPattern, pObject, nValue ); } FcBool FcPatternAddString( FcPattern* pPattern, const char* pObject, const FcChar8* pString ) { return m_pFcPatternAddString( pPattern, pObject, pString ); } FcBool FcPatternAddBool( FcPattern* pPattern, const char* pObject, bool nValue ) { return m_pFcPatternAddBool( pPattern, pObject, nValue ); } FcBool FcPatternAddCharSet(FcPattern* pPattern,const char* pObject,const FcCharSet*pCharSet) { return m_pFcPatternAddCharSet(pPattern,pObject,pCharSet); } FcBool FcPatternDel(FcPattern* pPattern, const char* object) { return m_pFcPatternDel( pPattern, object); } FT_UInt FcFreeTypeCharIndex( FT_Face face, FcChar32 ucs4 ) { return m_pFcFreeTypeCharIndex ? m_pFcFreeTypeCharIndex( face, ucs4 ) : 0; } public: // TODO: cleanup FcResult FamilyFromPattern(FcPattern* pPattern, FcChar8 **family); std::hash_map< rtl::OString, rtl::OString, rtl::OStringHash > m_aFontNameToLocalized; std::hash_map< rtl::OString, rtl::OString, rtl::OStringHash > m_aLocalizedToCanonical; }; oslGenericFunction FontCfgWrapper::loadSymbol( const char* pSymbol ) { OUString aSym( OUString::createFromAscii( pSymbol ) ); oslGenericFunction pSym = osl_getFunctionSymbol( m_pLib, aSym.pData ); #if OSL_DEBUG_LEVEL > 1 fprintf( stderr, "%s %s\n", pSymbol, pSym ? "found" : "not found" ); #endif return pSym; } FontCfgWrapper::FontCfgWrapper() : m_pLib( NULL ), m_pOutlineSet( NULL ), m_nFcVersion( 0 ) { OUString aLib( RTL_CONSTASCII_USTRINGPARAM( "libfontconfig.so.1" ) ); m_pLib = osl_loadModule( aLib.pData, SAL_LOADMODULE_LAZY ); if( !m_pLib ) { aLib = OUString( RTL_CONSTASCII_USTRINGPARAM( "libfontconfig.so" ) ); m_pLib = osl_loadModule( aLib.pData, SAL_LOADMODULE_LAZY ); } if( ! m_pLib ) { #if OSL_DEBUG_LEVEL > 1 fprintf( stderr, "no libfontconfig\n" ); #endif return; } m_pFcInit = (FcBool(*)()) loadSymbol( "FcInit" ); m_pFcGetVersion = (int(*)()) loadSymbol( "FcGetVersion" ); m_pFcConfigGetCurrent = (FcConfig *(*)()) loadSymbol( "FcConfigGetCurrent" ); m_pFcObjectSetVaBuild = (FcObjectSet*(*)(const char*,va_list)) loadSymbol( "FcObjectSetVaBuild" ); m_pFcObjectSetDestroy = (void(*)(FcObjectSet*)) loadSymbol( "FcObjectSetDestroy" ); m_pFcPatternCreate = (FcPattern*(*)()) loadSymbol( "FcPatternCreate" ); m_pFcPatternDestroy = (void(*)(FcPattern*)) loadSymbol( "FcPatternDestroy" ); m_pFcFontList = (FcFontSet*(*)(FcConfig*,FcPattern*,FcObjectSet*)) loadSymbol( "FcFontList" ); m_pFcConfigGetFonts = (FcFontSet*(*)(FcConfig*,FcSetName)) loadSymbol( "FcConfigGetFonts" ); m_pFcFontSetCreate = (FcFontSet*(*)()) loadSymbol( "FcFontSetCreate" ); m_pFcCharSetCreate = (FcCharSet*(*)()) loadSymbol( "FcCharSetCreate" ); m_pFcCharSetAddChar = (FcBool(*)(FcCharSet*, FcChar32)) loadSymbol( "FcCharSetAddChar" ); m_pFcCharSetHasChar = (FcBool(*)(FcCharSet*, FcChar32)) loadSymbol( "FcCharSetHasChar" ); m_pFcCharSetDestroy = (void(*)(FcCharSet*)) loadSymbol( "FcCharSetDestroy" ); m_pFcFontSetDestroy = (void(*)(FcFontSet*)) loadSymbol( "FcFontSetDestroy" ); m_pFcFontSetAdd = (FcBool(*)(FcFontSet*,FcPattern*)) loadSymbol( "FcFontSetAdd" ); m_pFcPatternReference = (void(*)(FcPattern*)) loadSymbol( "FcPatternReference" ); m_pFcPatternGetCharSet = (FcResult(*)(const FcPattern*,const char*,int,FcCharSet**)) loadSymbol( "FcPatternGetCharSet" ); m_pFcPatternGetString = (FcResult(*)(const FcPattern*,const char*,int,FcChar8**)) loadSymbol( "FcPatternGetString" ); m_pFcPatternGetInteger = (FcResult(*)(const FcPattern*,const char*,int,int*)) loadSymbol( "FcPatternGetInteger" ); m_pFcPatternGetDouble = (FcResult(*)(const FcPattern*,const char*,int,double*)) loadSymbol( "FcPatternGetDouble" ); m_pFcPatternGetBool = (FcResult(*)(const FcPattern*,const char*,int,FcBool*)) loadSymbol( "FcPatternGetBool" ); m_pFcConfigAppFontAddFile = (FcBool(*)(FcConfig*, const FcChar8*)) loadSymbol( "FcConfigAppFontAddFile" ); m_pFcConfigAppFontAddDir = (FcBool(*)(FcConfig*, const FcChar8*)) loadSymbol( "FcConfigAppFontAddDir" ); m_pFcConfigParseAndLoad = (FcBool(*)(FcConfig*, const FcChar8*, FcBool)) loadSymbol( "FcConfigParseAndLoad" ); m_pFcDefaultSubstitute = (void(*)(FcPattern *)) loadSymbol( "FcDefaultSubstitute" ); m_pFcFontSetMatch = (FcPattern*(*)(FcConfig*,FcFontSet**,int,FcPattern*,FcResult*)) loadSymbol( "FcFontSetMatch" ); m_pFcFontMatch = (FcPattern*(*)(FcConfig*,FcPattern*,FcResult*)) loadSymbol( "FcFontMatch" ); m_pFcConfigSubstitute = (FcBool(*)(FcConfig*,FcPattern*,FcMatchKind)) loadSymbol( "FcConfigSubstitute" ); m_pFcPatternDuplicate = (FcPattern*(*)(const FcPattern*)) loadSymbol( "FcPatternDuplicate" ); m_pFcPatternAddInteger = (FcBool(*)(FcPattern*,const char*,int)) loadSymbol( "FcPatternAddInteger" ); m_pFcPatternAddDouble = (FcBool(*)(FcPattern*,const char*,double)) loadSymbol( "FcPatternAddDouble" ); m_pFcPatternAddBool = (FcBool(*)(FcPattern*,const char*,FcBool)) loadSymbol( "FcPatternAddBool" ); m_pFcPatternAddCharSet = (FcBool(*)(FcPattern*,const char*,const FcCharSet *)) loadSymbol( "FcPatternAddCharSet" ); m_pFcPatternAddString = (FcBool(*)(FcPattern*,const char*,const FcChar8*)) loadSymbol( "FcPatternAddString" ); m_pFcPatternDel = (FcBool(*)(FcPattern*,const char*)) loadSymbol( "FcPatternDel" ); m_pFcFreeTypeCharIndex = (FT_UInt(*)(FT_Face,FcChar32)) loadSymbol( "FcFreeTypeCharIndex" ); m_nFcVersion = FcGetVersion(); #if (OSL_DEBUG_LEVEL > 1) fprintf( stderr,"FC_VERSION = %05d\n", m_nFcVersion ); #endif // make minimum version configurable const char* pMinFcVersion = getenv( "SAL_MIN_FC_VERSION"); if( pMinFcVersion ) { const int nMinFcVersion = atoi( pMinFcVersion ); if( m_nFcVersion < nMinFcVersion ) m_pFcInit = NULL; } if( ! ( m_pFcInit && m_pFcGetVersion && m_pFcConfigGetCurrent && m_pFcObjectSetVaBuild && m_pFcObjectSetDestroy && m_pFcPatternCreate && m_pFcPatternDestroy && m_pFcFontList && m_pFcConfigGetFonts && m_pFcFontSetCreate && m_pFcCharSetCreate && m_pFcCharSetAddChar && m_pFcCharSetHasChar && m_pFcCharSetDestroy && m_pFcFontSetDestroy && m_pFcFontSetAdd && m_pFcPatternReference && m_pFcPatternGetCharSet && m_pFcPatternGetString && m_pFcPatternGetInteger && m_pFcPatternGetDouble && m_pFcPatternGetBool && m_pFcConfigAppFontAddFile && m_pFcConfigAppFontAddDir && m_pFcConfigParseAndLoad && m_pFcFontMatch && m_pFcDefaultSubstitute && m_pFcConfigSubstitute && m_pFcPatternDuplicate && m_pFcPatternAddInteger && m_pFcPatternAddDouble && m_pFcPatternAddCharSet && m_pFcPatternAddBool && m_pFcPatternAddString && m_pFcPatternDel ) ) { osl_unloadModule( (oslModule)m_pLib ); m_pLib = NULL; #if OSL_DEBUG_LEVEL > 1 fprintf( stderr, "not all needed symbols were found in libfontconfig\n" ); #endif return; } FcInit(); if( ! FcConfigGetCurrent() ) { osl_unloadModule( (oslModule)m_pLib ); m_pLib = NULL; } } void FontCfgWrapper::addFontSet( FcSetName eSetName ) { #ifdef ENABLE_FONTCONFIG /* add only acceptable outlined fonts to our config, for future fontconfig use */ FcFontSet* pOrig = FcConfigGetFonts( FcConfigGetCurrent(), eSetName ); if( !pOrig ) return; // filter the font sets to remove obsolete or duplicate faces for( int i = 0; i < pOrig->nfont; ++i ) { FcPattern* pOrigPattern = pOrig->fonts[i]; // #i115131# ignore non-outline fonts FcBool bOutline = FcFalse; FcResult eOutRes = FcPatternGetBool( pOrigPattern, FC_OUTLINE, 0, &bOutline ); if( (eOutRes != FcResultMatch) || (bOutline == FcFalse) ) continue; // create a pattern to find eventually better alternatives FcPattern* pBetterPattern = pOrigPattern; if( m_nFcVersion > 20400 ) // #i115204# avoid trouble with old FC versions { FcPattern* pTestPattern = FcPatternDuplicate( pOrigPattern ); FcPatternAddBool( pTestPattern, FC_OUTLINE, FcTrue ); // TODO: ignore all attributes that are not interesting for finding dupes // e.g. by using pattern->ImplFontAttr->pattern conversion FcPatternDel( pTestPattern, FC_FONTVERSION ); FcPatternDel( pTestPattern, FC_CHARSET ); FcPatternDel( pTestPattern, FC_FILE ); // find the font face for the dupe-search pattern FcResult eFcResult = FcResultMatch; pBetterPattern = FcFontMatch( FcConfigGetCurrent(), pTestPattern, &eFcResult ); FcPatternDestroy( pTestPattern ); if( eFcResult != FcResultMatch ) continue; // #i115131# double check results and eventually ignore them eOutRes = FcPatternGetBool( pBetterPattern, FC_OUTLINE, 0, &bOutline ); if( (eOutRes != FcResultMatch) || (bOutline == FcFalse) ) continue; } // insert best found pattern for the dupe-search pattern // TODO: skip inserting patterns that are already known in the target fontset FcPatternReference( pBetterPattern ); FcFontSetAdd( m_pOutlineSet, pBetterPattern ); } // TODO?: FcFontSetDestroy( pOrig ); #else (void)eSetName; // prevent compiler warning about unused parameter #endif } FcFontSet* FontCfgWrapper::getFontSet() { #ifdef ENABLE_FONTCONFIG if( !m_pOutlineSet ) { m_pOutlineSet = FcFontSetCreate(); addFontSet( FcSetSystem ); if( m_nFcVersion > 20400 ) // #i85462# prevent crashes addFontSet( FcSetApplication ); } #endif return m_pOutlineSet; } FontCfgWrapper::~FontCfgWrapper() { if( m_pOutlineSet ) FcFontSetDestroy( m_pOutlineSet ); if( m_pLib ) osl_unloadModule( (oslModule)m_pLib ); } static FontCfgWrapper* pOneInstance = NULL; FontCfgWrapper& FontCfgWrapper::get() { if( ! pOneInstance ) pOneInstance = new FontCfgWrapper(); return *pOneInstance; } void FontCfgWrapper::release() { if( pOneInstance ) { delete pOneInstance; pOneInstance = NULL; } } #ifdef ENABLE_FONTCONFIG namespace { typedef std::pair lang_and_family; class localizedsorter { rtl::OLocale maLoc; public: localizedsorter(rtl_Locale* pLoc) : maLoc(pLoc) {} FcChar8* bestname(const std::vector &families); }; FcChar8* localizedsorter::bestname(const std::vector &families) { FcChar8* candidate = families.begin()->second; rtl::OString sLangMatch(rtl::OUStringToOString(maLoc.getLanguage().toAsciiLowerCase(), RTL_TEXTENCODING_UTF8)); rtl::OString sFullMatch = sLangMatch; sFullMatch += OString('-'); sFullMatch += rtl::OUStringToOString(maLoc.getCountry().toAsciiLowerCase(), RTL_TEXTENCODING_UTF8); std::vector::const_iterator aEnd = families.end(); bool alreadyclosematch = false; for( std::vector::const_iterator aIter = families.begin(); aIter != aEnd; ++aIter ) { const char *pLang = (const char*)aIter->first; if( rtl_str_compare( pLang, sFullMatch.getStr() ) == 0) { // both language and country match candidate = aIter->second; break; } else if( alreadyclosematch ) continue; else if( rtl_str_compare( pLang, sLangMatch.getStr()) == 0) { // just the language matches candidate = aIter->second; alreadyclosematch = true; } else if( rtl_str_compare( pLang, "en") == 0) { // fallback to the english family name candidate = aIter->second; } } return candidate; } } FcResult FontCfgWrapper::FamilyFromPattern(FcPattern* pPattern, FcChar8 **family) { FcChar8 *origfamily; FcResult eFamilyRes = FcPatternGetString( pPattern, FC_FAMILY, 0, &origfamily ); *family = origfamily; if( eFamilyRes == FcResultMatch) { FcChar8* familylang = NULL; if (FcPatternGetString( pPattern, FC_FAMILYLANG, 0, &familylang ) == FcResultMatch) { std::vector< lang_and_family > lang_and_families; lang_and_families.push_back(lang_and_family(familylang, *family)); int k = 1; while (1) { if (FcPatternGetString( pPattern, FC_FAMILYLANG, k, &familylang ) != FcResultMatch) break; if (FcPatternGetString( pPattern, FC_FAMILY, k, family ) != FcResultMatch) break; lang_and_families.push_back(lang_and_family(familylang, *family)); ++k; } //possible to-do, sort by UILocale instead of process locale rtl_Locale* pLoc; osl_getProcessLocale(&pLoc); localizedsorter aSorter(pLoc); *family = aSorter.bestname(lang_and_families); std::vector::const_iterator aEnd = lang_and_families.end(); for (std::vector::const_iterator aIter = lang_and_families.begin(); aIter != aEnd; ++aIter) { const char *candidate = (const char*)(aIter->second); if (rtl_str_compare(candidate, (const char*)(*family)) != 0) m_aFontNameToLocalized[OString(candidate)] = OString((const char*)(*family)); } if (rtl_str_compare((const char*)origfamily, (const char*)(*family)) != 0) m_aLocalizedToCanonical[OString((const char*)(*family))] = OString((const char*)origfamily); } } return eFamilyRes; } /* * PrintFontManager::initFontconfig */ bool PrintFontManager::initFontconfig() { FontCfgWrapper& rWrapper = FontCfgWrapper::get(); if( ! rWrapper.isValid() ) return false; return true; } namespace { weight::type convertWeight(int weight) { // set weight if( weight <= FC_WEIGHT_THIN ) return weight::Thin; else if( weight <= FC_WEIGHT_ULTRALIGHT ) return weight::UltraLight; else if( weight <= FC_WEIGHT_LIGHT ) return weight::Light; else if( weight <= FC_WEIGHT_BOOK ) return weight::SemiLight; else if( weight <= FC_WEIGHT_NORMAL ) return weight::Normal; else if( weight <= FC_WEIGHT_MEDIUM ) return weight::Medium; else if( weight <= FC_WEIGHT_SEMIBOLD ) return weight::SemiBold; else if( weight <= FC_WEIGHT_BOLD ) return weight::Bold; else if( weight <= FC_WEIGHT_ULTRABOLD ) return weight::UltraBold; return weight::Black; } italic::type convertSlant(int slant) { // set italic if( slant == FC_SLANT_ITALIC ) return italic::Italic; else if( slant == FC_SLANT_OBLIQUE ) return italic::Oblique; return italic::Upright; } pitch::type convertSpacing(int spacing) { // set pitch if( spacing == FC_MONO || spacing == FC_CHARCELL ) return pitch::Fixed; return pitch::Variable; } width::type convertWidth(int width) { if (width == FC_WIDTH_ULTRACONDENSED) return width::UltraCondensed; else if (width == FC_WIDTH_EXTRACONDENSED) return width::ExtraCondensed; else if (width == FC_WIDTH_CONDENSED) return width::Condensed; else if (width == FC_WIDTH_SEMICONDENSED) return width::SemiCondensed; else if (width == FC_WIDTH_SEMIEXPANDED) return width::SemiExpanded; else if (width == FC_WIDTH_EXPANDED) return width::Expanded; else if (width == FC_WIDTH_EXTRAEXPANDED) return width::ExtraExpanded; else if (width == FC_WIDTH_ULTRAEXPANDED) return width::UltraExpanded; return width::Normal; } } int PrintFontManager::countFontconfigFonts( std::hash_map& o_rVisitedPaths ) { int nFonts = 0; FontCfgWrapper& rWrapper = FontCfgWrapper::get(); if( !rWrapper.isValid() ) return 0; FcFontSet* pFSet = rWrapper.getFontSet(); if( pFSet ) { #if OSL_DEBUG_LEVEL > 1 fprintf( stderr, "found %d entries in fontconfig fontset\n", pFSet->nfont ); #endif for( int i = 0; i < pFSet->nfont; i++ ) { FcChar8* file = NULL; FcChar8* family = NULL; FcChar8* style = NULL; int slant = 0; int weight = 0; int spacing = 0; int nCollectionEntry = -1; FcBool outline = false; FcResult eFileRes = rWrapper.FcPatternGetString( pFSet->fonts[i], FC_FILE, 0, &file ); FcResult eFamilyRes = rWrapper.FamilyFromPattern( pFSet->fonts[i], &family ); FcResult eStyleRes = rWrapper.FcPatternGetString( pFSet->fonts[i], FC_STYLE, 0, &style ); FcResult eSlantRes = rWrapper.FcPatternGetInteger( pFSet->fonts[i], FC_SLANT, 0, &slant ); FcResult eWeightRes = rWrapper.FcPatternGetInteger( pFSet->fonts[i], FC_WEIGHT, 0, &weight ); FcResult eSpacRes = rWrapper.FcPatternGetInteger( pFSet->fonts[i], FC_SPACING, 0, &spacing ); FcResult eOutRes = rWrapper.FcPatternGetBool( pFSet->fonts[i], FC_OUTLINE, 0, &outline ); FcResult eIndexRes = rWrapper.FcPatternGetInteger( pFSet->fonts[i], FC_INDEX, 0, &nCollectionEntry ); if( eFileRes != FcResultMatch || eFamilyRes != FcResultMatch || eOutRes != FcResultMatch ) continue; #if (OSL_DEBUG_LEVEL > 2) fprintf( stderr, "found font \"%s\" in file %s\n" " weight = %d, slant = %d, style = \"%s\"\n" " spacing = %d, outline = %d\n" , family, file , eWeightRes == FcResultMatch ? weight : -1 , eSpacRes == FcResultMatch ? slant : -1 , eStyleRes == FcResultMatch ? (const char*) style : "" , eSpacRes == FcResultMatch ? spacing : -1 , eOutRes == FcResultMatch ? outline : -1 ); #endif // OSL_ASSERT(eOutRes != FcResultMatch || outline); // only outline fonts are usable to psprint anyway if( eOutRes == FcResultMatch && ! outline ) continue; // see if this font is already cached // update attributes std::list< PrintFont* > aFonts; OString aDir, aBase, aOrgPath( (sal_Char*)file ); splitPath( aOrgPath, aDir, aBase ); o_rVisitedPaths[aDir] = 1; int nDirID = getDirectoryAtom( aDir, true ); if( ! m_pFontCache->getFontCacheFile( nDirID, aBase, aFonts ) ) { #if OSL_DEBUG_LEVEL > 2 fprintf( stderr, "file %s not cached\n", aBase.getStr() ); #endif // not known, analyze font file to get attributes // not described by fontconfig (e.g. alias names, PSName) std::list< OString > aDummy; analyzeFontFile( nDirID, aBase, aDummy, aFonts ); #if OSL_DEBUG_LEVEL > 1 if( aFonts.empty() ) fprintf( stderr, "Warning: file \"%s\" is unusable to psprint\n", aOrgPath.getStr() ); #endif } if( aFonts.empty() ) { // TODO: remove fonts unusable to psprint from fontset continue; } int nFamilyName = m_pAtoms->getAtom( ATOM_FAMILYNAME, OStringToOUString( OString( (sal_Char*)family ), RTL_TEXTENCODING_UTF8 ), sal_True ); PrintFont* pUpdate = aFonts.front(); std::list::const_iterator second_font = aFonts.begin(); ++second_font; if( second_font != aFonts.end() ) // more than one font { // a collection entry, get the correct index if( eIndexRes == FcResultMatch && nCollectionEntry != -1 ) { for( std::list< PrintFont* >::iterator it = aFonts.begin(); it != aFonts.end(); ++it ) { if( (*it)->m_eType == fonttype::TrueType && static_cast(*it)->m_nCollectionEntry == nCollectionEntry ) { pUpdate = *it; break; } } // update collection entry // additional entries will be created in the cache // if this is a new index (that is if the loop above // ran to the end of the list) if( pUpdate->m_eType == fonttype::TrueType ) // sanity check, this should always be the case here static_cast(pUpdate)->m_nCollectionEntry = nCollectionEntry; } else { #if OSL_DEBUG_LEVEL > 1 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 ); #endif // we have found more than one font in this file // but fontconfig will not tell us which index is meant // -> something is in disorder, do not use this font pUpdate = NULL; } } if( pUpdate ) { // set family name if( pUpdate->m_nFamilyName != nFamilyName ) { #if 0 // fontconfig prefers nameid=16 for the family name which is all fine // but Writer suffers from #i79878# // the only reasonable workaround for now is to use the classic nameid=1 pUpdate->m_aAliases.remove( pUpdate->m_nFamilyName ); pUpdate->m_aAliases.push_back( pUpdate->m_nFamilyName ); pUpdate->m_aAliases.remove( nFamilyName ); pUpdate->m_nFamilyName = nFamilyName; #endif } if( eWeightRes == FcResultMatch ) pUpdate->m_eWeight = convertWeight(weight); if( eSpacRes == FcResultMatch ) pUpdate->m_ePitch = convertSpacing(spacing); if( eSlantRes == FcResultMatch ) pUpdate->m_eItalic = convertSlant(slant); if( eStyleRes == FcResultMatch ) { pUpdate->m_aStyleName = OStringToOUString( OString( (sal_Char*)style ), RTL_TEXTENCODING_UTF8 ); } // update font cache m_pFontCache->updateFontCacheEntry( pUpdate, false ); // sort into known fonts fontID aFont = m_nNextFontID++; m_aFonts[ aFont ] = pUpdate; m_aFontFileToFontID[ aBase ].insert( aFont ); nFonts++; #if OSL_DEBUG_LEVEL > 2 fprintf( stderr, "inserted font %s as fontID %d\n", family, aFont ); #endif } // clean up the fonts we did not put into the list for( std::list< PrintFont* >::iterator it = aFonts.begin(); it != aFonts.end(); ++it ) { if( *it != pUpdate ) { m_pFontCache->updateFontCacheEntry( *it, false ); // prepare a cache entry for a collection item delete *it; } } } } // how does one get rid of the config ? #if OSL_DEBUG_LEVEL > 1 fprintf( stderr, "inserted %d fonts from fontconfig\n", nFonts ); #endif return nFonts; } void PrintFontManager::deinitFontconfig() { FontCfgWrapper::release(); } int PrintFontManager::FreeTypeCharIndex( void *pFace, sal_uInt32 aChar ) { FontCfgWrapper& rWrapper = FontCfgWrapper::get(); return rWrapper.isValid() ? rWrapper.FcFreeTypeCharIndex( (FT_Face)pFace, aChar ) : 0; } bool PrintFontManager::addFontconfigDir( const rtl::OString& rDirName ) { FontCfgWrapper& rWrapper = FontCfgWrapper::get(); if( ! rWrapper.isValid() ) return false; // workaround for a stability problems in older FC versions // when handling application specifc fonts const int nVersion = rWrapper.FcGetVersion(); if( nVersion <= 20400 ) return false; const char* pDirName = (const char*)rDirName.getStr(); bool bDirOk = (rWrapper.FcConfigAppFontAddDir( rWrapper.FcConfigGetCurrent(), (FcChar8*)pDirName ) == FcTrue); #if OSL_DEBUG_LEVEL > 1 fprintf( stderr, "FcConfigAppFontAddDir( \"%s\") => %d\n", pDirName, bDirOk ); #endif if( !bDirOk ) return false; // load dir-specific fc-config file too if available const rtl::OString aConfFileName = rDirName + "/fc_local.conf"; FILE* pCfgFile = fopen( aConfFileName.getStr(), "rb" ); if( pCfgFile ) { fclose( pCfgFile); bool bCfgOk = rWrapper.FcConfigParseAndLoad( rWrapper.FcConfigGetCurrent(), (FcChar8*)aConfFileName.getStr(), FcTrue ); if( !bCfgOk ) fprintf( stderr, "FcConfigParseAndLoad( \"%s\") => %d\n", aConfFileName.getStr(), bCfgOk ); } return true; } static void addtopattern(FontCfgWrapper& rWrapper, FcPattern *pPattern, italic::type eItalic, weight::type eWeight, width::type eWidth, pitch::type ePitch) { if( eItalic != italic::Unknown ) { int nSlant = FC_SLANT_ROMAN; switch( eItalic ) { case italic::Italic: nSlant = FC_SLANT_ITALIC;break; case italic::Oblique: nSlant = FC_SLANT_OBLIQUE;break; default: break; } rWrapper.FcPatternAddInteger( pPattern, FC_SLANT, nSlant ); } if( eWeight != weight::Unknown ) { int nWeight = FC_WEIGHT_NORMAL; switch( eWeight ) { case weight::Thin: nWeight = FC_WEIGHT_THIN;break; case weight::UltraLight: nWeight = FC_WEIGHT_ULTRALIGHT;break; case weight::Light: nWeight = FC_WEIGHT_LIGHT;break; case weight::SemiLight: nWeight = FC_WEIGHT_BOOK;break; case weight::Normal: nWeight = FC_WEIGHT_NORMAL;break; case weight::Medium: nWeight = FC_WEIGHT_MEDIUM;break; case weight::SemiBold: nWeight = FC_WEIGHT_SEMIBOLD;break; case weight::Bold: nWeight = FC_WEIGHT_BOLD;break; case weight::UltraBold: nWeight = FC_WEIGHT_ULTRABOLD;break; case weight::Black: nWeight = FC_WEIGHT_BLACK;break; default: break; } rWrapper.FcPatternAddInteger( pPattern, FC_WEIGHT, nWeight ); } if( eWidth != width::Unknown ) { int nWidth = FC_WIDTH_NORMAL; switch( eWidth ) { case width::UltraCondensed: nWidth = FC_WIDTH_ULTRACONDENSED;break; case width::ExtraCondensed: nWidth = FC_WIDTH_EXTRACONDENSED;break; case width::Condensed: nWidth = FC_WIDTH_CONDENSED;break; case width::SemiCondensed: nWidth = FC_WIDTH_SEMICONDENSED;break; case width::Normal: nWidth = FC_WIDTH_NORMAL;break; case width::SemiExpanded: nWidth = FC_WIDTH_SEMIEXPANDED;break; case width::Expanded: nWidth = FC_WIDTH_EXPANDED;break; case width::ExtraExpanded: nWidth = FC_WIDTH_EXTRAEXPANDED;break; case width::UltraExpanded: nWidth = FC_WIDTH_ULTRACONDENSED;break; default: break; } rWrapper.FcPatternAddInteger( pPattern, FC_WIDTH, nWidth ); } if( ePitch != pitch::Unknown ) { int nSpacing = FC_PROPORTIONAL; switch( ePitch ) { case pitch::Fixed: nSpacing = FC_MONO;break; case pitch::Variable: nSpacing = FC_PROPORTIONAL;break; default: break; } rWrapper.FcPatternAddInteger( pPattern, FC_SPACING, nSpacing ); if (nSpacing == FC_MONO) rWrapper.FcPatternAddString( pPattern, FC_FAMILY, (FcChar8*)"monospace"); } } rtl::OUString PrintFontManager::Substitute(const rtl::OUString& rFontName, rtl::OUString& rMissingCodes, const rtl::OString &rLangAttrib, italic::type &rItalic, weight::type &rWeight, width::type &rWidth, pitch::type &rPitch) const { rtl::OUString aName; FontCfgWrapper& rWrapper = FontCfgWrapper::get(); if( ! rWrapper.isValid() ) return aName; // build pattern argument for fontconfig query FcPattern* pPattern = rWrapper.FcPatternCreate(); // Prefer scalable fonts rWrapper.FcPatternAddBool( pPattern, FC_SCALABLE, FcTrue ); const rtl::OString aTargetName = rtl::OUStringToOString( rFontName, RTL_TEXTENCODING_UTF8 ); const FcChar8* pTargetNameUtf8 = (FcChar8*)aTargetName.getStr(); rWrapper.FcPatternAddString( pPattern, FC_FAMILY, pTargetNameUtf8 ); const FcChar8* pLangAttribUtf8 = (FcChar8*)rLangAttrib.getStr(); if( rLangAttrib.getLength() ) rWrapper.FcPatternAddString( pPattern, FC_LANG, pLangAttribUtf8 ); // Add required Unicode characters, if any if ( rMissingCodes.getLength() ) { FcCharSet *unicodes = rWrapper.FcCharSetCreate(); for( sal_Int32 nStrIndex = 0; nStrIndex < rMissingCodes.getLength(); ) { // also handle unicode surrogates const sal_uInt32 nCode = rMissingCodes.iterateCodePoints( &nStrIndex ); rWrapper.FcCharSetAddChar( unicodes, nCode ); } rWrapper.FcPatternAddCharSet( pPattern, FC_CHARSET, unicodes); rWrapper.FcCharSetDestroy( unicodes ); } addtopattern(rWrapper, pPattern, rItalic, rWeight, rWidth, rPitch); // query fontconfig for a substitute rWrapper.FcConfigSubstitute( rWrapper.FcConfigGetCurrent(), pPattern, FcMatchPattern ); rWrapper.FcDefaultSubstitute( pPattern ); // process the result of the fontconfig query FcResult eResult = FcResultNoMatch; FcFontSet* pFontSet = rWrapper.getFontSet(); FcPattern* pResult = rWrapper.FcFontSetMatch( rWrapper.FcConfigGetCurrent(), &pFontSet, 1, pPattern, &eResult ); rWrapper.FcPatternDestroy( pPattern ); FcFontSet* pSet = NULL; if( pResult ) { pSet = rWrapper.FcFontSetCreate(); // info: destroying the pSet destroys pResult implicitly // since pResult was "added" to pSet rWrapper.FcFontSetAdd( pSet, pResult ); } if( pSet ) { if( pSet->nfont > 0 ) { //extract the closest match FcChar8* family = NULL; FcResult eFileRes = rWrapper.FcPatternGetString( pSet->fonts[0], FC_FAMILY, 0, &family ); // get the family name if( eFileRes == FcResultMatch ) { OString sFamily((sal_Char*)family); std::hash_map< rtl::OString, rtl::OString, rtl::OStringHash >::const_iterator aI = rWrapper.m_aFontNameToLocalized.find(sFamily); if (aI != rWrapper.m_aFontNameToLocalized.end()) sFamily = aI->second; aName = rtl::OStringToOUString( sFamily, RTL_TEXTENCODING_UTF8 ); int val = 0; if ( FcResultMatch == rWrapper.FcPatternGetInteger( pSet->fonts[0], FC_WEIGHT, 0, &val)) rWeight = convertWeight(val); if ( FcResultMatch == rWrapper.FcPatternGetInteger( pSet->fonts[0], FC_SLANT, 0, &val)) rItalic = convertSlant(val); if ( FcResultMatch == rWrapper.FcPatternGetInteger( pSet->fonts[0], FC_SPACING, 0, &val)) rPitch = convertSpacing(val); if ( FcResultMatch == rWrapper.FcPatternGetInteger( pSet->fonts[0], FC_WIDTH, 0, &val)) rWidth = convertWidth(val); } // update rMissingCodes by removing resolved unicodes if( rMissingCodes.getLength() > 0 ) { sal_uInt32* pRemainingCodes = (sal_uInt32*)alloca( rMissingCodes.getLength() * sizeof(sal_uInt32) ); int nRemainingLen = 0; FcCharSet* unicodes; if( !rWrapper.FcPatternGetCharSet( pSet->fonts[0], FC_CHARSET, 0, &unicodes ) ) { for( sal_Int32 nStrIndex = 0; nStrIndex < rMissingCodes.getLength(); ) { // also handle unicode surrogates const sal_uInt32 nCode = rMissingCodes.iterateCodePoints( &nStrIndex ); if( rWrapper.FcCharSetHasChar( unicodes, nCode ) != FcTrue ) pRemainingCodes[ nRemainingLen++ ] = nCode; } } rMissingCodes = OUString( pRemainingCodes, nRemainingLen ); } } rWrapper.FcFontSetDestroy( pSet ); } return aName; } bool PrintFontManager::getFontOptions( const FastPrintFontInfo& rInfo, int nSize, void (*subcallback)(void*), ImplFontOptions& rOptions) const { #ifndef ENABLE_FONTCONFIG (void)rInfo;(void)nSize;(void)subcallback;(void)rOptions; return false; #else // ENABLE_FONTCONFIG FontCfgWrapper& rWrapper = FontCfgWrapper::get(); if( ! rWrapper.isValid() ) return false; FcConfig* pConfig = rWrapper.FcConfigGetCurrent(); FcPattern* pPattern = rWrapper.FcPatternCreate(); OString sFamily = OUStringToOString( rInfo.m_aFamilyName, RTL_TEXTENCODING_UTF8 ); std::hash_map< rtl::OString, rtl::OString, rtl::OStringHash >::const_iterator aI = rWrapper.m_aLocalizedToCanonical.find(sFamily); if (aI != rWrapper.m_aLocalizedToCanonical.end()) sFamily = aI->second; if( sFamily.getLength() ) rWrapper.FcPatternAddString( pPattern, FC_FAMILY, (FcChar8*)sFamily.getStr() ); addtopattern(rWrapper, pPattern, rInfo.m_eItalic, rInfo.m_eWeight, rInfo.m_eWidth, rInfo.m_ePitch); rWrapper.FcPatternAddDouble( pPattern, FC_PIXEL_SIZE, nSize); FcBool embitmap = true, antialias = true, autohint = true, hinting = true; int hintstyle = FC_HINT_FULL; rWrapper.FcConfigSubstitute( pConfig, pPattern, FcMatchPattern ); if (subcallback) subcallback(pPattern); rWrapper.FcDefaultSubstitute( pPattern ); FcResult eResult = FcResultNoMatch; FcFontSet* pFontSet = rWrapper.getFontSet(); FcPattern* pResult = rWrapper.FcFontSetMatch( pConfig, &pFontSet, 1, pPattern, &eResult ); if( pResult ) { FcFontSet* pSet = rWrapper.FcFontSetCreate(); rWrapper.FcFontSetAdd( pSet, pResult ); if( pSet->nfont > 0 ) { FcResult eEmbeddedBitmap = rWrapper.FcPatternGetBool(pSet->fonts[0], FC_EMBEDDED_BITMAP, 0, &embitmap); FcResult eAntialias = rWrapper.FcPatternGetBool(pSet->fonts[0], FC_ANTIALIAS, 0, &antialias); FcResult eAutoHint = rWrapper.FcPatternGetBool(pSet->fonts[0], FC_AUTOHINT, 0, &autohint); FcResult eHinting = rWrapper.FcPatternGetBool(pSet->fonts[0], FC_HINTING, 0, &hinting); /*FcResult eHintStyle =*/ rWrapper.FcPatternGetInteger( pSet->fonts[0], FC_HINT_STYLE, 0, &hintstyle); if( eEmbeddedBitmap == FcResultMatch ) rOptions.meEmbeddedBitmap = embitmap ? EMBEDDEDBITMAP_TRUE : EMBEDDEDBITMAP_FALSE; if( eAntialias == FcResultMatch ) rOptions.meAntiAlias = antialias ? ANTIALIAS_TRUE : ANTIALIAS_FALSE; if( eAutoHint == FcResultMatch ) rOptions.meAutoHint = autohint ? AUTOHINT_TRUE : AUTOHINT_FALSE; if( eHinting == FcResultMatch ) rOptions.meHinting = hinting ? HINTING_TRUE : HINTING_FALSE; switch (hintstyle) { case FC_HINT_NONE: rOptions.meHintStyle = HINT_NONE; break; case FC_HINT_SLIGHT: rOptions.meHintStyle = HINT_SLIGHT; break; case FC_HINT_MEDIUM: rOptions.meHintStyle = HINT_MEDIUM; break; default: // fall through case FC_HINT_FULL: rOptions.meHintStyle = HINT_FULL; break; } } // info: destroying the pSet destroys pResult implicitly // since pResult was "added" to pSet rWrapper.FcFontSetDestroy( pSet ); } // cleanup rWrapper.FcPatternDestroy( pPattern ); // TODO: return true only if non-default font options are set const bool bOK = (pResult != NULL); return bOK; #endif } bool PrintFontManager::matchFont( FastPrintFontInfo& rInfo, const com::sun::star::lang::Locale& rLocale ) { FontCfgWrapper& rWrapper = FontCfgWrapper::get(); if( ! rWrapper.isValid() ) return false; FcConfig* pConfig = rWrapper.FcConfigGetCurrent(); FcPattern* pPattern = rWrapper.FcPatternCreate(); OString aLangAttrib; // populate pattern with font characteristics if( rLocale.Language.getLength() ) { OUStringBuffer aLang(6); aLang.append( rLocale.Language ); if( rLocale.Country.getLength() ) { aLang.append( sal_Unicode('-') ); aLang.append( rLocale.Country ); } aLangAttrib = OUStringToOString( aLang.makeStringAndClear(), RTL_TEXTENCODING_UTF8 ); } if( aLangAttrib.getLength() ) rWrapper.FcPatternAddString( pPattern, FC_LANG, (FcChar8*)aLangAttrib.getStr() ); OString aFamily = OUStringToOString( rInfo.m_aFamilyName, RTL_TEXTENCODING_UTF8 ); if( aFamily.getLength() ) rWrapper.FcPatternAddString( pPattern, FC_FAMILY, (FcChar8*)aFamily.getStr() ); addtopattern(rWrapper, pPattern, rInfo.m_eItalic, rInfo.m_eWeight, rInfo.m_eWidth, rInfo.m_ePitch); rWrapper.FcConfigSubstitute( pConfig, pPattern, FcMatchPattern ); rWrapper.FcDefaultSubstitute( pPattern ); FcResult eResult = FcResultNoMatch; FcFontSet *pFontSet = rWrapper.getFontSet(); FcPattern* pResult = rWrapper.FcFontSetMatch( pConfig, &pFontSet, 1, pPattern, &eResult ); bool bSuccess = false; if( pResult ) { FcFontSet* pSet = rWrapper.FcFontSetCreate(); rWrapper.FcFontSetAdd( pSet, pResult ); if( pSet->nfont > 0 ) { //extract the closest match FcChar8* file = NULL; FcResult eFileRes = rWrapper.FcPatternGetString( pSet->fonts[0], FC_FILE, 0, &file ); if( eFileRes == FcResultMatch ) { OString aDir, aBase, aOrgPath( (sal_Char*)file ); splitPath( aOrgPath, aDir, aBase ); int nDirID = getDirectoryAtom( aDir, true ); fontID aFont = findFontFileID( nDirID, aBase ); if( aFont > 0 ) bSuccess = getFontFastInfo( aFont, rInfo ); } } // info: destroying the pSet destroys pResult implicitly // since pResult was "added" to pSet rWrapper.FcFontSetDestroy( pSet ); } // cleanup rWrapper.FcPatternDestroy( pPattern ); return bSuccess; } #else // ENABLE_FONTCONFIG not defined bool PrintFontManager::initFontconfig() { return false; } int PrintFontManager::countFontconfigFonts( std::hash_map& ) { return 0; } void PrintFontManager::deinitFontconfig() {} bool PrintFontManager::addFontconfigDir( const rtl::OString& ) { return false; } bool PrintFontManager::matchFont( FastPrintFontInfo&, const com::sun::star::lang::Locale& ) { return false; } int PrintFontManager::FreeTypeCharIndex( void*, sal_uInt32 ) { return 0; } rtl::OUString PrintFontManager::Substitute( const rtl::OUString&, rtl::OUString&, const rtl::OString&, italic::type, weight::type, width::type, pitch::type) const { rtl::OUString aName; return aName; } #endif // ENABLE_FONTCONFIG