Code Review :代码审查 + 产物体积 −12.2%(890,880 → 782,336 B)+ 面板结构收敛 + 离屏验证工具入库 #3
No files matched your search
@@ -236,3 +236,38 @@
|
||||
`__USE_MINGW_ANSI_STDIO=1`,命令行关不掉 —— 见 Makefile 注释)。
|
||||
4. **改面板几何/绘制前后必须跑** `OffscreenChecks -run panels -mode record/compare`;
|
||||
本轮它当场抓到了"截取面板少了 37px 高度"的回归。
|
||||
|
||||
---
|
||||
|
||||
## 八、第 36 轮追加(2026-11-04):§12.7 两项建议的落地
|
||||
|
||||
> 触发:用户要求「继续按照上轮报告的后续建议推进」。§12.7 列了两项:
|
||||
> ① `EdgePanelLayout` 平行数组合并;② `PaintEdgeCursor` 拆分。
|
||||
|
||||
| 节点 | 内容 | 结论 |
|
||||
| --- | --- | --- |
|
||||
| **P26** | 拆分 `PaintEdgeCursor` 三段内容绘制 | ✅ 完成(新建 `PlotViewPanelPaint.cpp`) |
|
||||
| **P27** | 平行数组错位隐患 | ✅ 用 `AppendRow()` 唯一入口消除(**未做**完整结构合并,理由见下) |
|
||||
| **P28** | 收紧不变式 | ✅ 18 个数组**全部**必须等于行数(不再允许"重采样专属列可为空") |
|
||||
|
||||
### 8.1 本轮新增硬约束
|
||||
|
||||
1. **新增一种面板行,只能走 `EdgePanelLayout::AppendRow(...)`**。
|
||||
18 个平行数组由它一次补齐;参数行 / 重采样行一律 `rowXxx.back() = …` **赋值**。
|
||||
**禁止**在任何布局分支里手写 `rowXxx.push_back(...)`。
|
||||
2. **面板内容绘制按排版类别分文件**:骨架(边框/标题栏/✕/按钮)在 `PlotViewPaint.cpp`,
|
||||
内容在 `PlotViewPanelPaint.cpp`。新增一种面板 = 加一个 `PanelStyleOf` 分支 +
|
||||
在对应内容函数里加一支。
|
||||
3. **`OffscreenChecks -run panels` 的长度不变式现在是"全等"判定**:
|
||||
任何一列短于行数即失败(这条检查是"绕过 `AppendRow`"的唯一探测器)。
|
||||
|
||||
### 8.2 为什么没有做「完整合并成 `std::vector<PanelRow>` + 列视图」
|
||||
|
||||
技术上可行(`PanelColumn<T>` 持有 `std::vector<PanelRow>*` + 成员指针,
|
||||
读点只需在 `layout.rowXxx` 后加一对括号),但 **`EdgePanelLayout` 需要自定义拷贝构造/赋值**
|
||||
来重新绑定视图;而它是 `EdgePanelLayoutFor()` 的返回值、又被存进 `std::vector`,
|
||||
拷贝是热路径 —— 拷贝语义一旦写错,会产生**比原缺陷更隐蔽的悬垂视图**(原缺陷至少会被
|
||||
长度不变式抓到,悬垂指针不会)。
|
||||
|
||||
本轮先用 `AppendRow()` 把**真实隐患**("某分支漏推一列")消除,
|
||||
完整结构合并留待"逐行几何基线"检查就绪后再做。
|
||||
@@ -347,3 +347,66 @@ Makefile 按目录通配收集源文件,**无需登记新文件**。
|
||||
**本轮未做**:与 P22 抢时间,且属纯可读性收益。
|
||||
3. **给平行数组补检查**:在 `panels` 里增加"每个 row 的 17 项长度一致"断言
|
||||
(成本极低,可作为第 1 项的前置护栏)—— 已记入待办。
|
||||
|
||||
---
|
||||
|
||||
## 第 36 轮(2026-11-04):§12.7 两项建议落地
|
||||
|
||||
### P26 拆分 `PaintEdgeCursor` —— ✅ 完成(提交 `38fbd4b`)
|
||||
|
||||
* 新增 `Components/PlotView/Src/PlotViewPanelPaint.cpp`(1016 行,**机械搬移、零逻辑改动**):
|
||||
* `PaintPanelCountTableRows` —— 边沿计数表格(固定表头 + 可滚动行);
|
||||
* `PaintPanelListRows` —— 列表式(均值/中心轴/弱峰/重采样/截取)条目栏 + 参数行;
|
||||
* `PaintPanelMarkerGroups` —— 自由标记(分组栏 + 表头 + 条目 + 吸顶)。
|
||||
每个函数只接收它真正需要的参数(`layout` / `tabLane` / `kind` / `laneIndex`),
|
||||
不再"整个函数都看得见"。
|
||||
* `PlotViewPaint.cpp`:6554 → 5575 行(`PaintEdgeCursor` 由约 1900 行降到约 900 行);
|
||||
三处块替换为一行调用,骨架(边框/标题栏/折起三角/GX 徽标/✕)与底部按钮仍在一处。
|
||||
* 滚动条绘制抽为 `pvdetail::PaintPanelScrollBar(g, layout, theme)`。
|
||||
* **顺带补上第 35 轮承诺未落地的一处**:`PaintEdgeCursor` 的标题仍是 7 层三元式
|
||||
(与 `EdgePanelWidth` 里另一条链并存,后者漏了 MARK/CLIP)⇒ 统一为 `PanelTitle(kind)`。
|
||||
|
||||
**过程中"机械搬移"踩到的三个真实问题**(都已修)
|
||||
1. 提取块里引用的 `paintCounts` / `paintPanelScrollBar` 是**局部 lambda** ⇒
|
||||
前者改为新函数内的局部 lambda(只服务于该段)、后者提升为 pvdetail 内联函数。
|
||||
2. 「标记透明度」滑块用到的 `panel` / `pad` 是外层局部变量 ⇒ 改为从 `layout.panel` 派生。
|
||||
3. `tabLanes` 在 marker 段里是**被写**的(回写各列实测宽度)⇒ 参数必须非 const。
|
||||
|
||||
### P27 平行数组错位隐患 —— ✅ 用 `AppendRow()` 消除(提交 `85aaed5`)
|
||||
|
||||
审计发现 `EdgePanelLayout` 每行对应 **18 个平行 vector**,而**四个**布局分支各自手写 push:
|
||||
* 边沿计数表格:13 次 push;
|
||||
* 列表式基行:13 次 push;
|
||||
* 「未勾选/收起」分支:又补 6(+重采样 4)次空 push;
|
||||
* 「重采样展开」/「普通展开」分支:各自再 push 6(+4)次。
|
||||
任何一处漏推 ⇒ 该列之后所有行读到**别人的**矩形。
|
||||
|
||||
改法:
|
||||
* 新增 `EdgePanelLayout::AppendRow(ref, header, nameRect, triangle, check)` —— **唯一入口**,
|
||||
18 个数组一次补齐(其余列为空矩形)。
|
||||
* 三个 push 块 → 各 **1 次 `AppendRow`**;参数行/重采样行改为 `rowXxx.back() = …` **赋值**;
|
||||
「未勾选/收起」分支的 6+4 次补空 push **整段删除**(AppendRow 已补过)。
|
||||
* ⇒ "新增一列"只需改 `AppendRow` 一处;"新增一行"必须走它(结构上不会漏列)。
|
||||
|
||||
⚠️ **没做完整结构合并**(`std::vector<PanelRow>` + 列视图),理由:
|
||||
列视图需要 `EdgePanelLayout` 自定义拷贝构造/赋值来重绑视图,而该类型是
|
||||
`EdgePanelLayoutFor()` 的返回值、又被存进 `std::vector` —— 拷贝是热路径,
|
||||
拷贝语义写错会产生**比原缺陷更隐蔽的悬垂视图**(原缺陷至少会被长度不变式抓到)。
|
||||
先消除真实隐患,结构合并留待"逐行几何基线"检查就绪。
|
||||
|
||||
### P28 收紧不变式
|
||||
|
||||
`panels` / `panelscroll` 里的长度检查从"13 个必须等长 + 4 个可空"改为
|
||||
**18 个全部必须等于行数** —— `AppendRow()` 成为唯一入口后,"某列短了"
|
||||
就是"有人绕过它手写 push"的直接证据。
|
||||
|
||||
### 本轮验证
|
||||
|
||||
| 项 | 结果 |
|
||||
| --- | --- |
|
||||
| `make release`(全量) | 零 error / 零 warning;产物 786,432 → **785,408 B** |
|
||||
| `make -C Tools` | 零 error / 零 warning |
|
||||
| `UnitTests` | `checks=260 failed=0 cases=19` |
|
||||
| `OffscreenChecks -all` | 6/6 PASS,`checks=101 failed=0`(断言合并后略减) |
|
||||
| `panels -mode compare` | 7 个面板像素哈希 + 几何**逐项不变**(两次重构全程守住) |
|
||||
| `panelscroll`(MF4,566 行) | 18 个行数组长度全部 = 566,行为不变 |
|
||||
@@ -480,3 +480,78 @@ Tools/README.md 目录结构、作用、测试项、验收标准、A/B
|
||||
机械提取为 3 个成员函数,判据 = `panels -mode compare` 全绿。
|
||||
3. **`EdgeScanFor` 状态查找**:维持线性扫描(第 34 轮实测 198 状态 0.097 µs/次,
|
||||
哈希化需 +5,632 B,不划算)。
|
||||
|
||||
---
|
||||
|
||||
## 13. 第 36 轮(2026-11-04):§12.7 两项建议的落地结果
|
||||
|
||||
> 计划 `Code_Review_Plan.md` §八,逐节点 `Code_Review_Progress.md` 第 36 轮。
|
||||
|
||||
### 13.1 一句话结论
|
||||
|
||||
§12.7 的两项都做完了,并且**都用像素基线证明是纯结构改动**:
|
||||
`PaintEdgeCursor` 从约 1900 行降到约 900 行(内容绘制拆到 `PlotViewPanelPaint.cpp` 1016 行),
|
||||
平行数组的"漏推一列"隐患用 `AppendRow()` 唯一入口消除。
|
||||
产物 786,432 → **785,408 B**(−1,024),7 个面板的像素哈希与几何**逐项不变**。
|
||||
|
||||
| §12.7 建议 | 结果 |
|
||||
| --- | --- |
|
||||
| 1. `EdgePanelLayout` 平行数组隐患 | ✅ 用 `AppendRow()` 消除真实隐患;**完整结构合并**按其风险(悬垂视图)暂不做,理由见 §13.3 |
|
||||
| 2. 拆分 `PaintEdgeCursor` | ✅ 完成,新建 `PlotViewPanelPaint.cpp` |
|
||||
|
||||
### 13.2 拆分后的文件职责
|
||||
|
||||
| 文件 | 行数 | 职责 |
|
||||
| --- | --- | --- |
|
||||
| `PlotViewPaint.cpp` | 5575 | 面板**骨架**(边框 / 标题栏 / 折起三角 / GX 徽标 / ✕)+ 底部按钮 + 其余全部绘制 |
|
||||
| `PlotViewPanelPaint.cpp` | 1016 | 面板**内容**:`PaintPanelCountTableRows` / `PaintPanelListRows` / `PaintPanelMarkerGroups` |
|
||||
|
||||
⚠️ 骨架与内容的划分依据:**对所有面板都是同一份**的留在骨架;
|
||||
**按排版类别不同**的进内容函数。新增一种面板 = `PanelStyleOf` 加一支 +
|
||||
在对应内容函数里加一支(不会碰到骨架)。
|
||||
|
||||
### 13.3 为什么没做"完整合并成 `std::vector<PanelRow>`"
|
||||
|
||||
技术上可行:`PanelColumn<T>` 持有 `std::vector<PanelRow>*` + 成员指针,
|
||||
读点只需 `layout.rowXxx` → `layout.rowXxx()`(纯正则,314 处可信)。
|
||||
|
||||
**但**:`EdgePanelLayout` 必须自定义拷贝构造 / 拷贝赋值来重绑视图,
|
||||
而它是 `EdgePanelLayoutFor()` 的返回值、又被存进 `std::vector<EdgePanelLayout>` ——
|
||||
拷贝在热路径上。视图一旦在拷贝后忘记重绑,行为是**悬垂指针**:
|
||||
可能读出垃圾矩形、也可能"看起来正常"直到某次重排才崩。
|
||||
|
||||
对比两个方案的**失败可见性**:
|
||||
* 现在的平行数组 + `AppendRow()`:漏一列 ⇒ **长度不变式当场报错**;
|
||||
* 列视图:忘了重绑 ⇒ **没有检查能抓到**。
|
||||
|
||||
因此本轮只做"消除真实隐患"(`AppendRow`),完整合并推迟到
|
||||
"逐行几何基线"(把每行 18 个矩形都写进基线文件、逐项比对)就绪之后。
|
||||
|
||||
### 13.4 本轮"机械搬移"踩到的三个真问题(值得记住)
|
||||
|
||||
1. **局部 lambda 无法跨函数复用**:`paintCounts` 只服务列表段 ⇒ 下沉为该函数的局部 lambda;
|
||||
`paintPanelScrollBar` 服务三段 ⇒ 提升为 `pvdetail::PaintPanelScrollBar` 内联函数
|
||||
(参数显式化,不再隐式捕获 `m_theme`)。
|
||||
2. **提取块依赖外层局部变量**:「标记透明度」滑块用 `panel` / `pad` ⇒ 改为从 `layout.panel` 派生。
|
||||
这类隐式依赖正是"整个函数都看得见"的害处,提取时必须逐个查。
|
||||
3. **const 正确性**:`tabLanes` 在 marker 段里是**被写**的(回写各列实测宽度)⇒
|
||||
参数不能是 `const std::vector<Lane>&`。提取时"看起来很只读"的参数要核对写入点。
|
||||
|
||||
### 13.5 验证与现状
|
||||
|
||||
| 项 | 结果 |
|
||||
| --- | --- |
|
||||
| `make release`(全量) | 零 error / 零 warning;**785,408 B**(距 1 MB 预警线 ≈260 KB) |
|
||||
| `UnitTests` | `checks=260 failed=0 cases=19` |
|
||||
| `OffscreenChecks -all` | 6/6 PASS,`checks=101 failed=0` |
|
||||
| `panels -mode compare` | 7 个面板像素哈希 + 几何逐项不变 |
|
||||
| `panelscroll`(566 行) | 18 个行数组全部等于 566 |
|
||||
|
||||
### 13.6 后续建议(更新)
|
||||
|
||||
1. **逐行几何基线**:把每行 18 个矩形写进 `Temp/tools/rows-baseline.txt`,逐项比对。
|
||||
这是"完整结构合并"与"重写布局算式"的前置护栏,成本低(导出 + 字符串比对)。
|
||||
2. **`rowPoints` / `rowIterations` 已无绘制方使用**(旧式输入框排版已删除):
|
||||
可在 `AppendRow` 里保留但标注"仅为兼容保留",或在下一轮与文档一起清掉。
|
||||
3. **`PaintPanelListRows` 仍约 470 行**:可再按"条目栏 / 参数行 / 重采样行"拆三段,
|
||||
但当前已不在"改一次就出错"的路径上,优先级低于第 1 项。
|
||||
@@ -10499,3 +10499,68 @@ release/debug **零警告**;Release `TargetCheck.exe` **890,880 B**(< 1 MB
|
||||
是"改布局就出错"的最后一块机制隐患;已先用长度检查兜住。
|
||||
* `PaintEdgeCursor`(约 1600 行)把三段内容绘制机械提取为 3 个成员函数,
|
||||
判据 = `panels -mode compare` 全绿。
|
||||
|
||||
---
|
||||
|
||||
## 2026-11-04 · 第 36 轮(`Code_Review` 分支):§12.7 两项建议落地
|
||||
|
||||
> 提交:`38fbd4b`(拆分 PaintEdgeCursor)、`85aaed5`(AppendRow 唯一入口)、本提交(不变式收紧+文档)。
|
||||
> 规则原文:`Documents/agent_mem.md` 第 36 轮、`Code_Review_Report.md` §13。
|
||||
|
||||
### 1. ✅ `PaintEdgeCursor` 已拆分(1900 → 约 900 行)
|
||||
|
||||
| 文件 | 行数 | 职责 |
|
||||
| --- | --- | --- |
|
||||
| `PlotViewPaint.cpp` | 5575 | 面板**骨架**(边框/标题栏/折起三角/GX 徽标/✕)+ 底部按钮 + 其余绘制 |
|
||||
| `PlotViewPanelPaint.cpp` | 1016 | 面板**内容**:`PaintPanelCountTableRows` / `PaintPanelListRows` / `PaintPanelMarkerGroups` |
|
||||
|
||||
划分依据:**对所有面板都是同一份**的留骨架;**按排版类别不同**的进内容函数。
|
||||
新增一种面板 = `PanelStyleOf` 加一支 + 对应内容函数加一支(不碰骨架)。
|
||||
滚动条外观统一为 `pvdetail::PaintPanelScrollBar(g, layout, theme)`。
|
||||
|
||||
### 2. ✅ 平行数组错位隐患用 `AppendRow()` 消除
|
||||
|
||||
**新硬规则**:新增面板行**只能**走 `EdgePanelLayout::AppendRow(ref, header, nameRect, triangle, check)`
|
||||
(18 个平行数组一次补齐);参数行 / 重采样行一律 `rowXxx.back() = …` **赋值**。
|
||||
**禁止**在任何布局分支里手写 `rowXxx.push_back(...)`。
|
||||
⇒ "新增一列"只需改 `AppendRow` 一处;"新增一行"必须走它(结构上不会漏列)。
|
||||
|
||||
改前有 **4 个**地方各自手写 push(表格 13 次 / 列表基行 13 次 / 未勾选分支 6+4 次空 push /
|
||||
展开分支 6+4 次),任何一处漏推都会让该列之后的所有行读到别人的矩形。
|
||||
|
||||
### 3. ⚠️ 为什么**不**把平行数组合并成 `std::vector<PanelRow>` + 列视图
|
||||
|
||||
技术上可行(读点只需正则加括号),但 `EdgePanelLayout` 必须自定义拷贝构造/赋值来重绑视图,
|
||||
而它是 `EdgePanelLayoutFor()` 的返回值、又被存进 `std::vector` —— 拷贝是热路径。
|
||||
**失败可见性对比**:
|
||||
* 现在(平行数组 + AppendRow):漏一列 ⇒ **长度不变式当场报错**;
|
||||
* 列视图:忘了重绑 ⇒ **悬垂指针,没有检查能抓到**。
|
||||
⇒ 先消除真实隐患,完整合并推迟到"逐行几何基线"就绪后。
|
||||
|
||||
### 4. ✅ 不变式收紧为"全等"
|
||||
|
||||
`panels` / `panelscroll` 的长度检查从"13 个等长 + 4 个可空"改为
|
||||
**18 个全部必须等于行数** —— `AppendRow()` 成为唯一入口后,
|
||||
"某列短了"就是"有人绕过它"的直接证据。
|
||||
|
||||
### 5. ⚠️ 机械搬移踩到的三个真问题(提取代码时必查)
|
||||
|
||||
1. **局部 lambda 不能跨函数复用**:只服务一段的下沉为该函数局部;多段共用的提升为
|
||||
pvdetail 内联函数(参数显式化)。
|
||||
2. **提取块会隐式依赖外层局部变量**(如「标记透明度」滑块的 `panel` / `pad`)⇒
|
||||
改为从 `layout` 派生。这是"整个函数都看得见"的害处。
|
||||
3. **const 正确性**:`tabLanes` 在 marker 段里是**被写**的(回写各列实测宽度)⇒
|
||||
"看起来只读"的参数要核对写入点。
|
||||
|
||||
### 6. 本轮数字
|
||||
|
||||
* Release **785,408 B**(786,432 → −1,024);零 warning。
|
||||
* `UnitTests` 260 断言 / 19 用例;`OffscreenChecks -all` 6 检查 / 101 断言;全部 PASS。
|
||||
* `panels -mode compare` 7 个面板像素哈希 + 几何**逐项不变**(两次重构全程守住)。
|
||||
* `panelscroll`(MF4 566 行)18 个行数组全部 = 566。
|
||||
|
||||
### 7. 遗留(下一步候选)
|
||||
|
||||
* **逐行几何基线**(导出每行 18 个矩形做逐项比对)—— 完整结构合并与布局算式重写的前置护栏。
|
||||
* `rowPoints` / `rowIterations` 已无绘制方使用(旧式输入框排版早已删除),可标注/清理。
|
||||
* `PaintPanelListRows` 仍约 470 行,可再拆三段,但已不在"改一次就出错"的路径上。
|
||||
@@ -418,22 +418,23 @@ namespace jdi
|
||||
Expect(inside, std::string("panel inside plot area: ") + PanelKindName(kind));
|
||||
|
||||
// 不变式:`EdgePanelLayout` 的**平行数组长度必须全部等于行数**。
|
||||
// 这 13 个按行平行的 vector 每个分支都要按同一顺序 push 恰好 13 项,
|
||||
// 漏一项就会让某一列读到别的行的矩形("改布局就出错"的典型机制)。
|
||||
// ⚠️ 「重采样」专属的 4 个数组(最大/最小间隔、间隔/频率输入框)在**其它**
|
||||
// 面板里允许为空(没人读),但只要非空就必须同样与行数对齐。
|
||||
// 这 18 个按行平行的 vector 现在由 `AppendRow()` 一次补齐
|
||||
//(新增行的唯一入口),因此**不允许**任何一列短于行数 ——
|
||||
// 短了就说明有分支绕过 `AppendRow` 手写 push("某列读到别人矩形"的根因)。
|
||||
// 成本极低(O(1) 比长度),但能挡住整类错位缺陷。
|
||||
const std::size_t rowCount = layout.rowRefs.size();
|
||||
const std::size_t coreSizes[] = {
|
||||
const std::size_t parallelSizes[] = {
|
||||
layout.rowRefs.size(), layout.rowHeaders.size(),
|
||||
layout.rowNameRects.size(), layout.rowTriangles.size(),
|
||||
layout.rowChecks.size(), layout.rowPoints.size(),
|
||||
layout.rowIterations.size(), layout.rowStats.size(),
|
||||
layout.rowLevelTracks.size(), layout.rowLevelValues.size(),
|
||||
layout.rowLevelResets.size(), layout.rowIterTracks.size(),
|
||||
layout.rowIterValues.size(), layout.rowIterResets.size()};
|
||||
layout.rowIterValues.size(), layout.rowIterResets.size(),
|
||||
layout.rowInfoMaxInterval.size(), layout.rowInfoMinInterval.size(),
|
||||
layout.rowIntervalField.size(), layout.rowFrequencyField.size()};
|
||||
bool parallel = true;
|
||||
for (const std::size_t size : coreSizes)
|
||||
for (const std::size_t size : parallelSizes)
|
||||
{
|
||||
if (size != rowCount)
|
||||
{
|
||||
@@ -441,19 +442,7 @@ namespace jdi
|
||||
break;
|
||||
}
|
||||
}
|
||||
const std::size_t resampleSizes[] = {
|
||||
layout.rowInfoMaxInterval.size(), layout.rowInfoMinInterval.size(),
|
||||
layout.rowIntervalField.size(), layout.rowFrequencyField.size()};
|
||||
bool resampleParallel = true;
|
||||
for (const std::size_t size : resampleSizes)
|
||||
{
|
||||
if (size != 0 && size != rowCount)
|
||||
{
|
||||
resampleParallel = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!parallel || !resampleParallel)
|
||||
if (!parallel)
|
||||
{
|
||||
EmitLine("[panels] %s row arrays: refs=%d hdr=%d name=%d tri=%d chk=%d pts=%d it=%d "
|
||||
"stat=%d lvl=%d/%d/%d iter=%d/%d/%d info=%d/%d fld=%d/%d\n",
|
||||
@@ -476,9 +465,7 @@ namespace jdi
|
||||
static_cast<int>(layout.rowIntervalField.size()),
|
||||
static_cast<int>(layout.rowFrequencyField.size()));
|
||||
}
|
||||
Expect(parallel, std::string("row arrays have identical lengths: ") + PanelKindName(kind));
|
||||
Expect(resampleParallel,
|
||||
std::string("resample row arrays empty-or-aligned: ") + PanelKindName(kind));
|
||||
Expect(parallel, std::string("all 18 row arrays match row count: ") + PanelKindName(kind));
|
||||
|
||||
char buffer[160] = {};
|
||||
std::snprintf(buffer, sizeof(buffer), "%s=%016llX,%d,%d,%d,%d\n", PanelKindName(kind),
|
||||
@@ -605,7 +592,8 @@ namespace jdi
|
||||
initial.scrollTrack.Width > 0.0f ? 1 : 0,
|
||||
static_cast<int>(initial.rowRefs.size()));
|
||||
|
||||
// 多信号场景下额外守住"平行数组长度一致"(本轮新增,成本 O(1))。
|
||||
// 多信号场景下额外守住"18 个平行数组长度全部等于行数"
|
||||
//(`AppendRow()` 是新增行的唯一入口 ⇒ 任何一列短了就是绕过它的证据)。
|
||||
{
|
||||
const std::size_t rows = initial.rowRefs.size();
|
||||
const std::size_t sizes[] = {initial.rowHeaders.size(), initial.rowNameRects.size(),
|
||||
@@ -621,14 +609,13 @@ namespace jdi
|
||||
bool aligned = true;
|
||||
for (const std::size_t size : sizes)
|
||||
{
|
||||
// 「重采样」专属数组在其它面板允许为空(见 `panels` 检查的说明)。
|
||||
if (size != rows && size != 0)
|
||||
if (size != rows)
|
||||
{
|
||||
aligned = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Expect(aligned, std::string("row arrays aligned with rows: ") + name);
|
||||
Expect(aligned, std::string("all 18 row arrays match row count: ") + name);
|
||||
}
|
||||
|
||||
if (maxScroll <= 1.0f)
|
||||
|
||||
+2
-2
@@ -171,8 +171,8 @@ Tools\OffscreenChecks\Build\OffscreenChecks.exe -list
|
||||
| --- | --- | --- |
|
||||
| `smoke` | 建隐藏窗口 → 加载 → 显示 3 条信号 → 渲染 → 抓帧 → 落盘 `smoke.png` | 客户区/绘图区尺寸合理、绘图区墨迹 > 1000 像素、**同一状态连续两帧逐像素相同**(渲染确定性) |
|
||||
| `frames` | 沿信号列表逐行移动"鼠标",每帧抓图 + 区域哈希 + 耗时 | 平均帧 < 500ms、帧序列**至少出现一次可见变化**;输出 `frame-XXX.png` 供事后分析 |
|
||||
| `panels` | 打开全部 7 个实验性面板(含双光标下的「选区截取」) | 每个面板:功能已启用、有尺寸、**必须被绘图区夹住**、**平行数组长度与行数一致**;`-mode record` 写 `panels-baseline.txt`,`-mode compare` 逐面板比对**像素哈希 + 几何** |
|
||||
| `panelscroll` | 全部信号合并到同一网格后,逐一滚动 7 种面板的内容区 | 可滚动时:滚到底/滚回顶、`scrollOffset` 夹到 `maxScroll`、滑块到达/返回轨道端点、内容区几何不动;不可滚动时不得出现滚动条。另守住平行数组一致性 |
|
||||
| `panels` | 打开全部 7 个实验性面板(含双光标下的「选区截取」) | 每个面板:功能已启用、有尺寸、**必须被绘图区夹住**、**18 个行数组长度全部等于行数**;`-mode record` 写 `panels-baseline.txt`,`-mode compare` 逐面板比对**像素哈希 + 几何** |
|
||||
| `panelscroll` | 全部信号合并到同一网格后,逐一滚动 7 种面板的内容区 | 可滚动时:滚到底/滚回顶、`scrollOffset` 夹到 `maxScroll`、滑块到达/返回轨道端点、内容区几何不动;不可滚动时不得出现滚动条。另守住 18 个行数组与行数完全一致 |
|
||||
| `edgestats` | 3 个阈值下的边沿计数(普通计数)+ 中心轴计数 | 与 `Checks.cpp` 内的**独立参考实现**(朴素逐点)**逐位相等**;同参数重复查询结果稳定 |
|
||||
| `perf` | 整帧中位数、`EdgePanelLayoutFor` 单次耗时、198 个统计状态的整轮查询耗时 | 整帧 < 500ms、面板几何 < 200µs/次、统计查询 < 20µs/次;数字用于前后对比 |
|
||||
|
||||
|
||||
Reference in new issue
Block a user