mirror of
https://github.com/servo/servo.git
synced 2025-08-13 01:15:34 +01:00
compositor/layout: Rely on layout for fine-grained input event hit testing (#38480)
Before, the compositor was responsible for doing the hit testing during input events within a page. This change moves that hit testing to layout. With this change, epoch mismatches are no longer a bit deal and we can simply ignore them, as the Constellation and Script will take care of ignoring hit tests against scroll nodes and browsing contexts that no longer exist. This means that hit testing retry support can be removed. Add the concept of a Script `HitTest` that transforms the coarse-grained renderer hit test into one that hit tests against the actual layout items. Testing: Currently we do not have good tests for verifying the behavior of input events, but WebDriver tests should cover this. Fixes: This is part of #37932. Fixes: #26608. Fixes: #25282. Fixes: #38090. Signed-off-by: Martin Robinson <mrobinson@igalia.com> Co-authored-by: Oriol Brufau <obrufau@igalia.com> Co-authored-by: kongbai1996 <1782765876@qq.com>
This commit is contained in:
parent
c0cc8484f8
commit
ad805e3110
19 changed files with 348 additions and 511 deletions
|
@ -28,10 +28,10 @@ use data_url::mime::Mime;
|
|||
use devtools_traits::ScriptToDevtoolsControlMsg;
|
||||
use dom_struct::dom_struct;
|
||||
use embedder_traits::{
|
||||
AllowOrDeny, AnimationState, CompositorHitTestResult, ContextMenuResult, EditingActionEvent,
|
||||
EmbedderMsg, FocusSequenceNumber, ImeEvent, InputEvent, LoadStatus, MouseButton,
|
||||
MouseButtonAction, MouseButtonEvent, ScrollEvent, TouchEvent, TouchEventType, TouchId,
|
||||
UntrustedNodeAddress, WheelEvent,
|
||||
AllowOrDeny, AnimationState, ContextMenuResult, EditingActionEvent, EmbedderMsg,
|
||||
FocusSequenceNumber, ImeEvent, InputEvent, LoadStatus, MouseButton, MouseButtonAction,
|
||||
MouseButtonEvent, ScrollEvent, TouchEvent, TouchEventType, TouchId, UntrustedNodeAddress,
|
||||
WheelEvent,
|
||||
};
|
||||
use encoding_rs::{Encoding, UTF_8};
|
||||
use euclid::Point2D;
|
||||
|
@ -172,6 +172,7 @@ use crate::dom::htmlinputelement::HTMLInputElement;
|
|||
use crate::dom::htmlscriptelement::{HTMLScriptElement, ScriptResult};
|
||||
use crate::dom::htmltextareaelement::HTMLTextAreaElement;
|
||||
use crate::dom::htmltitleelement::HTMLTitleElement;
|
||||
use crate::dom::inputevent::HitTestResult;
|
||||
use crate::dom::intersectionobserver::IntersectionObserver;
|
||||
use crate::dom::keyboardevent::KeyboardEvent;
|
||||
use crate::dom::location::{Location, NavigationType};
|
||||
|
@ -1542,7 +1543,6 @@ impl Document {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
pub(crate) fn handle_mouse_button_event(
|
||||
&self,
|
||||
event: MouseButtonEvent,
|
||||
|
@ -1550,17 +1550,17 @@ impl Document {
|
|||
can_gc: CanGc,
|
||||
) {
|
||||
// Ignore all incoming events without a hit test.
|
||||
let Some(hit_test_result) = &input_event.hit_test_result else {
|
||||
let Some(hit_test_result) = self.window.hit_test_from_input_event(input_event) else {
|
||||
return;
|
||||
};
|
||||
|
||||
debug!(
|
||||
"{:?}: at {:?}",
|
||||
event.action, hit_test_result.point_in_viewport
|
||||
event.action, hit_test_result.point_in_frame
|
||||
);
|
||||
|
||||
let node = unsafe { node::from_untrusted_node_address(hit_test_result.node) };
|
||||
let Some(el) = node
|
||||
let Some(el) = hit_test_result
|
||||
.node
|
||||
.inclusive_ancestors(ShadowIncluding::Yes)
|
||||
.filter_map(DomRoot::downcast::<Element>)
|
||||
.next()
|
||||
|
@ -1591,7 +1591,7 @@ impl Document {
|
|||
event,
|
||||
input_event.pressed_mouse_buttons,
|
||||
&self.window,
|
||||
hit_test_result,
|
||||
&hit_test_result,
|
||||
input_event.active_keyboard_modifiers,
|
||||
can_gc,
|
||||
));
|
||||
|
@ -1626,13 +1626,13 @@ impl Document {
|
|||
if self.focus_transaction.borrow().is_some() {
|
||||
self.commit_focus_transaction(FocusInitiator::Local, can_gc);
|
||||
}
|
||||
self.maybe_fire_dblclick(node, hit_test_result, input_event, 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(), hit_test_result, input_event, can_gc);
|
||||
self.maybe_show_context_menu(node.upcast(), &hit_test_result, input_event, can_gc);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1640,7 +1640,7 @@ impl Document {
|
|||
fn maybe_show_context_menu(
|
||||
&self,
|
||||
target: &EventTarget,
|
||||
hit_test_result: &CompositorHitTestResult,
|
||||
hit_test_result: &HitTestResult,
|
||||
input_event: &ConstellationInputEvent,
|
||||
can_gc: CanGc,
|
||||
) {
|
||||
|
@ -1652,8 +1652,8 @@ impl Document {
|
|||
EventCancelable::Cancelable, // cancelable
|
||||
Some(&self.window), // view
|
||||
0, // detail
|
||||
hit_test_result.point_in_viewport.to_i32(),
|
||||
hit_test_result.point_in_viewport.to_i32(),
|
||||
hit_test_result.point_in_frame.to_i32(),
|
||||
hit_test_result.point_in_frame.to_i32(),
|
||||
hit_test_result
|
||||
.point_relative_to_initial_containing_block
|
||||
.to_i32(),
|
||||
|
@ -1698,13 +1698,13 @@ impl Document {
|
|||
fn maybe_fire_dblclick(
|
||||
&self,
|
||||
target: &Node,
|
||||
hit_test_result: &CompositorHitTestResult,
|
||||
hit_test_result: &HitTestResult,
|
||||
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 point_in_frame = hit_test_result.point_in_frame;
|
||||
let opt = self.last_click_info.borrow_mut().take();
|
||||
|
||||
if let Some((last_time, last_pos)) = opt {
|
||||
|
@ -1713,7 +1713,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 = point_in_viewport - last_pos;
|
||||
let line = point_in_frame - last_pos;
|
||||
let dist = (line.dot(line) as f64).sqrt();
|
||||
|
||||
if now.duration_since(last_time) < DBL_CLICK_TIMEOUT &&
|
||||
|
@ -1729,8 +1729,8 @@ impl Document {
|
|||
EventCancelable::Cancelable,
|
||||
Some(&self.window),
|
||||
click_count,
|
||||
point_in_viewport.to_i32(),
|
||||
point_in_viewport.to_i32(),
|
||||
point_in_frame.to_i32(),
|
||||
point_in_frame.to_i32(),
|
||||
hit_test_result
|
||||
.point_relative_to_initial_containing_block
|
||||
.to_i32(),
|
||||
|
@ -1750,7 +1750,7 @@ impl Document {
|
|||
}
|
||||
|
||||
// Update last_click_info with the time and position of the click.
|
||||
*self.last_click_info.borrow_mut() = Some((now, point_in_viewport));
|
||||
*self.last_click_info.borrow_mut() = Some((now, point_in_frame));
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
|
@ -1760,7 +1760,7 @@ impl Document {
|
|||
event_name: FireMouseEventType,
|
||||
can_bubble: EventBubbles,
|
||||
cancelable: EventCancelable,
|
||||
hit_test_result: &CompositorHitTestResult,
|
||||
hit_test_result: &HitTestResult,
|
||||
input_event: &ConstellationInputEvent,
|
||||
can_gc: CanGc,
|
||||
) {
|
||||
|
@ -1771,8 +1771,8 @@ impl Document {
|
|||
cancelable,
|
||||
Some(&self.window),
|
||||
0i32,
|
||||
hit_test_result.point_in_viewport.to_i32(),
|
||||
hit_test_result.point_in_viewport.to_i32(),
|
||||
hit_test_result.point_in_frame.to_i32(),
|
||||
hit_test_result.point_in_frame.to_i32(),
|
||||
hit_test_result
|
||||
.point_relative_to_initial_containing_block
|
||||
.to_i32(),
|
||||
|
@ -2004,12 +2004,12 @@ impl Document {
|
|||
can_gc: CanGc,
|
||||
) {
|
||||
// Ignore all incoming events without a hit test.
|
||||
let Some(hit_test_result) = &input_event.hit_test_result else {
|
||||
let Some(hit_test_result) = self.window.hit_test_from_input_event(input_event) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let node = unsafe { node::from_untrusted_node_address(hit_test_result.node) };
|
||||
let Some(new_target) = node
|
||||
let Some(new_target) = hit_test_result
|
||||
.node
|
||||
.inclusive_ancestors(ShadowIncluding::No)
|
||||
.filter_map(DomRoot::downcast::<Element>)
|
||||
.next()
|
||||
|
@ -2049,7 +2049,7 @@ impl Document {
|
|||
FireMouseEventType::Out,
|
||||
EventBubbles::Bubbles,
|
||||
EventCancelable::Cancelable,
|
||||
hit_test_result,
|
||||
&hit_test_result,
|
||||
input_event,
|
||||
can_gc,
|
||||
);
|
||||
|
@ -2061,7 +2061,7 @@ impl Document {
|
|||
event_target,
|
||||
moving_into,
|
||||
FireMouseEventType::Leave,
|
||||
hit_test_result,
|
||||
&hit_test_result,
|
||||
input_event,
|
||||
can_gc,
|
||||
);
|
||||
|
@ -2085,7 +2085,7 @@ impl Document {
|
|||
FireMouseEventType::Over,
|
||||
EventBubbles::Bubbles,
|
||||
EventCancelable::Cancelable,
|
||||
hit_test_result,
|
||||
&hit_test_result,
|
||||
input_event,
|
||||
can_gc,
|
||||
);
|
||||
|
@ -2098,7 +2098,7 @@ impl Document {
|
|||
event_target,
|
||||
moving_from,
|
||||
FireMouseEventType::Enter,
|
||||
hit_test_result,
|
||||
&hit_test_result,
|
||||
input_event,
|
||||
can_gc,
|
||||
);
|
||||
|
@ -2111,7 +2111,7 @@ impl Document {
|
|||
FireMouseEventType::Move,
|
||||
EventBubbles::Bubbles,
|
||||
EventCancelable::Cancelable,
|
||||
hit_test_result,
|
||||
&hit_test_result,
|
||||
input_event,
|
||||
can_gc,
|
||||
);
|
||||
|
@ -2129,15 +2129,15 @@ impl Document {
|
|||
can_gc: CanGc,
|
||||
) {
|
||||
// Ignore all incoming events without a hit test.
|
||||
let Some(hit_test_result) = &input_event.hit_test_result else {
|
||||
let Some(hit_test_result) = self.window.hit_test_from_input_event(input_event) else {
|
||||
return;
|
||||
};
|
||||
|
||||
self.window()
|
||||
.send_to_embedder(EmbedderMsg::Status(self.webview_id(), None));
|
||||
|
||||
let node = unsafe { node::from_untrusted_node_address(hit_test_result.node) };
|
||||
for element in node
|
||||
for element in hit_test_result
|
||||
.node
|
||||
.inclusive_ancestors(ShadowIncluding::No)
|
||||
.filter_map(DomRoot::downcast::<Element>)
|
||||
{
|
||||
|
@ -2146,19 +2146,19 @@ impl Document {
|
|||
}
|
||||
|
||||
self.fire_mouse_event(
|
||||
node.upcast(),
|
||||
hit_test_result.node.upcast(),
|
||||
FireMouseEventType::Out,
|
||||
EventBubbles::Bubbles,
|
||||
EventCancelable::Cancelable,
|
||||
hit_test_result,
|
||||
&hit_test_result,
|
||||
input_event,
|
||||
can_gc,
|
||||
);
|
||||
self.handle_mouse_enter_leave_event(
|
||||
node,
|
||||
hit_test_result.node.clone(),
|
||||
None,
|
||||
FireMouseEventType::Leave,
|
||||
hit_test_result,
|
||||
&hit_test_result,
|
||||
input_event,
|
||||
can_gc,
|
||||
);
|
||||
|
@ -2169,7 +2169,7 @@ impl Document {
|
|||
event_target: DomRoot<Node>,
|
||||
related_target: Option<DomRoot<Node>>,
|
||||
event_type: FireMouseEventType,
|
||||
hit_test_result: &CompositorHitTestResult,
|
||||
hit_test_result: &HitTestResult,
|
||||
input_event: &ConstellationInputEvent,
|
||||
can_gc: CanGc,
|
||||
) {
|
||||
|
@ -2224,12 +2224,12 @@ impl Document {
|
|||
can_gc: CanGc,
|
||||
) {
|
||||
// Ignore all incoming events without a hit test.
|
||||
let Some(hit_test_result) = &input_event.hit_test_result else {
|
||||
let Some(hit_test_result) = self.window.hit_test_from_input_event(input_event) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let node = unsafe { node::from_untrusted_node_address(hit_test_result.node) };
|
||||
let Some(el) = node
|
||||
let Some(el) = hit_test_result
|
||||
.node
|
||||
.inclusive_ancestors(ShadowIncluding::No)
|
||||
.filter_map(DomRoot::downcast::<Element>)
|
||||
.next()
|
||||
|
@ -2243,7 +2243,7 @@ impl Document {
|
|||
"{}: on {:?} at {:?}",
|
||||
wheel_event_type_string,
|
||||
node.debug_str(),
|
||||
hit_test_result.point_in_viewport
|
||||
hit_test_result.point_in_frame
|
||||
);
|
||||
|
||||
// https://w3c.github.io/uievents/#event-wheelevents
|
||||
|
@ -2254,8 +2254,8 @@ impl Document {
|
|||
EventCancelable::Cancelable,
|
||||
Some(&self.window),
|
||||
0i32,
|
||||
hit_test_result.point_in_viewport.to_i32(),
|
||||
hit_test_result.point_in_viewport.to_i32(),
|
||||
hit_test_result.point_in_frame.to_i32(),
|
||||
hit_test_result.point_in_frame.to_i32(),
|
||||
hit_test_result
|
||||
.point_relative_to_initial_containing_block
|
||||
.to_i32(),
|
||||
|
@ -2286,11 +2286,11 @@ impl Document {
|
|||
pub(crate) fn handle_touch_event(
|
||||
&self,
|
||||
event: TouchEvent,
|
||||
hit_test_result: Option<CompositorHitTestResult>,
|
||||
input_event: &ConstellationInputEvent,
|
||||
can_gc: CanGc,
|
||||
) -> TouchEventResult {
|
||||
// Ignore all incoming events without a hit test.
|
||||
let Some(hit_test_result) = hit_test_result else {
|
||||
let Some(hit_test_result) = self.window.hit_test_from_input_event(input_event) else {
|
||||
self.update_active_touch_points_when_early_return(event);
|
||||
return TouchEventResult::Forwarded;
|
||||
};
|
||||
|
@ -2303,8 +2303,8 @@ impl Document {
|
|||
TouchEventType::Cancel => "touchcancel",
|
||||
};
|
||||
|
||||
let node = unsafe { node::from_untrusted_node_address(hit_test_result.node) };
|
||||
let Some(el) = node
|
||||
let Some(el) = hit_test_result
|
||||
.node
|
||||
.inclusive_ancestors(ShadowIncluding::No)
|
||||
.filter_map(DomRoot::downcast::<Element>)
|
||||
.next()
|
||||
|
@ -2316,12 +2316,12 @@ impl Document {
|
|||
let target = DomRoot::upcast::<EventTarget>(el);
|
||||
let window = &*self.window;
|
||||
|
||||
let client_x = Finite::wrap(hit_test_result.point_in_viewport.x as f64);
|
||||
let client_y = Finite::wrap(hit_test_result.point_in_viewport.y as f64);
|
||||
let client_x = Finite::wrap(hit_test_result.point_in_frame.x as f64);
|
||||
let client_y = Finite::wrap(hit_test_result.point_in_frame.y as f64);
|
||||
let page_x =
|
||||
Finite::wrap(hit_test_result.point_in_viewport.x as f64 + window.PageXOffset() as f64);
|
||||
Finite::wrap(hit_test_result.point_in_frame.x as f64 + window.PageXOffset() as f64);
|
||||
let page_y =
|
||||
Finite::wrap(hit_test_result.point_in_viewport.y as f64 + window.PageYOffset() as f64);
|
||||
Finite::wrap(hit_test_result.point_in_frame.y as f64 + window.PageYOffset() as f64);
|
||||
|
||||
let touch = Touch::new(
|
||||
window, identifier, &target, client_x,
|
||||
|
|
|
@ -8,7 +8,7 @@ use std::fmt;
|
|||
|
||||
use embedder_traits::UntrustedNodeAddress;
|
||||
use js::rust::HandleValue;
|
||||
use layout_api::{ElementsFromPointFlags, ElementsFromPointResult, QueryMsg};
|
||||
use layout_api::ElementsFromPointFlags;
|
||||
use script_bindings::error::{Error, ErrorResult};
|
||||
use script_bindings::script_runtime::JSContext;
|
||||
use servo_arc::Arc;
|
||||
|
@ -137,15 +137,6 @@ impl DocumentOrShadowRoot {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn query_elements_from_point(
|
||||
&self,
|
||||
point: LayoutPoint,
|
||||
flags: ElementsFromPointFlags,
|
||||
) -> Vec<ElementsFromPointResult> {
|
||||
self.window.layout_reflow(QueryMsg::ElementsFromPoint);
|
||||
self.window.layout().query_elements_from_point(point, flags)
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
// https://drafts.csswg.org/cssom-view/#dom-document-elementfrompoint
|
||||
pub(crate) fn element_from_point(
|
||||
|
@ -168,7 +159,8 @@ impl DocumentOrShadowRoot {
|
|||
}
|
||||
|
||||
match self
|
||||
.query_elements_from_point(LayoutPoint::new(x, y), ElementsFromPointFlags::empty())
|
||||
.window
|
||||
.elements_from_point_query(LayoutPoint::new(x, y), ElementsFromPointFlags::empty())
|
||||
.first()
|
||||
{
|
||||
Some(result) => {
|
||||
|
@ -218,8 +210,9 @@ impl DocumentOrShadowRoot {
|
|||
}
|
||||
|
||||
// Step 1 and Step 3
|
||||
let nodes =
|
||||
self.query_elements_from_point(LayoutPoint::new(x, y), ElementsFromPointFlags::FindAll);
|
||||
let nodes = self
|
||||
.window
|
||||
.elements_from_point_query(LayoutPoint::new(x, y), ElementsFromPointFlags::FindAll);
|
||||
let mut elements: Vec<DomRoot<Element>> = nodes
|
||||
.iter()
|
||||
.flat_map(|result| {
|
||||
|
|
|
@ -3,7 +3,9 @@
|
|||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
use euclid::Point2D;
|
||||
use js::rust::HandleObject;
|
||||
use style_traits::CSSPixel;
|
||||
|
||||
use crate::dom::bindings::codegen::Bindings::InputEventBinding::{self, InputEventMethods};
|
||||
use crate::dom::bindings::codegen::Bindings::UIEventBinding::UIEvent_Binding::UIEventMethods;
|
||||
|
@ -11,6 +13,7 @@ use crate::dom::bindings::error::Fallible;
|
|||
use crate::dom::bindings::reflector::reflect_dom_object_with_proto;
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::node::Node;
|
||||
use crate::dom::uievent::UIEvent;
|
||||
use crate::dom::window::Window;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
@ -91,3 +94,12 @@ impl InputEventMethods<crate::DomTypeHolder> for InputEvent {
|
|||
self.uievent.IsTrusted()
|
||||
}
|
||||
}
|
||||
|
||||
/// A [`HitTestResult`] that is the result of doing a hit test based on a less-fine-grained
|
||||
/// `CompositorHitTestResult` against our current layout.
|
||||
pub(crate) struct HitTestResult {
|
||||
pub node: DomRoot<Node>,
|
||||
pub point_in_node: Point2D<f32, CSSPixel>,
|
||||
pub point_in_frame: Point2D<f32, CSSPixel>,
|
||||
pub point_relative_to_initial_containing_block: Point2D<f32, CSSPixel>,
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ use std::cell::Cell;
|
|||
use std::default::Default;
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
use embedder_traits::CompositorHitTestResult;
|
||||
use euclid::Point2D;
|
||||
use js::rust::HandleObject;
|
||||
use keyboard_types::Modifiers;
|
||||
|
@ -25,6 +24,7 @@ use crate::dom::bindings::root::{DomRoot, MutNullableDom};
|
|||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::event::{Event, EventBubbles, EventCancelable};
|
||||
use crate::dom::eventtarget::EventTarget;
|
||||
use crate::dom::inputevent::HitTestResult;
|
||||
use crate::dom::node::Node;
|
||||
use crate::dom::uievent::UIEvent;
|
||||
use crate::dom::window::Window;
|
||||
|
@ -226,7 +226,7 @@ impl MouseEvent {
|
|||
event: embedder_traits::MouseButtonEvent,
|
||||
pressed_mouse_buttons: u16,
|
||||
window: &Window,
|
||||
hit_test_result: &CompositorHitTestResult,
|
||||
hit_test_result: &HitTestResult,
|
||||
modifiers: Modifiers,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<Self> {
|
||||
|
@ -236,7 +236,7 @@ impl MouseEvent {
|
|||
embedder_traits::MouseButtonAction::Down => "mousedown",
|
||||
};
|
||||
|
||||
let client_point = hit_test_result.point_in_viewport.to_i32();
|
||||
let client_point = hit_test_result.point_in_frame.to_i32();
|
||||
let page_point = hit_test_result
|
||||
.point_relative_to_initial_containing_block
|
||||
.to_i32();
|
||||
|
@ -256,7 +256,7 @@ impl MouseEvent {
|
|||
event.button.into(),
|
||||
pressed_mouse_buttons,
|
||||
None,
|
||||
Some(hit_test_result.point_relative_to_item),
|
||||
Some(hit_test_result.point_in_node),
|
||||
can_gc,
|
||||
);
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ use std::cmp;
|
|||
use std::collections::hash_map::Entry;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::default::Default;
|
||||
use std::ffi::c_void;
|
||||
use std::io::{Write, stderr, stdout};
|
||||
use std::rc::Rc;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
@ -33,8 +34,8 @@ use dom_struct::dom_struct;
|
|||
use embedder_traits::user_content_manager::{UserContentManager, UserScript};
|
||||
use embedder_traits::{
|
||||
AlertResponse, ConfirmResponse, EmbedderMsg, GamepadEvent, GamepadSupportedHapticEffects,
|
||||
GamepadUpdateType, PromptResponse, SimpleDialog, Theme, ViewportDetails, WebDriverJSError,
|
||||
WebDriverJSResult, WebDriverLoadStatus,
|
||||
GamepadUpdateType, PromptResponse, SimpleDialog, Theme, UntrustedNodeAddress, ViewportDetails,
|
||||
WebDriverJSError, WebDriverJSResult, WebDriverLoadStatus,
|
||||
};
|
||||
use euclid::default::{Point2D as UntypedPoint2D, Rect as UntypedRect, Size2D as UntypedSize2D};
|
||||
use euclid::{Point2D, Scale, Size2D, Vector2D};
|
||||
|
@ -51,9 +52,10 @@ use js::rust::{
|
|||
MutableHandleValue,
|
||||
};
|
||||
use layout_api::{
|
||||
FragmentType, Layout, PendingImage, PendingImageState, PendingRasterizationImage, QueryMsg,
|
||||
ReflowGoal, ReflowPhasesRun, ReflowRequest, ReflowRequestRestyle, RestyleReason,
|
||||
TrustedNodeAddress, combine_id_with_fragment_type,
|
||||
ElementsFromPointFlags, ElementsFromPointResult, FragmentType, Layout, PendingImage,
|
||||
PendingImageState, PendingRasterizationImage, QueryMsg, ReflowGoal, ReflowPhasesRun,
|
||||
ReflowRequest, ReflowRequestRestyle, RestyleReason, TrustedNodeAddress,
|
||||
combine_id_with_fragment_type,
|
||||
};
|
||||
use malloc_size_of::MallocSizeOf;
|
||||
use media::WindowGLContext;
|
||||
|
@ -72,7 +74,7 @@ use script_bindings::codegen::GenericBindings::PerformanceBinding::PerformanceMe
|
|||
use script_bindings::conversions::SafeToJSValConvertible;
|
||||
use script_bindings::interfaces::WindowHelpers;
|
||||
use script_bindings::root::Root;
|
||||
use script_traits::ScriptThreadMessage;
|
||||
use script_traits::{ConstellationInputEvent, ScriptThreadMessage};
|
||||
use selectors::attr::CaseSensitivity;
|
||||
use servo_arc::Arc as ServoArc;
|
||||
use servo_config::{opts, pref};
|
||||
|
@ -88,7 +90,7 @@ use style_traits::CSSPixel;
|
|||
use stylo_atoms::Atom;
|
||||
use url::Position;
|
||||
use webrender_api::ExternalScrollId;
|
||||
use webrender_api::units::{DeviceIntSize, DevicePixel, LayoutPixel};
|
||||
use webrender_api::units::{DeviceIntSize, DevicePixel, LayoutPixel, LayoutPoint};
|
||||
|
||||
use super::bindings::codegen::Bindings::MessagePortBinding::StructuredSerializeOptions;
|
||||
use super::bindings::trace::HashMapTracedValues;
|
||||
|
@ -138,6 +140,7 @@ use crate::dom::history::History;
|
|||
use crate::dom::htmlcollection::{CollectionFilter, HTMLCollection};
|
||||
use crate::dom::htmliframeelement::HTMLIFrameElement;
|
||||
use crate::dom::idbfactory::IDBFactory;
|
||||
use crate::dom::inputevent::HitTestResult;
|
||||
use crate::dom::location::Location;
|
||||
use crate::dom::medialist::MediaList;
|
||||
use crate::dom::mediaquerylist::{MediaQueryList, MediaQueryListMatchState};
|
||||
|
@ -2589,6 +2592,41 @@ impl Window {
|
|||
.query_text_indext(node.to_opaque(), point_in_node)
|
||||
}
|
||||
|
||||
pub(crate) fn elements_from_point_query(
|
||||
&self,
|
||||
point: LayoutPoint,
|
||||
flags: ElementsFromPointFlags,
|
||||
) -> Vec<ElementsFromPointResult> {
|
||||
self.layout_reflow(QueryMsg::ElementsFromPoint);
|
||||
self.layout().query_elements_from_point(point, flags)
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
pub(crate) fn hit_test_from_input_event(
|
||||
&self,
|
||||
input_event: &ConstellationInputEvent,
|
||||
) -> Option<HitTestResult> {
|
||||
let compositor_hit_test_result = input_event.hit_test_result.as_ref()?;
|
||||
let result = self
|
||||
.elements_from_point_query(
|
||||
compositor_hit_test_result.point_in_viewport.cast_unit(),
|
||||
ElementsFromPointFlags::empty(),
|
||||
)
|
||||
.into_iter()
|
||||
.nth(0)?;
|
||||
|
||||
// SAFETY: This is safe because `Window::query_elements_from_point` has ensured that
|
||||
// layout has run and any OpaqueNodes that no longer refer to real nodes are gone.
|
||||
let address = UntrustedNodeAddress(result.node.0 as *const c_void);
|
||||
Some(HitTestResult {
|
||||
node: unsafe { from_untrusted_node_address(address) },
|
||||
point_in_node: result.point_in_target,
|
||||
point_in_frame: compositor_hit_test_result.point_in_viewport,
|
||||
point_relative_to_initial_containing_block: compositor_hit_test_result
|
||||
.point_relative_to_initial_containing_block,
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
pub(crate) fn init_window_proxy(&self, window_proxy: &WindowProxy) {
|
||||
assert!(self.window_proxy.get().is_none());
|
||||
|
|
|
@ -1137,8 +1137,7 @@ impl ScriptThread {
|
|||
document.handle_mouse_leave_event(&event, can_gc);
|
||||
},
|
||||
InputEvent::Touch(touch_event) => {
|
||||
let touch_result =
|
||||
document.handle_touch_event(touch_event, event.hit_test_result, can_gc);
|
||||
let touch_result = document.handle_touch_event(touch_event, &event, can_gc);
|
||||
if let (TouchEventResult::Processed(handled), true) =
|
||||
(touch_result, touch_event.is_cancelable())
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue