Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions core/libs/prx/libSceFont/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ if(BUILD_TESTING)
add_test_executable(guest_font_tests ${LIBS_INCLUDE_DIR}/tests/GuestFont.cpp)
target_include_directories(guest_font_tests PRIVATE ${LIBS_INCLUDE_DIR})
target_link_libraries(guest_font_tests PRIVATE libSceFont libSceFontFt libc)
configure_windows_unwind(guest_font_tests)
add_test(NAME guest_font COMMAND guest_font_tests)
add_test_executable(guest_system_font_tests ${LIBS_INCLUDE_DIR}/tests/GuestSystemFont.cpp)
target_include_directories(guest_system_font_tests PRIVATE ${LIBS_INCLUDE_DIR})
Expand All @@ -24,4 +25,13 @@ if(BUILD_TESTING)
set_tests_properties(guest_font_writing_line PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceFont>")
endif()
add_test_executable(guest_font_text_tests ${LIBS_INCLUDE_DIR}/tests/GuestFontText.cpp)
target_include_directories(guest_font_text_tests PRIVATE ${LIBS_INCLUDE_DIR})
target_link_libraries(guest_font_text_tests PRIVATE libSceFont libc)
configure_windows_unwind(guest_font_text_tests)
add_test(NAME guest_font_text COMMAND guest_font_text_tests)
if(WIN32)
set_tests_properties(guest_font_text PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceFont>")
endif()
endif()
9 changes: 9 additions & 0 deletions core/libs/prx/libSceFont/include/FontTypes.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,13 @@ struct FontTextCharacter {
std::uint8_t reserved_0x40[136];
};

struct FontTextCodes {
void* textOrder;
std::uint32_t textCode;
std::uint32_t reserved;
void* systemUse[6];
};

struct FontRenderSurface {
void* buffer;
std::int32_t widthByte;
Expand Down Expand Up @@ -427,6 +434,8 @@ static_assert(sizeof(FontSurfaceImage) == 0x10);
static_assert(sizeof(FontRenderOutput) == 0x40);
static_assert(sizeof(FontTextCharacter) == 0xC8);
static_assert(offsetof(FontTextCharacter, flags) == 0x38);
static_assert(sizeof(FontTextCodes) == 0x40);
static_assert(offsetof(FontTextCodes, textCode) == 0x08);
static_assert(sizeof(FontRenderSurface) == 0x80);
static_assert(sizeof(FontStyleFrame) == 0x60);
static_assert(offsetof(FontStyleFrame, scalePixelW) == 0x14);
Expand Down
86 changes: 86 additions & 0 deletions core/libs/prx/libSceFont/src/Style.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,59 @@
// SPDX-License-Identifier: GPL-2.0-or-later

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <stdexcept>
#include <string>

#include "prx/libSceFont/include/FontInternal.hpp"

namespace {

using namespace Font;

constexpr std::uint16_t HANDLE_WRITING_VERTICAL = 0x8000;
constexpr int ATTRIBUTE_NONE = 0;
constexpr int ATTRIBUTE_WRITING_HORIZONTAL = 0x40;
constexpr int ATTRIBUTE_WRITING_VERTICAL = 0x41;
constexpr int ATTRIBUTE_RENDER_DETAIL_NO_ADJOIN = 0x10;
constexpr int ATTRIBUTE_RENDER_DETAIL_ADJOIN = 0x11;
constexpr int ATTRIBUTE_VERTICAL_NO_EXCLUSIVE = 0x20;
constexpr int ATTRIBUTE_VERTICAL_EXCLUSIVE = 0x21;
constexpr int ATTRIBUTE_VERTICAL_ROTATION_ENABLE = 0x30;
constexpr int ATTRIBUTE_VERTICAL_ROTATION_DISABLE = 0x31;

[[noreturn]] void Unsupported(const char* function, const std::string& what) {
throw std::runtime_error(std::string(function) + ": " + what);
}

std::string AttributeName(int attribute) {
char name[16];
std::snprintf(name, sizeof(name), "0x%X", static_cast<unsigned>(attribute));
return name;
}

void CheckWritingAttribute(const char* function, int attribute) {
switch (attribute) {
case ATTRIBUTE_WRITING_HORIZONTAL:
case ATTRIBUTE_WRITING_VERTICAL:
return;
case ATTRIBUTE_RENDER_DETAIL_NO_ADJOIN:
case ATTRIBUTE_RENDER_DETAIL_ADJOIN:
case ATTRIBUTE_VERTICAL_NO_EXCLUSIVE:
case ATTRIBUTE_VERTICAL_EXCLUSIVE:
case ATTRIBUTE_VERTICAL_ROTATION_ENABLE:
case ATTRIBUTE_VERTICAL_ROTATION_DISABLE:
Unsupported(function, "attribute " + AttributeName(attribute) + " is not modelled");
default:
Unsupported(function, "unknown attribute " + AttributeName(attribute) + " (error code not verified)");
}
}

int WritingAttribute(const FontHandleNative* font) {
return (font->flags & HANDLE_WRITING_VERTICAL) != 0 ? ATTRIBUTE_WRITING_VERTICAL : ATTRIBUTE_WRITING_HORIZONTAL;
}

template<typename Setter>
int UpdateFontStyle(FontHandle fontHandle, Setter&& setter) {
auto* font = GetNativeFont(fontHandle);
Expand Down Expand Up @@ -145,6 +190,47 @@ int APS5_VABI sceFontGetEffectWeight(FontHandle fontHandle, float* weightXScale,
return rc;
}

int APS5_VABI sceFontDefineAttribute(FontHandle fontHandle, int attribute, int* oldAttribute) {
auto* font = GetNativeFont(fontHandle);
std::uint32_t fontLock = 0;
if (!font || font->magic != HANDLE_MAGIC) {
if (oldAttribute) *oldAttribute = ATTRIBUTE_NONE;
return SCE_FONT_ERROR_INVALID_FONT_HANDLE;
}
CheckWritingAttribute(__func__, attribute);
if (!AcquireFontLock(font, fontLock)) {
if (oldAttribute) *oldAttribute = ATTRIBUTE_NONE;
return SCE_FONT_ERROR_INVALID_FONT_HANDLE;
}
const int previous = WritingAttribute(font);
if (attribute == ATTRIBUTE_WRITING_VERTICAL) {
font->flags = static_cast<std::uint16_t>(font->flags | HANDLE_WRITING_VERTICAL);
} else {
font->flags = static_cast<std::uint16_t>(font->flags & ~HANDLE_WRITING_VERTICAL);
}
ReleaseFontLock(font, fontLock);
if (oldAttribute) *oldAttribute = previous;
return SCE_FONT_OK;
}

int APS5_VABI sceFontGetAttribute(FontHandle fontHandle, int attribute, int* nowAttribute) {
if (!nowAttribute) return SCE_FONT_ERROR_INVALID_PARAMETER;
auto* font = GetNativeFont(fontHandle);
std::uint32_t fontLock = 0;
if (!font || font->magic != HANDLE_MAGIC) {
*nowAttribute = ATTRIBUTE_NONE;
return SCE_FONT_ERROR_INVALID_FONT_HANDLE;
}
CheckWritingAttribute(__func__, attribute);
if (!AcquireFontLock(font, fontLock)) {
*nowAttribute = ATTRIBUTE_NONE;
return SCE_FONT_ERROR_INVALID_FONT_HANDLE;
}
*nowAttribute = WritingAttribute(font);
ReleaseFontLock(font, fontLock);
return SCE_FONT_OK;
}

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;
Expand Down
87 changes: 87 additions & 0 deletions core/libs/prx/libSceFont/src/Text.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@
#include <algorithm>
#include <atomic>
#include <cstddef>
#include <cstdio>
#include <cstring>
#include <iterator>
#include <new>
#include <stdexcept>
#include <string>
#include <vector>

#include "prx/libSceFont/include/FontInternal.hpp"
Expand All @@ -27,6 +31,56 @@ constexpr std::size_t MAX_PARSED_CHARACTERS = 4096;
constexpr std::int32_t WRITING_MASK_NONE = 0;
constexpr std::int32_t WRITING_MASK_FORMAT_CHARACTERS = 1;
constexpr std::uint64_t CHARACTER_FLAG_FORMAT = 1ull << 42;
constexpr std::uint64_t TEXT_CODES_TAG = 0x5345444F43545854ull;
constexpr int SYLLABLE_STRING_NON_DETECTION = 0;

struct TextCodesState {
std::uint64_t tag;
FontTextCharacter* current;
const FontTextCharacter* term;
};

static_assert(sizeof(TextCodesState) <= sizeof(FontTextCodes::systemUse));

[[noreturn]] void Unsupported(const char* function, const std::string& what) {
throw std::runtime_error(std::string(function) + ": " + what);
}

std::string CodeName(std::uint32_t code) {
char name[16];
std::snprintf(name, sizeof(name), "U+%04X", static_cast<unsigned>(code));
return name;
}

FontTextCodes* SetTextCodesStep(FontTextCodes* textCodes, FontTextCharacter* character, const FontTextCharacter* term) {
textCodes->textOrder = character->textOrder;
textCodes->textCode = character->characterCode;
const TextCodesState state{TEXT_CODES_TAG, character, term};
std::memcpy(textCodes->systemUse, &state, sizeof(state));
return textCodes;
}

TextCodesState GetTextCodesStep(const char* function, const FontTextCodes* textCodesStep) {
TextCodesState state{};
std::memcpy(&state, textCodesStep->systemUse, sizeof(state));
if (state.tag != TEXT_CODES_TAG || !state.current) Unsupported(function, "text codes step not set up by sceFontCharactersRefersTextCodes");
return state;
}

bool IsSyllableFreeCode(std::uint32_t code) {
struct Range {
std::uint32_t first;
std::uint32_t last;
};
static constexpr Range ranges[] = {
{0x0000, 0x00AC}, {0x00AE, 0x02FF}, {0x0370, 0x03FF}, {0x0400, 0x0482}, {0x048A, 0x052F},
{0x1E00, 0x1FFF}, {0x2000, 0x200A}, {0x2010, 0x2027}, {0x202F, 0x205F}, {0x2070, 0x20CF},
{0x2100, 0x2BFF}, {0x3000, 0x3029}, {0x3030, 0x303F}, {0x3041, 0x3096}, {0x309B, 0x30FF},
{0x31F0, 0x31FF}, {0x3400, 0x4DBF}, {0x4E00, 0x9FFF}, {0xF900, 0xFAFF}, {0xFF01, 0xFF9D},
{0xFFE0, 0xFFEE}, {0x20000, 0x3FFFF},
};
return std::any_of(std::begin(ranges), std::end(ranges), [code](const Range& range) { return code >= range.first && code <= range.last; });
}

struct CharacterStorage {
std::atomic<std::uint32_t> refCount{1};
Expand Down Expand Up @@ -539,6 +593,39 @@ FontTextCharacter* APS5_VABI sceFontCharacterRefersTextNext(const FontTextCharac
return nullptr;
}

int APS5_VABI sceFontCharacterGetSyllableStringState(const FontTextCharacter* textCharacter, int* syllableStringState) {
if (!textCharacter || !syllableStringState) return SCE_FONT_ERROR_INVALID_PARAMETER;
const FontTextCharacter* const neighbourhood[] = {textCharacter->prev, textCharacter, textCharacter->next};
for (const FontTextCharacter* character : neighbourhood) {
if (character && !IsSyllableFreeCode(character->characterCode)) Unsupported(__func__, "syllable detection next to " + CodeName(character->characterCode) + " is not modelled");
}
*syllableStringState = SYLLABLE_STRING_NON_DETECTION;
return SCE_FONT_OK;
}

FontTextCodes* APS5_VABI sceFontCharactersRefersTextCodes(const FontTextCharacter* textCharacter, const FontTextCharacter* termCharacter, FontTextCodes* textCodes) {
if (!textCodes || !textCharacter) return nullptr;
if (textCharacter == termCharacter) Unsupported(__func__, "a start character equal to the term character is not modelled");
std::memset(textCodes, 0, sizeof(*textCodes));
return SetTextCodesStep(textCodes, const_cast<FontTextCharacter*>(textCharacter), termCharacter);
}

FontTextCodes* APS5_VABI sceFontTextCodesStepNext(FontTextCodes* textCodesStep) {
if (!textCodesStep) return nullptr;
const TextCodesState state = GetTextCodesStep(__func__, textCodesStep);
FontTextCharacter* next = state.current->next;
if (!next || next == state.term) return nullptr;
return SetTextCodesStep(textCodesStep, next, state.term);
}

FontTextCodes* APS5_VABI sceFontTextCodesStepBack(FontTextCodes* textCodesStep) {
if (!textCodesStep) return nullptr;
const TextCodesState state = GetTextCodesStep(__func__, textCodesStep);
FontTextCharacter* previous = state.current->prev;
if (!previous) return nullptr;
return SetTextCodesStep(textCodesStep, previous, state.term);
}

int APS5_VABI sceFontWritingInit(FontWriting* fontWriting, FontString fontString, const FontTextCharacter* fontCharacter) {
if (!fontWriting || !fontString || !fontCharacter) return SCE_FONT_ERROR_INVALID_PARAMETER;
auto* data = GetStringData(fontString);
Expand Down
30 changes: 0 additions & 30 deletions core/libs/prx/libSceFont/src/Unimplemented.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,6 @@

extern "C" {

int APS5_VABI sceFontCharacterGetSyllableStringState() {
NotImplemented_nid_no_patch(__func__);
return 0;
}

int APS5_VABI sceFontCharactersRefersTextCodes() {
NotImplemented_nid_no_patch(__func__);
return 0;
}

int APS5_VABI sceFontControl() {
NotImplemented_nid_no_patch(__func__);
return 0;
Expand All @@ -42,11 +32,6 @@ int APS5_VABI sceFontCreateWords() {
return 0;
}

int APS5_VABI sceFontDefineAttribute() {
NotImplemented_nid_no_patch(__func__);
return 0;
}

int APS5_VABI sceFontDestroyGraphicsDevice() {
NotImplemented_nid_no_patch(__func__);
return 0;
Expand All @@ -63,11 +48,6 @@ int APS5_VABI sceFontDestroyWords() {
}


int APS5_VABI sceFontGetAttribute() {
NotImplemented_nid_no_patch(__func__);
return 0;
}

int APS5_VABI sceFontGetFontGlyphsOutlineProfile() {
NotImplemented_nid_no_patch(__func__);
return 0;
Expand Down Expand Up @@ -383,16 +363,6 @@ int APS5_VABI sceFontSupportGlyphs() {
return 0;
}

int APS5_VABI sceFontTextCodesStepBack() {
NotImplemented_nid_no_patch(__func__);
return 0;
}

int APS5_VABI sceFontTextCodesStepNext() {
NotImplemented_nid_no_patch(__func__);
return 0;
}

int APS5_VABI sceFontWordsFindWordCharacters() {
NotImplemented_nid_no_patch(__func__);
return 0;
Expand Down
Loading
Loading