Revert "feat: closest-pt size selection instead of ordinal slot" (#1949)

Reverts crosspoint-reader/crosspoint-reader#1912

This was meant to be more robust with partial SD card fonts, but causes
trouble for folks using custom font sizes. We need a better approach to
decouple numeric font sizes from S/M/L/XL settings.
This commit is contained in:
Zach Nelson
2026-05-11 12:44:52 -05:00
committed by GitHub
parent 24977048c3
commit 63d5094f2e
5 changed files with 31 additions and 60 deletions
+12 -8
View File
@@ -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);
+5 -9
View File
@@ -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);
-17
View File
@@ -4,8 +4,6 @@
#include <Logging.h>
#include <algorithm>
#include <climits>
#include <cstdlib>
#include <cstring>
// --- SdCardFontFamilyInfo helpers ---
@@ -40,21 +38,6 @@ std::vector<uint8_t> 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<int>(f.pointSize) - static_cast<int>(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) {
-9
View File
@@ -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<uint8_t> 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 {