Merge RootFlow into BlockFlow

This commit is contained in:
Seth Fowler 2013-05-10 18:20:14 -07:00
parent b69a1e1ebd
commit c0d8836e06
5 changed files with 77 additions and 229 deletions

View file

@ -7,7 +7,7 @@
use layout::box::{RenderBox};
use layout::context::LayoutContext;
use layout::display_list_builder::{DisplayListBuilder, FlowDisplayListBuilderMethods};
use layout::flow::{BlockFlow, FlowContext, FlowData, InlineBlockFlow, RootFlow};
use layout::flow::{BlockFlow, FlowContext, FlowData, InlineBlockFlow};
use layout::inline::InlineLayout;
use au = gfx::geometry;
@ -23,7 +23,10 @@ pub struct BlockFlowData {
common: FlowData,
/// The associated render box.
box: Option<RenderBox>
box: Option<RenderBox>,
/// Whether this block flow is the root flow.
is_root: bool
}
impl BlockFlowData {
@ -31,53 +34,41 @@ impl BlockFlowData {
BlockFlowData {
common: common,
box: None,
is_root: false
}
}
pub fn new_root(common: FlowData) -> BlockFlowData {
BlockFlowData {
common: common,
box: None,
is_root: true
}
}
}
/// NB: These are part of FlowContext, not part of BlockFlowData, because the root flow calls these
/// as well. It is not clear to me whether this needs to be the case, or whether `RootFlow` can be
/// merged into this.
pub trait BlockLayout {
fn starts_root_flow(&self) -> bool;
fn starts_block_flow(&self) -> bool;
fn with_block_box(&self, &fn(box: RenderBox) -> ()) -> ();
fn bubble_widths_block(&self, ctx: &LayoutContext);
fn assign_widths_block(&self, ctx: &LayoutContext);
fn assign_height_block(&self, ctx: &LayoutContext);
fn build_display_list_block(&self,
a: &DisplayListBuilder,
b: &Rect<Au>,
c: &Point2D<Au>,
d: &Cell<DisplayList>);
}
impl BlockLayout for FlowContext {
fn starts_block_flow(&self) -> bool {
fn starts_root_flow(&self) -> bool {
match *self {
RootFlow(*) | BlockFlow(*) | InlineBlockFlow(*) => true,
BlockFlow(info) => info.is_root,
_ => false
}
}
/// 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.
fn with_block_box(&self, callback: &fn(box: RenderBox) -> ()) -> () {
fn starts_block_flow(&self) -> bool {
match *self {
BlockFlow(*) => {
for self.block().box.each |&b| {
callback(b);
BlockFlow(*) | InlineBlockFlow(*) => true,
_ => false
}
},
RootFlow(*) => {
for self.root().box.each |&b| {
callback(b);
}
},
_ => fail!(fmt!("Tried to do something with_block_box(), but this is a %?", self))
}
}
impl BlockFlowData {
/* Recursively (bottom-up) determine the context's preferred and
minimum widths. When called on this context, all child contexts
have had their min/pref widths set. This function must decide
@ -87,14 +78,12 @@ impl BlockLayout for FlowContext {
/* TODO: floats */
/* TODO: absolute contexts */
/* TODO: inline-blocks */
fn bubble_widths_block(&self, ctx: &LayoutContext) {
assert!(self.starts_block_flow());
pub fn bubble_widths_block(@mut self, ctx: &LayoutContext) {
let mut min_width = Au(0);
let mut pref_width = Au(0);
/* find max width from child block contexts */
for self.each_child |child_ctx| {
for BlockFlow(self).each_child |child_ctx| {
assert!(child_ctx.starts_block_flow() || child_ctx.starts_inline_flow());
do child_ctx.with_imm_node |child_node| {
@ -105,15 +94,13 @@ impl BlockLayout for FlowContext {
/* if not an anonymous block context, add in block box's widths.
these widths will not include child elements, just padding etc. */
do self.with_block_box |box| {
self.box.map(|&box| {
min_width = min_width.add(&box.get_min_width(ctx));
pref_width = pref_width.add(&box.get_pref_width(ctx));
}
});
do self.with_mut_node |this_node| {
this_node.min_width = min_width;
this_node.pref_width = pref_width;
}
self.common.min_width = min_width;
self.common.pref_width = pref_width;
}
/// Recursively (top-down) determines the actual width of child contexts and boxes. When called
@ -121,23 +108,26 @@ impl BlockLayout for FlowContext {
///
/// Dual boxes consume some width first, and the remainder is assigned to all child (block)
/// contexts.
fn assign_widths_block(&self, _: &LayoutContext) {
assert!(self.starts_block_flow());
pub fn assign_widths_block(@mut self, ctx: &LayoutContext) {
if self.is_root {
self.common.position.origin = Au::zero_point();
self.common.position.size.width = ctx.screen_size.size.width;
}
let mut remaining_width = self.with_imm_node(|this| this.position.size.width);
let mut remaining_width = self.common.position.size.width;
let left_used = Au(0);
// Let the box consume some width. It will return the amount remaining for its children.
do self.with_block_box |box| {
self.box.map(|&box| {
do box.with_mut_base |base| {
base.position.size.width = remaining_width;
let (left_used, right_used) = box.get_used_width();
remaining_width -= left_used.add(&right_used);
}
}
});
for self.each_child |kid| {
for BlockFlow(self).each_child |kid| {
assert!(kid.starts_block_flow() || kid.starts_inline_flow());
do kid.with_mut_node |child_node| {
@ -147,51 +137,50 @@ impl BlockLayout for FlowContext {
}
}
fn assign_height_block(&self, _ctx: &LayoutContext) {
assert!(self.starts_block_flow());
pub fn assign_height_block(@mut self, ctx: &LayoutContext) {
let mut cur_y = Au(0);
for self.each_child |kid| {
for BlockFlow(self).each_child |kid| {
do kid.with_mut_node |child_node| {
child_node.position.origin.y = cur_y;
cur_y += child_node.position.size.height;
}
}
do self.with_mut_node |this_node| {
this_node.position.size.height = cur_y;
}
let height = if self.is_root { Au::max(ctx.screen_size.size.height, cur_y) }
else { cur_y };
self.common.position.size.height = height;
let _used_top = Au(0);
let _used_bot = Au(0);
do self.with_block_box |box| {
self.box.map(|&box| {
do box.with_mut_base |base| {
base.position.origin.y = Au(0);
base.position.size.height = cur_y;
base.position.size.height = height;
let (_used_top, _used_bot) = box.get_used_height();
}
}
});
}
fn build_display_list_block(&self,
pub fn build_display_list_block(@mut self,
builder: &DisplayListBuilder,
dirty: &Rect<Au>,
offset: &Point2D<Au>,
list: &Cell<DisplayList>) {
assert!(self.starts_block_flow());
// add box that starts block context
do self.with_block_box |box| {
self.box.map(|&box| {
box.build_display_list(builder, dirty, offset, list)
}
});
// TODO: handle any out-of-flow elements
// go deeper into the flow tree
for self.each_child |child| {
self.build_display_list_for_child(builder, child, dirty, offset, list)
let flow = BlockFlow(self);
for flow.each_child |child| {
flow.build_display_list_for_child(builder, child, dirty, offset, list)
}
}
}

View file

@ -15,9 +15,8 @@ use layout::context::LayoutContext;
use layout::debug::{BoxedMutDebugMethods, DebugMethods};
use layout::flow::{AbsoluteFlow, BlockFlow, FloatFlow, Flow_Absolute, Flow_Block, Flow_Float};
use layout::flow::{Flow_Inline, Flow_InlineBlock, Flow_Root, Flow_Table, FlowContext};
use layout::flow::{FlowContextType, FlowData, InlineBlockFlow, InlineFlow, RootFlow, TableFlow};
use layout::flow::{FlowContextType, FlowData, InlineBlockFlow, InlineFlow, TableFlow};
use layout::inline::{InlineFlowData, InlineLayout};
use layout::root::RootFlowData;
use newcss::values::{CSSDisplay, CSSDisplayBlock, CSSDisplayInline, CSSDisplayInlineBlock};
use newcss::values::{CSSDisplayNone};
@ -153,18 +152,6 @@ impl BoxGenerator {
assert!(block.box.is_none());
block.box = Some(new_box);
},
RootFlow(root) => {
debug!("BoxGenerator[f%d]: point c", root.common.id);
let new_box = builder.make_box(ctx, box_type, node, self.flow);
debug!("BoxGenerator[f%d]: (node is: %s)", root.common.id, node.debug_str());
debug!("BoxGenerator[f%d]: attaching box[b%d] to root flow (node: %s)",
root.common.id,
new_box.id(),
node.debug_str());
assert!(root.box.is_none());
root.box = Some(new_box);
},
_ => warn!("push_node() not implemented for flow f%d", self.flow.id()),
}
}
@ -195,7 +182,7 @@ impl BoxGenerator {
debug!("BoxGenerator: adding element range=%?", node_range);
inline.elems.add_mapping(node, &node_range);
},
BlockFlow(*) | RootFlow(*) => assert!(self.range_stack.len() == 0),
BlockFlow(*) => assert!(self.range_stack.len() == 0),
_ => warn!("pop_node() not implemented for flow %?", self.flow.id()),
}
}
@ -279,17 +266,15 @@ impl BuilderContext {
};
let containing_context = match (simulated_display, self.default_collector.flow) {
(CSSDisplayBlock, RootFlow(*)) => {
(CSSDisplayBlock, BlockFlow(info)) => match (info.is_root, node.parent_node()) {
// If this is the root node, then use the root flow's
// context. Otherwise, make a child block context.
match node.parent_node() {
Some(_) => { self.create_child_flow_of_type(Flow_Block, builder, node) }
None => { self.clone() },
}
},
(CSSDisplayBlock, BlockFlow(*)) => {
(true, Some(_)) => { self.create_child_flow_of_type(Flow_Block, builder, node) }
(true, None) => { self.clone() }
(false, _) => {
self.clear_inline_collector();
self.create_child_flow_of_type(Flow_Block, builder, node)
}
},
(CSSDisplayInline, InlineFlow(*)) => self.clone(),
(CSSDisplayInlineBlock, InlineFlow(*)) => self.clone(),
@ -453,7 +438,7 @@ pub impl LayoutTreeBuilder {
Flow_Float => FloatFlow(@mut info),
Flow_InlineBlock => InlineBlockFlow(@mut info),
Flow_Inline => InlineFlow(@mut InlineFlowData::new(info)),
Flow_Root => RootFlow(@mut RootFlowData::new(info)),
Flow_Root => BlockFlow(@mut BlockFlowData::new_root(info)),
Flow_Table => TableFlow(@mut info),
};
debug!("LayoutTreeBuilder: created flow: %s", result.debug_str());

View file

@ -17,24 +17,21 @@
/// * `BlockFlow`: A flow that establishes a block context. It has several child flows, each of
/// which are positioned according to block formatting context rules (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.)
/// (In the future, this render box may be folded into `BlockFlow` to save space.) The BlockFlow
/// at the root of the tree has special behavior: it stretches to the boundaries of the viewport.
///
/// * `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()` and
/// similar methods.
///
/// * `RootFlow`: The flow at the root of the tree. This flow behaves like a `BlockFlow`, except
/// that stretches to the boundaries of the viewport.
use dom::node::AbstractNode;
use layout::block::{BlockFlowData, BlockLayout};
use layout::block::{BlockFlowData};
use layout::box::RenderBox;
use layout::context::LayoutContext;
use layout::debug::DebugMethods;
use layout::display_list_builder::DisplayListBuilder;
use layout::inline::{InlineFlowData};
use layout::root::{RootFlowData};
use core::cell::Cell;
use geom::point::Point2D;
@ -51,7 +48,6 @@ pub enum FlowContext {
FloatFlow(@mut FlowData),
InlineBlockFlow(@mut FlowData),
InlineFlow(@mut InlineFlowData),
RootFlow(@mut RootFlowData),
TableFlow(@mut FlowData),
}
@ -83,10 +79,7 @@ impl TreeNodeRef<FlowData> for FlowContext {
InlineFlow(info) => {
callback(&info.common)
}
RootFlow(info) => {
callback(&info.common)
}
TableFlow(info) => callback(info),
TableFlow(info) => callback(info)
}
}
fn with_mut_node<R>(&self, callback: &fn(&mut FlowData) -> R) -> R {
@ -100,9 +93,6 @@ impl TreeNodeRef<FlowData> for FlowContext {
InlineFlow(info) => {
callback(&mut info.common)
}
RootFlow(info) => {
callback(&mut info.common)
}
TableFlow(info) => callback(info),
}
}
@ -227,36 +217,33 @@ impl<'self> FlowContext {
}
}
pub fn root(&self) -> @mut RootFlowData {
pub fn root(&self) -> @mut BlockFlowData {
match *self {
RootFlow(info) => info,
_ => fail!(fmt!("Tried to access root data of non-root: f%d", self.id()))
BlockFlow(info) if info.is_root => info,
_ => fail!(fmt!("Tried to access root block data of non-root: f%d", self.id()))
}
}
pub fn bubble_widths(&self, ctx: &mut LayoutContext) {
match *self {
BlockFlow(*) => self.bubble_widths_block(ctx),
BlockFlow(info) => info.bubble_widths_block(ctx),
InlineFlow(info) => info.bubble_widths_inline(ctx),
RootFlow(info) => info.bubble_widths_root(ctx),
_ => fail!(fmt!("Tried to bubble_widths of flow: f%d", self.id()))
}
}
pub fn assign_widths(&self, ctx: &mut LayoutContext) {
match *self {
BlockFlow(*) => self.assign_widths_block(ctx),
BlockFlow(info) => info.assign_widths_block(ctx),
InlineFlow(info) => info.assign_widths_inline(ctx),
RootFlow(info) => info.assign_widths_root(ctx),
_ => fail!(fmt!("Tried to assign_widths of flow: f%d", self.id()))
}
}
pub fn assign_height(&self, ctx: &mut LayoutContext) {
match *self {
BlockFlow(*) => self.assign_height_block(ctx),
BlockFlow(info) => info.assign_height_block(ctx),
InlineFlow(info) => info.assign_height_inline(ctx),
RootFlow(info) => info.assign_height_root(ctx),
_ => fail!(fmt!("Tried to assign_height of flow: f%d", self.id()))
}
}
@ -271,8 +258,7 @@ impl<'self> FlowContext {
}
match *self {
RootFlow(info) => info.build_display_list_root(builder, dirty, offset, list),
BlockFlow(*) => self.build_display_list_block(builder, dirty, offset, list),
BlockFlow(info) => info.build_display_list_block(builder, dirty, offset, list),
InlineFlow(info) => info.build_display_list_inline(builder, dirty, offset, list),
_ => fail!(fmt!("Tried to build_display_list_recurse of flow: %?", self))
}
@ -281,12 +267,6 @@ impl<'self> FlowContext {
// Actual methods that do not require much flow-specific logic
pub fn foldl_all_boxes<B:Copy>(&self, seed: B, cb: &fn(a: B, b: RenderBox) -> B) -> B {
match *self {
RootFlow(root) => {
let root = &mut *root;
do root.box.map_default(seed) |box| {
cb(seed, *box)
}
}
BlockFlow(block) => {
let block = &mut *block;
do block.box.map_default(seed) |box| {
@ -319,14 +299,6 @@ impl<'self> FlowContext {
pub fn iter_all_boxes(&self, cb: &fn(RenderBox) -> bool) {
match *self {
RootFlow(root) => {
let root = &mut *root;
for root.box.each |box| {
if !cb(*box) {
break;
}
}
}
BlockFlow(block) => {
let block = &mut *block;
for block.box.each |box| {
@ -394,12 +366,6 @@ impl DebugMethods for FlowContext {
None => ~"BlockFlow",
}
},
RootFlow(root) => {
match root.box {
Some(box) => fmt!("RootFlow(box=b%d)", box.id()),
None => ~"RootFlow",
}
},
_ => ~"(Unknown flow)"
};

View file

@ -1,91 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use core::cell::Cell;
use geom::point::Point2D;
use geom::rect::Rect;
use gfx::display_list::DisplayList;
use gfx::geometry::Au;
use layout::block::BlockLayout;
use layout::box::RenderBox;
use layout::context::LayoutContext;
use layout::flow::{FlowContext, FlowData, RootFlow};
use layout::display_list_builder::DisplayListBuilder;
use servo_util::tree::{TreeNodeRef, TreeUtils};
pub struct RootFlowData {
/// Data common to all flows.
common: FlowData,
/// The render box at the root of the tree.
box: Option<RenderBox>
}
impl RootFlowData {
pub fn new(common: FlowData) -> RootFlowData {
RootFlowData {
common: common,
box: None,
}
}
}
pub trait RootLayout {
fn starts_root_flow(&self) -> bool;
}
impl RootLayout for FlowContext {
fn starts_root_flow(&self) -> bool {
match *self {
RootFlow(*) => true,
_ => false
}
}
}
impl RootFlowData {
/// Defer to the block algorithm.
pub fn bubble_widths_root(@mut self, ctx: &LayoutContext) {
RootFlow(self).bubble_widths_block(ctx)
}
pub fn assign_widths_root(@mut self, ctx: &LayoutContext) {
self.common.position.origin = Au::zero_point();
self.common.position.size.width = ctx.screen_size.size.width;
RootFlow(self).assign_widths_block(ctx)
}
pub fn assign_height_root(@mut self, ctx: &LayoutContext) {
// this is essentially the same as assign_height_block(), except
// the root adjusts self height to at least cover the viewport.
let mut cur_y = Au(0);
for RootFlow(self).each_child |child_flow| {
do child_flow.with_mut_node |child_node| {
child_node.position.origin.y = cur_y;
cur_y += child_node.position.size.height;
}
}
self.common.position.size.height = Au::max(ctx.screen_size.size.height, cur_y);
do RootFlow(self).with_block_box |box| {
do box.with_mut_base |base| {
base.position.origin.y = Au(0);
base.position.size.height = Au::max(ctx.screen_size.size.height, cur_y);
let (_used_top, _used_bot) = box.get_used_height();
}
}
}
pub fn build_display_list_root(@mut self,
builder: &DisplayListBuilder,
dirty: &Rect<Au>,
offset: &Point2D<Au>,
list: &Cell<DisplayList>) {
RootFlow(self).build_display_list_block(builder, dirty, offset, list);
}
}

View file

@ -111,7 +111,6 @@ pub mod layout {
pub mod flow;
pub mod layout_task;
pub mod inline;
pub mod root;
pub mod text;
mod aux;
}