mirror of https://github.com/OpenTTD/OpenTTD
Merge f8bd97a848
into 3a05978cc4
commit
5ea5bc6727
|
@ -24,6 +24,8 @@
|
|||
#include "fios.h"
|
||||
#include "fileio_func.h"
|
||||
#include "fontcache.h"
|
||||
#include "fontdetection.h"
|
||||
#include "language.h"
|
||||
#include "screenshot.h"
|
||||
#include "genworld.h"
|
||||
#include "strings_func.h"
|
||||
|
@ -46,6 +48,7 @@
|
|||
#include "company_cmd.h"
|
||||
#include "misc_cmd.h"
|
||||
|
||||
#include <charconv>
|
||||
#include <sstream>
|
||||
|
||||
#include "safeguards.h"
|
||||
|
@ -2225,6 +2228,52 @@ DEF_CONSOLE_CMD(ConContent)
|
|||
}
|
||||
#endif /* defined(WITH_ZLIB) */
|
||||
|
||||
/* List all the fonts available via console */
|
||||
DEF_CONSOLE_CMD(ConListFonts)
|
||||
{
|
||||
if (argc == 0) {
|
||||
IConsolePrint(CC_HELP, "List all fonts.");
|
||||
return true;
|
||||
}
|
||||
|
||||
FontSearcher *fs = FontSearcher::GetFontSearcher();
|
||||
if (fs == nullptr) {
|
||||
IConsolePrint(CC_ERROR, "No font searcher exists.");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (argc == 1) {
|
||||
auto families = fs->ListFamilies(_current_language->isocode, _current_language->winlangid);
|
||||
|
||||
int i = 0;
|
||||
for (const std::string_view &family : families) {
|
||||
IConsolePrint(CC_DEFAULT, "{}) {}", i, family);
|
||||
++i;
|
||||
}
|
||||
} else if (argc == 2) {
|
||||
std::string family = argv[1];
|
||||
|
||||
/* If argv is a number treat it as an index into the list of fonts, which we need to get again... */
|
||||
int index;
|
||||
auto [_, err] = std::from_chars(family.data(), family.data() + family.size(), index, 10);
|
||||
if (err == std::errc()) {
|
||||
auto families = fs->ListFamilies(_current_language->isocode, _current_language->winlangid);
|
||||
std::sort(std::begin(families), std::end(families));
|
||||
if (IsInsideMM(index, 0, families.size())) family = families[index];
|
||||
}
|
||||
|
||||
auto styles = fs->ListStyles(_current_language->isocode, _current_language->winlangid, family);
|
||||
|
||||
int i = 0;
|
||||
for (const FontFamily &font : styles) {
|
||||
IConsolePrint(CC_DEFAULT, "{}) {}, {}", i, font.family, font.style);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
DEF_CONSOLE_CMD(ConFont)
|
||||
{
|
||||
if (argc == 0) {
|
||||
|
@ -2807,6 +2856,7 @@ void IConsoleStdLibRegister()
|
|||
IConsole::CmdRegister("saveconfig", ConSaveConfig);
|
||||
IConsole::CmdRegister("ls", ConListFiles);
|
||||
IConsole::CmdRegister("list_saves", ConListFiles);
|
||||
IConsole::CmdRegister("list_fonts", ConListFonts);
|
||||
IConsole::CmdRegister("list_scenarios", ConListScenarios);
|
||||
IConsole::CmdRegister("list_heightmaps", ConListHeightmaps);
|
||||
IConsole::CmdRegister("cd", ConChangeDirectory);
|
||||
|
|
|
@ -250,6 +250,67 @@ void UninitFontCache()
|
|||
#endif /* WITH_FREETYPE */
|
||||
}
|
||||
|
||||
bool FontFamilySorter(const FontFamily &a, const FontFamily &b)
|
||||
{
|
||||
int r = StrNaturalCompare(a.family, b.family);
|
||||
if (r == 0) r = (a.weight - b.weight);
|
||||
if (r == 0) r = (a.slant - b.slant);
|
||||
if (r == 0) r = StrNaturalCompare(a.style, b.style);
|
||||
return r < 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the FontSearcher instance. There can be only one font searcher, which depends on platform.
|
||||
*/
|
||||
FontSearcher::FontSearcher()
|
||||
{
|
||||
FontSearcher::instance = this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deregister this FontSearcher.
|
||||
*/
|
||||
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; }
|
||||
|
|
|
@ -39,4 +39,59 @@ FT_Error GetFontByFaceName(const char *font_name, FT_Face *face);
|
|||
*/
|
||||
bool SetFallbackFont(struct FontCacheSettings *settings, const std::string &language_isocode, int winlangid, class MissingGlyphSearcher *callback);
|
||||
|
||||
struct FontFamily {
|
||||
std::string family;
|
||||
std::string style;
|
||||
int32_t slant;
|
||||
int32_t weight;
|
||||
|
||||
FontFamily(std::string_view family, std::string_view style, int32_t slant, int32_t weight) : family(family), style(style), slant(slant), weight(weight) {}
|
||||
};
|
||||
|
||||
bool FontFamilySorter(const FontFamily &a, const FontFamily &b);
|
||||
|
||||
class FontSearcher {
|
||||
public:
|
||||
FontSearcher();
|
||||
virtual ~FontSearcher();
|
||||
|
||||
/**
|
||||
* Get the active FontSearcher instance.
|
||||
* @return FontSearcher instance, or nullptr if not present.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
std::vector<std::string_view> ListFamilies(const std::string &language_isocode, int winlangid);
|
||||
|
||||
/**
|
||||
* List available styles for a font family.
|
||||
* @param language_isocode the language, e.g. en_GB.
|
||||
* @param winlangid the language ID windows style.
|
||||
* @param font_family The font family to list.
|
||||
* @return vector containing style information for the family.
|
||||
*/
|
||||
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;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
#include "safeguards.h"
|
||||
|
||||
bool SetFallbackFont(FontCacheSettings *settings, const std::string &language_isocode, int, MissingGlyphSearcher *callback)
|
||||
static void EnumerateCoreFextFonts(const std::string &language_isocode, int ntries, std::function<bool(int, CTFontDescriptorRef, CTFontSymbolicTraits)> enum_func)
|
||||
{
|
||||
/* Determine fallback font using CoreText. This uses the language isocode
|
||||
* to find a suitable font. CoreText is available from 10.5 onwards. */
|
||||
|
@ -55,9 +55,12 @@ bool SetFallbackFont(FontCacheSettings *settings, const std::string &language_is
|
|||
CFAutoRelease<CFSetRef> mandatory_attribs(CFSetCreate(kCFAllocatorDefault, const_cast<const void **>(reinterpret_cast<const void *const *>(&kCTFontLanguagesAttribute)), 1, &kCFTypeSetCallBacks));
|
||||
CFAutoRelease<CFArrayRef> descs(CTFontDescriptorCreateMatchingFontDescriptors(lang_desc.get(), mandatory_attribs.get()));
|
||||
|
||||
bool result = false;
|
||||
for (int tries = 0; tries < 2; tries++) {
|
||||
for (CFIndex i = 0; descs.get() != nullptr && i < CFArrayGetCount(descs.get()); i++) {
|
||||
/* Nothing to see here. */
|
||||
if (descs == nullptr) return;
|
||||
|
||||
CFIndex count = CFArrayGetCount(descs.get());
|
||||
for (int tries = 0; tries < ntries; tries++) {
|
||||
for (CFIndex i = 0; i < count; i++) {
|
||||
CTFontDescriptorRef font = (CTFontDescriptorRef)CFArrayGetValueAtIndex(descs.get(), i);
|
||||
|
||||
/* Get font traits. */
|
||||
|
@ -67,34 +70,46 @@ bool SetFallbackFont(FontCacheSettings *settings, const std::string &language_is
|
|||
|
||||
/* Skip symbol fonts and vertical fonts. */
|
||||
if ((symbolic_traits & kCTFontClassMaskTrait) == (CTFontStylisticClass)kCTFontSymbolicClass || (symbolic_traits & kCTFontVerticalTrait)) continue;
|
||||
/* Skip bold fonts (especially Arial Bold, which looks worse than regular Arial). */
|
||||
if (symbolic_traits & kCTFontBoldTrait) continue;
|
||||
/* Select monospaced fonts if asked for. */
|
||||
if (((symbolic_traits & kCTFontMonoSpaceTrait) == kCTFontMonoSpaceTrait) != callback->Monospace()) continue;
|
||||
|
||||
/* Get font name. */
|
||||
char name[128];
|
||||
CFAutoRelease<CFStringRef> font_name((CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontDisplayNameAttribute));
|
||||
CFStringGetCString(font_name.get(), name, lengthof(name), kCFStringEncodingUTF8);
|
||||
|
||||
/* Serif fonts usually look worse on-screen with only small
|
||||
* font sizes. As such, we try for a sans-serif font first.
|
||||
* If we can't find one in the first try, try all fonts. */
|
||||
if (tries == 0 && (symbolic_traits & kCTFontClassMaskTrait) != (CTFontStylisticClass)kCTFontSansSerifClass) continue;
|
||||
|
||||
/* There are some special fonts starting with an '.' and the last
|
||||
* resort font that aren't usable. Skip them. */
|
||||
if (name[0] == '.' || strncmp(name, "LastResort", 10) == 0) continue;
|
||||
|
||||
/* Save result. */
|
||||
callback->SetFontNames(settings, name);
|
||||
if (!callback->FindMissingGlyphs()) {
|
||||
Debug(fontcache, 2, "CT-Font for {}: {}", language_isocode, name);
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
bool continue_enumerating = enum_func(tries, font, symbolic_traits);
|
||||
if (!continue_enumerating) return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SetFallbackFont(FontCacheSettings *settings, const std::string &language_isocode, int, MissingGlyphSearcher *callback)
|
||||
{
|
||||
bool result = false;
|
||||
EnumerateCoreFextFonts(language_isocode, 2, [&settings, &language_isocode, &callback, &result](int tries, CTFontDescriptorRef font, CTFontSymbolicTraits symbolic_traits) {
|
||||
/* Skip bold fonts (especially Arial Bold, which looks worse than regular Arial). */
|
||||
if (symbolic_traits & kCTFontBoldTrait) return true;
|
||||
/* Select monospaced fonts if asked for. */
|
||||
if (((symbolic_traits & kCTFontMonoSpaceTrait) == kCTFontMonoSpaceTrait) != callback->Monospace()) return true;
|
||||
|
||||
/* Get font name. */
|
||||
char name[128];
|
||||
CFAutoRelease<CFStringRef> font_name((CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontDisplayNameAttribute));
|
||||
CFStringGetCString(font_name.get(), name, lengthof(name), kCFStringEncodingUTF8);
|
||||
|
||||
/* Serif fonts usually look worse on-screen with only small
|
||||
* font sizes. As such, we try for a sans-serif font first.
|
||||
* If we can't find one in the first try, try all fonts. */
|
||||
if (tries == 0 && (symbolic_traits & kCTFontClassMaskTrait) != (CTFontStylisticClass)kCTFontSansSerifClass) return true;
|
||||
|
||||
/* There are some special fonts starting with an '.' and the last
|
||||
* resort font that aren't usable. Skip them. */
|
||||
if (name[0] == '.' || strncmp(name, "LastResort", 10) == 0) return true;
|
||||
|
||||
/* Save result. */
|
||||
callback->SetFontNames(settings, name);
|
||||
if (!callback->FindMissingGlyphs()) {
|
||||
Debug(fontcache, 2, "CT-Font for {}: {}", language_isocode, name);
|
||||
result = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
if (!result) {
|
||||
/* For some OS versions, the font 'Arial Unicode MS' does not report all languages it
|
||||
|
@ -371,3 +386,43 @@ void LoadCoreTextFont(FontSize fs)
|
|||
|
||||
new CoreTextFontCache(fs, std::move(font_ref), GetFontCacheFontSize(fs));
|
||||
}
|
||||
|
||||
class CoreTextFontSearcher : public FontSearcher {
|
||||
public:
|
||||
void UpdateCachedFonts(const std::string &language_isocode, int winlangid) override;
|
||||
};
|
||||
|
||||
void CoreTextFontSearcher::UpdateCachedFonts(const std::string &language_isocode, int)
|
||||
{
|
||||
this->cached_fonts.clear();
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
this->cached_fonts.emplace_back(sv_family, sv_style, static_cast<int>(slant * 100), static_cast<int>(weight * 100));
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
std::sort(std::begin(this->cached_fonts), std::end(this->cached_fonts), FontFamilySorter);
|
||||
}
|
||||
|
||||
CoreTextFontSearcher _coretextfs_instance;
|
||||
|
|
|
@ -39,6 +39,19 @@ static std::tuple<std::string, std::string> SplitFontFamilyAndStyle(std::string_
|
|||
return { std::string(font_name.substr(0, separator)), std::string(font_name.substr(begin)) };
|
||||
}
|
||||
|
||||
/**
|
||||
* Get language string for FontConfig pattern matching.
|
||||
* @param language_isocode Language's ISO code.
|
||||
* @return Language code for FontConfig.
|
||||
*/
|
||||
static std::string GetFontConfigLanguage(const std::string &language_isocode)
|
||||
{
|
||||
/* Fontconfig doesn't handle full language isocodes, only the part
|
||||
* before the _ of e.g. en_GB is used, so "remove" everything after
|
||||
* the _. */
|
||||
return fmt::format(":lang={}", language_isocode.substr(0, language_isocode.find('_')));
|
||||
}
|
||||
|
||||
FT_Error GetFontByFaceName(const char *font_name, FT_Face *face)
|
||||
{
|
||||
FT_Error err = FT_Err_Cannot_Open_Resource;
|
||||
|
@ -107,10 +120,7 @@ bool SetFallbackFont(FontCacheSettings *settings, const std::string &language_is
|
|||
auto fc_instance = FcConfigReference(nullptr);
|
||||
assert(fc_instance != nullptr);
|
||||
|
||||
/* Fontconfig doesn't handle full language isocodes, only the part
|
||||
* before the _ of e.g. en_GB is used, so "remove" everything after
|
||||
* the _. */
|
||||
std::string lang = fmt::format(":lang={}", language_isocode.substr(0, language_isocode.find('_')));
|
||||
std::string lang = GetFontConfigLanguage(language_isocode);
|
||||
|
||||
/* First create a pattern to match the wanted language. */
|
||||
FcPattern *pat = FcNameParse((const FcChar8 *)lang.c_str());
|
||||
|
@ -180,3 +190,69 @@ bool SetFallbackFont(FontCacheSettings *settings, const std::string &language_is
|
|||
FcConfigDestroy(fc_instance);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* FontConfig implementation of FontSearcher.
|
||||
*/
|
||||
class FontConfigFontSearcher : public FontSearcher {
|
||||
public:
|
||||
void UpdateCachedFonts(const std::string &language_isocode, int winlangid) override;
|
||||
};
|
||||
|
||||
void FontConfigFontSearcher::UpdateCachedFonts(const std::string &language_isocode, int)
|
||||
{
|
||||
this->cached_fonts.clear();
|
||||
|
||||
if (!FcInit()) return;
|
||||
|
||||
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()));
|
||||
/* We want to know this attributes. */
|
||||
FcObjectSet *os = FcObjectSetCreate();
|
||||
FcObjectSetAdd(os, FC_FAMILY);
|
||||
FcObjectSetAdd(os, FC_STYLE);
|
||||
FcObjectSetAdd(os, FC_SLANT);
|
||||
FcObjectSetAdd(os, FC_WEIGHT);
|
||||
/* 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) {
|
||||
this->cached_fonts.reserve(fs->nfont);
|
||||
for (const FcPattern *font : std::span(fs->fonts, fs->nfont)) {
|
||||
FcChar8 *family;
|
||||
FcChar8 *style;
|
||||
int32_t slant;
|
||||
int32_t weight;
|
||||
|
||||
if (FcPatternGetString(font, FC_FAMILY, 0, &family) != FcResultMatch) continue;
|
||||
if (FcPatternGetString(font, FC_STYLE, 0, &style) != FcResultMatch) continue;
|
||||
if (FcPatternGetInteger(font, FC_SLANT, 0, &slant) != FcResultMatch) continue;
|
||||
if (FcPatternGetInteger(font, FC_WEIGHT, 0, &weight) != FcResultMatch) continue;
|
||||
|
||||
/* 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. */
|
||||
FcFontSetDestroy(fs);
|
||||
}
|
||||
|
||||
FcConfigDestroy(fc_instance);
|
||||
|
||||
std::sort(std::begin(this->cached_fonts), std::end(this->cached_fonts), FontFamilySorter);
|
||||
}
|
||||
|
||||
static FontConfigFontSearcher _fcfs_instance;
|
||||
|
|
|
@ -34,15 +34,14 @@
|
|||
|
||||
struct EFCParam {
|
||||
FontCacheSettings *settings;
|
||||
LOCALESIGNATURE locale;
|
||||
LOCALESIGNATURE locale;
|
||||
MissingGlyphSearcher *callback;
|
||||
std::vector<std::wstring> fonts;
|
||||
|
||||
bool Add(const std::wstring_view &font)
|
||||
{
|
||||
for (const auto &entry : this->fonts) {
|
||||
if (font.compare(entry) == 0) return false;
|
||||
}
|
||||
if (font.starts_with('@')) return false;
|
||||
if (std::find(std::begin(this->fonts), std::end(this->fonts), font) != std::end(this->fonts)) return false;
|
||||
|
||||
this->fonts.emplace_back(font);
|
||||
|
||||
|
@ -99,7 +98,6 @@ bool SetFallbackFont(FontCacheSettings *settings, const std::string &, int winla
|
|||
return ret == 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a new Win32FontCache.
|
||||
* @param fs The font size that is going to be cached.
|
||||
|
@ -380,3 +378,73 @@ void LoadWin32Font(FontSize fs)
|
|||
|
||||
LoadWin32Font(fs, logfont, GetFontCacheFontSize(fs), font_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Win32 implementation of FontSearcher.
|
||||
*/
|
||||
class Win32FontSearcher : public FontSearcher {
|
||||
public:
|
||||
void UpdateCachedFonts(const std::string &language_isocode, int winlangid) override;
|
||||
};
|
||||
|
||||
/**
|
||||
* State passed between EnumFontFamiliesEx and our list fonts callbacks.
|
||||
*/
|
||||
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)
|
||||
{
|
||||
EFCListFontsParam &info = *reinterpret_cast<EFCListFontsParam *>(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;
|
||||
|
||||
HDC dc = GetDC(nullptr);
|
||||
EnumFontFamiliesEx(dc, &lf, (FONTENUMPROC)&ListStylesFontCallback, reinterpret_cast<LPARAM>(&info), 0);
|
||||
ReleaseDC(nullptr, dc);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Win32FontSearcher::UpdateCachedFonts(const std::string &, int winlangid)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
LOGFONT lf{};
|
||||
lf.lfCharSet = DEFAULT_CHARSET;
|
||||
|
||||
HDC dc = GetDC(nullptr);
|
||||
EnumFontFamiliesEx(dc, &lf, (FONTENUMPROC)&ListFamiliesFontCallback, reinterpret_cast<LPARAM>(&info), 0);
|
||||
ReleaseDC(nullptr, dc);
|
||||
}
|
||||
|
||||
static Win32FontSearcher _win32fs_instance;
|
||||
|
|
Loading…
Reference in New Issue