mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-28 00:35:47 +00:00
Merge pull request #9550 from Ondra97/codex/feat-freetype-size-objects
feat(libSceFreeType): manage multiple size objects
This commit is contained in:
6 files changed
+340
-11
No files matched your search
@@ -6,6 +6,7 @@
|
||||
|
||||
#include FT_GASP_H
|
||||
#include FT_CID_H
|
||||
#include FT_SIZES_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <bit>
|
||||
@@ -33,14 +34,17 @@ void FinalizeSlot(void* object) {
|
||||
|
||||
void FinalizeSize(void* object) {
|
||||
auto* host = static_cast<FT_Size>(object);
|
||||
auto* face = static_cast<GuestFace*>(host->generic.data);
|
||||
if (face->size.generic.finalizer) face->size.generic.finalizer(&face->size);
|
||||
face->rec.size = nullptr;
|
||||
auto* rec = static_cast<GuestSizeRec*>(host->generic.data);
|
||||
auto* face = static_cast<GuestFace*>(host->face->generic.data);
|
||||
SyncSizeRecord_nid_no_patch(*face, *rec, host);
|
||||
SyncSizePointer_nid_no_patch(*face);
|
||||
if (rec->generic.finalizer) rec->generic.finalizer(rec);
|
||||
}
|
||||
|
||||
void FinalizeFace(void* object) {
|
||||
auto* host = static_cast<FT_Face>(object);
|
||||
auto* face = static_cast<GuestFace*>(host->generic.data);
|
||||
SyncSizePointer_nid_no_patch(*face);
|
||||
if (face->rec.generic.finalizer) face->rec.generic.finalizer(&face->rec);
|
||||
face->finalized = true;
|
||||
}
|
||||
@@ -54,7 +58,7 @@ void PublishFace(GuestLibrary* library, std::unique_ptr<GuestFace> face, FT_Face
|
||||
library->faces.push_back(std::move(face));
|
||||
host->generic = {owner, FinalizeFace};
|
||||
if (host->glyph) host->glyph->generic = {owner, FinalizeSlot};
|
||||
if (host->size) host->size->generic = {owner, FinalizeSize};
|
||||
if (host->size) host->size->generic = {&owner->size, FinalizeSize};
|
||||
*aface = &owner->rec;
|
||||
hostOwner.release();
|
||||
}
|
||||
@@ -164,6 +168,60 @@ int APS5_VABI FT_Done_Face_nid_postfix(GuestFaceRec* face) {
|
||||
return error;
|
||||
}
|
||||
|
||||
int APS5_VABI FT_New_Size_nid_postfix(GuestFaceRec* face, GuestSizeRec** asize) {
|
||||
GuestFace* owner = FaceOf(face);
|
||||
FT_Face hostFace = owner ? owner->host : nullptr;
|
||||
if (!hostFace || !asize || !hostFace->driver) {
|
||||
FT_Size unused = nullptr;
|
||||
return FT_New_Size(hostFace, asize ? &unused : nullptr);
|
||||
}
|
||||
const bool activates = asize == &owner->rec.size;
|
||||
*asize = nullptr;
|
||||
if (activates) hostFace->size = nullptr;
|
||||
try {
|
||||
owner->sizes.emplace_back();
|
||||
} catch (const std::bad_alloc&) {
|
||||
return FT_Err_Out_Of_Memory;
|
||||
}
|
||||
auto entry = std::prev(owner->sizes.end());
|
||||
FT_Size host = nullptr;
|
||||
const FT_Error error = FT_New_Size(hostFace, activates ? &hostFace->size : &host);
|
||||
if (activates) host = hostFace->size;
|
||||
if (error != 0) {
|
||||
owner->sizes.erase(entry);
|
||||
SyncSizePointer_nid_no_patch(*owner);
|
||||
return error;
|
||||
}
|
||||
entry->host = host;
|
||||
SyncSizeRecord_nid_no_patch(*owner, entry->rec, host);
|
||||
host->generic = {&entry->rec, FinalizeSize};
|
||||
*asize = &entry->rec;
|
||||
SyncSizePointer_nid_no_patch(*owner);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI FT_Activate_Size_nid_postfix(GuestSizeRec* size) {
|
||||
FT_Size host = size ? static_cast<FT_Size>(size->internal) : nullptr;
|
||||
const FT_Error error = FT_Activate_Size(host);
|
||||
if (error == 0) SyncSize(*static_cast<GuestFace*>(host->face->generic.data));
|
||||
return error;
|
||||
}
|
||||
|
||||
int APS5_VABI FT_Done_Size_nid_postfix(GuestSizeRec* size) {
|
||||
FT_Size host = size ? static_cast<FT_Size>(size->internal) : nullptr;
|
||||
auto* owner = host && host->face ? static_cast<GuestFace*>(host->face->generic.data) : nullptr;
|
||||
const FT_Error error = FT_Done_Size(host);
|
||||
if (error != 0) return error;
|
||||
if (host == owner->initialSize) {
|
||||
owner->initialSize = nullptr;
|
||||
owner->size.internal = nullptr;
|
||||
} else {
|
||||
owner->sizes.remove_if([host](const auto& entry) { return entry.host == host; });
|
||||
}
|
||||
SyncSize(*owner);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI FT_Set_Pixel_Sizes_nid_postfix(GuestFaceRec* face, std::uint32_t pixel_width, std::uint32_t pixel_height) {
|
||||
GuestFace* owner = FaceOf(face);
|
||||
const FT_Error error = FT_Set_Pixel_Sizes(owner ? owner->host : nullptr, pixel_width, pixel_height);
|
||||
|
||||
@@ -13,6 +13,9 @@ int APS5_VABI FT_New_Memory_Face_nid_postfix(FreeType::GuestLibrary* library, co
|
||||
int APS5_VABI FT_Reference_Face_nid_postfix(FreeType::GuestFaceRec* face);
|
||||
int APS5_VABI FT_Done_Face_nid_postfix(FreeType::GuestFaceRec* face);
|
||||
int APS5_VABI FT_Select_Size_nid_postfix(FreeType::GuestFaceRec* face, std::int32_t strikeIndex);
|
||||
int APS5_VABI FT_New_Size_nid_postfix(FreeType::GuestFaceRec* face, FreeType::GuestSizeRec** asize);
|
||||
int APS5_VABI FT_Activate_Size_nid_postfix(FreeType::GuestSizeRec* size);
|
||||
int APS5_VABI FT_Done_Size_nid_postfix(FreeType::GuestSizeRec* size);
|
||||
int APS5_VABI FT_Set_Pixel_Sizes_nid_postfix(FreeType::GuestFaceRec* face, std::uint32_t pixelWidth, std::uint32_t pixelHeight);
|
||||
int APS5_VABI FT_Set_Char_Size_nid_postfix(FreeType::GuestFaceRec* face, std::int64_t charWidth, std::int64_t charHeight, std::uint32_t horizontalResolution, std::uint32_t verticalResolution);
|
||||
std::uint32_t APS5_VABI FT_Get_Char_Index_nid_postfix(FreeType::GuestFaceRec* face, std::uint64_t charcode);
|
||||
|
||||
@@ -21,6 +21,11 @@ struct GuestLibrary {
|
||||
|
||||
void UnregisterBitmap_nid_no_patch(const GuestBitmap* bitmap);
|
||||
|
||||
struct GuestSize {
|
||||
GuestSizeRec rec{};
|
||||
FT_Size host = nullptr;
|
||||
};
|
||||
|
||||
struct GuestFace {
|
||||
GuestFaceRec rec{};
|
||||
GuestGlyphSlotRec slot{};
|
||||
@@ -28,6 +33,9 @@ struct GuestFace {
|
||||
GuestLibrary* library = nullptr;
|
||||
FT_Face host = nullptr;
|
||||
bool finalized = false;
|
||||
FT_Size initialSize = nullptr;
|
||||
bool sizeInitialized = false;
|
||||
std::list<GuestSize> sizes;
|
||||
std::vector<unsigned char> bytes;
|
||||
std::vector<GuestBitmapSize> fixedSizes;
|
||||
std::vector<GuestCharMapRec> charmaps;
|
||||
@@ -43,6 +51,8 @@ GuestFace* FaceOf(const GuestFaceRec* face);
|
||||
GuestFace* FaceOf(const GuestGlyphSlotRec* slot);
|
||||
void SyncFace(GuestFace& face);
|
||||
void SyncSize(GuestFace& face);
|
||||
void SyncSizePointer_nid_no_patch(GuestFace& face);
|
||||
void SyncSizeRecord_nid_no_patch(GuestFace& face, GuestSizeRec& rec, FT_Size host);
|
||||
void SyncSlot(GuestFace& face);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "prx/libSceFreeType/include/GuestObjects.hpp"
|
||||
|
||||
#include <cstddef>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace FreeType {
|
||||
|
||||
@@ -51,20 +52,48 @@ void SyncFace(GuestFace& face) {
|
||||
rec.underline_position = host->underline_position;
|
||||
rec.underline_thickness = host->underline_thickness;
|
||||
rec.glyph = host->glyph ? &face.slot : nullptr;
|
||||
rec.size = host->size ? &face.size : nullptr;
|
||||
rec.internal = &face;
|
||||
SyncSize(face);
|
||||
SyncSlot(face);
|
||||
}
|
||||
|
||||
void SyncSize(GuestFace& face) {
|
||||
face.size.face = &face.rec;
|
||||
if (!face.host->size) {
|
||||
face.size.metrics = {};
|
||||
void SyncSizeRecord_nid_no_patch(GuestFace& face, GuestSizeRec& rec, FT_Size host) {
|
||||
rec.face = &face.rec;
|
||||
rec.internal = host;
|
||||
if (!host) {
|
||||
rec.metrics = {};
|
||||
return;
|
||||
}
|
||||
const auto& metrics = face.host->size->metrics;
|
||||
face.size.metrics = {metrics.x_ppem, metrics.y_ppem, metrics.x_scale, metrics.y_scale, metrics.ascender, metrics.descender, metrics.height, metrics.max_advance};
|
||||
const auto& metrics = host->metrics;
|
||||
rec.metrics = {metrics.x_ppem, metrics.y_ppem, metrics.x_scale, metrics.y_scale, metrics.ascender, metrics.descender, metrics.height, metrics.max_advance};
|
||||
}
|
||||
|
||||
void SyncSizePointer_nid_no_patch(GuestFace& face) {
|
||||
const FT_Size active = face.host->size;
|
||||
if (!active) {
|
||||
face.rec.size = nullptr;
|
||||
return;
|
||||
}
|
||||
if (active == face.initialSize) {
|
||||
face.rec.size = &face.size;
|
||||
return;
|
||||
}
|
||||
for (auto& size : face.sizes) {
|
||||
if (size.host != active) continue;
|
||||
face.rec.size = &size.rec;
|
||||
return;
|
||||
}
|
||||
throw std::runtime_error("FreeType: an active size created outside the guest bridge is not implemented");
|
||||
}
|
||||
|
||||
void SyncSize(GuestFace& face) {
|
||||
if (!face.sizeInitialized) {
|
||||
face.initialSize = face.host->size;
|
||||
face.sizeInitialized = true;
|
||||
SyncSizeRecord_nid_no_patch(face, face.size, face.initialSize);
|
||||
}
|
||||
SyncSizePointer_nid_no_patch(face);
|
||||
if (face.rec.size) SyncSizeRecord_nid_no_patch(face, *face.rec.size, face.host->size);
|
||||
}
|
||||
|
||||
void SyncSlot(GuestFace& face) {
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
#include FT_OUTLINE_H
|
||||
#include FT_TRIGONOMETRY_H
|
||||
#include FT_CID_H
|
||||
#include FT_SIZES_H
|
||||
#include FT_SYSTEM_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
@@ -1257,7 +1259,232 @@ static void CheckTransforms(const std::vector<unsigned char>& font) {
|
||||
std::printf("FT_Set_Transform: %zu native glyph and bitmap comparisons\n", comparisons);
|
||||
}
|
||||
|
||||
static void SizeMatches(const GuestSizeRec* size, FT_Size native) {
|
||||
Require(size != nullptr && native != nullptr);
|
||||
const auto& a = size->metrics;
|
||||
const auto& b = native->metrics;
|
||||
Require(a.x_ppem == b.x_ppem && a.y_ppem == b.y_ppem && a.x_scale == b.x_scale && a.y_scale == b.y_scale);
|
||||
Require(a.ascender == b.ascender && a.descender == b.descender && a.height == b.height && a.max_advance == b.max_advance);
|
||||
}
|
||||
|
||||
static bool OwnsSize(const GuestFace& face, const GuestSizeRec* size) {
|
||||
if (size == &face.size) return true;
|
||||
for (const auto& entry : face.sizes) {
|
||||
if (size == &entry.rec) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
struct SizeEvents {
|
||||
std::vector<void*> sizes;
|
||||
std::vector<std::array<int, 4>> calls;
|
||||
|
||||
int Index(void* size) const {
|
||||
if (!size) return -1;
|
||||
for (std::size_t index = 0; index < sizes.size(); ++index) {
|
||||
if (sizes[index] == size) return static_cast<int>(index);
|
||||
}
|
||||
Require(false);
|
||||
return -2;
|
||||
}
|
||||
};
|
||||
|
||||
static void NativeMultipleSizeFinalizer(void* object) {
|
||||
auto* size = static_cast<FT_Size>(object);
|
||||
auto& events = *static_cast<SizeEvents*>(size->generic.data);
|
||||
events.calls.push_back({events.Index(size), events.Index(size->face->size), size->metrics.y_ppem, size->face->glyph == nullptr});
|
||||
}
|
||||
|
||||
static void APS5_VABI GuestMultipleSizeFinalizer(void* object) {
|
||||
auto* size = static_cast<GuestSizeRec*>(object);
|
||||
auto* face = static_cast<GuestFaceRec*>(size->face);
|
||||
const auto& owner = *static_cast<GuestFace*>(face->internal);
|
||||
Require(OwnsSize(owner, size));
|
||||
if (face->size) Require(OwnsSize(owner, face->size));
|
||||
SizeMatches(size, static_cast<FT_Size>(size->internal));
|
||||
auto& events = *static_cast<SizeEvents*>(size->generic.data);
|
||||
events.calls.push_back({events.Index(size), events.Index(face->size), size->metrics.y_ppem, face->glyph == nullptr});
|
||||
}
|
||||
|
||||
static void NativeMultipleSizeFaceFinalizer(void* object) {
|
||||
auto* face = static_cast<FT_Face>(object);
|
||||
Require(face->glyph == nullptr && face->size == nullptr);
|
||||
static_cast<SizeEvents*>(face->generic.data)->calls.push_back({100, -1, 0, 1});
|
||||
}
|
||||
|
||||
static void APS5_VABI GuestMultipleSizeFaceFinalizer(void* object) {
|
||||
auto* face = static_cast<GuestFaceRec*>(object);
|
||||
Require(face->glyph == nullptr && face->size == nullptr);
|
||||
static_cast<SizeEvents*>(face->generic.data)->calls.push_back({100, -1, 0, 1});
|
||||
}
|
||||
|
||||
static FT_Alloc_Func SizeOriginalAlloc = nullptr;
|
||||
static int SizeAllocationsBeforeFailure = 0;
|
||||
|
||||
static void* SizeFailingAlloc(FT_Memory memory, long bytes) {
|
||||
if (SizeAllocationsBeforeFailure-- == 0) return nullptr;
|
||||
return SizeOriginalAlloc(memory, bytes);
|
||||
}
|
||||
|
||||
static void SizeObjects(const std::vector<unsigned char>& font) {
|
||||
Require(FT_New_Size_nid_postfix(nullptr, nullptr) == FT_New_Size(nullptr, nullptr));
|
||||
Require(FT_Done_Size_nid_postfix(nullptr) == FT_Done_Size(nullptr));
|
||||
Require(FT_Activate_Size_nid_postfix(nullptr) == FT_Activate_Size(nullptr));
|
||||
GuestSizeRec sentinel{};
|
||||
GuestSizeRec* untouched = &sentinel;
|
||||
Require(FT_New_Size_nid_postfix(nullptr, &untouched) == FT_Err_Invalid_Face_Handle && untouched == &sentinel);
|
||||
FT_FaceRec driverless{};
|
||||
GuestFace invalidOwner;
|
||||
invalidOwner.host = &driverless;
|
||||
invalidOwner.rec.internal = &invalidOwner;
|
||||
FT_Size nativeUntouched = reinterpret_cast<FT_Size>(&sentinel);
|
||||
Require(FT_New_Size(&driverless, &nativeUntouched) == FT_Err_Invalid_Driver_Handle);
|
||||
Require(FT_New_Size_nid_postfix(&invalidOwner.rec, &untouched) == FT_Err_Invalid_Driver_Handle && untouched == &sentinel);
|
||||
Require(FT_New_Size_nid_postfix(&invalidOwner.rec, nullptr) == FT_New_Size(&driverless, nullptr));
|
||||
|
||||
FT_SizeRec driverlessSize{};
|
||||
GuestSizeRec invalidSize{};
|
||||
invalidSize.internal = &driverlessSize;
|
||||
Require(FT_Done_Size_nid_postfix(&invalidSize) == FT_Done_Size(&driverlessSize));
|
||||
Require(FT_Activate_Size_nid_postfix(&invalidSize) == FT_Activate_Size(&driverlessSize));
|
||||
driverlessSize.face = &driverless;
|
||||
Require(FT_Done_Size_nid_postfix(&invalidSize) == FT_Done_Size(&driverlessSize));
|
||||
Require(FT_Activate_Size_nid_postfix(&invalidSize) == FT_Activate_Size(&driverlessSize));
|
||||
static_assert(sizeof(GuestSizeMetrics) == 56 && sizeof(GuestSizeRec) == 88);
|
||||
|
||||
int scenarios = 0;
|
||||
int rendered = 0;
|
||||
int failures = 0;
|
||||
for (const int faceIndex : {0, -1}) {
|
||||
for (const int count : {0, 1, 5, 41}) {
|
||||
for (const int cleanup : {0, 1, 2}) {
|
||||
GuestLibrary* library = nullptr;
|
||||
FT_Library oracle = nullptr;
|
||||
Require(FT_Init_FreeType_nid_postfix(&library) == 0 && FT_Init_FreeType(&oracle) == 0);
|
||||
GuestFaceRec* face = nullptr;
|
||||
FT_Face native = nullptr;
|
||||
Require(FT_New_Memory_Face_nid_postfix(library, font.data(), font.size(), faceIndex, &face) == 0);
|
||||
Require(FT_New_Memory_Face(oracle, font.data(), static_cast<FT_Long>(font.size()), faceIndex, &native) == 0);
|
||||
SizeEvents actual;
|
||||
SizeEvents expected;
|
||||
face->generic = {&actual, GuestMultipleSizeFaceFinalizer};
|
||||
native->generic = {&expected, NativeMultipleSizeFaceFinalizer};
|
||||
std::vector<GuestSizeRec*> sizes;
|
||||
std::vector<FT_Size> originals;
|
||||
auto remember = [&](GuestSizeRec* size, FT_Size original) {
|
||||
Require(size->face == face && original->face == native);
|
||||
actual.sizes.push_back(size);
|
||||
expected.sizes.push_back(original);
|
||||
size->generic = {&actual, GuestMultipleSizeFinalizer};
|
||||
original->generic = {&expected, NativeMultipleSizeFinalizer};
|
||||
sizes.push_back(size);
|
||||
originals.push_back(original);
|
||||
SizeMatches(size, original);
|
||||
};
|
||||
if (native->size) remember(face->size, native->size);
|
||||
Require(FT_New_Size_nid_postfix(face, nullptr) == FT_New_Size(native, nullptr));
|
||||
for (int index = 0; index < count; ++index) {
|
||||
GuestSizeRec* before = face->size;
|
||||
FT_Size previous = native->size;
|
||||
GuestSizeRec* created = nullptr;
|
||||
FT_Size original = nullptr;
|
||||
Require(FT_New_Size_nid_postfix(face, &created) == FT_New_Size(native, &original));
|
||||
Require(created != nullptr && original != nullptr && face->size == before && native->size == previous);
|
||||
remember(created, original);
|
||||
}
|
||||
if (count == 5) {
|
||||
Require(FT_New_Size_nid_postfix(face, &face->size) == FT_New_Size(native, &native->size));
|
||||
remember(face->size, native->size);
|
||||
}
|
||||
for (std::size_t index = 0; index < sizes.size(); ++index) {
|
||||
Require(FT_Activate_Size_nid_postfix(sizes[index]) == 0 && FT_Activate_Size(originals[index]) == 0);
|
||||
Require(face->size == sizes[index] && native->size == originals[index]);
|
||||
Require(FT_Set_Pixel_Sizes_nid_postfix(face, 0, 12 + index) == FT_Set_Pixel_Sizes(native, 0, 12 + index));
|
||||
SizeMatches(sizes[index], originals[index]);
|
||||
}
|
||||
for (std::size_t turn = 0; turn < sizes.size() * 3; ++turn) {
|
||||
const std::size_t index = (turn * 17 + 3) % sizes.size();
|
||||
Require(FT_Activate_Size_nid_postfix(sizes[index]) == FT_Activate_Size(originals[index]));
|
||||
Require(face->size == sizes[index]);
|
||||
for (std::size_t other = 0; other < sizes.size(); ++other) SizeMatches(sizes[other], originals[other]);
|
||||
if (!native->glyph) continue;
|
||||
Require(FT_Load_Char_nid_postfix(face, 'A', FT_LOAD_NO_HINTING) == FT_Load_Char(native, 'A', FT_LOAD_NO_HINTING));
|
||||
for (unsigned point = 0; point < face->glyph->outline.n_points; ++point) face->glyph->outline.points[point].x += 64;
|
||||
FT_Outline_Translate(&native->glyph->outline, 64, 0);
|
||||
Require(FT_Activate_Size_nid_postfix(sizes[index]) == FT_Activate_Size(originals[index]));
|
||||
Require(FT_Render_Glyph_nid_postfix(face->glyph, FT_RENDER_MODE_NORMAL) == FT_Render_Glyph(native->glyph, FT_RENDER_MODE_NORMAL));
|
||||
SlotMatches(face->glyph, native->glyph);
|
||||
++rendered;
|
||||
}
|
||||
if (cleanup == 0) {
|
||||
while (!sizes.empty()) {
|
||||
const std::size_t index = sizes.size() % 2 == 0 ? 0 : sizes.size() - 1;
|
||||
const int removed = actual.Index(sizes[index]);
|
||||
Require(FT_Done_Size_nid_postfix(sizes[index]) == FT_Done_Size(originals[index]));
|
||||
actual.sizes[removed] = nullptr;
|
||||
expected.sizes[removed] = nullptr;
|
||||
sizes.erase(sizes.begin() + index);
|
||||
originals.erase(originals.begin() + index);
|
||||
Require(actual.Index(face->size) == expected.Index(native->size) && actual.calls == expected.calls);
|
||||
}
|
||||
Require(face->size == nullptr && native->size == nullptr);
|
||||
Require(FT_Set_Pixel_Sizes_nid_postfix(face, 0, 24) == FT_Set_Pixel_Sizes(native, 0, 24));
|
||||
Require(FT_New_Size_nid_postfix(face, &face->size) == FT_New_Size(native, &native->size));
|
||||
Require(face->size != nullptr && native->size != nullptr);
|
||||
remember(face->size, native->size);
|
||||
Require(FT_Set_Pixel_Sizes_nid_postfix(face, 0, 24) == FT_Set_Pixel_Sizes(native, 0, 24));
|
||||
for (const bool alias : {false, true}) {
|
||||
for (const int allocation : {0, 1, 2}) {
|
||||
auto* owner = static_cast<GuestFace*>(face->internal);
|
||||
FT_Memory memory = owner->host->memory;
|
||||
SizeOriginalAlloc = memory->alloc;
|
||||
SizeAllocationsBeforeFailure = allocation;
|
||||
memory->alloc = SizeFailingAlloc;
|
||||
GuestSizeRec* output = &sentinel;
|
||||
const int error = FT_New_Size_nid_postfix(face, alias ? &face->size : &output);
|
||||
memory->alloc = SizeOriginalAlloc;
|
||||
Require(error == FT_Err_Out_Of_Memory && owner->sizes.size() == 1);
|
||||
FT_Memory nativeMemory = native->memory;
|
||||
SizeOriginalAlloc = nativeMemory->alloc;
|
||||
SizeAllocationsBeforeFailure = allocation;
|
||||
nativeMemory->alloc = SizeFailingAlloc;
|
||||
FT_Size nativeOutput = reinterpret_cast<FT_Size>(&sentinel);
|
||||
const int nativeError = FT_New_Size(native, alias ? &native->size : &nativeOutput);
|
||||
nativeMemory->alloc = SizeOriginalAlloc;
|
||||
Require(error == nativeError);
|
||||
Require(alias ? face->size == nullptr && native->size == nullptr : output == nullptr && nativeOutput == nullptr);
|
||||
Require(actual.Index(face->size) == expected.Index(native->size));
|
||||
Require(actual.calls == expected.calls);
|
||||
++failures;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cleanup == 1) {
|
||||
Require(FT_Reference_Face_nid_postfix(face) == 0 && FT_Reference_Face(native) == 0);
|
||||
Require(FT_Done_Face_nid_postfix(face) == 0 && FT_Done_Face(native) == 0);
|
||||
Require(actual.calls.empty() && expected.calls.empty());
|
||||
}
|
||||
if (cleanup == 2 && count == 5) {
|
||||
Require(sizes.size() > 2);
|
||||
Require(FT_Activate_Size_nid_postfix(sizes[1]) == FT_Activate_Size(originals[1]));
|
||||
Require(face->size == sizes[1] && native->size == originals[1]);
|
||||
}
|
||||
if (cleanup != 2) Require(FT_Done_Face_nid_postfix(face) == 0 && FT_Done_Face(native) == 0);
|
||||
Require(FT_Done_FreeType_nid_postfix(library) == 0 && FT_Done_FreeType(oracle) == 0);
|
||||
Require(actual.calls == expected.calls && !actual.calls.empty() && actual.calls.back()[0] == 100);
|
||||
if (cleanup == 2 && count == 5) {
|
||||
Require(actual.calls.size() > 3 && actual.calls[0][1] == 1 && actual.calls[1][0] == 1);
|
||||
for (std::size_t index = 2; index + 1 < actual.calls.size(); ++index) Require(actual.calls[index][1] == 1);
|
||||
}
|
||||
++scenarios;
|
||||
}
|
||||
}
|
||||
}
|
||||
std::printf("FreeType size objects: %d lifecycles, %d rendered glyphs, %d allocation failures compared with native\n", scenarios, rendered, failures);
|
||||
}
|
||||
|
||||
int main() {
|
||||
SizeObjects(SquareGlyphFont('A', 700));
|
||||
{
|
||||
const auto referenceFont = SquareGlyphFont('A', 700);
|
||||
GuestLibrary* referenceLibrary = nullptr;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
# libSceFreeType technical debt
|
||||
|
||||
### Unknown function info
|
||||
- [FT_New_Size, FT_Activate_Size and FT_Done_Size](../../../core/libs/prx/libSceFreeType/Export.cpp) (libSceFreeType) - console signatures, errors and generic-finalizer ordering are unverified; the LP64 guest adapter follows bundled [FreeType 2.13.3](https://github.com/freetype/freetype/blob/42608f77f20749dd6ddc9e0536788eaad70ea4b5/src/base/ftobjs.c). Private size fields are bridge-owned. Sizes created outside the bridge throw when selected.
|
||||
|
||||
- [FT_Reference_Face](../../../core/libs/prx/libSceFreeType/Export.cpp) (libSceFreeType) - console signature, reference-counter limits and finalizer behavior are unverified; the LP64 guest adapter follows bundled [FreeType 2.13.3](https://github.com/freetype/freetype/blob/42608f77f20749dd6ddc9e0536788eaad70ea4b5/src/base/ftobjs.c). Counter overflow and reentrant finalization have not been measured on the console.
|
||||
|
||||
- [FT_Get_Sfnt_Name_Count, FT_Get_Sfnt_Name](../../../core/libs/prx/libSceFreeType/src/Names.cpp) (libSceFreeType) - console signatures, record layout and errors are unverified; the adapter follows bundled [FreeType 2.13.3](https://github.com/freetype/freetype/blob/42608f77f20749dd6ddc9e0536788eaad70ea4b5/src/base/ftsnames.c) and assumes the public LP64 `FT_SfntName` layout (24 bytes, string pointer at 8, byte length at 16). Strings retain their original encoding, borrow native face storage and remain valid only while the face is alive
|
||||
|
||||
Reference in new issue
Block a user