Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

switch/application : shared font workaround #79

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
6 changes: 6 additions & 0 deletions library/include/borealis/core/application.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
39 changes: 35 additions & 4 deletions library/include/borealis/core/font.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,46 @@

#include <string>
#include <unordered_map>
#include <vector>

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<std::string, int> 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<uint32_t> SharedFontFallbackOrder;
static const std::unordered_map<int, std::string> 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
{
Expand All @@ -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:
/**
Expand Down
2 changes: 1 addition & 1 deletion library/include/borealis/core/i18n.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down
1 change: 1 addition & 0 deletions library/include/borealis/platforms/switch/switch_font.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
64 changes: 52 additions & 12 deletions library/lib/core/application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 && i<HOSSharedFontType_Total; i++)
{
firstFont = i;
regular = Application::getFont(HOSSharedFontMap.at(fallbackOrder.at(firstFont)));
}
if (regular != FONT_INVALID)
{
Logger::debug("regular font switched to: {:s}", HOSSharedFontMap.at(fallbackOrder.at(firstFont)));
// build fallback chain to regular font (switch icons)
for (int i=firstFont+1; i<HOSSharedFontType_Total; i++)
Application::addFontFallback(HOSSharedFontMap.at(fallbackOrder.at(firstFont)), HOSSharedFontMap.at(fallbackOrder.at(i)));

// redirect regular font stash
Application::fontStash[FONT_REGULAR] = regular;
}
}

if (regular != FONT_INVALID)
{
// Switch icons - duplicate
// bool switchIcons = Application::addFontFallback(FONT_REGULAR, FONT_SWITCH_ICONS);
// if (!switchIcons)
// Logger::warning("Switch icons font was not loaded, icons will not be displayed");
// Material icons
int materialIcons = Application::getFont(FONT_MATERIAL_ICONS);
if (materialIcons != FONT_INVALID)
nvgAddFallbackFontId(vg, regular, materialIcons);
else
bool materialIcons = Application::addFontFallback(FONT_REGULAR, FONT_MATERIAL_ICONS);
if (!materialIcons)
Logger::warning("Material icons font was not loaded, icons will not be displayed");
}
else
Expand Down Expand Up @@ -678,6 +702,22 @@ bool Application::loadFontFromMemory(std::string fontName, void* address, size_t
return true;
}

bool Application::addFontFallback(std::string baseFontName, std::string fallbackFontName)
{
NVGcontext* vg = Application::getNVGContext();
int baseFont = Application::getFont(baseFontName);
if (baseFont != FONT_INVALID)
{
int fallbackFont = Application::getFont(fallbackFontName);
if (fallbackFont != FONT_INVALID)
{
nvgAddFallbackFontId(vg, baseFont, fallbackFont);
return true;
}
}
return false;
}

void Application::crash(std::string text)
{
// To be implemented
Expand Down
11 changes: 11 additions & 0 deletions library/lib/core/font.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,15 @@ bool FontLoader::loadMaterialFromResources()
return this->loadFontFromFile(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; i<order_list_count; i++)
{
order_list->push_back(i);
}
return true;
}

} // namespace brls
121 changes: 104 additions & 17 deletions library/lib/platforms/switch/switch_font.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,40 +19,127 @@

#include <borealis/core/application.hpp>
#include <borealis/core/logger.hpp>
#include <borealis/core/i18n.hpp>
#include <borealis/platforms/switch/switch_font.hpp>

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; i<PlSharedFontType_Total; i++) {
fontsSorted[fonts[i].type] = &fonts[i];
}

// Extented (symbols)
rc = plGetSharedFontByType(&font, PlSharedFontType_NintendoExt);
if (R_SUCCEEDED(rc))
Application::loadFontFromMemory(FONT_SWITCH_ICONS, font.address, font.size, false);
// Standard
Application::loadFontFromMemory(FONT_HOS_STANDARD,
fontsSorted[PlSharedFontType_Standard]->address,
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; i<order_list_count; i++)
{
order_list->push_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