[Bug]: Embedded browser view renders a duplicated page and drifts over the chat pane at fractional DPI
維護者通常 1 天內回覆
還沒有人認領這個 Issue。
評估
- 難度
- 4/5
- 預估耗時
- 3-5 天
- 新手友好度
- 40/100
- Issue 類型
- 缺陷
- 描述清晰度
- 描述清楚
- 活躍度
- 活躍
- 技術堆疊
- rust, typescript
- 領域
- desktop-dev, frontend
研究方向
Start in src/web-ui/src/app/scenes/browser/useEmbeddedBrowserWebview.ts, where syncWebviewBounds and the browser_webview_create and browser_webview_set_bounds calls pass CSS-pixel bounds straight to the native host, then check the presentation.isCurrent() guard and the BrowserPreview frozen-frame overlay. Reproduce by setting devicePixelRatio to 1.21 and confirming the child view rect differs from the host rect. Done when the native view matches the host rect at fractional scale and geometry keeps syncing after a lost resize event.
由索引模型根據 Issue 內容生成。
描述
Summary
At a fractional Windows display scale (121%, devicePixelRatio = 1.21), the built-in browser panel renders the page twice: a live interactive view plus a second, magnified and blurred copy to its right. The live view itself is also mispositioned — it is smaller than its host and shifted toward the window origin, so it visually covers the chat pane next to the panel.
Area
Desktop app
Reproduction or evidence
Steps:
- Set the Windows display scale to a fractional value (here: 121%).
- Open the built-in browser panel — either let the agent open any URL, or use the Browser tab.
- Observe that the page is drawn twice, and that the interactive copy does not sit inside the panel.
Measurements (Win32 GetWindowRect on the child view vs. the rectangle the frontend computes for the panel host):
host rect (CSS px) 1325.6, 89.8, 397.5 x 986.2
devicePixelRatio 1.21
child view before 1044, ..., 398 x ... <- CSS numbers applied 1:1 as device pixels
child view after 1604, 109, 481 x 1193 <- expected: rect x 1.21
So the child view was rendered at 1 / 1.21 of its host and pulled toward the window origin by the same factor. At 100% scale the bug is invisible, which is why it only shows up on scaled displays.
Root cause 1 — units. getBoundingClientRect() reports CSS pixels, while browser_webview_create / browser_webview_set_bounds hand those values straight to the native host, which applies them 1:1 without multiplying by the window scale factor. At fractional DPI the child view therefore shrinks and offsets.
src/web-ui/src/app/scenes/browser/useEmbeddedBrowserWebview.ts:
await api.invoke('browser_webview_set_bounds', {
request: { label, x: bounds.left, y: bounds.top, width: bounds.width, height: bounds.height },
});
Root cause 2 — geometry sync can be blocked forever. syncWebviewBounds() returns early when presentationRef.current.isCurrent() is false. A panel that loses the presentation race still renders the visible native view, but it never syncs its geometry again, so the view stays at its creation-time size:
if (!isTauri || !target || !viewportRef.current || !mountedRef.current
|| (targetId && !presentationRef.current?.isCurrent())) return;
The presentation.run() wrapper used for the actual call has the same owner check, so it silently skips too.
Root cause 3 — the frozen frame shows through. BrowserPreview is a decorative JPEG of the native view pinned below it (captured every 5s, object-fit: fill, pointer-events: none). It is only supposed to be visible while a DOM overlay covers the native view. When the geometry above drifts, the stale frame is stretched across the gap and produces exactly the "second, blurred browser" appearance. Additionally the ResizeObserver that drives syncWebviewBounds only reports layout changes it actually witnessed — a panel that mounts at its final size never receives one.
Proposed fix (I have a patch and updated unit tests ready):
- Convert CSS → device pixels once, at the
create/set_boundsboundary:const dpr = window.devicePixelRatio || 1; x: bounds.left * dpr, y: bounds.top * dpr, width: bounds.width * dpr, height: bounds.height * dpr, - Do not gate geometry sync on presentation ownership, and add a periodic reconcile (e.g. 400 ms) so a lost
resizeevent cannot leave the view at its creation size. - Render the frozen frame only on the active panel, and hide inactive panel content (
visibility: hidden).
Happy to open a PR with the patch if that is useful.
Environment, if relevant
OpenBitFun version: 1.0.8 (frontend revision bundled-b5489663e559ac91)
OS: Windows 11 家庭中文版, build 22631
Display: 2560x1440 @ 121% scale
Mode: Desktop app, built-in browser panel (not an external browser)
- 主要語言
- Rust
- 星號
- 2.3k
- 分支
- 236
- 平均合併
- 12 小時 24 分鐘
- 30 天內合併 PR
- 370
環境準備
從這裡開始
- 先讀完整個 Issue,再讀專案的貢獻指南。
- 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
- Fork 儲存庫,在一個分支上完成修改。
- 送出 Pull Request,並在描述裡引用這個 Issue 編號。
GCWing/OpenBitFun 的其他 Issue
-
[Feature]: 模型服务表单缺少「图像生成」分类入口 —— 后端已支持 default_models.image_generation可能已有人在做 @skyfireitdiy 於 22 天前認領。 未關閉
難度 2/5 半天 新手友好度 74/100
GCWing/OpenBitFun#3279 · 1 個 reaction ·
維護者通常 1 天內回覆
-
難度 5/5 一週以上 新手友好度 35/100
GCWing/OpenBitFun#3784 ·
維護者通常 1 天內回覆
-
難度 5/5 一週以上 新手友好度 25/100
GCWing/OpenBitFun#3782 ·
維護者通常 1 天內回覆
-
難度 3/5 1-2 天 新手友好度 52/100
GCWing/OpenBitFun#3777 ·
維護者通常 1 天內回覆
-
[Bug]: v1.0.9 GLIBC_2.43 not found可能已有人在做 @kev1n77 於 1 天前認領。 未關閉
GCWing/OpenBitFun#3767 · 已指派 1 人 ·
維護者通常 1 天內回覆
查看 GCWing/OpenBitFun 的全部 Issue
相似的 Issue
-
binding:python bug
難度 2/5 1-3 小時 新手友好度 82/100
維護者通常 1 天內回覆
-
enhancement
難度 2/5 1-3 小時 新手友好度 78/100
coollabsio/orbit#72 ·
維護者通常 1 天內回覆
-
Synth suite fails unless run from the repo root: signal_flow's default machine path is cwd-relative未關閉bug
難度 2/5 1-3 小時 新手友好度 80/100
Nimblesite/osprey#370 ·
維護者通常 1 天內回覆
-
enhancement
難度 2/5 1-3 小時 新手友好度 70/100
-
bug order-flow studies ui
難度 2/5 1-3 小時 新手友好度 88/100
userFRM/egui-charts#2417 ·
維護者通常 1 天內回覆