Commit Graph
31 Commits
Author SHA1 Message Date
+7 e6c6e72a24 chore(release): 1.2.0 Release Candidate (#1483)
Compile Release / build-release (push) Canceled after 0s
## Summary

It's been a little while since the last release, but the community has
been incredibly busy. With 155 changes from 48 contributors (30 of which
were new!), there was a lot to cover. Here are some of the highlights:

**🔤 Kerning, Ligatures, and Font Improvements**
Text rendering gets a significant upgrade with proper kerning and
ligature support, fixed-point fractional x-advance for more accurate
character placement, and font compression improvements that reduce flash
usage.

**📝 Footnotes**
Footnote anchor navigation lets you select a footnote reference and jump
to the footnote text, then jump back. Slim footnotes support is also
available for books that use inline footnotes.

**📖 EPUB Optimizer**
A new integrated EPUB optimizer can clean up and reprocess books for
better compatibility with the reader, directly from the device.

**🔋 Battery Charging Indicator**
You can now see when your device is actively charging, with a visual
indicator on the battery icon.

**💾 Crash Diagnostics**
When something goes wrong, the firmware now dumps a crash report to the
SD card — even without USB plugged in. This makes it much easier to
report and diagnose issues.

**🌐 New Languages**
The community continues to expand language support. New in this release:
Turkish, Danish, Finnish, Polish, Dutch, Belarusian, Italian, Ukrainian,
Romanian, Catalan, Vietnamese, and Kazakh — along with significant
improvements to existing translations.

**📂 File Management**
Multi-select file deletion, BMP image viewer in the file browser, hidden
directory browsing, and long-click file deletion from the file browser.

** Performance**
Under the hood, text layout switched from `std::list` to `std::vector`,
HTML entity lookups are now O(log(n)), font rendering is faster, image
decode is 5-20% faster with per-pixel overhead eliminated, and multiple
string allocation hot paths were eliminated. Pre-indexing of the next
chapter also reduces page-turn latency at chapter boundaries.

---

Along with all of the above, there are many other additions including
**WebDAV support**, **auto page turn**, **QR code for current page**,
**split status bar settings**, **screenshot capture**, **JSON-based
settings migration**, **light/dark theme groundwork**, and a long list
of stability fixes and translation improvements.

## What's Changed
### Features
* feat: Support for kerning and ligatures by @znelson in
https://github.com/crosspoint-reader/crosspoint-reader/pull/873
* feat: footnote anchor navigation by @Uri-Tauber in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1245
* feat: slim footnotes support by @Uri-Tauber in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1031
* feat: integrated epub optimizer by @zgredex and @pablohc in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1224
* feat: battery charging indicator (mirroring PR #537) by @jpirnay in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1427
* feat: dump crash report to sdcard by @ngxson in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1145
* feat: Implement silent pre-indexing for the next chapter in
EpubReaderActivity by @LSTAR1900 in
https://github.com/crosspoint-reader/crosspoint-reader/pull/979
* feat: upgrade platform and support webdav by @dexif in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1047
* feat: Auto Page Turn for Epub Reader by @GenesiaW in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1219
* feat: enhance file deletion functionality with multi-select by
@Jessica765 in
https://github.com/crosspoint-reader/crosspoint-reader/pull/682
* feat: Long Click for File Deletion through File Browser by @Levrk in
https://github.com/crosspoint-reader/crosspoint-reader/pull/909
* feat: Take screenshots by @el in
https://github.com/crosspoint-reader/crosspoint-reader/pull/759
* feat: Current page as QR by @el in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1099
* feat: Download links for web server by @el in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1039
* feat: Added BmpViewer activity for viewing .bmp images in file browser
by @Levrk in
https://github.com/crosspoint-reader/crosspoint-reader/pull/887
* feat: User setting for image display by @jpirnay in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1291
* feat: Show hidden directories in browser by @jpirnay in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1288
* feat: Prefer ".sleep" over "sleep" for custom image directory by
@jpirnay in
https://github.com/crosspoint-reader/crosspoint-reader/pull/948
* feat: Allow a local configuration file for custom compiles by @jpirnay
in https://github.com/crosspoint-reader/crosspoint-reader/pull/879
* feat: Migrate binary settings to json by @jpirnay in
https://github.com/crosspoint-reader/crosspoint-reader/pull/920
* feat: split status bar setting by @whyte-j in
https://github.com/crosspoint-reader/crosspoint-reader/pull/733
* feat: wrapped text in GfxRender, implemented in themes so far by
@iandchasse in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1141
* feat: Themed language screen by @CaptainFrito in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1020
* feat: set WiFi hostname to CrossPoint-Reader-XXXXXXXXXXXX by @dexif in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1107
* feat: Add maxAlloc to memory information by @jpirnay in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1152
* feat: replace picojpeg with JPEGDEC for JPEG image decoding by
@martinbrook in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1136
* feat: Add git branch to version information on settings screen by
@jpirnay in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1225
* feat: sort languages in selection menu by @ariel-lindemann in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1071
* feat: Latin Extended-B European glyphs by @znelson in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1157
* feat: Latin Extended-B European glyphs by @znelson in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1167
* feat: Vietnamese glyphs support by @danoooob in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1147
* feat: add Turkish translation by @barbarhan in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1192
* feat: add full Danish translation by @hajisan in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1146
* feat: Add Finnish translations by @plahteenlahti in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1133
* feat: Add Polish Language by @th0m4sek in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1155
* feat: add Dutch translation by @basvdploeg in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1204
* feat: add Belarusian translation by @dexif in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1120
* feat: Add full Italian translations by @andreaturchet in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1144
* feat: add Ukrainian translation by @mirus-ua in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1065
* feat: Add Kazakh (kk) language support by @fsocietyipa in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1377
* feat: added Romanian strings by @ariel-lindemann in
https://github.com/crosspoint-reader/crosspoint-reader/pull/987
* feat: add Catalan strings by @angeldenom in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1049
* feat: Make directories stand out more in local file browser: "[dir]"
instead of "dir" by @jpirnay in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1339
* feat: Add Polish strings for commits #1219,#1169,#1031 +tweaks by
@th0m4sek in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1227
* feat: Polish translation tweaks by @th0m4sek in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1193
### Fixes
* fix: Fix img layout issue / support CSS display:none for elements and
images by @jpirnay in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1443
* fix: Overlapping battery percentage on image pages with anti-aliasing
by @znelson in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1452
* fix: Fix prewarm perf when a page contains many styles by
@adriancaruana in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1451
* fix: use sleep routine from the original firmware by @ngxson in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1298
* fix: Prevent line breaks on common English contractions by @znelson in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1405
* fix: Build with -fno-exceptions by @znelson in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1412
* fix: Reduce flash usage by cleaning up I18n translations by @steka in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1401
* fix: jpeg resource cleanup by @jpirnay in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1320
* fix: back button in settings returns to tab bar first by @Cache8063 in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1354
* fix: Init lastSleepImage (edge case) by @jpirnay in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1360
* fix: Add special handling for apostrophe hyphenation by @jpirnay in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1318
* fix: Fix inter-word spacing rounding error in text layout by @znelson
in https://github.com/crosspoint-reader/crosspoint-reader/pull/1311
* fix: load access fault crash by @Uri-Tauber in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1370
* fix: Fix bootloop logging crash by @jpirnay in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1357
* fix: dump crash log without usb plugged, bump release log to INFO by
@ngxson in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1332
* fix: avoid zip filename overflow by @jpirnay in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1321
* fix: Hanging indent (negative text-indent) and em-unit sizing by
@jpirnay in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1229
* fix: Use fixed-point fractional x-advance and kerning for better text
layout by @znelson in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1168
* fix: use HTTPClient::writeToStream for downloading files from OPDS by
@osteotek in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1207
* fix: make file system operations thread-safe (HalFile) by @ngxson in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1212
* fix: properly implement requestUpdateAndWait() by @ngxson in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1218
* fix: prevent infinite render loop in Calibre Wireless after file
transfer by @pablohc in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1070
* fix: WiFi lifecycle and hyphenation heap defragmentation for KOReader
sync by @jpirnay in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1151
* fix: Fix coverRendered flag by @jpirnay in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1154
* fix: Handle non-ASCII characters in sanitizeFilename by @znelson in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1132
* fix: Update activity was missing "Back" button label by @znelson in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1128
* fix: force auto-hinting for Bookerly to fix inconsistent stem widths
by @adriancaruana in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1098
* fix: image centering bleed by @martinbrook in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1096
* fix: double free WebDAVHandler by @ngxson in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1093
* fix: Consider extra quotation styles when hyphenating quoted words by
@cbix in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1077
* fix: acquire power lock before sleeping by @ngxson in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1125
* fix: Unify inconsistent Wi-Fi/WiFi in Czech translation by @pepastach
in https://github.com/crosspoint-reader/crosspoint-reader/pull/1138
* fix: sdfat warning about redefinition of macro by @ngxson in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1135
* fix: Close leaked file descriptors in SleepActivity and web server by
@brbla in
https://github.com/crosspoint-reader/crosspoint-reader/pull/869
* fix: Enable DESTRUCTOR_CLOSES_FILE flag by @daveallie in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1075
* fix: Change "UI Font Size" to "Reader Font Size" by @divinitycove in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1171
* fix: Hide unusable button hints when viewing empty directory by @Levrk
in https://github.com/crosspoint-reader/crosspoint-reader/pull/1253
* fix: broken translations in status bar settings by @ariel-lindemann in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1188
* fix: clarity issue with ambiguous string `SET` by @ariel-lindemann in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1169
* fix: Crash (Load access fault) when indexing chapters containing
characters unsupported by bold/italic font variants by @Uri-Tauber in
https://github.com/crosspoint-reader/crosspoint-reader/pull/997
* fix: Increase PNGdec buffer size to support wide images by @osteotek
in https://github.com/crosspoint-reader/crosspoint-reader/pull/995
* fix: Use HalPowerManager for battery percentage by @vjapolitzer in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1005
* fix: Fix dangling pointer by @Uri-Tauber in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1010
* fix: re-implementing Cover Outlines for the new Lyra Themes by @Levrk
in https://github.com/crosspoint-reader/crosspoint-reader/pull/1017
* fix: use double FAST_REFRESH to prevent washout on large grey images
by @martinbrook in
https://github.com/crosspoint-reader/crosspoint-reader/pull/957
* fix: Fixed Image Sizing When No Width is Set by @DestinySpeaker in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1002
* fix: Strip unused CSS rules by @daveallie in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1014
* fix: continue reading card classic theme by @pablohc in
https://github.com/crosspoint-reader/crosspoint-reader/pull/990
* fix: Destroy CSS Cache file when invalid by @daveallie in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1018
* fix: Shorten "Forget Wifi" button labels to fit on button by
@lukestein in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1045
* fix: improve Spanish translations by @pablohc in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1054
* fix: Fixed book title in home screen by @DestinySpeaker in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1013
* fix: Fix hyphenation and rendering of decomposed characters by
@jpirnay in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1037
* fix: Improve and add Spanish translations by @DaniPhii in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1338
* fix: improve and add Spanish translations by @DaniPhii in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1254
* fix: improve and add Swedish translations by @steka in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1317
* fix: Extend missing / amend existing German translations by @jpirnay
in https://github.com/crosspoint-reader/crosspoint-reader/pull/1226
* fix: update french.yaml file to have a better French translation of
the CFW by @Spigaw in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1130
* fix: added romanian translation to new strings by @ariel-lindemann in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1105
* fix: add missing romanian strings by @ariel-lindemann in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1187
* fix: add new Ukrainian translation line for STR_SCREENSHOT_BUTTON by
@mirus-ua in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1149
* fix: Dutch translation prefix correction by @basvdploeg in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1223
* fix: Small typo in i18n.md regarding C++ identifiers by
@victordomingos in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1210
* fix: typo in USER_GUIDE.md by @arnaugamez in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1036
* fix: add missing keyboard metrics to Lyra3CoversTheme by @dexif in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1101

### Internal
* perf: font-compression improvements by @adriancaruana in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1056
* perf: Improve font drawing performance by @jpirnay in
https://github.com/crosspoint-reader/crosspoint-reader/pull/978
* perf: Replace std::list with std::vector in text layout by @znelson in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1038
* perf: Optimize HTML entities lookup to O(log(n)) by @Uri-Tauber in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1194
* perf: UITheme::getMetrics const and const-ref usage by @znelson in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1094
* perf: Avoid creating strings for file extension checks by @znelson in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1303
* perf: Eliminate per-pixel overheads in image rendering by @martinbrook
in https://github.com/crosspoint-reader/crosspoint-reader/pull/1293
* perf: Update github actions for optimal performance with pioarduino by
@Jason2866 in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1080
* style: Phase 1 - Simple light dark themes by @cdmoro in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1006
* refactor: implement ActivityManager by @ngxson in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1016
* refactor: Simplify REPLACEMENT_GLYPH fallback by @znelson in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1119
* refactor: Simplify new setting introduction by @jpirnay in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1086
* refactor: Use std binary search algorithms for font lookups by
@znelson in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1202
* refactor: rename MyLibrary to FileBrowser by @osteotek in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1260
* refactor: Avoid rebuilding cache path strings by @znelson in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1300
* refactor: reader utils by @Uri-Tauber in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1329
* chore: Remove miniz and modularise inflation logic by @daveallie in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1073
* chore: Resolve several build warnings by @daveallie in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1076
* chore: Removed generated language headers by @znelson in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1156
* chore: Added generated lang headers to .gitignore by @znelson in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1158
* chore: remove redundant xTaskCreate by @ngxson in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1264
* chore: Removed unused PlatformIO include directory placeholder by
@znelson in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1417
* chore: micro-optimisation: early exit on fillUncompressedSizes by
@jpirnay in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1322
* chore: change label while on settings tab actions by @jpirnay in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1325
* chore: add firmware size history script by @znelson in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1235
* chore: Add powershell script for clang-formatting by @jpirnay in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1472
* chore: Removed unused ConfirmationActivity member by @znelson in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1234
* chore: Update russian.yaml by @madebyKir in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1198
* chore: new Ukrainian translation lines by @mirus-ua in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1199
* chore: new Ukrainian localization strings by @mirus-ua in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1270
* chore: Polish localization for STR_DELETE by @JonaszPotoniec in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1323
* chore: Image settings Polish localization by @znelson in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1299
* chore: add missing Catalan strings by @angeldenom in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1302
* chore: add missing translations for Romanian by @ariel-lindemann in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1265
* chore: Add Portuguese (Portugal) translator to the list by
@victordomingos in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1211
* chore: Reduce flash usage by cleaning up I18n translations by @steka
in https://github.com/crosspoint-reader/crosspoint-reader/pull/1401
* docs: Add lightweight contributor onboarding documentation by @bilalix
in https://github.com/crosspoint-reader/crosspoint-reader/pull/894
* docs: ActivityManager migration guide by @znelson in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1222
* docs: USER_GUIDE.md update for 1.1.0 by @divinitycove in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1108
* docs: add quick KOReader sync setup guide by @wjhrdy in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1181
* docs: image support marked as completed by @ariel-lindemann in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1008
* feat: aiagent context definition by @jpirnay in
https://github.com/crosspoint-reader/crosspoint-reader/pull/922
* chore: Update SKILL.md to reflect generated i18n files are gitignored
by @znelson in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1423
* fix: ActivityManager tweaks by @znelson in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1220
* fix: Correct relative file paths in SKILL.md documentation by @pablohc
in https://github.com/crosspoint-reader/crosspoint-reader/pull/1304
* fix: add Technically Unsupported section to SCOPE.md by @Uri-Tauber in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1295

## New Contributors
* @DestinySpeaker made their first contribution in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1002
* @arnaugamez made their first contribution in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1036
* @angeldenom made their first contribution in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1049
* @cdmoro made their first contribution in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1006
* @bilalix made their first contribution in
https://github.com/crosspoint-reader/crosspoint-reader/pull/894
* @Jessica765 made their first contribution in
https://github.com/crosspoint-reader/crosspoint-reader/pull/682
* @brbla made their first contribution in
https://github.com/crosspoint-reader/crosspoint-reader/pull/869
* @dexif made their first contribution in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1047
* @mirus-ua made their first contribution in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1065
* @cbix made their first contribution in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1077
* @divinitycove made their first contribution in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1108
* @pepastach made their first contribution in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1138
* @Jason2866 made their first contribution in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1080
* @andreaturchet made their first contribution in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1144
* @Spigaw made their first contribution in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1130
* @iandchasse made their first contribution in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1141
* @th0m4sek made their first contribution in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1155
* @plahteenlahti made their first contribution in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1133
* @hajisan made their first contribution in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1146
* @madebyKir made their first contribution in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1198
* @victordomingos made their first contribution in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1210
* @basvdploeg made their first contribution in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1204
* @wjhrdy made their first contribution in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1181
* @DaniPhii made their first contribution in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1254
* @steka made their first contribution in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1317
* @barbarhan made their first contribution in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1192
* @JonaszPotoniec made their first contribution in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1323
* @Cache8063 made their first contribution in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1354
* @fsocietyipa made their first contribution in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1377
* @LSTAR1900 made their first contribution in
https://github.com/crosspoint-reader/crosspoint-reader/pull/979
* @zgredex made their first contribution in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1224

**Full Changelog**:
https://github.com/crosspoint-reader/crosspoint-reader/compare/1.1.1...release/1.2.0

---------

Co-authored-by: jpirnay <jens@pirnay.com>
Co-authored-by: Dani Poveda <daniphii@outlook.com>
Co-authored-by: Baris Albayrak <80099286+barbarhan@users.noreply.github.com>
Co-authored-by: Barış Albayrak <barisa@pop-os.lan>
Co-authored-by: Stefan Blixten Karlsson <sbkarlsson@gmail.com>
Co-authored-by: Àngel <153315454+angeldenom@users.noreply.github.com>
Co-authored-by: Jonasz Potoniec <jonasz@potoniec.eu>
Co-authored-by: Егор Мартынов <martynovegorOF@yandex.ru>
Co-authored-by: Mirus <mirusim@gmail.com>
Co-authored-by: Spigaw <73850535+Spigaw@users.noreply.github.com>
Co-authored-by: ariel-lindemann <41641978+ariel-lindemann@users.noreply.github.com>
Co-authored-by: Nima Salami <54304457+hajisan@users.noreply.github.com>
Co-authored-by: Arthur Tazhitdinov <lisnake@gmail.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Bas van der Ploeg <bas@basvanderploeg.nl>
Co-authored-by: martin brook <martin.brook100@googlemail.com>
2026-04-03 17:33:02 -05:00
Zach Nelson 0cbfaa007d fix: Overlapping battery percentage on image pages with anti-aliasing (#1452)
## Summary

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

When viewing a page with images and anti-aliasing enabled, the
`imagePageWithAA` path renders the page twice with fast refreshes (blank
image area, then restore). Both passes called `renderStatusBar()`, which
reads the battery percentage live. If the value changed between the two
renders (e.g. 88% -> 87%), the digits would overlap on screen.
Fix: Removed the redundant `renderStatusBar()` from the second BW
render. The status bar is already drawn and displayed in the first pass,
and only the image area needs restoration.

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _**NO**_
2026-03-23 22:05:15 +00:00
Zach Nelson 53beeeed2b chore: Removed unused PlatformIO include directory placeholder (#1417)
## Summary

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

This change deletes include/README, which is a PlatformIO boilerplate
placeholder file explaining what header files are. The include/
directory isn't used by this project (headers live in lib/ and src/), so
this is just cleanup.

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _**NO**_
2026-03-19 23:20:50 -05:00
Zach Nelson 9665dd7473 chore: Update SKILL.md to reflect generated i18n files are gitignored (#1423)
## Summary

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

Update SKILL.md to stop instructing contributors to commit `I18nKeys.h`
and `I18nStrings.h`. All three generated i18n files have been gitignored
since ff577540 and are regenerated at build time.

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _**NO**_
2026-03-19 23:19:54 -05:00
Zach Nelson d6951f81b7 fix: Build with -fno-exceptions (#1412)
## Summary

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

Until today, I sincerely thought we were building without exception
support. The codebase is not set up with any exception handling
infrastructure. The SKILL.md file specifies no exceptions.

I just learned that we actually were building with exceptions enabled,
with `-fexceptions` coming from
~/.platformio/packages/framework-arduinoespressif32-libs/esp32c3/pioarduino-build.py.

This change removes the `-fexceptions` flag and adds `-fno-exceptions`.
The result is **53,670 bytes in flash savings**.

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _**NO**_
2026-03-18 11:41:18 -05:00
Zach Nelson dc39480349 fix: Prevent line breaks on common English contractions (#1405) 2026-03-16 20:04:06 -04:00
Zach Nelson 32a5c1c358 fix: Fix inter-word spacing rounding error in text layout (#1311)
## Summary

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

### Problem

Inter-word gap widths were computed as two separately-snapped integers:

```cpp
gap = getSpaceWidth(fontId, style);                        // fp4::toPixel(spaceAdvance)
gap += getSpaceKernAdjust(fontId, leftCp, rightCp, style); // fp4::toPixel(kern1 + kern2)
```

Because `fp4::toPixel(a) + fp4::toPixel(b)` can differ from
`fp4::toPixel(a + b)` by +/-1 pixel when the fractional parts straddle a
rounding boundary, each inter-word space could be one pixel wider or
narrower than the correct value. This affected line-break width
decisions and word-position accumulation across the whole paragraph
layout pipeline.

### Fix

Replaces `getSpaceKernAdjust()` with `getSpaceAdvance(fontId, leftCp,
rightCp, style)`, which combines the space glyph advance and both
flanking kern values (`kern(leftCp, ' ')` + `kern(' ', rightCp)`) into a
single fixed-point sum before the snap:

```cpp
return fp4::toPixel(spaceAdvanceFP + kern(leftCp, ' ') + kern(' ', rightCp));
```

This is the same single-snap pattern already used by `getTextAdvanceX`
for word widths.

### Changes

- **`GfxRenderer`**: Replaces `getSpaceKernAdjust()` with
`getSpaceAdvance()`. `getSpaceWidth()` is retained for the
single-space-word case in `measureWordWidth` where no adjacent-word kern
context is available.
- **`ParsedText`**: All four call sites (`computeLineBreaks`,
`computeHyphenatedLineBreaks`, and both loops in `extractLine`) updated
to use `getSpaceAdvance()`. The now-redundant `spaceWidth`
pre-computation and parameter are removed from all three internal layout
functions.

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _**YES to analyze for
correctness**_
2026-03-10 22:55:23 -05:00
Zach Nelson c3f1dbfa09 perf: Avoid creating strings for file extension checks (#1303)
## Summary

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

This change avoids the pattern of creating a `std::string` using
`.substr` in order to compare against a file extension literal.
```c++
std::string path;
if (path.length() >= 4 && path.substr(path.length() - 4) == ".ext")
```

The `checkFileExtension` utility has moved from StringUtils to
FsHelpers, to be available to code in lib/. The signature now accepts a
`std::string_view` instead of `std::string`, which makes the single
implementation reusable for Arduino `String`.

Added utility functions for commonly repeated extensions.

These changes **save about 2 KB of flash (5,999,427 to 5,997,343)**.

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _**NO**_
2026-03-05 10:12:22 -06:00
Zach Nelson ea88797c8e chore: Image settings Polish localization (#1299)
## Summary

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

Quick follow up to #1291, adding Polish translations suggested by
@th0m4sek

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _**NO**_
2026-03-05 19:08:36 +03:00
Zach Nelson a826569a0f refactor: Avoid rebuilding cache path strings (#1300)
## Summary

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

Avoid building cache path strings twice, once to check existence of the
file and a second time to delete the file.

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _**NO**_
2026-03-04 20:48:02 -05:00
Zach Nelson 7dc518624c fix: Use fixed-point fractional x-advance and kerning for better text layout (#1168)
## Summary

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

Hopefully fixes #1182.

_Note: I think letterforms got a "heavier" appearance after #1098, which
makes this more noticeable. The current version of this PR reverts the
change to add `--force-autohint` for Bookerly, which to me seems to
bring the font back to a more aesthetic and consistent weight._

#### Problem

Character spacing was uneven in certain words. The word "drew" in
Bookerly was the clearest example: a visible gap between `d` and `r`,
while `e` and `w` appeared tightly condensed. The root cause was
twofold:

1. **Integer-only glyph advances.** `advanceX` was stored as a `uint8_t`
of whole pixels, sourced from FreeType's hinted `advance.x` (which
grid-fits to integers). A glyph whose true advance is 15.56px was stored
as 16px -- an error of +0.44px per character that compounds across a
line.

2. **Floor-rounded kerning.** Kern adjustments were converted with
`math.floor()`, which systematically over-tightened negative kerns. A
kern of -0.3px became -1px -- a 0.7px over-correction that visibly
closed gaps.

Combined, these produced the classic symptom: some pairs too wide,
others too tight, with the imbalance varying per word.

#### Solution: fixed-point accumulation with 1/16-pixel resolution, for
sub-pixel precision during text layout

All font metrics now use a "fixed-point 4" format -- 4 fractional bits
giving 1/16-pixel (0.0625px) resolution. This is implemented with plain
integer arithmetic (shifts and adds), requiring no floating-point on the
ESP32.

**How it works:**

A value like 15.56px is stored as the integer `249`:

```
249 = 15 * 16 + 9    (where 9/16 = 0.5625, closest to 0.56)
```

Two storage widths share the same 4 fractional bits:

| Field | Type | Format | Range | Use |
|-------|------|--------|-------|-----|
| `advanceX` | `uint16_t` | 12.4 | 0 -- 4095.9375 px | Glyph advance
width |
| `kernMatrix` | `int8_t` | 4.4 | -8.0 -- +7.9375 px | Kerning
adjustment |

Because both have 4 fractional bits, they add directly into a single
`int32_t` accumulator during layout. The accumulator is only snapped to
the nearest whole pixel at the moment each glyph is rendered:

```cpp
int32_t xFP = fp4::fromPixel(startX);     // pixel to 12.4: startX << 4

for each character:
    xFP += kernFP;                          // add 4.4 kern (sign-extends into int32_t)
    int xPx = fp4::toPixel(xFP);           // snap to nearest pixel: (xFP + 8) >> 4
    render glyph at xPx;
    xFP += glyph->advanceX;                // add 12.4 advance
```

Fractional remainders carry forward indefinitely. Rounding errors stay
below +/- 0.5px and never compound.

#### Concrete example: "drew" in Bookerly

**Before** (integer advances, floor-rounded kerning):

| Char | Advance | Kern | Cursor | Snap | Gap from prev |
|------|---------|------|--------|------|---------------|
| d | 16 px | -- | 33 | 33 | -- |
| r | 12 px | 0 | 49 | 49 | ~2px |
| e | 13 px | -1 | 60 | 60 | ~0px |
| w | 22 px | -1 | 72 | 72 | ~0px |

The d-to-r gap was visibly wider than the tightly packed `rew`.

**After** (12.4 advances, 4.4 kerning, fractional accumulation):

| Char | Advance (FP) | Kern (FP) | Accumulator | Snap | Ink start | Gap
from prev |

|------|-------------|-----------|-------------|------|-----------|---------------|
| d | 249 (15.56px) | -- | 528 | 33 | 34 | -- |
| r | 184 (11.50px) | 0 | 777 | 49 | 49 | 0px |
| e | 208 (13.00px) | -8 (-0.50px) | 953 | 60 | 61 | 1px |
| w | 356 (22.25px) | -4 (-0.25px) | 1157 | 72 | 72 | 0px |

Spacing is now `0, 1, 0` pixels -- nearly uniform. Verified on-device:
all 5 copies of "drew" in the test EPUB produce identical spacing,
confirming zero accumulator drift.

#### Changes

**Font conversion (`fontconvert.py`)**
- Use `linearHoriAdvance` (FreeType 16.16, unhinted) instead of
`advance.x` (26.6, grid-fitted to integers) for glyph advances
- Encode kern values as 4.4 fixed-point with `round()` instead of
`floor()`
- Add `fp4_from_ft16_16()` and `fp4_from_design_units()` helper
functions
- Add module-level documentation of fixed-point conventions

**Font data structures (`EpdFontData.h`)**
- `EpdGlyph::advanceX`: `uint8_t` to `uint16_t` (no memory cost due to
existing struct padding)
- Add `fp4` namespace with `constexpr` helpers: `fromPixel()`,
`toPixel()`, `toFloat()`
- Document fixed-point conventions

**Font API (`EpdFont.h/cpp`, `EpdFontFamily.h/cpp`)**
- `getKerning()` return type: `int8_t` to `int` (to avoid truncation of
the 4.4 value)

**Rendering (`GfxRenderer.cpp`)**
- `drawText()`: replace integer cursor with `int32_t` fixed-point
accumulator
- `drawTextRotated90CW()`: same accumulator treatment for vertical
layout
- `getTextAdvanceX()`, `getSpaceWidth()`, `getSpaceKernAdjust()`,
`getKerning()`: convert from fixed-point to pixel at API boundary

**Regenerated all built-in font headers** with new 12.4 advances and 4.4
kern values.

#### Memory impact

Zero additional RAM. The `advanceX` field grew from `uint8_t` to
`uint16_t`, but the `EpdGlyph` struct already had 1 byte of padding at
that position, so the struct size is unchanged. The fixed-point
accumulator is a single `int32_t` on the stack.

#### Test plan

- [ ] Verify "drew" spacing in Bookerly at small, medium, and large
sizes
- [ ] Verify uppercase kerning pairs: AVERY, WAVE, VALUE
- [ ] Verify ligature words: coffee, waffle, office
- [ ] Verify all built-in fonts render correctly at each size
- [ ] Verify rotated text (progress bar percentage) renders correctly
- [ ] Verify combining marks (accented characters) still position
correctly
- [ ] Spot-check a full-length book for any layout regressions

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _**YES, Claude Opus 4.6
helped figure out a non-floating point approach for sub-pixel error
accumulation**_
2026-03-01 10:43:37 -06:00
Zach Nelson 620835a6a1 chore: add firmware size history script (#1235)
## Summary

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

- Adds `scripts/firmware_size_history.py`, a developer tool that builds
firmware at selected git commits and reports flash usage with deltas
between them.
- Supports two input modes: `--range START END` to walk every commit in
a range, or `--commits REF [REF ...]` to compare specific refs (which
can span branches).
- Defaults to a human-readable aligned table; pass `--csv` for
machine-readable output to stdout or `--csv FILE` to write to a file.

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _**YES, fully written by
AI**_
2026-03-01 10:28:32 -06:00
Zach Nelson 3cc8e272ca refactor: Use std binary search algorithms for font lookups (#1202)
## Summary

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

Rewrite of font routines to use std binary search algorithms instead of
custom repeated implementations: `lookupKernClass`,
`EpdFont::getLigature`, and `EpdFont::getGlyph`.

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _**NO**_
2026-03-01 10:28:15 -06:00
Zach Nelson 80d1856330 perf: Removed unused ConfirmationActivity member (#1234)
## Summary

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

Small follow up to #909, removing an unused member variable and some
temporary debug logging.

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _**NO**_
2026-03-01 10:04:52 -06:00
Zach Nelson 42b122b8fd docs: ActivityManager migration guide (#1222)
## Summary

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

Added overview and migration guide for ActivityManager changes in #1016.
Thanks for the suggestion, @drbourbon!

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _**YES, fully written by
Claude 4.6**_
2026-02-28 11:10:14 +01:00
Zach Nelson 050a3bd1b6 fix: ActivityManager tweaks (#1220)
## Summary

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

Small tweaks to #1016:
- Only Activity and ActivityManager can access activityResultHandler and
activityResult
- `[[maybe_unused]]` in RenderLock constructor
- Only ActivityManager and RenderLock can access renderingMutex
- Missing renderUpdate after failed wifi selection
- Standardize on activities calling finish instead of
activityManager.popActivity
- Hold RenderLock while mutating state in EpubReaderActivity result
handlers

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _**NO**_
2026-02-27 22:48:24 +01:00
Zach Nelson cb72916397 feat: Latin Extended-B European glyphs (#1167)
## Summary

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

Correction to #1157, which (embarrassingly) failed to actually include
the updated font header files. (Maybe we should generate these at build
time?)

Add Latin Extended-B glyphs for Croatian, Romanian, Pinyin, and European
diacritical variants. Fixes #921.

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _**PARTIALLY, confirmed
codepoint ranges with Claude**_
2026-02-25 12:56:11 +03:00
Zach Nelson 31396da064 fix: Update activity was missing "Back" button label (#1128)
## Summary

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

When update activity finds no update or fails, the "Back" button label
was missing. Fixes #1089.

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _**NO**_
2026-02-24 22:21:46 -06:00
Zach Nelson 8ab2f22730 fix: Handle non-ASCII characters in sanitizeFilename (#1132)
## Summary

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

Probable fix for #1118. `sanitizeFilename` was only passing through
ASCII characters from filenames. It now maintains valid UTF-8
codepoints, including non-ASCII multibyte sequences. Truncation happens
at a maximum number of bytes, rather than characters, to prevent
filenames with many multibyte sequences from unexpectedly exceeding
FAT32 limits.

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _**YES, I described #1118
to Claude and it suggested sanitizeFilename as the likely cause**_
2026-02-24 17:43:58 -06:00
Zach Nelson c0cd7c13a3 feat: Latin Extended-B European glyphs (#1157)
## Summary

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

Add Latin Extended-B glyphs for Croatian, Romanian, Pinyin, and European
diacritical variants. Fixes #921.

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _**PARTIALLY, confirmed
codepoint ranges with Claude**_
2026-02-24 16:44:20 -06:00
Zach Nelson ff577540a3 chore: Added generated lang headers to .gitignore (#1158)
## Summary

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

Following up on #1156: generated language header files should be
ignored.

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _**NO**_
2026-02-24 21:48:07 +03:00
Zach Nelson 43efd80e14 chore: Removed generated language headers (#1156)
## Summary

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

I18nKeys.h and I18nStrings.h are generated by gen_i18n.py prior to each
build, so we do not need to maintain a checked-in copy of these files.

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _**NO**_
2026-02-24 11:42:05 -06:00
Zach NelsonandCursor 0eb8a9346b feat: Support for kerning and ligatures (#873)
## Summary

**What is the goal of this PR?**
Improved typesetting, including
[kerning](https://en.wikipedia.org/wiki/Kerning) and
[ligatures](https://en.wikipedia.org/wiki/Ligature_(writing)#Latin_alphabet).

**What changes are included?**
- The script to convert built-in fonts now adds kerning and ligature
information to the generated font headers.
- Epub page layout calculates proper kerning spaces and makes ligature
substitutions according to the selected font.


![3U1B1808](https://github.com/user-attachments/assets/1accb16f-2f1a-41e5-adca-89f1f1348494)

![3U1B1810](https://github.com/user-attachments/assets/2f6bd007-490e-420f-b774-3380b4add7ea)

![3U1B1815](https://github.com/user-attachments/assets/1986bb77-2db0-46e2-a5d6-8315dae9eb19)

## Additional Context

- I am not a typography expert. 
- The implementation has been reworked from the earlier version, so it
is no longer necessary to omit Open Dyslexic, and kerning data now
covers all fonts, styles, and codepoints for which we include bitmap
data.
- Claude Opus 4.6 helped with a lot of this.
- There's an included test epub document with lots of kerning and
ligature examples, shown in the photos.

**_After some time to mature, I think this change is in decent shape to
merge and get people testing._**

After opening this PR I came across #660, which overlaps in adding
ligature support.

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _**YES, Claude Opus 4.6**_

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-24 11:31:43 +03:00
Zach Nelson 13fc8b94b0 refactor: Simplify REPLACEMENT_GLYPH fallback (#1119)
## Summary

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

Consolidated repeated logic to fall back to REPLACEMENT_GLYPH.

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _**NO**_
2026-02-23 13:32:50 +01:00
Zach Nelson 410c70ab89 perf: UITheme::getMetrics const and const-ref usage (#1094)
## Summary

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

Small cleanup to make getTheme and getMetrics methods on UITheme const.
They return const refs, so updated call sites to use `const auto&`.

Realistically this won't make much performance difference, but it better
conveys the nature of theme metrics being shared const state.

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _**NO**_
2026-02-23 13:29:18 +01:00
Zach NelsonandKuanysh Bekkulov 3696794591 perf: Replace std::list with std::vector in text layout (#1038)
## Summary

_Revision to @blindbat's #802. Description comes from the original PR._

- Replace `std::list` with `std::vector` for word storage in `TextBlock`
and `ParsedText`
- Use index-based access (`words[i]`) instead of iterator advancement
(`std::advance(it, n)`)
- Remove the separate `continuesVec` copy that was built from
`wordContinues` for O(1) access — now unnecessary since
`std::vector<bool>` already provides O(1) indexing

## Why

`std::list` allocates each node individually on the heap with 16 bytes
of prev/next pointer overhead per node. For text layout with many small
words, this means:
- Scattered heap allocations instead of contiguous memory
- Poor cache locality during iteration (each node can be anywhere in
memory)
- Per-node malloc/free overhead during construction and destruction

`std::vector` stores elements contiguously, giving better cache
performance during the tight rendering and layout loops. The
`extractLine` function also benefits: list splice was O(1) but required
maintaining three parallel iterators, while vector range construction
with move iterators is simpler and still efficient for the small
line-sized chunks involved.

## Files changed

- `lib/Epub/Epub/blocks/TextBlock.h` / `.cpp`
- `lib/Epub/Epub/ParsedText.h` / `.cpp`

## AI Usage

YES

## Test plan

- [ ] Open an EPUB with mixed formatting (bold, italic, underline) —
verify text renders correctly
- [ ] Open a book with justified text — verify word spacing is correct
- [ ] Open a book with hyphenation enabled — verify words break
correctly at hyphens
- [ ] Navigate through pages rapidly — verify no rendering glitches or
crashes
- [ ] Open a book with long paragraphs — verify text layout matches
pre-change behavior

---------

Co-authored-by: Kuanysh Bekkulov <kbekkulov@gmail.com>
2026-02-22 15:28:56 +11:00
Zach Nelson 448a77f02b perf: Remove hasPrintableChars pass (#971)
## Summary

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

`hasPrintableChars` does a pass over text before rendering. It looks up
glyphs in the font and measures dimensions, returning early if the text
results in zero size.

This additional pass doesn't offer any benefit over moving straight to
rendering the text, because the rendering loop already gracefully
handles missing glyphs. This change saves an extra pass over all
rendered text.

Note that both `hasPrintableChars` and `renderChar` replace missing
glyphs with `glyph = getGlyph(REPLACEMENT_GLYPH)`, so there's no
difference for characters which are not present in the font.

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _**NO**_
2026-02-19 21:58:09 +11:00
Zach Nelson f1740dbe1e fix: Correct word width and space calculations (#963)
## Summary

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

This change fixes an issue I noticed while reading where occasionally,
especially in italics, some words would have too much space between
them. The problem was that word width calculations were including any
negative X overhang, and combined with a space before the word, that can
lead to an inconsistently large space.

## Additional Context

Screenshots of some problematic text:

| In CrossPoint 1.0 | With this change |
| -- | -- |
| <img
src="https://github.com/user-attachments/assets/87bf0e4b-341f-4ba9-b3ea-38c13bd26363"
width="400" /> | <img
src="https://github.com/user-attachments/assets/bf11ba20-c297-4ce1-aa07-43477ef86fc2"
width="400" /> |

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _**NO**_
2026-02-19 20:44:07 +11:00
Zach Nelson d02e21a48f fix: Added missing up/down button labels (#935)
## Summary

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

In some places, button labels are omitted intentionally because the
button has no purpose in the activity. I noticed a few obvious cases,
like Home > File Transfer and Settings > System > Language, where the up
and down button labels were missing. This change fixes those and all
similar instances I could find.

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _**NO**_
2026-02-18 21:54:02 +03:00
Zach Nelson 9125a7ce68 perf: Avoid redundant font map lookups (#933)
## Summary

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

Several methods in GfxRenderer were doing a `count()` followed by `at()`
on the fonts map, effectively doing the same map lookup unnecessarily.
This can be avoided by doing a single `find()` and reusing the iterator.

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _**NO**_
2026-02-18 11:55:41 +01:00
Zach Nelson 97c33141bd perf: Skip constructing unnecessary std::string (#932)
## Summary

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

Skip constructing a `std::string` just to get the underlying `c_str()`
buffer, when a string literal gives the same end result.

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _**NO**_
2026-02-16 22:07:08 +01:00