Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
c6fe67d
fix(ruby): don't flush while in a ruby group (#3102)
brianhuster Aug 18, 2026
27f964b
fix: stop negative font IDs from stealing scan slots (#3107)
serialx Aug 18, 2026
eef2050
fix: clear sleep image after wake (#3009)
thiagokokada Aug 18, 2026
a7a776a
fix: add `'` to the static HTML entity table (#3122)
Uri-Tauber Aug 19, 2026
a4a03c6
fix: don't use dithering for non alpha bmp transparent sleep screen (…
theZiz Aug 19, 2026
d28b939
feat: strip embedded fonts during EPUB optimization (#3085)
hyemin-ht-kang Aug 19, 2026
93d572f
feat(fonts): add script-group metadata to the font manifest (#2699)
Uri-Tauber Aug 20, 2026
7e42d07
fix(epub): ignore trailing non-XML data after </html> tag in ChapterH…
bjesus Aug 20, 2026
66a7ae1
feat(fonts): use Ubuntu Medium as the UI text weight (#3096)
fain182 Aug 20, 2026
75c079f
feat: Lower frontlight brightness for x4pro (#3115)
itsthisjustin Aug 20, 2026
3d5c4a5
feat: Scripts grouping in fonts manager (#3141)
Uri-Tauber Aug 20, 2026
da3d50c
feat: render EPUB tables as columns (#2654)
lpla Aug 21, 2026
d72ae2a
fix: fit Hebrew and Arabic UI fonts (#3151)
Uri-Tauber Aug 21, 2026
69dd947
fix: display chapter tilde in 10pt font (#3155)
uxjulia Aug 21, 2026
57c692f
fix: (dictionary) stop styled HTML definitions refusing their own fir…
jpirnay Aug 22, 2026
62e84a1
feat: Brings back features from the x4pro beta that everyone wanted (…
itsthisjustin Aug 22, 2026
cdbe2a7
feat: Language Ordering (#3184)
dasrecht Aug 23, 2026
139de1e
fix(settings): a tapped row doesn't keep the focus (touch boards) (#3…
jetaudio Aug 23, 2026
dc7bb07
fix(fonts): stop Ubuntu Medium glyphs colliding in the UI (#3186)
fain182 Aug 23, 2026
8575b14
feat: control center — quick-setting tiles on the frontlight panel (t…
jetaudio Aug 23, 2026
f58f9b8
fix: text-field line wrapping splits multi-byte characters (#3095)
winst0niuss Aug 24, 2026
6c5bc30
fix: block cursor mangles non-ASCII characters in cursor mode (#3094)
winst0niuss Aug 24, 2026
5182d27
fix: (dictionary) restore heading breaks in htmlToPlainText (#3153)
jpirnay Aug 24, 2026
dc65ccd
docs: fix Settings path for Manage Fonts (#3159)
yaneury Aug 24, 2026
cdd89b1
feat: Improve power button wake detection and timing (#3191)
itsthisjustin Aug 24, 2026
8665dd7
fix: run title check after PR pushes (#3202)
lpla Aug 24, 2026
5a6f3f5
fix: restore reader long-press shortcuts (#3120)
thiagokokada Aug 26, 2026
b6746c1
fix: retry low-memory CSS cache safely (#3005)
lpla Aug 26, 2026
c484dc7
perf: Reduce built-in font flash by 323 KB (sparse kerning, split cla…
jpirnay Aug 26, 2026
f0c6550
fix(x4pro): hold power-latch pins HIGH through deep sleep (#3215)
Belphemur Aug 26, 2026
b4cd1af
feat(reader): toolbar reader menu — an overlay over the page (opt-in)…
jetaudio Aug 26, 2026
8141d7b
perf: optimize style-aware font prewarm (#3222)
Uri-Tauber Aug 26, 2026
8bc1603
fix: Add fallback USB detection via battery charging state (#3223)
itsthisjustin Aug 26, 2026
820d0b9
chore: fix clang-format-21 violation in FontCacheManagerTest (#3230)
puls72s Aug 27, 2026
14cdb28
fix(KOSync): keep WiFi awake during KOReader authentication and sync …
jadehawk Aug 27, 2026
f24ef20
chore: fui cleanup (#3227)
Uri-Tauber Aug 27, 2026
e31dcbb
fix: don't recompile Arduino IDF libs (#3242)
Uri-Tauber Aug 28, 2026
218dc6a
feat: add usb mass storage mode for x4 pro (#3203)
uxjulia Aug 28, 2026
e82b517
fix: swedish translation (#3241)
steka Aug 28, 2026
4638119
docs: document X4 Pro frontlight controls (#3187)
puls72s Aug 28, 2026
e37164c
fix: cold-boot power-button misclassification (#3248)
itsthisjustin Aug 28, 2026
86976ab
fix: prevent size_t underflow on ZipFile read errors (#3244)
sfoulad Aug 28, 2026
b42927b
fix(KOSync): avoid redundant NTP sync before KOReader sync (#3185)
WhoTheHeck Aug 28, 2026
68be3ae
fix: show full IP address on Calibre screen (#3235)
fdkevin0 Aug 29, 2026
7a4c96d
fix(ui): match list row label and value font sizes (#3284)
fain182 Aug 29, 2026
4f0b4b7
fix: keep the home screen in portrait (#3264)
winst0niuss Aug 29, 2026
ecc0c4f
chore: ask for the device in the bug report template (#3272)
fain182 Aug 29, 2026
f021d1e
feat: Add support for Xteink X4 Classic board (#3279)
itsthisjustin Aug 29, 2026
88ddc9a
chore: Update docs (#3288)
itsthisjustin Aug 29, 2026
a56a7f0
fix: Switch XTC cover BMP output from 1-bit to 2-bit grayscale (#2335)
itsthisjustin Aug 29, 2026
790a081
fix: disable WiFi power-save during OPDS/book HTTP downloads (#3252)
sfoulad Aug 29, 2026
e7a3bb4
fix(reader): give the overlay and the end-of-book menu input preceden…
sfoulad Aug 30, 2026
3b73e7f
fix: Hide reader menu style setting on button boards & change refresh…
itsthisjustin Aug 31, 2026
52444a0
fix(epub): some problems when extra paragraph spacing is off (#3221)
brianhuster Aug 31, 2026
25bbfae
fix: dismiss the quick-settings sheet with a swipe up (#3267)
winst0niuss Aug 31, 2026
84fcff8
fix: release dictionary font caches on exit (#3317)
Uri-Tauber Aug 31, 2026
c3534ed
fix: Decouple reader menu gestures from touch controls (#3319)
adiskill Sep 1, 2026
3099231
fix(epub): stop font ligatures re-collapsing shaped Arabic/Persian Al…
aminalaee Sep 1, 2026
d5d2d67
feat(keyboard): user-selectable layout set with a language key (#2858)
winst0niuss Sep 1, 2026
ce6c6cb
fix: RTL inline direction inheritance (#3198)
Uri-Tauber Sep 1, 2026
8cb0a39
fix: Four small UX fixes (#3318)
Uri-Tauber Sep 1, 2026
fb0523d
chore: revert #3096 (#3314)
Uri-Tauber Sep 1, 2026
7bcc3a6
feat: add touch navigation for EPUB links (#3296)
Uri-Tauber Sep 1, 2026
e613986
feat: add Persian translation (#3338)
aminalaee Sep 1, 2026
4a679d5
fix: sd not shutting down on deep sleep & restores single click power…
itsthisjustin Sep 2, 2026
b95965f
fix(fonts): add missing Perso-Arabic glyphs to built-in UI fonts (U+0…
aminalaee Sep 2, 2026
badfa95
fix: restore superscript styling on footnote links (#3355)
uxjulia Sep 3, 2026
32a0cad
fix: regenerate stale built-in font content-hash IDs (#3359)
YuunJiee Sep 3, 2026
5fcd263
docs: fix outdated pioarduino links in README (#3362)
Oreoxmt Sep 3, 2026
1c4cebd
Merge CrossPoint develop (69 commits) and the FreeInk SDK fork
ma-r-s Sep 4, 2026
a71b14f
Finish the margin adoption, and point .gitmodules at a branch that ex…
ma-r-s Sep 4, 2026
73c6772
Make the merged tree build: fonts, the sim HAL, and two suites
ma-r-s Sep 4, 2026
a564d94
Get the simulator building again after the sync, and drop three orphans
ma-r-s Sep 4, 2026
ebfdaaa
Merge origin/xteink into app/upsync
ma-r-s Sep 4, 2026
8dd28ac
style: clang-format-21 the three files this sync left drifting
ma-r-s Sep 4, 2026
27b507e
sim_catchup: anchor the USB Drive patches on text the simulator alrea…
ma-r-s Sep 4, 2026
0e9e2c3
docs: .gitmodules no longer names a deleted branch
ma-r-s Sep 4, 2026
d3677ce
Merge remote-tracking branch 'origin/xteink' into app/upsync
ma-r-s Sep 4, 2026
d52eedc
Merge remote-tracking branch 'origin/xteink' into app/upsync2
ma-r-s Sep 4, 2026
7f8c573
fix(settings): Keyboard Layouts applies the safe area once
ma-r-s Sep 4, 2026
3e71fc2
chore: format the safe-area fix and rebuild the study tools archive
ma-r-s Sep 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/pr-formatting-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ on:
- opened
- reopened
- edited
- synchronize

permissions:
pull-requests: read
Expand Down
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[submodule "freeink-sdk"]
path = freeink-sdk
url = https://github.com/ma-r-s/freeink-sdk.git
branch = x4pro-measured-insets
branch = fix/sd-free-space
4 changes: 1 addition & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -887,9 +887,7 @@ Tested in all 4 orientations with 5MB+ files.
**To add/modify translations (i18n)**:

1. Edit or add YAML file: `lib/I18n/translations/<language>.yaml`

- Each file must contain: `_language_name`, `_language_code`, `_order`, and `STR_*` keys

- Each file must contain: `_language_name`, `_language_code`, `_order`, `_bcp47`, and `STR_*` keys
- English (`english.yaml`) is the reference; missing keys in other languages fall back to English

2. Run generator: `python scripts/gen_i18n.py lib/I18n/translations lib/I18n/`
Expand Down
2 changes: 1 addition & 1 deletion SCOPE.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ During this period, the priorities are:
PRs in the following areas will be closed until this notice is lifted. Adding these now makes the cleanup and multi-device work materially harder:

* **New themes.** The existing theming surface is frozen.
* **New external network connectors.** This includes sync engines, cloud storage clients, OPDS extensions beyond what exists, remote file access, and any new "talk to a server" feature. We now have our own CrossPoint KOSync server which gives us a way to sync to 3rd party systems like Hardcover at an API level instead of bloating the firmware. If you're interested in helping here, the sync server is also open source.
* **New external network connectors.** This includes sync engines, cloud storage clients, remote file access, and any new "talk to a server" feature. Fixes and improvements to the *existing* OPDS support (usability, performance, compatibility with more catalogs) remain in scope and welcome; what is closed is adding entirely new protocols or connectors. We now have our own CrossPoint KOSync server which gives us a way to sync to 3rd party systems like Hardcover at an API level instead of bloating the firmware. If you're interested in helping here, the sync server is also open source.

If you are unsure whether your idea falls into one of these categories, open a Discussion first.

Expand Down
42 changes: 30 additions & 12 deletions USER_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Welcome to the **CrossPlay** firmware, a fork of CrossPoint for the Xteink X4 Pr
- [1. Hardware Overview](#1-hardware-overview)
- [Button Layout](#button-layout)
- [Taking a Screenshot](#taking-a-screenshot)
- [Frontlight (X4 Pro only)](#frontlight-x4-pro-only)
- [2. Power \& Startup](#2-power--startup)
- [Power On / Off](#power-on--off)
- [First Launch](#first-launch)
Expand Down Expand Up @@ -42,6 +43,7 @@ Welcome to the **CrossPlay** firmware, a fork of CrossPoint for the Xteink X4 Pr
- [Auto Page Turn](#auto-page-turn)
- [Tilt Page Turn (X3 only)](#tilt-page-turn-x3-only)
- [Footnote Navigation](#footnote-navigation)
- [Dictionary Lookup](#dictionary-lookup)
- [System Navigation](#system-navigation)
- [Supported Languages](#supported-languages)
- [5. Reader Menu](#5-reader-menu)
Expand All @@ -59,16 +61,28 @@ The device utilises the standard buttons on the Xteink X4 (in the same layout as
| Location | Buttons |
| --------------- | ---------------------------------------------------- |
| **Bottom Edge** | **Back**, **Confirm**, **Left**, **Right** |
| **Right Side** | **Power**, **Volume Up**, **Volume Down**, **Reset** |
| **Right Side** | **Power**, **Side Up**, **Side Down**, **Reset** |

Button layout can be customized in the **[Controls Settings](#363-controls)**.

### Taking a Screenshot

When the Power Button and Volume Down button are pressed at the same time, it will take a screenshot and save it in the folder `screenshots/`.
When the Power button and the lower side button (Side Down) are pressed at the same time, it will take a screenshot and save it in the folder `screenshots/`.

Alternatively, while reading a book, press the **Confirm** button to open the reader menu and select **Take screenshot**.

### Frontlight (X4 Pro only)

The X4 Pro has a built-in frontlight with adjustable brightness and warmth. It is controlled from a swipe panel rather than the Settings menu:

* **Open the frontlight panel:** Swipe down from the top edge of the screen, from almost any screen (Home, Browse Files, Reading Mode, etc.). Drag the brightness and warmth sliders to adjust the light live, or tap the sun icon to turn it on or off.
* **Quick toggle:** Double-click the **Power** button to turn the frontlight on or off instantly, without opening the panel.

> [!NOTE]
> Frontlight brightness and warmth are intentionally not listed in **[Display Settings](#361-display)** — the swipe panel is the only place to adjust them. The on/off state can also be toggled with the Power-button double-click above.

If the frontlight doesn't come back on after the device wakes from sleep, check **Restore Light on Wake** in **[Display Settings](#361-display)** (on by default). Turning it off is intentional if you'd rather have the light stay off on wake and switch it on yourself each time — but it's easy to forget you changed it.

---

## 2. Power & Startup
Expand Down Expand Up @@ -103,7 +117,7 @@ See [Reading Mode](#4-reading-mode) below for more information.

The Browse Files screen acts as a file and folder browser. The full path to the current directory is shown at the top of the screen. File extensions are displayed alongside each filename, and directories are shown with brackets (e.g. `[folder-name]`). Hidden directories (those beginning with `.`) are also visible.

* **Navigate List:** Use **Left** (or **Volume Up**), or **Right** (or **Volume Down**) to move the selection cursor up and down through folders and books. You can also long-press these buttons to scroll a full page up or down.
* **Navigate List:** Use **Left** (or **Side Up**), or **Right** (or **Side Down**) to move the selection cursor up and down through folders and books. You can also long-press these buttons to scroll a full page up or down.
* **Open Selection:** Press **Confirm** to open a folder or start reading a selected book. Selecting a `.bmp` file will open the image viewer.
* **Delete Files or Folders:** Hold and release **Confirm** to delete the selected file or folder. You will be given an option to either confirm or cancel. Multiple files can be selected for deletion in a single operation.
* **Rename or Move:** Files can be renamed or moved to a different folder from within the browse screen.
Expand Down Expand Up @@ -275,7 +289,7 @@ The Settings screen allows you to configure the device's behavior. There are a f

- **Remap Front Buttons**: A menu for customising the function of each bottom edge button.

- **Side Button Layout (reader)**: Swap the order of the up and down volume buttons from "Prev/Next" (default) to "Next/Prev". You can also disable them entirely. This change is only in effect when reading.
- **Side Button Layout (reader)**: Swap the order of the up and down side buttons from "Prev/Next" (default) to "Next/Prev". You can also disable them entirely. This change is only in effect when reading.

- **Long-press Chapter Skip**: Set whether long-pressing page turn buttons skips to the next/previous chapter:

Expand Down Expand Up @@ -631,17 +645,17 @@ Once you have opened a book, the button layout changes to facilitate reading.

| Action | Buttons |
| ----------------- | ------------------------------------ |
| **Previous Page** | Press **Left** _or_ **Volume Up** |
| **Next Page** | Press **Right** _or_ **Volume Down** |
| **Previous Page** | Press **Left** _or_ **Side Up** |
| **Next Page** | Press **Right** _or_ **Side Down** |

The role of the volume (side) buttons can be swapped in the **[Controls Settings](#363-controls)**.
The role of the side buttons can be swapped in the **[Controls Settings](#363-controls)**.

If the **Short Power Button Click** setting is set to "Page Turn", you can also turn to the next page by briefly pressing the Power button.

### Chapter Navigation

* **Next Chapter:** Press and **hold** the **Right** (or **Volume Down**) button briefly, then release.
* **Previous Chapter:** Press and **hold** the **Left** (or **Volume Up**) button briefly, then release.
* **Next Chapter:** Press and **hold** the **Right** (or **Side Down**) button briefly, then release.
* **Previous Chapter:** Press and **hold** the **Left** (or **Side Up**) button briefly, then release.

This feature can be disabled in the **[Controls Settings](#363-controls)** to help avoid changing chapters by mistake.

Expand All @@ -659,6 +673,12 @@ When reading an EPUB that contains footnotes, you can navigate to the footnote t

If the device goes to sleep or you close the book while viewing a footnote, the book reopens to your original reading position, not the footnote.

### Dictionary Lookup

Words on the current page can be looked up in an offline StarDict dictionary stored on the SD card. Copy a dictionary to the `/dictionaries/` folder, select it in **Settings → Reader → Dictionary**, then start a lookup by choosing **Look Up** in the **[Reader Menu](#5-reader-menu)** (or by holding **Confirm**, if the **Long-press Menu** setting in **[Controls Settings](#363-controls)** is set to "Dictionary"). Use **Left/Right** to highlight a word and press **Confirm** to show its definition.

See [docs/dictionary.md](docs/dictionary.md) for supported formats, setup, and where to find dictionaries.

### System Navigation

* **Return to Home:** Press the **Back** button to close the book and return to the **[Home](#31-home-screen)** screen.
Expand Down Expand Up @@ -702,7 +722,7 @@ Press **Back** at any time to close the menu and return to your current page.

Accessible by selecting **Chapters** from the Reader Menu.

1. Use **Left** (or **Volume Up**), or **Right** (or **Volume Down**) to highlight the desired chapter.
1. Use **Left** (or **Side Up**), or **Right** (or **Side Down**) to highlight the desired chapter.
2. Press **Confirm** to jump to that chapter.
3. *Alternatively, press **Back** to cancel and return to your current page.*

Expand All @@ -724,8 +744,6 @@ Please note that this firmware is currently in active development. The following

* **Cover Images:** Large cover images embedded into EPUB require several seconds (~10s for ~2000 pixel tall image) to convert for sleep screen and home screen thumbnail. Consider optimizing the EPUB with e.g. https://github.com/bigbag/epub-to-xtc-converter to speed this up.
* **Unsupported Image Formats:** Most JPG and PNG images in EPUBs render correctly. GIFs and progressive JPEGs are not supported and will fall back to an `[Image]` placeholder.
*
* **Dictionary Lookup:** Inline word lookup is not yet implemented.

---

Expand Down
44 changes: 38 additions & 6 deletions docs/bezel-insets.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,44 @@ edge), the readers, and every screen laid out from
What made the flip safe for the screens that DO honor it, in the order the
traps were found:

1. **The ~23 absolute-margin `setContentMargin` sites** (reader menus,
settings lists, wifi, sliders) build margins in the full screen frame
from `getScreenSafeArea()`. They now call `setContentMarginAbsolute()`,
which insets from `screen()` rather than `safeRect()` -- same geometry as
before the flip, insets applied exactly once. Never hand absolute margins
to plain `setContentMargin()`; that applies the safe area twice.
1. **The ~23 absolute-margin sites** (reader menus, settings lists, wifi,
sliders) build margins in the full screen frame from `getScreenSafeArea()`.
Since the 2026-09-04 upstream sync they call upstream's
`setContentMarginFromScreen()`. Never hand absolute margins to plain
`setContentMargin()`; that applies the safe area twice.

`setContentMarginFromScreen()` does NOT apply it twice, which is why the
fork could adopt it and delete its own `setContentMarginAbsolute()` from
every screen upstream also has. The arithmetic, from `FreeInkApp.h`:

```
marginBeyondSafeArea(m, s) = m > s ? m - s : 0
setContentMarginFromScreen(m) -> screen inset by s + max(0, m - s) = max(m, s)
setContentMarginAbsolute(m) -> screen inset by m
```

`max(m, s)` is idempotent: a margin that already folds the safe area in
(every one of these sites does, they derive from `getScreenSafeArea()`)
comes back unchanged. The two calls differ only where a margin is BELOW
the safe area on some side.

**That one difference is why `setContentMarginAbsolute()` still exists**,
with exactly two callers left, both in `src/apps_local/`:

- `toybox::absoluteChrome()` passes `Insets{}` -- all zeros, deliberately
the full frame. `FromScreen({})` would give `max(0, safe)` = the safe
rect, pushing every game's chrome down by the top inset. That is the
regression described above, found on the device twice.
- `XkcdScreens.cpp` passes a band that may sit on the true panel edge.
On the X4 Pro `safe.bottom` is 0 so the two agree, but on a board using
the inherited `{9, 3, 3, 3}` default `max(m, s)` would clamp a
deliberate full-bleed bottom by 3px.

Upstream has no way to express "content rect = the full frame": `Screen`
seeds `content_` from `safeRect()`, and both upstream calls inset from
`safeRect()`. So this is a capability the fork needs, not a style
preference -- but it is now confined to fork-only screens, and no screen
shared with upstream diverges.
2. **The divider rule** under header bands is `toybox::headerRule(screen)`
(ToyboxScreen.h), derived from `screen.body().y` right after
`screen.header(...)`. The old idiom (a fill at absolute
Expand Down
2 changes: 1 addition & 1 deletion docs/contributing/touch-and-ui.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ All under `freeink-sdk/libs/ui/FreeInkUI/include/components/`:
|---|---|
| Controls | `button`, `checkbox`, `slider`, `progress-bar`, `header` |
| Lists | `list` (virtualized), `table`, `dropdown`, `radio-group`, `setting-row`, `toggle-row`, `stepper-row` |
| Keyboard | `keyboard` (QWERTY/AZERTY/QWERTZ/ES layouts), `key-grid` |
| Keyboard | `keyboard` (Latin, Cyrillic and Hebrew layouts), `key-grid` |
| Overlays | `popup`, `option-dialog`, `context-menu`, `message-panel`, `toast` |
| Bars | `status-bar`, `tab-bar`, `reader-chrome`, `battery-indicator`, `gesture-bar`, `tap-zones` |
| Media | `book-card`, `cover-grid`, `cover-carousel`, `metric-card` |
Expand Down
42 changes: 38 additions & 4 deletions docs/file-formats.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,18 +90,51 @@ if (parsedSize != fileSize) {

## `section.bin`

### Version 37
### Version 45

Version 45 keeps the version 44 serialized layout unchanged. It was bumped
because internal EPUB links now preserve CSS superscript and subscript styles,
changing their cached word-style flags and page layout.

### Version 44

Each file in `sections/*.bin` stores one laid-out spine section. The header is
also the cache-busting key: if any layout-affecting setting differs from the
current reader settings, the section is discarded and rebuilt.

Version 44 appends the internal-link rectangles produced during text layout to
each serialized page. The reader uses these rectangles for touch navigation;
older caches are rebuilt because they contain no link geometry.

Version 43 keeps the version 42 serialized layout unchanged. It was bumped
because paragraph base direction now excludes direction changes from inline
elements.

Version 42 keeps the version 41 serialized layout unchanged. It was bumped
because closing a block now strips inherited vertical margins and padding.

Version 41 keeps the version 40 serialized layout unchanged. It was bumped
because simple HTML table rows are now laid out as positioned columns rather
than flattened paragraphs with synthetic row/cell labels.

Version 40 keeps the version 39 serialized layout unchanged. It was bumped
because ruby groups now remain intact when large text blocks are soft-flushed.

Version 39 keeps the version 38 serialized layout unchanged. It was bumped
because image top margins are now clamped to keep full-height images within the
page viewport.

Version 38 keeps the version 37 serialized layout unchanged. It was bumped
because Focus Reading now permits line breaks at visible hyphens and dashes
and hyphenates focus-split words as a whole, changing cached page layout.

Version 37 increases the fixed-size footnote href field from 96 to 256 bytes.
This changes each serialized footnote record from 128 to 288 bytes, so older
section caches must be discarded and rebuilt.

Version 36 invalidates cached word positions after ruby and CJK justification
layout changes.
Version 36 keeps the version 35 serialized layout unchanged. It was bumped
because ruby and justified text positioning and CJK line breaking now use
corrected word measurements, so version 35 cached page layouts no longer match.

Version 35 adds a header offset and a `uint32_t` entry per page for the
visible-text offset LUT. The other section LUTs remain unchanged.
Expand Down Expand Up @@ -142,7 +175,7 @@ import std.mem;
import std.string;
import std.core;

#define EXPECTED_VERSION 37
#define EXPECTED_VERSION 41
#define MAX_STRING_LENGTH 65535
#define FOOTNOTE_NUMBER_LEN 32
#define FOOTNOTE_HREF_LEN 256
Expand Down Expand Up @@ -224,6 +257,7 @@ struct TextBlock {

struct ImageBlock {
String imagePath;
String srcPath;
s16 width;
s16 height;
};
Expand Down
5 changes: 4 additions & 1 deletion docs/i18n.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ A file looks like this:
_language_name: "Español"
_language_code: "ES"
_order: "1"
_bcp47: "es"

STR_CROSSPLAY: "CrossPlay"
STR_BOOTING: "BOOTING"
Expand All @@ -78,7 +79,8 @@ STR_BROWSE_FILES: "Buscar archivos"
**Metadata keys** (prefixed with `_`):
- `_language_name` — Native display name shown to the user (e.g. "Français")
- `_language_code` — C++ enum name (e.g. "FR"). Please use the [ISO Code](https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes) of the language. Must be a valid C++ identifier.
- `_order` — Controls the position in the Language enum (English is always 0)
- `_order` — Historical metadata, still validated for uniqueness but no longer used to compute the `Language` enum order (see `_bcp47` below).
- `_bcp47` — [BCP 47](https://www.rfc-editor.org/rfc/rfc5646) language tag (e.g. `"pt-PT"`, `"ca-valencia"`). Must be unique. Controls the position in the `Language` enum and the visible Settings menu order (English is always first, then the rest sorted alphabetically by this tag). Persisted user language preferences are stored by `_language_code` string, not by the enum ordinal, so changing `_bcp47` (and thus the enum/menu order) does not reset anyone's saved language.

**Rules:**
- Use UTF-8 encoding
Expand Down Expand Up @@ -147,6 +149,7 @@ Create `lib/I18n/translations/italian.yaml`:
_language_name: "Italiano"
_language_code: "IT"
_order: "7"
_bcp47: "it"

STR_CROSSPLAY: "CrossPlay"
STR_BOOTING: "AVVIO"
Expand Down
3 changes: 2 additions & 1 deletion docs/sd-card-fonts.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ There are three ways to install fonts:
### Option 1: Download from device (recommended)

1. Connect your CrossPoint reader to Wi-Fi
2. Go to **Settings > System > Manage Fonts**
2. Go to **Settings > Reader > Manage Fonts**
3. Browse available font families and tap to download
4. Downloaded fonts appear immediately in **Settings > Reader > Font Family**

Expand Down Expand Up @@ -149,6 +149,7 @@ To convert your own TrueType/OpenType fonts:
| `greek` | Greek + Extended Greek |
| `cyrillic` | Cyrillic + Supplement |
| `hebrew` | Hebrew + Alphabetic Presentation Forms |
| `arabic` | Arabic + Supplement + Extended-A + Presentation Forms A/B (RTL, contextual shaping) |
| `georgian` | Georgian + Georgian Supplement |
| `armenian` | Armenian |
| `ethiopic` | Ethiopic + Extended |
Expand Down
Loading
Loading