124 if( aSearchLang.Lower() == aSupportedLang.Lower() )
127 if( aSupportedLang.empty() )
130 if( aSearchLang.empty() )
133 wxArrayString supportedLangBits;
134 wxStringSplit( aSupportedLang.Lower(), supportedLangBits, wxS(
'-' ) );
136 wxArrayString searhcLangBits;
137 wxStringSplit( aSearchLang.Lower(), searhcLangBits, wxS(
'-' ) );
141 if( searhcLangBits.size() == 1 || supportedLangBits.size() == 1 )
143 return searhcLangBits[0] == supportedLangBits[0];
214 int& aFaceIndex,
bool aBold,
bool aItalic,
215 const std::vector<wxString>* aEmbeddedFiles )
224 if( aFontName.Lower().Contains( wxS(
"bold" ) )
225 || aFontName.Lower().Contains( wxS(
"heavy" ) )
226 || aFontName.Lower().Contains( wxS(
"black" ) )
227 || aFontName.Lower().Contains( wxS(
"thick" ) )
228 || aFontName.Lower().Contains( wxS(
"dark" ) ) )
233 FcConfig*
config = FcConfigGetCurrent();
237 for(
const auto& file : *aEmbeddedFiles )
239 FcConfigAppFontAddFile(
config, (
const FcChar8*) file.c_str().AsChar() );
243 wxString qualifiedFontName = aFontName;
245 wxScopedCharBuffer
const fcBuffer = qualifiedFontName.ToUTF8();
247 FcPattern* pat = FcPatternCreate();
250 FcPatternAddString( pat, FC_STYLE, (
const FcChar8*)
"Bold" );
253 FcPatternAddString( pat, FC_STYLE, (
const FcChar8*)
"Italic" );
255 FcPatternAddString( pat, FC_FAMILY, (FcChar8*) fcBuffer.data() );
257 FcConfigSubstitute(
config, pat, FcMatchPattern );
258 FcDefaultSubstitute( pat );
260 FcResult r = FcResultNoMatch;
261 FcPattern* font = FcFontMatch(
config, pat, &r );
267 FcChar8* file =
nullptr;
269 if( FcPatternGetString( font, FC_FILE, 0, &file ) == FcResultMatch )
271 aFontFile = wxString::FromUTF8( (
char*) file );
275 FcChar8* family =
nullptr;
276 FcChar8* style =
nullptr;
280 std::unordered_map<std::string, std::string> famStrings;
285 if( FcPatternGetString( font, FC_FAMILY, 0, &family ) == FcResultMatch )
287 FcPatternGetInteger( font, FC_INDEX, 0, &aFaceIndex );
289 fontName = wxString::FromUTF8( (
char*) family );
291 if( FcPatternGetString( font, FC_STYLE, 0, &style ) == FcResultMatch )
293 styleStr = wxString::FromUTF8( (
char*) style );
295 if( !styleStr.IsEmpty() )
297 styleStr.Replace(
' ',
':' );
298 fontName +=
':' + styleStr;
302 bool has_bold =
false;
303 bool has_ital =
false;
304 wxString lower_style = styleStr.Lower();
306 if( lower_style.Contains( wxS(
"thin" ) )
307 || lower_style.Contains( wxS(
"light" ) )
308 || lower_style.Contains( wxS(
"regular" ) )
309 || lower_style.Contains( wxS(
"roman" ) )
310 || lower_style.Contains( wxS(
"book" ) ) )
314 else if( lower_style.Contains( wxS(
"medium" ) )
315 || lower_style.Contains( wxS(
"semibold" ) )
316 || lower_style.Contains( wxS(
"demibold" ) ) )
320 else if( lower_style.Contains( wxS(
"bold" ) )
321 || lower_style.Contains( wxS(
"heavy" ) )
322 || lower_style.Contains( wxS(
"black" ) )
323 || lower_style.Contains( wxS(
"thick" ) )
324 || lower_style.Contains( wxS(
"dark" ) ) )
329 if( lower_style.Contains( wxS(
"italic" ) )
330 || lower_style.Contains( wxS(
"oblique" ) )
331 || lower_style.Contains( wxS(
"slant" ) ) )
336 for(
auto const& [key, val] : famStrings )
339 searchFont = wxString::FromUTF8( (
char*) val.data() );
341 if( searchFont.Lower().StartsWith( aFontName.Lower() ) )
343 if( ( aBold && !has_bold ) && ( aItalic && !has_ital ) )
345 else if( aBold && !has_bold )
347 else if( aItalic && !has_ital )
349 else if( ( aBold != has_bold ) || ( aItalic != has_ital ) )
360 FcPatternDestroy( font );
366 s_reporter->Report( wxString::Format(
_(
"Error loading font '%s'." ),
367 qualifiedFontName ) );
371 fontName.Replace(
':',
' ' );
375 if( fontName.CmpNoCase( qualifiedFontName ) == 0 )
378 s_reporter->Report( wxString::Format(
_(
"Font '%s' not found; substituting '%s'." ),
379 qualifiedFontName, fontName ) );
382 FcPatternDestroy( pat );
388 const std::vector<wxString>* aEmbeddedFiles,
bool aForce )
396 FcConfig*
config = FcConfigGetCurrent();
400 for(
const auto& file : *aEmbeddedFiles )
402 FcConfigAppFontAddFile(
config, (
const FcChar8*) file.c_str().AsChar() );
406 FcPattern* pat = FcPatternCreate();
407 FcObjectSet* os = FcObjectSetBuild( FC_FAMILY, FC_FAMILYLANG, FC_STYLE, FC_LANG, FC_FILE,
408 FC_OUTLINE,
nullptr );
409 FcFontSet* fs = FcFontList(
config, pat, os );
411 for(
int i = 0; fs && i < fs->nfont; ++i )
413 FcPattern* font = fs->fonts[i];
419 if( FcPatternGetString( font, FC_FILE, 0, &file ) == FcResultMatch
420 && FcPatternGetString( font, FC_STYLE, 0, &style ) == FcResultMatch
421 && FcPatternGetLangSet( font, FC_LANG, 0, &langSet ) == FcResultMatch
422 && FcPatternGetBool( font, FC_OUTLINE, 0, &outline ) == FcResultMatch )
428 std::string theFamily =
439 static std::map<wxString, bool> availableLanguages;
441 FcStrSet* langStrSet = FcLangSetGetLangs( langSet );
442 FcStrList* langStrList = FcStrListCreate( langStrSet );
443 FcChar8* langStr = FcStrListNext( langStrList );
444 bool langSupported =
false;
449 langSupported =
true;
451 else while( langStr )
453 wxString langWxStr(
reinterpret_cast<char *
>( langStr ) );
455 if( availableLanguages.find( langWxStr ) == availableLanguages.end() )
457 const wxLanguageInfo* langInfo = wxLocale::FindLanguageInfo( langWxStr );
458 bool available = langInfo && wxLocale::IsAvailable( langInfo->Language );
460 availableLanguages[ langWxStr ] = available;
463 if( availableLanguages[ langWxStr ] )
465 langSupported =
true;
471 wxS(
"Font '%s' language '%s' not supported by OS." ),
472 theFamily, langWxStr );
475 langStr = FcStrListNext( langStrList );
478 FcStrListDone( langStrList );
479 FcStrSetDestroy( langStrSet );
485 std::string theFile(
reinterpret_cast<char *
>( file ) );
486 std::string theStyle(
reinterpret_cast<char *
>( style ) );
487 FONTINFO fontInfo( std::move( theFile ), std::move( theStyle ), theFamily );
489 if( theFamily.length() > 0 && theFamily.front() ==
'.' )
492 std::map<std::string, FONTINFO>::iterator it =
m_fontInfoCache.find( theFamily );
497 it->second.Children().push_back( fontInfo );
502 FcFontSetDestroy( fs );
507 for(
const std::pair<const std::string, FONTINFO>& entry :
m_fontInfoCache )
508 aFonts.push_back( entry.second.Family() );