diff --git a/components/layout/lib.rs b/components/layout/lib.rs index 50ab10f052cc..4c5bd766e244 100644 --- a/components/layout/lib.rs +++ b/components/layout/lib.rs @@ -73,7 +73,7 @@ mod linked_list; mod list_item; mod model; mod multicol; -mod opaque_node; +pub mod opaque_node; pub mod parallel; mod persistent_list; pub mod query; diff --git a/components/layout/query.rs b/components/layout/query.rs index 2f26fede59f7..b4008d24c60f 100644 --- a/components/layout/query.rs +++ b/components/layout/query.rs @@ -94,6 +94,9 @@ pub struct LayoutThreadData { /// A list of images requests that need to be initiated. pub pending_images: Vec, + + /// A queued response for the list of nodes at a given point. + pub nodes_from_point_response: Vec, } pub struct LayoutRPCImpl(pub Arc>); @@ -144,33 +147,10 @@ impl LayoutRPC for LayoutRPCImpl { } } - fn nodes_from_point(&self, - page_point: Point2D, - client_point: Point2D) -> Vec { - let page_point = Point2D::new(Au::from_f32_px(page_point.x), - Au::from_f32_px(page_point.y)); - let client_point = Point2D::new(Au::from_f32_px(client_point.x), - Au::from_f32_px(client_point.y)); - - let nodes_from_point_list = { - let &LayoutRPCImpl(ref rw_data) = self; - let rw_data = rw_data.lock().unwrap(); - let result = match rw_data.display_list { - None => panic!("Tried to hit test without a DisplayList"), - Some(ref display_list) => { - display_list.hit_test(&page_point, - &client_point, - &rw_data.stacking_context_scroll_offsets) - } - }; - - result - }; - - nodes_from_point_list.iter() - .rev() - .map(|metadata| metadata.node.to_untrusted_node_address()) - .collect() + fn nodes_from_point_response(&self) -> Vec { + let &LayoutRPCImpl(ref rw_data) = self; + let rw_data = rw_data.lock().unwrap(); + rw_data.nodes_from_point_response.clone() } fn node_geometry(&self) -> NodeGeometryResponse { @@ -193,8 +173,8 @@ impl LayoutRPC for LayoutRPCImpl { fn node_scroll_root_id(&self) -> NodeScrollRootIdResponse { NodeScrollRootIdResponse(self.0.lock() - .unwrap().scroll_root_id_response - .expect("scroll_root_id is not correctly fetched")) + .unwrap().scroll_root_id_response + .expect("scroll_root_id is not correctly fetched")) } /// Retrieves the resolved value for a CSS style property. diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs index dbb61b48ec6a..c196f394d511 100644 --- a/components/layout_thread/lib.rs +++ b/components/layout_thread/lib.rs @@ -63,6 +63,7 @@ use layout::flow::{self, Flow, ImmutableFlowUtils, MutableFlowUtils, MutableOwne use layout::flow_ref::FlowRef; use layout::incremental::{LayoutDamageComputation, REFLOW_ENTIRE_DOCUMENT}; use layout::layout_debug; +use layout::opaque_node::OpaqueNodeMethods; use layout::parallel; use layout::query::{LayoutRPCImpl, LayoutThreadData, process_content_box_request, process_content_boxes_request}; use layout::query::{process_margin_style_query, process_node_overflow_request, process_resolved_style_request}; @@ -459,6 +460,7 @@ impl LayoutThread { stacking_context_scroll_offsets: HashMap::new(), text_index_response: TextIndexResponse(None), pending_images: vec![], + nodes_from_point_response: vec![], })), error_reporter: CSSErrorReporter { pipelineid: id, @@ -977,6 +979,9 @@ impl LayoutThread { ReflowQueryType::HitTestQuery(..) => { rw_data.hit_test_response = (None, false); }, + ReflowQueryType::NodesFromPoint(..) => { + rw_data.nodes_from_point_response = Vec::new(); + }, ReflowQueryType::NodeGeometryQuery(_) => { rw_data.client_rect_response = Rect::zero(); }, @@ -1279,6 +1284,29 @@ impl LayoutThread { let node = unsafe { ServoLayoutNode::new(&node) }; rw_data.margin_style_response = process_margin_style_query(node); }, + ReflowQueryType::NodesFromPoint(page_point, client_point) => { + let page_point = Point2D::new(Au::from_f32_px(page_point.x), + Au::from_f32_px(page_point.y)); + let client_point = Point2D::new(Au::from_f32_px(client_point.x), + Au::from_f32_px(client_point.y)); + let nodes_from_point_list = { + let result = match rw_data.display_list { + None => panic!("Tried to hit test without a DisplayList"), + Some(ref display_list) => { + display_list.hit_test(&page_point, + &client_point, + &rw_data.stacking_context_scroll_offsets) + } + }; + + result + }; + + rw_data.nodes_from_point_response = nodes_from_point_list.iter() + .rev() + .map(|metadata| metadata.node.to_untrusted_node_address()) + .collect() + }, ReflowQueryType::NoQuery => {} } } @@ -1585,7 +1613,8 @@ fn get_ua_stylesheets() -> Result { /// or false if it only needs stacking-relative positions. fn reflow_query_type_needs_display_list(query_type: &ReflowQueryType) -> bool { match *query_type { - ReflowQueryType::HitTestQuery(..) | ReflowQueryType::TextIndexQuery(..) => true, + ReflowQueryType::HitTestQuery(..) | ReflowQueryType::TextIndexQuery(..) | + ReflowQueryType::NodesFromPoint(..) => true, ReflowQueryType::ContentBoxQuery(_) | ReflowQueryType::ContentBoxesQuery(_) | ReflowQueryType::NodeGeometryQuery(_) | ReflowQueryType::NodeScrollGeometryQuery(_) | ReflowQueryType::NodeOverflowQuery(_) | ReflowQueryType::NodeScrollRootIdQuery(_) | diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index d70976f236e2..991d93f7fcdf 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -1877,7 +1877,13 @@ impl Document { Point2D::new(client_point.x + self.window.PageXOffset() as f32, client_point.y + self.window.PageYOffset() as f32); - self.window.layout().nodes_from_point(page_point, *client_point) + if !self.window.reflow(ReflowGoal::ForScriptQuery, + ReflowQueryType::NodesFromPoint(page_point, *client_point), + ReflowReason::Query) { + return vec!(); + }; + + self.window.layout().nodes_from_point_response() } } diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 7a09394c3fda..64a303c9412f 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -1811,6 +1811,7 @@ fn debug_reflow_events(id: PipelineId, goal: &ReflowGoal, query_type: &ReflowQue ReflowQueryType::ContentBoxQuery(_n) => "\tContentBoxQuery", ReflowQueryType::ContentBoxesQuery(_n) => "\tContentBoxesQuery", ReflowQueryType::HitTestQuery(..) => "\tHitTestQuery", + ReflowQueryType::NodesFromPoint(..) => "\tNodesFromPoint", ReflowQueryType::NodeGeometryQuery(_n) => "\tNodeGeometryQuery", ReflowQueryType::NodeOverflowQuery(_n) => "\tNodeOverFlowQuery", ReflowQueryType::NodeScrollGeometryQuery(_n) => "\tNodeScrollGeometryQuery", diff --git a/components/script_layout_interface/message.rs b/components/script_layout_interface/message.rs index 80c354d02431..59c31ce66970 100644 --- a/components/script_layout_interface/message.rs +++ b/components/script_layout_interface/message.rs @@ -101,6 +101,7 @@ pub enum ReflowQueryType { OffsetParentQuery(TrustedNodeAddress), MarginStyleQuery(TrustedNodeAddress), TextIndexQuery(TrustedNodeAddress, i32, i32), + NodesFromPoint(Point2D, Point2D), } /// Information needed for a reflow. diff --git a/components/script_layout_interface/rpc.rs b/components/script_layout_interface/rpc.rs index 78e99571ee73..b07fa25a8c12 100644 --- a/components/script_layout_interface/rpc.rs +++ b/components/script_layout_interface/rpc.rs @@ -40,7 +40,8 @@ pub trait LayoutRPC { fn margin_style(&self) -> MarginStyleResponse; /// Requests the list of not-yet-loaded images that were encountered in the last reflow. fn pending_images(&self) -> Vec; - fn nodes_from_point(&self, page_point: Point2D, client_point: Point2D) -> Vec; + /// Requests the list of nodes from the given point. + fn nodes_from_point_response(&self) -> Vec; fn text_index(&self) -> TextIndexResponse; } diff --git a/tests/wpt/mozilla/meta/MANIFEST.json b/tests/wpt/mozilla/meta/MANIFEST.json index 9ecaa48d5597..8fdbc6e596e0 100644 --- a/tests/wpt/mozilla/meta/MANIFEST.json +++ b/tests/wpt/mozilla/meta/MANIFEST.json @@ -12598,6 +12598,12 @@ {} ] ], + "mozilla/document_elementsFromPoint.html": [ + [ + "/_mozilla/mozilla/document_elementsFromPoint.html", + {} + ] + ], "mozilla/document_getElementById.html": [ [ "/_mozilla/mozilla/document_getElementById.html", @@ -25137,6 +25143,10 @@ "12eef74e9ba1a62b0302df79633cab5c48f4977f", "testharness" ], + "mozilla/document_elementsFromPoint.html": [ + "00da2141b1143619351c6fbb66d677ca9002a4a8", + "testharness" + ], "mozilla/document_getElementById.html": [ "ae5270afde878c8fbe9b4a89c5c3f8ff609220dc", "testharness" diff --git a/tests/wpt/mozilla/tests/mozilla/document_elementsFromPoint.html b/tests/wpt/mozilla/tests/mozilla/document_elementsFromPoint.html new file mode 100644 index 000000000000..a17f0b698165 --- /dev/null +++ b/tests/wpt/mozilla/tests/mozilla/document_elementsFromPoint.html @@ -0,0 +1,10 @@ + + +document.elementsFromPoint does not crash due to a missing display list + + +