2026-02-19 20:30:15 +11:00
|
|
|
#pragma once
|
|
|
|
|
|
2026-02-22 21:38:03 +11:00
|
|
|
#include <InflateReader.h>
|
2026-02-19 20:30:15 +11:00
|
|
|
|
2026-03-12 07:05:46 +11:00
|
|
|
#include <vector>
|
|
|
|
|
|
2026-02-19 20:30:15 +11:00
|
|
|
#include "EpdFontData.h"
|
|
|
|
|
|
|
|
|
|
class FontDecompressor {
|
|
|
|
|
public:
|
2026-03-12 07:05:46 +11:00
|
|
|
static constexpr uint16_t MAX_PAGE_GLYPHS = 512;
|
2026-03-22 04:10:41 +11:00
|
|
|
static constexpr uint8_t MAX_PAGE_SLOTS = 4; // One per font style (R/B/I/BI)
|
2026-03-12 07:05:46 +11:00
|
|
|
|
|
|
|
|
FontDecompressor() = default;
|
|
|
|
|
~FontDecompressor();
|
|
|
|
|
|
2026-02-19 20:30:15 +11:00
|
|
|
bool init();
|
|
|
|
|
void deinit();
|
|
|
|
|
|
|
|
|
|
// Returns pointer to decompressed bitmap data for the given glyph.
|
2026-03-12 07:05:46 +11:00
|
|
|
// Checks the page buffer (from prewarm) first, then falls back to the hot group slot.
|
|
|
|
|
const uint8_t* getBitmap(const EpdFontData* fontData, const EpdGlyph* glyph, uint32_t glyphIndex);
|
2026-02-19 20:30:15 +11:00
|
|
|
|
2026-03-12 07:05:46 +11:00
|
|
|
// Free all cached data (page buffer + hot group).
|
2026-02-19 20:30:15 +11:00
|
|
|
void clearCache();
|
|
|
|
|
|
2026-03-12 07:05:46 +11:00
|
|
|
// Pre-scan UTF-8 text and extract needed glyph bitmaps into a flat page buffer.
|
|
|
|
|
// Each group is decompressed once into a temp buffer; only needed glyphs are kept.
|
|
|
|
|
// Returns the number of glyphs that couldn't be loaded (0 on full success).
|
|
|
|
|
int prewarmCache(const EpdFontData* fontData, const char* utf8Text);
|
2026-02-19 20:30:15 +11:00
|
|
|
|
2026-03-12 07:05:46 +11:00
|
|
|
struct Stats {
|
|
|
|
|
uint32_t cacheHits = 0;
|
|
|
|
|
uint32_t cacheMisses = 0;
|
|
|
|
|
uint32_t decompressTimeMs = 0;
|
|
|
|
|
uint16_t uniqueGroupsAccessed = 0;
|
|
|
|
|
uint32_t pageBufferBytes = 0; // pageBuffer allocation
|
|
|
|
|
uint32_t pageGlyphsBytes = 0; // pageGlyphs lookup table allocation
|
|
|
|
|
uint32_t hotGroupBytes = 0; // current hot group allocation
|
|
|
|
|
uint32_t peakTempBytes = 0; // largest temp buffer in prewarm
|
|
|
|
|
uint32_t getBitmapTimeUs = 0; // cumulative getBitmap time (micros)
|
|
|
|
|
uint32_t getBitmapCalls = 0; // number of getBitmap calls
|
2026-02-19 20:30:15 +11:00
|
|
|
};
|
2026-03-12 07:05:46 +11:00
|
|
|
void logStats(const char* label = "FDC");
|
|
|
|
|
void resetStats();
|
|
|
|
|
const Stats& getStats() const { return stats; }
|
2026-02-19 20:30:15 +11:00
|
|
|
|
2026-03-12 07:05:46 +11:00
|
|
|
private:
|
|
|
|
|
Stats stats;
|
2026-02-22 21:38:03 +11:00
|
|
|
InflateReader inflateReader;
|
2026-02-19 20:30:15 +11:00
|
|
|
|
2026-03-22 04:10:41 +11:00
|
|
|
// Page buffer slots: each style gets its own flat glyph buffer with sorted lookup.
|
|
|
|
|
// Up to MAX_PAGE_SLOTS (4) styles can be prewarmed simultaneously.
|
2026-03-12 07:05:46 +11:00
|
|
|
struct PageGlyphEntry {
|
|
|
|
|
uint32_t glyphIndex;
|
|
|
|
|
uint32_t bufferOffset;
|
|
|
|
|
uint32_t alignedOffset; // byte-aligned offset within its decompressed group (set during prewarm pre-scan)
|
|
|
|
|
};
|
2026-03-22 04:10:41 +11:00
|
|
|
struct PageSlot {
|
|
|
|
|
uint8_t* buffer = nullptr;
|
|
|
|
|
const EpdFontData* fontData = nullptr;
|
|
|
|
|
PageGlyphEntry* glyphs = nullptr;
|
|
|
|
|
uint16_t glyphCount = 0;
|
|
|
|
|
};
|
|
|
|
|
PageSlot pageSlots[MAX_PAGE_SLOTS] = {};
|
|
|
|
|
uint8_t pageSlotCount = 0;
|
2026-03-12 07:05:46 +11:00
|
|
|
|
|
|
|
|
// Hot group: last decompressed group (byte-aligned) for non-prewarmed fallback path.
|
|
|
|
|
// Kept in byte-aligned format; individual glyphs are compacted on demand into hotGlyphBuf.
|
|
|
|
|
const EpdFontData* hotGroupFont = nullptr;
|
|
|
|
|
uint16_t hotGroupIndex = UINT16_MAX;
|
|
|
|
|
std::vector<uint8_t> hotGroup;
|
|
|
|
|
|
|
|
|
|
// Scratch buffer for compacting a single glyph from the hot group.
|
|
|
|
|
// Valid until the next getBitmap() call.
|
|
|
|
|
std::vector<uint8_t> hotGlyphBuf;
|
|
|
|
|
|
|
|
|
|
void freePageBuffer();
|
|
|
|
|
void freeHotGroup();
|
|
|
|
|
uint16_t getGroupIndex(const EpdFontData* fontData, uint32_t glyphIndex);
|
|
|
|
|
uint32_t getAlignedOffset(const EpdFontData* fontData, uint16_t groupIndex, uint32_t glyphIndex);
|
|
|
|
|
bool decompressGroup(const EpdFontData* fontData, uint16_t groupIndex, uint8_t* outBuf, uint32_t outSize);
|
|
|
|
|
static void compactSingleGlyph(const uint8_t* alignedSrc, uint8_t* packedDst, uint8_t width, uint8_t height);
|
|
|
|
|
static int32_t findGlyphIndex(const EpdFontData* fontData, uint32_t codepoint);
|
2026-02-19 20:30:15 +11:00
|
|
|
};
|