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
co-authored by Claude
parent 8c5059e72f
commit 15b15d0e11
23 changed files with 95 additions and 492 deletions
@@ -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"
}
}
}
@@ -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
}
@@ -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
@@ -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
}
}
}