Skip to content

fix(web): avoid forced layouts in mouse glow discovery - #1809

Merged
wsp1911 merged 1 commit into
GCWing:mainfrom
wsp1911:dev
Jul 27, 2026
Merged

fix(web): avoid forced layouts in mouse glow discovery#1809
wsp1911 merged 1 commit into
GCWing:mainfrom
wsp1911:dev

Conversation

@wsp1911

@wsp1911 wsp1911 commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Make MouseGlow automatic-surface and divider candidate discovery geometry-free.
  • Measure only the final selected surface instead of every composed-path ancestor.
  • Keep normal overlays fixed under document.body; retain local positioning for actual floating layers.
  • Reuse the selected surface rect when a floating surface is its own overlay host.
  • Add regression coverage for geometry reads and normal stacking/transformed hosts.

Type and Areas

Type:

Regression fix

Areas:

Web UI, mouse-follow glow

Motivation / Impact

BitFun 0.2.14 could crash its WebView2 renderer with
STATUS_ACCESS_VIOLATION when the mouse-follow glow was enabled and the user
repeatedly switched between the Session and Settings scenes. Disabling the
effect prevented reproduction.

The native dump ended in:

requestAnimationFrame -> getBoundingClientRect -> Blink Flex layout -> OutOfFlowLayoutPart::LayoutCandidates

MouseGlowService.findSurface() walked the full composed ancestor path on
pointer frames. For each candidate it could call getBoundingClientRect() in
both divider and automatic-surface detection, then measure the selected surface
and an ordinary stacking-context host again. Session mounting and virtualized
content updates made these synchronous layout reads enter unstable Blink flex
layout repeatedly.

The regression was introduced in 1ec22139 / PR #1743, which added
the pointer-follow glow and its geometry-based ancestor discovery and overlay
host selection. The follow-up e3169ccf / PR #1757 consolidated the
ancestor style scan, but retained the per-candidate geometry reads.

The fix classifies candidates using computed styles, attributes, roles, and
class semantics. Geometry validation is deferred until one surface has been
selected. Ordinary stacking contexts no longer become overlay hosts, avoiding
the final SceneViewport flex-host measurement. Dialogs, listboxes, popovers,
and other actual floating layers retain local hosting.

No functional change is intended for the glow setting or normal pointer
tracking. Users should see the same effect with less layout work and without
the renderer crash.

Verification

  • pnpm --dir src/web-ui run test:run src/infrastructure/mouse-glow/core/MouseGlowService.test.ts
    • 1 test file passed, 15 tests passed.
  • pnpm run type-check:web
    • Passed.
  • git diff --cached --check
    • Passed.
  • Manual reproduction with mouse-follow glow enabled and repeated
    Session/Settings switching:
    • No crash reproduced after the fix.
  • Post-fix instrumentation sample:
    • 1,097 log entries inspected.
    • 763 MouseGlow reads measured only the final surface.
    • 0 divider/automatic ancestor geometry reads.
    • 0 SceneViewport or workspace stacking-host geometry reads.
    • The only additional host read was for an actual closing floating menu.

Reviewer Notes

Normal surfaces now use viewport coordinates with the fixed overlay hosted by
document.body, even when they are inside transformed or stacking-context
ancestors. Actual floating layers still use local coordinates so their clipping
and z-order behavior is preserved.

Divider line-shape validation now runs against the final selected rect instead
of during ancestor discovery.

All temporary runtime probes and the debug receiver were removed after manual
confirmation.

Checklist

  • This PR is focused and does not include secrets, temporary prompts, generated scratch files, or unrelated artifacts.
  • Relevant verification is recorded above, or skipped checks are explained.
  • User-facing strings, docs, and locales are updated where applicable.

MouseGlowService measured every composed-path ancestor while resolving a
glow surface, potentially forcing two synchronous layouts per element.
It then measured the selected surface and ordinary stacking host again.

This could enter Blink flex layout repeatedly while session content was
mounting, eventually causing a WebView2 STATUS_ACCESS_VIOLATION.

Detect candidates from styles and semantics, measure only the selected
surface, and keep normal overlays fixed under document.body. Preserve
local positioning for actual floating layers and reuse an existing rect
when the floating surface is its own host.

The regression originated in 1ec2213 (GCWing#1743).
@wsp1911
wsp1911 merged commit 19339e6 into GCWing:main Jul 27, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant