fix(servo): resize through WebView only, never the rendering context

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.
This commit is contained in:
2026-05-18 15:30:55 -04:00
parent 3678db60b9
commit d1e811b724
+17 -1
View File
@@ -270,8 +270,24 @@ impl ServoHost for SoftwareServoHost {
.get(&request.webview_id) .get(&request.webview_id)
.ok_or_else(|| ServoHostError::WebViewNotFound { id: request.webview_id.clone() })?; .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); let size = PhysicalSize::new(request.width, request.height);
webview.rendering_context.resize(size);
webview.webview.resize(size); webview.webview.resize(size);
Ok(()) Ok(())
} }