Files
Dean 52f7807a55 Merge pull request #6581 from Thomas73737/feat/libscefont-words
feat(libSceFont): implement handle and glyph attributes
2026-10-21 02:43:40 +13:00

470 lines
30 KiB
C++

#include "prx/libSceFont/include/FontDriver.hpp"
#include "tests/FontFixture.hpp"
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <filesystem>
#include <initializer_list>
#include <map>
#include <random>
#include <stdexcept>
#include <string>
#include <vector>
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, int, int*);
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();
int APS5_VABI sceFontFtSupportCid();
int APS5_VABI sceFontFtSupportOpenType();
int APS5_VABI sceFontFtSupportOpenTypeOtf();
int APS5_VABI sceFontFtSupportOpenTypeTtf();
int APS5_VABI sceFontFtSupportPcf();
int APS5_VABI sceFontFtSupportPfr();
int APS5_VABI sceFontFtSupportTrueType();
int APS5_VABI sceFontFtSupportType1();
int APS5_VABI sceFontFtSupportType42();
int APS5_VABI sceFontFtSupportWinFonts();
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;
}
using FontFixture::BuildFont;
using FontFixture::Words;
static std::vector<unsigned char> EmptyGlyphFont() {
return BuildFont(1, {});
}
static std::vector<unsigned char> 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<ParsedText*>(source->textObject);
*order = const_cast<char*>(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<unsigned char>(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);
Require(sceFontFtSupportBdf() == 0 && sceFontFtSupportCid() == 0 && sceFontFtSupportOpenType() == 0 && sceFontFtSupportOpenTypeOtf() == 0 && sceFontFtSupportOpenTypeTtf() == 0 && sceFontFtSupportPcf() == 0 && sceFontFtSupportPfr() == 0 && sceFontFtSupportTrueType() == 0 && sceFontFtSupportType1() == 0 && sceFontFtSupportType42() == 0 && sceFontFtSupportWinFonts() == 0);
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);
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_PARAMETER);
subPixelCount = 1;
Require(sceFontGetPixelResolution(nullptr, &subPixelCount) == SCE_FONT_ERROR_INVALID_LIBRARY && subPixelCount == 0);
FontHandleOpaque notALibrary{};
subPixelCount = 1;
Require(sceFontGetPixelResolution(&notALibrary, &subPixelCount) == SCE_FONT_ERROR_INVALID_LIBRARY && subPixelCount == 0);
Font::SysDriver coarseDriver = *static_cast<const Font::SysDriver*>(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);
coarseDriver.pixel_resolution = nullptr;
Require(sceFontGetPixelResolution(coarseLibrary, &subPixelCount) == SCE_FONT_ERROR_INVALID_LIBRARY && subPixelCount == 0);
Require(sceFontDestroyLibrary(&coarseLibrary) == SCE_FONT_OK && coarseLibrary == nullptr);
void* cacheBuffer = nullptr;
std::uint32_t cacheSize = 0;
Require(sceFontDettachDeviceCacheBuffer(nullptr, &cacheBuffer, &cacheSize) == SCE_FONT_ERROR_INVALID_LIBRARY);
Require(sceFontDettachDeviceCacheBuffer(&notALibrary, &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<unsigned char> callerCache(0x2000);
Require(sceFontAttachDeviceCacheBuffer(library, callerCache.data(), 0x1000) == SCE_FONT_ERROR_INVALID_PARAMETER);
Require(sceFontAttachDeviceCacheBuffer(library, callerCache.data(), static_cast<std::uint32_t>(callerCache.size())) == SCE_FONT_OK);
Require(sceFontAttachDeviceCacheBuffer(library, callerCache.data(), static_cast<std::uint32_t>(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());
Require(sceFontDettachDeviceCacheBuffer(library, &cacheBuffer, &cacheSize) == SCE_FONT_ERROR_NOT_ATTACHED_CACHE_BUFFER);
Require(sceFontAttachDeviceCacheBuffer(library, nullptr, 0x2000) == SCE_FONT_OK);
cacheBuffer = nullptr;
cacheSize = 0;
Require(sceFontDettachDeviceCacheBuffer(library, &cacheBuffer, &cacheSize) == SCE_FONT_OK && cacheBuffer != nullptr && cacheSize == 0x2000);
Release(nullptr, cacheBuffer);
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<FontHandle>(&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<FontHandle>(&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<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);
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<std::uint32_t>(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);
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<unsigned char> kerningData = KerningFont();
font = nullptr;
Require(sceFontOpenFontMemory(library, kerningData.data(), static_cast<std::uint32_t>(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 == 1);
Require(sceFontGetCharGlyphCode(font, 'V', &glyphCode) == SCE_FONT_OK && glyphCode == 2);
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);
int glyphAttribute = -1;
Require(sceFontGlyphDefineAttribute(glyph, 0x11, &glyphAttribute) == SCE_FONT_OK && glyphAttribute == 0);
Require(sceFontGlyphGetAttribute(glyph, 0x11, &glyphAttribute) == SCE_FONT_OK && glyphAttribute == 0x11);
glyphAttribute = -1;
Require(sceFontGlyphDefineAttribute(glyph, 0, &glyphAttribute) == SCE_FONT_OK && glyphAttribute == 0x11);
Require(sceFontGlyphDefineAttribute(glyph, 5, nullptr) == SCE_FONT_OK);
glyphAttribute = -1;
Require(sceFontGlyphGetAttribute(glyph, 0, &glyphAttribute) == SCE_FONT_OK && glyphAttribute == 5);
Require(sceFontGlyphGetAttribute(glyph, 0x11, nullptr) == SCE_FONT_ERROR_INVALID_PARAMETER);
glyphAttribute = -1;
Require(sceFontGlyphDefineAttribute(nullptr, 0x11, &glyphAttribute) == SCE_FONT_ERROR_INVALID_GLYPH && glyphAttribute == -1);
Require(sceFontGlyphGetAttribute(nullptr, 0x11, &glyphAttribute) == SCE_FONT_ERROR_INVALID_GLYPH && glyphAttribute == -1);
FontGlyphOpaque notAGlyph{};
Require(sceFontGlyphDefineAttribute(&notAGlyph, 0x11, &glyphAttribute) == SCE_FONT_ERROR_INVALID_GLYPH);
Require(sceFontGlyphGetAttribute(&notAGlyph, 0x11, &glyphAttribute) == SCE_FONT_ERROR_INVALID_GLYPH);
FontGlyph otherGlyph = nullptr;
Require(sceFontGenerateCharGlyph(font, 'V', nullptr, &otherGlyph) == SCE_FONT_OK && otherGlyph != nullptr);
glyphAttribute = -1;
Require(sceFontGlyphGetAttribute(otherGlyph, 0, &glyphAttribute) == SCE_FONT_OK && glyphAttribute == 0);
Require(sceFontGlyphDefineAttribute(otherGlyph, 9, &glyphAttribute) == SCE_FONT_OK && glyphAttribute == 0);
glyphAttribute = -1;
Require(sceFontGlyphGetAttribute(otherGlyph, 0, &glyphAttribute) == SCE_FONT_OK && glyphAttribute == 9);
Require(sceFontGlyphGetAttribute(glyph, 0, &glyphAttribute) == SCE_FONT_OK && glyphAttribute == 5);
Require(sceFontDeleteGlyph(&memory, &otherGlyph) == SCE_FONT_OK && otherGlyph == nullptr);
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<const FontWritingLetterStep*>(&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);
}