ReadViewSDK/.planning/phases/04-reader-capabilities/04-RESEARCH.md

8.3 KiB
Raw Blame History

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 4s 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 users 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>