Compare commits

..

25 Commits

Author SHA1 Message Date
Dave Allie 5fdf23f1d2 Cut release 0.12.0 2026-01-03 19:42:14 +11:00
Justinian 2fb417ee90 Feat/sleep and refresh settings (#209)
## Summary

* **What is the goal of this PR?** (e.g., Fixes a bug in the user
authentication module, Implements the new feature for
  file uploading.)
* **What changes are included?**

## Additional Context

* Add any other information that might be helpful for the reviewer
(e.g., performance implications, potential risks, specific areas to
focus on).

---------

Co-authored-by: ratedcounsel <hello@ratedcounsel.com>
Co-authored-by: Dave Allie <dave@daveallie.com>
2026-01-03 19:33:42 +11:00
V c8f6160fbc Refactor semantic version comparison for OTA updates (#216)
## Summary

* **What is the goal of this PR?** (e.g., Fixes a bug in the user
authentication module, Implements the new feature for
  file uploading.)

This PR refactors the semantic version comparison logic used during OTA
update checks.

Memory stats before : 
RAM:   [===       ]  30.8% (used 101068 bytes from 327680 bytes)
Flash: [========= ]  85.7% (used **5617830** bytes from 6553600 bytes)

Memory stats before : 
RAM:   [===       ]  30.8% (used 101068 bytes from 327680 bytes)
Flash: [========= ]  85.7% (used **5616870** bytes from 6553600 bytes)


* **What changes are included?**

Replaced std::string::substr() and std::stoi() based parsing with a
lightweight, heap-free approach.
Version parsing is now done in a single pass without creating temporary
std::string objects.
Behavior remains identical: versions are still compared as
MAJOR.MINOR.PATCH.

## Additional Context

`std::string::substr() ` creates a new string and performs heap
allocation

* Add any other information that might be helpful for the reviewer
(e.g., performance implications, potential risks, specific areas to
focus on).
2026-01-03 19:19:53 +11:00
Brendan O'Leary 8e4484cd22 Add buton hints to keyboard screen (#205)
## Summary

This adds the correctly styled button hints to the keyboard screen as
well as the ability to add hints to the side buttons (and up/down hints
to that screen)

## Additional Context

N/A
2026-01-03 19:17:53 +11:00
Pavel Liashkov 0332e1103a Add EPUB 3 nav.xhtml TOC support (#197)
## Summary

* **What is the goal of this PR?** Add EPUB 3 support by implementing
native navigation document (nav.xhtml) parsing with NCX fallback,
addressing issue Fixes: #143.

  * **What changes are included?**
- New `TocNavParser` for parsing EPUB 3 HTML5 navigation documents
(`<nav epub:type="toc">`)
- Detection of nav documents via `properties="nav"` attribute in OPF
manifest
- Fallback logic: try EPUB 3 nav first, fall back to NCX (EPUB 2) if
unavailable
- Graceful degradation: books without any TOC now load with a warning
instead of failing

  ## Additional Context

* The implementation follows the existing streaming XML parser pattern
using Expat to minimize RAM usage on the ESP32-C3
* EPUB 3 books that include both nav.xhtml and toc.ncx will prefer the
nav document (per EPUB 3 spec recommendation)
* No breaking changes - existing EPUB 2 books continue to work as before
* Tested on examples from
https://idpf.github.io/epub3-samples/30/samples.html
2026-01-03 19:10:35 +11:00
Jonas Diemer 5790d6f5dc Subtract time it took reaching the evaluation from the press duration. (#208)
Adresses #206
2026-01-03 18:54:23 +11:00
Jake Lyell 062d69dc2a Add support for uploading multiple epubs (#202)
Upload multiple files at once in sequence. Add retry button for files
that fail

## Summary

* **What is the goal of this PR?**
Add support for selecting multiple epub files in one go, before
uploading them all to the device
* **What changes are included?**
Allow multiple selections to be submitted to the input field.
Sends each file to the device one by one in a loop
Adds retry logic and UI for easy re-trying of failed uploads

Addresses #201 


button now says "Choose Files", and shows the number of files you
selected
<img width="506" height="199" alt="image"
src="https://github.com/user-attachments/assets/64b0b921-1e67-438e-9cd7-57d5466f2456"
/>

Shows which file is uploading:
<img width="521" height="283" alt="image"
src="https://github.com/user-attachments/assets/17b4d349-0698-4712-984c-b72fcdcb0918"
/>

Failed upload dialog:
<img width="851" height="441" alt="image"
src="https://github.com/user-attachments/assets/e8bf4aa6-d3d2-4c0b-9c7a-420e8c413033"
/>
<img width="834" height="641" alt="image"
src="https://github.com/user-attachments/assets/656a9732-3963-4844-94e3-4d8736f6d9d5"
/>
2026-01-02 18:32:26 +11:00
Maeve Andrews 5e9626eb2a Add paragraph alignment setting (justify/left/center/right) (#191)
## Summary

* **What is the goal of this PR?** 

Add a new user setting for paragraph alignment, instead of hard-coding
full justification.

* **What changes are included?**

One new line in the settings screen, with 4 options
(justify/left/center/right). Default is justified since that's what it
was already. I personally only wanted to disable justification and use
"left", but I included the other options for completeness since they
were already supported.

## Additional Context

Tested on my X4 and looks as expected for each alignment.

Co-authored-by: Maeve Andrews <maeve@git.mail.maeveandrews.com>
2026-01-02 18:21:48 +11:00
Jonas Diemer 00e83af4e8 Show "Entering Sleep" on black, so it's quicker to notice (in book). (#181)
Black popup is easier to notice at higher contrast.
2026-01-02 17:55:21 +11:00
Jonas Diemer 39080c0e51 Skip soft hyphens. (#195)
For now, let's skip the soft hyphens (later, we can treat them in the
layouter). See
https://github.com/daveallie/crosspoint-reader/discussions/17#discussioncomment-15378475
2026-01-02 17:54:46 +11:00
Brendan O'Leary 9e59a5106b Fix race condition with keyboard and Wifi entry (#204)
## Summary

* **What is the goal of this PR?** Fixes a bug -
https://github.com/daveallie/crosspoint-reader/issues/187 - where the
screen would freeze after entering a WiFi password, causing the device
to appear hung.

* **What changes are included?**
- Fixed a race condition in `WifiSelectionActivity::displayTaskLoop()`
that caused rendering of an empty screen when transitioning from the
keyboard subactivity
- Added `vTaskDelay()` when a subactivity is active to prevent CPU
starvation from a tight `continue` loop
- Added a check to skip rendering when in `PASSWORD_ENTRY` state,
allowing the state machine to properly transition to `CONNECTING` before
the display updates

## Additional Context

* **Root cause:** When the keyboard subactivity exited after password
entry, the display task would wake up and attempt to render. However,
the `state` was still `PASSWORD_ENTRY` (before `attemptConnection()`
changed it to `CONNECTING`), and since there was no render case for
`PASSWORD_ENTRY`, the display would show a cleared/empty buffer,
appearing frozen.

* **Performance implications:** The added `vTaskDelay(10)` calls when
subactivity is active or in `PASSWORD_ENTRY` state actually improve
performance by preventing CPU starvation - previously the display task
would spin in a tight loop with `continue` while a subactivity was
present.

* **Testing focus:** Test the full WiFi connection flow:
  1. Enter network selection
  2. Select a network requiring a password
  3. Enter password and press OK
  4. Verify "Connecting..." screen appears
  5. Verify connection completes and prompts to save password
2026-01-02 17:49:16 +11:00
Pavel Liashkov a922e553ed Prevent device sleep during WiFi file transfer and OTA updates (#203)
## Summary

* **What is the goal of this PR?** Fixes #199 - Device falls asleep
during WiFi file transfer after 10 minutes of inactivity, disconnecting
the web server.

  * **What changes are included?**
    - Add `preventAutoSleep()` virtual method to `Activity` base class
- Modify main loop to reset inactivity timer when `preventAutoSleep()`
returns true
- Override `preventAutoSleep()` in `CrossPointWebServerActivity`
(returns true when web server running)
- Override `preventAutoSleep()` in `OtaUpdateActivity` (returns true
during update check/download)

  ## Additional Context

* The existing `skipLoopDelay()` method controls loop timing (yield vs
delay) for HTTP responsiveness. The new `preventAutoSleep()` method is
semantically separate - it explicitly signals that an activity should
keep the device awake.
* `CrossPointWebServerActivity` uses both methods: `skipLoopDelay()` for
responsive HTTP handling, `preventAutoSleep()` for staying awake.
* `OtaUpdateActivity` only needs `preventAutoSleep()` since the OTA
library handles HTTP internally.
2026-01-02 17:44:17 +11:00
Dave Allie 04ad4e5aa4 Replace book and section bin format images with ImHex hexpat definition (#189)
## Summary

* Replace book and section bin format images with ImHex hexpat
definition
* This should give readers an understanding of the file format but also
supply some utility when validating content/output
2025-12-31 13:28:24 +11:00
Dave Allie 6e9ba1006a Use sane smaller data types for data in section.bin (#188)
## Summary

* Update EpdFontFamily::Style to be u8 instead of u32 (saving 3 bytes
per word)
* Update layout width/height to be u16 from int
* Update page element count to be u16 from u32
* Update text block element count to be u16 from u32
* Bumped section bin version to version 8
2025-12-31 13:11:36 +11:00
Luke Stein 40f9ed485c Enhance USER_GUIDE with links and clarifications (#185)
Updated USER_GUIDE.md for clarity and added links to sections.

## Summary

* Clarify and improve documentation
2025-12-31 10:01:48 +11:00
Dave Allie b82e044ac3 Cut release 0.11.2 2025-12-31 09:28:14 +11:00
Dave Allie 026733a4fe Hide "System Volume Information" folder (#184)
## Summary

* Hide "System Volume Information" folder
* It's a FAT filesystem folder, shouldn't be used

## Additional Context

* Fixes https://github.com/daveallie/crosspoint-reader/issues/177
2025-12-31 09:27:17 +11:00
Dave Allie 57b075ec97 Update README.md features 2025-12-31 09:18:05 +11:00
dangson 648c688642 Update button hints on OTA update screen and update user guide to reflect current settings (#183)
## Summary

- Update the button hints on the OTA update screen to reflect the
current front button layout.
- Update user guide to reflect current available settings. A lot has
been added recently!
2025-12-31 09:15:40 +11:00
Jonas Diemer 06065dfd8b Show book title instead of "Select Chapter". (#169)
I think this is nicer ;)
2025-12-31 09:10:41 +11:00
Eunchurn Park 93226c9fbb Fix file browser navigation for non-ASCII folder names (#178)
## Summary

* **What is the goal of this PR?**

Fix file browser failing to navigate into subdirectories with non-ASCII
(Korean/Unicode) folder names.

* **What changes are included?**

- Enable UTF-8 long file names in SdFat (`USE_UTF8_LONG_NAMES=1`)
- Add directory validation before iterating files
- Add `rewindDirectory()` call for stability

## Additional Context
2025-12-31 09:08:31 +11:00
Dave Allie 941643cf97 Cut release 0.11.1 2025-12-31 02:47:24 +11:00
Dave Allie 9bba41ed96 Move home screen battery indicator to avoid clashing with button hints (#174)
## Summary

* Move home screen battery indicator to avoid clashing with button hints
* Default button mapping was fine, but others clashes with the indicator
2025-12-31 02:46:46 +11:00
Dave Allie 34cf5f0636 Add button mapping for Left, Back, Confirm, Right (#173)
## Summary

* Add button mapping for Left, Back, Confirm, Right for front buttons

## Additional Context

* Asked for in
https://github.com/daveallie/crosspoint-reader/discussions/78#discussioncomment-15375326
2025-12-31 02:46:35 +11:00
Dave Allie f2ca65d752 Swap from Aleo to Bookerly for wider glyph support (#172)
## Summary

* Swap from Aleo to Bookerly for wider glyph support
* Swap from Space Grotesk to a small Noto Sans

## Additional Context

* 0.11.0 swapped to Aleo which has a few issues (things like Cyrillic
support for eg)
2025-12-31 02:28:25 +11:00
101 changed files with 93627 additions and 45863 deletions
+7 -5
View File
@@ -25,7 +25,7 @@ This project is **not affiliated with Xteink**; it's built as a community projec
## Features & Usage
- [x] EPUB parsing and rendering
- [x] EPUB parsing and rendering (EPUB 2 and EPUB 3)
- [ ] Image support within EPUB
- [x] Saved reading position
- [x] File explorer with file picker
@@ -33,11 +33,13 @@ This project is **not affiliated with Xteink**; it's built as a community projec
- [x] Support nested folders
- [ ] EPUB picker with cover art
- [x] Custom sleep screen
- [ ] Cover sleep screen
- [x] Cover sleep screen
- [x] Wifi book upload
- [ ] Wifi OTA updates
- [ ] Configurable font, layout, and display options
- [ ] Screen rotation
- [x] Wifi OTA updates
- [x] Configurable font, layout, and display options
- [ ] User provided fonts
- [ ] Full UTF support
- [x] Screen rotation
See [the user guide](./USER_GUIDE.md) for instructions on operating CrossPoint.
+39 -17
View File
@@ -5,7 +5,7 @@ the device.
## 1. Hardware Overview
The device utilises the standard buttons on the Xtink X4 in the same layout:
The device utilises the standard buttons on the Xtink X4 (in the same layout as the manufacturer firmware, by default):
### Button Layout
| Location | Buttons |
@@ -13,20 +13,23 @@ The device utilises the standard buttons on the Xtink X4 in the same layout:
| **Bottom Edge** | **Back**, **Confirm**, **Left**, **Right** |
| **Right Side** | **Power**, **Volume Up**, **Volume Down** |
Button layout can be customized in **[Settings](#35-settings)**.
---
## 2. Power & Startup
### Power On / Off
To turn the device on or off, **press and hold the Power button for half a second**. In **Settings** you can configure
To turn the device on or off, **press and hold the Power button for half a second**. In **[Settings](#35-settings)** you can configure
the power button to trigger on a short press instead of a long one.
### First Launch
Upon turning the device on for the first time, you will be placed on the **Home** screen.
Upon turning the device on for the first time, you will be placed on the **[Home](#31-home-screen)** screen.
> **Note:** On subsequent restarts, the firmware will automatically reopen the last book you were reading.
> [!NOTE]
> On subsequent restarts, the firmware will automatically reopen the last book you were reading.
---
@@ -34,10 +37,10 @@ Upon turning the device on for the first time, you will be placed on the **Home*
### 3.1 Home Screen
The Home Screen is the main entry point to the firmware. From here you can navigate to the **Book Selection** screen,
**Settings** screen, or **File Upload** screen.
The Home Screen is the main entry point to the firmware. From here you can navigate to **[Reading Mode](#4-reading-mode)** with the most recently read book, **[Book Selection](#32-book-selection)**,
**[Settings](#35-settings)**, or the **[File Upload](#34-file-upload-screen)** screen.
### 3.2 Book Selection (Read)
### 3.2 Book Selection
The Book Selection acts as a folder and file browser.
@@ -45,13 +48,13 @@ The Book Selection acts as a folder and file browser.
and down through folders and books.
* **Open Selection:** Press **Confirm** to open a folder or read a selected book.
### 3.3 Reading Screen
### 3.3 Reading Mode
See [4. Reading Mode](#4-reading-mode) below for more information.
See [Reading Mode](#4-reading-mode) below for more information.
### 3.4 File Upload Screen
The File Upload screen allows you to upload new e-books to the device. When you enter the screen you'll be prompted with
The File Upload screen allows you to upload new e-books to the device. When you enter the screen, you'll be prompted with
a WiFi selection dialog and then your X4 will start hosting a web server.
See the [webserver docs](./docs/webserver.md) for more information on how to connect to the web server and upload files.
@@ -62,12 +65,32 @@ The Settings screen allows you to configure the device's behavior. There are a f
- **Sleep Screen**: Which sleep screen to display when the device sleeps, options are:
- "Dark" (default) - The default dark sleep screen
- "Light" - The same default sleep screen, on a white background
- "Custom" - Custom images from the SD card, see [3.6 Sleep Screen](#36-sleep-screen) below for more information
- "Custom" - Custom images from the SD card, see [Sleep Screen](#36-sleep-screen) below for more information
- "Cover" - The book cover image (Note: this is experimental and may not work as expected)
- **Status Bar**: Configure the status bar displayed while reading, options are:
- "None" - No status bar
- "No Progress" - Show status bar without reading progress
- "Full" - Show status bar with reading progress
- **Extra Paragraph Spacing**: If enabled, vertical space will be added between paragraphs in the book, if disabled,
paragraphs will not have vertical space between them, but will have first word indentation.
- **Short Power Button Click**: Whether to trigger the power button on a short press or a long press.
- **Front Button Layout**: Swap the order of the bottom edge buttons from Back/Confirm/Left/Right to Left/Right/Back/Confirm.
- **Reading Orientation**: Set the screen orientation for reading, options are:
- "Portrait" (default) - Standard portrait orientation
- "Landscape CW" - Landscape, rotated clockwise
- "Inverted" - Portrait, upside down
- "Landscape CCW" - Landscape, rotated counter-clockwise
- **Front Button Layout**: Configure the order of the bottom edge buttons, options are:
- "Bck, Cnfrm, Lft, Rght" (default) - Back, Confirm, Left, Right
- "Lft, Rght, Bck, Cnfrm" - Left, Right, Back, Confirm
- "Lft, Bck, Cnfrm, Rght" - Left, Back, Confirm, Right
- **Side Button Layout**: Swap the order of the volume buttons from Previous/Next to Next/Previous. This change is only in effect when reading.
- **Reader Font Family**: Choose the font used for reading, options are:
- "Bookerly" (default) - Amazon's reading font
- "Noto Sans" - Google's sans-serif font
- "Open Dyslexic" - Font designed for readers with dyslexia
- **Reader Font Size**: Adjust the text size for reading, options are "Small", "Medium", "Large", or "X Large".
- **Reader Line Spacing**: Adjust the spacing between lines, options are "Tight", "Normal", or "Wide".
- **Check for updates**: Check for firmware updates over WiFi.
### 3.6 Sleep Screen
@@ -75,7 +98,7 @@ You can customize the sleep screen by placing custom images in specific location
- **Single Image:** Place a file named `sleep.bmp` in the root directory.
- **Multiple Images:** Create a `sleep` directory in the root of the SD card and place any number of `.bmp` images
inside. If images are found in this directory, they will take priority over the `sleep.png` file, and one will be
inside. If images are found in this directory, they will take priority over the `sleep.bmp` file, and one will be
randomly selected each time the device sleeps.
> [!NOTE]
@@ -103,8 +126,9 @@ Once you have opened a book, the button layout changes to facilitate reading.
* **Previous Chapter:** Press and **hold** the **Left** (or **Volume Up**) button briefly, then release.
### System Navigation
* **Return to Home:** Press **Back** to close the book and return to the Book Selection screen.
* **Chapter Menu:** Press **Confirm** to open the Table of Contents/Chapter Selection screen.
* **Return to Book Selection:** Press **Back** to close the book and return to the **[Book Selection](#32-book-selection)** screen.
* **Return to Home:** Press and hold **Back** to close the book and return to the **[Home](#31-home-screen)** screen.
* **Chapter Menu:** Press **Confirm** to open the **[Table of Contents/Chapter Selection](#5-chapter-selection-screen)**.
---
@@ -124,5 +148,3 @@ Please note that this firmware is currently in active development. The following
are planned for future updates:
* **Images:** Embedded images in e-books will not render.
* **Text Formatting:** There are currently no settings to adjust font type, size, line spacing, or margins.
* **Rotation**: Different rotation options are not supported.
+214 -2
View File
@@ -2,8 +2,220 @@
## `book.bin`
![](./images/file-formats/book-bin.png)
### Version 3
ImHex Pattern:
```c++
import std.mem;
import std.string;
import std.core;
// === Configuration ===
#define EXPECTED_VERSION 3
#define MAX_STRING_LENGTH 65535
// === String Structure ===
struct String {
u32 length [[hidden, comment("String byte length")]];
if (length > MAX_STRING_LENGTH) {
std::warning(std::format("Unusually large string length: {} bytes", length));
}
char data[length] [[comment("UTF-8 string data")]];
} [[sealed, format("format_string"), comment("Length-prefixed UTF-8 string")]];
fn format_string(String s) {
return s.data;
};
// === Metadata Structure ===
struct Metadata {
String title [[comment("Book title")]];
String author [[comment("Book author")]];
String coverItemHref [[comment("Path to cover image")]];
String textReferenceHref [[comment("Path to guided first text reference")]];
} [[comment("Book metadata information")]];
// === Spine Entry Structure ===
struct SpineEntry {
String href [[comment("Resource path")]];
u32 cumulativeSize [[comment("Cumulative size in bytes"), color("FF6B6B")]];
s16 tocIndex [[comment("Index into TOC (-1 if none)"), color("4ECDC4")]];
} [[comment("Spine entry defining reading order")]];
// === TOC Entry Structure ===
struct TocEntry {
String title [[comment("Chapter/section title")]];
String href [[comment("Resource path")]];
String anchor [[comment("Fragment identifier")]];
u8 level [[comment("Nesting level (0-255)"), color("95E1D3")]];
s16 spineIndex [[comment("Index into spine (-1 if none)"), color("F38181")]];
} [[comment("Table of contents entry")]];
// === Book Bin Structure ===
struct BookBin {
// Header
u8 version [[comment("Format version"), color("FFD93D")]];
// Version validation
if (version != EXPECTED_VERSION) {
std::error(std::format("Unsupported version: {} (expected {})", version, EXPECTED_VERSION));
}
u32 lutOffset [[comment("Offset to lookup tables"), color("6BCB77")]];
u16 spineCount [[comment("Number of spine entries"), color("4D96FF")]];
u16 tocCount [[comment("Number of TOC entries"), color("FF6B9D")]];
// Metadata section
Metadata metadata [[comment("Book metadata")]];
// Validate LUT offset alignment
u32 currentOffset = $;
if (currentOffset != lutOffset) {
std::warning(std::format("LUT offset mismatch: expected 0x{:X}, got 0x{:X}", lutOffset, currentOffset));
}
// Lookup Tables
u32 spineLut[spineCount] [[comment("Spine entry offsets"), color("4D96FF")]];
u32 tocLut[tocCount] [[comment("TOC entry offsets"), color("FF6B9D")]];
// Data Entries
SpineEntry spines[spineCount] [[comment("Spine entries (reading order)")]];
TocEntry toc[tocCount] [[comment("Table of contents entries")]];
};
// === File Parsing ===
BookBin book @ 0x00;
// Validate we've consumed the entire file
u32 fileSize = std::mem::size();
u32 parsedSize = $;
if (parsedSize != fileSize) {
std::warning(std::format("Unparsed data detected: {} bytes remaining at offset 0x{:X}", fileSize - parsedSize, parsedSize));
}
```
## `section.bin`
![](./images/file-formats/section-bin.png)
### Version 8
ImHex Pattern:
```c++
import std.mem;
import std.string;
import std.core;
// === Configuration ===
#define EXPECTED_VERSION 8
#define MAX_STRING_LENGTH 65535
// === String Structure ===
struct String {
u32 length [[hidden, comment("String byte length")]];
if (length > MAX_STRING_LENGTH) {
std::warning(std::format("Unusually large string length: {} bytes", length));
}
char data[length] [[comment("UTF-8 string data")]];
} [[sealed, format("format_string"), comment("Length-prefixed UTF-8 string")]];
fn format_string(String s) {
return s.data;
};
// === Page Structure ===
enum StorageType : u8 {
PageLine = 1
};
enum WordStyle : u8 {
REGULAR = 0,
BOLD = 1,
ITALIC = 2,
BOLD_ITALIC = 3
};
enum BlockStyle : u8 {
JUSTIFIED = 0,
LEFT_ALIGN = 1,
CENTER_ALIGN = 2,
RIGHT_ALIGN = 3,
};
struct PageLine {
s16 xPos;
s16 yPos;
u16 wordCount;
String words[wordCount];
u16 wordXPos[wordCount];
WordStyle wordStyle[wordCount];
BlockStyle blockStyle;
};
struct PageElement {
u8 pageElementType;
if (pageElementType == 1) {
PageLine pageLine [[inline]];
} else {
std::error(std::format("Unknown page element type: {}", pageElementType));
}
};
struct Page {
u16 elementCount;
PageElement elements[elementCount] [[inline]];
};
// === Section Bin Structure ===
struct SectionBin {
// Header
u8 version [[comment("Format version"), color("FFD93D")]];
// Version validation
if (version != EXPECTED_VERSION) {
std::error(std::format("Unsupported version: {} (expected {})", version, EXPECTED_VERSION));
}
// Cache busting parameters
s32 fontId;
float lineCompression;
bool extraParagraphSpacing;
u16 viewportWidth;
u16 vieportHeight;
u16 pageCount;
u32 lutOffset;
Page page[pageCount];
// Validate LUT offset alignment
u32 currentOffset = $;
if (currentOffset != lutOffset) {
std::warning(std::format("LUT offset mismatch: expected 0x{:X}, got 0x{:X}", lutOffset, currentOffset));
}
// Lookup Tables
u32 lut[pageCount];
};
// === File Parsing ===
SectionBin book @ 0x00;
// Validate we've consumed the entire file
u32 fileSize = std::mem::size();
u32 parsedSize = $;
if (parsedSize != fileSize) {
std::warning(std::format("Unparsed data detected: {} bytes remaining at offset 0x{:X}", fileSize - parsedSize, parsedSize));
}
```
Binary file not shown.

Before

Width:  |  Height:  |  Size: 539 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 296 KiB

+5 -5
View File
@@ -1,6 +1,6 @@
#include "EpdFontFamily.h"
const EpdFont* EpdFontFamily::getFont(const EpdFontStyle style) const {
const EpdFont* EpdFontFamily::getFont(const Style style) const {
if (style == BOLD && bold) {
return bold;
}
@@ -22,16 +22,16 @@ const EpdFont* EpdFontFamily::getFont(const EpdFontStyle style) const {
return regular;
}
void EpdFontFamily::getTextDimensions(const char* string, int* w, int* h, const EpdFontStyle style) const {
void EpdFontFamily::getTextDimensions(const char* string, int* w, int* h, const Style style) const {
getFont(style)->getTextDimensions(string, w, h);
}
bool EpdFontFamily::hasPrintableChars(const char* string, const EpdFontStyle style) const {
bool EpdFontFamily::hasPrintableChars(const char* string, const Style style) const {
return getFont(style)->hasPrintableChars(string);
}
const EpdFontData* EpdFontFamily::getData(const EpdFontStyle style) const { return getFont(style)->data; }
const EpdFontData* EpdFontFamily::getData(const Style style) const { return getFont(style)->data; }
const EpdGlyph* EpdFontFamily::getGlyph(const uint32_t cp, const EpdFontStyle style) const {
const EpdGlyph* EpdFontFamily::getGlyph(const uint32_t cp, const Style style) const {
return getFont(style)->getGlyph(cp);
};
+14 -14
View File
@@ -1,24 +1,24 @@
#pragma once
#include "EpdFont.h"
enum EpdFontStyle { REGULAR, BOLD, ITALIC, BOLD_ITALIC };
class EpdFontFamily {
public:
enum Style : uint8_t { REGULAR = 0, BOLD = 1, ITALIC = 2, BOLD_ITALIC = 3 };
explicit EpdFontFamily(const EpdFont* regular, const EpdFont* bold = nullptr, const EpdFont* italic = nullptr,
const EpdFont* boldItalic = nullptr)
: regular(regular), bold(bold), italic(italic), boldItalic(boldItalic) {}
~EpdFontFamily() = default;
void getTextDimensions(const char* string, int* w, int* h, Style style = REGULAR) const;
bool hasPrintableChars(const char* string, Style style = REGULAR) const;
const EpdFontData* getData(Style style = REGULAR) const;
const EpdGlyph* getGlyph(uint32_t cp, Style style = REGULAR) const;
private:
const EpdFont* regular;
const EpdFont* bold;
const EpdFont* italic;
const EpdFont* boldItalic;
const EpdFont* getFont(EpdFontStyle style) const;
public:
explicit EpdFontFamily(const EpdFont* regular, const EpdFont* bold = nullptr, const EpdFont* italic = nullptr,
const EpdFont* boldItalic = nullptr)
: regular(regular), bold(bold), italic(italic), boldItalic(boldItalic) {}
~EpdFontFamily() = default;
void getTextDimensions(const char* string, int* w, int* h, EpdFontStyle style = REGULAR) const;
bool hasPrintableChars(const char* string, EpdFontStyle style = REGULAR) const;
const EpdFontData* getData(EpdFontStyle style = REGULAR) const;
const EpdGlyph* getGlyph(uint32_t cp, EpdFontStyle style = REGULAR) const;
const EpdFont* getFont(Style style) const;
};
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More