- 新增 RDEPUBReaderSearchCoordinator 与 RDEPUBSelectionState 管理搜索和选中状态 - 新增 BookmarkChromeStateTests、NavigationBackwardTests、SelectionAnnotateTests 等 UI 测试 - 新增多个边界测试 epub 样本(损坏结构、空归档、缺失文件、流式外链验证) - 重构阅读器 chrome 状态管理,统一 tool bar 与 search bar 交互 - 优化大书分页缓存策略(RDEPUBChapterSummaryDiskCache、RDEPUBPageCountCache) - 移除废弃的 RDEPUBLocationConverter 和 RDEPUBPageBreakPolicy - 更新 epub-bridge.js 与 JS bridge 通信协议 - 全面更新现有 UI 测试以适配新的 helper 和状态管理
105 lines
4.5 KiB
Swift
105 lines
4.5 KiB
Swift
// RDEPUBReaderController+RenderSupport.swift
|
||
// EPUB 阅读器渲染支持辅助方法
|
||
// 提供获取当前布局上下文、偏好设置、页面尺寸、渲染样式、文本布局配置,
|
||
// 以及构建渲染请求、管理分页宿主视图和回退位置查询等功能。
|
||
|
||
import UIKit
|
||
|
||
/// RDEPUBReaderController 渲染支持扩展
|
||
///
|
||
/// 本文件提供阅读器渲染所需的辅助方法,包括获取当前布局上下文、偏好设置、页面尺寸、
|
||
/// 渲染样式、文本布局配置,以及构建渲染请求和回退位置查询等功能。
|
||
|
||
extension RDEPUBReaderController {
|
||
/// 获取当前导航器布局上下文(视口尺寸、方向等)
|
||
func currentLayoutContext() -> RDEPUBNavigatorLayoutContext {
|
||
readerContext.currentLayoutContext()
|
||
}
|
||
|
||
/// 获取当前阅读偏好设置
|
||
func currentPreferences() -> RDEPUBPreferences {
|
||
readerContext.currentPreferences()
|
||
}
|
||
|
||
/// 获取当前文本页面尺寸
|
||
func currentTextPageSize() -> CGSize {
|
||
readerContext.currentTextPageSize()
|
||
}
|
||
|
||
/// 获取当前文本渲染样式(字体、行高等)
|
||
func currentTextRenderStyle() -> RDEPUBTextRenderStyle {
|
||
readerContext.currentTextRenderStyle()
|
||
}
|
||
|
||
/// 获取指定页面尺寸下的文本布局配置
|
||
func currentTextLayoutConfig(pageSize: CGSize) -> RDEPUBTextLayoutConfig {
|
||
readerContext.currentTextLayoutConfig(pageSize: pageSize)
|
||
}
|
||
|
||
/// 获取已解析的文本渲染器实例
|
||
func resolvedTextRenderer() -> RDEPUBTextRenderer {
|
||
readerContext.resolvedTextRenderer()
|
||
}
|
||
|
||
/// 确保分页宿主视图已添加到视图层级(位于屏幕外用于预计算分页)
|
||
func ensurePaginationHostView() -> UIView {
|
||
let viewportSize = currentLayoutContext().viewportSize
|
||
let hostFrame = CGRect(x: -viewportSize.width - 32, y: 0, width: viewportSize.width, height: viewportSize.height)
|
||
if paginationHostView.superview == nil {
|
||
view.addSubview(paginationHostView)
|
||
view.sendSubviewToBack(paginationHostView)
|
||
}
|
||
paginationHostView.frame = hostFrame
|
||
return paginationHostView
|
||
}
|
||
|
||
/// 为指定页面索引构建渲染请求(含位置、高亮、搜索状态)
|
||
func request(for pageIndex: Int) -> RDEPUBRenderRequest? {
|
||
guard let publication, activePages.indices.contains(pageIndex) else {
|
||
return nil
|
||
}
|
||
let page = activePages[pageIndex]
|
||
let pendingLocation = readingSession?.pendingLocation(forPageNumber: pageIndex + 1, spineIndex: page.spineIndex)
|
||
let pendingHighlightRangeInfo = readingSession?.pendingHighlightRangeInfo(
|
||
forPageNumber: pageIndex + 1,
|
||
spineIndex: page.spineIndex
|
||
)
|
||
return currentPreferences().renderRequest(
|
||
for: page,
|
||
publication: publication,
|
||
viewportSize: currentLayoutContext().viewportSize,
|
||
targetLocation: pendingLocation,
|
||
targetHighlightRangeInfo: pendingHighlightRangeInfo,
|
||
highlights: highlights(for: page),
|
||
searchPresentation: searchPresentation(for: page)
|
||
)
|
||
}
|
||
|
||
/// 获取指定页面索引的回退位置(当无法确定精确位置时使用)
|
||
func fallbackLocation(for pageIndex: Int) -> RDEPUBLocation? {
|
||
guard activePages.indices.contains(pageIndex) else { return nil }
|
||
return readingSession?.fallbackLocation(for: activePages[pageIndex], bookIdentifier: currentBookIdentifier)
|
||
}
|
||
|
||
/// 获取指定固定布局页面上的高亮标注列表
|
||
private func highlights(for page: EPUBPage) -> [RDEPUBHighlight] {
|
||
guard let publication else { return [] }
|
||
if let spread = page.fixedSpread {
|
||
let hrefs = Set(spread.resources.compactMap { publication.resourceResolver.normalizedHref($0.href) })
|
||
return activeHighlights.filter { highlight in
|
||
guard let normalizedHref = publication.resourceResolver.normalizedHref(highlight.location.href) else {
|
||
return false
|
||
}
|
||
return hrefs.contains(normalizedHref)
|
||
}
|
||
}
|
||
|
||
guard publication.spine.indices.contains(page.spineIndex) else { return [] }
|
||
let href = publication.spine[page.spineIndex].href
|
||
let normalizedHref = publication.resourceResolver.normalizedHref(href)
|
||
return activeHighlights.filter { highlight in
|
||
publication.resourceResolver.normalizedHref(highlight.location.href) == normalizedHref
|
||
}
|
||
}
|
||
}
|