fix: BookInfo performance — Y-culling, newline normalization, cover clamping

Addressed critical render performance issues identified via device debug log:
- Add Y-culling in render() to skip off-screen draw calls (was causing
  337K LOG_ERR calls per frame, 7-13s render times)
- Normalize description whitespace (strip embedded \n/\r/\t) to prevent
  "No glyph for codepoint 10" errors
- Clamp cover bitmap maxHeight to prevent drawing beyond screen edge
- Pre-compute layout in onEnter() with InfoField struct (wrappedText
  called once, not per frame)
- Add cover image display via generateThumbBmp + drawBitmap1Bit

Made-with: Cursor
This commit is contained in:
cottongin
2026-03-09 01:52:07 -04:00
parent 4cf395aee9
commit 1105919359
3 changed files with 228 additions and 72 deletions

View File

@@ -0,0 +1,38 @@
# BookInfoActivity: Performance Fix and Cover Image
## Task
Fix BookInfoActivity sluggishness (slow open, unresponsive scrolling) and add book cover display.
## Root Cause (from device debug log)
1. **No Y-culling in render()**: All text lines drawn even when off-screen. Content extending ~1162px on 800px screen caused hundreds of thousands of `LOG_ERR("Outside range")` calls per frame, each doing serial I/O. Render times: 7-13 seconds per frame.
2. **Description text contained literal newlines**: `stripHtml()` and `trim()` in ContentOpfParser don't replace interior `\n` characters. These got passed to `drawText()`, triggering "No glyph for codepoint 10" errors.
3. **`wrappedText()` recomputed every frame**: Original render called it for every field on every scroll -- now pre-computed once.
4. **No cover image**: Activity never loaded or displayed any cover.
## Changes Made
### Committed first: PR #1342 port (commit 4cf395a)
- Staged and committed all prior working state before making further changes
### BookInfoActivity refactor (2 files)
**`src/activities/home/BookInfoActivity.h`**:
- Replaced individual metadata string members with `InfoField` struct + `std::vector<InfoField> fields`
- Added `coverBmpPath`, `coverDisplayHeight`, `coverDisplayWidth` members
- Added `buildLayout()` method for pre-computation
**`src/activities/home/BookInfoActivity.cpp`**:
- **Y-culling**: `render()` skips draw calls for items entirely above or below the visible screen area (`y + height > 0 && y < pageH`); breaks out of field loop when `y >= pageH`
- **Newline normalization**: Added `normalizeWhitespace()` helper that collapses `\n`, `\r`, `\t` sequences into single spaces; applied to description text before word-wrapping
- **Cover height clamping**: `drawBitmap1Bit` maxHeight capped to `std::min(coverDisplayHeight, pageH - y)` to prevent drawing beyond screen
- **Pre-computed layout**: All `wrappedText()` calls moved to `onEnter()` via `buildLayout()`; `render()` only iterates pre-computed lines
- Cover thumbnail generated via `epub.generateThumbBmp()` / `xtc.generateThumbBmp()`; fallback to `PlaceholderCoverGenerator`
- Cover rendered centered at top using `renderer.drawBitmap1Bit()`
## Build Verification
- `pio run` SUCCESS (19s incremental, RAM 30.3%, Flash 95.7%)
## Follow-up Items
- Hardware test: verify render times dropped from 7-13s to <100ms with Y-culling
- Hardware test: verify cover image renders correctly
- Hardware test: verify scroll responsiveness on device