summaryrefslogtreecommitdiff
path: root/vcl/unx/generic/fontmanager/fontconfig.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'vcl/unx/generic/fontmanager/fontconfig.cxx')
-rw-r--r--vcl/unx/generic/fontmanager/fontconfig.cxx1306
1 files changed, 1306 insertions, 0 deletions
diff --git a/vcl/unx/generic/fontmanager/fontconfig.cxx b/vcl/unx/generic/fontmanager/fontconfig.cxx
new file mode 100644
index 000000000000..be7904c55959
--- /dev/null
+++ b/vcl/unx/generic/fontmanager/fontconfig.cxx
@@ -0,0 +1,1306 @@
+/*************************************************************************
+ *
+ * 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
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 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 )
+{
+ 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<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
+