Refactor FlowContext to have the preferred nesting strategy of enum variants and structs.

This commit is contained in:
Brian J. Burg 2012-09-26 18:17:44 -07:00
parent e89d2fa782
commit 49de0a7fac
7 changed files with 207 additions and 190 deletions

View file

@ -22,7 +22,6 @@ fn BlockFlowData() -> BlockFlowData {
trait BlockLayout {
pure fn starts_block_flow() -> bool;
pure fn access_block<T>(fn(&&BlockFlowData) -> T) -> T;
pure fn with_block_box(fn(&&@RenderBox) -> ()) -> ();
fn bubble_widths_block(ctx: &LayoutContext);
@ -36,36 +35,25 @@ trait BlockLayout {
impl FlowContext : BlockLayout {
pure fn starts_block_flow() -> bool {
match self.kind {
match self {
RootFlow(*) | BlockFlow(*) | InlineBlockFlow(*) => true,
_ => false
}
}
pure fn access_block<T>(cb:fn(&&BlockFlowData) -> T) -> T {
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(&&@RenderBox) -> ()) -> () {
match self.kind {
BlockFlow(*) => {
do self.access_block |d| {
let mut box = d.box;
box.iter(cb)
}
},
match self {
BlockFlow(*) => {
let mut box = self.block().box;
box.iter(cb);
},
RootFlow(*) => {
do self.access_root |d| {
let mut box = d.box;
box.iter(cb)
}
let mut box = self.root().box;
box.iter(cb);
},
_ => fail fmt!("Tried to do something with_block_box(), but this is a %?", self.kind)
_ => fail fmt!("Tried to do something with_block_box(), but this is a %?", self)
}
}
@ -88,8 +76,8 @@ impl FlowContext : BlockLayout {
for FlowTree.each_child(@self) |child_ctx| {
assert child_ctx.starts_block_flow() || child_ctx.starts_inline_flow();
min_width = au::max(min_width, child_ctx.data.min_width);
pref_width = au::max(pref_width, child_ctx.data.pref_width);
min_width = au::max(min_width, child_ctx.d().min_width);
pref_width = au::max(pref_width, child_ctx.d().pref_width);
}
/* if not an anonymous block context, add in block box's widths.
@ -99,8 +87,8 @@ impl FlowContext : BlockLayout {
pref_width = pref_width.add(box.get_pref_width());
}
self.data.min_width = min_width;
self.data.pref_width = pref_width;
self.d().min_width = min_width;
self.d().pref_width = pref_width;
}
/* Recursively (top-down) determines the actual width of child
@ -113,7 +101,7 @@ impl FlowContext : BlockLayout {
fn assign_widths_block(_ctx: &LayoutContext) {
assert self.starts_block_flow();
let mut remaining_width = self.data.position.size.width;
let mut remaining_width = self.d().position.size.width;
let mut _right_used = au(0);
let mut left_used = au(0);
@ -127,8 +115,8 @@ impl FlowContext : BlockLayout {
for FlowTree.each_child(@self) |child_ctx| {
assert child_ctx.starts_block_flow() || child_ctx.starts_inline_flow();
child_ctx.data.position.origin.x = left_used;
child_ctx.data.position.size.width = remaining_width;
child_ctx.d().position.origin.x = left_used;
child_ctx.d().position.size.width = remaining_width;
}
}
@ -138,11 +126,11 @@ impl FlowContext : BlockLayout {
let mut cur_y = au(0);
for FlowTree.each_child(@self) |child_ctx| {
child_ctx.data.position.origin.y = cur_y;
cur_y = cur_y.add(child_ctx.data.position.size.height);
child_ctx.d().position.origin.y = cur_y;
cur_y = cur_y.add(child_ctx.d().position.size.height);
}
self.data.position.size.height = cur_y;
self.d().position.size.height = cur_y;
let _used_top = au(0);
let _used_bot = au(0);

View file

@ -7,10 +7,10 @@ use css::values::{Inherit, Initial, Specified};
use dom::element::*;
use dom::node::{Comment, Doctype, Element, Text, Node, NodeTree, LayoutData};
use image::holder::ImageHolder;
use layout::flow::{FlowContext, FlowContextData, BlockFlow, InlineFlow, InlineBlockFlow, RootFlow, FlowTree};
use layout::box::*;
use layout::block::BlockFlowData;
use layout::context::LayoutContext;
use layout::flow::*;
use layout::inline::InlineFlowData;
use layout::root::RootFlowData;
use layout::text::TextBoxData;
@ -69,7 +69,7 @@ impl LayoutTreeBuilder {
if (parent_ctx.starts_inline_flow()) {
parent_ctx
} else {
self.make_ctx(InlineFlow(InlineFlowData()), tree::empty())
self.make_ctx(Flow_Inline)
}
},
RenderBox_Image | RenderBox_Generic => {
@ -80,12 +80,12 @@ impl LayoutTreeBuilder {
if (parent_ctx.starts_inline_flow()) {
parent_ctx
} else {
self.make_ctx(InlineFlow(InlineFlowData()), tree::empty())
self.make_ctx(Flow_Inline)
}
},
/* block boxes always create a new context */
DisplayBlock => {
self.make_ctx(BlockFlow(BlockFlowData()), tree::empty())
self.make_ctx(Flow_Block)
},
_ => fail fmt!("unsupported display type in box generation: %?", simulated_display)
}
@ -101,25 +101,27 @@ impl LayoutTreeBuilder {
let mut new_box = self.make_box(layout_ctx, box_type, cur_node, parent_ctx);
debug!("Assign ^box to flow: %?", next_ctx.debug_str());
match next_ctx.kind {
InlineFlow(d) => {
d.boxes.push(new_box);
match *next_ctx {
InlineFlow(*) => {
next_ctx.inline().boxes.push(new_box);
if (parent_box.is_some()) {
let parent = parent_box.get();
// connect the box to its parent box
debug!("In inline flow f%?, set child b%? of parent b%?", next_ctx.id, parent.d().id, new_box.d().id);
debug!("In inline flow f%?, set child b%? of parent b%?",
next_ctx.d().id, parent.d().id, new_box.d().id);
RenderBoxTree.add_child(parent, new_box);
}
}
BlockFlow(d) => { d.box = Some(new_box) }
BlockFlow(*) => next_ctx.block().box = Some(new_box),
_ => {} // TODO: float lists, etc.
};
if !core::box::ptr_eq(next_ctx, parent_ctx) {
debug!("Adding child flow f%? of f%?", parent_ctx.id, next_ctx.id);
debug!("Adding child flow f%? of f%?",
parent_ctx.d().id, next_ctx.d().id);
FlowTree.add_child(parent_ctx, next_ctx);
}
// recurse
@ -134,8 +136,8 @@ impl LayoutTreeBuilder {
let mut found_child_block = false;
do FlowTree.each_child(next_ctx) |child_ctx| {
match child_ctx.kind {
InlineFlow(*) | InlineBlockFlow => found_child_inline = true,
match *child_ctx {
InlineFlow(*) | InlineBlockFlow(*) => found_child_inline = true,
BlockFlow(*) => found_child_block = true,
_ => {}
}; true
@ -176,14 +178,22 @@ impl LayoutTreeBuilder {
/** entry point for box creation. Should only be
called on root DOM element. */
fn construct_trees(layout_ctx: &LayoutContext, root: Node) -> Result<@FlowContext, ()> {
self.root_ctx = Some(self.make_ctx(RootFlow(RootFlowData()), tree::empty()));
self.root_ctx = Some(self.make_ctx(Flow_Root));
self.construct_recursively(layout_ctx, root, self.root_ctx.get(), None);
return Ok(self.root_ctx.get())
}
fn make_ctx(kind : FlowContextData, tree: tree::Tree<@FlowContext>) -> @FlowContext {
let ret = @FlowContext(self.next_ctx_id(), kind, tree);
fn make_ctx(ty : FlowContextType) -> @FlowContext {
let data = FlowData(self.next_ctx_id());
let ret = match ty {
Flow_Absolute => @AbsoluteFlow(data),
Flow_Block => @BlockFlow(data, BlockFlowData()),
Flow_Float => @FloatFlow(data),
Flow_InlineBlock => @InlineBlockFlow(data),
Flow_Inline => @InlineFlow(data, InlineFlowData()),
Flow_Root => @RootFlow(data, RootFlowData()),
Flow_Table => @TableFlow(data)
};
debug!("Created context: %s", ret.debug_str());
ret
}

View file

@ -49,10 +49,10 @@ impl FlowContext: FlowDisplayListBuilderMethods {
dirty: &Rect<au>, offset: &Point2D<au>, list: &dl::DisplayList) {
// 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);
let adj_dirty = dirty.translate(&child.d().position.origin);
let adj_offset = offset.add(&child.d().position.origin);
if (adj_dirty.intersects(&child.data.position)) {
if (adj_dirty.intersects(&child.d().position)) {
child.build_display_list_recurse(builder, &adj_dirty, &adj_offset, list);
}
}

View file

@ -40,8 +40,74 @@ Currently, the important types of flows are:
*/
/* The type of the formatting context, and data specific to each
context, such as linebox structures or float lists */
enum FlowContext {
AbsoluteFlow(FlowData),
BlockFlow(FlowData, BlockFlowData),
FloatFlow(FlowData),
InlineBlockFlow(FlowData),
InlineFlow(FlowData, InlineFlowData),
RootFlow(FlowData, RootFlowData),
TableFlow(FlowData)
}
struct FlowLayoutData {
enum FlowContextType {
Flow_Absolute,
Flow_Block,
Flow_Float,
Flow_InlineBlock,
Flow_Inline,
Flow_Root,
Flow_Table
}
impl FlowContext {
pure fn d(&self) -> &self/FlowData {
match *self {
AbsoluteFlow(ref d) => d,
BlockFlow(ref d, _) => d,
FloatFlow(ref d) => d,
InlineBlockFlow(ref d) => d,
InlineFlow(ref d, _) => d,
RootFlow(ref d, _) => d,
TableFlow(ref d) => d
}
}
pure fn inline(&self) -> &self/InlineFlowData {
match *self {
InlineFlow(_, ref i) => i,
_ => fail fmt!("Tried to access inline data of non-inline: %?", self)
}
}
pure fn block(&self) -> &self/BlockFlowData {
match *self {
BlockFlow(_, ref b) => b,
_ => fail fmt!("Tried to access block data of non-block: %?", self)
}
}
pure fn root(&self) -> &self/RootFlowData {
match *self {
RootFlow(_, ref r) => r,
_ => fail fmt!("Tried to access root data of non-root: %?", self)
}
}
}
/* A particular kind of layout context. It manages the positioning of
render boxes within the context. */
struct FlowData {
mut node: Option<Node>,
/* reference to parent, children flow contexts */
tree: tree::Tree<@FlowContext>,
/* TODO (Issue #87): debug only */
mut id: int,
/* layout computations */
// 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,
@ -49,85 +115,55 @@ struct FlowLayoutData {
mut position: Rect<au>,
}
fn FlowLayoutData() -> FlowLayoutData {
FlowLayoutData {
fn FlowData(id: int) -> FlowData {
FlowData {
node: None,
tree: tree::empty(),
id: id,
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 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
render boxes within the context. */
struct FlowContext {
kind: FlowContextData,
data: FlowLayoutData,
mut node: Option<Node>,
/* reference to parent, children flow contexts */
tree: tree::Tree<@FlowContext>,
/* TODO (Issue #87): debug only */
mut id: int
}
fn FlowContext(id: int, kind: FlowContextData, tree: tree::Tree<@FlowContext>) -> FlowContext {
FlowContext {
kind: kind,
data: FlowLayoutData(),
node: None,
tree: tree,
id: id
position: au::zero_rect()
}
}
/* Flow context disambiguation methods: the verbose alternative to virtual methods */
impl FlowContext {
fn bubble_widths(ctx: &LayoutContext) {
match self.kind {
match self {
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)
_ => fail fmt!("Tried to bubble_widths of flow: %?", self)
}
}
fn assign_widths(ctx: &LayoutContext) {
match self.kind {
match self {
BlockFlow(*) => self.assign_widths_block(ctx),
InlineFlow(*) => self.assign_widths_inline(ctx),
RootFlow(*) => self.assign_widths_root(ctx),
_ => fail fmt!("Tried to assign_widths of flow: %?", self.kind)
_ => fail fmt!("Tried to assign_widths of flow: %?", self)
}
}
fn assign_height(ctx: &LayoutContext) {
match self.kind {
match self {
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)
_ => fail fmt!("Tried to assign_height of flow: %?", self)
}
}
fn build_display_list_recurse(builder: &dl::DisplayListBuilder, dirty: &Rect<au>,
offset: &Point2D<au>, list: &dl::DisplayList) {
match self.kind {
match self {
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)
_ => fail fmt!("Tried to build_display_list_recurse of flow: %?", self)
}
}
}
@ -135,39 +171,39 @@ impl FlowContext {
// Actual methods that do not require much flow-specific logic
impl FlowContext {
pure fn foldl_boxes_for_node<B: Copy>(node: Node, seed: B, blk: pure fn&(B,@RenderBox) -> B) -> B {
match self.kind {
RootFlow(d) => match d.box {
match self {
RootFlow(*) => match self.root().box {
Some(box) if box.d().node == node => { blk(seed, box) },
_ => seed
},
BlockFlow(d) => match d.box {
BlockFlow(*) => match self.block().box {
Some(box) if box.d().node == node => { blk(seed, box) },
_ => seed
},
InlineFlow(d) => do d.boxes.foldl(seed) |acc, box| {
InlineFlow(*) => do self.inline().boxes.foldl(seed) |acc, box| {
if box.d().node == node { blk(acc, box) }
else { acc }
},
_ => fail fmt!("Don't know how to iterate node's RenderBoxes for %?", self.kind)
_ => fail fmt!("Don't know how to iterate node's RenderBoxes for %?", self)
}
}
pure fn iter_boxes_for_node<T>(node: Node, cb: pure fn&(@RenderBox) -> T) {
match self.kind {
RootFlow(d) => match d.box {
match self {
RootFlow(*) => match self.root().box {
Some(box) if box.d().node == node => { cb(box); },
_ => {}
},
BlockFlow(d) => match d.box {
BlockFlow(*) => match self.block().box {
Some(box) if box.d().node == node => { cb(box); },
_ => {}
},
InlineFlow(d) => {
for d.boxes.each |box| {
InlineFlow(*) => {
for self.inline().boxes.each |box| {
if box.d().node == node { cb(*box); }
}
},
_ => fail fmt!("Don't know how to iterate node's RenderBoxes for %?", self.kind)
_ => fail fmt!("Don't know how to iterate node's RenderBoxes for %?", self)
}
}
}
@ -182,7 +218,7 @@ impl FlowTree : tree::ReadMethods<@FlowContext> {
}
fn with_tree_fields<R>(&&b: @FlowContext, f: fn(tree::Tree<@FlowContext>) -> R) -> R {
f(b.tree)
f(b.d().tree)
}
}
@ -193,7 +229,7 @@ impl FlowTree : tree::WriteMethods<@FlowContext> {
}
fn with_tree_fields<R>(&&b: @FlowContext, f: fn(tree::Tree<@FlowContext>) -> R) -> R {
f(b.tree)
f(b.d().tree)
}
}
@ -220,22 +256,28 @@ impl FlowContext : BoxedDebugMethods {
/* TODO: we need a string builder. This is horribly inefficient */
fn debug_str(@self) -> ~str {
let repr = match self.kind {
InlineFlow(d) => {
let mut s = d.boxes.foldl(~"InlineFlow(children=", |s, box| {
let repr = match *self {
InlineFlow(*) => {
let mut s = self.inline().boxes.foldl(~"InlineFlow(children=", |s, box| {
fmt!("%s %?", s, box.d().id)
});
s += ~")"; s
},
BlockFlow(d) => {
match d.box {
Some(_b) => fmt!("BlockFlow(box=b%?)", d.box.get().d().id),
BlockFlow(*) => {
match self.block().box {
Some(box) => fmt!("BlockFlow(box=b%?)", box.d().id),
None => ~"BlockFlow",
}
},
_ => fmt!("%?", self.kind)
RootFlow(*) => {
match self.root().box {
Some(box) => fmt!("RootFlo(box=b%?)", box.d().id),
None => ~"RootFlow",
}
},
_ => ~"(Unknown flow)"
};
fmt!("c%? %?", self.id, repr)
fmt!("c%? %?", self.d().id, repr)
}
}

View file

@ -50,7 +50,6 @@ fn InlineFlowData() -> InlineFlowData {
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);
@ -58,14 +57,7 @@ trait InlineLayout {
}
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),
_ => fail fmt!("Tried to access() data of InlineFlow, but this is a %?", self.kind)
}
}
pure fn starts_inline_flow() -> bool { match self { InlineFlow(*) => true, _ => false } }
fn bubble_widths_inline(_ctx: &LayoutContext) {
assert self.starts_inline_flow();
@ -73,15 +65,13 @@ impl FlowContext : InlineLayout {
let mut min_width = au(0);
let mut pref_width = au(0);
do self.access_inline |d| {
for d.boxes.each |box| {
min_width = au::max(min_width, box.get_min_width());
pref_width = au::max(pref_width, box.get_pref_width());
}
for self.inline().boxes.each |box| {
min_width = au::max(min_width, box.get_min_width());
pref_width = au::max(pref_width, box.get_pref_width());
}
self.data.min_width = min_width;
self.data.pref_width = pref_width;
self.d().min_width = min_width;
self.d().pref_width = pref_width;
}
/* Recursively (top-down) determines the actual width of child
@ -91,59 +81,56 @@ impl FlowContext : InlineLayout {
assert self.starts_inline_flow();
/* Perform inline flow with the available width. */
//let avail_width = self.data.position.size.width;
//let avail_width = self.d().position.size.width;
let line_height = au::from_px(20);
//let mut cur_x = au(0);
let mut cur_y = au(0);
do self.access_inline |d| {
for d.boxes.each |box| {
/* TODO: actually do inline flow.
- Create a working linebox, and successively put boxes
into it, splitting if necessary.
- Set width and height for each positioned element based on
where its chunks ended up.
for self.inline().boxes.each |box| {
/* TODO: actually do inline flow.
- Create a working linebox, and successively put boxes
into it, splitting if necessary.
- Set width and height for each positioned element based on
where its chunks ended up.
- Save the dvec of this context's lineboxes. */
- Save the dvec of this context's lineboxes. */
/* hack: until text box splitting is hoisted into this
function, force "reflow" on TextBoxes. */
match *box {
@TextBox(*) => box.reflow_text(ctx),
_ => {}
}
/* hack: until text box splitting is hoisted into this
function, force "reflow" on TextBoxes. */
match *box {
@TextBox(*) => box.reflow_text(ctx),
_ => {}
}
box.d().position.size.width = match *box {
@ImageBox(_,img) => au::from_px(img.get_size().get_default(Size2D(0,0)).width),
@TextBox(_,d) => d.runs[0].size().width,
// TODO: this should be set to the extents of its children
@GenericBox(*) => au(0)
};
box.d().position.size.width = match *box {
@ImageBox(_,img) => au::from_px(img.get_size().get_default(Size2D(0,0)).width),
@TextBox(_,d) => d.runs[0].size().width,
// TODO: this should be set to the extents of its children
@GenericBox(*) => au(0)
};
box.d().position.size.height = match *box {
@ImageBox(_,img) => au::from_px(img.get_size().get_default(Size2D(0,0)).height),
@TextBox(_,d) => d.runs[0].size().height,
// TODO: this should be set to the extents of its children
@GenericBox(*) => au(0)
};
box.d().position.size.height = match *box {
@ImageBox(_,img) => au::from_px(img.get_size().get_default(Size2D(0,0)).height),
@TextBox(_,d) => d.runs[0].size().height,
// TODO: this should be set to the extents of its children
@GenericBox(*) => au(0)
};
box.d().position.origin = Point2D(au(0), cur_y);
cur_y = cur_y.add(au::max(line_height, box.d().position.size.height));
} // for boxes.each |box|
}
box.d().position.origin = Point2D(au(0), cur_y);
cur_y = cur_y.add(au::max(line_height, box.d().position.size.height));
} // for boxes.each |box|
self.data.position.size.height = cur_y;
/* There are no child contexts, so stop here. */
self.d().position.size.height = cur_y;
/* There are no child contexts, so stop here. */
// TODO: once there are 'inline-block' elements, this won't be
// true. In that case, perform inline flow, and then set the
// block flow context's width as the width of the
// 'inline-block' box that created this flow.
} // fn assign_widths_inline
// TODO: once there are 'inline-block' elements, this won't be
// true. In that case, perform inline flow, and then set the
// block flow context's width as the width of the
// 'inline-block' box that created this flow.
}
fn assign_height_inline(_ctx: &LayoutContext) {
// Don't need to set box or ctx heights, since that is done
@ -160,10 +147,8 @@ impl FlowContext : InlineLayout {
// 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)
}
for self.inline().boxes.each |box| {
box.build_display_list(builder, dirty, offset, list)
}
// TODO: should inline-block elements have flows as children

View file

@ -168,7 +168,7 @@ impl Layout {
};
// TODO: set options on the builder before building
// TODO: be smarter about what needs painting
layout_root.build_display_list(&builder, &copy layout_root.data.position, &dlist);
layout_root.build_display_list(&builder, &copy layout_root.d().position, &dlist);
self.render_task.send(render_task::RenderMsg(dlist));
} // time(layout)
} // BuildMsg

View file

@ -21,7 +21,6 @@ fn RootFlowData() -> RootFlowData {
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);
@ -33,19 +32,12 @@ trait RootLayout {
impl FlowContext : RootLayout {
pure fn starts_root_flow() -> bool {
match self.kind {
match self {
RootFlow(*) => true,
_ => false
}
}
pure fn access_root<T>(cb:fn(&&RootFlowData) -> T) -> T {
match self.kind {
RootFlow(d) => cb(d),
_ => fail fmt!("Tried to access() data of RootFlow, but this is a %?", self.kind)
}
}
/* defer to the block algorithm */
fn bubble_widths_root(ctx: &LayoutContext) {
assert self.starts_root_flow();
@ -55,7 +47,7 @@ impl FlowContext : RootLayout {
fn assign_widths_root(ctx: &LayoutContext) {
assert self.starts_root_flow();
self.data.position = copy ctx.screen_size;
self.d().position = copy ctx.screen_size;
self.assign_widths_block(ctx)
}