feat(font): keep a handle's script languages and typographic features

sceFontSetScriptLanguage, sceFontGetScriptLanguage,
sceFontSetTypographicDesign and sceFontGetTypographicDesign threw. With
the signatures SharpProspero declares, a font handle now keeps the
language set for each script and the feature set for each typographic
design, under the handle's lock, and returns them, with 0 for one never
set. They do not change shaping or rendering yet; TechnicalDebt records
the assumptions.

Claude-Session: https://claude.ai/code/session_012SLQbhAiexxW6TtjYToW8a
(cherry picked from commit c4dcbe4403dc635fde2a823dec311a939816cefc)
This commit is contained in:
Abdulrahman Elkordy 2026-10-11 01:38:32 +03:00 committed by Adrià Franch
parent 64baa79b65
commit 5ea89c7d4c
5 changed files with 59 additions and 20 deletions

View File

@ -7,6 +7,7 @@
#include <cstddef>
#include <cstdint>
#include <filesystem>
#include <map>
#include <memory>
#include <optional>
#include <vector>
@ -28,6 +29,8 @@ struct FontState {
FT_Face face = nullptr;
float scaleW = 16.0f;
float scaleH = 16.0f;
std::map<int, int> scriptLanguages;
std::map<int, int> typographicFeatures;
FontState() = default;
FontState(const FontState&) = delete;

View File

@ -51,6 +51,30 @@ int ReadFontStyle(FontHandle fontHandle, bool checkMagic, Getter&& getter) {
return rc;
}
template<typename Access>
int AccessFontSettings(FontHandle fontHandle, Access&& access) {
return ReadFontStyle(fontHandle, true, [&](FontHandleNative*) {
FontState* state = TryGetState(fontHandle);
return state ? access(*state) : SCE_FONT_ERROR_INVALID_FONT_HANDLE;
});
}
int SetFontSetting(FontHandle fontHandle, std::map<int, int> FontState::*table, int key, int value) {
return AccessFontSettings(fontHandle, [&](FontState& state) {
(state.*table)[key] = value;
return SCE_FONT_OK;
});
}
int GetFontSetting(FontHandle fontHandle, std::map<int, int> FontState::*table, int key, int* value) {
if (!value) return SCE_FONT_ERROR_INVALID_PARAMETER;
return AccessFontSettings(fontHandle, [&](FontState& state) {
const auto found = (state.*table).find(key);
*value = found == (state.*table).end() ? 0 : found->second;
return SCE_FONT_OK;
});
}
void ResetScaleOutputs(float* w, float* h) {
if (w) *w = 0.0f;
if (h) *h = 0.0f;
@ -77,6 +101,22 @@ float ClampWeightDelta(float scale) {
extern "C" {
int APS5_VABI sceFontSetScriptLanguage(FontHandle fontHandle, int fontScript, int fontLanguage) {
return SetFontSetting(fontHandle, &FontState::scriptLanguages, fontScript, fontLanguage);
}
int APS5_VABI sceFontGetScriptLanguage(FontHandle fontHandle, int fontScript, int* fontLanguage) {
return GetFontSetting(fontHandle, &FontState::scriptLanguages, fontScript, fontLanguage);
}
int APS5_VABI sceFontSetTypographicDesign(FontHandle fontHandle, int typographic, int feature) {
return SetFontSetting(fontHandle, &FontState::typographicFeatures, typographic, feature);
}
int APS5_VABI sceFontGetTypographicDesign(FontHandle fontHandle, int typographic, int* feature) {
return GetFontSetting(fontHandle, &FontState::typographicFeatures, typographic, feature);
}
int APS5_VABI sceFontSetScalePixel(FontHandle fontHandle, float w, float h) {
return UpdateFontStyle(fontHandle, [&](FontHandleNative* font) {
const int changed = StyleStateSetScalePixel(&font->style, w, h);

View File

@ -88,16 +88,6 @@ int APS5_VABI sceFontGetGlyphExpandBufferState() {
return 0;
}
int APS5_VABI sceFontGetScriptLanguage() {
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI sceFontGetTypographicDesign() {
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI sceFontGlyphGetAttribute() {
NotImplemented_nid_no_patch(__func__);
return 0;
@ -368,16 +358,6 @@ int APS5_VABI sceFontGraphicsUpdateShapeFillPlot() {
return 0;
}
int APS5_VABI sceFontSetScriptLanguage() {
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI sceFontSetTypographicDesign() {
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI sceFontSupportGlyphs() {
NotImplemented_nid_no_patch(__func__);
return 0;

View File

@ -26,6 +26,10 @@ int APS5_VABI sceFontSupportExternalFonts(FontLibrary, std::uint32_t, std::uint3
int APS5_VABI sceFontOpenFontSet(FontLibrary, std::uint32_t, std::uint32_t, const FontOpenDetail*, FontHandle*);
int APS5_VABI sceFontOpenFontMemory(FontLibrary, const void*, std::uint32_t, const FontOpenDetail*, FontHandle*);
int APS5_VABI sceFontCloseFont(FontHandle);
int APS5_VABI sceFontSetScriptLanguage(FontHandle, int, int);
int APS5_VABI sceFontGetScriptLanguage(FontHandle, int, int*);
int APS5_VABI sceFontSetTypographicDesign(FontHandle, int, int);
int APS5_VABI sceFontGetTypographicDesign(FontHandle, int, int*);
int APS5_VABI sceFontSetResolutionDpi(FontHandle, std::uint32_t, std::uint32_t);
int APS5_VABI sceFontGetResolutionDpi(FontHandle, std::uint32_t*, std::uint32_t*);
int APS5_VABI sceFontSetScalePixel(FontHandle, float, float);
@ -203,6 +207,17 @@ int main() {
const std::vector<unsigned char> fontData = EmptyGlyphFont();
Require(sceFontOpenFontMemory(library, fontData.data(), static_cast<std::uint32_t>(fontData.size()), nullptr, &font) == SCE_FONT_OK && font != nullptr);
int setting = -1;
Require(sceFontGetScriptLanguage(font, 3, &setting) == SCE_FONT_OK && setting == 0);
Require(sceFontSetScriptLanguage(font, 3, 7) == SCE_FONT_OK && sceFontSetScriptLanguage(font, 4, 9) == SCE_FONT_OK);
Require(sceFontGetScriptLanguage(font, 3, &setting) == SCE_FONT_OK && setting == 7);
Require(sceFontGetScriptLanguage(font, 4, &setting) == SCE_FONT_OK && setting == 9);
Require(sceFontGetScriptLanguage(font, 3, nullptr) == SCE_FONT_ERROR_INVALID_PARAMETER);
Require(sceFontSetScriptLanguage(nullptr, 3, 7) == SCE_FONT_ERROR_INVALID_FONT_HANDLE);
Require(sceFontSetTypographicDesign(font, 1, 2) == SCE_FONT_OK);
Require(sceFontGetTypographicDesign(font, 1, &setting) == SCE_FONT_OK && setting == 2);
Require(sceFontGetTypographicDesign(font, 5, &setting) == SCE_FONT_OK && setting == 0);
Require(sceFontGetTypographicDesign(nullptr, 1, &setting) == SCE_FONT_ERROR_INVALID_FONT_HANDLE);
std::uint32_t hDpi = 1;
std::uint32_t vDpi = 1;
Require(sceFontGetResolutionDpi(font, &hDpi, &vDpi) == SCE_FONT_OK && hDpi == 72 && vDpi == 72);

View File

@ -39,6 +39,7 @@ Throughout the project, every function at every stage either **does exactly what
- [ulobjmgr](../../core/libs/prx/ulobjmgr/Export.cpp) registers no object: `_sceUlobjmgrRegisterObject` always hands out id 0 and `_sceUlobjmgrUnregisterObject` releases nothing, as shadPS4 does
- [libSceHttp](../../core/libs/prx/libSceHttp/Export.cpp) - no request reaches the network, so `sceHttpSetResponseHeaderMaxSize` has no response header to limit, `sceHttpSetRecvBlockSize` (`(int id, u32 blockSize)` as in [shadPS4](https://github.com/shadps4-emu/shadPS4/blob/main/src/core/libraries/network/http.h)) no response body to read in blocks and `sceHttpRedirectCacheFlush` no redirect to forget; `sceHttpsUnloadCert` returns success like `sceHttpsLoadCert`, which keeps no certificate; `sceHttpSetRedirectCallback` and `sceHttpSetCookieRecvCallback` accept callbacks that are never called, `sceHttpsSetSslVersion` has no TLS connection to configure and `sceHttpsGetSslError` reports error 0 with detail 0; `sceHttpSetAuthInfoCallback` accepts a callback that is never called, as no server asks for authentication
- [sceFontGlyphDefineAttribute](../../core/libs/prx/libSceFont/src/Render.cpp) (libSceFont) checks the glyph and ignores the attribute and its value, whose meaning is unknown. PPSA01325 sets attribute 0x11 to 0 on a glyph from `sceFontGenerateCharGlyph` that it deletes unused, and draws the character with `sceFontRenderCharGlyphImageHorizontal`
- [sceFontSetScriptLanguage, sceFontGetScriptLanguage, sceFontSetTypographicDesign, sceFontGetTypographicDesign](../../core/libs/prx/libSceFont/src/Style.cpp) (libSceFont) - signatures follow [SharpProspero](https://github.com/SvenGDK/SharpProspero/blob/main/src/SharpProspero/Interop/Font/SceFont.cs), not confirmed for the PS5. The handle keeps the language set for each script and the feature set for each typographic design and returns them, with 0 for one never set; the console default and its valid ranges are unknown, so any value is accepted. Neither setting changes shaping or rendering yet
### Unknown function info