// SPDX-FileCopyrightText: Copyright 2024-2026 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "font_internal.h"

#include <array>

#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_OUTLINE_H
#include FT_TRUETYPE_TABLES_H

#include "core/emulator_settings.h"
#include "core/libraries/font/fontft_internal.h"
#include "core/libraries/kernel/kernel.h"
#include "imgui/notifications_layer.h"
#include "imgui/renderer/font_data.h"

namespace Libraries::Font::Internal {

Core::FileSys::MntPoints* g_mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();

using Libraries::Font::OrbisFontGenerateGlyphParams;
using Libraries::Font::OrbisFontGlyph;
using Libraries::Font::OrbisFontGlyphMetrics;
using Libraries::Font::OrbisFontGlyphOpaque;
using Libraries::Font::OrbisFontGlyphOutline;
using Libraries::Font::OrbisFontGlyphOutlinePoint;
using Libraries::Font::OrbisFontMem;
using Libraries::Font::OrbisFontStyleFrame;

std::unordered_map<Libraries::Font::OrbisFontHandle, FontState> g_font_state;

std::unordered_map<Libraries::Font::OrbisFontLib, LibraryState> g_library_state;

namespace {
std::mutex g_state_mutex;
} // namespace

std::unordered_map<Libraries::Font::OrbisFontRenderSurface*,
                   const Libraries::Font::OrbisFontStyleFrame*>
    g_style_for_surface;

void* g_allocator_vtbl_stub[4] = {};
std::uint8_t g_sys_driver_stub{};
std::uint8_t g_fontset_registry_stub{};
std::uint8_t g_sysfonts_ctx_stub{};
std::uint8_t g_external_fonts_ctx_stub{};
u32 g_device_cache_stub{};

std::string FormatNamedParams(std::initializer_list<NamedParam> params) {
    fmt::memory_buffer buffer;
    fmt::format_to(std::back_inserter(buffer), "params:\n");
    for (const auto& p : params) {
        fmt::format_to(std::back_inserter(buffer), "{}: {}\n", p.name, p.value);
    }
    return fmt::to_string(buffer);
}

bool HasSfntTables(const std::vector<unsigned char>& bytes);
std::string ReportSystemFaceRequest(FontState& st, Libraries::Font::OrbisFontHandle handle,
                                    bool& attached_out);

namespace {

static FT_Library GetFreeTypeLibrary() {
    static std::once_flag once;
    static FT_Library lib = nullptr;
    std::call_once(once, [] {
        FT_Library created = nullptr;
        if (FT_Init_FreeType(&created) != 0) {
            created = nullptr;
        }
        lib = created;
    });
    return lib;
}

static constexpr FT_Int32 kFtLoadFlagsBase =
    static_cast<FT_Int32>(FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP | FT_LOAD_VERTICAL_LAYOUT);

static constexpr FT_Int32 kFtLoadFlagsRender =
    static_cast<FT_Int32>(kFtLoadFlagsBase | FT_LOAD_RENDER);

} // namespace

FT_Face CreateFreeTypeFaceFromBytes(const unsigned char* data, std::size_t size,
                                    u32 subfont_index) {
    if (!data || size == 0) {
        return nullptr;
    }
    FT_Library lib = GetFreeTypeLibrary();
    if (!lib) {
        return nullptr;
    }
    FT_Face face = nullptr;
    if (FT_New_Memory_Face(lib, reinterpret_cast<const FT_Byte*>(data), static_cast<FT_Long>(size),
                           static_cast<FT_Long>(subfont_index), &face) != 0) {
        LOG_DEBUG(Lib_Font, "CreateFreeTypeFaceFromBytes: failed size={} subfont_index={}", size,
                  subfont_index);
        return nullptr;
    }
    (void)FT_Select_Charmap(face, FT_ENCODING_UNICODE);
    LOG_DEBUG(Lib_Font, "CreateFreeTypeFaceFromBytes: ok face={} size={} subfont_index={}",
              reinterpret_cast<const void*>(face), size, subfont_index);
    return face;
}

void DestroyFreeTypeFace(FT_Face& face) {
    if (!face) {
        return;
    }
    FT_Done_Face(face);
    face = nullptr;
}

namespace {

constexpr std::string_view kBuiltinFontPrefix = "@builtin/";
constexpr std::string_view kBuiltinFontLatin = "@builtin/NotoSans-Regular.ttf";
constexpr std::string_view kBuiltinFontArabic = "@builtin/NotoSansArabic-Regular.ttf";
constexpr std::string_view kBuiltinFontThai = "@builtin/NotoSansThai-Regular.ttf";
constexpr std::string_view kBuiltinFontSymbols = "@builtin/NotoSansSymbols2-Regular.ttf";
constexpr std::string_view kBuiltinFontCjkJp = "@builtin/NotoSansCJK-Regular.jp.ttc";
constexpr std::string_view kBuiltinFontCjkKr = "@builtin/NotoSansCJK-Regular.kr.ttc";
constexpr std::string_view kBuiltinFontCjkSc = "@builtin/NotoSansCJK-Regular.sc.ttc";
constexpr std::string_view kBuiltinFontCjkTc = "@builtin/NotoSansCJK-Regular.tc.ttc";

struct BuiltinFontBlob {
    std::string_view virtual_path;
    const unsigned char* compressed_data = nullptr;
    unsigned int compressed_size = 0;
    u32 face_index = 0;
};

static const std::array<BuiltinFontBlob, 8> kBuiltinFontBlobs{{
    BuiltinFontBlob{kBuiltinFontLatin, imgui_font_notosans_regular_compressed_data,
                    imgui_font_notosans_regular_compressed_size, 0},
    BuiltinFontBlob{kBuiltinFontArabic, imgui_font_notosansarabic_regular_compressed_data,
                    imgui_font_notosansarabic_regular_compressed_size, 0},
    BuiltinFontBlob{kBuiltinFontThai, imgui_font_notosansthai_regular_compressed_data,
                    imgui_font_notosansthai_regular_compressed_size, 0},
    BuiltinFontBlob{kBuiltinFontSymbols, imgui_font_notosanssymbols2_regular_compressed_data,
                    imgui_font_notosanssymbols2_regular_compressed_size, 0},
    BuiltinFontBlob{kBuiltinFontCjkJp, imgui_font_notosanscjk_regular_compressed_data,
                    imgui_font_notosanscjk_regular_compressed_size, 0},
    BuiltinFontBlob{kBuiltinFontCjkKr, imgui_font_notosanscjk_regular_compressed_data,
                    imgui_font_notosanscjk_regular_compressed_size, 1},
    BuiltinFontBlob{kBuiltinFontCjkSc, imgui_font_notosanscjk_regular_compressed_data,
                    imgui_font_notosanscjk_regular_compressed_size, 2},
    BuiltinFontBlob{kBuiltinFontCjkTc, imgui_font_notosanscjk_regular_compressed_data,
                    imgui_font_notosanscjk_regular_compressed_size, 3},
}};

static unsigned char* g_stb_barrier_out_e = nullptr;
static unsigned char* g_stb_barrier_out_b = nullptr;
static const unsigned char* g_stb_barrier_in_b = nullptr;
static unsigned char* g_stb_dout = nullptr;

static unsigned int StbDecompressLength(const unsigned char* input) {
    return (input[8] << 24) + (input[9] << 16) + (input[10] << 8) + input[11];
}

static void StbMatch(const unsigned char* data, unsigned int length) {
    if (g_stb_dout + length > g_stb_barrier_out_e) {
        g_stb_dout += length;
        return;
    }
    if (data < g_stb_barrier_out_b) {
        g_stb_dout = g_stb_barrier_out_e + 1;
        return;
    }
    while (length-- != 0u) {
        *g_stb_dout++ = *data++;
    }
}

static void StbLiteral(const unsigned char* data, unsigned int length) {
    if (g_stb_dout + length > g_stb_barrier_out_e) {
        g_stb_dout += length;
        return;
    }
    if (data < g_stb_barrier_in_b) {
        g_stb_dout = g_stb_barrier_out_e + 1;
        return;
    }
    std::memcpy(g_stb_dout, data, length);
    g_stb_dout += length;
}

#define STB_IN2(x) ((i[x] << 8) + i[(x) + 1])
#define STB_IN3(x) ((i[x] << 16) + STB_IN2((x) + 1))
#define STB_IN4(x) ((i[x] << 24) + STB_IN3((x) + 1))

static const unsigned char* StbDecompressToken(const unsigned char* i) {
    if (*i >= 0x20) {
        if (*i >= 0x80) {
            StbMatch(g_stb_dout - i[1] - 1, i[0] - 0x80 + 1);
            i += 2;
        } else if (*i >= 0x40) {
            StbMatch(g_stb_dout - (STB_IN2(0) - 0x4000 + 1), i[2] + 1);
            i += 3;
        } else {
            StbLiteral(i + 1, i[0] - 0x20 + 1);
            i += 1 + (i[0] - 0x20 + 1);
        }
    } else {
        if (*i >= 0x18) {
            StbMatch(g_stb_dout - (STB_IN3(0) - 0x180000 + 1), i[3] + 1);
            i += 4;
        } else if (*i >= 0x10) {
            StbMatch(g_stb_dout - (STB_IN3(0) - 0x100000 + 1), STB_IN2(3) + 1);
            i += 5;
        } else if (*i >= 0x08) {
            StbLiteral(i + 2, STB_IN2(0) - 0x0800 + 1);
            i += 2 + (STB_IN2(0) - 0x0800 + 1);
        } else if (*i == 0x07) {
            StbLiteral(i + 3, STB_IN2(1) + 1);
            i += 3 + (STB_IN2(1) + 1);
        } else if (*i == 0x06) {
            StbMatch(g_stb_dout - (STB_IN3(1) + 1), i[4] + 1);
            i += 5;
        } else if (*i == 0x04) {
            StbMatch(g_stb_dout - (STB_IN3(1) + 1), STB_IN2(4) + 1);
            i += 6;
        }
    }
    return i;
}

static unsigned int StbAdler32(unsigned int adler32, unsigned char* buffer,
                               unsigned int buffer_len) {
    constexpr unsigned long kAdlerMod = 65521;
    unsigned long s1 = adler32 & 0xffff;
    unsigned long s2 = adler32 >> 16;
    unsigned long block_len = buffer_len % 5552;

    while (buffer_len != 0u) {
        unsigned long i = 0;
        for (; i + 7 < block_len; i += 8) {
            s1 += buffer[0];
            s2 += s1;
            s1 += buffer[1];
            s2 += s1;
            s1 += buffer[2];
            s2 += s1;
            s1 += buffer[3];
            s2 += s1;
            s1 += buffer[4];
            s2 += s1;
            s1 += buffer[5];
            s2 += s1;
            s1 += buffer[6];
            s2 += s1;
            s1 += buffer[7];
            s2 += s1;
            buffer += 8;
        }
        for (; i < block_len; ++i) {
            s1 += *buffer++;
            s2 += s1;
        }
        s1 %= kAdlerMod;
        s2 %= kAdlerMod;
        buffer_len -= static_cast<unsigned int>(block_len);
        block_len = 5552;
    }
    return (static_cast<unsigned int>(s2) << 16) + static_cast<unsigned int>(s1);
}

static unsigned int StbDecompress(unsigned char* output, const unsigned char* i) {
    if (STB_IN4(0) != 0x57BC0000u || STB_IN4(4) != 0u) {
        return 0;
    }

    const unsigned int output_len = StbDecompressLength(i);
    g_stb_barrier_in_b = i;
    g_stb_barrier_out_e = output + output_len;
    g_stb_barrier_out_b = output;
    i += 16;

    g_stb_dout = output;
    for (;;) {
        const unsigned char* old_i = i;
        i = StbDecompressToken(i);
        if (i == old_i) {
            if (*i == 0x05 && i[1] == 0xFA) {
                if (g_stb_dout != output + output_len) {
                    return 0;
                }
                return StbAdler32(1, output, output_len) == static_cast<unsigned int>(STB_IN4(2))
                           ? output_len
                           : 0;
            }
            return 0;
        }
        if (g_stb_dout > output + output_len) {
            return 0;
        }
    }
}

#undef STB_IN2
#undef STB_IN3
#undef STB_IN4

static const BuiltinFontBlob* FindBuiltinFontBlob(const std::filesystem::path& path) {
    const std::string normalized = path.generic_string();
    for (const auto& blob : kBuiltinFontBlobs) {
        if (normalized == blob.virtual_path) {
            return &blob;
        }
    }
    return nullptr;
}

static std::string LowerAsciiString(std::string value) {
    for (auto& c : value) {
        c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
    }
    return value;
}

static bool StartsWithAsciiInsensitive(std::string_view value, std::string_view prefix) {
    if (value.size() < prefix.size()) {
        return false;
    }
    for (std::size_t i = 0; i < prefix.size(); ++i) {
        const auto lhs = static_cast<unsigned char>(value[i]);
        const auto rhs = static_cast<unsigned char>(prefix[i]);
        if (std::tolower(lhs) != std::tolower(rhs)) {
            return false;
        }
    }
    return true;
}

static bool EqualsAsciiInsensitive(std::string_view lhs, std::string_view rhs) {
    if (lhs.size() != rhs.size()) {
        return false;
    }
    return StartsWithAsciiInsensitive(lhs, rhs);
}

static bool IsThaiSeaWeightTag(u32 font_set_type) {
    const u32 tag = (font_set_type >> 8) & 0xFFu;
    u32 sea_weight_code = font_set_type & 0xFFu;
    switch (sea_weight_code) {
    case 0xD3u:
        sea_weight_code = 0x53u;
        break;
    case 0xD4u:
        sea_weight_code = 0x54u;
        break;
    case 0xD5u:
        sea_weight_code = 0x55u;
        break;
    case 0xD7u:
        sea_weight_code = 0x57u;
        break;
    default:
        break;
    }

    const bool is_sea_weight = (sea_weight_code == 0x53u) || (sea_weight_code == 0x54u) ||
                               (sea_weight_code == 0x55u) || (sea_weight_code == 0x57u);
    if (!is_sea_weight) {
        return false;
    }

    return (tag == 0x10u) || (tag == 0x14u) || (tag == 0x34u) || (tag == 0x90u) || (tag == 0x94u) ||
           (tag == 0xB0u) || (tag == 0xB4u) || (tag == 0xBCu);
}

static bool HasPathFilenameLower(const FontState& st, std::string_view filename_lower) {
    if (filename_lower.empty()) {
        return false;
    }
    const auto primary_lower = LowerAsciiString(st.system_font_path.filename().string());
    if (primary_lower == filename_lower) {
        return true;
    }
    for (const auto& fb : st.system_fallback_faces) {
        if (LowerAsciiString(fb.path.filename().string()) == filename_lower) {
            return true;
        }
    }
    return false;
}

static std::optional<std::filesystem::path> ResolveKnownSysFontAliasImpl(
    const std::filesystem::path& sysfonts_dir, std::string_view ps4_filename) {
    const auto resolve_existing =
        [&](std::string_view filename) -> std::optional<std::filesystem::path> {
        const std::filesystem::path file_path{std::string(filename)};
        std::error_code ec;
        {
            const auto candidate = sysfonts_dir / file_path;
            if (std::filesystem::exists(candidate, ec)) {
                return candidate;
            }
        }
        {
            const auto candidate = sysfonts_dir / "font" / file_path;
            if (std::filesystem::exists(candidate, ec)) {
                return candidate;
            }
        }
        {
            const auto candidate = sysfonts_dir / "font2" / file_path;
            if (std::filesystem::exists(candidate, ec)) {
                return candidate;
            }
        }
        return std::nullopt;
    };

    static constexpr std::array<std::pair<std::string_view, std::string_view>, 41> kAliases = {{
        {"SST-EU-ROMAN-L.OTF", "SST-Light.otf"},
        {"SST-EU-ROMAN.OTF", "SST-Roman.otf"},
        {"SST-EU-ROMAN-M.OTF", "SST-Medium.otf"},
        {"SST-EU-ROMAN-R.OTF", "SST-Roman.otf"},
        {"SST-EU-ROMAN-I.OTF", "SST-Italic.otf"},
        {"SST-EU-ROMAN-B.OTF", "SST-Bold.otf"},
        {"SST-EU-ROMAN-BI.OTF", "SST-BoldItalic.otf"},
        {"SST-ITALIC-L.OTF", "SST-LightItalic.otf"},
        {"SST-ITALIC-R.OTF", "SST-Italic.otf"},
        {"SST-ITALIC-M.OTF", "SST-MediumItalic.otf"},
        {"SST-ITALIC-B.OTF", "SST-BoldItalic.otf"},
        {"SST-TYPEWRITER-R.OTF", "SSTTypewriter-Roman.otf"},
        {"SST-TYPEWRITER-B.OTF", "SSTTypewriter-Bd.otf"},
        {"SST-JPPRO-R.OTF", "SSTJpPro-Regular.otf"},
        {"SST-JPPRO-B.OTF", "SSTJpPro-Bold.otf"},
        {"SST-CNGB-HEI-R.TTF", "DFHEI5-SONY.ttf"},
        {"SST-ARIB-STD-B24-R.TTF", "SSTAribStdB24-Regular.ttf"},
        {"SST-ARABIC-R.OTF", "SSTArabic-Roman.otf"},
        {"SST-ARABIC-L.OTF", "SSTArabic-Light.otf"},
        {"SST-ARABIC-M.OTF", "SSTArabic-Medium.otf"},
        {"SST-ARABIC-B.OTF", "SSTArabic-Bold.otf"},
        {"SCE-EXT-HANGUL-L.OTF", "SCEPS4Yoongd-Light.otf"},
        {"SCE-EXT-HANGUL-R.OTF", "SCEPS4Yoongd-Medium.otf"},
        {"SCE-EXT-HANGUL-B.OTF", "SCEPS4Yoongd-Bold.otf"},
        {"SSTCC-SERIF-MONO.OTF", "e046323ms.ttf"},
        {"SSTCC-SERIF.OTF", "e046323ts.ttf"},
        {"SSTCC-SANSSERIF-MONO.OTF", "n023055ms.ttf"},
        {"SSTCC-SANSSERIF.OTF", "n023055ts.ttf"},
        {"SSTCC-CUSUAL.OTF", "d013013ds.ttf"},
        {"SSTCC-CURSIVE.OTF", "k006004ds.ttf"},
        {"SSTCC-SMALLCAPITAL.OTF", "c041056ts.ttf"},
        {"SCE-JP-CATTLEYA-L.OTF", "SCE-RDC-R-JPN.otf"},
        {"SCE-JP-CATTLEYA-B.OTF", "SCE-RDC-B-JPN.otf"},
        {"SST-THAI-L.OTF", "SSTThai-Light.otf"},
        {"SST-THAI-R.OTF", "SSTThai-Roman.otf"},
        {"SST-THAI-M.OTF", "SSTThai-Medium.otf"},
        {"SST-THAI-B.OTF", "SSTThai-Bold.otf"},
        {"SST-VIETNAMESE-L.OTF", "SSTVietnamese-Light.otf"},
        {"SST-VIETNAMESE-R.OTF", "SSTVietnamese-Roman.otf"},
        {"SST-VIETNAMESE-M.OTF", "SSTVietnamese-Medium.otf"},
        {"SST-VIETNAMESE-B.OTF", "SSTVietnamese-Bold.otf"},
    }};

    for (const auto& [from, to] : kAliases) {
        if (ps4_filename == from) {
            return resolve_existing(to);
        }
        if (ps4_filename == to) {
            if (auto reverse = resolve_existing(from)) {
                return reverse;
            }
        }
    }
    return std::nullopt;
}

static std::mutex g_sysfont_file_cache_mutex;
static std::unordered_map<std::string, std::shared_ptr<std::vector<unsigned char>>>
    g_sysfont_file_cache;

static std::shared_ptr<std::vector<unsigned char>> GetCachedFontBytes(
    const std::filesystem::path& host_path) {
    const std::string key = host_path.string();
    {
        std::scoped_lock lock(g_sysfont_file_cache_mutex);
        if (auto it = g_sysfont_file_cache.find(key); it != g_sysfont_file_cache.end()) {
            return it->second;
        }
    }

    std::vector<unsigned char> bytes;
    if (!LoadGuestFileBytes(host_path, bytes) || bytes.empty()) {
        return {};
    }

    auto shared = std::make_shared<std::vector<unsigned char>>(std::move(bytes));
    {
        std::scoped_lock lock(g_sysfont_file_cache_mutex);
        g_sysfont_file_cache.emplace(key, shared);
    }
    return shared;
}

} // namespace

std::optional<std::filesystem::path> ResolveKnownSysFontAlias(
    const std::filesystem::path& sysfonts_dir, std::string_view ps4_filename) {
    return ResolveKnownSysFontAliasImpl(sysfonts_dir, ps4_filename);
}

FontState::~FontState() {
    DestroyFreeTypeFace(ext_ft_face);
    for (auto& fb : system_fallback_faces) {
        DestroyFreeTypeFace(fb.ft_face);
    }
}

std::mutex g_generated_glyph_mutex;
std::unordered_set<OrbisFontGlyph> g_generated_glyphs;

void TrackGeneratedGlyph(OrbisFontGlyph glyph) {
    std::scoped_lock lock(g_generated_glyph_mutex);
    g_generated_glyphs.insert(glyph);
}

bool ForgetGeneratedGlyph(OrbisFontGlyph glyph) {
    std::scoped_lock lock(g_generated_glyph_mutex);
    return g_generated_glyphs.erase(glyph) > 0;
}

GeneratedGlyph* TryGetGeneratedGlyph(OrbisFontGlyph glyph) {
    if (!glyph || glyph->magic != 0x0F03) {
        return nullptr;
    }
    std::scoped_lock lock(g_generated_glyph_mutex);
    if (g_generated_glyphs.find(glyph) == g_generated_glyphs.end()) {
        return nullptr;
    }
    return reinterpret_cast<GeneratedGlyph*>(glyph);
}

void PopulateGlyphMetricVariants(GeneratedGlyph& gg) {
    if (gg.metrics_initialized) {
        return;
    }
    gg.metrics_horizontal.width = gg.metrics.width;
    gg.metrics_horizontal.height = gg.metrics.height;
    gg.metrics_horizontal.horizontal.bearing_x = gg.metrics.Horizontal.bearingX;
    gg.metrics_horizontal.horizontal.bearing_y = gg.metrics.Horizontal.bearingY;
    gg.metrics_horizontal.horizontal.advance = gg.metrics.Horizontal.advance;

    gg.metrics_horizontal_x.width = gg.metrics.width;
    gg.metrics_horizontal_x.horizontal.bearing_x = gg.metrics.Horizontal.bearingX;
    gg.metrics_horizontal_x.horizontal.advance = gg.metrics.Horizontal.advance;

    gg.metrics_horizontal_adv.horizontal.advance = gg.metrics.Horizontal.advance;
    gg.origin_x = static_cast<float>(gg.bbox_x0);
    gg.origin_y = static_cast<float>(gg.bbox_y0);
    gg.metrics_initialized = true;
}

void BuildBoundingOutline(GeneratedGlyph& gg) {
    const float left = gg.metrics.Horizontal.bearingX;
    const float top = gg.metrics.Horizontal.bearingY;
    const float right = gg.metrics.Horizontal.bearingX + gg.metrics.width;
    const float bottom = gg.metrics.Horizontal.bearingY - gg.metrics.height;

    gg.outline_points.clear();
    gg.outline_tags.clear();
    gg.outline_contours.clear();

    gg.outline_points.push_back({left, top});
    gg.outline_points.push_back({right, top});
    gg.outline_points.push_back({right, bottom});
    gg.outline_points.push_back({left, bottom});

    gg.outline_tags.resize(gg.outline_points.size(), 1);
    gg.outline_contours.push_back(static_cast<u16>(gg.outline_points.size() - 1));

    gg.outline.points_ptr = gg.outline_points.data();
    gg.outline.tags_ptr = gg.outline_tags.data();
    gg.outline.contour_end_idx = gg.outline_contours.data();
    gg.outline.points_cnt = static_cast<s16>(gg.outline_points.size());
    gg.outline.contours_cnt = static_cast<s16>(gg.outline_contours.size());
    gg.outline_initialized = true;
}

bool BuildTrueOutline(GeneratedGlyph& gg) {
    auto* st = TryGetState(gg.owner_handle);
    if (!st) {
        return false;
    }

    FT_Face primary_face = nullptr;
    if (!ResolveFace(*st, gg.owner_handle, primary_face)) {
        return false;
    }

    const auto* native =
        reinterpret_cast<const Libraries::Font::FontHandleOpaqueNative*>(gg.owner_handle);
    if (!native || native->magic != 0x0F02) {
        return false;
    }

    u32 resolved_code = gg.codepoint;
    u32 resolved_font_id = 0;
    FT_Face resolved_face = primary_face;
    float resolved_scale_factor = 1.0f;
    float range_scale = 1.0f;
    s32 shift_x_units = 0;
    s32 shift_y_units = 0;

    if (native->open_info.fontset_record) {
        const auto* fontset_record =
            static_cast<const FontSetRecordHeader*>(native->open_info.fontset_record);
        const bool is_internal_fontset_record =
            fontset_record &&
            fontset_record->magic == Libraries::Font::Internal::FontSetSelector::kMagic;
        u32 mapped_font_id = 0;
        resolved_code = ResolveSysFontCodepoint(native->open_info.fontset_record,
                                                static_cast<u64>(gg.codepoint),
                                                native->open_info.fontset_flags, &mapped_font_id);
        if (resolved_code == 0) {
            return false;
        }

        resolved_font_id = mapped_font_id;
        if (!is_internal_fontset_record) {
            resolved_scale_factor = st->system_font_scale_factor;
        }
        if (st->system_requested) {
            if (mapped_font_id == st->system_font_id) {
                resolved_face = st->ext_ft_face;
                shift_y_units = st->system_font_shift_value;
            } else {
                resolved_face = nullptr;
                for (const auto& fb : st->system_fallback_faces) {
                    if (fb.ready && fb.ft_face && fb.font_id == mapped_font_id) {
                        resolved_face = fb.ft_face;
                        resolved_scale_factor = fb.scale_factor;
                        shift_y_units = fb.shift_value;
                        break;
                    }
                }
            }
        }
        if (!resolved_face) {
            return false;
        }
        if (!is_internal_fontset_record) {
            if (shift_y_units == 0) {
                shift_y_units = GetSysFontDesc(mapped_font_id).shift_value;
            }
            if (const std::uint8_t* range_rec =
                    FindSysFontRangeRecord(mapped_font_id, resolved_code)) {
                SysFontRangeRecord rec{};
                std::memcpy(&rec, range_rec, sizeof(rec));
                shift_x_units = static_cast<s32>(rec.shift_x);
                shift_y_units += static_cast<s32>(rec.shift_y);
                range_scale = rec.scale_mul;
                if (range_scale == 0.0f) {
                    range_scale = 1.0f;
                }
            }
        }
    }

    if (!resolved_face) {
        return false;
    }

    const FT_UInt glyph_index =
        FT_Get_Char_Index(resolved_face, static_cast<FT_ULong>(resolved_code));
    if (glyph_index == 0) {
        return false;
    }

    const float scaled_w = gg.glyph.scale_x * resolved_scale_factor * range_scale;
    const float scaled_h = gg.glyph.base_scale * resolved_scale_factor * range_scale;
    const auto char_w = static_cast<FT_F26Dot6>(static_cast<s32>(scaled_w * 64.0f));
    const auto char_h = static_cast<FT_F26Dot6>(static_cast<s32>(scaled_h * 64.0f));
    if (FT_Set_Char_Size(resolved_face, char_w, char_h, 72, 72) != 0) {
        return false;
    }

    if (shift_x_units != 0 || shift_y_units != 0) {
        if (!resolved_face->size) {
            return false;
        }
        const long x_scale = static_cast<long>(resolved_face->size->metrics.x_scale);
        const long y_scale = static_cast<long>(resolved_face->size->metrics.y_scale);

        FT_Vector delta{};
        delta.x = static_cast<FT_Pos>(RoundFixedMul16x16ToS32(x_scale, shift_x_units));
        delta.y = static_cast<FT_Pos>(RoundFixedMul16x16ToS32(y_scale, shift_y_units));
        FT_Set_Transform(resolved_face, nullptr, &delta);
    } else {
        FT_Set_Transform(resolved_face, nullptr, nullptr);
    }

    constexpr FT_Int32 kFtLoadFlagsBase =
        static_cast<FT_Int32>(FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP);
    const bool loaded = (FT_Load_Glyph(resolved_face, glyph_index, kFtLoadFlagsBase) == 0);
    FT_Set_Transform(resolved_face, nullptr, nullptr);
    if (!loaded) {
        return false;
    }

    const FT_GlyphSlot slot = resolved_face->glyph;
    if (!slot || slot->format != FT_GLYPH_FORMAT_OUTLINE) {
        return false;
    }

    const FT_Outline& outline = slot->outline;
    if (outline.n_points <= 0 || outline.n_contours <= 0 || !outline.points || !outline.tags ||
        !outline.contours) {
        return false;
    }

    gg.outline_points.clear();
    gg.outline_tags.clear();
    gg.outline_contours.clear();
    gg.outline_points.reserve(static_cast<std::size_t>(outline.n_points));
    gg.outline_tags.reserve(static_cast<std::size_t>(outline.n_points));
    gg.outline_contours.reserve(static_cast<std::size_t>(outline.n_contours));

    for (int i = 0; i < outline.n_points; ++i) {
        const FT_Vector& p = outline.points[i];
        gg.outline_points.push_back(
            {static_cast<float>(p.x) / 64.0f, static_cast<float>(p.y) / 64.0f});
        const std::uint8_t tag = outline.tags[i];
        gg.outline_tags.push_back(FT_CURVE_TAG(tag) == FT_CURVE_TAG_ON ? 1 : 0);
    }
    for (int c = 0; c < outline.n_contours; ++c) {
        gg.outline_contours.push_back(static_cast<u16>(outline.contours[c]));
    }

    const bool ok = !gg.outline_points.empty() && !gg.outline_contours.empty();
    if (!ok) {
        return false;
    }

    gg.outline.points_ptr = gg.outline_points.data();
    gg.outline.tags_ptr = gg.outline_tags.data();
    gg.outline.contour_end_idx = gg.outline_contours.data();
    gg.outline.points_cnt = static_cast<s16>(gg.outline_points.size());
    gg.outline.contours_cnt = static_cast<s16>(gg.outline_contours.size());
    gg.outline_initialized = true;
    return true;
}

u16 ClampToU16(float value) {
    if (value <= 0.0f) {
        return 0;
    }
    const float clamped = std::min(value, static_cast<float>(std::numeric_limits<u16>::max()));
    return static_cast<u16>(std::lround(clamped));
}

FontState& GetState(Libraries::Font::OrbisFontHandle h) {
    std::scoped_lock lock(g_state_mutex);
    return g_font_state[h];
}

FontState* TryGetState(Libraries::Font::OrbisFontHandle h) {
    if (!h)
        return nullptr;
    std::scoped_lock lock(g_state_mutex);
    auto it = g_font_state.find(h);
    if (it == g_font_state.end())
        return nullptr;
    return &it->second;
}

void RemoveState(Libraries::Font::OrbisFontHandle h) {
    if (!h) {
        return;
    }
    std::scoped_lock lock(g_state_mutex);
    g_font_state.erase(h);
}

LibraryState& GetLibState(Libraries::Font::OrbisFontLib lib) {
    std::scoped_lock lock(g_state_mutex);
    return g_library_state[lib];
}

bool AcquireLibraryLock(FontLibOpaque* lib, u32& out_prev_lock_word) {
    if (!lib) {
        return false;
    }

    for (;;) {
        const u32 lock_word = lib->lock_word;
        if (lib->magic != 0x0F01) {
            return false;
        }
        if (static_cast<s32>(lock_word) < 0) {
            Libraries::Kernel::sceKernelUsleep(0x1e);
            continue;
        }

        std::atomic_ref<u32> ref(lib->lock_word);
        u32 expected = lock_word;
        if (ref.compare_exchange_weak(expected, lock_word | 0x80000000u,
                                      std::memory_order_acq_rel)) {
            out_prev_lock_word = lock_word;
            return true;
        }
        Libraries::Kernel::sceKernelUsleep(0x1e);
    }
}

void ReleaseLibraryLock(FontLibOpaque* lib, u32 prev_lock_word) {
    if (!lib) {
        return;
    }
    lib->lock_word = prev_lock_word & 0x7fffffff;
}

void RemoveLibState(Libraries::Font::OrbisFontLib lib) {
    LibraryState state{};
    {
        std::scoped_lock lock(g_state_mutex);
        auto it = g_library_state.find(lib);
        if (it == g_library_state.end()) {
            return;
        }
        state = std::move(it->second);
        g_library_state.erase(it);
    }

    const auto free_fn = state.free_fn;
    const auto alloc_ctx = state.alloc_ctx;
    auto free_owned = [&](void* p) {
        if (!p) {
            return;
        }
        if (free_fn) {
            const auto free_fn_guest =
                reinterpret_cast<void(PS4_SYSV_ABI*)(void* object, void* p)>(free_fn);
            free_fn_guest(alloc_ctx, p);
            return;
        }
        std::free(p);
    };

    free_owned(state.owned_device_cache);
    free_owned(state.owned_external_fonts_ctx);
    free_owned(state.owned_sysfonts_ctx);
    free_owned(state.owned_mspace);
}

void LogFontOpenError(s32 rc) {
    switch (rc) {
    case ORBIS_FONT_ERROR_INVALID_LIBRARY:
        LOG_ERROR(Lib_Font, "INVALID_LIBRARY");
        break;
    case ORBIS_FONT_ERROR_INVALID_PARAMETER:
        LOG_ERROR(Lib_Font, "INVALID_PARAMETER");
        break;
    case ORBIS_FONT_ERROR_ALLOCATION_FAILED:
        LOG_ERROR(Lib_Font, "ALLOCATION_FAILED");
        break;
    case ORBIS_FONT_ERROR_FS_OPEN_FAILED:
        LOG_ERROR(Lib_Font, "FS_OPEN_FAILED");
        break;
    case ORBIS_FONT_ERROR_NO_SUPPORT_FUNCTION:
        LOG_ERROR(Lib_Font, "NO_SUPPORT_FUNCTION");
        break;
    case ORBIS_FONT_ERROR_NO_SUPPORT_FORMAT:
        LOG_ERROR(Lib_Font, "NO_SUPPORT_FORMAT");
        break;
    case ORBIS_FONT_ERROR_NO_SUPPORT_FONTSET:
        LOG_ERROR(Lib_Font, "NO_SUPPORT_FONTSET");
        break;
    case ORBIS_FONT_ERROR_FONT_OPEN_MAX:
        LOG_ERROR(Lib_Font, "FONT_OPEN_MAX");
        break;
    default:
        LOG_ERROR(Lib_Font, "FAILED");
        break;
    }
}

void LogExternalFormatSupport(u32 formats_mask) {
    LOG_INFO(Lib_Font, "ExternalFormatsMask=0x{:X}", formats_mask);
}

bool LoadFontFile(const std::filesystem::path& path, std::vector<unsigned char>& out_bytes);

void LogFontOpenParams(const Libraries::Font::OrbisFontOpenParams* params) {
    if (!params) {
        LOG_INFO(Lib_Font, "OpenFontSetParams: <null>");
        return;
    }
    LOG_INFO(
        Lib_Font,
        "OpenFontSetParams: tag=0x{:04X} flags=0x{:X} subfont={} unique_id={} reserved_ptrs=[{}, "
        "{}]",
        params->tag, params->flags, params->subfont_index, params->unique_id, params->reserved_ptr1,
        params->reserved_ptr2);
}

std::filesystem::path ResolveGuestPath(const char* guest_path) {
    if (!guest_path) {
        return {};
    }
    if (guest_path[0] != '/') {
        return std::filesystem::path(guest_path);
    }
    if (!g_mnt) {
        g_mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
    }
    if (!g_mnt) {
        return {};
    }
    return g_mnt->GetHostPath(guest_path);
}

bool LoadGuestFileBytes(const std::filesystem::path& host_path,
                        std::vector<unsigned char>& out_bytes) {
    std::ifstream file(host_path, std::ios::binary | std::ios::ate);
    if (!file) {
        return false;
    }
    const std::streamoff size = file.tellg();
    if (size < 0) {
        return false;
    }
    if (size == 0) {
        out_bytes.clear();
        return true;
    }
    if (static_cast<std::uint64_t>(size) > std::numeric_limits<std::size_t>::max()) {
        return false;
    }
    out_bytes.resize(static_cast<std::size_t>(size));
    file.seekg(0, std::ios::beg);
    if (!file.read(reinterpret_cast<char*>(out_bytes.data()),
                   static_cast<std::streamsize>(out_bytes.size()))) {
        out_bytes.clear();
        return false;
    }
    return true;
}

FaceMetrics LoadFaceMetrics(FT_Face face) {
    FaceMetrics m{};
    if (!face) {
        return m;
    }
    m.units_per_em = static_cast<int>(face->units_per_EM);

    if (const auto* hhea =
            static_cast<const TT_HoriHeader*>(FT_Get_Sfnt_Table(face, ft_sfnt_hhea))) {
        m.hhea_ascent = static_cast<int>(hhea->Ascender);
        m.hhea_descent = static_cast<int>(hhea->Descender);
        m.hhea_lineGap = static_cast<int>(hhea->Line_Gap);
    } else {
        m.hhea_ascent = static_cast<int>(face->ascender);
        m.hhea_descent = static_cast<int>(face->descender);
        const int height = static_cast<int>(face->height);
        m.hhea_lineGap = height - (m.hhea_ascent - m.hhea_descent);
    }

    if (const auto* os2 = static_cast<const TT_OS2*>(FT_Get_Sfnt_Table(face, ft_sfnt_os2))) {
        m.has_typo = true;
        m.typo_ascent = static_cast<int>(os2->sTypoAscender);
        m.typo_descent = static_cast<int>(os2->sTypoDescender);
        m.typo_lineGap = static_cast<int>(os2->sTypoLineGap);
        m.use_typo = (os2->fsSelection & (1u << 7)) != 0;
    }
    return m;
}

void PopulateStateMetrics(FontState& st, const FaceMetrics& m) {
    st.ext_units_per_em = m.units_per_em;
    st.ext_ascent = m.use_typo && m.has_typo ? m.typo_ascent : m.hhea_ascent;
    st.ext_descent = m.use_typo && m.has_typo ? m.typo_descent : m.hhea_descent;
    st.ext_lineGap = m.use_typo && m.has_typo ? m.typo_lineGap : m.hhea_lineGap;
    st.ext_typo_ascent = m.typo_ascent;
    st.ext_typo_descent = m.typo_descent;
    st.ext_typo_lineGap = m.typo_lineGap;
    st.ext_use_typo_metrics = m.use_typo && m.has_typo;
}

float ComputeScaleExtForState(const FontState& st, FT_Face face, float pixel_h) {
    if (st.ext_units_per_em > 0) {
        return pixel_h / static_cast<float>(st.ext_units_per_em);
    }
    if (!face || face->units_per_EM == 0) {
        return 0.0f;
    }
    return pixel_h / static_cast<float>(face->units_per_EM);
}

float ComputeScaleForPixelHeight(const FontState& st, float pixel_h) {
    if (st.ext_units_per_em <= 0) {
        return 0.0f;
    }
    return pixel_h / static_cast<float>(st.ext_units_per_em);
}

const float kPointsPerInch = 72.0f;
const float kScaleEpsilon = 1e-4f;

float SafeDpiToFloat(u32 dpi) {
    return dpi == 0 ? kPointsPerInch : static_cast<float>(dpi);
}

float PointsToPixels(float pt, u32 dpi) {
    return pt * SafeDpiToFloat(dpi) / kPointsPerInch;
}

float PixelsToPoints(float px, u32 dpi) {
    const float dpi_f = SafeDpiToFloat(dpi);
    return px * kPointsPerInch / dpi_f;
}

const u16 kStyleFrameMagic = 0x0F09;
const u8 kStyleFrameFlagScale = 0x01;
const u8 kStyleFrameFlagSlant = 0x02;
const u8 kStyleFrameFlagWeight = 0x04;

StyleFrameScaleState ResolveStyleFrameScale(const OrbisFontStyleFrame* style, const FontState& st) {
    StyleFrameScaleState resolved{
        .scale_w = st.scale_w,
        .scale_h = st.scale_h,
        .dpi_x = st.dpi_x,
        .dpi_y = st.dpi_y,
        .scale_overridden = false,
        .dpi_overridden = false,
    };
    if (!style || style->magic != kStyleFrameMagic) {
        return resolved;
    }
    if ((style->flags1 & kStyleFrameFlagScale) != 0) {
        const bool unit_is_pixel = (style->scaleUnit == 0);
        const u32 dpi_x = style->hDpi;
        const u32 dpi_y = style->vDpi;
        resolved.scale_w = unit_is_pixel ? style->scalePixelW
                                         : (dpi_x ? PointsToPixels(style->scalePixelW, dpi_x)
                                                  : style->scalePixelW);
        resolved.scale_h = unit_is_pixel ? style->scalePixelH
                                         : (dpi_y ? PointsToPixels(style->scalePixelH, dpi_y)
                                                  : style->scalePixelH);
        resolved.scale_overridden = true;
    }
    if (!resolved.scale_overridden && st.scale_point_active) {
        resolved.scale_w = PointsToPixels(st.scale_point_w, resolved.dpi_x);
        resolved.scale_h = PointsToPixels(st.scale_point_h, resolved.dpi_y);
    }
    return resolved;
}

void InitializeStyleFrame(OrbisFontStyleFrame& frame) {
    std::memset(&frame, 0, sizeof(frame));
    frame.magic = kStyleFrameMagic;
    frame.hDpi = 72;
    frame.vDpi = 72;
}

bool EnsureStyleFrameInitialized(OrbisFontStyleFrame* frame) {
    return ValidateStyleFramePtr(frame);
}

bool ValidateStyleFramePtr(const OrbisFontStyleFrame* frame) {
    return frame && frame->magic == kStyleFrameMagic;
}

void UpdateCachedLayout(FontState& st) {
    if (!st.ext_face_ready || !st.ext_ft_face) {
        return;
    }
    if (st.ext_scale_for_height == 0.0f) {
        st.ext_scale_for_height =
            ComputeScaleExtForState(st, st.ext_ft_face, st.scale_h * st.system_font_scale_factor);
    }
    const float scale = st.ext_scale_for_height;
    st.cached_baseline_y = static_cast<float>(st.ext_ascent) * scale;
    st.layout_cached = true;
}

std::uint64_t MakeGlyphKey(u32 code, int pixel_h) {
    return (static_cast<std::uint64_t>(code) << 32) | static_cast<std::uint32_t>(pixel_h);
}

void ClearRenderOutputs(Libraries::Font::OrbisFontGlyphMetrics* metrics,
                        Libraries::Font::OrbisFontRenderOutput* result) {
    if (metrics) {
        *metrics = {};
    }
    if (result) {
        *result = {};
    }
}

bool ResolveFaceAndScale(FontState& st, Libraries::Font::OrbisFontHandle handle, float pixel_h,
                         FT_Face& face_out, float& scale_y_out) {
    face_out = nullptr;
    scale_y_out = 0.0f;
    if (st.ext_face_ready) {
        face_out = st.ext_ft_face;
    }
    if (!face_out) {
        bool system_attached = false;
        const std::string sys_log = ReportSystemFaceRequest(st, handle, system_attached);
        if (!sys_log.empty()) {
            LOG_ERROR(Lib_Font, "{}", sys_log);
        }
        if (system_attached) {
            face_out = st.ext_ft_face;
        }
    }
    if (pixel_h <= kScaleEpsilon) {
        return false;
    }
    if (!face_out) {
        return false;
    }
    scale_y_out = ComputeScaleExtForState(st, face_out, pixel_h * st.system_font_scale_factor);
    return scale_y_out > kScaleEpsilon;
}

bool ResolveFace(FontState& st, Libraries::Font::OrbisFontHandle handle, FT_Face& face_out) {
    face_out = nullptr;
    if (st.ext_face_ready) {
        face_out = st.ext_ft_face;
    }
    if (!face_out) {
        bool system_attached = false;
        const std::string sys_log = ReportSystemFaceRequest(st, handle, system_attached);
        if (!sys_log.empty()) {
            LOG_ERROR(Lib_Font, "{}", sys_log);
        }
        if (system_attached) {
            face_out = st.ext_ft_face;
        }
    }
    return face_out != nullptr;
}

s32 RenderCodepointToSurface(FontState& st, Libraries::Font::OrbisFontHandle handle, FT_Face face,
                             float pixel_w, float pixel_h,
                             Libraries::Font::OrbisFontRenderSurface* surf, u32 code, float x,
                             float y, Libraries::Font::OrbisFontGlyphMetrics* metrics,
                             Libraries::Font::OrbisFontRenderOutput* result, s32 shift_x_units,
                             s32 shift_y_units) {
    ClearRenderOutputs(metrics, result);

    if (!surf || !metrics || !result) {
        return ORBIS_FONT_ERROR_INVALID_PARAMETER;
    }
    if (!surf->buffer || surf->width <= 0 || surf->height <= 0 || surf->widthByte <= 0 ||
        surf->pixelSizeByte <= 0) {
        return ORBIS_FONT_ERROR_NO_SUPPORT_SURFACE;
    }

    const int bpp = static_cast<int>(surf->pixelSizeByte);
    if (bpp != 1 && bpp != 4) {
        return ORBIS_FONT_ERROR_NO_SUPPORT_SURFACE;
    }

    FT_Face primary_face = face;
    if (!primary_face) {
        float primary_scale_y = 0.0f;
        if (!ResolveFaceAndScale(st, handle, pixel_h, primary_face, primary_scale_y)) {
            return ORBIS_FONT_ERROR_NO_SUPPORT_GLYPH;
        }
    }

    auto resolve_scale_factor = [&](FT_Face candidate) -> float {
        if (!candidate) {
            return st.system_font_scale_factor;
        }
        if (candidate == st.ext_ft_face) {
            return st.system_font_scale_factor;
        }
        for (const auto& fb : st.system_fallback_faces) {
            if (fb.ready && fb.ft_face == candidate) {
                return fb.scale_factor;
            }
        }
        return st.system_font_scale_factor;
    };

    FT_Face resolved_face = primary_face;
    FT_UInt resolved_glyph_index =
        resolved_face ? FT_Get_Char_Index(resolved_face, static_cast<FT_ULong>(code)) : 0;
    float resolved_scale_factor = resolve_scale_factor(resolved_face);
    if (resolved_glyph_index == 0) {
        if (st.ext_face_ready && st.ext_ft_face && resolved_face != st.ext_ft_face) {
            const FT_UInt gi = FT_Get_Char_Index(st.ext_ft_face, static_cast<FT_ULong>(code));
            if (gi != 0) {
                resolved_face = st.ext_ft_face;
                resolved_glyph_index = gi;
                resolved_scale_factor = st.system_font_scale_factor;
            }
        }
        if (resolved_glyph_index == 0) {
            for (const auto& fb : st.system_fallback_faces) {
                if (!fb.ready || !fb.ft_face) {
                    continue;
                }
                const FT_UInt gi = FT_Get_Char_Index(fb.ft_face, static_cast<FT_ULong>(code));
                if (gi == 0) {
                    continue;
                }
                resolved_face = fb.ft_face;
                resolved_glyph_index = gi;
                resolved_scale_factor = fb.scale_factor;
                break;
            }
        }
    }
    if (!resolved_face || resolved_glyph_index == 0) {
        return ORBIS_FONT_ERROR_NO_SUPPORT_GLYPH;
    }

    const auto set_size = [&](float w, float h) -> bool {
        const auto char_w = static_cast<FT_F26Dot6>(static_cast<s32>(w * 64.0f));
        const auto char_h = static_cast<FT_F26Dot6>(static_cast<s32>(h * 64.0f));
        return FT_Set_Char_Size(resolved_face, char_w, char_h, 72, 72) == 0;
    };
    if (!set_size(pixel_w * resolved_scale_factor, pixel_h * resolved_scale_factor)) {
        return ORBIS_FONT_ERROR_NO_SUPPORT_GLYPH;
    }

    const float frac_x = x - std::floor(x);
    const float frac_y = y - std::floor(y);
    FT_Vector delta{};
    delta.x = static_cast<FT_Pos>(static_cast<s32>(frac_x * 64.0f));
    delta.y = static_cast<FT_Pos>(-static_cast<s32>(frac_y * 64.0f));

    if ((shift_x_units != 0 || shift_y_units != 0) && resolved_face->size) {
        const long x_scale = static_cast<long>(resolved_face->size->metrics.x_scale);
        const long y_scale = static_cast<long>(resolved_face->size->metrics.y_scale);

        delta.x += static_cast<FT_Pos>(RoundFixedMul16x16ToS32(x_scale, shift_x_units));
        delta.y += static_cast<FT_Pos>(RoundFixedMul16x16ToS32(y_scale, shift_y_units));
    }
    FT_Set_Transform(resolved_face, nullptr, &delta);

    if (FT_Load_Glyph(resolved_face, resolved_glyph_index, kFtLoadFlagsRender) != 0) {
        FT_Set_Transform(resolved_face, nullptr, nullptr);
        return ORBIS_FONT_ERROR_NO_SUPPORT_GLYPH;
    }
    std::vector<unsigned char> glyph_bitmap;
    int x0 = 0, y0 = 0;
    int glyph_w = 0;
    int glyph_h = 0;

    const FT_GlyphSlot slot = resolved_face->glyph;
    glyph_w = static_cast<int>(slot->bitmap.width);
    glyph_h = static_cast<int>(slot->bitmap.rows);
    x0 = static_cast<int>(slot->bitmap_left);
    y0 = -static_cast<int>(slot->bitmap_top);
    FT_Set_Transform(resolved_face, nullptr, nullptr);

    const float bearing_x = static_cast<float>(slot->metrics.horiBearingX) / 64.0f;
    const float bearing_y = static_cast<float>(slot->metrics.horiBearingY) / 64.0f;
    const float advance = static_cast<float>(slot->metrics.horiAdvance) / 64.0f;
    const float width_px = static_cast<float>(slot->metrics.width) / 64.0f;
    const float height_px = static_cast<float>(slot->metrics.height) / 64.0f;

    metrics->width = width_px;
    metrics->height = height_px;
    metrics->Horizontal.bearingX = bearing_x;
    metrics->Horizontal.bearingY = bearing_y;
    metrics->Horizontal.advance = advance;
    metrics->Vertical.bearingX = 0.0f;
    metrics->Vertical.bearingY = 0.0f;
    metrics->Vertical.advance = 0.0f;

    glyph_bitmap.resize(static_cast<std::size_t>(glyph_w) * static_cast<std::size_t>(glyph_h));
    if (glyph_w > 0 && glyph_h > 0) {
        const int pitch = static_cast<int>(slot->bitmap.pitch);
        const unsigned char* src = reinterpret_cast<const unsigned char*>(slot->bitmap.buffer);
        if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) {
            for (int row = 0; row < glyph_h; ++row) {
                const unsigned char* src_row = src + static_cast<std::size_t>(row) * pitch;
                unsigned char* dst_row =
                    glyph_bitmap.data() + static_cast<std::size_t>(row) * glyph_w;
                for (int col = 0; col < glyph_w; ++col) {
                    const unsigned char byte = src_row[col >> 3];
                    const unsigned char bit = static_cast<unsigned char>(0x80u >> (col & 7));
                    dst_row[col] = (byte & bit) ? 0xFFu : 0x00u;
                }
            }
        } else {
            for (int row = 0; row < glyph_h; ++row) {
                const unsigned char* src_row = src + static_cast<std::size_t>(row) * pitch;
                unsigned char* dst_row =
                    glyph_bitmap.data() + static_cast<std::size_t>(row) * glyph_w;
                std::memcpy(dst_row, src_row, static_cast<std::size_t>(glyph_w));
            }
        }
    }

    const int dest_x = static_cast<int>(std::floor(x)) + x0;
    const int dest_y = static_cast<int>(std::floor(y)) + y0;

    const int surface_w = std::max(surf->width, 0);
    const int surface_h = std::max(surf->height, 0);
    const int clip_x0 = std::clamp(static_cast<int>(surf->sc_x0), 0, surface_w);
    const int clip_y0 = std::clamp(static_cast<int>(surf->sc_y0), 0, surface_h);
    const int clip_x1 = std::clamp(static_cast<int>(surf->sc_x1), 0, surface_w);
    const int clip_y1 = std::clamp(static_cast<int>(surf->sc_y1), 0, surface_h);

    int update_x0 = dest_x;
    int update_y0 = dest_y;
    int update_w = 0;
    int update_h = 0;

    if (glyph_w > 0 && glyph_h > 0 && clip_x1 > clip_x0 && clip_y1 > clip_y0) {
        auto* dst_base = static_cast<std::uint8_t*>(surf->buffer);
        const int start_row = std::max(dest_y, clip_y0);
        const int end_row = std::min(dest_y + glyph_h, clip_y1);
        const int start_col = std::max(dest_x, clip_x0);
        const int end_col = std::min(dest_x + glyph_w, clip_x1);

        update_x0 = start_col;
        update_y0 = start_row;
        update_w = std::max(0, end_col - start_col);
        update_h = std::max(0, end_row - start_row);

        for (int row = start_row; row < end_row; ++row) {
            const int src_y = row - dest_y;
            if (src_y < 0 || src_y >= glyph_h)
                continue;
            const std::uint8_t* src_row =
                glyph_bitmap.data() + static_cast<std::size_t>(src_y) * glyph_w;
            std::uint8_t* dst_row = dst_base + static_cast<std::size_t>(row) *
                                                   static_cast<std::size_t>(surf->widthByte);
            for (int col = start_col; col < end_col; ++col) {
                const int src_x = col - dest_x;
                if (src_x < 0 || src_x >= glyph_w)
                    continue;
                const std::uint8_t cov = src_row[src_x];
                std::uint8_t* dst = dst_row + static_cast<std::size_t>(col) * bpp;
                if (bpp == 1) {
                    dst[0] = cov;
                } else {
                    dst[0] = cov;
                    dst[1] = cov;
                    dst[2] = cov;
                    dst[3] = cov;
                }
            }
        }
    }

