Deal with stale caches
This commit is contained in:
@@ -832,8 +832,8 @@ void EpubReaderActivity::restoreSavedPosition() {
|
|||||||
|
|
||||||
bool EpubReaderActivity::drawCurrentPageToBuffer(const std::string& filePath, GfxRenderer& renderer) {
|
bool EpubReaderActivity::drawCurrentPageToBuffer(const std::string& filePath, GfxRenderer& renderer) {
|
||||||
auto epub = std::make_shared<Epub>(filePath, "/.crosspoint");
|
auto epub = std::make_shared<Epub>(filePath, "/.crosspoint");
|
||||||
// skip CSS (second arg) since we only need layout/section data
|
// Load CSS when embeddedStyle is enabled, as createSectionFile may need it to rebuild the cache.
|
||||||
if (!epub->load(true, false)) {
|
if (!epub->load(true, SETTINGS.embeddedStyle == 0)) {
|
||||||
LOG_DBG("SLP", "EPUB: failed to load %s", filePath.c_str());
|
LOG_DBG("SLP", "EPUB: failed to load %s", filePath.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -868,13 +868,19 @@ bool EpubReaderActivity::drawCurrentPageToBuffer(const std::string& filePath, Gf
|
|||||||
const uint16_t viewportWidth = renderer.getScreenWidth() - marginLeft - marginRight;
|
const uint16_t viewportWidth = renderer.getScreenWidth() - marginLeft - marginRight;
|
||||||
const uint16_t viewportHeight = renderer.getScreenHeight() - marginTop - marginBottom;
|
const uint16_t viewportHeight = renderer.getScreenHeight() - marginTop - marginBottom;
|
||||||
|
|
||||||
// Load the cached section file (won't rebuild if cache missing — too slow for sleep)
|
// Load or rebuild the section cache. Rebuilding is needed when the cache is missing or stale
|
||||||
|
// (e.g. after a firmware update). A no-op popup callback avoids any UI during sleep preparation.
|
||||||
auto section = std::unique_ptr<Section>(new Section(epub, spineIndex, renderer));
|
auto section = std::unique_ptr<Section>(new Section(epub, spineIndex, renderer));
|
||||||
if (!section->loadSectionFile(SETTINGS.getReaderFontId(), SETTINGS.getReaderLineCompression(),
|
if (!section->loadSectionFile(SETTINGS.getReaderFontId(), SETTINGS.getReaderLineCompression(),
|
||||||
SETTINGS.extraParagraphSpacing, SETTINGS.paragraphAlignment, viewportWidth,
|
SETTINGS.extraParagraphSpacing, SETTINGS.paragraphAlignment, viewportWidth,
|
||||||
viewportHeight, SETTINGS.hyphenationEnabled, SETTINGS.embeddedStyle)) {
|
viewportHeight, SETTINGS.hyphenationEnabled, SETTINGS.embeddedStyle)) {
|
||||||
LOG_DBG("SLP", "EPUB: section cache not found for spine %d", spineIndex);
|
LOG_DBG("SLP", "EPUB: section cache not found for spine %d, rebuilding", spineIndex);
|
||||||
return false;
|
if (!section->createSectionFile(SETTINGS.getReaderFontId(), SETTINGS.getReaderLineCompression(),
|
||||||
|
SETTINGS.extraParagraphSpacing, SETTINGS.paragraphAlignment, viewportWidth,
|
||||||
|
viewportHeight, SETTINGS.hyphenationEnabled, SETTINGS.embeddedStyle, []() {})) {
|
||||||
|
LOG_ERR("SLP", "EPUB: failed to rebuild section cache for spine %d", spineIndex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pageNumber < 0 || pageNumber >= section->pageCount) pageNumber = 0;
|
if (pageNumber < 0 || pageNumber >= section->pageCount) pageNumber = 0;
|
||||||
|
|||||||
@@ -405,12 +405,17 @@ void TxtReaderActivity::renderStatusBar() const {
|
|||||||
void TxtReaderActivity::saveProgress() const {
|
void TxtReaderActivity::saveProgress() const {
|
||||||
FsFile f;
|
FsFile f;
|
||||||
if (Storage.openFileForWrite("TRS", txt->getCachePath() + "/progress.bin", f)) {
|
if (Storage.openFileForWrite("TRS", txt->getCachePath() + "/progress.bin", f)) {
|
||||||
uint8_t data[4];
|
// 6-byte format: page(2 bytes LE) + file offset(4 bytes LE)
|
||||||
|
// The offset lets drawCurrentPageToBuffer render without requiring index.bin.
|
||||||
|
const size_t offset = (currentPage < static_cast<int>(pageOffsets.size())) ? pageOffsets[currentPage] : 0;
|
||||||
|
uint8_t data[6];
|
||||||
data[0] = currentPage & 0xFF;
|
data[0] = currentPage & 0xFF;
|
||||||
data[1] = (currentPage >> 8) & 0xFF;
|
data[1] = (currentPage >> 8) & 0xFF;
|
||||||
data[2] = 0;
|
data[2] = offset & 0xFF;
|
||||||
data[3] = 0;
|
data[3] = (offset >> 8) & 0xFF;
|
||||||
f.write(data, 4);
|
data[4] = (offset >> 16) & 0xFF;
|
||||||
|
data[5] = (offset >> 24) & 0xFF;
|
||||||
|
f.write(data, 6);
|
||||||
f.close();
|
f.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -611,82 +616,79 @@ bool TxtReaderActivity::drawCurrentPageToBuffer(const std::string& filePath, Gfx
|
|||||||
const int lineHeight = renderer.getLineHeight(fontId);
|
const int lineHeight = renderer.getLineHeight(fontId);
|
||||||
const int linesPerPage = std::max(1, vh / lineHeight);
|
const int linesPerPage = std::max(1, vh / lineHeight);
|
||||||
|
|
||||||
// Load the page offset index from cache (must already exist from normal reading)
|
// Step 1: Try to read the saved page and its file offset from progress.bin.
|
||||||
std::string cachePath = txt.getCachePath() + "/index.bin";
|
// The 6-byte format (written by saveProgress) stores: page(2) + offset(4).
|
||||||
FsFile cacheFile;
|
// This lets us skip index.bin entirely, so the overlay works even when the
|
||||||
if (!Storage.openFileForRead("SLP", cachePath, cacheFile)) {
|
// page index cache is missing or stale (e.g. after a firmware update).
|
||||||
LOG_DBG("SLP", "TXT: no page index cache");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t magic;
|
|
||||||
serialization::readPod(cacheFile, magic);
|
|
||||||
if (magic != CACHE_MAGIC) {
|
|
||||||
cacheFile.close();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t version;
|
|
||||||
serialization::readPod(cacheFile, version);
|
|
||||||
if (version != CACHE_VERSION) {
|
|
||||||
cacheFile.close();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t cachedFileSize;
|
|
||||||
serialization::readPod(cacheFile, cachedFileSize);
|
|
||||||
if (cachedFileSize != txt.getFileSize()) {
|
|
||||||
cacheFile.close();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t cachedVw, cachedLpp, cachedFontId, cachedMargin;
|
|
||||||
serialization::readPod(cacheFile, cachedVw);
|
|
||||||
serialization::readPod(cacheFile, cachedLpp);
|
|
||||||
serialization::readPod(cacheFile, cachedFontId);
|
|
||||||
serialization::readPod(cacheFile, cachedMargin);
|
|
||||||
if (cachedVw != vw || cachedLpp != linesPerPage || cachedFontId != fontId || cachedMargin != screenMargin) {
|
|
||||||
LOG_DBG("SLP", "TXT: cache invalid (settings changed)");
|
|
||||||
cacheFile.close();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t cachedAlignment;
|
|
||||||
serialization::readPod(cacheFile, cachedAlignment);
|
|
||||||
if (cachedAlignment != paragraphAlignment) {
|
|
||||||
cacheFile.close();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t numPages;
|
|
||||||
serialization::readPod(cacheFile, numPages);
|
|
||||||
if (numPages == 0 || numPages > MAX_CACHE_PAGES) {
|
|
||||||
cacheFile.close();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load saved page number before reading offsets
|
|
||||||
int savedPage = 0;
|
int savedPage = 0;
|
||||||
FsFile progFile;
|
|
||||||
if (Storage.openFileForRead("SLP", txt.getCachePath() + "/progress.bin", progFile)) {
|
|
||||||
uint8_t data[4];
|
|
||||||
if (progFile.read(data, 4) == 4) {
|
|
||||||
savedPage = (int)((uint32_t)data[0] | ((uint32_t)data[1] << 8));
|
|
||||||
}
|
|
||||||
progFile.close();
|
|
||||||
}
|
|
||||||
if (savedPage < 0 || savedPage >= static_cast<int>(numPages)) savedPage = 0;
|
|
||||||
|
|
||||||
// Read offsets sequentially, retaining only the one we need
|
|
||||||
size_t savedOffset = 0;
|
size_t savedOffset = 0;
|
||||||
for (uint32_t i = 0; i < numPages; i++) {
|
bool offsetKnown = false;
|
||||||
uint32_t off;
|
{
|
||||||
serialization::readPod(cacheFile, off);
|
FsFile progFile;
|
||||||
if (static_cast<int>(i) == savedPage) {
|
if (Storage.openFileForRead("SLP", txt.getCachePath() + "/progress.bin", progFile)) {
|
||||||
savedOffset = off;
|
uint8_t data[6] = {0};
|
||||||
|
const int n = progFile.read(data, 6);
|
||||||
|
progFile.close();
|
||||||
|
if (n >= 2) {
|
||||||
|
savedPage = (int)((uint32_t)data[0] | ((uint32_t)data[1] << 8));
|
||||||
|
}
|
||||||
|
if (n >= 6) {
|
||||||
|
const uint32_t off =
|
||||||
|
(uint32_t)data[2] | ((uint32_t)data[3] << 8) | ((uint32_t)data[4] << 16) | ((uint32_t)data[5] << 24);
|
||||||
|
if (off < txt.getFileSize()) {
|
||||||
|
savedOffset = off;
|
||||||
|
offsetKnown = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 2: If progress.bin didn't provide the offset, fall back to index.bin.
|
||||||
|
if (!offsetKnown) {
|
||||||
|
std::string cachePath = txt.getCachePath() + "/index.bin";
|
||||||
|
FsFile cacheFile;
|
||||||
|
if (Storage.openFileForRead("SLP", cachePath, cacheFile)) {
|
||||||
|
uint32_t magic;
|
||||||
|
serialization::readPod(cacheFile, magic);
|
||||||
|
uint8_t version;
|
||||||
|
serialization::readPod(cacheFile, version);
|
||||||
|
uint32_t cachedFileSize;
|
||||||
|
serialization::readPod(cacheFile, cachedFileSize);
|
||||||
|
int32_t cachedVw, cachedLpp, cachedFontId, cachedMargin;
|
||||||
|
serialization::readPod(cacheFile, cachedVw);
|
||||||
|
serialization::readPod(cacheFile, cachedLpp);
|
||||||
|
serialization::readPod(cacheFile, cachedFontId);
|
||||||
|
serialization::readPod(cacheFile, cachedMargin);
|
||||||
|
uint8_t cachedAlignment;
|
||||||
|
serialization::readPod(cacheFile, cachedAlignment);
|
||||||
|
uint32_t numPages;
|
||||||
|
serialization::readPod(cacheFile, numPages);
|
||||||
|
|
||||||
|
if (magic == CACHE_MAGIC && version == CACHE_VERSION && cachedFileSize == txt.getFileSize() && cachedVw == vw &&
|
||||||
|
cachedLpp == linesPerPage && cachedFontId == fontId && cachedMargin == screenMargin &&
|
||||||
|
cachedAlignment == paragraphAlignment && numPages > 0 && numPages <= MAX_CACHE_PAGES) {
|
||||||
|
if (savedPage < 0 || savedPage >= static_cast<int>(numPages)) savedPage = 0;
|
||||||
|
for (uint32_t i = 0; i < numPages; i++) {
|
||||||
|
uint32_t off;
|
||||||
|
serialization::readPod(cacheFile, off);
|
||||||
|
if (static_cast<int>(i) == savedPage) {
|
||||||
|
savedOffset = off;
|
||||||
|
offsetKnown = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG_DBG("SLP", "TXT: index cache invalid or stale");
|
||||||
|
}
|
||||||
|
cacheFile.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3: No valid cache at all — render from the start of the file as a last resort.
|
||||||
|
// This shows page 1 rather than a blank screen, which is always preferable.
|
||||||
|
if (!offsetKnown) {
|
||||||
|
LOG_DBG("SLP", "TXT: no valid cache, falling back to start of file");
|
||||||
|
savedOffset = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cacheFile.close();
|
|
||||||
|
|
||||||
// Load the page lines from file
|
// Load the page lines from file
|
||||||
std::vector<std::string> pageLines;
|
std::vector<std::string> pageLines;
|
||||||
|
|||||||
Reference in New Issue
Block a user