layout: Move overflow calculation to be a separate, sequential,

bottom-up pass.

Right now, the only reason that overflow calculation works is that we
rely on script inducing extra reflows that are sent for display. This
was preventing #10021 from landing.

This change regresses layout performance by about 1% in my tests.

Fixes #7797 properly.
This commit is contained in:
Patrick Walton 2016-03-17 14:28:37 -07:00
parent 2d6283c64b
commit 5ea8c34276
7 changed files with 60 additions and 17 deletions

View file

@ -16,27 +16,31 @@ bitflags! {
#[doc = "Currently unused; need to decide how this propagates."] #[doc = "Currently unused; need to decide how this propagates."]
const REPAINT = 0x01, const REPAINT = 0x01,
#[doc = "Recompute the overflow regions (bounding box of object and all descendants)."]
#[doc = "Propagates down the flow tree because the computation is bottom-up."]
const STORE_OVERFLOW = 0x02,
#[doc = "Recompute intrinsic inline_sizes (minimum and preferred)."] #[doc = "Recompute intrinsic inline_sizes (minimum and preferred)."]
#[doc = "Propagates down the flow tree because the computation is"] #[doc = "Propagates down the flow tree because the computation is"]
#[doc = "bottom-up."] #[doc = "bottom-up."]
const BUBBLE_ISIZES = 0x02, const BUBBLE_ISIZES = 0x04,
#[doc = "Recompute actual inline-sizes and block-sizes, only taking out-of-flow children \ #[doc = "Recompute actual inline-sizes and block-sizes, only taking out-of-flow children \
into account. \ into account. \
Propagates up the flow tree because the computation is top-down."] Propagates up the flow tree because the computation is top-down."]
const REFLOW_OUT_OF_FLOW = 0x04, const REFLOW_OUT_OF_FLOW = 0x08,
#[doc = "Recompute actual inline_sizes and block_sizes."] #[doc = "Recompute actual inline_sizes and block_sizes."]
#[doc = "Propagates up the flow tree because the computation is"] #[doc = "Propagates up the flow tree because the computation is"]
#[doc = "top-down."] #[doc = "top-down."]
const REFLOW = 0x08, const REFLOW = 0x10,
#[doc = "Re-resolve generated content. \ #[doc = "Re-resolve generated content. \
Propagates up the flow tree because the computation is inorder."] Propagates up the flow tree because the computation is inorder."]
const RESOLVE_GENERATED_CONTENT = 0x10, const RESOLVE_GENERATED_CONTENT = 0x20,
#[doc = "The entire flow needs to be reconstructed."] #[doc = "The entire flow needs to be reconstructed."]
const RECONSTRUCT_FLOW = 0x20 const RECONSTRUCT_FLOW = 0x40
} }
} }
@ -56,7 +60,7 @@ impl TRestyleDamage for RestyleDamage {
/// Use this instead of `RestyleDamage::all()` because `RestyleDamage::all()` will result in /// Use this instead of `RestyleDamage::all()` because `RestyleDamage::all()` will result in
/// unnecessary sequential resolution of generated content. /// unnecessary sequential resolution of generated content.
fn rebuild_and_reflow() -> RestyleDamage { fn rebuild_and_reflow() -> RestyleDamage {
REPAINT | BUBBLE_ISIZES | REFLOW_OUT_OF_FLOW | REFLOW | RECONSTRUCT_FLOW REPAINT | STORE_OVERFLOW | BUBBLE_ISIZES | REFLOW_OUT_OF_FLOW | REFLOW | RECONSTRUCT_FLOW
} }
} }
@ -66,9 +70,10 @@ impl RestyleDamage {
/// we should add to the *parent* of this flow. /// we should add to the *parent* of this flow.
pub fn damage_for_parent(self, child_is_absolutely_positioned: bool) -> RestyleDamage { pub fn damage_for_parent(self, child_is_absolutely_positioned: bool) -> RestyleDamage {
if child_is_absolutely_positioned { if child_is_absolutely_positioned {
self & (REPAINT | REFLOW_OUT_OF_FLOW | RESOLVE_GENERATED_CONTENT) self & (REPAINT | STORE_OVERFLOW | REFLOW_OUT_OF_FLOW | RESOLVE_GENERATED_CONTENT)
} else { } else {
self & (REPAINT | REFLOW | REFLOW_OUT_OF_FLOW | RESOLVE_GENERATED_CONTENT) self & (REPAINT | STORE_OVERFLOW | REFLOW | REFLOW_OUT_OF_FLOW |
RESOLVE_GENERATED_CONTENT)
} }
} }
@ -108,6 +113,7 @@ impl fmt::Display for RestyleDamage {
let to_iter = let to_iter =
[ (REPAINT, "Repaint") [ (REPAINT, "Repaint")
, (STORE_OVERFLOW, "StoreOverflow")
, (BUBBLE_ISIZES, "BubbleISizes") , (BUBBLE_ISIZES, "BubbleISizes")
, (REFLOW_OUT_OF_FLOW, "ReflowOutOfFlow") , (REFLOW_OUT_OF_FLOW, "ReflowOutOfFlow")
, (REFLOW, "Reflow") , (REFLOW, "Reflow")
@ -165,13 +171,13 @@ pub fn compute_damage(old: Option<&Arc<ComputedValues>>, new: &ComputedValues) -
]); ]);
add_if_not_equal!(old, new, damage, add_if_not_equal!(old, new, damage,
[ REPAINT, REFLOW_OUT_OF_FLOW ], [ [ REPAINT, STORE_OVERFLOW, REFLOW_OUT_OF_FLOW ], [
get_positionoffsets.top, get_positionoffsets.left, get_positionoffsets.top, get_positionoffsets.left,
get_positionoffsets.right, get_positionoffsets.bottom get_positionoffsets.right, get_positionoffsets.bottom
]); ]);
add_if_not_equal!(old, new, damage, add_if_not_equal!(old, new, damage,
[ REPAINT, BUBBLE_ISIZES, REFLOW_OUT_OF_FLOW, REFLOW ], [ [ REPAINT, STORE_OVERFLOW, BUBBLE_ISIZES, REFLOW_OUT_OF_FLOW, REFLOW ], [
get_border.border_top_width, get_border.border_right_width, get_border.border_top_width, get_border.border_right_width,
get_border.border_bottom_width, get_border.border_left_width, get_border.border_bottom_width, get_border.border_left_width,
get_margin.margin_top, get_margin.margin_right, get_margin.margin_top, get_margin.margin_right,
@ -183,7 +189,14 @@ pub fn compute_damage(old: Option<&Arc<ComputedValues>>, new: &ComputedValues) -
]); ]);
add_if_not_equal!(old, new, damage, add_if_not_equal!(old, new, damage,
[ REPAINT, BUBBLE_ISIZES, REFLOW_OUT_OF_FLOW, REFLOW, RECONSTRUCT_FLOW ], [ [
REPAINT,
STORE_OVERFLOW,
BUBBLE_ISIZES,
REFLOW_OUT_OF_FLOW,
REFLOW,
RECONSTRUCT_FLOW
], [
get_box.float, get_box.display, get_box.position, get_box.content, get_box.float, get_box.display, get_box.position, get_box.content,
get_counters.counter_reset, get_counters.counter_increment, get_counters.counter_reset, get_counters.counter_increment,
get_list.quotes, get_list.list_style_type, get_list.quotes, get_list.list_style_type,

View file

@ -12,7 +12,7 @@ use app_units::Au;
use azure::azure::AzColor; use azure::azure::AzColor;
use canvas_traits::CanvasMsg; use canvas_traits::CanvasMsg;
use construct::ConstructionResult; use construct::ConstructionResult;
use context::{SharedLayoutContext, heap_size_of_local_context}; use context::{LayoutContext, SharedLayoutContext, heap_size_of_local_context};
use display_list_builder::ToGfxColor; use display_list_builder::ToGfxColor;
use euclid::Matrix4; use euclid::Matrix4;
use euclid::point::Point2D; use euclid::point::Point2D;
@ -1336,14 +1336,23 @@ impl LayoutThread {
Some(ref mut parallel) => { Some(ref mut parallel) => {
// Parallel mode. // Parallel mode.
LayoutThread::solve_constraints_parallel(parallel, LayoutThread::solve_constraints_parallel(parallel,
&mut root_flow, &mut root_flow,
profiler_metadata, profiler_metadata,
self.time_profiler_chan.clone(), self.time_profiler_chan.clone(),
&*layout_context); &*layout_context);
} }
} }
}); });
profile(time::ProfilerCategory::LayoutStoreOverflow,
self.profiler_metadata(),
self.time_profiler_chan.clone(),
|| {
let layout_context = LayoutContext::new(&*layout_context);
sequential::store_overflow(&layout_context,
flow_ref::deref_mut(&mut root_flow) as &mut Flow);
});
self.perform_post_main_layout_passes(data, rw_data, layout_context); self.perform_post_main_layout_passes(data, rw_data, layout_context);
} }
} }

