1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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"
39 #ifdef ENABLE_FONTCONFIG
40 #include <fontconfig/fontconfig.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
47 #ifndef FC_EMBEDDED_BITMAP
48 #define FC_EMBEDDED_BITMAP "embeddedbitmap"
51 #define FC_FAMILYLANG "familylang"
54 typedef void FcConfig
;
55 typedef void FcObjectSet
;
56 typedef void FcPattern
;
57 typedef void FcFontSet
;
58 typedef void FcCharSet
;
61 typedef int FcMatchKind
;
64 typedef unsigned int FT_UInt
;
65 typedef void* FT_Face
;
66 typedef int FcSetName
;
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"
92 FcFontSet
* m_pOutlineSet
;
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
);
135 static FontCfgWrapper
& get();
136 static void release();
139 { return m_pLib
!= NULL
;}
141 FcFontSet
* getFontSet();
144 { return m_pFcInit(); }
147 { return m_pFcGetVersion(); }
149 FcConfig
* FcConfigGetCurrent()
150 { return m_pFcConfigGetCurrent(); }
152 FcObjectSet
* FcObjectSetBuild( const char* first
, ... )
155 va_start( ap
, first
);
156 FcObjectSet
* pSet
= m_pFcObjectSetVaBuild( first
, ap
);
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" );
250 FontCfgWrapper::FontCfgWrapper()
252 m_pOutlineSet( NULL
),
255 OUString
aLib( RTL_CONSTASCII_USTRINGPARAM( "libfontconfig.so.1" ) );
256 m_pLib
= osl_loadModule( aLib
.pData
, SAL_LOADMODULE_LAZY
);
259 aLib
= OUString( RTL_CONSTASCII_USTRINGPARAM( "libfontconfig.so" ) );
260 m_pLib
= osl_loadModule( aLib
.pData
, SAL_LOADMODULE_LAZY
);
265 #if OSL_DEBUG_LEVEL > 1
266 fprintf( stderr
, "no libfontconfig\n" );
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
);
340 // make minimum version configurable
341 const char* pMinFcVersion
= getenv( "SAL_MIN_FC_VERSION");
344 const int nMinFcVersion
= atoi( pMinFcVersion
);
345 if( m_nFcVersion
< nMinFcVersion
)
352 m_pFcConfigGetCurrent
&&
353 m_pFcObjectSetVaBuild
&&
354 m_pFcObjectSetDestroy
&&
355 m_pFcPatternCreate
&&
356 m_pFcPatternDestroy
&&
358 m_pFcConfigGetFonts
&&
359 m_pFcFontSetCreate
&&
360 m_pFcCharSetCreate
&&
361 m_pFcCharSetAddChar
&&
362 m_pFcCharSetHasChar
&&
363 m_pFcCharSetDestroy
&&
364 m_pFcFontSetDestroy
&&
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
);
384 #if OSL_DEBUG_LEVEL > 1
385 fprintf( stderr
, "not all needed symbols were found in libfontconfig\n" );
392 if( ! FcConfigGetCurrent() )
394 osl_unloadModule( (oslModule
)m_pLib
);
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
);
410 for( int i
= 0; i
< pOrig
->nfont
; ++i
)
412 FcBool outline
= false;
413 FcPattern
*pOutlinePattern
= pOrig
->fonts
[i
];
415 FcPatternGetBool( pOutlinePattern
, FC_OUTLINE
, 0, &outline
);
416 if( (eOutRes
!= FcResultMatch
) || (outline
!= FcTrue
) )
418 FcPatternReference(pOutlinePattern
);
419 FcFontSetAdd(m_pOutlineSet
, pOutlinePattern
);
421 // TODO: FcFontSetDestroy( pOrig );
423 (void)eSetName
; // prevent compiler warning about unused parameter
427 FcFontSet
* FontCfgWrapper::getFontSet()
429 #ifdef ENABLE_FONTCONFIG
432 m_pOutlineSet
= FcFontSetCreate();
433 addFontSet( FcSetSystem
);
434 if( m_nFcVersion
> 20400 ) // #i85462# prevent crashes
435 addFontSet( FcSetApplication
);
439 return m_pOutlineSet
;
442 FontCfgWrapper::~FontCfgWrapper()
445 FcFontSetDestroy( m_pOutlineSet
);
447 osl_unloadModule( (oslModule
)m_pLib
);
450 static FontCfgWrapper
* pOneInstance
= NULL
;
452 FontCfgWrapper
& FontCfgWrapper::get()
455 pOneInstance
= new FontCfgWrapper();
456 return *pOneInstance
;
459 void FontCfgWrapper::release()
468 #ifdef ENABLE_FONTCONFIG
471 typedef std::pair
<FcChar8
*, FcChar8
*> lang_and_family
;
473 class localizedsorter
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
;
495 if( rtl_str_compare(pLang
,sFullMatch
.getStr() ) == 0)
497 candidate
= aIter
->second
;
500 else if( (rtl_str_compare(pLang
,sLangMatch
.getStr()) == 0) && (!alreadyclosematch
))
502 candidate
= aIter
->second
;
503 alreadyclosematch
= true;
511 FcResult
lcl_FamilyFromPattern(FontCfgWrapper
& rWrapper
, FcPattern
* pPattern
, FcChar8
**family
,
512 std::hash_map
< rtl::OString
, rtl::OString
, rtl::OStringHash
> &aFontconfigNameToLocalized
)
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
));
528 if (rWrapper
.FcPatternGetString( pPattern
, FC_FAMILYLANG
, k
, &familylang
) != FcResultMatch
)
530 if (rWrapper
.FcPatternGetString( pPattern
, FC_FAMILY
, k
, family
) != FcResultMatch
)
532 lang_and_families
.push_back(lang_and_family(familylang
, *family
));
536 //possible to-do, sort by UILocale instead of process locale
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
));
558 * PrintFontManager::initFontconfig
560 bool PrintFontManager::initFontconfig()
562 FontCfgWrapper
& rWrapper
= FontCfgWrapper::get();
563 if( ! rWrapper
.isValid() )
568 int PrintFontManager::countFontconfigFonts()
572 FontCfgWrapper
& rWrapper
= FontCfgWrapper::get();
573 if( !rWrapper
.isValid() )
576 FcFontSet
* pFSet
= rWrapper
.getFontSet();
579 #if OSL_DEBUG_LEVEL > 1
580 fprintf( stderr
, "found %d entries in fontconfig fontset\n", pFSet
->nfont
);
582 for( int i
= 0; i
< pFSet
->nfont
; i
++ )
584 FcChar8
* file
= NULL
;
585 FcChar8
* family
= NULL
;
586 FcChar8
* style
= NULL
;
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
)
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"
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
620 OSL_ASSERT(eOutRes
!= FcResultMatch
|| outline
);
622 // only outline fonts are usable to psprint anyway
623 if( eOutRes
== FcResultMatch
&& ! outline
)
626 // see if this font is already cached
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() );
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
643 fprintf( stderr
, "Warning: file \"%s\" is unusable to psprint\n", aOrgPath
.getStr() );
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();
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
)
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
;
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
);
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
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
)
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
;
718 pUpdate
->m_eWeight
= weight::Black
;
720 if( eSpacRes
== FcResultMatch
)
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
)
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
;
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
);
759 #if OSL_DEBUG_LEVEL > 2
760 fprintf( stderr
, "inserted font %s as fontID %d\n", family
, aFont
);
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
)
768 m_pFontCache
->updateFontCacheEntry( *it
, false ); // prepare a cache entry for a collection item
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
);
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() )
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 )
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
);
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
;
822 case italic::Italic
: nSlant
= FC_SLANT_ITALIC
;break;
823 case italic::Oblique
: nSlant
= FC_SLANT_OBLIQUE
;break;
827 rWrapper
.FcPatternAddInteger( pPattern
, FC_SLANT
, nSlant
);
829 if( eWeight
!= weight::Unknown
)
831 int nWeight
= FC_WEIGHT_NORMAL
;
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;
847 rWrapper
.FcPatternAddInteger( pPattern
, FC_WEIGHT
, nWeight
);
849 if( eWidth
!= width::Unknown
)
851 int nWidth
= FC_WIDTH_NORMAL
;
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;
866 rWrapper
.FcPatternAddInteger( pPattern
, FC_WIDTH
, nWidth
);
868 if( ePitch
!= pitch::Unknown
)
870 int nSpacing
= FC_PROPORTIONAL
;
873 case pitch::Fixed
: nSpacing
= FC_MONO
;break;
874 case pitch::Variable
: nSpacing
= FC_PROPORTIONAL
;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
890 FontCfgWrapper
& rWrapper
= FontCfgWrapper::get();
891 if( ! rWrapper
.isValid() )
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
;
937 pSet
= rWrapper
.FcFontSetCreate();
938 // info: destroying the pSet destroys pResult implicitly
939 // since pResult was "added" to pSet
940 rWrapper
.FcFontSetAdd( pSet
, pResult
);
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;
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
);
987 bool PrintFontManager::matchFont( FastPrintFontInfo
& rInfo
, const com::sun::star::lang::Locale
& rLocale
)
989 FontCfgWrapper
& rWrapper
= FontCfgWrapper::get();
990 if( ! rWrapper
.isValid() )
993 FcConfig
* pConfig
= rWrapper
.FcConfigGetCurrent();
994 FcPattern
* pPattern
= rWrapper
.FcPatternCreate();
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;
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
);
1040 bSuccess
= getFontFastInfo( aFont
, rInfo
);
1043 // info: destroying the pSet destroys pResult implicitly
1044 // since pResult was "added" to pSet
1045 rWrapper
.FcFontSetDestroy( pSet
);
1049 rWrapper
.FcPatternDestroy( pPattern
);
1054 #else // ENABLE_FONTCONFIG not defined
1056 bool PrintFontManager::initFontconfig()
1061 int PrintFontManager::countFontconfigFonts()
1066 void PrintFontManager::deinitFontconfig()
1069 bool PrintFontManager::addFontconfigDir( const rtl::OString
& )
1074 bool PrintFontManager::matchFont( FastPrintFontInfo
&, const com::sun::star::lang::Locale
& )
1079 int PrintFontManager::FreeTypeCharIndex( void*, sal_uInt32
)
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
;
1091 #endif // ENABLE_FONTCONFIG