2026-01-19 06:55:35 -05:00
|
|
|
#pragma once
|
|
|
|
|
#include <Epub.h>
|
|
|
|
|
|
|
|
|
|
#include <memory>
|
|
|
|
|
#include <string>
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* CrossPoint position representation.
|
|
|
|
|
*/
|
|
|
|
|
struct CrossPointPosition {
|
|
|
|
|
int spineIndex; // Current spine item (chapter) index
|
|
|
|
|
int pageNumber; // Current page within the spine item
|
|
|
|
|
int totalPages; // Total pages in the current spine item
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* KOReader position representation.
|
|
|
|
|
*/
|
|
|
|
|
struct KOReaderPosition {
|
|
|
|
|
std::string xpath; // XPath-like progress string
|
|
|
|
|
float percentage; // Progress percentage (0.0 to 1.0)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Maps between CrossPoint and KOReader position formats.
|
|
|
|
|
*
|
|
|
|
|
* CrossPoint tracks position as (spineIndex, pageNumber).
|
|
|
|
|
* KOReader uses XPath-like strings + percentage.
|
|
|
|
|
*
|
2026-03-02 05:19:14 -05:00
|
|
|
* Forward mapping (CrossPoint -> KOReader):
|
|
|
|
|
* - Prefer element-level XPath extracted from current spine XHTML.
|
|
|
|
|
* - Fallback to synthetic chapter XPath if extraction fails.
|
|
|
|
|
*
|
|
|
|
|
* Reverse mapping (KOReader -> CrossPoint):
|
|
|
|
|
* - Prefer incoming XPath (DocFragment + element path) when resolvable.
|
|
|
|
|
* - Fallback to percentage-based approximation when XPath is missing/invalid.
|
|
|
|
|
*
|
|
|
|
|
* This keeps behavior stable on low-memory devices while improving round-trip
|
|
|
|
|
* sync precision when KOReader provides detailed paths.
|
2026-01-19 06:55:35 -05:00
|
|
|
*/
|
|
|
|
|
class ProgressMapper {
|
|
|
|
|
public:
|
|
|
|
|
/**
|
|
|
|
|
* Convert CrossPoint position to KOReader format.
|
|
|
|
|
*
|
|
|
|
|
* @param epub The EPUB book
|
|
|
|
|
* @param pos CrossPoint position
|
|
|
|
|
* @return KOReader position
|
|
|
|
|
*/
|
|
|
|
|
static KOReaderPosition toKOReader(const std::shared_ptr<Epub>& epub, const CrossPointPosition& pos);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Convert KOReader position to CrossPoint format.
|
|
|
|
|
*
|
2026-03-02 05:19:14 -05:00
|
|
|
* Uses XPath-first resolution when possible and percentage fallback otherwise.
|
|
|
|
|
* Returned pageNumber can still be approximate because page counts differ
|
|
|
|
|
* across renderer/font/layout settings.
|
2026-01-19 06:55:35 -05:00
|
|
|
*
|
|
|
|
|
* @param epub The EPUB book
|
|
|
|
|
* @param koPos KOReader position
|
2026-02-19 11:38:46 +01:00
|
|
|
* @param currentSpineIndex Index of the currently open spine item (for density estimation)
|
|
|
|
|
* @param totalPagesInCurrentSpine Total pages in the current spine item (for density estimation)
|
2026-01-19 06:55:35 -05:00
|
|
|
* @return CrossPoint position
|
|
|
|
|
*/
|
|
|
|
|
static CrossPointPosition toCrossPoint(const std::shared_ptr<Epub>& epub, const KOReaderPosition& koPos,
|
2026-02-19 11:38:46 +01:00
|
|
|
int currentSpineIndex = -1, int totalPagesInCurrentSpine = 0);
|
2026-01-19 06:55:35 -05:00
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
/**
|
|
|
|
|
* Generate XPath for KOReader compatibility.
|
2026-03-02 05:19:14 -05:00
|
|
|
* Fallback format: /body/DocFragment[spineIndex + 1]/body
|
2026-01-19 06:55:35 -05:00
|
|
|
*/
|
2026-03-02 05:19:14 -05:00
|
|
|
static std::string generateXPath(int spineIndex);
|
2026-01-19 06:55:35 -05:00
|
|
|
};
|