feat: add SD card font support with on-device download and web management
Add a complete SD card font subsystem that enables users to install and use custom fonts beyond the three built-in families. This combines the back-end firmware support (#1327) with the font configuration, build pipeline, CI distribution, and user-facing management UI (#1392). Core font system: - Custom .cpfont binary format (v4) with multi-style support (regular, bold, italic, bold-italic) packed into a single file per size - On-demand glyph loading from SD card with two-pass prewarm rendering to bulk-read glyphs per page, achieving near-flash performance for Latin text (~697ms vs ~681ms) and viable CJK rendering (~32% slower) - Persistent advance cache for layout measurement without SD I/O - Overflow ring buffer for glyph cache misses during rendering - Memory-conscious design: only advance tables kept in RAM; glyph bitmaps, kern tables, and ligatures loaded on demand from SD Font management: - On-device WiFi download from GitHub Releases with manifest-based discovery, install/update detection, and progress UI - Web interface font upload, listing, and deletion via /fonts page - Manual SD card copy to /fonts/ or /.fonts/ directories - Font selection integrated into Settings > Reader > Font Family Build pipeline: - Declarative YAML config (sd-fonts.yaml) as single source of truth for the 17-family font library (serif, sans, mono, accessibility) - Python converter (fontconvert_sdcard.py) for TTF/OTF to .cpfont with FreeType rasterization, class-based kerning, and ligature extraction - Parallel build orchestrator with variable font instance extraction - CI workflow publishing versioned + stable releases to a dedicated crosspoint-fonts repository with auto-incrementing revision tags - Centralized version constants (cpfont_version.py) shared across build tooling and CI, with firmware headers as manual sync points Additional fixes: - CJK characters no longer get hyphens inserted at line breaks - Advance table eliminates 30+ second stalls during CJK section indexing for paragraphs with >512 unique codepoints Closes #930 Co-authored-by: Zach Nelson <zach@zdnelson.com> Co-authored-by: Justin <itsthisjustin@users.noreply.github.com> Co-authored-by: jpirnay <jens@pirnay.com> Co-authored-by: mcrosson <kemonine@kemonine.info>
This commit is contained in:
committed by
Zach Nelson
co-authored by
Zach Nelson
Justin
jpirnay
mcrosson
parent
29fd29f537
commit
7993b2bb97
@@ -0,0 +1,52 @@
|
||||
#pragma once
|
||||
|
||||
#include <SdCardFontManager.h>
|
||||
#include <SdCardFontRegistry.h>
|
||||
|
||||
#include <atomic>
|
||||
|
||||
class GfxRenderer;
|
||||
|
||||
/// Facade that owns the SD card font registry, manager, and resolver logic.
|
||||
/// Hides implementation details behind a single begin() + ensureLoaded() API.
|
||||
class SdCardFontSystem {
|
||||
public:
|
||||
SdCardFontSystem() = default;
|
||||
SdCardFontSystem(const SdCardFontSystem&) = delete;
|
||||
SdCardFontSystem& operator=(const SdCardFontSystem&) = delete;
|
||||
/// Discover SD card fonts and load user's saved selection. Call once during setup.
|
||||
void begin(GfxRenderer& renderer);
|
||||
|
||||
/// Ensure the correct SD font family is loaded for the current settings.
|
||||
/// Call before entering the reader or after settings change.
|
||||
/// Also re-discovers if the registry has been marked dirty (e.g. by web upload).
|
||||
void ensureLoaded(GfxRenderer& renderer);
|
||||
|
||||
/// Resolve an SD card font ID from family name + fontSize enum.
|
||||
/// Returns 0 if not found. Used by CrossPointSettings::getReaderFontId().
|
||||
int resolveFontId(const char* familyName, uint8_t fontSizeEnum) const;
|
||||
|
||||
/// Access the registry (e.g. for settings UI to enumerate available fonts).
|
||||
const SdCardFontRegistry& registry() const { return registry_; }
|
||||
|
||||
/// Non-const access to the registry (for FontInstaller).
|
||||
SdCardFontRegistry& registry() { return registry_; }
|
||||
|
||||
/// Mark the registry as needing re-discovery.
|
||||
/// Thread-safe: can be called from the web server task.
|
||||
void markRegistryDirty() { registryDirty_.store(true, std::memory_order_release); }
|
||||
|
||||
/// If the registry is dirty, re-scan the SD card now and clear the flag.
|
||||
/// Used by the web UI so uploaded/deleted fonts appear in the list
|
||||
/// without waiting for the reader activity to run ensureLoaded().
|
||||
void refreshIfDirty() {
|
||||
if (registryDirty_.exchange(false, std::memory_order_acquire)) {
|
||||
registry_.discover();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
SdCardFontRegistry registry_;
|
||||
SdCardFontManager manager_;
|
||||
std::atomic<bool> registryDirty_{false};
|
||||
};
|
||||
Reference in New Issue
Block a user