mirror of
https://github.com/servo/servo.git
synced 2025-07-20 05:43:41 +01:00
script: Get the window rectangle from the WebViewDelegate
instead of via the compositor (#37960)
Previously, `screenX`, `screenY`, `outerHeight`, `outerWidth`, `moveBy`, `resizeBy` ask compositor for window rectangle, which then return "inner" rectangle after consulting Embedder. This PR 1. removes `GetClientWindowRect` from compositor, and directly let script ask embedder. 2. add `window_size` to `ScreenGeometry` 3. add a lot of docs to `ScreenGeometry` Testing: `tests\wpt\mozilla\tests\mozilla\window_resizeTo.html` can now pass for Headed Window. Fixes: #37824 --------- Signed-off-by: Euclid Ye <yezhizhenjiakang@gmail.com> Signed-off-by: Martin Robinson <mrobinson@igalia.com> Co-authored-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
parent
d40e9f82a2
commit
c5aeac3cea
16 changed files with 59 additions and 104 deletions
|
@ -912,18 +912,6 @@ impl IOCompositor {
|
|||
.collect();
|
||||
let _ = result_sender.send((font_keys, font_instance_keys));
|
||||
},
|
||||
CompositorMsg::GetClientWindowRect(webview_id, response_sender) => {
|
||||
let client_window_rect = self
|
||||
.webview_renderers
|
||||
.get(webview_id)
|
||||
.map(|webview_renderer| {
|
||||
webview_renderer.client_window_rect(self.rendering_context.size2d())
|
||||
})
|
||||
.unwrap_or_default();
|
||||
if let Err(error) = response_sender.send(client_window_rect) {
|
||||
warn!("Sending response to get client window failed ({error:?}).");
|
||||
}
|
||||
},
|
||||
CompositorMsg::GetScreenSize(webview_id, response_sender) => {
|
||||
let screen_size = self
|
||||
.webview_renderers
|
||||
|
@ -993,11 +981,6 @@ impl IOCompositor {
|
|||
.collect();
|
||||
let _ = result_sender.send((font_keys, font_instance_keys));
|
||||
},
|
||||
CompositorMsg::GetClientWindowRect(_, response_sender) => {
|
||||
if let Err(error) = response_sender.send(Default::default()) {
|
||||
warn!("Sending response to get client window failed ({error:?}).");
|
||||
}
|
||||
},
|
||||
CompositorMsg::GetScreenSize(_, response_sender) => {
|
||||
if let Err(error) = response_sender.send(Default::default()) {
|
||||
warn!("Sending response to get client window failed ({error:?}).");
|
||||
|
|
|
@ -51,7 +51,6 @@ mod from_constellation {
|
|||
Self::AddSystemFont(..) => target!("AddSystemFont"),
|
||||
Self::AddFontInstance(..) => target!("AddFontInstance"),
|
||||
Self::RemoveFonts(..) => target!("RemoveFonts"),
|
||||
Self::GetClientWindowRect(..) => target!("GetClientWindowRect"),
|
||||
Self::GetScreenSize(..) => target!("GetScreenSize"),
|
||||
Self::GetAvailableScreenSize(..) => target!("GetAvailableScreenSize"),
|
||||
Self::CollectMemoryReport(..) => target!("CollectMemoryReport"),
|
||||
|
|
|
@ -19,14 +19,12 @@ use embedder_traits::{
|
|||
MouseButtonEvent, MouseMoveEvent, ScrollEvent as EmbedderScrollEvent, ShutdownState,
|
||||
TouchEvent, TouchEventResult, TouchEventType, TouchId, ViewportDetails,
|
||||
};
|
||||
use euclid::{Box2D, Point2D, Scale, Size2D, Vector2D};
|
||||
use euclid::{Point2D, Scale, Size2D, Vector2D};
|
||||
use fnv::FnvHashSet;
|
||||
use log::{debug, warn};
|
||||
use servo_geometry::DeviceIndependentPixel;
|
||||
use style_traits::{CSSPixel, PinchZoomFactor};
|
||||
use webrender_api::units::{
|
||||
DeviceIntPoint, DeviceIntRect, DevicePixel, DevicePoint, DeviceRect, LayoutVector2D,
|
||||
};
|
||||
use webrender_api::units::{DeviceIntPoint, DevicePixel, DevicePoint, DeviceRect, LayoutVector2D};
|
||||
use webrender_api::{ExternalScrollId, HitTestFlags, ScrollLocation};
|
||||
|
||||
use crate::compositor::{HitTestError, PipelineDetails, ServoRenderer};
|
||||
|
@ -1041,20 +1039,6 @@ impl WebViewRenderer {
|
|||
old_rect != self.rect
|
||||
}
|
||||
|
||||
pub(crate) fn client_window_rect(
|
||||
&self,
|
||||
rendering_context_size: Size2D<u32, DevicePixel>,
|
||||
) -> Box2D<i32, DeviceIndependentPixel> {
|
||||
let screen_geometry = self.webview.screen_geometry().unwrap_or_default();
|
||||
let rect = DeviceIntRect::from_origin_and_size(
|
||||
screen_geometry.offset,
|
||||
rendering_context_size.to_i32(),
|
||||
)
|
||||
.to_f32() /
|
||||
self.hidpi_scale_factor;
|
||||
rect.to_i32()
|
||||
}
|
||||
|
||||
pub(crate) fn screen_size(&self) -> Size2D<i32, DeviceIndependentPixel> {
|
||||
let screen_geometry = self.webview.screen_geometry().unwrap_or_default();
|
||||
(screen_geometry.size.to_f32() / self.hidpi_scale_factor).to_i32()
|
||||
|
|
|
@ -214,6 +214,7 @@ mod from_script {
|
|||
Self::SetCursor(..) => target_variant!("SetCursor"),
|
||||
Self::NewFavicon(..) => target_variant!("NewFavicon"),
|
||||
Self::HistoryChanged(..) => target_variant!("HistoryChanged"),
|
||||
Self::GetWindowRect(..) => target_variant!("GetWindowRect"),
|
||||
Self::NotifyFullscreenStateChanged(..) => {
|
||||
target_variant!("NotifyFullscreenStateChanged")
|
||||
},
|
||||
|
|
|
@ -1686,12 +1686,9 @@ impl WindowMethods<crate::DomTypeHolder> for Window {
|
|||
|
||||
// https://drafts.csswg.org/cssom-view/#dom-window-resizeby
|
||||
fn ResizeBy(&self, x: i32, y: i32) {
|
||||
let (size, _) = self.client_window();
|
||||
let size = self.client_window().size();
|
||||
// Step 1
|
||||
self.ResizeTo(
|
||||
x + size.width.to_i32().unwrap_or(1),
|
||||
y + size.height.to_i32().unwrap_or(1),
|
||||
)
|
||||
self.ResizeTo(x + size.width, y + size.height)
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom-view/#dom-window-moveto
|
||||
|
@ -1706,33 +1703,29 @@ impl WindowMethods<crate::DomTypeHolder> for Window {
|
|||
|
||||
// https://drafts.csswg.org/cssom-view/#dom-window-moveby
|
||||
fn MoveBy(&self, x: i32, y: i32) {
|
||||
let (_, origin) = self.client_window();
|
||||
let origin = self.client_window().min;
|
||||
// Step 1
|
||||
self.MoveTo(x + origin.x, y + origin.y)
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom-view/#dom-window-screenx
|
||||
fn ScreenX(&self) -> i32 {
|
||||
let (_, origin) = self.client_window();
|
||||
origin.x
|
||||
self.client_window().min.x
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom-view/#dom-window-screeny
|
||||
fn ScreenY(&self) -> i32 {
|
||||
let (_, origin) = self.client_window();
|
||||
origin.y
|
||||
self.client_window().min.y
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom-view/#dom-window-outerheight
|
||||
fn OuterHeight(&self) -> i32 {
|
||||
let (size, _) = self.client_window();
|
||||
size.height.to_i32().unwrap_or(1)
|
||||
self.client_window().height()
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom-view/#dom-window-outerwidth
|
||||
fn OuterWidth(&self) -> i32 {
|
||||
let (size, _) = self.client_window();
|
||||
size.width.to_i32().unwrap_or(1)
|
||||
self.client_window().width()
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom-view/#dom-window-devicepixelratio
|
||||
|
@ -2151,18 +2144,12 @@ impl Window {
|
|||
self.viewport_details.get().hidpi_scale_factor
|
||||
}
|
||||
|
||||
fn client_window(&self) -> (Size2D<u32, CSSPixel>, Point2D<i32, CSSPixel>) {
|
||||
let timer_profile_chan = self.global().time_profiler_chan().clone();
|
||||
let (sender, receiver) =
|
||||
ProfiledIpc::channel::<DeviceIndependentIntRect>(timer_profile_chan).unwrap();
|
||||
let _ = self.compositor_api.sender().send(
|
||||
compositing_traits::CompositorMsg::GetClientWindowRect(self.webview_id(), sender),
|
||||
);
|
||||
let rect = receiver.recv().unwrap_or_default();
|
||||
(
|
||||
Size2D::new(rect.size().width as u32, rect.size().height as u32),
|
||||
Point2D::new(rect.min.x, rect.min.y),
|
||||
)
|
||||
fn client_window(&self) -> DeviceIndependentIntRect {
|
||||
let (sender, receiver) = ipc::channel().expect("Failed to create IPC channel!");
|
||||
|
||||
self.send_to_embedder(EmbedderMsg::GetWindowRect(self.webview_id(), sender));
|
||||
|
||||
receiver.recv().unwrap_or_default()
|
||||
}
|
||||
|
||||
/// Prepares to tick animations and then does a reflow which also advances the
|
||||
|
|
|
@ -100,6 +100,7 @@ use servo_config::opts::Opts;
|
|||
use servo_config::prefs::Preferences;
|
||||
use servo_config::{opts, pref, prefs};
|
||||
use servo_delegate::DefaultServoDelegate;
|
||||
use servo_geometry::DeviceIndependentIntRect;
|
||||
use servo_media::ServoMedia;
|
||||
use servo_media::player::context::GlContext;
|
||||
use servo_url::ServoUrl;
|
||||
|
@ -998,6 +999,25 @@ impl Servo {
|
|||
webview.delegate().show_form_control(webview, form_control);
|
||||
}
|
||||
},
|
||||
EmbedderMsg::GetWindowRect(webview_id, response_sender) => {
|
||||
let window_rect = || {
|
||||
let Some(webview) = self.get_webview_handle(webview_id) else {
|
||||
return DeviceIndependentIntRect::default();
|
||||
};
|
||||
let hidpi_scale_factor = webview.hidpi_scale_factor();
|
||||
let Some(screen_geometry) = webview.delegate().screen_geometry(webview) else {
|
||||
return DeviceIndependentIntRect::default();
|
||||
};
|
||||
|
||||
(screen_geometry.window_rect.to_f32() / hidpi_scale_factor)
|
||||
.round()
|
||||
.to_i32()
|
||||
};
|
||||
|
||||
if let Err(error) = response_sender.send(window_rect()) {
|
||||
warn!("Failed to respond to GetWindowRect: {error}");
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ use euclid::default::Size2D as UntypedSize2D;
|
|||
use ipc_channel::ipc::{self, IpcSharedMemory};
|
||||
use profile_traits::mem::{OpaqueSender, ReportsChan};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use servo_geometry::{DeviceIndependentIntRect, DeviceIndependentIntSize};
|
||||
use servo_geometry::DeviceIndependentIntSize;
|
||||
use webrender_api::units::{DevicePoint, LayoutVector2D, TexelRect};
|
||||
use webrender_api::{
|
||||
BuiltDisplayList, BuiltDisplayListDescriptor, ExternalImage, ExternalImageData,
|
||||
|
@ -152,9 +152,6 @@ pub enum CompositorMsg {
|
|||
AddFontInstance(FontInstanceKey, FontKey, f32, FontInstanceFlags),
|
||||
/// Remove the given font resources from our WebRender instance.
|
||||
RemoveFonts(Vec<FontKey>, Vec<FontInstanceKey>),
|
||||
|
||||
/// Get the client window size and position.
|
||||
GetClientWindowRect(WebViewId, IpcSender<DeviceIndependentIntRect>),
|
||||
/// Get the size of the screen that the client window inhabits.
|
||||
GetScreenSize(WebViewId, IpcSender<DeviceIndependentIntSize>),
|
||||
/// Get the available screen size, without system interface elements such as menus, docks, and
|
||||
|
|
|
@ -31,6 +31,7 @@ use malloc_size_of_derive::MallocSizeOf;
|
|||
use num_derive::FromPrimitive;
|
||||
use pixels::RasterImage;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use servo_geometry::DeviceIndependentIntRect;
|
||||
use servo_url::ServoUrl;
|
||||
use strum_macros::IntoStaticStr;
|
||||
use style::queries::values::PrefersColorScheme;
|
||||
|
@ -363,6 +364,8 @@ pub enum EmbedderMsg {
|
|||
NewFavicon(WebViewId, ServoUrl),
|
||||
/// The history state has changed.
|
||||
HistoryChanged(WebViewId, Vec<ServoUrl>, usize),
|
||||
/// Get the device independent window rectangle.
|
||||
GetWindowRect(WebViewId, IpcSender<DeviceIndependentIntRect>),
|
||||
/// Entered or exited fullscreen.
|
||||
NotifyFullscreenStateChanged(WebViewId, bool),
|
||||
/// The [`LoadStatus`] of the Given `WebView` has changed.
|
||||
|
@ -754,22 +757,25 @@ pub struct NotificationAction {
|
|||
}
|
||||
|
||||
/// Information about a `WebView`'s screen geometry and offset. This is used
|
||||
/// for the [Screen](https://drafts.csswg.org/cssom-view/#the-screen-interface)
|
||||
/// CSSOM APIs and `window.screenLeft` / `window.screenTop`.
|
||||
/// for the [Screen](https://drafts.csswg.org/cssom-view/#the-screen-interface) CSSOM APIs
|
||||
/// and `window.screenLeft` / `window.screenX` / `window.screenTop` / `window.screenY` /
|
||||
/// `window.moveBy`/ `window.resizeBy` / `window.outerWidth` / `window.outerHeight` /
|
||||
/// `window.screen.availHeight` / `window.screen.availWidth`.
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub struct ScreenGeometry {
|
||||
/// The size of the screen in device pixels. This will be converted to
|
||||
/// CSS pixels based on the pixel scaling of the `WebView`.
|
||||
pub size: DeviceIntSize,
|
||||
/// The available size of the screen in device pixels. This size is the size
|
||||
/// The available size of the screen in device pixels for the purposes of
|
||||
/// the `window.screen.availHeight` / `window.screen.availWidth`. This is the size
|
||||
/// available for web content on the screen, and should be `size` minus any system
|
||||
/// toolbars, docks, and interface elements. This will be converted to
|
||||
/// CSS pixels based on the pixel scaling of the `WebView`.
|
||||
pub available_size: DeviceIntSize,
|
||||
/// The offset of the `WebView` in device pixels for the purposes of the `window.screenLeft`
|
||||
/// and `window.screenTop` APIs. This will be converted to CSS pixels based on the pixel scaling
|
||||
/// of the `WebView`.
|
||||
pub offset: DeviceIntPoint,
|
||||
/// The rectangle the `WebView`'s containing window in device pixels for the purposes of the
|
||||
/// `window.screenLeft` and similar APIs. This will be converted to CSS pixels based
|
||||
/// on the pixel scaling of the `WebView`.
|
||||
pub window_rect: DeviceIntRect,
|
||||
}
|
||||
|
||||
impl From<SelectElementOption> for SelectElementOptionOrOptgroup {
|
||||
|
|
|
@ -17,7 +17,7 @@ use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawWindowHandle};
|
|||
use servo::servo_config::pref;
|
||||
use servo::servo_geometry::{DeviceIndependentIntRect, DeviceIndependentPixel};
|
||||
use servo::webrender_api::ScrollLocation;
|
||||
use servo::webrender_api::units::{DeviceIntPoint, DeviceIntSize, DevicePixel};
|
||||
use servo::webrender_api::units::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePixel};
|
||||
use servo::{
|
||||
Cursor, ImeEvent, InputEvent, Key, KeyState, KeyboardEvent, MouseButton as ServoMouseButton,
|
||||
MouseButtonAction, MouseButtonEvent, MouseLeaveEvent, MouseMoveEvent,
|
||||
|
@ -429,22 +429,22 @@ impl WindowPortsMethods for Window {
|
|||
0.0,
|
||||
(self.toolbar_height.get() * self.hidpi_scale_factor()).0,
|
||||
);
|
||||
|
||||
let screen_size = self.screen_size.to_f32() * hidpi_factor;
|
||||
|
||||
// FIXME: In reality, this should subtract screen space used by the system interface
|
||||
// elements, but it is difficult to get this value with `winit` currently. See:
|
||||
// See https://github.com/rust-windowing/winit/issues/2494
|
||||
let available_screen_size = screen_size - toolbar_size;
|
||||
|
||||
// Offset the WebView origin by the toolbar so that it reflects the actual viewport and
|
||||
// not the window origin.
|
||||
let window_origin = self.winit_window.outer_position().unwrap_or_default();
|
||||
let offset = winit_position_to_euclid_point(window_origin);
|
||||
let window_rect = DeviceIntRect::from_origin_and_size(
|
||||
winit_position_to_euclid_point(self.winit_window.outer_position().unwrap_or_default()),
|
||||
winit_size_to_euclid_size(self.winit_window.outer_size()).to_i32(),
|
||||
);
|
||||
|
||||
ScreenGeometry {
|
||||
size: screen_size.to_i32(),
|
||||
available_size: available_screen_size.to_i32(),
|
||||
offset,
|
||||
window_rect,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -68,7 +68,7 @@ impl WindowPortsMethods for Window {
|
|||
ScreenGeometry {
|
||||
size: self.screen_size,
|
||||
available_size: self.screen_size,
|
||||
offset: Default::default(),
|
||||
window_rect: self.inner_size.get().into(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -124,13 +124,12 @@ impl ServoDelegate for ServoShellServoDelegate {
|
|||
impl WebViewDelegate for RunningAppState {
|
||||
fn screen_geometry(&self, _webview: WebView) -> Option<ScreenGeometry> {
|
||||
let coord = self.callbacks.coordinates.borrow();
|
||||
let offset = coord.origin();
|
||||
let available_size = coord.size();
|
||||
let screen_size = coord.size();
|
||||
Some(ScreenGeometry {
|
||||
size: screen_size,
|
||||
available_size,
|
||||
offset,
|
||||
window_rect: DeviceIntRect::from_origin_and_size(coord.origin(), coord.size()),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,3 @@
|
|||
[close.py]
|
||||
[test_close_browsing_context_with_accepted_beforeunload_prompt[tab\]]
|
||||
expected: FAIL
|
||||
|
||||
[test_close_browsing_context_with_accepted_beforeunload_prompt[window\]]
|
||||
expected: FAIL
|
||||
|
||||
[test_element_usage_after_closing_browsing_context]
|
||||
expected: ERROR
|
||||
|
|
|
@ -211,9 +211,3 @@
|
|||
|
||||
[test_resettable_element_does_not_satisfy_validation_constraints[range-foo\]]
|
||||
expected: FAIL
|
||||
|
||||
[test_resettable_element_does_not_satisfy_validation_constraints[color-foo\]]
|
||||
expected: FAIL
|
||||
|
||||
[test_resettable_element_does_not_satisfy_validation_constraints[datetime-foo\]]
|
||||
expected: FAIL
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
[get.py]
|
||||
[test_payload]
|
||||
expected: FAIL
|
|
@ -1,3 +0,0 @@
|
|||
[alerts.py]
|
||||
[test_retain_tab_modal_status]
|
||||
expected: FAIL
|
|
@ -1,7 +1,4 @@
|
|||
[switch.py]
|
||||
[test_finds_exising_user_prompt_after_tab_switch[alert\]]
|
||||
expected: FAIL
|
||||
|
||||
[test_finds_exising_user_prompt_after_tab_switch[confirm\]]
|
||||
expected: ERROR
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue