mirror of
https://github.com/daveallie/crosspoint-reader.git
synced 2026-02-06 15:47:39 +03:00
Address PR review feedback for TXT reader
- Add font ID to cache header for invalidation when font changes - Use serialization module for consistent cache read/write - Add screenMargin setting and read padding from settings - Implement grayscale rendering pass for anti-aliased fonts - Add text alignment support (left, center, right, justified) - Bump cache version to invalidate old caches
This commit is contained in:
parent
2072741a59
commit
f885efeeb9
@ -12,7 +12,7 @@ CrossPointSettings CrossPointSettings::instance;
|
|||||||
namespace {
|
namespace {
|
||||||
constexpr uint8_t SETTINGS_FILE_VERSION = 1;
|
constexpr uint8_t SETTINGS_FILE_VERSION = 1;
|
||||||
// Increment this when adding new persisted settings fields
|
// Increment this when adding new persisted settings fields
|
||||||
constexpr uint8_t SETTINGS_COUNT = 13;
|
constexpr uint8_t SETTINGS_COUNT = 14;
|
||||||
constexpr char SETTINGS_FILE[] = "/.crosspoint/settings.bin";
|
constexpr char SETTINGS_FILE[] = "/.crosspoint/settings.bin";
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@ -40,6 +40,7 @@ bool CrossPointSettings::saveToFile() const {
|
|||||||
serialization::writePod(outputFile, paragraphAlignment);
|
serialization::writePod(outputFile, paragraphAlignment);
|
||||||
serialization::writePod(outputFile, sleepTimeout);
|
serialization::writePod(outputFile, sleepTimeout);
|
||||||
serialization::writePod(outputFile, refreshFrequency);
|
serialization::writePod(outputFile, refreshFrequency);
|
||||||
|
serialization::writePod(outputFile, screenMargin);
|
||||||
outputFile.close();
|
outputFile.close();
|
||||||
|
|
||||||
Serial.printf("[%lu] [CPS] Settings saved to file\n", millis());
|
Serial.printf("[%lu] [CPS] Settings saved to file\n", millis());
|
||||||
@ -92,6 +93,8 @@ bool CrossPointSettings::loadFromFile() {
|
|||||||
if (++settingsRead >= fileSettingsCount) break;
|
if (++settingsRead >= fileSettingsCount) break;
|
||||||
serialization::readPod(inputFile, refreshFrequency);
|
serialization::readPod(inputFile, refreshFrequency);
|
||||||
if (++settingsRead >= fileSettingsCount) break;
|
if (++settingsRead >= fileSettingsCount) break;
|
||||||
|
serialization::readPod(inputFile, screenMargin);
|
||||||
|
if (++settingsRead >= fileSettingsCount) break;
|
||||||
} while (false);
|
} while (false);
|
||||||
|
|
||||||
inputFile.close();
|
inputFile.close();
|
||||||
@ -167,6 +170,22 @@ int CrossPointSettings::getRefreshFrequency() const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int CrossPointSettings::getScreenMargin() const {
|
||||||
|
switch (screenMargin) {
|
||||||
|
case MARGIN_0:
|
||||||
|
return 0;
|
||||||
|
case MARGIN_5:
|
||||||
|
default:
|
||||||
|
return 5;
|
||||||
|
case MARGIN_10:
|
||||||
|
return 10;
|
||||||
|
case MARGIN_15:
|
||||||
|
return 15;
|
||||||
|
case MARGIN_20:
|
||||||
|
return 20;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int CrossPointSettings::getReaderFontId() const {
|
int CrossPointSettings::getReaderFontId() const {
|
||||||
switch (fontFamily) {
|
switch (fontFamily) {
|
||||||
case BOOKERLY:
|
case BOOKERLY:
|
||||||
|
|||||||
@ -51,6 +51,9 @@ class CrossPointSettings {
|
|||||||
// E-ink refresh frequency (pages between full refreshes)
|
// E-ink refresh frequency (pages between full refreshes)
|
||||||
enum REFRESH_FREQUENCY { REFRESH_1 = 0, REFRESH_5 = 1, REFRESH_10 = 2, REFRESH_15 = 3, REFRESH_30 = 4 };
|
enum REFRESH_FREQUENCY { REFRESH_1 = 0, REFRESH_5 = 1, REFRESH_10 = 2, REFRESH_15 = 3, REFRESH_30 = 4 };
|
||||||
|
|
||||||
|
// Screen margin options
|
||||||
|
enum SCREEN_MARGIN { MARGIN_0 = 0, MARGIN_5 = 1, MARGIN_10 = 2, MARGIN_15 = 3, MARGIN_20 = 4 };
|
||||||
|
|
||||||
// Sleep screen settings
|
// Sleep screen settings
|
||||||
uint8_t sleepScreen = DARK;
|
uint8_t sleepScreen = DARK;
|
||||||
// Status bar settings
|
// Status bar settings
|
||||||
@ -74,6 +77,8 @@ class CrossPointSettings {
|
|||||||
uint8_t sleepTimeout = SLEEP_10_MIN;
|
uint8_t sleepTimeout = SLEEP_10_MIN;
|
||||||
// E-ink refresh frequency (default 15 pages)
|
// E-ink refresh frequency (default 15 pages)
|
||||||
uint8_t refreshFrequency = REFRESH_15;
|
uint8_t refreshFrequency = REFRESH_15;
|
||||||
|
// Screen margin setting (default 5px)
|
||||||
|
uint8_t screenMargin = MARGIN_5;
|
||||||
|
|
||||||
~CrossPointSettings() = default;
|
~CrossPointSettings() = default;
|
||||||
|
|
||||||
@ -89,6 +94,7 @@ class CrossPointSettings {
|
|||||||
float getReaderLineCompression() const;
|
float getReaderLineCompression() const;
|
||||||
unsigned long getSleepTimeoutMs() const;
|
unsigned long getSleepTimeoutMs() const;
|
||||||
int getRefreshFrequency() const;
|
int getRefreshFrequency() const;
|
||||||
|
int getScreenMargin() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Helper macro to access settings
|
// Helper macro to access settings
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <GfxRenderer.h>
|
#include <GfxRenderer.h>
|
||||||
#include <SDCardManager.h>
|
#include <SDCardManager.h>
|
||||||
|
#include <Serialization.h>
|
||||||
#include <Utf8.h>
|
#include <Utf8.h>
|
||||||
|
|
||||||
#include "CrossPointSettings.h"
|
#include "CrossPointSettings.h"
|
||||||
@ -12,10 +13,12 @@
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
constexpr unsigned long goHomeMs = 1000;
|
constexpr unsigned long goHomeMs = 1000;
|
||||||
constexpr int topPadding = 10;
|
|
||||||
constexpr int horizontalPadding = 15;
|
|
||||||
constexpr int statusBarMargin = 25;
|
constexpr int statusBarMargin = 25;
|
||||||
constexpr size_t CHUNK_SIZE = 8 * 1024; // 8KB chunk for reading
|
constexpr size_t CHUNK_SIZE = 8 * 1024; // 8KB chunk for reading
|
||||||
|
|
||||||
|
// Cache file magic and version
|
||||||
|
constexpr uint32_t CACHE_MAGIC = 0x54585449; // "TXTI"
|
||||||
|
constexpr uint8_t CACHE_VERSION = 2; // Increment when cache format changes
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void TxtReaderActivity::taskTrampoline(void* param) {
|
void TxtReaderActivity::taskTrampoline(void* param) {
|
||||||
@ -139,18 +142,23 @@ void TxtReaderActivity::initializeReader() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Store current settings for cache validation
|
||||||
|
cachedFontId = SETTINGS.getReaderFontId();
|
||||||
|
cachedScreenMargin = SETTINGS.getScreenMargin();
|
||||||
|
cachedParagraphAlignment = SETTINGS.paragraphAlignment;
|
||||||
|
|
||||||
// Calculate viewport dimensions
|
// Calculate viewport dimensions
|
||||||
int orientedMarginTop, orientedMarginRight, orientedMarginBottom, orientedMarginLeft;
|
int orientedMarginTop, orientedMarginRight, orientedMarginBottom, orientedMarginLeft;
|
||||||
renderer.getOrientedViewableTRBL(&orientedMarginTop, &orientedMarginRight, &orientedMarginBottom,
|
renderer.getOrientedViewableTRBL(&orientedMarginTop, &orientedMarginRight, &orientedMarginBottom,
|
||||||
&orientedMarginLeft);
|
&orientedMarginLeft);
|
||||||
orientedMarginTop += topPadding;
|
orientedMarginTop += cachedScreenMargin;
|
||||||
orientedMarginLeft += horizontalPadding;
|
orientedMarginLeft += cachedScreenMargin;
|
||||||
orientedMarginRight += horizontalPadding;
|
orientedMarginRight += cachedScreenMargin;
|
||||||
orientedMarginBottom += statusBarMargin;
|
orientedMarginBottom += statusBarMargin;
|
||||||
|
|
||||||
viewportWidth = renderer.getScreenWidth() - orientedMarginLeft - orientedMarginRight;
|
viewportWidth = renderer.getScreenWidth() - orientedMarginLeft - orientedMarginRight;
|
||||||
const int viewportHeight = renderer.getScreenHeight() - orientedMarginTop - orientedMarginBottom;
|
const int viewportHeight = renderer.getScreenHeight() - orientedMarginTop - orientedMarginBottom;
|
||||||
const int lineHeight = renderer.getLineHeight(SETTINGS.getReaderFontId());
|
const int lineHeight = renderer.getLineHeight(cachedFontId);
|
||||||
|
|
||||||
linesPerPage = viewportHeight / lineHeight;
|
linesPerPage = viewportHeight / lineHeight;
|
||||||
if (linesPerPage < 1) linesPerPage = 1;
|
if (linesPerPage < 1) linesPerPage = 1;
|
||||||
@ -291,7 +299,7 @@ bool TxtReaderActivity::loadPageAtOffset(size_t offset, std::vector<std::string>
|
|||||||
|
|
||||||
// Word wrap if needed
|
// Word wrap if needed
|
||||||
while (!line.empty() && static_cast<int>(outLines.size()) < linesPerPage) {
|
while (!line.empty() && static_cast<int>(outLines.size()) < linesPerPage) {
|
||||||
int lineWidth = renderer.getTextWidth(SETTINGS.getReaderFontId(), line.c_str());
|
int lineWidth = renderer.getTextWidth(cachedFontId, line.c_str());
|
||||||
|
|
||||||
if (lineWidth <= viewportWidth) {
|
if (lineWidth <= viewportWidth) {
|
||||||
outLines.push_back(line);
|
outLines.push_back(line);
|
||||||
@ -301,7 +309,7 @@ bool TxtReaderActivity::loadPageAtOffset(size_t offset, std::vector<std::string>
|
|||||||
// Find break point
|
// Find break point
|
||||||
size_t breakPos = line.length();
|
size_t breakPos = line.length();
|
||||||
while (breakPos > 0 &&
|
while (breakPos > 0 &&
|
||||||
renderer.getTextWidth(SETTINGS.getReaderFontId(), line.substr(0, breakPos).c_str()) > viewportWidth) {
|
renderer.getTextWidth(cachedFontId, line.substr(0, breakPos).c_str()) > viewportWidth) {
|
||||||
// Try to break at space
|
// Try to break at space
|
||||||
size_t spacePos = line.rfind(' ', breakPos - 1);
|
size_t spacePos = line.rfind(' ', breakPos - 1);
|
||||||
if (spacePos != std::string::npos && spacePos > 0) {
|
if (spacePos != std::string::npos && spacePos > 0) {
|
||||||
@ -393,21 +401,51 @@ void TxtReaderActivity::renderPage() {
|
|||||||
int orientedMarginTop, orientedMarginRight, orientedMarginBottom, orientedMarginLeft;
|
int orientedMarginTop, orientedMarginRight, orientedMarginBottom, orientedMarginLeft;
|
||||||
renderer.getOrientedViewableTRBL(&orientedMarginTop, &orientedMarginRight, &orientedMarginBottom,
|
renderer.getOrientedViewableTRBL(&orientedMarginTop, &orientedMarginRight, &orientedMarginBottom,
|
||||||
&orientedMarginLeft);
|
&orientedMarginLeft);
|
||||||
orientedMarginTop += topPadding;
|
orientedMarginTop += cachedScreenMargin;
|
||||||
orientedMarginLeft += horizontalPadding;
|
orientedMarginLeft += cachedScreenMargin;
|
||||||
orientedMarginRight += horizontalPadding;
|
orientedMarginRight += cachedScreenMargin;
|
||||||
orientedMarginBottom += statusBarMargin;
|
orientedMarginBottom += statusBarMargin;
|
||||||
|
|
||||||
const int lineHeight = renderer.getLineHeight(SETTINGS.getReaderFontId());
|
const int lineHeight = renderer.getLineHeight(cachedFontId);
|
||||||
|
const int contentWidth = viewportWidth;
|
||||||
|
|
||||||
int y = orientedMarginTop;
|
// Render text lines with alignment
|
||||||
for (const auto& line : currentPageLines) {
|
auto renderLines = [&]() {
|
||||||
if (!line.empty()) {
|
int y = orientedMarginTop;
|
||||||
renderer.drawText(SETTINGS.getReaderFontId(), orientedMarginLeft, y, line.c_str());
|
for (const auto& line : currentPageLines) {
|
||||||
|
if (!line.empty()) {
|
||||||
|
int x = orientedMarginLeft;
|
||||||
|
|
||||||
|
// Apply text alignment
|
||||||
|
switch (cachedParagraphAlignment) {
|
||||||
|
case CrossPointSettings::LEFT_ALIGN:
|
||||||
|
default:
|
||||||
|
// x already set to left margin
|
||||||
|
break;
|
||||||
|
case CrossPointSettings::CENTER_ALIGN: {
|
||||||
|
int textWidth = renderer.getTextWidth(cachedFontId, line.c_str());
|
||||||
|
x = orientedMarginLeft + (contentWidth - textWidth) / 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CrossPointSettings::RIGHT_ALIGN: {
|
||||||
|
int textWidth = renderer.getTextWidth(cachedFontId, line.c_str());
|
||||||
|
x = orientedMarginLeft + contentWidth - textWidth;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CrossPointSettings::JUSTIFIED:
|
||||||
|
// For plain text, justified is treated as left-aligned
|
||||||
|
// (true justification would require word spacing adjustments)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderer.drawText(cachedFontId, x, y, line.c_str());
|
||||||
|
}
|
||||||
|
y += lineHeight;
|
||||||
}
|
}
|
||||||
y += lineHeight;
|
};
|
||||||
}
|
|
||||||
|
|
||||||
|
// First pass: BW rendering
|
||||||
|
renderLines();
|
||||||
renderStatusBar(orientedMarginRight, orientedMarginBottom, orientedMarginLeft);
|
renderStatusBar(orientedMarginRight, orientedMarginBottom, orientedMarginLeft);
|
||||||
|
|
||||||
if (pagesUntilFullRefresh <= 1) {
|
if (pagesUntilFullRefresh <= 1) {
|
||||||
@ -417,6 +455,28 @@ void TxtReaderActivity::renderPage() {
|
|||||||
renderer.displayBuffer();
|
renderer.displayBuffer();
|
||||||
pagesUntilFullRefresh--;
|
pagesUntilFullRefresh--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Save BW buffer for restoration after grayscale pass
|
||||||
|
renderer.storeBwBuffer();
|
||||||
|
|
||||||
|
// Grayscale rendering pass (for anti-aliased fonts)
|
||||||
|
{
|
||||||
|
renderer.clearScreen(0x00);
|
||||||
|
renderer.setRenderMode(GfxRenderer::GRAYSCALE_LSB);
|
||||||
|
renderLines();
|
||||||
|
renderer.copyGrayscaleLsbBuffers();
|
||||||
|
|
||||||
|
renderer.clearScreen(0x00);
|
||||||
|
renderer.setRenderMode(GfxRenderer::GRAYSCALE_MSB);
|
||||||
|
renderLines();
|
||||||
|
renderer.copyGrayscaleMsbBuffers();
|
||||||
|
|
||||||
|
renderer.displayGrayBuffer();
|
||||||
|
renderer.setRenderMode(GfxRenderer::BW);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore BW buffer
|
||||||
|
renderer.restoreBwBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TxtReaderActivity::renderStatusBar(const int orientedMarginRight, const int orientedMarginBottom,
|
void TxtReaderActivity::renderStatusBar(const int orientedMarginRight, const int orientedMarginBottom,
|
||||||
@ -492,13 +552,17 @@ void TxtReaderActivity::loadProgress() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool TxtReaderActivity::loadPageIndexCache() {
|
bool TxtReaderActivity::loadPageIndexCache() {
|
||||||
// Cache file format:
|
// Cache file format (using serialization module):
|
||||||
// - 4 bytes: magic "TXTI"
|
// - uint32_t: magic "TXTI"
|
||||||
// - 4 bytes: file size (to validate cache)
|
// - uint8_t: cache version
|
||||||
// - 4 bytes: viewport width
|
// - uint32_t: file size (to validate cache)
|
||||||
// - 4 bytes: lines per page
|
// - int32_t: viewport width
|
||||||
// - 4 bytes: total pages count
|
// - int32_t: lines per page
|
||||||
// - N * 4 bytes: page offsets (size_t stored as uint32_t)
|
// - int32_t: font ID (to invalidate cache on font change)
|
||||||
|
// - int32_t: screen margin (to invalidate cache on margin change)
|
||||||
|
// - uint8_t: paragraph alignment (to invalidate cache on alignment change)
|
||||||
|
// - uint32_t: total pages count
|
||||||
|
// - N * uint32_t: page offsets
|
||||||
|
|
||||||
std::string cachePath = txt->getCachePath() + "/index.bin";
|
std::string cachePath = txt->getCachePath() + "/index.bin";
|
||||||
FsFile f;
|
FsFile f;
|
||||||
@ -507,58 +571,81 @@ bool TxtReaderActivity::loadPageIndexCache() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read and validate header
|
// Read and validate header using serialization module
|
||||||
uint8_t header[20];
|
uint32_t magic;
|
||||||
if (f.read(header, 20) != 20) {
|
serialization::readPod(f, magic);
|
||||||
|
if (magic != CACHE_MAGIC) {
|
||||||
|
Serial.printf("[%lu] [TRS] Cache magic mismatch, rebuilding\n", millis());
|
||||||
f.close();
|
f.close();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check magic
|
uint8_t version;
|
||||||
if (header[0] != 'T' || header[1] != 'X' || header[2] != 'T' || header[3] != 'I') {
|
serialization::readPod(f, version);
|
||||||
|
if (version != CACHE_VERSION) {
|
||||||
|
Serial.printf("[%lu] [TRS] Cache version mismatch (%d != %d), rebuilding\n", millis(), version, CACHE_VERSION);
|
||||||
f.close();
|
f.close();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check file size matches
|
uint32_t fileSize;
|
||||||
uint32_t cachedFileSize = header[4] | (header[5] << 8) | (header[6] << 16) | (header[7] << 24);
|
serialization::readPod(f, fileSize);
|
||||||
if (cachedFileSize != txt->getFileSize()) {
|
if (fileSize != txt->getFileSize()) {
|
||||||
Serial.printf("[%lu] [TRS] Cache file size mismatch, rebuilding\n", millis());
|
Serial.printf("[%lu] [TRS] Cache file size mismatch, rebuilding\n", millis());
|
||||||
f.close();
|
f.close();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check viewport width matches
|
int32_t cachedWidth;
|
||||||
uint32_t cachedViewportWidth = header[8] | (header[9] << 8) | (header[10] << 16) | (header[11] << 24);
|
serialization::readPod(f, cachedWidth);
|
||||||
if (static_cast<int>(cachedViewportWidth) != viewportWidth) {
|
if (cachedWidth != viewportWidth) {
|
||||||
Serial.printf("[%lu] [TRS] Cache viewport width mismatch, rebuilding\n", millis());
|
Serial.printf("[%lu] [TRS] Cache viewport width mismatch, rebuilding\n", millis());
|
||||||
f.close();
|
f.close();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check lines per page matches
|
int32_t cachedLines;
|
||||||
uint32_t cachedLinesPerPage = header[12] | (header[13] << 8) | (header[14] << 16) | (header[15] << 24);
|
serialization::readPod(f, cachedLines);
|
||||||
if (static_cast<int>(cachedLinesPerPage) != linesPerPage) {
|
if (cachedLines != linesPerPage) {
|
||||||
Serial.printf("[%lu] [TRS] Cache lines per page mismatch, rebuilding\n", millis());
|
Serial.printf("[%lu] [TRS] Cache lines per page mismatch, rebuilding\n", millis());
|
||||||
f.close();
|
f.close();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read total pages
|
int32_t fontId;
|
||||||
uint32_t cachedTotalPages = header[16] | (header[17] << 8) | (header[18] << 16) | (header[19] << 24);
|
serialization::readPod(f, fontId);
|
||||||
|
if (fontId != cachedFontId) {
|
||||||
|
Serial.printf("[%lu] [TRS] Cache font ID mismatch (%d != %d), rebuilding\n", millis(), fontId, cachedFontId);
|
||||||
|
f.close();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t margin;
|
||||||
|
serialization::readPod(f, margin);
|
||||||
|
if (margin != cachedScreenMargin) {
|
||||||
|
Serial.printf("[%lu] [TRS] Cache screen margin mismatch, rebuilding\n", millis());
|
||||||
|
f.close();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t alignment;
|
||||||
|
serialization::readPod(f, alignment);
|
||||||
|
if (alignment != cachedParagraphAlignment) {
|
||||||
|
Serial.printf("[%lu] [TRS] Cache paragraph alignment mismatch, rebuilding\n", millis());
|
||||||
|
f.close();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t numPages;
|
||||||
|
serialization::readPod(f, numPages);
|
||||||
|
|
||||||
// Read page offsets
|
// Read page offsets
|
||||||
pageOffsets.clear();
|
pageOffsets.clear();
|
||||||
pageOffsets.reserve(cachedTotalPages);
|
pageOffsets.reserve(numPages);
|
||||||
|
|
||||||
for (uint32_t i = 0; i < cachedTotalPages; i++) {
|
for (uint32_t i = 0; i < numPages; i++) {
|
||||||
uint8_t offsetData[4];
|
uint32_t offset;
|
||||||
if (f.read(offsetData, 4) != 4) {
|
serialization::readPod(f, offset);
|
||||||
f.close();
|
|
||||||
pageOffsets.clear();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
uint32_t offset = offsetData[0] | (offsetData[1] << 8) | (offsetData[2] << 16) | (offsetData[3] << 24);
|
|
||||||
pageOffsets.push_back(offset);
|
pageOffsets.push_back(offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -576,49 +663,20 @@ void TxtReaderActivity::savePageIndexCache() const {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write header
|
// Write header using serialization module
|
||||||
uint8_t header[20];
|
serialization::writePod(f, CACHE_MAGIC);
|
||||||
header[0] = 'T';
|
serialization::writePod(f, CACHE_VERSION);
|
||||||
header[1] = 'X';
|
serialization::writePod(f, static_cast<uint32_t>(txt->getFileSize()));
|
||||||
header[2] = 'T';
|
serialization::writePod(f, static_cast<int32_t>(viewportWidth));
|
||||||
header[3] = 'I';
|
serialization::writePod(f, static_cast<int32_t>(linesPerPage));
|
||||||
|
serialization::writePod(f, static_cast<int32_t>(cachedFontId));
|
||||||
// File size
|
serialization::writePod(f, static_cast<int32_t>(cachedScreenMargin));
|
||||||
uint32_t fileSize = txt->getFileSize();
|
serialization::writePod(f, cachedParagraphAlignment);
|
||||||
header[4] = fileSize & 0xFF;
|
serialization::writePod(f, static_cast<uint32_t>(pageOffsets.size()));
|
||||||
header[5] = (fileSize >> 8) & 0xFF;
|
|
||||||
header[6] = (fileSize >> 16) & 0xFF;
|
|
||||||
header[7] = (fileSize >> 24) & 0xFF;
|
|
||||||
|
|
||||||
// Viewport width
|
|
||||||
header[8] = viewportWidth & 0xFF;
|
|
||||||
header[9] = (viewportWidth >> 8) & 0xFF;
|
|
||||||
header[10] = (viewportWidth >> 16) & 0xFF;
|
|
||||||
header[11] = (viewportWidth >> 24) & 0xFF;
|
|
||||||
|
|
||||||
// Lines per page
|
|
||||||
header[12] = linesPerPage & 0xFF;
|
|
||||||
header[13] = (linesPerPage >> 8) & 0xFF;
|
|
||||||
header[14] = (linesPerPage >> 16) & 0xFF;
|
|
||||||
header[15] = (linesPerPage >> 24) & 0xFF;
|
|
||||||
|
|
||||||
// Total pages
|
|
||||||
uint32_t numPages = pageOffsets.size();
|
|
||||||
header[16] = numPages & 0xFF;
|
|
||||||
header[17] = (numPages >> 8) & 0xFF;
|
|
||||||
header[18] = (numPages >> 16) & 0xFF;
|
|
||||||
header[19] = (numPages >> 24) & 0xFF;
|
|
||||||
|
|
||||||
f.write(header, 20);
|
|
||||||
|
|
||||||
// Write page offsets
|
// Write page offsets
|
||||||
for (size_t offset : pageOffsets) {
|
for (size_t offset : pageOffsets) {
|
||||||
uint8_t offsetData[4];
|
serialization::writePod(f, static_cast<uint32_t>(offset));
|
||||||
offsetData[0] = offset & 0xFF;
|
|
||||||
offsetData[1] = (offset >> 8) & 0xFF;
|
|
||||||
offsetData[2] = (offset >> 16) & 0xFF;
|
|
||||||
offsetData[3] = (offset >> 24) & 0xFF;
|
|
||||||
f.write(offsetData, 4);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
f.close();
|
f.close();
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "CrossPointSettings.h"
|
||||||
#include "activities/ActivityWithSubactivity.h"
|
#include "activities/ActivityWithSubactivity.h"
|
||||||
|
|
||||||
class TxtReaderActivity final : public ActivityWithSubactivity {
|
class TxtReaderActivity final : public ActivityWithSubactivity {
|
||||||
@ -27,6 +28,11 @@ class TxtReaderActivity final : public ActivityWithSubactivity {
|
|||||||
int viewportWidth = 0;
|
int viewportWidth = 0;
|
||||||
bool initialized = false;
|
bool initialized = false;
|
||||||
|
|
||||||
|
// Cached settings for cache validation (different fonts/margins require re-indexing)
|
||||||
|
int cachedFontId = 0;
|
||||||
|
int cachedScreenMargin = 0;
|
||||||
|
uint8_t cachedParagraphAlignment = CrossPointSettings::LEFT_ALIGN;
|
||||||
|
|
||||||
static void taskTrampoline(void* param);
|
static void taskTrampoline(void* param);
|
||||||
[[noreturn]] void displayTaskLoop();
|
[[noreturn]] void displayTaskLoop();
|
||||||
void renderScreen();
|
void renderScreen();
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user