Update ooo320-m1
[ooovba.git] / vcl / unx / source / fontmanager / fontconfig.cxx
blob12b9f00764eaaa63058b03e1d9ce462c7b92d083
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: fontconfig.cxx,v $
10 * $Revision: 1.30.24.2 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_vcl.hxx"
34 #include "vcl/fontmanager.hxx"
35 #include "vcl/fontcache.hxx"
37 using namespace psp;
39 #ifdef ENABLE_FONTCONFIG
40 #include <fontconfig/fontconfig.h>
41 #include <ft2build.h>
42 #include <fontconfig/fcfreetype.h>
43 // be compatible with fontconfig 2.2.0 release
44 #ifndef FC_WEIGHT_BOOK
45 #define FC_WEIGHT_BOOK 75
46 #endif
47 #ifndef FC_EMBEDDED_BITMAP
48 #define FC_EMBEDDED_BITMAP "embeddedbitmap"
49 #endif
50 #ifndef FC_FAMILYLANG
51 #define FC_FAMILYLANG "familylang"
52 #endif
53 #else
54 typedef void FcConfig;
55 typedef void FcObjectSet;
56 typedef void FcPattern;
57 typedef void FcFontSet;
58 typedef void FcCharSet;
59 typedef int FcResult;
60 typedef int FcBool;
61 typedef int FcMatchKind;
62 typedef char FcChar8;
63 typedef int FcChar32;
64 typedef unsigned int FT_UInt;
65 typedef void* FT_Face;
66 typedef int FcSetName;
67 #endif
69 #include <cstdio>
70 #include <cstdarg>
72 #include "unotools/atom.hxx"
74 #include "osl/module.h"
75 #include "osl/thread.h"
76 #include "osl/process.h"
78 #include "rtl/ustrbuf.hxx"
79 #include "rtl/locale.hxx"
81 #include "sal/alloca.h"
83 #include <utility>
84 #include <algorithm>
86 using namespace osl;
87 using namespace rtl;
89 class FontCfgWrapper
91 oslModule m_pLib;
92 FcFontSet* m_pOutlineSet;
94 int m_nFcVersion;
95 FcBool (*m_pFcInit)();
96 int (*m_pFcGetVersion)();
97 FcConfig* (*m_pFcConfigGetCurrent)();
98 FcObjectSet* (*m_pFcObjectSetVaBuild)(const char*,va_list);
99 void (*m_pFcObjectSetDestroy)(FcObjectSet* pSet);
100 FcPattern* (*m_pFcPatternCreate)();
101 void (*m_pFcPatternDestroy)(FcPattern*);
102 FcFontSet* (*m_pFcFontList)(FcConfig*,FcPattern*,FcObjectSet*);
103 FcFontSet* (*m_pFcConfigGetFonts)(FcConfig*,FcSetName);
104 FcFontSet* (*m_pFcFontSetCreate)();
105 FcCharSet* (*m_pFcCharSetCreate)();
106 FcBool (*m_pFcCharSetAddChar)(FcCharSet *, FcChar32);
107 FcBool (*m_pFcCharSetHasChar)(FcCharSet *, FcChar32);
108 void (*m_pFcCharSetDestroy)(FcCharSet*);
109 void (*m_pFcFontSetDestroy)(FcFontSet*);
110 FcBool (*m_pFcFontSetAdd)(FcFontSet*,FcPattern*);
111 void (*m_pFcPatternReference)(FcPattern*);
112 FcResult (*m_pFcPatternGetCharSet)(const FcPattern*,const char*,int,FcCharSet**);
113 FcResult (*m_pFcPatternGetString)(const FcPattern*,const char*,int,FcChar8**);
114 FcResult (*m_pFcPatternGetInteger)(const FcPattern*,const char*,int,int*);
115 FcResult (*m_pFcPatternGetDouble)(const FcPattern*,const char*,int,double*);
116 FcResult (*m_pFcPatternGetBool)(const FcPattern*,const char*,int,FcBool*);
117 void (*m_pFcDefaultSubstitute)(FcPattern *);
118 FcPattern* (*m_pFcFontSetMatch)(FcConfig*,FcFontSet**, int, FcPattern*,FcResult*);
119 FcBool (*m_pFcConfigAppFontAddFile)(FcConfig*, const FcChar8*);
120 FcBool (*m_pFcConfigAppFontAddDir)(FcConfig*, const FcChar8*);
121 FcBool (*m_pFcConfigSubstitute)(FcConfig*,FcPattern*,FcMatchKind);
122 FcBool (*m_pFcPatternAddInteger)(FcPattern*,const char*,int);
123 FcBool (*m_pFcPatternAddBool)(FcPattern*,const char*,FcBool);
124 FcBool (*m_pFcPatternAddCharSet)(FcPattern*,const char*,const FcCharSet*);
125 FcBool (*m_pFcPatternAddString)(FcPattern*,const char*,const FcChar8*);
126 FT_UInt (*m_pFcFreeTypeCharIndex)(FT_Face,FcChar32);
128 oslGenericFunction loadSymbol( const char* );
129 void addFontSet( FcSetName );
131 FontCfgWrapper();
132 ~FontCfgWrapper();
134 public:
135 static FontCfgWrapper& get();
136 static void release();
138 bool isValid() const
139 { return m_pLib != NULL;}
141 FcFontSet* getFontSet();
143 FcBool FcInit()
144 { return m_pFcInit(); }
146 int FcGetVersion()
147 { return m_pFcGetVersion(); }
149 FcConfig* FcConfigGetCurrent()
150 { return m_pFcConfigGetCurrent(); }
152 FcObjectSet* FcObjectSetBuild( const char* first, ... )
154 va_list ap;
155 va_start( ap, first );
156 FcObjectSet* pSet = m_pFcObjectSetVaBuild( first, ap );
157 va_end( ap );
158 return pSet;
161 void FcObjectSetDestroy( FcObjectSet* pSet )
162 { m_pFcObjectSetDestroy( pSet ); }
164 FcPattern* FcPatternCreate()
165 { return m_pFcPatternCreate(); }
167 void FcPatternDestroy( FcPattern* pPattern )
168 { m_pFcPatternDestroy( pPattern ); }
170 FcFontSet* FcFontList( FcConfig* pConfig, FcPattern* pPattern, FcObjectSet* pSet )
171 { return m_pFcFontList( pConfig, pPattern, pSet ); }
173 FcFontSet* FcConfigGetFonts( FcConfig* pConfig, FcSetName eSet)
174 { return m_pFcConfigGetFonts( pConfig, eSet ); }
176 FcFontSet* FcFontSetCreate()
177 { return m_pFcFontSetCreate(); }
179 FcCharSet* FcCharSetCreate()
180 { return m_pFcCharSetCreate(); }
182 FcBool FcCharSetAddChar(FcCharSet *fcs, FcChar32 ucs4)
183 { return m_pFcCharSetAddChar(fcs, ucs4); }
185 FcBool FcCharSetHasChar(FcCharSet *fcs, FcChar32 ucs4)
186 { return m_pFcCharSetHasChar(fcs, ucs4); }
188 void FcCharSetDestroy( FcCharSet* pSet )
189 { m_pFcCharSetDestroy( pSet );}
191 void FcFontSetDestroy( FcFontSet* pSet )
192 { m_pFcFontSetDestroy( pSet );}
194 FcBool FcFontSetAdd( FcFontSet* pSet, FcPattern* pPattern )
195 { return m_pFcFontSetAdd( pSet, pPattern ); }
197 void FcPatternReference( FcPattern* pPattern )
198 { m_pFcPatternReference( pPattern ); }
200 FcResult FcPatternGetCharSet( const FcPattern* pPattern, const char* object, int n, FcCharSet** s )
201 { return m_pFcPatternGetCharSet( pPattern, object, n, s ); }
203 FcResult FcPatternGetString( const FcPattern* pPattern, const char* object, int n, FcChar8** s )
204 { return m_pFcPatternGetString( pPattern, object, n, s ); }
206 FcResult FcPatternGetInteger( const FcPattern* pPattern, const char* object, int n, int* s )
207 { return m_pFcPatternGetInteger( pPattern, object, n, s ); }
209 FcResult FcPatternGetDouble( const FcPattern* pPattern, const char* object, int n, double* s )
210 { return m_pFcPatternGetDouble( pPattern, object, n, s ); }
212 FcResult FcPatternGetBool( const FcPattern* pPattern, const char* object, int n, FcBool* s )
213 { return m_pFcPatternGetBool( pPattern, object, n, s ); }
214 FcBool FcConfigAppFontAddFile( FcConfig* pConfig, const FcChar8* pFileName )
215 { return m_pFcConfigAppFontAddFile( pConfig, pFileName ); }
216 FcBool FcConfigAppFontAddDir(FcConfig* pConfig, const FcChar8* pDirName )
217 { return m_pFcConfigAppFontAddDir( pConfig, pDirName ); }
218 void FcDefaultSubstitute( FcPattern* pPattern )
219 { m_pFcDefaultSubstitute( pPattern ); }
220 FcPattern* FcFontSetMatch( FcConfig* pConfig, FcFontSet **ppFontSet, int nset, FcPattern* pPattern, FcResult* pResult )
221 { return m_pFcFontSetMatch ? m_pFcFontSetMatch( pConfig, ppFontSet, nset, pPattern, pResult ) : 0; }
222 FcBool FcConfigSubstitute( FcConfig* pConfig, FcPattern* pPattern, FcMatchKind eKind )
223 { return m_pFcConfigSubstitute( pConfig, pPattern, eKind ); }
224 FcBool FcPatternAddInteger( FcPattern* pPattern, const char* pObject, int nValue )
225 { return m_pFcPatternAddInteger( pPattern, pObject, nValue ); }
226 FcBool FcPatternAddString( FcPattern* pPattern, const char* pObject, const FcChar8* pString )
227 { return m_pFcPatternAddString( pPattern, pObject, pString ); }
228 FcBool FcPatternAddBool( FcPattern* pPattern, const char* pObject, bool nValue )
229 { return m_pFcPatternAddBool( pPattern, pObject, nValue ); }
230 FcBool FcPatternAddCharSet(FcPattern* pPattern,const char* pObject,const FcCharSet*pCharSet)
231 { return m_pFcPatternAddCharSet(pPattern,pObject,pCharSet); }
233 FT_UInt FcFreeTypeCharIndex( FT_Face face, FcChar32 ucs4 )
234 { return m_pFcFreeTypeCharIndex ? m_pFcFreeTypeCharIndex( face, ucs4 ) : 0; }
236 public: // TODO: cleanup
237 std::hash_map< rtl::OString, rtl::OString, rtl::OStringHash > m_aFontconfigNameToLocalized;
240 oslGenericFunction FontCfgWrapper::loadSymbol( const char* pSymbol )
242 OUString aSym( OUString::createFromAscii( pSymbol ) );
243 oslGenericFunction pSym = osl_getFunctionSymbol( m_pLib, aSym.pData );
244 #if OSL_DEBUG_LEVEL > 1
245 fprintf( stderr, "%s %s\n", pSymbol, pSym ? "found" : "not found" );
246 #endif
247 return pSym;
250 FontCfgWrapper::FontCfgWrapper()
251 : m_pLib( NULL ),
252 m_pOutlineSet( NULL ),
253 m_nFcVersion( 0 )
255 OUString aLib( RTL_CONSTASCII_USTRINGPARAM( "libfontconfig.so.1" ) );
256 m_pLib = osl_loadModule( aLib.pData, SAL_LOADMODULE_LAZY );
257 if( !m_pLib )
259 aLib = OUString( RTL_CONSTASCII_USTRINGPARAM( "libfontconfig.so" ) );
260 m_pLib = osl_loadModule( aLib.pData, SAL_LOADMODULE_LAZY );
263 if( ! m_pLib )
265 #if OSL_DEBUG_LEVEL > 1
266 fprintf( stderr, "no libfontconfig\n" );
267 #endif
268 return;
271 m_pFcInit = (FcBool(*)())
272 loadSymbol( "FcInit" );
273 m_pFcGetVersion = (int(*)())
274 loadSymbol( "FcGetVersion" );
275 m_pFcConfigGetCurrent = (FcConfig *(*)())
276 loadSymbol( "FcConfigGetCurrent" );
277 m_pFcObjectSetVaBuild = (FcObjectSet*(*)(const char*,va_list))
278 loadSymbol( "FcObjectSetVaBuild" );
279 m_pFcObjectSetDestroy = (void(*)(FcObjectSet*))
280 loadSymbol( "FcObjectSetDestroy" );
281 m_pFcPatternCreate = (FcPattern*(*)())
282 loadSymbol( "FcPatternCreate" );
283 m_pFcPatternDestroy = (void(*)(FcPattern*))
284 loadSymbol( "FcPatternDestroy" );
285 m_pFcFontList = (FcFontSet*(*)(FcConfig*,FcPattern*,FcObjectSet*))
286 loadSymbol( "FcFontList" );
287 m_pFcConfigGetFonts = (FcFontSet*(*)(FcConfig*,FcSetName))
288 loadSymbol( "FcConfigGetFonts" );
289 m_pFcFontSetCreate = (FcFontSet*(*)())
290 loadSymbol( "FcFontSetCreate" );
291 m_pFcCharSetCreate = (FcCharSet*(*)())
292 loadSymbol( "FcCharSetCreate" );
293 m_pFcCharSetAddChar = (FcBool(*)(FcCharSet*, FcChar32))
294 loadSymbol( "FcCharSetAddChar" );
295 m_pFcCharSetHasChar = (FcBool(*)(FcCharSet*, FcChar32))
296 loadSymbol( "FcCharSetHasChar" );
297 m_pFcCharSetDestroy = (void(*)(FcCharSet*))
298 loadSymbol( "FcCharSetDestroy" );
299 m_pFcFontSetDestroy = (void(*)(FcFontSet*))
300 loadSymbol( "FcFontSetDestroy" );
301 m_pFcFontSetAdd = (FcBool(*)(FcFontSet*,FcPattern*))
302 loadSymbol( "FcFontSetAdd" );
303 m_pFcPatternReference = (void(*)(FcPattern*))
304 loadSymbol( "FcPatternReference" );
305 m_pFcPatternGetCharSet = (FcResult(*)(const FcPattern*,const char*,int,FcCharSet**))
306 loadSymbol( "FcPatternGetCharSet" );
307 m_pFcPatternGetString = (FcResult(*)(const FcPattern*,const char*,int,FcChar8**))
308 loadSymbol( "FcPatternGetString" );
309 m_pFcPatternGetInteger = (FcResult(*)(const FcPattern*,const char*,int,int*))
310 loadSymbol( "FcPatternGetInteger" );
311 m_pFcPatternGetDouble = (FcResult(*)(const FcPattern*,const char*,int,double*))
312 loadSymbol( "FcPatternGetDouble" );
313 m_pFcPatternGetBool = (FcResult(*)(const FcPattern*,const char*,int,FcBool*))
314 loadSymbol( "FcPatternGetBool" );
315 m_pFcConfigAppFontAddFile = (FcBool(*)(FcConfig*, const FcChar8*))
316 loadSymbol( "FcConfigAppFontAddFile" );
317 m_pFcConfigAppFontAddDir = (FcBool(*)(FcConfig*, const FcChar8*))
318 loadSymbol( "FcConfigAppFontAddDir" );
319 m_pFcDefaultSubstitute = (void(*)(FcPattern *))
320 loadSymbol( "FcDefaultSubstitute" );
321 m_pFcFontSetMatch = (FcPattern*(*)(FcConfig*,FcFontSet**,int,FcPattern*,FcResult*))
322 loadSymbol( "FcFontSetMatch" );
323 m_pFcConfigSubstitute = (FcBool(*)(FcConfig*,FcPattern*,FcMatchKind))
324 loadSymbol( "FcConfigSubstitute" );
325 m_pFcPatternAddInteger = (FcBool(*)(FcPattern*,const char*,int))
326 loadSymbol( "FcPatternAddInteger" );
327 m_pFcPatternAddBool = (FcBool(*)(FcPattern*,const char*,FcBool))
328 loadSymbol( "FcPatternAddBool" );
329 m_pFcPatternAddCharSet = (FcBool(*)(FcPattern*,const char*,const FcCharSet *))
330 loadSymbol( "FcPatternAddCharSet" );
331 m_pFcPatternAddString = (FcBool(*)(FcPattern*,const char*,const FcChar8*))
332 loadSymbol( "FcPatternAddString" );
333 m_pFcFreeTypeCharIndex = (FT_UInt(*)(FT_Face,FcChar32))
334 loadSymbol( "FcFreeTypeCharIndex" );
336 m_nFcVersion = FcGetVersion();
337 #if (OSL_DEBUG_LEVEL > 1)
338 fprintf( stderr,"FC_VERSION = %05d\n", m_nFcVersion );
339 #endif
340 // make minimum version configurable
341 const char* pMinFcVersion = getenv( "SAL_MIN_FC_VERSION");
342 if( pMinFcVersion )
344 const int nMinFcVersion = atoi( pMinFcVersion );
345 if( m_nFcVersion < nMinFcVersion )
346 m_pFcInit = NULL;
349 if( ! (
350 m_pFcInit &&
351 m_pFcGetVersion &&
352 m_pFcConfigGetCurrent &&
353 m_pFcObjectSetVaBuild &&
354 m_pFcObjectSetDestroy &&
355 m_pFcPatternCreate &&
356 m_pFcPatternDestroy &&
357 m_pFcFontList &&
358 m_pFcConfigGetFonts &&
359 m_pFcFontSetCreate &&
360 m_pFcCharSetCreate &&
361 m_pFcCharSetAddChar &&
362 m_pFcCharSetHasChar &&
363 m_pFcCharSetDestroy &&
364 m_pFcFontSetDestroy &&
365 m_pFcFontSetAdd &&
366 m_pFcPatternReference &&
367 m_pFcPatternGetCharSet &&
368 m_pFcPatternGetString &&
369 m_pFcPatternGetInteger &&
370 m_pFcPatternGetDouble &&
371 m_pFcPatternGetBool &&
372 m_pFcConfigAppFontAddFile &&
373 m_pFcConfigAppFontAddDir &&
374 m_pFcDefaultSubstitute &&
375 m_pFcConfigSubstitute &&
376 m_pFcPatternAddInteger &&
377 m_pFcPatternAddCharSet &&
378 m_pFcPatternAddBool &&
379 m_pFcPatternAddString
382 osl_unloadModule( (oslModule)m_pLib );
383 m_pLib = NULL;
384 #if OSL_DEBUG_LEVEL > 1
385 fprintf( stderr, "not all needed symbols were found in libfontconfig\n" );
386 #endif
387 return;
391 FcInit();
392 if( ! FcConfigGetCurrent() )
394 osl_unloadModule( (oslModule)m_pLib );
395 m_pLib = NULL;
399 void FontCfgWrapper::addFontSet( FcSetName eSetName )
401 #ifdef ENABLE_FONTCONFIG
403 add only acceptable outlined fonts to our config,
404 for future fontconfig use
406 FcFontSet* pOrig = FcConfigGetFonts( FcConfigGetCurrent(), eSetName );
407 if( !pOrig )
408 return;
410 for( int i = 0; i < pOrig->nfont; ++i )
412 FcBool outline = false;
413 FcPattern *pOutlinePattern = pOrig->fonts[i];
414 FcResult eOutRes =
415 FcPatternGetBool( pOutlinePattern, FC_OUTLINE, 0, &outline );
416 if( (eOutRes != FcResultMatch) || (outline != FcTrue) )
417 continue;
418 FcPatternReference(pOutlinePattern);
419 FcFontSetAdd(m_pOutlineSet, pOutlinePattern);
421 // TODO: FcFontSetDestroy( pOrig );
422 #else
423 (void)eSetName; // prevent compiler warning about unused parameter
424 #endif
427 FcFontSet* FontCfgWrapper::getFontSet()
429 #ifdef ENABLE_FONTCONFIG
430 if( !m_pOutlineSet )
432 m_pOutlineSet = FcFontSetCreate();
433 addFontSet( FcSetSystem );
434 if( m_nFcVersion > 20400 ) // #i85462# prevent crashes
435 addFontSet( FcSetApplication );
437 #endif
439 return m_pOutlineSet;
442 FontCfgWrapper::~FontCfgWrapper()
444 if( m_pOutlineSet )
445 FcFontSetDestroy( m_pOutlineSet );
446 if( m_pLib )
447 osl_unloadModule( (oslModule)m_pLib );
450 static FontCfgWrapper* pOneInstance = NULL;
452 FontCfgWrapper& FontCfgWrapper::get()
454 if( ! pOneInstance )
455 pOneInstance = new FontCfgWrapper();
456 return *pOneInstance;
459 void FontCfgWrapper::release()
461 if( pOneInstance )
463 delete pOneInstance;
464 pOneInstance = NULL;
468 #ifdef ENABLE_FONTCONFIG
469 namespace
471 typedef std::pair<FcChar8*, FcChar8*> lang_and_family;
473 class localizedsorter
475 rtl::OLocale maLoc;
476 public:
477 localizedsorter(rtl_Locale* pLoc) : maLoc(pLoc) {}
478 FcChar8* bestname(const std::vector<lang_and_family> &families);
481 FcChar8* localizedsorter::bestname(const std::vector<lang_and_family> &families)
483 FcChar8* candidate = families.begin()->second;
484 rtl::OString sLangMatch(rtl::OUStringToOString(maLoc.getLanguage().toAsciiLowerCase(), RTL_TEXTENCODING_UTF8));
485 rtl::OString sFullMatch = sLangMatch;
486 sFullMatch += OString('-');
487 sFullMatch += rtl::OUStringToOString(maLoc.getCountry().toAsciiLowerCase(), RTL_TEXTENCODING_UTF8);
489 std::vector<lang_and_family>::const_iterator aEnd = families.end();
490 bool alreadyclosematch = false;
491 for (std::vector<lang_and_family>::const_iterator aIter = families.begin(); aIter != aEnd; ++aIter)
493 const char *pLang = (const char*)aIter->first;
494 //perfect
495 if( rtl_str_compare(pLang,sFullMatch.getStr() ) == 0)
497 candidate = aIter->second;
498 break;
500 else if( (rtl_str_compare(pLang,sLangMatch.getStr()) == 0) && (!alreadyclosematch))
502 candidate = aIter->second;
503 alreadyclosematch = true;
507 return candidate;
511 FcResult lcl_FamilyFromPattern(FontCfgWrapper& rWrapper, FcPattern* pPattern, FcChar8 **family,
512 std::hash_map< rtl::OString, rtl::OString, rtl::OStringHash > &aFontconfigNameToLocalized)
514 FcChar8 *origfamily;
515 FcResult eFamilyRes = rWrapper.FcPatternGetString( pPattern, FC_FAMILY, 0, &origfamily );
516 *family = origfamily;
518 if( eFamilyRes == FcResultMatch)
520 FcChar8* familylang = NULL;
521 if (rWrapper.FcPatternGetString( pPattern, FC_FAMILYLANG, 0, &familylang ) == FcResultMatch)
523 std::vector< lang_and_family > lang_and_families;
524 lang_and_families.push_back(lang_and_family(familylang, *family));
525 int k = 1;
526 while (1)
528 if (rWrapper.FcPatternGetString( pPattern, FC_FAMILYLANG, k, &familylang ) != FcResultMatch)
529 break;
530 if (rWrapper.FcPatternGetString( pPattern, FC_FAMILY, k, family ) != FcResultMatch)
531 break;
532 lang_and_families.push_back(lang_and_family(familylang, *family));
533 ++k;
536 //possible to-do, sort by UILocale instead of process locale
537 rtl_Locale* pLoc;
538 osl_getProcessLocale(&pLoc);
539 localizedsorter aSorter(pLoc);
540 *family = aSorter.bestname(lang_and_families);
542 std::vector<lang_and_family>::const_iterator aEnd = lang_and_families.end();
543 for (std::vector<lang_and_family>::const_iterator aIter = lang_and_families.begin(); aIter != aEnd; ++aIter)
545 const char *candidate = (const char*)(aIter->second);
546 if (rtl_str_compare(candidate, (const char*)(*family)) != 0)
547 aFontconfigNameToLocalized[OString(candidate)] = OString((const char*)(*family));
552 return eFamilyRes;
558 * PrintFontManager::initFontconfig
560 bool PrintFontManager::initFontconfig()
562 FontCfgWrapper& rWrapper = FontCfgWrapper::get();
563 if( ! rWrapper.isValid() )
564 return false;
565 return true;
568 int PrintFontManager::countFontconfigFonts()
570 int nFonts = 0;
572 FontCfgWrapper& rWrapper = FontCfgWrapper::get();
573 if( !rWrapper.isValid() )
574 return 0;
576 FcFontSet* pFSet = rWrapper.getFontSet();
577 if( pFSet )
579 #if OSL_DEBUG_LEVEL > 1
580 fprintf( stderr, "found %d entries in fontconfig fontset\n", pFSet->nfont );
581 #endif
582 for( int i = 0; i < pFSet->nfont; i++ )
584 FcChar8* file = NULL;
585 FcChar8* family = NULL;
586 FcChar8* style = NULL;
587 int slant = 0;
588 int weight = 0;
589 int spacing = 0;
590 int nCollectionEntry = -1;
591 FcBool outline = false, embitmap = true, antialias = true;
593 FcResult eFileRes = rWrapper.FcPatternGetString( pFSet->fonts[i], FC_FILE, 0, &file );
594 FcResult eFamilyRes = lcl_FamilyFromPattern(rWrapper, pFSet->fonts[i], &family, rWrapper.m_aFontconfigNameToLocalized );
595 FcResult eStyleRes = rWrapper.FcPatternGetString( pFSet->fonts[i], FC_STYLE, 0, &style );
596 FcResult eSlantRes = rWrapper.FcPatternGetInteger( pFSet->fonts[i], FC_SLANT, 0, &slant );
597 FcResult eWeightRes = rWrapper.FcPatternGetInteger( pFSet->fonts[i], FC_WEIGHT, 0, &weight );
598 FcResult eSpacRes = rWrapper.FcPatternGetInteger( pFSet->fonts[i], FC_SPACING, 0, &spacing );
599 FcResult eOutRes = rWrapper.FcPatternGetBool( pFSet->fonts[i], FC_OUTLINE, 0, &outline );
600 FcResult eIndexRes = rWrapper.FcPatternGetInteger( pFSet->fonts[i], FC_INDEX, 0, &nCollectionEntry );
601 FcResult eEmbeddedBitmap = rWrapper.FcPatternGetBool( pFSet->fonts[i], FC_EMBEDDED_BITMAP, 0, &embitmap );
602 FcResult eAntialias = rWrapper.FcPatternGetBool( pFSet->fonts[i], FC_ANTIALIAS, 0, &antialias );
604 if( eFileRes != FcResultMatch || eFamilyRes != FcResultMatch || eOutRes != FcResultMatch )
605 continue;
607 #if (OSL_DEBUG_LEVEL > 2)
608 fprintf( stderr, "found font \"%s\" in file %s\n"
609 " weight = %d, slant = %d, style = \"%s\"\n"
610 " spacing = %d, outline = %d\n"
611 , family, file
612 , eWeightRes == FcResultMatch ? weight : -1
613 , eSpacRes == FcResultMatch ? slant : -1
614 , eStyleRes == FcResultMatch ? (const char*) style : "<nil>"
615 , eSpacRes == FcResultMatch ? spacing : -1
616 , eOutRes == FcResultMatch ? outline : -1
618 #endif
620 OSL_ASSERT(eOutRes != FcResultMatch || outline);
622 // only outline fonts are usable to psprint anyway
623 if( eOutRes == FcResultMatch && ! outline )
624 continue;
626 // see if this font is already cached
627 // update attributes
628 std::list< PrintFont* > aFonts;
629 OString aDir, aBase, aOrgPath( (sal_Char*)file );
630 splitPath( aOrgPath, aDir, aBase );
631 int nDirID = getDirectoryAtom( aDir, true );
632 if( ! m_pFontCache->getFontCacheFile( nDirID, aBase, aFonts ) )
634 #if OSL_DEBUG_LEVEL > 2
635 fprintf( stderr, "file %s not cached\n", aBase.getStr() );
636 #endif
637 // not known, analyze font file to get attributes
638 // not described by fontconfig (e.g. alias names, PSName)
639 std::list< OString > aDummy;
640 analyzeFontFile( nDirID, aBase, aDummy, aFonts );
641 #if OSL_DEBUG_LEVEL > 1
642 if( aFonts.empty() )
643 fprintf( stderr, "Warning: file \"%s\" is unusable to psprint\n", aOrgPath.getStr() );
644 #endif
646 if( aFonts.empty() )
647 continue;
649 int nFamilyName = m_pAtoms->getAtom( ATOM_FAMILYNAME, OStringToOUString( OString( (sal_Char*)family ), RTL_TEXTENCODING_UTF8 ), sal_True );
650 PrintFont* pUpdate = aFonts.front();
651 std::list<PrintFont*>::const_iterator second_font = aFonts.begin();
652 ++second_font;
653 if( second_font != aFonts.end() ) // more than one font
655 // a collection entry, get the correct index
656 if( eIndexRes == FcResultMatch && nCollectionEntry != -1 )
658 for( std::list< PrintFont* >::iterator it = aFonts.begin(); it != aFonts.end(); ++it )
660 if( (*it)->m_eType == fonttype::TrueType &&
661 static_cast<TrueTypeFontFile*>(*it)->m_nCollectionEntry == nCollectionEntry )
663 pUpdate = *it;
664 break;
667 // update collection entry
668 // additional entries will be created in the cache
669 // if this is a new index (that is if the loop above
670 // ran to the end of the list)
671 if( pUpdate->m_eType == fonttype::TrueType ) // sanity check, this should always be the case here
672 static_cast<TrueTypeFontFile*>(pUpdate)->m_nCollectionEntry = nCollectionEntry;
674 else
676 #if OSL_DEBUG_LEVEL > 1
677 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 );
678 #endif
679 // we have found more than one font in this file
680 // but fontconfig will not tell us which index is meant
681 // -> something is in disorder, do not use this font
682 pUpdate = NULL;
686 if( pUpdate )
688 // set family name
689 if( pUpdate->m_nFamilyName != nFamilyName )
691 pUpdate->m_aAliases.remove( pUpdate->m_nFamilyName );
692 pUpdate->m_aAliases.push_back( pUpdate->m_nFamilyName );
693 pUpdate->m_aAliases.remove( nFamilyName );
694 pUpdate->m_nFamilyName = nFamilyName;
696 if( eWeightRes == FcResultMatch )
698 // set weight
699 if( weight <= FC_WEIGHT_THIN )
700 pUpdate->m_eWeight = weight::Thin;
701 else if( weight <= FC_WEIGHT_ULTRALIGHT )
702 pUpdate->m_eWeight = weight::UltraLight;
703 else if( weight <= FC_WEIGHT_LIGHT )
704 pUpdate->m_eWeight = weight::Light;
705 else if( weight <= FC_WEIGHT_BOOK )
706 pUpdate->m_eWeight = weight::SemiLight;
707 else if( weight <= FC_WEIGHT_NORMAL )
708 pUpdate->m_eWeight = weight::Normal;
709 else if( weight <= FC_WEIGHT_MEDIUM )
710 pUpdate->m_eWeight = weight::Medium;
711 else if( weight <= FC_WEIGHT_SEMIBOLD )
712 pUpdate->m_eWeight = weight::SemiBold;
713 else if( weight <= FC_WEIGHT_BOLD )
714 pUpdate->m_eWeight = weight::Bold;
715 else if( weight <= FC_WEIGHT_ULTRABOLD )
716 pUpdate->m_eWeight = weight::UltraBold;
717 else
718 pUpdate->m_eWeight = weight::Black;
720 if( eSpacRes == FcResultMatch )
722 // set pitch
723 if( spacing == FC_PROPORTIONAL )
724 pUpdate->m_ePitch = pitch::Variable;
725 else if( spacing == FC_MONO || spacing == FC_CHARCELL )
726 pUpdate->m_ePitch = pitch::Fixed;
728 if( eSlantRes == FcResultMatch )
730 // set italic
731 if( slant == FC_SLANT_ROMAN )
732 pUpdate->m_eItalic = italic::Upright;
733 else if( slant == FC_SLANT_ITALIC )
734 pUpdate->m_eItalic = italic::Italic;
735 else if( slant == FC_SLANT_OBLIQUE )
736 pUpdate->m_eItalic = italic::Oblique;
738 if( eStyleRes == FcResultMatch )
740 pUpdate->m_aStyleName = OStringToOUString( OString( (sal_Char*)style ), RTL_TEXTENCODING_UTF8 );
742 if( eEmbeddedBitmap == FcResultMatch )
744 pUpdate->m_eEmbeddedbitmap = embitmap ? fcstatus::istrue : fcstatus::isfalse;
746 if( eAntialias == FcResultMatch )
748 pUpdate->m_eAntialias = antialias ? fcstatus::istrue : fcstatus::isfalse;
752 // update font cache
753 m_pFontCache->updateFontCacheEntry( pUpdate, false );
754 // sort into known fonts
755 fontID aFont = m_nNextFontID++;
756 m_aFonts[ aFont ] = pUpdate;
757 m_aFontFileToFontID[ aBase ].insert( aFont );
758 nFonts++;
759 #if OSL_DEBUG_LEVEL > 2
760 fprintf( stderr, "inserted font %s as fontID %d\n", family, aFont );
761 #endif
763 // clean up the fonts we did not put into the list
764 for( std::list< PrintFont* >::iterator it = aFonts.begin(); it != aFonts.end(); ++it )
766 if( *it != pUpdate )
768 m_pFontCache->updateFontCacheEntry( *it, false ); // prepare a cache entry for a collection item
769 delete *it;
775 // how does one get rid of the config ?
776 #if OSL_DEBUG_LEVEL > 1
777 fprintf( stderr, "inserted %d fonts from fontconfig\n", nFonts );
778 #endif
779 return nFonts;
782 void PrintFontManager::deinitFontconfig()
784 FontCfgWrapper::release();
787 int PrintFontManager::FreeTypeCharIndex( void *pFace, sal_uInt32 aChar )
789 FontCfgWrapper& rWrapper = FontCfgWrapper::get();
790 return rWrapper.isValid() ? rWrapper.FcFreeTypeCharIndex( (FT_Face)pFace, aChar ) : 0;
793 bool PrintFontManager::addFontconfigDir( const rtl::OString& rDirName )
795 FontCfgWrapper& rWrapper = FontCfgWrapper::get();
796 if( ! rWrapper.isValid() )
797 return false;
799 // workaround for a stability problems in older FC versions
800 // when handling application specifc fonts
801 const int nVersion = rWrapper.FcGetVersion();
802 if( nVersion <= 20400 )
803 return false;
804 const char* pDirName = (const char*)rDirName.getStr();
805 bool bRet = (rWrapper.FcConfigAppFontAddDir( rWrapper.FcConfigGetCurrent(), (FcChar8*)pDirName ) == FcTrue);
807 #if OSL_DEBUG_LEVEL > 1
808 fprintf( stderr, "FcConfigAppFontAddDir( \"%s\") => %d\n", pDirName, bRet );
809 #endif
811 return bRet;
814 static void addtopattern(FontCfgWrapper& rWrapper, FcPattern *pPattern,
815 italic::type eItalic, weight::type eWeight, width::type eWidth, pitch::type ePitch)
817 if( eItalic != italic::Unknown )
819 int nSlant = FC_SLANT_ROMAN;
820 switch( eItalic )
822 case italic::Italic: nSlant = FC_SLANT_ITALIC;break;
823 case italic::Oblique: nSlant = FC_SLANT_OBLIQUE;break;
824 default:
825 break;
827 rWrapper.FcPatternAddInteger( pPattern, FC_SLANT, nSlant );
829 if( eWeight != weight::Unknown )
831 int nWeight = FC_WEIGHT_NORMAL;
832 switch( eWeight )
834 case weight::Thin: nWeight = FC_WEIGHT_THIN;break;
835 case weight::UltraLight: nWeight = FC_WEIGHT_ULTRALIGHT;break;
836 case weight::Light: nWeight = FC_WEIGHT_LIGHT;break;
837 case weight::SemiLight: nWeight = FC_WEIGHT_BOOK;break;
838 case weight::Normal: nWeight = FC_WEIGHT_NORMAL;break;
839 case weight::Medium: nWeight = FC_WEIGHT_MEDIUM;break;
840 case weight::SemiBold: nWeight = FC_WEIGHT_SEMIBOLD;break;
841 case weight::Bold: nWeight = FC_WEIGHT_BOLD;break;
842 case weight::UltraBold: nWeight = FC_WEIGHT_ULTRABOLD;break;
843 case weight::Black: nWeight = FC_WEIGHT_BLACK;break;
844 default:
845 break;
847 rWrapper.FcPatternAddInteger( pPattern, FC_WEIGHT, nWeight );
849 if( eWidth != width::Unknown )
851 int nWidth = FC_WIDTH_NORMAL;
852 switch( eWidth )
854 case width::UltraCondensed: nWidth = FC_WIDTH_ULTRACONDENSED;break;
855 case width::ExtraCondensed: nWidth = FC_WIDTH_EXTRACONDENSED;break;
856 case width::Condensed: nWidth = FC_WIDTH_CONDENSED;break;
857 case width::SemiCondensed: nWidth = FC_WIDTH_SEMICONDENSED;break;
858 case width::Normal: nWidth = FC_WIDTH_NORMAL;break;
859 case width::SemiExpanded: nWidth = FC_WIDTH_SEMIEXPANDED;break;
860 case width::Expanded: nWidth = FC_WIDTH_EXPANDED;break;
861 case width::ExtraExpanded: nWidth = FC_WIDTH_EXTRAEXPANDED;break;
862 case width::UltraExpanded: nWidth = FC_WIDTH_ULTRACONDENSED;break;
863 default:
864 break;
866 rWrapper.FcPatternAddInteger( pPattern, FC_WIDTH, nWidth );
868 if( ePitch != pitch::Unknown )
870 int nSpacing = FC_PROPORTIONAL;
871 switch( ePitch )
873 case pitch::Fixed: nSpacing = FC_MONO;break;
874 case pitch::Variable: nSpacing = FC_PROPORTIONAL;break;
875 default:
876 break;
878 rWrapper.FcPatternAddInteger( pPattern, FC_SPACING, nSpacing );
879 if (nSpacing == FC_MONO)
880 rWrapper.FcPatternAddString( pPattern, FC_FAMILY, (FcChar8*)"monospace");
884 rtl::OUString PrintFontManager::Substitute(const rtl::OUString& rFontName,
885 rtl::OUString& rMissingCodes, const rtl::OString &rLangAttrib,
886 italic::type eItalic, weight::type eWeight,
887 width::type eWidth, pitch::type ePitch) const
889 rtl::OUString aName;
890 FontCfgWrapper& rWrapper = FontCfgWrapper::get();
891 if( ! rWrapper.isValid() )
892 return aName;
894 // build pattern argument for fontconfig query
895 FcPattern* pPattern = rWrapper.FcPatternCreate();
897 // Prefer scalable fonts
898 rWrapper.FcPatternAddBool( pPattern, FC_SCALABLE, FcTrue );
900 const rtl::OString aTargetName = rtl::OUStringToOString( rFontName, RTL_TEXTENCODING_UTF8 );
901 const FcChar8* pTargetNameUtf8 = (FcChar8*)aTargetName.getStr();
902 rWrapper.FcPatternAddString( pPattern, FC_FAMILY, pTargetNameUtf8 );
904 const FcChar8* pLangAttribUtf8 = (FcChar8*)rLangAttrib.getStr();
905 if( rLangAttrib.getLength() )
906 rWrapper.FcPatternAddString( pPattern, FC_LANG, pLangAttribUtf8 );
908 // Add required Unicode characters, if any
909 if ( rMissingCodes.getLength() )
911 FcCharSet *unicodes = rWrapper.FcCharSetCreate();
912 for( sal_Int32 nStrIndex = 0; nStrIndex < rMissingCodes.getLength(); )
914 // also handle unicode surrogates
915 const sal_uInt32 nCode = rMissingCodes.iterateCodePoints( &nStrIndex );
916 rWrapper.FcCharSetAddChar( unicodes, nCode );
918 rWrapper.FcPatternAddCharSet( pPattern, FC_CHARSET, unicodes);
919 rWrapper.FcCharSetDestroy( unicodes );
922 addtopattern(rWrapper, pPattern, eItalic, eWeight, eWidth, ePitch);
924 // query fontconfig for a substitute
925 rWrapper.FcConfigSubstitute( rWrapper.FcConfigGetCurrent(), pPattern, FcMatchPattern );
926 rWrapper.FcDefaultSubstitute( pPattern );
928 // process the result of the fontconfig query
929 FcResult eResult = FcResultNoMatch;
930 FcFontSet* pFontSet = rWrapper.getFontSet();
931 FcPattern* pResult = rWrapper.FcFontSetMatch( rWrapper.FcConfigGetCurrent(), &pFontSet, 1, pPattern, &eResult );
932 rWrapper.FcPatternDestroy( pPattern );
934 FcFontSet* pSet = NULL;
935 if( pResult )
937 pSet = rWrapper.FcFontSetCreate();
938 // info: destroying the pSet destroys pResult implicitly
939 // since pResult was "added" to pSet
940 rWrapper.FcFontSetAdd( pSet, pResult );
943 if( pSet )
945 if( pSet->nfont > 0 )
947 //extract the closest match
948 FcChar8* family = NULL;
949 FcResult eFileRes = rWrapper.FcPatternGetString( pSet->fonts[0], FC_FAMILY, 0, &family );
951 // get the family name
952 if( eFileRes == FcResultMatch )
954 OString sFamily((sal_Char*)family);
955 std::hash_map< rtl::OString, rtl::OString, rtl::OStringHash >::const_iterator aI = rWrapper.m_aFontconfigNameToLocalized.find(sFamily);
956 if (aI != rWrapper.m_aFontconfigNameToLocalized.end())
957 sFamily = aI->second;
958 aName = rtl::OStringToOUString( sFamily, RTL_TEXTENCODING_UTF8 );
961 // update rMissingCodes by removing resolved unicodes
962 if( rMissingCodes.getLength() > 0 )
964 sal_uInt32* pRemainingCodes = (sal_uInt32*)alloca( rMissingCodes.getLength() * sizeof(sal_uInt32) );
965 int nRemainingLen = 0;
966 FcCharSet* unicodes;
967 if( !rWrapper.FcPatternGetCharSet( pSet->fonts[0], FC_CHARSET, 0, &unicodes ) )
969 for( sal_Int32 nStrIndex = 0; nStrIndex < rMissingCodes.getLength(); )
971 // also handle unicode surrogates
972 const sal_uInt32 nCode = rMissingCodes.iterateCodePoints( &nStrIndex );
973 if( rWrapper.FcCharSetHasChar( unicodes, nCode ) != FcTrue )
974 pRemainingCodes[ nRemainingLen++ ] = nCode;
977 rMissingCodes = OUString( pRemainingCodes, nRemainingLen );
981 rWrapper.FcFontSetDestroy( pSet );
984 return aName;
987 bool PrintFontManager::matchFont( FastPrintFontInfo& rInfo, const com::sun::star::lang::Locale& rLocale )
989 FontCfgWrapper& rWrapper = FontCfgWrapper::get();
990 if( ! rWrapper.isValid() )
991 return false;
993 FcConfig* pConfig = rWrapper.FcConfigGetCurrent();
994 FcPattern* pPattern = rWrapper.FcPatternCreate();
996 OString aLangAttrib;
997 // populate pattern with font characteristics
998 if( rLocale.Language.getLength() )
1000 OUStringBuffer aLang(6);
1001 aLang.append( rLocale.Language );
1002 if( rLocale.Country.getLength() )
1004 aLang.append( sal_Unicode('-') );
1005 aLang.append( rLocale.Country );
1007 aLangAttrib = OUStringToOString( aLang.makeStringAndClear(), RTL_TEXTENCODING_UTF8 );
1009 if( aLangAttrib.getLength() )
1010 rWrapper.FcPatternAddString( pPattern, FC_LANG, (FcChar8*)aLangAttrib.getStr() );
1012 OString aFamily = OUStringToOString( rInfo.m_aFamilyName, RTL_TEXTENCODING_UTF8 );
1013 if( aFamily.getLength() )
1014 rWrapper.FcPatternAddString( pPattern, FC_FAMILY, (FcChar8*)aFamily.getStr() );
1016 addtopattern(rWrapper, pPattern, rInfo.m_eItalic, rInfo.m_eWeight, rInfo.m_eWidth, rInfo.m_ePitch);
1018 rWrapper.FcConfigSubstitute( pConfig, pPattern, FcMatchPattern );
1019 rWrapper.FcDefaultSubstitute( pPattern );
1020 FcResult eResult = FcResultNoMatch;
1021 FcFontSet *pFontSet = rWrapper.getFontSet();
1022 FcPattern* pResult = rWrapper.FcFontSetMatch( pConfig, &pFontSet, 1, pPattern, &eResult );
1023 bool bSuccess = false;
1024 if( pResult )
1026 FcFontSet* pSet = rWrapper.FcFontSetCreate();
1027 rWrapper.FcFontSetAdd( pSet, pResult );
1028 if( pSet->nfont > 0 )
1030 //extract the closest match
1031 FcChar8* file = NULL;
1032 FcResult eFileRes = rWrapper.FcPatternGetString( pSet->fonts[0], FC_FILE, 0, &file );
1033 if( eFileRes == FcResultMatch )
1035 OString aDir, aBase, aOrgPath( (sal_Char*)file );
1036 splitPath( aOrgPath, aDir, aBase );
1037 int nDirID = getDirectoryAtom( aDir, true );
1038 fontID aFont = findFontFileID( nDirID, aBase );
1039 if( aFont > 0 )
1040 bSuccess = getFontFastInfo( aFont, rInfo );
1043 // info: destroying the pSet destroys pResult implicitly
1044 // since pResult was "added" to pSet
1045 rWrapper.FcFontSetDestroy( pSet );
1048 // cleanup
1049 rWrapper.FcPatternDestroy( pPattern );
1051 return bSuccess;
1054 #else // ENABLE_FONTCONFIG not defined
1056 bool PrintFontManager::initFontconfig()
1058 return false;
1061 int PrintFontManager::countFontconfigFonts()
1063 return 0;
1066 void PrintFontManager::deinitFontconfig()
1069 bool PrintFontManager::addFontconfigDir( const rtl::OString& )
1071 return false;
1074 bool PrintFontManager::matchFont( FastPrintFontInfo&, const com::sun::star::lang::Locale& )
1076 return false;
1079 int PrintFontManager::FreeTypeCharIndex( void*, sal_uInt32 )
1081 return 0;
1084 rtl::OUString PrintFontManager::Substitute( const rtl::OUString&,
1085 rtl::OUString&, const rtl::OString&, italic::type, weight::type, width::type, pitch::type) const
1087 rtl::OUString aName;
1088 return aName;
1091 #endif // ENABLE_FONTCONFIG