A fork of https://github.com/crosspoint-reader/crosspoint-reader
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at records-reader 96 lines 3.2 kB view raw
1#include "FontCacheManager.h" 2 3#include <FontDecompressor.h> 4#include <Logging.h> 5 6#include <cstring> 7 8FontCacheManager::FontCacheManager(const std::map<int, EpdFontFamily>& fontMap) : fontMap_(fontMap) {} 9 10void FontCacheManager::setFontDecompressor(FontDecompressor* d) { fontDecompressor_ = d; } 11 12void FontCacheManager::clearCache() { 13 if (fontDecompressor_) fontDecompressor_->clearCache(); 14} 15 16void FontCacheManager::prewarmCache(int fontId, const char* utf8Text, uint8_t styleMask) { 17 if (!fontDecompressor_ || fontMap_.count(fontId) == 0) return; 18 19 for (uint8_t i = 0; i < 4; i++) { 20 if (!(styleMask & (1 << i))) continue; 21 auto style = static_cast<EpdFontFamily::Style>(i); 22 const EpdFontData* data = fontMap_.at(fontId).getData(style); 23 if (!data || !data->groups) continue; 24 int missed = fontDecompressor_->prewarmCache(data, utf8Text); 25 if (missed > 0) { 26 LOG_DBG("FCM", "prewarmCache: %d glyph(s) not cached for style %d", missed, i); 27 } 28 } 29} 30 31void FontCacheManager::logStats(const char* label) { 32 if (fontDecompressor_) fontDecompressor_->logStats(label); 33} 34 35void FontCacheManager::resetStats() { 36 if (fontDecompressor_) fontDecompressor_->resetStats(); 37} 38 39bool FontCacheManager::isScanning() const { return scanMode_ == ScanMode::Scanning; } 40 41void FontCacheManager::recordText(const char* text, int fontId, EpdFontFamily::Style style) { 42 scanText_ += text; 43 if (scanFontId_ < 0) scanFontId_ = fontId; 44 const uint8_t baseStyle = static_cast<uint8_t>(style) & 0x03; 45 const unsigned char* p = reinterpret_cast<const unsigned char*>(text); 46 uint32_t cpCount = 0; 47 while (*p) { 48 if ((*p & 0xC0) != 0x80) cpCount++; 49 p++; 50 } 51 scanStyleCounts_[baseStyle] += cpCount; 52} 53 54// --- PrewarmScope implementation --- 55 56FontCacheManager::PrewarmScope::PrewarmScope(FontCacheManager& manager) : manager_(&manager) { 57 manager_->scanMode_ = ScanMode::Scanning; 58 manager_->clearCache(); 59 manager_->resetStats(); 60 manager_->scanText_.clear(); 61 manager_->scanText_.reserve(2048); // Pre-allocate to avoid heap fragmentation from repeated concat 62 memset(manager_->scanStyleCounts_, 0, sizeof(manager_->scanStyleCounts_)); 63 manager_->scanFontId_ = -1; 64} 65 66void FontCacheManager::PrewarmScope::endScanAndPrewarm() { 67 manager_->scanMode_ = ScanMode::None; 68 if (manager_->scanText_.empty()) return; 69 70 // Build style bitmask from all styles that appeared during the scan 71 uint8_t styleMask = 0; 72 for (uint8_t i = 0; i < 4; i++) { 73 if (manager_->scanStyleCounts_[i] > 0) styleMask |= (1 << i); 74 } 75 if (styleMask == 0) styleMask = 1; // default to regular 76 77 manager_->prewarmCache(manager_->scanFontId_, manager_->scanText_.c_str(), styleMask); 78 79 // Free scan string memory 80 manager_->scanText_.clear(); 81 manager_->scanText_.shrink_to_fit(); 82} 83 84FontCacheManager::PrewarmScope::~PrewarmScope() { 85 if (active_) { 86 endScanAndPrewarm(); // no-op if already called (scanText_ is empty) 87 manager_->clearCache(); 88 } 89} 90 91FontCacheManager::PrewarmScope::PrewarmScope(PrewarmScope&& other) noexcept 92 : manager_(other.manager_), active_(other.active_) { 93 other.active_ = false; 94} 95 96FontCacheManager::PrewarmScope FontCacheManager::createPrewarmScope() { return PrewarmScope(*this); }