diff options
author | bors-servo <release+servo@mozilla.com> | 2014-05-03 14:25:22 -0400 |
---|---|---|
committer | bors-servo <release+servo@mozilla.com> | 2014-05-03 14:25:22 -0400 |
commit | 731e66ff132e41cdc49bc5324c0e15be19c46ec2 (patch) | |
tree | ccce9b42e8a6c54245e53620082efe0b9840eae1 /src/components/script/dom/node.rs | |
parent | 4051a8096d7ba7e7f9c86e76d0b4bffd83e85805 (diff) | |
parent | 91278da9dd55582401154e07f9eea34425a332c2 (diff) | |
download | servo-731e66ff132e41cdc49bc5324c0e15be19c46ec2.tar.gz servo-731e66ff132e41cdc49bc5324c0e15be19c46ec2.zip |
auto merge of #2101 : jdm/servo/newroot_rebase, r=Ms2ger
As described in #1764, this strategy uses the following properties:
* DOM members are `JS<T>` types. These cannot be used with being explicitly rooted, but they are required for compiler-derived trace hooks.
* Methods that take DOM type arguments receive `&[mut] JSRef<T>`. These are rooted value references that are cloneable but cannot escape.
* Methods that return DOM values use `Unrooted<T>`. These are values that may or may not be rooted elsewhere, but callers must root them in order to interact with them in any way. One unsoundness hole exists - `Unrooted` values must be rooted ASAP, or there exists the danger that JSAPI calls could be made that could cause the underlying JS value to be GCed.
* All methods are implemented on `JSRef<T>`, enforcing the requirement that all DOM values are rooted for the duration of a method call (with a few exceptions for layout-related code, which cannot root values and therefore interacts with `JS<T>` and `&T` values - this is safe under the assumption that layout code interacts with DOM nodes that are in the tree, therefore rooted, and does not run concurrently with content code)
Diffstat (limited to 'src/components/script/dom/node.rs')
-rw-r--r-- | src/components/script/dom/node.rs | 1577 |
1 files changed, 827 insertions, 750 deletions
diff --git a/src/components/script/dom/node.rs b/src/components/script/dom/node.rs index d5b43a6257f..e9a2d0ca37b 100644 --- a/src/components/script/dom/node.rs +++ b/src/components/script/dom/node.rs @@ -6,23 +6,25 @@ use dom::attr::Attr; use dom::bindings::codegen::InheritTypes::{CommentCast, DocumentCast, DocumentTypeCast}; -use dom::bindings::codegen::InheritTypes::{ElementCast, TextCast, NodeCast}; +use dom::bindings::codegen::InheritTypes::{ElementCast, TextCast, NodeCast, ElementDerived}; use dom::bindings::codegen::InheritTypes::{CharacterDataCast, NodeBase, NodeDerived}; use dom::bindings::codegen::InheritTypes::{ProcessingInstructionCast, EventTargetCast}; use dom::bindings::codegen::BindingDeclarations::NodeBinding::NodeConstants; -use dom::bindings::js::JS; +use dom::bindings::js::{JS, JSRef, RootedReference, Temporary, Root, OptionalUnrootable}; +use dom::bindings::js::{OptionalSettable, TemporaryPushable, OptionalRootedRootable}; +use dom::bindings::js::{ResultRootable, OptionalRootable}; use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object}; use dom::bindings::error::{ErrorResult, Fallible, NotFound, HierarchyRequest}; use dom::bindings::utils; -use dom::characterdata::CharacterData; +use dom::characterdata::{CharacterData, CharacterDataMethods}; use dom::comment::Comment; -use dom::document::{Document, HTMLDocument, NonHTMLDocument}; +use dom::document::{Document, DocumentMethods, DocumentHelpers, HTMLDocument, NonHTMLDocument}; use dom::documentfragment::DocumentFragment; use dom::documenttype::DocumentType; -use dom::element::{Element, ElementTypeId, HTMLAnchorElementTypeId}; +use dom::element::{Element, ElementMethods, ElementTypeId, HTMLAnchorElementTypeId}; use dom::eventtarget::{EventTarget, NodeTargetTypeId}; use dom::nodelist::{NodeList}; -use dom::processinginstruction::ProcessingInstruction; +use dom::processinginstruction::{ProcessingInstruction, ProcessingInstructionMethods}; use dom::text::Text; use dom::virtualmethods::{VirtualMethods, vtable_for}; use dom::window::Window; @@ -222,26 +224,161 @@ pub enum NodeTypeId { ProcessingInstructionNodeTypeId, } -pub trait INode { - fn AppendChild(&mut self, node: &mut JS<Node>) -> Fallible<JS<Node>>; - fn ReplaceChild(&mut self, node: &mut JS<Node>, child: &mut JS<Node>) -> Fallible<JS<Node>>; - fn RemoveChild(&mut self, node: &mut JS<Node>) -> Fallible<JS<Node>>; +trait PrivateNodeHelpers { + fn set_parent_node(&mut self, new_parent_node: Option<JSRef<Node>>); + fn set_first_child(&mut self, new_first_child: Option<JSRef<Node>>); + fn set_last_child(&mut self, new_last_child: Option<JSRef<Node>>); + fn set_prev_sibling(&mut self, new_prev_sibling: Option<JSRef<Node>>); + fn set_next_sibling(&mut self, new_next_sibling: Option<JSRef<Node>>); + + fn node_inserted(&self); + fn node_removed(&self); + fn add_child(&mut self, new_child: &mut JSRef<Node>, before: Option<JSRef<Node>>); + fn remove_child(&mut self, child: &mut JSRef<Node>); } -impl INode for JS<Node> { - fn AppendChild(&mut self, node: &mut JS<Node>) -> Fallible<JS<Node>> { - let mut self_node = self.clone(); - self.get_mut().AppendChild(&mut self_node, node) +impl<'a> PrivateNodeHelpers for JSRef<'a, Node> { + // http://dom.spec.whatwg.org/#node-is-inserted + fn node_inserted(&self) { + assert!(self.parent_node().is_some()); + let document = document_from_node(self).root(); + + if self.is_in_doc() { + for mut node in self.traverse_preorder() { + vtable_for(&mut node).bind_to_tree(); + } + } + + let mut parent = self.parent_node().root(); + parent.as_mut().map(|parent| vtable_for(&mut **parent).child_inserted(self)); + + document.deref().content_changed(); + } + + // http://dom.spec.whatwg.org/#node-is-removed + fn node_removed(&self) { + assert!(self.parent_node().is_none()); + let document = document_from_node(self).root(); + + for mut node in self.traverse_preorder() { + // XXX how about if the node wasn't in the tree in the first place? + vtable_for(&mut node).unbind_from_tree(); + } + + document.deref().content_changed(); + } + + // + // Pointer stitching + // + + /// Adds a new child to the end of this node's list of children. + /// + /// Fails unless `new_child` is disconnected from the tree. + fn add_child(&mut self, new_child: &mut JSRef<Node>, mut before: Option<JSRef<Node>>) { + assert!(new_child.parent_node().is_none()); + assert!(new_child.prev_sibling().is_none()); + assert!(new_child.next_sibling().is_none()); + match before { + Some(ref mut before) => { + // XXX Should assert that parent is self. + assert!(before.parent_node().is_some()); + match before.prev_sibling().root() { + None => { + // XXX Should assert that before is the first child of + // self. + self.set_first_child(Some(new_child.clone())); + }, + Some(mut prev_sibling) => { + prev_sibling.set_next_sibling(Some(new_child.clone())); + new_child.set_prev_sibling(Some((*prev_sibling).clone())); + }, + } + before.set_prev_sibling(Some(new_child.clone())); + new_child.set_next_sibling(Some(before.clone())); + }, + None => { + match self.last_child().root() { + None => self.set_first_child(Some(new_child.clone())), + Some(mut last_child) => { + assert!(last_child.next_sibling().is_none()); + last_child.set_next_sibling(Some(new_child.clone())); + new_child.set_prev_sibling(Some((*last_child).clone())); + } + } + + self.set_last_child(Some(new_child.clone())); + }, + } + + new_child.set_parent_node(Some(self.clone())); + } + + /// Removes the given child from this node's list of children. + /// + /// Fails unless `child` is a child of this node. (FIXME: This is not yet checked.) + fn remove_child(&mut self, child: &mut JSRef<Node>) { + assert!(child.parent_node.is_some()); + + match child.prev_sibling.root() { + None => { + let next_sibling = child.next_sibling.root(); + self.set_first_child(next_sibling.root_ref()); + } + Some(ref mut prev_sibling) => { + let next_sibling = child.next_sibling.root(); + prev_sibling.set_next_sibling(next_sibling.root_ref()); + } + } + + match child.next_sibling.root() { + None => { + let prev_sibling = child.prev_sibling.root(); + self.set_last_child(prev_sibling.root_ref()); + } + Some(ref mut next_sibling) => { + let prev_sibling = child.prev_sibling.root(); + next_sibling.set_prev_sibling(prev_sibling.root_ref()); + } + } + + child.set_prev_sibling(None); + child.set_next_sibling(None); + child.set_parent_node(None); + } + + // + // Low-level pointer stitching + // + + fn set_parent_node(&mut self, new_parent_node: Option<JSRef<Node>>) { + let doc = self.owner_doc().root(); + doc.deref().wait_until_safe_to_modify_dom(); + self.parent_node.assign(new_parent_node); + } + + fn set_first_child(&mut self, new_first_child: Option<JSRef<Node>>) { + let doc = self.owner_doc().root(); + doc.deref().wait_until_safe_to_modify_dom(); + self.first_child.assign(new_first_child); } - fn ReplaceChild(&mut self, node: &mut JS<Node>, child: &mut JS<Node>) -> Fallible<JS<Node>> { - let mut self_node = self.clone(); - self.get_mut().ReplaceChild(&mut self_node, node, child) + fn set_last_child(&mut self, new_last_child: Option<JSRef<Node>>) { + let doc = self.owner_doc().root(); + doc.deref().wait_until_safe_to_modify_dom(); + self.last_child.assign(new_last_child); } - fn RemoveChild(&mut self, node: &mut JS<Node>) -> Fallible<JS<Node>> { - let mut self_node = self.clone(); - self.get_mut().RemoveChild(&mut self_node, node) + fn set_prev_sibling(&mut self, new_prev_sibling: Option<JSRef<Node>>) { + let doc = self.owner_doc().root(); + doc.deref().wait_until_safe_to_modify_dom(); + self.prev_sibling.assign(new_prev_sibling); + } + + fn set_next_sibling(&mut self, new_next_sibling: Option<JSRef<Node>>) { + let doc = self.owner_doc().root(); + doc.deref().wait_until_safe_to_modify_dom(); + self.next_sibling.assign(new_next_sibling); } } @@ -251,16 +388,21 @@ pub trait NodeHelpers { fn child_elements(&self) -> ChildElementIterator; fn following_siblings(&self) -> AbstractNodeChildrenIterator; fn is_in_doc(&self) -> bool; - fn is_inclusive_ancestor_of(&self, parent: &JS<Node>) -> bool; - fn is_parent_of(&self, child: &JS<Node>) -> bool; + fn is_inclusive_ancestor_of(&self, parent: &JSRef<Node>) -> bool; + fn is_parent_of(&self, child: &JSRef<Node>) -> bool; fn type_id(&self) -> NodeTypeId; - fn parent_node(&self) -> Option<JS<Node>>; - fn first_child(&self) -> Option<JS<Node>>; - fn last_child(&self) -> Option<JS<Node>>; - fn prev_sibling(&self) -> Option<JS<Node>>; - fn next_sibling(&self) -> Option<JS<Node>>; + fn parent_node(&self) -> Option<Temporary<Node>>; + fn first_child(&self) -> Option<Temporary<Node>>; + fn last_child(&self) -> Option<Temporary<Node>>; + fn prev_sibling(&self) -> Option<Temporary<Node>>; + fn next_sibling(&self) -> Option<Temporary<Node>>; + + fn owner_doc(&self) -> Temporary<Document>; + fn set_owner_doc(&mut self, document: &JSRef<Document>); + + fn wait_until_safe_to_modify_dom(&self); fn is_element(&self) -> bool; fn is_document(&self) -> bool; @@ -268,11 +410,6 @@ pub trait NodeHelpers { fn is_text(&self) -> bool; fn is_anchor_element(&self) -> bool; - fn node_inserted(&self); - fn node_removed(&self); - fn add_child(&mut self, new_child: &mut JS<Node>, before: Option<JS<Node>>); - fn remove_child(&mut self, child: &mut JS<Node>); - fn get_hover_state(&self) -> bool; fn set_hover_state(&mut self, state: bool); @@ -280,18 +417,17 @@ pub trait NodeHelpers { fn dump_indent(&self, indent: uint); fn debug_str(&self) -> ~str; - fn traverse_preorder(&self) -> TreeIterator; - fn sequential_traverse_postorder(&self) -> TreeIterator; - fn inclusively_following_siblings(&self) -> AbstractNodeChildrenIterator; + fn traverse_preorder<'a>(&'a self) -> TreeIterator<'a>; + fn sequential_traverse_postorder<'a>(&'a self) -> TreeIterator<'a>; + fn inclusively_following_siblings<'a>(&'a self) -> AbstractNodeChildrenIterator<'a>; - fn from_untrusted_node_address(runtime: *JSRuntime, candidate: UntrustedNodeAddress) -> Self; fn to_trusted_node_address(&self) -> TrustedNodeAddress; fn get_bounding_content_box(&self) -> Rect<Au>; fn get_content_boxes(&self) -> Vec<Rect<Au>>; } -impl NodeHelpers for JS<Node> { +impl<'a> NodeHelpers for JSRef<'a, Node> { /// Dumps the subtree rooted at this node, for debugging. fn dump(&self) { self.dump_indent(0); @@ -318,53 +454,40 @@ impl NodeHelpers for JS<Node> { format!("{:?}", self.type_id()) } - /// Iterates over all ancestors of this node. - fn ancestors(&self) -> AncestorIterator { - self.get().ancestors() - } - - fn children(&self) -> AbstractNodeChildrenIterator { - self.get().children() - } - - fn child_elements(&self) -> ChildElementIterator { - self.get().child_elements() - } - fn is_in_doc(&self) -> bool { - self.get().flags.is_in_doc() + self.deref().flags.is_in_doc() } /// Returns the type ID of this node. Fails if this node is borrowed mutably. fn type_id(&self) -> NodeTypeId { - self.get().type_id + self.deref().type_id } - fn parent_node(&self) -> Option<JS<Node>> { - self.get().parent_node.clone() + fn parent_node(&self) -> Option<Temporary<Node>> { + self.deref().parent_node.clone().map(|node| Temporary::new(node)) } - fn first_child(&self) -> Option<JS<Node>> { - self.get().first_child.clone() + fn first_child(&self) -> Option<Temporary<Node>> { + self.deref().first_child.clone().map(|node| Temporary::new(node)) } - fn last_child(&self) -> Option<JS<Node>> { - self.get().last_child.clone() + fn last_child(&self) -> Option<Temporary<Node>> { + self.deref().last_child.clone().map(|node| Temporary::new(node)) } /// Returns the previous sibling of this node. Fails if this node is borrowed mutably. - fn prev_sibling(&self) -> Option<JS<Node>> { - self.get().prev_sibling.clone() + fn prev_sibling(&self) -> Option<Temporary<Node>> { + self.deref().prev_sibling.clone().map(|node| Temporary::new(node)) } /// Returns the next sibling of this node. Fails if this node is borrowed mutably. - fn next_sibling(&self) -> Option<JS<Node>> { - self.get().next_sibling.clone() + fn next_sibling(&self) -> Option<Temporary<Node>> { + self.deref().next_sibling.clone().map(|node| Temporary::new(node)) } #[inline] fn is_element(&self) -> bool { - match self.type_id() { + match self.type_id { ElementNodeTypeId(..) => true, _ => false } @@ -388,7 +511,7 @@ impl NodeHelpers for JS<Node> { #[inline] fn is_doctype(&self) -> bool { - match self.type_id() { + match self.type_id { DoctypeNodeTypeId => true, _ => false } @@ -404,177 +527,58 @@ impl NodeHelpers for JS<Node> { } } - // http://dom.spec.whatwg.org/#node-is-inserted - fn node_inserted(&self) { - assert!(self.parent_node().is_some()); - let document = document_from_node(self); - - if self.is_in_doc() { - for node in self.traverse_preorder() { - vtable_for(&node).bind_to_tree(); - } - } - - self.parent_node().map(|parent| vtable_for(&parent).child_inserted(self)); - document.get().content_changed(); - } - - // http://dom.spec.whatwg.org/#node-is-removed - fn node_removed(&self) { - assert!(self.parent_node().is_none()); - let document = document_from_node(self); - - for node in self.traverse_preorder() { - // XXX how about if the node wasn't in the tree in the first place? - vtable_for(&node).unbind_from_tree(); - } - - document.get().content_changed(); - } - - // - // Pointer stitching - // - - /// Adds a new child to the end of this node's list of children. - /// - /// Fails unless `new_child` is disconnected from the tree. - fn add_child(&mut self, new_child: &mut JS<Node>, before: Option<JS<Node>>) { - assert!(new_child.parent_node().is_none()); - assert!(new_child.prev_sibling().is_none()); - assert!(new_child.next_sibling().is_none()); - match before { - Some(mut before) => { - // XXX Should assert that parent is self. - assert!(before.parent_node().is_some()); - match before.prev_sibling() { - None => { - // XXX Should assert that before is the first child of - // self. - self.get_mut().set_first_child(Some(new_child.clone())); - }, - Some(mut prev_sibling) => { - prev_sibling.get_mut().set_next_sibling(Some(new_child.clone())); - new_child.get_mut().set_prev_sibling(Some(prev_sibling.clone())); - }, - } - before.get_mut().set_prev_sibling(Some(new_child.clone())); - new_child.get_mut().set_next_sibling(Some(before.clone())); - }, - None => { - match self.last_child() { - None => self.get_mut().set_first_child(Some(new_child.clone())), - Some(mut last_child) => { - assert!(last_child.next_sibling().is_none()); - last_child.get_mut().set_next_sibling(Some(new_child.clone())); - new_child.get_mut().set_prev_sibling(Some(last_child.clone())); - } - } - - self.get_mut().set_last_child(Some(new_child.clone())); - }, - } - - new_child.get_mut().set_parent_node(Some(self.clone())); - } - - /// Removes the given child from this node's list of children. - /// - /// Fails unless `child` is a child of this node. (FIXME: This is not yet checked.) - fn remove_child(&mut self, child: &mut JS<Node>) { - let this_node = self.get_mut(); - let child_node = child.get_mut(); - assert!(child_node.parent_node.is_some()); - - match child_node.prev_sibling { - None => this_node.set_first_child(child_node.next_sibling.clone()), - Some(ref mut prev_sibling) => { - let prev_sibling_node = prev_sibling.get_mut(); - prev_sibling_node.set_next_sibling(child_node.next_sibling.clone()); - } - } - - match child_node.next_sibling { - None => this_node.set_last_child(child_node.prev_sibling.clone()), - Some(ref mut next_sibling) => { - let next_sibling_node = next_sibling.get_mut(); - next_sibling_node.set_prev_sibling(child_node.prev_sibling.clone()); - } - } - - child_node.set_prev_sibling(None); - child_node.set_next_sibling(None); - child_node.set_parent_node(None); - } - fn get_hover_state(&self) -> bool { - self.get().flags.get_in_hover_state() + self.flags.get_in_hover_state() } fn set_hover_state(&mut self, state: bool) { - self.get_mut().flags.set_is_in_hover_state(state); + self.flags.set_is_in_hover_state(state); } /// Iterates over this node and all its descendants, in preorder. - fn traverse_preorder(&self) -> TreeIterator { + fn traverse_preorder<'a>(&'a self) -> TreeIterator<'a> { let mut nodes = vec!(); gather_abstract_nodes(self, &mut nodes, false); TreeIterator::new(nodes) } /// Iterates over this node and all its descendants, in postorder. - fn sequential_traverse_postorder(&self) -> TreeIterator { + fn sequential_traverse_postorder<'a>(&'a self) -> TreeIterator<'a> { let mut nodes = vec!(); gather_abstract_nodes(self, &mut nodes, true); TreeIterator::new(nodes) } - fn inclusively_following_siblings(&self) -> AbstractNodeChildrenIterator { + fn inclusively_following_siblings<'a>(&'a self) -> AbstractNodeChildrenIterator<'a> { AbstractNodeChildrenIterator { current_node: Some(self.clone()), } } - fn is_inclusive_ancestor_of(&self, parent: &JS<Node>) -> bool { - self == parent || parent.ancestors().any(|ancestor| ancestor == *self) + fn is_inclusive_ancestor_of(&self, parent: &JSRef<Node>) -> bool { + self == parent || parent.ancestors().any(|ancestor| &ancestor == self) } fn following_siblings(&self) -> AbstractNodeChildrenIterator { AbstractNodeChildrenIterator { - current_node: self.next_sibling(), + current_node: self.next_sibling().root().map(|next| next.deref().clone()), } } - fn is_parent_of(&self, child: &JS<Node>) -> bool { + fn is_parent_of(&self, child: &JSRef<Node>) -> bool { match child.parent_node() { - Some(ref parent) if parent == self => true, + Some(ref parent) if *parent == Temporary::from_rooted(self) => true, _ => false } } - /// If the given untrusted node address represents a valid DOM node in the given runtime, - /// returns it. - fn from_untrusted_node_address(runtime: *JSRuntime, candidate: UntrustedNodeAddress) - -> JS<Node> { - unsafe { - let candidate: uintptr_t = cast::transmute(candidate); - let object: *JSObject = jsfriendapi::bindgen::JS_GetAddressableObject(runtime, - candidate); - if object.is_null() { - fail!("Attempted to create a `JS<Node>` from an invalid pointer!") - } - let boxed_node: *mut Node = utils::unwrap(object); - JS::from_raw(boxed_node) - } - } - fn to_trusted_node_address(&self) -> TrustedNodeAddress { - TrustedNodeAddress(self.get() as *Node as *libc::c_void) + TrustedNodeAddress(self.deref() as *Node as *libc::c_void) } fn get_bounding_content_box(&self) -> Rect<Au> { - let window = window_from_node(self); - let page = window.get().page(); + let window = window_from_node(self).root(); + let page = window.deref().page(); let (chan, port) = channel(); let addr = self.to_trusted_node_address(); let ContentBoxResponse(rect) = page.query_layout(ContentBoxQuery(addr, chan), port); @@ -582,63 +586,180 @@ impl NodeHelpers for JS<Node> { } fn get_content_boxes(&self) -> Vec<Rect<Au>> { - let window = window_from_node(self); - let page = window.get().page(); + let window = window_from_node(self).root(); + let page = window.deref().page(); let (chan, port) = channel(); let addr = self.to_trusted_node_address(); let ContentBoxesResponse(rects) = page.query_layout(ContentBoxesQuery(addr, chan), port); rects } + + fn ancestors(&self) -> AncestorIterator { + AncestorIterator { + current: self.parent_node.clone().map(|node| (*node.root()).clone()), + } + } + + fn owner_doc(&self) -> Temporary<Document> { + Temporary::new(self.owner_doc.get_ref().clone()) + } + + fn set_owner_doc(&mut self, document: &JSRef<Document>) { + self.owner_doc.assign(Some(document.clone())); + } + + fn children(&self) -> AbstractNodeChildrenIterator { + AbstractNodeChildrenIterator { + current_node: self.first_child.clone().map(|node| (*node.root()).clone()), + } + } + + fn child_elements(&self) -> ChildElementIterator { + self.children() + .filter(|node| { + node.is_element() + }) + .map(|node| { + let elem: &JSRef<Element> = ElementCast::to_ref(&node).unwrap(); + elem.clone() + }) + } + + fn wait_until_safe_to_modify_dom(&self) { + let document = self.owner_doc().root(); + document.deref().wait_until_safe_to_modify_dom(); + } + +} + +/// If the given untrusted node address represents a valid DOM node in the given runtime, +/// returns it. +pub fn from_untrusted_node_address(runtime: *JSRuntime, candidate: UntrustedNodeAddress) + -> Temporary<Node> { + unsafe { + let candidate: uintptr_t = cast::transmute(candidate); + let object: *JSObject = jsfriendapi::bindgen::JS_GetAddressableObject(runtime, + candidate); + if object.is_null() { + fail!("Attempted to create a `JS<Node>` from an invalid pointer!") + } + let boxed_node: *mut Node = utils::unwrap(object); + Temporary::new(JS::from_raw(boxed_node)) + } +} + +pub trait LayoutNodeHelpers { + unsafe fn type_id_for_layout(&self) -> NodeTypeId; + + unsafe fn parent_node_ref<'a>(&'a self) -> Option<&'a JS<Node>>; + unsafe fn first_child_ref<'a>(&'a self) -> Option<&'a JS<Node>>; + unsafe fn last_child_ref<'a>(&'a self) -> Option<&'a JS<Node>>; + unsafe fn prev_sibling_ref<'a>(&'a self) -> Option<&'a JS<Node>>; + unsafe fn next_sibling_ref<'a>(&'a self) -> Option<&'a JS<Node>>; + + unsafe fn owner_doc_for_layout<'a>(&'a self) -> &'a JS<Document>; + + unsafe fn is_element_for_layout(&self) -> bool; } +impl LayoutNodeHelpers for JS<Node> { + unsafe fn type_id_for_layout(&self) -> NodeTypeId { + (*self.unsafe_get()).type_id + } + + unsafe fn is_element_for_layout(&self) -> bool { + (*self.unsafe_get()).is_element() + } + + #[inline] + unsafe fn parent_node_ref<'a>(&'a self) -> Option<&'a JS<Node>> { + (*self.unsafe_get()).parent_node.as_ref() + } + + #[inline] + unsafe fn first_child_ref<'a>(&'a self) -> Option<&'a JS<Node>> { + (*self.unsafe_get()).first_child.as_ref() + } + + #[inline] + unsafe fn last_child_ref<'a>(&'a self) -> Option<&'a JS<Node>> { + (*self.unsafe_get()).last_child.as_ref() + } + + #[inline] + unsafe fn prev_sibling_ref<'a>(&'a self) -> Option<&'a JS<Node>> { + (*self.unsafe_get()).prev_sibling.as_ref() + } + + #[inline] + unsafe fn next_sibling_ref<'a>(&'a self) -> Option<&'a JS<Node>> { + (*self.unsafe_get()).next_sibling.as_ref() + } + + unsafe fn owner_doc_for_layout<'a>(&'a self) -> &'a JS<Document> { + (*self.unsafe_get()).owner_doc.get_ref() + } +} + +pub trait RawLayoutNodeHelpers { + unsafe fn get_hover_state_for_layout(&self) -> bool; +} + +impl RawLayoutNodeHelpers for Node { + unsafe fn get_hover_state_for_layout(&self) -> bool { + self.flags.get_in_hover_state() + } +} + + // // Iteration and traversal // -pub type ChildElementIterator<'a> = Map<'a, JS<Node>, - JS<Element>, - Filter<'a, JS<Node>, AbstractNodeChildrenIterator>>; +pub type ChildElementIterator<'a, 'b> = Map<'a, JSRef<'b, Node>, + JSRef<'b, Element>, + Filter<'a, JSRef<'b, Node>, AbstractNodeChildrenIterator<'b>>>; -pub struct AbstractNodeChildrenIterator { - current_node: Option<JS<Node>>, +pub struct AbstractNodeChildrenIterator<'a> { + current_node: Option<JSRef<'a, Node>>, } -impl Iterator<JS<Node>> for AbstractNodeChildrenIterator { - fn next(&mut self) -> Option<JS<Node>> { +impl<'a> Iterator<JSRef<'a, Node>> for AbstractNodeChildrenIterator<'a> { + fn next(&mut self) -> Option<JSRef<'a, Node>> { let node = self.current_node.clone(); self.current_node = node.clone().and_then(|node| { - node.next_sibling() + node.next_sibling().map(|node| (*node.root()).clone()) }); node } } -pub struct AncestorIterator { - current: Option<JS<Node>>, +pub struct AncestorIterator<'a> { + current: Option<JSRef<'a, Node>>, } -impl Iterator<JS<Node>> for AncestorIterator { - fn next(&mut self) -> Option<JS<Node>> { +impl<'a> Iterator<JSRef<'a, Node>> for AncestorIterator<'a> { + fn next(&mut self) -> Option<JSRef<'a, Node>> { if self.current.is_none() { return None; } // FIXME: Do we need two clones here? let x = self.current.get_ref().clone(); - self.current = x.parent_node(); - Some(x.clone()) + self.current = x.parent_node().map(|node| (*node.root()).clone()); + Some(x) } } // FIXME: Do this without precomputing a vector of refs. // Easy for preorder; harder for postorder. -pub struct TreeIterator { - nodes: Vec<JS<Node>>, +pub struct TreeIterator<'a> { + nodes: Vec<JSRef<'a, Node>>, index: uint, } -impl TreeIterator { - fn new(nodes: Vec<JS<Node>>) -> TreeIterator { +impl<'a> TreeIterator<'a> { + fn new(nodes: Vec<JSRef<'a, Node>>) -> TreeIterator<'a> { TreeIterator { nodes: nodes, index: 0, @@ -646,8 +767,8 @@ impl TreeIterator { } } -impl Iterator<JS<Node>> for TreeIterator { - fn next(&mut self) -> Option<JS<Node>> { +impl<'a> Iterator<JSRef<'a, Node>> for TreeIterator<'a> { + fn next(&mut self) -> Option<JSRef<'a, Node>> { if self.index >= self.nodes.len() { None } else { @@ -667,9 +788,11 @@ pub struct NodeIterator { } impl NodeIterator { - pub fn new(start_node: JS<Node>, include_start: bool, include_descendants_of_void: bool) -> NodeIterator { + pub fn new<'a>(start_node: &JSRef<'a, Node>, + include_start: bool, + include_descendants_of_void: bool) -> NodeIterator { NodeIterator { - start_node: start_node, + start_node: start_node.unrooted(), current_node: None, depth: 0, include_start: include_start, @@ -677,51 +800,54 @@ impl NodeIterator { } } - fn next_child(&self, node: &JS<Node>) -> Option<JS<Node>> { + fn next_child<'b>(&self, node: &JSRef<'b, Node>) -> Option<JSRef<Node>> { if !self.include_descendants_of_void && node.is_element() { - let elem: JS<Element> = ElementCast::to(node).unwrap(); - if elem.get().is_void() { + let elem: &JSRef<Element> = ElementCast::to_ref(node).unwrap(); + if elem.deref().is_void() { None } else { - node.first_child() + node.first_child().map(|child| (*child.root()).clone()) } } else { - node.first_child() + node.first_child().map(|child| (*child.root()).clone()) } } } -impl Iterator<JS<Node>> for NodeIterator { - fn next(&mut self) -> Option<JS<Node>> { - self.current_node = match self.current_node { +impl<'a> Iterator<JSRef<'a, Node>> for NodeIterator { + fn next(&mut self) -> Option<JSRef<Node>> { + self.current_node = match self.current_node.as_ref().map(|node| node.root()) { None => { if self.include_start { Some(self.start_node.clone()) } else { - self.next_child(&self.start_node) + self.next_child(&*self.start_node.root()) + .map(|child| child.unrooted()) } }, - Some(ref node) => { - match self.next_child(node) { + Some(node) => { + match self.next_child(&*node) { Some(child) => { self.depth += 1; - Some(child.clone()) + Some(child.unrooted()) }, - None if node == &self.start_node => None, + None if node.deref().unrooted() == self.start_node => None, None => { - match node.next_sibling() { - Some(sibling) => Some(sibling), + match node.deref().next_sibling().root() { + Some(sibling) => Some(sibling.deref().unrooted()), None => { - let mut candidate = node.clone(); + let mut candidate = node.deref().clone(); while candidate.next_sibling().is_none() { - candidate = candidate.parent_node().expect("Got to root without reaching start node"); + candidate = (*candidate.parent_node() + .expect("Got to root without reaching start node") + .root()).clone(); self.depth -= 1; - if candidate == self.start_node { + if candidate.unrooted() == self.start_node { break; } } - if candidate != self.start_node { - candidate.next_sibling() + if candidate.unrooted() != self.start_node { + candidate.next_sibling().map(|node| node.root().unrooted()) } else { None } @@ -731,11 +857,11 @@ impl Iterator<JS<Node>> for NodeIterator { } } }; - self.current_node.clone() + self.current_node.clone().map(|node| (*node.root()).clone()) } } -fn gather_abstract_nodes(cur: &JS<Node>, refs: &mut Vec<JS<Node>>, postorder: bool) { +fn gather_abstract_nodes<'a>(cur: &JSRef<'a, Node>, refs: &mut Vec<JSRef<'a, Node>>, postorder: bool) { if !postorder { refs.push(cur.clone()); } @@ -757,55 +883,27 @@ pub enum CloneChildrenFlag { fn as_uintptr<T>(t: &T) -> uintptr_t { t as *T as uintptr_t } impl Node { - pub fn ancestors(&self) -> AncestorIterator { - AncestorIterator { - current: self.parent_node.clone(), - } - } - - pub fn owner_doc<'a>(&'a self) -> &'a JS<Document> { - self.owner_doc.get_ref() - } - - pub fn set_owner_doc(&mut self, document: &JS<Document>) { - self.owner_doc = Some(document.clone()); - } - - pub fn children(&self) -> AbstractNodeChildrenIterator { - AbstractNodeChildrenIterator { - current_node: self.first_child.clone(), - } - } - - pub fn child_elements(&self) -> ChildElementIterator { - self.children() - .filter(|node| node.is_element()) - .map(|node| { - let elem: JS<Element> = ElementCast::to(&node).unwrap(); - elem - }) - } - pub fn reflect_node<N: Reflectable+NodeBase> (node: ~N, - document: &JS<Document>, - wrap_fn: extern "Rust" fn(*JSContext, &JS<Window>, ~N) -> JS<N>) - -> JS<N> { + document: &JSRef<Document>, + wrap_fn: extern "Rust" fn(*JSContext, &JSRef<Window>, ~N) -> JS<N>) + -> Temporary<N> { assert!(node.reflector().get_jsobject().is_null()); - let node = reflect_dom_object(node, &document.get().window, wrap_fn); - assert!(node.reflector().get_jsobject().is_not_null()); - node + let window = document.deref().window.root(); + let node = reflect_dom_object(node, &window.root_ref(), wrap_fn).root(); + assert!(node.deref().reflector().get_jsobject().is_not_null()); + Temporary::from_rooted(&*node) } - pub fn new_inherited(type_id: NodeTypeId, doc: JS<Document>) -> Node { - Node::new_(type_id, Some(doc)) + pub fn new_inherited(type_id: NodeTypeId, doc: &JSRef<Document>) -> Node { + Node::new_(type_id, Some(doc.clone())) } pub fn new_without_doc(type_id: NodeTypeId) -> Node { Node::new_(type_id, None) } - fn new_(type_id: NodeTypeId, doc: Option<JS<Document>>) -> Node { + fn new_(type_id: NodeTypeId, doc: Option<JSRef<Document>>) -> Node { Node { eventtarget: EventTarget::new_inherited(NodeTargetTypeId(type_id)), type_id: type_id, @@ -816,7 +914,7 @@ impl Node { next_sibling: None, prev_sibling: None, - owner_doc: doc, + owner_doc: doc.unrooted(), child_list: None, flags: NodeFlags::new(type_id), @@ -825,227 +923,21 @@ impl Node { } } - /// Sends layout data, if any, back to the script task to be destroyed. - pub unsafe fn reap_layout_data(&mut self) { - if self.layout_data.is_present() { - let layout_data = mem::replace(&mut self.layout_data, LayoutDataRef::new()); - let layout_chan = layout_data.take_chan(); - match layout_chan { - None => {} - Some(chan) => { - let LayoutChan(chan) = chan; - chan.send(ReapLayoutDataMsg(layout_data)) - }, - } - } - } - - // http://dom.spec.whatwg.org/#dom-node-nodetype - pub fn NodeType(&self) -> u16 { - match self.type_id { - ElementNodeTypeId(_) => NodeConstants::ELEMENT_NODE, - TextNodeTypeId => NodeConstants::TEXT_NODE, - ProcessingInstructionNodeTypeId => NodeConstants::PROCESSING_INSTRUCTION_NODE, - CommentNodeTypeId => NodeConstants::COMMENT_NODE, - DocumentNodeTypeId => NodeConstants::DOCUMENT_NODE, - DoctypeNodeTypeId => NodeConstants::DOCUMENT_TYPE_NODE, - DocumentFragmentNodeTypeId => NodeConstants::DOCUMENT_FRAGMENT_NODE, - } - } - - // http://dom.spec.whatwg.org/#dom-node-nodename - pub fn NodeName(&self, abstract_self: &JS<Node>) -> DOMString { - match self.type_id { - ElementNodeTypeId(..) => { - let elem: JS<Element> = ElementCast::to(abstract_self).unwrap(); - elem.get().TagName() - } - TextNodeTypeId => ~"#text", - ProcessingInstructionNodeTypeId => { - let processing_instruction: JS<ProcessingInstruction> = - ProcessingInstructionCast::to(abstract_self).unwrap(); - processing_instruction.get().Target() - } - CommentNodeTypeId => ~"#comment", - DoctypeNodeTypeId => { - let doctype: JS<DocumentType> = DocumentTypeCast::to(abstract_self).unwrap(); - doctype.get().name.clone() - }, - DocumentFragmentNodeTypeId => ~"#document-fragment", - DocumentNodeTypeId => ~"#document" - } - } - - // http://dom.spec.whatwg.org/#dom-node-baseuri - pub fn GetBaseURI(&self) -> Option<DOMString> { - // FIXME (#1824) implement. - None - } - - // http://dom.spec.whatwg.org/#dom-node-ownerdocument - pub fn GetOwnerDocument(&self) -> Option<JS<Document>> { - match self.type_id { - ElementNodeTypeId(..) | - CommentNodeTypeId | - TextNodeTypeId | - ProcessingInstructionNodeTypeId | - DoctypeNodeTypeId | - DocumentFragmentNodeTypeId => Some(self.owner_doc().clone()), - DocumentNodeTypeId => None - } - } - - // http://dom.spec.whatwg.org/#dom-node-parentnode - pub fn GetParentNode(&self) -> Option<JS<Node>> { - self.parent_node.clone() - } - - // http://dom.spec.whatwg.org/#dom-node-parentelement - pub fn GetParentElement(&self) -> Option<JS<Element>> { - self.parent_node.clone().and_then(|parent| ElementCast::to(&parent)) - } - - // http://dom.spec.whatwg.org/#dom-node-haschildnodes - pub fn HasChildNodes(&self) -> bool { - self.first_child.is_some() - } - - // http://dom.spec.whatwg.org/#dom-node-childnodes - pub fn ChildNodes(&mut self, abstract_self: &JS<Node>) -> JS<NodeList> { - match self.child_list { - None => { - let doc = self.owner_doc().clone(); - let doc = doc.get(); - let list = NodeList::new_child_list(&doc.window, abstract_self); - self.child_list = Some(list.clone()); - list - } - Some(ref list) => list.clone() - } - } - - // http://dom.spec.whatwg.org/#dom-node-firstchild - pub fn GetFirstChild(&self) -> Option<JS<Node>> { - self.first_child.clone() - } - - // http://dom.spec.whatwg.org/#dom-node-lastchild - pub fn GetLastChild(&self) -> Option<JS<Node>> { - self.last_child.clone() - } - - // http://dom.spec.whatwg.org/#dom-node-previoussibling - pub fn GetPreviousSibling(&self) -> Option<JS<Node>> { - self.prev_sibling.clone() - } - - // http://dom.spec.whatwg.org/#dom-node-nextsibling - pub fn GetNextSibling(&self) -> Option<JS<Node>> { - self.next_sibling.clone() - } - - // http://dom.spec.whatwg.org/#dom-node-nodevalue - pub fn GetNodeValue(&self, abstract_self: &JS<Node>) -> Option<DOMString> { - match self.type_id { - CommentNodeTypeId | - TextNodeTypeId | - ProcessingInstructionNodeTypeId => { - let chardata: JS<CharacterData> = CharacterDataCast::to(abstract_self).unwrap(); - Some(chardata.get().Data()) - } - _ => { - None - } - } - } - - // http://dom.spec.whatwg.org/#dom-node-nodevalue - pub fn SetNodeValue(&mut self, abstract_self: &mut JS<Node>, val: Option<DOMString>) - -> ErrorResult { - match self.type_id { - CommentNodeTypeId | - TextNodeTypeId | - ProcessingInstructionNodeTypeId => { - self.SetTextContent(abstract_self, val) - } - _ => Ok(()) - } - } - - // http://dom.spec.whatwg.org/#dom-node-textcontent - pub fn GetTextContent(&self, abstract_self: &JS<Node>) -> Option<DOMString> { - match self.type_id { - DocumentFragmentNodeTypeId | - ElementNodeTypeId(..) => { - let mut content = ~""; - for node in abstract_self.traverse_preorder() { - if node.is_text() { - let text: JS<Text> = TextCast::to(&node).unwrap(); - content.push_str(text.get().characterdata.data.as_slice()); - } - } - Some(content) - } - CommentNodeTypeId | - TextNodeTypeId | - ProcessingInstructionNodeTypeId => { - let characterdata: JS<CharacterData> = CharacterDataCast::to(abstract_self).unwrap(); - Some(characterdata.get().Data()) - } - DoctypeNodeTypeId | - DocumentNodeTypeId => { - None - } - } - } - - // http://dom.spec.whatwg.org/#dom-node-textcontent - pub fn SetTextContent(&mut self, abstract_self: &mut JS<Node>, value: Option<DOMString>) - -> ErrorResult { - let value = null_str_as_empty(&value); - match self.type_id { - DocumentFragmentNodeTypeId | - ElementNodeTypeId(..) => { - // Step 1-2. - let node = if value.len() == 0 { - None - } else { - let document = self.owner_doc(); - Some(NodeCast::from(&document.get().CreateTextNode(document, value))) - }; - // Step 3. - Node::replace_all(node, abstract_self); - } - CommentNodeTypeId | - TextNodeTypeId | - ProcessingInstructionNodeTypeId => { - self.wait_until_safe_to_modify_dom(); - - let mut characterdata: JS<CharacterData> = CharacterDataCast::to(abstract_self).unwrap(); - characterdata.get_mut().data = value.clone(); - - // Notify the document that the content of this node is different - let document = self.owner_doc(); - document.get().content_changed(); - } - DoctypeNodeTypeId | - DocumentNodeTypeId => {} - } - Ok(()) - } - // http://dom.spec.whatwg.org/#concept-node-adopt - pub fn adopt(node: &mut JS<Node>, document: &JS<Document>) { + pub fn adopt(node: &mut JSRef<Node>, document: &JSRef<Document>) { // Step 1. - match node.parent_node() { - Some(ref mut parent) => Node::remove(node, parent, Unsuppressed), + match node.parent_node().root() { + Some(mut parent) => { + Node::remove(node, &mut *parent, Unsuppressed); + } None => (), } // Step 2. - if document_from_node(node) != *document { + let node_doc = document_from_node(node).root(); + if &*node_doc != document { for mut descendant in node.traverse_preorder() { - descendant.get_mut().set_owner_doc(document); + descendant.set_owner_doc(document); } } @@ -1054,8 +946,8 @@ impl Node { } // http://dom.spec.whatwg.org/#concept-node-pre-insert - fn pre_insert(node: &mut JS<Node>, parent: &mut JS<Node>, child: Option<JS<Node>>) - -> Fallible<JS<Node>> { + fn pre_insert(node: &mut JSRef<Node>, parent: &mut JSRef<Node>, child: Option<JSRef<Node>>) + -> Fallible<Temporary<Node>> { // Step 1. match parent.type_id() { DocumentNodeTypeId | @@ -1078,13 +970,13 @@ impl Node { // Step 4-5. match node.type_id() { TextNodeTypeId => { - match node.parent_node() { + match node.parent_node().root() { Some(ref parent) if parent.is_document() => return Err(HierarchyRequest), _ => () } } DoctypeNodeTypeId => { - match node.parent_node() { + match node.parent_node().root() { Some(ref parent) if !parent.is_document() => return Err(HierarchyRequest), _ => () } @@ -1175,24 +1067,25 @@ impl Node { // Step 7-8. let referenceChild = match child { - Some(ref child) if child == node => node.next_sibling(), + Some(ref child) if child == node => node.next_sibling().map(|node| (*node.root()).clone()), _ => child }; // Step 9. - Node::adopt(node, &document_from_node(parent)); + let document = document_from_node(parent).root(); + Node::adopt(node, &*document); // Step 10. Node::insert(node, parent, referenceChild, Unsuppressed); // Step 11. - return Ok(node.clone()) + return Ok(Temporary::from_rooted(node)) } // http://dom.spec.whatwg.org/#concept-node-insert - fn insert(node: &mut JS<Node>, - parent: &mut JS<Node>, - child: Option<JS<Node>>, + fn insert(node: &mut JSRef<Node>, + parent: &mut JSRef<Node>, + child: Option<JSRef<Node>>, suppress_observers: SuppressObserver) { // XXX assert owner_doc // Step 1-3: ranges. @@ -1217,7 +1110,7 @@ impl Node { // Step 8. for node in nodes.mut_iter() { parent.add_child(node, child.clone()); - node.get_mut().flags.set_is_in_doc(parent.is_in_doc()); + node.deref_mut().flags.set_is_in_doc(parent.is_in_doc()); } // Step 9. @@ -1232,15 +1125,19 @@ impl Node { } // http://dom.spec.whatwg.org/#concept-node-replace-all - pub fn replace_all(mut node: Option<JS<Node>>, parent: &mut JS<Node>) { + fn replace_all(mut node: Option<JSRef<Node>>, parent: &mut JSRef<Node>) { + // Step 1. match node { - Some(ref mut node) => Node::adopt(node, &document_from_node(parent)), + Some(ref mut node) => { + let document = document_from_node(parent).root(); + Node::adopt(node, &*document); + } None => (), } // Step 2. - let removedNodes: Vec<JS<Node>> = parent.children().collect(); + let removedNodes: Vec<JSRef<Node>> = parent.children().collect(); // Step 3. let addedNodes = match node { @@ -1274,10 +1171,10 @@ impl Node { } // http://dom.spec.whatwg.org/#concept-node-pre-remove - fn pre_remove(child: &mut JS<Node>, parent: &mut JS<Node>) -> Fallible<JS<Node>> { + fn pre_remove(child: &mut JSRef<Node>, parent: &mut JSRef<Node>) -> Fallible<Temporary<Node>> { // Step 1. match child.parent_node() { - Some(ref node) if node != parent => return Err(NotFound), + Some(ref node) if *node != Temporary::from_rooted(parent) => return Err(NotFound), _ => () } @@ -1285,18 +1182,18 @@ impl Node { Node::remove(child, parent, Unsuppressed); // Step 3. - Ok(child.clone()) + Ok(Temporary::from_rooted(child)) } // http://dom.spec.whatwg.org/#concept-node-remove - fn remove(node: &mut JS<Node>, parent: &mut JS<Node>, suppress_observers: SuppressObserver) { - assert!(node.parent_node().map_or(false, |ref node_parent| node_parent == parent)); + fn remove(node: &mut JSRef<Node>, parent: &mut JSRef<Node>, suppress_observers: SuppressObserver) { + assert!(node.parent_node().map_or(false, |node_parent| node_parent == Temporary::from_rooted(parent))); // Step 1-5: ranges. // Step 6-7: mutation observers. // Step 8. parent.remove_child(node); - node.get_mut().flags.set_is_in_doc(false); + node.deref_mut().flags.set_is_in_doc(false); // Step 9. match suppress_observers { @@ -1306,100 +1203,103 @@ impl Node { } // http://dom.spec.whatwg.org/#concept-node-clone - pub fn clone(node: &JS<Node>, maybe_doc: Option<&JS<Document>>, - clone_children: CloneChildrenFlag) -> JS<Node> { + pub fn clone(node: &JSRef<Node>, maybe_doc: Option<&JSRef<Document>>, + clone_children: CloneChildrenFlag) -> Temporary<Node> { + // Step 1. let mut document = match maybe_doc { - Some(doc) => doc.clone(), - None => node.get().owner_doc().clone() + Some(doc) => doc.unrooted().root(), + None => node.owner_doc().root() }; // Step 2. // XXXabinader: clone() for each node as trait? - let mut copy: JS<Node> = match node.type_id() { + let mut copy: Root<Node> = match node.type_id() { DoctypeNodeTypeId => { - let doctype: JS<DocumentType> = DocumentTypeCast::to(node).unwrap(); - let doctype = doctype.get(); + let doctype: &JSRef<DocumentType> = DocumentTypeCast::to_ref(node).unwrap(); + let doctype = doctype.deref(); let doctype = DocumentType::new(doctype.name.clone(), Some(doctype.public_id.clone()), - Some(doctype.system_id.clone()), &document); - NodeCast::from(&doctype) + Some(doctype.system_id.clone()), &*document); + NodeCast::from_unrooted(doctype) }, DocumentFragmentNodeTypeId => { - let doc_fragment = DocumentFragment::new(&document); - NodeCast::from(&doc_fragment) + let doc_fragment = DocumentFragment::new(&*document); + NodeCast::from_unrooted(doc_fragment) }, CommentNodeTypeId => { - let comment: JS<Comment> = CommentCast::to(node).unwrap(); - let comment = comment.get(); - let comment = Comment::new(comment.characterdata.data.clone(), &document); - NodeCast::from(&comment) + let comment: &JSRef<Comment> = CommentCast::to_ref(node).unwrap(); + let comment = comment.deref(); + let comment = Comment::new(comment.characterdata.data.clone(), &*document); + NodeCast::from_unrooted(comment) }, DocumentNodeTypeId => { - let document: JS<Document> = DocumentCast::to(node).unwrap(); - let document = document.get(); + let document: &JSRef<Document> = DocumentCast::to_ref(node).unwrap(); let is_html_doc = match document.is_html_document { true => HTMLDocument, false => NonHTMLDocument }; - let document = Document::new(&document.window, Some(document.url().clone()), + let window = document.window.root(); + let document = Document::new(&*window, Some(document.url().clone()), is_html_doc, None); - NodeCast::from(&document) + NodeCast::from_unrooted(document) }, ElementNodeTypeId(..) => { - let element: JS<Element> = ElementCast::to(node).unwrap(); - let element = element.get(); - let element = build_element_from_tag(element.local_name.clone(), &document); - NodeCast::from(&element) + let element: &JSRef<Element> = ElementCast::to_ref(node).unwrap(); + let element = element.deref(); + let element = build_element_from_tag(element.local_name.clone(), &*document); + NodeCast::from_unrooted(element) }, TextNodeTypeId => { - let text: JS<Text> = TextCast::to(node).unwrap(); - let text = text.get(); - let text = Text::new(text.characterdata.data.clone(), &document); - NodeCast::from(&text) + let text: &JSRef<Text> = TextCast::to_ref(node).unwrap(); + let text = text.deref(); + let text = Text::new(text.characterdata.data.clone(), &*document); + NodeCast::from_unrooted(text) }, ProcessingInstructionNodeTypeId => { - let pi: JS<ProcessingInstruction> = ProcessingInstructionCast::to(node).unwrap(); - let pi = pi.get(); + let pi: &JSRef<ProcessingInstruction> = ProcessingInstructionCast::to_ref(node).unwrap(); + let pi = pi.deref(); let pi = ProcessingInstruction::new(pi.target.clone(), - pi.characterdata.data.clone(), &document); - NodeCast::from(&pi) + pi.characterdata.data.clone(), &*document); + NodeCast::from_unrooted(pi) }, - }; + }.root(); // Step 3. - if copy.is_document() { - document = DocumentCast::to(©).unwrap(); - } - assert!(copy.get().owner_doc() == &document); + let document = if copy.is_document() { + let doc: &JSRef<Document> = DocumentCast::to_ref(&*copy).unwrap(); + doc.unrooted().root() + } else { + document.unrooted().root() + }; + assert!(&*copy.owner_doc().root() == &*document); // Step 4 (some data already copied in step 2). match node.type_id() { DocumentNodeTypeId => { - let node_doc: JS<Document> = DocumentCast::to(node).unwrap(); - let node_doc = node_doc.get(); - let mut copy_doc: JS<Document> = DocumentCast::to(©).unwrap(); - let copy_doc = copy_doc.get_mut(); + let node_doc: &JSRef<Document> = DocumentCast::to_ref(node).unwrap(); + let copy_doc: &mut JSRef<Document> = DocumentCast::to_mut_ref(&mut *copy).unwrap(); copy_doc.set_encoding_name(node_doc.encoding_name.clone()); copy_doc.set_quirks_mode(node_doc.quirks_mode()); }, ElementNodeTypeId(..) => { - let node_elem: JS<Element> = ElementCast::to(node).unwrap(); - let node_elem = node_elem.get(); - let mut copy_elem: JS<Element> = ElementCast::to(©).unwrap(); + let node_elem: &JSRef<Element> = ElementCast::to_ref(node).unwrap(); + let node_elem = node_elem.deref(); + let copy_elem: &mut JSRef<Element> = ElementCast::to_mut_ref(&mut *copy).unwrap(); // XXX: to avoid double borrowing compile error. we might be able to fix this after #1854 - let copy_elem_alias: JS<Element> = copy_elem.clone(); + let copy_elem_alias = copy_elem.clone(); - let copy_elem = copy_elem.get_mut(); + let copy_elem = copy_elem.deref_mut(); // FIXME: https://github.com/mozilla/servo/issues/1737 copy_elem.namespace = node_elem.namespace.clone(); - for attr in node_elem.attrs.iter() { - let attr = attr.get(); - copy_elem.attrs.push(Attr::new(&document.get().window, - attr.local_name.clone(), attr.value.clone(), - attr.name.clone(), attr.namespace.clone(), - attr.prefix.clone(), copy_elem_alias.clone())); + let window = document.deref().window.root(); + for attr in node_elem.attrs.iter().map(|attr| attr.root()) { + copy_elem.attrs.push_unrooted( + &Attr::new(&*window, + attr.deref().local_name.clone(), attr.deref().value.clone(), + attr.deref().name.clone(), attr.deref().namespace.clone(), + attr.deref().prefix.clone(), ©_elem_alias)); } }, _ => () @@ -1409,38 +1309,282 @@ impl Node { // Step 6. if clone_children == CloneChildren { - for ref child in node.get().children() { - let mut child_copy = Node::clone(child, Some(&document), clone_children); - let _inserted_node = Node::pre_insert(&mut child_copy, &mut copy, None); + for ref child in node.children() { + let mut child_copy = Node::clone(&*child, Some(&*document), clone_children).root(); + let _inserted_node = Node::pre_insert(&mut *child_copy, &mut *copy, None); } } // Step 7. - copy + Temporary::from_rooted(&*copy) } - // http://dom.spec.whatwg.org/#dom-node-insertbefore - pub fn InsertBefore(&self, abstract_self: &mut JS<Node>, node: &mut JS<Node>, child: Option<JS<Node>>) - -> Fallible<JS<Node>> { - Node::pre_insert(node, abstract_self, child) + /// Sends layout data, if any, back to the script task to be destroyed. + unsafe fn reap_layout_data(&mut self) { + if self.layout_data.is_present() { + let layout_data = mem::replace(&mut self.layout_data, LayoutDataRef::new()); + let layout_chan = layout_data.take_chan(); + match layout_chan { + None => {} + Some(chan) => { + let LayoutChan(chan) = chan; + chan.send(ReapLayoutDataMsg(layout_data)) + }, + } + } + } +} + +pub trait NodeMethods { + fn NodeType(&self) -> u16; + fn NodeName(&self) -> DOMString; + fn GetBaseURI(&self) -> Option<DOMString>; + fn GetOwnerDocument(&self) -> Option<Temporary<Document>>; + fn GetParentNode(&self) -> Option<Temporary<Node>>; + fn GetParentElement(&self) -> Option<Temporary<Element>>; + fn HasChildNodes(&self) -> bool; + fn ChildNodes(&mut self) -> Temporary<NodeList>; + fn GetFirstChild(&self) -> Option<Temporary<Node>>; + fn GetLastChild(&self) -> Option<Temporary<Node>>; + fn GetPreviousSibling(&self) -> Option<Temporary<Node>>; + fn GetNextSibling(&self) -> Option<Temporary<Node>>; + fn GetNodeValue(&self) -> Option<DOMString>; + fn SetNodeValue(&mut self, val: Option<DOMString>) -> ErrorResult; + fn GetTextContent(&self) -> Option<DOMString>; + fn SetTextContent(&mut self, value: Option<DOMString>) -> ErrorResult; + fn InsertBefore(&mut self, node: &mut JSRef<Node>, child: Option<JSRef<Node>>) -> Fallible<Temporary<Node>>; + fn AppendChild(&mut self, node: &mut JSRef<Node>) -> Fallible<Temporary<Node>>; + fn ReplaceChild(&mut self, node: &mut JSRef<Node>, child: &mut JSRef<Node>) -> Fallible<Temporary<Node>>; + fn RemoveChild(&mut self, node: &mut JSRef<Node>) -> Fallible<Temporary<Node>>; + fn Normalize(&mut self); + fn CloneNode(&self, deep: bool) -> Temporary<Node>; + fn IsEqualNode(&self, maybe_node: Option<JSRef<Node>>) -> bool; + fn CompareDocumentPosition(&self, other: &JSRef<Node>) -> u16; + fn Contains(&self, maybe_other: Option<JSRef<Node>>) -> bool; + fn LookupPrefix(&self, _prefix: Option<DOMString>) -> Option<DOMString>; + fn LookupNamespaceURI(&self, _namespace: Option<DOMString>) -> Option<DOMString>; + fn IsDefaultNamespace(&self, _namespace: Option<DOMString>) -> bool; +} + +impl<'a> NodeMethods for JSRef<'a, Node> { + // http://dom.spec.whatwg.org/#dom-node-nodetype + fn NodeType(&self) -> u16 { + match self.type_id { + ElementNodeTypeId(_) => NodeConstants::ELEMENT_NODE, + TextNodeTypeId => NodeConstants::TEXT_NODE, + ProcessingInstructionNodeTypeId => NodeConstants::PROCESSING_INSTRUCTION_NODE, + CommentNodeTypeId => NodeConstants::COMMENT_NODE, + DocumentNodeTypeId => NodeConstants::DOCUMENT_NODE, + DoctypeNodeTypeId => NodeConstants::DOCUMENT_TYPE_NODE, + DocumentFragmentNodeTypeId => NodeConstants::DOCUMENT_FRAGMENT_NODE, + } + } + + // http://dom.spec.whatwg.org/#dom-node-nodename + fn NodeName(&self) -> DOMString { + match self.type_id { + ElementNodeTypeId(..) => { + let elem: &JSRef<Element> = ElementCast::to_ref(self).unwrap(); + elem.TagName() + } + TextNodeTypeId => ~"#text", + ProcessingInstructionNodeTypeId => { + let processing_instruction: &JSRef<ProcessingInstruction> = + ProcessingInstructionCast::to_ref(self).unwrap(); + processing_instruction.Target() + } + CommentNodeTypeId => ~"#comment", + DoctypeNodeTypeId => { + let doctype: &JSRef<DocumentType> = DocumentTypeCast::to_ref(self).unwrap(); + doctype.deref().name.clone() + }, + DocumentFragmentNodeTypeId => ~"#document-fragment", + DocumentNodeTypeId => ~"#document" + } + } + + // http://dom.spec.whatwg.org/#dom-node-baseuri + fn GetBaseURI(&self) -> Option<DOMString> { + // FIXME (#1824) implement. + None + } + + // http://dom.spec.whatwg.org/#dom-node-ownerdocument + fn GetOwnerDocument(&self) -> Option<Temporary<Document>> { + match self.type_id { + ElementNodeTypeId(..) | + CommentNodeTypeId | + TextNodeTypeId | + ProcessingInstructionNodeTypeId | + DoctypeNodeTypeId | + DocumentFragmentNodeTypeId => Some(self.owner_doc()), + DocumentNodeTypeId => None + } + } + + // http://dom.spec.whatwg.org/#dom-node-parentnode + fn GetParentNode(&self) -> Option<Temporary<Node>> { + self.parent_node.clone().map(|node| Temporary::new(node)) + } + + // http://dom.spec.whatwg.org/#dom-node-parentelement + fn GetParentElement(&self) -> Option<Temporary<Element>> { + self.parent_node.clone() + .and_then(|parent| { + let parent = parent.root(); + ElementCast::to_ref(&*parent).map(|elem| { + Temporary::from_rooted(elem) + }) + }) + } + + // http://dom.spec.whatwg.org/#dom-node-haschildnodes + fn HasChildNodes(&self) -> bool { + self.first_child.is_some() + } + + // http://dom.spec.whatwg.org/#dom-node-childnodes + fn ChildNodes(&mut self) -> Temporary<NodeList> { + match self.child_list { + None => (), + Some(ref list) => return Temporary::new(list.clone()), + } + + let doc = self.owner_doc().root(); + let window = doc.deref().window.root(); + let child_list = NodeList::new_child_list(&*window, self); + self.child_list.assign(Some(child_list)); + Temporary::new(self.child_list.get_ref().clone()) + } + + // http://dom.spec.whatwg.org/#dom-node-firstchild + fn GetFirstChild(&self) -> Option<Temporary<Node>> { + self.first_child.clone().map(|node| Temporary::new(node)) + } + + // http://dom.spec.whatwg.org/#dom-node-lastchild + fn GetLastChild(&self) -> Option<Temporary<Node>> { + self.last_child.clone().map(|node| Temporary::new(node)) + } + + // http://dom.spec.whatwg.org/#dom-node-previoussibling + fn GetPreviousSibling(&self) -> Option<Temporary<Node>> { + self.prev_sibling.clone().map(|node| Temporary::new(node)) + } + + // http://dom.spec.whatwg.org/#dom-node-nextsibling + fn GetNextSibling(&self) -> Option<Temporary<Node>> { + self.next_sibling.clone().map(|node| Temporary::new(node)) + } + + // http://dom.spec.whatwg.org/#dom-node-nodevalue + fn GetNodeValue(&self) -> Option<DOMString> { + match self.type_id { + CommentNodeTypeId | + TextNodeTypeId | + ProcessingInstructionNodeTypeId => { + let chardata: &JSRef<CharacterData> = CharacterDataCast::to_ref(self).unwrap(); + Some(chardata.Data()) + } + _ => { + None + } + } + } + + // http://dom.spec.whatwg.org/#dom-node-nodevalue + fn SetNodeValue(&mut self, val: Option<DOMString>) + -> ErrorResult { + match self.type_id { + CommentNodeTypeId | + TextNodeTypeId | + ProcessingInstructionNodeTypeId => { + self.SetTextContent(val) + } + _ => Ok(()) + } + } + + // http://dom.spec.whatwg.org/#dom-node-textcontent + fn GetTextContent(&self) -> Option<DOMString> { + match self.type_id { + DocumentFragmentNodeTypeId | + ElementNodeTypeId(..) => { + let mut content = ~""; + for node in self.traverse_preorder() { + if node.is_text() { + let text: &JSRef<Text> = TextCast::to_ref(&node).unwrap(); + content.push_str(text.deref().characterdata.data.as_slice()); + } + } + Some(content) + } + CommentNodeTypeId | + TextNodeTypeId | + ProcessingInstructionNodeTypeId => { + let characterdata: &JSRef<CharacterData> = CharacterDataCast::to_ref(self).unwrap(); + Some(characterdata.Data()) + } + DoctypeNodeTypeId | + DocumentNodeTypeId => { + None + } + } } - pub fn wait_until_safe_to_modify_dom(&self) { - let document = self.owner_doc(); - document.get().wait_until_safe_to_modify_dom(); + // http://dom.spec.whatwg.org/#dom-node-textcontent + fn SetTextContent(&mut self, value: Option<DOMString>) + -> ErrorResult { + let value = null_str_as_empty(&value); + match self.type_id { + DocumentFragmentNodeTypeId | + ElementNodeTypeId(..) => { + // Step 1-2. + let node = if value.len() == 0 { + None + } else { + let document = self.owner_doc().root(); + Some(NodeCast::from_unrooted(document.deref().CreateTextNode(value))) + }.root(); + + // Step 3. + Node::replace_all(node.root_ref(), self); + } + CommentNodeTypeId | + TextNodeTypeId | + ProcessingInstructionNodeTypeId => { + self.wait_until_safe_to_modify_dom(); + + { + let characterdata: &mut JSRef<CharacterData> = CharacterDataCast::to_mut_ref(self).unwrap(); + characterdata.deref_mut().data = value.clone(); + } + + // Notify the document that the content of this node is different + let document = self.owner_doc().root(); + document.deref().content_changed(); + } + DoctypeNodeTypeId | + DocumentNodeTypeId => {} + } + Ok(()) + } + + // http://dom.spec.whatwg.org/#dom-node-insertbefore + fn InsertBefore(&mut self, node: &mut JSRef<Node>, child: Option<JSRef<Node>>) -> Fallible<Temporary<Node>> { + Node::pre_insert(node, self, child) } // http://dom.spec.whatwg.org/#dom-node-appendchild - pub fn AppendChild(&self, abstract_self: &mut JS<Node>, node: &mut JS<Node>) - -> Fallible<JS<Node>> { - Node::pre_insert(node, abstract_self, None) + fn AppendChild(&mut self, node: &mut JSRef<Node>) -> Fallible<Temporary<Node>> { + Node::pre_insert(node, self, None) } // http://dom.spec.whatwg.org/#concept-node-replace - pub fn ReplaceChild(&self, parent: &mut JS<Node>, node: &mut JS<Node>, child: &mut JS<Node>) - -> Fallible<JS<Node>> { + fn ReplaceChild(&mut self, node: &mut JSRef<Node>, child: &mut JSRef<Node>) -> Fallible<Temporary<Node>> { + // Step 1. - match parent.type_id() { + match self.type_id() { DocumentNodeTypeId | DocumentFragmentNodeTypeId | ElementNodeTypeId(..) => (), @@ -1448,19 +1592,19 @@ impl Node { } // Step 2. - if node.is_inclusive_ancestor_of(parent) { + if node.is_inclusive_ancestor_of(self) { return Err(HierarchyRequest); } // Step 3. - if !parent.is_parent_of(child) { + if !self.is_parent_of(child) { return Err(NotFound); } // Step 4-5. match node.type_id() { - TextNodeTypeId if parent.is_document() => return Err(HierarchyRequest), - DoctypeNodeTypeId if !parent.is_document() => return Err(HierarchyRequest), + TextNodeTypeId if self.is_document() => return Err(HierarchyRequest), + DoctypeNodeTypeId if !self.is_document() => return Err(HierarchyRequest), DocumentFragmentNodeTypeId | DoctypeNodeTypeId | ElementNodeTypeId(..) | @@ -1471,7 +1615,7 @@ impl Node { } // Step 6. - match parent.type_id() { + match self.type_id() { DocumentNodeTypeId => { match node.type_id() { // Step 6.1 @@ -1484,7 +1628,7 @@ impl Node { 0 => (), // Step 6.1.2 1 => { - if parent.child_elements().any(|c| &NodeCast::from(&c) != child) { + if self.child_elements().any(|c| NodeCast::from_ref(&c) != child) { return Err(HierarchyRequest); } if child.following_siblings() @@ -1498,7 +1642,7 @@ impl Node { }, // Step 6.2 ElementNodeTypeId(..) => { - if parent.child_elements().any(|c| &NodeCast::from(&c) != child) { + if self.child_elements().any(|c| NodeCast::from_ref(&c) != child) { return Err(HierarchyRequest); } if child.following_siblings() @@ -1508,10 +1652,10 @@ impl Node { }, // Step 6.3 DoctypeNodeTypeId => { - if parent.children().any(|c| c.is_doctype() && &c != child) { + if self.children().any(|c| c.is_doctype() && &c != child) { return Err(HierarchyRequest); } - if parent.children() + if self.children() .take_while(|c| c != child) .any(|c| c.is_element()) { return Err(HierarchyRequest); @@ -1528,25 +1672,26 @@ impl Node { // Ok if not caught by previous error checks. if *node == *child { - return Ok(child.clone()); + return Ok(Temporary::from_rooted(child)); } // Step 7-8. - let next_sibling = child.next_sibling(); + let next_sibling = child.next_sibling().map(|node| (*node.root()).clone()); let reference_child = match next_sibling { - Some(ref sibling) if sibling == node => node.next_sibling(), + Some(ref sibling) if sibling == node => node.next_sibling().map(|node| (*node.root()).clone()), _ => next_sibling }; // Step 9. - Node::adopt(node, &document_from_node(parent)); + let document = document_from_node(self).root(); + Node::adopt(node, &*document); { // Step 10. - Node::remove(child, parent, Suppressed); + Node::remove(child, self, Suppressed); // Step 11. - Node::insert(node, parent, reference_child, Suppressed); + Node::insert(node, self, reference_child, Suppressed); } // Step 12-14. @@ -1561,36 +1706,36 @@ impl Node { } // Step 15. - Ok(child.clone()) + Ok(Temporary::from_rooted(child)) } // http://dom.spec.whatwg.org/#dom-node-removechild - pub fn RemoveChild(&self, abstract_self: &mut JS<Node>, node: &mut JS<Node>) - -> Fallible<JS<Node>> { - Node::pre_remove(node, abstract_self) + fn RemoveChild(&mut self, node: &mut JSRef<Node>) + -> Fallible<Temporary<Node>> { + Node::pre_remove(node, self) } // http://dom.spec.whatwg.org/#dom-node-normalize - pub fn Normalize(&mut self, abstract_self: &mut JS<Node>) { + fn Normalize(&mut self) { let mut prev_text = None; for mut child in self.children() { if child.is_text() { - let characterdata: JS<CharacterData> = CharacterDataCast::to(&child).unwrap(); - if characterdata.get().Length() == 0 { - abstract_self.remove_child(&mut child); + let mut child_alias = child.clone(); + let characterdata: &JSRef<CharacterData> = CharacterDataCast::to_ref(&child).unwrap(); + if characterdata.Length() == 0 { + self.remove_child(&mut child_alias); } else { match prev_text { - Some(ref text_node) => { - let mut prev_characterdata: JS<CharacterData> = CharacterDataCast::to(text_node).unwrap(); - let _ = prev_characterdata.get_mut().AppendData(characterdata.get().Data()); - abstract_self.remove_child(&mut child); + Some(ref mut text_node) => { + let prev_characterdata: &mut JSRef<CharacterData> = CharacterDataCast::to_mut_ref(text_node).unwrap(); + let _ = prev_characterdata.AppendData(characterdata.Data()); + self.remove_child(&mut child_alias); }, - None => prev_text = Some(child) + None => prev_text = Some(child_alias) } } } else { - let c = &mut child.clone(); - child.get_mut().Normalize(c); + child.Normalize(); prev_text = None; } @@ -1598,54 +1743,54 @@ impl Node { } // http://dom.spec.whatwg.org/#dom-node-clonenode - pub fn CloneNode(&self, abstract_self: &mut JS<Node>, deep: bool) -> JS<Node> { + fn CloneNode(&self, deep: bool) -> Temporary<Node> { match deep { - true => Node::clone(abstract_self, None, CloneChildren), - false => Node::clone(abstract_self, None, DoNotCloneChildren) + true => Node::clone(self, None, CloneChildren), + false => Node::clone(self, None, DoNotCloneChildren) } } // http://dom.spec.whatwg.org/#dom-node-isequalnode - pub fn IsEqualNode(&self, abstract_self: &JS<Node>, maybe_node: Option<JS<Node>>) -> bool { - fn is_equal_doctype(node: &JS<Node>, other: &JS<Node>) -> bool { - let doctype: JS<DocumentType> = DocumentTypeCast::to(node).unwrap(); - let other_doctype: JS<DocumentType> = DocumentTypeCast::to(other).unwrap(); - (doctype.get().name == other_doctype.get().name) && - (doctype.get().public_id == other_doctype.get().public_id) && - (doctype.get().system_id == other_doctype.get().system_id) - } - fn is_equal_element(node: &JS<Node>, other: &JS<Node>) -> bool { - let element: JS<Element> = ElementCast::to(node).unwrap(); - let other_element: JS<Element> = ElementCast::to(other).unwrap(); + fn IsEqualNode(&self, maybe_node: Option<JSRef<Node>>) -> bool { + fn is_equal_doctype(node: &JSRef<Node>, other: &JSRef<Node>) -> bool { + let doctype: &JSRef<DocumentType> = DocumentTypeCast::to_ref(node).unwrap(); + let other_doctype: &JSRef<DocumentType> = DocumentTypeCast::to_ref(other).unwrap(); + (doctype.deref().name == other_doctype.deref().name) && + (doctype.deref().public_id == other_doctype.deref().public_id) && + (doctype.deref().system_id == other_doctype.deref().system_id) + } + fn is_equal_element(node: &JSRef<Node>, other: &JSRef<Node>) -> bool { + let element: &JSRef<Element> = ElementCast::to_ref(node).unwrap(); + let other_element: &JSRef<Element> = ElementCast::to_ref(other).unwrap(); // FIXME: namespace prefix - (element.get().namespace == other_element.get().namespace) && - (element.get().local_name == other_element.get().local_name) && - (element.get().attrs.len() == other_element.get().attrs.len()) - } - fn is_equal_processinginstruction(node: &JS<Node>, other: &JS<Node>) -> bool { - let pi: JS<ProcessingInstruction> = ProcessingInstructionCast::to(node).unwrap(); - let other_pi: JS<ProcessingInstruction> = ProcessingInstructionCast::to(other).unwrap(); - (pi.get().target == other_pi.get().target) && - (pi.get().characterdata.data == other_pi.get().characterdata.data) - } - fn is_equal_characterdata(node: &JS<Node>, other: &JS<Node>) -> bool { - let characterdata: JS<CharacterData> = CharacterDataCast::to(node).unwrap(); - let other_characterdata: JS<CharacterData> = CharacterDataCast::to(other).unwrap(); - characterdata.get().data == other_characterdata.get().data - } - fn is_equal_element_attrs(node: &JS<Node>, other: &JS<Node>) -> bool { - let element: JS<Element> = ElementCast::to(node).unwrap(); - let other_element: JS<Element> = ElementCast::to(other).unwrap(); - assert!(element.get().attrs.len() == other_element.get().attrs.len()); - element.get().attrs.iter().all(|attr| { - other_element.get().attrs.iter().any(|other_attr| { - (attr.get().namespace == other_attr.get().namespace) && - (attr.get().local_name == other_attr.get().local_name) && - (attr.get().value == other_attr.get().value) + (element.deref().namespace == other_element.deref().namespace) && + (element.deref().local_name == other_element.deref().local_name) && + (element.deref().attrs.len() == other_element.deref().attrs.len()) + } + fn is_equal_processinginstruction(node: &JSRef<Node>, other: &JSRef<Node>) -> bool { + let pi: &JSRef<ProcessingInstruction> = ProcessingInstructionCast::to_ref(node).unwrap(); + let other_pi: &JSRef<ProcessingInstruction> = ProcessingInstructionCast::to_ref(other).unwrap(); + (pi.deref().target == other_pi.deref().target) && + (pi.deref().characterdata.data == other_pi.deref().characterdata.data) + } + fn is_equal_characterdata(node: &JSRef<Node>, other: &JSRef<Node>) -> bool { + let characterdata: &JSRef<CharacterData> = CharacterDataCast::to_ref(node).unwrap(); + let other_characterdata: &JSRef<CharacterData> = CharacterDataCast::to_ref(other).unwrap(); + characterdata.deref().data == other_characterdata.deref().data + } + fn is_equal_element_attrs(node: &JSRef<Node>, other: &JSRef<Node>) -> bool { + let element: &JSRef<Element> = ElementCast::to_ref(node).unwrap(); + let other_element: &JSRef<Element> = ElementCast::to_ref(other).unwrap(); + assert!(element.deref().attrs.len() == other_element.deref().attrs.len()); + element.deref().attrs.iter().map(|attr| attr.root()).all(|attr| { + other_element.deref().attrs.iter().map(|attr| attr.root()).any(|other_attr| { + (attr.namespace == other_attr.namespace) && + (attr.local_name == other_attr.local_name) && + (attr.value == other_attr.value) }) }) } - fn is_equal_node(this: &JS<Node>, node: &JS<Node>) -> bool { + fn is_equal_node(this: &JSRef<Node>, node: &JSRef<Node>) -> bool { // Step 2. if this.type_id() != node.type_id() { return false; @@ -1669,44 +1814,46 @@ impl Node { } // Step 6. - this.children().zip(node.children()).all(|(ref child, ref other_child)| is_equal_node(child, other_child)) + this.children().zip(node.children()).all(|(ref child, ref other_child)| { + is_equal_node(child, other_child) + }) } match maybe_node { // Step 1. None => false, // Step 2-6. - Some(ref node) => is_equal_node(abstract_self, node) + Some(ref node) => is_equal_node(self, node) } } // http://dom.spec.whatwg.org/#dom-node-comparedocumentposition - pub fn CompareDocumentPosition(&self, abstract_self: &JS<Node>, other: &JS<Node>) -> u16 { - if abstract_self == other { + fn CompareDocumentPosition(&self, other: &JSRef<Node>) -> u16 { + if self == other { // step 2. 0 } else { - let mut lastself = abstract_self.clone(); + let mut lastself = self.clone(); let mut lastother = other.clone(); - for ancestor in abstract_self.ancestors() { + for ancestor in self.ancestors() { if &ancestor == other { // step 4. return NodeConstants::DOCUMENT_POSITION_CONTAINS + NodeConstants::DOCUMENT_POSITION_PRECEDING; } - lastself = ancestor; + lastself = ancestor.clone(); } for ancestor in other.ancestors() { - if &ancestor == abstract_self { + if &ancestor == self { // step 5. return NodeConstants::DOCUMENT_POSITION_CONTAINED_BY + NodeConstants::DOCUMENT_POSITION_FOLLOWING; } - lastother = ancestor; + lastother = ancestor.clone(); } if lastself != lastother { - let abstract_uint: uintptr_t = as_uintptr(&abstract_self.get()); - let other_uint: uintptr_t = as_uintptr(&other.get()); + let abstract_uint: uintptr_t = as_uintptr(&*self); + let other_uint: uintptr_t = as_uintptr(&*other); let random = if abstract_uint < other_uint { NodeConstants::DOCUMENT_POSITION_FOLLOWING @@ -1724,7 +1871,7 @@ impl Node { // step 6. return NodeConstants::DOCUMENT_POSITION_PRECEDING; } - if &child == abstract_self { + if &child == self { // step 7. return NodeConstants::DOCUMENT_POSITION_FOLLOWING; } @@ -1734,103 +1881,33 @@ impl Node { } // http://dom.spec.whatwg.org/#dom-node-contains - pub fn Contains(&self, abstract_self: &JS<Node>, maybe_other: Option<JS<Node>>) -> bool { + fn Contains(&self, maybe_other: Option<JSRef<Node>>) -> bool { match maybe_other { None => false, - Some(ref other) => abstract_self.is_inclusive_ancestor_of(other) + Some(ref other) => self.is_inclusive_ancestor_of(other) } } // http://dom.spec.whatwg.org/#dom-node-lookupprefix - pub fn LookupPrefix(&self, _prefix: Option<DOMString>) -> Option<DOMString> { + fn LookupPrefix(&self, _prefix: Option<DOMString>) -> Option<DOMString> { // FIXME (#1826) implement. None } // http://dom.spec.whatwg.org/#dom-node-lookupnamespaceuri - pub fn LookupNamespaceURI(&self, _namespace: Option<DOMString>) -> Option<DOMString> { + fn LookupNamespaceURI(&self, _namespace: Option<DOMString>) -> Option<DOMString> { // FIXME (#1826) implement. None } // http://dom.spec.whatwg.org/#dom-node-isdefaultnamespace - pub fn IsDefaultNamespace(&self, _namespace: Option<DOMString>) -> bool { + fn IsDefaultNamespace(&self, _namespace: Option<DOMString>) -> bool { // FIXME (#1826) implement. false } - - // - // Low-level pointer stitching - // - - pub fn set_parent_node(&mut self, new_parent_node: Option<JS<Node>>) { - let doc = self.owner_doc().clone(); - doc.get().wait_until_safe_to_modify_dom(); - self.parent_node = new_parent_node - } - - pub fn set_first_child(&mut self, new_first_child: Option<JS<Node>>) { - let doc = self.owner_doc().clone(); - doc.get().wait_until_safe_to_modify_dom(); - self.first_child = new_first_child - } - - pub fn set_last_child(&mut self, new_last_child: Option<JS<Node>>) { - let doc = self.owner_doc().clone(); - doc.get().wait_until_safe_to_modify_dom(); - self.last_child = new_last_child - } - - pub fn set_prev_sibling(&mut self, new_prev_sibling: Option<JS<Node>>) { - let doc = self.owner_doc().clone(); - doc.get().wait_until_safe_to_modify_dom(); - self.prev_sibling = new_prev_sibling - } - - pub fn set_next_sibling(&mut self, new_next_sibling: Option<JS<Node>>) { - let doc = self.owner_doc().clone(); - doc.get().wait_until_safe_to_modify_dom(); - self.next_sibling = new_next_sibling - } - - pub fn get_hover_state(&self) -> bool { - self.flags.get_in_hover_state() - } - - pub fn set_hover_state(&mut self, state: bool) { - self.flags.set_is_in_hover_state(state); - } - - #[inline] - pub fn parent_node_ref<'a>(&'a self) -> Option<&'a JS<Node>> { - self.parent_node.as_ref() - } - - #[inline] - pub fn first_child_ref<'a>(&'a self) -> Option<&'a JS<Node>> { - self.first_child.as_ref() - } - - #[inline] - pub fn last_child_ref<'a>(&'a self) -> Option<&'a JS<Node>> { - self.last_child.as_ref() - } - - #[inline] - pub fn prev_sibling_ref<'a>(&'a self) -> Option<&'a JS<Node>> { - self.prev_sibling.as_ref() - } - - #[inline] - pub fn next_sibling_ref<'a>(&'a self) -> Option<&'a JS<Node>> { - self.next_sibling.as_ref() - } - - pub unsafe fn get_hover_state_for_layout(&self) -> bool { - self.flags.get_in_hover_state() - } } + impl Reflectable for Node { fn reflector<'a>(&'a self) -> &'a Reflector { self.eventtarget.reflector() @@ -1841,19 +1918,19 @@ impl Reflectable for Node { } } -pub fn document_from_node<T: NodeBase>(derived: &JS<T>) -> JS<Document> { - let node: JS<Node> = NodeCast::from(derived); - node.get().owner_doc().clone() +pub fn document_from_node<T: NodeBase>(derived: &JSRef<T>) -> Temporary<Document> { + let node: &JSRef<Node> = NodeCast::from_ref(derived); + node.owner_doc() } -pub fn window_from_node<T: NodeBase>(derived: &JS<T>) -> JS<Window> { - let document: JS<Document> = document_from_node(derived); - document.get().window.clone() +pub fn window_from_node<T: NodeBase>(derived: &JSRef<T>) -> Temporary<Window> { + let document = document_from_node(derived).root(); + Temporary::new(document.deref().window.clone()) } -impl VirtualMethods for JS<Node> { - fn super_type(&self) -> Option<~VirtualMethods:> { - let eventtarget: JS<EventTarget> = EventTargetCast::from(self); - Some(~eventtarget as ~VirtualMethods:) +impl<'a> VirtualMethods for JSRef<'a, Node> { + fn super_type<'a>(&'a mut self) -> Option<&'a mut VirtualMethods:> { + let eventtarget: &mut JSRef<EventTarget> = EventTargetCast::from_mut_ref(self); + Some(eventtarget as &mut VirtualMethods:) } } |