blob: 4397cfb20ec53998290958ae4213391d30930da4 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_vcl.hxx"
#include "fontcache.hxx"
#include "impfont.hxx"
#include "vcl/fontmanager.hxx"
using namespace psp;
#ifdef ENABLE_FONTCONFIG
#include <fontconfig/fontconfig.h>
#include <ft2build.h>
#include <fontconfig/fcfreetype.h>
// 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 <cstdio>
#include <cstdarg>
#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 <utility>
#include <algorithm>
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 )
{
m_pLib = osl_loadAsciiModule( "libfontconfig.so.1", SAL_LOADMODULE_LAZY );
if( !m_pLib )
m_pLib = osl_loadAsciiModule( "libfontconfig.so", 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<FcChar8*, FcChar8*> lang_and_family;
class localizedsorter
{
rtl::OLocale maLoc;
public:
localizedsorter(rtl_Locale* pLoc) : maLoc(pLoc) {}
FcChar8* bestname(const std::vector<lang_and_family> &families);
};
FcChar8* localizedsorter::bestname(const std::vector<lang_and_family> &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<lang_and_family>::const_iterator aEnd = families.end();
bool alreadyclosematch = false;
for( std::vector<lang_and_family>::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<lang_and_family>::const_iterator aEnd = lang_and_families.end();
for (std::vector<lang_and_family>::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<rtl::OString, int, rtl::OStringHash>& 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 : "<nil>"
, 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<PrintFont*>::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<TrueTypeFontFile*>(*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<TrueTypeFontFile*>(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<rtl::OString, int, rtl::OStringHash>& )
{
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