mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
script: Pass more information to the MouseEvent
constructor (#37672)
- Instead of eagerly computing `pageX` and `pageY`, collect the offset from the content's initial containing block in the compositor and pass that information through to `MouseEvent`. This prevents a layout flush that was happening when eagerly trying to fetch `Document` scroll offsets. - Pass keyboard modifiers properly to `MouseEvent`. - Now all this information is stored and passed as `Point2D` (typed) and `Modifiers` which greatly reduces the amount of arguments that need to be passed around. Testing: It is difficult to test input events as they require WebDriver which isn't completely working yet. I have manually run Speedometer 2.1 and I have verified that this fixes the regression from #37601. Fixes: #37601. Signed-off-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
parent
50cf01cf3d
commit
0346a62214
11 changed files with 374 additions and 369 deletions
|
@ -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 {
|
|||
/// <https://w3c.github.io/uievents/#event-type-dblclick>
|
||||
#[ignore_malloc_size_of = "Defined in std"]
|
||||
#[no_trace]
|
||||
last_click_info: DomRefCell<Option<(Instant, Point2D<f32>)>>,
|
||||
last_click_info: DomRefCell<Option<(Instant, Point2D<f32, CSSPixel>)>>,
|
||||
/// <https://html.spec.whatwg.org/multipage/#ignore-destructive-writes-counter>
|
||||
ignore_destructive_writes_counter: Cell<u32>,
|
||||
/// <https://html.spec.whatwg.org/multipage/#ignore-opens-during-unload-counter>
|
||||
|
@ -1515,12 +1516,11 @@ impl Document {
|
|||
pub(crate) fn handle_mouse_button_event(
|
||||
&self,
|
||||
event: MouseButtonEvent,
|
||||
hit_test_result: Option<CompositorHitTestResult>,
|
||||
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::<Event>(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<f32>,
|
||||
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);
|
||||
|
||||
// <https://w3c.github.io/uievents/#contextmenu>
|
||||
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::<Event>();
|
||||
|
@ -1678,14 +1664,14 @@ impl Document {
|
|||
|
||||
fn maybe_fire_dblclick(
|
||||
&self,
|
||||
click_pos: Point2D<f32>,
|
||||
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<f32>,
|
||||
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<CompositorHitTestResult>,
|
||||
pressed_mouse_buttons: u16,
|
||||
input_event: &ConstellationInputEvent,
|
||||
prev_mouse_over_target: &MutNullableDom<Element>,
|
||||
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::<Node>());
|
||||
let moving_into = Some(DomRoot::from_ref(new_target.upcast::<Node>()));
|
||||
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::<Node>()));
|
||||
let event_target = DomRoot::from_ref(new_target.upcast::<Node>());
|
||||
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<CompositorHitTestResult>,
|
||||
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<f32>,
|
||||
event_type: FireMouseEventType,
|
||||
related_target: Option<DomRoot<Node>>,
|
||||
event_target: DomRoot<Node>,
|
||||
pressed_mouse_buttons: u16,
|
||||
related_target: Option<DomRoot<Node>>,
|
||||
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,
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue