fix: Switch to xpath map for paragraph level syncing in KOSync (#1686)
Switch KOReader sync progress mapping from chapter matching to XPath-based mapping. - resolves KOReader positions using real XHTML ancestry paths - supports paragraph-based upload mapping with text offsets where needed - passes the current paragraph index into sync so uploads map back to KOReader more accurately No HTTP client changes are included. No reader-state or resume-flow changes are included. --------- Co-authored-by: jpirnay <jens@pirnay.com>
This commit is contained in:
co-authored by
jpirnay
parent
e8645ed92e
commit
302dea1eea
@@ -163,6 +163,10 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char*
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(name, "p") == 0) {
|
||||
self->xpathParagraphIndex++;
|
||||
}
|
||||
|
||||
// Extract class, style, and id attributes
|
||||
std::string classAttr;
|
||||
std::string styleAttr;
|
||||
@@ -428,7 +432,7 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char*
|
||||
// Create page for image - only break if image won't fit remaining space
|
||||
if (self->currentPage && !self->currentPage->elements.empty() &&
|
||||
(self->currentPageNextY + displayHeight > self->viewportHeight)) {
|
||||
self->completePageFn(std::move(self->currentPage));
|
||||
self->completePageFn(std::move(self->currentPage), self->xpathParagraphIndex);
|
||||
self->completedPageCount++;
|
||||
self->currentPage.reset(new Page());
|
||||
if (!self->currentPage) {
|
||||
@@ -1066,7 +1070,7 @@ bool ChapterHtmlSlimParser::parseAndBuildPages() {
|
||||
anchorData.push_back({std::move(pendingAnchorId), static_cast<uint16_t>(completedPageCount)});
|
||||
pendingAnchorId.clear();
|
||||
}
|
||||
completePageFn(std::move(currentPage));
|
||||
completePageFn(std::move(currentPage), xpathParagraphIndex);
|
||||
completedPageCount++;
|
||||
currentPage.reset();
|
||||
currentTextBlock.reset();
|
||||
@@ -1084,7 +1088,7 @@ void ChapterHtmlSlimParser::addLineToPage(std::shared_ptr<TextBlock> line) {
|
||||
}
|
||||
|
||||
if (currentPageNextY + lineHeight > viewportHeight) {
|
||||
completePageFn(std::move(currentPage));
|
||||
completePageFn(std::move(currentPage), xpathParagraphIndex);
|
||||
completedPageCount++;
|
||||
currentPage.reset(new Page());
|
||||
currentPageNextY = 0;
|
||||
|
||||
@@ -25,7 +25,7 @@ class ChapterHtmlSlimParser {
|
||||
std::shared_ptr<Epub> epub;
|
||||
const std::string& filepath;
|
||||
GfxRenderer& renderer;
|
||||
std::function<void(std::unique_ptr<Page>)> completePageFn;
|
||||
std::function<void(std::unique_ptr<Page>, uint16_t)> completePageFn;
|
||||
std::function<void()> popupFn; // Popup callback
|
||||
int depth = 0;
|
||||
int skipUntilDepth = INT_MAX;
|
||||
@@ -74,6 +74,7 @@ class ChapterHtmlSlimParser {
|
||||
int completedPageCount = 0;
|
||||
std::vector<std::pair<std::string, uint16_t>> anchorData;
|
||||
std::string pendingAnchorId; // deferred until after previous text block is flushed
|
||||
uint16_t xpathParagraphIndex = 0;
|
||||
|
||||
// Footnote link tracking
|
||||
bool insideFootnoteLink = false;
|
||||
@@ -99,7 +100,7 @@ class ChapterHtmlSlimParser {
|
||||
const int fontId, const float lineCompression, const bool extraParagraphSpacing,
|
||||
const uint8_t paragraphAlignment, const uint16_t viewportWidth,
|
||||
const uint16_t viewportHeight, const bool hyphenationEnabled,
|
||||
const std::function<void(std::unique_ptr<Page>)>& completePageFn,
|
||||
const std::function<void(std::unique_ptr<Page>, uint16_t)>& completePageFn,
|
||||
const bool embeddedStyle, const std::string& contentBase,
|
||||
const std::string& imageBasePath, const uint8_t imageRendering = 0,
|
||||
const std::function<void()>& popupFn = nullptr, const CssParser* cssParser = nullptr)
|
||||
|
||||
Reference in New Issue
Block a user