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

View file

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

View file

@ -95,6 +95,7 @@ impl WheelEvent {
delta_y, delta_y,
delta_z, delta_z,
delta_mode, delta_mode,
can_gc,
); );
ev ev
@ -160,6 +161,7 @@ impl WheelEventMethods<crate::DomTypeHolder> for WheelEvent {
delta_y_arg: Finite<f64>, delta_y_arg: Finite<f64>,
delta_z_arg: Finite<f64>, delta_z_arg: Finite<f64>,
delta_mode_arg: u32, delta_mode_arg: u32,
can_gc: CanGc,
) { ) {
if self.upcast::<Event>().dispatching() { if self.upcast::<Event>().dispatching() {
return; return;
@ -181,6 +183,7 @@ impl WheelEventMethods<crate::DomTypeHolder> for WheelEvent {
self.mouseevent.MetaKey(), self.mouseevent.MetaKey(),
self.mouseevent.Button(), self.mouseevent.Button(),
self.mouseevent.GetRelatedTarget().as_deref(), self.mouseevent.GetRelatedTarget().as_deref(),
can_gc,
); );
self.delta_x.set(delta_x_arg); self.delta_x.set(delta_x_arg);
self.delta_y.set(delta_y_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> /// <https://drafts.csswg.org/cssom-view/#dom-window-scrollx>
fn ScrollX(&self) -> i32 { fn ScrollX(&self) -> i32 {
self.scroll_offset_query_with_external_scroll_id( self.scroll_offset(CanGc::note()).x as i32
self.pipeline_id().root_scroll_id(),
CanGc::note(),
)
.x as i32
} }
// https://drafts.csswg.org/cssom-view/#dom-window-pagexoffset // 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> /// <https://drafts.csswg.org/cssom-view/#dom-window-scrolly>
fn ScrollY(&self) -> i32 { fn ScrollY(&self) -> i32 {
self.scroll_offset_query_with_external_scroll_id( self.scroll_offset(CanGc::note()).y as i32
self.pipeline_id().root_scroll_id(),
CanGc::note(),
)
.y as i32
} }
// https://drafts.csswg.org/cssom-view/#dom-window-pageyoffset // 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 // https://drafts.csswg.org/cssom-view/#dom-window-scrollby
fn ScrollBy_(&self, x: f64, y: f64, can_gc: CanGc) { fn ScrollBy_(&self, x: f64, y: f64, can_gc: CanGc) {
let scroll_offset = self.scroll_offset(can_gc);
// Step 3 // Step 3
let left = x + self.ScrollX() as f64; let left = x + scroll_offset.x as f64;
// Step 4 // Step 4
let top = y + self.ScrollY() as f64; let top = y + scroll_offset.y as f64;
// Step 5 // Step 5
self.scroll(left, top, ScrollBehavior::Auto, can_gc); self.scroll(left, top, ScrollBehavior::Auto, can_gc);
@ -1984,6 +1977,13 @@ impl WindowMethods<crate::DomTypeHolder> for Window {
} }
impl 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://heycam.github.io/webidl/#named-properties-object
// https://html.spec.whatwg.org/multipage/#named-access-on-the-window-object // https://html.spec.whatwg.org/multipage/#named-access-on-the-window-object
#[allow(unsafe_code)] #[allow(unsafe_code)]
@ -2102,7 +2102,8 @@ impl Window {
// Step 10 // Step 10
//TODO handling ongoing smooth scrolling //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; return;
} }

View file

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