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