Integrate upstream #1392 by adriancaruana
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
#include "SdCardFontManager.h"
|
||||
|
||||
#include <EpdFontFamily.h>
|
||||
#include <GfxRenderer.h>
|
||||
#include <Logging.h>
|
||||
#include <SdCardFont.h>
|
||||
#include <SdCardFontRegistry.h>
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
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 targetPtSize) {
|
||||
// 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 = nullptr;
|
||||
int bestDiff = INT32_MAX;
|
||||
for (const auto& fileInfo : family.files) {
|
||||
int diff = std::abs(static_cast<int>(fileInfo.pointSize) - static_cast<int>(targetPtSize));
|
||||
if (diff < bestDiff) {
|
||||
bestDiff = diff;
|
||||
selected = &fileInfo;
|
||||
}
|
||||
}
|
||||
if (!selected) {
|
||||
LOG_ERR("SDMGR", "Family %s has no files to load", family.name.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
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 (target=%u)", selected->path.c_str(), selected->pointSize, fontId,
|
||||
font->styleCount(), targetPtSize);
|
||||
|
||||
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;
|
||||
}
|
||||
Reference in New Issue
Block a user