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