Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : :
30 : : #include "fontcache.hxx"
31 : : #include "impfont.hxx"
32 : : #include "vcl/fontmanager.hxx"
33 : : #include "vcl/vclenum.hxx"
34 : : #include "outfont.hxx"
35 : : #include <i18npool/mslangid.hxx>
36 : :
37 : : using namespace psp;
38 : :
39 : : #include <fontconfig/fontconfig.h>
40 : : #include <ft2build.h>
41 : : #include <fontconfig/fcfreetype.h>
42 : : // allow compile on baseline (currently with fontconfig 2.2.0)
43 : : #ifndef FC_WEIGHT_BOOK // TODO: remove when baseline moves to fc>=2.2.1
44 : : #define FC_WEIGHT_BOOK 75
45 : : #endif
46 : : #ifndef FC_EMBEDDED_BITMAP // TODO: remove when baseline moves to fc>=2.3.92
47 : : #define FC_EMBEDDED_BITMAP "embeddedbitmap"
48 : : #endif
49 : : #ifndef FC_FAMILYLANG // TODO: remove when baseline moves to fc>=2.2.97
50 : : #define FC_FAMILYLANG "familylang"
51 : : #endif
52 : : #ifndef FC_CAPABILITY // TODO: remove when baseline moves to fc>=2.2.97
53 : : #define FC_CAPABILITY "capability"
54 : : #endif
55 : : #ifndef FC_STYLELANG // TODO: remove when baseline moves to fc>=2.2.97
56 : : #define FC_STYLELANG "stylelang"
57 : : #endif
58 : : #ifndef FC_HINT_STYLE // TODO: remove when baseline moves to fc>=2.2.91
59 : : #define FC_HINT_STYLE "hintstyle"
60 : : #define FC_HINT_NONE 0
61 : : #define FC_HINT_SLIGHT 1
62 : : #define FC_HINT_MEDIUM 2
63 : : #define FC_HINT_FULL 3
64 : : #endif
65 : : #ifndef FC_FT_FACE
66 : : #define FC_FT_FACE "ftface"
67 : : #endif
68 : : #ifndef FC_EMBOLDEN
69 : : #define FC_EMBOLDEN "embolden"
70 : : #endif
71 : : #ifndef FC_MATRIX
72 : : #define FC_MATRIX "matrix"
73 : : #endif
74 : : #ifndef FC_FONTFORMAT
75 : : #define FC_FONTFORMAT "fontformat"
76 : : #endif
77 : :
78 : : #include <cstdio>
79 : : #include <cstdarg>
80 : :
81 : : #include "unotools/atom.hxx"
82 : :
83 : : #include "osl/module.h"
84 : : #include "osl/thread.h"
85 : : #include "osl/process.h"
86 : :
87 : : #include "rtl/ustrbuf.hxx"
88 : : #include "rtl/locale.hxx"
89 : :
90 : : #include "sal/alloca.h"
91 : :
92 : : #include <utility>
93 : : #include <algorithm>
94 : :
95 : : using namespace osl;
96 : : using ::rtl::OUString;
97 : : using ::rtl::OUStringBuffer;
98 : : using ::rtl::OString;
99 : :
100 : : namespace
101 : : {
102 : : typedef std::pair<FcChar8*, FcChar8*> lang_and_element;
103 : : }
104 : :
105 : : class FontCfgWrapper
106 : : {
107 : : FcFontSet* m_pOutlineSet;
108 : :
109 : : void addFontSet( FcSetName );
110 : :
111 : : FontCfgWrapper();
112 : : ~FontCfgWrapper();
113 : :
114 : : public:
115 : : static FontCfgWrapper& get();
116 : : static void release();
117 : :
118 : : FcFontSet* getFontSet();
119 : :
120 : : public:
121 : : FcResult LocalizedElementFromPattern(FcPattern* pPattern, FcChar8 **family,
122 : : const char *elementtype, const char *elementlangtype);
123 : : //to-do, make private and add some cleanish accessor methods
124 : : boost::unordered_map< rtl::OString, rtl::OString, rtl::OStringHash > m_aFontNameToLocalized;
125 : : boost::unordered_map< rtl::OString, rtl::OString, rtl::OStringHash > m_aLocalizedToCanonical;
126 : : private:
127 : : void cacheLocalizedFontNames(const FcChar8 *origfontname, const FcChar8 *bestfontname, const std::vector< lang_and_element > &lang_and_elements);
128 : : };
129 : :
130 : 236 : FontCfgWrapper::FontCfgWrapper()
131 [ + - ][ + - ]: 236 : : m_pOutlineSet( NULL )
132 : : {
133 [ + - ]: 236 : FcInit();
134 : 236 : }
135 : :
136 : 472 : void FontCfgWrapper::addFontSet( FcSetName eSetName )
137 : : {
138 : : /*
139 : : add only acceptable outlined fonts to our config,
140 : : for future fontconfig use
141 : : */
142 : 472 : FcFontSet* pOrig = FcConfigGetFonts( FcConfigGetCurrent(), eSetName );
143 [ + + ]: 472 : if( !pOrig )
144 : 472 : return;
145 : :
146 : : // filter the font sets to remove obsolete faces
147 [ + + ]: 37007 : for( int i = 0; i < pOrig->nfont; ++i )
148 : : {
149 : 36538 : FcPattern* pPattern = pOrig->fonts[i];
150 : : // #i115131# ignore non-outline fonts
151 : 36538 : FcBool bOutline = FcFalse;
152 [ + - ]: 36538 : FcResult eOutRes = FcPatternGetBool( pPattern, FC_OUTLINE, 0, &bOutline );
153 [ + - ][ - + ]: 36538 : if( (eOutRes != FcResultMatch) || (bOutline == FcFalse) )
154 : 0 : continue;
155 [ + - ]: 36538 : FcPatternReference( pPattern );
156 [ + - ]: 36538 : FcFontSetAdd( m_pOutlineSet, pPattern );
157 : : }
158 : :
159 : : // TODO?: FcFontSetDestroy( pOrig );
160 : : }
161 : :
162 : : namespace
163 : : {
164 : 315732 : int compareFontNames(const FcPattern *a, const FcPattern *b)
165 : : {
166 : 315732 : FcChar8 *pNameA=NULL, *pNameB=NULL;
167 : :
168 [ + - ]: 315732 : int nHaveA = FcPatternGetString(a, FC_FAMILY, 0, &pNameA) == FcResultMatch;
169 [ + - ]: 315732 : int nHaveB = FcPatternGetString(b, FC_FAMILY, 0, &pNameB) == FcResultMatch;
170 : :
171 [ + - ][ + - ]: 315732 : if (nHaveA && nHaveB)
172 : 315732 : return strcmp((const char*)pNameA, (const char*)pNameB);
173 : :
174 : 315732 : return nHaveA - nHaveB;
175 : : }
176 : :
177 : : //Sort fonts so that fonts with the same family name are side-by-side, with
178 : : //those with higher version numbers first
179 : : class SortFont : public ::std::binary_function< const FcPattern*, const FcPattern*, bool >
180 : : {
181 : : public:
182 : 279430 : bool operator()(const FcPattern *a, const FcPattern *b)
183 : : {
184 [ + - ]: 279430 : int comp = compareFontNames(a, b);
185 [ + + ]: 279430 : if (comp != 0)
186 : 232382 : return comp < 0;
187 : :
188 : 47048 : int nVersionA=0, nVersionB=0;
189 : :
190 [ + - ]: 47048 : int nHaveA = FcPatternGetInteger(a, FC_FONTVERSION, 0, &nVersionA) == FcResultMatch;
191 [ + - ]: 47048 : int nHaveB = FcPatternGetInteger(b, FC_FONTVERSION, 0, &nVersionB) == FcResultMatch;
192 : :
193 [ + - ][ + - ]: 47048 : if (nHaveA && nHaveB)
194 : 47048 : return nVersionA > nVersionB;
195 : :
196 : 279430 : return nHaveA > nHaveB;
197 : : }
198 : : };
199 : :
200 : : //See fdo#30729 for where an old opensymbol installed system-wide can
201 : : //clobber the new opensymbol installed locally
202 : : //
203 : : //See if this font is a duplicate with equal attributes which has already been
204 : : //inserted, or if it an older version of an inserted fonts. Depends on FcFontSet
205 : : //on being sorted with SortFont
206 : 36538 : bool isPreviouslyDuplicateOrObsoleted(FcFontSet *pFSet, int i)
207 : : {
208 [ + + ]: 36538 : if (i == 0)
209 : 236 : return false;
210 : :
211 : 36302 : const FcPattern *a = pFSet->fonts[i];
212 : 36302 : const FcPattern *b = pFSet->fonts[i-1];
213 : :
214 [ + + ]: 36302 : if (compareFontNames(a, b) != 0)
215 : 12984 : return false;
216 : :
217 : 23318 : FcPattern* pTestPatternA = FcPatternDuplicate(a);
218 : 23318 : FcPatternDel(pTestPatternA, FC_FILE);
219 : 23318 : FcPatternDel(pTestPatternA, FC_CHARSET);
220 : 23318 : FcPatternDel(pTestPatternA, FC_CAPABILITY);
221 : 23318 : FcPatternDel(pTestPatternA, FC_FONTVERSION);
222 : :
223 : 23318 : FcPattern* pTestPatternB = FcPatternDuplicate(b);
224 : 23318 : FcPatternDel(pTestPatternB, FC_FILE);
225 : 23318 : FcPatternDel(pTestPatternB, FC_CHARSET);
226 : 23318 : FcPatternDel(pTestPatternB, FC_CAPABILITY);
227 : 23318 : FcPatternDel(pTestPatternB, FC_FONTVERSION);
228 : :
229 : 23318 : bool bIsDup = FcPatternEqual(pTestPatternA, pTestPatternB);
230 : :
231 : 23318 : FcPatternDestroy(pTestPatternB);
232 : 23318 : FcPatternDestroy(pTestPatternA);
233 : :
234 : 36538 : return bIsDup;
235 : : }
236 : : }
237 : :
238 : 8985 : FcFontSet* FontCfgWrapper::getFontSet()
239 : : {
240 [ + + ]: 8985 : if( !m_pOutlineSet )
241 : : {
242 : 236 : m_pOutlineSet = FcFontSetCreate();
243 : 236 : addFontSet( FcSetSystem );
244 [ + - ]: 236 : if( FcGetVersion() > 20400 ) // #i85462# prevent crashes
245 : 236 : addFontSet( FcSetApplication );
246 : :
247 [ + - ]: 236 : ::std::sort(m_pOutlineSet->fonts,m_pOutlineSet->fonts+m_pOutlineSet->nfont,SortFont());
248 : : }
249 : :
250 : 8985 : return m_pOutlineSet;
251 : : }
252 : :
253 [ + - ]: 236 : FontCfgWrapper::~FontCfgWrapper()
254 : : {
255 [ + - ]: 236 : if( m_pOutlineSet )
256 [ + - ]: 236 : FcFontSetDestroy( m_pOutlineSet );
257 : : //To-Do: get gtk vclplug smoketest to pass
258 : : //FcFini();
259 : 236 : }
260 : :
261 : : static FontCfgWrapper* pOneInstance = NULL;
262 : :
263 : 9221 : FontCfgWrapper& FontCfgWrapper::get()
264 : : {
265 [ + + ]: 9221 : if( ! pOneInstance )
266 [ + - ]: 236 : pOneInstance = new FontCfgWrapper();
267 : 9221 : return *pOneInstance;
268 : : }
269 : :
270 : 236 : void FontCfgWrapper::release()
271 : : {
272 [ + - ]: 236 : if( pOneInstance )
273 : : {
274 [ + - ]: 236 : delete pOneInstance;
275 : 236 : pOneInstance = NULL;
276 : : }
277 : 236 : }
278 : :
279 : : namespace
280 : : {
281 : : class localizedsorter
282 : : {
283 : : rtl::OLocale maLoc;
284 : : public:
285 : 54668 : localizedsorter(rtl_Locale* pLoc) : maLoc(pLoc) {}
286 : : FcChar8* bestname(const std::vector<lang_and_element> &elements);
287 : : };
288 : :
289 : 54668 : FcChar8* localizedsorter::bestname(const std::vector<lang_and_element> &elements)
290 : : {
291 [ + - ]: 54668 : FcChar8* candidate = elements.begin()->second;
292 [ + - ]: 54668 : rtl::OString sLangMatch(rtl::OUStringToOString(maLoc.getLanguage().toAsciiLowerCase(), RTL_TEXTENCODING_UTF8));
293 : 54668 : rtl::OString sFullMatch = sLangMatch;
294 : 54668 : sFullMatch += OString('-');
295 [ + - ]: 54668 : sFullMatch += rtl::OUStringToOString(maLoc.getCountry().toAsciiLowerCase(), RTL_TEXTENCODING_UTF8);
296 : :
297 : 54668 : std::vector<lang_and_element>::const_iterator aEnd = elements.end();
298 : 54668 : bool alreadyclosematch = false;
299 : 54668 : bool found_fallback_englishname = false;
300 [ + - ][ + - ]: 119338 : for( std::vector<lang_and_element>::const_iterator aIter = elements.begin(); aIter != aEnd; ++aIter )
[ + + ]
301 : : {
302 [ + - ]: 64670 : const char *pLang = (const char*)aIter->first;
303 [ - + ]: 64670 : if( rtl_str_compare( pLang, sFullMatch.getStr() ) == 0)
304 : : {
305 : : // both language and country match
306 [ # # ]: 0 : candidate = aIter->second;
307 : 0 : break;
308 : : }
309 [ + + ]: 64670 : else if( alreadyclosematch )
310 : : {
311 : : // current candidate matches lang of lang-TERRITORY
312 : : // override candidate only if there is a full match
313 : 9294 : continue;
314 : : }
315 [ + + ]: 55376 : else if( rtl_str_compare( pLang, sLangMatch.getStr()) == 0)
316 : : {
317 : : // just the language matches
318 [ + - ]: 53960 : candidate = aIter->second;
319 : 53960 : alreadyclosematch = true;
320 : : }
321 [ - + ]: 1416 : else if( found_fallback_englishname )
322 : : {
323 : : // already found an english fallback, don't override candidate
324 : : // unless there is a better language match
325 : 0 : continue;
326 : : }
327 [ - + ]: 1416 : else if( rtl_str_compare( pLang, "en") == 0)
328 : : {
329 : : // select a fallback candidate of the first english element
330 : : // name
331 [ # # ]: 0 : candidate = aIter->second;
332 : 0 : found_fallback_englishname = true;
333 : : }
334 : : }
335 : 54668 : return candidate;
336 : : }
337 : : }
338 : :
339 : : //Set up maps to quickly map between a fonts best UI name and all the rest of its names, and vice versa
340 : 27334 : void FontCfgWrapper::cacheLocalizedFontNames(const FcChar8 *origfontname, const FcChar8 *bestfontname,
341 : : const std::vector< lang_and_element > &lang_and_elements)
342 : : {
343 : 27334 : std::vector<lang_and_element>::const_iterator aEnd = lang_and_elements.end();
344 [ + - ][ + - ]: 61046 : for (std::vector<lang_and_element>::const_iterator aIter = lang_and_elements.begin(); aIter != aEnd; ++aIter)
[ + + ]
345 : : {
346 [ + - ]: 33712 : const char *candidate = (const char*)(aIter->second);
347 [ + + ]: 33712 : if (rtl_str_compare(candidate, (const char*)bestfontname) != 0)
348 [ + - ]: 6378 : m_aFontNameToLocalized[OString(candidate)] = OString((const char*)bestfontname);
349 : : }
350 [ + + ]: 27334 : if (rtl_str_compare((const char*)origfontname, (const char*)bestfontname) != 0)
351 [ + - ]: 708 : m_aLocalizedToCanonical[OString((const char*)bestfontname)] = OString((const char*)origfontname);
352 : 27334 : }
353 : :
354 : 73076 : FcResult FontCfgWrapper::LocalizedElementFromPattern(FcPattern* pPattern, FcChar8 **element,
355 : : const char *elementtype, const char *elementlangtype)
356 : : { /* e. g.: ^ FC_FAMILY ^ FC_FAMILYLANG */
357 : : FcChar8 *origelement;
358 [ + - ]: 73076 : FcResult eElementRes = FcPatternGetString( pPattern, elementtype, 0, &origelement );
359 : 73076 : *element = origelement;
360 : :
361 [ + - ]: 73076 : if( eElementRes == FcResultMatch)
362 : : {
363 : 73076 : FcChar8* elementlang = NULL;
364 [ + - ][ + + ]: 73076 : if (FcPatternGetString( pPattern, elementlangtype, 0, &elementlang ) == FcResultMatch)
365 : : {
366 [ + - ]: 54668 : std::vector< lang_and_element > lang_and_elements;
367 [ + - ][ + - ]: 54668 : lang_and_elements.push_back(lang_and_element(elementlang, *element));
368 : 54668 : int k = 1;
369 : 10002 : while (1)
370 : : {
371 [ + - ][ + + ]: 64670 : if (FcPatternGetString( pPattern, elementlangtype, k, &elementlang ) != FcResultMatch)
372 : 54668 : break;
373 [ + - ][ - + ]: 10002 : if (FcPatternGetString( pPattern, elementtype, k, element ) != FcResultMatch)
374 : 0 : break;
375 [ + - ][ + - ]: 10002 : lang_and_elements.push_back(lang_and_element(elementlang, *element));
376 : 10002 : ++k;
377 : : }
378 : :
379 : : //possible to-do, sort by UILocale instead of process locale
380 : : rtl_Locale* pLoc;
381 [ + - ]: 54668 : osl_getProcessLocale(&pLoc);
382 : 54668 : localizedsorter aSorter(pLoc);
383 [ + - ]: 54668 : *element = aSorter.bestname(lang_and_elements);
384 : :
385 : : //if this element is a fontname, map the other names to this best-name
386 [ + + ]: 54668 : if (rtl_str_compare(elementtype, FC_FAMILY) == 0)
387 [ + - ]: 73076 : cacheLocalizedFontNames(origelement, *element, lang_and_elements);
388 : : }
389 : : }
390 : :
391 : 73076 : return eElementRes;
392 : : }
393 : :
394 : : /*
395 : : * PrintFontManager::initFontconfig
396 : : */
397 : 236 : void PrintFontManager::initFontconfig()
398 : : {
399 : 236 : FontCfgWrapper::get();
400 : 236 : }
401 : :
402 : : namespace
403 : : {
404 : 43711 : FontWeight convertWeight(int weight)
405 : : {
406 : : // set weight
407 [ - + ]: 43711 : if( weight <= FC_WEIGHT_THIN )
408 : 0 : return WEIGHT_THIN;
409 [ + + ]: 43711 : else if( weight <= FC_WEIGHT_ULTRALIGHT )
410 : 822 : return WEIGHT_ULTRALIGHT;
411 [ + + ]: 42889 : else if( weight <= FC_WEIGHT_LIGHT )
412 : 950 : return WEIGHT_LIGHT;
413 [ + + ]: 41939 : else if( weight <= FC_WEIGHT_BOOK )
414 : 472 : return WEIGHT_SEMILIGHT;
415 [ + + ]: 41467 : else if( weight <= FC_WEIGHT_NORMAL )
416 : 23299 : return WEIGHT_NORMAL;
417 [ + + ]: 18168 : else if( weight <= FC_WEIGHT_MEDIUM )
418 : 2303 : return WEIGHT_MEDIUM;
419 [ + + ]: 15865 : else if( weight <= FC_WEIGHT_SEMIBOLD )
420 : 1024 : return WEIGHT_SEMIBOLD;
421 [ + - ]: 14841 : else if( weight <= FC_WEIGHT_BOLD )
422 : 14841 : return WEIGHT_BOLD;
423 [ # # ]: 0 : else if( weight <= FC_WEIGHT_ULTRABOLD )
424 : 0 : return WEIGHT_ULTRABOLD;
425 : 43711 : return WEIGHT_BLACK;
426 : : }
427 : :
428 : 43711 : FontItalic convertSlant(int slant)
429 : : {
430 : : // set italic
431 [ + + ]: 43711 : if( slant == FC_SLANT_ITALIC )
432 : 9723 : return ITALIC_NORMAL;
433 [ + + ]: 33988 : else if( slant == FC_SLANT_OBLIQUE )
434 : 4233 : return ITALIC_OBLIQUE;
435 : 43711 : return ITALIC_NONE;
436 : : }
437 : :
438 : 7660 : FontPitch convertSpacing(int spacing)
439 : : {
440 : : // set pitch
441 [ + + ][ - + ]: 7660 : if( spacing == FC_MONO || spacing == FC_CHARCELL )
442 : 3663 : return PITCH_FIXED;
443 : 7660 : return PITCH_VARIABLE;
444 : : }
445 : :
446 : : // translation: fontconfig enum -> vcl enum
447 : 8749 : FontWidth convertWidth(int width)
448 : : {
449 [ - + ]: 8749 : if (width == FC_WIDTH_ULTRACONDENSED)
450 : 0 : return WIDTH_ULTRA_CONDENSED;
451 [ - + ]: 8749 : else if (width == FC_WIDTH_EXTRACONDENSED)
452 : 0 : return WIDTH_EXTRA_CONDENSED;
453 [ - + ]: 8749 : else if (width == FC_WIDTH_CONDENSED)
454 : 0 : return WIDTH_CONDENSED;
455 [ - + ]: 8749 : else if (width == FC_WIDTH_SEMICONDENSED)
456 : 0 : return WIDTH_SEMI_CONDENSED;
457 [ - + ]: 8749 : else if (width == FC_WIDTH_SEMIEXPANDED)
458 : 0 : return WIDTH_SEMI_EXPANDED;
459 [ - + ]: 8749 : else if (width == FC_WIDTH_EXPANDED)
460 : 0 : return WIDTH_EXPANDED;
461 [ - + ]: 8749 : else if (width == FC_WIDTH_EXTRAEXPANDED)
462 : 0 : return WIDTH_EXTRA_EXPANDED;
463 [ - + ]: 8749 : else if (width == FC_WIDTH_ULTRAEXPANDED)
464 : 0 : return WIDTH_ULTRA_EXPANDED;
465 : 8749 : return WIDTH_NORMAL;
466 : : }
467 : : }
468 : :
469 : : //FontConfig doesn't come with a way to remove an element from a FontSet as far
470 : : //as I can see
471 : 944 : static void lcl_FcFontSetRemove(FcFontSet* pFSet, int i)
472 : : {
473 : 944 : FcPatternDestroy(pFSet->fonts[i]);
474 : :
475 : 944 : int nTail = pFSet->nfont - (i + 1);
476 : 944 : --pFSet->nfont;
477 [ - + ]: 944 : if (!nTail)
478 : 944 : return;
479 : 944 : memmove(pFSet->fonts + i, pFSet->fonts + i + 1, nTail*sizeof(FcPattern*));
480 : : }
481 : :
482 : 236 : void PrintFontManager::countFontconfigFonts( boost::unordered_map<rtl::OString, int, rtl::OStringHash>& o_rVisitedPaths )
483 : : {
484 : : #if OSL_DEBUG_LEVEL > 1
485 : : int nFonts = 0;
486 : : #endif
487 : 236 : FontCfgWrapper& rWrapper = FontCfgWrapper::get();
488 : :
489 : 236 : FcFontSet* pFSet = rWrapper.getFontSet();
490 [ + - ]: 236 : if( pFSet )
491 : : {
492 : : #if OSL_DEBUG_LEVEL > 1
493 : : fprintf( stderr, "found %d entries in fontconfig fontset\n", pFSet->nfont );
494 : : #endif
495 [ + + ]: 36774 : for( int i = 0; i < pFSet->nfont; i++ )
496 : : {
497 : 36538 : FcChar8* file = NULL;
498 : 36538 : FcChar8* family = NULL;
499 : 36538 : FcChar8* style = NULL;
500 : 36538 : FcChar8* format = NULL;
501 : 36538 : int slant = 0;
502 : 36538 : int weight = 0;
503 : 36538 : int spacing = 0;
504 : 36538 : int nCollectionEntry = -1;
505 : 36538 : FcBool outline = false;
506 : :
507 [ + - ]: 36538 : FcResult eFileRes = FcPatternGetString(pFSet->fonts[i], FC_FILE, 0, &file);
508 [ + - ]: 36538 : FcResult eFamilyRes = rWrapper.LocalizedElementFromPattern( pFSet->fonts[i], &family, FC_FAMILY, FC_FAMILYLANG );
509 [ + - ]: 36538 : FcResult eStyleRes = rWrapper.LocalizedElementFromPattern( pFSet->fonts[i], &style, FC_STYLE, FC_STYLELANG );
510 [ + - ]: 36538 : FcResult eSlantRes = FcPatternGetInteger(pFSet->fonts[i], FC_SLANT, 0, &slant);
511 [ + - ]: 36538 : FcResult eWeightRes = FcPatternGetInteger(pFSet->fonts[i], FC_WEIGHT, 0, &weight);
512 [ + - ]: 36538 : FcResult eSpacRes = FcPatternGetInteger(pFSet->fonts[i], FC_SPACING, 0, &spacing);
513 [ + - ]: 36538 : FcResult eOutRes = FcPatternGetBool(pFSet->fonts[i], FC_OUTLINE, 0, &outline);
514 [ + - ]: 36538 : FcResult eIndexRes = FcPatternGetInteger(pFSet->fonts[i], FC_INDEX, 0, &nCollectionEntry);
515 [ + - ]: 36538 : FcResult eFormatRes = FcPatternGetString(pFSet->fonts[i], FC_FONTFORMAT, 0, &format);
516 : :
517 [ + - ][ + - ]: 36538 : if( eFileRes != FcResultMatch || eFamilyRes != FcResultMatch || eOutRes != FcResultMatch )
[ - + ]
518 : 0 : continue;
519 : :
520 : : #if (OSL_DEBUG_LEVEL > 2)
521 : : fprintf( stderr, "found font \"%s\" in file %s\n"
522 : : " weight = %d, slant = %d, style = \"%s\"\n"
523 : : " spacing = %d, outline = %d, format %s\n"
524 : : , family, file
525 : : , eWeightRes == FcResultMatch ? weight : -1
526 : : , eSpacRes == FcResultMatch ? slant : -1
527 : : , eStyleRes == FcResultMatch ? (const char*) style : "<nil>"
528 : : , eSpacRes == FcResultMatch ? spacing : -1
529 : : , eOutRes == FcResultMatch ? outline : -1
530 : : , eFormatRes == FcResultMatch ? (const char*)format : "<unknown>"
531 : : );
532 : : #endif
533 : :
534 : : // OSL_ASSERT(eOutRes != FcResultMatch || outline);
535 : :
536 : : // only outline fonts are usable to psprint anyway
537 [ + - ][ - + ]: 36538 : if( eOutRes == FcResultMatch && ! outline )
538 : 0 : continue;
539 : :
540 [ + - ][ + + ]: 36538 : if (isPreviouslyDuplicateOrObsoleted(pFSet, i))
541 : : {
542 : : #if OSL_DEBUG_LEVEL > 2
543 : : fprintf(stderr, "Ditching %s as duplicate/obsolete\n", file);
544 : : #endif
545 : 632 : continue;
546 : : }
547 : :
548 : : // see if this font is already cached
549 : : // update attributes
550 [ + - ]: 35906 : std::list< PrintFont* > aFonts;
551 : 35906 : OString aDir, aBase, aOrgPath( (sal_Char*)file );
552 [ + - ]: 35906 : splitPath( aOrgPath, aDir, aBase );
553 : :
554 [ + - ]: 35906 : o_rVisitedPaths[aDir] = 1;
555 : :
556 [ + - ]: 35906 : int nDirID = getDirectoryAtom( aDir, true );
557 [ + - ][ + + ]: 35906 : if( ! m_pFontCache->getFontCacheFile( nDirID, aBase, aFonts ) )
558 : : {
559 : : #if OSL_DEBUG_LEVEL > 2
560 : : fprintf( stderr, "file %s not cached\n", aBase.getStr() );
561 : : #endif
562 : : // not known, analyze font file to get attributes
563 : : // not described by fontconfig (e.g. alias names, PSName)
564 [ - + ]: 11191 : if (eFormatRes != FcResultMatch)
565 : 0 : format = NULL;
566 [ + - ]: 11191 : analyzeFontFile( nDirID, aBase, aFonts, (const char*)format );
567 : : #if OSL_DEBUG_LEVEL > 1
568 : : if( aFonts.empty() )
569 : : fprintf( stderr, "Warning: file \"%s\" is unusable to psprint\n", aOrgPath.getStr() );
570 : : #endif
571 : : }
572 [ + + ]: 35906 : if( aFonts.empty() )
573 : : {
574 : : //remove font, reuse index
575 : : //we want to remove unusable fonts here, in case there is a usable font
576 : : //which duplicates the properties of the unusable one
577 : : //
578 : : //not removing the unusable font will risk the usable font being rejected
579 : : //as a duplicate by isPreviouslyDuplicateOrObsoleted
580 [ + - ]: 944 : lcl_FcFontSetRemove(pFSet, i--);
581 : 944 : continue;
582 : : }
583 : :
584 [ + - ][ + - ]: 34962 : int nFamilyName = m_pAtoms->getAtom( ATOM_FAMILYNAME, OStringToOUString( OString( (sal_Char*)family ), RTL_TEXTENCODING_UTF8 ), sal_True );
585 [ + - ]: 34962 : PrintFont* pUpdate = aFonts.front();
586 [ + - ]: 34962 : std::list<PrintFont*>::const_iterator second_font = aFonts.begin();
587 [ + - ]: 34962 : ++second_font;
588 [ + - ][ + - ]: 34962 : if( second_font != aFonts.end() ) // more than one font
[ + + ]
589 : : {
590 : : // a collection entry, get the correct index
591 [ + - ][ + - ]: 1652 : if( eIndexRes == FcResultMatch && nCollectionEntry != -1 )
592 : : {
593 [ + - ][ + - ]: 3776 : for( std::list< PrintFont* >::iterator it = aFonts.begin(); it != aFonts.end(); ++it )
[ + - ]
594 : : {
595 [ + - ][ + - ]: 7552 : if( (*it)->m_eType == fonttype::TrueType &&
[ + + ][ + + ]
596 [ + - ]: 3776 : static_cast<TrueTypeFontFile*>(*it)->m_nCollectionEntry == nCollectionEntry )
597 : : {
598 [ + - ]: 1652 : pUpdate = *it;
599 : 1652 : break;
600 : : }
601 : : }
602 : : // update collection entry
603 : : // additional entries will be created in the cache
604 : : // if this is a new index (that is if the loop above
605 : : // ran to the end of the list)
606 [ + - ]: 1652 : if( pUpdate->m_eType == fonttype::TrueType ) // sanity check, this should always be the case here
607 : 1652 : static_cast<TrueTypeFontFile*>(pUpdate)->m_nCollectionEntry = nCollectionEntry;
608 : : }
609 : : else
610 : : {
611 : : #if OSL_DEBUG_LEVEL > 1
612 : : 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 );
613 : : #endif
614 : : // we have found more than one font in this file
615 : : // but fontconfig will not tell us which index is meant
616 : : // -> something is in disorder, do not use this font
617 : 1652 : pUpdate = NULL;
618 : : }
619 : : }
620 : :
621 [ + - ]: 34962 : if( pUpdate )
622 : : {
623 : : // set family name
624 : 34962 : if( pUpdate->m_nFamilyName != nFamilyName )
625 : : {
626 : : }
627 [ + - ]: 34962 : if( eWeightRes == FcResultMatch )
628 : 34962 : pUpdate->m_eWeight = convertWeight(weight);
629 [ + + ]: 34962 : if( eSpacRes == FcResultMatch )
630 : 3544 : pUpdate->m_ePitch = convertSpacing(spacing);
631 [ + - ]: 34962 : if( eSlantRes == FcResultMatch )
632 : 34962 : pUpdate->m_eItalic = convertSlant(slant);
633 [ + - ]: 34962 : if( eStyleRes == FcResultMatch )
634 : : {
635 [ + - ]: 34962 : pUpdate->m_aStyleName = OStringToOUString( OString( (sal_Char*)style ), RTL_TEXTENCODING_UTF8 );
636 : : }
637 : :
638 : : // update font cache
639 [ + - ]: 34962 : m_pFontCache->updateFontCacheEntry( pUpdate, false );
640 : : // sort into known fonts
641 : 34962 : fontID aFont = m_nNextFontID++;
642 [ + - ]: 34962 : m_aFonts[ aFont ] = pUpdate;
643 [ + - ][ + - ]: 34962 : m_aFontFileToFontID[ aBase ].insert( aFont );
644 : : #if OSL_DEBUG_LEVEL > 1
645 : : nFonts++;
646 : : #endif
647 : : #if OSL_DEBUG_LEVEL > 2
648 : : fprintf( stderr, "inserted font %s as fontID %d\n", family, aFont );
649 : : #endif
650 : : }
651 : : // clean up the fonts we did not put into the list
652 [ + - ][ + - ]: 74172 : for( std::list< PrintFont* >::iterator it = aFonts.begin(); it != aFonts.end(); ++it )
[ + + ]
653 : : {
654 [ + - ][ + + ]: 39210 : if( *it != pUpdate )
655 : : {
656 [ + - ][ + - ]: 4248 : m_pFontCache->updateFontCacheEntry( *it, false ); // prepare a cache entry for a collection item
657 [ + - ][ + - ]: 4248 : delete *it;
[ + - ]
658 : : }
659 : : }
660 [ + + ][ + + ]: 36538 : }
[ + + ][ + + ]
661 : : }
662 : :
663 : : // how does one get rid of the config ?
664 : : #if OSL_DEBUG_LEVEL > 1
665 : : fprintf( stderr, "inserted %d fonts from fontconfig\n", nFonts );
666 : : #endif
667 : 236 : }
668 : :
669 : 236 : void PrintFontManager::deinitFontconfig()
670 : : {
671 : 236 : FontCfgWrapper::release();
672 : 236 : }
673 : :
674 : 549 : bool PrintFontManager::addFontconfigDir( const rtl::OString& rDirName )
675 : : {
676 : : // workaround for a stability problems in older FC versions
677 : : // when handling application specifc fonts
678 [ + - ]: 549 : const int nVersion = FcGetVersion();
679 [ - + ]: 549 : if( nVersion <= 20400 )
680 : 0 : return false;
681 : 549 : const char* pDirName = (const char*)rDirName.getStr();
682 [ + - ][ + - ]: 549 : bool bDirOk = (FcConfigAppFontAddDir(FcConfigGetCurrent(), (FcChar8*)pDirName ) == FcTrue);
683 : :
684 : : #if OSL_DEBUG_LEVEL > 1
685 : : fprintf( stderr, "FcConfigAppFontAddDir( \"%s\") => %d\n", pDirName, bDirOk );
686 : : #endif
687 : :
688 [ - + ]: 549 : if( !bDirOk )
689 : 0 : return false;
690 : :
691 : : // load dir-specific fc-config file too if available
692 : 549 : const rtl::OString aConfFileName = rDirName + "/fc_local.conf";
693 [ + - ]: 549 : FILE* pCfgFile = fopen( aConfFileName.getStr(), "rb" );
694 [ + + ]: 549 : if( pCfgFile )
695 : : {
696 [ + - ]: 158 : fclose( pCfgFile);
697 : : bool bCfgOk = FcConfigParseAndLoad(FcConfigGetCurrent(),
698 [ + - ][ + - ]: 158 : (FcChar8*)aConfFileName.getStr(), FcTrue);
699 [ - + ]: 158 : if( !bCfgOk )
700 [ # # ]: 0 : fprintf( stderr, "FcConfigParseAndLoad( \"%s\") => %d\n", aConfFileName.getStr(), bCfgOk );
701 : : }
702 : :
703 : 549 : return true;
704 : : }
705 : :
706 : 8749 : static void addtopattern(FcPattern *pPattern,
707 : : FontItalic eItalic, FontWeight eWeight, FontWidth eWidth, FontPitch ePitch)
708 : : {
709 [ + - ]: 8749 : if( eItalic != ITALIC_DONTKNOW )
710 : : {
711 : 8749 : int nSlant = FC_SLANT_ROMAN;
712 [ + + + ]: 8749 : switch( eItalic )
713 : : {
714 : : case ITALIC_NORMAL:
715 : 494 : nSlant = FC_SLANT_ITALIC;
716 : 494 : break;
717 : : case ITALIC_OBLIQUE:
718 : 302 : nSlant = FC_SLANT_OBLIQUE;
719 : 302 : break;
720 : : default:
721 : 7953 : break;
722 : : }
723 : 8749 : FcPatternAddInteger(pPattern, FC_SLANT, nSlant);
724 : : }
725 [ + + ]: 8749 : if( eWeight != WEIGHT_DONTKNOW )
726 : : {
727 : 5868 : int nWeight = FC_WEIGHT_NORMAL;
728 [ + + + + : 5868 : switch( eWeight )
+ - - + +
+ - ]
729 : : {
730 : 601 : case WEIGHT_THIN: nWeight = FC_WEIGHT_THIN;break;
731 : 22 : case WEIGHT_ULTRALIGHT: nWeight = FC_WEIGHT_ULTRALIGHT;break;
732 : 101 : case WEIGHT_LIGHT: nWeight = FC_WEIGHT_LIGHT;break;
733 : 19 : case WEIGHT_SEMILIGHT: nWeight = FC_WEIGHT_BOOK;break;
734 : 3522 : case WEIGHT_NORMAL: nWeight = FC_WEIGHT_NORMAL;break;
735 : 0 : case WEIGHT_MEDIUM: nWeight = FC_WEIGHT_MEDIUM;break;
736 : 0 : case WEIGHT_SEMIBOLD: nWeight = FC_WEIGHT_SEMIBOLD;break;
737 : 997 : case WEIGHT_BOLD: nWeight = FC_WEIGHT_BOLD;break;
738 : 463 : case WEIGHT_ULTRABOLD: nWeight = FC_WEIGHT_ULTRABOLD;break;
739 : 143 : case WEIGHT_BLACK: nWeight = FC_WEIGHT_BLACK;break;
740 : : default:
741 : 0 : break;
742 : : }
743 : 5868 : FcPatternAddInteger(pPattern, FC_WEIGHT, nWeight);
744 : : }
745 [ - + ]: 8749 : if( eWidth != WIDTH_DONTKNOW )
746 : : {
747 : 0 : int nWidth = FC_WIDTH_NORMAL;
748 [ # # # # : 0 : switch( eWidth )
# # # # #
# ]
749 : : {
750 : 0 : case WIDTH_ULTRA_CONDENSED: nWidth = FC_WIDTH_ULTRACONDENSED;break;
751 : 0 : case WIDTH_EXTRA_CONDENSED: nWidth = FC_WIDTH_EXTRACONDENSED;break;
752 : 0 : case WIDTH_CONDENSED: nWidth = FC_WIDTH_CONDENSED;break;
753 : 0 : case WIDTH_SEMI_CONDENSED: nWidth = FC_WIDTH_SEMICONDENSED;break;
754 : 0 : case WIDTH_NORMAL: nWidth = FC_WIDTH_NORMAL;break;
755 : 0 : case WIDTH_SEMI_EXPANDED: nWidth = FC_WIDTH_SEMIEXPANDED;break;
756 : 0 : case WIDTH_EXPANDED: nWidth = FC_WIDTH_EXPANDED;break;
757 : 0 : case WIDTH_EXTRA_EXPANDED: nWidth = FC_WIDTH_EXTRAEXPANDED;break;
758 : 0 : case WIDTH_ULTRA_EXPANDED: nWidth = FC_WIDTH_ULTRACONDENSED;break;
759 : : default:
760 : 0 : break;
761 : : }
762 : 0 : FcPatternAddInteger(pPattern, FC_WIDTH, nWidth);
763 : : }
764 [ + + ]: 8749 : if( ePitch != PITCH_DONTKNOW )
765 : : {
766 : 4113 : int nSpacing = FC_PROPORTIONAL;
767 [ + + + ]: 4113 : switch( ePitch )
768 : : {
769 : 116 : case PITCH_FIXED: nSpacing = FC_MONO;break;
770 : 2604 : case PITCH_VARIABLE: nSpacing = FC_PROPORTIONAL;break;
771 : : default:
772 : 1393 : break;
773 : : }
774 : 4113 : FcPatternAddInteger(pPattern, FC_SPACING, nSpacing);
775 [ + + ]: 4113 : if (nSpacing == FC_MONO)
776 : 116 : FcPatternAddString(pPattern, FC_FAMILY, (FcChar8*)"monospace");
777 : : }
778 : 8749 : }
779 : :
780 : 8749 : bool PrintFontManager::Substitute( FontSelectPattern &rPattern, rtl::OUString& rMissingCodes )
781 : : {
782 : 8749 : bool bRet = false;
783 : :
784 [ + - ]: 8749 : FontCfgWrapper& rWrapper = FontCfgWrapper::get();
785 : :
786 : : // build pattern argument for fontconfig query
787 [ + - ]: 8749 : FcPattern* pPattern = FcPatternCreate();
788 : :
789 : : // Prefer scalable fonts
790 [ + - ]: 8749 : FcPatternAddBool(pPattern, FC_SCALABLE, FcTrue);
791 : :
792 [ + - ][ + - ]: 8749 : const rtl::OString aTargetName = rtl::OUStringToOString( rPattern.maTargetName, RTL_TEXTENCODING_UTF8 );
793 : 8749 : const FcChar8* pTargetNameUtf8 = (FcChar8*)aTargetName.getStr();
794 [ + - ]: 8749 : FcPatternAddString(pPattern, FC_FAMILY, pTargetNameUtf8);
795 : :
796 [ + - ]: 8749 : const rtl::OString aLangAttrib = MsLangId::convertLanguageToIsoByteString(rPattern.meLanguage);
797 [ + + ]: 8749 : if( !aLangAttrib.isEmpty() )
798 : : {
799 : : const FcChar8* pLangAttribUtf8;
800 [ - + ]: 3539 : if (aLangAttrib.equalsIgnoreAsciiCase(OString(RTL_CONSTASCII_STRINGPARAM("pa-in"))))
801 : 0 : pLangAttribUtf8 = (FcChar8*)"pa";
802 : : else
803 : 3539 : pLangAttribUtf8 = (FcChar8*)aLangAttrib.getStr();
804 [ + - ]: 3539 : FcPatternAddString(pPattern, FC_LANG, pLangAttribUtf8);
805 : : }
806 : :
807 : : // Add required Unicode characters, if any
808 [ + + ]: 8749 : if ( !rMissingCodes.isEmpty() )
809 : : {
810 [ + - ]: 3570 : FcCharSet *unicodes = FcCharSetCreate();
811 [ + + ]: 7173 : for( sal_Int32 nStrIndex = 0; nStrIndex < rMissingCodes.getLength(); )
812 : : {
813 : : // also handle unicode surrogates
814 [ + - ]: 3603 : const sal_uInt32 nCode = rMissingCodes.iterateCodePoints( &nStrIndex );
815 [ + - ]: 3603 : FcCharSetAddChar( unicodes, nCode );
816 : : }
817 [ + - ]: 3570 : FcPatternAddCharSet(pPattern, FC_CHARSET, unicodes);
818 [ + - ]: 3570 : FcCharSetDestroy(unicodes);
819 : : }
820 : :
821 : : addtopattern(pPattern, rPattern.meItalic, rPattern.meWeight,
822 [ + - ]: 8749 : rPattern.meWidthType, rPattern.mePitch);
823 : :
824 : : // query fontconfig for a substitute
825 [ + - ][ + - ]: 8749 : FcConfigSubstitute(FcConfigGetCurrent(), pPattern, FcMatchPattern);
826 [ + - ]: 8749 : FcDefaultSubstitute(pPattern);
827 : :
828 : : // process the result of the fontconfig query
829 : 8749 : FcResult eResult = FcResultNoMatch;
830 [ + - ]: 8749 : FcFontSet* pFontSet = rWrapper.getFontSet();
831 [ + - ][ + - ]: 8749 : FcPattern* pResult = FcFontSetMatch(FcConfigGetCurrent(), &pFontSet, 1, pPattern, &eResult);
832 [ + - ]: 8749 : FcPatternDestroy( pPattern );
833 : :
834 : 8749 : FcFontSet* pSet = NULL;
835 [ + - ]: 8749 : if( pResult )
836 : : {
837 [ + - ]: 8749 : pSet = FcFontSetCreate();
838 : : // info: destroying the pSet destroys pResult implicitly
839 : : // since pResult was "added" to pSet
840 [ + - ]: 8749 : FcFontSetAdd( pSet, pResult );
841 : : }
842 : :
843 [ + - ]: 8749 : if( pSet )
844 : : {
845 [ + - ]: 8749 : if( pSet->nfont > 0 )
846 : : {
847 : : //extract the closest match
848 : 8749 : FcChar8* file = NULL;
849 [ + - ]: 8749 : FcResult eFileRes = FcPatternGetString(pSet->fonts[0], FC_FILE, 0, &file);
850 : 8749 : int nCollectionEntry = 0;
851 [ + - ]: 8749 : FcResult eIndexRes = FcPatternGetInteger(pSet->fonts[0], FC_INDEX, 0, &nCollectionEntry);
852 [ - + ]: 8749 : if (eIndexRes != FcResultMatch)
853 : 0 : nCollectionEntry = 0;
854 [ + - ]: 8749 : if( eFileRes == FcResultMatch )
855 : : {
856 : 8749 : OString aDir, aBase, aOrgPath( (sal_Char*)file );
857 [ + - ]: 8749 : splitPath( aOrgPath, aDir, aBase );
858 [ + - ]: 8749 : int nDirID = getDirectoryAtom( aDir, true );
859 [ + - ]: 8749 : fontID aFont = findFontFileID( nDirID, aBase, nCollectionEntry );
860 [ + - ]: 8749 : if( aFont > 0 )
861 : : {
862 [ + - ]: 8749 : FastPrintFontInfo aInfo;
863 [ + - ]: 8749 : bRet = getFontFastInfo( aFont, aInfo );
864 [ + - ]: 8749 : rPattern.maSearchName = aInfo.m_aFamilyName;
865 : 8749 : }
866 : : }
867 : :
868 : : SAL_WARN_IF(!bRet, "vcl", "no FC_FILE found, falling back to name search");
869 : :
870 [ - + ]: 8749 : if (!bRet)
871 : : {
872 : 0 : FcChar8* family = NULL;
873 [ # # ]: 0 : FcResult eFamilyRes = FcPatternGetString( pSet->fonts[0], FC_FAMILY, 0, &family );
874 : :
875 : : // get the family name
876 [ # # ]: 0 : if( eFamilyRes == FcResultMatch )
877 : : {
878 : 0 : OString sFamily((sal_Char*)family);
879 : : boost::unordered_map< rtl::OString, rtl::OString, rtl::OStringHash >::const_iterator aI =
880 [ # # ]: 0 : rWrapper.m_aFontNameToLocalized.find(sFamily);
881 [ # # ][ # # ]: 0 : if (aI != rWrapper.m_aFontNameToLocalized.end())
882 [ # # ]: 0 : sFamily = aI->second;
883 [ # # ][ # # ]: 0 : rPattern.maSearchName = rtl::OStringToOUString( sFamily, RTL_TEXTENCODING_UTF8 );
884 : 0 : bRet = true;
885 : : }
886 : : }
887 : :
888 [ + - ]: 8749 : if (bRet)
889 : : {
890 : 8749 : int val = 0;
891 [ + - ][ + - ]: 8749 : if (FcResultMatch == FcPatternGetInteger(pSet->fonts[0], FC_WEIGHT, 0, &val))
892 : 8749 : rPattern.meWeight = convertWeight(val);
893 [ + - ][ + - ]: 8749 : if (FcResultMatch == FcPatternGetInteger(pSet->fonts[0], FC_SLANT, 0, &val))
894 : 8749 : rPattern.meItalic = convertSlant(val);
895 [ + - ][ + + ]: 8749 : if (FcResultMatch == FcPatternGetInteger(pSet->fonts[0], FC_SPACING, 0, &val))
896 : 4116 : rPattern.mePitch = convertSpacing(val);
897 [ + - ][ + - ]: 8749 : if (FcResultMatch == FcPatternGetInteger(pSet->fonts[0], FC_WIDTH, 0, &val))
898 : 8749 : rPattern.meWidthType = convertWidth(val);
899 : : FcBool bEmbolden;
900 [ + - ][ - + ]: 8749 : if (FcResultMatch == FcPatternGetBool(pSet->fonts[0], FC_EMBOLDEN, 0, &bEmbolden))
901 : 0 : rPattern.mbEmbolden = bEmbolden;
902 : 8749 : FcMatrix *pMatrix = 0;
903 [ + - ][ - + ]: 8749 : if (FcResultMatch == FcPatternGetMatrix(pSet->fonts[0], FC_MATRIX, 0, &pMatrix))
904 : : {
905 : 0 : rPattern.maItalicMatrix.xx = pMatrix->xx;
906 : 0 : rPattern.maItalicMatrix.xy = pMatrix->xy;
907 : 0 : rPattern.maItalicMatrix.yx = pMatrix->yx;
908 : 8749 : rPattern.maItalicMatrix.yy = pMatrix->yy;
909 : : }
910 : : }
911 : :
912 : : // update rMissingCodes by removing resolved unicodes
913 [ + + ]: 8749 : if( !rMissingCodes.isEmpty() )
914 : : {
915 : 3570 : sal_uInt32* pRemainingCodes = (sal_uInt32*)alloca( rMissingCodes.getLength() * sizeof(sal_uInt32) );
916 : 3570 : int nRemainingLen = 0;
917 : : FcCharSet* unicodes;
918 [ + - ][ + - ]: 3570 : if (!FcPatternGetCharSet(pSet->fonts[0], FC_CHARSET, 0, &unicodes))
919 : : {
920 [ + + ]: 7173 : for( sal_Int32 nStrIndex = 0; nStrIndex < rMissingCodes.getLength(); )
921 : : {
922 : : // also handle unicode surrogates
923 [ + - ]: 3603 : const sal_uInt32 nCode = rMissingCodes.iterateCodePoints( &nStrIndex );
924 [ + - ][ - + ]: 3603 : if (FcCharSetHasChar(unicodes, nCode) != FcTrue)
925 : 0 : pRemainingCodes[ nRemainingLen++ ] = nCode;
926 : : }
927 : : }
928 [ + - ]: 8749 : rMissingCodes = OUString( pRemainingCodes, nRemainingLen );
929 : : }
930 : : }
931 : :
932 [ + - ]: 8749 : FcFontSetDestroy( pSet );
933 : : }
934 : :
935 : 8749 : return bRet;
936 : : }
937 : :
938 : : class FontConfigFontOptions : public ImplFontOptions
939 : : {
940 : : public:
941 : 0 : FontConfigFontOptions() : mpPattern(0) {}
942 : 0 : ~FontConfigFontOptions()
943 : 0 : {
944 [ # # ]: 0 : FcPatternDestroy(mpPattern);
945 [ # # ]: 0 : }
946 : 0 : virtual void *GetPattern(void * face, bool bEmbolden, bool /*bVerticalLayout*/) const
947 : : {
948 : : FcValue value;
949 : 0 : value.type = FcTypeFTFace;
950 : 0 : value.u.f = face;
951 [ # # ]: 0 : FcPatternDel(mpPattern, FC_FT_FACE);
952 [ # # ]: 0 : FcPatternAdd (mpPattern, FC_FT_FACE, value, FcTrue);
953 [ # # ]: 0 : FcPatternDel(mpPattern, FC_EMBOLDEN);
954 [ # # ][ # # ]: 0 : FcPatternAddBool(mpPattern, FC_EMBOLDEN, bEmbolden ? FcTrue : FcFalse);
955 : : #if 0
956 : : FcPatternDel(mpPattern, FC_VERTICAL_LAYOUT);
957 : : FcPatternAddBool(mpPattern, FC_VERTICAL_LAYOUT, bVerticalLayout ? FcTrue : FcFalse);
958 : : #endif
959 : 0 : return mpPattern;
960 : : }
961 : : FcPattern* mpPattern;
962 : : };
963 : :
964 : 0 : ImplFontOptions* PrintFontManager::getFontOptions(
965 : : const FastPrintFontInfo& rInfo, int nSize, void (*subcallback)(void*)) const
966 : : {
967 [ # # ]: 0 : FontCfgWrapper& rWrapper = FontCfgWrapper::get();
968 : :
969 : 0 : FontConfigFontOptions* pOptions = NULL;
970 [ # # ]: 0 : FcConfig* pConfig = FcConfigGetCurrent();
971 [ # # ]: 0 : FcPattern* pPattern = FcPatternCreate();
972 : :
973 [ # # ]: 0 : OString sFamily = OUStringToOString( rInfo.m_aFamilyName, RTL_TEXTENCODING_UTF8 );
974 : :
975 [ # # ]: 0 : boost::unordered_map< rtl::OString, rtl::OString, rtl::OStringHash >::const_iterator aI = rWrapper.m_aLocalizedToCanonical.find(sFamily);
976 [ # # ][ # # ]: 0 : if (aI != rWrapper.m_aLocalizedToCanonical.end())
977 [ # # ]: 0 : sFamily = aI->second;
978 [ # # ]: 0 : if( !sFamily.isEmpty() )
979 [ # # ]: 0 : FcPatternAddString(pPattern, FC_FAMILY, (FcChar8*)sFamily.getStr());
980 : :
981 [ # # ]: 0 : addtopattern(pPattern, rInfo.m_eItalic, rInfo.m_eWeight, rInfo.m_eWidth, rInfo.m_ePitch);
982 [ # # ]: 0 : FcPatternAddDouble(pPattern, FC_PIXEL_SIZE, nSize);
983 : :
984 : 0 : FcBool embitmap = true, antialias = true, autohint = true, hinting = true;
985 : 0 : int hintstyle = FC_HINT_FULL;
986 : :
987 [ # # ]: 0 : FcConfigSubstitute(pConfig, pPattern, FcMatchPattern);
988 [ # # ]: 0 : if (subcallback)
989 [ # # ]: 0 : subcallback(pPattern);
990 [ # # ]: 0 : FcDefaultSubstitute(pPattern);
991 : :
992 : 0 : FcResult eResult = FcResultNoMatch;
993 [ # # ]: 0 : FcFontSet* pFontSet = rWrapper.getFontSet();
994 [ # # ]: 0 : FcPattern* pResult = FcFontSetMatch( pConfig, &pFontSet, 1, pPattern, &eResult );
995 [ # # ]: 0 : if( pResult )
996 : : {
997 : : FcResult eEmbeddedBitmap = FcPatternGetBool(pResult,
998 [ # # ]: 0 : FC_EMBEDDED_BITMAP, 0, &embitmap);
999 : : FcResult eAntialias = FcPatternGetBool(pResult,
1000 [ # # ]: 0 : FC_ANTIALIAS, 0, &antialias);
1001 : : FcResult eAutoHint = FcPatternGetBool(pResult,
1002 [ # # ]: 0 : FC_AUTOHINT, 0, &autohint);
1003 : : FcResult eHinting = FcPatternGetBool(pResult,
1004 [ # # ]: 0 : FC_HINTING, 0, &hinting);
1005 : : /*FcResult eHintStyle =*/ FcPatternGetInteger(pResult,
1006 [ # # ]: 0 : FC_HINT_STYLE, 0, &hintstyle);
1007 : :
1008 [ # # ]: 0 : pOptions = new FontConfigFontOptions;
1009 : :
1010 : 0 : pOptions->mpPattern = pResult;
1011 : :
1012 [ # # ]: 0 : if( eEmbeddedBitmap == FcResultMatch )
1013 [ # # ]: 0 : pOptions->meEmbeddedBitmap = embitmap ? EMBEDDEDBITMAP_TRUE : EMBEDDEDBITMAP_FALSE;
1014 [ # # ]: 0 : if( eAntialias == FcResultMatch )
1015 [ # # ]: 0 : pOptions->meAntiAlias = antialias ? ANTIALIAS_TRUE : ANTIALIAS_FALSE;
1016 [ # # ]: 0 : if( eAutoHint == FcResultMatch )
1017 [ # # ]: 0 : pOptions->meAutoHint = autohint ? AUTOHINT_TRUE : AUTOHINT_FALSE;
1018 [ # # ]: 0 : if( eHinting == FcResultMatch )
1019 [ # # ]: 0 : pOptions->meHinting = hinting ? HINTING_TRUE : HINTING_FALSE;
1020 [ # # # # ]: 0 : switch (hintstyle)
1021 : : {
1022 : 0 : case FC_HINT_NONE: pOptions->meHintStyle = HINT_NONE; break;
1023 : 0 : case FC_HINT_SLIGHT: pOptions->meHintStyle = HINT_SLIGHT; break;
1024 : 0 : case FC_HINT_MEDIUM: pOptions->meHintStyle = HINT_MEDIUM; break;
1025 : : default: // fall through
1026 : 0 : case FC_HINT_FULL: pOptions->meHintStyle = HINT_FULL; break;
1027 : : }
1028 : : }
1029 : :
1030 : : // cleanup
1031 [ # # ]: 0 : FcPatternDestroy( pPattern );
1032 : :
1033 : 0 : return pOptions;
1034 : : }
1035 : :
1036 : 0 : bool PrintFontManager::matchFont( FastPrintFontInfo& rInfo, const com::sun::star::lang::Locale& rLocale )
1037 : : {
1038 [ # # ]: 0 : FontCfgWrapper& rWrapper = FontCfgWrapper::get();
1039 : :
1040 [ # # ]: 0 : FcConfig* pConfig = FcConfigGetCurrent();
1041 [ # # ]: 0 : FcPattern* pPattern = FcPatternCreate();
1042 : :
1043 : 0 : OString aLangAttrib;
1044 : : // populate pattern with font characteristics
1045 [ # # ]: 0 : if( !rLocale.Language.isEmpty() )
1046 : : {
1047 : 0 : OUStringBuffer aLang(6);
1048 [ # # ]: 0 : aLang.append( rLocale.Language );
1049 [ # # ]: 0 : if( !rLocale.Country.isEmpty() )
1050 : : {
1051 [ # # ]: 0 : aLang.append( sal_Unicode('-') );
1052 [ # # ]: 0 : aLang.append( rLocale.Country );
1053 : : }
1054 [ # # ][ # # ]: 0 : aLangAttrib = OUStringToOString( aLang.makeStringAndClear(), RTL_TEXTENCODING_UTF8 );
1055 : : }
1056 [ # # ]: 0 : if( !aLangAttrib.isEmpty() )
1057 [ # # ]: 0 : FcPatternAddString(pPattern, FC_LANG, (FcChar8*)aLangAttrib.getStr());
1058 : :
1059 [ # # ]: 0 : OString aFamily = OUStringToOString( rInfo.m_aFamilyName, RTL_TEXTENCODING_UTF8 );
1060 [ # # ]: 0 : if( !aFamily.isEmpty() )
1061 [ # # ]: 0 : FcPatternAddString(pPattern, FC_FAMILY, (FcChar8*)aFamily.getStr());
1062 : :
1063 [ # # ]: 0 : addtopattern(pPattern, rInfo.m_eItalic, rInfo.m_eWeight, rInfo.m_eWidth, rInfo.m_ePitch);
1064 : :
1065 [ # # ]: 0 : FcConfigSubstitute(pConfig, pPattern, FcMatchPattern);
1066 [ # # ]: 0 : FcDefaultSubstitute(pPattern);
1067 : 0 : FcResult eResult = FcResultNoMatch;
1068 [ # # ]: 0 : FcFontSet *pFontSet = rWrapper.getFontSet();
1069 [ # # ]: 0 : FcPattern* pResult = FcFontSetMatch(pConfig, &pFontSet, 1, pPattern, &eResult);
1070 : 0 : bool bSuccess = false;
1071 [ # # ]: 0 : if( pResult )
1072 : : {
1073 [ # # ]: 0 : FcFontSet* pSet = FcFontSetCreate();
1074 [ # # ]: 0 : FcFontSetAdd( pSet, pResult );
1075 [ # # ]: 0 : if( pSet->nfont > 0 )
1076 : : {
1077 : : //extract the closest match
1078 : 0 : FcChar8* file = NULL;
1079 [ # # ]: 0 : FcResult eFileRes = FcPatternGetString(pSet->fonts[0], FC_FILE, 0, &file);
1080 : 0 : int nCollectionEntry = 0;
1081 [ # # ]: 0 : FcResult eIndexRes = FcPatternGetInteger(pSet->fonts[0], FC_INDEX, 0, &nCollectionEntry);
1082 [ # # ]: 0 : if (eIndexRes != FcResultMatch)
1083 : 0 : nCollectionEntry = 0;
1084 [ # # ]: 0 : if( eFileRes == FcResultMatch )
1085 : : {
1086 : 0 : OString aDir, aBase, aOrgPath( (sal_Char*)file );
1087 [ # # ]: 0 : splitPath( aOrgPath, aDir, aBase );
1088 [ # # ]: 0 : int nDirID = getDirectoryAtom( aDir, true );
1089 [ # # ]: 0 : fontID aFont = findFontFileID( nDirID, aBase, nCollectionEntry );
1090 [ # # ]: 0 : if( aFont > 0 )
1091 [ # # ]: 0 : bSuccess = getFontFastInfo( aFont, rInfo );
1092 : : }
1093 : : }
1094 : : // info: destroying the pSet destroys pResult implicitly
1095 : : // since pResult was "added" to pSet
1096 [ # # ]: 0 : FcFontSetDestroy( pSet );
1097 : : }
1098 : :
1099 : : // cleanup
1100 [ # # ]: 0 : FcPatternDestroy( pPattern );
1101 : :
1102 : 0 : return bSuccess;
1103 : : }
1104 : :
1105 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|