granular position tracking
This commit is contained in:
@@ -332,6 +332,11 @@ void XMLCALL ChapterHtmlSlimParser::characterData(void* userData, const XML_Char
|
||||
if (self->skipUntilDepth < self->depth) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Capture byte offset of this character data for page position tracking
|
||||
if (self->xmlParser) {
|
||||
self->lastCharDataOffset = XML_GetCurrentByteIndex(self->xmlParser);
|
||||
}
|
||||
|
||||
// Determine font style from depth-based tracking and CSS effective style
|
||||
const bool isBold = self->boldUntilDepth < self->depth || self->effectiveBold;
|
||||
@@ -477,17 +482,18 @@ void XMLCALL ChapterHtmlSlimParser::endElement(void* userData, const XML_Char* n
|
||||
bool ChapterHtmlSlimParser::parseAndBuildPages() {
|
||||
startNewTextBlock((TextBlock::Style)this->paragraphAlignment);
|
||||
|
||||
const XML_Parser parser = XML_ParserCreate(nullptr);
|
||||
xmlParser = XML_ParserCreate(nullptr);
|
||||
int done;
|
||||
|
||||
if (!parser) {
|
||||
if (!xmlParser) {
|
||||
Serial.printf("[%lu] [EHP] Couldn't allocate memory for parser\n", millis());
|
||||
return false;
|
||||
}
|
||||
|
||||
FsFile file;
|
||||
if (!SdMan.openFileForRead("EHP", filepath, file)) {
|
||||
XML_ParserFree(parser);
|
||||
XML_ParserFree(xmlParser);
|
||||
xmlParser = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -495,19 +501,24 @@ bool ChapterHtmlSlimParser::parseAndBuildPages() {
|
||||
const size_t totalSize = file.size();
|
||||
size_t bytesRead = 0;
|
||||
int lastProgress = -1;
|
||||
|
||||
// Initialize offset tracking - first page starts at offset 0
|
||||
currentPageStartOffset = 0;
|
||||
lastCharDataOffset = 0;
|
||||
|
||||
XML_SetUserData(parser, this);
|
||||
XML_SetElementHandler(parser, startElement, endElement);
|
||||
XML_SetCharacterDataHandler(parser, characterData);
|
||||
XML_SetUserData(xmlParser, this);
|
||||
XML_SetElementHandler(xmlParser, startElement, endElement);
|
||||
XML_SetCharacterDataHandler(xmlParser, characterData);
|
||||
|
||||
do {
|
||||
void* const buf = XML_GetBuffer(parser, 1024);
|
||||
void* const buf = XML_GetBuffer(xmlParser, 1024);
|
||||
if (!buf) {
|
||||
Serial.printf("[%lu] [EHP] Couldn't allocate memory for buffer\n", millis());
|
||||
XML_StopParser(parser, XML_FALSE); // Stop any pending processing
|
||||
XML_SetElementHandler(parser, nullptr, nullptr); // Clear callbacks
|
||||
XML_SetCharacterDataHandler(parser, nullptr);
|
||||
XML_ParserFree(parser);
|
||||
XML_StopParser(xmlParser, XML_FALSE); // Stop any pending processing
|
||||
XML_SetElementHandler(xmlParser, nullptr, nullptr); // Clear callbacks
|
||||
XML_SetCharacterDataHandler(xmlParser, nullptr);
|
||||
XML_ParserFree(xmlParser);
|
||||
xmlParser = nullptr;
|
||||
file.close();
|
||||
return false;
|
||||
}
|
||||
@@ -516,10 +527,11 @@ bool ChapterHtmlSlimParser::parseAndBuildPages() {
|
||||
|
||||
if (len == 0 && file.available() > 0) {
|
||||
Serial.printf("[%lu] [EHP] File read error\n", millis());
|
||||
XML_StopParser(parser, XML_FALSE); // Stop any pending processing
|
||||
XML_SetElementHandler(parser, nullptr, nullptr); // Clear callbacks
|
||||
XML_SetCharacterDataHandler(parser, nullptr);
|
||||
XML_ParserFree(parser);
|
||||
XML_StopParser(xmlParser, XML_FALSE); // Stop any pending processing
|
||||
XML_SetElementHandler(xmlParser, nullptr, nullptr); // Clear callbacks
|
||||
XML_SetCharacterDataHandler(xmlParser, nullptr);
|
||||
XML_ParserFree(xmlParser);
|
||||
xmlParser = nullptr;
|
||||
file.close();
|
||||
return false;
|
||||
}
|
||||
@@ -537,27 +549,33 @@ bool ChapterHtmlSlimParser::parseAndBuildPages() {
|
||||
|
||||
done = file.available() == 0;
|
||||
|
||||
if (XML_ParseBuffer(parser, static_cast<int>(len), done) == XML_STATUS_ERROR) {
|
||||
Serial.printf("[%lu] [EHP] Parse error at line %lu:\n%s\n", millis(), XML_GetCurrentLineNumber(parser),
|
||||
XML_ErrorString(XML_GetErrorCode(parser)));
|
||||
XML_StopParser(parser, XML_FALSE); // Stop any pending processing
|
||||
XML_SetElementHandler(parser, nullptr, nullptr); // Clear callbacks
|
||||
XML_SetCharacterDataHandler(parser, nullptr);
|
||||
XML_ParserFree(parser);
|
||||
if (XML_ParseBuffer(xmlParser, static_cast<int>(len), done) == XML_STATUS_ERROR) {
|
||||
Serial.printf("[%lu] [EHP] Parse error at line %lu:\n%s\n", millis(), XML_GetCurrentLineNumber(xmlParser),
|
||||
XML_ErrorString(XML_GetErrorCode(xmlParser)));
|
||||
XML_StopParser(xmlParser, XML_FALSE); // Stop any pending processing
|
||||
XML_SetElementHandler(xmlParser, nullptr, nullptr); // Clear callbacks
|
||||
XML_SetCharacterDataHandler(xmlParser, nullptr);
|
||||
XML_ParserFree(xmlParser);
|
||||
xmlParser = nullptr;
|
||||
file.close();
|
||||
return false;
|
||||
}
|
||||
} while (!done);
|
||||
|
||||
XML_StopParser(parser, XML_FALSE); // Stop any pending processing
|
||||
XML_SetElementHandler(parser, nullptr, nullptr); // Clear callbacks
|
||||
XML_SetCharacterDataHandler(parser, nullptr);
|
||||
XML_ParserFree(parser);
|
||||
XML_StopParser(xmlParser, XML_FALSE); // Stop any pending processing
|
||||
XML_SetElementHandler(xmlParser, nullptr, nullptr); // Clear callbacks
|
||||
XML_SetCharacterDataHandler(xmlParser, nullptr);
|
||||
XML_ParserFree(xmlParser);
|
||||
xmlParser = nullptr;
|
||||
file.close();
|
||||
|
||||
// Process last page if there is still text
|
||||
if (currentTextBlock) {
|
||||
makePages();
|
||||
// Set the content offset for the final page
|
||||
if (currentPage) {
|
||||
currentPage->firstContentOffset = static_cast<uint32_t>(currentPageStartOffset);
|
||||
}
|
||||
completePageFn(std::move(currentPage));
|
||||
currentPage.reset();
|
||||
currentTextBlock.reset();
|
||||
@@ -570,8 +588,15 @@ void ChapterHtmlSlimParser::addLineToPage(std::shared_ptr<TextBlock> line) {
|
||||
const int lineHeight = renderer.getLineHeight(fontId) * lineCompression;
|
||||
|
||||
if (currentPageNextY + lineHeight > viewportHeight) {
|
||||
// Set the content offset for the page being completed
|
||||
if (currentPage) {
|
||||
currentPage->firstContentOffset = static_cast<uint32_t>(currentPageStartOffset);
|
||||
}
|
||||
completePageFn(std::move(currentPage));
|
||||
|
||||
// Start new page - offset will be set when first content is added
|
||||
currentPage.reset(new Page());
|
||||
currentPageStartOffset = lastCharDataOffset; // Use offset from when content was parsed
|
||||
currentPageNextY = 0;
|
||||
}
|
||||
|
||||
@@ -587,6 +612,8 @@ void ChapterHtmlSlimParser::makePages() {
|
||||
|
||||
if (!currentPage) {
|
||||
currentPage.reset(new Page());
|
||||
// Use offset captured during character data parsing
|
||||
currentPageStartOffset = lastCharDataOffset;
|
||||
currentPageNextY = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -54,6 +54,11 @@ class ChapterHtmlSlimParser {
|
||||
bool effectiveBold = false;
|
||||
bool effectiveItalic = false;
|
||||
bool effectiveUnderline = false;
|
||||
|
||||
// Byte offset tracking for position restoration after re-indexing
|
||||
XML_Parser xmlParser = nullptr; // Store parser for getting current byte index
|
||||
size_t currentPageStartOffset = 0; // Byte offset when current page was started
|
||||
size_t lastCharDataOffset = 0; // Byte offset of last character data (captured during parsing)
|
||||
|
||||
void updateEffectiveInlineStyle();
|
||||
void startNewTextBlock(TextBlock::Style style);
|
||||
|
||||
Reference in New Issue
Block a user