mirror of
https://github.com/servo/servo.git
synced 2025-09-27 15:20:09 +01:00
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:
parent
406eab4ec2
commit
ebfb5b1abb
9 changed files with 153 additions and 43 deletions
|
@ -49,12 +49,10 @@ use {
|
|||
use super::app_state::RunningAppState;
|
||||
use super::geometry::{winit_position_to_euclid_point, winit_size_to_euclid_size};
|
||||
use super::keyutils::{CMD_OR_ALT, keyboard_event_from_winit};
|
||||
use super::window_trait::{
|
||||
LINE_HEIGHT, LINE_WIDTH, MIN_INNER_HEIGHT, MIN_INNER_WIDTH, PIXEL_DELTA_FACTOR,
|
||||
WindowPortsMethods,
|
||||
};
|
||||
use super::window_trait::{LINE_HEIGHT, LINE_WIDTH, PIXEL_DELTA_FACTOR, WindowPortsMethods};
|
||||
use crate::desktop::accelerated_gl_media::setup_gl_accelerated_media;
|
||||
use crate::desktop::keyutils::CMD_OR_CONTROL;
|
||||
use crate::desktop::window_trait::MIN_WINDOW_INNER_SIZE;
|
||||
use crate::prefs::ServoShellPreferences;
|
||||
|
||||
pub struct Window {
|
||||
|
@ -99,7 +97,10 @@ impl Window {
|
|||
.with_decorations(!no_native_titlebar)
|
||||
.with_transparent(no_native_titlebar)
|
||||
.with_inner_size(LogicalSize::new(inner_size.width, inner_size.height))
|
||||
.with_min_inner_size(LogicalSize::new(MIN_INNER_WIDTH, MIN_INNER_HEIGHT))
|
||||
.with_min_inner_size(LogicalSize::new(
|
||||
MIN_WINDOW_INNER_SIZE.width,
|
||||
MIN_WINDOW_INNER_SIZE.height,
|
||||
))
|
||||
// Must be invisible at startup; accesskit_winit setup needs to
|
||||
// happen before the window is shown for the first time.
|
||||
.with_visible(false);
|
||||
|
@ -489,26 +490,36 @@ impl WindowPortsMethods for Window {
|
|||
}
|
||||
|
||||
fn request_resize(&self, _: &WebView, new_outer_size: DeviceIntSize) -> Option<DeviceIntSize> {
|
||||
// Allocate space for the window deocrations, but do not let the inner size get
|
||||
// smaller than `MIN_WINDOW_INNER_SIZE` or larger than twice the screen size.
|
||||
let inner_size = self.winit_window.inner_size();
|
||||
let outer_size = self.winit_window.outer_size();
|
||||
let decoration_size: DeviceIntSize = Size2D::new(
|
||||
outer_size.height - inner_size.height,
|
||||
outer_size.width - inner_size.width,
|
||||
)
|
||||
.cast();
|
||||
|
||||
let screen_size = (self.screen_size.to_f32() * self.hidpi_scale_factor()).to_i32();
|
||||
let new_outer_size =
|
||||
new_outer_size.clamp(MIN_WINDOW_INNER_SIZE + decoration_size, screen_size * 2);
|
||||
|
||||
if outer_size.width == new_outer_size.width as u32 &&
|
||||
outer_size.height == new_outer_size.height as u32
|
||||
{
|
||||
return Some(new_outer_size);
|
||||
}
|
||||
|
||||
let inner_size = self.winit_window.inner_size();
|
||||
let decoration_height = outer_size.height - inner_size.height;
|
||||
let decoration_width = outer_size.width - inner_size.width;
|
||||
|
||||
let new_inner_size = new_outer_size - decoration_size;
|
||||
self.winit_window
|
||||
.request_inner_size::<PhysicalSize<i32>>(PhysicalSize::new(
|
||||
new_outer_size.width - decoration_width as i32,
|
||||
new_outer_size.height - decoration_height as i32,
|
||||
.request_inner_size(PhysicalSize::new(
|
||||
new_inner_size.width,
|
||||
new_inner_size.height,
|
||||
))
|
||||
.map(|resulting_size| {
|
||||
DeviceIntSize::new(
|
||||
(resulting_size.width + decoration_width) as i32,
|
||||
(resulting_size.height + decoration_height) as i32,
|
||||
resulting_size.width as i32 + decoration_size.width,
|
||||
resulting_size.height as i32 + decoration_size.height,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
@ -777,12 +788,6 @@ impl WindowPortsMethods for Window {
|
|||
return;
|
||||
}
|
||||
self.toolbar_height.set(height);
|
||||
// Prevent the inner area from being 0 pixels wide or tall
|
||||
// this prevents a crash in the compositor due to invalid surface size
|
||||
self.winit_window.set_min_inner_size(Some(PhysicalSize::new(
|
||||
MIN_INNER_WIDTH,
|
||||
MIN_INNER_HEIGHT.max((self.toolbar_height() * self.hidpi_scale_factor()).0 as i32),
|
||||
)));
|
||||
}
|
||||
|
||||
fn rendering_context(&self) -> Rc<dyn RenderingContext> {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -24,8 +24,7 @@ pub(crate) const PIXEL_DELTA_FACTOR: f64 = 4.0;
|
|||
|
||||
/// <https://github.com/web-platform-tests/wpt/blob/9320b1f724632c52929a3fdb11bdaf65eafc7611/webdriver/tests/classic/set_window_rect/set.py#L287-L290>
|
||||
/// "A window size of 10x10px shouldn't be supported by any browser."
|
||||
pub(crate) const MIN_INNER_WIDTH: i32 = 20;
|
||||
pub(crate) const MIN_INNER_HEIGHT: i32 = 20;
|
||||
pub(crate) const MIN_WINDOW_INNER_SIZE: DeviceIntSize = DeviceIntSize::new(100, 100);
|
||||
|
||||
pub trait WindowPortsMethods {
|
||||
fn id(&self) -> winit::window::WindowId;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue