124 lines
8.3 KiB
Markdown
124 lines
8.3 KiB
Markdown
# Phase 4: 接回现有 reader 能力链路 - Research
|
||
|
||
**Researched:** 2026-05-22
|
||
**Domain:** iOS EPUB reader reintegration / location mapping / highlight-search-state continuity
|
||
**Confidence:** HIGH
|
||
|
||
<user_constraints>
|
||
## User Constraints
|
||
|
||
No `CONTEXT.md` exists for this phase. Planning is based on ROADMAP requirements, current code, and completed artifacts from Phases 1-3 only.
|
||
</user_constraints>
|
||
|
||
<architectural_responsibility_map>
|
||
## Architectural Responsibility Map
|
||
|
||
| Capability | Primary Tier | Secondary Tier | Rationale |
|
||
|------------|-------------|----------------|-----------|
|
||
| Reflowable native pagination output | EPUBTextRendering | EPUBCore | Phase 3 already moved richer page semantics into `RDEPUBTextBook` / `RDEPUBTextPage`. |
|
||
| Reader orchestration and restore logic | EPUBUI | EPUBCore | `RDEPUBReaderController` owns `paginatePublication`, `finishPagination`, restore, search navigation, selection, and configuration updates. |
|
||
| Page lookup and navigator state | EPUBCore | EPUBUI | `RDEPUBReadingSession` remains the non-UI state owner for fixed/web flows and should keep that role rather than pushing state into `RDReaderView`. |
|
||
| Highlight/search persistence semantics | EPUBCore | EPUBUI | `RDEPUBTextOffsetRangeInfo` and normalized locations are the durable compatibility contract. |
|
||
| Page-turn UI and display modes | RDReaderView | EPUBUI | Explicitly out of scope to change; Phase 4 must adapt to existing `RDReaderView` APIs. |
|
||
|
||
</architectural_responsibility_map>
|
||
|
||
<research_summary>
|
||
## Summary
|
||
|
||
Phase 3 strengthened the native reflowable engine but did not yet make that richer page model a first-class citizen across the whole reader capability chain. The main Phase 4 work is therefore not “more pagination”; it is reconnecting the existing reader shell to the upgraded `RDEPUBTextBook` path without changing `RDReaderView` or introducing a second native reader model.
|
||
|
||
The current code already shows the exact reintegration seams:
|
||
|
||
- `RDEPUBReaderController.paginatePublication` branches between native `RDEPUBTextBookBuilder`, fixed-layout snapshots, and `RDEPUBPaginator` WebKit measurement.
|
||
- `applyTextBook`, `finishPagination`, `restoreReadingLocation`, and `currentVisibleLocation` already contain a parallel text-book path that bypasses `RDEPUBReadingSession.pageIndex(for:)`.
|
||
- `pageContentView(readerView:pageNum:containerView:)` already swaps between `RDEPUBTextContentView` and `RDEPUBWebContentView`.
|
||
- Search uses `RDEPUBTextSearchEngine` when `textBook` exists and `RDEPUBHTMLSearchEngine` otherwise.
|
||
- Selection/highlight persistence for native text still depends on `RDEPUBTextOffsetRangeInfo` absolute offsets and chapter href normalization.
|
||
|
||
That means Phase 4 should stabilize and tighten an already-existing split path rather than invent a new architecture. The right outcome is:
|
||
|
||
1. Reflowable native pages remain rendered through `RDEPUBTextBook`.
|
||
2. `RDEPUBReaderController` keeps one coherent restore/navigation/search/highlight API no matter whether the source page is native text or Web content.
|
||
3. Repagination triggered by font size, line height, viewport changes, or theme changes preserves reader state instead of resetting to page 1 or dropping search/highlight context.
|
||
|
||
The riskiest compatibility areas are also already visible:
|
||
|
||
- `RDEPUBReaderController.restoreReadingLocation` and `currentVisibleLocation` use separate logic for text-book vs snapshot pages.
|
||
- `normalizedTextSelection` recomputes progression from absolute offset payloads; regressions here would silently break persisted highlights.
|
||
- `refreshVisibleContentPreservingLocation` and `rebuildExternalTextBook` can preserve location only if the text-book lookup contract remains stable after repagination.
|
||
- `flattenedTableOfContentsItems` and `pageNumber(for:)` need page-number continuity for TOC and search to stay believable.
|
||
|
||
**Primary recommendation:** Treat Phase 4 as a reader-state consolidation phase. Strengthen `RDEPUBReaderController` and adjacent state surfaces so the Phase 3 native pagination model behaves like a first-class reader backend while preserving the existing `RDReaderView` page-turn container and the fixed / interactive WebKit paths.
|
||
</research_summary>
|
||
|
||
<code_evidence>
|
||
## Code Evidence
|
||
|
||
| Concern | Source | Why it matters |
|
||
|--------|--------|----------------|
|
||
| Native-vs-web pagination entry split | `RDEPUBReaderController.paginatePublication` | Defines Phase 4’s main re-integration entry point. |
|
||
| Native restore and current-location logic | `RDEPUBReaderController.restoreReadingLocation`, `currentVisibleLocation` | Text-book navigation already bypasses `RDEPUBReadingSession`; this must stay coherent. |
|
||
| Reader state owner for non-native flows | `RDEPUBReadingSession` | Existing navigation/session state should remain centralized instead of leaking into UI code. |
|
||
| Native selection/highlight normalization | `RDEPUBReaderController.normalizedTextSelection`, `RDEPUBTextContentView`, `RDEPUBReadingModels` | Absolute offsets must survive reader interactions and persistence. |
|
||
| Search backend switching | `RDEPUBReaderController.resolvedSearchMatches`, `RDEPUBTextSearchEngine` | Search behavior must remain uniform from the user’s perspective across render backends. |
|
||
| Repagination triggers | `RDEPUBReaderController.configuration.didSet`, `handleViewportChangeIfNeeded`, `rebuildExternalTextBook`, `repaginatePreservingCurrentLocation` | These are the operational triggers most likely to break restore/state continuity. |
|
||
|
||
</code_evidence>
|
||
|
||
<architecture_patterns>
|
||
## Architecture Patterns
|
||
|
||
### Pattern 1: Consolidate reader behavior at the controller boundary
|
||
**What:** Keep branching localized in `RDEPUBReaderController`, but make navigation, restore, search, and persistence semantics consistent across text-book and web paths.
|
||
**Why:** The UI entry point already exists there; moving branching elsewhere would enlarge scope.
|
||
|
||
### Pattern 2: Keep offsets as the native compatibility key
|
||
**What:** Native text selection, search, and highlight flows should continue to resolve through chapter href + absolute offset payloads.
|
||
**Why:** Phase 3 deliberately preserved this invariant to make Phase 4 possible.
|
||
|
||
### Pattern 3: Repaginate by restoring location, not page number
|
||
**What:** Font/theme/viewport changes should always preserve a semantic location and rebuild around it.
|
||
**Why:** Page numbers are not stable under re-pagination; href + progression + offset-compatible selection are.
|
||
|
||
### Anti-Patterns to Avoid
|
||
- Refactoring `RDReaderView` to understand native page metadata directly.
|
||
- Creating a second navigation state machine just for the native text path.
|
||
- Switching highlights/search to page-local identifiers that cannot survive repagination.
|
||
|
||
</architecture_patterns>
|
||
|
||
<dont_hand_roll>
|
||
## Don't Hand-Roll
|
||
|
||
| Problem | Don't Build | Use Instead | Why |
|
||
|---------|-------------|-------------|-----|
|
||
| Native reader shell | A new dedicated native-text controller | Existing `RDEPUBReaderController` split path | Scope stays contained and existing app entry points remain valid. |
|
||
| Restore state | Page-number-only recovery | `RDEPUBLocation` + native page lookup + offset contract | Page numbers drift after repagination. |
|
||
| Search compatibility | Separate search UI semantics for text pages | Existing `RDEPUBSearchState` and `RDEPUBSearchMatch` flow | User-facing search behavior should stay unified. |
|
||
|
||
</dont_hand_roll>
|
||
|
||
<common_pitfalls>
|
||
## Common Pitfalls
|
||
|
||
### Pitfall 1: Letting native and web reader paths diverge in user-visible behavior
|
||
If search, selection, or TOC navigation behaves differently based on backend, the reader becomes unpredictable.
|
||
|
||
### Pitfall 2: Preserving page numbers instead of semantic locations during repagination
|
||
This causes subtle wrong-page restores after font, theme, or viewport changes.
|
||
|
||
### Pitfall 3: Refreshing visible content without reapplying current search/highlight state
|
||
Native text pages are recreated from attributed substrings, so state must be re-derived every time.
|
||
|
||
</common_pitfalls>
|
||
|
||
<open_questions>
|
||
## Open Questions
|
||
|
||
- Should any of the new Phase 3 page metadata be surfaced to reader delegates in Phase 4, or remain internal until Phase 5 diagnostics?
|
||
- Is `RDEPUBReadingSession` worth extending to cover native `RDEPUBTextBook` page lookup as well, or is the current controller-local split still the smallest safe change?
|
||
- Which search/highlight and TOC navigation paths are most important to validate interactively in the demo during execution?
|
||
|
||
</open_questions>
|