feat(libSceFreeType): expose glyph-to-script maps

This commit is contained in:
Zain committed 2026-10-28 20:42:06 -05:00
1 parent 3a2b919816
commit 1ca278f05a
3 files changed
+62 -2

No files matched your search

@@ -3,7 +3,9 @@
#include "prx/libc/include/General.hpp"
#include FT_MODULE_H
#include FT_DRIVER_H
#include <cstddef>
#include <cstdint>
#include <cstring>
@@ -16,7 +18,7 @@ static_assert(sizeof(FT_Bool) == sizeof(std::uint8_t));
namespace {
enum class PropertyType { Unsigned, Signed, Boolean, Darkening, Unsupported };
enum class PropertyType { Unsigned, Signed, Boolean, Darkening, GlyphToScriptMap, Unsupported };
using DarkeningParameters = FT_Int[8];
PropertyType TypeOf(const char* moduleName, const char* propertyName) {
@@ -32,6 +34,7 @@ PropertyType TypeOf(const char* moduleName, const char* propertyName) {
if (std::strcmp(propertyName, "no-stem-darkening") == 0) return PropertyType::Boolean;
if (std::strcmp(propertyName, "darkening-parameters") == 0) return PropertyType::Darkening;
}
if (autoHinter && std::strcmp(propertyName, "glyph-to-script-map") == 0) return PropertyType::GlyphToScriptMap;
if (autoHinter && (std::strcmp(propertyName, "fallback-script") == 0 ||
std::strcmp(propertyName, "default-script") == 0)) {
return PropertyType::Unsigned;
@@ -39,6 +42,21 @@ PropertyType TypeOf(const char* moduleName, const char* propertyName) {
return PropertyType::Unsupported;
}
struct GuestGlyphToScriptMap {
GuestFaceRec* face;
std::uint16_t* map;
};
int ReadGlyphToScriptMap(FT_Library library, const char* moduleName, const char* propertyName, void* output) {
GuestFaceRec* face = nullptr;
std::memcpy(&face, output, sizeof(face));
const GuestFace* owner = FaceOf(face);
FT_Prop_GlyphToScriptMap property{owner ? owner->host : nullptr, nullptr};
const int error = FT_Property_Get(library, moduleName, propertyName, &property);
if (!error) std::memcpy(static_cast<char*>(output) + offsetof(GuestGlyphToScriptMap, map), &property.map, sizeof(property.map));
return error;
}
template <typename TValue>
int Read(FT_Library library, const char* moduleName, const char* propertyName, void* output) {
TValue value{};
@@ -65,6 +83,7 @@ extern "C" int APS5_VABI FT_Property_Get_nid_postfix(GuestLibrary* library, cons
case PropertyType::Signed: return Read<FT_Int32>(host, moduleName, propertyName, value);
case PropertyType::Boolean: return Read<FT_Bool>(host, moduleName, propertyName, value);
case PropertyType::Darkening: return Read<DarkeningParameters>(host, moduleName, propertyName, value);
case PropertyType::GlyphToScriptMap: return ReadGlyphToScriptMap(host, moduleName, propertyName, value);
default: NotImplemented_nid_no_patch(__func__);
}
}
@@ -78,6 +97,10 @@ extern "C" int APS5_VABI FT_Property_Set_nid_postfix(GuestLibrary* library, cons
case PropertyType::Signed: return Write<FT_Int32>(host, moduleName, propertyName, value);
case PropertyType::Boolean: return Write<FT_Bool>(host, moduleName, propertyName, value);
case PropertyType::Darkening: return Write<DarkeningParameters>(host, moduleName, propertyName, value);
case PropertyType::GlyphToScriptMap: {
FT_Prop_GlyphToScriptMap property{};
return FT_Property_Set(host, moduleName, propertyName, &property);
}
default: NotImplemented_nid_no_patch(__func__);
}
}
+36
View File
@@ -11,6 +11,8 @@
#include FT_CID_H
#include FT_SIZES_H
#include FT_SYSTEM_H
#include FT_MODULE_H
#include FT_DRIVER_H
#include <algorithm>
#include <array>
@@ -1483,7 +1485,41 @@ static void SizeObjects(const std::vector<unsigned char>& font) {
std::printf("FreeType size objects: %d lifecycles, %d rendered glyphs, %d allocation failures compared with native\n", scenarios, rendered, failures);
}
static void CheckGlyphToScriptMap() {
const auto font = SquareGlyphFont('A', 700);
GuestLibrary* library = nullptr;
GuestFaceRec* face = nullptr;
FT_Library nativeLibrary = nullptr;
FT_Face nativeFace = nullptr;
Require(FT_Init_FreeType_nid_postfix(&library) == 0 && FT_Init_FreeType(&nativeLibrary) == 0);
Require(FT_New_Memory_Face_nid_postfix(library, font.data(), font.size(), 0, &face) == 0);
Require(FT_New_Memory_Face(nativeLibrary, font.data(), static_cast<FT_Long>(font.size()), 0, &nativeFace) == 0);
struct GuestMap { GuestFaceRec* face; std::uint16_t* map; };
GuestMap guest{face, nullptr};
FT_Prop_GlyphToScriptMap expected{nativeFace, nullptr};
const int nativeResult = FT_Property_Get(nativeLibrary, "autofitter", "glyph-to-script-map", &expected);
Require(FT_Property_Get_nid_postfix(library, "autofitter", "glyph-to-script-map", &guest) == nativeResult);
Require(nativeResult == 0 && guest.face == face && guest.map && expected.map);
Require(std::equal(guest.map, guest.map + face->num_glyphs, expected.map));
std::array<unsigned char, sizeof(GuestMap) + 1> storage{};
GuestMap unaligned{face, nullptr};
std::memcpy(storage.data() + 1, &unaligned, sizeof(unaligned));
Require(FT_Property_Get_nid_postfix(library, "autofitter", "glyph-to-script-map", storage.data() + 1) == 0);
std::memcpy(&unaligned, storage.data() + 1, sizeof(unaligned));
Require(unaligned.face == face && unaligned.map == guest.map);
Require(FT_Property_Set_nid_postfix(library, "autofitter", "glyph-to-script-map", &guest) ==
FT_Property_Set(nativeLibrary, "autofitter", "glyph-to-script-map", &expected));
GuestMap invalid{nullptr, reinterpret_cast<std::uint16_t*>(1)};
FT_Prop_GlyphToScriptMap nativeInvalid{nullptr, reinterpret_cast<FT_UShort*>(1)};
Require(FT_Property_Get_nid_postfix(library, "autofitter", "glyph-to-script-map", &invalid) ==
FT_Property_Get(nativeLibrary, "autofitter", "glyph-to-script-map", &nativeInvalid));
Require(invalid.map == reinterpret_cast<std::uint16_t*>(1));
Require(FT_Done_Face_nid_postfix(face) == 0 && FT_Done_Face(nativeFace) == 0);
Require(FT_Done_FreeType_nid_postfix(library) == 0 && FT_Done_FreeType(nativeLibrary) == 0);
}
int main() {
CheckGlyphToScriptMap();
SizeObjects(SquareGlyphFont('A', 700));
{
const auto referenceFont = SquareGlyphFont('A', 700);
+2 -1
View File
@@ -41,7 +41,8 @@
- [FT_Get_Charmap_Index, FT_Get_CMap_Language_ID, FT_Get_CMap_Format](../../../core/libs/prx/libSceFreeType/src/Charmap.cpp) (libSceFreeType) - console signatures and return values are unverified; the adapter follows bundled [FreeType 2.13.3](https://github.com/freetype/freetype/blob/42608f77f20749dd6ddc9e0536788eaad70ea4b5/src/base/ftobjs.c) and the existing guest LP64 model. Charmaps must be the face's original read-only guest records; copied or otherwise unregistered records with a non-null face throw instead of reading private native cmap fields from guest memory
- [FT_Property_Get, FT_Property_Set](../../../core/libs/prx/libSceFreeType/src/ModuleProperties.cpp) - console signatures, property availability and backend/error equivalence are unverified. Only `truetype/interpreter-version`, the `cff`, `type1` and `t1cid` hinting-engine, random-seed, no-stem-darkening and darkening-parameters properties, and the autofitter fallback-script, default-script, no-stem-darkening and darkening-parameters properties follow bundled FreeType 2.13.3. Other module/property pairs throw, including properties carrying face pointers or callbacks. Values use 32-bit signed/unsigned integers, one-byte booleans or eight 32-bit darkening parameters; getters copy only successful native results.
- [FT_Property_Get, FT_Property_Set](../../../core/libs/prx/libSceFreeType/src/ModuleProperties.cpp) - console signatures, property availability and backend/error equivalence are unverified. Only `truetype/interpreter-version`, the `cff`, `type1` and `t1cid` hinting-engine, random-seed, no-stem-darkening and darkening-parameters properties, and the autofitter fallback-script, default-script, no-stem-darkening and darkening-parameters properties follow bundled FreeType 2.13.3. Other module/property pairs throw, including unsupported properties carrying face pointers or callbacks. Values use 32-bit signed/unsigned integers, one-byte booleans or eight 32-bit darkening parameters; getters copy only successful native results.
- [autofitter glyph-to-script-map](../../../core/libs/prx/libSceFreeType/src/ModuleProperties.cpp) assumes the FreeType LP64 face/map carrier and translates the guest face to its host face. The returned 16-bit map borrows host face storage and is valid only while that face is alive; the setter returns the bundled FreeType error. Console ABI, glyph classification and firmware behavior are unverified.
- [FT_Outline_Reverse, FT_Outline_Translate](../../../core/libs/prx/libSceFreeType/src/Outline.cpp) (libSceFreeType) - console signatures, count signedness and overflow behavior are unverified; the adapter follows bundled [FreeType 2.13.3](https://github.com/freetype/freetype/blob/42608f77f20749dd6ddc9e0536788eaad70ea4b5/src/base/ftoutln.c) with LP64 coordinates. Translation uses 64-bit modular addition to match that build's `ADD_LONG`; reversal preserves each contour's first point and toggles the reverse-fill flag. Coordinates outside the host `FT_Pos` range still throw if the modified outline is later rendered on Windows