Compare commits

..

No commits in common. "8e4ce5225cabf1d35942ebb75e7a9489de88769a" and "f41e7496adf6ec066b7258c6440dc340bfaac3a3" have entirely different histories.

5 changed files with 14 additions and 79 deletions

View File

@ -106,18 +106,6 @@ std::vector<size_t> ParsedText::computeLineBreaks(const int pageWidth, const int
ans[i] = j; // j is the index of the last word in this optimal line ans[i] = j; // j is the index of the last word in this optimal line
} }
} }
// Handle oversized word: if no valid configuration found, force single-word line
// This prevents cascade failure where one oversized word breaks all preceding words
if (dp[i] == MAX_COST) {
ans[i] = i; // Just this word on its own line
// Inherit cost from next word to allow subsequent words to find valid configurations
if (i + 1 < static_cast<int>(totalWordCount)) {
dp[i] = dp[i + 1];
} else {
dp[i] = 0;
}
}
} }
// Stores the index of the word that starts the next line (last_word_index + 1) // Stores the index of the word that starts the next line (last_word_index + 1)

View File

@ -115,39 +115,24 @@ bool Section::clearCache() const {
bool Section::persistPageDataToSD(const int fontId, const float lineCompression, const int marginTop, bool Section::persistPageDataToSD(const int fontId, const float lineCompression, const int marginTop,
const int marginRight, const int marginBottom, const int marginLeft, const int marginRight, const int marginBottom, const int marginLeft,
const bool extraParagraphSpacing, const std::function<void()>& progressSetupFn, const bool extraParagraphSpacing, const std::function<void(int)>& progressFn) {
const std::function<void(int)>& progressFn) {
constexpr size_t MIN_SIZE_FOR_PROGRESS = 50 * 1024; // 50KB
const auto localPath = epub->getSpineItem(spineIndex).href; const auto localPath = epub->getSpineItem(spineIndex).href;
const auto tmpHtmlPath = epub->getCachePath() + "/.tmp_" + std::to_string(spineIndex) + ".html"; const auto tmpHtmlPath = epub->getCachePath() + "/.tmp_" + std::to_string(spineIndex) + ".html";
// Retry logic for SD card timing issues // Retry logic for SD card timing issues
bool success = false; bool success = false;
size_t fileSize = 0;
for (int attempt = 0; attempt < 3 && !success; attempt++) { for (int attempt = 0; attempt < 3 && !success; attempt++) {
if (attempt > 0) { if (attempt > 0) {
Serial.printf("[%lu] [SCT] Retrying stream (attempt %d)...\n", millis(), attempt + 1); Serial.printf("[%lu] [SCT] Retrying stream (attempt %d)...\n", millis(), attempt + 1);
delay(50); // Brief delay before retry delay(50); // Brief delay before retry
} }
// Remove any incomplete file from previous attempt before retrying
if (SD.exists(tmpHtmlPath.c_str())) {
SD.remove(tmpHtmlPath.c_str());
}
File tmpHtml; File tmpHtml;
if (!FsHelpers::openFileForWrite("SCT", tmpHtmlPath, tmpHtml)) { if (!FsHelpers::openFileForWrite("SCT", tmpHtmlPath, tmpHtml)) {
continue; continue;
} }
success = epub->readItemContentsToStream(localPath, tmpHtml, 1024); success = epub->readItemContentsToStream(localPath, tmpHtml, 1024);
fileSize = tmpHtml.size();
tmpHtml.close(); tmpHtml.close();
// If streaming failed, remove the incomplete file immediately
if (!success && SD.exists(tmpHtmlPath.c_str())) {
SD.remove(tmpHtmlPath.c_str());
Serial.printf("[%lu] [SCT] Removed incomplete temp file after failed attempt\n", millis());
}
} }
if (!success) { if (!success) {
@ -155,12 +140,7 @@ bool Section::persistPageDataToSD(const int fontId, const float lineCompression,
return false; return false;
} }
Serial.printf("[%lu] [SCT] Streamed temp HTML to %s (%d bytes)\n", millis(), tmpHtmlPath.c_str(), fileSize); Serial.printf("[%lu] [SCT] Streamed temp HTML to %s\n", millis(), tmpHtmlPath.c_str());
// Only show progress bar for larger chapters where rendering overhead is worth it
if (progressSetupFn && fileSize >= MIN_SIZE_FOR_PROGRESS) {
progressSetupFn();
}
ChapterHtmlSlimParser visitor( ChapterHtmlSlimParser visitor(
tmpHtmlPath, renderer, fontId, lineCompression, marginTop, marginRight, marginBottom, marginLeft, tmpHtmlPath, renderer, fontId, lineCompression, marginTop, marginRight, marginBottom, marginLeft,

View File

@ -33,7 +33,6 @@ class Section {
bool clearCache() const; bool clearCache() const;
bool persistPageDataToSD(int fontId, float lineCompression, int marginTop, int marginRight, int marginBottom, bool persistPageDataToSD(int fontId, float lineCompression, int marginTop, int marginRight, int marginBottom,
int marginLeft, bool extraParagraphSpacing, int marginLeft, bool extraParagraphSpacing,
const std::function<void()>& progressSetupFn = nullptr,
const std::function<void(int)>& progressFn = nullptr); const std::function<void(int)>& progressFn = nullptr);
std::unique_ptr<Page> loadPageFromSD() const; std::unique_ptr<Page> loadPageFromSD() const;
}; };

View File

@ -4,18 +4,11 @@
#include <Serialization.h> #include <Serialization.h>
void TextBlock::render(const GfxRenderer& renderer, const int fontId, const int x, const int y) const { void TextBlock::render(const GfxRenderer& renderer, const int fontId, const int x, const int y) const {
// Validate iterator bounds before rendering
if (words.size() != wordXpos.size() || words.size() != wordStyles.size()) {
Serial.printf("[%lu] [TXB] Render skipped: size mismatch (words=%u, xpos=%u, styles=%u)\n", millis(),
(uint32_t)words.size(), (uint32_t)wordXpos.size(), (uint32_t)wordStyles.size());
return;
}
auto wordIt = words.begin(); auto wordIt = words.begin();
auto wordStylesIt = wordStyles.begin(); auto wordStylesIt = wordStyles.begin();
auto wordXposIt = wordXpos.begin(); auto wordXposIt = wordXpos.begin();
for (size_t i = 0; i < words.size(); i++) { for (int i = 0; i < words.size(); i++) {
renderer.drawText(fontId, *wordXposIt + x, y, wordIt->c_str(), true, *wordStylesIt); renderer.drawText(fontId, *wordXposIt + x, y, wordIt->c_str(), true, *wordStylesIt);
std::advance(wordIt, 1); std::advance(wordIt, 1);
@ -53,13 +46,6 @@ std::unique_ptr<TextBlock> TextBlock::deserialize(File& file) {
// words // words
serialization::readPod(file, wc); serialization::readPod(file, wc);
// Sanity check: prevent allocation of unreasonably large lists (max 10000 words per block)
if (wc > 10000) {
Serial.printf("[%lu] [TXB] Deserialization failed: word count %u exceeds maximum\n", millis(), wc);
return nullptr;
}
words.resize(wc); words.resize(wc);
for (auto& w : words) serialization::readString(file, w); for (auto& w : words) serialization::readString(file, w);
@ -73,13 +59,6 @@ std::unique_ptr<TextBlock> TextBlock::deserialize(File& file) {
wordStyles.resize(sc); wordStyles.resize(sc);
for (auto& s : wordStyles) serialization::readPod(file, s); for (auto& s : wordStyles) serialization::readPod(file, s);
// Validate data consistency: all three lists must have the same size
if (wc != xc || wc != sc) {
Serial.printf("[%lu] [TXB] Deserialization failed: size mismatch (words=%u, xpos=%u, styles=%u)\n", millis(), wc,
xc, sc);
return nullptr;
}
// style // style
serialization::readPod(file, style); serialization::readPod(file, style);

View File

@ -224,37 +224,26 @@ void EpubReaderActivity::renderScreen() {
constexpr int barHeight = 10; constexpr int barHeight = 10;
constexpr int boxMargin = 20; constexpr int boxMargin = 20;
const int textWidth = renderer.getTextWidth(READER_FONT_ID, "Indexing..."); const int textWidth = renderer.getTextWidth(READER_FONT_ID, "Indexing...");
const int boxWidthWithBar = (barWidth > textWidth ? barWidth : textWidth) + boxMargin * 2; const int boxWidth = (barWidth > textWidth ? barWidth : textWidth) + boxMargin * 2;
const int boxWidthNoBar = textWidth + boxMargin * 2; const int boxHeight = renderer.getLineHeight(READER_FONT_ID) + barHeight + boxMargin * 3;
const int boxHeightWithBar = renderer.getLineHeight(READER_FONT_ID) + barHeight + boxMargin * 3; const int boxX = (GfxRenderer::getScreenWidth() - boxWidth) / 2;
const int boxHeightNoBar = renderer.getLineHeight(READER_FONT_ID) + boxMargin * 2;
const int boxXWithBar = (GfxRenderer::getScreenWidth() - boxWidthWithBar) / 2;
const int boxXNoBar = (GfxRenderer::getScreenWidth() - boxWidthNoBar) / 2;
constexpr int boxY = 50; constexpr int boxY = 50;
const int barX = boxXWithBar + (boxWidthWithBar - barWidth) / 2; const int barX = boxX + (boxWidth - barWidth) / 2;
const int barY = boxY + renderer.getLineHeight(READER_FONT_ID) + boxMargin * 2; const int barY = boxY + renderer.getLineHeight(READER_FONT_ID) + boxMargin * 2;
// Always show "Indexing..." text first // Draw initial indexing box with 0% progress
{ {
renderer.fillRect(boxXNoBar, boxY, boxWidthNoBar, boxHeightNoBar, false); renderer.fillRect(boxX, boxY, boxWidth, boxHeight, false);
renderer.drawText(READER_FONT_ID, boxXNoBar + boxMargin, boxY + boxMargin, "Indexing..."); renderer.drawText(READER_FONT_ID, boxX + boxMargin, boxY + boxMargin, "Indexing...");
renderer.drawRect(boxXNoBar + 5, boxY + 5, boxWidthNoBar - 10, boxHeightNoBar - 10); renderer.drawRect(boxX + 5, boxY + 5, boxWidth - 10, boxHeight - 10);
// Draw empty progress bar outline
renderer.drawRect(barX, barY, barWidth, barHeight);
renderer.displayBuffer(); renderer.displayBuffer();
pagesUntilFullRefresh = 0; pagesUntilFullRefresh = 0;
} }
section->setupCacheDir(); section->setupCacheDir();
// Setup callback - only called for chapters >= 50KB, redraws with progress bar
auto progressSetup = [this, boxXWithBar, boxWidthWithBar, boxHeightWithBar, boxMargin, barX, barY, barWidth,
barHeight]() {
renderer.fillRect(boxXWithBar, boxY, boxWidthWithBar, boxHeightWithBar, false);
renderer.drawText(READER_FONT_ID, boxXWithBar + boxMargin, boxY + boxMargin, "Indexing...");
renderer.drawRect(boxXWithBar + 5, boxY + 5, boxWidthWithBar - 10, boxHeightWithBar - 10);
renderer.drawRect(barX, barY, barWidth, barHeight);
renderer.displayBuffer();
};
// Progress callback to update progress bar // Progress callback to update progress bar
auto progressCallback = [this, barX, barY, barWidth, barHeight](int progress) { auto progressCallback = [this, barX, barY, barWidth, barHeight](int progress) {
const int fillWidth = (barWidth - 2) * progress / 100; const int fillWidth = (barWidth - 2) * progress / 100;
@ -263,7 +252,7 @@ void EpubReaderActivity::renderScreen() {
}; };
if (!section->persistPageDataToSD(READER_FONT_ID, lineCompression, marginTop, marginRight, marginBottom, if (!section->persistPageDataToSD(READER_FONT_ID, lineCompression, marginTop, marginRight, marginBottom,
marginLeft, SETTINGS.extraParagraphSpacing, progressSetup, progressCallback)) { marginLeft, SETTINGS.extraParagraphSpacing, progressCallback)) {
Serial.printf("[%lu] [ERS] Failed to persist page data to SD\n", millis()); Serial.printf("[%lu] [ERS] Failed to persist page data to SD\n", millis());
section.reset(); section.reset();
return; return;