Remove all RDEPUBBackgroundTrace.log and bare print diagnostic calls

Keep only the evaluateFullPageMapTakeover: fullReplace diagnostic log
in RDEPUBPageMapReconciliationCoordinator.swift for future debugging.

Simplified RDEPUBBackgroundTrace to just the log method (removed measure
and debug gating). Removed all [EPUB][...], [ReadViewDemo], and
[EPUB][Pagination] print statements across the project.

Also includes earlier bug fixes:
- Fix stale currentPageNumber in extendPartial commit
- Fix pageCurl rebindVisiblePage during transition
- Fix keepCurrentWindow not removing pending update from queue
- Fix right-aligned text (巫鸿 bug) via avoidPageBreakInside,
  tail merger, and continuation paragraph normalization
- Add text-indent reset for aligned blocks in CSS compatibility layer

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
shenlei 2026-06-25 18:25:22 +08:00
parent 8c5059e72f
commit 15b15d0e11
23 changed files with 95 additions and 492 deletions

View File

@ -199,6 +199,8 @@ public struct RDEPUBBookmark: Codable, Equatable {
public var location: RDEPUBLocation
public var rangeInfo: String?
public var chapterTitle: String?
public var note: String?
@ -209,6 +211,7 @@ public struct RDEPUBBookmark: Codable, Equatable {
id: String = UUID().uuidString,
bookIdentifier: String? = nil,
location: RDEPUBLocation,
rangeInfo: String? = nil,
chapterTitle: String? = nil,
note: String? = nil,
createdAt: Date = Date()
@ -216,6 +219,7 @@ public struct RDEPUBBookmark: Codable, Equatable {
self.id = id
self.bookIdentifier = bookIdentifier
self.location = location
self.rangeInfo = rangeInfo?.nilIfEmpty
self.chapterTitle = chapterTitle?.nilIfEmpty
self.note = note?.nilIfEmpty
self.createdAt = createdAt
@ -288,7 +292,7 @@ public struct RDEPUBAnnotation: Codable, Equatable {
kind: .bookmark,
location: bookmark.location,
text: nil,
rangeInfo: nil,
rangeInfo: bookmark.rangeInfo,
color: nil,
chapterTitle: bookmark.chapterTitle,
note: bookmark.note,
@ -302,6 +306,7 @@ public struct RDEPUBAnnotation: Codable, Equatable {
id: id,
bookIdentifier: bookIdentifier,
location: location,
rangeInfo: rangeInfo,
chapterTitle: chapterTitle,
note: note,
createdAt: createdAt

View File

@ -22,10 +22,6 @@ struct RDEPUBChapterTailNormalizer {
previous.diagnostics.append(note)
compacted.append(previous)
} else {
#if DEBUG
print("[EPUB][Pagination] href=\(href) dropped leading/intermediate whitespace frame \(NSStringFromRange(frame.contentRange))")
#endif
}
continue
}
@ -41,9 +37,6 @@ struct RDEPUBChapterTailNormalizer {
previousFrame.diagnostics.append(note)
normalized.append(previousFrame)
} else {
#if DEBUG
print("[EPUB][Pagination] href=\(href) dropped trailing frame \(NSStringFromRange(lastFrame.contentRange))")
#endif
}
}

View File

@ -187,16 +187,8 @@ public final class RDEPUBTextBookBuilder {
let renderDuration = CFAbsoluteTimeGetCurrent() - renderStart
let plainText = rendered.attributedString.string.trimmingCharacters(in: .whitespacesAndNewlines)
if item.href.lowercased().contains("cover") {
#if DEBUG
print("[EPUB][Cover] rendered href=\(item.href) textLength=\(plainText.count) attrLength=\(rendered.attributedString.length) attachments=\(attachmentCount(in: rendered.attributedString))")
#endif
}
if shouldSkipChapter(item: item, content: rendered.attributedString, text: plainText) {
if item.href.lowercased().contains("cover") {
#if DEBUG
print("[EPUB][Cover] skipped href=\(item.href)")
#endif
}
return nil
}
@ -287,12 +279,6 @@ public final class RDEPUBTextBookBuilder {
]
: normalizedFrames
if item.href.lowercased().contains("cover") {
#if DEBUG
print("[EPUB][Cover] paginated href=\(item.href) pages=\(effectiveFrames.count) firstRange=\(effectiveFrames.first.map { NSStringFromRange($0.contentRange) } ?? "none")")
#endif
}
let chapterAttributedContent = content.copy() as! NSAttributedString
let pages = effectiveFrames.enumerated().map { localPageIndex, frame in
let range = frame.contentRange

View File

@ -51,9 +51,6 @@ struct RDEPUBAttachmentNormalizer {
if !didLogFootnoteAttachment {
didLogFootnoteAttachment = true
#if DEBUG
print("[EPUB][Attachment] footnote original=\(RDEPUBHTMLNormalizer.string(from: originalSize)) display=\(RDEPUBHTMLNormalizer.string(from: attachment.displaySize)) font=\(pointSize)")
#endif
}
return
}
@ -77,9 +74,6 @@ struct RDEPUBAttachmentNormalizer {
if !didLogCoverAttachment {
didLogCoverAttachment = true
#if DEBUG
print("[EPUB][Attachment] cover original=\(RDEPUBHTMLNormalizer.string(from: originalSize)) display=\(RDEPUBHTMLNormalizer.string(from: attachment.displaySize))")
#endif
}
return
}

View File

@ -38,10 +38,6 @@ extension RDEPUBReaderController: RDReaderDataSource, RDReaderPageProvider, RDRe
readerView.currentPage < 0 || readerView.currentPage == pageNum
) && !readerView.isPageCurlTransitioning
if resolvedPage == nil, shouldAllowSynchronousFallback {
RDEPUBBackgroundTrace.log(
"LoadingPage",
"sync fallback requested page=\(pageNum + 1) currentPage=\(readerView.currentPage + 1) totalKnown=\(pageCountOfReaderView(readerView: readerView))"
)
_ = runtime.prepareOnDemandChapter(
forAbsolutePageNumber: pageNum + 1,
allowSynchronousLoad: true
@ -84,10 +80,6 @@ extension RDEPUBReaderController: RDReaderDataSource, RDReaderPageProvider, RDRe
guard let readerView, let contentView else { return }
readerView.updateSelectionPagingSuppression(for: contentView, isSuppressed: isSuppressed)
}
RDEPUBBackgroundTrace.log(
"LoadingPage",
"configureLoading page=\(pageNum + 1) currentPage=\(readerView.currentPage + 1) totalKnown=\(pageCountOfReaderView(readerView: readerView)) hasMap=\(readerContext.bookPageMap != nil)"
)
contentView.configureLoading(
pageNumber: pageNum + 1,
totalPages: pageCountOfReaderView(readerView: readerView),
@ -369,15 +361,7 @@ extension RDEPUBReaderController: RDReaderDataSource, RDReaderPageProvider, RDRe
}
}
let effectivePageNum = readerView.currentPage >= 0 ? readerView.currentPage : pageNum
RDEPUBBackgroundTrace.log(
"PageEvent",
"pageNum callback raw=\(pageNum + 1) effective=\(effectivePageNum + 1) previousCurrent=\(previousCurrentPage + 1) readerCurrent=\(readerView.currentPage + 1) totalPages=\(pageCountOfReaderView(readerView: readerView)) display=\(readerView.currentDisplayType)"
)
if previousCurrentPage != readerView.currentPage, effectivePageNum != pageNum {
RDEPUBBackgroundTrace.log(
"PageEvent",
"pageNum callback aborted dueToCurrentPageMutation raw=\(pageNum + 1) effective=\(effectivePageNum + 1)"
)
return
}

View File

@ -94,6 +94,35 @@ extension RDEPUBReaderController {
return location
}
func currentVisibleRangeInfo() -> String? {
guard let pageNumber = currentPageNumber else {
return nil
}
if let resolvedPage = resolvedRuntimePage(forPageNumber: pageNumber) {
let startOffset = resolvedPage.page.pageStartOffset
let endOffset = max(startOffset + 1, resolvedPage.page.pageEndOffset + 1)
return RDEPUBTextOffsetRangeInfo(
href: resolvedPage.chapter.href,
start: startOffset,
end: endOffset
).jsonString()
}
guard let textBook,
let page = textBook.page(at: pageNumber) else {
return nil
}
let startOffset = page.pageStartOffset
let endOffset = max(startOffset + 1, page.pageEndOffset + 1)
return RDEPUBTextOffsetRangeInfo(
href: page.href,
start: startOffset,
end: endOffset
).jsonString()
}
func synchronizeTextReadingState(pageNumber: Int, location: RDEPUBLocation) {
if let resolvedPage = resolvedRuntimePage(forPageNumber: pageNumber) {
readingSession?.updateReadingContext(

View File

@ -214,9 +214,7 @@ public final class RDURLReaderController: UIViewController {
?? readerController.textBook?.pages.count
?? readerController.activePages.count
let numPages = readerController.readerView.numberOfPages()
print("[ReadViewDemo] performDemoPageNavigation(\(pageNumber)): knownPages=\(knownPages), readerView.numberOfPages=\(numPages), currentPage=\(readerController.readerView.currentPage)")
let moved = readerController.go(toPageNumber: pageNumber, animated: animated)
print("[ReadViewDemo] performDemoPageNavigation(\(pageNumber)): moved=\(moved), after currentPage=\(readerController.readerView.currentPage)")
if moved {
emitDemoState(prefix: "page=\(pageNumber)")
}
@ -264,7 +262,6 @@ public final class RDURLReaderController: UIViewController {
if pendingDemoPageRequest.attemptCount >= maxPendingDemoPageAttempts {
self.pendingDemoPageRequest = nil
isRetryingPendingDemoPage = false
print("[ReadViewDemo] automation page=\(pendingDemoPageRequest.pageNumber) failed after \(pendingDemoPageRequest.attemptCount) attempts")
return
}
@ -280,7 +277,6 @@ public final class RDURLReaderController: UIViewController {
let href = location?.href ?? "nil"
let progression = location.map { String(format: "%.4f", $0.navigationProgression) } ?? "nil"
let page = readerController.currentPageNumber.map(String.init) ?? "nil"
print("[ReadViewDemo] automation \(prefix) -> page \(page) href \(href) progression \(progression)")
}
private func installDemoStateLabel() {
@ -370,7 +366,6 @@ public final class RDURLReaderController: UIViewController {
if let logPrefix {
logDemoState(prefix: logPrefix)
} else if logIfChanged, state != lastEmittedDemoState {
print("[ReadViewDemo] automation \(state)")
}
lastEmittedDemoState = state
}

View File

@ -2,59 +2,9 @@ import Foundation
enum RDEPUBBackgroundTrace {
static var isEnabled: Bool {
#if DEBUG
return _enabled
#else
return false
#endif
}
static var _enabled = true
static func log(_ scope: String, _ message: String) {
guard isEnabled else { return }
let threadRole = Thread.isMainThread ? "main" : "bg"
let threadName = resolvedThreadName()
let queueLabel = resolvedQueueLabel()
print("[EPUB][\(scope)][\(threadRole)][queue=\(queueLabel)][thread=\(threadName)] \(message)")
let queueLabel = String(validatingUTF8: __dispatch_queue_get_label(nil)) ?? "unknown"
print("[EPUB][\(scope)][\(threadRole)][queue=\(queueLabel)] \(message)")
}
static func measure<T>(_ scope: String, _ message: String, work: () throws -> T) rethrows -> T {
guard isEnabled else { return try work() }
let startedAt = CFAbsoluteTimeGetCurrent()
log(scope, "START \(message)")
do {
let result = try work()
let elapsedMs = Int((CFAbsoluteTimeGetCurrent() - startedAt) * 1000)
log(scope, "END \(message) elapsedMs=\(elapsedMs)")
return result
} catch {
let elapsedMs = Int((CFAbsoluteTimeGetCurrent() - startedAt) * 1000)
log(scope, "FAIL \(message) elapsedMs=\(elapsedMs) error=\(error)")
throw error
}
}
private static func resolvedThreadName() -> String {
if let name = Thread.current.name, !name.isEmpty {
return name
}
if Thread.isMainThread {
return "main"
}
return String(describing: Unmanaged.passUnretained(Thread.current).toOpaque())
}
private static func resolvedQueueLabel() -> String {
String(validatingUTF8: __dispatch_queue_get_label(nil)) ?? "unknown"
}
}
}

View File

@ -47,10 +47,7 @@ final class RDEPUBChapterLoader {
priority: LoadPriority = .navigation,
completion: @escaping (Result<RDEPUBRuntimeChapter, Error>) -> Void
) {
RDEPUBBackgroundTrace.log("ChapterLoader", "request spine=\(spineIndex) priority=\(priority)")
if let cached = store.chapterData(for: spineIndex) {
RDEPUBBackgroundTrace.log("ChapterLoader", "cache hit spine=\(spineIndex) priority=\(priority)")
if let context {
scheduleDeferredCFIMapBuildIfNeeded(
for: cached,
@ -78,10 +75,6 @@ final class RDEPUBChapterLoader {
switch registration {
case .joined(let existingPriority, let effectivePriority):
RDEPUBBackgroundTrace.log(
"ChapterLoader",
"dedupe spine=\(spineIndex) existingPriority=\(existingPriority) requestedPriority=\(priority) effectivePriority=\(effectivePriority)"
)
return
case .created:
break
@ -98,39 +91,26 @@ final class RDEPUBChapterLoader {
return
}
let queuePriority = self.pendingPriority(for: spineIndex) ?? priority
RDEPUBBackgroundTrace.log("ChapterLoader", "queue start spine=\(spineIndex) priority=\(queuePriority)")
let cacheKey = self.makeCacheKey(spineIndex: spineIndex, context: context)
let precomputedPageRanges = store.pageCount(for: cacheKey)?.pageRanges
let diskSummary: RDEPUBChapterSummary?
if precomputedPageRanges == nil {
diskSummary = self.summaryDiskCache?.read(for: cacheKey)
if diskSummary != nil {
RDEPUBBackgroundTrace.log("ChapterLoader", "磁盘摘要缓存命中 spine=\(spineIndex)")
} else {
RDEPUBBackgroundTrace.log("ChapterLoader", "缓存未命中 spine=\(spineIndex)")
}
} else {
diskSummary = nil
RDEPUBBackgroundTrace.log("ChapterLoader", "页数缓存命中 spine=\(spineIndex)")
}
let diskPageRanges = diskSummary?.pageRanges.map { $0.nsRange }
let availablePageRanges = precomputedPageRanges ?? diskPageRanges
do {
let chapter = try RDEPUBBackgroundTrace.measure(
"ChapterLoader",
"buildChapter spine=\(spineIndex) priority=\(queuePriority) cachedRanges=\(availablePageRanges?.count ?? 0)"
) {
try self.buildChapter(
spineIndex: spineIndex,
availablePageRanges: availablePageRanges,
diskSummary: diskSummary,
context: context
)
}
RDEPUBBackgroundTrace.log("ChapterLoader", "buildChapter OK: spine=\(spineIndex) pages=\(chapter.pages.count)")
let chapter = try self.buildChapter(
spineIndex: spineIndex,
availablePageRanges: availablePageRanges,
diskSummary: diskSummary,
context: context
)
store.insertChapter(chapter)
let pc = RDEPUBRuntimePageCount(
@ -174,8 +154,6 @@ final class RDEPUBChapterLoader {
self.resolvePendingLoad(spineIndex: spineIndex, result: .success(chapter))
}
} catch {
RDEPUBBackgroundTrace.log("ChapterLoader", "buildChapter FAILED: spine=\(spineIndex) error=\(error)")
store.endPendingChapterLoad(for: spineIndex)
store.markBuilding(false)
self.resolvePendingLoad(spineIndex: spineIndex, result: .failure(error))
@ -217,10 +195,6 @@ final class RDEPUBChapterLoader {
semaphore.signal()
}
if case .joined(let existingPriority, let effectivePriority) = registration {
RDEPUBBackgroundTrace.log(
"ChapterLoader",
"sync join spine=\(spineIndex) existingPriority=\(existingPriority) effectivePriority=\(effectivePriority)"
)
semaphore.wait()
return try result!.get()
}
@ -230,45 +204,40 @@ final class RDEPUBChapterLoader {
var result: Result<RDEPUBRuntimeChapter, Error>?
let semaphore = DispatchSemaphore(value: 0)
RDEPUBBackgroundTrace.log("ChapterLoader", "sync request spine=\(spineIndex)")
store.chapterLoadQueue.async {
do {
result = try RDEPUBBackgroundTrace.measure(
"ChapterLoader",
"sync buildChapter spine=\(spineIndex)"
) {
try autoreleasepool { () -> Result<RDEPUBRuntimeChapter, Error> in
let cacheKey = self.makeCacheKey(spineIndex: spineIndex, context: context)
let precomputedPageRanges = store.pageCount(for: cacheKey)?.pageRanges
let diskSummary: RDEPUBChapterSummary?
if precomputedPageRanges == nil {
diskSummary = self.summaryDiskCache?.read(for: cacheKey)
} else {
diskSummary = nil
}
let chapter = try self.buildChapter(
spineIndex: spineIndex,
availablePageRanges: precomputedPageRanges ?? diskSummary?.pageRanges.map(\.nsRange),
diskSummary: diskSummary,
context: context
)
store.insertChapter(chapter)
let pageCount = RDEPUBRuntimePageCount(
cacheKey: cacheKey,
spineIndex: spineIndex,
pageRanges: chapter.pageRanges,
pageCount: chapter.pages.count,
renderSignature: cacheKey.renderSignature
)
store.insertPageCount(pageCount, for: cacheKey)
self.scheduleDeferredCFIMapBuildIfNeeded(
for: chapter,
cacheKey: cacheKey,
store: store
)
return .success(chapter)
let chapter: RDEPUBRuntimeChapter = try autoreleasepool {
let cacheKey = self.makeCacheKey(spineIndex: spineIndex, context: context)
let precomputedPageRanges = store.pageCount(for: cacheKey)?.pageRanges
let diskSummary: RDEPUBChapterSummary?
if precomputedPageRanges == nil {
diskSummary = self.summaryDiskCache?.read(for: cacheKey)
} else {
diskSummary = nil
}
let chapter = try self.buildChapter(
spineIndex: spineIndex,
availablePageRanges: precomputedPageRanges ?? diskSummary?.pageRanges.map(\.nsRange),
diskSummary: diskSummary,
context: context
)
store.insertChapter(chapter)
let pageCount = RDEPUBRuntimePageCount(
cacheKey: cacheKey,
spineIndex: spineIndex,
pageRanges: chapter.pageRanges,
pageCount: chapter.pages.count,
renderSignature: cacheKey.renderSignature
)
store.insertPageCount(pageCount, for: cacheKey)
self.scheduleDeferredCFIMapBuildIfNeeded(
for: chapter,
cacheKey: cacheKey,
store: store
)
return chapter
}
result = .success(chapter)
} catch {
result = .failure(error)
}
@ -332,7 +301,6 @@ final class RDEPUBChapterLoader {
if let pageRanges = availablePageRanges {
RDEPUBBackgroundTrace.log("ChapterLoader", "轻量路径 spine=\(spineIndex) 缓存页数=\(pageRanges.count)")
return try buildChapterFromCachedPageRanges(
spineIndex: spineIndex,
pageRanges: pageRanges,
@ -346,7 +314,6 @@ final class RDEPUBChapterLoader {
)
}
RDEPUBBackgroundTrace.log("ChapterLoader", "完整路径 spine=\(spineIndex)")
let builder = context.makeTextBookBuilder(layoutConfig: layoutConfig)
guard let result = try builder.buildChapter(
parser: parser,
@ -410,10 +377,6 @@ final class RDEPUBChapterLoader {
effectivePageRanges = sanitizedCachedRanges
metadataSource = diskSummary?.pageMetadataList
} else {
RDEPUBBackgroundTrace.log(
"ChapterLoader",
"缓存页范围失效,回退重分页 spine=\(spineIndex) cached=\(pageRanges.count) valid=\(sanitizedCachedRanges.count) textLength=\(typesetString.length)"
)
effectivePageRanges = typesetString.rd_paginatedFrames(size: pageSize, config: layoutConfig).map(\.contentRange)
metadataSource = nil
}

View File

@ -83,10 +83,6 @@ final class RDEPUBChapterWarmupOrchestrator {
windowRadius: context.configuration.chapterWindowRadius
)
presentationRuntime.navigationStateMachine.transition(to: .preparingChapter(spineIndex: spineIndex))
RDEPUBBackgroundTrace.log(
"Runtime",
"prepareOnDemandChapter page=\(pageNumber) absoluteIndex=\(absolutePageIndex) spine=\(spineIndex)"
)
if !chapterReady {
guard allowSynchronousLoad else {
@ -104,7 +100,6 @@ final class RDEPUBChapterWarmupOrchestrator {
)
} catch {
clearPendingPreparePageNumber(pageNumber)
RDEPUBBackgroundTrace.log("Runtime", "prepareOnDemandChapter FAILED: spine=\(spineIndex) error=\(error)")
return false
}
}
@ -151,10 +146,6 @@ final class RDEPUBChapterWarmupOrchestrator {
return
}
RDEPUBBackgroundTrace.log(
"Runtime",
"extendPartialBookPageMap currentPage=\(currentPageNumber) totalPages=\(currentMap.totalPages) appendSpines=\(spineIndicesToAppend) direction=\(isNearEnd ? "forward" : "backward")"
)
let currentLocation = locationCoordinator.currentVisibleLocation()
let loadedChaptersLock = NSLock()
@ -174,8 +165,8 @@ final class RDEPUBChapterWarmupOrchestrator {
loadedChaptersLock.lock()
loadedChapters[spineIndex] = chapter
loadedChaptersLock.unlock()
case .failure(let error):
RDEPUBBackgroundTrace.log("Runtime", "extendPartialBookPageMap skip spine=\(spineIndex) error=\(error)")
case .failure:
break
}
}
}
@ -216,7 +207,6 @@ final class RDEPUBChapterWarmupOrchestrator {
guard shouldSchedulePrefetch(for: spineIndex) else { continue }
store.addPrefetchTarget(spineIndex)
RDEPUBBackgroundTrace.log("Runtime", "initial open prefetch forward spine=\(spineIndex)")
loader.loadChapter(spineIndex: spineIndex, store: store, priority: .prefetch) { [weak self] result in
guard let self, case .success = result else { return }
self.appendLoadedForwardChaptersToCurrentPageMapIfPossible()
@ -363,10 +353,6 @@ final class RDEPUBChapterWarmupOrchestrator {
}
let newMap = RDEPUBBookPageMap(entries: normalizedEntries)
RDEPUBBackgroundTrace.log(
"Runtime",
"extendPartialBookPageMap applied chapters=\(newMap.totalChapters) pages=\(newMap.totalPages)"
)
presentationRuntime.queueExtendedPartialPageMap(
newMap,
currentPageNumber: currentPageNumber,
@ -380,16 +366,8 @@ final class RDEPUBChapterWarmupOrchestrator {
completion: ((Bool) -> Void)?
) {
guard beginAsynchronousChapterPreparation(for: spineIndex) else {
RDEPUBBackgroundTrace.log(
"Runtime",
"prepareOnDemandChapter async deduped spine=\(spineIndex) page=\(triggerPageNumber)"
)
return
}
RDEPUBBackgroundTrace.log(
"Runtime",
"prepareOnDemandChapter async spine=\(spineIndex) page=\(triggerPageNumber)"
)
loader.loadChapter(
spineIndex: spineIndex,
store: store,
@ -406,10 +384,6 @@ final class RDEPUBChapterWarmupOrchestrator {
self.refreshVisibleContentIfNeeded(afterPreparing: spineIndex, triggerPageNumber: triggerPageNumber)
case .failure(let error):
self.clearPendingPreparePageNumber(triggerPageNumber)
RDEPUBBackgroundTrace.log(
"Runtime",
"prepareOnDemandChapter async FAILED: spine=\(spineIndex) error=\(error)"
)
completion?(false)
}
}
@ -429,10 +403,6 @@ final class RDEPUBChapterWarmupOrchestrator {
for adjacentSpineIndex in store.windowSpineIndices where adjacentSpineIndex != spineIndex {
guard shouldSchedulePrefetch(for: adjacentSpineIndex) else { continue }
store.addPrefetchTarget(adjacentSpineIndex)
RDEPUBBackgroundTrace.log(
"Runtime",
"schedule prefetch currentSpine=\(spineIndex) adjacentSpine=\(adjacentSpineIndex)"
)
loader.loadChapter(
spineIndex: adjacentSpineIndex,
store: store,
@ -468,10 +438,6 @@ final class RDEPUBChapterWarmupOrchestrator {
for targetSpineIndex in targets {
guard shouldSchedulePrefetch(for: targetSpineIndex) else { continue }
store.addPrefetchTarget(targetSpineIndex)
RDEPUBBackgroundTrace.log(
"Runtime",
"boundary prefetch currentSpine=\(spineIndex) targetSpine=\(targetSpineIndex) remainingPages=\(remainingPages)"
)
loader.loadChapter(spineIndex: targetSpineIndex, store: store, priority: .prefetch) { [weak self] result in
guard let self, case .success = result else { return }
self.appendLoadedForwardChaptersToCurrentPageMapIfPossible()
@ -544,10 +510,6 @@ final class RDEPUBChapterWarmupOrchestrator {
let newMap = RDEPUBBookPageMap(entries: newEntries)
guard newMap.totalPages > currentMap.totalPages else { return }
RDEPUBBackgroundTrace.log(
"Runtime",
"appendLoadedForwardChapters currentPage=\(currentPageNumber) trailingBefore=\(trailingPages) trailingAfter=\(newMap.totalPages - currentPageNumber) chapters=\(newMap.totalChapters) pages=\(newMap.totalPages)"
)
presentationRuntime.queueForwardAppendedPageMap(newMap)
}
@ -574,10 +536,6 @@ final class RDEPUBChapterWarmupOrchestrator {
if !allowSynchronousLoad && !chapterReady {
let inserted = pendingPreparePageNumbers.insert(pageNumber).inserted
if !inserted {
RDEPUBBackgroundTrace.log(
"Runtime",
"prepareOnDemandChapter page deduped page=\(pageNumber) spine=\(spineIndex) chapterReady=false"
)
return false
}
return nil
@ -586,10 +544,6 @@ final class RDEPUBChapterWarmupOrchestrator {
pendingPreparePageNumbers.remove(pageNumber)
if let lastTimestamp = recentPrepareTimestamps[pageNumber],
now - lastTimestamp <= prepareRequestDebounceInterval {
RDEPUBBackgroundTrace.log(
"Runtime",
"prepareOnDemandChapter page debounced page=\(pageNumber) spine=\(spineIndex) chapterReady=\(chapterReady)"
)
return chapterReady
}
@ -616,10 +570,6 @@ final class RDEPUBChapterWarmupOrchestrator {
return
}
if readerView.isPageCurlTransitioning {
RDEPUBBackgroundTrace.log(
"LoadingPage",
"defer refreshVisibleContent spine=\(spineIndex) triggerPage=\(triggerPageNumber) reason=pageCurlTransition"
)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in
self?.refreshVisibleContentIfNeeded(
afterPreparing: spineIndex,
@ -630,26 +580,14 @@ final class RDEPUBChapterWarmupOrchestrator {
}
let visiblePageNumber = readerView.currentPage + 1
if visiblePageNumber == triggerPageNumber {
RDEPUBBackgroundTrace.log(
"LoadingPage",
"refreshVisibleContent matchedTrigger spine=\(spineIndex) triggerPage=\(triggerPageNumber) visiblePage=\(visiblePageNumber)"
)
refreshVisibleContentPreservingLocation()
return
}
guard visiblePageNumber > 0,
let visibleSpineIndex = bookPageMap.spineIndex(forAbsolutePage: visiblePageNumber - 1),
visibleSpineIndex == spineIndex else {
RDEPUBBackgroundTrace.log(
"LoadingPage",
"skip refreshVisibleContent spine=\(spineIndex) triggerPage=\(triggerPageNumber) visiblePage=\(visiblePageNumber)"
)
return
}
RDEPUBBackgroundTrace.log(
"LoadingPage",
"refreshVisibleContent matchedVisibleSpine spine=\(spineIndex) triggerPage=\(triggerPageNumber) visiblePage=\(visiblePageNumber)"
)
refreshVisibleContentPreservingLocation()
}
@ -677,16 +615,8 @@ final class RDEPUBChapterWarmupOrchestrator {
chapters.append(chapter)
} catch {
if spineIndex == targetSpineIndex {
RDEPUBBackgroundTrace.log(
"Runtime",
"ensureNavigationTarget FAILED target spine=\(spineIndex) error=\(error)"
)
return []
}
RDEPUBBackgroundTrace.log(
"Runtime",
"ensureNavigationTarget skip adjacent spine=\(spineIndex) error=\(error)"
)
}
}
return chapters

View File

@ -46,10 +46,6 @@ final class RDEPUBChapterWindowCoordinator {
self.isSwitchingChapter = false
self.buildSnapshotAroundCurrent(chapter: chapter)
case .failure(let error):
#if DEBUG
print("[EPUB][WindowCoord] loadChapter failed at spine=\(initialSpineIndex): \(error), trying next")
#endif
let nextIndex = initialSpineIndex + 1
if nextIndex < totalSpineCount {
self.store.setCurrentChapter(
@ -70,9 +66,6 @@ final class RDEPUBChapterWindowCoordinator {
private func buildSnapshotAroundCurrent(chapter: RDEPUBRuntimeChapter) {
guard let current = store.currentSpineIndex else {
#if DEBUG
print("[EPUB][WindowCoord] buildSnapshot: currentSpineIndex is nil, ABORT")
#endif
return
}
let chapters = store.windowSpineIndices.compactMap { spineIndex -> RDEPUBRuntimeChapter? in
@ -82,9 +75,6 @@ final class RDEPUBChapterWindowCoordinator {
return store.chapterData(for: spineIndex)
}
let snapshot = RDEPUBChapterWindowSnapshot.from(chapters: chapters, anchorSpineIndex: current)
#if DEBUG
print("[EPUB][WindowCoord] snapshot: chapters=\(snapshot.chapters.count) pages=\(snapshot.pageCount) anchorPage=\(snapshot.anchorPageOffset)")
#endif
currentSnapshot = snapshot
isApplyingSnapshot = true
onSnapshotChanged?(snapshot)
@ -213,20 +203,9 @@ final class RDEPUBChapterWindowCoordinator {
}
private func handle(error: Error) {
#if DEBUG
print("[RDEPUBChapterWindowCoordinator] chapter load error: \(error)")
#endif
DispatchQueue.main.async { [weak self] in
guard let self else { return }
self.context.hideLoading()
if self.currentSnapshot == nil {
#if DEBUG
print("[RDEPUBChapterWindowCoordinator] No snapshot after error, page will be blank")
#endif
}
}
}

View File

@ -69,10 +69,6 @@ final class RDEPUBBackgroundCoverageStore {
segments[index] = mergedSegment
currentMemoryBytes = currentMemoryBytes - existing.estimatedMemoryBytes + mergedSegment.estimatedMemoryBytes
merged = true
RDEPUBBackgroundTrace.log(
"CoverageStore",
"merged segments: \(existing.lowerSpineIndex)-\(existing.upperSpineIndex) + \(segment.lowerSpineIndex)-\(segment.upperSpineIndex)"
)
break
}
}
@ -84,11 +80,6 @@ final class RDEPUBBackgroundCoverageStore {
}
lastAccessTime[segment.lowerSpineIndex] = CFAbsoluteTimeGetCurrent()
RDEPUBBackgroundTrace.log(
"CoverageStore",
"added segment \(segment.lowerSpineIndex)-\(segment.upperSpineIndex) total=\(segments.count) memory=\(currentMemoryBytes)B"
)
}
func findSegment(containing spineIndex: Int) -> RDEPUBBackgroundCoverageSegment? {
@ -138,10 +129,6 @@ final class RDEPUBBackgroundCoverageStore {
activeWindowSpineIndices: Set<Int>,
protectedSpineIndices: Set<Int>
) {
RDEPUBBackgroundTrace.log(
"CoverageStore",
"memory warning: clearing cold segments, current=\(currentMemoryBytes)B"
)
clearColdSegments(
activeWindowSpineIndices: activeWindowSpineIndices,
@ -167,11 +154,6 @@ final class RDEPUBBackgroundCoverageStore {
segments.removeAll { $0.lowerSpineIndex == segment.lowerSpineIndex }
}
}
RDEPUBBackgroundTrace.log(
"CoverageStore",
"after cleanup: segments=\(segments.count) memory=\(currentMemoryBytes)B"
)
}
private func evictIfNeeded(forNewSegment newSegment: RDEPUBBackgroundCoverageSegment) {
@ -201,11 +183,6 @@ final class RDEPUBBackgroundCoverageStore {
let evicted = segments.remove(at: oldestIndex)
currentMemoryBytes -= evicted.estimatedMemoryBytes
lastAccessTime.removeValue(forKey: evicted.lowerSpineIndex)
RDEPUBBackgroundTrace.log(
"CoverageStore",
"evicted segment \(evicted.lowerSpineIndex)-\(evicted.upperSpineIndex)"
)
}
private func canMerge(_ lhs: RDEPUBBackgroundCoverageSegment, _ rhs: RDEPUBBackgroundCoverageSegment) -> Bool {

View File

@ -93,10 +93,6 @@ final class RDEPUBBackgroundPriorityManager {
currentGeneration += 1
coldCursor = 0
RDEPUBBackgroundTrace.log(
"PriorityManager",
"addWarmAnchor spine=\(spineIndex) generation=\(currentGeneration) anchors=\(warmAnchors.count)"
)
}
func makeMetadataPriorityOrder(

View File

@ -121,10 +121,6 @@ final class RDEPUBJumpSessionManager {
lastPageDirection = nil
lastActivityTime = now
RDEPUBBackgroundTrace.log(
"JumpSession",
"created anchor=\(anchorSpineIndex) protected=\(protectedIndices.count) seq=\(nextSequenceNumber)"
)
return session
}
@ -163,20 +159,12 @@ final class RDEPUBJumpSessionManager {
if now >= session.expiresAt {
if isIdle || (now - lastActivityTime) >= policy.idleGracePeriod {
RDEPUBBackgroundTrace.log(
"JumpSession",
"end: timeout seq=\(session.sequenceNumber)"
)
return .timeout
}
}
if !session.protectedSpineIndices.contains(currentSpineIndex) {
if consecutivePageCount >= policy.exitPageThreshold {
RDEPUBBackgroundTrace.log(
"JumpSession",
"end: navigated-away seq=\(session.sequenceNumber) pages=\(consecutivePageCount)"
)
return .navigatedAway
}
} else {
@ -189,10 +177,6 @@ final class RDEPUBJumpSessionManager {
func endSession(_ reason: RDEPUBJumpSession.EndReason) {
guard let session = activeSession else { return }
RDEPUBBackgroundTrace.log(
"JumpSession",
"ended seq=\(session.sequenceNumber) reason=\(reason)"
)
activeSession = nil
consecutivePageCount = 0
lastPageDirection = nil

View File

@ -125,10 +125,6 @@ final class RDEPUBMetadataParseWorker {
context.paginationToken == token else { return }
if let restoredPageMap = self.restoreBookPageMapIfPossible() {
RDEPUBBackgroundTrace.log(
"MetadataParse",
"full cache restore hit chapters=\(restoredPageMap.totalChapters) pages=\(restoredPageMap.totalPages)"
)
DispatchQueue.main.async {
guard context.paginationToken == token,
context.controller != nil,
@ -140,13 +136,8 @@ final class RDEPUBMetadataParseWorker {
let prewarmStart = CFAbsoluteTimeGetCurrent()
let prewarmMs = Int((CFAbsoluteTimeGetCurrent() - prewarmStart) * 1000)
RDEPUBBackgroundTrace.log("MetadataParse", "prewarmHashMs=\(prewarmMs) chapters=\(self.allBuildableIndices.count)")
let restored = self.summaryDiskCache?.readAll(keys: self.catalog)
RDEPUBBackgroundTrace.log(
"MetadataParse",
"begin token=\(token.uuidString) buildableChapters=\(self.allBuildableIndices.count) concurrency=\(self.workerCount)"
)
let cachedSummaries = restored?.summaries ?? [:]
let cachedSpineIndices = Set(cachedSummaries.keys)
let resultLock = NSLock()
@ -157,10 +148,6 @@ final class RDEPUBMetadataParseWorker {
)
if !cachedSpineIndices.isEmpty {
RDEPUBBackgroundTrace.log(
"MetadataParse",
"resumeFromCache cachedChapters=\(cachedSpineIndices.count) total=\(self.allBuildableIndices.count)"
)
let cachedMap = self.buildPageMap(summaries: parseState.summariesBySpineIndex)
DispatchQueue.main.async {
guard context.paginationToken == token,
@ -178,10 +165,6 @@ final class RDEPUBMetadataParseWorker {
currentSpineIndex: currentSpineIndex,
cachedSpineIndices: cachedSpineIndices
)
RDEPUBBackgroundTrace.log(
"MetadataParse",
"prioritized hot=\(prioritizedSpineIndices.prefix(10).count) total=\(prioritizedSpineIndices.count)"
)
} else {
prioritizedSpineIndices = self.allBuildableIndices.filter { !cachedSpineIndices.contains($0) }
}
@ -192,7 +175,6 @@ final class RDEPUBMetadataParseWorker {
guard !cancellationController.isCancelled,
context.controller != nil,
context.paginationToken == token else {
RDEPUBBackgroundTrace.log("MetadataParse", "abort before queue start")
return
}
@ -222,7 +204,6 @@ final class RDEPUBMetadataParseWorker {
return
}
do {
RDEPUBBackgroundTrace.log("MetadataParse", "正在解析 spine=\(spineIndex) \(offset + 1)/\(uncachedSpineIndices.count)")
let renderResult: RDEPUBChapterSummary? = try autoreleasepool { () -> RDEPUBChapterSummary? in
guard context.controller != nil,
@ -246,7 +227,6 @@ final class RDEPUBMetadataParseWorker {
context.paginationToken == token,
!cancellationController.isCancelled,
operation?.isCancelled != true else {
RDEPUBBackgroundTrace.log("MetadataParse", "drop rendered chapter due to cancellation spine=\(spineIndex)")
return nil
}
let renderElapsed = (CFAbsoluteTimeGetCurrent() - renderStart) * 1000
@ -272,7 +252,6 @@ final class RDEPUBMetadataParseWorker {
context.paginationToken == token,
!cancellationController.isCancelled,
operation?.isCancelled != true else {
RDEPUBBackgroundTrace.log("MetadataParse", "skip disk write due to cancellation spine=\(spineIndex)")
return nil
}
let writeStart = CFAbsoluteTimeGetCurrent()
@ -285,10 +264,6 @@ final class RDEPUBMetadataParseWorker {
completedChapters += 1
timingLock.unlock()
RDEPUBBackgroundTrace.log(
"MetadataParse",
"spine=\(spineIndex) renderMs=\(Int(renderElapsed)) writeMs=\(Int(writeElapsed))"
)
return summary
}
@ -335,7 +310,6 @@ final class RDEPUBMetadataParseWorker {
timingLock.lock()
failedChapters += 1
timingLock.unlock()
RDEPUBBackgroundTrace.log("MetadataParse", "buildChapter FAILED: spine=\(spineIndex) error=\(error)")
self.scheduleRetry(
spineIndex: spineIndex,
@ -364,29 +338,18 @@ final class RDEPUBMetadataParseWorker {
let failed = failedChapters
timingLock.unlock()
let avgRenderMs = rendered > 0 ? renderTotal / rendered : 0
RDEPUBBackgroundTrace.log(
"MetadataParse",
"timing wallClockMs=\(wallClockMs) chapters=\(rendered) failed=\(failed) " +
"prewarmHashMs=\(prewarmMs) renderTotalMs=\(renderTotal) writeTotalMs=\(writeTotal) " +
"mergeTotalMs=\(mergeTotal) avgRenderMs=\(avgRenderMs) concurrency=\(self.workerCount)"
)
context.lastMetadataParseWallClockMs = wallClockMs
context.lastMetadataParseConcurrency = self.workerCount
guard context.controller != nil,
context.paginationToken == token,
!cancellationController.isCancelled else {
RDEPUBBackgroundTrace.log("MetadataParse", "abort: reader dismissed or token changed")
return
}
let finalMergeStart = CFAbsoluteTimeGetCurrent()
let pageMap = self.buildPageMap(summaries: parseState.summariesBySpineIndex)
let finalMergeMs = Int((CFAbsoluteTimeGetCurrent() - finalMergeStart) * 1000)
RDEPUBBackgroundTrace.log(
"MetadataParse",
"complete chapters=\(pageMap.totalChapters) pages=\(pageMap.totalPages) finalMergeMs=\(finalMergeMs)"
)
if let coverageStore = context.runtime?.backgroundCoverageStore {
let resolvedSpineIndices = Set(parseState.summariesBySpineIndex.keys)
@ -434,18 +397,10 @@ final class RDEPUBMetadataParseWorker {
cancellationController: RDEPUBMetadataParseCancellationController
) {
guard retryCount < Self.maxRetryCount else {
RDEPUBBackgroundTrace.log(
"MetadataParse",
"spine=\(spineIndex) max retries reached, marking as deferredFailure"
)
return
}
let delay = Self.retryDelays[min(retryCount, Self.retryDelays.count - 1)]
RDEPUBBackgroundTrace.log(
"MetadataParse",
"scheduling retry for spine=\(spineIndex) attempt=\(retryCount + 1) delay=\(delay)s"
)
DispatchQueue.global(qos: .utility).asyncAfter(deadline: .now() + delay) { [weak self] in
guard let self else { return }
@ -470,7 +425,6 @@ final class RDEPUBMetadataParseWorker {
guard context.controller != nil,
context.paginationToken == self.token,
!cancellationController.isCancelled else {
RDEPUBBackgroundTrace.log("MetadataParse", "drop retry result due to cancellation spine=\(spineIndex)")
return
}
@ -494,7 +448,6 @@ final class RDEPUBMetadataParseWorker {
guard context.controller != nil,
context.paginationToken == self.token,
!cancellationController.isCancelled else {
RDEPUBBackgroundTrace.log("MetadataParse", "skip retry disk write due to cancellation spine=\(spineIndex)")
return
}
self.summaryDiskCache?.write(summary: summary, for: cacheKey)
@ -520,15 +473,7 @@ final class RDEPUBMetadataParseWorker {
}
}
RDEPUBBackgroundTrace.log(
"MetadataParse",
"retry succeeded for spine=\(spineIndex) attempt=\(retryCount + 1)"
)
} catch {
RDEPUBBackgroundTrace.log(
"MetadataParse",
"retry failed for spine=\(spineIndex) attempt=\(retryCount + 1) error=\(error)"
)
self.scheduleRetry(
spineIndex: spineIndex,

View File

@ -67,10 +67,9 @@ final class RDEPUBNavigationStateMachine {
isValid = false
}
if !isValid {
RDEPUBBackgroundTrace.log(
"NavigationStateMachine",
"WARNING: unexpected transition \(oldState)\(newState)"
)
#if DEBUG
assertionFailure("Unexpected navigation state transition: \(oldState)\(newState)")
#endif
}
}
#endif

View File

@ -28,10 +28,8 @@ final class RDEPUBPageMapReconciliationCoordinator {
guard let currentWindow else {
if let candidatePageMap {
RDEPUBBackgroundTrace.log("Reconciliation", "evaluateTakeover: no currentWindow, fullReplace candidateChapters=\(candidatePageMap.totalChapters) candidatePages=\(candidatePageMap.totalPages)")
return .fullReplace(candidatePageMap)
}
RDEPUBBackgroundTrace.log("Reconciliation", "evaluateTakeover: no currentWindow, no candidate")
return .keepCurrentWindow
}
@ -54,10 +52,6 @@ final class RDEPUBPageMapReconciliationCoordinator {
let coverageRatio = Double(protectedIndices.intersection(candidateIndices).count) /
Double(protectedIndices.count)
if coverageRatio < 0.8 {
RDEPUBBackgroundTrace.log(
"Reconciliation",
"evaluateTakeover: blocked by jumpSession protection coverage=\(String(format: "%.2f", coverageRatio)) currentSpine=\(currentSpineIndex) protected=\(protectedIndices)"
)
return .keepCurrentWindow
}
}
@ -72,10 +66,6 @@ final class RDEPUBPageMapReconciliationCoordinator {
let hasPrev = candidateSegment.contains(spineIndex: currentSpineIndex - 1)
let hasNext = candidateSegment.contains(spineIndex: currentSpineIndex + 1)
if !hasPrev || !hasNext {
RDEPUBBackgroundTrace.log(
"Reconciliation",
"evaluateTakeover: blocked by missing adjacent coverage (segment) currentSpine=\(currentSpineIndex) hasPrev=\(hasPrev) hasNext=\(hasNext)"
)
return .keepCurrentWindow
}
}
@ -85,10 +75,6 @@ final class RDEPUBPageMapReconciliationCoordinator {
if let candidateSegment {
let currentRenderSignature = context.currentRenderSignature()
if candidateSegment.renderSignature != currentRenderSignature {
RDEPUBBackgroundTrace.log(
"Reconciliation",
"evaluateTakeover: blocked by render signature mismatch"
)
return .keepCurrentWindow
}
}
@ -111,7 +97,6 @@ final class RDEPUBPageMapReconciliationCoordinator {
)
}
RDEPUBBackgroundTrace.log("Reconciliation", "evaluateTakeover: no candidate, keepCurrentWindow")
return .keepCurrentWindow
}
@ -126,10 +111,6 @@ final class RDEPUBPageMapReconciliationCoordinator {
if let currentSpineIndex {
if !candidateIndices.contains(currentSpineIndex) {
RDEPUBBackgroundTrace.log(
"Reconciliation",
"evaluateSegmentTakeover: keepCurrentWindow — currentSpine=\(currentSpineIndex) not in candidate"
)
return .keepCurrentWindow
}
}
@ -139,10 +120,6 @@ final class RDEPUBPageMapReconciliationCoordinator {
let hasNext = candidateIndices.contains(currentSpineIndex + 1) ||
currentSpineIndex == lastBuildableSpineIndex
if !hasPrev || !hasNext {
RDEPUBBackgroundTrace.log(
"Reconciliation",
"evaluateSegmentTakeover: keepCurrentWindow — missing adjacent spine=\(currentSpineIndex) hasPrev=\(hasPrev) hasNext=\(hasNext)"
)
return .keepCurrentWindow
}
}
@ -179,10 +156,6 @@ final class RDEPUBPageMapReconciliationCoordinator {
if let currentSpineIndex {
if !candidateIndices.contains(currentSpineIndex) {
RDEPUBBackgroundTrace.log(
"Reconciliation",
"evaluateFullPageMapTakeover: keepCurrentWindow — currentSpine=\(currentSpineIndex) not in candidate (candidateChapters=\(candidateIndices.count) currentChapters=\(currentEntries) candidatePages=\(candidatePageMap.totalPages) currentPages=\(currentWindow.totalPages))"
)
return .keepCurrentWindow
}
}
@ -192,10 +165,6 @@ final class RDEPUBPageMapReconciliationCoordinator {
let hasNext = candidateIndices.contains(currentSpineIndex + 1) ||
currentSpineIndex == lastBuildableSpineIndex
if !hasPrev || !hasNext {
RDEPUBBackgroundTrace.log(
"Reconciliation",
"evaluateFullPageMapTakeover: keepCurrentWindow — missing adjacent spine=\(currentSpineIndex) hasPrev=\(hasPrev) hasNext=\(hasNext) lastBuildable=\(lastBuildableSpineIndex)"
)
return .keepCurrentWindow
}
}
@ -209,10 +178,6 @@ final class RDEPUBPageMapReconciliationCoordinator {
return .fullReplace(candidatePageMap)
}
RDEPUBBackgroundTrace.log(
"Reconciliation",
"evaluateFullPageMapTakeover: keepCurrentWindow — candidateChapters=\(candidateIndices.count) < currentChapters=\(currentEntries)"
)
return .keepCurrentWindow
}
@ -237,4 +202,4 @@ final class RDEPUBPageMapReconciliationCoordinator {
return indices
}
}
}

View File

@ -71,7 +71,6 @@ final class RDEPUBPresentationRuntime {
guard !controller.isRepaginating else { return }
guard !readerView.isPageCurlTransitioning else {
RDEPUBBackgroundTrace.log("PageMapCommit", "defer commit reason=pageCurlTransition")
return
}
@ -226,18 +225,15 @@ final class RDEPUBPresentationRuntime {
switch decision {
case .keepCurrentWindow:
RDEPUBBackgroundTrace.log("Reconciliation", "decision: keepCurrentWindow — pending update removed to prevent indefinite retry")
removePendingPageMapUpdate(at: index)
return false
case .fullReplace(let newPageMap):
RDEPUBBackgroundTrace.log("Reconciliation", "decision: fullReplace")
removePendingPageMapUpdate(at: index)
applyFullPageMapReplacement(newPageMap, readerView: readerView, controller: controller)
return true
case .expandWindow, .segmentReplace:
RDEPUBBackgroundTrace.log("Reconciliation", "decision: unexpected segment decision")
removePendingPageMapUpdate(at: index)
return false
}

View File

@ -266,6 +266,7 @@ final class RDEPUBReaderAnnotationCoordinator {
let newBookmark = RDEPUBBookmark(
bookIdentifier: controller.currentBookIdentifier,
location: location,
rangeInfo: controller.currentVisibleRangeInfo(),
chapterTitle: titleForBookmarkLocation(location),
note: normalizedBookmarkNote(note)
)
@ -306,7 +307,11 @@ final class RDEPUBReaderAnnotationCoordinator {
guard let bookmark = bookmark(withID: id) else {
return false
}
return controller.restoreReadingLocation(bookmark.location, animated: animated)
return controller.restoreReadingLocation(
bookmark.location,
animated: animated,
targetHighlightRangeInfo: bookmark.rangeInfo
)
}
func presentBookmarksManager() {
@ -320,7 +325,11 @@ final class RDEPUBReaderAnnotationCoordinator {
bookmarksController.onSelectBookmark = { [weak self, weak bookmarksController] bookmark in
guard let controller = self?.controller else { return }
bookmarksController?.dismiss(animated: true) {
_ = controller.restoreReadingLocation(bookmark.location, animated: true)
_ = controller.restoreReadingLocation(
bookmark.location,
animated: true,
targetHighlightRangeInfo: bookmark.rangeInfo
)
}
}
bookmarksController.onDeleteBookmark = { [weak self] bookmark in

View File

@ -16,9 +16,6 @@ final class RDEPUBReaderAssemblyCoordinator {
setupLoadingIndicator(controller.loadingIndicator, in: controller.view)
setupErrorLabel(controller.errorLabel, in: controller.view)
controller.delegate?.epubReader(controller, configureTopToolView: controller.topToolView)
#if DEBUG
print("[ReadViewDemo] assembleInterface: pageProvider=\(readerView.pageProvider != nil ? "set" : "nil"), numberOfPages=\(readerView.numberOfPages())")
#endif
}
func finishExternalTextBookLaunchIfNeeded() {
@ -35,13 +32,7 @@ final class RDEPUBReaderAssemblyCoordinator {
}
if let textBook = controller.textBook {
#if DEBUG
print("[ReadViewDemo] finishExternalTextBook: applying textBook with \(textBook.pages.count) pages")
#endif
runtime.applyTextBook(textBook, restoreLocation: restoreLocation)
#if DEBUG
print("[ReadViewDemo] finishExternalTextBook: after applyTextBook, numberOfPages=\(context.readerView?.numberOfPages() ?? -1)")
#endif
} else {
runtime.finishPagination(restoreLocation: restoreLocation)
}

View File

@ -28,14 +28,8 @@ final class RDEPUBReaderPaginationCoordinator {
controller.showLoading()
let token = UUID()
context.paginationToken = token
#if DEBUG
print("[EPUB][Pagination] profile=\(publication.readingProfile.rawValue) layout=\(publication.layout.rawValue) spine=\(publication.spine.count)")
#endif
if publication.readingProfile == .textReflowable {
#if DEBUG
print("[EPUB][Pagination] path=text-reflowable-on-demand")
#endif
paginateTextPublication(
parser: parser,
publication: publication,
@ -47,9 +41,6 @@ final class RDEPUBReaderPaginationCoordinator {
}
if publication.layout == .fixed {
#if DEBUG
print("[EPUB][Pagination] path=fixed-layout")
#endif
let snapshot = readingSession.makePaginationSnapshot(
pageCounts: Array(repeating: 1, count: publication.spine.count),
preferences: controller.currentPreferences(),
@ -60,9 +51,6 @@ final class RDEPUBReaderPaginationCoordinator {
}
let paginator = context.makePaginator()
#if DEBUG
print("[EPUB][Pagination] path=web-paginator")
#endif
context.paginator = paginator
paginator.calculate(
parser: parser,
@ -143,31 +131,15 @@ final class RDEPUBReaderPaginationCoordinator {
func refreshVisibleContentPreservingLocation() {
guard let readerView = context.readerView else { return }
if readerView.isPageCurlTransitioning {
RDEPUBBackgroundTrace.log(
"LoadingPage",
"defer refreshVisibleContent currentPage=\(readerView.currentPage + 1) reason=pageCurlTransition"
)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in
self?.refreshVisibleContentPreservingLocation()
}
return
}
let restoreLocation = context.currentVisibleLocation() ?? context.persistenceLocation()
RDEPUBBackgroundTrace.log(
"LoadingPage",
"refreshVisibleContentPreservingLocation currentPage=\(readerView.currentPage + 1) restoreHref=\(restoreLocation?.href ?? "nil") restoreCFI=\(restoreLocation?.cfi ?? "nil")"
)
if readerView.currentDisplayType == .pageCurl, readerView.currentPage >= 0 {
RDEPUBBackgroundTrace.log(
"LoadingPage",
"refreshVisibleContent using transitionToPage currentPage=\(readerView.currentPage + 1)"
)
readerView.transitionToPage(pageNum: readerView.currentPage, animated: false)
} else {
RDEPUBBackgroundTrace.log(
"LoadingPage",
"refreshVisibleContent using reloadData currentPage=\(readerView.currentPage + 1)"
)
readerView.reloadData()
}
if let restoreLocation {
@ -220,22 +192,9 @@ final class RDEPUBReaderPaginationCoordinator {
do {
guard context.controller != nil,
let runtime = context.runtime else { return }
RDEPUBBackgroundTrace.log(
"QuickOpen",
"begin token=\(token.uuidString) candidates=\(prioritizedCandidates.count) restoreSpine=\(readingSession.initialSpineIndex(for: restoreLocation))"
)
let runtimeChapter = try RDEPUBBackgroundTrace.measure(
"QuickOpen",
"loadFirstRenderableRuntimeChapter"
) {
try self.loadFirstRenderableRuntimeChapter(
prioritizedSpineIndices: prioritizedCandidates,
runtime: runtime
)
}
RDEPUBBackgroundTrace.log(
"QuickOpen",
"ready anchorSpine=\(runtimeChapter.spineIndex) pages=\(runtimeChapter.pages.count)"
let runtimeChapter = try self.loadFirstRenderableRuntimeChapter(
prioritizedSpineIndices: prioritizedCandidates,
runtime: runtime
)
let initialChapters = self.loadInitialInteractiveRuntimeChapters(
anchorChapter: runtimeChapter,
@ -290,7 +249,6 @@ final class RDEPUBReaderPaginationCoordinator {
)
} catch {
lastError = error
RDEPUBBackgroundTrace.log("QuickOpen", "skip spine=\(spineIndex) reason=\(error)")
}
}
throw lastError ?? RDEPUBParserError.emptySpine
@ -329,10 +287,6 @@ final class RDEPUBReaderPaginationCoordinator {
)
selectedChapters.append(chapter)
} catch {
RDEPUBBackgroundTrace.log(
"QuickOpen",
"lookahead skip spine=\(spineIndex) reason=\(error)"
)
}
}

View File

@ -430,11 +430,6 @@ final class RDEPUBReaderRuntime {
}
let previewLocation = locationCoordinator.currentVisibleLocation() ?? context.persistenceLocation()
RDEPUBBackgroundTrace.log(
"Runtime",
"repaginateCurrentChapterOnly spine=\(currentSpineIndex) generation=\(previewGeneration)"
)
chapterLoader.loadChapter(
spineIndex: currentSpineIndex,
store: chapterRuntimeStore,
@ -468,10 +463,7 @@ final class RDEPUBReaderRuntime {
readerView.transitionToPage(pageNum: 0, animated: false)
case .failure(let error):
RDEPUBBackgroundTrace.log(
"Runtime",
"repaginateCurrentChapterOnly FAILED spine=\(currentSpineIndex) generation=\(previewGeneration) error=\(error)"
)
break
}
}
}
@ -523,7 +515,6 @@ final class RDEPUBReaderRuntime {
if needsFullRepaginationAfterSettingsClose {
needsFullRepaginationAfterSettingsClose = false
RDEPUBBackgroundTrace.log("Runtime", "settingsPanelDidDisappear: triggering full repagination")
paginationCoordinator.repaginatePreservingCurrentLocation()
}
}

View File

@ -97,10 +97,6 @@ extension RDReaderView: UIPageViewControllerDataSource, UIPageViewControllerDele
public func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
let resolvedPage = (pageViewController.viewControllers?.first as? RDReaderPageChildViewController)?.pageNum ?? -1
RDEPUBBackgroundTrace.log(
"PageCurl",
"didFinishAnimating finished=\(finished) completed=\(completed) resolvedPage=\(resolvedPage + 1) currentPageBeforeFinish=\(currentPage + 1)"
)
if completed, let firstVC = pageViewController.viewControllers?.first as? RDReaderPageChildViewController {
let pn = firstVC.pageNum
if pn != RDReaderView.blankPageNum && pn != RDReaderView.blankEndPageNum {
@ -119,17 +115,9 @@ extension RDReaderView: UIPageViewControllerDataSource, UIPageViewControllerDele
if let target = pendingViewControllers.first as? RDReaderPageChildViewController,
target.pageNum != RDReaderView.blankPageNum,
target.pageNum != RDReaderView.blankEndPageNum {
RDEPUBBackgroundTrace.log(
"PageCurl",
"willTransitionTo targetPage=\(target.pageNum + 1) currentPage=\(currentPage + 1)"
)
predictedPageDirection = target.pageNum >= currentPage
primePageCache(around: target.pageNum, preferredForward: predictedPageDirection)
} else {
RDEPUBBackgroundTrace.log(
"PageCurl",
"willTransitionTo blank target currentPage=\(currentPage + 1)"
)
}
}
}