layout: Switch display list building from bottom-up to top-down.

This eliminates a lot of allocations and O(n^2) behavior.
This commit is contained in:
Patrick Walton 2016-03-02 15:41:50 -08:00
parent f4b95dd00b
commit d3d2dd05f2
5 changed files with 35 additions and 58 deletions

View file

@ -18,7 +18,7 @@ use context::LayoutContext;
use euclid::num::Zero; use euclid::num::Zero;
use euclid::{Matrix4, Point2D, Point3D, Rect, SideOffsets2D, Size2D}; use euclid::{Matrix4, Point2D, Point3D, Rect, SideOffsets2D, Size2D};
use flex::FlexFlow; use flex::FlexFlow;
use flow::{self, BaseFlow, Flow, IS_ABSOLUTELY_POSITIONED}; use flow::{BaseFlow, Flow, IS_ABSOLUTELY_POSITIONED};
use flow_ref; use flow_ref;
use fragment::{CoordinateSystem, Fragment, HAS_LAYER, ImageFragmentInfo, ScannedTextFragmentInfo}; use fragment::{CoordinateSystem, Fragment, HAS_LAYER, ImageFragmentInfo, ScannedTextFragmentInfo};
use fragment::{SpecificFragmentInfo}; use fragment::{SpecificFragmentInfo};
@ -86,21 +86,15 @@ impl<'a> DisplayListBuildState<'a> {
}); });
} }
fn append_from(&mut self, other_list: &mut Option<Vec<DisplayListEntry>>) {
if let Some(mut other) = other_list.take() {
self.items.append(&mut other);
}
}
fn stacking_context_id(&self) -> StackingContextId { fn stacking_context_id(&self) -> StackingContextId {
self.stacking_context_id_stack.last().unwrap().clone() self.stacking_context_id_stack.last().unwrap().clone()
} }
fn push_stacking_context_id(&mut self, stacking_context_id: StackingContextId) { pub fn push_stacking_context_id(&mut self, stacking_context_id: StackingContextId) {
self.stacking_context_id_stack.push(stacking_context_id); self.stacking_context_id_stack.push(stacking_context_id);
} }
fn pop_stacking_context_id(&mut self) { pub fn pop_stacking_context_id(&mut self) {
self.stacking_context_id_stack.pop(); self.stacking_context_id_stack.pop();
assert!(!self.stacking_context_id_stack.is_empty()); assert!(!self.stacking_context_id_stack.is_empty());
} }
@ -1736,11 +1730,6 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
clip, clip,
&self.base.stacking_relative_position_of_display_port); &self.base.stacking_relative_position_of_display_port);
// Add children.
for kid in self.base.children.iter_mut() {
state.append_from(&mut flow::mut_base(kid).display_list_building_result);
}
self.base.build_display_items_for_debugging_tint(state, self.fragment.node); self.base.build_display_items_for_debugging_tint(state, self.fragment.node);
} }
} }
@ -1805,22 +1794,6 @@ impl InlineFlowDisplayListBuilding for InlineFlow {
DisplayListSection::Content, DisplayListSection::Content,
&self.base.clip, &self.base.clip,
&self.base.stacking_relative_position_of_display_port); &self.base.stacking_relative_position_of_display_port);
match fragment.specific {
SpecificFragmentInfo::InlineBlock(ref mut block_flow) => {
let block_flow = flow_ref::deref_mut(&mut block_flow.flow_ref);
state.append_from(&mut flow::mut_base(block_flow).display_list_building_result)
}
SpecificFragmentInfo::InlineAbsoluteHypothetical(ref mut block_flow) => {
let block_flow = flow_ref::deref_mut(&mut block_flow.flow_ref);
state.append_from(&mut flow::mut_base(block_flow).display_list_building_result)
}
SpecificFragmentInfo::InlineAbsolute(ref mut block_flow) => {
let block_flow = flow_ref::deref_mut(&mut block_flow.flow_ref);
state.append_from(&mut flow::mut_base(block_flow).display_list_building_result)
}
_ => {}
}
} }
fn build_display_list_for_inline(&mut self, state: &mut DisplayListBuildState) { fn build_display_list_for_inline(&mut self, state: &mut DisplayListBuildState) {

View file

@ -34,7 +34,7 @@ use floats::Floats;
use flow_list::{FlowList, FlowListIterator, MutFlowListIterator}; use flow_list::{FlowList, FlowListIterator, MutFlowListIterator};
use flow_ref::{self, FlowRef, WeakFlowRef}; use flow_ref::{self, FlowRef, WeakFlowRef};
use fragment::{Fragment, FragmentBorderBoxIterator, Overflow, SpecificFragmentInfo}; use fragment::{Fragment, FragmentBorderBoxIterator, Overflow, SpecificFragmentInfo};
use gfx::display_list::{ClippingRegion, DisplayListEntry, StackingContext, StackingContextId}; use gfx::display_list::{ClippingRegion, StackingContext, StackingContextId};
use gfx_traits::{LayerId, LayerType}; use gfx_traits::{LayerId, LayerType};
use incremental::{RECONSTRUCT_FLOW, REFLOW, REFLOW_OUT_OF_FLOW, REPAINT, RestyleDamage}; use incremental::{RECONSTRUCT_FLOW, REFLOW, REFLOW_OUT_OF_FLOW, REPAINT, RestyleDamage};
use inline::InlineFlow; use inline::InlineFlow;
@ -957,9 +957,6 @@ pub struct BaseFlow {
/// per-stacking-context. /// per-stacking-context.
pub stacking_relative_position_of_display_port: Rect<Au>, pub stacking_relative_position_of_display_port: Rect<Au>,
/// The results of display list building for this flow.
pub display_list_building_result: Option<Vec<DisplayListEntry>>,
/// The writing mode for this flow. /// The writing mode for this flow.
pub writing_mode: WritingMode, pub writing_mode: WritingMode,
@ -1129,7 +1126,6 @@ impl BaseFlow {
block_container_writing_mode: writing_mode, block_container_writing_mode: writing_mode,
block_container_explicit_block_size: None, block_container_explicit_block_size: None,
absolute_cb: ContainingBlockLink::new(), absolute_cb: ContainingBlockLink::new(),
display_list_building_result: None,
early_absolute_position_info: EarlyAbsolutePositionInfo::new(writing_mode), early_absolute_position_info: EarlyAbsolutePositionInfo::new(writing_mode),
late_absolute_position_info: LateAbsolutePositionInfo::new(), late_absolute_position_info: LateAbsolutePositionInfo::new(),
clip: ClippingRegion::max(), clip: ClippingRegion::max(),
@ -1147,8 +1143,6 @@ impl BaseFlow {
children: children, children: children,
restyle_damage: self.restyle_damage | REPAINT | REFLOW_OUT_OF_FLOW | REFLOW, restyle_damage: self.restyle_damage | REPAINT | REFLOW_OUT_OF_FLOW | REFLOW,
parallel: FlowParallelInfo::new(), parallel: FlowParallelInfo::new(),
display_list_building_result: None,
floats: self.floats.clone(), floats: self.floats.clone(),
abs_descendants: self.abs_descendants.clone(), abs_descendants: self.abs_descendants.clone(),
absolute_cb: self.absolute_cb.clone(), absolute_cb: self.absolute_cb.clone(),

View file

@ -875,9 +875,10 @@ impl LayoutThread {
false, false,
None); None);
sequential::build_display_list_for_subtree(layout_root, let display_list_entries =
&mut root_stacking_context, sequential::build_display_list_for_subtree(layout_root,
shared_layout_context); &mut root_stacking_context,
shared_layout_context);
if data.goal == ReflowGoal::ForDisplay { if data.goal == ReflowGoal::ForDisplay {
debug!("Done building display list."); debug!("Done building display list.");
@ -900,11 +901,9 @@ impl LayoutThread {
ScrollPolicy::Scrollable, ScrollPolicy::Scrollable,
None, None,
root_background_color)); root_background_color));
let display_list = DisplayList::new(
root_stacking_context,
&mut flow::mut_base(flow_ref::deref_mut(layout_root))
.display_list_building_result);
let display_list = DisplayList::new(root_stacking_context,
&mut Some(display_list_entries));
if opts::get().dump_display_list { if opts::get().dump_display_list {
display_list.print(); display_list.print();
} }

View file

@ -6,13 +6,14 @@
use app_units::Au; use app_units::Au;
use context::{LayoutContext, SharedLayoutContext}; use context::{LayoutContext, SharedLayoutContext};
use display_list_builder::DisplayListBuildState;
use euclid::point::Point2D; use euclid::point::Point2D;
use flow::{PostorderFlowTraversal, PreorderFlowTraversal}; use flow::{PostorderFlowTraversal, PreorderFlowTraversal};
use flow::{self, Flow, ImmutableFlowUtils, InorderFlowTraversal, MutableFlowUtils}; use flow::{self, Flow, ImmutableFlowUtils, InorderFlowTraversal, MutableFlowUtils};
use flow_ref::{self, FlowRef}; use flow_ref::{self, FlowRef};
use fragment::FragmentBorderBoxIterator; use fragment::FragmentBorderBoxIterator;
use generated_content::ResolveGeneratedContent; use generated_content::ResolveGeneratedContent;
use gfx::display_list::StackingContext; use gfx::display_list::{DisplayListEntry, StackingContext};
use style::dom::TNode; use style::dom::TNode;
use style::traversal::DomTraversalContext; use style::traversal::DomTraversalContext;
use traversal::{AssignBSizesAndStoreOverflow, AssignISizes}; use traversal::{AssignBSizesAndStoreOverflow, AssignISizes};
@ -77,13 +78,19 @@ pub fn traverse_flow_tree_preorder(root: &mut FlowRef,
pub fn build_display_list_for_subtree(root: &mut FlowRef, pub fn build_display_list_for_subtree(root: &mut FlowRef,
root_stacking_context: &mut StackingContext, root_stacking_context: &mut StackingContext,
shared_layout_context: &SharedLayoutContext) { shared_layout_context: &SharedLayoutContext)
-> Vec<DisplayListEntry> {
let flow_root = flow_ref::deref_mut(root); let flow_root = flow_ref::deref_mut(root);
let layout_context = LayoutContext::new(shared_layout_context); let layout_context = LayoutContext::new(shared_layout_context);
flow_root.traverse_preorder(&ComputeAbsolutePositions { layout_context: &layout_context }); flow_root.traverse_preorder(&ComputeAbsolutePositions { layout_context: &layout_context });
flow_root.collect_stacking_contexts(root_stacking_context.id, flow_root.collect_stacking_contexts(root_stacking_context.id,
&mut root_stacking_context.children); &mut root_stacking_context.children);
flow_root.traverse_postorder(&BuildDisplayList { layout_context: &layout_context }); let mut build_display_list = BuildDisplayList {
state: DisplayListBuildState::new(&layout_context,
flow::base(&**root).stacking_context_id),
};
build_display_list.traverse(&mut *flow_root);
build_display_list.state.items
} }
pub fn iterate_through_flow_tree_fragment_border_boxes(root: &mut FlowRef, pub fn iterate_through_flow_tree_fragment_border_boxes(root: &mut FlowRef,

View file

@ -215,23 +215,27 @@ impl<'a> PreorderFlowTraversal for ComputeAbsolutePositions<'a> {
} }
} }
#[derive(Copy, Clone)]
pub struct BuildDisplayList<'a> { pub struct BuildDisplayList<'a> {
pub layout_context: &'a LayoutContext<'a>, pub state: DisplayListBuildState<'a>,
} }
impl<'a> PostorderFlowTraversal for BuildDisplayList<'a> { impl<'a> BuildDisplayList<'a> {
#[inline] #[inline]
fn process(&self, flow: &mut Flow) { pub fn traverse(&mut self, flow: &mut Flow) {
let mut state = DisplayListBuildState::new( if self.should_process() {
self.layout_context, flow::base(flow).stacking_context_id); self.state.push_stacking_context_id(flow::base(flow).stacking_context_id);
flow.build_display_list(&mut state); flow.build_display_list(&mut self.state);
flow::mut_base(flow).display_list_building_result = Some(state.items); flow::mut_base(flow).restyle_damage.remove(REPAINT);
flow::mut_base(flow).restyle_damage.remove(REPAINT); self.state.pop_stacking_context_id();
}
for kid in flow::child_iter(flow) {
self.traverse(kid);
}
} }
#[inline] #[inline]
fn should_process(&self, _: &mut Flow) -> bool { fn should_process(&self) -> bool {
self.layout_context.shared_context().goal == ReflowGoal::ForDisplay self.state.layout_context.shared_context().goal == ReflowGoal::ForDisplay
} }
} }