From db3bb850b22494abbfe4aa8106576bb5c80b670d Mon Sep 17 00:00:00 2001 From: Chun Ming Lee <95391408+leecming82@users.noreply.github.com> Date: Wed, 13 May 2026 03:11:37 +0800 Subject: [PATCH] fix: handle fallbacks for advance table and prewarm (#1929) ## Summary - Fixes #1928 by having the prewarm and advance table functions resolve fallback styles --- ### AI Usage Did you use AI tools to help write this code? YES - Codex --------- Co-authored-by: Uri Tauber --- lib/EpdFont/SdCardFont.cpp | 35 +++++++++++++++++++++++++++++++++ lib/EpdFont/SdCardFont.h | 7 +++++++ lib/GfxRenderer/GfxRenderer.cpp | 18 +---------------- 3 files changed, 43 insertions(+), 17 deletions(-) diff --git a/lib/EpdFont/SdCardFont.cpp b/lib/EpdFont/SdCardFont.cpp index 7bd75baa..8b496719 100644 --- a/lib/EpdFont/SdCardFont.cpp +++ b/lib/EpdFont/SdCardFont.cpp @@ -9,6 +9,8 @@ #include #include +#include "EpdFontFamily.h" + static_assert(sizeof(EpdGlyph) == 16, "EpdGlyph must be 16 bytes to match .cpfont file layout"); static_assert(sizeof(EpdUnicodeInterval) == 12, "EpdUnicodeInterval must be 12 bytes to match .cpfont file layout"); static_assert(sizeof(EpdKernClassEntry) == 3, "EpdKernClassEntry must be 3 bytes to match .cpfont file layout"); @@ -587,6 +589,8 @@ int32_t SdCardFont::findGlobalGlyphIndex(const PerStyle& s, uint32_t codepoint) int SdCardFont::prewarm(const char* utf8Text, uint8_t styleMask, bool metadataOnly) { if (!loaded_) return -1; + styleMask = resolveStyleMask(styleMask); + if (styleMask == 0) return 0; unsigned long startMs = millis(); @@ -1017,6 +1021,8 @@ uint16_t SdCardFont::getAdvance(uint32_t codepoint, uint8_t style) const { int SdCardFont::buildAdvanceTable(const char* utf8Text, uint8_t styleMask) { if (!loaded_) return -1; + styleMask = resolveStyleMask(styleMask); + if (styleMask == 0) return 0; // Note: advance table is preserved across calls. We only fetch codepoints // not already present, then merge them in. Use clearPersistentCache() to @@ -1194,6 +1200,35 @@ EpdFont* SdCardFont::getEpdFont(uint8_t style) { bool SdCardFont::hasStyle(uint8_t style) const { return styles_[style & (MAX_STYLES - 1)].present; } +uint8_t SdCardFont::resolveStyle(uint8_t style) const { + static const uint8_t kFallbacks[MAX_STYLES][MAX_STYLES] = { + // REGULAR: REGULAR -> BOLD -> ITALIC -> BOLD_ITALIC + {EpdFontFamily::REGULAR, EpdFontFamily::BOLD, EpdFontFamily::ITALIC, EpdFontFamily::BOLD_ITALIC}, + // BOLD: BOLD -> REGULAR -> BOLD_ITALIC -> ITALIC + {EpdFontFamily::BOLD, EpdFontFamily::REGULAR, EpdFontFamily::BOLD_ITALIC, EpdFontFamily::ITALIC}, + // ITALIC: ITALIC -> REGULAR -> BOLD_ITALIC -> BOLD + {EpdFontFamily::ITALIC, EpdFontFamily::REGULAR, EpdFontFamily::BOLD_ITALIC, EpdFontFamily::BOLD}, + // BOLD_ITALIC: BOLD_ITALIC -> BOLD -> ITALIC -> REGULAR + {EpdFontFamily::BOLD_ITALIC, EpdFontFamily::BOLD, EpdFontFamily::ITALIC, EpdFontFamily::REGULAR}, + }; + + const uint8_t styleBits = style & (MAX_STYLES - 1); + for (uint8_t candidate : kFallbacks[styleBits]) { + if (styles_[candidate].present) return candidate; + } + return EpdFontFamily::REGULAR; +} + +uint8_t SdCardFont::resolveStyleMask(uint8_t styleMask) const { + uint8_t resolvedMask = 0; + for (uint8_t si = 0; si < MAX_STYLES; si++) { + if (styleMask & (1 << si)) { + resolvedMask |= static_cast(1u << resolveStyle(si)); + } + } + return resolvedMask; +} + // --- On-demand glyph loading (overflow buffer) --- const EpdGlyph* SdCardFont::onGlyphMiss(void* ctx, uint32_t codepoint) { diff --git a/lib/EpdFont/SdCardFont.h b/lib/EpdFont/SdCardFont.h index 821697ee..c826000e 100644 --- a/lib/EpdFont/SdCardFont.h +++ b/lib/EpdFont/SdCardFont.h @@ -71,6 +71,13 @@ class SdCardFont { // Returns true if the given style is present in this font file. bool hasStyle(uint8_t style) const; + // Resolve requested style bits to the closest present style. + uint8_t resolveStyle(uint8_t style) const; + + // Resolve every requested style bit through fallback and return the actual + // styles that need cache/advance preparation. + uint8_t resolveStyleMask(uint8_t styleMask) const; + // Number of styles present in this font file. uint8_t styleCount() const { return styleCount_; } diff --git a/lib/GfxRenderer/GfxRenderer.cpp b/lib/GfxRenderer/GfxRenderer.cpp index 13283ef3..769402ef 100644 --- a/lib/GfxRenderer/GfxRenderer.cpp +++ b/lib/GfxRenderer/GfxRenderer.cpp @@ -19,23 +19,7 @@ const char* resolveVisualText(const char* text, std::string& visualBuffer, int p * Falls back gracefully when the font lacks the requested variant. */ uint8_t resolveSdCardStyle(const SdCardFont& font, const EpdFontFamily::Style style) { - // Indexed by styleBits (0=REGULAR, 1=BOLD, 2=ITALIC, 3=BOLD_ITALIC) - static const uint8_t kFallbacks[4][4] = { - // REGULAR: REGULAR → BOLD → ITALIC → BOLD_ITALIC - {EpdFontFamily::REGULAR, EpdFontFamily::BOLD, EpdFontFamily::ITALIC, EpdFontFamily::BOLD_ITALIC}, - // BOLD: BOLD → BOLD_ITALIC → REGULAR → ITALIC - {EpdFontFamily::BOLD, EpdFontFamily::BOLD_ITALIC, EpdFontFamily::REGULAR, EpdFontFamily::ITALIC}, - // ITALIC: ITALIC → REGULAR → BOLD → BOLD_ITALIC (REGULAR before BOLD!) - {EpdFontFamily::ITALIC, EpdFontFamily::REGULAR, EpdFontFamily::BOLD, EpdFontFamily::BOLD_ITALIC}, - // BOLD_ITALIC: BOLD_ITALIC → BOLD → ITALIC → REGULAR - {EpdFontFamily::BOLD_ITALIC, EpdFontFamily::BOLD, EpdFontFamily::ITALIC, EpdFontFamily::REGULAR}, - }; - - const uint8_t styleBits = static_cast(style) & 0x03; - for (uint8_t candidate : kFallbacks[styleBits]) { - if (font.hasStyle(candidate)) return candidate; - } - return EpdFontFamily::REGULAR; // no-variant-at-all safety net + return font.resolveStyle(static_cast(style)); } } // namespace