overlays: Add basic font substitution system and separate JPN from Latin-1 set

- Gets JP glyphs to render correctly, but the generalization may negatively affect other CJK glyph sets.
  PS3 doesn't seem to use other glyph sets much however.
This commit is contained in:
kd-11 2020-02-19 21:10:53 +03:00 committed by kd-11
commit 8e68427daf
2 changed files with 82 additions and 23 deletions

View file

@ -51,48 +51,92 @@ namespace rsx
initialized = true; initialized = true;
} }
codepage* font::initialize_codepage(u16 codepage_id) language_class font::classify(u16 codepage_id)
{ {
// Init glyph if (codepage_id >= 0x2E && codepage_id <= 0x9F)
std::vector<u8> bytes; {
std::vector<std::string> font_dirs; return language_class::cjk;
std::vector<std::string> fallback_fonts; }
return language_class::default_;
}
glyph_load_setup font::get_glyph_files(language_class class_)
{
glyph_load_setup result;
#ifdef _WIN32 #ifdef _WIN32
font_dirs.push_back("C:/Windows/Fonts/"); result.lookup_font_dirs.push_back("C:/Windows/Fonts/");
fallback_fonts.push_back("C:/Windows/Fonts/Arial.ttf");
#else #else
char* home = getenv("HOME"); char* home = getenv("HOME");
if (home == nullptr) if (home == nullptr)
home = getpwuid(getuid())->pw_dir; home = getpwuid(getuid())->pw_dir;
font_dirs.emplace_back(home); result.lookup_font_dirs.emplace_back(home);
if (home[font_dirs[0].length() - 1] == '/') if (home[result.lookup_font_dirs[0].length() - 1] == '/')
font_dirs[0] += ".fonts/"; result.lookup_font_dirs[0] += ".fonts/";
else else
font_dirs[0] += "/.fonts/"; result.lookup_font_dirs[0] += "/.fonts/";
fallback_fonts.emplace_back("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"); // ubuntu
fallback_fonts.emplace_back("/usr/share/fonts/TTF/DejaVuSans.ttf"); // arch
#endif #endif
// Search dev_flash for the font too // Search dev_flash for the font too
font_dirs.push_back(g_cfg.vfs.get_dev_flash() + "data/font/"); result.lookup_font_dirs.push_back(g_cfg.vfs.get_dev_flash() + "data/font/");
font_dirs.push_back(g_cfg.vfs.get_dev_flash() + "data/font/SONY-CC/"); result.lookup_font_dirs.push_back(g_cfg.vfs.get_dev_flash() + "data/font/SONY-CC/");
// Attempt to load a font from dev_flash as a last resort switch (class_)
fallback_fonts.push_back(g_cfg.vfs.get_dev_flash() + "data/font/SCE-PS3-VR-R-LATIN.TTF"); {
case language_class::default_:
{
// Standard name
result.font_name = font_name;
#ifdef _WIN32
result.fallback_fonts.push_back("C:/Windows/Fonts/Arial.ttf");
#else
fallback_fonts.emplace_back("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"); // ubuntu
fallback_fonts.emplace_back("/usr/share/fonts/TTF/DejaVuSans.ttf"); // arch
#endif
// Attempt to load a font from dev_flash as a last resort
result.fallback_fonts.push_back(g_cfg.vfs.get_dev_flash() + "data/font/SCE-PS3-VR-R-LATIN.TTF");
break;
}
case language_class::cjk:
{
// Skip loading font files directly
result.lookup_font_dirs.clear();
// Attempt to load a font from dev_flash before any other source
result.fallback_fonts.push_back(g_cfg.vfs.get_dev_flash() + "data/font/SCE-PS3-SR-R-JPN.TTF");
#ifdef _WIN32
result.fallback_fonts.push_back("C:/Windows/Fonts/Yu Gothic.ttf"); // Japanese only
#else
// No standard CJK set on linux
#endif
break;
}
}
return result;
}
codepage* font::initialize_codepage(u16 codepage_id)
{
// Init glyph
const auto class_ = classify(codepage_id);
const auto fs_settings = get_glyph_files(class_);
// Attemt to load requested font // Attemt to load requested font
std::vector<u8> bytes;
std::string file_path; std::string file_path;
bool font_found = false; bool font_found = false;
for (auto& font_dir : font_dirs)
for (auto& font_dir : fs_settings.lookup_font_dirs)
{ {
std::string requested_file = font_dir + font_name; std::string requested_file = font_dir + fs_settings.font_name;
// Append ".ttf" if not present // Append ".ttf" if not present
std::string font_lower(requested_file); std::string font_lower(requested_file);
std::transform(requested_file.begin(), requested_file.end(), font_lower.begin(), ::tolower); std::transform(requested_file.begin(), requested_file.end(), font_lower.begin(), ::tolower);
if (font_lower.substr(font_lower.size() - 4) != ".ttf") if (!font_lower.ends_with(".ttf"))
requested_file += ".ttf"; requested_file += ".ttf";
file_path = requested_file; file_path = requested_file;
@ -107,7 +151,7 @@ namespace rsx
// Attemt to load a fallback if request font wasn't found // Attemt to load a fallback if request font wasn't found
if (!font_found) if (!font_found)
{ {
for (auto& fallback_font : fallback_fonts) for (auto& fallback_font : fs_settings.fallback_fonts)
{ {
if (fs::is_file(fallback_font)) if (fs::is_file(fallback_font))
{ {
@ -128,7 +172,7 @@ namespace rsx
} }
else else
{ {
rsx_log.error("Failed to initialize font '%s.ttf'", font_name); rsx_log.error("Failed to initialize font '%s.ttf' on codepage %d", font_name, codepage_id);
return nullptr; return nullptr;
} }

View file

@ -12,6 +12,19 @@ namespace rsx
{ {
namespace overlays namespace overlays
{ {
enum language_class
{
default_ = 0, // Typically latin-1, extended latin, hebrew, arabic and cyrillic
cjk = 1 // The thousands of CJK glyphs occupying pages 2E-9F
};
struct glyph_load_setup
{
std::string font_name;
std::vector<std::string> lookup_font_dirs;
std::vector<std::string> fallback_fonts;
};
// Each 'page' holds an indexed block of 256 code points // Each 'page' holds an indexed block of 256 code points
// The BMP (Basic Multilingual Plane) has 256 allocated pages but not all are necessary // The BMP (Basic Multilingual Plane) has 256 allocated pages but not all are necessary
// While there are supplementary planes, the BMP is the most important thing to support // While there are supplementary planes, the BMP is the most important thing to support
@ -49,6 +62,8 @@ namespace rsx
} }
codepage_cache; codepage_cache;
language_class classify(u16 page);
glyph_load_setup get_glyph_files(language_class class_);
codepage* initialize_codepage(u16 page); codepage* initialize_codepage(u16 page);
public: public: