diff options
Diffstat (limited to 'src/components/script/dom/node.rs')
-rw-r--r-- | src/components/script/dom/node.rs | 294 |
1 files changed, 252 insertions, 42 deletions
diff --git a/src/components/script/dom/node.rs b/src/components/script/dom/node.rs index 9999503a758..71b2b121136 100644 --- a/src/components/script/dom/node.rs +++ b/src/components/script/dom/node.rs @@ -4,15 +4,20 @@ //! The core DOM types. Defines the basic DOM hierarchy as well as all the HTML elements. -use dom::bindings::codegen::InheritTypes::{DocumentTypeCast, ElementCast, TextCast, NodeCast}; +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::{CharacterDataCast, NodeBase, NodeDerived}; use dom::bindings::codegen::InheritTypes::ProcessingInstructionCast; +use dom::bindings::codegen::NodeBinding::NodeConstants; use dom::bindings::js::JS; 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::document::Document; +use dom::comment::Comment; +use dom::document::{Document, HTMLDocument, NonHTMLDocument}; +use dom::documentfragment::DocumentFragment; use dom::documenttype::DocumentType; use dom::element::{Element, ElementTypeId, HTMLAnchorElementTypeId, IElement}; use dom::eventtarget::{EventTarget, NodeTargetTypeId}; @@ -20,6 +25,7 @@ use dom::nodelist::{NodeList}; use dom::text::Text; use dom::processinginstruction::ProcessingInstruction; use dom::window::Window; +use html::hubbub_html_parser::build_element_from_tag; use layout_interface::{LayoutChan, ReapLayoutDataMsg, UntrustedNodeAddress}; use layout_interface::TrustedNodeAddress; use servo_util::str::{DOMString, null_str_as_empty}; @@ -31,10 +37,9 @@ use std::cast; use std::cell::{RefCell, Ref, RefMut}; use std::iter::{Map, Filter}; use std::libc::uintptr_t; -use std::unstable::raw::Box; -use std::util; +use std::mem; -use extra::serialize::{Encoder, Encodable}; +use serialize::{Encoder, Encodable}; // // The basic Node structure @@ -399,10 +404,12 @@ impl NodeHelpers for JS<Node> { assert!(self.parent_node().is_some()); let document = document_from_node(self); - for node in self.traverse_preorder() { - if node.is_element() { - let element: JS<Element> = ElementCast::to(&node); - element.bind_to_tree_impl(); + if self.is_in_doc() { + for node in self.traverse_preorder() { + if node.is_element() { + let element: JS<Element> = ElementCast::to(&node); + element.bind_to_tree_impl(); + } } } @@ -555,8 +562,8 @@ impl NodeHelpers for JS<Node> { if object.is_null() { fail!("Attempted to create a `JS<Node>` from an invalid pointer!") } - let boxed_node: *mut Box<Node> = utils::unwrap(object); - JS::from_box(boxed_node) + let boxed_node: *mut Node = utils::unwrap(object); + JS::from_raw(boxed_node) } } @@ -721,6 +728,14 @@ fn gather_abstract_nodes(cur: &JS<Node>, refs: &mut ~[JS<Node>], postorder: bool } } +/// Specifies whether children must be recursively cloned or not. +enum CloneChildrenFlag { + CloneChildren, + DoNotCloneChildren +} + +fn as_uintptr<T>(t: &T) -> uintptr_t { t as *T as uintptr_t } + impl Node { pub fn ancestors(&self) -> AncestorIterator { AncestorIterator { @@ -728,8 +743,8 @@ impl Node { } } - pub fn owner_doc(&self) -> JS<Document> { - self.owner_doc.clone().unwrap() + 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>) { @@ -793,11 +808,14 @@ 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 = util::replace(&mut self.layout_data, LayoutDataRef::new()); + let layout_data = mem::replace(&mut self.layout_data, LayoutDataRef::new()); let layout_chan = layout_data.take_chan(); match layout_chan { None => {} - Some(chan) => chan.send(ReapLayoutDataMsg(layout_data)), + Some(chan) => { + let LayoutChan(chan) = chan; + chan.send(ReapLayoutDataMsg(layout_data)) + }, } } } @@ -805,13 +823,13 @@ impl Node { // http://dom.spec.whatwg.org/#dom-node-nodetype pub fn NodeType(&self) -> u16 { match self.type_id { - ElementNodeTypeId(_) => 1, - TextNodeTypeId => 3, - ProcessingInstructionNodeTypeId => 7, - CommentNodeTypeId => 8, - DocumentNodeTypeId => 9, - DoctypeNodeTypeId => 10, - DocumentFragmentNodeTypeId => 11, + 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, } } @@ -852,7 +870,7 @@ impl Node { TextNodeTypeId | ProcessingInstructionNodeTypeId | DoctypeNodeTypeId | - DocumentFragmentNodeTypeId => Some(self.owner_doc()), + DocumentFragmentNodeTypeId => Some(self.owner_doc().clone()), DocumentNodeTypeId => None } } @@ -878,7 +896,7 @@ impl Node { pub fn ChildNodes(&mut self, abstract_self: &JS<Node>) -> JS<NodeList> { match self.child_list { None => { - let doc = self.owner_doc(); + 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()); @@ -930,11 +948,10 @@ impl Node { CommentNodeTypeId | TextNodeTypeId | ProcessingInstructionNodeTypeId => { - self.SetTextContent(abstract_self, val); + self.SetTextContent(abstract_self, val) } - _ => {} + _ => Ok(()) } - Ok(()) } // http://dom.spec.whatwg.org/#dom-node-textcontent @@ -976,7 +993,7 @@ impl Node { None } else { let document = self.owner_doc(); - Some(NodeCast::from(&document.get().CreateTextNode(&document, value))) + Some(NodeCast::from(&document.get().CreateTextNode(document, value))) }; // Step 3. Node::replace_all(node, abstract_self); @@ -1255,7 +1272,7 @@ impl Node { // 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_default(false, |ref node_parent| node_parent == parent)); + assert!(node.parent_node().map_or(false, |ref node_parent| node_parent == parent)); // Step 1-5: ranges. // Step 6-7: mutation observers. @@ -1270,6 +1287,124 @@ impl Node { } } + // http://dom.spec.whatwg.org/#concept-node-clone + fn clone(node: &JS<Node>, maybe_doc: Option<&JS<Document>>, clone_children: CloneChildrenFlag) + -> JS<Node> { + fn clone_recursively(node: &JS<Node>, copy: &mut JS<Node>, doc: &JS<Document>) { + for ref child in node.get().children() { + let mut cloned = Node::clone(child, Some(doc), DoNotCloneChildren); + match Node::pre_insert(&mut cloned, copy, None) { + Ok(ref mut appended) => clone_recursively(child, appended, doc), + Err(..) => fail!("an error occurred while appending children") + } + } + } + + // Step 1. + let mut document = match maybe_doc { + Some(doc) => doc.clone(), + None => node.get().owner_doc().clone() + }; + + // Step 2. + // XXXabinader: clone() for each node as trait? + let mut copy: JS<Node> = match node.type_id() { + DoctypeNodeTypeId => { + let doctype: JS<DocumentType> = DocumentTypeCast::to(node); + let doctype = doctype.get(); + let doctype = DocumentType::new(doctype.name.clone(), + Some(doctype.public_id.clone()), + Some(doctype.system_id.clone()), &document); + NodeCast::from(&doctype) + }, + DocumentFragmentNodeTypeId => { + let doc_fragment = DocumentFragment::new(&document); + NodeCast::from(&doc_fragment) + }, + CommentNodeTypeId => { + let comment: JS<Comment> = CommentCast::to(node); + let comment = comment.get(); + let comment = Comment::new(comment.characterdata.data.clone(), &document); + NodeCast::from(&comment) + }, + DocumentNodeTypeId => { + let document: JS<Document> = DocumentCast::to(node); + let document = document.get(); + let is_html_doc = match document.is_html_document { + true => HTMLDocument, + false => NonHTMLDocument + }; + let document = Document::new(&document.window, Some(document.url().clone()), + is_html_doc, None); + NodeCast::from(&document) + }, + ElementNodeTypeId(..) => { + let element: JS<Element> = ElementCast::to(node); + let element = element.get(); + let element = build_element_from_tag(element.tag_name.clone(), &document); + NodeCast::from(&element) + }, + TextNodeTypeId => { + let text: JS<Text> = TextCast::to(node); + let text = text.get(); + let text = Text::new(text.characterdata.data.clone(), &document); + NodeCast::from(&text) + }, + ProcessingInstructionNodeTypeId => { + let pi: JS<ProcessingInstruction> = ProcessingInstructionCast::to(node); + let pi = pi.get(); + let pi = ProcessingInstruction::new(pi.target.clone(), + pi.characterdata.data.clone(), &document); + NodeCast::from(&pi) + }, + }; + + // Step 3. + if copy.is_document() { + document = DocumentCast::to(©); + } + assert_eq!(copy.get().owner_doc(), &document); + + // Step 4 (some data already copied in step 2). + match node.type_id() { + DocumentNodeTypeId => { + let node_doc: JS<Document> = DocumentCast::to(node); + let node_doc = node_doc.get(); + let mut copy_doc: JS<Document> = DocumentCast::to(©); + let copy_doc = copy_doc.get_mut(); + 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); + let node_elem = node_elem.get(); + let mut copy_elem: JS<Element> = ElementCast::to(©); + let copy_elem = copy_elem.get_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_ns(&document.get().window, + attr.local_name.clone(), attr.value.clone(), + attr.name.clone(), attr.namespace.clone(), + attr.prefix.clone())); + } + }, + _ => () + } + + // Step 5: cloning steps. + + // Step 6. + match clone_children { + CloneChildren => clone_recursively(node, &mut copy, &document), + DoNotCloneChildren => () + } + + // Step 7. + 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>> { @@ -1422,14 +1557,36 @@ impl Node { } // http://dom.spec.whatwg.org/#dom-node-normalize - pub fn Normalize(&mut self) { - // FIXME (#1823) implement. + pub fn Normalize(&mut self, abstract_self: &mut JS<Node>) { + let mut prev_text = None; + for mut child in self.children() { + if child.is_text() { + let characterdata: JS<CharacterData> = CharacterDataCast::to(&child); + if characterdata.get().Length() == 0 { + abstract_self.remove_child(&mut child); + } else { + match prev_text { + Some(ref text_node) => { + let mut prev_characterdata: JS<CharacterData> = CharacterDataCast::to(text_node); + let _ = prev_characterdata.get_mut().AppendData(characterdata.get().Data()); + abstract_self.remove_child(&mut child); + }, + None => prev_text = Some(child) + } + } + } else { + prev_text = None; + } + + } } // http://dom.spec.whatwg.org/#dom-node-clonenode - pub fn CloneNode(&self, _deep: bool) -> Fallible<JS<Node>> { - // FIXME: stub - https://github.com/mozilla/servo/issues/1240 - fail!("stub") + pub fn CloneNode(&self, abstract_self: &mut JS<Node>, deep: bool) -> JS<Node> { + match deep { + true => Node::clone(abstract_self, None, CloneChildren), + false => Node::clone(abstract_self, None, DoNotCloneChildren) + } } // http://dom.spec.whatwg.org/#dom-node-isequalnode @@ -1507,9 +1664,57 @@ impl Node { } // http://dom.spec.whatwg.org/#dom-node-comparedocumentposition - pub fn CompareDocumentPosition(&self, _other: &JS<Node>) -> u16 { - // FIXME (#1794) implement. - 0 + pub fn CompareDocumentPosition(&self, abstract_self: &JS<Node>, other: &JS<Node>) -> u16 { + if abstract_self == other { + // step 2. + 0 + } else { + let mut lastself = abstract_self.clone(); + let mut lastother = other.clone(); + for ancestor in abstract_self.ancestors() { + if &ancestor == other { + // step 4. + return NodeConstants::DOCUMENT_POSITION_CONTAINS + + NodeConstants::DOCUMENT_POSITION_PRECEDING; + } + lastself = ancestor; + } + for ancestor in other.ancestors() { + if &ancestor == abstract_self { + // step 5. + return NodeConstants::DOCUMENT_POSITION_CONTAINED_BY + + NodeConstants::DOCUMENT_POSITION_FOLLOWING; + } + lastother = ancestor; + } + + if lastself != lastother { + let abstract_uint: uintptr_t = as_uintptr(&abstract_self.get()); + let other_uint: uintptr_t = as_uintptr(&other.get()); + + let random = if abstract_uint < other_uint { + NodeConstants::DOCUMENT_POSITION_FOLLOWING + } else { + NodeConstants::DOCUMENT_POSITION_PRECEDING + }; + // step 3. + return random + + NodeConstants::DOCUMENT_POSITION_DISCONNECTED + + NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC; + } + + for child in lastself.traverse_preorder() { + if &child == other { + // step 6. + return NodeConstants::DOCUMENT_POSITION_PRECEDING; + } + if &child == abstract_self { + // step 7. + return NodeConstants::DOCUMENT_POSITION_FOLLOWING; + } + } + unreachable!() + } } // http://dom.spec.whatwg.org/#dom-node-contains @@ -1558,31 +1763,31 @@ impl Node { // pub fn set_parent_node(&mut self, new_parent_node: Option<JS<Node>>) { - let doc = self.owner_doc(); + 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(); + 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(); + 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(); + 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(); + let doc = self.owner_doc().clone(); doc.get().wait_until_safe_to_modify_dom(); self.next_sibling = new_next_sibling } @@ -1619,6 +1824,11 @@ impl Node { 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 { + let unsafe_this: *Node = cast::transmute::<&Node,*Node>(self); + (*unsafe_this).flags.get_in_hover_state() + } } impl Reflectable for Node { |