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] 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) }) }