script: Get the screen metrics from the WebViewDelegate instead of via the compositor (#38020)

Similar to #37960, previously, `AvailHeight`, `AvailWidth`, `Height`,
`Width` ask compositor for screen metrics. This PR moves the request to
embedder.

This simplifies code, and reduces workload of compositor, which is
busier most of time.

Testing: No behaviour change. Updated some tests. `Width/Height` matches
other browsers.

---------

Signed-off-by: Euclid Ye <yezhizhenjiakang@gmail.com>
This commit is contained in:
Euclid Ye 2025-07-13 00:07:39 +08:00 committed by GitHub
parent d0a93a8b02
commit d38ffb82b2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 79 additions and 102 deletions

View file

@ -912,26 +912,6 @@ impl IOCompositor {
.collect(); .collect();
let _ = result_sender.send((font_keys, font_instance_keys)); let _ = result_sender.send((font_keys, font_instance_keys));
}, },
CompositorMsg::GetScreenSize(webview_id, response_sender) => {
let screen_size = self
.webview_renderers
.get(webview_id)
.map(WebViewRenderer::screen_size)
.unwrap_or_default();
if let Err(error) = response_sender.send(screen_size) {
warn!("Sending response to get screen size failed ({error:?}).");
}
},
CompositorMsg::GetAvailableScreenSize(webview_id, response_sender) => {
let available_screen_size = self
.webview_renderers
.get(webview_id)
.map(WebViewRenderer::available_screen_size)
.unwrap_or_default();
if let Err(error) = response_sender.send(available_screen_size) {
warn!("Sending response to get screen size failed ({error:?}).");
}
},
CompositorMsg::Viewport(webview_id, viewport_description) => { CompositorMsg::Viewport(webview_id, viewport_description) => {
if let Some(webview) = self.webview_renderers.get_mut(webview_id) { if let Some(webview) = self.webview_renderers.get_mut(webview_id) {
webview.set_viewport_description(viewport_description); webview.set_viewport_description(viewport_description);
@ -981,16 +961,6 @@ impl IOCompositor {
.collect(); .collect();
let _ = result_sender.send((font_keys, font_instance_keys)); let _ = result_sender.send((font_keys, font_instance_keys));
}, },
CompositorMsg::GetScreenSize(_, response_sender) => {
if let Err(error) = response_sender.send(Default::default()) {
warn!("Sending response to get client window failed ({error:?}).");
}
},
CompositorMsg::GetAvailableScreenSize(_, response_sender) => {
if let Err(error) = response_sender.send(Default::default()) {
warn!("Sending response to get client window failed ({error:?}).");
}
},
CompositorMsg::NewWebRenderFrameReady(..) => { CompositorMsg::NewWebRenderFrameReady(..) => {
// Subtract from the number of pending frames, but do not do any compositing. // Subtract from the number of pending frames, but do not do any compositing.
self.pending_frames -= 1; self.pending_frames -= 1;

View file

@ -51,8 +51,6 @@ mod from_constellation {
Self::AddSystemFont(..) => target!("AddSystemFont"), Self::AddSystemFont(..) => target!("AddSystemFont"),
Self::AddFontInstance(..) => target!("AddFontInstance"), Self::AddFontInstance(..) => target!("AddFontInstance"),
Self::RemoveFonts(..) => target!("RemoveFonts"), Self::RemoveFonts(..) => target!("RemoveFonts"),
Self::GetScreenSize(..) => target!("GetScreenSize"),
Self::GetAvailableScreenSize(..) => target!("GetAvailableScreenSize"),
Self::CollectMemoryReport(..) => target!("CollectMemoryReport"), Self::CollectMemoryReport(..) => target!("CollectMemoryReport"),
Self::Viewport(..) => target!("Viewport"), Self::Viewport(..) => target!("Viewport"),
Self::GenerateImageKeysForPipeline(..) => target!("GenerateImageKeysForPipeline"), Self::GenerateImageKeysForPipeline(..) => target!("GenerateImageKeysForPipeline"),

View file

@ -19,7 +19,7 @@ use embedder_traits::{
MouseButtonEvent, MouseMoveEvent, ScrollEvent as EmbedderScrollEvent, ShutdownState, MouseButtonEvent, MouseMoveEvent, ScrollEvent as EmbedderScrollEvent, ShutdownState,
TouchEvent, TouchEventResult, TouchEventType, TouchId, ViewportDetails, TouchEvent, TouchEventResult, TouchEventType, TouchId, ViewportDetails,
}; };
use euclid::{Point2D, Scale, Size2D, Vector2D}; use euclid::{Point2D, Scale, Vector2D};
use fnv::FnvHashSet; use fnv::FnvHashSet;
use log::{debug, warn}; use log::{debug, warn};
use servo_geometry::DeviceIndependentPixel; use servo_geometry::DeviceIndependentPixel;
@ -1039,16 +1039,6 @@ impl WebViewRenderer {
old_rect != self.rect old_rect != self.rect
} }
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()
}
pub(crate) fn available_screen_size(&self) -> Size2D<i32, DeviceIndependentPixel> {
let screen_geometry = self.webview.screen_geometry().unwrap_or_default();
(screen_geometry.available_size.to_f32() / self.hidpi_scale_factor).to_i32()
}
pub fn set_viewport_description(&mut self, viewport_description: ViewportDescription) { pub fn set_viewport_description(&mut self, viewport_description: ViewportDescription) {
self.pending_scroll_zoom_events self.pending_scroll_zoom_events
.push(ScrollZoomEvent::ViewportZoom( .push(ScrollZoomEvent::ViewportZoom(

View file

@ -215,6 +215,7 @@ mod from_script {
Self::NewFavicon(..) => target_variant!("NewFavicon"), Self::NewFavicon(..) => target_variant!("NewFavicon"),
Self::HistoryChanged(..) => target_variant!("HistoryChanged"), Self::HistoryChanged(..) => target_variant!("HistoryChanged"),
Self::GetWindowRect(..) => target_variant!("GetWindowRect"), Self::GetWindowRect(..) => target_variant!("GetWindowRect"),
Self::GetScreenMetrics(..) => target_variant!("GetScreenMetrics"),
Self::NotifyFullscreenStateChanged(..) => { Self::NotifyFullscreenStateChanged(..) => {
target_variant!("NotifyFullscreenStateChanged") target_variant!("NotifyFullscreenStateChanged")
}, },

View file

@ -6,9 +6,12 @@ use std::f32;
use app_units::{Au, MAX_AU, MIN_AU}; use app_units::{Au, MAX_AU, MIN_AU};
use euclid::default::{Point2D as UntypedPoint2D, Rect as UntypedRect, Size2D as UntypedSize2D}; use euclid::default::{Point2D as UntypedPoint2D, Rect as UntypedRect, Size2D as UntypedSize2D};
use euclid::{Box2D, Length, Point2D, SideOffsets2D, Size2D, Vector2D}; use euclid::{Box2D, Length, Point2D, Scale, SideOffsets2D, Size2D, Vector2D};
use malloc_size_of_derive::MallocSizeOf; use malloc_size_of_derive::MallocSizeOf;
use webrender_api::units::{FramebufferPixel, LayoutPoint, LayoutRect, LayoutSize}; use webrender_api::units::{
DeviceIntRect, DeviceIntSize, DevicePixel, FramebufferPixel, LayoutPoint, LayoutRect,
LayoutSize,
};
// Units for use with euclid::length and euclid::scale_factor. // Units for use with euclid::length and euclid::scale_factor.
@ -51,6 +54,22 @@ pub trait MaxRect {
fn max_rect() -> Self; fn max_rect() -> Self;
} }
/// A helper function to convert a Device rect to CSS pixels.
pub fn convert_rect_to_css_pixel(
rect: DeviceIntRect,
scale: Scale<f32, DeviceIndependentPixel, DevicePixel>,
) -> DeviceIndependentIntRect {
(rect.to_f32() / scale).round().to_i32()
}
/// A helper function to convert a Device size to CSS pixels.
pub fn convert_size_to_css_pixel(
size: DeviceIntSize,
scale: Scale<f32, DeviceIndependentPixel, DevicePixel>,
) -> DeviceIndependentIntSize {
(size.to_f32() / scale).round().to_i32()
}
impl MaxRect for UntypedRect<Au> { impl MaxRect for UntypedRect<Au> {
#[inline] #[inline]
fn max_rect() -> Self { fn max_rect() -> Self {

View file

@ -2,16 +2,13 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use compositing_traits::CompositorMsg;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use euclid::Size2D; use embedder_traits::{EmbedderMsg, ScreenMetrics};
use profile_traits::ipc; use ipc_channel::ipc;
use servo_geometry::DeviceIndependentIntSize;
use style_traits::CSSPixel;
use crate::dom::bindings::codegen::Bindings::ScreenBinding::ScreenMethods; use crate::dom::bindings::codegen::Bindings::ScreenBinding::ScreenMethods;
use crate::dom::bindings::num::Finite; use crate::dom::bindings::num::Finite;
use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object}; use crate::dom::bindings::reflector::{Reflector, reflect_dom_object};
use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::window::Window; use crate::dom::window::Window;
use crate::script_runtime::CanGc; use crate::script_runtime::CanGc;
@ -34,58 +31,38 @@ impl Screen {
reflect_dom_object(Box::new(Screen::new_inherited(window)), window, can_gc) reflect_dom_object(Box::new(Screen::new_inherited(window)), window, can_gc)
} }
fn screen_size(&self) -> Size2D<u32, CSSPixel> { /// Retrives [`ScreenMetrics`] from the embedder.
let (sender, receiver) = fn screen_metrics(&self) -> ScreenMetrics {
ipc::channel::<DeviceIndependentIntSize>(self.global().time_profiler_chan().clone()) let (sender, receiver) = ipc::channel().expect("Failed to create IPC channel!");
.unwrap();
self.window
.compositor_api()
.sender()
.send(CompositorMsg::GetScreenSize(
self.window.webview_id(),
sender,
))
.unwrap();
let size = receiver.recv().unwrap_or(Size2D::zero()).to_u32();
Size2D::new(size.width, size.height)
}
fn screen_avail_size(&self) -> Size2D<u32, CSSPixel> { self.window.send_to_embedder(EmbedderMsg::GetScreenMetrics(
let (sender, receiver) = self.window.webview_id(),
ipc::channel::<DeviceIndependentIntSize>(self.global().time_profiler_chan().clone()) sender,
.unwrap(); ));
self.window
.compositor_api() receiver.recv().unwrap_or_default()
.sender()
.send(CompositorMsg::GetAvailableScreenSize(
self.window.webview_id(),
sender,
))
.unwrap();
let size = receiver.recv().unwrap_or(Size2D::zero()).to_u32();
Size2D::new(size.width, size.height)
} }
} }
impl ScreenMethods<crate::DomTypeHolder> for Screen { impl ScreenMethods<crate::DomTypeHolder> for Screen {
// https://drafts.csswg.org/cssom-view/#dom-screen-availwidth // https://drafts.csswg.org/cssom-view/#dom-screen-availwidth
fn AvailWidth(&self) -> Finite<f64> { fn AvailWidth(&self) -> Finite<f64> {
Finite::wrap(self.screen_avail_size().width as f64) Finite::wrap(self.screen_metrics().available_size.width as f64)
} }
// https://drafts.csswg.org/cssom-view/#dom-screen-availheight // https://drafts.csswg.org/cssom-view/#dom-screen-availheight
fn AvailHeight(&self) -> Finite<f64> { fn AvailHeight(&self) -> Finite<f64> {
Finite::wrap(self.screen_avail_size().height as f64) Finite::wrap(self.screen_metrics().available_size.height as f64)
} }
// https://drafts.csswg.org/cssom-view/#dom-screen-width // https://drafts.csswg.org/cssom-view/#dom-screen-width
fn Width(&self) -> Finite<f64> { fn Width(&self) -> Finite<f64> {
Finite::wrap(self.screen_size().width as f64) Finite::wrap(self.screen_metrics().screen_size.width as f64)
} }
// https://drafts.csswg.org/cssom-view/#dom-screen-height // https://drafts.csswg.org/cssom-view/#dom-screen-height
fn Height(&self) -> Finite<f64> { fn Height(&self) -> Finite<f64> {
Finite::wrap(self.screen_size().height as f64) Finite::wrap(self.screen_metrics().screen_size.height as f64)
} }
// https://drafts.csswg.org/cssom-view/#dom-screen-colordepth // https://drafts.csswg.org/cssom-view/#dom-screen-colordepth

View file

@ -100,7 +100,9 @@ use servo_config::opts::Opts;
use servo_config::prefs::Preferences; use servo_config::prefs::Preferences;
use servo_config::{opts, pref, prefs}; use servo_config::{opts, pref, prefs};
use servo_delegate::DefaultServoDelegate; use servo_delegate::DefaultServoDelegate;
use servo_geometry::DeviceIndependentIntRect; use servo_geometry::{
DeviceIndependentIntRect, convert_rect_to_css_pixel, convert_size_to_css_pixel,
};
use servo_media::ServoMedia; use servo_media::ServoMedia;
use servo_media::player::context::GlContext; use servo_media::player::context::GlContext;
use servo_url::ServoUrl; use servo_url::ServoUrl;
@ -1009,15 +1011,38 @@ impl Servo {
return DeviceIndependentIntRect::default(); return DeviceIndependentIntRect::default();
}; };
(screen_geometry.window_rect.to_f32() / hidpi_scale_factor) convert_rect_to_css_pixel(screen_geometry.window_rect, hidpi_scale_factor)
.round()
.to_i32()
}; };
if let Err(error) = response_sender.send(window_rect()) { if let Err(error) = response_sender.send(window_rect()) {
warn!("Failed to respond to GetWindowRect: {error}"); warn!("Failed to respond to GetWindowRect: {error}");
} }
}, },
EmbedderMsg::GetScreenMetrics(webview_id, response_sender) => {
let screen_metrics = || {
let Some(webview) = self.get_webview_handle(webview_id) else {
return ScreenMetrics::default();
};
let hidpi_scale_factor = webview.hidpi_scale_factor();
let Some(screen_geometry) = webview.delegate().screen_geometry(webview) else {
return ScreenMetrics::default();
};
ScreenMetrics {
screen_size: convert_size_to_css_pixel(
screen_geometry.size,
hidpi_scale_factor,
),
available_size: convert_size_to_css_pixel(
screen_geometry.available_size,
hidpi_scale_factor,
),
}
};
if let Err(error) = response_sender.send(screen_metrics()) {
warn!("Failed to respond to GetScreenMetrics: {error}");
}
},
} }
} }

View file

@ -33,7 +33,6 @@ use euclid::default::Size2D as UntypedSize2D;
use ipc_channel::ipc::{self, IpcSharedMemory}; use ipc_channel::ipc::{self, IpcSharedMemory};
use profile_traits::mem::{OpaqueSender, ReportsChan}; use profile_traits::mem::{OpaqueSender, ReportsChan};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use servo_geometry::DeviceIndependentIntSize;
use webrender_api::units::{DevicePoint, LayoutVector2D, TexelRect}; use webrender_api::units::{DevicePoint, LayoutVector2D, TexelRect};
use webrender_api::{ use webrender_api::{
BuiltDisplayList, BuiltDisplayListDescriptor, ExternalImage, ExternalImageData, BuiltDisplayList, BuiltDisplayListDescriptor, ExternalImage, ExternalImageData,
@ -152,13 +151,6 @@ pub enum CompositorMsg {
AddFontInstance(FontInstanceKey, FontKey, f32, FontInstanceFlags), AddFontInstance(FontInstanceKey, FontKey, f32, FontInstanceFlags),
/// Remove the given font resources from our WebRender instance. /// Remove the given font resources from our WebRender instance.
RemoveFonts(Vec<FontKey>, Vec<FontInstanceKey>), RemoveFonts(Vec<FontKey>, Vec<FontInstanceKey>),
/// 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
/// taskbars.
/// the client window inhabits.
GetAvailableScreenSize(WebViewId, IpcSender<DeviceIndependentIntSize>),
/// Measure the current memory usage associated with the compositor. /// Measure the current memory usage associated with the compositor.
/// The report must be sent on the provided channel once it's complete. /// The report must be sent on the provided channel once it's complete.
CollectMemoryReport(ReportsChan), CollectMemoryReport(ReportsChan),

View file

@ -31,7 +31,7 @@ use malloc_size_of_derive::MallocSizeOf;
use num_derive::FromPrimitive; use num_derive::FromPrimitive;
use pixels::RasterImage; use pixels::RasterImage;
use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::{Deserialize, Deserializer, Serialize, Serializer};
use servo_geometry::DeviceIndependentIntRect; use servo_geometry::{DeviceIndependentIntRect, DeviceIndependentIntSize};
use servo_url::ServoUrl; use servo_url::ServoUrl;
use strum_macros::IntoStaticStr; use strum_macros::IntoStaticStr;
use style::queries::values::PrefersColorScheme; use style::queries::values::PrefersColorScheme;
@ -310,6 +310,14 @@ pub struct ViewportDetails {
pub hidpi_scale_factor: Scale<f32, CSSPixel, DevicePixel>, pub hidpi_scale_factor: Scale<f32, CSSPixel, DevicePixel>,
} }
/// Unlike [`ScreenGeometry`], the data is in device-independent pixels
/// to be used by DOM APIs
#[derive(Default, Deserialize, Serialize)]
pub struct ScreenMetrics {
pub screen_size: DeviceIndependentIntSize,
pub available_size: DeviceIndependentIntSize,
}
#[derive(Deserialize, IntoStaticStr, Serialize)] #[derive(Deserialize, IntoStaticStr, Serialize)]
pub enum EmbedderMsg { pub enum EmbedderMsg {
/// A status message to be displayed by the browser chrome. /// A status message to be displayed by the browser chrome.
@ -366,6 +374,8 @@ pub enum EmbedderMsg {
HistoryChanged(WebViewId, Vec<ServoUrl>, usize), HistoryChanged(WebViewId, Vec<ServoUrl>, usize),
/// Get the device independent window rectangle. /// Get the device independent window rectangle.
GetWindowRect(WebViewId, IpcSender<DeviceIndependentIntRect>), GetWindowRect(WebViewId, IpcSender<DeviceIndependentIntRect>),
/// Get the device independent screen size and available size.
GetScreenMetrics(WebViewId, IpcSender<ScreenMetrics>),
/// Entered or exited fullscreen. /// Entered or exited fullscreen.
NotifyFullscreenStateChanged(WebViewId, bool), NotifyFullscreenStateChanged(WebViewId, bool),
/// The [`LoadStatus`] of the Given `WebView` has changed. /// The [`LoadStatus`] of the Given `WebView` has changed.

View file

@ -2,9 +2,6 @@
[test_document_element_is_interactable] [test_document_element_is_interactable]
expected: FAIL expected: FAIL
[test_iframe_is_interactable]
expected: FAIL
[test_not_a_focusable_element] [test_not_a_focusable_element]
expected: FAIL expected: FAIL

View file

@ -1,2 +0,0 @@
[linear_gradients_non_square_a.html]
expected: FAIL