Integrate upstream #1392 by adriancaruana
This commit is contained in:
@@ -0,0 +1,160 @@
|
||||
#include "SdCardFontSystem.h"
|
||||
|
||||
#include <GfxRenderer.h>
|
||||
#include <I18n.h>
|
||||
#include <Logging.h>
|
||||
|
||||
#include <climits>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#include "CrossPointSettings.h"
|
||||
#include "SdCardFontGlobals.h"
|
||||
|
||||
// Free-function resolver used by CrossPointSettings::getReaderFontId().
|
||||
// Resolved by the linker — no callback indirection stored in settings.
|
||||
int resolveSdCardFontId(const char* familyName) { return sdFontSystem.resolveFontId(familyName, 0); }
|
||||
|
||||
// --- Font-family dynamic SettingInfo trampolines ---
|
||||
//
|
||||
// The font-family SettingInfo lives in a namespace-static SettingsList that is
|
||||
// initialized at global-static phase, well before sdFontSystem.begin() runs.
|
||||
// We therefore cannot bake the SD family list into the SettingInfo at
|
||||
// construction; instead the SettingInfo holds these stateless trampolines that
|
||||
// consult sdFontSystem at every call. enumLabels is enriched lazily by the
|
||||
// consumers (SettingsActivity, CrossPointWebServer) before each iteration.
|
||||
|
||||
uint8_t fontFamilyDynamicGetter(const void* /*ctx*/) {
|
||||
if (SETTINGS.sdFontFamilyName[0] != '\0') {
|
||||
const auto& families = sdFontSystem.registry().getFamilies();
|
||||
for (size_t i = 0; i < families.size(); i++) {
|
||||
if (families[i].name == SETTINGS.sdFontFamilyName) {
|
||||
return static_cast<uint8_t>(CrossPointSettings::BUILTIN_FONT_COUNT + i);
|
||||
}
|
||||
}
|
||||
// SD family no longer present (card removed?); fall through to built-in.
|
||||
}
|
||||
return SETTINGS.fontFamily < CrossPointSettings::BUILTIN_FONT_COUNT ? SETTINGS.fontFamily
|
||||
: CrossPointSettings::BOOKERLY;
|
||||
}
|
||||
|
||||
void fontFamilyDynamicSetter(void* /*ctx*/, uint8_t value) {
|
||||
if (value < CrossPointSettings::BUILTIN_FONT_COUNT) {
|
||||
SETTINGS.fontFamily = value;
|
||||
SETTINGS.sdFontFamilyName[0] = '\0';
|
||||
return;
|
||||
}
|
||||
const auto& families = sdFontSystem.registry().getFamilies();
|
||||
uint8_t sdIdx = value - CrossPointSettings::BUILTIN_FONT_COUNT;
|
||||
if (sdIdx < families.size()) {
|
||||
strncpy(SETTINGS.sdFontFamilyName, families[sdIdx].name.c_str(), sizeof(SETTINGS.sdFontFamilyName) - 1);
|
||||
SETTINGS.sdFontFamilyName[sizeof(SETTINGS.sdFontFamilyName) - 1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t fontFamilyOptionCount() {
|
||||
return static_cast<uint8_t>(CrossPointSettings::BUILTIN_FONT_COUNT + sdFontSystem.registry().getFamilies().size());
|
||||
}
|
||||
|
||||
std::string fontFamilyOptionLabel(uint8_t i) {
|
||||
if (i < CrossPointSettings::BUILTIN_FONT_COUNT) {
|
||||
static const StrId BUILTIN_LABELS[] = {StrId::STR_BOOKERLY, StrId::STR_NOTO_SANS, StrId::STR_OPEN_DYSLEXIC};
|
||||
return I18N.get(BUILTIN_LABELS[i]);
|
||||
}
|
||||
const auto& families = sdFontSystem.registry().getFamilies();
|
||||
uint8_t sdIdx = i - CrossPointSettings::BUILTIN_FONT_COUNT;
|
||||
return sdIdx < families.size() ? families[sdIdx].name : std::string();
|
||||
}
|
||||
|
||||
// Map fontSize enum (SMALL=0, MEDIUM=1, LARGE=2, EXTRA_LARGE=3) to point sizes.
|
||||
static constexpr uint8_t FONT_SIZE_TO_PT[] = {12, 14, 16, 18};
|
||||
|
||||
static uint8_t targetPtSizeFromSettings() {
|
||||
uint8_t e = SETTINGS.fontSize;
|
||||
if (e >= sizeof(FONT_SIZE_TO_PT)) e = 1; // default to MEDIUM
|
||||
return FONT_SIZE_TO_PT[e];
|
||||
}
|
||||
|
||||
void SdCardFontSystem::begin(GfxRenderer& renderer) {
|
||||
registry_.discover();
|
||||
|
||||
// If user has a saved SD font selection, load it
|
||||
if (SETTINGS.sdFontFamilyName[0] != '\0') {
|
||||
const auto* family = registry_.findFamily(SETTINGS.sdFontFamilyName);
|
||||
if (family) {
|
||||
if (manager_.loadFamily(*family, renderer, targetPtSizeFromSettings())) {
|
||||
LOG_DBG("SDFS", "Loaded SD card font family: %s", SETTINGS.sdFontFamilyName);
|
||||
} else {
|
||||
LOG_ERR("SDFS", "Failed to load SD font family: %s (clearing)", SETTINGS.sdFontFamilyName);
|
||||
SETTINGS.sdFontFamilyName[0] = '\0';
|
||||
}
|
||||
} else {
|
||||
LOG_DBG("SDFS", "SD font family not found on card: %s (clearing)", SETTINGS.sdFontFamilyName);
|
||||
SETTINGS.sdFontFamilyName[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
LOG_DBG("SDFS", "SD font system ready (%d families discovered)", registry_.getFamilyCount());
|
||||
}
|
||||
|
||||
void SdCardFontSystem::ensureLoaded(GfxRenderer& renderer) {
|
||||
const char* wantedFamily = SETTINGS.sdFontFamilyName;
|
||||
const std::string& currentFamily = manager_.currentFamilyName();
|
||||
const uint8_t targetPt = targetPtSizeFromSettings();
|
||||
|
||||
if (wantedFamily[0] == '\0') {
|
||||
if (!currentFamily.empty()) {
|
||||
manager_.unloadAll(renderer);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Reload if family changed OR if the user-selected size changed and the
|
||||
// family has a closer file than what's currently loaded.
|
||||
bool familyMatches = (currentFamily == wantedFamily);
|
||||
if (familyMatches) {
|
||||
const auto* family = registry_.findFamily(wantedFamily);
|
||||
if (!family) {
|
||||
LOG_DBG("SDFS", "SD font family disappeared: %s (clearing)", wantedFamily);
|
||||
manager_.unloadAll(renderer);
|
||||
SETTINGS.sdFontFamilyName[0] = '\0';
|
||||
return;
|
||||
}
|
||||
uint8_t bestPt = 0;
|
||||
int bestDiff = INT32_MAX;
|
||||
for (const auto& f : family->files) {
|
||||
int diff = abs(static_cast<int>(f.pointSize) - static_cast<int>(targetPt));
|
||||
if (diff < bestDiff) {
|
||||
bestDiff = diff;
|
||||
bestPt = f.pointSize;
|
||||
}
|
||||
}
|
||||
if (bestPt == manager_.currentPointSize()) return; // already loaded with the right size
|
||||
LOG_DBG("SDFS", "Reloading %s: size %u -> %u (target %u)", wantedFamily, manager_.currentPointSize(), bestPt,
|
||||
targetPt);
|
||||
}
|
||||
|
||||
if (!currentFamily.empty()) {
|
||||
manager_.unloadAll(renderer);
|
||||
}
|
||||
|
||||
const auto* family = registry_.findFamily(wantedFamily);
|
||||
if (family) {
|
||||
if (manager_.loadFamily(*family, renderer, targetPt)) {
|
||||
LOG_DBG("SDFS", "Loaded SD font family: %s", wantedFamily);
|
||||
} else {
|
||||
LOG_ERR("SDFS", "Failed to load SD font family: %s (clearing)", wantedFamily);
|
||||
SETTINGS.sdFontFamilyName[0] = '\0';
|
||||
}
|
||||
} else {
|
||||
LOG_DBG("SDFS", "SD font family not found: %s (clearing)", wantedFamily);
|
||||
SETTINGS.sdFontFamilyName[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
int SdCardFontSystem::resolveFontId(const char* familyName, uint8_t /*fontSizeEnum*/) const {
|
||||
// The manager loads exactly one size (closest to SETTINGS.fontSize), so the
|
||||
// enum is implicit — always return the single loaded font ID for this family.
|
||||
// ensureLoaded() must have been called with the current settings before this.
|
||||
return manager_.getFontId(familyName);
|
||||
}
|
||||
Reference in New Issue
Block a user