diff options
Diffstat (limited to 'src/components/script/dom/node.rs')
-rw-r--r-- | src/components/script/dom/node.rs | 332 |
1 files changed, 2 insertions, 330 deletions
diff --git a/src/components/script/dom/node.rs b/src/components/script/dom/node.rs index cbc7595b609..2d4e15ef8c8 100644 --- a/src/components/script/dom/node.rs +++ b/src/components/script/dom/node.rs @@ -14,14 +14,12 @@ use dom::documenttype::DocumentType; use dom::element::{Element, ElementTypeId, HTMLImageElementTypeId, HTMLIframeElementTypeId}; use dom::element::{HTMLAnchorElementTypeId, HTMLStyleElementTypeId}; use dom::eventtarget::{AbstractEventTarget, EventTarget, NodeTypeId}; -use dom::nodelist::{NodeList}; -use dom::htmlimageelement::HTMLImageElement; use dom::htmliframeelement::HTMLIFrameElement; +use dom::htmlimageelement::HTMLImageElement; +use dom::nodelist::{NodeList}; use dom::text::Text; -use extra::url::Url; use js::jsapi::{JSObject, JSContext}; -use servo_msg::constellation_msg::{PipelineId, SubpageId}; use servo_util::slot::{MutSlotRef, Slot, SlotRef}; use std::cast::transmute; use std::cast; @@ -30,198 +28,6 @@ use std::util; use style::TNode; // -// Layout's immutable, sanitized view of nodes. -// - -/// A nonsense constant for layout nodes to point to just to establish a lifetime. -/// -/// FIXME(pcwalton): Phantom lifetimes in Rust would be useful... -static HEAVY_IRON_BALL: () = (); - -/// A wrapper so that layout can access only the methods that it should have access to. Layout must -/// only ever see these and must never see instances of `AbstractNode`. -#[deriving(Clone, Eq)] -pub struct LayoutNode<'self> { - /// The wrapped node. - priv node: AbstractNode, - - /// Being chained to a `HEAVY_IRON_BALL` prevents `LayoutNode`s from escaping. - priv chain: &'self (), -} - -impl<'self> LayoutNode<'self> { - /// NB: Do not make this public. - /// - /// FIXME(pcwalton): Probably this should be marked `unsafe`. - /*PRIVATE-FOR-SECURITY-REASONS*/ fn new(node: AbstractNode) -> LayoutNode<'static> { - LayoutNode { - node: node, - chain: &HEAVY_IRON_BALL, - } - } - - /// Returns the interior of this node as a `Node`. This is highly unsafe for layout to call - /// and as such is marked `unsafe`. - pub unsafe fn get<'a>(&'a self) -> &'a Node<LayoutView> { - cast::transmute(self.node.node()) - } - - /// Returns the first child of this node. - pub fn first_child(&self) -> Option<LayoutNode<'self>> { - self.node.first_child().map(|node| LayoutNode::new(node)) - } - - /// Returns the first child of this node. - pub fn last_child(&self) -> Option<LayoutNode<'self>> { - self.node.last_child().map(|node| LayoutNode::new(node)) - } - - /// Iterates over this node and all its descendants, in preorder. - /// - /// FIXME(pcwalton): Terribly inefficient. We should use parallelism. - pub fn traverse_preorder(&self) -> LayoutTreeIterator<'self> { - let mut nodes = ~[]; - gather_layout_nodes(self, &mut nodes, false); - LayoutTreeIterator::new(nodes) - } - - /// Returns an iterator over this node's children. - pub fn children(&self) -> LayoutNodeChildrenIterator<'self> { - LayoutNodeChildrenIterator { - current_node: self.first_child(), - } - } - - /// Returns the type ID of this node. Fails if this node is borrowed mutably. - pub fn type_id(&self) -> NodeTypeId { - self.node.type_id() - } - - /// If this is an image element, returns its URL. If this is not an image element, fails. - /// - /// FIXME(pcwalton): Don't copy URLs. - pub fn image_url(&self) -> Option<Url> { - self.with_image_element(|image_element| { - image_element.image.as_ref().map(|url| (*url).clone()) - }) - } - - /// Downcasts this node to an image element and calls the given closure. - /// - /// NB: Do not make this public, as layout will be able to do unsafe things with `AbstractNode` - /// otherwise. - /// - /// FIXME(pcwalton): RAII. - /*PRIVATE-FOR-SECURITY-REASONS*/ fn with_image_element<R>( - self, - f: &fn(&HTMLImageElement) -> R) - -> R { - if !self.node.is_image_element() { - fail!(~"node is not an image element"); - } - self.node.transmute(f) - } - - /// If this node is an iframe element, returns its pipeline and subpage IDs. If this node is - /// not an iframe element, fails. - pub fn iframe_pipeline_and_subpage_ids(&self) -> (PipelineId, SubpageId) { - self.with_iframe_element(|iframe_element| { - let size = iframe_element.size.unwrap(); - (size.pipeline_id, size.subpage_id) - }) - } - - /// Downcasts this node to an iframe element and calls the given closure. - /// - /// NB: Do not make this public, as layout will be able to do unsafe things with `AbstractNode` - /// otherwise. - /// - /// FIXME(pcwalton): RAII. - /*PRIVATE-FOR-SECURITY-REASONS*/ fn with_iframe_element<R>( - self, - f: &fn(&HTMLIFrameElement) -> R) - -> R { - if !self.node.is_iframe_element() { - fail!(~"node is not an iframe element"); - } - self.node.transmute(f) - } - - /// Returns true if this node is a text node or false otherwise. - #[inline] - pub fn is_text(self) -> bool { - self.node.is_text() - } - - /// Returns true if this node consists entirely of ignorable whitespace and false otherwise. - /// Ignorable whitespace is defined as whitespace that would be removed per CSS 2.1 § 16.6.1. - pub fn is_ignorable_whitespace(&self) -> bool { - self.is_text() && self.with_text(|text| text.element.data.is_whitespace()) - } - - /// If this is a text node, copies out the text. If this is not a text node, fails. - /// - /// FIXME(pcwalton): Don't copy text. Atomically reference count instead. - pub fn text(&self) -> ~str { - self.with_text(|text| text.element.data.to_str()) - } - - /// Downcasts this node to a text node and calls the given closure. - /// - /// NB: Do not make this public, as layout will be able to do unsafe things with `AbstractNode` - /// otherwise. - /// - /// FIXME(pcwalton): RAII. - /*PRIVATE-FOR-SECURITY-REASONS*/ fn with_text<R>(self, f: &fn(&Text) -> R) -> R { - self.node.with_imm_text(f) - } - - /// Dumps this node tree, for debugging. - pub fn dump(&self) { - self.node.dump() - } - - /// Returns a string that describes this node, for debugging. - pub fn debug_str(&self) -> ~str { - self.node.debug_str() - } -} - -impl<'self> TNode<Element> for LayoutNode<'self> { - fn parent_node(&self) -> Option<LayoutNode<'self>> { - self.node.node().parent_node.map(|node| LayoutNode::new(node)) - } - - fn prev_sibling(&self) -> Option<LayoutNode<'self>> { - self.node.node().prev_sibling.map(|node| LayoutNode::new(node)) - } - - fn next_sibling(&self) -> Option<LayoutNode<'self>> { - self.node.node().next_sibling.map(|node| LayoutNode::new(node)) - } - - fn is_element(&self) -> bool { - match self.node.type_id() { - ElementNodeTypeId(*) => true, - _ => false - } - } - - fn is_document(&self) -> bool { - match self.node.type_id() { - DocumentNodeTypeId(*) => true, - _ => false - } - } - - /// FIXME(pcwalton): Unsafe! - #[inline] - fn with_element<R>(&self, f: &fn(&Element) -> R) -> R { - self.node.with_imm_element(f) - } -} - -// // The basic Node structure // @@ -851,20 +657,6 @@ impl Iterator<AbstractNode> for AbstractNodeChildrenIterator { } } -pub struct LayoutNodeChildrenIterator<'self> { - priv current_node: Option<LayoutNode<'self>>, -} - -impl<'self> Iterator<LayoutNode<'self>> for LayoutNodeChildrenIterator<'self> { - fn next(&mut self) -> Option<LayoutNode<'self>> { - let node = self.current_node; - self.current_node = do self.current_node.and_then |node| { - node.next_sibling() - }; - node - } -} - pub struct AncestorIterator { priv current: Option<AbstractNode>, } @@ -922,49 +714,6 @@ fn gather_abstract_nodes(cur: &AbstractNode, refs: &mut ~[AbstractNode], postord } } -// FIXME: Do this without precomputing a vector of refs. -// Easy for preorder; harder for postorder. -// -// FIXME(pcwalton): Parallelism! Eventually this should just be nuked. -pub struct LayoutTreeIterator<'self> { - priv nodes: ~[LayoutNode<'self>], - priv index: uint, -} - -impl<'self> LayoutTreeIterator<'self> { - fn new(nodes: ~[LayoutNode<'self>]) -> LayoutTreeIterator<'self> { - LayoutTreeIterator { - nodes: nodes, - index: 0, - } - } -} - -impl<'self> Iterator<LayoutNode<'self>> for LayoutTreeIterator<'self> { - fn next(&mut self) -> Option<LayoutNode<'self>> { - if self.index >= self.nodes.len() { - None - } else { - let v = self.nodes[self.index].clone(); - self.index += 1; - Some(v) - } - } -} - -/// FIXME(pcwalton): This is super inefficient. -fn gather_layout_nodes<'a>(cur: &LayoutNode<'a>, refs: &mut ~[LayoutNode<'a>], postorder: bool) { - if !postorder { - refs.push(cur.clone()); - } - for kid in cur.children() { - gather_layout_nodes(&kid, refs, postorder) - } - if postorder { - refs.push(cur.clone()); - } -} - impl AbstractNode { /// Iterates over all ancestors of this node. pub fn ancestors(&self) -> AncestorIterator { @@ -1629,80 +1378,3 @@ impl Reflectable for Node<ScriptView> { } } -/// A bottom-up, parallelizable traversal. -pub trait PostorderNodeTraversal { - /// The operation to perform. Return true to continue or false to stop. - fn process<'a>(&'a self, node: LayoutNode<'a>) -> bool; - - /// 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<'a>(&'a self, _node: LayoutNode<'a>) -> bool { - false - } -} - -/// A bottom-up, parallelizable traversal. -pub trait PostorderNodeMutTraversal { - /// The operation to perform. Return true to continue or false to stop. - fn process<'a>(&'a mut self, node: LayoutNode<'a>) -> bool; - - /// 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<'a>(&'a self, _node: LayoutNode<'a>) -> bool { - false - } -} - -impl<'self> LayoutNode<'self> { - /// Traverses the tree in postorder. - /// - /// TODO(pcwalton): Offer a parallel version with a compatible API. - pub fn traverse_postorder<T:PostorderNodeTraversal>(self, traversal: &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() - } - } - } - - traversal.process(self) - } - - /// Traverses the tree in postorder. - /// - /// TODO(pcwalton): Offer a parallel version with a compatible API. - pub fn traverse_postorder_mut<T:PostorderNodeMutTraversal>(mut 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_mut(traversal) { - return false - } - opt_kid = kid.next_sibling() - } - } - } - - traversal.process(self) - } - -} |