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 FcPatternAddBool( pTestPattern, FC_OUTLINE, FcTrue );
460 // TODO: ignore all attributes that are not interesting for finding dupes
461 // e.g. by using pattern->ImplFontAttr->pattern conversion
462 FcPatternDel( pTestPattern, FC_FONTVERSION );
463 FcPatternDel( pTestPattern, FC_CHARSET );
464 FcPatternDel( pTestPattern, FC_FILE );
465 // find the font face for the dupe-search pattern
466 FcResult eFcResult = FcResultMatch;
467 pBetterPattern = FcFontMatch( FcConfigGetCurrent(), pTestPattern, &eFcResult );
468 FcPatternDestroy( pTestPattern );
469 if( eFcResult != FcResultMatch )
470 continue;
471 // #i115131# double check results and eventually ignore them
472 eOutRes = FcPatternGetBool( pBetterPattern, FC_OUTLINE, 0, &bOutline );
473 if( (eOutRes != FcResultMatch) || (bOutline == FcFalse) )
474 continue;
475 }
476 // insert best found pattern for the dupe-search pattern
477 // TODO: skip inserting patterns that are already known in the target fontset
478 FcPatternReference( pBetterPattern );
479 FcFontSetAdd( m_pOutlineSet, pBetterPattern );
480 }
481
482 // TODO?: FcFontSetDestroy( pOrig );
483 #else
484 (void)eSetName; // prevent compiler warning about unused parameter
485 #endif
486 }
487
getFontSet()488 FcFontSet* FontCfgWrapper::getFontSet()
489 {
490 #ifdef ENABLE_FONTCONFIG
491 if( !m_pOutlineSet )
492 {
493 m_pOutlineSet = FcFontSetCreate();
494 addFontSet( FcSetSystem );
495 if( m_nFcVersion > 20400 ) // #i85462# prevent crashes
496 addFontSet( FcSetApplication );
497 }
498 #endif
499
500 return m_pOutlineSet;
501 }
502
~FontCfgWrapper()503 FontCfgWrapper::~FontCfgWrapper()
504 {
505 if( m_pOutlineSet )
506 FcFontSetDestroy( m_pOutlineSet );
507 if( m_pLib )
508 osl_unloadModule( (oslModule)m_pLib );
509 }
510
511 static FontCfgWrapper* pOneInstance = NULL;
512
get()513 FontCfgWrapper& FontCfgWrapper::get()
514 {
515 if( ! pOneInstance )
516 pOneInstance = new FontCfgWrapper();
517 return *pOneInstance;
518 }
519
release()520 void FontCfgWrapper::release()
521 {
522 if( pOneInstance )
523 {
524 delete pOneInstance;
525 pOneInstance = NULL;
526 }
527 }
528
529 #ifdef ENABLE_FONTCONFIG
530 namespace
531 {
532 typedef std::pair<FcChar8*, FcChar8*> lang_and_family;
533
534 class localizedsorter
535 {
536 rtl::OLocale maLoc;
537 public:
localizedsorter(rtl_Locale * pLoc)538 localizedsorter(rtl_Locale* pLoc) : maLoc(pLoc) {}
539 FcChar8* bestname(const std::vector<lang_and_family> &families);
540 };
541
bestname(const std::vector<lang_and_family> & families)542 FcChar8* localizedsorter::bestname(const std::vector<lang_and_family> &families)
543 {
544 FcChar8* candidate = families.begin()->second;
545 rtl::OString sLangMatch(rtl::OUStringToOString(maLoc.getLanguage().toAsciiLowerCase(), RTL_TEXTENCODING_UTF8));
546 rtl::OString sFullMatch = sLangMatch;
547 sFullMatch += OString('-');
548 sFullMatch += rtl::OUStringToOString(maLoc.getCountry().toAsciiLowerCase(), RTL_TEXTENCODING_UTF8);
549
550 std::vector<lang_and_family>::const_iterator aEnd = families.end();
551 bool alreadyclosematch = false;
552 for( std::vector<lang_and_family>::const_iterator aIter = families.begin(); aIter != aEnd; ++aIter )
553 {
554 const char *pLang = (const char*)aIter->first;
555 if( rtl_str_compare( pLang, sFullMatch.getStr() ) == 0)
556 {
557 // both language and country match
558 candidate = aIter->second;
559 break;
560 }
561 else if( alreadyclosematch )
562 continue;
563 else if( rtl_str_compare( pLang, sLangMatch.getStr()) == 0)
564 {
565 // just the language matches
566 candidate = aIter->second;
567 alreadyclosematch = true;
568 }
569 else if( rtl_str_compare( pLang, "en") == 0)
570 {
571 // fallback to the english family name
572 candidate = aIter->second;
573 }
574 }
575 return candidate;
576 }
577 }
578
FamilyFromPattern(FcPattern * pPattern,FcChar8 ** family)579 FcResult FontCfgWrapper::FamilyFromPattern(FcPattern* pPattern, FcChar8 **family)
580 {
581 FcChar8 *origfamily;
582 FcResult eFamilyRes = FcPatternGetString( pPattern, FC_FAMILY, 0, &origfamily );
583 *family = origfamily;
584
585 if( eFamilyRes == FcResultMatch)
586 {
587 FcChar8* familylang = NULL;
588 if (FcPatternGetString( pPattern, FC_FAMILYLANG, 0, &familylang ) == FcResultMatch)
589 {
590 std::vector< lang_and_family > lang_and_families;
591 lang_and_families.push_back(lang_and_family(familylang, *family));
592 int k = 1;
593 while (1)
594 {
595 if (FcPatternGetString( pPattern, FC_FAMILYLANG, k, &familylang ) != FcResultMatch)
596 break;
597 if (FcPatternGetString( pPattern, FC_FAMILY, k, family ) != FcResultMatch)
598 break;
599 lang_and_families.push_back(lang_and_family(familylang, *family));
600 ++k;
601 }
602
603 //possible to-do, sort by UILocale instead of process locale
604 rtl_Locale* pLoc;
605 osl_getProcessLocale(&pLoc);
606 localizedsorter aSorter(pLoc);
607 *family = aSorter.bestname(lang_and_families);
608
609 std::vector<lang_and_family>::const_iterator aEnd = lang_and_families.end();
610 for (std::vector<lang_and_family>::const_iterator aIter = lang_and_families.begin(); aIter != aEnd; ++aIter)
611 {
612 const char *candidate = (const char*)(aIter->second);
613 if (rtl_str_compare(candidate, (const char*)(*family)) != 0)
614 m_aFontNameToLocalized[OString(candidate)] = OString((const char*)(*family));
615 }
616 if (rtl_str_compare((const char*)origfamily, (const char*)(*family)) != 0)
617 m_aLocalizedToCanonical[OString((const char*)(*family))] = OString((const char*)origfamily);
618 }
619 }
620
621 return eFamilyRes;
622 }
623
624 /*
625 * PrintFontManager::initFontconfig
626 */
initFontconfig()627 bool PrintFontManager::initFontconfig()
628 {
629 FontCfgWrapper& rWrapper = FontCfgWrapper::get();
630 if( ! rWrapper.isValid() )
631 return false;
632 return true;
633 }
634
635 namespace
636 {
convertWeight(int weight)637 weight::type convertWeight(int weight)
638 {
639 // set weight
640 if( weight <= FC_WEIGHT_THIN )
641 return weight::Thin;
642 else if( weight <= FC_WEIGHT_ULTRALIGHT )
643 return weight::UltraLight;
644 else if( weight <= FC_WEIGHT_LIGHT )
645 return weight::Light;
646 else if( weight <= FC_WEIGHT_BOOK )
647 return weight::SemiLight;
648 else if( weight <= FC_WEIGHT_NORMAL )
649 return weight::Normal;
650 else if( weight <= FC_WEIGHT_MEDIUM )
651 return weight::Medium;
652 else if( weight <= FC_WEIGHT_SEMIBOLD )
653 return weight::SemiBold;
654 else if( weight <= FC_WEIGHT_BOLD )
655 return weight::Bold;
656 else if( weight <= FC_WEIGHT_ULTRABOLD )
657 return weight::UltraBold;
658 return weight::Black;
659 }
660
convertSlant(int slant)661 italic::type convertSlant(int slant)
662 {
663 // set italic
664 if( slant == FC_SLANT_ITALIC )
665 return italic::Italic;
666 else if( slant == FC_SLANT_OBLIQUE )
667 return italic::Oblique;
668 return italic::Upright;
669 }
670
convertSpacing(int spacing)671 pitch::type convertSpacing(int spacing)
672 {
673 // set pitch
674 if( spacing == FC_MONO || spacing == FC_CHARCELL )
675 return pitch::Fixed;
676 return pitch::Variable;
677 }
678
convertWidth(int width)679 width::type convertWidth(int width)
680 {
681 if (width == FC_WIDTH_ULTRACONDENSED)
682 return width::UltraCondensed;
683 else if (width == FC_WIDTH_EXTRACONDENSED)
684 return width::ExtraCondensed;
685 else if (width == FC_WIDTH_CONDENSED)
686 return width::Condensed;
687 else if (width == FC_WIDTH_SEMICONDENSED)
688 return width::SemiCondensed;
689 else if (width == FC_WIDTH_SEMIEXPANDED)
690 return width::SemiExpanded;
691 else if (width == FC_WIDTH_EXPANDED)
692 return width::Expanded;
693 else if (width == FC_WIDTH_EXTRAEXPANDED)
694 return width::ExtraExpanded;
695 else if (width == FC_WIDTH_ULTRAEXPANDED)
696 return width::UltraExpanded;
697 return width::Normal;
698 }
699 }
700
countFontconfigFonts(std::hash_map<rtl::OString,int,rtl::OStringHash> & o_rVisitedPaths)701 int PrintFontManager::countFontconfigFonts( std::hash_map<rtl::OString, int, rtl::OStringHash>& o_rVisitedPaths )
702 {
703 int nFonts = 0;
704
705 FontCfgWrapper& rWrapper = FontCfgWrapper::get();
706 if( !rWrapper.isValid() )
707 return 0;
708
709 FcFontSet* pFSet = rWrapper.getFontSet();
710 if( pFSet )
711 {
712 #if OSL_DEBUG_LEVEL > 1
713 fprintf( stderr, "found %d entries in fontconfig fontset\n", pFSet->nfont );
714 #endif
715 for( int i = 0; i < pFSet->nfont; i++ )
716 {
717 FcChar8* file = NULL;
718 FcChar8* family = NULL;
719 FcChar8* style = NULL;
720 int slant = 0;
721 int weight = 0;
722 int spacing = 0;
723 int nCollectionEntry = -1;
724 FcBool outline = false;
725
726 FcResult eFileRes = rWrapper.FcPatternGetString( pFSet->fonts[i], FC_FILE, 0, &file );
727 FcResult eFamilyRes = rWrapper.FamilyFromPattern( pFSet->fonts[i], &family );
728 FcResult eStyleRes = rWrapper.FcPatternGetString( pFSet->fonts[i], FC_STYLE, 0, &style );
729 FcResult eSlantRes = rWrapper.FcPatternGetInteger( pFSet->fonts[i], FC_SLANT, 0, &slant );
730 FcResult eWeightRes = rWrapper.FcPatternGetInteger( pFSet->fonts[i], FC_WEIGHT, 0, &weight );
731 FcResult eSpacRes = rWrapper.FcPatternGetInteger( pFSet->fonts[i], FC_SPACING, 0, &spacing );
732 FcResult eOutRes = rWrapper.FcPatternGetBool( pFSet->fonts[i], FC_OUTLINE, 0, &outline );
733 FcResult eIndexRes = rWrapper.FcPatternGetInteger( pFSet->fonts[i], FC_INDEX, 0, &nCollectionEntry );
734
735 if( eFileRes != FcResultMatch || eFamilyRes != FcResultMatch || eOutRes != FcResultMatch )
736 continue;
737
738 #if (OSL_DEBUG_LEVEL > 2)
739 fprintf( stderr, "found font \"%s\" in file %s\n"
740 " weight = %d, slant = %d, style = \"%s\"\n"
741 " spacing = %d, outline = %d\n"
742 , family, file
743 , eWeightRes == FcResultMatch ? weight : -1
744 , eSpacRes == FcResultMatch ? slant : -1
745 , eStyleRes == FcResultMatch ? (const char*) style : "<nil>"
746 , eSpacRes == FcResultMatch ? spacing : -1
747 , eOutRes == FcResultMatch ? outline : -1
748 );
749 #endif
750
751 // OSL_ASSERT(eOutRes != FcResultMatch || outline);
752
753 // only outline fonts are usable to psprint anyway
754 if( eOutRes == FcResultMatch && ! outline )
755 continue;
756
757 // see if this font is already cached
758 // update attributes
759 std::list< PrintFont* > aFonts;
760 OString aDir, aBase, aOrgPath( (sal_Char*)file );
761 splitPath( aOrgPath, aDir, aBase );
762
763 o_rVisitedPaths[aDir] = 1;
764
765 int nDirID = getDirectoryAtom( aDir, true );
766 if( ! m_pFontCache->getFontCacheFile( nDirID, aBase, aFonts ) )
767 {
768 #if OSL_DEBUG_LEVEL > 2
769 fprintf( stderr, "file %s not cached\n", aBase.getStr() );
770 #endif
771 // not known, analyze font file to get attributes
772 // not described by fontconfig (e.g. alias names, PSName)
773 std::list< OString > aDummy;
774 analyzeFontFile( nDirID, aBase, aDummy, aFonts );
775 #if OSL_DEBUG_LEVEL > 1
776 if( aFonts.empty() )
777 fprintf( stderr, "Warning: file \"%s\" is unusable to psprint\n", aOrgPath.getStr() );
778 #endif
779 }
780 if( aFonts.empty() )
781 {
782 // TODO: remove fonts unusable to psprint from fontset
783 continue;
784 }
785
786 int nFamilyName = m_pAtoms->getAtom( ATOM_FAMILYNAME, OStringToOUString( OString( (sal_Char*)family ), RTL_TEXTENCODING_UTF8 ), sal_True );
787 PrintFont* pUpdate = aFonts.front();
788 std::list<PrintFont*>::const_iterator second_font = aFonts.begin();
789 ++second_font;
790 if( second_font != aFonts.end() ) // more than one font
791 {
792 // a collection entry, get the correct index
793 if( eIndexRes == FcResultMatch && nCollectionEntry != -1 )
794 {
795 for( std::list< PrintFont* >::iterator it = aFonts.begin(); it != aFonts.end(); ++it )
796 {
797 if( (*it)->m_eType == fonttype::TrueType &&
798 static_cast<TrueTypeFontFile*>(*it)->m_nCollectionEntry == nCollectionEntry )
799 {
800 pUpdate = *it;
801 break;
802 }
803 }
804 // update collection entry
805 // additional entries will be created in the cache
806 // if this is a new index (that is if the loop above
807 // ran to the end of the list)
808 if( pUpdate->m_eType == fonttype::TrueType ) // sanity check, this should always be the case here
809 static_cast<TrueTypeFontFile*>(pUpdate)->m_nCollectionEntry = nCollectionEntry;
810 }
811 else
812 {
813 #if OSL_DEBUG_LEVEL > 1
814 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 );
815 #endif
816 // we have found more than one font in this file
817 // but fontconfig will not tell us which index is meant
818 // -> something is in disorder, do not use this font
819 pUpdate = NULL;
820 }
821 }
822
823 if( pUpdate )
824 {
825 // set family name
826 if( pUpdate->m_nFamilyName != nFamilyName )
827 {
828 #if 0 // fontconfig prefers nameid=16 for the family name which is all fine
829 // but Writer suffers from #i79878#
830 // the only reasonable workaround for now is to use the classic nameid=1
831 pUpdate->m_aAliases.remove( pUpdate->m_nFamilyName );
832 pUpdate->m_aAliases.push_back( pUpdate->m_nFamilyName );
833 pUpdate->m_aAliases.remove( nFamilyName );
834 pUpdate->m_nFamilyName = nFamilyName;
835 #endif
836 }
837 if( eWeightRes == FcResultMatch )
838 pUpdate->m_eWeight = convertWeight(weight);
839 if( eSpacRes == FcResultMatch )
840 pUpdate->m_ePitch = convertSpacing(spacing);
841 if( eSlantRes == FcResultMatch )
842 pUpdate->m_eItalic = convertSlant(slant);
843 if( eStyleRes == FcResultMatch )
844 {
845 pUpdate->m_aStyleName = OStringToOUString( OString( (sal_Char*)style ), RTL_TEXTENCODING_UTF8 );
846 }
847
848 // update font cache
849 m_pFontCache->updateFontCacheEntry( pUpdate, false );
850 // sort into known fonts
851 fontID aFont = m_nNextFontID++;
852 m_aFonts[ aFont ] = pUpdate;
853 m_aFontFileToFontID[ aBase ].insert( aFont );
854 nFonts++;
855 #if OSL_DEBUG_LEVEL > 2
856 fprintf( stderr, "inserted font %s as fontID %d\n", family, aFont );
857 #endif
858 }
859 // clean up the fonts we did not put into the list
860 for( std::list< PrintFont* >::iterator it = aFonts.begin(); it != aFonts.end(); ++it )
861 {
862 if( *it != pUpdate )
863 {
864 m_pFontCache->updateFontCacheEntry( *it, false ); // prepare a cache entry for a collection item
865 delete *it;
866 }
867 }
868 }
869 }
870
871 // how does one get rid of the config ?
872 #if OSL_DEBUG_LEVEL > 1
873 fprintf( stderr, "inserted %d fonts from fontconfig\n", nFonts );
874 #endif
875 return nFonts;
876 }
877
deinitFontconfig()878 void PrintFontManager::deinitFontconfig()
879 {
880 FontCfgWrapper::release();
881 }
882
FreeTypeCharIndex(void * pFace,sal_uInt32 aChar)883 int PrintFontManager::FreeTypeCharIndex( void *pFace, sal_uInt32 aChar )
884 {
885 FontCfgWrapper& rWrapper = FontCfgWrapper::get();
886 return rWrapper.isValid() ? rWrapper.FcFreeTypeCharIndex( (FT_Face)pFace, aChar ) : 0;
887 }
888
addFontconfigDir(const rtl::OString & rDirName)889 bool PrintFontManager::addFontconfigDir( const rtl::OString& rDirName )
890 {
891 FontCfgWrapper& rWrapper = FontCfgWrapper::get();
892 if( ! rWrapper.isValid() )
893 return false;
894
895 // workaround for a stability problems in older FC versions
896 // when handling application specifc fonts
897 const int nVersion = rWrapper.FcGetVersion();
898 if( nVersion <= 20400 )
899 return false;
900 const char* pDirName = (const char*)rDirName.getStr();
901 bool bDirOk = (rWrapper.FcConfigAppFontAddDir( rWrapper.FcConfigGetCurrent(), (FcChar8*)pDirName ) == FcTrue);
902
903 #if OSL_DEBUG_LEVEL > 1
904 fprintf( stderr, "FcConfigAppFontAddDir( \"%s\") => %d\n", pDirName, bDirOk );
905 #endif
906
907 if( !bDirOk )
908 return false;
909
910 // load dir-specific fc-config file too if available
911 const rtl::OString aConfFileName = rDirName + "/fc_local.conf";
912 FILE* pCfgFile = fopen( aConfFileName.getStr(), "rb" );
913 if( pCfgFile )
914 {
915 fclose( pCfgFile);
916 bool bCfgOk = rWrapper.FcConfigParseAndLoad( rWrapper.FcConfigGetCurrent(),
917 (FcChar8*)aConfFileName.getStr(), FcTrue );
918 if( !bCfgOk )
919 fprintf( stderr, "FcConfigParseAndLoad( \"%s\") => %d\n", aConfFileName.getStr(), bCfgOk );
920 }
921
922 return true;
923 }
924
addtopattern(FontCfgWrapper & rWrapper,FcPattern * pPattern,italic::type eItalic,weight::type eWeight,width::type eWidth,pitch::type ePitch)925 static void addtopattern(FontCfgWrapper& rWrapper, FcPattern *pPattern,
926 italic::type eItalic, weight::type eWeight, width::type eWidth, pitch::type ePitch)
927 {
928 if( eItalic != italic::Unknown )
929 {
930 int nSlant = FC_SLANT_ROMAN;
931 switch( eItalic )
932 {
933 case italic::Italic: nSlant = FC_SLANT_ITALIC;break;
934 case italic::Oblique: nSlant = FC_SLANT_OBLIQUE;break;
935 default:
936 break;
937 }
938 rWrapper.FcPatternAddInteger( pPattern, FC_SLANT, nSlant );
939 }
940 if( eWeight != weight::Unknown )
941 {
942 int nWeight = FC_WEIGHT_NORMAL;
943 switch( eWeight )
944 {
945 case weight::Thin: nWeight = FC_WEIGHT_THIN;break;
946 case weight::UltraLight: nWeight = FC_WEIGHT_ULTRALIGHT;break;
947 case weight::Light: nWeight = FC_WEIGHT_LIGHT;break;
948 case weight::SemiLight: nWeight = FC_WEIGHT_BOOK;break;
949 case weight::Normal: nWeight = FC_WEIGHT_NORMAL;break;
950 case weight::Medium: nWeight = FC_WEIGHT_MEDIUM;break;
951 case weight::SemiBold: nWeight = FC_WEIGHT_SEMIBOLD;break;
952 case weight::Bold: nWeight = FC_WEIGHT_BOLD;break;
953 case weight::UltraBold: nWeight = FC_WEIGHT_ULTRABOLD;break;
954 case weight::Black: nWeight = FC_WEIGHT_BLACK;break;
955 default:
956 break;
957 }
958 rWrapper.FcPatternAddInteger( pPattern, FC_WEIGHT, nWeight );
959 }
960 if( eWidth != width::Unknown )
961 {
962 int nWidth = FC_WIDTH_NORMAL;
963 switch( eWidth )
964 {
965 case width::UltraCondensed: nWidth = FC_WIDTH_ULTRACONDENSED;break;
966 case width::ExtraCondensed: nWidth = FC_WIDTH_EXTRACONDENSED;break;
967 case width::Condensed: nWidth = FC_WIDTH_CONDENSED;break;
968 case width::SemiCondensed: nWidth = FC_WIDTH_SEMICONDENSED;break;
969 case width::Normal: nWidth = FC_WIDTH_NORMAL;break;
970 case width::SemiExpanded: nWidth = FC_WIDTH_SEMIEXPANDED;break;
971 case width::Expanded: nWidth = FC_WIDTH_EXPANDED;break;
972 case width::ExtraExpanded: nWidth = FC_WIDTH_EXTRAEXPANDED;break;
973 case width::UltraExpanded: nWidth = FC_WIDTH_ULTRACONDENSED;break;
974 default:
975 break;
976 }
977 rWrapper.FcPatternAddInteger( pPattern, FC_WIDTH, nWidth );
978 }
979 if( ePitch != pitch::Unknown )
980 {
981 int nSpacing = FC_PROPORTIONAL;
982 switch( ePitch )
983 {
984 case pitch::Fixed: nSpacing = FC_MONO;break;
985 case pitch::Variable: nSpacing = FC_PROPORTIONAL;break;
986 default:
987 break;
988 }
989 rWrapper.FcPatternAddInteger( pPattern, FC_SPACING, nSpacing );
990 if (nSpacing == FC_MONO)
991 rWrapper.FcPatternAddString( pPattern, FC_FAMILY, (FcChar8*)"monospace");
992 }
993 }
994
Substitute(const rtl::OUString & rFontName,rtl::OUString & rMissingCodes,const rtl::OString & rLangAttrib,italic::type & rItalic,weight::type & rWeight,width::type & rWidth,pitch::type & rPitch) const995 rtl::OUString PrintFontManager::Substitute(const rtl::OUString& rFontName,
996 rtl::OUString& rMissingCodes, const rtl::OString &rLangAttrib,
997 italic::type &rItalic, weight::type &rWeight,
998 width::type &rWidth, pitch::type &rPitch) const
999 {
1000 rtl::OUString aName;
1001 FontCfgWrapper& rWrapper = FontCfgWrapper::get();
1002 if( ! rWrapper.isValid() )
1003 return aName;
1004
1005 // build pattern argument for fontconfig query
1006 FcPattern* pPattern = rWrapper.FcPatternCreate();
1007
1008 // Prefer scalable fonts
1009 rWrapper.FcPatternAddBool( pPattern, FC_SCALABLE, FcTrue );
1010
1011 const rtl::OString aTargetName = rtl::OUStringToOString( rFontName, RTL_TEXTENCODING_UTF8 );
1012 const FcChar8* pTargetNameUtf8 = (FcChar8*)aTargetName.getStr();
1013 rWrapper.FcPatternAddString( pPattern, FC_FAMILY, pTargetNameUtf8 );
1014
1015 const FcChar8* pLangAttribUtf8 = (FcChar8*)rLangAttrib.getStr();
1016 if( rLangAttrib.getLength() )
1017 rWrapper.FcPatternAddString( pPattern, FC_LANG, pLangAttribUtf8 );
1018
1019 // Add required Unicode characters, if any
1020 if ( rMissingCodes.getLength() )
1021 {
1022 FcCharSet *unicodes = rWrapper.FcCharSetCreate();
1023 for( sal_Int32 nStrIndex = 0; nStrIndex < rMissingCodes.getLength(); )
1024 {
1025 // also handle unicode surrogates
1026 const sal_uInt32 nCode = rMissingCodes.iterateCodePoints( &nStrIndex );
1027 rWrapper.FcCharSetAddChar( unicodes, nCode );
1028 }
1029 rWrapper.FcPatternAddCharSet( pPattern, FC_CHARSET, unicodes);
1030 rWrapper.FcCharSetDestroy( unicodes );
1031 }
1032
1033 addtopattern(rWrapper, pPattern, rItalic, rWeight, rWidth, rPitch);
1034
1035 // query fontconfig for a substitute
1036 rWrapper.FcConfigSubstitute( rWrapper.FcConfigGetCurrent(), pPattern, FcMatchPattern );
1037 rWrapper.FcDefaultSubstitute( pPattern );
1038
1039 // process the result of the fontconfig query
1040 FcResult eResult = FcResultNoMatch;
1041 FcFontSet* pFontSet = rWrapper.getFontSet();
1042 FcPattern* pResult = rWrapper.FcFontSetMatch( rWrapper.FcConfigGetCurrent(), &pFontSet, 1, pPattern, &eResult );
1043 rWrapper.FcPatternDestroy( pPattern );
1044
1045 FcFontSet* pSet = NULL;
1046 if( pResult )
1047 {
1048 pSet = rWrapper.FcFontSetCreate();
1049 // info: destroying the pSet destroys pResult implicitly
1050 // since pResult was "added" to pSet
1051 rWrapper.FcFontSetAdd( pSet, pResult );
1052 }
1053
1054 if( pSet )
1055 {
1056 if( pSet->nfont > 0 )
1057 {
1058 //extract the closest match
1059 FcChar8* family = NULL;
1060 FcResult eFileRes = rWrapper.FcPatternGetString( pSet->fonts[0], FC_FAMILY, 0, &family );
1061
1062 // get the family name
1063 if( eFileRes == FcResultMatch )
1064 {
1065 OString sFamily((sal_Char*)family);
1066 std::hash_map< rtl::OString, rtl::OString, rtl::OStringHash >::const_iterator aI = rWrapper.m_aFontNameToLocalized.find(sFamily);
1067 if (aI != rWrapper.m_aFontNameToLocalized.end())
1068 sFamily = aI->second;
1069 aName = rtl::OStringToOUString( sFamily, RTL_TEXTENCODING_UTF8 );
1070
1071
1072 int val = 0;
1073 if ( FcResultMatch == rWrapper.FcPatternGetInteger( pSet->fonts[0], FC_WEIGHT, 0, &val))
1074 rWeight = convertWeight(val);
1075 if ( FcResultMatch == rWrapper.FcPatternGetInteger( pSet->fonts[0], FC_SLANT, 0, &val))
1076 rItalic = convertSlant(val);
1077 if ( FcResultMatch == rWrapper.FcPatternGetInteger( pSet->fonts[0], FC_SPACING, 0, &val))
1078 rPitch = convertSpacing(val);
1079 if ( FcResultMatch == rWrapper.FcPatternGetInteger( pSet->fonts[0], FC_WIDTH, 0, &val))
1080 rWidth = convertWidth(val);
1081 }
1082
1083 // update rMissingCodes by removing resolved unicodes
1084 if( rMissingCodes.getLength() > 0 )
1085 {
1086 sal_uInt32* pRemainingCodes = (sal_uInt32*)alloca( rMissingCodes.getLength() * sizeof(sal_uInt32) );
1087 int nRemainingLen = 0;
1088 FcCharSet* unicodes;
1089 if( !rWrapper.FcPatternGetCharSet( pSet->fonts[0], FC_CHARSET, 0, &unicodes ) )
1090 {
1091 for( sal_Int32 nStrIndex = 0; nStrIndex < rMissingCodes.getLength(); )
1092 {
1093 // also handle unicode surrogates
1094 const sal_uInt32 nCode = rMissingCodes.iterateCodePoints( &nStrIndex );
1095 if( rWrapper.FcCharSetHasChar( unicodes, nCode ) != FcTrue )
1096 pRemainingCodes[ nRemainingLen++ ] = nCode;
1097 }
1098 }
1099 rMissingCodes = OUString( pRemainingCodes, nRemainingLen );
1100 }
1101 }
1102
1103 rWrapper.FcFontSetDestroy( pSet );
1104 }
1105
1106 return aName;
1107 }
1108
getFontOptions(const FastPrintFontInfo & rInfo,int nSize,void (* subcallback)(void *),ImplFontOptions & rOptions) const1109 bool PrintFontManager::getFontOptions(
1110 const FastPrintFontInfo& rInfo, int nSize, void (*subcallback)(void*),
1111 ImplFontOptions& rOptions) const
1112 {
1113 #ifndef ENABLE_FONTCONFIG
1114 (void)rInfo;(void)nSize;(void)subcallback;(void)rOptions;
1115 return false;
1116 #else // ENABLE_FONTCONFIG
1117 FontCfgWrapper& rWrapper = FontCfgWrapper::get();
1118 if( ! rWrapper.isValid() )
1119 return false;
1120
1121 FcConfig* pConfig = rWrapper.FcConfigGetCurrent();
1122 FcPattern* pPattern = rWrapper.FcPatternCreate();
1123
1124 OString sFamily = OUStringToOString( rInfo.m_aFamilyName, RTL_TEXTENCODING_UTF8 );
1125
1126 std::hash_map< rtl::OString, rtl::OString, rtl::OStringHash >::const_iterator aI = rWrapper.m_aLocalizedToCanonical.find(sFamily);
1127 if (aI != rWrapper.m_aLocalizedToCanonical.end())
1128 sFamily = aI->second;
1129 if( sFamily.getLength() )
1130 rWrapper.FcPatternAddString( pPattern, FC_FAMILY, (FcChar8*)sFamily.getStr() );
1131
1132 addtopattern(rWrapper, pPattern, rInfo.m_eItalic, rInfo.m_eWeight, rInfo.m_eWidth, rInfo.m_ePitch);
1133 rWrapper.FcPatternAddDouble( pPattern, FC_PIXEL_SIZE, nSize);
1134
1135 FcBool embitmap = true, antialias = true, autohint = true, hinting = true;
1136 int hintstyle = FC_HINT_FULL;
1137
1138 rWrapper.FcConfigSubstitute( pConfig, pPattern, FcMatchPattern );
1139 if (subcallback) subcallback(pPattern);
1140 rWrapper.FcDefaultSubstitute( pPattern );
1141
1142 FcResult eResult = FcResultNoMatch;
1143 FcFontSet* pFontSet = rWrapper.getFontSet();
1144 FcPattern* pResult = rWrapper.FcFontSetMatch( pConfig, &pFontSet, 1, pPattern, &eResult );
1145 if( pResult )
1146 {
1147 FcFontSet* pSet = rWrapper.FcFontSetCreate();
1148 rWrapper.FcFontSetAdd( pSet, pResult );
1149 if( pSet->nfont > 0 )
1150 {
1151 FcResult eEmbeddedBitmap = rWrapper.FcPatternGetBool(pSet->fonts[0],
1152 FC_EMBEDDED_BITMAP, 0, &embitmap);
1153 FcResult eAntialias = rWrapper.FcPatternGetBool(pSet->fonts[0],
1154 FC_ANTIALIAS, 0, &antialias);
1155 FcResult eAutoHint = rWrapper.FcPatternGetBool(pSet->fonts[0],
1156 FC_AUTOHINT, 0, &autohint);
1157 FcResult eHinting = rWrapper.FcPatternGetBool(pSet->fonts[0],
1158 FC_HINTING, 0, &hinting);
1159 /*FcResult eHintStyle =*/ rWrapper.FcPatternGetInteger( pSet->fonts[0],
1160 FC_HINT_STYLE, 0, &hintstyle);
1161
1162 if( eEmbeddedBitmap == FcResultMatch )
1163 rOptions.meEmbeddedBitmap = embitmap ? EMBEDDEDBITMAP_TRUE : EMBEDDEDBITMAP_FALSE;
1164 if( eAntialias == FcResultMatch )
1165 rOptions.meAntiAlias = antialias ? ANTIALIAS_TRUE : ANTIALIAS_FALSE;
1166 if( eAutoHint == FcResultMatch )
1167 rOptions.meAutoHint = autohint ? AUTOHINT_TRUE : AUTOHINT_FALSE;
1168 if( eHinting == FcResultMatch )
1169 rOptions.meHinting = hinting ? HINTING_TRUE : HINTING_FALSE;
1170 switch (hintstyle)
1171 {
1172 case FC_HINT_NONE: rOptions.meHintStyle = HINT_NONE; break;
1173 case FC_HINT_SLIGHT: rOptions.meHintStyle = HINT_SLIGHT; break;
1174 case FC_HINT_MEDIUM: rOptions.meHintStyle = HINT_MEDIUM; break;
1175 default: // fall through
1176 case FC_HINT_FULL: rOptions.meHintStyle = HINT_FULL; break;
1177 }
1178 }
1179 // info: destroying the pSet destroys pResult implicitly
1180 // since pResult was "added" to pSet
1181 rWrapper.FcFontSetDestroy( pSet );
1182 }
1183
1184 // cleanup
1185 rWrapper.FcPatternDestroy( pPattern );
1186
1187 // TODO: return true only if non-default font options are set
1188 const bool bOK = (pResult != NULL);
1189 return bOK;
1190 #endif
1191 }
1192
matchFont(FastPrintFontInfo & rInfo,const com::sun::star::lang::Locale & rLocale)1193 bool PrintFontManager::matchFont( FastPrintFontInfo& rInfo, const com::sun::star::lang::Locale& rLocale )
1194 {
1195 FontCfgWrapper& rWrapper = FontCfgWrapper::get();
1196 if( ! rWrapper.isValid() )
1197 return false;
1198
1199 FcConfig* pConfig = rWrapper.FcConfigGetCurrent();
1200 FcPattern* pPattern = rWrapper.FcPatternCreate();
1201
1202 OString aLangAttrib;
1203 // populate pattern with font characteristics
1204 if( rLocale.Language.getLength() )
1205 {
1206 OUStringBuffer aLang(6);
1207 aLang.append( rLocale.Language );
1208 if( rLocale.Country.getLength() )
1209 {
1210 aLang.append( sal_Unicode('-') );
1211 aLang.append( rLocale.Country );
1212 }
1213 aLangAttrib = OUStringToOString( aLang.makeStringAndClear(), RTL_TEXTENCODING_UTF8 );
1214 }
1215 if( aLangAttrib.getLength() )
1216 rWrapper.FcPatternAddString( pPattern, FC_LANG, (FcChar8*)aLangAttrib.getStr() );
1217
1218 OString aFamily = OUStringToOString( rInfo.m_aFamilyName, RTL_TEXTENCODING_UTF8 );
1219 if( aFamily.getLength() )
1220 rWrapper.FcPatternAddString( pPattern, FC_FAMILY, (FcChar8*)aFamily.getStr() );
1221
1222 addtopattern(rWrapper, pPattern, rInfo.m_eItalic, rInfo.m_eWeight, rInfo.m_eWidth, rInfo.m_ePitch);
1223
1224 rWrapper.FcConfigSubstitute( pConfig, pPattern, FcMatchPattern );
1225 rWrapper.FcDefaultSubstitute( pPattern );
1226 FcResult eResult = FcResultNoMatch;
1227 FcFontSet *pFontSet = rWrapper.getFontSet();
1228 FcPattern* pResult = rWrapper.FcFontSetMatch( pConfig, &pFontSet, 1, pPattern, &eResult );
1229 bool bSuccess = false;
1230 if( pResult )
1231 {
1232 FcFontSet* pSet = rWrapper.FcFontSetCreate();
1233 rWrapper.FcFontSetAdd( pSet, pResult );
1234 if( pSet->nfont > 0 )
1235 {
1236 //extract the closest match
1237 FcChar8* file = NULL;
1238 FcResult eFileRes = rWrapper.FcPatternGetString( pSet->fonts[0], FC_FILE, 0, &file );
1239 if( eFileRes == FcResultMatch )
1240 {
1241 OString aDir, aBase, aOrgPath( (sal_Char*)file );
1242 splitPath( aOrgPath, aDir, aBase );
1243 int nDirID = getDirectoryAtom( aDir, true );
1244 fontID aFont = findFontFileID( nDirID, aBase );
1245 if( aFont > 0 )
1246 bSuccess = getFontFastInfo( aFont, rInfo );
1247 }
1248 }
1249 // info: destroying the pSet destroys pResult implicitly
1250 // since pResult was "added" to pSet
1251 rWrapper.FcFontSetDestroy( pSet );
1252 }
1253
1254 // cleanup
1255 rWrapper.FcPatternDestroy( pPattern );
1256
1257 return bSuccess;
1258 }
1259
1260 #else // ENABLE_FONTCONFIG not defined
1261
initFontconfig()1262 bool PrintFontManager::initFontconfig()
1263 {
1264 return false;
1265 }
1266
countFontconfigFonts(std::hash_map<rtl::OString,int,rtl::OStringHash> &)1267 int PrintFontManager::countFontconfigFonts( std::hash_map<rtl::OString, int, rtl::OStringHash>& )
1268 {
1269 return 0;
1270 }
1271
deinitFontconfig()1272 void PrintFontManager::deinitFontconfig()
1273 {}
1274
addFontconfigDir(const rtl::OString &)1275 bool PrintFontManager::addFontconfigDir( const rtl::OString& )
1276 {
1277 return false;
1278 }
1279
matchFont(FastPrintFontInfo &,const com::sun::star::lang::Locale &)1280 bool PrintFontManager::matchFont( FastPrintFontInfo&, const com::sun::star::lang::Locale& )
1281 {
1282 return false;
1283 }
1284
FreeTypeCharIndex(void *,sal_uInt32)1285 int PrintFontManager::FreeTypeCharIndex( void*, sal_uInt32 )
1286 {
1287 return 0;
1288 }
1289
Substitute(const rtl::OUString &,rtl::OUString &,const rtl::OString &,italic::type,weight::type,width::type,pitch::type) const1290 rtl::OUString PrintFontManager::Substitute( const rtl::OUString&,
1291 rtl::OUString&, const rtl::OString&, italic::type, weight::type, width::type, pitch::type) const
1292 {
1293 rtl::OUString aName;
1294 return aName;
1295 }
1296
1297 #endif // ENABLE_FONTCONFIG
1298
1299