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 -->
This commit is contained in:
bors-servo 2016-04-04 12:48:39 +05:30
commit 241518a7d2
7 changed files with 88 additions and 0 deletions

View file

@ -20,6 +20,7 @@ use script::layout_interface::{ContentBoxResponse, ContentBoxesResponse, NodeGeo
use script::layout_interface::{HitTestResponse, LayoutRPC, OffsetParentResponse}; use script::layout_interface::{HitTestResponse, LayoutRPC, OffsetParentResponse};
use script::layout_interface::{ResolvedStyleResponse, ScriptLayoutChan, MarginStyleResponse}; use script::layout_interface::{ResolvedStyleResponse, ScriptLayoutChan, MarginStyleResponse};
use script_traits::LayoutMsg as ConstellationMsg; use script_traits::LayoutMsg as ConstellationMsg;
use script_traits::UntrustedNodeAddress;
use sequential; use sequential;
use std::cmp::{min, max}; use std::cmp::{min, max};
use std::ops::Deref; 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 { fn node_geometry(&self) -> NodeGeometryResponse {
let &LayoutRPCImpl(ref rw_data) = self; let &LayoutRPCImpl(ref rw_data) = self;
let rw_data = rw_data.lock().unwrap(); let rw_data = rw_data.lock().unwrap();

View file

@ -94,6 +94,7 @@ use net_traits::response::HttpsState;
use net_traits::{AsyncResponseTarget, PendingAsyncLoad}; use net_traits::{AsyncResponseTarget, PendingAsyncLoad};
use num::ToPrimitive; use num::ToPrimitive;
use script_thread::{MainThreadScriptChan, MainThreadScriptMsg, Runnable, ScriptChan}; use script_thread::{MainThreadScriptChan, MainThreadScriptMsg, Runnable, ScriptChan};
use script_traits::UntrustedNodeAddress;
use script_traits::{AnimationState, MouseButton, MouseEventType, MozBrowserEvent}; use script_traits::{AnimationState, MouseButton, MouseEventType, MozBrowserEvent};
use script_traits::{ScriptMsg as ConstellationMsg, ScriptToCompositorMsg}; use script_traits::{ScriptMsg as ConstellationMsg, ScriptToCompositorMsg};
use script_traits::{TouchEventType, TouchId}; use script_traits::{TouchEventType, TouchId};
@ -1480,6 +1481,12 @@ impl Document {
self.browsing_context.is_none() || !url_has_network_scheme(&self.url) 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)] #[derive(PartialEq, HeapSizeOf)]
@ -2601,6 +2608,40 @@ impl DocumentMethods for Document {
None => self.GetDocumentElement() 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 { fn is_scheme_host_port_tuple(url: &Url) -> bool {
@ -2672,3 +2713,4 @@ pub enum FocusEventType {
Focus, // Element gained focus. Doesn't bubble. Focus, // Element gained focus. Doesn't bubble.
Blur, // Element lost focus. Doesn't bubble. Blur, // Element lost focus. Doesn't bubble.
} }

View file

@ -184,6 +184,7 @@ partial interface Document {
// https://drafts.csswg.org/cssom-view/#dom-document-elementfrompoint // https://drafts.csswg.org/cssom-view/#dom-document-elementfrompoint
partial interface Document { partial interface Document {
Element? elementFromPoint(double x, double y); Element? elementFromPoint(double x, double y);
sequence<Element> elementsFromPoint(double x, double y);
}; };
// https://drafts.csswg.org/cssom/#extensions-to-the-document-interface // https://drafts.csswg.org/cssom/#extensions-to-the-document-interface

View file

@ -113,6 +113,8 @@ pub trait LayoutRPC {
fn offset_parent(&self) -> OffsetParentResponse; fn offset_parent(&self) -> OffsetParentResponse;
/// Query layout for the resolve values of the margin properties for an element. /// Query layout for the resolve values of the margin properties for an element.
fn margin_style(&self) -> MarginStyleResponse; fn margin_style(&self) -> MarginStyleResponse;
fn nodes_from_point(&self, point: Point2D<f32>) -> Vec<UntrustedNodeAddress>;
} }
#[derive(Clone)] #[derive(Clone)]

View file

@ -55,3 +55,5 @@ skip: true
skip: false skip: false
[WebIDL] [WebIDL]
skip: false skip: false
[cssom-view]
skip: false

View file

@ -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

View file

@ -0,0 +1,5 @@
[scrollingElement.html]
type: testharness
[Tests for scrollingElement]
expected: FAIL