From d845b9503df225d8ec3a1ca40b20651f62e915c5 Mon Sep 17 00:00:00 2001 From: w1naenator Date: Fri, 9 Jan 2026 13:00:17 +0200 Subject: [PATCH] Refactor font rendering and path resolution logic to fix Metaphor: ReFantazio glyphs cropping and anywhereVR "thin" glyphs. - Updated RenderCodepointToSurface and RenderCodepointToSurfaceWithScale functions to set result->transImage to nullptr instead of result->stage. - Modified font definitions to use updated font file names for various language sets. - Introduced ResolveSystemFontPathCandidate function to streamline font path resolution, allowing for better handling of font directories. - Enhanced LoadFontFile function to check for font files in "font" and "font2" directories based on the parent directory name. - Improved error logging for font path overrides in ResolveSystemFontPath function. --- src/core/libraries/font/font.cpp | 389 +++++++++++++++++++- src/core/libraries/font/font_internal.cpp | 198 ++++++---- src/core/libraries/font/fontft_internal.cpp | 276 +++++++------- 3 files changed, 637 insertions(+), 226 deletions(-) diff --git a/src/core/libraries/font/font.cpp b/src/core/libraries/font/font.cpp index 6083a5187..85636e973 100644 --- a/src/core/libraries/font/font.cpp +++ b/src/core/libraries/font/font.cpp @@ -566,6 +566,44 @@ static std::filesystem::path GetSysFontBaseDir() { return {}; } +static std::filesystem::path ResolveSystemFontPathCandidate(const std::filesystem::path& base_dir, + const std::filesystem::path& filename) { + if (base_dir.empty() || filename.empty()) { + return {}; + } + std::error_code ec; + const auto is_file = [&](const std::filesystem::path& p) -> bool { + return std::filesystem::is_regular_file(p, ec) && !ec; + }; + + const auto direct = base_dir / filename; + if (is_file(direct)) { + return direct; + } + + const auto base_name = base_dir.filename().string(); + if (base_name != "font" && base_name != "font2") { + const auto in_font = base_dir / "font" / filename; + if (is_file(in_font)) { + return in_font; + } + const auto in_font2 = base_dir / "font2" / filename; + if (is_file(in_font2)) { + return in_font2; + } + } + + if (base_name == "font" || base_name == "font2") { + const auto container = base_dir.parent_path(); + const auto sibling = container / ((base_name == "font") ? "font2" : "font") / filename; + if (is_file(sibling)) { + return sibling; + } + } + + return direct; +} + static std::string MacroToCamel(const char* macro_key) { if (!macro_key) { return {}; @@ -605,7 +643,7 @@ static std::filesystem::path ResolveSystemFontPath(u32 font_set_type) { if (auto override_path = Config::getSystemFontOverride(def->config_key)) { if (!override_path->empty() && !override_path->is_absolute() && !override_path->has_parent_path()) { - return base_dir / *override_path; + return ResolveSystemFontPathCandidate(base_dir, *override_path); } LOG_ERROR(Lib_Font, "SystemFonts: override for '{}' must be a filename only (no path): '{}'", @@ -616,7 +654,7 @@ static std::filesystem::path ResolveSystemFontPath(u32 font_set_type) { if (auto override_path2 = Config::getSystemFontOverride(camel_key)) { if (!override_path2->empty() && !override_path2->is_absolute() && !override_path2->has_parent_path()) { - return base_dir / *override_path2; + return ResolveSystemFontPathCandidate(base_dir, *override_path2); } LOG_ERROR(Lib_Font, "SystemFonts: override for '{}' must be a filename only (no path): '{}'", @@ -628,7 +666,7 @@ static std::filesystem::path ResolveSystemFontPath(u32 font_set_type) { if (auto override_path3 = Config::getSystemFontOverride(lower_camel)) { if (!override_path3->empty() && !override_path3->is_absolute() && !override_path3->has_parent_path()) { - return base_dir / *override_path3; + return ResolveSystemFontPathCandidate(base_dir, *override_path3); } LOG_ERROR(Lib_Font, "SystemFonts: override for '{}' must be a filename only (no path): '{}'", @@ -636,7 +674,7 @@ static std::filesystem::path ResolveSystemFontPath(u32 font_set_type) { } } if (def->default_file && *def->default_file) { - return base_dir / def->default_file; + return ResolveSystemFontPathCandidate(base_dir, def->default_file); } } LOG_ERROR(Lib_Font, "SystemFonts: unknown font set type=0x{:08X}", font_set_type); @@ -668,10 +706,47 @@ static bool LoadFontFile(const std::filesystem::path& path, std::vector bool { + out_bytes.clear(); + if (!LoadGuestFileBytes(p, out_bytes) || out_bytes.empty()) { + out_bytes.clear(); + return false; + } + return true; + }; + + if (try_load(path)) { + return true; } - return true; + + std::error_code ec; + const auto parent = path.parent_path(); + const auto parent_name = parent.filename().string(); + const auto file_name = path.filename(); + if (!file_name.empty() && parent_name != "font" && parent_name != "font2") { + const auto cand_font = parent / "font" / file_name; + if (std::filesystem::is_regular_file(cand_font, ec) && !ec) { + if (try_load(cand_font)) { + return true; + } + } + const auto cand_font2 = parent / "font2" / file_name; + if (std::filesystem::is_regular_file(cand_font2, ec) && !ec) { + if (try_load(cand_font2)) { + return true; + } + } + } + + if (!file_name.empty() && (parent_name == "font" || parent_name == "font2")) { + const auto container = parent.parent_path(); + const auto sibling = container / ((parent_name == "font") ? "font2" : "font") / file_name; + if (std::filesystem::is_regular_file(sibling, ec) && !ec) { + return try_load(sibling); + } + } + + return false; } } // namespace @@ -4366,6 +4441,53 @@ s32 PS4_SYSV_ABI sceFontOpenFontSet(OrbisFontLib library, u32 fontSetType, u32 o Internal::PopulateStateMetrics(st, m); st.ext_face_ready = true; + auto compute_sysfont_scale_factor = [](FT_Face face, int units_per_em) -> float { + (void)units_per_em; + if (!face) { + return 1.0f; + } + const TT_OS2* os2 = + static_cast(FT_Get_Sfnt_Table(face, ft_sfnt_os2)); + if (os2) { + if (os2->sTypoAscender == 770 && os2->sTypoDescender == -230) { + return 1024.0f / 952.0f; + } + } + return 1.0f; + }; + auto compute_sysfont_shift_value = [](FT_Face face) -> s32 { + if (!face) { + return 0; + } + const TT_OS2* os2 = + static_cast(FT_Get_Sfnt_Table(face, ft_sfnt_os2)); + if (!os2) { + return 0; + } + const bool is_jp_pro_metrics = (os2->sTypoAscender == 880) && + (os2->sTypoDescender == -120) && + (os2->sTypoLineGap == 1); + if (is_jp_pro_metrics) { + const auto* vhea = + static_cast(FT_Get_Sfnt_Table(face, ft_sfnt_vhea)); + if (vhea) { + const int units = static_cast(face->units_per_EM); + const int gap = static_cast(os2->sTypoLineGap); + const int shift = 1024 - units - gap; + if (shift > 0 && shift < 128) { + return static_cast(shift); + } + } + } + return 0; + }; + st.system_font_scale_factor = compute_sysfont_scale_factor(st.ext_ft_face, st.ext_units_per_em); + st.system_font_shift_value = compute_sysfont_shift_value(st.ext_ft_face); + LOG_DEBUG(Lib_Font, "SystemFonts: primary='{}' unitsPerEm={} scaleFactor={} shiftValue={}", + primary_path.filename().string(), st.ext_units_per_em, st.system_font_scale_factor, + st.system_font_shift_value); + + std::string preferred_latin_name_lower; const auto base_dir = Internal::GetSysFontBaseDir(); if (!base_dir.empty()) { auto resolve_existing = @@ -4470,6 +4592,14 @@ s32 PS4_SYSV_ABI sceFontOpenFontSet(OrbisFontLib library, u32 fontSetType, u32 o fb.bytes->data(), fb.bytes->size(), sub_font_index); fb.ready = (fb.ft_face != nullptr); if (fb.ready) { + fb.scale_factor = compute_sysfont_scale_factor( + fb.ft_face, fb.ft_face ? static_cast(fb.ft_face->units_per_EM) : 0); + fb.shift_value = compute_sysfont_shift_value(fb.ft_face); + LOG_DEBUG(Lib_Font, + "SystemFonts: fallback='{}' unitsPerEm={} scaleFactor={} shiftValue={}", + fb.path.filename().string(), + fb.ft_face ? static_cast(fb.ft_face->units_per_EM) : 0, + fb.scale_factor, fb.shift_value); st.system_fallback_faces.push_back(std::move(fb)); } else { Internal::DestroyFreeTypeFace(fb.ft_face); @@ -4477,10 +4607,83 @@ s32 PS4_SYSV_ABI sceFontOpenFontSet(OrbisFontLib library, u32 fontSetType, u32 o }; { - if (auto roman_path = resolve_sysfont_path(base_dir / "SST-Roman.otf")) { - const std::string roman_lower = lower_ascii(roman_path->filename().string()); - if (!has_fallback_name_lower(roman_lower)) { - add_fallback_face(*roman_path); + const u32 tag = (fontSetType >> 8) & 0xFFu; + const u32 variant = (fontSetType >> 20) & 0x0Fu; + u32 style_suffix = fontSetType & 0xFFu; + + switch (style_suffix) { + case 0xC3: + style_suffix = 0x43; + break; + case 0xC4: + style_suffix = 0x44; + break; + case 0xC5: + style_suffix = 0x45; + break; + case 0xC7: + style_suffix = 0x47; + break; + default: + break; + } + + const char* latin_file = nullptr; + if (tag != 0x00u && tag != 0x10u) { + if (variant == 0x3u) { + switch (style_suffix) { + case 0x44: + latin_file = "SSTTypewriter-Roman.otf"; + break; + case 0x47: + latin_file = "SSTTypewriter-Bd.otf"; + break; + default: + break; + } + } else if (variant == 0x1u) { + switch (style_suffix) { + case 0x43: + latin_file = "SST-LightItalic.otf"; + break; + case 0x44: + latin_file = "SST-Italic.otf"; + break; + case 0x45: + latin_file = "SST-MediumItalic.otf"; + break; + case 0x47: + latin_file = "SST-BoldItalic.otf"; + break; + default: + break; + } + } else { + switch (style_suffix) { + case 0x43: + latin_file = "SST-Light.otf"; + break; + case 0x44: + latin_file = "SST-Roman.otf"; + break; + case 0x45: + latin_file = "SST-Medium.otf"; + break; + case 0x47: + latin_file = "SST-Bold.otf"; + break; + default: + break; + } + } + } + + if (latin_file) { + if (auto latin_path = resolve_sysfont_path(base_dir / latin_file)) { + preferred_latin_name_lower = lower_ascii(latin_path->filename().string()); + if (!has_fallback_name_lower(preferred_latin_name_lower)) { + add_fallback_face(*latin_path); + } } } } @@ -4501,6 +4704,18 @@ s32 PS4_SYSV_ABI sceFontOpenFontSet(OrbisFontLib library, u32 fontSetType, u32 o case 0xC7: arabic_file = "SSTArabic-Bold.otf"; break; + case 0xD3: + arabic_file = "SSTArabic-Light.otf"; + break; + case 0xD4: + arabic_file = "SSTArabic-Roman.otf"; + break; + case 0xD5: + arabic_file = "SSTArabic-Medium.otf"; + break; + case 0xD7: + arabic_file = "SSTArabic-Bold.otf"; + break; default: break; } @@ -4515,6 +4730,115 @@ s32 PS4_SYSV_ABI sceFontOpenFontSet(OrbisFontLib library, u32 fontSetType, u32 o } } + { + const u32 tag = (fontSetType >> 8) & 0xFFu; + const u32 style_suffix = fontSetType & 0xFFu; + + auto add_named_fallback = [&](std::string_view filename) { + if (filename.empty()) { + return; + } + if (auto p = resolve_sysfont_path(base_dir / std::filesystem::path{filename})) { + const std::string lower = lower_ascii(p->filename().string()); + if (!has_fallback_name_lower(lower)) { + add_fallback_face(*p); + } + } + }; + + const bool is_bold_like = (style_suffix == 0x47u) || (style_suffix == 0x57u) || + (style_suffix == 0xC7u) || (style_suffix == 0xD7u); + + const bool needs_jppro = (tag == 0x04u) || (tag == 0x24u) || (tag == 0x34u) || + (tag == 0x84u) || (tag == 0xA4u) || (tag == 0xACu) || + (tag == 0xB4u) || (tag == 0xBCu); + const bool needs_cngb = (tag == 0x80u) || (tag == 0x84u) || (tag == 0x90u) || + (tag == 0xA0u) || (tag == 0xA4u) || (tag == 0xACu) || + (tag == 0xB0u) || (tag == 0xB4u) || (tag == 0xBCu); + const bool needs_hangul = (tag == 0x24u) || (tag == 0x34u) || (tag == 0xA0u) || + (tag == 0xA4u) || (tag == 0xACu) || (tag == 0xB0u) || + (tag == 0xB4u) || (tag == 0xBCu); + + u32 sea_weight_code = style_suffix; + switch (sea_weight_code) { + case 0xD3u: + sea_weight_code = 0x53u; + break; + case 0xD4u: + sea_weight_code = 0x54u; + break; + case 0xD5u: + sea_weight_code = 0x55u; + break; + case 0xD7u: + sea_weight_code = 0x57u; + break; + default: + break; + } + const bool is_sea_weight = (sea_weight_code == 0x53u) || (sea_weight_code == 0x54u) || + (sea_weight_code == 0x55u) || (sea_weight_code == 0x57u); + + if (is_sea_weight && primary_name_lower.rfind("sstvietnamese-", 0) != 0) { + const char* vn_file = nullptr; + switch (sea_weight_code) { + case 0x53: + vn_file = "SSTVietnamese-Light.otf"; + break; + case 0x54: + vn_file = "SSTVietnamese-Roman.otf"; + break; + case 0x55: + vn_file = "SSTVietnamese-Medium.otf"; + break; + case 0x57: + vn_file = "SSTVietnamese-Bold.otf"; + break; + default: + break; + } + if (vn_file) { + add_named_fallback(vn_file); + } + } + + if (is_sea_weight && ((tag == 0x10u) || (tag == 0x14u) || (tag == 0x34u) || + (tag == 0x90u) || (tag == 0x94u) || (tag == 0xB0u) || + (tag == 0xB4u) || (tag == 0xBCu))) { + const char* th_file = nullptr; + switch (sea_weight_code) { + case 0x53: + th_file = "SSTThai-Light.otf"; + break; + case 0x54: + th_file = "SSTThai-Roman.otf"; + break; + case 0x55: + th_file = "SSTThai-Medium.otf"; + break; + case 0x57: + th_file = "SSTThai-Bold.otf"; + break; + default: + break; + } + if (th_file) { + add_named_fallback(th_file); + } + } + + if (needs_jppro && primary_name_lower.rfind("sstjppro-", 0) != 0) { + add_named_fallback(is_bold_like ? "SSTJpPro-Bold.otf" : "SSTJpPro-Regular.otf"); + } + if (needs_cngb && primary_name_lower != "dfhei5-sony.ttf") { + add_named_fallback("DFHEI5-SONY.ttf"); + } + if (needs_hangul && primary_name_lower.rfind("sceps4yoongd-", 0) != 0) { + add_named_fallback(is_bold_like ? "SCEPS4Yoongd-Bold.otf" + : "SCEPS4Yoongd-Medium.otf"); + } + } + for (int i = 0; i < 8; ++i) { const std::string key_a = fmt::format("fontset_0x{:08X}_fallback{}", fontSetType, i); @@ -4556,6 +4880,14 @@ s32 PS4_SYSV_ABI sceFontOpenFontSet(OrbisFontLib library, u32 fontSetType, u32 o fb.bytes->data(), fb.bytes->size(), sub_font_index); fb.ready = (fb.ft_face != nullptr); if (fb.ready) { + fb.scale_factor = compute_sysfont_scale_factor( + fb.ft_face, fb.ft_face ? static_cast(fb.ft_face->units_per_EM) : 0); + fb.shift_value = compute_sysfont_shift_value(fb.ft_face); + LOG_DEBUG(Lib_Font, + "SystemFonts: fallback='{}' unitsPerEm={} scaleFactor={} shiftValue={}", + fb.path.filename().string(), + fb.ft_face ? static_cast(fb.ft_face->units_per_EM) : 0, + fb.scale_factor, fb.shift_value); st.system_fallback_faces.push_back(std::move(fb)); } else { Internal::DestroyFreeTypeFace(fb.ft_face); @@ -4902,10 +5234,26 @@ s32 PS4_SYSV_ABI sceFontOpenFontSet(OrbisFontLib library, u32 fontSetType, u32 o } return s; }; + const auto select_preferred_latin_id = [&](const std::string& name_lower) -> bool { + if (name_lower.empty()) { + return false; + } + for (const auto& fb : st.system_fallback_faces) { + const auto candidate = lower_ascii_local(fb.path.filename().string()); + if (candidate == name_lower && fb.font_id != 0xffffffffu) { + st.fontset_selector->roman_font_id = fb.font_id; + return true; + } + } + return false; + }; + if (!select_preferred_latin_id(preferred_latin_name_lower)) { + (void)select_preferred_latin_id("sst-roman.otf"); + } for (const auto& fb : st.system_fallback_faces) { const auto name = lower_ascii_local(fb.path.filename().string()); - if (name == "sst-roman.otf" && fb.font_id != 0xffffffffu) { - st.fontset_selector->roman_font_id = fb.font_id; + if (name.rfind("sstarabic-", 0) == 0 && fb.font_id != 0xffffffffu) { + st.fontset_selector->arabic_font_id = fb.font_id; break; } } @@ -4933,7 +5281,7 @@ s32 PS4_SYSV_ABI sceFontOpenFontSet(OrbisFontLib library, u32 fontSetType, u32 o header->entry_count = entry_count; auto* entries = reinterpret_cast(st.fontset_record_storage->data() + - sizeof(Internal::FontSetRecordHeader)); + sizeof(Internal::FontSetRecordHeader)); for (u32 i = 0; i < entry_count; ++i) { std::construct_at(entries + i, font_ids[i]); } @@ -5129,6 +5477,19 @@ s32 PS4_SYSV_ABI sceFontRenderCharGlyphImage(OrbisFontHandle fontHandle, u32 cod } const float y_used = y + baseline_add; + { + static std::mutex s_baseline_log_mutex; + static std::unordered_map s_baseline_log_counts; + std::lock_guard lock(s_baseline_log_mutex); + int& count = s_baseline_log_counts[fontHandle]; + if (count < 5) { + LOG_DEBUG(Lib_Font, + "RenderBaseline: handle={} code=U+{:04X} y_in={} baseline_add={} y_used={} pre_rc={}", + static_cast(fontHandle), code, y, baseline_add, y_used, + pre_rc); + ++count; + } + } CachedStyleSetDirectionWord(font->cached_style, 1); diff --git a/src/core/libraries/font/font_internal.cpp b/src/core/libraries/font/font_internal.cpp index 56d2c5e8f..738cb302d 100644 --- a/src/core/libraries/font/font_internal.cpp +++ b/src/core/libraries/font/font_internal.cpp @@ -766,7 +766,6 @@ bool ResolveFace(FontState& st, Libraries::Font::OrbisFontHandle handle, FT_Face return face_out != nullptr; } -// LLE: FUN_0100a690 s32 RenderCodepointToSurface(FontState& st, Libraries::Font::OrbisFontHandle handle, FT_Face face, float pixel_w, float pixel_h, Libraries::Font::OrbisFontRenderSurface* surf, u32 code, float x, @@ -990,7 +989,7 @@ s32 RenderCodepointToSurface(FontState& st, Libraries::Font::OrbisFontHandle han } } - result->stage = nullptr; + result->transImage = nullptr; result->SurfaceImage.address = static_cast(surf->buffer); result->SurfaceImage.widthByte = static_cast(surf->widthByte); result->SurfaceImage.pixelSizeByte = static_cast(surf->pixelSizeByte); @@ -1051,7 +1050,6 @@ s32 RenderCodepointToSurface(FontState& st, Libraries::Font::OrbisFontHandle han return ORBIS_OK; } -// LLE: FUN_0100e050 s32 RenderCodepointToSurfaceWithScale(FontState& st, Libraries::Font::OrbisFontHandle handle, FT_Face face, float scale_x, float scale_y, Libraries::Font::OrbisFontRenderSurface* surf, u32 code, @@ -1237,7 +1235,7 @@ s32 RenderCodepointToSurfaceWithScale(FontState& st, Libraries::Font::OrbisFontH } } - result->stage = nullptr; + result->transImage = nullptr; result->SurfaceImage.address = static_cast(surf->buffer); result->SurfaceImage.widthByte = static_cast(surf->widthByte); result->SurfaceImage.pixelSizeByte = static_cast(surf->pixelSizeByte); @@ -1391,76 +1389,76 @@ constexpr SystemFontDefinition kSystemFontDefinitions[] = { {0x18070054, "FONTSET_SST_STD_VIETNAMESE", "SSTVietnamese-Roman.otf"}, {0x18070055, "FONTSET_SST_STD_VIETNAMESE_MEDIUM", "SSTVietnamese-Medium.otf"}, {0x18070057, "FONTSET_SST_STD_VIETNAMESE_BOLD", "SSTVietnamese-Bold.otf"}, - {0x180700C3, "FONTSET_SST_STD_EUROPEAN_AR_LIGHT", "SSTArabic-Light.otf"}, - {0x180700C4, "FONTSET_SST_STD_EUROPEAN_AR", "SSTArabic-Roman.otf"}, - {0x180700C5, "FONTSET_SST_STD_EUROPEAN_AR_MEDIUM", "SSTArabic-Medium.otf"}, - {0x180700C7, "FONTSET_SST_STD_EUROPEAN_AR_BOLD", "SSTArabic-Bold.otf"}, - {0x18070444, "FONTSET_SST_STD_EUROPEAN_JP", "SSTVietnamese-Roman.otf"}, - {0x18070447, "FONTSET_SST_STD_EUROPEAN_JP_BOLD", "SSTVietnamese-Bold.otf"}, - {0x18070454, "FONTSET_SST_STD_EUROPEAN_JP", "SSTVietnamese-Roman.otf"}, - {0x18070457, "FONTSET_SST_STD_EUROPEAN_JP_BOLD", "SSTVietnamese-Bold.otf"}, - {0x180704C4, "FONTSET_SST_STD_EUROPEAN_JP_AR", "SSTArabic-Roman.otf"}, - {0x180704C7, "FONTSET_SST_STD_EUROPEAN_JP_AR_BOLD", "SSTArabic-Bold.otf"}, - {0x18071053, "FONTSET_SST_STD_THAI_LIGHT", "SSTThai-Light.otf"}, - {0x18071054, "FONTSET_SST_STD_THAI", "SSTThai-Roman.otf"}, - {0x18071055, "FONTSET_SST_STD_THAI_MEDIUM", "SSTThai-Medium.otf"}, - {0x18071057, "FONTSET_SST_STD_THAI_BOLD", "SSTThai-Bold.otf"}, - {0x18071454, "FONTSET_SST_STD_EUROPEAN_JP_TH", "SSTThai-Roman.otf"}, - {0x18071457, "FONTSET_SST_STD_EUROPEAN_JP_TH_BOLD", "SSTThai-Bold.otf"}, - {0x18072444, "FONTSET_SST_STD_EUROPEAN_JPUH", "SSTAribStdB24-Regular.ttf"}, + {0x180700C3, "FONTSET_SST_STD_EUROPEAN_AR_LIGHT", "SST-Light.otf"}, + {0x180700C4, "FONTSET_SST_STD_EUROPEAN_AR", "SST-Roman.otf"}, + {0x180700C5, "FONTSET_SST_STD_EUROPEAN_AR_MEDIUM", "SST-Medium.otf"}, + {0x180700C7, "FONTSET_SST_STD_EUROPEAN_AR_BOLD", "SST-Bold.otf"}, + {0x18070444, "FONTSET_SST_STD_EUROPEAN_JP", "SSTJpPro-Regular.otf"}, + {0x18070447, "FONTSET_SST_STD_EUROPEAN_JP_BOLD", "SSTJpPro-Bold.otf"}, + {0x18070454, "FONTSET_SST_STD_EUROPEAN_JP", "SSTJpPro-Regular.otf"}, + {0x18070457, "FONTSET_SST_STD_EUROPEAN_JP_BOLD", "SSTJpPro-Bold.otf"}, + {0x180704C4, "FONTSET_SST_STD_EUROPEAN_JP_AR", "SSTJpPro-Regular.otf"}, + {0x180704C7, "FONTSET_SST_STD_EUROPEAN_JP_AR_BOLD", "SSTJpPro-Bold.otf"}, + {0x18071053, "FONTSET_SST_STD_THAI_LIGHT", "SSTVietnamese-Light.otf"}, + {0x18071054, "FONTSET_SST_STD_THAI", "SSTVietnamese-Roman.otf"}, + {0x18071055, "FONTSET_SST_STD_THAI_MEDIUM", "SSTVietnamese-Medium.otf"}, + {0x18071057, "FONTSET_SST_STD_THAI_BOLD", "SSTVietnamese-Bold.otf"}, + {0x18071454, "FONTSET_SST_STD_EUROPEAN_JP_TH", "SSTJpPro-Regular.otf"}, + {0x18071457, "FONTSET_SST_STD_EUROPEAN_JP_TH_BOLD", "SSTJpPro-Bold.otf"}, + {0x18072444, "FONTSET_SST_STD_EUROPEAN_JPUH", "SSTJpPro-Regular.otf"}, {0x18072447, "FONTSET_SST_STD_EUROPEAN_JPUH_BOLD", "SSTJpPro-Bold.otf"}, - {0x180724C4, "FONTSET_SST_STD_EUROPEAN_JPUH_AR", "SSTArabic-Roman.otf"}, - {0x180724C7, "FONTSET_SST_STD_EUROPEAN_JPUH_AR_BOLD", "SSTArabic-Bold.otf"}, - {0x18073454, "FONTSET_SST_STD_EUROPEAN_JPUH_TH", "SSTThai-Roman.otf"}, - {0x18073457, "FONTSET_SST_STD_EUROPEAN_JPUH_TH_BOLD", "SSTThai-Bold.otf"}, - {0x180734D4, "FONTSET_SST_STD_EUROPEAN_JPUH_TH_AR", "SSTThai-Roman.otf"}, - {0x180734D7, "FONTSET_SST_STD_EUROPEAN_JPUH_TH_AR_BOLD", "SSTThai-Bold.otf"}, + {0x180724C4, "FONTSET_SST_STD_EUROPEAN_JPUH_AR", "SSTJpPro-Regular.otf"}, + {0x180724C7, "FONTSET_SST_STD_EUROPEAN_JPUH_AR_BOLD", "SSTJpPro-Bold.otf"}, + {0x18073454, "FONTSET_SST_STD_EUROPEAN_JPUH_TH", "SSTJpPro-Regular.otf"}, + {0x18073457, "FONTSET_SST_STD_EUROPEAN_JPUH_TH_BOLD", "SSTJpPro-Bold.otf"}, + {0x180734D4, "FONTSET_SST_STD_EUROPEAN_JPUH_TH_AR", "SSTJpPro-Regular.otf"}, + {0x180734D7, "FONTSET_SST_STD_EUROPEAN_JPUH_TH_AR_BOLD", "SSTJpPro-Bold.otf"}, {0x18078044, "FONTSET_SST_STD_EUROPEAN_GB", "DFHEI5-SONY.ttf"}, - {0x180780C4, "FONTSET_SST_STD_EUROPEAN_GB_AR", "SSTArabic-Roman.otf"}, - {0x18079054, "FONTSET_SST_STD_EUROPEAN_GB_TH", "SSTThai-Roman.otf"}, - {0x1807A044, "FONTSET_SST_STD_EUROPEAN_GBUH", "e046323ms.ttf"}, - {0x1807A0C4, "FONTSET_SST_STD_EUROPEAN_GBUH_AR", "SSTArabic-Bold.otf"}, + {0x180780C4, "FONTSET_SST_STD_EUROPEAN_GB_AR", "DFHEI5-SONY.ttf"}, + {0x18079054, "FONTSET_SST_STD_EUROPEAN_GB_TH", "DFHEI5-SONY.ttf"}, + {0x1807A044, "FONTSET_SST_STD_EUROPEAN_GBUH", "DFHEI5-SONY.ttf"}, + {0x1807A0C4, "FONTSET_SST_STD_EUROPEAN_GBUH_AR", "DFHEI5-SONY.ttf"}, {0x1807A444, "FONTSET_SST_STD_EUROPEAN_JPCJK", "SSTJpPro-Regular.otf"}, - {0x1807A4C4, "FONTSET_SST_STD_EUROPEAN_JPCJK_AR", "SSTArabic-Roman.otf"}, - {0x1807AC44, "FONTSET_SST_STD_EUROPEAN_GBCJK", "n023055ms.ttf"}, - {0x1807ACC4, "FONTSET_SST_STD_EUROPEAN_GBCJK_AR", "SSTArabic-Bold.otf"}, - {0x1807B054, "FONTSET_SST_STD_EUROPEAN_GBUH_TH", "SSTThai-Roman.otf"}, - {0x1807B0D4, "FONTSET_SST_STD_EUROPEAN_GBUH_TH_AR", "SSTThai-Bold.otf"}, - {0x1807B454, "FONTSET_SST_STD_EUROPEAN_JPCJK_TH", "SSTThai-Roman.otf"}, - {0x1807B4D4, "FONTSET_SST_STD_EUROPEAN_JPCJK_TH_AR", "SSTThai-Bold.otf"}, - {0x1807BC54, "FONTSET_SST_STD_EUROPEAN_GBCJK_TH", "SSTThai-Roman.otf"}, - {0x1807BCD4, "FONTSET_SST_STD_EUROPEAN_GBCJK_TH_AR", "SSTThai-Bold.otf"}, - {0x18080444, "FONTSET_SST_STD_JAPANESE_JP", "SSTAribStdB24-Regular.ttf"}, - {0x18080447, "FONTSET_SST_STD_JAPANESE_JP_BOLD", "SSTAribStdB24-Regular.ttf"}, - {0x18080454, "FONTSET_SST_STD_VIETNAMESE_JP", "SSTVietnamese-Roman.otf"}, - {0x18080457, "FONTSET_SST_STD_VIETNAMESE_JP_BOLD", "SSTVietnamese-Bold.otf"}, - {0x180804C4, "FONTSET_SST_STD_JAPANESE_JP_AR", "SSTAribStdB24-Regular.ttf"}, - {0x180804C7, "FONTSET_SST_STD_JAPANESE_JP_AR_BOLD", "SSTAribStdB24-Regular.ttf"}, - {0x18081454, "FONTSET_SST_STD_ASIAN_JP_TH", "SSTThai-Roman.otf"}, - {0x18081457, "FONTSET_SST_STD_ASIAN_JP_TH_BOLD", "SSTThai-Bold.otf"}, - {0x18082444, "FONTSET_SST_STD_JAPANESE_JPUH", "SSTAribStdB24-Regular.ttf"}, + {0x1807A4C4, "FONTSET_SST_STD_EUROPEAN_JPCJK_AR", "SSTJpPro-Regular.otf"}, + {0x1807AC44, "FONTSET_SST_STD_EUROPEAN_GBCJK", "SCEPS4Yoongd-Medium.otf"}, + {0x1807ACC4, "FONTSET_SST_STD_EUROPEAN_GBCJK_AR", "DFHEI5-SONY.ttf"}, + {0x1807B054, "FONTSET_SST_STD_EUROPEAN_GBUH_TH", "DFHEI5-SONY.ttf"}, + {0x1807B0D4, "FONTSET_SST_STD_EUROPEAN_GBUH_TH_AR", "DFHEI5-SONY.ttf"}, + {0x1807B454, "FONTSET_SST_STD_EUROPEAN_JPCJK_TH", "SSTJpPro-Regular.otf"}, + {0x1807B4D4, "FONTSET_SST_STD_EUROPEAN_JPCJK_TH_AR", "SSTJpPro-Regular.otf"}, + {0x1807BC54, "FONTSET_SST_STD_EUROPEAN_GBCJK_TH", "DFHEI5-SONY.ttf"}, + {0x1807BCD4, "FONTSET_SST_STD_EUROPEAN_GBCJK_TH_AR", "DFHEI5-SONY.ttf"}, + {0x18080444, "FONTSET_SST_STD_JAPANESE_JP", "SSTJpPro-Regular.otf"}, + {0x18080447, "FONTSET_SST_STD_JAPANESE_JP_BOLD", "SSTJpPro-Bold.otf"}, + {0x18080454, "FONTSET_SST_STD_VIETNAMESE_JP", "SSTJpPro-Regular.otf"}, + {0x18080457, "FONTSET_SST_STD_VIETNAMESE_JP_BOLD", "SSTJpPro-Bold.otf"}, + {0x180804C4, "FONTSET_SST_STD_JAPANESE_JP_AR", "SSTJpPro-Regular.otf"}, + {0x180804C7, "FONTSET_SST_STD_JAPANESE_JP_AR_BOLD", "SSTJpPro-Bold.otf"}, + {0x18081454, "FONTSET_SST_STD_ASIAN_JP_TH", "SSTJpPro-Regular.otf"}, + {0x18081457, "FONTSET_SST_STD_ASIAN_JP_TH_BOLD", "SSTJpPro-Bold.otf"}, + {0x18082444, "FONTSET_SST_STD_JAPANESE_JPUH", "SSTJpPro-Regular.otf"}, {0x18082447, "FONTSET_SST_STD_JAPANESE_JPUH_BOLD", "SSTJpPro-Bold.otf"}, - {0x180824C4, "FONTSET_SST_STD_JAPANESE_JPUH_AR", "SSTAribStdB24-Regular.ttf"}, + {0x180824C4, "FONTSET_SST_STD_JAPANESE_JPUH_AR", "SSTJpPro-Regular.otf"}, {0x180824C7, "FONTSET_SST_STD_JAPANESE_JPUH_AR_BOLD", "SSTJpPro-Bold.otf"}, - {0x18083454, "FONTSET_SST_STD_ASIAN_JPUH_TH", "SSTThai-Roman.otf"}, - {0x18083457, "FONTSET_SST_STD_ASIAN_JPUH_TH_BOLD", "SSTThai-Bold.otf"}, - {0x180834D4, "FONTSET_SST_STD_ASIAN_JPUH_TH_AR", "SSTThai-Roman.otf"}, - {0x180834D7, "FONTSET_SST_STD_ASIAN_JPUH_TH_AR_BOLD", "SSTThai-Bold.otf"}, - {0x1808A444, "FONTSET_SST_STD_JAPANESE_JPCJK", "SSTAribStdB24-Regular.ttf"}, - {0x1808A4C4, "FONTSET_SST_STD_JAPANESE_JPCJK_AR", "SSTJpPro-Bold.otf"}, - {0x1808B454, "FONTSET_SST_STD_ASIAN_JPCJK_TH", "SSTThai-Roman.otf"}, - {0x1808B4D4, "FONTSET_SST_STD_ASIAN_JPCJK_TH_AR", "SSTThai-Bold.otf"}, + {0x18083454, "FONTSET_SST_STD_ASIAN_JPUH_TH", "SSTJpPro-Regular.otf"}, + {0x18083457, "FONTSET_SST_STD_ASIAN_JPUH_TH_BOLD", "SSTJpPro-Bold.otf"}, + {0x180834D4, "FONTSET_SST_STD_ASIAN_JPUH_TH_AR", "SSTJpPro-Regular.otf"}, + {0x180834D7, "FONTSET_SST_STD_ASIAN_JPUH_TH_AR_BOLD", "SSTJpPro-Bold.otf"}, + {0x1808A444, "FONTSET_SST_STD_JAPANESE_JPCJK", "SSTJpPro-Regular.otf"}, + {0x1808A4C4, "FONTSET_SST_STD_JAPANESE_JPCJK_AR", "SSTJpPro-Regular.otf"}, + {0x1808B454, "FONTSET_SST_STD_ASIAN_JPCJK_TH", "SSTJpPro-Regular.otf"}, + {0x1808B4D4, "FONTSET_SST_STD_ASIAN_JPCJK_TH_AR", "SSTJpPro-Regular.otf"}, {0x180C8044, "FONTSET_SST_STD_SCHINESE_GB", "DFHEI5-SONY.ttf"}, {0x180C80C4, "FONTSET_SST_STD_SCHINESE_GB_AR", "DFHEI5-SONY.ttf"}, - {0x180C9054, "FONTSET_SST_STD_ASIAN_GB_TH", "SSTThai-Roman.otf"}, - {0x180CA044, "FONTSET_SST_STD_SCHINESE_GBUH", "e046323ms.ttf"}, - {0x180CA0C4, "FONTSET_SST_STD_SCHINESE_GBUH_AR", "e046323ms.ttf"}, - {0x180CAC44, "FONTSET_SST_STD_SCHINESE_GBCJK", "n023055ms.ttf"}, - {0x180CACC4, "FONTSET_SST_STD_SCHINESE_GBCJK_AR", "SSTAribStdB24-Regular.ttf"}, - {0x180CB054, "FONTSET_SST_STD_ASIAN_GBUH_TH", "SSTThai-Roman.otf"}, - {0x180CB0D4, "FONTSET_SST_STD_ASIAN_GBUH_TH_AR", "SSTThai-Bold.otf"}, - {0x180CBC54, "FONTSET_SST_STD_ASIAN_GBCJK_TH", "SSTThai-Roman.otf"}, - {0x180CBCD4, "FONTSET_SST_STD_ASIAN_GBCJK_TH_AR", "SSTThai-Bold.otf"}, + {0x180C9054, "FONTSET_SST_STD_ASIAN_GB_TH", "DFHEI5-SONY.ttf"}, + {0x180CA044, "FONTSET_SST_STD_SCHINESE_GBUH", "DFHEI5-SONY.ttf"}, + {0x180CA0C4, "FONTSET_SST_STD_SCHINESE_GBUH_AR", "DFHEI5-SONY.ttf"}, + {0x180CAC44, "FONTSET_SST_STD_SCHINESE_GBCJK", "DFHEI5-SONY.ttf"}, + {0x180CACC4, "FONTSET_SST_STD_SCHINESE_GBCJK_AR", "DFHEI5-SONY.ttf"}, + {0x180CB054, "FONTSET_SST_STD_ASIAN_GBUH_TH", "DFHEI5-SONY.ttf"}, + {0x180CB0D4, "FONTSET_SST_STD_ASIAN_GBUH_TH_AR", "DFHEI5-SONY.ttf"}, + {0x180CBC54, "FONTSET_SST_STD_ASIAN_GBCJK_TH", "DFHEI5-SONY.ttf"}, + {0x180CBCD4, "FONTSET_SST_STD_ASIAN_GBCJK_TH_AR", "DFHEI5-SONY.ttf"}, {0x18170043, "FONTSET_SST_STD_EUROPEAN_LIGHT_ITALIC", "SST-LightItalic.otf"}, {0x18170044, "FONTSET_SST_STD_EUROPEAN_ITALIC", "SST-Italic.otf"}, {0x18170045, "FONTSET_SST_STD_EUROPEAN_MEDIUM_ITALIC", "SST-MediumItalic.otf"}, @@ -1469,8 +1467,8 @@ constexpr SystemFontDefinition kSystemFontDefinitions[] = { {0x18170447, "FONTSET_SST_STD_EUROPEAN_JP_BOLD_ITALIC", "SSTJpPro-Bold.otf"}, {0x18370044, "FONTSET_SST_TYPEWRITER_EUROPEAN", "SSTTypewriter-Roman.otf"}, {0x18370047, "FONTSET_SST_TYPEWRITER_EUROPEAN_BOLD", "SSTTypewriter-Bd.otf"}, - {0x18370444, "FONTSET_SST_TYPEWRITER_EUROPEAN_JP", "SSTTypewriter-Roman.otf"}, - {0x18370447, "FONTSET_SST_TYPEWRITER_EUROPEAN_JP_BOLD", "SSTTypewriter-Bd.otf"}, + {0x18370444, "FONTSET_SST_TYPEWRITER_EUROPEAN_JP", "SSTJpPro-Regular.otf"}, + {0x18370447, "FONTSET_SST_TYPEWRITER_EUROPEAN_JP_BOLD", "SSTJpPro-Bold.otf"}, }; std::mutex g_fontset_cache_mutex; @@ -1600,6 +1598,44 @@ std::filesystem::path GetSysFontBaseDir() { return {}; } +static std::filesystem::path ResolveSystemFontPathCandidate(const std::filesystem::path& base_dir, + const std::filesystem::path& filename) { + if (base_dir.empty() || filename.empty()) { + return {}; + } + std::error_code ec; + const auto is_file = [&](const std::filesystem::path& p) -> bool { + return std::filesystem::is_regular_file(p, ec) && !ec; + }; + + const auto direct = base_dir / filename; + if (is_file(direct)) { + return direct; + } + + const auto base_name = base_dir.filename().string(); + if (base_name != "font" && base_name != "font2") { + const auto in_font = base_dir / "font" / filename; + if (is_file(in_font)) { + return in_font; + } + const auto in_font2 = base_dir / "font2" / filename; + if (is_file(in_font2)) { + return in_font2; + } + } + + if (base_name == "font" || base_name == "font2") { + const auto container = base_dir.parent_path(); + const auto sibling = container / ((base_name == "font") ? "font2" : "font") / filename; + if (is_file(sibling)) { + return sibling; + } + } + + return direct; +} + std::string MacroToCamel(const char* macro_key) { if (!macro_key) { return {}; @@ -1639,7 +1675,7 @@ std::filesystem::path ResolveSystemFontPath(u32 font_set_type) { if (auto override_path = Config::getSystemFontOverride(def->config_key)) { if (!override_path->empty() && !override_path->is_absolute() && !override_path->has_parent_path()) { - return base_dir / *override_path; + return ResolveSystemFontPathCandidate(base_dir, *override_path); } LOG_ERROR(Lib_Font, "SystemFonts: override for '{}' must be a filename only (no path): '{}'", @@ -1650,7 +1686,7 @@ std::filesystem::path ResolveSystemFontPath(u32 font_set_type) { if (auto override_path2 = Config::getSystemFontOverride(camel_key)) { if (!override_path2->empty() && !override_path2->is_absolute() && !override_path2->has_parent_path()) { - return base_dir / *override_path2; + return ResolveSystemFontPathCandidate(base_dir, *override_path2); } LOG_ERROR(Lib_Font, "SystemFonts: override for '{}' must be a filename only (no path): '{}'", @@ -1662,7 +1698,7 @@ std::filesystem::path ResolveSystemFontPath(u32 font_set_type) { if (auto override_path3 = Config::getSystemFontOverride(lower_camel)) { if (!override_path3->empty() && !override_path3->is_absolute() && !override_path3->has_parent_path()) { - return base_dir / *override_path3; + return ResolveSystemFontPathCandidate(base_dir, *override_path3); } LOG_ERROR(Lib_Font, "SystemFonts: override for '{}' must be a filename only (no path): '{}'", @@ -1670,7 +1706,7 @@ std::filesystem::path ResolveSystemFontPath(u32 font_set_type) { } } if (def->default_file && *def->default_file) { - return base_dir / def->default_file; + return ResolveSystemFontPathCandidate(base_dir, def->default_file); } } LOG_ERROR(Lib_Font, "SystemFonts: unknown font set type=0x{:08X}", font_set_type); @@ -1772,6 +1808,21 @@ bool LoadFontFile(const std::filesystem::path& path, std::vector& const auto parent = path.parent_path(); const auto parent_name = parent.filename().string(); const auto file_name = path.filename(); + if (!file_name.empty() && parent_name != "font" && parent_name != "font2") { + const auto cand_font = parent / "font" / file_name; + if (std::filesystem::is_regular_file(cand_font, ec) && !ec) { + if (try_load(cand_font)) { + return true; + } + } + const auto cand_font2 = parent / "font2" / file_name; + if (std::filesystem::is_regular_file(cand_font2, ec) && !ec) { + if (try_load(cand_font2)) { + return true; + } + } + } + if (!file_name.empty() && (parent_name == "font" || parent_name == "font2")) { const auto container = parent.parent_path(); const auto sibling = container / ((parent_name == "font") ? "font2" : "font") / file_name; @@ -1928,5 +1979,4 @@ std::string ReportSystemFaceRequest(FontState& st, Libraries::Font::OrbisFontHan } return {}; } - } // namespace Libraries::Font::Internal diff --git a/src/core/libraries/font/fontft_internal.cpp b/src/core/libraries/font/fontft_internal.cpp index 6dc3d95bd..fe755c268 100644 --- a/src/core/libraries/font/fontft_internal.cpp +++ b/src/core/libraries/font/fontft_internal.cpp @@ -3,9 +3,9 @@ #include "core/libraries/font/fontft_internal.h" +#include #include #include -#include #include #include #include @@ -42,7 +42,6 @@ using Libraries::Font::OrbisFontRenderOutput; using Libraries::Font::OrbisFontRenderSurface; using Libraries::Font::OrbisFontStyleFrame; -// LLE: FUN_01007e80 static void UpdateFtFontObjShiftCache(u8* font_obj) { if (!font_obj) { return; @@ -52,7 +51,8 @@ static void UpdateFtFontObjShiftCache(u8* font_obj) { obj->shift_cache_x = static_cast(obj->shift_units_x); obj->shift_cache_y = static_cast(obj->shift_units_y); - const s32 seed_low = static_cast(static_cast(obj->layout_seed_pair & 0xFFFFFFFFu)); + const s32 seed_low = + static_cast(static_cast(obj->layout_seed_pair & 0xFFFFFFFFu)); const s32 seed_high = static_cast(static_cast((obj->layout_seed_pair >> 32) & 0xFFFFFFFFu)); obj->layout_seed_vec[0] = static_cast(static_cast(seed_low)); @@ -136,7 +136,6 @@ void ReleaseCachedStyleLock(Libraries::Font::FontHandleOpaqueNative* font, u32 p font->cached_style.cache_lock_word = prev_lock_word & 0x7fffffff; } -// LLE: FUN_01000c30 std::uint8_t* AcquireFontCtxEntry(std::uint8_t* ctx, u32 idx, u32 mode_low, void** out_obj, u32* out_lock_word) { if (!ctx || !out_obj || !out_lock_word) { @@ -193,7 +192,6 @@ std::uint8_t* AcquireFontCtxEntry(std::uint8_t* ctx, u32 idx, u32 mode_low, void } } -// LLE: FUN_01000d70 static std::uint8_t* AcquireFontCtxEntryAndSelectNode(std::uint8_t* ctx, u32 idx, u32 mode_low, u32 sub_font_index, void** out_obj, u32* out_lock_word) { @@ -212,7 +210,6 @@ static std::uint8_t* AcquireFontCtxEntryAndSelectNode(std::uint8_t* ctx, u32 idx return entry_u8; } -// LLE: FUN_01000db0 static void ReleaseFontCtxEntryLock(std::uint8_t* entry_u8, u32 mode_low, u32 lock_word) { if (!entry_u8) { return; @@ -244,21 +241,20 @@ static void ReleaseFontCtxEntryLock(std::uint8_t* entry_u8, u32 mode_low, u32 lo *lock_word_ptr = lock_word & 0x7FFFFFFFu; } -// LLE: FUN_01000ba0 static void ApplyGlyphSpecialCaseAdjust(int font_id, int glyph_index, int* inout_seed_words) { if (!inout_seed_words) { return; } if (((font_id == 10) && (static_cast(glyph_index - 0x23d1U) < 0x5e)) && ((0x5c0000000017ULL >> - (static_cast(static_cast((static_cast(glyph_index - 0x23d1U) >> 1) & 0x3f)) & - 0x3fULL)) & + (static_cast( + static_cast((static_cast(glyph_index - 0x23d1U) >> 1) & 0x3f)) & + 0x3fULL)) & 1ULL) != 0) { inout_seed_words[0] = inout_seed_words[0] + 500; } } -// LLE: FUN_01009ff0 static std::uintptr_t AcquireRendererSelectionLock(RendererOpaque* renderer) { if (!renderer) { return 0; @@ -279,7 +275,6 @@ static std::uintptr_t AcquireRendererSelectionLock(RendererOpaque* renderer) { } } -// LLE: FUN_0100bf00 static std::uint64_t ResolveGposTagForCode(u32 codepoint) { (void)codepoint; return 0; @@ -301,32 +296,27 @@ static_assert(sizeof(SysFontRangeRecord) == 0x1C); static_assert(offsetof(SysFontRangeRecord, shift_x) == 0x08); static_assert(offsetof(SysFontRangeRecord, scale_mul) == 0x0C); -// LLE: FUN_01000480 static float SysFontScaleFactor(u32 font_id) { (void)font_id; return 1.0f; } -// LLE: FUN_010004d0 static float SysFontShiftValueF32(u32 font_id) { (void)font_id; return 0.0f; } -// LLE: FUN_010004f0 static u8 SysFontHasAltFlag(u32 font_id) { (void)font_id; return 0; } -// LLE: FUN_010006c0 const std::uint8_t* FindSysFontRangeRecord(u32 font_id, u32 codepoint) { (void)font_id; (void)codepoint; return nullptr; } -// LLE: FUN_010098b0 static u32 ResolveSysFontMapping(const void* record, int table_id, u32 codepoint, u32* out_codepoint) { (void)record; @@ -337,7 +327,6 @@ static u32 ResolveSysFontMapping(const void* record, int table_id, u32 codepoint return 0; } -// LLE: FUN_010008b0 u32 ResolveSysFontCodepoint(const void* record, u64 code, u32 flags, u32* out_font_id) { if (!record) { if (out_font_id) { @@ -352,8 +341,7 @@ u32 ResolveSysFontCodepoint(const void* record, u64 code, u32 flags, u32* out_fo if (rec->magic == Libraries::Font::Internal::FontSetSelector::kMagic) { const auto view = MakeFontSetRecordView(rec); const u32 entry_count = view.header ? view.header->entry_count : 0u; - const u32 record_primary_id = - (entry_count && view.entry_indices) ? view.entry_indices[0] : 0u; + const u32 record_primary_id = (entry_count && view.entry_indices) ? view.entry_indices[0] : 0u; const auto* selector = view.selector; if (!selector || selector->magic != Libraries::Font::Internal::FontSetSelector::kMagic) { if (out_font_id) { @@ -362,98 +350,60 @@ u32 ResolveSysFontCodepoint(const void* record, u64 code, u32 flags, u32* out_fo return code_u32; } + const u32 primary_id = selector->primary_font_id != 0xffffffffu ? selector->primary_font_id + : record_primary_id; + const u32 roman_id = selector->roman_font_id != 0xffffffffu ? selector->roman_font_id + : record_primary_id; + const u32 arabic_id = selector->arabic_font_id != 0xffffffffu ? selector->arabic_font_id : roman_id; + auto is_cjk_like = [](u32 cp) -> bool { - if ((cp >= 0x3040u && cp <= 0x30FFu) || (cp >= 0x31F0u && cp <= 0x31FFu) || - (cp >= 0x3400u && cp <= 0x4DBFu) || (cp >= 0x4E00u && cp <= 0x9FFFu) || - (cp >= 0xAC00u && cp <= 0xD7AFu) || (cp >= 0xF900u && cp <= 0xFAFFu) || + if ((cp >= 0x3040u && cp <= 0x30FFu) || + (cp >= 0x31F0u && cp <= 0x31FFu) || + (cp >= 0x3400u && cp <= 0x4DBFu) || + (cp >= 0x4E00u && cp <= 0x9FFFu) || + (cp >= 0xAC00u && cp <= 0xD7AFu) || + (cp >= 0xF900u && cp <= 0xFAFFu) || (cp >= 0x20000u && cp <= 0x2FA1Fu)) { return true; } return false; }; + auto is_arabic_like = [](u32 cp) -> bool { + return (cp >= 0x0600u && cp <= 0x06FFu) || (cp >= 0x0750u && cp <= 0x077Fu) || + (cp >= 0x08A0u && cp <= 0x08FFu) || (cp >= 0xFB50u && cp <= 0xFDFFu) || + (cp >= 0xFE70u && cp <= 0xFEFFu); + }; + auto is_symbol_like = [](u32 cp) -> bool { + return (cp >= 0x25A0u && cp <= 0x25FFu) || + (cp >= 0x2600u && cp <= 0x26FFu) || + (cp >= 0x2700u && cp <= 0x27BFu); + }; - const u32 primary_id = selector->primary_font_id != 0xffffffffu ? selector->primary_font_id - : record_primary_id; + u32 selected_font_id = roman_id; + if (is_arabic_like(code_u32)) { + selected_font_id = arabic_id; + } else if (is_cjk_like(code_u32) || is_symbol_like(code_u32)) { + selected_font_id = primary_id; + } - auto has_glyph_in_ctx = [&](u32 font_id, u32 cp) -> bool { - if (!selector->library || selector->mode_low == 0) { - return false; - } - auto* lib = static_cast(selector->library); - auto* ctx = lib ? static_cast(lib->sysfonts_ctx) : nullptr; - if (!ctx) { - return false; - } - void* head = nullptr; - u32 lock_word = 0; - u8* entry_u8 = AcquireFontCtxEntry(ctx, font_id, selector->mode_low, &head, &lock_word); - auto* entry = entry_u8 ? reinterpret_cast(entry_u8) : nullptr; - auto* node = static_cast(head); - while (node) { - if (node->sub_font_index == selector->sub_font_index) { + if (view.entry_indices && entry_count) { + bool found = false; + for (u32 i = 0; i < entry_count; ++i) { + if (view.entry_indices[i] == selected_font_id) { + found = true; break; } - node = node->next; } - FT_Face face = node ? static_cast(node->ft_face) : nullptr; - const bool ok = face && (FT_Get_Char_Index(face, static_cast(cp)) != 0); - if (entry) { - if (selector->mode_low == 3) { - entry->lock_mode3 = lock_word & 0x7fffffffu; - } else if (selector->mode_low == 2) { - entry->lock_mode2 = lock_word & 0x7fffffffu; - } else { - entry->lock_mode1 = lock_word & 0x7fffffffu; - } - } - return ok; - }; - - auto has_glyph = [&](u32 font_id, u32 cp) -> bool { - if (font_id == 0xffffffffu) { - return false; - } - if (has_glyph_in_ctx(font_id, cp)) { - return true; - } - for (const auto& c : selector->candidates) { - if (c.font_id != font_id || !c.face) { - continue; - } - return FT_Get_Char_Index(c.face, static_cast(cp)) != 0; - } - return false; - }; - - auto select_font = [&](u32 font_id) -> bool { - if (!has_glyph(font_id, code_u32)) { - return false; - } - if (out_font_id) { - *out_font_id = font_id; - } - return true; - }; - - if (selector->roman_font_id != 0xffffffffu && !is_cjk_like(code_u32)) { - if (select_font(selector->roman_font_id)) { - return code_u32; - } - } - if (select_font(primary_id)) { - return code_u32; - } - for (const auto& c : selector->candidates) { - if (select_font(c.font_id)) { - return code_u32; + if (!found) { + selected_font_id = record_primary_id; } } if (out_font_id) { - *out_font_id = primary_id; + *out_font_id = selected_font_id; } (void)flags; - return 0; + return code_u32; } (void)flags; @@ -463,7 +413,6 @@ u32 ResolveSysFontCodepoint(const void* record, u64 code, u32 flags, u32* out_fo return code_u32; } -// LLE: FUN_010042e0 void ReleaseFontObjectsForHandle(Libraries::Font::OrbisFontHandle fontHandle, int entryCount) { if (!fontHandle) { return; @@ -586,7 +535,6 @@ void ReleaseFontObjectsForHandle(Libraries::Font::OrbisFontHandle fontHandle, in } } -// LLE: FUN_01006990 s32 ComputeHorizontalLayoutBlocks(OrbisFontHandle fontHandle, const void* style_state_block, u8 (*out_words)[16]) { if (out_words) { @@ -717,7 +665,26 @@ s32 ComputeHorizontalLayoutBlocks(OrbisFontHandle fontHandle, const void* style_ float fontset_scale_factor = 1.0f; int fontset_shift_value = 0; - (void)fontset_record; + if (fontset_record && fontset_record->magic == Libraries::Font::Internal::FontSetSelector::kMagic) { + if (auto* st = Internal::TryGetState(fontHandle)) { + if (st->system_requested) { + if (font_id == st->system_font_id) { + fontset_scale_factor = st->system_font_scale_factor; + fontset_shift_value = st->system_font_shift_value; + } else { + for (const auto& fb : st->system_fallback_faces) { + if (fb.font_id == font_id) { + fontset_scale_factor = fb.scale_factor; + fontset_shift_value = fb.shift_value; + break; + } + } + } + } + } + } else { + (void)fontset_record; + } void* head = nullptr; u32 lock_word = 0; @@ -844,8 +811,7 @@ s32 ComputeHorizontalLayoutBlocks(OrbisFontHandle fontHandle, const void* style_ const float line_h = baseline_max + delta_max; const float effect_h = maxss(effect_for_baseline, effect_for_delta); - if ((reinterpret_cast(out_words) & (alignof(HorizontalLayoutBlocks) - 1)) == - 0) { + if ((reinterpret_cast(out_words) & (alignof(HorizontalLayoutBlocks) - 1)) == 0) { auto* out_blocks = reinterpret_cast(out_words); out_blocks->set_baseline(baseline_max); out_blocks->set_line_advance(line_h); @@ -866,7 +832,6 @@ s32 ComputeHorizontalLayoutBlocks(OrbisFontHandle fontHandle, const void* style_ return ORBIS_OK; } -// LLE: FUN_01006fb0 s32 ComputeVerticalLayoutBlocks(OrbisFontHandle fontHandle, const void* style_state_block, u8 (*out_words)[16]) { auto* font = GetNativeFont(fontHandle); @@ -946,7 +911,25 @@ s32 ComputeVerticalLayoutBlocks(OrbisFontHandle fontHandle, const void* style_st float scale_factor = 1.0f; s32 shift_value = 0; - if (fontset_record) { + if (fontset_record && static_cast(fontset_record)->magic == + Libraries::Font::Internal::FontSetSelector::kMagic) { + if (auto* st = Internal::TryGetState(fontHandle)) { + if (st->system_requested) { + if (font_id == st->system_font_id) { + scale_factor = st->system_font_scale_factor; + shift_value = st->system_font_shift_value; + } else { + for (const auto& fb : st->system_fallback_faces) { + if (fb.font_id == font_id) { + scale_factor = fb.scale_factor; + shift_value = fb.shift_value; + break; + } + } + } + } + } + } else if (fontset_record) { const auto desc = GetSysFontDesc(font_id); scale_factor = desc.scale_factor; shift_value = desc.shift_value; @@ -998,10 +981,11 @@ s32 ComputeVerticalLayoutBlocks(OrbisFontHandle fontHandle, const void* style_st VerticalLayoutAltBlocks layout_alt{}; if (call_rc == ORBIS_OK) { UpdateFtFontObjShiftCache(reinterpret_cast(font_obj)); - call_rc = driver->compute_layout_alt - ? driver->compute_layout_alt(font_obj, style_state_block, - LayoutWordsBytes(layout_alt.words())) - : ORBIS_FONT_ERROR_FATAL; + call_rc = + driver->compute_layout_alt + ? driver->compute_layout_alt(font_obj, style_state_block, + LayoutWordsBytes(layout_alt.words())) + : ORBIS_FONT_ERROR_FATAL; } if (call_rc == ORBIS_OK) { @@ -1021,14 +1005,12 @@ s32 ComputeVerticalLayoutBlocks(OrbisFontHandle fontHandle, const void* style_st if (acc_neg_local64_max < neg_baseline_offset_x_candidate) { assoc_for_neg_local64_max = decoration_span_candidate; } - acc_neg_local64_max = - std::max(acc_neg_local64_max, neg_baseline_offset_x_candidate); + acc_neg_local64_max = std::max(acc_neg_local64_max, neg_baseline_offset_x_candidate); if (acc_sum_max < sum_primary_0x00_and_baseline_offset_x_candidate) { assoc_for_sum_max = decoration_span_candidate; } - acc_sum_max = - std::max(acc_sum_max, sum_primary_0x00_and_baseline_offset_x_candidate); + acc_sum_max = std::max(acc_sum_max, sum_primary_0x00_and_baseline_offset_x_candidate); const float diff = extra_0x08 - baseline_offset_x_candidate; acc_diff_min = std::min(diff, acc_diff_min); @@ -1094,8 +1076,7 @@ s32 ComputeVerticalLayoutBlocks(OrbisFontHandle fontHandle, const void* style_st const float unknown_decoration_0x08 = acc_temp_min - acc_neg_local64_max; const float unknown_decoration_0x0C = -acc_sum_max; - if ((reinterpret_cast(out_words) & (alignof(VerticalLayoutBlocks) - 1)) == - 0) { + if ((reinterpret_cast(out_words) & (alignof(VerticalLayoutBlocks) - 1)) == 0) { auto* out_blocks = reinterpret_cast(out_words); out_blocks->set_column_advance(column_advance); out_blocks->set_baseline_offset_x(baseline_offset_x); @@ -1118,7 +1099,6 @@ s32 ComputeVerticalLayoutBlocks(OrbisFontHandle fontHandle, const void* style_st return ORBIS_OK; } -// LLE: FUN_01007e40 s32 GetCharGlyphMetrics(OrbisFontHandle fontHandle, u32 code, OrbisFontGlyphMetrics* metrics, bool use_cached_style) { auto clear_metrics = [&] { @@ -1503,7 +1483,6 @@ inline const RenderSurfaceSystemUse* GetSurfaceSystemUse( return surf ? reinterpret_cast(surf->reserved_q) : nullptr; } -// LLE: FUN_0100a690 static const StyleStateBlock* ResolveSurfaceStyleState( const StyleStateBlock* cached_style_state, const Libraries::Font::OrbisFontRenderSurface* surf, const RenderSurfaceSystemUse* sys, StyleStateBlock& tmp_out) { @@ -1541,7 +1520,6 @@ static const StyleStateBlock* ResolveSurfaceStyleState( return &tmp_out; } -// LLE: FUN_0100a690 static s32 RenderGlyphIndexToSurface(FontObj& font_obj, u32 glyph_index, Libraries::Font::OrbisFontRenderSurface* surf, float x, float y, Libraries::Font::OrbisFontGlyphMetrics* metrics, @@ -1708,7 +1686,7 @@ static s32 RenderGlyphIndexToSurface(FontObj& font_obj, u32 glyph_index, } } - result->stage = nullptr; + result->transImage = nullptr; result->SurfaceImage.address = static_cast(surf->buffer); result->SurfaceImage.widthByte = static_cast(surf->widthByte); result->SurfaceImage.pixelSizeByte = static_cast(surf->pixelSizeByte); @@ -1746,7 +1724,7 @@ static s32 RenderGlyphIndexToSurface(FontObj& font_obj, u32 glyph_index, const int left_i = floor_int(left_f); const int top_i = floor_int(top_f); const int right_i = ceil_int(right_f); - const int bottom_i = ceil_int(bottom_f); + const int bottom_i = floor_int(bottom_f); const float adv_f = x + metrics->Horizontal.advance; const float adv_snapped = static_cast(floor_int(adv_f)) - x; @@ -1798,7 +1776,6 @@ StyleFrameScaleState ResolveMergedStyleFrameScale(const Libraries::Font::OrbisFo } // namespace -// LLE: FUN_0100a690 s32 RenderCharGlyphImageCore(Libraries::Font::OrbisFontHandle fontHandle, u32 code, Libraries::Font::OrbisFontRenderSurface* surf, float x, float y, Libraries::Font::OrbisFontGlyphMetrics* metrics, @@ -1881,7 +1858,24 @@ s32 RenderCharGlyphImageCore(Libraries::Font::OrbisFontHandle fontHandle, u32 co return ORBIS_FONT_ERROR_NO_SUPPORT_CODE; } - if (!is_internal_fontset_record) { + if (is_internal_fontset_record) { + if (auto* st = Internal::TryGetState(fontHandle)) { + if (st->system_requested) { + if (font_id == st->system_font_id) { + sys_scale_factor = st->system_font_scale_factor; + shift_y_units = st->system_font_shift_value; + } else { + for (const auto& fb : st->system_fallback_faces) { + if (fb.font_id == font_id) { + sys_scale_factor = fb.scale_factor; + shift_y_units = fb.shift_value; + break; + } + } + } + } + } + } else { const SysFontDesc desc = GetSysFontDesc(font_id); sys_scale_factor = desc.scale_factor; shift_y_units = desc.shift_value; @@ -1904,6 +1898,25 @@ s32 RenderCharGlyphImageCore(Libraries::Font::OrbisFontHandle fontHandle, u32 co } } + { + static std::mutex s_mutex; + static std::unordered_map s_counts; + std::scoped_lock lock(s_mutex); + int& count = s_counts[fontHandle]; + const bool force_diag = (code == 0x000Au) || (code == 0x000Du) || (code == 0x25B3u); + if (force_diag || count < 5) { + if (!force_diag) { + ++count; + } + LOG_DEBUG(Lib_Font, + "SysfontRender: handle={} code=U+{:04X} mapped=U+{:04X} font_id={} " + "scale_unit={} dpi_x={} dpi_y={} scale_w={} scale_h={} sys_scale_factor={} " + "shift_y_units={}", + static_cast(fontHandle), code, mapped_code, font_id, scale_unit, + dpi_x, dpi_y, scale_x_in, scale_y_in, sys_scale_factor, shift_y_units); + } + } + void* font_obj_void = nullptr; u32 lock_word = 0; std::uint8_t* entry_u8 = AcquireFontCtxEntryAndSelectNode( @@ -1973,7 +1986,6 @@ s32 RenderCharGlyphImageCore(Libraries::Font::OrbisFontHandle fontHandle, u32 co return cleanup_return(rc); } -// LLE: FUN_0100e050 s32 RenderGlyphImageCore(Libraries::Font::OrbisFontGlyph fontGlyph, Libraries::Font::OrbisFontStyleFrame* fontStyleFrame, Libraries::Font::OrbisFontRenderer fontRenderer, @@ -2102,7 +2114,6 @@ s32 RenderGlyphImageCore(Libraries::Font::OrbisFontGlyph fontGlyph, return rc; } -// LLE: FUN_0100b6f0 s32 StyleStateSetScalePixel(void* style_state_block, float w, float h) { auto* st = static_cast(style_state_block); if (!st) { @@ -2119,7 +2130,6 @@ s32 StyleStateSetScalePixel(void* style_state_block, float w, float h) { return 1; } -// LLE: FUN_0100b730 s32 StyleStateSetScalePoint(void* style_state_block, float w, float h) { auto* st = static_cast(style_state_block); if (!st) { @@ -2136,7 +2146,6 @@ s32 StyleStateSetScalePoint(void* style_state_block, float w, float h) { return 1; } -// LLE: FUN_0100b770 s32 StyleStateGetScalePixel(const void* style_state_block, float* w, float* h) { const auto* st = static_cast(style_state_block); if (!st || (!w && !h)) { @@ -2165,7 +2174,6 @@ s32 StyleStateGetScalePixel(const void* style_state_block, float* w, float* h) { return ORBIS_OK; } -// LLE: FUN_0100b7e0 s32 StyleStateGetScalePoint(const void* style_state_block, float* w, float* h) { const auto* st = static_cast(style_state_block); if (!st || (!w && !h)) { @@ -2194,7 +2202,6 @@ s32 StyleStateGetScalePoint(const void* style_state_block, float* w, float* h) { return ORBIS_OK; } -// LLE: FUN_0100b860 s32 StyleStateSetDpi(u32* dpi_pair, u32 h_dpi, u32 v_dpi) { if (!dpi_pair) { return 0; @@ -2213,7 +2220,6 @@ s32 StyleStateSetDpi(u32* dpi_pair, u32 h_dpi, u32 v_dpi) { return 1; } -// LLE: FUN_0100b8b0 s32 StyleStateSetSlantRatio(void* style_state_block, float slantRatio) { auto* st = static_cast(style_state_block); if (!st) { @@ -2234,7 +2240,6 @@ s32 StyleStateSetSlantRatio(void* style_state_block, float slantRatio) { return 1; } -// LLE: FUN_0100b8f0 s32 StyleStateGetSlantRatio(const void* style_state_block, float* slantRatio) { const auto* st = static_cast(style_state_block); if (!st || !slantRatio) { @@ -2244,7 +2249,6 @@ s32 StyleStateGetSlantRatio(const void* style_state_block, float* slantRatio) { return ORBIS_OK; } -// LLE: FUN_0100b910 s32 StyleStateSetWeightScale(void* style_state_block, float weightXScale, float weightYScale) { auto* st = static_cast(style_state_block); if (!st) { @@ -2280,7 +2284,6 @@ s32 StyleStateSetWeightScale(void* style_state_block, float weightXScale, float return changed ? 1 : 0; } -// LLE: FUN_0100b9a0 s32 StyleStateGetWeightScale(const void* style_state_block, float* weightXScale, float* weightYScale, u32* mode) { if ((reinterpret_cast(weightXScale) | @@ -2484,7 +2487,8 @@ static bool ResolveSfntBaseOffset(const u8* data, std::size_t size, u32 subFontI return false; } - const u32 base = static_cast(static_cast(data + want_off))->value(); + const u32 base = + static_cast(static_cast(data + want_off))->value(); if (base > size || (size - base) < 0x0C) { return false; } @@ -2544,8 +2548,7 @@ static bool ReadUnitsPerEm(const u8* data, std::size_t size, u32 base, u16& out_ if (head_len < 0x14 || head_off + 0x14 > size) { return false; } - out_units = - static_cast(static_cast(data + head_off + 0x12))->value(); + out_units = static_cast(static_cast(data + head_off + 0x12))->value(); return out_units != 0; } @@ -3093,6 +3096,7 @@ s32 PS4_SYSV_ABI LibrarySetCharSizeWithDpiStub(void* fontObj, u32 dpi_x, u32 dpi return ORBIS_FONT_ERROR_FATAL; } + const auto char_w = static_cast(static_cast(scale_x * 64.0f)); const auto char_h = static_cast(static_cast(scale_y * 64.0f)); if (FT_Set_Char_Size(face, char_w, char_h, dpi_x, dpi_y) != 0) { @@ -3264,7 +3268,8 @@ s32 PS4_SYSV_ABI LibraryComputeLayoutBlockStub(void* fontObj, const void* style_ float hhea_out = 0.0f; if (const TT_HoriHeader* hhea = static_cast(FT_Get_Sfnt_Table(face, ft_sfnt_hhea))) { - const s64 caret_rise_units = x_shift + static_cast(hhea->caret_Slope_Rise); + const s64 caret_rise_units = + x_shift + static_cast(hhea->caret_Slope_Rise); const s32 caret_rise_px = trunc_fixed_16_16_to_int(caret_rise_units * x_scale); hhea_out = static_cast(caret_rise_px - half_effect_w_px) * kOneOver64; } @@ -3442,7 +3447,6 @@ s32 PS4_SYSV_ABI LibraryComputeLayoutAltBlockStub(void* fontObj, const void* sty return ORBIS_OK; } -// LLE: FUN_01007e80 (sys_driver +0xA8) s32 PS4_SYSV_ABI LibraryLoadGlyphCachedStub(void* fontObj, u32 glyphIndex, s32 mode, std::uint64_t* out_words) { if (out_words) { @@ -3470,8 +3474,7 @@ s32 PS4_SYSV_ABI LibraryLoadGlyphCachedStub(void* fontObj, u32 glyphIndex, s32 m (obj->cached_units_y_0x70 == obj->cached_units_x_0x68) && (mode == 0); auto write_vec88_from_seed_pair_unscaled = [&]() { - const s32 seed_low = - static_cast(static_cast(obj->layout_seed_pair & 0xFFFFFFFFu)); + const s32 seed_low = static_cast(static_cast(obj->layout_seed_pair & 0xFFFFFFFFu)); const s32 seed_high = static_cast(static_cast((obj->layout_seed_pair >> 32) & 0xFFFFFFFFu)); obj->layout_seed_vec[0] = static_cast(static_cast(seed_low)); @@ -3585,7 +3588,6 @@ s32 PS4_SYSV_ABI LibraryLoadGlyphCachedStub(void* fontObj, u32 glyphIndex, s32 m return ORBIS_OK; } -// LLE: FUN_0100a740 (sys_driver +0xB8) s32 PS4_SYSV_ABI LibraryGetGlyphMetricsStub(void* fontObj, std::uint32_t* /*opt_param2*/, std::uint8_t /*mode*/, std::uint8_t* out_params, Libraries::Font::OrbisFontGlyphMetrics* out_metrics) { @@ -3631,7 +3633,6 @@ s32 PS4_SYSV_ABI LibraryGetGlyphMetricsStub(void* fontObj, std::uint32_t* /*opt_ return ORBIS_OK; } -// LLE: FUN_0100b750 (sys_driver +0xE0) s32 PS4_SYSV_ABI LibraryApplyGlyphAdjustStub(void* fontObj, u32 /*p2*/, u32 glyphIndex, s32 p4, s32 p5, u32* inoutGlyphIndex) { if (!fontObj || !inoutGlyphIndex) { @@ -3645,7 +3646,6 @@ s32 PS4_SYSV_ABI LibraryApplyGlyphAdjustStub(void* fontObj, u32 /*p2*/, u32 glyp return ORBIS_OK; } -// LLE: FUN_0100d990 (sys_driver +0x108) s32 PS4_SYSV_ABI LibraryConfigureGlyphStub(void* fontObj, std::uint32_t* in_params, s32 mode, std::uint32_t* inout_state) { if (!fontObj || !in_params || !inout_state) {