aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/script/dom/node.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/script/dom/node.rs')
-rw-r--r--src/components/script/dom/node.rs294
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(&copy);
+ }
+ 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(&copy);
+ 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(&copy);
+ 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 {