script: Minimize layout queries for window scroll offsets. (#38018)

These changes reduce the number of times we need to query layout for the
same information when creating mouse/pointer events.

Testing: No new tests required for maintaining existing behaviour.

Signed-off-by: Josh Matthews <josh@joshmatthews.net>
This commit is contained in:
Josh Matthews 2025-07-12 10:17:55 -04:00 committed by GitHub
parent 6dbd64e72d
commit d0a93a8b02
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 32 additions and 21 deletions

View file

@ -278,9 +278,10 @@ impl MouseEventMethods<crate::DomTypeHolder> for MouseEvent {
) -> Fallible<DomRoot<MouseEvent>> {
let bubbles = EventBubbles::from(init.parent.parent.parent.bubbles);
let cancelable = EventCancelable::from(init.parent.parent.parent.cancelable);
let scroll_offset = window.scroll_offset(can_gc);
let page_point = Point2D::new(
window.ScrollX() + init.clientX,
window.ScrollY() + init.clientY,
scroll_offset.x as i32 + init.clientX,
scroll_offset.y as i32 + init.clientY,
);
let event = MouseEvent::new_with_proto(
window,
@ -478,6 +479,7 @@ impl MouseEventMethods<crate::DomTypeHolder> for MouseEvent {
meta_key_arg: bool,
button_arg: i16,
related_target_arg: Option<&EventTarget>,
can_gc: CanGc,
) {
if self.upcast::<Event>().dispatching() {
return;
@ -496,9 +498,10 @@ impl MouseEventMethods<crate::DomTypeHolder> for MouseEvent {
.set(Point2D::new(client_x_arg, client_y_arg));
let global = self.global();
let scroll_offset = global.as_window().scroll_offset(can_gc);
self.page_point.set(Point2D::new(
global.as_window().ScrollX() + client_x_arg,
global.as_window().ScrollY() + client_y_arg,
scroll_offset.x as i32 + client_x_arg,
scroll_offset.y as i32 + client_y_arg,
));
let mut modifiers = Modifiers::empty();

View file

@ -8,7 +8,6 @@ use dom_struct::dom_struct;
use euclid::Point2D;
use js::rust::HandleObject;
use keyboard_types::Modifiers;
use script_bindings::codegen::GenericBindings::WindowBinding::WindowMethods;
use style_traits::CSSPixel;
use super::bindings::codegen::Bindings::MouseEventBinding::MouseEventMethods;
@ -234,9 +233,10 @@ impl PointerEventMethods<crate::DomTypeHolder> for PointerEvent {
) -> DomRoot<PointerEvent> {
let bubbles = EventBubbles::from(init.parent.parent.parent.parent.bubbles);
let cancelable = EventCancelable::from(init.parent.parent.parent.parent.cancelable);
let scroll_offset = window.scroll_offset(can_gc);
let page_point = Point2D::new(
window.ScrollX() + init.parent.clientX,
window.ScrollY() + init.parent.clientY,
scroll_offset.x as i32 + init.parent.clientX,
scroll_offset.y as i32 + init.parent.clientY,
);
PointerEvent::new_with_proto(
window,

View file

@ -95,6 +95,7 @@ impl WheelEvent {
delta_y,
delta_z,
delta_mode,
can_gc,
);
ev
@ -160,6 +161,7 @@ impl WheelEventMethods<crate::DomTypeHolder> for WheelEvent {
delta_y_arg: Finite<f64>,
delta_z_arg: Finite<f64>,
delta_mode_arg: u32,
can_gc: CanGc,
) {
if self.upcast::<Event>().dispatching() {
return;
@ -181,6 +183,7 @@ impl WheelEventMethods<crate::DomTypeHolder> for WheelEvent {
self.mouseevent.MetaKey(),
self.mouseevent.Button(),
self.mouseevent.GetRelatedTarget().as_deref(),
can_gc,
);
self.delta_x.set(delta_x_arg);
self.delta_y.set(delta_y_arg);

View file

@ -1596,11 +1596,7 @@ impl WindowMethods<crate::DomTypeHolder> for Window {
/// <https://drafts.csswg.org/cssom-view/#dom-window-scrollx>
fn ScrollX(&self) -> i32 {
self.scroll_offset_query_with_external_scroll_id(
self.pipeline_id().root_scroll_id(),
CanGc::note(),
)
.x as i32
self.scroll_offset(CanGc::note()).x as i32
}
// https://drafts.csswg.org/cssom-view/#dom-window-pagexoffset
@ -1610,11 +1606,7 @@ impl WindowMethods<crate::DomTypeHolder> for Window {
/// <https://drafts.csswg.org/cssom-view/#dom-window-scrolly>
fn ScrollY(&self) -> i32 {
self.scroll_offset_query_with_external_scroll_id(
self.pipeline_id().root_scroll_id(),
CanGc::note(),
)
.y as i32
self.scroll_offset(CanGc::note()).y as i32
}
// https://drafts.csswg.org/cssom-view/#dom-window-pageyoffset
@ -1656,10 +1648,11 @@ impl WindowMethods<crate::DomTypeHolder> for Window {
// https://drafts.csswg.org/cssom-view/#dom-window-scrollby
fn ScrollBy_(&self, x: f64, y: f64, can_gc: CanGc) {
let scroll_offset = self.scroll_offset(can_gc);
// Step 3
let left = x + self.ScrollX() as f64;
let left = x + scroll_offset.x as f64;
// Step 4
let top = y + self.ScrollY() as f64;
let top = y + scroll_offset.y as f64;
// Step 5
self.scroll(left, top, ScrollBehavior::Auto, can_gc);
@ -1984,6 +1977,13 @@ impl WindowMethods<crate::DomTypeHolder> for Window {
}
impl Window {
pub(crate) fn scroll_offset(&self, can_gc: CanGc) -> Vector2D<f32, LayoutPixel> {
self.scroll_offset_query_with_external_scroll_id(
self.pipeline_id().root_scroll_id(),
can_gc,
)
}
// https://heycam.github.io/webidl/#named-properties-object
// https://html.spec.whatwg.org/multipage/#named-access-on-the-window-object
#[allow(unsafe_code)]
@ -2102,7 +2102,8 @@ impl Window {
// Step 10
//TODO handling ongoing smooth scrolling
if x == self.ScrollX() as f64 && y == self.ScrollY() as f64 {
let scroll_offset = self.scroll_offset(can_gc);
if x == scroll_offset.x as f64 && y == scroll_offset.y as f64 {
return;
}

View file

@ -488,7 +488,7 @@ DOMInterfaces = {
},
'MouseEvent': {
'canGc': ['OffsetX', 'OffsetY'],
'canGc': ['InitMouseEvent', 'OffsetX', 'OffsetY'],
},
'NavigationPreloadManager': {
@ -649,6 +649,10 @@ DOMInterfaces = {
'additionalTraits': ['crate::interfaces::WebGL2RenderingContextHelpers'],
},
'WheelEvent': {
'canGc': ['InitWheelEvent'],
},
'Window': {
'canGc': ['Stop', 'Fetch', 'Scroll', 'Scroll_','ScrollBy', 'ScrollBy_', 'Stop', 'Fetch', 'Open', 'CreateImageBitmap', 'CreateImageBitmap_', 'TrustedTypes', 'WebdriverCallback', 'WebdriverException'],
'inRealms': ['Fetch', 'GetOpener', 'WebdriverCallback', 'WebdriverException'],