diff options
author | Fernando Jiménez Moreno <ferjmoreno@gmail.com> | 2019-01-24 18:16:20 +0100 |
---|---|---|
committer | Fernando Jiménez Moreno <ferjmoreno@gmail.com> | 2019-04-26 10:17:45 +0200 |
commit | 48975840dd3a4becfc5ee6adccabd303e06fc554 (patch) | |
tree | 6c76ac86fffba6222c6197bb7eca0e4ce17257e6 | |
parent | f3e707306f64d714e4b631fcd76513625469233e (diff) | |
download | servo-48975840dd3a4becfc5ee6adccabd303e06fc554.tar.gz servo-48975840dd3a4becfc5ee6adccabd303e06fc554.zip |
Unify DocumentOrShadowRoot implementation
-rw-r--r-- | components/script/dom/document.rs | 51 | ||||
-rw-r--r-- | components/script/dom/documentorshadowroot.rs | 159 | ||||
-rw-r--r-- | components/script/dom/macros.rs | 129 | ||||
-rw-r--r-- | components/script/dom/shadowroot.rs | 60 |
4 files changed, 238 insertions, 161 deletions
diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 2ff1516b231..5b1de4e6b85 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -43,7 +43,7 @@ use crate::dom::cssstylesheet::CSSStyleSheet; use crate::dom::customelementregistry::CustomElementDefinition; use crate::dom::customevent::CustomEvent; use crate::dom::documentfragment::DocumentFragment; -use crate::dom::documentorshadowroot::DocumentOrShadowRoot; +use crate::dom::documentorshadowroot::{DocumentOrShadowRoot, DocumentOrShadowRootImpl}; use crate::dom::documenttype::DocumentType; use crate::dom::domimplementation::DOMImplementation; use crate::dom::element::CustomElementCreationMode; @@ -114,7 +114,6 @@ use euclid::Point2D; use html5ever::{LocalName, Namespace, QualName}; use hyper_serde::Serde; use ipc_channel::ipc::{self, IpcSender}; -use js::jsapi::JS_GetRuntime; use js::jsapi::{JSContext, JSObject, JSRuntime}; use keyboard_types::{Key, KeyState, Modifiers}; use metrics::{ @@ -133,7 +132,7 @@ use num_traits::ToPrimitive; use profile_traits::ipc as profile_ipc; use profile_traits::time::{TimerMetadata, TimerMetadataFrameType, TimerMetadataReflowType}; use ref_slice::ref_slice; -use script_layout_interface::message::{Msg, NodesFromPointQueryType, QueryMsg, ReflowGoal}; +use script_layout_interface::message::{Msg, ReflowGoal}; use script_traits::{AnimationState, DocumentActivity, MouseButton, MouseEventType}; use script_traits::{MsDuration, ScriptMsg, TouchEventType, TouchId, UntrustedNodeAddress}; use servo_arc::Arc; @@ -267,6 +266,7 @@ impl ::style::stylesheets::StylesheetInDocument for StyleSheetInDocument { #[dom_struct] pub struct Document { node: Node, + document_or_shadow_root: DocumentOrShadowRootImpl, window: Dom<Window>, implementation: MutNullableDom<DOMImplementation>, #[ignore_malloc_size_of = "type from external crate"] @@ -488,6 +488,11 @@ impl Document { } #[inline] + pub fn browsing_context(&self) -> Option<DomRoot<WindowProxy>> { + self.document_or_shadow_root.browsing_context() + } + + #[inline] pub fn window(&self) -> &Window { &*self.window } @@ -2613,10 +2618,12 @@ impl Document { .and_then(|charset| Encoding::for_label(charset.as_str().as_bytes())) .unwrap_or(UTF_8); + let has_browsing_context = has_browsing_context == HasBrowsingContext::Yes; Document { node: Node::new_document_node(), + document_or_shadow_root: DocumentOrShadowRootImpl::new(window, has_browsing_context), window: Dom::from_ref(window), - has_browsing_context: has_browsing_context == HasBrowsingContext::Yes, + has_browsing_context, implementation: Default::default(), content_type, last_modified: last_modified, @@ -2665,7 +2672,7 @@ impl Document { deferred_scripts: Default::default(), asap_in_order_scripts_list: Default::default(), asap_scripts_set: Default::default(), - scripting_enabled: has_browsing_context == HasBrowsingContext::Yes, + scripting_enabled: has_browsing_context, animation_frame_ident: Cell::new(0), animation_frame_list: DomRefCell::new(vec![]), running_animation_callbacks: Cell::new(false), @@ -3246,8 +3253,6 @@ impl Document { } } } - - impl_document_or_shadow_root_helpers!(); } impl Element { @@ -3277,8 +3282,15 @@ impl ProfilerMetadataFactory for Document { } impl DocumentMethods for Document { - // https://w3c.github.io/webcomponents/spec/shadow/#extensions-to-the-documentorshadowroot-mixin - impl_document_or_shadow_root_methods!(Document); + // https://drafts.csswg.org/cssom/#dom-document-stylesheets + fn StyleSheets(&self) -> DomRoot<StyleSheetList> { + self.stylesheet_list.or_init(|| { + StyleSheetList::new( + &self.window, + DocumentOrShadowRoot::Document(Dom::from_ref(self)), + ) + }) + } // https://dom.spec.whatwg.org/#dom-document-implementation fn Implementation(&self) -> DomRoot<DOMImplementation> { @@ -3290,6 +3302,15 @@ impl DocumentMethods for Document { USVString(String::from(self.url().as_str())) } + // https://html.spec.whatwg.org/multipage/#dom-document-activeelement + fn GetActiveElement(&self) -> Option<DomRoot<Element>> { + self.document_or_shadow_root.get_active_element( + self.get_focused_element(), + self.GetBody(), + self.GetDocumentElement(), + ) + } + // https://html.spec.whatwg.org/multipage/#dom-document-hasfocus fn HasFocus(&self) -> bool { // Step 1-2. @@ -4234,6 +4255,18 @@ impl DocumentMethods for Document { SetOnreadystatechange ); + // https://drafts.csswg.org/cssom-view/#dom-document-elementfrompoint + fn ElementFromPoint(&self, x: Finite<f64>, y: Finite<f64>) -> Option<DomRoot<Element>> { + self.document_or_shadow_root + .element_from_point(x, y, self.GetDocumentElement()) + } + + // https://drafts.csswg.org/cssom-view/#dom-document-elementsfrompoint + fn ElementsFromPoint(&self, x: Finite<f64>, y: Finite<f64>) -> Vec<DomRoot<Element>> { + self.document_or_shadow_root + .elements_from_point(x, y, self.GetDocumentElement()) + } + // https://html.spec.whatwg.org/multipage/#dom-document-open fn Open( &self, 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, + }, + } + } +} diff --git a/components/script/dom/macros.rs b/components/script/dom/macros.rs index c64902d8f94..a566fee4fb6 100644 --- a/components/script/dom/macros.rs +++ b/components/script/dom/macros.rs @@ -632,132 +632,3 @@ macro_rules! handle_potential_webgl_error { handle_potential_webgl_error!($context, $call, ()); }; } - -macro_rules! impl_document_or_shadow_root_helpers( - () => ( - /// <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() - } - ); -); - -macro_rules! impl_document_or_shadow_root_methods( - ($struct:ident) => ( - #[allow(unsafe_code)] - // https://drafts.csswg.org/cssom-view/#dom-document-elementfrompoint - fn ElementFromPoint(&self, x: Finite<f64>, y: Finite<f64>) -> 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 => self.GetDocumentElement(), - } - } - - #[allow(unsafe_code)] - // https://drafts.csswg.org/cssom-view/#dom-document-elementsfrompoint - fn ElementsFromPoint(&self, x: Finite<f64>, y: Finite<f64>) -> 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) = self.GetDocumentElement() { - if elements.last() != Some(&root_element) { - elements.push(root_element); - } - } - - // Step 5 - elements - } - - // https://html.spec.whatwg.org/multipage/#dom-document-activeelement - fn GetActiveElement(&self) -> Option<DomRoot<Element>> { - // TODO: Step 2. - - match self.get_focused_element() { - Some(element) => Some(element), // Step 3. and 4. - None => match self.GetBody() { - // Step 5. - Some(body) => Some(DomRoot::upcast(body)), - None => self.GetDocumentElement(), - }, - } - } - - // https://drafts.csswg.org/cssom/#dom-document-stylesheets - fn StyleSheets(&self) -> DomRoot<StyleSheetList> { - self.stylesheet_list - .or_init(|| StyleSheetList::new(&self.window, DocumentOrShadowRoot::$struct(Dom::from_ref(self)))) - } - ); -); diff --git a/components/script/dom/shadowroot.rs b/components/script/dom/shadowroot.rs index c16c77f6b64..e543750e6da 100644 --- a/components/script/dom/shadowroot.rs +++ b/components/script/dom/shadowroot.rs @@ -2,33 +2,25 @@ * 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::codegen::Bindings::ShadowRootBinding::ShadowRootBinding::ShadowRootMethods; use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::{self, ShadowRootMode}; -use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::num::Finite; use crate::dom::bindings::reflector::reflect_dom_object; use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom}; use crate::dom::cssstylesheet::CSSStyleSheet; use crate::dom::document::Document; use crate::dom::documentfragment::DocumentFragment; -use crate::dom::documentorshadowroot::DocumentOrShadowRoot; +use crate::dom::documentorshadowroot::{DocumentOrShadowRoot, DocumentOrShadowRootImpl}; use crate::dom::element::Element; -use crate::dom::htmlelement::HTMLElement; -use crate::dom::node; use crate::dom::stylesheetlist::StyleSheetList; use crate::dom::window::Window; -use crate::dom::windowproxy::WindowProxy; use dom_struct::dom_struct; -use euclid::Point2D; -use js::jsapi::JS_GetRuntime; -use script_layout_interface::message::{NodesFromPointQueryType, QueryMsg}; -use script_traits::UntrustedNodeAddress; // https://dom.spec.whatwg.org/#interface-shadowroot #[dom_struct] pub struct ShadowRoot { document_fragment: DocumentFragment, + document_or_shadow_root: DocumentOrShadowRootImpl, has_browsing_context: bool, host: Dom<Element>, stylesheet_list: MutNullableDom<StyleSheetList>, @@ -37,9 +29,14 @@ pub struct ShadowRoot { impl ShadowRoot { fn new_inherited(host: &Element, document: &Document) -> ShadowRoot { + let has_browsing_context = true; ShadowRoot { document_fragment: DocumentFragment::new_inherited(document), - has_browsing_context: true, + document_or_shadow_root: DocumentOrShadowRootImpl::new( + document.window(), + has_browsing_context, + ), + has_browsing_context, host: Dom::from_ref(host), stylesheet_list: MutNullableDom::new(None), window: Dom::from_ref(document.window()), @@ -59,14 +56,6 @@ impl ShadowRoot { None } - pub fn GetDocumentElement(&self) -> Option<DomRoot<Element>> { - None - } - - pub fn GetBody(&self) -> Option<DomRoot<HTMLElement>> { - None - } - pub fn stylesheet_count(&self) -> usize { //XXX handle shadowroot stylesheets 0 @@ -76,13 +65,28 @@ impl ShadowRoot { //XXX handle shadowroot stylesheets None } - - impl_document_or_shadow_root_helpers!(); } impl ShadowRootMethods for ShadowRoot { - /// https://w3c.github.io/webcomponents/spec/shadow/#extensions-to-the-documentorshadowroot-mixin - impl_document_or_shadow_root_methods!(ShadowRoot); + // https://html.spec.whatwg.org/multipage/#dom-document-activeelement + fn GetActiveElement(&self) -> Option<DomRoot<Element>> { + self.document_or_shadow_root + .get_active_element(self.get_focused_element(), None, None) + } + + // https://drafts.csswg.org/cssom-view/#dom-document-elementfrompoint + fn ElementFromPoint(&self, x: Finite<f64>, y: Finite<f64>) -> Option<DomRoot<Element>> { + // XXX return the result of running the retargeting algorithm with context object + // and the original result as input + self.document_or_shadow_root.element_from_point(x, y, None) + } + + // https://drafts.csswg.org/cssom-view/#dom-document-elementsfrompoint + fn ElementsFromPoint(&self, x: Finite<f64>, y: Finite<f64>) -> Vec<DomRoot<Element>> { + // XXX return the result of running the retargeting algorithm with context object + // and the original result as input + self.document_or_shadow_root.elements_from_point(x, y, None) + } /// https://dom.spec.whatwg.org/#dom-shadowroot-mode fn Mode(&self) -> ShadowRootMode { @@ -93,4 +97,14 @@ impl ShadowRootMethods for ShadowRoot { fn Host(&self) -> DomRoot<Element> { DomRoot::from_ref(&self.host) } + + // https://drafts.csswg.org/cssom/#dom-document-stylesheets + fn StyleSheets(&self) -> DomRoot<StyleSheetList> { + self.stylesheet_list.or_init(|| { + StyleSheetList::new( + &self.window, + DocumentOrShadowRoot::ShadowRoot(Dom::from_ref(self)), + ) + }) + } } |