Address review comment: fix bionic reading on continuation

This commit is contained in:
spfenwick
2026-05-02 16:59:03 +12:00
parent c04ec25dc7
commit 0a5fee2839
2 changed files with 44 additions and 26 deletions
+42 -25
View File
@@ -215,13 +215,16 @@ void ParsedText::layoutAndExtractLines(
} }
// Apply fixed transforms before any per-line layout work. // Apply fixed transforms before any per-line layout work.
// Skip on continuation flushes: the words are mid-paragraph and have // Paragraph indent only applies to the first layout pass; skip on continuations.
// already been transformed by the initial layoutAndExtractLines call.
if (!isContinuation_) { if (!isContinuation_) {
applyParagraphIndent(); applyParagraphIndent();
if (bionicReadingEnabled) { }
applyBionicReadingTransform(); // Bionic transform is incremental: applyBionicReadingTransform() is a no-op
} // for already-transformed words (bionicTransformedUpTo_ == words.size()) and
// only processes raw words appended since the last flush, so it is always safe
// to call regardless of isContinuation_.
if (bionicReadingEnabled) {
applyBionicReadingTransform();
} }
// Ensure SD card font glyph metrics are loaded before measuring word widths. // Ensure SD card font glyph metrics are loaded before measuring word widths.
@@ -382,6 +385,9 @@ void ParsedText::layoutAndExtractLines(
wordStyles.shrink_to_fit(); wordStyles.shrink_to_fit();
wordContinues.shrink_to_fit(); wordContinues.shrink_to_fit();
isContinuation_ = !includeLastLine; isContinuation_ = !includeLastLine;
// All remaining words were already transformed before the flush; reset the
// watermark so that words appended by addWord() are processed next time.
bionicTransformedUpTo_ = words.size();
} }
} }
@@ -585,18 +591,23 @@ void ParsedText::applyParagraphIndent() {
} }
void ParsedText::applyBionicReadingTransform() { void ParsedText::applyBionicReadingTransform() {
if (words.empty()) { // Only transform words that haven't been processed yet. On a fresh block
// bionicTransformedUpTo_ == 0 so all words are processed. After an
// intermediate flush, only the new raw words appended since the last flush
// (indices bionicTransformedUpTo_..words.size()-1) need transformation.
if (words.empty() || bionicTransformedUpTo_ >= words.size()) {
return; return;
} }
std::vector<std::string> transformedWords; const size_t suffixStart = bionicTransformedUpTo_;
std::vector<EpdFontFamily::Style> transformedStyles; std::vector<std::string> transformedSuffix;
std::vector<bool> transformedContinues; std::vector<EpdFontFamily::Style> transformedSuffixStyles;
transformedWords.reserve(words.size() * 2); std::vector<bool> transformedSuffixContinues;
transformedStyles.reserve(wordStyles.size() * 2); transformedSuffix.reserve((words.size() - suffixStart) * 2);
transformedContinues.reserve(wordContinues.size() * 2); transformedSuffixStyles.reserve(transformedSuffix.capacity());
transformedSuffixContinues.reserve(transformedSuffix.capacity());
for (size_t i = 0; i < words.size(); ++i) { for (size_t i = suffixStart; i < words.size(); ++i) {
std::string source = std::move(words[i]); std::string source = std::move(words[i]);
const auto originalStyle = wordStyles[i]; const auto originalStyle = wordStyles[i];
const bool originalAttachToPrevious = wordContinues[i]; const bool originalAttachToPrevious = wordContinues[i];
@@ -638,29 +649,35 @@ void ParsedText::applyBionicReadingTransform() {
std::string suffix(reinterpret_cast<const char*>(prefixEnd), token.size() - prefixByteCount); std::string suffix(reinterpret_cast<const char*>(prefixEnd), token.size() - prefixByteCount);
token.resize(prefixByteCount); token.resize(prefixByteCount);
const auto boldStyle = static_cast<EpdFontFamily::Style>(originalStyle | EpdFontFamily::BOLD); const auto boldStyle = static_cast<EpdFontFamily::Style>(originalStyle | EpdFontFamily::BOLD);
transformedWords.push_back(std::move(token)); transformedSuffix.push_back(std::move(token));
transformedStyles.push_back(boldStyle); transformedSuffixStyles.push_back(boldStyle);
transformedContinues.push_back(attachToPrevious); transformedSuffixContinues.push_back(attachToPrevious);
transformedWords.push_back(std::move(suffix)); transformedSuffix.push_back(std::move(suffix));
transformedStyles.push_back(originalStyle); transformedSuffixStyles.push_back(originalStyle);
transformedContinues.push_back(true); transformedSuffixContinues.push_back(true);
attachToPrevious = true; attachToPrevious = true;
continue; continue;
} }
} }
} }
transformedWords.push_back(std::move(token)); transformedSuffix.push_back(std::move(token));
transformedStyles.push_back(originalStyle); transformedSuffixStyles.push_back(originalStyle);
transformedContinues.push_back(attachToPrevious); transformedSuffixContinues.push_back(attachToPrevious);
attachToPrevious = true; attachToPrevious = true;
} }
} }
words = std::move(transformedWords); // Replace the (now move-emptied) suffix with the transformed version.
wordStyles = std::move(transformedStyles); words.resize(suffixStart);
wordContinues = std::move(transformedContinues); wordStyles.resize(suffixStart);
wordContinues.resize(suffixStart);
words.insert(words.end(), std::make_move_iterator(transformedSuffix.begin()),
std::make_move_iterator(transformedSuffix.end()));
wordStyles.insert(wordStyles.end(), transformedSuffixStyles.begin(), transformedSuffixStyles.end());
wordContinues.insert(wordContinues.end(), transformedSuffixContinues.begin(), transformedSuffixContinues.end());
bionicTransformedUpTo_ = words.size();
} }
// Builds break indices while opportunistically splitting the word that would overflow the current line. // Builds break indices while opportunistically splitting the word that would overflow the current line.
+2 -1
View File
@@ -27,7 +27,8 @@ class ParsedText {
bool extraParagraphSpacing; bool extraParagraphSpacing;
bool hyphenationEnabled; bool hyphenationEnabled;
bool bionicReadingEnabled; bool bionicReadingEnabled;
bool isContinuation_ = false; ///< true after an intermediate flush; suppresses re-applying indent/transforms bool isContinuation_ = false; ///< true after an intermediate flush; suppresses re-applying paragraph indent
size_t bionicTransformedUpTo_ = 0; ///< words[0..bionicTransformedUpTo_) have already been bionic-transformed
void applyParagraphIndent(); void applyParagraphIndent();
void applyBionicReadingTransform(); void applyBionicReadingTransform();