mirror of
https://github.com/OpenTTD/OpenTTD
synced 2025-12-10 06:52:05 +01:00
Add: Automatically load fonts for missing glyphs. (#14856)
This commit is contained in:
@@ -2326,7 +2326,7 @@ static bool ConContent(std::span<std::string_view> argv)
|
||||
*/
|
||||
static std::string_view FontLoadReasonToName(FontLoadReason load_reason)
|
||||
{
|
||||
static const std::string_view LOAD_REASON_TO_NAME[] = { "default", "configured", "language" };
|
||||
static const std::string_view LOAD_REASON_TO_NAME[] = { "default", "configured", "language", "missing" };
|
||||
static_assert(std::size(LOAD_REASON_TO_NAME) == to_underlying(FontLoadReason::End));
|
||||
return LOAD_REASON_TO_NAME[to_underlying(load_reason)];
|
||||
}
|
||||
|
||||
@@ -75,6 +75,7 @@ int FontCache::GetDefaultFontHeight(FontSize fs)
|
||||
|
||||
for (const auto &fc : FontCache::caches) {
|
||||
if (fc == nullptr || fc->fs != fs) continue;
|
||||
if (fc->load_reason == FontLoadReason::MissingFallback) continue; // Avoid dynamically loaded fonts affecting widget sizes.
|
||||
ascender = std::max(ascender, fc->ascender);
|
||||
descender = std::min(descender, fc->descender);
|
||||
}
|
||||
@@ -269,10 +270,11 @@ std::string GetFontCacheFontName(FontSize fs)
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ void FontCache::LoadFallbackFonts(FontSize fs)
|
||||
/* static */ void FontCache::LoadFallbackFonts(FontSize fs, FontLoadReason load_reason)
|
||||
{
|
||||
const FontCacheSubSetting *setting = GetFontCacheSubSetting(fs);
|
||||
for (auto it = setting->fallback_fonts.rbegin(); it != setting->fallback_fonts.rend(); ++it) {
|
||||
if (it->load_reason != load_reason) continue;
|
||||
FontCache::Register(FontProviderManager::LoadFont(fs, FontType::TrueType, false, it->name, it->os_handle), it->load_reason);
|
||||
}
|
||||
}
|
||||
@@ -318,12 +320,15 @@ std::string GetFontCacheFontName(FontSize fs)
|
||||
if (std::ranges::find(fontnames, extra_font) == std::end(fontnames)) fontnames.push_back(extra_font);
|
||||
}
|
||||
|
||||
/* First load fonts for missing glyphs discovered during string formatting. */
|
||||
FontCache::LoadFallbackFonts(fs, FontLoadReason::MissingFallback);
|
||||
|
||||
/* Load configured fonts in reverse order so that the first entry has priority. */
|
||||
for (auto it = fontnames.rbegin(); it != fontnames.rend(); ++it) {
|
||||
if (*it == DEFAULT_FONT) {
|
||||
FontCache::LoadDefaultFonts(fs);
|
||||
} else if (*it == FALLBACK_FONT) {
|
||||
FontCache::LoadFallbackFonts(fs);
|
||||
FontCache::LoadFallbackFonts(fs, FontLoadReason::LanguageFallback);
|
||||
} else {
|
||||
FontCache::Register(FontProviderManager::LoadFont(fs, FontType::TrueType, true, std::string{*it}, {}), FontLoadReason::Configured);
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ enum class FontLoadReason : uint8_t {
|
||||
Default,
|
||||
Configured,
|
||||
LanguageFallback,
|
||||
MissingFallback,
|
||||
End,
|
||||
};
|
||||
|
||||
@@ -51,7 +52,7 @@ protected:
|
||||
FontCache(FontSize fs) : fs(fs) {}
|
||||
static void Register(std::unique_ptr<FontCache> &&fc, FontLoadReason load_reason);
|
||||
static void LoadDefaultFonts(FontSize fs);
|
||||
static void LoadFallbackFonts(FontSize fs);
|
||||
static void LoadFallbackFonts(FontSize fs, FontLoadReason load_reason);
|
||||
|
||||
public:
|
||||
virtual ~FontCache() = default;
|
||||
|
||||
@@ -10,10 +10,15 @@
|
||||
#include "stdafx.h"
|
||||
#include "core/math_func.hpp"
|
||||
#include "gfx_layout.h"
|
||||
#include "gfx_func.h"
|
||||
#include "string_func.h"
|
||||
#include "strings_func.h"
|
||||
#include "core/utf8.hpp"
|
||||
#include "debug.h"
|
||||
#include "timer/timer.h"
|
||||
#include "timer/timer_window.h"
|
||||
#include "viewport_func.h"
|
||||
#include "window_func.h"
|
||||
|
||||
#include "table/control_codes.h"
|
||||
|
||||
@@ -37,6 +42,50 @@
|
||||
/** Cache of ParagraphLayout lines. */
|
||||
std::unique_ptr<Layouter::LineCache> Layouter::linecache;
|
||||
|
||||
class RuntimeMissingGlyphSearcher : public MissingGlyphSearcher {
|
||||
std::array<std::set<char32_t>, FS_END> glyphs{};
|
||||
public:
|
||||
RuntimeMissingGlyphSearcher() : MissingGlyphSearcher(FONTSIZES_ALL) {}
|
||||
|
||||
FontLoadReason GetLoadReason() override { return FontLoadReason::MissingFallback; }
|
||||
|
||||
inline void Insert(FontSize fs, char32_t c)
|
||||
{
|
||||
this->glyphs[fs].insert(c);
|
||||
this->search_timeout.Reset();
|
||||
}
|
||||
|
||||
std::set<char32_t> GetRequiredGlyphs(FontSizes fontsizes) override
|
||||
{
|
||||
std::set<char32_t> r;
|
||||
for (FontSize fs : fontsizes) {
|
||||
r.merge(this->glyphs[fs]);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
TimeoutTimer<TimerWindow> search_timeout{std::chrono::milliseconds(250), [this]()
|
||||
{
|
||||
FontSizes changed_fontsizes{};
|
||||
for (FontSize fs = FS_BEGIN; fs != FS_END; ++fs) {
|
||||
auto &missing = this->glyphs[fs];
|
||||
if (missing.empty()) continue;
|
||||
|
||||
if (FontProviderManager::FindFallbackFont({}, fs, this)) changed_fontsizes.Set(fs);
|
||||
missing.clear();
|
||||
}
|
||||
|
||||
if (!changed_fontsizes.Any()) return;
|
||||
|
||||
FontCache::LoadFontCaches(changed_fontsizes);
|
||||
LoadStringWidthTable(changed_fontsizes);
|
||||
UpdateAllVirtCoords();
|
||||
ReInitAllWindows(true);
|
||||
}};
|
||||
};
|
||||
|
||||
static RuntimeMissingGlyphSearcher _missing_glyphs;
|
||||
|
||||
/**
|
||||
* Helper for getting a ParagraphLayouter of the given type.
|
||||
*
|
||||
@@ -98,6 +147,7 @@ static inline void GetLayouter(Layouter::LineCacheItem &line, std::string_view s
|
||||
FontIndex font_index = FontCache::GetFontIndexForCharacter(state.fontsize, c);
|
||||
|
||||
if (font_index == INVALID_FONT_INDEX) {
|
||||
_missing_glyphs.Insert(state.fontsize, c);
|
||||
font_index = FontCache::GetDefaultFontIndex(state.fontsize);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user