    result->stage = nullptr;
    result->SurfaceImage.address = static_cast<u8*>(surf->buffer);
    result->SurfaceImage.widthByte = static_cast<u32>(surf->widthByte);
    result->SurfaceImage.pixelSizeByte = static_cast<u8>(surf->pixelSizeByte);
    result->SurfaceImage.pixelFormat = 0;
    result->SurfaceImage.pad16 = 0;
    result->UpdateRect.x = static_cast<u32>(std::max(update_x0, 0));
    result->UpdateRect.y = static_cast<u32>(std::max(update_y0, 0));
    result->UpdateRect.w = static_cast<u32>(std::max(update_w, 0));
    result->UpdateRect.h = static_cast<u32>(std::max(update_h, 0));
    result->SurfaceImage.address =
        static_cast<u8*>(surf->buffer) +
        static_cast<std::size_t>(result->UpdateRect.y) * static_cast<std::size_t>(surf->widthByte) +
        static_cast<std::size_t>(result->UpdateRect.x) * static_cast<std::size_t>(bpp);
    const float left_f = x + metrics->Horizontal.bearingX;
    const float top_f = y + metrics->Horizontal.bearingY;
    const float right_f = left_f + metrics->width;
    const float bottom_f = top_f - metrics->height;

    const int left_i = FloorIntCompat(left_f);
    const int top_i = CeilIntCompat(top_f);
    const int right_i = CeilIntCompat(right_f);
    const int bottom_i = FloorIntCompat(bottom_f);

