diff options
Diffstat (limited to 'components/script/dom/documentorshadowroot.rs')
-rw-r--r-- | components/script/dom/documentorshadowroot.rs | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/components/script/dom/documentorshadowroot.rs b/components/script/dom/documentorshadowroot.rs index c305afce1d6..91ce83af659 100644 --- a/components/script/dom/documentorshadowroot.rs +++ b/components/script/dom/documentorshadowroot.rs @@ -2,10 +2,22 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeBinding::NodeMethods; +use crate::dom::bindings::inheritance::Castable; +use crate::dom::bindings::num::Finite; use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::cssstylesheet::CSSStyleSheet; use crate::dom::document::Document; +use crate::dom::element::Element; +use crate::dom::htmlelement::HTMLElement; +use crate::dom::node; use crate::dom::shadowroot::ShadowRoot; +use crate::dom::window::Window; +use crate::dom::windowproxy::WindowProxy; +use euclid::Point2D; +use js::jsapi::JS_GetRuntime; +use script_layout_interface::message::{NodesFromPointQueryType, QueryMsg}; +use script_traits::UntrustedNodeAddress; macro_rules! proxy_call( ($fn_name:ident, $return_type:ty) => ( @@ -38,3 +50,150 @@ impl DocumentOrShadowRoot { proxy_call!(stylesheet_count, usize); proxy_call!(stylesheet_at, index, usize, Option<DomRoot<CSSStyleSheet>>); } + +// https://w3c.github.io/webcomponents/spec/shadow/#extensions-to-the-documentorshadowroot-mixin +#[must_root] +#[derive(JSTraceable, MallocSizeOf)] +pub struct DocumentOrShadowRootImpl { + has_browsing_context: bool, + window: Dom<Window>, +} + +impl DocumentOrShadowRootImpl { + pub fn new(window: &Window, has_browsing_context: bool) -> Self { + Self { + has_browsing_context, + window: Dom::from_ref(window), + } + } + + /// <https://html.spec.whatwg.org/multipage/#concept-document-bc> + #[inline] + pub fn browsing_context(&self) -> Option<DomRoot<WindowProxy>> { + if self.has_browsing_context { + self.window.undiscarded_window_proxy() + } else { + None + } + } + + pub fn nodes_from_point( + &self, + client_point: &Point2D<f32>, + reflow_goal: NodesFromPointQueryType, + ) -> Vec<UntrustedNodeAddress> { + if !self + .window + .layout_reflow(QueryMsg::NodesFromPointQuery(*client_point, reflow_goal)) + { + return vec![]; + }; + + self.window.layout().nodes_from_point_response() + } + + #[allow(unsafe_code)] + // https://drafts.csswg.org/cssom-view/#dom-document-elementfrompoint + pub fn element_from_point( + &self, + x: Finite<f64>, + y: Finite<f64>, + document_element: Option<DomRoot<Element>>, + ) -> Option<DomRoot<Element>> { + let x = *x as f32; + let y = *y as f32; + let point = &Point2D::new(x, y); + let viewport = self.window.window_size().initial_viewport; + + if self.browsing_context().is_none() { + return None; + } + + if x < 0.0 || y < 0.0 || x > viewport.width || y > viewport.height { + return None; + } + + match self + .nodes_from_point(point, NodesFromPointQueryType::Topmost) + .first() + { + Some(address) => { + let js_runtime = unsafe { JS_GetRuntime(self.window.get_cx()) }; + let node = unsafe { node::from_untrusted_node_address(js_runtime, *address) }; + let parent_node = node.GetParentNode().unwrap(); + let element_ref = node + .downcast::<Element>() + .unwrap_or_else(|| parent_node.downcast::<Element>().unwrap()); + + Some(DomRoot::from_ref(element_ref)) + }, + None => document_element, + } + } + + #[allow(unsafe_code)] + // https://drafts.csswg.org/cssom-view/#dom-document-elementsfrompoint + pub fn elements_from_point( + &self, + x: Finite<f64>, + y: Finite<f64>, + document_element: Option<DomRoot<Element>>, + ) -> Vec<DomRoot<Element>> { + let x = *x as f32; + let y = *y as f32; + let point = &Point2D::new(x, y); + let viewport = self.window.window_size().initial_viewport; + + if self.browsing_context().is_none() { + return vec![]; + } + + // Step 2 + if x < 0.0 || y < 0.0 || x > viewport.width || y > viewport.height { + return vec![]; + } + + let js_runtime = unsafe { JS_GetRuntime(self.window.get_cx()) }; + + // Step 1 and Step 3 + let nodes = self.nodes_from_point(point, NodesFromPointQueryType::All); + let mut elements: Vec<DomRoot<Element>> = nodes + .iter() + .flat_map(|&untrusted_node_address| { + let node = unsafe { + node::from_untrusted_node_address(js_runtime, untrusted_node_address) + }; + DomRoot::downcast::<Element>(node) + }) + .collect(); + + // Step 4 + if let Some(root_element) = document_element { + if elements.last() != Some(&root_element) { + elements.push(root_element); + } + } + + // Step 5 + elements + } + + // https://html.spec.whatwg.org/multipage/#dom-document-activeelement + pub fn get_active_element( + &self, + focused_element: Option<DomRoot<Element>>, + body: Option<DomRoot<HTMLElement>>, + document_element: Option<DomRoot<Element>>, + ) -> Option<DomRoot<Element>> { + // TODO: Step 2. + + match focused_element { + Some(element) => Some(element), // Step 3. and 4. + None => match body { + // Step 5. + Some(body) => Some(DomRoot::upcast(body)), + None => document_element, + }, + } + } +} |