Implement basic overflow computation. Closes #1148.

This adds just 4 ms out of ~120 ms on the rainbow page.
This commit is contained in:
Patrick Walton 2013-10-29 19:19:51 -07:00
parent cc76a2188e
commit 5327c9c44f
5 changed files with 65 additions and 20 deletions

View file

@ -302,6 +302,7 @@ impl FlowContext for FloatFlow {
position.size.height = height; position.size.height = height;
} }
} }
fn collapse_margins(&mut self, fn collapse_margins(&mut self,

View file

@ -90,12 +90,12 @@ pub trait FlowContext {
fail!("assign_widths not yet implemented") fail!("assign_widths not yet implemented")
} }
/// Pass 3 of reflow: computes height. /// Pass 3a of reflow: computes height.
fn assign_height(&mut self, _ctx: &mut LayoutContext) { fn assign_height(&mut self, _ctx: &mut LayoutContext) {
fail!("assign_height not yet implemented") fail!("assign_height not yet implemented")
} }
/// In-order version of pass 3 of reflow: computes heights with floats present. /// In-order version of pass 3a of reflow: computes heights with floats present.
fn assign_height_inorder(&mut self, _ctx: &mut LayoutContext) { fn assign_height_inorder(&mut self, _ctx: &mut LayoutContext) {
fail!("assign_height_inorder not yet implemented") fail!("assign_height_inorder not yet implemented")
} }
@ -190,6 +190,9 @@ pub trait MutableFlowUtils {
/// Removes the last child of this flow and destroys it. /// Removes the last child of this flow and destroys it.
fn remove_last(self); fn remove_last(self);
/// Computes the overflow region for this flow.
fn store_overflow(self, _: &mut LayoutContext);
/// Builds a display list for this flow and its children. /// Builds a display list for this flow and its children.
fn build_display_list<E:ExtraDisplayListData>( fn build_display_list<E:ExtraDisplayListData>(
self, self,
@ -315,7 +318,15 @@ pub struct FlowData {
// layout; maybe combine into a single enum to save space. // layout; maybe combine into a single enum to save space.
min_width: Au, min_width: Au,
pref_width: Au, pref_width: Au,
/// The position of the upper left corner of the border box of this flow, relative to the
/// containing block.
position: Rect<Au>, position: Rect<Au>,
/// The amount of overflow of this flow, relative to the containing block. Must include all the
/// pixels of all the display list items for correct invalidation.
overflow: Rect<Au>,
floats_in: FloatContext, floats_in: FloatContext,
floats_out: FloatContext, floats_out: FloatContext,
num_floats: uint, num_floats: uint,
@ -353,6 +364,7 @@ impl FlowData {
min_width: Au::new(0), min_width: Au::new(0),
pref_width: Au::new(0), pref_width: Au::new(0),
position: Au::zero_rect(), position: Au::zero_rect(),
overflow: Au::zero_rect(),
floats_in: Invalid, floats_in: Invalid,
floats_out: Invalid, floats_out: Invalid,
num_floats: 0, num_floats: 0,
@ -467,6 +479,17 @@ impl<'self> MutableFlowUtils for &'self mut FlowContext {
let _ = mut_base(self).children.pop_back(); let _ = mut_base(self).children.pop_back();
} }
fn store_overflow(self, _: &mut LayoutContext) {
let my_position = mut_base(self).position;
let mut overflow = my_position;
for kid in mut_base(self).child_iter() {
let mut kid_overflow = base(*kid).overflow;
kid_overflow = kid_overflow.translate(&my_position.origin);
overflow = overflow.union(&kid_overflow)
}
mut_base(self).overflow = overflow
}
fn build_display_list<E:ExtraDisplayListData>( fn build_display_list<E:ExtraDisplayListData>(
self, self,
builder: &DisplayListBuilder, builder: &DisplayListBuilder,

View file

@ -138,15 +138,16 @@ impl<'self> PreorderFlowTraversal for AssignWidthsTraversal<'self> {
} }
} }
/// The assign-heights traversal, the last (and most expensive) part of layout computation. /// The assign-heights-and-store-overflow traversal, the last (and most expensive) part of layout
/// Determines the final heights for all layout objects. In Gecko this corresponds to /// computation. Determines the final heights for all layout objects, computes positions, and
/// `FinishAndStoreOverflow`. /// computes overflow regions. In Gecko this corresponds to `FinishAndStoreOverflow`.
struct AssignHeightsTraversal<'self>(&'self mut LayoutContext); struct AssignHeightsAndStoreOverflowTraversal<'self>(&'self mut LayoutContext);
impl<'self> PostorderFlowTraversal for AssignHeightsTraversal<'self> { impl<'self> PostorderFlowTraversal for AssignHeightsAndStoreOverflowTraversal<'self> {
#[inline] #[inline]
fn process(&mut self, flow: &mut FlowContext) -> bool { fn process(&mut self, flow: &mut FlowContext) -> bool {
flow.assign_height(**self); flow.assign_height(**self);
flow.store_overflow(**self);
true true
} }
@ -296,6 +297,29 @@ impl LayoutTask {
self.stylist.add_stylesheet(sheet, AuthorOrigin); self.stylist.add_stylesheet(sheet, AuthorOrigin);
} }
/// Performs layout constraint solving.
///
/// This corresponds to `Reflow()` in Gecko and `layout()` in WebKit/Blink and should be
/// benchmarked against those two. It is marked `#[inline(never)]` to aid profiling.
#[inline(never)]
fn solve_constraints(&mut self,
layout_root: &mut FlowContext,
layout_context: &mut LayoutContext) {
let _ = layout_root.traverse_postorder(&mut BubbleWidthsTraversal(layout_context));
// FIXME(kmc): We want to do
// for flow in layout_root.traverse_preorder_prune(|f|
// f.restyle_damage().lacks(Reflow))
// but FloatContext values can't be reused, so we need to recompute them every time.
// NOTE: this currently computes borders, so any pruning should separate that operation out.
let _ = layout_root.traverse_preorder(&mut AssignWidthsTraversal(layout_context));
// For now, this is an inorder traversal
// FIXME: prune this traversal as well
let _ = layout_root.traverse_postorder(&mut
AssignHeightsAndStoreOverflowTraversal(layout_context));
}
/// The high-level routine that performs layout tasks. /// The high-level routine that performs layout tasks.
fn handle_reflow(&mut self, data: &Reflow) { fn handle_reflow(&mut self, data: &Reflow) {
// FIXME: Isolate this transmutation into a "bridge" module. // FIXME: Isolate this transmutation into a "bridge" module.
@ -365,17 +389,7 @@ impl LayoutTask {
// Perform the primary layout passes over the flow tree to compute the locations of all // Perform the primary layout passes over the flow tree to compute the locations of all
// the boxes. // the boxes.
do profile(time::LayoutMainCategory, self.profiler_chan.clone()) { do profile(time::LayoutMainCategory, self.profiler_chan.clone()) {
let _ = layout_root.traverse_postorder(&mut BubbleWidthsTraversal(&mut layout_ctx)); self.solve_constraints(layout_root, &mut layout_ctx)
// FIXME(kmc): We want to do
// for flow in layout_root.traverse_preorder_prune(|f| f.restyle_damage().lacks(Reflow))
// but FloatContext values can't be reused, so we need to recompute them every time.
// NOTE: this currently computes borders, so any pruning should separate that operation out.
let _ = layout_root.traverse_preorder(&mut AssignWidthsTraversal(&mut layout_ctx));
// For now, this is an inorder traversal
// FIXME: prune this traversal as well
let _ = layout_root.traverse_postorder(&mut AssignHeightsTraversal(&mut layout_ctx));
} }
// Build the display list if necessary, and send it to the renderer. // Build the display list if necessary, and send it to the renderer.

View file

@ -8,9 +8,16 @@ use geom::size::Size2D;
use std::num::{NumCast, One, Zero}; use std::num::{NumCast, One, Zero};
#[deriving(Clone)]
pub struct Au(i32); pub struct Au(i32);
// We don't use #[deriving] here for inlining.
impl Clone for Au {
#[inline]
fn clone(&self) -> Au {
Au(**self)
}
}
impl Eq for Au { impl Eq for Au {
#[inline] #[inline]
fn eq(&self, other: &Au) -> bool { fn eq(&self, other: &Au) -> bool {

@ -1 +1 @@
Subproject commit 82d56dfc632fe458d126d049fd5abe856170f48d Subproject commit 6e4db1ea746f38fe8156bc285c89ad5c12b124a9