Enhance error logging in font metrics functions and update comments for clarity

This commit is contained in:
w1naenator 2026-01-13 17:27:49 +02:00
parent 2113de96f0
commit 0864bafe47
4 changed files with 88 additions and 2 deletions

View File

@ -1968,7 +1968,13 @@ s32 PS4_SYSV_ABI sceFontGetCharGlyphMetrics(OrbisFontHandle fontHandle, u32 code
const s32 rc = Internal::GetCharGlyphMetrics(fontHandle, code, metrics, false);
if (rc != ORBIS_OK) {
LOG_ERROR(Lib_Font, "FAILED");
if (rc == ORBIS_FONT_ERROR_INVALID_FONT_HANDLE) {
LOG_ERROR(Lib_Font, "INVALID_HANDLE");
} else if (rc == ORBIS_FONT_ERROR_INVALID_PARAMETER) {
LOG_ERROR(Lib_Font, "INVALID_PARAMETER");
} else if (rc == ORBIS_FONT_ERROR_NOT_BOUND_RENDERER) {
LOG_ERROR(Lib_Font, "NOT_BOUND_RENDERER");
}
}
return rc;
}
@ -2250,7 +2256,13 @@ s32 PS4_SYSV_ABI sceFontGetRenderCharGlyphMetrics(OrbisFontHandle fontHandle, u3
const s32 rc = Internal::GetCharGlyphMetrics(fontHandle, codepoint, out_metrics, true);
if (rc != ORBIS_OK) {
LOG_ERROR(Lib_Font, "FAILED");
if (rc == ORBIS_FONT_ERROR_INVALID_FONT_HANDLE) {
LOG_ERROR(Lib_Font, "INVALID_HANDLE");
} else if (rc == ORBIS_FONT_ERROR_INVALID_PARAMETER) {
LOG_ERROR(Lib_Font, "INVALID_PARAMETER");
} else if (rc == ORBIS_FONT_ERROR_NOT_BOUND_RENDERER) {
LOG_ERROR(Lib_Font, "NOT_BOUND_RENDERER");
}
}
return rc;
}

View File

@ -30,6 +30,9 @@ struct OrbisFontOpenParams {
const void* reserved_ptr1;
};
// Fontlib APIs use Unicode scalar values (UTF-32 codepoints) in `u32` parameters such as `code` and
// `codepoint`. Codepoint-to-glyph resolution is performed via FreeType charmaps, with additional
// sysfont mapping and fallback behavior handled internally.
struct OrbisFontGlyphMetrics {
float width;
float height;
@ -88,6 +91,8 @@ struct OrbisFontGlyphImageMetrics {
struct OrbisFontGenerateGlyphParams {
u16 id;
u16 res0;
// Bitmask copied into `OrbisFontGlyphOpaque::flags`. Only bits `0x01` and `0x10` are accepted
// by the public API; other bits are rejected as invalid.
u16 form_options;
u8 glyph_form;
u8 metrics_form;
@ -112,6 +117,7 @@ struct OrbisFontGlyphOutline {
struct OrbisFontGlyphOpaque {
u16 magic;
// Encoded flags copied from `OrbisFontGenerateGlyphParams::form_options`.
u16 flags;
u8 glyph_form;
u8 metrics_form;
@ -222,10 +228,17 @@ struct OrbisFontRenderSurface {
struct OrbisFontStyleFrame {
/*0x00*/ u16 magic;
// `flags1` controls which fields are considered valid overrides:
// - bit0: scale override present (scaleUnit/scalePixelW/scalePixelH)
// - bit1: slant override present (slantRatio)
// - bit2: weight override present (effectWeightX/effectWeightY)
/*0x02*/ u8 flags1;
/*0x03*/ u8 flags2;
/*0x04*/ u32 hDpi;
/*0x08*/ u32 vDpi;
// `scaleUnit` selects how scale fields are interpreted:
// - 0: pixel scale (`scalePixelW/scalePixelH`)
// - 1: point scale (converted via DPI by style-state getters)
/*0x0C*/ u32 scaleUnit;
/*0x10*/ float baseScale;
/*0x14*/ float scalePixelW;
@ -235,6 +248,9 @@ struct OrbisFontStyleFrame {
/*0x24*/ float slantRatio;
/*0x28*/ u32 reserved_0x28;
/*0x2C*/ u32 layout_cache_state;
// Packed cache metadata:
// - bits [7:0] cache flags
// - bits [31:16] direction word
/*0x30*/ u32 cache_flags_and_direction;
/*0x34*/ u32 cache_lock_word;
/*0x38*/ u8 layout_cache_bytes[0x20];

View File

@ -200,6 +200,15 @@ struct GlyphEntry {
};
struct FontState {
// `scale_*` fields are controlled by style-state setters and are interpreted according to the
// style frame `scaleUnit` (pixel vs point). Public APIs accept codepoints as UTF-32 scalar
// values; glyph lookup and rendering uses FreeType + deterministic fallback selection.
//
// Fallback behavior (high level):
// - A font handle may have an external face (opened from file/memory) and, optionally, a
// sysfont selection (font_set_type + primary sysfont + additional fallback sysfonts).
// - When a glyph is missing from the primary face, the implementation may consult the external
// face and then the configured system fallback faces to preserve observable behavior.
float scale_w = 16.0f;
float scale_h = 16.0f;
float scale_point_w = 12.0f;

View File

@ -42,6 +42,52 @@ using Libraries::Font::OrbisFontRenderOutput;
using Libraries::Font::OrbisFontRenderSurface;
using Libraries::Font::OrbisFontStyleFrame;
namespace {
struct GetCharGlyphMetricsFailLogState {
u32 count = 0;
bool suppression_logged = false;
};
static thread_local GetCharGlyphMetricsFailLogState g_get_char_metrics_fail;
static void LogGetCharGlyphMetricsFailOnce(std::string_view stage, s32 rc, FT_Error ft_err,
bool is_system, u32 code, FT_UInt glyph_index,
FT_Face face, float scale_w, float scale_h) {
constexpr u32 kMaxDetailedLogs = 16;
if (g_get_char_metrics_fail.count < kMaxDetailedLogs) {
u32 enc = 0;
u16 platform_id = 0;
u16 encoding_id = 0;
u32 num_glyphs = 0;
u32 num_charmaps = 0;
if (face) {
num_glyphs = static_cast<u32>(face->num_glyphs);
num_charmaps = static_cast<u32>(face->num_charmaps);
if (face->charmap) {
enc = static_cast<u32>(face->charmap->encoding);
platform_id = face->charmap->platform_id;
encoding_id = face->charmap->encoding_id;
}
}
LOG_WARNING(
Lib_Font,
"GetCharGlyphMetricsFail: rc={} stage={} ft_err={} is_system={} code={} glyph_index={} "
"num_glyphs={} cmap(enc={},pid={},eid={}) num_charmaps={} scale_w={} scale_h={}",
rc, stage, static_cast<int>(ft_err), is_system, code, glyph_index, num_glyphs, enc,
platform_id, encoding_id, num_charmaps, scale_w, scale_h);
++g_get_char_metrics_fail.count;
return;
}
if (!g_get_char_metrics_fail.suppression_logged) {
LOG_WARNING(Lib_Font, "GetCharGlyphMetricsFail: further failures suppressed");
g_get_char_metrics_fail.suppression_logged = true;
}
}
} // namespace
static void UpdateFtFontObjShiftCache(u8* font_obj) {
if (!font_obj) {
return;
@ -1293,6 +1339,9 @@ s32 GetCharGlyphMetrics(OrbisFontHandle fontHandle, u32 code, OrbisFontGlyphMetr
}
if (resolved_glyph_index == 0) {
LogGetCharGlyphMetricsFailOnce("no_glyph", ORBIS_FONT_ERROR_NO_SUPPORT_GLYPH, 0,
font->open_info.fontset_record != nullptr, code,
resolved_glyph_index, resolved_face, scale_w, scale_h);
if (use_cached_style) {
font->cached_style.cache_lock_word = prev_cached_lock;
}