2025-12-06 20:57:24 +11:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
#include <expat.h>
|
|
|
|
|
|
2025-12-08 22:06:09 +11:00
|
|
|
#include <climits>
|
2025-12-06 20:57:24 +11:00
|
|
|
#include <functional>
|
2025-12-12 22:13:34 +11:00
|
|
|
#include <memory>
|
feat: slim footnotes support (#1031)
## Summary
**What is the goal of this PR?** Implement support for footnotes in epub
files.
It is based on #553, but simplified — removed the parts which
complicated the code and burden the CPU/RAM. This version supports basic
footnotes and lets the user jump from location to location inside the
epub.
**What changes are included?**
- `FootnoteEntry` struct — A small POD struct (number[24], href[64])
shared between parser, page storage, and UI.
- Parser: `<a href>` detection (`ChapterHtmlSlimParser`) — During a
single parsing pass, internal epub links are detected and collected as
footnotes. The link text is underlined to hint navigability.
Bracket/whitespace normalization is applied to the display label (e.g.
[1] → 1).
- Footnote-to-page assignment (`ChapterHtmlSlimParser`, `Page`) —
Footnotes are attached to the exact page where their anchor word
appears, tracked via a cumulative word counter during layout, surviving
paragraph splits and the 750-word mid-paragraph safety flush.
- Page serialization (`Page`, `Section`) — Footnotes are
serialized/deserialized per page (max 16 per page). Section cache
version bumped to 14 to force a clean rebuild.
- Href → spine resolution (`Epub`) — `resolveHrefToSpineIndex()` maps an
href (e.g. `chapter2.xhtml#note1`) to its spine index by filename
matching.
- Footnotes menu + activity (`EpubReaderMenuActivity`,
`EpubReaderFootnotesActivity`) — A new "Footnotes" entry in the reader
menu lists all footnote links found on the current page. The user
scrolls and selects to navigate.
- Navigate & restore (`EpubReaderActivity`) — `navigateToHref()` saves
the current spine index and page number, then jumps to the target. The
Back button restores the saved position when the user is done reading
the footnote.
**Additional Context**
**What was removed vs #553:** virtual spine items
(`addVirtualSpineItem`, `isVirtualSpineItem`), two-pass parsing,
`<aside>` content extraction to temp HTML files, `<p class="note">`
paragraph note extraction, `replaceHtmlEntities` (master already has
`lookupHtmlEntity`), `footnotePages` / `buildFilteredChapterList`,
`noterefCallback` / `Noteref` struct, and the stack size increase from 8
KB to 24 KB (not needed without two-pass parsing and virtual file I/O on
the render task).
**Performance:** Single-pass parsing. No new heap allocations in the hot
path — footnote text is collected into fixed stack buffers (char[24],
char[64]). Active runtime memory is ~2.8 KB worst-case (one page × 16
footnotes × 88 bytes, mirrored in `currentPageFootnotes`). Flash usage
is unchanged at 97.4%; RAM stays at 31%.
**Known limitations:** When clicking a footnote, it jumps to the start
of the HTML file instead of the specific anchor. This could be
problematic for books that don't have separate files for each footnote.
(no element-id-to-page mapping yet - will be another PR soon).
---
### AI Usage
Did you use AI tools to help write this code? _**< PARTIALLY>**_
Claude Opus 4.6 was used to do most of the migration, I checked manually
its work, and fixed some stuff, but I haven't review all the changes
yet, so feedback is welcomed.
---------
Co-authored-by: Arthur Tazhitdinov <lisnake@gmail.com>
2026-02-26 16:47:34 +02:00
|
|
|
#include <vector>
|
2025-12-06 20:57:24 +11:00
|
|
|
|
feat: slim footnotes support (#1031)
## Summary
**What is the goal of this PR?** Implement support for footnotes in epub
files.
It is based on #553, but simplified — removed the parts which
complicated the code and burden the CPU/RAM. This version supports basic
footnotes and lets the user jump from location to location inside the
epub.
**What changes are included?**
- `FootnoteEntry` struct — A small POD struct (number[24], href[64])
shared between parser, page storage, and UI.
- Parser: `<a href>` detection (`ChapterHtmlSlimParser`) — During a
single parsing pass, internal epub links are detected and collected as
footnotes. The link text is underlined to hint navigability.
Bracket/whitespace normalization is applied to the display label (e.g.
[1] → 1).
- Footnote-to-page assignment (`ChapterHtmlSlimParser`, `Page`) —
Footnotes are attached to the exact page where their anchor word
appears, tracked via a cumulative word counter during layout, surviving
paragraph splits and the 750-word mid-paragraph safety flush.
- Page serialization (`Page`, `Section`) — Footnotes are
serialized/deserialized per page (max 16 per page). Section cache
version bumped to 14 to force a clean rebuild.
- Href → spine resolution (`Epub`) — `resolveHrefToSpineIndex()` maps an
href (e.g. `chapter2.xhtml#note1`) to its spine index by filename
matching.
- Footnotes menu + activity (`EpubReaderMenuActivity`,
`EpubReaderFootnotesActivity`) — A new "Footnotes" entry in the reader
menu lists all footnote links found on the current page. The user
scrolls and selects to navigate.
- Navigate & restore (`EpubReaderActivity`) — `navigateToHref()` saves
the current spine index and page number, then jumps to the target. The
Back button restores the saved position when the user is done reading
the footnote.
**Additional Context**
**What was removed vs #553:** virtual spine items
(`addVirtualSpineItem`, `isVirtualSpineItem`), two-pass parsing,
`<aside>` content extraction to temp HTML files, `<p class="note">`
paragraph note extraction, `replaceHtmlEntities` (master already has
`lookupHtmlEntity`), `footnotePages` / `buildFilteredChapterList`,
`noterefCallback` / `Noteref` struct, and the stack size increase from 8
KB to 24 KB (not needed without two-pass parsing and virtual file I/O on
the render task).
**Performance:** Single-pass parsing. No new heap allocations in the hot
path — footnote text is collected into fixed stack buffers (char[24],
char[64]). Active runtime memory is ~2.8 KB worst-case (one page × 16
footnotes × 88 bytes, mirrored in `currentPageFootnotes`). Flash usage
is unchanged at 97.4%; RAM stays at 31%.
**Known limitations:** When clicking a footnote, it jumps to the start
of the HTML file instead of the specific anchor. This could be
problematic for books that don't have separate files for each footnote.
(no element-id-to-page mapping yet - will be another PR soon).
---
### AI Usage
Did you use AI tools to help write this code? _**< PARTIALLY>**_
Claude Opus 4.6 was used to do most of the migration, I checked manually
its work, and fixed some stuff, but I haven't review all the changes
yet, so feedback is welcomed.
---------
Co-authored-by: Arthur Tazhitdinov <lisnake@gmail.com>
2026-02-26 16:47:34 +02:00
|
|
|
#include "../FootnoteEntry.h"
|
2025-12-13 19:36:01 +11:00
|
|
|
#include "../ParsedText.h"
|
2026-02-16 08:56:59 +00:00
|
|
|
#include "../blocks/ImageBlock.h"
|
2025-12-13 19:36:01 +11:00
|
|
|
#include "../blocks/TextBlock.h"
|
feat: Add CSS parsing and CSS support in EPUBs (#411)
## Summary
* **What is the goal of this PR?**
- Adds basic CSS parsing to EPUBs and determine the CSS rules when
rendering to the screen so that text is styled correctly. Currently
supports bold, underline, italics, margin, padding, and text alignment
## Additional Context
- My main reason for wanting this is that the book I'm currently
reading, Carl's Doomsday Scenario (2nd in the Dungeon Crawler Carl
series), relies _a lot_ on styled text for telling parts of the story.
When text is bolded, it's supposed to be a message that's rendered
"on-screen" in the story. When characters are "chatting" with each
other, the text is bolded and their names are underlined. Plus, normal
emphasis is provided with italicizing words here and there. So, this
greatly improves my experience reading this book on the Xteink, and I
figured it was useful enough for others too.
- For transparency: I'm a software engineer, but I'm mostly frontend and
TypeScript/JavaScript. It's been _years_ since I did any C/C++, so I
would not be surprised if I'm doing something dumb along the way in this
code. Please don't hesitate to ask for changes if something looks off. I
heavily relied on Claude Code for help, and I had a lot of inspiration
from how [microreader](https://github.com/CidVonHighwind/microreader)
achieves their CSS parsing and styling. I did give this as good of a
code review as I could and went through everything, and _it works on my
machine_ 😄
### Before


### After


---
### AI Usage
Did you use AI tools to help write this code? **YES**, Claude Code
2026-02-05 05:28:10 -05:00
|
|
|
#include "../css/CssParser.h"
|
|
|
|
|
#include "../css/CssStyle.h"
|
2025-12-06 20:57:24 +11:00
|
|
|
|
|
|
|
|
class Page;
|
2025-12-08 22:06:09 +11:00
|
|
|
class GfxRenderer;
|
2026-02-16 08:56:59 +00:00
|
|
|
class Epub;
|
2025-12-06 20:57:24 +11:00
|
|
|
|
2025-12-08 22:06:09 +11:00
|
|
|
#define MAX_WORD_SIZE 200
|
2025-12-06 20:57:24 +11:00
|
|
|
|
2025-12-13 19:36:01 +11:00
|
|
|
class ChapterHtmlSlimParser {
|
2026-02-16 08:56:59 +00:00
|
|
|
std::shared_ptr<Epub> epub;
|
2025-12-23 14:14:10 +11:00
|
|
|
const std::string& filepath;
|
2025-12-08 22:06:09 +11:00
|
|
|
GfxRenderer& renderer;
|
2025-12-12 22:13:34 +11:00
|
|
|
std::function<void(std::unique_ptr<Page>)> completePageFn;
|
2026-02-01 12:41:24 +05:00
|
|
|
std::function<void()> popupFn; // Popup callback
|
2025-12-06 20:57:24 +11:00
|
|
|
int depth = 0;
|
|
|
|
|
int skipUntilDepth = INT_MAX;
|
|
|
|
|
int boldUntilDepth = INT_MAX;
|
|
|
|
|
int italicUntilDepth = INT_MAX;
|
feat: Add CSS parsing and CSS support in EPUBs (#411)
## Summary
* **What is the goal of this PR?**
- Adds basic CSS parsing to EPUBs and determine the CSS rules when
rendering to the screen so that text is styled correctly. Currently
supports bold, underline, italics, margin, padding, and text alignment
## Additional Context
- My main reason for wanting this is that the book I'm currently
reading, Carl's Doomsday Scenario (2nd in the Dungeon Crawler Carl
series), relies _a lot_ on styled text for telling parts of the story.
When text is bolded, it's supposed to be a message that's rendered
"on-screen" in the story. When characters are "chatting" with each
other, the text is bolded and their names are underlined. Plus, normal
emphasis is provided with italicizing words here and there. So, this
greatly improves my experience reading this book on the Xteink, and I
figured it was useful enough for others too.
- For transparency: I'm a software engineer, but I'm mostly frontend and
TypeScript/JavaScript. It's been _years_ since I did any C/C++, so I
would not be surprised if I'm doing something dumb along the way in this
code. Please don't hesitate to ask for changes if something looks off. I
heavily relied on Claude Code for help, and I had a lot of inspiration
from how [microreader](https://github.com/CidVonHighwind/microreader)
achieves their CSS parsing and styling. I did give this as good of a
code review as I could and went through everything, and _it works on my
machine_ 😄
### Before


### After


---
### AI Usage
Did you use AI tools to help write this code? **YES**, Claude Code
2026-02-05 05:28:10 -05:00
|
|
|
int underlineUntilDepth = INT_MAX;
|
2025-12-08 22:06:09 +11:00
|
|
|
// buffer for building up words from characters, will auto break if longer than this
|
|
|
|
|
// leave one char at end for null pointer
|
|
|
|
|
char partWordBuffer[MAX_WORD_SIZE + 1] = {};
|
2025-12-06 20:57:24 +11:00
|
|
|
int partWordBufferIndex = 0;
|
2026-02-06 03:10:37 -05:00
|
|
|
bool nextWordContinues = false; // true when next flushed word attaches to previous (inline element boundary)
|
2025-12-12 22:13:34 +11:00
|
|
|
std::unique_ptr<ParsedText> currentTextBlock = nullptr;
|
|
|
|
|
std::unique_ptr<Page> currentPage = nullptr;
|
2025-12-13 00:42:17 +11:00
|
|
|
int16_t currentPageNextY = 0;
|
2025-12-08 22:06:09 +11:00
|
|
|
int fontId;
|
|
|
|
|
float lineCompression;
|
2025-12-15 13:16:46 +01:00
|
|
|
bool extraParagraphSpacing;
|
2026-01-02 01:21:48 -06:00
|
|
|
uint8_t paragraphAlignment;
|
2025-12-31 12:11:36 +10:00
|
|
|
uint16_t viewportWidth;
|
|
|
|
|
uint16_t viewportHeight;
|
2026-01-19 17:56:26 +05:00
|
|
|
bool hyphenationEnabled;
|
feat: Add CSS parsing and CSS support in EPUBs (#411)
## Summary
* **What is the goal of this PR?**
- Adds basic CSS parsing to EPUBs and determine the CSS rules when
rendering to the screen so that text is styled correctly. Currently
supports bold, underline, italics, margin, padding, and text alignment
## Additional Context
- My main reason for wanting this is that the book I'm currently
reading, Carl's Doomsday Scenario (2nd in the Dungeon Crawler Carl
series), relies _a lot_ on styled text for telling parts of the story.
When text is bolded, it's supposed to be a message that's rendered
"on-screen" in the story. When characters are "chatting" with each
other, the text is bolded and their names are underlined. Plus, normal
emphasis is provided with italicizing words here and there. So, this
greatly improves my experience reading this book on the Xteink, and I
figured it was useful enough for others too.
- For transparency: I'm a software engineer, but I'm mostly frontend and
TypeScript/JavaScript. It's been _years_ since I did any C/C++, so I
would not be surprised if I'm doing something dumb along the way in this
code. Please don't hesitate to ask for changes if something looks off. I
heavily relied on Claude Code for help, and I had a lot of inspiration
from how [microreader](https://github.com/CidVonHighwind/microreader)
achieves their CSS parsing and styling. I did give this as good of a
code review as I could and went through everything, and _it works on my
machine_ 😄
### Before


### After


---
### AI Usage
Did you use AI tools to help write this code? **YES**, Claude Code
2026-02-05 05:28:10 -05:00
|
|
|
const CssParser* cssParser;
|
2026-02-06 02:49:04 -05:00
|
|
|
bool embeddedStyle;
|
2026-03-03 16:59:06 +01:00
|
|
|
uint8_t imageRendering;
|
2026-02-16 08:56:59 +00:00
|
|
|
std::string contentBase;
|
|
|
|
|
std::string imageBasePath;
|
|
|
|
|
int imageCounter = 0;
|
2025-12-06 20:57:24 +11:00
|
|
|
|
feat: Add CSS parsing and CSS support in EPUBs (#411)
## Summary
* **What is the goal of this PR?**
- Adds basic CSS parsing to EPUBs and determine the CSS rules when
rendering to the screen so that text is styled correctly. Currently
supports bold, underline, italics, margin, padding, and text alignment
## Additional Context
- My main reason for wanting this is that the book I'm currently
reading, Carl's Doomsday Scenario (2nd in the Dungeon Crawler Carl
series), relies _a lot_ on styled text for telling parts of the story.
When text is bolded, it's supposed to be a message that's rendered
"on-screen" in the story. When characters are "chatting" with each
other, the text is bolded and their names are underlined. Plus, normal
emphasis is provided with italicizing words here and there. So, this
greatly improves my experience reading this book on the Xteink, and I
figured it was useful enough for others too.
- For transparency: I'm a software engineer, but I'm mostly frontend and
TypeScript/JavaScript. It's been _years_ since I did any C/C++, so I
would not be surprised if I'm doing something dumb along the way in this
code. Please don't hesitate to ask for changes if something looks off. I
heavily relied on Claude Code for help, and I had a lot of inspiration
from how [microreader](https://github.com/CidVonHighwind/microreader)
achieves their CSS parsing and styling. I did give this as good of a
code review as I could and went through everything, and _it works on my
machine_ 😄
### Before


### After


---
### AI Usage
Did you use AI tools to help write this code? **YES**, Claude Code
2026-02-05 05:28:10 -05:00
|
|
|
// Style tracking (replaces depth-based approach)
|
|
|
|
|
struct StyleStackEntry {
|
|
|
|
|
int depth = 0;
|
|
|
|
|
bool hasBold = false, bold = false;
|
|
|
|
|
bool hasItalic = false, italic = false;
|
|
|
|
|
bool hasUnderline = false, underline = false;
|
|
|
|
|
};
|
|
|
|
|
std::vector<StyleStackEntry> inlineStyleStack;
|
|
|
|
|
CssStyle currentCssStyle;
|
|
|
|
|
bool effectiveBold = false;
|
|
|
|
|
bool effectiveItalic = false;
|
|
|
|
|
bool effectiveUnderline = false;
|
2026-02-19 14:13:23 +01:00
|
|
|
int tableDepth = 0;
|
|
|
|
|
int tableRowIndex = 0;
|
|
|
|
|
int tableColIndex = 0;
|
feat: Add CSS parsing and CSS support in EPUBs (#411)
## Summary
* **What is the goal of this PR?**
- Adds basic CSS parsing to EPUBs and determine the CSS rules when
rendering to the screen so that text is styled correctly. Currently
supports bold, underline, italics, margin, padding, and text alignment
## Additional Context
- My main reason for wanting this is that the book I'm currently
reading, Carl's Doomsday Scenario (2nd in the Dungeon Crawler Carl
series), relies _a lot_ on styled text for telling parts of the story.
When text is bolded, it's supposed to be a message that's rendered
"on-screen" in the story. When characters are "chatting" with each
other, the text is bolded and their names are underlined. Plus, normal
emphasis is provided with italicizing words here and there. So, this
greatly improves my experience reading this book on the Xteink, and I
figured it was useful enough for others too.
- For transparency: I'm a software engineer, but I'm mostly frontend and
TypeScript/JavaScript. It's been _years_ since I did any C/C++, so I
would not be surprised if I'm doing something dumb along the way in this
code. Please don't hesitate to ask for changes if something looks off. I
heavily relied on Claude Code for help, and I had a lot of inspiration
from how [microreader](https://github.com/CidVonHighwind/microreader)
achieves their CSS parsing and styling. I did give this as good of a
code review as I could and went through everything, and _it works on my
machine_ 😄
### Before


### After


---
### AI Usage
Did you use AI tools to help write this code? **YES**, Claude Code
2026-02-05 05:28:10 -05:00
|
|
|
|
feat: slim footnotes support (#1031)
## Summary
**What is the goal of this PR?** Implement support for footnotes in epub
files.
It is based on #553, but simplified — removed the parts which
complicated the code and burden the CPU/RAM. This version supports basic
footnotes and lets the user jump from location to location inside the
epub.
**What changes are included?**
- `FootnoteEntry` struct — A small POD struct (number[24], href[64])
shared between parser, page storage, and UI.
- Parser: `<a href>` detection (`ChapterHtmlSlimParser`) — During a
single parsing pass, internal epub links are detected and collected as
footnotes. The link text is underlined to hint navigability.
Bracket/whitespace normalization is applied to the display label (e.g.
[1] → 1).
- Footnote-to-page assignment (`ChapterHtmlSlimParser`, `Page`) —
Footnotes are attached to the exact page where their anchor word
appears, tracked via a cumulative word counter during layout, surviving
paragraph splits and the 750-word mid-paragraph safety flush.
- Page serialization (`Page`, `Section`) — Footnotes are
serialized/deserialized per page (max 16 per page). Section cache
version bumped to 14 to force a clean rebuild.
- Href → spine resolution (`Epub`) — `resolveHrefToSpineIndex()` maps an
href (e.g. `chapter2.xhtml#note1`) to its spine index by filename
matching.
- Footnotes menu + activity (`EpubReaderMenuActivity`,
`EpubReaderFootnotesActivity`) — A new "Footnotes" entry in the reader
menu lists all footnote links found on the current page. The user
scrolls and selects to navigate.
- Navigate & restore (`EpubReaderActivity`) — `navigateToHref()` saves
the current spine index and page number, then jumps to the target. The
Back button restores the saved position when the user is done reading
the footnote.
**Additional Context**
**What was removed vs #553:** virtual spine items
(`addVirtualSpineItem`, `isVirtualSpineItem`), two-pass parsing,
`<aside>` content extraction to temp HTML files, `<p class="note">`
paragraph note extraction, `replaceHtmlEntities` (master already has
`lookupHtmlEntity`), `footnotePages` / `buildFilteredChapterList`,
`noterefCallback` / `Noteref` struct, and the stack size increase from 8
KB to 24 KB (not needed without two-pass parsing and virtual file I/O on
the render task).
**Performance:** Single-pass parsing. No new heap allocations in the hot
path — footnote text is collected into fixed stack buffers (char[24],
char[64]). Active runtime memory is ~2.8 KB worst-case (one page × 16
footnotes × 88 bytes, mirrored in `currentPageFootnotes`). Flash usage
is unchanged at 97.4%; RAM stays at 31%.
**Known limitations:** When clicking a footnote, it jumps to the start
of the HTML file instead of the specific anchor. This could be
problematic for books that don't have separate files for each footnote.
(no element-id-to-page mapping yet - will be another PR soon).
---
### AI Usage
Did you use AI tools to help write this code? _**< PARTIALLY>**_
Claude Opus 4.6 was used to do most of the migration, I checked manually
its work, and fixed some stuff, but I haven't review all the changes
yet, so feedback is welcomed.
---------
Co-authored-by: Arthur Tazhitdinov <lisnake@gmail.com>
2026-02-26 16:47:34 +02:00
|
|
|
// Footnote link tracking
|
|
|
|
|
bool insideFootnoteLink = false;
|
|
|
|
|
int footnoteLinkDepth = -1;
|
|
|
|
|
char currentFootnoteLinkText[24] = {};
|
|
|
|
|
int currentFootnoteLinkTextLen = 0;
|
|
|
|
|
char currentFootnoteLinkHref[64] = {};
|
|
|
|
|
std::vector<std::pair<int, FootnoteEntry>> pendingFootnotes; // <wordIndex, entry>
|
|
|
|
|
int wordsExtractedInBlock = 0;
|
|
|
|
|
|
feat: Add CSS parsing and CSS support in EPUBs (#411)
## Summary
* **What is the goal of this PR?**
- Adds basic CSS parsing to EPUBs and determine the CSS rules when
rendering to the screen so that text is styled correctly. Currently
supports bold, underline, italics, margin, padding, and text alignment
## Additional Context
- My main reason for wanting this is that the book I'm currently
reading, Carl's Doomsday Scenario (2nd in the Dungeon Crawler Carl
series), relies _a lot_ on styled text for telling parts of the story.
When text is bolded, it's supposed to be a message that's rendered
"on-screen" in the story. When characters are "chatting" with each
other, the text is bolded and their names are underlined. Plus, normal
emphasis is provided with italicizing words here and there. So, this
greatly improves my experience reading this book on the Xteink, and I
figured it was useful enough for others too.
- For transparency: I'm a software engineer, but I'm mostly frontend and
TypeScript/JavaScript. It's been _years_ since I did any C/C++, so I
would not be surprised if I'm doing something dumb along the way in this
code. Please don't hesitate to ask for changes if something looks off. I
heavily relied on Claude Code for help, and I had a lot of inspiration
from how [microreader](https://github.com/CidVonHighwind/microreader)
achieves their CSS parsing and styling. I did give this as good of a
code review as I could and went through everything, and _it works on my
machine_ 😄
### Before


### After


---
### AI Usage
Did you use AI tools to help write this code? **YES**, Claude Code
2026-02-05 05:28:10 -05:00
|
|
|
void updateEffectiveInlineStyle();
|
|
|
|
|
void startNewTextBlock(const BlockStyle& blockStyle);
|
2026-01-27 03:07:02 -08:00
|
|
|
void flushPartWordBuffer();
|
2025-12-06 20:57:24 +11:00
|
|
|
void makePages();
|
|
|
|
|
// XML callbacks
|
|
|
|
|
static void XMLCALL startElement(void* userData, const XML_Char* name, const XML_Char** atts);
|
|
|
|
|
static void XMLCALL characterData(void* userData, const XML_Char* s, int len);
|
2026-02-13 09:46:46 -05:00
|
|
|
static void XMLCALL defaultHandlerExpand(void* userData, const XML_Char* s, int len);
|
2025-12-06 20:57:24 +11:00
|
|
|
static void XMLCALL endElement(void* userData, const XML_Char* name);
|
|
|
|
|
|
|
|
|
|
public:
|
2026-02-16 08:56:59 +00:00
|
|
|
explicit ChapterHtmlSlimParser(std::shared_ptr<Epub> epub, const std::string& filepath, GfxRenderer& renderer,
|
|
|
|
|
const int fontId, const float lineCompression, const bool extraParagraphSpacing,
|
2026-01-02 01:21:48 -06:00
|
|
|
const uint8_t paragraphAlignment, const uint16_t viewportWidth,
|
2026-01-19 17:56:26 +05:00
|
|
|
const uint16_t viewportHeight, const bool hyphenationEnabled,
|
2025-12-28 13:59:44 +09:00
|
|
|
const std::function<void(std::unique_ptr<Page>)>& completePageFn,
|
2026-02-16 08:56:59 +00:00
|
|
|
const bool embeddedStyle, const std::string& contentBase,
|
2026-03-03 16:59:06 +01:00
|
|
|
const std::string& imageBasePath, const uint8_t imageRendering = 0,
|
|
|
|
|
const std::function<void()>& popupFn = nullptr, const CssParser* cssParser = nullptr)
|
feat: Add CSS parsing and CSS support in EPUBs (#411)
## Summary
* **What is the goal of this PR?**
- Adds basic CSS parsing to EPUBs and determine the CSS rules when
rendering to the screen so that text is styled correctly. Currently
supports bold, underline, italics, margin, padding, and text alignment
## Additional Context
- My main reason for wanting this is that the book I'm currently
reading, Carl's Doomsday Scenario (2nd in the Dungeon Crawler Carl
series), relies _a lot_ on styled text for telling parts of the story.
When text is bolded, it's supposed to be a message that's rendered
"on-screen" in the story. When characters are "chatting" with each
other, the text is bolded and their names are underlined. Plus, normal
emphasis is provided with italicizing words here and there. So, this
greatly improves my experience reading this book on the Xteink, and I
figured it was useful enough for others too.
- For transparency: I'm a software engineer, but I'm mostly frontend and
TypeScript/JavaScript. It's been _years_ since I did any C/C++, so I
would not be surprised if I'm doing something dumb along the way in this
code. Please don't hesitate to ask for changes if something looks off. I
heavily relied on Claude Code for help, and I had a lot of inspiration
from how [microreader](https://github.com/CidVonHighwind/microreader)
achieves their CSS parsing and styling. I did give this as good of a
code review as I could and went through everything, and _it works on my
machine_ 😄
### Before


### After


---
### AI Usage
Did you use AI tools to help write this code? **YES**, Claude Code
2026-02-05 05:28:10 -05:00
|
|
|
|
2026-02-16 08:56:59 +00:00
|
|
|
: epub(epub),
|
|
|
|
|
filepath(filepath),
|
2025-12-08 22:06:09 +11:00
|
|
|
renderer(renderer),
|
|
|
|
|
fontId(fontId),
|
|
|
|
|
lineCompression(lineCompression),
|
2025-12-15 13:16:46 +01:00
|
|
|
extraParagraphSpacing(extraParagraphSpacing),
|
2026-01-02 01:21:48 -06:00
|
|
|
paragraphAlignment(paragraphAlignment),
|
Rotation Support (#77)
• What is the goal of this PR?
Implement a horizontal EPUB reading mode so books can be read in
landscape orientation (both 90° and 270°), while keeping the rest of the
UI in portrait.
• What changes are included?
◦ Rendering / Display
▪ Added an orientation model to GfxRenderer (Portrait, LandscapeNormal,
LandscapeFlipped) and made:
▪ drawPixel, drawImage, displayWindow map logical coordinates
differently depending on orientation.
▪ getScreenWidth() / getScreenHeight() return orientation‑aware logical
dimensions (480×800 in portrait, 800×480 in landscape).
◦ Settings / Configuration
▪ Extended CrossPointSettings with:
▪ landscapeReading (toggle for portrait vs. landscape EPUB reading).
▪ landscapeFlipped (toggle to flip landscape 180° so both horizontal
holding directions are supported).
▪ Updated settings serialization/deserialization to persist these fields
while remaining backward‑compatible with existing settings files.
▪ Updated SettingsActivity to expose two new toggles:
▪ “Landscape Reading”
▪ “Flip Landscape (swap top/bottom)”
◦ EPUB Reader
▪ In EpubReaderActivity:
▪ On onEnter, set GfxRenderer orientation based on the new settings
(Portrait, LandscapeNormal, or LandscapeFlipped).
▪ On onExit, reset orientation back to Portrait so Home, WiFi, Settings,
etc. continue to render as before.
▪ Adjusted renderStatusBar to position the status bar and battery
indicator relative to GfxRenderer::getScreenHeight() instead of
hard‑coded Y coordinates, so it stays correctly at the bottom in both
portrait and landscape.
◦ EPUB Caching / Layout
▪ Extended Section cache metadata (section.bin) to include the logical
screenWidth and screenHeight used when pages were generated; bumped
SECTION_FILE_VERSION.
▪ Updated loadCacheMetadata to compare:
▪ font/margins/line compression/extraParagraphSpacing and screen
dimensions; mismatches now invalidate and clear the cache.
▪ Updated persistPageDataToSD and all call sites in EpubReaderActivity
to pass the current GfxRenderer::getScreenWidth() / getScreenHeight() so
portrait and landscape caches are kept separate and correctly sized.
Additional Context
• Cache behavior / migration
◦ Existing section.bin files (old SECTION_FILE_VERSION) will be detected
as incompatible and their caches cleared and rebuilt once per chapter
when first opened after this change.
◦ Within a given orientation, caches will be reused as before. Switching
orientation (portrait ↔ landscape) will cause a one‑time re‑index of
each chapter in the new orientation.
• Scope and risks
◦ Orientation changes are scoped to the EPUB reader; the Home screen,
Settings, WiFi selection, sleep screens, and web server UI continue to
assume portrait orientation.
◦ The renderer’s orientation is a static/global setting; if future code
uses GfxRenderer outside the reader while a reader instance is active,
it should be aware that orientation is no longer implicitly fixed.
◦ All drawing primitives now go through orientation‑aware coordinate
transforms; any code that previously relied on edge‑case behavior or
out‑of‑bounds writes might surface as logged “Outside range” warnings
instead.
• Testing suggestions / areas to focus on
◦ Verify in hardware:
▪ Portrait mode still renders correctly (boot, home, settings, WiFi,
reader).
▪ Landscape reading in both directions:
▪ Landscape Reading = ON, Flip Landscape = OFF.
▪ Landscape Reading = ON, Flip Landscape = ON.
▪ Status bar (page X/Y, % progress, battery icon) is fully visible and
aligned at the bottom in all three combinations.
◦ Open the same book:
▪ In portrait first, then switch to landscape and reopen it.
▪ Confirm that:
▪ Old portrait caches are rebuilt once for landscape (you should see the
“Indexing…” page).
▪ Progress save/restore still works (resume opens to the correct page in
the current orientation).
◦ Ensure grayscale rendering (the secondary pass in
EpubReaderActivity::renderContents) still looks correct in both
orientations.
---------
Co-authored-by: Dave Allie <dave@daveallie.com>
2025-12-28 05:33:20 -05:00
|
|
|
viewportWidth(viewportWidth),
|
|
|
|
|
viewportHeight(viewportHeight),
|
2026-01-19 17:56:26 +05:00
|
|
|
hyphenationEnabled(hyphenationEnabled),
|
2025-12-28 13:59:44 +09:00
|
|
|
completePageFn(completePageFn),
|
feat: Add CSS parsing and CSS support in EPUBs (#411)
## Summary
* **What is the goal of this PR?**
- Adds basic CSS parsing to EPUBs and determine the CSS rules when
rendering to the screen so that text is styled correctly. Currently
supports bold, underline, italics, margin, padding, and text alignment
## Additional Context
- My main reason for wanting this is that the book I'm currently
reading, Carl's Doomsday Scenario (2nd in the Dungeon Crawler Carl
series), relies _a lot_ on styled text for telling parts of the story.
When text is bolded, it's supposed to be a message that's rendered
"on-screen" in the story. When characters are "chatting" with each
other, the text is bolded and their names are underlined. Plus, normal
emphasis is provided with italicizing words here and there. So, this
greatly improves my experience reading this book on the Xteink, and I
figured it was useful enough for others too.
- For transparency: I'm a software engineer, but I'm mostly frontend and
TypeScript/JavaScript. It's been _years_ since I did any C/C++, so I
would not be surprised if I'm doing something dumb along the way in this
code. Please don't hesitate to ask for changes if something looks off. I
heavily relied on Claude Code for help, and I had a lot of inspiration
from how [microreader](https://github.com/CidVonHighwind/microreader)
achieves their CSS parsing and styling. I did give this as good of a
code review as I could and went through everything, and _it works on my
machine_ 😄
### Before


### After


---
### AI Usage
Did you use AI tools to help write this code? **YES**, Claude Code
2026-02-05 05:28:10 -05:00
|
|
|
popupFn(popupFn),
|
2026-02-06 02:49:04 -05:00
|
|
|
cssParser(cssParser),
|
2026-02-16 08:56:59 +00:00
|
|
|
embeddedStyle(embeddedStyle),
|
2026-03-03 16:59:06 +01:00
|
|
|
imageRendering(imageRendering),
|
2026-02-16 08:56:59 +00:00
|
|
|
contentBase(contentBase),
|
|
|
|
|
imageBasePath(imageBasePath) {}
|
feat: Add CSS parsing and CSS support in EPUBs (#411)
## Summary
* **What is the goal of this PR?**
- Adds basic CSS parsing to EPUBs and determine the CSS rules when
rendering to the screen so that text is styled correctly. Currently
supports bold, underline, italics, margin, padding, and text alignment
## Additional Context
- My main reason for wanting this is that the book I'm currently
reading, Carl's Doomsday Scenario (2nd in the Dungeon Crawler Carl
series), relies _a lot_ on styled text for telling parts of the story.
When text is bolded, it's supposed to be a message that's rendered
"on-screen" in the story. When characters are "chatting" with each
other, the text is bolded and their names are underlined. Plus, normal
emphasis is provided with italicizing words here and there. So, this
greatly improves my experience reading this book on the Xteink, and I
figured it was useful enough for others too.
- For transparency: I'm a software engineer, but I'm mostly frontend and
TypeScript/JavaScript. It's been _years_ since I did any C/C++, so I
would not be surprised if I'm doing something dumb along the way in this
code. Please don't hesitate to ask for changes if something looks off. I
heavily relied on Claude Code for help, and I had a lot of inspiration
from how [microreader](https://github.com/CidVonHighwind/microreader)
achieves their CSS parsing and styling. I did give this as good of a
code review as I could and went through everything, and _it works on my
machine_ 😄
### Before


### After


---
### AI Usage
Did you use AI tools to help write this code? **YES**, Claude Code
2026-02-05 05:28:10 -05:00
|
|
|
|
2025-12-13 19:36:01 +11:00
|
|
|
~ChapterHtmlSlimParser() = default;
|
2025-12-06 20:57:24 +11:00
|
|
|
bool parseAndBuildPages();
|
2025-12-13 20:10:16 +11:00
|
|
|
void addLineToPage(std::shared_ptr<TextBlock> line);
|
2025-12-06 20:57:24 +11:00
|
|
|
};
|