    const float adv_f = x + metrics->Horizontal.advance;
    const int adv_i = CeilIntCompat(adv_f);
    const float adv_snapped = static_cast<float>(adv_i) - x;

    result->ImageMetrics.bearingX = static_cast<float>(left_i) - x;
    result->ImageMetrics.bearingY = static_cast<float>(top_i) - y;
    result->ImageMetrics.advance = adv_snapped;
    int stride_i = adv_i;
    if (adv_f != static_cast<float>(adv_i)) {
        const int tmp_i = static_cast<int>((static_cast<float>(right_i) - right_f) + adv_f);
        stride_i = right_i + 1;
        if (adv_f <= right_f) {
            stride_i = tmp_i;
        }
        if (stride_i < tmp_i) {
            stride_i = tmp_i;
        }
    }
    result->ImageMetrics.stride = static_cast<float>(stride_i) - x;
    result->ImageMetrics.width = static_cast<u32>(std::max(0, right_i - left_i));
    result->ImageMetrics.height = static_cast<u32>(std::max(0, top_i - bottom_i));
    return ORBIS_OK;
}

s32 RenderCodepointToSurfaceWithScale(FontState& st, Libraries::Font::OrbisFontHandle handle,
                                      FT_Face face, float scale_x, float scale_y,
                                      Libraries::Font::OrbisFontRenderSurface* surf, u32 code,
                                      float x, float y, Libraries::Font::OrbisFontGlyphMetrics* m,
                                      Libraries::Font::OrbisFontRenderOutput* result) {
    ClearRenderOutputs(m, result);

    if (!surf || !m || !result) {
        return ORBIS_FONT_ERROR_INVALID_PARAMETER;
    }
    if (scale_x <= kScaleEpsilon || scale_y <= kScaleEpsilon) {
        return ORBIS_FONT_ERROR_NO_SUPPORT_GLYPH;
    }
    if (!surf->buffer || surf->width <= 0 || surf->height <= 0 || surf->widthByte <= 0 ||
        surf->pixelSizeByte <= 0) {
        return ORBIS_FONT_ERROR_NO_SUPPORT_SURFACE;
    }
    const int bpp = static_cast<int>(surf->pixelSizeByte);
    if (bpp != 1 && bpp != 4) {
        return ORBIS_FONT_ERROR_NO_SUPPORT_SURFACE;
    }

    FT_Face primary_face = face;
    if (!ResolveFace(st, handle, primary_face)) {
        return ORBIS_FONT_ERROR_NO_SUPPORT_GLYPH;
    }

    FT_Face resolved_face = primary_face;
    FT_UInt resolved_glyph_index =
        resolved_face ? FT_Get_Char_Index(resolved_face, static_cast<FT_ULong>(code)) : 0;
    float resolved_scale_factor = st.system_font_scale_factor;
    if (resolved_glyph_index == 0) {
        for (const auto& fb : st.system_fallback_faces) {
            if (!fb.ready || !fb.ft_face) {
                continue;
            }
            const FT_UInt gi = FT_Get_Char_Index(fb.ft_face, static_cast<FT_ULong>(code));
            if (gi == 0) {
                continue;
            }
            resolved_face = fb.ft_face;
            resolved_glyph_index = gi;
            resolved_scale_factor = fb.scale_factor;
            break;
        }
    }
    if (!resolved_face || resolved_glyph_index == 0) {
        return ORBIS_FONT_ERROR_NO_SUPPORT_GLYPH;
    }

    const int base_units = (st.ext_units_per_em > 0)
                               ? st.ext_units_per_em
                               : static_cast<int>(resolved_face->units_per_EM);
    if (base_units <= 0) {
        return ORBIS_FONT_ERROR_NO_SUPPORT_GLYPH;
    }

    const float pixel_w = scale_x * static_cast<float>(base_units) * resolved_scale_factor;
    const float pixel_h = scale_y * static_cast<float>(base_units) * resolved_scale_factor;

    const auto set_size = [&](float w, float h) -> bool {
        const auto char_w = static_cast<FT_F26Dot6>(static_cast<s32>(w * 64.0f));
        const auto char_h = static_cast<FT_F26Dot6>(static_cast<s32>(h * 64.0f));
        return FT_Set_Char_Size(resolved_face, char_w, char_h, 72, 72) == 0;
    };
    if (!set_size(pixel_w, pixel_h)) {
        return ORBIS_FONT_ERROR_NO_SUPPORT_GLYPH;
    }

    const float frac_x = x - std::floor(x);
    const float frac_y = y - std::floor(y);
    FT_Vector delta{};
    delta.x = static_cast<FT_Pos>(static_cast<s32>(frac_x * 64.0f));
    delta.y = static_cast<FT_Pos>(-static_cast<s32>(frac_y * 64.0f));
    FT_Set_Transform(resolved_face, nullptr, &delta);

    if (FT_Load_Glyph(resolved_face, resolved_glyph_index, kFtLoadFlagsRender) != 0) {
        FT_Set_Transform(resolved_face, nullptr, nullptr);
        return ORBIS_FONT_ERROR_NO_SUPPORT_GLYPH;
    }
    std::vector<unsigned char> glyph_bitmap;
    int x0 = 0, y0 = 0;
    int glyph_w = 0;
    int glyph_h = 0;

    const FT_GlyphSlot slot = resolved_face->glyph;
    glyph_w = static_cast<int>(slot->bitmap.width);
    glyph_h = static_cast<int>(slot->bitmap.rows);
    x0 = static_cast<int>(slot->bitmap_left);
    y0 = -static_cast<int>(slot->bitmap_top);
    FT_Set_Transform(resolved_face, nullptr, nullptr);

    const float bearing_x = static_cast<float>(slot->metrics.horiBearingX) / 64.0f;
    const float bearing_y = static_cast<float>(slot->metrics.horiBearingY) / 64.0f;
    const float advance = static_cast<float>(slot->metrics.horiAdvance) / 64.0f;
    const float width_px = static_cast<float>(slot->metrics.width) / 64.0f;
    const float height_px = static_cast<float>(slot->metrics.height) / 64.0f;

    m->width = width_px;
    m->height = height_px;
    m->Horizontal.bearingX = bearing_x;
    m->Horizontal.bearingY = bearing_y;
    m->Horizontal.advance = advance;
    m->Vertical.bearingX = 0.0f;
    m->Vertical.bearingY = 0.0f;
    m->Vertical.advance = 0.0f;

    glyph_bitmap.resize(static_cast<std::size_t>(glyph_w) * static_cast<std::size_t>(glyph_h));
    if (glyph_w > 0 && glyph_h > 0) {
        const int pitch = static_cast<int>(slot->bitmap.pitch);
        const unsigned char* src = reinterpret_cast<const unsigned char*>(slot->bitmap.buffer);
        if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) {
            for (int row = 0; row < glyph_h; ++row) {
                const unsigned char* src_row = src + static_cast<std::size_t>(row) * pitch;
                unsigned char* dst_row =
                    glyph_bitmap.data() + static_cast<std::size_t>(row) * glyph_w;
                for (int col = 0; col < glyph_w; ++col) {
                    const unsigned char byte = src_row[col >> 3];
                    const unsigned char bit = static_cast<unsigned char>(0x80u >> (col & 7));
                    dst_row[col] = (byte & bit) ? 0xFFu : 0x00u;
                }
            }
        } else {
            for (int row = 0; row < glyph_h; ++row) {
                const unsigned char* src_row = src + static_cast<std::size_t>(row) * pitch;
                unsigned char* dst_row =
                    glyph_bitmap.data() + static_cast<std::size_t>(row) * glyph_w;
                std::memcpy(dst_row, src_row, static_cast<std::size_t>(glyph_w));
            }
        }
    }

    const int dest_x = static_cast<int>(std::floor(x)) + x0;
    const int dest_y = static_cast<int>(std::floor(y)) + y0;

    const int surface_w = std::max(surf->width, 0);
    const int surface_h = std::max(surf->height, 0);
    const int clip_x0 = std::clamp(static_cast<int>(surf->sc_x0), 0, surface_w);
    const int clip_y0 = std::clamp(static_cast<int>(surf->sc_y0), 0, surface_h);
    const int clip_x1 = std::clamp(static_cast<int>(surf->sc_x1), 0, surface_w);
    const int clip_y1 = std::clamp(static_cast<int>(surf->sc_y1), 0, surface_h);

    int update_x0 = dest_x;
    int update_y0 = dest_y;
    int update_w = 0;
    int update_h = 0;

    if (glyph_w > 0 && glyph_h > 0 && clip_x1 > clip_x0 && clip_y1 > clip_y0) {
        auto* dst_base = static_cast<std::uint8_t*>(surf->buffer);
        const int start_row = std::max(dest_y, clip_y0);
        const int end_row = std::min(dest_y + glyph_h, clip_y1);
        const int start_col = std::max(dest_x, clip_x0);
        const int end_col = std::min(dest_x + glyph_w, clip_x1);

        update_x0 = start_col;
        update_y0 = start_row;
        update_w = std::max(0, end_col - start_col);
        update_h = std::max(0, end_row - start_row);

        for (int row = start_row; row < end_row; ++row) {
            const int src_y = row - dest_y;
            if (src_y < 0 || src_y >= glyph_h)
                continue;
            const std::uint8_t* src_row =
                glyph_bitmap.data() + static_cast<std::size_t>(src_y) * glyph_w;
            std::uint8_t* dst_row = dst_base + static_cast<std::size_t>(row) *
                                                   static_cast<std::size_t>(surf->widthByte);
            for (int col = start_col; col < end_col; ++col) {
                const int src_x = col - dest_x;
                if (src_x < 0 || src_x >= glyph_w)
                    continue;
                const std::uint8_t cov = src_row[src_x];
                std::uint8_t* dst = dst_row + static_cast<std::size_t>(col) * bpp;
                if (bpp == 1) {
                    dst[0] = cov;
                } else {
                    dst[0] = cov;
                    dst[1] = cov;
                    dst[2] = cov;
                    dst[3] = cov;
                }
            }
        }
    }

    result->stage = nullptr;
    result->SurfaceImage.address = static_cast<u8*>(surf->buffer);
    result->SurfaceImage.widthByte = static_cast<u32>(surf->widthByte);
    result->SurfaceImage.pixelSizeByte = static_cast<u8>(surf->pixelSizeByte);
    result->SurfaceImage.pixelFormat = 0;
    result->SurfaceImage.pad16 = 0;
    result->UpdateRect.x = static_cast<u32>(std::max(update_x0, 0));
    result->UpdateRect.y = static_cast<u32>(std::max(update_y0, 0));
    result->UpdateRect.w = static_cast<u32>(std::max(update_w, 0));
    result->UpdateRect.h = static_cast<u32>(std::max(update_h, 0));
    result->SurfaceImage.address =
        static_cast<u8*>(surf->buffer) +
        static_cast<std::size_t>(result->UpdateRect.y) * static_cast<std::size_t>(surf->widthByte) +
        static_cast<std::size_t>(result->UpdateRect.x) * static_cast<std::size_t>(bpp);
    const float left_f = x + m->Horizontal.bearingX;
    const float top_f = y + m->Horizontal.bearingY;
    const float right_f = left_f + m->width;
    const float bottom_f = top_f - m->height;

    const int left_i = FloorIntCompat(left_f);
    const int top_i = CeilIntCompat(top_f);
    const int right_i = CeilIntCompat(right_f);
    const int bottom_i = FloorIntCompat(bottom_f);

    const float adv_f = x + m->Horizontal.advance;
    const int adv_i = CeilIntCompat(adv_f);
    const float adv_snapped = static_cast<float>(adv_i) - x;

    result->ImageMetrics.bearingX = static_cast<float>(left_i) - x;
    result->ImageMetrics.bearingY = static_cast<float>(top_i) - y;
    result->ImageMetrics.advance = adv_snapped;
    int stride_i = adv_i;
    if (adv_f != static_cast<float>(adv_i)) {
        const int tmp_i = static_cast<int>((static_cast<float>(right_i) - right_f) + adv_f);
        stride_i = right_i + 1;
        if (adv_f <= right_f) {
            stride_i = tmp_i;
        }
        if (stride_i < tmp_i) {
            stride_i = tmp_i;
        }
    }
    result->ImageMetrics.stride = static_cast<float>(stride_i) - x;
    result->ImageMetrics.width = static_cast<u32>(std::max(0, right_i - left_i));
    result->ImageMetrics.height = static_cast<u32>(std::max(0, top_i - bottom_i));
    return ORBIS_OK;
}

const GlyphEntry* GetGlyphEntry(FontState& st, Libraries::Font::OrbisFontHandle handle, u32 code,
                                FT_Face& face_out, float& scale_out) {
    face_out = nullptr;
    scale_out = 0.0f;

    if (st.ext_face_ready) {
        face_out = st.ext_ft_face;
    }
    if (!face_out) {
        bool system_attached = false;
        const std::string sys_log = ReportSystemFaceRequest(st, handle, system_attached);
        if (!sys_log.empty()) {
            LOG_ERROR(Lib_Font, "SYSTEM_FONT_FAILED");
            LOG_DEBUG(Lib_Font, "{}", sys_log);
        }
        if (system_attached) {
            face_out = st.ext_ft_face;
        }
    }
    if (!face_out) {
        return nullptr;
    }

    float resolved_scale_factor = st.system_font_scale_factor;
    FT_Face resolved_face = face_out;
    FT_UInt resolved_glyph_index = FT_Get_Char_Index(resolved_face, static_cast<FT_ULong>(code));
    if (resolved_glyph_index == 0) {
        for (const auto& fb : st.system_fallback_faces) {
            if (!fb.ready || !fb.ft_face) {
                continue;
            }
            const FT_UInt gi = FT_Get_Char_Index(fb.ft_face, static_cast<FT_ULong>(code));
            if (gi == 0) {
                continue;
            }
            resolved_face = fb.ft_face;
            resolved_glyph_index = gi;
            resolved_scale_factor = fb.scale_factor;
            break;
        }
    }
    if (!resolved_face || resolved_glyph_index == 0) {
        return nullptr;
    }

    const float pixel_h_f = st.scale_h * resolved_scale_factor;
    const int pixel_h = std::max(1, static_cast<int>(std::lround(pixel_h_f)));
    const std::uint64_t key = MakeGlyphKey(code, pixel_h);

    GlyphEntry* ge = nullptr;
    if (auto it = st.ext_cache.find(key); it != st.ext_cache.end()) {
        ge = &it->second;
    }
    if (!ge) {
        const auto set_size = [&](float h) -> bool {
            const auto char_h = static_cast<FT_F26Dot6>(static_cast<s32>(h * 64.0f));
            return FT_Set_Char_Size(resolved_face, 0, char_h, 72, 72) == 0;
        };
        if (!set_size(pixel_h_f)) {
            return nullptr;
        }

        if (FT_Load_Glyph(resolved_face, resolved_glyph_index, kFtLoadFlagsRender) != 0) {
            return nullptr;
        }

        const FT_GlyphSlot slot = resolved_face->glyph;
        GlyphEntry entry{};
        entry.w = static_cast<int>(slot->bitmap.width);
        entry.h = static_cast<int>(slot->bitmap.rows);
        entry.x0 = static_cast<int>(slot->bitmap_left);
        entry.y0 = -static_cast<int>(slot->bitmap_top);
        entry.x1 = entry.x0 + entry.w;
        entry.y1 = entry.y0 + entry.h;
        entry.advance = static_cast<float>(slot->metrics.horiAdvance) / 64.0f;
        entry.bearingX = static_cast<float>(slot->bitmap_left);
        ge = &st.ext_cache.emplace(key, std::move(entry)).first->second;
    }

    face_out = resolved_face;
    scale_out = ComputeScaleExtForState(st, resolved_face, pixel_h_f);
    return ge;
}

constexpr SystemFontDefinition kSystemFontDefinitions[] = {
    {0x18070043, "FONTSET_SST_STD_EUROPEAN_LIGHT", "SST-Light.otf"},
    {0x18070044, "FONTSET_SST_STD_EUROPEAN", "SST-Roman.otf"},
    {0x18070045, "FONTSET_SST_STD_EUROPEAN_MEDIUM", "SST-Medium.otf"},
    {0x18070047, "FONTSET_SST_STD_EUROPEAN_BOLD", "SST-Bold.otf"},
    {0x18070053, "FONTSET_SST_STD_VIETNAMESE_LIGHT", "SSTVietnamese-Light.otf"},
    {0x18070054, "FONTSET_SST_STD_VIETNAMESE", "SSTVietnamese-Roman.otf"},
    {0x18070055, "FONTSET_SST_STD_VIETNAMESE_MEDIUM", "SSTVietnamese-Medium.otf"},
    {0x18070057, "FONTSET_SST_STD_VIETNAMESE_BOLD", "SSTVietnamese-Bold.otf"},
    {0x180700C3, "FONTSET_SST_STD_EUROPEAN_AR_LIGHT", "SST-Light.otf"},
    {0x180700C4, "FONTSET_SST_STD_EUROPEAN_AR", "SST-Roman.otf"},
    {0x180700C5, "FONTSET_SST_STD_EUROPEAN_AR_MEDIUM", "SST-Medium.otf"},
    {0x180700C7, "FONTSET_SST_STD_EUROPEAN_AR_BOLD", "SST-Bold.otf"},
    {0x18070444, "FONTSET_SST_STD_EUROPEAN_JP", "SSTJpPro-Regular.otf"},
    {0x18070447, "FONTSET_SST_STD_EUROPEAN_JP_BOLD", "SSTJpPro-Bold.otf"},
    {0x18070454, "FONTSET_SST_STD_EUROPEAN_JP", "SSTJpPro-Regular.otf"},
    {0x18070457, "FONTSET_SST_STD_EUROPEAN_JP_BOLD", "SSTJpPro-Bold.otf"},
    {0x180704C4, "FONTSET_SST_STD_EUROPEAN_JP_AR", "SSTJpPro-Regular.otf"},
    {0x180704C7, "FONTSET_SST_STD_EUROPEAN_JP_AR_BOLD", "SSTJpPro-Bold.otf"},
    {0x18071053, "FONTSET_SST_STD_THAI_LIGHT", "SSTVietnamese-Light.otf"},
    {0x18071054, "FONTSET_SST_STD_THAI", "SSTVietnamese-Roman.otf"},
    {0x18071055, "FONTSET_SST_STD_THAI_MEDIUM", "SSTVietnamese-Medium.otf"},
    {0x18071057, "FONTSET_SST_STD_THAI_BOLD", "SSTVietnamese-Bold.otf"},
    {0x18071454, "FONTSET_SST_STD_EUROPEAN_JP_TH", "SSTJpPro-Regular.otf"},
    {0x18071457, "FONTSET_SST_STD_EUROPEAN_JP_TH_BOLD", "SSTJpPro-Bold.otf"},
    {0x18072444, "FONTSET_SST_STD_EUROPEAN_JPUH", "SSTJpPro-Regular.otf"},
    {0x18072447, "FONTSET_SST_STD_EUROPEAN_JPUH_BOLD", "SSTJpPro-Bold.otf"},
    {0x180724C4, "FONTSET_SST_STD_EUROPEAN_JPUH_AR", "SSTJpPro-Regular.otf"},
    {0x180724C7, "FONTSET_SST_STD_EUROPEAN_JPUH_AR_BOLD", "SSTJpPro-Bold.otf"},
    {0x18073454, "FONTSET_SST_STD_EUROPEAN_JPUH_TH", "SSTJpPro-Regular.otf"},
    {0x18073457, "FONTSET_SST_STD_EUROPEAN_JPUH_TH_BOLD", "SSTJpPro-Bold.otf"},
    {0x180734D4, "FONTSET_SST_STD_EUROPEAN_JPUH_TH_AR", "SSTJpPro-Regular.otf"},
    {0x180734D7, "FONTSET_SST_STD_EUROPEAN_JPUH_TH_AR_BOLD", "SSTJpPro-Bold.otf"},
    {0x18078044, "FONTSET_SST_STD_EUROPEAN_GB", "DFHEI5-SONY.ttf"},
    {0x180780C4, "FONTSET_SST_STD_EUROPEAN_GB_AR", "DFHEI5-SONY.ttf"},
    {0x18079054, "FONTSET_SST_STD_EUROPEAN_GB_TH", "DFHEI5-SONY.ttf"},
    {0x1807A044, "FONTSET_SST_STD_EUROPEAN_GBUH", "DFHEI5-SONY.ttf"},
    {0x1807A0C4, "FONTSET_SST_STD_EUROPEAN_GBUH_AR", "DFHEI5-SONY.ttf"},
    {0x1807A444, "FONTSET_SST_STD_EUROPEAN_JPCJK", "SSTJpPro-Regular.otf"},
    {0x1807A4C4, "FONTSET_SST_STD_EUROPEAN_JPCJK_AR", "SSTJpPro-Regular.otf"},
    {0x1807AC44, "FONTSET_SST_STD_EUROPEAN_GBCJK", "SCEPS4Yoongd-Medium.otf"},
    {0x1807ACC4, "FONTSET_SST_STD_EUROPEAN_GBCJK_AR", "DFHEI5-SONY.ttf"},
    {0x1807B054, "FONTSET_SST_STD_EUROPEAN_GBUH_TH", "DFHEI5-SONY.ttf"},
    {0x1807B0D4, "FONTSET_SST_STD_EUROPEAN_GBUH_TH_AR", "DFHEI5-SONY.ttf"},
    {0x1807B454, "FONTSET_SST_STD_EUROPEAN_JPCJK_TH", "SSTJpPro-Regular.otf"},
    {0x1807B4D4, "FONTSET_SST_STD_EUROPEAN_JPCJK_TH_AR", "SSTJpPro-Regular.otf"},
    {0x1807BC54, "FONTSET_SST_STD_EUROPEAN_GBCJK_TH", "DFHEI5-SONY.ttf"},
    {0x1807BCD4, "FONTSET_SST_STD_EUROPEAN_GBCJK_TH_AR", "DFHEI5-SONY.ttf"},
    {0x18080444, "FONTSET_SST_STD_JAPANESE_JP", "SSTJpPro-Regular.otf"},
    {0x18080447, "FONTSET_SST_STD_JAPANESE_JP_BOLD", "SSTJpPro-Bold.otf"},
    {0x18080454, "FONTSET_SST_STD_VIETNAMESE_JP", "SSTJpPro-Regular.otf"},
    {0x18080457, "FONTSET_SST_STD_VIETNAMESE_JP_BOLD", "SSTJpPro-Bold.otf"},
    {0x180804C4, "FONTSET_SST_STD_JAPANESE_JP_AR", "SSTJpPro-Regular.otf"},
    {0x180804C7, "FONTSET_SST_STD_JAPANESE_JP_AR_BOLD", "SSTJpPro-Bold.otf"},
    {0x18081454, "FONTSET_SST_STD_ASIAN_JP_TH", "SSTJpPro-Regular.otf"},
    {0x18081457, "FONTSET_SST_STD_ASIAN_JP_TH_BOLD", "SSTJpPro-Bold.otf"},
    {0x18082444, "FONTSET_SST_STD_JAPANESE_JPUH", "SSTJpPro-Regular.otf"},
    {0x18082447, "FONTSET_SST_STD_JAPANESE_JPUH_BOLD", "SSTJpPro-Bold.otf"},
    {0x180824C4, "FONTSET_SST_STD_JAPANESE_JPUH_AR", "SSTJpPro-Regular.otf"},
    {0x180824C7, "FONTSET_SST_STD_JAPANESE_JPUH_AR_BOLD", "SSTJpPro-Bold.otf"},
    {0x18083454, "FONTSET_SST_STD_ASIAN_JPUH_TH", "SSTJpPro-Regular.otf"},
    {0x18083457, "FONTSET_SST_STD_ASIAN_JPUH_TH_BOLD", "SSTJpPro-Bold.otf"},
    {0x180834D4, "FONTSET_SST_STD_ASIAN_JPUH_TH_AR", "SSTJpPro-Regular.otf"},
    {0x180834D7, "FONTSET_SST_STD_ASIAN_JPUH_TH_AR_BOLD", "SSTJpPro-Bold.otf"},
    {0x1808A444, "FONTSET_SST_STD_JAPANESE_JPCJK", "SSTJpPro-Regular.otf"},
    {0x1808A4C4, "FONTSET_SST_STD_JAPANESE_JPCJK_AR", "SSTJpPro-Regular.otf"},
    {0x1808B454, "FONTSET_SST_STD_ASIAN_JPCJK_TH", "SSTJpPro-Regular.otf"},
    {0x1808B4D4, "FONTSET_SST_STD_ASIAN_JPCJK_TH_AR", "SSTJpPro-Regular.otf"},
    {0x180C8044, "FONTSET_SST_STD_SCHINESE_GB", "DFHEI5-SONY.ttf"},
    {0x180C80C4, "FONTSET_SST_STD_SCHINESE_GB_AR", "DFHEI5-SONY.ttf"},
    {0x180C9054, "FONTSET_SST_STD_ASIAN_GB_TH", "DFHEI5-SONY.ttf"},
    {0x180CA044, "FONTSET_SST_STD_SCHINESE_GBUH", "DFHEI5-SONY.ttf"},
    {0x180CA0C4, "FONTSET_SST_STD_SCHINESE_GBUH_AR", "DFHEI5-SONY.ttf"},
    {0x180CAC44, "FONTSET_SST_STD_SCHINESE_GBCJK", "DFHEI5-SONY.ttf"},
    {0x180CACC4, "FONTSET_SST_STD_SCHINESE_GBCJK_AR", "DFHEI5-SONY.ttf"},
    {0x180CB054, "FONTSET_SST_STD_ASIAN_GBUH_TH", "DFHEI5-SONY.ttf"},
    {0x180CB0D4, "FONTSET_SST_STD_ASIAN_GBUH_TH_AR", "DFHEI5-SONY.ttf"},
    {0x180CBC54, "FONTSET_SST_STD_ASIAN_GBCJK_TH", "DFHEI5-SONY.ttf"},
    {0x180CBCD4, "FONTSET_SST_STD_ASIAN_GBCJK_TH_AR", "DFHEI5-SONY.ttf"},
    {0x18170043, "FONTSET_SST_STD_EUROPEAN_LIGHT_ITALIC", "SST-LightItalic.otf"},
    {0x18170044, "FONTSET_SST_STD_EUROPEAN_ITALIC", "SST-Italic.otf"},
    {0x18170045, "FONTSET_SST_STD_EUROPEAN_MEDIUM_ITALIC", "SST-MediumItalic.otf"},
    {0x18170047, "FONTSET_SST_STD_EUROPEAN_BOLD_ITALIC", "SST-BoldItalic.otf"},
    {0x18170444, "FONTSET_SST_STD_EUROPEAN_JP_ITALIC", "SSTJpPro-Regular.otf"},
    {0x18170447, "FONTSET_SST_STD_EUROPEAN_JP_BOLD_ITALIC", "SSTJpPro-Bold.otf"},
    {0x18370044, "FONTSET_SST_TYPEWRITER_EUROPEAN", "SSTTypewriter-Roman.otf"},
    {0x18370047, "FONTSET_SST_TYPEWRITER_EUROPEAN_BOLD", "SSTTypewriter-Bd.otf"},
    {0x18370444, "FONTSET_SST_TYPEWRITER_EUROPEAN_JP", "SSTJpPro-Regular.otf"},
    {0x18370447, "FONTSET_SST_TYPEWRITER_EUROPEAN_JP_BOLD", "SSTJpPro-Bold.otf"},
};

