From d1e811b72441db9d31bfd7c547938b28f4234932 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E7=94=B5=E8=8A=BD=E8=A1=A3?= Date: Mon, 18 May 2026 15:30:55 -0400 Subject: [PATCH] fix(servo): resize through WebView only, never the rendering context MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Servo's reference embedder (\`examples/winit_minimal.rs\`) handles resize with a single call: \`webview.resize(new_size)\`. The Servo paint pipeline behind that call: 1. early-returns if \`rendering_context.size() == new_size\`, 2. otherwise calls \`rendering_context.resize\` itself, 3. updates \`webview_renderer.rect\` so the compositor relays out the page at the new device viewport, 4. sends \`transaction.set_document_view(...)\` so WebRender's document viewport matches the surface, 5. flags the painter \`needs_repaint(RepaintReason::Resize)\`. Our \`runtime.rs::resize\` called \`webview.rendering_context.resize\` *before* \`webview.webview.resize\`. surfman accepted the new size, so the painter saw \`rendering_context.size() == new_size\` and took the early-return path — steps 3, 4, and 5 never ran. The compositor kept the original (creation-time) viewport rect while we presented a much larger surface. The page ended up laid out for a tiny viewport and either rendered into the top-left of a sea of cleared background (StableLance) or never painted any pipeline at all (google.com appeared totally blank). Drop the direct \`rendering_context.resize\` call and route through \`WebView::resize\` exactly as the reference embedder does. The debounce in \`record_viewport_size\` still collapses a sidebar / window-edge animation into a single trailing-edge resize, so we also avoid hammering Servo with per-frame surface mutations. --- crates/ely_servo_host/src/runtime.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/crates/ely_servo_host/src/runtime.rs b/crates/ely_servo_host/src/runtime.rs index fe43262..fa012a8 100644 --- a/crates/ely_servo_host/src/runtime.rs +++ b/crates/ely_servo_host/src/runtime.rs @@ -270,8 +270,24 @@ impl ServoHost for SoftwareServoHost { .get(&request.webview_id) .ok_or_else(|| ServoHostError::WebViewNotFound { id: request.webview_id.clone() })?; + // `WebView::resize` is the single entry point — it routes through + // `paint().resize_rendering_context`, which: + // 1. early-returns if `rendering_context.size() == new_size`; + // 2. calls `rendering_context.resize` itself; + // 3. calls `webview_renderer.set_rect(new_viewport_rect)` so the + // compositor relays out the page at the new size; and + // 4. sends `transaction.set_document_view(...)` so WebRender's + // document viewport matches the surface. + // + // Calling `rendering_context.resize` *ourselves* before that path + // is what produced the original bug: surfman saw the new size, + // Servo's early-return then skipped steps 3 and 4, and the page + // stayed laid out at the original size while we presented a + // larger surface — content collapsed to the top-left of a giant + // viewport (StableLance) or rendered nothing at all (Google). + // The Servo `winit_minimal` reference embedder calls + // `webview.resize` and nothing else; mirror that exactly. let size = PhysicalSize::new(request.width, request.height); - webview.rendering_context.resize(size); webview.webview.resize(size); Ok(()) }