From 5fd57284beaacaf811bb42c2d8264c58df4106ed Mon Sep 17 00:00:00 2001 From: wenkaifan0720 Date: Tue, 29 Sep 2026 15:19:35 -0700 Subject: [PATCH] cef_host: point the resize capture refresh at CEF issue #3826 The capturer's retries never capture after a dropped frame because Chromium's FrameSinkVideoCapturerImpl::MaybeDeliverFrame doesn't call VideoCaptureOracle::CompleteCapture for it, so num_frames_pending_ stays up and every kRefreshRequest is refused (CEF issue #3826). That is the "nothing pending" check our trace showed rejecting them. CEF fixed it with viz_capture_3826.patch on branch 8037 and master; we're on 7559. Say so, and when the refresh can go. Comment and changelog only. Co-Authored-By: Claude Opus 5.5 (1M context) --- packages/flutter_cef_macos/CHANGELOG.md | 5 +++-- .../native/cef_host/browser_ops.mm | 16 +++++++++------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/packages/flutter_cef_macos/CHANGELOG.md b/packages/flutter_cef_macos/CHANGELOG.md index e67d222..6ac238d 100644 --- a/packages/flutter_cef_macos/CHANGELOG.md +++ b/packages/flutter_cef_macos/CHANGELOG.md @@ -4,8 +4,9 @@ the new size (up to about 4 s), most often mid-way through an animated device switch. CEF paints by capturing the view: the renderer's first frame at the new size was captured at the old size, and the capturer's own retries were - turned away until the stall fallback kicked in. `cef_host` now asks for a - fresh capture every 100 ms while a resize waits for its paint. + turned away until the stall fallback kicked in (CEF issue #3826, fixed in + CEF 8037+). `cef_host` now asks for a fresh capture every 100 ms while a + resize waits for its paint. `device_frame` no longer needs the stall fallback (it did in 1 to 12 of 30 switches). The prebuilt must be republished. * Fix: a view could stop painting for good after a resize that changed the diff --git a/packages/flutter_cef_macos/native/cef_host/browser_ops.mm b/packages/flutter_cef_macos/native/cef_host/browser_ops.mm index add1a15..b1e5d26 100644 --- a/packages/flutter_cef_macos/native/cef_host/browser_ops.mm +++ b/packages/flutter_cef_macos/native/cef_host/browser_ops.mm @@ -402,13 +402,15 @@ void DoSetVisible(const std::shared_ptr& slot, bool visible) { // size of the renderer's last activated frame. When the renderer's frame at the // new size activates, it is captured at the OLD size, and only then does CEF set // the new capture size. The capture that change asks for is rate-limited (one -// was just taken), and the capturer's own retries go through a stricter check -// (nothing pending, no recent animation) that can turn them all away. A page -// with nothing else changing gives it no damage either, so no paint at the new -// size came until the stall kick. Invalidate asks for a capture the way a -// compositor update does, which isn't subject to that check. The one at the -// start of a resize comes too early, so ask again every kResizeRefreshMs until -// the paint arrives. +// was just taken), and the capturer's own retries only capture when no capture +// is pending. Chromium leaves a dropped capture counted as pending, so after one +// drop those retries never capture again (CEF issue #3826). A page with nothing +// else changing gives it no damage either, so no paint at the new size came +// until the stall kick. Invalidate asks for a capture the way a compositor +// update does, which isn't subject to that check. The one at the start of a +// resize comes too early, so ask again every kResizeRefreshMs until the paint +// arrives. CEF fixed the bookkeeping in viz_capture_3826.patch (branch 8037 and +// later); on such a CEF this refresh is no longer needed. namespace { constexpr int kResizeRefreshMs = 100; constexpr int kResizePaintWaitMs = 1000;