#include "prx/libSceFont/include/FontDriver.hpp" #include "tests/FontFixture.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include extern "C" { int APS5_VABI sceFontMemoryInit(FontMemory*, void*, std::uint32_t, const FontMemoryInterface*, void*, FontMemoryDestroyFunction, void*); int APS5_VABI sceFontMemoryTerm(FontMemory*); int APS5_VABI sceFontCreateLibrary(const FontMemory*, const void*, FontLibrary*); int APS5_VABI sceFontDestroyLibrary(FontLibrary*); int APS5_VABI sceFontCreateRenderer(const FontMemory*, const void*, FontRenderer*); int APS5_VABI sceFontDestroyRenderer(FontRenderer*); int APS5_VABI sceFontGetPixelResolution(FontLibrary, std::uint32_t*); int APS5_VABI sceFontAttachDeviceCacheBuffer(FontLibrary, void*, std::uint32_t); int APS5_VABI sceFontClearDeviceCache(FontLibrary); int APS5_VABI sceFontDettachDeviceCacheBuffer(FontLibrary, void**, std::uint32_t*); int APS5_VABI sceFontSupportSystemFonts(FontLibrary); int APS5_VABI sceFontSupportExternalFonts(FontLibrary, std::uint32_t, std::uint32_t); 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 sceFontOpenFontFile(FontLibrary, const char*, 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 sceFontDefineAttribute(FontHandle, int, int*); int APS5_VABI sceFontGetAttribute(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); int APS5_VABI sceFontBindRenderer(FontHandle, FontRenderer); int APS5_VABI sceFontUnbindRenderer(FontHandle); int APS5_VABI sceFontSetupRenderScalePixel(FontHandle, float, float); int APS5_VABI sceFontSetupRenderScalePoint(FontHandle, float, float); int APS5_VABI sceFontGetKerning(FontHandle, std::uint32_t, std::uint32_t, FontKerning*); int APS5_VABI sceFontGetFontGlyphsCount(FontHandle, std::uint32_t*); int APS5_VABI sceFontGetCharGlyphCode(FontHandle, std::uint32_t, std::uint32_t*); int APS5_VABI sceFontGetFontResolution(FontHandle, std::uint32_t*, float*); int APS5_VABI sceFontGetRenderScaledKerning(FontHandle, std::uint32_t, std::uint32_t, FontKerning*); int APS5_VABI sceFontGenerateCharGlyph(FontHandle, std::uint32_t, const FontGenerateGlyphDetail*, FontGlyph*); int APS5_VABI sceFontGlyphDefineAttribute(FontGlyph, std::int32_t, std::int32_t*); int APS5_VABI sceFontGlyphGetAttribute(FontGlyph, int, int*); int APS5_VABI sceFontDeleteGlyph(const FontMemory*, FontGlyph*); int APS5_VABI sceFontTextSourceInit(FontTextSource*, const void*, std::uint32_t, FontTextParseFunction, void*); int APS5_VABI sceFontCreateString(const FontMemory*, FontTextSource*, const FontCreateStringDetail*, FontString*); int APS5_VABI sceFontDestroyString(FontString*); FontTextCharacter* APS5_VABI sceFontStringRefersTextCharacters(FontString, std::uint32_t*); int APS5_VABI sceFontWritingInit(FontWriting*, FontString, const FontTextCharacter*); const FontWritingStep* APS5_VABI sceFontWritingRefersRenderStep(FontWriting*); FontTextCharacter* APS5_VABI sceFontWritingRefersRenderStepCharacter(FontWriting*, const FontWritingLetterStep**); const void* APS5_VABI sceFontSelectLibraryFt(int); const void* APS5_VABI sceFontSelectRendererFt(int); int APS5_VABI sceFontFtSupportBdf(FontLibrary library); int APS5_VABI sceFontFtSupportCid(FontLibrary library); int APS5_VABI sceFontFtSupportOpenType(FontLibrary library); int APS5_VABI sceFontFtSupportOpenTypeOtf(FontLibrary library); int APS5_VABI sceFontFtSupportOpenTypeTtf(FontLibrary library); int APS5_VABI sceFontFtSupportPcf(FontLibrary library); int APS5_VABI sceFontFtSupportPfr(FontLibrary library); int APS5_VABI sceFontFtSupportTrueType(FontLibrary library); int APS5_VABI sceFontFtSupportType1(FontLibrary library); int APS5_VABI sceFontFtSupportType42(FontLibrary library); int APS5_VABI sceFontFtSupportWinFonts(FontLibrary library); int APS5_VABI sceFontCharacterGetSyllableStringState(const FontTextCharacter*, int*); FontTextCodes* APS5_VABI sceFontCharactersRefersTextCodes(const FontTextCharacter*, const FontTextCharacter*, FontTextCodes*); FontTextCodes* APS5_VABI sceFontTextCodesStepNext(FontTextCodes*); FontTextCodes* APS5_VABI sceFontTextCodesStepBack(FontTextCodes*); } static void Check(bool value, int line) { if (!value) { std::fprintf(stderr, "Font check failed at line %d\n", line); std::abort(); } } #define Require(value) Check((value), __LINE__) static void SetFontDirectory(const std::filesystem::path& directory) { #ifdef _WIN32 Require(_putenv_s("ANYPS5_SYSTEM_FONTS", directory.string().c_str()) == 0); #else Require(::setenv("ANYPS5_SYSTEM_FONTS", directory.string().c_str(), 1) == 0); #endif } static int allocations = 0; static void* APS5_VABI Allocate(void*, std::uint32_t size) { ++allocations; return std::malloc(size); } static void APS5_VABI Release(void*, void* pointer) { if (pointer) --allocations; std::free(pointer); } static std::uint32_t APS5_VABI CoarsePixelResolution() { return 16; } static int APS5_VABI WideFontResolution(Font::FontObj*, std::uint32_t* resolution, float* scale) { *resolution = 0x12345678; *scale = 12.5f; return SCE_FONT_OK; } using FontFixture::BuildFont; using FontFixture::Words; static std::vector EmptyGlyphFont() { return BuildFont(1, {}); } static std::vector KerningFont() { return BuildFont(3, { {"cmap", Words({0, 1, 3, 1, 0, 12, 4, 40, 0, 6, 4, 1, 2, 'A', 'V', 0xFFFF, 0, 'A', 'V', 0xFFFF, 1 - 'A', 2 - 'V', 1, 0, 0, 0})}, {"kern", Words({0, 1, 0, 20, 1, 1, 6, 0, 0, 1, 2, -200})}, }); } struct ParsedText { const char* text; std::size_t at; FontHandle font; }; static std::int32_t APS5_VABI ParseText(FontTextSource* source, void** order, FontTextParseResult* result) { auto* parsed = static_cast(source->textObject); *order = const_cast(parsed->text + parsed->at); if (parsed->text[parsed->at] == 0) { result->Terminate.terminateCode = 0; return 0; } result->FontCode.font = parsed->font; result->FontCode.code = static_cast(parsed->text[parsed->at++]); return 1; } static void CheckTextCodes(const FontMemory* memory, FontHandle font) { ParsedText parsed{"AVA", 0, font}; FontTextSource source{}; Require(sceFontTextSourceInit(&source, parsed.text, 3, ParseText, &parsed) == SCE_FONT_OK); FontString string = nullptr; Require(sceFontCreateString(memory, &source, nullptr, &string) == SCE_FONT_OK && string != nullptr); std::uint32_t count = 0; FontTextCharacter* characters = sceFontStringRefersTextCharacters(string, &count); Require(characters != nullptr && count == 3); FontTextCodes codes; std::memset(&codes, 0xa5, sizeof(codes)); Require(sceFontCharactersRefersTextCodes(characters, nullptr, &codes) == &codes); Require(codes.text.order == parsed.text && codes.text.code == 'A' && codes.text.reserved == 0); Require(codes.systemUse[5] == characters && codes.systemUse[6] == characters && codes.systemUse[7] == nullptr); Require(sceFontTextCodesStepNext(&codes) == &codes && codes.text.code == 'V' && codes.text.order == parsed.text + 1); Require(sceFontTextCodesStepNext(&codes) == &codes && codes.text.code == 'A' && codes.text.order == parsed.text + 2); Require(sceFontTextCodesStepNext(&codes) == nullptr && codes.text.order == parsed.text + 2); Require(sceFontTextCodesStepBack(&codes) == &codes && codes.text.code == 'V' && codes.text.order == parsed.text + 1); Require(sceFontTextCodesStepBack(&codes) == &codes && codes.text.code == 'A' && codes.text.order == parsed.text); Require(sceFontTextCodesStepBack(&codes) == nullptr && codes.text.order == parsed.text); Require(sceFontCharactersRefersTextCodes(characters + 1, characters + 2, &codes) == &codes && codes.text.code == 'V'); Require(sceFontTextCodesStepNext(&codes) == &codes && codes.text.order == parsed.text + 2); Require(sceFontTextCodesStepNext(&codes) == nullptr && codes.text.order == parsed.text + 2); Require(sceFontTextCodesStepBack(&codes) == &codes && codes.text.order == parsed.text + 1); Require(sceFontTextCodesStepBack(&codes) == nullptr && codes.text.order == parsed.text + 1); Require(sceFontCharactersRefersTextCodes(characters + 2, characters + 2, &codes) == &codes && codes.text.order == parsed.text + 2); Require(sceFontTextCodesStepNext(&codes) == nullptr && sceFontTextCodesStepBack(&codes) == nullptr); characters[1].synthetic = 1; Require(sceFontCharactersRefersTextCodes(characters, nullptr, &codes) == &codes); Require(sceFontTextCodesStepNext(&codes) == &codes && codes.text.order == parsed.text + 2); Require(sceFontTextCodesStepBack(&codes) == &codes && codes.text.order == parsed.text); Require(sceFontCharactersRefersTextCodes(characters + 1, nullptr, &codes) == nullptr && codes.text.order == parsed.text); characters[1].synthetic = 0; characters[1].clusterIndex = 1; Require(sceFontCharactersRefersTextCodes(characters + 1, nullptr, &codes) == nullptr && codes.text.order == parsed.text); Require(sceFontTextCodesStepNext(&codes) == &codes && codes.text.order == parsed.text + 1); characters[1].clusterIndex = 0; Require(sceFontCharactersRefersTextCodes(characters, nullptr, nullptr) == nullptr); Require(sceFontTextCodesStepNext(nullptr) == nullptr && sceFontTextCodesStepBack(nullptr) == nullptr); bool threw = false; try { sceFontCharactersRefersTextCodes(nullptr, nullptr, &codes); } catch (const std::runtime_error&) { threw = true; } Require(threw && codes.text.order == parsed.text + 1); Require(sceFontDestroyString(&string) == SCE_FONT_OK); } static bool KerningIs(const FontKerning& kerning, float offsetX) { return kerning.offsetX == offsetX && kerning.offsetY == 0.0f && kerning.positionX == 0.0f && kerning.positionY == 0.0f; } int main() { constexpr std::uint32_t SystemFontSet = 0x18070043u; const std::filesystem::path fontRoot = std::filesystem::temp_directory_path() / ("anyps5_guest_font-" + std::to_string(std::random_device{}())); std::filesystem::remove_all(fontRoot); std::filesystem::create_directories(fontRoot); SetFontDirectory(fontRoot); const FontMemoryInterface iface{Allocate, Release, nullptr, nullptr, nullptr, nullptr}; FontMemory memory{}; Require(sceFontMemoryInit(&memory, nullptr, 0, &iface, nullptr, nullptr, nullptr) == SCE_FONT_OK); Require(sceFontSelectLibraryFt(0) != nullptr && sceFontSelectLibraryFt(1) == nullptr); Require(sceFontSelectRendererFt(0) != nullptr && sceFontSelectRendererFt(1) == nullptr); FontLibrary library = nullptr; Require(sceFontCreateLibrary(&memory, nullptr, &library) == SCE_FONT_ERROR_INVALID_PARAMETER && library == nullptr); Require(sceFontCreateLibrary(&memory, sceFontSelectLibraryFt(0), &library) == SCE_FONT_OK && library != nullptr); Require(sceFontFtSupportBdf(library) == 0 && sceFontFtSupportCid(library) == 0 && sceFontFtSupportOpenType(library) == 0 && sceFontFtSupportOpenTypeOtf(library) == 0 && sceFontFtSupportOpenTypeTtf(library) == 0 && sceFontFtSupportPcf(library) == 0 && sceFontFtSupportPfr(library) == 0 && sceFontFtSupportTrueType(library) == 0 && sceFontFtSupportType1(library) == 0 && sceFontFtSupportType42(library) == 0 && sceFontFtSupportWinFonts(library) == 0); const auto* nativeLibrary = static_cast(library); const auto savedLock = nativeLibrary->lock_word; for (auto support : {sceFontFtSupportBdf, sceFontFtSupportCid, sceFontFtSupportOpenType, sceFontFtSupportOpenTypeOtf, sceFontFtSupportOpenTypeTtf, sceFontFtSupportPcf, sceFontFtSupportPfr, sceFontFtSupportTrueType, sceFontFtSupportType1, sceFontFtSupportType42, sceFontFtSupportWinFonts}) { Font::FontLibNative invalidLibrary{}; Require(support(nullptr) == SCE_FONT_ERROR_INVALID_LIBRARY); Require(support(&invalidLibrary) == SCE_FONT_ERROR_INVALID_LIBRARY); Require(support(library) == SCE_FONT_OK); Require(nativeLibrary->lock_word == savedLock); } Font::FontLibNative foreignLibrary{}; foreignLibrary.magic = Font::LIBRARY_MAGIC; foreignLibrary.lock_word = 5; bool foreignDriverRejected = false; try { static_cast(sceFontFtSupportTrueType(&foreignLibrary)); } catch (const std::runtime_error&) { foreignDriverRejected = true; } Require(foreignDriverRejected && foreignLibrary.lock_word == 5); std::uint32_t subPixelCount = 1; Require(sceFontGetPixelResolution(library, &subPixelCount) == SCE_FONT_OK && subPixelCount == 64); Require(sceFontGetPixelResolution(library, nullptr) == SCE_FONT_ERROR_INVALID_PARAMETER); Require(sceFontGetPixelResolution(nullptr, nullptr) == SCE_FONT_ERROR_INVALID_LIBRARY); subPixelCount = 1; Require(sceFontGetPixelResolution(nullptr, &subPixelCount) == SCE_FONT_ERROR_INVALID_LIBRARY && subPixelCount == 0); FontHandleOpaque notALibrary{}; subPixelCount = 1; Require(sceFontGetPixelResolution(¬ALibrary, &subPixelCount) == SCE_FONT_ERROR_INVALID_LIBRARY && subPixelCount == 0); Font::SysDriver coarseDriver = *static_cast(sceFontSelectLibraryFt(0)); coarseDriver.pixel_resolution = CoarsePixelResolution; FontLibrary coarseLibrary = nullptr; Require(sceFontCreateLibrary(&memory, &coarseDriver, &coarseLibrary) == SCE_FONT_OK && coarseLibrary != nullptr); Require(sceFontGetPixelResolution(coarseLibrary, &subPixelCount) == SCE_FONT_OK && subPixelCount == 16); Require(sceFontGetPixelResolution(library, &subPixelCount) == SCE_FONT_OK && subPixelCount == 64); Require(static_cast(coarseLibrary)->lock_word == 0); coarseDriver.pixel_resolution = nullptr; Require(sceFontGetPixelResolution(coarseLibrary, &subPixelCount) == SCE_FONT_ERROR_INVALID_LIBRARY && subPixelCount == 0); Require(sceFontGetPixelResolution(coarseLibrary, nullptr) == SCE_FONT_ERROR_INVALID_LIBRARY); Require(static_cast(coarseLibrary)->lock_word == 0); Require(sceFontDestroyLibrary(&coarseLibrary) == SCE_FONT_OK && coarseLibrary == nullptr); void* cacheBuffer = ¬ALibrary; std::uint32_t cacheSize = 0; cacheSize = 123; Require(sceFontDettachDeviceCacheBuffer(nullptr, &cacheBuffer, &cacheSize) == SCE_FONT_ERROR_INVALID_LIBRARY); Require(cacheBuffer == nullptr && cacheSize == 0); Require(sceFontDettachDeviceCacheBuffer(¬ALibrary, &cacheBuffer, &cacheSize) == SCE_FONT_ERROR_INVALID_LIBRARY); Require(sceFontClearDeviceCache(library) == SCE_FONT_ERROR_NOT_ATTACHED_CACHE_BUFFER); Require(sceFontDettachDeviceCacheBuffer(library, &cacheBuffer, &cacheSize) == SCE_FONT_ERROR_NOT_ATTACHED_CACHE_BUFFER); std::vector callerCache(0x2000); Require(sceFontAttachDeviceCacheBuffer(library, callerCache.data(), 0x1000) == SCE_FONT_ERROR_INVALID_PARAMETER); Require(sceFontAttachDeviceCacheBuffer(library, callerCache.data(), static_cast(callerCache.size())) == SCE_FONT_OK); Require(sceFontAttachDeviceCacheBuffer(library, callerCache.data(), static_cast(callerCache.size())) == SCE_FONT_ERROR_ALREADY_ATTACHED); Require(sceFontClearDeviceCache(library) == SCE_FONT_OK); Require(sceFontDettachDeviceCacheBuffer(library, &cacheBuffer, &cacheSize) == SCE_FONT_OK && cacheBuffer == callerCache.data() && cacheSize == callerCache.size()); for (std::size_t offset = 4; offset < 24; ++offset) Require(callerCache[offset] == 0); Require(sceFontDettachDeviceCacheBuffer(library, &cacheBuffer, &cacheSize) == SCE_FONT_ERROR_NOT_ATTACHED_CACHE_BUFFER); Require(sceFontAttachDeviceCacheBuffer(library, nullptr, 0x2000) == SCE_FONT_OK); cacheBuffer = nullptr; cacheSize = 0; const int allocationsBeforeDetach = allocations; Require(sceFontDettachDeviceCacheBuffer(library, &cacheBuffer, &cacheSize) == SCE_FONT_OK && cacheBuffer == nullptr && cacheSize == 0); Require(allocations == allocationsBeforeDetach - 1); Require(sceFontDettachDeviceCacheBuffer(library, &cacheBuffer, &cacheSize) == SCE_FONT_ERROR_NOT_ATTACHED_CACHE_BUFFER); Require(sceFontAttachDeviceCacheBuffer(library, nullptr, 0x2000) == SCE_FONT_OK); Require(sceFontDettachDeviceCacheBuffer(library, nullptr, nullptr) == SCE_FONT_OK); Require(sceFontDettachDeviceCacheBuffer(library, nullptr, nullptr) == SCE_FONT_ERROR_NOT_ATTACHED_CACHE_BUFFER); FontHandle font = reinterpret_cast(&memory); Require(sceFontOpenFontSet(library, SystemFontSet, 1, nullptr, &font) == SCE_FONT_ERROR_NO_SUPPORT_FUNCTION && font == nullptr); Require(sceFontSupportSystemFonts(library) == SCE_FONT_OK); Require(sceFontOpenFontSet(library, SystemFontSet, 1, nullptr, &font) == SCE_FONT_ERROR_FONT_OPEN_FAILED && font == nullptr); Require(sceFontOpenFontSet(library, 0x12345678u, 1, nullptr, &font) == SCE_FONT_ERROR_NO_SUPPORT_FONTSET); Require(sceFontOpenFontSet(library, SystemFontSet, 7, nullptr, &font) == SCE_FONT_ERROR_INVALID_PARAMETER); Require(sceFontOpenFontSet(nullptr, SystemFontSet, 1, nullptr, &font) == SCE_FONT_ERROR_INVALID_LIBRARY); const unsigned char notAFont[64] = {1, 2, 3, 4}; Require(sceFontOpenFontMemory(library, notAFont, sizeof(notAFont), nullptr, &font) == SCE_FONT_ERROR_NO_SUPPORT_FUNCTION && font == nullptr); Require(sceFontSupportExternalFonts(library, 4, 0x52) == SCE_FONT_OK); Require(sceFontSupportExternalFonts(library, 4, 0x52) == SCE_FONT_ERROR_ALREADY_SPECIFIED); font = reinterpret_cast(&memory); Require(sceFontOpenFontFile(library, "anyps5-missing-font-parent/../font.ttf", 1, nullptr, &font) == SCE_FONT_ERROR_FS_OPEN_FAILED && font == nullptr); Require(sceFontOpenFontMemory(library, nullptr, 0, nullptr, &font) == SCE_FONT_ERROR_INVALID_PARAMETER && font == nullptr); Require(sceFontOpenFontMemory(library, notAFont, sizeof(notAFont), nullptr, &font) == SCE_FONT_ERROR_NO_SUPPORT_FORMAT && font == nullptr); const std::vector fontData = EmptyGlyphFont(); Require(sceFontOpenFontMemory(library, fontData.data(), static_cast(fontData.size()), nullptr, &font) == SCE_FONT_OK && font != nullptr); int setting = -1; Require(sceFontGetScriptLanguage(font, 3, &setting) == SCE_FONT_ERROR_INVALID_PARAMETER && setting == 0); Require(sceFontSetScriptLanguage(font, 3, 7) == SCE_FONT_ERROR_INVALID_PARAMETER); Require(sceFontSetScriptLanguage(font, 0x100, 0x106) == SCE_FONT_ERROR_INVALID_PARAMETER); Require(sceFontSetScriptLanguage(font, 0x600, 0x603) == SCE_FONT_ERROR_INVALID_PARAMETER); Require(sceFontSetScriptLanguage(font, 0x3000, 0x3015) == SCE_FONT_ERROR_INVALID_PARAMETER); Require(sceFontGetScriptLanguage(font, 0x100, nullptr) == SCE_FONT_ERROR_INVALID_PARAMETER); Require(sceFontSetScriptLanguage(nullptr, 3, 7) == SCE_FONT_ERROR_INVALID_FONT_HANDLE); Require(sceFontGetScriptLanguage(nullptr, 3, nullptr) == SCE_FONT_ERROR_INVALID_FONT_HANDLE); for (const auto script : {0x100, 0x600, 0x3000}) { bool setThrew = false; bool getThrew = false; try { sceFontSetScriptLanguage(font, script, script); } catch (const std::logic_error&) { setThrew = true; } try { sceFontGetScriptLanguage(font, script, &setting); } catch (const std::logic_error&) { getThrew = true; } Require(setThrew && getThrew && setting == 0); } Require(sceFontSetTypographicDesign(font, 1, 2) == SCE_FONT_ERROR_INVALID_PARAMETER); Require(sceFontSetTypographicDesign(font, 17, 1) == SCE_FONT_ERROR_INVALID_PARAMETER); for (const auto selector : {-1, 0, 2, 5, 16, 18, 65536, 65540}) { Require(sceFontSetTypographicDesign(font, selector, 0) == SCE_FONT_ERROR_INVALID_PARAMETER); setting = 123; Require(sceFontGetTypographicDesign(font, selector, &setting) == SCE_FONT_ERROR_INVALID_PARAMETER && setting == 0); } Require(sceFontGetTypographicDesign(nullptr, 1, &setting) == SCE_FONT_ERROR_INVALID_FONT_HANDLE && setting == 0); Require(sceFontGetTypographicDesign(nullptr, 1, nullptr) == SCE_FONT_ERROR_INVALID_FONT_HANDLE); Require(sceFontSetTypographicDesign(nullptr, 1, 2) == SCE_FONT_ERROR_INVALID_FONT_HANDLE); Require(sceFontSetTypographicDesign(font, 65537, 0) == SCE_FONT_ERROR_INVALID_PARAMETER); for (const auto selector : {1, 17, 65537, 65538, 65539}) { Require(sceFontGetTypographicDesign(font, selector, nullptr) == SCE_FONT_ERROR_INVALID_PARAMETER); bool getThrew = false; try { sceFontGetTypographicDesign(font, selector, &setting); } catch (const std::logic_error&) { getThrew = true; } Require(getThrew && setting == 0); if (selector == 65537) continue; for (const auto feature : {0, selector == 1 ? 1 : 32}) { bool setThrew = false; try { sceFontSetTypographicDesign(font, selector, feature); } catch (const std::logic_error&) { setThrew = true; } Require(setThrew); } } std::array typographyRecord{}; auto* nativeFont = reinterpret_cast(font); nativeFont->open_info.fontset_record = typographyRecord.data(); for (const auto selector : {65537, 65538, 65539}) { Require(sceFontSetTypographicDesign(font, selector, 0) == SCE_FONT_ERROR_NO_SUPPORT_TYPOGRAPHY); setting = 123; Require(sceFontGetTypographicDesign(font, selector, &setting) == SCE_FONT_ERROR_NO_SUPPORT_TYPOGRAPHY && setting == 0); Require(sceFontGetTypographicDesign(font, selector, nullptr) == SCE_FONT_ERROR_INVALID_PARAMETER); } const std::uint32_t typographyCount = 1; const std::int32_t typographyFontId = 10; std::memcpy(typographyRecord.data() + 32, &typographyCount, sizeof(typographyCount)); std::memcpy(typographyRecord.data() + 36, &typographyFontId, sizeof(typographyFontId)); Require(sceFontSetTypographicDesign(font, 65537, 0) == SCE_FONT_ERROR_INVALID_PARAMETER); Require(sceFontGetTypographicDesign(font, 65538, &setting) == SCE_FONT_ERROR_NO_SUPPORT_TYPOGRAPHY); bool typographyQueryThrew = false; try { sceFontGetTypographicDesign(font, 65537, &setting); } catch (const std::logic_error&) { typographyQueryThrew = true; } Require(typographyQueryThrew && setting == 0); nativeFont->open_info.fontset_record = nullptr; int attribute = -1; Require(sceFontGetAttribute(font, 0x11, &attribute) == SCE_FONT_OK && attribute == 0); Require(sceFontDefineAttribute(font, 0x11, &attribute) == SCE_FONT_OK && attribute == 0); attribute = -1; Require(sceFontGetAttribute(font, 0x99, &attribute) == SCE_FONT_OK && attribute == 0x11); Require(sceFontDefineAttribute(font, 0, &attribute) == SCE_FONT_OK && attribute == 0x11); Require(sceFontDefineAttribute(font, 5, nullptr) == SCE_FONT_OK); attribute = -1; Require(sceFontGetAttribute(font, 0, &attribute) == SCE_FONT_OK && attribute == 5); Require(sceFontGetAttribute(font, 0x11, nullptr) == SCE_FONT_ERROR_INVALID_PARAMETER); attribute = -1; Require(sceFontDefineAttribute(nullptr, 0x11, &attribute) == SCE_FONT_ERROR_INVALID_FONT_HANDLE && attribute == -1); Require(sceFontGetAttribute(nullptr, 0x11, &attribute) == SCE_FONT_ERROR_INVALID_FONT_HANDLE && attribute == -1); FontHandle otherFont = nullptr; Require(sceFontOpenFontMemory(library, fontData.data(), static_cast(fontData.size()), nullptr, &otherFont) == SCE_FONT_OK && otherFont != nullptr); attribute = -1; Require(sceFontGetAttribute(otherFont, 0, &attribute) == SCE_FONT_OK && attribute == 0); Require(sceFontDefineAttribute(otherFont, 7, &attribute) == SCE_FONT_OK && attribute == 0); attribute = -1; Require(sceFontGetAttribute(otherFont, 0, &attribute) == SCE_FONT_OK && attribute == 7); Require(sceFontGetAttribute(font, 0, &attribute) == SCE_FONT_OK && attribute == 5); Require(sceFontCloseFont(otherFont) == SCE_FONT_OK); auto* resolutionLibrary = static_cast(library); const Font::SysDriver* originalDriver = resolutionLibrary->sys_driver; Font::SysDriver wideResolutionDriver = *originalDriver; wideResolutionDriver.scale = WideFontResolution; resolutionLibrary->sys_driver = &wideResolutionDriver; std::uint32_t wideResolution = 0; float wideScale = 0; Require(sceFontGetFontResolution(font, &wideResolution, &wideScale) == SCE_FONT_OK); Require(wideResolution == 0x12345678 && wideScale == 12.5f); resolutionLibrary->sys_driver = originalDriver; std::uint32_t hDpi = 1; std::uint32_t vDpi = 1; Require(sceFontGetResolutionDpi(font, &hDpi, &vDpi) == SCE_FONT_OK && hDpi == 72 && vDpi == 72); Require(sceFontSetResolutionDpi(font, 96, 144) == SCE_FONT_OK); Require(sceFontGetResolutionDpi(font, &hDpi, &vDpi) == SCE_FONT_OK && hDpi == 96 && vDpi == 144); hDpi = 1; vDpi = 1; Require(sceFontGetResolutionDpi(font, &hDpi, nullptr) == SCE_FONT_OK && hDpi == 96); Require(sceFontGetResolutionDpi(font, nullptr, &vDpi) == SCE_FONT_OK && vDpi == 144); Require(sceFontGetResolutionDpi(font, nullptr, nullptr) == SCE_FONT_ERROR_INVALID_PARAMETER); Require(sceFontSetResolutionDpi(font, 0, 300) == SCE_FONT_OK); Require(sceFontGetResolutionDpi(font, &hDpi, &vDpi) == SCE_FONT_OK && hDpi == 72 && vDpi == 300); Require(sceFontGetResolutionDpi(nullptr, &hDpi, &vDpi) == SCE_FONT_ERROR_INVALID_FONT_HANDLE && hDpi == 0 && vDpi == 0); FontHandleOpaque unopened{}; hDpi = 1; vDpi = 1; Require(sceFontGetResolutionDpi(&unopened, &hDpi, &vDpi) == SCE_FONT_ERROR_INVALID_FONT_HANDLE && hDpi == 0 && vDpi == 0); std::uint32_t glyphsCount = 0; Require(sceFontGetFontGlyphsCount(font, &glyphsCount) == SCE_FONT_OK && glyphsCount == 1); Require(sceFontGetFontGlyphsCount(font, nullptr) == SCE_FONT_ERROR_INVALID_PARAMETER); glyphsCount = 1; Require(sceFontGetFontGlyphsCount(nullptr, &glyphsCount) == SCE_FONT_ERROR_INVALID_FONT_HANDLE && glyphsCount == 0); glyphsCount = 1; Require(sceFontGetFontGlyphsCount(&unopened, &glyphsCount) == SCE_FONT_ERROR_INVALID_FONT_HANDLE && glyphsCount == 0); std::uint32_t glyphCode = 1; Require(sceFontGetCharGlyphCode(font, 'A', &glyphCode) == SCE_FONT_ERROR_NO_SUPPORT_GLYPH && glyphCode == 0); Require(sceFontGetCharGlyphCode(font, 'A', nullptr) == SCE_FONT_ERROR_INVALID_PARAMETER); glyphCode = 1; Require(sceFontGetCharGlyphCode(nullptr, 'A', &glyphCode) == SCE_FONT_ERROR_INVALID_FONT_HANDLE && glyphCode == 0); glyphCode = 1; Require(sceFontGetCharGlyphCode(&unopened, 'A', &glyphCode) == SCE_FONT_ERROR_INVALID_FONT_HANDLE && glyphCode == 0); std::uint32_t resolution = 0; float scalePixel = 0.0f; Require(sceFontGetFontResolution(font, &resolution, &scalePixel) == SCE_FONT_OK && resolution == 1000 && scalePixel == 15.625f); resolution = 0; Require(sceFontGetFontResolution(font, &resolution, nullptr) == SCE_FONT_OK && resolution == 1000); scalePixel = 0.0f; Require(sceFontGetFontResolution(font, nullptr, &scalePixel) == SCE_FONT_OK && scalePixel == 15.625f); Require(sceFontGetFontResolution(font, nullptr, nullptr) == SCE_FONT_ERROR_INVALID_PARAMETER); Require(sceFontGetFontResolution(nullptr, &resolution, &scalePixel) == SCE_FONT_ERROR_INVALID_FONT_HANDLE && resolution == 0 && scalePixel == 0.0f); resolution = 1; scalePixel = 1.0f; Require(sceFontGetFontResolution(&unopened, &resolution, &scalePixel) == SCE_FONT_ERROR_INVALID_FONT_HANDLE && resolution == 0 && scalePixel == 0.0f); Require(sceFontCloseFont(font) == SCE_FONT_OK); FontRenderer renderer = nullptr; Require(sceFontCreateRenderer(&memory, sceFontSelectRendererFt(0), &renderer) == SCE_FONT_OK && renderer != nullptr); const std::vector kerningData = KerningFont(); font = nullptr; Require(sceFontOpenFontMemory(library, kerningData.data(), static_cast(kerningData.size()), nullptr, &font) == SCE_FONT_OK && font != nullptr); Require(sceFontGetFontGlyphsCount(font, &glyphsCount) == SCE_FONT_OK && glyphsCount == 3); Require(sceFontGetCharGlyphCode(font, 'A', &glyphCode) == SCE_FONT_OK && glyphCode == 0x80000001u); Require(sceFontGetCharGlyphCode(font, 'V', &glyphCode) == SCE_FONT_OK && glyphCode == 0x80000002u); Require(sceFontGetCharGlyphCode(nullptr, 0, nullptr) == SCE_FONT_ERROR_INVALID_FONT_HANDLE); Require(sceFontGetFontGlyphsCount(nullptr, nullptr) == SCE_FONT_ERROR_INVALID_FONT_HANDLE); Require(sceFontGetCharGlyphCode(font, 0, nullptr) == SCE_FONT_ERROR_NO_SUPPORT_CODE); Require(sceFontGetCharGlyphCode(font, 0x80000000u, &glyphCode) == SCE_FONT_OK && glyphCode == 0x80000000u); Require(sceFontGetCharGlyphCode(font, 0x80000002u, &glyphCode) == SCE_FONT_OK && glyphCode == 0x80000002u); Require(sceFontGetCharGlyphCode(font, 0xc0000001u, &glyphCode) == SCE_FONT_OK && glyphCode == 0x80000001u); Require(sceFontGetCharGlyphCode(font, 0x80000003u, &glyphCode) == SCE_FONT_ERROR_NO_SUPPORT_GLYPH && glyphCode == 0); Require(sceFontGetCharGlyphCode(font, 0x80010001u, &glyphCode) == SCE_FONT_ERROR_NO_SUPPORT_CODE && glyphCode == 0); glyphCode = 1; Require(sceFontGetCharGlyphCode(font, 'B', &glyphCode) == SCE_FONT_ERROR_NO_SUPPORT_GLYPH && glyphCode == 0); glyphCode = 1; Require(sceFontGetCharGlyphCode(font, 0, &glyphCode) == SCE_FONT_ERROR_NO_SUPPORT_CODE && glyphCode == 0); Require(sceFontSetResolutionDpi(font, 144, 144) == SCE_FONT_OK); Require(sceFontSetScalePixel(font, 100.0f, 100.0f) == SCE_FONT_OK); FontGlyph glyph = nullptr; Require(sceFontGenerateCharGlyph(font, 'A', nullptr, &glyph) == SCE_FONT_OK && glyph != nullptr); const auto originalFlags = glyph->flags; std::int32_t previousAttribute = -1; Require(sceFontGlyphDefineAttribute(glyph, 0x11, &previousAttribute) == SCE_FONT_OK); Require(previousAttribute == ((originalFlags & 2) ? 0x11 : 0x10)); Require(glyph->flags == (originalFlags | 2)); Require(sceFontGlyphDefineAttribute(glyph, 0x10, &previousAttribute) == SCE_FONT_OK && previousAttribute == 0x11); Require(glyph->flags == (originalFlags & ~2u)); Require(sceFontGlyphDefineAttribute(glyph, 0x10, &previousAttribute) == SCE_FONT_OK && previousAttribute == 0x10); Require(sceFontGlyphDefineAttribute(glyph, 0x11, nullptr) == SCE_FONT_OK); for (std::int32_t attribute = -1; attribute <= 256; ++attribute) { if (attribute == 0x10 || attribute == 0x11) continue; previousAttribute = -1; Require(sceFontGlyphDefineAttribute(glyph, attribute, &previousAttribute) == SCE_FONT_ERROR_INVALID_PARAMETER); Require(previousAttribute == 0 && glyph->flags == (originalFlags | 2)); } previousAttribute = -1; Require(sceFontGlyphDefineAttribute(nullptr, 0x11, &previousAttribute) == SCE_FONT_ERROR_INVALID_GLYPH && previousAttribute == 0); Require(sceFontGlyphDefineAttribute(nullptr, 0x11, nullptr) == SCE_FONT_ERROR_INVALID_GLYPH); FontGlyphOpaque notAGlyph{}; previousAttribute = -1; Require(sceFontGlyphDefineAttribute(¬AGlyph, 0x11, &previousAttribute) == SCE_FONT_ERROR_INVALID_GLYPH && previousAttribute == 0); int glyphAttribute = -1; Require(sceFontGlyphGetAttribute(glyph, 0x11, &glyphAttribute) == SCE_FONT_OK && glyphAttribute == 0x11); Require(sceFontGlyphGetAttribute(glyph, 0x11, nullptr) == SCE_FONT_ERROR_INVALID_PARAMETER); Require(sceFontGlyphGetAttribute(nullptr, 0x11, &glyphAttribute) == SCE_FONT_ERROR_INVALID_GLYPH); Require(sceFontDeleteGlyph(&memory, &glyph) == SCE_FONT_OK && glyph == nullptr); FontKerning kerning{1.0f, 1.0f, 1.0f, 1.0f}; Require(sceFontGetKerning(font, 'A', 'V', &kerning) == SCE_FONT_OK && KerningIs(kerning, -20.0f)); kerning = {1.0f, 1.0f, 1.0f, 1.0f}; Require(sceFontGetRenderScaledKerning(font, 'A', 'V', &kerning) == SCE_FONT_ERROR_NOT_BOUND_RENDERER && KerningIs(kerning, 0.0f)); Require(sceFontBindRenderer(font, renderer) == SCE_FONT_OK); Require(sceFontGetRenderScaledKerning(font, 'A', 'V', &kerning) == SCE_FONT_OK && KerningIs(kerning, -20.0f)); Require(sceFontSetupRenderScalePixel(font, 50.0f, 50.0f) == SCE_FONT_OK); Require(sceFontGetRenderScaledKerning(font, 'A', 'V', &kerning) == SCE_FONT_OK && KerningIs(kerning, -10.0f)); Require(sceFontGetKerning(font, 'A', 'V', &kerning) == SCE_FONT_OK && KerningIs(kerning, -20.0f)); Require(sceFontSetupRenderScalePoint(font, 20.0f, 20.0f) == SCE_FONT_OK); Require(sceFontGetRenderScaledKerning(font, 'A', 'V', &kerning) == SCE_FONT_OK && KerningIs(kerning, -8.0f)); kerning = {1.0f, 1.0f, 1.0f, 1.0f}; Require(sceFontGetRenderScaledKerning(font, 'V', 'A', &kerning) == SCE_FONT_OK && KerningIs(kerning, 0.0f)); kerning = {1.0f, 1.0f, 1.0f, 1.0f}; Require(sceFontGetRenderScaledKerning(font, 'A', 'B', &kerning) == SCE_FONT_OK && KerningIs(kerning, 0.0f)); Require(sceFontGetRenderScaledKerning(font, 'A', 'V', nullptr) == SCE_FONT_ERROR_INVALID_PARAMETER); kerning = {1.0f, 1.0f, 1.0f, 1.0f}; Require(sceFontGetRenderScaledKerning(nullptr, 'A', 'V', &kerning) == SCE_FONT_ERROR_INVALID_FONT_HANDLE && KerningIs(kerning, 0.0f)); kerning = {1.0f, 1.0f, 1.0f, 1.0f}; Require(sceFontGetRenderScaledKerning(&unopened, 'A', 'V', &kerning) == SCE_FONT_ERROR_INVALID_FONT_HANDLE && KerningIs(kerning, 0.0f)); Require(sceFontUnbindRenderer(font) == SCE_FONT_OK); Require(sceFontGetRenderScaledKerning(font, 'A', 'V', &kerning) == SCE_FONT_ERROR_NOT_BOUND_RENDERER); ParsedText parsed{"AV", 0, font}; FontTextSource source{}; Require(sceFontTextSourceInit(&source, parsed.text, 2, ParseText, &parsed) == SCE_FONT_OK); FontString string = nullptr; Require(sceFontCreateString(&memory, &source, nullptr, &string) == SCE_FONT_OK && string != nullptr); std::uint32_t characterCount = 0; FontTextCharacter* characters = sceFontStringRefersTextCharacters(string, &characterCount); Require(characters != nullptr && characterCount == 2); FontWriting writing{}; Require(sceFontWritingInit(&writing, string, characters) == SCE_FONT_OK); constexpr std::uint64_t guard = 0x5a5a5a5a5a5a5a5aull; struct { const FontWritingLetterStep* letter; std::uint64_t guard; } out{reinterpret_cast(&memory), guard}; Require(sceFontWritingRefersRenderStepCharacter(&writing, &out.letter) == nullptr && out.letter == nullptr && out.guard == guard); const FontWritingStep* step = sceFontWritingRefersRenderStep(&writing); Require(step != nullptr); Require(sceFontWritingRefersRenderStepCharacter(&writing, &out.letter) == characters && out.letter != nullptr && out.guard == guard); Require(out.letter->x == step->x && out.letter->advanceX == step->advanceX && out.letter->Components.textsIndex == 0 && out.letter->Components.characterTextCount == 1); step = sceFontWritingRefersRenderStep(&writing); Require(step != nullptr); Require(sceFontWritingRefersRenderStepCharacter(&writing, &out.letter) == characters + 1 && out.guard == guard); Require(out.letter->x == step->x && out.letter->Components.textsIndex == 1 && out.letter->Components.glyphsIndex == 1); Require(sceFontWritingRefersRenderStepCharacter(&writing, nullptr) == characters + 1); Require(sceFontDestroyString(&string) == SCE_FONT_OK); CheckTextCodes(&memory, font); Require(sceFontCloseFont(font) == SCE_FONT_OK); Require(sceFontDestroyRenderer(&renderer) == SCE_FONT_OK && renderer == nullptr); Require(sceFontDestroyRenderer(&renderer) == SCE_FONT_ERROR_INVALID_RENDERER); Require(sceFontDestroyLibrary(&library) == SCE_FONT_OK && library == nullptr); Require(sceFontDestroyLibrary(&library) == SCE_FONT_ERROR_INVALID_LIBRARY); Require(allocations == 0); Require(sceFontMemoryTerm(&memory) == SCE_FONT_OK); Require(sceFontMemoryTerm(&memory) == SCE_FONT_ERROR_INVALID_MEMORY); FontTextCharacter character{}; character.characterCode = 'A'; int syllableState = -1; Require(sceFontCharacterGetSyllableStringState(&character, &syllableState) == SCE_FONT_OK && syllableState == 0); syllableState = -1; Require(sceFontCharacterGetSyllableStringState(nullptr, &syllableState) == SCE_FONT_ERROR_INVALID_PARAMETER && syllableState == 0); Require(sceFontCharacterGetSyllableStringState(&character, nullptr) == SCE_FONT_ERROR_INVALID_PARAMETER); std::filesystem::remove_all(fontRoot); }