diff --git a/Cargo.lock b/Cargo.lock index b35f268ed2b..4bbb902a20b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7139,6 +7139,7 @@ dependencies = [ "html5ever", "indexmap", "jstraceable_derive", + "keyboard-types", "libc", "log", "malloc_size_of_derive", diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index ead7ca4fb60..2505aba7603 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -336,11 +336,23 @@ impl ServoRenderer { _ => return None, } + let offset = details + .scroll_tree + .scroll_offset(pipeline_id.root_scroll_id()) + .unwrap_or_default(); + let point_in_initial_containing_block = + (item.point_in_viewport + offset).to_untyped(); + let info = &details.hit_test_items[item.tag.0 as usize]; Some(CompositorHitTestResult { pipeline_id, - point_in_viewport: item.point_in_viewport.to_untyped(), - point_relative_to_item: item.point_relative_to_item.to_untyped(), + point_in_viewport: Point2D::from_untyped(item.point_in_viewport.to_untyped()), + point_relative_to_initial_containing_block: Point2D::from_untyped( + point_in_initial_containing_block, + ), + point_relative_to_item: Point2D::from_untyped( + item.point_relative_to_item.to_untyped(), + ), node: UntrustedNodeAddress(info.node as *const c_void), cursor: info.cursor, scroll_tree_node: info.scroll_tree_node, diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 20b1456a4d1..62419e75984 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -34,7 +34,8 @@ use embedder_traits::{ UntrustedNodeAddress, WheelEvent, }; use encoding_rs::{Encoding, UTF_8}; -use euclid::default::{Point2D, Rect, Size2D}; +use euclid::Point2D; +use euclid::default::{Rect, Size2D}; use fnv::FnvHashMap; use html5ever::{LocalName, Namespace, QualName, local_name, ns}; use hyper_serde::Serde; @@ -50,7 +51,6 @@ use net_traits::pub_domains::is_pub_domain; use net_traits::request::{InsecureRequestsPolicy, RequestBuilder}; use net_traits::response::HttpsState; use net_traits::{FetchResponseListener, IpcSend, ReferrerPolicy}; -use num_traits::ToPrimitive; use percent_encoding::percent_decode; use profile_traits::ipc as profile_ipc; use profile_traits::time::TimerMetadataFrameType; @@ -69,6 +69,7 @@ use style::shared_lock::SharedRwLock as StyleSharedRwLock; use style::str::{split_html_space_chars, str_join}; use style::stylesheet_set::DocumentStylesheetSet; use style::stylesheets::{Origin, OriginSet, Stylesheet}; +use style_traits::CSSPixel; use stylo_atoms::Atom; use url::Host; use uuid::Uuid; @@ -425,7 +426,7 @@ pub(crate) struct Document { /// #[ignore_malloc_size_of = "Defined in std"] #[no_trace] - last_click_info: DomRefCell)>>, + last_click_info: DomRefCell)>>, /// ignore_destructive_writes_counter: Cell, /// @@ -1515,12 +1516,11 @@ impl Document { pub(crate) fn handle_mouse_button_event( &self, event: MouseButtonEvent, - hit_test_result: Option, - pressed_mouse_buttons: u16, + input_event: &ConstellationInputEvent, can_gc: CanGc, ) { // Ignore all incoming events without a hit test. - let Some(hit_test_result) = hit_test_result else { + let Some(hit_test_result) = &input_event.hit_test_result else { return; }; @@ -1556,9 +1556,10 @@ impl Document { let dom_event = DomRoot::upcast::(MouseEvent::for_platform_mouse_event( event, - pressed_mouse_buttons, + input_event.pressed_mouse_buttons, &self.window, - &hit_test_result, + hit_test_result, + input_event.active_keyboard_modifiers, can_gc, )); @@ -1592,23 +1593,13 @@ impl Document { if self.focus_transaction.borrow().is_some() { self.commit_focus_transaction(FocusInitiator::Local, can_gc); } - self.maybe_fire_dblclick( - hit_test_result.point_in_viewport, - node, - pressed_mouse_buttons, - can_gc, - ); + self.maybe_fire_dblclick(node, hit_test_result, input_event, can_gc); } // When the contextmenu event is triggered by right mouse button // the contextmenu event MUST be dispatched after the mousedown event. if let (MouseButtonAction::Down, MouseButton::Right) = (event.action, event.button) { - self.maybe_show_context_menu( - node.upcast(), - pressed_mouse_buttons, - hit_test_result.point_in_viewport, - can_gc, - ); + self.maybe_show_context_menu(node.upcast(), hit_test_result, input_event, can_gc); } } @@ -1616,13 +1607,10 @@ impl Document { fn maybe_show_context_menu( &self, target: &EventTarget, - pressed_mouse_buttons: u16, - client_point: Point2D, + hit_test_result: &CompositorHitTestResult, + input_event: &ConstellationInputEvent, can_gc: CanGc, ) { - let client_x = client_point.x.to_i32().unwrap_or(0); - let client_y = client_point.y.to_i32().unwrap_or(0); - // let menu_event = PointerEvent::new( &self.window, // window @@ -1631,32 +1619,30 @@ impl Document { EventCancelable::Cancelable, // cancelable Some(&self.window), // view 0, // detail - client_x, // screen_x - client_y, // screen_y - client_x, // client_x - client_y, // client_y - false, // ctrl_key - false, // alt_key - false, // shift_key - false, // meta_key - 2i16, // button, right mouse button - pressed_mouse_buttons, // buttons - None, // related_target - None, // point_in_target - PointerId::Mouse as i32, // pointer_id - 1, // width - 1, // height - 0.5, // pressure - 0.0, // tangential_pressure - 0, // tilt_x - 0, // tilt_y - 0, // twist - PI / 2.0, // altitude_angle - 0.0, // azimuth_angle - DOMString::from("mouse"), // pointer_type - true, // is_primary - vec![], // coalesced_events - vec![], // predicted_events + hit_test_result.point_in_viewport.to_i32(), + hit_test_result.point_in_viewport.to_i32(), + hit_test_result + .point_relative_to_initial_containing_block + .to_i32(), + input_event.active_keyboard_modifiers, + 2i16, // button, right mouse button + input_event.pressed_mouse_buttons, + None, // related_target + None, // point_in_target + PointerId::Mouse as i32, // pointer_id + 1, // width + 1, // height + 0.5, // pressure + 0.0, // tangential_pressure + 0, // tilt_x + 0, // tilt_y + 0, // twist + PI / 2.0, // altitude_angle + 0.0, // azimuth_angle + DOMString::from("mouse"), // pointer_type + true, // is_primary + vec![], // coalesced_events + vec![], // predicted_events can_gc, ); let event = menu_event.upcast::(); @@ -1678,14 +1664,14 @@ impl Document { fn maybe_fire_dblclick( &self, - click_pos: Point2D, target: &Node, - pressed_mouse_buttons: u16, + hit_test_result: &CompositorHitTestResult, + input_event: &ConstellationInputEvent, can_gc: CanGc, ) { // https://w3c.github.io/uievents/#event-type-dblclick let now = Instant::now(); - + let point_in_viewport = hit_test_result.point_in_viewport; let opt = self.last_click_info.borrow_mut().take(); if let Some((last_time, last_pos)) = opt { @@ -1694,7 +1680,7 @@ impl Document { let DBL_CLICK_DIST_THRESHOLD = pref!(dom_document_dblclick_dist) as u64; // Calculate distance between this click and the previous click. - let line = click_pos - last_pos; + let line = point_in_viewport - last_pos; let dist = (line.dot(line) as f64).sqrt(); if now.duration_since(last_time) < DBL_CLICK_TIMEOUT && @@ -1702,8 +1688,6 @@ impl Document { { // A double click has occurred if this click is within a certain time and dist. of previous click. let click_count = 2; - let client_x = click_pos.x as i32; - let client_y = click_pos.y as i32; let event = MouseEvent::new( &self.window, @@ -1712,16 +1696,14 @@ impl Document { EventCancelable::Cancelable, Some(&self.window), click_count, - client_x, - client_y, - client_x, - client_y, - false, - false, - false, - false, + point_in_viewport.to_i32(), + point_in_viewport.to_i32(), + hit_test_result + .point_relative_to_initial_containing_block + .to_i32(), + input_event.active_keyboard_modifiers, 0i16, - pressed_mouse_buttons, + input_event.pressed_mouse_buttons, None, None, can_gc, @@ -1735,23 +1717,20 @@ impl Document { } // Update last_click_info with the time and position of the click. - *self.last_click_info.borrow_mut() = Some((now, click_pos)); + *self.last_click_info.borrow_mut() = Some((now, point_in_viewport)); } #[allow(clippy::too_many_arguments)] pub(crate) fn fire_mouse_event( &self, - client_point: Point2D, target: &EventTarget, event_name: FireMouseEventType, can_bubble: EventBubbles, cancelable: EventCancelable, - pressed_mouse_buttons: u16, + hit_test_result: &CompositorHitTestResult, + input_event: &ConstellationInputEvent, can_gc: CanGc, ) { - let client_x = client_point.x.to_i32().unwrap_or(0); - let client_y = client_point.y.to_i32().unwrap_or(0); - MouseEvent::new( &self.window, DOMString::from(event_name.as_str()), @@ -1759,16 +1738,14 @@ impl Document { cancelable, Some(&self.window), 0i32, - client_x, - client_y, - client_x, - client_y, - false, - false, - false, - false, + hit_test_result.point_in_viewport.to_i32(), + hit_test_result.point_in_viewport.to_i32(), + hit_test_result + .point_relative_to_initial_containing_block + .to_i32(), + input_event.active_keyboard_modifiers, 0i16, - pressed_mouse_buttons, + input_event.pressed_mouse_buttons, None, None, can_gc, @@ -1989,13 +1966,12 @@ impl Document { #[allow(unsafe_code)] pub(crate) unsafe fn handle_mouse_move_event( &self, - hit_test_result: Option, - pressed_mouse_buttons: u16, + input_event: &ConstellationInputEvent, prev_mouse_over_target: &MutNullableDom, can_gc: CanGc, ) { // Ignore all incoming events without a hit test. - let Some(hit_test_result) = hit_test_result else { + let Some(hit_test_result) = &input_event.hit_test_result else { return; }; @@ -2036,12 +2012,12 @@ impl Document { } self.fire_mouse_event( - hit_test_result.point_in_viewport, old_target.upcast(), FireMouseEventType::Out, EventBubbles::Bubbles, EventCancelable::Cancelable, - pressed_mouse_buttons, + hit_test_result, + input_event, can_gc, ); @@ -2049,11 +2025,11 @@ impl Document { let event_target = DomRoot::from_ref(old_target.upcast::()); let moving_into = Some(DomRoot::from_ref(new_target.upcast::())); self.handle_mouse_enter_leave_event( - hit_test_result.point_in_viewport, - FireMouseEventType::Leave, - moving_into, event_target, - pressed_mouse_buttons, + moving_into, + FireMouseEventType::Leave, + hit_test_result, + input_event, can_gc, ); } @@ -2072,12 +2048,12 @@ impl Document { } self.fire_mouse_event( - hit_test_result.point_in_viewport, new_target.upcast(), FireMouseEventType::Over, EventBubbles::Bubbles, EventCancelable::Cancelable, - pressed_mouse_buttons, + hit_test_result, + input_event, can_gc, ); @@ -2086,11 +2062,11 @@ impl Document { .map(|old_target| DomRoot::from_ref(old_target.upcast::())); let event_target = DomRoot::from_ref(new_target.upcast::()); self.handle_mouse_enter_leave_event( - hit_test_result.point_in_viewport, - FireMouseEventType::Enter, - moving_from, event_target, - pressed_mouse_buttons, + moving_from, + FireMouseEventType::Enter, + hit_test_result, + input_event, can_gc, ); } @@ -2098,12 +2074,12 @@ impl Document { // Send mousemove event to topmost target, unless it's an iframe, in which case the // compositor should have also sent an event to the inner document. self.fire_mouse_event( - hit_test_result.point_in_viewport, new_target.upcast(), FireMouseEventType::Move, EventBubbles::Bubbles, EventCancelable::Cancelable, - pressed_mouse_buttons, + hit_test_result, + input_event, can_gc, ); @@ -2116,12 +2092,11 @@ impl Document { #[allow(unsafe_code)] pub(crate) fn handle_mouse_leave_event( &self, - hit_test_result: Option, - pressed_mouse_buttons: u16, + input_event: &ConstellationInputEvent, can_gc: CanGc, ) { // Ignore all incoming events without a hit test. - let Some(hit_test_result) = hit_test_result else { + let Some(hit_test_result) = &input_event.hit_test_result else { return; }; @@ -2138,31 +2113,31 @@ impl Document { } self.fire_mouse_event( - hit_test_result.point_in_viewport, node.upcast(), FireMouseEventType::Out, EventBubbles::Bubbles, EventCancelable::Cancelable, - pressed_mouse_buttons, + hit_test_result, + input_event, can_gc, ); self.handle_mouse_enter_leave_event( - hit_test_result.point_in_viewport, - FireMouseEventType::Leave, - None, node, - pressed_mouse_buttons, + None, + FireMouseEventType::Leave, + hit_test_result, + input_event, can_gc, ); } fn handle_mouse_enter_leave_event( &self, - client_point: Point2D, - event_type: FireMouseEventType, - related_target: Option>, event_target: DomRoot, - pressed_mouse_buttons: u16, + related_target: Option>, + event_type: FireMouseEventType, + hit_test_result: &CompositorHitTestResult, + input_event: &ConstellationInputEvent, can_gc: CanGc, ) { assert!(matches!( @@ -2197,12 +2172,12 @@ impl Document { for target in targets { self.fire_mouse_event( - client_point, target.upcast(), event_type, EventBubbles::DoesNotBubble, EventCancelable::NotCancelable, - pressed_mouse_buttons, + hit_test_result, + input_event, can_gc, ); } diff --git a/components/script/dom/htmlinputelement.rs b/components/script/dom/htmlinputelement.rs index 7c826580fad..b5386ad8d3a 100644 --- a/components/script/dom/htmlinputelement.rs +++ b/components/script/dom/htmlinputelement.rs @@ -2853,8 +2853,11 @@ impl VirtualMethods for HTMLInputElement { // now. if let Some(point_in_target) = mouse_event.point_in_target() { let window = self.owner_window(); - let index = - window.text_index_query(self.upcast::(), point_in_target, can_gc); + let index = window.text_index_query( + self.upcast::(), + point_in_target.to_untyped(), + can_gc, + ); // Position the caret at the click position or at the end of the current // value. let edit_point_index = match index { diff --git a/components/script/dom/mouseevent.rs b/components/script/dom/mouseevent.rs index 657101b6681..e2e304b195a 100644 --- a/components/script/dom/mouseevent.rs +++ b/components/script/dom/mouseevent.rs @@ -7,10 +7,12 @@ use std::default::Default; use dom_struct::dom_struct; use embedder_traits::CompositorHitTestResult; -use euclid::default::Point2D; +use euclid::Point2D; use js::rust::HandleObject; +use keyboard_types::Modifiers; use script_bindings::codegen::GenericBindings::WindowBinding::WindowMethods; use servo_config::pref; +use style_traits::CSSPixel; use crate::dom::bindings::codegen::Bindings::EventBinding::Event_Binding::EventMethods; use crate::dom::bindings::codegen::Bindings::MouseEventBinding; @@ -33,36 +35,36 @@ use crate::script_runtime::CanGc; pub(crate) struct MouseEvent { uievent: UIEvent, + /// The point on the screen of where this [`MouseEvent`] was originally triggered, + /// to use during the dispatch phase. + /// + /// See: /// - screen_x: Cell, - /// - screen_y: Cell, + #[no_trace] + screen_point: Cell>, + /// The point in the viewport of where this [`MouseEvent`] was originally triggered, + /// to use during the dispatch phase. + /// + /// See: /// - client_x: Cell, - /// - client_y: Cell, + #[no_trace] + client_point: Cell>, - page_x: Cell, - page_y: Cell, - x: Cell, - y: Cell, - offset_x: Cell, - offset_y: Cell, + /// The point in the initial containing block of where this [`MouseEvent`] was + /// originally triggered to use during the dispatch phase. + /// + /// See: + /// + /// + #[no_trace] + page_point: Cell>, - /// - ctrl_key: Cell, - - /// - shift_key: Cell, - - /// - alt_key: Cell, - - /// - meta_key: Cell, + /// The keyboard modifiers that were active when this mouse event was triggered. + #[no_trace] + modifiers: Cell, /// button: Cell, @@ -73,27 +75,17 @@ pub(crate) struct MouseEvent { /// related_target: MutNullableDom, #[no_trace] - point_in_target: Cell>>, + point_in_target: Cell>>, } impl MouseEvent { pub(crate) fn new_inherited() -> MouseEvent { MouseEvent { uievent: UIEvent::new_inherited(), - screen_x: Cell::new(0), - screen_y: Cell::new(0), - client_x: Cell::new(0), - client_y: Cell::new(0), - page_x: Cell::new(0), - page_y: Cell::new(0), - x: Cell::new(0), - y: Cell::new(0), - offset_x: Cell::new(0), - offset_y: Cell::new(0), - ctrl_key: Cell::new(false), - shift_key: Cell::new(false), - alt_key: Cell::new(false), - meta_key: Cell::new(false), + screen_point: Cell::new(Default::default()), + client_point: Cell::new(Default::default()), + page_point: Cell::new(Default::default()), + modifiers: Cell::new(Modifiers::empty()), button: Cell::new(0), buttons: Cell::new(0), related_target: Default::default(), @@ -121,18 +113,14 @@ impl MouseEvent { cancelable: EventCancelable, view: Option<&Window>, detail: i32, - screen_x: i32, - screen_y: i32, - client_x: i32, - client_y: i32, - ctrl_key: bool, - alt_key: bool, - shift_key: bool, - meta_key: bool, + screen_point: Point2D, + client_point: Point2D, + page_point: Point2D, + modifiers: Modifiers, button: i16, buttons: u16, related_target: Option<&EventTarget>, - point_in_target: Option>, + point_in_target: Option>, can_gc: CanGc, ) -> DomRoot { Self::new_with_proto( @@ -143,14 +131,10 @@ impl MouseEvent { cancelable, view, detail, - screen_x, - screen_y, - client_x, - client_y, - ctrl_key, - alt_key, - shift_key, - meta_key, + screen_point, + client_point, + page_point, + modifiers, button, buttons, related_target, @@ -168,18 +152,14 @@ impl MouseEvent { cancelable: EventCancelable, view: Option<&Window>, detail: i32, - screen_x: i32, - screen_y: i32, - client_x: i32, - client_y: i32, - ctrl_key: bool, - alt_key: bool, - shift_key: bool, - meta_key: bool, + screen_point: Point2D, + client_point: Point2D, + page_point: Point2D, + modifiers: Modifiers, button: i16, buttons: u16, related_target: Option<&EventTarget>, - point_in_target: Option>, + point_in_target: Option>, can_gc: CanGc, ) -> DomRoot { let ev = MouseEvent::new_uninitialized_with_proto(window, proto, can_gc); @@ -189,14 +169,10 @@ impl MouseEvent { cancelable, view, detail, - screen_x, - screen_y, - client_x, - client_y, - ctrl_key, - alt_key, - shift_key, - meta_key, + screen_point, + client_point, + page_point, + modifiers, button, buttons, related_target, @@ -214,18 +190,14 @@ impl MouseEvent { cancelable: EventCancelable, view: Option<&Window>, detail: i32, - screen_x: i32, - screen_y: i32, - client_x: i32, - client_y: i32, - ctrl_key: bool, - alt_key: bool, - shift_key: bool, - meta_key: bool, + screen_point: Point2D, + client_point: Point2D, + page_point: Point2D, + modifiers: Modifiers, button: i16, buttons: u16, related_target: Option<&EventTarget>, - point_in_target: Option>, + point_in_target: Option>, ) { self.uievent.initialize_ui_event( type_, @@ -235,32 +207,17 @@ impl MouseEvent { ); self.uievent.set_detail(detail); - - self.screen_x.set(screen_x); - self.screen_y.set(screen_y); - self.client_x.set(client_x); - self.client_y.set(client_y); - self.page_x.set(self.PageX()); - self.page_y.set(self.PageY()); - - // skip setting flags as they are absent - self.shift_key.set(shift_key); - self.ctrl_key.set(ctrl_key); - self.alt_key.set(alt_key); - self.meta_key.set(meta_key); - + self.screen_point.set(screen_point); + self.client_point.set(client_point); + self.page_point.set(page_point); + self.modifiers.set(modifiers); self.button.set(button); self.buttons.set(buttons); - // skip step 3: Initialize PointerLock attributes for MouseEvent with event, - // as movementX, movementY is absent - self.related_target.set(related_target); - - // below is not in the spec self.point_in_target.set(point_in_target); } - pub(crate) fn point_in_target(&self) -> Option> { + pub(crate) fn point_in_target(&self) -> Option> { self.point_in_target.get() } @@ -270,6 +227,7 @@ impl MouseEvent { pressed_mouse_buttons: u16, window: &Window, hit_test_result: &CompositorHitTestResult, + modifiers: Modifiers, can_gc: CanGc, ) -> DomRoot { let mouse_event_type_string = match event.action { @@ -278,8 +236,11 @@ impl MouseEvent { embedder_traits::MouseButtonAction::Down => "mousedown", }; - let client_x = hit_test_result.point_in_viewport.x as i32; - let client_y = hit_test_result.point_in_viewport.y as i32; + let client_point = hit_test_result.point_in_viewport.to_i32(); + let page_point = hit_test_result + .point_relative_to_initial_containing_block + .to_i32(); + let click_count = 1; let mouse_event = MouseEvent::new( window, @@ -288,14 +249,10 @@ impl MouseEvent { EventCancelable::Cancelable, Some(window), click_count, - client_x, - client_y, - client_x, - client_y, // TODO: Get real screen coordinates? - false, - false, - false, - false, + client_point, // TODO: Get real screen coordinates? + client_point, + page_point, + modifiers, event.button.into(), pressed_mouse_buttons, None, @@ -321,6 +278,10 @@ impl MouseEventMethods for MouseEvent { ) -> Fallible> { let bubbles = EventBubbles::from(init.parent.parent.parent.bubbles); let cancelable = EventCancelable::from(init.parent.parent.parent.cancelable); + let page_point = Point2D::new( + window.ScrollX() + init.clientX, + window.ScrollY() + init.clientY, + ); let event = MouseEvent::new_with_proto( window, proto, @@ -329,14 +290,10 @@ impl MouseEventMethods for MouseEvent { cancelable, init.parent.parent.view.as_deref(), init.parent.parent.detail, - init.screenX, - init.screenY, - init.clientX, - init.clientY, - init.parent.ctrlKey, - init.parent.altKey, - init.parent.shiftKey, - init.parent.metaKey, + Point2D::new(init.screenX, init.screenY), + Point2D::new(init.clientX, init.clientY), + page_point, + init.parent.modifiers(), init.button, init.buttons, init.relatedTarget.as_deref(), @@ -351,110 +308,128 @@ impl MouseEventMethods for MouseEvent { /// fn ScreenX(&self) -> i32 { - self.screen_x.get() + self.screen_point.get().x } /// fn ScreenY(&self) -> i32 { - self.screen_y.get() + self.screen_point.get().y } /// fn ClientX(&self) -> i32 { - self.client_x.get() + self.client_point.get().x } /// fn ClientY(&self) -> i32 { - self.client_y.get() + self.client_point.get().y } /// fn PageX(&self) -> i32 { + // The pageX attribute must follow these steps: + // > 1. If the event’s dispatch flag is set, return the horizontal coordinate of the + // > position where the event occurred relative to the origin of the initial containing + // > block and terminate these steps. if self.upcast::().dispatching() { - self.page_x.get() - } else { - self.global().as_window().ScrollX() + self.client_x.get() + return self.page_point.get().x; } + + // > 2. Let offset be the value of the scrollX attribute of the event’s associated + // > Window object, if there is one, or zero otherwise. + // > 3. Return the sum of offset and the value of the event’s clientX attribute. + self.global().as_window().ScrollX() + self.ClientX() } /// fn PageY(&self) -> i32 { + // The pageY attribute must follow these steps: + // > 1. If the event’s dispatch flag is set, return the vertical coordinate of the + // > position where the event occurred relative to the origin of the initial + // > containing block and terminate these steps. if self.upcast::().dispatching() { - self.page_y.get() - } else { - self.global().as_window().ScrollY() + self.client_y.get() + return self.page_point.get().y; } + + // > 2. Let offset be the value of the scrollY attribute of the event’s associated + // > Window object, if there is one, or zero otherwise. + // > 3. Return the sum of offset and the value of the event’s clientY attribute. + self.global().as_window().ScrollY() + self.ClientY() } /// fn X(&self) -> i32 { - self.client_x.get() + self.ClientX() } /// fn Y(&self) -> i32 { - self.client_y.get() + self.ClientY() } /// fn OffsetX(&self, can_gc: CanGc) -> i32 { + // > The offsetX attribute must follow these steps: + // > 1. If the event’s dispatch flag is set, return the x-coordinate of the position + // > where the event occurred relative to the origin of the padding edge of the + // > target node, ignoring the transforms that apply to the element and its + // > ancestors, and terminate these steps. let event = self.upcast::(); if event.dispatching() { - match event.GetTarget() { - Some(target) => { - if let Some(node) = target.downcast::() { - let rect = node.client_rect(can_gc); - self.client_x.get() - rect.origin.x - } else { - self.offset_x.get() - } - }, - None => self.offset_x.get(), - } - } else { - self.PageX() + let Some(target) = event.GetTarget() else { + return 0; + }; + let Some(node) = target.downcast::() else { + return 0; + }; + return self.ClientX() - node.client_rect(can_gc).origin.x; } + + // > 2. Return the value of the event’s pageX attribute. + self.PageX() } /// fn OffsetY(&self, can_gc: CanGc) -> i32 { + // > The offsetY attribute must follow these steps: + // > 1. If the event’s dispatch flag is set, return the y-coordinate of the + // > position where the event occurred relative to the origin of the padding edge of + // > the target node, ignoring the transforms that apply to the element and its + // > ancestors, and terminate these steps. let event = self.upcast::(); if event.dispatching() { - match event.GetTarget() { - Some(target) => { - if let Some(node) = target.downcast::() { - let rect = node.client_rect(can_gc); - self.client_y.get() - rect.origin.y - } else { - self.offset_y.get() - } - }, - None => self.offset_y.get(), - } - } else { - self.PageY() + let Some(target) = event.GetTarget() else { + return 0; + }; + let Some(node) = target.downcast::() else { + return 0; + }; + return self.ClientY() - node.client_rect(can_gc).origin.y; } + + // 2. Return the value of the event’s pageY attribute. + self.PageY() } /// fn CtrlKey(&self) -> bool { - self.ctrl_key.get() + self.modifiers.get().contains(Modifiers::CONTROL) } /// fn ShiftKey(&self) -> bool { - self.shift_key.get() + self.modifiers.get().contains(Modifiers::SHIFT) } /// fn AltKey(&self) -> bool { - self.alt_key.get() + self.modifiers.get().contains(Modifiers::ALT) } /// fn MetaKey(&self) -> bool { - self.meta_key.get() + self.modifiers.get().contains(Modifiers::META) } /// @@ -515,14 +490,32 @@ impl MouseEventMethods for MouseEvent { view_arg, detail_arg, ); - self.screen_x.set(screen_x_arg); - self.screen_y.set(screen_y_arg); - self.client_x.set(client_x_arg); - self.client_y.set(client_y_arg); - self.ctrl_key.set(ctrl_key_arg); - self.alt_key.set(alt_key_arg); - self.shift_key.set(shift_key_arg); - self.meta_key.set(meta_key_arg); + self.screen_point + .set(Point2D::new(screen_x_arg, screen_y_arg)); + self.client_point + .set(Point2D::new(client_x_arg, client_y_arg)); + + let global = self.global(); + self.page_point.set(Point2D::new( + global.as_window().ScrollX() + client_x_arg, + global.as_window().ScrollY() + client_y_arg, + )); + + let mut modifiers = Modifiers::empty(); + if ctrl_key_arg { + modifiers.insert(Modifiers::CONTROL); + } + if alt_key_arg { + modifiers.insert(Modifiers::ALT); + } + if shift_key_arg { + modifiers.insert(Modifiers::SHIFT); + } + if meta_key_arg { + modifiers.insert(Modifiers::META); + } + self.modifiers.set(modifiers); + self.button.set(button_arg); self.related_target.set(related_target_arg); } diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 4e06bc1909b..95c1bd5a662 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -18,11 +18,13 @@ use bitflags::bitflags; use devtools_traits::NodeInfo; use dom_struct::dom_struct; use embedder_traits::UntrustedNodeAddress; +use euclid::Point2D; use euclid::default::{Rect, Size2D}; use html5ever::serialize::HtmlSerializer; use html5ever::{Namespace, Prefix, QualName, ns, serialize as html_serialize}; use js::jsapi::JSObject; use js::rust::HandleObject; +use keyboard_types::Modifiers; use layout_api::{ GenericLayoutData, HTMLCanvasData, HTMLMediaData, LayoutElementType, LayoutNodeType, QueryMsg, SVGSVGData, StyleData, TrustedNodeAddress, @@ -479,14 +481,10 @@ impl Node { EventCancelable::Cancelable, // Step 3: cancelable Some(&window), // Step 7: view 0, // detail uninitialized - 0, // coordinates uninitialized - 0, // coordinates uninitialized - 0, // coordinates uninitialized - 0, // coordinates uninitialized - false, // ctrl_key - false, // alt_key - false, // shift_key - false, // meta_key + Point2D::zero(), // coordinates uninitialized + Point2D::zero(), // coordinates uninitialized + Point2D::zero(), // coordinates uninitialized + Modifiers::empty(), // empty modifiers 0, // button, left mouse button 0, // buttons None, // related_target diff --git a/components/script/dom/pointerevent.rs b/components/script/dom/pointerevent.rs index d3cd9434e7d..64dd2aed685 100644 --- a/components/script/dom/pointerevent.rs +++ b/components/script/dom/pointerevent.rs @@ -5,8 +5,11 @@ use std::cell::Cell; use dom_struct::dom_struct; -use euclid::default::Point2D; +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; use crate::dom::bindings::cell::DomRefCell; @@ -95,18 +98,14 @@ impl PointerEvent { cancelable: EventCancelable, view: Option<&Window>, detail: i32, - screen_x: i32, - screen_y: i32, - client_x: i32, - client_y: i32, - ctrl_key: bool, - alt_key: bool, - shift_key: bool, - meta_key: bool, + screen_point: Point2D, + client_point: Point2D, + page_point: Point2D, + modifiers: Modifiers, button: i16, buttons: u16, related_target: Option<&EventTarget>, - point_in_target: Option>, + point_in_target: Option>, pointer_id: i32, width: i32, height: i32, @@ -131,14 +130,10 @@ impl PointerEvent { cancelable, view, detail, - screen_x, - screen_y, - client_x, - client_y, - ctrl_key, - alt_key, - shift_key, - meta_key, + screen_point, + client_point, + page_point, + modifiers, button, buttons, related_target, @@ -170,18 +165,14 @@ impl PointerEvent { cancelable: EventCancelable, view: Option<&Window>, detail: i32, - screen_x: i32, - screen_y: i32, - client_x: i32, - client_y: i32, - ctrl_key: bool, - alt_key: bool, - shift_key: bool, - meta_key: bool, + screen_point: Point2D, + client_point: Point2D, + page_point: Point2D, + modifiers: Modifiers, button: i16, buttons: u16, related_target: Option<&EventTarget>, - point_in_target: Option>, + point_in_target: Option>, pointer_id: i32, width: i32, height: i32, @@ -205,14 +196,10 @@ impl PointerEvent { cancelable, view, detail, - screen_x, - screen_y, - client_x, - client_y, - ctrl_key, - alt_key, - shift_key, - meta_key, + screen_point, + client_point, + page_point, + modifiers, button, buttons, related_target, @@ -247,6 +234,10 @@ impl PointerEventMethods for PointerEvent { ) -> DomRoot { let bubbles = EventBubbles::from(init.parent.parent.parent.parent.bubbles); let cancelable = EventCancelable::from(init.parent.parent.parent.parent.cancelable); + let page_point = Point2D::new( + window.ScrollX() + init.parent.clientX, + window.ScrollY() + init.parent.clientY, + ); PointerEvent::new_with_proto( window, proto, @@ -255,14 +246,10 @@ impl PointerEventMethods for PointerEvent { cancelable, init.parent.parent.parent.view.as_deref(), init.parent.parent.parent.detail, - init.parent.screenX, - init.parent.screenY, - init.parent.clientX, - init.parent.clientY, - init.parent.parent.ctrlKey, - init.parent.parent.altKey, - init.parent.parent.shiftKey, - init.parent.parent.metaKey, + Point2D::new(init.parent.screenX, init.parent.screenY), + Point2D::new(init.parent.clientX, init.parent.clientY), + page_point, + init.parent.parent.modifiers(), init.parent.button, init.parent.buttons, init.parent.relatedTarget.as_deref(), diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index 1a02b8a4ef1..0d59688f0a4 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -49,9 +49,9 @@ use devtools_traits::{ }; use embedder_traits::user_content_manager::UserContentManager; use embedder_traits::{ - CompositorHitTestResult, EmbedderMsg, FocusSequenceNumber, InputEvent, - JavaScriptEvaluationError, JavaScriptEvaluationId, MediaSessionActionType, MouseButton, - MouseButtonAction, MouseButtonEvent, Theme, ViewportDetails, WebDriverScriptCommand, + EmbedderMsg, FocusSequenceNumber, InputEvent, JavaScriptEvaluationError, + JavaScriptEvaluationId, MediaSessionActionType, MouseButton, MouseButtonAction, + MouseButtonEvent, Theme, ViewportDetails, WebDriverScriptCommand, }; use euclid::Point2D; use euclid::default::Rect; @@ -1021,20 +1021,14 @@ impl ScriptThread { fn process_mouse_move_event( &self, document: &Document, - hit_test_result: Option, - pressed_mouse_buttons: u16, + input_event: &ConstellationInputEvent, can_gc: CanGc, ) { // Get the previous target temporarily let prev_mouse_over_target = self.topmost_mouse_over_target.get(); unsafe { - document.handle_mouse_move_event( - hit_test_result, - pressed_mouse_buttons, - &self.topmost_mouse_over_target, - can_gc, - ) + document.handle_mouse_move_event(input_event, &self.topmost_mouse_over_target, can_gc) } // Short-circuit if nothing changed @@ -1109,29 +1103,15 @@ impl ScriptThread { match event.event { InputEvent::MouseButton(mouse_button_event) => { - document.handle_mouse_button_event( - mouse_button_event, - event.hit_test_result, - event.pressed_mouse_buttons, - can_gc, - ); + document.handle_mouse_button_event(mouse_button_event, &event, can_gc); }, InputEvent::MouseMove(_) => { // The event itself is unecessary here, because the point in the viewport is in the hit test. - self.process_mouse_move_event( - &document, - event.hit_test_result, - event.pressed_mouse_buttons, - can_gc, - ); + self.process_mouse_move_event(&document, &event, can_gc); }, InputEvent::MouseLeave(_) => { self.topmost_mouse_over_target.take(); - document.handle_mouse_leave_event( - event.hit_test_result, - event.pressed_mouse_buttons, - can_gc, - ); + document.handle_mouse_leave_event(&event, can_gc); }, InputEvent::Touch(touch_event) => { let touch_result = diff --git a/components/script_bindings/Cargo.toml b/components/script_bindings/Cargo.toml index 06d6b59e6c3..0833d155c9d 100644 --- a/components/script_bindings/Cargo.toml +++ b/components/script_bindings/Cargo.toml @@ -28,6 +28,7 @@ js = { workspace = true } jstraceable_derive = { path = "../jstraceable_derive" } libc = { workspace = true } log = { workspace = true } +keyboard-types = { workspace = true } malloc_size_of = { workspace = true } malloc_size_of_derive = { workspace = true } num-traits = { workspace = true } diff --git a/components/script_bindings/conversions.rs b/components/script_bindings/conversions.rs index 953dca889a8..adbf21d96e3 100644 --- a/components/script_bindings/conversions.rs +++ b/components/script_bindings/conversions.rs @@ -22,9 +22,11 @@ use js::rust::{ HandleId, HandleValue, MutableHandleValue, ToString, get_object_class, is_dom_class, is_dom_object, maybe_wrap_value, }; +use keyboard_types::Modifiers; use num_traits::Float; use crate::JSTraceable; +use crate::codegen::GenericBindings::EventModifierInitBinding::EventModifierInit; use crate::inheritance::Castable; use crate::num::Finite; use crate::reflector::{DomObject, Reflector}; @@ -589,3 +591,52 @@ pub(crate) unsafe fn windowproxy_from_handlevalue( let ptr = value.to_private() as *const D::WindowProxy; Ok(DomRoot::from_ref(&*ptr)) } + +impl EventModifierInit { + pub fn modifiers(&self) -> Modifiers { + let mut modifiers = Modifiers::empty(); + if self.altKey { + modifiers.insert(Modifiers::ALT); + } + if self.ctrlKey { + modifiers.insert(Modifiers::CONTROL); + } + if self.shiftKey { + modifiers.insert(Modifiers::SHIFT); + } + if self.metaKey { + modifiers.insert(Modifiers::META); + } + if self.keyModifierStateAltGraph { + modifiers.insert(Modifiers::ALT_GRAPH); + } + if self.keyModifierStateCapsLock { + modifiers.insert(Modifiers::CAPS_LOCK); + } + if self.keyModifierStateFn { + modifiers.insert(Modifiers::FN); + } + if self.keyModifierStateFnLock { + modifiers.insert(Modifiers::FN_LOCK); + } + if self.keyModifierStateHyper { + modifiers.insert(Modifiers::HYPER); + } + if self.keyModifierStateNumLock { + modifiers.insert(Modifiers::NUM_LOCK); + } + if self.keyModifierStateScrollLock { + modifiers.insert(Modifiers::SCROLL_LOCK); + } + if self.keyModifierStateSuper { + modifiers.insert(Modifiers::SUPER); + } + if self.keyModifierStateSymbol { + modifiers.insert(Modifiers::SYMBOL); + } + if self.keyModifierStateSymbolLock { + modifiers.insert(Modifiers::SYMBOL_LOCK); + } + modifiers + } +} diff --git a/components/shared/embedder/lib.rs b/components/shared/embedder/lib.rs index adbb2237e23..89fb41d7327 100644 --- a/components/shared/embedder/lib.rs +++ b/components/shared/embedder/lib.rs @@ -22,7 +22,7 @@ use std::sync::Arc; use base::id::{PipelineId, ScrollTreeNodeId, WebViewId}; use crossbeam_channel::Sender; -use euclid::{Scale, Size2D}; +use euclid::{Point2D, Scale, Size2D}; use http::{HeaderMap, Method, StatusCode}; use ipc_channel::ipc::IpcSender; use log::warn; @@ -770,10 +770,14 @@ pub struct CompositorHitTestResult { pub pipeline_id: PipelineId, /// The hit test point in the item's viewport. - pub point_in_viewport: euclid::default::Point2D, + pub point_in_viewport: Point2D, + + /// The hit test point relative to the root scroll node content origin / initial + /// containing block. + pub point_relative_to_initial_containing_block: Point2D, /// The hit test point relative to the item itself. - pub point_relative_to_item: euclid::default::Point2D, + pub point_relative_to_item: Point2D, /// The node address of the hit test result. pub node: UntrustedNodeAddress,