Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement NodeIterator #5981

Merged
merged 5 commits into from May 28, 2015
Merged
Changes from 1 commit
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

Implement nextNode(), previousNode() and detach() in NodeIterator

First patch to resolve #1235. We need more implementation for handling node removals,
and I'll implement in next patch.
  • Loading branch information
Jinwoo-Song committed May 27, 2015
commit cb2bdf19778a317413a385b28cc95dfbc864c71f
@@ -2,23 +2,29 @@
* 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/. */

use dom::bindings::callback::ExceptionHandling::Rethrow;
use dom::bindings::codegen::Bindings::NodeIteratorBinding;
use dom::bindings::codegen::Bindings::NodeIteratorBinding::NodeIteratorMethods;
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use dom::bindings::codegen::Bindings::NodeFilterBinding::NodeFilter;
use dom::bindings::codegen::Bindings::NodeFilterBinding::NodeFilterConstants;
use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JS, JSRef, MutNullableHeap, Temporary, Rootable};
use dom::bindings::js::{JS, JSRef, MutNullableHeap, OptionalRootable, Temporary, Rootable};
use dom::bindings::utils::{Reflector, reflect_dom_object};
use dom::document::{Document, DocumentHelpers};
use dom::node::{Node};
use dom::node::Node;

use std::cell::Cell;

#[dom_struct]
pub struct NodeIterator {
reflector_: Reflector,
root_node: JS<Node>,
reference_node: MutNullableHeap<JS<Node>>,

This comment has been minimized.

@nox

nox May 8, 2015

Member

AFAICT you never set it to None, so MutHeap would be enough here.

pointer_before_reference_node: Cell<bool>,
what_to_show: u32,
filter: Filter
filter: Filter,
}

impl NodeIterator {
@@ -29,6 +35,7 @@ impl NodeIterator {
reflector_: Reflector::new(),
root_node: JS::from_rooted(root_node),
reference_node: MutNullableHeap::new(Some(JS::from_rooted(root_node))),
pointer_before_reference_node: Cell::new(true),
what_to_show: what_to_show,
filter: filter
}
@@ -81,6 +88,10 @@ impl<'a> NodeIteratorMethods for JSRef<'a, NodeIterator> {
self.reference_node.get().map(Temporary::from_rooted)
}

fn PointerBeforeReferenceNode(self) -> bool {
self.pointer_before_reference_node.get()
}

// https://dom.spec.whatwg.org/#dom-nodeiterator-previousnode
fn PreviousNode(self) -> Fallible<Option<Temporary<Node>>> {
self.prev_node()
@@ -90,31 +101,205 @@ impl<'a> NodeIteratorMethods for JSRef<'a, NodeIterator> {
fn NextNode(self) -> Fallible<Option<Temporary<Node>>> {
self.next_node()
}

// https://dom.spec.whatwg.org/#dom-nodeiterator-detach
fn Detach(self) {
// This method intentionally left blank.
}
}

/*
trait PrivateNodeIteratorHelpers {
//fn accept_node(self, node: JSRef<Node>) -> Fallible<u16>;
fn is_root_node(self, node: JSRef<Node>) -> bool;
fn first_following_node_not_following_root(self, node: JSRef<Node>) -> Option<Temporary<Node>>;
fn first_preceding_node_not_preceding_root(self, node: JSRef<Node>) -> Option<Temporary<Node>>;
fn accept_node(self, node: JSRef<Node>) -> Fallible<u16>;
}

impl<'a> PrivateNodeIteratorHelpers for JSRef<'a, NodeIterator> {

// https://dom.spec.whatwg.org/#concept-tree-following
fn first_following_node_not_following_root(self, node: JSRef<Node>)
-> Option<Temporary<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.GetFirstChild() {
Some (child) => { return Some(Temporary::from_rooted(child.root().get_unsound_ref_forever())) },
None => {}
}
match node.GetNextSibling() {
None => {
let mut candidate = 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.root().get_unsound_ref_forever(); }
}
}
if self.is_root_node(candidate) {
None
} else {
candidate.GetNextSibling()
}
},
it => {
if self.is_root_node(node) {
return None
} else {
it
}
}
}
}

// https://dom.spec.whatwg.org/#concept-tree-preceding
fn first_preceding_node_not_preceding_root(self, node: JSRef<Node>)
-> Option<Temporary<Node>> {
// "An object A is preceding an object B if A and B are in the same tree
// and A comes before B in tree order."
match node.GetPreviousSibling() {
None => {
let mut candidate = node;
while !self.is_root_node(candidate) && candidate.GetPreviousSibling().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.root().get_unsound_ref_forever(); }
}
}
if self.is_root_node(candidate) {
None
} else {
candidate.GetPreviousSibling()
}
},
it => {
let candidate = node;
if self.is_root_node(candidate) {
return None
} else {
it
}
}
}
}

// https://dom.spec.whatwg.org/#concept-node-filter
fn accept_node(self, node: JSRef<Node>) -> Fallible<u16> {
// "To filter node run these steps:"
// "1. Let n be node's nodeType attribute value minus 1."
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."
if (self.what_to_show & (1 << n)) == 0 {
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 {
Filter::None => Ok(NodeFilterConstants::FILTER_ACCEPT),
Filter::Native(f) => Ok((f)(node)),
Filter::JS(callback) => callback.AcceptNode_(self, node, Rethrow)
}
}

fn is_root_node(self, node: JSRef<Node>) -> bool {
JS::from_rooted(node) == self.root_node
}
}
*/

pub trait NodeIteratorHelpers {
fn next_node(self) -> Fallible<Option<Temporary<Node>>>;
fn prev_node(self) -> Fallible<Option<Temporary<Node>>>;
fn traverse(self, direction: Direction) -> Fallible<Option<Temporary<Node>>>;
}

impl<'a> NodeIteratorHelpers for JSRef<'a, NodeIterator> {
// https://dom.spec.whatwg.org/#dom-nodeiterator-nextnode
fn next_node(self) -> Fallible<Option<Temporary<Node>>> {
Ok(None)
self.traverse(Direction::Next)
}

// https://dom.spec.whatwg.org/#dom-nodeiterator-previousnode
fn prev_node(self) -> Fallible<Option<Temporary<Node>>> {
Ok(None)
self.traverse(Direction::Previous)
}

fn traverse(self, direction: Direction) -> Fallible<Option<Temporary<Node>>> {
// "1. Let node be the value of the referenceNode attribute."
let mut node = self.reference_node.get();
// "2. Let before node be the value of the pointerBeforeReferenceNode attribute."
let mut before_node = self.pointer_before_reference_node.get();
// "3. Run these substeps:
loop {
match direction {
// "1. If direction is next"
Direction::Next => {
// "If before node is false, let node be the first node following node in the iterator collection.
// If there is no such node return null. If before node is true, set it to false."
if !before_node {
match node {
None => return Ok(None),
Some(n) => {
match self.first_following_node_not_following_root(n.root().get_unsound_ref_forever()) {
None => return Ok(None),
Some(n) => node = Some(JS::from_rooted(n))
}
}
}
}
else {
before_node = false;
}
}
// "If direction is previous"
Direction::Previous => {
// "If before node is true, let node be the first node preceding node in the iterator collection.
// If there is no such node return null. If before node is false, set it to true.
if before_node {
match node {
None => return Ok(None),
Some(n) => {
match self.first_preceding_node_not_preceding_root(n.root().get_unsound_ref_forever()) {
None => return Ok(None),
Some(n) => node = Some(JS::from_rooted(n))
}
}
}
}
else {
before_node = true;
}
}
}
// "2. Filter node and let result be the return value."
let result = try!(self.accept_node(node.unwrap().root().get_unsound_ref_forever()));

// "3. If result is FILTER_ACCEPT, go to the next step in the overall set of steps. Otherwise, run these substeps again."
match result {
NodeFilterConstants::FILTER_ACCEPT => break,
_ => {}
}

}
// "4. Set the referenceNode attribute to node, set the pointerBeforeReferenceNode attribute to before node, and return node."
self.reference_node.set(Some(JS::from_rooted(node.unwrap())));
self.pointer_before_reference_node.set(before_node);

Ok(Some(Temporary::from_rooted(node.unwrap())))
}
}

pub enum Direction {
Next,
Previous
}

#[jstraceable]
pub enum Filter {
@@ -16,8 +16,8 @@ interface NodeIterator {
readonly attribute Node root;
[Pure]
readonly attribute Node? referenceNode;
// [Pure]
// readonly attribute boolean pointerBeforeReferenceNode;
[Pure]
readonly attribute boolean pointerBeforeReferenceNode;
[Constant]
readonly attribute unsigned long whatToShow;
[Constant]
@@ -28,5 +28,5 @@ interface NodeIterator {
[Throws]
Node? previousNode();

// void detach();
void detach();
};
@@ -132,10 +132,10 @@
[Document interface: xmlDoc must inherit property "origin" with the proper type (3)]
expected: FAIL
[Document interface: xmlDoc must inherit property "createNodeIterator" with the proper type (25)]
[Document interface: calling prepend([object Object\],[object Object\]) on xmlDoc with too few arguments must throw TypeError]
expected: FAIL
[Document interface: calling createNodeIterator(Node,unsigned long,NodeFilter) on xmlDoc with too few arguments must throw TypeError]
[Document interface: calling append([object Object\],[object Object\]) on xmlDoc with too few arguments must throw TypeError]
expected: FAIL
[Document interface: xmlDoc must inherit property "query" with the proper type (34)]
@@ -363,58 +363,7 @@
[Range interface: calling surroundContents(Node) on detachedRange with too few arguments must throw TypeError]
expected: FAIL
[NodeIterator interface: attribute root]
expected: FAIL
[NodeIterator interface: attribute referenceNode]
expected: FAIL
[NodeIterator interface: attribute pointerBeforeReferenceNode]
expected: FAIL
[NodeIterator interface: attribute whatToShow]
expected: FAIL
[NodeIterator interface: attribute filter]
expected: FAIL
[NodeIterator interface: operation nextNode()]
expected: FAIL
[NodeIterator interface: operation previousNode()]
expected: FAIL
[NodeIterator interface: operation detach()]
expected: FAIL
[NodeIterator must be primary interface of document.createNodeIterator(document.body, NodeFilter.SHOW_ALL, null, false)]
expected: FAIL
[Stringification of document.createNodeIterator(document.body, NodeFilter.SHOW_ALL, null, false)]
expected: FAIL
[NodeIterator interface: document.createNodeIterator(document.body, NodeFilter.SHOW_ALL, null, false) must inherit property "root" with the proper type (0)]
expected: FAIL
[NodeIterator interface: document.createNodeIterator(document.body, NodeFilter.SHOW_ALL, null, false) must inherit property "referenceNode" with the proper type (1)]
expected: FAIL
[NodeIterator interface: document.createNodeIterator(document.body, NodeFilter.SHOW_ALL, null, false) must inherit property "pointerBeforeReferenceNode" with the proper type (2)]
expected: FAIL
[NodeIterator interface: document.createNodeIterator(document.body, NodeFilter.SHOW_ALL, null, false) must inherit property "whatToShow" with the proper type (3)]
expected: FAIL
[NodeIterator interface: document.createNodeIterator(document.body, NodeFilter.SHOW_ALL, null, false) must inherit property "filter" with the proper type (4)]
expected: FAIL
[NodeIterator interface: document.createNodeIterator(document.body, NodeFilter.SHOW_ALL, null, false) must inherit property "nextNode" with the proper type (5)]
expected: FAIL
[NodeIterator interface: document.createNodeIterator(document.body, NodeFilter.SHOW_ALL, null, false) must inherit property "previousNode" with the proper type (6)]
expected: FAIL
[NodeIterator interface: document.createNodeIterator(document.body, NodeFilter.SHOW_ALL, null, false) must inherit property "detach" with the proper type (7)]
[NodeIterator interface object length]
expected: FAIL
[TreeWalker interface object length]
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.