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.
99 lines
3.3 KiB
C++
99 lines
3.3 KiB
C++
#include "SdCardFontManager.h"
|
|
|
|
#include <EpdFontFamily.h>
|
|
#include <GfxRenderer.h>
|
|
#include <Logging.h>
|
|
#include <SdCardFont.h>
|
|
#include <SdCardFontRegistry.h>
|
|
|
|
SdCardFontManager::~SdCardFontManager() {
|
|
for (auto& lf : loaded_) {
|
|
delete lf.font;
|
|
}
|
|
}
|
|
|
|
// FNV-1a continuation: seeds with contentHash, then hashes family name + point size.
|
|
// Produces a deterministic ID that is stable across load/unload cycles and reboots,
|
|
// and changes when font content changes (different header/TOC = different contentHash).
|
|
int SdCardFontManager::computeFontId(uint32_t contentHash, const char* familyName, uint8_t pointSize) {
|
|
static constexpr uint32_t FNV_PRIME = 16777619u;
|
|
uint32_t hash = contentHash;
|
|
while (*familyName) {
|
|
hash ^= static_cast<uint8_t>(*familyName++);
|
|
hash *= FNV_PRIME;
|
|
}
|
|
hash ^= pointSize;
|
|
hash *= FNV_PRIME;
|
|
int id = static_cast<int>(hash);
|
|
return id != 0 ? id : 1; // 0 is reserved as "not found" sentinel
|
|
}
|
|
|
|
bool SdCardFontManager::loadFamily(const SdCardFontFamilyInfo& family, GfxRenderer& renderer, uint8_t fontSizeEnum) {
|
|
// Unload any previously loaded family first
|
|
if (!loadedFamilyName_.empty()) {
|
|
unloadAll(renderer);
|
|
}
|
|
|
|
// 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());
|
|
return false;
|
|
}
|
|
|
|
if (!font->load(selected->path.c_str())) {
|
|
LOG_ERR("SDMGR", "Failed to load %s", selected->path.c_str());
|
|
delete font;
|
|
return false;
|
|
}
|
|
|
|
int fontId = computeFontId(font->contentHash(), family.name.c_str(), selected->pointSize);
|
|
// Guard against collision with built-in font IDs (astronomically unlikely
|
|
// with FNV-1a hashes, but provides a safety net)
|
|
if (renderer.getFontMap().count(fontId) != 0) {
|
|
LOG_ERR("SDMGR", "Font ID %d collides with existing font, skipping %s", fontId, selected->path.c_str());
|
|
delete font;
|
|
return false;
|
|
}
|
|
renderer.registerSdCardFont(fontId, font);
|
|
loaded_.push_back({font, fontId, selected->pointSize});
|
|
|
|
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);
|
|
|
|
loadedFamilyName_ = family.name;
|
|
loadedPointSize_ = selected->pointSize;
|
|
return true;
|
|
}
|
|
|
|
void SdCardFontManager::unloadAll(GfxRenderer& renderer) {
|
|
renderer.clearSdCardFonts();
|
|
for (auto& lf : loaded_) {
|
|
renderer.removeFont(lf.fontId);
|
|
delete lf.font;
|
|
}
|
|
loaded_.clear();
|
|
loadedFamilyName_.clear();
|
|
loadedPointSize_ = 0;
|
|
}
|
|
|
|
int SdCardFontManager::getFontId(const std::string& familyName) const {
|
|
if (familyName != loadedFamilyName_ || loaded_.empty()) return 0;
|
|
return loaded_.front().fontId;
|
|
}
|