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.rs207
1 files changed, 110 insertions, 97 deletions
diff --git a/src/components/script/dom/node.rs b/src/components/script/dom/node.rs
index a6cf77d0c19..78533b2b48c 100644
--- a/src/components/script/dom/node.rs
+++ b/src/components/script/dom/node.rs
@@ -21,12 +21,8 @@ use dom::text::Text;
use std::cast;
use std::cast::transmute;
use std::unstable::raw::Box;
-use extra::arc::Arc;
use js::jsapi::{JSObject, JSContext};
-use style::{ComputedValues, PropertyDeclaration};
use servo_util::tree::{TreeNode, TreeNodeRef, TreeNodeRefAsElement};
-use servo_util::range::Range;
-use gfx::display_list::DisplayList;
//
// The basic Node structure
@@ -93,7 +89,7 @@ pub struct Node<View> {
child_list: Option<@mut NodeList>,
/// Layout information. Only the layout task may touch this data.
- priv layout_data: LayoutData,
+ layout_data: Option<~Any>,
}
/// The different types of nodes.
@@ -445,9 +441,7 @@ impl<'self, View> AbstractNode<View> {
}
pub fn children(&self) -> AbstractNodeChildrenIterator<View> {
- AbstractNodeChildrenIterator {
- current_node: self.first_child(),
- }
+ self.node().children()
}
// Issue #1030: should not walk the tree
@@ -502,6 +496,12 @@ impl<View> Node<View> {
pub fn set_owner_doc(&mut self, document: AbstractDocument) {
self.owner_doc = Some(document);
}
+
+ pub fn children(&self) -> AbstractNodeChildrenIterator<View> {
+ AbstractNodeChildrenIterator {
+ current_node: self.first_child,
+ }
+ }
}
impl Node<ScriptView> {
@@ -543,7 +543,7 @@ impl Node<ScriptView> {
owner_doc: doc,
child_list: None,
- layout_data: LayoutData::new(),
+ layout_data: None,
}
}
}
@@ -562,10 +562,10 @@ impl Node<ScriptView> {
}
pub fn NodeName(&self, abstract_self: AbstractNode<ScriptView>) -> DOMString {
- Some(match self.type_id {
+ match self.type_id {
ElementNodeTypeId(*) => {
do abstract_self.with_imm_element |element| {
- element.TagName().expect("tagName should never be null")
+ element.TagName()
}
}
CommentNodeTypeId => ~"#comment",
@@ -577,10 +577,10 @@ impl Node<ScriptView> {
},
DocumentFragmentNodeTypeId => ~"#document-fragment",
DocumentNodeTypeId(_) => ~"#document"
- })
+ }
}
- pub fn GetBaseURI(&self) -> DOMString {
+ pub fn GetBaseURI(&self) -> Option<DOMString> {
None
}
@@ -623,12 +623,12 @@ impl Node<ScriptView> {
self.next_sibling
}
- pub fn GetNodeValue(&self, abstract_self: AbstractNode<ScriptView>) -> DOMString {
+ pub fn GetNodeValue(&self, abstract_self: AbstractNode<ScriptView>) -> Option<DOMString> {
match self.type_id {
// ProcessingInstruction
CommentNodeTypeId | TextNodeTypeId => {
do abstract_self.with_imm_characterdata() |characterdata| {
- characterdata.Data()
+ Some(characterdata.Data())
}
}
_ => {
@@ -637,19 +637,18 @@ impl Node<ScriptView> {
}
}
- pub fn SetNodeValue(&mut self, _abstract_self: AbstractNode<ScriptView>, _val: &DOMString) -> ErrorResult {
+ pub fn SetNodeValue(&mut self, _abstract_self: AbstractNode<ScriptView>, _val: Option<DOMString>) -> ErrorResult {
Ok(())
}
- pub fn GetTextContent(&self, abstract_self: AbstractNode<ScriptView>) -> DOMString {
+ pub fn GetTextContent(&self, abstract_self: AbstractNode<ScriptView>) -> Option<DOMString> {
match self.type_id {
DocumentFragmentNodeTypeId | ElementNodeTypeId(*) => {
let mut content = ~"";
for node in abstract_self.traverse_preorder() {
if node.is_text() {
do node.with_imm_text() |text| {
- let s = text.element.Data();
- content = content + null_str_as_empty(&s);
+ content = content + text.element.Data();
}
}
}
@@ -657,7 +656,7 @@ impl Node<ScriptView> {
}
CommentNodeTypeId | TextNodeTypeId => {
do abstract_self.with_imm_characterdata() |characterdata| {
- characterdata.Data()
+ Some(characterdata.Data())
}
}
DoctypeNodeTypeId | DocumentNodeTypeId(_) => {
@@ -875,6 +874,15 @@ impl Node<ScriptView> {
// Step 5: DocumentFragment, mutation records.
// Step 6: DocumentFragment.
+ match node.type_id() {
+ DocumentFragmentNodeTypeId => {
+ for c in node.children() {
+ Node::remove(c, node, true);
+ }
+ },
+ _ => (),
+ }
+
// Step 7: mutation records.
// Step 8.
for node in nodes.iter() {
@@ -890,18 +898,45 @@ impl Node<ScriptView> {
}
// http://dom.spec.whatwg.org/#concept-node-replace-all
- pub fn replace_all(&mut self,
- abstract_self: AbstractNode<ScriptView>,
- node: Option<AbstractNode<ScriptView>>) {
- //FIXME: We should batch document notifications that occur here
- for child in abstract_self.children() {
- self.RemoveChild(abstract_self, child);
+ pub fn replace_all(node: Option<AbstractNode<ScriptView>>,
+ parent: AbstractNode<ScriptView>) {
+ // Step 1.
+ match node {
+ Some(node) => Node::adopt(node, parent.node().owner_doc()),
+ None => (),
}
+
+ // Step 2.
+ let removedNodes: ~[AbstractNode<ScriptView>] = parent.children().collect();
+
+ // Step 3.
+ let addedNodes = match node {
+ None => ~[],
+ Some(node) => match node.type_id() {
+ DocumentFragmentNodeTypeId => node.children().collect(),
+ _ => ~[node],
+ },
+ };
+
+ // Step 4.
+ for child in parent.children() {
+ Node::remove(child, parent, true);
+ }
+
+ // Step 5.
match node {
- None => {},
- Some(node) => {
- self.AppendChild(abstract_self, node);
- }
+ Some(node) => Node::insert(node, parent, None, true),
+ None => (),
+ }
+
+ // Step 6: mutation records.
+
+ // Step 7.
+ for removedNode in removedNodes.iter() {
+ removedNode.node_removed();
+ }
+ for addedNode in addedNodes.iter() {
+ addedNode.node_inserted();
}
}
@@ -939,26 +974,25 @@ impl Node<ScriptView> {
pub fn SetTextContent(&mut self,
abstract_self: AbstractNode<ScriptView>,
- value: &DOMString) -> ErrorResult {
- let is_empty = match value {
- &Some(~"") | &None => true,
- _ => false
- };
+ value: Option<DOMString>) -> ErrorResult {
+ self.wait_until_safe_to_modify_dom();
+
+ let value = null_str_as_empty(&value);
match self.type_id {
DocumentFragmentNodeTypeId | ElementNodeTypeId(*) => {
- let node = if is_empty {
+ // Step 1-2.
+ let node = if value.len() == 0 {
None
} else {
let document = self.owner_doc();
Some(document.document().CreateTextNode(document, value))
};
- self.replace_all(abstract_self, node);
+ // Step 3.
+ Node::replace_all(node, abstract_self);
}
CommentNodeTypeId | TextNodeTypeId => {
- self.wait_until_safe_to_modify_dom();
-
do abstract_self.with_mut_characterdata() |characterdata| {
- characterdata.data = null_str_as_empty(value);
+ characterdata.data = value.clone();
// Notify the document that the content of this node is different
let document = self.owner_doc();
@@ -1019,27 +1053,27 @@ impl Node<ScriptView> {
false
}
- pub fn LookupPrefix(&self, _prefix: &DOMString) -> DOMString {
+ pub fn LookupPrefix(&self, _prefix: Option<DOMString>) -> Option<DOMString> {
None
}
- pub fn LookupNamespaceURI(&self, _namespace: &DOMString) -> DOMString {
+ pub fn LookupNamespaceURI(&self, _namespace: Option<DOMString>) -> Option<DOMString> {
None
}
- pub fn IsDefaultNamespace(&self, _namespace: &DOMString) -> bool {
+ pub fn IsDefaultNamespace(&self, _namespace: Option<DOMString>) -> bool {
false
}
- pub fn GetNamespaceURI(&self) -> DOMString {
+ pub fn GetNamespaceURI(&self) -> Option<DOMString> {
None
}
- pub fn GetPrefix(&self) -> DOMString {
+ pub fn GetPrefix(&self) -> Option<DOMString> {
None
}
- pub fn GetLocalName(&self) -> DOMString {
+ pub fn GetLocalName(&self) -> Option<DOMString> {
None
}
@@ -1058,62 +1092,41 @@ impl Reflectable for Node<ScriptView> {
}
}
-// This stuff is notionally private to layout, but we put it here because it needs
-// to be stored in a Node, and we can't have cross-crate cyclic dependencies.
-
-pub struct DisplayBoxes {
- display_list: Option<Arc<DisplayList<AbstractNode<()>>>>,
- range: Option<Range>,
-}
-
-/// Data that layout associates with a node.
-pub struct LayoutData {
- /// The results of CSS matching for this node.
- applicable_declarations: ~[Arc<~[PropertyDeclaration]>],
-
- /// The results of CSS styling for this node.
- style: Option<ComputedValues>,
+/// A bottom-up, parallelizable traversal.
+pub trait PostorderNodeTraversal {
+ /// The operation to perform. Return true to continue or false to stop.
+ fn process(&mut self, node: AbstractNode<LayoutView>) -> bool;
- /// Description of how to account for recent style changes.
- restyle_damage: Option<int>,
-
- /// The boxes assosiated with this flow.
- /// Used for getBoundingClientRect and friends.
- boxes: DisplayBoxes,
-}
-
-impl LayoutData {
- /// Creates new layout data.
- pub fn new() -> LayoutData {
- LayoutData {
- applicable_declarations: ~[],
- style: None,
- restyle_damage: None,
- boxes: DisplayBoxes {
- display_list: None,
- range: None,
- },
- }
+ /// Returns true if this node should be pruned. If this returns true, we skip the operation
+ /// entirely and do not process any descendant nodes. This is called *before* child nodes are
+ /// visited. The default implementation never prunes any nodes.
+ fn should_prune(&mut self, _node: AbstractNode<LayoutView>) -> bool {
+ false
}
}
-// This serves as a static assertion that layout data remains sendable. If this is not done, then
-// we can have memory unsafety, which usually manifests as shutdown crashes.
-fn assert_is_sendable<T:Send>(_: T) {}
-fn assert_layout_data_is_sendable() {
- assert_is_sendable(LayoutData::new())
-}
-
impl AbstractNode<LayoutView> {
- // These accessors take a continuation rather than returning a reference, because
- // an AbstractNode doesn't have a lifetime parameter relating to the underlying
- // Node. Also this makes it easier to switch to RWArc if we decide that is
- // necessary.
- pub fn read_layout_data<R>(self, blk: &fn(data: &LayoutData) -> R) -> R {
- blk(&self.node().layout_data)
- }
+ /// Traverses the tree in postorder.
+ ///
+ /// TODO(pcwalton): Offer a parallel version with a compatible API.
+ pub fn traverse_postorder<T:PostorderNodeTraversal>(self, traversal: &mut T) -> bool {
+ if traversal.should_prune(self) {
+ return true
+ }
+
+ let mut opt_kid = self.first_child();
+ loop {
+ match opt_kid {
+ None => break,
+ Some(kid) => {
+ if !kid.traverse_postorder(traversal) {
+ return false
+ }
+ opt_kid = kid.next_sibling()
+ }
+ }
+ }
- pub fn write_layout_data<R>(self, blk: &fn(data: &mut LayoutData) -> R) -> R {
- blk(&mut self.mut_node().layout_data)
+ traversal.process(self)
}
}