feat(font): implement sceFontGetResolutionDpi

Report the horizontal and vertical resolution kept in the font handle's
style block, as set when the font is opened (72 dpi) or by
sceFontSetResolutionDpi. Error handling follows the other handle getters:
an invalid handle or two null outputs fail and clear the outputs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
DotDebian 2026-10-04 17:59:31 +02:00
parent 2cf901bcff
commit cd6c20f783
3 changed files with 78 additions and 5 deletions

View File

@ -56,6 +56,11 @@ void ResetScaleOutputs(float* w, float* h) {
if (h) *h = 0.0f;
}
void ResetDpiOutputs(std::uint32_t* hDpi, std::uint32_t* vDpi) {
if (hDpi) *hDpi = 0;
if (vDpi) *vDpi = 0;
}
void ResetWeightOutputs(float* weightXScale, float* weightYScale, std::uint32_t* mode) {
if (weightXScale) *weightXScale = 1.0f;
if (weightYScale) *weightYScale = 1.0f;
@ -117,6 +122,17 @@ int APS5_VABI sceFontGetScalePoint(FontHandle fontHandle, float* w, float* h) {
return rc;
}
int APS5_VABI sceFontGetResolutionDpi(FontHandle fontHandle, std::uint32_t* hDpi, std::uint32_t* vDpi) {
const int rc = ReadFontStyle(fontHandle, true, [&](FontHandleNative* font) {
if (!hDpi && !vDpi) return SCE_FONT_ERROR_INVALID_PARAMETER;
if (hDpi) *hDpi = font->style.dpi_x;
if (vDpi) *vDpi = font->style.dpi_y;
return SCE_FONT_OK;
});
if (rc != SCE_FONT_OK) ResetDpiOutputs(hDpi, vDpi);
return rc;
}
int APS5_VABI sceFontGetEffectSlant(FontHandle fontHandle, float* slantRatio) {
const int rc = ReadFontStyle(fontHandle, true, [&](FontHandleNative* font) { return StyleStateGetSlantRatio(&font->style, slantRatio); });
if (rc != SCE_FONT_OK && slantRatio) *slantRatio = 0.0f;

View File

@ -127,11 +127,6 @@ int APS5_VABI sceFontGetRenderScaledKerning() {
return 0;
}
int APS5_VABI sceFontGetResolutionDpi() {
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI sceFontGetScriptLanguage() {
NotImplemented_nid_no_patch(__func__);
return 0;

View File

@ -1,7 +1,11 @@
#include "prx/libSceFont/include/FontTypes.hpp"
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <initializer_list>
#include <utility>
#include <vector>
extern "C" {
int APS5_VABI sceFontMemoryInit(FontMemory*, void*, std::uint32_t, const FontMemoryInterface*, void*, FontMemoryDestroyFunction, void*);
@ -14,6 +18,9 @@ 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 sceFontCloseFont(FontHandle);
int APS5_VABI sceFontSetResolutionDpi(FontHandle, std::uint32_t, std::uint32_t);
int APS5_VABI sceFontGetResolutionDpi(FontHandle, std::uint32_t*, std::uint32_t*);
const void* APS5_VABI sceFontSelectLibraryFt(int);
const void* APS5_VABI sceFontSelectRendererFt(int);
}
@ -36,6 +43,40 @@ static void APS5_VABI Release(void*, void* pointer) {
std::free(pointer);
}
static void Put16(std::vector<unsigned char>& out, int value) {
out.push_back(static_cast<unsigned char>((value >> 8) & 0xFF));
out.push_back(static_cast<unsigned char>(value & 0xFF));
}
static std::vector<unsigned char> Words(std::initializer_list<int> values) {
std::vector<unsigned char> out;
for (const int value : values) Put16(out, value);
return out;
}
static std::vector<unsigned char> EmptyGlyphFont() {
const std::vector<std::pair<const char*, std::vector<unsigned char>>> tables = {
{"glyf", Words({0, 0})},
{"head", Words({1, 0, 1, 0, 0, 0, 0x5F0F, 0x3CF5, 0, 1000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 2, 0, 0})},
{"hhea", Words({1, 0, 800, -200, 0, 500, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1})},
{"hmtx", Words({500, 0})},
{"loca", Words({0, 0})},
{"maxp", Words({1, 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0})},
};
std::vector<unsigned char> font = Words({1, 0, static_cast<int>(tables.size()), 64, 2, 32});
int offset = 12 + 16 * static_cast<int>(tables.size());
for (const auto& table : tables) {
font.insert(font.end(), table.first, table.first + 4);
for (const int value : {0, 0, offset >> 16, offset & 0xFFFF, 0, static_cast<int>(table.second.size())}) Put16(font, value);
offset += static_cast<int>((table.second.size() + 3) & ~std::size_t{3});
}
for (const auto& table : tables) {
font.insert(font.end(), table.second.begin(), table.second.end());
font.resize((font.size() + 3) & ~std::size_t{3});
}
return font;
}
int main() {
constexpr std::uint32_t SystemFontSet = 0x18070043u;
const FontMemoryInterface iface{Allocate, Release, nullptr, nullptr, nullptr, nullptr};
@ -62,6 +103,27 @@ int main() {
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);
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);
Require(sceFontCloseFont(font) == SCE_FONT_OK);
FontRenderer renderer = nullptr;
Require(sceFontCreateRenderer(&memory, sceFontSelectRendererFt(0), &renderer) == SCE_FONT_OK && renderer != nullptr);
Require(sceFontDestroyRenderer(&renderer) == SCE_FONT_OK && renderer == nullptr);