diff options
Diffstat (limited to 'components/script/dom/treewalker.rs')
-rw-r--r-- | components/script/dom/treewalker.rs | 286 |
1 files changed, 148 insertions, 138 deletions
diff --git a/components/script/dom/treewalker.rs b/components/script/dom/treewalker.rs index 2409d65af4f..86aa97466a7 100644 --- a/components/script/dom/treewalker.rs +++ b/components/script/dom/treewalker.rs @@ -1,62 +1,66 @@ /* 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 http://mozilla.org/MPL/2.0/. */ + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -use dom::bindings::callback::ExceptionHandling::Rethrow; -use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; -use dom::bindings::codegen::Bindings::NodeFilterBinding::NodeFilter; -use dom::bindings::codegen::Bindings::NodeFilterBinding::NodeFilterConstants; -use dom::bindings::codegen::Bindings::TreeWalkerBinding; -use dom::bindings::codegen::Bindings::TreeWalkerBinding::TreeWalkerMethods; -use dom::bindings::error::Fallible; -use dom::bindings::js::{JS, MutJS}; -use dom::bindings::js::Root; -use dom::bindings::reflector::{Reflector, reflect_dom_object}; -use dom::document::Document; -use dom::node::Node; +use crate::dom::bindings::callback::ExceptionHandling::Rethrow; +use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; +use crate::dom::bindings::codegen::Bindings::NodeFilterBinding::NodeFilter; +use crate::dom::bindings::codegen::Bindings::NodeFilterBinding::NodeFilterConstants; +use crate::dom::bindings::codegen::Bindings::TreeWalkerBinding::TreeWalkerMethods; +use crate::dom::bindings::error::{Error, Fallible}; +use crate::dom::bindings::reflector::{reflect_dom_object, Reflector}; +use crate::dom::bindings::root::{Dom, DomRoot, MutDom}; +use crate::dom::document::Document; +use crate::dom::node::Node; use dom_struct::dom_struct; +use std::cell::Cell; use std::rc::Rc; // https://dom.spec.whatwg.org/#interface-treewalker #[dom_struct] pub struct TreeWalker { reflector_: Reflector, - root_node: JS<Node>, - current_node: MutJS<Node>, + root_node: Dom<Node>, + current_node: MutDom<Node>, what_to_show: u32, - #[ignore_heap_size_of = "function pointers and Rc<T> are hard"] - filter: Filter + #[ignore_malloc_size_of = "function pointers and Rc<T> are hard"] + filter: Filter, + active: Cell<bool>, } impl TreeWalker { - fn new_inherited(root_node: &Node, - what_to_show: u32, - filter: Filter) -> TreeWalker { + fn new_inherited(root_node: &Node, what_to_show: u32, filter: Filter) -> TreeWalker { TreeWalker { reflector_: Reflector::new(), - root_node: JS::from_ref(root_node), - current_node: MutJS::new(root_node), + root_node: Dom::from_ref(root_node), + current_node: MutDom::new(root_node), what_to_show: what_to_show, - filter: filter + filter: filter, + active: Cell::new(false), } } - pub fn new_with_filter(document: &Document, - root_node: &Node, - what_to_show: u32, - filter: Filter) -> Root<TreeWalker> { - reflect_dom_object(box TreeWalker::new_inherited(root_node, what_to_show, filter), - document.window(), - TreeWalkerBinding::Wrap) + pub fn new_with_filter( + document: &Document, + root_node: &Node, + what_to_show: u32, + filter: Filter, + ) -> DomRoot<TreeWalker> { + reflect_dom_object( + Box::new(TreeWalker::new_inherited(root_node, what_to_show, filter)), + document.window(), + ) } - pub fn new(document: &Document, - root_node: &Node, - what_to_show: u32, - node_filter: Option<Rc<NodeFilter>>) -> Root<TreeWalker> { + pub fn new( + document: &Document, + root_node: &Node, + what_to_show: u32, + node_filter: Option<Rc<NodeFilter>>, + ) -> DomRoot<TreeWalker> { let filter = match node_filter { None => Filter::None, - Some(jsfilter) => Filter::JS(jsfilter) + Some(jsfilter) => Filter::Dom(jsfilter), }; TreeWalker::new_with_filter(document, root_node, what_to_show, filter) } @@ -64,8 +68,8 @@ impl TreeWalker { impl TreeWalkerMethods for TreeWalker { // https://dom.spec.whatwg.org/#dom-treewalker-root - fn Root(&self) -> Root<Node> { - Root::from_ref(&*self.root_node) + fn Root(&self) -> DomRoot<Node> { + DomRoot::from_ref(&*self.root_node) } // https://dom.spec.whatwg.org/#dom-treewalker-whattoshow @@ -77,13 +81,12 @@ impl TreeWalkerMethods for TreeWalker { fn GetFilter(&self) -> Option<Rc<NodeFilter>> { match self.filter { Filter::None => None, - Filter::JS(ref nf) => Some(nf.clone()), - Filter::Native(_) => panic!("Cannot convert native node filter to DOM NodeFilter") + Filter::Dom(ref nf) => Some(nf.clone()), } } // https://dom.spec.whatwg.org/#dom-treewalker-currentnode - fn CurrentNode(&self) -> Root<Node> { + fn CurrentNode(&self) -> DomRoot<Node> { self.current_node.get() } @@ -93,7 +96,7 @@ impl TreeWalkerMethods for TreeWalker { } // https://dom.spec.whatwg.org/#dom-treewalker-parentnode - fn ParentNode(&self) -> Fallible<Option<Root<Node>>> { + fn ParentNode(&self) -> Fallible<Option<DomRoot<Node>>> { // "1. Let node be the value of the currentNode attribute." let mut node = self.current_node.get(); // "2. While node is not null and is not root, run these substeps:" @@ -104,9 +107,9 @@ impl TreeWalkerMethods for TreeWalker { node = n; // "2. If node is not null and filtering node returns FILTER_ACCEPT, // then set the currentNode attribute to node, return node." - if NodeFilterConstants::FILTER_ACCEPT == try!(self.accept_node(&node)) { + if NodeFilterConstants::FILTER_ACCEPT == self.accept_node(&node)? { self.current_node.set(&node); - return Ok(Some(node)) + return Ok(Some(node)); } }, None => break, @@ -117,35 +120,31 @@ impl TreeWalkerMethods for TreeWalker { } // https://dom.spec.whatwg.org/#dom-treewalker-firstchild - fn FirstChild(&self) -> Fallible<Option<Root<Node>>> { + fn FirstChild(&self) -> Fallible<Option<DomRoot<Node>>> { // "The firstChild() method must traverse children of type first." - self.traverse_children(|node| node.GetFirstChild(), - |node| node.GetNextSibling()) + self.traverse_children(|node| node.GetFirstChild(), |node| node.GetNextSibling()) } // https://dom.spec.whatwg.org/#dom-treewalker-lastchild - fn LastChild(&self) -> Fallible<Option<Root<Node>>> { + fn LastChild(&self) -> Fallible<Option<DomRoot<Node>>> { // "The lastChild() method must traverse children of type last." - self.traverse_children(|node| node.GetLastChild(), - |node| node.GetPreviousSibling()) + self.traverse_children(|node| node.GetLastChild(), |node| node.GetPreviousSibling()) } // https://dom.spec.whatwg.org/#dom-treewalker-previoussibling - fn PreviousSibling(&self) -> Fallible<Option<Root<Node>>> { + fn PreviousSibling(&self) -> Fallible<Option<DomRoot<Node>>> { // "The nextSibling() method must traverse siblings of type next." - self.traverse_siblings(|node| node.GetLastChild(), - |node| node.GetPreviousSibling()) + self.traverse_siblings(|node| node.GetLastChild(), |node| node.GetPreviousSibling()) } // https://dom.spec.whatwg.org/#dom-treewalker-nextsibling - fn NextSibling(&self) -> Fallible<Option<Root<Node>>> { + fn NextSibling(&self) -> Fallible<Option<DomRoot<Node>>> { // "The previousSibling() method must traverse siblings of type previous." - self.traverse_siblings(|node| node.GetFirstChild(), - |node| node.GetNextSibling()) + self.traverse_siblings(|node| node.GetFirstChild(), |node| node.GetNextSibling()) } // https://dom.spec.whatwg.org/#dom-treewalker-previousnode - fn PreviousNode(&self) -> Fallible<Option<Root<Node>>> { + fn PreviousNode(&self) -> Fallible<Option<DomRoot<Node>>> { // "1. Let node be the value of the currentNode attribute." let mut node = self.current_node.get(); // "2. While node is not root, run these substeps:" @@ -163,16 +162,15 @@ impl TreeWalkerMethods for TreeWalker { // "4. If result is FILTER_ACCEPT, then // set the currentNode attribute to node and return node." loop { - let result = try!(self.accept_node(&node)); + let result = self.accept_node(&node)?; match result { NodeFilterConstants::FILTER_REJECT => break, - _ if node.GetFirstChild().is_some() => - node = node.GetLastChild().unwrap(), + _ if node.GetFirstChild().is_some() => node = node.GetLastChild().unwrap(), NodeFilterConstants::FILTER_ACCEPT => { self.current_node.set(&node); - return Ok(Some(node)) + return Ok(Some(node)); }, - _ => break + _ => break, } } // "5. Set sibling to the previous sibling of node." @@ -180,21 +178,23 @@ impl TreeWalkerMethods for TreeWalker { } // "3. If node is root or node's parent is null, return null." if self.is_root_node(&node) || node.GetParentNode().is_none() { - return Ok(None) + return Ok(None); } // "4. Set node to its parent." match node.GetParentNode() { None => - // This can happen if the user set the current node to somewhere - // outside of the tree rooted at the original root. - return Ok(None), - Some(n) => node = n + // This can happen if the user set the current node to somewhere + // outside of the tree rooted at the original root. + { + return Ok(None); + } + Some(n) => node = n, } // "5. Filter node and if the return value is FILTER_ACCEPT, then // set the currentNode attribute to node and return node." - if NodeFilterConstants::FILTER_ACCEPT == try!(self.accept_node(&node)) { + if NodeFilterConstants::FILTER_ACCEPT == self.accept_node(&node)? { self.current_node.set(&node); - return Ok(Some(node)) + return Ok(Some(node)); } } // "6. Return null." @@ -202,7 +202,7 @@ impl TreeWalkerMethods for TreeWalker { } // https://dom.spec.whatwg.org/#dom-treewalker-nextnode - fn NextNode(&self) -> Fallible<Option<Root<Node>>> { + fn NextNode(&self) -> Fallible<Option<DomRoot<Node>>> { // "1. Let node be the value of the currentNode attribute." let mut node = self.current_node.get(); // "2. Let result be FILTER_ACCEPT." @@ -220,14 +220,14 @@ impl TreeWalkerMethods for TreeWalker { // "1. Set node to its first child." node = child; // "2. Filter node and set result to the return value." - result = try!(self.accept_node(&node)); + result = self.accept_node(&node)?; // "3. If result is FILTER_ACCEPT, then // set the currentNode attribute to node and return node." if NodeFilterConstants::FILTER_ACCEPT == result { self.current_node.set(&node); - return Ok(Some(node)) + return Ok(Some(node)); } - } + }, } } // "2. If a node is following node and is not following root, @@ -238,14 +238,14 @@ impl TreeWalkerMethods for TreeWalker { Some(n) => { node = n; // "3. Filter node and set result to the return value." - result = try!(self.accept_node(&node)); + result = self.accept_node(&node)?; // "4. If result is FILTER_ACCEPT, then // set the currentNode attribute to node and return node." if NodeFilterConstants::FILTER_ACCEPT == result { self.current_node.set(&node); - return Ok(Some(node)) + return Ok(Some(node)); } - } + }, } // "5. Run these substeps again." } @@ -254,12 +254,14 @@ impl TreeWalkerMethods for TreeWalker { impl TreeWalker { // https://dom.spec.whatwg.org/#concept-traverse-children - fn traverse_children<F, G>(&self, - next_child: F, - next_sibling: G) - -> Fallible<Option<Root<Node>>> - where F: Fn(&Node) -> Option<Root<Node>>, - G: Fn(&Node) -> Option<Root<Node>> + fn traverse_children<F, G>( + &self, + next_child: F, + next_sibling: G, + ) -> Fallible<Option<DomRoot<Node>>> + where + F: Fn(&Node) -> Option<DomRoot<Node>>, + G: Fn(&Node) -> Option<DomRoot<Node>>, { // "To **traverse children** of type *type*, run these steps:" // "1. Let node be the value of the currentNode attribute." @@ -275,13 +277,13 @@ impl TreeWalker { // 4. Main: Repeat these substeps: 'main: loop { // "1. Filter node and let result be the return value." - let result = try!(self.accept_node(&node)); + let result = self.accept_node(&node)?; match result { // "2. If result is FILTER_ACCEPT, then set the currentNode // attribute to node and return node." NodeFilterConstants::FILTER_ACCEPT => { self.current_node.set(&node); - return Ok(Some(Root::from_ref(&node))) + return Ok(Some(DomRoot::from_ref(&node))); }, // "3. If result is FILTER_SKIP, run these subsubsteps:" NodeFilterConstants::FILTER_SKIP => { @@ -290,10 +292,10 @@ impl TreeWalker { if let Some(child) = next_child(&node) { // "2. If child is not null, set node to child and goto Main." node = child; - continue 'main + continue 'main; } }, - _ => {} + _ => {}, } // "4. Repeat these subsubsteps:" loop { @@ -304,7 +306,7 @@ impl TreeWalker { // set node to sibling and goto Main." Some(sibling) => { node = sibling; - continue 'main + continue 'main; }, None => { // "3. Let parent be node's parent." @@ -313,32 +315,36 @@ impl TreeWalker { // or parent is currentNode attribute's value, // return null." None => return Ok(None), - Some(ref parent) if self.is_root_node(&parent) - || self.is_current_node(&parent) => - return Ok(None), + Some(ref parent) + if self.is_root_node(&parent) || self.is_current_node(&parent) => + { + return Ok(None); + } // "5. Otherwise, set node to parent." - Some(parent) => node = parent + Some(parent) => node = parent, } - } + }, } } } } // https://dom.spec.whatwg.org/#concept-traverse-siblings - fn traverse_siblings<F, G>(&self, - next_child: F, - next_sibling: G) - -> Fallible<Option<Root<Node>>> - where F: Fn(&Node) -> Option<Root<Node>>, - G: Fn(&Node) -> Option<Root<Node>> + fn traverse_siblings<F, G>( + &self, + next_child: F, + next_sibling: G, + ) -> Fallible<Option<DomRoot<Node>>> + where + F: Fn(&Node) -> Option<DomRoot<Node>>, + G: Fn(&Node) -> Option<DomRoot<Node>>, { // "To **traverse siblings** of type *type* run these steps:" // "1. Let node be the value of the currentNode attribute." let mut node = self.current_node.get(); // "2. If node is root, return null." if self.is_root_node(&node) { - return Ok(None) + return Ok(None); } // "3. Run these substeps:" loop { @@ -350,12 +356,12 @@ impl TreeWalker { // "1. Set node to sibling." node = sibling_op.unwrap(); // "2. Filter node and let result be the return value." - let result = try!(self.accept_node(&node)); + let result = self.accept_node(&node)?; // "3. If result is FILTER_ACCEPT, then set the currentNode // attribute to node and return node." if NodeFilterConstants::FILTER_ACCEPT == result { self.current_node.set(&node); - return Ok(Some(node)) + return Ok(Some(node)); } // "4. Set sibling to node's first child if type is next, @@ -365,9 +371,10 @@ impl TreeWalker { // then set sibling to node's next sibling if type is next, // and node's previous sibling if type is previous." match (result, &sibling_op) { - (NodeFilterConstants::FILTER_REJECT, _) - | (_, &None) => sibling_op = next_sibling(&node), - _ => {} + (NodeFilterConstants::FILTER_REJECT, _) | (_, &None) => { + sibling_op = next_sibling(&node) + }, + _ => {}, } } // "3. Set node to its parent." @@ -378,31 +385,26 @@ impl TreeWalker { // "5. Filter node and if the return value is FILTER_ACCEPT, then return null." Some(n) => { node = n; - if NodeFilterConstants::FILTER_ACCEPT == try!(self.accept_node(&node)) { - return Ok(None) + if NodeFilterConstants::FILTER_ACCEPT == self.accept_node(&node)? { + return Ok(None); } - } + }, } // "6. Run these substeps again." } } // https://dom.spec.whatwg.org/#concept-tree-following - fn first_following_node_not_following_root(&self, node: &Node) - -> Option<Root<Node>> { + fn first_following_node_not_following_root(&self, node: &Node) -> Option<DomRoot<Node>> { // "An object A is following an object B if A and B are in the same tree // and A comes after B in tree order." match node.GetNextSibling() { None => { - let mut candidate = Root::from_ref(node); + let mut candidate = DomRoot::from_ref(node); while !self.is_root_node(&candidate) && candidate.GetNextSibling().is_none() { - match candidate.GetParentNode() { - None => - // This can happen if the user set the current node to somewhere - // outside of the tree rooted at the original root. - return None, - Some(n) => candidate = n - } + // This can return None if the user set the current node to somewhere + // outside of the tree rooted at the original root. + candidate = candidate.GetParentNode()?; } if self.is_root_node(&candidate) { None @@ -410,33 +412,40 @@ impl TreeWalker { candidate.GetNextSibling() } }, - it => it + it => it, } } // https://dom.spec.whatwg.org/#concept-node-filter fn accept_node(&self, node: &Node) -> Fallible<u16> { - // "To filter node run these steps:" - // "1. Let n be node's nodeType attribute value minus 1." + // Step 1. + if self.active.get() { + return Err(Error::InvalidState); + } + // Step 2. let n = node.NodeType() - 1; - // "2. If the nth bit (where 0 is the least significant bit) of whatToShow is not set, - // return FILTER_SKIP." + // Step 3. if (self.what_to_show & (1 << n)) == 0 { - return Ok(NodeFilterConstants::FILTER_SKIP) + return Ok(NodeFilterConstants::FILTER_SKIP); } - // "3. If filter is null, return FILTER_ACCEPT." - // "4. Let result be the return value of invoking filter." - // "5. If an exception was thrown, re-throw the exception." - // "6. Return result." match self.filter { + // Step 4. Filter::None => Ok(NodeFilterConstants::FILTER_ACCEPT), - Filter::Native(f) => Ok((f)(node)), - Filter::JS(ref callback) => callback.AcceptNode_(self, node, Rethrow) + Filter::Dom(ref callback) => { + // Step 5. + self.active.set(true); + // Step 6. + let result = callback.AcceptNode_(self, node, Rethrow); + // Step 7. + self.active.set(false); + // Step 8. + result + }, } } fn is_root_node(&self, node: &Node) -> bool { - JS::from_ref(node) == self.root_node + Dom::from_ref(node) == self.root_node } fn is_current_node(&self, node: &Node) -> bool { @@ -445,18 +454,20 @@ impl TreeWalker { } impl<'a> Iterator for &'a TreeWalker { - type Item = Root<Node>; + type Item = DomRoot<Node>; - fn next(&mut self) -> Option<Root<Node>> { + fn next(&mut self) -> Option<DomRoot<Node>> { match self.NextNode() { Ok(node) => node, Err(_) => - // The Err path happens only when a JavaScript - // NodeFilter throws an exception. This iterator - // is meant for internal use from Rust code, which - // will probably be using a native Rust filter, - // which cannot produce an Err result. + // The Err path happens only when a JavaScript + // NodeFilter throws an exception. This iterator + // is meant for internal use from Rust code, which + // will probably be using a native Rust filter, + // which cannot produce an Err result. + { unreachable!() + } } } } @@ -464,6 +475,5 @@ impl<'a> Iterator for &'a TreeWalker { #[derive(JSTraceable)] pub enum Filter { None, - Native(fn (node: &Node) -> u16), - JS(Rc<NodeFilter>) + Dom(Rc<NodeFilter>), } |