ReadViewSDK/.planning/phases/03-page-metadata-pagination/03-RESEARCH.md

9.4 KiB

Phase 3: 重构属性体系与复杂分页器 - Research

Researched: 2026-05-22 Domain: iOS EPUB native pagination / page metadata / CoreText layout semantics Confidence: HIGH

<user_constraints>

User Constraints

No CONTEXT.md exists for this phase. Planning is based on ROADMAP requirements, current code, Phase 1 strategy, and Phase 2 implementation artifacts only. </user_constraints>

<architectural_responsibility_map>

Architectural Responsibility Map

Capability Primary Tier Secondary Tier Rationale
Page-level attributed string metadata EPUBTextRendering EPUBCore Metadata must stay adjacent to chapter/page models so offsets, fragments, and attachments remain queryable.
Stronger pagination semantics EPUBTextRendering CoreText ss_pageRanges(size:) is the only current paginator; Phase 3 must replace or wrap it with richer layout decisions.
Offset continuity for location/highlight/search EPUBTextRendering EPUBUI RDEPUBTextBook, RDEPUBTextContentView, and RDEPUBReadingSession all assume stable chapter offsets.
Reader state + navigation orchestration EPUBCore EPUBUI RDEPUBReadingSession should keep owning navigation/page lookup; it should consume richer page metadata rather than invent a new UI model.
Fixed / interactive EPUB rendering EPUBCore WebKit Still out of scope; WebView paths remain unchanged.

</architectural_responsibility_map>

<research_summary>

Summary

Phase 2 solved the renderer input problem. The native reflowable path now has chapter-scoped preprocessing, explicit CSS precedence, and resolver-backed resource diagnostics. What remains weak is the page model and paginator. RDEPUBTextPaginationSupport.ss_pageRanges(size:) still slices the chapter with CTFrameGetVisibleStringRange and returns only bare NSRange values. RDEPUBTextPage then stores those ranges plus pageStartOffset / pageEndOffset, but no block metadata, no attachment semantics, no page-edge reasons, and no way to explain why a page boundary landed where it did.

That limitation is now the main blocker for REND-03 and REND-04. Search, selection, highlights, RDEPUBReadingSession.pageIndex(for:), and RDEPUBTextContentView all depend on stable offsets. Phase 3 therefore cannot replace RDEPUBTextBook with a new UI-only model. It has to extend the existing RDEPUBTextChapter / RDEPUBTextPage contract with richer metadata while preserving chapter text continuity and global offsets.

The safest implementation path is incremental:

  1. Define page metadata and attribute keys first.
  2. Introduce an internal layouter / layout-frame abstraction that can reason about blocks, attachments, and page edges while still returning offset-stable page slices.
  3. Validate the new paginator on real EPUBs with large blocks and images before touching Phase 4 reader reintegration.

The repo already exposes the exact compatibility surface we need to preserve:

  • RDEPUBTextContentView derives relative highlight/search ranges from pageStartOffset and pageEndOffset.
  • RDEPUBTextOffsetRangeInfo serializes highlight ranges as absolute chapter offsets.
  • RDEPUBTextSearchEngine indexes chapter-level attributed strings and stores match ranges by chapter offset.
  • RDEPUBReadingSession still resolves navigation by href + progression and maps that back onto active pages.

Primary recommendation: Build a richer internal pagination layer under EPUBTextRendering that emits extended RDEPUBTextPage metadata while keeping pageStartOffset, pageEndOffset, fragmentOffsets, and chapter text continuity intact. Do not move layout logic into RDEPUBReaderController or RDEPUBTextContentView. </research_summary>

<standard_stack>

Standard Stack

Core

Library Version Purpose Why Standard
Foundation System Metadata models, ranges, serialization, diagnostics Existing page/highlight/search models are already Foundation-driven.
CoreText System Low-level line/frame measurement Needed to upgrade beyond pure visible-range slicing.
UIKit iOS 15+ SDK Text page presentation and selection mapping RDEPUBTextContentView still presents NSAttributedString pages and maps ranges back to offsets.
DTCoreText 1.6.28 HTML-to-attributed-string import Phase 3 builds on imported attributed content rather than replacing the typesetter.

Supporting

Library Version Purpose When to Use
ZIPFoundation 0.9.20 EPUB archive access Real-book validation still depends on sample EPUB extraction.
DTFoundation 1.7.19 DTCoreText support Attachment and HTML import remain rooted here.

Alternatives Considered

Instead of Could Use Tradeoff
Extend RDEPUBTextPage / RDEPUBTextChapter Create a brand-new page tree model Would break current reader/highlight/search callers too early and enlarge Phase 4 scope.
Introduce layouter/frame types under EPUBTextRendering Keep growing ss_pageRanges(size:) as a single function Hard to express page-edge reasons, block avoidance rules, and attachment metadata in one range-only helper.
Preserve chapter offsets as the compatibility key Shift to page-local only locations Would break selection/highlight persistence and make Phase 4 much harder.

</standard_stack>

<architecture_patterns>

Architecture Patterns

Pattern 1: Extend, don't replace, the book contract

What: Add metadata to RDEPUBTextPage / RDEPUBTextChapter while preserving existing offset fields. When to use: When downstream readers already depend on href + offsets + pages. Why: Highlights, search matches, and navigation already serialize offsets and chapter hrefs.

Pattern 2: Separate layouter from page serialization

What: Use internal layouter/layout-frame types to compute page boundaries, then convert those results into RDEPUBTextPage. When to use: When pagination logic is becoming more complex than plain visible-range slicing. Why: Keeps RDEPUBTextBookBuilder as the chapter/page assembly boundary without forcing it to own all layout heuristics inline.

Pattern 3: Preserve chapter-level continuity as the invariant

What: Every new metadata structure should be traceable back to absolute chapter offsets. When to use: For block edges, attachments, fragment anchors, and page break reasons. Why: Current location/highlight/search behavior uses absolute chapter ranges; Phase 3 should enrich that graph, not replace it.

Anti-Patterns to Avoid

  • Rewriting RDReaderView or page presentation controls in the name of pagination.
  • Introducing metadata that cannot be mapped back to pageStartOffset / pageEndOffset.
  • Letting validation rely only on “looks okay” manual checks without capturing page-edge or attachment evidence.

</architecture_patterns>

<dont_hand_roll>

Don't Hand-Roll

Problem Don't Build Use Instead Why
Reader reintegration A new reader shell Existing RDEPUBTextBook / RDEPUBReadingSession contract Phase 4 needs continuity, not a second UI model.
Location persistence Page-local ephemeral IDs only Absolute chapter offsets + fragment compatibility Current highlights and search results already use offset-based range info.
Validation Purely visual checks with no metadata evidence Source assertions plus sample EPUB diagnostics Complex pagination bugs need explainable metadata, not only screenshots.

</dont_hand_roll>

<common_pitfalls>

Common Pitfalls

Pitfall 1: Richer metadata that doesn't survive page serialization

If metadata lives only in temporary layout structures and never lands on RDEPUBTextPage, Phase 4 cannot consume it.

Pitfall 2: Better page edges but broken offset continuity

If page boundaries improve but pageStartOffset / pageEndOffset drift from chapter content, highlights and search navigation regress immediately.

Pitfall 3: Attachment-aware pagination without validation hooks

Image/attachment rules are hard to trust unless the phase leaves behind enough metadata or demo diagnostics to confirm what happened on a given page boundary.

</common_pitfalls>

<sota_updates>

State of the Art (2024-2025)

Old Approach Current Approach Impact
CTFrameGetVisibleStringRange only Layout pipeline with page-edge semantics and attachment-aware metadata Needed to express avoid-break rules and richer page reasoning.
Range-only page model Page model with semantic metadata and diagnostics Needed for later reader reintegration and regression debugging.
Paginator hidden inside a helper Layouter/frame responsibilities separated from book assembly Improves testability and makes pagination regressions explainable.

</sota_updates>

<open_questions>

Open Questions

  • Which page metadata belongs directly on RDEPUBTextPage versus a nested layout-metadata payload?
  • Should attachment/block metadata be encoded as custom NSAttributedString.Key values, separate page structs, or both?
  • How much of the new layouter/frame API should remain internal to EPUBTextRendering versus surfaced through RDEPUBTextBookBuilder?
  • Which sample EPUBs in ReadViewDemo/ReadViewDemo/book/ best expose large-block and image boundary cases for repeatable validation?

</open_questions>