// RDEPUBPublication.swift // EPUB 出版物门面(Facade) // 对 RDEPUBParser 的高层封装,提供 metadata、spine、TOC 等只读访问, // 以及固定版式双页展开判断和 spread 生成等业务逻辑。 // 是 EPUBCore Publication 层对外暴露的主要接口。 import Foundation /// EPUB 出版物门面对象,封装解析结果并提供高层访问接口 public final class RDEPUBPublication { /// 底层解析器(持有解析数据) public let parser: RDEPUBParser /// 资源解析器(URL 转换和路径规范化) public let resourceResolver: RDEPUBResourceResolver /// 基于解析器创建出版物门面对象 /// - Parameter parser: 已完成解析的 EPUB 解析器 public init(parser: RDEPUBParser) { self.parser = parser self.resourceResolver = RDEPUBResourceResolver(parser: parser) } /// 元数据代理 public var metadata: RDEPUBMetadata { parser.metadata } /// 资源清单代理 public var manifest: [String: RDEPUBManifestItem] { parser.manifest } /// 阅读顺序代理 public var spine: [RDEPUBSpineItem] { parser.spine } /// 目录代理 public var tableOfContents: [EPUBTableOfContentsItem] { parser.tableOfContents } /// 布局模式(fixed/reflowable) public var layout: RDEPUBLayout { metadata.layout } /// 阅读配置文件(webFixedLayout/webInteractive/textReflowable) public var readingProfile: RDEPUBReadingProfile { parser.readingProfile() } /// 阅读方向(ltr/rtl/auto) public var readingProgression: RDEPUBReadingProgression { metadata.readingProgression } /// 书籍唯一标识符 public var bookIdentifier: String? { metadata.identifier } /// 判断固定版式是否启用双页展开模式 /// 综合考虑 metadata.spread、偏好设置和视口方向 public func fixedLayoutSpreadEnabled(for preferences: RDEPUBPreferences, viewportSize: CGSize) -> Bool { guard layout == .fixed else { return false } guard metadata.spread?.lowercased() != "none" else { return false } switch preferences.fixedLayoutSpreadMode { case .never: return false case .always: return spine.count > 1 case .automatic: return viewportSize.width > viewportSize.height } } /// 根据偏好和视口生成固定版式的 spread 数组 public func makeFixedSpreads(preferences: RDEPUBPreferences, viewportSize: CGSize) -> [EPUBFixedSpread] { EPUBFixedSpread.makeSpreads( spine: spine, spreadEnabled: fixedLayoutSpreadEnabled(for: preferences, viewportSize: viewportSize) ) } }