diff --git a/lib/Epub/Epub/Page.cpp b/lib/Epub/Epub/Page.cpp index b41dd3c..15e50d0 100644 --- a/lib/Epub/Epub/Page.cpp +++ b/lib/Epub/Epub/Page.cpp @@ -7,7 +7,9 @@ namespace { constexpr uint8_t PAGE_FILE_VERSION = 3; } -void PageLine::render(GfxRenderer& renderer, const int fontId) { block->render(renderer, fontId, xPos, yPos); } +void PageLine::render(GfxRenderer& renderer, const int fontId, const int xOffset, const int yOffset) { + block->render(renderer, fontId, xPos + xOffset, yPos + yOffset); +} void PageLine::serialize(File& file) { serialization::writePod(file, xPos); @@ -27,9 +29,9 @@ std::unique_ptr PageLine::deserialize(File& file) { return std::unique_ptr(new PageLine(std::move(tb), xPos, yPos)); } -void Page::render(GfxRenderer& renderer, const int fontId) const { +void Page::render(GfxRenderer& renderer, const int fontId, const int xOffset, const int yOffset) const { for (auto& element : elements) { - element->render(renderer, fontId); + element->render(renderer, fontId, xOffset, yOffset); } } diff --git a/lib/Epub/Epub/Page.h b/lib/Epub/Epub/Page.h index 1026653..f43e498 100644 --- a/lib/Epub/Epub/Page.h +++ b/lib/Epub/Epub/Page.h @@ -17,7 +17,7 @@ class PageElement { int16_t yPos; explicit PageElement(const int16_t xPos, const int16_t yPos) : xPos(xPos), yPos(yPos) {} virtual ~PageElement() = default; - virtual void render(GfxRenderer& renderer, int fontId) = 0; + virtual void render(GfxRenderer& renderer, int fontId, int xOffset, int yOffset) = 0; virtual void serialize(File& file) = 0; }; @@ -28,7 +28,7 @@ class PageLine final : public PageElement { public: PageLine(std::shared_ptr block, const int16_t xPos, const int16_t yPos) : PageElement(xPos, yPos), block(std::move(block)) {} - void render(GfxRenderer& renderer, int fontId) override; + void render(GfxRenderer& renderer, int fontId, int xOffset, int yOffset) override; void serialize(File& file) override; static std::unique_ptr deserialize(File& file); }; @@ -37,7 +37,7 @@ class Page { public: // the list of block index and line numbers on this page std::vector> elements; - void render(GfxRenderer& renderer, int fontId) const; + void render(GfxRenderer& renderer, int fontId, int xOffset, int yOffset) const; void serialize(File& file) const; static std::unique_ptr deserialize(File& file); }; diff --git a/lib/Epub/Epub/ParsedText.cpp b/lib/Epub/Epub/ParsedText.cpp index 7a045d5..0e850f3 100644 --- a/lib/Epub/Epub/ParsedText.cpp +++ b/lib/Epub/Epub/ParsedText.cpp @@ -18,14 +18,14 @@ void ParsedText::addWord(std::string word, const EpdFontStyle fontStyle) { } // Consumes data to minimize memory usage -void ParsedText::layoutAndExtractLines(const GfxRenderer& renderer, const int fontId, const int horizontalMargin, +void ParsedText::layoutAndExtractLines(const GfxRenderer& renderer, const int fontId, const int viewportWidth, const std::function)>& processLine, const bool includeLastLine) { if (words.empty()) { return; } - const int pageWidth = renderer.getScreenWidth() - horizontalMargin; + const int pageWidth = viewportWidth; const int spaceWidth = renderer.getSpaceWidth(fontId); const auto wordWidths = calculateWordWidths(renderer, fontId); const auto lineBreakIndices = computeLineBreaks(pageWidth, spaceWidth, wordWidths); diff --git a/lib/Epub/Epub/ParsedText.h b/lib/Epub/Epub/ParsedText.h index 7fdb128..2696407 100644 --- a/lib/Epub/Epub/ParsedText.h +++ b/lib/Epub/Epub/ParsedText.h @@ -34,7 +34,7 @@ class ParsedText { TextBlock::BLOCK_STYLE getStyle() const { return style; } size_t size() const { return words.size(); } bool isEmpty() const { return words.empty(); } - void layoutAndExtractLines(const GfxRenderer& renderer, int fontId, int horizontalMargin, + void layoutAndExtractLines(const GfxRenderer& renderer, int fontId, int viewportWidth, const std::function)>& processLine, bool includeLastLine = true); }; diff --git a/lib/Epub/Epub/Section.cpp b/lib/Epub/Epub/Section.cpp index 18de3d8..7b81579 100644 --- a/lib/Epub/Epub/Section.cpp +++ b/lib/Epub/Epub/Section.cpp @@ -26,10 +26,8 @@ void Section::onPageComplete(std::unique_ptr page) { pageCount++; } -void Section::writeCacheMetadata(const int fontId, const float lineCompression, const int marginTop, - const int marginRight, const int marginBottom, const int marginLeft, - const bool extraParagraphSpacing, const int screenWidth, - const int screenHeight) const { +void Section::writeCacheMetadata(const int fontId, const float lineCompression, const bool extraParagraphSpacing, + const int viewportWidth, const int viewportHeight) const { File outputFile; if (!FsHelpers::openFileForWrite("SCT", cachePath + "/section.bin", outputFile)) { return; @@ -37,20 +35,15 @@ void Section::writeCacheMetadata(const int fontId, const float lineCompression, serialization::writePod(outputFile, SECTION_FILE_VERSION); serialization::writePod(outputFile, fontId); serialization::writePod(outputFile, lineCompression); - serialization::writePod(outputFile, marginTop); - serialization::writePod(outputFile, marginRight); - serialization::writePod(outputFile, marginBottom); - serialization::writePod(outputFile, marginLeft); serialization::writePod(outputFile, extraParagraphSpacing); - serialization::writePod(outputFile, screenWidth); - serialization::writePod(outputFile, screenHeight); + serialization::writePod(outputFile, viewportWidth); + serialization::writePod(outputFile, viewportHeight); serialization::writePod(outputFile, pageCount); outputFile.close(); } -bool Section::loadCacheMetadata(const int fontId, const float lineCompression, const int marginTop, - const int marginRight, const int marginBottom, const int marginLeft, - const bool extraParagraphSpacing, const int screenWidth, const int screenHeight) { +bool Section::loadCacheMetadata(const int fontId, const float lineCompression, const bool extraParagraphSpacing, + const int viewportWidth, const int viewportHeight) { const auto sectionFilePath = cachePath + "/section.bin"; File inputFile; if (!FsHelpers::openFileForRead("SCT", sectionFilePath, inputFile)) { @@ -68,24 +61,18 @@ bool Section::loadCacheMetadata(const int fontId, const float lineCompression, c return false; } - int fileFontId, fileMarginTop, fileMarginRight, fileMarginBottom, fileMarginLeft; + int fileFontId, fileViewportWidth, fileViewportHeight; float fileLineCompression; bool fileExtraParagraphSpacing; - int fileScreenWidth, fileScreenHeight; serialization::readPod(inputFile, fileFontId); serialization::readPod(inputFile, fileLineCompression); - serialization::readPod(inputFile, fileMarginTop); - serialization::readPod(inputFile, fileMarginRight); - serialization::readPod(inputFile, fileMarginBottom); - serialization::readPod(inputFile, fileMarginLeft); serialization::readPod(inputFile, fileExtraParagraphSpacing); - serialization::readPod(inputFile, fileScreenWidth); - serialization::readPod(inputFile, fileScreenHeight); + serialization::readPod(inputFile, fileViewportWidth); + serialization::readPod(inputFile, fileViewportHeight); - if (fontId != fileFontId || lineCompression != fileLineCompression || marginTop != fileMarginTop || - marginRight != fileMarginRight || marginBottom != fileMarginBottom || marginLeft != fileMarginLeft || - extraParagraphSpacing != fileExtraParagraphSpacing || screenWidth != fileScreenWidth || - screenHeight != fileScreenHeight) { + if (fontId != fileFontId || lineCompression != fileLineCompression || + extraParagraphSpacing != fileExtraParagraphSpacing || viewportWidth != fileViewportWidth || + viewportHeight != fileViewportHeight) { inputFile.close(); Serial.printf("[%lu] [SCT] Deserialization failed: Parameters do not match\n", millis()); clearCache(); @@ -120,9 +107,8 @@ bool Section::clearCache() const { return true; } -bool Section::persistPageDataToSD(const int fontId, const float lineCompression, const int marginTop, - const int marginRight, const int marginBottom, const int marginLeft, - const bool extraParagraphSpacing, const int screenWidth, const int screenHeight, +bool Section::persistPageDataToSD(const int fontId, const float lineCompression, const bool extraParagraphSpacing, + const int viewportWidth, const int viewportHeight, const std::function& progressSetupFn, const std::function& progressFn) { constexpr size_t MIN_SIZE_FOR_PROGRESS = 50 * 1024; // 50KB @@ -171,8 +157,8 @@ bool Section::persistPageDataToSD(const int fontId, const float lineCompression, } ChapterHtmlSlimParser visitor( - tmpHtmlPath, renderer, fontId, lineCompression, marginTop, marginRight, marginBottom, marginLeft, - extraParagraphSpacing, [this](std::unique_ptr page) { this->onPageComplete(std::move(page)); }, progressFn); + tmpHtmlPath, renderer, fontId, lineCompression, extraParagraphSpacing, viewportWidth, viewportHeight, + [this](std::unique_ptr page) { this->onPageComplete(std::move(page)); }, progressFn); success = visitor.parseAndBuildPages(); SD.remove(tmpHtmlPath.c_str()); @@ -181,8 +167,7 @@ bool Section::persistPageDataToSD(const int fontId, const float lineCompression, return false; } - writeCacheMetadata(fontId, lineCompression, marginTop, marginRight, marginBottom, marginLeft, extraParagraphSpacing, - screenWidth, screenHeight); + writeCacheMetadata(fontId, lineCompression, extraParagraphSpacing, viewportWidth, viewportHeight); return true; } diff --git a/lib/Epub/Epub/Section.h b/lib/Epub/Epub/Section.h index 77f4c73..a1a6216 100644 --- a/lib/Epub/Epub/Section.h +++ b/lib/Epub/Epub/Section.h @@ -13,8 +13,8 @@ class Section { GfxRenderer& renderer; std::string cachePath; - void writeCacheMetadata(int fontId, float lineCompression, int marginTop, int marginRight, int marginBottom, - int marginLeft, bool extraParagraphSpacing, int screenWidth, int screenHeight) const; + void writeCacheMetadata(int fontId, float lineCompression, bool extraParagraphSpacing, int viewportWidth, + int viewportHeight) const; void onPageComplete(std::unique_ptr page); public: @@ -27,13 +27,12 @@ class Section { renderer(renderer), cachePath(epub->getCachePath() + "/" + std::to_string(spineIndex)) {} ~Section() = default; - bool loadCacheMetadata(int fontId, float lineCompression, int marginTop, int marginRight, int marginBottom, - int marginLeft, bool extraParagraphSpacing, int screenWidth, int screenHeight); + bool loadCacheMetadata(int fontId, float lineCompression, bool extraParagraphSpacing, int viewportWidth, + int viewportHeight); void setupCacheDir() const; bool clearCache() const; - bool persistPageDataToSD(int fontId, float lineCompression, int marginTop, int marginRight, int marginBottom, - int marginLeft, bool extraParagraphSpacing, int screenWidth, int screenHeight, - const std::function& progressSetupFn = nullptr, + bool persistPageDataToSD(int fontId, float lineCompression, bool extraParagraphSpacing, int viewportWidth, + int viewportHeight, const std::function& progressSetupFn = nullptr, const std::function& progressFn = nullptr); std::unique_ptr loadPageFromSD() const; }; diff --git a/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp b/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp index bb29ff1..b2dc2c0 100644 --- a/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp +++ b/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp @@ -155,7 +155,7 @@ void XMLCALL ChapterHtmlSlimParser::characterData(void* userData, const XML_Char if (self->currentTextBlock->size() > 750) { Serial.printf("[%lu] [EHP] Text block too long, splitting into multiple pages\n", millis()); self->currentTextBlock->layoutAndExtractLines( - self->renderer, self->fontId, self->marginLeft + self->marginRight, + self->renderer, self->fontId, self->viewportWidth, [self](const std::shared_ptr& textBlock) { self->addLineToPage(textBlock); }, false); } } @@ -301,15 +301,14 @@ bool ChapterHtmlSlimParser::parseAndBuildPages() { void ChapterHtmlSlimParser::addLineToPage(std::shared_ptr line) { const int lineHeight = renderer.getLineHeight(fontId) * lineCompression; - const int pageHeight = renderer.getScreenHeight() - marginTop - marginBottom; - if (currentPageNextY + lineHeight > pageHeight) { + if (currentPageNextY + lineHeight > viewportHeight) { completePageFn(std::move(currentPage)); currentPage.reset(new Page()); - currentPageNextY = marginTop; + currentPageNextY = 0; } - currentPage->elements.push_back(std::make_shared(line, marginLeft, currentPageNextY)); + currentPage->elements.push_back(std::make_shared(line, 0, currentPageNextY)); currentPageNextY += lineHeight; } @@ -321,12 +320,12 @@ void ChapterHtmlSlimParser::makePages() { if (!currentPage) { currentPage.reset(new Page()); - currentPageNextY = marginTop; + currentPageNextY = 0; } const int lineHeight = renderer.getLineHeight(fontId) * lineCompression; currentTextBlock->layoutAndExtractLines( - renderer, fontId, marginLeft + marginRight, + renderer, fontId, viewportWidth, [this](const std::shared_ptr& textBlock) { addLineToPage(textBlock); }); // Extra paragraph spacing if enabled if (extraParagraphSpacing) { diff --git a/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.h b/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.h index 7d75317..53bbbb4 100644 --- a/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.h +++ b/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.h @@ -32,11 +32,9 @@ class ChapterHtmlSlimParser { int16_t currentPageNextY = 0; int fontId; float lineCompression; - int marginTop; - int marginRight; - int marginBottom; - int marginLeft; bool extraParagraphSpacing; + int viewportWidth; + int viewportHeight; void startNewTextBlock(TextBlock::BLOCK_STYLE style); void makePages(); @@ -47,19 +45,17 @@ class ChapterHtmlSlimParser { public: explicit ChapterHtmlSlimParser(const std::string& filepath, GfxRenderer& renderer, const int fontId, - const float lineCompression, const int marginTop, const int marginRight, - const int marginBottom, const int marginLeft, const bool extraParagraphSpacing, + const float lineCompression, const bool extraParagraphSpacing, const int viewportWidth, + const int viewportHeight, const std::function)>& completePageFn, const std::function& progressFn = nullptr) : filepath(filepath), renderer(renderer), fontId(fontId), lineCompression(lineCompression), - marginTop(marginTop), - marginRight(marginRight), - marginBottom(marginBottom), - marginLeft(marginLeft), extraParagraphSpacing(extraParagraphSpacing), + viewportWidth(viewportWidth), + viewportHeight(viewportHeight), completePageFn(completePageFn), progressFn(progressFn) {} ~ChapterHtmlSlimParser() = default; diff --git a/lib/GfxRenderer/GfxRenderer.h b/lib/GfxRenderer/GfxRenderer.h index a724e78..8199fbf 100644 --- a/lib/GfxRenderer/GfxRenderer.h +++ b/lib/GfxRenderer/GfxRenderer.h @@ -36,7 +36,7 @@ class GfxRenderer { void renderChar(const EpdFontFamily& fontFamily, uint32_t cp, int* x, const int* y, bool pixelState, EpdFontStyle style) const; void freeBwBufferChunks(); - void rotateCoordinates(int x, int y, int *rotatedX, int *rotatedY) const; + void rotateCoordinates(int x, int y, int* rotatedX, int* rotatedY) const; public: explicit GfxRenderer(EInkDisplay& einkDisplay) : einkDisplay(einkDisplay), renderMode(BW) {} diff --git a/src/activities/reader/EpubReaderActivity.cpp b/src/activities/reader/EpubReaderActivity.cpp index 87dfe79..efc18e0 100644 --- a/src/activities/reader/EpubReaderActivity.cpp +++ b/src/activities/reader/EpubReaderActivity.cpp @@ -244,9 +244,12 @@ void EpubReaderActivity::renderScreen() { const auto filepath = epub->getSpineItem(currentSpineIndex).href; Serial.printf("[%lu] [ERS] Loading file: %s, index: %d\n", millis(), filepath.c_str(), currentSpineIndex); section = std::unique_ptr
(new Section(epub, currentSpineIndex, renderer)); - if (!section->loadCacheMetadata(READER_FONT_ID, lineCompression, marginTop, marginRight, marginBottom, marginLeft, - SETTINGS.extraParagraphSpacing, renderer.getScreenWidth(), - renderer.getScreenHeight())) { + + const auto viewportWidth = renderer.getScreenWidth() - marginLeft - marginRight; + const auto viewportHeight = renderer.getScreenHeight() - marginTop - marginBottom; + + if (!section->loadCacheMetadata(READER_FONT_ID, lineCompression, SETTINGS.extraParagraphSpacing, viewportWidth, + viewportHeight)) { Serial.printf("[%lu] [ERS] Cache not found, building...\n", millis()); // Progress bar dimensions @@ -292,9 +295,8 @@ void EpubReaderActivity::renderScreen() { renderer.displayBuffer(EInkDisplay::FAST_REFRESH); }; - if (!section->persistPageDataToSD(READER_FONT_ID, lineCompression, marginTop, marginRight, marginBottom, - marginLeft, SETTINGS.extraParagraphSpacing, renderer.getScreenWidth(), - renderer.getScreenHeight(), progressSetup, progressCallback)) { + if (!section->persistPageDataToSD(READER_FONT_ID, lineCompression, SETTINGS.extraParagraphSpacing, viewportWidth, + viewportHeight, progressSetup, progressCallback)) { Serial.printf("[%lu] [ERS] Failed to persist page data to SD\n", millis()); section.reset(); return; @@ -354,7 +356,7 @@ void EpubReaderActivity::renderScreen() { } void EpubReaderActivity::renderContents(std::unique_ptr page) { - page->render(renderer, READER_FONT_ID); + page->render(renderer, READER_FONT_ID, marginLeft, marginTop); renderStatusBar(); if (pagesUntilFullRefresh <= 1) { renderer.displayBuffer(EInkDisplay::HALF_REFRESH); @@ -372,13 +374,13 @@ void EpubReaderActivity::renderContents(std::unique_ptr page) { { renderer.clearScreen(0x00); renderer.setRenderMode(GfxRenderer::GRAYSCALE_LSB); - page->render(renderer, READER_FONT_ID); + page->render(renderer, READER_FONT_ID, marginLeft, marginTop); renderer.copyGrayscaleLsbBuffers(); // Render and copy to MSB buffer renderer.clearScreen(0x00); renderer.setRenderMode(GfxRenderer::GRAYSCALE_MSB); - page->render(renderer, READER_FONT_ID); + page->render(renderer, READER_FONT_ID, marginLeft, marginTop); renderer.copyGrayscaleMsbBuffers(); // display grayscale part