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
@@ -104,7 +104,7 @@ final class ChapterPaginationArchive: NSObject, NSSecureCoding {
public final class RDEPUBTextBookCache {
public var schemaVersion: Int = 13
public var schemaVersion: Int = 14
private let queue = DispatchQueue(label: "com.rdreader.textbookcache", qos: .utility)
@@ -27,6 +27,7 @@ struct RDEPUBHTMLNormalizer: RDEPUBTypesettingStage {
}
cleanedHTML = normalizeAttachmentHTMLMarkers(in: cleanedHTML)
cleanedHTML = normalizeBodyLeadingSpacing(in: cleanedHTML)
return cleanedHTML
}
@@ -129,6 +130,64 @@ struct RDEPUBHTMLNormalizer: RDEPUBTypesettingStage {
return normalized
}
private static func normalizeBodyLeadingSpacing(in html: String) -> String {
var normalized = html
if let bodyStartRegex = try? NSRegularExpression(
pattern: #"(<body\b[^>]*>)\s+"#,
options: [.caseInsensitive]
) {
normalized = bodyStartRegex.stringByReplacingMatches(
in: normalized,
options: [],
range: NSRange(location: 0, length: (normalized as NSString).length),
withTemplate: "$1"
)
}
if let bodyEndRegex = try? NSRegularExpression(
pattern: #"\s+(</body>)"#,
options: [.caseInsensitive]
) {
normalized = bodyEndRegex.stringByReplacingMatches(
in: normalized,
options: [],
range: NSRange(location: 0, length: (normalized as NSString).length),
withTemplate: "$1"
)
}
guard let firstBlockRegex = try? NSRegularExpression(
pattern: #"(<body\b[^>]*>)(\s*)(<(?<tag>h[1-6]|p|div|blockquote|section|article|ul|ol)\b[^>]*>)"#,
options: [.caseInsensitive]
) else {
return normalized
}
let nsNormalized = normalized as NSString
let fullRange = NSRange(location: 0, length: nsNormalized.length)
guard let match = firstBlockRegex.firstMatch(in: normalized, options: [], range: fullRange),
match.numberOfRanges >= 4,
let bodyRange = Range(match.range(at: 1), in: normalized),
let blockRange = Range(match.range(at: 3), in: normalized) else {
return normalized
}
let prefix = String(normalized[..<bodyRange.lowerBound])
let bodyTag = String(normalized[bodyRange])
let blockTag = String(normalized[blockRange])
let normalizedBlockTag = mergeHTMLAttributes(
into: blockTag,
requiredClass: nil,
styleFragments: [
"margin-top:0 !important",
"-webkit-margin-before:0 !important",
"padding-top:0 !important"
]
)
return prefix + bodyTag + normalizedBlockTag + String(normalized[blockRange.upperBound...])
}
static func replaceMatches(
using regex: NSRegularExpression,
in source: String,