From ea21c6a831c31b6f47761e3a4bc5f821c24a8005 Mon Sep 17 00:00:00 2001 From: shen <> Date: Tue, 26 May 2026 23:27:52 +0800 Subject: [PATCH] =?UTF-8?q?epub=E9=97=AE=E9=A2=98=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../UserInterfaceState.xcuserstate | Bin 75854 -> 102806 bytes .../RDEPUBTextBookBuilder.swift | 65 ++++- .../RDEPUBTextBookCache.swift | 3 +- .../RDEPUBTextLayouter.swift | 274 ++++++++++++------ .../RDEPUBPageInteractionController.swift | 32 +- .../EPUBUI/RDEPUBPageLayoutSnapshot.swift | 5 +- .../EPUBUI/RDEPUBReaderController.swift | 3 + .../EPUBUI/RDEPUBTextContentView.swift | 19 +- 8 files changed, 257 insertions(+), 144 deletions(-) diff --git a/ReadViewDemo/ReadViewDemo.xcworkspace/xcuserdata/shen.xcuserdatad/UserInterfaceState.xcuserstate b/ReadViewDemo/ReadViewDemo.xcworkspace/xcuserdata/shen.xcuserdatad/UserInterfaceState.xcuserstate index add3653dc4ad4fc17ffe38d1e72f9da53fb5574a..904f89cf38b27f85dabfb257ef78eaf7b8e68ad4 100644 GIT binary patch literal 102806 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 M`TzbC(y#Xa0KpF literal 75854 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 DlXFct diff --git a/Sources/RDReaderView/EPUBTextRendering/RDEPUBTextBookBuilder.swift b/Sources/RDReaderView/EPUBTextRendering/RDEPUBTextBookBuilder.swift index f0f7090..e22c841 100644 --- a/Sources/RDReaderView/EPUBTextRendering/RDEPUBTextBookBuilder.swift +++ b/Sources/RDReaderView/EPUBTextRendering/RDEPUBTextBookBuilder.swift @@ -223,6 +223,10 @@ public final class RDEPUBTextBookBuilder { self.init(renderer: RDEPUBDTCoreTextRenderer()) } + private var isPaginationDebugEnabled: Bool { + ProcessInfo.processInfo.arguments.contains("--demo-pagination-debug") + } + /// 生成最近一次构建的语义摘要,用于 Phase 7 质量检测日志 public func phase7SemanticSummary(title: String? = nil) -> String? { guard !lastBuildPaginationDiagnostics.isEmpty else { return nil } @@ -263,6 +267,9 @@ public final class RDEPUBTextBookBuilder { pageSize: CGSize, style: RDEPUBTextRenderStyle ) throws -> RDEPUBTextBook { + if isPaginationDebugEnabled { + print("[PaginationDebug] build pageSize=\(NSCoder.string(for: pageSize)) layoutInsets=\(NSCoder.string(for: layoutConfig.edgeInsets))") + } var chapters: [RDEPUBTextChapter] = [] var flatPages: [RDEPUBTextPage] = [] lastBuildResourceDiagnostics = [] @@ -437,6 +444,18 @@ public final class RDEPUBTextBookBuilder { ) } + if isPaginationDebugEnabled, + item.href.contains("Chapter_3.xhtml") { + print("[PaginationDebug] href=\(item.href) pages=\(pages.count)") + for page in pages { + let preview = debugPreview(for: page.content, limit: 36) + print("[PaginationDebug] absPage=\(page.absolutePageIndex + 1) localPage=\(page.pageIndexInChapter + 1) range=\(NSStringFromRange(page.contentRange)) break=\(page.metadata.breakReason.rawValue) preview=\(preview)") + for note in page.metadata.diagnostics.prefix(4) { + print("[PaginationDebug] note=\(note)") + } + } + } + chapters.append( RDEPUBTextChapter( chapterIndex: chapterIndex, @@ -575,11 +594,26 @@ public final class RDEPUBTextBookBuilder { return attachmentCount(in: content) > 0 && trimmed.count <= 1 } + private func debugPreview(for content: NSAttributedString, limit: Int) -> String { + let collapsed = content.string + .replacingOccurrences(of: "\n", with: " ") + .replacingOccurrences(of: "\r", with: " ") + .replacingOccurrences(of: "\t", with: " ") + .trimmingCharacters(in: .whitespacesAndNewlines) + guard !collapsed.isEmpty else { return "" } + if collapsed.count <= limit { + return collapsed + } + let head = collapsed.prefix(limit) + return "\(head)…" + } + // MARK: - 尾页规范化 - /// 规范化分页结果的尾部页面: - /// 1. 丢弃纯空白的尾页 - /// 2. 将过短的尾页(≤2 字符)合并到前一页 + /// 规范化分页结果: + /// 1. 移除章节中间误产生的纯空白页 + /// 2. 丢弃纯空白的尾页 + /// 3. 将过短的尾页(≤2 字符)合并到前一页 private func normalizeTrailingFrames( _ frames: [RDEPUBTextLayoutFrame], content: NSAttributedString, @@ -589,9 +623,28 @@ public final class RDEPUBTextBookBuilder { var normalized = frames + // 先移除章节中间的纯空白页。这类页通常只包含换行/占位空白, + // 会把相邻正文页硬生生拆开,直接表现为“上一页底部空很多”。 + var compacted: [RDEPUBTextLayoutFrame] = [] + compacted.reserveCapacity(normalized.count) + for frame in normalized { + if shouldDropWhitespaceOnlyFrame(frame, in: content) { + let note = "normalized: dropped whitespace-only intermediate page \(NSStringFromRange(frame.contentRange))" + if var previous = compacted.popLast() { + previous.diagnostics.append(note) + compacted.append(previous) + } else { + print("[EPUB][Pagination] href=\(href) dropped leading/intermediate whitespace frame \(NSStringFromRange(frame.contentRange))") + } + continue + } + compacted.append(frame) + } + normalized = compacted + // 丢弃纯空白的尾页 while let lastFrame = normalized.last, - shouldDropWhitespaceOnlyTrailingFrame(lastFrame, in: content) { + shouldDropWhitespaceOnlyFrame(lastFrame, in: content) { normalized.removeLast() let note = "normalized: dropped whitespace-only trailing page \(NSStringFromRange(lastFrame.contentRange))" if var previousFrame = normalized.popLast() { @@ -617,7 +670,7 @@ public final class RDEPUBTextBookBuilder { } /// 判断尾页是否为纯空白(无可显示字符且无附件) - private func shouldDropWhitespaceOnlyTrailingFrame( + private func shouldDropWhitespaceOnlyFrame( _ frame: RDEPUBTextLayoutFrame, in content: NSAttributedString ) -> Bool { @@ -737,7 +790,7 @@ public final class RDEPUBTextBookBuilder { bookID: bookID, fontSize: style.font.pointSize, lineHeightMultiple: style.lineSpacing, - contentInsets: .zero, + contentInsets: layoutConfig.edgeInsets, pageSize: pageSize, layoutConfigSignature: layoutConfig.cacheSignature ) diff --git a/Sources/RDReaderView/EPUBTextRendering/RDEPUBTextBookCache.swift b/Sources/RDReaderView/EPUBTextRendering/RDEPUBTextBookCache.swift index 3c9d021..2322f11 100644 --- a/Sources/RDReaderView/EPUBTextRendering/RDEPUBTextBookCache.swift +++ b/Sources/RDReaderView/EPUBTextRendering/RDEPUBTextBookCache.swift @@ -123,7 +123,8 @@ final class ChapterPaginationArchive: NSObject, NSSecureCoding { public final class RDEPUBTextBookCache { /// 缓存模式版本号,变更时旧缓存自动失效 - public var schemaVersion: Int = 4 + // 分页算法调整后需要提升版本,避免继续复用旧页范围缓存。 + public var schemaVersion: Int = 6 /// 串行队列,保证缓存读写的线程安全 private let queue = DispatchQueue(label: "com.rdreader.textbookcache", qos: .utility) diff --git a/Sources/RDReaderView/EPUBTextRendering/RDEPUBTextLayouter.swift b/Sources/RDReaderView/EPUBTextRendering/RDEPUBTextLayouter.swift index 1930713..177a501 100644 --- a/Sources/RDReaderView/EPUBTextRendering/RDEPUBTextLayouter.swift +++ b/Sources/RDReaderView/EPUBTextRendering/RDEPUBTextLayouter.swift @@ -67,23 +67,42 @@ struct RDEPUBTextLayouter { var frames: [RDEPUBTextLayoutFrame] = [] var location = 0 + let resolvedSize = config.resolvedFrameSize(fallback: pageSize) + let usableWidth = resolvedSize.width - config.edgeInsets.left - config.edgeInsets.right + let usableHeight = resolvedSize.height - config.edgeInsets.top - config.edgeInsets.bottom + + guard usableWidth > 0, usableHeight > 0 else { + return [] + } while location < attributedString.length { - let frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(location, 0), path, nil) - let visibleRange = CTFrameGetVisibleStringRange(frame) - guard visibleRange.length > 0 else { + let framePath = CGMutablePath() + // 对齐 WXRead WRChapterPageCount: + // CoreText 分页路径使用 bottom inset 作为 y 原点,而不是 UIKit 语义的 top inset。 + let pageRect = CGRect( + x: config.edgeInsets.left, + y: config.edgeInsets.bottom, + width: usableWidth, + height: usableHeight + ) + framePath.addRect(pageRect) + let frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(location, 0), framePath, nil) + let proposedRange = proposedRangeUsingWXReadPageCount( + from: frame, + start: location, + usableHeight: usableHeight, + totalLength: attributedString.length + ) + guard proposedRange.length > 0 else { break } - let proposedRange = NSRange(location: location, length: visibleRange.length) - // 行级 avoidPageBreakInside 处理(WXRead 方案:从最后一行向前扫描) let avoidAdjusted = trimmedRangeForAvoidPageBreakInside(from: frame, proposed: proposedRange) - let lineAdjusted = trimmedRangeForKeepWithNext(from: frame, proposed: avoidAdjusted) let lineRanges = lineRanges(from: frame) let adjusted = adjustedRange( - from: lineAdjusted, + from: avoidAdjusted, totalLength: attributedString.length, lineRanges: lineRanges ) @@ -108,7 +127,7 @@ struct RDEPUBTextLayouter { let nextLocation = adjusted.range.location + adjusted.range.length guard nextLocation > location else { - location += max(visibleRange.length, 1) + location += max(proposedRange.length, 1) continue } location = nextLocation @@ -155,7 +174,12 @@ struct RDEPUBTextLayouter { totalLength: attributedString.length, lineRanges: lineRanges ) - let verifiedRange = verifiedDisplayRange(for: adjusted.range) + let verifiedRange: NSRange + if adjusted.breakReason == .attachmentBoundary { + verifiedRange = verifiedDisplayRange(for: adjusted.range) + } else { + verifiedRange = adjusted.range + } let trailingFragmentID = nearestTrailingFragmentID( endingAt: verifiedRange.location + verifiedRange.length, fragmentOffsets: fragmentOffsets @@ -191,27 +215,28 @@ struct RDEPUBTextLayouter { } private func verifiedDisplayRange(for range: NSRange) -> NSRange { - guard range.length > 0, - !attachmentRanges(in: range).isEmpty else { + guard let clampedRange = clampedRange(range), + clampedRange.length > 0, + !attachmentRanges(in: clampedRange).isEmpty else { return range } - let pageContent = attributedString.attributedSubstring(from: range) + let pageContent = attributedString.attributedSubstring(from: clampedRange) guard let layouter = DTCoreTextLayouter(attributedString: pageContent) else { - return range + return clampedRange } layouter.shouldCacheLayoutFrames = false guard let layoutFrame = layouter.layoutFrame(with: dtLayoutRect, range: NSRange(location: 0, length: 0)) else { - return range + return clampedRange } let visibleRange = layoutFrame.visibleStringRange() - guard visibleRange.length > 0, visibleRange.length < range.length else { - return range + guard visibleRange.length > 0, visibleRange.length < clampedRange.length else { + return clampedRange } - return NSRange(location: range.location, length: visibleRange.length) + return NSRange(location: clampedRange.location, length: visibleRange.length) } #endif @@ -281,10 +306,6 @@ struct RDEPUBTextLayouter { ) } - // 最小分页长度:原始范围的 55% - let minLength = max(Int(Double(proposedRange.length) * 0.55), 1) - let minimumEnd = proposedRange.location + minLength - let currentBlockRange = blockRange(at: max(proposedRange.location, pageEnd - 1)) let currentAttachmentRanges = attachmentRanges(in: proposedRange) let currentAttachmentKinds = attachmentKinds(in: proposedRange) @@ -292,38 +313,12 @@ struct RDEPUBTextLayouter { let currentSemanticHints = proposedSemanticHints let currentAttachmentPlacements = proposedAttachmentPlacements - // 1. 语义边界(pageBreakBefore/After) - if let semanticBoundary = preferredSemanticBoundary( - in: proposedRange, - minimumEnd: minimumEnd - ) { - let adjustedRange = NSRange(location: proposedRange.location, length: semanticBoundary.location - proposedRange.location) - return ( - range: adjustedRange, - breakReason: .semanticBoundary, - blockRange: currentBlockRange, - attachmentRanges: currentAttachmentRanges, - attachmentKinds: currentAttachmentKinds, - blockKinds: currentBlockKinds, - semanticHints: currentSemanticHints, - attachmentPlacements: currentAttachmentPlacements, - diagnostics: diagnostics( - reason: .semanticBoundary, - range: adjustedRange, - attachmentRanges: currentAttachmentRanges, - blockRange: currentBlockRange, - blockKinds: currentBlockKinds, - semanticHints: currentSemanticHints, - attachmentPlacements: currentAttachmentPlacements, - trigger: semanticBoundary.trigger - ) - ) - } - - // 2. pageRelate 跨页关联边界 + // 对齐 WXRead:默认按 CTFrame 已经容纳的行数分页,仅保留 pageRelate 这种 + // 微信读书特有的跨页关联规则;其他 keepWithNext/attachmentBoundary/通用语义边界 + // 先不参与截断,避免提前裁短页尾内容。 if let pageRelateBoundary = preferredPageRelateBoundary( after: proposedRange, - minimumEnd: minimumEnd, + minimumEnd: proposedRange.location + 1, lineRanges: lineRanges ) { let adjustedRange = NSRange(location: proposedRange.location, length: pageRelateBoundary - proposedRange.location) @@ -349,33 +344,6 @@ struct RDEPUBTextLayouter { ) } - // 3. 附件边界(块级附件整体移动) - if let attachmentBoundary = preferredAttachmentBoundary( - in: proposedRange, - minimumEnd: minimumEnd - ) { - let adjustedRange = NSRange(location: proposedRange.location, length: attachmentBoundary - proposedRange.location) - return ( - range: adjustedRange, - breakReason: .attachmentBoundary, - blockRange: currentBlockRange, - attachmentRanges: currentAttachmentRanges, - attachmentKinds: currentAttachmentKinds, - blockKinds: currentBlockKinds, - semanticHints: currentSemanticHints, - attachmentPlacements: currentAttachmentPlacements, - diagnostics: diagnostics( - reason: .attachmentBoundary, - range: adjustedRange, - attachmentRanges: currentAttachmentRanges, - blockRange: currentBlockRange, - blockKinds: currentBlockKinds, - semanticHints: currentSemanticHints, - attachmentPlacements: currentAttachmentPlacements - ) - ) - } - // 4. 帧限制(默认分页) return ( range: proposedRange, @@ -407,8 +375,11 @@ struct RDEPUBTextLayouter { in range: NSRange, minimumEnd: Int ) -> (location: Int, trigger: String)? { + guard let safeRange = clampedRange(range), safeRange.length > 0 else { + return nil + } var boundary: (location: Int, trigger: String)? - attributedString.enumerateAttribute(.rdPageSemanticHints, in: range) { value, attributeRange, stop in + attributedString.enumerateAttribute(.rdPageSemanticHints, in: safeRange) { value, attributeRange, stop in guard let rawValue = value as? String else { return } let hints = rawValue .split(separator: ",") @@ -416,7 +387,7 @@ struct RDEPUBTextLayouter { guard !hints.isEmpty else { return } if hints.contains(.pageBreakBefore), - attributeRange.location > range.location, + attributeRange.location > safeRange.location, attributeRange.location >= minimumEnd { boundary = (attributeRange.location, RDEPUBTextSemanticHint.pageBreakBefore.rawValue) stop.pointee = true @@ -426,7 +397,7 @@ struct RDEPUBTextLayouter { let attributeEnd = attributeRange.location + attributeRange.length if hints.contains(.pageBreakAfter), attributeEnd > minimumEnd, - attributeEnd < range.location + range.length { + attributeEnd < safeRange.location + safeRange.length { boundary = (attributeEnd, RDEPUBTextSemanticHint.pageBreakAfter.rawValue) stop.pointee = true return @@ -438,8 +409,11 @@ struct RDEPUBTextLayouter { /// 查找附件边界:只有块级附件(.attachment 或 .centered)才触发分页, /// 行内脚注图标等不应导致整段移动。 private func preferredAttachmentBoundary(in range: NSRange, minimumEnd: Int) -> Int? { + guard let safeRange = clampedRange(range), safeRange.length > 0 else { + return nil + } var boundary: Int? - attributedString.enumerateAttribute(.rdPageAttachmentKind, in: range) { value, attributeRange, stop in + attributedString.enumerateAttribute(.rdPageAttachmentKind, in: safeRange) { value, attributeRange, stop in guard value != nil else { return } let location = attributeRange.location @@ -448,11 +422,21 @@ struct RDEPUBTextLayouter { // 对标 WXRead:只有块级附件才应将整个块推到下一页。 // 行内脚注图标等行内附件不应导致整段移动。 - let isBlockLevelAttachment = blockKind == .attachment || placement == .centered + // 只有真正的块级附件才需要整块挪页。 + // 行内/基线对齐的附件(例如脚注 note.png)不能触发附件边界分页。 + let isBlockLevelAttachment: Bool + switch placement { + case .centered: + isBlockLevelAttachment = true + case .inline, .baseline: + isBlockLevelAttachment = false + case nil: + isBlockLevelAttachment = blockKind == .attachment + } guard isBlockLevelAttachment else { return } let boundaryRange = blockRange(at: location) ?? paragraphRange(containing: location) - if boundaryRange.location > range.location, boundaryRange.location >= minimumEnd { + if boundaryRange.location > safeRange.location, boundaryRange.location >= minimumEnd { boundary = boundaryRange.location stop.pointee = true } @@ -523,8 +507,11 @@ struct RDEPUBTextLayouter { /// 获取指定范围内的所有附件字符范围 private func attachmentRanges(in range: NSRange) -> [NSRange] { + guard let safeRange = clampedRange(range), safeRange.length > 0 else { + return [] + } var results: [NSRange] = [] - attributedString.enumerateAttribute(.rdPageAttachmentKind, in: range) { value, attributeRange, _ in + attributedString.enumerateAttribute(.rdPageAttachmentKind, in: safeRange) { value, attributeRange, _ in guard value != nil else { return } results.append(attributeRange) } @@ -543,8 +530,11 @@ struct RDEPUBTextLayouter { /// 获取指定范围内的附件类型列表(去重) private func attachmentKinds(in range: NSRange) -> [RDEPUBTextAttachmentKind] { + guard let safeRange = clampedRange(range), safeRange.length > 0 else { + return [] + } var kinds: [RDEPUBTextAttachmentKind] = [] - attributedString.enumerateAttribute(.rdPageAttachmentKind, in: range) { value, _, _ in + attributedString.enumerateAttribute(.rdPageAttachmentKind, in: safeRange) { value, _, _ in guard let rawValue = value as? String, let kind = RDEPUBTextAttachmentKind(rawValue: rawValue), !kinds.contains(kind) else { @@ -557,8 +547,11 @@ struct RDEPUBTextLayouter { /// 获取指定范围内的块级元素类型列表(去重) private func blockKinds(in range: NSRange) -> [RDEPUBTextBlockKind] { + guard let safeRange = clampedRange(range), safeRange.length > 0 else { + return [] + } var kinds: [RDEPUBTextBlockKind] = [] - attributedString.enumerateAttribute(.rdPageBlockKind, in: range) { value, _, _ in + attributedString.enumerateAttribute(.rdPageBlockKind, in: safeRange) { value, _, _ in guard let rawValue = value as? String, let kind = RDEPUBTextBlockKind(rawValue: rawValue), !kinds.contains(kind) else { @@ -571,8 +564,11 @@ struct RDEPUBTextLayouter { /// 获取指定范围内的语义提示列表(去重) private func semanticHints(in range: NSRange) -> [RDEPUBTextSemanticHint] { + guard let safeRange = clampedRange(range), safeRange.length > 0 else { + return [] + } var hints: [RDEPUBTextSemanticHint] = [] - attributedString.enumerateAttribute(.rdPageSemanticHints, in: range) { value, _, _ in + attributedString.enumerateAttribute(.rdPageSemanticHints, in: safeRange) { value, _, _ in guard let rawValue = value as? String else { return } for hint in rawValue.split(separator: ",").compactMap({ RDEPUBTextSemanticHint(rawValue: String($0)) }) where !hints.contains(hint) { hints.append(hint) @@ -583,8 +579,11 @@ struct RDEPUBTextLayouter { /// 获取指定范围内的附件布局方式列表(去重) private func attachmentPlacements(in range: NSRange) -> [RDEPUBTextAttachmentPlacement] { + guard let safeRange = clampedRange(range), safeRange.length > 0 else { + return [] + } var placements: [RDEPUBTextAttachmentPlacement] = [] - attributedString.enumerateAttribute(.rdPageAttachmentPlacement, in: range) { value, _, _ in + attributedString.enumerateAttribute(.rdPageAttachmentPlacement, in: safeRange) { value, _, _ in guard let rawValue = value as? String, let placement = RDEPUBTextAttachmentPlacement(rawValue: rawValue), !placements.contains(placement) else { @@ -595,6 +594,22 @@ struct RDEPUBTextLayouter { return placements } + /// 将范围裁剪到 attributedString 的合法边界内,避免属性枚举与子串提取越界。 + private func clampedRange(_ range: NSRange) -> NSRange? { + guard range.location >= 0, range.length >= 0 else { return nil } + guard attributedString.length > 0 else { + return range.location == 0 ? NSRange(location: 0, length: 0) : nil + } + guard range.location < attributedString.length else { return nil } + + let maxLength = attributedString.length - range.location + return NSRange(location: range.location, length: min(range.length, maxLength)) + } + + private func clampedProbeRange(for lineRange: NSRange) -> NSRange? { + clampedRange(NSRange(location: lineRange.location, length: max(lineRange.length, 1))) + } + /// 查找指定位置之前最近的 fragment ID(用于阅读位置恢复) private func nearestTrailingFragmentID( endingAt location: Int, @@ -770,10 +785,15 @@ struct RDEPUBTextLayouter { /// 检查某行是否落在 avoidPageBreakInside 保护块内 private func lineIsInAvoidPageBreakInsideBlock(_ lineRange: NSRange) -> Bool { + guard let probeRange = clampedProbeRange(for: lineRange) else { + return false + } var found = false - let probeRange = NSRange(location: lineRange.location, length: max(lineRange.length, 1)) - attributedString.enumerateAttribute(.rdPageSemanticHints, in: probeRange) { value, _, stop in - guard let rawValue = value as? String else { return } + attributedString.enumerateAttributes(in: probeRange) { attributes, _, stop in + guard shouldTreatAvoidHintAsBlockProtection(attributes) else { + return + } + guard let rawValue = attributes[.rdPageSemanticHints] as? String else { return } let hints = rawValue .split(separator: ",") .compactMap { RDEPUBTextSemanticHint(rawValue: String($0)) } @@ -785,10 +805,37 @@ struct RDEPUBTextLayouter { return found } + /// 只有真正的块级内容才应触发 avoidPageBreakInside。 + /// 像脚注 note.png 这类行内图片会被标记为 `img`,但不该把整行推到下一页。 + private func shouldTreatAvoidHintAsBlockProtection(_ attributes: [NSAttributedString.Key: Any]) -> Bool { + guard let rawValue = attributes[.rdPageSemanticHints] as? String else { + return false + } + let hints = rawValue + .split(separator: ",") + .compactMap { RDEPUBTextSemanticHint(rawValue: String($0)) } + guard hints.contains(.avoidPageBreakInside) else { + return false + } + + let placement = (attributes[.rdPageAttachmentPlacement] as? String) + .flatMap(RDEPUBTextAttachmentPlacement.init(rawValue:)) + let blockKind = (attributes[.rdPageBlockKind] as? String) + .flatMap(RDEPUBTextBlockKind.init(rawValue:)) + + if blockKind == .attachment, placement != .centered { + return false + } + + return true + } + /// 检查某行是否落在 keepWithNext 保护块内 private func lineIsInKeepWithNextBlock(_ lineRange: NSRange) -> Bool { + guard let probeRange = clampedProbeRange(for: lineRange) else { + return false + } var found = false - let probeRange = NSRange(location: lineRange.location, length: max(lineRange.length, 1)) attributedString.enumerateAttribute(.rdPageSemanticHints, in: probeRange) { value, _, stop in guard let rawValue = value as? String else { return } let hints = rawValue @@ -811,6 +858,47 @@ struct RDEPUBTextLayouter { } } + /// 逐句对齐 WXRead `WRChapterPageCount.recalculatePageRangesForAttributedString` 的分页循环: + /// 1. 取出 CTFrame 当前页的所有行 + /// 2. 读取每行 origin + /// 3. 用 `lineY - ascent > usableHeight` 判断是否越过可用高度 + /// 4. 累计能容纳行的字符数得到本页范围 + private func proposedRangeUsingWXReadPageCount( + from frame: CTFrame, + start location: Int, + usableHeight: CGFloat, + totalLength: Int + ) -> NSRange { + let lines = CTFrameGetLines(frame) as! [CTLine] + guard !lines.isEmpty else { + return NSRange(location: location, length: 0) + } + + var origins = [CGPoint](repeating: .zero, count: lines.count) + CTFrameGetLineOrigins(frame, CFRangeMake(0, 0), &origins) + + var pageCharCount = 0 + for (index, line) in lines.enumerated() { + let lineRange = CTLineGetStringRange(line) + let lineY = origins[index].y + var ascent: CGFloat = 0 + var descent: CGFloat = 0 + CTLineGetTypographicBounds(line, &ascent, &descent, nil) + + if lineY - ascent > usableHeight { + break + } + + pageCharCount += lineRange.length + } + + if pageCharCount == 0 { + pageCharCount = 1 + } + + return NSRange(location: location, length: min(pageCharCount, totalLength - location)) + } + #if canImport(DTCoreText) /// 获取 DTCoreTextLayoutFrame 中所有行的字符范围 private func lineRanges(from layoutFrame: DTCoreTextLayoutFrame) -> [NSRange] { diff --git a/Sources/RDReaderView/EPUBUI/RDEPUBPageInteractionController.swift b/Sources/RDReaderView/EPUBUI/RDEPUBPageInteractionController.swift index eef42e3..c02cb42 100644 --- a/Sources/RDReaderView/EPUBUI/RDEPUBPageInteractionController.swift +++ b/Sources/RDReaderView/EPUBUI/RDEPUBPageInteractionController.swift @@ -13,18 +13,12 @@ final class RDEPUBPageInteractionController { var snapshot: RDEPUBPageLayoutSnapshot? private var dtLayoutFrame: DTCoreTextLayoutFrame? - private var contentOffsetBase: Int = 0 #if canImport(DTCoreText) - func configure(layoutFrame: DTCoreTextLayoutFrame?, page: RDEPUBTextPage?, contentOffsetBase: Int = 0) { + func configure(layoutFrame: DTCoreTextLayoutFrame?, page: RDEPUBTextPage?) { dtLayoutFrame = layoutFrame - self.contentOffsetBase = contentOffsetBase if let layoutFrame, let page { - snapshot = RDEPUBPageLayoutSnapshot.build( - from: layoutFrame, - page: page, - contentOffsetBase: contentOffsetBase - ) + snapshot = RDEPUBPageLayoutSnapshot.build(from: layoutFrame, page: page) } else { snapshot = nil } @@ -53,11 +47,7 @@ final class RDEPUBPageInteractionController { ) let idx = dtLine.stringIndex(forPosition: relativePoint) guard idx != NSNotFound, idx >= 0 else { return nil } - return normalizedIndex( - absoluteIndex(for: idx), - lineRange: line.stringRange, - pageRange: snapshot.pageContentRange - ) + return normalizedIndex(idx, lineRange: line.stringRange, pageRange: snapshot.pageContentRange) #else return nil #endif @@ -85,9 +75,9 @@ final class RDEPUBPageInteractionController { #if canImport(DTCoreText) guard let dtLine = dtLineContaining(range: line.stringRange) else { continue } - let startX = dtLine.offset(forStringIndex: localIndex(for: overlap.location)) + let startX = dtLine.offset(forStringIndex: overlap.location) let endIdx = overlap.location + overlap.length - let endX = dtLine.offset(forStringIndex: localIndex(for: endIdx)) + let endX = dtLine.offset(forStringIndex: endIdx) #else let startX: CGFloat = 0 let endX: CGFloat = line.frame.width @@ -145,7 +135,7 @@ final class RDEPUBPageInteractionController { #if canImport(DTCoreText) guard let dtLine = dtLineContaining(range: line.stringRange) else { return nil } - let offsetX = dtLine.offset(forStringIndex: localIndex(for: index)) + let offsetX = dtLine.offset(forStringIndex: index) #else let offsetX: CGFloat = 0 #endif @@ -197,18 +187,10 @@ final class RDEPUBPageInteractionController { #if canImport(DTCoreText) private func dtLineContaining(range: NSRange) -> DTCoreTextLayoutLine? { guard let dtLayoutFrame else { return nil } - return dtLayoutFrame.lineContaining(UInt(max(localIndex(for: range.location), 0))) + return dtLayoutFrame.lineContaining(UInt(range.location)) } #endif - private func localIndex(for absoluteIndex: Int) -> Int { - absoluteIndex - contentOffsetBase - } - - private func absoluteIndex(for localIndex: Int) -> Int { - localIndex + contentOffsetBase - } - private func mergeAdjacentRects(_ rects: [CGRect]) -> [CGRect] { guard rects.count > 1 else { return rects } diff --git a/Sources/RDReaderView/EPUBUI/RDEPUBPageLayoutSnapshot.swift b/Sources/RDReaderView/EPUBUI/RDEPUBPageLayoutSnapshot.swift index 9186c7b..c78808e 100644 --- a/Sources/RDReaderView/EPUBUI/RDEPUBPageLayoutSnapshot.swift +++ b/Sources/RDReaderView/EPUBUI/RDEPUBPageLayoutSnapshot.swift @@ -130,8 +130,7 @@ struct RDEPUBPageLayoutSnapshot { #if canImport(DTCoreText) static func build( from layoutFrame: DTCoreTextLayoutFrame, - page: RDEPUBTextPage, - contentOffsetBase: Int + page: RDEPUBTextPage ) -> RDEPUBPageLayoutSnapshot? { guard let dtLines = layoutFrame.lines as? [DTCoreTextLayoutLine], !dtLines.isEmpty else { return nil @@ -140,7 +139,7 @@ struct RDEPUBPageLayoutSnapshot { var lines: [RDEPUBPageLine] = [] var runs: [RDEPUBPageRun] = [] var attachments: [RDEPUBPageAttachment] = [] - let pageOffset = contentOffsetBase + let pageOffset = page.pageStartOffset for dtLine in dtLines { let lineRange = offset(dtLine.stringRange(), by: pageOffset) diff --git a/Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift b/Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift index cef6047..9c77276 100644 --- a/Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift +++ b/Sources/RDReaderView/EPUBUI/RDEPUBReaderController.swift @@ -1267,6 +1267,9 @@ public final class RDEPUBReaderController: UIViewController { private func currentTextPageSize() -> CGSize { let pageNum = readerView.currentPage >= 0 ? readerView.currentPage : nil let resolvedSize = readerView.resolvedSinglePageSize(pageNum: pageNum) + if ProcessInfo.processInfo.arguments.contains("--demo-pagination-debug") { + print("[PaginationDebug] currentTextPageSize currentPage=\(readerView.currentPage) resolved=\(NSCoder.string(for: resolvedSize)) readerBounds=\(NSCoder.string(for: readerView.bounds)) viewBounds=\(NSCoder.string(for: view.bounds)) safe=\(NSCoder.string(for: view.safeAreaInsets))") + } if resolvedSize.width > 0, resolvedSize.height > 0 { return resolvedSize } diff --git a/Sources/RDReaderView/EPUBUI/RDEPUBTextContentView.swift b/Sources/RDReaderView/EPUBUI/RDEPUBTextContentView.swift index f0ab590..f09a11e 100644 --- a/Sources/RDReaderView/EPUBUI/RDEPUBTextContentView.swift +++ b/Sources/RDReaderView/EPUBUI/RDEPUBTextContentView.swift @@ -114,7 +114,6 @@ final class RDEPUBTextContentView: UIView { private var coreTextDisplayContent: NSAttributedString? private var coreTextDisplayRange: NSRange? - private var coreTextDisplayOffsetBase: Int = 0 #endif private let interactionController = RDEPUBPageInteractionController() @@ -266,10 +265,7 @@ final class RDEPUBTextContentView: UIView { ) #if canImport(DTCoreText) - let usesChapterContextDisplay = shouldUseChapterContextDisplay(for: page) - let displayContent = usesChapterContextDisplay - ? NSMutableAttributedString(attributedString: page.chapterContent) - : normalizedPageContent(from: page) + let displayContent = normalizedPageContent(from: page) let fullRange = NSRange(location: 0, length: displayContent.length) displayContent.addAttribute( .foregroundColor, @@ -279,8 +275,7 @@ final class RDEPUBTextContentView: UIView { coreTextContentView.isHidden = false coreTextContentView.backgroundColor = .clear coreTextDisplayContent = displayContent - coreTextDisplayRange = usesChapterContextDisplay ? page.contentRange : NSRange(location: 0, length: displayContent.length) - coreTextDisplayOffsetBase = usesChapterContextDisplay ? 0 : page.pageStartOffset + coreTextDisplayRange = NSRange(location: 0, length: displayContent.length) textView.isHidden = true textView.isUserInteractionEnabled = false textView.attributedText = nil @@ -688,10 +683,6 @@ final class RDEPUBTextContentView: UIView { return !CharacterSet.newlines.contains(previousScalar) } - private func shouldUseChapterContextDisplay(for page: RDEPUBTextPage) -> Bool { - page.metadata.attachmentRanges.isEmpty - } - #if canImport(DTCoreText) private func updateCoreTextLayoutFrameIfNeeded() { guard !coreTextContentView.isHidden, @@ -712,11 +703,7 @@ final class RDEPUBTextContentView: UIView { layouter.shouldCacheLayoutFrames = false let layoutFrame = layouter.layoutFrame(with: coreTextContentView.bounds, range: displayRange) coreTextContentView.layoutFrame = layoutFrame - interactionController.configure( - layoutFrame: layoutFrame, - page: page, - contentOffsetBase: coreTextDisplayOffsetBase - ) + interactionController.configure(layoutFrame: layoutFrame, page: page) overlayView.updateSnapshot(interactionController.snapshot) backgroundOverlayView.updateSnapshot(interactionController.snapshot) }