mirror of
https://github.com/servo/servo.git
synced 2025-06-19 14:48:59 +01:00
layout: Add a lifetime to LayoutNode
to prevent layout from stuffing
them into evil places.
This commit is contained in:
parent
ee9873bdb5
commit
c506e52c7c
8 changed files with 77 additions and 46 deletions
|
@ -4,18 +4,19 @@
|
||||||
|
|
||||||
// High-level interface to CSS selector matching.
|
// High-level interface to CSS selector matching.
|
||||||
|
|
||||||
use std::cell::Cell;
|
|
||||||
use std::comm;
|
|
||||||
use std::task;
|
|
||||||
use std::vec;
|
|
||||||
use std::rt;
|
|
||||||
use extra::arc::{Arc, RWArc};
|
|
||||||
|
|
||||||
use css::node_style::StyledNode;
|
use css::node_style::StyledNode;
|
||||||
use layout::incremental;
|
use layout::incremental;
|
||||||
use layout::util::LayoutDataAccess;
|
use layout::util::LayoutDataAccess;
|
||||||
|
|
||||||
|
use extra::arc::{Arc, RWArc};
|
||||||
use script::dom::node::LayoutNode;
|
use script::dom::node::LayoutNode;
|
||||||
|
use std::cast;
|
||||||
|
use std::cell::Cell;
|
||||||
|
use std::comm;
|
||||||
|
use std::libc::uintptr_t;
|
||||||
|
use std::rt;
|
||||||
|
use std::task;
|
||||||
|
use std::vec;
|
||||||
use style::{TNode, Stylist, cascade};
|
use style::{TNode, Stylist, cascade};
|
||||||
|
|
||||||
pub trait MatchMethods {
|
pub trait MatchMethods {
|
||||||
|
@ -26,7 +27,7 @@ pub trait MatchMethods {
|
||||||
fn cascade_subtree(&self, parent: Option<LayoutNode>);
|
fn cascade_subtree(&self, parent: Option<LayoutNode>);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MatchMethods for LayoutNode {
|
impl<'self> MatchMethods for LayoutNode<'self> {
|
||||||
fn match_node(&self, stylist: &Stylist) {
|
fn match_node(&self, stylist: &Stylist) {
|
||||||
let applicable_declarations = do self.with_element |element| {
|
let applicable_declarations = do self.with_element |element| {
|
||||||
let style_attribute = match element.style_attribute {
|
let style_attribute = match element.style_attribute {
|
||||||
|
@ -63,7 +64,20 @@ impl MatchMethods for LayoutNode {
|
||||||
if nodes.len() > 0 {
|
if nodes.len() > 0 {
|
||||||
let chan = chan.clone();
|
let chan = chan.clone();
|
||||||
let stylist = stylist.clone();
|
let stylist = stylist.clone();
|
||||||
do task::spawn_with((nodes, stylist)) |(nodes, stylist)| {
|
|
||||||
|
// FIXME(pcwalton): This transmute is to work around the fact that we have no
|
||||||
|
// mechanism for safe fork/join parallelism. If we had such a thing, then we could
|
||||||
|
// close over the lifetime-bounded `LayoutNode`. But we can't, so we force it with
|
||||||
|
// a transmute.
|
||||||
|
let evil: uintptr_t = unsafe {
|
||||||
|
cast::transmute(nodes)
|
||||||
|
};
|
||||||
|
|
||||||
|
do task::spawn_with((evil, stylist)) |(evil, stylist)| {
|
||||||
|
let nodes: ~[LayoutNode] = unsafe {
|
||||||
|
cast::transmute(evil)
|
||||||
|
};
|
||||||
|
|
||||||
let nodes = Cell::new(nodes);
|
let nodes = Cell::new(nodes);
|
||||||
do stylist.read |stylist| {
|
do stylist.read |stylist| {
|
||||||
for node in nodes.take().move_iter() {
|
for node in nodes.take().move_iter() {
|
||||||
|
|
|
@ -17,7 +17,7 @@ pub trait StyledNode {
|
||||||
fn restyle_damage(&self) -> RestyleDamage;
|
fn restyle_damage(&self) -> RestyleDamage;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StyledNode for LayoutNode {
|
impl<'self> StyledNode for LayoutNode<'self> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn style<'a>(&'a self) -> &'a Arc<ComputedValues> {
|
fn style<'a>(&'a self) -> &'a Arc<ComputedValues> {
|
||||||
self.get_css_select_results()
|
self.get_css_select_results()
|
||||||
|
|
|
@ -18,7 +18,7 @@ pub trait NodeUtil {
|
||||||
fn set_restyle_damage(self, damage: RestyleDamage);
|
fn set_restyle_damage(self, damage: RestyleDamage);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NodeUtil for LayoutNode {
|
impl<'self> NodeUtil for LayoutNode<'self> {
|
||||||
/**
|
/**
|
||||||
* Provides the computed style for the given node. If CSS selector
|
* Provides the computed style for the given node. If CSS selector
|
||||||
* Returns the style results for the given node. If CSS selector
|
* Returns the style results for the given node. If CSS selector
|
||||||
|
|
|
@ -528,7 +528,7 @@ trait NodeUtils {
|
||||||
fn swap_out_construction_result(self) -> ConstructionResult;
|
fn swap_out_construction_result(self) -> ConstructionResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NodeUtils for LayoutNode {
|
impl<'self> NodeUtils for LayoutNode<'self> {
|
||||||
fn is_replaced_content(self) -> bool {
|
fn is_replaced_content(self) -> bool {
|
||||||
match self.type_id() {
|
match self.type_id() {
|
||||||
TextNodeTypeId |
|
TextNodeTypeId |
|
||||||
|
|
|
@ -14,7 +14,7 @@ pub trait LayoutAuxMethods {
|
||||||
fn initialize_style_for_subtree(self);
|
fn initialize_style_for_subtree(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LayoutAuxMethods for LayoutNode {
|
impl<'self> LayoutAuxMethods for LayoutNode<'self> {
|
||||||
/// Resets layout data and styles for the node.
|
/// Resets layout data and styles for the node.
|
||||||
///
|
///
|
||||||
/// FIXME(pcwalton): Do this as part of box building instead of in a traversal.
|
/// FIXME(pcwalton): Do this as part of box building instead of in a traversal.
|
||||||
|
|
|
@ -441,10 +441,11 @@ pub struct InlineFlow {
|
||||||
// these ranges are disjoint, and are the result of inline layout.
|
// these ranges are disjoint, and are the result of inline layout.
|
||||||
// also some metadata used for positioning lines
|
// also some metadata used for positioning lines
|
||||||
lines: ~[LineBox],
|
lines: ~[LineBox],
|
||||||
|
|
||||||
// vec of ranges into boxes that represent elements. These ranges
|
// vec of ranges into boxes that represent elements. These ranges
|
||||||
// must be well-nested, and are only related to the content of
|
// must be well-nested, and are only related to the content of
|
||||||
// boxes (not lines). Ranges are only kept for non-leaf elements.
|
// boxes (not lines). Ranges are only kept for non-leaf elements.
|
||||||
elems: ElementMapping
|
elems: ElementMapping,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InlineFlow {
|
impl InlineFlow {
|
||||||
|
|
|
@ -163,7 +163,7 @@ pub trait LayoutDataAccess {
|
||||||
fn mutate_layout_data<'a>(&'a self) -> MutSlotRef<'a,Option<~LayoutData>>;
|
fn mutate_layout_data<'a>(&'a self) -> MutSlotRef<'a,Option<~LayoutData>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LayoutDataAccess for LayoutNode {
|
impl<'self> LayoutDataAccess for LayoutNode<'self> {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
unsafe fn borrow_layout_data_unchecked<'a>(&'a self) -> &'a Option<~LayoutData> {
|
unsafe fn borrow_layout_data_unchecked<'a>(&'a self) -> &'a Option<~LayoutData> {
|
||||||
cast::transmute(self.get().layout_data.borrow_unchecked())
|
cast::transmute(self.get().layout_data.borrow_unchecked())
|
||||||
|
|
|
@ -30,23 +30,33 @@ use std::util;
|
||||||
use style::TNode;
|
use style::TNode;
|
||||||
|
|
||||||
//
|
//
|
||||||
// The basic Node structure
|
// Layout's immutable, sanitized view of nodes.
|
||||||
//
|
//
|
||||||
|
|
||||||
/// A wrapper so that layout can access only the properties that it should have access to. Layout
|
/// A nonsense constant for layout nodes to point to just to establish a lifetime.
|
||||||
/// should only ever see this.
|
///
|
||||||
|
/// FIXME(pcwalton): Phantom lifetimes in Rust would be useful...
|
||||||
|
static HEAVY_IRON_BALL: () = ();
|
||||||
|
|
||||||
|
/// A wrapper so that layout can access only the methods that it should have access to. Layout must
|
||||||
|
/// only ever see these and must never see instances of `AbstractNode`.
|
||||||
#[deriving(Clone, Eq)]
|
#[deriving(Clone, Eq)]
|
||||||
pub struct LayoutNode {
|
pub struct LayoutNode<'self> {
|
||||||
|
/// The wrapped node.
|
||||||
priv node: AbstractNode,
|
priv node: AbstractNode,
|
||||||
|
|
||||||
|
/// Being chained to a `HEAVY_IRON_BALL` prevents `LayoutNode`s from escaping.
|
||||||
|
priv chain: &'self (),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LayoutNode {
|
impl<'self> LayoutNode<'self> {
|
||||||
/// NB: Do not make this public.
|
/// NB: Do not make this public.
|
||||||
///
|
///
|
||||||
/// FIXME(pcwalton): Probably this should be marked `unsafe`.
|
/// FIXME(pcwalton): Probably this should be marked `unsafe`.
|
||||||
/*PRIVATE-FOR-SECURITY-REASONS*/ fn new(node: AbstractNode) -> LayoutNode {
|
/*PRIVATE-FOR-SECURITY-REASONS*/ fn new(node: AbstractNode) -> LayoutNode<'static> {
|
||||||
LayoutNode {
|
LayoutNode {
|
||||||
node: node,
|
node: node,
|
||||||
|
chain: &HEAVY_IRON_BALL,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,26 +67,26 @@ impl LayoutNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the first child of this node.
|
/// Returns the first child of this node.
|
||||||
pub fn first_child(&self) -> Option<LayoutNode> {
|
pub fn first_child(&self) -> Option<LayoutNode<'self>> {
|
||||||
self.node.first_child().map(|node| LayoutNode::new(node))
|
self.node.first_child().map(|node| LayoutNode::new(node))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the first child of this node.
|
/// Returns the first child of this node.
|
||||||
pub fn last_child(&self) -> Option<LayoutNode> {
|
pub fn last_child(&self) -> Option<LayoutNode<'self>> {
|
||||||
self.node.last_child().map(|node| LayoutNode::new(node))
|
self.node.last_child().map(|node| LayoutNode::new(node))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterates over this node and all its descendants, in preorder.
|
/// Iterates over this node and all its descendants, in preorder.
|
||||||
///
|
///
|
||||||
/// FIXME(pcwalton): Terribly inefficient. We should use parallelism.
|
/// FIXME(pcwalton): Terribly inefficient. We should use parallelism.
|
||||||
pub fn traverse_preorder(&self) -> LayoutTreeIterator {
|
pub fn traverse_preorder(&self) -> LayoutTreeIterator<'self> {
|
||||||
let mut nodes = ~[];
|
let mut nodes = ~[];
|
||||||
gather_layout_nodes(self, &mut nodes, false);
|
gather_layout_nodes(self, &mut nodes, false);
|
||||||
LayoutTreeIterator::new(nodes)
|
LayoutTreeIterator::new(nodes)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an iterator over this node's children.
|
/// Returns an iterator over this node's children.
|
||||||
pub fn children(&self) -> LayoutNodeChildrenIterator {
|
pub fn children(&self) -> LayoutNodeChildrenIterator<'self> {
|
||||||
LayoutNodeChildrenIterator {
|
LayoutNodeChildrenIterator {
|
||||||
current_node: self.first_child(),
|
current_node: self.first_child(),
|
||||||
}
|
}
|
||||||
|
@ -177,16 +187,16 @@ impl LayoutNode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TNode<Element> for LayoutNode {
|
impl<'self> TNode<Element> for LayoutNode<'self> {
|
||||||
fn parent_node(&self) -> Option<LayoutNode> {
|
fn parent_node(&self) -> Option<LayoutNode<'self>> {
|
||||||
self.node.node().parent_node.map(|node| LayoutNode::new(node))
|
self.node.node().parent_node.map(|node| LayoutNode::new(node))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prev_sibling(&self) -> Option<LayoutNode> {
|
fn prev_sibling(&self) -> Option<LayoutNode<'self>> {
|
||||||
self.node.node().prev_sibling.map(|node| LayoutNode::new(node))
|
self.node.node().prev_sibling.map(|node| LayoutNode::new(node))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_sibling(&self) -> Option<LayoutNode> {
|
fn next_sibling(&self) -> Option<LayoutNode<'self>> {
|
||||||
self.node.node().next_sibling.map(|node| LayoutNode::new(node))
|
self.node.node().next_sibling.map(|node| LayoutNode::new(node))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,12 +214,17 @@ impl TNode<Element> for LayoutNode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// FIXME(pcwalton): Unsafe!
|
||||||
#[inline]
|
#[inline]
|
||||||
fn with_element<R>(&self, f: &fn(&Element) -> R) -> R {
|
fn with_element<R>(&self, f: &fn(&Element) -> R) -> R {
|
||||||
self.node.with_imm_element(f)
|
self.node.with_imm_element(f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// The basic Node structure
|
||||||
|
//
|
||||||
|
|
||||||
/// This is what a Node looks like if you do not know what kind of node it is. To unpack it, use
|
/// This is what a Node looks like if you do not know what kind of node it is. To unpack it, use
|
||||||
/// downcast().
|
/// downcast().
|
||||||
///
|
///
|
||||||
|
@ -836,12 +851,12 @@ impl Iterator<AbstractNode> for AbstractNodeChildrenIterator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct LayoutNodeChildrenIterator {
|
pub struct LayoutNodeChildrenIterator<'self> {
|
||||||
priv current_node: Option<LayoutNode>,
|
priv current_node: Option<LayoutNode<'self>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Iterator<LayoutNode> for LayoutNodeChildrenIterator {
|
impl<'self> Iterator<LayoutNode<'self>> for LayoutNodeChildrenIterator<'self> {
|
||||||
fn next(&mut self) -> Option<LayoutNode> {
|
fn next(&mut self) -> Option<LayoutNode<'self>> {
|
||||||
let node = self.current_node;
|
let node = self.current_node;
|
||||||
self.current_node = do self.current_node.and_then |node| {
|
self.current_node = do self.current_node.and_then |node| {
|
||||||
node.next_sibling()
|
node.next_sibling()
|
||||||
|
@ -911,13 +926,13 @@ fn gather_abstract_nodes(cur: &AbstractNode, refs: &mut ~[AbstractNode], postord
|
||||||
// Easy for preorder; harder for postorder.
|
// Easy for preorder; harder for postorder.
|
||||||
//
|
//
|
||||||
// FIXME(pcwalton): Parallelism! Eventually this should just be nuked.
|
// FIXME(pcwalton): Parallelism! Eventually this should just be nuked.
|
||||||
pub struct LayoutTreeIterator {
|
pub struct LayoutTreeIterator<'self> {
|
||||||
priv nodes: ~[LayoutNode],
|
priv nodes: ~[LayoutNode<'self>],
|
||||||
priv index: uint,
|
priv index: uint,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LayoutTreeIterator {
|
impl<'self> LayoutTreeIterator<'self> {
|
||||||
fn new(nodes: ~[LayoutNode]) -> LayoutTreeIterator {
|
fn new(nodes: ~[LayoutNode<'self>]) -> LayoutTreeIterator<'self> {
|
||||||
LayoutTreeIterator {
|
LayoutTreeIterator {
|
||||||
nodes: nodes,
|
nodes: nodes,
|
||||||
index: 0,
|
index: 0,
|
||||||
|
@ -925,8 +940,8 @@ impl LayoutTreeIterator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Iterator<LayoutNode> for LayoutTreeIterator {
|
impl<'self> Iterator<LayoutNode<'self>> for LayoutTreeIterator<'self> {
|
||||||
fn next(&mut self) -> Option<LayoutNode> {
|
fn next(&mut self) -> Option<LayoutNode<'self>> {
|
||||||
if self.index >= self.nodes.len() {
|
if self.index >= self.nodes.len() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
|
@ -938,7 +953,7 @@ impl Iterator<LayoutNode> for LayoutTreeIterator {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// FIXME(pcwalton): This is super inefficient.
|
/// FIXME(pcwalton): This is super inefficient.
|
||||||
fn gather_layout_nodes(cur: &LayoutNode, refs: &mut ~[LayoutNode], postorder: bool) {
|
fn gather_layout_nodes<'a>(cur: &LayoutNode<'a>, refs: &mut ~[LayoutNode<'a>], postorder: bool) {
|
||||||
if !postorder {
|
if !postorder {
|
||||||
refs.push(cur.clone());
|
refs.push(cur.clone());
|
||||||
}
|
}
|
||||||
|
@ -1617,12 +1632,12 @@ impl Reflectable for Node<ScriptView> {
|
||||||
/// A bottom-up, parallelizable traversal.
|
/// A bottom-up, parallelizable traversal.
|
||||||
pub trait PostorderNodeTraversal {
|
pub trait PostorderNodeTraversal {
|
||||||
/// The operation to perform. Return true to continue or false to stop.
|
/// The operation to perform. Return true to continue or false to stop.
|
||||||
fn process(&self, node: LayoutNode) -> bool;
|
fn process<'a>(&'a self, node: LayoutNode<'a>) -> bool;
|
||||||
|
|
||||||
/// Returns true if this node should be pruned. If this returns true, we skip the operation
|
/// Returns true if this node should be pruned. If this returns true, we skip the operation
|
||||||
/// entirely and do not process any descendant nodes. This is called *before* child nodes are
|
/// entirely and do not process any descendant nodes. This is called *before* child nodes are
|
||||||
/// visited. The default implementation never prunes any nodes.
|
/// visited. The default implementation never prunes any nodes.
|
||||||
fn should_prune(&self, _node: LayoutNode) -> bool {
|
fn should_prune<'a>(&'a self, _node: LayoutNode<'a>) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1630,17 +1645,17 @@ pub trait PostorderNodeTraversal {
|
||||||
/// A bottom-up, parallelizable traversal.
|
/// A bottom-up, parallelizable traversal.
|
||||||
pub trait PostorderNodeMutTraversal {
|
pub trait PostorderNodeMutTraversal {
|
||||||
/// The operation to perform. Return true to continue or false to stop.
|
/// The operation to perform. Return true to continue or false to stop.
|
||||||
fn process(&mut self, node: LayoutNode) -> bool;
|
fn process<'a>(&'a mut self, node: LayoutNode<'a>) -> bool;
|
||||||
|
|
||||||
/// Returns true if this node should be pruned. If this returns true, we skip the operation
|
/// Returns true if this node should be pruned. If this returns true, we skip the operation
|
||||||
/// entirely and do not process any descendant nodes. This is called *before* child nodes are
|
/// entirely and do not process any descendant nodes. This is called *before* child nodes are
|
||||||
/// visited. The default implementation never prunes any nodes.
|
/// visited. The default implementation never prunes any nodes.
|
||||||
fn should_prune(&self, _node: LayoutNode) -> bool {
|
fn should_prune<'a>(&'a self, _node: LayoutNode<'a>) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LayoutNode {
|
impl<'self> LayoutNode<'self> {
|
||||||
/// Traverses the tree in postorder.
|
/// Traverses the tree in postorder.
|
||||||
///
|
///
|
||||||
/// TODO(pcwalton): Offer a parallel version with a compatible API.
|
/// TODO(pcwalton): Offer a parallel version with a compatible API.
|
||||||
|
@ -1668,7 +1683,8 @@ impl LayoutNode {
|
||||||
/// Traverses the tree in postorder.
|
/// Traverses the tree in postorder.
|
||||||
///
|
///
|
||||||
/// TODO(pcwalton): Offer a parallel version with a compatible API.
|
/// TODO(pcwalton): Offer a parallel version with a compatible API.
|
||||||
pub fn traverse_postorder_mut<T:PostorderNodeMutTraversal>(mut self, traversal: &mut T) -> bool {
|
pub fn traverse_postorder_mut<T:PostorderNodeMutTraversal>(mut self, traversal: &mut T)
|
||||||
|
-> bool {
|
||||||
if traversal.should_prune(self) {
|
if traversal.should_prune(self) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue