feat: add multi-spine chapter caching for seamless cross-spine navigation
When loading a section, proactively indexes all spine items belonging to the same TOC chapter so page-turning across spine boundaries within a chapter is instant. Uses Section::readCachedPageCount() to skip already-cached sections and shows an "Indexing (x/y)" progress popup. Ported from upstream PR #1172, adapted to mod architecture. Made-with: Cursor
This commit is contained in:
@@ -892,6 +892,58 @@ bool EpubReaderActivity::silentIndexNextChapterIfNeeded() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void EpubReaderActivity::cacheMultiSpineChapter(const uint16_t vpWidth, const uint16_t vpHeight) {
|
||||
if (!epub || !section) return;
|
||||
|
||||
const int tocCount = epub->getTocItemsCount();
|
||||
if (tocCount == 0) return;
|
||||
|
||||
const int currentTocIdx = section->getTocIndexForPage(section->currentPage);
|
||||
if (currentTocIdx < 0) return;
|
||||
|
||||
const int startSpine = epub->getSpineIndexForTocIndex(currentTocIdx);
|
||||
if (startSpine < 0) return;
|
||||
|
||||
// Chapter ends where the next TOC entry begins on a different spine
|
||||
int endSpine = epub->getSpineItemsCount();
|
||||
for (int t = currentTocIdx + 1; t < tocCount; t++) {
|
||||
const int tSpine = epub->getSpineIndexForTocIndex(t);
|
||||
if (tSpine > startSpine) {
|
||||
endSpine = tSpine;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Collect uncached spines in this chapter
|
||||
std::vector<int> uncached;
|
||||
uncached.reserve(endSpine - startSpine);
|
||||
for (int i = startSpine; i < endSpine; i++) {
|
||||
if (i == currentSpineIndex) continue;
|
||||
auto cached = Section::readCachedPageCount(epub->getCachePath(), i, SETTINGS.getReaderFontId(),
|
||||
SETTINGS.getReaderLineCompression(), SETTINGS.extraParagraphSpacing,
|
||||
SETTINGS.paragraphAlignment, vpWidth, vpHeight,
|
||||
SETTINGS.hyphenationEnabled, SETTINGS.embeddedStyle,
|
||||
SETTINGS.imageRendering);
|
||||
if (!cached) uncached.push_back(i);
|
||||
}
|
||||
|
||||
if (uncached.empty()) return;
|
||||
|
||||
const int total = static_cast<int>(uncached.size());
|
||||
char buf[64];
|
||||
for (int idx = 0; idx < total; idx++) {
|
||||
snprintf(buf, sizeof(buf), "%s (%d/%d)", tr(STR_INDEXING), idx + 1, total);
|
||||
GUI.drawPopup(renderer, buf);
|
||||
|
||||
Section s(epub, uncached[idx], renderer);
|
||||
if (!s.createSectionFile(SETTINGS.getReaderFontId(), SETTINGS.getReaderLineCompression(),
|
||||
SETTINGS.extraParagraphSpacing, SETTINGS.paragraphAlignment, vpWidth, vpHeight,
|
||||
SETTINGS.hyphenationEnabled, SETTINGS.embeddedStyle, SETTINGS.imageRendering)) {
|
||||
LOG_ERR("ERS", "Multi-spine cache failed for spine %d", uncached[idx]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Failure handling
|
||||
void EpubReaderActivity::render(RenderLock&& lock) {
|
||||
if (!epub) {
|
||||
@@ -1011,6 +1063,10 @@ void EpubReaderActivity::render(RenderLock&& lock) {
|
||||
section->currentPage = newPage;
|
||||
pendingPercentJump = false;
|
||||
}
|
||||
|
||||
const uint16_t vpW = renderer.getScreenWidth() - orientedMarginLeft - orientedMarginRight;
|
||||
const uint16_t vpH = renderer.getScreenHeight() - orientedMarginTop - orientedMarginBottom;
|
||||
cacheMultiSpineChapter(vpW, vpH);
|
||||
}
|
||||
|
||||
renderer.clearScreen();
|
||||
|
||||
@@ -40,6 +40,10 @@ class EpubReaderActivity final : public Activity {
|
||||
bool silentIndexingActive = false;
|
||||
bool silentIndexNextChapterIfNeeded();
|
||||
|
||||
// Multi-spine chapter caching: proactively indexes all spine items that belong
|
||||
// to the same TOC chapter so cross-spine page turns are instant.
|
||||
void cacheMultiSpineChapter(uint16_t vpWidth, uint16_t vpHeight);
|
||||
|
||||
// Footnote support
|
||||
std::vector<FootnoteEntry> currentPageFootnotes;
|
||||
struct SavedPosition {
|
||||
|
||||
Reference in New Issue
Block a user