mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +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 layout::util::LayoutDataAccess;
|
||||||
|
|
||||||
use script::dom::node::{AbstractNode, LayoutView};
|
use script::dom::node::{AbstractNode, LayoutView};
|
||||||
use style::Stylist;
|
use style::{TNode, Stylist, cascade};
|
||||||
use style::cascade;
|
|
||||||
use servo_util::tree::TreeNodeRef;
|
|
||||||
|
|
||||||
pub trait MatchMethods {
|
pub trait MatchMethods {
|
||||||
fn match_node(&self, stylist: &Stylist);
|
fn match_node(&self, stylist: &Stylist);
|
||||||
|
|
|
@ -7,9 +7,8 @@ use layout::util::LayoutDataAccess;
|
||||||
|
|
||||||
use extra::arc::Arc;
|
use extra::arc::Arc;
|
||||||
use std::cast;
|
use std::cast;
|
||||||
use style::ComputedValues;
|
use style::{ComputedValues, TNode};
|
||||||
use script::dom::node::{AbstractNode, LayoutView};
|
use script::dom::node::{AbstractNode, LayoutView};
|
||||||
use servo_util::tree::TreeNodeRef;
|
|
||||||
|
|
||||||
pub trait NodeUtil {
|
pub trait NodeUtil {
|
||||||
fn get_css_select_results<'a>(&'a self) -> &'a Arc<ComputedValues>;
|
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::geometry;
|
||||||
use servo_util::range::*;
|
use servo_util::range::*;
|
||||||
use servo_util::slot::Slot;
|
use servo_util::slot::Slot;
|
||||||
use servo_util::tree::{TreeNodeRef, ElementLike};
|
|
||||||
use std::cast;
|
use std::cast;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::cmp::ApproxEq;
|
use std::cmp::ApproxEq;
|
||||||
use std::num::Zero;
|
use std::num::Zero;
|
||||||
use style::ComputedValues;
|
use style::{ComputedValues, TElement, TNode};
|
||||||
use style::computed_values::{LengthOrPercentage, overflow};
|
use style::computed_values::{LengthOrPercentage, overflow};
|
||||||
use style::computed_values::{border_style, clear, font_family, font_style, line_height};
|
use style::computed_values::{border_style, clear, font_family, font_style, line_height};
|
||||||
use style::computed_values::{text_align, text_decoration, vertical_align, visibility};
|
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::{DocumentFragmentNodeTypeId, DocumentNodeTypeId, ElementNodeTypeId};
|
||||||
use script::dom::node::{LayoutView, PostorderNodeMutTraversal, TextNodeTypeId};
|
use script::dom::node::{LayoutView, PostorderNodeMutTraversal, TextNodeTypeId};
|
||||||
use servo_util::slot::Slot;
|
use servo_util::slot::Slot;
|
||||||
use servo_util::tree::TreeNodeRef;
|
|
||||||
use std::util;
|
use std::util;
|
||||||
use style::computed_values::{display, float};
|
use style::computed_values::{display, float};
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
use layout::util::{LayoutData, LayoutDataAccess};
|
use layout::util::{LayoutData, LayoutDataAccess};
|
||||||
|
|
||||||
use script::dom::node::{AbstractNode, LayoutView};
|
use script::dom::node::{AbstractNode, LayoutView};
|
||||||
use servo_util::tree::TreeNodeRef;
|
|
||||||
|
|
||||||
/// Functionality useful for querying the layout-specific data on DOM nodes.
|
/// Functionality useful for querying the layout-specific data on DOM nodes.
|
||||||
pub trait LayoutAuxMethods {
|
pub trait LayoutAuxMethods {
|
||||||
|
|
|
@ -22,8 +22,7 @@ use servo_util::range::Range;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::u16;
|
use std::u16;
|
||||||
use std::util;
|
use std::util;
|
||||||
use style::computed_values::text_align;
|
use style::computed_values::{text_align, vertical_align};
|
||||||
use style::computed_values::vertical_align;
|
|
||||||
|
|
||||||
/// Lineboxes are represented as offsets into the child list, rather than
|
/// Lineboxes are represented as offsets into the child list, rather than
|
||||||
/// as an object that "owns" boxes. Choosing a different set of line
|
/// 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::geometry::Au;
|
||||||
use servo_util::time::{ProfilerChan, profile};
|
use servo_util::time::{ProfilerChan, profile};
|
||||||
use servo_util::time;
|
use servo_util::time;
|
||||||
use servo_util::tree::TreeNodeRef;
|
|
||||||
use std::cast::transmute;
|
use std::cast::transmute;
|
||||||
use std::cast;
|
use std::cast;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::comm::Port;
|
use std::comm::Port;
|
||||||
use std::task;
|
use std::task;
|
||||||
use std::util;
|
use std::util;
|
||||||
use style::AuthorOrigin;
|
use style::{AuthorOrigin, Stylesheet, Stylist};
|
||||||
use style::Stylesheet;
|
|
||||||
use style::Stylist;
|
|
||||||
|
|
||||||
/// Information needed by the layout task.
|
/// Information needed by the layout task.
|
||||||
struct LayoutTask {
|
struct LayoutTask {
|
||||||
|
|
|
@ -9,7 +9,6 @@ use extra::arc::Arc;
|
||||||
use script::dom::node::{AbstractNode, LayoutView};
|
use script::dom::node::{AbstractNode, LayoutView};
|
||||||
use servo_util::range::Range;
|
use servo_util::range::Range;
|
||||||
use servo_util::slot::{MutSlotRef, SlotRef};
|
use servo_util::slot::{MutSlotRef, SlotRef};
|
||||||
use servo_util::tree::TreeNodeRef;
|
|
||||||
use std::cast;
|
use std::cast;
|
||||||
use std::iter::Enumerate;
|
use std::iter::Enumerate;
|
||||||
use std::libc::uintptr_t;
|
use std::libc::uintptr_t;
|
||||||
|
|
|
@ -10,7 +10,6 @@ use std::cast;
|
||||||
use std::libc;
|
use std::libc;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use js::jsapi::{JSTracer, JSTRACE_OBJECT, JS_CallTracer};
|
use js::jsapi::{JSTracer, JSTRACE_OBJECT, JS_CallTracer};
|
||||||
use servo_util::tree::TreeNodeRef;
|
|
||||||
|
|
||||||
impl Reflectable for AbstractNode<ScriptView> {
|
impl Reflectable for AbstractNode<ScriptView> {
|
||||||
fn reflector<'a>(&'a self) -> &'a Reflector {
|
fn reflector<'a>(&'a self) -> &'a Reflector {
|
||||||
|
|
|
@ -21,16 +21,15 @@ use dom::uievent::UIEvent;
|
||||||
use dom::window::Window;
|
use dom::window::Window;
|
||||||
use dom::htmltitleelement::HTMLTitleElement;
|
use dom::htmltitleelement::HTMLTitleElement;
|
||||||
use html::hubbub_html_parser::build_element_from_tag;
|
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 layout_interface::{DocumentDamageLevel, ContentChangedDocumentDamage};
|
||||||
|
|
||||||
use std::hashmap::HashMap;
|
use js::jsapi::{JSObject, JSContext, JSTracer};
|
||||||
|
|
||||||
use std::cast;
|
|
||||||
use std::str::eq_slice;
|
|
||||||
use std::ascii::StrAsciiExt;
|
use std::ascii::StrAsciiExt;
|
||||||
|
use std::cast;
|
||||||
|
use std::hashmap::HashMap;
|
||||||
|
use std::str::eq_slice;
|
||||||
use std::unstable::raw::Box;
|
use std::unstable::raw::Box;
|
||||||
|
use style::{TElement, TNode};
|
||||||
|
|
||||||
#[deriving(Eq)]
|
#[deriving(Eq)]
|
||||||
pub enum DocumentTypeId {
|
pub enum DocumentTypeId {
|
||||||
|
|
|
@ -20,8 +20,8 @@ use dom::namespace::Namespace;
|
||||||
use layout_interface::{ContentBoxQuery, ContentBoxResponse, ContentBoxesQuery};
|
use layout_interface::{ContentBoxQuery, ContentBoxResponse, ContentBoxesQuery};
|
||||||
use layout_interface::{ContentBoxesResponse, ContentChangedDocumentDamage};
|
use layout_interface::{ContentBoxesResponse, ContentChangedDocumentDamage};
|
||||||
use layout_interface::{MatchSelectorsDocumentDamage};
|
use layout_interface::{MatchSelectorsDocumentDamage};
|
||||||
|
use style::{TElement, TNode};
|
||||||
use style;
|
use style;
|
||||||
use servo_util::tree::{TreeNodeRef, ElementLike};
|
|
||||||
|
|
||||||
use std::comm;
|
use std::comm;
|
||||||
use std::hashmap::HashMap;
|
use std::hashmap::HashMap;
|
||||||
|
@ -125,7 +125,7 @@ pub enum ElementTypeId {
|
||||||
// Element methods
|
// Element methods
|
||||||
//
|
//
|
||||||
|
|
||||||
impl ElementLike for Element {
|
impl TElement for Element {
|
||||||
fn get_local_name<'a>(&'a self) -> &'a str {
|
fn get_local_name<'a>(&'a self) -> &'a str {
|
||||||
self.tag_name.as_slice()
|
self.tag_name.as_slice()
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ use dom::bindings::callback::eReportExceptions;
|
||||||
use dom::eventtarget::{AbstractEventTarget, Capturing, Bubbling};
|
use dom::eventtarget::{AbstractEventTarget, Capturing, Bubbling};
|
||||||
use dom::event::{AbstractEvent, Phase_At_Target, Phase_None, Phase_Bubbling, Phase_Capturing};
|
use dom::event::{AbstractEvent, Phase_At_Target, Phase_None, Phase_Bubbling, Phase_Capturing};
|
||||||
use dom::node::AbstractNode;
|
use dom::node::AbstractNode;
|
||||||
use servo_util::tree::{TreeNodeRef};
|
|
||||||
|
|
||||||
// See http://dom.spec.whatwg.org/#concept-event-dispatch for the full dispatch algorithm
|
// See http://dom.spec.whatwg.org/#concept-event-dispatch for the full dispatch algorithm
|
||||||
pub fn dispatch_event(target: AbstractEventTarget,
|
pub fn dispatch_event(target: AbstractEventTarget,
|
||||||
|
|
|
@ -11,10 +11,8 @@ use dom::node::{AbstractNode, ScriptView, ElementNodeTypeId};
|
||||||
use dom::window::Window;
|
use dom::window::Window;
|
||||||
|
|
||||||
use js::jsapi::JSTracer;
|
use js::jsapi::JSTracer;
|
||||||
|
|
||||||
use servo_util::tree::{TreeNodeRef, ElementLike};
|
|
||||||
|
|
||||||
use std::str::eq_slice;
|
use std::str::eq_slice;
|
||||||
|
use style::TElement;
|
||||||
|
|
||||||
pub struct HTMLDocument {
|
pub struct HTMLDocument {
|
||||||
parent: Document
|
parent: Document
|
||||||
|
|
|
@ -14,7 +14,7 @@ use layout_interface::{ContentBoxQuery, ContentBoxResponse};
|
||||||
use servo_net::image_cache_task;
|
use servo_net::image_cache_task;
|
||||||
use servo_net::image_cache_task::ImageCacheTask;
|
use servo_net::image_cache_task::ImageCacheTask;
|
||||||
use servo_util::url::make_url;
|
use servo_util::url::make_url;
|
||||||
use servo_util::tree::ElementLike;
|
use style::TElement;
|
||||||
|
|
||||||
pub struct HTMLImageElement {
|
pub struct HTMLImageElement {
|
||||||
htmlelement: HTMLElement,
|
htmlelement: HTMLElement,
|
||||||
|
|
|
@ -8,7 +8,7 @@ use dom::document::AbstractDocument;
|
||||||
use dom::element::HTMLScriptElementTypeId;
|
use dom::element::HTMLScriptElementTypeId;
|
||||||
use dom::htmlelement::HTMLElement;
|
use dom::htmlelement::HTMLElement;
|
||||||
use dom::node::{AbstractNode, Node, ScriptView};
|
use dom::node::{AbstractNode, Node, ScriptView};
|
||||||
use servo_util::tree::ElementLike;
|
use style::TElement;
|
||||||
|
|
||||||
pub struct HTMLScriptElement {
|
pub struct HTMLScriptElement {
|
||||||
htmlelement: HTMLElement,
|
htmlelement: HTMLElement,
|
||||||
|
|
|
@ -21,11 +21,11 @@ use dom::text::Text;
|
||||||
|
|
||||||
use js::jsapi::{JSObject, JSContext};
|
use js::jsapi::{JSObject, JSContext};
|
||||||
use servo_util::slot::{MutSlotRef, Slot, SlotRef};
|
use servo_util::slot::{MutSlotRef, Slot, SlotRef};
|
||||||
use servo_util::tree::{TreeNode, TreeNodeRef, TreeNodeRefAsElement};
|
|
||||||
use std::cast::transmute;
|
use std::cast::transmute;
|
||||||
use std::cast;
|
use std::cast;
|
||||||
use std::unstable::raw::Box;
|
use std::unstable::raw::Box;
|
||||||
use std::util;
|
use std::util;
|
||||||
|
use style::TNode;
|
||||||
|
|
||||||
//
|
//
|
||||||
// The basic Node structure
|
// The basic Node structure
|
||||||
|
@ -210,59 +210,17 @@ impl<View> Clone for AbstractNode<View> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<View> TreeNodeRef<Node<View>> for AbstractNode<View> {
|
impl<View> TNode<Element> for AbstractNode<View> {
|
||||||
fn node<'a>(&'a self) -> &'a Node<View> {
|
fn parent_node(&self) -> Option<AbstractNode<View>> {
|
||||||
unsafe {
|
self.node().parent_node
|
||||||
&(*self.obj).data
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mut_node<'a>(&'a self) -> &'a mut Node<View> {
|
fn prev_sibling(&self) -> Option<AbstractNode<View>> {
|
||||||
unsafe {
|
self.node().prev_sibling
|
||||||
&mut (*self.obj).data
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parent_node(node: &Node<View>) -> Option<AbstractNode<View>> {
|
fn next_sibling(&self) -> Option<AbstractNode<View>> {
|
||||||
node.parent_node
|
self.node().next_sibling
|
||||||
}
|
|
||||||
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 is_element(&self) -> bool {
|
fn is_element(&self) -> bool {
|
||||||
|
@ -278,17 +236,34 @@ impl<View> TreeNodeRef<Node<View>> for AbstractNode<View> {
|
||||||
_ => false
|
_ => false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<View> TreeNodeRefAsElement<Node<View>, Element> for AbstractNode<View> {
|
|
||||||
#[inline]
|
#[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)
|
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> {
|
impl<'self, View> AbstractNode<View> {
|
||||||
// Unsafe accessors
|
// Unsafe accessors
|
||||||
|
@ -335,21 +310,6 @@ impl<'self, View> AbstractNode<View> {
|
||||||
self.node().type_id
|
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.
|
/// Returns the previous sibling of this node. Fails if this node is borrowed mutably.
|
||||||
pub fn prev_sibling(self) -> Option<AbstractNode<View>> {
|
pub fn prev_sibling(self) -> Option<AbstractNode<View>> {
|
||||||
self.node().prev_sibling
|
self.node().prev_sibling
|
||||||
|
@ -562,6 +522,14 @@ impl<'self, View> AbstractNode<View> {
|
||||||
format!("{:?}", self.type_id())
|
format!("{:?}", self.type_id())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Convenience accessors
|
||||||
|
//
|
||||||
|
|
||||||
|
fn is_leaf(&self) -> bool {
|
||||||
|
self.first_child().is_none()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn children(&self) -> AbstractNodeChildrenIterator<View> {
|
pub fn children(&self) -> AbstractNodeChildrenIterator<View> {
|
||||||
self.node().children()
|
self.node().children()
|
||||||
}
|
}
|
||||||
|
@ -601,8 +569,123 @@ impl AbstractNode<ScriptView> {
|
||||||
|
|
||||||
document.document().content_changed();
|
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> {
|
impl<View> Iterator<AbstractNode<View>> for AbstractNodeChildrenIterator<View> {
|
||||||
fn next(&mut self) -> Option<AbstractNode<View>> {
|
fn next(&mut self) -> Option<AbstractNode<View>> {
|
||||||
let node = self.current_node;
|
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> {
|
impl<View> Node<View> {
|
||||||
pub fn owner_doc(&self) -> AbstractDocument {
|
pub fn owner_doc(&self) -> AbstractDocument {
|
||||||
self.owner_doc.unwrap()
|
self.owner_doc.unwrap()
|
||||||
|
@ -1215,6 +1378,41 @@ impl Node<ScriptView> {
|
||||||
pub fn HasAttributes(&self) -> bool {
|
pub fn HasAttributes(&self) -> bool {
|
||||||
false
|
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> {
|
impl Reflectable for Node<ScriptView> {
|
||||||
|
|
|
@ -20,7 +20,6 @@ use js::jsapi::JSContext;
|
||||||
use servo_msg::constellation_msg::SubpageId;
|
use servo_msg::constellation_msg::SubpageId;
|
||||||
use servo_net::image_cache_task::ImageCacheTask;
|
use servo_net::image_cache_task::ImageCacheTask;
|
||||||
use servo_net::resource_task::{Load, Payload, Done, ResourceTask, load_whole_resource};
|
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 servo_util::url::make_url;
|
||||||
use std::cast;
|
use std::cast;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
|
@ -29,7 +28,7 @@ use std::comm;
|
||||||
use std::from_str::FromStr;
|
use std::from_str::FromStr;
|
||||||
use std::str::eq_slice;
|
use std::str::eq_slice;
|
||||||
use std::str;
|
use std::str;
|
||||||
use style::Stylesheet;
|
use style::{Stylesheet, TElement};
|
||||||
|
|
||||||
macro_rules! handle_element(
|
macro_rules! handle_element(
|
||||||
($document: expr,
|
($document: expr,
|
||||||
|
|
|
@ -45,7 +45,6 @@ use servo_msg::constellation_msg;
|
||||||
use servo_net::image_cache_task::ImageCacheTask;
|
use servo_net::image_cache_task::ImageCacheTask;
|
||||||
use servo_net::resource_task::ResourceTask;
|
use servo_net::resource_task::ResourceTask;
|
||||||
use servo_util::geometry::to_frac_px;
|
use servo_util::geometry::to_frac_px;
|
||||||
use servo_util::tree::{TreeNode, TreeNodeRef, ElementLike};
|
|
||||||
use servo_util::url::make_url;
|
use servo_util::url::make_url;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::comm::{Port, SharedChan};
|
use std::comm::{Port, SharedChan};
|
||||||
|
@ -54,6 +53,7 @@ use std::ptr;
|
||||||
use std::str::eq_slice;
|
use std::str::eq_slice;
|
||||||
use std::task::{spawn_sched, SingleThreaded};
|
use std::task::{spawn_sched, SingleThreaded};
|
||||||
use std::util::replace;
|
use std::util::replace;
|
||||||
|
use style::{TElement, TNode};
|
||||||
|
|
||||||
/// Messages used to control the script task.
|
/// Messages used to control the script task.
|
||||||
pub enum ScriptMsg {
|
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
|
* 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/. */
|
* 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::arc::Arc;
|
||||||
use extra::sort::tim_sort;
|
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 selectors::*;
|
||||||
use stylesheets::{Stylesheet, iter_style_rules};
|
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 {
|
pub enum StylesheetOrigin {
|
||||||
UserAgentOrigin,
|
UserAgentOrigin,
|
||||||
|
@ -67,16 +66,15 @@ impl SelectorMap {
|
||||||
///
|
///
|
||||||
/// Extract matching rules as per node's ID, classes, tag name, etc..
|
/// Extract matching rules as per node's ID, classes, tag name, etc..
|
||||||
/// Sort the Rules at the end to maintain cascading order.
|
/// Sort the Rules at the end to maintain cascading order.
|
||||||
fn get_all_matching_rules<N:TreeNode<T>,
|
fn get_all_matching_rules<E:TElement,
|
||||||
T:TreeNodeRefAsElement<N,E>,
|
N:TNode<E>>(
|
||||||
E:ElementLike>(
|
|
||||||
&self,
|
&self,
|
||||||
node: &T,
|
node: &N,
|
||||||
pseudo_element: Option<PseudoElement>,
|
pseudo_element: Option<PseudoElement>,
|
||||||
matching_rules_list: &mut ~[Rule]) {
|
matching_rules_list: &mut ~[Rule]) {
|
||||||
// At the end, we're going to sort the rules that we added, so remember where we began.
|
// 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();
|
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") {
|
match element.get_attr(None, "id") {
|
||||||
Some(id) => {
|
Some(id) => {
|
||||||
SelectorMap::get_matching_rules_from_hash(node,
|
SelectorMap::get_matching_rules_from_hash(node,
|
||||||
|
@ -118,10 +116,9 @@ impl SelectorMap {
|
||||||
tim_sort(matching_rules_list.mut_slice_from(init_len));
|
tim_sort(matching_rules_list.mut_slice_from(init_len));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_matching_rules_from_hash<N:TreeNode<T>,
|
fn get_matching_rules_from_hash<E:TElement,
|
||||||
T:TreeNodeRefAsElement<N,E>,
|
N:TNode<E>>(
|
||||||
E:ElementLike>(
|
node: &N,
|
||||||
node: &T,
|
|
||||||
pseudo_element: Option<PseudoElement>,
|
pseudo_element: Option<PseudoElement>,
|
||||||
hash: &HashMap<~str,~[Rule]>,
|
hash: &HashMap<~str,~[Rule]>,
|
||||||
key: &str,
|
key: &str,
|
||||||
|
@ -135,10 +132,9 @@ impl SelectorMap {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds rules in `rules` that match `node` to the `matching_rules` list.
|
/// Adds rules in `rules` that match `node` to the `matching_rules` list.
|
||||||
fn get_matching_rules<N:TreeNode<T>,
|
fn get_matching_rules<E:TElement,
|
||||||
T:TreeNodeRefAsElement<N,E>,
|
N:TNode<E>>(
|
||||||
E:ElementLike>(
|
node: &N,
|
||||||
node: &T,
|
|
||||||
pseudo_element: Option<PseudoElement>,
|
pseudo_element: Option<PseudoElement>,
|
||||||
rules: &[Rule],
|
rules: &[Rule],
|
||||||
matching_rules: &mut ~[Rule]) {
|
matching_rules: &mut ~[Rule]) {
|
||||||
|
@ -301,11 +297,10 @@ impl Stylist {
|
||||||
|
|
||||||
/// Returns the applicable CSS declarations for the given element. This corresponds to
|
/// Returns the applicable CSS declarations for the given element. This corresponds to
|
||||||
/// `ElementRuleCollector` in WebKit.
|
/// `ElementRuleCollector` in WebKit.
|
||||||
pub fn get_applicable_declarations<N:TreeNode<T>,
|
pub fn get_applicable_declarations<E:TElement,
|
||||||
T:TreeNodeRefAsElement<N,E>,
|
N:TNode<E>>(
|
||||||
E:ElementLike>(
|
|
||||||
&self,
|
&self,
|
||||||
element: &T,
|
element: &N,
|
||||||
style_attribute: Option<&PropertyDeclarationBlock>,
|
style_attribute: Option<&PropertyDeclarationBlock>,
|
||||||
pseudo_element: Option<PseudoElement>)
|
pseudo_element: Option<PseudoElement>)
|
||||||
-> ~[Arc<~[PropertyDeclaration]>] {
|
-> ~[Arc<~[PropertyDeclaration]>] {
|
||||||
|
@ -421,7 +416,6 @@ struct Rule {
|
||||||
stylesheet_index: uint,
|
stylesheet_index: uint,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl Ord for Rule {
|
impl Ord for Rule {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn lt(&self, other: &Rule) -> bool {
|
fn lt(&self, other: &Rule) -> bool {
|
||||||
|
@ -431,16 +425,19 @@ impl Ord for Rule {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn matches_selector<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: ElementLike>(
|
fn matches_selector<E:TElement,
|
||||||
selector: &Selector, element: &T, pseudo_element: Option<PseudoElement>) -> bool {
|
N:TNode<E>>(
|
||||||
|
selector: &Selector,
|
||||||
|
element: &N,
|
||||||
|
pseudo_element: Option<PseudoElement>)
|
||||||
|
-> bool {
|
||||||
selector.pseudo_element == pseudo_element &&
|
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>(
|
fn matches_compound_selector<E:TElement,N:TNode<E>>(selector: &CompoundSelector, element: &N)
|
||||||
selector: &CompoundSelector, element: &T) -> bool {
|
-> bool {
|
||||||
if !do selector.simple_selectors.iter().all |simple_selector| {
|
if !do selector.simple_selectors.iter().all |simple_selector| {
|
||||||
matches_simple_selector(simple_selector, element)
|
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),
|
NextSibling => (true, true),
|
||||||
LaterSibling => (true, false),
|
LaterSibling => (true, false),
|
||||||
};
|
};
|
||||||
let mut node = element.clone();
|
let mut node = (*element).clone();
|
||||||
loop {
|
loop {
|
||||||
let next_node = if siblings {
|
let next_node = if siblings {
|
||||||
node.node().prev_sibling()
|
node.prev_sibling()
|
||||||
} else {
|
} else {
|
||||||
node.node().parent_node()
|
node.parent_node()
|
||||||
};
|
};
|
||||||
match next_node {
|
match next_node {
|
||||||
None => return false,
|
None => return false,
|
||||||
|
@ -479,25 +476,24 @@ fn matches_compound_selector<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: E
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn matches_simple_selector<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: ElementLike>(
|
fn matches_simple_selector<E:TElement,N:TNode<E>>(selector: &SimpleSelector, element: &N) -> bool {
|
||||||
selector: &SimpleSelector, element: &T) -> bool {
|
|
||||||
match *selector {
|
match *selector {
|
||||||
// TODO: case-sensitivity depends on the document type
|
// TODO: case-sensitivity depends on the document type
|
||||||
// TODO: intern element names
|
// TODO: intern element names
|
||||||
LocalNameSelector(ref name) => {
|
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())
|
element.get_local_name().eq_ignore_ascii_case(name.as_slice())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NamespaceSelector(ref url) => {
|
NamespaceSelector(ref url) => {
|
||||||
do element.with_imm_element_like |element: &E| {
|
do element.with_element |element: &E| {
|
||||||
element.get_namespace_url() == url.as_slice()
|
element.get_namespace_url() == url.as_slice()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: case-sensitivity depends on the document type and quirks mode
|
// TODO: case-sensitivity depends on the document type and quirks mode
|
||||||
// TODO: cache and intern IDs on elements.
|
// TODO: cache and intern IDs on elements.
|
||||||
IDSelector(ref id) => {
|
IDSelector(ref id) => {
|
||||||
do element.with_imm_element_like |element: &E| {
|
do element.with_element |element: &E| {
|
||||||
match element.get_attr(None, "id") {
|
match element.get_attr(None, "id") {
|
||||||
Some(attr) => str::eq_slice(attr, *id),
|
Some(attr) => str::eq_slice(attr, *id),
|
||||||
None => false
|
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.
|
// TODO: cache and intern classe names on elements.
|
||||||
ClassSelector(ref class) => {
|
ClassSelector(ref class) => {
|
||||||
do element.with_imm_element_like |element: &E| {
|
do element.with_element |element: &E| {
|
||||||
match element.get_attr(None, "class") {
|
match element.get_attr(None, "class") {
|
||||||
None => false,
|
None => false,
|
||||||
// TODO: case-sensitivity depends on the document type and quirks mode
|
// 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 => {
|
AnyLink => {
|
||||||
do element.with_imm_element_like |element: &E| {
|
do element.with_element |element: &E| {
|
||||||
element.get_link().is_some()
|
element.get_link().is_some()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Link => {
|
Link => {
|
||||||
do element.with_imm_element_like |element: &E| {
|
do element.with_element |element: &E| {
|
||||||
match element.get_link() {
|
match element.get_link() {
|
||||||
Some(url) => !url_is_visited(url),
|
Some(url) => !url_is_visited(url),
|
||||||
None => false,
|
None => false,
|
||||||
|
@ -550,7 +546,7 @@ fn matches_simple_selector<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: Ele
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Visited => {
|
Visited => {
|
||||||
do element.with_imm_element_like |element: &E| {
|
do element.with_element |element: &E| {
|
||||||
match element.get_link() {
|
match element.get_link() {
|
||||||
Some(url) => url_is_visited(url),
|
Some(url) => url_is_visited(url),
|
||||||
None => false,
|
None => false,
|
||||||
|
@ -589,12 +585,18 @@ fn url_is_visited(_url: &str) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn matches_generic_nth_child<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: ElementLike>(
|
fn matches_generic_nth_child<E:TElement,
|
||||||
element: &T, a: i32, b: i32, is_of_type: bool, is_from_end: bool) -> bool {
|
N:TNode<E>>(
|
||||||
|
element: &N,
|
||||||
|
a: i32,
|
||||||
|
b: i32,
|
||||||
|
is_of_type: bool,
|
||||||
|
is_from_end: bool)
|
||||||
|
-> bool {
|
||||||
let mut node = element.clone();
|
let mut node = element.clone();
|
||||||
// fail if we can't find a parent or if the node is the root element
|
// fail if we can't find a parent or if the node is the root element
|
||||||
// of the document (Cf. Selectors Level 3)
|
// of the document (Cf. Selectors Level 3)
|
||||||
match node.node().parent_node() {
|
match node.parent_node() {
|
||||||
Some(parent) => if parent.is_document() {
|
Some(parent) => if parent.is_document() {
|
||||||
return false;
|
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_local_name = "";
|
||||||
let mut element_namespace = "";
|
let mut element_namespace = "";
|
||||||
if is_of_type {
|
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_local_name = element.get_local_name();
|
||||||
element_namespace = element.get_namespace_url();
|
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;
|
let mut index = 1;
|
||||||
loop {
|
loop {
|
||||||
if is_from_end {
|
if is_from_end {
|
||||||
match node.node().next_sibling() {
|
match node.next_sibling() {
|
||||||
None => break,
|
None => break,
|
||||||
Some(next_sibling) => node = next_sibling
|
Some(next_sibling) => node = next_sibling
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match node.node().prev_sibling() {
|
match node.prev_sibling() {
|
||||||
None => break,
|
None => break,
|
||||||
Some(prev_sibling) => node = prev_sibling
|
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 node.is_element() {
|
||||||
if is_of_type {
|
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() &&
|
if element_local_name == node.get_local_name() &&
|
||||||
element_namespace == node.get_namespace_url() {
|
element_namespace == node.get_namespace_url() {
|
||||||
index += 1;
|
index += 1;
|
||||||
|
@ -648,27 +650,25 @@ fn matches_generic_nth_child<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: E
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn matches_root<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: ElementLike>(
|
fn matches_root<E:TElement,N:TNode<E>>(element: &N) -> bool {
|
||||||
element: &T) -> bool {
|
match element.parent_node() {
|
||||||
match element.node().parent_node() {
|
|
||||||
Some(parent) => parent.is_document(),
|
Some(parent) => parent.is_document(),
|
||||||
None => false
|
None => false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn matches_first_child<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: ElementLike>(
|
fn matches_first_child<E:TElement,N:TNode<E>>(element: &N) -> bool {
|
||||||
element: &T) -> bool {
|
|
||||||
let mut node = element.clone();
|
let mut node = element.clone();
|
||||||
loop {
|
loop {
|
||||||
match node.node().prev_sibling() {
|
match node.prev_sibling() {
|
||||||
Some(prev_sibling) => {
|
Some(prev_sibling) => {
|
||||||
node = prev_sibling;
|
node = prev_sibling;
|
||||||
if node.is_element() {
|
if node.is_element() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None => match node.node().parent_node() {
|
None => match node.parent_node() {
|
||||||
// Selectors level 3 says :first-child does not match the
|
// Selectors level 3 says :first-child does not match the
|
||||||
// root of the document; Warning, level 4 says, for the time
|
// root of the document; Warning, level 4 says, for the time
|
||||||
// being, the contrary...
|
// being, the contrary...
|
||||||
|
@ -680,18 +680,17 @@ fn matches_first_child<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: Element
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn matches_last_child<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: ElementLike>(
|
fn matches_last_child<E:TElement,N:TNode<E>>(element: &N) -> bool {
|
||||||
element: &T) -> bool {
|
|
||||||
let mut node = element.clone();
|
let mut node = element.clone();
|
||||||
loop {
|
loop {
|
||||||
match node.node().next_sibling() {
|
match node.next_sibling() {
|
||||||
Some(next_sibling) => {
|
Some(next_sibling) => {
|
||||||
node = next_sibling;
|
node = next_sibling;
|
||||||
if node.is_element() {
|
if node.is_element() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None => match node.node().parent_node() {
|
None => match node.parent_node() {
|
||||||
// Selectors level 3 says :last-child does not match the
|
// Selectors level 3 says :last-child does not match the
|
||||||
// root of the document; Warning, level 4 says, for the time
|
// root of the document; Warning, level 4 says, for the time
|
||||||
// being, the contrary...
|
// being, the contrary...
|
||||||
|
@ -703,9 +702,13 @@ fn matches_last_child<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: ElementL
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn match_attribute<N: TreeNode<T>, T: TreeNodeRefAsElement<N, E>, E: ElementLike>(
|
fn match_attribute<E:TElement,
|
||||||
attr: &AttrSelector, element: &T, f: &fn(&str)-> bool) -> bool {
|
N:TNode<E>>(
|
||||||
do element.with_imm_element_like |element: &E| {
|
attr: &AttrSelector,
|
||||||
|
element: &N,
|
||||||
|
f: &fn(&str) -> bool)
|
||||||
|
-> bool {
|
||||||
|
do element.with_element |element: &E| {
|
||||||
// FIXME: avoid .clone() here? See #1367
|
// FIXME: avoid .clone() here? See #1367
|
||||||
match element.get_attr(attr.namespace.clone(), attr.name) {
|
match element.get_attr(attr.namespace.clone(), attr.name) {
|
||||||
None => false,
|
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::{cascade, PropertyDeclaration, ComputedValues, computed_values};
|
||||||
pub use properties::{PropertyDeclarationBlock, parse_style_attribute}; // Style attributes
|
pub use properties::{PropertyDeclarationBlock, parse_style_attribute}; // Style attributes
|
||||||
pub use errors::with_errors_silenced;
|
pub use errors::with_errors_silenced;
|
||||||
|
pub use node::{TElement, TNode};
|
||||||
|
|
||||||
mod stylesheets;
|
mod stylesheets;
|
||||||
mod errors;
|
mod errors;
|
||||||
|
@ -32,5 +33,6 @@ mod selectors;
|
||||||
mod selector_matching;
|
mod selector_matching;
|
||||||
mod properties;
|
mod properties;
|
||||||
mod namespaces;
|
mod namespaces;
|
||||||
|
mod node;
|
||||||
mod media_queries;
|
mod media_queries;
|
||||||
mod parsing_utils;
|
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 range;
|
||||||
pub mod slot;
|
pub mod slot;
|
||||||
pub mod time;
|
pub mod time;
|
||||||
pub mod tree;
|
|
||||||
pub mod url;
|
pub mod url;
|
||||||
pub mod vec;
|
pub mod vec;
|
||||||
pub mod debug;
|
pub mod debug;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue