aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/components/main/layout/block.rs74
-rw-r--r--src/components/main/layout/box.rs2
-rw-r--r--src/components/main/layout/float.rs100
-rw-r--r--src/components/main/layout/flow.rs56
-rw-r--r--src/components/main/layout/inline.rs40
-rw-r--r--src/components/main/layout/layout_task.rs16
6 files changed, 198 insertions, 90 deletions
diff --git a/src/components/main/layout/block.rs b/src/components/main/layout/block.rs
index d5a98390eda..62110c27a5e 100644
--- a/src/components/main/layout/block.rs
+++ b/src/components/main/layout/block.rs
@@ -10,7 +10,7 @@ use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData};
use layout::flow::{BlockFlow, FlowContext, FlowData, InlineBlockFlow, FloatFlow};
use layout::inline::InlineLayout;
use layout::model::{MaybeAuto, Specified, Auto};
-use layout::float_context::FloatContext;
+use layout::float_context::{FloatContext, Invalid};
use newcss::values::{CSSClearNone, CSSClearLeft, CSSClearRight, CSSClearBoth};
use layout::float_context::{ClearLeft, ClearRight, ClearBoth};
@@ -187,6 +187,7 @@ impl BlockFlowData {
self.common.position.origin = Au::zero_point();
self.common.position.size.width = ctx.screen_size.size.width;
self.common.floats_in = FloatContext::new(self.common.num_floats);
+ self.common.is_inorder = false;
}
//position was set to the containing block by the flow's parent
@@ -239,22 +240,45 @@ impl BlockFlowData {
}
}
+ let has_inorder_children = self.common.is_inorder || self.common.num_floats > 0;
for BlockFlow(self).each_child |kid| {
assert!(kid.starts_block_flow() || kid.starts_inline_flow());
do kid.with_mut_base |child_node| {
child_node.position.origin.x = x_offset;
child_node.position.size.width = remaining_width;
+ child_node.is_inorder = has_inorder_children;
+
+ if !child_node.is_inorder {
+ child_node.floats_in = FloatContext::new(0);
+ }
}
}
}
+ pub fn assign_height_inorder_block(@mut self, ctx: &mut LayoutContext) {
+ debug!("assign_height_inorder_block: assigning height for block %?", self.common.id);
+ self.assign_height_block_base(ctx, true);
+ }
+
pub fn assign_height_block(@mut self, ctx: &mut LayoutContext) {
+ debug!("assign_height_block: assigning height for block %?", self.common.id);
+ // This is the only case in which a block flow can start an inorder
+ // subtraversal.
+ if self.is_root && self.common.num_floats > 0 {
+ self.assign_height_inorder_block(ctx);
+ return;
+ }
+ self.assign_height_block_base(ctx, false);
+ }
+
+ fn assign_height_block_base(@mut self, ctx: &mut LayoutContext, inorder: bool) {
let mut cur_y = Au(0);
let mut clearance = Au(0);
let mut top_offset = Au(0);
let mut bottom_offset = Au(0);
let mut left_offset = Au(0);
+ let mut float_ctx = Invalid;
for self.box.iter().advance |&box| {
let style = box.style();
@@ -279,27 +303,25 @@ impl BlockFlowData {
};
}
- // TODO(eatkinson): the translation here is probably
- // totally wrong. We need to do it right or pages
- // with floats will look very strange.
-
- // Floats for blocks work like this:
- // self.floats_in -> child[0].floats_in
- // visit child[0]
- // child[i-1].floats_out -> child[i].floats_in
- // visit child[i]
- // repeat until all children are visited.
- // last_child.floats_out -> self.floats_out (done at the end of this method)
- let mut float_ctx = self.common.floats_in.translate(Point2D(-left_offset, -top_offset));
- for BlockFlow(self).each_child |kid| {
- do kid.with_mut_base |child_node| {
- child_node.floats_in = float_ctx.clone();
- }
- kid.assign_height(ctx);
- do kid.with_mut_base |child_node| {
- float_ctx = child_node.floats_out.clone();
- }
+ if inorder {
+ // Floats for blocks work like this:
+ // self.floats_in -> child[0].floats_in
+ // visit child[0]
+ // child[i-1].floats_out -> child[i].floats_in
+ // visit child[i]
+ // repeat until all children are visited.
+ // last_child.floats_out -> self.floats_out (done at the end of this method)
+ float_ctx = self.common.floats_in.translate(Point2D(-left_offset, -top_offset));
+ for BlockFlow(self).each_child |kid| {
+ do kid.with_mut_base |child_node| {
+ child_node.floats_in = float_ctx.clone();
+ }
+ kid.assign_height_inorder(ctx);
+ do kid.with_mut_base |child_node| {
+ float_ctx = child_node.floats_out.clone();
+ }
+ }
}
for BlockFlow(self).each_child |kid| {
do kid.with_mut_base |child_node| {
@@ -311,7 +333,7 @@ impl BlockFlowData {
let mut height = if self.is_root {
Au::max(ctx.screen_size.size.height, cur_y)
} else {
- cur_y - top_offset
+ cur_y - top_offset
};
for self.box.iter().advance |&box| {
@@ -338,8 +360,12 @@ impl BlockFlowData {
//TODO(eatkinson): compute heights using the 'height' property.
self.common.position.size.height = height + noncontent_height;
- let extra_height = height - (cur_y - top_offset) + bottom_offset;
- self.common.floats_out = float_ctx.translate(Point2D(left_offset, -extra_height));
+ if inorder {
+ let extra_height = height - (cur_y - top_offset) + bottom_offset;
+ self.common.floats_out = float_ctx.translate(Point2D(left_offset, -extra_height));
+ } else {
+ self.common.floats_out = self.common.floats_in.clone();
+ }
}
pub fn build_display_list_block<E:ExtraDisplayListData>(@mut self,
diff --git a/src/components/main/layout/box.rs b/src/components/main/layout/box.rs
index 72271e0cd39..ca82a925845 100644
--- a/src/components/main/layout/box.rs
+++ b/src/components/main/layout/box.rs
@@ -271,7 +271,7 @@ impl RenderBox {
/// Attempts to split this box so that its width is no more than `max_width`. Fails if this box
/// is an unscanned text box.
- pub fn split_to_width(&self, _: &LayoutContext, max_width: Au, starts_line: bool)
+ pub fn split_to_width(&self, max_width: Au, starts_line: bool)
-> SplitBoxResult {
match *self {
GenericRenderBoxClass(*) | ImageRenderBoxClass(*) => CannotSplit(*self),
diff --git a/src/components/main/layout/float.rs b/src/components/main/layout/float.rs
index f8024464fd6..84f09723ebd 100644
--- a/src/components/main/layout/float.rs
+++ b/src/components/main/layout/float.rs
@@ -35,6 +35,9 @@ pub struct FloatFlowData {
/// Index into the box list for inline floats
index: Option<uint>,
+ /// Number of floated children
+ floated_children: uint,
+
}
impl FloatFlowData {
@@ -46,6 +49,7 @@ impl FloatFlowData {
index: None,
float_type: float_type,
rel_pos: Point2D(Au(0), Au(0)),
+ floated_children: 0,
}
}
@@ -63,7 +67,7 @@ impl FloatFlowData {
pub fn bubble_widths_float(@mut self, ctx: &LayoutContext) {
let mut min_width = Au(0);
let mut pref_width = Au(0);
- let mut num_floats = 1;
+ let mut num_floats = 0;
for FloatFlow(self).each_child |child_ctx| {
//assert!(child_ctx.starts_block_flow() || child_ctx.starts_inline_flow());
@@ -71,12 +75,12 @@ impl FloatFlowData {
do child_ctx.with_mut_base |child_node| {
min_width = geometry::max(min_width, child_node.min_width);
pref_width = geometry::max(pref_width, child_node.pref_width);
-
num_floats = num_floats + child_node.num_floats;
}
}
- self.common.num_floats = num_floats;
+ self.common.num_floats = 1;
+ self.floated_children = num_floats;
self.box.map(|&box| {
@@ -93,13 +97,16 @@ impl FloatFlowData {
self.common.pref_width = pref_width;
}
- pub fn assign_widths_float(@mut self, _: &LayoutContext) {
+ pub fn assign_widths_float(@mut self) {
debug!("assign_widths_float: assigning width for flow %?", self.common.id);
// position.size.width is set by parent even though we don't know
// position.origin yet.
let mut remaining_width = self.common.position.size.width;
self.containing_width = remaining_width;
let mut x_offset = Au(0);
+
+ // Parent usually sets this, but floats are never inorder
+ self.common.is_inorder = false;
for self.box.iter().advance |&box| {
let style = box.style();
@@ -154,25 +161,77 @@ impl FloatFlowData {
self.common.position.size.width = remaining_width;
+ let has_inorder_children = self.common.num_floats > 0;
for FloatFlow(self).each_child |kid| {
//assert!(kid.starts_block_flow() || kid.starts_inline_flow());
do kid.with_mut_base |child_node| {
child_node.position.origin.x = x_offset;
child_node.position.size.width = remaining_width;
+ child_node.is_inorder = has_inorder_children;
+
+ if !child_node.is_inorder {
+ child_node.floats_in = FloatContext::new(0);
+ }
}
}
}
- pub fn assign_height_float(@mut self, ctx: &mut LayoutContext) {
- let mut float_ctx = FloatContext::new(self.common.num_floats);
- for FloatFlow(self).each_child |kid| {
- do kid.with_mut_base |child_node| {
- child_node.floats_in = float_ctx.clone();
+ pub fn assign_height_inorder_float(@mut self) {
+ debug!("assign_height_inorder_float: assigning height for float %?", self.common.id);
+ // assign_height_float was already called by the traversal function
+ // so this is well-defined
+
+ let mut height = Au(0);
+ let mut full_noncontent_width = Au(0);
+ let mut full_noncontent_height = Au(0);
+
+ self.box.map(|&box| {
+ height = do box.with_base |base| {
+ base.position.size.height
+ };
+
+ do box.with_base |base| {
+
+ let noncontent_width = base.model.padding.left + base.model.padding.right +
+ base.model.border.left + base.model.border.right;
+ let noncontent_height = base.model.padding.top + base.model.padding.bottom +
+ base.model.border.top + base.model.border.bottom;
+
+ full_noncontent_width = noncontent_width + base.model.margin.left + base.model.margin.right;
+ full_noncontent_height = noncontent_height + base.model.margin.top + base.model.margin.bottom;
+
}
- kid.assign_height(ctx);
- do kid.with_mut_base |child_node| {
- float_ctx = child_node.floats_out.clone();
+
+ });
+
+ let info = PlacementInfo {
+ width: self.common.position.size.width + full_noncontent_width,
+ height: height + full_noncontent_height,
+ ceiling: Au(0),
+ 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.common.floats_out = self.common.floats_in.add_float(&info);
+ self.rel_pos = self.common.floats_out.last_float_pos();
+ }
+
+ pub fn assign_height_float(@mut self, ctx: &mut LayoutContext) {
+ debug!("assign_height_float: assigning height for float %?", self.common.id);
+ let has_inorder_children = self.common.num_floats > 0;
+ if has_inorder_children {
+ let mut float_ctx = FloatContext::new(self.floated_children);
+ for FloatFlow(self).each_child |kid| {
+ do kid.with_mut_base |child_node| {
+ child_node.floats_in = float_ctx.clone();
+ }
+ kid.assign_height_inorder(ctx);
+ do kid.with_mut_base |child_node| {
+ float_ctx = child_node.floats_out.clone();
+ }
}
}
@@ -197,8 +256,6 @@ impl FloatFlowData {
let mut noncontent_width = Au(0);
let mut noncontent_height = Au(0);
- let mut full_noncontent_width = Au(0);
- let mut full_noncontent_height = Au(0);
self.box.map(|&box| {
do box.with_mut_base |base| {
//The associated box is the border box of this flow
@@ -210,8 +267,6 @@ impl FloatFlowData {
base.model.border.top + base.model.border.bottom;
base.position.size.height = height + noncontent_height;
- full_noncontent_width = noncontent_width + base.model.margin.left + base.model.margin.right;
- full_noncontent_height = noncontent_height + base.model.margin.top + base.model.margin.bottom;
}
});
@@ -229,19 +284,6 @@ impl FloatFlowData {
base.position.size.height = height;
}
}
-
- let info = PlacementInfo {
- width: self.common.position.size.width + full_noncontent_width,
- height: height + full_noncontent_height,
- ceiling: Au(0),
- 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.common.floats_out = self.common.floats_in.add_float(&info);
- self.rel_pos = self.common.floats_out.last_float_pos();
}
pub fn build_display_list_float<E:ExtraDisplayListData>(@mut self,
diff --git a/src/components/main/layout/flow.rs b/src/components/main/layout/flow.rs
index 6dd1654e746..2d7db5d4a3c 100644
--- a/src/components/main/layout/flow.rs
+++ b/src/components/main/layout/flow.rs
@@ -94,6 +94,21 @@ impl FlowContext {
kid.partially_traverse_preorder(|a| callback(a));
}
}
+
+ fn traverse_bu_sub_inorder (&self, callback: &fn(FlowContext) -> bool) -> bool {
+ for self.each_child |kid| {
+ // FIXME: Work around rust#2202. We should be able to pass the callback directly.
+ if !kid.traverse_bu_sub_inorder(|a| callback(a)) {
+ return false;
+ }
+ }
+
+ if !self.is_inorder() {
+ callback((*self).clone())
+ } else {
+ true
+ }
+ }
}
impl FlowData {
@@ -177,7 +192,8 @@ pub struct FlowData {
floats_in: FloatContext,
floats_out: FloatContext,
num_floats: uint,
- abs_position: Point2D<Au>
+ abs_position: Point2D<Au>,
+ is_inorder: bool,
}
impl TreeNode<FlowContext> for FlowData {
@@ -242,7 +258,8 @@ impl FlowData {
floats_in: Invalid,
floats_out: Invalid,
num_floats: 0,
- abs_position: Point2D(Au(0), Au(0))
+ abs_position: Point2D(Au(0), Au(0)),
+ is_inorder: false
}
}
}
@@ -257,6 +274,13 @@ impl<'self> FlowContext {
}
}
+ #[inline(always)]
+ pub fn is_inorder(&self) -> bool {
+ do self.with_base |common_info| {
+ common_info.is_inorder
+ }
+ }
+
/// A convenience method to return the ID of this flow. Fails if the flow is currently being
/// borrowed mutably.
#[inline(always)]
@@ -266,14 +290,6 @@ impl<'self> FlowContext {
}
}
- /// A convenience method to return the restyle damage of this flow. Fails if the flow is
- /// currently being borrowed mutably.
- #[inline(always)]
- pub fn restyle_damage(&self) -> RestyleDamage {
- do self.with_base |info| {
- info.restyle_damage
- }
- }
pub fn inline(&self) -> @mut InlineFlowData {
match *self {
@@ -309,7 +325,7 @@ impl<'self> FlowContext {
match *self {
BlockFlow(info) => info.assign_widths_block(ctx),
InlineFlow(info) => info.assign_widths_inline(ctx),
- FloatFlow(info) => info.assign_widths_float(ctx),
+ FloatFlow(info) => info.assign_widths_float(),
_ => fail!(fmt!("Tried to assign_widths of flow: f%d", self.id()))
}
}
@@ -323,6 +339,15 @@ impl<'self> FlowContext {
}
}
+ pub fn assign_height_inorder(&self, ctx: &mut LayoutContext) {
+ match *self {
+ BlockFlow(info) => info.assign_height_inorder_block(ctx),
+ InlineFlow(info) => info.assign_height_inorder_inline(ctx),
+ FloatFlow(info) => info.assign_height_inorder_float(),
+ _ => fail!(fmt!("Tried to assign_height of flow: f%d", self.id()))
+ }
+ }
+
pub fn build_display_list<E:ExtraDisplayListData>(&self,
builder: &DisplayListBuilder,
dirty: &Rect<Au>,
@@ -340,6 +365,15 @@ impl<'self> FlowContext {
}
}
+ /// A convenience method to return the restyle damage of this flow. Fails if the flow is
+ /// currently being borrowed mutably.
+ #[inline(always)]
+ pub fn restyle_damage(&self) -> RestyleDamage {
+ do self.with_base |info| {
+ info.restyle_damage
+ }
+ }
+
// Actual methods that do not require much flow-specific logic
pub fn foldl_all_boxes<B:Clone>(&self, seed: B, cb: &fn(a: B, b: RenderBox) -> B) -> B {
diff --git a/src/components/main/layout/inline.rs b/src/components/main/layout/inline.rs
index 9d8f5cfbb4f..3886695c4d3 100644
--- a/src/components/main/layout/inline.rs
+++ b/src/components/main/layout/inline.rs
@@ -105,7 +105,7 @@ impl LineboxScanner {
self.pending_line.green_zone = Size2D(Au(0), Au(0))
}
- pub fn scan_for_lines(&mut self, ctx: &LayoutContext) {
+ pub fn scan_for_lines(&mut self) {
self.reset_scanner();
{ // FIXME: manually control borrow length
@@ -127,7 +127,7 @@ impl LineboxScanner {
box
};
- let box_was_appended = self.try_append_to_line(ctx, cur_box);
+ let box_was_appended = self.try_append_to_line(cur_box);
if !box_was_appended {
debug!("LineboxScanner: Box wasn't appended, because line %u was full.",
self.lines.len());
@@ -222,7 +222,7 @@ impl LineboxScanner {
/// Computes the position of a line that has only the provided RenderBox.
/// Returns: the bounding rect of the line's green zone (whose origin coincides
/// with the line's origin) and the actual width of the first box after splitting.
- fn initial_line_placement (&self, ctx: &LayoutContext, first_box: RenderBox, ceiling: Au) -> (Rect<Au>, Au) {
+ fn initial_line_placement (&self, first_box: RenderBox, ceiling: Au) -> (Rect<Au>, Au) {
debug!("LineboxScanner: Trying to place first box of line %?", self.lines.len());
debug!("LineboxScanner: box size: %?", first_box.position().size);
let splitable = first_box.can_split();
@@ -266,7 +266,7 @@ impl LineboxScanner {
// FIXME(eatkinson): calling split_to_width here seems excessive and expensive.
// We should find a better abstraction or merge it with the call in
// try_append_to_line.
- match first_box.split_to_width(ctx, line_bounds.size.width, line_is_empty) {
+ match first_box.split_to_width(line_bounds.size.width, line_is_empty) {
CannotSplit(_) => {
error!("LineboxScanner: Tried to split unsplittable render box! %s",
first_box.debug_str());
@@ -279,7 +279,7 @@ impl LineboxScanner {
(Some(l_box), Some(_)) => l_box.position().size.width,
(Some(l_box), None) => l_box.position().size.width,
(None, Some(r_box)) => r_box.position().size.width,
- (None, None) => fail!("This cas makes no sense.")
+ (None, None) => fail!("This case makes no sense.")
};
return (line_bounds, actual_box_width);
}
@@ -293,7 +293,7 @@ impl LineboxScanner {
(Some(l_box), Some(_)) => l_box.position().size.width,
(Some(l_box), None) => l_box.position().size.width,
(None, Some(r_box)) => r_box.position().size.width,
- (None, None) => fail!("This cas makes no sense.")
+ (None, None) => fail!("This case makes no sense.")
};
info.width = actual_box_width;
@@ -307,11 +307,11 @@ impl LineboxScanner {
}
/// Returns false only if we should break the line.
- fn try_append_to_line(&mut self, ctx: &LayoutContext, in_box: RenderBox) -> bool {
+ fn try_append_to_line(&mut self, in_box: RenderBox) -> bool {
let line_is_empty: bool = self.pending_line.range.length() == 0;
if line_is_empty {
- let (line_bounds, _) = self.initial_line_placement(ctx, in_box, self.cur_y);
+ let (line_bounds, _) = self.initial_line_placement(in_box, self.cur_y);
self.pending_line.bounds.origin = line_bounds.origin;
self.pending_line.green_zone = line_bounds.size;
}
@@ -348,7 +348,7 @@ impl LineboxScanner {
// First predict where the next line is going to be
let this_line_y = self.pending_line.bounds.origin.y;
- let (next_line, first_box_width) = self.initial_line_placement(ctx, in_box, this_line_y);
+ let (next_line, first_box_width) = self.initial_line_placement(in_box, this_line_y);
let next_green_zone = next_line.size;
let new_width = self.pending_line.bounds.size.width + first_box_width;
@@ -396,7 +396,7 @@ impl LineboxScanner {
} else {
let available_width = green_zone.width - self.pending_line.bounds.size.width;
- match in_box.split_to_width(ctx, available_width, line_is_empty) {
+ match in_box.split_to_width(available_width, line_is_empty) {
CannotSplit(_) => {
error!("LineboxScanner: Tried to split unsplittable render box! %s",
in_box.debug_str());
@@ -542,7 +542,7 @@ impl InlineFlowData {
/// Recursively (top-down) determines the actual width of child contexts and boxes. When called
/// on this context, the context has had its width set by the parent context.
- pub fn assign_widths_inline(@mut self, _: &mut LayoutContext) {
+ pub fn assign_widths_inline(@mut self, _: &LayoutContext) {
// Initialize content box widths if they haven't been initialized already.
//
// TODO: Combine this with `LineboxScanner`'s walk in the box list, or put this into
@@ -574,6 +574,7 @@ impl InlineFlowData {
for InlineFlow(self).each_child |kid| {
do kid.with_mut_base |base| {
base.position.size.width = self.common.position.size.width;
+ base.is_inorder = self.common.is_inorder;
}
}
// There are no child contexts, so stop here.
@@ -585,11 +586,16 @@ impl InlineFlowData {
// 'inline-block' box that created this flow before recursing.
}
- pub fn assign_height_inline(@mut self, ctx: &mut LayoutContext) {
-
+ pub fn assign_height_inorder_inline(@mut self, ctx: &mut LayoutContext) {
for InlineFlow(self).each_child |kid| {
- kid.assign_height(ctx);
+ kid.assign_height_inorder(ctx);
}
+ self.assign_height_inline(ctx);
+ }
+
+ pub fn assign_height_inline(@mut self, _: &LayoutContext) {
+
+ debug!("assign_height_inline: assigning height for flow %?", self.common.id);
// Divide the boxes into lines
// TODO(#226): Get the CSS `line-height` property from the containing block's style to
@@ -598,7 +604,7 @@ impl InlineFlowData {
// TODO(#226): Get the CSS `line-height` property from each non-replaced inline element to
// determine its height for computing linebox height.
let mut scanner = LineboxScanner::new(InlineFlow(self), self.common.floats_in.clone());
- scanner.scan_for_lines(ctx);
+ scanner.scan_for_lines();
// Now, go through each line and lay out the boxes inside
for self.lines.iter().advance |line| {
@@ -765,7 +771,9 @@ impl InlineFlowData {
// TODO(#225): Should `inline-block` elements have flows as children of the inline flow or
// should the flow be nested inside the box somehow?
- true
+
+ // For now, don't traverse the subtree rooted here
+ false
}
}
diff --git a/src/components/main/layout/layout_task.rs b/src/components/main/layout/layout_task.rs
index 1581ba5f2e8..5170d6f5f88 100644
--- a/src/components/main/layout/layout_task.rs
+++ b/src/components/main/layout/layout_task.rs
@@ -251,14 +251,10 @@ impl LayoutTask {
}
for layout_root.traverse_postorder |flow| {
- do flow.with_base |base| {
- match base.parent {
- None => {},
- Some(parent_ctx) => {
- let prop = base.restyle_damage.propagate_up();
- do parent_ctx.with_mut_base |parent| {
- parent.restyle_damage.union_in_place(prop);
- }
+ for flow.each_child |child| {
+ do child.with_base |child_base| {
+ do flow.with_mut_base |base| {
+ base.restyle_damage.union_in_place(child_base.restyle_damage);
}
}
}
@@ -283,7 +279,9 @@ impl LayoutTask {
// For now, this is an inorder traversal
// FIXME: prune this traversal as well
- layout_root.assign_height(&mut layout_ctx);
+ for layout_root.traverse_bu_sub_inorder |flow| {
+ flow.assign_height(&mut layout_ctx);
+ }
}
// Build the display list if necessary, and send it to the renderer.