diff options
-rw-r--r-- | components/layout_2020/display_list/gradient.rs | 8 | ||||
-rw-r--r-- | components/layout_2020/display_list/mod.rs | 140 | ||||
-rw-r--r-- | components/layout_2020/display_list/stacking_context.rs | 265 | ||||
-rw-r--r-- | components/layout_2020/flow/root.rs | 61 | ||||
-rw-r--r-- | components/layout_thread_2020/lib.rs | 30 |
5 files changed, 326 insertions, 178 deletions
diff --git a/components/layout_2020/display_list/gradient.rs b/components/layout_2020/display_list/gradient.rs index 09f5be610c2..bc057330023 100644 --- a/components/layout_2020/display_list/gradient.rs +++ b/components/layout_2020/display_list/gradient.rs @@ -144,9 +144,9 @@ pub(super) fn build_linear( let stops = fixup_stops(style, items, Length::new(gradient_line_length)); let linear_gradient = builder - .wr + .wr() .create_gradient(start_point, end_point, stops, extend_mode); - builder.wr.push_gradient( + builder.wr().push_gradient( &layer.common, layer.bounds, linear_gradient, @@ -244,9 +244,9 @@ pub(super) fn build_radial( let stops = fixup_stops(style, items, Length::new(gradient_line_length)); let radial_gradient = builder - .wr + .wr() .create_radial_gradient(center, radii, stops, extend_mode); - builder.wr.push_radial_gradient( + builder.wr().push_radial_gradient( &layer.common, layer.bounds, radial_gradient, diff --git a/components/layout_2020/display_list/mod.rs b/components/layout_2020/display_list/mod.rs index 79274277704..bd4a237fb59 100644 --- a/components/layout_2020/display_list/mod.rs +++ b/components/layout_2020/display_list/mod.rs @@ -10,6 +10,7 @@ use crate::fragments::{BoxFragment, Fragment, TextFragment}; use crate::geom::{PhysicalPoint, PhysicalRect}; use crate::replaced::IntrinsicSizes; use crate::style_ext::ComputedValuesExt; +use crate::FragmentTree; use embedder_traits::Cursor; use euclid::{Point2D, SideOffsets2D, Size2D}; use fnv::FnvHashMap; @@ -32,7 +33,9 @@ use webrender_api::{self as wr, units}; mod background; mod conversions; mod gradient; -pub mod stacking_context; +mod stacking_context; + +pub use stacking_context::*; #[derive(Clone, Copy)] pub struct WebRenderImageInfo { @@ -45,38 +48,99 @@ pub struct WebRenderImageInfo { type ItemTag = (u64, u16); type HitInfo = Option<ItemTag>; -pub struct DisplayListBuilder<'a> { - /// The current SpatialId and ClipId information for this `DisplayListBuilder`. - current_space_and_clip: wr::SpaceAndClipInfo, - - element_for_canvas_background: OpaqueNode, - pub context: &'a LayoutContext<'a>, +/// Where the information that's used to build display lists is stored. This +/// includes both a [wr::DisplayListBuilder] for building up WebRender-specific +/// display list information and a [CompositorDisplayListInfo] used to store +/// information used by the compositor, such as a compositor-side scroll tree. +pub struct DisplayList { + /// The [wr::DisplayListBuilder] used to collect display list items. pub wr: wr::DisplayListBuilder, - pub compositor_info: CompositorDisplayListInfo, - pub iframe_sizes: FnvHashMap<BrowsingContextId, Size2D<f32, CSSPixel>>, - /// Contentful paint, for the purpose of - /// https://w3c.github.io/paint-timing/#first-contentful-paint - /// (i.e. the display list contains items of type text, - /// image, non-white canvas or SVG). Used by metrics. - pub is_contentful: bool, + /// The information about the WebRender display list that the compositor + /// consumes. This curerntly contains the out-of-band hit testing information + /// data structure that the compositor uses to map hit tests to information + /// about the item hit. + pub compositor_info: CompositorDisplayListInfo, } -impl<'a> DisplayListBuilder<'a> { +impl DisplayList { + /// Create a new [DisplayList] given the dimensions of the layout and the WebRender + /// pipeline id. + /// + /// TODO(mrobinson): `_viewport_size` will eventually be used in the creation + /// of the compositor-side scroll tree. pub fn new( + _viewport_size: units::LayoutSize, + content_size: units::LayoutSize, pipeline_id: wr::PipelineId, - context: &'a LayoutContext, - fragment_tree: &crate::FragmentTree, ) -> Self { Self { - current_space_and_clip: wr::SpaceAndClipInfo::root_scroll(pipeline_id), + wr: wr::DisplayListBuilder::new(pipeline_id, content_size), + compositor_info: CompositorDisplayListInfo::default(), + } + } +} + +pub(crate) struct DisplayListBuilder<'a> { + /// The current [wr::SpatialId] for this [DisplayListBuilder]. This allows + /// only passing the builder instead passing the containing + /// [stacking_context::StackingContextFragment] as an argument to display + /// list building functions. + current_spatial_id: wr::SpatialId, + + /// The current [wr::ClipId] for this [DisplayListBuilder]. This allows + /// only passing the builder instead passing the containing + /// [stacking_context::StackingContextFragment] as an argument to display + /// list building functions. + current_clip_id: wr::ClipId, + + /// The [OpaqueNode] handle to the node used to paint the page background + /// if the background was a canvas. + element_for_canvas_background: OpaqueNode, + + /// A [LayoutContext] used to get information about the device pixel ratio + /// and get handles to WebRender images. + pub context: &'a LayoutContext<'a>, + + /// The [DisplayList] used to collect display list items and metadata. + pub display_list: &'a mut DisplayList, + + /// A recording of the sizes of iframes encountered when building this + /// display list. This information is forwarded to the layout thread for the + /// iframe so that its layout knows how large the initial containing block / + /// viewport is. + iframe_sizes: FnvHashMap<BrowsingContextId, Size2D<f32, CSSPixel>>, + + /// Contentful paint i.e. whether the display list contains items of type + /// text, image, non-white canvas or SVG). Used by metrics. + /// See https://w3c.github.io/paint-timing/#first-contentful-paint. + is_contentful: bool, +} + +impl DisplayList { + pub fn build<'a>( + &mut self, + context: &'a LayoutContext, + fragment_tree: &FragmentTree, + root_stacking_context: &StackingContext, + ) -> (FnvHashMap<BrowsingContextId, Size2D<f32, CSSPixel>>, bool) { + let mut builder = DisplayListBuilder { + current_spatial_id: wr::SpatialId::root_scroll_node(self.wr.pipeline_id), + current_clip_id: wr::ClipId::root(self.wr.pipeline_id), element_for_canvas_background: fragment_tree.canvas_background.from_element, is_contentful: false, context, - wr: wr::DisplayListBuilder::new(pipeline_id, fragment_tree.scrollable_overflow()), - compositor_info: CompositorDisplayListInfo::default(), + display_list: self, iframe_sizes: FnvHashMap::default(), - } + }; + fragment_tree.build_display_list(&mut builder, root_stacking_context); + (builder.iframe_sizes, builder.is_contentful) + } +} + +impl<'a> DisplayListBuilder<'a> { + fn wr(&mut self) -> &mut wr::DisplayListBuilder { + &mut self.display_list.wr } fn common_properties( @@ -89,8 +153,8 @@ impl<'a> DisplayListBuilder<'a> { // for fragments that paint their entire border rectangle. wr::CommonItemProperties { clip_rect, - spatial_id: self.current_space_and_clip.spatial_id, - clip_id: self.current_space_and_clip.clip_id, + spatial_id: self.current_spatial_id, + clip_id: self.current_clip_id, hit_info: None, flags: style.get_webrender_primitive_flags(), } @@ -109,7 +173,7 @@ impl<'a> DisplayListBuilder<'a> { return None; } - let hit_test_index = self.compositor_info.add_hit_test_info( + let hit_test_index = self.display_list.compositor_info.add_hit_test_info( tag?.node.0 as u64, Some(cursor(inherited_ui.cursor.keyword, auto_cursor)), ); @@ -143,7 +207,7 @@ impl Fragment { .translate(containing_block.origin.to_vector()); let common = builder.common_properties(rect.to_webrender(), &i.style); - builder.wr.push_image( + builder.wr().push_image( &common, rect.to_webrender(), image_rendering(i.style.get_inherited_box().image_rendering), @@ -169,7 +233,7 @@ impl Fragment { ); let common = builder.common_properties(rect.to_webrender(), &iframe.style); - builder.wr.push_iframe( + builder.wr().push_iframe( rect.to_webrender(), common.clip_rect, &wr::SpaceAndClipInfo { @@ -248,7 +312,7 @@ impl Fragment { } // Text. - builder.wr.push_text( + builder.wr().push_text( &common, rect.to_webrender(), &glyphs, @@ -287,7 +351,7 @@ impl Fragment { if text_decoration_style == ComputedTextDecorationStyle::MozNone { return; } - builder.wr.push_line( + builder.display_list.wr.push_line( &builder.common_properties(rect, &fragment.parent_style), &rect, wavy_line_thickness, @@ -448,7 +512,7 @@ impl<'a> BuilderForBoxFragment<'a> { if let Some(clip_id) = self.border_edge_clip(builder) { common.clip_id = clip_id } - builder.wr.push_hit_test(&common) + builder.wr().push_hit_test(&common) } } @@ -473,7 +537,7 @@ impl<'a> BuilderForBoxFragment<'a> { let layer_index = b.background_image.0.len() - 1; let (bounds, common) = background::painting_area(self, &source, builder, layer_index); builder - .wr + .wr() .push_rect(&common, *bounds, rgba(background_color)) } @@ -550,7 +614,7 @@ impl<'a> BuilderForBoxFragment<'a> { { let image_rendering = image_rendering(style.clone_image_rendering()); if layer.repeat { - builder.wr.push_repeating_image( + builder.wr().push_repeating_image( &layer.common, layer.bounds, layer.tile_size, @@ -561,7 +625,7 @@ impl<'a> BuilderForBoxFragment<'a> { wr::ColorF::WHITE, ) } else { - builder.wr.push_image( + builder.wr().push_image( &layer.common, layer.bounds, image_rendering, @@ -620,7 +684,7 @@ impl<'a> BuilderForBoxFragment<'a> { do_aa: true, }); builder - .wr + .wr() .push_border(&common, self.border_rect, widths, details) } @@ -655,7 +719,7 @@ impl<'a> BuilderForBoxFragment<'a> { do_aa: true, }); builder - .wr + .wr() .push_border(&common, outline_rect, widths, details) } } @@ -801,8 +865,12 @@ fn clip_for_radii( if radii.is_zero() { None } else { - Some(builder.wr.define_clip_rounded_rect( - &builder.current_space_and_clip, + let parent_space_and_clip = wr::SpaceAndClipInfo { + spatial_id: builder.current_spatial_id, + clip_id: builder.current_clip_id, + }; + Some(builder.wr().define_clip_rounded_rect( + &parent_space_and_clip, wr::ComplexClipRegion { rect, radii, diff --git a/components/layout_2020/display_list/stacking_context.rs b/components/layout_2020/display_list/stacking_context.rs index 7f15a530863..e88c08c6c1a 100644 --- a/components/layout_2020/display_list/stacking_context.rs +++ b/components/layout_2020/display_list/stacking_context.rs @@ -2,6 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +use super::DisplayList; use crate::cell::ArcRefCell; use crate::display_list::conversions::ToWebRender; use crate::display_list::DisplayListBuilder; @@ -9,6 +10,7 @@ use crate::fragment_tree::ContainingBlockManager; use crate::fragments::{AnonymousFragment, BoxFragment, Fragment}; use crate::geom::PhysicalRect; use crate::style_ext::ComputedValuesExt; +use crate::FragmentTree; use euclid::default::Rect; use servo_arc::Arc as ServoArc; use std::cmp::Ordering; @@ -24,30 +26,39 @@ use style::values::generics::box_::Perspective; use style::values::generics::transform; use style::values::specified::box_::DisplayOutside; use webrender_api as wr; -use webrender_api::units::{LayoutPoint, LayoutTransform, LayoutVector2D}; +use webrender_api::units::{LayoutPoint, LayoutRect, LayoutTransform, LayoutVector2D}; #[derive(Clone)] pub(crate) struct ContainingBlock { - /// The SpaceAndClipInfo that contains the children of the fragment that - /// established this containing block. - space_and_clip: wr::SpaceAndClipInfo, + /// The SpatialId of the spatial node that contains the children + /// of this containing block. + spatial_id: wr::SpatialId, + + /// The WebRender ClipId to use for this children of this containing + /// block. + clip_id: wr::ClipId, /// The physical rect of this containing block. rect: PhysicalRect<Length>, } impl ContainingBlock { - pub(crate) fn new(rect: &PhysicalRect<Length>, space_and_clip: wr::SpaceAndClipInfo) -> Self { + pub(crate) fn new( + rect: &PhysicalRect<Length>, + spatial_id: wr::SpatialId, + clip_id: wr::ClipId, + ) -> Self { ContainingBlock { - space_and_clip, + spatial_id, + clip_id, rect: *rect, } } pub(crate) fn new_replacing_rect(&self, rect: &PhysicalRect<Length>) -> Self { ContainingBlock { - space_and_clip: self.space_and_clip, rect: *rect, + ..*self } } } @@ -62,8 +73,89 @@ pub(crate) enum StackingContextSection { Outline, } +impl DisplayList { + pub fn build_stacking_context_tree(&mut self, fragment_tree: &FragmentTree) -> StackingContext { + let cb_for_non_fixed_descendants = ContainingBlock::new( + &fragment_tree.initial_containing_block, + wr::SpatialId::root_scroll_node(self.wr.pipeline_id), + wr::ClipId::root(self.wr.pipeline_id), + ); + let cb_for_fixed_descendants = ContainingBlock::new( + &fragment_tree.initial_containing_block, + wr::SpatialId::root_reference_frame(self.wr.pipeline_id), + wr::ClipId::root(self.wr.pipeline_id), + ); + + // We need to specify all three containing blocks here, because absolute + // descdendants of the root cannot share the containing block we specify + // for fixed descendants. In this case, they need to have the spatial + // id of the root scroll frame, whereas fixed descendants need the + // spatial id of the root reference frame so that they do not scroll with + // page content. + let containing_block_info = ContainingBlockInfo { + for_non_absolute_descendants: &cb_for_non_fixed_descendants, + for_absolute_descendants: Some(&cb_for_non_fixed_descendants), + for_absolute_and_fixed_descendants: &cb_for_fixed_descendants, + }; + + let mut root_stacking_context = StackingContext::create_root(&self.wr); + for fragment in &fragment_tree.root_fragments { + fragment.borrow().build_stacking_context_tree( + fragment, + self, + &containing_block_info, + &mut root_stacking_context, + StackingContextBuildMode::SkipHoisted, + ); + } + root_stacking_context.sort(); + root_stacking_context + } + + fn push_reference_frame( + &mut self, + origin: LayoutPoint, + parent_spatial_id: &wr::SpatialId, + transform_style: wr::TransformStyle, + transform: wr::PropertyBinding<LayoutTransform>, + kind: wr::ReferenceFrameKind, + ) -> wr::SpatialId { + self.wr + .push_reference_frame(origin, *parent_spatial_id, transform_style, transform, kind) + } + + fn pop_reference_frame(&mut self) { + self.wr.pop_reference_frame(); + } + + fn define_scroll_frame( + &mut self, + parent_spatial_id: &wr::SpatialId, + parent_clip_id: &wr::ClipId, + external_id: Option<wr::ExternalScrollId>, + content_rect: LayoutRect, + clip_rect: LayoutRect, + scroll_sensitivity: wr::ScrollSensitivity, + external_scroll_offset: LayoutVector2D, + ) -> (wr::SpatialId, wr::ClipId) { + let new_space_and_clip = self.wr.define_scroll_frame( + &wr::SpaceAndClipInfo { + spatial_id: *parent_spatial_id, + clip_id: *parent_clip_id, + }, + external_id, + content_rect, + clip_rect, + scroll_sensitivity, + external_scroll_offset, + ); + (new_space_and_clip.spatial_id, new_space_and_clip.clip_id) + } +} + pub(crate) struct StackingContextFragment { - space_and_clip: wr::SpaceAndClipInfo, + spatial_id: wr::SpatialId, + clip_id: wr::ClipId, section: StackingContextSection, containing_block: PhysicalRect<Length>, fragment: ArcRefCell<Fragment>, @@ -71,7 +163,8 @@ pub(crate) struct StackingContextFragment { impl StackingContextFragment { fn build_display_list(&self, builder: &mut DisplayListBuilder) { - builder.current_space_and_clip = self.space_and_clip; + builder.current_spatial_id = self.spatial_id; + builder.current_clip_id = self.clip_id; self.fragment .borrow() .build_display_list(builder, &self.containing_block, self.section); @@ -86,7 +179,7 @@ pub(crate) enum StackingContextType { PseudoAtomicInline, } -pub(crate) struct StackingContext { +pub struct StackingContext { /// The spatial id of this fragment. This is used to properly handle /// things like preserve-3d. spatial_id: wr::SpatialId, @@ -162,9 +255,9 @@ impl StackingContext { }); } - fn push_webrender_stacking_context_if_necessary<'a>( + fn push_webrender_stacking_context_if_necessary( &self, - builder: &'a mut DisplayListBuilder, + builder: &mut DisplayListBuilder, ) -> bool { let style = match self.initializing_fragment_style.as_ref() { Some(style) => style, @@ -202,7 +295,7 @@ impl StackingContext { // This will require additional tracking during layout // before we start collecting stacking contexts so that // information will be available when we reach this point. - builder.wr.push_stacking_context( + builder.wr().push_stacking_context( LayoutPoint::zero(), // origin self.spatial_id, style.get_webrender_primitive_flags(), @@ -251,7 +344,10 @@ impl StackingContext { if background_color.alpha > 0 { let common = builder.common_properties(painting_area, &style); let color = super::rgba(background_color); - builder.wr.push_rect(&common, painting_area, color) + builder + .display_list + .wr + .push_rect(&common, painting_area, color) } // `background-color` was comparatively easy, @@ -299,11 +395,10 @@ impl StackingContext { Some(fragment_tree.canvas_background.root_element), ); - // The root element may have a CSS transform, - // and we want the canvas’ background image to be transformed. - // To do so, take its `SpatialId` (but not its `ClipId`) - builder.current_space_and_clip.spatial_id = - first_stacking_context_fragment.space_and_clip.spatial_id; + // The root element may have a CSS transform, and we want the canvas’ + // background image to be transformed. To do so, take its `SpatialId` + // (but not its `ClipId`) + builder.current_spatial_id = first_stacking_context_fragment.spatial_id; // Now we need express the painting area rectangle in the local coordinate system, // which differs from the top-level coordinate system based on… @@ -393,7 +488,7 @@ impl StackingContext { } if pushed_context { - builder.wr.pop_stacking_context(); + builder.display_list.wr.pop_stacking_context(); } } } @@ -408,7 +503,7 @@ impl Fragment { pub(crate) fn build_stacking_context_tree( &self, fragment_ref: &ArcRefCell<Fragment>, - wr: &mut wr::DisplayListBuilder, + display_list: &mut DisplayList, containing_block_info: &ContainingBlockInfo, stacking_context: &mut StackingContext, mode: StackingContextBuildMode, @@ -432,7 +527,7 @@ impl Fragment { fragment.build_stacking_context_tree( fragment_ref, - wr, + display_list, containing_block, containing_block_info, stacking_context, @@ -447,7 +542,7 @@ impl Fragment { fragment_ref.borrow().build_stacking_context_tree( fragment_ref, - wr, + display_list, containing_block_info, stacking_context, StackingContextBuildMode::IncludeHoisted, @@ -455,7 +550,7 @@ impl Fragment { }, Fragment::Anonymous(fragment) => { fragment.build_stacking_context_tree( - wr, + display_list, containing_block, containing_block_info, stacking_context, @@ -464,7 +559,8 @@ impl Fragment { Fragment::Text(_) | Fragment::Image(_) | Fragment::IFrame(_) => { stacking_context.fragments.push(StackingContextFragment { section: StackingContextSection::Content, - space_and_clip: containing_block.space_and_clip, + spatial_id: containing_block.spatial_id, + clip_id: containing_block.clip_id, containing_block: containing_block.rect, fragment: fragment_ref.clone(), }); @@ -516,14 +612,14 @@ impl BoxFragment { fn build_stacking_context_tree( &self, fragment: &ArcRefCell<Fragment>, - wr: &mut wr::DisplayListBuilder, + display_list: &mut DisplayList, containing_block: &ContainingBlock, containing_block_info: &ContainingBlockInfo, parent_stacking_context: &mut StackingContext, ) { self.build_stacking_context_tree_maybe_creating_reference_frame( fragment, - wr, + display_list, containing_block, containing_block_info, parent_stacking_context, @@ -533,7 +629,7 @@ impl BoxFragment { fn build_stacking_context_tree_maybe_creating_reference_frame( &self, fragment: &ArcRefCell<Fragment>, - wr: &mut wr::DisplayListBuilder, + display_list: &mut DisplayList, containing_block: &ContainingBlock, containing_block_info: &ContainingBlockInfo, parent_stacking_context: &mut StackingContext, @@ -544,7 +640,7 @@ impl BoxFragment { None => { return self.build_stacking_context_tree_maybe_creating_stacking_context( fragment, - wr, + display_list, containing_block, containing_block_info, parent_stacking_context, @@ -552,9 +648,9 @@ impl BoxFragment { }, }; - let new_spatial_id = wr.push_reference_frame( + let new_spatial_id = display_list.push_reference_frame( reference_frame_data.origin.to_webrender(), - containing_block.space_and_clip.spatial_id, + &containing_block.spatial_id, self.style.get_box().transform_style.to_webrender(), wr::PropertyBinding::Value(reference_frame_data.transform), reference_frame_data.kind, @@ -576,29 +672,27 @@ impl BoxFragment { &containing_block .rect .translate(-reference_frame_data.origin.to_vector()), - wr::SpaceAndClipInfo { - spatial_id: new_spatial_id, - clip_id: containing_block.space_and_clip.clip_id, - }, + new_spatial_id, + containing_block.clip_id, ); let new_containing_block_info = containing_block_info.new_for_non_absolute_descendants(&adjusted_containing_block); self.build_stacking_context_tree_maybe_creating_stacking_context( fragment, - wr, + display_list, &adjusted_containing_block, &new_containing_block_info, parent_stacking_context, ); - wr.pop_reference_frame(); + display_list.pop_reference_frame(); } fn build_stacking_context_tree_maybe_creating_stacking_context( &self, fragment: &ArcRefCell<Fragment>, - wr: &mut wr::DisplayListBuilder, + display_list: &mut DisplayList, containing_block: &ContainingBlock, containing_block_info: &ContainingBlockInfo, parent_stacking_context: &mut StackingContext, @@ -608,7 +702,7 @@ impl BoxFragment { None => { self.build_stacking_context_tree_for_children( fragment, - wr, + display_list, containing_block, containing_block_info, parent_stacking_context, @@ -618,13 +712,13 @@ impl BoxFragment { }; let mut child_stacking_context = StackingContext::new( - containing_block.space_and_clip.spatial_id, + containing_block.spatial_id, self.style.clone(), context_type, ); self.build_stacking_context_tree_for_children( fragment, - wr, + display_list, containing_block, containing_block_info, &mut child_stacking_context, @@ -647,30 +741,36 @@ impl BoxFragment { .append(&mut stolen_children); } - fn build_stacking_context_tree_for_children<'a>( - &'a self, + fn build_stacking_context_tree_for_children( + &self, fragment: &ArcRefCell<Fragment>, - wr: &mut wr::DisplayListBuilder, + display_list: &mut DisplayList, containing_block: &ContainingBlock, containing_block_info: &ContainingBlockInfo, stacking_context: &mut StackingContext, ) { - let mut new_space_and_clip = containing_block.space_and_clip; - if let Some(new_clip_id) = - self.build_clip_frame_if_necessary(wr, new_space_and_clip, &containing_block.rect) - { - new_space_and_clip.clip_id = new_clip_id; + let mut new_spatial_id = containing_block.spatial_id; + let mut new_clip_id = containing_block.clip_id; + if let Some(clip_id) = self.build_clip_frame_if_necessary( + display_list, + &new_spatial_id, + &new_clip_id, + &containing_block.rect, + ) { + new_clip_id = clip_id; } stacking_context.fragments.push(StackingContextFragment { - space_and_clip: new_space_and_clip, + spatial_id: new_spatial_id, + clip_id: new_clip_id, section: self.get_stacking_context_section(), containing_block: containing_block.rect, fragment: fragment.clone(), }); if self.style.get_outline().outline_width.px() > 0.0 { stacking_context.fragments.push(StackingContextFragment { - space_and_clip: new_space_and_clip, + spatial_id: new_spatial_id, + clip_id: new_clip_id, section: StackingContextSection::Outline, containing_block: containing_block.rect, fragment: fragment.clone(), @@ -679,10 +779,14 @@ impl BoxFragment { // We want to build the scroll frame after the background and border, because // they shouldn't scroll with the rest of the box content. - if let Some(scroll_space_and_clip) = - self.build_scroll_frame_if_necessary(wr, new_space_and_clip, &containing_block.rect) - { - new_space_and_clip = scroll_space_and_clip; + if let Some((spatial_id, clip_id)) = self.build_scroll_frame_if_necessary( + display_list, + &new_spatial_id, + &new_clip_id, + &containing_block.rect, + ) { + new_spatial_id = spatial_id; + new_clip_id = clip_id; } let padding_rect = self @@ -694,14 +798,10 @@ impl BoxFragment { .to_physical(self.style.writing_mode, &containing_block.rect) .translate(containing_block.rect.origin.to_vector()); - let for_absolute_descendants = ContainingBlock { - rect: padding_rect, - space_and_clip: new_space_and_clip, - }; - let for_non_absolute_descendants = ContainingBlock { - rect: content_rect, - space_and_clip: new_space_and_clip, - }; + let for_absolute_descendants = + ContainingBlock::new(&padding_rect, new_spatial_id, new_clip_id); + let for_non_absolute_descendants = + ContainingBlock::new(&content_rect, new_spatial_id, new_clip_id); // Create a new `ContainingBlockInfo` for descendants depending on // whether or not this fragment establishes a containing block for @@ -729,7 +829,7 @@ impl BoxFragment { for child in &self.children { child.borrow().build_stacking_context_tree( child, - wr, + display_list, &new_containing_block_info, stacking_context, StackingContextBuildMode::SkipHoisted, @@ -739,8 +839,9 @@ impl BoxFragment { fn build_clip_frame_if_necessary( &self, - wr: &mut wr::DisplayListBuilder, - current_space_and_clip: wr::SpaceAndClipInfo, + display_list: &mut DisplayList, + parent_spatial_id: &wr::SpatialId, + parent_clip_id: &wr::ClipId, containing_block_rect: &PhysicalRect<Length>, ) -> Option<wr::ClipId> { let position = self.style.get_box().position; @@ -764,15 +865,22 @@ impl BoxFragment { .translate(containing_block_rect.origin.to_vector()) .to_webrender(); - Some(wr.define_clip_rect(¤t_space_and_clip, clip_rect)) + Some(display_list.wr.define_clip_rect( + &wr::SpaceAndClipInfo { + spatial_id: *parent_spatial_id, + clip_id: *parent_clip_id, + }, + clip_rect, + )) } - fn build_scroll_frame_if_necessary<'a>( + fn build_scroll_frame_if_necessary( &self, - wr: &mut wr::DisplayListBuilder, - current_space_and_clip: wr::SpaceAndClipInfo, + display_list: &mut DisplayList, + parent_spatial_id: &wr::SpatialId, + parent_clip_id: &wr::ClipId, containing_block_rect: &PhysicalRect<Length>, - ) -> Option<wr::SpaceAndClipInfo> { + ) -> Option<(wr::SpatialId, wr::ClipId)> { let overflow_x = self.style.get_box().overflow_x; let overflow_y = self.style.get_box().overflow_y; if overflow_x == ComputedOverflow::Visible && overflow_y == ComputedOverflow::Visible { @@ -780,7 +888,10 @@ impl BoxFragment { } let tag = self.base.tag?; - let external_id = wr::ExternalScrollId(tag.to_display_list_fragment_id(), wr.pipeline_id); + let external_id = wr::ExternalScrollId( + tag.to_display_list_fragment_id(), + display_list.wr.pipeline_id, + ); let sensitivity = if ComputedOverflow::Hidden == overflow_x && ComputedOverflow::Hidden == overflow_y { @@ -794,9 +905,11 @@ impl BoxFragment { .to_physical(self.style.writing_mode, &containing_block_rect) .translate(containing_block_rect.origin.to_vector()) .to_webrender(); + Some( - wr.define_scroll_frame( - ¤t_space_and_clip, + display_list.define_scroll_frame( + parent_spatial_id, + parent_clip_id, Some(external_id), self.scrollable_overflow(&containing_block_rect) .to_webrender(), @@ -937,7 +1050,7 @@ impl BoxFragment { impl AnonymousFragment { fn build_stacking_context_tree( &self, - wr: &mut wr::DisplayListBuilder, + display_list: &mut DisplayList, containing_block: &ContainingBlock, containing_block_info: &ContainingBlockInfo, stacking_context: &mut StackingContext, @@ -953,7 +1066,7 @@ impl AnonymousFragment { for child in &self.children { child.borrow().build_stacking_context_tree( child, - wr, + display_list, &new_containing_block_info, stacking_context, StackingContextBuildMode::SkipHoisted, diff --git a/components/layout_2020/flow/root.rs b/components/layout_2020/flow/root.rs index f44b0c88159..5006b65a48b 100644 --- a/components/layout_2020/flow/root.rs +++ b/components/layout_2020/flow/root.rs @@ -4,9 +4,7 @@ use crate::cell::ArcRefCell; use crate::context::LayoutContext; -use crate::display_list::stacking_context::{ - ContainingBlock, ContainingBlockInfo, StackingContext, StackingContextBuildMode, -}; +use crate::display_list::StackingContext; use crate::dom::{LayoutBox, NodeExt}; use crate::dom_traversal::{iter_child_nodes, Contents, NodeAndStyleInfo}; use crate::flexbox::FlexLevelBox; @@ -38,7 +36,6 @@ use style::dom::OpaqueNode; use style::properties::ComputedValues; use style::values::computed::Length; use style_traits::CSSPixel; -use webrender_api::{ClipId, SpaceAndClipInfo, SpatialId}; #[derive(Serialize)] pub struct BoxTree { @@ -60,7 +57,7 @@ pub struct FragmentTree { /// * The first fragment is generated by the root element. /// * There may be additional fragments generated by positioned boxes /// that have the initial containing block. - root_fragments: Vec<ArcRefCell<Fragment>>, + pub(crate) root_fragments: Vec<ArcRefCell<Fragment>>, /// The scrollable overflow rectangle for the entire tree /// https://drafts.csswg.org/css-overflow/#scrollable @@ -384,58 +381,18 @@ impl BoxTree { } impl FragmentTree { - pub fn build_display_list(&self, builder: &mut crate::display_list::DisplayListBuilder) { - let stacking_context = self.build_stacking_context_tree(builder); - + pub(crate) fn build_display_list( + &self, + builder: &mut crate::display_list::DisplayListBuilder, + root_stacking_context: &StackingContext, + ) { // Paint the canvas’ background (if any) before/under everything else - stacking_context.build_canvas_background_display_list( + root_stacking_context.build_canvas_background_display_list( builder, self, &self.initial_containing_block, ); - - stacking_context.build_display_list(builder); - } - - fn build_stacking_context_tree( - &self, - builder: &mut crate::display_list::DisplayListBuilder, - ) -> StackingContext { - let mut stacking_context = StackingContext::create_root(&builder.wr); - let pipeline_id = builder.wr.pipeline_id; - let cb_for_non_fixed_descendants = ContainingBlock::new( - &self.initial_containing_block, - SpaceAndClipInfo::root_scroll(pipeline_id), - ); - let cb_for_fixed_descendants = ContainingBlock::new( - &self.initial_containing_block, - SpaceAndClipInfo { - spatial_id: SpatialId::root_reference_frame(pipeline_id), - clip_id: ClipId::root(pipeline_id), - }, - ); - - for fragment in &self.root_fragments { - fragment.borrow().build_stacking_context_tree( - fragment, - &mut builder.wr, - // We need to specify all three containing blocks here, because absolute - // descdendants of the root cannot share the containing block we specify - // for fixed descendants. In this case, they need to have the spatial - // id of the root scroll frame, whereas fixed descendants need the - // spatial id of the root reference frame so that they do not scroll with - // page content. - &ContainingBlockInfo { - for_non_absolute_descendants: &cb_for_non_fixed_descendants, - for_absolute_descendants: Some(&cb_for_non_fixed_descendants), - for_absolute_and_fixed_descendants: &cb_for_fixed_descendants, - }, - &mut stacking_context, - StackingContextBuildMode::SkipHoisted, - ); - } - stacking_context.sort(); - stacking_context + root_stacking_context.build_display_list(builder); } pub fn print(&self) { diff --git a/components/layout_thread_2020/lib.rs b/components/layout_thread_2020/lib.rs index 90c6f4da952..60b00075ddb 100644 --- a/components/layout_thread_2020/lib.rs +++ b/components/layout_thread_2020/lib.rs @@ -29,7 +29,7 @@ use gfx_traits::{node_id_from_scroll_id, Epoch}; use ipc_channel::ipc::{self, IpcReceiver, IpcSender}; use ipc_channel::router::ROUTER; use layout::context::LayoutContext; -use layout::display_list::{DisplayListBuilder, WebRenderImageInfo}; +use layout::display_list::{DisplayList, WebRenderImageInfo}; use layout::dom::DOMLayoutData; use layout::layout_debug; use layout::query::{ @@ -1268,8 +1268,15 @@ impl LayoutThread { document.will_paint(); } - let mut display_list = - DisplayListBuilder::new(self.id.to_webrender(), context, &fragment_tree); + let viewport_size = webrender_api::units::LayoutSize::from_untyped(Size2D::new( + self.viewport_size.width.to_f32_px(), + self.viewport_size.height.to_f32_px(), + )); + let mut display_list = DisplayList::new( + viewport_size, + fragment_tree.scrollable_overflow(), + self.id.to_webrender(), + ); // `dump_serialized_display_list` doesn't actually print anything. It sets up // the display list for printing the serialized version when `finalize()` is called. @@ -1279,7 +1286,14 @@ impl LayoutThread { display_list.wr.dump_serialized_display_list(); } - fragment_tree.build_display_list(&mut display_list); + // Build the root stacking context. This turns the `FragmentTree` into a + // tree of fragments in CSS painting order and also creates all + // applicable spatial and clip nodes. + let root_stacking_context = display_list.build_stacking_context_tree(&fragment_tree); + + // Build the rest of the display list which inclues all of the WebRender primitives. + let (iframe_sizes, is_contentful) = + display_list.build(context, &fragment_tree, &root_stacking_context); if self.debug.dump_flow_tree { fragment_tree.print(); @@ -1294,12 +1308,8 @@ impl LayoutThread { // sending the display list to WebRender in order to set time related // Progressive Web Metrics. self.paint_time_metrics - .maybe_observe_paint_time(self, epoch, display_list.is_contentful); + .maybe_observe_paint_time(self, epoch, is_contentful); - let viewport_size = webrender_api::units::LayoutSize::from_untyped(Size2D::new( - self.viewport_size.width.to_f32_px(), - self.viewport_size.height.to_f32_px(), - )); self.webrender_api.send_display_list( epoch, viewport_size, @@ -1307,7 +1317,7 @@ impl LayoutThread { display_list.wr.finalize(), ); - self.update_iframe_sizes(display_list.iframe_sizes); + self.update_iframe_sizes(iframe_sizes); if self.debug.trace_layout { layout_debug::end_trace(self.generation.get()); |