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
;
534 int nCollectionEntry
= -1;
535 FcBool outline
= false;
537 FcResult eFileRes
= FcPatternGetString(pFSet
->fonts
[i
], FC_FILE
, 0, &file
);
538 FcResult eFamilyRes
= rWrapper
.LocalizedElementFromPattern( pFSet
->fonts
[i
], &family
, FC_FAMILY
, FC_FAMILYLANG
);
539 FcResult eStyleRes
= rWrapper
.LocalizedElementFromPattern( pFSet
->fonts
[i
], &style
, FC_STYLE
, FC_STYLELANG
);
540 FcResult eSlantRes
= FcPatternGetInteger(pFSet
->fonts
[i
], FC_SLANT
, 0, &slant
);
541 FcResult eWeightRes
= FcPatternGetInteger(pFSet
->fonts
[i
], FC_WEIGHT
, 0, &weight
);
542 FcResult eWidthRes
= FcPatternGetInteger(pFSet
->fonts
[i
], FC_WIDTH
, 0, &width
);
543 FcResult eSpacRes
= FcPatternGetInteger(pFSet
->fonts
[i
], FC_SPACING
, 0, &spacing
);
544 FcResult eOutRes
= FcPatternGetBool(pFSet
->fonts
[i
], FC_OUTLINE
, 0, &outline
);
545 FcResult eIndexRes
= FcPatternGetInteger(pFSet
->fonts
[i
], FC_INDEX
, 0, &nCollectionEntry
);
546 FcResult eFormatRes
= FcPatternGetString(pFSet
->fonts
[i
], FC_FONTFORMAT
, 0, &format
);
548 if( eFileRes
!= FcResultMatch
|| eFamilyRes
!= FcResultMatch
|| eOutRes
!= FcResultMatch
)
551 #if (OSL_DEBUG_LEVEL > 2)
552 fprintf( stderr
, "found font \"%s\" in file %s\n"
553 " weight = %d, slant = %d, style = \"%s\"\n"
554 " width = %d, spacing = %d, outline = %d, format %s\n"
556 , eWeightRes
== FcResultMatch
? weight
: -1
557 , eSpacRes
== FcResultMatch
? slant
: -1
558 , eStyleRes
== FcResultMatch
? (const char*) style
: "<nil>"
559 , eWeightRes
== FcResultMatch
? width
: -1
560 , eSpacRes
== FcResultMatch
? spacing
: -1
561 , eOutRes
== FcResultMatch
? outline
: -1
562 , eFormatRes
== FcResultMatch
? (const char*)format
: "<unknown>"
566 // OSL_ASSERT(eOutRes != FcResultMatch || outline);
568 // only outline fonts are usable to psprint anyway
569 if( eOutRes
== FcResultMatch
&& ! outline
)
572 if (isPreviouslyDuplicateOrObsoleted(pFSet
, i
))
574 #if OSL_DEBUG_LEVEL > 2
575 fprintf(stderr
, "Ditching %s as duplicate/obsolete\n", file
);
580 // see if this font is already cached
582 std::list
< PrintFont
* > aFonts
;
583 OString aDir
, aBase
, aOrgPath( (sal_Char
*)file
);
584 splitPath( aOrgPath
, aDir
, aBase
);
586 o_rVisitedPaths
[aDir
] = 1;
588 int nDirID
= getDirectoryAtom( aDir
, true );
589 if( ! m_pFontCache
->getFontCacheFile( nDirID
, aBase
, aFonts
) )
591 #if OSL_DEBUG_LEVEL > 2
592 fprintf( stderr
, "file %s not cached\n", aBase
.getStr() );
594 // not known, analyze font file to get attributes
595 // not described by fontconfig (e.g. alias names, PSName)
596 if (eFormatRes
!= FcResultMatch
)
598 analyzeFontFile( nDirID
, aBase
, aFonts
, (const char*)format
);
599 #if OSL_DEBUG_LEVEL > 1
601 fprintf( stderr
, "Warning: file \"%s\" is unusable to psprint\n", aOrgPath
.getStr() );
606 //remove font, reuse index
607 //we want to remove unusable fonts here, in case there is a usable font
608 //which duplicates the properties of the unusable one
610 //not removing the unusable font will risk the usable font being rejected
611 //as a duplicate by isPreviouslyDuplicateOrObsoleted
612 lcl_FcFontSetRemove(pFSet
, i
--);
616 int nFamilyName
= m_pAtoms
->getAtom( ATOM_FAMILYNAME
, OStringToOUString( OString( (sal_Char
*)family
), RTL_TEXTENCODING_UTF8
), sal_True
);
617 PrintFont
* pUpdate
= aFonts
.front();
618 std::list
<PrintFont
*>::const_iterator second_font
= aFonts
.begin();
620 if( second_font
!= aFonts
.end() ) // more than one font
622 // a collection entry, get the correct index
623 if( eIndexRes
== FcResultMatch
&& nCollectionEntry
!= -1 )
625 for( std::list
< PrintFont
* >::iterator it
= aFonts
.begin(); it
!= aFonts
.end(); ++it
)
627 if( (*it
)->m_eType
== fonttype::TrueType
&&
628 static_cast<TrueTypeFontFile
*>(*it
)->m_nCollectionEntry
== nCollectionEntry
)
634 // update collection entry
635 // additional entries will be created in the cache
636 // if this is a new index (that is if the loop above
637 // ran to the end of the list)
638 if( pUpdate
->m_eType
== fonttype::TrueType
) // sanity check, this should always be the case here
639 static_cast<TrueTypeFontFile
*>(pUpdate
)->m_nCollectionEntry
= nCollectionEntry
;
643 #if OSL_DEBUG_LEVEL > 1
644 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
);
646 // we have found more than one font in this file
647 // but fontconfig will not tell us which index is meant
648 // -> something is in disorder, do not use this font
656 if( pUpdate
->m_nFamilyName
!= nFamilyName
)
659 if( eWeightRes
== FcResultMatch
)
660 pUpdate
->m_eWeight
= convertWeight(weight
);
661 if( eWidthRes
== FcResultMatch
)
662 pUpdate
->m_eWidth
= convertWidth(width
);
663 if( eSpacRes
== FcResultMatch
)
664 pUpdate
->m_ePitch
= convertSpacing(spacing
);
665 if( eSlantRes
== FcResultMatch
)
666 pUpdate
->m_eItalic
= convertSlant(slant
);
667 if( eStyleRes
== FcResultMatch
)
669 pUpdate
->m_aStyleName
= OStringToOUString( OString( (sal_Char
*)style
), RTL_TEXTENCODING_UTF8
);
673 m_pFontCache
->updateFontCacheEntry( pUpdate
, false );
674 // sort into known fonts
675 fontID aFont
= m_nNextFontID
++;
676 m_aFonts
[ aFont
] = pUpdate
;
677 m_aFontFileToFontID
[ aBase
].insert( aFont
);
678 #if OSL_DEBUG_LEVEL > 1
681 #if OSL_DEBUG_LEVEL > 2
682 fprintf( stderr
, "inserted font %s as fontID %d\n", family
, aFont
);
685 // clean up the fonts we did not put into the list
686 for( std::list
< PrintFont
* >::iterator it
= aFonts
.begin(); it
!= aFonts
.end(); ++it
)
690 m_pFontCache
->updateFontCacheEntry( *it
, false ); // prepare a cache entry for a collection item
697 // how does one get rid of the config ?
698 #if OSL_DEBUG_LEVEL > 1
699 fprintf( stderr
, "inserted %d fonts from fontconfig\n", nFonts
);
703 void PrintFontManager::deinitFontconfig()
705 FontCfgWrapper::release();
708 bool PrintFontManager::addFontconfigDir( const OString
& rDirName
)
710 // workaround for a stability problems in older FC versions
711 // when handling application specifc fonts
712 const int nVersion
= FcGetVersion();
713 if( nVersion
<= 20400 )
715 const char* pDirName
= (const char*)rDirName
.getStr();
716 bool bDirOk
= (FcConfigAppFontAddDir(FcConfigGetCurrent(), (FcChar8
*)pDirName
) == FcTrue
);
718 #if OSL_DEBUG_LEVEL > 1
719 fprintf( stderr
, "FcConfigAppFontAddDir( \"%s\") => %d\n", pDirName
, bDirOk
);
725 // load dir-specific fc-config file too if available
726 const OString aConfFileName
= rDirName
+ "/fc_local.conf";
727 FILE* pCfgFile
= fopen( aConfFileName
.getStr(), "rb" );
731 bool bCfgOk
= FcConfigParseAndLoad(FcConfigGetCurrent(),
732 (FcChar8
*)aConfFileName
.getStr(), FcTrue
);
734 fprintf( stderr
, "FcConfigParseAndLoad( \"%s\") => %d\n", aConfFileName
.getStr(), bCfgOk
);
740 static void addtopattern(FcPattern
*pPattern
,
741 FontItalic eItalic
, FontWeight eWeight
, FontWidth eWidth
, FontPitch ePitch
)
743 if( eItalic
!= ITALIC_DONTKNOW
)
745 int nSlant
= FC_SLANT_ROMAN
;
749 nSlant
= FC_SLANT_ITALIC
;
752 nSlant
= FC_SLANT_OBLIQUE
;
757 FcPatternAddInteger(pPattern
, FC_SLANT
, nSlant
);
759 if( eWeight
!= WEIGHT_DONTKNOW
)
761 int nWeight
= FC_WEIGHT_NORMAL
;
764 case WEIGHT_THIN
: nWeight
= FC_WEIGHT_THIN
;break;
765 case WEIGHT_ULTRALIGHT
: nWeight
= FC_WEIGHT_ULTRALIGHT
;break;
766 case WEIGHT_LIGHT
: nWeight
= FC_WEIGHT_LIGHT
;break;
767 case WEIGHT_SEMILIGHT
: nWeight
= FC_WEIGHT_BOOK
;break;
768 case WEIGHT_NORMAL
: nWeight
= FC_WEIGHT_NORMAL
;break;
769 case WEIGHT_MEDIUM
: nWeight
= FC_WEIGHT_MEDIUM
;break;
770 case WEIGHT_SEMIBOLD
: nWeight
= FC_WEIGHT_SEMIBOLD
;break;
771 case WEIGHT_BOLD
: nWeight
= FC_WEIGHT_BOLD
;break;
772 case WEIGHT_ULTRABOLD
: nWeight
= FC_WEIGHT_ULTRABOLD
;break;
773 case WEIGHT_BLACK
: nWeight
= FC_WEIGHT_BLACK
;break;
777 FcPatternAddInteger(pPattern
, FC_WEIGHT
, nWeight
);
779 if( eWidth
!= WIDTH_DONTKNOW
)
781 int nWidth
= FC_WIDTH_NORMAL
;
784 case WIDTH_ULTRA_CONDENSED
: nWidth
= FC_WIDTH_ULTRACONDENSED
;break;
785 case WIDTH_EXTRA_CONDENSED
: nWidth
= FC_WIDTH_EXTRACONDENSED
;break;
786 case WIDTH_CONDENSED
: nWidth
= FC_WIDTH_CONDENSED
;break;
787 case WIDTH_SEMI_CONDENSED
: nWidth
= FC_WIDTH_SEMICONDENSED
;break;
788 case WIDTH_NORMAL
: nWidth
= FC_WIDTH_NORMAL
;break;
789 case WIDTH_SEMI_EXPANDED
: nWidth
= FC_WIDTH_SEMIEXPANDED
;break;
790 case WIDTH_EXPANDED
: nWidth
= FC_WIDTH_EXPANDED
;break;
791 case WIDTH_EXTRA_EXPANDED
: nWidth
= FC_WIDTH_EXTRAEXPANDED
;break;
792 case WIDTH_ULTRA_EXPANDED
: nWidth
= FC_WIDTH_ULTRACONDENSED
;break;
796 FcPatternAddInteger(pPattern
, FC_WIDTH
, nWidth
);
798 if( ePitch
!= PITCH_DONTKNOW
)
800 int nSpacing
= FC_PROPORTIONAL
;
803 case PITCH_FIXED
: nSpacing
= FC_MONO
;break;
804 case PITCH_VARIABLE
: nSpacing
= FC_PROPORTIONAL
;break;
808 FcPatternAddInteger(pPattern
, FC_SPACING
, nSpacing
);
809 if (nSpacing
== FC_MONO
)
810 FcPatternAddString(pPattern
, FC_FAMILY
, (FcChar8
*)"monospace");
816 //Someday fontconfig will hopefully use bcp47, see fdo#19869
817 //In the meantime try something that will fit to workaround fdo#35118
818 OString
mapToFontConfigLangTag(const LanguageTag
&rLangTag
)
820 #if defined(FC_VERSION) && (FC_VERSION >= 20492)
821 boost::shared_ptr
<FcStrSet
> xLangSet(FcGetLangs(), FcStrSetDestroy
);
824 sLangAttrib
= OUStringToOString(rLangTag
.getBcp47(), RTL_TEXTENCODING_UTF8
).toAsciiLowerCase();
825 if (FcStrSetMember(xLangSet
.get(), (const FcChar8
*)sLangAttrib
.getStr()))
830 sLangAttrib
= OUStringToOString(rLangTag
.getLanguageAndScript(), RTL_TEXTENCODING_UTF8
).toAsciiLowerCase();
831 if (FcStrSetMember(xLangSet
.get(), (const FcChar8
*)sLangAttrib
.getStr()))
836 OString sLang
= OUStringToOString(rLangTag
.getLanguage(), RTL_TEXTENCODING_UTF8
).toAsciiLowerCase();
837 OString sRegion
= OUStringToOString(rLangTag
.getCountry(), RTL_TEXTENCODING_UTF8
).toAsciiLowerCase();
839 if (!sRegion
.isEmpty())
841 sLangAttrib
= sLang
+ OString('-') + sRegion
;
842 if (FcStrSetMember(xLangSet
.get(), (const FcChar8
*)sLangAttrib
.getStr()))
848 if (FcStrSetMember(xLangSet
.get(), (const FcChar8
*)sLang
.getStr()))
855 OString sLangAttrib
= OUStringToOString(rLangTag
.getLanguageAndScript(), RTL_TEXTENCODING_UTF8
).toAsciiLowerCase();
856 if (sLangAttrib
.equalsIgnoreAsciiCase("pa-in"))
862 //returns true if the given code-point couldn't possibly be in rLangTag.
863 bool isImpossibleCodePointForLang(const LanguageTag
&rLangTag
, sal_uInt32 currentChar
)
865 //a non-default script is set, lets believe it
866 if (rLangTag
.hasScript())
869 int32_t script
= u_getIntPropertyValue(currentChar
, UCHAR_SCRIPT
);
870 UScriptCode eScript
= static_cast<UScriptCode
>(script
);
871 bool bIsImpossible
= false;
872 OUString sLang
= rLangTag
.getLanguage();
875 //http://en.wiktionary.org/wiki/Category:Oriya_script_languages
881 //http://en.wiktionary.org/wiki/Category:Telugu_script_languages
888 //http://en.wiktionary.org/wiki/Category:Bengali_script_languages
889 case USCRIPT_BENGALI
:
900 SAL_WARN_IF(bIsImpossible
, "vcl", "Throwing away user set language of "
901 << sLang
<< " for finding a font for glyph fallback and autodetecting instead");
902 return bIsImpossible
;
905 LanguageTag
getExemplerLangTagForCodePoint(sal_uInt32 currentChar
)
907 int32_t script
= u_getIntPropertyValue(currentChar
, UCHAR_SCRIPT
);
908 UScriptCode eScript
= static_cast<UScriptCode
>(script
);
909 OStringBuffer
aBuf(unicode::getExemplerLanguageForUScriptCode(eScript
));
910 const char* pScriptCode
= uscript_getShortName(eScript
);
912 aBuf
.append('-').append(pScriptCode
);
913 return LanguageTag(OStringToOUString(aBuf
.makeStringAndClear(), RTL_TEXTENCODING_UTF8
));
916 #if defined(ENABLE_DBUS) && defined(ENABLE_PACKAGEKIT)
917 guint
get_xid_for_dbus()
919 const Window
*pTopWindow
= Application::IsHeadlessModeEnabled() ? NULL
: Application::GetActiveTopWindow();
920 const SystemEnvData
* pEnvData
= pTopWindow
? pTopWindow
->GetSystemData() : NULL
;
921 return pEnvData
? pEnvData
->aWindow
: 0;
926 IMPL_LINK_NOARG(PrintFontManager
, autoInstallFontLangSupport
)
928 #if defined(ENABLE_DBUS) && defined(ENABLE_PACKAGEKIT)
929 guint xid
= get_xid_for_dbus();
934 GError
*error
= NULL
;
935 /* get the DBUS session connection */
936 DBusGConnection
*session_connection
= dbus_g_bus_get(DBUS_BUS_SESSION
, &error
);
939 g_debug ("DBUS cannot connect : %s", error
->message
);
940 g_error_free (error
);
944 /* get the proxy with gnome-session-manager */
945 DBusGProxy
*proxy
= dbus_g_proxy_new_for_name(session_connection
,
946 "org.freedesktop.PackageKit",
947 "/org/freedesktop/PackageKit",
948 "org.freedesktop.PackageKit.Modify");
951 g_debug("Could not get DBUS proxy: org.freedesktop.PackageKit");
955 gchar
**fonts
= (gchar
**)g_malloc((m_aCurrentRequests
.size() + 1) * sizeof(gchar
*));
956 gchar
**font
= fonts
;
957 for (std::vector
<OString
>::const_iterator aI
= m_aCurrentRequests
.begin(); aI
!= m_aCurrentRequests
.end(); ++aI
)
958 *font
++ = (gchar
*)aI
->getStr();
960 gboolean res
= dbus_g_proxy_call(proxy
, "InstallFontconfigResources", &error
,
961 G_TYPE_UINT
, xid
, /* xid */
962 G_TYPE_STRV
, fonts
, /* data */
963 G_TYPE_STRING
, "hide-finished", /* interaction */
966 /* check the return value */
968 g_debug("InstallFontconfigResources method failed");
970 /* check the error value */
973 g_debug("InstallFontconfigResources problem : %s", error
->message
);
978 g_object_unref(G_OBJECT (proxy
));
979 m_aCurrentRequests
.clear();
984 bool PrintFontManager::Substitute( FontSelectPattern
&rPattern
, OUString
& rMissingCodes
)
988 FontCfgWrapper
& rWrapper
= FontCfgWrapper::get();
990 // build pattern argument for fontconfig query
991 FcPattern
* pPattern
= FcPatternCreate();
993 // Prefer scalable fonts
994 FcPatternAddBool(pPattern
, FC_SCALABLE
, FcTrue
);
996 const OString aTargetName
= OUStringToOString( rPattern
.maTargetName
, RTL_TEXTENCODING_UTF8
);
997 const FcChar8
* pTargetNameUtf8
= (FcChar8
*)aTargetName
.getStr();
998 FcPatternAddString(pPattern
, FC_FAMILY
, pTargetNameUtf8
);
1000 LanguageTag
aLangTag(rPattern
.meLanguage
);
1001 OString aLangAttrib
= mapToFontConfigLangTag(aLangTag
);
1003 // Add required Unicode characters, if any
1004 if ( !rMissingCodes
.isEmpty() )
1006 FcCharSet
*unicodes
= FcCharSetCreate();
1007 for( sal_Int32 nStrIndex
= 0; nStrIndex
< rMissingCodes
.getLength(); )
1009 // also handle unicode surrogates
1010 const sal_uInt32 nCode
= rMissingCodes
.iterateCodePoints( &nStrIndex
);
1011 FcCharSetAddChar( unicodes
, nCode
);
1012 //if the codepoint is impossible for this lang tag, then clear it
1013 //and autodetect something useful
1014 if (!aLangAttrib
.isEmpty() && isImpossibleCodePointForLang(aLangTag
, nCode
))
1015 aLangAttrib
= OString();
1016 //#i105784#/rhbz#527719 improve selection of fallback font
1017 if (aLangAttrib
.isEmpty())
1019 aLangTag
= getExemplerLangTagForCodePoint(nCode
);
1020 aLangAttrib
= mapToFontConfigLangTag(aLangTag
);
1023 FcPatternAddCharSet(pPattern
, FC_CHARSET
, unicodes
);
1024 FcCharSetDestroy(unicodes
);
1027 if (!aLangAttrib
.isEmpty())
1028 FcPatternAddString(pPattern
, FC_LANG
, (FcChar8
*)aLangAttrib
.getStr());
1030 addtopattern(pPattern
, rPattern
.GetSlant(), rPattern
.GetWeight(),
1031 rPattern
.GetWidthType(), rPattern
.GetPitch());
1033 // query fontconfig for a substitute
1034 FcConfigSubstitute(FcConfigGetCurrent(), pPattern
, FcMatchPattern
);
1035 FcDefaultSubstitute(pPattern
);
1037 // process the result of the fontconfig query
1038 FcResult eResult
= FcResultNoMatch
;
1039 FcFontSet
* pFontSet
= rWrapper
.getFontSet();
1040 FcPattern
* pResult
= FcFontSetMatch(FcConfigGetCurrent(), &pFontSet
, 1, pPattern
, &eResult
);
1041 FcPatternDestroy( pPattern
);
1043 FcFontSet
* pSet
= NULL
;
1046 pSet
= FcFontSetCreate();
1047 // info: destroying the pSet destroys pResult implicitly
1048 // since pResult was "added" to pSet
1049 FcFontSetAdd( pSet
, pResult
);
1054 if( pSet
->nfont
> 0 )
1056 //extract the closest match
1057 FcChar8
* file
= NULL
;
1058 FcResult eFileRes
= FcPatternGetString(pSet
->fonts
[0], FC_FILE
, 0, &file
);
1059 int nCollectionEntry
= 0;
1060 FcResult eIndexRes
= FcPatternGetInteger(pSet
->fonts
[0], FC_INDEX
, 0, &nCollectionEntry
);
1061 if (eIndexRes
!= FcResultMatch
)
1062 nCollectionEntry
= 0;
1063 if( eFileRes
== FcResultMatch
)
1065 OString aDir
, aBase
, aOrgPath( (sal_Char
*)file
);
1066 splitPath( aOrgPath
, aDir
, aBase
);
1067 int nDirID
= getDirectoryAtom( aDir
, true );
1068 fontID aFont
= findFontFileID( nDirID
, aBase
, nCollectionEntry
);
1071 FastPrintFontInfo aInfo
;
1072 bRet
= getFontFastInfo( aFont
, aInfo
);
1073 rPattern
.maSearchName
= aInfo
.m_aFamilyName
;
1077 SAL_WARN_IF(!bRet
, "vcl", "no FC_FILE found, falling back to name search");
1081 FcChar8
* family
= NULL
;
1082 FcResult eFamilyRes
= FcPatternGetString( pSet
->fonts
[0], FC_FAMILY
, 0, &family
);
1084 // get the family name
1085 if( eFamilyRes
== FcResultMatch
)
1087 OString
sFamily((sal_Char
*)family
);
1088 boost::unordered_map
< OString
, OString
, OStringHash
>::const_iterator aI
=
1089 rWrapper
.m_aFontNameToLocalized
.find(sFamily
);
1090 if (aI
!= rWrapper
.m_aFontNameToLocalized
.end())
1091 sFamily
= aI
->second
;
1092 rPattern
.maSearchName
= OStringToOUString( sFamily
, RTL_TEXTENCODING_UTF8
);
1100 if (FcResultMatch
== FcPatternGetInteger(pSet
->fonts
[0], FC_WEIGHT
, 0, &val
))
1101 rPattern
.SetWeight( convertWeight(val
) );
1102 if (FcResultMatch
== FcPatternGetInteger(pSet
->fonts
[0], FC_SLANT
, 0, &val
))
1103 rPattern
.SetItalic( convertSlant(val
) );
1104 if (FcResultMatch
== FcPatternGetInteger(pSet
->fonts
[0], FC_SPACING
, 0, &val
))
1105 rPattern
.SetPitch ( convertSpacing(val
) );
1106 if (FcResultMatch
== FcPatternGetInteger(pSet
->fonts
[0], FC_WIDTH
, 0, &val
))
1107 rPattern
.SetWidthType ( convertWidth(val
) );
1109 if (FcResultMatch
== FcPatternGetBool(pSet
->fonts
[0], FC_EMBOLDEN
, 0, &bEmbolden
))
1110 rPattern
.mbEmbolden
= bEmbolden
;
1111 FcMatrix
*pMatrix
= 0;
1112 if (FcResultMatch
== FcPatternGetMatrix(pSet
->fonts
[0], FC_MATRIX
, 0, &pMatrix
))
1114 rPattern
.maItalicMatrix
.xx
= pMatrix
->xx
;
1115 rPattern
.maItalicMatrix
.xy
= pMatrix
->xy
;
1116 rPattern
.maItalicMatrix
.yx
= pMatrix
->yx
;
1117 rPattern
.maItalicMatrix
.yy
= pMatrix
->yy
;
1121 // update rMissingCodes by removing resolved unicodes
1122 if( !rMissingCodes
.isEmpty() )
1124 sal_uInt32
* pRemainingCodes
= (sal_uInt32
*)alloca( rMissingCodes
.getLength() * sizeof(sal_uInt32
) );
1125 int nRemainingLen
= 0;
1126 FcCharSet
* unicodes
;
1127 if (!FcPatternGetCharSet(pSet
->fonts
[0], FC_CHARSET
, 0, &unicodes
))
1129 for( sal_Int32 nStrIndex
= 0; nStrIndex
< rMissingCodes
.getLength(); )
1131 // also handle unicode surrogates
1132 const sal_uInt32 nCode
= rMissingCodes
.iterateCodePoints( &nStrIndex
);
1133 if (FcCharSetHasChar(unicodes
, nCode
) != FcTrue
)
1134 pRemainingCodes
[ nRemainingLen
++ ] = nCode
;
1137 OUString
sStillMissing(pRemainingCodes
, nRemainingLen
);
1138 #if defined(ENABLE_DBUS) && defined(ENABLE_PACKAGEKIT)
1139 if (get_xid_for_dbus())
1141 if (sStillMissing
== rMissingCodes
) //replaced nothing
1143 //It'd be better if we could ask packagekit using the
1144 //missing codepoints or some such rather than using
1145 //"language" as a proxy to how fontconfig considers
1146 //scripts to default to a given language.
1147 for (sal_Int32 i
= 0; i
< nRemainingLen
; ++i
)
1149 LanguageTag aOurTag
= getExemplerLangTagForCodePoint(pRemainingCodes
[i
]);
1150 OString sTag
= OUStringToOString(aOurTag
.getBcp47(), RTL_TEXTENCODING_UTF8
);
1151 if (m_aPreviousLangSupportRequests
.find(sTag
) != m_aPreviousLangSupportRequests
.end())
1153 m_aPreviousLangSupportRequests
.insert(sTag
);
1154 sTag
= mapToFontConfigLangTag(aOurTag
);
1155 if (!sTag
.isEmpty() && m_aPreviousLangSupportRequests
.find(sTag
) == m_aPreviousLangSupportRequests
.end())
1157 OString sReq
= OString(":lang=") + sTag
;
1158 m_aCurrentRequests
.push_back(sReq
);
1159 m_aPreviousLangSupportRequests
.insert(sTag
);
1163 if (!m_aCurrentRequests
.empty())
1165 m_aFontInstallerTimer
.Stop();
1166 m_aFontInstallerTimer
.Start();
1170 rMissingCodes
= sStillMissing
;
1174 FcFontSetDestroy( pSet
);
1180 class FontConfigFontOptions
: public ImplFontOptions
1183 FontConfigFontOptions() : mpPattern(0) {}
1184 ~FontConfigFontOptions()
1186 FcPatternDestroy(mpPattern
);
1188 virtual void *GetPattern(void * face
, bool bEmbolden
, bool /*bVerticalLayout*/) const
1191 value
.type
= FcTypeFTFace
;
1193 FcPatternDel(mpPattern
, FC_FT_FACE
);
1194 FcPatternAdd (mpPattern
, FC_FT_FACE
, value
, FcTrue
);
1195 FcPatternDel(mpPattern
, FC_EMBOLDEN
);
1196 FcPatternAddBool(mpPattern
, FC_EMBOLDEN
, bEmbolden
? FcTrue
: FcFalse
);
1198 FcPatternDel(mpPattern
, FC_VERTICAL_LAYOUT
);
1199 FcPatternAddBool(mpPattern
, FC_VERTICAL_LAYOUT
, bVerticalLayout
? FcTrue
: FcFalse
);
1203 FcPattern
* mpPattern
;
1206 ImplFontOptions
* PrintFontManager::getFontOptions(
1207 const FastPrintFontInfo
& rInfo
, int nSize
, void (*subcallback
)(void*)) const
1209 FontCfgWrapper
& rWrapper
= FontCfgWrapper::get();
1211 FontConfigFontOptions
* pOptions
= NULL
;
1212 FcConfig
* pConfig
= FcConfigGetCurrent();
1213 FcPattern
* pPattern
= FcPatternCreate();
1215 OString sFamily
= OUStringToOString( rInfo
.m_aFamilyName
, RTL_TEXTENCODING_UTF8
);
1217 boost::unordered_map
< OString
, OString
, OStringHash
>::const_iterator aI
= rWrapper
.m_aLocalizedToCanonical
.find(sFamily
);
1218 if (aI
!= rWrapper
.m_aLocalizedToCanonical
.end())
1219 sFamily
= aI
->second
;
1220 if( !sFamily
.isEmpty() )
1221 FcPatternAddString(pPattern
, FC_FAMILY
, (FcChar8
*)sFamily
.getStr());
1223 addtopattern(pPattern
, rInfo
.m_eItalic
, rInfo
.m_eWeight
, rInfo
.m_eWidth
, rInfo
.m_ePitch
);
1224 FcPatternAddDouble(pPattern
, FC_PIXEL_SIZE
, nSize
);
1226 FcBool embitmap
= true, antialias
= true, autohint
= true, hinting
= true;
1227 int hintstyle
= FC_HINT_FULL
;
1229 FcConfigSubstitute(pConfig
, pPattern
, FcMatchPattern
);
1231 subcallback(pPattern
);
1232 FcDefaultSubstitute(pPattern
);
1234 FcResult eResult
= FcResultNoMatch
;
1235 FcFontSet
* pFontSet
= rWrapper
.getFontSet();
1236 FcPattern
* pResult
= FcFontSetMatch( pConfig
, &pFontSet
, 1, pPattern
, &eResult
);
1239 FcResult eEmbeddedBitmap
= FcPatternGetBool(pResult
,
1240 FC_EMBEDDED_BITMAP
, 0, &embitmap
);
1241 FcResult eAntialias
= FcPatternGetBool(pResult
,
1242 FC_ANTIALIAS
, 0, &antialias
);
1243 FcResult eAutoHint
= FcPatternGetBool(pResult
,
1244 FC_AUTOHINT
, 0, &autohint
);
1245 FcResult eHinting
= FcPatternGetBool(pResult
,
1246 FC_HINTING
, 0, &hinting
);
1247 /*FcResult eHintStyle =*/ FcPatternGetInteger(pResult
,
1248 FC_HINT_STYLE
, 0, &hintstyle
);
1250 pOptions
= new FontConfigFontOptions
;
1252 pOptions
->mpPattern
= pResult
;
1254 if( eEmbeddedBitmap
== FcResultMatch
)
1255 pOptions
->meEmbeddedBitmap
= embitmap
? EMBEDDEDBITMAP_TRUE
: EMBEDDEDBITMAP_FALSE
;
1256 if( eAntialias
== FcResultMatch
)
1257 pOptions
->meAntiAlias
= antialias
? ANTIALIAS_TRUE
: ANTIALIAS_FALSE
;
1258 if( eAutoHint
== FcResultMatch
)
1259 pOptions
->meAutoHint
= autohint
? AUTOHINT_TRUE
: AUTOHINT_FALSE
;
1260 if( eHinting
== FcResultMatch
)
1261 pOptions
->meHinting
= hinting
? HINTING_TRUE
: HINTING_FALSE
;
1264 case FC_HINT_NONE
: pOptions
->meHintStyle
= HINT_NONE
; break;
1265 case FC_HINT_SLIGHT
: pOptions
->meHintStyle
= HINT_SLIGHT
; break;
1266 case FC_HINT_MEDIUM
: pOptions
->meHintStyle
= HINT_MEDIUM
; break;
1267 default: // fall through
1268 case FC_HINT_FULL
: pOptions
->meHintStyle
= HINT_FULL
; break;
1273 FcPatternDestroy( pPattern
);
1278 bool PrintFontManager::matchFont( FastPrintFontInfo
& rInfo
, const com::sun::star::lang::Locale
& rLocale
)
1280 FontCfgWrapper
& rWrapper
= FontCfgWrapper::get();
1282 FcConfig
* pConfig
= FcConfigGetCurrent();
1283 FcPattern
* pPattern
= FcPatternCreate();
1285 // populate pattern with font characteristics
1286 const LanguageTag
aLangTag(rLocale
);
1287 const OString aLangAttrib
= mapToFontConfigLangTag(aLangTag
);
1288 if (!aLangAttrib
.isEmpty())
1289 FcPatternAddString(pPattern
, FC_LANG
, (FcChar8
*)aLangAttrib
.getStr());
1291 OString aFamily
= OUStringToOString( rInfo
.m_aFamilyName
, RTL_TEXTENCODING_UTF8
);
1292 if( !aFamily
.isEmpty() )
1293 FcPatternAddString(pPattern
, FC_FAMILY
, (FcChar8
*)aFamily
.getStr());
1295 addtopattern(pPattern
, rInfo
.m_eItalic
, rInfo
.m_eWeight
, rInfo
.m_eWidth
, rInfo
.m_ePitch
);
1297 FcConfigSubstitute(pConfig
, pPattern
, FcMatchPattern
);
1298 FcDefaultSubstitute(pPattern
);
1299 FcResult eResult
= FcResultNoMatch
;
1300 FcFontSet
*pFontSet
= rWrapper
.getFontSet();
1301 FcPattern
* pResult
= FcFontSetMatch(pConfig
, &pFontSet
, 1, pPattern
, &eResult
);
1302 bool bSuccess
= false;
1305 FcFontSet
* pSet
= FcFontSetCreate();
1306 FcFontSetAdd( pSet
, pResult
);
1307 if( pSet
->nfont
> 0 )
1309 //extract the closest match
1310 FcChar8
* file
= NULL
;
1311 FcResult eFileRes
= FcPatternGetString(pSet
->fonts
[0], FC_FILE
, 0, &file
);
1312 int nCollectionEntry
= 0;
1313 FcResult eIndexRes
= FcPatternGetInteger(pSet
->fonts
[0], FC_INDEX
, 0, &nCollectionEntry
);
1314 if (eIndexRes
!= FcResultMatch
)
1315 nCollectionEntry
= 0;
1316 if( eFileRes
== FcResultMatch
)
1318 OString aDir
, aBase
, aOrgPath( (sal_Char
*)file
);
1319 splitPath( aOrgPath
, aDir
, aBase
);
1320 int nDirID
= getDirectoryAtom( aDir
, true );
1321 fontID aFont
= findFontFileID( nDirID
, aBase
, nCollectionEntry
);
1323 bSuccess
= getFontFastInfo( aFont
, rInfo
);
1326 // info: destroying the pSet destroys pResult implicitly
1327 // since pResult was "added" to pSet
1328 FcFontSetDestroy( pSet
);
1332 FcPatternDestroy( pPattern
);
1337 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */