diff options
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:) } } |