feat(epub): align text rendering with WXRead

This commit is contained in:
shen
2026-05-24 09:56:32 +08:00
parent 5125b8de51
commit a318c0e3d0
13 changed files with 1556 additions and 135 deletions
+323
View File
@@ -0,0 +1,323 @@
# WXRead 剩余问题修复计划
> 基于 [架构对比分析_WXRead_vs_ReadViewSDK.md](/Users/shen/Work/Code/ReadViewSDK/Doc/架构对比分析_WXRead_vs_ReadViewSDK.md) 的 2026-05-24 核查结果整理。
> 目标:把当前已完成的 CoreText 页面直绘继续收口到更接近 WXRead 的页面级排版、命中、装饰和位置模型。
---
## 目标概览
当前已经完成的部分:
- 文本页已经切到页面级 CoreText 直绘。
- 分页器已经切到 `RDEPUBTextLayouter + rd_paginatedFrames`
- 4 级语义断页、`avoidPageBreakInside`、分页缓存、5 层 CSS、`<link>` 外部 CSS 内联都已经落地。
当前仍需修复的核心问题:
1. 选区与命中仍依赖 `UITextView` 代理层,没有完全走 CoreText 页面几何。
2. 高亮、下划线、搜索命中仍主要靠 attributedString 属性,不是页面级装饰绘制。
3. `RDEPUBSelectionOverlayView` 还是半成品,未形成可用闭环。
4. inline attachment 虽已大幅收敛,但仍需要对问题书样做专项验书。
5. 位置模型仍是 `href + progression`,不是 WXRead 的字符级锚点。
6. 章节数据模型仍然分散,没有形成 `WRChapterData` 式内聚模型。
---
## 优先级
### P1:当前渲染链必须补齐
- CoreText 原生命中测试与选区模型
- 页面级装饰绘制层
- `RDEPUBSelectionOverlayView` 闭环
- inline attachment 验书与细节修正
### P2:精度与架构内聚
- 字符级位置模型
- 章节数据模型内聚
### P3:外围能力
- 翻页 crash patch
- 多栏
- 字体系统
- TTS / DRM / Pencil 等
---
## Phase 1CoreText 命中与选区收口
### 目标
去掉文本页对 `UITextView` 选区代理的核心依赖,改成和 WXRead 一样基于页面 `layoutFrame` / `line` / `run` 的命中测试与选区计算。
### 范围
- `RDEPUBTextContentView`
- `RDEPUBSelectionOverlayView`
- 新增页面几何辅助对象或工具类型
### 主要工作
1. 基于当前页 `DTCoreTextLayoutFrame` 建立字符命中入口。
2. 实现单点命中:`CGPoint -> character index`
3. 实现拖拽扩选:起点 index、终点 index、range 归一化。
4. 输出选区矩形集合:用于高亮、手柄、菜单定位。
5.`RDEPUBSelectionOverlayView` 直接消费 CoreText 选区矩形,而不是依赖 `UITextView`
6. 保留 `UITextView` 仅作为兜底或临时兼容层,最终目标是让它不再决定正文选区几何。
### 产出
- 页面级命中测试工具
- 页面级选区 range 计算逻辑
- 页面级选区 rect 计算逻辑
- `RDEPUBSelectionOverlayView` 可实际工作
### 验收标准
- 长按正文任意位置,选区起点与落点稳定。
- 拖动选区不会出现明显错位、跳行、截断。
- 脚注图标、inline image、跨行高亮附近仍能稳定选中相邻文字。
- 不再依赖 `UITextView.selectedRange` 作为主选区真值。
### 风险
- DTCoreText 暴露的行/run 几何可能和系统 `UITextView` 行为不完全一致。
- inline attachment 附近的 index 映射需要特别小心。
---
## Phase 2:页面级装饰绘制层
### 目标
把高亮、下划线、搜索命中从 attributedString 注入迁到页面级 CGContext 绘制,和 WXRead 的页面装饰层一致。
### 范围
- `RDEPUBDirectCoreTextPageView`
- `RDEPUBTextContentView`
- 可能新增 `RDEPUBPageDecorationRenderer`
### 主要工作
1. 将高亮、下划线、搜索命中从“内容属性”改成“页面装饰数据”。
2. 基于当前页 range 计算每种装饰的 rect 集合。
3. 在页面 `draw(_:)` 或 overlay 中按层次绘制:
- 搜索命中
- 高亮背景
- 下划线
- 选区高亮
4. 统一颜色、透明度、绘制顺序,避免正文颜色污染。
### 产出
- 页面装饰几何模型
- 页面装饰绘制实现
- attributedString 注入逻辑的瘦身或移除
### 验收标准
- 搜索高亮不再改变底层排版结果。
- 高亮和下划线不再依赖正文属性重排。
- 同一页同时存在搜索命中、标注、选区时,层次稳定、不互相遮挡异常。
### 风险
- 需要处理跨行 range 拆分。
- 需要处理 attachment、段前段后间距、最后一行空白的 rect 裁剪。
---
## Phase 3inline attachment 专项验书与收敛
### 目标
继续把 inline image、脚注图标、特殊图片在排版指标和页面显示上收紧到更接近 WXRead。
### 范围
- `RDEPUBTextRendererSupport.normalizeAttachmentLayoutForWXRead`
- `RDEPUBTextContentView.normalizeInlineAttachments`
- 问题 EPUB 样本专项验证
### 主要工作
1. 建立 attachment 分类表:
- 脚注图标
- 普通 inline image
- block image
- cover image
2. 逐类校正:
- `displaySize`
- `verticalAlignment`
- 基线占位
- 页内/跨页表现
3. 对问题书样做页对页比对,记录剩余差异。
4. 去掉重复、冲突的 attachment 二次归一化逻辑,保证“同一类 attachment 只走一套规则”。
### 产出
- attachment 规则矩阵
- 书样问题清单
- 附件归一化逻辑收口
### 验收标准
- `.qqreader-footnote` 与正文基线对齐稳定。
- 普通内容图片不再出现页内漂移、倒置、重复绘制、页尾大空白。
- 同一 EPUB 在分页和显示阶段不会再出现 attachment 指标不一致。
### 风险
- 不同 EPUB 资源命名习惯不同,分类可能需要结合 class、src、style 多维判断。
---
## Phase 4:字符级位置模型
### 目标
从当前 `href + progression` 提升到更接近 WXRead 的字符级位置锚点,减少重排后的标注漂移。
### 范围
- `RDEPUBLocation`
- `RDEPUBTextBook`
- `RDEPUBHighlight` / `RDEPUBBookmark`
- 选区序列化与恢复
### 主要工作
1. 设计新的文本位置载体:
- 章节索引
- 章节内字符偏移
- 可选 fragment / 行列辅助信息
2. 建立双向转换:
- 页面 → 字符 range
- 字符 range → 页面
3. 保留对旧 `progression` 数据的兼容读取。
4. 更新标注恢复、搜索跳转、书签跳转逻辑。
### 产出
- 新位置模型
- 兼容迁移策略
- 标注恢复精度提升
### 验收标准
- 改字号、改行距后重新分页,已有标注仍能落回正确正文范围。
- 多次翻页、重建 `RDEPUBTextBook` 后,范围恢复稳定。
### 风险
- 旧数据兼容与迁移策略需要谨慎。
- attachment、fragment marker、语义 marker 会影响纯字符 offset 映射。
---
## Phase 5:章节数据模型内聚
### 目标
把分散在 `RDEPUBTextChapter``RDEPUBHighlight`、目录、分页诊断里的数据逐步收敛成更像 `WRChapterData` 的一体化章节模型。
### 范围
- `RDEPUBTextChapter`
- `RDEPUBTextBook`
- 标注、目录、分页诊断承载方式
### 主要工作
1. 定义章节聚合对象,统一承载:
- attributedContent
- page frames / page ranges
- fragment offsets
- highlights / bookmarks
- outline / TOC mapping
- pagination diagnostics
2. 让控制器层从“自己拼数据”改成“消费章节聚合对象”。
3. 为后续位置模型、装饰绘制、选区恢复提供统一数据入口。
### 产出
- 新章节聚合模型
- 控制器简化
- 数据流收口
### 验收标准
- 阅读器控制器中的章节相关派生逻辑明显减少。
- 标注、分页、目录不再分散在多个不一致的数据结构里。
---
## Phase 6:外围能力补齐
### 目标
处理不影响当前正文质量但和 WXRead 存在差距的外围能力。
### 包含项
- `UIPageViewController` crash patch
- 多栏排版
- 字体动态加载
- TTS / DRM / Pencil / 预加载
### 建议
- 这批能力不要和当前正文排版修复混在一个阶段。
- 先把正文页面链路闭环,再独立立项。
---
## 执行顺序建议
1. Phase 1CoreText 命中与选区收口
2. Phase 2:页面级装饰绘制层
3. Phase 3inline attachment 专项验书与收敛
4. Phase 4:字符级位置模型
5. Phase 5:章节数据模型内聚
6. Phase 6:外围能力补齐
原因:
- Phase 1 和 Phase 2 会直接决定“页面几何模型”是否真正闭环。
- Phase 3 需要建立在前两步的页面几何一致性之上,否则 attachment 还会被多套逻辑干扰。
- Phase 4 和 Phase 5 更偏位置与架构内聚,适合在页面几何稳定后推进。
---
## 每阶段验证方式
### 功能验证
- 问题 EPUB 书样页对页比对
- 翻页前后位置恢复
- 高亮、搜索、选区、脚注图标组合场景验证
### 构建验证
- `RDReaderView` scheme 构建
- `ReadViewDemo` scheme 构建
### 回归关注点
- 页尾空白是否回归
- 图片是否重复绘制
- 内容是否倒置
- 搜索高亮是否影响分页
- 标注恢复是否漂移
---
## 建议的文档联动
- 本文档用于排期和实施顺序。
- [架构对比分析_WXRead_vs_ReadViewSDK.md](/Users/shen/Work/Code/ReadViewSDK/Doc/架构对比分析_WXRead_vs_ReadViewSDK.md) 继续作为“差距现状”文档。
- 每完成一个阶段,回写一份“已完成/剩余风险”更新到对比分析文档中。
@@ -0,0 +1,249 @@
# 架构对比分析:微信读书 vs ReadViewSDK
> 基于微信读书 v10.0.3 (Build 79) 逆向工程,对比当前 ReadViewSDK 项目架构差距。
> 分析日期: 2026-05-23
> 当前代码核查日期: 2026-05-24
> 参考文档: `Doc/WXRead/decompiled-doc.md`、`Doc/WXRead/resources-doc.md`、`Doc/WXRead/微信读书EPUB阅读器实现架构.md`
> 标注说明:
> - `✅ 已实现`:当前代码已经按接近 WXRead 的路径落地
> - `⚠️ 有差异/有问题`:已经实现一部分,但仍与 WXRead 有结构差异,或者当前实现仍有已知问题
> - `❌ 未实现`:当前代码中仍缺失
---
## 核心结论
微信读书使用**双渲染引擎架构**Path A: 原生 CoreText / Path B: WebView)。ReadViewSDK 当前也已经是 CoreText 文本页 + WebView 双路径,但文本页仍保留 `UITextView` 作为选区代理层,因此“页面绘制”已接近 WXRead,“选区/装饰/命中测试”仍未完全收口到同一套 CoreText 页面模型。
## 核查摘要
### ✅ 已按 WXRead 路径落地
- 文本页已经改成页面级 CoreText 直绘,不再是单纯 `UITextView` 展示。
- `RDEPUBTextLayouter` 已经接入 `RDEPUBTextBookBuilder` / `RDPlainTextBookBuilder`
- 4 级语义断页、`avoidPageBreakInside` 页尾回退、分页缓存都已经落地。
- 5 层 CSS 级联和 EPUB `<link>` 外部样式表内联都已经落地。
### ❌ 仍未实现
- CoreText 原生 hit test / 选区命中。
- 独立 CGContext 标注绘制层与搜索高亮层。
- WXRead 式字符级位置模型(`fileIndex + row + column`)。
- `WRChapterData` 一体化章节数据模型。
- UIPageViewController crash patch、多栏、字体动态加载、TTS/DRM 等外围能力。
### ⚠️ 已实现但仍有问题/差异
- 当前文本页虽然已直绘,但仍依赖 `UITextView` 代理选区,页面几何模型没有完全统一。
- `RDEPUBSelectionOverlayView` 仍是半成品,尚未形成完整可用的 CoreText 选区/装饰 overlay。
- 高亮、下划线、搜索命中仍主要靠 attributedString 属性注入,而不是 WXRead 那种页面装饰绘制。
- inline attachment 已按 WXRead 路径收敛,但仍需要继续结合问题书样验证特殊图片、脚注图标和页内基线细节。
---
## 1. 渲染路径对比
| 维度 | 微信读书 | ReadViewSDK | 核查 |
|------|---------|-------------|------|
| EPUB 文本渲染 | `WRPageView.drawRect:``CTFrameDraw` 到 CGContext | `RDEPUBTextContentView``RDEPUBDirectCoreTextPageView.draw(_:)` + `DTCoreTextLayoutFrame.draw(in:)` 页面级直绘 | ✅ 已实现 |
| WebView 路径 | WKWebView(公众号/文集文章) | WKWebViewinteractive/fixed-layout EPUB | ✅ 已实现 |
| 文本选区 | `CTLineGetStringIndexForPosition` 坐标级 hit test | 仍主要依赖 `UITextView` 代理选区;`RDEPUBSelectionOverlayView` 仍是半成品 | ⚠️ 有差异/有问题 |
| 标注绘制 | `CTFrame` 层叠加绘制(CGContext) | 高亮/下划线仍主要通过 attributedString 属性注入,不是独立 CGContext 装饰层 | ⚠️ 有差异/有问题 |
| 搜索高亮 | `WRCoreTextLayoutFrame.highlightSearchResults:` 直接绘制 | 仍是 attributedString 注入临时高亮属性 | ⚠️ 有差异/有问题 |
**核查结论:** 这段原分析已经过时。当前文本页的底层排版和绘制已经切到 CoreText 页面直绘,但“命中测试、标注装饰层、搜索高亮层”还没有完全像 WXRead 那样归并到同一套页面级 CoreText 几何模型。
---
## 2. 分页引擎对比
| 维度 | 微信读书 | ReadViewSDK | 核查 |
|------|---------|-------------|------|
| 分页核心 | `WRCoreTextLayouter` + `WRCoreTextLayoutFrame` | `RDEPUBTextLayouter` + `RDEPUBTextLayoutFrame`,并已接入 `RDEPUBTextBookBuilder` / `RDPlainTextBookBuilder` | ✅ 已实现 |
| 断页策略 | 4 级语义断页:语义边界 > 附件边界 > 块边界 > 帧限制 | `rd_paginatedFrames` 已启用 4 级语义断页,并改为与显示层一致的 `DTCoreTextLayoutFrame.visibleStringRange` | ✅ 已实现 |
| 分页配置 | `WRCoreTextLayoutConfig`(列数、栏间距、孤行控制、连字符) | 已有 `RDEPUBTextLayoutConfig`,含 `avoidOrphans`/`avoidWidows`/`avoidPageBreakInsideEnabled`/`imageMaxHeightRatio`,但多栏等能力仍缺 | ⚠️ 有差异/有问题 |
| 缓存 | `WRChapterPageCount.currentCacheKeyWithBookId:` 按排版设置缓存 | 已有 `RDEPUBTextBookCache`,按书籍 + 排版设置缓存每章分页结果 | ✅ 已实现 |
| 跨页避让 | `avoidPageBreakInsideByRemovingLastLinesIfNeeded` — CSS `avoid-page-break-inside` 实现 | 已实现页尾最多回退 3 行的 WXRead 式 `avoidPageBreakInside` 处理 | ✅ 已实现 |
**核查结论:** 这段原判断已经过时。`RDEPUBTextBookBuilder``RDPlainTextBookBuilder` 已经走 `rd_paginatedFrames(size:fragmentOffsets:)`,不再是“能力已写但未接入”的状态。
---
## 3. CSS 处理对比
| 维度 | 微信读书 | ReadViewSDK | 核查 |
|------|---------|-------------|------|
| CSS 级联层级 | 5 级:`default.css < replace.css < dark.css < EPUB 内嵌 < 用户设置` | `RDEPUBTextStyleSheetPackage` 已实际生成 5 层:`default/replace/dark/epub/user`,并分别注入 | ✅ 已实现 |
| EPUB `<link>` CSS | `DTHTMLAttributedStringBuilder` 解析前级联合并 `<link>` 引用的 CSS | 已实现 `<link rel="stylesheet">` 抽取、内联、URL 重写与资源诊断 | ✅ 已实现 |
| 自定义 CSS 属性 | `wr-vertical-center-style`(图片垂直居中)、`weread-page-relate`(跨页关联)、`DTPageBreakInsideAvoid`(断页避让) | 已部分支持:`pageRelate``avoidPageBreakInside`、attachment placement 推断;但并非完整 WeRead 属性集 | ⚠️ 有差异/有问题 |
| CSS 层级模型 | 已定义 `RDEPUBTextStyleSheetPackage`/`RDEPUBTextStyleSheetLayer`(5 种 kind),但未完整使用 | 已实际使用;但和 WXRead 资源体系仍不是同一批 CSS 文件/规则 | ⚠️ 有差异/有问题 |
**核查结论:** “未处理 `<link>` 外部 CSS” 这一条已经不成立;但外部 CSS 即使已被内联,规则兼容度和 WXRead 自带 replace/default 体系仍可能存在差异。
---
## 4. 位置模型对比
| 维度 | 微信读书 | ReadViewSDK |
|------|---------|-------------|
| 位置模型 | `WREpubPositionConverter``(fileIndex, row, column)` 三元组 | `RDEPUBLocation``href + progression` 浮点值 |
| 精度 | 字符级精度 | 章节内比例精度 (0..1) |
| 索引构建 | `initIndices` 预建全书字符索引表 | 无索引,每次实时计算 |
| 双向转换 | `stringRangeFromFileRange:` / `fileIndexForCharacterPosition:` / `localOffsetInFileAtIndex:forGlobalPosition:` | `RDEPUBTextBook.pageNumber(for:)` / `location(forPageNumber:)` |
**影响分析:** progression 是 0..1 浮点值,在跨字号/行距重排后能保持大致位置,但无法精确到字符。微信读书的三元组提供字符级精度,适合精确标注恢复。当前 progression 模式对大部分场景够用,但在密集标注场景下可能出现标注漂移。
**核查:** `❌ 未实现`。当前位置模型仍然不是 WXRead 的字符级三元组。
---
## 5. 章节数据模型对比
| 维度 | 微信读书 | ReadViewSDK |
|------|---------|-------------|
| 核心模型 | `WRChapterData` — 一个对象承载渲染结果 + 标注 + 目录 + 免费试读截断 | `RDEPUBTextChapter` + `RDEPUBHighlight` + `EPUBChapterInfo` 分散在多处 |
| 标注内聚 | `addHighlightInRange:` / `addUnderLineToAttributedString:` 直接在 chapterData 上操作 | 标注在 `RDEPUBReaderController` 层管理,与章节数据分离 |
| 目录生成 | `WRChapterData.generateOutlineContents` — 从渲染结果反向提取目录 | 目录从 NCX/Nav 独立解析,不与渲染数据关联 |
**核查:** `❌ 未实现`。章节数据模型仍未收敛成 WXRead 的 `WRChapterData` 一体化模式。
---
## 6. 翻页控制器对比
| 维度 | 微信读书 | ReadViewSDK |
|------|---------|-------------|
| 翻页动画 | 4 种:curl / slide / fade / none | 4 种:pageCurl / horizontalScroll / verticalScroll / horizontalCoverScroll |
| UIPageViewController 崩溃修复 | 3 个 patch 方法处理已知 Apple bug(导航方向崩溃、子 VC 丢失、快速翻页动画故障) | 无 crash patch |
| 导航方向检测 | `detectNavigationDirectionCrashWithPageViewController:` | 无 |
**核查:** `❌ 未实现`。这一块目前仍没有 WXRead 那类 page controller crash patch。
---
## 7. CSS 资源文件对比
### 微信读书 CSS 文件(`resources/css/`
| 文件 | 职责 | ReadViewSDK 对应 |
|------|------|-----------------|
| `default.css` | 基础 HTML 标签样式(font 18px, line-height 30px | `RDEPUBStyleSheetBuilder` 注入的基础 CSS |
| `replace.css` | EPUB 书版排版(6 级标题、首字下沉、引用、图片居中) | `RDEPUBTextRendererSupport.replaceCSS()`(部分覆盖) |
| `dark.css` | 暗黑主题(纯黑背景 + 灰色文字) | `RDEPUBReaderTheme` 的 CSS 计算属性 |
| `replaceForLatinLanguageBook.css` | 拉丁语言字体 | 无对应 |
| `replaceForMPChapter.css` | 公众号文章专用 | 无对应(非 EPUB 场景) |
**核查:**
- `default.css` / `dark.css` / `replace.css` 思路已落地,但规则集合仍不是 WXRead 原文件的完整镜像,属于 `⚠️ 有差异/有问题`
- `replaceForLatinLanguageBook.css` 仍是 `❌ 未实现`
- `replaceForMPChapter.css` 属于非 EPUB 场景,当前可视为 `❌ 未实现(暂不需要)`
### 微信读书 JS 文件(`resources/js/`
| 文件 | 职责 | ReadViewSDK 对应 |
|------|------|-----------------|
| `weread-highlighter.js` | Rangy 高亮引擎,5 种样式 | `epub-bridge.js` + `RDEPUBWebView+JavaScriptBridge.swift` |
| `rangy-core.js` / `rangy-highlighter.js` / `rangy-textrange.js` | Rangy 选区/高亮库 | 无(CoreText 路径不需要) |
| `Readability.js` | HTML 正文提取 | 无(EPUB spine 直接提供内容) |
| `cssInjector.js` | 动态 CSS 注入/移除 | 无(静态注入) |
| `WeReadApi.js` | JS-Native 桥接 | `epub-bridge.js``window.RDReaderBridge` |
**核查:** 这一节整体仍然成立。WebView 路径没有按 WXRead 的 JS 资源体系一一复刻,属于 `⚠️ 有差异/有问题`,但对纯 EPUB CoreText 路径不是当前主阻塞。
---
## 8. 缺失能力对比
| 能力 | 微信读书 | ReadViewSDK | 核查 | 当前优先级 |
|------|---------|-------------|------|-----------|
| CoreText 直接绘制 | `WRPageView.drawRect:` + `CTFrameDraw` | 已是页面级 CoreText 直绘,但选区/装饰层还未完全 CoreText 化 | ⚠️ 有差异/有问题 | P1 |
| 分页引擎集成 | `WRCoreTextLayouter` 完整集成 | 已集成到 builder | ✅ 已实现 | - |
| CSS `<link>` 处理 | 级联合并外部 CSS | 已处理 | ✅ 已实现 | - |
| 5 层 CSS 级联 | default/replace/dark/epub/user | 已生成并注入 | ✅ 已实现 | - |
| 分页缓存 | `WRChapterPageCount.currentCacheKeyWithBookId:` | 已有磁盘缓存 | ✅ 已实现 | - |
| 字符级位置精度 | `WREpubPositionConverter` | progression 浮点值 | ❌ 未实现 | P2 |
| 字体动态加载 | CDN + `WRFontsManager` | 仅系统字体 | ❌ 未实现 | P1(延迟) |
| 繁简转换 | `WRReaderCht2sManager` | 无 | ❌ 未实现 | P3 |
| TTS 朗读 | wxtts 引擎 + 位置标记 | 无 | ❌ 未实现 | P3 |
| DRM | 逐章加密 + Keychain 密钥 | 无 | ❌ 未实现 | P3 |
| 预加载 | `WRForecastUtils` 预测 + 后台下载 | 无 | ❌ 未实现 | P3 |
| Apple Pencil | PencilKit + COS 云同步 | 无 | ❌ 未实现 | P3 |
| 多栏排版 | `WRCoreTextLayoutConfig.columns/columnGap` | 无 | ❌ 未实现 | P3 |
---
## 9. 优先级排序与 Roadmap 映射
| 优先级 | 问题 | 核查 | 对应 Phase / 建议 | 说明 |
|--------|------|------|-------------------|------|
| ~~P0~~ | 集成 `RDEPUBTextLayouter``RDEPUBTextBookBuilder` | ✅ 已完成 | 已落地 | 不再是待办 |
| ~~P0~~ | CSS `<link>` 外部样式表处理 | ✅ 已完成 | 已落地 | 不再是待办 |
| ~~P0~~ | 5 层 CSS 级联 | ✅ 已完成 | 已落地 | 不再是待办 |
| ~~P0~~ | 分页缓存 | ✅ 已完成 | 已落地 | 不再是待办 |
| **P1** | CoreText 原生选区 / hit test | ❌ 未实现 | 新增 phase | 当前仍主要依赖 `UITextView` |
| **P1** | 标注/搜索独立 CGContext 装饰层 | ❌ 未实现 | 新增 phase | 当前仍用 attributedString 属性注入 |
| **P1** | 页面几何与选区 overlay 收口 | ⚠️ 半成品 | 延续 page-geometry phase | `RDEPUBSelectionOverlayView` 仍未闭环 |
| **P1** | inline attachment 细节对齐 | ⚠️ 已接近但仍需验书 | 延续 pagination/rendering phase | 尤其脚注图标、特殊 inline image |
| **P1** | 字体系统 | ❌ 未实现 | 未来版本 | 内嵌固定字体集,延迟实现 |
| **P2** | 位置精度提升 | ❌ 未实现 | 独立重构 | 字符级锚点 / 双向转换 |
| **P2** | 章节数据模型内聚 | ❌ 未实现 | 独立重构 | WRChapterData 模式 |
| **P3** | TTS / DRM / Pencil / 多栏 | ❌ 未实现 | 独立功能模块 | 后续迭代 |
---
## 10. 微信读书关键类职责速查
| 类名 | 职责 | ReadViewSDK 对应 | 核查 |
|------|------|-----------------|------|
| `WRReaderViewController` | 阅读器主控制器(431 方法) | `RDEPUBReaderController` | ✅ 已有对应 |
| `WRPageViewController` | 翻页控制器(含 3 个 crash patch | `RDReaderView`pageCurl 模式) | ⚠️ 有差异/无 crash patch |
| `WRPageView` | CoreText 直接绘制页面 | `RDEPUBTextContentView` + `RDEPUBDirectCoreTextPageView` | ✅ 已实现 |
| `WREpubParser` | EPUB 解析 | `RDEPUBParser` | ✅ 已有对应 |
| `WREpubTypesetter` | HTML → NSAttributedStringCSS 级联) | `RDEPUBDTCoreTextRenderer` | ✅ 已有对应 |
| `WRCoreTextLayouter` | CoreText 排版引擎 | `RDEPUBTextLayouter` | ✅ 已实现 |
| `WRCoreTextLayoutFrame` | 排版帧(绘制/选区/搜索/装饰) | `RDEPUBTextLayoutFrame` | ⚠️ 绘制/分页接近,选区/装饰未闭环 |
| `WRChapterData` | 章节数据模型(渲染+标注+目录一体) | `RDEPUBTextChapter` + `RDEPUBHighlight`(分散) | ❌ 未实现 |
| `WRChapterPageCount` | 分页计算器(含缓存 key) | `RDEPUBTextBookBuilder` + `RDEPUBTextBookCache` | ✅ 已实现 |
| `WREpubPositionConverter` | 字符级位置双向转换 | `RDEPUBTextBook.pageNumber(for:)`(精度较低) | ❌ 未实现 |
| `WRBookmark` | 5 种标注类型统一模型 | `RDEPUBHighlight` + `RDEPUBBookmark` | ⚠️ 部分对应 |
| `DTHTMLAttributedStringBuilder` | HTML DOM → NSAttributedString | 同(复用 DTCoreText | ✅ 已实现 |
---
## 数据流对比
### 微信读书
```
EPUB 文件
→ WREpubParser.parse (container.xml → OPF → spine)
→ WREpubTypesetter (CSS 级联: default < replace < dark < epub < user)
→ DTHTMLAttributedStringBuilder (HTML → NSAttributedString)
→ WRCoreTextLayouter (CTFramesetter → CTFrame)
→ WRChapterPageCount (分页 NSRange)
→ WRPageView.drawRect (CTFrameDraw → CGContext)
→ 屏幕显示
```
### ReadViewSDK 当前(已按当前代码修正)
```
EPUB 文件
→ RDEPUBParser.parse (container.xml → OPF → spine)
→ readingProfile 分流:
textReflowable:
→ RDEPUBDTCoreTextRenderer (DTHTMLAttributedStringBuilder + 5 层 CSS + <link> CSS 内联)
→ RDEPUBTextBookBuilder (rd_paginatedFrames + RDEPUBTextBookCache)
→ RDEPUBTextContentView (页面级 CoreText 直绘 + UITextView 选区代理)
webInteractive:
→ RDEPUBPaginator (离屏 WKWebView 分页)
→ RDEPUBWebContentView (WKWebView 渲染)
webFixedLayout:
→ RDEPUBWebContentView (WKWebView + fixed-layout template)
```
---
*分析基础:微信读书 v10.0.3 (Build 79) 逆向工程文档*
*产出:10 个维度对比、14 项差距识别、优先级排序*