servo: Add comments on overall design; move display list building to Flows and Boxes; create a DisplayListBuilder context; rename Box to RenderBox
authorBrian J. Burg <burg@cs.washington.edu>
Wed, 19 Sep 2012 17:45:22 -0700
changeset 471083 9b060738ac180e54d3e05603af14ced9168a87be
parent 471082 6ebb808cb993da764c5549d4a0844857bcdd4836
child 471084 d86a2a914984ca292ed0da6a89127f6c7bf61442
push id44079
push userbmo:gps@mozilla.com
push dateSat, 04 Feb 2017 00:14:49 +0000
servo: Add comments on overall design; move display list building to Flows and Boxes; create a DisplayListBuilder context; rename Box to RenderBox Source-Repo: https://github.com/servo/servo Source-Revision: da7ae8a280b2165e14113c6ae6ebe5ac7a1ebf36
servo/src/servo/css/resolve/apply.rs
servo/src/servo/dom/base.rs
servo/src/servo/gfx/display_list.rs
servo/src/servo/layout/base.rs
servo/src/servo/layout/block.rs
servo/src/servo/layout/box_builder.rs
servo/src/servo/layout/display_list_builder.rs
servo/src/servo/layout/inline.rs
servo/src/servo/layout/layout_task.rs
servo/src/servo/layout/root.rs
servo/src/servo/layout/text.rs
servo/src/servo/layout/traverse.rs
servo/src/servo/layout/traverse_parallel.rs
--- a/servo/src/servo/css/resolve/apply.rs
+++ b/servo/src/servo/css/resolve/apply.rs
@@ -1,12 +1,12 @@
 #[doc="Applies the appropriate CSS style to boxes."]
 
 use au = gfx::geometry;
-use layout::base::{Box, SpecifiedStyle, BoxTree};
+use layout::base::{RenderBox, SpecifiedStyle, RenderBoxTree};
 use layout::context::LayoutContext;
 use layout::traverse_parallel::top_down_traversal;
 use image::ImageHolder;
 use resource::image_cache_task::ImageCacheTask;
 use std::net::url::Url;
 
 use css::values::*;
 
@@ -27,66 +27,66 @@ impl CSSValue<BoxSizing> : ResolveMethod
 }
 
 impl CSSValue<CSSFontSize> : ResolveMethods<CSSFontSize> {
     pure fn initial() -> CSSFontSize { return AbsoluteSize(Medium); }
 }
 
 
 struct StyleApplicator {
-    box: @Box,
+    box: @RenderBox,
     reflow: fn~(),
 }
 
 // TODO: normalize this into a normal preorder tree traversal function
