docs: 补充注释、修正过时文档、清理重复内容

源码注释:
- 为 ~60 个 Swift 文件补充缺失的 doc comment(file header、类型、属性、方法)
- 修正 4 处错误注释:翻页模式数量、搜索行为描述、手势识别器描述、悬空文档块

文档维护:
- 删除重复文档:WXRead/读书EPUB阅读器实现架构.md(与微信读书版完全一致)
- 合并重叠文档:阅读器规划.md → 阅读器功能开发计划.md(单一真值)
- 修正过时内容:所有文档中"四种翻页模式"→"三种",移除 horizontalCoverScroll
- 更新架构图:补齐 EPUBUI/ReaderController、Paging/、Typesetter/ 等子目录
- 更新 index.md 索引:新增开发计划和架构对比文档引用
This commit is contained in:
shen
2026-06-01 09:33:23 +08:00
parent 1efb9d172f
commit 948004eed1
56 changed files with 1691 additions and 792 deletions
@@ -1,4 +1,6 @@
import UIKit
/// EPUB EPUB publication `RDEPUBTextBook`
public final class RDEPUBTextBookBuilder {
private let renderer: RDEPUBTextRenderer
private let cache: RDEPUBTextBookCache?
@@ -19,6 +21,11 @@ public final class RDEPUBTextBookBuilder {
/// /
public private(set) var lastBuildCacheStats: (hits: Int, misses: Int) = (0, 0)
///
/// - Parameters:
/// - renderer:
/// - cache:
/// - layoutConfig:
public init(
renderer: RDEPUBTextRenderer,
cache: RDEPUBTextBookCache? = nil,
@@ -181,13 +181,3 @@ public struct RDEPUBTextBook {
}
}
// MARK: -
/// EPUB publication
///
/// spine HTML / RDEPUBTextBook
///
///
/// - WXRead
/// - /
/// -
@@ -1,5 +1,9 @@
// RDEPUBTextBuildPipelineInterfaces.swift
// EPUB 线线
import UIKit
/// EPUB EPUB
protocol RDEPUBTextBookBuilding {
func build(
parser: RDEPUBParser,
@@ -9,25 +13,41 @@ protocol RDEPUBTextBookBuilding {
) throws -> RDEPUBTextBook
}
/// 线
struct RDEPUBChapterRenderPipeline {
private let renderer: RDEPUBTextRenderer
/// 线
/// - Parameter renderer:
init(renderer: RDEPUBTextRenderer) {
self.renderer = renderer
}
///
/// - Parameter request:
/// - Returns:
func render(_ request: RDEPUBTextChapterRenderRequest) throws -> RDEPUBRenderedChapterContent {
try renderer.renderChapter(request: request)
}
}
/// 线
struct RDEPUBChapterPaginationPipeline {
private let frameFactory: RDEPUBPageFrameBuilding
/// 线
/// - Parameter frameFactory: 使 CoreText
init(frameFactory: RDEPUBPageFrameBuilding = RDEPUBCoreTextPageFrameFactory()) {
self.frameFactory = frameFactory
}
///
/// - Parameters:
/// - content:
/// - pageSize:
/// - config:
/// - fragmentOffsets: fragment
/// - Returns:
func frames(
for content: NSAttributedString,
pageSize: CGSize,
@@ -1,15 +1,30 @@
// RDEPUBTextPaginationInterfaces.swift
// EPUB
import Foundation
import UIKit
// MARK: -
///
struct RDEPUBPageBreakDecision {
///
var range: NSRange
///
var reason: RDEPUBTextPageBreakReason
///
var diagnostics: [String]
}
///
protocol RDEPUBChapterPageCounting {
///
/// - Parameters:
/// - attributedString:
/// - pageSize:
/// - config:
/// - fragmentOffsets: fragment
/// - Returns:
func pageRanges(
for attributedString: NSAttributedString,
pageSize: CGSize,
@@ -18,7 +33,15 @@ protocol RDEPUBChapterPageCounting {
) -> [RDEPUBPageBreakDecision]
}
///
protocol RDEPUBPageFrameBuilding {
///
/// - Parameters:
/// - attributedString:
/// - pageSize:
/// - config:
/// - fragmentOffsets: fragment
/// - Returns:
func makeFrames(
attributedString: NSAttributedString,
pageSize: CGSize,
@@ -1,3 +1,6 @@
// RDEPUBTextPositionConverter.swift
// EPUB
import Foundation
/// WXRead `WREpubPositionConverter`
@@ -8,44 +11,74 @@ import Foundation
/// -
/// - / `RDEPUBLocation`
public struct RDEPUBTextPositionConverter {
/// EPUB
public let book: RDEPUBTextBook
/// EPUB
/// - Parameter book: EPUB
public init(book: RDEPUBTextBook) {
self.book = book
}
///
public var totalCharacterCount: Int {
book.indexTable.totalCharacterCount
}
///
/// - Parameter anchor:
/// - Returns:
public func globalIndex(for anchor: RDEPUBTextAnchor) -> Int {
book.indexTable.globalIndex(for: anchor)
}
///
/// - Parameter rangeAnchor:
/// - Returns: `NSRange`
public func globalRange(for rangeAnchor: RDEPUBTextRangeAnchor) -> NSRange {
book.indexTable.globalRange(for: rangeAnchor)
}
///
/// - Parameter index:
/// - Returns: `nil`
public func fileIndex(forCharacterPosition index: Int) -> Int? {
book.indexTable.fileIndex(forCharacterPosition: index)
}
///
/// - Parameters:
/// - fileIndex:
/// - index:
/// - Returns: `nil`
public func localOffsetInFile(at fileIndex: Int, forGlobalPosition index: Int) -> Int? {
book.indexTable.localOffsetInFile(at: fileIndex, forGlobalPosition: index)
}
///
/// - Parameter index:
/// - Returns: `nil`
public func anchor(forCharacterPosition index: Int) -> RDEPUBTextAnchor? {
book.indexTable.anchor(forGlobalIndex: index)
}
/// `RDEPUBLocation`
/// - Parameter location: EPUB
/// - Returns: `nil`
public func anchor(for location: RDEPUBLocation) -> RDEPUBTextAnchor? {
book.indexTable.anchor(for: location)
}
/// 1
/// - Parameter anchor:
/// - Returns: `nil`
public func pageNumber(for anchor: RDEPUBTextAnchor) -> Int? {
book.indexTable.pageNumber(for: anchor, in: book).map { $0 + 1 }
}
/// 1
/// - Parameter index:
/// - Returns: `nil`
public func pageNumber(forCharacterPosition index: Int) -> Int? {
guard let anchor = anchor(forCharacterPosition: index) else {
return nil
@@ -53,6 +86,11 @@ public struct RDEPUBTextPositionConverter {
return pageNumber(for: anchor)
}
/// `RDEPUBLocation`
/// - Parameters:
/// - anchor:
/// - bookIdentifier: location `bookId`
/// - Returns: `RDEPUBLocation` `nil`
public func location(
for anchor: RDEPUBTextAnchor,
bookIdentifier: String?
@@ -63,6 +101,11 @@ public struct RDEPUBTextPositionConverter {
return book.indexTable.location(for: anchor, in: chapter, bookIdentifier: bookIdentifier)
}
/// `RDEPUBLocation`
/// - Parameters:
/// - rangeAnchor:
/// - bookIdentifier: location `bookId`
/// - Returns: `RDEPUBLocation` `nil`
public func location(
for rangeAnchor: RDEPUBTextRangeAnchor,
bookIdentifier: String?
@@ -4,6 +4,7 @@ import UIKit
import DTCoreText
#endif
///
struct RDEPUBAttachmentNormalizer {
///
private static var didLogFootnoteAttachment = false
@@ -1,6 +1,7 @@
import UIKit
import CoreText
/// EPUB
struct RDEPUBFontNormalizer {
/// CTFontManager
private static var registeredFontPaths = Set<String>()
@@ -52,6 +53,8 @@ struct RDEPUBFontNormalizer {
}
}
/// CTFontManager
/// - Parameter fileURL: URL
static func registerFontIfNeeded(at fileURL: URL) {
let standardizedPath = fileURL.standardizedFileURL.path
guard !registeredFontPaths.contains(standardizedPath) else { return }
@@ -1,10 +1,18 @@
/// RDEPUBFragmentMarkerInjector - Fragment
import Foundation
/// Fragment HTML fragment
///
///
/// 1. `process` HTML `id` `${id=xxx}`
/// 2. `extractOffsets` NSAttributedString
struct RDEPUBFragmentMarkerInjector: RDEPUBTypesettingStage {
/// HTML id fragment 使
func process(_ html: String, context: RDEPUBTypesettingInput) -> String {
Self.injectFragmentMarkers(into: html)
}
/// `${id=xxx}` fragment ID
func extractOffsets(from attributedString: NSMutableAttributedString) -> [String: Int] {
Self.extractFragmentOffsets(from: attributedString)
}
@@ -1,6 +1,12 @@
import Foundation
/// HTML HTML
struct RDEPUBHTMLNormalizer: RDEPUBTypesettingStage {
/// HTML
/// - Parameters:
/// - html: HTML
/// - context:
/// - Returns: HTML
func process(_ html: String, context: RDEPUBTypesettingInput) -> String {
Self.normalizeHTML(html)
}
@@ -1,11 +1,17 @@
import Foundation
/// HTML
struct RDEPUBRenderDiagnosticsCollector {
///
private static let stylesheetLinkPattern = #"<link\b[^>]*rel\s*=\s*["'][^"']*stylesheet[^"']*["'][^>]*href\s*=\s*["']([^"']+)["'][^>]*>"#
/// 图片源地址正则
private static let imageSourcePattern = #"<img\b[^>]*src\s*=\s*["']([^"']+)["'][^>]*>"#
/// HTML
/// - Parameters:
/// - html: HTML
/// - input:
/// - Returns:
func collect(
in html: String,
input: RDEPUBTypesettingInput
@@ -1,14 +1,22 @@
/// RDEPUBSemanticMarkerInjector -
import Foundation
import UIKit
/// HTML
///
///
/// 1. HTML `process` `${rd-sem-start/end}`
/// 2. `apply` NSAttributedString
struct RDEPUBSemanticMarkerInjector: RDEPUBTypesettingStage {
/// ${rd-sem-start:...} / ${rd-sem-end:...}
private static let semanticMarkerPattern = #"\$\{rd-sem-(start|end):([^}]+)\}"#
/// HTML `${rd-sem-start/end}`
func process(_ html: String, context: RDEPUBTypesettingInput) -> String {
Self.injectPaginationSemanticMarkers(into: html)
}
/// NSAttributedString
func apply(to attributedString: NSMutableAttributedString) {
Self.applyPaginationSemantics(in: attributedString)
}
@@ -323,6 +331,7 @@ struct RDEPUBSemanticMarkerInjector: RDEPUBTypesettingStage {
// MARK: -
/// HTML
struct RDPaginationSemantics {
var id: String
var blockKind: RDEPUBTextBlockKind?
@@ -1,13 +1,24 @@
import UIKit
/// HTMLCSS
struct RDEPUBStyleSheetComposition {
/// HTML
var html: String
/// CSS default/replace/dark/epub/user
var layers: [RDEPUBTextStyleSheetLayer]
/// CSS
var inlinedCSS: String
///
var diagnostics: [RDEPUBTextResourceReferenceDiagnostic]
}
/// EPUB CSS HTML
struct RDEPUBStyleSheetComposer {
/// CSS HTML
/// - Parameters:
/// - html: HTML
/// - input:
/// - Returns: HTMLCSS
func compose(html: String, input: RDEPUBTypesettingInput) -> RDEPUBStyleSheetComposition {
let stylesheetHrefReplacements = RDEPUBRenderDiagnosticsCollector.inlineLinkedStyleSheets(
in: html,
@@ -84,8 +95,11 @@ struct RDEPUBStyleSheetComposer {
// MARK: - Style
/// `<style>`
enum StyleInjectionPosition {
/// `<head>`
case headStart
/// `</head>`
case headEnd
}
@@ -1,27 +1,50 @@
import UIKit
/// HTML
struct RDEPUBTypesettingInput {
///
var href: String
///
var title: String
/// HTML
var rawHTML: String
/// HTML URL
var baseURL: URL?
///
var style: RDEPUBTextRenderStyle
///
var resourceResolver: RDEPUBResourceResolver?
/// zh-CN
var contentLanguageCode: String?
///
var pageSize: CGSize?
///
var layoutConfig: RDEPUBTextLayoutConfig?
}
///
struct RDEPUBTypesettingOutput {
///
var request: RDEPUBTextChapterRenderRequest
///
var diagnostics: [RDEPUBTextResourceReferenceDiagnostic]
}
/// HTML 线
protocol RDEPUBTypesettingStage {
/// HTML
/// - Parameters:
/// - html: HTML
/// - context:
/// - Returns: HTML
func process(_ html: String, context: RDEPUBTypesettingInput) -> String
}
/// 线 HTML
struct RDEPUBTextTypesetterPipeline {
///
/// - Parameter input:
/// - Returns:
func makeRequest(from input: RDEPUBTypesettingInput) -> RDEPUBTypesettingOutput {
let htmlNormalizer = RDEPUBHTMLNormalizer()
let semanticMarkerInjector = RDEPUBSemanticMarkerInjector()