Integrate upstream #1392 by adriancaruana
This commit is contained in:
@@ -2,18 +2,35 @@
|
||||
|
||||
#include <FontDecompressor.h>
|
||||
#include <Logging.h>
|
||||
#include <SdCardFont.h>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
FontCacheManager::FontCacheManager(const std::map<int, EpdFontFamily>& fontMap) : fontMap_(fontMap) {}
|
||||
FontCacheManager::FontCacheManager(const std::map<int, EpdFontFamily>& fontMap,
|
||||
const std::map<int, SdCardFont*>& sdCardFonts)
|
||||
: fontMap_(fontMap), sdCardFonts_(sdCardFonts) {}
|
||||
|
||||
void FontCacheManager::setFontDecompressor(FontDecompressor* d) { fontDecompressor_ = d; }
|
||||
|
||||
void FontCacheManager::clearCache() {
|
||||
if (fontDecompressor_) fontDecompressor_->clearCache();
|
||||
for (auto& [id, font] : sdCardFonts_) {
|
||||
font->clearCache();
|
||||
}
|
||||
}
|
||||
|
||||
void FontCacheManager::prewarmCache(int fontId, const char* utf8Text, uint8_t styleMask) {
|
||||
// SD card font prewarm path: prewarm all requested styles in one call
|
||||
auto sdIt = sdCardFonts_.find(fontId);
|
||||
if (sdIt != sdCardFonts_.end()) {
|
||||
int missed = sdIt->second->prewarm(utf8Text, styleMask);
|
||||
if (missed > 0) {
|
||||
LOG_DBG("FCM", "prewarmCache(SD): %d glyph(s) not found (styleMask=0x%02X)", missed, styleMask);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Standard compressed font prewarm path: loop over all requested styles
|
||||
if (!fontDecompressor_ || fontMap_.count(fontId) == 0) return;
|
||||
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
@@ -30,10 +47,16 @@ void FontCacheManager::prewarmCache(int fontId, const char* utf8Text, uint8_t st
|
||||
|
||||
void FontCacheManager::logStats(const char* label) {
|
||||
if (fontDecompressor_) fontDecompressor_->logStats(label);
|
||||
for (auto& [id, font] : sdCardFonts_) {
|
||||
font->logStats(label);
|
||||
}
|
||||
}
|
||||
|
||||
void FontCacheManager::resetStats() {
|
||||
if (fontDecompressor_) fontDecompressor_->resetStats();
|
||||
for (auto& [id, font] : sdCardFonts_) {
|
||||
font->resetStats();
|
||||
}
|
||||
}
|
||||
|
||||
bool FontCacheManager::isScanning() const { return scanMode_ == ScanMode::Scanning; }
|
||||
|
||||
@@ -7,10 +7,11 @@
|
||||
#include <string>
|
||||
|
||||
class FontDecompressor;
|
||||
class SdCardFont;
|
||||
|
||||
class FontCacheManager {
|
||||
public:
|
||||
explicit FontCacheManager(const std::map<int, EpdFontFamily>& fontMap);
|
||||
FontCacheManager(const std::map<int, EpdFontFamily>& fontMap, const std::map<int, SdCardFont*>& sdCardFonts);
|
||||
|
||||
void setFontDecompressor(FontDecompressor* d);
|
||||
|
||||
@@ -45,6 +46,7 @@ class FontCacheManager {
|
||||
|
||||
private:
|
||||
const std::map<int, EpdFontFamily>& fontMap_;
|
||||
const std::map<int, SdCardFont*>& sdCardFonts_;
|
||||
FontDecompressor* fontDecompressor_ = nullptr;
|
||||
|
||||
enum class ScanMode : uint8_t { None, Scanning };
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <FontDecompressor.h>
|
||||
#include <HalGPIO.h>
|
||||
#include <Logging.h>
|
||||
#include <SdCardFont.h>
|
||||
#include <Utf8.h>
|
||||
#include <esp_heap_caps.h>
|
||||
|
||||
@@ -21,9 +22,34 @@ const uint8_t* GfxRenderer::getGlyphBitmap(const EpdFontData* fontData, const Ep
|
||||
// must consume it (draw the glyph) before requesting another bitmap.
|
||||
return fd->getBitmap(fontData, glyph, glyphIndex);
|
||||
}
|
||||
// For SD card fonts, check if the glyph was loaded on demand into the overflow
|
||||
// buffer. getOverflowBitmap() returns:
|
||||
// - bitmap pointer for overflow glyphs with bitmap data
|
||||
// - nullptr for overflow glyphs without bitmap data (e.g. space: width=0, height=0)
|
||||
// - nullptr for non-overflow glyphs (normal prewarmed path)
|
||||
// We distinguish overflow-with-no-bitmap from non-overflow by checking isOverflowGlyph().
|
||||
if (fontData->glyphMissCtx) {
|
||||
auto* sdFont = SdCardFont::fromMissCtx(fontData->glyphMissCtx);
|
||||
if (sdFont->isOverflowGlyph(glyph)) {
|
||||
return sdFont->getOverflowBitmap(glyph); // may be nullptr for zero-width glyphs
|
||||
}
|
||||
}
|
||||
return &fontData->bitmap[glyph->dataOffset];
|
||||
}
|
||||
|
||||
void GfxRenderer::ensureSdCardFontReady(int fontId, const char* utf8Text) const {
|
||||
auto it = sdCardFonts_.find(fontId);
|
||||
if (it != sdCardFonts_.end()) {
|
||||
// Metadata-only: loads glyph metrics (advanceX) without bitmap data.
|
||||
// Saves ~50-100KB heap vs full prewarm — layout only needs advance widths.
|
||||
// Prewarm all present styles (0x0F) for layout measurement.
|
||||
int missed = it->second->prewarm(utf8Text, 0x0F, /*metadataOnly=*/true);
|
||||
if (missed > 0) {
|
||||
LOG_DBG("GFX", "ensureSdCardFontReady: %d glyph(s) not found", missed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GfxRenderer::begin() {
|
||||
frameBuffer = display.getFrameBuffer();
|
||||
if (!frameBuffer) {
|
||||
@@ -38,7 +64,12 @@ void GfxRenderer::begin() {
|
||||
bwBufferChunks.assign((frameBufferSize + bwBufferChunkSize - 1) / bwBufferChunkSize, nullptr);
|
||||
}
|
||||
|
||||
void GfxRenderer::insertFont(const int fontId, EpdFontFamily font) { fontMap.insert({fontId, font}); }
|
||||
void GfxRenderer::insertFont(const int fontId, EpdFontFamily font) {
|
||||
auto result = fontMap.insert({fontId, font});
|
||||
if (!result.second) {
|
||||
LOG_ERR("GFX", "Font ID %d already registered, ignoring duplicate", fontId);
|
||||
}
|
||||
}
|
||||
|
||||
// Translate logical (x,y) coordinates to physical panel coordinates based on current orientation
|
||||
// This should always be inlined for better performance
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <HalDisplay.h>
|
||||
|
||||
class FontCacheManager;
|
||||
class SdCardFont;
|
||||
|
||||
#include <atomic>
|
||||
#include <cstring>
|
||||
@@ -57,6 +58,10 @@ class GfxRenderer {
|
||||
size_t bwBufferChunkSize = BW_BUFFER_CHUNK_SIZE;
|
||||
std::vector<uint8_t*> bwBufferChunks;
|
||||
std::map<int, EpdFontFamily> fontMap;
|
||||
// Mutable because ensureSdCardFontReady() is const (called from layout code that
|
||||
// holds a const GfxRenderer&) but triggers SD card reads and heap allocation
|
||||
// inside the SdCardFont objects. Same pragmatic compromise as fontCacheManager_.
|
||||
mutable std::map<int, SdCardFont*> sdCardFonts_;
|
||||
|
||||
// Mutable because drawText() is const but needs to delegate scan-mode
|
||||
// recording to the (non-const) FontCacheManager. Same pragmatic compromise
|
||||
@@ -97,9 +102,19 @@ class GfxRenderer {
|
||||
// Setup
|
||||
void begin(); // must be called right after display.begin()
|
||||
void insertFont(int fontId, EpdFontFamily font);
|
||||
void removeFont(int fontId) { fontMap.erase(fontId); }
|
||||
void setFontCacheManager(FontCacheManager* m) { fontCacheManager_ = m; }
|
||||
FontCacheManager* getFontCacheManager() const { return fontCacheManager_; }
|
||||
const std::map<int, EpdFontFamily>& getFontMap() const { return fontMap; }
|
||||
void registerSdCardFont(int fontId, SdCardFont* font) { sdCardFonts_[fontId] = font; }
|
||||
void unregisterSdCardFont(int fontId) { sdCardFonts_.erase(fontId); }
|
||||
void clearSdCardFonts() { sdCardFonts_.clear(); }
|
||||
const std::map<int, SdCardFont*>& getSdCardFonts() const { return sdCardFonts_; }
|
||||
bool isSdCardFont(int fontId) const { return sdCardFonts_.count(fontId) > 0; }
|
||||
// Ensure SD card font glyph data is loaded for the given text. Called from layout code
|
||||
// (which holds a const GfxRenderer&) before measuring word widths. Safe to call on
|
||||
// non-SD fonts (no-op).
|
||||
void ensureSdCardFontReady(int fontId, const char* utf8Text) const;
|
||||
|
||||
// Orientation control (affects logical width/height and coordinate transforms)
|
||||
void setOrientation(const Orientation o) { orientation.store(static_cast<int>(o), std::memory_order_relaxed); }
|
||||
|
||||
Reference in New Issue
Block a user