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;
}
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)
bool SetFallbackFont(FontCacheSettings *, const std::string &, int, MissingGlyphSearcher *) { return false; }

View File

@ -61,13 +61,20 @@ public:
*/
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.
* @param language_isocode the language, e.g. en_GB.
* @param winlangid the language ID windows style.
* @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.
@ -76,7 +83,12 @@ public:
* @param font_family The font family to list.
* @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:
static inline FontSearcher *instance = nullptr;

View File

@ -389,61 +389,40 @@ void LoadCoreTextFont(FontSize fs)
class CoreTextFontSearcher : public FontSearcher {
public:
std::vector<std::string> ListFamilies(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;
void UpdateCachedFonts(const std::string &language_isocode, int winlangid) 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) {
/* 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) {
EnumerateCoreFextFonts(language_isocode, 1, [this](int, CTFontDescriptorRef font, CTFontSymbolicTraits) {
/* Get font name. */
char family[128];
CFAutoRelease<CFStringRef> family_name((CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontFamilyNameAttribute));
CFStringGetCString(family_name.get(), family, std::size(family), kCFStringEncodingUTF8);
if (font_family != family) return true;
char style[128];
CFAutoRelease<CFStringRef> style_name((CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontStyleNameAttribute));
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));
float weight = 0.0f;
CFNumberGetValue((CFNumberRef)CFDictionaryGetValue(traits.get(), kCTFontWeightTrait), kCFNumberFloatType, &weight);
float slant = 0.0f;
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 styles;
std::sort(std::begin(this->cached_fonts), std::end(this->cached_fonts), FontFamilySorter);
}
CoreTextFontSearcher _coretextfs_instance;

View File

@ -196,15 +196,14 @@ bool SetFallbackFont(FontCacheSettings *settings, const std::string &language_is
*/
class FontConfigFontSearcher : public FontSearcher {
public:
std::vector<std::string> ListFamilies(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;
void UpdateCachedFonts(const std::string &language_isocode, int winlangid) 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);
assert(fc_instance != nullptr);
@ -216,51 +215,6 @@ std::vector<std::string> FontConfigFontSearcher::ListFamilies(const std::string
/* We want to know this attributes. */
FcObjectSet *os = FcObjectSetCreate();
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_SLANT);
FcObjectSetAdd(os, FC_WEIGHT);
@ -272,7 +226,7 @@ std::vector<FontFamily> FontConfigFontSearcher::ListStyles(const std::string &la
FcPatternDestroy(pat);
if (fs != nullptr) {
styles.reserve(fs->nfont);
this->cached_fonts.reserve(fs->nfont);
for (const FcPattern *font : std::span(fs->fonts, fs->nfont)) {
FcChar8 *family;
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_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. */
@ -292,7 +251,8 @@ std::vector<FontFamily> FontConfigFontSearcher::ListStyles(const std::string &la
}
FcConfigDestroy(fc_instance);
return styles;
std::sort(std::begin(this->cached_fonts), std::end(this->cached_fonts), FontFamilySorter);
}
static FontConfigFontSearcher _fcfs_instance;

View File

@ -34,7 +34,7 @@
struct EFCParam {
FontCacheSettings *settings;
LOCALESIGNATURE locale;
LOCALESIGNATURE locale;
MissingGlyphSearcher *callback;
std::vector<std::wstring> fonts;
@ -384,20 +384,31 @@ void LoadWin32Font(FontSize fs)
*/
class Win32FontSearcher : public FontSearcher {
public:
std::vector<std::string> ListFamilies(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;
void UpdateCachedFonts(const std::string &language_isocode, int winlangid) override;
};
/**
* State passed between EnumFontFamiliesEx and our list families callback.
* State passed between EnumFontFamiliesEx and our list fonts callbacks.
*/
struct EFCListFamiliesParam : EFCParam {
std::vector<std::string> families; ///< List of families found.
struct EFCListFontsParam : EFCParam {
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)
{
EFCListFamiliesParam &info = *reinterpret_cast<EFCListFamiliesParam *>(lParam);
EFCListFontsParam &info = *reinterpret_cast<EFCListFontsParam *>(lParam);
/* Only use TrueType fonts */
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;
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;
}
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) {
/* 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.families;
return;
}
LOGFONT lf{};
@ -429,54 +445,6 @@ std::vector<std::string> Win32FontSearcher::ListFamilies(const std::string &, in
HDC dc = GetDC(nullptr);
EnumFontFamiliesEx(dc, &lf, (FONTENUMPROC)&ListFamiliesFontCallback, reinterpret_cast<LPARAM>(&info), 0);
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;