Remove 'FloatFlow'

Removes 'FloatFlow' in favor of FloatBlockFlow, which is cointained
inside BlockFlow in a 'has-a' relationship. This avoids a bunch of
duplicated code.

This patch is for:
https://github.com/mozilla/servo/issues/1281
This commit is contained in:
Bruno de Oliveira Abinader 2013-11-29 10:47:30 -04:00
parent a0c6075b4d
commit ac45d70a4a
5 changed files with 321 additions and 412 deletions

View file

@ -10,7 +10,7 @@ use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData};
use layout::flow::{BlockFlowClass, FlowClass, Flow, FlowData, ImmutableFlowUtils};
use layout::flow;
use layout::model::{MaybeAuto, Specified, Auto, specified_or_none, specified};
use layout::float_context::{FloatContext, Invalid};
use layout::float_context::{FloatContext, PlacementInfo, Invalid, FloatType};
use std::cell::Cell;
use geom::point::Point2D;
@ -20,6 +20,34 @@ use gfx::display_list::DisplayList;
use servo_util::geometry::{Au, to_frac_px};
use servo_util::geometry;
pub struct FloatedBlockInfo {
containing_width: Au,
/// Offset relative to where the parent tried to position this flow
rel_pos: Point2D<Au>,
/// Index into the box list for inline floats
index: Option<uint>,
/// Number of floated children
floated_children: uint,
/// Left or right?
float_type: FloatType
}
impl FloatedBlockInfo {
pub fn new(float_type: FloatType) -> FloatedBlockInfo {
FloatedBlockInfo {
containing_width: Au(0),
rel_pos: Point2D(Au(0), Au(0)),
index: None,
floated_children: 0,
float_type: float_type
}
}
}
pub struct BlockFlow {
/// Data common to all flows.
base: FlowData,
@ -28,7 +56,10 @@ pub struct BlockFlow {
box: Option<@RenderBox>,
/// Whether this block flow is the root flow.
is_root: bool
is_root: bool,
// Additional floating flow members.
float: Option<~FloatedBlockInfo>
}
impl BlockFlow {
@ -36,7 +67,8 @@ impl BlockFlow {
BlockFlow {
base: base,
box: None,
is_root: false
is_root: false,
float: None
}
}
@ -44,7 +76,17 @@ impl BlockFlow {
BlockFlow {
base: base,
box: Some(box),
is_root: false
is_root: false,
float: None
}
}
pub fn float_from_box(base: FlowData, float_type: FloatType, box: @RenderBox) -> BlockFlow {
BlockFlow {
base: base,
box: Some(box),
is_root: false,
float: Some(~FloatedBlockInfo::new(float_type))
}
}
@ -52,15 +94,30 @@ impl BlockFlow {
BlockFlow {
base: base,
box: None,
is_root: true
is_root: true,
float: None
}
}
pub fn new_float(base: FlowData, float_type: FloatType) -> BlockFlow {
BlockFlow {
base: base,
box: None,
is_root: false,
float: Some(~FloatedBlockInfo::new(float_type))
}
}
pub fn is_float(&self) -> bool {
self.float.is_some()
}
pub fn teardown(&mut self) {
for box in self.box.iter() {
box.teardown();
}
self.box = None;
self.float = None;
}
/// Computes left and right margins and width based on CSS 2.1 section 10.3.3.
@ -115,6 +172,63 @@ impl BlockFlow {
(width_Au, left_margin_Au, right_margin_Au)
}
fn compute_block_margins(&self, box: @RenderBox, remaining_width: Au, available_width: Au) -> (Au, Au, Au) {
let base = box.base();
let style = base.style();
let (width, maybe_margin_left, maybe_margin_right) =
(MaybeAuto::from_style(style.Box.width, remaining_width),
MaybeAuto::from_style(style.Margin.margin_left, remaining_width),
MaybeAuto::from_style(style.Margin.margin_right, remaining_width));
let (width, margin_left, margin_right) = self.compute_horiz(width,
maybe_margin_left,
maybe_margin_right,
available_width);
// If the tentative used width is greater than 'max-width', width should be recalculated,
// but this time using the computed value of 'max-width' as the computed value for 'width'.
let (width, margin_left, margin_right) = {
match specified_or_none(style.Box.max_width, remaining_width) {
Some(value) if value < width => self.compute_horiz(Specified(value),
maybe_margin_left,
maybe_margin_right,
available_width),
_ => (width, margin_left, margin_right)
}
};
// If the resulting width is smaller than 'min-width', width should be recalculated,
// but this time using the value of 'min-width' as the computed value for 'width'.
let (width, margin_left, margin_right) = {
let computed_min_width = specified(style.Box.min_width, remaining_width);
if computed_min_width > width {
self.compute_horiz(Specified(computed_min_width),
maybe_margin_left,
maybe_margin_right,
available_width)
} else {
(width, margin_left, margin_right)
}
};
return (width, margin_left, margin_right);
}
fn compute_float_margins(&self, box: @RenderBox, remaining_width: Au) -> (Au, Au, Au) {
let style = box.base().style();
let margin_left = MaybeAuto::from_style(style.Margin.margin_left,
remaining_width).specified_or_zero();
let margin_right = MaybeAuto::from_style(style.Margin.margin_right,
remaining_width).specified_or_zero();
let shrink_to_fit = geometry::min(self.base.pref_width,
geometry::max(self.base.min_width, remaining_width));
let width = MaybeAuto::from_style(style.Box.width,
remaining_width).specified_or_default(shrink_to_fit);
debug!("assign_widths_float -- width: {}", width);
return (width, margin_left, margin_right);
}
// inline(always) because this is only ever called by in-order or non-in-order top-level
// methods
#[inline(always)]
@ -252,12 +366,104 @@ impl BlockFlow {
}
}
fn assign_height_float_inorder(&mut self) {
// assign_height_float was already called by the traversal function
// so this is well-defined
let mut height = Au(0);
let mut clearance = Au(0);
let mut full_noncontent_width = Au(0);
let mut margin_height = Au(0);
for box in self.box.iter() {
let base = box.base();
height = base.position.borrow().ptr.size.height;
clearance = match base.clear() {
None => Au(0),
Some(clear) => self.base.floats_in.clearance(clear),
};
let noncontent_width = base.padding.left + base.padding.right + base.border.left +
base.border.right;
full_noncontent_width = noncontent_width + base.margin.left + base.margin.right;
margin_height = base.margin.top + base.margin.bottom;
}
let info = PlacementInfo {
width: self.base.position.size.width + full_noncontent_width,
height: height + margin_height,
ceiling: clearance,
max_width: self.float.get_ref().containing_width,
f_type: self.float.get_ref().float_type,
};
// Place the float and return the FloatContext back to the parent flow.
// After, grab the position and use that to set our position.
self.base.floats_out = self.base.floats_in.add_float(&info);
self.float.get_mut_ref().rel_pos = self.base.floats_out.last_float_pos();
}
fn assign_height_float(&mut self, ctx: &mut LayoutContext) {
// Now that we've determined our height, propagate that out.
let has_inorder_children = self.base.num_floats > 0;
if has_inorder_children {
let mut float_ctx = FloatContext::new(self.float.get_ref().floated_children);
for kid in self.base.child_iter() {
flow::mut_base(*kid).floats_in = float_ctx.clone();
kid.assign_height_inorder(ctx);
float_ctx = flow::mut_base(*kid).floats_out.clone();
}
}
let mut cur_y = Au(0);
let mut top_offset = Au(0);
for &box in self.box.iter() {
let base = box.base();
top_offset = base.margin.top + base.border.top + base.padding.top;
cur_y = cur_y + top_offset;
}
for kid in self.base.child_iter() {
let child_base = flow::mut_base(*kid);
child_base.position.origin.y = cur_y;
cur_y = cur_y + child_base.position.size.height;
}
let mut height = cur_y - top_offset;
let mut noncontent_height;
let box = self.box.as_ref().unwrap();
let base = box.base();
let mut position_ref = base.position.mutate();
let position = &mut position_ref.ptr;
// The associated box is the border box of this flow.
position.origin.y = base.margin.top;
noncontent_height = base.padding.top + base.padding.bottom + base.border.top +
base.border.bottom;
//TODO(eatkinson): compute heights properly using the 'height' property.
let height_prop = MaybeAuto::from_style(base.style().Box.height,
Au::new(0)).specified_or_zero();
height = geometry::max(height, height_prop) + noncontent_height;
debug!("assign_height_float -- height: {}", height);
position.size.height = height;
}
pub fn build_display_list_block<E:ExtraDisplayListData>(
&mut self,
builder: &DisplayListBuilder,
dirty: &Rect<Au>,
list: &Cell<DisplayList<E>>)
-> bool {
if self.is_float() {
return self.build_display_list_float(builder, dirty, list);
}
if self.base.node.is_iframe_element() {
let x = self.base.abs_position.x + do self.box.map_default(Au::new(0)) |box| {
let base = box.base();
@ -302,6 +508,39 @@ impl BlockFlow {
false
}
pub fn build_display_list_float<E:ExtraDisplayListData>(&mut self,
builder: &DisplayListBuilder,
dirty: &Rect<Au>,
list: &Cell<DisplayList<E>>)
-> bool {
//TODO: implement iframe size messaging
if self.base.node.is_iframe_element() {
error!("float iframe size messaging not implemented yet");
}
let abs_rect = Rect(self.base.abs_position, self.base.position.size);
if !abs_rect.intersects(dirty) {
return true;
}
let offset = self.base.abs_position + self.float.get_ref().rel_pos;
// add box that starts block context
for box in self.box.iter() {
box.build_display_list(builder, dirty, &offset, list)
}
// TODO: handle any out-of-flow elements
// go deeper into the flow tree
for child in self.base.child_iter() {
let child_base = flow::mut_base(*child);
child_base.abs_position = offset + child_base.position.origin;
}
false
}
}
impl Flow for BlockFlow {
@ -334,10 +573,16 @@ impl Flow for BlockFlow {
let child_base = flow::mut_base(*child_ctx);
min_width = geometry::max(min_width, child_base.min_width);
pref_width = geometry::max(pref_width, child_base.pref_width);
num_floats = num_floats + child_base.num_floats;
}
if self.is_float() {
self.base.num_floats = 1;
self.float.get_mut_ref().floated_children = num_floats;
} else {
self.base.num_floats = num_floats;
}
/* if not an anonymous block context, add in block box's widths.
these widths will not include child elements, just padding etc. */
for box in self.box.iter() {
@ -355,7 +600,6 @@ impl Flow for BlockFlow {
self.base.min_width = min_width;
self.base.pref_width = pref_width;
self.base.num_floats = num_floats;
}
/// Recursively (top-down) determines the actual width of child contexts and boxes. When called
@ -364,7 +608,12 @@ impl Flow for BlockFlow {
/// Dual boxes consume some width first, and the remainder is assigned to all child (block)
/// contexts.
fn assign_widths(&mut self, ctx: &mut LayoutContext) {
if self.is_float() {
debug!("assign_widths_float: assigning width for flow {}", self.base.id);
} else {
debug!("assign_widths_block: assigning width for flow {}", self.base.id);
}
if self.is_root {
debug!("Setting root position");
self.base.position.origin = Au::zero_point();
@ -377,12 +626,19 @@ impl Flow for BlockFlow {
let mut remaining_width = self.base.position.size.width;
let mut x_offset = Au::new(0);
if self.is_float() {
// Parent usually sets this, but floats are never inorder
self.base.is_inorder = false;
}
for &box in self.box.iter() {
let base = box.mut_base();
let base = box.base();
let mut_base = box.mut_base();
let style = base.style();
let mut_position = &mut base.position.mutate().ptr;
// Can compute padding here since we know containing block width.
base.compute_padding(style, remaining_width);
mut_base.compute_padding(style, remaining_width);
// Margins are 0 right now so base.noncontent_width() is just borders + padding.
let available_width = remaining_width - base.noncontent_width();
@ -393,58 +649,38 @@ impl Flow for BlockFlow {
let margin_bottom = MaybeAuto::from_style(style.Margin.margin_bottom,
remaining_width).specified_or_zero();
let (width, maybe_margin_left, maybe_margin_right) =
(MaybeAuto::from_style(style.Box.width, remaining_width),
MaybeAuto::from_style(style.Margin.margin_left, remaining_width),
MaybeAuto::from_style(style.Margin.margin_right, remaining_width));
let (width, margin_left, margin_right) = self.compute_horiz(width,
maybe_margin_left,
maybe_margin_right,
available_width);
// If the tentative used width is greater than 'max-width', width should be recalculated,
// but this time using the computed value of 'max-width' as the computed value for 'width'.
let (width, margin_left, margin_right) = {
match specified_or_none(style.Box.max_width, remaining_width) {
Some(value) if value < width => self.compute_horiz(Specified(value),
maybe_margin_left,
maybe_margin_right,
available_width),
_ => (width, margin_left, margin_right)
}
};
// If the resulting width is smaller than 'min-width', width should be recalculated,
// but this time using the value of 'min-width' as the computed value for 'width'.
let (width, margin_left, margin_right) = {
let computed_min_width = specified(style.Box.min_width, remaining_width);
if computed_min_width > width {
self.compute_horiz(Specified(computed_min_width),
maybe_margin_left,
maybe_margin_right,
available_width)
let (width, margin_left, margin_right) = if self.is_float() {
self.compute_float_margins(box, remaining_width)
} else {
(width, margin_left, margin_right)
}
self.compute_block_margins(box, remaining_width, available_width)
};
base.margin.top = margin_top;
base.margin.right = margin_right;
base.margin.bottom = margin_bottom;
base.margin.left = margin_left;
mut_base.margin.top = margin_top;
mut_base.margin.right = margin_right;
mut_base.margin.bottom = margin_bottom;
mut_base.margin.left = margin_left;
x_offset = base.offset();
remaining_width = width;
//The associated box is the border box of this flow
let position_ref = base.position.mutate();
position_ref.ptr.origin.x = base.margin.left;
mut_position.origin.x = base.margin.left;
let padding_and_borders = base.padding.left + base.padding.right +
base.border.left + base.border.right;
position_ref.ptr.size.width = remaining_width + padding_and_borders;
mut_position.size.width = remaining_width + padding_and_borders;
}
let has_inorder_children = self.base.is_inorder || self.base.num_floats > 0;
if self.is_float() {
self.base.position.size.width = remaining_width;
}
let has_inorder_children = if self.is_float() {
self.base.num_floats > 0
} else {
self.base.is_inorder || self.base.num_floats > 0
};
for kid in self.base.child_iter() {
assert!(kid.starts_block_flow() || kid.starts_inline_flow());
@ -460,11 +696,20 @@ impl Flow for BlockFlow {
}
fn assign_height_inorder(&mut self, ctx: &mut LayoutContext) {
if self.is_float() {
debug!("assign_height_inorder_float: assigning height for float {}", self.base.id);
self.assign_height_float_inorder();
} else {
debug!("assign_height_inorder: assigning height for block {}", self.base.id);
self.assign_height_block_base(ctx, true);
}
}
fn assign_height(&mut self, ctx: &mut LayoutContext) {
if self.is_float() {
debug!("assign_height_float: assigning height for float {}", self.base.id);
self.assign_height_float(ctx);
} else {
debug!("assign_height: assigning height for block {}", self.base.id);
// This is the only case in which a block flow can start an inorder
// subtraversal.
@ -474,6 +719,7 @@ impl Flow for BlockFlow {
}
self.assign_height_block_base(ctx, false);
}
}
fn collapse_margins(&mut self,
top_margin_collapsible: bool,
@ -482,6 +728,12 @@ impl Flow for BlockFlow {
top_offset: &mut Au,
collapsing: &mut Au,
collapsible: &mut Au) {
if self.is_float() {
// Margins between a floated box and any other box do not collapse.
*collapsing = Au::new(0);
return;
}
for &box in self.box.iter() {
let base = box.base();
@ -515,7 +767,7 @@ impl Flow for BlockFlow {
if self.is_root {
~"BlockFlow(root)"
} else {
let txt = ~"BlockFlow: ";
let txt = if self.is_float() { ~"FloatFlow: " } else { ~"BlockFlow: " };
txt.append(match self.box {
Some(rb) => {
rb.debug_str()

View file

@ -25,7 +25,6 @@ use layout::block::BlockFlow;
use layout::box::{GenericRenderBox, ImageRenderBox, RenderBox, RenderBoxBase};
use layout::box::{UnscannedTextRenderBox};
use layout::context::LayoutContext;
use layout::float::FloatFlow;
use layout::float_context::FloatType;
use layout::flow::{Flow, FlowData, MutableFlowUtils};
use layout::inline::InlineFlow;
@ -360,13 +359,13 @@ impl<'self> FlowConstructor<'self> {
flow
}
/// Builds the flow for a node with `float: {left|right}`. This yields a `FloatFlow` with a
/// `BlockFlow` underneath it.
/// Builds the flow for a node with `float: {left|right}`. This yields a float `BlockFlow` with
/// a `BlockFlow` underneath it.
fn build_flow_for_floated_block(&self, node: AbstractNode<LayoutView>, float_type: FloatType)
-> ~Flow: {
let base = FlowData::new(self.next_flow_id(), node);
let box = self.build_box_for_node(node);
let mut flow = ~FloatFlow::from_box(base, float_type, box) as ~Flow:;
let mut flow = ~BlockFlow::float_from_box(base, float_type, box) as ~Flow:;
self.build_children_of_block_flow(&mut flow, node);
flow
}

View file

@ -1,333 +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 layout::box::{RenderBox, RenderBoxUtils};
use layout::context::LayoutContext;
use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData};
use layout::flow::{FloatFlowClass, FlowClass, Flow, FlowData};
use layout::flow;
use layout::model::{MaybeAuto};
use layout::float_context::{FloatContext, PlacementInfo, FloatType};
use std::cell::Cell;
use geom::point::Point2D;
use geom::rect::Rect;
use gfx::display_list::DisplayList;
use servo_util::geometry::Au;
use servo_util::geometry;
pub struct FloatFlow {
/// Data common to all flows.
base: FlowData,
/// The associated render box.
box: Option<@RenderBox>,
containing_width: Au,
/// Offset relative to where the parent tried to position this flow
rel_pos: Point2D<Au>,
/// Left or right?
float_type: FloatType,
/// Index into the box list for inline floats
index: Option<uint>,
/// Number of floated children
floated_children: uint,
}
impl FloatFlow {
pub fn new(base: FlowData, float_type: FloatType) -> FloatFlow {
FloatFlow {
base: base,
containing_width: Au(0),
box: None,
index: None,
float_type: float_type,
rel_pos: Point2D(Au(0), Au(0)),
floated_children: 0,
}
}
pub fn from_box(base: FlowData, float_type: FloatType, box: @RenderBox) -> FloatFlow {
FloatFlow {
base: base,
containing_width: Au(0),
box: Some(box),
index: None,
float_type: float_type,
rel_pos: Point2D(Au(0), Au(0)),
floated_children: 0,
}
}
pub fn teardown(&mut self) {
for box in self.box.iter() {
box.teardown();
}
self.box = None;
self.index = None;
}
pub fn build_display_list_float<E:ExtraDisplayListData>(&mut self,
builder: &DisplayListBuilder,
dirty: &Rect<Au>,
list: &Cell<DisplayList<E>>)
-> bool {
//TODO: implement iframe size messaging
if self.base.node.is_iframe_element() {
error!("float iframe size messaging not implemented yet");
}
let abs_rect = Rect(self.base.abs_position, self.base.position.size);
if !abs_rect.intersects(dirty) {
return true;
}
let offset = self.base.abs_position + self.rel_pos;
// add box that starts block context
for box in self.box.iter() {
box.build_display_list(builder, dirty, &offset, list)
}
// TODO: handle any out-of-flow elements
// go deeper into the flow tree
for child in self.base.child_iter() {
let child_base = flow::mut_base(*child);
child_base.abs_position = offset + child_base.position.origin;
}
false
}
fn debug_str(&self) -> ~str {
~"FloatFlow"
}
}
impl Flow for FloatFlow {
fn class(&self) -> FlowClass {
FloatFlowClass
}
fn as_float<'a>(&'a mut self) -> &'a mut FloatFlow {
self
}
fn bubble_widths(&mut self, _: &mut LayoutContext) {
let mut min_width = Au(0);
let mut pref_width = Au(0);
let mut num_floats = 0;
for child_ctx in self.base.child_iter() {
//assert!(child_ctx.starts_block_flow() || child_ctx.starts_inline_flow());
let child_base = flow::mut_base(*child_ctx);
min_width = geometry::max(min_width, child_base.min_width);
pref_width = geometry::max(pref_width, child_base.pref_width);
num_floats = num_floats + child_base.num_floats;
}
self.base.num_floats = 1;
self.floated_children = num_floats;
for box in self.box.iter() {
{
box.mut_base().compute_borders(box.base().style());
}
let (this_minimum_width, this_preferred_width) = box.minimum_and_preferred_widths();
min_width = min_width + this_minimum_width;
pref_width = pref_width + this_preferred_width;
}
self.base.min_width = min_width;
self.base.pref_width = pref_width;
}
fn assign_widths(&mut self, _: &mut LayoutContext) {
debug!("assign_widths_float: assigning width for flow {}", self.base.id);
// position.size.width is set by parent even though we don't know
// position.origin yet.
let mut remaining_width = self.base.position.size.width;
self.containing_width = remaining_width;
let mut x_offset = Au(0);
// Parent usually sets this, but floats are never inorder
self.base.is_inorder = false;
for &box in self.box.iter() {
let base = box.base();
let mut_base = box.mut_base();
let style = base.style();
let mut position_ref = base.position.mutate();
let position = &mut position_ref.ptr;
// Can compute padding here since we know containing block width.
mut_base.compute_padding(style, remaining_width);
// Margins for floats are 0 if auto.
let margin_top = MaybeAuto::from_style(style.Margin.margin_top,
remaining_width).specified_or_zero();
let margin_bottom = MaybeAuto::from_style(style.Margin.margin_bottom,
remaining_width).specified_or_zero();
let margin_left = MaybeAuto::from_style(style.Margin.margin_left,
remaining_width).specified_or_zero();
let margin_right = MaybeAuto::from_style(style.Margin.margin_right,
remaining_width).specified_or_zero();
let shrink_to_fit = geometry::min(self.base.pref_width,
geometry::max(self.base.min_width, remaining_width));
let width = MaybeAuto::from_style(style.Box.width,
remaining_width).specified_or_default(shrink_to_fit);
debug!("assign_widths_float -- width: {}", width);
mut_base.margin.top = margin_top;
mut_base.margin.right = margin_right;
mut_base.margin.bottom = margin_bottom;
mut_base.margin.left = margin_left;
x_offset = base.offset();
remaining_width = width;
// The associated box is the border box of this flow.
position.origin.x = base.margin.left;
let padding_and_borders = base.padding.left + base.padding.right +
base.border.left + base.border.right;
position.size.width = remaining_width + padding_and_borders;
}
self.base.position.size.width = remaining_width;
let has_inorder_children = self.base.num_floats > 0;
for kid in self.base.child_iter() {
//assert!(kid.starts_block_flow() || kid.starts_inline_flow());
let child_base = flow::mut_base(*kid);
child_base.position.origin.x = x_offset;
child_base.position.size.width = remaining_width;
child_base.is_inorder = has_inorder_children;
if !child_base.is_inorder {
child_base.floats_in = FloatContext::new(0);
}
}
}
fn assign_height_inorder(&mut self, _: &mut LayoutContext) {
debug!("assign_height_inorder_float: assigning height for float {}", self.base.id);
// assign_height_float was already called by the traversal function
// so this is well-defined
let mut height = Au(0);
let mut clearance = Au(0);
let mut full_noncontent_width = Au(0);
let mut margin_height = Au(0);
for box in self.box.iter() {
let base = box.base();
height = base.position.borrow().ptr.size.height;
clearance = match base.clear() {
None => Au(0),
Some(clear) => self.base.floats_in.clearance(clear),
};
let noncontent_width = base.padding.left + base.padding.right + base.border.left +
base.border.right;
full_noncontent_width = noncontent_width + base.margin.left + base.margin.right;
margin_height = base.margin.top + base.margin.bottom;
}
let info = PlacementInfo {
width: self.base.position.size.width + full_noncontent_width,
height: height + margin_height,
ceiling: clearance,
max_width: self.containing_width,
f_type: self.float_type,
};
// Place the float and return the FloatContext back to the parent flow.
// After, grab the position and use that to set our position.
self.base.floats_out = self.base.floats_in.add_float(&info);
self.rel_pos = self.base.floats_out.last_float_pos();
}
fn assign_height(&mut self, ctx: &mut LayoutContext) {
// Now that we've determined our height, propagate that out.
let has_inorder_children = self.base.num_floats > 0;
if has_inorder_children {
let mut float_ctx = FloatContext::new(self.floated_children);
for kid in self.base.child_iter() {
flow::mut_base(*kid).floats_in = float_ctx.clone();
kid.assign_height_inorder(ctx);
float_ctx = flow::mut_base(*kid).floats_out.clone();
}
}
debug!("assign_height_float: assigning height for float {}", self.base.id);
let mut cur_y = Au(0);
let mut top_offset = Au(0);
for &box in self.box.iter() {
let base = box.base();
top_offset = base.margin.top + base.border.top + base.padding.top;
cur_y = cur_y + top_offset;
}
for kid in self.base.child_iter() {
let child_base = flow::mut_base(*kid);
child_base.position.origin.y = cur_y;
cur_y = cur_y + child_base.position.size.height;
}
let mut height = cur_y - top_offset;
let mut noncontent_height;
let box = self.box.as_ref().unwrap();
let base = box.base();
let mut position_ref = base.position.mutate();
let position = &mut position_ref.ptr;
// The associated box is the border box of this flow.
position.origin.y = base.margin.top;
noncontent_height = base.padding.top + base.padding.bottom + base.border.top +
base.border.bottom;
//TODO(eatkinson): compute heights properly using the 'height' property.
let height_prop = MaybeAuto::from_style(base.style().Box.height,
Au::new(0)).specified_or_zero();
height = geometry::max(height, height_prop) + noncontent_height;
debug!("assign_height_float -- height: {}", height);
position.size.height = height;
}
fn collapse_margins(&mut self,
_: bool,
_: &mut bool,
_: &mut Au,
_: &mut Au,
collapsing: &mut Au,
_: &mut Au) {
// Margins between a floated box and any other box do not collapse.
*collapsing = Au::new(0);
}
fn debug_str(&self) -> ~str {
~"FloatFlow"
}
}

View file

@ -29,7 +29,6 @@ use css::node_style::StyledNode;
use layout::block::BlockFlow;
use layout::box::RenderBox;
use layout::context::LayoutContext;
use layout::float::FloatFlow;
use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData};
use layout::float_context::{FloatContext, Invalid};
use layout::incremental::RestyleDamage;
@ -74,11 +73,6 @@ pub trait Flow {
fail!("called as_inline() on a non-inline flow")
}
/// If this is a float flow, returns the underlying object. Fails otherwise.
fn as_float<'a>(&'a mut self) -> &'a mut FloatFlow {
fail!("called as_float() on a non-float flow")
}
// Main methods
/// Pass 1 of reflow: computes minimum and preferred widths.
@ -217,7 +211,6 @@ pub trait MutableFlowUtils {
pub enum FlowClass {
AbsoluteFlowClass,
BlockFlowClass,
FloatFlowClass,
InlineBlockFlowClass,
InlineFlowClass,
TableFlowClass,
@ -395,7 +388,7 @@ impl<'self> ImmutableFlowUtils for &'self Flow {
/// Returns true if this flow is a block or a float flow.
fn is_block_like(self) -> bool {
match self.class() {
BlockFlowClass | FloatFlowClass => true,
BlockFlowClass => true,
AbsoluteFlowClass | InlineBlockFlowClass | InlineFlowClass | TableFlowClass => false,
}
}
@ -408,7 +401,7 @@ impl<'self> ImmutableFlowUtils for &'self Flow {
/// Returns true if this flow is a block flow, an inline-block flow, or a float flow.
fn starts_block_flow(self) -> bool {
match self.class() {
BlockFlowClass | InlineBlockFlowClass | FloatFlowClass => true,
BlockFlowClass | InlineBlockFlowClass => true,
AbsoluteFlowClass | InlineFlowClass | TableFlowClass => false,
}
}
@ -417,7 +410,7 @@ impl<'self> ImmutableFlowUtils for &'self Flow {
fn starts_inline_flow(self) -> bool {
match self.class() {
InlineFlowClass => true,
AbsoluteFlowClass | BlockFlowClass | FloatFlowClass | InlineBlockFlowClass |
AbsoluteFlowClass | BlockFlowClass | InlineBlockFlowClass |
TableFlowClass => false,
}
}
@ -525,7 +518,6 @@ impl<'self> MutableFlowUtils for &'self mut Flow {
match self.class() {
BlockFlowClass => self.as_block().build_display_list_block(builder, dirty, list),
InlineFlowClass => self.as_inline().build_display_list_inline(builder, dirty, list),
FloatFlowClass => self.as_float().build_display_list_float(builder, dirty, list),
_ => fail!("Tried to build_display_list_recurse of flow: {:?}", self),
};

View file

@ -81,7 +81,6 @@ pub mod layout {
pub mod context;
pub mod display_list_builder;
pub mod float_context;
pub mod float;
pub mod flow;
pub mod layout_task;
pub mod inline;