🐛 fix(window): 直接调 WebView2 zoom factor 零感知修复 Windows 字体异常

- 新增 ResetWebViewZoom RPC:从 ctx 反射拿 Wails 内部 *edge.Chromium,调 PutZoomFactor(1.0) 强制 WebView2 重算 D2D/DirectWrite 字体度量,完全不动窗口零动画
- 自动路径:maximised + restore + drift 时直接调 backend reset,告别 9848b8b2 之后字体偶发变大的取舍
- 手动路径:保留 Ctrl+Shift+0 快捷键作为兜底(优先 WebView2 reset,失败回退 toggle)
- 撤回上一版 CSS zoom nudge:实测在 WebView2 上不能修字体度量(度量缓存在 D2D 层不在 Chromium layout 层)
- 反射做了 3 层签名校验(frontend value / chromium 字段 / PutZoomFactor 方法签名),wails 升级破坏接口时返回 error 不让进程崩溃
- 新增 windows-only 反射逻辑测试 4 个、跨平台 RPC 行为测试 2 个、Ctrl+Shift+0 快捷键注册测试
This commit is contained in:
Syngnat
2026-05-15 16:01:18 +08:00
parent 32d51f3c25
commit 2580e4d6f3
10 changed files with 304 additions and 69 deletions

View File

@@ -44,34 +44,3 @@ export const getWindowsScaleFixNudgedWidth = (width: number): number => {
}
return normalizedWidth > 480 ? normalizedWidth - 1 : normalizedWidth + 1;
};
// applyWindowsViewportZoomNudge 通过短暂改变 documentElement 的 CSS zoom 触发 Chromium
// 重新计算 layout metrics。用于 maximised 窗口在 restore 场景下 viewport drift 修复的
// 无动画路径:不重新最大化(避免 9848b8b2 修复的可见"重复最大化"抖动),也不调 WebView2
// COM API避免 Windows 平台特定代码)。
//
// 为什么这样能修Chromium 在切换 zoom factor 时会重算所有 px 度量与 currentColor/font-size
// 派生值drift 后残留的旧度量被丢弃。1.0001 与 1 在视觉上不可分辨但属于 invalidation 阈值
// 之外,强制触发完整 layout 重排。
//
// 用 requestAnimationFrame 两帧而不是立即 reset让 Chromium 在第一帧完成 nudge layout、
// 第二帧恢复——避免单帧合成被合并掉。
export const applyWindowsViewportZoomNudge = (): void => {
if (typeof document === 'undefined' || !document.documentElement) {
return;
}
const root = document.documentElement;
const style = root.style as CSSStyleDeclaration & { zoom?: string };
const previousZoom = style.zoom ?? '';
style.zoom = '1.0001';
const reset = () => {
style.zoom = previousZoom;
};
if (typeof window === 'undefined' || typeof window.requestAnimationFrame !== 'function') {
reset();
return;
}
window.requestAnimationFrame(() => {
window.requestAnimationFrame(reset);
});
};