diff options
author | bors-servo <lbergstrom+bors@mozilla.com> | 2016-04-04 12:48:39 +0530 |
---|---|---|
committer | bors-servo <lbergstrom+bors@mozilla.com> | 2016-04-04 12:48:39 +0530 |
commit | 241518a7d2c26da421d0273f101550215576c5a7 (patch) | |
tree | eed9c5cb5f33941a25835e1841db76608a2288ec | |
parent | d35ae3beb73158ec4c9ab20b3361e948379a4c90 (diff) | |
parent | 07584b9f29bf99362b74c75ea4291e3438768291 (diff) | |
download | servo-241518a7d2c26da421d0273f101550215576c5a7.tar.gz servo-241518a7d2c26da421d0273f101550215576c5a7.zip |
Auto merge of #10034 - rilut:implement-elementsfrompoint, r=emilio
Implement Document#elementsFromPoint
Fixes #9859.
I'm trying to implement Document#elementsFromPoint, which I need to reuse the `get_nodes_under_mouse` and `mouse_over` function which have been removed a days ago in #9715. So I added it back while I'm not sure if my implementation is correct. Any advice will be greatly appreciated.
<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="35" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/10034)
<!-- Reviewable:end -->
-rw-r--r-- | components/layout/query.rs | 19 | ||||
-rw-r--r-- | components/script/dom/document.rs | 42 | ||||
-rw-r--r-- | components/script/dom/webidls/Document.webidl | 1 | ||||
-rw-r--r-- | components/script/layout_interface.rs | 2 | ||||
-rw-r--r-- | tests/wpt/include.ini | 2 | ||||
-rw-r--r-- | tests/wpt/metadata/cssom-view/elementsFromPoint.html.ini | 17 | ||||
-rw-r--r-- | tests/wpt/metadata/cssom-view/scrollingElement.html.ini | 5 |
7 files changed, 88 insertions, 0 deletions
diff --git a/components/layout/query.rs b/components/layout/query.rs index 65296bc1b4e..2d914ece89a 100644 --- a/components/layout/query.rs +++ b/components/layout/query.rs @@ -20,6 +20,7 @@ use script::layout_interface::{ContentBoxResponse, ContentBoxesResponse, NodeGeo use script::layout_interface::{HitTestResponse, LayoutRPC, OffsetParentResponse}; use script::layout_interface::{ResolvedStyleResponse, ScriptLayoutChan, MarginStyleResponse}; use script_traits::LayoutMsg as ConstellationMsg; +use script_traits::UntrustedNodeAddress; use sequential; use std::cmp::{min, max}; use std::ops::Deref; @@ -85,6 +86,24 @@ impl LayoutRPC for LayoutRPCImpl { } } + fn nodes_from_point(&self, point: Point2D<f32>) -> Vec<UntrustedNodeAddress> { + let point = Point2D::new(Au::from_f32_px(point.x), Au::from_f32_px(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(point), + }; + + result + }; + + nodes_from_point_list.iter() + .map(|metadata| metadata.node.to_untrusted_node_address()) + .collect() + } + fn node_geometry(&self) -> NodeGeometryResponse { let &LayoutRPCImpl(ref rw_data) = self; let rw_data = rw_data.lock().unwrap(); diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index eb7e0da8a1b..a708e9b6cc6 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -94,6 +94,7 @@ use net_traits::response::HttpsState; use net_traits::{AsyncResponseTarget, PendingAsyncLoad}; use num::ToPrimitive; use script_thread::{MainThreadScriptChan, MainThreadScriptMsg, Runnable, ScriptChan}; +use script_traits::UntrustedNodeAddress; use script_traits::{AnimationState, MouseButton, MouseEventType, MozBrowserEvent}; use script_traits::{ScriptMsg as ConstellationMsg, ScriptToCompositorMsg}; use script_traits::{TouchEventType, TouchId}; @@ -1480,6 +1481,12 @@ impl Document { self.browsing_context.is_none() || !url_has_network_scheme(&self.url) } + + pub fn nodes_from_point(&self, page_point: &Point2D<f32>) -> Vec<UntrustedNodeAddress> { + assert!(self.GetDocumentElement().is_some()); + + self.window.layout().nodes_from_point(*page_point) + } } #[derive(PartialEq, HeapSizeOf)] @@ -2601,6 +2608,40 @@ impl DocumentMethods for Document { None => self.GetDocumentElement() } } + + #[allow(unsafe_code)] + // https://drafts.csswg.org/cssom-view/#dom-document-elementsfrompoint + fn ElementsFromPoint(&self, x: Finite<f64>, y: Finite<f64>) -> Vec<Root<Element>> { + let x = *x as f32; + let y = *y as f32; + let point = &Point2D { x: x, y: y }; + let window = window_from_node(self); + let viewport = window.window_size().unwrap().visible_viewport; + + // Step 2 + if x < 0.0 || y < 0.0 || x > viewport.width.get() || y > viewport.height.get() { + return vec!(); + } + + let js_runtime = unsafe { JS_GetRuntime(window.get_cx()) }; + + // Step 1 and Step 3 + let mut elements: Vec<Root<Element>> = self.nodes_from_point(point).iter() + .flat_map(|&untrusted_node_address| { + let node = node::from_untrusted_node_address(js_runtime, untrusted_node_address); + Root::downcast::<Element>(node) + }).collect(); + + // Step 4 + if let Some(root_element) = self.GetDocumentElement() { + if elements.last() != Some(&root_element) { + elements.push(root_element); + } + } + + // Step 5 + elements + } } fn is_scheme_host_port_tuple(url: &Url) -> bool { @@ -2672,3 +2713,4 @@ pub enum FocusEventType { Focus, // Element gained focus. Doesn't bubble. Blur, // Element lost focus. Doesn't bubble. } + diff --git a/components/script/dom/webidls/Document.webidl b/components/script/dom/webidls/Document.webidl index 845037e430c..7ca1dec527f 100644 --- a/components/script/dom/webidls/Document.webidl +++ b/components/script/dom/webidls/Document.webidl @@ -184,6 +184,7 @@ partial interface Document { // https://drafts.csswg.org/cssom-view/#dom-document-elementfrompoint partial interface Document { Element? elementFromPoint(double x, double y); + sequence<Element> elementsFromPoint(double x, double y); }; // https://drafts.csswg.org/cssom/#extensions-to-the-document-interface diff --git a/components/script/layout_interface.rs b/components/script/layout_interface.rs index 0d063f47bc1..07d8ac47edc 100644 --- a/components/script/layout_interface.rs +++ b/components/script/layout_interface.rs @@ -113,6 +113,8 @@ pub trait LayoutRPC { fn offset_parent(&self) -> OffsetParentResponse; /// Query layout for the resolve values of the margin properties for an element. fn margin_style(&self) -> MarginStyleResponse; + + fn nodes_from_point(&self, point: Point2D<f32>) -> Vec<UntrustedNodeAddress>; } #[derive(Clone)] diff --git a/tests/wpt/include.ini b/tests/wpt/include.ini index 77436641c36..75243947ba9 100644 --- a/tests/wpt/include.ini +++ b/tests/wpt/include.ini @@ -55,3 +55,5 @@ skip: true skip: false [WebIDL] skip: false +[cssom-view] + skip: false diff --git a/tests/wpt/metadata/cssom-view/elementsFromPoint.html.ini b/tests/wpt/metadata/cssom-view/elementsFromPoint.html.ini new file mode 100644 index 00000000000..ceb62f43b0b --- /dev/null +++ b/tests/wpt/metadata/cssom-view/elementsFromPoint.html.ini @@ -0,0 +1,17 @@ +[elementsFromPoint.html] + type: testharness + [co-ordinates larger than the viewport from in iframe] + expected: FAIL + + [SVG element at x,y] + expected: FAIL + + [transformed element at x,y] + expected: FAIL + + [no hit target at x,y] + expected: FAIL + + [No viewport available] + expected: FAIL + diff --git a/tests/wpt/metadata/cssom-view/scrollingElement.html.ini b/tests/wpt/metadata/cssom-view/scrollingElement.html.ini new file mode 100644 index 00000000000..8719b06550b --- /dev/null +++ b/tests/wpt/metadata/cssom-view/scrollingElement.html.ini @@ -0,0 +1,5 @@ +[scrollingElement.html] + type: testharness + [Tests for scrollingElement] + expected: FAIL + |