Repository navigation
Expand file tree
/
Copy pathWritingLine.cpp
More file actions
139 lines (119 loc) · 5.03 KB
/
Copy pathWritingLine.cpp
File metadata and controls
139 lines (119 loc) · 5.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <mutex>
#include <stdexcept>
#include <string>
#include <unordered_set>
#include <vector>
#include "prx/libSceFont/include/FontTypes.hpp"
namespace {
constexpr std::int32_t WRITING_FORM_HORIZONTAL = 0x10;
constexpr std::int32_t WRITING_FORM_HORIZONTAL_LTR = 0x12;
constexpr std::uint16_t CREATE_WRITING_LINE_DETAIL_ID = 0x0FD5;
struct CreateWritingLineDetail {
std::uint16_t detailId;
};
struct WritingLine {
std::vector<FontWritingLineStep> steps;
std::size_t cursor = 0;
FontWritingMetrics metrics{};
};
std::mutex linesMutex;
std::unordered_set<WritingLine*> lines;
[[noreturn]] void Unsupported(const char* function, const std::string& what) {
throw std::runtime_error(std::string(function) + ": " + what);
}
WritingLine* GetLine(const char* function, void* writingLine) {
auto* line = static_cast<WritingLine*>(writingLine);
std::lock_guard lock(linesMutex);
if (!lines.contains(line)) Unsupported(function, "unknown writing line handle (error code not verified)");
return line;
}
}
#pragma GCC visibility push(default)
extern "C" {
int APS5_VABI sceFontCreateWritingLine(const FontMemory* memory, std::int32_t writingForm, const void* writingLineDetail, void** pWritingLine) {
(void)memory;
if (!pWritingLine) Unsupported(__func__, "null writing line pointer (error code not verified)");
if (writingForm != WRITING_FORM_HORIZONTAL && writingForm != WRITING_FORM_HORIZONTAL_LTR)
Unsupported(__func__, "writing form " + std::to_string(writingForm) + " is not modelled");
if (writingLineDetail && static_cast<const CreateWritingLineDetail*>(writingLineDetail)->detailId != CREATE_WRITING_LINE_DETAIL_ID)
Unsupported(__func__, "unknown writing line detail id");
auto* line = new WritingLine{};
{
std::lock_guard lock(linesMutex);
lines.insert(line);
}
*pWritingLine = line;
return SCE_FONT_OK;
}
int APS5_VABI sceFontDestroyWritingLine(void** pWritingLine) {
if (!pWritingLine || !*pWritingLine) return SCE_FONT_OK;
auto* line = GetLine(__func__, *pWritingLine);
{
std::lock_guard lock(linesMutex);
lines.erase(line);
}
delete line;
*pWritingLine = nullptr;
return SCE_FONT_OK;
}
int APS5_VABI sceFontWritingLineClear(void* writingLine) {
auto* line = GetLine(__func__, writingLine);
line->steps.clear();
line->cursor = 0;
line->metrics = {};
return SCE_FONT_OK;
}
int APS5_VABI sceFontWritingLineWritesOrder(void* writingLine, std::uint64_t writingAttribute, const FontWritingMetrics* writingMetrics, void* writingOrderer) {
auto* line = GetLine(__func__, writingLine);
if (writingAttribute != 0) Unsupported(__func__, "writing attribute " + std::to_string(writingAttribute) + " is not modelled");
if (!writingMetrics) Unsupported(__func__, "null writing metrics are not modelled");
const FontWritingMetrics& order = *writingMetrics;
const float pen = line->metrics.advanceX;
FontWritingLineStep step{};
step.x = pen;
step.advanceX = order.advanceX;
step.advanceY = order.advanceY;
step.writingOrderer = writingOrderer;
step.Metrics = order;
const FontWritingExtent extent{order.Extent.top, order.Extent.bottom, pen + order.Extent.left, pen + order.Extent.right};
if (line->steps.empty()) {
line->metrics.Extent = extent;
} else {
line->metrics.Extent.top = std::min(line->metrics.Extent.top, extent.top);
line->metrics.Extent.bottom = std::max(line->metrics.Extent.bottom, extent.bottom);
line->metrics.Extent.left = std::min(line->metrics.Extent.left, extent.left);
line->metrics.Extent.right = std::max(line->metrics.Extent.right, extent.right);
}
line->metrics.advanceX += order.advanceX;
line->metrics.advanceY += order.advanceY;
line->steps.push_back(step);
line->cursor = 0;
return SCE_FONT_OK;
}
const FontWritingLineStep* APS5_VABI sceFontWritingLineRefersRenderStep(void* writingLine) {
if (!writingLine) return nullptr;
auto* line = GetLine(__func__, writingLine);
if (line->cursor >= line->steps.size()) return nullptr;
return &line->steps[line->cursor++];
}
int APS5_VABI sceFontWritingLineGetRenderMetrics(void* writingLine, FontWritingMetrics* writingMetrics) {
auto* line = GetLine(__func__, writingLine);
if (!writingMetrics) Unsupported(__func__, "null metrics pointer (error code not verified)");
if (line->steps.empty()) Unsupported(__func__, "metrics of an empty line are not modelled");
*writingMetrics = line->metrics;
return SCE_FONT_OK;
}
int APS5_VABI sceFontWritingLineGetOrderingSpace(void* writingLine, float* headSpace, float* inlineSpace, float* tailSpace, float* advanceSpace) {
GetLine(__func__, writingLine);
if (!headSpace || !inlineSpace || !tailSpace || !advanceSpace) Unsupported(__func__, "null space pointer (error code not verified)");
*headSpace = 0.0f;
*inlineSpace = 0.0f;
*tailSpace = 0.0f;
*advanceSpace = 0.0f;
return SCE_FONT_OK;
}
}
#pragma GCC visibility pop