-fn apply_style(layout_ctx: &LayoutContext, box: @Box, reflow: fn~()) {
+fn apply_style(layout_ctx: &LayoutContext, box: @RenderBox, reflow: fn~()) {
     let applicator = StyleApplicator {
         box: box,
         reflow: reflow
     };
 
     applicator.apply_css_style(layout_ctx);
 }
 
 // TODO: this is misleadingly-named. It is actually trying to resolve CSS 'inherit' values.
 
 #[doc="A wrapper around a set of functions that can be applied as a top-down traversal of layout
        boxes."]
-fn inheritance_wrapper(layout_ctx: &LayoutContext, box : @Box, reflow: fn~()) {
+fn inheritance_wrapper(layout_ctx: &LayoutContext, box : @RenderBox, reflow: fn~()) {
     let applicator = StyleApplicator {
         box: box,
         reflow: reflow
     };
     applicator.apply_style(layout_ctx);
 }
 
 /*
-fn resolve_fontsize(box : @Box) {
+fn resolve_fontsize(box : @RenderBox) {
     // TODO: complete this
     return
 }
 
-fn resolve_height(box : @Box) -> au {
+fn resolve_height(box : @RenderBox) -> au {
     let style = box.node.get_style();
     let inherit_val = match box.tree.parent {
         None => au(0),
         Some(parent) => parent.data.computed_size.height
     };
 
     box.appearance.height = match style.height {
         Initial => style.height.initial(),
         Inherit => inherit_val,
         Specified(val) => match val { // BoxSizing
             BoxPercent(*) | BoxAuto | BoxLength(Px(_)) => val,
             BoxLength(Em(n)) => BoxLength(Px(n * box.appearance.font_size.abs()))
         }
     }
 }
 
-fn resolve_width(box : @Box) {
+fn resolve_width(box : @RenderBox) {
     let style = box.node.get_specified_style();
     let inherit_val = match box.tree.parent {
         None => style.height.initial(),
         Some(node) => node.appearance.width
     };
 
     box.appearance.width = match style.width {
         Initial => style.width.initial(),
@@ -97,17 +97,17 @@ fn resolve_width(box : @Box) {
         }
     }
 }*/
 
 impl StyleApplicator {
     fn apply_css_style(layout_ctx: &LayoutContext) {
         let reflow = copy self.reflow;
 
-        do BoxTree.each_child(self.box) |child| {
+        do RenderBoxTree.each_child(self.box) |child| {
             inheritance_wrapper(layout_ctx, child, reflow); true
         }
     }
 
     #[doc="Applies CSS style to a layout box.
 
       Get the specified style and apply the existing traits to a
       layout box.  If a trait does not exist, calculate the default
--- a/servo/src/servo/dom/base.rs
+++ b/servo/src/servo/dom/base.rs
@@ -8,17 +8,17 @@ use dom::bindings;
 use dvec::DVec;
 use geom::size::Size2D;
 use gfx::geometry::au;
 use js::crust::*;
 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::Box;
+use layout::base::RenderBox;
 use layout::debug::DebugMethods;
 use ptr::null;
 use std::arc::ARC;
 use util::tree;
 
 enum TimerControlMsg {
     Fire(~dom::bindings::window::TimerData),
     Close
@@ -188,22 +188,22 @@ enum ElementKind {
     HTMLHeadElement,
     HTMLImageElement({mut size: Size2D<au>}),
     HTMLScriptElement
 }
 
 
 /** The RCU rd_aux data is a (weak) pointer to the layout data,
    defined by this `LayoutData` enum. It contains the CSS style object
-   as well as the primary `Box`.
+   as well as the primary `RenderBox`.
 
    Note that there may be multiple boxes per DOM node. */
 enum LayoutData = {
     mut style: ~SpecifiedStyle,
-    mut box: Option<@Box>
+    mut box: Option<@RenderBox>
 };
 
 type Node = rcu::Handle<NodeData, LayoutData>;
 
 type NodeScope = rcu::Scope<NodeData, LayoutData>;
 
 fn NodeScope() -> NodeScope {
     rcu::Scope()
--- a/servo/src/servo/gfx/display_list.rs
+++ b/servo/src/servo/gfx/display_list.rs
@@ -4,16 +4,18 @@ use gfx::geometry::*;
 use geom::rect::Rect;
 use image::base::Image;
 use render_task::RenderContext;
 
 use std::arc::{ARC, clone};
 use dvec::DVec;
 use text::glyph::Glyph;
 
+pub use layout::display_list_builder::DisplayListBuilder;
+
 struct DisplayItem {
     draw: ~fn((&DisplayItem), (&RenderContext)),
     bounds : Rect<au>, // TODO: whose coordinate system should this use?
     data : DisplayItemData
 }
 
 enum DisplayItemData {
     SolidColorData(u8, u8, u8),
@@ -83,13 +85,13 @@ type DisplayList = DVec<~DisplayItem>;
 
 trait DisplayListMethods {
     fn draw(ctx: &RenderContext);
 }
 
 impl DisplayList : DisplayListMethods {
     fn draw(ctx: &RenderContext) {
         for self.each |item| {
-            debug!["drawing %?", item];
+            debug!("drawing %?", item);
             item.draw(item, ctx);
         }
     }
 }
\ No newline at end of file
--- a/servo/src/servo/layout/base.rs
+++ b/servo/src/servo/layout/base.rs
@@ -1,72 +1,128 @@
 /* Fundamental layout structures and algorithms. */
 
+use arc = std::arc;
+use arc::ARC;
 use au = gfx::geometry;
+use au::au;
 use core::dvec::DVec;
 use core::to_str::ToStr;
 use core::rand;
 use css::styles::SpecifiedStyle;
-use css::values::{BoxSizing, Length, Px, CSSDisplay};
+use css::values::{BoxSizing, Length, Px, CSSDisplay, Specified, BgColor, BgTransparent};
+use dl = gfx::display_list;
 use dom::base::{Element, ElementKind, HTMLDivElement, HTMLImageElement};
 use dom::base::{Node, NodeData, NodeKind, NodeTree};
 use dom::rcu;
 use geom::rect::Rect;
 use geom::size::Size2D;
-use gfx::geometry::au;
+use geom::point::Point2D;
 use image::{Image, ImageHolder};
 use layout::block::BlockFlowData;
 use layout::context::LayoutContext;
 use layout::debug::DebugMethods;
 use layout::inline::InlineFlowData;
 use layout::root::RootFlowData;
 use layout::text::TextBoxData;
 use servo_text::text_run::TextRun;
-use std::arc::{ARC, clone};
 use std::net::url::Url;
 use task::spawn;
 use util::color::Color;
 use util::tree;
 use vec::{push, push_all};
 
+
+/** Servo's experimental layout system builds a tree of FlowContexts
+and RenderBoxes, and figures out positions and display attributes of
+tree nodes. Positions are computed in several tree traversals driven
+by fundamental data dependencies of inline and block layout.
+
+Render boxes (`struct RenderBox`) are the leafs of the layout
+tree. They cannot position themselves. In general, render boxes do not
+have a simple correspondence with CSS boxes as in the specification:
+
+ * Several render boxes may correspond to the same CSS box or DOM
+   node. For example, a CSS text box broken across two lines is
+   represented by two render boxes.
+
+ * Some CSS boxes are not created at all, such as some anonymous block
+   boxes induced by inline boxes with block-level sibling boxes. In
+   that case, Servo uses an InlineFlow with BlockFlow siblings; the
+   InlineFlow is block-level, but not a block container. It is
+   positioned as if it were a block box, but its children are
+   positioned according to inline flow.
+
+Fundamental box types include:
+
+ * GenericBox: an empty box that contributes only borders, margins,
+padding, backgrounds. It is analogous to a CSS nonreplaced content box.
+
+ * ImageBox: a box that represents a (replaced content) image and its
+   accompanying borders, shadows, etc.
+
+ * TextBox: a box representing a single run of text with a distinct
+   style. A TextBox may be split into two or more render boxes across
+   line breaks. Several TextBoxes may correspond to a single DOM text
+   node. Split text boxes are implemented by referring to subsets of a
+   master TextRun object.
+
+
+Flows (`struct FlowContext`) are interior nodes in the layout tree,
+and correspond closely to flow contexts in the CSS
+specification. Flows are responsible for positioning their child flow
+contexts and render boxes. Flows have purpose-specific fields, such as
+auxilliary line box structs, out-of-flow child lists, and so on.
+
+Currently, the important types of flows are:
+
+ * BlockFlow: a flow that establishes a block context. It has several
+   child flows, each of which are positioned according to block
+   formatting context rules (as if child flows CSS block boxes). Block
+   flows also contain a single GenericBox to represent their rendered
+   borders, padding, etc. (In the future, this render box may be
+   folded into BlockFlow to save space.)
+
+ * InlineFlow: a flow that establishes an inline context. It has a
+   flat list of child boxes/flows that are subject to inline layout
+   and line breaking, and structs to represent line breaks and mapping
+   to CSS boxes, for the purpose of handling `getClientRects()`.
+
+*/
+
 struct FlowLayoutData {
+    // TODO: min/pref and position are used during disjoint phases of
+    // layout; maybe combine into a single enum to save space.
     mut min_width: au,
     mut pref_width: au,
     mut position: Rect<au>,
 }
 
 fn FlowLayoutData() -> FlowLayoutData {
     FlowLayoutData {
         min_width: au(0),
         pref_width: au(0),
         position : au::zero_rect(),
     }
 }
 
 /* The type of the formatting context, and data specific to each
-context, such as lineboxes or float lists */ 
+context, such as linebox structures or float lists */ 
 enum FlowContextData {
     AbsoluteFlow, 
     BlockFlow(BlockFlowData),
     FloatFlow,
     InlineBlockFlow,
     InlineFlow(InlineFlowData),
     RootFlow(RootFlowData),
     TableFlow
 }
 
 /* A particular kind of layout context. It manages the positioning of
-   layout boxes within the context.
-
-   Flow contexts form a tree that is induced by the structure of the
-   box tree. Each context is responsible for laying out one or more
-   boxes, according to the flow type. The number of flow contexts should
-   be much fewer than the number of boxes. The context maintains a vector
-   of its constituent boxes in their document order.
-*/
+   render boxes within the context.  */
 struct FlowContext {
     kind: FlowContextData,
     data: FlowLayoutData,
     /* reference to parent, children flow contexts */
     tree: tree::Tree<@FlowContext>,
     /* TODO: debug only */
     mut id: int
 }
@@ -80,16 +136,18 @@ fn FlowContext(id: int, kind: FlowContex
     }
 }
 
 impl @FlowContext : cmp::Eq {
     pure fn eq(&&other: @FlowContext) -> bool { box::ptr_eq(self, other) }
     pure fn ne(&&other: @FlowContext) -> bool { !box::ptr_eq(self, other) }
 }
 
+
+/* Flow context disambiguation methods: the verbose alternative to virtual methods */
 impl @FlowContext {
     fn bubble_widths(ctx: &LayoutContext) {
         match self.kind {
             BlockFlow(*)  => self.bubble_widths_block(ctx),
             InlineFlow(*) => self.bubble_widths_inline(ctx),
             RootFlow(*)   => self.bubble_widths_root(ctx),
             _ => fail fmt!("Tried to bubble_widths of flow: %?", self.kind)
         }
@@ -107,16 +165,26 @@ impl @FlowContext {
     fn assign_height(ctx: &LayoutContext) {
         match self.kind {
             BlockFlow(*)  => self.assign_height_block(ctx),
             InlineFlow(*) => self.assign_height_inline(ctx),
             RootFlow(*)   => self.assign_height_root(ctx),
             _ => fail fmt!("Tried to assign_height of flow: %?", self.kind)
         }
     }
+
+    fn build_display_list_recurse(builder: &dl::DisplayListBuilder, dirty: &Rect<au>,
+                                  offset: &Point2D<au>, list: &dl::DisplayList) {
+        match self.kind {
+            RootFlow(*) => self.build_display_list_root(builder, dirty, offset, list),
+            BlockFlow(*) => self.build_display_list_block(builder, dirty, offset, list),
+            InlineFlow(*) => self.build_display_list_inline(builder, dirty, offset, list),
+            _ => fail fmt!("Tried to build_display_list_recurse of flow: %?", self.kind)
+        }
+    }
 }
 
 /* The tree holding FlowContexts */
 enum FlowTree { FlowTree }
 
 impl FlowTree : tree::ReadMethods<@FlowContext> {
     fn each_child(ctx: @FlowContext, f: fn(&&@FlowContext) -> bool) {
         tree::each_child(self, ctx, f)
@@ -161,68 +229,66 @@ fn BoxLayoutData() -> BoxLayoutData {
 }
 
 enum BoxData {
     GenericBox,
     ImageBox(Size2D<au>),
     TextBox(TextBoxData)
 }
 
-struct Box {
+struct RenderBox {
     /* references to children, parent */
-    tree : tree::Tree<@Box>,
+    tree : tree::Tree<@RenderBox>,
     /* originating DOM node */
     node : Node,
     /* reference to containing flow context, which this box
        participates in */
     ctx  : @FlowContext,
     /* results of flow computation */
     data : BoxLayoutData,
     /* kind tag and kind-specific data */
     kind : BoxData,
     /* TODO: debug only */
     mut id: int
 }
 
-fn Box(id: int, node: Node, ctx: @FlowContext, kind: BoxData) -> Box {
-    Box {
+fn RenderBox(id: int, node: Node, ctx: @FlowContext, kind: BoxData) -> RenderBox {
+    RenderBox {
         /* will be set when box is parented */
         tree : tree::empty(),
         node : node,
         ctx  : ctx,
         data : BoxLayoutData(),
         kind : kind,
         id : id
     }
 }
 
-impl @Box {
+impl @RenderBox {
     pure fn is_replaced() -> bool {
         match self.kind {
             ImageBox(*) => true, // TODO: form elements, etc
             _ => false
         }
     }
 
     pure fn get_min_width() -> au {
         match self.kind {
             // TODO: this should account for min/pref widths of the
             // box element in isolation. That includes
             // border/margin/padding but not child widths. The block
             // FlowContext will combine the width of this element and
             // that of its children to arrive at the context width.
             GenericBox => au(0),
+            // TODO: consult CSS 'width', margin, border.
             // TODO: If image isn't available, consult Node
             // attrs, etc. to determine intrinsic dimensions. These
             // dimensions are not defined by CSS 2.1, but are defined
             // by the HTML5 spec in Section 4.8.1
             ImageBox(size) => size.width,
-            // TODO: account for line breaks, etc. The run should know
-            // how to compute its own min and pref widths, and should
-            // probably cache them.
             TextBox(d) => d.runs.foldl(au(0), |sum, run| {
                 au::max(sum, run.min_break_width())
             })
         }
     }
 
     pure fn get_pref_width() -> au {
         match self.kind {
@@ -277,40 +343,109 @@ impl @Box {
             temp <-> self.data.background_image;
             let holder <- option::unwrap(temp);
             image = holder.get_image();
             self.data.background_image = Some(holder);
         }
 
         image
     }
+
+    // TODO: to implement stacking contexts correctly, we need to
+    // create a set of display lists, one per each layer of a stacking
+    // context. (CSS 2.1, Section 9.9.1). Each box is passed the list
+    // set representing the box's stacking context. When asked to
+    // construct its constituent display items, each box puts its
+    // DisplayItems into the correct stack layer (according to CSS 2.1
+    // Appendix E).  and then builder flattens the list at the end.
+
+    /* Methods for building a display list. This is a good candidate
+       for a function pointer as the number of boxes explodes.
+
+    # Arguments
+
+    * `builder` - the display list builder which manages the coordinate system and options.
+    * `dirty` - Dirty rectangle, in the coordinate system of the owning flow (self.ctx)
+    * `origin` - Total offset from display list root flow to this box's owning flow
+    * `list` - List to which items should be appended
+    */
+    fn build_display_list(builder: &dl::DisplayListBuilder, dirty: &Rect<au>, 
+                          offset: &Point2D<au>, list: &dl::DisplayList) {
+        if !self.data.position.intersects(dirty) {
+            return;
+        }
+
+        let bounds : Rect<au> = Rect(self.data.position.origin.add(offset),
+                                     copy self.data.position.size);
+
+        match self.kind {
+            TextBox(d) => {
+                let mut runs = d.runs;
+                // TODO: don't paint background for text boxes
+                list.push(~dl::SolidColor(bounds, 255u8, 255u8, 255u8));
+                
+                let mut bounds = bounds;
+                for uint::range(0, runs.len()) |i| {
+                    bounds.size.height = runs[i].size().height;
+                    let glyph_run = make_glyph_run(&runs[i]);
+                    list.push(~dl::Glyphs(bounds, glyph_run));
+                    bounds.origin.y += bounds.size.height;
+                }
+                return;
+
+                pure fn make_glyph_run(text_run: &TextRun) -> dl::GlyphRun {
+                    dl::GlyphRun {
+                        glyphs: copy text_run.glyphs
+                    }
+                }
+            },
+            // TODO: items for background, border, outline
+            GenericBox(*) => { },
+            ImageBox(*) => {
+                match self.get_image() {
+                    Some(image) => list.push(~dl::Image(bounds, image)),
+                    /* No image data at all? Okay, add some fallback content instead. */
+                    None => {
+                        // TODO: shouldn't need to unbox CSSValue by now
+                        let boxed_color = self.node.style().background_color;
+                        let color = match boxed_color {
+                            Specified(BgColor(c)) => c,
+                            Specified(BgTransparent) | _ => util::color::rgba(0,0,0,0.0)
+                        };
+                        list.push(~dl::SolidColor(bounds, color.red, color.green, color.blue));
+                    }
+                }
+            }
+        }
+    }
 }
 
 // FIXME: Why do these have to be redefined for each node type?
 
-/* The tree holding boxes */
-enum BoxTree { BoxTree }
+/* The tree holding render box relations. (This should only be used 
+for painting nested inlines, AFAIK-- everything else depends on Flow tree)  */
+enum RenderBoxTree { RenderBoxTree }
 
-impl BoxTree : tree::ReadMethods<@Box> {
-    fn each_child(node: @Box, f: fn(&&@Box) -> bool) {
+impl RenderBoxTree : tree::ReadMethods<@RenderBox> {
+    fn each_child(node: @RenderBox, f: fn(&&@RenderBox) -> bool) {
         tree::each_child(self, node, f)
     }
 
-    fn with_tree_fields<R>(&&b: @Box, f: fn(tree::Tree<@Box>) -> R) -> R {
+    fn with_tree_fields<R>(&&b: @RenderBox, f: fn(tree::Tree<@RenderBox>) -> R) -> R {
         f(b.tree)
     }
 }
 
-impl BoxTree : tree::WriteMethods<@Box> {
-    fn add_child(parent: @Box, child: @Box) {
+impl RenderBoxTree : tree::WriteMethods<@RenderBox> {
+    fn add_child(parent: @RenderBox, child: @RenderBox) {
         assert !box::ptr_eq(parent, child);
         tree::add_child(self, parent, child)
     }
 
-    fn with_tree_fields<R>(&&b: @Box, f: fn(tree::Tree<@Box>) -> R) -> R {
+    fn with_tree_fields<R>(&&b: @RenderBox, f: fn(tree::Tree<@RenderBox>) -> R) -> R {
         f(b.tree)
     }
 }
 
 // Debugging
 
 impl @FlowContext : DebugMethods {
     fn dump() {
@@ -349,32 +484,32 @@ impl @FlowContext : DebugMethods {
             },
             _ => fmt!("%?", self.kind)
         };
             
         fmt!("c%? %?", self.id, repr)
     }
 }
 
-impl @Box : DebugMethods {
+impl @RenderBox : DebugMethods {
     fn dump() {
         self.dump_indent(0u);
     }
 
     /* Dumps the node tree, for debugging, with indentation. */
     fn dump_indent(indent: uint) {
         let mut s = ~"";
         for uint::range(0u, indent) |_i| {
             s += ~"    ";
         }
 
         s += self.debug_str();
         debug!("%s", s);
 
-        for BoxTree.each_child(self) |kid| {
+        for RenderBoxTree.each_child(self) |kid| {
             kid.dump_indent(indent + 1u) 
         }
     }
 
     fn debug_str() -> ~str {
         let repr = match self.kind {
             GenericBox(*) => ~"GenericBox",
             ImageBox(*) => ~"ImageBox",
@@ -407,19 +542,19 @@ mod test {
         assert screen != ptr::null();
 
         f(screen);
 
         video::free_surface(screen);
     }
     */
 
-    fn flat_bounds(root: @Box) -> ~[Rect<au>] {
+    fn flat_bounds(root: @RenderBox) -> ~[Rect<au>] {
         let mut r = ~[];
-        for tree::each_child(BoxTree, root) |c| {
+        for tree::each_child(RenderBoxTree, root) |c| {
             push_all(r, flat_bounds(c));
         }
 
         push(r, copy root.data.position);
 
         return r;
     }
 
--- a/servo/src/servo/layout/block.rs
+++ b/servo/src/servo/layout/block.rs
@@ -1,35 +1,40 @@
 use au = gfx::geometry;
 use css::values::*;
+use dl = gfx::display_list;
 use geom::point::Point2D;
+use geom::rect::Rect;
 use geom::size::Size2D;
 use gfx::geometry::au;
-use layout::base::{Box, FlowContext, FlowTree, InlineBlockFlow, BlockFlow, RootFlow};
+use layout::base::{RenderBox, FlowContext, FlowTree, InlineBlockFlow, BlockFlow, RootFlow};
 use layout::context::LayoutContext;
 use util::tree;
 
 struct BlockFlowData {
-    mut box: Option<@Box>
+    mut box: Option<@RenderBox>
 }
 
 fn BlockFlowData() -> BlockFlowData {
     BlockFlowData {
         box: None
     }
 }
 
 trait BlockLayout {
     pure fn starts_block_flow() -> bool;
     pure fn access_block<T>(fn(&&BlockFlowData) -> T) -> T;
-    pure fn with_block_box(fn(&&@Box) -> ()) -> ();
+    pure fn with_block_box(fn(&&@RenderBox) -> ()) -> ();
 
     fn bubble_widths_block(ctx: &LayoutContext);
     fn assign_widths_block(ctx: &LayoutContext);
     fn assign_height_block(ctx: &LayoutContext);
+
+    fn build_display_list_block(a: &dl::DisplayListBuilder, b: &Rect<au>,
+                                c: &Point2D<au>, d: &dl::DisplayList);
 }
 
 impl @FlowContext : BlockLayout {
 
     pure fn starts_block_flow() -> bool {
         match self.kind {
             RootFlow(*) | BlockFlow(*) | InlineBlockFlow(*) => true,
             _ => false 
@@ -40,17 +45,17 @@ impl @FlowContext : BlockLayout {
         match self.kind {
             BlockFlow(d) => cb(d),
             _  => fail fmt!("Tried to access() data of BlockFlow, but this is a %?", self.kind)
         }
     }
 
     /* Get the current flow's corresponding block box, if it exists, and do something with it. 
        This works on both BlockFlow and RootFlow, since they are mostly the same. */
-    pure fn with_block_box(cb:fn(&&@Box) -> ()) -> () {
+    pure fn with_block_box(cb:fn(&&@RenderBox) -> ()) -> () {
         match self.kind {
             BlockFlow(*) => { 
                 do self.access_block |d| {
                     let mut box = d.box;
                     box.iter(cb)
                 }
             },
             RootFlow(*) => {
@@ -142,9 +147,27 @@ impl @FlowContext : BlockLayout {
         let used_bot = au(0);
         
         do self.with_block_box |box| {
             box.data.position.origin.y = au(0);
             box.data.position.size.height = cur_y;
             let (used_top, used_bot) = box.get_used_height();
         }
     }
+
+    fn build_display_list_block(builder: &dl::DisplayListBuilder, dirty: &Rect<au>, 
+                                offset: &Point2D<au>, list: &dl::DisplayList) {
+
+        assert self.starts_block_flow();
+        
+        // add box that starts block context
+        do self.with_block_box |box| {
+            box.build_display_list(builder, dirty, offset, list)
+        }
+
+        // TODO: handle any out-of-flow elements
+
+        // go deeper into the flow tree
+        for FlowTree.each_child(self) |child| {
+            self.build_display_list_for_child(builder, child, dirty, offset, list)
+        }
+    }
 }
--- a/servo/src/servo/layout/box_builder.rs
+++ b/servo/src/servo/layout/box_builder.rs
@@ -1,31 +1,31 @@
 /** Creates CSS boxes from a DOM. */
 use au = gfx::geometry;
 use core::dvec::DVec;
 use css::values::{CSSDisplay, DisplayBlock, DisplayInline, DisplayInlineBlock, DisplayNone};
 use css::values::{Inherit, Initial, Specified};
 use dom::base::{ElementData, HTMLDivElement, HTMLImageElement};
 use dom::base::{Element, Text, Node, Doctype, Comment, NodeTree};
-use layout::base::{Box, BoxData, GenericBox, ImageBox, TextBox, BoxTree};
+use layout::base::{RenderBox, BoxData, GenericBox, ImageBox, TextBox, RenderBoxTree};
 use layout::base::{FlowContext, FlowContextData, BlockFlow, InlineFlow, InlineBlockFlow, RootFlow, FlowTree};
 use layout::block::BlockFlowData;
 use layout::context::LayoutContext;
 use layout::inline::InlineFlowData;
 use layout::root::RootFlowData;
 use layout::text::TextBoxData;
 use option::is_none;
 use util::tree;
 use servo_text::text_run::TextRun;
 use servo_text::font_cache::FontCache;
 
 export LayoutTreeBuilder;
 
 struct LayoutTreeBuilder {
-    mut root_box: Option<@Box>,
+    mut root_box: Option<@RenderBox>,
     mut root_ctx: Option<@FlowContext>,
     mut next_bid: int,
     mut next_cid: int
 }
 
 fn LayoutTreeBuilder() -> LayoutTreeBuilder {
     LayoutTreeBuilder {
         root_box: None,
@@ -37,17 +37,17 @@ fn LayoutTreeBuilder() -> LayoutTreeBuil
 
 impl LayoutTreeBuilder {
     /* Debug-only ids */
     fn next_box_id() -> int { self.next_bid += 1; self.next_bid }
     fn next_ctx_id() -> int { self.next_cid += 1; self.next_cid }
 
     /** Creates necessary box(es) and flow context(s) for the current DOM node,
     and recurses on its children. */
-    fn construct_recursively(layout_ctx: &LayoutContext, cur_node: Node, parent_ctx: @FlowContext, parent_box: @Box) {
+    fn construct_recursively(layout_ctx: &LayoutContext, cur_node: Node, parent_ctx: @FlowContext, parent_box: @RenderBox) {
         let style = cur_node.style();
         
         // DEBUG
         let n_str = fmt!("%?", cur_node.read(|n| copy n.kind ));
         debug!("Considering node: %?", n_str);
 
         // TODO: handle interactions with 'float', 'position' (CSS 2.1, Section 9.7)
         let display = match style.display_type {
@@ -104,17 +104,17 @@ impl LayoutTreeBuilder {
         match next_ctx.kind {
             InlineFlow(d) => { d.boxes.push(new_box) }
             BlockFlow(d) => { d.box = Some(new_box) }
             _ => {} // TODO: float lists, etc.
         };
 
         // connect the box to its parent box
         debug!("Adding child box b%? of b%?", parent_box.id, new_box.id);
-        BoxTree.add_child(parent_box, new_box);
+        RenderBoxTree.add_child(parent_box, new_box);
     
         if (!next_ctx.eq(parent_ctx)) {
             debug!("Adding child flow f%? of f%?", parent_ctx.id, next_ctx.id);
             FlowTree.add_child(parent_ctx, next_ctx);
         }
         // recurse
         do NodeTree.each_child(cur_node) |child_node| {
             self.construct_recursively(layout_ctx, child_node, next_ctx, new_box); true
@@ -141,32 +141,32 @@ impl LayoutTreeBuilder {
 
     fn fixup_split_inline(foo: @FlowContext) {
         // TODO: finish me. 
         fail ~"TODO: handle case where an inline is split by a block"
     }
 
     /** entry point for box creation. Should only be 
     called on root DOM element. */
-    fn construct_trees(layout_ctx: &LayoutContext, root: Node) -> Result<@Box, ()> {
+    fn construct_trees(layout_ctx: &LayoutContext, root: Node) -> Result<@RenderBox, ()> {
         self.root_ctx = Some(self.make_ctx(RootFlow(RootFlowData()), tree::empty()));
         self.root_box = Some(self.make_box(root, self.root_ctx.get(), GenericBox));
 
         self.construct_recursively(layout_ctx, root, self.root_ctx.get(), self.root_box.get());
         return Ok(self.root_box.get())
     }
 
     fn make_ctx(kind : FlowContextData, tree: tree::Tree<@FlowContext>) -> @FlowContext {
         let ret = @FlowContext(self.next_ctx_id(), kind, tree);
         debug!("Created context: %s", ret.debug_str());
         ret
     }
 
-    fn make_box(node : Node, ctx: @FlowContext, data: BoxData) -> @Box {
-        let ret = @Box(self.next_box_id(), node, ctx, data);
+    fn make_box(node : Node, ctx: @FlowContext, data: BoxData) -> @RenderBox {
+        let ret = @RenderBox(self.next_box_id(), node, ctx, data);
         debug!("Created box: %s", ret.debug_str());
         ret
     }
 }
 
 trait PrivateBuilderMethods {
     fn create_box_data(layout_ctx: &LayoutContext, display: CSSDisplay) -> Option<BoxData>;
 }
--- a/servo/src/servo/layout/display_list_builder.rs
+++ b/servo/src/servo/layout/display_list_builder.rs
@@ -1,135 +1,68 @@
-export build_display_list;
+export DisplayListBuilder;
 
 use au = gfx::geometry;
-use base::Box;
+use base::{RenderBox, RenderBoxTree};
 use css::values::{BgColor, BgTransparent, Specified};
 use dl = gfx::display_list;
 use dom::base::{Text, NodeScope};
 use dom::rcu::Scope;
 use dvec::DVec;
 use either::{Left, Right};
 use geom::point::Point2D;
 use geom::rect::Rect;
 use geom::size::Size2D;
 use gfx::geometry::au;
 use layout::text::TextBoxData;
-use layout::base::{TextBox, BoxTree};
+use layout::base::{LayoutContext, FlowContext, TextBox};
 use servo_text::text_run::TextRun;
 use util::tree;
 use vec::push;
 
-/** 
-Builds a display list for a box and all its children
-*/
-fn build_display_list(box : @Box) -> dl::DisplayList {
-    let list = DVec();
-    build_display_list_from_origin(list, box, Point2D(au(0), au(0)));
-    return list;
+/** A builder object that manages display list builder should mainly
+ hold information about the initial request and desired result---for
+ example, whether the DisplayList to be used for painting or hit
+ testing. This can affect which boxes are created.
+
+ Right now, the builder isn't used for much, but it  establishes the
+ pattern we'll need once we support DL-based hit testing &c.  */
+struct DisplayListBuilder {
+    ctx:  &LayoutContext,
 }
 
-/**
-Builds a display list for a box and all its children.
+
+trait FlowDisplayListBuilderMethods {
+    fn build_display_list(a: &DisplayListBuilder, b: &Rect<au>, c: &dl::DisplayList);
 
-# Arguments
+    fn build_display_list_for_child(a: &DisplayListBuilder, b: @FlowContext,
+                                    c: &Rect<au>, d: &Point2D<au>, e: &dl::DisplayList);
+}
 
-* `box` - The box to build the display list for.
-* `origin` - The coordinates of upper-left corner of the box containing the
-             passed-in box.
+impl @FlowContext: FlowDisplayListBuilderMethods {
 
-*/
-fn build_display_list_from_origin(list: dl::DisplayList, box: @Box, origin: Point2D<au>) {
-    let box_origin = Point2D(
-        au::from_px(au::to_px(origin.x) + au::to_px(box.data.position.origin.x)),
-        au::from_px(au::to_px(origin.y) + au::to_px(box.data.position.origin.y)));
-    debug!("Handed origin %?, box has bounds %?, starting with origin %?", origin, box.data.position.size, box_origin);
+    fn build_display_list(builder: &DisplayListBuilder, dirty: &Rect<au>, list: &dl::DisplayList) {
+        let zero = au::zero_point();
+        self.build_display_list_recurse(builder, dirty, &zero, list);
+    }
+
+    fn build_display_list_for_child(builder: &DisplayListBuilder, child: @FlowContext,
+                                    dirty: &Rect<au>, offset: &Point2D<au>, list: &dl::DisplayList) {
 
-    box_to_display_items(list, box, box_origin);
+        // adjust the dirty rect to child flow context coordinates
+        let adj_dirty = dirty.translate(&child.data.position.origin);
+        let adj_offset = offset.add(&child.data.position.origin);
 
-    for BoxTree.each_child(box) |c| {
-        debug!("Recursively building display list with origin %?", box_origin);
-        build_display_list_from_origin(list, c, box_origin);
+        if (adj_dirty.intersects(&child.data.position)) {
+            child.build_display_list_recurse(builder, &adj_dirty, &adj_offset, list);
+        }
     }
 }
 
-/**
-Creates a display list item for a single block. 
-
-# Arguments 
-
-* `box` - The box to build the display list for
-* `origin` - The coordinates of upper-left corner of the passed in box.
-
-*/
-#[allow(non_implicitly_copyable_typarams)]
-fn box_to_display_items(list: dl::DisplayList, box: @Box, origin: Point2D<au>) {
-
-    // TODO: each box should know how to make its own display items.
-    // The display list builder should mainly hold information about
-    // the initial request and desired result---for example, is the 
-    // DisplayList to be used for painting or hit testing. This can
-    // influence which boxes are created.
-
-    // TODO: to implement stacking contexts correctly, we need to
-    // create a set of display lists, one per each layer of a stacking
-    // context. (CSS 2.1, Section 9.9.1). Each box is passed the list
-    // set representing the box's stacking context. When asked to
-    // construct its constituent display items, each box puts its
-    // DisplayItems into the correct stack layer (according to CSS 2.1
-    // Appendix E).  and then builder flattens the list at the end.
-    
-    debug!("request to display a box from origin %?", origin);
-
-    let bounds : Rect<au> = Rect(origin, copy box.data.position.size);
-
-    match box.kind {
-      TextBox(d) => {
-        let mut runs = d.runs;
-        list.push(~dl::SolidColor(bounds, 255u8, 255u8, 255u8));
-
-        let mut bounds = bounds;
-        for uint::range(0, runs.len()) |i| {
-            bounds.size.height = runs[i].size().height;
-            let glyph_run = text_run_to_dl_glyph_run(& runs[i]);
-            list.push(~dl::Glyphs(bounds, glyph_run));
-            bounds.origin.y += bounds.size.height;
-        }
-        return;
-
-        pure fn text_run_to_dl_glyph_run(text_run: &TextRun) ->
-                dl::GlyphRun {
-            dl::GlyphRun {
-                glyphs: copy text_run.glyphs
-            }
-        }
-      }
-      _ => {
-        // Fall through
-      }
-    };
-
-    // Check if there is a background image, if not set the background color.
-    let image = box.get_image();
-    
-    if image.is_some() {
-        list.push(~dl::Image(bounds, option::unwrap(image)))
-    } else {
-        // DAC
-        // TODO: shouldn't need to unbox CSSValue by now
-        let boxed_color = box.node.style().background_color;
-        let color = match boxed_color {
-            Specified(BgColor(c)) => c,
-            Specified(BgTransparent) | _ => util::color::rgba(0,0,0,0.0)
-        };
-        debug!("Assigning color %? to box with bounds %?", color, bounds);
-        list.push(~dl::SolidColor(bounds, color.red, color.green, color.blue));
-    }
-}
-
+/* TODO: redo unit tests, if possible?gn
 
 fn should_convert_text_boxes_to_solid_color_background_items() {
     #[test];
 
     use layout::box_builder::LayoutTreeBuilder;
 
     let s = Scope();
     let n = s.new_node(Text(~"firecracker"));
@@ -207,8 +140,9 @@ fn should_calculate_the_bounds_of_the_te
 
     let expected = Rect(
         Point2D(au::from_px(0), au::from_px(0)),
         Size2D(au::from_px(84), au::from_px(20))
     );
 
     do list.borrow |l| { assert l[1].bounds == expected; }
 }
+*/
\ No newline at end of file
--- a/servo/src/servo/layout/inline.rs
+++ b/servo/src/servo/layout/inline.rs
@@ -1,38 +1,65 @@
 use au = gfx::geometry;
-use base::Box;
+use base::RenderBox;
 use core::dvec::DVec;
 use css::values::{BoxAuto, BoxLength, Px};
+use dl = gfx::display_list;
 use dom::rcu;
 use geom::point::Point2D;
+use geom::rect::Rect;
 use geom::size::Size2D;
 use gfx::geometry::au;
 use layout::context::LayoutContext;
-use layout::base::{FlowContext, InlineFlow, BoxTree, ImageBox, TextBox, GenericBox};
+use layout::base::{FlowContext, InlineFlow, RenderBoxTree, ImageBox, TextBox, GenericBox};
 use num::Num;
 use util::tree;
 
+/*
+Tentative design: (may not line up with reality)
+
+Lineboxes are represented as offsets into the child list, rather than
+as an object that "owns" boxes. Choosing a different set of line
+breaks requires a new list of offsets, and possibly some splitting and
+merging of TextBoxes.
+
+A similar list will keep track of the mapping between CSS boxes and
+the corresponding render boxes in the inline flow.
+
+After line breaks are determined, lender boxes in the inline flow may
+overlap visually. For example, in the case of nested inline CSS boxes,
+outer inlines must be at least as large as the inner inlines, for
+purposes of drawing noninherited things like backgrounds, borders,
+outlines.
+
+N.B. roc has an alternative design where the list instead consists of
+things like "start outer box, text, start inner box, text, end inner
+box, text, end outer box, text". This seems a little complicated to
+serve as the starting point, but the current design doesn't make it
+hard to try out that alternative.
+*/
+
 struct InlineFlowData {
-    boxes: ~DVec<@Box>
+    boxes: ~DVec<@RenderBox>
 }
 
 fn InlineFlowData() -> InlineFlowData {
     InlineFlowData {
         boxes: ~DVec()
     }
 }
 
 trait InlineLayout {
     pure fn starts_inline_flow() -> bool;
 
     pure fn access_inline<T>(fn(&&InlineFlowData) -> T) -> T;
     fn bubble_widths_inline(ctx: &LayoutContext);
     fn assign_widths_inline(ctx: &LayoutContext);
     fn assign_height_inline(ctx: &LayoutContext);
+    fn build_display_list_inline(a: &dl::DisplayListBuilder, b: &Rect<au>, c: &Point2D<au>, d: &dl::DisplayList);
 }
 
 impl @FlowContext : InlineLayout {
     pure fn starts_inline_flow() -> bool { match self.kind { InlineFlow(*) => true, _ => false } }
 
     pure fn access_inline<T>(cb: fn(&&InlineFlowData) -> T) -> T {
         match self.kind {
             InlineFlow(d) => cb(d),
@@ -111,9 +138,32 @@ impl @FlowContext : InlineLayout {
 
     } // fn assign_widths_inline
 
     fn assign_height_inline(ctx: &LayoutContext) {
         // Don't need to set box or ctx heights, since that is done
         // during inline flowing.
     }
 
+    fn build_display_list_inline(builder: &dl::DisplayListBuilder, dirty: &Rect<au>, 
+                                 offset: &Point2D<au>, list: &dl::DisplayList) {
+
+        assert self.starts_inline_flow();
+
+        // TODO: if the CSS box introducing this inline context is *not* anonymous,
+        // we need to draw it too, in a way similar to BlowFlowContext
+
+        // TODO: once we form line boxes and have their cached bounds, we can be 
+        // smarter and not recurse on a line if nothing in it can intersect dirty
+        do self.access_inline |d| {
+            for d.boxes.each |box| {
+                box.build_display_list(builder, dirty, offset, list)
+            }
+        }
+
+        // TODO: should inline-block elements have flows as children
+        // of the inline flow, or should the flow be nested inside the
+        // box somehow? Maybe it's best to unify flows and boxes into
+        // the same enum, so inline-block flows are normal
+        // (indivisible) children in the inline flow child list.
+    }
+
 } // @FlowContext : InlineLayout
--- a/servo/src/servo/layout/layout_task.rs
+++ b/servo/src/servo/layout/layout_task.rs
@@ -1,26 +1,27 @@
 #[doc = "
     The layout task. Performs layout on the DOM, builds display lists and sends them to be
     rendered.
 "];
 
 use au = gfx::geometry;
 use au::au;
 use content::content_task;
+use core::dvec::DVec;
 use css::resolve::apply::apply_style;
 use css::values::Stylesheet;
-use display_list_builder::build_display_list;
+use dl = gfx::display_list;
 use dom::base::Node;
 use dom::event::{Event, ReflowEvent};
 use geom::point::Point2D;
 use geom::rect::Rect;
 use geom::size::Size2D;
 use gfx::render_task;
-use layout::base::Box;
+use layout::base::RenderBox;
 use layout::box_builder::LayoutTreeBuilder;
 use layout::context::LayoutContext;
 use render_task::RenderTask;
 use resource::image_cache_task::ImageCacheTask;
 use std::arc::ARC;
 use std::net::url::Url;
 use servo_text::font_cache::FontCache;
 
@@ -62,39 +63,46 @@ fn LayoutTask(render_task: RenderTask, i
                         // TODO: obtain screen size from a real data source
                         screen_size: Rect(Point2D(au(0), au(0)), Size2D(au::from_px(800), au::from_px(600)))
                     };
 
                     do util::time::time(~"layout") {
                         layout_data_refs += node.initialize_style_for_subtree();
                         node.recompute_style_for_subtree(&layout_ctx, styles);
 
-                        let root_box: @Box;
+                        // TODO: this should care about root flow, not root box.
+                        let root_box: @RenderBox;
                         let builder = LayoutTreeBuilder();
                         match builder.construct_trees(&layout_ctx, node) {
                             Ok(root) => root_box = root,
                             Err(*) => fail ~"Root node should always exist"
                         }
 
-                        debug!("layout: constructed Box tree");
+                        debug!("layout: constructed RenderBox tree");
                         root_box.dump();
 
                         debug!("layout: constructed Flow tree");
                         root_box.ctx.dump();
 
                         /* resolve styles (convert relative values) down the box tree */
                         let reflow_cb: fn~() = || event_chan.send(ReflowEvent);
                         apply_style(&layout_ctx, root_box, reflow_cb);
 
                         /* perform layout passes over the flow tree */
                         let root_flow = root_box.ctx;
                         do root_flow.traverse_postorder |f| { f.bubble_widths(&layout_ctx) }
                         do root_flow.traverse_preorder |f| { f.assign_widths(&layout_ctx) }
                         do root_flow.traverse_postorder |f| { f.assign_height(&layout_ctx) }
 
-                        let dlist = build_display_list(root_box);
+                        let dlist = DVec();
+                        let builder = dl::DisplayListBuilder {
+                            ctx: &layout_ctx,
+                        };
+                        // TODO: set options on the builder before building
+                        // TODO: be smarter about what needs painting
+                        root_flow.build_display_list(&builder, &copy root_flow.data.position, &dlist);
                         render_task.send(render_task::RenderMsg(dlist));
                     }
                 }
             }
         }
     }
 }
--- a/servo/src/servo/layout/root.rs
+++ b/servo/src/servo/layout/root.rs
@@ -1,32 +1,37 @@
 use au = gfx::geometry;
 use css::values::*;
+use dl = gfx::display_list;
+use geom::point::Point2D;
+use geom::rect::Rect;
 use gfx::geometry::au;
-use layout::base::{Box, FlowContext, FlowTree, InlineBlockFlow, BlockFlow, RootFlow};
+use layout::base::{RenderBox, FlowContext, FlowTree, InlineBlockFlow, BlockFlow, RootFlow};
 use layout::context::LayoutContext;
 use util::tree;
 
 struct RootFlowData {
-    mut box: Option<@Box>
+    mut box: Option<@RenderBox>
 }
 
 fn RootFlowData() -> RootFlowData {
     RootFlowData {
         box: None
     }
 }
 
 trait RootLayout {
     pure fn starts_root_flow() -> bool;
     pure fn access_root<T>(fn(&&RootFlowData) -> T) -> T;
 
     fn bubble_widths_root(ctx: &LayoutContext);
     fn assign_widths_root(ctx: &LayoutContext);
     fn assign_height_root(ctx: &LayoutContext);
+
+    fn build_display_list_root(a: &dl::DisplayListBuilder, b: &Rect<au>, c: &Point2D<au>, d: &dl::DisplayList);
 }
 
 impl @FlowContext : RootLayout {
 
     pure fn starts_root_flow() -> bool {
         match self.kind {
             RootFlow(*) => true,
             _ => false 
@@ -53,9 +58,16 @@ impl @FlowContext : RootLayout {
         self.assign_widths_block(ctx)
     }
 
     fn assign_height_root(ctx: &LayoutContext) {
         assert self.starts_root_flow();
 
         self.assign_height_block(ctx);
     }
+
+    fn build_display_list_root(builder: &dl::DisplayListBuilder, dirty: &Rect<au>, 
+                               offset: &Point2D<au>, list: &dl::DisplayList) {
+        assert self.starts_root_flow();
+        
+        self.build_display_list_block(builder, dirty, offset, list);
+    }
 }
--- a/servo/src/servo/layout/text.rs
+++ b/servo/src/servo/layout/text.rs
@@ -1,16 +1,16 @@
 #[doc="Text layout."]
 
 use au = gfx::geometry;
 use geom::size::Size2D;
 use gfx::geometry::au;
 use servo_text::text_run::TextRun;
 use servo_text::font_cache::FontCache;
-use layout::base::{TextBox, Box};
+use layout::base::{TextBox, RenderBox};
 use layout::context::LayoutContext;
 
 struct TextBoxData {
     text: ~str,
     mut runs: ~[TextRun]
 }
 
 fn TextBoxData(text: ~str, runs: ~[TextRun]) -> TextBoxData {
@@ -20,17 +20,17 @@ fn TextBoxData(text: ~str, runs: ~[TextR
     }
 }
 
 trait TextLayout {
     fn reflow_text(ctx: &LayoutContext);
 }
 
 #[doc="The main reflow routine for text layout."]
-impl @Box : TextLayout {
+impl @RenderBox : TextLayout {
     fn reflow_text(ctx: &LayoutContext) {
         let d = match self.kind {
             TextBox(d) => { d }
             _ => { fail ~"expected text box in reflow_text!" }
         };
 
         let font = ctx.font_cache.get_test_font();
 
@@ -73,16 +73,17 @@ impl @Box : TextLayout {
         let total_height = au(*current.size().height * line_count);
         lines.push(move current);
 
         self.data.position.size = Size2D(max_width, total_height);
         d.runs = move dvec::unwrap(lines);
     }
 }
 
+/* TODO: new unit tests for TextBox splitting, etc
 fn should_calculate_the_size_of_the_text_box() {
     #[test];
     #[ignore(cfg(target_os = "macos"))];
 
     use au = gfx::geometry;
     use dom::rcu::{Scope};
     use dom::base::{Text, NodeScope};
     use util::tree;
@@ -92,8 +93,9 @@ fn should_calculate_the_size_of_the_text
     let n = s.new_node(Text(~"firecracker"));
     let builder = LayoutTreeBuilder();
     let b = builder.construct_trees(n).get();
 
     b.reflow_text();
     let expected = Size2D(au::from_px(84), au::from_px(20));
     assert b.data.position.size == expected;
 }
+*/
\ No newline at end of file
--- a/servo/src/servo/layout/traverse.rs
+++ b/servo/src/servo/layout/traverse.rs
@@ -1,21 +1,22 @@
 /** Interface for running tree-based traversals over layout boxes and contextsg */
 
-use layout::base::{Box, BoxTree};
+use layout::base::{RenderBox, RenderBoxTree};
 use layout::base::{FlowContext, FlowTree};
 
-trait BoxTraversals {
-    fn traverse_preorder(preorder_cb: &fn(@Box));
+/* TODO: we shouldn't need render box traversals  */
+trait RenderBoxTraversals {
+    fn traverse_preorder(preorder_cb: &fn(@RenderBox));
 }
 
-impl @Box : BoxTraversals {
-    fn traverse_preorder(preorder_cb: &fn(@Box)) {
+impl @RenderBox : RenderBoxTraversals {
+    fn traverse_preorder(preorder_cb: &fn(@RenderBox)) {
         preorder_cb(self);
-        do BoxTree.each_child(self) |child| { child.traverse_preorder(preorder_cb); true }
+        do RenderBoxTree.each_child(self) |child| { child.traverse_preorder(preorder_cb); true }
     }
 }
 
 trait FlowContextTraversals {
     fn traverse_preorder(preorder_cb: &fn(@FlowContext));
     fn traverse_postorder(postorder_cb: &fn(@FlowContext));
 }
 
--- a/servo/src/servo/layout/traverse_parallel.rs
+++ b/servo/src/servo/layout/traverse_parallel.rs
@@ -1,11 +1,11 @@
 
 #[doc = "Interface for running tree-based traversals over layout boxes"]
-use base::{Box, BoxTree};
+use base::{RenderBox, RenderBoxTree};
 use intrinsic::TyDesc;
 
 export full_traversal;
 export top_down_traversal;
 export bottom_up_traversal;
 export extended_full_traversal;
 export extended_top_down_traversal;
 
@@ -17,24 +17,24 @@ type shared_box<T> = {
     // These are generic unsafe pointers, not just *ints
     foo : *int,
     bar : *int,
     baz : *int,
     payload : T
 };
 
 #[doc="Transform and @ into its underlying representation.  The reference count stays constant."]
-fn unwrap_box(-b : @Box) -> *shared_box<Box> unsafe {
-    let new_box : *shared_box<Box> = unsafe::transmute(b);
+fn unwrap_box(-b : @RenderBox) -> *shared_box<RenderBox> unsafe {
+    let new_box : *shared_box<RenderBox> = unsafe::transmute(b);
     return new_box;
 }
 
 #[doc="Transform an underlying representation back to an @.  The reference count stays constant."]
-fn rewrap_box(-b : *shared_box<Box>) -> @Box unsafe {
-    let new_box : @Box = unsafe::transmute(b);
+fn rewrap_box(-b : *shared_box<RenderBox>) -> @RenderBox unsafe {
+    let new_box : @RenderBox = unsafe::transmute(b);
     return new_box;
 }
 
 #[doc="
 
 Iterate down and then up a tree of layout boxes in parallel and apply
 the given functions to each box.  Each box applies the first function,
 spawns a task to complete all of its children in parallel, passing
@@ -48,110 +48,110 @@ finish, and then applies the second func
 * `returned` - The value returned by applying top_down to the parent
                of the current box, or a passed in default
 * `top_down` - A function that is applied to each node after it is
               applied to that node's parent.
 * `bottom_up` - A function that is applied to each node after it is
                 applied to that node's children
 
 "]
-fn traverse_helper<T : Copy Send>(-root : @Box, returned : T, -top_down : fn~(+T, @Box) -> T,
-                      -bottom_up : fn~(@Box)) {
+fn traverse_helper<T : Copy Send>(-root : @RenderBox, returned : T, -top_down : fn~(+T, @RenderBox) -> T,
+                      -bottom_up : fn~(@RenderBox)) {
     let returned = top_down(returned, root);
 
     do listen |ack_chan| { 
         let mut count = 0;
         
         // For each child we will send it off to another task and then
         // recurse.  It is safe to send these boxes across tasks
         // because root still holds a reference to the children so
         // they will not be destroyed from the other task.  Also the
         // current task will block until all of it's children return,
         // so the original owner of the @-box will not exit while the
         // children are still live.
-        for BoxTree.each_child(root) |kid| {
+        for RenderBoxTree.each_child(root) |kid| {
             count += 1;
 
             // Unwrap the box so we can send it out of this task
             let unwrapped = unwrap_box(copy kid);
             // Hide the box in an option so we can get it across the
             // task boundary without copying it
-            let swappable : ~mut Option<*shared_box<Box>> = ~mut Some(unwrapped);
+            let swappable : ~mut Option<*shared_box<RenderBox>> = ~mut Some(unwrapped);
 
             do task::spawn |copy top_down, copy bottom_up| {
                 // Get the box out of the option and into the new task
                 let mut swapped_in = None;
                 swapped_in <-> *swappable;
 
-                // Retrieve the original @Box and recurse
+                // Retrieve the original @RenderBox and recurse
                 let new_kid = rewrap_box(option::unwrap(swapped_in));
                 traverse_helper(new_kid, copy returned, copy top_down, copy bottom_up);
 
                 ack_chan.send(());
             }
         }
 
         // wait for all the children to finish before preceding
         for count.times() { ack_chan.recv(); }
     }
 
     bottom_up(root);
 }
 
 #[doc="A noneffectful function to be used if only one pass is required."]
-fn nop(_box : @Box) {
+fn nop(_box : @RenderBox) {
     return;
 }
 
 #[doc= "
    A wrapper to change a function that only acts on a box to one that
    threasds a unit through to match travserse_helper
 "]
-fn unit_wrapper(-fun : fn~(@Box)) -> fn~(+(), @Box) {
-    fn~(+_u : (), box : @Box) { fun(box); }
+fn unit_wrapper(-fun : fn~(@RenderBox)) -> fn~(+(), @RenderBox) {
+    fn~(+_u : (), box : @RenderBox) { fun(box); }
 }
 
 #[doc="
    Iterate in parallel over the boxes in a tree, applying one function
    to a parent before recursing on its children and one after.
 "]
-fn full_traversal(+root : @Box, -top_down : fn~(@Box), -bottom_up : fn~(@Box)) {
+fn full_traversal(+root : @RenderBox, -top_down : fn~(@RenderBox), -bottom_up : fn~(@RenderBox)) {
     traverse_helper(root, (), unit_wrapper(top_down), bottom_up);
 }
 
 #[doc="
    Iterate in parallel over the boxes in a tree, applying the given
    function to a parent before its children.
 "]
-fn top_down_traversal(+root : @Box, -top_down : fn~(@Box)) {
+fn top_down_traversal(+root : @RenderBox, -top_down : fn~(@RenderBox)) {
     traverse_helper(root, (), unit_wrapper(top_down), nop);
 }
 
 #[doc="
    Iterate in parallel over the boxes in a tree, applying the given
    function to a parent after its children.
 "]
-fn bottom_up_traversal(+root : @Box, -bottom_up : fn~(@Box)) {
+fn bottom_up_traversal(+root : @RenderBox, -bottom_up : fn~(@RenderBox)) {
     traverse_helper(root, (), unit_wrapper(nop), bottom_up);
 }
 
 #[doc="
    Iterate in parallel over the boxes in a tree, applying the given
    function to a parent before its children, the value returned by the
    function is passed to each child when they are recursed upon.  As
    the recursion unwinds, the second function is applied to first the
    children in parallel, and then the parent.
 "]
-fn extended_full_traversal<T : Copy Send>(+root : @Box, first_val : T, 
-                                          -top_down : fn~(+T, @Box) -> T,
-                                          -bottom_up : fn~(@Box)) {
+fn extended_full_traversal<T : Copy Send>(+root : @RenderBox, first_val : T, 
+                                          -top_down : fn~(+T, @RenderBox) -> T,
+                                          -bottom_up : fn~(@RenderBox)) {
     traverse_helper(root, first_val, top_down, bottom_up);
 }
 
 #[doc="
    Iterate in parallel over the boxes in a tree, applying the given
    function to a parent before its children, the value returned by the
    function is passed to each child when they are recursed upon.
 "]
-fn extended_top_down_traversal<T : Copy Send>(+root : @Box, first_val : T,
-                                              -top_down : fn~(+T, @Box) -> T) {
+fn extended_top_down_traversal<T : Copy Send>(+root : @RenderBox, first_val : T,
+                                              -top_down : fn~(+T, @RenderBox) -> T) {
     traverse_helper(root, first_val, top_down, nop);
 }