mirror of https://github.com/OpenTTD/OpenTTD
Change: WIP Change interface to list all families and styles at once.
parent
2f75614cfe
commit
233061aaa2
|
@ -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; }
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue