182 lines
6.0 KiB
Swift
182 lines
6.0 KiB
Swift
//
|
||
// RDEPUBRenderRequest.swift
|
||
// RDReaderView
|
||
//
|
||
// EPUBCore 层渲染请求模型定义文件。
|
||
// 包含渲染所需的展示样式(PresentationStyle)、可重排/固定版式渲染请求(RenderRequest)、
|
||
// 固定版式适配模式(Fit)和 Spread 模式(SpreadMode)。
|
||
// 由 RDEPUBPreferences 构建,传递给 RDEPUBWebView 执行渲染。
|
||
//
|
||
|
||
import UIKit
|
||
|
||
/// 固定版式页面适配模式
|
||
/// - auto: 自动选择最佳适配策略
|
||
/// - page: 适配整页(缩放至屏幕大小)
|
||
/// - width: 适配宽度(按宽度等比缩放)
|
||
public enum RDEPUBFixedLayoutFit: String, Codable {
|
||
case auto
|
||
case page
|
||
case width
|
||
}
|
||
|
||
/// 固定版式 Spread(双页)显示模式
|
||
/// - automatic: 根据设备方向和屏幕尺寸自动判断
|
||
/// - always: 始终启用双页显示
|
||
/// - never: 始终单页显示
|
||
public enum RDEPUBFixedLayoutSpreadMode: String, Codable {
|
||
case automatic
|
||
case always
|
||
case never
|
||
}
|
||
|
||
/// 渲染展示样式,WebView 和 Paginator 共用的视觉参数
|
||
/// 由 RDEPUBPreferences 根据用户设置构建
|
||
public struct RDEPUBPresentationStyle: Equatable {
|
||
/// 视口尺寸(容器的可见区域大小)
|
||
public var viewportSize: CGSize
|
||
/// 内容内边距(上下左右的安全区域偏移)
|
||
public var contentInsets: UIEdgeInsets
|
||
/// 字号(pt)
|
||
public var fontSize: CGFloat
|
||
/// 行距倍数(1.0 为默认行距)
|
||
public var lineHeightMultiple: CGFloat
|
||
/// 栏数,对标 WXRead 的多栏分页配置
|
||
public var numberOfColumns: Int
|
||
/// 栏间距,对标 WXRead 的 columnGap
|
||
public var columnGap: CGFloat
|
||
/// 主题背景色(CSS 颜色值,如 "#FFFFFF")
|
||
public var themeBackgroundColor: String?
|
||
/// 主题文字色(CSS 颜色值,如 "#000000")
|
||
public var themeTextColor: String?
|
||
|
||
public init(
|
||
viewportSize: CGSize,
|
||
contentInsets: UIEdgeInsets,
|
||
fontSize: CGFloat,
|
||
lineHeightMultiple: CGFloat,
|
||
numberOfColumns: Int = 1,
|
||
columnGap: CGFloat = 20,
|
||
themeBackgroundColor: String? = nil,
|
||
themeTextColor: String? = nil
|
||
) {
|
||
self.viewportSize = viewportSize
|
||
self.contentInsets = contentInsets
|
||
self.fontSize = fontSize
|
||
self.lineHeightMultiple = lineHeightMultiple
|
||
self.numberOfColumns = max(1, numberOfColumns)
|
||
self.columnGap = max(0, columnGap)
|
||
self.themeBackgroundColor = themeBackgroundColor
|
||
self.themeTextColor = themeTextColor
|
||
}
|
||
}
|
||
|
||
/// 可重排内容渲染请求,包含加载和渲染一个 reflowable spine 项所需的全部参数
|
||
public struct RDEPUBReflowableRenderRequest: Equatable {
|
||
/// spine 索引
|
||
public var spineIndex: Int
|
||
/// 资源路径
|
||
public var href: String
|
||
/// 目标页在章节中的索引
|
||
public var pageIndex: Int
|
||
/// 该章节的总页数
|
||
public var totalPagesInChapter: Int
|
||
/// 展示样式
|
||
public var presentation: RDEPUBPresentationStyle
|
||
/// 目标跳转位置(用于恢复阅读位置或锚点跳转)
|
||
public var targetLocation: RDEPUBLocation?
|
||
/// 高亮列表
|
||
public var highlights: [RDEPUBHighlight]
|
||
/// 搜索结果展示信息
|
||
public var searchPresentation: RDEPUBSearchPresentation?
|
||
|
||
public init(
|
||
spineIndex: Int,
|
||
href: String,
|
||
pageIndex: Int,
|
||
totalPagesInChapter: Int,
|
||
presentation: RDEPUBPresentationStyle,
|
||
targetLocation: RDEPUBLocation? = nil,
|
||
highlights: [RDEPUBHighlight] = [],
|
||
searchPresentation: RDEPUBSearchPresentation? = nil
|
||
) {
|
||
self.spineIndex = spineIndex
|
||
self.href = href
|
||
self.pageIndex = pageIndex
|
||
self.totalPagesInChapter = totalPagesInChapter
|
||
self.presentation = presentation
|
||
self.targetLocation = targetLocation
|
||
self.highlights = highlights
|
||
self.searchPresentation = searchPresentation
|
||
}
|
||
}
|
||
|
||
/// 固定版式渲染请求,包含加载和渲染一个 fixed spread 所需的全部参数
|
||
public struct RDEPUBFixedRenderRequest: Equatable {
|
||
/// 要渲染的 spread(包含 1-2 个资源)
|
||
public var spread: EPUBFixedSpread
|
||
/// 视口尺寸
|
||
public var viewportSize: CGSize
|
||
/// 内容内边距
|
||
public var contentInset: UIEdgeInsets
|
||
/// 背景色 CSS 值
|
||
public var backgroundColorCSS: String?
|
||
/// 页面适配模式(auto/page/width)
|
||
public var fit: RDEPUBFixedLayoutFit
|
||
/// 搜索结果展示信息
|
||
public var searchPresentation: RDEPUBSearchPresentation?
|
||
|
||
public init(
|
||
spread: EPUBFixedSpread,
|
||
viewportSize: CGSize,
|
||
contentInset: UIEdgeInsets,
|
||
backgroundColorCSS: String? = nil,
|
||
fit: RDEPUBFixedLayoutFit = .page,
|
||
searchPresentation: RDEPUBSearchPresentation? = nil
|
||
) {
|
||
self.spread = spread
|
||
self.viewportSize = viewportSize
|
||
self.contentInset = contentInset
|
||
self.backgroundColorCSS = backgroundColorCSS
|
||
self.fit = fit
|
||
self.searchPresentation = searchPresentation
|
||
}
|
||
}
|
||
|
||
/// 渲染请求枚举,统一可重排和固定版式两种渲染模式
|
||
/// RDEPUBWebView 根据此请求类型选择对应的加载和渲染路径
|
||
public enum RDEPUBRenderRequest: Equatable {
|
||
/// 可重排内容渲染请求
|
||
case reflowable(RDEPUBReflowableRenderRequest)
|
||
/// 固定版式渲染请求
|
||
case fixed(RDEPUBFixedRenderRequest)
|
||
|
||
/// 是否为固定版式渲染
|
||
public var isFixedLayout: Bool {
|
||
if case .fixed = self {
|
||
return true
|
||
}
|
||
return false
|
||
}
|
||
|
||
/// 主资源的 spine 索引
|
||
public var primarySpineIndex: Int {
|
||
switch self {
|
||
case .reflowable(let request):
|
||
return request.spineIndex
|
||
case .fixed(let request):
|
||
return request.spread.primaryResource.spineIndex
|
||
}
|
||
}
|
||
|
||
/// 主资源的路径
|
||
public var primaryHref: String {
|
||
switch self {
|
||
case .reflowable(let request):
|
||
return request.href
|
||
case .fixed(let request):
|
||
return request.spread.primaryResource.href
|
||
}
|
||
}
|
||
}
|