247 lines
14 KiB
C++
247 lines
14 KiB
C++
#include "prx/libSceFont/include/FontTypes.hpp"
|
|
#include <cstdint>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <exception>
|
|
|
|
extern "C" {
|
|
int APS5_VABI sceFontCreateWritingLine(const FontMemory*, std::int32_t, const void*, void**);
|
|
int APS5_VABI sceFontDestroyWritingLine(void**);
|
|
int APS5_VABI sceFontWritingLineClear(void*);
|
|
int APS5_VABI sceFontWritingLineWritesOrder(void*, std::uint64_t, const FontWritingMetrics*, void*);
|
|
const FontWritingLineStep* APS5_VABI sceFontWritingLineRefersRenderStep(void*);
|
|
int APS5_VABI sceFontWritingLineGetRenderMetrics(void*, FontWritingMetrics*);
|
|
int APS5_VABI sceFontWritingLineGetOrderingSpace(void*, float*, float*, float*, float*);
|
|
}
|
|
|
|
static void Check(bool value, int line) {
|
|
if (!value) {
|
|
std::fprintf(stderr, "Font writing line check failed at line %d\n", line);
|
|
std::abort();
|
|
}
|
|
}
|
|
#define Require(value) Check((value), __LINE__)
|
|
|
|
template <typename F>
|
|
static bool Throws(F f) {
|
|
try {
|
|
f();
|
|
} catch (const std::exception&) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
struct WritingLineDetail {
|
|
std::uint16_t detailId;
|
|
std::uint16_t reserved[3];
|
|
void* reservedPointers[3];
|
|
};
|
|
|
|
constexpr std::uint64_t SPACE_BEFORE = std::uint64_t{1} << 30;
|
|
constexpr std::uint64_t SPACE_AFTER = std::uint64_t{1} << 31;
|
|
|
|
static std::uint64_t Attribute(std::uint64_t level, std::uint64_t flags = 0) {
|
|
return 0xFA | (level << 8) | flags;
|
|
}
|
|
|
|
static bool Same(const FontWritingMetrics& a, const FontWritingMetrics& b) {
|
|
return a.advanceX == b.advanceX && a.advanceY == b.advanceY && a.Extent.top == b.Extent.top &&
|
|
a.Extent.bottom == b.Extent.bottom && a.Extent.left == b.Extent.left && a.Extent.right == b.Extent.right;
|
|
}
|
|
|
|
static bool SpaceIs(void* line, float advance, float head, float inner, float tail) {
|
|
float gotAdvance = -1.0f;
|
|
float gotHead = -1.0f;
|
|
float gotInner = -1.0f;
|
|
float gotTail = -1.0f;
|
|
return sceFontWritingLineGetOrderingSpace(line, &gotAdvance, &gotHead, &gotInner, &gotTail) == SCE_FONT_OK && gotAdvance == advance &&
|
|
gotHead == head && gotInner == inner && gotTail == tail;
|
|
}
|
|
|
|
static bool StepIs(const FontWritingLineStep* step, float x, float progress, const FontWritingMetrics& run, void* orderer) {
|
|
return step && step->x == x && step->y == 0.0f && step->advanceX == 0.0f && step->advanceY == 0.0f &&
|
|
step->spacingProgress == progress && step->writingOrderer == orderer && step->Adjusting.x == 0.0f &&
|
|
step->Adjusting.y == 0.0f && Same(step->Metrics, run);
|
|
}
|
|
|
|
static bool OrderIs(void* line, const std::uint64_t* levels, const std::size_t* order, std::size_t count) {
|
|
static int orderers[16];
|
|
const FontWritingMetrics run{1.0f, 0.0f, {-1.0f, 1.0f, 0.0f, 1.0f}};
|
|
if (sceFontWritingLineClear(line) != SCE_FONT_OK) return false;
|
|
for (std::size_t i = 0; i < count; ++i) {
|
|
if (sceFontWritingLineWritesOrder(line, Attribute(levels[i]), &run, &orderers[i]) != SCE_FONT_OK) return false;
|
|
}
|
|
for (std::size_t i = 0; i < count; ++i) {
|
|
const FontWritingLineStep* step = sceFontWritingLineRefersRenderStep(line);
|
|
if (!step || step->writingOrderer != &orderers[order[i]]) return false;
|
|
}
|
|
return sceFontWritingLineRefersRenderStep(line) == nullptr;
|
|
}
|
|
|
|
int main() {
|
|
FontMemory memory{};
|
|
void* line = nullptr;
|
|
Require(Throws([&] { sceFontCreateWritingLine(&memory, 0x10, nullptr, nullptr); }));
|
|
Require(Throws([&] { sceFontCreateWritingLine(&memory, 0x13, nullptr, &line); }) && line == nullptr);
|
|
Require(Throws([&] { sceFontCreateWritingLine(&memory, 0, nullptr, &line); }) && line == nullptr);
|
|
WritingLineDetail detail{0x0FD4, {}, {}};
|
|
Require(Throws([&] { sceFontCreateWritingLine(&memory, 0x10, &detail, &line); }) && line == nullptr);
|
|
detail.detailId = 0x0FD5;
|
|
Require(sceFontCreateWritingLine(&memory, 0x10, &detail, &line) == SCE_FONT_OK && line != nullptr);
|
|
void* ltr = nullptr;
|
|
Require(sceFontCreateWritingLine(&memory, 0x12, nullptr, <r) == SCE_FONT_OK && ltr != nullptr && ltr != line);
|
|
void* rtl = nullptr;
|
|
Require(sceFontCreateWritingLine(&memory, 0x11, nullptr, &rtl) == SCE_FONT_OK && rtl != nullptr);
|
|
|
|
FontWritingMetrics metrics{1.0f, 1.0f, {1.0f, 1.0f, 1.0f, 1.0f}};
|
|
Require(SpaceIs(line, 0.0f, 0.0f, 0.0f, 0.0f));
|
|
Require(sceFontWritingLineRefersRenderStep(line) == nullptr);
|
|
Require(sceFontWritingLineGetRenderMetrics(line, &metrics) == SCE_FONT_OK && Same(metrics, {}));
|
|
|
|
int a = 0;
|
|
int b = 0;
|
|
int c = 0;
|
|
int d = 0;
|
|
const FontWritingMetrics runA{10.0f, 0.0f, {-8.0f, 2.0f, 1.0f, 9.0f}};
|
|
const FontWritingMetrics runB{6.0f, 0.0f, {-12.0f, 3.0f, -1.0f, 5.0f}};
|
|
const FontWritingMetrics runC{8.0f, 0.0f, {-4.0f, 1.0f, 2.0f, 5.0f}};
|
|
const FontWritingMetrics runD{4.0f, 0.0f, {-4.0f, 1.0f, 0.0f, 20.0f}};
|
|
|
|
Require(Throws([&] { sceFontWritingLineWritesOrder(nullptr, Attribute(0), &runA, &a); }));
|
|
Require(Throws([&] { sceFontWritingLineWritesOrder(line, 1, &runA, &a); }));
|
|
Require(Throws([&] { sceFontWritingLineWritesOrder(line, 0x1FB, &runA, &a); }));
|
|
Require(Throws([&] { sceFontWritingLineWritesOrder(line, Attribute(0), &runA, nullptr); }));
|
|
Require(Throws([&] { sceFontWritingLineWritesOrder(line, Attribute(0x7F), &runA, &a); }));
|
|
Require(sceFontWritingLineRefersRenderStep(line) == nullptr);
|
|
|
|
Require(sceFontWritingLineWritesOrder(line, 0, &runA, &a) == SCE_FONT_OK);
|
|
Require(sceFontWritingLineWritesOrder(line, Attribute(0), &runB, &b) == SCE_FONT_OK);
|
|
Require(SpaceIs(line, 16.0f, 1.0f, 0.0f, 1.0f));
|
|
Require(sceFontWritingLineGetRenderMetrics(line, &metrics) == SCE_FONT_OK && Same(metrics, {}));
|
|
Require(StepIs(sceFontWritingLineRefersRenderStep(line), 0.0f, 0.0f, runA, &a));
|
|
Require(sceFontWritingLineGetRenderMetrics(line, &metrics) == SCE_FONT_OK && Same(metrics, {}));
|
|
Require(StepIs(sceFontWritingLineRefersRenderStep(line), 10.0f, 0.0f, runB, &b));
|
|
Require(sceFontWritingLineGetRenderMetrics(line, &metrics) == SCE_FONT_OK && Same(metrics, {10.0f, 0.0f, {-8.0f, 2.0f, 1.0f, 9.0f}}));
|
|
Require(sceFontWritingLineRefersRenderStep(line) == nullptr);
|
|
Require(sceFontWritingLineGetRenderMetrics(line, &metrics) == SCE_FONT_OK && Same(metrics, {16.0f, 0.0f, {-12.0f, 3.0f, 1.0f, 15.0f}}));
|
|
Require(StepIs(sceFontWritingLineRefersRenderStep(line), 0.0f, 0.0f, runA, &a));
|
|
Require(sceFontWritingLineGetRenderMetrics(line, &metrics) == SCE_FONT_OK && Same(metrics, {}));
|
|
|
|
Require(sceFontWritingLineWritesOrder(line, Attribute(0x7E), nullptr, &d) == SCE_FONT_OK);
|
|
Require(SpaceIs(line, 0.0f, 0.0f, 0.0f, 0.0f));
|
|
Require(StepIs(sceFontWritingLineRefersRenderStep(line), 0.0f, 0.0f, {}, &d));
|
|
Require(sceFontWritingLineRefersRenderStep(line) == nullptr);
|
|
|
|
Require(sceFontWritingLineClear(line) == SCE_FONT_OK);
|
|
Require(sceFontWritingLineRefersRenderStep(line) == nullptr);
|
|
Require(sceFontWritingLineWritesOrder(line, Attribute(0), &runA, &a) == SCE_FONT_OK);
|
|
Require(sceFontWritingLineWritesOrder(line, Attribute(1), &runB, &b) == SCE_FONT_OK);
|
|
Require(sceFontWritingLineWritesOrder(line, Attribute(1), &runC, &c) == SCE_FONT_OK);
|
|
Require(sceFontWritingLineWritesOrder(line, Attribute(0), &runD, &d) == SCE_FONT_OK);
|
|
Require(SpaceIs(line, 28.0f, 1.0f, 0.0f, -16.0f));
|
|
Require(StepIs(sceFontWritingLineRefersRenderStep(line), 0.0f, 0.0f, runA, &a));
|
|
Require(StepIs(sceFontWritingLineRefersRenderStep(line), 10.0f, 0.0f, runC, &c));
|
|
Require(StepIs(sceFontWritingLineRefersRenderStep(line), 18.0f, 0.0f, runB, &b));
|
|
Require(StepIs(sceFontWritingLineRefersRenderStep(line), 24.0f, 0.0f, runD, &d));
|
|
Require(sceFontWritingLineRefersRenderStep(line) == nullptr);
|
|
|
|
Require(sceFontWritingLineClear(line) == SCE_FONT_OK);
|
|
Require(sceFontWritingLineWritesOrder(line, Attribute(0), &runA, &a) == SCE_FONT_OK);
|
|
Require(sceFontWritingLineWritesOrder(line, Attribute(1), &runB, &b) == SCE_FONT_OK);
|
|
Require(sceFontWritingLineWritesOrder(line, Attribute(2), &runC, &c) == SCE_FONT_OK);
|
|
Require(sceFontWritingLineWritesOrder(line, Attribute(2), &runD, &d) == SCE_FONT_OK);
|
|
Require(sceFontWritingLineWritesOrder(line, Attribute(1), &runA, &b) == SCE_FONT_OK);
|
|
Require(sceFontWritingLineWritesOrder(line, Attribute(0), &runB, &a) == SCE_FONT_OK);
|
|
Require(StepIs(sceFontWritingLineRefersRenderStep(line), 0.0f, 0.0f, runA, &a));
|
|
Require(StepIs(sceFontWritingLineRefersRenderStep(line), 10.0f, 0.0f, runA, &b));
|
|
Require(StepIs(sceFontWritingLineRefersRenderStep(line), 20.0f, 0.0f, runC, &c));
|
|
Require(StepIs(sceFontWritingLineRefersRenderStep(line), 28.0f, 0.0f, runD, &d));
|
|
Require(StepIs(sceFontWritingLineRefersRenderStep(line), 32.0f, 0.0f, runB, &b));
|
|
Require(StepIs(sceFontWritingLineRefersRenderStep(line), 38.0f, 0.0f, runB, &a));
|
|
Require(sceFontWritingLineRefersRenderStep(line) == nullptr);
|
|
|
|
Require(sceFontWritingLineWritesOrder(ltr, Attribute(0, SPACE_AFTER), &runA, &a) == SCE_FONT_OK);
|
|
Require(SpaceIs(ltr, 10.0f, 1.0f, 0.0f, 1.0f));
|
|
Require(sceFontWritingLineWritesOrder(ltr, Attribute(0), &runC, &c) == SCE_FONT_OK);
|
|
Require(SpaceIs(ltr, 18.0f, 1.0f, 3.0f, 3.0f));
|
|
Require(sceFontWritingLineWritesOrder(ltr, Attribute(0, SPACE_BEFORE), &runB, &b) == SCE_FONT_OK);
|
|
Require(SpaceIs(ltr, 24.0f, 1.0f, 5.0f, 1.0f));
|
|
Require(StepIs(sceFontWritingLineRefersRenderStep(ltr), 0.0f, 0.0f, runA, &a));
|
|
Require(StepIs(sceFontWritingLineRefersRenderStep(ltr), 10.0f, 3.0f / 5.0f, runC, &c));
|
|
Require(StepIs(sceFontWritingLineRefersRenderStep(ltr), 18.0f, 1.0f, runB, &b));
|
|
Require(sceFontWritingLineRefersRenderStep(ltr) == nullptr);
|
|
|
|
Require(sceFontWritingLineClear(ltr) == SCE_FONT_OK);
|
|
Require(sceFontWritingLineWritesOrder(ltr, Attribute(0, SPACE_AFTER), &runA, &a) == SCE_FONT_OK);
|
|
Require(sceFontWritingLineWritesOrder(ltr, Attribute(1), &runC, &c) == SCE_FONT_OK);
|
|
Require(SpaceIs(ltr, 18.0f, 1.0f, 3.0f, 3.0f));
|
|
Require(sceFontWritingLineWritesOrder(ltr, Attribute(1), &runB, &b) == SCE_FONT_OK);
|
|
Require(SpaceIs(ltr, 24.0f, 1.0f, 0.0f, 3.0f));
|
|
Require(sceFontWritingLineWritesOrder(ltr, Attribute(1, SPACE_AFTER), &runD, &d) == SCE_FONT_OK);
|
|
Require(SpaceIs(ltr, 28.0f, 1.0f, -16.0f, 3.0f));
|
|
Require(StepIs(sceFontWritingLineRefersRenderStep(ltr), 0.0f, 0.0f, runA, &a));
|
|
Require(StepIs(sceFontWritingLineRefersRenderStep(ltr), 10.0f, 1.0f / -16.0f, runD, &d));
|
|
Require(StepIs(sceFontWritingLineRefersRenderStep(ltr), 14.0f, 1.0f, runB, &b));
|
|
Require(StepIs(sceFontWritingLineRefersRenderStep(ltr), 20.0f, 1.0f, runC, &c));
|
|
Require(sceFontWritingLineRefersRenderStep(ltr) == nullptr);
|
|
|
|
Require(sceFontWritingLineWritesOrder(rtl, Attribute(0, SPACE_AFTER), &runA, &a) == SCE_FONT_OK);
|
|
Require(sceFontWritingLineWritesOrder(rtl, Attribute(0), &runC, &c) == SCE_FONT_OK);
|
|
Require(SpaceIs(rtl, 18.0f, 5.0f, 15.0f, 9.0f));
|
|
Require(StepIs(sceFontWritingLineRefersRenderStep(rtl), 0.0f, 0.0f, runC, &c));
|
|
Require(StepIs(sceFontWritingLineRefersRenderStep(rtl), 8.0f, 1.0f, runA, &a));
|
|
Require(sceFontWritingLineRefersRenderStep(rtl) == nullptr);
|
|
Require(sceFontWritingLineGetRenderMetrics(rtl, &metrics) == SCE_FONT_OK && Same(metrics, {18.0f, 0.0f, {-8.0f, 2.0f, 2.0f, 17.0f}}));
|
|
|
|
const std::uint64_t nested[] = {0, 1, 2, 3, 1, 1, 0};
|
|
const std::size_t nestedOrder[] = {0, 5, 4, 2, 3, 1, 6};
|
|
Require(OrderIs(ltr, nested, nestedOrder, 7));
|
|
const std::uint64_t repeated[] = {0, 1, 1, 2, 2, 0, 1, 2, 2, 0};
|
|
const std::size_t repeatedOrder[] = {0, 3, 4, 2, 1, 5, 7, 8, 6, 9};
|
|
Require(OrderIs(ltr, repeated, repeatedOrder, 10));
|
|
const std::uint64_t skipped[] = {0, 2, 3, 3, 2, 1, 0};
|
|
const std::size_t skippedOrder[] = {0, 5, 1, 3, 2, 4, 6};
|
|
Require(OrderIs(ltr, skipped, skippedOrder, 7));
|
|
|
|
const FontWritingMetrics runE{10.0f, 3.0f, {-8.0f, 2.0f, 1.0f, 9.0f}};
|
|
const FontWritingMetrics runF{6.0f, -1.0f, {-12.0f, 3.0f, -1.0f, 5.0f}};
|
|
Require(sceFontWritingLineClear(ltr) == SCE_FONT_OK);
|
|
Require(sceFontWritingLineWritesOrder(ltr, Attribute(0), &runE, &a) == SCE_FONT_OK);
|
|
Require(sceFontWritingLineWritesOrder(ltr, Attribute(0), &runF, &b) == SCE_FONT_OK);
|
|
auto* adjusted = const_cast<FontWritingLineStep*>(sceFontWritingLineRefersRenderStep(ltr));
|
|
Require(adjusted && adjusted->x == 0.0f && adjusted->y == 0.0f && adjusted->writingOrderer == &a);
|
|
adjusted->Adjusting = {2.0f, 5.0f};
|
|
const FontWritingLineStep* second = sceFontWritingLineRefersRenderStep(ltr);
|
|
Require(second && second->x == 10.0f && second->y == 3.0f && second->Adjusting.x == 0.0f && second->Adjusting.y == 0.0f);
|
|
Require(sceFontWritingLineGetRenderMetrics(ltr, &metrics) == SCE_FONT_OK && Same(metrics, {12.0f, 8.0f, {-3.0f, 7.0f, 3.0f, 11.0f}}));
|
|
Require(sceFontWritingLineRefersRenderStep(ltr) == nullptr);
|
|
Require(sceFontWritingLineGetRenderMetrics(ltr, &metrics) == SCE_FONT_OK && Same(metrics, {16.0f, 2.0f, {-9.0f, 7.0f, 3.0f, 15.0f}}));
|
|
|
|
float space = 7.0f;
|
|
Require(sceFontWritingLineGetOrderingSpace(rtl, nullptr, nullptr, &space, nullptr) == SCE_FONT_OK && space == 15.0f);
|
|
Require(Throws([&] { sceFontWritingLineGetOrderingSpace(rtl, &space, &space, &space, nullptr); }));
|
|
Require(Throws([&] { sceFontWritingLineGetOrderingSpace(nullptr, &space, nullptr, nullptr, nullptr); }));
|
|
Require(Throws([&] { sceFontWritingLineGetRenderMetrics(nullptr, &metrics); }));
|
|
Require(Throws([&] { sceFontWritingLineGetRenderMetrics(rtl, nullptr); }));
|
|
Require(Throws([&] { sceFontWritingLineClear(nullptr); }));
|
|
|
|
int notALine = 0;
|
|
Require(sceFontWritingLineRefersRenderStep(nullptr) == nullptr);
|
|
Require(Throws([&] { sceFontWritingLineClear(¬ALine); }));
|
|
Require(Throws([&] { sceFontWritingLineRefersRenderStep(¬ALine); }));
|
|
Require(Throws([&] { sceFontWritingLineGetOrderingSpace(¬ALine, &space, &space, &space, &space); }));
|
|
void* bogus = ¬ALine;
|
|
Require(Throws([&] { sceFontDestroyWritingLine(&bogus); }) && bogus == ¬ALine);
|
|
|
|
void* destroyed = line;
|
|
Require(sceFontDestroyWritingLine(&line) == SCE_FONT_OK && line == nullptr);
|
|
Require(sceFontDestroyWritingLine(&line) == SCE_FONT_OK && line == nullptr);
|
|
Require(sceFontDestroyWritingLine(nullptr) == SCE_FONT_OK);
|
|
Require(Throws([&] { sceFontWritingLineClear(destroyed); }));
|
|
Require(Throws([&] { sceFontWritingLineWritesOrder(destroyed, Attribute(0), &runA, &a); }));
|
|
Require(sceFontDestroyWritingLine(<r) == SCE_FONT_OK && ltr == nullptr);
|
|
Require(sceFontDestroyWritingLine(&rtl) == SCE_FONT_OK && rtl == nullptr);
|
|
std::puts("font writing line: ok");
|
|
}
|