mirror of
https://github.com/servo/servo.git
synced 2025-08-05 21:50:18 +01:00
script: Make trees less generic
This commit is contained in:
parent
44a8b0987c
commit
199ca33b72
23 changed files with 382 additions and 523 deletions
|
@ -15,9 +15,7 @@ use layout::incremental;
|
|||
use layout::util::LayoutDataAccess;
|
||||
|
||||
use script::dom::node::{AbstractNode, LayoutView};
|
||||
use style::Stylist;
|
||||
use style::cascade;
|
||||
use servo_util::tree::TreeNodeRef;
|
||||
use style::{TNode, Stylist, cascade};
|
||||
|
||||
pub trait MatchMethods {
|
||||
fn match_node(&self, stylist: &Stylist);
|
||||
|
|
|
@ -7,9 +7,8 @@ use layout::util::LayoutDataAccess;
|
|||
|
||||
use extra::arc::Arc;
|
||||
use std::cast;
|
||||
use style::ComputedValues;
|
||||
use style::{ComputedValues, TNode};
|
||||
use script::dom::node::{AbstractNode, LayoutView};
|
||||
use servo_util::tree::TreeNodeRef;
|
||||
|
||||
pub trait NodeUtil {
|
||||
fn get_css_select_results<'a>(&'a self) -> &'a Arc<ComputedValues>;
|
||||
|
|
|
@ -23,12 +23,11 @@ use servo_util::geometry::Au;
|
|||
use servo_util::geometry;
|
||||
use servo_util::range::*;
|
||||
use servo_util::slot::Slot;
|
||||
use servo_util::tree::{TreeNodeRef, ElementLike};
|
||||
use std::cast;
|
||||
use std::cell::Cell;
|
||||
use std::cmp::ApproxEq;
|
||||
use std::num::Zero;
|
||||
use style::ComputedValues;
|
||||
use style::{ComputedValues, TElement, TNode};
|
||||
use style::computed_values::{LengthOrPercentage, overflow};
|
||||
use style::computed_values::{border_style, clear, font_family, font_style, line_height};
|
||||
use style::computed_values::{text_align, text_decoration, vertical_align, visibility};
|
||||
|
|
|
@ -36,7 +36,6 @@ use script::dom::node::{AbstractNode, CommentNodeTypeId, DoctypeNodeTypeId};
|
|||
use script::dom::node::{DocumentFragmentNodeTypeId, DocumentNodeTypeId, ElementNodeTypeId};
|
||||
use script::dom::node::{LayoutView, PostorderNodeMutTraversal, TextNodeTypeId};
|
||||
use servo_util::slot::Slot;
|
||||
use servo_util::tree::TreeNodeRef;
|
||||
use std::util;
|
||||
use style::computed_values::{display, float};
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
use layout::util::{LayoutData, LayoutDataAccess};
|
||||
|
||||
use script::dom::node::{AbstractNode, LayoutView};
|
||||
use servo_util::tree::TreeNodeRef;
|
||||
|
||||
/// Functionality useful for querying the layout-specific data on DOM nodes.
|
||||
pub trait LayoutAuxMethods {
|
||||
|
|
|
@ -22,8 +22,7 @@ use servo_util::range::Range;
|
|||
use std::cell::Cell;
|
||||
use std::u16;
|
||||
use std::util;
|
||||
use style::computed_values::text_align;
|
||||
use style::computed_values::vertical_align;
|
||||
use style::computed_values::{text_align, vertical_align};
|
||||
|
||||
/// Lineboxes are represented as offsets into the child list, rather than
|
||||
/// as an object that "owns" boxes. Choosing a different set of line
|
||||
|
|
|
@ -43,16 +43,13 @@ use servo_net::local_image_cache::{ImageResponder, LocalImageCache};
|
|||
use servo_util::geometry::Au;
|
||||
use servo_util::time::{ProfilerChan, profile};
|
||||
use servo_util::time;
|
||||
use servo_util::tree::TreeNodeRef;
|
||||
use std::cast::transmute;
|
||||
use std::cast;
|
||||
use std::cell::Cell;
|
||||
use std::comm::Port;
|
||||
use std::task;
|
||||
use std::util;
|
||||
use style::AuthorOrigin;
|
||||
use style::Stylesheet;
|
||||
use style::Stylist;
|
||||
use style::{AuthorOrigin, Stylesheet, Stylist};
|
||||
|
||||
/// Information needed by the layout task.
|
||||
struct LayoutTask {
|
||||
|
|
|
@ -9,7 +9,6 @@ use extra::arc::Arc;
|
|||
use script::dom::node::{AbstractNode, LayoutView};
|
||||
use servo_util::range::Range;
|
||||
use servo_util::slot::{MutSlotRef, SlotRef};
|
||||
use servo_util::tree::TreeNodeRef;
|
||||
use std::cast;
|
||||
use std::iter::Enumerate;
|
||||
use std::libc::uintptr_t;
|
||||
|
|
|
@ -10,7 +10,6 @@ use std::cast;
|
|||
use std::libc;
|
||||
use std::ptr;
|
||||
use js::jsapi::{JSTracer, JSTRACE_OBJECT, JS_CallTracer};
|
||||
use servo_util::tree::TreeNodeRef;
|
||||
|
||||
impl Reflectable for AbstractNode<ScriptView> {
|
||||
fn reflector<'a>(&'a self) -> &'a Reflector {
|
||||
|
|
|
@ -21,16 +21,15 @@ use dom::uievent::UIEvent;
|
|||
use dom::window::Window;
|
||||
use dom::htmltitleelement::HTMLTitleElement;
|
||||
use html::hubbub_html_parser::build_element_from_tag;
|
||||
use js::jsapi::{JSObject, JSContext, JSTracer};
|
||||
use servo_util::tree::{TreeNodeRef, ElementLike};
|
||||
use layout_interface::{DocumentDamageLevel, ContentChangedDocumentDamage};
|
||||
|
||||
use std::hashmap::HashMap;
|
||||
|
||||
use std::cast;
|
||||
use std::str::eq_slice;
|
||||
use js::jsapi::{JSObject, JSContext, JSTracer};
|
||||
use std::ascii::StrAsciiExt;
|
||||
use std::cast;
|
||||
use std::hashmap::HashMap;
|
||||
use std::str::eq_slice;
|
||||
use std::unstable::raw::Box;
|
||||
use style::{TElement, TNode};
|
||||
|
||||
#[deriving(Eq)]
|
||||
pub enum DocumentTypeId {
|
||||
|
|
|
@ -20,8 +20,8 @@ use dom::namespace::Namespace;
|
|||
use layout_interface::{ContentBoxQuery, ContentBoxResponse, ContentBoxesQuery};
|
||||
use layout_interface::{ContentBoxesResponse, ContentChangedDocumentDamage};
|
||||
use layout_interface::{MatchSelectorsDocumentDamage};
|
||||
use style::{TElement, TNode};
|
||||
use style;
|
||||
use servo_util::tree::{TreeNodeRef, ElementLike};
|
||||
|
||||
use std::comm;
|
||||
use std::hashmap::HashMap;
|
||||
|
@ -125,7 +125,7 @@ pub enum ElementTypeId {
|
|||
// Element methods
|
||||
//
|
||||
|
||||
impl ElementLike for Element {
|
||||
impl TElement for Element {
|
||||
fn get_local_name<'a>(&'a self) -> &'a str {
|
||||
self.tag_name.as_slice()
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ use dom::bindings::callback::eReportExceptions;
|
|||
use dom::eventtarget::{AbstractEventTarget, Capturing, Bubbling};
|
||||
use dom::event::{AbstractEvent, Phase_At_Target, Phase_None, Phase_Bubbling, Phase_Capturing};
|
||||
use dom::node::AbstractNode;
|
||||
use servo_util::tree::{TreeNodeRef};
|
||||
|
||||
// See http://dom.spec.whatwg.org/#concept-event-dispatch for the full dispatch algorithm
|
||||
pub fn dispatch_event(target: AbstractEventTarget,
|
||||
|
|
|
@ -11,10 +11,8 @@ use dom::node::{AbstractNode, ScriptView, ElementNodeTypeId};
|
|||
use dom::window::Window;
|
||||
|
||||
use js::jsapi::JSTracer;
|
||||
|
||||
use servo_util::tree::{TreeNodeRef, ElementLike};
|
||||
|
||||
use std::str::eq_slice;
|
||||
use style::TElement;
|
||||
|
||||
pub struct HTMLDocument {
|
||||
parent: Document
|
||||
|
|
|
@ -14,7 +14,7 @@ use layout_interface::{ContentBoxQuery, ContentBoxResponse};
|
|||
use servo_net::image_cache_task;
|
||||
use servo_net::image_cache_task::ImageCacheTask;
|
||||
use servo_util::url::make_url;
|
||||
use servo_util::tree::ElementLike;
|
||||
use style::TElement;
|
||||
|
||||
pub struct HTMLImageElement {
|
||||
htmlelement: HTMLElement,
|
||||
|
|
|
@ -8,7 +8,7 @@ use dom::document::AbstractDocument;
|
|||
use dom::element::HTMLScriptElementTypeId;
|
||||
use dom::htmlelement::HTMLElement;
|
||||
use dom::node::{AbstractNode, Node, ScriptView};
|
||||
use servo_util::tree::ElementLike;
|
||||
use style::TElement;
|
||||
|
||||
pub struct HTMLScriptElement {
|
||||
htmlelement: HTMLElement,
|
||||
|
|
|
@ -21,11 +21,11 @@ use dom::text::Text;
|
|||
|
||||
use js::jsapi::{JSObject, JSContext};
|
||||
use servo_util::slot::{MutSlotRef, Slot, SlotRef};
|
||||
use servo_util::tree::{TreeNode, TreeNodeRef, TreeNodeRefAsElement};
|
||||
use std::cast::transmute;
|
||||
use std::cast;
|
||||
use std::unstable::raw::Box;
|
||||
use std::util;
|
||||
use style::TNode;
|
||||
|
||||
//
|
||||
// The basic Node structure
|
||||
|
@ -210,59 +210,17 @@ impl<View> Clone for AbstractNode<View> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<View> TreeNodeRef<Node<View>> for AbstractNode<View> {
|
||||
fn node<'a>(&'a self) -> &'a Node<View> {
|
||||
unsafe {
|
||||
&(*self.obj).data
|
||||
}
|
||||
impl<View> TNode<Element> for AbstractNode<View> {
|
||||
fn parent_node(&self) -> Option<AbstractNode<View>> {
|
||||
self.node().parent_node
|
||||
}
|
||||
|
||||
fn mut_node<'a>(&'a self) -> &'a mut Node<View> {
|
||||
unsafe {
|
||||
&mut (*self.obj).data
|
||||
}
|
||||
fn prev_sibling(&self) -> Option<AbstractNode<View>> {
|
||||
self.node().prev_sibling
|
||||
}
|
||||
|
||||
fn parent_node(node: &Node<View>) -> Option<AbstractNode<View>> {
|
||||
node.parent_node
|
||||
}
|
||||
fn first_child(node: &Node<View>) -> Option<AbstractNode<View>> {
|
||||
node.first_child
|
||||
}
|
||||
fn last_child(node: &Node<View>) -> Option<AbstractNode<View>> {
|
||||
node.last_child
|
||||
}
|
||||
fn prev_sibling(node: &Node<View>) -> Option<AbstractNode<View>> {
|
||||
node.prev_sibling
|
||||
}
|
||||
fn next_sibling(node: &Node<View>) -> Option<AbstractNode<View>> {
|
||||
node.next_sibling
|
||||
}
|
||||
|
||||
fn set_parent_node(node: &mut Node<View>, new_parent_node: Option<AbstractNode<View>>) {
|
||||
let doc = node.owner_doc();
|
||||
doc.document().wait_until_safe_to_modify_dom();
|
||||
node.parent_node = new_parent_node
|
||||
}
|
||||
fn set_first_child(node: &mut Node<View>, new_first_child: Option<AbstractNode<View>>) {
|
||||
let doc = node.owner_doc();
|
||||
doc.document().wait_until_safe_to_modify_dom();
|
||||
node.first_child = new_first_child
|
||||
}
|
||||
fn set_last_child(node: &mut Node<View>, new_last_child: Option<AbstractNode<View>>) {
|
||||
let doc = node.owner_doc();
|
||||
doc.document().wait_until_safe_to_modify_dom();
|
||||
node.last_child = new_last_child
|
||||
}
|
||||
fn set_prev_sibling(node: &mut Node<View>, new_prev_sibling: Option<AbstractNode<View>>) {
|
||||
let doc = node.owner_doc();
|
||||
doc.document().wait_until_safe_to_modify_dom();
|
||||
node.prev_sibling = new_prev_sibling
|
||||
}
|
||||
fn set_next_sibling(node: &mut Node<View>, new_next_sibling: Option<AbstractNode<View>>) {
|
||||
let doc = node.owner_doc();
|
||||
doc.document().wait_until_safe_to_modify_dom();
|
||||
node.next_sibling = new_next_sibling
|
||||
fn next_sibling(&self) -> Option<AbstractNode<View>> {
|
||||
self.node().next_sibling
|
||||
}
|
||||
|
||||
fn is_element(&self) -> bool {
|
||||
|
@ -278,17 +236,34 @@ impl<View> TreeNodeRef<Node<View>> for AbstractNode<View> {
|
|||
_ => false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<View> TreeNodeRefAsElement<Node<View>, Element> for AbstractNode<View> {
|
||||
#[inline]
|
||||
fn with_imm_element_like<R>(&self, f: &fn(&Element) -> R) -> R {
|
||||
fn with_element<R>(&self, f: &fn(&Element) -> R) -> R {
|
||||
self.with_imm_element(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<View> AbstractNode<View> {
|
||||
pub fn node<'a>(&'a self) -> &'a Node<View> {
|
||||
unsafe {
|
||||
&(*self.obj).data
|
||||
}
|
||||
}
|
||||
|
||||
impl<View> TreeNode<AbstractNode<View>> for Node<View> { }
|
||||
pub fn mut_node<'a>(&'a self) -> &'a mut Node<View> {
|
||||
unsafe {
|
||||
&mut (*self.obj).data
|
||||
}
|
||||
}
|
||||
|
||||
pub fn first_child(&self) -> Option<AbstractNode<View>> {
|
||||
self.node().first_child
|
||||
}
|
||||
|
||||
pub fn last_child(&self) -> Option<AbstractNode<View>> {
|
||||
self.node().last_child
|
||||
}
|
||||
}
|
||||
|
||||
impl<'self, View> AbstractNode<View> {
|
||||
// Unsafe accessors
|
||||
|
@ -335,21 +310,6 @@ impl<'self, View> AbstractNode<View> {
|
|||
self.node().type_id
|
||||
}
|
||||
|
||||
/// Returns the parent node of this node. Fails if this node is borrowed mutably.
|
||||
pub fn parent_node(self) -> Option<AbstractNode<View>> {
|
||||
self.node().parent_node
|
||||
}
|
||||
|
||||
/// Returns the first child of this node. Fails if this node is borrowed mutably.
|
||||
pub fn first_child(self) -> Option<AbstractNode<View>> {
|
||||
self.node().first_child
|
||||
}
|
||||
|
||||
/// Returns the last child of this node. Fails if this node is borrowed mutably.
|
||||
pub fn last_child(self) -> Option<AbstractNode<View>> {
|
||||
self.node().last_child
|
||||
}
|
||||
|
||||
/// Returns the previous sibling of this node. Fails if this node is borrowed mutably.
|
||||
pub fn prev_sibling(self) -> Option<AbstractNode<View>> {
|
||||
self.node().prev_sibling
|
||||
|
@ -562,6 +522,14 @@ impl<'self, View> AbstractNode<View> {
|
|||
format!("{:?}", self.type_id())
|
||||
}
|
||||
|
||||
//
|
||||
// Convenience accessors
|
||||
//
|
||||
|
||||
fn is_leaf(&self) -> bool {
|
||||
self.first_child().is_none()
|
||||
}
|
||||
|
||||
pub fn children(&self) -> AbstractNodeChildrenIterator<View> {
|
||||
self.node().children()
|
||||
}
|
||||
|
@ -601,8 +569,123 @@ impl AbstractNode<ScriptView> {
|
|||
|
||||
document.document().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(&self,
|
||||
new_child: AbstractNode<ScriptView>,
|
||||
before: Option<AbstractNode<ScriptView>>) {
|
||||
let this_node = self.mut_node();
|
||||
let new_child_node = new_child.mut_node();
|
||||
assert!(new_child_node.parent_node.is_none());
|
||||
assert!(new_child_node.prev_sibling.is_none());
|
||||
assert!(new_child_node.next_sibling.is_none());
|
||||
match before {
|
||||
Some(before) => {
|
||||
let before_node = before.mut_node();
|
||||
// XXX Should assert that parent is self.
|
||||
assert!(before_node.parent_node.is_some());
|
||||
before_node.set_prev_sibling(Some(new_child.clone()));
|
||||
new_child_node.set_next_sibling(Some(before.clone()));
|
||||
match before_node.prev_sibling {
|
||||
None => {
|
||||
// XXX Should assert that before is the first child of
|
||||
// self.
|
||||
this_node.set_first_child(Some(new_child.clone()));
|
||||
},
|
||||
Some(prev_sibling) => {
|
||||
let prev_sibling_node = prev_sibling.mut_node();
|
||||
prev_sibling_node.set_next_sibling(Some(new_child.clone()));
|
||||
new_child_node.set_prev_sibling(Some(prev_sibling.clone()));
|
||||
},
|
||||
}
|
||||
},
|
||||
None => {
|
||||
match this_node.last_child {
|
||||
None => this_node.set_first_child(Some(new_child.clone())),
|
||||
Some(last_child) => {
|
||||
let last_child_node = last_child.mut_node();
|
||||
assert!(last_child_node.next_sibling.is_none());
|
||||
last_child_node.set_next_sibling(Some(new_child.clone()));
|
||||
new_child_node.set_prev_sibling(Some(last_child.clone()));
|
||||
}
|
||||
}
|
||||
|
||||
this_node.set_last_child(Some(new_child.clone()));
|
||||
},
|
||||
}
|
||||
|
||||
new_child_node.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(&self, child: AbstractNode<ScriptView>) {
|
||||
let this_node = self.mut_node();
|
||||
let child_node = child.mut_node();
|
||||
assert!(child_node.parent_node.is_some());
|
||||
|
||||
match child_node.prev_sibling {
|
||||
None => this_node.set_first_child(child_node.next_sibling),
|
||||
Some(prev_sibling) => {
|
||||
let prev_sibling_node = prev_sibling.mut_node();
|
||||
prev_sibling_node.set_next_sibling(child_node.next_sibling);
|
||||
}
|
||||
}
|
||||
|
||||
match child_node.next_sibling {
|
||||
None => this_node.set_last_child(child_node.prev_sibling),
|
||||
Some(next_sibling) => {
|
||||
let next_sibling_node = next_sibling.mut_node();
|
||||
next_sibling_node.set_prev_sibling(child_node.prev_sibling);
|
||||
}
|
||||
}
|
||||
|
||||
child_node.set_prev_sibling(None);
|
||||
child_node.set_next_sibling(None);
|
||||
child_node.set_parent_node(None);
|
||||
}
|
||||
|
||||
//
|
||||
// Low-level pointer stitching wrappers
|
||||
//
|
||||
|
||||
fn set_parent_node(&self, new_parent_node: Option<AbstractNode<ScriptView>>) {
|
||||
let node = self.mut_node();
|
||||
node.set_parent_node(new_parent_node)
|
||||
}
|
||||
|
||||
fn set_first_child(&self, new_first_child: Option<AbstractNode<ScriptView>>) {
|
||||
let node = self.mut_node();
|
||||
node.set_first_child(new_first_child)
|
||||
}
|
||||
|
||||
fn set_last_child(&self, new_last_child: Option<AbstractNode<ScriptView>>) {
|
||||
let node = self.mut_node();
|
||||
node.set_last_child(new_last_child)
|
||||
}
|
||||
|
||||
fn set_prev_sibling(&self, new_prev_sibling: Option<AbstractNode<ScriptView>>) {
|
||||
let node = self.mut_node();
|
||||
node.set_prev_sibling(new_prev_sibling)
|
||||
}
|
||||
|
||||
fn set_next_sibling(&self, new_next_sibling: Option<AbstractNode<ScriptView>>) {
|
||||
let node = self.mut_node();
|
||||
node.set_next_sibling(new_next_sibling)
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Iteration and traversal
|
||||
//
|
||||
|
||||
impl<View> Iterator<AbstractNode<View>> for AbstractNodeChildrenIterator<View> {
|
||||
fn next(&mut self) -> Option<AbstractNode<View>> {
|
||||
let node = self.current_node;
|
||||
|
@ -613,6 +696,86 @@ impl<View> Iterator<AbstractNode<View>> for AbstractNodeChildrenIterator<View> {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct AncestorIterator<View> {
|
||||
priv current: Option<AbstractNode<View>>,
|
||||
}
|
||||
|
||||
impl<View> Iterator<AbstractNode<View>> for AncestorIterator<View> {
|
||||
fn next(&mut self) -> Option<AbstractNode<View>> {
|
||||
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())
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Do this without precomputing a vector of refs.
|
||||
// Easy for preorder; harder for postorder.
|
||||
pub struct TreeIterator<View> {
|
||||
priv nodes: ~[AbstractNode<View>],
|
||||
priv index: uint,
|
||||
}
|
||||
|
||||
impl<View> TreeIterator<View> {
|
||||
fn new(nodes: ~[AbstractNode<View>]) -> TreeIterator<View> {
|
||||
TreeIterator {
|
||||
nodes: nodes,
|
||||
index: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<View> Iterator<AbstractNode<View>> for TreeIterator<View> {
|
||||
fn next(&mut self) -> Option<AbstractNode<View>> {
|
||||
if self.index >= self.nodes.len() {
|
||||
None
|
||||
} else {
|
||||
let v = self.nodes[self.index].clone();
|
||||
self.index += 1;
|
||||
Some(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn gather<View>(cur: &AbstractNode<View>, refs: &mut ~[AbstractNode<View>], postorder: bool) {
|
||||
if !postorder {
|
||||
refs.push(cur.clone());
|
||||
}
|
||||
for kid in cur.children() {
|
||||
gather(&kid, refs, postorder)
|
||||
}
|
||||
if postorder {
|
||||
refs.push(cur.clone());
|
||||
}
|
||||
}
|
||||
|
||||
impl<View> AbstractNode<View> {
|
||||
/// Iterates over all ancestors of this node.
|
||||
pub fn ancestors(&self) -> AncestorIterator<View> {
|
||||
AncestorIterator {
|
||||
current: self.parent_node(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterates over this node and all its descendants, in preorder.
|
||||
pub fn traverse_preorder(&self) -> TreeIterator<View> {
|
||||
let mut nodes = ~[];
|
||||
gather(self, &mut nodes, false);
|
||||
TreeIterator::new(nodes)
|
||||
}
|
||||
|
||||
/// Iterates over this node and all its descendants, in postorder.
|
||||
pub fn sequential_traverse_postorder(&self) -> TreeIterator<View> {
|
||||
let mut nodes = ~[];
|
||||
gather(self, &mut nodes, true);
|
||||
TreeIterator::new(nodes)
|
||||
}
|
||||
}
|
||||
|
||||
impl<View> Node<View> {
|
||||
pub fn owner_doc(&self) -> AbstractDocument {
|
||||
self.owner_doc.unwrap()
|
||||
|
@ -1215,6 +1378,41 @@ impl Node<ScriptView> {
|
|||
pub fn HasAttributes(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Low-level pointer stitching
|
||||
//
|
||||
|
||||
pub fn set_parent_node(&mut self, new_parent_node: Option<AbstractNode<ScriptView>>) {
|
||||
let doc = self.owner_doc();
|
||||
doc.document().wait_until_safe_to_modify_dom();
|
||||
self.parent_node = new_parent_node
|
||||
}
|
||||
|
||||
pub fn set_first_child(&mut self, new_first_child: Option<AbstractNode<ScriptView>>) {
|
||||
let doc = self.owner_doc();
|
||||
doc.document().wait_until_safe_to_modify_dom();
|
||||
self.first_child = new_first_child
|
||||
}
|
||||
|
||||
pub fn set_last_child(&mut self, new_last_child: Option<AbstractNode<ScriptView>>) {
|
||||
let doc = self.owner_doc();
|
||||
doc.document().wait_until_safe_to_modify_dom();
|
||||
self.last_child = new_last_child
|
||||
}
|
||||
|
||||
pub fn set_prev_sibling(&mut self, new_prev_sibling: Option<AbstractNode<ScriptView>>) {
|
||||
let doc = self.owner_doc();
|
||||
doc.document().wait_until_safe_to_modify_dom();
|
||||
self.prev_sibling = new_prev_sibling
|
||||
}
|
||||
|
||||
pub fn set_next_sibling(&mut self, new_next_sibling: Option<AbstractNode<ScriptView>>) {
|
||||
let doc = self.owner_doc();
|
||||
doc.document().wait_until_safe_to_modify_dom();
|
||||
self.next_sibling = new_next_sibling
|
||||
}
|
||||
}
|
||||
|
||||
impl Reflectable for Node<ScriptView> {
|
||||
|
|
|
@ -20,7 +20,6 @@ use js::jsapi::JSContext;
|
|||
use servo_msg::constellation_msg::SubpageId;
|
||||
use servo_net::image_cache_task::ImageCacheTask;
|
||||
use servo_net::resource_task::{Load, Payload, Done, ResourceTask, load_whole_resource};
|
||||
use servo_util::tree::{TreeNodeRef, ElementLike};
|
||||
use servo_util::url::make_url;
|
||||
use std::cast;
|
||||
use std::cell::Cell;
|
||||
|
@ -29,7 +28,7 @@ use std::comm;
|
|||
use std::from_str::FromStr;
|
||||
use std::str::eq_slice;
|
||||
use std::str;
|
||||
use style::Stylesheet;
|
||||
use style::{Stylesheet, TElement};
|
||||
|
||||
macro_rules! handle_element(
|
||||
($document: expr,
|
||||
|
|
|
@ -45,7 +45,6 @@ use servo_msg::constellation_msg;
|
|||
use servo_net::image_cache_task::ImageCacheTask;
|
||||
use servo_net::resource_task::ResourceTask;
|
||||
use servo_util::geometry::to_frac_px;
|
||||
use servo_util::tree::{TreeNode, TreeNodeRef, ElementLike};
|
||||
use servo_util::url::make_url;
|
||||
use std::cell::Cell;
|
||||
use std::comm::{Port, SharedChan};
|
||||
|
@ -54,6 +53,7 @@ use std::ptr;
|
|||
use std::str::eq_slice;
|
||||
use std::task::{spawn_sched, SingleThreaded};
|
||||
use std::util::replace;
|
||||
use style::{TElement, TNode};
|
||||
|
||||
/// Messages used to control the script task.
|
||||
pub enum ScriptMsg {
|
||||
|
|
28
src/components/style/node.rs
Normal file
28
src/components/style/node.rs
Normal file
|
@ -0,0 +1,28 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
//! Traits that nodes must implement. Breaks the otherwise-cyclic dependency between script and
|
||||
//! style.
|
||||
|
||||
/// FIXME(pcwalton): Should not require `Clone` and should instead return references. When this
|
||||
/// happens this will need to only be implemented for `AbstractNode<LayoutView>`.
|
||||
pub trait TNode<E:TElement> : Clone {
|
||||
fn parent_node(&self) -> Option<Self>;
|
||||
fn prev_sibling(&self) -> Option<Self>;
|
||||
fn next_sibling(&self) -> Option<Self>;
|
||||
|
||||
fn is_document(&self) -> bool;
|
||||
fn is_element(&self) -> bool;
|
||||
|
||||
/// FIXME(pcwalton): This should not use the `with` pattern.
|
||||
fn with_element<R>(&self, f: &fn(&E) -> R) -> R;
|
||||
}
|
||||
|
||||
pub trait TElement {
|
||||
fn get_attr(&self, namespace: Option<~str>, attr: &str) -> Option<~str>;
|
||||
fn get_link(&self) -> Option<~str>;
|
||||
fn get_local_name<'a>(&'a self) -> &'a str;
|
||||
fn get_namespace_url<'a>(&'a self) -> &'a str;
|
||||
}
|
||||
|
|
@ -2,18 +2,17 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::ascii::StrAsciiExt;
|
||||
use std::hashmap::HashMap;
|
||||
use extra::arc::Arc;
|
||||
use extra::sort::tim_sort;
|
||||
use std::ascii::StrAsciiExt;
|
||||
use std::hashmap::HashMap;
|
||||
use std::str;
|
||||
|
||||
use media_queries::{Device, Screen};
|
||||
use node::{TElement, TNode};
|
||||
use properties::{PropertyDeclaration, PropertyDeclarationBlock};
|
||||
use selectors::*;
|
||||
use stylesheets::{Stylesheet, iter_style_rules};
|
||||
use media_queries::{Device, Screen};
|
||||
use properties::{PropertyDeclaration, PropertyDeclarationBlock};
|
||||
use servo_util::tree::{TreeNodeRefAsElement, TreeNode, ElementLike};
|
||||
|
||||
use std::str;
|
||||
|
||||
pub enum StylesheetOrigin {
|
||||
UserAgentOrigin,
|
||||
|
@ -67,16 +66,15 @@ impl SelectorMap {
|
|||
///
|
||||
/// Extract matching rules as per node's ID, classes, tag name, etc..
|
||||
/// Sort the Rules at the end to maintain cascading order.
|
||||
fn get_all_matching_rules<N:TreeNode<T>,
|
||||
T:TreeNodeRefAsElement<N,E>,
|
||||
E:ElementLike>(
|
||||
fn get_all_matching_rules<E:TElement,
|
||||
N:TNode<E>>(
|
||||
&self,
|
||||
node: &T,
|
||||
node: &N,
|
||||
pseudo_element: Option<PseudoElement>,
|
||||
matching_rules_list: &mut ~[Rule]) {
|
||||
// At the end, we're going to sort the rules that we added, so remember where we began.
|
||||
let init_len = matching_rules_list.len();
|
||||
node.with_imm_element_like(|element: &E| {
|
||||
node.with_element(|element: &E| {
|
||||
match element.get_attr(None, "id") {
|
||||
Some(id) => {
|
||||
SelectorMap::get_matching_rules_from_hash(node,
|
||||
|
@ -118,10 +116,9 @@ impl SelectorMap {
|
|||
tim_sort(matching_rules_list.mut_slice_from(init_len));
|
||||
}
|
||||
|
||||
fn get_matching_rules_from_hash<N:TreeNode<T>,
|
||||
T:TreeNodeRefAsElement<N,E>,
|
||||
E:ElementLike>(
|
||||
node: &T,
|
||||
fn get_matching_rules_from_hash<E:TElement,
|
||||
N:TNode<E>>(
|
||||
node: &N,
|
||||
pseudo_element: Option<PseudoElement>,
|
||||
hash: &HashMap<~str,~[Rule]>,
|
||||
key: &str,
|
||||
|
@ -135,10 +132,9 @@ impl SelectorMap {
|
|||
}
|
||||
|
||||
/// Adds rules in `rules` that match `node` to the `matching_rules` list.
|
||||
fn get_matching_rules<N:TreeNode<T>,
|
||||
T:TreeNodeRefAsElement<N,E>,
|
||||
E:ElementLike>(
|
||||
node: &T,
|
||||
fn get_matching_rules<E:TElement,
|
||||
N:TNode<E>>(
|
||||
node: &N,
|
||||
pseudo_element: Option<PseudoElement>,
|
||||
rules: &[Rule],
|
||||
matching_rules: &mut ~[Rule]) {
|
||||
|
@ -301,11 +297,10 @@ impl Stylist {
|
|||
|
||||
/// Returns the applicable CSS declarations for the given element. This corresponds to
|
||||
/// `ElementRuleCollector` in WebKit.
|
||||
pub fn get_applicable_declarations<N:TreeNode<T>,
|
||||
T:TreeNodeRefAsElement<N,E>,
|
||||
E:ElementLike>(
|
||||
pub fn get_applicable_declarations<E:TElement,
|
||||
N:TNode<E>>(
|
||||
&self,
|
||||
element: &T,
|
||||
element: &N,
|
||||
style_attribute: Option<&PropertyDeclarationBlock>,
|
||||
pseudo_element: Option<PseudoElement>)
|
||||
-> ~[Arc<~[PropertyDeclaration]>] {
|
||||
|
@ -421,7 +416,6 @@ struct Rule {
|
|||
stylesheet_index: uint,
|
||||
}
|
||||
|
||||
|
||||
impl Ord for Rule {
|
||||
#[inline]
|
||||
fn lt(&self, other: &Rule) -> bool {
|
||||
|
@ -431,16 +425,19 @@ impl Ord for Rule {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
#[inline]
|
||||
fn matches_selector<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: ElementLike>(
|
||||
selector: &Selector, element: &T, pseudo_element: Option<PseudoElement>) -> bool {
|
||||
fn matches_selector<E:TElement,
|
||||
N:TNode<E>>(
|
||||
selector: &Selector,
|
||||
element: &N,
|
||||
pseudo_element: Option<PseudoElement>)
|
||||
-> bool {
|
||||
selector.pseudo_element == pseudo_element &&
|
||||
matches_compound_selector::<N, T, E>(&selector.compound_selectors, element)
|
||||
matches_compound_selector::<E,N>(&selector.compound_selectors, element)
|
||||
}
|
||||
|
||||
fn matches_compound_selector<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: ElementLike>(
|
||||
selector: &CompoundSelector, element: &T) -> bool {
|
||||
fn matches_compound_selector<E:TElement,N:TNode<E>>(selector: &CompoundSelector, element: &N)
|
||||
-> bool {
|
||||
if !do selector.simple_selectors.iter().all |simple_selector| {
|
||||
matches_simple_selector(simple_selector, element)
|
||||
} {
|
||||
|
@ -455,12 +452,12 @@ fn matches_compound_selector<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: E
|
|||
NextSibling => (true, true),
|
||||
LaterSibling => (true, false),
|
||||
};
|
||||
let mut node = element.clone();
|
||||
let mut node = (*element).clone();
|
||||
loop {
|
||||
let next_node = if siblings {
|
||||
node.node().prev_sibling()
|
||||
node.prev_sibling()
|
||||
} else {
|
||||
node.node().parent_node()
|
||||
node.parent_node()
|
||||
};
|
||||
match next_node {
|
||||
None => return false,
|
||||
|
@ -479,25 +476,24 @@ fn matches_compound_selector<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: E
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn matches_simple_selector<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: ElementLike>(
|
||||
selector: &SimpleSelector, element: &T) -> bool {
|
||||
fn matches_simple_selector<E:TElement,N:TNode<E>>(selector: &SimpleSelector, element: &N) -> bool {
|
||||
match *selector {
|
||||
// TODO: case-sensitivity depends on the document type
|
||||
// TODO: intern element names
|
||||
LocalNameSelector(ref name) => {
|
||||
do element.with_imm_element_like |element: &E| {
|
||||
do element.with_element |element: &E| {
|
||||
element.get_local_name().eq_ignore_ascii_case(name.as_slice())
|
||||
}
|
||||
}
|
||||
NamespaceSelector(ref url) => {
|
||||
do element.with_imm_element_like |element: &E| {
|
||||
do element.with_element |element: &E| {
|
||||
element.get_namespace_url() == url.as_slice()
|
||||
}
|
||||
}
|
||||
// TODO: case-sensitivity depends on the document type and quirks mode
|
||||
// TODO: cache and intern IDs on elements.
|
||||
IDSelector(ref id) => {
|
||||
do element.with_imm_element_like |element: &E| {
|
||||
do element.with_element |element: &E| {
|
||||
match element.get_attr(None, "id") {
|
||||
Some(attr) => str::eq_slice(attr, *id),
|
||||
None => false
|
||||
|
@ -506,7 +502,7 @@ fn matches_simple_selector<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: Ele
|
|||
}
|
||||
// TODO: cache and intern classe names on elements.
|
||||
ClassSelector(ref class) => {
|
||||
do element.with_imm_element_like |element: &E| {
|
||||
do element.with_element |element: &E| {
|
||||
match element.get_attr(None, "class") {
|
||||
None => false,
|
||||
// TODO: case-sensitivity depends on the document type and quirks mode
|
||||
|
@ -537,12 +533,12 @@ fn matches_simple_selector<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: Ele
|
|||
|
||||
|
||||
AnyLink => {
|
||||
do element.with_imm_element_like |element: &E| {
|
||||
do element.with_element |element: &E| {
|
||||
element.get_link().is_some()
|
||||
}
|
||||
}
|
||||
Link => {
|
||||
do element.with_imm_element_like |element: &E| {
|
||||
do element.with_element |element: &E| {
|
||||
match element.get_link() {
|
||||
Some(url) => !url_is_visited(url),
|
||||
None => false,
|
||||
|
@ -550,7 +546,7 @@ fn matches_simple_selector<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: Ele
|
|||
}
|
||||
}
|
||||
Visited => {
|
||||
do element.with_imm_element_like |element: &E| {
|
||||
do element.with_element |element: &E| {
|
||||
match element.get_link() {
|
||||
Some(url) => url_is_visited(url),
|
||||
None => false,
|
||||
|
@ -589,12 +585,18 @@ fn url_is_visited(_url: &str) -> bool {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn matches_generic_nth_child<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: ElementLike>(
|
||||
element: &T, a: i32, b: i32, is_of_type: bool, is_from_end: bool) -> bool {
|
||||
fn matches_generic_nth_child<E:TElement,
|
||||
N:TNode<E>>(
|
||||
element: &N,
|
||||
a: i32,
|
||||
b: i32,
|
||||
is_of_type: bool,
|
||||
is_from_end: bool)
|
||||
-> bool {
|
||||
let mut node = element.clone();
|
||||
// fail if we can't find a parent or if the node is the root element
|
||||
// of the document (Cf. Selectors Level 3)
|
||||
match node.node().parent_node() {
|
||||
match node.parent_node() {
|
||||
Some(parent) => if parent.is_document() {
|
||||
return false;
|
||||
},
|
||||
|
@ -604,7 +606,7 @@ fn matches_generic_nth_child<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: E
|
|||
let mut element_local_name = "";
|
||||
let mut element_namespace = "";
|
||||
if is_of_type {
|
||||
do element.with_imm_element_like |element: &E| {
|
||||
do element.with_element |element: &E| {
|
||||
element_local_name = element.get_local_name();
|
||||
element_namespace = element.get_namespace_url();
|
||||
}
|
||||
|
@ -613,12 +615,12 @@ fn matches_generic_nth_child<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: E
|
|||
let mut index = 1;
|
||||
loop {
|
||||
if is_from_end {
|
||||
match node.node().next_sibling() {
|
||||
match node.next_sibling() {
|
||||
None => break,
|
||||
Some(next_sibling) => node = next_sibling
|
||||
}
|
||||
} else {
|
||||
match node.node().prev_sibling() {
|
||||
match node.prev_sibling() {
|
||||
None => break,
|
||||
Some(prev_sibling) => node = prev_sibling
|
||||
}
|
||||
|
@ -626,7 +628,7 @@ fn matches_generic_nth_child<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: E
|
|||
|
||||
if node.is_element() {
|
||||
if is_of_type {
|
||||
do node.with_imm_element_like |node: &E| {
|
||||
do node.with_element |node: &E| {
|
||||
if element_local_name == node.get_local_name() &&
|
||||
element_namespace == node.get_namespace_url() {
|
||||
index += 1;
|
||||
|
@ -648,27 +650,25 @@ fn matches_generic_nth_child<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: E
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn matches_root<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: ElementLike>(
|
||||
element: &T) -> bool {
|
||||
match element.node().parent_node() {
|
||||
fn matches_root<E:TElement,N:TNode<E>>(element: &N) -> bool {
|
||||
match element.parent_node() {
|
||||
Some(parent) => parent.is_document(),
|
||||
None => false
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn matches_first_child<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: ElementLike>(
|
||||
element: &T) -> bool {
|
||||
fn matches_first_child<E:TElement,N:TNode<E>>(element: &N) -> bool {
|
||||
let mut node = element.clone();
|
||||
loop {
|
||||
match node.node().prev_sibling() {
|
||||
match node.prev_sibling() {
|
||||
Some(prev_sibling) => {
|
||||
node = prev_sibling;
|
||||
if node.is_element() {
|
||||
return false
|
||||
}
|
||||
},
|
||||
None => match node.node().parent_node() {
|
||||
None => match node.parent_node() {
|
||||
// Selectors level 3 says :first-child does not match the
|
||||
// root of the document; Warning, level 4 says, for the time
|
||||
// being, the contrary...
|
||||
|
@ -680,18 +680,17 @@ fn matches_first_child<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: Element
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn matches_last_child<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: ElementLike>(
|
||||
element: &T) -> bool {
|
||||
fn matches_last_child<E:TElement,N:TNode<E>>(element: &N) -> bool {
|
||||
let mut node = element.clone();
|
||||
loop {
|
||||
match node.node().next_sibling() {
|
||||
match node.next_sibling() {
|
||||
Some(next_sibling) => {
|
||||
node = next_sibling;
|
||||
if node.is_element() {
|
||||
return false
|
||||
}
|
||||
},
|
||||
None => match node.node().parent_node() {
|
||||
None => match node.parent_node() {
|
||||
// Selectors level 3 says :last-child does not match the
|
||||
// root of the document; Warning, level 4 says, for the time
|
||||
// being, the contrary...
|
||||
|
@ -703,9 +702,13 @@ fn matches_last_child<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: ElementL
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn match_attribute<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: ElementLike>(
|
||||
attr: &AttrSelector, element: &T, f: &fn(&str)-> bool) -> bool {
|
||||
do element.with_imm_element_like |element: &E| {
|
||||
fn match_attribute<E:TElement,
|
||||
N:TNode<E>>(
|
||||
attr: &AttrSelector,
|
||||
element: &N,
|
||||
f: &fn(&str) -> bool)
|
||||
-> bool {
|
||||
do element.with_element |element: &E| {
|
||||
// FIXME: avoid .clone() here? See #1367
|
||||
match element.get_attr(attr.namespace.clone(), attr.name) {
|
||||
None => false,
|
||||
|
|
|
@ -25,6 +25,7 @@ pub use selector_matching::{Stylist, StylesheetOrigin, UserAgentOrigin, AuthorOr
|
|||
pub use properties::{cascade, PropertyDeclaration, ComputedValues, computed_values};
|
||||
pub use properties::{PropertyDeclarationBlock, parse_style_attribute}; // Style attributes
|
||||
pub use errors::with_errors_silenced;
|
||||
pub use node::{TElement, TNode};
|
||||
|
||||
mod stylesheets;
|
||||
mod errors;
|
||||
|
@ -32,5 +33,6 @@ mod selectors;
|
|||
mod selector_matching;
|
||||
mod properties;
|
||||
mod namespaces;
|
||||
mod node;
|
||||
mod media_queries;
|
||||
mod parsing_utils;
|
||||
|
|
|
@ -1,354 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
//! Helper functions for garbage collected doubly-linked trees.
|
||||
|
||||
// Macros to make add_child etc. less painful to write.
|
||||
// Code outside this module should instead implement TreeNode
|
||||
// and use its default methods.
|
||||
macro_rules! get(
|
||||
($node:expr, $fun:ident) => (
|
||||
{
|
||||
let val: Option<Self> = TreeNodeRef::<Node>::$fun($node);
|
||||
val
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
macro_rules! set(
|
||||
($node:expr, $fun:ident, $val:expr) => (
|
||||
{
|
||||
let val: Option<Self> = $val;
|
||||
TreeNodeRef::<Node>::$fun($node, val)
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
pub struct ChildIterator<Ref> {
|
||||
priv current: Option<Ref>,
|
||||
}
|
||||
|
||||
impl<Node, Ref: TreeNodeRef<Node>> Iterator<Ref> for ChildIterator<Ref> {
|
||||
fn next(&mut self) -> Option<Ref> {
|
||||
if self.current.is_none() {
|
||||
return None;
|
||||
}
|
||||
|
||||
// FIXME: Do we need two clones here?
|
||||
let x = self.current.get_ref().clone();
|
||||
self.current = TreeNodeRef::<Node>::next_sibling(x.node());
|
||||
Some(x.clone())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AncestorIterator<Ref> {
|
||||
priv current: Option<Ref>,
|
||||
}
|
||||
|
||||
impl<Node, Ref: TreeNodeRef<Node>> Iterator<Ref> for AncestorIterator<Ref> {
|
||||
fn next(&mut self) -> Option<Ref> {
|
||||
if self.current.is_none() {
|
||||
return None;
|
||||
}
|
||||
|
||||
// FIXME: Do we need two clones here?
|
||||
let x = self.current.get_ref().clone();
|
||||
self.current = TreeNodeRef::<Node>::parent_node(x.node());
|
||||
Some(x.clone())
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Do this without precomputing a vector of refs.
|
||||
// Easy for preorder; harder for postorder.
|
||||
pub struct TreeIterator<Ref> {
|
||||
priv nodes: ~[Ref],
|
||||
priv index: uint,
|
||||
}
|
||||
|
||||
impl<Ref> TreeIterator<Ref> {
|
||||
fn new(nodes: ~[Ref]) -> TreeIterator<Ref> {
|
||||
TreeIterator {
|
||||
nodes: nodes,
|
||||
index: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ref: Clone> Iterator<Ref> for TreeIterator<Ref> {
|
||||
fn next(&mut self) -> Option<Ref> {
|
||||
if self.index >= self.nodes.len() {
|
||||
None
|
||||
} else {
|
||||
let v = self.nodes[self.index].clone();
|
||||
self.index += 1;
|
||||
Some(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A type implementing TreeNodeRef<Node> is a clonable reference to an underlying
|
||||
/// node type Node.
|
||||
///
|
||||
/// We have to define both ref and node operations in the same trait, which makes
|
||||
/// the latter more annoying to call (as static methods). But we provide non-static
|
||||
/// proxies in trait TreeNode below.
|
||||
pub trait TreeNodeRef<Node>: Clone {
|
||||
|
||||
// Fundamental operations on refs.
|
||||
|
||||
/// Borrows this node as immutable.
|
||||
fn node<'a>(&'a self) -> &'a Node;
|
||||
/// Borrows this node as mutable.
|
||||
fn mut_node<'a>(&'a self) -> &'a mut Node;
|
||||
|
||||
// Fundamental operations on nodes.
|
||||
|
||||
/// Returns the parent of this node.
|
||||
fn parent_node(node: &Node) -> Option<Self>;
|
||||
|
||||
/// Returns the first child of this node.
|
||||
fn first_child(node: &Node) -> Option<Self>;
|
||||
|
||||
/// Returns the last child of this node.
|
||||
fn last_child(node: &Node) -> Option<Self>;
|
||||
|
||||
/// Returns the previous sibling of this node.
|
||||
fn prev_sibling(node: &Node) -> Option<Self>;
|
||||
|
||||
/// Returns the next sibling of this node.
|
||||
fn next_sibling(node: &Node) -> Option<Self>;
|
||||
|
||||
/// Sets the parent of this node.
|
||||
fn set_parent_node(node: &mut Node, new_parent: Option<Self>);
|
||||
|
||||
/// Sets the first child of this node.
|
||||
fn set_first_child(node: &mut Node, new_first_child: Option<Self>);
|
||||
|
||||
/// Sets the last child of this node.
|
||||
fn set_last_child(node: &mut Node, new_last_child: Option<Self>);
|
||||
|
||||
/// Sets the previous sibling of this node.
|
||||
fn set_prev_sibling(node: &mut Node, new_prev_sibling: Option<Self>);
|
||||
|
||||
/// Sets the next sibling of this node.
|
||||
fn set_next_sibling(node: &mut Node, new_next_sibling: Option<Self>);
|
||||
|
||||
|
||||
// The tree utilities, operating on refs mostly.
|
||||
|
||||
/// Returns true if this node is disconnected from the tree or has no children.
|
||||
fn is_leaf(&self) -> bool {
|
||||
(get!(self.node(), first_child)).is_none()
|
||||
}
|
||||
|
||||
/// 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(&self, new_child: Self, before: Option<Self>) {
|
||||
let this_node = self.mut_node();
|
||||
let new_child_node = new_child.mut_node();
|
||||
assert!((get!(new_child_node, parent_node)).is_none());
|
||||
assert!((get!(new_child_node, prev_sibling)).is_none());
|
||||
assert!((get!(new_child_node, next_sibling)).is_none());
|
||||
match before {
|
||||
Some(before) => {
|
||||
let before_node = before.mut_node();
|
||||
// XXX Should assert that parent is self.
|
||||
assert!((get!(before_node, parent_node)).is_some());
|
||||
set!(before_node, set_prev_sibling, Some(new_child.clone()));
|
||||
set!(new_child_node, set_next_sibling, Some(before.clone()));
|
||||
match get!(before_node, prev_sibling) {
|
||||
None => {
|
||||
// XXX Should assert that before is the first child of
|
||||
// self.
|
||||
set!(this_node, set_first_child, Some(new_child.clone()));
|
||||
},
|
||||
Some(prev_sibling) => {
|
||||
let prev_sibling_node = prev_sibling.mut_node();
|
||||
set!(prev_sibling_node, set_next_sibling, Some(new_child.clone()));
|
||||
set!(new_child_node, set_prev_sibling, Some(prev_sibling.clone()));
|
||||
},
|
||||
}
|
||||
},
|
||||
None => {
|
||||
match get!(this_node, last_child) {
|
||||
None => set!(this_node, set_first_child, Some(new_child.clone())),
|
||||
Some(last_child) => {
|
||||
let last_child_node = last_child.mut_node();
|
||||
assert!((get!(last_child_node, next_sibling)).is_none());
|
||||
set!(last_child_node, set_next_sibling, Some(new_child.clone()));
|
||||
set!(new_child_node, set_prev_sibling, Some(last_child.clone()));
|
||||
}
|
||||
}
|
||||
|
||||
set!(this_node, set_last_child, Some(new_child.clone()));
|
||||
},
|
||||
}
|
||||
|
||||
set!(new_child_node, 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(&self, child: Self) {
|
||||
let this_node = self.mut_node();
|
||||
let child_node = child.mut_node();
|
||||
assert!((get!(child_node, parent_node)).is_some());
|
||||
|
||||
match get!(child_node, prev_sibling) {
|
||||
None => set!(this_node, set_first_child, get!(child_node, next_sibling)),
|
||||
Some(prev_sibling) => {
|
||||
let prev_sibling_node = prev_sibling.mut_node();
|
||||
set!(prev_sibling_node, set_next_sibling, get!(child_node, next_sibling));
|
||||
}
|
||||
}
|
||||
|
||||
match get!(child_node, next_sibling) {
|
||||
None => set!(this_node, set_last_child, get!(child_node, prev_sibling)),
|
||||
Some(next_sibling) => {
|
||||
let next_sibling_node = next_sibling.mut_node();
|
||||
set!(next_sibling_node, set_prev_sibling, get!(child_node, prev_sibling));
|
||||
}
|
||||
}
|
||||
|
||||
set!(child_node, set_prev_sibling, None);
|
||||
set!(child_node, set_next_sibling, None);
|
||||
set!(child_node, set_parent_node, None);
|
||||
}
|
||||
|
||||
/// Iterates over all children of this node.
|
||||
fn children(&self) -> ChildIterator<Self> {
|
||||
ChildIterator {
|
||||
current: get!(self.node(), first_child),
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterates over all ancestors of this node.
|
||||
fn ancestors(&self) -> AncestorIterator<Self> {
|
||||
AncestorIterator {
|
||||
current: get!(self.node(), parent_node),
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterates over this node and all its descendants, in preorder.
|
||||
fn traverse_preorder(&self) -> TreeIterator<Self> {
|
||||
self.traverse_preorder_prune(|_| false)
|
||||
}
|
||||
|
||||
/// Iterates over this node and all its descendants, in postorder.
|
||||
fn traverse_postorder(&self) -> TreeIterator<Self> {
|
||||
self.traverse_postorder_prune(|_| false)
|
||||
}
|
||||
|
||||
/// Like traverse_preorder but calls 'prune' first on each node. If it returns true then we
|
||||
/// skip the whole subtree but continue iterating.
|
||||
fn traverse_preorder_prune(&self, prune: &fn(&Self) -> bool) -> TreeIterator<Self> {
|
||||
let mut nodes = ~[];
|
||||
gather(self, &mut nodes, false, prune);
|
||||
TreeIterator::new(nodes)
|
||||
}
|
||||
|
||||
/// Like traverse_postorder but calls 'prune' first on each node. If it returns true then we
|
||||
/// skip the whole subtree but continue iterating.
|
||||
///
|
||||
/// NB: 'prune' is called *before* traversing children, even though this is a
|
||||
/// postorder traversal.
|
||||
fn traverse_postorder_prune(&self, prune: &fn(&Self) -> bool) -> TreeIterator<Self> {
|
||||
let mut nodes = ~[];
|
||||
gather(self, &mut nodes, true, prune);
|
||||
TreeIterator::new(nodes)
|
||||
}
|
||||
|
||||
fn is_element(&self) -> bool;
|
||||
|
||||
fn is_document(&self) -> bool;
|
||||
}
|
||||
|
||||
pub trait TreeNodeRefAsElement<Node, E: ElementLike>: TreeNodeRef<Node> {
|
||||
fn with_imm_element_like<R>(&self, f: &fn(&E) -> R) -> R;
|
||||
}
|
||||
|
||||
fn gather<Node, Ref: TreeNodeRef<Node>>(cur: &Ref, refs: &mut ~[Ref],
|
||||
postorder: bool, prune: &fn(&Ref) -> bool) {
|
||||
// prune shouldn't mutate, so don't clone
|
||||
if prune(cur) {
|
||||
return;
|
||||
}
|
||||
|
||||
if !postorder {
|
||||
refs.push(cur.clone());
|
||||
}
|
||||
for kid in cur.children() {
|
||||
// FIXME: Work around rust#2202. We should be able to pass the callback directly.
|
||||
gather(&kid, refs, postorder, |a| prune(a))
|
||||
}
|
||||
if postorder {
|
||||
refs.push(cur.clone());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Access the fields of a node without a static TreeNodeRef method call.
|
||||
/// If you make an impl TreeNodeRef<Node> for Ref then you should also make
|
||||
/// impl TreeNode<Ref> for Node with an empty body.
|
||||
pub trait TreeNode<Ref: TreeNodeRef<Self>> {
|
||||
/// Returns the parent of this node.
|
||||
fn parent_node(&self) -> Option<Ref> {
|
||||
TreeNodeRef::<Self>::parent_node(self)
|
||||
}
|
||||
|
||||
/// Returns the first child of this node.
|
||||
fn first_child(&self) -> Option<Ref> {
|
||||
TreeNodeRef::<Self>::first_child(self)
|
||||
}
|
||||
|
||||
/// Returns the last child of this node.
|
||||
fn last_child(&self) -> Option<Ref> {
|
||||
TreeNodeRef::<Self>::last_child(self)
|
||||
}
|
||||
|
||||
/// Returns the previous sibling of this node.
|
||||
fn prev_sibling(&self) -> Option<Ref> {
|
||||
TreeNodeRef::<Self>::prev_sibling(self)
|
||||
}
|
||||
|
||||
/// Returns the next sibling of this node.
|
||||
fn next_sibling(&self) -> Option<Ref> {
|
||||
TreeNodeRef::<Self>::next_sibling(self)
|
||||
}
|
||||
|
||||
/// Sets the parent of this node.
|
||||
fn set_parent_node(&mut self, new_parent: Option<Ref>) {
|
||||
TreeNodeRef::<Self>::set_parent_node(self, new_parent)
|
||||
}
|
||||
|
||||
/// Sets the first child of this node.
|
||||
fn set_first_child(&mut self, new_first_child: Option<Ref>) {
|
||||
TreeNodeRef::<Self>::set_first_child(self, new_first_child)
|
||||
}
|
||||
|
||||
/// Sets the last child of this node.
|
||||
fn set_last_child(&mut self, new_last_child: Option<Ref>) {
|
||||
TreeNodeRef::<Self>::set_last_child(self, new_last_child)
|
||||
}
|
||||
|
||||
/// Sets the previous sibling of this node.
|
||||
fn set_prev_sibling(&mut self, new_prev_sibling: Option<Ref>) {
|
||||
TreeNodeRef::<Self>::set_prev_sibling(self, new_prev_sibling)
|
||||
}
|
||||
|
||||
/// Sets the next sibling of this node.
|
||||
fn set_next_sibling(&mut self, new_next_sibling: Option<Ref>) {
|
||||
TreeNodeRef::<Self>::set_next_sibling(self, new_next_sibling)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub trait ElementLike {
|
||||
fn get_local_name<'a>(&'a self) -> &'a str;
|
||||
fn get_namespace_url<'a>(&'a self) -> &'a str;
|
||||
fn get_attr(&self, ns_url: Option<~str>, name: &str) -> Option<~str>;
|
||||
fn get_link(&self) -> Option<~str>;
|
||||
}
|
|
@ -18,7 +18,6 @@ pub mod geometry;
|
|||
pub mod range;
|
||||
pub mod slot;
|
||||
pub mod time;
|
||||
pub mod tree;
|
||||
pub mod url;
|
||||
pub mod vec;
|
||||
pub mod debug;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue