1
0
Fork 0

Change: WIP Change interface to list all families and styles at once.

pull/12790/head
Peter Nelson 2024-06-15 21:11:18 +01:00
parent 2f75614cfe
commit 233061aaa2
No known key found for this signature in database
GPG Key ID: 8EF8F0A467DF75ED
5 changed files with 101 additions and 146 deletions

View File

@ -255,6 +255,42 @@ FontSearcher::~FontSearcher()
FontSearcher::instance = nullptr; FontSearcher::instance = nullptr;
} }
std::vector<std::string_view> FontSearcher::ListFamilies(const std::string &language_isocode, int winlangid)
{
std::vector<std::string_view> families;
if (this->cached_language_isocode != language_isocode || this->cached_winlangid != winlangid) {
this->UpdateCachedFonts(language_isocode, winlangid);
this->cached_language_isocode = language_isocode;
this->cached_winlangid = winlangid;
}
for (const FontFamily &ff : this->cached_fonts) {
if (std::find(std::begin(families), std::end(families), ff.family) != std::end(families)) continue;
families.push_back(ff.family);
}
return families;
}
std::vector<std::reference_wrapper<const FontFamily>> FontSearcher::ListStyles(const std::string &language_isocode, int winlangid, std::string_view family)
{
std::vector<std::reference_wrapper<const FontFamily>> styles;
if (this->cached_language_isocode != language_isocode || this->cached_winlangid != winlangid) {
this->UpdateCachedFonts(language_isocode, winlangid);
this->cached_language_isocode = language_isocode;
this->cached_winlangid = winlangid;
}
for (const FontFamily &ff : this->cached_fonts) {
if (ff.family != family) continue;
styles.emplace_back(std::ref(ff));
}
return styles;
}
#if !defined(_WIN32) && !defined(__APPLE__) && !defined(WITH_FONTCONFIG) && !defined(WITH_COCOA) #if !defined(_WIN32) && !defined(__APPLE__) && !defined(WITH_FONTCONFIG) && !defined(WITH_COCOA)
bool SetFallbackFont(FontCacheSettings *, const std::string &, int, MissingGlyphSearcher *) { return false; } bool SetFallbackFont(FontCacheSettings *, const std::string &, int, MissingGlyphSearcher *) { return false; }

View File

@ -61,13 +61,20 @@ public:
*/ */
static inline FontSearcher *GetFontSearcher() { return FontSearcher::instance; } static inline FontSearcher *GetFontSearcher() { return FontSearcher::instance; }
/**
* Update cached font information.
* @param language_isocode the language, e.g. en_GB.
* @param winlangid the language ID windows style.
*/
virtual void UpdateCachedFonts(const std::string &language_isocode, int winlangid) = 0;
/** /**
* List available fonts. * List available fonts.
* @param language_isocode the language, e.g. en_GB. * @param language_isocode the language, e.g. en_GB.
* @param winlangid the language ID windows style. * @param winlangid the language ID windows style.
* @return vector containing font family names. * @return vector containing font family names.
*/ */
virtual std::vector<std::string> ListFamilies(const std::string &language_isocode, int winlangid) = 0; std::vector<std::string_view> ListFamilies(const std::string &language_isocode, int winlangid);
/** /**
* List available styles for a font family. * List available styles for a font family.
@ -76,7 +83,12 @@ public:
* @param font_family The font family to list. * @param font_family The font family to list.
* @return vector containing style information for the family. * @return vector containing style information for the family.
*/ */
virtual std::vector<FontFamily> ListStyles(const std::string &language_isocode, int winlangid, std::string_view font_family) = 0; std::vector<std::reference_wrapper<const FontFamily>> ListStyles(const std::string &language_isocode, int winlangid, std::string_view family);
protected:
std::vector<FontFamily> cached_fonts;
std::string cached_language_isocode;
int cached_winlangid;
private: private:
static inline FontSearcher *instance = nullptr; static inline FontSearcher *instance = nullptr;

View File