View file

@ -14,6 +14,7 @@ use flow_ref::{self, FlowRef};
use fragment::FragmentBorderBoxIterator; use fragment::FragmentBorderBoxIterator;
use generated_content::ResolveGeneratedContent; use generated_content::ResolveGeneratedContent;
use gfx::display_list::{DisplayListEntry, StackingContext}; use gfx::display_list::{DisplayListEntry, StackingContext};
use incremental::STORE_OVERFLOW;
use style::dom::TNode; use style::dom::TNode;
use style::traversal::DomTraversalContext; use style::traversal::DomTraversalContext;
use traversal::{AssignBSizes, AssignISizes}; use traversal::{AssignBSizes, AssignISizes};
@ -117,3 +118,18 @@ pub fn iterate_through_flow_tree_fragment_border_boxes(root: &mut FlowRef,
doit(flow_ref::deref_mut(root), 0, iterator, &Point2D::zero()); doit(flow_ref::deref_mut(root), 0, iterator, &Point2D::zero());
} }
pub fn store_overflow(layout_context: &LayoutContext, flow: &mut Flow) {
if !flow::base(flow).restyle_damage.contains(STORE_OVERFLOW) {
return
}
for mut kid in flow::mut_base(flow).child_iter() {
store_overflow(layout_context, kid);
}
flow.store_overflow(layout_context);
flow::mut_base(flow).restyle_damage.remove(STORE_OVERFLOW);
}

