1*b1cdbd2cSJim Jagielski /**************************************************************
2*b1cdbd2cSJim Jagielski  *
3*b1cdbd2cSJim Jagielski  * Licensed to the Apache Software Foundation (ASF) under one
4*b1cdbd2cSJim Jagielski  * or more contributor license agreements.  See the NOTICE file
5*b1cdbd2cSJim Jagielski  * distributed with this work for additional information
6*b1cdbd2cSJim Jagielski  * regarding copyright ownership.  The ASF licenses this file
7*b1cdbd2cSJim Jagielski  * to you under the Apache License, Version 2.0 (the
8*b1cdbd2cSJim Jagielski  * "License"); you may not use this file except in compliance
9*b1cdbd2cSJim Jagielski  * with the License.  You may obtain a copy of the License at
10*b1cdbd2cSJim Jagielski  *
11*b1cdbd2cSJim Jagielski  *   http://www.apache.org/licenses/LICENSE-2.0
12*b1cdbd2cSJim Jagielski  *
13*b1cdbd2cSJim Jagielski  * Unless required by applicable law or agreed to in writing,
14*b1cdbd2cSJim Jagielski  * software distributed under the License is distributed on an
15*b1cdbd2cSJim Jagielski  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*b1cdbd2cSJim Jagielski  * KIND, either express or implied.  See the License for the
17*b1cdbd2cSJim Jagielski  * specific language governing permissions and limitations
18*b1cdbd2cSJim Jagielski  * under the License.
19*b1cdbd2cSJim Jagielski  *
20*b1cdbd2cSJim Jagielski  *************************************************************/
21*b1cdbd2cSJim Jagielski 
22*b1cdbd2cSJim Jagielski 
23*b1cdbd2cSJim Jagielski 
24*b1cdbd2cSJim Jagielski // MARKER(update_precomp.py): autogen include statement, do not remove
25*b1cdbd2cSJim Jagielski #include "precompiled_vcl.hxx"
26*b1cdbd2cSJim Jagielski 
27*b1cdbd2cSJim Jagielski #include "fontcache.hxx"
28*b1cdbd2cSJim Jagielski #include "impfont.hxx"
29*b1cdbd2cSJim Jagielski #include "vcl/fontmanager.hxx"
30*b1cdbd2cSJim Jagielski 
31*b1cdbd2cSJim Jagielski using namespace psp;
32*b1cdbd2cSJim Jagielski 
33*b1cdbd2cSJim Jagielski #ifdef ENABLE_FONTCONFIG
34*b1cdbd2cSJim Jagielski     #include <fontconfig/fontconfig.h>
35*b1cdbd2cSJim Jagielski     #include <ft2build.h>
36*b1cdbd2cSJim Jagielski     #include <fontconfig/fcfreetype.h>
37*b1cdbd2cSJim Jagielski     // allow compile on baseline (currently with fontconfig 2.2.0)
38*b1cdbd2cSJim Jagielski     #ifndef FC_WEIGHT_BOOK		// TODO: remove when baseline moves to fc>=2.2.1
39*b1cdbd2cSJim Jagielski         #define FC_WEIGHT_BOOK 75
40*b1cdbd2cSJim Jagielski     #endif
41*b1cdbd2cSJim Jagielski     #ifndef FC_EMBEDDED_BITMAP	// TODO: remove when baseline moves to fc>=2.3.92
42*b1cdbd2cSJim Jagielski         #define FC_EMBEDDED_BITMAP "embeddedbitmap"
43*b1cdbd2cSJim Jagielski     #endif
44*b1cdbd2cSJim Jagielski     #ifndef FC_FAMILYLANG		// TODO: remove when baseline moves to fc>=2.2.97
45*b1cdbd2cSJim Jagielski         #define FC_FAMILYLANG "familylang"
46*b1cdbd2cSJim Jagielski     #endif
47*b1cdbd2cSJim Jagielski     #ifndef FC_HINT_STYLE		// TODO: remove when baseline moves to fc>=2.2.91
48*b1cdbd2cSJim Jagielski     	#define FC_HINT_STYLE  "hintstyle"
49*b1cdbd2cSJim Jagielski     	#define FC_HINT_NONE   0
50*b1cdbd2cSJim Jagielski     	#define FC_HINT_SLIGHT 1
51*b1cdbd2cSJim Jagielski     	#define FC_HINT_MEDIUM 2
52*b1cdbd2cSJim Jagielski     	#define FC_HINT_FULL   3
53*b1cdbd2cSJim Jagielski 	#endif
54*b1cdbd2cSJim Jagielski #else
55*b1cdbd2cSJim Jagielski     typedef void FcConfig;
56*b1cdbd2cSJim Jagielski     typedef void FcObjectSet;
57*b1cdbd2cSJim Jagielski     typedef void FcPattern;
58*b1cdbd2cSJim Jagielski     typedef void FcFontSet;
59*b1cdbd2cSJim Jagielski     typedef void FcCharSet;
60*b1cdbd2cSJim Jagielski     typedef int FcResult;
61*b1cdbd2cSJim Jagielski     typedef int FcBool;
62*b1cdbd2cSJim Jagielski     typedef int FcMatchKind;
63*b1cdbd2cSJim Jagielski     typedef char FcChar8;
64*b1cdbd2cSJim Jagielski     typedef int FcChar32;
65*b1cdbd2cSJim Jagielski     typedef unsigned int FT_UInt;
66*b1cdbd2cSJim Jagielski     typedef void* FT_Face;
67*b1cdbd2cSJim Jagielski     typedef int FcSetName;
68*b1cdbd2cSJim Jagielski #endif
69*b1cdbd2cSJim Jagielski 
70*b1cdbd2cSJim Jagielski #include <cstdio>
71*b1cdbd2cSJim Jagielski #include <cstdarg>
72*b1cdbd2cSJim Jagielski 
73*b1cdbd2cSJim Jagielski #include "unotools/atom.hxx"
74*b1cdbd2cSJim Jagielski 
75*b1cdbd2cSJim Jagielski #include "osl/module.h"
76*b1cdbd2cSJim Jagielski #include "osl/thread.h"
77*b1cdbd2cSJim Jagielski #include "osl/process.h"
78*b1cdbd2cSJim Jagielski 
79*b1cdbd2cSJim Jagielski #include "rtl/ustrbuf.hxx"
80*b1cdbd2cSJim Jagielski #include "rtl/locale.hxx"
81*b1cdbd2cSJim Jagielski 
82*b1cdbd2cSJim Jagielski #include "sal/alloca.h"
83*b1cdbd2cSJim Jagielski 
84*b1cdbd2cSJim Jagielski #include <utility>
85*b1cdbd2cSJim Jagielski #include <algorithm>
86*b1cdbd2cSJim Jagielski 
87*b1cdbd2cSJim Jagielski using namespace osl;
88*b1cdbd2cSJim Jagielski using namespace rtl;
89*b1cdbd2cSJim Jagielski 
90*b1cdbd2cSJim Jagielski class FontCfgWrapper
91*b1cdbd2cSJim Jagielski {
92*b1cdbd2cSJim Jagielski     oslModule		m_pLib;
93*b1cdbd2cSJim Jagielski     FcFontSet*      m_pOutlineSet;
94*b1cdbd2cSJim Jagielski 
95*b1cdbd2cSJim Jagielski     int             m_nFcVersion;
96*b1cdbd2cSJim Jagielski     FcBool          (*m_pFcInit)();
97*b1cdbd2cSJim Jagielski     int             (*m_pFcGetVersion)();
98*b1cdbd2cSJim Jagielski     FcConfig*		(*m_pFcConfigGetCurrent)();
99*b1cdbd2cSJim Jagielski     FcObjectSet*	(*m_pFcObjectSetVaBuild)(const char*,va_list);
100*b1cdbd2cSJim Jagielski     void			(*m_pFcObjectSetDestroy)(FcObjectSet* pSet);
101*b1cdbd2cSJim Jagielski     FcPattern*		(*m_pFcPatternCreate)();
102*b1cdbd2cSJim Jagielski     void			(*m_pFcPatternDestroy)(FcPattern*);
103*b1cdbd2cSJim Jagielski     FcFontSet*		(*m_pFcFontList)(FcConfig*,FcPattern*,FcObjectSet*);
104*b1cdbd2cSJim Jagielski     FcFontSet*      (*m_pFcConfigGetFonts)(FcConfig*,FcSetName);
105*b1cdbd2cSJim Jagielski     FcFontSet*		(*m_pFcFontSetCreate)();
106*b1cdbd2cSJim Jagielski     FcCharSet*                (*m_pFcCharSetCreate)();
107*b1cdbd2cSJim Jagielski     FcBool                    (*m_pFcCharSetAddChar)(FcCharSet *, FcChar32);
108*b1cdbd2cSJim Jagielski     FcBool          (*m_pFcCharSetHasChar)(FcCharSet *, FcChar32);
109*b1cdbd2cSJim Jagielski     void            (*m_pFcCharSetDestroy)(FcCharSet*);
110*b1cdbd2cSJim Jagielski     void			(*m_pFcFontSetDestroy)(FcFontSet*);
111*b1cdbd2cSJim Jagielski     FcBool			(*m_pFcFontSetAdd)(FcFontSet*,FcPattern*);
112*b1cdbd2cSJim Jagielski     void            (*m_pFcPatternReference)(FcPattern*);
113*b1cdbd2cSJim Jagielski     FcResult        (*m_pFcPatternGetCharSet)(const FcPattern*,const char*,int,FcCharSet**);
114*b1cdbd2cSJim Jagielski     FcResult		(*m_pFcPatternGetString)(const FcPattern*,const char*,int,FcChar8**);
115*b1cdbd2cSJim Jagielski     FcResult		(*m_pFcPatternGetInteger)(const FcPattern*,const char*,int,int*);
116*b1cdbd2cSJim Jagielski     FcResult		(*m_pFcPatternGetDouble)(const FcPattern*,const char*,int,double*);
117*b1cdbd2cSJim Jagielski     FcResult		(*m_pFcPatternGetBool)(const FcPattern*,const char*,int,FcBool*);
118*b1cdbd2cSJim Jagielski     void			(*m_pFcDefaultSubstitute)(FcPattern *);
119*b1cdbd2cSJim Jagielski     FcPattern*		(*m_pFcFontSetMatch)(FcConfig*,FcFontSet**, int, FcPattern*,FcResult*);
120*b1cdbd2cSJim Jagielski     FcPattern*		(*m_pFcFontMatch)(FcConfig*,FcPattern*,FcResult*);
121*b1cdbd2cSJim Jagielski     FcBool			(*m_pFcConfigAppFontAddFile)(FcConfig*, const FcChar8*);
122*b1cdbd2cSJim Jagielski     FcBool			(*m_pFcConfigAppFontAddDir)(FcConfig*, const FcChar8*);
123*b1cdbd2cSJim Jagielski     FcBool			(*m_pFcConfigParseAndLoad)(FcConfig*,const FcChar8*,FcBool);
124*b1cdbd2cSJim Jagielski     FcBool			(*m_pFcConfigSubstitute)(FcConfig*,FcPattern*,FcMatchKind);
125*b1cdbd2cSJim Jagielski 
126*b1cdbd2cSJim Jagielski     FcPattern*		(*m_pFcPatternDuplicate)(const FcPattern*);
127*b1cdbd2cSJim Jagielski     FcBool			(*m_pFcPatternAddInteger)(FcPattern*,const char*,int);
128*b1cdbd2cSJim Jagielski     FcBool                    (*m_pFcPatternAddDouble)(FcPattern*,const char*,double);
129*b1cdbd2cSJim Jagielski     FcBool                    (*m_pFcPatternAddBool)(FcPattern*,const char*,FcBool);
130*b1cdbd2cSJim Jagielski     FcBool                    (*m_pFcPatternAddCharSet)(FcPattern*,const char*,const FcCharSet*);
131*b1cdbd2cSJim Jagielski     FcBool			(*m_pFcPatternAddString)(FcPattern*,const char*,const FcChar8*);
132*b1cdbd2cSJim Jagielski     FcBool                    (*m_pFcPatternDel)(FcPattern*,const char*);
133*b1cdbd2cSJim Jagielski 
134*b1cdbd2cSJim Jagielski 	FT_UInt         (*m_pFcFreeTypeCharIndex)(FT_Face,FcChar32);
135*b1cdbd2cSJim Jagielski 
136*b1cdbd2cSJim Jagielski     oslGenericFunction loadSymbol( const char* );
137*b1cdbd2cSJim Jagielski     void addFontSet( FcSetName );
138*b1cdbd2cSJim Jagielski 
139*b1cdbd2cSJim Jagielski     FontCfgWrapper();
140*b1cdbd2cSJim Jagielski     ~FontCfgWrapper();
141*b1cdbd2cSJim Jagielski 
142*b1cdbd2cSJim Jagielski public:
143*b1cdbd2cSJim Jagielski     static FontCfgWrapper& get();
144*b1cdbd2cSJim Jagielski     static void release();
145*b1cdbd2cSJim Jagielski 
isValid() const146*b1cdbd2cSJim Jagielski     bool isValid() const
147*b1cdbd2cSJim Jagielski     { return m_pLib != NULL;}
148*b1cdbd2cSJim Jagielski 
149*b1cdbd2cSJim Jagielski     FcFontSet* getFontSet();
150*b1cdbd2cSJim Jagielski 
FcInit()151*b1cdbd2cSJim Jagielski     FcBool FcInit()
152*b1cdbd2cSJim Jagielski     { return m_pFcInit(); }
153*b1cdbd2cSJim Jagielski 
FcGetVersion()154*b1cdbd2cSJim Jagielski     int FcGetVersion()
155*b1cdbd2cSJim Jagielski     { return m_pFcGetVersion(); }
156*b1cdbd2cSJim Jagielski 
FcConfigGetCurrent()157*b1cdbd2cSJim Jagielski     FcConfig* FcConfigGetCurrent()
158*b1cdbd2cSJim Jagielski     { return m_pFcConfigGetCurrent(); }
159*b1cdbd2cSJim Jagielski 
FcObjectSetBuild(const char * first,...)160*b1cdbd2cSJim Jagielski     FcObjectSet* FcObjectSetBuild( const char* first, ... )
161*b1cdbd2cSJim Jagielski     {
162*b1cdbd2cSJim Jagielski         va_list ap;
163*b1cdbd2cSJim Jagielski         va_start( ap, first );
164*b1cdbd2cSJim Jagielski         FcObjectSet* pSet = m_pFcObjectSetVaBuild( first, ap );
165*b1cdbd2cSJim Jagielski         va_end( ap );
166*b1cdbd2cSJim Jagielski         return pSet;
167*b1cdbd2cSJim Jagielski     }
168*b1cdbd2cSJim Jagielski 
FcObjectSetDestroy(FcObjectSet * pSet)169*b1cdbd2cSJim Jagielski     void FcObjectSetDestroy( FcObjectSet* pSet )
170*b1cdbd2cSJim Jagielski     { m_pFcObjectSetDestroy( pSet ); }
171*b1cdbd2cSJim Jagielski 
FcPatternCreate()172*b1cdbd2cSJim Jagielski     FcPattern* FcPatternCreate()
173*b1cdbd2cSJim Jagielski     { return m_pFcPatternCreate(); }
174*b1cdbd2cSJim Jagielski 
FcPatternDestroy(FcPattern * pPattern)175*b1cdbd2cSJim Jagielski     void FcPatternDestroy( FcPattern* pPattern )
176*b1cdbd2cSJim Jagielski     { m_pFcPatternDestroy( pPattern ); }
177*b1cdbd2cSJim Jagielski 
FcFontList(FcConfig * pConfig,FcPattern * pPattern,FcObjectSet * pSet)178*b1cdbd2cSJim Jagielski     FcFontSet* FcFontList( FcConfig* pConfig, FcPattern* pPattern, FcObjectSet* pSet )
179*b1cdbd2cSJim Jagielski     { return m_pFcFontList( pConfig, pPattern, pSet ); }
180*b1cdbd2cSJim Jagielski 
FcConfigGetFonts(FcConfig * pConfig,FcSetName eSet)181*b1cdbd2cSJim Jagielski     FcFontSet* FcConfigGetFonts( FcConfig* pConfig, FcSetName eSet)
182*b1cdbd2cSJim Jagielski     { return m_pFcConfigGetFonts( pConfig, eSet ); }
183*b1cdbd2cSJim Jagielski 
FcFontSetCreate()184*b1cdbd2cSJim Jagielski     FcFontSet* FcFontSetCreate()
185*b1cdbd2cSJim Jagielski     { return m_pFcFontSetCreate(); }
186*b1cdbd2cSJim Jagielski 
FcCharSetCreate()187*b1cdbd2cSJim Jagielski     FcCharSet* FcCharSetCreate()
188*b1cdbd2cSJim Jagielski     { return m_pFcCharSetCreate(); }
189*b1cdbd2cSJim Jagielski 
FcCharSetAddChar(FcCharSet * fcs,FcChar32 ucs4)190*b1cdbd2cSJim Jagielski     FcBool FcCharSetAddChar(FcCharSet *fcs, FcChar32 ucs4)
191*b1cdbd2cSJim Jagielski     { return m_pFcCharSetAddChar(fcs, ucs4); }
192*b1cdbd2cSJim Jagielski 
FcCharSetHasChar(FcCharSet * fcs,FcChar32 ucs4)193*b1cdbd2cSJim Jagielski     FcBool FcCharSetHasChar(FcCharSet *fcs, FcChar32 ucs4)
194*b1cdbd2cSJim Jagielski     { return m_pFcCharSetHasChar(fcs, ucs4); }
195*b1cdbd2cSJim Jagielski 
FcCharSetDestroy(FcCharSet * pSet)196*b1cdbd2cSJim Jagielski     void FcCharSetDestroy( FcCharSet* pSet )
197*b1cdbd2cSJim Jagielski     { m_pFcCharSetDestroy( pSet );}
198*b1cdbd2cSJim Jagielski 
FcFontSetDestroy(FcFontSet * pSet)199*b1cdbd2cSJim Jagielski     void FcFontSetDestroy( FcFontSet* pSet )
200*b1cdbd2cSJim Jagielski     { m_pFcFontSetDestroy( pSet );}
201*b1cdbd2cSJim Jagielski 
FcFontSetAdd(FcFontSet * pSet,FcPattern * pPattern)202*b1cdbd2cSJim Jagielski     FcBool FcFontSetAdd( FcFontSet* pSet, FcPattern* pPattern )
203*b1cdbd2cSJim Jagielski     { return m_pFcFontSetAdd( pSet, pPattern ); }
204*b1cdbd2cSJim Jagielski 
FcPatternReference(FcPattern * pPattern)205*b1cdbd2cSJim Jagielski     void FcPatternReference( FcPattern* pPattern )
206*b1cdbd2cSJim Jagielski     { m_pFcPatternReference( pPattern ); }
207*b1cdbd2cSJim Jagielski 
FcPatternGetCharSet(const FcPattern * pPattern,const char * object,int n,FcCharSet ** s)208*b1cdbd2cSJim Jagielski     FcResult FcPatternGetCharSet( const FcPattern* pPattern, const char* object, int n, FcCharSet** s )
209*b1cdbd2cSJim Jagielski     { return m_pFcPatternGetCharSet( pPattern, object, n, s ); }
210*b1cdbd2cSJim Jagielski 
FcPatternGetString(const FcPattern * pPattern,const char * object,int n,FcChar8 ** s)211*b1cdbd2cSJim Jagielski     FcResult FcPatternGetString( const FcPattern* pPattern, const char* object, int n, FcChar8** s )
212*b1cdbd2cSJim Jagielski     { return m_pFcPatternGetString( pPattern, object, n, s ); }
213*b1cdbd2cSJim Jagielski 
FcPatternGetInteger(const FcPattern * pPattern,const char * object,int n,int * s)214*b1cdbd2cSJim Jagielski     FcResult FcPatternGetInteger( const FcPattern* pPattern, const char* object, int n, int* s )
215*b1cdbd2cSJim Jagielski     { return m_pFcPatternGetInteger( pPattern, object, n, s ); }
216*b1cdbd2cSJim Jagielski 
FcPatternGetDouble(const FcPattern * pPattern,const char * object,int n,double * s)217*b1cdbd2cSJim Jagielski     FcResult FcPatternGetDouble( const FcPattern* pPattern, const char* object, int n, double* s )
218*b1cdbd2cSJim Jagielski     { return m_pFcPatternGetDouble( pPattern, object, n, s ); }
219*b1cdbd2cSJim Jagielski 
FcPatternGetBool(const FcPattern * pPattern,const char * object,int n,FcBool * s)220*b1cdbd2cSJim Jagielski     FcResult FcPatternGetBool( const FcPattern* pPattern, const char* object, int n, FcBool* s )
221*b1cdbd2cSJim Jagielski     { return m_pFcPatternGetBool( pPattern, object, n, s ); }
FcConfigAppFontAddFile(FcConfig * pConfig,const FcChar8 * pFileName)222*b1cdbd2cSJim Jagielski     FcBool FcConfigAppFontAddFile( FcConfig* pConfig, const FcChar8* pFileName )
223*b1cdbd2cSJim Jagielski     { return m_pFcConfigAppFontAddFile( pConfig, pFileName ); }
FcConfigAppFontAddDir(FcConfig * pConfig,const FcChar8 * pDirName)224*b1cdbd2cSJim Jagielski     FcBool FcConfigAppFontAddDir(FcConfig* pConfig, const FcChar8* pDirName )
225*b1cdbd2cSJim Jagielski     { return m_pFcConfigAppFontAddDir( pConfig, pDirName ); }
FcConfigParseAndLoad(FcConfig * pConfig,const FcChar8 * pFileName,FcBool bComplain)226*b1cdbd2cSJim Jagielski     FcBool FcConfigParseAndLoad( FcConfig* pConfig, const FcChar8* pFileName, FcBool bComplain )
227*b1cdbd2cSJim Jagielski     { return m_pFcConfigParseAndLoad( pConfig, pFileName, bComplain ); }
228*b1cdbd2cSJim Jagielski 
FcDefaultSubstitute(FcPattern * pPattern)229*b1cdbd2cSJim Jagielski     void FcDefaultSubstitute( FcPattern* pPattern )
230*b1cdbd2cSJim Jagielski     { m_pFcDefaultSubstitute( pPattern ); }
FcFontSetMatch(FcConfig * pConfig,FcFontSet ** ppFontSet,int nset,FcPattern * pPattern,FcResult * pResult)231*b1cdbd2cSJim Jagielski     FcPattern* FcFontSetMatch( FcConfig* pConfig, FcFontSet **ppFontSet, int nset, FcPattern* pPattern, FcResult* pResult )
232*b1cdbd2cSJim Jagielski     { return m_pFcFontSetMatch ? m_pFcFontSetMatch( pConfig, ppFontSet, nset, pPattern, pResult ) : 0; }
FcFontMatch(FcConfig * pConfig,FcPattern * pPattern,FcResult * pResult)233*b1cdbd2cSJim Jagielski     FcPattern* FcFontMatch( FcConfig* pConfig, FcPattern* pPattern, FcResult* pResult )
234*b1cdbd2cSJim Jagielski     { return m_pFcFontMatch( pConfig, pPattern, pResult ); }
FcConfigSubstitute(FcConfig * pConfig,FcPattern * pPattern,FcMatchKind eKind)235*b1cdbd2cSJim Jagielski     FcBool FcConfigSubstitute( FcConfig* pConfig, FcPattern* pPattern, FcMatchKind eKind )
236*b1cdbd2cSJim Jagielski     { return m_pFcConfigSubstitute( pConfig, pPattern, eKind ); }
237*b1cdbd2cSJim Jagielski 
FcPatternDuplicate(const FcPattern * pPattern) const238*b1cdbd2cSJim Jagielski     FcPattern* FcPatternDuplicate( const FcPattern* pPattern ) const
239*b1cdbd2cSJim Jagielski     { return m_pFcPatternDuplicate( pPattern ); }
FcPatternAddInteger(FcPattern * pPattern,const char * pObject,int nValue)240*b1cdbd2cSJim Jagielski     FcBool FcPatternAddInteger( FcPattern* pPattern, const char* pObject, int nValue )
241*b1cdbd2cSJim Jagielski     { return m_pFcPatternAddInteger( pPattern, pObject, nValue ); }
FcPatternAddDouble(FcPattern * pPattern,const char * pObject,double nValue)242*b1cdbd2cSJim Jagielski     FcBool FcPatternAddDouble( FcPattern* pPattern, const char* pObject, double nValue )
243*b1cdbd2cSJim Jagielski     { return m_pFcPatternAddDouble( pPattern, pObject, nValue ); }
FcPatternAddString(FcPattern * pPattern,const char * pObject,const FcChar8 * pString)244*b1cdbd2cSJim Jagielski     FcBool FcPatternAddString( FcPattern* pPattern, const char* pObject, const FcChar8* pString )
245*b1cdbd2cSJim Jagielski     { return m_pFcPatternAddString( pPattern, pObject, pString ); }
FcPatternAddBool(FcPattern * pPattern,const char * pObject,bool nValue)246*b1cdbd2cSJim Jagielski     FcBool FcPatternAddBool( FcPattern* pPattern, const char* pObject, bool nValue )
247*b1cdbd2cSJim Jagielski     { return m_pFcPatternAddBool( pPattern, pObject, nValue ); }
FcPatternAddCharSet(FcPattern * pPattern,const char * pObject,const FcCharSet * pCharSet)248*b1cdbd2cSJim Jagielski     FcBool FcPatternAddCharSet(FcPattern* pPattern,const char* pObject,const FcCharSet*pCharSet)
249*b1cdbd2cSJim Jagielski     { return m_pFcPatternAddCharSet(pPattern,pObject,pCharSet); }
FcPatternDel(FcPattern * pPattern,const char * object)250*b1cdbd2cSJim Jagielski 	FcBool FcPatternDel(FcPattern* pPattern, const char* object)
251*b1cdbd2cSJim Jagielski 	{ return m_pFcPatternDel( pPattern, object); }
252*b1cdbd2cSJim Jagielski 
FcFreeTypeCharIndex(FT_Face face,FcChar32 ucs4)253*b1cdbd2cSJim Jagielski     FT_UInt FcFreeTypeCharIndex( FT_Face face, FcChar32 ucs4 )
254*b1cdbd2cSJim Jagielski     { return m_pFcFreeTypeCharIndex ? m_pFcFreeTypeCharIndex( face, ucs4 ) : 0; }
255*b1cdbd2cSJim Jagielski 
256*b1cdbd2cSJim Jagielski public: // TODO: cleanup
257*b1cdbd2cSJim Jagielski     FcResult FamilyFromPattern(FcPattern* pPattern, FcChar8 **family);
258*b1cdbd2cSJim Jagielski     std::hash_map< rtl::OString, rtl::OString, rtl::OStringHash > m_aFontNameToLocalized;
259*b1cdbd2cSJim Jagielski     std::hash_map< rtl::OString, rtl::OString, rtl::OStringHash > m_aLocalizedToCanonical;
260*b1cdbd2cSJim Jagielski };
261*b1cdbd2cSJim Jagielski 
loadSymbol(const char * pSymbol)262*b1cdbd2cSJim Jagielski oslGenericFunction FontCfgWrapper::loadSymbol( const char* pSymbol )
263*b1cdbd2cSJim Jagielski {
264*b1cdbd2cSJim Jagielski     OUString aSym( OUString::createFromAscii( pSymbol ) );
265*b1cdbd2cSJim Jagielski     oslGenericFunction pSym = osl_getFunctionSymbol( m_pLib, aSym.pData );
266*b1cdbd2cSJim Jagielski #if OSL_DEBUG_LEVEL > 1
267*b1cdbd2cSJim Jagielski     fprintf( stderr, "%s %s\n", pSymbol, pSym ? "found" : "not found" );
268*b1cdbd2cSJim Jagielski #endif
269*b1cdbd2cSJim Jagielski     return pSym;
270*b1cdbd2cSJim Jagielski }
271*b1cdbd2cSJim Jagielski 
FontCfgWrapper()272*b1cdbd2cSJim Jagielski FontCfgWrapper::FontCfgWrapper()
273*b1cdbd2cSJim Jagielski         : m_pLib( NULL ),
274*b1cdbd2cSJim Jagielski           m_pOutlineSet( NULL ),
275*b1cdbd2cSJim Jagielski           m_nFcVersion( 0 )
276*b1cdbd2cSJim Jagielski {
277*b1cdbd2cSJim Jagielski     m_pLib = osl_loadAsciiModule( "libfontconfig.so.1", SAL_LOADMODULE_LAZY );
278*b1cdbd2cSJim Jagielski     if( !m_pLib )
279*b1cdbd2cSJim Jagielski         m_pLib = osl_loadAsciiModule( "libfontconfig.so", SAL_LOADMODULE_LAZY );
280*b1cdbd2cSJim Jagielski 
281*b1cdbd2cSJim Jagielski     if( ! m_pLib )
282*b1cdbd2cSJim Jagielski     {
283*b1cdbd2cSJim Jagielski #if OSL_DEBUG_LEVEL > 1
284*b1cdbd2cSJim Jagielski         fprintf( stderr, "no libfontconfig\n" );
285*b1cdbd2cSJim Jagielski #endif
286*b1cdbd2cSJim Jagielski         return;
287*b1cdbd2cSJim Jagielski     }
288*b1cdbd2cSJim Jagielski 
289*b1cdbd2cSJim Jagielski     m_pFcInit = (FcBool(*)())
290*b1cdbd2cSJim Jagielski         loadSymbol( "FcInit" );
291*b1cdbd2cSJim Jagielski     m_pFcGetVersion = (int(*)())
292*b1cdbd2cSJim Jagielski         loadSymbol( "FcGetVersion" );
293*b1cdbd2cSJim Jagielski     m_pFcConfigGetCurrent = (FcConfig *(*)())
294*b1cdbd2cSJim Jagielski         loadSymbol( "FcConfigGetCurrent" );
295*b1cdbd2cSJim Jagielski     m_pFcObjectSetVaBuild = (FcObjectSet*(*)(const char*,va_list))
296*b1cdbd2cSJim Jagielski         loadSymbol( "FcObjectSetVaBuild" );
297*b1cdbd2cSJim Jagielski     m_pFcObjectSetDestroy = (void(*)(FcObjectSet*))
298*b1cdbd2cSJim Jagielski         loadSymbol( "FcObjectSetDestroy" );
299*b1cdbd2cSJim Jagielski     m_pFcPatternCreate = (FcPattern*(*)())
300*b1cdbd2cSJim Jagielski         loadSymbol( "FcPatternCreate" );
301*b1cdbd2cSJim Jagielski     m_pFcPatternDestroy = (void(*)(FcPattern*))
302*b1cdbd2cSJim Jagielski         loadSymbol( "FcPatternDestroy" );
303*b1cdbd2cSJim Jagielski     m_pFcFontList = (FcFontSet*(*)(FcConfig*,FcPattern*,FcObjectSet*))
304*b1cdbd2cSJim Jagielski         loadSymbol( "FcFontList" );
305*b1cdbd2cSJim Jagielski     m_pFcConfigGetFonts = (FcFontSet*(*)(FcConfig*,FcSetName))
306*b1cdbd2cSJim Jagielski         loadSymbol( "FcConfigGetFonts" );
307*b1cdbd2cSJim Jagielski     m_pFcFontSetCreate = (FcFontSet*(*)())
308*b1cdbd2cSJim Jagielski         loadSymbol( "FcFontSetCreate" );
309*b1cdbd2cSJim Jagielski     m_pFcCharSetCreate = (FcCharSet*(*)())
310*b1cdbd2cSJim Jagielski         loadSymbol( "FcCharSetCreate" );
311*b1cdbd2cSJim Jagielski     m_pFcCharSetAddChar = (FcBool(*)(FcCharSet*, FcChar32))
312*b1cdbd2cSJim Jagielski         loadSymbol( "FcCharSetAddChar" );
313*b1cdbd2cSJim Jagielski     m_pFcCharSetHasChar = (FcBool(*)(FcCharSet*, FcChar32))
314*b1cdbd2cSJim Jagielski         loadSymbol( "FcCharSetHasChar" );
315*b1cdbd2cSJim Jagielski     m_pFcCharSetDestroy = (void(*)(FcCharSet*))
316*b1cdbd2cSJim Jagielski         loadSymbol( "FcCharSetDestroy" );
317*b1cdbd2cSJim Jagielski     m_pFcFontSetDestroy = (void(*)(FcFontSet*))
318*b1cdbd2cSJim Jagielski         loadSymbol( "FcFontSetDestroy" );
319*b1cdbd2cSJim Jagielski     m_pFcFontSetAdd = (FcBool(*)(FcFontSet*,FcPattern*))
320*b1cdbd2cSJim Jagielski         loadSymbol( "FcFontSetAdd" );
321*b1cdbd2cSJim Jagielski     m_pFcPatternReference = (void(*)(FcPattern*))
322*b1cdbd2cSJim Jagielski         loadSymbol( "FcPatternReference" );
323*b1cdbd2cSJim Jagielski     m_pFcPatternGetCharSet = (FcResult(*)(const FcPattern*,const char*,int,FcCharSet**))
324*b1cdbd2cSJim Jagielski         loadSymbol( "FcPatternGetCharSet" );
325*b1cdbd2cSJim Jagielski     m_pFcPatternGetString = (FcResult(*)(const FcPattern*,const char*,int,FcChar8**))
326*b1cdbd2cSJim Jagielski         loadSymbol( "FcPatternGetString" );
327*b1cdbd2cSJim Jagielski     m_pFcPatternGetInteger = (FcResult(*)(const FcPattern*,const char*,int,int*))
328*b1cdbd2cSJim Jagielski         loadSymbol( "FcPatternGetInteger" );
329*b1cdbd2cSJim Jagielski     m_pFcPatternGetDouble = (FcResult(*)(const FcPattern*,const char*,int,double*))
330*b1cdbd2cSJim Jagielski         loadSymbol( "FcPatternGetDouble" );
331*b1cdbd2cSJim Jagielski     m_pFcPatternGetBool = (FcResult(*)(const FcPattern*,const char*,int,FcBool*))
332*b1cdbd2cSJim Jagielski         loadSymbol( "FcPatternGetBool" );
333*b1cdbd2cSJim Jagielski     m_pFcConfigAppFontAddFile = (FcBool(*)(FcConfig*, const FcChar8*))
334*b1cdbd2cSJim Jagielski         loadSymbol( "FcConfigAppFontAddFile" );
335*b1cdbd2cSJim Jagielski     m_pFcConfigAppFontAddDir = (FcBool(*)(FcConfig*, const FcChar8*))
336*b1cdbd2cSJim Jagielski         loadSymbol( "FcConfigAppFontAddDir" );
337*b1cdbd2cSJim Jagielski     m_pFcConfigParseAndLoad = (FcBool(*)(FcConfig*, const FcChar8*, FcBool))
338*b1cdbd2cSJim Jagielski         loadSymbol( "FcConfigParseAndLoad" );
339*b1cdbd2cSJim Jagielski     m_pFcDefaultSubstitute = (void(*)(FcPattern *))
340*b1cdbd2cSJim Jagielski         loadSymbol( "FcDefaultSubstitute" );
341*b1cdbd2cSJim Jagielski     m_pFcFontSetMatch = (FcPattern*(*)(FcConfig*,FcFontSet**,int,FcPattern*,FcResult*))
342*b1cdbd2cSJim Jagielski         loadSymbol( "FcFontSetMatch" );
343*b1cdbd2cSJim Jagielski     m_pFcFontMatch = (FcPattern*(*)(FcConfig*,FcPattern*,FcResult*))
344*b1cdbd2cSJim Jagielski         loadSymbol( "FcFontMatch" );
345*b1cdbd2cSJim Jagielski     m_pFcConfigSubstitute = (FcBool(*)(FcConfig*,FcPattern*,FcMatchKind))
346*b1cdbd2cSJim Jagielski         loadSymbol( "FcConfigSubstitute" );
347*b1cdbd2cSJim Jagielski 
348*b1cdbd2cSJim Jagielski     m_pFcPatternDuplicate = (FcPattern*(*)(const FcPattern*))
349*b1cdbd2cSJim Jagielski         loadSymbol( "FcPatternDuplicate" );
350*b1cdbd2cSJim Jagielski     m_pFcPatternAddInteger = (FcBool(*)(FcPattern*,const char*,int))
351*b1cdbd2cSJim Jagielski         loadSymbol( "FcPatternAddInteger" );
352*b1cdbd2cSJim Jagielski     m_pFcPatternAddDouble = (FcBool(*)(FcPattern*,const char*,double))
353*b1cdbd2cSJim Jagielski         loadSymbol( "FcPatternAddDouble" );
354*b1cdbd2cSJim Jagielski     m_pFcPatternAddBool = (FcBool(*)(FcPattern*,const char*,FcBool))
355*b1cdbd2cSJim Jagielski         loadSymbol( "FcPatternAddBool" );
356*b1cdbd2cSJim Jagielski     m_pFcPatternAddCharSet = (FcBool(*)(FcPattern*,const char*,const FcCharSet *))
357*b1cdbd2cSJim Jagielski         loadSymbol( "FcPatternAddCharSet" );
358*b1cdbd2cSJim Jagielski     m_pFcPatternAddString = (FcBool(*)(FcPattern*,const char*,const FcChar8*))
359*b1cdbd2cSJim Jagielski         loadSymbol( "FcPatternAddString" );
360*b1cdbd2cSJim Jagielski     m_pFcPatternDel = (FcBool(*)(FcPattern*,const char*))
361*b1cdbd2cSJim Jagielski 		loadSymbol( "FcPatternDel" );
362*b1cdbd2cSJim Jagielski 
363*b1cdbd2cSJim Jagielski     m_pFcFreeTypeCharIndex = (FT_UInt(*)(FT_Face,FcChar32))
364*b1cdbd2cSJim Jagielski         loadSymbol( "FcFreeTypeCharIndex" );
365*b1cdbd2cSJim Jagielski 
366*b1cdbd2cSJim Jagielski     m_nFcVersion = FcGetVersion();
367*b1cdbd2cSJim Jagielski #if (OSL_DEBUG_LEVEL > 1)
368*b1cdbd2cSJim Jagielski     fprintf( stderr,"FC_VERSION = %05d\n", m_nFcVersion );
369*b1cdbd2cSJim Jagielski #endif
370*b1cdbd2cSJim Jagielski     // make minimum version configurable
371*b1cdbd2cSJim Jagielski     const char* pMinFcVersion = getenv( "SAL_MIN_FC_VERSION");
372*b1cdbd2cSJim Jagielski     if( pMinFcVersion )
373*b1cdbd2cSJim Jagielski     {
374*b1cdbd2cSJim Jagielski         const int nMinFcVersion = atoi( pMinFcVersion );
375*b1cdbd2cSJim Jagielski         if( m_nFcVersion < nMinFcVersion )
376*b1cdbd2cSJim Jagielski             m_pFcInit = NULL;
377*b1cdbd2cSJim Jagielski     }
378*b1cdbd2cSJim Jagielski 
379*b1cdbd2cSJim Jagielski     if( ! (
380*b1cdbd2cSJim Jagielski             m_pFcInit						&&
381*b1cdbd2cSJim Jagielski             m_pFcGetVersion					&&
382*b1cdbd2cSJim Jagielski             m_pFcConfigGetCurrent			&&
383*b1cdbd2cSJim Jagielski             m_pFcObjectSetVaBuild			&&
384*b1cdbd2cSJim Jagielski             m_pFcObjectSetDestroy			&&
385*b1cdbd2cSJim Jagielski             m_pFcPatternCreate				&&
386*b1cdbd2cSJim Jagielski             m_pFcPatternDestroy				&&
387*b1cdbd2cSJim Jagielski             m_pFcFontList					&&
388*b1cdbd2cSJim Jagielski             m_pFcConfigGetFonts             &&
389*b1cdbd2cSJim Jagielski             m_pFcFontSetCreate				&&
390*b1cdbd2cSJim Jagielski             m_pFcCharSetCreate				&&
391*b1cdbd2cSJim Jagielski             m_pFcCharSetAddChar 			&&
392*b1cdbd2cSJim Jagielski             m_pFcCharSetHasChar             &&
393*b1cdbd2cSJim Jagielski             m_pFcCharSetDestroy             &&
394*b1cdbd2cSJim Jagielski             m_pFcFontSetDestroy				&&
395*b1cdbd2cSJim Jagielski             m_pFcFontSetAdd					&&
396*b1cdbd2cSJim Jagielski             m_pFcPatternReference           &&
397*b1cdbd2cSJim Jagielski             m_pFcPatternGetCharSet			&&
398*b1cdbd2cSJim Jagielski             m_pFcPatternGetString			&&
399*b1cdbd2cSJim Jagielski             m_pFcPatternGetInteger			&&
400*b1cdbd2cSJim Jagielski             m_pFcPatternGetDouble			&&
401*b1cdbd2cSJim Jagielski             m_pFcPatternGetBool				&&
402*b1cdbd2cSJim Jagielski             m_pFcConfigAppFontAddFile				&&
403*b1cdbd2cSJim Jagielski             m_pFcConfigAppFontAddDir				&&
404*b1cdbd2cSJim Jagielski             m_pFcConfigParseAndLoad				&&
405*b1cdbd2cSJim Jagielski             m_pFcFontMatch					&&
406*b1cdbd2cSJim Jagielski             m_pFcDefaultSubstitute			&&
407*b1cdbd2cSJim Jagielski             m_pFcConfigSubstitute			&&
408*b1cdbd2cSJim Jagielski             m_pFcPatternDuplicate			&&
409*b1cdbd2cSJim Jagielski             m_pFcPatternAddInteger			&&
410*b1cdbd2cSJim Jagielski             m_pFcPatternAddDouble                     &&
411*b1cdbd2cSJim Jagielski             m_pFcPatternAddCharSet			&&
412*b1cdbd2cSJim Jagielski             m_pFcPatternAddBool 			&&
413*b1cdbd2cSJim Jagielski             m_pFcPatternAddString 			&&
414*b1cdbd2cSJim Jagielski             m_pFcPatternDel
415*b1cdbd2cSJim Jagielski             ) )
416*b1cdbd2cSJim Jagielski     {
417*b1cdbd2cSJim Jagielski         osl_unloadModule( (oslModule)m_pLib );
418*b1cdbd2cSJim Jagielski         m_pLib = NULL;
419*b1cdbd2cSJim Jagielski #if OSL_DEBUG_LEVEL > 1
420*b1cdbd2cSJim Jagielski         fprintf( stderr, "not all needed symbols were found in libfontconfig\n" );
421*b1cdbd2cSJim Jagielski #endif
422*b1cdbd2cSJim Jagielski         return;
423*b1cdbd2cSJim Jagielski     }
424*b1cdbd2cSJim Jagielski 
425*b1cdbd2cSJim Jagielski 
426*b1cdbd2cSJim Jagielski     FcInit();
427*b1cdbd2cSJim Jagielski     if( ! FcConfigGetCurrent() )
428*b1cdbd2cSJim Jagielski     {
429*b1cdbd2cSJim Jagielski         osl_unloadModule( (oslModule)m_pLib );
430*b1cdbd2cSJim Jagielski         m_pLib = NULL;
431*b1cdbd2cSJim Jagielski     }
432*b1cdbd2cSJim Jagielski }
433*b1cdbd2cSJim Jagielski 
addFontSet(FcSetName eSetName)434*b1cdbd2cSJim Jagielski void FontCfgWrapper::addFontSet( FcSetName eSetName )
435*b1cdbd2cSJim Jagielski {
436*b1cdbd2cSJim Jagielski     #ifdef ENABLE_FONTCONFIG
437*b1cdbd2cSJim Jagielski     /*
438*b1cdbd2cSJim Jagielski       add only acceptable outlined fonts to our config,
439*b1cdbd2cSJim Jagielski       for future fontconfig use
440*b1cdbd2cSJim Jagielski     */
441*b1cdbd2cSJim Jagielski     FcFontSet* pOrig = FcConfigGetFonts( FcConfigGetCurrent(), eSetName );
442*b1cdbd2cSJim Jagielski     if( !pOrig )
443*b1cdbd2cSJim Jagielski         return;
444*b1cdbd2cSJim Jagielski 
445*b1cdbd2cSJim Jagielski 	// filter the font sets to remove obsolete or duplicate faces
446*b1cdbd2cSJim Jagielski 	for( int i = 0; i < pOrig->nfont; ++i )
447*b1cdbd2cSJim Jagielski 	{
448*b1cdbd2cSJim Jagielski 		FcPattern* pOrigPattern = pOrig->fonts[i];
449*b1cdbd2cSJim Jagielski 		// #i115131# ignore non-outline fonts
450*b1cdbd2cSJim Jagielski 		FcBool bOutline = FcFalse;
451*b1cdbd2cSJim Jagielski 		FcResult eOutRes = FcPatternGetBool( pOrigPattern, FC_OUTLINE, 0, &bOutline );
452*b1cdbd2cSJim Jagielski 		if( (eOutRes != FcResultMatch) || (bOutline == FcFalse) )
453*b1cdbd2cSJim Jagielski 			continue;
454*b1cdbd2cSJim Jagielski 		// create a pattern to find eventually better alternatives
455*b1cdbd2cSJim Jagielski 		FcPattern* pBetterPattern = pOrigPattern;
456*b1cdbd2cSJim Jagielski 		if( m_nFcVersion > 20400 ) // #i115204# avoid trouble with old FC versions
457*b1cdbd2cSJim Jagielski 		{
458*b1cdbd2cSJim Jagielski 			FcPattern* pTestPattern = FcPatternDuplicate( pOrigPattern );
459*b1cdbd2cSJim Jagielski 			FcPatternAddBool( pTestPattern, FC_OUTLINE, FcTrue );
460*b1cdbd2cSJim Jagielski 			// TODO: ignore all attributes that are not interesting for finding dupes
461*b1cdbd2cSJim Jagielski 			//       e.g. by using pattern->ImplFontAttr->pattern conversion
462*b1cdbd2cSJim Jagielski 			FcPatternDel( pTestPattern, FC_FONTVERSION );
463*b1cdbd2cSJim Jagielski 			FcPatternDel( pTestPattern, FC_CHARSET );
464*b1cdbd2cSJim Jagielski 			FcPatternDel( pTestPattern, FC_FILE );
465*b1cdbd2cSJim Jagielski 			// find the font face for the dupe-search pattern
466*b1cdbd2cSJim Jagielski 			FcResult eFcResult = FcResultMatch;
467*b1cdbd2cSJim Jagielski 			pBetterPattern = FcFontMatch( FcConfigGetCurrent(), pTestPattern, &eFcResult );
468*b1cdbd2cSJim Jagielski 			FcPatternDestroy( pTestPattern );
469*b1cdbd2cSJim Jagielski 			if( eFcResult != FcResultMatch )
470*b1cdbd2cSJim Jagielski 				continue;
471*b1cdbd2cSJim Jagielski 			// #i115131# double check results and eventually ignore them
472*b1cdbd2cSJim Jagielski 			eOutRes = FcPatternGetBool( pBetterPattern, FC_OUTLINE, 0, &bOutline );
473*b1cdbd2cSJim Jagielski 			if( (eOutRes != FcResultMatch) || (bOutline == FcFalse) )
474*b1cdbd2cSJim Jagielski 				continue;
475*b1cdbd2cSJim Jagielski 		}
476*b1cdbd2cSJim Jagielski 		// insert best found pattern for the dupe-search pattern
477*b1cdbd2cSJim Jagielski 		// TODO: skip inserting patterns that are already known in the target fontset
478*b1cdbd2cSJim Jagielski 		FcPatternReference( pBetterPattern );
479*b1cdbd2cSJim Jagielski 		FcFontSetAdd( m_pOutlineSet, pBetterPattern );
480*b1cdbd2cSJim Jagielski 	}
481*b1cdbd2cSJim Jagielski 
482*b1cdbd2cSJim Jagielski     // TODO?: FcFontSetDestroy( pOrig );
483*b1cdbd2cSJim Jagielski     #else
484*b1cdbd2cSJim Jagielski     (void)eSetName; // prevent compiler warning about unused parameter
485*b1cdbd2cSJim Jagielski     #endif
486*b1cdbd2cSJim Jagielski }
487*b1cdbd2cSJim Jagielski 
getFontSet()488*b1cdbd2cSJim Jagielski FcFontSet* FontCfgWrapper::getFontSet()
489*b1cdbd2cSJim Jagielski {
490*b1cdbd2cSJim Jagielski     #ifdef ENABLE_FONTCONFIG
491*b1cdbd2cSJim Jagielski     if( !m_pOutlineSet )
492*b1cdbd2cSJim Jagielski     {
493*b1cdbd2cSJim Jagielski         m_pOutlineSet = FcFontSetCreate();
494*b1cdbd2cSJim Jagielski         addFontSet( FcSetSystem );
495*b1cdbd2cSJim Jagielski 	if( m_nFcVersion > 20400 ) // #i85462# prevent crashes
496*b1cdbd2cSJim Jagielski             addFontSet( FcSetApplication );
497*b1cdbd2cSJim Jagielski     }
498*b1cdbd2cSJim Jagielski     #endif
499*b1cdbd2cSJim Jagielski 
500*b1cdbd2cSJim Jagielski     return m_pOutlineSet;
501*b1cdbd2cSJim Jagielski }
502*b1cdbd2cSJim Jagielski 
~FontCfgWrapper()503*b1cdbd2cSJim Jagielski FontCfgWrapper::~FontCfgWrapper()
504*b1cdbd2cSJim Jagielski {
505*b1cdbd2cSJim Jagielski 	if( m_pOutlineSet )
506*b1cdbd2cSJim Jagielski 		FcFontSetDestroy( m_pOutlineSet );
507*b1cdbd2cSJim Jagielski     if( m_pLib )
508*b1cdbd2cSJim Jagielski         osl_unloadModule( (oslModule)m_pLib );
509*b1cdbd2cSJim Jagielski }
510*b1cdbd2cSJim Jagielski 
511*b1cdbd2cSJim Jagielski static FontCfgWrapper* pOneInstance = NULL;
512*b1cdbd2cSJim Jagielski 
get()513*b1cdbd2cSJim Jagielski FontCfgWrapper& FontCfgWrapper::get()
514*b1cdbd2cSJim Jagielski {
515*b1cdbd2cSJim Jagielski     if( ! pOneInstance )
516*b1cdbd2cSJim Jagielski         pOneInstance = new FontCfgWrapper();
517*b1cdbd2cSJim Jagielski     return *pOneInstance;
518*b1cdbd2cSJim Jagielski }
519*b1cdbd2cSJim Jagielski 
release()520*b1cdbd2cSJim Jagielski void FontCfgWrapper::release()
521*b1cdbd2cSJim Jagielski {
522*b1cdbd2cSJim Jagielski     if( pOneInstance )
523*b1cdbd2cSJim Jagielski     {
524*b1cdbd2cSJim Jagielski         delete pOneInstance;
525*b1cdbd2cSJim Jagielski         pOneInstance = NULL;
526*b1cdbd2cSJim Jagielski     }
527*b1cdbd2cSJim Jagielski }
528*b1cdbd2cSJim Jagielski 
529*b1cdbd2cSJim Jagielski #ifdef ENABLE_FONTCONFIG
530*b1cdbd2cSJim Jagielski namespace
531*b1cdbd2cSJim Jagielski {
532*b1cdbd2cSJim Jagielski     typedef std::pair<FcChar8*, FcChar8*> lang_and_family;
533*b1cdbd2cSJim Jagielski 
534*b1cdbd2cSJim Jagielski     class localizedsorter
535*b1cdbd2cSJim Jagielski     {
536*b1cdbd2cSJim Jagielski             rtl::OLocale maLoc;
537*b1cdbd2cSJim Jagielski         public:
localizedsorter(rtl_Locale * pLoc)538*b1cdbd2cSJim Jagielski             localizedsorter(rtl_Locale* pLoc) : maLoc(pLoc) {}
539*b1cdbd2cSJim Jagielski             FcChar8* bestname(const std::vector<lang_and_family> &families);
540*b1cdbd2cSJim Jagielski     };
541*b1cdbd2cSJim Jagielski 
bestname(const std::vector<lang_and_family> & families)542*b1cdbd2cSJim Jagielski     FcChar8* localizedsorter::bestname(const std::vector<lang_and_family> &families)
543*b1cdbd2cSJim Jagielski     {
544*b1cdbd2cSJim Jagielski         FcChar8* candidate = families.begin()->second;
545*b1cdbd2cSJim Jagielski         rtl::OString sLangMatch(rtl::OUStringToOString(maLoc.getLanguage().toAsciiLowerCase(), RTL_TEXTENCODING_UTF8));
546*b1cdbd2cSJim Jagielski 	rtl::OString sFullMatch = sLangMatch;
547*b1cdbd2cSJim Jagielski         sFullMatch += OString('-');
548*b1cdbd2cSJim Jagielski         sFullMatch += rtl::OUStringToOString(maLoc.getCountry().toAsciiLowerCase(), RTL_TEXTENCODING_UTF8);
549*b1cdbd2cSJim Jagielski 
550*b1cdbd2cSJim Jagielski         std::vector<lang_and_family>::const_iterator aEnd = families.end();
551*b1cdbd2cSJim Jagielski         bool alreadyclosematch = false;
552*b1cdbd2cSJim Jagielski         for( std::vector<lang_and_family>::const_iterator aIter = families.begin(); aIter != aEnd; ++aIter )
553*b1cdbd2cSJim Jagielski         {
554*b1cdbd2cSJim Jagielski             const char *pLang = (const char*)aIter->first;
555*b1cdbd2cSJim Jagielski             if( rtl_str_compare( pLang, sFullMatch.getStr() ) == 0)
556*b1cdbd2cSJim Jagielski             {
557*b1cdbd2cSJim Jagielski                 // both language and country match
558*b1cdbd2cSJim Jagielski                 candidate = aIter->second;
559*b1cdbd2cSJim Jagielski                 break;
560*b1cdbd2cSJim Jagielski             }
561*b1cdbd2cSJim Jagielski             else if( alreadyclosematch )
562*b1cdbd2cSJim Jagielski 	        continue;
563*b1cdbd2cSJim Jagielski             else if( rtl_str_compare( pLang, sLangMatch.getStr()) == 0)
564*b1cdbd2cSJim Jagielski             {
565*b1cdbd2cSJim Jagielski                 // just the language matches
566*b1cdbd2cSJim Jagielski                 candidate = aIter->second;
567*b1cdbd2cSJim Jagielski                 alreadyclosematch = true;
568*b1cdbd2cSJim Jagielski             }
569*b1cdbd2cSJim Jagielski             else if( rtl_str_compare( pLang, "en") == 0)
570*b1cdbd2cSJim Jagielski             {
571*b1cdbd2cSJim Jagielski                 // fallback to the english family name
572*b1cdbd2cSJim Jagielski                 candidate = aIter->second;
573*b1cdbd2cSJim Jagielski             }
574*b1cdbd2cSJim Jagielski         }
575*b1cdbd2cSJim Jagielski         return candidate;
576*b1cdbd2cSJim Jagielski     }
577*b1cdbd2cSJim Jagielski }
578*b1cdbd2cSJim Jagielski 
FamilyFromPattern(FcPattern * pPattern,FcChar8 ** family)579*b1cdbd2cSJim Jagielski FcResult FontCfgWrapper::FamilyFromPattern(FcPattern* pPattern, FcChar8 **family)
580*b1cdbd2cSJim Jagielski {
581*b1cdbd2cSJim Jagielski     FcChar8 *origfamily;
582*b1cdbd2cSJim Jagielski     FcResult eFamilyRes	= FcPatternGetString( pPattern, FC_FAMILY, 0, &origfamily );
583*b1cdbd2cSJim Jagielski     *family = origfamily;
584*b1cdbd2cSJim Jagielski 
585*b1cdbd2cSJim Jagielski     if( eFamilyRes == FcResultMatch)
586*b1cdbd2cSJim Jagielski     {
587*b1cdbd2cSJim Jagielski         FcChar8* familylang = NULL;
588*b1cdbd2cSJim Jagielski         if (FcPatternGetString( pPattern, FC_FAMILYLANG, 0, &familylang ) == FcResultMatch)
589*b1cdbd2cSJim Jagielski         {
590*b1cdbd2cSJim Jagielski             std::vector< lang_and_family > lang_and_families;
591*b1cdbd2cSJim Jagielski             lang_and_families.push_back(lang_and_family(familylang, *family));
592*b1cdbd2cSJim Jagielski             int k = 1;
593*b1cdbd2cSJim Jagielski             while (1)
594*b1cdbd2cSJim Jagielski             {
595*b1cdbd2cSJim Jagielski                 if (FcPatternGetString( pPattern, FC_FAMILYLANG, k, &familylang ) != FcResultMatch)
596*b1cdbd2cSJim Jagielski                     break;
597*b1cdbd2cSJim Jagielski                 if (FcPatternGetString( pPattern, FC_FAMILY, k, family ) != FcResultMatch)
598*b1cdbd2cSJim Jagielski                     break;
599*b1cdbd2cSJim Jagielski                 lang_and_families.push_back(lang_and_family(familylang, *family));
600*b1cdbd2cSJim Jagielski                 ++k;
601*b1cdbd2cSJim Jagielski             }
602*b1cdbd2cSJim Jagielski 
603*b1cdbd2cSJim Jagielski             //possible to-do, sort by UILocale instead of process locale
604*b1cdbd2cSJim Jagielski             rtl_Locale* pLoc;
605*b1cdbd2cSJim Jagielski             osl_getProcessLocale(&pLoc);
606*b1cdbd2cSJim Jagielski             localizedsorter aSorter(pLoc);
607*b1cdbd2cSJim Jagielski             *family = aSorter.bestname(lang_and_families);
608*b1cdbd2cSJim Jagielski 
609*b1cdbd2cSJim Jagielski             std::vector<lang_and_family>::const_iterator aEnd = lang_and_families.end();
610*b1cdbd2cSJim Jagielski             for (std::vector<lang_and_family>::const_iterator aIter = lang_and_families.begin(); aIter != aEnd; ++aIter)
611*b1cdbd2cSJim Jagielski             {
612*b1cdbd2cSJim Jagielski                 const char *candidate = (const char*)(aIter->second);
613*b1cdbd2cSJim Jagielski                 if (rtl_str_compare(candidate, (const char*)(*family)) != 0)
614*b1cdbd2cSJim Jagielski                     m_aFontNameToLocalized[OString(candidate)] = OString((const char*)(*family));
615*b1cdbd2cSJim Jagielski             }
616*b1cdbd2cSJim Jagielski             if (rtl_str_compare((const char*)origfamily, (const char*)(*family)) != 0)
617*b1cdbd2cSJim Jagielski                 m_aLocalizedToCanonical[OString((const char*)(*family))] = OString((const char*)origfamily);
618*b1cdbd2cSJim Jagielski         }
619*b1cdbd2cSJim Jagielski     }
620*b1cdbd2cSJim Jagielski 
621*b1cdbd2cSJim Jagielski     return eFamilyRes;
622*b1cdbd2cSJim Jagielski }
623*b1cdbd2cSJim Jagielski 
624*b1cdbd2cSJim Jagielski /*
625*b1cdbd2cSJim Jagielski  * PrintFontManager::initFontconfig
626*b1cdbd2cSJim Jagielski  */
initFontconfig()627*b1cdbd2cSJim Jagielski bool PrintFontManager::initFontconfig()
628*b1cdbd2cSJim Jagielski {
629*b1cdbd2cSJim Jagielski     FontCfgWrapper& rWrapper = FontCfgWrapper::get();
630*b1cdbd2cSJim Jagielski     if( ! rWrapper.isValid() )
631*b1cdbd2cSJim Jagielski         return false;
632*b1cdbd2cSJim Jagielski     return true;
633*b1cdbd2cSJim Jagielski }
634*b1cdbd2cSJim Jagielski 
635*b1cdbd2cSJim Jagielski namespace
636*b1cdbd2cSJim Jagielski {
convertWeight(int weight)637*b1cdbd2cSJim Jagielski     weight::type convertWeight(int weight)
638*b1cdbd2cSJim Jagielski     {
639*b1cdbd2cSJim Jagielski         // set weight
640*b1cdbd2cSJim Jagielski         if( weight <= FC_WEIGHT_THIN )
641*b1cdbd2cSJim Jagielski             return weight::Thin;
642*b1cdbd2cSJim Jagielski         else if( weight <= FC_WEIGHT_ULTRALIGHT )
643*b1cdbd2cSJim Jagielski             return weight::UltraLight;
644*b1cdbd2cSJim Jagielski         else if( weight <= FC_WEIGHT_LIGHT )
645*b1cdbd2cSJim Jagielski             return weight::Light;
646*b1cdbd2cSJim Jagielski         else if( weight <= FC_WEIGHT_BOOK )
647*b1cdbd2cSJim Jagielski             return weight::SemiLight;
648*b1cdbd2cSJim Jagielski         else if( weight <= FC_WEIGHT_NORMAL )
649*b1cdbd2cSJim Jagielski             return weight::Normal;
650*b1cdbd2cSJim Jagielski         else if( weight <= FC_WEIGHT_MEDIUM )
651*b1cdbd2cSJim Jagielski             return weight::Medium;
652*b1cdbd2cSJim Jagielski         else if( weight <= FC_WEIGHT_SEMIBOLD )
653*b1cdbd2cSJim Jagielski             return weight::SemiBold;
654*b1cdbd2cSJim Jagielski         else if( weight <= FC_WEIGHT_BOLD )
655*b1cdbd2cSJim Jagielski             return weight::Bold;
656*b1cdbd2cSJim Jagielski         else if( weight <= FC_WEIGHT_ULTRABOLD )
657*b1cdbd2cSJim Jagielski             return weight::UltraBold;
658*b1cdbd2cSJim Jagielski         return weight::Black;
659*b1cdbd2cSJim Jagielski     }
660*b1cdbd2cSJim Jagielski 
convertSlant(int slant)661*b1cdbd2cSJim Jagielski     italic::type convertSlant(int slant)
662*b1cdbd2cSJim Jagielski     {
663*b1cdbd2cSJim Jagielski         // set italic
664*b1cdbd2cSJim Jagielski         if( slant == FC_SLANT_ITALIC )
665*b1cdbd2cSJim Jagielski             return italic::Italic;
666*b1cdbd2cSJim Jagielski         else if( slant == FC_SLANT_OBLIQUE )
667*b1cdbd2cSJim Jagielski             return italic::Oblique;
668*b1cdbd2cSJim Jagielski         return italic::Upright;
669*b1cdbd2cSJim Jagielski     }
670*b1cdbd2cSJim Jagielski 
convertSpacing(int spacing)671*b1cdbd2cSJim Jagielski     pitch::type convertSpacing(int spacing)
672*b1cdbd2cSJim Jagielski     {
673*b1cdbd2cSJim Jagielski         // set pitch
674*b1cdbd2cSJim Jagielski         if( spacing == FC_MONO || spacing == FC_CHARCELL )
675*b1cdbd2cSJim Jagielski             return pitch::Fixed;
676*b1cdbd2cSJim Jagielski         return pitch::Variable;
677*b1cdbd2cSJim Jagielski     }
678*b1cdbd2cSJim Jagielski 
convertWidth(int width)679*b1cdbd2cSJim Jagielski     width::type convertWidth(int width)
680*b1cdbd2cSJim Jagielski     {
681*b1cdbd2cSJim Jagielski         if (width == FC_WIDTH_ULTRACONDENSED)
682*b1cdbd2cSJim Jagielski             return width::UltraCondensed;
683*b1cdbd2cSJim Jagielski         else if (width == FC_WIDTH_EXTRACONDENSED)
684*b1cdbd2cSJim Jagielski             return width::ExtraCondensed;
685*b1cdbd2cSJim Jagielski         else if (width == FC_WIDTH_CONDENSED)
686*b1cdbd2cSJim Jagielski             return width::Condensed;
687*b1cdbd2cSJim Jagielski         else if (width == FC_WIDTH_SEMICONDENSED)
688*b1cdbd2cSJim Jagielski             return width::SemiCondensed;
689*b1cdbd2cSJim Jagielski         else if (width == FC_WIDTH_SEMIEXPANDED)
690*b1cdbd2cSJim Jagielski             return width::SemiExpanded;
691*b1cdbd2cSJim Jagielski         else if (width == FC_WIDTH_EXPANDED)
692*b1cdbd2cSJim Jagielski             return width::Expanded;
693*b1cdbd2cSJim Jagielski         else if (width == FC_WIDTH_EXTRAEXPANDED)
694*b1cdbd2cSJim Jagielski             return width::ExtraExpanded;
695*b1cdbd2cSJim Jagielski         else if (width == FC_WIDTH_ULTRAEXPANDED)
696*b1cdbd2cSJim Jagielski             return width::UltraExpanded;
697*b1cdbd2cSJim Jagielski         return width::Normal;
698*b1cdbd2cSJim Jagielski     }
699*b1cdbd2cSJim Jagielski }
700*b1cdbd2cSJim Jagielski 
countFontconfigFonts(std::hash_map<rtl::OString,int,rtl::OStringHash> & o_rVisitedPaths)701*b1cdbd2cSJim Jagielski int PrintFontManager::countFontconfigFonts( std::hash_map<rtl::OString, int, rtl::OStringHash>& o_rVisitedPaths )
702*b1cdbd2cSJim Jagielski {
703*b1cdbd2cSJim Jagielski     int nFonts = 0;
704*b1cdbd2cSJim Jagielski 
705*b1cdbd2cSJim Jagielski     FontCfgWrapper& rWrapper = FontCfgWrapper::get();
706*b1cdbd2cSJim Jagielski     if( !rWrapper.isValid() )
707*b1cdbd2cSJim Jagielski         return 0;
708*b1cdbd2cSJim Jagielski 
709*b1cdbd2cSJim Jagielski     FcFontSet* pFSet = rWrapper.getFontSet();
710*b1cdbd2cSJim Jagielski     if( pFSet )
711*b1cdbd2cSJim Jagielski     {
712*b1cdbd2cSJim Jagielski #if OSL_DEBUG_LEVEL > 1
713*b1cdbd2cSJim Jagielski         fprintf( stderr, "found %d entries in fontconfig fontset\n", pFSet->nfont );
714*b1cdbd2cSJim Jagielski #endif
715*b1cdbd2cSJim Jagielski         for( int i = 0; i < pFSet->nfont; i++ )
716*b1cdbd2cSJim Jagielski         {
717*b1cdbd2cSJim Jagielski             FcChar8* file = NULL;
718*b1cdbd2cSJim Jagielski             FcChar8* family = NULL;
719*b1cdbd2cSJim Jagielski             FcChar8* style = NULL;
720*b1cdbd2cSJim Jagielski             int slant = 0;
721*b1cdbd2cSJim Jagielski             int weight = 0;
722*b1cdbd2cSJim Jagielski             int spacing = 0;
723*b1cdbd2cSJim Jagielski             int nCollectionEntry = -1;
724*b1cdbd2cSJim Jagielski             FcBool outline = false;
725*b1cdbd2cSJim Jagielski 
726*b1cdbd2cSJim Jagielski             FcResult eFileRes	      = rWrapper.FcPatternGetString( pFSet->fonts[i], FC_FILE, 0, &file );
727*b1cdbd2cSJim Jagielski             FcResult eFamilyRes       = rWrapper.FamilyFromPattern( pFSet->fonts[i], &family );
728*b1cdbd2cSJim Jagielski             FcResult eStyleRes	      = rWrapper.FcPatternGetString( pFSet->fonts[i], FC_STYLE, 0, &style );
729*b1cdbd2cSJim Jagielski             FcResult eSlantRes	      = rWrapper.FcPatternGetInteger( pFSet->fonts[i], FC_SLANT, 0, &slant );
730*b1cdbd2cSJim Jagielski             FcResult eWeightRes	      = rWrapper.FcPatternGetInteger( pFSet->fonts[i], FC_WEIGHT, 0, &weight );
731*b1cdbd2cSJim Jagielski             FcResult eSpacRes	      = rWrapper.FcPatternGetInteger( pFSet->fonts[i], FC_SPACING, 0, &spacing );
732*b1cdbd2cSJim Jagielski             FcResult eOutRes	      = rWrapper.FcPatternGetBool( pFSet->fonts[i], FC_OUTLINE, 0, &outline );
733*b1cdbd2cSJim Jagielski             FcResult eIndexRes        = rWrapper.FcPatternGetInteger( pFSet->fonts[i], FC_INDEX, 0, &nCollectionEntry );
734*b1cdbd2cSJim Jagielski 
735*b1cdbd2cSJim Jagielski             if( eFileRes != FcResultMatch || eFamilyRes != FcResultMatch || eOutRes != FcResultMatch )
736*b1cdbd2cSJim Jagielski                 continue;
737*b1cdbd2cSJim Jagielski 
738*b1cdbd2cSJim Jagielski #if (OSL_DEBUG_LEVEL > 2)
739*b1cdbd2cSJim Jagielski             fprintf( stderr, "found font \"%s\" in file %s\n"
740*b1cdbd2cSJim Jagielski                      "   weight = %d, slant = %d, style = \"%s\"\n"
741*b1cdbd2cSJim Jagielski                      "   spacing = %d, outline = %d\n"
742*b1cdbd2cSJim Jagielski                      , family, file
743*b1cdbd2cSJim Jagielski                      , eWeightRes == FcResultMatch ? weight : -1
744*b1cdbd2cSJim Jagielski                      , eSpacRes == FcResultMatch ? slant : -1
745*b1cdbd2cSJim Jagielski                      , eStyleRes == FcResultMatch ? (const char*) style : "<nil>"
746*b1cdbd2cSJim Jagielski                      , eSpacRes == FcResultMatch ? spacing : -1
747*b1cdbd2cSJim Jagielski                      , eOutRes == FcResultMatch ? outline : -1
748*b1cdbd2cSJim Jagielski                      );
749*b1cdbd2cSJim Jagielski #endif
750*b1cdbd2cSJim Jagielski 
751*b1cdbd2cSJim Jagielski //            OSL_ASSERT(eOutRes != FcResultMatch || outline);
752*b1cdbd2cSJim Jagielski 
753*b1cdbd2cSJim Jagielski             // only outline fonts are usable to psprint anyway
754*b1cdbd2cSJim Jagielski             if( eOutRes == FcResultMatch && ! outline )
755*b1cdbd2cSJim Jagielski                 continue;
756*b1cdbd2cSJim Jagielski 
757*b1cdbd2cSJim Jagielski             // see if this font is already cached
758*b1cdbd2cSJim Jagielski             // update attributes
759*b1cdbd2cSJim Jagielski             std::list< PrintFont* > aFonts;
760*b1cdbd2cSJim Jagielski             OString aDir, aBase, aOrgPath( (sal_Char*)file );
761*b1cdbd2cSJim Jagielski             splitPath( aOrgPath, aDir, aBase );
762*b1cdbd2cSJim Jagielski 
763*b1cdbd2cSJim Jagielski             o_rVisitedPaths[aDir] = 1;
764*b1cdbd2cSJim Jagielski 
765*b1cdbd2cSJim Jagielski             int nDirID = getDirectoryAtom( aDir, true );
766*b1cdbd2cSJim Jagielski             if( ! m_pFontCache->getFontCacheFile( nDirID, aBase, aFonts ) )
767*b1cdbd2cSJim Jagielski             {
768*b1cdbd2cSJim Jagielski #if OSL_DEBUG_LEVEL > 2
769*b1cdbd2cSJim Jagielski                 fprintf( stderr, "file %s not cached\n", aBase.getStr() );
770*b1cdbd2cSJim Jagielski #endif
771*b1cdbd2cSJim Jagielski                 // not known, analyze font file to get attributes
772*b1cdbd2cSJim Jagielski                 // not described by fontconfig (e.g. alias names, PSName)
773*b1cdbd2cSJim Jagielski                 std::list< OString > aDummy;
774*b1cdbd2cSJim Jagielski                 analyzeFontFile( nDirID, aBase, aDummy, aFonts );
775*b1cdbd2cSJim Jagielski #if OSL_DEBUG_LEVEL > 1
776*b1cdbd2cSJim Jagielski                 if( aFonts.empty() )
777*b1cdbd2cSJim Jagielski                     fprintf( stderr, "Warning: file \"%s\" is unusable to psprint\n", aOrgPath.getStr() );
778*b1cdbd2cSJim Jagielski #endif
779*b1cdbd2cSJim Jagielski             }
780*b1cdbd2cSJim Jagielski             if( aFonts.empty() )
781*b1cdbd2cSJim Jagielski             {
782*b1cdbd2cSJim Jagielski                 // TODO: remove fonts unusable to psprint from fontset
783*b1cdbd2cSJim Jagielski                 continue;
784*b1cdbd2cSJim Jagielski             }
785*b1cdbd2cSJim Jagielski 
786*b1cdbd2cSJim Jagielski             int nFamilyName = m_pAtoms->getAtom( ATOM_FAMILYNAME, OStringToOUString( OString( (sal_Char*)family ), RTL_TEXTENCODING_UTF8 ), sal_True );
787*b1cdbd2cSJim Jagielski             PrintFont* pUpdate = aFonts.front();
788*b1cdbd2cSJim Jagielski             std::list<PrintFont*>::const_iterator second_font = aFonts.begin();
789*b1cdbd2cSJim Jagielski             ++second_font;
790*b1cdbd2cSJim Jagielski             if( second_font != aFonts.end() ) // more than one font
791*b1cdbd2cSJim Jagielski             {
792*b1cdbd2cSJim Jagielski                 // a collection entry, get the correct index
793*b1cdbd2cSJim Jagielski                 if( eIndexRes == FcResultMatch && nCollectionEntry != -1 )
794*b1cdbd2cSJim Jagielski                 {
795*b1cdbd2cSJim Jagielski                     for( std::list< PrintFont* >::iterator it = aFonts.begin(); it != aFonts.end(); ++it )
796*b1cdbd2cSJim Jagielski                     {
797*b1cdbd2cSJim Jagielski                         if( (*it)->m_eType == fonttype::TrueType &&
798*b1cdbd2cSJim Jagielski                             static_cast<TrueTypeFontFile*>(*it)->m_nCollectionEntry == nCollectionEntry )
799*b1cdbd2cSJim Jagielski                         {
800*b1cdbd2cSJim Jagielski                             pUpdate = *it;
801*b1cdbd2cSJim Jagielski                             break;
802*b1cdbd2cSJim Jagielski                         }
803*b1cdbd2cSJim Jagielski                     }
804*b1cdbd2cSJim Jagielski                     // update collection entry
805*b1cdbd2cSJim Jagielski                     // additional entries will be created in the cache
806*b1cdbd2cSJim Jagielski                     // if this is a new index (that is if the loop above
807*b1cdbd2cSJim Jagielski                     // ran to the end of the list)
808*b1cdbd2cSJim Jagielski                     if( pUpdate->m_eType == fonttype::TrueType ) // sanity check, this should always be the case here
809*b1cdbd2cSJim Jagielski                         static_cast<TrueTypeFontFile*>(pUpdate)->m_nCollectionEntry = nCollectionEntry;
810*b1cdbd2cSJim Jagielski                 }
811*b1cdbd2cSJim Jagielski                 else
812*b1cdbd2cSJim Jagielski                 {
813*b1cdbd2cSJim Jagielski #if OSL_DEBUG_LEVEL > 1
814*b1cdbd2cSJim Jagielski                     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 );
815*b1cdbd2cSJim Jagielski #endif
816*b1cdbd2cSJim Jagielski                     // we have found more than one font in this file
817*b1cdbd2cSJim Jagielski                     // but fontconfig will not tell us which index is meant
818*b1cdbd2cSJim Jagielski                     // -> something is in disorder, do not use this font
819*b1cdbd2cSJim Jagielski                     pUpdate = NULL;
820*b1cdbd2cSJim Jagielski                 }
821*b1cdbd2cSJim Jagielski             }
822*b1cdbd2cSJim Jagielski 
823*b1cdbd2cSJim Jagielski             if( pUpdate )
824*b1cdbd2cSJim Jagielski             {
825*b1cdbd2cSJim Jagielski                 // set family name
826*b1cdbd2cSJim Jagielski                 if( pUpdate->m_nFamilyName != nFamilyName )
827*b1cdbd2cSJim Jagielski                 {
828*b1cdbd2cSJim Jagielski #if 0 // fontconfig prefers nameid=16 for the family name which is all fine
829*b1cdbd2cSJim Jagielski       // but Writer suffers from #i79878#
830*b1cdbd2cSJim Jagielski       // the only reasonable workaround for now is to use the classic nameid=1
831*b1cdbd2cSJim Jagielski                     pUpdate->m_aAliases.remove( pUpdate->m_nFamilyName );
832*b1cdbd2cSJim Jagielski                     pUpdate->m_aAliases.push_back( pUpdate->m_nFamilyName );
833*b1cdbd2cSJim Jagielski                     pUpdate->m_aAliases.remove( nFamilyName );
834*b1cdbd2cSJim Jagielski                     pUpdate->m_nFamilyName = nFamilyName;
835*b1cdbd2cSJim Jagielski #endif
836*b1cdbd2cSJim Jagielski                 }
837*b1cdbd2cSJim Jagielski                 if( eWeightRes == FcResultMatch )
838*b1cdbd2cSJim Jagielski 					pUpdate->m_eWeight = convertWeight(weight);
839*b1cdbd2cSJim Jagielski                 if( eSpacRes == FcResultMatch )
840*b1cdbd2cSJim Jagielski                     pUpdate->m_ePitch = convertSpacing(spacing);
841*b1cdbd2cSJim Jagielski                 if( eSlantRes == FcResultMatch )
842*b1cdbd2cSJim Jagielski 					pUpdate->m_eItalic = convertSlant(slant);
843*b1cdbd2cSJim Jagielski                 if( eStyleRes == FcResultMatch )
844*b1cdbd2cSJim Jagielski                 {
845*b1cdbd2cSJim Jagielski                     pUpdate->m_aStyleName = OStringToOUString( OString( (sal_Char*)style ), RTL_TEXTENCODING_UTF8 );
846*b1cdbd2cSJim Jagielski                 }
847*b1cdbd2cSJim Jagielski 
848*b1cdbd2cSJim Jagielski                 // update font cache
849*b1cdbd2cSJim Jagielski                 m_pFontCache->updateFontCacheEntry( pUpdate, false );
850*b1cdbd2cSJim Jagielski                 // sort into known fonts
851*b1cdbd2cSJim Jagielski                 fontID aFont = m_nNextFontID++;
852*b1cdbd2cSJim Jagielski                 m_aFonts[ aFont ] = pUpdate;
853*b1cdbd2cSJim Jagielski                 m_aFontFileToFontID[ aBase ].insert( aFont );
854*b1cdbd2cSJim Jagielski                 nFonts++;
855*b1cdbd2cSJim Jagielski #if OSL_DEBUG_LEVEL > 2
856*b1cdbd2cSJim Jagielski                 fprintf( stderr, "inserted font %s as fontID %d\n", family, aFont );
857*b1cdbd2cSJim Jagielski #endif
858*b1cdbd2cSJim Jagielski             }
859*b1cdbd2cSJim Jagielski             // clean up the fonts we did not put into the list
860*b1cdbd2cSJim Jagielski             for( std::list< PrintFont* >::iterator it = aFonts.begin(); it != aFonts.end(); ++it )
861*b1cdbd2cSJim Jagielski             {
862*b1cdbd2cSJim Jagielski                 if( *it != pUpdate )
863*b1cdbd2cSJim Jagielski                 {
864*b1cdbd2cSJim Jagielski                     m_pFontCache->updateFontCacheEntry( *it, false ); // prepare a cache entry for a collection item
865*b1cdbd2cSJim Jagielski                     delete *it;
866*b1cdbd2cSJim Jagielski                 }
867*b1cdbd2cSJim Jagielski             }
868*b1cdbd2cSJim Jagielski         }
869*b1cdbd2cSJim Jagielski     }
870*b1cdbd2cSJim Jagielski 
871*b1cdbd2cSJim Jagielski     // how does one get rid of the config ?
872*b1cdbd2cSJim Jagielski #if OSL_DEBUG_LEVEL > 1
873*b1cdbd2cSJim Jagielski     fprintf( stderr, "inserted %d fonts from fontconfig\n", nFonts );
874*b1cdbd2cSJim Jagielski #endif
875*b1cdbd2cSJim Jagielski     return nFonts;
876*b1cdbd2cSJim Jagielski }
877*b1cdbd2cSJim Jagielski 
deinitFontconfig()878*b1cdbd2cSJim Jagielski void PrintFontManager::deinitFontconfig()
879*b1cdbd2cSJim Jagielski {
880*b1cdbd2cSJim Jagielski     FontCfgWrapper::release();
881*b1cdbd2cSJim Jagielski }
882*b1cdbd2cSJim Jagielski 
FreeTypeCharIndex(void * pFace,sal_uInt32 aChar)883*b1cdbd2cSJim Jagielski int PrintFontManager::FreeTypeCharIndex( void *pFace, sal_uInt32 aChar )
884*b1cdbd2cSJim Jagielski {
885*b1cdbd2cSJim Jagielski     FontCfgWrapper& rWrapper = FontCfgWrapper::get();
886*b1cdbd2cSJim Jagielski     return rWrapper.isValid() ? rWrapper.FcFreeTypeCharIndex( (FT_Face)pFace, aChar ) : 0;
887*b1cdbd2cSJim Jagielski }
888*b1cdbd2cSJim Jagielski 
addFontconfigDir(const rtl::OString & rDirName)889*b1cdbd2cSJim Jagielski bool PrintFontManager::addFontconfigDir( const rtl::OString& rDirName )
890*b1cdbd2cSJim Jagielski {
891*b1cdbd2cSJim Jagielski     FontCfgWrapper& rWrapper = FontCfgWrapper::get();
892*b1cdbd2cSJim Jagielski     if( ! rWrapper.isValid() )
893*b1cdbd2cSJim Jagielski         return false;
894*b1cdbd2cSJim Jagielski 
895*b1cdbd2cSJim Jagielski     // workaround for a stability problems in older FC versions
896*b1cdbd2cSJim Jagielski     // when handling application specifc fonts
897*b1cdbd2cSJim Jagielski     const int nVersion = rWrapper.FcGetVersion();
898*b1cdbd2cSJim Jagielski     if( nVersion <= 20400 )
899*b1cdbd2cSJim Jagielski         return false;
900*b1cdbd2cSJim Jagielski     const char* pDirName = (const char*)rDirName.getStr();
901*b1cdbd2cSJim Jagielski     bool bDirOk = (rWrapper.FcConfigAppFontAddDir( rWrapper.FcConfigGetCurrent(), (FcChar8*)pDirName ) == FcTrue);
902*b1cdbd2cSJim Jagielski 
903*b1cdbd2cSJim Jagielski #if OSL_DEBUG_LEVEL > 1
904*b1cdbd2cSJim Jagielski     fprintf( stderr, "FcConfigAppFontAddDir( \"%s\") => %d\n", pDirName, bDirOk );
905*b1cdbd2cSJim Jagielski #endif
906*b1cdbd2cSJim Jagielski 
907*b1cdbd2cSJim Jagielski     if( !bDirOk )
908*b1cdbd2cSJim Jagielski         return false;
909*b1cdbd2cSJim Jagielski 
910*b1cdbd2cSJim Jagielski     // load dir-specific fc-config file too if available
911*b1cdbd2cSJim Jagielski     const rtl::OString aConfFileName = rDirName + "/fc_local.conf";
912*b1cdbd2cSJim Jagielski     FILE* pCfgFile = fopen( aConfFileName.getStr(), "rb" );
913*b1cdbd2cSJim Jagielski     if( pCfgFile )
914*b1cdbd2cSJim Jagielski     {
915*b1cdbd2cSJim Jagielski         fclose( pCfgFile);
916*b1cdbd2cSJim Jagielski         bool bCfgOk = rWrapper.FcConfigParseAndLoad( rWrapper.FcConfigGetCurrent(),
917*b1cdbd2cSJim Jagielski                         (FcChar8*)aConfFileName.getStr(), FcTrue );
918*b1cdbd2cSJim Jagielski         if( !bCfgOk )
919*b1cdbd2cSJim Jagielski             fprintf( stderr, "FcConfigParseAndLoad( \"%s\") => %d\n", aConfFileName.getStr(), bCfgOk );
920*b1cdbd2cSJim Jagielski     }
921*b1cdbd2cSJim Jagielski 
922*b1cdbd2cSJim Jagielski     return true;
923*b1cdbd2cSJim Jagielski }
924*b1cdbd2cSJim Jagielski 
addtopattern(FontCfgWrapper & rWrapper,FcPattern * pPattern,italic::type eItalic,weight::type eWeight,width::type eWidth,pitch::type ePitch)925*b1cdbd2cSJim Jagielski static void addtopattern(FontCfgWrapper& rWrapper, FcPattern *pPattern,
926*b1cdbd2cSJim Jagielski 	italic::type eItalic, weight::type eWeight, width::type eWidth, pitch::type ePitch)
927*b1cdbd2cSJim Jagielski {
928*b1cdbd2cSJim Jagielski     if( eItalic != italic::Unknown )
929*b1cdbd2cSJim Jagielski     {
930*b1cdbd2cSJim Jagielski         int nSlant = FC_SLANT_ROMAN;
931*b1cdbd2cSJim Jagielski         switch( eItalic )
932*b1cdbd2cSJim Jagielski         {
933*b1cdbd2cSJim Jagielski             case italic::Italic:	 	nSlant = FC_SLANT_ITALIC;break;
934*b1cdbd2cSJim Jagielski             case italic::Oblique:	 	nSlant = FC_SLANT_OBLIQUE;break;
935*b1cdbd2cSJim Jagielski             default:
936*b1cdbd2cSJim Jagielski                 break;
937*b1cdbd2cSJim Jagielski         }
938*b1cdbd2cSJim Jagielski         rWrapper.FcPatternAddInteger( pPattern, FC_SLANT, nSlant );
939*b1cdbd2cSJim Jagielski     }
940*b1cdbd2cSJim Jagielski     if( eWeight != weight::Unknown )
941*b1cdbd2cSJim Jagielski     {
942*b1cdbd2cSJim Jagielski         int nWeight = FC_WEIGHT_NORMAL;
943*b1cdbd2cSJim Jagielski         switch( eWeight )
944*b1cdbd2cSJim Jagielski         {
945*b1cdbd2cSJim Jagielski             case weight::Thin:			nWeight = FC_WEIGHT_THIN;break;
946*b1cdbd2cSJim Jagielski             case weight::UltraLight:	nWeight = FC_WEIGHT_ULTRALIGHT;break;
947*b1cdbd2cSJim Jagielski             case weight::Light:			nWeight = FC_WEIGHT_LIGHT;break;
948*b1cdbd2cSJim Jagielski             case weight::SemiLight:		nWeight = FC_WEIGHT_BOOK;break;
949*b1cdbd2cSJim Jagielski             case weight::Normal:		nWeight = FC_WEIGHT_NORMAL;break;
950*b1cdbd2cSJim Jagielski             case weight::Medium:		nWeight = FC_WEIGHT_MEDIUM;break;
951*b1cdbd2cSJim Jagielski             case weight::SemiBold:		nWeight = FC_WEIGHT_SEMIBOLD;break;
952*b1cdbd2cSJim Jagielski             case weight::Bold:			nWeight = FC_WEIGHT_BOLD;break;
953*b1cdbd2cSJim Jagielski             case weight::UltraBold:		nWeight	= FC_WEIGHT_ULTRABOLD;break;
954*b1cdbd2cSJim Jagielski             case weight::Black:			nWeight	= FC_WEIGHT_BLACK;break;
955*b1cdbd2cSJim Jagielski             default:
956*b1cdbd2cSJim Jagielski                 break;
957*b1cdbd2cSJim Jagielski         }
958*b1cdbd2cSJim Jagielski         rWrapper.FcPatternAddInteger( pPattern, FC_WEIGHT, nWeight );
959*b1cdbd2cSJim Jagielski     }
960*b1cdbd2cSJim Jagielski     if( eWidth != width::Unknown )
961*b1cdbd2cSJim Jagielski     {
962*b1cdbd2cSJim Jagielski         int nWidth = FC_WIDTH_NORMAL;
963*b1cdbd2cSJim Jagielski         switch( eWidth )
964*b1cdbd2cSJim Jagielski         {
965*b1cdbd2cSJim Jagielski             case width::UltraCondensed:	nWidth = FC_WIDTH_ULTRACONDENSED;break;
966*b1cdbd2cSJim Jagielski             case width::ExtraCondensed: nWidth = FC_WIDTH_EXTRACONDENSED;break;
967*b1cdbd2cSJim Jagielski             case width::Condensed:		nWidth = FC_WIDTH_CONDENSED;break;
968*b1cdbd2cSJim Jagielski             case width::SemiCondensed:	nWidth = FC_WIDTH_SEMICONDENSED;break;
969*b1cdbd2cSJim Jagielski             case width::Normal:			nWidth = FC_WIDTH_NORMAL;break;
970*b1cdbd2cSJim Jagielski             case width::SemiExpanded:	nWidth = FC_WIDTH_SEMIEXPANDED;break;
971*b1cdbd2cSJim Jagielski             case width::Expanded:		nWidth = FC_WIDTH_EXPANDED;break;
972*b1cdbd2cSJim Jagielski             case width::ExtraExpanded:	nWidth = FC_WIDTH_EXTRAEXPANDED;break;
973*b1cdbd2cSJim Jagielski             case width::UltraExpanded:	nWidth = FC_WIDTH_ULTRACONDENSED;break;
974*b1cdbd2cSJim Jagielski             default:
975*b1cdbd2cSJim Jagielski                 break;
976*b1cdbd2cSJim Jagielski         }
977*b1cdbd2cSJim Jagielski         rWrapper.FcPatternAddInteger( pPattern, FC_WIDTH, nWidth );
978*b1cdbd2cSJim Jagielski     }
979*b1cdbd2cSJim Jagielski     if( ePitch != pitch::Unknown )
980*b1cdbd2cSJim Jagielski     {
981*b1cdbd2cSJim Jagielski         int nSpacing = FC_PROPORTIONAL;
982*b1cdbd2cSJim Jagielski         switch( ePitch )
983*b1cdbd2cSJim Jagielski         {
984*b1cdbd2cSJim Jagielski             case pitch::Fixed:			nSpacing = FC_MONO;break;
985*b1cdbd2cSJim Jagielski             case pitch::Variable:		nSpacing = FC_PROPORTIONAL;break;
986*b1cdbd2cSJim Jagielski             default:
987*b1cdbd2cSJim Jagielski                 break;
988*b1cdbd2cSJim Jagielski         }
989*b1cdbd2cSJim Jagielski         rWrapper.FcPatternAddInteger( pPattern, FC_SPACING, nSpacing );
990*b1cdbd2cSJim Jagielski         if (nSpacing == FC_MONO)
991*b1cdbd2cSJim Jagielski             rWrapper.FcPatternAddString( pPattern, FC_FAMILY, (FcChar8*)"monospace");
992*b1cdbd2cSJim Jagielski     }
993*b1cdbd2cSJim Jagielski }
994*b1cdbd2cSJim Jagielski 
Substitute(const rtl::OUString & rFontName,rtl::OUString & rMissingCodes,const rtl::OString & rLangAttrib,italic::type & rItalic,weight::type & rWeight,width::type & rWidth,pitch::type & rPitch) const995*b1cdbd2cSJim Jagielski rtl::OUString PrintFontManager::Substitute(const rtl::OUString& rFontName,
996*b1cdbd2cSJim Jagielski     rtl::OUString& rMissingCodes, const rtl::OString &rLangAttrib,
997*b1cdbd2cSJim Jagielski     italic::type &rItalic, weight::type &rWeight,
998*b1cdbd2cSJim Jagielski     width::type &rWidth, pitch::type &rPitch) const
999*b1cdbd2cSJim Jagielski {
1000*b1cdbd2cSJim Jagielski     rtl::OUString aName;
1001*b1cdbd2cSJim Jagielski     FontCfgWrapper& rWrapper = FontCfgWrapper::get();
1002*b1cdbd2cSJim Jagielski     if( ! rWrapper.isValid() )
1003*b1cdbd2cSJim Jagielski         return aName;
1004*b1cdbd2cSJim Jagielski 
1005*b1cdbd2cSJim Jagielski     // build pattern argument for fontconfig query
1006*b1cdbd2cSJim Jagielski     FcPattern* pPattern = rWrapper.FcPatternCreate();
1007*b1cdbd2cSJim Jagielski 
1008*b1cdbd2cSJim Jagielski     // Prefer scalable fonts
1009*b1cdbd2cSJim Jagielski     rWrapper.FcPatternAddBool( pPattern, FC_SCALABLE, FcTrue );
1010*b1cdbd2cSJim Jagielski 
1011*b1cdbd2cSJim Jagielski     const rtl::OString aTargetName = rtl::OUStringToOString( rFontName, RTL_TEXTENCODING_UTF8 );
1012*b1cdbd2cSJim Jagielski     const FcChar8* pTargetNameUtf8 = (FcChar8*)aTargetName.getStr();
1013*b1cdbd2cSJim Jagielski     rWrapper.FcPatternAddString( pPattern, FC_FAMILY, pTargetNameUtf8 );
1014*b1cdbd2cSJim Jagielski 
1015*b1cdbd2cSJim Jagielski     const FcChar8* pLangAttribUtf8 = (FcChar8*)rLangAttrib.getStr();
1016*b1cdbd2cSJim Jagielski     if( rLangAttrib.getLength() )
1017*b1cdbd2cSJim Jagielski         rWrapper.FcPatternAddString( pPattern, FC_LANG, pLangAttribUtf8 );
1018*b1cdbd2cSJim Jagielski 
1019*b1cdbd2cSJim Jagielski     // Add required Unicode characters, if any
1020*b1cdbd2cSJim Jagielski     if ( rMissingCodes.getLength() )
1021*b1cdbd2cSJim Jagielski     {
1022*b1cdbd2cSJim Jagielski        FcCharSet *unicodes = rWrapper.FcCharSetCreate();
1023*b1cdbd2cSJim Jagielski        for( sal_Int32 nStrIndex = 0; nStrIndex < rMissingCodes.getLength(); )
1024*b1cdbd2cSJim Jagielski        {
1025*b1cdbd2cSJim Jagielski            // also handle unicode surrogates
1026*b1cdbd2cSJim Jagielski            const sal_uInt32 nCode = rMissingCodes.iterateCodePoints( &nStrIndex );
1027*b1cdbd2cSJim Jagielski            rWrapper.FcCharSetAddChar( unicodes, nCode );
1028*b1cdbd2cSJim Jagielski        }
1029*b1cdbd2cSJim Jagielski        rWrapper.FcPatternAddCharSet( pPattern, FC_CHARSET, unicodes);
1030*b1cdbd2cSJim Jagielski        rWrapper.FcCharSetDestroy( unicodes );
1031*b1cdbd2cSJim Jagielski     }
1032*b1cdbd2cSJim Jagielski 
1033*b1cdbd2cSJim Jagielski     addtopattern(rWrapper, pPattern, rItalic, rWeight, rWidth, rPitch);
1034*b1cdbd2cSJim Jagielski 
1035*b1cdbd2cSJim Jagielski     // query fontconfig for a substitute
1036*b1cdbd2cSJim Jagielski     rWrapper.FcConfigSubstitute( rWrapper.FcConfigGetCurrent(), pPattern, FcMatchPattern );
1037*b1cdbd2cSJim Jagielski     rWrapper.FcDefaultSubstitute( pPattern );
1038*b1cdbd2cSJim Jagielski 
1039*b1cdbd2cSJim Jagielski     // process the result of the fontconfig query
1040*b1cdbd2cSJim Jagielski     FcResult eResult = FcResultNoMatch;
1041*b1cdbd2cSJim Jagielski     FcFontSet* pFontSet = rWrapper.getFontSet();
1042*b1cdbd2cSJim Jagielski     FcPattern* pResult = rWrapper.FcFontSetMatch( rWrapper.FcConfigGetCurrent(), &pFontSet, 1, pPattern, &eResult );
1043*b1cdbd2cSJim Jagielski     rWrapper.FcPatternDestroy( pPattern );
1044*b1cdbd2cSJim Jagielski 
1045*b1cdbd2cSJim Jagielski     FcFontSet*  pSet = NULL;
1046*b1cdbd2cSJim Jagielski     if( pResult )
1047*b1cdbd2cSJim Jagielski     {
1048*b1cdbd2cSJim Jagielski         pSet = rWrapper.FcFontSetCreate();
1049*b1cdbd2cSJim Jagielski         // info: destroying the pSet destroys pResult implicitly
1050*b1cdbd2cSJim Jagielski         // since pResult was "added" to pSet
1051*b1cdbd2cSJim Jagielski         rWrapper.FcFontSetAdd( pSet, pResult );
1052*b1cdbd2cSJim Jagielski     }
1053*b1cdbd2cSJim Jagielski 
1054*b1cdbd2cSJim Jagielski     if( pSet )
1055*b1cdbd2cSJim Jagielski     {
1056*b1cdbd2cSJim Jagielski         if( pSet->nfont > 0 )
1057*b1cdbd2cSJim Jagielski         {
1058*b1cdbd2cSJim Jagielski             //extract the closest match
1059*b1cdbd2cSJim Jagielski             FcChar8* family = NULL;
1060*b1cdbd2cSJim Jagielski             FcResult eFileRes = rWrapper.FcPatternGetString( pSet->fonts[0], FC_FAMILY, 0, &family );
1061*b1cdbd2cSJim Jagielski 
1062*b1cdbd2cSJim Jagielski 			// get the family name
1063*b1cdbd2cSJim Jagielski             if( eFileRes == FcResultMatch )
1064*b1cdbd2cSJim Jagielski             {
1065*b1cdbd2cSJim Jagielski                 OString sFamily((sal_Char*)family);
1066*b1cdbd2cSJim Jagielski                 std::hash_map< rtl::OString, rtl::OString, rtl::OStringHash >::const_iterator aI = rWrapper.m_aFontNameToLocalized.find(sFamily);
1067*b1cdbd2cSJim Jagielski                 if (aI != rWrapper.m_aFontNameToLocalized.end())
1068*b1cdbd2cSJim Jagielski                     sFamily = aI->second;
1069*b1cdbd2cSJim Jagielski                 aName = rtl::OStringToOUString( sFamily, RTL_TEXTENCODING_UTF8 );
1070*b1cdbd2cSJim Jagielski 
1071*b1cdbd2cSJim Jagielski 
1072*b1cdbd2cSJim Jagielski                 int val = 0;
1073*b1cdbd2cSJim Jagielski                 if ( FcResultMatch == rWrapper.FcPatternGetInteger( pSet->fonts[0], FC_WEIGHT, 0, &val))
1074*b1cdbd2cSJim Jagielski                     rWeight = convertWeight(val);
1075*b1cdbd2cSJim Jagielski                 if ( FcResultMatch == rWrapper.FcPatternGetInteger( pSet->fonts[0], FC_SLANT, 0, &val))
1076*b1cdbd2cSJim Jagielski                     rItalic = convertSlant(val);
1077*b1cdbd2cSJim Jagielski                 if ( FcResultMatch == rWrapper.FcPatternGetInteger( pSet->fonts[0], FC_SPACING, 0, &val))
1078*b1cdbd2cSJim Jagielski                     rPitch = convertSpacing(val);
1079*b1cdbd2cSJim Jagielski                 if ( FcResultMatch == rWrapper.FcPatternGetInteger( pSet->fonts[0], FC_WIDTH, 0, &val))
1080*b1cdbd2cSJim Jagielski                     rWidth = convertWidth(val);
1081*b1cdbd2cSJim Jagielski             }
1082*b1cdbd2cSJim Jagielski 
1083*b1cdbd2cSJim Jagielski 			// update rMissingCodes by removing resolved unicodes
1084*b1cdbd2cSJim Jagielski 	    	if( rMissingCodes.getLength() > 0 )
1085*b1cdbd2cSJim Jagielski             {
1086*b1cdbd2cSJim Jagielski                 sal_uInt32* pRemainingCodes = (sal_uInt32*)alloca( rMissingCodes.getLength() * sizeof(sal_uInt32) );
1087*b1cdbd2cSJim Jagielski                 int nRemainingLen = 0;
1088*b1cdbd2cSJim Jagielski 		    	FcCharSet* unicodes;
1089*b1cdbd2cSJim Jagielski 		    	if( !rWrapper.FcPatternGetCharSet( pSet->fonts[0], FC_CHARSET, 0, &unicodes ) )
1090*b1cdbd2cSJim Jagielski 		    	{
1091*b1cdbd2cSJim Jagielski        				for( sal_Int32 nStrIndex = 0; nStrIndex < rMissingCodes.getLength(); )
1092*b1cdbd2cSJim Jagielski 					{
1093*b1cdbd2cSJim Jagielski 						// also handle unicode surrogates
1094*b1cdbd2cSJim Jagielski 						const sal_uInt32 nCode = rMissingCodes.iterateCodePoints( &nStrIndex );
1095*b1cdbd2cSJim Jagielski 		            	if( rWrapper.FcCharSetHasChar( unicodes, nCode ) != FcTrue )
1096*b1cdbd2cSJim Jagielski 							pRemainingCodes[ nRemainingLen++ ] = nCode;
1097*b1cdbd2cSJim Jagielski                     }
1098*b1cdbd2cSJim Jagielski 		    	}
1099*b1cdbd2cSJim Jagielski 		    	rMissingCodes = OUString( pRemainingCodes, nRemainingLen );
1100*b1cdbd2cSJim Jagielski             }
1101*b1cdbd2cSJim Jagielski         }
1102*b1cdbd2cSJim Jagielski 
1103*b1cdbd2cSJim Jagielski     	rWrapper.FcFontSetDestroy( pSet );
1104*b1cdbd2cSJim Jagielski     }
1105*b1cdbd2cSJim Jagielski 
1106*b1cdbd2cSJim Jagielski     return aName;
1107*b1cdbd2cSJim Jagielski }
1108*b1cdbd2cSJim Jagielski 
getFontOptions(const FastPrintFontInfo & rInfo,int nSize,void (* subcallback)(void *),ImplFontOptions & rOptions) const1109*b1cdbd2cSJim Jagielski bool PrintFontManager::getFontOptions(
1110*b1cdbd2cSJim Jagielski     const FastPrintFontInfo& rInfo, int nSize, void (*subcallback)(void*),
1111*b1cdbd2cSJim Jagielski     ImplFontOptions& rOptions) const
1112*b1cdbd2cSJim Jagielski {
1113*b1cdbd2cSJim Jagielski #ifndef ENABLE_FONTCONFIG
1114*b1cdbd2cSJim Jagielski     (void)rInfo;(void)nSize;(void)subcallback;(void)rOptions;
1115*b1cdbd2cSJim Jagielski     return false;
1116*b1cdbd2cSJim Jagielski #else // ENABLE_FONTCONFIG
1117*b1cdbd2cSJim Jagielski     FontCfgWrapper& rWrapper = FontCfgWrapper::get();
1118*b1cdbd2cSJim Jagielski     if( ! rWrapper.isValid() )
1119*b1cdbd2cSJim Jagielski         return false;
1120*b1cdbd2cSJim Jagielski 
1121*b1cdbd2cSJim Jagielski     FcConfig* pConfig = rWrapper.FcConfigGetCurrent();
1122*b1cdbd2cSJim Jagielski     FcPattern* pPattern = rWrapper.FcPatternCreate();
1123*b1cdbd2cSJim Jagielski 
1124*b1cdbd2cSJim Jagielski     OString sFamily = OUStringToOString( rInfo.m_aFamilyName, RTL_TEXTENCODING_UTF8 );
1125*b1cdbd2cSJim Jagielski 
1126*b1cdbd2cSJim Jagielski     std::hash_map< rtl::OString, rtl::OString, rtl::OStringHash >::const_iterator aI = rWrapper.m_aLocalizedToCanonical.find(sFamily);
1127*b1cdbd2cSJim Jagielski     if (aI != rWrapper.m_aLocalizedToCanonical.end())
1128*b1cdbd2cSJim Jagielski         sFamily = aI->second;
1129*b1cdbd2cSJim Jagielski     if( sFamily.getLength() )
1130*b1cdbd2cSJim Jagielski         rWrapper.FcPatternAddString( pPattern, FC_FAMILY, (FcChar8*)sFamily.getStr() );
1131*b1cdbd2cSJim Jagielski 
1132*b1cdbd2cSJim Jagielski     addtopattern(rWrapper, pPattern, rInfo.m_eItalic, rInfo.m_eWeight, rInfo.m_eWidth, rInfo.m_ePitch);
1133*b1cdbd2cSJim Jagielski     rWrapper.FcPatternAddDouble( pPattern, FC_PIXEL_SIZE, nSize);
1134*b1cdbd2cSJim Jagielski 
1135*b1cdbd2cSJim Jagielski     FcBool embitmap = true, antialias = true, autohint = true, hinting = true;
1136*b1cdbd2cSJim Jagielski     int hintstyle = FC_HINT_FULL;
1137*b1cdbd2cSJim Jagielski 
1138*b1cdbd2cSJim Jagielski     rWrapper.FcConfigSubstitute( pConfig, pPattern, FcMatchPattern );
1139*b1cdbd2cSJim Jagielski     if (subcallback) subcallback(pPattern);
1140*b1cdbd2cSJim Jagielski     rWrapper.FcDefaultSubstitute( pPattern );
1141*b1cdbd2cSJim Jagielski 
1142*b1cdbd2cSJim Jagielski     FcResult eResult = FcResultNoMatch;
1143*b1cdbd2cSJim Jagielski     FcFontSet* pFontSet = rWrapper.getFontSet();
1144*b1cdbd2cSJim Jagielski     FcPattern* pResult = rWrapper.FcFontSetMatch( pConfig, &pFontSet, 1, pPattern, &eResult );
1145*b1cdbd2cSJim Jagielski     if( pResult )
1146*b1cdbd2cSJim Jagielski     {
1147*b1cdbd2cSJim Jagielski         FcFontSet* pSet = rWrapper.FcFontSetCreate();
1148*b1cdbd2cSJim Jagielski         rWrapper.FcFontSetAdd( pSet, pResult );
1149*b1cdbd2cSJim Jagielski         if( pSet->nfont > 0 )
1150*b1cdbd2cSJim Jagielski         {
1151*b1cdbd2cSJim Jagielski             FcResult eEmbeddedBitmap = rWrapper.FcPatternGetBool(pSet->fonts[0],
1152*b1cdbd2cSJim Jagielski                 FC_EMBEDDED_BITMAP, 0, &embitmap);
1153*b1cdbd2cSJim Jagielski             FcResult eAntialias = rWrapper.FcPatternGetBool(pSet->fonts[0],
1154*b1cdbd2cSJim Jagielski                 FC_ANTIALIAS, 0, &antialias);
1155*b1cdbd2cSJim Jagielski             FcResult eAutoHint = rWrapper.FcPatternGetBool(pSet->fonts[0],
1156*b1cdbd2cSJim Jagielski                 FC_AUTOHINT, 0, &autohint);
1157*b1cdbd2cSJim Jagielski             FcResult eHinting = rWrapper.FcPatternGetBool(pSet->fonts[0],
1158*b1cdbd2cSJim Jagielski                 FC_HINTING, 0, &hinting);
1159*b1cdbd2cSJim Jagielski             /*FcResult eHintStyle =*/ rWrapper.FcPatternGetInteger( pSet->fonts[0],
1160*b1cdbd2cSJim Jagielski                 FC_HINT_STYLE, 0, &hintstyle);
1161*b1cdbd2cSJim Jagielski 
1162*b1cdbd2cSJim Jagielski             if( eEmbeddedBitmap == FcResultMatch )
1163*b1cdbd2cSJim Jagielski                 rOptions.meEmbeddedBitmap = embitmap ? EMBEDDEDBITMAP_TRUE : EMBEDDEDBITMAP_FALSE;
1164*b1cdbd2cSJim Jagielski             if( eAntialias == FcResultMatch )
1165*b1cdbd2cSJim Jagielski                 rOptions.meAntiAlias = antialias ? ANTIALIAS_TRUE : ANTIALIAS_FALSE;
1166*b1cdbd2cSJim Jagielski             if( eAutoHint == FcResultMatch )
1167*b1cdbd2cSJim Jagielski                 rOptions.meAutoHint = autohint ? AUTOHINT_TRUE : AUTOHINT_FALSE;
1168*b1cdbd2cSJim Jagielski             if( eHinting == FcResultMatch )
1169*b1cdbd2cSJim Jagielski                 rOptions.meHinting = hinting ? HINTING_TRUE : HINTING_FALSE;
1170*b1cdbd2cSJim Jagielski             switch (hintstyle)
1171*b1cdbd2cSJim Jagielski             {
1172*b1cdbd2cSJim Jagielski                 case FC_HINT_NONE:   rOptions.meHintStyle = HINT_NONE; break;
1173*b1cdbd2cSJim Jagielski                 case FC_HINT_SLIGHT: rOptions.meHintStyle = HINT_SLIGHT; break;
1174*b1cdbd2cSJim Jagielski                 case FC_HINT_MEDIUM: rOptions.meHintStyle = HINT_MEDIUM; break;
1175*b1cdbd2cSJim Jagielski                 default: // fall through
1176*b1cdbd2cSJim Jagielski                 case FC_HINT_FULL:   rOptions.meHintStyle = HINT_FULL; break;
1177*b1cdbd2cSJim Jagielski             }
1178*b1cdbd2cSJim Jagielski         }
1179*b1cdbd2cSJim Jagielski         // info: destroying the pSet destroys pResult implicitly
1180*b1cdbd2cSJim Jagielski         // since pResult was "added" to pSet
1181*b1cdbd2cSJim Jagielski         rWrapper.FcFontSetDestroy( pSet );
1182*b1cdbd2cSJim Jagielski     }
1183*b1cdbd2cSJim Jagielski 
1184*b1cdbd2cSJim Jagielski     // cleanup
1185*b1cdbd2cSJim Jagielski     rWrapper.FcPatternDestroy( pPattern );
1186*b1cdbd2cSJim Jagielski 
1187*b1cdbd2cSJim Jagielski     // TODO: return true only if non-default font options are set
1188*b1cdbd2cSJim Jagielski     const bool bOK = (pResult != NULL);
1189*b1cdbd2cSJim Jagielski     return bOK;
1190*b1cdbd2cSJim Jagielski #endif
1191*b1cdbd2cSJim Jagielski }
1192*b1cdbd2cSJim Jagielski 
matchFont(FastPrintFontInfo & rInfo,const com::sun::star::lang::Locale & rLocale)1193*b1cdbd2cSJim Jagielski bool PrintFontManager::matchFont( FastPrintFontInfo& rInfo, const com::sun::star::lang::Locale& rLocale )
1194*b1cdbd2cSJim Jagielski {
1195*b1cdbd2cSJim Jagielski     FontCfgWrapper& rWrapper = FontCfgWrapper::get();
1196*b1cdbd2cSJim Jagielski     if( ! rWrapper.isValid() )
1197*b1cdbd2cSJim Jagielski         return false;
1198*b1cdbd2cSJim Jagielski 
1199*b1cdbd2cSJim Jagielski     FcConfig* pConfig = rWrapper.FcConfigGetCurrent();
1200*b1cdbd2cSJim Jagielski     FcPattern* pPattern = rWrapper.FcPatternCreate();
1201*b1cdbd2cSJim Jagielski 
1202*b1cdbd2cSJim Jagielski     OString aLangAttrib;
1203*b1cdbd2cSJim Jagielski     // populate pattern with font characteristics
1204*b1cdbd2cSJim Jagielski     if( rLocale.Language.getLength() )
1205*b1cdbd2cSJim Jagielski     {
1206*b1cdbd2cSJim Jagielski         OUStringBuffer aLang(6);
1207*b1cdbd2cSJim Jagielski         aLang.append( rLocale.Language );
1208*b1cdbd2cSJim Jagielski         if( rLocale.Country.getLength() )
1209*b1cdbd2cSJim Jagielski         {
1210*b1cdbd2cSJim Jagielski             aLang.append( sal_Unicode('-') );
1211*b1cdbd2cSJim Jagielski             aLang.append( rLocale.Country );
1212*b1cdbd2cSJim Jagielski         }
1213*b1cdbd2cSJim Jagielski         aLangAttrib = OUStringToOString( aLang.makeStringAndClear(), RTL_TEXTENCODING_UTF8 );
1214*b1cdbd2cSJim Jagielski     }
1215*b1cdbd2cSJim Jagielski     if( aLangAttrib.getLength() )
1216*b1cdbd2cSJim Jagielski         rWrapper.FcPatternAddString( pPattern, FC_LANG, (FcChar8*)aLangAttrib.getStr() );
1217*b1cdbd2cSJim Jagielski 
1218*b1cdbd2cSJim Jagielski     OString aFamily = OUStringToOString( rInfo.m_aFamilyName, RTL_TEXTENCODING_UTF8 );
1219*b1cdbd2cSJim Jagielski     if( aFamily.getLength() )
1220*b1cdbd2cSJim Jagielski         rWrapper.FcPatternAddString( pPattern, FC_FAMILY, (FcChar8*)aFamily.getStr() );
1221*b1cdbd2cSJim Jagielski 
1222*b1cdbd2cSJim Jagielski     addtopattern(rWrapper, pPattern, rInfo.m_eItalic, rInfo.m_eWeight, rInfo.m_eWidth, rInfo.m_ePitch);
1223*b1cdbd2cSJim Jagielski 
1224*b1cdbd2cSJim Jagielski     rWrapper.FcConfigSubstitute( pConfig, pPattern, FcMatchPattern );
1225*b1cdbd2cSJim Jagielski     rWrapper.FcDefaultSubstitute( pPattern );
1226*b1cdbd2cSJim Jagielski     FcResult eResult = FcResultNoMatch;
1227*b1cdbd2cSJim Jagielski     FcFontSet *pFontSet = rWrapper.getFontSet();
1228*b1cdbd2cSJim Jagielski     FcPattern* pResult = rWrapper.FcFontSetMatch( pConfig, &pFontSet, 1, pPattern, &eResult );
1229*b1cdbd2cSJim Jagielski     bool bSuccess = false;
1230*b1cdbd2cSJim Jagielski     if( pResult )
1231*b1cdbd2cSJim Jagielski     {
1232*b1cdbd2cSJim Jagielski         FcFontSet* pSet = rWrapper.FcFontSetCreate();
1233*b1cdbd2cSJim Jagielski         rWrapper.FcFontSetAdd( pSet, pResult );
1234*b1cdbd2cSJim Jagielski         if( pSet->nfont > 0 )
1235*b1cdbd2cSJim Jagielski         {
1236*b1cdbd2cSJim Jagielski             //extract the closest match
1237*b1cdbd2cSJim Jagielski             FcChar8* file = NULL;
1238*b1cdbd2cSJim Jagielski             FcResult eFileRes = rWrapper.FcPatternGetString( pSet->fonts[0], FC_FILE, 0, &file );
1239*b1cdbd2cSJim Jagielski             if( eFileRes == FcResultMatch )
1240*b1cdbd2cSJim Jagielski             {
1241*b1cdbd2cSJim Jagielski                 OString aDir, aBase, aOrgPath( (sal_Char*)file );
1242*b1cdbd2cSJim Jagielski                 splitPath( aOrgPath, aDir, aBase );
1243*b1cdbd2cSJim Jagielski                 int nDirID = getDirectoryAtom( aDir, true );
1244*b1cdbd2cSJim Jagielski                 fontID aFont = findFontFileID( nDirID, aBase );
1245*b1cdbd2cSJim Jagielski                 if( aFont > 0 )
1246*b1cdbd2cSJim Jagielski                     bSuccess = getFontFastInfo( aFont, rInfo );
1247*b1cdbd2cSJim Jagielski             }
1248*b1cdbd2cSJim Jagielski         }
1249*b1cdbd2cSJim Jagielski         // info: destroying the pSet destroys pResult implicitly
1250*b1cdbd2cSJim Jagielski         // since pResult was "added" to pSet
1251*b1cdbd2cSJim Jagielski         rWrapper.FcFontSetDestroy( pSet );
1252*b1cdbd2cSJim Jagielski     }
1253*b1cdbd2cSJim Jagielski 
1254*b1cdbd2cSJim Jagielski     // cleanup
1255*b1cdbd2cSJim Jagielski     rWrapper.FcPatternDestroy( pPattern );
1256*b1cdbd2cSJim Jagielski 
1257*b1cdbd2cSJim Jagielski     return bSuccess;
1258*b1cdbd2cSJim Jagielski }
1259*b1cdbd2cSJim Jagielski 
1260*b1cdbd2cSJim Jagielski #else // ENABLE_FONTCONFIG not defined
1261*b1cdbd2cSJim Jagielski 
initFontconfig()1262*b1cdbd2cSJim Jagielski bool PrintFontManager::initFontconfig()
1263*b1cdbd2cSJim Jagielski {
1264*b1cdbd2cSJim Jagielski     return false;
1265*b1cdbd2cSJim Jagielski }
1266*b1cdbd2cSJim Jagielski 
countFontconfigFonts(std::hash_map<rtl::OString,int,rtl::OStringHash> &)1267*b1cdbd2cSJim Jagielski int PrintFontManager::countFontconfigFonts( std::hash_map<rtl::OString, int, rtl::OStringHash>& )
1268*b1cdbd2cSJim Jagielski {
1269*b1cdbd2cSJim Jagielski     return 0;
1270*b1cdbd2cSJim Jagielski }
1271*b1cdbd2cSJim Jagielski 
deinitFontconfig()1272*b1cdbd2cSJim Jagielski void PrintFontManager::deinitFontconfig()
1273*b1cdbd2cSJim Jagielski {}
1274*b1cdbd2cSJim Jagielski 
addFontconfigDir(const rtl::OString &)1275*b1cdbd2cSJim Jagielski bool PrintFontManager::addFontconfigDir( const rtl::OString& )
1276*b1cdbd2cSJim Jagielski {
1277*b1cdbd2cSJim Jagielski     return false;
1278*b1cdbd2cSJim Jagielski }
1279*b1cdbd2cSJim Jagielski 
matchFont(FastPrintFontInfo &,const com::sun::star::lang::Locale &)1280*b1cdbd2cSJim Jagielski bool PrintFontManager::matchFont( FastPrintFontInfo&, const com::sun::star::lang::Locale& )
1281*b1cdbd2cSJim Jagielski {
1282*b1cdbd2cSJim Jagielski     return false;
1283*b1cdbd2cSJim Jagielski }
1284*b1cdbd2cSJim Jagielski 
FreeTypeCharIndex(void *,sal_uInt32)1285*b1cdbd2cSJim Jagielski int PrintFontManager::FreeTypeCharIndex( void*, sal_uInt32 )
1286*b1cdbd2cSJim Jagielski {
1287*b1cdbd2cSJim Jagielski     return 0;
1288*b1cdbd2cSJim Jagielski }
1289*b1cdbd2cSJim Jagielski 
Substitute(const rtl::OUString &,rtl::OUString &,const rtl::OString &,italic::type,weight::type,width::type,pitch::type) const1290*b1cdbd2cSJim Jagielski rtl::OUString PrintFontManager::Substitute( const rtl::OUString&,
1291*b1cdbd2cSJim Jagielski     rtl::OUString&, const rtl::OString&, italic::type, weight::type, width::type, pitch::type) const
1292*b1cdbd2cSJim Jagielski {
1293*b1cdbd2cSJim Jagielski     rtl::OUString aName;
1294*b1cdbd2cSJim Jagielski     return aName;
1295*b1cdbd2cSJim Jagielski }
1296*b1cdbd2cSJim Jagielski 
1297*b1cdbd2cSJim Jagielski #endif // ENABLE_FONTCONFIG
1298*b1cdbd2cSJim Jagielski 
1299