@ -389,61 +389,40 @@ void LoadCoreTextFont(FontSize fs)
class CoreTextFontSearcher : public FontSearcher { class CoreTextFontSearcher : public FontSearcher {
public: public:
std::vector<std::string> ListFamilies(const std::string &language_isocode, int winlangid) override; void UpdateCachedFonts(const std::string &language_isocode, int winlangid) override;
std::vector<FontFamily> ListStyles(const std::string &language_isocode, int winlangid, std::string_view font_family) override;
}; };
std::vector<std::string> CoreTextFontSearcher::ListFamilies(const std::string &language_isocode, int) void CoreTextFontSearcher::UpdateCachedFonts(const std::string &language_isocode, int)
{ {
std::vector<std::string> families; this->cached_fonts.clear();
EnumerateCoreFextFonts(language_isocode, 1, [&families](int, CTFontDescriptorRef font, CTFontSymbolicTraits) { EnumerateCoreFextFonts(language_isocode, 1, [this](int, CTFontDescriptorRef font, CTFontSymbolicTraits) {
/* Get font name. */
char family[128];
CFAutoRelease<CFStringRef> font_name((CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontFamilyNameAttribute));
CFStringGetCString(font_name.get(), family, std::size(family), kCFStringEncodingUTF8);
/* There are some special fonts starting with an '.' and the last resort font that aren't usable. Skip them. */
if (family[0] == '.' || strncmp(family, "LastResort", 10) == 0) return true;
if (std::find(std::begin(families), std::end(families), family) == std::end(families)) {
families.push_back(family);
}
return true;
});
return families;
}
std::vector<FontFamily> CoreTextFontSearcher::ListStyles(const std::string &language_isocode, int, std::string_view font_family)
{
std::vector<FontFamily> styles;
EnumerateCoreFextFonts(language_isocode, 1, [&styles, &font_family](int, CTFontDescriptorRef font, CTFontSymbolicTraits) {
/* Get font name. */ /* Get font name. */
char family[128]; char family[128];
CFAutoRelease<CFStringRef> family_name((CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontFamilyNameAttribute)); CFAutoRelease<CFStringRef> family_name((CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontFamilyNameAttribute));
CFStringGetCString(family_name.get(), family, std::size(family), kCFStringEncodingUTF8); CFStringGetCString(family_name.get(), family, std::size(family), kCFStringEncodingUTF8);
if (font_family != family) return true;
char style[128]; char style[128];
CFAutoRelease<CFStringRef> style_name((CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontStyleNameAttribute)); CFAutoRelease<CFStringRef> style_name((CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontStyleNameAttribute));
CFStringGetCString(style_name.get(), style, std::size(style), kCFStringEncodingUTF8); CFStringGetCString(style_name.get(), style, std::size(style), kCFStringEncodingUTF8);
/* Don't add duplicate fonts. */
std::string_view sv_family = family;
std::string_view sv_style = style;
if (std::any_of(std::begin(this->cached_fonts), std::end(this->cached_fonts), [&sv_family, &sv_style](const FontFamily &ff) { return ff.family == sv_family && ff.style == sv_style; })) return true;
CFAutoRelease<CFDictionaryRef> traits((CFDictionaryRef)CTFontDescriptorCopyAttribute(font, kCTFontTraitsAttribute)); CFAutoRelease<CFDictionaryRef> traits((CFDictionaryRef)CTFontDescriptorCopyAttribute(font, kCTFontTraitsAttribute));
float weight = 0.0f; float weight = 0.0f;
CFNumberGetValue((CFNumberRef)CFDictionaryGetValue(traits.get(), kCTFontWeightTrait), kCFNumberFloatType, &weight); CFNumberGetValue((CFNumberRef)CFDictionaryGetValue(traits.get(), kCTFontWeightTrait), kCFNumberFloatType, &weight);
float slant = 0.0f; float slant = 0.0f;
CFNumberGetValue((CFNumberRef)CFDictionaryGetValue(traits.get(), kCTFontSlantTrait), kCFNumberFloatType, &slant); CFNumberGetValue((CFNumberRef)CFDictionaryGetValue(traits.get(), kCTFontSlantTrait), kCFNumberFloatType, &slant);
styles.emplace_back(family, style, static_cast<int>(slant * 100), static_cast<int>(weight * 100)); this->cached_fonts.emplace_back(sv_family, sv_style, static_cast<int>(slant * 100), static_cast<int>(weight * 100));
return true; return true;
}); });
return styles; std::sort(std::begin(this->cached_fonts), std::end(this->cached_fonts), FontFamilySorter);
} }
CoreTextFontSearcher _coretextfs_instance; CoreTextFontSearcher _coretextfs_instance;

View File