View file

@ -210,7 +210,6 @@ impl<'a> PreorderFlowTraversal for ComputeAbsolutePositions<'a> {
#[inline] #[inline]
fn process(&self, flow: &mut Flow) { fn process(&self, flow: &mut Flow) {
flow.compute_absolute_position(self.layout_context); flow.compute_absolute_position(self.layout_context);
flow.store_overflow(self.layout_context);
} }
} }

View file

@ -60,6 +60,7 @@ impl Formattable for ProfilerCategory {
ProfilerCategory::LayoutGeneratedContent | ProfilerCategory::LayoutGeneratedContent |
ProfilerCategory::LayoutDisplayListSorting | ProfilerCategory::LayoutDisplayListSorting |
ProfilerCategory::LayoutMain | ProfilerCategory::LayoutMain |
ProfilerCategory::LayoutStoreOverflow |
ProfilerCategory::LayoutDispListBuild | ProfilerCategory::LayoutDispListBuild |
ProfilerCategory::LayoutDamagePropagate | ProfilerCategory::LayoutDamagePropagate |
ProfilerCategory::PaintingPerTile | ProfilerCategory::PaintingPerTile |
@ -83,6 +84,7 @@ impl Formattable for ProfilerCategory {
ProfilerCategory::LayoutDisplayListSorting => "Sorting Display List", ProfilerCategory::LayoutDisplayListSorting => "Sorting Display List",
ProfilerCategory::LayoutGeneratedContent => "Generated Content Resolution", ProfilerCategory::LayoutGeneratedContent => "Generated Content Resolution",
ProfilerCategory::LayoutMain => "Primary Layout Pass", ProfilerCategory::LayoutMain => "Primary Layout Pass",
ProfilerCategory::LayoutStoreOverflow => "Store Overflow",
ProfilerCategory::LayoutParallelWarmup => "Parallel Warmup", ProfilerCategory::LayoutParallelWarmup => "Parallel Warmup",
ProfilerCategory::LayoutDispListBuild => "Display List Construction", ProfilerCategory::LayoutDispListBuild => "Display List Construction",
ProfilerCategory::PaintingPerTile => "Painting Per Tile", ProfilerCategory::PaintingPerTile => "Painting Per Tile",

View file

@ -50,6 +50,7 @@ pub enum ProfilerCategory {
LayoutGeneratedContent, LayoutGeneratedContent,
LayoutDisplayListSorting, LayoutDisplayListSorting,
LayoutMain, LayoutMain,
LayoutStoreOverflow,
LayoutParallelWarmup, LayoutParallelWarmup,
LayoutDispListBuild, LayoutDispListBuild,
PaintingPerTile, PaintingPerTile,

View file

@ -0,0 +1,3 @@
[numbers-units-018.htm]
type: reftest
expected: FAIL