diff --git a/lib/EpdFont/SdCardFontManager.cpp b/lib/EpdFont/SdCardFontManager.cpp index 804df07d..a6032336 100644 --- a/lib/EpdFont/SdCardFontManager.cpp +++ b/lib/EpdFont/SdCardFontManager.cpp @@ -28,21 +28,25 @@ int SdCardFontManager::computeFontId(uint32_t contentHash, const char* familyNam return id != 0 ? id : 1; // 0 is reserved as "not found" sentinel } -bool SdCardFontManager::loadFamily(const SdCardFontFamilyInfo& family, GfxRenderer& renderer, uint8_t targetPtSize) { +bool SdCardFontManager::loadFamily(const SdCardFontFamilyInfo& family, GfxRenderer& renderer, uint8_t fontSizeEnum) { // Unload any previously loaded family first if (!loadedFamilyName_.empty()) { unloadAll(renderer); } - // Pick the single file whose size is closest to targetPtSize. Loading - // only one size bounds resident memory (intervals + kern/ligature tables - // per style) to one file's worth, vs. N_sizes × per-file overhead. - const SdCardFontFileInfo* selected = family.pickClosestSize(targetPtSize); - if (!selected) { + // Select by ordinal position: sort available sizes, then map the font size + // enum (SMALL=0 .. EXTRA_LARGE=3) to the corresponding slot. When the + // family has fewer sizes than 4, clamp to the last available size. + auto sizes = family.availableSizes(); + if (sizes.empty()) { LOG_ERR("SDMGR", "Family %s has no files to load", family.name.c_str()); return false; } + uint8_t idx = fontSizeEnum; + if (idx >= sizes.size()) idx = sizes.size() - 1; + const SdCardFontFileInfo* selected = family.findFile(sizes[idx]); + auto* font = new (std::nothrow) SdCardFont(); if (!font) { LOG_ERR("SDMGR", "Failed to allocate SdCardFont for %s", selected->path.c_str()); @@ -66,8 +70,8 @@ bool SdCardFontManager::loadFamily(const SdCardFontFamilyInfo& family, GfxRender renderer.registerSdCardFont(fontId, font); loaded_.push_back({font, fontId, selected->pointSize}); - LOG_DBG("SDMGR", "Loaded %s size=%u id=%d styles=%u (target=%u)", selected->path.c_str(), selected->pointSize, fontId, - font->styleCount(), targetPtSize); + LOG_DBG("SDMGR", "Loaded %s size=%u id=%d styles=%u (sizeEnum=%u)", selected->path.c_str(), selected->pointSize, + fontId, font->styleCount(), fontSizeEnum); EpdFontFamily fontFamily(font->getEpdFont(0), font->getEpdFont(1), font->getEpdFont(2), font->getEpdFont(3)); renderer.insertFont(fontId, fontFamily); diff --git a/lib/EpdFont/SdCardFontManager.h b/lib/EpdFont/SdCardFontManager.h index def66e8d..aec07472 100644 --- a/lib/EpdFont/SdCardFontManager.h +++ b/lib/EpdFont/SdCardFontManager.h @@ -15,16 +15,12 @@ class SdCardFontManager { SdCardFontManager(const SdCardFontManager&) = delete; SdCardFontManager& operator=(const SdCardFontManager&) = delete; - // Load the single size whose pointSize is closest to targetPtSize. Only one - // .cpfont file is loaded; other sizes remain on disk. This keeps resident - // interval + kern/ligature tables to one size's worth of memory. - // - // Closest-pt selection is robust against families that don't ship the - // canonical {12,14,16,18}: a family with only [10,14,18] still resolves - // any reasonable target, where ordinal slot-mapping by SMALL..EXTRA_LARGE - // would mis-select. + // Load the font file matching fontSizeEnum (SMALL=0 .. EXTRA_LARGE=3) by + // ordinal position in the family's sorted size list. Only one .cpfont file + // is loaded; other sizes remain on disk. This keeps resident interval + + // kern/ligature tables to one size's worth of memory. // Returns true on success. - bool loadFamily(const SdCardFontFamilyInfo& family, GfxRenderer& renderer, uint8_t targetPtSize); + bool loadFamily(const SdCardFontFamilyInfo& family, GfxRenderer& renderer, uint8_t fontSizeEnum); // Unload everything, unregister from renderer. void unloadAll(GfxRenderer& renderer); diff --git a/lib/EpdFont/SdCardFontRegistry.cpp b/lib/EpdFont/SdCardFontRegistry.cpp index af1009b0..2e0f145c 100644 --- a/lib/EpdFont/SdCardFontRegistry.cpp +++ b/lib/EpdFont/SdCardFontRegistry.cpp @@ -4,8 +4,6 @@ #include #include -#include -#include #include // --- SdCardFontFamilyInfo helpers --- @@ -40,21 +38,6 @@ std::vector SdCardFontFamilyInfo::availableSizes() const { return sizes; } -const SdCardFontFileInfo* SdCardFontFamilyInfo::pickClosestSize(uint8_t targetPtSize) const { - const SdCardFontFileInfo* selected = nullptr; - int bestDiff = INT_MAX; - for (const auto& f : files) { - int diff = std::abs(static_cast(f.pointSize) - static_cast(targetPtSize)); - // Strict < ensures the first scan wins on ties; then tie-break by smaller - // pointSize to make the choice independent of filesystem enumeration order. - if (diff < bestDiff || (diff == bestDiff && selected && f.pointSize < selected->pointSize)) { - bestDiff = diff; - selected = &f; - } - } - return selected; -} - // --- SdCardFontRegistry --- bool SdCardFontRegistry::parseFilename(const char* filename, uint8_t& size, uint8_t& style) { diff --git a/lib/EpdFont/SdCardFontRegistry.h b/lib/EpdFont/SdCardFontRegistry.h index aae932d9..f96035ed 100644 --- a/lib/EpdFont/SdCardFontRegistry.h +++ b/lib/EpdFont/SdCardFontRegistry.h @@ -20,15 +20,6 @@ struct SdCardFontFamilyInfo { const SdCardFontFileInfo* findFile(uint8_t size, uint8_t style = 0) const; bool hasSize(uint8_t size) const; std::vector availableSizes() const; - - // Pick the file whose pointSize is closest to targetPtSize. On ties (equal - // distance) prefers the smaller pointSize so behaviour is deterministic - // across SD card layouts. Returns nullptr when files is empty. - // - // Robust against families that don't ship the canonical {12,14,16,18} set: - // a family with only [10,14,18] resolves target 12 → 10 (or 14 on tie), - // target 16 → 14 or 18, etc., instead of mis-indexing by ordinal slot. - const SdCardFontFileInfo* pickClosestSize(uint8_t targetPtSize) const; }; class SdCardFontRegistry { diff --git a/src/SdCardFontSystem.cpp b/src/SdCardFontSystem.cpp index 8e59d6ed..b771bede 100644 --- a/src/SdCardFontSystem.cpp +++ b/src/SdCardFontSystem.cpp @@ -5,15 +5,10 @@ #include "CrossPointSettings.h" -// Map fontSize enum (SMALL=0, MEDIUM=1, LARGE=2, EXTRA_LARGE=3) to the point -// sizes shipped with the built-in fonts. Used to drive closest-pt selection -// in the SD card font registry (see SdCardFontFamilyInfo::pickClosestSize). -static constexpr uint8_t FONT_SIZE_TO_PT[CrossPointSettings::FONT_SIZE_COUNT] = {12, 14, 16, 18}; - -static uint8_t targetPtSizeFromSettings() { +static uint8_t fontSizeEnumFromSettings() { uint8_t e = SETTINGS.fontSize; if (e >= CrossPointSettings::FONT_SIZE_COUNT) e = 1; // default to MEDIUM - return FONT_SIZE_TO_PT[e]; + return e; } void SdCardFontSystem::begin(GfxRenderer& renderer) { @@ -30,7 +25,7 @@ void SdCardFontSystem::begin(GfxRenderer& renderer) { if (SETTINGS.sdFontFamilyName[0] != '\0') { const auto* family = registry_.findFamily(SETTINGS.sdFontFamilyName); if (family) { - if (manager_.loadFamily(*family, renderer, targetPtSizeFromSettings())) { + if (manager_.loadFamily(*family, renderer, fontSizeEnumFromSettings())) { 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); @@ -58,7 +53,7 @@ void SdCardFontSystem::ensureLoaded(GfxRenderer& renderer) { const char* wantedFamily = SETTINGS.sdFontFamilyName; const std::string& currentFamily = manager_.currentFamilyName(); - const uint8_t targetPt = targetPtSizeFromSettings(); + const uint8_t sizeEnum = fontSizeEnumFromSettings(); if (wantedFamily[0] == '\0') { if (!currentFamily.empty()) { @@ -67,8 +62,8 @@ void SdCardFontSystem::ensureLoaded(GfxRenderer& renderer) { return; } - // Reload if family changed OR if the user-selected size now resolves to a - // different on-disk file than what's currently loaded OR if the registry was + // Reload if family changed OR if the user-selected size maps to a + // different file than what's currently loaded OR if the registry was // just rediscovered (file may have been replaced on disk). bool familyMatches = (currentFamily == wantedFamily); if (familyMatches) { @@ -79,11 +74,13 @@ void SdCardFontSystem::ensureLoaded(GfxRenderer& renderer) { SETTINGS.sdFontFamilyName[0] = '\0'; return; } - const auto* best = family->pickClosestSize(targetPt); - const uint8_t bestPt = best ? best->pointSize : 0; - if (!registryWasDirty && bestPt == manager_.currentPointSize()) return; - LOG_DBG("SDFS", "Reloading %s: size %u -> %u (target %u)%s", wantedFamily, manager_.currentPointSize(), bestPt, - targetPt, registryWasDirty ? " [registry dirty]" : ""); + auto sizes = family->availableSizes(); + uint8_t idx = sizeEnum; + if (idx >= sizes.size()) idx = sizes.size() - 1; + uint8_t wantedPt = sizes.empty() ? 0 : sizes[idx]; + if (!registryWasDirty && wantedPt == manager_.currentPointSize()) return; + LOG_DBG("SDFS", "Reloading %s: size %u -> %u (enum %u)%s", wantedFamily, manager_.currentPointSize(), wantedPt, + sizeEnum, registryWasDirty ? " [registry dirty]" : ""); } if (!currentFamily.empty()) { @@ -92,7 +89,7 @@ void SdCardFontSystem::ensureLoaded(GfxRenderer& renderer) { const auto* family = registry_.findFamily(wantedFamily); if (family) { - if (manager_.loadFamily(*family, renderer, targetPt)) { + if (manager_.loadFamily(*family, renderer, sizeEnum)) { LOG_DBG("SDFS", "Loaded SD font family: %s", wantedFamily); } else { LOG_ERR("SDFS", "Failed to load SD font family: %s (clearing)", wantedFamily);