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>
# Conflicts:
#	lib/EpdFont/SdCardFont.cpp
This commit is contained in:
Zach Nelson
2026-05-15 09:56:21 -05:00
parent b145e4437c
commit a7586f20a1
6 changed files with 126 additions and 88 deletions
+1 -15
View File
@@ -255,20 +255,6 @@ void ParsedText::layoutAndExtractLines(const GfxRenderer& renderer, const int fo
// (advanceX only, no bitmaps) for all unique codepoints in this paragraph so
// that calculateWordWidths() can measure text without on-demand SD I/O.
if (renderer.isSdCardFont(fontId)) {
// Reserve upfront so the joined text allocates exactly once. Without this,
// paragraphs with many words trigger a chain of vector-like reallocations
// inside std::string during layout — visible in prewarm timings for SD fonts.
size_t totalSize = hyphenationEnabled ? 1 : 0;
if (!words.empty()) totalSize += words.size() - 1; // inter-word spaces
for (const auto& w : words) totalSize += w.size();
std::string allText;
allText.reserve(totalSize);
for (size_t i = 0; i < words.size(); i++) {
if (i > 0) allText += ' ';
allText += words[i];
}
if (hyphenationEnabled) allText += '-';
// Style mask: only ask the SD font to load advances for styles actually
// used in this paragraph. Style index is the low two bits (regular/bold/
// italic/bold-italic); the underline bit is irrelevant to advance metrics.
@@ -277,7 +263,7 @@ void ParsedText::layoutAndExtractLines(const GfxRenderer& renderer, const int fo
styleMask |= static_cast<uint8_t>(1u << (static_cast<uint8_t>(s) & 0x03));
}
if (styleMask == 0) styleMask = 0x01; // defensive: regular only
renderer.ensureSdCardFontReady(fontId, allText.c_str(), styleMask);
renderer.ensureSdCardFontReady(fontId, words, hyphenationEnabled, styleMask);
}
const int pageWidth = viewportWidth;