diff --git a/Makefile b/Makefile index bd85fda87..c9a2a5482 100644 --- a/Makefile +++ b/Makefile @@ -62,7 +62,9 @@ ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE CFLAGS := -g -Wall -O2 -ffunction-sections \ $(ARCH) $(DEFINES) -CFLAGS += $(INCLUDE) -D__SWITCH__ +CFLAGS += $(INCLUDE) -D__SWITCH__ \ + # -DSW_STANDARD_FONT_ONLY \ + # -DSW_DISABLE_FONT_FALLBACK CXXFLAGS := $(CFLAGS) -std=c++1z -O2 -Wno-volatile diff --git a/library/include/borealis/core/application.hpp b/library/include/borealis/core/application.hpp index 42449fa2e..6ac3f0f9a 100644 --- a/library/include/borealis/core/application.hpp +++ b/library/include/borealis/core/application.hpp @@ -116,6 +116,12 @@ class Application */ static bool loadFontFromMemory(std::string fontName, void* data, size_t size, bool freeData); + /** + * Wrapper for adding font fallback with nvgAddFallbackFontId. + * Returns true if both font stash exists and the operation succeeded. + */ + static bool addFontFallback(std::string baseFontName, std::string fallbackFontName); + /** * Returns the nanovg handle to the given font name, or FONT_INVALID if * no such font is currently loaded. diff --git a/library/include/borealis/core/font.hpp b/library/include/borealis/core/font.hpp index 4e70c67e8..cf6a7fa5b 100644 --- a/library/include/borealis/core/font.hpp +++ b/library/include/borealis/core/font.hpp @@ -18,19 +18,46 @@ #include #include +#include namespace brls { static constexpr const int FONT_INVALID = -1; -static const std::string FONT_REGULAR = "regular"; // regular Latin font -static const std::string FONT_KOREAN_REGULAR = "korean"; // regular Korean font -static const std::string FONT_MATERIAL_ICONS = "material"; // Material icons font -static const std::string FONT_SWITCH_ICONS = "switch"; // Switch icons font (see the HOS shared symbols font for an example) +static const std::string FONT_REGULAR = "regular"; // regular font (Borealis default font) +static const std::string FONT_MATERIAL_ICONS = "material"; // Material icons font typedef std::unordered_map FontStash; +// HOS Shared Font +static const std::string FONT_HOS_STANDARD = "switch_standard"; // Switch Standard (Latin/Japanese) shared font +static const std::string FONT_HOS_SCHINESE = "switch_schinese"; // Switch S.Chinese shared font +static const std::string FONT_HOS_SCHINESE_EXTEND = "switch_extschinese"; // Switch extended S.Chinese shared font +static const std::string FONT_HOS_TCHINESE = "switch_tchinese"; // Switch T.Chinese shared font +static const std::string FONT_HOS_KOREAN = "switch_korean"; // Switch Korean shared font +static const std::string FONT_SWITCH_ICONS = "switch_icons"; // Switch icons font (see the HOS shared symbols font for an example) + +typedef enum { +HOSSharedFontType_Standard = 0, ///< Japan, US and Europe +HOSSharedFontType_ChineseSimplified = 1, ///< Chinese Simplified +HOSSharedFontType_ExtChineseSimplified = 2, ///< Extended Chinese Simplified +HOSSharedFontType_ChineseTraditional = 3, ///< Chinese Traditional +HOSSharedFontType_KO = 4, ///< Korean (Hangul) +HOSSharedFontType_NintendoExt = 5, ///< Nintendo Extended. This font only has the special Nintendo-specific characters, which aren't available with the other fonts. +HOSSharedFontType_Total, ///< Total fonts supported by this enum. +} HOSSharedFontType; + +typedef std::vector SharedFontFallbackOrder; +static const std::unordered_map HOSSharedFontMap = { + {HOSSharedFontType_Standard, FONT_HOS_STANDARD}, + {HOSSharedFontType_ChineseSimplified, FONT_HOS_SCHINESE}, + {HOSSharedFontType_ExtChineseSimplified, FONT_HOS_SCHINESE_EXTEND}, + {HOSSharedFontType_ChineseTraditional, FONT_HOS_TCHINESE}, + {HOSSharedFontType_KO, FONT_HOS_KOREAN}, + {HOSSharedFontType_NintendoExt, FONT_SWITCH_ICONS}, +}; + // Platform interface to load fonts from disk or other sources (system / shared font...) class FontLoader { @@ -44,6 +71,10 @@ class FontLoader * of the "built-in" fonts defined in the FONT_* constants above. */ virtual void loadFonts() = 0; + /** + * Load font fallback order, mainly for SW. + */ + virtual bool loadSharedFontFallbackOrder(SharedFontFallbackOrder* order_list, int order_list_count = HOSSharedFontType_Total); protected: /** diff --git a/library/include/borealis/core/i18n.hpp b/library/include/borealis/core/i18n.hpp index 24784c9be..b345c2303 100644 --- a/library/include/borealis/core/i18n.hpp +++ b/library/include/borealis/core/i18n.hpp @@ -36,7 +36,7 @@ const std::string LOCALE_ZH_CN = "zh-CN"; const std::string LOCALE_ZH_HANS = "zh-Hans"; const std::string LOCALE_ZH_HANT = "zh-Hant"; const std::string LOCALE_ZH_TW = "zh-TW"; -const std::string LOCALE_Ko = "ko"; +const std::string LOCALE_KO = "ko"; const std::string LOCALE_NL = "nl"; const std::string LOCALE_PT = "pt"; const std::string LOCALE_PT_BR = "pt-BR"; diff --git a/library/include/borealis/platforms/switch/switch_font.hpp b/library/include/borealis/platforms/switch/switch_font.hpp index b51f5d7c5..d2f84071d 100644 --- a/library/include/borealis/platforms/switch/switch_font.hpp +++ b/library/include/borealis/platforms/switch/switch_font.hpp @@ -26,6 +26,7 @@ class SwitchFontLoader : public FontLoader { public: void loadFonts() override; + bool loadSharedFontFallbackOrder(SharedFontFallbackOrder* order_list, int order_list_count = HOSSharedFontType_Total) override; }; } // namespace brls diff --git a/library/lib/core/application.cpp b/library/lib/core/application.cpp index 16dd6beaf..b45d8046c 100644 --- a/library/lib/core/application.cpp +++ b/library/lib/core/application.cpp @@ -118,23 +118,47 @@ void Application::createWindow(std::string windowTitle) // Load fonts and setup fallbacks Application::platform->getFontLoader()->loadFonts(); + std::string locale = Application::getLocale(); int regular = Application::getFont(FONT_REGULAR); - if (regular != FONT_INVALID) + + // switch only: when defined font stash exists, try to find available font stash, + // build fallback chain and switch regular font, all fallback failures won't be logged + if (Application::platform->getName() == "Switch" && regular == FONT_INVALID) { - NVGcontext* vg = Application::getNVGContext(); + Logger::info("switch: no borealis regular font loaded, checking the rest of font stash"); - // Switch icons - int switchIcons = Application::getFont(FONT_SWITCH_ICONS); - if (switchIcons != FONT_INVALID) - nvgAddFallbackFontId(vg, regular, switchIcons); - else - Logger::warning("Switch icons font was not loaded, icons will not be displayed"); + // get fallback order + SharedFontFallbackOrder fallbackOrder {}; + Application::platform->getFontLoader()->loadSharedFontFallbackOrder(&fallbackOrder); // orderCount == HOSSharedFontType_Total + + // determine first available font stash as regular font + int firstFont = 0; + for (int i=firstFont; regular == FONT_INVALID && iloadFontFromFile(FONT_MATERIAL_ICONS, MATERIAL_ICONS_PATH); } +bool FontLoader::loadSharedFontFallbackOrder(SharedFontFallbackOrder* order_list, int order_list_count) +{ + // stub + Logger::warning("stub loadSharedFontFallbackOrder"); + for (int i=0; ipush_back(i); + } + return true; +} + } // namespace brls diff --git a/library/lib/platforms/switch/switch_font.cpp b/library/lib/platforms/switch/switch_font.cpp index eb1e7998d..e801bb68a 100644 --- a/library/lib/platforms/switch/switch_font.cpp +++ b/library/lib/platforms/switch/switch_font.cpp @@ -19,6 +19,7 @@ #include #include +#include #include namespace brls @@ -26,33 +27,119 @@ namespace brls void SwitchFontLoader::loadFonts() { - PlFontData font; Result rc; + PlFontData fonts[PlSharedFontType_Total]; + PlFontData* fontsSorted[PlSharedFontType_Total]; + std::string locale = Application::getLocale(); - // Standard - rc = plGetSharedFontByType(&font, PlSharedFontType_Standard); - if (R_SUCCEEDED(rc)) - Application::loadFontFromMemory(FONT_REGULAR, font.address, font.size, false); - else - Logger::error("switch: could not load Standard shared font: {:#x}", rc); + bool useStandardOnly = false; + // Compile-time flag + #ifdef SW_STANDARD_FONT_ONLY + bool useStandardOnly = true; + Logger::warning("switch: saving RAM: use standard shared font only!"); + #endif - // Korean - rc = plGetSharedFontByType(&font, PlSharedFontType_KO); + // todo: plGetSharedFont must use (u64)languageCode, conflict with suggested use of (std::string)locale + uint64_t languageCode = 0; + rc = setGetSystemLanguage(&languageCode); if (R_SUCCEEDED(rc)) - Application::loadFontFromMemory(FONT_KOREAN_REGULAR, font.address, font.size, false); - else - Logger::error("switch: could not load Korean shared font: {:#x}", rc); + { + int total_fonts=0; + rc = plGetSharedFont(languageCode, fonts, PlSharedFontType_Total, &total_fonts); + if (R_SUCCEEDED(rc)) + { + for (int i=0; iaddress, + fontsSorted[PlSharedFontType_Standard]->size, false); + + if (!useStandardOnly) + { + bool isFullFallback = false; + // Detect if non applet + AppletType at = appletGetAppletType(); + if (at == AppletType_Application || at == AppletType_SystemApplication) // title takeover + isFullFallback = true; + + // Compile-time flag + #ifdef SW_DISABLE_FONT_FALLBACK + isFullFallback = false; + Logger::warning("switch: saving RAM: full font fallback is disabled!"); + #endif + + if (isFullFallback) + Logger::info("switch: non applet mode, all shared fonts will be loaded!"); + else + Logger::info("switch: applet mode or disabling fallback, only shared font for current locale will be loaded."); + + if (locale == LOCALE_ZH_CN || locale == LOCALE_ZH_HANS || isFullFallback) + { + // S.Chinese + Application::loadFontFromMemory(FONT_HOS_SCHINESE, + fontsSorted[PlSharedFontType_ChineseSimplified]->address, + fontsSorted[PlSharedFontType_ChineseSimplified]->size, false); + // Ext S.Chinese + Application::loadFontFromMemory(FONT_HOS_SCHINESE_EXTEND, + fontsSorted[PlSharedFontType_ExtChineseSimplified]->address, + fontsSorted[PlSharedFontType_ExtChineseSimplified]->size, false); + } + + if (locale == LOCALE_ZH_TW || locale == LOCALE_ZH_HANT || isFullFallback) + // T.Chinese + Application::loadFontFromMemory(FONT_HOS_TCHINESE, + fontsSorted[PlSharedFontType_ChineseTraditional]->address, + fontsSorted[PlSharedFontType_ChineseTraditional]->size, false); + + if (locale == LOCALE_KO || isFullFallback) + // Korean + Application::loadFontFromMemory(FONT_HOS_KOREAN, + fontsSorted[PlSharedFontType_KO]->address, + fontsSorted[PlSharedFontType_KO]->size, false); + } + + // Extented (symbols) + Application::loadFontFromMemory(FONT_SWITCH_ICONS, + fontsSorted[PlSharedFontType_NintendoExt]->address, + fontsSorted[PlSharedFontType_NintendoExt]->size, false); + } + else + Logger::error("switch: shared font loading stopped - could not load multi shared font: {:#x}", rc); + } else - Logger::error("switch: could not load Extented shared font: {:#x}", rc); + Logger::error("switch: shared font loading stopped - could not load languageCode: {:#x}", rc); // Material icons if (!this->loadMaterialFromResources()) Logger::error("switch: could not load Material icons font from resources", rc); } +bool SwitchFontLoader::loadSharedFontFallbackOrder(SharedFontFallbackOrder* order_list, int order_list_count) +{ + Result rc; + PlFontData fonts[PlSharedFontType_Total]; + + // todo: plGetSharedFont must use (u64)languageCode, conflict with suggested use of (std::string)locale? + uint64_t languageCode = 0; + rc = setGetSystemLanguage(&languageCode); + if (R_SUCCEEDED(rc)) + { + int total_fonts=0; + rc = plGetSharedFont(languageCode, fonts, PlSharedFontType_Total, &total_fonts); + if (R_SUCCEEDED(rc)) + { + for (int i=0; ipush_back(fonts[i].type); + Logger::debug("switch: pushing type {:#x} to font fallback order list", order_list->at(i)); + } + } + return true; + } + return false; +} + } // namespace brls