std::mutex g_fontset_cache_mutex;
std::unordered_map<u32, FontSetCache> g_fontset_cache;

const SystemFontDefinition* FindSystemFontDefinition(u32 font_set_type) {
    for (const auto& def : kSystemFontDefinitions) {
        if (def.font_set_type == font_set_type) {
            return &def;
        }
    }
    return nullptr;
}

float ComputeSysfontScaleFactor(FT_Face face, int units_per_em) {
    (void)units_per_em;
    if (!face) {
        return 1.0f;
    }
    const auto* os2 = static_cast<const TT_OS2*>(FT_Get_Sfnt_Table(face, ft_sfnt_os2));
    if (os2 && os2->sTypoAscender == 770 && os2->sTypoDescender == -230) {
        return 1024.0f / 952.0f;
    }
    return 1.0f;
}

s32 ComputeSysfontShiftValue(FT_Face face) {
    if (!face) {
        return 0;
    }
    const auto* os2 = static_cast<const TT_OS2*>(FT_Get_Sfnt_Table(face, ft_sfnt_os2));
    if (!os2) {
        return 0;
    }
    const bool is_jp_pro_metrics =
        (os2->sTypoAscender == 880) && (os2->sTypoDescender == -120) && (os2->sTypoLineGap == 1);
    if (!is_jp_pro_metrics) {
        return 0;
    }
    const auto* vhea = static_cast<const TT_VertHeader*>(FT_Get_Sfnt_Table(face, ft_sfnt_vhea));
    if (!vhea) {
        return 0;
    }
    const int units = static_cast<int>(face->units_per_EM);
    const int gap = static_cast<int>(os2->sTypoLineGap);
    const int shift = 1024 - units - gap;
    if (shift > 0 && shift < 128) {
        return static_cast<s32>(shift);
    }
    return 0;
}

std::shared_ptr<std::vector<unsigned char>> LoadBuiltinFontBytesShared(
    const std::filesystem::path& path, u32* out_subfont_index) {
    const auto* blob = FindBuiltinFontBlob(path);
    if (!blob) {
        return {};
    }
    if (out_subfont_index) {
        *out_subfont_index = blob->face_index;
    }

    static std::mutex cache_mutex;
    static std::unordered_map<std::string, std::shared_ptr<std::vector<unsigned char>>> cache;

    const std::string cache_key(blob->virtual_path);
    {
        std::scoped_lock lock(cache_mutex);
        if (const auto it = cache.find(cache_key); it != cache.end()) {
            return it->second;
        }
    }

    const unsigned int output_len = StbDecompressLength(blob->compressed_data);
    if (output_len == 0u) {
        return {};
    }

    auto bytes = std::make_shared<std::vector<unsigned char>>(output_len);
    if (StbDecompress(bytes->data(), blob->compressed_data) != output_len) {
        return {};
    }

    {
        std::scoped_lock lock(cache_mutex);
        return cache.emplace(cache_key, std::move(bytes)).first->second;
    }
}

bool IsBuiltinFontPath(const std::filesystem::path& path) {
    const std::string normalized = path.generic_string();
    return normalized.rfind(kBuiltinFontPrefix, 0) == 0;
}

BuiltinSystemFontSelection BuildBuiltinSystemFontSelection(u32 font_set_type) {
    BuiltinSystemFontSelection selection{};
    const auto* def = FindSystemFontDefinition(font_set_type);
    if (!def || !def->default_file || !*def->default_file) {
        return selection;
    }

    const std::string_view default_file(def->default_file);
    const u32 tag = (font_set_type >> 8) & 0xFFu;
    const u32 style_suffix = font_set_type & 0xFFu;
    const bool needs_arabic = (style_suffix == 0xC3u) || (style_suffix == 0xC4u) ||
                              (style_suffix == 0xC5u) || (style_suffix == 0xC7u) ||
                              (style_suffix == 0xD3u) || (style_suffix == 0xD4u) ||
                              (style_suffix == 0xD5u) || (style_suffix == 0xD7u);
    const bool needs_jppro = (tag == 0x04u) || (tag == 0x24u) || (tag == 0x34u) || (tag == 0x84u) ||
                             (tag == 0xA4u) || (tag == 0xACu) || (tag == 0xB4u) || (tag == 0xBCu);
    const bool needs_cngb = (tag == 0x80u) || (tag == 0x84u) || (tag == 0x90u) || (tag == 0xA0u) ||
                            (tag == 0xA4u) || (tag == 0xACu) || (tag == 0xB0u) || (tag == 0xB4u) ||
                            (tag == 0xBCu);
    const bool needs_hangul = (tag == 0x24u) || (tag == 0x34u) || (tag == 0xA0u) ||
                              (tag == 0xA4u) || (tag == 0xACu) || (tag == 0xB0u) ||
                              (tag == 0xB4u) || (tag == 0xBCu);
    const bool needs_thai = IsThaiSeaWeightTag(font_set_type);

    const auto push_unique = [&](std::vector<std::filesystem::path>& paths,
                                 std::string_view path_string) {
        if (path_string.empty()) {
            return;
        }
        const std::string filename_lower =
            LowerAsciiString(std::filesystem::path(std::string(path_string)).filename().string());
        for (const auto& existing : paths) {
            if (LowerAsciiString(existing.filename().string()) == filename_lower) {
                return;
            }
        }
        paths.emplace_back(std::string(path_string));
    };

    enum class PrimaryKind { Latin, Thai, Jp, Kr, Sc };
    PrimaryKind primary_kind = PrimaryKind::Latin;
    if (EqualsAsciiInsensitive(default_file, "DFHEI5-SONY.ttf")) {
        primary_kind = PrimaryKind::Sc;
    } else if (StartsWithAsciiInsensitive(default_file, "SCEPS4Yoongd-")) {
        primary_kind = PrimaryKind::Kr;
    } else if (StartsWithAsciiInsensitive(default_file, "SSTJpPro-") ||
               StartsWithAsciiInsensitive(default_file, "SCE-RDC-")) {
        primary_kind = PrimaryKind::Jp;
    } else if (StartsWithAsciiInsensitive(default_file, "SSTThai-") ||
               (needs_thai && !needs_jppro && !needs_cngb && !needs_hangul)) {
        primary_kind = PrimaryKind::Thai;
    }

    switch (primary_kind) {
    case PrimaryKind::Thai:
        selection.primary_path = std::filesystem::path(std::string(kBuiltinFontThai));
        break;
    case PrimaryKind::Jp:
        selection.primary_path = std::filesystem::path(std::string(kBuiltinFontCjkJp));
        break;
    case PrimaryKind::Kr:
        selection.primary_path = std::filesystem::path(std::string(kBuiltinFontCjkKr));
        break;
    case PrimaryKind::Sc:
        selection.primary_path = std::filesystem::path(std::string(kBuiltinFontCjkSc));
        break;
    case PrimaryKind::Latin:
    default:
        selection.primary_path = std::filesystem::path(std::string(kBuiltinFontLatin));
        break;
    }

    selection.preferred_latin_name_lower =
        LowerAsciiString(std::filesystem::path(std::string(kBuiltinFontLatin)).filename().string());

    if (primary_kind != PrimaryKind::Latin) {
        push_unique(selection.fallback_paths, kBuiltinFontLatin);
    }
    if (needs_arabic) {
        push_unique(selection.fallback_paths, kBuiltinFontArabic);
    }
    if (needs_thai && primary_kind != PrimaryKind::Thai) {
        push_unique(selection.fallback_paths, kBuiltinFontThai);
    }
    if (needs_jppro && primary_kind != PrimaryKind::Jp) {
        push_unique(selection.fallback_paths, kBuiltinFontCjkJp);
    }
    if (needs_hangul && primary_kind != PrimaryKind::Kr) {
        push_unique(selection.fallback_paths, kBuiltinFontCjkKr);
    }
    if (needs_cngb && primary_kind != PrimaryKind::Sc) {
        push_unique(selection.fallback_paths, kBuiltinFontCjkSc);
    }
    push_unique(selection.fallback_paths, kBuiltinFontSymbols);
    return selection;
}

static bool DirectoryContainsAnyFontFiles(const std::filesystem::path& dir) {
    std::error_code ec;
    if (!std::filesystem::is_directory(dir, ec)) {
        return false;
    }
    for (const auto& entry : std::filesystem::directory_iterator(dir, ec)) {
        if (ec) {
            return false;
        }
        if (!entry.is_regular_file(ec) || ec) {
            continue;
        }
        const auto ext = entry.path().extension().string();
        std::string lower;
        lower.reserve(ext.size());
        for (const char c : ext) {
            lower.push_back(static_cast<char>(std::tolower(static_cast<unsigned char>(c))));
        }
        if (lower == ".otf" || lower == ".ttf" || lower == ".ttc" || lower == ".otc") {
            return true;
        }
    }
    return false;
}

static std::filesystem::path GetSysFontBaseDirImpl(bool log_errors) {
    std::filesystem::path base = EmulatorSettings.GetFontsDir();
    std::error_code ec;
    if (base.empty()) {
        if (log_errors) {
            LOG_ERROR(Lib_Font, "SystemFonts: FontsPath not set");
        }
        return {};
    }
    if (std::filesystem::is_directory(base, ec)) {
        const auto font_dir = base / "font";
        const auto font2_dir = base / "font2";
        if (DirectoryContainsAnyFontFiles(base) || DirectoryContainsAnyFontFiles(font_dir) ||
            DirectoryContainsAnyFontFiles(font2_dir)) {
            return base;
        }
        if (log_errors) {
            LOG_ERROR(
                Lib_Font,
                "SystemFonts: FontsPath '{}' contains no font files; expected files directly in "
                "this directory or under 'font'/'font2'",
                base.string());
        }
        return {};
    }
    if (std::filesystem::is_regular_file(base, ec)) {
        return base.parent_path();
    }
    if (log_errors) {
        LOG_ERROR(Lib_Font, "SystemFonts: FontsPath '{}' is not a valid directory or file",
                  base.string());
    }
    return {};
}

std::filesystem::path GetSysFontBaseDir() {
    return GetSysFontBaseDirImpl(true);
}

static std::filesystem::path ResolveSystemFontPathCandidate(const std::filesystem::path& base_dir,
                                                            const std::filesystem::path& filename) {
    if (base_dir.empty() || filename.empty()) {
        return {};
    }
    std::error_code ec;
    const auto is_file = [&](const std::filesystem::path& p) -> bool {
        return std::filesystem::is_regular_file(p, ec) && !ec;
    };

    const auto direct = base_dir / filename;
    if (is_file(direct)) {
        return direct;
    }

    const auto base_name = base_dir.filename().string();
    if (base_name != "font" && base_name != "font2") {
        const auto in_font = base_dir / "font" / filename;
        if (is_file(in_font)) {
            return in_font;
        }
        const auto in_font2 = base_dir / "font2" / filename;
        if (is_file(in_font2)) {
            return in_font2;
        }
    }

    if (base_name == "font" || base_name == "font2") {
        const auto container = base_dir.parent_path();
        const auto sibling = container / ((base_name == "font") ? "font2" : "font") / filename;
        if (is_file(sibling)) {
            return sibling;
        }
    }

    return direct;
}

