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();
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) => {
if let Some(webview) = self.webview_renderers.get_mut(webview_id) {
webview.set_viewport_description(viewport_description);
@ -981,16 +961,6 @@ impl IOCompositor {
.collect();
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(..) => {
// Subtract from the number of pending frames, but do not do any compositing.
self.pending_frames -= 1;

View file

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

View file

@ -19,7 +19,7 @@ use embedder_traits::{
MouseButtonEvent, MouseMoveEvent, ScrollEvent as EmbedderScrollEvent, ShutdownState,
TouchEvent, TouchEventResult, TouchEventType, TouchId, ViewportDetails,
};
use euclid::{Point2D, Scale, Size2D, Vector2D};
use euclid::{Point2D, Scale, Vector2D};
use fnv::FnvHashSet;
use log::{debug, warn};
use servo_geometry::DeviceIndependentPixel;
@ -1039,16 +1039,6 @@ impl WebViewRenderer {
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) {
self.pending_scroll_zoom_events
.push(ScrollZoomEvent::ViewportZoom(

View file

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

View file

@ -6,9 +6,12 @@ use std::f32;
use app_units::{Au, MAX_AU, MIN_AU};
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 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.
@ -51,6 +54,22 @@ pub trait MaxRect {
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> {
#[inline]
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
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use compositing_traits::CompositorMsg;
use dom_struct::dom_struct;
use euclid::Size2D;
use profile_traits::ipc;
use servo_geometry::DeviceIndependentIntSize;
use style_traits::CSSPixel;
use embedder_traits::{EmbedderMsg, ScreenMetrics};
use ipc_channel::ipc;
use crate::dom::bindings::codegen::Bindings::ScreenBinding::ScreenMethods;
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::window::Window;
use crate::script_runtime::CanGc;
@ -34,58 +31,38 @@ impl Screen {
reflect_dom_object(Box::new(Screen::new_inherited(window)), window, can_gc)
}
fn screen_size(&self) -> Size2D<u32, CSSPixel> {
let (sender, receiver) =
ipc::channel::<DeviceIndependentIntSize>(self.global().time_profiler_chan().clone())
.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)
}
/// Retrives [`ScreenMetrics`] from the embedder.
fn screen_metrics(&self) -> ScreenMetrics {
let (sender, receiver) = ipc::channel().expect("Failed to create IPC channel!");
fn screen_avail_size(&self) -> Size2D<u32, CSSPixel> {
let (sender, receiver) =
ipc::channel::<DeviceIndependentIntSize>(self.global().time_profiler_chan().clone())
.unwrap();
self.window
.compositor_api()
.sender()
.send(CompositorMsg::GetAvailableScreenSize(
self.window.send_to_embedder(EmbedderMsg::GetScreenMetrics(
self.window.webview_id(),
sender,
))
.unwrap();
let size = receiver.recv().unwrap_or(Size2D::zero()).to_u32();
Size2D::new(size.width, size.height)
));
receiver.recv().unwrap_or_default()
}
}
impl ScreenMethods<crate::DomTypeHolder> for Screen {
// https://drafts.csswg.org/cssom-view/#dom-screen-availwidth
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
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
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
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

View file

@ -100,7 +100,9 @@ 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_geometry::{
DeviceIndependentIntRect, convert_rect_to_css_pixel, convert_size_to_css_pixel,
};
use servo_media::ServoMedia;
use servo_media::player::context::GlContext;
use servo_url::ServoUrl;
@ -1009,15 +1011,38 @@ impl Servo {
return DeviceIndependentIntRect::default();
};
(screen_geometry.window_rect.to_f32() / hidpi_scale_factor)
.round()
.to_i32()
convert_rect_to_css_pixel(screen_geometry.window_rect, hidpi_scale_factor)
};
if let Err(error) = response_sender.send(window_rect()) {
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 profile_traits::mem::{OpaqueSender, ReportsChan};
use serde::{Deserialize, Serialize};
use servo_geometry::DeviceIndependentIntSize;
use webrender_api::units::{DevicePoint, LayoutVector2D, TexelRect};
use webrender_api::{
BuiltDisplayList, BuiltDisplayListDescriptor, ExternalImage, ExternalImageData,
@ -152,13 +151,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 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.
/// The report must be sent on the provided channel once it's complete.
CollectMemoryReport(ReportsChan),

View file

@ -31,7 +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_geometry::{DeviceIndependentIntRect, DeviceIndependentIntSize};
use servo_url::ServoUrl;
use strum_macros::IntoStaticStr;
use style::queries::values::PrefersColorScheme;
@ -310,6 +310,14 @@ pub struct ViewportDetails {
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)]
pub enum EmbedderMsg {
/// A status message to be displayed by the browser chrome.
@ -366,6 +374,8 @@ pub enum EmbedderMsg {
HistoryChanged(WebViewId, Vec<ServoUrl>, usize),
/// Get the device independent window rectangle.
GetWindowRect(WebViewId, IpcSender<DeviceIndependentIntRect>),
/// Get the device independent screen size and available size.
GetScreenMetrics(WebViewId, IpcSender<ScreenMetrics>),
/// Entered or exited fullscreen.
NotifyFullscreenStateChanged(WebViewId, bool),
/// The [`LoadStatus`] of the Given `WebView` has changed.

View file

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

View file

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