Files
AnyPS5/docs/dev/debt/libSceFont.md
T
2026-10-30 11:56:59 +01:00

27 KiB

libSceFont technical debt

Unknown function info

  • sceFontRenderCharGlyphImage, sceFontRenderCharGlyphImageHorizontal, sceFontRenderCharGlyphImageVertical (libSceFont) accept a surface whose width or height is 0, with any row stride, and return the glyph metrics and an empty update rectangle without writing to the surface. A negative width, height or stride, a zero stride on a surface with pixels, a null buffer and a pixel size other than 1 or 4 bytes still return SCE_FONT_ERROR_NO_SUPPORT_SURFACE; those cases and the exact console result for a zero-extent surface are not measured. The extent-0 behaviour is inferred from the Tekken Dark Resurrection PSP emulator which, to measure a string, initialises the surface with width 0 and height 31 and an unbound stride, renders each character and sums the returned advances.

The 44 additional exports below have unknown signatures and behavior. Their parameterless int declarations are import-resolution placeholders, not confirmed ABI signatures; every call throws through NotImplemented_nid_no_patch. Only names and NIDs are established by the 13.60 export inventory. They have not been measured on a console.

Functional

  • sceFontOpenFontSet (libSceFont) - the other script files of a set and their priority are inferred, not measured on a console: Vietnamese for low-byte bit 0x10, Thai for script bit 0x10, Japanese for 0x04, simplified Chinese for 0x80 (before Japanese with 0x08), Hangul for 0x20 and Arabic for low-byte bit 0x80. The SDK set names (..._JP_AR, ..._GBCJK_TH) and Hangul aliases (SCEPS4Yoongd-Light.otf, SCEPS4Yoongd-Medium.otf, SCEPS4Yoongd-Bold.otf) come from shadPS4; the Vietnamese bit rule and the priority used here are our inferences, not its fallback implementation. A character the primary file lacks is taken from the first of them that has it; kerning between two files is 0, and sceFontGetCharGlyphCode and sceFontGetFontGlyphsCount answer for the primary file only

  • sceFontOpenFontSet (libSceFont) - the console file names are those of the PS4 firmware; the names of the PS5-only JG2 sets (0x1A......) are unknown, so they use the SSTJpPro files. When a console file is missing, an openly licensed substitute (Noto Sans, Noto Sans Mono, Noto Sans Thai, Noto Sans Arabic, Noto Sans CJK with its Korean face for Hangul) is loaded instead; its metrics differ, so text width, line height and wrapping differ from the console. System font faces are loaded by FreeType in host memory, not in the font memory the title passes to the library: FreeType needs about 1 MiB per CJK face, which the title's font memory is not sized for.

  • sceFontGetCharGlyphMetrics, sceFontGetRenderCharGlyphMetrics (libSceFont) report the vertical metrics the way the FreeType driver reports them for a rendered glyph, not confirmed on a title: FreeType's vertical advance, and for a face without vertical metrics a bearing of half the horizontal advance left of the horizontal bearing and of half the advance left over by the glyph height.

  • sceFontGetFontMetrics (libSceFont) - the 64-byte output, the form fallbacks (2 and 3 fall back to the hhea values when OS/2 is missing or gives an empty range, 4 builds vertical values from vhea or OS/2) and the raw weight deltas and slant copied from the style are not measured on a console. For a font set the values are those of its primary file; which file the console reports is not recovered. Closes when: measured on a PS5

  • sceFontGetFontStyleInformation (libSceFont) - the 24-byte output (FreeType family and style names, italic and bold flags, OS/2 weight class when it is a multiple of 100 from 100 to 900, width class below 10, and 1 plus a right-to-left head direction plus 0x80 for vertical metrics) and the font-set record path are not measured on a console. A face without a head table, such as a BDF font, throws, as its console result is unknown. Closes when: measured on a PS5

  • sceFontGetFontGlyphsOutlineProfile (libSceFont) - the 16-byte output (the maxp maximum contours, points, composite contours and composite points) and SCE_FONT_ERROR_NO_SUPPORT_FUNCTION for a maxp older than 1.0 are not measured on a console. A handle with a font-set record throws, as the maximum over the record's system font entries is not modelled. A face without a maxp table throws, as its console result is unknown. Closes when: measured on a PS5

  • sceFontWritingRefersRenderStep and sceFontWritingRefersRenderStepCharacter on a writing whose string was destroyed: what the console returns there and on a second destroy, and where it allocates a string's characters, is not measured. Here sceFontCreateString allocates the characters through the string's FontMemory, as it does the string, and sceFontDestroyString clears the string's magic and frees both. A writing keeps only a pointer to its string and checks the magic on each step, so both calls return null after the destroy unless that memory holds the magic again, as when a new string is allocated there. A second destroy through another copy of the handle returns SCE_FONT_ERROR_INVALID_STRING unless the magic is back. Character pointers taken from the string then point into freed guest memory. Closes when: measured on a PS5

  • Font writing lines: visual ordering and spacing originated from PS4 measurements and match the supplied PS5 structure and control flow. Exhaustive floating-point equivalence, including NaN payloads and rounding, has not been verified against a running PS5 module.

  • Font graphics and metric signatures: graphics-device/service creation takes font memory, parameters and a handle output; destruction takes a handle pointer. Attribute selectors and outputs are 32-bit values. Expansion-buffer outputs remain opaque pending field recovery. Protected implementations are unchanged.

  • Font graphics fill descriptors: the region, fill-method, fill-plot and fill-rates initialisers and setters, and sceFontSetGraphicsErrorCallback, follow firmware 13.60 libSceFont.sprx (read from disassembly, not measured on a console): argument checks in the same order, error codes, tags and the bytes written. What the layout selectors, mapping values, region corner flags and fill effects mean is unknown, because the calls that read these descriptors (sceFontGraphicsSetup*, sceFontGraphicsUpdate*) still throw. The error codes 0x80460086 to 0x80460089 have no public names; the source names them after the argument they reject

Frame lifecycle, drawing completion, device usage, frame policy, clipping and fill setup/update argument signatures in Unimplemented.cpp are recovered. Frame and resource layouts remain opaque; their runtime implementation is still unavailable.

Positioning takes a mask and two floats. Control, word-character search and resource release/exchange/render signatures in Unimplemented.cpp are recovered; control payload types depend on the command and remain unmodeled.

Canvas, design and surface texture construction signatures in Unimplemented.cpp are recovered. For the two drawup texture producers, the ABI described above places four pointer/integer arguments in integer registers and the rectangle in XMM0-XMM3; the former pattern declaration incorrectly passed the rectangle through integer registers. The PPSA20397 caller reads the mode from an 8-bit field at +0xf; the handling of the upper 24 bits of the ABI parameter has not been measured. Texture pattern payload semantics and graphics surface descriptor fields still require reconstruction; distinct opaque types preserve confirmed object categories.

Unimplemented.cpp now defines the 32-byte fill method, 64-byte fill plot/rates and 96-byte device usage layouts, with size and field-offset assertions. Uninterpreted descriptor tails remain reserved; pool statistics expose capacity, current usage, available bytes, peak and signed change.

The glyph support registration and drawup texture signatures are recovered from native argument use. The drawup texture producers consume an opaque fill-object pointer, a mode, an output pointer and four rectangle floats; they still throw because their queue, pool and renderer operations are not implemented. CreateWords and CreateGraphicsServiceWithEdition consume the output pointer in the fourth general-purpose argument slot but do not read the third slot, whose source type is not established.

  • sceFontCreateGraphicsServiceWithEdition and sceFontCreateWords take their handle output in the fourth integer argument slot. The third slot is not read by the supplied module and is represented as an opaque 64-bit value; its declared source type remains unknown.
  • Word dictionaries: building, depth limit, sort and error rules and longest-match selection are read from disassembly, not measured on a console. The text source is parsed once instead of twice. More than 65535 nodes return SCE_FONT_ERROR_FUNCTIONAL_LIMIT, where the native 16-bit indices would wrap. The shape-entry test on the next character is skipped since strings built here have no shape entry. The low flag byte and flag bits 43-45 are tested as read; strings built here leave them clear, so names are ours.
  • Font writing steps (libSceFont) - every supported writing form (0x10, 0x11, 0x12) is horizontal, so a writing step's advanceY and the pen's vertical movement are zero and the step's GlyphMetrics keep the glyph's own width and height. This follows steps measured on PS4 11.00 firmware ("Ab c": y stays 0, advanceY is 0 on every step), not shadPS4's FillWritingMetricsFromGlyph, which copies the vertical advance. The drift came from advancing the pen by the vertical advance, not from the value of that advance: it stays reported by sceFontGetCharGlyphMetrics and its FreeType source is still unconfirmed on a title (see the metrics entry above). The step's width/height are not measured on the PS4 firmware; they keep the glyph's values.