fix: Prepare SD card font caches from txt reader (#1973)
## Summary SD card font fixes: - `TxtReaderActivity` needs to call `renderer.ensureSdCardFontReady` to build the advance lookup table to support rendering with SD card fonts. This revealed that `TxtReaderActivity` was inconsistently performing layout with `getTextWidth`, when the renderer actually uses `getTextAdvanceX`, which can lead to minor inconsistencies in alignment. - Avoid allocating one big `allText` string in `ParsedText::layoutAndExtractLines`. Instead, pass the vector of word strings directly to `SdCardFont::buildAdvanceTable`, where the algorithm just needs to iterate codepoints anyway. --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? _**PARTIALLY**_ --------- Co-authored-by: Justin Mitchell <justin@jmitch.com>
This commit is contained in:
co-authored by
Justin Mitchell
parent
5fa5a71ba2
commit
b186529120
@@ -192,6 +192,17 @@ bool TxtReaderActivity::loadPageAtOffset(size_t offset, std::vector<std::string>
|
||||
}
|
||||
buffer[chunkSize] = '\0';
|
||||
|
||||
// Prime the SD card font's advance table with this chunk's codepoints.
|
||||
// Without this, every getTextAdvanceX() call in the wrap loop below triggers
|
||||
// on-demand glyph loads through the 8-slot overflow ring buffer, which
|
||||
// thrashes for any text with more than 8 unique chars (i.e. all English),
|
||||
// floods the heap with short-lived bitmap allocations, and eventually
|
||||
// corrupts FreeRTOS state. The advance table persists across calls per
|
||||
// font, so the cost amortizes to ~ASCII-size after the first chunk.
|
||||
if (renderer.isSdCardFont(cachedFontId)) {
|
||||
renderer.ensureSdCardFontReady(cachedFontId, reinterpret_cast<const char*>(buffer), /*styleMask=*/0x01);
|
||||
}
|
||||
|
||||
// Parse lines from buffer
|
||||
size_t pos = 0;
|
||||
|
||||
@@ -231,7 +242,7 @@ bool TxtReaderActivity::loadPageAtOffset(size_t offset, std::vector<std::string>
|
||||
break;
|
||||
}
|
||||
|
||||
int lineWidth = renderer.getTextWidth(cachedFontId, line.c_str());
|
||||
int lineWidth = renderer.getTextAdvanceX(cachedFontId, line.c_str(), EpdFontFamily::REGULAR);
|
||||
|
||||
if (lineWidth <= viewportWidth) {
|
||||
outLines.push_back(line);
|
||||
@@ -242,7 +253,8 @@ bool TxtReaderActivity::loadPageAtOffset(size_t offset, std::vector<std::string>
|
||||
|
||||
// Find break point
|
||||
size_t breakPos = line.length();
|
||||
while (breakPos > 0 && renderer.getTextWidth(cachedFontId, line.substr(0, breakPos).c_str()) > viewportWidth) {
|
||||
while (breakPos > 0 && renderer.getTextAdvanceX(cachedFontId, line.substr(0, breakPos).c_str(),
|
||||
EpdFontFamily::REGULAR) > viewportWidth) {
|
||||
// Try to break at space
|
||||
size_t spacePos = line.rfind(' ', breakPos - 1);
|
||||
if (spacePos != std::string::npos && spacePos > 0) {
|
||||
@@ -354,12 +366,12 @@ void TxtReaderActivity::renderPage() {
|
||||
// x already set to left margin
|
||||
break;
|
||||
case CrossPointSettings::CENTER_ALIGN: {
|
||||
int textWidth = renderer.getTextWidth(cachedFontId, line.c_str());
|
||||
int textWidth = renderer.getTextAdvanceX(cachedFontId, line.c_str(), EpdFontFamily::REGULAR);
|
||||
x = cachedOrientedMarginLeft + (contentWidth - textWidth) / 2;
|
||||
break;
|
||||
}
|
||||
case CrossPointSettings::RIGHT_ALIGN: {
|
||||
int textWidth = renderer.getTextWidth(cachedFontId, line.c_str());
|
||||
int textWidth = renderer.getTextAdvanceX(cachedFontId, line.c_str(), EpdFontFamily::REGULAR);
|
||||
x = cachedOrientedMarginLeft + contentWidth - textWidth;
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user