Snapshot before max-resize threshold diagnosis

This commit is contained in:
Codex
2026-04-09 03:23:10 +08:00
parent 77a8fe568a
commit f567369300
25 changed files with 1489 additions and 36 deletions
@@ -0,0 +1,93 @@
# Fix-BUG-20260409-0001
> 适用场景:记录某个 BUG 的修复方案、影响评估、验证结果与落地信息。
## 关联信息
- Fix ID: Fix-BUG-20260409-0001
- 关联 BUG ID: BUG-20260409-0001
- 修复目标: 收紧对话框快照、遮挡、事件分发和统一提交重绘链
- 状态:已完成 / 待持续回归
- 负责人:Codex 协作修改
- 分支 / 版本:`master`
## 根因分析
- 根因:
- 旧实现中“作废快照”和“回贴旧背景”混在一起,resize 时容易把旧画面贴回屏幕。
- 非模态对话框与底层控件之间缺少明确的事件阻断和 hover 清理机制。
- 重绘长期依赖控件即时局部绘制,导致底层先画、对话框后补,容易闪烁或层级错乱。
- 标题曾作为独立 `Label` 存在,导致额外一层背景快照,时序敏感。
- 触发条件:
- 非模态遮挡下的 hover / click
- 模态或非模态 resize
- 对话框打开 / 关闭
- 为什么之前没发现:
- 问题主要集中在“高频交互 + 对话框遮挡 + resize”组合路径
## 修复方案
- 修复思路:
- 拆分快照语义
- 收紧对话框事件消费
-`Dialog` 在窗口变化时只重新居中
- 将标题绘制并入 `Dialog`
- 把重绘推进到窗口统一收口
- 关键改动:
- `discardBackground()``invalidateBackgroundSnapshot()` 分离
- `Dialog` 标题改为直接绘制,不再使用独立 `Label`
- `Dialog::handleEvent()` 对自身区域内鼠标事件统一吞掉
- 对话框关闭及遮挡场景补发合成 `WM_MOUSEMOVE`,清理底层 hover
- `Window` 引入托管重绘,先重绘受影响 root,再补画相交对话框
- 涉及文件 / 类 / 函数:
- `Window.h / Window.cpp`
- `Dialog.h / Dialog.cpp`
- `Control.h / Control.cpp`
- `Canvas.cpp`
- `TabControl.cpp`
- `Button.cpp`
- `TextBox.cpp`
- 影响的 API / 行为:
- `Dialog` 在窗口变化时的语义固定为“只重新居中,不拉伸”
- 非模态对话框覆盖区域内不再允许鼠标事件穿透到底层
- 关键约束 / 不变量:
- 对话框始终绘制在普通控件之上
- 托管分发期间控件不直接提交绘制
- resize 和对话框开关仍走整场景重绘兜底
## 影响评估
- 影响范围:
- 所有包含 `Dialog`、按钮 hover、遮挡重绘的场景
- 兼容性影响:有(行为更严格,底层控件不再穿透响应)
- 行为变化:有(对话框 resize 只居中;遮挡区域 hover 不再透传)
- 性能影响:有正向变化(减少无意义整场景补画);同时在某些兜底场景仍保留整场景重绘
- 回归风险:
- 托管重绘 root 选择不当可能导致嵌套容器局部重绘异常
- 需持续回归 `Canvas / TabControl / Table / Dialog` 组合场景
## 验证结果
- 验证步骤:
1.`KEY == 2 / 4` 中打开非模态对话框,快速在遮挡区域附近 hover 和点击。
2.`KEY == 3 / 4` 中打开模态对话框并拖动窗口大小。
3. 关闭对话框后观察底层按钮 hover 恢复。
- 验证结果:
- 穿透、残影、关闭后 hover 不恢复等主问题已压住。
- 回归检查:
- 保留对“快速划过多个按钮时偶发一帧双高亮”的已知限制记录。
- 验证证据:
- 静态推演 + 多轮编译验证 + 用户回归反馈
## 落地信息
- Commit:
- `4a6e153`
- `7f8431a`
- `b07a4ec`
- 当前工作区未提交阶段
- PR[可选]
- 发布版本:[可选]
- 备注:该修复跨多个阶段逐步收敛,不是一次性完成