Auto merge of #9843 - pcwalton:optimize-flat-display-lists, r=mrobinson

Optimize flat display lists

Flat display lists were a 2x regression on the spheres demo. This patch series fixes that.

See the individual commits for more details.

r? @mrobinson

<!-- Reviewable:start -->
[<img src="https://reviewable.io/review_button.svg" height="40" alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/9843)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2016-03-04 02:49:04 +05:30
commit 55fc48e4c4
19 changed files with 241 additions and 231 deletions

View file

@ -21,15 +21,22 @@ use euclid::approxeq::ApproxEq;
use euclid::num::Zero; use euclid::num::Zero;
use euclid::rect::TypedRect; use euclid::rect::TypedRect;
use euclid::{Matrix2D, Matrix4, Point2D, Rect, SideOffsets2D, Size2D}; use euclid::{Matrix2D, Matrix4, Point2D, Rect, SideOffsets2D, Size2D};
use fnv::FnvHasher;
use gfx_traits::{LayerId, ScrollPolicy}; use gfx_traits::{LayerId, ScrollPolicy};
use heapsize::HeapSizeOf; use heapsize::HeapSizeOf;
use msg::constellation_msg::PipelineId; use msg::constellation_msg::PipelineId;
use net_traits::image::base::Image; use net_traits::image::base::Image;
use paint_context::PaintContext; use paint_context::PaintContext;
use range::Range; use range::Range;
use serde::de::{self, Deserialize, Deserializer, MapVisitor, Visitor};
use serde::ser::impls::MapIteratorVisitor;
use serde::ser::{Serialize, Serializer};
use std::cmp::Ordering; use std::cmp::Ordering;
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt; use std::fmt;
use std::hash::{BuildHasherDefault, Hash};
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use std::sync::Arc; use std::sync::Arc;
use style::computed_values::{border_style, cursor, filter, image_rendering, mix_blend_mode}; use style::computed_values::{border_style, cursor, filter, image_rendering, mix_blend_mode};
use style::computed_values::{pointer_events}; use style::computed_values::{pointer_events};
@ -141,10 +148,75 @@ pub struct StackingContextOffsets {
pub outlines: u32, pub outlines: u32,
} }
/// A FNV-based hash map. This is not serializable by `serde` by default, so we provide an
/// implementation ourselves.
pub struct FnvHashMap<K, V>(pub HashMap<K, V, BuildHasherDefault<FnvHasher>>);
impl<K, V> Deref for FnvHashMap<K, V> {
type Target = HashMap<K, V, BuildHasherDefault<FnvHasher>>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<K, V> DerefMut for FnvHashMap<K, V> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<K, V> Serialize for FnvHashMap<K, V> where K: Eq + Hash + Serialize, V: Serialize {
#[inline]
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer {
serializer.visit_map(MapIteratorVisitor::new(self.iter(), Some(self.len())))
}
}
impl<K, V> Deserialize for FnvHashMap<K, V> where K: Eq + Hash + Deserialize, V: Deserialize {
#[inline]
fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error> where D: Deserializer {
deserializer.visit_map(FnvHashMapVisitor::new())
}
}
/// A visitor that produces a map.
pub struct FnvHashMapVisitor<K, V> {
marker: PhantomData<FnvHashMap<K, V>>,
}
impl<K, V> FnvHashMapVisitor<K, V> {
/// Construct a `FnvHashMapVisitor<T>`.
pub fn new() -> Self {
FnvHashMapVisitor {
marker: PhantomData,
}
}
}
impl<K, V> Visitor for FnvHashMapVisitor<K, V> where K: Eq + Hash + Deserialize, V: Deserialize {
type Value = FnvHashMap<K, V>;
#[inline]
fn visit_unit<E>(&mut self) -> Result<FnvHashMap<K, V>, E> where E: de::Error {
Ok(FnvHashMap(HashMap::with_hasher(Default::default())))
}
#[inline]
fn visit_map<Visitor>(&mut self, mut visitor: Visitor)
-> Result<FnvHashMap<K, V>, Visitor::Error>
where Visitor: MapVisitor {
let mut values = FnvHashMap(HashMap::with_hasher(Default::default()));
while let Some((key, value)) = try!(visitor.visit()) {
HashMap::insert(&mut values, key, value);
}
try!(visitor.end());
Ok(values)
}
}
#[derive(HeapSizeOf, Deserialize, Serialize)] #[derive(HeapSizeOf, Deserialize, Serialize)]
pub struct DisplayList { pub struct DisplayList {
pub list: Vec<DisplayListEntry>, pub list: Vec<DisplayListEntry>,
pub offsets: HashMap<StackingContextId, StackingContextOffsets>, pub offsets: FnvHashMap<StackingContextId, StackingContextOffsets>,
pub root_stacking_context: StackingContext, pub root_stacking_context: StackingContext,
} }
@ -157,7 +229,7 @@ impl DisplayList {
None => panic!("Tried to create empty display list."), None => panic!("Tried to create empty display list."),
}; };
let mut offsets = HashMap::new(); let mut offsets = FnvHashMap(HashMap::with_hasher(Default::default()));
DisplayList::sort_and_count_stacking_contexts(&mut root_stacking_context, &mut offsets, 0); DisplayList::sort_and_count_stacking_contexts(&mut root_stacking_context, &mut offsets, 0);
let mut display_list = DisplayList { let mut display_list = DisplayList {
@ -201,7 +273,9 @@ impl DisplayList {
fn sort_and_count_stacking_contexts( fn sort_and_count_stacking_contexts(
stacking_context: &mut StackingContext, stacking_context: &mut StackingContext,
offsets: &mut HashMap<StackingContextId, StackingContextOffsets>, offsets: &mut HashMap<StackingContextId,
StackingContextOffsets,
BuildHasherDefault<FnvHasher>>,
mut current_offset: u32) mut current_offset: u32)
-> u32 { -> u32 {
stacking_context.children.sort(); stacking_context.children.sort();
@ -508,7 +582,7 @@ pub struct StackingContext {
pub layer_info: Option<LayerInfo>, pub layer_info: Option<LayerInfo>,
/// Children of this StackingContext. /// Children of this StackingContext.
pub children: Vec<StackingContext>, pub children: Vec<Box<StackingContext>>,
} }
impl StackingContext { impl StackingContext {
@ -761,16 +835,13 @@ impl ClippingRegion {
} }
} }
/// Returns the intersection of this clipping region and the given rectangle. /// Mutates this clipping region to intersect with the given rectangle.
/// ///
/// TODO(pcwalton): This could more eagerly eliminate complex clipping regions, at the cost of /// TODO(pcwalton): This could more eagerly eliminate complex clipping regions, at the cost of
/// complexity. /// complexity.
#[inline] #[inline]
pub fn intersect_rect(self, rect: &Rect<Au>) -> ClippingRegion { pub fn intersect_rect(&mut self, rect: &Rect<Au>) {
ClippingRegion { self.main = self.main.intersection(rect).unwrap_or(Rect::zero())
main: self.main.intersection(rect).unwrap_or(Rect::zero()),
complex: self.complex,
}
} }
/// Returns true if this clipping region might be nonempty. This can return false positives, /// Returns true if this clipping region might be nonempty. This can return false positives,

View file

@ -64,7 +64,6 @@ use style::properties::ComputedValues;
use style::values::computed::{LengthOrNone, LengthOrPercentageOrNone}; use style::values::computed::{LengthOrNone, LengthOrPercentageOrNone};
use style::values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto}; use style::values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto};
use util::geometry::MAX_RECT; use util::geometry::MAX_RECT;
use util::opts;
use util::print_tree::PrintTree; use util::print_tree::PrintTree;
/// Information specific to floated blocks. /// Information specific to floated blocks.
@ -1622,14 +1621,18 @@ impl BlockFlow {
} }
} }
pub fn establishes_pseudo_stacking_context(&self) -> bool { pub fn block_stacking_context_type(&self) -> BlockStackingContextType {
if self.fragment.establishes_stacking_context() { if self.fragment.establishes_stacking_context() {
return false; return BlockStackingContextType::StackingContext
} }
self.base.flags.contains(IS_ABSOLUTELY_POSITIONED) || if self.base.flags.contains(IS_ABSOLUTELY_POSITIONED) ||
self.fragment.style.get_box().position != position::T::static_ || self.fragment.style.get_box().position != position::T::static_ ||
self.base.flags.is_float() self.base.flags.is_float() {
BlockStackingContextType::PseudoStackingContext
} else {
BlockStackingContextType::NonstackingContext
}
} }
pub fn has_scrolling_overflow(&self) -> bool { pub fn has_scrolling_overflow(&self) -> bool {
@ -1954,8 +1957,10 @@ impl Flow for BlockFlow {
self.base.position.size.to_physical(self.base.writing_mode); self.base.position.size.to_physical(self.base.writing_mode);
// Compute the origin and clipping rectangle for children. // Compute the origin and clipping rectangle for children.
//
// `clip` is in the child coordinate system.
let mut clip;
let origin_for_children; let origin_for_children;
let clip_in_child_coordinate_system;
let is_stacking_context = self.fragment.establishes_stacking_context(); let is_stacking_context = self.fragment.establishes_stacking_context();
if is_stacking_context { if is_stacking_context {
// We establish a stacking context, so the position of our children is vertically // We establish a stacking context, so the position of our children is vertically
@ -1966,12 +1971,11 @@ impl Flow for BlockFlow {
// FIXME(pcwalton): Is this vertical-writing-direction-safe? // FIXME(pcwalton): Is this vertical-writing-direction-safe?
let margin = self.fragment.margin.to_physical(self.base.writing_mode); let margin = self.fragment.margin.to_physical(self.base.writing_mode);
origin_for_children = Point2D::new(-margin.left, Au(0)); origin_for_children = Point2D::new(-margin.left, Au(0));
clip_in_child_coordinate_system = clip = self.base.clip.translate(&-self.base.stacking_relative_position);
self.base.clip.translate(&-self.base.stacking_relative_position);
} else { } else {
let relative_offset = relative_offset.to_physical(self.base.writing_mode); let relative_offset = relative_offset.to_physical(self.base.writing_mode);
origin_for_children = self.base.stacking_relative_position + relative_offset; origin_for_children = self.base.stacking_relative_position + relative_offset;
clip_in_child_coordinate_system = self.base.clip.clone(); clip = self.base.clip.clone();
} }
let stacking_relative_position_of_display_port_for_children = let stacking_relative_position_of_display_port_for_children =
@ -2003,8 +2007,8 @@ impl Flow for BlockFlow {
.early_absolute_position_info .early_absolute_position_info
.relative_containing_block_mode, .relative_containing_block_mode,
CoordinateSystem::Own); CoordinateSystem::Own);
let clip = self.fragment.clipping_region_for_children( self.fragment.adjust_clipping_region_for_children(
&clip_in_child_coordinate_system, &mut clip,
&stacking_relative_border_box, &stacking_relative_border_box,
self.base.flags.contains(IS_ABSOLUTELY_POSITIONED)); self.base.flags.contains(IS_ABSOLUTELY_POSITIONED));
@ -2109,7 +2113,7 @@ impl Flow for BlockFlow {
fn collect_stacking_contexts(&mut self, fn collect_stacking_contexts(&mut self,
parent_id: StackingContextId, parent_id: StackingContextId,
contexts: &mut Vec<StackingContext>) contexts: &mut Vec<Box<StackingContext>>)
-> StackingContextId { -> StackingContextId {
self.collect_stacking_contexts_for_block(parent_id, contexts) self.collect_stacking_contexts_for_block(parent_id, contexts)
} }
@ -2117,9 +2121,6 @@ impl Flow for BlockFlow {
fn build_display_list(&mut self, state: &mut DisplayListBuildState) { fn build_display_list(&mut self, state: &mut DisplayListBuildState) {
self.build_display_list_for_block(state, BorderPaintingMode::Separate); self.build_display_list_for_block(state, BorderPaintingMode::Separate);
self.fragment.restyle_damage.remove(REPAINT); self.fragment.restyle_damage.remove(REPAINT);
if opts::get().validate_display_list_geometry {
self.base.validate_display_list_geometry();
}
} }
fn repair_style(&mut self, new_style: &Arc<ComputedValues>) { fn repair_style(&mut self, new_style: &Arc<ComputedValues>) {
@ -3036,3 +3037,12 @@ impl ISizeAndMarginsComputer for InlineBlockReplaced {
MaybeAuto::Specified(fragment.content_inline_size()) MaybeAuto::Specified(fragment.content_inline_size())
} }
} }
/// A stacking context, a pseudo-stacking context, or a non-stacking context.
#[derive(Copy, Clone, PartialEq)]
pub enum BlockStackingContextType {
NonstackingContext,
PseudoStackingContext,
StackingContext,
}

View file

@ -12,13 +12,13 @@
use app_units::{Au, AU_PER_PX}; use app_units::{Au, AU_PER_PX};
use azure::azure_hl::Color; use azure::azure_hl::Color;
use block::BlockFlow; use block::{BlockFlow, BlockStackingContextType};
use canvas_traits::{CanvasMsg, CanvasPixelData, CanvasData, FromLayoutMsg}; use canvas_traits::{CanvasMsg, CanvasPixelData, CanvasData, FromLayoutMsg};
use context::LayoutContext; 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};
@ -67,8 +67,7 @@ pub struct DisplayListBuildState<'a> {
} }
impl<'a> DisplayListBuildState<'a> { impl<'a> DisplayListBuildState<'a> {
pub fn new(layout_context: &'a LayoutContext, pub fn new(layout_context: &'a LayoutContext, stacking_context_id: StackingContextId)
stacking_context_id: StackingContextId)
-> DisplayListBuildState<'a> { -> DisplayListBuildState<'a> {
DisplayListBuildState { DisplayListBuildState {
layout_context: layout_context, layout_context: layout_context,
@ -87,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());
} }
@ -232,19 +225,17 @@ pub trait FragmentDisplayListBuilding {
clip: &ClippingRegion, clip: &ClippingRegion,
stacking_relative_display_port: &Rect<Au>); stacking_relative_display_port: &Rect<Au>);
/// Returns the appropriate clipping region for descendants of this fragment. /// Adjusts the clipping region for descendants of this fragment as appropriate.
fn clipping_region_for_children(&self, fn adjust_clipping_region_for_children(&self,
current_clip: &ClippingRegion, current_clip: &mut ClippingRegion,
stacking_relative_border_box: &Rect<Au>, stacking_relative_border_box: &Rect<Au>,
is_absolutely_positioned: bool) is_absolutely_positioned: bool);
-> ClippingRegion;
/// Calculates the clipping rectangle for a fragment, taking the `clip` property into account /// Adjusts the clipping rectangle for a fragment to take the `clip` property into account
/// per CSS 2.1 § 11.1.2. /// per CSS 2.1 § 11.1.2.
fn calculate_style_specified_clip(&self, fn adjust_clip_for_style(&self,
parent_clip: &ClippingRegion, parent_clip: &mut ClippingRegion,
stacking_relative_border_box: &Rect<Au>) stacking_relative_border_box: &Rect<Au>);
-> ClippingRegion;
/// Builds the display items necessary to paint the selection and/or caret for this fragment, /// Builds the display items necessary to paint the selection and/or caret for this fragment,
/// if any. /// if any.
@ -287,7 +278,7 @@ pub trait FragmentDisplayListBuilding {
base_flow: &BaseFlow, base_flow: &BaseFlow,
scroll_policy: ScrollPolicy, scroll_policy: ScrollPolicy,
mode: StackingContextCreationMode) mode: StackingContextCreationMode)
-> StackingContext; -> Box<StackingContext>;
} }
fn handle_overlapping_radii(size: &Size2D<Au>, radii: &BorderRadii<Au>) -> BorderRadii<Au> { fn handle_overlapping_radii(size: &Size2D<Au>, radii: &BorderRadii<Au>) -> BorderRadii<Au> {
@ -482,7 +473,8 @@ impl FragmentDisplayListBuilding for Fragment {
// Clip. // Clip.
// //
// TODO: Check the bounds to see if a clip item is actually required. // TODO: Check the bounds to see if a clip item is actually required.
let clip = clip.clone().intersect_rect(&bounds); let mut clip = clip.clone();
clip.intersect_rect(&bounds);
// Background image should be positioned on the padding box basis. // Background image should be positioned on the padding box basis.
let border = style.logical_border_width().to_physical(style.writing_mode); let border = style.logical_border_width().to_physical(style.writing_mode);
@ -581,7 +573,8 @@ impl FragmentDisplayListBuilding for Fragment {
clip: &ClippingRegion, clip: &ClippingRegion,
gradient: &LinearGradient, gradient: &LinearGradient,
style: &ComputedValues) { style: &ComputedValues) {
let clip = clip.clone().intersect_rect(absolute_bounds); let mut clip = clip.clone();
clip.intersect_rect(absolute_bounds);
// This is the distance between the center and the ending point; i.e. half of the distance // This is the distance between the center and the ending point; i.e. half of the distance
// between the starting point and the ending point. // between the starting point and the ending point.
@ -894,15 +887,14 @@ impl FragmentDisplayListBuilding for Fragment {
}), DisplayListSection::Content); }), DisplayListSection::Content);
} }
fn calculate_style_specified_clip(&self, fn adjust_clip_for_style(&self,
parent_clip: &ClippingRegion, parent_clip: &mut ClippingRegion,
stacking_relative_border_box: &Rect<Au>) stacking_relative_border_box: &Rect<Au>) {
-> ClippingRegion {
// Account for `clip` per CSS 2.1 § 11.1.2. // Account for `clip` per CSS 2.1 § 11.1.2.
let style_clip_rect = match (self.style().get_box().position, let style_clip_rect = match (self.style().get_box().position,
self.style().get_effects().clip.0) { self.style().get_effects().clip.0) {
(position::T::absolute, Some(style_clip_rect)) => style_clip_rect, (position::T::absolute, Some(style_clip_rect)) => style_clip_rect,
_ => return (*parent_clip).clone(), _ => return,
}; };
// FIXME(pcwalton, #2795): Get the real container size. // FIXME(pcwalton, #2795): Get the real container size.
@ -911,7 +903,7 @@ impl FragmentDisplayListBuilding for Fragment {
let right = style_clip_rect.right.unwrap_or(stacking_relative_border_box.size.width); let right = style_clip_rect.right.unwrap_or(stacking_relative_border_box.size.width);
let bottom = style_clip_rect.bottom.unwrap_or(stacking_relative_border_box.size.height); let bottom = style_clip_rect.bottom.unwrap_or(stacking_relative_border_box.size.height);
let clip_size = Size2D::new(right - clip_origin.x, bottom - clip_origin.y); let clip_size = Size2D::new(right - clip_origin.x, bottom - clip_origin.y);
(*parent_clip).clone().intersect_rect(&Rect::new(clip_origin, clip_size)) parent_clip.intersect_rect(&Rect::new(clip_origin, clip_size))
} }
fn build_display_items_for_selection_if_necessary(&self, fn build_display_items_for_selection_if_necessary(&self,
@ -996,7 +988,8 @@ impl FragmentDisplayListBuilding for Fragment {
// Calculate the clip rect. If there's nothing to render at all, don't even construct // Calculate the clip rect. If there's nothing to render at all, don't even construct
// display list items. // display list items.
let clip = self.calculate_style_specified_clip(clip, &stacking_relative_border_box); let mut clip = (*clip).clone();
self.adjust_clip_for_style(&mut clip, &stacking_relative_border_box);
if !clip.might_intersect_rect(&stacking_relative_border_box) { if !clip.might_intersect_rect(&stacking_relative_border_box) {
return; return;
} }
@ -1277,7 +1270,7 @@ impl FragmentDisplayListBuilding for Fragment {
base_flow: &BaseFlow, base_flow: &BaseFlow,
scroll_policy: ScrollPolicy, scroll_policy: ScrollPolicy,
mode: StackingContextCreationMode) mode: StackingContextCreationMode)
-> StackingContext { -> Box<StackingContext> {
let border_box = match mode { let border_box = match mode {
StackingContextCreationMode::InnerScrollWrapper => { StackingContextCreationMode::InnerScrollWrapper => {
Rect::new(Point2D::zero(), base_flow.overflow.scroll.size) Rect::new(Point2D::zero(), base_flow.overflow.scroll.size)
@ -1411,33 +1404,31 @@ impl FragmentDisplayListBuilding for Fragment {
_ => StackingContextType::Real, _ => StackingContextType::Real,
}; };
StackingContext::new(id, Box::new(StackingContext::new(id,
context_type, context_type,
&border_box, &border_box,
&overflow, &overflow,
self.effective_z_index(), self.effective_z_index(),
filters, filters,
self.style().get_effects().mix_blend_mode, self.style().get_effects().mix_blend_mode,
transform, transform,
perspective, perspective,
establishes_3d_context, establishes_3d_context,
scrolls_overflow_area, scrolls_overflow_area,
layer_info) layer_info))
} }
fn clipping_region_for_children(&self, fn adjust_clipping_region_for_children(&self,
current_clip: &ClippingRegion, current_clip: &mut ClippingRegion,
stacking_relative_border_box: &Rect<Au>, stacking_relative_border_box: &Rect<Au>,
is_absolutely_positioned: bool) is_absolutely_positioned: bool) {
-> ClippingRegion {
// Don't clip if we're text. // Don't clip if we're text.
if self.is_scanned_text_fragment() { if self.is_scanned_text_fragment() {
return (*current_clip).clone() return
} }
// Account for style-specified `clip`. // Account for style-specified `clip`.
let mut current_clip = self.calculate_style_specified_clip(current_clip, self.adjust_clip_for_style(current_clip, stacking_relative_border_box);
stacking_relative_border_box);
// Clip according to the values of `overflow-x` and `overflow-y`. // Clip according to the values of `overflow-x` and `overflow-y`.
// //
@ -1453,7 +1444,7 @@ impl FragmentDisplayListBuilding for Fragment {
let max_x = cmp::min(bounds.max_x(), stacking_relative_border_box.max_x()); let max_x = cmp::min(bounds.max_x(), stacking_relative_border_box.max_x());
bounds.origin.x = cmp::max(bounds.origin.x, stacking_relative_border_box.origin.x); bounds.origin.x = cmp::max(bounds.origin.x, stacking_relative_border_box.origin.x);
bounds.size.width = max_x - bounds.origin.x; bounds.size.width = max_x - bounds.origin.x;
current_clip = current_clip.intersect_rect(&bounds) current_clip.intersect_rect(&bounds)
} }
_ => {} _ => {}
} }
@ -1465,12 +1456,10 @@ impl FragmentDisplayListBuilding for Fragment {
let max_y = cmp::min(bounds.max_y(), stacking_relative_border_box.max_y()); let max_y = cmp::min(bounds.max_y(), stacking_relative_border_box.max_y());
bounds.origin.y = cmp::max(bounds.origin.y, stacking_relative_border_box.origin.y); bounds.origin.y = cmp::max(bounds.origin.y, stacking_relative_border_box.origin.y);
bounds.size.height = max_y - bounds.origin.y; bounds.size.height = max_y - bounds.origin.y;
current_clip = current_clip.intersect_rect(&bounds) current_clip.intersect_rect(&bounds)
} }
_ => {} _ => {}
} }
current_clip
} }
fn build_display_list_for_text_fragment(&self, fn build_display_list_for_text_fragment(&self,
@ -1600,7 +1589,7 @@ impl FragmentDisplayListBuilding for Fragment {
pub trait BlockFlowDisplayListBuilding { pub trait BlockFlowDisplayListBuilding {
fn collect_stacking_contexts_for_block(&mut self, fn collect_stacking_contexts_for_block(&mut self,
parent_id: StackingContextId, parent_id: StackingContextId,
contexts: &mut Vec<StackingContext>) contexts: &mut Vec<Box<StackingContext>>)
-> StackingContextId; -> StackingContextId;
fn build_display_list_for_block(&mut self, fn build_display_list_for_block(&mut self,
state: &mut DisplayListBuildState, state: &mut DisplayListBuildState,
@ -1610,10 +1599,10 @@ pub trait BlockFlowDisplayListBuilding {
impl BlockFlowDisplayListBuilding for BlockFlow { impl BlockFlowDisplayListBuilding for BlockFlow {
fn collect_stacking_contexts_for_block(&mut self, fn collect_stacking_contexts_for_block(&mut self,
parent_id: StackingContextId, parent_id: StackingContextId,
contexts: &mut Vec<StackingContext>) contexts: &mut Vec<Box<StackingContext>>)
-> StackingContextId { -> StackingContextId {
if !self.fragment.establishes_stacking_context() && let block_stacking_context_type = self.block_stacking_context_type();
!self.establishes_pseudo_stacking_context() { if block_stacking_context_type == BlockStackingContextType::NonstackingContext {
self.base.stacking_context_id = parent_id; self.base.stacking_context_id = parent_id;
self.base.collect_stacking_contexts_for_children(parent_id, contexts); self.base.collect_stacking_contexts_for_children(parent_id, contexts);
return parent_id; return parent_id;
@ -1625,8 +1614,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
self.base.stacking_context_id = stacking_context_id; self.base.stacking_context_id = stacking_context_id;
let inner_stacking_context_id = if self.has_scrolling_overflow() { let inner_stacking_context_id = if self.has_scrolling_overflow() {
StackingContextId::new_of_type(self.base.flow_id(), StackingContextId::new_of_type(self.base.flow_id(), self.fragment.fragment_type())
self.fragment.fragment_type())
} else { } else {
stacking_context_id stacking_context_id
}; };
@ -1635,7 +1623,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
self.base.collect_stacking_contexts_for_children(inner_stacking_context_id, self.base.collect_stacking_contexts_for_children(inner_stacking_context_id,
&mut child_contexts); &mut child_contexts);
if self.establishes_pseudo_stacking_context() { if block_stacking_context_type == BlockStackingContextType::PseudoStackingContext {
let creation_mode = if self.base.flags.contains(IS_ABSOLUTELY_POSITIONED) || let creation_mode = if self.base.flags.contains(IS_ABSOLUTELY_POSITIONED) ||
self.fragment.style.get_box().position != position::T::static_ { self.fragment.style.get_box().position != position::T::static_ {
StackingContextCreationMode::PseudoPositioned StackingContextCreationMode::PseudoPositioned
@ -1644,18 +1632,24 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
StackingContextCreationMode::PseudoFloat StackingContextCreationMode::PseudoFloat
}; };
let mut stacking_context = let stacking_context_index = contexts.len();
self.fragment.create_stacking_context(stacking_context_id, contexts.push(self.fragment.create_stacking_context(stacking_context_id,
&self.base, &self.base,
ScrollPolicy::Scrollable, ScrollPolicy::Scrollable,
creation_mode); creation_mode));
let (mut floating, mut positioned) = child_contexts.into_iter().partition(|context| {
context.context_type == StackingContextType::PseudoFloat
});
stacking_context.children.append(&mut floating); let mut floating = vec![];
contexts.push(stacking_context); for child_context in child_contexts.into_iter() {
contexts.append(&mut positioned); if child_context.context_type == StackingContextType::PseudoFloat {
// Floating.
floating.push(child_context)
} else {
// Positioned.
contexts.push(child_context)
}
}
contexts[stacking_context_index].children = floating;
return stacking_context_id; return stacking_context_id;
} }
@ -1671,7 +1665,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
&self.base, &self.base,
scroll_policy, scroll_policy,
StackingContextCreationMode::InnerScrollWrapper); StackingContextCreationMode::InnerScrollWrapper);
inner_stacking_context.children.append(&mut child_contexts); inner_stacking_context.children = child_contexts;
let mut outer_stacking_context = self.fragment.create_stacking_context( let mut outer_stacking_context = self.fragment.create_stacking_context(
stacking_context_id, stacking_context_id,
@ -1686,7 +1680,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
&self.base, &self.base,
scroll_policy, scroll_policy,
StackingContextCreationMode::Normal); StackingContextCreationMode::Normal);
stacking_context.children.append(&mut child_contexts); stacking_context.children = child_contexts;
stacking_context stacking_context
}; };
@ -1697,10 +1691,11 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
fn build_display_list_for_block(&mut self, fn build_display_list_for_block(&mut self,
state: &mut DisplayListBuildState, state: &mut DisplayListBuildState,
border_painting_mode: BorderPaintingMode) { border_painting_mode: BorderPaintingMode) {
let establishes_stacking_context = self.fragment.establishes_stacking_context();
let background_border_section = if self.base.flags.is_float() { let background_border_section = if self.base.flags.is_float() {
DisplayListSection::BackgroundAndBorders DisplayListSection::BackgroundAndBorders
} else if self.base.flags.contains(IS_ABSOLUTELY_POSITIONED) { } else if self.base.flags.contains(IS_ABSOLUTELY_POSITIONED) {
if self.fragment.establishes_stacking_context() { if establishes_stacking_context {
DisplayListSection::BackgroundAndBorders DisplayListSection::BackgroundAndBorders
} else { } else {
DisplayListSection::BlockBackgroundsAndBorders DisplayListSection::BlockBackgroundsAndBorders
@ -1710,10 +1705,14 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
}; };
// Add the box that starts the block context. // Add the box that starts the block context.
let clip = if self.fragment.establishes_stacking_context() { let translated_clip = if establishes_stacking_context {
self.base.clip.translate(&-self.base.stacking_relative_position) Some(self.base.clip.translate(&-self.base.stacking_relative_position))
} else { } else {
self.base.clip.clone() None
};
let clip = match translated_clip {
Some(ref translated_clip) => translated_clip,
None => &self.base.clip,
}; };
self.fragment self.fragment
@ -1727,14 +1726,9 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
.relative_containing_block_mode, .relative_containing_block_mode,
border_painting_mode, border_painting_mode,
background_border_section, background_border_section,
&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);
} }
} }
@ -1742,7 +1736,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
pub trait InlineFlowDisplayListBuilding { pub trait InlineFlowDisplayListBuilding {
fn collect_stacking_contexts_for_inline(&mut self, fn collect_stacking_contexts_for_inline(&mut self,
parent_id: StackingContextId, parent_id: StackingContextId,
contexts: &mut Vec<StackingContext>) contexts: &mut Vec<Box<StackingContext>>)
-> StackingContextId; -> StackingContextId;
fn build_display_list_for_inline_fragment_at_index(&mut self, fn build_display_list_for_inline_fragment_at_index(&mut self,
state: &mut DisplayListBuildState, state: &mut DisplayListBuildState,
@ -1753,7 +1747,7 @@ pub trait InlineFlowDisplayListBuilding {
impl InlineFlowDisplayListBuilding for InlineFlow { impl InlineFlowDisplayListBuilding for InlineFlow {
fn collect_stacking_contexts_for_inline(&mut self, fn collect_stacking_contexts_for_inline(&mut self,
parent_id: StackingContextId, parent_id: StackingContextId,
contexts: &mut Vec<StackingContext>) contexts: &mut Vec<Box<StackingContext>>)
-> StackingContextId { -> StackingContextId {
self.base.stacking_context_id = parent_id; self.base.stacking_context_id = parent_id;
@ -1799,22 +1793,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) {
@ -1847,10 +1825,6 @@ impl InlineFlowDisplayListBuilding for InlineFlow {
self.base.build_display_items_for_debugging_tint(state, self.base.build_display_items_for_debugging_tint(state,
self.fragments.fragments[0].node); self.fragments.fragments[0].node);
} }
if opts::get().validate_display_list_geometry {
self.base.validate_display_list_geometry();
}
} }
} }

View file

@ -31,7 +31,6 @@ use style::logical_geometry::LogicalSize;
use style::properties::ComputedValues; use style::properties::ComputedValues;
use style::properties::style_structs; use style::properties::style_structs;
use style::values::computed::LengthOrPercentageOrAuto; use style::values::computed::LengthOrPercentageOrAuto;
use util::opts;
// A mode describes which logical axis a flex axis is parallel with. // A mode describes which logical axis a flex axis is parallel with.
// The logical axises are inline and block, the flex axises are main and cross. // The logical axises are inline and block, the flex axises are main and cross.
@ -422,15 +421,11 @@ impl Flow for FlexFlow {
fn build_display_list(&mut self, state: &mut DisplayListBuildState) { fn build_display_list(&mut self, state: &mut DisplayListBuildState) {
self.build_display_list_for_flex(state); self.build_display_list_for_flex(state);
if opts::get().validate_display_list_geometry {
self.block_flow.base.validate_display_list_geometry();
}
} }
fn collect_stacking_contexts(&mut self, fn collect_stacking_contexts(&mut self,
parent_id: StackingContextId, parent_id: StackingContextId,
contexts: &mut Vec<StackingContext>) contexts: &mut Vec<Box<StackingContext>>)
-> StackingContextId { -> StackingContextId {
self.block_flow.collect_stacking_contexts(parent_id, contexts) self.block_flow.collect_stacking_contexts(parent_id, contexts)
} }

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;
@ -224,7 +224,7 @@ pub trait Flow: fmt::Debug + Sync + Send + 'static {
fn collect_stacking_contexts(&mut self, fn collect_stacking_contexts(&mut self,
_parent_id: StackingContextId, _parent_id: StackingContextId,
_: &mut Vec<StackingContext>) _: &mut Vec<Box<StackingContext>>)
-> StackingContextId; -> StackingContextId;
/// If this is a float, places it. The default implementation does nothing. /// If this is a float, places it. The default implementation does nothing.
@ -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(),
@ -1167,43 +1161,13 @@ impl BaseFlow {
p as usize p as usize
} }
/// Ensures that all display list items generated by this flow are within the flow's overflow
/// rect. This should only be used for debugging.
pub fn validate_display_list_geometry(&self) {
// FIXME(pcwalton, #2795): Get the real container size.
let container_size = Size2D::zero();
let position_with_overflow = self.position
.to_physical(self.writing_mode, container_size)
.union(&self.overflow.paint);
let bounds = Rect::new(self.stacking_relative_position, position_with_overflow.size);
let items = match self.display_list_building_result {
Some(ref items) => items,
None => return,
};
for item in items.iter() {
let base_item = item.item.base();
let paint_bounds = base_item.clip.clone().intersect_rect(&base_item.bounds);
if !paint_bounds.might_be_nonempty() {
continue;
}
if bounds.union(&paint_bounds.bounding_rect()) != bounds {
error!("DisplayList item {:?} outside of Flow overflow ({:?})",
item.item,
paint_bounds);
}
}
}
pub fn flow_id(&self) -> usize { pub fn flow_id(&self) -> usize {
return self as *const BaseFlow as usize; return self as *const BaseFlow as usize;
} }
pub fn collect_stacking_contexts_for_children(&mut self, pub fn collect_stacking_contexts_for_children(&mut self,
parent_id: StackingContextId, parent_id: StackingContextId,
contexts: &mut Vec<StackingContext>) { contexts: &mut Vec<Box<StackingContext>>) {
for kid in self.children.iter_mut() { for kid in self.children.iter_mut() {
kid.collect_stacking_contexts(parent_id, contexts); kid.collect_stacking_contexts(parent_id, contexts);
} }

View file

@ -1680,9 +1680,10 @@ impl Flow for InlineFlow {
CoordinateSystem::Parent); CoordinateSystem::Parent);
let stacking_relative_content_box = let stacking_relative_content_box =
fragment.stacking_relative_content_box(&stacking_relative_border_box); fragment.stacking_relative_content_box(&stacking_relative_border_box);
let clip = fragment.clipping_region_for_children(&self.base.clip, let mut clip = self.base.clip.clone();
&stacking_relative_border_box, fragment.adjust_clipping_region_for_children(&mut clip,
false); &stacking_relative_border_box,
false);
let is_positioned = fragment.is_positioned(); let is_positioned = fragment.is_positioned();
match fragment.specific { match fragment.specific {
SpecificFragmentInfo::InlineBlock(ref mut info) => { SpecificFragmentInfo::InlineBlock(ref mut info) => {
@ -1750,7 +1751,7 @@ impl Flow for InlineFlow {
fn collect_stacking_contexts(&mut self, fn collect_stacking_contexts(&mut self,
parent_id: StackingContextId, parent_id: StackingContextId,
contexts: &mut Vec<StackingContext>) contexts: &mut Vec<Box<StackingContext>>)
-> StackingContextId { -> StackingContextId {
self.collect_stacking_contexts_for_inline(parent_id, contexts) self.collect_stacking_contexts_for_inline(parent_id, contexts)
} }

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

@ -25,7 +25,6 @@ use style::computed_values::{list_style_type, position};
use style::logical_geometry::LogicalSize; use style::logical_geometry::LogicalSize;
use style::properties::ComputedValues; use style::properties::ComputedValues;
use text; use text;
use util::opts;
/// A block with the CSS `display` property equal to `list-item`. /// A block with the CSS `display` property equal to `list-item`.
#[derive(Debug)] #[derive(Debug)]
@ -144,14 +143,11 @@ impl Flow for ListItemFlow {
fn build_display_list(&mut self, state: &mut DisplayListBuildState) { fn build_display_list(&mut self, state: &mut DisplayListBuildState) {
self.build_display_list_for_list_item(state); self.build_display_list_for_list_item(state);
if opts::get().validate_display_list_geometry {
self.block_flow.base.validate_display_list_geometry();
}
} }
fn collect_stacking_contexts(&mut self, fn collect_stacking_contexts(&mut self,
parent_id: StackingContextId, parent_id: StackingContextId,
contexts: &mut Vec<StackingContext>) contexts: &mut Vec<Box<StackingContext>>)
-> StackingContextId { -> StackingContextId {
self.block_flow.collect_stacking_contexts(parent_id, contexts) self.block_flow.collect_stacking_contexts(parent_id, contexts)
} }

View file

@ -186,7 +186,7 @@ impl Flow for MulticolFlow {
fn collect_stacking_contexts(&mut self, fn collect_stacking_contexts(&mut self,
parent_id: StackingContextId, parent_id: StackingContextId,
contexts: &mut Vec<StackingContext>) contexts: &mut Vec<Box<StackingContext>>)
-> StackingContextId { -> StackingContextId {
self.block_flow.collect_stacking_contexts(parent_id, contexts) self.block_flow.collect_stacking_contexts(parent_id, contexts)
} }
@ -271,7 +271,7 @@ impl Flow for MulticolColumnFlow {
fn collect_stacking_contexts(&mut self, fn collect_stacking_contexts(&mut self,
parent_id: StackingContextId, parent_id: StackingContextId,
contexts: &mut Vec<StackingContext>) contexts: &mut Vec<Box<StackingContext>>)
-> StackingContextId { -> StackingContextId {
self.block_flow.collect_stacking_contexts(parent_id, contexts) self.block_flow.collect_stacking_contexts(parent_id, contexts)
} }

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

@ -467,7 +467,7 @@ impl Flow for TableFlow {
fn collect_stacking_contexts(&mut self, fn collect_stacking_contexts(&mut self,
parent_id: StackingContextId, parent_id: StackingContextId,
contexts: &mut Vec<StackingContext>) contexts: &mut Vec<Box<StackingContext>>)
-> StackingContextId { -> StackingContextId {
self.block_flow.collect_stacking_contexts(parent_id, contexts) self.block_flow.collect_stacking_contexts(parent_id, contexts)
} }

View file

@ -83,7 +83,7 @@ impl Flow for TableCaptionFlow {
fn collect_stacking_contexts(&mut self, fn collect_stacking_contexts(&mut self,
parent_id: StackingContextId, parent_id: StackingContextId,
contexts: &mut Vec<StackingContext>) contexts: &mut Vec<Box<StackingContext>>)
-> StackingContextId { -> StackingContextId {
self.block_flow.collect_stacking_contexts(parent_id, contexts) self.block_flow.collect_stacking_contexts(parent_id, contexts)
} }

View file

@ -193,7 +193,7 @@ impl Flow for TableCellFlow {
fn collect_stacking_contexts(&mut self, fn collect_stacking_contexts(&mut self,
parent_id: StackingContextId, parent_id: StackingContextId,
contexts: &mut Vec<StackingContext>) contexts: &mut Vec<Box<StackingContext>>)
-> StackingContextId { -> StackingContextId {
self.block_flow.collect_stacking_contexts(parent_id, contexts) self.block_flow.collect_stacking_contexts(parent_id, contexts)
} }

View file

@ -96,7 +96,7 @@ impl Flow for TableColGroupFlow {
fn collect_stacking_contexts(&mut self, fn collect_stacking_contexts(&mut self,
parent_id: StackingContextId, parent_id: StackingContextId,
_: &mut Vec<StackingContext>) _: &mut Vec<Box<StackingContext>>)
-> StackingContextId { -> StackingContextId {
parent_id parent_id
} }

View file

@ -435,7 +435,7 @@ impl Flow for TableRowFlow {
fn collect_stacking_contexts(&mut self, fn collect_stacking_contexts(&mut self,
parent_id: StackingContextId, parent_id: StackingContextId,
contexts: &mut Vec<StackingContext>) contexts: &mut Vec<Box<StackingContext>>)
-> StackingContextId { -> StackingContextId {
self.block_flow.collect_stacking_contexts(parent_id, contexts) self.block_flow.collect_stacking_contexts(parent_id, contexts)
} }

View file

@ -212,7 +212,7 @@ impl Flow for TableRowGroupFlow {
fn collect_stacking_contexts(&mut self, fn collect_stacking_contexts(&mut self,
parent_id: StackingContextId, parent_id: StackingContextId,
contexts: &mut Vec<StackingContext>) contexts: &mut Vec<Box<StackingContext>>)
-> StackingContextId { -> StackingContextId {
self.block_flow.collect_stacking_contexts(parent_id, contexts) self.block_flow.collect_stacking_contexts(parent_id, contexts)
} }

View file

@ -451,7 +451,7 @@ impl Flow for TableWrapperFlow {
fn collect_stacking_contexts(&mut self, fn collect_stacking_contexts(&mut self,
parent_id: StackingContextId, parent_id: StackingContextId,
contexts: &mut Vec<StackingContext>) contexts: &mut Vec<Box<StackingContext>>)
-> StackingContextId { -> StackingContextId {
self.block_flow.collect_stacking_contexts(parent_id, contexts) self.block_flow.collect_stacking_contexts(parent_id, contexts)
} }

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
} }
} }

View file

@ -163,9 +163,6 @@ pub struct Opts {
/// Emits notifications when there is a relayout. /// Emits notifications when there is a relayout.
pub relayout_event: bool, pub relayout_event: bool,
/// Whether to show an error when display list geometry escapes flow overflow regions.
pub validate_display_list_geometry: bool,
/// Whether Style Sharing Cache is used /// Whether Style Sharing Cache is used
pub disable_share_style_cache: bool, pub disable_share_style_cache: bool,
@ -254,9 +251,6 @@ pub struct DebugOptions {
/// Write layout trace to an external file for debugging. /// Write layout trace to an external file for debugging.
pub trace_layout: bool, pub trace_layout: bool,
/// Display an error when display list geometry escapes overflow region.
pub validate_display_list_geometry: bool,
/// Disable the style sharing cache. /// Disable the style sharing cache.
pub disable_share_style_cache: bool, pub disable_share_style_cache: bool,
@ -308,7 +302,6 @@ impl DebugOptions {
"show-parallel-layout" => debug_options.show_parallel_layout = true, "show-parallel-layout" => debug_options.show_parallel_layout = true,
"paint-flashing" => debug_options.paint_flashing = true, "paint-flashing" => debug_options.paint_flashing = true,
"trace-layout" => debug_options.trace_layout = true, "trace-layout" => debug_options.trace_layout = true,
"validate-display-list-geometry" => debug_options.validate_display_list_geometry = true,
"disable-share-style-cache" => debug_options.disable_share_style_cache = true, "disable-share-style-cache" => debug_options.disable_share_style_cache = true,
"convert-mouse-to-touch" => debug_options.convert_mouse_to_touch = true, "convert-mouse-to-touch" => debug_options.convert_mouse_to_touch = true,
"replace-surrogates" => debug_options.replace_surrogates = true, "replace-surrogates" => debug_options.replace_surrogates = true,
@ -351,8 +344,6 @@ pub fn print_debug_usage(app: &str) -> ! {
print_option("show-parallel-layout", "Mark which thread laid each flow out with colors."); print_option("show-parallel-layout", "Mark which thread laid each flow out with colors.");
print_option("paint-flashing", "Overlay repainted areas with a random color."); print_option("paint-flashing", "Overlay repainted areas with a random color.");
print_option("trace-layout", "Write layout trace to an external file for debugging."); print_option("trace-layout", "Write layout trace to an external file for debugging.");
print_option("validate-display-list-geometry",
"Display an error when display list geometry escapes overflow region.");
print_option("disable-share-style-cache", print_option("disable-share-style-cache",
"Disable the style sharing cache."); "Disable the style sharing cache.");
print_option("parallel-display-list-building", "Build display lists in parallel."); print_option("parallel-display-list-building", "Build display lists in parallel.");
@ -486,7 +477,6 @@ pub fn default_opts() -> Opts {
dump_display_list_optimized: false, dump_display_list_optimized: false,
dump_layer_tree: false, dump_layer_tree: false,
relayout_event: false, relayout_event: false,
validate_display_list_geometry: false,
profile_script_events: false, profile_script_events: false,
profile_heartbeats: false, profile_heartbeats: false,
disable_share_style_cache: false, disable_share_style_cache: false,
@ -727,7 +717,6 @@ pub fn from_cmdline_args(args: &[String]) -> ArgumentParsingResult {
dump_display_list_optimized: debug_options.dump_display_list_optimized, dump_display_list_optimized: debug_options.dump_display_list_optimized,
dump_layer_tree: debug_options.dump_layer_tree, dump_layer_tree: debug_options.dump_layer_tree,
relayout_event: debug_options.relayout_event, relayout_event: debug_options.relayout_event,
validate_display_list_geometry: debug_options.validate_display_list_geometry,
disable_share_style_cache: debug_options.disable_share_style_cache, disable_share_style_cache: debug_options.disable_share_style_cache,
convert_mouse_to_touch: debug_options.convert_mouse_to_touch, convert_mouse_to_touch: debug_options.convert_mouse_to_touch,
exit_after_load: opt_match.opt_present("x"), exit_after_load: opt_match.opt_present("x"),