feat: EPUB阅读器搜索、注释、CFI模块及大书远距跳转优化

- 实现EPUB阅读器搜索功能及选中注释功能
- 优化CFI模块,修复代码审查发现的11个问题
- 实现大书远距目录跳转与后台补全优化方案
- 优化设置面板与章节运行时联动
- 重构及大量改进优化
This commit is contained in:
shenlei
2026-06-22 20:26:34 +08:00
parent f50495ad91
commit c65c190b71
178 changed files with 11380 additions and 6728 deletions
@@ -4,17 +4,14 @@ import UIKit
import DTCoreText
#endif
// MARK: -
///
/// DTCoreText
///
final class RDEPUBPageInteractionController {
var snapshot: RDEPUBPageLayoutSnapshot?
private var dtLayoutFrame: DTCoreTextLayoutFrame?
#if canImport(DTCoreText)
func configure(layoutFrame: DTCoreTextLayoutFrame?, page: RDEPUBTextPage?) {
dtLayoutFrame = layoutFrame
if let layoutFrame, let page {
@@ -25,9 +22,6 @@ final class RDEPUBPageInteractionController {
}
#endif
// MARK: - Hit Testing
/// WXRead stringIndexForPoint:
func characterIndexForViewPoint(at viewPoint: CGPoint, in view: UIView) -> Int? {
let localPoint = CGPoint(x: viewPoint.x, y: viewPoint.y)
return characterIndex(at: localPoint)
@@ -36,7 +30,6 @@ final class RDEPUBPageInteractionController {
func characterIndex(at point: CGPoint) -> Int? {
guard let snapshot else { return nil }
// Attachment rect priority (6pt inset for easier tapping)
for attachment in snapshot.attachments {
if attachment.frame.insetBy(dx: -6, dy: -6).contains(point) {
return attachment.stringRange.location
@@ -63,8 +56,6 @@ final class RDEPUBPageInteractionController {
#endif
}
// MARK: - Selection Range
func selectionRange(from startPoint: CGPoint, to endPoint: CGPoint) -> NSRange? {
guard let start = characterIndex(at: startPoint),
let end = characterIndex(at: endPoint) else { return nil }
@@ -73,8 +64,6 @@ final class RDEPUBPageInteractionController {
return NSRange(location: lower, length: max(upper - lower, 1))
}
// MARK: - Selection Rects
func selectionRects(for absoluteRange: NSRange) -> [CGRect] {
guard let snapshot else { return [] }
var rects: [CGRect] = []
@@ -136,8 +125,6 @@ final class RDEPUBPageInteractionController {
return CGRect(x: minX, y: minY, width: max(maxX - minX, 2), height: max(maxY - minY, 2))
}
// MARK: - Caret Rect
func caretRect(at index: Int) -> CGRect? {
guard let snapshot else { return nil }
guard let line = snapshot.lines.first(where: { NSLocationInRange(index, $0.stringRange) }) else {
@@ -159,8 +146,6 @@ final class RDEPUBPageInteractionController {
)
}
// MARK: - Private Helpers
private func nearestLine(to point: CGPoint, in lines: [RDEPUBPageLine]) -> RDEPUBPageLine? {
var bestLine: RDEPUBPageLine?
var bestDistance: CGFloat = .greatestFiniteMagnitude
@@ -196,6 +181,7 @@ final class RDEPUBPageInteractionController {
}
#if canImport(DTCoreText)
private func dtLineContaining(range: NSRange) -> DTCoreTextLayoutLine? {
guard let dtLayoutFrame, let snapshot else { return nil }
let localLocation = max(range.location - pageOffset(for: snapshot), 0)