From cd1c881830a4a94fe95d20467bd431e1cb56cc81 Mon Sep 17 00:00:00 2001 From: Martin Robinson Date: Wed, 2 Nov 2016 11:18:17 +0100 Subject: [PATCH] Fold some DisplayList methods into DisplayListBuildState This makes the API used to build display lists quite a bit simpler and reduces the amount of auxiliary data structures that need to be passed around. It is also important preparation work for separating scrolling areas from stacking contexts. --- components/gfx/display_list/mod.rs | 128 +++++++--------------- components/layout/display_list_builder.rs | 102 ++++++++++++++++- components/layout/sequential.rs | 20 ++-- components/layout_thread/lib.rs | 37 ++----- 4 files changed, 150 insertions(+), 137 deletions(-) diff --git a/components/gfx/display_list/mod.rs b/components/gfx/display_list/mod.rs index 36a09aff4a7..d4afcc60875 100644 --- a/components/gfx/display_list/mod.rs +++ b/components/gfx/display_list/mod.rs @@ -29,7 +29,6 @@ use range::Range; use std::cmp::{self, Ordering}; use std::collections::HashMap; use std::fmt; -use std::mem; use std::sync::Arc; use style::computed_values::{border_style, filter, image_rendering, mix_blend_mode}; use style_traits::cursor::Cursor; @@ -54,96 +53,6 @@ pub struct DisplayList { } impl DisplayList { - pub fn new(root_stacking_context: StackingContext, - all_items: Vec) - -> DisplayList { - let mut mapped_items = HashMap::new(); - for item in all_items.into_iter() { - let items = mapped_items.entry(item.stacking_context_id()).or_insert(Vec::new()); - items.push(item); - } - - let mut list = Vec::new(); - DisplayList::generate_display_list(&mut list, &mut mapped_items, root_stacking_context); - - DisplayList { - list: list, - } - } - - fn generate_display_list(list: &mut Vec, - mapped_items: &mut HashMap>, - mut stacking_context: StackingContext) { - let mut child_stacking_contexts = - mem::replace(&mut stacking_context.children, Vec::new()); - child_stacking_contexts.sort(); - let mut child_stacking_contexts = child_stacking_contexts.into_iter().peekable(); - - let mut child_items = mapped_items.remove(&stacking_context.id) - .unwrap_or(Vec::new()); - child_items.sort_by(|a, b| a.base().section.cmp(&b.base().section)); - child_items.reverse(); - - let stacking_context_id = stacking_context.id; - let real_stacking_context = stacking_context.context_type == StackingContextType::Real; - if real_stacking_context { - list.push(DisplayItem::PushStackingContext(Box::new(PushStackingContextItem { - base: BaseDisplayItem::empty(), - stacking_context: stacking_context, - }))); - } - - // Properly order display items that make up a stacking context. "Steps" here - // refer to the steps in CSS 2.1 Appendix E. - // Steps 1 and 2: Borders and background for the root. - while child_items.last().map_or(false, - |child| child.section() == DisplayListSection::BackgroundAndBorders) { - list.push(child_items.pop().unwrap()); - } - - // Step 3: Positioned descendants with negative z-indices. - while child_stacking_contexts.peek().map_or(false, |child| child.z_index < 0) { - let context = child_stacking_contexts.next().unwrap(); - DisplayList::generate_display_list(list, mapped_items, context); - } - - // Step 4: Block backgrounds and borders. - while child_items.last().map_or(false, - |child| child.section() == DisplayListSection::BlockBackgroundsAndBorders) { - list.push(child_items.pop().unwrap()); - } - - // Step 5: Floats. - while child_stacking_contexts.peek().map_or(false, - |child| child.context_type == StackingContextType::PseudoFloat) { - let context = child_stacking_contexts.next().unwrap(); - DisplayList::generate_display_list(list, mapped_items, context); - } - - // Step 6 & 7: Content and inlines that generate stacking contexts. - while child_items.last().map_or(false, - |child| child.section() == DisplayListSection::Content) { - list.push(child_items.pop().unwrap()); - } - - // Step 8 & 9: Positioned descendants with nonnegative, numeric z-indices. - for child in child_stacking_contexts { - DisplayList::generate_display_list(list, mapped_items, child); - } - - // Step 10: Outlines. - list.extend(child_items); - - if real_stacking_context { - list.push(DisplayItem::PopStackingContext(Box::new( - PopStackingContextItem { - base: BaseDisplayItem::empty(), - stacking_context_id: stacking_context_id, - } - ))); - } - } - // Return all nodes containing the point of interest, bottommost first, and // respecting the `pointer-events` CSS property. pub fn hit_test(&self, @@ -424,6 +333,22 @@ impl StackingContext { } } + #[inline] + pub fn root() -> StackingContext { + StackingContext::new(StackingContextId::new(0), + StackingContextType::Real, + &Rect::zero(), + &Rect::zero(), + 0, + filter::T::new(Vec::new()), + mix_blend_mode::T::normal, + Matrix4D::identity(), + Matrix4D::identity(), + true, + ScrollPolicy::Scrollable, + None) + } + pub fn add_child(&mut self, mut child: StackingContext) { child.update_overflow_for_all_children(); self.children.push(child); @@ -474,6 +399,27 @@ impl StackingContext { } print_tree.end_level(); } + + pub fn to_display_list_items(self) -> (DisplayItem, DisplayItem) { + let mut base_item = BaseDisplayItem::empty(); + base_item.stacking_context_id = self.id; + + let pop_item = DisplayItem::PopStackingContext(Box::new( + PopStackingContextItem { + base: base_item.clone(), + stacking_context_id: self.id, + } + )); + + let push_item = DisplayItem::PushStackingContext(Box::new( + PushStackingContextItem { + base: base_item, + stacking_context: self, + } + )); + + (push_item, pop_item) + } } impl Ord for StackingContext { diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs index bcf3f0f8f6c..b1c82680cc0 100644 --- a/components/layout/display_list_builder.rs +++ b/components/layout/display_list_builder.rs @@ -23,11 +23,11 @@ use fragment::{CoordinateSystem, Fragment, ImageFragmentInfo, ScannedTextFragmen use fragment::SpecificFragmentInfo; use gfx::display_list::{BLUR_INFLATION_FACTOR, BaseDisplayItem, BorderDisplayItem}; use gfx::display_list::{BorderRadii, BoxShadowClipMode, BoxShadowDisplayItem, ClippingRegion}; -use gfx::display_list::{DisplayItem, DisplayItemMetadata, DisplayListSection, GradientDisplayItem}; -use gfx::display_list::{GradientStop, IframeDisplayItem, ImageDisplayItem, WebGLDisplayItem}; +use gfx::display_list::{DisplayItem, DisplayItemMetadata, DisplayList, DisplayListSection}; +use gfx::display_list::{GradientDisplayItem, GradientStop, IframeDisplayItem, ImageDisplayItem}; use gfx::display_list::{LineDisplayItem, OpaqueNode}; use gfx::display_list::{SolidColorDisplayItem, StackingContext, StackingContextType}; -use gfx::display_list::{TextDisplayItem, TextOrientation, WebRenderImageInfo}; +use gfx::display_list::{TextDisplayItem, TextOrientation, WebGLDisplayItem, WebRenderImageInfo}; use gfx_traits::{ScrollPolicy, ScrollRootId, StackingContextId}; use inline::{FIRST_FRAGMENT_OF_ELEMENT, InlineFlow, LAST_FRAGMENT_OF_ELEMENT}; use ipc_channel::ipc; @@ -38,7 +38,9 @@ use net_traits::image_cache_thread::UsePlaceholder; use range::Range; use script_layout_interface::restyle_damage::REPAINT; use std::{cmp, f32}; +use std::collections::HashMap; use std::default::Default; +use std::mem; use std::sync::Arc; use style::computed_values::{background_attachment, background_clip, background_origin}; use style::computed_values::{background_repeat, background_size, border_style}; @@ -76,7 +78,8 @@ fn get_cyclic(arr: &[T], index: usize) -> &T { pub struct DisplayListBuildState<'a> { pub shared_layout_context: &'a SharedLayoutContext, - pub items: Vec, + pub root_stacking_context: StackingContext, + pub items: HashMap>, pub stacking_context_id_stack: Vec, pub scroll_root_id_stack: Vec, } @@ -87,14 +90,16 @@ impl<'a> DisplayListBuildState<'a> { -> DisplayListBuildState<'a> { DisplayListBuildState { shared_layout_context: shared_layout_context, - items: Vec::new(), + root_stacking_context: StackingContext::root(), + items: HashMap::new(), stacking_context_id_stack: vec!(stacking_context_id), scroll_root_id_stack: vec!(ScrollRootId::root()), } } fn add_display_item(&mut self, display_item: DisplayItem) { - self.items.push(display_item); + let items = self.items.entry(display_item.stacking_context_id()).or_insert(Vec::new()); + items.push(display_item); } pub fn stacking_context_id(&self) -> StackingContextId { @@ -139,6 +144,91 @@ impl<'a> DisplayListBuildState<'a> { section, self.stacking_context_id()) } + + pub fn to_display_list(mut self) -> DisplayList { + let mut list = Vec::new(); + let root_context = mem::replace(&mut self.root_stacking_context, StackingContext::root()); + + self.to_display_list_for_stacking_context(&mut list, root_context); + + DisplayList { + list: list, + } + } + + fn to_display_list_for_stacking_context(&mut self, + list: &mut Vec, + mut stacking_context: StackingContext) { + let mut child_items = self.items.remove(&stacking_context.id).unwrap_or(Vec::new()); + child_items.sort_by(|a, b| a.base().section.cmp(&b.base().section)); + child_items.reverse(); + + let mut child_stacking_contexts = + mem::replace(&mut stacking_context.children, Vec::new()); + child_stacking_contexts.sort(); + + let real_stacking_context = stacking_context.context_type == StackingContextType::Real; + if !real_stacking_context { + self.to_display_list_for_items(list, + child_items, + child_stacking_contexts); + return; + } + + let (push_item, pop_item) = stacking_context.to_display_list_items(); + list.push(push_item); + self.to_display_list_for_items(list, + child_items, + child_stacking_contexts); + list.push(pop_item); + } + + fn to_display_list_for_items(&mut self, + list: &mut Vec, + mut child_items: Vec, + child_stacking_contexts: Vec) { + // Properly order display items that make up a stacking context. "Steps" here + // refer to the steps in CSS 2.1 Appendix E. + // Steps 1 and 2: Borders and background for the root. + while child_items.last().map_or(false, + |child| child.section() == DisplayListSection::BackgroundAndBorders) { + list.push(child_items.pop().unwrap()); + } + + // Step 3: Positioned descendants with negative z-indices. + let mut child_stacking_contexts = child_stacking_contexts.into_iter().peekable(); + while child_stacking_contexts.peek().map_or(false, |child| child.z_index < 0) { + let context = child_stacking_contexts.next().unwrap(); + self.to_display_list_for_stacking_context(list, context); + } + + // Step 4: Block backgrounds and borders. + while child_items.last().map_or(false, + |child| child.section() == DisplayListSection::BlockBackgroundsAndBorders) { + list.push(child_items.pop().unwrap()); + } + + // Step 5: Floats. + while child_stacking_contexts.peek().map_or(false, + |child| child.context_type == StackingContextType::PseudoFloat) { + let context = child_stacking_contexts.next().unwrap(); + self.to_display_list_for_stacking_context(list, context); + } + + // Step 6 & 7: Content and inlines that generate stacking contexts. + while child_items.last().map_or(false, + |child| child.section() == DisplayListSection::Content) { + list.push(child_items.pop().unwrap()); + } + + // Step 8 & 9: Positioned descendants with nonnegative, numeric z-indices. + for child in child_stacking_contexts { + self.to_display_list_for_stacking_context(list, child); + } + + // Step 10: Outlines. + list.extend(child_items); + } } /// The logical width of an insertion point: at the moment, a one-pixel-wide line. diff --git a/components/layout/sequential.rs b/components/layout/sequential.rs index 51f2ac874a0..59819efe414 100644 --- a/components/layout/sequential.rs +++ b/components/layout/sequential.rs @@ -14,7 +14,6 @@ use flow::{PostorderFlowTraversal, PreorderFlowTraversal}; use flow::IS_ABSOLUTELY_POSITIONED; use fragment::FragmentBorderBoxIterator; use generated_content::ResolveGeneratedContent; -use gfx::display_list::{DisplayItem, StackingContext}; use gfx_traits::ScrollRootId; use script_layout_interface::restyle_damage::{REFLOW, STORE_OVERFLOW}; use style::context::StyleContext; @@ -75,17 +74,16 @@ pub fn traverse_flow_tree_preorder(root: &mut Flow, doit(root, assign_inline_sizes, assign_block_sizes); } -pub fn build_display_list_for_subtree(flow_root: &mut Flow, - root_stacking_context: &mut StackingContext, - shared_layout_context: &SharedLayoutContext) - -> Vec { - flow_root.collect_stacking_contexts(root_stacking_context, ScrollRootId::root()); - let mut build_display_list = BuildDisplayList { - state: DisplayListBuildState::new(shared_layout_context, - flow::base(flow_root).stacking_context_id), - }; +pub fn build_display_list_for_subtree<'a>(flow_root: &mut Flow, + shared_layout_context: &'a SharedLayoutContext) + -> DisplayListBuildState<'a> { + let mut state = DisplayListBuildState::new(shared_layout_context, + flow::base(flow_root).stacking_context_id); + flow_root.collect_stacking_contexts(&mut state.root_stacking_context, ScrollRootId::root()); + + let mut build_display_list = BuildDisplayList { state: state }; build_display_list.traverse(flow_root); - build_display_list.state.items + build_display_list.state } pub fn iterate_through_flow_tree_fragment_border_boxes(root: &mut Flow, diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs index 32231f1808b..3cb0522b42e 100644 --- a/components/layout_thread/lib.rs +++ b/components/layout_thread/lib.rs @@ -47,18 +47,16 @@ extern crate webrender_traits; use app_units::Au; use azure::azure_hl::Color; -use euclid::Matrix4D; use euclid::point::Point2D; use euclid::rect::Rect; use euclid::scale_factor::ScaleFactor; use euclid::size::Size2D; use fnv::FnvHasher; -use gfx::display_list::{ClippingRegion, DisplayList, OpaqueNode}; -use gfx::display_list::{StackingContext, StackingContextType, WebRenderImageInfo}; +use gfx::display_list::{ClippingRegion, OpaqueNode, WebRenderImageInfo}; use gfx::font; use gfx::font_cache_thread::FontCacheThread; use gfx::font_context; -use gfx_traits::{Epoch, FragmentType, ScrollPolicy, ScrollRootId, StackingContextId}; +use gfx_traits::{Epoch, FragmentType, ScrollRootId}; use heapsize::HeapSizeOf; use ipc_channel::ipc::{self, IpcReceiver, IpcSender}; use ipc_channel::router::ROUTER; @@ -107,7 +105,6 @@ use std::sync::{Arc, Mutex, MutexGuard}; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::mpsc::{Receiver, Sender, channel}; use style::animation::Animation; -use style::computed_values::{filter, mix_blend_mode}; use style::context::{LocalStyleContextCreationInfo, ReflowGoal, SharedStyleContext}; use style::dom::{TDocument, TElement, TNode}; use style::error_reporting::{ParseErrorReporter, StdoutErrorReporter}; @@ -910,24 +907,9 @@ impl LayoutThread { .unwrap_or(false); match (data.goal, display_list_needed) { (ReflowGoal::ForDisplay, _) | (ReflowGoal::ForScriptQuery, true) => { - let mut root_stacking_context = - StackingContext::new(StackingContextId::new(0), - StackingContextType::Real, - &Rect::zero(), - &Rect::zero(), - 0, - filter::T::new(Vec::new()), - mix_blend_mode::T::normal, - Matrix4D::identity(), - Matrix4D::identity(), - true, - ScrollPolicy::Scrollable, - None); - - let display_list_entries = - sequential::build_display_list_for_subtree(layout_root, - &mut root_stacking_context, - shared_layout_context); + let mut build_state = + sequential::build_display_list_for_subtree(layout_root, + shared_layout_context); debug!("Done building display list."); @@ -941,12 +923,9 @@ impl LayoutThread { }; let origin = Rect::new(Point2D::new(Au(0), Au(0)), root_size); - root_stacking_context.bounds = origin; - root_stacking_context.overflow = origin; - - rw_data.display_list = - Some(Arc::new(DisplayList::new(root_stacking_context, - display_list_entries))) + build_state.root_stacking_context.bounds = origin; + build_state.root_stacking_context.overflow = origin; + rw_data.display_list = Some(Arc::new(build_state.to_display_list())); } (ReflowGoal::ForScriptQuery, false) => {} }