UI 重构 P5(1):共享表面 UiSurface + 后备缓冲改 top-down 32bpp DIB;修复退出期绘制崩溃
一、共享表面(为「整个应用共享一张后台位图」落地基础设施)
- 新增 Components/Shared/{Inc,Src}/UiSurface.*:{ dc, rect, stride, bits, version, scale }。
SubView() 把子矩形换算到宿主坐标、夹取在本表面内、按 stride 重算 bits 偏移、传递 version。
⚠️ 注释里写明:bits 只在 CPU 侧合成时使用;画控件只需 dc + rect(用 bits 画字会破坏 ClearType)。
- Application 增 BackBufferSurface();后备缓冲由 CreateCompatibleBitmap 改为
**top-down 32bpp CreateDIBSection**(biHeight 取负,y 向下递增),并记录 bits/stride/version
(重建位图时 ++version,旧句柄因此可判定作废)。
二、修复「退出时访问违例」(真实缺陷)
- Application::Shutdown() 中 **DestroyWindow 必须在 GdiplusShutdown 之前**:前一帧的 InvalidateRect
可能留下未处理更新区域,DestroyWindow 期间派发 WM_PAINT ⇒ Render() ⇒ 在已关闭的 GDI+ 上构造
Graphics ⇒ 崩溃。
- Render() 开头加保护:!m_gdiplusReady 或 m_hwnd 为空时直接返回。
验证:
- 像素:8 场景(A 全览 / B 复杂浮层 / C 平移 / D 悬停 / E 按下 / F 松开 / G 悬停主按钮 / H 移出)
哈希与 DIB 改造前**逐一相同**(A 2166933…、B C444ECF…、C 7984446…、D BF85587…、
E 1C663E4…、F 0535292…、G 7A58172…、H 23F390D…)。
- 功能:locate-cursor-button (1291,73) / click-cursor-changes-mode (1->2) /
release-outside-does-not-fire 全部 PASS。
- uicheck 69 passed / 0 failed(新增 7 条 UiSurface 断言:bits 按 stride 偏移、矩形夹取、
完全在外时返回无效表面、version/scale 传递)。
- make release / make debug 零警告;Target.exe 883,200 B(< 900KB)。
附注:探针此前的退出崩溃其实来自「探针自己又调了一次 GdiplusShutdown」(Application::Shutdown
内部已 shutdown),与本轮修复无关;本轮的顺序调整与 Render 保护仍保留为防御性正确做法。
This commit is contained in:
1 parent
9a9802e589
commit
b60debc4ee
4 files changed
+166
-12
No files matched your search
@@ -17,6 +17,7 @@
|
||||
#include "TabBar.hpp"
|
||||
#include "Theme.hpp"
|
||||
#include "Toolbar.hpp"
|
||||
#include "UiSurface.hpp"
|
||||
|
||||
namespace jdi
|
||||
{
|
||||
@@ -130,12 +131,21 @@ namespace jdi
|
||||
* @param [IN] height 客户区高度。
|
||||
*/
|
||||
void EnsureBackBuffer(int width, int height);
|
||||
|
||||
/**
|
||||
* @brief 释放后备缓冲区。
|
||||
*/
|
||||
void ReleaseBackBuffer();
|
||||
|
||||
/**
|
||||
* @brief 取"整个应用共享的那张后台位图"作为一段可绘制表面。
|
||||
*
|
||||
* 这是 P5 的基础设施:后备缓冲是 **top-down 32bpp DIB 段**,因此除了 `dc` 之外
|
||||
* 还能给出 `bits`(像素直写)与 `version`(位图代次;`WM_SIZE` / `WM_DPICHANGED`
|
||||
* 重建后旧句柄必须作废)。
|
||||
* ⚠️ 绝大多数绘制只需要 `dc + rect`;`bits` 仅用于 CPU 侧合成,**不要**用它画控件。
|
||||
*/
|
||||
UiSurface BackBufferSurface() const;
|
||||
|
||||
/**
|
||||
* @brief 完整重绘客户区并呈现到窗口。
|
||||
*/
|
||||
@@ -428,10 +438,13 @@ namespace jdi
|
||||
int m_splitterGrabOffset = 0; /**< 分隔条拖动的抓取偏移。 */
|
||||
|
||||
HDC m_backDc = nullptr; /**< 后备缓冲设备上下文。 */
|
||||
HBITMAP m_backBitmap = nullptr; /**< 后备缓冲位图。 */
|
||||
HBITMAP m_backBitmap = nullptr; /**< 后备缓冲位图(top-down 32bpp DIB 段)。 */
|
||||
HGDIOBJ m_backOldBitmap = nullptr; /**< 后备缓冲原始位图。 */
|
||||
int m_backWidth = 0; /**< 后备缓冲宽度。 */
|
||||
int m_backHeight = 0; /**< 后备缓冲高度。 */
|
||||
int m_backWidth = 0; /**< 后备缓冲宽度(设备像素)。 */
|
||||
int m_backHeight = 0; /**< 后备缓冲高度(设备像素)。 */
|
||||
std::uint32_t* m_backBits = nullptr; /**< 后备缓冲像素首地址(仅 CPU 侧合成时使用)。 */
|
||||
int m_backStride = 0; /**< 后备缓冲行字节数(**不可**假设 = 宽 × 4)。 */
|
||||
std::uint64_t m_backVersion = 0; /**< 后备缓冲代次(重建位图时递增,用于作废旧句柄)。 */
|
||||
|
||||
Target m_activeTarget = Target::NONE; /**< 当前鼠标作用目标。 */
|
||||
bool m_trackingLeave = false; /**< 是否已注册鼠标离开通知。 */
|
||||
|
||||
Reference in new issue
Block a user