@ -196,15 +196,14 @@ bool SetFallbackFont(FontCacheSettings *settings, const std::string &language_is
*/ */
class FontConfigFontSearcher : public FontSearcher { class FontConfigFontSearcher : public FontSearcher {
public: public:
std::vector<std::string> ListFamilies(const std::string &language_isocode, int winlangid) override; void UpdateCachedFonts(const std::string &language_isocode, int winlangid) override;
std::vector<FontFamily> ListStyles(const std::string &language_isocode, int winlangid, std::string_view font_family) override;
}; };
std::vector<std::string> FontConfigFontSearcher::ListFamilies(const std::string &language_isocode, int) void FontConfigFontSearcher::UpdateCachedFonts(const std::string &language_isocode, int)
{ {
std::vector<std::string> families; this->cached_fonts.clear();
if (!FcInit()) return families; if (!FcInit()) return;
FcConfig *fc_instance = FcConfigReference(nullptr); FcConfig *fc_instance = FcConfigReference(nullptr);
assert(fc_instance != nullptr); assert(fc_instance != nullptr);
@ -216,51 +215,6 @@ std::vector<std::string> FontConfigFontSearcher::ListFamilies(const std::string
/* We want to know this attributes. */ /* We want to know this attributes. */
FcObjectSet *os = FcObjectSetCreate(); FcObjectSet *os = FcObjectSetCreate();
FcObjectSetAdd(os, FC_FAMILY); FcObjectSetAdd(os, FC_FAMILY);
/* Get the list of filenames matching the wanted language. */
FcFontSet *fs = FcFontList(nullptr, pat, os);
/* We don't need these anymore. */
FcObjectSetDestroy(os);
FcPatternDestroy(pat);
if (fs != nullptr) {
families.reserve(fs->nfont);
for (const FcPattern *font : std::span(fs->fonts, fs->nfont)) {
FcChar8 *family;
if (FcPatternGetString(font, FC_FAMILY, 0, &family) != FcResultMatch) continue;
/* Check if the family already exists. */
std::string_view sv_family = reinterpret_cast<const char *>(family);
if (std::find(std::begin(families), std::end(families), sv_family) != std::end(families)) continue;
families.emplace_back(sv_family);
}
/* Clean up the list of filenames. */
FcFontSetDestroy(fs);
}
FcConfigDestroy(fc_instance);
return families;
}
std::vector<FontFamily> FontConfigFontSearcher::ListStyles(const std::string &language_isocode, int, std::string_view font_family)
{
std::vector<FontFamily> styles;
if (!FcInit()) return styles;
FcConfig *fc_instance = FcConfigReference(nullptr);
assert(fc_instance != nullptr);
std::string lang = GetFontConfigLanguage(language_isocode);
/* First create a pattern to match the wanted language. */
FcPattern *pat = FcNameParse(reinterpret_cast<const FcChar8 *>(lang.c_str()));
FcPatternAddString(pat, FC_FAMILY, reinterpret_cast<const FcChar8 *>(std::string(font_family).c_str()));
/* We want to know these attributes. */
FcObjectSet *os = FcObjectSetCreate();
FcObjectSetAdd(os, FC_FAMILY);
FcObjectSetAdd(os, FC_STYLE); FcObjectSetAdd(os, FC_STYLE);
FcObjectSetAdd(os, FC_SLANT); FcObjectSetAdd(os, FC_SLANT);
FcObjectSetAdd(os, FC_WEIGHT); FcObjectSetAdd(os, FC_WEIGHT);
@ -272,7 +226,7 @@ std::vector<FontFamily> FontConfigFontSearcher::ListStyles(const std::string &la
FcPatternDestroy(pat); FcPatternDestroy(pat);
if (fs != nullptr) { if (fs != nullptr) {
styles.reserve(fs->nfont); this->cached_fonts.reserve(fs->nfont);
for (const FcPattern *font : std::span(fs->fonts, fs->nfont)) { for (const FcPattern *font : std::span(fs->fonts, fs->nfont)) {
FcChar8 *family; FcChar8 *family;
FcChar8 *style; FcChar8 *style;
@ -284,7 +238,12 @@ std::vector<FontFamily> FontConfigFontSearcher::ListStyles(const std::string &la
if (FcPatternGetInteger(font, FC_SLANT, 0, &slant) != FcResultMatch) continue; if (FcPatternGetInteger(font, FC_SLANT, 0, &slant) != FcResultMatch) continue;
if (FcPatternGetInteger(font, FC_WEIGHT, 0, &weight) != FcResultMatch) continue; if (FcPatternGetInteger(font, FC_WEIGHT, 0, &weight) != FcResultMatch) continue;
styles.emplace_back(reinterpret_cast<const char *>(family), reinterpret_cast<const char *>(style), slant, weight); /* Don't add duplicate fonts. */
std::string_view sv_family = reinterpret_cast<const char *>(family);
std::string_view sv_style = reinterpret_cast<const char *>(style);
if (std::any_of(std::begin(this->cached_fonts), std::end(this->cached_fonts), [&sv_family, &sv_style](const FontFamily &ff) { return ff.family == sv_family && ff.style == sv_style; })) continue;
this->cached_fonts.emplace_back(sv_family, sv_style, slant, weight);
} }
/* Clean up the list of filenames. */ /* Clean up the list of filenames. */
@ -292,7 +251,8 @@ std::vector<FontFamily> FontConfigFontSearcher::ListStyles(const std::string &la
} }
FcConfigDestroy(fc_instance); FcConfigDestroy(fc_instance);
return styles;
std::sort(std::begin(this->cached_fonts), std::end(this->cached_fonts), FontFamilySorter);
} }
static FontConfigFontSearcher _fcfs_instance; static FontConfigFontSearcher _fcfs_instance;

View File

@ -34,7 +34,7 @@
struct EFCParam { struct EFCParam {
FontCacheSettings *settings; FontCacheSettings *settings;
LOCALESIGNATURE locale; LOCALESIGNATURE locale;
MissingGlyphSearcher *callback; MissingGlyphSearcher *callback;
std::vector<std::wstring> fonts; std::vector<std::wstring> fonts;
@ -384,20 +384,31 @@ void LoadWin32Font(FontSize fs)
*/ */
class Win32FontSearcher : public FontSearcher { class Win32FontSearcher : public FontSearcher {
public: public:
std::vector<std::string> ListFamilies(const std::string &language_isocode, int winlangid) override; void UpdateCachedFonts(const std::string &language_isocode, int winlangid) override;
std::vector<FontFamily> ListStyles(const std::string &language_isocode, int winlangid, std::string_view font_family) override;
}; };
/** /**
* State passed between EnumFontFamiliesEx and our list families callback. * State passed between EnumFontFamiliesEx and our list fonts callbacks.
*/ */
struct EFCListFamiliesParam : EFCParam { struct EFCListFontsParam : EFCParam {
std::vector<std::string> families; ///< List of families found. std::vector<FontFamily> &fonts;
explicit EFCListFontsParam(std::vector<FontFamily> &fonts) : fonts(fonts) {}
}; };
static int CALLBACK ListStylesFontCallback(ENUMLOGFONTEX *lpelfe, NEWTEXTMETRICEX *, DWORD, LPARAM lParam)
{
EFCListFontsParam &info = *reinterpret_cast<EFCListFontsParam *>(lParam);
LOGFONT &lf = lpelfe->elfLogFont;
info.fonts.emplace_back(FS2OTTD(lf.lfFaceName), FS2OTTD(lpelfe->elfStyle), lf.lfItalic, lf.lfWeight);
return 1;
}
static int CALLBACK ListFamiliesFontCallback(ENUMLOGFONTEX *lpelfe, NEWTEXTMETRICEX *metric, DWORD type, LPARAM lParam) static int CALLBACK ListFamiliesFontCallback(ENUMLOGFONTEX *lpelfe, NEWTEXTMETRICEX *metric, DWORD type, LPARAM lParam)
{ {
EFCListFamiliesParam &info = *reinterpret_cast<EFCListFamiliesParam *>(lParam); EFCListFontsParam &info = *reinterpret_cast<EFCListFontsParam *>(lParam);
/* Only use TrueType fonts */ /* Only use TrueType fonts */
if (!(type & TRUETYPE_FONTTYPE)) return 1; if (!(type & TRUETYPE_FONTTYPE)) return 1;
@ -409,18 +420,23 @@ static int CALLBACK ListFamiliesFontCallback(ENUMLOGFONTEX *lpelfe, NEWTEXTMETRI
if ((metric->ntmFontSig.fsCsb[0] & info.locale.lsCsbSupported[0]) == 0 && (metric->ntmFontSig.fsCsb[1] & info.locale.lsCsbSupported[1]) == 0) return 1; if ((metric->ntmFontSig.fsCsb[0] & info.locale.lsCsbSupported[0]) == 0 && (metric->ntmFontSig.fsCsb[1] & info.locale.lsCsbSupported[1]) == 0) return 1;
LOGFONT &lf = lpelfe->elfLogFont; LOGFONT &lf = lpelfe->elfLogFont;
info.families.emplace_back(FS2OTTD(lf.lfFaceName));
HDC dc = GetDC(nullptr);
EnumFontFamiliesEx(dc, &lf, (FONTENUMPROC)&ListStylesFontCallback, reinterpret_cast<LPARAM>(&info), 0);
ReleaseDC(nullptr, dc);
return 1; return 1;
} }
std::vector<std::string> Win32FontSearcher::ListFamilies(const std::string &, int winlangid) void Win32FontSearcher::UpdateCachedFonts(const std::string &, int winlangid)
{ {
EFCListFamiliesParam info; EFCListFontsParam info(this->cached_fonts);
this->cached_fonts.clear();
if (GetLocaleInfo(MAKELCID(winlangid, SORT_DEFAULT), LOCALE_FONTSIGNATURE, reinterpret_cast<LPTSTR>(&info.locale), sizeof(info.locale) / sizeof(wchar_t)) == 0) { if (GetLocaleInfo(MAKELCID(winlangid, SORT_DEFAULT), LOCALE_FONTSIGNATURE, reinterpret_cast<LPTSTR>(&info.locale), sizeof(info.locale) / sizeof(wchar_t)) == 0) {
/* Invalid langid or some other mysterious error, can't determine fallback font. */ /* Invalid langid or some other mysterious error, can't determine fallback font. */
Debug(fontcache, 1, "Can't get locale info for fallback font (langid=0x{:x})", winlangid); Debug(fontcache, 1, "Can't get locale info for fallback font (langid=0x{:x})", winlangid);
return info.families; return;
} }
LOGFONT lf{}; LOGFONT lf{};
@ -429,54 +445,6 @@ std::vector<std::string> Win32FontSearcher::ListFamilies(const std::string &, in
HDC dc = GetDC(nullptr); HDC dc = GetDC(nullptr);
EnumFontFamiliesEx(dc, &lf, (FONTENUMPROC)&ListFamiliesFontCallback, reinterpret_cast<LPARAM>(&info), 0); EnumFontFamiliesEx(dc, &lf, (FONTENUMPROC)&ListFamiliesFontCallback, reinterpret_cast<LPARAM>(&info), 0);
ReleaseDC(nullptr, dc); ReleaseDC(nullptr, dc);
return info.families;
}
/**
* State passed between EnumFontFamiliesEx and our list styles callback.
*/
struct EFCListStylesParam : EFCParam {
std::vector<FontFamily> styles; ///< List of styles for the family.
};
static int CALLBACK ListStylesFontCallback(ENUMLOGFONTEX *lpelfe, NEWTEXTMETRICEX *metric, DWORD type, LPARAM lParam)
{
EFCListStylesParam &info = *reinterpret_cast<EFCListStylesParam *>(lParam);
/* Only use TrueType fonts */
if (!(type & TRUETYPE_FONTTYPE)) return 1;
/* Skip duplicates */
if (!info.Add(lpelfe->elfFullName)) return 1;
/* Don't use SYMBOL fonts */
if (lpelfe->elfLogFont.lfCharSet == SYMBOL_CHARSET) return 1;
/* The font has to have at least one of the supported locales to be usable. */
if ((metric->ntmFontSig.fsCsb[0] & info.locale.lsCsbSupported[0]) == 0 && (metric->ntmFontSig.fsCsb[1] & info.locale.lsCsbSupported[1]) == 0) return 1;
LOGFONT &lf = lpelfe->elfLogFont;
info.styles.emplace_back(FS2OTTD(lf.lfFaceName), FS2OTTD(lpelfe->elfStyle), lf.lfItalic, lf.lfWeight);
return 1;
}
std::vector<FontFamily> Win32FontSearcher::ListStyles(const std::string &, int winlangid, std::string_view font_family)
{
EFCListStylesParam info;
if (GetLocaleInfo(MAKELCID(winlangid, SORT_DEFAULT), LOCALE_FONTSIGNATURE, reinterpret_cast<LPTSTR>(&info.locale), sizeof(info.locale) / sizeof(wchar_t)) == 0) {
/* Invalid langid or some other mysterious error, can't determine fallback font. */
Debug(fontcache, 1, "Can't get locale info for fallback font (langid=0x{:x})", winlangid);
return info.styles;
}
LOGFONT lf{};
lf.lfCharSet = DEFAULT_CHARSET;
convert_to_fs(font_family, lf.lfFaceName, std::size(lf.lfFaceName));
HDC dc = GetDC(nullptr);
EnumFontFamiliesEx(dc, &lf, (FONTENUMPROC)&ListStylesFontCallback, reinterpret_cast<LPARAM>(&info), 0);
ReleaseDC(nullptr, dc);
return info.styles;
} }
static Win32FontSearcher _win32fs_instance; static Win32FontSearcher _win32fs_instance;