mirror of
https://github.com/servo/servo.git
synced 2025-08-04 21:20:23 +01:00
dom: Document the node structure better and remove the node pointer stitching routines
This commit is contained in:
parent
58679216b3
commit
6a6cad1e39
4 changed files with 94 additions and 119 deletions
|
@ -2,9 +2,7 @@
|
|||
* 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/. */
|
||||
|
||||
//
|
||||
// The core DOM types. Defines the basic DOM hierarchy as well as all the HTML elements.
|
||||
//
|
||||
//! The core DOM types. Defines the basic DOM hierarchy as well as all the HTML elements.
|
||||
|
||||
use content::content_task::global_content;
|
||||
use dom::bindings::codegen;
|
||||
|
@ -36,28 +34,47 @@ pub struct AbstractNode {
|
|||
}
|
||||
|
||||
impl Eq for AbstractNode {
|
||||
fn eq(&self, other: &AbstractNode) -> bool { self.obj == other.obj }
|
||||
fn ne(&self, other: &AbstractNode) -> bool { self.obj != other.obj }
|
||||
fn eq(&self, other: &AbstractNode) -> bool {
|
||||
self.obj == other.obj
|
||||
}
|
||||
fn ne(&self, other: &AbstractNode) -> bool {
|
||||
self.obj != other.obj
|
||||
}
|
||||
}
|
||||
|
||||
/// An HTML node.
|
||||
pub struct Node {
|
||||
/// The JavaScript wrapper for this node.
|
||||
wrapper: WrapperCache,
|
||||
|
||||
/// The type of node that this is.
|
||||
type_id: NodeTypeId,
|
||||
|
||||
abstract: Option<AbstractNode>,
|
||||
|
||||
/// The parent of this node.
|
||||
parent_node: Option<AbstractNode>,
|
||||
|
||||
/// The first child of this node.
|
||||
first_child: Option<AbstractNode>,
|
||||
|
||||
/// The last child of this node.
|
||||
last_child: Option<AbstractNode>,
|
||||
|
||||
/// The next sibling of this node.
|
||||
next_sibling: Option<AbstractNode>,
|
||||
|
||||
/// The previous sibling of this node.
|
||||
prev_sibling: Option<AbstractNode>,
|
||||
|
||||
/// The document that this node belongs to.
|
||||
owner_doc: Option<@mut Document>,
|
||||
|
||||
// You must not touch this if you are not layout.
|
||||
/// Layout information. You must not touch this if you are not layout.
|
||||
priv layout_data: Option<@mut LayoutData>
|
||||
}
|
||||
|
||||
/// The different types of nodes.
|
||||
#[deriving(Eq)]
|
||||
pub enum NodeTypeId {
|
||||
DoctypeNodeTypeId,
|
||||
|
@ -70,12 +87,17 @@ pub enum NodeTypeId {
|
|||
// Auxiliary layout data
|
||||
//
|
||||
|
||||
/// Data that layout associates with a node.
|
||||
pub struct LayoutData {
|
||||
/// The results of CSS styling for this node.
|
||||
style: Option<CompleteSelectResults>,
|
||||
|
||||
/// The CSS flow that this node is associated with.
|
||||
flow: Option<FlowContext>,
|
||||
}
|
||||
|
||||
impl LayoutData {
|
||||
/// Creates new layout data.
|
||||
pub fn new() -> LayoutData {
|
||||
LayoutData {
|
||||
style: None,
|
||||
|
@ -88,6 +110,7 @@ impl LayoutData {
|
|||
// Basic node types
|
||||
//
|
||||
|
||||
/// The `DOCTYPE` tag.
|
||||
pub struct Doctype {
|
||||
parent: Node,
|
||||
name: ~str,
|
||||
|
@ -97,6 +120,7 @@ pub struct Doctype {
|
|||
}
|
||||
|
||||
impl Doctype {
|
||||
/// Creates a new `DOCTYPE` tag.
|
||||
pub fn new(name: ~str,
|
||||
public_id: Option<~str>,
|
||||
system_id: Option<~str>,
|
||||
|
@ -112,11 +136,13 @@ impl Doctype {
|
|||
}
|
||||
}
|
||||
|
||||
/// An HTML comment.
|
||||
pub struct Comment {
|
||||
parent: CharacterData,
|
||||
}
|
||||
|
||||
impl Comment {
|
||||
/// Creates a new HTML comment.
|
||||
pub fn new(text: ~str) -> Comment {
|
||||
Comment {
|
||||
parent: CharacterData::new(CommentNodeTypeId, text)
|
||||
|
@ -124,11 +150,13 @@ impl Comment {
|
|||
}
|
||||
}
|
||||
|
||||
/// An HTML text node.
|
||||
pub struct Text {
|
||||
parent: CharacterData,
|
||||
}
|
||||
|
||||
impl Text {
|
||||
/// Creates a new HTML text node.
|
||||
pub fn new(text: ~str) -> Text {
|
||||
Text {
|
||||
parent: CharacterData::new(TextNodeTypeId, text)
|
||||
|
@ -187,118 +215,56 @@ impl TreeNodeRef<Node> for AbstractNode {
|
|||
}
|
||||
}
|
||||
|
||||
pub impl AbstractNode {
|
||||
impl AbstractNode {
|
||||
// Convenience accessors
|
||||
|
||||
/// Returns the type ID of this node.
|
||||
fn type_id(self) -> NodeTypeId { self.with_imm_node(|n| n.type_id) }
|
||||
/// Returns the type ID of this node. Fails if this node is borrowed mutably.
|
||||
pub fn type_id(self) -> NodeTypeId {
|
||||
self.with_imm_node(|n| n.type_id)
|
||||
}
|
||||
|
||||
/// Returns the parent node of this node.
|
||||
fn parent_node(self) -> Option<AbstractNode> { self.with_imm_node(|n| n.parent_node) }
|
||||
/// Returns the parent node of this node. Fails if this node is borrowed mutably.
|
||||
pub fn parent_node(self) -> Option<AbstractNode> {
|
||||
self.with_imm_node(|n| n.parent_node)
|
||||
}
|
||||
|
||||
/// Returns the first child of this node.
|
||||
fn first_child(self) -> Option<AbstractNode> { self.with_imm_node(|n| n.first_child) }
|
||||
/// Returns the first child of this node. Fails if this node is borrowed mutably.
|
||||
pub fn first_child(self) -> Option<AbstractNode> {
|
||||
self.with_imm_node(|n| n.first_child)
|
||||
}
|
||||
|
||||
/// Returns the last child of this node.
|
||||
fn last_child(self) -> Option<AbstractNode> { self.with_imm_node(|n| n.last_child) }
|
||||
/// Returns the last child of this node. Fails if this node is borrowed mutably.
|
||||
pub fn last_child(self) -> Option<AbstractNode> {
|
||||
self.with_imm_node(|n| n.last_child)
|
||||
}
|
||||
|
||||
/// Returns the previous sibling of this node.
|
||||
fn prev_sibling(self) -> Option<AbstractNode> { self.with_imm_node(|n| n.prev_sibling) }
|
||||
/// Returns the previous sibling of this node. Fails if this node is borrowed mutably.
|
||||
pub fn prev_sibling(self) -> Option<AbstractNode> {
|
||||
self.with_imm_node(|n| n.prev_sibling)
|
||||
}
|
||||
|
||||
/// Returns the next sibling of this node.
|
||||
fn next_sibling(self) -> Option<AbstractNode> { self.with_imm_node(|n| n.next_sibling) }
|
||||
/// Returns the next sibling of this node. Fails if this node is borrowed mutably.
|
||||
pub fn next_sibling(self) -> Option<AbstractNode> {
|
||||
self.with_imm_node(|n| n.next_sibling)
|
||||
}
|
||||
|
||||
// NB: You must not call these if you are not layout. We should do something with scoping to
|
||||
// ensure this.
|
||||
fn layout_data(self) -> @mut LayoutData {
|
||||
pub fn layout_data(self) -> @mut LayoutData {
|
||||
self.with_imm_node(|n| n.layout_data.get())
|
||||
}
|
||||
fn has_layout_data(self) -> bool {
|
||||
pub fn has_layout_data(self) -> bool {
|
||||
self.with_imm_node(|n| n.layout_data.is_some())
|
||||
}
|
||||
fn set_layout_data(self, data: @mut LayoutData) {
|
||||
pub fn set_layout_data(self, data: @mut LayoutData) {
|
||||
self.with_mut_node(|n| n.layout_data = Some(data))
|
||||
}
|
||||
|
||||
//
|
||||
// Tree operations
|
||||
//
|
||||
// FIXME: Fold this into util::tree.
|
||||
//
|
||||
|
||||
fn is_leaf(self) -> bool { self.first_child().is_none() }
|
||||
|
||||
// Invariant: `child` is disconnected from the document.
|
||||
fn append_child(self, child: AbstractNode) {
|
||||
assert!(self != child);
|
||||
|
||||
do self.with_mut_node |parent_n| {
|
||||
do child.with_mut_node |child_n| {
|
||||
assert!(child_n.parent_node.is_none());
|
||||
assert!(child_n.prev_sibling.is_none());
|
||||
assert!(child_n.next_sibling.is_none());
|
||||
|
||||
child_n.parent_node = Some(self);
|
||||
|
||||
match parent_n.last_child {
|
||||
None => parent_n.first_child = Some(child),
|
||||
Some(last_child) => {
|
||||
do last_child.with_mut_node |last_child_n| {
|
||||
assert!(last_child_n.next_sibling.is_none());
|
||||
last_child_n.next_sibling = Some(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
child_n.prev_sibling = parent_n.last_child;
|
||||
parent_n.last_child = Some(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Tree traversal
|
||||
//
|
||||
// FIXME: Fold this into util::tree.
|
||||
//
|
||||
|
||||
fn each_child(self, f: &fn(AbstractNode) -> bool) {
|
||||
let mut current_opt = self.first_child();
|
||||
while !current_opt.is_none() {
|
||||
let current = current_opt.get();
|
||||
if !f(current) {
|
||||
break;
|
||||
}
|
||||
current_opt = current.next_sibling();
|
||||
}
|
||||
}
|
||||
|
||||
fn traverse_preorder(self, f: &fn(AbstractNode) -> bool) -> bool {
|
||||
if !f(self) {
|
||||
return false;
|
||||
}
|
||||
for self.each_child |kid| {
|
||||
if !kid.traverse_preorder(f) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn traverse_postorder(self, f: &fn(AbstractNode) -> bool) -> bool {
|
||||
for self.each_child |kid| {
|
||||
if !kid.traverse_postorder(f) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
f(self)
|
||||
}
|
||||
|
||||
//
|
||||
// Downcasting borrows
|
||||
//
|
||||
|
||||
fn transmute<T, R>(self, f: &fn(&T) -> R) -> R {
|
||||
pub fn transmute<T, R>(self, f: &fn(&T) -> R) -> R {
|
||||
unsafe {
|
||||
let node_box: *mut bindings::utils::rust_box<Node> = transmute(self.obj);
|
||||
let node = &mut (*node_box).payload;
|
||||
|
@ -311,7 +277,7 @@ pub impl AbstractNode {
|
|||
}
|
||||
}
|
||||
|
||||
fn transmute_mut<T, R>(self, f: &fn(&mut T) -> R) -> R {
|
||||
pub fn transmute_mut<T, R>(self, f: &fn(&mut T) -> R) -> R {
|
||||
unsafe {
|
||||
let node_box: *mut bindings::utils::rust_box<Node> = transmute(self.obj);
|
||||
let node = &mut (*node_box).payload;
|
||||
|
@ -324,25 +290,27 @@ pub impl AbstractNode {
|
|||
}
|
||||
}
|
||||
|
||||
fn with_imm_node<R>(self, f: &fn(&Node) -> R) -> R {
|
||||
pub fn with_imm_node<R>(self, f: &fn(&Node) -> R) -> R {
|
||||
self.transmute(f)
|
||||
}
|
||||
|
||||
fn with_mut_node<R>(self, f: &fn(&mut Node) -> R) -> R {
|
||||
pub fn with_mut_node<R>(self, f: &fn(&mut Node) -> R) -> R {
|
||||
self.transmute_mut(f)
|
||||
}
|
||||
|
||||
fn is_text(self) -> bool { self.type_id() == TextNodeTypeId }
|
||||
pub fn is_text(self) -> bool {
|
||||
self.type_id() == TextNodeTypeId
|
||||
}
|
||||
|
||||
// FIXME: This should be doing dynamic borrow checking for safety.
|
||||
fn with_imm_text<R>(self, f: &fn(&Text) -> R) -> R {
|
||||
pub fn with_imm_text<R>(self, f: &fn(&Text) -> R) -> R {
|
||||
if !self.is_text() {
|
||||
fail!(~"node is not text");
|
||||
}
|
||||
self.transmute(f)
|
||||
}
|
||||
|
||||
fn is_element(self) -> bool {
|
||||
pub fn is_element(self) -> bool {
|
||||
match self.type_id() {
|
||||
ElementNodeTypeId(*) => true,
|
||||
_ => false
|
||||
|
@ -350,7 +318,7 @@ pub impl AbstractNode {
|
|||
}
|
||||
|
||||
// FIXME: This should be doing dynamic borrow checking for safety.
|
||||
fn with_imm_element<R>(self, f: &fn(&Element) -> R) -> R {
|
||||
pub fn with_imm_element<R>(self, f: &fn(&Element) -> R) -> R {
|
||||
if !self.is_element() {
|
||||
fail!(~"node is not an element");
|
||||
}
|
||||
|
@ -358,40 +326,40 @@ pub impl AbstractNode {
|
|||
}
|
||||
|
||||
// FIXME: This should be doing dynamic borrow checking for safety.
|
||||
fn as_mut_element<R>(self, f: &fn(&mut Element) -> R) -> R {
|
||||
pub fn as_mut_element<R>(self, f: &fn(&mut Element) -> R) -> R {
|
||||
if !self.is_element() {
|
||||
fail!(~"node is not an element");
|
||||
}
|
||||
self.transmute_mut(f)
|
||||
}
|
||||
|
||||
fn is_image_element(self) -> bool {
|
||||
pub fn is_image_element(self) -> bool {
|
||||
self.type_id() == ElementNodeTypeId(HTMLImageElementTypeId)
|
||||
}
|
||||
|
||||
fn with_imm_image_element<R>(self, f: &fn(&HTMLImageElement) -> R) -> R {
|
||||
pub fn with_imm_image_element<R>(self, f: &fn(&HTMLImageElement) -> R) -> R {
|
||||
if !self.is_image_element() {
|
||||
fail!(~"node is not an image element");
|
||||
}
|
||||
self.transmute(f)
|
||||
}
|
||||
|
||||
fn with_mut_image_element<R>(self, f: &fn(&mut HTMLImageElement) -> R) -> R {
|
||||
pub fn with_mut_image_element<R>(self, f: &fn(&mut HTMLImageElement) -> R) -> R {
|
||||
if !self.is_image_element() {
|
||||
fail!(~"node is not an image element");
|
||||
}
|
||||
self.transmute_mut(f)
|
||||
}
|
||||
|
||||
fn is_style_element(self) -> bool {
|
||||
pub fn is_style_element(self) -> bool {
|
||||
self.type_id() == ElementNodeTypeId(HTMLStyleElementTypeId)
|
||||
}
|
||||
|
||||
unsafe fn raw_object(self) -> *mut Node {
|
||||
pub unsafe fn raw_object(self) -> *mut Node {
|
||||
self.obj
|
||||
}
|
||||
|
||||
fn from_raw(raw: *mut Node) -> AbstractNode {
|
||||
pub fn from_raw(raw: *mut Node) -> AbstractNode {
|
||||
AbstractNode {
|
||||
obj: raw
|
||||
}
|
||||
|
|
|
@ -14,8 +14,9 @@ use util::task::spawn_conversation;
|
|||
use core::cell::Cell;
|
||||
use core::comm::{Chan, Port, SharedChan};
|
||||
use core::str::eq_slice;
|
||||
use servo_util::url::make_url;
|
||||
use hubbub::hubbub;
|
||||
use servo_util::tree::TreeUtils;
|
||||
use servo_util::url::make_url;
|
||||
use std::net::url::Url;
|
||||
use std::net::url;
|
||||
|
||||
|
@ -336,7 +337,7 @@ pub fn parse_html(url: Url,
|
|||
debug!("append child %x %x", cast::transmute(parent), cast::transmute(child));
|
||||
let parent: AbstractNode = NodeWrapping::from_hubbub_node(parent);
|
||||
let child: AbstractNode = NodeWrapping::from_hubbub_node(child);
|
||||
parent.append_child(child);
|
||||
parent.add_child(child);
|
||||
append_hook(parent, child);
|
||||
}
|
||||
child
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
* 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/. */
|
||||
|
||||
/**
|
||||
Code for managing the DOM aux pointer
|
||||
*/
|
||||
//! Code for managing the layout data in the DOM.
|
||||
|
||||
use dom::node::{AbstractNode, LayoutData};
|
||||
|
||||
use servo_util::tree::TreeUtils;
|
||||
|
||||
pub trait LayoutAuxMethods {
|
||||
fn initialize_layout_data(self) -> Option<@mut LayoutData>;
|
||||
fn initialize_style_for_subtree(self, refs: &mut ~[@mut LayoutData]);
|
||||
|
@ -36,5 +36,5 @@ impl LayoutAuxMethods for AbstractNode {
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -121,6 +121,8 @@ impl BoxGenerator {
|
|||
// depending on flow, make a box for this node.
|
||||
match self.flow {
|
||||
InlineFlow(inline) => {
|
||||
use servo_util::tree::TreeUtils; // For `is_leaf()`.
|
||||
|
||||
let mut inline = &mut *inline;
|
||||
let node_range_start = inline.boxes.len();
|
||||
self.range_stack.push(node_range_start);
|
||||
|
@ -336,9 +338,13 @@ pub impl LayoutTreeBuilder {
|
|||
debug!("point b: %s", cur_node.debug_str());
|
||||
|
||||
// recurse on child nodes.
|
||||
{
|
||||
use servo_util::tree::TreeUtils; // For `each_child()`.
|
||||
|
||||
for cur_node.each_child |child_node| {
|
||||
self.construct_recursively(layout_ctx, child_node, &mut this_ctx);
|
||||
}
|
||||
}
|
||||
|
||||
this_ctx.default_collector.pop_node(layout_ctx, self, cur_node);
|
||||
self.simplify_children_of_flow(layout_ctx, &this_ctx);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue