From cbcf21c2489521fbed29681ee59fbcdd90db2d80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Fri, 18 Jan 2019 18:22:09 +0100 Subject: [PATCH 01/83] DocumentOrShadowRoot mixin --- components/script/dom/document.rs | 99 +---------------- components/script/dom/macros.rs | 102 ++++++++++++++++++ components/script/dom/webidls/Document.webidl | 14 +-- .../dom/webidls/DocumentOrShadowRoot.webidl | 18 ++++ 4 files changed, 124 insertions(+), 109 deletions(-) create mode 100644 components/script/dom/webidls/DocumentOrShadowRoot.webidl diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index ed011c8029d..81bd243aab8 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -3299,11 +3299,8 @@ impl ProfilerMetadataFactory for Document { } impl DocumentMethods for Document { - // https://drafts.csswg.org/cssom/#dom-document-stylesheets - fn StyleSheets(&self) -> DomRoot { - self.stylesheet_list - .or_init(|| StyleSheetList::new(&self.window, Dom::from_ref(&self))) - } + // https://w3c.github.io/webcomponents/spec/shadow/#extensions-to-the-documentorshadowroot-mixin + impl_document_or_shadow_root!(); // https://dom.spec.whatwg.org/#dom-document-implementation fn Implementation(&self) -> DomRoot { @@ -3315,20 +3312,6 @@ impl DocumentMethods for Document { USVString(String::from(self.url().as_str())) } - // https://html.spec.whatwg.org/multipage/#dom-document-activeelement - fn GetActiveElement(&self) -> Option> { - // 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://html.spec.whatwg.org/multipage/#dom-document-hasfocus fn HasFocus(&self) -> bool { // Step 1-2. @@ -4273,84 +4256,6 @@ impl DocumentMethods for Document { SetOnreadystatechange ); - #[allow(unsafe_code)] - // https://drafts.csswg.org/cssom-view/#dom-document-elementfrompoint - fn ElementFromPoint(&self, x: Finite, y: Finite) -> Option> { - let x = *x as f32; - let y = *y as f32; - let point = &Point2D::new(x, y); - let window = window_from_node(self); - let viewport = 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(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::() - .unwrap_or_else(|| parent_node.downcast::().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, y: Finite) -> Vec> { - let x = *x as f32; - let y = *y as f32; - let point = &Point2D::new(x, y); - let window = window_from_node(self); - let viewport = 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(window.get_cx()) }; - - // Step 1 and Step 3 - let nodes = self.nodes_from_point(point, NodesFromPointQueryType::All); - let mut elements: Vec> = nodes - .iter() - .flat_map(|&untrusted_node_address| { - let node = unsafe { - node::from_untrusted_node_address(js_runtime, untrusted_node_address) - }; - DomRoot::downcast::(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-open fn Open( &self, diff --git a/components/script/dom/macros.rs b/components/script/dom/macros.rs index a566fee4fb6..94a0779732c 100644 --- a/components/script/dom/macros.rs +++ b/components/script/dom/macros.rs @@ -632,3 +632,105 @@ macro_rules! handle_potential_webgl_error { handle_potential_webgl_error!($context, $call, ()); }; } + +macro_rules! impl_document_or_shadow_root { + () => ( + #[allow(unsafe_code)] + // https://drafts.csswg.org/cssom-view/#dom-document-elementfrompoint + fn ElementFromPoint(&self, x: Finite, y: Finite) -> Option> { + let x = *x as f32; + let y = *y as f32; + let point = &Point2D::new(x, y); + let window = window_from_node(self); + let viewport = 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(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::() + .unwrap_or_else(|| parent_node.downcast::().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, y: Finite) -> Vec> { + let x = *x as f32; + let y = *y as f32; + let point = &Point2D::new(x, y); + let window = window_from_node(self); + let viewport = 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(window.get_cx()) }; + + // Step 1 and Step 3 + let nodes = self.nodes_from_point(point, NodesFromPointQueryType::All); + let mut elements: Vec> = nodes + .iter() + .flat_map(|&untrusted_node_address| { + let node = unsafe { + node::from_untrusted_node_address(js_runtime, untrusted_node_address) + }; + DomRoot::downcast::(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> { + // 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 { + self.stylesheet_list + .or_init(|| StyleSheetList::new(&self.window, Dom::from_ref(&self))) + } + ) +} diff --git a/components/script/dom/webidls/Document.webidl b/components/script/dom/webidls/Document.webidl index ccc3d339377..85c3362f42e 100644 --- a/components/script/dom/webidls/Document.webidl +++ b/components/script/dom/webidls/Document.webidl @@ -132,7 +132,6 @@ partial /*sealed*/ interface Document { // user interaction readonly attribute Window?/*Proxy?*/ defaultView; - readonly attribute Element? activeElement; boolean hasFocus(); // [CEReactions] // attribute DOMString designMode; @@ -199,17 +198,6 @@ partial interface Document { TouchList createTouchList(Touch... touches); }; -// https://drafts.csswg.org/cssom-view/#dom-document-elementfrompoint -partial interface Document { - Element? elementFromPoint(double x, double y); - sequence elementsFromPoint(double x, double y); -}; - -// https://drafts.csswg.org/cssom/#extensions-to-the-document-interface -partial interface Document { - [SameObject] readonly attribute StyleSheetList styleSheets; -}; - // https://fullscreen.spec.whatwg.org/#api partial interface Document { [LenientSetter] readonly attribute boolean fullscreenEnabled; @@ -221,3 +209,5 @@ partial interface Document { attribute EventHandler onfullscreenchange; attribute EventHandler onfullscreenerror; }; + +Document implements DocumentOrShadowRoot; diff --git a/components/script/dom/webidls/DocumentOrShadowRoot.webidl b/components/script/dom/webidls/DocumentOrShadowRoot.webidl new file mode 100644 index 00000000000..b5a1a1d0cee --- /dev/null +++ b/components/script/dom/webidls/DocumentOrShadowRoot.webidl @@ -0,0 +1,18 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * 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/. */ +/* + * The origin of this IDL file is + * https://dom.spec.whatwg.org/#documentorshadowroot + * https://w3c.github.io/webcomponents/spec/shadow/#extensions-to-the-documentorshadowroot-mixin + */ + +[NoInterfaceObject] +interface DocumentOrShadowRoot { + // Selection? getSelection(); + Element? elementFromPoint (double x, double y); + sequence elementsFromPoint (double x, double y); + // CaretPosition? caretPositionFromPoint (double x, double y); + readonly attribute Element? activeElement; + readonly attribute StyleSheetList styleSheets; +}; From 18ae0fcbd6af223f978a527d7d5039633d3c22ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Mon, 21 Jan 2019 15:58:54 +0100 Subject: [PATCH 02/83] ShadowRoot interface --- components/script/dom/documentfragment.rs | 2 +- components/script/dom/element.rs | 2 +- components/script/dom/mod.rs | 1 + components/script/dom/node.rs | 34 ++++++++-------- components/script/dom/range.rs | 8 ++-- components/script/dom/servoparser/html.rs | 2 +- components/script/dom/shadowroot.rs | 40 +++++++++++++++++++ .../script/dom/webidls/ShadowRoot.webidl | 15 +++++++ 8 files changed, 82 insertions(+), 22 deletions(-) create mode 100644 components/script/dom/shadowroot.rs create mode 100644 components/script/dom/webidls/ShadowRoot.webidl diff --git a/components/script/dom/documentfragment.rs b/components/script/dom/documentfragment.rs index 2e504750947..00718d0534d 100644 --- a/components/script/dom/documentfragment.rs +++ b/components/script/dom/documentfragment.rs @@ -27,7 +27,7 @@ pub struct DocumentFragment { impl DocumentFragment { /// Creates a new DocumentFragment. - fn new_inherited(document: &Document) -> DocumentFragment { + pub fn new_inherited(document: &Document) -> DocumentFragment { DocumentFragment { node: Node::new_inherited(document), } diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index c3d5fbb55d0..bce6a22cc46 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -2372,7 +2372,7 @@ impl ElementMethods for Element { NodeTypeId::Document(_) => return Err(Error::NoModificationAllowed), // Step 4. - NodeTypeId::DocumentFragment => { + NodeTypeId::DocumentFragment(_) => { let body_elem = Element::create( QualName::new(None, ns!(html), local_name!("body")), None, diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs index 813f4659a08..17d55d3c3a3 100644 --- a/components/script/dom/mod.rs +++ b/components/script/dom/mod.rs @@ -454,6 +454,7 @@ pub mod serviceworkercontainer; pub mod serviceworkerglobalscope; pub mod serviceworkerregistration; pub mod servoparser; +pub mod shadowroot; pub mod storage; pub mod storageevent; pub mod stylepropertymapreadonly; diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 3331686eef4..a015324b449 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -14,6 +14,7 @@ use crate::dom::bindings::codegen::Bindings::NodeBinding::{NodeConstants, NodeMe use crate::dom::bindings::codegen::Bindings::NodeListBinding::NodeListMethods; use crate::dom::bindings::codegen::Bindings::ProcessingInstructionBinding::ProcessingInstructionMethods; use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; +use crate::dom::bindings::codegen::InheritTypes::DocumentFragmentTypeId; use crate::dom::bindings::codegen::UnionTypes::NodeOrString; use crate::dom::bindings::conversions::{self, DerivedFrom}; use crate::dom::bindings::error::{Error, ErrorResult, Fallible}; @@ -1559,7 +1560,7 @@ impl Node { ) -> ErrorResult { // Step 1. match parent.type_id() { - NodeTypeId::Document(_) | NodeTypeId::DocumentFragment | NodeTypeId::Element(..) => (), + NodeTypeId::Document(_) | NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => (), _ => return Err(Error::HierarchyRequest), } @@ -1587,7 +1588,7 @@ impl Node { return Err(Error::HierarchyRequest); } }, - NodeTypeId::DocumentFragment | + NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(_) | NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) | NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => (), @@ -1598,7 +1599,7 @@ impl Node { if parent.is::() { match node.type_id() { // Step 6.1 - NodeTypeId::DocumentFragment => { + NodeTypeId::DocumentFragment(_) => { // Step 6.1.1(b) if node.children().any(|c| c.is::()) { return Err(Error::HierarchyRequest); @@ -1723,7 +1724,7 @@ impl Node { } } rooted_vec!(let mut new_nodes); - let new_nodes = if let NodeTypeId::DocumentFragment = node.type_id() { + let new_nodes = if let NodeTypeId::DocumentFragment(_) = node.type_id() { // Step 3. new_nodes.extend(node.children().map(|kid| Dom::from_ref(&*kid))); // Step 4. @@ -1809,7 +1810,7 @@ impl Node { // Step 3. rooted_vec!(let mut added_nodes); let added_nodes = if let Some(node) = node.as_ref() { - if let NodeTypeId::DocumentFragment = node.type_id() { + if let NodeTypeId::DocumentFragment(_) = node.type_id() { added_nodes.extend(node.children().map(|child| Dom::from_ref(&*child))); added_nodes.r() } else { @@ -1935,7 +1936,7 @@ impl Node { ); DomRoot::upcast::(doctype) }, - NodeTypeId::DocumentFragment => { + NodeTypeId::DocumentFragment(_) => { let doc_fragment = DocumentFragment::new(&document); DomRoot::upcast::(doc_fragment) }, @@ -2068,7 +2069,7 @@ impl Node { .GetDocumentElement() .as_ref() .map_or(ns!(), |elem| elem.locate_namespace(prefix)), - NodeTypeId::DocumentType | NodeTypeId::DocumentFragment => ns!(), + NodeTypeId::DocumentType | NodeTypeId::DocumentFragment(_) => ns!(), _ => node .GetParentElement() .as_ref() @@ -2093,7 +2094,7 @@ impl NodeMethods for Node { NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => NodeConstants::COMMENT_NODE, NodeTypeId::Document(_) => NodeConstants::DOCUMENT_NODE, NodeTypeId::DocumentType => NodeConstants::DOCUMENT_TYPE_NODE, - NodeTypeId::DocumentFragment => NodeConstants::DOCUMENT_FRAGMENT_NODE, + NodeTypeId::DocumentFragment(_) => NodeConstants::DOCUMENT_FRAGMENT_NODE, NodeTypeId::Element(_) => NodeConstants::ELEMENT_NODE, } } @@ -2113,7 +2114,7 @@ impl NodeMethods for Node { }, NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => DOMString::from("#comment"), NodeTypeId::DocumentType => self.downcast::().unwrap().name().clone(), - NodeTypeId::DocumentFragment => DOMString::from("#document-fragment"), + NodeTypeId::DocumentFragment(_) => DOMString::from("#document-fragment"), NodeTypeId::Document(_) => DOMString::from("#document"), } } @@ -2129,7 +2130,7 @@ impl NodeMethods for Node { NodeTypeId::CharacterData(..) | NodeTypeId::Element(..) | NodeTypeId::DocumentType | - NodeTypeId::DocumentFragment => Some(self.owner_doc()), + NodeTypeId::DocumentFragment(_) => Some(self.owner_doc()), NodeTypeId::Document(_) => None, } } @@ -2198,7 +2199,7 @@ impl NodeMethods for Node { // https://dom.spec.whatwg.org/#dom-node-textcontent fn GetTextContent(&self) -> Option { match self.type_id() { - NodeTypeId::DocumentFragment | NodeTypeId::Element(..) => { + NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => { let content = Node::collect_text_contents(self.traverse_preorder()); Some(content) }, @@ -2214,7 +2215,7 @@ impl NodeMethods for Node { fn SetTextContent(&self, value: Option) { let value = value.unwrap_or_default(); match self.type_id() { - NodeTypeId::DocumentFragment | NodeTypeId::Element(..) => { + NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => { // Step 1-2. let node = if value.is_empty() { None @@ -2247,7 +2248,7 @@ impl NodeMethods for Node { fn ReplaceChild(&self, node: &Node, child: &Node) -> Fallible> { // Step 1. match self.type_id() { - NodeTypeId::Document(_) | NodeTypeId::DocumentFragment | NodeTypeId::Element(..) => (), + NodeTypeId::Document(_) | NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => (), _ => return Err(Error::HierarchyRequest), } @@ -2277,7 +2278,7 @@ impl NodeMethods for Node { if self.is::() { match node.type_id() { // Step 6.1 - NodeTypeId::DocumentFragment => { + NodeTypeId::DocumentFragment(_) => { // Step 6.1.1(b) if node.children().any(|c| c.is::()) { return Err(Error::HierarchyRequest); @@ -2350,7 +2351,8 @@ impl NodeMethods for Node { // Step 12. rooted_vec!(let mut nodes); - let nodes = if node.type_id() == NodeTypeId::DocumentFragment { + let nodes = if node.type_id() == NodeTypeId::DocumentFragment(DocumentFragmentTypeId::DocumentFragment) || + node.type_id() == NodeTypeId::DocumentFragment(DocumentFragmentTypeId::ShadowRoot) { nodes.extend(node.children().map(|node| Dom::from_ref(&*node))); nodes.r() } else { @@ -2612,7 +2614,7 @@ impl NodeMethods for Node { .unwrap() .GetDocumentElement() .and_then(|element| element.lookup_prefix(namespace)), - NodeTypeId::DocumentType | NodeTypeId::DocumentFragment => None, + NodeTypeId::DocumentType | NodeTypeId::DocumentFragment(_) => None, _ => self .GetParentElement() .and_then(|element| element.lookup_prefix(namespace)), diff --git a/components/script/dom/range.rs b/components/script/dom/range.rs index 630c4acd245..9a1bc5db7a6 100644 --- a/components/script/dom/range.rs +++ b/components/script/dom/range.rs @@ -10,6 +10,7 @@ use crate::dom::bindings::codegen::Bindings::RangeBinding::RangeMethods; use crate::dom::bindings::codegen::Bindings::RangeBinding::{self, RangeConstants}; use crate::dom::bindings::codegen::Bindings::TextBinding::TextMethods; use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; +use crate::dom::bindings::codegen::InheritTypes::DocumentFragmentTypeId; use crate::dom::bindings::error::{Error, ErrorResult, Fallible}; use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::inheritance::{CharacterDataTypeId, NodeTypeId}; @@ -763,7 +764,8 @@ impl RangeMethods for Range { // Step 11 let new_offset = new_offset + - if node.type_id() == NodeTypeId::DocumentFragment { + if node.type_id() == NodeTypeId::DocumentFragment(DocumentFragmentTypeId::DocumentFragment) || + node.type_id() == NodeTypeId::DocumentFragment(DocumentFragmentTypeId::ShadowRoot) { node.len() } else { 1 @@ -878,7 +880,7 @@ impl RangeMethods for Range { // Step 2. match new_parent.type_id() { - NodeTypeId::Document(_) | NodeTypeId::DocumentType | NodeTypeId::DocumentFragment => { + NodeTypeId::Document(_) | NodeTypeId::DocumentType | NodeTypeId::DocumentFragment(_) => { return Err(Error::InvalidNodeType); }, _ => (), @@ -954,7 +956,7 @@ impl RangeMethods for Range { let node = self.StartContainer(); let owner_doc = node.owner_doc(); let element = match node.type_id() { - NodeTypeId::Document(_) | NodeTypeId::DocumentFragment => None, + NodeTypeId::Document(_) | NodeTypeId::DocumentFragment(_) => None, NodeTypeId::Element(_) => Some(DomRoot::downcast::(node).unwrap()), NodeTypeId::CharacterData(CharacterDataTypeId::Comment) | NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) => node.GetParentElement(), diff --git a/components/script/dom/servoparser/html.rs b/components/script/dom/servoparser/html.rs index 965982d8b51..c9e3a06f34f 100644 --- a/components/script/dom/servoparser/html.rs +++ b/components/script/dom/servoparser/html.rs @@ -249,7 +249,7 @@ impl<'a> Serialize for &'a Node { serializer.write_processing_instruction(&pi.target(), &data)?; }, - NodeTypeId::DocumentFragment => {}, + NodeTypeId::DocumentFragment(_) => {}, NodeTypeId::Document(_) => panic!("Can't serialize Document node itself"), NodeTypeId::Element(_) => panic!("Element shouldn't appear here"), diff --git a/components/script/dom/shadowroot.rs b/components/script/dom/shadowroot.rs new file mode 100644 index 00000000000..bb3b646a9d2 --- /dev/null +++ b/components/script/dom/shadowroot.rs @@ -0,0 +1,40 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * 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::documentfragment::DocumentFragment; +use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::ShadowRootBinding::ShadowRootMethods; +use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::ShadowRootMode; +use crate::dom::bindings::root::{Dom, DomRoot}; +use crate::dom::document::Document; +use crate::dom::element::Element; +use dom_struct::dom_struct; + +// https://dom.spec.whatwg.org/#interface-shadowroot +#[dom_struct] +pub struct ShadowRoot { + document_fragment: DocumentFragment, + host: Dom, +} + +impl ShadowRoot { + #[allow(dead_code)] + pub fn new_inherited(host: &Element, document: &Document) -> ShadowRoot { + ShadowRoot { + document_fragment: DocumentFragment::new_inherited(document), + host: Dom::from_ref(host), + } + } +} + +impl ShadowRootMethods for ShadowRoot { + /// https://dom.spec.whatwg.org/#dom-shadowroot-mode + fn Mode(&self) -> ShadowRootMode { + ShadowRootMode::Closed + } + + /// https://dom.spec.whatwg.org/#dom-shadowroot-host + fn Host(&self) -> DomRoot { + DomRoot::from_ref(&self.host) + } +} diff --git a/components/script/dom/webidls/ShadowRoot.webidl b/components/script/dom/webidls/ShadowRoot.webidl new file mode 100644 index 00000000000..f8372bdb6cd --- /dev/null +++ b/components/script/dom/webidls/ShadowRoot.webidl @@ -0,0 +1,15 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * 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/. */ +/* + * The origin of this IDL file is: + * https://dom.spec.whatwg.org/#interface-shadowroot + */ + +[Exposed=Window] +interface ShadowRoot : DocumentFragment { + readonly attribute ShadowRootMode mode; + readonly attribute Element host; +}; + +enum ShadowRootMode { "open", "closed"}; From 4304ee28dceffa8ad66f5b088754705bc2bb3b4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Mon, 21 Jan 2019 20:58:52 +0100 Subject: [PATCH 03/83] Partial ShadowRoot implementation of DocumentOrShadowRoot --- components/script/dom/document.rs | 30 ++--------- components/script/dom/documentorshadowroot.rs | 40 ++++++++++++++ components/script/dom/macros.rs | 47 +++++++++++++---- components/script/dom/mod.rs | 1 + components/script/dom/node.rs | 14 +++-- components/script/dom/range.rs | 11 ++-- components/script/dom/shadowroot.rs | 52 ++++++++++++++++++- components/script/dom/stylesheetlist.rs | 18 +++---- .../script/dom/webidls/ShadowRoot.webidl | 2 + 9 files changed, 161 insertions(+), 54 deletions(-) create mode 100644 components/script/dom/documentorshadowroot.rs diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 81bd243aab8..2ff1516b231 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -43,6 +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::documenttype::DocumentType; use crate::dom::domimplementation::DOMImplementation; use crate::dom::element::CustomElementCreationMode; @@ -486,16 +487,6 @@ impl Document { self.has_browsing_context } - /// - #[inline] - pub fn browsing_context(&self) -> Option> { - if self.has_browsing_context { - self.window.undiscarded_window_proxy() - } else { - None - } - } - #[inline] pub fn window(&self) -> &Window { &*self.window @@ -2395,21 +2386,6 @@ impl Document { !self.has_browsing_context || !url_has_network_scheme(&self.url()) } - pub fn nodes_from_point( - &self, - client_point: &Point2D, - reflow_goal: NodesFromPointQueryType, - ) -> Vec { - if !self - .window - .layout_reflow(QueryMsg::NodesFromPointQuery(*client_point, reflow_goal)) - { - return vec![]; - }; - - self.window.layout().nodes_from_point_response() - } - /// pub fn lookup_custom_element_definition( &self, @@ -3270,6 +3246,8 @@ impl Document { } } } + + impl_document_or_shadow_root_helpers!(); } impl Element { @@ -3300,7 +3278,7 @@ 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!(); + impl_document_or_shadow_root_methods!(Document); // https://dom.spec.whatwg.org/#dom-document-implementation fn Implementation(&self) -> DomRoot { diff --git a/components/script/dom/documentorshadowroot.rs b/components/script/dom/documentorshadowroot.rs new file mode 100644 index 00000000000..c305afce1d6 --- /dev/null +++ b/components/script/dom/documentorshadowroot.rs @@ -0,0 +1,40 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * 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::root::{Dom, DomRoot}; +use crate::dom::cssstylesheet::CSSStyleSheet; +use crate::dom::document::Document; +use crate::dom::shadowroot::ShadowRoot; + +macro_rules! proxy_call( + ($fn_name:ident, $return_type:ty) => ( + pub fn $fn_name(&self) -> $return_type { + match self { + DocumentOrShadowRoot::Document(doc) => doc.$fn_name(), + DocumentOrShadowRoot::ShadowRoot(root) => root.$fn_name(), + } + } + ); + + ($fn_name:ident, $arg1:ident, $arg1_type:ty, $return_type:ty) => ( + pub fn $fn_name(&self, $arg1: $arg1_type) -> $return_type { + match self { + DocumentOrShadowRoot::Document(doc) => doc.$fn_name($arg1), + DocumentOrShadowRoot::ShadowRoot(root) => root.$fn_name($arg1), + } + } + ); +); + +#[must_root] +#[derive(JSTraceable, MallocSizeOf)] +pub enum DocumentOrShadowRoot { + Document(Dom), + ShadowRoot(Dom), +} + +impl DocumentOrShadowRoot { + proxy_call!(stylesheet_count, usize); + proxy_call!(stylesheet_at, index, usize, Option>); +} diff --git a/components/script/dom/macros.rs b/components/script/dom/macros.rs index 94a0779732c..c64902d8f94 100644 --- a/components/script/dom/macros.rs +++ b/components/script/dom/macros.rs @@ -633,16 +633,44 @@ macro_rules! handle_potential_webgl_error { }; } -macro_rules! impl_document_or_shadow_root { +macro_rules! impl_document_or_shadow_root_helpers( () => ( + /// + #[inline] + pub fn browsing_context(&self) -> Option> { + if self.has_browsing_context { + self.window.undiscarded_window_proxy() + } else { + None + } + } + + pub fn nodes_from_point( + &self, + client_point: &Point2D, + reflow_goal: NodesFromPointQueryType, + ) -> Vec { + 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, y: Finite) -> Option> { let x = *x as f32; let y = *y as f32; let point = &Point2D::new(x, y); - let window = window_from_node(self); - let viewport = window.window_size().initial_viewport; + let viewport = self.window.window_size().initial_viewport; if self.browsing_context().is_none() { return None; @@ -657,7 +685,7 @@ macro_rules! impl_document_or_shadow_root { .first() { Some(address) => { - let js_runtime = unsafe { JS_GetRuntime(window.get_cx()) }; + 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 @@ -676,8 +704,7 @@ macro_rules! impl_document_or_shadow_root { let x = *x as f32; let y = *y as f32; let point = &Point2D::new(x, y); - let window = window_from_node(self); - let viewport = window.window_size().initial_viewport; + let viewport = self.window.window_size().initial_viewport; if self.browsing_context().is_none() { return vec![]; @@ -688,7 +715,7 @@ macro_rules! impl_document_or_shadow_root { return vec![]; } - let js_runtime = unsafe { JS_GetRuntime(window.get_cx()) }; + let js_runtime = unsafe { JS_GetRuntime(self.window.get_cx()) }; // Step 1 and Step 3 let nodes = self.nodes_from_point(point, NodesFromPointQueryType::All); @@ -730,7 +757,7 @@ macro_rules! impl_document_or_shadow_root { // https://drafts.csswg.org/cssom/#dom-document-stylesheets fn StyleSheets(&self) -> DomRoot { self.stylesheet_list - .or_init(|| StyleSheetList::new(&self.window, Dom::from_ref(&self))) + .or_init(|| StyleSheetList::new(&self.window, DocumentOrShadowRoot::$struct(Dom::from_ref(self)))) } - ) -} + ); +); diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs index 17d55d3c3a3..15d3ba34a23 100644 --- a/components/script/dom/mod.rs +++ b/components/script/dom/mod.rs @@ -280,6 +280,7 @@ pub mod dissimilaroriginlocation; pub mod dissimilaroriginwindow; pub mod document; pub mod documentfragment; +pub mod documentorshadowroot; pub mod documenttype; pub mod domexception; pub mod domimplementation; diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index a015324b449..33c05aa2a5a 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -1560,7 +1560,9 @@ impl Node { ) -> ErrorResult { // Step 1. match parent.type_id() { - NodeTypeId::Document(_) | NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => (), + NodeTypeId::Document(_) | NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => { + () + }, _ => return Err(Error::HierarchyRequest), } @@ -2248,7 +2250,9 @@ impl NodeMethods for Node { fn ReplaceChild(&self, node: &Node, child: &Node) -> Fallible> { // Step 1. match self.type_id() { - NodeTypeId::Document(_) | NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => (), + NodeTypeId::Document(_) | NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => { + () + }, _ => return Err(Error::HierarchyRequest), } @@ -2351,8 +2355,10 @@ impl NodeMethods for Node { // Step 12. rooted_vec!(let mut nodes); - let nodes = if node.type_id() == NodeTypeId::DocumentFragment(DocumentFragmentTypeId::DocumentFragment) || - node.type_id() == NodeTypeId::DocumentFragment(DocumentFragmentTypeId::ShadowRoot) { + let nodes = if node.type_id() == + NodeTypeId::DocumentFragment(DocumentFragmentTypeId::DocumentFragment) || + node.type_id() == NodeTypeId::DocumentFragment(DocumentFragmentTypeId::ShadowRoot) + { nodes.extend(node.children().map(|node| Dom::from_ref(&*node))); nodes.r() } else { diff --git a/components/script/dom/range.rs b/components/script/dom/range.rs index 9a1bc5db7a6..96f276944bc 100644 --- a/components/script/dom/range.rs +++ b/components/script/dom/range.rs @@ -764,8 +764,11 @@ impl RangeMethods for Range { // Step 11 let new_offset = new_offset + - if node.type_id() == NodeTypeId::DocumentFragment(DocumentFragmentTypeId::DocumentFragment) || - node.type_id() == NodeTypeId::DocumentFragment(DocumentFragmentTypeId::ShadowRoot) { + if node.type_id() == + NodeTypeId::DocumentFragment(DocumentFragmentTypeId::DocumentFragment) || + node.type_id() == + NodeTypeId::DocumentFragment(DocumentFragmentTypeId::ShadowRoot) + { node.len() } else { 1 @@ -880,7 +883,9 @@ impl RangeMethods for Range { // Step 2. match new_parent.type_id() { - NodeTypeId::Document(_) | NodeTypeId::DocumentType | NodeTypeId::DocumentFragment(_) => { + NodeTypeId::Document(_) | + NodeTypeId::DocumentType | + NodeTypeId::DocumentFragment(_) => { return Err(Error::InvalidNodeType); }, _ => (), diff --git a/components/script/dom/shadowroot.rs b/components/script/dom/shadowroot.rs index bb3b646a9d2..7f21ca57ad0 100644 --- a/components/script/dom/shadowroot.rs +++ b/components/script/dom/shadowroot.rs @@ -2,19 +2,36 @@ * 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::documentfragment::DocumentFragment; +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::ShadowRootMode; -use crate::dom::bindings::root::{Dom, DomRoot}; +use crate::dom::bindings::inheritance::Castable; +use crate::dom::bindings::num::Finite; +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::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, + has_browsing_context: bool, host: Dom, + stylesheet_list: MutNullableDom, + window: Dom, } impl ShadowRoot { @@ -22,12 +39,43 @@ impl ShadowRoot { pub fn new_inherited(host: &Element, document: &Document) -> ShadowRoot { ShadowRoot { document_fragment: DocumentFragment::new_inherited(document), + has_browsing_context: true, host: Dom::from_ref(host), + stylesheet_list: MutNullableDom::new(None), + window: Dom::from_ref(document.window()), } } + + pub fn get_focused_element(&self) -> Option> { + //XXX get retargeted focused element + None + } + + pub fn GetDocumentElement(&self) -> Option> { + None + } + + pub fn GetBody(&self) -> Option> { + None + } + + pub fn stylesheet_count(&self) -> usize { + //XXX handle shadowroot stylesheets + 0 + } + + pub fn stylesheet_at(&self, _index: usize) -> Option> { + //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://dom.spec.whatwg.org/#dom-shadowroot-mode fn Mode(&self) -> ShadowRootMode { ShadowRootMode::Closed diff --git a/components/script/dom/stylesheetlist.rs b/components/script/dom/stylesheetlist.rs index c1c5c0b2d5f..79afcfed21f 100644 --- a/components/script/dom/stylesheetlist.rs +++ b/components/script/dom/stylesheetlist.rs @@ -5,8 +5,8 @@ use crate::dom::bindings::codegen::Bindings::StyleSheetListBinding; use crate::dom::bindings::codegen::Bindings::StyleSheetListBinding::StyleSheetListMethods; use crate::dom::bindings::reflector::{reflect_dom_object, Reflector}; -use crate::dom::bindings::root::{Dom, DomRoot}; -use crate::dom::document::Document; +use crate::dom::bindings::root::DomRoot; +use crate::dom::documentorshadowroot::DocumentOrShadowRoot; use crate::dom::stylesheet::StyleSheet; use crate::dom::window::Window; use dom_struct::dom_struct; @@ -14,22 +14,22 @@ use dom_struct::dom_struct; #[dom_struct] pub struct StyleSheetList { reflector_: Reflector, - document: Dom, + document_or_shadow_root: DocumentOrShadowRoot, } impl StyleSheetList { #[allow(unrooted_must_root)] - fn new_inherited(doc: Dom) -> StyleSheetList { + fn new_inherited(doc_or_sr: DocumentOrShadowRoot) -> StyleSheetList { StyleSheetList { reflector_: Reflector::new(), - document: doc, + document_or_shadow_root: doc_or_sr, } } #[allow(unrooted_must_root)] - pub fn new(window: &Window, document: Dom) -> DomRoot { + pub fn new(window: &Window, doc_or_sr: DocumentOrShadowRoot) -> DomRoot { reflect_dom_object( - Box::new(StyleSheetList::new_inherited(document)), + Box::new(StyleSheetList::new_inherited(doc_or_sr)), window, StyleSheetListBinding::Wrap, ) @@ -39,14 +39,14 @@ impl StyleSheetList { impl StyleSheetListMethods for StyleSheetList { // https://drafts.csswg.org/cssom/#dom-stylesheetlist-length fn Length(&self) -> u32 { - self.document.stylesheet_count() as u32 + self.document_or_shadow_root.stylesheet_count() as u32 } // https://drafts.csswg.org/cssom/#dom-stylesheetlist-item fn Item(&self, index: u32) -> Option> { // XXXManishearth this doesn't handle the origin clean flag and is a // cors vulnerability - self.document + self.document_or_shadow_root .stylesheet_at(index as usize) .map(DomRoot::upcast) } diff --git a/components/script/dom/webidls/ShadowRoot.webidl b/components/script/dom/webidls/ShadowRoot.webidl index f8372bdb6cd..711d4f853bd 100644 --- a/components/script/dom/webidls/ShadowRoot.webidl +++ b/components/script/dom/webidls/ShadowRoot.webidl @@ -13,3 +13,5 @@ interface ShadowRoot : DocumentFragment { }; enum ShadowRootMode { "open", "closed"}; + +ShadowRoot implements DocumentOrShadowRoot; From 569b4fce102a423b513b8282b7a12c02641fa61f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Tue, 22 Jan 2019 12:58:42 +0100 Subject: [PATCH 04/83] Element attachShadow implementation --- components/script/dom/element.rs | 53 +++++++++++++++++++++++++++++ components/script/dom/shadowroot.rs | 14 ++++++-- 2 files changed, 64 insertions(+), 3 deletions(-) diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index bce6a22cc46..dcc89638e8a 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -76,6 +76,7 @@ use crate::dom::node::{NodeDamage, NodeFlags, UnbindContext}; use crate::dom::nodelist::NodeList; use crate::dom::promise::Promise; use crate::dom::servoparser::ServoParser; +use crate::dom::shadowroot::ShadowRoot; use crate::dom::text::Text; use crate::dom::validation::Validatable; use crate::dom::virtualmethods::{vtable_for, VirtualMethods}; @@ -170,6 +171,10 @@ pub struct Element { custom_element_definition: DomRefCell>>, /// custom_element_state: Cell, + /// https://dom.spec.whatwg.org/#dom-element-shadowroot + /// XXX This is currently not exposed to web content. Only for + /// internal use. + shadow_root: MutNullableDom, } impl fmt::Debug for Element { @@ -297,6 +302,7 @@ impl Element { custom_element_reaction_queue: Default::default(), custom_element_definition: Default::default(), custom_element_state: Cell::new(CustomElementState::Uncustomized), + shadow_root: Default::default(), } } @@ -436,6 +442,53 @@ impl Element { box_.clone_overflow_y() == overflow_y::computed_value::T::Hidden }) } + + fn is_shadow_host(&self) -> bool { + self.shadow_root.get().is_some() + } + + /// https://dom.spec.whatwg.org/#dom-element-attachshadow + /// XXX This is not exposed to web content yet. It is meant to be used + /// for UA widgets only. + pub fn attach_shadow(&self) -> Fallible> { + // Step 1. + if self.namespace != ns!(html) { + return Err(Error::NotSupported); + } + + // Step 2. + match self.local_name() { + &local_name!("article") | + &local_name!("aside") | + &local_name!("blockquote") | + &local_name!("body") | + &local_name!("div") | + &local_name!("footer") | + &local_name!("h1") | + &local_name!("h2") | + &local_name!("h3") | + &local_name!("h4") | + &local_name!("h5") | + &local_name!("h6") | + &local_name!("header") | + &local_name!("main") | + &local_name!("nav") | + &local_name!("p") | + &local_name!("section") | + &local_name!("span") => {}, + _ => return Err(Error::NotSupported), + }; + + // Step 3. + if self.is_shadow_host() { + return Err(Error::InvalidState); + } + + // Steps 4, 5 and 6. + Ok(self + .shadow_root + .or_init(|| ShadowRoot::new(self, &*self.node.owner_doc()))) + } } #[allow(unsafe_code)] diff --git a/components/script/dom/shadowroot.rs b/components/script/dom/shadowroot.rs index 7f21ca57ad0..c16c77f6b64 100644 --- a/components/script/dom/shadowroot.rs +++ b/components/script/dom/shadowroot.rs @@ -4,9 +4,10 @@ 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::ShadowRootMode; +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; @@ -35,8 +36,7 @@ pub struct ShadowRoot { } impl ShadowRoot { - #[allow(dead_code)] - pub fn new_inherited(host: &Element, document: &Document) -> ShadowRoot { + fn new_inherited(host: &Element, document: &Document) -> ShadowRoot { ShadowRoot { document_fragment: DocumentFragment::new_inherited(document), has_browsing_context: true, @@ -46,6 +46,14 @@ impl ShadowRoot { } } + pub fn new(host: &Element, document: &Document) -> DomRoot { + reflect_dom_object( + Box::new(ShadowRoot::new_inherited(host, document)), + document.window(), + ShadowRootBinding::Wrap, + ) + } + pub fn get_focused_element(&self) -> Option> { //XXX get retargeted focused element None From 9022bd3d1162298931153f5ad8c144489c790708 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Wed, 23 Jan 2019 17:34:10 +0100 Subject: [PATCH 05/83] IS_IN_SHADOW_TREE flag --- components/script/dom/element.rs | 3 +++ components/script/dom/node.rs | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index dcc89638e8a..6dc7b7c3147 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -484,6 +484,9 @@ impl Element { return Err(Error::InvalidState); } + self.upcast::() + .set_flag(NodeFlags::IS_IN_SHADOW_TREE, true); + // Steps 4, 5 and 6. Ok(self .shadow_root diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 33c05aa2a5a..ba3298cb071 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -182,6 +182,9 @@ bitflags! { /// Whether this element has already handled the stored snapshot. const HANDLED_SNAPSHOT = 1 << 8; + + // Whether this node participates in a shadow tree. + const IS_IN_SHADOW_TREE = 1 << 9; } } @@ -265,8 +268,10 @@ impl Node { self.children_count.set(self.children_count.get() + 1); let parent_in_doc = self.is_in_doc(); + let parent_in_shadow_tree = self.is_in_shadow_tree(); for node in new_child.traverse_preorder() { node.set_flag(NodeFlags::IS_IN_DOC, parent_in_doc); + node.set_flag(NodeFlags::IS_IN_SHADOW_TREE, parent_in_shadow_tree); // Out-of-document elements never have the descendants flag set. debug_assert!(!node.get_flag(NodeFlags::HAS_DIRTY_DESCENDANTS)); vtable_for(&&*node).bind_to_tree(parent_in_doc); @@ -464,6 +469,10 @@ impl Node { self.flags.get().contains(NodeFlags::IS_IN_DOC) } + pub fn is_in_shadow_tree(&self) -> bool { + self.flags.get().contains(NodeFlags::IS_IN_SHADOW_TREE) + } + /// Returns the type ID of this node. pub fn type_id(&self) -> NodeTypeId { match *self.eventtarget.type_id() { From 091fcbecd13e6d45f49f2760df939ed57282eada Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Wed, 23 Jan 2019 17:46:54 +0100 Subject: [PATCH 06/83] Node shadow root owner --- components/script/dom/node.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index ba3298cb071..7dd402796df 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -23,6 +23,7 @@ use crate::dom::bindings::inheritance::{EventTargetTypeId, HTMLElementTypeId, No use crate::dom::bindings::inheritance::{SVGElementTypeId, SVGGraphicsElementTypeId, TextTypeId}; use crate::dom::bindings::reflector::{reflect_dom_object, DomObject}; use crate::dom::bindings::root::{Dom, DomRoot, DomSlice, LayoutDom, MutNullableDom}; +use crate::dom::shadowroot::ShadowRoot; use crate::dom::bindings::str::{DOMString, USVString}; use crate::dom::bindings::xmlname::namespace_from_domstring; use crate::dom::characterdata::{CharacterData, LayoutCharacterDataHelpers}; @@ -119,6 +120,9 @@ pub struct Node { /// The document that this node belongs to. owner_doc: MutNullableDom, + /// The shadow root this node belongs to. + owner_shadow_root: MutNullableDom, + /// The live list of children return by .childNodes. child_list: MutNullableDom, @@ -272,6 +276,9 @@ impl Node { for node in new_child.traverse_preorder() { node.set_flag(NodeFlags::IS_IN_DOC, parent_in_doc); node.set_flag(NodeFlags::IS_IN_SHADOW_TREE, parent_in_shadow_tree); + if parent_in_shadow_tree { + node.set_owner_shadow_root(&*self.owner_shadow_root()); + } // Out-of-document elements never have the descendants flag set. debug_assert!(!node.get_flag(NodeFlags::HAS_DIRTY_DESCENDANTS)); vtable_for(&&*node).bind_to_tree(parent_in_doc); @@ -886,6 +893,14 @@ impl Node { self.owner_doc.set(Some(document)); } + pub fn owner_shadow_root(&self) -> DomRoot { + self.owner_shadow_root.get().unwrap() + } + + pub fn set_owner_shadow_root(&self, shadow_root: &ShadowRoot) { + self.owner_shadow_root.set(Some(shadow_root)); + } + pub fn is_in_html_doc(&self) -> bool { self.owner_doc().is_html_document() } @@ -1511,6 +1526,7 @@ impl Node { next_sibling: Default::default(), prev_sibling: Default::default(), owner_doc: MutNullableDom::new(doc), + owner_shadow_root: Default::default(), child_list: Default::default(), children_count: Cell::new(0u32), flags: Cell::new(flags), From ffdc9d255f017fc82ff8d8a0c57256563082bf1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Wed, 23 Jan 2019 18:08:28 +0100 Subject: [PATCH 07/83] Expose Element.AttachShadow under dom.shadowdom.enabled pref --- components/script/dom/element.rs | 7 +++++++ components/script/dom/node.rs | 2 +- components/script/dom/webidls/Element.webidl | 2 ++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 6dc7b7c3147..599efd4a8cc 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -2642,6 +2642,13 @@ impl ElementMethods for Element { let doc = document_from_node(self); doc.enter_fullscreen(self) } + + // XXX Hidden under dom.shadowdom.enabled pref. Only exposed to be able + // to test partial Shadow DOM support for UA widgets. + // https://dom.spec.whatwg.org/#dom-element-attachshadow + fn AttachShadow(&self) -> Fallible> { + self.attach_shadow() + } } impl VirtualMethods for Element { diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 7dd402796df..4aa6f390b16 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -23,7 +23,6 @@ use crate::dom::bindings::inheritance::{EventTargetTypeId, HTMLElementTypeId, No use crate::dom::bindings::inheritance::{SVGElementTypeId, SVGGraphicsElementTypeId, TextTypeId}; use crate::dom::bindings::reflector::{reflect_dom_object, DomObject}; use crate::dom::bindings::root::{Dom, DomRoot, DomSlice, LayoutDom, MutNullableDom}; -use crate::dom::shadowroot::ShadowRoot; use crate::dom::bindings::str::{DOMString, USVString}; use crate::dom::bindings::xmlname::namespace_from_domstring; use crate::dom::characterdata::{CharacterData, LayoutCharacterDataHelpers}; @@ -51,6 +50,7 @@ use crate::dom::mutationobserver::{Mutation, MutationObserver, RegisteredObserve use crate::dom::nodelist::NodeList; use crate::dom::processinginstruction::ProcessingInstruction; use crate::dom::range::WeakRangeVec; +use crate::dom::shadowroot::ShadowRoot; use crate::dom::svgsvgelement::{LayoutSVGSVGElementHelpers, SVGSVGElement}; use crate::dom::text::Text; use crate::dom::virtualmethods::{vtable_for, VirtualMethods}; diff --git a/components/script/dom/webidls/Element.webidl b/components/script/dom/webidls/Element.webidl index b7de03ac344..af14f81b373 100644 --- a/components/script/dom/webidls/Element.webidl +++ b/components/script/dom/webidls/Element.webidl @@ -81,6 +81,8 @@ interface Element : Node { void insertAdjacentText(DOMString where_, DOMString data); [CEReactions, Throws] void insertAdjacentHTML(DOMString position, DOMString html); + + [Throws, Pref="dom.shadowdom.enabled"] ShadowRoot attachShadow(); }; // http://dev.w3.org/csswg/cssom-view/#extensions-to-the-element-interface From f3e707306f64d714e4b631fcd76513625469233e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Thu, 24 Jan 2019 10:48:08 +0100 Subject: [PATCH 08/83] Test DOM isolation for shadow trees --- tests/wpt/mozilla/meta/MANIFEST.json | 10 +++++ .../meta/mozilla/partial_shadow_dom.html.ini | 2 + .../tests/mozilla/partial_shadow_dom.html | 38 +++++++++++++++++++ 3 files changed, 50 insertions(+) create mode 100644 tests/wpt/mozilla/meta/mozilla/partial_shadow_dom.html.ini create mode 100644 tests/wpt/mozilla/tests/mozilla/partial_shadow_dom.html diff --git a/tests/wpt/mozilla/meta/MANIFEST.json b/tests/wpt/mozilla/meta/MANIFEST.json index a29a6bb5c5a..f556de3c784 100644 --- a/tests/wpt/mozilla/meta/MANIFEST.json +++ b/tests/wpt/mozilla/meta/MANIFEST.json @@ -13515,6 +13515,12 @@ {} ] ], + "mozilla/partial_shadow_dom.html": [ + [ + "mozilla/partial_shadow_dom.html", + {} + ] + ], "mozilla/postmessage_closed.html": [ [ "mozilla/postmessage_closed.html", @@ -20430,6 +20436,10 @@ "5aff666995fe6cd1d4e84e63a9f6019d04387f8e", "testharness" ], + "mozilla/partial_shadow_dom.html": [ + "d97f1422d20161e989f200d44be6e379f79410bd", + "testharness" + ], "mozilla/poster.png": [ "33834c3ef095fa9c0080017e1b65b2eb8413eac4", "support" diff --git a/tests/wpt/mozilla/meta/mozilla/partial_shadow_dom.html.ini b/tests/wpt/mozilla/meta/mozilla/partial_shadow_dom.html.ini new file mode 100644 index 00000000000..6b14e5081c1 --- /dev/null +++ b/tests/wpt/mozilla/meta/mozilla/partial_shadow_dom.html.ini @@ -0,0 +1,2 @@ +[partial_shadow_dom.html] + prefs: [dom.shadowdom.enabled:true] diff --git a/tests/wpt/mozilla/tests/mozilla/partial_shadow_dom.html b/tests/wpt/mozilla/tests/mozilla/partial_shadow_dom.html new file mode 100644 index 00000000000..d97f1422d20 --- /dev/null +++ b/tests/wpt/mozilla/tests/mozilla/partial_shadow_dom.html @@ -0,0 +1,38 @@ + + + + + + + + +

Not in the shadows

+
+
+ + From 48975840dd3a4becfc5ee6adccabd303e06fc554 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Thu, 24 Jan 2019 18:16:20 +0100 Subject: [PATCH 09/83] Unify DocumentOrShadowRoot implementation --- components/script/dom/document.rs | 51 +++++- components/script/dom/documentorshadowroot.rs | 159 ++++++++++++++++++ components/script/dom/macros.rs | 129 -------------- 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, implementation: MutNullableDom, #[ignore_malloc_size_of = "type from external crate"] @@ -487,6 +487,11 @@ impl Document { self.has_browsing_context } + #[inline] + pub fn browsing_context(&self) -> Option> { + 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 { + 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 { @@ -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> { + 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, y: Finite) -> Option> { + 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, y: Finite) -> Vec> { + 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>); } + +// 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, +} + +impl DocumentOrShadowRootImpl { + pub fn new(window: &Window, has_browsing_context: bool) -> Self { + Self { + has_browsing_context, + window: Dom::from_ref(window), + } + } + + /// + #[inline] + pub fn browsing_context(&self) -> Option> { + if self.has_browsing_context { + self.window.undiscarded_window_proxy() + } else { + None + } + } + + pub fn nodes_from_point( + &self, + client_point: &Point2D, + reflow_goal: NodesFromPointQueryType, + ) -> Vec { + 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, + y: Finite, + document_element: Option>, + ) -> Option> { + 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::() + .unwrap_or_else(|| parent_node.downcast::().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, + y: Finite, + document_element: Option>, + ) -> Vec> { + 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> = nodes + .iter() + .flat_map(|&untrusted_node_address| { + let node = unsafe { + node::from_untrusted_node_address(js_runtime, untrusted_node_address) + }; + DomRoot::downcast::(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>, + body: Option>, + document_element: Option>, + ) -> Option> { + // 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( - () => ( - /// - #[inline] - pub fn browsing_context(&self) -> Option> { - if self.has_browsing_context { - self.window.undiscarded_window_proxy() - } else { - None - } - } - - pub fn nodes_from_point( - &self, - client_point: &Point2D, - reflow_goal: NodesFromPointQueryType, - ) -> Vec { - 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, y: Finite) -> Option> { - 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::() - .unwrap_or_else(|| parent_node.downcast::().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, y: Finite) -> Vec> { - 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> = nodes - .iter() - .flat_map(|&untrusted_node_address| { - let node = unsafe { - node::from_untrusted_node_address(js_runtime, untrusted_node_address) - }; - DomRoot::downcast::(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> { - // 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 { - 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, stylesheet_list: MutNullableDom, @@ -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> { - None - } - - pub fn GetBody(&self) -> Option> { - 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> { + 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, y: Finite) -> Option> { + // 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, y: Finite) -> Vec> { + // 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 { DomRoot::from_ref(&self.host) } + + // https://drafts.csswg.org/cssom/#dom-document-stylesheets + fn StyleSheets(&self) -> DomRoot { + self.stylesheet_list.or_init(|| { + StyleSheetList::new( + &self.window, + DocumentOrShadowRoot::ShadowRoot(Dom::from_ref(self)), + ) + }) + } } From 640fc04743e38491e582a6ba30ded5bebb0a3ebb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Fri, 25 Jan 2019 13:00:26 +0100 Subject: [PATCH 10/83] Implement shadow-including root, set node as in doc when connected. Makes JS work in shadow trees --- components/script/dom/element.rs | 9 +++---- components/script/dom/htmlscriptelement.rs | 6 ++--- components/script/dom/node.rs | 30 +++++++++++++++++----- components/script/dom/shadowroot.rs | 9 ++++++- components/script/dom/webidls/Node.webidl | 6 ++++- 5 files changed, 44 insertions(+), 16 deletions(-) diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 599efd4a8cc..20b51fbfaa1 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -14,7 +14,7 @@ use crate::dom::bindings::codegen::Bindings::ElementBinding::ElementMethods; use crate::dom::bindings::codegen::Bindings::EventBinding::EventMethods; use crate::dom::bindings::codegen::Bindings::FunctionBinding::Function; use crate::dom::bindings::codegen::Bindings::HTMLTemplateElementBinding::HTMLTemplateElementMethods; -use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; +use crate::dom::bindings::codegen::Bindings::NodeBinding::{GetRootNodeOptions, NodeMethods}; use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; use crate::dom::bindings::codegen::Bindings::WindowBinding::{ScrollBehavior, ScrollToOptions}; use crate::dom::bindings::codegen::UnionTypes::NodeOrString; @@ -484,9 +484,6 @@ impl Element { return Err(Error::InvalidState); } - self.upcast::() - .set_flag(NodeFlags::IS_IN_SHADOW_TREE, true); - // Steps 4, 5 and 6. Ok(self .shadow_root @@ -3293,7 +3290,9 @@ impl Element { /// pub fn is_connected(&self) -> bool { let node = self.upcast::(); - let root = node.GetRootNode(); + let mut options = GetRootNodeOptions::empty(); + options.composed = true; // shadow included. + let root = node.GetRootNode(&options); root.is::() } diff --git a/components/script/dom/htmlscriptelement.rs b/components/script/dom/htmlscriptelement.rs index 627cfc7e779..12399c3b58e 100644 --- a/components/script/dom/htmlscriptelement.rs +++ b/components/script/dom/htmlscriptelement.rs @@ -778,12 +778,12 @@ impl VirtualMethods for HTMLScriptElement { } } - fn bind_to_tree(&self, tree_in_doc: bool) { + fn bind_to_tree(&self, is_connected: bool) { if let Some(ref s) = self.super_type() { - s.bind_to_tree(tree_in_doc); + s.bind_to_tree(is_connected); } - if tree_in_doc && !self.parser_inserted.get() { + if is_connected && !self.parser_inserted.get() { let script = Trusted::new(self); document_from_node(self).add_delayed_task(task!(ScriptDelayedInitialize: move || { script.root().prepare(); diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 4aa6f390b16..d27b6fad873 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -10,9 +10,12 @@ use crate::dom::bindings::codegen::Bindings::CharacterDataBinding::CharacterData use crate::dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods; use crate::dom::bindings::codegen::Bindings::ElementBinding::ElementMethods; use crate::dom::bindings::codegen::Bindings::HTMLCollectionBinding::HTMLCollectionMethods; -use crate::dom::bindings::codegen::Bindings::NodeBinding::{NodeConstants, NodeMethods}; +use crate::dom::bindings::codegen::Bindings::NodeBinding::{ + GetRootNodeOptions, NodeConstants, NodeMethods, +}; use crate::dom::bindings::codegen::Bindings::NodeListBinding::NodeListMethods; use crate::dom::bindings::codegen::Bindings::ProcessingInstructionBinding::ProcessingInstructionMethods; +use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::ShadowRootBinding::ShadowRootMethods; use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; use crate::dom::bindings::codegen::InheritTypes::DocumentFragmentTypeId; use crate::dom::bindings::codegen::UnionTypes::NodeOrString; @@ -274,14 +277,23 @@ impl Node { let parent_in_doc = self.is_in_doc(); let parent_in_shadow_tree = self.is_in_shadow_tree(); for node in new_child.traverse_preorder() { - node.set_flag(NodeFlags::IS_IN_DOC, parent_in_doc); - node.set_flag(NodeFlags::IS_IN_SHADOW_TREE, parent_in_shadow_tree); if parent_in_shadow_tree { - node.set_owner_shadow_root(&*self.owner_shadow_root()); + if let Some(shadow_root) = self.downcast::() { + node.set_owner_shadow_root(&*shadow_root); + } else { + node.set_owner_shadow_root(&*self.owner_shadow_root()); + } } + let is_connected = if let Some(element) = node.downcast::() { + element.is_connected() + } else { + false + }; + node.set_flag(NodeFlags::IS_IN_DOC, parent_in_doc || is_connected); + node.set_flag(NodeFlags::IS_IN_SHADOW_TREE, parent_in_shadow_tree); // Out-of-document elements never have the descendants flag set. debug_assert!(!node.get_flag(NodeFlags::HAS_DIRTY_DESCENDANTS)); - vtable_for(&&*node).bind_to_tree(parent_in_doc); + vtable_for(&&*node).bind_to_tree(is_connected); } } @@ -2163,7 +2175,13 @@ impl NodeMethods for Node { } // https://dom.spec.whatwg.org/#dom-node-getrootnode - fn GetRootNode(&self) -> DomRoot { + fn GetRootNode(&self, options: &GetRootNodeOptions) -> DomRoot { + if options.composed { + if let Some(shadow_root) = self.owner_shadow_root.get() { + // shadow-including root. + return shadow_root.Host().upcast::().GetRootNode(options); + } + } self.inclusive_ancestors().last().unwrap() } diff --git a/components/script/dom/shadowroot.rs b/components/script/dom/shadowroot.rs index e543750e6da..a7a3bb693e5 100644 --- a/components/script/dom/shadowroot.rs +++ b/components/script/dom/shadowroot.rs @@ -4,6 +4,7 @@ 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}; @@ -12,6 +13,7 @@ use crate::dom::document::Document; use crate::dom::documentfragment::DocumentFragment; use crate::dom::documentorshadowroot::{DocumentOrShadowRoot, DocumentOrShadowRootImpl}; use crate::dom::element::Element; +use crate::dom::node::{Node, NodeFlags}; use crate::dom::stylesheetlist::StyleSheetList; use crate::dom::window::Window; use dom_struct::dom_struct; @@ -28,10 +30,15 @@ pub struct ShadowRoot { } impl ShadowRoot { + #[allow(unrooted_must_root)] fn new_inherited(host: &Element, document: &Document) -> ShadowRoot { let has_browsing_context = true; + let document_fragment = DocumentFragment::new_inherited(document); + document_fragment + .upcast::() + .set_flag(NodeFlags::IS_IN_SHADOW_TREE, true); ShadowRoot { - document_fragment: DocumentFragment::new_inherited(document), + document_fragment, document_or_shadow_root: DocumentOrShadowRootImpl::new( document.window(), has_browsing_context, diff --git a/components/script/dom/webidls/Node.webidl b/components/script/dom/webidls/Node.webidl index cddb776e416..479bec28a1f 100644 --- a/components/script/dom/webidls/Node.webidl +++ b/components/script/dom/webidls/Node.webidl @@ -32,7 +32,7 @@ interface Node : EventTarget { readonly attribute Document? ownerDocument; [Pure] - Node getRootNode(); + Node getRootNode(optional GetRootNodeOptions options); [Pure] readonly attribute Node? parentNode; @@ -92,3 +92,7 @@ interface Node : EventTarget { [CEReactions, Throws] Node removeChild(Node child); }; + +dictionary GetRootNodeOptions { + boolean composed = false; +}; From 441357b74e38b604a60206ff38e5cf3719a15e08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Sun, 27 Jan 2019 17:11:11 +0100 Subject: [PATCH 11/83] Add is_connected flag to node and use it to replace most uses of is_in_doc --- components/layout/query.rs | 2 +- components/layout_thread/dom_wrapper.rs | 6 ++--- components/script/dom/cssstyledeclaration.rs | 2 +- components/script/dom/document.rs | 8 +++--- components/script/dom/element.rs | 19 +++++++++----- components/script/dom/htmlbaseelement.rs | 12 ++++----- components/script/dom/htmlbodyelement.rs | 6 ++--- components/script/dom/htmlbuttonelement.rs | 4 +-- components/script/dom/htmlelement.rs | 2 +- components/script/dom/htmlformelement.rs | 2 +- components/script/dom/htmlheadelement.rs | 4 +-- components/script/dom/htmliframeelement.rs | 10 ++++---- components/script/dom/htmlimageelement.rs | 6 ++--- components/script/dom/htmlinputelement.rs | 4 +-- components/script/dom/htmllegendelement.rs | 4 +-- components/script/dom/htmllinkelement.rs | 8 +++--- components/script/dom/htmlmediaelement.rs | 4 +-- components/script/dom/htmlmetaelement.rs | 8 +++--- components/script/dom/htmloptionelement.rs | 4 +-- components/script/dom/htmlscriptelement.rs | 6 ++--- components/script/dom/htmlselectelement.rs | 4 +-- components/script/dom/htmlsourceelement.rs | 4 +-- components/script/dom/htmlstyleelement.rs | 8 +++--- components/script/dom/htmltextareaelement.rs | 4 +-- components/script/dom/htmltitleelement.rs | 8 +++--- components/script/dom/node.rs | 26 +++++++++++++------- components/script/dom/virtualmethods.rs | 8 +++--- components/style/dom.rs | 4 +-- components/style/dom_apis.rs | 20 +++++++-------- 29 files changed, 111 insertions(+), 96 deletions(-) diff --git a/components/layout/query.rs b/components/layout/query.rs index 7a795e387fe..a74eda165e2 100644 --- a/components/layout/query.rs +++ b/components/layout/query.rs @@ -1050,7 +1050,7 @@ fn inner_text_collection_steps( // Step 3. let display = style.get_box().display; - if !child.is_in_document() || display == Display::None { + if !child.is_connected() || display == Display::None { continue; } diff --git a/components/layout_thread/dom_wrapper.rs b/components/layout_thread/dom_wrapper.rs index 14c09923aec..497c7f135d2 100644 --- a/components/layout_thread/dom_wrapper.rs +++ b/components/layout_thread/dom_wrapper.rs @@ -260,8 +260,8 @@ impl<'ln> TNode for ServoLayoutNode<'ln> { None } - fn is_in_document(&self) -> bool { - unsafe { self.node.get_flag(NodeFlags::IS_IN_DOC) } + fn is_connected(&self) -> bool { + unsafe { self.node.get_flag(NodeFlags::IS_CONNECTED) } } } @@ -488,7 +488,7 @@ impl<'le> TElement for ServoLayoutElement<'le> { } unsafe fn set_dirty_descendants(&self) { - debug_assert!(self.as_node().is_in_document()); + debug_assert!(self.as_node().is_connected()); self.as_node() .node .set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true) diff --git a/components/script/dom/cssstyledeclaration.rs b/components/script/dom/cssstyledeclaration.rs index 2dabe431496..5cc2f64af11 100644 --- a/components/script/dom/cssstyledeclaration.rs +++ b/components/script/dom/cssstyledeclaration.rs @@ -246,7 +246,7 @@ impl CSSStyleDeclaration { }, CSSStyleOwner::Element(ref el) => { let node = el.upcast::(); - if !node.is_in_doc() { + if !node.is_connected() { // TODO: Node should be matched against the style rules of this window. // Firefox is currently the only browser to implement this. return DOMString::new(); diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 5b1de4e6b85..623ebe79722 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -680,7 +680,7 @@ impl Document { } pub fn content_and_heritage_changed(&self, node: &Node) { - if node.is_in_doc() { + if node.is_connected() { node.note_dirty_descendants(); } @@ -749,7 +749,7 @@ impl Document { "Adding named element to document {:p}: {:p} id={}", self, element, id ); - assert!(element.upcast::().is_in_doc()); + assert!(element.upcast::().is_connected()); assert!(!id.is_empty()); let root = self.GetDocumentElement().expect( @@ -2481,12 +2481,12 @@ impl LayoutDocumentHelpers for LayoutDom { let mut elements = (*self.unsafe_get()) .pending_restyles .borrow_mut_for_layout(); - // Elements were in a document when they were adding to this list, but that + // Elements were in a document when they were added to this list, but that // may no longer be true when the next layout occurs. let result = elements .drain() .map(|(k, v)| (k.to_layout(), v)) - .filter(|&(ref k, _)| k.upcast::().get_flag(NodeFlags::IS_IN_DOC)) + .filter(|&(ref k, _)| k.upcast::().get_flag(NodeFlags::IS_CONNECTED)) .collect(); result } diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 20b51fbfaa1..5d23400e745 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -9,6 +9,7 @@ use crate::dom::attr::{Attr, AttrHelpersForLayout}; use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::codegen::Bindings::AttrBinding::AttrMethods; use crate::dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods; +use crate::dom::bindings::codegen::Bindings::DocumentFragmentBinding::DocumentFragmentBinding::DocumentFragmentMethods; use crate::dom::bindings::codegen::Bindings::ElementBinding; use crate::dom::bindings::codegen::Bindings::ElementBinding::ElementMethods; use crate::dom::bindings::codegen::Bindings::EventBinding::EventMethods; @@ -1202,7 +1203,13 @@ impl Element { } pub fn root_element(&self) -> DomRoot { - if self.node.is_in_doc() { + if self.node.is_in_shadow_tree() { + self.upcast::() + .owner_shadow_root() + .upcast::() + .GetFirstElementChild() + .unwrap() + } else if self.node.is_in_doc() { self.upcast::() .owner_doc() .GetDocumentElement() @@ -2718,7 +2725,7 @@ impl VirtualMethods for Element { None } }); - if node.is_in_doc() { + if node.is_connected() { let value = attr.value().as_atom().clone(); match mutation { AttributeMutation::Set(old_value) => { @@ -2764,16 +2771,16 @@ impl VirtualMethods for Element { } } - fn bind_to_tree(&self, tree_in_doc: bool) { + fn bind_to_tree(&self, tree_connected: bool) { if let Some(ref s) = self.super_type() { - s.bind_to_tree(tree_in_doc); + s.bind_to_tree(tree_connected); } if let Some(f) = self.as_maybe_form_control() { f.bind_form_control_to_tree(); } - if !tree_in_doc { + if !tree_connected { return; } @@ -2792,7 +2799,7 @@ impl VirtualMethods for Element { f.unbind_form_control_from_tree(); } - if !context.tree_in_doc { + if !context.tree_connected { return; } diff --git a/components/script/dom/htmlbaseelement.rs b/components/script/dom/htmlbaseelement.rs index 6823925cb37..a08f3ba9c88 100644 --- a/components/script/dom/htmlbaseelement.rs +++ b/components/script/dom/htmlbaseelement.rs @@ -63,8 +63,8 @@ impl HTMLBaseElement { /// Update the cached base element in response to binding or unbinding from /// a tree. - pub fn bind_unbind(&self, tree_in_doc: bool) { - if !tree_in_doc { + pub fn bind_unbind(&self, tree_connected: bool) { + if !tree_connected { return; } @@ -119,13 +119,13 @@ impl VirtualMethods for HTMLBaseElement { } } - fn bind_to_tree(&self, tree_in_doc: bool) { - self.super_type().unwrap().bind_to_tree(tree_in_doc); - self.bind_unbind(tree_in_doc); + fn bind_to_tree(&self, tree_connected: bool) { + self.super_type().unwrap().bind_to_tree(tree_connected); + self.bind_unbind(tree_connected); } fn unbind_from_tree(&self, context: &UnbindContext) { self.super_type().unwrap().unbind_from_tree(context); - self.bind_unbind(context.tree_in_doc); + self.bind_unbind(context.tree_connected); } } diff --git a/components/script/dom/htmlbodyelement.rs b/components/script/dom/htmlbodyelement.rs index 951643c7ea7..ccef81f2cd8 100644 --- a/components/script/dom/htmlbodyelement.rs +++ b/components/script/dom/htmlbodyelement.rs @@ -149,12 +149,12 @@ impl VirtualMethods for HTMLBodyElement { .attribute_affects_presentational_hints(attr) } - fn bind_to_tree(&self, tree_in_doc: bool) { + fn bind_to_tree(&self, tree_connected: bool) { if let Some(ref s) = self.super_type() { - s.bind_to_tree(tree_in_doc); + s.bind_to_tree(tree_connected); } - if !tree_in_doc { + if !tree_connected { return; } diff --git a/components/script/dom/htmlbuttonelement.rs b/components/script/dom/htmlbuttonelement.rs index 96b51b472c4..85bb5e2ea56 100755 --- a/components/script/dom/htmlbuttonelement.rs +++ b/components/script/dom/htmlbuttonelement.rs @@ -232,9 +232,9 @@ impl VirtualMethods for HTMLButtonElement { } } - fn bind_to_tree(&self, tree_in_doc: bool) { + fn bind_to_tree(&self, tree_connected: bool) { if let Some(ref s) = self.super_type() { - s.bind_to_tree(tree_in_doc); + s.bind_to_tree(tree_connected); } self.upcast::() diff --git a/components/script/dom/htmlelement.rs b/components/script/dom/htmlelement.rs index ade940c536e..52184326a62 100644 --- a/components/script/dom/htmlelement.rs +++ b/components/script/dom/htmlelement.rs @@ -459,7 +459,7 @@ impl HTMLElementMethods for HTMLElement { let element = self.upcast::(); // Step 1. - let element_not_rendered = !node.is_in_doc() || !element.has_css_layout_box(); + let element_not_rendered = !node.is_connected() || !element.has_css_layout_box(); if element_not_rendered { return node.GetTextContent().unwrap(); } diff --git a/components/script/dom/htmlformelement.rs b/components/script/dom/htmlformelement.rs index 31087dc11df..cd4bb442296 100755 --- a/components/script/dom/htmlformelement.rs +++ b/components/script/dom/htmlformelement.rs @@ -1100,7 +1100,7 @@ pub trait FormControl: DomObject { let form_id = elem.get_string_attribute(&local_name!("form")); let node = elem.upcast::(); - if self.is_listed() && !form_id.is_empty() && node.is_in_doc() { + if self.is_listed() && !form_id.is_empty() && node.is_connected() { let doc = document_from_node(node); doc.register_form_id_listener(form_id, self); } diff --git a/components/script/dom/htmlheadelement.rs b/components/script/dom/htmlheadelement.rs index 5daf82fd896..ddb06f70932 100644 --- a/components/script/dom/htmlheadelement.rs +++ b/components/script/dom/htmlheadelement.rs @@ -81,9 +81,9 @@ impl VirtualMethods for HTMLHeadElement { fn super_type(&self) -> Option<&dyn VirtualMethods> { Some(self.upcast::() as &dyn VirtualMethods) } - fn bind_to_tree(&self, tree_in_doc: bool) { + fn bind_to_tree(&self, tree_connected: bool) { if let Some(ref s) = self.super_type() { - s.bind_to_tree(tree_in_doc); + s.bind_to_tree(tree_connected); } load_script(self); } diff --git a/components/script/dom/htmliframeelement.rs b/components/script/dom/htmliframeelement.rs index 24cea710450..a1afa73bddc 100644 --- a/components/script/dom/htmliframeelement.rs +++ b/components/script/dom/htmliframeelement.rs @@ -584,7 +584,7 @@ impl VirtualMethods for HTMLIFrameElement { // may be in a different script thread. Instread, we check to see if the parent // is in a document tree and has a browsing context, which is what causes // the child browsing context to be created. - if self.upcast::().is_in_doc_with_browsing_context() { + if self.upcast::().is_connected_with_browsing_context() { debug!("iframe src set while in browsing context."); self.process_the_iframe_attributes(ProcessingMode::NotFirstTime); } @@ -610,9 +610,9 @@ impl VirtualMethods for HTMLIFrameElement { } } - fn bind_to_tree(&self, tree_in_doc: bool) { + fn bind_to_tree(&self, tree_connected: bool) { if let Some(ref s) = self.super_type() { - s.bind_to_tree(tree_in_doc); + s.bind_to_tree(tree_connected); } let iframe = Trusted::new(self); @@ -624,9 +624,9 @@ impl VirtualMethods for HTMLIFrameElement { // browsing context, set the element's nested browsing context // to the newly-created browsing context, and then process the // iframe attributes for the "first time"." - if this.upcast::().is_in_doc_with_browsing_context() { + if this.upcast::().is_connected_with_browsing_context() { debug!("iframe bound to browsing context."); - debug_assert!(tree_in_doc, "is_in_doc_with_bc, but not tree_in_doc"); + debug_assert!(tree_connected, "is_connected_with_bc, but not tree_connected"); this.create_nested_browsing_context(); this.process_the_iframe_attributes(ProcessingMode::FirstTime); } diff --git a/components/script/dom/htmlimageelement.rs b/components/script/dom/htmlimageelement.rs index 3848b3d7d2a..7ad2aeac1e6 100644 --- a/components/script/dom/htmlimageelement.rs +++ b/components/script/dom/htmlimageelement.rs @@ -1645,12 +1645,12 @@ impl VirtualMethods for HTMLImageElement { } } - fn bind_to_tree(&self, tree_in_doc: bool) { + fn bind_to_tree(&self, tree_connected: bool) { if let Some(ref s) = self.super_type() { - s.bind_to_tree(tree_in_doc); + s.bind_to_tree(tree_connected); } let document = document_from_node(self); - if tree_in_doc { + if tree_connected { document.register_responsive_image(self); } diff --git a/components/script/dom/htmlinputelement.rs b/components/script/dom/htmlinputelement.rs index 94ffadb69fd..7adda0a1cae 100755 --- a/components/script/dom/htmlinputelement.rs +++ b/components/script/dom/htmlinputelement.rs @@ -1422,9 +1422,9 @@ impl VirtualMethods for HTMLInputElement { } } - fn bind_to_tree(&self, tree_in_doc: bool) { + fn bind_to_tree(&self, tree_connected: bool) { if let Some(ref s) = self.super_type() { - s.bind_to_tree(tree_in_doc); + s.bind_to_tree(tree_connected); } self.upcast::() .check_ancestors_disabled_state_for_form_control(); diff --git a/components/script/dom/htmllegendelement.rs b/components/script/dom/htmllegendelement.rs index b69a066d9a1..a623eb5cd79 100644 --- a/components/script/dom/htmllegendelement.rs +++ b/components/script/dom/htmllegendelement.rs @@ -56,9 +56,9 @@ impl VirtualMethods for HTMLLegendElement { Some(self.upcast::() as &dyn VirtualMethods) } - fn bind_to_tree(&self, tree_in_doc: bool) { + fn bind_to_tree(&self, tree_connected: bool) { if let Some(ref s) = self.super_type() { - s.bind_to_tree(tree_in_doc); + s.bind_to_tree(tree_connected); } self.upcast::() diff --git a/components/script/dom/htmllinkelement.rs b/components/script/dom/htmllinkelement.rs index 36bafa58fb5..6623593bc43 100644 --- a/components/script/dom/htmllinkelement.rs +++ b/components/script/dom/htmllinkelement.rs @@ -183,7 +183,7 @@ impl VirtualMethods for HTMLLinkElement { fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) { self.super_type().unwrap().attribute_mutated(attr, mutation); - if !self.upcast::().is_in_doc() || mutation.is_removal() { + if !self.upcast::().is_connected() || mutation.is_removal() { return; } @@ -222,12 +222,12 @@ impl VirtualMethods for HTMLLinkElement { } } - fn bind_to_tree(&self, tree_in_doc: bool) { + fn bind_to_tree(&self, tree_connected: bool) { if let Some(ref s) = self.super_type() { - s.bind_to_tree(tree_in_doc); + s.bind_to_tree(tree_connected); } - if tree_in_doc { + if tree_connected { let element = self.upcast(); let rel = get_attr(element, &local_name!("rel")); diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index 1b5f991ac8e..74c7c7ade62 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -2009,7 +2009,7 @@ impl VirtualMethods for HTMLMediaElement { fn unbind_from_tree(&self, context: &UnbindContext) { self.super_type().unwrap().unbind_from_tree(context); - if context.tree_in_doc { + if context.tree_connected { let task = MediaElementMicrotask::PauseIfNotInDocumentTask { elem: DomRoot::from_ref(self), }; @@ -2061,7 +2061,7 @@ impl MicrotaskRunnable for MediaElementMicrotask { } }, &MediaElementMicrotask::PauseIfNotInDocumentTask { ref elem } => { - if !elem.upcast::().is_in_doc() { + if !elem.upcast::().is_connected() { elem.internal_pause_steps(); } }, diff --git a/components/script/dom/htmlmetaelement.rs b/components/script/dom/htmlmetaelement.rs index a8e829c3d1c..de605c31092 100644 --- a/components/script/dom/htmlmetaelement.rs +++ b/components/script/dom/htmlmetaelement.rs @@ -171,12 +171,12 @@ impl VirtualMethods for HTMLMetaElement { Some(self.upcast::() as &dyn VirtualMethods) } - fn bind_to_tree(&self, tree_in_doc: bool) { + fn bind_to_tree(&self, tree_connected: bool) { if let Some(ref s) = self.super_type() { - s.bind_to_tree(tree_in_doc); + s.bind_to_tree(tree_connected); } - if tree_in_doc { + if tree_connected { self.process_attributes(); } } @@ -204,7 +204,7 @@ impl VirtualMethods for HTMLMetaElement { s.unbind_from_tree(context); } - if context.tree_in_doc { + if context.tree_connected { self.process_referrer_attribute(); if let Some(s) = self.stylesheet.borrow_mut().take() { diff --git a/components/script/dom/htmloptionelement.rs b/components/script/dom/htmloptionelement.rs index 494ff7b0a8c..e232aa63712 100644 --- a/components/script/dom/htmloptionelement.rs +++ b/components/script/dom/htmloptionelement.rs @@ -235,9 +235,9 @@ impl VirtualMethods for HTMLOptionElement { } } - fn bind_to_tree(&self, tree_in_doc: bool) { + fn bind_to_tree(&self, tree_connected: bool) { if let Some(ref s) = self.super_type() { - s.bind_to_tree(tree_in_doc); + s.bind_to_tree(tree_connected); } self.upcast::() diff --git a/components/script/dom/htmlscriptelement.rs b/components/script/dom/htmlscriptelement.rs index 12399c3b58e..299c66a04d8 100644 --- a/components/script/dom/htmlscriptelement.rs +++ b/components/script/dom/htmlscriptelement.rs @@ -372,7 +372,7 @@ impl HTMLScriptElement { } // Step 5. - if !self.upcast::().is_in_doc() { + if !self.upcast::().is_connected() { return; } @@ -760,7 +760,7 @@ impl VirtualMethods for HTMLScriptElement { match *attr.local_name() { local_name!("src") => { if let AttributeMutation::Set(_) = mutation { - if !self.parser_inserted.get() && self.upcast::().is_in_doc() { + if !self.parser_inserted.get() && self.upcast::().is_connected() { self.prepare(); } } @@ -773,7 +773,7 @@ impl VirtualMethods for HTMLScriptElement { if let Some(ref s) = self.super_type() { s.children_changed(mutation); } - if !self.parser_inserted.get() && self.upcast::().is_in_doc() { + if !self.parser_inserted.get() && self.upcast::().is_connected() { self.prepare(); } } diff --git a/components/script/dom/htmlselectelement.rs b/components/script/dom/htmlselectelement.rs index 50d88710161..4bcdcc85160 100755 --- a/components/script/dom/htmlselectelement.rs +++ b/components/script/dom/htmlselectelement.rs @@ -382,9 +382,9 @@ impl VirtualMethods for HTMLSelectElement { } } - fn bind_to_tree(&self, tree_in_doc: bool) { + fn bind_to_tree(&self, tree_connected: bool) { if let Some(ref s) = self.super_type() { - s.bind_to_tree(tree_in_doc); + s.bind_to_tree(tree_connected); } self.upcast::() diff --git a/components/script/dom/htmlsourceelement.rs b/components/script/dom/htmlsourceelement.rs index 783bcde4c80..22a03f5ae6c 100644 --- a/components/script/dom/htmlsourceelement.rs +++ b/components/script/dom/htmlsourceelement.rs @@ -82,8 +82,8 @@ impl VirtualMethods for HTMLSourceElement { } /// - fn bind_to_tree(&self, tree_in_doc: bool) { - self.super_type().unwrap().bind_to_tree(tree_in_doc); + fn bind_to_tree(&self, tree_connected: bool) { + self.super_type().unwrap().bind_to_tree(tree_connected); let parent = self.upcast::().GetParentNode().unwrap(); if let Some(media) = parent.downcast::() { media.handle_source_child_insertion(); diff --git a/components/script/dom/htmlstyleelement.rs b/components/script/dom/htmlstyleelement.rs index b4065d205a8..20617a37079 100644 --- a/components/script/dom/htmlstyleelement.rs +++ b/components/script/dom/htmlstyleelement.rs @@ -185,14 +185,14 @@ impl VirtualMethods for HTMLStyleElement { } } - fn bind_to_tree(&self, tree_in_doc: bool) { - self.super_type().unwrap().bind_to_tree(tree_in_doc); + fn bind_to_tree(&self, tree_connected: bool) { + self.super_type().unwrap().bind_to_tree(tree_connected); // https://html.spec.whatwg.org/multipage/#update-a-style-block // Handles the case when: // "The element is not on the stack of open elements of an HTML parser or XML parser, // and it becomes connected or disconnected." - if tree_in_doc && !self.in_stack_of_open_elements.get() { + if tree_connected && !self.in_stack_of_open_elements.get() { self.parse_own_css(); } } @@ -214,7 +214,7 @@ impl VirtualMethods for HTMLStyleElement { s.unbind_from_tree(context); } - if context.tree_in_doc { + if context.tree_connected { if let Some(s) = self.stylesheet.borrow_mut().take() { document_from_node(self).remove_stylesheet(self.upcast(), &s) } diff --git a/components/script/dom/htmltextareaelement.rs b/components/script/dom/htmltextareaelement.rs index 9116b26b575..39057da6347 100755 --- a/components/script/dom/htmltextareaelement.rs +++ b/components/script/dom/htmltextareaelement.rs @@ -466,9 +466,9 @@ impl VirtualMethods for HTMLTextAreaElement { } } - fn bind_to_tree(&self, tree_in_doc: bool) { + fn bind_to_tree(&self, tree_connected: bool) { if let Some(ref s) = self.super_type() { - s.bind_to_tree(tree_in_doc); + s.bind_to_tree(tree_connected); } self.upcast::() diff --git a/components/script/dom/htmltitleelement.rs b/components/script/dom/htmltitleelement.rs index 1aa60373df6..1c26580eec5 100644 --- a/components/script/dom/htmltitleelement.rs +++ b/components/script/dom/htmltitleelement.rs @@ -69,17 +69,17 @@ impl VirtualMethods for HTMLTitleElement { s.children_changed(mutation); } let node = self.upcast::(); - if node.is_in_doc() { + if node.is_connected() { node.owner_doc().title_changed(); } } - fn bind_to_tree(&self, tree_in_doc: bool) { + fn bind_to_tree(&self, tree_connected: bool) { if let Some(ref s) = self.super_type() { - s.bind_to_tree(tree_in_doc); + s.bind_to_tree(tree_connected); } let node = self.upcast::(); - if tree_in_doc { + if tree_connected { node.owner_doc().title_changed(); } } diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index d27b6fad873..6527a4a904f 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -190,8 +190,11 @@ bitflags! { /// Whether this element has already handled the stored snapshot. const HANDLED_SNAPSHOT = 1 << 8; - // Whether this node participates in a shadow tree. + /// Whether this node participates in a shadow tree. const IS_IN_SHADOW_TREE = 1 << 9; + + /// Specifies whether this node's shadow-including root is a document. + const IS_CONNECTED = 1 << 10; } } @@ -289,8 +292,9 @@ impl Node { } else { false }; - node.set_flag(NodeFlags::IS_IN_DOC, parent_in_doc || is_connected); + node.set_flag(NodeFlags::IS_IN_DOC, parent_in_doc); node.set_flag(NodeFlags::IS_IN_SHADOW_TREE, parent_in_shadow_tree); + node.set_flag(NodeFlags::IS_CONNECTED, is_connected); // Out-of-document elements never have the descendants flag set. debug_assert!(!node.get_flag(NodeFlags::HAS_DIRTY_DESCENDANTS)); vtable_for(&&*node).bind_to_tree(is_connected); @@ -492,6 +496,10 @@ impl Node { self.flags.get().contains(NodeFlags::IS_IN_SHADOW_TREE) } + pub fn is_connected(&self) -> bool { + self.flags.get().contains(NodeFlags::IS_CONNECTED) + } + /// Returns the type ID of this node. pub fn type_id(&self) -> NodeTypeId { match *self.eventtarget.type_id() { @@ -550,7 +558,7 @@ impl Node { // FIXME(emilio): This and the function below should move to Element. pub fn note_dirty_descendants(&self) { - debug_assert!(self.is_in_doc()); + debug_assert!(self.is_connected()); for ancestor in self.inclusive_ancestors() { if ancestor.get_flag(NodeFlags::HAS_DIRTY_DESCENDANTS) { @@ -583,7 +591,7 @@ impl Node { pub fn dirty(&self, damage: NodeDamage) { self.rev_version(); - if !self.is_in_doc() { + if !self.is_connected() { return; } @@ -917,8 +925,8 @@ impl Node { self.owner_doc().is_html_document() } - pub fn is_in_doc_with_browsing_context(&self) -> bool { - self.is_in_doc() && self.owner_doc().browsing_context().is_some() + pub fn is_connected_with_browsing_context(&self) -> bool { + self.is_connected() && self.owner_doc().browsing_context().is_some() } pub fn children(&self) -> impl Iterator> { @@ -2915,8 +2923,8 @@ pub struct UnbindContext<'a> { prev_sibling: Option<&'a Node>, /// The next sibling of the inclusive ancestor that was removed. pub next_sibling: Option<&'a Node>, - /// Whether the tree is in a document. - pub tree_in_doc: bool, + /// Whether the tree is connected. + pub tree_connected: bool, } impl<'a> UnbindContext<'a> { @@ -2932,7 +2940,7 @@ impl<'a> UnbindContext<'a> { parent: parent, prev_sibling: prev_sibling, next_sibling: next_sibling, - tree_in_doc: parent.is_in_doc(), + tree_connected: parent.is_connected(), } } diff --git a/components/script/dom/virtualmethods.rs b/components/script/dom/virtualmethods.rs index 7a41642a201..2bb90e93b53 100644 --- a/components/script/dom/virtualmethods.rs +++ b/components/script/dom/virtualmethods.rs @@ -90,15 +90,15 @@ pub trait VirtualMethods { } } - /// Called when a Node is appended to a tree, where 'tree_in_doc' indicates + /// Called when a Node is appended to a tree, where 'tree_connected' indicates /// whether the tree is part of a Document. - fn bind_to_tree(&self, tree_in_doc: bool) { + fn bind_to_tree(&self, tree_connected: bool) { if let Some(ref s) = self.super_type() { - s.bind_to_tree(tree_in_doc); + s.bind_to_tree(tree_connected); } } - /// Called when a Node is removed from a tree, where 'tree_in_doc' + /// Called when a Node is removed from a tree, where 'tree_connected' /// indicates whether the tree is part of a Document. /// Implements removing steps: /// diff --git a/components/style/dom.rs b/components/style/dom.rs index 967b978bad4..d282ceeafad 100644 --- a/components/style/dom.rs +++ b/components/style/dom.rs @@ -185,8 +185,8 @@ pub trait TNode: Sized + Copy + Clone + Debug + NodeInfo + PartialEq { DomChildren(self.first_child()) } - /// Returns whether the node is attached to a document. - fn is_in_document(&self) -> bool; + /// Returns whether the node is connected. + fn is_connected(&self) -> bool; /// Iterate over the DOM children of a node, in preorder. fn dom_descendants(&self) -> DomDescendants { diff --git a/components/style/dom_apis.rs b/components/style/dom_apis.rs index e43c861271e..1ef07e24a4a 100644 --- a/components/style/dom_apis.rs +++ b/components/style/dom_apis.rs @@ -231,7 +231,7 @@ where // Optimize for when the root is a document or a shadow root and the element // is connected to that root. if root.as_document().is_some() { - debug_assert!(element.as_node().is_in_document(), "Not connected?"); + debug_assert!(element.as_node().is_connected(), "Not connected?"); debug_assert_eq!( root, root.owner_doc().as_node(), @@ -275,18 +275,18 @@ where return Err(()); } - if root.is_in_document() { + if root.is_connected() { + if let Some(shadow) = root.as_shadow_root() { + return shadow.elements_with_id(id); + } + + if let Some(shadow) = root.as_element().and_then(|e| e.containing_shadow()) { + return shadow.elements_with_id(id); + } + return root.owner_doc().elements_with_id(id); } - if let Some(shadow) = root.as_shadow_root() { - return shadow.elements_with_id(id); - } - - if let Some(shadow) = root.as_element().and_then(|e| e.containing_shadow()) { - return shadow.elements_with_id(id); - } - Err(()) } From ea69bbc75b6a40af77df5528b23a05b29385f488 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Mon, 28 Jan 2019 15:48:12 +0100 Subject: [PATCH 12/83] Node retargeting algorithm --- components/script/dom/node.rs | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 6527a4a904f..6c509d70c16 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -640,6 +640,10 @@ impl Node { parent.ancestors().any(|ancestor| &*ancestor == self) } + fn is_shadow_including_inclusive_ancestor_of(&self, node: &Node) -> bool { + node.shadow_including_inclusive_ancestors().any(|ancestor| &*ancestor == self) + } + pub fn following_siblings(&self) -> impl Iterator> { SimpleNodeIterator { current: self.GetNextSibling(), @@ -905,6 +909,20 @@ impl Node { } } + /// https://dom.spec.whatwg.org/#concept-shadow-including-inclusive-ancestor + pub fn shadow_including_inclusive_ancestors(&self) -> impl Iterator> { + SimpleNodeIterator { + current: Some(DomRoot::from_ref(self)), + next_node: |n| { + if let Some(shadow_root) = n.downcast::() { + Some(DomRoot::from_ref(shadow_root.Host().upcast::())) + } else { + n.GetParentNode() + } + }, + } + } + pub fn owner_doc(&self) -> DomRoot { self.owner_doc.get().unwrap() } @@ -1087,6 +1105,19 @@ impl Node { None } } + + /// https://dom.spec.whatwg.org/#retarget + pub fn retarget(&self, a: &Node, b: &Node) -> DomRoot { + let mut a = DomRoot::from_ref(&*a); + loop { + let a_root = a.GetRootNode(&GetRootNodeOptions::empty()); + if !a_root.is::() || a_root.is_shadow_including_inclusive_ancestor_of(b) { + return DomRoot::from_ref(&a); + } + + a = DomRoot::from_ref(a_root.downcast::().unwrap().Host().upcast::()); + } + } } /// Iterate through `nodes` until we find a `Node` that is not in `not_in` From 4740ce53a0cfe64e82ecedd02667390327805f2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Mon, 28 Jan 2019 15:57:42 +0100 Subject: [PATCH 13/83] Make note_dirty_descendants jump around shadow roots --- components/script/dom/node.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 6c509d70c16..9a248e7263f 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -560,7 +560,7 @@ impl Node { pub fn note_dirty_descendants(&self) { debug_assert!(self.is_connected()); - for ancestor in self.inclusive_ancestors() { + for ancestor in self.shadow_including_inclusive_ancestors() { if ancestor.get_flag(NodeFlags::HAS_DIRTY_DESCENDANTS) { return; } From df81debffcdf2d73bfbc936392236fd82d61aeac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Mon, 28 Jan 2019 17:33:24 +0100 Subject: [PATCH 14/83] Set connected flag not only on elements --- components/script/dom/node.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 9a248e7263f..25a0c4625e8 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -279,6 +279,7 @@ impl Node { let parent_in_doc = self.is_in_doc(); let parent_in_shadow_tree = self.is_in_shadow_tree(); + let parent_is_connected = self.is_connected(); for node in new_child.traverse_preorder() { if parent_in_shadow_tree { if let Some(shadow_root) = self.downcast::() { @@ -287,11 +288,12 @@ impl Node { node.set_owner_shadow_root(&*self.owner_shadow_root()); } } - let is_connected = if let Some(element) = node.downcast::() { - element.is_connected() - } else { - false - }; + let mut is_connected = parent_is_connected; + if !is_connected { + if let Some(element) = node.downcast::() { + is_connected = element.is_connected(); + } + } node.set_flag(NodeFlags::IS_IN_DOC, parent_in_doc); node.set_flag(NodeFlags::IS_IN_SHADOW_TREE, parent_in_shadow_tree); node.set_flag(NodeFlags::IS_CONNECTED, is_connected); From 1b036355ced7cd6b8195970fef07383ba3561c4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Mon, 28 Jan 2019 18:12:31 +0100 Subject: [PATCH 15/83] Bind/unbind shadow host children to/from tree --- components/script/dom/element.rs | 20 ++++++++++++++++++++ components/script/dom/node.rs | 11 +++++++++-- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 5d23400e745..dac2d29e51f 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -2784,6 +2784,16 @@ impl VirtualMethods for Element { return; } + if self.is_shadow_host() { + let shadow_root = self.shadow_root.get().unwrap(); + let shadow_root = shadow_root.upcast::(); + shadow_root.set_flag(NodeFlags::IS_CONNECTED, tree_connected); + for node in shadow_root.children() { + node.set_flag(NodeFlags::IS_CONNECTED, tree_connected); + node.bind_to_tree(tree_connected); + } + } + let doc = document_from_node(self); if let Some(ref value) = *self.id_attribute.borrow() { doc.register_named_element(self, value.clone()); @@ -2803,6 +2813,16 @@ impl VirtualMethods for Element { return; } + if self.is_shadow_host() { + let shadow_root = self.shadow_root.get().unwrap(); + let shadow_root = shadow_root.upcast::(); + shadow_root.set_flag(NodeFlags::IS_CONNECTED, false); + for node in shadow_root.children() { + node.set_flag(NodeFlags::IS_CONNECTED, false); + node.unbind_from_tree(context); + } + } + let doc = document_from_node(self); let fullscreen = doc.GetFullscreenElement(); if fullscreen.deref() == Some(self) { diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 25a0c4625e8..1585f81693e 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -643,7 +643,8 @@ impl Node { } fn is_shadow_including_inclusive_ancestor_of(&self, node: &Node) -> bool { - node.shadow_including_inclusive_ancestors().any(|ancestor| &*ancestor == self) + node.shadow_including_inclusive_ancestors() + .any(|ancestor| &*ancestor == self) } pub fn following_siblings(&self) -> impl Iterator> { @@ -1117,7 +1118,13 @@ impl Node { return DomRoot::from_ref(&a); } - a = DomRoot::from_ref(a_root.downcast::().unwrap().Host().upcast::()); + a = DomRoot::from_ref( + a_root + .downcast::() + .unwrap() + .Host() + .upcast::(), + ); } } } From c48ad0ff7ee8a7573ce5c5e5b015b7f133dbb3a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Tue, 29 Jan 2019 11:00:14 +0100 Subject: [PATCH 16/83] Introduce concept of composed parent node --- components/script/dom/node.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 1585f81693e..e05bd2b9aa4 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -108,6 +108,9 @@ pub struct Node { /// The parent of this node. parent_node: MutNullableDom, + /// The parent of this node, ignoring shadow roots. + composed_parent_node: MutNullableDom, + /// The first child of this node. first_child: MutNullableDom, @@ -240,6 +243,7 @@ impl Node { /// Fails unless `new_child` is disconnected from the tree. fn add_child(&self, new_child: &Node, before: Option<&Node>) { assert!(new_child.parent_node.get().is_none()); + assert!(new_child.composed_parent_node.get().is_none()); assert!(new_child.prev_sibling.get().is_none()); assert!(new_child.next_sibling.get().is_none()); match before { @@ -275,6 +279,11 @@ impl Node { } new_child.parent_node.set(Some(self)); + if let Some(shadow_root) = self.downcast::() { + new_child.composed_parent_node.set(Some(shadow_root.Host().upcast::())); + } else { + new_child.composed_parent_node.set(Some(self)); + } self.children_count.set(self.children_count.get() + 1); let parent_in_doc = self.is_in_doc(); @@ -341,6 +350,7 @@ impl Node { child.prev_sibling.set(None); child.next_sibling.set(None); child.parent_node.set(None); + child.composed_parent_node.set(None); self.children_count.set(self.children_count.get() - 1); for node in child.traverse_preorder() { @@ -599,7 +609,7 @@ impl Node { match self.type_id() { NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::Text)) => self - .parent_node + .composed_parent_node .get() .unwrap() .downcast::() @@ -1581,6 +1591,7 @@ impl Node { eventtarget: EventTarget::new_inherited(), parent_node: Default::default(), + composed_parent_node: Default::default(), first_child: Default::default(), last_child: Default::default(), next_sibling: Default::default(), From d6ddb08e23965c3b037bb61829015009a30f86fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Tue, 29 Jan 2019 12:33:46 +0100 Subject: [PATCH 17/83] Do not care about shadow roots when getting root element --- components/script/dom/element.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index dac2d29e51f..bde1d46582f 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -9,7 +9,6 @@ use crate::dom::attr::{Attr, AttrHelpersForLayout}; use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::codegen::Bindings::AttrBinding::AttrMethods; use crate::dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods; -use crate::dom::bindings::codegen::Bindings::DocumentFragmentBinding::DocumentFragmentBinding::DocumentFragmentMethods; use crate::dom::bindings::codegen::Bindings::ElementBinding; use crate::dom::bindings::codegen::Bindings::ElementBinding::ElementMethods; use crate::dom::bindings::codegen::Bindings::EventBinding::EventMethods; @@ -1203,13 +1202,7 @@ impl Element { } pub fn root_element(&self) -> DomRoot { - if self.node.is_in_shadow_tree() { - self.upcast::() - .owner_shadow_root() - .upcast::() - .GetFirstElementChild() - .unwrap() - } else if self.node.is_in_doc() { + if self.node.is_in_doc() { self.upcast::() .owner_doc() .GetDocumentElement() From 6a85409ffe674f92c08d5d79c4b6fe68dac5ad93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Tue, 29 Jan 2019 15:06:34 +0100 Subject: [PATCH 18/83] Throw NotSupported when trying to deep clone a shadow root --- components/script/dom/node.rs | 13 +++++++++---- components/script/dom/range.rs | 16 ++++++++-------- components/script/dom/webidls/Node.webidl | 2 +- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index e05bd2b9aa4..cecad5d7b76 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -280,7 +280,9 @@ impl Node { new_child.parent_node.set(Some(self)); if let Some(shadow_root) = self.downcast::() { - new_child.composed_parent_node.set(Some(shadow_root.Host().upcast::())); + new_child + .composed_parent_node + .set(Some(shadow_root.Host().upcast::())); } else { new_child.composed_parent_node.set(Some(self)); } @@ -2528,8 +2530,11 @@ impl NodeMethods for Node { } // https://dom.spec.whatwg.org/#dom-node-clonenode - fn CloneNode(&self, deep: bool) -> DomRoot { - Node::clone( + fn CloneNode(&self, deep: bool) -> Fallible> { + if deep && self.is::() { + return Err(Error::NotSupported); + } + Ok(Node::clone( self, None, if deep { @@ -2537,7 +2542,7 @@ impl NodeMethods for Node { } else { CloneChildrenFlag::DoNotCloneChildren }, - ) + )) } // https://dom.spec.whatwg.org/#dom-node-isequalnode diff --git a/components/script/dom/range.rs b/components/script/dom/range.rs index 96f276944bc..afa759de52f 100644 --- a/components/script/dom/range.rs +++ b/components/script/dom/range.rs @@ -500,7 +500,7 @@ impl RangeMethods for Range { fragment.upcast::().AppendChild(&clone)?; } else { // Step 14.1. - let clone = child.CloneNode(false); + let clone = child.CloneNode(/* deep */ false)?; // Step 14.2. fragment.upcast::().AppendChild(&clone)?; // Step 14.3. @@ -521,7 +521,7 @@ impl RangeMethods for Range { // Step 15. for child in contained_children { // Step 15.1. - let clone = child.CloneNode(true); + let clone = child.CloneNode(/* deep */ true)?; // Step 15.2. fragment.upcast::().AppendChild(&clone)?; } @@ -537,7 +537,7 @@ impl RangeMethods for Range { fragment.upcast::().AppendChild(&clone)?; } else { // Step 17.1. - let clone = child.CloneNode(false); + let clone = child.CloneNode(/* deep */ false)?; // Step 17.2. fragment.upcast::().AppendChild(&clone)?; // Step 17.3. @@ -573,7 +573,7 @@ impl RangeMethods for Range { if end_node == start_node { if let Some(end_data) = end_node.downcast::() { // Step 4.1. - let clone = end_node.CloneNode(true); + let clone = end_node.CloneNode(/* deep */ true)?; // Step 4.2. let text = end_data.SubstringData(start_offset, end_offset - start_offset); clone @@ -614,7 +614,7 @@ impl RangeMethods for Range { if let Some(start_data) = child.downcast::() { assert!(child == start_node); // Step 15.1. - let clone = start_node.CloneNode(true); + let clone = start_node.CloneNode(/* deep */ true)?; // Step 15.2. let text = start_data.SubstringData(start_offset, start_node.len() - start_offset); clone @@ -631,7 +631,7 @@ impl RangeMethods for Range { )?; } else { // Step 16.1. - let clone = child.CloneNode(false); + let clone = child.CloneNode(/* deep */ false)?; // Step 16.2. fragment.upcast::().AppendChild(&clone)?; // Step 16.3. @@ -658,7 +658,7 @@ impl RangeMethods for Range { if let Some(end_data) = child.downcast::() { assert!(child == end_node); // Step 18.1. - let clone = end_node.CloneNode(true); + let clone = end_node.CloneNode(/* deep */ true)?; // Step 18.2. let text = end_data.SubstringData(0, end_offset); clone @@ -671,7 +671,7 @@ impl RangeMethods for Range { end_data.ReplaceData(0, end_offset, DOMString::new())?; } else { // Step 19.1. - let clone = child.CloneNode(false); + let clone = child.CloneNode(/* deep */ false)?; // Step 19.2. fragment.upcast::().AppendChild(&clone)?; // Step 19.3. diff --git a/components/script/dom/webidls/Node.webidl b/components/script/dom/webidls/Node.webidl index 479bec28a1f..9433e96efa2 100644 --- a/components/script/dom/webidls/Node.webidl +++ b/components/script/dom/webidls/Node.webidl @@ -58,7 +58,7 @@ interface Node : EventTarget { [CEReactions] void normalize(); - [CEReactions] + [CEReactions, Throws] Node cloneNode(optional boolean deep = false); [Pure] boolean isEqualNode(Node? node); From f6ba16588280aa6c2dcd872860a181c74b270c9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Tue, 29 Jan 2019 16:14:17 +0100 Subject: [PATCH 19/83] Throw when trying to import or adopt a shadow root --- components/script/dom/document.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 623ebe79722..14dc0643925 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -87,6 +87,7 @@ use crate::dom::progressevent::ProgressEvent; use crate::dom::promise::Promise; use crate::dom::range::Range; use crate::dom::servoparser::ServoParser; +use crate::dom::shadowroot::ShadowRoot; use crate::dom::storageevent::StorageEvent; use crate::dom::stylesheetlist::StyleSheetList; use crate::dom::text::Text; @@ -3625,7 +3626,7 @@ impl DocumentMethods for Document { // https://dom.spec.whatwg.org/#dom-document-importnode fn ImportNode(&self, node: &Node, deep: bool) -> Fallible> { // Step 1. - if node.is::() { + if node.is::() || node.is::() { return Err(Error::NotSupported); } @@ -3647,9 +3648,14 @@ impl DocumentMethods for Document { } // Step 2. - Node::adopt(node, self); + if node.is::() { + return Err(Error::HierarchyRequest); + } // Step 3. + Node::adopt(node, self); + + // Step 4. Ok(DomRoot::from_ref(node)) } From 2e5c0584637079889f4ed490b98afe07445f26d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Wed, 30 Jan 2019 16:19:40 +0100 Subject: [PATCH 20/83] Implement concept of shadow including tree order --- components/script/devtools.rs | 2 +- .../script/dom/customelementregistry.rs | 2 +- components/script/dom/document.rs | 21 ++++--- components/script/dom/documentfragment.rs | 2 +- components/script/dom/element.rs | 2 +- components/script/dom/htmlelement.rs | 2 +- components/script/dom/htmlfieldsetelement.rs | 2 +- components/script/dom/htmlformelement.rs | 2 +- components/script/dom/htmlheadelement.rs | 2 +- components/script/dom/htmlimageelement.rs | 2 +- components/script/dom/htmllabelelement.rs | 2 +- components/script/dom/htmlmapelement.rs | 2 +- components/script/dom/node.rs | 62 ++++++++++++------- components/script/dom/range.rs | 5 +- components/script/webdriver_handlers.rs | 2 +- 15 files changed, 69 insertions(+), 43 deletions(-) diff --git a/components/script/devtools.rs b/components/script/devtools.rs index 7a24d959980..9494dbe41ac 100644 --- a/components/script/devtools.rs +++ b/components/script/devtools.rs @@ -103,7 +103,7 @@ fn find_node_by_unique_id( documents.find_document(pipeline).and_then(|document| { document .upcast::() - .traverse_preorder() + .traverse_preorder(/* shadow including */ false) .find(|candidate| candidate.unique_id() == node_id) }) } diff --git a/components/script/dom/customelementregistry.rs b/components/script/dom/customelementregistry.rs index abefc4eca58..411d5c7fb7b 100644 --- a/components/script/dom/customelementregistry.rs +++ b/components/script/dom/customelementregistry.rs @@ -364,7 +364,7 @@ impl CustomElementRegistryMethods for CustomElementRegistry { // Steps 14-15 for candidate in document .upcast::() - .traverse_preorder() + .traverse_preorder(/* shadow including */ true) .filter_map(DomRoot::downcast::) { let is = candidate.get_is(); diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 14dc0643925..3ed7082e4b5 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -631,7 +631,7 @@ impl Document { pub fn refresh_base_element(&self) { let base = self .upcast::() - .traverse_preorder() + .traverse_preorder(/* shadow including */ false) .filter_map(DomRoot::downcast::) .find(|element| { element @@ -869,7 +869,7 @@ impl Document { }; let doc_node = self.upcast::(); doc_node - .traverse_preorder() + .traverse_preorder(/* shadow including */ false) .filter_map(DomRoot::downcast) .find(|node| check_anchor(&node)) .map(DomRoot::upcast) @@ -978,7 +978,7 @@ impl Document { pub fn dirty_all_nodes(&self) { let root = self.upcast::(); - for node in root.traverse_preorder() { + for node in root.traverse_preorder(/* shadow including */ true) { node.dirty(NodeDamage::OtherNodeDamage) } } @@ -2273,7 +2273,7 @@ impl Document { /// Iterate over all iframes in the document. pub fn iter_iframes(&self) -> impl Iterator> { self.upcast::() - .traverse_preorder() + .traverse_preorder(/* shadow including */ true) .filter_map(DomRoot::downcast::) } @@ -2837,7 +2837,7 @@ impl Document { let maybe_node = doc.deref().map(Castable::upcast::); let iter = maybe_node .iter() - .flat_map(|node| node.traverse_preorder()) + .flat_map(|node| node.traverse_preorder(/* shadow including */ false)) .filter(|node| callback(&node)); NodeList::new_simple_list(&self.window, iter) } @@ -3793,7 +3793,7 @@ impl DocumentMethods for Document { } else { // Step 2. root.upcast::() - .traverse_preorder() + .traverse_preorder(/* shadow including */ false) .find(|node| node.is::()) } }); @@ -3840,7 +3840,7 @@ impl DocumentMethods for Document { } else if root.namespace() == &ns!(html) { let elem = root .upcast::() - .traverse_preorder() + .traverse_preorder(/* shadow including */ false) .find(|node| node.is::()); match elem { Some(elem) => elem, @@ -4207,7 +4207,7 @@ impl DocumentMethods for Document { { // Step 1. let mut elements = root - .traverse_preorder() + .traverse_preorder(/* shadow including */ false) .filter(|node| filter_by_name(&name, &node)) .peekable(); if let Some(first) = elements.next() { @@ -4325,7 +4325,10 @@ impl DocumentMethods for Document { } // Step 8 - for node in self.upcast::().traverse_preorder() { + for node in self + .upcast::() + .traverse_preorder(/* shadow including */ true) + { node.upcast::().remove_all_listeners(); } diff --git a/components/script/dom/documentfragment.rs b/components/script/dom/documentfragment.rs index 00718d0534d..ac9df62f59f 100644 --- a/components/script/dom/documentfragment.rs +++ b/components/script/dom/documentfragment.rs @@ -59,7 +59,7 @@ impl DocumentFragmentMethods for DocumentFragment { fn GetElementById(&self, id: DOMString) -> Option> { let node = self.upcast::(); let id = Atom::from(id); - node.traverse_preorder() + node.traverse_preorder(/* shadow including */ false) .filter_map(DomRoot::downcast::) .find( |descendant| match descendant.get_attribute(&ns!(), &local_name!("id")) { diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index bde1d46582f..5b5b93f78c1 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -443,7 +443,7 @@ impl Element { }) } - fn is_shadow_host(&self) -> bool { + pub fn is_shadow_host(&self) -> bool { self.shadow_root.get().is_some() } diff --git a/components/script/dom/htmlelement.rs b/components/script/dom/htmlelement.rs index 52184326a62..a9e75c531df 100644 --- a/components/script/dom/htmlelement.rs +++ b/components/script/dom/htmlelement.rs @@ -707,7 +707,7 @@ impl HTMLElement { let root_element = element.root_element(); let root_node = root_element.upcast::(); let children = root_node - .traverse_preorder() + .traverse_preorder(/* shadow including */ false) .filter_map(DomRoot::downcast::) .filter(|elem| elem.is::()) .filter(|elem| elem.get_string_attribute(&local_name!("for")) == id) diff --git a/components/script/dom/htmlfieldsetelement.rs b/components/script/dom/htmlfieldsetelement.rs index d8e92180e56..d90555db9f1 100644 --- a/components/script/dom/htmlfieldsetelement.rs +++ b/components/script/dom/htmlfieldsetelement.rs @@ -128,7 +128,7 @@ impl VirtualMethods for HTMLFieldSetElement { }); let fields = children.flat_map(|child| { child - .traverse_preorder() + .traverse_preorder(/* shadow including */ false) .filter(|descendant| match descendant.type_id() { NodeTypeId::Element(ElementTypeId::HTMLElement( HTMLElementTypeId::HTMLButtonElement, diff --git a/components/script/dom/htmlformelement.rs b/components/script/dom/htmlformelement.rs index cd4bb442296..385389eb9d7 100755 --- a/components/script/dom/htmlformelement.rs +++ b/components/script/dom/htmlformelement.rs @@ -582,7 +582,7 @@ impl HTMLFormElement { // form, refactor this when html5ever's form owner PR lands // Step 1-3 let invalid_controls = node - .traverse_preorder() + .traverse_preorder(/* shadow including */ false) .filter_map(|field| { if let Some(el) = field.downcast::() { if el.disabled_state() { diff --git a/components/script/dom/htmlheadelement.rs b/components/script/dom/htmlheadelement.rs index ddb06f70932..3c356e279ed 100644 --- a/components/script/dom/htmlheadelement.rs +++ b/components/script/dom/htmlheadelement.rs @@ -55,7 +55,7 @@ impl HTMLHeadElement { let node = self.upcast::(); let candidates = node - .traverse_preorder() + .traverse_preorder(/* shadow including */ false) .filter_map(DomRoot::downcast::) .filter(|elem| elem.is::()) .filter(|elem| elem.get_string_attribute(&local_name!("name")) == "referrer") diff --git a/components/script/dom/htmlimageelement.rs b/components/script/dom/htmlimageelement.rs index 7ad2aeac1e6..fd545b47016 100644 --- a/components/script/dom/htmlimageelement.rs +++ b/components/script/dom/htmlimageelement.rs @@ -1259,7 +1259,7 @@ impl HTMLImageElement { let useMapElements = document_from_node(self) .upcast::() - .traverse_preorder() + .traverse_preorder(/* shadow including */ false) .filter_map(DomRoot::downcast::) .find(|n| { n.upcast::() diff --git a/components/script/dom/htmllabelelement.rs b/components/script/dom/htmllabelelement.rs index 3c9106a589a..6ed17609a03 100644 --- a/components/script/dom/htmllabelelement.rs +++ b/components/script/dom/htmllabelelement.rs @@ -162,7 +162,7 @@ impl VirtualMethods for HTMLLabelElement { impl HTMLLabelElement { pub fn first_labelable_descendant(&self) -> Option> { self.upcast::() - .traverse_preorder() + .traverse_preorder(/* shadow including */ false) .filter_map(DomRoot::downcast::) .filter(|elem| elem.is_labelable_element()) .next() diff --git a/components/script/dom/htmlmapelement.rs b/components/script/dom/htmlmapelement.rs index 34b73e7e0b9..33a5e96aea7 100644 --- a/components/script/dom/htmlmapelement.rs +++ b/components/script/dom/htmlmapelement.rs @@ -43,7 +43,7 @@ impl HTMLMapElement { pub fn get_area_elements(&self) -> Vec> { self.upcast::() - .traverse_preorder() + .traverse_preorder(/* shadow including */ false) .filter_map(DomRoot::downcast::) .collect() } diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index cecad5d7b76..d8c1a2f4d5d 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -291,7 +291,7 @@ impl Node { let parent_in_doc = self.is_in_doc(); let parent_in_shadow_tree = self.is_in_shadow_tree(); let parent_is_connected = self.is_connected(); - for node in new_child.traverse_preorder() { + for node in new_child.traverse_preorder(/* shadow including */ false) { if parent_in_shadow_tree { if let Some(shadow_root) = self.downcast::() { node.set_owner_shadow_root(&*shadow_root); @@ -355,7 +355,7 @@ impl Node { child.composed_parent_node.set(None); self.children_count.set(self.children_count.get() - 1); - for node in child.traverse_preorder() { + for node in child.traverse_preorder(/* shadow including */ true) { // Out-of-document elements never have the descendants flag set. node.set_flag( NodeFlags::IS_IN_DOC | @@ -365,7 +365,7 @@ impl Node { false, ); } - for node in child.traverse_preorder() { + for node in child.traverse_preorder(/* shadow including */ true) { // This needs to be in its own loop, because unbind_from_tree may // rely on the state of IS_IN_DOC of the context node's descendants, // e.g. when removing a
. @@ -628,8 +628,8 @@ impl Node { } /// Iterates over this node and all its descendants, in preorder. - pub fn traverse_preorder(&self) -> TreeIterator { - TreeIterator::new(self) + pub fn traverse_preorder(&self, shadow_including: bool) -> TreeIterator { + TreeIterator::new(self, shadow_including) } pub fn inclusively_following_siblings(&self) -> impl Iterator> { @@ -876,7 +876,7 @@ impl Node { self.owner_doc().quirks_mode(), ); Ok(self - .traverse_preorder() + .traverse_preorder(/* shadow including */ false) .filter_map(DomRoot::downcast) .find(|element| matches_selector_list(&selectors, element, &mut ctx))) }, @@ -894,7 +894,7 @@ impl Node { Err(_) => Err(Error::Syntax), // Step 3. Ok(selectors) => { - let mut descendants = self.traverse_preorder(); + let mut descendants = self.traverse_preorder(/* shadow including */ false); // Skip the root of the tree. assert!(&*descendants.next().unwrap() == self); Ok(QuerySelectorIterator::new(descendants, selectors)) @@ -917,16 +917,16 @@ impl Node { } } - pub fn inclusive_ancestors(&self) -> impl Iterator> { - SimpleNodeIterator { + pub fn inclusive_ancestors(&self) -> Box>> { + Box::new(SimpleNodeIterator { current: Some(DomRoot::from_ref(self)), next_node: |n| n.GetParentNode(), - } + }) } /// https://dom.spec.whatwg.org/#concept-shadow-including-inclusive-ancestor - pub fn shadow_including_inclusive_ancestors(&self) -> impl Iterator> { - SimpleNodeIterator { + pub fn shadow_including_inclusive_ancestors(&self) -> Box>> { + Box::new(SimpleNodeIterator { current: Some(DomRoot::from_ref(self)), next_node: |n| { if let Some(shadow_root) = n.downcast::() { @@ -935,7 +935,7 @@ impl Node { n.GetParentNode() } }, - } + }) } pub fn owner_doc(&self) -> DomRoot { @@ -1505,13 +1505,15 @@ where pub struct TreeIterator { current: Option>, depth: usize, + shadow_including: bool, } impl TreeIterator { - fn new(root: &Node) -> TreeIterator { + fn new(root: &Node, shadow_including: bool) -> TreeIterator { TreeIterator { current: Some(DomRoot::from_ref(root)), depth: 0, + shadow_including, } } @@ -1522,7 +1524,13 @@ impl TreeIterator { } fn next_skipping_children_impl(&mut self, current: DomRoot) -> Option> { - for ancestor in current.inclusive_ancestors() { + let iter = if self.shadow_including { + current.shadow_including_inclusive_ancestors() + } else { + current.inclusive_ancestors() + }; + + for ancestor in iter { if self.depth == 0 { break; } @@ -1542,8 +1550,18 @@ impl Iterator for TreeIterator { type Item = DomRoot; // https://dom.spec.whatwg.org/#concept-tree-order + // https://dom.spec.whatwg.org/#concept-shadow-including-tree-order fn next(&mut self) -> Option> { let current = self.current.take()?; + + if !self.shadow_including { + if let Some(element) = current.downcast::() { + if element.is_shadow_host() { + return self.next_skipping_children_impl(current); + } + } + } + if let Some(first_child) = current.GetFirstChild() { self.current = Some(first_child); self.depth += 1; @@ -1626,11 +1644,11 @@ impl Node { // Step 3. if &*old_doc != document { // Step 3.1. - for descendant in node.traverse_preorder() { + for descendant in node.traverse_preorder(/* shadow including */ true) { descendant.set_owner_doc(document); } for descendant in node - .traverse_preorder() + .traverse_preorder(/* shadow including */ true) .filter_map(|d| d.as_custom_element()) { // Step 3.2. @@ -1640,7 +1658,7 @@ impl Node { None, ); } - for descendant in node.traverse_preorder() { + for descendant in node.traverse_preorder(/* shadow including */ true) { // Step 3.3. vtable_for(&descendant).adopting_steps(&old_doc); } @@ -1861,7 +1879,7 @@ impl Node { parent.add_child(*kid, child); // Step 7.7. for descendant in kid - .traverse_preorder() + .traverse_preorder(/* shadow including */ true) .filter_map(DomRoot::downcast::) { // Step 7.7.2. @@ -2306,7 +2324,9 @@ impl NodeMethods for Node { fn GetTextContent(&self) -> Option { match self.type_id() { NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => { - let content = Node::collect_text_contents(self.traverse_preorder()); + let content = Node::collect_text_contents( + self.traverse_preorder(/* shadow including */ false), + ); Some(content) }, NodeTypeId::CharacterData(..) => { @@ -3143,7 +3163,7 @@ where let elem_node = elem.upcast::(); let mut head: usize = 0; - for node in tree_root.traverse_preorder() { + for node in tree_root.traverse_preorder(/* shadow including */ false) { let head_node = DomRoot::upcast::(DomRoot::from_ref(&*self[head])); if head_node == node { head += 1; diff --git a/components/script/dom/range.rs b/components/script/dom/range.rs index afa759de52f..2f0b5422b1e 100644 --- a/components/script/dom/range.rs +++ b/components/script/dom/range.rs @@ -976,7 +976,10 @@ impl RangeMethods for Range { let fragment_node = element.parse_fragment(fragment)?; // Step 4. - for node in fragment_node.upcast::().traverse_preorder() { + for node in fragment_node + .upcast::() + .traverse_preorder(/* shadow incluing */ false) + { if let Some(script) = node.downcast::() { script.set_already_started(false); script.set_parser_inserted(false); diff --git a/components/script/webdriver_handlers.rs b/components/script/webdriver_handlers.rs index a3c143a4faa..8bcb63a58f4 100644 --- a/components/script/webdriver_handlers.rs +++ b/components/script/webdriver_handlers.rs @@ -50,7 +50,7 @@ fn find_node_by_unique_id( documents.find_document(pipeline).and_then(|document| { document .upcast::() - .traverse_preorder() + .traverse_preorder(/* shadow including */ true) .find(|candidate| candidate.unique_id() == node_id) }) } From be06f1e9b346d16538ddac5dea468f346cb1f18c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Wed, 30 Jan 2019 17:15:20 +0100 Subject: [PATCH 21/83] Always get browsing context from document --- components/script/dom/document.rs | 25 ++++++++++++++----- components/script/dom/documentorshadowroot.rs | 21 ++++------------ components/script/dom/shadowroot.rs | 24 +++++++++++------- 3 files changed, 39 insertions(+), 31 deletions(-) diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 3ed7082e4b5..31778542466 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -488,9 +488,14 @@ impl Document { self.has_browsing_context } + /// #[inline] pub fn browsing_context(&self) -> Option> { - self.document_or_shadow_root.browsing_context() + if self.has_browsing_context { + self.window.undiscarded_window_proxy() + } else { + None + } } #[inline] @@ -2622,7 +2627,7 @@ impl Document { 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), + document_or_shadow_root: DocumentOrShadowRootImpl::new(window), window: Dom::from_ref(window), has_browsing_context, implementation: Default::default(), @@ -4263,14 +4268,22 @@ impl DocumentMethods for Document { // https://drafts.csswg.org/cssom-view/#dom-document-elementfrompoint fn ElementFromPoint(&self, x: Finite, y: Finite) -> Option> { - self.document_or_shadow_root - .element_from_point(x, y, self.GetDocumentElement()) + self.document_or_shadow_root.element_from_point( + x, + y, + self.GetDocumentElement(), + self.has_browsing_context, + ) } // https://drafts.csswg.org/cssom-view/#dom-document-elementsfrompoint fn ElementsFromPoint(&self, x: Finite, y: Finite) -> Vec> { - self.document_or_shadow_root - .elements_from_point(x, y, self.GetDocumentElement()) + self.document_or_shadow_root.elements_from_point( + x, + y, + self.GetDocumentElement(), + self.has_browsing_context, + ) } // https://html.spec.whatwg.org/multipage/#dom-document-open diff --git a/components/script/dom/documentorshadowroot.rs b/components/script/dom/documentorshadowroot.rs index 91ce83af659..5e413c5cc89 100644 --- a/components/script/dom/documentorshadowroot.rs +++ b/components/script/dom/documentorshadowroot.rs @@ -13,7 +13,6 @@ 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}; @@ -55,28 +54,16 @@ impl DocumentOrShadowRoot { #[must_root] #[derive(JSTraceable, MallocSizeOf)] pub struct DocumentOrShadowRootImpl { - has_browsing_context: bool, window: Dom, } impl DocumentOrShadowRootImpl { - pub fn new(window: &Window, has_browsing_context: bool) -> Self { + pub fn new(window: &Window) -> Self { Self { - has_browsing_context, window: Dom::from_ref(window), } } - /// - #[inline] - pub fn browsing_context(&self) -> Option> { - if self.has_browsing_context { - self.window.undiscarded_window_proxy() - } else { - None - } - } - pub fn nodes_from_point( &self, client_point: &Point2D, @@ -99,13 +86,14 @@ impl DocumentOrShadowRootImpl { x: Finite, y: Finite, document_element: Option>, + has_browsing_context: bool, ) -> Option> { 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() { + if has_browsing_context { return None; } @@ -138,13 +126,14 @@ impl DocumentOrShadowRootImpl { x: Finite, y: Finite, document_element: Option>, + has_browsing_context: bool, ) -> Vec> { 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() { + if has_browsing_context { return vec![]; } diff --git a/components/script/dom/shadowroot.rs b/components/script/dom/shadowroot.rs index a7a3bb693e5..e64401ab494 100644 --- a/components/script/dom/shadowroot.rs +++ b/components/script/dom/shadowroot.rs @@ -23,7 +23,7 @@ use dom_struct::dom_struct; pub struct ShadowRoot { document_fragment: DocumentFragment, document_or_shadow_root: DocumentOrShadowRootImpl, - has_browsing_context: bool, + document: Dom, host: Dom, stylesheet_list: MutNullableDom, window: Dom, @@ -32,18 +32,14 @@ pub struct ShadowRoot { impl ShadowRoot { #[allow(unrooted_must_root)] fn new_inherited(host: &Element, document: &Document) -> ShadowRoot { - let has_browsing_context = true; let document_fragment = DocumentFragment::new_inherited(document); document_fragment .upcast::() .set_flag(NodeFlags::IS_IN_SHADOW_TREE, true); ShadowRoot { document_fragment, - document_or_shadow_root: DocumentOrShadowRootImpl::new( - document.window(), - has_browsing_context, - ), - has_browsing_context, + document_or_shadow_root: DocumentOrShadowRootImpl::new(document.window()), + document: Dom::from_ref(document), host: Dom::from_ref(host), stylesheet_list: MutNullableDom::new(None), window: Dom::from_ref(document.window()), @@ -85,14 +81,24 @@ impl ShadowRootMethods for ShadowRoot { fn ElementFromPoint(&self, x: Finite, y: Finite) -> Option> { // 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) + self.document_or_shadow_root.element_from_point( + x, + y, + None, + self.document.has_browsing_context(), + ) } // https://drafts.csswg.org/cssom-view/#dom-document-elementsfrompoint fn ElementsFromPoint(&self, x: Finite, y: Finite) -> Vec> { // 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) + self.document_or_shadow_root.elements_from_point( + x, + y, + None, + self.document.has_browsing_context(), + ) } /// https://dom.spec.whatwg.org/#dom-shadowroot-mode From 7c9e8aa4cc3131c42a9412e1fa3e4f99b4324763 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Thu, 31 Jan 2019 16:10:26 +0100 Subject: [PATCH 22/83] First bits of shadow dom layout --- components/layout_thread/dom_wrapper.rs | 90 +++++++++++++++++++------ components/script/dom/element.rs | 23 ++++++- components/script/dom/node.rs | 15 +++-- components/script/dom/shadowroot.rs | 15 ++++- components/script/lib.rs | 5 +- 5 files changed, 118 insertions(+), 30 deletions(-) diff --git a/components/layout_thread/dom_wrapper.rs b/components/layout_thread/dom_wrapper.rs index 497c7f135d2..6227df9f04c 100644 --- a/components/layout_thread/dom_wrapper.rs +++ b/components/layout_thread/dom_wrapper.rs @@ -40,13 +40,16 @@ use net_traits::image::base::{Image, ImageMetadata}; use range::Range; use script::layout_exports::NodeFlags; use script::layout_exports::PendingRestyle; +use script::layout_exports::ShadowRoot; use script::layout_exports::{ - CharacterDataTypeId, ElementTypeId, HTMLElementTypeId, NodeTypeId, TextTypeId, + CharacterDataTypeId, DocumentFragmentTypeId, ElementTypeId, HTMLElementTypeId, NodeTypeId, + TextTypeId, }; use script::layout_exports::{Document, Element, Node, Text}; use script::layout_exports::{LayoutCharacterDataHelpers, LayoutDocumentHelpers}; use script::layout_exports::{ - LayoutDom, LayoutElementHelpers, LayoutNodeHelpers, RawLayoutElementHelpers, + LayoutDom, LayoutElementHelpers, LayoutNodeHelpers, LayoutShadowRootHelpers, + RawLayoutElementHelpers, }; use script_layout_interface::wrapper_traits::{ DangerousThreadSafeLayoutNode, GetLayoutData, LayoutNode, @@ -160,35 +163,60 @@ impl<'ln> NodeInfo for ServoLayoutNode<'ln> { } } -#[derive(Clone, Copy, PartialEq)] -enum Impossible {} +#[derive(Clone, Copy)] +pub struct ServoShadowRoot<'a> { + /// The wrapped shadow root. + shadow_root: LayoutDom, -#[derive(Clone, Copy, PartialEq)] -pub struct ShadowRoot<'lr>(Impossible, PhantomData<&'lr ()>); + /// Being chained to a PhantomData prevents `ShadowRoot`s from escaping. + chain: PhantomData<&'a ()>, +} -impl<'lr> TShadowRoot for ShadowRoot<'lr> { - type ConcreteNode = ServoLayoutNode<'lr>; +impl<'sr> Debug for ServoShadowRoot<'sr> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.as_node().fmt(f) + } +} + +impl<'a> PartialEq for ServoShadowRoot<'a> { + #[inline] + fn eq(&self, other: &ServoShadowRoot) -> bool { + self.shadow_root == other.shadow_root + } +} + +impl<'sr> TShadowRoot for ServoShadowRoot<'sr> { + type ConcreteNode = ServoLayoutNode<'sr>; fn as_node(&self) -> Self::ConcreteNode { - match self.0 {} + ServoLayoutNode::from_layout_js(self.shadow_root.upcast()) } - fn host(&self) -> ServoLayoutElement<'lr> { - match self.0 {} + fn host(&self) -> ServoLayoutElement<'sr> { + ServoLayoutElement::from_layout_js(unsafe { self.shadow_root.get_host_for_layout() }) } fn style_data<'a>(&self) -> Option<&'a CascadeData> where Self: 'a, { - match self.0 {} + None + } +} + +impl<'sr> ServoShadowRoot<'sr> { + fn from_layout_js(shadow_root: LayoutDom) -> ServoShadowRoot<'sr> { + ServoShadowRoot { + shadow_root, + chain: PhantomData, + } } } impl<'ln> TNode for ServoLayoutNode<'ln> { type ConcreteDocument = ServoLayoutDocument<'ln>; type ConcreteElement = ServoLayoutElement<'ln>; - type ConcreteShadowRoot = ShadowRoot<'ln>; + type ConcreteShadowRoot = ServoShadowRoot<'ln>; fn parent_node(&self) -> Option { unsafe { @@ -256,8 +284,8 @@ impl<'ln> TNode for ServoLayoutNode<'ln> { .map(ServoLayoutDocument::from_layout_js) } - fn as_shadow_root(&self) -> Option> { - None + fn as_shadow_root(&self) -> Option> { + self.node.downcast().map(ServoShadowRoot::from_layout_js) } fn is_connected(&self) -> bool { @@ -616,12 +644,23 @@ impl<'le> TElement for ServoLayoutElement<'le> { } } - fn shadow_root(&self) -> Option> { - None + /// The shadow root this element is a host of. + fn shadow_root(&self) -> Option> { + unsafe { + self.element + .get_shadow_root_for_layout() + .map(ServoShadowRoot::from_layout_js) + } } - fn containing_shadow(&self) -> Option> { - None + /// The shadow root which roots the subtree this element is contained in. + fn containing_shadow(&self) -> Option> { + unsafe { + self.element + .upcast() + .owner_shadow_root_for_layout() + .map(ServoShadowRoot::from_layout_js) + } } } @@ -706,11 +745,20 @@ impl<'le> ::selectors::Element for ServoLayoutElement<'le> { } fn parent_node_is_shadow_root(&self) -> bool { - false + match self.as_node().parent_node() { + None => false, + Some(node) => { + node.script_type_id() == + NodeTypeId::DocumentFragment(DocumentFragmentTypeId::ShadowRoot) + }, + } } fn containing_shadow_host(&self) -> Option { - None + match self.containing_shadow() { + Some(shadow) => Some(shadow.host()), + None => None, + } } fn prev_sibling_element(&self) -> Option> { diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 5b5b93f78c1..f9923da3fea 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -15,6 +15,7 @@ use crate::dom::bindings::codegen::Bindings::EventBinding::EventMethods; use crate::dom::bindings::codegen::Bindings::FunctionBinding::Function; use crate::dom::bindings::codegen::Bindings::HTMLTemplateElementBinding::HTMLTemplateElementMethods; use crate::dom::bindings::codegen::Bindings::NodeBinding::{GetRootNodeOptions, NodeMethods}; +use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::ShadowRootBinding::ShadowRootMethods; use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; use crate::dom::bindings::codegen::Bindings::WindowBinding::{ScrollBehavior, ScrollToOptions}; use crate::dom::bindings::codegen::UnionTypes::NodeOrString; @@ -76,7 +77,7 @@ use crate::dom::node::{NodeDamage, NodeFlags, UnbindContext}; use crate::dom::nodelist::NodeList; use crate::dom::promise::Promise; use crate::dom::servoparser::ServoParser; -use crate::dom::shadowroot::ShadowRoot; +use crate::dom::shadowroot::{LayoutShadowRootHelpers, ShadowRoot}; use crate::dom::text::Text; use crate::dom::validation::Validatable; use crate::dom::virtualmethods::{vtable_for, VirtualMethods}; @@ -587,6 +588,9 @@ pub trait LayoutElementHelpers { fn get_state_for_layout(&self) -> ElementState; fn insert_selector_flags(&self, flags: ElementSelectorFlags); fn has_selector_flags(&self, flags: ElementSelectorFlags) -> bool; + /// The shadow root this element is a host of. + #[allow(unsafe_code)] + unsafe fn get_shadow_root_for_layout(&self) -> Option>; } impl LayoutElementHelpers for LayoutDom { @@ -1049,6 +1053,12 @@ impl LayoutElementHelpers for LayoutDom { fn has_selector_flags(&self, flags: ElementSelectorFlags) -> bool { unsafe { (*self.unsafe_get()).selector_flags.get().contains(flags) } } + + #[inline] + #[allow(unsafe_code)] + unsafe fn get_shadow_root_for_layout(&self) -> Option> { + (*self.unsafe_get()).shadow_root.get_inner_as_layout() + } } impl Element { @@ -2877,11 +2887,18 @@ impl<'a> SelectorsElement for DomRoot { } fn parent_node_is_shadow_root(&self) -> bool { - false + match self.upcast::().GetParentNode() { + None => false, + Some(node) => node.is::(), + } } fn containing_shadow_host(&self) -> Option { - None + if let Some(shadow_root) = self.upcast::().owner_shadow_root() { + Some(shadow_root.Host()) + } else { + None + } } fn match_pseudo_element( diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index d8c1a2f4d5d..b20f8cf037e 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -295,8 +295,8 @@ impl Node { if parent_in_shadow_tree { if let Some(shadow_root) = self.downcast::() { node.set_owner_shadow_root(&*shadow_root); - } else { - node.set_owner_shadow_root(&*self.owner_shadow_root()); + } else if let Some(shadow_root) = self.owner_shadow_root() { + node.set_owner_shadow_root(&*shadow_root); } } let mut is_connected = parent_is_connected; @@ -946,8 +946,8 @@ impl Node { self.owner_doc.set(Some(document)); } - pub fn owner_shadow_root(&self) -> DomRoot { - self.owner_shadow_root.get().unwrap() + pub fn owner_shadow_root(&self) -> Option> { + self.owner_shadow_root.get() } pub fn set_owner_shadow_root(&self, shadow_root: &ShadowRoot) { @@ -1184,6 +1184,7 @@ pub trait LayoutNodeHelpers { unsafe fn next_sibling_ref(&self) -> Option>; unsafe fn owner_doc_for_layout(&self) -> LayoutDom; + unsafe fn owner_shadow_root_for_layout(&self) -> Option>; unsafe fn is_element_for_layout(&self) -> bool; unsafe fn get_flag(&self, flag: NodeFlags) -> bool; @@ -1260,6 +1261,12 @@ impl LayoutNodeHelpers for LayoutDom { .unwrap() } + #[inline] + #[allow(unsafe_code)] + unsafe fn owner_shadow_root_for_layout(&self) -> Option> { + (*self.unsafe_get()).owner_shadow_root.get_inner_as_layout() + } + #[inline] #[allow(unsafe_code)] unsafe fn get_flag(&self, flag: NodeFlags) -> bool { diff --git a/components/script/dom/shadowroot.rs b/components/script/dom/shadowroot.rs index e64401ab494..55470a9935d 100644 --- a/components/script/dom/shadowroot.rs +++ b/components/script/dom/shadowroot.rs @@ -7,7 +7,7 @@ use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::{self, ShadowRoo 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::bindings::root::{Dom, DomRoot, LayoutDom, MutNullableDom}; use crate::dom::cssstylesheet::CSSStyleSheet; use crate::dom::document::Document; use crate::dom::documentfragment::DocumentFragment; @@ -121,3 +121,16 @@ impl ShadowRootMethods for ShadowRoot { }) } } + +#[allow(unsafe_code)] +pub trait LayoutShadowRootHelpers { + unsafe fn get_host_for_layout(&self) -> LayoutDom; +} + +impl LayoutShadowRootHelpers for LayoutDom { + #[inline] + #[allow(unsafe_code)] + unsafe fn get_host_for_layout(&self) -> LayoutDom { + (*self.unsafe_get()).host.to_layout() + } +} diff --git a/components/script/lib.rs b/components/script/lib.rs index a057540ae22..3f48e3d9118 100644 --- a/components/script/lib.rs +++ b/components/script/lib.rs @@ -84,7 +84,9 @@ mod webdriver_handlers; /// /// TODO(emilio): A few of the FooHelpers can go away, presumably... pub mod layout_exports { - pub use crate::dom::bindings::inheritance::{CharacterDataTypeId, ElementTypeId}; + pub use crate::dom::bindings::inheritance::{ + CharacterDataTypeId, DocumentFragmentTypeId, ElementTypeId, + }; pub use crate::dom::bindings::inheritance::{HTMLElementTypeId, NodeTypeId, TextTypeId}; pub use crate::dom::bindings::root::LayoutDom; pub use crate::dom::characterdata::LayoutCharacterDataHelpers; @@ -92,6 +94,7 @@ pub mod layout_exports { pub use crate::dom::element::{Element, LayoutElementHelpers, RawLayoutElementHelpers}; pub use crate::dom::node::NodeFlags; pub use crate::dom::node::{LayoutNodeHelpers, Node}; + pub use crate::dom::shadowroot::{LayoutShadowRootHelpers, ShadowRoot}; pub use crate::dom::text::Text; } From d2e1a3ab33e59bf3debc59d35619f11ff395fa7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Fri, 1 Feb 2019 16:46:29 +0100 Subject: [PATCH 23/83] Adapt traversals for shadow dom --- components/layout_thread/dom_wrapper.rs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/components/layout_thread/dom_wrapper.rs b/components/layout_thread/dom_wrapper.rs index 6227df9f04c..580965b91d0 100644 --- a/components/layout_thread/dom_wrapper.rs +++ b/components/layout_thread/dom_wrapper.rs @@ -263,7 +263,11 @@ impl<'ln> TNode for ServoLayoutNode<'ln> { } fn traversal_parent(&self) -> Option> { - self.parent_element() + let parent = self.parent_node()?; + if let Some(shadow) = parent.as_shadow_root() { + return Some(shadow.host()); + }; + parent.as_element() } fn opaque(&self) -> OpaqueNode { @@ -442,7 +446,11 @@ impl<'le> TElement for ServoLayoutElement<'le> { } fn traversal_children(&self) -> LayoutIterator { - LayoutIterator(self.as_node().dom_children()) + LayoutIterator(if let Some(shadow) = self.shadow_root() { + shadow.as_node().dom_children() + } else { + self.as_node().dom_children() + }) } fn is_html_element(&self) -> bool { @@ -1033,6 +1041,13 @@ impl<'ln> ThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> { } fn children(&self) -> LayoutIterator { + if let Some(element) = self.node.as_element() { + if let Some(shadow) = element.shadow_root() { + return LayoutIterator(ThreadSafeLayoutNodeChildrenIterator::new( + shadow.as_node().to_threadsafe(), + )); + } + } LayoutIterator(ThreadSafeLayoutNodeChildrenIterator::new(*self)) } From 0d6bd24245df02e8e745a273e37cd53d70c19ce6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Mon, 4 Feb 2019 21:11:56 +0100 Subject: [PATCH 24/83] Move stylesheets related code to DocumentOrShadowRoot --- components/script/dom/bindings/trace.rs | 2 + components/script/dom/document.rs | 161 +++------------ components/script/dom/documentorshadowroot.rs | 185 ++++++++++++++---- components/script/dom/element.rs | 2 +- components/script/dom/shadowroot.rs | 36 ++-- components/script/dom/stylesheetlist.rs | 15 +- 6 files changed, 208 insertions(+), 193 deletions(-) diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index f1734d74b55..2c86040308e 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -39,6 +39,7 @@ use crate::dom::bindings::utils::WindowProxyHandler; use crate::dom::document::PendingRestyle; use crate::dom::htmlimageelement::SourceSet; use crate::dom::htmlmediaelement::{HTMLMediaElementFetchContext, MediaFrameRenderer}; +use crate::dom::stylesheetlist::StyleSheetListOwner; use crate::task::TaskBox; use app_units::Au; use canvas_traits::canvas::{ @@ -497,6 +498,7 @@ unsafe_no_jsmanaged_fields!(HTMLMediaElementFetchContext); unsafe_no_jsmanaged_fields!(Rotation3D, Transform2D, Transform3D); unsafe_no_jsmanaged_fields!(Point2D, Vector2D, Rect); unsafe_no_jsmanaged_fields!(Rect, RigidTransform3D); +unsafe_no_jsmanaged_fields!(StyleSheetListOwner); unsafe impl<'a> JSTraceable for &'a str { #[inline] diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 31778542466..f4f0e809fce 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, DocumentOrShadowRootImpl}; +use crate::dom::documentorshadowroot::{DocumentOrShadowRoot, StyleSheetInDocument}; use crate::dom::documenttype::DocumentType; use crate::dom::domimplementation::DOMImplementation; use crate::dom::element::CustomElementCreationMode; @@ -68,7 +68,6 @@ use crate::dom::htmlheadelement::HTMLHeadElement; use crate::dom::htmlhtmlelement::HTMLHtmlElement; use crate::dom::htmliframeelement::HTMLIFrameElement; use crate::dom::htmlimageelement::HTMLImageElement; -use crate::dom::htmlmetaelement::HTMLMetaElement; use crate::dom::htmlscriptelement::{HTMLScriptElement, ScriptResult}; use crate::dom::htmltitleelement::HTMLTitleElement; use crate::dom::keyboardevent::KeyboardEvent; @@ -89,7 +88,7 @@ use crate::dom::range::Range; use crate::dom::servoparser::ServoParser; use crate::dom::shadowroot::ShadowRoot; use crate::dom::storageevent::StorageEvent; -use crate::dom::stylesheetlist::StyleSheetList; +use crate::dom::stylesheetlist::{StyleSheetList, StyleSheetListOwner}; use crate::dom::text::Text; use crate::dom::touch::Touch; use crate::dom::touchevent::TouchEvent; @@ -145,7 +144,6 @@ use std::cell::{Cell, Ref, RefMut}; use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::collections::{HashMap, HashSet, VecDeque}; use std::default::Default; -use std::fmt; use std::mem; use std::ptr::NonNull; use std::rc::Rc; @@ -153,12 +151,12 @@ use std::time::{Duration, Instant}; use style::attr::AttrValue; use style::context::QuirksMode; use style::invalidation::element::restyle_hints::RestyleHint; -use style::media_queries::{Device, MediaList, MediaType}; +use style::media_queries::{Device, MediaType}; use style::selector_parser::{RestyleDamage, Snapshot}; -use style::shared_lock::{SharedRwLock as StyleSharedRwLock, SharedRwLockReadGuard}; +use style::shared_lock::SharedRwLock as StyleSharedRwLock; use style::str::{split_html_space_chars, str_join}; use style::stylesheet_set::DocumentStylesheetSet; -use style::stylesheets::{CssRule, Origin, OriginSet, Stylesheet}; +use style::stylesheets::Stylesheet; use url::percent_encoding::percent_decode; use url::Host; @@ -221,53 +219,11 @@ impl PendingRestyle { } } -#[derive(Clone, JSTraceable, MallocSizeOf)] -#[must_root] -struct StyleSheetInDocument { - #[ignore_malloc_size_of = "Arc"] - sheet: Arc, - owner: Dom, -} - -impl fmt::Debug for StyleSheetInDocument { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.sheet.fmt(formatter) - } -} - -impl PartialEq for StyleSheetInDocument { - fn eq(&self, other: &Self) -> bool { - Arc::ptr_eq(&self.sheet, &other.sheet) - } -} - -impl ::style::stylesheets::StylesheetInDocument for StyleSheetInDocument { - fn origin(&self, guard: &SharedRwLockReadGuard) -> Origin { - self.sheet.origin(guard) - } - - fn quirks_mode(&self, guard: &SharedRwLockReadGuard) -> QuirksMode { - self.sheet.quirks_mode(guard) - } - - fn enabled(&self) -> bool { - self.sheet.enabled() - } - - fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList> { - self.sheet.media(guard) - } - - fn rules<'a, 'b: 'a>(&'a self, guard: &'b SharedRwLockReadGuard) -> &'a [CssRule] { - self.sheet.rules(guard) - } -} - /// #[dom_struct] pub struct Document { node: Node, - document_or_shadow_root: DocumentOrShadowRootImpl, + document_or_shadow_root: DocumentOrShadowRoot, window: Dom, implementation: MutNullableDom, #[ignore_malloc_size_of = "type from external crate"] @@ -618,7 +574,7 @@ impl Document { // FIXME: This should check the dirty bit on the document, // not the document element. Needs some layout changes to make // that workable. - self.stylesheets.borrow().has_changed() || + self.document_or_shadow_root.stylesheets_have_changed() || self.GetDocumentElement().map_or(false, |root| { root.upcast::().has_dirty_descendants() || !self.pending_restyles.borrow().is_empty() || @@ -1580,7 +1536,7 @@ impl Document { } pub fn invalidate_stylesheets(&self) { - self.stylesheets.borrow_mut().force_dirty(OriginSet::all()); + self.document_or_shadow_root.invalidate_stylesheets(); // Mark the document element dirty so a reflow will be performed. // @@ -2627,7 +2583,7 @@ impl Document { let has_browsing_context = has_browsing_context == HasBrowsingContext::Yes; Document { node: Node::new_document_node(), - document_or_shadow_root: DocumentOrShadowRootImpl::new(window), + document_or_shadow_root: DocumentOrShadowRoot::new(window), window: Dom::from_ref(window), has_browsing_context, implementation: Default::default(), @@ -2865,9 +2821,9 @@ impl Document { // and normal stylesheets additions / removals, because in the last case // the layout thread already has that information and we could avoid // dirtying the whole thing. - let mut stylesheets = self.stylesheets.borrow_mut(); - let have_changed = stylesheets.has_changed(); - stylesheets.flush_without_invalidation(); + let have_changed = self.document_or_shadow_root.stylesheets_have_changed(); + self.document_or_shadow_root + .flush_stylesheets_without_invalidation(); have_changed } @@ -2885,90 +2841,21 @@ impl Document { /// Remove a stylesheet owned by `owner` from the list of document sheets. #[allow(unrooted_must_root)] // Owner needs to be rooted already necessarily. pub fn remove_stylesheet(&self, owner: &Element, s: &Arc) { - self.window() - .layout_chan() - .send(Msg::RemoveStylesheet(s.clone())) - .unwrap(); - - let guard = s.shared_lock.read(); - - // FIXME(emilio): Would be nice to remove the clone, etc. - self.stylesheets.borrow_mut().remove_stylesheet( - None, - StyleSheetInDocument { - sheet: s.clone(), - owner: Dom::from_ref(owner), - }, - &guard, - ); + self.document_or_shadow_root.remove_stylesheet(owner, s) } /// Add a stylesheet owned by `owner` to the list of document sheets, in the /// correct tree position. #[allow(unrooted_must_root)] // Owner needs to be rooted already necessarily. pub fn add_stylesheet(&self, owner: &Element, sheet: Arc) { - // FIXME(emilio): It'd be nice to unify more code between the elements - // that own stylesheets, but StylesheetOwner is more about loading - // them... - debug_assert!( - owner.as_stylesheet_owner().is_some() || owner.is::(), - "Wat" - ); - - let mut stylesheets = self.stylesheets.borrow_mut(); - let insertion_point = stylesheets - .iter() - .map(|(sheet, _origin)| sheet) - .find(|sheet_in_doc| { - owner - .upcast::() - .is_before(sheet_in_doc.owner.upcast()) - }) - .cloned(); - - self.window() - .layout_chan() - .send(Msg::AddStylesheet( - sheet.clone(), - insertion_point.as_ref().map(|s| s.sheet.clone()), - )) - .unwrap(); - - let sheet = StyleSheetInDocument { - sheet, - owner: Dom::from_ref(owner), - }; - - let lock = self.style_shared_lock(); - let guard = lock.read(); - - match insertion_point { - Some(ip) => { - stylesheets.insert_stylesheet_before(None, sheet, ip, &guard); - }, - None => { - stylesheets.append_stylesheet(None, sheet, &guard); - }, - } - } - - /// Returns the number of document stylesheets. - pub fn stylesheet_count(&self) -> usize { - self.stylesheets.borrow().len() + self.document_or_shadow_root + .add_stylesheet(owner, sheet, self.style_shared_lock()); } pub fn salvageable(&self) -> bool { self.salvageable.get() } - pub fn stylesheet_at(&self, index: usize) -> Option> { - let stylesheets = self.stylesheets.borrow(); - - stylesheets - .get(Origin::Author, index) - .and_then(|s| s.owner.upcast::().get_cssom_stylesheet()) - } - /// pub fn appropriate_template_contents_owner_document(&self) -> DomRoot { self.appropriate_template_contents_owner_document @@ -3290,12 +3177,8 @@ impl ProfilerMetadataFactory for Document { impl DocumentMethods for Document { // https://drafts.csswg.org/cssom/#dom-document-stylesheets fn StyleSheets(&self) -> DomRoot { - self.stylesheet_list.or_init(|| { - StyleSheetList::new( - &self.window, - DocumentOrShadowRoot::Document(Dom::from_ref(self)), - ) - }) + self.stylesheet_list + .or_init(|| StyleSheetList::new(&self.window, Box::new(Dom::from_ref(self)))) } // https://dom.spec.whatwg.org/#dom-document-implementation @@ -4678,3 +4561,13 @@ impl PendingScript { .map(|result| (DomRoot::from_ref(&*self.element), result)) } } + +impl StyleSheetListOwner for Dom { + fn stylesheet_count(&self) -> usize { + self.document_or_shadow_root.stylesheet_count() + } + + fn stylesheet_at(&self, index: usize) -> Option> { + self.document_or_shadow_root.stylesheet_at(index) + } +} diff --git a/components/script/dom/documentorshadowroot.rs b/components/script/dom/documentorshadowroot.rs index 5e413c5cc89..b1ea9ee1549 100644 --- a/components/script/dom/documentorshadowroot.rs +++ b/components/script/dom/documentorshadowroot.rs @@ -2,65 +2,86 @@ * 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::cell::DomRefCell; 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::htmlmetaelement::HTMLMetaElement; +use crate::dom::node::{self, Node}; use crate::dom::window::Window; use euclid::Point2D; use js::jsapi::JS_GetRuntime; -use script_layout_interface::message::{NodesFromPointQueryType, QueryMsg}; +use script_layout_interface::message::{Msg, NodesFromPointQueryType, QueryMsg}; use script_traits::UntrustedNodeAddress; +use servo_arc::Arc; +use std::fmt; +use style::context::QuirksMode; +use style::media_queries::MediaList; +use style::shared_lock::{SharedRwLock as StyleSharedRwLock, SharedRwLockReadGuard}; +use style::stylesheet_set::DocumentStylesheetSet; +use style::stylesheets::{CssRule, Origin, OriginSet, Stylesheet}; -macro_rules! proxy_call( - ($fn_name:ident, $return_type:ty) => ( - pub fn $fn_name(&self) -> $return_type { - match self { - DocumentOrShadowRoot::Document(doc) => doc.$fn_name(), - DocumentOrShadowRoot::ShadowRoot(root) => root.$fn_name(), - } - } - ); - - ($fn_name:ident, $arg1:ident, $arg1_type:ty, $return_type:ty) => ( - pub fn $fn_name(&self, $arg1: $arg1_type) -> $return_type { - match self { - DocumentOrShadowRoot::Document(doc) => doc.$fn_name($arg1), - DocumentOrShadowRoot::ShadowRoot(root) => root.$fn_name($arg1), - } - } - ); -); - +#[derive(Clone, JSTraceable, MallocSizeOf)] #[must_root] -#[derive(JSTraceable, MallocSizeOf)] -pub enum DocumentOrShadowRoot { - Document(Dom), - ShadowRoot(Dom), +pub struct StyleSheetInDocument { + #[ignore_malloc_size_of = "Arc"] + sheet: Arc, + owner: Dom, } -impl DocumentOrShadowRoot { - proxy_call!(stylesheet_count, usize); - proxy_call!(stylesheet_at, index, usize, Option>); +impl fmt::Debug for StyleSheetInDocument { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + self.sheet.fmt(formatter) + } +} + +impl PartialEq for StyleSheetInDocument { + fn eq(&self, other: &Self) -> bool { + Arc::ptr_eq(&self.sheet, &other.sheet) + } +} + +impl ::style::stylesheets::StylesheetInDocument for StyleSheetInDocument { + fn origin(&self, guard: &SharedRwLockReadGuard) -> Origin { + self.sheet.origin(guard) + } + + fn quirks_mode(&self, guard: &SharedRwLockReadGuard) -> QuirksMode { + self.sheet.quirks_mode(guard) + } + + fn enabled(&self) -> bool { + self.sheet.enabled() + } + + fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList> { + self.sheet.media(guard) + } + + fn rules<'a, 'b: 'a>(&'a self, guard: &'b SharedRwLockReadGuard) -> &'a [CssRule] { + self.sheet.rules(guard) + } } // https://w3c.github.io/webcomponents/spec/shadow/#extensions-to-the-documentorshadowroot-mixin #[must_root] #[derive(JSTraceable, MallocSizeOf)] -pub struct DocumentOrShadowRootImpl { +pub struct DocumentOrShadowRoot { window: Dom, + /// List of stylesheets associated with nodes in this document or shadow root. + /// |None| if the list needs to be refreshed. + stylesheets: DomRefCell>, } -impl DocumentOrShadowRootImpl { +impl DocumentOrShadowRoot { pub fn new(window: &Window) -> Self { Self { window: Dom::from_ref(window), + stylesheets: DomRefCell::new(DocumentStylesheetSet::new()), } } @@ -185,4 +206,102 @@ impl DocumentOrShadowRootImpl { }, } } + + pub fn stylesheet_count(&self) -> usize { + self.stylesheets.borrow().len() + } + + pub fn stylesheet_at(&self, index: usize) -> Option> { + let stylesheets = self.stylesheets.borrow(); + + stylesheets + .get(Origin::Author, index) + .and_then(|s| s.owner.upcast::().get_cssom_stylesheet()) + } + + pub fn stylesheets_have_changed(&self) -> bool { + self.stylesheets.borrow().has_changed() + } + + pub fn invalidate_stylesheets(&self) { + self.stylesheets.borrow_mut().force_dirty(OriginSet::all()); + } + + pub fn flush_stylesheets_without_invalidation(&self) { + self.stylesheets.borrow_mut().flush_without_invalidation(); + } + + /// Remove a stylesheet owned by `owner` from the list of document sheets. + #[allow(unrooted_must_root)] // Owner needs to be rooted already necessarily. + pub fn remove_stylesheet(&self, owner: &Element, s: &Arc) { + self.window + .layout_chan() + .send(Msg::RemoveStylesheet(s.clone())) + .unwrap(); + + let guard = s.shared_lock.read(); + + // FIXME(emilio): Would be nice to remove the clone, etc. + self.stylesheets.borrow_mut().remove_stylesheet( + None, + StyleSheetInDocument { + sheet: s.clone(), + owner: Dom::from_ref(owner), + }, + &guard, + ); + } + + /// Add a stylesheet owned by `owner` to the list of document sheets, in the + /// correct tree position. + #[allow(unrooted_must_root)] // Owner needs to be rooted already necessarily. + pub fn add_stylesheet( + &self, + owner: &Element, + sheet: Arc, + style_shared_lock: &StyleSharedRwLock, + ) { + // FIXME(emilio): It'd be nice to unify more code between the elements + // that own stylesheets, but StylesheetOwner is more about loading + // them... + debug_assert!( + owner.as_stylesheet_owner().is_some() || owner.is::(), + "Wat" + ); + + let mut stylesheets = self.stylesheets.borrow_mut(); + let insertion_point = stylesheets + .iter() + .map(|(sheet, _origin)| sheet) + .find(|sheet_in_doc| { + owner + .upcast::() + .is_before(sheet_in_doc.owner.upcast()) + }) + .cloned(); + + self.window + .layout_chan() + .send(Msg::AddStylesheet( + sheet.clone(), + insertion_point.as_ref().map(|s| s.sheet.clone()), + )) + .unwrap(); + + let sheet = StyleSheetInDocument { + sheet, + owner: Dom::from_ref(owner), + }; + + let guard = style_shared_lock.read(); + + match insertion_point { + Some(ip) => { + stylesheets.insert_stylesheet_before(None, sheet, ip, &guard); + }, + None => { + stylesheets.append_stylesheet(None, sheet, &guard); + }, + } + } } diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index f9923da3fea..4b24ab84a90 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -77,7 +77,7 @@ use crate::dom::node::{NodeDamage, NodeFlags, UnbindContext}; use crate::dom::nodelist::NodeList; use crate::dom::promise::Promise; use crate::dom::servoparser::ServoParser; -use crate::dom::shadowroot::{LayoutShadowRootHelpers, ShadowRoot}; +use crate::dom::shadowroot::ShadowRoot; use crate::dom::text::Text; use crate::dom::validation::Validatable; use crate::dom::virtualmethods::{vtable_for, VirtualMethods}; diff --git a/components/script/dom/shadowroot.rs b/components/script/dom/shadowroot.rs index 55470a9935d..4a77452a2a5 100644 --- a/components/script/dom/shadowroot.rs +++ b/components/script/dom/shadowroot.rs @@ -11,10 +11,10 @@ use crate::dom::bindings::root::{Dom, DomRoot, LayoutDom, MutNullableDom}; use crate::dom::cssstylesheet::CSSStyleSheet; use crate::dom::document::Document; use crate::dom::documentfragment::DocumentFragment; -use crate::dom::documentorshadowroot::{DocumentOrShadowRoot, DocumentOrShadowRootImpl}; +use crate::dom::documentorshadowroot::DocumentOrShadowRoot; use crate::dom::element::Element; use crate::dom::node::{Node, NodeFlags}; -use crate::dom::stylesheetlist::StyleSheetList; +use crate::dom::stylesheetlist::{StyleSheetList, StyleSheetListOwner}; use crate::dom::window::Window; use dom_struct::dom_struct; @@ -22,7 +22,7 @@ use dom_struct::dom_struct; #[dom_struct] pub struct ShadowRoot { document_fragment: DocumentFragment, - document_or_shadow_root: DocumentOrShadowRootImpl, + document_or_shadow_root: DocumentOrShadowRoot, document: Dom, host: Dom, stylesheet_list: MutNullableDom, @@ -38,7 +38,7 @@ impl ShadowRoot { .set_flag(NodeFlags::IS_IN_SHADOW_TREE, true); ShadowRoot { document_fragment, - document_or_shadow_root: DocumentOrShadowRootImpl::new(document.window()), + document_or_shadow_root: DocumentOrShadowRoot::new(document.window()), document: Dom::from_ref(document), host: Dom::from_ref(host), stylesheet_list: MutNullableDom::new(None), @@ -58,16 +58,6 @@ impl ShadowRoot { //XXX get retargeted focused element None } - - pub fn stylesheet_count(&self) -> usize { - //XXX handle shadowroot stylesheets - 0 - } - - pub fn stylesheet_at(&self, _index: usize) -> Option> { - //XXX handle shadowroot stylesheets - None - } } impl ShadowRootMethods for ShadowRoot { @@ -113,12 +103,8 @@ impl ShadowRootMethods for ShadowRoot { // https://drafts.csswg.org/cssom/#dom-document-stylesheets fn StyleSheets(&self) -> DomRoot { - self.stylesheet_list.or_init(|| { - StyleSheetList::new( - &self.window, - DocumentOrShadowRoot::ShadowRoot(Dom::from_ref(self)), - ) - }) + self.stylesheet_list + .or_init(|| StyleSheetList::new(&self.window, Box::new(Dom::from_ref(self)))) } } @@ -134,3 +120,13 @@ impl LayoutShadowRootHelpers for LayoutDom { (*self.unsafe_get()).host.to_layout() } } + +impl StyleSheetListOwner for Dom { + fn stylesheet_count(&self) -> usize { + self.document_or_shadow_root.stylesheet_count() + } + + fn stylesheet_at(&self, index: usize) -> Option> { + self.document_or_shadow_root.stylesheet_at(index) + } +} diff --git a/components/script/dom/stylesheetlist.rs b/components/script/dom/stylesheetlist.rs index 79afcfed21f..101a252086e 100644 --- a/components/script/dom/stylesheetlist.rs +++ b/components/script/dom/stylesheetlist.rs @@ -6,20 +6,25 @@ use crate::dom::bindings::codegen::Bindings::StyleSheetListBinding; use crate::dom::bindings::codegen::Bindings::StyleSheetListBinding::StyleSheetListMethods; use crate::dom::bindings::reflector::{reflect_dom_object, Reflector}; use crate::dom::bindings::root::DomRoot; -use crate::dom::documentorshadowroot::DocumentOrShadowRoot; +use crate::dom::cssstylesheet::CSSStyleSheet; use crate::dom::stylesheet::StyleSheet; use crate::dom::window::Window; use dom_struct::dom_struct; +pub trait StyleSheetListOwner { + fn stylesheet_count(&self) -> usize; + fn stylesheet_at(&self, index: usize) -> Option>; +} + #[dom_struct] pub struct StyleSheetList { reflector_: Reflector, - document_or_shadow_root: DocumentOrShadowRoot, + #[ignore_malloc_size_of = "trait object"] + document_or_shadow_root: Box, } impl StyleSheetList { - #[allow(unrooted_must_root)] - fn new_inherited(doc_or_sr: DocumentOrShadowRoot) -> StyleSheetList { + fn new_inherited(doc_or_sr: Box) -> StyleSheetList { StyleSheetList { reflector_: Reflector::new(), document_or_shadow_root: doc_or_sr, @@ -27,7 +32,7 @@ impl StyleSheetList { } #[allow(unrooted_must_root)] - pub fn new(window: &Window, doc_or_sr: DocumentOrShadowRoot) -> DomRoot { + pub fn new(window: &Window, doc_or_sr: Box) -> DomRoot { reflect_dom_object( Box::new(StyleSheetList::new_inherited(doc_or_sr)), window, From 3bb50cc4795c3ac98d25e2b54d871ded2c3f3fed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Tue, 5 Feb 2019 20:50:44 +0100 Subject: [PATCH 25/83] ShadowRoot stylesheet list --- components/script/dom/bindings/trace.rs | 13 ++++++++++- components/script/dom/document.rs | 28 +++++++++++------------ components/script/dom/htmllinkelement.rs | 12 ++++++---- components/script/dom/htmlmetaelement.rs | 9 +++++--- components/script/dom/htmlstyleelement.rs | 11 +++++---- components/script/dom/node.rs | 17 ++++++++++++++ components/script/dom/shadowroot.rs | 27 +++++++++++++++++++++- components/script/dom/stylesheetlist.rs | 5 ++++ 8 files changed, 93 insertions(+), 29 deletions(-) diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 2c86040308e..06ee56e173a 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -126,7 +126,7 @@ use style::media_queries::MediaList; use style::properties::PropertyDeclarationBlock; use style::selector_parser::{PseudoElement, Snapshot}; use style::shared_lock::{Locked as StyleLocked, SharedRwLock as StyleSharedRwLock}; -use style::stylesheet_set::DocumentStylesheetSet; +use style::stylesheet_set::{AuthorStylesheetSet, DocumentStylesheetSet}; use style::stylesheets::keyframes_rule::Keyframe; use style::stylesheets::{CssRules, FontFaceRule, KeyframesRule, MediaRule, Stylesheet}; use style::stylesheets::{ImportRule, NamespaceRule, StyleRule, SupportsRule, ViewportRule}; @@ -717,6 +717,17 @@ where } } +unsafe impl JSTraceable for AuthorStylesheetSet +where + S: JSTraceable + ::style::stylesheets::StylesheetInDocument + PartialEq + 'static, +{ + unsafe fn trace(&self, tracer: *mut JSTracer) { + for s in self.iter() { + s.trace(tracer) + } + } +} + unsafe impl JSTraceable for LossyDecoder where Sink: JSTraceable + TendrilSink, diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index f4f0e809fce..ad4099bdbf9 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -2838,20 +2838,6 @@ impl Document { Device::new(MediaType::screen(), viewport_size, device_pixel_ratio) } - /// Remove a stylesheet owned by `owner` from the list of document sheets. - #[allow(unrooted_must_root)] // Owner needs to be rooted already necessarily. - pub fn remove_stylesheet(&self, owner: &Element, s: &Arc) { - self.document_or_shadow_root.remove_stylesheet(owner, s) - } - - /// Add a stylesheet owned by `owner` to the list of document sheets, in the - /// correct tree position. - #[allow(unrooted_must_root)] // Owner needs to be rooted already necessarily. - pub fn add_stylesheet(&self, owner: &Element, sheet: Arc) { - self.document_or_shadow_root - .add_stylesheet(owner, sheet, self.style_shared_lock()); - } - pub fn salvageable(&self) -> bool { self.salvageable.get() } @@ -4570,4 +4556,18 @@ impl StyleSheetListOwner for Dom { fn stylesheet_at(&self, index: usize) -> Option> { self.document_or_shadow_root.stylesheet_at(index) } + + /// Add a stylesheet owned by `owner` to the list of document sheets, in the + /// correct tree position. + #[allow(unrooted_must_root)] // Owner needs to be rooted already necessarily. + fn add_stylesheet(&self, owner: &Element, sheet: Arc) { + self.document_or_shadow_root + .add_stylesheet(owner, sheet, self.style_shared_lock()); + } + + /// Remove a stylesheet owned by `owner` from the list of document sheets. + #[allow(unrooted_must_root)] // Owner needs to be rooted already necessarily. + fn remove_stylesheet(&self, owner: &Element, s: &Arc) { + self.document_or_shadow_root.remove_stylesheet(owner, s) + } } diff --git a/components/script/dom/htmllinkelement.rs b/components/script/dom/htmllinkelement.rs index 6623593bc43..9e102795b2c 100644 --- a/components/script/dom/htmllinkelement.rs +++ b/components/script/dom/htmllinkelement.rs @@ -18,7 +18,9 @@ use crate::dom::element::{ }; use crate::dom::element::{AttributeMutation, Element, ElementCreator}; use crate::dom::htmlelement::HTMLElement; -use crate::dom::node::{document_from_node, window_from_node, Node, UnbindContext}; +use crate::dom::node::{ + document_from_node, stylesheets_owner_from_node, window_from_node, Node, UnbindContext, +}; use crate::dom::stylesheet::StyleSheet as DOMStyleSheet; use crate::dom::virtualmethods::VirtualMethods; use crate::stylesheet_loader::{StylesheetContextSource, StylesheetLoader, StylesheetOwner}; @@ -108,13 +110,13 @@ impl HTMLLinkElement { // FIXME(emilio): These methods are duplicated with // HTMLStyleElement::set_stylesheet. pub fn set_stylesheet(&self, s: Arc) { - let doc = document_from_node(self); + let stylesheets_owner = stylesheets_owner_from_node(self); if let Some(ref s) = *self.stylesheet.borrow() { - doc.remove_stylesheet(self.upcast(), s) + stylesheets_owner.remove_stylesheet(self.upcast(), s) } *self.stylesheet.borrow_mut() = Some(s.clone()); self.cssom_stylesheet.set(None); - doc.add_stylesheet(self.upcast(), s); + stylesheets_owner.add_stylesheet(self.upcast(), s); } pub fn get_stylesheet(&self) -> Option> { @@ -252,7 +254,7 @@ impl VirtualMethods for HTMLLinkElement { } if let Some(s) = self.stylesheet.borrow_mut().take() { - document_from_node(self).remove_stylesheet(self.upcast(), &s); + stylesheets_owner_from_node(self).remove_stylesheet(self.upcast(), &s); } } } diff --git a/components/script/dom/htmlmetaelement.rs b/components/script/dom/htmlmetaelement.rs index de605c31092..0c8794711f1 100644 --- a/components/script/dom/htmlmetaelement.rs +++ b/components/script/dom/htmlmetaelement.rs @@ -15,7 +15,9 @@ use crate::dom::document::Document; use crate::dom::element::{AttributeMutation, Element}; use crate::dom::htmlelement::HTMLElement; use crate::dom::htmlheadelement::HTMLHeadElement; -use crate::dom::node::{document_from_node, window_from_node, Node, UnbindContext}; +use crate::dom::node::{ + document_from_node, stylesheets_owner_from_node, window_from_node, Node, UnbindContext, +}; use crate::dom::virtualmethods::VirtualMethods; use dom_struct::dom_struct; use html5ever::{LocalName, Prefix}; @@ -106,6 +108,7 @@ impl HTMLMetaElement { let content = content.value(); if !content.is_empty() { if let Some(translated_rule) = ViewportRule::from_meta(&**content) { + let stylesheets_owner = stylesheets_owner_from_node(self); let document = document_from_node(self); let shared_lock = document.style_shared_lock(); let rule = CssRule::Viewport(Arc::new(shared_lock.wrap(translated_rule))); @@ -124,7 +127,7 @@ impl HTMLMetaElement { disabled: AtomicBool::new(false), }); *self.stylesheet.borrow_mut() = Some(sheet.clone()); - document.add_stylesheet(self.upcast(), sheet); + stylesheets_owner.add_stylesheet(self.upcast(), sheet); } } } @@ -208,7 +211,7 @@ impl VirtualMethods for HTMLMetaElement { self.process_referrer_attribute(); if let Some(s) = self.stylesheet.borrow_mut().take() { - document_from_node(self).remove_stylesheet(self.upcast(), &s); + stylesheets_owner_from_node(self).remove_stylesheet(self.upcast(), &s); } } } diff --git a/components/script/dom/htmlstyleelement.rs b/components/script/dom/htmlstyleelement.rs index 20617a37079..f8465874a38 100644 --- a/components/script/dom/htmlstyleelement.rs +++ b/components/script/dom/htmlstyleelement.rs @@ -13,7 +13,8 @@ use crate::dom::document::Document; use crate::dom::element::{Element, ElementCreator}; use crate::dom::htmlelement::HTMLElement; use crate::dom::node::{ - document_from_node, window_from_node, ChildrenMutation, Node, UnbindContext, + document_from_node, stylesheets_owner_from_node, window_from_node, ChildrenMutation, Node, + UnbindContext, }; use crate::dom::stylesheet::StyleSheet as DOMStyleSheet; use crate::dom::virtualmethods::VirtualMethods; @@ -138,13 +139,13 @@ impl HTMLStyleElement { // FIXME(emilio): This is duplicated with HTMLLinkElement::set_stylesheet. pub fn set_stylesheet(&self, s: Arc) { - let doc = document_from_node(self); + let stylesheets_owner = stylesheets_owner_from_node(self); if let Some(ref s) = *self.stylesheet.borrow() { - doc.remove_stylesheet(self.upcast(), s) + stylesheets_owner.remove_stylesheet(self.upcast(), s) } *self.stylesheet.borrow_mut() = Some(s.clone()); self.cssom_stylesheet.set(None); - doc.add_stylesheet(self.upcast(), s); + stylesheets_owner.add_stylesheet(self.upcast(), s); } pub fn get_stylesheet(&self) -> Option> { @@ -216,7 +217,7 @@ impl VirtualMethods for HTMLStyleElement { if context.tree_connected { if let Some(s) = self.stylesheet.borrow_mut().take() { - document_from_node(self).remove_stylesheet(self.upcast(), &s) + stylesheets_owner_from_node(self).remove_stylesheet(self.upcast(), &s) } } } diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index b20f8cf037e..e1a40c13982 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -54,6 +54,7 @@ use crate::dom::nodelist::NodeList; use crate::dom::processinginstruction::ProcessingInstruction; use crate::dom::range::WeakRangeVec; use crate::dom::shadowroot::ShadowRoot; +use crate::dom::stylesheetlist::StyleSheetListOwner; use crate::dom::svgsvgelement::{LayoutSVGSVGElementHelpers, SVGSVGElement}; use crate::dom::text::Text; use crate::dom::virtualmethods::{vtable_for, VirtualMethods}; @@ -2786,6 +2787,22 @@ pub fn document_from_node + DomObject>(derived: &T) -> DomR derived.upcast().owner_doc() } +pub fn shadow_root_from_node + DomObject>( + derived: &T, +) -> Option> { + derived.upcast().owner_shadow_root() +} + +pub fn stylesheets_owner_from_node + DomObject>( + derived: &T, +) -> Box { + if let Some(shadow_root) = shadow_root_from_node(derived) { + Box::new(Dom::from_ref(&*shadow_root)) + } else { + Box::new(Dom::from_ref(&*document_from_node(derived))) + } +} + pub fn window_from_node + DomObject>(derived: &T) -> DomRoot { let document = document_from_node(derived); DomRoot::from_ref(document.window()) diff --git a/components/script/dom/shadowroot.rs b/components/script/dom/shadowroot.rs index 4a77452a2a5..3b1e9d34b87 100644 --- a/components/script/dom/shadowroot.rs +++ b/components/script/dom/shadowroot.rs @@ -2,6 +2,7 @@ * 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::cell::DomRefCell; use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::ShadowRootBinding::ShadowRootMethods; use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::{self, ShadowRootMode}; use crate::dom::bindings::inheritance::Castable; @@ -11,12 +12,15 @@ use crate::dom::bindings::root::{Dom, DomRoot, LayoutDom, 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, StyleSheetInDocument}; use crate::dom::element::Element; use crate::dom::node::{Node, NodeFlags}; use crate::dom::stylesheetlist::{StyleSheetList, StyleSheetListOwner}; use crate::dom::window::Window; use dom_struct::dom_struct; +use servo_arc::Arc; +use style::stylesheet_set::AuthorStylesheetSet; +use style::stylesheets::Stylesheet; // https://dom.spec.whatwg.org/#interface-shadowroot #[dom_struct] @@ -25,6 +29,9 @@ pub struct ShadowRoot { document_or_shadow_root: DocumentOrShadowRoot, document: Dom, host: Dom, + /// List of stylesheets associated with nodes in this shadow tree. + /// |None| if the list needs to be refreshed. + stylesheets: DomRefCell>, stylesheet_list: MutNullableDom, window: Dom, } @@ -41,6 +48,7 @@ impl ShadowRoot { document_or_shadow_root: DocumentOrShadowRoot::new(document.window()), document: Dom::from_ref(document), host: Dom::from_ref(host), + stylesheets: DomRefCell::new(AuthorStylesheetSet::new()), stylesheet_list: MutNullableDom::new(None), window: Dom::from_ref(document.window()), } @@ -129,4 +137,21 @@ impl StyleSheetListOwner for Dom { fn stylesheet_at(&self, index: usize) -> Option> { self.document_or_shadow_root.stylesheet_at(index) } + + /// Add a stylesheet owned by `owner` to the list of shadow root sheets, in the + /// correct tree position. + #[allow(unrooted_must_root)] // Owner needs to be rooted already necessarily. + fn add_stylesheet(&self, owner: &Element, sheet: Arc) { + self.document_or_shadow_root.add_stylesheet( + owner, + sheet, + self.document.style_shared_lock(), + ); + } + + /// Remove a stylesheet owned by `owner` from the list of shadow root sheets. + #[allow(unrooted_must_root)] // Owner needs to be rooted already necessarily. + fn remove_stylesheet(&self, owner: &Element, s: &Arc) { + self.document_or_shadow_root.remove_stylesheet(owner, s) + } } diff --git a/components/script/dom/stylesheetlist.rs b/components/script/dom/stylesheetlist.rs index 101a252086e..b87d7957dfb 100644 --- a/components/script/dom/stylesheetlist.rs +++ b/components/script/dom/stylesheetlist.rs @@ -7,13 +7,18 @@ use crate::dom::bindings::codegen::Bindings::StyleSheetListBinding::StyleSheetLi use crate::dom::bindings::reflector::{reflect_dom_object, Reflector}; use crate::dom::bindings::root::DomRoot; use crate::dom::cssstylesheet::CSSStyleSheet; +use crate::dom::element::Element; use crate::dom::stylesheet::StyleSheet; use crate::dom::window::Window; use dom_struct::dom_struct; +use servo_arc::Arc; +use style::stylesheets::Stylesheet; pub trait StyleSheetListOwner { fn stylesheet_count(&self) -> usize; fn stylesheet_at(&self, index: usize) -> Option>; + fn add_stylesheet(&self, owner: &Element, sheet: Arc); + fn remove_stylesheet(&self, owner: &Element, s: &Arc); } #[dom_struct] From 23b92d54d48274f4e80521c427a959cfd4cb646c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Fri, 8 Feb 2019 19:57:00 +0100 Subject: [PATCH 26/83] Remove stylesheets ownership from DocumentOrShadowRoot --- components/script/dom/bindings/trace.rs | 12 ++ components/script/dom/document.rs | 45 +++-- components/script/dom/documentorshadowroot.rs | 62 ++----- components/script/dom/htmlstyleelement.rs | 2 +- components/script/dom/shadowroot.rs | 31 +++- components/style/author_styles.rs | 2 + components/style/stylesheet_set.rs | 168 ++++++++++++------ components/style/stylist.rs | 2 +- 8 files changed, 200 insertions(+), 124 deletions(-) diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 06ee56e173a..2d568208b69 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -119,6 +119,7 @@ use std::sync::atomic::{AtomicBool, AtomicUsize}; use std::sync::{Arc, Mutex}; use std::time::{Instant, SystemTime}; use style::attr::{AttrIdentifier, AttrValue, LengthOrPercentageOrAuto}; +use style::author_styles::AuthorStyles; use style::context::QuirksMode; use style::dom::OpaqueNode; use style::element_state::*; @@ -130,6 +131,7 @@ use style::stylesheet_set::{AuthorStylesheetSet, DocumentStylesheetSet}; use style::stylesheets::keyframes_rule::Keyframe; use style::stylesheets::{CssRules, FontFaceRule, KeyframesRule, MediaRule, Stylesheet}; use style::stylesheets::{ImportRule, NamespaceRule, StyleRule, SupportsRule, ViewportRule}; +use style::stylist::CascadeData; use style::values::specified::Length; use tendril::fmt::UTF8; use tendril::stream::LossyDecoder; @@ -499,6 +501,7 @@ unsafe_no_jsmanaged_fields!(Rotation3D, Transform2D, Transform3D) unsafe_no_jsmanaged_fields!(Point2D, Vector2D, Rect); unsafe_no_jsmanaged_fields!(Rect, RigidTransform3D); unsafe_no_jsmanaged_fields!(StyleSheetListOwner); +unsafe_no_jsmanaged_fields!(CascadeData); unsafe impl<'a> JSTraceable for &'a str { #[inline] @@ -728,6 +731,15 @@ where } } +unsafe impl JSTraceable for AuthorStyles +where + S: JSTraceable + ::style::stylesheets::StylesheetInDocument + PartialEq + 'static, +{ + unsafe fn trace(&self, tracer: *mut JSTracer) { + self.stylesheets.trace(tracer) + } +} + unsafe impl JSTraceable for LossyDecoder where Sink: JSTraceable + TendrilSink, diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index ad4099bdbf9..977bff505dc 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -156,7 +156,7 @@ use style::selector_parser::{RestyleDamage, Snapshot}; use style::shared_lock::SharedRwLock as StyleSharedRwLock; use style::str::{split_html_space_chars, str_join}; use style::stylesheet_set::DocumentStylesheetSet; -use style::stylesheets::Stylesheet; +use style::stylesheets::{Origin, OriginSet, Stylesheet}; use url::percent_encoding::percent_decode; use url::Host; @@ -574,7 +574,7 @@ impl Document { // FIXME: This should check the dirty bit on the document, // not the document element. Needs some layout changes to make // that workable. - self.document_or_shadow_root.stylesheets_have_changed() || + self.stylesheets.borrow().has_changed() || self.GetDocumentElement().map_or(false, |root| { root.upcast::().has_dirty_descendants() || !self.pending_restyles.borrow().is_empty() || @@ -1536,7 +1536,7 @@ impl Document { } pub fn invalidate_stylesheets(&self) { - self.document_or_shadow_root.invalidate_stylesheets(); + self.stylesheets.borrow_mut().force_dirty(OriginSet::all()); // Mark the document element dirty so a reflow will be performed. // @@ -2821,9 +2821,9 @@ impl Document { // and normal stylesheets additions / removals, because in the last case // the layout thread already has that information and we could avoid // dirtying the whole thing. - let have_changed = self.document_or_shadow_root.stylesheets_have_changed(); - self.document_or_shadow_root - .flush_stylesheets_without_invalidation(); + let mut stylesheets = self.stylesheets.borrow_mut(); + let have_changed = stylesheets.has_changed(); + stylesheets.flush_without_invalidation(); have_changed } @@ -4550,24 +4550,47 @@ impl PendingScript { impl StyleSheetListOwner for Dom { fn stylesheet_count(&self) -> usize { - self.document_or_shadow_root.stylesheet_count() + self.stylesheets.borrow().len() } fn stylesheet_at(&self, index: usize) -> Option> { - self.document_or_shadow_root.stylesheet_at(index) + let stylesheets = self.stylesheets.borrow(); + + stylesheets + .get(Origin::Author, index) + .and_then(|s| s.owner.upcast::().get_cssom_stylesheet()) } /// Add a stylesheet owned by `owner` to the list of document sheets, in the /// correct tree position. #[allow(unrooted_must_root)] // Owner needs to be rooted already necessarily. fn add_stylesheet(&self, owner: &Element, sheet: Arc) { - self.document_or_shadow_root - .add_stylesheet(owner, sheet, self.style_shared_lock()); + let stylesheets = &mut *self.stylesheets.borrow_mut(); + let insertion_point = stylesheets + .iter() + .map(|(sheet, _origin)| sheet) + .find(|sheet_in_doc| { + owner + .upcast::() + .is_before(sheet_in_doc.owner.upcast()) + }) + .cloned(); + self.document_or_shadow_root.add_stylesheet( + owner, + stylesheets, + sheet, + insertion_point, + self.style_shared_lock(), + ); } /// Remove a stylesheet owned by `owner` from the list of document sheets. #[allow(unrooted_must_root)] // Owner needs to be rooted already necessarily. fn remove_stylesheet(&self, owner: &Element, s: &Arc) { - self.document_or_shadow_root.remove_stylesheet(owner, s) + self.document_or_shadow_root.remove_stylesheet( + owner, + s, + &mut *self.stylesheets.borrow_mut(), + ) } } diff --git a/components/script/dom/documentorshadowroot.rs b/components/script/dom/documentorshadowroot.rs index b1ea9ee1549..577df4bfd51 100644 --- a/components/script/dom/documentorshadowroot.rs +++ b/components/script/dom/documentorshadowroot.rs @@ -2,16 +2,14 @@ * 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::cell::DomRefCell; 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::element::Element; use crate::dom::htmlelement::HTMLElement; use crate::dom::htmlmetaelement::HTMLMetaElement; -use crate::dom::node::{self, Node}; +use crate::dom::node; use crate::dom::window::Window; use euclid::Point2D; use js::jsapi::JS_GetRuntime; @@ -22,15 +20,15 @@ use std::fmt; use style::context::QuirksMode; use style::media_queries::MediaList; use style::shared_lock::{SharedRwLock as StyleSharedRwLock, SharedRwLockReadGuard}; -use style::stylesheet_set::DocumentStylesheetSet; -use style::stylesheets::{CssRule, Origin, OriginSet, Stylesheet}; +use style::stylesheet_set::StylesheetSet; +use style::stylesheets::{CssRule, Origin, Stylesheet}; #[derive(Clone, JSTraceable, MallocSizeOf)] #[must_root] pub struct StyleSheetInDocument { #[ignore_malloc_size_of = "Arc"] - sheet: Arc, - owner: Dom, + pub sheet: Arc, + pub owner: Dom, } impl fmt::Debug for StyleSheetInDocument { @@ -72,16 +70,12 @@ impl ::style::stylesheets::StylesheetInDocument for StyleSheetInDocument { #[derive(JSTraceable, MallocSizeOf)] pub struct DocumentOrShadowRoot { window: Dom, - /// List of stylesheets associated with nodes in this document or shadow root. - /// |None| if the list needs to be refreshed. - stylesheets: DomRefCell>, } impl DocumentOrShadowRoot { pub fn new(window: &Window) -> Self { Self { window: Dom::from_ref(window), - stylesheets: DomRefCell::new(DocumentStylesheetSet::new()), } } @@ -207,33 +201,14 @@ impl DocumentOrShadowRoot { } } - pub fn stylesheet_count(&self) -> usize { - self.stylesheets.borrow().len() - } - - pub fn stylesheet_at(&self, index: usize) -> Option> { - let stylesheets = self.stylesheets.borrow(); - - stylesheets - .get(Origin::Author, index) - .and_then(|s| s.owner.upcast::().get_cssom_stylesheet()) - } - - pub fn stylesheets_have_changed(&self) -> bool { - self.stylesheets.borrow().has_changed() - } - - pub fn invalidate_stylesheets(&self) { - self.stylesheets.borrow_mut().force_dirty(OriginSet::all()); - } - - pub fn flush_stylesheets_without_invalidation(&self) { - self.stylesheets.borrow_mut().flush_without_invalidation(); - } - /// Remove a stylesheet owned by `owner` from the list of document sheets. #[allow(unrooted_must_root)] // Owner needs to be rooted already necessarily. - pub fn remove_stylesheet(&self, owner: &Element, s: &Arc) { + pub fn remove_stylesheet( + &self, + owner: &Element, + s: &Arc, + stylesheets: &mut StylesheetSet, + ) { self.window .layout_chan() .send(Msg::RemoveStylesheet(s.clone())) @@ -242,7 +217,7 @@ impl DocumentOrShadowRoot { let guard = s.shared_lock.read(); // FIXME(emilio): Would be nice to remove the clone, etc. - self.stylesheets.borrow_mut().remove_stylesheet( + stylesheets.remove_stylesheet( None, StyleSheetInDocument { sheet: s.clone(), @@ -258,7 +233,9 @@ impl DocumentOrShadowRoot { pub fn add_stylesheet( &self, owner: &Element, + stylesheets: &mut StylesheetSet, sheet: Arc, + insertion_point: Option, style_shared_lock: &StyleSharedRwLock, ) { // FIXME(emilio): It'd be nice to unify more code between the elements @@ -269,17 +246,6 @@ impl DocumentOrShadowRoot { "Wat" ); - let mut stylesheets = self.stylesheets.borrow_mut(); - let insertion_point = stylesheets - .iter() - .map(|(sheet, _origin)| sheet) - .find(|sheet_in_doc| { - owner - .upcast::() - .is_before(sheet_in_doc.owner.upcast()) - }) - .cloned(); - self.window .layout_chan() .send(Msg::AddStylesheet( diff --git a/components/script/dom/htmlstyleelement.rs b/components/script/dom/htmlstyleelement.rs index f8465874a38..763afcf1bdb 100644 --- a/components/script/dom/htmlstyleelement.rs +++ b/components/script/dom/htmlstyleelement.rs @@ -82,7 +82,7 @@ impl HTMLStyleElement { pub fn parse_own_css(&self) { let node = self.upcast::(); let element = self.upcast::(); - assert!(node.is_in_doc()); + assert!(node.is_connected()); let window = window_from_node(node); let doc = document_from_node(self); diff --git a/components/script/dom/shadowroot.rs b/components/script/dom/shadowroot.rs index 3b1e9d34b87..7790423fb0a 100644 --- a/components/script/dom/shadowroot.rs +++ b/components/script/dom/shadowroot.rs @@ -19,7 +19,7 @@ use crate::dom::stylesheetlist::{StyleSheetList, StyleSheetListOwner}; use crate::dom::window::Window; use dom_struct::dom_struct; use servo_arc::Arc; -use style::stylesheet_set::AuthorStylesheetSet; +use style::author_styles::AuthorStyles; use style::stylesheets::Stylesheet; // https://dom.spec.whatwg.org/#interface-shadowroot @@ -31,7 +31,7 @@ pub struct ShadowRoot { host: Dom, /// List of stylesheets associated with nodes in this shadow tree. /// |None| if the list needs to be refreshed. - stylesheets: DomRefCell>, + author_styles: DomRefCell>, stylesheet_list: MutNullableDom, window: Dom, } @@ -48,7 +48,7 @@ impl ShadowRoot { document_or_shadow_root: DocumentOrShadowRoot::new(document.window()), document: Dom::from_ref(document), host: Dom::from_ref(host), - stylesheets: DomRefCell::new(AuthorStylesheetSet::new()), + author_styles: DomRefCell::new(AuthorStyles::new()), stylesheet_list: MutNullableDom::new(None), window: Dom::from_ref(document.window()), } @@ -131,20 +131,35 @@ impl LayoutShadowRootHelpers for LayoutDom { impl StyleSheetListOwner for Dom { fn stylesheet_count(&self) -> usize { - self.document_or_shadow_root.stylesheet_count() + self.author_styles.borrow().stylesheets.len() } fn stylesheet_at(&self, index: usize) -> Option> { - self.document_or_shadow_root.stylesheet_at(index) + let stylesheets = &self.author_styles.borrow().stylesheets; + + stylesheets + .get(index) + .and_then(|s| s.owner.upcast::().get_cssom_stylesheet()) } /// Add a stylesheet owned by `owner` to the list of shadow root sheets, in the /// correct tree position. #[allow(unrooted_must_root)] // Owner needs to be rooted already necessarily. fn add_stylesheet(&self, owner: &Element, sheet: Arc) { + let stylesheets = &mut self.author_styles.borrow_mut().stylesheets; + let insertion_point = stylesheets + .iter() + .find(|sheet_in_shadow| { + owner + .upcast::() + .is_before(sheet_in_shadow.owner.upcast()) + }) + .cloned(); self.document_or_shadow_root.add_stylesheet( owner, + stylesheets, sheet, + insertion_point, self.document.style_shared_lock(), ); } @@ -152,6 +167,10 @@ impl StyleSheetListOwner for Dom { /// Remove a stylesheet owned by `owner` from the list of shadow root sheets. #[allow(unrooted_must_root)] // Owner needs to be rooted already necessarily. fn remove_stylesheet(&self, owner: &Element, s: &Arc) { - self.document_or_shadow_root.remove_stylesheet(owner, s) + self.document_or_shadow_root.remove_stylesheet( + owner, + s, + &mut self.author_styles.borrow_mut().stylesheets, + ) } } diff --git a/components/style/author_styles.rs b/components/style/author_styles.rs index 37eb68ff4f7..46f95e1cac9 100644 --- a/components/style/author_styles.rs +++ b/components/style/author_styles.rs @@ -18,6 +18,7 @@ use crate::stylist::CascadeData; /// A set of author stylesheets and their computed representation, such as the /// ones used for ShadowRoot and XBL. +#[derive(MallocSizeOf)] pub struct AuthorStyles where S: StylesheetInDocument + PartialEq + 'static, @@ -29,6 +30,7 @@ where pub data: CascadeData, /// The quirks mode of the last stylesheet flush, used because XBL sucks and /// we should really fix it, see bug 1406875. + #[ignore_malloc_size_of = "XXX"] pub quirks_mode: QuirksMode, } diff --git a/components/style/stylesheet_set.rs b/components/style/stylesheet_set.rs index 409978c3a9e..9a53339f5f9 100644 --- a/components/style/stylesheet_set.rs +++ b/components/style/stylesheet_set.rs @@ -373,69 +373,113 @@ where invalidations: StylesheetInvalidationSet, } +/// Functionality common to DocumentStylesheetSet and AuthorStylesheetSet. +pub trait StylesheetSet +where + S: StylesheetInDocument + PartialEq + 'static, +{ + /// Appends a new stylesheet to the current set. + /// + /// No device implies not computing invalidations. + fn append_stylesheet( + &mut self, + device: Option<&Device>, + sheet: S, + guard: &SharedRwLockReadGuard, + ); + + /// Insert a given stylesheet before another stylesheet in the document. + fn insert_stylesheet_before( + &mut self, + device: Option<&Device>, + sheet: S, + before_sheet: S, + guard: &SharedRwLockReadGuard, + ); + + /// Remove a given stylesheet from the set. + fn remove_stylesheet( + &mut self, + device: Option<&Device>, + sheet: S, + guard: &SharedRwLockReadGuard, + ); +} + /// This macro defines methods common to DocumentStylesheetSet and /// AuthorStylesheetSet. /// /// We could simplify the setup moving invalidations to SheetCollection, but /// that would imply not sharing invalidations across origins of the same /// documents, which is slightly annoying. -macro_rules! sheet_set_methods { - ($set_name:expr) => { - fn collect_invalidations_for( - &mut self, - device: Option<&Device>, - sheet: &S, - guard: &SharedRwLockReadGuard, - ) { - if let Some(device) = device { - self.invalidations.collect_invalidations_for(device, sheet, guard); +macro_rules! stylesheetset_impl { + ($set_name:expr, $set_type:ty) => { + impl $set_type + where + S: StylesheetInDocument + PartialEq + 'static, + { + fn collect_invalidations_for( + &mut self, + device: Option<&Device>, + sheet: &S, + guard: &SharedRwLockReadGuard, + ) { + if let Some(device) = device { + self.invalidations + .collect_invalidations_for(device, sheet, guard); + } } } - /// Appends a new stylesheet to the current set. - /// - /// No device implies not computing invalidations. - pub fn append_stylesheet( - &mut self, - device: Option<&Device>, - sheet: S, - guard: &SharedRwLockReadGuard, - ) { - debug!(concat!($set_name, "::append_stylesheet")); - self.collect_invalidations_for(device, &sheet, guard); - let collection = self.collection_for(&sheet, guard); - collection.append(sheet); + impl StylesheetSet for $set_type + where + S: StylesheetInDocument + PartialEq + 'static, + { + /// Appends a new stylesheet to the current set. + /// + /// No device implies not computing invalidations. + fn append_stylesheet( + &mut self, + device: Option<&Device>, + sheet: S, + guard: &SharedRwLockReadGuard, + ) { + debug!(concat!($set_name, "::append_stylesheet")); + self.collect_invalidations_for(device, &sheet, guard); + let collection = self.collection_for(&sheet, guard); + collection.append(sheet); + } + + /// Insert a given stylesheet before another stylesheet in the document. + fn insert_stylesheet_before( + &mut self, + device: Option<&Device>, + sheet: S, + before_sheet: S, + guard: &SharedRwLockReadGuard, + ) { + debug!(concat!($set_name, "::insert_stylesheet_before")); + self.collect_invalidations_for(device, &sheet, guard); + + let collection = self.collection_for(&sheet, guard); + collection.insert_before(sheet, &before_sheet); + } + + /// Remove a given stylesheet from the set. + fn remove_stylesheet( + &mut self, + device: Option<&Device>, + sheet: S, + guard: &SharedRwLockReadGuard, + ) { + debug!(concat!($set_name, "::remove_stylesheet")); + self.collect_invalidations_for(device, &sheet, guard); + + let collection = self.collection_for(&sheet, guard); + collection.remove(&sheet) + } } - - /// Insert a given stylesheet before another stylesheet in the document. - pub fn insert_stylesheet_before( - &mut self, - device: Option<&Device>, - sheet: S, - before_sheet: S, - guard: &SharedRwLockReadGuard, - ) { - debug!(concat!($set_name, "::insert_stylesheet_before")); - self.collect_invalidations_for(device, &sheet, guard); - - let collection = self.collection_for(&sheet, guard); - collection.insert_before(sheet, &before_sheet); - } - - /// Remove a given stylesheet from the set. - pub fn remove_stylesheet( - &mut self, - device: Option<&Device>, - sheet: S, - guard: &SharedRwLockReadGuard, - ) { - debug!(concat!($set_name, "::remove_stylesheet")); - self.collect_invalidations_for(device, &sheet, guard); - - let collection = self.collection_for(&sheet, guard); - collection.remove(&sheet) - } - } + }; } impl DocumentStylesheetSet @@ -459,8 +503,6 @@ where self.collections.borrow_mut_for_origin(&origin) } - sheet_set_methods!("DocumentStylesheetSet"); - /// Returns the number of stylesheets in the set. pub fn len(&self) -> usize { self.collections @@ -539,6 +581,8 @@ where } } +stylesheetset_impl!("DocumentStylesheetSet", DocumentStylesheetSet); + /// The set of stylesheets effective for a given XBL binding or Shadow Root. #[derive(MallocSizeOf)] pub struct AuthorStylesheetSet @@ -585,6 +629,16 @@ where self.collection.len() == 0 } + /// Returns the `index`th stylesheet in the collection of author styles if present. + pub fn get(&self, index: usize) -> Option<&S> { + self.collection.get(index) + } + + /// Returns the number of author stylesheets. + pub fn len(&self) -> usize { + self.collection.len() + } + fn collection_for( &mut self, _sheet: &S, @@ -593,8 +647,6 @@ where &mut self.collection } - sheet_set_methods!("AuthorStylesheetSet"); - /// Iterate over the list of stylesheets. pub fn iter(&self) -> StylesheetCollectionIterator { self.collection.iter() @@ -626,3 +678,5 @@ where } } } + +stylesheetset_impl!("AuthorStylesheetSet", AuthorStylesheetSet); diff --git a/components/style/stylist.rs b/components/style/stylist.rs index ece14e9896f..045d6b01cd1 100644 --- a/components/style/stylist.rs +++ b/components/style/stylist.rs @@ -23,7 +23,7 @@ use crate::selector_map::{PrecomputedHashMap, PrecomputedHashSet, SelectorMap, S use crate::selector_parser::{PerPseudoElementMap, PseudoElement, SelectorImpl, SnapshotMap}; use crate::shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards}; use crate::stylesheet_set::{DataValidity, DocumentStylesheetSet, SheetRebuildKind}; -use crate::stylesheet_set::{DocumentStylesheetFlusher, SheetCollectionFlusher}; +use crate::stylesheet_set::{DocumentStylesheetFlusher, SheetCollectionFlusher, StylesheetSet}; use crate::stylesheets::keyframes_rule::KeyframesAnimation; use crate::stylesheets::viewport_rule::{self, MaybeNew, ViewportRule}; use crate::stylesheets::StyleRule; From e9f0e76d3c53888683fca4c9330f4b5884238f01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Mon, 11 Feb 2019 10:20:42 +0100 Subject: [PATCH 27/83] Implement TShadowRoot::style_data --- components/layout_thread/dom_wrapper.rs | 7 ++++++- components/script/dom/documentorshadowroot.rs | 7 +++++++ components/script/dom/shadowroot.rs | 21 +++++++++++++++++-- 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/components/layout_thread/dom_wrapper.rs b/components/layout_thread/dom_wrapper.rs index 580965b91d0..8dc06aad9cb 100644 --- a/components/layout_thread/dom_wrapper.rs +++ b/components/layout_thread/dom_wrapper.rs @@ -200,7 +200,12 @@ impl<'sr> TShadowRoot for ServoShadowRoot<'sr> { where Self: 'a, { - None + Some(unsafe { + &self + .shadow_root + .get_style_data_for_layout::() + .data + }) } } diff --git a/components/script/dom/documentorshadowroot.rs b/components/script/dom/documentorshadowroot.rs index 577df4bfd51..80b0e0022ba 100644 --- a/components/script/dom/documentorshadowroot.rs +++ b/components/script/dom/documentorshadowroot.rs @@ -18,6 +18,7 @@ use script_traits::UntrustedNodeAddress; use servo_arc::Arc; use std::fmt; use style::context::QuirksMode; +use style::invalidation::media_queries::{MediaListKey, ToMediaListKey}; use style::media_queries::MediaList; use style::shared_lock::{SharedRwLock as StyleSharedRwLock, SharedRwLockReadGuard}; use style::stylesheet_set::StylesheetSet; @@ -43,6 +44,12 @@ impl PartialEq for StyleSheetInDocument { } } +impl ToMediaListKey for StyleSheetInDocument { + fn to_media_list_key(&self) -> MediaListKey { + self.sheet.to_media_list_key() + } +} + impl ::style::stylesheets::StylesheetInDocument for StyleSheetInDocument { fn origin(&self, guard: &SharedRwLockReadGuard) -> Origin { self.sheet.origin(guard) diff --git a/components/script/dom/shadowroot.rs b/components/script/dom/shadowroot.rs index 7790423fb0a..d99f0c86493 100644 --- a/components/script/dom/shadowroot.rs +++ b/components/script/dom/shadowroot.rs @@ -20,6 +20,7 @@ use crate::dom::window::Window; use dom_struct::dom_struct; use servo_arc::Arc; use style::author_styles::AuthorStyles; +use style::dom::TElement; use style::stylesheets::Stylesheet; // https://dom.spec.whatwg.org/#interface-shadowroot @@ -29,8 +30,7 @@ pub struct ShadowRoot { document_or_shadow_root: DocumentOrShadowRoot, document: Dom, host: Dom, - /// List of stylesheets associated with nodes in this shadow tree. - /// |None| if the list needs to be refreshed. + /// List of author styles associated with nodes in this shadow tree. author_styles: DomRefCell>, stylesheet_list: MutNullableDom, window: Dom, @@ -119,6 +119,9 @@ impl ShadowRootMethods for ShadowRoot { #[allow(unsafe_code)] pub trait LayoutShadowRootHelpers { unsafe fn get_host_for_layout(&self) -> LayoutDom; + unsafe fn get_style_data_for_layout<'a, E: TElement>( + &self, + ) -> &'a AuthorStyles; } impl LayoutShadowRootHelpers for LayoutDom { @@ -127,6 +130,20 @@ impl LayoutShadowRootHelpers for LayoutDom { unsafe fn get_host_for_layout(&self) -> LayoutDom { (*self.unsafe_get()).host.to_layout() } + + #[inline] + #[allow(unsafe_code)] + unsafe fn get_style_data_for_layout<'a, E: TElement>( + &self, + ) -> &'a AuthorStyles { + { + let mut author_styles = (*self.unsafe_get()).author_styles.borrow_mut_for_layout(); + // let document = &(*self.unsafe_get()).document; + // let guard = document.style_shared_lock().read(); + // author_styles.flush::(&document.device(), document.quirks_mode(), &guard); + } + (*self.unsafe_get()).author_styles.borrow_for_layout() + } } impl StyleSheetListOwner for Dom { From cd07574235bb4e9b3f8d23b83408ef636bdcef9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Tue, 12 Feb 2019 10:38:29 +0100 Subject: [PATCH 28/83] Expose a way to flush shadow root stylesheets from layout --- components/layout_thread/dom_wrapper.rs | 12 +++++++++++- components/script/dom/shadowroot.rs | 16 ++++++++++------ 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/components/layout_thread/dom_wrapper.rs b/components/layout_thread/dom_wrapper.rs index 8dc06aad9cb..bbc023cf958 100644 --- a/components/layout_thread/dom_wrapper.rs +++ b/components/layout_thread/dom_wrapper.rs @@ -86,7 +86,9 @@ use style::font_metrics::ServoMetricsProvider; use style::properties::{ComputedValues, PropertyDeclarationBlock}; use style::selector_parser::{extended_filtering, PseudoElement, SelectorImpl}; use style::selector_parser::{AttrValue as SelectorAttrValue, Lang, NonTSPseudoClass}; -use style::shared_lock::{Locked as StyleLocked, SharedRwLock as StyleSharedRwLock}; +use style::shared_lock::{ + Locked as StyleLocked, SharedRwLock as StyleSharedRwLock, SharedRwLockReadGuard, +}; use style::str::is_whitespace; use style::stylist::CascadeData; use style::CaseSensitivityExt; @@ -216,6 +218,14 @@ impl<'sr> ServoShadowRoot<'sr> { chain: PhantomData, } } + + pub fn flush_stylesheets(&self, guard: &SharedRwLockReadGuard) { + unsafe { + &self + .shadow_root + .flush_stylesheets::(guard) + }; + } } impl<'ln> TNode for ServoLayoutNode<'ln> { diff --git a/components/script/dom/shadowroot.rs b/components/script/dom/shadowroot.rs index d99f0c86493..7f06b486b1d 100644 --- a/components/script/dom/shadowroot.rs +++ b/components/script/dom/shadowroot.rs @@ -21,6 +21,7 @@ use dom_struct::dom_struct; use servo_arc::Arc; use style::author_styles::AuthorStyles; use style::dom::TElement; +use style::shared_lock::SharedRwLockReadGuard; use style::stylesheets::Stylesheet; // https://dom.spec.whatwg.org/#interface-shadowroot @@ -122,6 +123,7 @@ pub trait LayoutShadowRootHelpers { unsafe fn get_style_data_for_layout<'a, E: TElement>( &self, ) -> &'a AuthorStyles; + unsafe fn flush_stylesheets(&self, guard: &SharedRwLockReadGuard); } impl LayoutShadowRootHelpers for LayoutDom { @@ -136,14 +138,16 @@ impl LayoutShadowRootHelpers for LayoutDom { unsafe fn get_style_data_for_layout<'a, E: TElement>( &self, ) -> &'a AuthorStyles { - { - let mut author_styles = (*self.unsafe_get()).author_styles.borrow_mut_for_layout(); - // let document = &(*self.unsafe_get()).document; - // let guard = document.style_shared_lock().read(); - // author_styles.flush::(&document.device(), document.quirks_mode(), &guard); - } (*self.unsafe_get()).author_styles.borrow_for_layout() } + + #[inline] + #[allow(unsafe_code)] + unsafe fn flush_stylesheets(&self, guard: &SharedRwLockReadGuard) { + let document = &(*self.unsafe_get()).document; + let mut author_styles = (*self.unsafe_get()).author_styles.borrow_mut_for_layout(); + author_styles.flush::(&document.device(), document.quirks_mode(), guard); + } } impl StyleSheetListOwner for Dom { From 18c1b8f6908e6f5eddce5413b37a83e34268d8e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Tue, 12 Feb 2019 12:44:44 +0100 Subject: [PATCH 29/83] Register/unregister shadow roots in documents when they are connected --- components/script/dom/document.rs | 17 +++++++++++++++++ components/script/dom/element.rs | 19 +++++++++++++------ 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 977bff505dc..3f1bf1c450a 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -377,6 +377,8 @@ pub struct Document { delayed_tasks: DomRefCell>>, /// https://html.spec.whatwg.org/multipage/#completely-loaded completely_loaded: Cell, + /// List of shadow roots bound to the document tree. + shadow_roots: DomRefCell>>, } #[derive(JSTraceable, MallocSizeOf)] @@ -2680,6 +2682,7 @@ impl Document { completely_loaded: Cell::new(false), script_and_layout_blockers: Cell::new(0), delayed_tasks: Default::default(), + shadow_roots: DomRefCell::new(Vec::new()), } } @@ -3132,6 +3135,20 @@ impl Document { } } } + + pub fn register_shadow_root(&self, shadow_root: &ShadowRoot) { + self.shadow_roots + .borrow_mut() + .push(Dom::from_ref(shadow_root)); + } + + pub fn unregister_shadow_root(&self, shadow_root: &ShadowRoot) { + let mut shadow_roots = self.shadow_roots.borrow_mut(); + let position = shadow_roots.iter().position(|sr| **sr == *shadow_root); + if let Some(index) = position { + shadow_roots.remove(index); + } + } } impl Element { diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 4b24ab84a90..7a69d4c781f 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -486,9 +486,13 @@ impl Element { } // Steps 4, 5 and 6. - Ok(self + let shadow_root = self .shadow_root - .or_init(|| ShadowRoot::new(self, &*self.node.owner_doc()))) + .or_init(|| ShadowRoot::new(self, &*self.node.owner_doc())); + + self.node.owner_doc().register_shadow_root(&*shadow_root); + + Ok(shadow_root) } } @@ -2787,8 +2791,9 @@ impl VirtualMethods for Element { return; } - if self.is_shadow_host() { - let shadow_root = self.shadow_root.get().unwrap(); + let doc = document_from_node(self); + + if let Some(shadow_root) = self.upcast::().owner_shadow_root() { let shadow_root = shadow_root.upcast::(); shadow_root.set_flag(NodeFlags::IS_CONNECTED, tree_connected); for node in shadow_root.children() { @@ -2797,7 +2802,6 @@ impl VirtualMethods for Element { } } - let doc = document_from_node(self); if let Some(ref value) = *self.id_attribute.borrow() { doc.register_named_element(self, value.clone()); } @@ -2816,8 +2820,12 @@ impl VirtualMethods for Element { return; } + let doc = document_from_node(self); + if self.is_shadow_host() { let shadow_root = self.shadow_root.get().unwrap(); + doc.unregister_shadow_root(&shadow_root); + let shadow_root = shadow_root.upcast::(); let shadow_root = shadow_root.upcast::(); shadow_root.set_flag(NodeFlags::IS_CONNECTED, false); for node in shadow_root.children() { @@ -2826,7 +2834,6 @@ impl VirtualMethods for Element { } } - let doc = document_from_node(self); let fullscreen = doc.GetFullscreenElement(); if fullscreen.deref() == Some(self) { doc.exit_fullscreen(); From 519cc2c31754d75c1b6cab7db0cfb0c1aaabbdf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Wed, 13 Feb 2019 17:01:30 +0100 Subject: [PATCH 30/83] Invalidate and flush shadow tree stylesheets where needed --- components/layout_thread/dom_wrapper.rs | 20 +++++++++++-- components/layout_thread/lib.rs | 13 +++++++- components/script/dom/cssstyledeclaration.rs | 16 ++++++---- components/script/dom/cssstylerule.rs | 19 ++++++++---- components/script/dom/cssstylesheet.rs | 18 +++++++++--- components/script/dom/document.rs | 11 +++++++ components/script/dom/shadowroot.rs | 31 ++++++++++++++++---- components/script/stylesheet_loader.rs | 12 ++++++-- 8 files changed, 115 insertions(+), 25 deletions(-) diff --git a/components/layout_thread/dom_wrapper.rs b/components/layout_thread/dom_wrapper.rs index bbc023cf958..1aa9488c327 100644 --- a/components/layout_thread/dom_wrapper.rs +++ b/components/layout_thread/dom_wrapper.rs @@ -83,6 +83,7 @@ use style::dom::{DomChildren, LayoutIterator, NodeInfo, OpaqueNode}; use style::dom::{TDocument, TElement, TNode, TShadowRoot}; use style::element_state::*; use style::font_metrics::ServoMetricsProvider; +use style::media_queries::Device; use style::properties::{ComputedValues, PropertyDeclarationBlock}; use style::selector_parser::{extended_filtering, PseudoElement, SelectorImpl}; use style::selector_parser::{AttrValue as SelectorAttrValue, Lang, NonTSPseudoClass}; @@ -219,11 +220,16 @@ impl<'sr> ServoShadowRoot<'sr> { } } - pub fn flush_stylesheets(&self, guard: &SharedRwLockReadGuard) { + pub fn flush_stylesheets( + &self, + device: &Device, + quirks_mode: QuirksMode, + guard: &SharedRwLockReadGuard, + ) { unsafe { &self .shadow_root - .flush_stylesheets::(guard) + .flush_stylesheets::(device, quirks_mode, guard) }; } } @@ -425,6 +431,16 @@ impl<'ld> ServoLayoutDocument<'ld> { unsafe { self.document.style_shared_lock() } } + pub fn shadow_roots(&self) -> Vec { + unsafe { + self.document + .shadow_roots() + .iter() + .map(|sr| ServoShadowRoot::from_layout_js(*sr)) + .collect() + } + } + pub fn from_layout_js(doc: LayoutDom) -> ServoLayoutDocument<'ld> { ServoLayoutDocument { document: doc, diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs index 839fac79006..8c46fb90720 100644 --- a/components/layout_thread/lib.rs +++ b/components/layout_thread/lib.rs @@ -103,7 +103,7 @@ use std::time::Duration; use style::animation::Animation; use style::context::{QuirksMode, RegisteredSpeculativePainter, RegisteredSpeculativePainters}; use style::context::{SharedStyleContext, ThreadLocalStyleContextCreationInfo}; -use style::dom::{ShowSubtree, ShowSubtreeDataAndPrimaryValues, TElement, TNode}; +use style::dom::{ShowSubtree, ShowSubtreeDataAndPrimaryValues, TDocument, TElement, TNode}; use style::driver; use style::error_reporting::RustLogReporter; use style::global_style_data::{GLOBAL_STYLE_DATA, STYLE_THREAD_POOL}; @@ -1346,6 +1346,17 @@ impl LayoutThread { } } + debug!( + "Shadow roots in document {:?}", + document.shadow_roots().len() + ); + + let device = Device::new(MediaType::screen(), initial_viewport, device_pixel_ratio); + // Flush shadow roots stylesheets if dirty. + for shadow_root in document.shadow_roots() { + shadow_root.flush_stylesheets(&device, document.quirks_mode(), guards.author.clone()); + } + let restyles = document.drain_pending_restyles(); debug!("Draining restyles: {}", restyles.len()); diff --git a/components/script/dom/cssstyledeclaration.rs b/components/script/dom/cssstyledeclaration.rs index 5cc2f64af11..bbb788cceeb 100644 --- a/components/script/dom/cssstyledeclaration.rs +++ b/components/script/dom/cssstyledeclaration.rs @@ -13,7 +13,7 @@ use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::bindings::str::DOMString; use crate::dom::cssrule::CSSRule; use crate::dom::element::Element; -use crate::dom::node::{document_from_node, window_from_node, Node}; +use crate::dom::node::{document_from_node, shadow_root_from_node, window_from_node, Node}; use crate::dom::window::Window; use dom_struct::dom_struct; use servo_arc::Arc; @@ -115,10 +115,16 @@ impl CSSStyleOwner { if changed { // If this is changed, see also // CSSStyleRule::SetSelectorText, which does the same thing. - rule.global() - .as_window() - .Document() - .invalidate_stylesheets(); + if let Some(shadow_root) = + shadow_root_from_node(rule.parent_stylesheet().owner().upcast::()) + { + shadow_root.invalidate_stylesheets(); + } else { + rule.global() + .as_window() + .Document() + .invalidate_stylesheets(); + } } result }, diff --git a/components/script/dom/cssstylerule.rs b/components/script/dom/cssstylerule.rs index c76e3bdd938..173661eb30a 100644 --- a/components/script/dom/cssstylerule.rs +++ b/components/script/dom/cssstylerule.rs @@ -11,6 +11,7 @@ use crate::dom::bindings::str::DOMString; use crate::dom::cssrule::{CSSRule, SpecificCSSRule}; use crate::dom::cssstyledeclaration::{CSSModificationAccess, CSSStyleDeclaration, CSSStyleOwner}; use crate::dom::cssstylesheet::CSSStyleSheet; +use crate::dom::node::{shadow_root_from_node, Node}; use crate::dom::window::Window; use cssparser::ToCss; use cssparser::{Parser as CssParser, ParserInput as CssParserInput}; @@ -118,12 +119,18 @@ impl CSSStyleRuleMethods for CSSStyleRule { let mut guard = self.cssrule.shared_lock().write(); let stylerule = self.stylerule.write_with(&mut guard); mem::swap(&mut stylerule.selectors, &mut s); - // It seems like we will want to avoid having to invalidate all - // stylesheets eventually! - self.global() - .as_window() - .Document() - .invalidate_stylesheets(); + if let Some(shadow_root) = + shadow_root_from_node(self.cssrule.parent_stylesheet().owner().upcast::()) + { + shadow_root.invalidate_stylesheets(); + } else { + // It seems like we will want to avoid having to invalidate all + // stylesheets eventually! + self.global() + .as_window() + .Document() + .invalidate_stylesheets(); + } } } } diff --git a/components/script/dom/cssstylesheet.rs b/components/script/dom/cssstylesheet.rs index 2def47d7aaa..9863dede5cb 100644 --- a/components/script/dom/cssstylesheet.rs +++ b/components/script/dom/cssstylesheet.rs @@ -6,11 +6,13 @@ use crate::dom::bindings::codegen::Bindings::CSSStyleSheetBinding; use crate::dom::bindings::codegen::Bindings::CSSStyleSheetBinding::CSSStyleSheetMethods; use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods; use crate::dom::bindings::error::{Error, ErrorResult, Fallible}; +use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::reflector::{reflect_dom_object, DomObject}; use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom}; use crate::dom::bindings::str::DOMString; use crate::dom::cssrulelist::{CSSRuleList, RulesSource}; use crate::dom::element::Element; +use crate::dom::node::{shadow_root_from_node, Node}; use crate::dom::stylesheet::StyleSheet; use crate::dom::window::Window; use dom_struct::dom_struct; @@ -64,6 +66,10 @@ impl CSSStyleSheet { ) } + pub fn owner(&self) -> DomRoot { + DomRoot::from_ref(&*self.owner) + } + fn rulelist(&self) -> DomRoot { self.rulelist.or_init(|| { let rules = self.style_stylesheet.contents.rules.clone(); @@ -81,10 +87,14 @@ impl CSSStyleSheet { pub fn set_disabled(&self, disabled: bool) { if self.style_stylesheet.set_disabled(disabled) { - self.global() - .as_window() - .Document() - .invalidate_stylesheets(); + if let Some(shadow_root) = shadow_root_from_node(self.owner.upcast::()) { + shadow_root.invalidate_stylesheets(); + } else { + self.global() + .as_window() + .Document() + .invalidate_stylesheets(); + } } } diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 3f1bf1c450a..f1ddfc9f378 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -2430,6 +2430,7 @@ pub trait LayoutDocumentHelpers { unsafe fn will_paint(&self); unsafe fn quirks_mode(&self) -> QuirksMode; unsafe fn style_shared_lock(&self) -> &StyleSharedRwLock; + unsafe fn shadow_roots(&self) -> Vec>; } #[allow(unsafe_code)] @@ -2474,6 +2475,16 @@ impl LayoutDocumentHelpers for LayoutDom { unsafe fn style_shared_lock(&self) -> &StyleSharedRwLock { (*self.unsafe_get()).style_shared_lock() } + + #[inline] + unsafe fn shadow_roots(&self) -> Vec> { + (*self.unsafe_get()) + .shadow_roots + .borrow_for_layout() + .iter() + .map(|sr| sr.to_layout()) + .collect() + } } // https://html.spec.whatwg.org/multipage/#is-a-registrable-domain-suffix-of-or-is-equal-to diff --git a/components/script/dom/shadowroot.rs b/components/script/dom/shadowroot.rs index 7f06b486b1d..aad85d4d087 100644 --- a/components/script/dom/shadowroot.rs +++ b/components/script/dom/shadowroot.rs @@ -14,13 +14,15 @@ use crate::dom::document::Document; use crate::dom::documentfragment::DocumentFragment; use crate::dom::documentorshadowroot::{DocumentOrShadowRoot, StyleSheetInDocument}; use crate::dom::element::Element; -use crate::dom::node::{Node, NodeFlags}; +use crate::dom::node::{Node, NodeDamage, NodeFlags}; use crate::dom::stylesheetlist::{StyleSheetList, StyleSheetListOwner}; use crate::dom::window::Window; use dom_struct::dom_struct; +use selectors::context::QuirksMode; use servo_arc::Arc; use style::author_styles::AuthorStyles; use style::dom::TElement; +use style::media_queries::Device; use style::shared_lock::SharedRwLockReadGuard; use style::stylesheets::Stylesheet; @@ -67,6 +69,14 @@ impl ShadowRoot { //XXX get retargeted focused element None } + + pub fn invalidate_stylesheets(&self) { + self.author_styles.borrow_mut().stylesheets.force_dirty(); + // Mark the host element dirty so a reflow will be performed. + self.host + .upcast::() + .dirty(NodeDamage::NodeStyleDamaged); + } } impl ShadowRootMethods for ShadowRoot { @@ -123,7 +133,12 @@ pub trait LayoutShadowRootHelpers { unsafe fn get_style_data_for_layout<'a, E: TElement>( &self, ) -> &'a AuthorStyles; - unsafe fn flush_stylesheets(&self, guard: &SharedRwLockReadGuard); + unsafe fn flush_stylesheets( + &self, + device: &Device, + quirks_mode: QuirksMode, + guard: &SharedRwLockReadGuard, + ); } impl LayoutShadowRootHelpers for LayoutDom { @@ -143,10 +158,16 @@ impl LayoutShadowRootHelpers for LayoutDom { #[inline] #[allow(unsafe_code)] - unsafe fn flush_stylesheets(&self, guard: &SharedRwLockReadGuard) { - let document = &(*self.unsafe_get()).document; + unsafe fn flush_stylesheets( + &self, + device: &Device, + quirks_mode: QuirksMode, + guard: &SharedRwLockReadGuard, + ) { let mut author_styles = (*self.unsafe_get()).author_styles.borrow_mut_for_layout(); - author_styles.flush::(&document.device(), document.quirks_mode(), guard); + if author_styles.stylesheets.dirty() { + author_styles.flush::(device, quirks_mode, guard); + } } } diff --git a/components/script/stylesheet_loader.rs b/components/script/stylesheet_loader.rs index 61c89b35f80..3c75bfef520 100644 --- a/components/script/stylesheet_loader.rs +++ b/components/script/stylesheet_loader.rs @@ -13,8 +13,9 @@ use crate::dom::eventtarget::EventTarget; use crate::dom::globalscope::GlobalScope; use crate::dom::htmlelement::HTMLElement; use crate::dom::htmllinkelement::{HTMLLinkElement, RequestGenerationId}; -use crate::dom::node::{document_from_node, window_from_node}; +use crate::dom::node::{document_from_node, shadow_root_from_node, window_from_node}; use crate::dom::performanceresourcetiming::InitiatorType; +use crate::dom::shadowroot::ShadowRoot; use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener}; use cssparser::SourceLocation; use encoding_rs::UTF_8; @@ -81,6 +82,7 @@ pub struct StylesheetContext { data: Vec, /// The node document for elem when the load was initiated. document: Trusted, + shadow_root: Option>, origin_clean: bool, /// A token which must match the generation id of the `HTMLLinkElement` for it to load the stylesheet. /// This is ignored for `HTMLStyleElement` and imports. @@ -187,7 +189,11 @@ impl FetchResponseListener for StylesheetContext { }, } - document.invalidate_stylesheets(); + if let Some(ref shadow_root) = self.shadow_root { + shadow_root.root().invalidate_stylesheets(); + } else { + document.invalidate_stylesheets(); + } // FIXME: Revisit once consensus is reached at: // https://github.com/whatwg/html/issues/1142 @@ -264,6 +270,7 @@ impl<'a> StylesheetLoader<'a> { integrity_metadata: String, ) { let document = document_from_node(self.elem); + let shadow_root = shadow_root_from_node(self.elem).map(|sr| Trusted::new(&*sr)); let gen = self .elem .downcast::() @@ -275,6 +282,7 @@ impl<'a> StylesheetLoader<'a> { metadata: None, data: vec![], document: Trusted::new(&*document), + shadow_root, origin_clean: true, request_generation_id: gen, resource_timing: ResourceFetchTiming::new(ResourceTimingType::Resource), From 47872cdaa38792f0bb04fe368e8463924fd3284a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Wed, 13 Feb 2019 18:22:20 +0100 Subject: [PATCH 31/83] Do not add shadow tree styles to stylist --- components/script/dom/document.rs | 9 +++++++++ components/script/dom/documentorshadowroot.rs | 8 -------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index f1ddfc9f378..c58313f6ee0 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -4603,6 +4603,15 @@ impl StyleSheetListOwner for Dom { .is_before(sheet_in_doc.owner.upcast()) }) .cloned(); + + self.window + .layout_chan() + .send(Msg::AddStylesheet( + sheet.clone(), + insertion_point.as_ref().map(|s| s.sheet.clone()), + )) + .unwrap(); + self.document_or_shadow_root.add_stylesheet( owner, stylesheets, diff --git a/components/script/dom/documentorshadowroot.rs b/components/script/dom/documentorshadowroot.rs index 80b0e0022ba..70e49ca5ad5 100644 --- a/components/script/dom/documentorshadowroot.rs +++ b/components/script/dom/documentorshadowroot.rs @@ -253,14 +253,6 @@ impl DocumentOrShadowRoot { "Wat" ); - self.window - .layout_chan() - .send(Msg::AddStylesheet( - sheet.clone(), - insertion_point.as_ref().map(|s| s.sheet.clone()), - )) - .unwrap(); - let sheet = StyleSheetInDocument { sheet, owner: Dom::from_ref(owner), From 8641866a505733686e24d588ae8d5c9e86e2bcfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Thu, 14 Feb 2019 15:47:02 +0100 Subject: [PATCH 32/83] Fix Document.Element(s)FromPoint --- components/script/dom/documentorshadowroot.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/script/dom/documentorshadowroot.rs b/components/script/dom/documentorshadowroot.rs index 70e49ca5ad5..eda3432dc5a 100644 --- a/components/script/dom/documentorshadowroot.rs +++ b/components/script/dom/documentorshadowroot.rs @@ -115,7 +115,7 @@ impl DocumentOrShadowRoot { let point = &Point2D::new(x, y); let viewport = self.window.window_size().initial_viewport; - if has_browsing_context { + if !has_browsing_context { return None; } From 07e2f41c34d6676afd2a510cef9ea74b0fde576e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Thu, 14 Feb 2019 18:19:06 +0100 Subject: [PATCH 33/83] Retarget result of shadowRoot.element(s)FromPoint --- components/script/dom/documentorshadowroot.rs | 2 +- components/script/dom/node.rs | 6 ++-- components/script/dom/shadowroot.rs | 32 +++++++++++++++---- 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/components/script/dom/documentorshadowroot.rs b/components/script/dom/documentorshadowroot.rs index eda3432dc5a..51846baa443 100644 --- a/components/script/dom/documentorshadowroot.rs +++ b/components/script/dom/documentorshadowroot.rs @@ -155,7 +155,7 @@ impl DocumentOrShadowRoot { let point = &Point2D::new(x, y); let viewport = self.window.window_size().initial_viewport; - if has_browsing_context { + if !has_browsing_context { return vec![]; } diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index e1a40c13982..7f8c2b611ce 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -1123,14 +1123,16 @@ impl Node { } /// https://dom.spec.whatwg.org/#retarget - pub fn retarget(&self, a: &Node, b: &Node) -> DomRoot { - let mut a = DomRoot::from_ref(&*a); + pub fn retarget(&self, b: &Node) -> DomRoot { + let mut a = DomRoot::from_ref(&*self); loop { + // Step 1. let a_root = a.GetRootNode(&GetRootNodeOptions::empty()); if !a_root.is::() || a_root.is_shadow_including_inclusive_ancestor_of(b) { return DomRoot::from_ref(&a); } + // Step 2. a = DomRoot::from_ref( a_root .downcast::() diff --git a/components/script/dom/shadowroot.rs b/components/script/dom/shadowroot.rs index aad85d4d087..a5d67ea30cc 100644 --- a/components/script/dom/shadowroot.rs +++ b/components/script/dom/shadowroot.rs @@ -88,26 +88,44 @@ impl ShadowRootMethods for ShadowRoot { // https://drafts.csswg.org/cssom-view/#dom-document-elementfrompoint fn ElementFromPoint(&self, x: Finite, y: Finite) -> Option> { - // 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( + // Return the result of running the retargeting algorithm with context object + // and the original result as input. + match self.document_or_shadow_root.element_from_point( x, y, None, self.document.has_browsing_context(), - ) + ) { + Some(e) => { + let retargeted_node = self.upcast::().retarget(e.upcast::()); + retargeted_node + .downcast::() + .map(|n| DomRoot::from_ref(n)) + }, + None => None, + } } // https://drafts.csswg.org/cssom-view/#dom-document-elementsfrompoint fn ElementsFromPoint(&self, x: Finite, y: Finite) -> Vec> { - // XXX return the result of running the retargeting algorithm with context object + // 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( + let mut elements = Vec::new(); + for e in self.document_or_shadow_root.elements_from_point( x, y, None, self.document.has_browsing_context(), - ) + ).iter() { + let retargeted_node = self.upcast::().retarget(e.upcast::()); + if let Some(element) = retargeted_node + .downcast::() + .map(|n| DomRoot::from_ref(n)) { + elements.push(element); + } + } + elements + } /// https://dom.spec.whatwg.org/#dom-shadowroot-mode From efce2825b942926546da50f79402738d8a7a3b07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Mon, 18 Feb 2019 17:49:52 +0100 Subject: [PATCH 34/83] Return composed parent node. Fixes style sharing panics --- components/script/dom/node.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 7f8c2b611ce..24a50a8b4ad 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -1228,7 +1228,7 @@ impl LayoutNodeHelpers for LayoutDom { #[inline] #[allow(unsafe_code)] unsafe fn parent_node_ref(&self) -> Option> { - (*self.unsafe_get()).parent_node.get_inner_as_layout() + (*self.unsafe_get()).composed_parent_node.get_inner_as_layout() } #[inline] From f097233707d74582a96cdff632c167e1c0659fd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Mon, 18 Feb 2019 18:26:16 +0100 Subject: [PATCH 35/83] Update test expectations and whitelist ShadowRoot interface --- tests/wpt/metadata/dom/interfaces.html.ini | 24 ------------------- .../wpt/mozilla/tests/mozilla/interfaces.html | 1 + 2 files changed, 1 insertion(+), 24 deletions(-) diff --git a/tests/wpt/metadata/dom/interfaces.html.ini b/tests/wpt/metadata/dom/interfaces.html.ini index 3fb70edaaca..5586cd6a5b9 100644 --- a/tests/wpt/metadata/dom/interfaces.html.ini +++ b/tests/wpt/metadata/dom/interfaces.html.ini @@ -998,30 +998,6 @@ [Unscopable handled correctly for append([object Object\],[object Object\]) on DocumentFragment] expected: FAIL - [ShadowRoot interface: existence and properties of interface object] - expected: FAIL - - [ShadowRoot interface object length] - expected: FAIL - - [ShadowRoot interface object name] - expected: FAIL - - [ShadowRoot interface: existence and properties of interface prototype object] - expected: FAIL - - [ShadowRoot interface: existence and properties of interface prototype object's "constructor" property] - expected: FAIL - - [ShadowRoot interface: existence and properties of interface prototype object's @@unscopables property] - expected: FAIL - - [ShadowRoot interface: attribute mode] - expected: FAIL - - [ShadowRoot interface: attribute host] - expected: FAIL - [Element interface: existence and properties of interface prototype object's @@unscopables property] expected: FAIL diff --git a/tests/wpt/mozilla/tests/mozilla/interfaces.html b/tests/wpt/mozilla/tests/mozilla/interfaces.html index a2b9fd23948..c7e1929c626 100644 --- a/tests/wpt/mozilla/tests/mozilla/interfaces.html +++ b/tests/wpt/mozilla/tests/mozilla/interfaces.html @@ -202,6 +202,7 @@ test_interfaces([ "Request", "Response", "Screen", + "ShadowRoot", "Storage", "StorageEvent", "StyleSheet", From 067acdfd27da2f04c580664d48e1460c28e62ec9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Tue, 19 Feb 2019 07:52:45 +0100 Subject: [PATCH 36/83] Update size of tests with shadow root size --- tests/unit/script/size_of.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/unit/script/size_of.rs b/tests/unit/script/size_of.rs index 4d56b2ab10b..ddb73791854 100644 --- a/tests/unit/script/size_of.rs +++ b/tests/unit/script/size_of.rs @@ -30,10 +30,10 @@ macro_rules! sizeof_checker ( // Update the sizes here sizeof_checker!(size_event_target, EventTarget, 56); -sizeof_checker!(size_node, Node, 200); -sizeof_checker!(size_element, Element, 448); -sizeof_checker!(size_htmlelement, HTMLElement, 464); -sizeof_checker!(size_div, HTMLDivElement, 464); -sizeof_checker!(size_span, HTMLSpanElement, 464); -sizeof_checker!(size_text, Text, 232); -sizeof_checker!(size_characterdata, CharacterData, 232); +sizeof_checker!(size_node, Node, 216); +sizeof_checker!(size_element, Element, 472); +sizeof_checker!(size_htmlelement, HTMLElement, 488); +sizeof_checker!(size_div, HTMLDivElement, 488); +sizeof_checker!(size_span, HTMLSpanElement, 488); +sizeof_checker!(size_text, Text, 248); +sizeof_checker!(size_characterdata, CharacterData, 248); From 2515966db6f780d9df4c722e213480b2261e1520 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Tue, 19 Feb 2019 07:53:55 +0100 Subject: [PATCH 37/83] Fix formatting issues --- components/script/dom/node.rs | 4 +++- components/script/dom/shadowroot.rs | 15 +++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 24a50a8b4ad..f45394d19de 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -1228,7 +1228,9 @@ impl LayoutNodeHelpers for LayoutDom { #[inline] #[allow(unsafe_code)] unsafe fn parent_node_ref(&self) -> Option> { - (*self.unsafe_get()).composed_parent_node.get_inner_as_layout() + (*self.unsafe_get()) + .composed_parent_node + .get_inner_as_layout() } #[inline] diff --git a/components/script/dom/shadowroot.rs b/components/script/dom/shadowroot.rs index a5d67ea30cc..7f8d0de22f2 100644 --- a/components/script/dom/shadowroot.rs +++ b/components/script/dom/shadowroot.rs @@ -111,21 +111,20 @@ impl ShadowRootMethods for ShadowRoot { // Return the result of running the retargeting algorithm with context object // and the original result as input let mut elements = Vec::new(); - for e in self.document_or_shadow_root.elements_from_point( - x, - y, - None, - self.document.has_browsing_context(), - ).iter() { + for e in self + .document_or_shadow_root + .elements_from_point(x, y, None, self.document.has_browsing_context()) + .iter() + { let retargeted_node = self.upcast::().retarget(e.upcast::()); if let Some(element) = retargeted_node .downcast::() - .map(|n| DomRoot::from_ref(n)) { + .map(|n| DomRoot::from_ref(n)) + { elements.push(element); } } elements - } /// https://dom.spec.whatwg.org/#dom-shadowroot-mode From 0d2f65baea8e859af9154aed690e6ff568efa959 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Tue, 19 Feb 2019 12:21:30 +0100 Subject: [PATCH 38/83] Shadow DOM layout and style reftest --- tests/wpt/mozilla/meta/MANIFEST.json | 27 ++++++++++++++++++- .../partial_shadow_dom_layout_style.html.ini | 2 ++ .../partial_shadow_dom_layout_style.html | 22 +++++++++++++++ .../partial_shadow_dom_layout_style_ref.html | 11 ++++++++ 4 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 tests/wpt/mozilla/meta/mozilla/partial_shadow_dom_layout_style.html.ini create mode 100644 tests/wpt/mozilla/tests/mozilla/partial_shadow_dom_layout_style.html create mode 100644 tests/wpt/mozilla/tests/mozilla/partial_shadow_dom_layout_style_ref.html diff --git a/tests/wpt/mozilla/meta/MANIFEST.json b/tests/wpt/mozilla/meta/MANIFEST.json index f556de3c784..eaaf5ea3c94 100644 --- a/tests/wpt/mozilla/meta/MANIFEST.json +++ b/tests/wpt/mozilla/meta/MANIFEST.json @@ -7301,6 +7301,18 @@ {} ] ], + "mozilla/partial_shadow_dom_layout_style.html": [ + [ + "mozilla/partial_shadow_dom_layout_style.html", + [ + [ + "/_mozilla/mozilla/partial_shadow_dom_layout_style_ref.html", + "==" + ] + ], + {} + ] + ], "mozilla/remove_link_styles.html": [ [ "mozilla/remove_link_styles.html", @@ -10844,6 +10856,11 @@ {} ] ], + "mozilla/partial_shadow_dom_layout_style_ref.html": [ + [ + {} + ] + ], "mozilla/poster.png": [ [ {} @@ -20289,7 +20306,7 @@ "testharness" ], "mozilla/interfaces.html": [ - "a2b9fd23948319fabc0b5fff550b9565704b6678", + "c7e1929c626007e2ef3cdf9f2276620aa995c5b7", "testharness" ], "mozilla/interfaces.js": [ @@ -20440,6 +20457,14 @@ "d97f1422d20161e989f200d44be6e379f79410bd", "testharness" ], + "mozilla/partial_shadow_dom_layout_style.html": [ + "822e86bc07103351a5ceb2203fd9b6bee0c6367d", + "reftest" + ], + "mozilla/partial_shadow_dom_layout_style_ref.html": [ + "bf40d2cc35b6b2c1e32afffa0651cb1b26e41fe8", + "support" + ], "mozilla/poster.png": [ "33834c3ef095fa9c0080017e1b65b2eb8413eac4", "support" diff --git a/tests/wpt/mozilla/meta/mozilla/partial_shadow_dom_layout_style.html.ini b/tests/wpt/mozilla/meta/mozilla/partial_shadow_dom_layout_style.html.ini new file mode 100644 index 00000000000..6612e2fb467 --- /dev/null +++ b/tests/wpt/mozilla/meta/mozilla/partial_shadow_dom_layout_style.html.ini @@ -0,0 +1,2 @@ +[partial_shadow_dom_layout_style.html] + prefs: [dom.shadowdom.enabled:true] diff --git a/tests/wpt/mozilla/tests/mozilla/partial_shadow_dom_layout_style.html b/tests/wpt/mozilla/tests/mozilla/partial_shadow_dom_layout_style.html new file mode 100644 index 00000000000..822e86bc071 --- /dev/null +++ b/tests/wpt/mozilla/tests/mozilla/partial_shadow_dom_layout_style.html @@ -0,0 +1,22 @@ + + + + Partial Shadow DOM support - layout & style + + +

Not in the shadows

+
+
+ + diff --git a/tests/wpt/mozilla/tests/mozilla/partial_shadow_dom_layout_style_ref.html b/tests/wpt/mozilla/tests/mozilla/partial_shadow_dom_layout_style_ref.html new file mode 100644 index 00000000000..bf40d2cc35b --- /dev/null +++ b/tests/wpt/mozilla/tests/mozilla/partial_shadow_dom_layout_style_ref.html @@ -0,0 +1,11 @@ + + +Partial Shadow DOM support - layout & style + +

Not in the shadows

+
+

In the shadows

+
From e66438de48c61c1c23e92b2e77945e05a524e741 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Tue, 19 Feb 2019 18:19:36 +0100 Subject: [PATCH 39/83] Fix the way the IS_CONNECTED flag is set --- components/script/dom/element.rs | 9 ++------- components/script/dom/node.rs | 16 +++++++--------- components/script/dom/shadowroot.rs | 4 ++++ 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 7a69d4c781f..313ca6111a3 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -14,7 +14,7 @@ use crate::dom::bindings::codegen::Bindings::ElementBinding::ElementMethods; use crate::dom::bindings::codegen::Bindings::EventBinding::EventMethods; use crate::dom::bindings::codegen::Bindings::FunctionBinding::Function; use crate::dom::bindings::codegen::Bindings::HTMLTemplateElementBinding::HTMLTemplateElementMethods; -use crate::dom::bindings::codegen::Bindings::NodeBinding::{GetRootNodeOptions, NodeMethods}; +use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::ShadowRootBinding::ShadowRootMethods; use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; use crate::dom::bindings::codegen::Bindings::WindowBinding::{ScrollBehavior, ScrollToOptions}; @@ -2826,7 +2826,6 @@ impl VirtualMethods for Element { let shadow_root = self.shadow_root.get().unwrap(); doc.unregister_shadow_root(&shadow_root); let shadow_root = shadow_root.upcast::(); - let shadow_root = shadow_root.upcast::(); shadow_root.set_flag(NodeFlags::IS_CONNECTED, false); for node in shadow_root.children() { node.set_flag(NodeFlags::IS_CONNECTED, false); @@ -3333,11 +3332,7 @@ impl Element { /// pub fn is_connected(&self) -> bool { - let node = self.upcast::(); - let mut options = GetRootNodeOptions::empty(); - options.composed = true; // shadow included. - let root = node.GetRootNode(&options); - root.is::() + self.upcast::().is_connected() } // https://html.spec.whatwg.org/multipage/#cannot-navigate diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index f45394d19de..79d838c5292 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -292,6 +292,7 @@ impl Node { let parent_in_doc = self.is_in_doc(); let parent_in_shadow_tree = self.is_in_shadow_tree(); let parent_is_connected = self.is_connected(); + for node in new_child.traverse_preorder(/* shadow including */ false) { if parent_in_shadow_tree { if let Some(shadow_root) = self.downcast::() { @@ -300,18 +301,12 @@ impl Node { node.set_owner_shadow_root(&*shadow_root); } } - let mut is_connected = parent_is_connected; - if !is_connected { - if let Some(element) = node.downcast::() { - is_connected = element.is_connected(); - } - } node.set_flag(NodeFlags::IS_IN_DOC, parent_in_doc); node.set_flag(NodeFlags::IS_IN_SHADOW_TREE, parent_in_shadow_tree); - node.set_flag(NodeFlags::IS_CONNECTED, is_connected); + node.set_flag(NodeFlags::IS_CONNECTED, parent_is_connected); // Out-of-document elements never have the descendants flag set. debug_assert!(!node.get_flag(NodeFlags::HAS_DIRTY_DESCENDANTS)); - vtable_for(&&*node).bind_to_tree(is_connected); + vtable_for(&&*node).bind_to_tree(parent_is_connected); } } @@ -1614,7 +1609,10 @@ impl Node { #[allow(unrooted_must_root)] pub fn new_document_node() -> Node { - Node::new_(NodeFlags::new() | NodeFlags::IS_IN_DOC, None) + Node::new_( + NodeFlags::new() | NodeFlags::IS_IN_DOC | NodeFlags::IS_CONNECTED, + None, + ) } #[allow(unrooted_must_root)] diff --git a/components/script/dom/shadowroot.rs b/components/script/dom/shadowroot.rs index 7f8d0de22f2..b562172dd05 100644 --- a/components/script/dom/shadowroot.rs +++ b/components/script/dom/shadowroot.rs @@ -46,6 +46,10 @@ impl ShadowRoot { document_fragment .upcast::() .set_flag(NodeFlags::IS_IN_SHADOW_TREE, true); + document_fragment.upcast::().set_flag( + NodeFlags::IS_CONNECTED, + host.upcast::().is_connected(), + ); ShadowRoot { document_fragment, document_or_shadow_root: DocumentOrShadowRoot::new(document.window()), From d7b6a6f509995eaaa2d44b6c5522f758f3a2925b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Tue, 19 Feb 2019 19:00:29 +0100 Subject: [PATCH 40/83] Do not set dirty out-of-doc nodes --- components/layout_thread/dom_wrapper.rs | 6 +++++- components/script/dom/document.rs | 2 +- components/script/dom/node.rs | 2 +- components/style/dom.rs | 3 +++ components/style/gecko/wrapper.rs | 5 +++++ 5 files changed, 15 insertions(+), 3 deletions(-) diff --git a/components/layout_thread/dom_wrapper.rs b/components/layout_thread/dom_wrapper.rs index 1aa9488c327..0558d648eb8 100644 --- a/components/layout_thread/dom_wrapper.rs +++ b/components/layout_thread/dom_wrapper.rs @@ -313,6 +313,10 @@ impl<'ln> TNode for ServoLayoutNode<'ln> { self.node.downcast().map(ServoShadowRoot::from_layout_js) } + fn is_in_document(&self) -> bool { + unsafe { self.node.get_flag(NodeFlags::IS_IN_DOC) } + } + fn is_connected(&self) -> bool { unsafe { self.node.get_flag(NodeFlags::IS_CONNECTED) } } @@ -555,7 +559,7 @@ impl<'le> TElement for ServoLayoutElement<'le> { } unsafe fn set_dirty_descendants(&self) { - debug_assert!(self.as_node().is_connected()); + debug_assert!(self.as_node().is_in_document()); self.as_node() .node .set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true) diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index c58313f6ee0..0d25b535593 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -644,7 +644,7 @@ impl Document { } pub fn content_and_heritage_changed(&self, node: &Node) { - if node.is_connected() { + if node.is_in_doc() { node.note_dirty_descendants(); } diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 79d838c5292..a93389638fe 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -568,7 +568,7 @@ impl Node { // FIXME(emilio): This and the function below should move to Element. pub fn note_dirty_descendants(&self) { - debug_assert!(self.is_connected()); + debug_assert!(self.is_in_doc()); for ancestor in self.shadow_including_inclusive_ancestors() { if ancestor.get_flag(NodeFlags::HAS_DIRTY_DESCENDANTS) { diff --git a/components/style/dom.rs b/components/style/dom.rs index d282ceeafad..541ef4dbcdc 100644 --- a/components/style/dom.rs +++ b/components/style/dom.rs @@ -185,6 +185,9 @@ pub trait TNode: Sized + Copy + Clone + Debug + NodeInfo + PartialEq { DomChildren(self.first_child()) } + /// Returns whether the node is attached to a document. + fn is_in_document(&self) -> bool; + /// Returns whether the node is connected. fn is_connected(&self) -> bool; diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs index 0fa354fb139..e8e5078c53a 100644 --- a/components/style/gecko/wrapper.rs +++ b/components/style/gecko/wrapper.rs @@ -421,6 +421,11 @@ impl<'ln> TNode for GeckoNode<'ln> { self.get_bool_flag(nsINode_BooleanFlag::IsInDocument) } + #[inline] + fn is_connected(&self) -> bool { + self.get_bool_flag(nsINode_BooleanFlag::IsConnected) + } + fn traversal_parent(&self) -> Option> { self.flattened_tree_parent().and_then(|n| n.as_element()) } From 39c96acbbe2188e75eecb45cd4068fa9747e6875 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Wed, 20 Feb 2019 10:57:50 +0100 Subject: [PATCH 41/83] Remove IS_CONNECTED flag when node is removed from the doc --- components/script/dom/node.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index a93389638fe..86d952146a4 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -355,6 +355,7 @@ impl Node { // Out-of-document elements never have the descendants flag set. node.set_flag( NodeFlags::IS_IN_DOC | + NodeFlags::IS_CONNECTED | NodeFlags::HAS_DIRTY_DESCENDANTS | NodeFlags::HAS_SNAPSHOT | NodeFlags::HANDLED_SNAPSHOT, From 57fa6b1c51ce759535c648c655c80161eb72ac05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Wed, 20 Feb 2019 12:51:12 +0100 Subject: [PATCH 42/83] Update expectations for cssom tests --- tests/wpt/metadata/css/cssom/interfaces.html.ini | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/wpt/metadata/css/cssom/interfaces.html.ini b/tests/wpt/metadata/css/cssom/interfaces.html.ini index d6a28f8765b..8ff4227d3c3 100644 --- a/tests/wpt/metadata/css/cssom/interfaces.html.ini +++ b/tests/wpt/metadata/css/cssom/interfaces.html.ini @@ -1272,6 +1272,3 @@ [CSSStyleDeclaration interface: sheet.cssRules[2\].cssRules[0\].style must inherit property "cssFloat" with the proper type] expected: FAIL - [ShadowRoot interface: attribute styleSheets] - expected: FAIL - From 00178aff4d75e33cf40820637e8d5644b63e2476 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Wed, 20 Feb 2019 16:25:36 +0100 Subject: [PATCH 43/83] Derive PartialEq for ServoShadowRoot --- components/layout_thread/dom_wrapper.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/components/layout_thread/dom_wrapper.rs b/components/layout_thread/dom_wrapper.rs index 0558d648eb8..390dba09f06 100644 --- a/components/layout_thread/dom_wrapper.rs +++ b/components/layout_thread/dom_wrapper.rs @@ -166,7 +166,7 @@ impl<'ln> NodeInfo for ServoLayoutNode<'ln> { } } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, PartialEq)] pub struct ServoShadowRoot<'a> { /// The wrapped shadow root. shadow_root: LayoutDom, @@ -181,13 +181,6 @@ impl<'sr> Debug for ServoShadowRoot<'sr> { } } -impl<'a> PartialEq for ServoShadowRoot<'a> { - #[inline] - fn eq(&self, other: &ServoShadowRoot) -> bool { - self.shadow_root == other.shadow_root - } -} - impl<'sr> TShadowRoot for ServoShadowRoot<'sr> { type ConcreteNode = ServoLayoutNode<'sr>; From a841c713d653f57256e5b795197920c7ee6834e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Wed, 20 Feb 2019 16:30:38 +0100 Subject: [PATCH 44/83] Minor layout thread cleanups: - lifetime naming - unrequired reference removal - containing_shadow_host getter simplification - use stylist.device getter where possible --- components/layout_thread/dom_wrapper.rs | 20 ++++++++------------ components/layout_thread/lib.rs | 7 +++++-- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/components/layout_thread/dom_wrapper.rs b/components/layout_thread/dom_wrapper.rs index 390dba09f06..7ea68e6e3a2 100644 --- a/components/layout_thread/dom_wrapper.rs +++ b/components/layout_thread/dom_wrapper.rs @@ -175,20 +175,20 @@ pub struct ServoShadowRoot<'a> { chain: PhantomData<&'a ()>, } -impl<'sr> Debug for ServoShadowRoot<'sr> { +impl<'lr> Debug for ServoShadowRoot<'lr> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.as_node().fmt(f) } } -impl<'sr> TShadowRoot for ServoShadowRoot<'sr> { - type ConcreteNode = ServoLayoutNode<'sr>; +impl<'lr> TShadowRoot for ServoShadowRoot<'lr> { + type ConcreteNode = ServoLayoutNode<'lr>; fn as_node(&self) -> Self::ConcreteNode { ServoLayoutNode::from_layout_js(self.shadow_root.upcast()) } - fn host(&self) -> ServoLayoutElement<'sr> { + fn host(&self) -> ServoLayoutElement<'lr> { ServoLayoutElement::from_layout_js(unsafe { self.shadow_root.get_host_for_layout() }) } @@ -205,8 +205,8 @@ impl<'sr> TShadowRoot for ServoShadowRoot<'sr> { } } -impl<'sr> ServoShadowRoot<'sr> { - fn from_layout_js(shadow_root: LayoutDom) -> ServoShadowRoot<'sr> { +impl<'lr> ServoShadowRoot<'lr> { + fn from_layout_js(shadow_root: LayoutDom) -> ServoShadowRoot<'lr> { ServoShadowRoot { shadow_root, chain: PhantomData, @@ -220,8 +220,7 @@ impl<'sr> ServoShadowRoot<'sr> { guard: &SharedRwLockReadGuard, ) { unsafe { - &self - .shadow_root + self.shadow_root .flush_stylesheets::(device, quirks_mode, guard) }; } @@ -791,10 +790,7 @@ impl<'le> ::selectors::Element for ServoLayoutElement<'le> { } fn containing_shadow_host(&self) -> Option { - match self.containing_shadow() { - Some(shadow) => Some(shadow.host()), - None => None, - } + self.containing_shadow().map(|s| s.host()) } fn prev_sibling_element(&self) -> Option> { diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs index 8c46fb90720..3ed2624d2d3 100644 --- a/components/layout_thread/lib.rs +++ b/components/layout_thread/lib.rs @@ -1351,10 +1351,13 @@ impl LayoutThread { document.shadow_roots().len() ); - let device = Device::new(MediaType::screen(), initial_viewport, device_pixel_ratio); // Flush shadow roots stylesheets if dirty. for shadow_root in document.shadow_roots() { - shadow_root.flush_stylesheets(&device, document.quirks_mode(), guards.author.clone()); + shadow_root.flush_stylesheets( + &self.stylist.device(), + document.quirks_mode(), + guards.author.clone(), + ); } let restyles = document.drain_pending_restyles(); From 2674a3e71748eb0ef6db371fc2f1401a951b94c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Thu, 21 Feb 2019 12:34:59 +0100 Subject: [PATCH 45/83] Flush shadow roots stylesheets only if they changed --- components/layout_thread/dom_wrapper.rs | 17 ++++++++++++++ components/layout_thread/lib.rs | 12 ++++------ components/script/dom/document.rs | 31 +++++++++++++++++++++++++ components/script/dom/shadowroot.rs | 1 + 4 files changed, 54 insertions(+), 7 deletions(-) diff --git a/components/layout_thread/dom_wrapper.rs b/components/layout_thread/dom_wrapper.rs index 7ea68e6e3a2..72cbdf04701 100644 --- a/components/layout_thread/dom_wrapper.rs +++ b/components/layout_thread/dom_wrapper.rs @@ -437,6 +437,23 @@ impl<'ld> ServoLayoutDocument<'ld> { } } + pub fn flush_shadow_roots_stylesheets( + &self, + device: &Device, + quirks_mode: QuirksMode, + guard: &SharedRwLockReadGuard, + ) { + unsafe { + if !self.document.shadow_roots_styles_changed() { + return; + } + self.document.flush_shadow_roots_stylesheets(); + for shadow_root in self.shadow_roots() { + shadow_root.flush_stylesheets(device, quirks_mode, guard); + } + } + } + pub fn from_layout_js(doc: LayoutDom) -> ServoLayoutDocument<'ld> { ServoLayoutDocument { document: doc, diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs index 3ed2624d2d3..b44bbb54b96 100644 --- a/components/layout_thread/lib.rs +++ b/components/layout_thread/lib.rs @@ -1352,13 +1352,11 @@ impl LayoutThread { ); // Flush shadow roots stylesheets if dirty. - for shadow_root in document.shadow_roots() { - shadow_root.flush_stylesheets( - &self.stylist.device(), - document.quirks_mode(), - guards.author.clone(), - ); - } + document.flush_shadow_roots_stylesheets( + &self.stylist.device(), + document.quirks_mode(), + guards.author.clone(), + ); let restyles = document.drain_pending_restyles(); debug!("Draining restyles: {}", restyles.len()); diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 0d25b535593..3c02d76e7d0 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -379,6 +379,8 @@ pub struct Document { completely_loaded: Cell, /// List of shadow roots bound to the document tree. shadow_roots: DomRefCell>>, + /// Whether any of the shadow roots need the stylesheets flushed. + shadow_roots_styles_changed: Cell, } #[derive(JSTraceable, MallocSizeOf)] @@ -2431,6 +2433,8 @@ pub trait LayoutDocumentHelpers { unsafe fn quirks_mode(&self) -> QuirksMode; unsafe fn style_shared_lock(&self) -> &StyleSharedRwLock; unsafe fn shadow_roots(&self) -> Vec>; + unsafe fn shadow_roots_styles_changed(&self) -> bool; + unsafe fn flush_shadow_roots_stylesheets(&self); } #[allow(unsafe_code)] @@ -2485,6 +2489,16 @@ impl LayoutDocumentHelpers for LayoutDom { .map(|sr| sr.to_layout()) .collect() } + + #[inline] + unsafe fn shadow_roots_styles_changed(&self) -> bool { + (*self.unsafe_get()).shadow_roots_styles_changed() + } + + #[inline] + unsafe fn flush_shadow_roots_stylesheets(&self) { + (*self.unsafe_get()).flush_shadow_roots_stylesheets() + } } // https://html.spec.whatwg.org/multipage/#is-a-registrable-domain-suffix-of-or-is-equal-to @@ -2694,6 +2708,7 @@ impl Document { script_and_layout_blockers: Cell::new(0), delayed_tasks: Default::default(), shadow_roots: DomRefCell::new(Vec::new()), + shadow_roots_styles_changed: Cell::new(false), } } @@ -3151,6 +3166,7 @@ impl Document { self.shadow_roots .borrow_mut() .push(Dom::from_ref(shadow_root)); + self.invalidate_shadow_roots_stylesheets(); } pub fn unregister_shadow_root(&self, shadow_root: &ShadowRoot) { @@ -3160,6 +3176,21 @@ impl Document { shadow_roots.remove(index); } } + + pub fn invalidate_shadow_roots_stylesheets(&self) { + self.shadow_roots_styles_changed.set(true); + } + + pub fn shadow_roots_styles_changed(&self) -> bool { + self.shadow_roots_styles_changed.get() + } + + pub fn flush_shadow_roots_stylesheets(&self) { + if !self.shadow_roots_styles_changed.get() { + return; + } + self.shadow_roots_styles_changed.set(false); + } } impl Element { diff --git a/components/script/dom/shadowroot.rs b/components/script/dom/shadowroot.rs index b562172dd05..dd47187836e 100644 --- a/components/script/dom/shadowroot.rs +++ b/components/script/dom/shadowroot.rs @@ -75,6 +75,7 @@ impl ShadowRoot { } pub fn invalidate_stylesheets(&self) { + self.document.invalidate_shadow_roots_stylesheets(); self.author_styles.borrow_mut().stylesheets.force_dirty(); // Mark the host element dirty so a reflow will be performed. self.host From 3ccd622c9b94930ce43ca1bfb5d101783b367d58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Thu, 21 Feb 2019 13:19:01 +0100 Subject: [PATCH 46/83] Introduce ShadowIncluding enum for tree traversals --- components/script/devtools.rs | 4 +- .../script/dom/customelementregistry.rs | 4 +- components/script/dom/document.rs | 20 +++++----- components/script/dom/documentfragment.rs | 4 +- components/script/dom/htmlelement.rs | 4 +- components/script/dom/htmlfieldsetelement.rs | 4 +- components/script/dom/htmlformelement.rs | 5 ++- components/script/dom/htmlheadelement.rs | 4 +- components/script/dom/htmlimageelement.rs | 5 ++- components/script/dom/htmllabelelement.rs | 4 +- components/script/dom/htmlmapelement.rs | 4 +- components/script/dom/node.rs | 38 +++++++++++-------- components/script/dom/range.rs | 4 +- components/script/webdriver_handlers.rs | 4 +- 14 files changed, 58 insertions(+), 50 deletions(-) diff --git a/components/script/devtools.rs b/components/script/devtools.rs index 9494dbe41ac..9abeb5cf988 100644 --- a/components/script/devtools.rs +++ b/components/script/devtools.rs @@ -15,7 +15,7 @@ use crate::dom::bindings::str::DOMString; use crate::dom::document::AnimationFrameCallback; use crate::dom::element::Element; use crate::dom::globalscope::GlobalScope; -use crate::dom::node::{window_from_node, Node}; +use crate::dom::node::{window_from_node, Node, ShadowIncluding}; use crate::dom::window::Window; use crate::script_thread::Documents; use devtools_traits::TimelineMarkerType; @@ -103,7 +103,7 @@ fn find_node_by_unique_id( documents.find_document(pipeline).and_then(|document| { document .upcast::() - .traverse_preorder(/* shadow including */ false) + .traverse_preorder(ShadowIncluding::No) .find(|candidate| candidate.unique_id() == node_id) }) } diff --git a/components/script/dom/customelementregistry.rs b/components/script/dom/customelementregistry.rs index 411d5c7fb7b..ff109f3c966 100644 --- a/components/script/dom/customelementregistry.rs +++ b/components/script/dom/customelementregistry.rs @@ -26,7 +26,7 @@ use crate::dom::domexception::{DOMErrorName, DOMException}; use crate::dom::element::{CustomElementState, Element}; use crate::dom::globalscope::GlobalScope; use crate::dom::htmlelement::HTMLElement; -use crate::dom::node::{document_from_node, window_from_node, Node}; +use crate::dom::node::{document_from_node, window_from_node, Node, ShadowIncluding}; use crate::dom::promise::Promise; use crate::dom::window::Window; use crate::microtask::Microtask; @@ -364,7 +364,7 @@ impl CustomElementRegistryMethods for CustomElementRegistry { // Steps 14-15 for candidate in document .upcast::() - .traverse_preorder(/* shadow including */ true) + .traverse_preorder(ShadowIncluding::Yes) .filter_map(DomRoot::downcast::) { let is = candidate.get_is(); diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 3c02d76e7d0..72c25a8fa54 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -76,7 +76,7 @@ use crate::dom::messageevent::MessageEvent; use crate::dom::mouseevent::MouseEvent; use crate::dom::node::VecPreOrderInsertionHelper; use crate::dom::node::{self, document_from_node, window_from_node, CloneChildrenFlag}; -use crate::dom::node::{LayoutNodeHelpers, Node, NodeDamage, NodeFlags}; +use crate::dom::node::{LayoutNodeHelpers, Node, NodeDamage, NodeFlags, ShadowIncluding}; use crate::dom::nodeiterator::NodeIterator; use crate::dom::nodelist::NodeList; use crate::dom::pagetransitionevent::PageTransitionEvent; @@ -596,7 +596,7 @@ impl Document { pub fn refresh_base_element(&self) { let base = self .upcast::() - .traverse_preorder(/* shadow including */ false) + .traverse_preorder(ShadowIncluding::No) .filter_map(DomRoot::downcast::) .find(|element| { element @@ -834,7 +834,7 @@ impl Document { }; let doc_node = self.upcast::(); doc_node - .traverse_preorder(/* shadow including */ false) + .traverse_preorder(ShadowIncluding::No) .filter_map(DomRoot::downcast) .find(|node| check_anchor(&node)) .map(DomRoot::upcast) @@ -943,7 +943,7 @@ impl Document { pub fn dirty_all_nodes(&self) { let root = self.upcast::(); - for node in root.traverse_preorder(/* shadow including */ true) { + for node in root.traverse_preorder(ShadowIncluding::Yes) { node.dirty(NodeDamage::OtherNodeDamage) } } @@ -2238,7 +2238,7 @@ impl Document { /// Iterate over all iframes in the document. pub fn iter_iframes(&self) -> impl Iterator> { self.upcast::() - .traverse_preorder(/* shadow including */ true) + .traverse_preorder(ShadowIncluding::Yes) .filter_map(DomRoot::downcast::) } @@ -2827,7 +2827,7 @@ impl Document { let maybe_node = doc.deref().map(Castable::upcast::); let iter = maybe_node .iter() - .flat_map(|node| node.traverse_preorder(/* shadow including */ false)) + .flat_map(|node| node.traverse_preorder(ShadowIncluding::No)) .filter(|node| callback(&node)); NodeList::new_simple_list(&self.window, iter) } @@ -3726,7 +3726,7 @@ impl DocumentMethods for Document { } else { // Step 2. root.upcast::() - .traverse_preorder(/* shadow including */ false) + .traverse_preorder(ShadowIncluding::No) .find(|node| node.is::()) } }); @@ -3773,7 +3773,7 @@ impl DocumentMethods for Document { } else if root.namespace() == &ns!(html) { let elem = root .upcast::() - .traverse_preorder(/* shadow including */ false) + .traverse_preorder(ShadowIncluding::No) .find(|node| node.is::()); match elem { Some(elem) => elem, @@ -4140,7 +4140,7 @@ impl DocumentMethods for Document { { // Step 1. let mut elements = root - .traverse_preorder(/* shadow including */ false) + .traverse_preorder(ShadowIncluding::No) .filter(|node| filter_by_name(&name, &node)) .peekable(); if let Some(first) = elements.next() { @@ -4268,7 +4268,7 @@ impl DocumentMethods for Document { // Step 8 for node in self .upcast::() - .traverse_preorder(/* shadow including */ true) + .traverse_preorder(ShadowIncluding::Yes) { node.upcast::().remove_all_listeners(); } diff --git a/components/script/dom/documentfragment.rs b/components/script/dom/documentfragment.rs index ac9df62f59f..315e04f830d 100644 --- a/components/script/dom/documentfragment.rs +++ b/components/script/dom/documentfragment.rs @@ -13,7 +13,7 @@ use crate::dom::bindings::str::DOMString; use crate::dom::document::Document; use crate::dom::element::Element; use crate::dom::htmlcollection::HTMLCollection; -use crate::dom::node::{window_from_node, Node}; +use crate::dom::node::{window_from_node, Node, ShadowIncluding}; use crate::dom::nodelist::NodeList; use crate::dom::window::Window; use dom_struct::dom_struct; @@ -59,7 +59,7 @@ impl DocumentFragmentMethods for DocumentFragment { fn GetElementById(&self, id: DOMString) -> Option> { let node = self.upcast::(); let id = Atom::from(id); - node.traverse_preorder(/* shadow including */ false) + node.traverse_preorder(ShadowIncluding::No) .filter_map(DomRoot::downcast::) .find( |descendant| match descendant.get_attribute(&ns!(), &local_name!("id")) { diff --git a/components/script/dom/htmlelement.rs b/components/script/dom/htmlelement.rs index a9e75c531df..4bbbfd14cb7 100644 --- a/components/script/dom/htmlelement.rs +++ b/components/script/dom/htmlelement.rs @@ -28,7 +28,7 @@ use crate::dom::htmlhtmlelement::HTMLHtmlElement; use crate::dom::htmlinputelement::{HTMLInputElement, InputType}; use crate::dom::htmllabelelement::HTMLLabelElement; use crate::dom::node::{document_from_node, window_from_node}; -use crate::dom::node::{Node, NodeFlags}; +use crate::dom::node::{Node, NodeFlags, ShadowIncluding}; use crate::dom::nodelist::NodeList; use crate::dom::text::Text; use crate::dom::virtualmethods::VirtualMethods; @@ -707,7 +707,7 @@ impl HTMLElement { let root_element = element.root_element(); let root_node = root_element.upcast::(); let children = root_node - .traverse_preorder(/* shadow including */ false) + .traverse_preorder(ShadowIncluding::No) .filter_map(DomRoot::downcast::) .filter(|elem| elem.is::()) .filter(|elem| elem.get_string_attribute(&local_name!("for")) == id) diff --git a/components/script/dom/htmlfieldsetelement.rs b/components/script/dom/htmlfieldsetelement.rs index d90555db9f1..4f97f7e66c7 100644 --- a/components/script/dom/htmlfieldsetelement.rs +++ b/components/script/dom/htmlfieldsetelement.rs @@ -13,7 +13,7 @@ use crate::dom::htmlcollection::{CollectionFilter, HTMLCollection}; use crate::dom::htmlelement::HTMLElement; use crate::dom::htmlformelement::{FormControl, HTMLFormElement}; use crate::dom::htmllegendelement::HTMLLegendElement; -use crate::dom::node::{window_from_node, Node}; +use crate::dom::node::{window_from_node, Node, ShadowIncluding}; use crate::dom::validitystate::ValidityState; use crate::dom::virtualmethods::VirtualMethods; use dom_struct::dom_struct; @@ -128,7 +128,7 @@ impl VirtualMethods for HTMLFieldSetElement { }); let fields = children.flat_map(|child| { child - .traverse_preorder(/* shadow including */ false) + .traverse_preorder(ShadowIncluding::No) .filter(|descendant| match descendant.type_id() { NodeTypeId::Element(ElementTypeId::HTMLElement( HTMLElementTypeId::HTMLButtonElement, diff --git a/components/script/dom/htmlformelement.rs b/components/script/dom/htmlformelement.rs index 385389eb9d7..9e988515ac0 100755 --- a/components/script/dom/htmlformelement.rs +++ b/components/script/dom/htmlformelement.rs @@ -41,7 +41,8 @@ use crate::dom::htmloutputelement::HTMLOutputElement; use crate::dom::htmlselectelement::HTMLSelectElement; use crate::dom::htmltextareaelement::HTMLTextAreaElement; use crate::dom::node::{document_from_node, window_from_node}; -use crate::dom::node::{Node, NodeFlags, UnbindContext, VecPreOrderInsertionHelper}; +use crate::dom::node::{Node, NodeFlags, ShadowIncluding}; +use crate::dom::node::{UnbindContext, VecPreOrderInsertionHelper}; use crate::dom::validitystate::ValidationFlags; use crate::dom::virtualmethods::VirtualMethods; use crate::dom::window::Window; @@ -582,7 +583,7 @@ impl HTMLFormElement { // form, refactor this when html5ever's form owner PR lands // Step 1-3 let invalid_controls = node - .traverse_preorder(/* shadow including */ false) + .traverse_preorder(ShadowIncluding::No) .filter_map(|field| { if let Some(el) = field.downcast::() { if el.disabled_state() { diff --git a/components/script/dom/htmlheadelement.rs b/components/script/dom/htmlheadelement.rs index 3c356e279ed..0cea69dff5e 100644 --- a/components/script/dom/htmlheadelement.rs +++ b/components/script/dom/htmlheadelement.rs @@ -10,7 +10,7 @@ use crate::dom::document::{determine_policy_for_token, Document}; use crate::dom::element::Element; use crate::dom::htmlelement::HTMLElement; use crate::dom::htmlmetaelement::HTMLMetaElement; -use crate::dom::node::{document_from_node, Node}; +use crate::dom::node::{document_from_node, Node, ShadowIncluding}; use crate::dom::userscripts::load_script; use crate::dom::virtualmethods::VirtualMethods; use dom_struct::dom_struct; @@ -55,7 +55,7 @@ impl HTMLHeadElement { let node = self.upcast::(); let candidates = node - .traverse_preorder(/* shadow including */ false) + .traverse_preorder(ShadowIncluding::No) .filter_map(DomRoot::downcast::) .filter(|elem| elem.is::()) .filter(|elem| elem.get_string_attribute(&local_name!("name")) == "referrer") diff --git a/components/script/dom/htmlimageelement.rs b/components/script/dom/htmlimageelement.rs index fd545b47016..efb372770b1 100644 --- a/components/script/dom/htmlimageelement.rs +++ b/components/script/dom/htmlimageelement.rs @@ -32,7 +32,8 @@ use crate::dom::htmlmapelement::HTMLMapElement; use crate::dom::htmlpictureelement::HTMLPictureElement; use crate::dom::htmlsourceelement::HTMLSourceElement; use crate::dom::mouseevent::MouseEvent; -use crate::dom::node::{document_from_node, window_from_node, Node, NodeDamage, UnbindContext}; +use crate::dom::node::UnbindContext; +use crate::dom::node::{document_from_node, window_from_node, Node, NodeDamage, ShadowIncluding}; use crate::dom::performanceresourcetiming::InitiatorType; use crate::dom::progressevent::ProgressEvent; use crate::dom::values::UNSIGNED_LONG_MAX; @@ -1259,7 +1260,7 @@ impl HTMLImageElement { let useMapElements = document_from_node(self) .upcast::() - .traverse_preorder(/* shadow including */ false) + .traverse_preorder(ShadowIncluding::No) .filter_map(DomRoot::downcast::) .find(|n| { n.upcast::() diff --git a/components/script/dom/htmllabelelement.rs b/components/script/dom/htmllabelelement.rs index 6ed17609a03..11ee09bce94 100644 --- a/components/script/dom/htmllabelelement.rs +++ b/components/script/dom/htmllabelelement.rs @@ -15,7 +15,7 @@ use crate::dom::event::Event; use crate::dom::eventtarget::EventTarget; use crate::dom::htmlelement::HTMLElement; use crate::dom::htmlformelement::{FormControl, FormControlElementHelpers, HTMLFormElement}; -use crate::dom::node::{document_from_node, Node}; +use crate::dom::node::{document_from_node, Node, ShadowIncluding}; use crate::dom::virtualmethods::VirtualMethods; use dom_struct::dom_struct; use html5ever::{LocalName, Prefix}; @@ -162,7 +162,7 @@ impl VirtualMethods for HTMLLabelElement { impl HTMLLabelElement { pub fn first_labelable_descendant(&self) -> Option> { self.upcast::() - .traverse_preorder(/* shadow including */ false) + .traverse_preorder(ShadowIncluding::No) .filter_map(DomRoot::downcast::) .filter(|elem| elem.is_labelable_element()) .next() diff --git a/components/script/dom/htmlmapelement.rs b/components/script/dom/htmlmapelement.rs index 33a5e96aea7..0b6acb3ba31 100644 --- a/components/script/dom/htmlmapelement.rs +++ b/components/script/dom/htmlmapelement.rs @@ -8,7 +8,7 @@ use crate::dom::bindings::root::DomRoot; use crate::dom::document::Document; use crate::dom::htmlareaelement::HTMLAreaElement; use crate::dom::htmlelement::HTMLElement; -use crate::dom::node::Node; +use crate::dom::node::{Node, ShadowIncluding}; use dom_struct::dom_struct; use html5ever::{LocalName, Prefix}; @@ -43,7 +43,7 @@ impl HTMLMapElement { pub fn get_area_elements(&self) -> Vec> { self.upcast::() - .traverse_preorder(/* shadow including */ false) + .traverse_preorder(ShadowIncluding::No) .filter_map(DomRoot::downcast::) .collect() } diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 86d952146a4..9a683f00698 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -293,7 +293,7 @@ impl Node { let parent_in_shadow_tree = self.is_in_shadow_tree(); let parent_is_connected = self.is_connected(); - for node in new_child.traverse_preorder(/* shadow including */ false) { + for node in new_child.traverse_preorder(ShadowIncluding::No) { if parent_in_shadow_tree { if let Some(shadow_root) = self.downcast::() { node.set_owner_shadow_root(&*shadow_root); @@ -351,7 +351,7 @@ impl Node { child.composed_parent_node.set(None); self.children_count.set(self.children_count.get() - 1); - for node in child.traverse_preorder(/* shadow including */ true) { + for node in child.traverse_preorder(ShadowIncluding::Yes) { // Out-of-document elements never have the descendants flag set. node.set_flag( NodeFlags::IS_IN_DOC | @@ -362,7 +362,7 @@ impl Node { false, ); } - for node in child.traverse_preorder(/* shadow including */ true) { + for node in child.traverse_preorder(ShadowIncluding::Yes) { // This needs to be in its own loop, because unbind_from_tree may // rely on the state of IS_IN_DOC of the context node's descendants, // e.g. when removing a . @@ -625,7 +625,7 @@ impl Node { } /// Iterates over this node and all its descendants, in preorder. - pub fn traverse_preorder(&self, shadow_including: bool) -> TreeIterator { + pub fn traverse_preorder(&self, shadow_including: ShadowIncluding) -> TreeIterator { TreeIterator::new(self, shadow_including) } @@ -873,7 +873,7 @@ impl Node { self.owner_doc().quirks_mode(), ); Ok(self - .traverse_preorder(/* shadow including */ false) + .traverse_preorder(ShadowIncluding::No) .filter_map(DomRoot::downcast) .find(|element| matches_selector_list(&selectors, element, &mut ctx))) }, @@ -891,7 +891,7 @@ impl Node { Err(_) => Err(Error::Syntax), // Step 3. Ok(selectors) => { - let mut descendants = self.traverse_preorder(/* shadow including */ false); + let mut descendants = self.traverse_preorder(ShadowIncluding::No); // Skip the root of the tree. assert!(&*descendants.next().unwrap() == self); Ok(QuerySelectorIterator::new(descendants, selectors)) @@ -1510,6 +1510,13 @@ where } } +/// Whether a tree traversal should pass shadow tree boundaries. +#[derive(PartialEq)] +pub enum ShadowIncluding { + No, + Yes, +} + pub struct TreeIterator { current: Option>, depth: usize, @@ -1517,11 +1524,11 @@ pub struct TreeIterator { } impl TreeIterator { - fn new(root: &Node, shadow_including: bool) -> TreeIterator { + fn new(root: &Node, shadow_including: ShadowIncluding) -> TreeIterator { TreeIterator { current: Some(DomRoot::from_ref(root)), depth: 0, - shadow_including, + shadow_including: shadow_including == ShadowIncluding::Yes, } } @@ -1655,11 +1662,11 @@ impl Node { // Step 3. if &*old_doc != document { // Step 3.1. - for descendant in node.traverse_preorder(/* shadow including */ true) { + for descendant in node.traverse_preorder(ShadowIncluding::Yes) { descendant.set_owner_doc(document); } for descendant in node - .traverse_preorder(/* shadow including */ true) + .traverse_preorder(ShadowIncluding::Yes) .filter_map(|d| d.as_custom_element()) { // Step 3.2. @@ -1669,7 +1676,7 @@ impl Node { None, ); } - for descendant in node.traverse_preorder(/* shadow including */ true) { + for descendant in node.traverse_preorder(ShadowIncluding::Yes) { // Step 3.3. vtable_for(&descendant).adopting_steps(&old_doc); } @@ -1890,7 +1897,7 @@ impl Node { parent.add_child(*kid, child); // Step 7.7. for descendant in kid - .traverse_preorder(/* shadow including */ true) + .traverse_preorder(ShadowIncluding::Yes) .filter_map(DomRoot::downcast::) { // Step 7.7.2. @@ -2335,9 +2342,8 @@ impl NodeMethods for Node { fn GetTextContent(&self) -> Option { match self.type_id() { NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => { - let content = Node::collect_text_contents( - self.traverse_preorder(/* shadow including */ false), - ); + let content = + Node::collect_text_contents(self.traverse_preorder(ShadowIncluding::No)); Some(content) }, NodeTypeId::CharacterData(..) => { @@ -3190,7 +3196,7 @@ where let elem_node = elem.upcast::(); let mut head: usize = 0; - for node in tree_root.traverse_preorder(/* shadow including */ false) { + for node in tree_root.traverse_preorder(ShadowIncluding::No) { let head_node = DomRoot::upcast::(DomRoot::from_ref(&*self[head])); if head_node == node { head += 1; diff --git a/components/script/dom/range.rs b/components/script/dom/range.rs index 2f0b5422b1e..462b3382c71 100644 --- a/components/script/dom/range.rs +++ b/components/script/dom/range.rs @@ -24,7 +24,7 @@ use crate::dom::document::Document; use crate::dom::documentfragment::DocumentFragment; use crate::dom::element::Element; use crate::dom::htmlscriptelement::HTMLScriptElement; -use crate::dom::node::{Node, UnbindContext}; +use crate::dom::node::{Node, ShadowIncluding, UnbindContext}; use crate::dom::text::Text; use crate::dom::window::Window; use dom_struct::dom_struct; @@ -978,7 +978,7 @@ impl RangeMethods for Range { // Step 4. for node in fragment_node .upcast::() - .traverse_preorder(/* shadow incluing */ false) + .traverse_preorder(ShadowIncluding::No) { if let Some(script) = node.downcast::() { script.set_already_started(false); diff --git a/components/script/webdriver_handlers.rs b/components/script/webdriver_handlers.rs index 8bcb63a58f4..ee373126513 100644 --- a/components/script/webdriver_handlers.rs +++ b/components/script/webdriver_handlers.rs @@ -22,7 +22,7 @@ use crate::dom::htmlelement::HTMLElement; use crate::dom::htmliframeelement::HTMLIFrameElement; use crate::dom::htmlinputelement::HTMLInputElement; use crate::dom::htmloptionelement::HTMLOptionElement; -use crate::dom::node::{window_from_node, Node}; +use crate::dom::node::{window_from_node, Node, ShadowIncluding}; use crate::script_thread::Documents; use cookie::Cookie; use euclid::{Point2D, Rect, Size2D}; @@ -50,7 +50,7 @@ fn find_node_by_unique_id( documents.find_document(pipeline).and_then(|document| { document .upcast::() - .traverse_preorder(/* shadow including */ true) + .traverse_preorder(ShadowIncluding::Yes) .find(|candidate| candidate.unique_id() == node_id) }) } From 3dd38151d4bb446864904428f03af23cc30684fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Thu, 21 Feb 2019 13:38:11 +0100 Subject: [PATCH 47/83] Make StyleSheetListOwner implement JSTraceable --- components/script/dom/bindings/trace.rs | 2 -- components/script/dom/stylesheetlist.rs | 3 ++- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 2d568208b69..56805e4d9fe 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -39,7 +39,6 @@ use crate::dom::bindings::utils::WindowProxyHandler; use crate::dom::document::PendingRestyle; use crate::dom::htmlimageelement::SourceSet; use crate::dom::htmlmediaelement::{HTMLMediaElementFetchContext, MediaFrameRenderer}; -use crate::dom::stylesheetlist::StyleSheetListOwner; use crate::task::TaskBox; use app_units::Au; use canvas_traits::canvas::{ @@ -500,7 +499,6 @@ unsafe_no_jsmanaged_fields!(HTMLMediaElementFetchContext); unsafe_no_jsmanaged_fields!(Rotation3D, Transform2D, Transform3D); unsafe_no_jsmanaged_fields!(Point2D, Vector2D, Rect); unsafe_no_jsmanaged_fields!(Rect, RigidTransform3D); -unsafe_no_jsmanaged_fields!(StyleSheetListOwner); unsafe_no_jsmanaged_fields!(CascadeData); unsafe impl<'a> JSTraceable for &'a str { diff --git a/components/script/dom/stylesheetlist.rs b/components/script/dom/stylesheetlist.rs index b87d7957dfb..930af55ae14 100644 --- a/components/script/dom/stylesheetlist.rs +++ b/components/script/dom/stylesheetlist.rs @@ -6,6 +6,7 @@ use crate::dom::bindings::codegen::Bindings::StyleSheetListBinding; use crate::dom::bindings::codegen::Bindings::StyleSheetListBinding::StyleSheetListMethods; use crate::dom::bindings::reflector::{reflect_dom_object, Reflector}; use crate::dom::bindings::root::DomRoot; +use crate::dom::bindings::trace::JSTraceable; use crate::dom::cssstylesheet::CSSStyleSheet; use crate::dom::element::Element; use crate::dom::stylesheet::StyleSheet; @@ -14,7 +15,7 @@ use dom_struct::dom_struct; use servo_arc::Arc; use style::stylesheets::Stylesheet; -pub trait StyleSheetListOwner { +pub trait StyleSheetListOwner: JSTraceable { fn stylesheet_count(&self) -> usize; fn stylesheet_at(&self, index: usize) -> Option>; fn add_stylesheet(&self, owner: &Element, sheet: Arc); From d77b9c6775d181168f245faf8620fe6e2b7ec096 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Thu, 21 Feb 2019 16:54:37 +0100 Subject: [PATCH 48/83] Add invalidate_stylesheets to StyleSheetsListOwner trait --- components/script/dom/cssstyledeclaration.rs | 14 +++----------- components/script/dom/cssstylerule.rs | 17 +++-------------- components/script/dom/cssstylesheet.rs | 12 ++---------- components/script/dom/document.rs | 4 ++++ components/script/dom/shadowroot.rs | 4 ++++ components/script/dom/stylesheetlist.rs | 1 + 6 files changed, 17 insertions(+), 35 deletions(-) diff --git a/components/script/dom/cssstyledeclaration.rs b/components/script/dom/cssstyledeclaration.rs index bbb788cceeb..d623f46005a 100644 --- a/components/script/dom/cssstyledeclaration.rs +++ b/components/script/dom/cssstyledeclaration.rs @@ -13,7 +13,7 @@ use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::bindings::str::DOMString; use crate::dom::cssrule::CSSRule; use crate::dom::element::Element; -use crate::dom::node::{document_from_node, shadow_root_from_node, window_from_node, Node}; +use crate::dom::node::{document_from_node, stylesheets_owner_from_node, window_from_node, Node}; use crate::dom::window::Window; use dom_struct::dom_struct; use servo_arc::Arc; @@ -115,16 +115,8 @@ impl CSSStyleOwner { if changed { // If this is changed, see also // CSSStyleRule::SetSelectorText, which does the same thing. - if let Some(shadow_root) = - shadow_root_from_node(rule.parent_stylesheet().owner().upcast::()) - { - shadow_root.invalidate_stylesheets(); - } else { - rule.global() - .as_window() - .Document() - .invalidate_stylesheets(); - } + stylesheets_owner_from_node(rule.parent_stylesheet().owner().upcast::()) + .invalidate_stylesheets(); } result }, diff --git a/components/script/dom/cssstylerule.rs b/components/script/dom/cssstylerule.rs index 173661eb30a..14d7cdcdbef 100644 --- a/components/script/dom/cssstylerule.rs +++ b/components/script/dom/cssstylerule.rs @@ -3,7 +3,6 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use crate::dom::bindings::codegen::Bindings::CSSStyleRuleBinding::{self, CSSStyleRuleMethods}; -use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods; use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::reflector::{reflect_dom_object, DomObject}; use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom}; @@ -11,7 +10,7 @@ use crate::dom::bindings::str::DOMString; use crate::dom::cssrule::{CSSRule, SpecificCSSRule}; use crate::dom::cssstyledeclaration::{CSSModificationAccess, CSSStyleDeclaration, CSSStyleOwner}; use crate::dom::cssstylesheet::CSSStyleSheet; -use crate::dom::node::{shadow_root_from_node, Node}; +use crate::dom::node::{stylesheets_owner_from_node, Node}; use crate::dom::window::Window; use cssparser::ToCss; use cssparser::{Parser as CssParser, ParserInput as CssParserInput}; @@ -119,18 +118,8 @@ impl CSSStyleRuleMethods for CSSStyleRule { let mut guard = self.cssrule.shared_lock().write(); let stylerule = self.stylerule.write_with(&mut guard); mem::swap(&mut stylerule.selectors, &mut s); - if let Some(shadow_root) = - shadow_root_from_node(self.cssrule.parent_stylesheet().owner().upcast::()) - { - shadow_root.invalidate_stylesheets(); - } else { - // It seems like we will want to avoid having to invalidate all - // stylesheets eventually! - self.global() - .as_window() - .Document() - .invalidate_stylesheets(); - } + stylesheets_owner_from_node(self.cssrule.parent_stylesheet().owner().upcast::()) + .invalidate_stylesheets(); } } } diff --git a/components/script/dom/cssstylesheet.rs b/components/script/dom/cssstylesheet.rs index 9863dede5cb..66d2fd8a339 100644 --- a/components/script/dom/cssstylesheet.rs +++ b/components/script/dom/cssstylesheet.rs @@ -4,7 +4,6 @@ use crate::dom::bindings::codegen::Bindings::CSSStyleSheetBinding; use crate::dom::bindings::codegen::Bindings::CSSStyleSheetBinding::CSSStyleSheetMethods; -use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods; use crate::dom::bindings::error::{Error, ErrorResult, Fallible}; use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::reflector::{reflect_dom_object, DomObject}; @@ -12,7 +11,7 @@ use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom}; use crate::dom::bindings::str::DOMString; use crate::dom::cssrulelist::{CSSRuleList, RulesSource}; use crate::dom::element::Element; -use crate::dom::node::{shadow_root_from_node, Node}; +use crate::dom::node::{stylesheets_owner_from_node, Node}; use crate::dom::stylesheet::StyleSheet; use crate::dom::window::Window; use dom_struct::dom_struct; @@ -87,14 +86,7 @@ impl CSSStyleSheet { pub fn set_disabled(&self, disabled: bool) { if self.style_stylesheet.set_disabled(disabled) { - if let Some(shadow_root) = shadow_root_from_node(self.owner.upcast::()) { - shadow_root.invalidate_stylesheets(); - } else { - self.global() - .as_window() - .Document() - .invalidate_stylesheets(); - } + stylesheets_owner_from_node(self.owner().upcast::()).invalidate_stylesheets(); } } diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 72c25a8fa54..861271abe43 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -4661,4 +4661,8 @@ impl StyleSheetListOwner for Dom { &mut *self.stylesheets.borrow_mut(), ) } + + fn invalidate_stylesheets(&self) { + Document::invalidate_stylesheets(self); + } } diff --git a/components/script/dom/shadowroot.rs b/components/script/dom/shadowroot.rs index dd47187836e..d99a5f3b3d7 100644 --- a/components/script/dom/shadowroot.rs +++ b/components/script/dom/shadowroot.rs @@ -237,4 +237,8 @@ impl StyleSheetListOwner for Dom { &mut self.author_styles.borrow_mut().stylesheets, ) } + + fn invalidate_stylesheets(&self) { + ShadowRoot::invalidate_stylesheets(self); + } } diff --git a/components/script/dom/stylesheetlist.rs b/components/script/dom/stylesheetlist.rs index 930af55ae14..0b10680f52a 100644 --- a/components/script/dom/stylesheetlist.rs +++ b/components/script/dom/stylesheetlist.rs @@ -20,6 +20,7 @@ pub trait StyleSheetListOwner: JSTraceable { fn stylesheet_at(&self, index: usize) -> Option>; fn add_stylesheet(&self, owner: &Element, sheet: Arc); fn remove_stylesheet(&self, owner: &Element, s: &Arc); + fn invalidate_stylesheets(&self); } #[dom_struct] From 67c90a0717c792c646f14d9a56d97fca3bd92305 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Thu, 21 Feb 2019 17:30:32 +0100 Subject: [PATCH 49/83] Relax attachShadow restrictions for user agent widgets --- components/script/dom/element.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 313ca6111a3..9d92f196a77 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -250,6 +250,13 @@ impl FromStr for AdjacentPosition { } } +/// Whether a shadow root hosts an User Agent widget. +#[derive(PartialEq)] +pub enum IsUserAgentWidget { + No, + Yes, +} + // // Element methods // @@ -451,7 +458,7 @@ impl Element { /// https://dom.spec.whatwg.org/#dom-element-attachshadow /// XXX This is not exposed to web content yet. It is meant to be used /// for UA widgets only. - pub fn attach_shadow(&self) -> Fallible> { + pub fn attach_shadow(&self, is_ua_widget: IsUserAgentWidget) -> Fallible> { // Step 1. if self.namespace != ns!(html) { return Err(Error::NotSupported); @@ -477,6 +484,8 @@ impl Element { &local_name!("p") | &local_name!("section") | &local_name!("span") => {}, + &local_name!("video") | &local_name!("audio") + if is_ua_widget == IsUserAgentWidget::Yes => {}, _ => return Err(Error::NotSupported), }; @@ -2658,7 +2667,7 @@ impl ElementMethods for Element { // to test partial Shadow DOM support for UA widgets. // https://dom.spec.whatwg.org/#dom-element-attachshadow fn AttachShadow(&self) -> Fallible> { - self.attach_shadow() + self.attach_shadow(IsUserAgentWidget::No) } } From 3e63655018e07c1d4a3aa1c4252290fbe482a7f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Thu, 28 Feb 2019 13:06:01 +0100 Subject: [PATCH 50/83] Make ServoShadowRoot.flush_stylesheets unsafe --- components/layout_thread/dom_wrapper.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/components/layout_thread/dom_wrapper.rs b/components/layout_thread/dom_wrapper.rs index 72cbdf04701..cae98f7e594 100644 --- a/components/layout_thread/dom_wrapper.rs +++ b/components/layout_thread/dom_wrapper.rs @@ -213,16 +213,14 @@ impl<'lr> ServoShadowRoot<'lr> { } } - pub fn flush_stylesheets( + pub unsafe fn flush_stylesheets( &self, device: &Device, quirks_mode: QuirksMode, guard: &SharedRwLockReadGuard, ) { - unsafe { - self.shadow_root - .flush_stylesheets::(device, quirks_mode, guard) - }; + self.shadow_root + .flush_stylesheets::(device, quirks_mode, guard) } } From 3e53962b2502cdb19790519c7ec82c499d248cc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Thu, 28 Feb 2019 16:42:19 +0100 Subject: [PATCH 51/83] Do not send RemoveStyleSheet message for shadow roots --- components/script/dom/document.rs | 5 +++++ components/script/dom/documentorshadowroot.rs | 7 +------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 861271abe43..8e1c09c2361 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -4655,6 +4655,11 @@ impl StyleSheetListOwner for Dom { /// Remove a stylesheet owned by `owner` from the list of document sheets. #[allow(unrooted_must_root)] // Owner needs to be rooted already necessarily. fn remove_stylesheet(&self, owner: &Element, s: &Arc) { + self.window + .layout_chan() + .send(Msg::RemoveStylesheet(s.clone())) + .unwrap(); + self.document_or_shadow_root.remove_stylesheet( owner, s, diff --git a/components/script/dom/documentorshadowroot.rs b/components/script/dom/documentorshadowroot.rs index 51846baa443..27d52e086c6 100644 --- a/components/script/dom/documentorshadowroot.rs +++ b/components/script/dom/documentorshadowroot.rs @@ -13,7 +13,7 @@ use crate::dom::node; use crate::dom::window::Window; use euclid::Point2D; use js::jsapi::JS_GetRuntime; -use script_layout_interface::message::{Msg, NodesFromPointQueryType, QueryMsg}; +use script_layout_interface::message::{NodesFromPointQueryType, QueryMsg}; use script_traits::UntrustedNodeAddress; use servo_arc::Arc; use std::fmt; @@ -216,11 +216,6 @@ impl DocumentOrShadowRoot { s: &Arc, stylesheets: &mut StylesheetSet, ) { - self.window - .layout_chan() - .send(Msg::RemoveStylesheet(s.clone())) - .unwrap(); - let guard = s.shared_lock.read(); // FIXME(emilio): Would be nice to remove the clone, etc. From 8b353ee3ced609d2de688a93dcfd825c3cef3eae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Fri, 1 Mar 2019 11:43:45 +0100 Subject: [PATCH 52/83] Make StylesheetSet an enum instead of a trait object --- components/script/dom/document.rs | 10 ++-- components/script/dom/documentorshadowroot.rs | 6 +-- components/script/dom/shadowroot.rs | 9 ++-- components/style/stylesheet_set.rs | 54 +++++++++++++------ 4 files changed, 51 insertions(+), 28 deletions(-) diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 8e1c09c2361..bef1edc68fd 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -155,7 +155,7 @@ use style::media_queries::{Device, MediaType}; use style::selector_parser::{RestyleDamage, Snapshot}; use style::shared_lock::SharedRwLock as StyleSharedRwLock; use style::str::{split_html_space_chars, str_join}; -use style::stylesheet_set::DocumentStylesheetSet; +use style::stylesheet_set::{DocumentStylesheetSet, StylesheetSet}; use style::stylesheets::{Origin, OriginSet, Stylesheet}; use url::percent_encoding::percent_decode; use url::Host; @@ -4643,9 +4643,9 @@ impl StyleSheetListOwner for Dom { )) .unwrap(); - self.document_or_shadow_root.add_stylesheet( + DocumentOrShadowRoot::add_stylesheet( owner, - stylesheets, + StylesheetSet::Document(stylesheets), sheet, insertion_point, self.style_shared_lock(), @@ -4660,10 +4660,10 @@ impl StyleSheetListOwner for Dom { .send(Msg::RemoveStylesheet(s.clone())) .unwrap(); - self.document_or_shadow_root.remove_stylesheet( + DocumentOrShadowRoot::remove_stylesheet( owner, s, - &mut *self.stylesheets.borrow_mut(), + StylesheetSet::Document(&mut *self.stylesheets.borrow_mut()), ) } diff --git a/components/script/dom/documentorshadowroot.rs b/components/script/dom/documentorshadowroot.rs index 27d52e086c6..0165c0b8384 100644 --- a/components/script/dom/documentorshadowroot.rs +++ b/components/script/dom/documentorshadowroot.rs @@ -211,10 +211,9 @@ impl DocumentOrShadowRoot { /// Remove a stylesheet owned by `owner` from the list of document sheets. #[allow(unrooted_must_root)] // Owner needs to be rooted already necessarily. pub fn remove_stylesheet( - &self, owner: &Element, s: &Arc, - stylesheets: &mut StylesheetSet, + mut stylesheets: StylesheetSet, ) { let guard = s.shared_lock.read(); @@ -233,9 +232,8 @@ impl DocumentOrShadowRoot { /// correct tree position. #[allow(unrooted_must_root)] // Owner needs to be rooted already necessarily. pub fn add_stylesheet( - &self, owner: &Element, - stylesheets: &mut StylesheetSet, + mut stylesheets: StylesheetSet, sheet: Arc, insertion_point: Option, style_shared_lock: &StyleSharedRwLock, diff --git a/components/script/dom/shadowroot.rs b/components/script/dom/shadowroot.rs index d99a5f3b3d7..5233e7b4143 100644 --- a/components/script/dom/shadowroot.rs +++ b/components/script/dom/shadowroot.rs @@ -24,6 +24,7 @@ use style::author_styles::AuthorStyles; use style::dom::TElement; use style::media_queries::Device; use style::shared_lock::SharedRwLockReadGuard; +use style::stylesheet_set::StylesheetSet; use style::stylesheets::Stylesheet; // https://dom.spec.whatwg.org/#interface-shadowroot @@ -219,9 +220,9 @@ impl StyleSheetListOwner for Dom { .is_before(sheet_in_shadow.owner.upcast()) }) .cloned(); - self.document_or_shadow_root.add_stylesheet( + DocumentOrShadowRoot::add_stylesheet( owner, - stylesheets, + StylesheetSet::Author(stylesheets), sheet, insertion_point, self.document.style_shared_lock(), @@ -231,10 +232,10 @@ impl StyleSheetListOwner for Dom { /// Remove a stylesheet owned by `owner` from the list of shadow root sheets. #[allow(unrooted_must_root)] // Owner needs to be rooted already necessarily. fn remove_stylesheet(&self, owner: &Element, s: &Arc) { - self.document_or_shadow_root.remove_stylesheet( + DocumentOrShadowRoot::remove_stylesheet( owner, s, - &mut self.author_styles.borrow_mut().stylesheets, + StylesheetSet::Author(&mut self.author_styles.borrow_mut().stylesheets), ) } diff --git a/components/style/stylesheet_set.rs b/components/style/stylesheet_set.rs index 9a53339f5f9..4c3e37d3cd8 100644 --- a/components/style/stylesheet_set.rs +++ b/components/style/stylesheet_set.rs @@ -374,36 +374,65 @@ where } /// Functionality common to DocumentStylesheetSet and AuthorStylesheetSet. -pub trait StylesheetSet +pub enum StylesheetSet<'a, S> +where + S: StylesheetInDocument + PartialEq + 'static, +{ + /// Author stylesheet set. + Author(&'a mut AuthorStylesheetSet), + /// Document stylesheet set. + Document(&'a mut DocumentStylesheetSet), +} + +impl<'a, S> StylesheetSet<'a, S> where S: StylesheetInDocument + PartialEq + 'static, { /// Appends a new stylesheet to the current set. /// /// No device implies not computing invalidations. - fn append_stylesheet( + pub fn append_stylesheet( &mut self, device: Option<&Device>, sheet: S, guard: &SharedRwLockReadGuard, - ); + ) { + match self { + StylesheetSet::Author(set) => set.append_stylesheet(device, sheet, guard), + StylesheetSet::Document(set) => set.append_stylesheet(device, sheet, guard), + } + } /// Insert a given stylesheet before another stylesheet in the document. - fn insert_stylesheet_before( + pub fn insert_stylesheet_before( &mut self, device: Option<&Device>, sheet: S, before_sheet: S, guard: &SharedRwLockReadGuard, - ); + ) { + match self { + StylesheetSet::Author(set) => { + set.insert_stylesheet_before(device, sheet, before_sheet, guard) + }, + StylesheetSet::Document(set) => { + set.insert_stylesheet_before(device, sheet, before_sheet, guard) + }, + } + } /// Remove a given stylesheet from the set. - fn remove_stylesheet( + pub fn remove_stylesheet( &mut self, device: Option<&Device>, sheet: S, guard: &SharedRwLockReadGuard, - ); + ) { + match self { + StylesheetSet::Author(set) => set.remove_stylesheet(device, sheet, guard), + StylesheetSet::Document(set) => set.remove_stylesheet(device, sheet, guard), + } + } } /// This macro defines methods common to DocumentStylesheetSet and @@ -429,16 +458,11 @@ macro_rules! stylesheetset_impl { .collect_invalidations_for(device, sheet, guard); } } - } - impl StylesheetSet for $set_type - where - S: StylesheetInDocument + PartialEq + 'static, - { /// Appends a new stylesheet to the current set. /// /// No device implies not computing invalidations. - fn append_stylesheet( + pub fn append_stylesheet( &mut self, device: Option<&Device>, sheet: S, @@ -451,7 +475,7 @@ macro_rules! stylesheetset_impl { } /// Insert a given stylesheet before another stylesheet in the document. - fn insert_stylesheet_before( + pub fn insert_stylesheet_before( &mut self, device: Option<&Device>, sheet: S, @@ -466,7 +490,7 @@ macro_rules! stylesheetset_impl { } /// Remove a given stylesheet from the set. - fn remove_stylesheet( + pub fn remove_stylesheet( &mut self, device: Option<&Device>, sheet: S, From 2350f0e3d1202d4c0cbb5189b9ab668b402eb179 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Fri, 1 Mar 2019 18:10:18 +0100 Subject: [PATCH 53/83] Make StyleSheetListOwner an enum instead of a trait object --- components/script/dom/document.rs | 132 +++++++++++----------- components/script/dom/htmllinkelement.rs | 1 + components/script/dom/htmlmetaelement.rs | 1 + components/script/dom/htmlstyleelement.rs | 1 + components/script/dom/node.rs | 7 +- components/script/dom/shadowroot.rs | 102 ++++++++--------- components/script/dom/stylesheetlist.rs | 67 +++++++++-- 7 files changed, 177 insertions(+), 134 deletions(-) diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index bef1edc68fd..4ec2e67521c 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -3191,6 +3191,65 @@ impl Document { } self.shadow_roots_styles_changed.set(false); } + + pub fn stylesheet_count(&self) -> usize { + self.stylesheets.borrow().len() + } + + pub fn stylesheet_at(&self, index: usize) -> Option> { + let stylesheets = self.stylesheets.borrow(); + + stylesheets + .get(Origin::Author, index) + .and_then(|s| s.owner.upcast::().get_cssom_stylesheet()) + } + + /// Add a stylesheet owned by `owner` to the list of document sheets, in the + /// correct tree position. + #[allow(unrooted_must_root)] // Owner needs to be rooted already necessarily. + pub fn add_stylesheet(&self, owner: &Element, sheet: Arc) { + let stylesheets = &mut *self.stylesheets.borrow_mut(); + let insertion_point = stylesheets + .iter() + .map(|(sheet, _origin)| sheet) + .find(|sheet_in_doc| { + owner + .upcast::() + .is_before(sheet_in_doc.owner.upcast()) + }) + .cloned(); + + self.window + .layout_chan() + .send(Msg::AddStylesheet( + sheet.clone(), + insertion_point.as_ref().map(|s| s.sheet.clone()), + )) + .unwrap(); + + DocumentOrShadowRoot::add_stylesheet( + owner, + StylesheetSet::Document(stylesheets), + sheet, + insertion_point, + self.style_shared_lock(), + ); + } + + /// Remove a stylesheet owned by `owner` from the list of document sheets. + #[allow(unrooted_must_root)] // Owner needs to be rooted already necessarily. + pub fn remove_stylesheet(&self, owner: &Element, s: &Arc) { + self.window + .layout_chan() + .send(Msg::RemoveStylesheet(s.clone())) + .unwrap(); + + DocumentOrShadowRoot::remove_stylesheet( + owner, + s, + StylesheetSet::Document(&mut *self.stylesheets.borrow_mut()), + ) + } } impl Element { @@ -3222,8 +3281,12 @@ impl ProfilerMetadataFactory for Document { impl DocumentMethods for Document { // https://drafts.csswg.org/cssom/#dom-document-stylesheets fn StyleSheets(&self) -> DomRoot { - self.stylesheet_list - .or_init(|| StyleSheetList::new(&self.window, Box::new(Dom::from_ref(self)))) + self.stylesheet_list.or_init(|| { + StyleSheetList::new( + &self.window, + StyleSheetListOwner::Document(Dom::from_ref(self)), + ) + }) } // https://dom.spec.whatwg.org/#dom-document-implementation @@ -4606,68 +4669,3 @@ impl PendingScript { .map(|result| (DomRoot::from_ref(&*self.element), result)) } } - -impl StyleSheetListOwner for Dom { - fn stylesheet_count(&self) -> usize { - self.stylesheets.borrow().len() - } - - fn stylesheet_at(&self, index: usize) -> Option> { - let stylesheets = self.stylesheets.borrow(); - - stylesheets - .get(Origin::Author, index) - .and_then(|s| s.owner.upcast::().get_cssom_stylesheet()) - } - - /// Add a stylesheet owned by `owner` to the list of document sheets, in the - /// correct tree position. - #[allow(unrooted_must_root)] // Owner needs to be rooted already necessarily. - fn add_stylesheet(&self, owner: &Element, sheet: Arc) { - let stylesheets = &mut *self.stylesheets.borrow_mut(); - let insertion_point = stylesheets - .iter() - .map(|(sheet, _origin)| sheet) - .find(|sheet_in_doc| { - owner - .upcast::() - .is_before(sheet_in_doc.owner.upcast()) - }) - .cloned(); - - self.window - .layout_chan() - .send(Msg::AddStylesheet( - sheet.clone(), - insertion_point.as_ref().map(|s| s.sheet.clone()), - )) - .unwrap(); - - DocumentOrShadowRoot::add_stylesheet( - owner, - StylesheetSet::Document(stylesheets), - sheet, - insertion_point, - self.style_shared_lock(), - ); - } - - /// Remove a stylesheet owned by `owner` from the list of document sheets. - #[allow(unrooted_must_root)] // Owner needs to be rooted already necessarily. - fn remove_stylesheet(&self, owner: &Element, s: &Arc) { - self.window - .layout_chan() - .send(Msg::RemoveStylesheet(s.clone())) - .unwrap(); - - DocumentOrShadowRoot::remove_stylesheet( - owner, - s, - StylesheetSet::Document(&mut *self.stylesheets.borrow_mut()), - ) - } - - fn invalidate_stylesheets(&self) { - Document::invalidate_stylesheets(self); - } -} diff --git a/components/script/dom/htmllinkelement.rs b/components/script/dom/htmllinkelement.rs index 9e102795b2c..d47d9343e53 100644 --- a/components/script/dom/htmllinkelement.rs +++ b/components/script/dom/htmllinkelement.rs @@ -109,6 +109,7 @@ impl HTMLLinkElement { // FIXME(emilio): These methods are duplicated with // HTMLStyleElement::set_stylesheet. + #[allow(unrooted_must_root)] pub fn set_stylesheet(&self, s: Arc) { let stylesheets_owner = stylesheets_owner_from_node(self); if let Some(ref s) = *self.stylesheet.borrow() { diff --git a/components/script/dom/htmlmetaelement.rs b/components/script/dom/htmlmetaelement.rs index 0c8794711f1..ffaf30e89f7 100644 --- a/components/script/dom/htmlmetaelement.rs +++ b/components/script/dom/htmlmetaelement.rs @@ -99,6 +99,7 @@ impl HTMLMetaElement { } } + #[allow(unrooted_must_root)] fn apply_viewport(&self) { if !pref!(layout.viewport.enabled) { return; diff --git a/components/script/dom/htmlstyleelement.rs b/components/script/dom/htmlstyleelement.rs index 763afcf1bdb..4c2d934a892 100644 --- a/components/script/dom/htmlstyleelement.rs +++ b/components/script/dom/htmlstyleelement.rs @@ -138,6 +138,7 @@ impl HTMLStyleElement { } // FIXME(emilio): This is duplicated with HTMLLinkElement::set_stylesheet. + #[allow(unrooted_must_root)] pub fn set_stylesheet(&self, s: Arc) { let stylesheets_owner = stylesheets_owner_from_node(self); if let Some(ref s) = *self.stylesheet.borrow() { diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 9a683f00698..04843e502c4 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -2802,13 +2802,14 @@ pub fn shadow_root_from_node + DomObject>( derived.upcast().owner_shadow_root() } +#[allow(unrooted_must_root)] pub fn stylesheets_owner_from_node + DomObject>( derived: &T, -) -> Box { +) -> StyleSheetListOwner { if let Some(shadow_root) = shadow_root_from_node(derived) { - Box::new(Dom::from_ref(&*shadow_root)) + StyleSheetListOwner::ShadowRoot(Dom::from_ref(&*shadow_root)) } else { - Box::new(Dom::from_ref(&*document_from_node(derived))) + StyleSheetListOwner::Document(Dom::from_ref(&*document_from_node(derived))) } } diff --git a/components/script/dom/shadowroot.rs b/components/script/dom/shadowroot.rs index 5233e7b4143..fb38c5531c6 100644 --- a/components/script/dom/shadowroot.rs +++ b/components/script/dom/shadowroot.rs @@ -75,6 +75,50 @@ impl ShadowRoot { None } + pub fn stylesheet_count(&self) -> usize { + self.author_styles.borrow().stylesheets.len() + } + + pub fn stylesheet_at(&self, index: usize) -> Option> { + let stylesheets = &self.author_styles.borrow().stylesheets; + + stylesheets + .get(index) + .and_then(|s| s.owner.upcast::().get_cssom_stylesheet()) + } + + /// Add a stylesheet owned by `owner` to the list of shadow root sheets, in the + /// correct tree position. + #[allow(unrooted_must_root)] // Owner needs to be rooted already necessarily. + pub fn add_stylesheet(&self, owner: &Element, sheet: Arc) { + let stylesheets = &mut self.author_styles.borrow_mut().stylesheets; + let insertion_point = stylesheets + .iter() + .find(|sheet_in_shadow| { + owner + .upcast::() + .is_before(sheet_in_shadow.owner.upcast()) + }) + .cloned(); + DocumentOrShadowRoot::add_stylesheet( + owner, + StylesheetSet::Author(stylesheets), + sheet, + insertion_point, + self.document.style_shared_lock(), + ); + } + + /// Remove a stylesheet owned by `owner` from the list of shadow root sheets. + #[allow(unrooted_must_root)] // Owner needs to be rooted already necessarily. + pub fn remove_stylesheet(&self, owner: &Element, s: &Arc) { + DocumentOrShadowRoot::remove_stylesheet( + owner, + s, + StylesheetSet::Author(&mut self.author_styles.borrow_mut().stylesheets), + ) + } + pub fn invalidate_stylesheets(&self) { self.document.invalidate_shadow_roots_stylesheets(); self.author_styles.borrow_mut().stylesheets.force_dirty(); @@ -145,8 +189,12 @@ impl ShadowRootMethods for ShadowRoot { // https://drafts.csswg.org/cssom/#dom-document-stylesheets fn StyleSheets(&self) -> DomRoot { - self.stylesheet_list - .or_init(|| StyleSheetList::new(&self.window, Box::new(Dom::from_ref(self)))) + self.stylesheet_list.or_init(|| { + StyleSheetList::new( + &self.window, + StyleSheetListOwner::ShadowRoot(Dom::from_ref(self)), + ) + }) } } @@ -193,53 +241,3 @@ impl LayoutShadowRootHelpers for LayoutDom { } } } - -impl StyleSheetListOwner for Dom { - fn stylesheet_count(&self) -> usize { - self.author_styles.borrow().stylesheets.len() - } - - fn stylesheet_at(&self, index: usize) -> Option> { - let stylesheets = &self.author_styles.borrow().stylesheets; - - stylesheets - .get(index) - .and_then(|s| s.owner.upcast::().get_cssom_stylesheet()) - } - - /// Add a stylesheet owned by `owner` to the list of shadow root sheets, in the - /// correct tree position. - #[allow(unrooted_must_root)] // Owner needs to be rooted already necessarily. - fn add_stylesheet(&self, owner: &Element, sheet: Arc) { - let stylesheets = &mut self.author_styles.borrow_mut().stylesheets; - let insertion_point = stylesheets - .iter() - .find(|sheet_in_shadow| { - owner - .upcast::() - .is_before(sheet_in_shadow.owner.upcast()) - }) - .cloned(); - DocumentOrShadowRoot::add_stylesheet( - owner, - StylesheetSet::Author(stylesheets), - sheet, - insertion_point, - self.document.style_shared_lock(), - ); - } - - /// Remove a stylesheet owned by `owner` from the list of shadow root sheets. - #[allow(unrooted_must_root)] // Owner needs to be rooted already necessarily. - fn remove_stylesheet(&self, owner: &Element, s: &Arc) { - DocumentOrShadowRoot::remove_stylesheet( - owner, - s, - StylesheetSet::Author(&mut self.author_styles.borrow_mut().stylesheets), - ) - } - - fn invalidate_stylesheets(&self) { - ShadowRoot::invalidate_stylesheets(self); - } -} diff --git a/components/script/dom/stylesheetlist.rs b/components/script/dom/stylesheetlist.rs index 0b10680f52a..236f1c9cd9a 100644 --- a/components/script/dom/stylesheetlist.rs +++ b/components/script/dom/stylesheetlist.rs @@ -5,33 +5,76 @@ use crate::dom::bindings::codegen::Bindings::StyleSheetListBinding; use crate::dom::bindings::codegen::Bindings::StyleSheetListBinding::StyleSheetListMethods; use crate::dom::bindings::reflector::{reflect_dom_object, Reflector}; -use crate::dom::bindings::root::DomRoot; -use crate::dom::bindings::trace::JSTraceable; +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::shadowroot::ShadowRoot; use crate::dom::stylesheet::StyleSheet; use crate::dom::window::Window; use dom_struct::dom_struct; use servo_arc::Arc; use style::stylesheets::Stylesheet; -pub trait StyleSheetListOwner: JSTraceable { - fn stylesheet_count(&self) -> usize; - fn stylesheet_at(&self, index: usize) -> Option>; - fn add_stylesheet(&self, owner: &Element, sheet: Arc); - fn remove_stylesheet(&self, owner: &Element, s: &Arc); - fn invalidate_stylesheets(&self); +#[must_root] +#[derive(JSTraceable, MallocSizeOf)] +pub enum StyleSheetListOwner { + Document(Dom), + ShadowRoot(Dom), +} + +impl StyleSheetListOwner { + pub fn stylesheet_count(&self) -> usize { + match *self { + StyleSheetListOwner::Document(ref doc) => doc.stylesheet_count(), + StyleSheetListOwner::ShadowRoot(ref shadow_root) => shadow_root.stylesheet_count(), + } + } + + pub fn stylesheet_at(&self, index: usize) -> Option> { + match *self { + StyleSheetListOwner::Document(ref doc) => doc.stylesheet_at(index), + StyleSheetListOwner::ShadowRoot(ref shadow_root) => shadow_root.stylesheet_at(index), + } + } + + pub fn add_stylesheet(&self, owner: &Element, sheet: Arc) { + match *self { + StyleSheetListOwner::Document(ref doc) => doc.add_stylesheet(owner, sheet), + StyleSheetListOwner::ShadowRoot(ref shadow_root) => { + shadow_root.add_stylesheet(owner, sheet) + }, + } + } + + pub fn remove_stylesheet(&self, owner: &Element, s: &Arc) { + match *self { + StyleSheetListOwner::Document(ref doc) => doc.remove_stylesheet(owner, s), + StyleSheetListOwner::ShadowRoot(ref shadow_root) => { + shadow_root.remove_stylesheet(owner, s) + }, + } + } + + pub fn invalidate_stylesheets(&self) { + match *self { + StyleSheetListOwner::Document(ref doc) => doc.invalidate_stylesheets(), + StyleSheetListOwner::ShadowRoot(ref shadow_root) => { + shadow_root.invalidate_stylesheets() + }, + } + } } #[dom_struct] pub struct StyleSheetList { reflector_: Reflector, - #[ignore_malloc_size_of = "trait object"] - document_or_shadow_root: Box, + document_or_shadow_root: StyleSheetListOwner, } impl StyleSheetList { - fn new_inherited(doc_or_sr: Box) -> StyleSheetList { + #[allow(unrooted_must_root)] + fn new_inherited(doc_or_sr: StyleSheetListOwner) -> StyleSheetList { StyleSheetList { reflector_: Reflector::new(), document_or_shadow_root: doc_or_sr, @@ -39,7 +82,7 @@ impl StyleSheetList { } #[allow(unrooted_must_root)] - pub fn new(window: &Window, doc_or_sr: Box) -> DomRoot { + pub fn new(window: &Window, doc_or_sr: StyleSheetListOwner) -> DomRoot { reflect_dom_object( Box::new(StyleSheetList::new_inherited(doc_or_sr)), window, From 542699691ea4eb6de25d7ec8509316663f1c5fed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Fri, 1 Mar 2019 18:49:37 +0100 Subject: [PATCH 54/83] Derive MallocSizeOf for QuirksMode --- components/malloc_size_of/lib.rs | 6 ++++++ components/style/author_styles.rs | 1 - components/style/stylist.rs | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/components/malloc_size_of/lib.rs b/components/malloc_size_of/lib.rs index 629cb1f0824..bb4fe1a6adc 100644 --- a/components/malloc_size_of/lib.rs +++ b/components/malloc_size_of/lib.rs @@ -778,6 +778,12 @@ impl MallocSizeOf } } +impl MallocSizeOf for selectors::context::QuirksMode { + fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize { + 0 + } +} + impl MallocSizeOf for Void { #[inline] fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize { diff --git a/components/style/author_styles.rs b/components/style/author_styles.rs index 46f95e1cac9..eff64ed6c1e 100644 --- a/components/style/author_styles.rs +++ b/components/style/author_styles.rs @@ -30,7 +30,6 @@ where pub data: CascadeData, /// The quirks mode of the last stylesheet flush, used because XBL sucks and /// we should really fix it, see bug 1406875. - #[ignore_malloc_size_of = "XXX"] pub quirks_mode: QuirksMode, } diff --git a/components/style/stylist.rs b/components/style/stylist.rs index 045d6b01cd1..ece14e9896f 100644 --- a/components/style/stylist.rs +++ b/components/style/stylist.rs @@ -23,7 +23,7 @@ use crate::selector_map::{PrecomputedHashMap, PrecomputedHashSet, SelectorMap, S use crate::selector_parser::{PerPseudoElementMap, PseudoElement, SelectorImpl, SnapshotMap}; use crate::shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards}; use crate::stylesheet_set::{DataValidity, DocumentStylesheetSet, SheetRebuildKind}; -use crate::stylesheet_set::{DocumentStylesheetFlusher, SheetCollectionFlusher, StylesheetSet}; +use crate::stylesheet_set::{DocumentStylesheetFlusher, SheetCollectionFlusher}; use crate::stylesheets::keyframes_rule::KeyframesAnimation; use crate::stylesheets::viewport_rule::{self, MaybeNew, ViewportRule}; use crate::stylesheets::StyleRule; From ea1fe15dfe76a838fbfd7b8948d07d284756e7be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Mon, 4 Mar 2019 12:08:09 +0100 Subject: [PATCH 55/83] Do not store composed parent node --- components/script/dom/node.rs | 47 +++++++++++++++++------------------ components/style/dom_apis.rs | 7 +++--- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 04843e502c4..7c50e4ae69d 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -53,7 +53,7 @@ use crate::dom::mutationobserver::{Mutation, MutationObserver, RegisteredObserve use crate::dom::nodelist::NodeList; use crate::dom::processinginstruction::ProcessingInstruction; use crate::dom::range::WeakRangeVec; -use crate::dom::shadowroot::ShadowRoot; +use crate::dom::shadowroot::{LayoutShadowRootHelpers, ShadowRoot}; use crate::dom::stylesheetlist::StyleSheetListOwner; use crate::dom::svgsvgelement::{LayoutSVGSVGElementHelpers, SVGSVGElement}; use crate::dom::text::Text; @@ -109,9 +109,6 @@ pub struct Node { /// The parent of this node. parent_node: MutNullableDom, - /// The parent of this node, ignoring shadow roots. - composed_parent_node: MutNullableDom, - /// The first child of this node. first_child: MutNullableDom, @@ -244,7 +241,6 @@ impl Node { /// Fails unless `new_child` is disconnected from the tree. fn add_child(&self, new_child: &Node, before: Option<&Node>) { assert!(new_child.parent_node.get().is_none()); - assert!(new_child.composed_parent_node.get().is_none()); assert!(new_child.prev_sibling.get().is_none()); assert!(new_child.next_sibling.get().is_none()); match before { @@ -280,13 +276,6 @@ impl Node { } new_child.parent_node.set(Some(self)); - if let Some(shadow_root) = self.downcast::() { - new_child - .composed_parent_node - .set(Some(shadow_root.Host().upcast::())); - } else { - new_child.composed_parent_node.set(Some(self)); - } self.children_count.set(self.children_count.get() + 1); let parent_in_doc = self.is_in_doc(); @@ -348,7 +337,6 @@ impl Node { child.prev_sibling.set(None); child.next_sibling.set(None); child.parent_node.set(None); - child.composed_parent_node.set(None); self.children_count.set(self.children_count.get() - 1); for node in child.traverse_preorder(ShadowIncluding::Yes) { @@ -607,13 +595,11 @@ impl Node { } match self.type_id() { - NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::Text)) => self - .composed_parent_node - .get() - .unwrap() - .downcast::() - .unwrap() - .restyle(damage), + NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::Text)) => { + if let Some(parent) = self.composed_parent_node() { + parent.downcast::().unwrap().restyle(damage) + } + }, NodeTypeId::Element(_) => self.downcast::().unwrap().restyle(damage), _ => {}, }; @@ -959,6 +945,16 @@ impl Node { self.is_connected() && self.owner_doc().browsing_context().is_some() } + fn composed_parent_node(&self) -> Option> { + let parent = self.parent_node.get(); + if let Some(ref parent) = parent { + if let Some(shadow_root) = parent.downcast::() { + return Some(DomRoot::from_ref(shadow_root.Host().upcast::())); + } + } + parent + } + pub fn children(&self) -> impl Iterator> { SimpleNodeIterator { current: self.GetFirstChild(), @@ -1224,9 +1220,13 @@ impl LayoutNodeHelpers for LayoutDom { #[inline] #[allow(unsafe_code)] unsafe fn parent_node_ref(&self) -> Option> { - (*self.unsafe_get()) - .composed_parent_node - .get_inner_as_layout() + let parent = (*self.unsafe_get()).parent_node.get_inner_as_layout(); + if let Some(ref parent) = parent { + if let Some(shadow_root) = parent.downcast::() { + return Some(shadow_root.get_host_for_layout().upcast()); + } + } + parent } #[inline] @@ -1629,7 +1629,6 @@ impl Node { eventtarget: EventTarget::new_inherited(), parent_node: Default::default(), - composed_parent_node: Default::default(), first_child: Default::default(), last_child: Default::default(), next_sibling: Default::default(), diff --git a/components/style/dom_apis.rs b/components/style/dom_apis.rs index 1ef07e24a4a..c66bb66c9f5 100644 --- a/components/style/dom_apis.rs +++ b/components/style/dom_apis.rs @@ -231,7 +231,7 @@ where // Optimize for when the root is a document or a shadow root and the element // is connected to that root. if root.as_document().is_some() { - debug_assert!(element.as_node().is_connected(), "Not connected?"); + debug_assert!(element.as_node().is_in_document(), "Not connected?"); debug_assert_eq!( root, root.owner_doc().as_node(), @@ -241,10 +241,11 @@ where } if root.as_shadow_root().is_some() { + debug_assert!(element.as_node().is_in_document(), "Not connected?"); debug_assert_eq!( element.containing_shadow().unwrap().as_node(), root, - "Not connected?" + "Where did this element come from?" ); return true; } @@ -275,7 +276,7 @@ where return Err(()); } - if root.is_connected() { + if root.is_in_document() { if let Some(shadow) = root.as_shadow_root() { return shadow.elements_with_id(id); } From ccf8a436490992d01ad4bd99e79a2b4e2e649361 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Mon, 4 Mar 2019 14:22:52 +0100 Subject: [PATCH 56/83] Document owner_shadow_root --- components/script/dom/node.rs | 10 +++++++--- components/script/dom/shadowroot.rs | 7 +++---- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 7c50e4ae69d..22e157f3132 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -125,6 +125,8 @@ pub struct Node { owner_doc: MutNullableDom, /// The shadow root this node belongs to. + /// This is None if the node is not in a shadow tree or + /// if it is a ShadowRoot. owner_shadow_root: MutNullableDom, /// The live list of children return by .childNodes. @@ -284,11 +286,10 @@ impl Node { for node in new_child.traverse_preorder(ShadowIncluding::No) { if parent_in_shadow_tree { - if let Some(shadow_root) = self.downcast::() { - node.set_owner_shadow_root(&*shadow_root); - } else if let Some(shadow_root) = self.owner_shadow_root() { + if let Some(shadow_root) = self.owner_shadow_root() { node.set_owner_shadow_root(&*shadow_root); } + debug_assert!(node.owner_shadow_root().is_some()); } node.set_flag(NodeFlags::IS_IN_DOC, parent_in_doc); node.set_flag(NodeFlags::IS_IN_SHADOW_TREE, parent_in_shadow_tree); @@ -930,6 +931,9 @@ impl Node { } pub fn owner_shadow_root(&self) -> Option> { + if let Some(ref shadow_root) = self.downcast::() { + return Some(DomRoot::from_ref(shadow_root)); + } self.owner_shadow_root.get() } diff --git a/components/script/dom/shadowroot.rs b/components/script/dom/shadowroot.rs index fb38c5531c6..078c937d701 100644 --- a/components/script/dom/shadowroot.rs +++ b/components/script/dom/shadowroot.rs @@ -44,10 +44,9 @@ impl ShadowRoot { #[allow(unrooted_must_root)] fn new_inherited(host: &Element, document: &Document) -> ShadowRoot { let document_fragment = DocumentFragment::new_inherited(document); - document_fragment - .upcast::() - .set_flag(NodeFlags::IS_IN_SHADOW_TREE, true); - document_fragment.upcast::().set_flag( + let node = document_fragment.upcast::(); + node.set_flag(NodeFlags::IS_IN_SHADOW_TREE, true); + node.set_flag( NodeFlags::IS_CONNECTED, host.upcast::().is_connected(), ); From 740aae06bad9e5ff864c914117cab1e74a727614 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Tue, 5 Mar 2019 10:23:18 +0100 Subject: [PATCH 57/83] Register named elements in either the document or shadow tree --- components/script/dom/document.rs | 51 +++------------- components/script/dom/documentfragment.rs | 26 ++++---- components/script/dom/documentorshadowroot.rs | 60 ++++++++++++++++++- components/script/dom/element.rs | 28 +++++++-- components/script/dom/shadowroot.rs | 22 +++++++ .../tests/mozilla/partial_shadow_dom.html | 5 +- 6 files changed, 131 insertions(+), 61 deletions(-) diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 4ec2e67521c..998055d3547 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -74,7 +74,6 @@ use crate::dom::keyboardevent::KeyboardEvent; use crate::dom::location::Location; use crate::dom::messageevent::MessageEvent; use crate::dom::mouseevent::MouseEvent; -use crate::dom::node::VecPreOrderInsertionHelper; use crate::dom::node::{self, document_from_node, window_from_node, CloneChildrenFlag}; use crate::dom::node::{LayoutNodeHelpers, Node, NodeDamage, NodeFlags, ShadowIncluding}; use crate::dom::nodeiterator::NodeIterator; @@ -682,55 +681,23 @@ impl Document { /// Remove any existing association between the provided id and any elements in this document. pub fn unregister_named_element(&self, to_unregister: &Element, id: Atom) { - debug!( - "Removing named element from document {:p}: {:p} id={}", - self, to_unregister, id - ); - // Limit the scope of the borrow because id_map might be borrowed again by - // GetElementById through the following sequence of calls - // reset_form_owner_for_listeners -> reset_form_owner -> GetElementById - { - let mut id_map = self.id_map.borrow_mut(); - let is_empty = match id_map.get_mut(&id) { - None => false, - Some(elements) => { - let position = elements - .iter() - .position(|element| &**element == to_unregister) - .expect("This element should be in registered."); - elements.remove(position); - elements.is_empty() - }, - }; - if is_empty { - id_map.remove(&id); - } - } + self.document_or_shadow_root + .unregister_named_element(&self.id_map, to_unregister, &id); self.reset_form_owner_for_listeners(&id); } /// Associate an element present in this document with the provided id. pub fn register_named_element(&self, element: &Element, id: Atom) { - debug!( - "Adding named element to document {:p}: {:p} id={}", - self, element, id - ); - assert!(element.upcast::().is_connected()); - assert!(!id.is_empty()); - let root = self.GetDocumentElement().expect( "The element is in the document, so there must be a document \ element.", ); - - // Limit the scope of the borrow because id_map might be borrowed again by - // GetElementById through the following sequence of calls - // reset_form_owner_for_listeners -> reset_form_owner -> GetElementById - { - let mut id_map = self.id_map.borrow_mut(); - let elements = id_map.entry(id.clone()).or_insert(Vec::new()); - elements.insert_pre_order(element, root.upcast::()); - } + self.document_or_shadow_root.register_named_element( + &self.id_map, + element, + &id, + DomRoot::from_ref(root.upcast::()), + ); self.reset_form_owner_for_listeners(&id); } @@ -2619,11 +2586,11 @@ impl Document { url: DomRefCell::new(url), // https://dom.spec.whatwg.org/#concept-document-quirks quirks_mode: Cell::new(QuirksMode::NoQuirks), + id_map: DomRefCell::new(HashMap::new()), // https://dom.spec.whatwg.org/#concept-document-encoding encoding: Cell::new(encoding), is_html_document: is_html_document == IsHTMLDocument::HTMLDocument, activity: Cell::new(activity), - id_map: DomRefCell::new(HashMap::new()), tag_map: DomRefCell::new(HashMap::new()), tagns_map: DomRefCell::new(HashMap::new()), classes_map: DomRefCell::new(HashMap::new()), diff --git a/components/script/dom/documentfragment.rs b/components/script/dom/documentfragment.rs index 315e04f830d..1561b0d007e 100644 --- a/components/script/dom/documentfragment.rs +++ b/components/script/dom/documentfragment.rs @@ -2,27 +2,31 @@ * 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::cell::DomRefCell; use crate::dom::bindings::codegen::Bindings::DocumentFragmentBinding; use crate::dom::bindings::codegen::Bindings::DocumentFragmentBinding::DocumentFragmentMethods; use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; use crate::dom::bindings::codegen::UnionTypes::NodeOrString; use crate::dom::bindings::error::{ErrorResult, Fallible}; use crate::dom::bindings::inheritance::Castable; -use crate::dom::bindings::root::DomRoot; +use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::bindings::str::DOMString; use crate::dom::document::Document; use crate::dom::element::Element; use crate::dom::htmlcollection::HTMLCollection; -use crate::dom::node::{window_from_node, Node, ShadowIncluding}; +use crate::dom::node::{window_from_node, Node}; use crate::dom::nodelist::NodeList; use crate::dom::window::Window; use dom_struct::dom_struct; use servo_atoms::Atom; +use std::collections::HashMap; // https://dom.spec.whatwg.org/#documentfragment #[dom_struct] pub struct DocumentFragment { node: Node, + /// Caches for the getElement methods + id_map: DomRefCell>>>, } impl DocumentFragment { @@ -30,6 +34,7 @@ impl DocumentFragment { pub fn new_inherited(document: &Document) -> DocumentFragment { DocumentFragment { node: Node::new_inherited(document), + id_map: DomRefCell::new(HashMap::new()), } } @@ -46,6 +51,10 @@ impl DocumentFragment { Ok(DocumentFragment::new(&document)) } + + pub fn id_map(&self) -> &DomRefCell>>> { + &self.id_map + } } impl DocumentFragmentMethods for DocumentFragment { @@ -57,16 +66,11 @@ impl DocumentFragmentMethods for DocumentFragment { // https://dom.spec.whatwg.org/#dom-nonelementparentnode-getelementbyid fn GetElementById(&self, id: DOMString) -> Option> { - let node = self.upcast::(); let id = Atom::from(id); - node.traverse_preorder(ShadowIncluding::No) - .filter_map(DomRoot::downcast::) - .find( - |descendant| match descendant.get_attribute(&ns!(), &local_name!("id")) { - None => false, - Some(attr) => *attr.value().as_atom() == id, - }, - ) + self.id_map + .borrow() + .get(&id) + .map(|ref elements| DomRoot::from_ref(&*(*elements)[0])) } // https://dom.spec.whatwg.org/#dom-parentnode-firstelementchild diff --git a/components/script/dom/documentorshadowroot.rs b/components/script/dom/documentorshadowroot.rs index 0165c0b8384..5c8428242ee 100644 --- a/components/script/dom/documentorshadowroot.rs +++ b/components/script/dom/documentorshadowroot.rs @@ -2,6 +2,7 @@ * 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::cell::DomRefCell; use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeBinding::NodeMethods; use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::num::Finite; @@ -9,13 +10,15 @@ use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::element::Element; use crate::dom::htmlelement::HTMLElement; use crate::dom::htmlmetaelement::HTMLMetaElement; -use crate::dom::node; +use crate::dom::node::{self, Node, VecPreOrderInsertionHelper}; use crate::dom::window::Window; use euclid::Point2D; use js::jsapi::JS_GetRuntime; use script_layout_interface::message::{NodesFromPointQueryType, QueryMsg}; use script_traits::UntrustedNodeAddress; use servo_arc::Arc; +use servo_atoms::Atom; +use std::collections::HashMap; use std::fmt; use style::context::QuirksMode; use style::invalidation::media_queries::{MediaListKey, ToMediaListKey}; @@ -262,4 +265,59 @@ impl DocumentOrShadowRoot { }, } } + + /// Remove any existing association between the provided id and any elements in this document. + pub fn unregister_named_element( + &self, + id_map: &DomRefCell>>>, + to_unregister: &Element, + id: &Atom, + ) { + debug!( + "Removing named element {:p}: {:p} id={}", + self, to_unregister, id + ); + // Limit the scope of the borrow because id_map might be borrowed again by + // GetElementById through the following sequence of calls + // reset_form_owner_for_listeners -> reset_form_owner -> GetElementById + { + let mut id_map = id_map.borrow_mut(); + let is_empty = match id_map.get_mut(&id) { + None => false, + Some(elements) => { + let position = elements + .iter() + .position(|element| &**element == to_unregister) + .expect("This element should be in registered."); + elements.remove(position); + elements.is_empty() + }, + }; + if is_empty { + id_map.remove(&id); + } + } + } + + /// Associate an element present in this document with the provided id. + pub fn register_named_element( + &self, + id_map: &DomRefCell>>>, + element: &Element, + id: &Atom, + root: DomRoot, + ) { + debug!("Adding named element {:p}: {:p} id={}", self, element, id); + assert!(element.upcast::().is_connected()); + assert!(!id.is_empty()); + + // Limit the scope of the borrow because id_map might be borrowed again by + // GetElementById through the following sequence of calls + // reset_form_owner_for_listeners -> reset_form_owner -> GetElementById + { + let mut id_map = id_map.borrow_mut(); + let elements = id_map.entry(id.clone()).or_insert(Vec::new()); + elements.insert_pre_order(element, &root); + } + } } diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 9d92f196a77..610df336541 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -2741,21 +2741,34 @@ impl VirtualMethods for Element { None } }); + let owner_shadow_root = self.upcast::().owner_shadow_root(); if node.is_connected() { let value = attr.value().as_atom().clone(); match mutation { AttributeMutation::Set(old_value) => { if let Some(old_value) = old_value { let old_value = old_value.as_atom().clone(); - doc.unregister_named_element(self, old_value); + if let Some(ref shadow_root) = owner_shadow_root { + shadow_root.unregister_named_element(self, old_value); + } else { + doc.unregister_named_element(self, old_value); + } } if value != atom!("") { - doc.register_named_element(self, value); + if let Some(ref shadow_root) = owner_shadow_root { + shadow_root.register_named_element(self, value); + } else { + doc.register_named_element(self, value); + } } }, AttributeMutation::Removed => { if value != atom!("") { - doc.unregister_named_element(self, value); + if let Some(ref shadow_root) = owner_shadow_root { + shadow_root.unregister_named_element(self, value); + } else { + doc.unregister_named_element(self, value); + } } }, } @@ -2800,8 +2813,6 @@ impl VirtualMethods for Element { return; } - let doc = document_from_node(self); - if let Some(shadow_root) = self.upcast::().owner_shadow_root() { let shadow_root = shadow_root.upcast::(); shadow_root.set_flag(NodeFlags::IS_CONNECTED, tree_connected); @@ -2811,8 +2822,13 @@ impl VirtualMethods for Element { } } + let doc = document_from_node(self); if let Some(ref value) = *self.id_attribute.borrow() { - doc.register_named_element(self, value.clone()); + if let Some(shadow_root) = self.upcast::().owner_shadow_root() { + shadow_root.register_named_element(self, value.clone()); + } else { + doc.register_named_element(self, value.clone()); + } } // This is used for layout optimization. doc.increment_dom_count(); diff --git a/components/script/dom/shadowroot.rs b/components/script/dom/shadowroot.rs index 078c937d701..55535ad9a9d 100644 --- a/components/script/dom/shadowroot.rs +++ b/components/script/dom/shadowroot.rs @@ -20,6 +20,7 @@ use crate::dom::window::Window; use dom_struct::dom_struct; use selectors::context::QuirksMode; use servo_arc::Arc; +use servo_atoms::Atom; use style::author_styles::AuthorStyles; use style::dom::TElement; use style::media_queries::Device; @@ -126,6 +127,27 @@ impl ShadowRoot { .upcast::() .dirty(NodeDamage::NodeStyleDamaged); } + + /// Remove any existing association between the provided id and any elements + /// in this shadow tree. + pub fn unregister_named_element(&self, to_unregister: &Element, id: Atom) { + self.document_or_shadow_root.unregister_named_element( + self.document_fragment.id_map(), + to_unregister, + &id, + ); + } + + /// Associate an element present in this shadow tree with the provided id. + pub fn register_named_element(&self, element: &Element, id: Atom) { + let root = self.upcast::().inclusive_ancestors().last().unwrap(); + self.document_or_shadow_root.register_named_element( + self.document_fragment.id_map(), + element, + &id, + root, + ); + } } impl ShadowRootMethods for ShadowRoot { diff --git a/tests/wpt/mozilla/tests/mozilla/partial_shadow_dom.html b/tests/wpt/mozilla/tests/mozilla/partial_shadow_dom.html index d97f1422d20..74e308f9403 100644 --- a/tests/wpt/mozilla/tests/mozilla/partial_shadow_dom.html +++ b/tests/wpt/mozilla/tests/mozilla/partial_shadow_dom.html @@ -6,7 +6,7 @@ -

Not in the shadows

+

Not in the shadows

From 813b242419d41505641b433c3b38b0d0542c559d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Tue, 5 Mar 2019 18:01:59 +0100 Subject: [PATCH 58/83] Introduce BindContext with in_doc and connected flags Fix some is_in_doc -> is_connected mistakes --- components/script/dom/element.rs | 23 ++++++++++---------- components/script/dom/htmlbaseelement.rs | 14 ++++++------ components/script/dom/htmlbodyelement.rs | 8 +++---- components/script/dom/htmlbuttonelement.rs | 6 ++--- components/script/dom/htmlelement.rs | 6 ++--- components/script/dom/htmlheadelement.rs | 6 ++--- components/script/dom/htmliframeelement.rs | 9 +++++--- components/script/dom/htmlimageelement.rs | 10 +++++---- components/script/dom/htmlinputelement.rs | 6 ++--- components/script/dom/htmllegendelement.rs | 6 ++--- components/script/dom/htmllinkelement.rs | 9 ++++---- components/script/dom/htmlmetaelement.rs | 9 ++++---- components/script/dom/htmloptionelement.rs | 6 ++--- components/script/dom/htmlscriptelement.rs | 8 +++---- components/script/dom/htmlselectelement.rs | 7 +++--- components/script/dom/htmlsourceelement.rs | 6 ++--- components/script/dom/htmlstyleelement.rs | 10 ++++----- components/script/dom/htmltextareaelement.rs | 8 ++++--- components/script/dom/htmltitleelement.rs | 10 ++++----- components/script/dom/node.rs | 16 +++++++++++++- components/script/dom/virtualmethods.rs | 6 ++--- 21 files changed, 105 insertions(+), 84 deletions(-) diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 610df336541..9ba5f7c21a2 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -72,8 +72,8 @@ use crate::dom::htmltextareaelement::{HTMLTextAreaElement, LayoutHTMLTextAreaEle use crate::dom::mutationobserver::{Mutation, MutationObserver}; use crate::dom::namednodemap::NamedNodeMap; use crate::dom::node::{document_from_node, window_from_node}; +use crate::dom::node::{BindContext, NodeDamage, NodeFlags, UnbindContext}; use crate::dom::node::{ChildrenMutation, LayoutNodeHelpers, Node}; -use crate::dom::node::{NodeDamage, NodeFlags, UnbindContext}; use crate::dom::nodelist::NodeList; use crate::dom::promise::Promise; use crate::dom::servoparser::ServoParser; @@ -2800,28 +2800,28 @@ impl VirtualMethods for Element { } } - fn bind_to_tree(&self, tree_connected: bool) { + fn bind_to_tree(&self, context: &BindContext) { if let Some(ref s) = self.super_type() { - s.bind_to_tree(tree_connected); + s.bind_to_tree(context); } if let Some(f) = self.as_maybe_form_control() { f.bind_form_control_to_tree(); } - if !tree_connected { - return; - } - if let Some(shadow_root) = self.upcast::().owner_shadow_root() { let shadow_root = shadow_root.upcast::(); - shadow_root.set_flag(NodeFlags::IS_CONNECTED, tree_connected); + shadow_root.set_flag(NodeFlags::IS_CONNECTED, context.tree_connected); for node in shadow_root.children() { - node.set_flag(NodeFlags::IS_CONNECTED, tree_connected); - node.bind_to_tree(tree_connected); + node.set_flag(NodeFlags::IS_CONNECTED, context.tree_connected); + node.bind_to_tree(context); } } + if !context.tree_connected { + return; + } + let doc = document_from_node(self); if let Some(ref value) = *self.id_attribute.borrow() { if let Some(shadow_root) = self.upcast::().owner_shadow_root() { @@ -2847,8 +2847,7 @@ impl VirtualMethods for Element { let doc = document_from_node(self); - if self.is_shadow_host() { - let shadow_root = self.shadow_root.get().unwrap(); + if let Some(shadow_root) = self.shadow_root.get() { doc.unregister_shadow_root(&shadow_root); let shadow_root = shadow_root.upcast::(); shadow_root.set_flag(NodeFlags::IS_CONNECTED, false); diff --git a/components/script/dom/htmlbaseelement.rs b/components/script/dom/htmlbaseelement.rs index a08f3ba9c88..fc20091302d 100644 --- a/components/script/dom/htmlbaseelement.rs +++ b/components/script/dom/htmlbaseelement.rs @@ -11,7 +11,7 @@ use crate::dom::bindings::str::DOMString; use crate::dom::document::Document; use crate::dom::element::{AttributeMutation, Element}; use crate::dom::htmlelement::HTMLElement; -use crate::dom::node::{document_from_node, Node, UnbindContext}; +use crate::dom::node::{document_from_node, BindContext, Node, UnbindContext}; use crate::dom::virtualmethods::VirtualMethods; use dom_struct::dom_struct; use html5ever::{LocalName, Prefix}; @@ -63,8 +63,8 @@ impl HTMLBaseElement { /// Update the cached base element in response to binding or unbinding from /// a tree. - pub fn bind_unbind(&self, tree_connected: bool) { - if !tree_connected { + pub fn bind_unbind(&self, tree_in_doc: bool) { + if !tree_in_doc || self.upcast::().owner_shadow_root().is_some() { return; } @@ -119,13 +119,13 @@ impl VirtualMethods for HTMLBaseElement { } } - fn bind_to_tree(&self, tree_connected: bool) { - self.super_type().unwrap().bind_to_tree(tree_connected); - self.bind_unbind(tree_connected); + fn bind_to_tree(&self, context: &BindContext) { + self.super_type().unwrap().bind_to_tree(context); + self.bind_unbind(context.tree_in_doc); } fn unbind_from_tree(&self, context: &UnbindContext) { self.super_type().unwrap().unbind_from_tree(context); - self.bind_unbind(context.tree_connected); + self.bind_unbind(context.tree_in_doc); } } diff --git a/components/script/dom/htmlbodyelement.rs b/components/script/dom/htmlbodyelement.rs index ccef81f2cd8..f59d163d163 100644 --- a/components/script/dom/htmlbodyelement.rs +++ b/components/script/dom/htmlbodyelement.rs @@ -14,7 +14,7 @@ use crate::dom::document::Document; use crate::dom::element::{AttributeMutation, Element, RawLayoutElementHelpers}; use crate::dom::eventtarget::EventTarget; use crate::dom::htmlelement::HTMLElement; -use crate::dom::node::{document_from_node, window_from_node, Node}; +use crate::dom::node::{document_from_node, window_from_node, BindContext, Node}; use crate::dom::virtualmethods::VirtualMethods; use cssparser::RGBA; use dom_struct::dom_struct; @@ -149,12 +149,12 @@ impl VirtualMethods for HTMLBodyElement { .attribute_affects_presentational_hints(attr) } - fn bind_to_tree(&self, tree_connected: bool) { + fn bind_to_tree(&self, context: &BindContext) { if let Some(ref s) = self.super_type() { - s.bind_to_tree(tree_connected); + s.bind_to_tree(context); } - if !tree_connected { + if !context.tree_in_doc { return; } diff --git a/components/script/dom/htmlbuttonelement.rs b/components/script/dom/htmlbuttonelement.rs index 85bb5e2ea56..a7b8dacd060 100755 --- a/components/script/dom/htmlbuttonelement.rs +++ b/components/script/dom/htmlbuttonelement.rs @@ -18,7 +18,7 @@ use crate::dom::htmlfieldsetelement::HTMLFieldSetElement; use crate::dom::htmlformelement::HTMLFormElement; use crate::dom::htmlformelement::{FormControl, FormDatum, FormDatumValue}; use crate::dom::htmlformelement::{FormSubmitter, ResetFrom, SubmittedFrom}; -use crate::dom::node::{document_from_node, window_from_node, Node, UnbindContext}; +use crate::dom::node::{document_from_node, window_from_node, BindContext, Node, UnbindContext}; use crate::dom::nodelist::NodeList; use crate::dom::validation::Validatable; use crate::dom::validitystate::{ValidationFlags, ValidityState}; @@ -232,9 +232,9 @@ impl VirtualMethods for HTMLButtonElement { } } - fn bind_to_tree(&self, tree_connected: bool) { + fn bind_to_tree(&self, context: &BindContext) { if let Some(ref s) = self.super_type() { - s.bind_to_tree(tree_connected); + s.bind_to_tree(context); } self.upcast::() diff --git a/components/script/dom/htmlelement.rs b/components/script/dom/htmlelement.rs index 4bbbfd14cb7..95ac9918996 100644 --- a/components/script/dom/htmlelement.rs +++ b/components/script/dom/htmlelement.rs @@ -28,7 +28,7 @@ use crate::dom::htmlhtmlelement::HTMLHtmlElement; use crate::dom::htmlinputelement::{HTMLInputElement, InputType}; use crate::dom::htmllabelelement::HTMLLabelElement; use crate::dom::node::{document_from_node, window_from_node}; -use crate::dom::node::{Node, NodeFlags, ShadowIncluding}; +use crate::dom::node::{BindContext, Node, NodeFlags, ShadowIncluding}; use crate::dom::nodelist::NodeList; use crate::dom::text::Text; use crate::dom::virtualmethods::VirtualMethods; @@ -740,9 +740,9 @@ impl VirtualMethods for HTMLElement { } } - fn bind_to_tree(&self, tree_in_doc: bool) { + fn bind_to_tree(&self, context: &BindContext) { if let Some(ref s) = self.super_type() { - s.bind_to_tree(tree_in_doc); + s.bind_to_tree(context); } self.update_sequentially_focusable_status(); } diff --git a/components/script/dom/htmlheadelement.rs b/components/script/dom/htmlheadelement.rs index 0cea69dff5e..0389ff9b43b 100644 --- a/components/script/dom/htmlheadelement.rs +++ b/components/script/dom/htmlheadelement.rs @@ -10,7 +10,7 @@ use crate::dom::document::{determine_policy_for_token, Document}; use crate::dom::element::Element; use crate::dom::htmlelement::HTMLElement; use crate::dom::htmlmetaelement::HTMLMetaElement; -use crate::dom::node::{document_from_node, Node, ShadowIncluding}; +use crate::dom::node::{document_from_node, BindContext, Node, ShadowIncluding}; use crate::dom::userscripts::load_script; use crate::dom::virtualmethods::VirtualMethods; use dom_struct::dom_struct; @@ -81,9 +81,9 @@ impl VirtualMethods for HTMLHeadElement { fn super_type(&self) -> Option<&dyn VirtualMethods> { Some(self.upcast::() as &dyn VirtualMethods) } - fn bind_to_tree(&self, tree_connected: bool) { + fn bind_to_tree(&self, context: &BindContext) { if let Some(ref s) = self.super_type() { - s.bind_to_tree(tree_connected); + s.bind_to_tree(context); } load_script(self); } diff --git a/components/script/dom/htmliframeelement.rs b/components/script/dom/htmliframeelement.rs index a1afa73bddc..a85b9bfa915 100644 --- a/components/script/dom/htmliframeelement.rs +++ b/components/script/dom/htmliframeelement.rs @@ -19,7 +19,9 @@ use crate::dom::element::{AttributeMutation, Element, RawLayoutElementHelpers}; use crate::dom::eventtarget::EventTarget; use crate::dom::globalscope::GlobalScope; use crate::dom::htmlelement::HTMLElement; -use crate::dom::node::{document_from_node, window_from_node, Node, NodeDamage, UnbindContext}; +use crate::dom::node::{ + document_from_node, window_from_node, BindContext, Node, NodeDamage, UnbindContext, +}; use crate::dom::virtualmethods::VirtualMethods; use crate::dom::window::ReflowReason; use crate::dom::windowproxy::WindowProxy; @@ -610,11 +612,12 @@ impl VirtualMethods for HTMLIFrameElement { } } - fn bind_to_tree(&self, tree_connected: bool) { + fn bind_to_tree(&self, context: &BindContext) { if let Some(ref s) = self.super_type() { - s.bind_to_tree(tree_connected); + s.bind_to_tree(context); } + let tree_connected = context.tree_connected; let iframe = Trusted::new(self); document_from_node(self).add_delayed_task(task!(IFrameDelayedInitialize: move || { let this = iframe.root(); diff --git a/components/script/dom/htmlimageelement.rs b/components/script/dom/htmlimageelement.rs index efb372770b1..62a369579a1 100644 --- a/components/script/dom/htmlimageelement.rs +++ b/components/script/dom/htmlimageelement.rs @@ -33,7 +33,9 @@ use crate::dom::htmlpictureelement::HTMLPictureElement; use crate::dom::htmlsourceelement::HTMLSourceElement; use crate::dom::mouseevent::MouseEvent; use crate::dom::node::UnbindContext; -use crate::dom::node::{document_from_node, window_from_node, Node, NodeDamage, ShadowIncluding}; +use crate::dom::node::{ + document_from_node, window_from_node, BindContext, Node, NodeDamage, ShadowIncluding, +}; use crate::dom::performanceresourcetiming::InitiatorType; use crate::dom::progressevent::ProgressEvent; use crate::dom::values::UNSIGNED_LONG_MAX; @@ -1646,12 +1648,12 @@ impl VirtualMethods for HTMLImageElement { } } - fn bind_to_tree(&self, tree_connected: bool) { + fn bind_to_tree(&self, context: &BindContext) { if let Some(ref s) = self.super_type() { - s.bind_to_tree(tree_connected); + s.bind_to_tree(context); } let document = document_from_node(self); - if tree_connected { + if context.tree_connected { document.register_responsive_image(self); } diff --git a/components/script/dom/htmlinputelement.rs b/components/script/dom/htmlinputelement.rs index 7adda0a1cae..e9a3923b5d0 100755 --- a/components/script/dom/htmlinputelement.rs +++ b/components/script/dom/htmlinputelement.rs @@ -35,7 +35,7 @@ use crate::dom::htmlformelement::{ResetFrom, SubmittedFrom}; use crate::dom::keyboardevent::KeyboardEvent; use crate::dom::mouseevent::MouseEvent; use crate::dom::node::{document_from_node, window_from_node}; -use crate::dom::node::{Node, NodeDamage, UnbindContext}; +use crate::dom::node::{BindContext, Node, NodeDamage, UnbindContext}; use crate::dom::nodelist::NodeList; use crate::dom::textcontrol::{TextControlElement, TextControlSelection}; use crate::dom::validation::Validatable; @@ -1422,9 +1422,9 @@ impl VirtualMethods for HTMLInputElement { } } - fn bind_to_tree(&self, tree_connected: bool) { + fn bind_to_tree(&self, context: &BindContext) { if let Some(ref s) = self.super_type() { - s.bind_to_tree(tree_connected); + s.bind_to_tree(context); } self.upcast::() .check_ancestors_disabled_state_for_form_control(); diff --git a/components/script/dom/htmllegendelement.rs b/components/script/dom/htmllegendelement.rs index a623eb5cd79..41cf7d3d8ff 100644 --- a/components/script/dom/htmllegendelement.rs +++ b/components/script/dom/htmllegendelement.rs @@ -12,7 +12,7 @@ use crate::dom::element::Element; use crate::dom::htmlelement::HTMLElement; use crate::dom::htmlfieldsetelement::HTMLFieldSetElement; use crate::dom::htmlformelement::{FormControl, HTMLFormElement}; -use crate::dom::node::{Node, UnbindContext}; +use crate::dom::node::{BindContext, Node, UnbindContext}; use crate::dom::virtualmethods::VirtualMethods; use dom_struct::dom_struct; use html5ever::{LocalName, Prefix}; @@ -56,9 +56,9 @@ impl VirtualMethods for HTMLLegendElement { Some(self.upcast::() as &dyn VirtualMethods) } - fn bind_to_tree(&self, tree_connected: bool) { + fn bind_to_tree(&self, context: &BindContext) { if let Some(ref s) = self.super_type() { - s.bind_to_tree(tree_connected); + s.bind_to_tree(context); } self.upcast::() diff --git a/components/script/dom/htmllinkelement.rs b/components/script/dom/htmllinkelement.rs index d47d9343e53..8dd50c11441 100644 --- a/components/script/dom/htmllinkelement.rs +++ b/components/script/dom/htmllinkelement.rs @@ -19,7 +19,8 @@ use crate::dom::element::{ use crate::dom::element::{AttributeMutation, Element, ElementCreator}; use crate::dom::htmlelement::HTMLElement; use crate::dom::node::{ - document_from_node, stylesheets_owner_from_node, window_from_node, Node, UnbindContext, + document_from_node, stylesheets_owner_from_node, window_from_node, BindContext, Node, + UnbindContext, }; use crate::dom::stylesheet::StyleSheet as DOMStyleSheet; use crate::dom::virtualmethods::VirtualMethods; @@ -225,12 +226,12 @@ impl VirtualMethods for HTMLLinkElement { } } - fn bind_to_tree(&self, tree_connected: bool) { + fn bind_to_tree(&self, context: &BindContext) { if let Some(ref s) = self.super_type() { - s.bind_to_tree(tree_connected); + s.bind_to_tree(context); } - if tree_connected { + if context.tree_connected { let element = self.upcast(); let rel = get_attr(element, &local_name!("rel")); diff --git a/components/script/dom/htmlmetaelement.rs b/components/script/dom/htmlmetaelement.rs index ffaf30e89f7..11b5706516d 100644 --- a/components/script/dom/htmlmetaelement.rs +++ b/components/script/dom/htmlmetaelement.rs @@ -16,7 +16,8 @@ use crate::dom::element::{AttributeMutation, Element}; use crate::dom::htmlelement::HTMLElement; use crate::dom::htmlheadelement::HTMLHeadElement; use crate::dom::node::{ - document_from_node, stylesheets_owner_from_node, window_from_node, Node, UnbindContext, + document_from_node, stylesheets_owner_from_node, window_from_node, BindContext, Node, + UnbindContext, }; use crate::dom::virtualmethods::VirtualMethods; use dom_struct::dom_struct; @@ -175,12 +176,12 @@ impl VirtualMethods for HTMLMetaElement { Some(self.upcast::() as &dyn VirtualMethods) } - fn bind_to_tree(&self, tree_connected: bool) { + fn bind_to_tree(&self, context: &BindContext) { if let Some(ref s) = self.super_type() { - s.bind_to_tree(tree_connected); + s.bind_to_tree(context); } - if tree_connected { + if context.tree_connected { self.process_attributes(); } } diff --git a/components/script/dom/htmloptionelement.rs b/components/script/dom/htmloptionelement.rs index e232aa63712..e9e2ce89c28 100644 --- a/components/script/dom/htmloptionelement.rs +++ b/components/script/dom/htmloptionelement.rs @@ -19,7 +19,7 @@ use crate::dom::htmlformelement::HTMLFormElement; use crate::dom::htmloptgroupelement::HTMLOptGroupElement; use crate::dom::htmlscriptelement::HTMLScriptElement; use crate::dom::htmlselectelement::HTMLSelectElement; -use crate::dom::node::{Node, UnbindContext}; +use crate::dom::node::{BindContext, Node, UnbindContext}; use crate::dom::text::Text; use crate::dom::virtualmethods::VirtualMethods; use dom_struct::dom_struct; @@ -235,9 +235,9 @@ impl VirtualMethods for HTMLOptionElement { } } - fn bind_to_tree(&self, tree_connected: bool) { + fn bind_to_tree(&self, context: &BindContext) { if let Some(ref s) = self.super_type() { - s.bind_to_tree(tree_connected); + s.bind_to_tree(context); } self.upcast::() diff --git a/components/script/dom/htmlscriptelement.rs b/components/script/dom/htmlscriptelement.rs index 299c66a04d8..8d44c4b9ffd 100644 --- a/components/script/dom/htmlscriptelement.rs +++ b/components/script/dom/htmlscriptelement.rs @@ -22,7 +22,7 @@ use crate::dom::event::{Event, EventBubbles, EventCancelable, EventStatus}; use crate::dom::globalscope::GlobalScope; use crate::dom::htmlelement::HTMLElement; use crate::dom::node::{document_from_node, window_from_node}; -use crate::dom::node::{ChildrenMutation, CloneChildrenFlag, Node}; +use crate::dom::node::{BindContext, ChildrenMutation, CloneChildrenFlag, Node}; use crate::dom::performanceresourcetiming::InitiatorType; use crate::dom::virtualmethods::VirtualMethods; use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener}; @@ -778,12 +778,12 @@ impl VirtualMethods for HTMLScriptElement { } } - fn bind_to_tree(&self, is_connected: bool) { + fn bind_to_tree(&self, context: &BindContext) { if let Some(ref s) = self.super_type() { - s.bind_to_tree(is_connected); + s.bind_to_tree(context); } - if is_connected && !self.parser_inserted.get() { + if context.tree_connected && !self.parser_inserted.get() { let script = Trusted::new(self); document_from_node(self).add_delayed_task(task!(ScriptDelayedInitialize: move || { script.root().prepare(); diff --git a/components/script/dom/htmlselectelement.rs b/components/script/dom/htmlselectelement.rs index 4bcdcc85160..c71a5442e73 100755 --- a/components/script/dom/htmlselectelement.rs +++ b/components/script/dom/htmlselectelement.rs @@ -12,7 +12,6 @@ use crate::dom::bindings::codegen::Bindings::HTMLSelectElementBinding::HTMLSelec use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; use crate::dom::bindings::codegen::UnionTypes::HTMLElementOrLong; use crate::dom::bindings::codegen::UnionTypes::HTMLOptionElementOrHTMLOptGroupElement; -//use dom::bindings::error::ErrorResult; use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::root::{DomRoot, MutNullableDom}; use crate::dom::bindings::str::DOMString; @@ -25,7 +24,7 @@ use crate::dom::htmlformelement::{FormControl, FormDatum, FormDatumValue, HTMLFo use crate::dom::htmloptgroupelement::HTMLOptGroupElement; use crate::dom::htmloptionelement::HTMLOptionElement; use crate::dom::htmloptionscollection::HTMLOptionsCollection; -use crate::dom::node::{window_from_node, Node, UnbindContext}; +use crate::dom::node::{window_from_node, BindContext, Node, UnbindContext}; use crate::dom::nodelist::NodeList; use crate::dom::validation::Validatable; use crate::dom::validitystate::{ValidationFlags, ValidityState}; @@ -382,9 +381,9 @@ impl VirtualMethods for HTMLSelectElement { } } - fn bind_to_tree(&self, tree_connected: bool) { + fn bind_to_tree(&self, context: &BindContext) { if let Some(ref s) = self.super_type() { - s.bind_to_tree(tree_connected); + s.bind_to_tree(context); } self.upcast::() diff --git a/components/script/dom/htmlsourceelement.rs b/components/script/dom/htmlsourceelement.rs index 22a03f5ae6c..f93de93599d 100644 --- a/components/script/dom/htmlsourceelement.rs +++ b/components/script/dom/htmlsourceelement.rs @@ -15,7 +15,7 @@ use crate::dom::element::AttributeMutation; use crate::dom::htmlelement::HTMLElement; use crate::dom::htmlimageelement::HTMLImageElement; use crate::dom::htmlmediaelement::HTMLMediaElement; -use crate::dom::node::{Node, UnbindContext}; +use crate::dom::node::{BindContext, Node, UnbindContext}; use crate::dom::virtualmethods::VirtualMethods; use dom_struct::dom_struct; use html5ever::{LocalName, Prefix}; @@ -82,8 +82,8 @@ impl VirtualMethods for HTMLSourceElement { } /// - fn bind_to_tree(&self, tree_connected: bool) { - self.super_type().unwrap().bind_to_tree(tree_connected); + fn bind_to_tree(&self, context: &BindContext) { + self.super_type().unwrap().bind_to_tree(context); let parent = self.upcast::().GetParentNode().unwrap(); if let Some(media) = parent.downcast::() { media.handle_source_child_insertion(); diff --git a/components/script/dom/htmlstyleelement.rs b/components/script/dom/htmlstyleelement.rs index 4c2d934a892..e483453252a 100644 --- a/components/script/dom/htmlstyleelement.rs +++ b/components/script/dom/htmlstyleelement.rs @@ -13,8 +13,8 @@ use crate::dom::document::Document; use crate::dom::element::{Element, ElementCreator}; use crate::dom::htmlelement::HTMLElement; use crate::dom::node::{ - document_from_node, stylesheets_owner_from_node, window_from_node, ChildrenMutation, Node, - UnbindContext, + document_from_node, stylesheets_owner_from_node, window_from_node, BindContext, + ChildrenMutation, Node, UnbindContext, }; use crate::dom::stylesheet::StyleSheet as DOMStyleSheet; use crate::dom::virtualmethods::VirtualMethods; @@ -187,14 +187,14 @@ impl VirtualMethods for HTMLStyleElement { } } - fn bind_to_tree(&self, tree_connected: bool) { - self.super_type().unwrap().bind_to_tree(tree_connected); + fn bind_to_tree(&self, context: &BindContext) { + self.super_type().unwrap().bind_to_tree(context); // https://html.spec.whatwg.org/multipage/#update-a-style-block // Handles the case when: // "The element is not on the stack of open elements of an HTML parser or XML parser, // and it becomes connected or disconnected." - if tree_connected && !self.in_stack_of_open_elements.get() { + if context.tree_connected && !self.in_stack_of_open_elements.get() { self.parse_own_css(); } } diff --git a/components/script/dom/htmltextareaelement.rs b/components/script/dom/htmltextareaelement.rs index 39057da6347..34dd94b7a36 100755 --- a/components/script/dom/htmltextareaelement.rs +++ b/components/script/dom/htmltextareaelement.rs @@ -24,7 +24,9 @@ use crate::dom::htmlfieldsetelement::HTMLFieldSetElement; use crate::dom::htmlformelement::{FormControl, HTMLFormElement}; use crate::dom::keyboardevent::KeyboardEvent; use crate::dom::node::{document_from_node, window_from_node}; -use crate::dom::node::{ChildrenMutation, CloneChildrenFlag, Node, NodeDamage, UnbindContext}; +use crate::dom::node::{ + BindContext, ChildrenMutation, CloneChildrenFlag, Node, NodeDamage, UnbindContext, +}; use crate::dom::nodelist::NodeList; use crate::dom::textcontrol::{TextControlElement, TextControlSelection}; use crate::dom::validation::Validatable; @@ -466,9 +468,9 @@ impl VirtualMethods for HTMLTextAreaElement { } } - fn bind_to_tree(&self, tree_connected: bool) { + fn bind_to_tree(&self, context: &BindContext) { if let Some(ref s) = self.super_type() { - s.bind_to_tree(tree_connected); + s.bind_to_tree(context); } self.upcast::() diff --git a/components/script/dom/htmltitleelement.rs b/components/script/dom/htmltitleelement.rs index 1c26580eec5..a1e543d34e2 100644 --- a/components/script/dom/htmltitleelement.rs +++ b/components/script/dom/htmltitleelement.rs @@ -10,7 +10,7 @@ use crate::dom::bindings::root::DomRoot; use crate::dom::bindings::str::DOMString; use crate::dom::document::Document; use crate::dom::htmlelement::HTMLElement; -use crate::dom::node::{ChildrenMutation, Node}; +use crate::dom::node::{BindContext, ChildrenMutation, Node}; use crate::dom::virtualmethods::VirtualMethods; use dom_struct::dom_struct; use html5ever::{LocalName, Prefix}; @@ -69,17 +69,17 @@ impl VirtualMethods for HTMLTitleElement { s.children_changed(mutation); } let node = self.upcast::(); - if node.is_connected() { + if node.is_in_doc() { node.owner_doc().title_changed(); } } - fn bind_to_tree(&self, tree_connected: bool) { + fn bind_to_tree(&self, context: &BindContext) { if let Some(ref s) = self.super_type() { - s.bind_to_tree(tree_connected); + s.bind_to_tree(context); } let node = self.upcast::(); - if tree_connected { + if context.tree_in_doc { node.owner_doc().title_changed(); } } diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 22e157f3132..8070481045a 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -296,7 +296,10 @@ impl Node { node.set_flag(NodeFlags::IS_CONNECTED, parent_is_connected); // Out-of-document elements never have the descendants flag set. debug_assert!(!node.get_flag(NodeFlags::HAS_DIRTY_DESCENDANTS)); - vtable_for(&&*node).bind_to_tree(parent_is_connected); + vtable_for(&&*node).bind_to_tree(&BindContext { + tree_connected: parent_is_connected, + tree_in_doc: parent_in_doc, + }); } } @@ -3025,6 +3028,14 @@ impl<'a> ChildrenMutation<'a> { } } +/// The context of the binding to tree of a node. +pub struct BindContext { + /// Whether the tree is connected. + pub tree_connected: bool, + /// Whether the tree is in the document. + pub tree_in_doc: bool, +} + /// The context of the unbinding from a tree of a node when one of its /// inclusive ancestors is removed. pub struct UnbindContext<'a> { @@ -3038,6 +3049,8 @@ pub struct UnbindContext<'a> { pub next_sibling: Option<&'a Node>, /// Whether the tree is connected. pub tree_connected: bool, + /// Whether the tree is in doc. + pub tree_in_doc: bool, } impl<'a> UnbindContext<'a> { @@ -3054,6 +3067,7 @@ impl<'a> UnbindContext<'a> { prev_sibling: prev_sibling, next_sibling: next_sibling, tree_connected: parent.is_connected(), + tree_in_doc: parent.is_in_doc(), } } diff --git a/components/script/dom/virtualmethods.rs b/components/script/dom/virtualmethods.rs index 2bb90e93b53..f3b8b633232 100644 --- a/components/script/dom/virtualmethods.rs +++ b/components/script/dom/virtualmethods.rs @@ -51,7 +51,7 @@ use crate::dom::htmltemplateelement::HTMLTemplateElement; use crate::dom::htmltextareaelement::HTMLTextAreaElement; use crate::dom::htmltitleelement::HTMLTitleElement; use crate::dom::htmlvideoelement::HTMLVideoElement; -use crate::dom::node::{ChildrenMutation, CloneChildrenFlag, Node, UnbindContext}; +use crate::dom::node::{BindContext, ChildrenMutation, CloneChildrenFlag, Node, UnbindContext}; use crate::dom::svgsvgelement::SVGSVGElement; use html5ever::LocalName; use style::attr::AttrValue; @@ -92,9 +92,9 @@ pub trait VirtualMethods { /// Called when a Node is appended to a tree, where 'tree_connected' indicates /// whether the tree is part of a Document. - fn bind_to_tree(&self, tree_connected: bool) { + fn bind_to_tree(&self, context: &BindContext) { if let Some(ref s) = self.super_type() { - s.bind_to_tree(tree_connected); + s.bind_to_tree(context); } } From 6af4729f42fc7d663a6b6ede5588732ec80e7dc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Wed, 6 Mar 2019 15:34:25 +0100 Subject: [PATCH 59/83] Introduce NodeRareData and ElementRareData --- components/script/dom/element.rs | 18 ++++++++++-------- components/script/dom/mod.rs | 1 + components/script/dom/node.rs | 20 +++++++++++--------- components/script/dom/raredata.rs | 24 ++++++++++++++++++++++++ 4 files changed, 46 insertions(+), 17 deletions(-) create mode 100644 components/script/dom/raredata.rs diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 9ba5f7c21a2..ce4a3ac5268 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -76,6 +76,7 @@ use crate::dom::node::{BindContext, NodeDamage, NodeFlags, UnbindContext}; use crate::dom::node::{ChildrenMutation, LayoutNodeHelpers, Node}; use crate::dom::nodelist::NodeList; use crate::dom::promise::Promise; +use crate::dom::raredata::ElementRareData; use crate::dom::servoparser::ServoParser; use crate::dom::shadowroot::ShadowRoot; use crate::dom::text::Text; @@ -172,10 +173,7 @@ pub struct Element { custom_element_definition: DomRefCell>>, /// custom_element_state: Cell, - /// https://dom.spec.whatwg.org/#dom-element-shadowroot - /// XXX This is currently not exposed to web content. Only for - /// internal use. - shadow_root: MutNullableDom, + rare_data: Box, } impl fmt::Debug for Element { @@ -310,7 +308,7 @@ impl Element { custom_element_reaction_queue: Default::default(), custom_element_definition: Default::default(), custom_element_state: Cell::new(CustomElementState::Uncustomized), - shadow_root: Default::default(), + rare_data: Default::default(), } } @@ -452,7 +450,7 @@ impl Element { } pub fn is_shadow_host(&self) -> bool { - self.shadow_root.get().is_some() + self.rare_data.shadow_root.get().is_some() } /// https://dom.spec.whatwg.org/#dom-element-attachshadow @@ -496,6 +494,7 @@ impl Element { // Steps 4, 5 and 6. let shadow_root = self + .rare_data .shadow_root .or_init(|| ShadowRoot::new(self, &*self.node.owner_doc())); @@ -1070,7 +1069,10 @@ impl LayoutElementHelpers for LayoutDom { #[inline] #[allow(unsafe_code)] unsafe fn get_shadow_root_for_layout(&self) -> Option> { - (*self.unsafe_get()).shadow_root.get_inner_as_layout() + (*self.unsafe_get()) + .rare_data + .shadow_root + .get_inner_as_layout() } } @@ -2847,7 +2849,7 @@ impl VirtualMethods for Element { let doc = document_from_node(self); - if let Some(shadow_root) = self.shadow_root.get() { + if let Some(shadow_root) = self.rare_data.shadow_root.get() { doc.unregister_shadow_root(&shadow_root); let shadow_root = shadow_root.upcast::(); shadow_root.set_flag(NodeFlags::IS_CONNECTED, false); diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs index 15d3ba34a23..776d20299c1 100644 --- a/components/script/dom/mod.rs +++ b/components/script/dom/mod.rs @@ -443,6 +443,7 @@ pub mod promisenativehandler; pub mod promiserejectionevent; pub mod radionodelist; pub mod range; +pub mod raredata; pub mod request; pub mod response; pub mod rtcicecandidate; diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 8070481045a..f8b6de5cb24 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -53,6 +53,7 @@ use crate::dom::mutationobserver::{Mutation, MutationObserver, RegisteredObserve use crate::dom::nodelist::NodeList; use crate::dom::processinginstruction::ProcessingInstruction; use crate::dom::range::WeakRangeVec; +use crate::dom::raredata::NodeRareData; use crate::dom::shadowroot::{LayoutShadowRootHelpers, ShadowRoot}; use crate::dom::stylesheetlist::StyleSheetListOwner; use crate::dom::svgsvgelement::{LayoutSVGSVGElementHelpers, SVGSVGElement}; @@ -124,10 +125,8 @@ pub struct Node { /// The document that this node belongs to. owner_doc: MutNullableDom, - /// The shadow root this node belongs to. - /// This is None if the node is not in a shadow tree or - /// if it is a ShadowRoot. - owner_shadow_root: MutNullableDom, + /// Rare node data. + rare_data: Box, /// The live list of children return by .childNodes. child_list: MutNullableDom, @@ -937,11 +936,11 @@ impl Node { if let Some(ref shadow_root) = self.downcast::() { return Some(DomRoot::from_ref(shadow_root)); } - self.owner_shadow_root.get() + self.rare_data.owner_shadow_root.get() } pub fn set_owner_shadow_root(&self, shadow_root: &ShadowRoot) { - self.owner_shadow_root.set(Some(shadow_root)); + self.rare_data.owner_shadow_root.set(Some(shadow_root)); } pub fn is_in_html_doc(&self) -> bool { @@ -1272,7 +1271,10 @@ impl LayoutNodeHelpers for LayoutDom { #[inline] #[allow(unsafe_code)] unsafe fn owner_shadow_root_for_layout(&self) -> Option> { - (*self.unsafe_get()).owner_shadow_root.get_inner_as_layout() + (*self.unsafe_get()) + .rare_data + .owner_shadow_root + .get_inner_as_layout() } #[inline] @@ -1641,7 +1643,7 @@ impl Node { next_sibling: Default::default(), prev_sibling: Default::default(), owner_doc: MutNullableDom::new(doc), - owner_shadow_root: Default::default(), + rare_data: Default::default(), child_list: Default::default(), children_count: Cell::new(0u32), flags: Cell::new(flags), @@ -2280,7 +2282,7 @@ impl NodeMethods for Node { // https://dom.spec.whatwg.org/#dom-node-getrootnode fn GetRootNode(&self, options: &GetRootNodeOptions) -> DomRoot { if options.composed { - if let Some(shadow_root) = self.owner_shadow_root.get() { + if let Some(shadow_root) = self.rare_data.owner_shadow_root.get() { // shadow-including root. return shadow_root.Host().upcast::().GetRootNode(options); } diff --git a/components/script/dom/raredata.rs b/components/script/dom/raredata.rs new file mode 100644 index 00000000000..65b47a40e41 --- /dev/null +++ b/components/script/dom/raredata.rs @@ -0,0 +1,24 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * 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::root::MutNullableDom; +use crate::dom::shadowroot::ShadowRoot; + +#[derive(Default, JSTraceable, MallocSizeOf)] +#[must_root] +pub struct NodeRareData { + /// The shadow root the node belongs to. + /// This is None if the node is not in a shadow tree or + /// if it is a ShadowRoot. + pub owner_shadow_root: MutNullableDom, +} + +#[derive(Default, JSTraceable, MallocSizeOf)] +#[must_root] +pub struct ElementRareData { + /// https://dom.spec.whatwg.org/#dom-element-shadowroot + /// XXX This is currently not exposed to web content. Only for + /// internal use. + pub shadow_root: MutNullableDom, +} From a9019da39d5a47e62f51aa3ab568389daccbe9bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Wed, 6 Mar 2019 16:05:59 +0100 Subject: [PATCH 60/83] Move mutation observers list to NodeRareData --- components/script/dom/node.rs | 11 +++-------- components/script/dom/raredata.rs | 4 ++++ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index f8b6de5cb24..f93679a3976 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -5,7 +5,6 @@ //! The core DOM types. Defines the basic DOM hierarchy as well as all the HTML elements. use crate::document_loader::DocumentLoader; -use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::codegen::Bindings::CharacterDataBinding::CharacterDataMethods; use crate::dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods; use crate::dom::bindings::codegen::Bindings::ElementBinding::ElementMethods; @@ -152,9 +151,6 @@ pub struct Node { /// node is finalized. style_and_layout_data: Cell>, - /// Registered observers for this node. - mutation_observers: DomRefCell>, - unique_id: UniqueId, } @@ -454,12 +450,13 @@ impl Node { /// Return all registered mutation observers for this node. pub fn registered_mutation_observers(&self) -> RefMut> { - self.mutation_observers.borrow_mut() + self.rare_data.mutation_observers.borrow_mut() } /// Removes the mutation observer for a given node. pub fn remove_mutation_observer(&self, observer: &MutationObserver) { - self.mutation_observers + self.rare_data + .mutation_observers .borrow_mut() .retain(|reg_obs| &*reg_obs.observer != observer) } @@ -1652,8 +1649,6 @@ impl Node { style_and_layout_data: Cell::new(None), - mutation_observers: Default::default(), - unique_id: UniqueId::new(), } } diff --git a/components/script/dom/raredata.rs b/components/script/dom/raredata.rs index 65b47a40e41..05383197da7 100644 --- a/components/script/dom/raredata.rs +++ b/components/script/dom/raredata.rs @@ -2,7 +2,9 @@ * 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::cell::DomRefCell; use crate::dom::bindings::root::MutNullableDom; +use crate::dom::mutationobserver::RegisteredObserver; use crate::dom::shadowroot::ShadowRoot; #[derive(Default, JSTraceable, MallocSizeOf)] @@ -12,6 +14,8 @@ pub struct NodeRareData { /// This is None if the node is not in a shadow tree or /// if it is a ShadowRoot. pub owner_shadow_root: MutNullableDom, + /// Registered observers for this node. + pub mutation_observers: DomRefCell>, } #[derive(Default, JSTraceable, MallocSizeOf)] From c75da615bdf2cd850859253768bf79a7c4050d0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Wed, 6 Mar 2019 16:34:16 +0100 Subject: [PATCH 61/83] Add custom elements related stuff into ElementRareData --- .../script/dom/bindings/htmlconstructor.rs | 4 +- components/script/dom/create.rs | 6 ++- .../script/dom/customelementregistry.rs | 17 ++++++- components/script/dom/element.rs | 49 ++++++++----------- components/script/dom/raredata.rs | 12 +++++ 5 files changed, 54 insertions(+), 34 deletions(-) diff --git a/components/script/dom/bindings/htmlconstructor.rs b/components/script/dom/bindings/htmlconstructor.rs index 5654b52938b..a13b6fa9ecb 100644 --- a/components/script/dom/bindings/htmlconstructor.rs +++ b/components/script/dom/bindings/htmlconstructor.rs @@ -72,8 +72,8 @@ use crate::dom::bindings::conversions::DerivedFrom; use crate::dom::bindings::error::{Error, Fallible}; use crate::dom::bindings::root::DomRoot; use crate::dom::create::create_native_html_element; -use crate::dom::customelementregistry::ConstructionStackEntry; -use crate::dom::element::{CustomElementState, Element, ElementCreator}; +use crate::dom::customelementregistry::{ConstructionStackEntry, CustomElementState}; +use crate::dom::element::{Element, ElementCreator}; use crate::dom::htmlelement::HTMLElement; use crate::dom::window::Window; use crate::script_thread::ScriptThread; diff --git a/components/script/dom/create.rs b/components/script/dom/create.rs index 461e37a28de..6ffb38f753a 100644 --- a/components/script/dom/create.rs +++ b/components/script/dom/create.rs @@ -5,9 +5,11 @@ use crate::dom::bindings::error::{report_pending_exception, throw_dom_exception}; use crate::dom::bindings::reflector::DomObject; use crate::dom::bindings::root::DomRoot; -use crate::dom::customelementregistry::{is_valid_custom_element_name, upgrade_element}; +use crate::dom::customelementregistry::{ + is_valid_custom_element_name, upgrade_element, CustomElementState, +}; use crate::dom::document::Document; -use crate::dom::element::{CustomElementCreationMode, CustomElementState, Element, ElementCreator}; +use crate::dom::element::{CustomElementCreationMode, Element, ElementCreator}; use crate::dom::globalscope::GlobalScope; use crate::dom::htmlanchorelement::HTMLAnchorElement; use crate::dom::htmlareaelement::HTMLAreaElement; diff --git a/components/script/dom/customelementregistry.rs b/components/script/dom/customelementregistry.rs index ff109f3c966..e1b3163bf4a 100644 --- a/components/script/dom/customelementregistry.rs +++ b/components/script/dom/customelementregistry.rs @@ -23,7 +23,7 @@ use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::bindings::str::DOMString; use crate::dom::document::Document; use crate::dom::domexception::{DOMErrorName, DOMException}; -use crate::dom::element::{CustomElementState, Element}; +use crate::dom::element::Element; use crate::dom::globalscope::GlobalScope; use crate::dom::htmlelement::HTMLElement; use crate::dom::node::{document_from_node, window_from_node, Node, ShadowIncluding}; @@ -47,6 +47,21 @@ use std::ops::Deref; use std::ptr; use std::rc::Rc; +/// +#[derive(Clone, Copy, Eq, JSTraceable, MallocSizeOf, PartialEq)] +pub enum CustomElementState { + Undefined, + Failed, + Uncustomized, + Custom, +} + +impl Default for CustomElementState { + fn default() -> CustomElementState { + CustomElementState::Uncustomized + } +} + /// #[dom_struct] pub struct CustomElementRegistry { diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index ce4a3ac5268..a27af0f99b3 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -33,7 +33,7 @@ use crate::dom::bindings::xmlname::{ use crate::dom::characterdata::CharacterData; use crate::dom::create::create_element; use crate::dom::customelementregistry::{ - CallbackReaction, CustomElementDefinition, CustomElementReaction, + CallbackReaction, CustomElementDefinition, CustomElementReaction, CustomElementState, }; use crate::dom::document::{Document, LayoutDocumentHelpers}; use crate::dom::documentfragment::DocumentFragment; @@ -166,13 +166,6 @@ pub struct Element { /// when it has exclusive access to the element. #[ignore_malloc_size_of = "bitflags defined in rust-selectors"] selector_flags: Cell, - /// - custom_element_reaction_queue: DomRefCell>, - /// - #[ignore_malloc_size_of = "Rc"] - custom_element_definition: DomRefCell>>, - /// - custom_element_state: Cell, rare_data: Box, } @@ -203,15 +196,6 @@ pub enum CustomElementCreationMode { Asynchronous, } -/// -#[derive(Clone, Copy, Eq, JSTraceable, MallocSizeOf, PartialEq)] -pub enum CustomElementState { - Undefined, - Failed, - Uncustomized, - Custom, -} - impl ElementCreator { pub fn is_parser_created(&self) -> bool { match *self { @@ -305,9 +289,6 @@ impl Element { class_list: Default::default(), state: Cell::new(state), selector_flags: Cell::new(ElementSelectorFlags::empty()), - custom_element_reaction_queue: Default::default(), - custom_element_definition: Default::default(), - custom_element_state: Cell::new(CustomElementState::Uncustomized), rare_data: Default::default(), } } @@ -349,45 +330,55 @@ impl Element { } pub fn set_custom_element_state(&self, state: CustomElementState) { - self.custom_element_state.set(state); + self.rare_data.custom_element_state.set(state); } pub fn get_custom_element_state(&self) -> CustomElementState { - self.custom_element_state.get() + self.rare_data.custom_element_state.get() } pub fn set_custom_element_definition(&self, definition: Rc) { - *self.custom_element_definition.borrow_mut() = Some(definition); + *self.rare_data.custom_element_definition.borrow_mut() = Some(definition); } pub fn get_custom_element_definition(&self) -> Option> { - (*self.custom_element_definition.borrow()).clone() + (*self.rare_data.custom_element_definition.borrow()).clone() } pub fn push_callback_reaction(&self, function: Rc, args: Box<[Heap]>) { - self.custom_element_reaction_queue + self.rare_data + .custom_element_reaction_queue .borrow_mut() .push(CustomElementReaction::Callback(function, args)); } pub fn push_upgrade_reaction(&self, definition: Rc) { - self.custom_element_reaction_queue + self.rare_data + .custom_element_reaction_queue .borrow_mut() .push(CustomElementReaction::Upgrade(definition)); } pub fn clear_reaction_queue(&self) { - self.custom_element_reaction_queue.borrow_mut().clear(); + self.rare_data + .custom_element_reaction_queue + .borrow_mut() + .clear(); } pub fn invoke_reactions(&self) { // TODO: This is not spec compliant, as this will allow some reactions to be processed // after clear_reaction_queue has been called. rooted_vec!(let mut reactions); - while !self.custom_element_reaction_queue.borrow().is_empty() { + while !self + .rare_data + .custom_element_reaction_queue + .borrow() + .is_empty() + { mem::swap( &mut *reactions, - &mut *self.custom_element_reaction_queue.borrow_mut(), + &mut *self.rare_data.custom_element_reaction_queue.borrow_mut(), ); for reaction in reactions.iter() { reaction.invoke(self); diff --git a/components/script/dom/raredata.rs b/components/script/dom/raredata.rs index 05383197da7..9ebf8e7d787 100644 --- a/components/script/dom/raredata.rs +++ b/components/script/dom/raredata.rs @@ -4,8 +4,13 @@ use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::root::MutNullableDom; +use crate::dom::customelementregistry::{ + CustomElementDefinition, CustomElementReaction, CustomElementState, +}; use crate::dom::mutationobserver::RegisteredObserver; use crate::dom::shadowroot::ShadowRoot; +use std::cell::Cell; +use std::rc::Rc; #[derive(Default, JSTraceable, MallocSizeOf)] #[must_root] @@ -25,4 +30,11 @@ pub struct ElementRareData { /// XXX This is currently not exposed to web content. Only for /// internal use. pub shadow_root: MutNullableDom, + /// + pub custom_element_reaction_queue: DomRefCell>, + /// + #[ignore_malloc_size_of = "Rc"] + pub custom_element_definition: DomRefCell>>, + /// + pub custom_element_state: Cell, } From 1427c436206d7a62f233e2185b52cbd93481ceba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Wed, 6 Mar 2019 16:41:53 +0100 Subject: [PATCH 62/83] Update size of tests after *RareData changes --- tests/unit/script/size_of.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/tests/unit/script/size_of.rs b/tests/unit/script/size_of.rs index ddb73791854..8496506ef9f 100644 --- a/tests/unit/script/size_of.rs +++ b/tests/unit/script/size_of.rs @@ -30,10 +30,11 @@ macro_rules! sizeof_checker ( // Update the sizes here sizeof_checker!(size_event_target, EventTarget, 56); -sizeof_checker!(size_node, Node, 216); -sizeof_checker!(size_element, Element, 472); -sizeof_checker!(size_htmlelement, HTMLElement, 488); -sizeof_checker!(size_div, HTMLDivElement, 488); -sizeof_checker!(size_span, HTMLSpanElement, 488); -sizeof_checker!(size_text, Text, 248); -sizeof_checker!(size_characterdata, CharacterData, 248); +sizeof_checker!(size_node, Node, 176); +sizeof_checker!(size_element, Element, 376); +sizeof_checker!(size_htmlelement, HTMLElement, 392); +sizeof_checker!(size_div, HTMLDivElement, 392); +sizeof_checker!(size_span, HTMLSpanElement, 392); +sizeof_checker!(size_text, Text, 208); +sizeof_checker!(size_characterdata, CharacterData, 208); + From b8925a0297af9d49372db9097af277bef50d59ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Wed, 6 Mar 2019 16:55:27 +0100 Subject: [PATCH 63/83] Set IS_CONNECTED flag on host and children instead of on containing shadow root --- components/script/dom/element.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index a27af0f99b3..34a4ec41cfa 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -2802,7 +2802,7 @@ impl VirtualMethods for Element { f.bind_form_control_to_tree(); } - if let Some(shadow_root) = self.upcast::().owner_shadow_root() { + if let Some(shadow_root) = self.rare_data.shadow_root.get() { let shadow_root = shadow_root.upcast::(); shadow_root.set_flag(NodeFlags::IS_CONNECTED, context.tree_connected); for node in shadow_root.children() { From 0313e38074d4fb768c914bfe6e73ae959e098394 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Wed, 6 Mar 2019 18:02:10 +0100 Subject: [PATCH 64/83] Tweak list of shadow roots attached to doc --- components/layout_thread/dom_wrapper.rs | 5 ++++- components/script/dom/document.rs | 11 ++++------- components/script/dom/element.rs | 8 ++++++-- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/components/layout_thread/dom_wrapper.rs b/components/layout_thread/dom_wrapper.rs index cae98f7e594..d1ab90fcb0c 100644 --- a/components/layout_thread/dom_wrapper.rs +++ b/components/layout_thread/dom_wrapper.rs @@ -430,7 +430,10 @@ impl<'ld> ServoLayoutDocument<'ld> { self.document .shadow_roots() .iter() - .map(|sr| ServoShadowRoot::from_layout_js(*sr)) + .map(|sr| { + debug_assert!(sr.upcast::().get_flag(NodeFlags::IS_CONNECTED)); + ServoShadowRoot::from_layout_js(*sr) + }) .collect() } } diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 998055d3547..697d2938115 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -377,7 +377,7 @@ pub struct Document { /// https://html.spec.whatwg.org/multipage/#completely-loaded completely_loaded: Cell, /// List of shadow roots bound to the document tree. - shadow_roots: DomRefCell>>, + shadow_roots: DomRefCell>>, /// Whether any of the shadow roots need the stylesheets flushed. shadow_roots_styles_changed: Cell, } @@ -2674,7 +2674,7 @@ impl Document { completely_loaded: Cell::new(false), script_and_layout_blockers: Cell::new(0), delayed_tasks: Default::default(), - shadow_roots: DomRefCell::new(Vec::new()), + shadow_roots: DomRefCell::new(HashSet::new()), shadow_roots_styles_changed: Cell::new(false), } } @@ -3132,16 +3132,13 @@ impl Document { pub fn register_shadow_root(&self, shadow_root: &ShadowRoot) { self.shadow_roots .borrow_mut() - .push(Dom::from_ref(shadow_root)); + .insert(Dom::from_ref(shadow_root)); self.invalidate_shadow_roots_stylesheets(); } pub fn unregister_shadow_root(&self, shadow_root: &ShadowRoot) { let mut shadow_roots = self.shadow_roots.borrow_mut(); - let position = shadow_roots.iter().position(|sr| **sr == *shadow_root); - if let Some(index) = position { - shadow_roots.remove(index); - } + shadow_roots.remove(&Dom::from_ref(shadow_root)); } pub fn invalidate_shadow_roots_stylesheets(&self) { diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 34a4ec41cfa..e0659729673 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -489,7 +489,9 @@ impl Element { .shadow_root .or_init(|| ShadowRoot::new(self, &*self.node.owner_doc())); - self.node.owner_doc().register_shadow_root(&*shadow_root); + if self.is_connected() { + self.node.owner_doc().register_shadow_root(&*shadow_root); + } Ok(shadow_root) } @@ -2802,7 +2804,10 @@ impl VirtualMethods for Element { f.bind_form_control_to_tree(); } + let doc = document_from_node(self); + if let Some(shadow_root) = self.rare_data.shadow_root.get() { + doc.register_shadow_root(&shadow_root); let shadow_root = shadow_root.upcast::(); shadow_root.set_flag(NodeFlags::IS_CONNECTED, context.tree_connected); for node in shadow_root.children() { @@ -2815,7 +2820,6 @@ impl VirtualMethods for Element { return; } - let doc = document_from_node(self); if let Some(ref value) = *self.id_attribute.borrow() { if let Some(shadow_root) = self.upcast::().owner_shadow_root() { shadow_root.register_named_element(self, value.clone()); From bdd2f32c0fd7d51d207b2889c597b9e2e05346a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Thu, 7 Mar 2019 13:10:04 +0100 Subject: [PATCH 65/83] Minor tweaks: rename composed_parent_node_ref, remove or update outdated comments... --- components/layout_thread/dom_wrapper.rs | 19 ++++---- components/script/dom/document.rs | 2 +- components/script/dom/documentorshadowroot.rs | 45 +++++++------------ components/script/dom/element.rs | 2 +- components/script/dom/node.rs | 4 +- components/script/dom/range.rs | 7 +-- 6 files changed, 33 insertions(+), 46 deletions(-) diff --git a/components/layout_thread/dom_wrapper.rs b/components/layout_thread/dom_wrapper.rs index d1ab90fcb0c..5a231161d7b 100644 --- a/components/layout_thread/dom_wrapper.rs +++ b/components/layout_thread/dom_wrapper.rs @@ -232,7 +232,7 @@ impl<'ln> TNode for ServoLayoutNode<'ln> { fn parent_node(&self) -> Option { unsafe { self.node - .parent_node_ref() + .composed_parent_node_ref() .map(|node| self.new_with_this_lifetime(&node)) } } @@ -794,7 +794,12 @@ impl<'le> ::selectors::Element for ServoLayoutElement<'le> { } fn parent_element(&self) -> Option> { - unsafe { self.element.upcast().parent_node_ref().and_then(as_element) } + unsafe { + self.element + .upcast() + .composed_parent_node_ref() + .and_then(as_element) + } } fn parent_node_is_shadow_root(&self) -> bool { @@ -1083,12 +1088,10 @@ impl<'ln> ThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> { } fn children(&self) -> LayoutIterator { - if let Some(element) = self.node.as_element() { - if let Some(shadow) = element.shadow_root() { - return LayoutIterator(ThreadSafeLayoutNodeChildrenIterator::new( - shadow.as_node().to_threadsafe(), - )); - } + if let Some(shadow) = self.node.as_element().and_then(|e| e.shadow_root()) { + return LayoutIterator(ThreadSafeLayoutNodeChildrenIterator::new( + shadow.as_node().to_threadsafe(), + )); } LayoutIterator(ThreadSafeLayoutNodeChildrenIterator::new(*self)) } diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 697d2938115..e0c1cf57027 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -376,7 +376,7 @@ pub struct Document { delayed_tasks: DomRefCell>>, /// https://html.spec.whatwg.org/multipage/#completely-loaded completely_loaded: Cell, - /// List of shadow roots bound to the document tree. + /// Set of shadow roots connected to the document tree. shadow_roots: DomRefCell>>, /// Whether any of the shadow roots need the stylesheets flushed. shadow_roots_styles_changed: Cell, diff --git a/components/script/dom/documentorshadowroot.rs b/components/script/dom/documentorshadowroot.rs index 5c8428242ee..03932159359 100644 --- a/components/script/dom/documentorshadowroot.rs +++ b/components/script/dom/documentorshadowroot.rs @@ -277,25 +277,20 @@ impl DocumentOrShadowRoot { "Removing named element {:p}: {:p} id={}", self, to_unregister, id ); - // Limit the scope of the borrow because id_map might be borrowed again by - // GetElementById through the following sequence of calls - // reset_form_owner_for_listeners -> reset_form_owner -> GetElementById - { - let mut id_map = id_map.borrow_mut(); - let is_empty = match id_map.get_mut(&id) { - None => false, - Some(elements) => { - let position = elements - .iter() - .position(|element| &**element == to_unregister) - .expect("This element should be in registered."); - elements.remove(position); - elements.is_empty() - }, - }; - if is_empty { - id_map.remove(&id); - } + let mut id_map = id_map.borrow_mut(); + let is_empty = match id_map.get_mut(&id) { + None => false, + Some(elements) => { + let position = elements + .iter() + .position(|element| &**element == to_unregister) + .expect("This element should be in registered."); + elements.remove(position); + elements.is_empty() + }, + }; + if is_empty { + id_map.remove(&id); } } @@ -310,14 +305,8 @@ impl DocumentOrShadowRoot { debug!("Adding named element {:p}: {:p} id={}", self, element, id); assert!(element.upcast::().is_connected()); assert!(!id.is_empty()); - - // Limit the scope of the borrow because id_map might be borrowed again by - // GetElementById through the following sequence of calls - // reset_form_owner_for_listeners -> reset_form_owner -> GetElementById - { - let mut id_map = id_map.borrow_mut(); - let elements = id_map.entry(id.clone()).or_insert(Vec::new()); - elements.insert_pre_order(element, &root); - } + let mut id_map = id_map.borrow_mut(); + let elements = id_map.entry(id.clone()).or_insert(Vec::new()); + elements.insert_pre_order(element, &root); } } diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index e0659729673..0d320b833b8 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -994,7 +994,7 @@ impl LayoutElementHelpers for LayoutDom { unsafe { let mut current_node = Some(self.upcast::()); while let Some(node) = current_node { - current_node = node.parent_node_ref(); + current_node = node.composed_parent_node_ref(); match node.downcast::().map(|el| el.unsafe_get()) { Some(elem) => { if let Some(attr) = diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index f93679a3976..809c54eff36 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -1175,7 +1175,7 @@ pub unsafe fn from_untrusted_node_address( pub trait LayoutNodeHelpers { unsafe fn type_id_for_layout(&self) -> NodeTypeId; - unsafe fn parent_node_ref(&self) -> Option>; + unsafe fn composed_parent_node_ref(&self) -> Option>; unsafe fn first_child_ref(&self) -> Option>; unsafe fn last_child_ref(&self) -> Option>; unsafe fn prev_sibling_ref(&self) -> Option>; @@ -1222,7 +1222,7 @@ impl LayoutNodeHelpers for LayoutDom { #[inline] #[allow(unsafe_code)] - unsafe fn parent_node_ref(&self) -> Option> { + unsafe fn composed_parent_node_ref(&self) -> Option> { let parent = (*self.unsafe_get()).parent_node.get_inner_as_layout(); if let Some(ref parent) = parent { if let Some(shadow_root) = parent.downcast::() { diff --git a/components/script/dom/range.rs b/components/script/dom/range.rs index 462b3382c71..8d9bfbf21d2 100644 --- a/components/script/dom/range.rs +++ b/components/script/dom/range.rs @@ -10,7 +10,6 @@ use crate::dom::bindings::codegen::Bindings::RangeBinding::RangeMethods; use crate::dom::bindings::codegen::Bindings::RangeBinding::{self, RangeConstants}; use crate::dom::bindings::codegen::Bindings::TextBinding::TextMethods; use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; -use crate::dom::bindings::codegen::InheritTypes::DocumentFragmentTypeId; use crate::dom::bindings::error::{Error, ErrorResult, Fallible}; use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::inheritance::{CharacterDataTypeId, NodeTypeId}; @@ -764,11 +763,7 @@ impl RangeMethods for Range { // Step 11 let new_offset = new_offset + - if node.type_id() == - NodeTypeId::DocumentFragment(DocumentFragmentTypeId::DocumentFragment) || - node.type_id() == - NodeTypeId::DocumentFragment(DocumentFragmentTypeId::ShadowRoot) - { + if let NodeTypeId::DocumentFragment(_) = node.type_id() { node.len() } else { 1 From 5be6779f9a65218a41d970eab6f01dd5d6b60775 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Thu, 7 Mar 2019 13:40:34 +0100 Subject: [PATCH 66/83] Revert style/dom_apis changes --- components/style/dom_apis.rs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/components/style/dom_apis.rs b/components/style/dom_apis.rs index c66bb66c9f5..e43c861271e 100644 --- a/components/style/dom_apis.rs +++ b/components/style/dom_apis.rs @@ -241,11 +241,10 @@ where } if root.as_shadow_root().is_some() { - debug_assert!(element.as_node().is_in_document(), "Not connected?"); debug_assert_eq!( element.containing_shadow().unwrap().as_node(), root, - "Where did this element come from?" + "Not connected?" ); return true; } @@ -277,17 +276,17 @@ where } if root.is_in_document() { - if let Some(shadow) = root.as_shadow_root() { - return shadow.elements_with_id(id); - } - - if let Some(shadow) = root.as_element().and_then(|e| e.containing_shadow()) { - return shadow.elements_with_id(id); - } - return root.owner_doc().elements_with_id(id); } + if let Some(shadow) = root.as_shadow_root() { + return shadow.elements_with_id(id); + } + + if let Some(shadow) = root.as_element().and_then(|e| e.containing_shadow()) { + return shadow.elements_with_id(id); + } + Err(()) } From 5a165c6bd85857578fadeb627a78d45afe4949f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Thu, 7 Mar 2019 13:59:23 +0100 Subject: [PATCH 67/83] Move is_connected function from style to layout, where it is used --- components/layout_thread/dom_wrapper.rs | 8 ++++---- components/script_layout_interface/wrapper_traits.rs | 3 +++ components/style/dom.rs | 3 --- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/components/layout_thread/dom_wrapper.rs b/components/layout_thread/dom_wrapper.rs index 5a231161d7b..58f3ed7327e 100644 --- a/components/layout_thread/dom_wrapper.rs +++ b/components/layout_thread/dom_wrapper.rs @@ -306,10 +306,6 @@ impl<'ln> TNode for ServoLayoutNode<'ln> { fn is_in_document(&self) -> bool { unsafe { self.node.get_flag(NodeFlags::IS_IN_DOC) } } - - fn is_connected(&self) -> bool { - unsafe { self.node.get_flag(NodeFlags::IS_CONNECTED) } - } } impl<'ln> LayoutNode for ServoLayoutNode<'ln> { @@ -340,6 +336,10 @@ impl<'ln> LayoutNode for ServoLayoutNode<'ln> { unsafe fn take_style_and_layout_data(&self) -> OpaqueStyleAndLayoutData { self.get_jsmanaged().take_style_and_layout_data() } + + fn is_connected(&self) -> bool { + unsafe { self.node.get_flag(NodeFlags::IS_CONNECTED) } + } } impl<'ln> GetLayoutData for ServoLayoutNode<'ln> { diff --git a/components/script_layout_interface/wrapper_traits.rs b/components/script_layout_interface/wrapper_traits.rs index 0a7e080bebb..0e1df2ac4c8 100644 --- a/components/script_layout_interface/wrapper_traits.rs +++ b/components/script_layout_interface/wrapper_traits.rs @@ -104,6 +104,9 @@ pub trait LayoutNode: Debug + GetLayoutData + TNode { fn traverse_preorder(self) -> TreeIterator { TreeIterator::new(self) } + + /// Returns whether the node is connected. + fn is_connected(&self) -> bool; } pub struct ReverseChildrenIterator diff --git a/components/style/dom.rs b/components/style/dom.rs index 541ef4dbcdc..967b978bad4 100644 --- a/components/style/dom.rs +++ b/components/style/dom.rs @@ -188,9 +188,6 @@ pub trait TNode: Sized + Copy + Clone + Debug + NodeInfo + PartialEq { /// Returns whether the node is attached to a document. fn is_in_document(&self) -> bool; - /// Returns whether the node is connected. - fn is_connected(&self) -> bool; - /// Iterate over the DOM children of a node, in preorder. fn dom_descendants(&self) -> DomDescendants { DomDescendants { From efbfc0f9398d864efaa699f22fc329ddffe3cc1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Thu, 7 Mar 2019 15:51:11 +0100 Subject: [PATCH 68/83] Make devtools find node by unique id function include shadow trees --- components/script/devtools.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/script/devtools.rs b/components/script/devtools.rs index 9abeb5cf988..087930042e6 100644 --- a/components/script/devtools.rs +++ b/components/script/devtools.rs @@ -103,7 +103,7 @@ fn find_node_by_unique_id( documents.find_document(pipeline).and_then(|document| { document .upcast::() - .traverse_preorder(ShadowIncluding::No) + .traverse_preorder(ShadowIncluding::Yes) .find(|candidate| candidate.unique_id() == node_id) }) } From 0ca4792dc622029b807b40eee47cc38dd5d24e9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Thu, 7 Mar 2019 17:33:26 +0100 Subject: [PATCH 69/83] Revert changes in sheet_set_methods macro --- components/style/stylesheet_set.rs | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/components/style/stylesheet_set.rs b/components/style/stylesheet_set.rs index 4c3e37d3cd8..e668ba0d03d 100644 --- a/components/style/stylesheet_set.rs +++ b/components/style/stylesheet_set.rs @@ -441,12 +441,8 @@ where /// We could simplify the setup moving invalidations to SheetCollection, but /// that would imply not sharing invalidations across origins of the same /// documents, which is slightly annoying. -macro_rules! stylesheetset_impl { - ($set_name:expr, $set_type:ty) => { - impl $set_type - where - S: StylesheetInDocument + PartialEq + 'static, - { +macro_rules! sheet_set_methods { + ($set_name:expr) => { fn collect_invalidations_for( &mut self, device: Option<&Device>, @@ -502,7 +498,6 @@ macro_rules! stylesheetset_impl { let collection = self.collection_for(&sheet, guard); collection.remove(&sheet) } - } }; } @@ -527,6 +522,8 @@ where self.collections.borrow_mut_for_origin(&origin) } + sheet_set_methods!("DocumentStylesheetSet"); + /// Returns the number of stylesheets in the set. pub fn len(&self) -> usize { self.collections @@ -605,8 +602,6 @@ where } } -stylesheetset_impl!("DocumentStylesheetSet", DocumentStylesheetSet); - /// The set of stylesheets effective for a given XBL binding or Shadow Root. #[derive(MallocSizeOf)] pub struct AuthorStylesheetSet @@ -671,6 +666,8 @@ where &mut self.collection } + sheet_set_methods!("AuthorStylesheetSet"); + /// Iterate over the list of stylesheets. pub fn iter(&self) -> StylesheetCollectionIterator { self.collection.iter() @@ -702,5 +699,3 @@ where } } } - -stylesheetset_impl!("AuthorStylesheetSet", AuthorStylesheetSet); From 8eba5875471c9ddef95e0e4d4207ee6d6e70bbfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Thu, 7 Mar 2019 18:46:08 +0100 Subject: [PATCH 70/83] Merge Node::shadow_including_inclusive_ancestors into inclusive_ancestors --- components/script/dom/document.rs | 10 ++-- components/script/dom/element.rs | 13 +++-- components/script/dom/htmloptionelement.rs | 4 +- components/script/dom/mutationobserver.rs | 4 +- components/script/dom/node.rs | 55 ++++++++++++---------- components/script/dom/range.rs | 48 ++++++++++++++----- components/script/dom/servoparser/mod.rs | 4 +- components/script/dom/shadowroot.rs | 8 +++- components/script/script_thread.rs | 8 ++-- 9 files changed, 95 insertions(+), 59 deletions(-) diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index e0c1cf57027..a54ffcd8cf5 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -934,7 +934,7 @@ impl Document { let el = node_address.and_then(|address| { let node = unsafe { node::from_untrusted_node_address(js_runtime, address) }; - node.inclusive_ancestors() + node.inclusive_ancestors(ShadowIncluding::No) .filter_map(DomRoot::downcast::) .next() }); @@ -1118,7 +1118,7 @@ impl Document { let maybe_new_target = node_address.and_then(|address| { let node = unsafe { node::from_untrusted_node_address(js_runtime, address) }; - node.inclusive_ancestors() + node.inclusive_ancestors(ShadowIncluding::No) .filter_map(DomRoot::downcast::) .next() }); @@ -1154,7 +1154,7 @@ impl Document { if !old_target_is_ancestor_of_new_target { for element in old_target .upcast::() - .inclusive_ancestors() + .inclusive_ancestors(ShadowIncluding::No) .filter_map(DomRoot::downcast::) { element.set_hover_state(false); @@ -1172,7 +1172,7 @@ impl Document { if let Some(ref new_target) = maybe_new_target { for element in new_target .upcast::() - .inclusive_ancestors() + .inclusive_ancestors(ShadowIncluding::No) .filter_map(DomRoot::downcast::) { if element.hover_state() { @@ -1214,7 +1214,7 @@ impl Document { let el = node_address.and_then(|address| { let node = unsafe { node::from_untrusted_node_address(js_runtime, address) }; - node.inclusive_ancestors() + node.inclusive_ancestors(ShadowIncluding::No) .filter_map(DomRoot::downcast::) .next() }); diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 0d320b833b8..169fb7b9013 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -73,7 +73,7 @@ use crate::dom::mutationobserver::{Mutation, MutationObserver}; use crate::dom::namednodemap::NamedNodeMap; use crate::dom::node::{document_from_node, window_from_node}; use crate::dom::node::{BindContext, NodeDamage, NodeFlags, UnbindContext}; -use crate::dom::node::{ChildrenMutation, LayoutNodeHelpers, Node}; +use crate::dom::node::{ChildrenMutation, LayoutNodeHelpers, Node, ShadowIncluding}; use crate::dom::nodelist::NodeList; use crate::dom::promise::Promise; use crate::dom::raredata::ElementRareData; @@ -1111,7 +1111,7 @@ impl Element { let inclusive_ancestor_elements = self .upcast::() - .inclusive_ancestors() + .inclusive_ancestors(ShadowIncluding::No) .filter_map(DomRoot::downcast::); // Steps 3-4. @@ -1227,7 +1227,7 @@ impl Element { .unwrap() } else { self.upcast::() - .inclusive_ancestors() + .inclusive_ancestors(ShadowIncluding::No) .filter_map(DomRoot::downcast) .last() .expect("We know inclusive_ancestors will return `self` which is an element") @@ -1236,7 +1236,10 @@ impl Element { // https://dom.spec.whatwg.org/#locate-a-namespace-prefix pub fn lookup_prefix(&self, namespace: Namespace) -> Option { - for node in self.upcast::().inclusive_ancestors() { + for node in self + .upcast::() + .inclusive_ancestors(ShadowIncluding::No) + { let element = node.downcast::()?; // Step 1. if *element.namespace() == namespace { @@ -3235,7 +3238,7 @@ impl Element { // https://html.spec.whatwg.org/multipage/#language pub fn get_lang(&self) -> String { self.upcast::() - .inclusive_ancestors() + .inclusive_ancestors(ShadowIncluding::No) .filter_map(|node| { node.downcast::().and_then(|el| { el.get_attribute(&ns!(xml), &local_name!("lang")) diff --git a/components/script/dom/htmloptionelement.rs b/components/script/dom/htmloptionelement.rs index e9e2ce89c28..3893aea95ab 100644 --- a/components/script/dom/htmloptionelement.rs +++ b/components/script/dom/htmloptionelement.rs @@ -19,7 +19,7 @@ use crate::dom::htmlformelement::HTMLFormElement; use crate::dom::htmloptgroupelement::HTMLOptGroupElement; use crate::dom::htmlscriptelement::HTMLScriptElement; use crate::dom::htmlselectelement::HTMLSelectElement; -use crate::dom::node::{BindContext, Node, UnbindContext}; +use crate::dom::node::{BindContext, Node, ShadowIncluding, UnbindContext}; use crate::dom::text::Text; use crate::dom::virtualmethods::VirtualMethods; use dom_struct::dom_struct; @@ -251,7 +251,7 @@ impl VirtualMethods for HTMLOptionElement { if let Some(select) = context .parent - .inclusive_ancestors() + .inclusive_ancestors(ShadowIncluding::No) .filter_map(DomRoot::downcast::) .next() { diff --git a/components/script/dom/mutationobserver.rs b/components/script/dom/mutationobserver.rs index b25f99d0861..2d303950b8c 100644 --- a/components/script/dom/mutationobserver.rs +++ b/components/script/dom/mutationobserver.rs @@ -13,7 +13,7 @@ use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector}; use crate::dom::bindings::root::DomRoot; use crate::dom::bindings::str::DOMString; use crate::dom::mutationrecord::MutationRecord; -use crate::dom::node::Node; +use crate::dom::node::{Node, ShadowIncluding}; use crate::dom::window::Window; use crate::microtask::Microtask; use crate::script_thread::ScriptThread; @@ -131,7 +131,7 @@ impl MutationObserver { let mut interested_observers: Vec<(DomRoot, Option)> = vec![]; // Step 2 & 3 - for node in target.inclusive_ancestors() { + for node in target.inclusive_ancestors(ShadowIncluding::No) { for registered in &*node.registered_mutation_observers() { if &*node != target && !registered.options.subtree { continue; diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 809c54eff36..8a879c481ab 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -559,7 +559,7 @@ impl Node { pub fn note_dirty_descendants(&self) { debug_assert!(self.is_in_doc()); - for ancestor in self.shadow_including_inclusive_ancestors() { + for ancestor in self.inclusive_ancestors(ShadowIncluding::Yes) { if ancestor.get_flag(NodeFlags::HAS_DIRTY_DESCENDANTS) { return; } @@ -582,7 +582,7 @@ impl Node { self.inclusive_descendants_version(), doc.inclusive_descendants_version(), ) + 1; - for ancestor in self.inclusive_ancestors() { + for ancestor in self.inclusive_ancestors(ShadowIncluding::No) { ancestor.inclusive_descendants_version.set(version); } doc.inclusive_descendants_version.set(version); @@ -638,7 +638,7 @@ impl Node { } fn is_shadow_including_inclusive_ancestor_of(&self, node: &Node) -> bool { - node.shadow_including_inclusive_ancestors() + node.inclusive_ancestors(ShadowIncluding::Yes) .any(|ancestor| &*ancestor == self) } @@ -900,25 +900,22 @@ impl Node { } } - pub fn inclusive_ancestors(&self) -> Box>> { - Box::new(SimpleNodeIterator { - current: Some(DomRoot::from_ref(self)), - next_node: |n| n.GetParentNode(), - }) - } - /// https://dom.spec.whatwg.org/#concept-shadow-including-inclusive-ancestor - pub fn shadow_including_inclusive_ancestors(&self) -> Box>> { - Box::new(SimpleNodeIterator { + pub fn inclusive_ancestors( + &self, + shadow_including: ShadowIncluding, + ) -> impl Iterator> { + SimpleNodeIterator { current: Some(DomRoot::from_ref(self)), - next_node: |n| { - if let Some(shadow_root) = n.downcast::() { - Some(DomRoot::from_ref(shadow_root.Host().upcast::())) - } else { - n.GetParentNode() + next_node: move |n| { + if shadow_including == ShadowIncluding::Yes { + if let Some(shadow_root) = n.downcast::() { + return Some(DomRoot::from_ref(shadow_root.Host().upcast::())); + } } + n.GetParentNode() }, - }) + } } pub fn owner_doc(&self) -> DomRoot { @@ -1436,7 +1433,7 @@ impl FollowingNodeIterator { return current.GetNextSibling(); } - for ancestor in current.inclusive_ancestors() { + for ancestor in current.inclusive_ancestors(ShadowIncluding::No) { if self.root == ancestor { break; } @@ -1545,11 +1542,11 @@ impl TreeIterator { } fn next_skipping_children_impl(&mut self, current: DomRoot) -> Option> { - let iter = if self.shadow_including { - current.shadow_including_inclusive_ancestors() + let iter = current.inclusive_ancestors(if self.shadow_including { + ShadowIncluding::Yes } else { - current.inclusive_ancestors() - }; + ShadowIncluding::No + }); for ancestor in iter { if self.depth == 0 { @@ -2282,7 +2279,9 @@ impl NodeMethods for Node { return shadow_root.Host().upcast::().GetRootNode(options); } } - self.inclusive_ancestors().last().unwrap() + self.inclusive_ancestors(ShadowIncluding::No) + .last() + .unwrap() } // https://dom.spec.whatwg.org/#dom-node-parentnode @@ -2687,8 +2686,12 @@ impl NodeMethods for Node { // FIXME(emilio): This will eventually need to handle attribute nodes. - let mut self_and_ancestors = self.inclusive_ancestors().collect::>(); - let mut other_and_ancestors = other.inclusive_ancestors().collect::>(); + let mut self_and_ancestors = self + .inclusive_ancestors(ShadowIncluding::No) + .collect::>(); + let mut other_and_ancestors = other + .inclusive_ancestors(ShadowIncluding::No) + .collect::>(); if self_and_ancestors.last() != other_and_ancestors.last() { let random = as_uintptr(self_and_ancestors.last().unwrap()) < diff --git a/components/script/dom/range.rs b/components/script/dom/range.rs index 8d9bfbf21d2..de17427664e 100644 --- a/components/script/dom/range.rs +++ b/components/script/dom/range.rs @@ -102,10 +102,10 @@ impl Range { // https://dom.spec.whatwg.org/#partially-contained fn partially_contains(&self, node: &Node) -> bool { self.StartContainer() - .inclusive_ancestors() + .inclusive_ancestors(ShadowIncluding::No) .any(|n| &*n == node) != self.EndContainer() - .inclusive_ancestors() + .inclusive_ancestors(ShadowIncluding::No) .any(|n| &*n == node) } @@ -193,8 +193,14 @@ impl Range { // https://dom.spec.whatwg.org/#dom-range-comparepointnode-offset fn compare_point(&self, node: &Node, offset: u32) -> Fallible { let start_node = self.StartContainer(); - let start_node_root = start_node.inclusive_ancestors().last().unwrap(); - let node_root = node.inclusive_ancestors().last().unwrap(); + let start_node_root = start_node + .inclusive_ancestors(ShadowIncluding::No) + .last() + .unwrap(); + let node_root = node + .inclusive_ancestors(ShadowIncluding::No) + .last() + .unwrap(); if start_node_root != node_root { // Step 1. return Err(Error::WrongDocument); @@ -253,7 +259,10 @@ impl RangeMethods for Range { fn CommonAncestorContainer(&self) -> DomRoot { let end_container = self.EndContainer(); // Step 1. - for container in self.StartContainer().inclusive_ancestors() { + for container in self + .StartContainer() + .inclusive_ancestors(ShadowIncluding::No) + { // Step 2. if container.is_inclusive_ancestor_of(&end_container) { // Step 3. @@ -368,8 +377,16 @@ impl RangeMethods for Range { // Step 1. return Err(Error::NotSupported); } - let this_root = self.StartContainer().inclusive_ancestors().last().unwrap(); - let other_root = other.StartContainer().inclusive_ancestors().last().unwrap(); + let this_root = self + .StartContainer() + .inclusive_ancestors(ShadowIncluding::No) + .last() + .unwrap(); + let other_root = other + .StartContainer() + .inclusive_ancestors(ShadowIncluding::No) + .last() + .unwrap(); if this_root != other_root { // Step 2. return Err(Error::WrongDocument); @@ -429,8 +446,15 @@ impl RangeMethods for Range { // https://dom.spec.whatwg.org/#dom-range-intersectsnode fn IntersectsNode(&self, node: &Node) -> bool { let start_node = self.StartContainer(); - let start_node_root = self.StartContainer().inclusive_ancestors().last().unwrap(); - let node_root = node.inclusive_ancestors().last().unwrap(); + let start_node_root = self + .StartContainer() + .inclusive_ancestors(ShadowIncluding::No) + .last() + .unwrap(); + let node_root = node + .inclusive_ancestors(ShadowIncluding::No) + .last() + .unwrap(); if start_node_root != node_root { // Step 1. return false; @@ -868,9 +892,9 @@ impl RangeMethods for Range { let end = self.EndContainer(); if start - .inclusive_ancestors() + .inclusive_ancestors(ShadowIncluding::No) .any(|n| !n.is_inclusive_ancestor_of(&end) && !n.is::()) || - end.inclusive_ancestors() + end.inclusive_ancestors(ShadowIncluding::No) .any(|n| !n.is_inclusive_ancestor_of(&start) && !n.is::()) { return Err(Error::InvalidState); @@ -1051,7 +1075,7 @@ fn bp_position(a_node: &Node, a_offset: u32, b_node: &Node, b_offset: u32) -> Op } } else if position & NodeConstants::DOCUMENT_POSITION_CONTAINS != 0 { // Step 3-1, 3-2. - let mut b_ancestors = b_node.inclusive_ancestors(); + let mut b_ancestors = b_node.inclusive_ancestors(ShadowIncluding::No); let child = b_ancestors .find(|child| &*child.GetParentNode().unwrap() == a_node) .unwrap(); diff --git a/components/script/dom/servoparser/mod.rs b/components/script/dom/servoparser/mod.rs index 3c0d321910c..9f6a2214ed0 100644 --- a/components/script/dom/servoparser/mod.rs +++ b/components/script/dom/servoparser/mod.rs @@ -27,7 +27,7 @@ use crate::dom::htmlformelement::{FormControlElementHelpers, HTMLFormElement}; use crate::dom::htmlimageelement::HTMLImageElement; use crate::dom::htmlscriptelement::{HTMLScriptElement, ScriptResult}; use crate::dom::htmltemplateelement::HTMLTemplateElement; -use crate::dom::node::Node; +use crate::dom::node::{Node, ShadowIncluding}; use crate::dom::performanceentry::PerformanceEntry; use crate::dom::performancenavigationtiming::PerformanceNavigationTiming; use crate::dom::processinginstruction::ProcessingInstruction; @@ -194,7 +194,7 @@ impl ServoParser { // Step 11. let form = context_node - .inclusive_ancestors() + .inclusive_ancestors(ShadowIncluding::No) .find(|element| element.is::()); let fragment_context = FragmentContext { diff --git a/components/script/dom/shadowroot.rs b/components/script/dom/shadowroot.rs index 55535ad9a9d..a32f9bb5c24 100644 --- a/components/script/dom/shadowroot.rs +++ b/components/script/dom/shadowroot.rs @@ -14,7 +14,7 @@ use crate::dom::document::Document; use crate::dom::documentfragment::DocumentFragment; use crate::dom::documentorshadowroot::{DocumentOrShadowRoot, StyleSheetInDocument}; use crate::dom::element::Element; -use crate::dom::node::{Node, NodeDamage, NodeFlags}; +use crate::dom::node::{Node, NodeDamage, NodeFlags, ShadowIncluding}; use crate::dom::stylesheetlist::{StyleSheetList, StyleSheetListOwner}; use crate::dom::window::Window; use dom_struct::dom_struct; @@ -140,7 +140,11 @@ impl ShadowRoot { /// Associate an element present in this shadow tree with the provided id. pub fn register_named_element(&self, element: &Element, id: Atom) { - let root = self.upcast::().inclusive_ancestors().last().unwrap(); + let root = self + .upcast::() + .inclusive_ancestors(ShadowIncluding::No) + .last() + .unwrap(); self.document_or_shadow_root.register_named_element( self.document_fragment.id_map(), element, diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index 84a4182ae3e..4fbaec2b465 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -51,7 +51,9 @@ use crate::dom::globalscope::GlobalScope; use crate::dom::htmlanchorelement::HTMLAnchorElement; use crate::dom::htmliframeelement::{HTMLIFrameElement, NavigationType}; use crate::dom::mutationobserver::MutationObserver; -use crate::dom::node::{from_untrusted_node_address, window_from_node, Node, NodeDamage}; +use crate::dom::node::{ + from_untrusted_node_address, window_from_node, Node, NodeDamage, ShadowIncluding, +}; use crate::dom::performanceentry::PerformanceEntry; use crate::dom::performancepainttiming::PerformancePaintTiming; use crate::dom::serviceworker::TrustedServiceWorkerAddress; @@ -3097,7 +3099,7 @@ impl ScriptThread { if let Some(target) = self.topmost_mouse_over_target.get() { if let Some(anchor) = target .upcast::() - .inclusive_ancestors() + .inclusive_ancestors(ShadowIncluding::No) .filter_map(DomRoot::downcast::) .next() { @@ -3121,7 +3123,7 @@ impl ScriptThread { if let Some(target) = prev_mouse_over_target { if let Some(_) = target .upcast::() - .inclusive_ancestors() + .inclusive_ancestors(ShadowIncluding::No) .filter_map(DomRoot::downcast::) .next() { From 890297ef0a448edbe074e23fb98f2b6054c03e0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Fri, 8 Mar 2019 08:01:09 +0100 Subject: [PATCH 71/83] Optimize Node::GetRootNode --- components/script/dom/node.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 8a879c481ab..4ceb4305ddf 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -2279,9 +2279,15 @@ impl NodeMethods for Node { return shadow_root.Host().upcast::().GetRootNode(options); } } - self.inclusive_ancestors(ShadowIncluding::No) - .last() - .unwrap() + if let Some(shadow_root) = self.rare_data.owner_shadow_root.get() { + DomRoot::from_ref(shadow_root.upcast::()) + } else if self.is_in_doc() { + DomRoot::from_ref(self.owner_doc().upcast::()) + } else { + self.inclusive_ancestors(ShadowIncluding::No) + .last() + .unwrap() + } } // https://dom.spec.whatwg.org/#dom-node-parentnode From f6069630d29bd49f805756a73b0f60aee2309c18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Fri, 8 Mar 2019 08:02:26 +0100 Subject: [PATCH 72/83] Update tests manifest --- tests/wpt/mozilla/meta/MANIFEST.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/wpt/mozilla/meta/MANIFEST.json b/tests/wpt/mozilla/meta/MANIFEST.json index eaaf5ea3c94..662740e9f0b 100644 --- a/tests/wpt/mozilla/meta/MANIFEST.json +++ b/tests/wpt/mozilla/meta/MANIFEST.json @@ -20454,7 +20454,7 @@ "testharness" ], "mozilla/partial_shadow_dom.html": [ - "d97f1422d20161e989f200d44be6e379f79410bd", + "74e308f94036a6dbf5c4223cd3d229f49ffceb4e", "testharness" ], "mozilla/partial_shadow_dom_layout_style.html": [ From 6bf1ca20a282fea83fd3438a11b16081352251df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Fri, 8 Mar 2019 17:03:34 +0100 Subject: [PATCH 73/83] Make Node and Element rare_data an Option --- components/script/dom/element.rs | 66 +++++++++------ components/script/dom/macros.rs | 30 +++++++ components/script/dom/mutationobserver.rs | 26 +++--- components/script/dom/node.rs | 45 ++++++++--- components/script/dom/raredata.rs | 16 ++-- components/style/gecko/wrapper.rs | 5 -- components/style/stylesheet_set.rs | 98 +++++++++++------------ tests/unit/script/size_of.rs | 15 ++-- 8 files changed, 181 insertions(+), 120 deletions(-) diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 169fb7b9013..6983b8be2c1 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -106,7 +106,7 @@ use selectors::Element as SelectorsElement; use servo_arc::Arc; use servo_atoms::Atom; use std::borrow::Cow; -use std::cell::{Cell, Ref}; +use std::cell::{Cell, Ref, RefMut}; use std::default::Default; use std::fmt; use std::mem; @@ -166,7 +166,7 @@ pub struct Element { /// when it has exclusive access to the element. #[ignore_malloc_size_of = "bitflags defined in rust-selectors"] selector_flags: Cell, - rare_data: Box, + rare_data: DomRefCell>>, } impl fmt::Debug for Element { @@ -308,6 +308,8 @@ impl Element { ) } + impl_rare_data!(ElementRareData); + pub fn restyle(&self, damage: NodeDamage) { let doc = self.node.owner_doc(); let mut restyle = doc.ensure_pending_restyle(self); @@ -330,39 +332,49 @@ impl Element { } pub fn set_custom_element_state(&self, state: CustomElementState) { - self.rare_data.custom_element_state.set(state); + self.rare_data_mut().as_mut().unwrap().custom_element_state = state; } pub fn get_custom_element_state(&self) -> CustomElementState { - self.rare_data.custom_element_state.get() + self.rare_data().as_ref().unwrap().custom_element_state } pub fn set_custom_element_definition(&self, definition: Rc) { - *self.rare_data.custom_element_definition.borrow_mut() = Some(definition); + self.rare_data_mut() + .as_mut() + .unwrap() + .custom_element_definition = Some(definition); } pub fn get_custom_element_definition(&self) -> Option> { - (*self.rare_data.custom_element_definition.borrow()).clone() + self.rare_data() + .as_ref() + .unwrap() + .custom_element_definition + .clone() } pub fn push_callback_reaction(&self, function: Rc, args: Box<[Heap]>) { - self.rare_data + self.rare_data_mut() + .as_mut() + .unwrap() .custom_element_reaction_queue - .borrow_mut() .push(CustomElementReaction::Callback(function, args)); } pub fn push_upgrade_reaction(&self, definition: Rc) { - self.rare_data + self.rare_data_mut() + .as_mut() + .unwrap() .custom_element_reaction_queue - .borrow_mut() .push(CustomElementReaction::Upgrade(definition)); } pub fn clear_reaction_queue(&self) { - self.rare_data + self.rare_data_mut() + .as_mut() + .unwrap() .custom_element_reaction_queue - .borrow_mut() .clear(); } @@ -371,14 +383,19 @@ impl Element { // after clear_reaction_queue has been called. rooted_vec!(let mut reactions); while !self - .rare_data + .rare_data() + .as_ref() + .unwrap() .custom_element_reaction_queue - .borrow() .is_empty() { mem::swap( &mut *reactions, - &mut *self.rare_data.custom_element_reaction_queue.borrow_mut(), + &mut self + .rare_data_mut() + .as_mut() + .unwrap() + .custom_element_reaction_queue, ); for reaction in reactions.iter() { reaction.invoke(self); @@ -441,7 +458,7 @@ impl Element { } pub fn is_shadow_host(&self) -> bool { - self.rare_data.shadow_root.get().is_some() + self.rare_data().as_ref().unwrap().shadow_root.is_some() } /// https://dom.spec.whatwg.org/#dom-element-attachshadow @@ -484,10 +501,8 @@ impl Element { } // Steps 4, 5 and 6. - let shadow_root = self - .rare_data - .shadow_root - .or_init(|| ShadowRoot::new(self, &*self.node.owner_doc())); + let shadow_root = ShadowRoot::new(self, &*self.node.owner_doc()); + self.rare_data_mut().as_mut().unwrap().shadow_root = Some(Dom::from_ref(&*shadow_root)); if self.is_connected() { self.node.owner_doc().register_shadow_root(&*shadow_root); @@ -1063,9 +1078,12 @@ impl LayoutElementHelpers for LayoutDom { #[allow(unsafe_code)] unsafe fn get_shadow_root_for_layout(&self) -> Option> { (*self.unsafe_get()) - .rare_data + .rare_data_for_layout() + .as_ref() + .unwrap() .shadow_root - .get_inner_as_layout() + .as_ref() + .map(|sr| sr.to_layout()) } } @@ -2809,7 +2827,7 @@ impl VirtualMethods for Element { let doc = document_from_node(self); - if let Some(shadow_root) = self.rare_data.shadow_root.get() { + if let Some(ref shadow_root) = self.rare_data().as_ref().unwrap().shadow_root { doc.register_shadow_root(&shadow_root); let shadow_root = shadow_root.upcast::(); shadow_root.set_flag(NodeFlags::IS_CONNECTED, context.tree_connected); @@ -2847,7 +2865,7 @@ impl VirtualMethods for Element { let doc = document_from_node(self); - if let Some(shadow_root) = self.rare_data.shadow_root.get() { + if let Some(ref shadow_root) = self.rare_data().as_ref().unwrap().shadow_root { doc.unregister_shadow_root(&shadow_root); let shadow_root = shadow_root.upcast::(); shadow_root.set_flag(NodeFlags::IS_CONNECTED, false); diff --git a/components/script/dom/macros.rs b/components/script/dom/macros.rs index a566fee4fb6..0fb51c7d8fd 100644 --- a/components/script/dom/macros.rs +++ b/components/script/dom/macros.rs @@ -632,3 +632,33 @@ macro_rules! handle_potential_webgl_error { handle_potential_webgl_error!($context, $call, ()); }; } + +macro_rules! impl_rare_data ( + ($type:ty) => ( + fn init_rare_data(&self) { + let mut rare_data = self.rare_data.borrow_mut(); + if rare_data.is_none() { + *rare_data = Some(Default::default()); + } + } + + fn rare_data(&self) -> Ref>> { + self.init_rare_data(); + self.rare_data.borrow() + } + + fn rare_data_mut(&self) -> RefMut>> { + self.init_rare_data(); + self.rare_data.borrow_mut() + } + + #[allow(unsafe_code)] + fn rare_data_for_layout(&self) -> &Option> { + let mut rare_data = self.rare_data.borrow_mut_for_layout(); + if rare_data.is_none() { + *rare_data = Some(Default::default()); + } + unsafe { self.rare_data.borrow_for_layout() } + } + ); +); diff --git a/components/script/dom/mutationobserver.rs b/components/script/dom/mutationobserver.rs index 2d303950b8c..bb87a10f4b2 100644 --- a/components/script/dom/mutationobserver.rs +++ b/components/script/dom/mutationobserver.rs @@ -318,20 +318,18 @@ impl MutationObserverMethods for MutationObserver { // Step 8 if add_new_observer { - target - .registered_mutation_observers() - .push(RegisteredObserver { - observer: DomRoot::from_ref(self), - options: ObserverOptions { - attributes, - attribute_old_value, - character_data, - character_data_old_value, - subtree, - attribute_filter, - child_list, - }, - }); + target.add_mutation_observer(RegisteredObserver { + observer: DomRoot::from_ref(self), + options: ObserverOptions { + attributes, + attribute_old_value, + character_data, + character_data_old_value, + subtree, + attribute_filter, + child_list, + }, + }); self.node_list.borrow_mut().push(DomRoot::from_ref(target)); } diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 4ceb4305ddf..3238727267e 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -5,6 +5,7 @@ //! The core DOM types. Defines the basic DOM hierarchy as well as all the HTML elements. use crate::document_loader::DocumentLoader; +use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::codegen::Bindings::CharacterDataBinding::CharacterDataMethods; use crate::dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods; use crate::dom::bindings::codegen::Bindings::ElementBinding::ElementMethods; @@ -82,7 +83,7 @@ use servo_arc::Arc; use servo_url::ServoUrl; use smallvec::SmallVec; use std::borrow::ToOwned; -use std::cell::{Cell, RefMut, UnsafeCell}; +use std::cell::{Cell, Ref, RefMut, UnsafeCell}; use std::cmp; use std::default::Default; use std::iter; @@ -125,7 +126,7 @@ pub struct Node { owner_doc: MutNullableDom, /// Rare node data. - rare_data: Box, + rare_data: DomRefCell>>, /// The live list of children return by .childNodes. child_list: MutNullableDom, @@ -430,6 +431,8 @@ impl<'a> Iterator for QuerySelectorIterator { } impl Node { + impl_rare_data!(NodeRareData); + pub fn teardown(&self) { self.style_and_layout_data.get().map(|d| self.dispose(d)); for kid in self.children() { @@ -450,14 +453,26 @@ impl Node { /// Return all registered mutation observers for this node. pub fn registered_mutation_observers(&self) -> RefMut> { - self.rare_data.mutation_observers.borrow_mut() + RefMut::map(self.rare_data_mut(), |rare_data| { + &mut rare_data.as_mut().unwrap().mutation_observers + }) + } + + /// Add a new mutation observer for a given node. + pub fn add_mutation_observer(&self, observer: RegisteredObserver) { + self.rare_data_mut() + .as_mut() + .unwrap() + .mutation_observers + .push(observer); } /// Removes the mutation observer for a given node. pub fn remove_mutation_observer(&self, observer: &MutationObserver) { - self.rare_data + self.rare_data_mut() + .as_mut() + .unwrap() .mutation_observers - .borrow_mut() .retain(|reg_obs| &*reg_obs.observer != observer) } @@ -930,11 +945,16 @@ impl Node { if let Some(ref shadow_root) = self.downcast::() { return Some(DomRoot::from_ref(shadow_root)); } - self.rare_data.owner_shadow_root.get() + self.rare_data() + .as_ref() + .unwrap() + .owner_shadow_root + .as_ref() + .map(|sr| DomRoot::from_ref(&**sr)) } pub fn set_owner_shadow_root(&self, shadow_root: &ShadowRoot) { - self.rare_data.owner_shadow_root.set(Some(shadow_root)); + self.rare_data_mut().as_mut().unwrap().owner_shadow_root = Some(Dom::from_ref(shadow_root)); } pub fn is_in_html_doc(&self) -> bool { @@ -1266,9 +1286,12 @@ impl LayoutNodeHelpers for LayoutDom { #[allow(unsafe_code)] unsafe fn owner_shadow_root_for_layout(&self) -> Option> { (*self.unsafe_get()) - .rare_data + .rare_data_for_layout() + .as_ref() + .unwrap() .owner_shadow_root - .get_inner_as_layout() + .as_ref() + .map(|sr| sr.to_layout()) } #[inline] @@ -2274,12 +2297,12 @@ impl NodeMethods for Node { // https://dom.spec.whatwg.org/#dom-node-getrootnode fn GetRootNode(&self, options: &GetRootNodeOptions) -> DomRoot { if options.composed { - if let Some(shadow_root) = self.rare_data.owner_shadow_root.get() { + if let Some(ref shadow_root) = self.rare_data().as_ref().unwrap().owner_shadow_root { // shadow-including root. return shadow_root.Host().upcast::().GetRootNode(options); } } - if let Some(shadow_root) = self.rare_data.owner_shadow_root.get() { + if let Some(ref shadow_root) = self.rare_data().as_ref().unwrap().owner_shadow_root { DomRoot::from_ref(shadow_root.upcast::()) } else if self.is_in_doc() { DomRoot::from_ref(self.owner_doc().upcast::()) diff --git a/components/script/dom/raredata.rs b/components/script/dom/raredata.rs index 9ebf8e7d787..874db7b48ad 100644 --- a/components/script/dom/raredata.rs +++ b/components/script/dom/raredata.rs @@ -2,14 +2,12 @@ * 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::cell::DomRefCell; -use crate::dom::bindings::root::MutNullableDom; +use crate::dom::bindings::root::Dom; use crate::dom::customelementregistry::{ CustomElementDefinition, CustomElementReaction, CustomElementState, }; use crate::dom::mutationobserver::RegisteredObserver; use crate::dom::shadowroot::ShadowRoot; -use std::cell::Cell; use std::rc::Rc; #[derive(Default, JSTraceable, MallocSizeOf)] @@ -18,9 +16,9 @@ pub struct NodeRareData { /// The shadow root the node belongs to. /// This is None if the node is not in a shadow tree or /// if it is a ShadowRoot. - pub owner_shadow_root: MutNullableDom, + pub owner_shadow_root: Option>, /// Registered observers for this node. - pub mutation_observers: DomRefCell>, + pub mutation_observers: Vec, } #[derive(Default, JSTraceable, MallocSizeOf)] @@ -29,12 +27,12 @@ pub struct ElementRareData { /// https://dom.spec.whatwg.org/#dom-element-shadowroot /// XXX This is currently not exposed to web content. Only for /// internal use. - pub shadow_root: MutNullableDom, + pub shadow_root: Option>, /// - pub custom_element_reaction_queue: DomRefCell>, + pub custom_element_reaction_queue: Vec, /// #[ignore_malloc_size_of = "Rc"] - pub custom_element_definition: DomRefCell>>, + pub custom_element_definition: Option>, /// - pub custom_element_state: Cell, + pub custom_element_state: CustomElementState, } diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs index e8e5078c53a..0fa354fb139 100644 --- a/components/style/gecko/wrapper.rs +++ b/components/style/gecko/wrapper.rs @@ -421,11 +421,6 @@ impl<'ln> TNode for GeckoNode<'ln> { self.get_bool_flag(nsINode_BooleanFlag::IsInDocument) } - #[inline] - fn is_connected(&self) -> bool { - self.get_bool_flag(nsINode_BooleanFlag::IsConnected) - } - fn traversal_parent(&self) -> Option> { self.flattened_tree_parent().and_then(|n| n.as_element()) } diff --git a/components/style/stylesheet_set.rs b/components/style/stylesheet_set.rs index e668ba0d03d..1d803e5dd01 100644 --- a/components/style/stylesheet_set.rs +++ b/components/style/stylesheet_set.rs @@ -443,61 +443,61 @@ where /// documents, which is slightly annoying. macro_rules! sheet_set_methods { ($set_name:expr) => { - fn collect_invalidations_for( - &mut self, - device: Option<&Device>, - sheet: &S, - guard: &SharedRwLockReadGuard, - ) { - if let Some(device) = device { - self.invalidations - .collect_invalidations_for(device, sheet, guard); - } + fn collect_invalidations_for( + &mut self, + device: Option<&Device>, + sheet: &S, + guard: &SharedRwLockReadGuard, + ) { + if let Some(device) = device { + self.invalidations + .collect_invalidations_for(device, sheet, guard); } + } - /// Appends a new stylesheet to the current set. - /// - /// No device implies not computing invalidations. - pub fn append_stylesheet( - &mut self, - device: Option<&Device>, - sheet: S, - guard: &SharedRwLockReadGuard, - ) { - debug!(concat!($set_name, "::append_stylesheet")); - self.collect_invalidations_for(device, &sheet, guard); - let collection = self.collection_for(&sheet, guard); - collection.append(sheet); - } + /// Appends a new stylesheet to the current set. + /// + /// No device implies not computing invalidations. + pub fn append_stylesheet( + &mut self, + device: Option<&Device>, + sheet: S, + guard: &SharedRwLockReadGuard, + ) { + debug!(concat!($set_name, "::append_stylesheet")); + self.collect_invalidations_for(device, &sheet, guard); + let collection = self.collection_for(&sheet, guard); + collection.append(sheet); + } - /// Insert a given stylesheet before another stylesheet in the document. - pub fn insert_stylesheet_before( - &mut self, - device: Option<&Device>, - sheet: S, - before_sheet: S, - guard: &SharedRwLockReadGuard, - ) { - debug!(concat!($set_name, "::insert_stylesheet_before")); - self.collect_invalidations_for(device, &sheet, guard); + /// Insert a given stylesheet before another stylesheet in the document. + pub fn insert_stylesheet_before( + &mut self, + device: Option<&Device>, + sheet: S, + before_sheet: S, + guard: &SharedRwLockReadGuard, + ) { + debug!(concat!($set_name, "::insert_stylesheet_before")); + self.collect_invalidations_for(device, &sheet, guard); - let collection = self.collection_for(&sheet, guard); - collection.insert_before(sheet, &before_sheet); - } + let collection = self.collection_for(&sheet, guard); + collection.insert_before(sheet, &before_sheet); + } - /// Remove a given stylesheet from the set. - pub fn remove_stylesheet( - &mut self, - device: Option<&Device>, - sheet: S, - guard: &SharedRwLockReadGuard, - ) { - debug!(concat!($set_name, "::remove_stylesheet")); - self.collect_invalidations_for(device, &sheet, guard); + /// Remove a given stylesheet from the set. + pub fn remove_stylesheet( + &mut self, + device: Option<&Device>, + sheet: S, + guard: &SharedRwLockReadGuard, + ) { + debug!(concat!($set_name, "::remove_stylesheet")); + self.collect_invalidations_for(device, &sheet, guard); - let collection = self.collection_for(&sheet, guard); - collection.remove(&sheet) - } + let collection = self.collection_for(&sheet, guard); + collection.remove(&sheet) + } }; } diff --git a/tests/unit/script/size_of.rs b/tests/unit/script/size_of.rs index 8496506ef9f..1c5bcace945 100644 --- a/tests/unit/script/size_of.rs +++ b/tests/unit/script/size_of.rs @@ -30,11 +30,10 @@ macro_rules! sizeof_checker ( // Update the sizes here sizeof_checker!(size_event_target, EventTarget, 56); -sizeof_checker!(size_node, Node, 176); -sizeof_checker!(size_element, Element, 376); -sizeof_checker!(size_htmlelement, HTMLElement, 392); -sizeof_checker!(size_div, HTMLDivElement, 392); -sizeof_checker!(size_span, HTMLSpanElement, 392); -sizeof_checker!(size_text, Text, 208); -sizeof_checker!(size_characterdata, CharacterData, 208); - +sizeof_checker!(size_node, Node, 184); +sizeof_checker!(size_element, Element, 392); +sizeof_checker!(size_htmlelement, HTMLElement, 408); +sizeof_checker!(size_div, HTMLDivElement, 408); +sizeof_checker!(size_span, HTMLSpanElement, 408); +sizeof_checker!(size_text, Text, 216); +sizeof_checker!(size_characterdata, CharacterData, 216); From 59c634b259f3b481a228c50b32dc8e68c013a609 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Sat, 23 Mar 2019 06:39:38 +0100 Subject: [PATCH 74/83] Set dirty descendants if node is connected --- components/layout_thread/dom_wrapper.rs | 2 +- components/script/dom/document.rs | 2 +- components/script/dom/node.rs | 22 ++++++++-------------- 3 files changed, 10 insertions(+), 16 deletions(-) diff --git a/components/layout_thread/dom_wrapper.rs b/components/layout_thread/dom_wrapper.rs index 58f3ed7327e..9b0f2f67131 100644 --- a/components/layout_thread/dom_wrapper.rs +++ b/components/layout_thread/dom_wrapper.rs @@ -569,7 +569,7 @@ impl<'le> TElement for ServoLayoutElement<'le> { } unsafe fn set_dirty_descendants(&self) { - debug_assert!(self.as_node().is_in_document()); + debug_assert!(self.as_node().is_connected()); self.as_node() .node .set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true) diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index a54ffcd8cf5..21144f79a67 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -645,7 +645,7 @@ impl Document { } pub fn content_and_heritage_changed(&self, node: &Node) { - if node.is_in_doc() { + if node.is_connected() { node.note_dirty_descendants(); } diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 3238727267e..d3ef77696ce 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -572,7 +572,7 @@ impl Node { // FIXME(emilio): This and the function below should move to Element. pub fn note_dirty_descendants(&self) { - debug_assert!(self.is_in_doc()); + debug_assert!(self.is_connected()); for ancestor in self.inclusive_ancestors(ShadowIncluding::Yes) { if ancestor.get_flag(NodeFlags::HAS_DIRTY_DESCENDANTS) { @@ -611,11 +611,15 @@ impl Node { match self.type_id() { NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::Text)) => { - if let Some(parent) = self.composed_parent_node() { - parent.downcast::().unwrap().restyle(damage) - } + self.parent_node.get().unwrap().dirty(damage) }, NodeTypeId::Element(_) => self.downcast::().unwrap().restyle(damage), + NodeTypeId::DocumentFragment(DocumentFragmentTypeId::ShadowRoot) => self + .downcast::() + .unwrap() + .Host() + .upcast::() + .restyle(damage), _ => {}, }; } @@ -965,16 +969,6 @@ impl Node { self.is_connected() && self.owner_doc().browsing_context().is_some() } - fn composed_parent_node(&self) -> Option> { - let parent = self.parent_node.get(); - if let Some(ref parent) = parent { - if let Some(shadow_root) = parent.downcast::() { - return Some(DomRoot::from_ref(shadow_root.Host().upcast::())); - } - } - parent - } - pub fn children(&self) -> impl Iterator> { SimpleNodeIterator { current: self.GetFirstChild(), From ccc4f7c37700a87b58fdaee6468e53983a6fb695 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Mon, 25 Mar 2019 10:18:09 +0100 Subject: [PATCH 75/83] Add dom.shadowdom.enabled to preferences list --- components/config/prefs.rs | 3 +++ resources/prefs.json | 1 + 2 files changed, 4 insertions(+) diff --git a/components/config/prefs.rs b/components/config/prefs.rs index e8b8b9a1e7e..76e70933bde 100644 --- a/components/config/prefs.rs +++ b/components/config/prefs.rs @@ -222,6 +222,9 @@ mod gen { enabled: bool, } }, + shadowdom: { + enabled: bool, + }, svg: { enabled: bool, }, diff --git a/resources/prefs.json b/resources/prefs.json index 1ca4197be44..b882ad9ca46 100644 --- a/resources/prefs.json +++ b/resources/prefs.json @@ -19,6 +19,7 @@ "dom.serviceworker.enabled": false, "dom.serviceworker.timeout_seconds": 60, "dom.servoparser.async_html_tokenizer.enabled": false, + "dom.shadowdom.enabled": false, "dom.svg.enabled": false, "dom.testable_crash.enabled": false, "dom.testbinding.enabled": false, From 3f312f7915fb3d025871ab5f4af56c0a9257f77d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Tue, 26 Mar 2019 10:48:41 +0100 Subject: [PATCH 76/83] Set dirty descendants flag only for elements --- components/script/dom/node.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index d3ef77696ce..889c22f68ca 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -579,7 +579,9 @@ impl Node { return; } - ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true); + if ancestor.is::() { + ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true); + } } } From 9df1c2f2cc25f77499bc5792547d11cf9db405eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Mon, 22 Apr 2019 12:29:39 +0200 Subject: [PATCH 77/83] Revert unnecessary format changes --- components/style/stylesheet_set.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/components/style/stylesheet_set.rs b/components/style/stylesheet_set.rs index 1d803e5dd01..1abc527bbdd 100644 --- a/components/style/stylesheet_set.rs +++ b/components/style/stylesheet_set.rs @@ -450,8 +450,7 @@ macro_rules! sheet_set_methods { guard: &SharedRwLockReadGuard, ) { if let Some(device) = device { - self.invalidations - .collect_invalidations_for(device, sheet, guard); + self.invalidations.collect_invalidations_for(device, sheet, guard); } } @@ -498,7 +497,7 @@ macro_rules! sheet_set_methods { let collection = self.collection_for(&sheet, guard); collection.remove(&sheet) } - }; + } } impl DocumentStylesheetSet From e4f34fde1bbddffdf1bd6e5157f9aee416938b8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Mon, 22 Apr 2019 13:19:51 +0200 Subject: [PATCH 78/83] Rename StylesheetSet to StylesheetSetRef --- components/script/dom/document.rs | 6 +++--- components/script/dom/documentorshadowroot.rs | 6 +++--- components/script/dom/shadowroot.rs | 6 +++--- components/style/stylesheet_set.rs | 16 ++++++++-------- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 21144f79a67..ddcdcca24dc 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -154,7 +154,7 @@ use style::media_queries::{Device, MediaType}; use style::selector_parser::{RestyleDamage, Snapshot}; use style::shared_lock::SharedRwLock as StyleSharedRwLock; use style::str::{split_html_space_chars, str_join}; -use style::stylesheet_set::{DocumentStylesheetSet, StylesheetSet}; +use style::stylesheet_set::{DocumentStylesheetSet, StylesheetSetRef}; use style::stylesheets::{Origin, OriginSet, Stylesheet}; use url::percent_encoding::percent_decode; use url::Host; @@ -3193,7 +3193,7 @@ impl Document { DocumentOrShadowRoot::add_stylesheet( owner, - StylesheetSet::Document(stylesheets), + StylesheetSetRef::Document(stylesheets), sheet, insertion_point, self.style_shared_lock(), @@ -3211,7 +3211,7 @@ impl Document { DocumentOrShadowRoot::remove_stylesheet( owner, s, - StylesheetSet::Document(&mut *self.stylesheets.borrow_mut()), + StylesheetSetRef::Document(&mut *self.stylesheets.borrow_mut()), ) } } diff --git a/components/script/dom/documentorshadowroot.rs b/components/script/dom/documentorshadowroot.rs index 03932159359..5aa2a9eb625 100644 --- a/components/script/dom/documentorshadowroot.rs +++ b/components/script/dom/documentorshadowroot.rs @@ -24,7 +24,7 @@ use style::context::QuirksMode; use style::invalidation::media_queries::{MediaListKey, ToMediaListKey}; use style::media_queries::MediaList; use style::shared_lock::{SharedRwLock as StyleSharedRwLock, SharedRwLockReadGuard}; -use style::stylesheet_set::StylesheetSet; +use style::stylesheet_set::StylesheetSetRef; use style::stylesheets::{CssRule, Origin, Stylesheet}; #[derive(Clone, JSTraceable, MallocSizeOf)] @@ -216,7 +216,7 @@ impl DocumentOrShadowRoot { pub fn remove_stylesheet( owner: &Element, s: &Arc, - mut stylesheets: StylesheetSet, + mut stylesheets: StylesheetSetRef, ) { let guard = s.shared_lock.read(); @@ -236,7 +236,7 @@ impl DocumentOrShadowRoot { #[allow(unrooted_must_root)] // Owner needs to be rooted already necessarily. pub fn add_stylesheet( owner: &Element, - mut stylesheets: StylesheetSet, + mut stylesheets: StylesheetSetRef, sheet: Arc, insertion_point: Option, style_shared_lock: &StyleSharedRwLock, diff --git a/components/script/dom/shadowroot.rs b/components/script/dom/shadowroot.rs index a32f9bb5c24..153993a1d62 100644 --- a/components/script/dom/shadowroot.rs +++ b/components/script/dom/shadowroot.rs @@ -25,7 +25,7 @@ use style::author_styles::AuthorStyles; use style::dom::TElement; use style::media_queries::Device; use style::shared_lock::SharedRwLockReadGuard; -use style::stylesheet_set::StylesheetSet; +use style::stylesheet_set::StylesheetSetRef; use style::stylesheets::Stylesheet; // https://dom.spec.whatwg.org/#interface-shadowroot @@ -102,7 +102,7 @@ impl ShadowRoot { .cloned(); DocumentOrShadowRoot::add_stylesheet( owner, - StylesheetSet::Author(stylesheets), + StylesheetSetRef::Author(stylesheets), sheet, insertion_point, self.document.style_shared_lock(), @@ -115,7 +115,7 @@ impl ShadowRoot { DocumentOrShadowRoot::remove_stylesheet( owner, s, - StylesheetSet::Author(&mut self.author_styles.borrow_mut().stylesheets), + StylesheetSetRef::Author(&mut self.author_styles.borrow_mut().stylesheets), ) } diff --git a/components/style/stylesheet_set.rs b/components/style/stylesheet_set.rs index 1abc527bbdd..ed0f5781061 100644 --- a/components/style/stylesheet_set.rs +++ b/components/style/stylesheet_set.rs @@ -374,7 +374,7 @@ where } /// Functionality common to DocumentStylesheetSet and AuthorStylesheetSet. -pub enum StylesheetSet<'a, S> +pub enum StylesheetSetRef<'a, S> where S: StylesheetInDocument + PartialEq + 'static, { @@ -384,7 +384,7 @@ where Document(&'a mut DocumentStylesheetSet), } -impl<'a, S> StylesheetSet<'a, S> +impl<'a, S> StylesheetSetRef<'a, S> where S: StylesheetInDocument + PartialEq + 'static, { @@ -398,8 +398,8 @@ where guard: &SharedRwLockReadGuard, ) { match self { - StylesheetSet::Author(set) => set.append_stylesheet(device, sheet, guard), - StylesheetSet::Document(set) => set.append_stylesheet(device, sheet, guard), + StylesheetSetRef::Author(set) => set.append_stylesheet(device, sheet, guard), + StylesheetSetRef::Document(set) => set.append_stylesheet(device, sheet, guard), } } @@ -412,10 +412,10 @@ where guard: &SharedRwLockReadGuard, ) { match self { - StylesheetSet::Author(set) => { + StylesheetSetRef::Author(set) => { set.insert_stylesheet_before(device, sheet, before_sheet, guard) }, - StylesheetSet::Document(set) => { + StylesheetSetRef::Document(set) => { set.insert_stylesheet_before(device, sheet, before_sheet, guard) }, } @@ -429,8 +429,8 @@ where guard: &SharedRwLockReadGuard, ) { match self { - StylesheetSet::Author(set) => set.remove_stylesheet(device, sheet, guard), - StylesheetSet::Document(set) => set.remove_stylesheet(device, sheet, guard), + StylesheetSetRef::Author(set) => set.remove_stylesheet(device, sheet, guard), + StylesheetSetRef::Document(set) => set.remove_stylesheet(device, sheet, guard), } } } From 9d52feffbbfd77a1e5432ae108e338d572e07eb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Mon, 22 Apr 2019 13:32:05 +0200 Subject: [PATCH 79/83] Rename shadow_root_from_node to containing_shadow_root --- components/script/dom/node.rs | 4 ++-- components/script/stylesheet_loader.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 889c22f68ca..f58f1af652b 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -2827,7 +2827,7 @@ pub fn document_from_node + DomObject>(derived: &T) -> DomR derived.upcast().owner_doc() } -pub fn shadow_root_from_node + DomObject>( +pub fn containing_shadow_root + DomObject>( derived: &T, ) -> Option> { derived.upcast().owner_shadow_root() @@ -2837,7 +2837,7 @@ pub fn shadow_root_from_node + DomObject>( pub fn stylesheets_owner_from_node + DomObject>( derived: &T, ) -> StyleSheetListOwner { - if let Some(shadow_root) = shadow_root_from_node(derived) { + if let Some(shadow_root) = containing_shadow_root(derived) { StyleSheetListOwner::ShadowRoot(Dom::from_ref(&*shadow_root)) } else { StyleSheetListOwner::Document(Dom::from_ref(&*document_from_node(derived))) diff --git a/components/script/stylesheet_loader.rs b/components/script/stylesheet_loader.rs index 3c75bfef520..69975c7803b 100644 --- a/components/script/stylesheet_loader.rs +++ b/components/script/stylesheet_loader.rs @@ -13,7 +13,7 @@ use crate::dom::eventtarget::EventTarget; use crate::dom::globalscope::GlobalScope; use crate::dom::htmlelement::HTMLElement; use crate::dom::htmllinkelement::{HTMLLinkElement, RequestGenerationId}; -use crate::dom::node::{document_from_node, shadow_root_from_node, window_from_node}; +use crate::dom::node::{containing_shadow_root, document_from_node, window_from_node}; use crate::dom::performanceresourcetiming::InitiatorType; use crate::dom::shadowroot::ShadowRoot; use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener}; @@ -270,7 +270,7 @@ impl<'a> StylesheetLoader<'a> { integrity_metadata: String, ) { let document = document_from_node(self.elem); - let shadow_root = shadow_root_from_node(self.elem).map(|sr| Trusted::new(&*sr)); + let shadow_root = containing_shadow_root(self.elem).map(|sr| Trusted::new(&*sr)); let gen = self .elem .downcast::() From d0b2e826ef4a79a0c4b0b33d4a66f0ab5c3c9d61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Mon, 22 Apr 2019 14:30:10 +0200 Subject: [PATCH 80/83] Move StylesheetSetRef to script --- components/script/dom/document.rs | 3 +- components/script/dom/documentorshadowroot.rs | 2 +- components/script/dom/shadowroot.rs | 2 +- components/script/lib.rs | 1 + components/script/stylesheet_set.rs | 70 +++++++++++++++++++ components/style/stylesheet_set.rs | 62 ---------------- 6 files changed, 75 insertions(+), 65 deletions(-) create mode 100644 components/script/stylesheet_set.rs diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index ddcdcca24dc..1a6714f5927 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -101,6 +101,7 @@ use crate::dom::windowproxy::WindowProxy; use crate::fetch::FetchCanceller; use crate::script_runtime::{CommonScriptMsg, ScriptThreadEventCategory}; use crate::script_thread::{MainThreadScriptMsg, ScriptThread}; +use crate::stylesheet_set::StylesheetSetRef; use crate::task::TaskBox; use crate::task_source::{TaskSource, TaskSourceName}; use crate::timers::OneshotTimerCallback; @@ -154,7 +155,7 @@ use style::media_queries::{Device, MediaType}; use style::selector_parser::{RestyleDamage, Snapshot}; use style::shared_lock::SharedRwLock as StyleSharedRwLock; use style::str::{split_html_space_chars, str_join}; -use style::stylesheet_set::{DocumentStylesheetSet, StylesheetSetRef}; +use style::stylesheet_set::DocumentStylesheetSet; use style::stylesheets::{Origin, OriginSet, Stylesheet}; use url::percent_encoding::percent_decode; use url::Host; diff --git a/components/script/dom/documentorshadowroot.rs b/components/script/dom/documentorshadowroot.rs index 5aa2a9eb625..8a29d16d013 100644 --- a/components/script/dom/documentorshadowroot.rs +++ b/components/script/dom/documentorshadowroot.rs @@ -12,6 +12,7 @@ use crate::dom::htmlelement::HTMLElement; use crate::dom::htmlmetaelement::HTMLMetaElement; use crate::dom::node::{self, Node, VecPreOrderInsertionHelper}; use crate::dom::window::Window; +use crate::stylesheet_set::StylesheetSetRef; use euclid::Point2D; use js::jsapi::JS_GetRuntime; use script_layout_interface::message::{NodesFromPointQueryType, QueryMsg}; @@ -24,7 +25,6 @@ use style::context::QuirksMode; use style::invalidation::media_queries::{MediaListKey, ToMediaListKey}; use style::media_queries::MediaList; use style::shared_lock::{SharedRwLock as StyleSharedRwLock, SharedRwLockReadGuard}; -use style::stylesheet_set::StylesheetSetRef; use style::stylesheets::{CssRule, Origin, Stylesheet}; #[derive(Clone, JSTraceable, MallocSizeOf)] diff --git a/components/script/dom/shadowroot.rs b/components/script/dom/shadowroot.rs index 153993a1d62..ae108f8109c 100644 --- a/components/script/dom/shadowroot.rs +++ b/components/script/dom/shadowroot.rs @@ -17,6 +17,7 @@ use crate::dom::element::Element; use crate::dom::node::{Node, NodeDamage, NodeFlags, ShadowIncluding}; use crate::dom::stylesheetlist::{StyleSheetList, StyleSheetListOwner}; use crate::dom::window::Window; +use crate::stylesheet_set::StylesheetSetRef; use dom_struct::dom_struct; use selectors::context::QuirksMode; use servo_arc::Arc; @@ -25,7 +26,6 @@ use style::author_styles::AuthorStyles; use style::dom::TElement; use style::media_queries::Device; use style::shared_lock::SharedRwLockReadGuard; -use style::stylesheet_set::StylesheetSetRef; use style::stylesheets::Stylesheet; // https://dom.spec.whatwg.org/#interface-shadowroot diff --git a/components/script/lib.rs b/components/script/lib.rs index 3f48e3d9118..327209d71db 100644 --- a/components/script/lib.rs +++ b/components/script/lib.rs @@ -69,6 +69,7 @@ pub mod script_thread; mod serviceworker_manager; mod serviceworkerjob; mod stylesheet_loader; +mod stylesheet_set; mod task_manager; mod task_queue; mod task_source; diff --git a/components/script/stylesheet_set.rs b/components/script/stylesheet_set.rs new file mode 100644 index 00000000000..ddb2f608e57 --- /dev/null +++ b/components/script/stylesheet_set.rs @@ -0,0 +1,70 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * 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 style::media_queries::Device; +use style::shared_lock::SharedRwLockReadGuard; +use style::stylesheet_set::{AuthorStylesheetSet, DocumentStylesheetSet}; +use style::stylesheets::StylesheetInDocument; + +/// Functionality common to DocumentStylesheetSet and AuthorStylesheetSet. +pub enum StylesheetSetRef<'a, S> +where + S: StylesheetInDocument + PartialEq + 'static, +{ + /// Author stylesheet set. + Author(&'a mut AuthorStylesheetSet), + /// Document stylesheet set. + Document(&'a mut DocumentStylesheetSet), +} + +impl<'a, S> StylesheetSetRef<'a, S> +where + S: StylesheetInDocument + PartialEq + 'static, +{ + /// Appends a new stylesheet to the current set. + /// + /// No device implies not computing invalidations. + pub fn append_stylesheet( + &mut self, + device: Option<&Device>, + sheet: S, + guard: &SharedRwLockReadGuard, + ) { + match self { + StylesheetSetRef::Author(set) => set.append_stylesheet(device, sheet, guard), + StylesheetSetRef::Document(set) => set.append_stylesheet(device, sheet, guard), + } + } + + /// Insert a given stylesheet before another stylesheet in the document. + pub fn insert_stylesheet_before( + &mut self, + device: Option<&Device>, + sheet: S, + before_sheet: S, + guard: &SharedRwLockReadGuard, + ) { + match self { + StylesheetSetRef::Author(set) => { + set.insert_stylesheet_before(device, sheet, before_sheet, guard) + }, + StylesheetSetRef::Document(set) => { + set.insert_stylesheet_before(device, sheet, before_sheet, guard) + }, + } + } + + /// Remove a given stylesheet from the set. + pub fn remove_stylesheet( + &mut self, + device: Option<&Device>, + sheet: S, + guard: &SharedRwLockReadGuard, + ) { + match self { + StylesheetSetRef::Author(set) => set.remove_stylesheet(device, sheet, guard), + StylesheetSetRef::Document(set) => set.remove_stylesheet(device, sheet, guard), + } + } +} diff --git a/components/style/stylesheet_set.rs b/components/style/stylesheet_set.rs index ed0f5781061..d2c3ad0f88e 100644 --- a/components/style/stylesheet_set.rs +++ b/components/style/stylesheet_set.rs @@ -373,68 +373,6 @@ where invalidations: StylesheetInvalidationSet, } -/// Functionality common to DocumentStylesheetSet and AuthorStylesheetSet. -pub enum StylesheetSetRef<'a, S> -where - S: StylesheetInDocument + PartialEq + 'static, -{ - /// Author stylesheet set. - Author(&'a mut AuthorStylesheetSet), - /// Document stylesheet set. - Document(&'a mut DocumentStylesheetSet), -} - -impl<'a, S> StylesheetSetRef<'a, S> -where - S: StylesheetInDocument + PartialEq + 'static, -{ - /// Appends a new stylesheet to the current set. - /// - /// No device implies not computing invalidations. - pub fn append_stylesheet( - &mut self, - device: Option<&Device>, - sheet: S, - guard: &SharedRwLockReadGuard, - ) { - match self { - StylesheetSetRef::Author(set) => set.append_stylesheet(device, sheet, guard), - StylesheetSetRef::Document(set) => set.append_stylesheet(device, sheet, guard), - } - } - - /// Insert a given stylesheet before another stylesheet in the document. - pub fn insert_stylesheet_before( - &mut self, - device: Option<&Device>, - sheet: S, - before_sheet: S, - guard: &SharedRwLockReadGuard, - ) { - match self { - StylesheetSetRef::Author(set) => { - set.insert_stylesheet_before(device, sheet, before_sheet, guard) - }, - StylesheetSetRef::Document(set) => { - set.insert_stylesheet_before(device, sheet, before_sheet, guard) - }, - } - } - - /// Remove a given stylesheet from the set. - pub fn remove_stylesheet( - &mut self, - device: Option<&Device>, - sheet: S, - guard: &SharedRwLockReadGuard, - ) { - match self { - StylesheetSetRef::Author(set) => set.remove_stylesheet(device, sheet, guard), - StylesheetSetRef::Document(set) => set.remove_stylesheet(device, sheet, guard), - } - } -} - /// This macro defines methods common to DocumentStylesheetSet and /// AuthorStylesheetSet. /// From 9b2eb775302b84542ab8fea921ab441342fe79c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Tue, 23 Apr 2019 11:36:06 +0200 Subject: [PATCH 81/83] Do not lazy initialize RareData on its getters --- components/script/dom/element.rs | 117 ++++++++++++++---------------- components/script/dom/macros.rs | 23 ++---- components/script/dom/node.rs | 67 +++++++++-------- components/script/dom/raredata.rs | 3 + 4 files changed, 101 insertions(+), 109 deletions(-) diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 6983b8be2c1..034c57abad8 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -332,75 +332,60 @@ impl Element { } pub fn set_custom_element_state(&self, state: CustomElementState) { - self.rare_data_mut().as_mut().unwrap().custom_element_state = state; + self.ensure_rare_data().custom_element_state = state; } pub fn get_custom_element_state(&self) -> CustomElementState { - self.rare_data().as_ref().unwrap().custom_element_state + if let Some(rare_data) = self.rare_data().as_ref() { + return rare_data.custom_element_state; + } + CustomElementState::Undefined } pub fn set_custom_element_definition(&self, definition: Rc) { - self.rare_data_mut() - .as_mut() - .unwrap() - .custom_element_definition = Some(definition); + self.ensure_rare_data().custom_element_definition = Some(definition); } pub fn get_custom_element_definition(&self) -> Option> { - self.rare_data() - .as_ref() - .unwrap() - .custom_element_definition - .clone() + if let Some(rare_data) = self.rare_data().as_ref() { + return rare_data.custom_element_definition.clone(); + } + None } pub fn push_callback_reaction(&self, function: Rc, args: Box<[Heap]>) { - self.rare_data_mut() - .as_mut() - .unwrap() + self.ensure_rare_data() .custom_element_reaction_queue .push(CustomElementReaction::Callback(function, args)); } pub fn push_upgrade_reaction(&self, definition: Rc) { - self.rare_data_mut() - .as_mut() - .unwrap() + self.ensure_rare_data() .custom_element_reaction_queue .push(CustomElementReaction::Upgrade(definition)); } pub fn clear_reaction_queue(&self) { - self.rare_data_mut() - .as_mut() - .unwrap() + self.ensure_rare_data() .custom_element_reaction_queue .clear(); } pub fn invoke_reactions(&self) { - // TODO: This is not spec compliant, as this will allow some reactions to be processed - // after clear_reaction_queue has been called. - rooted_vec!(let mut reactions); - while !self - .rare_data() - .as_ref() - .unwrap() - .custom_element_reaction_queue - .is_empty() - { - mem::swap( - &mut *reactions, - &mut self - .rare_data_mut() - .as_mut() - .unwrap() - .custom_element_reaction_queue, - ); - for reaction in reactions.iter() { - reaction.invoke(self); + if let Some(rare_data) = self.rare_data().as_ref() { + // TODO: This is not spec compliant, as this will allow some reactions to be processed + // after clear_reaction_queue has been called. + rooted_vec!(let mut reactions); + while !rare_data.custom_element_reaction_queue.is_empty() { + mem::swap( + &mut *reactions, + &mut self.ensure_rare_data().custom_element_reaction_queue, + ); + for reaction in reactions.iter() { + reaction.invoke(self); + } + reactions.clear(); } - reactions.clear(); } } @@ -458,7 +443,10 @@ impl Element { } pub fn is_shadow_host(&self) -> bool { - self.rare_data().as_ref().unwrap().shadow_root.is_some() + if let Some(rare_data) = self.rare_data().as_ref() { + return rare_data.shadow_root.is_some(); + } + false } /// https://dom.spec.whatwg.org/#dom-element-attachshadow @@ -502,7 +490,7 @@ impl Element { // Steps 4, 5 and 6. let shadow_root = ShadowRoot::new(self, &*self.node.owner_doc()); - self.rare_data_mut().as_mut().unwrap().shadow_root = Some(Dom::from_ref(&*shadow_root)); + self.ensure_rare_data().shadow_root = Some(Dom::from_ref(&*shadow_root)); if self.is_connected() { self.node.owner_doc().register_shadow_root(&*shadow_root); @@ -1077,13 +1065,10 @@ impl LayoutElementHelpers for LayoutDom { #[inline] #[allow(unsafe_code)] unsafe fn get_shadow_root_for_layout(&self) -> Option> { - (*self.unsafe_get()) - .rare_data_for_layout() - .as_ref() - .unwrap() - .shadow_root - .as_ref() - .map(|sr| sr.to_layout()) + if let Some(rare_data) = (*self.unsafe_get()).rare_data_for_layout().as_ref() { + return rare_data.shadow_root.as_ref().map(|sr| sr.to_layout()); + } + None } } @@ -2827,13 +2812,15 @@ impl VirtualMethods for Element { let doc = document_from_node(self); - if let Some(ref shadow_root) = self.rare_data().as_ref().unwrap().shadow_root { - doc.register_shadow_root(&shadow_root); - let shadow_root = shadow_root.upcast::(); - shadow_root.set_flag(NodeFlags::IS_CONNECTED, context.tree_connected); - for node in shadow_root.children() { - node.set_flag(NodeFlags::IS_CONNECTED, context.tree_connected); - node.bind_to_tree(context); + if let Some(rare_data) = self.rare_data().as_ref() { + if let Some(ref shadow_root) = rare_data.shadow_root { + doc.register_shadow_root(&shadow_root); + let shadow_root = shadow_root.upcast::(); + shadow_root.set_flag(NodeFlags::IS_CONNECTED, context.tree_connected); + for node in shadow_root.children() { + node.set_flag(NodeFlags::IS_CONNECTED, context.tree_connected); + node.bind_to_tree(context); + } } } @@ -2865,13 +2852,15 @@ impl VirtualMethods for Element { let doc = document_from_node(self); - if let Some(ref shadow_root) = self.rare_data().as_ref().unwrap().shadow_root { - doc.unregister_shadow_root(&shadow_root); - let shadow_root = shadow_root.upcast::(); - shadow_root.set_flag(NodeFlags::IS_CONNECTED, false); - for node in shadow_root.children() { - node.set_flag(NodeFlags::IS_CONNECTED, false); - node.unbind_from_tree(context); + if let Some(rare_data) = self.rare_data().as_ref() { + if let Some(ref shadow_root) = rare_data.shadow_root { + doc.unregister_shadow_root(&shadow_root); + let shadow_root = shadow_root.upcast::(); + shadow_root.set_flag(NodeFlags::IS_CONNECTED, false); + for node in shadow_root.children() { + node.set_flag(NodeFlags::IS_CONNECTED, false); + node.unbind_from_tree(context); + } } } diff --git a/components/script/dom/macros.rs b/components/script/dom/macros.rs index 0fb51c7d8fd..de531f0c53f 100644 --- a/components/script/dom/macros.rs +++ b/components/script/dom/macros.rs @@ -635,29 +635,22 @@ macro_rules! handle_potential_webgl_error { macro_rules! impl_rare_data ( ($type:ty) => ( - fn init_rare_data(&self) { + fn rare_data(&self) -> Ref>> { + self.rare_data.borrow() + } + + fn ensure_rare_data(&self) -> RefMut> { let mut rare_data = self.rare_data.borrow_mut(); if rare_data.is_none() { *rare_data = Some(Default::default()); } - } - - fn rare_data(&self) -> Ref>> { - self.init_rare_data(); - self.rare_data.borrow() - } - - fn rare_data_mut(&self) -> RefMut>> { - self.init_rare_data(); - self.rare_data.borrow_mut() + RefMut::map(rare_data, |rare_data| { + rare_data.as_mut().unwrap() + }) } #[allow(unsafe_code)] fn rare_data_for_layout(&self) -> &Option> { - let mut rare_data = self.rare_data.borrow_mut_for_layout(); - if rare_data.is_none() { - *rare_data = Some(Default::default()); - } unsafe { self.rare_data.borrow_for_layout() } } ); diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index f58f1af652b..c95e90e303c 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -452,26 +452,25 @@ impl Node { } /// Return all registered mutation observers for this node. + /// XXX(ferjm) This should probably be split into two functions, + /// `registered_mutation_observers`, which returns an Option or + /// an empty slice or something, and doesn't create the rare data, + /// and `registered_mutation_observers_mut`, which does lazily + /// initialize the raredata. pub fn registered_mutation_observers(&self) -> RefMut> { - RefMut::map(self.rare_data_mut(), |rare_data| { - &mut rare_data.as_mut().unwrap().mutation_observers + RefMut::map(self.ensure_rare_data(), |rare_data| { + &mut rare_data.mutation_observers }) } /// Add a new mutation observer for a given node. pub fn add_mutation_observer(&self, observer: RegisteredObserver) { - self.rare_data_mut() - .as_mut() - .unwrap() - .mutation_observers - .push(observer); + self.ensure_rare_data().mutation_observers.push(observer); } /// Removes the mutation observer for a given node. pub fn remove_mutation_observer(&self, observer: &MutationObserver) { - self.rare_data_mut() - .as_mut() - .unwrap() + self.ensure_rare_data() .mutation_observers .retain(|reg_obs| &*reg_obs.observer != observer) } @@ -951,16 +950,17 @@ impl Node { if let Some(ref shadow_root) = self.downcast::() { return Some(DomRoot::from_ref(shadow_root)); } - self.rare_data() - .as_ref() - .unwrap() - .owner_shadow_root - .as_ref() - .map(|sr| DomRoot::from_ref(&**sr)) + if let Some(rare_data) = self.rare_data().as_ref() { + return rare_data + .owner_shadow_root + .as_ref() + .map(|sr| DomRoot::from_ref(&**sr)); + } + None } pub fn set_owner_shadow_root(&self, shadow_root: &ShadowRoot) { - self.rare_data_mut().as_mut().unwrap().owner_shadow_root = Some(Dom::from_ref(shadow_root)); + self.ensure_rare_data().owner_shadow_root = Some(Dom::from_ref(shadow_root)); } pub fn is_in_html_doc(&self) -> bool { @@ -1281,13 +1281,13 @@ impl LayoutNodeHelpers for LayoutDom { #[inline] #[allow(unsafe_code)] unsafe fn owner_shadow_root_for_layout(&self) -> Option> { - (*self.unsafe_get()) - .rare_data_for_layout() - .as_ref() - .unwrap() - .owner_shadow_root - .as_ref() - .map(|sr| sr.to_layout()) + if let Some(rare_data) = (*self.unsafe_get()).rare_data_for_layout().as_ref() { + return rare_data + .owner_shadow_root + .as_ref() + .map(|sr| sr.to_layout()); + } + None } #[inline] @@ -2293,14 +2293,21 @@ impl NodeMethods for Node { // https://dom.spec.whatwg.org/#dom-node-getrootnode fn GetRootNode(&self, options: &GetRootNodeOptions) -> DomRoot { if options.composed { - if let Some(ref shadow_root) = self.rare_data().as_ref().unwrap().owner_shadow_root { - // shadow-including root. - return shadow_root.Host().upcast::().GetRootNode(options); + if let Some(rare_data) = self.rare_data().as_ref() { + if let Some(ref shadow_root) = rare_data.owner_shadow_root { + // shadow-including root. + return shadow_root.Host().upcast::().GetRootNode(options); + } } } - if let Some(ref shadow_root) = self.rare_data().as_ref().unwrap().owner_shadow_root { - DomRoot::from_ref(shadow_root.upcast::()) - } else if self.is_in_doc() { + + if let Some(rare_data) = self.rare_data().as_ref() { + if let Some(ref shadow_root) = rare_data.owner_shadow_root { + return DomRoot::from_ref(shadow_root.upcast::()); + } + } + + if self.is_in_doc() { DomRoot::from_ref(self.owner_doc().upcast::()) } else { self.inclusive_ancestors(ShadowIncluding::No) diff --git a/components/script/dom/raredata.rs b/components/script/dom/raredata.rs index 874db7b48ad..30929d2a247 100644 --- a/components/script/dom/raredata.rs +++ b/components/script/dom/raredata.rs @@ -10,6 +10,9 @@ use crate::dom::mutationobserver::RegisteredObserver; use crate::dom::shadowroot::ShadowRoot; use std::rc::Rc; +//XXX(ferjm) Ideally merge NodeRareData and ElementRareData so they share +// storage. + #[derive(Default, JSTraceable, MallocSizeOf)] #[must_root] pub struct NodeRareData { From 68bee1c7717f6219bcace8f6be4de42629687eab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Fri, 26 Apr 2019 09:44:21 +0200 Subject: [PATCH 82/83] Final nits; fix custom elements rare data usage; s/owner_s_r/containing_s_r Clarify special case for containing_shadow_root and add it to layout accessor --- components/layout_thread/dom_wrapper.rs | 2 +- components/script/dom/element.rs | 106 ++++++++++++----------- components/script/dom/htmlbaseelement.rs | 2 +- components/script/dom/macros.rs | 5 ++ components/script/dom/node.rs | 66 +++++++------- components/script/dom/raredata.rs | 3 +- 6 files changed, 95 insertions(+), 89 deletions(-) diff --git a/components/layout_thread/dom_wrapper.rs b/components/layout_thread/dom_wrapper.rs index 9b0f2f67131..88eedef7d17 100644 --- a/components/layout_thread/dom_wrapper.rs +++ b/components/layout_thread/dom_wrapper.rs @@ -711,7 +711,7 @@ impl<'le> TElement for ServoLayoutElement<'le> { unsafe { self.element .upcast() - .owner_shadow_root_for_layout() + .containing_shadow_root_for_layout() .map(ServoShadowRoot::from_layout_js) } } diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 034c57abad8..870b5dc7a4f 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -347,10 +347,7 @@ impl Element { } pub fn get_custom_element_definition(&self) -> Option> { - if let Some(rare_data) = self.rare_data().as_ref() { - return rare_data.custom_element_definition.clone(); - } - None + self.rare_data().as_ref()?.custom_element_definition.clone() } pub fn push_callback_reaction(&self, function: Rc, args: Box<[Heap]>) { @@ -366,26 +363,30 @@ impl Element { } pub fn clear_reaction_queue(&self) { - self.ensure_rare_data() - .custom_element_reaction_queue - .clear(); + if let Some(ref mut rare_data) = *self.rare_data_mut() { + rare_data.custom_element_reaction_queue.clear(); + } } pub fn invoke_reactions(&self) { - if let Some(rare_data) = self.rare_data().as_ref() { - // TODO: This is not spec compliant, as this will allow some reactions to be processed - // after clear_reaction_queue has been called. + loop { rooted_vec!(let mut reactions); - while !rare_data.custom_element_reaction_queue.is_empty() { - mem::swap( - &mut *reactions, - &mut self.ensure_rare_data().custom_element_reaction_queue, - ); - for reaction in reactions.iter() { - reaction.invoke(self); - } - reactions.clear(); + match *self.rare_data_mut() { + Some(ref mut data) => { + mem::swap(&mut *reactions, &mut data.custom_element_reaction_queue) + }, + None => break, + }; + + if reactions.is_empty() { + break; } + + for reaction in reactions.iter() { + reaction.invoke(self); + } + + reactions.clear(); } } @@ -442,11 +443,16 @@ impl Element { }) } + fn shadow_root(&self) -> Option> { + self.rare_data() + .as_ref()? + .shadow_root + .as_ref() + .map(|sr| DomRoot::from_ref(&**sr)) + } + pub fn is_shadow_host(&self) -> bool { - if let Some(rare_data) = self.rare_data().as_ref() { - return rare_data.shadow_root.is_some(); - } - false + self.shadow_root().is_some() } /// https://dom.spec.whatwg.org/#dom-element-attachshadow @@ -1065,10 +1071,12 @@ impl LayoutElementHelpers for LayoutDom { #[inline] #[allow(unsafe_code)] unsafe fn get_shadow_root_for_layout(&self) -> Option> { - if let Some(rare_data) = (*self.unsafe_get()).rare_data_for_layout().as_ref() { - return rare_data.shadow_root.as_ref().map(|sr| sr.to_layout()); - } - None + (*self.unsafe_get()) + .rare_data_for_layout() + .as_ref()? + .shadow_root + .as_ref() + .map(|sr| sr.to_layout()) } } @@ -2742,21 +2750,21 @@ impl VirtualMethods for Element { None } }); - let owner_shadow_root = self.upcast::().owner_shadow_root(); + let containing_shadow_root = self.upcast::().containing_shadow_root(); if node.is_connected() { let value = attr.value().as_atom().clone(); match mutation { AttributeMutation::Set(old_value) => { if let Some(old_value) = old_value { let old_value = old_value.as_atom().clone(); - if let Some(ref shadow_root) = owner_shadow_root { + if let Some(ref shadow_root) = containing_shadow_root { shadow_root.unregister_named_element(self, old_value); } else { doc.unregister_named_element(self, old_value); } } if value != atom!("") { - if let Some(ref shadow_root) = owner_shadow_root { + if let Some(ref shadow_root) = containing_shadow_root { shadow_root.register_named_element(self, value); } else { doc.register_named_element(self, value); @@ -2765,7 +2773,7 @@ impl VirtualMethods for Element { }, AttributeMutation::Removed => { if value != atom!("") { - if let Some(ref shadow_root) = owner_shadow_root { + if let Some(ref shadow_root) = containing_shadow_root { shadow_root.unregister_named_element(self, value); } else { doc.unregister_named_element(self, value); @@ -2812,15 +2820,13 @@ impl VirtualMethods for Element { let doc = document_from_node(self); - if let Some(rare_data) = self.rare_data().as_ref() { - if let Some(ref shadow_root) = rare_data.shadow_root { - doc.register_shadow_root(&shadow_root); - let shadow_root = shadow_root.upcast::(); - shadow_root.set_flag(NodeFlags::IS_CONNECTED, context.tree_connected); - for node in shadow_root.children() { - node.set_flag(NodeFlags::IS_CONNECTED, context.tree_connected); - node.bind_to_tree(context); - } + if let Some(ref shadow_root) = self.shadow_root() { + doc.register_shadow_root(&shadow_root); + let shadow_root = shadow_root.upcast::(); + shadow_root.set_flag(NodeFlags::IS_CONNECTED, context.tree_connected); + for node in shadow_root.children() { + node.set_flag(NodeFlags::IS_CONNECTED, context.tree_connected); + node.bind_to_tree(context); } } @@ -2829,7 +2835,7 @@ impl VirtualMethods for Element { } if let Some(ref value) = *self.id_attribute.borrow() { - if let Some(shadow_root) = self.upcast::().owner_shadow_root() { + if let Some(shadow_root) = self.upcast::().containing_shadow_root() { shadow_root.register_named_element(self, value.clone()); } else { doc.register_named_element(self, value.clone()); @@ -2852,15 +2858,13 @@ impl VirtualMethods for Element { let doc = document_from_node(self); - if let Some(rare_data) = self.rare_data().as_ref() { - if let Some(ref shadow_root) = rare_data.shadow_root { - doc.unregister_shadow_root(&shadow_root); - let shadow_root = shadow_root.upcast::(); - shadow_root.set_flag(NodeFlags::IS_CONNECTED, false); - for node in shadow_root.children() { - node.set_flag(NodeFlags::IS_CONNECTED, false); - node.unbind_from_tree(context); - } + if let Some(ref shadow_root) = self.shadow_root() { + doc.unregister_shadow_root(&shadow_root); + let shadow_root = shadow_root.upcast::(); + shadow_root.set_flag(NodeFlags::IS_CONNECTED, false); + for node in shadow_root.children() { + node.set_flag(NodeFlags::IS_CONNECTED, false); + node.unbind_from_tree(context); } } @@ -2931,7 +2935,7 @@ impl<'a> SelectorsElement for DomRoot { } fn containing_shadow_host(&self) -> Option { - if let Some(shadow_root) = self.upcast::().owner_shadow_root() { + if let Some(shadow_root) = self.upcast::().containing_shadow_root() { Some(shadow_root.Host()) } else { None diff --git a/components/script/dom/htmlbaseelement.rs b/components/script/dom/htmlbaseelement.rs index fc20091302d..71aa235df62 100644 --- a/components/script/dom/htmlbaseelement.rs +++ b/components/script/dom/htmlbaseelement.rs @@ -64,7 +64,7 @@ impl HTMLBaseElement { /// Update the cached base element in response to binding or unbinding from /// a tree. pub fn bind_unbind(&self, tree_in_doc: bool) { - if !tree_in_doc || self.upcast::().owner_shadow_root().is_some() { + if !tree_in_doc || self.upcast::().containing_shadow_root().is_some() { return; } diff --git a/components/script/dom/macros.rs b/components/script/dom/macros.rs index de531f0c53f..021527a286a 100644 --- a/components/script/dom/macros.rs +++ b/components/script/dom/macros.rs @@ -639,6 +639,11 @@ macro_rules! impl_rare_data ( self.rare_data.borrow() } + #[allow(dead_code)] + fn rare_data_mut(&self) -> RefMut>> { + self.rare_data.borrow_mut() + } + fn ensure_rare_data(&self) -> RefMut> { let mut rare_data = self.rare_data.borrow_mut(); if rare_data.is_none() { diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index c95e90e303c..630e16d6d0e 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -282,10 +282,10 @@ impl Node { for node in new_child.traverse_preorder(ShadowIncluding::No) { if parent_in_shadow_tree { - if let Some(shadow_root) = self.owner_shadow_root() { - node.set_owner_shadow_root(&*shadow_root); + if let Some(shadow_root) = self.containing_shadow_root() { + node.set_containing_shadow_root(&*shadow_root); } - debug_assert!(node.owner_shadow_root().is_some()); + debug_assert!(node.containing_shadow_root().is_some()); } node.set_flag(NodeFlags::IS_IN_DOC, parent_in_doc); node.set_flag(NodeFlags::IS_IN_SHADOW_TREE, parent_in_shadow_tree); @@ -946,21 +946,21 @@ impl Node { self.owner_doc.set(Some(document)); } - pub fn owner_shadow_root(&self) -> Option> { + pub fn containing_shadow_root(&self) -> Option> { + // NodeRareData contains the shadow root the node belongs to, + // but this node may be a shadow root itself. if let Some(ref shadow_root) = self.downcast::() { return Some(DomRoot::from_ref(shadow_root)); } - if let Some(rare_data) = self.rare_data().as_ref() { - return rare_data - .owner_shadow_root - .as_ref() - .map(|sr| DomRoot::from_ref(&**sr)); - } - None + self.rare_data() + .as_ref()? + .containing_shadow_root + .as_ref() + .map(|sr| DomRoot::from_ref(&**sr)) } - pub fn set_owner_shadow_root(&self, shadow_root: &ShadowRoot) { - self.ensure_rare_data().owner_shadow_root = Some(Dom::from_ref(shadow_root)); + pub fn set_containing_shadow_root(&self, shadow_root: &ShadowRoot) { + self.ensure_rare_data().containing_shadow_root = Some(Dom::from_ref(shadow_root)); } pub fn is_in_html_doc(&self) -> bool { @@ -1195,7 +1195,7 @@ pub trait LayoutNodeHelpers { unsafe fn next_sibling_ref(&self) -> Option>; unsafe fn owner_doc_for_layout(&self) -> LayoutDom; - unsafe fn owner_shadow_root_for_layout(&self) -> Option>; + unsafe fn containing_shadow_root_for_layout(&self) -> Option>; unsafe fn is_element_for_layout(&self) -> bool; unsafe fn get_flag(&self, flag: NodeFlags) -> bool; @@ -1280,14 +1280,16 @@ impl LayoutNodeHelpers for LayoutDom { #[inline] #[allow(unsafe_code)] - unsafe fn owner_shadow_root_for_layout(&self) -> Option> { - if let Some(rare_data) = (*self.unsafe_get()).rare_data_for_layout().as_ref() { - return rare_data - .owner_shadow_root - .as_ref() - .map(|sr| sr.to_layout()); + unsafe fn containing_shadow_root_for_layout(&self) -> Option> { + if let Some(ref shadow_root) = self.downcast::() { + return Some(*shadow_root); } - None + (*self.unsafe_get()) + .rare_data_for_layout() + .as_ref()? + .containing_shadow_root + .as_ref() + .map(|sr| sr.to_layout()) } #[inline] @@ -2292,19 +2294,13 @@ impl NodeMethods for Node { // https://dom.spec.whatwg.org/#dom-node-getrootnode fn GetRootNode(&self, options: &GetRootNodeOptions) -> DomRoot { - if options.composed { - if let Some(rare_data) = self.rare_data().as_ref() { - if let Some(ref shadow_root) = rare_data.owner_shadow_root { - // shadow-including root. - return shadow_root.Host().upcast::().GetRootNode(options); - } - } - } - - if let Some(rare_data) = self.rare_data().as_ref() { - if let Some(ref shadow_root) = rare_data.owner_shadow_root { - return DomRoot::from_ref(shadow_root.upcast::()); - } + if let Some(shadow_root) = self.containing_shadow_root() { + return if options.composed { + // shadow-including root. + shadow_root.Host().upcast::().GetRootNode(options) + } else { + DomRoot::from_ref(shadow_root.upcast::()) + }; } if self.is_in_doc() { @@ -2837,7 +2833,7 @@ pub fn document_from_node + DomObject>(derived: &T) -> DomR pub fn containing_shadow_root + DomObject>( derived: &T, ) -> Option> { - derived.upcast().owner_shadow_root() + derived.upcast().containing_shadow_root() } #[allow(unrooted_must_root)] diff --git a/components/script/dom/raredata.rs b/components/script/dom/raredata.rs index 30929d2a247..2372b0b89ab 100644 --- a/components/script/dom/raredata.rs +++ b/components/script/dom/raredata.rs @@ -19,7 +19,7 @@ pub struct NodeRareData { /// The shadow root the node belongs to. /// This is None if the node is not in a shadow tree or /// if it is a ShadowRoot. - pub owner_shadow_root: Option>, + pub containing_shadow_root: Option>, /// Registered observers for this node. pub mutation_observers: Vec, } @@ -28,6 +28,7 @@ pub struct NodeRareData { #[must_root] pub struct ElementRareData { /// https://dom.spec.whatwg.org/#dom-element-shadowroot + /// The ShadowRoot this element is host of. /// XXX This is currently not exposed to web content. Only for /// internal use. pub shadow_root: Option>, From 37e88e77cdf00e3555599dd4004d03548bd95dcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Mon, 29 Apr 2019 12:15:16 +0200 Subject: [PATCH 83/83] Set self as containing_shadow_root for shadow roots --- components/script/dom/element.rs | 3 +++ components/script/dom/node.rs | 8 -------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 870b5dc7a4f..2d12e93774d 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -497,6 +497,9 @@ impl Element { // Steps 4, 5 and 6. let shadow_root = ShadowRoot::new(self, &*self.node.owner_doc()); self.ensure_rare_data().shadow_root = Some(Dom::from_ref(&*shadow_root)); + shadow_root + .upcast::() + .set_containing_shadow_root(&shadow_root); if self.is_connected() { self.node.owner_doc().register_shadow_root(&*shadow_root); diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 630e16d6d0e..814378aca88 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -947,11 +947,6 @@ impl Node { } pub fn containing_shadow_root(&self) -> Option> { - // NodeRareData contains the shadow root the node belongs to, - // but this node may be a shadow root itself. - if let Some(ref shadow_root) = self.downcast::() { - return Some(DomRoot::from_ref(shadow_root)); - } self.rare_data() .as_ref()? .containing_shadow_root @@ -1281,9 +1276,6 @@ impl LayoutNodeHelpers for LayoutDom { #[inline] #[allow(unsafe_code)] unsafe fn containing_shadow_root_for_layout(&self) -> Option> { - if let Some(ref shadow_root) = self.downcast::() { - return Some(*shadow_root); - } (*self.unsafe_get()) .rare_data_for_layout() .as_ref()?