std::filesystem::path ResolveSystemFontPath(u32 font_set_type) {
    if (const auto* def = FindSystemFontDefinition(font_set_type); def) {
        const auto base_dir = GetSysFontBaseDir();
        if (base_dir.empty()) {
            return {};
        }
        if (def->default_file && *def->default_file) {
            return ResolveSystemFontPathCandidate(base_dir, def->default_file);
        }
    }
    LOG_ERROR(Lib_Font, "SystemFonts: unknown font set type=0x{:08X}", font_set_type);
    return {};
}

const FontSetCache* EnsureFontSetCache(u32 font_set_type) {
    if (font_set_type == 0) {
        return nullptr;
    }
    std::scoped_lock lock(g_fontset_cache_mutex);
    auto& cache = g_fontset_cache[font_set_type];
    if (!cache.loaded) {
        cache.loaded = true;
        auto path = ResolveSystemFontPath(font_set_type);
        if (path.empty()) {
            path = BuildBuiltinSystemFontSelection(font_set_type).primary_path;
        }
        if (!path.empty() && LoadFontFile(path, cache.bytes)) {
            cache.available = HasSfntTables(cache.bytes);
            cache.path = cache.available ? path : std::filesystem::path{};
        } else {
            cache.available = false;
            LOG_ERROR(Lib_Font, "SystemFonts: failed to load font for set type=0x{:08X} path='{}'",
                      font_set_type, path.string());
        }
    }
    return cache.available ? &cache : nullptr;
}

bool HasSfntTables(const std::vector<unsigned char>& bytes) {
    if (bytes.size() < 12) {
        return false;
    }
    const u8* ptr = bytes.data();
    const u32 num_tables = (ptr[4] << 8) | ptr[5];
    constexpr u32 kDirEntrySize = 16;
    if (bytes.size() < 12 + static_cast<size_t>(num_tables) * kDirEntrySize) {
        return false;
    }
    return true;
}

bool LoadFontFileWithSubfont(const std::filesystem::path& path,
                             std::vector<unsigned char>& out_bytes, u32& out_subfont_index) {
    if (path.empty()) {
        return false;
    }

    if (const auto builtin_bytes = LoadBuiltinFontBytesShared(path, &out_subfont_index)) {
        out_bytes.assign(builtin_bytes->begin(), builtin_bytes->end());
        return !out_bytes.empty();
    }

    out_subfont_index = 0;
    auto try_load = [&](const std::filesystem::path& p) -> bool {
        out_bytes.clear();
        if (!LoadGuestFileBytes(p, out_bytes) || out_bytes.empty()) {
            out_bytes.clear();
            return false;
        }
        return true;
    };

    if (try_load(path)) {
        return true;
    }

    std::error_code ec;
    const auto parent = path.parent_path();
    const auto parent_name = parent.filename().string();
    const auto file_name = path.filename();
    if (!file_name.empty() && parent_name != "font" && parent_name != "font2") {
        const auto cand_font = parent / "font" / file_name;
        if (std::filesystem::is_regular_file(cand_font, ec) && !ec) {
            if (try_load(cand_font)) {
                return true;
            }
        }
        const auto cand_font2 = parent / "font2" / file_name;
        if (std::filesystem::is_regular_file(cand_font2, ec) && !ec) {
            if (try_load(cand_font2)) {
                return true;
            }
        }
    }

    if (!file_name.empty() && (parent_name == "font" || parent_name == "font2")) {
        const auto container = parent.parent_path();
        const auto sibling = container / ((parent_name == "font") ? "font2" : "font") / file_name;
        if (std::filesystem::is_regular_file(sibling, ec) && !ec) {
            return try_load(sibling);
        }
    }

    return false;
}

bool LoadFontFile(const std::filesystem::path& path, std::vector<unsigned char>& out_bytes) {
    u32 ignored_subfont_index = 0;
    return LoadFontFileWithSubfont(path, out_bytes, ignored_subfont_index);
}

bool AddSystemFallbackFace(FontState& st, const std::filesystem::path& path, u32 subfont_index) {
    if (path.empty()) {
        return false;
    }

    const std::string filename_lower = LowerAsciiString(path.filename().string());
    if (HasPathFilenameLower(st, filename_lower)) {
        return false;
    }

    std::vector<unsigned char> fallback_bytes;
    u32 fallback_face_index = subfont_index;
    if (!LoadFontFileWithSubfont(path, fallback_bytes, fallback_face_index)) {
        return false;
    }

    FontState::SystemFallbackFace fallback{};
    fallback.font_id = 0xffffffffu;
    fallback.path = path;
    fallback.bytes = std::make_shared<std::vector<unsigned char>>(std::move(fallback_bytes));
    fallback.ft_face = CreateFreeTypeFaceFromBytes(fallback.bytes->data(), fallback.bytes->size(),
                                                   fallback_face_index);
    fallback.ready = (fallback.ft_face != nullptr);
    if (!fallback.ready) {
        DestroyFreeTypeFace(fallback.ft_face);
        return false;
    }

    fallback.scale_factor = ComputeSysfontScaleFactor(
        fallback.ft_face, fallback.ft_face ? static_cast<int>(fallback.ft_face->units_per_EM) : 0);
    fallback.shift_value = ComputeSysfontShiftValue(fallback.ft_face);
    st.system_fallback_faces.push_back(std::move(fallback));
    return true;
}

void AddBuiltinFallbackFaces(FontState& st, u32 font_set_type, u32 subfont_index,
                             std::string* preferred_latin_name_lower) {
    const auto selection = BuildBuiltinSystemFontSelection(font_set_type);
    if (preferred_latin_name_lower) {
        *preferred_latin_name_lower = selection.preferred_latin_name_lower;
    }
    for (const auto& path : selection.fallback_paths) {
        (void)AddSystemFallbackFace(st, path, subfont_index);
    }
}

void NotifyBuiltinFontFallbackOnce() {
    static std::once_flag once;
    std::call_once(once, [] {
        shadNotifications::QueueNotification("WARNING! PS4 system fonts not found.\n"
                                             "Using bundled fallback fonts instead.\n"
                                             "Text rendering may be inaccurate.",
                                             30.0f, shadNotifications::position::BottomRight,
                                             shadNotifications::stockIcons::shadPS4);
    });
}

bool AttachSystemFont(FontState& st, Libraries::Font::OrbisFontHandle handle) {
    if (st.ext_face_ready) {
        return true;
    }
    st.system_fallback_faces.clear();
    st.system_font_id = 0;
    st.system_font_scale_factor = 1.0f;
    st.system_font_shift_value = 0;

    const auto* native = reinterpret_cast<const Libraries::Font::FontHandleOpaqueNative*>(handle);
    const u32 subfont_index = native ? native->open_info.sub_font_index : 0u;
    auto* lib = static_cast<FontLibOpaque*>(st.library);
    if (!lib || lib->magic != 0x0F01 || st.font_set_type == 0) {
        return false;
    }

    std::filesystem::path primary_path = ResolveSystemFontPath(st.font_set_type);
    bool using_builtin_primary = false;
    std::vector<unsigned char> primary_bytes;
    u32 primary_face_index = subfont_index;
    if (primary_path.empty() ||
        !LoadFontFileWithSubfont(primary_path, primary_bytes, primary_face_index)) {
        primary_path = BuildBuiltinSystemFontSelection(st.font_set_type).primary_path;
        using_builtin_primary = !primary_path.empty();
    }
    if (primary_path.empty() ||
        !LoadFontFileWithSubfont(primary_path, primary_bytes, primary_face_index)) {
        return false;
    }

    DestroyFreeTypeFace(st.ext_ft_face);
    st.ext_face_data = std::move(primary_bytes);
    st.ext_ft_face = CreateFreeTypeFaceFromBytes(st.ext_face_data.data(), st.ext_face_data.size(),
                                                 primary_face_index);
    if (!st.ext_ft_face) {
        st.ext_face_data.clear();
        return false;
    }

    st.ext_cache.clear();
    st.scratch.clear();
    st.logged_ext_use = false;
    st.ext_scale_for_height = 0.0f;
    st.layout_cached = false;
    const FaceMetrics m = LoadFaceMetrics(st.ext_ft_face);
    PopulateStateMetrics(st, m);
    st.ext_face_ready = true;
    st.system_font_path = primary_path;
    st.system_requested = true;
    st.system_font_scale_factor = ComputeSysfontScaleFactor(st.ext_ft_face, st.ext_units_per_em);
    st.system_font_shift_value = ComputeSysfontShiftValue(st.ext_ft_face);

    if (using_builtin_primary || IsBuiltinFontPath(primary_path)) {
        AddBuiltinFallbackFaces(st, st.font_set_type, subfont_index, nullptr);
    }
    if (using_builtin_primary) {
        LOG_WARNING(Lib_Font, "SystemFonts: using bundled Noto fallback for set type=0x{:08X}",
                    st.font_set_type);
        NotifyBuiltinFontFallbackOnce();
    }

    LOG_INFO(Lib_Font, "system font attached");
    LOG_DEBUG(Lib_Font,
              "system font attach params:\n"
              " handle={}\n"
              " font_set_type=0x{:08X}\n"
              " path={}\n",
              static_cast<const void*>(handle), st.font_set_type, st.system_font_path.string());
    return true;
}

std::string ReportSystemFaceRequest(FontState& st, Libraries::Font::OrbisFontHandle handle,
                                    bool& attached_out) {
    attached_out = AttachSystemFont(st, handle);
    if (attached_out) {
        st.system_requested = true;
        return {};
    }
    if (!st.system_requested) {
        st.system_requested = true;
        const auto configured = EmulatorSettings.GetFontsDir();
        return fmt::format("SystemFace: handle={} requested internal font but fontsPath ('{}') "
                           "could not be loaded",
                           static_cast<const void*>(handle), configured.string());
    }
    return {};
}

void LogCachedStyleOnce(Libraries::Font::OrbisFontHandle handle,
                        const Libraries::Font::FontHandleOpaqueNative& font) {
    static std::mutex s_mutex;
    static std::unordered_set<Libraries::Font::OrbisFontHandle> s_logged;
    std::scoped_lock lock(s_mutex);
    if (s_logged.find(handle) != s_logged.end()) {
        return;
    }
    s_logged.insert(handle);

    LOG_DEBUG(Lib_Font,
              "BindRenderer: cached_style snapshot: hDpi={} vDpi={} scaleUnit={} baseScale={} "
              "scalePixelW={} scalePixelH={} effectWeightX={} effectWeightY={} slantRatio={}",
              font.cached_style.hDpi, font.cached_style.vDpi, font.cached_style.scaleUnit,
              font.cached_style.baseScale, font.cached_style.scalePixelW,
              font.cached_style.scalePixelH, font.cached_style.effectWeightX,
              font.cached_style.effectWeightY, font.cached_style.slantRatio);
}

void LogRenderResultSample(Libraries::Font::OrbisFontHandle handle, u32 code,
                           const Libraries::Font::OrbisFontGlyphMetrics& metrics,
                           const Libraries::Font::OrbisFontRenderOutput& result) {
    static std::mutex s_mutex;
    static std::unordered_map<Libraries::Font::OrbisFontHandle, int> s_counts;
    std::scoped_lock lock(s_mutex);
    int& count = s_counts[handle];
    if (count >= 5) {
        return;
    }
    ++count;
    LOG_DEBUG(Lib_Font,
              "RenderSample: handle={} code=U+{:04X} update=[{},{} {}x{}] img=[bx={} by={} adv={} "
              "stride={} w={} h={}] metrics=[w={} h={} hbx={} hby={} hadv={}]",
              static_cast<const void*>(handle), code, result.UpdateRect.x, result.UpdateRect.y,
              result.UpdateRect.w, result.UpdateRect.h, result.ImageMetrics.bearingX,
              result.ImageMetrics.bearingY, result.ImageMetrics.advance, result.ImageMetrics.stride,
              result.ImageMetrics.width, result.ImageMetrics.height, metrics.width, metrics.height,
              metrics.Horizontal.bearingX, metrics.Horizontal.bearingY, metrics.Horizontal.advance);
}

u8 CachedStyleCacheFlags(const Libraries::Font::OrbisFontStyleFrame& cached_style) {
    return static_cast<u8>(cached_style.cache_flags_and_direction & 0xFFu);
}

void CachedStyleSetCacheFlags(Libraries::Font::OrbisFontStyleFrame& cached_style, u8 flags) {
    cached_style.cache_flags_and_direction =
        (cached_style.cache_flags_and_direction & 0xFFFFFF00u) | static_cast<u32>(flags);
}

void CachedStyleSetDirectionWord(Libraries::Font::OrbisFontStyleFrame& cached_style, u16 word) {
    cached_style.cache_flags_and_direction =
        (cached_style.cache_flags_and_direction & 0x0000FFFFu) | (static_cast<u32>(word) << 16);
}

float CachedStyleGetScalar(const Libraries::Font::OrbisFontStyleFrame& cached_style) {
    float value = 0.0f;
    std::memcpy(&value, &cached_style.cached_scalar_bits, sizeof(value));
    return value;
}

void CachedStyleSetScalar(Libraries::Font::OrbisFontStyleFrame& cached_style, float value) {
    std::memcpy(&cached_style.cached_scalar_bits, &value, sizeof(value));
}
} // namespace Libraries::Font::Internal
