feat: chapter runtime refactoring and related updates

- Refactor chapter runtime: replace window coordinator/snapshot with warmup orchestrator
- Update EPUB core: parser, reading session, JS bridge, navigator layout
- Update reader controller: data source, location resolution, persistence
- Update chapter runtime: data cache, loader, runtime store, disk cache, warmup orchestrator
- Remove deprecated navigation state machine and pagination state
- Update text rendering: book cache, HTML normalizer
- Update UI: text content view, dark image adjuster, text selection controller
- Update settings and reader configuration
- Add CODE_REVIEW.md and AUDIT_FINAL.md documentation
- Update pod dependencies (remove SSAlertSwift, SnapKit)
- Update podspec and pod configuration files

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
shenlei
2026-06-26 18:50:07 +09:00
co-authored by Claude
parent b8aa10c535
commit 22e7e44220
123 changed files with 3701 additions and 9118 deletions
@@ -63,6 +63,7 @@ final class RDEPUBBackgroundPriorityManager {
private(set) var policy: RDEPUBBackgroundPriorityPolicy
private var warmAnchors: [RDEPUBWarmJumpAnchor] = []
private let warmAnchorsLock = NSLock()
private(set) var currentGeneration: Int = 0
@@ -84,11 +85,13 @@ final class RDEPUBBackgroundPriorityManager {
sequenceNumber: currentGeneration
)
warmAnchorsLock.lock()
warmAnchors.insert(anchor, at: 0)
if warmAnchors.count > policy.maxWarmJumpAnchors {
warmAnchors = Array(warmAnchors.prefix(policy.maxWarmJumpAnchors))
}
warmAnchorsLock.unlock()
currentGeneration += 1
coldCursor = 0
@@ -103,10 +106,17 @@ final class RDEPUBBackgroundPriorityManager {
let uncachedIndices = allBuildableIndices.filter { !cachedSpineIndices.contains($0) }
guard !uncachedIndices.isEmpty else { return [] }
// M-03: Snapshot warmAnchors under lock since it's written on main thread
// and read on background thread.
warmAnchorsLock.lock()
let warmAnchorsSnapshot = warmAnchors
warmAnchorsLock.unlock()
let items = uncachedIndices.map { spineIndex -> (spineIndex: Int, band: RDEPUBPriorityBand) in
let band = classifySpineIndex(
spineIndex: spineIndex,
currentSpineIndex: currentSpineIndex
currentSpineIndex: currentSpineIndex,
warmAnchors: warmAnchorsSnapshot
)
return (spineIndex, band)
}
@@ -131,7 +141,8 @@ final class RDEPUBBackgroundPriorityManager {
private func classifySpineIndex(
spineIndex: Int,
currentSpineIndex: Int?
currentSpineIndex: Int?,
warmAnchors: [RDEPUBWarmJumpAnchor]
) -> RDEPUBPriorityBand {
if let current = currentSpineIndex {
@@ -152,11 +163,15 @@ final class RDEPUBBackgroundPriorityManager {
}
func currentWarmAnchors() -> [RDEPUBWarmJumpAnchor] {
warmAnchors
warmAnchorsLock.lock()
defer { warmAnchorsLock.unlock() }
return warmAnchors
}
func reset() {
warmAnchorsLock.lock()
warmAnchors.removeAll()
warmAnchorsLock.unlock()
currentGeneration = 0
coldCursor = 0
}