// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include #include #include "prx/libSceFont/include/FontInternal.hpp" namespace { using namespace Font; template int UpdateFontStyle(FontHandle fontHandle, Setter&& setter) { auto* font = GetNativeFont(fontHandle); std::uint32_t fontLock = 0; if (!font || font->magic != HANDLE_MAGIC || !AcquireFontLock(font, fontLock)) return SCE_FONT_ERROR_INVALID_FONT_HANDLE; if (setter(font) != 0) font->cached_style.layout_cache_state = 0; ReleaseFontLock(font, fontLock); return SCE_FONT_OK; } template int UpdateRenderStyle(FontHandle fontHandle, Setter&& setter) { auto* font = GetNativeFont(fontHandle); std::uint32_t cachedLock = 0; if (!font || font->magic != HANDLE_MAGIC || !AcquireCachedStyleLock(font, cachedLock)) return SCE_FONT_ERROR_INVALID_FONT_HANDLE; int rc = SCE_FONT_ERROR_NOT_BOUND_RENDERER; if (font->renderer) rc = setter(font); ReleaseCachedStyleLock(font, cachedLock); return rc; } template int ReadRenderStyle(FontHandle fontHandle, bool checkMagic, Getter&& getter) { auto* font = GetNativeFont(fontHandle); std::uint32_t cachedLock = 0; if (!font || (checkMagic && font->magic != HANDLE_MAGIC) || !AcquireCachedStyleLock(font, cachedLock)) return SCE_FONT_ERROR_INVALID_FONT_HANDLE; const int rc = font->renderer ? getter(font) : SCE_FONT_ERROR_NOT_BOUND_RENDERER; ReleaseCachedStyleLock(font, cachedLock); return rc; } template int ReadFontStyle(FontHandle fontHandle, bool checkMagic, Getter&& getter) { auto* font = GetNativeFont(fontHandle); std::uint32_t fontLock = 0; if (!font || (checkMagic && font->magic != HANDLE_MAGIC) || !AcquireFontLock(font, fontLock)) return SCE_FONT_ERROR_INVALID_FONT_HANDLE; const int rc = getter(font); ReleaseFontLock(font, fontLock); return rc; } template 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 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 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; } 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; if (mode) *mode = 0; } float ClampWeightDelta(float scale) { return std::clamp(scale - 1.0f, -0.04f, 0.04f); } } #pragma GCC visibility push(default) 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); if (FontState* state = TryGetState(fontHandle)) { state->scaleW = w; state->scaleH = h; } return changed; }); } int APS5_VABI sceFontSetScalePoint(FontHandle fontHandle, float w, float h) { return UpdateFontStyle(fontHandle, [&](FontHandleNative* font) { return StyleStateSetScalePoint(&font->style, w, h); }); } int APS5_VABI sceFontSetResolutionDpi(FontHandle fontHandle, std::uint32_t hDpi, std::uint32_t vDpi) { auto* font = GetNativeFont(fontHandle); std::uint32_t fontLock = 0; if (!font || !AcquireFontLock(font, fontLock)) return SCE_FONT_ERROR_INVALID_FONT_HANDLE; if (StyleStateSetDpi(&font->style, hDpi, vDpi) != 0) font->cached_style.layout_cache_state = 0; ReleaseFontLock(font, fontLock); return SCE_FONT_OK; } int APS5_VABI sceFontSetEffectSlant(FontHandle fontHandle, float slantRatio) { return UpdateFontStyle(fontHandle, [&](FontHandleNative* font) { return StyleStateSetSlantRatio(&font->style, slantRatio); }); } int APS5_VABI sceFontSetEffectWeight(FontHandle fontHandle, float weightXScale, float weightYScale, std::uint32_t mode) { if (mode != 0) return SCE_FONT_ERROR_INVALID_PARAMETER; return UpdateFontStyle(fontHandle, [&](FontHandleNative* font) { return StyleStateSetWeightScale(&font->style, weightXScale, weightYScale); }); } int APS5_VABI sceFontGetScalePixel(FontHandle fontHandle, float* w, float* h) { const int rc = ReadFontStyle(fontHandle, true, [&](FontHandleNative* font) { return StyleStateGetScalePixel(&font->style, w, h); }); if (rc != SCE_FONT_OK) ResetScaleOutputs(w, h); return rc; } int APS5_VABI sceFontGetScalePoint(FontHandle fontHandle, float* w, float* h) { const int rc = ReadFontStyle(fontHandle, false, [&](FontHandleNative* font) { return StyleStateGetScalePoint(&font->style, w, h); }); if (rc != SCE_FONT_OK) ResetScaleOutputs(w, 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; return rc; } int APS5_VABI sceFontGetEffectWeight(FontHandle fontHandle, float* weightXScale, float* weightYScale, std::uint32_t* mode) { const int rc = ReadFontStyle(fontHandle, true, [&](FontHandleNative* font) { return StyleStateGetWeightScale(&font->style, weightXScale, weightYScale, mode); }); if (rc != SCE_FONT_OK) ResetWeightOutputs(weightXScale, weightYScale, mode); return rc; } int APS5_VABI sceFontSetupRenderScalePixel(FontHandle fontHandle, float w, float h) { return UpdateRenderStyle(fontHandle, [&](FontHandleNative* font) { if (StyleStateSetScalePixel(&font->cached_style.state, w, h) != 0) font->cached_style.cache_flags_and_direction &= 0xFFFF0000u; return SCE_FONT_OK; }); } int APS5_VABI sceFontSetupRenderScalePoint(FontHandle fontHandle, float w, float h) { return UpdateRenderStyle(fontHandle, [&](FontHandleNative* font) { if (StyleStateSetScalePoint(&font->cached_style.state, w, h) != 0) font->cached_style.cache_flags_and_direction &= 0xFFFF0000u; return SCE_FONT_OK; }); } int APS5_VABI sceFontSetupRenderEffectSlant(FontHandle fontHandle, float slantRatio) { return UpdateRenderStyle(fontHandle, [&](FontHandleNative* font) { if (StyleStateSetSlantRatio(&font->cached_style.state, slantRatio) != 0) font->cached_style.cache_flags_and_direction &= 0xFFFF0000u; return SCE_FONT_OK; }); } int APS5_VABI sceFontSetupRenderEffectWeight(FontHandle fontHandle, float weightXScale, float weightYScale, std::uint32_t mode) { return UpdateRenderStyle(fontHandle, [&](FontHandleNative* font) { if (mode != 0) return SCE_FONT_ERROR_INVALID_PARAMETER; if (StyleStateSetWeightScale(&font->cached_style.state, weightXScale, weightYScale) != 0) font->cached_style.cache_flags_and_direction &= 0xFFFF0000u; return SCE_FONT_OK; }); } int APS5_VABI sceFontGetRenderScalePixel(FontHandle fontHandle, float* w, float* h) { const int rc = ReadRenderStyle(fontHandle, false, [&](FontHandleNative* font) { return StyleStateGetScalePixel(&font->cached_style.state, w, h); }); if (rc != SCE_FONT_OK) ResetScaleOutputs(w, h); return rc; } int APS5_VABI sceFontGetRenderScalePoint(FontHandle fontHandle, float* w, float* h) { const int rc = ReadRenderStyle(fontHandle, false, [&](FontHandleNative* font) { return StyleStateGetScalePoint(&font->cached_style.state, w, h); }); if (rc != SCE_FONT_OK) ResetScaleOutputs(w, h); return rc; } int APS5_VABI sceFontGetRenderEffectSlant(FontHandle fontHandle, float* slantRatio) { const int rc = ReadRenderStyle(fontHandle, true, [&](FontHandleNative* font) { return StyleStateGetSlantRatio(&font->cached_style.state, slantRatio); }); if (rc != SCE_FONT_OK && slantRatio) *slantRatio = 0.0f; return rc; } int APS5_VABI sceFontGetRenderEffectWeight(FontHandle fontHandle, float* weightXScale, float* weightYScale, std::uint32_t* mode) { const int rc = ReadRenderStyle(fontHandle, true, [&](FontHandleNative* font) { return StyleStateGetWeightScale(&font->cached_style.state, weightXScale, weightYScale, mode); }); if (rc != SCE_FONT_OK) ResetWeightOutputs(weightXScale, weightYScale, mode); return rc; } int APS5_VABI sceFontStyleFrameInit(FontStyleFrame* styleFrame) { if (!styleFrame) return SCE_FONT_ERROR_INVALID_PARAMETER; std::memset(&styleFrame->scaleUnit, 0, 0x20); std::memset(&styleFrame->layout_cache_state, 0, 0x20); std::memset(&styleFrame->layout_cache_bytes[0x08], 0, 0x20); styleFrame->magic = STYLE_FRAME_MAGIC; styleFrame->flags1 = 0; styleFrame->flags2 = 0; styleFrame->hDpi = 0x48; styleFrame->vDpi = 0x48; return SCE_FONT_OK; } int APS5_VABI sceFontStyleFrameSetScalePixel(FontStyleFrame* styleFrame, float w, float h) { if (!ValidStyleFrame(styleFrame)) return SCE_FONT_ERROR_INVALID_PARAMETER; styleFrame->scaleUnit = 0; styleFrame->scalePixelW = w; styleFrame->scalePixelH = h; styleFrame->flags1 |= STYLE_FRAME_FLAG_SCALE; return SCE_FONT_OK; } int APS5_VABI sceFontStyleFrameSetScalePoint(FontStyleFrame* styleFrame, float w, float h) { if (!ValidStyleFrame(styleFrame)) return SCE_FONT_ERROR_INVALID_PARAMETER; styleFrame->scaleUnit = 1; styleFrame->scalePixelW = w; styleFrame->scalePixelH = h; styleFrame->flags1 |= STYLE_FRAME_FLAG_SCALE; return SCE_FONT_OK; } int APS5_VABI sceFontStyleFrameSetResolutionDpi(FontStyleFrame* styleFrame, std::uint32_t hDpi, std::uint32_t vDpi) { if (!ValidStyleFrame(styleFrame)) return SCE_FONT_ERROR_INVALID_PARAMETER; styleFrame->hDpi = hDpi == 0 ? 0x48 : hDpi; styleFrame->vDpi = vDpi == 0 ? 0x48 : vDpi; return SCE_FONT_OK; } int APS5_VABI sceFontStyleFrameSetEffectSlant(FontStyleFrame* styleFrame, float slantRatio) { if (!ValidStyleFrame(styleFrame)) return SCE_FONT_ERROR_INVALID_PARAMETER; styleFrame->slantRatio = std::clamp(slantRatio, -1.0f, 1.0f); styleFrame->flags1 |= STYLE_FRAME_FLAG_SLANT; return SCE_FONT_OK; } int APS5_VABI sceFontStyleFrameSetEffectWeight(FontStyleFrame* styleFrame, float weightXScale, float weightYScale, std::uint32_t mode) { if (!ValidStyleFrame(styleFrame) || mode != 0) return SCE_FONT_ERROR_INVALID_PARAMETER; styleFrame->effectWeightX = ClampWeightDelta(weightXScale); styleFrame->effectWeightY = ClampWeightDelta(weightYScale); styleFrame->flags1 |= STYLE_FRAME_FLAG_WEIGHT; return SCE_FONT_OK; } int APS5_VABI sceFontStyleFrameUnsetScale(FontStyleFrame* styleFrame) { if (!ValidStyleFrame(styleFrame)) return SCE_FONT_ERROR_INVALID_PARAMETER; styleFrame->flags1 &= static_cast(~STYLE_FRAME_FLAG_SCALE); return SCE_FONT_OK; } int APS5_VABI sceFontStyleFrameUnsetEffectSlant(FontStyleFrame* styleFrame) { if (!ValidStyleFrame(styleFrame)) return SCE_FONT_ERROR_INVALID_PARAMETER; styleFrame->flags1 &= static_cast(~STYLE_FRAME_FLAG_SLANT); return SCE_FONT_OK; } int APS5_VABI sceFontStyleFrameUnsetEffectWeight(FontStyleFrame* styleFrame) { if (!ValidStyleFrame(styleFrame)) return SCE_FONT_ERROR_INVALID_PARAMETER; styleFrame->flags1 &= static_cast(~STYLE_FRAME_FLAG_WEIGHT); return SCE_FONT_OK; } int APS5_VABI sceFontStyleFrameGetScalePixel(const FontStyleFrame* styleFrame, float* w, float* h) { if (!ValidStyleFrame(styleFrame)) return SCE_FONT_ERROR_INVALID_PARAMETER; if ((styleFrame->flags1 & STYLE_FRAME_FLAG_SCALE) == 0) return SCE_FONT_ERROR_UNSET_PARAMETER; if (!w && !h) return SCE_FONT_ERROR_INVALID_PARAMETER; const bool points = styleFrame->scaleUnit != 0; if (w) *w = points && styleFrame->hDpi != 0 ? styleFrame->scalePixelW * (static_cast(styleFrame->hDpi) / POINTS_PER_INCH) : styleFrame->scalePixelW; if (h) *h = points && styleFrame->vDpi != 0 ? styleFrame->scalePixelH * (static_cast(styleFrame->vDpi) / POINTS_PER_INCH) : styleFrame->scalePixelH; return SCE_FONT_OK; } int APS5_VABI sceFontStyleFrameGetScalePoint(const FontStyleFrame* styleFrame, float* w, float* h) { if (!ValidStyleFrame(styleFrame)) return SCE_FONT_ERROR_INVALID_PARAMETER; if ((styleFrame->flags1 & STYLE_FRAME_FLAG_SCALE) == 0) return SCE_FONT_ERROR_UNSET_PARAMETER; if (!w && !h) return SCE_FONT_ERROR_INVALID_PARAMETER; const bool pixels = styleFrame->scaleUnit == 0; if (w) *w = pixels && styleFrame->hDpi != 0 ? styleFrame->scalePixelW * (POINTS_PER_INCH / static_cast(styleFrame->hDpi)) : styleFrame->scalePixelW; if (h) *h = pixels && styleFrame->vDpi != 0 ? styleFrame->scalePixelH * (POINTS_PER_INCH / static_cast(styleFrame->vDpi)) : styleFrame->scalePixelH; return SCE_FONT_OK; } int APS5_VABI sceFontStyleFrameGetResolutionDpi(const FontStyleFrame* styleFrame, std::uint32_t* hDpi, std::uint32_t* vDpi) { if (!ValidStyleFrame(styleFrame) || (!hDpi && !vDpi)) return SCE_FONT_ERROR_INVALID_PARAMETER; if (hDpi) *hDpi = styleFrame->hDpi; if (vDpi) *vDpi = styleFrame->vDpi; return SCE_FONT_OK; } int APS5_VABI sceFontStyleFrameGetEffectSlant(const FontStyleFrame* styleFrame, float* slantRatio) { if (!ValidStyleFrame(styleFrame)) return SCE_FONT_ERROR_INVALID_PARAMETER; if ((styleFrame->flags1 & STYLE_FRAME_FLAG_SLANT) == 0) return SCE_FONT_ERROR_UNSET_PARAMETER; if (!slantRatio) return SCE_FONT_ERROR_INVALID_PARAMETER; *slantRatio = styleFrame->slantRatio; return SCE_FONT_OK; } int APS5_VABI sceFontStyleFrameGetEffectWeight(const FontStyleFrame* styleFrame, float* weightXScale, float* weightYScale, std::uint32_t* mode) { if (!ValidStyleFrame(styleFrame)) return SCE_FONT_ERROR_INVALID_PARAMETER; if ((styleFrame->flags1 & STYLE_FRAME_FLAG_WEIGHT) == 0) return SCE_FONT_ERROR_UNSET_PARAMETER; if (!weightXScale && !weightYScale && !mode) return SCE_FONT_ERROR_INVALID_PARAMETER; if (weightXScale) *weightXScale = styleFrame->effectWeightX + 1.0f; if (weightYScale) *weightYScale = styleFrame->effectWeightY + 1.0f; if (mode) *mode = 0; return SCE_FONT_OK; } } #pragma GCC visibility pop