overlays: Check if a font actually contains the character

This commit is contained in:
Megamouse 2025-11-16 12:17:12 +01:00
parent a6371ef5d3
commit 10f8a49e36
2 changed files with 55 additions and 20 deletions

View file

@ -159,25 +159,57 @@ namespace rsx
return result; return result;
} }
codepage* font::initialize_codepage(char32_t codepage_id) codepage* font::initialize_codepage(char32_t c)
{ {
// Init glyph // Init glyph
const auto codepage_id = get_page_id(c);
const auto class_ = classify(codepage_id); const auto class_ = classify(codepage_id);
const auto fs_settings = get_glyph_files(class_); const auto fs_settings = get_glyph_files(class_);
// Attemt to load requested font // Attemt to load requested font
std::vector<u8> bytes; std::vector<u8> bytes;
std::string file_path; std::vector<u8> fallback_bytes;
std::string fallback_file;
bool font_found = false; bool font_found = false;
const auto get_font = [&](const std::string& file_path) -> bool
{
// Read font
fs::file f(file_path);
f.read(bytes, f.size());
// Check if the character exists in the font
stbtt_fontinfo info;
stbtt_InitFont(&info, bytes.data(), stbtt_GetFontOffsetForIndex(bytes.data(), 0));
font_found = stbtt_FindGlyphIndex(&info, c) != 0;
if (!font_found)
{
if (fallback_bytes.empty())
{
// Save this font as a fallback so we don't get a segfault or exception
fallback_bytes = std::move(bytes);
fallback_file = file_path;
}
bytes.clear();
}
return font_found;
};
for (const auto& font_file : fs_settings.font_names) for (const auto& font_file : fs_settings.font_names)
{ {
if (fs::is_file(font_file)) if (fs::is_file(font_file))
{ {
// Check for absolute paths or fonts 'installed' to executable folder // Check for absolute paths or fonts 'installed' to executable folder
file_path = font_file; if (get_font(font_file))
font_found = true; {
break; break;
}
continue;
} }
std::string extension; std::string extension;
@ -196,11 +228,13 @@ namespace rsx
for (const auto& font_dir : fs_settings.lookup_font_dirs) for (const auto& font_dir : fs_settings.lookup_font_dirs)
{ {
file_path = font_dir + file_name; const std::string file_path = font_dir + file_name;
if (fs::is_file(file_path)) if (fs::is_file(file_path))
{ {
font_found = true; if (get_font(file_path))
break; {
break;
}
} }
} }
@ -210,16 +244,15 @@ namespace rsx
} }
} }
// Read font if (!font_found)
if (font_found)
{ {
fs::file f(file_path); if (fallback_bytes.empty())
f.read(bytes, f.size()); {
} fmt::throw_exception("Failed to initialize font for character 0x%x on codepage %d.", static_cast<u32>(c), static_cast<u32>(codepage_id));
else }
{
rsx_log.error("Failed to initialize font '%s.ttf' on codepage %d", font_name, static_cast<u32>(codepage_id)); rsx_log.error("Failed to initialize font for character 0x%x on codepage %d. Falling back to font '%s'", static_cast<u32>(c), static_cast<u32>(codepage_id), fallback_file);
return nullptr; bytes = std::move(fallback_bytes);
} }
codepage_cache.page = nullptr; codepage_cache.page = nullptr;
@ -245,7 +278,8 @@ namespace rsx
if (!initialized) if (!initialized)
return {}; return {};
const auto page_id = (c >> 8); const auto page_id = get_page_id(c);
if (codepage_cache.codepage_id == page_id && codepage_cache.page) [[likely]] if (codepage_cache.codepage_id == page_id && codepage_cache.page) [[likely]]
{ {
return codepage_cache.page->get_char(c, x_advance, y_advance); return codepage_cache.page->get_char(c, x_advance, y_advance);
@ -266,7 +300,7 @@ namespace rsx
if (!codepage_cache.page) [[unlikely]] if (!codepage_cache.page) [[unlikely]]
{ {
codepage_cache.page = initialize_codepage(page_id); codepage_cache.page = initialize_codepage(c);
} }
return codepage_cache.page->get_char(c, x_advance, y_advance); return codepage_cache.page->get_char(c, x_advance, y_advance);

View file

@ -64,9 +64,10 @@ namespace rsx
} }
codepage_cache; codepage_cache;
static char32_t get_page_id(char32_t c) { return c >> 8; }
static language_class classify(char32_t codepage_id); static language_class classify(char32_t codepage_id);
glyph_load_setup get_glyph_files(language_class class_) const; glyph_load_setup get_glyph_files(language_class class_) const;
codepage* initialize_codepage(char32_t codepage_id); codepage* initialize_codepage(char32_t c);
public: public:
font(std::string_view ttf_name, f32 size); font(std::string_view ttf_name, f32 size);