33#define WIN32_LEAN_AND_MEAN
55 return wxString::Format(
"%d.%d.%d", FC_MAJOR, FC_MINOR, FC_REVISION );
79#if defined( _MSC_VER )
85#if defined( _MSC_VER )
87 __except( GetExceptionCode() == STATUS_IN_PAGE_ERROR ? EXCEPTION_EXECUTE_HANDLER
88 : EXCEPTION_CONTINUE_SEARCH )
114 if( aSearchLang.Lower() == aSupportedLang.Lower() )
117 if( aSupportedLang.empty() )
120 if( aSearchLang.empty() )
123 wxArrayString supportedLangBits;
124 wxStringSplit( aSupportedLang.Lower(), supportedLangBits, wxS(
'-' ) );
126 wxArrayString searhcLangBits;
127 wxStringSplit( aSearchLang.Lower(), searhcLangBits, wxS(
'-' ) );
131 if( searhcLangBits.size() == 1 || supportedLangBits.size() == 1 )
133 return searhcLangBits[0] == supportedLangBits[0];
147 if( FcPatternGetString( aPat.
pat, aObj, aIdx, &str ) == FcResultMatch )
148 res = std::string(
reinterpret_cast<char*
>( str ) );
155 std::unordered_map<std::string, std::string>& aFamStringMap )
163 famLang =
getFcString( aPat, FC_FAMILYLANG, langIdx );
165 if( famLang.empty() && langIdx != 0 )
170 aFamStringMap.insert_or_assign( famLang, fam );
172 }
while( langIdx++ < std::numeric_limits<
179 std::unordered_map<std::string, std::string> famStrings;
182 if( famStrings.empty() )
185 for(
auto const& [key, val] : famStrings )
196 return famStrings.begin()->second;
201 int& aFaceIndex,
bool aBold,
bool aItalic,
202 const std::vector<wxString>* aEmbeddedFiles )
211 if( aFontName.Lower().Contains( wxS(
"bold" ) )
212 || aFontName.Lower().Contains( wxS(
"heavy" ) )
213 || aFontName.Lower().Contains( wxS(
"black" ) )
214 || aFontName.Lower().Contains( wxS(
"thick" ) )
215 || aFontName.Lower().Contains( wxS(
"dark" ) ) )
220 FcConfig*
config = FcConfigGetCurrent();
224 for(
const auto& file : *aEmbeddedFiles )
226 FcConfigAppFontAddFile(
config, (
const FcChar8*) file.c_str().AsChar() );
230 wxString qualifiedFontName = aFontName;
232 wxScopedCharBuffer
const fcBuffer = qualifiedFontName.ToUTF8();
234 FcPattern* pat = FcPatternCreate();
237 FcPatternAddString( pat, FC_STYLE, (
const FcChar8*)
"Bold" );
240 FcPatternAddString( pat, FC_STYLE, (
const FcChar8*)
"Italic" );
242 FcPatternAddString( pat, FC_FAMILY, (FcChar8*) fcBuffer.data() );
244 FcConfigSubstitute(
config, pat, FcMatchPattern );
245 FcDefaultSubstitute( pat );
247 FcResult r = FcResultNoMatch;
248 FcPattern* font = FcFontMatch(
config, pat, &r );
254 FcChar8* file =
nullptr;
256 if( FcPatternGetString( font, FC_FILE, 0, &file ) == FcResultMatch )
258 aFontFile = wxString::FromUTF8( (
char*) file );
262 FcChar8* family =
nullptr;
263 FcChar8* style =
nullptr;
267 std::unordered_map<std::string, std::string> famStrings;
272 if( FcPatternGetString( font, FC_FAMILY, 0, &family ) == FcResultMatch )
274 FcPatternGetInteger( font, FC_INDEX, 0, &aFaceIndex );
276 fontName = wxString::FromUTF8( (
char*) family );
278 if( FcPatternGetString( font, FC_STYLE, 0, &style ) == FcResultMatch )
280 styleStr = wxString::FromUTF8( (
char*) style );
282 if( !styleStr.IsEmpty() )
284 styleStr.Replace(
' ',
':' );
285 fontName +=
':' + styleStr;
289 bool has_bold =
false;
290 bool has_ital =
false;
291 wxString lower_style = styleStr.Lower();
293 if( lower_style.Contains( wxS(
"thin" ) )
294 || lower_style.Contains( wxS(
"light" ) )
295 || lower_style.Contains( wxS(
"regular" ) )
296 || lower_style.Contains( wxS(
"roman" ) )
297 || lower_style.Contains( wxS(
"book" ) ) )
301 else if( lower_style.Contains( wxS(
"medium" ) )
302 || lower_style.Contains( wxS(
"semibold" ) )
303 || lower_style.Contains( wxS(
"demibold" ) ) )
307 else if( lower_style.Contains( wxS(
"bold" ) )
308 || lower_style.Contains( wxS(
"heavy" ) )
309 || lower_style.Contains( wxS(
"black" ) )
310 || lower_style.Contains( wxS(
"thick" ) )
311 || lower_style.Contains( wxS(
"dark" ) ) )
316 if( lower_style.Contains( wxS(
"italic" ) )
317 || lower_style.Contains( wxS(
"oblique" ) )
318 || lower_style.Contains( wxS(
"slant" ) ) )
323 for(
auto const& [key, val] : famStrings )
326 searchFont = wxString::FromUTF8( (
char*) val.data() );
328 if( searchFont.Lower().StartsWith( aFontName.Lower() ) )
330 if( ( aBold && !has_bold ) && ( aItalic && !has_ital ) )
332 else if( aBold && !has_bold )
334 else if( aItalic && !has_ital )
336 else if( ( aBold != has_bold ) || ( aItalic != has_ital ) )
347 FcPatternDestroy( font );
353 s_reporter->
Report( wxString::Format(
_(
"Error loading font '%s'." ), qualifiedFontName ) );
357 fontName.Replace(
':',
' ' );
360 if( fontName.CmpNoCase( qualifiedFontName ) == 0 )
363 s_reporter->
Report( wxString::Format(
_(
"Font '%s' not found; substituting '%s'." ), qualifiedFontName, fontName ) );
366 FcPatternDestroy( pat );
372 const std::vector<wxString>* aEmbeddedFiles,
bool aForce )
380 FcConfig*
config = FcConfigGetCurrent();
384 for(
const auto& file : *aEmbeddedFiles )
386 FcConfigAppFontAddFile(
config, (
const FcChar8*) file.c_str().AsChar() );
390 FcPattern* pat = FcPatternCreate();
391 FcObjectSet* os = FcObjectSetBuild( FC_FAMILY, FC_FAMILYLANG, FC_STYLE, FC_LANG, FC_FILE,
392 FC_OUTLINE,
nullptr );
393 FcFontSet* fs = FcFontList(
config, pat, os );
395 for(
int i = 0; fs && i < fs->nfont; ++i )
397 FcPattern* font = fs->fonts[i];
403 if( FcPatternGetString( font, FC_FILE, 0, &file ) == FcResultMatch
404 && FcPatternGetString( font, FC_STYLE, 0, &style ) == FcResultMatch
405 && FcPatternGetLangSet( font, FC_LANG, 0, &langSet ) == FcResultMatch
406 && FcPatternGetBool( font, FC_OUTLINE, 0, &outline ) == FcResultMatch )
412 std::string theFamily =
423 static std::map<wxString, bool> availableLanguages;
425 FcStrSet* langStrSet = FcLangSetGetLangs( langSet );
426 FcStrList* langStrList = FcStrListCreate( langStrSet );
427 FcChar8* langStr = FcStrListNext( langStrList );
428 bool langSupported =
false;
433 langSupported =
true;
435 else while( langStr )
437 wxString langWxStr(
reinterpret_cast<char *
>( langStr ) );
439 if( availableLanguages.find( langWxStr ) == availableLanguages.end() )
441 const wxLanguageInfo* langInfo = wxLocale::FindLanguageInfo( langWxStr );
442 bool available = langInfo && wxLocale::IsAvailable( langInfo->Language );
444 availableLanguages[ langWxStr ] = available;
447 if( availableLanguages[ langWxStr ] )
449 langSupported =
true;
454 wxLogTrace(
traceFonts, wxS(
"Font '%s' language '%s' not supported by OS." ),
455 theFamily, langWxStr );
458 langStr = FcStrListNext( langStrList );
461 FcStrListDone( langStrList );
462 FcStrSetDestroy( langStrSet );
468 std::string theFile(
reinterpret_cast<char *
>( file ) );
469 std::string theStyle(
reinterpret_cast<char *
>( style ) );
470 FONTINFO fontInfo( std::move( theFile ), std::move( theStyle ), theFamily );
472 if( theFamily.length() > 0 && theFamily.front() ==
'.' )
475 std::map<std::string, FONTINFO>::iterator it =
m_fontInfoCache.find( theFamily );
480 it->second.Children().push_back( fontInfo );
485 FcFontSetDestroy( fs );
490 for(
const std::pair<const std::string, FONTINFO>& entry :
m_fontInfoCache )
491 aFonts.push_back( entry.second.Family() );
A pure virtual class used to derive REPORTER objects from.
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)=0
Report a string with a given severity.
static REPORTER * s_reporter
void getAllFamilyStrings(FONTCONFIG_PAT &aPat, std::unordered_map< std::string, std::string > &aFamStringMap)
Gets a list of all family name strings maped to lang.
static wxString Version()
static void SetReporter(REPORTER *aReporter)
Set the reporter to use for reporting font substitution warnings.
std::map< std::string, FONTINFO > m_fontInfoCache
FF_RESULT FindFont(const wxString &aFontName, wxString &aFontFile, int &aFaceIndex, bool aBold, bool aItalic, const std::vector< wxString > *aEmbeddedFiles=nullptr)
Given a fully-qualified font name ("Times:Bold:Italic") find the closest matching font and return its...
std::string getFcString(FONTCONFIG_PAT &aPat, const char *aObj, int aIdx)
Wrapper of FcPatternGetString to return a std::string.
std::string getFamilyStringByLang(FONTCONFIG_PAT &APat, const wxString &aDesiredLang)
Gets a family name based on desired language.
bool isLanguageMatch(const wxString &aSearchLang, const wxString &aSupportedLang)
Matches the two rfc 3306 language entries, used for when searching for matching family names.
void ListFonts(std::vector< std::string > &aFonts, const std::string &aDesiredLang, const std::vector< wxString > *aEmbeddedFiles=nullptr, bool aForce=false)
List the current available font families.
wxString m_fontCacheLastLang
static FONTCONFIG * g_config
FONTCONFIG * Fontconfig()
static void bootstrapFc()
This is simply a wrapper to call FcInit() with SEH for Windows SEH on Windows can only be used in fun...
static bool g_fcInitSuccess
const wxChar *const traceFonts
Flag to enable locale debug output.
This file contains miscellaneous commonly used macros and functions.
static WX_STRING_REPORTER s_reporter
wxString From_UTF8(const char *cstring)
void wxStringSplit(const wxString &aText, wxArrayString &aStrings, wxChar aSplitter)
Split aString to a string list separated at aSplitter.
A simple wrapper to avoid exporing fontconfig in the header.
wxLogTrace helper definitions.