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.
This commit is contained in:
w1naenator 2026-01-09 13:00:17 +02:00
parent cfe3259999
commit d845b9503d
3 changed files with 637 additions and 226 deletions

View File

@ -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<unsigned
if (path.empty()) {
return false;
}
if (!LoadGuestFileBytes(path, out_bytes) || out_bytes.empty()) {
return false;
auto try_load = [&](const std::filesystem::path& p) -> 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<const TT_OS2*>(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<const TT_OS2*>(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<const TT_VertHeader*>(FT_Get_Sfnt_Table(face, ft_sfnt_vhea));
if (vhea) {
const int units = static_cast<int>(face->units_per_EM);
const int gap = static_cast<int>(os2->sTypoLineGap);
const int shift = 1024 - units - gap;
if (shift > 0 && shift < 128) {
return static_cast<s32>(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<int>(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<int>(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<int>(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<int>(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<u32*>(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<OrbisFontHandle, int> s_baseline_log_counts;
std::lock_guard<std::mutex> 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<const void*>(fontHandle), code, y, baseline_add, y_used,
pre_rc);
++count;
}
}
CachedStyleSetDirectionWord(font->cached_style, 1);

View File

@ -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<u8*>(surf->buffer);
result->SurfaceImage.widthByte = static_cast<u32>(surf->widthByte);
result->SurfaceImage.pixelSizeByte = static_cast<u8>(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<u8*>(surf->buffer);
result->SurfaceImage.widthByte = static_cast<u32>(surf->widthByte);
result->SurfaceImage.pixelSizeByte = static_cast<u8>(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<unsigned char>&
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

View File

@ -3,9 +3,9 @@
#include "core/libraries/font/fontft_internal.h"
#include <bit>
#include <algorithm>
#include <atomic>
#include <bit>
#include <cmath>
#include <cstddef>
#include <cstdint>
@ -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<s64>(obj->shift_units_x);
obj->shift_cache_y = static_cast<s64>(obj->shift_units_y);
const s32 seed_low = static_cast<s32>(static_cast<u32>(obj->layout_seed_pair & 0xFFFFFFFFu));
const s32 seed_low =
static_cast<s32>(static_cast<u32>(obj->layout_seed_pair & 0xFFFFFFFFu));
const s32 seed_high =
static_cast<s32>(static_cast<u32>((obj->layout_seed_pair >> 32) & 0xFFFFFFFFu));
obj->layout_seed_vec[0] = static_cast<std::uint64_t>(static_cast<std::int64_t>(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<u32>(glyph_index - 0x23d1U) < 0x5e)) &&
((0x5c0000000017ULL >>
(static_cast<u64>(static_cast<u8>((static_cast<u8>(glyph_index - 0x23d1U) >> 1) & 0x3f)) &
0x3fULL)) &
(static_cast<u64>(
static_cast<u8>((static_cast<u8>(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<FontLibOpaque*>(selector->library);
auto* ctx = lib ? static_cast<u8*>(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<FontCtxEntry*>(entry_u8) : nullptr;
auto* node = static_cast<FontObj*>(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<FT_Face>(node->ft_face) : nullptr;
const bool ok = face && (FT_Get_Char_Index(face, static_cast<FT_ULong>(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<FT_ULong>(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<std::uintptr_t>(out_words) & (alignof(HorizontalLayoutBlocks) - 1)) ==
0) {
if ((reinterpret_cast<std::uintptr_t>(out_words) & (alignof(HorizontalLayoutBlocks) - 1)) == 0) {
auto* out_blocks = reinterpret_cast<HorizontalLayoutBlocks*>(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<const FontSetRecordHeader*>(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<u8*>(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<std::uintptr_t>(out_words) & (alignof(VerticalLayoutBlocks) - 1)) ==
0) {
if ((reinterpret_cast<std::uintptr_t>(out_words) & (alignof(VerticalLayoutBlocks) - 1)) == 0) {
auto* out_blocks = reinterpret_cast<VerticalLayoutBlocks*>(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<const RenderSurfaceSystemUse*>(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<u8*>(surf->buffer);
result->SurfaceImage.widthByte = static_cast<u32>(surf->widthByte);
result->SurfaceImage.pixelSizeByte = static_cast<u8>(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<float>(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<Libraries::Font::OrbisFontHandle, int> 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<const void*>(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<StyleStateBlock*>(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<StyleStateBlock*>(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<const StyleStateBlock*>(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<const StyleStateBlock*>(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<StyleStateBlock*>(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<const StyleStateBlock*>(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<StyleStateBlock*>(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<std::uintptr_t>(weightXScale) |
@ -2484,7 +2487,8 @@ static bool ResolveSfntBaseOffset(const u8* data, std::size_t size, u32 subFontI
return false;
}
const u32 base = static_cast<const BeU32*>(static_cast<const void*>(data + want_off))->value();
const u32 base =
static_cast<const BeU32*>(static_cast<const void*>(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<const BeU16*>(static_cast<const void*>(data + head_off + 0x12))->value();
out_units = static_cast<const BeU16*>(static_cast<const void*>(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<FT_F26Dot6>(static_cast<s32>(scale_x * 64.0f));
const auto char_h = static_cast<FT_F26Dot6>(static_cast<s32>(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<const TT_HoriHeader*>(FT_Get_Sfnt_Table(face, ft_sfnt_hhea))) {
const s64 caret_rise_units = x_shift + static_cast<s64>(hhea->caret_Slope_Rise);
const s64 caret_rise_units =
x_shift + static_cast<s64>(hhea->caret_Slope_Rise);
const s32 caret_rise_px = trunc_fixed_16_16_to_int(caret_rise_units * x_scale);
hhea_out = static_cast<float>(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<s32>(static_cast<u32>(obj->layout_seed_pair & 0xFFFFFFFFu));
const s32 seed_low = static_cast<s32>(static_cast<u32>(obj->layout_seed_pair & 0xFFFFFFFFu));
const s32 seed_high =
static_cast<s32>(static_cast<u32>((obj->layout_seed_pair >> 32) & 0xFFFFFFFFu));
obj->layout_seed_vec[0] = static_cast<u64>(static_cast<s64>(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) {