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