mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-22 08:33:12 -05:00
sceFontOpenFontSet failed for every set type, so PPSA21564 drew no text in system fonts (the title screen copyright line, credits, button guides). It now loads the set's primary font file from ANYPS5_SYSTEM_FONTS, or anyps5-fonts beside the executable: console files under their own names first, then openly licensed substitutes (Noto Sans, Noto Sans Mono, Noto Sans Thai, Noto Sans CJK). The PS5-only JG2 set types are accepted. System font handles use the system font context. Their faces are loaded by FreeType in host memory: about 1 MiB per CJK face does not fit the font memory the title sizes for the console's fonts, and sceFontCreateRenderer then failed with ALLOCATION_FAILED. Handles of the same font file share one copy of its bytes.
132 lines
6.5 KiB
C++
132 lines
6.5 KiB
C++
#include <algorithm>
|
|
#include <array>
|
|
#include <cstdlib>
|
|
#include <stdexcept>
|
|
#include <string_view>
|
|
#include <system_error>
|
|
#ifdef _WIN32
|
|
#include <windows.h>
|
|
#endif
|
|
|
|
#include "prx/libSceFont/include/FontInternal.hpp"
|
|
|
|
namespace {
|
|
|
|
constexpr std::array<std::uint32_t, 120> SYSTEM_FONT_SET_TYPES = {
|
|
0x18070043u, 0x18070044u, 0x18070045u, 0x18070047u, 0x18070053u, 0x18070054u,
|
|
0x18070055u, 0x18070057u, 0x180700C3u, 0x180700C4u, 0x180700C5u, 0x180700C7u,
|
|
0x18070444u, 0x18070447u, 0x18070454u, 0x18070457u, 0x180704C4u, 0x180704C7u,
|
|
0x18071053u, 0x18071054u, 0x18071055u, 0x18071057u, 0x18071454u, 0x18071457u,
|
|
0x18072444u, 0x18072447u, 0x180724C4u, 0x180724C7u, 0x18073454u, 0x18073457u,
|
|
0x180734D4u, 0x180734D7u, 0x18078044u, 0x180780C4u, 0x18079054u, 0x1807A044u,
|
|
0x1807A0C4u, 0x1807A444u, 0x1807A4C4u, 0x1807AC44u, 0x1807ACC4u, 0x1807B054u,
|
|
0x1807B0D4u, 0x1807B454u, 0x1807B4D4u, 0x1807BC54u, 0x1807BCD4u, 0x18080444u,
|
|
0x18080447u, 0x18080454u, 0x18080457u, 0x180804C4u, 0x180804C7u, 0x18081454u,
|
|
0x18081457u, 0x18082444u, 0x18082447u, 0x180824C4u, 0x180824C7u, 0x18083454u,
|
|
0x18083457u, 0x180834D4u, 0x180834D7u, 0x1808A444u, 0x1808A4C4u, 0x1808B454u,
|
|
0x1808B4D4u, 0x180C8044u, 0x180C80C4u, 0x180C9054u, 0x180CA044u, 0x180CA0C4u,
|
|
0x180CAC44u, 0x180CACC4u, 0x180CB054u, 0x180CB0D4u, 0x180CBC54u, 0x180CBCD4u,
|
|
0x18170043u, 0x18170044u, 0x18170045u, 0x18170047u, 0x18170444u, 0x18170447u,
|
|
0x18370044u, 0x18370047u, 0x18370444u, 0x18370447u, 0x1A070543u, 0x1A070547u,
|
|
0x1A070553u, 0x1A070557u, 0x1A0705C3u, 0x1A0705C7u, 0x1A071553u, 0x1A071557u,
|
|
0x1A072543u, 0x1A072547u, 0x1A0725C3u, 0x1A0725C7u, 0x1A073553u, 0x1A073557u,
|
|
0x1A0735D3u, 0x1A0735D7u, 0x1A080543u, 0x1A080547u, 0x1A080553u, 0x1A080557u,
|
|
0x1A0805C3u, 0x1A0805C7u, 0x1A081553u, 0x1A081557u, 0x1A082543u, 0x1A082547u,
|
|
0x1A0825C3u, 0x1A0825C7u, 0x1A083553u, 0x1A083557u, 0x1A0835D3u, 0x1A0835D7u,
|
|
};
|
|
|
|
enum class Family { Latin, LatinItalic, Typewriter, Vietnamese, Thai, Japanese, ChineseGb };
|
|
|
|
struct FamilyFiles {
|
|
std::array<std::string_view, 4> system;
|
|
std::array<std::string_view, 4> substitute;
|
|
std::uint32_t substituteSubFont;
|
|
};
|
|
|
|
constexpr std::array<FamilyFiles, 7> FAMILY_FILES = {{
|
|
{{"SST-Light.otf", "SST-Roman.otf", "SST-Medium.otf", "SST-Bold.otf"},
|
|
{"NotoSans-Light.ttf", "NotoSans-Regular.ttf", "NotoSans-Medium.ttf", "NotoSans-Bold.ttf"}, 0},
|
|
{{"SST-LightItalic.otf", "SST-Italic.otf", "SST-MediumItalic.otf", "SST-BoldItalic.otf"},
|
|
{"NotoSans-LightItalic.ttf", "NotoSans-Italic.ttf", "NotoSans-MediumItalic.ttf", "NotoSans-BoldItalic.ttf"}, 0},
|
|
{{"SSTTypewriter-Roman.otf", "SSTTypewriter-Roman.otf", "SSTTypewriter-Roman.otf", "SSTTypewriter-Bd.otf"},
|
|
{"NotoSansMono-Light.ttf", "NotoSansMono-Regular.ttf", "NotoSansMono-Medium.ttf", "NotoSansMono-Bold.ttf"}, 0},
|
|
{{"SSTVietnamese-Light.otf", "SSTVietnamese-Roman.otf", "SSTVietnamese-Medium.otf", "SSTVietnamese-Bold.otf"},
|
|
{"NotoSans-Light.ttf", "NotoSans-Regular.ttf", "NotoSans-Medium.ttf", "NotoSans-Bold.ttf"}, 0},
|
|
{{"SSTThai-Light.otf", "SSTThai-Roman.otf", "SSTThai-Medium.otf", "SSTThai-Bold.otf"},
|
|
{"NotoSansThai-Light.ttf", "NotoSansThai-Regular.ttf", "NotoSansThai-Medium.ttf", "NotoSansThai-Bold.ttf"}, 0},
|
|
{{"SSTJpPro-Regular.otf", "SSTJpPro-Regular.otf", "SSTJpPro-Regular.otf", "SSTJpPro-Bold.otf"},
|
|
{"NotoSansCJK-Light.ttc", "NotoSansCJK-Regular.ttc", "NotoSansCJK-Medium.ttc", "NotoSansCJK-Bold.ttc"}, 0},
|
|
{{"DFHEI5-SONY.ttf", "DFHEI5-SONY.ttf", "DFHEI5-SONY.ttf", "DFHEI5-SONY.ttf"},
|
|
{"NotoSansCJK-Light.ttc", "NotoSansCJK-Regular.ttc", "NotoSansCJK-Medium.ttc", "NotoSansCJK-Bold.ttc"}, 2},
|
|
}};
|
|
|
|
Family FamilyOf(std::uint32_t fontSetType) {
|
|
const std::uint32_t region = (fontSetType >> 16) & 0xFFu;
|
|
const std::uint32_t scripts = (fontSetType >> 8) & 0xFEu;
|
|
const bool vietnamese = (fontSetType & 0x10u) != 0;
|
|
switch (region) {
|
|
case 0x17: return Family::LatinItalic;
|
|
case 0x37: return Family::Typewriter;
|
|
case 0x08: return scripts == 0x04 && vietnamese ? Family::Vietnamese : Family::Japanese;
|
|
case 0x0C: return Family::ChineseGb;
|
|
default:
|
|
if (scripts == 0x10) return Family::Thai;
|
|
if (scripts == 0 && vietnamese) return Family::Vietnamese;
|
|
return Family::Latin;
|
|
}
|
|
}
|
|
|
|
std::size_t WeightOf(std::uint32_t fontSetType) {
|
|
switch (fontSetType & 0x0Fu) {
|
|
case 0x3: return 0;
|
|
case 0x5: return 2;
|
|
case 0x7: return 3;
|
|
default: return 1;
|
|
}
|
|
}
|
|
|
|
std::filesystem::path ExecutableDirectory() {
|
|
#ifdef _WIN32
|
|
wchar_t module[MAX_PATH];
|
|
const auto length = GetModuleFileNameW(nullptr, module, MAX_PATH);
|
|
if (length == 0 || length == MAX_PATH) throw std::runtime_error("libSceFont: cannot locate the executable");
|
|
return std::filesystem::path(module).parent_path();
|
|
#else
|
|
return std::filesystem::read_symlink("/proc/self/exe").parent_path();
|
|
#endif
|
|
}
|
|
|
|
}
|
|
|
|
bool Font::IsSystemFontSet(std::uint32_t fontSetType) {
|
|
return std::find(SYSTEM_FONT_SET_TYPES.begin(), SYSTEM_FONT_SET_TYPES.end(), fontSetType) != SYSTEM_FONT_SET_TYPES.end();
|
|
}
|
|
|
|
std::vector<Font::SystemFontFile> Font::SystemFontCandidates(std::uint32_t fontSetType) {
|
|
if (!IsSystemFontSet(fontSetType)) return {};
|
|
const FamilyFiles& files = FAMILY_FILES[static_cast<std::size_t>(FamilyOf(fontSetType))];
|
|
const std::size_t weight = WeightOf(fontSetType);
|
|
return {{std::filesystem::path(files.system[weight]), 0}, {std::filesystem::path(files.substitute[weight]), files.substituteSubFont}};
|
|
}
|
|
|
|
std::filesystem::path Font::SystemFontDirectory() {
|
|
const char* configured = std::getenv("ANYPS5_SYSTEM_FONTS");
|
|
if (!configured || configured[0] == '\0') return ExecutableDirectory() / "anyps5-fonts";
|
|
const std::filesystem::path directory(configured);
|
|
std::error_code error;
|
|
if (!std::filesystem::is_directory(directory, error)) throw std::runtime_error("libSceFont: ANYPS5_SYSTEM_FONTS is not a directory: " + directory.string());
|
|
return directory;
|
|
}
|
|
|
|
std::optional<Font::SystemFontFile> Font::FindSystemFontFile(std::uint32_t fontSetType) {
|
|
const std::vector<SystemFontFile> candidates = SystemFontCandidates(fontSetType);
|
|
if (candidates.empty()) return std::nullopt;
|
|
const std::filesystem::path directory = SystemFontDirectory();
|
|
for (const SystemFontFile& candidate : candidates) {
|
|
std::error_code error;
|
|
const std::filesystem::path path = directory / candidate.path;
|
|
if (std::filesystem::is_regular_file(path, error)) return SystemFontFile{path, candidate.subFontIndex};
|
|
}
|
|
return std::nullopt;
|
|
}
|