ReadViewSDK/.planning/phases/08-pagination-quality-cache-performance/08-02-SUMMARY.md

3.4 KiB

phase plan type date
08-pagination-quality-cache-performance 02 summary 2026-05-23

Phase 08-02 Summary

Objective

Improve pagination quality by enforcing avoidPageBreakInside, adding orphan/widow line control, and implementing general image fit-to-page sizing.

Tasks Completed

Task 1: RDEPUBTextLayoutConfig struct and wiring

  • Defined RDEPUBTextLayoutConfig in RDEPUBTextRenderer.swift with 4 properties: avoidOrphans, avoidWidows, avoidPageBreakInsideEnabled, imageMaxHeightRatio (default 0.85)
  • Follows the exact RDEPUBTextRenderStyle struct pattern: public struct, public stored properties, public init with defaults, static .default instance
  • Added config parameter to RDEPUBTextLayouter.init with .default default value
  • Added config parameter to rd_paginatedFrames extension with .default default value
  • All existing call sites continue to work unchanged (backward compatible)

Task 2: avoidPageBreakInside enforcement + orphan/widow control

  • Added avoidPageBreakInsideBoundary(in:minimumEnd:) method in RDEPUBTextLayouter.swift
    • Detects when page end falls INSIDE an avoidPageBreakInside block (complement to existing check that only handles block start as boundary)
    • Pushes entire block to next page when block start >= minimumEnd
    • Gated on config.avoidPageBreakInsideEnabled
  • Added orphanWidowAdjustedRange(from:minimumEnd:) method
    • Orphan control: When page starts at a paragraph beginning and only 1-2 lines fit, pulls back to include more content from previous page
    • Widow control: When page ends with only 1-2 lines of a paragraph remaining, pushes entire paragraph to next page
    • Both gated on config.avoidOrphans and config.avoidWidows respectively
  • Inserted both checks in adjustedRange() between preferredSemanticBoundary and preferredAttachmentBoundary
  • Diagnostic strings emitted on trigger: "avoidPageBreakInside enforcement", "orphan control: ...", "widow control: ..."

Task 3: General image fit-to-page sizing and diagnostics

  • Added return at end of cover image block to prevent fall-through to general handling
  • Added general image sizing block for all non-footnote, non-cover images:
    • Scales images exceeding maxImageHeight (screen height * 0.85) or maxWidth proportionally
    • Sets verticalAlignment = .center for block-level images (bodyPic, qrbodyPic, figure, .block displayStyle)
  • Added diagnostic output:
    • [EPUB][Attachment] general image ... with original/display sizes and scaled flag
    • [EPUB][Attachment] dark mode: image colors preserved ... when in dark mode
    • [EPUB][Attachment] background: ... with hasBackground check for attachment blocks

Files Modified

  • Sources/RDReaderView/EPUBTextRendering/RDEPUBTextRenderer.swift — added RDEPUBTextLayoutConfig struct
  • Sources/RDReaderView/EPUBTextRendering/RDEPUBTextLayouter.swift — added config property, avoidPageBreakInside enforcement, orphan/widow control
  • Sources/RDReaderView/EPUBTextRendering/RDEPUBTextPaginationSupport.swift — added config parameter to rd_paginatedFrames
  • Sources/RDReaderView/EPUBTextRendering/RDEPUBTextRendererSupport.swift — added general image sizing, cover return, diagnostic output

Build Status

All three tasks verified with xcodebuild build -workspace ReadViewDemo/ReadViewDemo.xcworkspace -scheme ReadViewDemo -destination 'platform=iOS Simulator,name=iPhone 17 Pro' — BUILD SUCCEEDED for each.