libservo: Make Servo (and servoshell) more resilient against extreme sizes (#39204)

Make several changes which should address panics and inconsistent
behavior around attempts to set extreme sizes:

1. Limit the minimum size of the `RenderingContext` to 1 pixel by 1
   pixel. This should address problems where users of the API try to
   directly set the size to a zero or negative dimension. In addition,
   improve the documentation around `WebView::resize` to mention this.
2. Clamp values sent in the `WebViewDelegate::request_resize_to` method
   to be at least 1x1. This prevents Servo from sending nonsense values
   to embedders. Improve documentation in this method.
3. In servoshell:
    - More consistently clamp inner and outer window size values.
    - Clamp all resize values to the available screen size, so that
      large screen sizes aren't processed directly.

Testing: This change fixes an existing WPT and adds two new API tests.
Fixes: #36763.
Fixes: #36841.
Fixes: #39141.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
Martin Robinson 2025-09-09 05:51:30 -07:00 committed by GitHub
parent 406eab4ec2
commit ebfb5b1abb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 153 additions and 43 deletions

View file

@ -20,7 +20,7 @@ use servo::{RenderingContext, ScreenGeometry, SoftwareRenderingContext, WebView}
use winit::dpi::PhysicalSize;
use super::app_state::RunningAppState;
use crate::desktop::window_trait::{MIN_INNER_HEIGHT, MIN_INNER_WIDTH, WindowPortsMethods};
use crate::desktop::window_trait::{MIN_WINDOW_INNER_SIZE, WindowPortsMethods};
use crate::prefs::ServoShellPreferences;
pub struct Window {
@ -87,15 +87,10 @@ impl WindowPortsMethods for Window {
self.window_position.set(point);
}
fn request_resize(
&self,
webview: &WebView,
outer_size: DeviceIntSize,
) -> Option<DeviceIntSize> {
let new_size = DeviceIntSize::new(
outer_size.width.max(MIN_INNER_WIDTH),
outer_size.height.max(MIN_INNER_HEIGHT),
);
fn request_resize(&self, webview: &WebView, new_size: DeviceIntSize) -> Option<DeviceIntSize> {
// Do not let the window size get smaller than `MIN_WINDOW_INNER_SIZE` or larger
// than twice the screen size.
let new_size = new_size.clamp(MIN_WINDOW_INNER_SIZE, self.screen_size * 2);
if self.inner_size.get() == new_size {
return Some(new_size);
}
@ -105,10 +100,10 @@ impl WindowPortsMethods for Window {
// Because we are managing the rendering surface ourselves, there will be no other
// notification (such as from the display manager) that it has changed size, so we
// must notify the compositor here.
webview.move_resize(outer_size.to_f32().into());
webview.move_resize(new_size.to_f32().into());
webview.resize(PhysicalSize::new(
outer_size.width as u32,
outer_size.height as u32,
new_size.width as u32,
new_size.height as u32,
));
Some(new_size)