From 528c65a6dbb19c7d0b07e4af9cef760949fd7522 Mon Sep 17 00:00:00 2001 From: jpirnay Date: Tue, 12 May 2026 13:05:34 +0200 Subject: [PATCH] No blank trailing page --- .../Epub/parsers/ChapterHtmlSlimParser.cpp | 19 +++++++++++++++---- lib/Epub/Epub/parsers/ChapterHtmlSlimParser.h | 1 + 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp b/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp index c8139393..a56f4b75 100644 --- a/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp +++ b/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp @@ -245,6 +245,7 @@ bool ChapterHtmlSlimParser::ensureHeapForTextLayout(const char* phase) { LOG_ERR("EHP", "Low heap (%u free, %u max alloc), aborting parse before %s", freeHeap, maxAllocHeap, phase); streamFailed = true; + layoutFailed = true; if (activeParser) { XML_StopParser(activeParser, XML_FALSE); } @@ -1637,6 +1638,7 @@ bool ChapterHtmlSlimParser::setup(const size_t totalInflatedSize) { bytesStreamed = 0; lastReportedProgress = -1; streamFailed = false; + layoutFailed = false; streamStartTimeMs = millis(); // Choose progress granularity by chapter size. Each callback drives a full-screen @@ -1741,11 +1743,13 @@ bool ChapterHtmlSlimParser::finalize() { // success scenario still flushes whatever pages were produced. if (currentTextBlock) { makePages(); - if (!pendingAnchorId.empty()) { - anchorData.push_back({std::move(pendingAnchorId), static_cast(completedPageCount)}); - pendingAnchorId.clear(); + if (!layoutFailed) { + if (!pendingAnchorId.empty()) { + anchorData.push_back({std::move(pendingAnchorId), static_cast(completedPageCount)}); + pendingAnchorId.clear(); + } + emitPage(0u); // post-parse: no byte offset available } - emitPage(0u); // post-parse: no byte offset available currentPage.reset(); currentTextBlock.reset(); } @@ -1793,6 +1797,11 @@ ParsedText::LineProcessResult ChapterHtmlSlimParser::addLineToPage(std::shared_p } void ChapterHtmlSlimParser::makePages() { + if (layoutFailed) { + currentTextBlock.reset(); + return; + } + if (!currentTextBlock) { LOG_ERR("EHP", "!! No text block to make pages for !!"); return; @@ -1824,6 +1833,8 @@ void ChapterHtmlSlimParser::makePages() { (horizontalInset < viewportWidth) ? static_cast(viewportWidth - horizontalInset) : viewportWidth; if (!ensureHeapForTextLayout("paragraph layout")) { + layoutFailed = true; + currentTextBlock.reset(); return; } diff --git a/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.h b/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.h index 85c4608e..60f41e11 100644 --- a/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.h +++ b/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.h @@ -149,6 +149,7 @@ class ChapterHtmlSlimParser final : public Print { std::vector> pendingFootnotes; // int wordsExtractedInBlock = 0; bool bionicReadingEnabled = false; + bool layoutFailed = false; // Per-chapter caches: resolveStyle and parseInlineStyle are called for every HTML element; // caching by (tag|classAttr) and styleAttr avoids repeated string operations and hash lookups.