Repository navigation
macOS: a density change during a resize no longer freezes the view - #59
Merged
Merged
Conversation
Switching the device frame in FlutterFlow's Test Mode changes the preview's size and render scale at once. On a page slow to relayout the view could stop painting for good: JS still answered, hide/show and reload didn't help. CEF's OSR view keeps one resize in flight and queues a change made meanwhile. A queued density change is applied through UpdateScreenInfo, which sends the renderer the new scale under the surface id it already has. viz rejects the renderer's next frame (surface invariants violation) and drops its frame sink. On macOS the view then never draws again: CEF 144 never embeds the surface id the renderer allocates for its new sink (DidUpdateVisualProperties is compiled out for Mac), or the external begin-frame source waits forever on the dropped sink. cef_host now hands CEF geometry through cef_width/cef_height/cef_dpr and changes them only when no resize is in flight (a paint at the new pixel size ends one). A density change goes through NotifyScreenInfoChanged, which retires the surface id first. A resize with no paint at its size gets the renderer a fresh surface id, 1, 2, then 4 s apart. Probe: device_frame (slow page, busy UI thread, plain/blip/anim switches). Before: froze at round 2 in 3 of 3 runs on the shipping framework. After: 30/30 in 3 of 3 runs, no invariants violation in a 40 s trace. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
CEF builds its view at the create size, and GetViewRect now reports the geometry handed to CEF rather than the latest request, so a resize that landed before OnAfterCreated would wait for the next one. Hand CEF the latest geometry when the browser binds. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Switching the device frame in FlutterFlow's Test Mode could freeze the preview for good. JS still answered, but nothing painted, and hide/show and reload didn't bring it back. It happens when the previewed page is slow to relayout, like a debug web build.
Cause
A device switch changes the view's size and render scale at once. CEF's OSR view keeps one resize in flight: a size or scale change "holds" until a paint arrives at the new pixel size, and a change made during the hold is queued for when it releases.
A queued density change is applied through
RenderWidgetHostViewBase::UpdateScreenInfo. That sends the renderer the new scale under the surface id it already has. The renderer's next frame therefore has a different scale for the same surface id, so viz rejects it as a surface invariants violation and drops the renderer's frame sink.On macOS the view never comes back from that, for one of two reasons:
CefRenderWidgetHostViewOSR::DidUpdateVisualPropertiesis compiled out for Mac (upstream CEF has since removed that guard). The display has no damage it recognises, never draws, and the hold never releases.Found with
--trace-startup: Surface invariants violation →DidLoseLayerTreeFrameSink→ChildLocalSurfaceIdAllocator::GenerateId, followed by no browser-side embed of the new id and noDisplay::DrawAndSwapfor the rest of the run.This also explains an earlier experiment. Dropping the
NotifyScreenInfoChangedcall made the freeze worse (round 1 instead of round 2):WasResizedalone applies the new density through the sameUpdateScreenInfopath.Fix
cef_hostnow shows CEF its geometry throughcef_width/cef_height/cef_dpr, viaGetViewRectandGetScreenInfo.ScaleToCeiledSizein float), and whatever the plugin asked for meanwhile is applied next. Intermediate sizes collapse into the latest one.NotifyScreenInfoChanged, which retires the surface id before applying the new scale.NotifyScreenInfoChangedagain, 1, 2, then 4 s apart, up to 6 times. With the geometry CEF sees unchanged, that only swaps in a fresh surface id.Verification
New probe
device_frame, added torun_probes.sh, mirrors Test Mode's widget tree: FittedBox, MediaQuery, CefWebView atdevicePixelRatio × zoom. It switches devices 30 times in three ways (plain, parked-then-shown, animated). The page blocks its main thread 600 ms on every resize, and the UI thread is janked 40 ms per frame. Each round checks the page's viewport and density, then that it still presents a frame.Full
tool/run_probes.sh: 18 of 19 passed. The one failure,host_robustness, is a pre-existing flake: a sentinel eval misses its 5 s window in a random case. It fails the same way on the baseline host (interleaved A/B: baseline 3/4, this branch 4/4). That probe creates its tiles headless and never resizes them, so none of the new code acts there.A second commit hands CEF the latest geometry in
OnAfterCreated.GetViewRectnow reports what CEF was handed, so without it a resize that arrived while the browser was being created would have waited for the next resize.The prebuilt must be republished (
make publish-cef-host) before consumers repin.🤖 Generated with Claude Code