Clean up aux layout data creation

This commit is contained in:
Brian J. Burg 2012-09-21 10:20:43 -07:00
parent 545acff3a8
commit b7b3cc8bbb
4 changed files with 67 additions and 65 deletions

View file

@ -1,7 +1,9 @@
#[doc="High-level interface to CSS selector matching."] /**
* High-level interface to CSS selector matching.
*/
use std::arc::{ARC, get, clone}; use std::arc::{ARC, get, clone};
use core::dvec::DVec;
use css::values::*; use css::values::*;
use css::values::Stylesheet; use css::values::Stylesheet;
use dom::element::{HTMLDivElement, HTMLHeadElement, HTMLImageElement, UnknownElement, HTMLScriptElement}; use dom::element::{HTMLDivElement, HTMLHeadElement, HTMLImageElement, UnknownElement, HTMLScriptElement};
@ -39,7 +41,7 @@ impl NodeKind : DefaultStyleMethods {
/* TODO: this belongs in the UA stylesheet */ /* TODO: this belongs in the UA stylesheet */
fn default_display_type() -> CSSDisplay { fn default_display_type() -> CSSDisplay {
match self { match self {
Text(*) => { DisplayInline } Text(*) => DisplayInline,
Element(element) => { Element(element) => {
match *element.kind { match *element.kind {
HTMLDivElement => DisplayBlock, HTMLDivElement => DisplayBlock,
@ -80,75 +82,64 @@ fn empty_style_for_node_kind(kind: NodeKind) -> SpecifiedStyle {
mut width : Initial} mut width : Initial}
} }
trait StylePriv {
fn initialize_style() -> ~[@LayoutData];
}
impl Node : StylePriv {
#[doc="
Set a default auxiliary data so that other threads can modify it.
This is, importantly, the function that creates the layout
data for the node (the reader-auxiliary box in the RCU model)
and populates it with the default style.
"]
// TODO: we should look into folding this into building the dom,
// instead of doing a linear sweep afterwards.
fn initialize_style() -> ~[@LayoutData] {
if !self.has_aux() {
let node_kind = self.read(|n| copy *n.kind);
let the_layout_data = @LayoutData({
mut style : ~empty_style_for_node_kind(node_kind),
mut box : None
});
self.set_aux(the_layout_data);
~[the_layout_data]
} else {
~[]
}
}
}
trait StyleMethods { trait StyleMethods {
fn initialize_style_for_subtree() -> ~[@LayoutData]; fn initialize_layout_data() -> Option<@LayoutData>;
fn style() -> SpecifiedStyle; fn style() -> SpecifiedStyle;
fn initialize_style_for_subtree(ctx: &LayoutContext, refs: &DVec<@LayoutData>);
fn recompute_style_for_subtree(ctx: &LayoutContext, styles : ARC<Stylesheet>); fn recompute_style_for_subtree(ctx: &LayoutContext, styles : ARC<Stylesheet>);
} }
impl Node : StyleMethods { impl Node : StyleMethods {
#[doc="Sequentially initialize the nodes' auxilliary data so they can be updated in parallel."] /** If none exists, creates empty layout data for the node (the reader-auxiliary
fn initialize_style_for_subtree() -> ~[@LayoutData] { * box in the RCU model) and populates it with an empty style object.
let mut handles = self.initialize_style(); */
fn initialize_layout_data() -> Option<@LayoutData> {
for NodeTree.each_child(self) |kid| { match self.has_aux() {
handles += kid.initialize_style_for_subtree(); false => {
let node_kind = self.read(|n| copy *n.kind);
let data = @LayoutData({
mut style : ~empty_style_for_node_kind(node_kind),
mut flow : None
});
self.set_aux(data); Some(data)
},
true => None
} }
return handles;
} }
#[doc=" /**
Returns the computed style for the given node. If CSS selector matching has not yet been * Returns the computed style for the given node. If CSS selector
performed, fails. * matching has not yet been performed, fails.
*/
TODO: Return a safe reference; don't copy.
"]
fn style() -> SpecifiedStyle { fn style() -> SpecifiedStyle {
if !self.has_aux() { if !self.has_aux() {
fail ~"get_style() called on a node without a style!"; fail ~"get_style() called on a node without a style!";
} }
// TODO: return a safe reference; don't copy!
return copy *self.aux(|x| copy x).style; return copy *self.aux(|x| copy x).style;
} }
#[doc=" /**
Performs CSS selector matching on a subtree. * Initializes layout data and styles for a Node tree, if any nodes do not have
* this data already. Append created layout data to the task's GC roots.
*/
fn initialize_style_for_subtree(_ctx: &LayoutContext, refs: &DVec<@LayoutData>) {
do self.traverse_preorder |n| {
match n.initialize_layout_data() {
Some(r) => refs.push(r),
None => {}
}
}
}
This is, importantly, the function that updates the layout data for the node (the reader- /**
auxiliary box in the RCU model) with the computed style. * Performs CSS selector matching on a subtree.
"]
* This is, importantly, the function that updates the layout data for
* the node (the reader-auxiliary box in the RCU model) with the
* computed style.
*/
fn recompute_style_for_subtree(ctx: &LayoutContext, styles : ARC<Stylesheet>) { fn recompute_style_for_subtree(ctx: &LayoutContext, styles : ARC<Stylesheet>) {
let mut i = 0u; let mut i = 0u;

View file

@ -12,7 +12,7 @@ use js::glue::bindgen::RUST_OBJECT_TO_JSVAL;
use js::jsapi::{JSClass, JSObject, JSPropertySpec, JSContext, jsid, jsval, JSBool}; use js::jsapi::{JSClass, JSObject, JSPropertySpec, JSContext, jsid, jsval, JSBool};
use js::rust::{bare_compartment, compartment, methods}; use js::rust::{bare_compartment, compartment, methods};
use js::{JSPROP_ENUMERATE, JSPROP_SHARED}; use js::{JSPROP_ENUMERATE, JSPROP_SHARED};
use layout::base::RenderBox; use layout::base::FlowContext;
use layout::debug::DebugMethods; use layout::debug::DebugMethods;
use ptr::null; use ptr::null;
use std::arc::ARC; use std::arc::ARC;
@ -37,6 +37,18 @@ impl NodeTree : tree::ReadMethods<Node> {
} }
} }
impl Node {
fn traverse_preorder(preorder_cb: &fn(Node)) {
preorder_cb(self);
do NodeTree.each_child(self) |child| { child.traverse_preorder(preorder_cb); true }
}
fn traverse_postorder(postorder_cb: &fn(Node)) {
do NodeTree.each_child(self) |child| { child.traverse_postorder(postorder_cb); true }
postorder_cb(self);
}
}
impl Node : DebugMethods { impl Node : DebugMethods {
/* Dumps the subtree rooted at this node, for debugging. */ /* Dumps the subtree rooted at this node, for debugging. */
@ -105,7 +117,7 @@ fn define_bindings(compartment: bare_compartment, doc: @Document,
Note that there may be multiple boxes per DOM node. */ Note that there may be multiple boxes per DOM node. */
enum LayoutData = { enum LayoutData = {
mut style: ~SpecifiedStyle, mut style: ~SpecifiedStyle,
mut box: Option<@RenderBox> mut flow: Option<@FlowContext>
}; };
type Node = rcu::Handle<NodeData, LayoutData>; type Node = rcu::Handle<NodeData, LayoutData>;
@ -151,5 +163,4 @@ impl NodeScope : tree::WriteMethods<Node> {
fn with_tree_fields<R>(node: Node, f: fn(tree::Tree<Node>) -> R) -> R { fn with_tree_fields<R>(node: Node, f: fn(tree::Tree<Node>) -> R) -> R {
self.write(node, |n| f(n.tree)) self.write(node, |n| f(n.tree))
} }
} }

View file

@ -1,11 +1,11 @@
/** Creates CSS boxes from a DOM. */ /** Creates CSS boxes from a DOM. */
use au = gfx::geometry; use au = gfx::geometry;
use core::dvec::DVec; use core::dvec::DVec;
use css::styles::SpecifiedStyle; use css::styles::{SpecifiedStyle, empty_style_for_node_kind};
use css::values::{CSSDisplay, DisplayBlock, DisplayInline, DisplayInlineBlock, DisplayNone}; use css::values::{CSSDisplay, DisplayBlock, DisplayInline, DisplayInlineBlock, DisplayNone};
use css::values::{Inherit, Initial, Specified}; use css::values::{Inherit, Initial, Specified};
use dom::element::*; use dom::element::*;
use dom::node::{Comment, Doctype, Element, Text, Node, NodeTree}; use dom::node::{Comment, Doctype, Element, Text, Node, NodeTree, LayoutData};
use layout::base::{RenderBox, BoxData, GenericBox, ImageBox, TextBox, RenderBoxTree}; use layout::base::{RenderBox, BoxData, GenericBox, ImageBox, TextBox, RenderBoxTree};
use layout::base::{FlowContext, FlowContextData, BlockFlow, InlineFlow, InlineBlockFlow, RootFlow, FlowTree}; use layout::base::{FlowContext, FlowContextData, BlockFlow, InlineFlow, InlineBlockFlow, RootFlow, FlowTree};
use layout::block::BlockFlowData; use layout::block::BlockFlowData;

View file

@ -10,7 +10,7 @@ use core::dvec::DVec;
use css::resolve::apply::apply_style; use css::resolve::apply::apply_style;
use css::values::Stylesheet; use css::values::Stylesheet;
use dl = gfx::display_list; use dl = gfx::display_list;
use dom::node::Node; use dom::node::{Node, LayoutData};
use dom::event::{Event, ReflowEvent}; use dom::event::{Event, ReflowEvent};
use geom::point::Point2D; use geom::point::Point2D;
use geom::rect::Rect; use geom::rect::Rect;
@ -41,7 +41,7 @@ fn LayoutTask(render_task: RenderTask, image_cache_task: ImageCacheTask) -> Layo
do spawn_listener::<Msg>|request| { do spawn_listener::<Msg>|request| {
// This just keeps our dom aux objects alive // This just keeps our dom aux objects alive
let mut layout_data_refs = ~[]; let layout_data_refs = DVec();
let font_cache = FontCache(); let font_cache = FontCache();
loop { loop {
@ -65,7 +65,7 @@ fn LayoutTask(render_task: RenderTask, image_cache_task: ImageCacheTask) -> Layo
}; };
do util::time::time(~"layout") { do util::time::time(~"layout") {
layout_data_refs += node.initialize_style_for_subtree(); node.initialize_style_for_subtree(&layout_ctx, &layout_data_refs);
node.recompute_style_for_subtree(&layout_ctx, styles); node.recompute_style_for_subtree(&layout_ctx, styles);
// TODO: this should care about root flow, not root box. // TODO: this should care about root flow, not root box.