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 .
21 #include "fontcache.hxx"
22 #include "impfont.hxx"
23 #include <vcl/fontmanager.hxx>
24 #include <vcl/svapp.hxx>
25 #include <vcl/sysdata.hxx>
26 #include <vcl/vclenum.hxx>
27 #include <vcl/wrkwin.hxx>
28 #include "outfont.hxx"
29 #include <i18nlangtag/languagetag.hxx>
30 #include <i18nutil/unicode.hxx>
31 #include <rtl/strbuf.hxx>
32 #include <unicode/uchar.h>
33 #include <unicode/uscript.h>
37 #include <fontconfig/fontconfig.h>
39 #include <fontconfig/fcfreetype.h>
40 // allow compile on baseline (currently with fontconfig 2.2.0)
41 #ifndef FC_WEIGHT_BOOK // TODO: remove when baseline moves to fc>=2.2.1
42 #define FC_WEIGHT_BOOK 75
44 #ifndef FC_EMBEDDED_BITMAP // TODO: remove when baseline moves to fc>=2.3.92
45 #define FC_EMBEDDED_BITMAP "embeddedbitmap"
47 #ifndef FC_FAMILYLANG // TODO: remove when baseline moves to fc>=2.2.97
48 #define FC_FAMILYLANG "familylang"
50 #ifndef FC_CAPABILITY // TODO: remove when baseline moves to fc>=2.2.97
51 #define FC_CAPABILITY "capability"
53 #ifndef FC_STYLELANG // TODO: remove when baseline moves to fc>=2.2.97
54 #define FC_STYLELANG "stylelang"
56 #ifndef FC_HINT_STYLE // TODO: remove when baseline moves to fc>=2.2.91
57 #define FC_HINT_STYLE "hintstyle"
58 #define FC_HINT_NONE 0
59 #define FC_HINT_SLIGHT 1
60 #define FC_HINT_MEDIUM 2
61 #define FC_HINT_FULL 3
64 #define FC_FT_FACE "ftface"
67 #define FC_EMBOLDEN "embolden"
70 #define FC_MATRIX "matrix"
73 #define FC_FONTFORMAT "fontformat"
76 #if defined(ENABLE_DBUS) && defined(ENABLE_PACKAGEKIT)
77 #include <dbus/dbus-glib.h>
83 #include "unotools/atom.hxx"
85 #include "osl/module.h"
86 #include "osl/thread.h"
87 #include "osl/process.h"
89 #include "rtl/ustrbuf.hxx"
91 #include "sal/alloca.h"
100 typedef std::pair
<FcChar8
*, FcChar8
*> lang_and_element
;
105 FcFontSet
* m_pOutlineSet
;
107 void addFontSet( FcSetName
);
113 static FontCfgWrapper
& get();
114 static void release();
116 FcFontSet
* getFontSet();
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
< OString
, OString
, OStringHash
> m_aFontNameToLocalized
;
125 boost::unordered_map
< OString
, OString
, OStringHash
> m_aLocalizedToCanonical
;
127 void cacheLocalizedFontNames(const FcChar8
*origfontname
, const FcChar8
*bestfontname
, const std::vector
< lang_and_element
> &lang_and_elements
);
129 LanguageTag
* m_pLanguageTag
;
132 FontCfgWrapper::FontCfgWrapper()
134 m_pOutlineSet( NULL
),
135 m_pLanguageTag( NULL
)
140 void FontCfgWrapper::addFontSet( FcSetName eSetName
)
143 add only acceptable outlined fonts to our config,
144 for future fontconfig use
146 FcFontSet
* pOrig
= FcConfigGetFonts( FcConfigGetCurrent(), eSetName
);
150 // filter the font sets to remove obsolete faces
151 for( int i
= 0; i
< pOrig
->nfont
; ++i
)
153 FcPattern
* pPattern
= pOrig
->fonts
[i
];
154 // #i115131# ignore non-outline fonts
155 FcBool bOutline
= FcFalse
;
156 FcResult eOutRes
= FcPatternGetBool( pPattern
, FC_OUTLINE
, 0, &bOutline
);
157 if( (eOutRes
!= FcResultMatch
) || (bOutline
== FcFalse
) )
159 FcPatternReference( pPattern
);
160 FcFontSetAdd( m_pOutlineSet
, pPattern
);
163 // TODO?: FcFontSetDestroy( pOrig );
168 int compareFontNames(const FcPattern
*a
, const FcPattern
*b
)
170 FcChar8
*pNameA
=NULL
, *pNameB
=NULL
;
172 int nHaveA
= FcPatternGetString(a
, FC_FAMILY
, 0, &pNameA
) == FcResultMatch
;
173 int nHaveB
= FcPatternGetString(b
, FC_FAMILY
, 0, &pNameB
) == FcResultMatch
;
175 if (nHaveA
&& nHaveB
)
176 return strcmp((const char*)pNameA
, (const char*)pNameB
);
178 return nHaveA
- nHaveB
;
181 //Sort fonts so that fonts with the same family name are side-by-side, with
182 //those with higher version numbers first
183 class SortFont
: public ::std::binary_function
< const FcPattern
*, const FcPattern
*, bool >
186 bool operator()(const FcPattern
*a
, const FcPattern
*b
)
188 int comp
= compareFontNames(a
, b
);
192 int nVersionA
=0, nVersionB
=0;
194 int nHaveA
= FcPatternGetInteger(a
, FC_FONTVERSION
, 0, &nVersionA
) == FcResultMatch
;
195 int nHaveB
= FcPatternGetInteger(b
, FC_FONTVERSION
, 0, &nVersionB
) == FcResultMatch
;
197 if (nHaveA
&& nHaveB
)
198 return nVersionA
> nVersionB
;
200 return nHaveA
> nHaveB
;
204 //See fdo#30729 for where an old opensymbol installed system-wide can
205 //clobber the new opensymbol installed locally
207 //See if this font is a duplicate with equal attributes which has already been
208 //inserted, or if it an older version of an inserted fonts. Depends on FcFontSet
209 //on being sorted with SortFont
210 bool isPreviouslyDuplicateOrObsoleted(FcFontSet
*pFSet
, int i
)
212 const FcPattern
*a
= pFSet
->fonts
[i
];
214 FcPattern
* pTestPatternA
= FcPatternDuplicate(a
);
215 FcPatternDel(pTestPatternA
, FC_FILE
);
216 FcPatternDel(pTestPatternA
, FC_CHARSET
);
217 FcPatternDel(pTestPatternA
, FC_CAPABILITY
);
218 FcPatternDel(pTestPatternA
, FC_FONTVERSION
);
219 FcPatternDel(pTestPatternA
, FC_LANG
);
223 // fdo#66715: loop for case of several font files for same font
224 for (int j
= i
- 1; 0 <= j
&& !bIsDup
; --j
)
226 const FcPattern
*b
= pFSet
->fonts
[j
];
228 if (compareFontNames(a
, b
) != 0)
231 FcPattern
* pTestPatternB
= FcPatternDuplicate(b
);
232 FcPatternDel(pTestPatternB
, FC_FILE
);
233 FcPatternDel(pTestPatternB
, FC_CHARSET
);
234 FcPatternDel(pTestPatternB
, FC_CAPABILITY
);
235 FcPatternDel(pTestPatternB
, FC_FONTVERSION
);
236 FcPatternDel(pTestPatternB
, FC_LANG
);
238 bIsDup
= FcPatternEqual(pTestPatternA
, pTestPatternB
);
240 FcPatternDestroy(pTestPatternB
);
243 FcPatternDestroy(pTestPatternA
);
249 FcFontSet
* FontCfgWrapper::getFontSet()
253 m_pOutlineSet
= FcFontSetCreate();
254 addFontSet( FcSetSystem
);
255 if( FcGetVersion() > 20400 ) // #i85462# prevent crashes
256 addFontSet( FcSetApplication
);
258 ::std::sort(m_pOutlineSet
->fonts
,m_pOutlineSet
->fonts
+m_pOutlineSet
->nfont
,SortFont());
261 return m_pOutlineSet
;
264 FontCfgWrapper::~FontCfgWrapper()
267 //To-Do: get gtk vclplug smoketest to pass
271 static FontCfgWrapper
* pOneInstance
= NULL
;
273 FontCfgWrapper
& FontCfgWrapper::get()
276 pOneInstance
= new FontCfgWrapper();
277 return *pOneInstance
;
280 void FontCfgWrapper::release()
291 class localizedsorter
294 localizedsorter() {};
295 FcChar8
* bestname(const std::vector
<lang_and_element
> &elements
, const LanguageTag
& rLangTag
);
298 FcChar8
* localizedsorter::bestname(const std::vector
<lang_and_element
> &elements
, const LanguageTag
& rLangTag
)
300 FcChar8
* candidate
= elements
.begin()->second
;
301 /* FIXME-BCP47: once fontconfig supports language tags this
302 * language-territory stuff needs to be changed! */
303 SAL_INFO_IF( !rLangTag
.isIsoLocale(), "i18n", "localizedsorter::bestname - not an ISO locale");
304 OString
sLangMatch(OUStringToOString(rLangTag
.getLanguage().toAsciiLowerCase(), RTL_TEXTENCODING_UTF8
));
305 OString sFullMatch
= sLangMatch
;
306 sFullMatch
+= OString('-');
307 sFullMatch
+= OUStringToOString(rLangTag
.getCountry().toAsciiLowerCase(), RTL_TEXTENCODING_UTF8
);
309 std::vector
<lang_and_element
>::const_iterator aEnd
= elements
.end();
310 bool alreadyclosematch
= false;
311 bool found_fallback_englishname
= false;
312 for( std::vector
<lang_and_element
>::const_iterator aIter
= elements
.begin(); aIter
!= aEnd
; ++aIter
)
314 const char *pLang
= (const char*)aIter
->first
;
315 if( rtl_str_compare( pLang
, sFullMatch
.getStr() ) == 0)
317 // both language and country match
318 candidate
= aIter
->second
;
321 else if( alreadyclosematch
)
323 // current candidate matches lang of lang-TERRITORY
324 // override candidate only if there is a full match
327 else if( rtl_str_compare( pLang
, sLangMatch
.getStr()) == 0)
329 // just the language matches
330 candidate
= aIter
->second
;
331 alreadyclosematch
= true;
333 else if( found_fallback_englishname
)
335 // already found an english fallback, don't override candidate
336 // unless there is a better language match
339 else if( rtl_str_compare( pLang
, "en") == 0)
341 // select a fallback candidate of the first english element
343 candidate
= aIter
->second
;
344 found_fallback_englishname
= true;
351 //Set up maps to quickly map between a fonts best UI name and all the rest of its names, and vice versa
352 void FontCfgWrapper::cacheLocalizedFontNames(const FcChar8
*origfontname
, const FcChar8
*bestfontname
,
353 const std::vector
< lang_and_element
> &lang_and_elements
)
355 std::vector
<lang_and_element
>::const_iterator aEnd
= lang_and_elements
.end();
356 for (std::vector
<lang_and_element
>::const_iterator aIter
= lang_and_elements
.begin(); aIter
!= aEnd
; ++aIter
)
358 const char *candidate
= (const char*)(aIter
->second
);
359 if (rtl_str_compare(candidate
, (const char*)bestfontname
) != 0)
360 m_aFontNameToLocalized
[OString(candidate
)] = OString((const char*)bestfontname
);
362 if (rtl_str_compare((const char*)origfontname
, (const char*)bestfontname
) != 0)
363 m_aLocalizedToCanonical
[OString((const char*)bestfontname
)] = OString((const char*)origfontname
);
366 FcResult
FontCfgWrapper::LocalizedElementFromPattern(FcPattern
* pPattern
, FcChar8
**element
,
367 const char *elementtype
, const char *elementlangtype
)
368 { /* e. g.: ^ FC_FAMILY ^ FC_FAMILYLANG */
369 FcChar8
*origelement
;
370 FcResult eElementRes
= FcPatternGetString( pPattern
, elementtype
, 0, &origelement
);
371 *element
= origelement
;
373 if( eElementRes
== FcResultMatch
)
375 FcChar8
* elementlang
= NULL
;
376 if (FcPatternGetString( pPattern
, elementlangtype
, 0, &elementlang
) == FcResultMatch
)
378 std::vector
< lang_and_element
> lang_and_elements
;
379 lang_and_elements
.push_back(lang_and_element(elementlang
, *element
));
383 if (FcPatternGetString( pPattern
, elementlangtype
, k
, &elementlang
) != FcResultMatch
)
385 if (FcPatternGetString( pPattern
, elementtype
, k
, element
) != FcResultMatch
)
387 lang_and_elements
.push_back(lang_and_element(elementlang
, *element
));
391 //possible to-do, sort by UILocale instead of process locale
394 rtl_Locale
* pLoc
= NULL
;
395 osl_getProcessLocale(&pLoc
);
396 m_pLanguageTag
= new LanguageTag(*pLoc
);
398 *element
= localizedsorter().bestname(lang_and_elements
, *m_pLanguageTag
);
400 //if this element is a fontname, map the other names to this best-name
401 if (rtl_str_compare(elementtype
, FC_FAMILY
) == 0)
402 cacheLocalizedFontNames(origelement
, *element
, lang_and_elements
);
409 void FontCfgWrapper::clear()
411 m_aFontNameToLocalized
.clear();
412 m_aLocalizedToCanonical
.clear();
415 FcFontSetDestroy( m_pOutlineSet
);
416 m_pOutlineSet
= NULL
;
418 delete m_pLanguageTag
;
419 m_pLanguageTag
= NULL
;
423 * PrintFontManager::initFontconfig
425 void PrintFontManager::initFontconfig()
427 FontCfgWrapper
& rWrapper
= FontCfgWrapper::get();
433 FontWeight
convertWeight(int weight
)
436 if( weight
<= FC_WEIGHT_THIN
)
438 else if( weight
<= FC_WEIGHT_ULTRALIGHT
)
439 return WEIGHT_ULTRALIGHT
;
440 else if( weight
<= FC_WEIGHT_LIGHT
)
442 else if( weight
<= FC_WEIGHT_BOOK
)
443 return WEIGHT_SEMILIGHT
;
444 else if( weight
<= FC_WEIGHT_NORMAL
)
445 return WEIGHT_NORMAL
;
446 else if( weight
<= FC_WEIGHT_MEDIUM
)
447 return WEIGHT_MEDIUM
;
448 else if( weight
<= FC_WEIGHT_SEMIBOLD
)
449 return WEIGHT_SEMIBOLD
;
450 else if( weight
<= FC_WEIGHT_BOLD
)
452 else if( weight
<= FC_WEIGHT_ULTRABOLD
)
453 return WEIGHT_ULTRABOLD
;
457 FontItalic
convertSlant(int slant
)
460 if( slant
== FC_SLANT_ITALIC
)
461 return ITALIC_NORMAL
;
462 else if( slant
== FC_SLANT_OBLIQUE
)
463 return ITALIC_OBLIQUE
;
467 FontPitch
convertSpacing(int spacing
)
470 if( spacing
== FC_MONO
|| spacing
== FC_CHARCELL
)
472 return PITCH_VARIABLE
;
475 // translation: fontconfig enum -> vcl enum
476 FontWidth
convertWidth(int width
)
478 if (width
== FC_WIDTH_ULTRACONDENSED
)
479 return WIDTH_ULTRA_CONDENSED
;
480 else if (width
== FC_WIDTH_EXTRACONDENSED
)
481 return WIDTH_EXTRA_CONDENSED
;
482 else if (width
== FC_WIDTH_CONDENSED
)
483 return WIDTH_CONDENSED
;
484 else if (width
== FC_WIDTH_SEMICONDENSED
)
485 return WIDTH_SEMI_CONDENSED
;
486 else if (width
== FC_WIDTH_SEMIEXPANDED
)
487 return WIDTH_SEMI_EXPANDED
;
488 else if (width
== FC_WIDTH_EXPANDED
)
489 return WIDTH_EXPANDED
;
490 else if (width
== FC_WIDTH_EXTRAEXPANDED
)
491 return WIDTH_EXTRA_EXPANDED
;
492 else if (width
== FC_WIDTH_ULTRAEXPANDED
)
493 return WIDTH_ULTRA_EXPANDED
;
498 //FontConfig doesn't come with a way to remove an element from a FontSet as far
500 static void lcl_FcFontSetRemove(FcFontSet
* pFSet
, int i
)
502 FcPatternDestroy(pFSet
->fonts
[i
]);
504 int nTail
= pFSet
->nfont
- (i
+ 1);
508 memmove(pFSet
->fonts
+ i
, pFSet
->fonts
+ i
+ 1, nTail
*sizeof(FcPattern
*));
511 void PrintFontManager::countFontconfigFonts( boost::unordered_map
<OString
, int, OStringHash
>& o_rVisitedPaths
)
513 #if OSL_DEBUG_LEVEL > 1
516 FontCfgWrapper
& rWrapper
= FontCfgWrapper::get();
518 FcFontSet
* pFSet
= rWrapper
.getFontSet();
521 #if OSL_DEBUG_LEVEL > 1
522 fprintf( stderr
, "found %d entries in fontconfig fontset\n", pFSet
->nfont
);
524 for( int i
= 0; i
< pFSet
->nfont
; i
++ )
526 FcChar8
* file
= NULL
;
527 FcChar8
* family
= NULL
;
528 FcChar8
* style
= NULL
;
529 FcChar8
* format
= NULL
;
533 int nCollectionEntry
= -1;
534 FcBool outline
= false;
536 FcResult eFileRes
= FcPatternGetString(pFSet
->fonts
[i
], FC_FILE
, 0, &file
);
537 FcResult eFamilyRes
= rWrapper
.LocalizedElementFromPattern( pFSet
->fonts
[i
], &family
, FC_FAMILY
, FC_FAMILYLANG
);
538 FcResult eStyleRes
= rWrapper
.LocalizedElementFromPattern( pFSet
->fonts
[i
], &style
, FC_STYLE
, FC_STYLELANG
);
539 FcResult eSlantRes
= FcPatternGetInteger(pFSet
->fonts
[i
], FC_SLANT
, 0, &slant
);
540 FcResult eWeightRes
= FcPatternGetInteger(pFSet
->fonts
[i
], FC_WEIGHT
, 0, &weight
);
541 FcResult eSpacRes
= FcPatternGetInteger(pFSet
->fonts
[i
], FC_SPACING
, 0, &spacing
);
542 FcResult eOutRes
= FcPatternGetBool(pFSet
->fonts
[i
], FC_OUTLINE
, 0, &outline
);
543 FcResult eIndexRes
= FcPatternGetInteger(pFSet
->fonts
[i
], FC_INDEX
, 0, &nCollectionEntry
);
544 FcResult eFormatRes
= FcPatternGetString(pFSet
->fonts
[i
], FC_FONTFORMAT
, 0, &format
);
546 if( eFileRes
!= FcResultMatch
|| eFamilyRes
!= FcResultMatch
|| eOutRes
!= FcResultMatch
)
549 #if (OSL_DEBUG_LEVEL > 2)
550 fprintf( stderr
, "found font \"%s\" in file %s\n"
551 " weight = %d, slant = %d, style = \"%s\"\n"
552 " spacing = %d, outline = %d, format %s\n"
554 , eWeightRes
== FcResultMatch
? weight
: -1
555 , eSpacRes
== FcResultMatch
? slant
: -1
556 , eStyleRes
== FcResultMatch
? (const char*) style
: "<nil>"
557 , eSpacRes
== FcResultMatch
? spacing
: -1
558 , eOutRes
== FcResultMatch
? outline
: -1
559 , eFormatRes
== FcResultMatch
? (const char*)format
: "<unknown>"
563 // OSL_ASSERT(eOutRes != FcResultMatch || outline);
565 // only outline fonts are usable to psprint anyway
566 if( eOutRes
== FcResultMatch
&& ! outline
)
569 if (isPreviouslyDuplicateOrObsoleted(pFSet
, i
))
571 #if OSL_DEBUG_LEVEL > 2
572 fprintf(stderr
, "Ditching %s as duplicate/obsolete\n", file
);
577 // see if this font is already cached
579 std::list
< PrintFont
* > aFonts
;
580 OString aDir
, aBase
, aOrgPath( (sal_Char
*)file
);
581 splitPath( aOrgPath
, aDir
, aBase
);
583 o_rVisitedPaths
[aDir
] = 1;
585 int nDirID
= getDirectoryAtom( aDir
, true );
586 if( ! m_pFontCache
->getFontCacheFile( nDirID
, aBase
, aFonts
) )
588 #if OSL_DEBUG_LEVEL > 2
589 fprintf( stderr
, "file %s not cached\n", aBase
.getStr() );
591 // not known, analyze font file to get attributes
592 // not described by fontconfig (e.g. alias names, PSName)
593 if (eFormatRes
!= FcResultMatch
)
595 analyzeFontFile( nDirID
, aBase
, aFonts
, (const char*)format
);
596 #if OSL_DEBUG_LEVEL > 1
598 fprintf( stderr
, "Warning: file \"%s\" is unusable to psprint\n", aOrgPath
.getStr() );
603 //remove font, reuse index
604 //we want to remove unusable fonts here, in case there is a usable font
605 //which duplicates the properties of the unusable one
607 //not removing the unusable font will risk the usable font being rejected
608 //as a duplicate by isPreviouslyDuplicateOrObsoleted
609 lcl_FcFontSetRemove(pFSet
, i
--);
613 int nFamilyName
= m_pAtoms
->getAtom( ATOM_FAMILYNAME
, OStringToOUString( OString( (sal_Char
*)family
), RTL_TEXTENCODING_UTF8
), sal_True
);
614 PrintFont
* pUpdate
= aFonts
.front();
615 std::list
<PrintFont
*>::const_iterator second_font
= aFonts
.begin();
617 if( second_font
!= aFonts
.end() ) // more than one font
619 // a collection entry, get the correct index
620 if( eIndexRes
== FcResultMatch
&& nCollectionEntry
!= -1 )
622 for( std::list
< PrintFont
* >::iterator it
= aFonts
.begin(); it
!= aFonts
.end(); ++it
)
624 if( (*it
)->m_eType
== fonttype::TrueType
&&
625 static_cast<TrueTypeFontFile
*>(*it
)->m_nCollectionEntry
== nCollectionEntry
)
631 // update collection entry
632 // additional entries will be created in the cache
633 // if this is a new index (that is if the loop above
634 // ran to the end of the list)
635 if( pUpdate
->m_eType
== fonttype::TrueType
) // sanity check, this should always be the case here
636 static_cast<TrueTypeFontFile
*>(pUpdate
)->m_nCollectionEntry
= nCollectionEntry
;
640 #if OSL_DEBUG_LEVEL > 1
641 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
);
643 // we have found more than one font in this file
644 // but fontconfig will not tell us which index is meant
645 // -> something is in disorder, do not use this font
653 if( pUpdate
->m_nFamilyName
!= nFamilyName
)
656 if( eWeightRes
== FcResultMatch
)
657 pUpdate
->m_eWeight
= convertWeight(weight
);
658 if( eSpacRes
== FcResultMatch
)
659 pUpdate
->m_ePitch
= convertSpacing(spacing
);
660 if( eSlantRes
== FcResultMatch
)
661 pUpdate
->m_eItalic
= convertSlant(slant
);
662 if( eStyleRes
== FcResultMatch
)
664 pUpdate
->m_aStyleName
= OStringToOUString( OString( (sal_Char
*)style
), RTL_TEXTENCODING_UTF8
);
668 m_pFontCache
->updateFontCacheEntry( pUpdate
, false );
669 // sort into known fonts
670 fontID aFont
= m_nNextFontID
++;
671 m_aFonts
[ aFont
] = pUpdate
;
672 m_aFontFileToFontID
[ aBase
].insert( aFont
);
673 #if OSL_DEBUG_LEVEL > 1
676 #if OSL_DEBUG_LEVEL > 2
677 fprintf( stderr
, "inserted font %s as fontID %d\n", family
, aFont
);
680 // clean up the fonts we did not put into the list
681 for( std::list
< PrintFont
* >::iterator it
= aFonts
.begin(); it
!= aFonts
.end(); ++it
)
685 m_pFontCache
->updateFontCacheEntry( *it
, false ); // prepare a cache entry for a collection item
692 // how does one get rid of the config ?
693 #if OSL_DEBUG_LEVEL > 1
694 fprintf( stderr
, "inserted %d fonts from fontconfig\n", nFonts
);
698 void PrintFontManager::deinitFontconfig()
700 FontCfgWrapper::release();
703 bool PrintFontManager::addFontconfigDir( const OString
& rDirName
)
705 // workaround for a stability problems in older FC versions
706 // when handling application specifc fonts
707 const int nVersion
= FcGetVersion();
708 if( nVersion
<= 20400 )
710 const char* pDirName
= (const char*)rDirName
.getStr();
711 bool bDirOk
= (FcConfigAppFontAddDir(FcConfigGetCurrent(), (FcChar8
*)pDirName
) == FcTrue
);
713 #if OSL_DEBUG_LEVEL > 1
714 fprintf( stderr
, "FcConfigAppFontAddDir( \"%s\") => %d\n", pDirName
, bDirOk
);
720 // load dir-specific fc-config file too if available
721 const OString aConfFileName
= rDirName
+ "/fc_local.conf";
722 FILE* pCfgFile
= fopen( aConfFileName
.getStr(), "rb" );
726 bool bCfgOk
= FcConfigParseAndLoad(FcConfigGetCurrent(),
727 (FcChar8
*)aConfFileName
.getStr(), FcTrue
);
729 fprintf( stderr
, "FcConfigParseAndLoad( \"%s\") => %d\n", aConfFileName
.getStr(), bCfgOk
);
735 static void addtopattern(FcPattern
*pPattern
,
736 FontItalic eItalic
, FontWeight eWeight
, FontWidth eWidth
, FontPitch ePitch
)
738 if( eItalic
!= ITALIC_DONTKNOW
)
740 int nSlant
= FC_SLANT_ROMAN
;
744 nSlant
= FC_SLANT_ITALIC
;
747 nSlant
= FC_SLANT_OBLIQUE
;
752 FcPatternAddInteger(pPattern
, FC_SLANT
, nSlant
);
754 if( eWeight
!= WEIGHT_DONTKNOW
)
756 int nWeight
= FC_WEIGHT_NORMAL
;
759 case WEIGHT_THIN
: nWeight
= FC_WEIGHT_THIN
;break;
760 case WEIGHT_ULTRALIGHT
: nWeight
= FC_WEIGHT_ULTRALIGHT
;break;
761 case WEIGHT_LIGHT
: nWeight
= FC_WEIGHT_LIGHT
;break;
762 case WEIGHT_SEMILIGHT
: nWeight
= FC_WEIGHT_BOOK
;break;
763 case WEIGHT_NORMAL
: nWeight
= FC_WEIGHT_NORMAL
;break;
764 case WEIGHT_MEDIUM
: nWeight
= FC_WEIGHT_MEDIUM
;break;
765 case WEIGHT_SEMIBOLD
: nWeight
= FC_WEIGHT_SEMIBOLD
;break;
766 case WEIGHT_BOLD
: nWeight
= FC_WEIGHT_BOLD
;break;
767 case WEIGHT_ULTRABOLD
: nWeight
= FC_WEIGHT_ULTRABOLD
;break;
768 case WEIGHT_BLACK
: nWeight
= FC_WEIGHT_BLACK
;break;
772 FcPatternAddInteger(pPattern
, FC_WEIGHT
, nWeight
);
774 if( eWidth
!= WIDTH_DONTKNOW
)
776 int nWidth
= FC_WIDTH_NORMAL
;
779 case WIDTH_ULTRA_CONDENSED
: nWidth
= FC_WIDTH_ULTRACONDENSED
;break;
780 case WIDTH_EXTRA_CONDENSED
: nWidth
= FC_WIDTH_EXTRACONDENSED
;break;
781 case WIDTH_CONDENSED
: nWidth
= FC_WIDTH_CONDENSED
;break;
782 case WIDTH_SEMI_CONDENSED
: nWidth
= FC_WIDTH_SEMICONDENSED
;break;
783 case WIDTH_NORMAL
: nWidth
= FC_WIDTH_NORMAL
;break;
784 case WIDTH_SEMI_EXPANDED
: nWidth
= FC_WIDTH_SEMIEXPANDED
;break;
785 case WIDTH_EXPANDED
: nWidth
= FC_WIDTH_EXPANDED
;break;
786 case WIDTH_EXTRA_EXPANDED
: nWidth
= FC_WIDTH_EXTRAEXPANDED
;break;
787 case WIDTH_ULTRA_EXPANDED
: nWidth
= FC_WIDTH_ULTRACONDENSED
;break;
791 FcPatternAddInteger(pPattern
, FC_WIDTH
, nWidth
);
793 if( ePitch
!= PITCH_DONTKNOW
)
795 int nSpacing
= FC_PROPORTIONAL
;
798 case PITCH_FIXED
: nSpacing
= FC_MONO
;break;
799 case PITCH_VARIABLE
: nSpacing
= FC_PROPORTIONAL
;break;
803 FcPatternAddInteger(pPattern
, FC_SPACING
, nSpacing
);
804 if (nSpacing
== FC_MONO
)
805 FcPatternAddString(pPattern
, FC_FAMILY
, (FcChar8
*)"monospace");
811 //Someday fontconfig will hopefully use bcp47, see fdo#19869
812 //In the meantime try something that will fit to workaround fdo#35118
813 OString
mapToFontConfigLangTag(const LanguageTag
&rLangTag
)
815 #if defined(FC_VERSION) && (FC_VERSION >= 20492)
816 boost::shared_ptr
<FcStrSet
> xLangSet(FcGetLangs(), FcStrSetDestroy
);
819 sLangAttrib
= OUStringToOString(rLangTag
.getBcp47(), RTL_TEXTENCODING_UTF8
).toAsciiLowerCase();
820 if (FcStrSetMember(xLangSet
.get(), (const FcChar8
*)sLangAttrib
.getStr()))
825 sLangAttrib
= OUStringToOString(rLangTag
.getLanguageAndScript(), RTL_TEXTENCODING_UTF8
).toAsciiLowerCase();
826 if (FcStrSetMember(xLangSet
.get(), (const FcChar8
*)sLangAttrib
.getStr()))
831 OString sLang
= OUStringToOString(rLangTag
.getLanguage(), RTL_TEXTENCODING_UTF8
).toAsciiLowerCase();
832 OString sRegion
= OUStringToOString(rLangTag
.getCountry(), RTL_TEXTENCODING_UTF8
).toAsciiLowerCase();
834 if (!sRegion
.isEmpty())
836 sLangAttrib
= sLang
+ OString('-') + sRegion
;
837 if (FcStrSetMember(xLangSet
.get(), (const FcChar8
*)sLangAttrib
.getStr()))
843 if (FcStrSetMember(xLangSet
.get(), (const FcChar8
*)sLang
.getStr()))
850 OString sLangAttrib
= OUStringToOString(rLangTag
.getLanguageAndScript(), RTL_TEXTENCODING_UTF8
).toAsciiLowerCase();
851 if (sLangAttrib
.equalsIgnoreAsciiCase("pa-in"))
857 //returns true if the given code-point couldn't possibly be in rLangTag.
858 bool isImpossibleCodePointForLang(const LanguageTag
&rLangTag
, sal_uInt32 currentChar
)
860 //a non-default script is set, lets believe it
861 if (rLangTag
.hasScript())
864 int32_t script
= u_getIntPropertyValue(currentChar
, UCHAR_SCRIPT
);
865 UScriptCode eScript
= static_cast<UScriptCode
>(script
);
866 bool bIsImpossible
= false;
867 OUString sLang
= rLangTag
.getLanguage();
870 //http://en.wiktionary.org/wiki/Category:Oriya_script_languages
876 //http://en.wiktionary.org/wiki/Category:Telugu_script_languages
883 //http://en.wiktionary.org/wiki/Category:Bengali_script_languages
884 case USCRIPT_BENGALI
:
895 SAL_WARN_IF(bIsImpossible
, "vcl", "Throwing away user set language of "
896 << sLang
<< " for finding a font for glyph fallback and autodetecting instead");
897 return bIsImpossible
;
900 LanguageTag
getExemplerLangTagForCodePoint(sal_uInt32 currentChar
)
902 int32_t script
= u_getIntPropertyValue(currentChar
, UCHAR_SCRIPT
);
903 UScriptCode eScript
= static_cast<UScriptCode
>(script
);
904 OStringBuffer
aBuf(unicode::getExemplerLanguageForUScriptCode(eScript
));
905 const char* pScriptCode
= uscript_getShortName(eScript
);
907 aBuf
.append('-').append(pScriptCode
);
908 return LanguageTag(OStringToOUString(aBuf
.makeStringAndClear(), RTL_TEXTENCODING_UTF8
));
911 #if defined(ENABLE_DBUS) && defined(ENABLE_PACKAGEKIT)
912 guint
get_xid_for_dbus()
914 const Window
*pTopWindow
= Application::IsHeadlessModeEnabled() ? NULL
: Application::GetActiveTopWindow();
915 const SystemEnvData
* pEnvData
= pTopWindow
? pTopWindow
->GetSystemData() : NULL
;
916 return pEnvData
? pEnvData
->aWindow
: 0;
921 IMPL_LINK_NOARG(PrintFontManager
, autoInstallFontLangSupport
)
923 #if defined(ENABLE_DBUS) && defined(ENABLE_PACKAGEKIT)
924 guint xid
= get_xid_for_dbus();
929 GError
*error
= NULL
;
930 /* get the DBUS session connection */
931 DBusGConnection
*session_connection
= dbus_g_bus_get(DBUS_BUS_SESSION
, &error
);
934 g_debug ("DBUS cannot connect : %s", error
->message
);
935 g_error_free (error
);
939 /* get the proxy with gnome-session-manager */
940 DBusGProxy
*proxy
= dbus_g_proxy_new_for_name(session_connection
,
941 "org.freedesktop.PackageKit",
942 "/org/freedesktop/PackageKit",
943 "org.freedesktop.PackageKit.Modify");
946 g_debug("Could not get DBUS proxy: org.freedesktop.PackageKit");
950 gchar
**fonts
= (gchar
**)g_malloc((m_aCurrentRequests
.size() + 1) * sizeof(gchar
*));
951 gchar
**font
= fonts
;
952 for (std::vector
<OString
>::const_iterator aI
= m_aCurrentRequests
.begin(); aI
!= m_aCurrentRequests
.end(); ++aI
)
953 *font
++ = (gchar
*)aI
->getStr();
955 gboolean res
= dbus_g_proxy_call(proxy
, "InstallFontconfigResources", &error
,
956 G_TYPE_UINT
, xid
, /* xid */
957 G_TYPE_STRV
, fonts
, /* data */
958 G_TYPE_STRING
, "hide-finished", /* interaction */
961 /* check the return value */
963 g_debug("InstallFontconfigResources method failed");
965 /* check the error value */
968 g_debug("InstallFontconfigResources problem : %s", error
->message
);
973 g_object_unref(G_OBJECT (proxy
));
974 m_aCurrentRequests
.clear();
979 bool PrintFontManager::Substitute( FontSelectPattern
&rPattern
, OUString
& rMissingCodes
)
983 FontCfgWrapper
& rWrapper
= FontCfgWrapper::get();
985 // build pattern argument for fontconfig query
986 FcPattern
* pPattern
= FcPatternCreate();
988 // Prefer scalable fonts
989 FcPatternAddBool(pPattern
, FC_SCALABLE
, FcTrue
);
991 const OString aTargetName
= OUStringToOString( rPattern
.maTargetName
, RTL_TEXTENCODING_UTF8
);
992 const FcChar8
* pTargetNameUtf8
= (FcChar8
*)aTargetName
.getStr();
993 FcPatternAddString(pPattern
, FC_FAMILY
, pTargetNameUtf8
);
995 LanguageTag
aLangTag(rPattern
.meLanguage
);
996 OString aLangAttrib
= mapToFontConfigLangTag(aLangTag
);
998 // Add required Unicode characters, if any
999 if ( !rMissingCodes
.isEmpty() )
1001 FcCharSet
*unicodes
= FcCharSetCreate();
1002 for( sal_Int32 nStrIndex
= 0; nStrIndex
< rMissingCodes
.getLength(); )
1004 // also handle unicode surrogates
1005 const sal_uInt32 nCode
= rMissingCodes
.iterateCodePoints( &nStrIndex
);
1006 FcCharSetAddChar( unicodes
, nCode
);
1007 //if the codepoint is impossible for this lang tag, then clear it
1008 //and autodetect something useful
1009 if (!aLangAttrib
.isEmpty() && isImpossibleCodePointForLang(aLangTag
, nCode
))
1010 aLangAttrib
= OString();
1011 //#i105784#/rhbz#527719 improve selection of fallback font
1012 if (aLangAttrib
.isEmpty())
1014 aLangTag
= getExemplerLangTagForCodePoint(nCode
);
1015 aLangAttrib
= mapToFontConfigLangTag(aLangTag
);
1018 FcPatternAddCharSet(pPattern
, FC_CHARSET
, unicodes
);
1019 FcCharSetDestroy(unicodes
);
1022 if (!aLangAttrib
.isEmpty())
1023 FcPatternAddString(pPattern
, FC_LANG
, (FcChar8
*)aLangAttrib
.getStr());
1025 addtopattern(pPattern
, rPattern
.GetSlant(), rPattern
.GetWeight(),
1026 rPattern
.GetWidthType(), rPattern
.GetPitch());
1028 // query fontconfig for a substitute
1029 FcConfigSubstitute(FcConfigGetCurrent(), pPattern
, FcMatchPattern
);
1030 FcDefaultSubstitute(pPattern
);
1032 // process the result of the fontconfig query
1033 FcResult eResult
= FcResultNoMatch
;
1034 FcFontSet
* pFontSet
= rWrapper
.getFontSet();
1035 FcPattern
* pResult
= FcFontSetMatch(FcConfigGetCurrent(), &pFontSet
, 1, pPattern
, &eResult
);
1036 FcPatternDestroy( pPattern
);
1038 FcFontSet
* pSet
= NULL
;
1041 pSet
= FcFontSetCreate();
1042 // info: destroying the pSet destroys pResult implicitly
1043 // since pResult was "added" to pSet
1044 FcFontSetAdd( pSet
, pResult
);
1049 if( pSet
->nfont
> 0 )
1051 //extract the closest match
1052 FcChar8
* file
= NULL
;
1053 FcResult eFileRes
= FcPatternGetString(pSet
->fonts
[0], FC_FILE
, 0, &file
);
1054 int nCollectionEntry
= 0;
1055 FcResult eIndexRes
= FcPatternGetInteger(pSet
->fonts
[0], FC_INDEX
, 0, &nCollectionEntry
);
1056 if (eIndexRes
!= FcResultMatch
)
1057 nCollectionEntry
= 0;
1058 if( eFileRes
== FcResultMatch
)
1060 OString aDir
, aBase
, aOrgPath( (sal_Char
*)file
);
1061 splitPath( aOrgPath
, aDir
, aBase
);
1062 int nDirID
= getDirectoryAtom( aDir
, true );
1063 fontID aFont
= findFontFileID( nDirID
, aBase
, nCollectionEntry
);
1066 FastPrintFontInfo aInfo
;
1067 bRet
= getFontFastInfo( aFont
, aInfo
);
1068 rPattern
.maSearchName
= aInfo
.m_aFamilyName
;
1072 SAL_WARN_IF(!bRet
, "vcl", "no FC_FILE found, falling back to name search");
1076 FcChar8
* family
= NULL
;
1077 FcResult eFamilyRes
= FcPatternGetString( pSet
->fonts
[0], FC_FAMILY
, 0, &family
);
1079 // get the family name
1080 if( eFamilyRes
== FcResultMatch
)
1082 OString
sFamily((sal_Char
*)family
);
1083 boost::unordered_map
< OString
, OString
, OStringHash
>::const_iterator aI
=
1084 rWrapper
.m_aFontNameToLocalized
.find(sFamily
);
1085 if (aI
!= rWrapper
.m_aFontNameToLocalized
.end())
1086 sFamily
= aI
->second
;
1087 rPattern
.maSearchName
= OStringToOUString( sFamily
, RTL_TEXTENCODING_UTF8
);
1095 if (FcResultMatch
== FcPatternGetInteger(pSet
->fonts
[0], FC_WEIGHT
, 0, &val
))
1096 rPattern
.SetWeight( convertWeight(val
) );
1097 if (FcResultMatch
== FcPatternGetInteger(pSet
->fonts
[0], FC_SLANT
, 0, &val
))
1098 rPattern
.SetItalic( convertSlant(val
) );
1099 if (FcResultMatch
== FcPatternGetInteger(pSet
->fonts
[0], FC_SPACING
, 0, &val
))
1100 rPattern
.SetPitch ( convertSpacing(val
) );
1101 if (FcResultMatch
== FcPatternGetInteger(pSet
->fonts
[0], FC_WIDTH
, 0, &val
))
1102 rPattern
.SetWidthType ( convertWidth(val
) );
1104 if (FcResultMatch
== FcPatternGetBool(pSet
->fonts
[0], FC_EMBOLDEN
, 0, &bEmbolden
))
1105 rPattern
.mbEmbolden
= bEmbolden
;
1106 FcMatrix
*pMatrix
= 0;
1107 if (FcResultMatch
== FcPatternGetMatrix(pSet
->fonts
[0], FC_MATRIX
, 0, &pMatrix
))
1109 rPattern
.maItalicMatrix
.xx
= pMatrix
->xx
;
1110 rPattern
.maItalicMatrix
.xy
= pMatrix
->xy
;
1111 rPattern
.maItalicMatrix
.yx
= pMatrix
->yx
;
1112 rPattern
.maItalicMatrix
.yy
= pMatrix
->yy
;
1116 // update rMissingCodes by removing resolved unicodes
1117 if( !rMissingCodes
.isEmpty() )
1119 sal_uInt32
* pRemainingCodes
= (sal_uInt32
*)alloca( rMissingCodes
.getLength() * sizeof(sal_uInt32
) );
1120 int nRemainingLen
= 0;
1121 FcCharSet
* unicodes
;
1122 if (!FcPatternGetCharSet(pSet
->fonts
[0], FC_CHARSET
, 0, &unicodes
))
1124 for( sal_Int32 nStrIndex
= 0; nStrIndex
< rMissingCodes
.getLength(); )
1126 // also handle unicode surrogates
1127 const sal_uInt32 nCode
= rMissingCodes
.iterateCodePoints( &nStrIndex
);
1128 if (FcCharSetHasChar(unicodes
, nCode
) != FcTrue
)
1129 pRemainingCodes
[ nRemainingLen
++ ] = nCode
;
1132 OUString
sStillMissing(pRemainingCodes
, nRemainingLen
);
1133 #if defined(ENABLE_DBUS) && defined(ENABLE_PACKAGEKIT)
1134 if (get_xid_for_dbus())
1136 if (sStillMissing
== rMissingCodes
) //replaced nothing
1138 //It'd be better if we could ask packagekit using the
1139 //missing codepoints or some such rather than using
1140 //"language" as a proxy to how fontconfig considers
1141 //scripts to default to a given language.
1142 for (sal_Int32 i
= 0; i
< nRemainingLen
; ++i
)
1144 LanguageTag aOurTag
= getExemplerLangTagForCodePoint(pRemainingCodes
[i
]);
1145 OString sTag
= OUStringToOString(aOurTag
.getBcp47(), RTL_TEXTENCODING_UTF8
);
1146 if (m_aPreviousLangSupportRequests
.find(sTag
) != m_aPreviousLangSupportRequests
.end())
1148 m_aPreviousLangSupportRequests
.insert(sTag
);
1149 sTag
= mapToFontConfigLangTag(aOurTag
);
1150 if (!sTag
.isEmpty() && m_aPreviousLangSupportRequests
.find(sTag
) == m_aPreviousLangSupportRequests
.end())
1152 OString sReq
= OString(":lang=") + sTag
;
1153 m_aCurrentRequests
.push_back(sReq
);
1154 m_aPreviousLangSupportRequests
.insert(sTag
);
1158 if (!m_aCurrentRequests
.empty())
1160 m_aFontInstallerTimer
.Stop();
1161 m_aFontInstallerTimer
.Start();
1165 rMissingCodes
= sStillMissing
;
1169 FcFontSetDestroy( pSet
);
1175 class FontConfigFontOptions
: public ImplFontOptions
1178 FontConfigFontOptions() : mpPattern(0) {}
1179 ~FontConfigFontOptions()
1181 FcPatternDestroy(mpPattern
);
1183 virtual void *GetPattern(void * face
, bool bEmbolden
, bool /*bVerticalLayout*/) const
1186 value
.type
= FcTypeFTFace
;
1188 FcPatternDel(mpPattern
, FC_FT_FACE
);
1189 FcPatternAdd (mpPattern
, FC_FT_FACE
, value
, FcTrue
);
1190 FcPatternDel(mpPattern
, FC_EMBOLDEN
);
1191 FcPatternAddBool(mpPattern
, FC_EMBOLDEN
, bEmbolden
? FcTrue
: FcFalse
);
1193 FcPatternDel(mpPattern
, FC_VERTICAL_LAYOUT
);
1194 FcPatternAddBool(mpPattern
, FC_VERTICAL_LAYOUT
, bVerticalLayout
? FcTrue
: FcFalse
);
1198 FcPattern
* mpPattern
;
1201 ImplFontOptions
* PrintFontManager::getFontOptions(
1202 const FastPrintFontInfo
& rInfo
, int nSize
, void (*subcallback
)(void*)) const
1204 FontCfgWrapper
& rWrapper
= FontCfgWrapper::get();
1206 FontConfigFontOptions
* pOptions
= NULL
;
1207 FcConfig
* pConfig
= FcConfigGetCurrent();
1208 FcPattern
* pPattern
= FcPatternCreate();
1210 OString sFamily
= OUStringToOString( rInfo
.m_aFamilyName
, RTL_TEXTENCODING_UTF8
);
1212 boost::unordered_map
< OString
, OString
, OStringHash
>::const_iterator aI
= rWrapper
.m_aLocalizedToCanonical
.find(sFamily
);
1213 if (aI
!= rWrapper
.m_aLocalizedToCanonical
.end())
1214 sFamily
= aI
->second
;
1215 if( !sFamily
.isEmpty() )
1216 FcPatternAddString(pPattern
, FC_FAMILY
, (FcChar8
*)sFamily
.getStr());
1218 addtopattern(pPattern
, rInfo
.m_eItalic
, rInfo
.m_eWeight
, rInfo
.m_eWidth
, rInfo
.m_ePitch
);
1219 FcPatternAddDouble(pPattern
, FC_PIXEL_SIZE
, nSize
);
1221 FcBool embitmap
= true, antialias
= true, autohint
= true, hinting
= true;
1222 int hintstyle
= FC_HINT_FULL
;
1224 FcConfigSubstitute(pConfig
, pPattern
, FcMatchPattern
);
1226 subcallback(pPattern
);
1227 FcDefaultSubstitute(pPattern
);
1229 FcResult eResult
= FcResultNoMatch
;
1230 FcFontSet
* pFontSet
= rWrapper
.getFontSet();
1231 FcPattern
* pResult
= FcFontSetMatch( pConfig
, &pFontSet
, 1, pPattern
, &eResult
);
1234 FcResult eEmbeddedBitmap
= FcPatternGetBool(pResult
,
1235 FC_EMBEDDED_BITMAP
, 0, &embitmap
);
1236 FcResult eAntialias
= FcPatternGetBool(pResult
,
1237 FC_ANTIALIAS
, 0, &antialias
);
1238 FcResult eAutoHint
= FcPatternGetBool(pResult
,
1239 FC_AUTOHINT
, 0, &autohint
);
1240 FcResult eHinting
= FcPatternGetBool(pResult
,
1241 FC_HINTING
, 0, &hinting
);
1242 /*FcResult eHintStyle =*/ FcPatternGetInteger(pResult
,
1243 FC_HINT_STYLE
, 0, &hintstyle
);
1245 pOptions
= new FontConfigFontOptions
;
1247 pOptions
->mpPattern
= pResult
;
1249 if( eEmbeddedBitmap
== FcResultMatch
)
1250 pOptions
->meEmbeddedBitmap
= embitmap
? EMBEDDEDBITMAP_TRUE
: EMBEDDEDBITMAP_FALSE
;
1251 if( eAntialias
== FcResultMatch
)
1252 pOptions
->meAntiAlias
= antialias
? ANTIALIAS_TRUE
: ANTIALIAS_FALSE
;
1253 if( eAutoHint
== FcResultMatch
)
1254 pOptions
->meAutoHint
= autohint
? AUTOHINT_TRUE
: AUTOHINT_FALSE
;
1255 if( eHinting
== FcResultMatch
)
1256 pOptions
->meHinting
= hinting
? HINTING_TRUE
: HINTING_FALSE
;
1259 case FC_HINT_NONE
: pOptions
->meHintStyle
= HINT_NONE
; break;
1260 case FC_HINT_SLIGHT
: pOptions
->meHintStyle
= HINT_SLIGHT
; break;
1261 case FC_HINT_MEDIUM
: pOptions
->meHintStyle
= HINT_MEDIUM
; break;
1262 default: // fall through
1263 case FC_HINT_FULL
: pOptions
->meHintStyle
= HINT_FULL
; break;
1268 FcPatternDestroy( pPattern
);
1273 bool PrintFontManager::matchFont( FastPrintFontInfo
& rInfo
, const com::sun::star::lang::Locale
& rLocale
)
1275 FontCfgWrapper
& rWrapper
= FontCfgWrapper::get();
1277 FcConfig
* pConfig
= FcConfigGetCurrent();
1278 FcPattern
* pPattern
= FcPatternCreate();
1280 // populate pattern with font characteristics
1281 const LanguageTag
aLangTag(rLocale
);
1282 const OString aLangAttrib
= mapToFontConfigLangTag(aLangTag
);
1283 if (!aLangAttrib
.isEmpty())
1284 FcPatternAddString(pPattern
, FC_LANG
, (FcChar8
*)aLangAttrib
.getStr());
1286 OString aFamily
= OUStringToOString( rInfo
.m_aFamilyName
, RTL_TEXTENCODING_UTF8
);
1287 if( !aFamily
.isEmpty() )
1288 FcPatternAddString(pPattern
, FC_FAMILY
, (FcChar8
*)aFamily
.getStr());
1290 addtopattern(pPattern
, rInfo
.m_eItalic
, rInfo
.m_eWeight
, rInfo
.m_eWidth
, rInfo
.m_ePitch
);
1292 FcConfigSubstitute(pConfig
, pPattern
, FcMatchPattern
);
1293 FcDefaultSubstitute(pPattern
);
1294 FcResult eResult
= FcResultNoMatch
;
1295 FcFontSet
*pFontSet
= rWrapper
.getFontSet();
1296 FcPattern
* pResult
= FcFontSetMatch(pConfig
, &pFontSet
, 1, pPattern
, &eResult
);
1297 bool bSuccess
= false;
1300 FcFontSet
* pSet
= FcFontSetCreate();
1301 FcFontSetAdd( pSet
, pResult
);
1302 if( pSet
->nfont
> 0 )
1304 //extract the closest match
1305 FcChar8
* file
= NULL
;
1306 FcResult eFileRes
= FcPatternGetString(pSet
->fonts
[0], FC_FILE
, 0, &file
);
1307 int nCollectionEntry
= 0;
1308 FcResult eIndexRes
= FcPatternGetInteger(pSet
->fonts
[0], FC_INDEX
, 0, &nCollectionEntry
);
1309 if (eIndexRes
!= FcResultMatch
)
1310 nCollectionEntry
= 0;
1311 if( eFileRes
== FcResultMatch
)
1313 OString aDir
, aBase
, aOrgPath( (sal_Char
*)file
);
1314 splitPath( aOrgPath
, aDir
, aBase
);
1315 int nDirID
= getDirectoryAtom( aDir
, true );
1316 fontID aFont
= findFontFileID( nDirID
, aBase
, nCollectionEntry
);
1318 bSuccess
= getFontFastInfo( aFont
, rInfo
);
1321 // info: destroying the pSet destroys pResult implicitly
1322 // since pResult was "added" to pSet
1323 FcFontSetDestroy( pSet
);
1327 FcPatternDestroy( pPattern
);
1332 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */