1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "fontcache.hxx"
21 #include "impfont.hxx"
22 #include "fontmanager.hxx"
23 #include <vcl/svapp.hxx>
24 #include <vcl/sysdata.hxx>
25 #include <vcl/vclenum.hxx>
26 #include <vcl/wrkwin.hxx>
27 #include "outfont.hxx"
28 #include <i18nlangtag/languagetag.hxx>
29 #include <i18nutil/unicode.hxx>
30 #include <rtl/strbuf.hxx>
31 #include <unicode/uchar.h>
32 #include <unicode/uscript.h>
36 #include <fontconfig/fontconfig.h>
38 #include <fontconfig/fcfreetype.h>
40 #if defined(ENABLE_DBUS) && defined(ENABLE_PACKAGEKIT)
41 #include <dbus/dbus-glib.h>
47 #include "unotools/atom.hxx"
49 #include "osl/module.h"
50 #include "osl/thread.h"
51 #include "osl/process.h"
53 #include "rtl/ustrbuf.hxx"
55 #include "sal/alloca.h"
64 typedef std::pair
<FcChar8
*, FcChar8
*> lang_and_element
;
69 FcFontSet
* m_pOutlineSet
;
71 void addFontSet( FcSetName
);
77 static FontCfgWrapper
& get();
78 static void release();
80 FcFontSet
* getFontSet();
85 FcResult
LocalizedElementFromPattern(FcPattern
* pPattern
, FcChar8
**family
,
86 const char *elementtype
, const char *elementlangtype
);
87 //to-do, make private and add some cleanish accessor methods
88 std::unordered_map
< OString
, OString
, OStringHash
> m_aFontNameToLocalized
;
89 std::unordered_map
< OString
, OString
, OStringHash
> m_aLocalizedToCanonical
;
91 void cacheLocalizedFontNames(const FcChar8
*origfontname
, const FcChar8
*bestfontname
, const std::vector
< lang_and_element
> &lang_and_elements
);
93 LanguageTag
* m_pLanguageTag
;
96 FontCfgWrapper::FontCfgWrapper()
98 m_pOutlineSet( NULL
),
99 m_pLanguageTag( NULL
)
104 void FontCfgWrapper::addFontSet( FcSetName eSetName
)
107 add only acceptable outlined fonts to our config,
108 for future fontconfig use
110 FcFontSet
* pOrig
= FcConfigGetFonts( FcConfigGetCurrent(), eSetName
);
114 // filter the font sets to remove obsolete faces
115 for( int i
= 0; i
< pOrig
->nfont
; ++i
)
117 FcPattern
* pPattern
= pOrig
->fonts
[i
];
118 // #i115131# ignore non-outline fonts
119 FcBool bOutline
= FcFalse
;
120 FcResult eOutRes
= FcPatternGetBool( pPattern
, FC_OUTLINE
, 0, &bOutline
);
121 if( (eOutRes
!= FcResultMatch
) || (bOutline
== FcFalse
) )
123 FcPatternReference( pPattern
);
124 FcFontSetAdd( m_pOutlineSet
, pPattern
);
127 // TODO?: FcFontSetDestroy( pOrig );
132 int compareFontNames(const FcPattern
*a
, const FcPattern
*b
)
134 FcChar8
*pNameA
=NULL
, *pNameB
=NULL
;
136 bool nHaveA
= FcPatternGetString(a
, FC_FAMILY
, 0, &pNameA
) == FcResultMatch
;
137 bool nHaveB
= FcPatternGetString(b
, FC_FAMILY
, 0, &pNameB
) == FcResultMatch
;
139 if (nHaveA
&& nHaveB
)
140 return strcmp(reinterpret_cast<const char*>(pNameA
), reinterpret_cast<const char*>(pNameB
));
142 return int(nHaveA
) - int(nHaveB
);
145 //Sort fonts so that fonts with the same family name are side-by-side, with
146 //those with higher version numbers first
147 class SortFont
: public ::std::binary_function
< const FcPattern
*, const FcPattern
*, bool >
150 bool operator()(const FcPattern
*a
, const FcPattern
*b
)
152 int comp
= compareFontNames(a
, b
);
156 int nVersionA
=0, nVersionB
=0;
158 bool nHaveA
= FcPatternGetInteger(a
, FC_FONTVERSION
, 0, &nVersionA
) == FcResultMatch
;
159 bool nHaveB
= FcPatternGetInteger(b
, FC_FONTVERSION
, 0, &nVersionB
) == FcResultMatch
;
161 if (nHaveA
&& nHaveB
)
162 return nVersionA
> nVersionB
;
164 return nHaveA
> nHaveB
;
168 //See fdo#30729 for where an old opensymbol installed system-wide can
169 //clobber the new opensymbol installed locally
171 //See if this font is a duplicate with equal attributes which has already been
172 //inserted, or if it an older version of an inserted fonts. Depends on FcFontSet
173 //on being sorted with SortFont
174 bool isPreviouslyDuplicateOrObsoleted(FcFontSet
*pFSet
, int i
)
176 const FcPattern
*a
= pFSet
->fonts
[i
];
178 FcPattern
* pTestPatternA
= FcPatternDuplicate(a
);
179 FcPatternDel(pTestPatternA
, FC_FILE
);
180 FcPatternDel(pTestPatternA
, FC_CHARSET
);
181 FcPatternDel(pTestPatternA
, FC_CAPABILITY
);
182 FcPatternDel(pTestPatternA
, FC_FONTVERSION
);
183 FcPatternDel(pTestPatternA
, FC_LANG
);
187 // fdo#66715: loop for case of several font files for same font
188 for (int j
= i
- 1; 0 <= j
&& !bIsDup
; --j
)
190 const FcPattern
*b
= pFSet
->fonts
[j
];
192 if (compareFontNames(a
, b
) != 0)
195 FcPattern
* pTestPatternB
= FcPatternDuplicate(b
);
196 FcPatternDel(pTestPatternB
, FC_FILE
);
197 FcPatternDel(pTestPatternB
, FC_CHARSET
);
198 FcPatternDel(pTestPatternB
, FC_CAPABILITY
);
199 FcPatternDel(pTestPatternB
, FC_FONTVERSION
);
200 FcPatternDel(pTestPatternB
, FC_LANG
);
202 bIsDup
= FcPatternEqual(pTestPatternA
, pTestPatternB
);
204 FcPatternDestroy(pTestPatternB
);
207 FcPatternDestroy(pTestPatternA
);
213 FcFontSet
* FontCfgWrapper::getFontSet()
217 m_pOutlineSet
= FcFontSetCreate();
218 addFontSet( FcSetSystem
);
219 if( FcGetVersion() > 20400 ) // #i85462# prevent crashes
220 addFontSet( FcSetApplication
);
222 ::std::sort(m_pOutlineSet
->fonts
,m_pOutlineSet
->fonts
+m_pOutlineSet
->nfont
,SortFont());
225 return m_pOutlineSet
;
228 FontCfgWrapper::~FontCfgWrapper()
231 //To-Do: get gtk vclplug smoketest to pass
235 static FontCfgWrapper
* pOneInstance
= NULL
;
237 FontCfgWrapper
& FontCfgWrapper::get()
240 pOneInstance
= new FontCfgWrapper();
241 return *pOneInstance
;
244 void FontCfgWrapper::release()
255 static FcChar8
* bestname(const std::vector
<lang_and_element
> &elements
, const LanguageTag
& rLangTag
);
257 FcChar8
* bestname(const std::vector
<lang_and_element
> &elements
, const LanguageTag
& rLangTag
)
259 FcChar8
* candidate
= elements
.begin()->second
;
260 /* FIXME-BCP47: once fontconfig supports language tags this
261 * language-territory stuff needs to be changed! */
262 SAL_INFO_IF( !rLangTag
.isIsoLocale(), "i18n", "localizedsorter::bestname - not an ISO locale");
263 OString
sLangMatch(OUStringToOString(rLangTag
.getLanguage().toAsciiLowerCase(), RTL_TEXTENCODING_UTF8
));
264 OString sFullMatch
= sLangMatch
;
265 sFullMatch
+= OString('-');
266 sFullMatch
+= OUStringToOString(rLangTag
.getCountry().toAsciiLowerCase(), RTL_TEXTENCODING_UTF8
);
268 std::vector
<lang_and_element
>::const_iterator aEnd
= elements
.end();
269 bool alreadyclosematch
= false;
270 bool found_fallback_englishname
= false;
271 for( std::vector
<lang_and_element
>::const_iterator aIter
= elements
.begin(); aIter
!= aEnd
; ++aIter
)
273 const char *pLang
= reinterpret_cast<const char*>(aIter
->first
);
274 if( rtl_str_compare( pLang
, sFullMatch
.getStr() ) == 0)
276 // both language and country match
277 candidate
= aIter
->second
;
280 else if( alreadyclosematch
)
282 // current candidate matches lang of lang-TERRITORY
283 // override candidate only if there is a full match
286 else if( rtl_str_compare( pLang
, sLangMatch
.getStr()) == 0)
288 // just the language matches
289 candidate
= aIter
->second
;
290 alreadyclosematch
= true;
292 else if( found_fallback_englishname
)
294 // already found an english fallback, don't override candidate
295 // unless there is a better language match
298 else if( rtl_str_compare( pLang
, "en") == 0)
300 // select a fallback candidate of the first english element
302 candidate
= aIter
->second
;
303 found_fallback_englishname
= true;
310 //Set up maps to quickly map between a fonts best UI name and all the rest of its names, and vice versa
311 void FontCfgWrapper::cacheLocalizedFontNames(const FcChar8
*origfontname
, const FcChar8
*bestfontname
,
312 const std::vector
< lang_and_element
> &lang_and_elements
)
314 std::vector
<lang_and_element
>::const_iterator aEnd
= lang_and_elements
.end();
315 for (std::vector
<lang_and_element
>::const_iterator aIter
= lang_and_elements
.begin(); aIter
!= aEnd
; ++aIter
)
317 const char *candidate
= reinterpret_cast<const char*>(aIter
->second
);
318 if (rtl_str_compare(candidate
, reinterpret_cast<const char*>(bestfontname
)) != 0)
319 m_aFontNameToLocalized
[OString(candidate
)] = OString(reinterpret_cast<const char*>(bestfontname
));
321 if (rtl_str_compare(reinterpret_cast<const char*>(origfontname
), reinterpret_cast<const char*>(bestfontname
)) != 0)
322 m_aLocalizedToCanonical
[OString(reinterpret_cast<const char*>(bestfontname
))] = OString(reinterpret_cast<const char*>(origfontname
));
325 FcResult
FontCfgWrapper::LocalizedElementFromPattern(FcPattern
* pPattern
, FcChar8
**element
,
326 const char *elementtype
, const char *elementlangtype
)
327 { /* e. g.: ^ FC_FAMILY ^ FC_FAMILYLANG */
328 FcChar8
*origelement
;
329 FcResult eElementRes
= FcPatternGetString( pPattern
, elementtype
, 0, &origelement
);
330 *element
= origelement
;
332 if( eElementRes
== FcResultMatch
)
334 FcChar8
* elementlang
= NULL
;
335 if (FcPatternGetString( pPattern
, elementlangtype
, 0, &elementlang
) == FcResultMatch
)
337 std::vector
< lang_and_element
> lang_and_elements
;
338 lang_and_elements
.push_back(lang_and_element(elementlang
, *element
));
342 if (FcPatternGetString( pPattern
, elementlangtype
, k
, &elementlang
) != FcResultMatch
)
344 if (FcPatternGetString( pPattern
, elementtype
, k
, element
) != FcResultMatch
)
346 lang_and_elements
.push_back(lang_and_element(elementlang
, *element
));
350 //possible to-do, sort by UILocale instead of process locale
353 rtl_Locale
* pLoc
= NULL
;
354 osl_getProcessLocale(&pLoc
);
355 m_pLanguageTag
= new LanguageTag(*pLoc
);
357 *element
= bestname(lang_and_elements
, *m_pLanguageTag
);
359 //if this element is a fontname, map the other names to this best-name
360 if (rtl_str_compare(elementtype
, FC_FAMILY
) == 0)
361 cacheLocalizedFontNames(origelement
, *element
, lang_and_elements
);
368 void FontCfgWrapper::clear()
370 m_aFontNameToLocalized
.clear();
371 m_aLocalizedToCanonical
.clear();
374 FcFontSetDestroy( m_pOutlineSet
);
375 m_pOutlineSet
= NULL
;
377 delete m_pLanguageTag
;
378 m_pLanguageTag
= NULL
;
382 * PrintFontManager::initFontconfig
384 void PrintFontManager::initFontconfig()
386 FontCfgWrapper
& rWrapper
= FontCfgWrapper::get();
392 FontWeight
convertWeight(int weight
)
395 if( weight
<= FC_WEIGHT_THIN
)
397 else if( weight
<= FC_WEIGHT_ULTRALIGHT
)
398 return WEIGHT_ULTRALIGHT
;
399 else if( weight
<= FC_WEIGHT_LIGHT
)
401 else if( weight
<= FC_WEIGHT_BOOK
)
402 return WEIGHT_SEMILIGHT
;
403 else if( weight
<= FC_WEIGHT_NORMAL
)
404 return WEIGHT_NORMAL
;
405 else if( weight
<= FC_WEIGHT_MEDIUM
)
406 return WEIGHT_MEDIUM
;
407 else if( weight
<= FC_WEIGHT_SEMIBOLD
)
408 return WEIGHT_SEMIBOLD
;
409 else if( weight
<= FC_WEIGHT_BOLD
)
411 else if( weight
<= FC_WEIGHT_ULTRABOLD
)
412 return WEIGHT_ULTRABOLD
;
416 FontItalic
convertSlant(int slant
)
419 if( slant
== FC_SLANT_ITALIC
)
420 return ITALIC_NORMAL
;
421 else if( slant
== FC_SLANT_OBLIQUE
)
422 return ITALIC_OBLIQUE
;
426 FontPitch
convertSpacing(int spacing
)
429 if( spacing
== FC_MONO
|| spacing
== FC_CHARCELL
)
431 return PITCH_VARIABLE
;
434 // translation: fontconfig enum -> vcl enum
435 FontWidth
convertWidth(int width
)
437 if (width
== FC_WIDTH_ULTRACONDENSED
)
438 return WIDTH_ULTRA_CONDENSED
;
439 else if (width
== FC_WIDTH_EXTRACONDENSED
)
440 return WIDTH_EXTRA_CONDENSED
;
441 else if (width
== FC_WIDTH_CONDENSED
)
442 return WIDTH_CONDENSED
;
443 else if (width
== FC_WIDTH_SEMICONDENSED
)
444 return WIDTH_SEMI_CONDENSED
;
445 else if (width
== FC_WIDTH_SEMIEXPANDED
)
446 return WIDTH_SEMI_EXPANDED
;
447 else if (width
== FC_WIDTH_EXPANDED
)
448 return WIDTH_EXPANDED
;
449 else if (width
== FC_WIDTH_EXTRAEXPANDED
)
450 return WIDTH_EXTRA_EXPANDED
;
451 else if (width
== FC_WIDTH_ULTRAEXPANDED
)
452 return WIDTH_ULTRA_EXPANDED
;
457 //FontConfig doesn't come with a way to remove an element from a FontSet as far
459 static void lcl_FcFontSetRemove(FcFontSet
* pFSet
, int i
)
461 FcPatternDestroy(pFSet
->fonts
[i
]);
463 int nTail
= pFSet
->nfont
- (i
+ 1);
467 memmove(pFSet
->fonts
+ i
, pFSet
->fonts
+ i
+ 1, nTail
*sizeof(FcPattern
*));
470 void PrintFontManager::countFontconfigFonts( std::unordered_map
<OString
, int, OStringHash
>& o_rVisitedPaths
)
472 #if OSL_DEBUG_LEVEL > 1
475 FontCfgWrapper
& rWrapper
= FontCfgWrapper::get();
477 FcFontSet
* pFSet
= rWrapper
.getFontSet();
480 #if OSL_DEBUG_LEVEL > 1
481 fprintf( stderr
, "found %d entries in fontconfig fontset\n", pFSet
->nfont
);
483 for( int i
= 0; i
< pFSet
->nfont
; i
++ )
485 FcChar8
* file
= NULL
;
486 FcChar8
* family
= NULL
;
487 FcChar8
* style
= NULL
;
488 FcChar8
* format
= NULL
;
493 int nCollectionEntry
= -1;
494 FcBool outline
= false;
496 FcResult eFileRes
= FcPatternGetString(pFSet
->fonts
[i
], FC_FILE
, 0, &file
);
497 FcResult eFamilyRes
= rWrapper
.LocalizedElementFromPattern( pFSet
->fonts
[i
], &family
, FC_FAMILY
, FC_FAMILYLANG
);
498 FcResult eStyleRes
= rWrapper
.LocalizedElementFromPattern( pFSet
->fonts
[i
], &style
, FC_STYLE
, FC_STYLELANG
);
499 FcResult eSlantRes
= FcPatternGetInteger(pFSet
->fonts
[i
], FC_SLANT
, 0, &slant
);
500 FcResult eWeightRes
= FcPatternGetInteger(pFSet
->fonts
[i
], FC_WEIGHT
, 0, &weight
);
501 FcResult eWidthRes
= FcPatternGetInteger(pFSet
->fonts
[i
], FC_WIDTH
, 0, &width
);
502 FcResult eSpacRes
= FcPatternGetInteger(pFSet
->fonts
[i
], FC_SPACING
, 0, &spacing
);
503 FcResult eOutRes
= FcPatternGetBool(pFSet
->fonts
[i
], FC_OUTLINE
, 0, &outline
);
504 FcResult eIndexRes
= FcPatternGetInteger(pFSet
->fonts
[i
], FC_INDEX
, 0, &nCollectionEntry
);
505 FcResult eFormatRes
= FcPatternGetString(pFSet
->fonts
[i
], FC_FONTFORMAT
, 0, &format
);
507 if( eFileRes
!= FcResultMatch
|| eFamilyRes
!= FcResultMatch
|| eOutRes
!= FcResultMatch
)
510 #if (OSL_DEBUG_LEVEL > 2)
511 fprintf( stderr
, "found font \"%s\" in file %s\n"
512 " weight = %d, slant = %d, style = \"%s\"\n"
513 " width = %d, spacing = %d, outline = %d, format %s\n"
515 , eWeightRes
== FcResultMatch
? weight
: -1
516 , eSpacRes
== FcResultMatch
? slant
: -1
517 , eStyleRes
== FcResultMatch
? (const char*) style
: "<nil>"
518 , eWeightRes
== FcResultMatch
? width
: -1
519 , eSpacRes
== FcResultMatch
? spacing
: -1
520 , eOutRes
== FcResultMatch
? outline
: -1
521 , eFormatRes
== FcResultMatch
? (const char*)format
: "<unknown>"
525 // OSL_ASSERT(eOutRes != FcResultMatch || outline);
527 // only outline fonts are usable to psprint anyway
528 if( eOutRes
== FcResultMatch
&& ! outline
)
531 if (isPreviouslyDuplicateOrObsoleted(pFSet
, i
))
533 #if OSL_DEBUG_LEVEL > 2
534 fprintf(stderr
, "Ditching %s as duplicate/obsolete\n", file
);
539 // see if this font is already cached
541 std::list
< PrintFont
* > aFonts
;
542 OString aDir
, aBase
, aOrgPath( reinterpret_cast<char*>(file
) );
543 splitPath( aOrgPath
, aDir
, aBase
);
545 o_rVisitedPaths
[aDir
] = 1;
547 int nDirID
= getDirectoryAtom( aDir
, true );
548 if( ! m_pFontCache
->getFontCacheFile( nDirID
, aBase
, aFonts
) )
550 #if OSL_DEBUG_LEVEL > 2
551 fprintf( stderr
, "file %s not cached\n", aBase
.getStr() );
553 // not known, analyze font file to get attributes
554 // not described by fontconfig (e.g. alias names, PSName)
555 if (eFormatRes
!= FcResultMatch
)
557 analyzeFontFile( nDirID
, aBase
, aFonts
, reinterpret_cast<char*>(format
) );
558 #if OSL_DEBUG_LEVEL > 1
560 fprintf( stderr
, "Warning: file \"%s\" is unusable to psprint\n", aOrgPath
.getStr() );
565 //remove font, reuse index
566 //we want to remove unusable fonts here, in case there is a usable font
567 //which duplicates the properties of the unusable one
569 //not removing the unusable font will risk the usable font being rejected
570 //as a duplicate by isPreviouslyDuplicateOrObsoleted
571 lcl_FcFontSetRemove(pFSet
, i
--);
575 int nFamilyName
= m_pAtoms
->getAtom( ATOM_FAMILYNAME
, OStringToOUString( OString( reinterpret_cast<char*>(family
) ), RTL_TEXTENCODING_UTF8
), true );
576 PrintFont
* pUpdate
= aFonts
.front();
577 std::list
<PrintFont
*>::const_iterator second_font
= aFonts
.begin();
579 if( second_font
!= aFonts
.end() ) // more than one font
581 // a collection entry, get the correct index
582 if( eIndexRes
== FcResultMatch
&& nCollectionEntry
!= -1 )
584 for( std::list
< PrintFont
* >::iterator it
= aFonts
.begin(); it
!= aFonts
.end(); ++it
)
586 if( (*it
)->m_eType
== fonttype::TrueType
&&
587 static_cast<TrueTypeFontFile
*>(*it
)->m_nCollectionEntry
== nCollectionEntry
)
593 // update collection entry
594 // additional entries will be created in the cache
595 // if this is a new index (that is if the loop above
596 // ran to the end of the list)
597 if( pUpdate
->m_eType
== fonttype::TrueType
) // sanity check, this should always be the case here
598 static_cast<TrueTypeFontFile
*>(pUpdate
)->m_nCollectionEntry
= nCollectionEntry
;
602 #if OSL_DEBUG_LEVEL > 1
603 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
);
605 // we have found more than one font in this file
606 // but fontconfig will not tell us which index is meant
607 // -> something is in disorder, do not use this font
615 if( pUpdate
->m_nFamilyName
!= nFamilyName
)
618 if( eWeightRes
== FcResultMatch
)
619 pUpdate
->m_eWeight
= convertWeight(weight
);
620 if( eWidthRes
== FcResultMatch
)
621 pUpdate
->m_eWidth
= convertWidth(width
);
622 if( eSpacRes
== FcResultMatch
)
623 pUpdate
->m_ePitch
= convertSpacing(spacing
);
624 if( eSlantRes
== FcResultMatch
)
625 pUpdate
->m_eItalic
= convertSlant(slant
);
626 if( eStyleRes
== FcResultMatch
)
628 pUpdate
->m_aStyleName
= OStringToOUString( OString( reinterpret_cast<char*>(style
) ), RTL_TEXTENCODING_UTF8
);
632 m_pFontCache
->updateFontCacheEntry( pUpdate
, false );
633 // sort into known fonts
634 fontID aFont
= m_nNextFontID
++;
635 m_aFonts
[ aFont
] = pUpdate
;
636 m_aFontFileToFontID
[ aBase
].insert( aFont
);
637 #if OSL_DEBUG_LEVEL > 1
640 #if OSL_DEBUG_LEVEL > 2
641 fprintf( stderr
, "inserted font %s as fontID %d\n", family
, aFont
);
644 // clean up the fonts we did not put into the list
645 for( std::list
< PrintFont
* >::iterator it
= aFonts
.begin(); it
!= aFonts
.end(); ++it
)
649 m_pFontCache
->updateFontCacheEntry( *it
, false ); // prepare a cache entry for a collection item
656 // how does one get rid of the config ?
657 #if OSL_DEBUG_LEVEL > 1
658 fprintf( stderr
, "inserted %d fonts from fontconfig\n", nFonts
);
662 void PrintFontManager::deinitFontconfig()
664 FontCfgWrapper::release();
667 bool PrintFontManager::addFontconfigDir( const OString
& rDirName
)
669 // workaround for a stability problems in older FC versions
670 // when handling application specific fonts
671 const int nVersion
= FcGetVersion();
672 if( nVersion
<= 20400 )
674 const char* pDirName
= (const char*)rDirName
.getStr();
675 bool bDirOk
= (FcConfigAppFontAddDir(FcConfigGetCurrent(), reinterpret_cast<FcChar8
const *>(pDirName
) ) == FcTrue
);
677 #if OSL_DEBUG_LEVEL > 1
678 fprintf( stderr
, "FcConfigAppFontAddDir( \"%s\") => %d\n", pDirName
, bDirOk
);
684 // load dir-specific fc-config file too if available
685 const OString aConfFileName
= rDirName
+ "/fc_local.conf";
686 FILE* pCfgFile
= fopen( aConfFileName
.getStr(), "rb" );
690 bool bCfgOk
= FcConfigParseAndLoad(FcConfigGetCurrent(),
691 reinterpret_cast<FcChar8
const *>(aConfFileName
.getStr()), FcTrue
);
693 fprintf( stderr
, "FcConfigParseAndLoad( \"%s\") => %d\n", aConfFileName
.getStr(), bCfgOk
);
699 static void addtopattern(FcPattern
*pPattern
,
700 FontItalic eItalic
, FontWeight eWeight
, FontWidth eWidth
, FontPitch ePitch
)
702 if( eItalic
!= ITALIC_DONTKNOW
)
704 int nSlant
= FC_SLANT_ROMAN
;
708 nSlant
= FC_SLANT_ITALIC
;
711 nSlant
= FC_SLANT_OBLIQUE
;
716 FcPatternAddInteger(pPattern
, FC_SLANT
, nSlant
);
718 if( eWeight
!= WEIGHT_DONTKNOW
)
720 int nWeight
= FC_WEIGHT_NORMAL
;
723 case WEIGHT_THIN
: nWeight
= FC_WEIGHT_THIN
;break;
724 case WEIGHT_ULTRALIGHT
: nWeight
= FC_WEIGHT_ULTRALIGHT
;break;
725 case WEIGHT_LIGHT
: nWeight
= FC_WEIGHT_LIGHT
;break;
726 case WEIGHT_SEMILIGHT
: nWeight
= FC_WEIGHT_BOOK
;break;
727 case WEIGHT_NORMAL
: nWeight
= FC_WEIGHT_NORMAL
;break;
728 case WEIGHT_MEDIUM
: nWeight
= FC_WEIGHT_MEDIUM
;break;
729 case WEIGHT_SEMIBOLD
: nWeight
= FC_WEIGHT_SEMIBOLD
;break;
730 case WEIGHT_BOLD
: nWeight
= FC_WEIGHT_BOLD
;break;
731 case WEIGHT_ULTRABOLD
: nWeight
= FC_WEIGHT_ULTRABOLD
;break;
732 case WEIGHT_BLACK
: nWeight
= FC_WEIGHT_BLACK
;break;
736 FcPatternAddInteger(pPattern
, FC_WEIGHT
, nWeight
);
738 if( eWidth
!= WIDTH_DONTKNOW
)
740 int nWidth
= FC_WIDTH_NORMAL
;
743 case WIDTH_ULTRA_CONDENSED
: nWidth
= FC_WIDTH_ULTRACONDENSED
;break;
744 case WIDTH_EXTRA_CONDENSED
: nWidth
= FC_WIDTH_EXTRACONDENSED
;break;
745 case WIDTH_CONDENSED
: nWidth
= FC_WIDTH_CONDENSED
;break;
746 case WIDTH_SEMI_CONDENSED
: nWidth
= FC_WIDTH_SEMICONDENSED
;break;
747 case WIDTH_NORMAL
: nWidth
= FC_WIDTH_NORMAL
;break;
748 case WIDTH_SEMI_EXPANDED
: nWidth
= FC_WIDTH_SEMIEXPANDED
;break;
749 case WIDTH_EXPANDED
: nWidth
= FC_WIDTH_EXPANDED
;break;
750 case WIDTH_EXTRA_EXPANDED
: nWidth
= FC_WIDTH_EXTRAEXPANDED
;break;
751 case WIDTH_ULTRA_EXPANDED
: nWidth
= FC_WIDTH_ULTRAEXPANDED
;break;
755 FcPatternAddInteger(pPattern
, FC_WIDTH
, nWidth
);
757 if( ePitch
!= PITCH_DONTKNOW
)
759 int nSpacing
= FC_PROPORTIONAL
;
762 case PITCH_FIXED
: nSpacing
= FC_MONO
;break;
763 case PITCH_VARIABLE
: nSpacing
= FC_PROPORTIONAL
;break;
767 FcPatternAddInteger(pPattern
, FC_SPACING
, nSpacing
);
768 if (nSpacing
== FC_MONO
)
769 FcPatternAddString(pPattern
, FC_FAMILY
, reinterpret_cast<FcChar8
const *>("monospace"));
775 //Someday fontconfig will hopefully use bcp47, see fdo#19869
776 //In the meantime try something that will fit to workaround fdo#35118
777 OString
mapToFontConfigLangTag(const LanguageTag
&rLangTag
)
779 #if defined(FC_VERSION) && (FC_VERSION >= 20492)
780 std::shared_ptr
<FcStrSet
> xLangSet(FcGetLangs(), FcStrSetDestroy
);
783 sLangAttrib
= OUStringToOString(rLangTag
.getBcp47(), RTL_TEXTENCODING_UTF8
).toAsciiLowerCase();
784 if (FcStrSetMember(xLangSet
.get(), reinterpret_cast<const FcChar8
*>(sLangAttrib
.getStr())))
789 sLangAttrib
= OUStringToOString(rLangTag
.getLanguageAndScript(), RTL_TEXTENCODING_UTF8
).toAsciiLowerCase();
790 if (FcStrSetMember(xLangSet
.get(), reinterpret_cast<const FcChar8
*>(sLangAttrib
.getStr())))
795 OString sLang
= OUStringToOString(rLangTag
.getLanguage(), RTL_TEXTENCODING_UTF8
).toAsciiLowerCase();
796 OString sRegion
= OUStringToOString(rLangTag
.getCountry(), RTL_TEXTENCODING_UTF8
).toAsciiLowerCase();
798 if (!sRegion
.isEmpty())
800 sLangAttrib
= sLang
+ OString('-') + sRegion
;
801 if (FcStrSetMember(xLangSet
.get(), reinterpret_cast<const FcChar8
*>(sLangAttrib
.getStr())))
807 if (FcStrSetMember(xLangSet
.get(), reinterpret_cast<const FcChar8
*>(sLang
.getStr())))
814 OString sLangAttrib
= OUStringToOString(rLangTag
.getLanguageAndScript(), RTL_TEXTENCODING_UTF8
).toAsciiLowerCase();
815 if (sLangAttrib
.equalsIgnoreAsciiCase("pa-in"))
821 //returns true if the given code-point couldn't possibly be in rLangTag.
822 bool isImpossibleCodePointForLang(const LanguageTag
&rLangTag
, sal_uInt32 currentChar
)
824 //a non-default script is set, lets believe it
825 if (rLangTag
.hasScript())
828 int32_t script
= u_getIntPropertyValue(currentChar
, UCHAR_SCRIPT
);
829 UScriptCode eScript
= static_cast<UScriptCode
>(script
);
830 bool bIsImpossible
= false;
831 OUString sLang
= rLangTag
.getLanguage();
834 //http://en.wiktionary.org/wiki/Category:Oriya_script_languages
840 //http://en.wiktionary.org/wiki/Category:Telugu_script_languages
847 //http://en.wiktionary.org/wiki/Category:Bengali_script_languages
848 case USCRIPT_BENGALI
:
859 SAL_WARN_IF(bIsImpossible
, "vcl", "In glyph fallback throwing away the language property of "
860 << sLang
<< " because the detected script for '0x"
861 << OUString::number(currentChar
, 16)
862 << "' is " << uscript_getName(eScript
)
863 << " and that language doesn't make sense. Autodetecting instead.");
864 return bIsImpossible
;
867 LanguageTag
getExemplarLangTagForCodePoint(sal_uInt32 currentChar
)
869 int32_t script
= u_getIntPropertyValue(currentChar
, UCHAR_SCRIPT
);
870 UScriptCode eScript
= static_cast<UScriptCode
>(script
);
871 OStringBuffer
aBuf(unicode::getExemplarLanguageForUScriptCode(eScript
));
872 const char* pScriptCode
= uscript_getShortName(eScript
);
874 aBuf
.append('-').append(pScriptCode
);
875 return LanguageTag(OStringToOUString(aBuf
.makeStringAndClear(), RTL_TEXTENCODING_UTF8
));
878 #if defined(ENABLE_DBUS) && defined(ENABLE_PACKAGEKIT)
879 guint
get_xid_for_dbus()
881 const vcl::Window
*pTopWindow
= Application::IsHeadlessModeEnabled() ? NULL
: Application::GetActiveTopWindow();
882 const SystemEnvData
* pEnvData
= pTopWindow
? pTopWindow
->GetSystemData() : NULL
;
883 return pEnvData
? pEnvData
->aWindow
: 0;
888 IMPL_LINK_NOARG_TYPED(PrintFontManager
, autoInstallFontLangSupport
, Timer
*, void)
890 #if defined(ENABLE_DBUS) && defined(ENABLE_PACKAGEKIT)
891 guint xid
= get_xid_for_dbus();
896 GError
*error
= NULL
;
897 /* get the DBUS session connection */
898 DBusGConnection
*session_connection
= dbus_g_bus_get(DBUS_BUS_SESSION
, &error
);
901 g_debug ("DBUS cannot connect : %s", error
->message
);
902 g_error_free (error
);
906 /* get the proxy with gnome-session-manager */
907 DBusGProxy
*proxy
= dbus_g_proxy_new_for_name(session_connection
,
908 "org.freedesktop.PackageKit",
909 "/org/freedesktop/PackageKit",
910 "org.freedesktop.PackageKit.Modify");
913 g_debug("Could not get DBUS proxy: org.freedesktop.PackageKit");
917 gchar
**fonts
= static_cast<gchar
**>(g_malloc((m_aCurrentRequests
.size() + 1) * sizeof(gchar
*)));
918 gchar
**font
= fonts
;
919 for (std::vector
<OString
>::const_iterator aI
= m_aCurrentRequests
.begin(); aI
!= m_aCurrentRequests
.end(); ++aI
)
920 *font
++ = const_cast<gchar
*>(aI
->getStr());
922 gboolean res
= dbus_g_proxy_call(proxy
, "InstallFontconfigResources", &error
,
923 G_TYPE_UINT
, xid
, /* xid */
924 G_TYPE_STRV
, fonts
, /* data */
925 G_TYPE_STRING
, "hide-finished", /* interaction */
928 /* check the return value */
930 g_debug("InstallFontconfigResources method failed");
932 /* check the error value */
935 g_debug("InstallFontconfigResources problem : %s", error
->message
);
940 g_object_unref(G_OBJECT (proxy
));
941 m_aCurrentRequests
.clear();
945 bool PrintFontManager::Substitute( FontSelectPattern
&rPattern
, OUString
& rMissingCodes
)
949 FontCfgWrapper
& rWrapper
= FontCfgWrapper::get();
951 // build pattern argument for fontconfig query
952 FcPattern
* pPattern
= FcPatternCreate();
954 // Prefer scalable fonts
955 FcPatternAddBool(pPattern
, FC_SCALABLE
, FcTrue
);
957 const OString aTargetName
= OUStringToOString( rPattern
.maTargetName
, RTL_TEXTENCODING_UTF8
);
958 const FcChar8
* pTargetNameUtf8
= reinterpret_cast<FcChar8
const *>(aTargetName
.getStr());
959 FcPatternAddString(pPattern
, FC_FAMILY
, pTargetNameUtf8
);
961 LanguageTag
aLangTag(rPattern
.meLanguage
);
962 OString aLangAttrib
= mapToFontConfigLangTag(aLangTag
);
964 // Add required Unicode characters, if any
965 if ( !rMissingCodes
.isEmpty() )
967 FcCharSet
*unicodes
= FcCharSetCreate();
968 for( sal_Int32 nStrIndex
= 0; nStrIndex
< rMissingCodes
.getLength(); )
970 // also handle unicode surrogates
971 const sal_uInt32 nCode
= rMissingCodes
.iterateCodePoints( &nStrIndex
);
972 FcCharSetAddChar( unicodes
, nCode
);
973 //if the codepoint is impossible for this lang tag, then clear it
974 //and autodetect something useful
975 if (!aLangAttrib
.isEmpty() && isImpossibleCodePointForLang(aLangTag
, nCode
))
977 //#i105784#/rhbz#527719 improve selection of fallback font
978 if (aLangAttrib
.isEmpty())
980 aLangTag
= getExemplarLangTagForCodePoint(nCode
);
981 aLangAttrib
= mapToFontConfigLangTag(aLangTag
);
984 FcPatternAddCharSet(pPattern
, FC_CHARSET
, unicodes
);
985 FcCharSetDestroy(unicodes
);
988 if (!aLangAttrib
.isEmpty())
989 FcPatternAddString(pPattern
, FC_LANG
, reinterpret_cast<FcChar8
const *>(aLangAttrib
.getStr()));
991 addtopattern(pPattern
, rPattern
.GetSlant(), rPattern
.GetWeight(),
992 rPattern
.GetWidthType(), rPattern
.GetPitch());
994 // query fontconfig for a substitute
995 FcConfigSubstitute(FcConfigGetCurrent(), pPattern
, FcMatchPattern
);
996 FcDefaultSubstitute(pPattern
);
998 // process the result of the fontconfig query
999 FcResult eResult
= FcResultNoMatch
;
1000 FcFontSet
* pFontSet
= rWrapper
.getFontSet();
1001 FcPattern
* pResult
= FcFontSetMatch(FcConfigGetCurrent(), &pFontSet
, 1, pPattern
, &eResult
);
1002 FcPatternDestroy( pPattern
);
1004 FcFontSet
* pSet
= NULL
;
1007 pSet
= FcFontSetCreate();
1008 // info: destroying the pSet destroys pResult implicitly
1009 // since pResult was "added" to pSet
1010 FcFontSetAdd( pSet
, pResult
);
1015 if( pSet
->nfont
> 0 )
1017 //extract the closest match
1018 FcChar8
* file
= NULL
;
1019 FcResult eFileRes
= FcPatternGetString(pSet
->fonts
[0], FC_FILE
, 0, &file
);
1020 int nCollectionEntry
= 0;
1021 FcResult eIndexRes
= FcPatternGetInteger(pSet
->fonts
[0], FC_INDEX
, 0, &nCollectionEntry
);
1022 if (eIndexRes
!= FcResultMatch
)
1023 nCollectionEntry
= 0;
1024 if( eFileRes
== FcResultMatch
)
1026 OString aDir
, aBase
, aOrgPath( reinterpret_cast<char*>(file
) );
1027 splitPath( aOrgPath
, aDir
, aBase
);
1028 int nDirID
= getDirectoryAtom( aDir
, true );
1029 fontID aFont
= findFontFileID( nDirID
, aBase
, nCollectionEntry
);
1032 FastPrintFontInfo aInfo
;
1033 bRet
= getFontFastInfo( aFont
, aInfo
);
1034 rPattern
.maSearchName
= aInfo
.m_aFamilyName
;
1038 SAL_WARN_IF(!bRet
, "vcl", "no FC_FILE found, falling back to name search");
1042 FcChar8
* family
= NULL
;
1043 FcResult eFamilyRes
= FcPatternGetString( pSet
->fonts
[0], FC_FAMILY
, 0, &family
);
1045 // get the family name
1046 if( eFamilyRes
== FcResultMatch
)
1048 OString
sFamily(reinterpret_cast<char*>(family
));
1049 std::unordered_map
< OString
, OString
, OStringHash
>::const_iterator aI
=
1050 rWrapper
.m_aFontNameToLocalized
.find(sFamily
);
1051 if (aI
!= rWrapper
.m_aFontNameToLocalized
.end())
1052 sFamily
= aI
->second
;
1053 rPattern
.maSearchName
= OStringToOUString( sFamily
, RTL_TEXTENCODING_UTF8
);
1061 if (FcResultMatch
== FcPatternGetInteger(pSet
->fonts
[0], FC_WEIGHT
, 0, &val
))
1062 rPattern
.SetWeight( convertWeight(val
) );
1063 if (FcResultMatch
== FcPatternGetInteger(pSet
->fonts
[0], FC_SLANT
, 0, &val
))
1064 rPattern
.SetItalic( convertSlant(val
) );
1065 if (FcResultMatch
== FcPatternGetInteger(pSet
->fonts
[0], FC_SPACING
, 0, &val
))
1066 rPattern
.SetPitch ( convertSpacing(val
) );
1067 if (FcResultMatch
== FcPatternGetInteger(pSet
->fonts
[0], FC_WIDTH
, 0, &val
))
1068 rPattern
.SetWidthType ( convertWidth(val
) );
1070 if (FcResultMatch
== FcPatternGetBool(pSet
->fonts
[0], FC_EMBOLDEN
, 0, &bEmbolden
))
1071 rPattern
.mbEmbolden
= bEmbolden
;
1072 FcMatrix
*pMatrix
= 0;
1073 if (FcResultMatch
== FcPatternGetMatrix(pSet
->fonts
[0], FC_MATRIX
, 0, &pMatrix
))
1075 rPattern
.maItalicMatrix
.xx
= pMatrix
->xx
;
1076 rPattern
.maItalicMatrix
.xy
= pMatrix
->xy
;
1077 rPattern
.maItalicMatrix
.yx
= pMatrix
->yx
;
1078 rPattern
.maItalicMatrix
.yy
= pMatrix
->yy
;
1082 // update rMissingCodes by removing resolved unicodes
1083 if( !rMissingCodes
.isEmpty() )
1085 sal_uInt32
* pRemainingCodes
= static_cast<sal_uInt32
*>(alloca( rMissingCodes
.getLength() * sizeof(sal_uInt32
) ));
1086 int nRemainingLen
= 0;
1087 FcCharSet
* unicodes
;
1088 if (!FcPatternGetCharSet(pSet
->fonts
[0], FC_CHARSET
, 0, &unicodes
))
1090 for( sal_Int32 nStrIndex
= 0; nStrIndex
< rMissingCodes
.getLength(); )
1092 // also handle unicode surrogates
1093 const sal_uInt32 nCode
= rMissingCodes
.iterateCodePoints( &nStrIndex
);
1094 if (FcCharSetHasChar(unicodes
, nCode
) != FcTrue
)
1095 pRemainingCodes
[ nRemainingLen
++ ] = nCode
;
1098 OUString
sStillMissing(pRemainingCodes
, nRemainingLen
);
1099 #if defined(ENABLE_DBUS) && defined(ENABLE_PACKAGEKIT)
1100 if (get_xid_for_dbus())
1102 if (sStillMissing
== rMissingCodes
) //replaced nothing
1104 //It'd be better if we could ask packagekit using the
1105 //missing codepoints or some such rather than using
1106 //"language" as a proxy to how fontconfig considers
1107 //scripts to default to a given language.
1108 for (sal_Int32 i
= 0; i
< nRemainingLen
; ++i
)
1110 LanguageTag aOurTag
= getExemplarLangTagForCodePoint(pRemainingCodes
[i
]);
1111 OString sTag
= OUStringToOString(aOurTag
.getBcp47(), RTL_TEXTENCODING_UTF8
);
1112 if (m_aPreviousLangSupportRequests
.find(sTag
) != m_aPreviousLangSupportRequests
.end())
1114 m_aPreviousLangSupportRequests
.insert(sTag
);
1115 sTag
= mapToFontConfigLangTag(aOurTag
);
1116 if (!sTag
.isEmpty() && m_aPreviousLangSupportRequests
.find(sTag
) == m_aPreviousLangSupportRequests
.end())
1118 OString sReq
= OString(":lang=") + sTag
;
1119 m_aCurrentRequests
.push_back(sReq
);
1120 m_aPreviousLangSupportRequests
.insert(sTag
);
1124 if (!m_aCurrentRequests
.empty())
1126 m_aFontInstallerTimer
.Stop();
1127 m_aFontInstallerTimer
.Start();
1131 rMissingCodes
= sStillMissing
;
1135 FcFontSetDestroy( pSet
);
1141 class FontConfigFontOptions
: public ImplFontOptions
1144 FontConfigFontOptions() : mpPattern(0) {}
1145 virtual ~FontConfigFontOptions()
1147 FcPatternDestroy(mpPattern
);
1149 virtual void *GetPattern(void * face
, bool bEmbolden
, bool /*bVerticalLayout*/) const SAL_OVERRIDE
1152 value
.type
= FcTypeFTFace
;
1154 FcPatternDel(mpPattern
, FC_FT_FACE
);
1155 FcPatternAdd (mpPattern
, FC_FT_FACE
, value
, FcTrue
);
1156 FcPatternDel(mpPattern
, FC_EMBOLDEN
);
1157 FcPatternAddBool(mpPattern
, FC_EMBOLDEN
, bEmbolden
? FcTrue
: FcFalse
);
1159 FcPatternDel(mpPattern
, FC_VERTICAL_LAYOUT
);
1160 FcPatternAddBool(mpPattern
, FC_VERTICAL_LAYOUT
, bVerticalLayout
? FcTrue
: FcFalse
);
1164 FcPattern
* mpPattern
;
1167 ImplFontOptions
* PrintFontManager::getFontOptions(
1168 const FastPrintFontInfo
& rInfo
, int nSize
, void (*subcallback
)(void*))
1170 FontCfgWrapper
& rWrapper
= FontCfgWrapper::get();
1172 FontConfigFontOptions
* pOptions
= NULL
;
1173 FcConfig
* pConfig
= FcConfigGetCurrent();
1174 FcPattern
* pPattern
= FcPatternCreate();
1176 OString sFamily
= OUStringToOString( rInfo
.m_aFamilyName
, RTL_TEXTENCODING_UTF8
);
1178 std::unordered_map
< OString
, OString
, OStringHash
>::const_iterator aI
= rWrapper
.m_aLocalizedToCanonical
.find(sFamily
);
1179 if (aI
!= rWrapper
.m_aLocalizedToCanonical
.end())
1180 sFamily
= aI
->second
;
1181 if( !sFamily
.isEmpty() )
1182 FcPatternAddString(pPattern
, FC_FAMILY
, reinterpret_cast<FcChar8
const *>(sFamily
.getStr()));
1184 addtopattern(pPattern
, rInfo
.m_eItalic
, rInfo
.m_eWeight
, rInfo
.m_eWidth
, rInfo
.m_ePitch
);
1185 FcPatternAddDouble(pPattern
, FC_PIXEL_SIZE
, nSize
);
1187 FcBool embitmap
= true, antialias
= true, autohint
= true, hinting
= true;
1188 int hintstyle
= FC_HINT_FULL
;
1190 FcConfigSubstitute(pConfig
, pPattern
, FcMatchPattern
);
1192 subcallback(pPattern
);
1193 FcDefaultSubstitute(pPattern
);
1195 FcResult eResult
= FcResultNoMatch
;
1196 FcFontSet
* pFontSet
= rWrapper
.getFontSet();
1197 FcPattern
* pResult
= FcFontSetMatch( pConfig
, &pFontSet
, 1, pPattern
, &eResult
);
1200 FcResult eEmbeddedBitmap
= FcPatternGetBool(pResult
,
1201 FC_EMBEDDED_BITMAP
, 0, &embitmap
);
1202 FcResult eAntialias
= FcPatternGetBool(pResult
,
1203 FC_ANTIALIAS
, 0, &antialias
);
1204 FcResult eAutoHint
= FcPatternGetBool(pResult
,
1205 FC_AUTOHINT
, 0, &autohint
);
1206 FcResult eHinting
= FcPatternGetBool(pResult
,
1207 FC_HINTING
, 0, &hinting
);
1208 (void) FcPatternGetInteger(pResult
,
1209 FC_HINT_STYLE
, 0, &hintstyle
);
1211 pOptions
= new FontConfigFontOptions
;
1213 pOptions
->mpPattern
= pResult
;
1215 if( eEmbeddedBitmap
== FcResultMatch
)
1216 pOptions
->meEmbeddedBitmap
= embitmap
? EMBEDDEDBITMAP_TRUE
: EMBEDDEDBITMAP_FALSE
;
1217 if( eAntialias
== FcResultMatch
)
1218 pOptions
->meAntiAlias
= antialias
? ANTIALIAS_TRUE
: ANTIALIAS_FALSE
;
1219 if( eAutoHint
== FcResultMatch
)
1220 pOptions
->meAutoHint
= autohint
? AUTOHINT_TRUE
: AUTOHINT_FALSE
;
1221 if( eHinting
== FcResultMatch
)
1222 pOptions
->meHinting
= hinting
? HINTING_TRUE
: HINTING_FALSE
;
1225 case FC_HINT_NONE
: pOptions
->meHintStyle
= HINT_NONE
; break;
1226 case FC_HINT_SLIGHT
: pOptions
->meHintStyle
= HINT_SLIGHT
; break;
1227 case FC_HINT_MEDIUM
: pOptions
->meHintStyle
= HINT_MEDIUM
; break;
1228 default: // fall through
1229 case FC_HINT_FULL
: pOptions
->meHintStyle
= HINT_FULL
; break;
1234 FcPatternDestroy( pPattern
);
1239 bool PrintFontManager::matchFont( FastPrintFontInfo
& rInfo
, const com::sun::star::lang::Locale
& rLocale
)
1241 FontCfgWrapper
& rWrapper
= FontCfgWrapper::get();
1243 FcConfig
* pConfig
= FcConfigGetCurrent();
1244 FcPattern
* pPattern
= FcPatternCreate();
1246 // populate pattern with font characteristics
1247 const LanguageTag
aLangTag(rLocale
);
1248 const OString aLangAttrib
= mapToFontConfigLangTag(aLangTag
);
1249 if (!aLangAttrib
.isEmpty())
1250 FcPatternAddString(pPattern
, FC_LANG
, reinterpret_cast<FcChar8
const *>(aLangAttrib
.getStr()));
1252 OString aFamily
= OUStringToOString( rInfo
.m_aFamilyName
, RTL_TEXTENCODING_UTF8
);
1253 if( !aFamily
.isEmpty() )
1254 FcPatternAddString(pPattern
, FC_FAMILY
, reinterpret_cast<FcChar8
const *>(aFamily
.getStr()));
1256 addtopattern(pPattern
, rInfo
.m_eItalic
, rInfo
.m_eWeight
, rInfo
.m_eWidth
, rInfo
.m_ePitch
);
1258 FcConfigSubstitute(pConfig
, pPattern
, FcMatchPattern
);
1259 FcDefaultSubstitute(pPattern
);
1260 FcResult eResult
= FcResultNoMatch
;
1261 FcFontSet
*pFontSet
= rWrapper
.getFontSet();
1262 FcPattern
* pResult
= FcFontSetMatch(pConfig
, &pFontSet
, 1, pPattern
, &eResult
);
1263 bool bSuccess
= false;
1266 FcFontSet
* pSet
= FcFontSetCreate();
1267 FcFontSetAdd( pSet
, pResult
);
1268 if( pSet
->nfont
> 0 )
1270 //extract the closest match
1271 FcChar8
* file
= NULL
;
1272 FcResult eFileRes
= FcPatternGetString(pSet
->fonts
[0], FC_FILE
, 0, &file
);
1273 int nCollectionEntry
= 0;
1274 FcResult eIndexRes
= FcPatternGetInteger(pSet
->fonts
[0], FC_INDEX
, 0, &nCollectionEntry
);
1275 if (eIndexRes
!= FcResultMatch
)
1276 nCollectionEntry
= 0;
1277 if( eFileRes
== FcResultMatch
)
1279 OString aDir
, aBase
, aOrgPath( reinterpret_cast<char*>(file
) );
1280 splitPath( aOrgPath
, aDir
, aBase
);
1281 int nDirID
= getDirectoryAtom( aDir
, true );
1282 fontID aFont
= findFontFileID( nDirID
, aBase
, nCollectionEntry
);
1284 bSuccess
= getFontFastInfo( aFont
, rInfo
);
1287 // info: destroying the pSet destroys pResult implicitly
1288 // since pResult was "added" to pSet
1289 FcFontSetDestroy( pSet
);
1293 FcPatternDestroy( pPattern
);
1298 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */