mirror of
https://github.com/servo/servo.git
synced 2025-08-06 06:00:15 +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
|
@ -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> {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue