diff --git a/src/servo/css/styles.rs b/src/servo/css/styles.rs index d07ae8e1ee1..48bcd1bfb82 100644 --- a/src/servo/css/styles.rs +++ b/src/servo/css/styles.rs @@ -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 core::dvec::DVec; use css::values::*; use css::values::Stylesheet; use dom::element::{HTMLDivElement, HTMLHeadElement, HTMLImageElement, UnknownElement, HTMLScriptElement}; @@ -39,7 +41,7 @@ impl NodeKind : DefaultStyleMethods { /* TODO: this belongs in the UA stylesheet */ fn default_display_type() -> CSSDisplay { match self { - Text(*) => { DisplayInline } + Text(*) => DisplayInline, Element(element) => { match *element.kind { HTMLDivElement => DisplayBlock, @@ -80,75 +82,64 @@ fn empty_style_for_node_kind(kind: NodeKind) -> SpecifiedStyle { 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 { - fn initialize_style_for_subtree() -> ~[@LayoutData]; + fn initialize_layout_data() -> Option<@LayoutData>; + fn style() -> SpecifiedStyle; + fn initialize_style_for_subtree(ctx: &LayoutContext, refs: &DVec<@LayoutData>); fn recompute_style_for_subtree(ctx: &LayoutContext, styles : ARC); } impl Node : StyleMethods { - #[doc="Sequentially initialize the nodes' auxilliary data so they can be updated in parallel."] - fn initialize_style_for_subtree() -> ~[@LayoutData] { - let mut handles = self.initialize_style(); - - for NodeTree.each_child(self) |kid| { - handles += kid.initialize_style_for_subtree(); + /** If none exists, creates empty layout data for the node (the reader-auxiliary + * box in the RCU model) and populates it with an empty style object. + */ + fn initialize_layout_data() -> Option<@LayoutData> { + match self.has_aux() { + 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 - performed, fails. - - TODO: Return a safe reference; don't copy. - "] + + /** + * Returns the computed style for the given node. If CSS selector + * matching has not yet been performed, fails. + */ fn style() -> SpecifiedStyle { if !self.has_aux() { 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; } - #[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) { let mut i = 0u; diff --git a/src/servo/dom/node.rs b/src/servo/dom/node.rs index f67b890a298..6866af093bd 100644 --- a/src/servo/dom/node.rs +++ b/src/servo/dom/node.rs @@ -12,7 +12,7 @@ use js::glue::bindgen::RUST_OBJECT_TO_JSVAL; use js::jsapi::{JSClass, JSObject, JSPropertySpec, JSContext, jsid, jsval, JSBool}; use js::rust::{bare_compartment, compartment, methods}; use js::{JSPROP_ENUMERATE, JSPROP_SHARED}; -use layout::base::RenderBox; +use layout::base::FlowContext; use layout::debug::DebugMethods; use ptr::null; use std::arc::ARC; @@ -37,6 +37,18 @@ impl NodeTree : tree::ReadMethods { } } +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 { /* 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. */ enum LayoutData = { mut style: ~SpecifiedStyle, - mut box: Option<@RenderBox> + mut flow: Option<@FlowContext> }; type Node = rcu::Handle; @@ -151,5 +163,4 @@ impl NodeScope : tree::WriteMethods { fn with_tree_fields(node: Node, f: fn(tree::Tree) -> R) -> R { self.write(node, |n| f(n.tree)) } -} - +} \ No newline at end of file diff --git a/src/servo/layout/box_builder.rs b/src/servo/layout/box_builder.rs index 51278d2c5d7..1389cdf936c 100644 --- a/src/servo/layout/box_builder.rs +++ b/src/servo/layout/box_builder.rs @@ -1,11 +1,11 @@ /** Creates CSS boxes from a DOM. */ use au = gfx::geometry; 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::{Inherit, Initial, Specified}; 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::{FlowContext, FlowContextData, BlockFlow, InlineFlow, InlineBlockFlow, RootFlow, FlowTree}; use layout::block::BlockFlowData; diff --git a/src/servo/layout/layout_task.rs b/src/servo/layout/layout_task.rs index 7143bc237e2..daf83924b80 100644 --- a/src/servo/layout/layout_task.rs +++ b/src/servo/layout/layout_task.rs @@ -10,7 +10,7 @@ use core::dvec::DVec; use css::resolve::apply::apply_style; use css::values::Stylesheet; use dl = gfx::display_list; -use dom::node::Node; +use dom::node::{Node, LayoutData}; use dom::event::{Event, ReflowEvent}; use geom::point::Point2D; use geom::rect::Rect; @@ -41,7 +41,7 @@ fn LayoutTask(render_task: RenderTask, image_cache_task: ImageCacheTask) -> Layo do spawn_listener::|request| { // This just keeps our dom aux objects alive - let mut layout_data_refs = ~[]; + let layout_data_refs = DVec(); let font_cache = FontCache(); loop { @@ -65,7 +65,7 @@ fn LayoutTask(render_task: RenderTask, image_cache_task: ImageCacheTask) -> Layo }; 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); // TODO: this should care about root flow, not root box.