360 lines
16 KiB
C++
360 lines
16 KiB
C++
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
#include <algorithm>
|
|
#include <cstring>
|
|
|
|
#include "prx/libSceFont/include/FontInternal.hpp"
|
|
|
|
namespace {
|
|
|
|
using namespace Font;
|
|
|
|
template<typename Setter>
|
|
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<typename Setter>
|
|
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<typename Getter>
|
|
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<typename Getter>
|
|
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<typename Access>
|
|
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<int, int> 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<int, int> 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<std::uint8_t>(~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<std::uint8_t>(~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<std::uint8_t>(~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<float>(styleFrame->hDpi) / POINTS_PER_INCH) : styleFrame->scalePixelW;
|
|
if (h) *h = points && styleFrame->vDpi != 0 ? styleFrame->scalePixelH * (static_cast<float>(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<float>(styleFrame->hDpi)) : styleFrame->scalePixelW;
|
|
if (h) *h = pixels && styleFrame->vDpi != 0 ? styleFrame->scalePixelH * (POINTS_PER_INCH / static_cast<float>(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
|