aboutsummaryrefslogtreecommitdiffstats
path: root/components/layout/display_list
diff options
context:
space:
mode:
Diffstat (limited to 'components/layout/display_list')
-rw-r--r--components/layout/display_list/background.rs4
-rw-r--r--components/layout/display_list/clip.rs276
-rw-r--r--components/layout/display_list/clip_path.rs259
-rw-r--r--components/layout/display_list/mod.rs392
-rw-r--r--components/layout/display_list/stacking_context.rs441
5 files changed, 732 insertions, 640 deletions
diff --git a/components/layout/display_list/background.rs b/components/layout/display_list/background.rs
index f49ddfbe6ce..563bce28450 100644
--- a/components/layout/display_list/background.rs
+++ b/components/layout/display_list/background.rs
@@ -66,7 +66,7 @@ impl<'a> BackgroundPainter<'a> {
if &BackgroundAttachment::Fixed ==
get_cyclic(&background.background_attachment.0, layer_index)
{
- let viewport_size = builder.display_list.compositor_info.viewport_size;
+ let viewport_size = builder.compositor_info.viewport_size;
return units::LayoutRect::from_origin_and_size(Point2D::origin(), viewport_size);
}
@@ -121,7 +121,7 @@ impl<'a> BackgroundPainter<'a> {
if &BackgroundAttachment::Fixed ==
get_cyclic(&style.get_background().background_attachment.0, layer_index)
{
- common.spatial_id = builder.current_reference_frame_scroll_node_id.spatial_id;
+ common.spatial_id = builder.spatial_id(builder.current_reference_frame_scroll_node_id);
}
common
}
diff --git a/components/layout/display_list/clip.rs b/components/layout/display_list/clip.rs
new file mode 100644
index 00000000000..d5bd0f52b69
--- /dev/null
+++ b/components/layout/display_list/clip.rs
@@ -0,0 +1,276 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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 app_units::Au;
+use base::id::ScrollTreeNodeId;
+use style::values::computed::basic_shape::{BasicShape, ClipPath};
+use style::values::computed::length_percentage::NonNegativeLengthPercentage;
+use style::values::computed::position::Position;
+use style::values::generics::basic_shape::{GenericShapeRadius, ShapeBox, ShapeGeometryBox};
+use style::values::generics::position::GenericPositionOrAuto;
+use webrender_api::BorderRadius;
+use webrender_api::units::{LayoutRect, LayoutSideOffsets, LayoutSize};
+
+use super::{BuilderForBoxFragment, compute_margin_box_radius, normalize_radii};
+
+/// An identifier for a clip used during StackingContextTree construction. This is a simple index in
+/// a [`ClipStore`]s vector of clips.
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub(crate) struct ClipId(pub usize);
+
+impl ClipId {
+ /// Equivalent to [`ClipChainId::INVALID`]. This means "no clip."
+ pub(crate) const INVALID: ClipId = ClipId(usize::MAX);
+}
+
+/// All the information needed to create a clip on a WebRender display list. These are created at
+/// two times: during `StackingContextTree` creation and during WebRender display list construction.
+/// Only the former are stored in a [`ClipStore`].
+#[derive(Clone)]
+pub(crate) struct Clip {
+ pub id: ClipId,
+ pub radii: BorderRadius,
+ pub rect: LayoutRect,
+ pub parent_scroll_node_id: ScrollTreeNodeId,
+ pub parent_clip_id: ClipId,
+}
+
+/// A simple vector of [`Clip`] that is built during `StackingContextTree` construction.
+/// These are later turned into WebRender clips and clip chains during WebRender display
+/// list construction.
+#[derive(Clone, Default)]
+pub(crate) struct StackingContextTreeClipStore(pub Vec<Clip>);
+
+impl StackingContextTreeClipStore {
+ pub(crate) fn add(
+ &mut self,
+ radii: webrender_api::BorderRadius,
+ rect: LayoutRect,
+ parent_scroll_node_id: ScrollTreeNodeId,
+ parent_clip_id: ClipId,
+ ) -> ClipId {
+ let id = ClipId(self.0.len());
+ self.0.push(Clip {
+ id,
+ radii,
+ rect,
+ parent_scroll_node_id,
+ parent_clip_id,
+ });
+ id
+ }
+
+ pub(super) fn add_for_clip_path(
+ &mut self,
+ clip_path: ClipPath,
+ parent_scroll_node_id: &ScrollTreeNodeId,
+ parent_clip_chain_id: &ClipId,
+ fragment_builder: BuilderForBoxFragment,
+ ) -> Option<ClipId> {
+ let geometry_box = match clip_path {
+ ClipPath::Shape(_, ShapeGeometryBox::ShapeBox(shape_box)) => shape_box,
+ ClipPath::Shape(_, ShapeGeometryBox::ElementDependent) => ShapeBox::BorderBox,
+ ClipPath::Box(ShapeGeometryBox::ShapeBox(shape_box)) => shape_box,
+ ClipPath::Box(ShapeGeometryBox::ElementDependent) => ShapeBox::BorderBox,
+ _ => return None,
+ };
+ let layout_rect = match geometry_box {
+ ShapeBox::BorderBox => fragment_builder.border_rect,
+ ShapeBox::ContentBox => *fragment_builder.content_rect(),
+ ShapeBox::PaddingBox => *fragment_builder.padding_rect(),
+ ShapeBox::MarginBox => *fragment_builder.margin_rect(),
+ };
+ if let ClipPath::Shape(shape, _) = clip_path {
+ match *shape {
+ BasicShape::Circle(_) | BasicShape::Ellipse(_) | BasicShape::Rect(_) => self
+ .add_for_basic_shape(
+ *shape,
+ layout_rect,
+ parent_scroll_node_id,
+ parent_clip_chain_id,
+ ),
+ BasicShape::Polygon(_) | BasicShape::PathOrShape(_) => None,
+ }
+ } else {
+ Some(self.add(
+ match geometry_box {
+ ShapeBox::MarginBox => compute_margin_box_radius(
+ fragment_builder.border_radius,
+ layout_rect.size(),
+ fragment_builder.fragment,
+ ),
+ _ => fragment_builder.border_radius,
+ },
+ layout_rect,
+ *parent_scroll_node_id,
+ *parent_clip_chain_id,
+ ))
+ }
+ }
+
+ #[cfg_attr(
+ feature = "tracing",
+ tracing::instrument(
+ name = "StackingContextClipStore::add_for_basic_shape",
+ skip_all,
+ fields(servo_profiling = true),
+ level = "trace",
+ )
+ )]
+ fn add_for_basic_shape(
+ &mut self,
+ shape: BasicShape,
+ layout_box: LayoutRect,
+ parent_scroll_node_id: &ScrollTreeNodeId,
+ parent_clip_chain_id: &ClipId,
+ ) -> Option<ClipId> {
+ match shape {
+ BasicShape::Rect(rect) => {
+ let box_height = Au::from_f32_px(layout_box.height());
+ let box_width = Au::from_f32_px(layout_box.width());
+ let insets = LayoutSideOffsets::new(
+ rect.rect.0.to_used_value(box_height).to_f32_px(),
+ rect.rect.1.to_used_value(box_width).to_f32_px(),
+ rect.rect.2.to_used_value(box_height).to_f32_px(),
+ rect.rect.3.to_used_value(box_width).to_f32_px(),
+ );
+
+ // `inner_rect()` will cause an assertion failure if the insets are larger than the
+ // rectangle dimension.
+ let shape_rect = if insets.left + insets.right >= layout_box.width() ||
+ insets.top + insets.bottom > layout_box.height()
+ {
+ LayoutRect::from_origin_and_size(layout_box.min, LayoutSize::zero())
+ } else {
+ layout_box.to_rect().inner_rect(insets).to_box2d()
+ };
+
+ let corner = |corner: &style::values::computed::BorderCornerRadius| {
+ LayoutSize::new(
+ corner.0.width.0.to_used_value(box_width).to_f32_px(),
+ corner.0.height.0.to_used_value(box_height).to_f32_px(),
+ )
+ };
+ let mut radii = webrender_api::BorderRadius {
+ top_left: corner(&rect.round.top_left),
+ top_right: corner(&rect.round.top_right),
+ bottom_left: corner(&rect.round.bottom_left),
+ bottom_right: corner(&rect.round.bottom_right),
+ };
+ normalize_radii(&layout_box, &mut radii);
+ Some(self.add(
+ radii,
+ shape_rect,
+ *parent_scroll_node_id,
+ *parent_clip_chain_id,
+ ))
+ },
+ BasicShape::Circle(circle) => {
+ let center = match circle.position {
+ GenericPositionOrAuto::Position(position) => position,
+ GenericPositionOrAuto::Auto => Position::center(),
+ };
+ let anchor_x = center
+ .horizontal
+ .to_used_value(Au::from_f32_px(layout_box.width()));
+ let anchor_y = center
+ .vertical
+ .to_used_value(Au::from_f32_px(layout_box.height()));
+ let center = layout_box
+ .min
+ .add_size(&LayoutSize::new(anchor_x.to_f32_px(), anchor_y.to_f32_px()));
+
+ let horizontal = compute_shape_radius(
+ center.x,
+ &circle.radius,
+ layout_box.min.x,
+ layout_box.max.x,
+ );
+ let vertical = compute_shape_radius(
+ center.y,
+ &circle.radius,
+ layout_box.min.y,
+ layout_box.max.y,
+ );
+
+ // If the value is `Length` then both values should be the same at this point.
+ let radius = match circle.radius {
+ GenericShapeRadius::FarthestSide => horizontal.max(vertical),
+ GenericShapeRadius::ClosestSide => horizontal.min(vertical),
+ GenericShapeRadius::Length(_) => horizontal,
+ };
+ let radius = LayoutSize::new(radius, radius);
+ let mut radii = webrender_api::BorderRadius {
+ top_left: radius,
+ top_right: radius,
+ bottom_left: radius,
+ bottom_right: radius,
+ };
+ let start = center.add_size(&-radius);
+ let rect = LayoutRect::from_origin_and_size(start, radius * 2.);
+ normalize_radii(&layout_box, &mut radii);
+ Some(self.add(radii, rect, *parent_scroll_node_id, *parent_clip_chain_id))
+ },
+ BasicShape::Ellipse(ellipse) => {
+ let center = match ellipse.position {
+ GenericPositionOrAuto::Position(position) => position,
+ GenericPositionOrAuto::Auto => Position::center(),
+ };
+ let anchor_x = center
+ .horizontal
+ .to_used_value(Au::from_f32_px(layout_box.width()));
+ let anchor_y = center
+ .vertical
+ .to_used_value(Au::from_f32_px(layout_box.height()));
+ let center = layout_box
+ .min
+ .add_size(&LayoutSize::new(anchor_x.to_f32_px(), anchor_y.to_f32_px()));
+
+ let width = compute_shape_radius(
+ center.x,
+ &ellipse.semiaxis_x,
+ layout_box.min.x,
+ layout_box.max.x,
+ );
+ let height = compute_shape_radius(
+ center.y,
+ &ellipse.semiaxis_y,
+ layout_box.min.y,
+ layout_box.max.y,
+ );
+
+ let mut radii = webrender_api::BorderRadius {
+ top_left: LayoutSize::new(width, height),
+ top_right: LayoutSize::new(width, height),
+ bottom_left: LayoutSize::new(width, height),
+ bottom_right: LayoutSize::new(width, height),
+ };
+ let size = LayoutSize::new(width, height);
+ let start = center.add_size(&-size);
+ let rect = LayoutRect::from_origin_and_size(start, size * 2.);
+ normalize_radii(&rect, &mut radii);
+ Some(self.add(radii, rect, *parent_scroll_node_id, *parent_clip_chain_id))
+ },
+ _ => None,
+ }
+ }
+}
+
+fn compute_shape_radius(
+ center: f32,
+ radius: &GenericShapeRadius<NonNegativeLengthPercentage>,
+ min_edge: f32,
+ max_edge: f32,
+) -> f32 {
+ let distance_from_min_edge = (min_edge - center).abs();
+ let distance_from_max_edge = (max_edge - center).abs();
+ match radius {
+ GenericShapeRadius::FarthestSide => distance_from_min_edge.max(distance_from_max_edge),
+ GenericShapeRadius::ClosestSide => distance_from_min_edge.min(distance_from_max_edge),
+ GenericShapeRadius::Length(length) => length
+ .0
+ .to_used_value(Au::from_f32_px(max_edge - min_edge))
+ .to_f32_px(),
+ }
+}
diff --git a/components/layout/display_list/clip_path.rs b/components/layout/display_list/clip_path.rs
deleted file mode 100644
index 419d15c3572..00000000000
--- a/components/layout/display_list/clip_path.rs
+++ /dev/null
@@ -1,259 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * 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 app_units::Au;
-use base::id::ScrollTreeNodeId;
-use style::values::computed::basic_shape::{BasicShape, ClipPath};
-use style::values::computed::length_percentage::NonNegativeLengthPercentage;
-use style::values::computed::position::Position;
-use style::values::generics::basic_shape::{GenericShapeRadius, ShapeBox, ShapeGeometryBox};
-use style::values::generics::position::GenericPositionOrAuto;
-use webrender_api::ClipChainId;
-use webrender_api::units::{LayoutRect, LayoutSideOffsets, LayoutSize};
-
-use super::{BuilderForBoxFragment, DisplayList, compute_margin_box_radius, normalize_radii};
-
-pub(super) fn build_clip_path_clip_chain_if_necessary(
- clip_path: ClipPath,
- display_list: &mut DisplayList,
- parent_scroll_node_id: &ScrollTreeNodeId,
- parent_clip_chain_id: &ClipChainId,
- fragment_builder: BuilderForBoxFragment,
-) -> Option<ClipChainId> {
- let geometry_box = match clip_path {
- ClipPath::Shape(_, ShapeGeometryBox::ShapeBox(shape_box)) => shape_box,
- ClipPath::Shape(_, ShapeGeometryBox::ElementDependent) => ShapeBox::BorderBox,
- ClipPath::Box(ShapeGeometryBox::ShapeBox(shape_box)) => shape_box,
- ClipPath::Box(ShapeGeometryBox::ElementDependent) => ShapeBox::BorderBox,
- _ => return None,
- };
- let layout_rect = match geometry_box {
- ShapeBox::BorderBox => fragment_builder.border_rect,
- ShapeBox::ContentBox => *fragment_builder.content_rect(),
- ShapeBox::PaddingBox => *fragment_builder.padding_rect(),
- ShapeBox::MarginBox => *fragment_builder.margin_rect(),
- };
- if let ClipPath::Shape(shape, _) = clip_path {
- match *shape {
- BasicShape::Circle(_) | BasicShape::Ellipse(_) | BasicShape::Rect(_) => {
- build_simple_shape(
- *shape,
- layout_rect,
- parent_scroll_node_id,
- parent_clip_chain_id,
- display_list,
- )
- },
- BasicShape::Polygon(_) | BasicShape::PathOrShape(_) => None,
- }
- } else {
- Some(create_rect_clip_chain(
- match geometry_box {
- ShapeBox::MarginBox => compute_margin_box_radius(
- fragment_builder.border_radius,
- layout_rect.size(),
- fragment_builder.fragment,
- ),
- _ => fragment_builder.border_radius,
- },
- layout_rect,
- parent_scroll_node_id,
- parent_clip_chain_id,
- display_list,
- ))
- }
-}
-
-#[cfg_attr(
- feature = "tracing",
- tracing::instrument(
- name = "display_list::build_simple_shape",
- skip_all,
- fields(servo_profiling = true),
- level = "trace",
- )
-)]
-fn build_simple_shape(
- shape: BasicShape,
- layout_box: LayoutRect,
- parent_scroll_node_id: &ScrollTreeNodeId,
- parent_clip_chain_id: &ClipChainId,
- display_list: &mut DisplayList,
-) -> Option<ClipChainId> {
- match shape {
- BasicShape::Rect(rect) => {
- let box_height = Au::from_f32_px(layout_box.height());
- let box_width = Au::from_f32_px(layout_box.width());
- let insets = LayoutSideOffsets::new(
- rect.rect.0.to_used_value(box_height).to_f32_px(),
- rect.rect.1.to_used_value(box_width).to_f32_px(),
- rect.rect.2.to_used_value(box_height).to_f32_px(),
- rect.rect.3.to_used_value(box_width).to_f32_px(),
- );
-
- // `inner_rect()` will cause an assertion failure if the insets are larger than the
- // rectangle dimension.
- let shape_rect = if insets.left + insets.right >= layout_box.width() ||
- insets.top + insets.bottom > layout_box.height()
- {
- LayoutRect::from_origin_and_size(layout_box.min, LayoutSize::zero())
- } else {
- layout_box.to_rect().inner_rect(insets).to_box2d()
- };
-
- let corner = |corner: &style::values::computed::BorderCornerRadius| {
- LayoutSize::new(
- corner.0.width.0.to_used_value(box_width).to_f32_px(),
- corner.0.height.0.to_used_value(box_height).to_f32_px(),
- )
- };
- let mut radii = webrender_api::BorderRadius {
- top_left: corner(&rect.round.top_left),
- top_right: corner(&rect.round.top_right),
- bottom_left: corner(&rect.round.bottom_left),
- bottom_right: corner(&rect.round.bottom_right),
- };
- normalize_radii(&layout_box, &mut radii);
- Some(create_rect_clip_chain(
- radii,
- shape_rect,
- parent_scroll_node_id,
- parent_clip_chain_id,
- display_list,
- ))
- },
- BasicShape::Circle(circle) => {
- let center = match circle.position {
- GenericPositionOrAuto::Position(position) => position,
- GenericPositionOrAuto::Auto => Position::center(),
- };
- let anchor_x = center
- .horizontal
- .to_used_value(Au::from_f32_px(layout_box.width()));
- let anchor_y = center
- .vertical
- .to_used_value(Au::from_f32_px(layout_box.height()));
- let center = layout_box
- .min
- .add_size(&LayoutSize::new(anchor_x.to_f32_px(), anchor_y.to_f32_px()));
-
- let horizontal =
- compute_shape_radius(center.x, &circle.radius, layout_box.min.x, layout_box.max.x);
- let vertical =
- compute_shape_radius(center.y, &circle.radius, layout_box.min.y, layout_box.max.y);
-
- // If the value is `Length` then both values should be the same at this point.
- let radius = match circle.radius {
- GenericShapeRadius::FarthestSide => horizontal.max(vertical),
- GenericShapeRadius::ClosestSide => horizontal.min(vertical),
- GenericShapeRadius::Length(_) => horizontal,
- };
- let radius = LayoutSize::new(radius, radius);
- let mut radii = webrender_api::BorderRadius {
- top_left: radius,
- top_right: radius,
- bottom_left: radius,
- bottom_right: radius,
- };
- let start = center.add_size(&-radius);
- let rect = LayoutRect::from_origin_and_size(start, radius * 2.);
- normalize_radii(&layout_box, &mut radii);
- Some(create_rect_clip_chain(
- radii,
- rect,
- parent_scroll_node_id,
- parent_clip_chain_id,
- display_list,
- ))
- },
- BasicShape::Ellipse(ellipse) => {
- let center = match ellipse.position {
- GenericPositionOrAuto::Position(position) => position,
- GenericPositionOrAuto::Auto => Position::center(),
- };
- let anchor_x = center
- .horizontal
- .to_used_value(Au::from_f32_px(layout_box.width()));
- let anchor_y = center
- .vertical
- .to_used_value(Au::from_f32_px(layout_box.height()));
- let center = layout_box
- .min
- .add_size(&LayoutSize::new(anchor_x.to_f32_px(), anchor_y.to_f32_px()));
-
- let width = compute_shape_radius(
- center.x,
- &ellipse.semiaxis_x,
- layout_box.min.x,
- layout_box.max.x,
- );
- let height = compute_shape_radius(
- center.y,
- &ellipse.semiaxis_y,
- layout_box.min.y,
- layout_box.max.y,
- );
-
- let mut radii = webrender_api::BorderRadius {
- top_left: LayoutSize::new(width, height),
- top_right: LayoutSize::new(width, height),
- bottom_left: LayoutSize::new(width, height),
- bottom_right: LayoutSize::new(width, height),
- };
- let size = LayoutSize::new(width, height);
- let start = center.add_size(&-size);
- let rect = LayoutRect::from_origin_and_size(start, size * 2.);
- normalize_radii(&rect, &mut radii);
- Some(create_rect_clip_chain(
- radii,
- rect,
- parent_scroll_node_id,
- parent_clip_chain_id,
- display_list,
- ))
- },
- _ => None,
- }
-}
-
-fn compute_shape_radius(
- center: f32,
- radius: &GenericShapeRadius<NonNegativeLengthPercentage>,
- min_edge: f32,
- max_edge: f32,
-) -> f32 {
- let distance_from_min_edge = (min_edge - center).abs();
- let distance_from_max_edge = (max_edge - center).abs();
- match radius {
- GenericShapeRadius::FarthestSide => distance_from_min_edge.max(distance_from_max_edge),
- GenericShapeRadius::ClosestSide => distance_from_min_edge.min(distance_from_max_edge),
- GenericShapeRadius::Length(length) => length
- .0
- .to_used_value(Au::from_f32_px(max_edge - min_edge))
- .to_f32_px(),
- }
-}
-fn create_rect_clip_chain(
- radii: webrender_api::BorderRadius,
- rect: LayoutRect,
- parent_scroll_node_id: &ScrollTreeNodeId,
- parent_clip_chain_id: &ClipChainId,
- display_list: &mut DisplayList,
-) -> ClipChainId {
- let new_clip_id = if radii.is_zero() {
- display_list
- .wr
- .define_clip_rect(parent_scroll_node_id.spatial_id, rect)
- } else {
- display_list.wr.define_clip_rounded_rect(
- parent_scroll_node_id.spatial_id,
- webrender_api::ComplexClipRegion {
- rect,
- radii,
- mode: webrender_api::ClipMode::Clip,
- },
- )
- };
- display_list.define_clip_chain(*parent_clip_chain_id, [new_clip_id])
-}
diff --git a/components/layout/display_list/mod.rs b/components/layout/display_list/mod.rs
index f017642908d..95689cf1186 100644
--- a/components/layout/display_list/mod.rs
+++ b/components/layout/display_list/mod.rs
@@ -8,13 +8,15 @@ use std::sync::Arc;
use app_units::{AU_PER_PX, Au};
use base::WebRenderEpochToU16;
use base::id::ScrollTreeNodeId;
-use compositing_traits::display_list::{AxesScrollSensitivity, CompositorDisplayListInfo};
+use clip::{Clip, ClipId};
+use compositing_traits::display_list::{CompositorDisplayListInfo, SpatialTreeNodeInfo};
use embedder_traits::Cursor;
use euclid::{Point2D, SideOffsets2D, Size2D, UnknownUnit};
use fonts::GlyphStore;
use gradient::WebRenderGradient;
use range::Range as ServoRange;
use servo_arc::Arc as ServoArc;
+use servo_config::opts::DebugOptions;
use servo_geometry::MaxRect;
use style::Zero;
use style::color::{AbsoluteColor, ColorSpace};
@@ -35,8 +37,9 @@ use style::values::specified::ui::CursorKind;
use style_traits::CSSPixel;
use webrender_api::units::{DevicePixel, LayoutPixel, LayoutRect, LayoutSize};
use webrender_api::{
- self as wr, BorderDetails, BoxShadowClipMode, ClipChainId, CommonItemProperties,
- ImageRendering, NinePatchBorder, NinePatchBorderSource, SpatialId, units,
+ self as wr, BorderDetails, BoxShadowClipMode, BuiltDisplayList, ClipChainId, ClipMode,
+ CommonItemProperties, ComplexClipRegion, ImageRendering, NinePatchBorder,
+ NinePatchBorderSource, PropertyBinding, SpatialId, SpatialTreeItemKey, units,
};
use wr::units::LayoutVector2D;
@@ -55,7 +58,7 @@ use crate::replaced::NaturalSizes;
use crate::style_ext::{BorderStyleColor, ComputedValuesExt};
mod background;
-mod clip_path;
+mod clip;
mod conversions;
mod gradient;
mod stacking_context;
@@ -74,68 +77,6 @@ type ItemTag = (u64, u16);
type HitInfo = Option<ItemTag>;
const INSERTION_POINT_LOGICAL_WIDTH: Au = Au(AU_PER_PX);
-/// 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,
-
- /// 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,
-
- /// A count of the number of SpatialTree nodes pushed to the WebRender display
- /// list. This is merely to ensure that the currently-unused SpatialTreeItemKey
- /// produced for every SpatialTree node is unique.
- pub spatial_tree_count: u64,
-}
-
-impl DisplayList {
- /// Create a new [DisplayList] given the dimensions of the layout and the WebRender
- /// pipeline id.
- pub fn new(
- viewport_size: units::LayoutSize,
- content_size: units::LayoutSize,
- pipeline_id: wr::PipelineId,
- epoch: wr::Epoch,
- viewport_scroll_sensitivity: AxesScrollSensitivity,
- first_reflow: bool,
- ) -> Self {
- Self {
- wr: wr::DisplayListBuilder::new(pipeline_id),
- compositor_info: CompositorDisplayListInfo::new(
- viewport_size,
- content_size,
- pipeline_id,
- epoch,
- viewport_scroll_sensitivity,
- first_reflow,
- ),
- spatial_tree_count: 0,
- }
- }
-
- pub fn define_clip_chain<I>(&mut self, parent: ClipChainId, clips: I) -> ClipChainId
- where
- I: IntoIterator<Item = wr::ClipId>,
- I::IntoIter: ExactSizeIterator + Clone,
- {
- // WebRender has two different ways of expressing "no clip." ClipChainId::INVALID should be
- // used for primitives, but `None` is used for stacking contexts and clip chains. We convert
- // to the `Option<ClipChainId>` representation here. Just passing Some(ClipChainId::INVALID)
- // leads to a crash.
- let parent = match parent {
- ClipChainId::INVALID => None,
- parent => Some(parent),
- };
- self.wr.define_clip_chain(parent, clips)
- }
-}
-
pub(crate) struct DisplayListBuilder<'a> {
/// The current [ScrollTreeNodeId] for this [DisplayListBuilder]. This
/// allows only passing the builder instead passing the containing
@@ -148,18 +89,21 @@ pub(crate) struct DisplayListBuilder<'a> {
/// `background-attachment: fixed` need to not scroll while the rest of the fragment does.
current_reference_frame_scroll_node_id: ScrollTreeNodeId,
- /// The current [wr::ClipId] for this [DisplayListBuilder]. This allows
+ /// The current [`ClipId`] for this [DisplayListBuilder]. This allows
/// only passing the builder instead passing the containing
/// [stacking_context::StackingContextContent::Fragment] as an argument to display
/// list building functions.
- current_clip_chain_id: ClipChainId,
+ current_clip_id: ClipId,
/// 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,
+ /// The [`wr::DisplayListBuilder`] for this Servo [`DisplayListBuilder`].
+ pub webrender_display_list_builder: &'a mut wr::DisplayListBuilder,
+
+ /// The [`CompositorDisplayListInfo`] used to collect display list items and metadata.
+ pub compositor_info: &'a mut CompositorDisplayListInfo,
/// Data about the fragments that are highlighted by the inspector, if any.
///
@@ -171,6 +115,10 @@ pub(crate) struct DisplayListBuilder<'a> {
/// element inherits the `<body>`'s background to paint the page canvas background.
/// See <https://drafts.csswg.org/css-backgrounds/#body-background>.
paint_body_background: bool,
+
+ /// A mapping from [`ClipId`] To WebRender [`ClipChainId`] used when building this WebRender
+ /// display list.
+ clip_map: Vec<ClipChainId>,
}
struct InspectorHighlight {
@@ -207,45 +155,224 @@ impl InspectorHighlight {
}
}
-impl DisplayList {
- pub fn build(
- &mut self,
+impl DisplayListBuilder<'_> {
+ pub(crate) fn build(
context: &LayoutContext,
+ stacking_context_tree: &mut StackingContextTree,
fragment_tree: &FragmentTree,
- root_stacking_context: &StackingContext,
- ) {
+ debug: &DebugOptions,
+ ) -> BuiltDisplayList {
+ // Build the rest of the display list which inclues all of the WebRender primitives.
+ let compositor_info = &mut stacking_context_tree.compositor_info;
+ compositor_info.hit_test_info.clear();
+
+ let mut webrender_display_list_builder =
+ webrender_api::DisplayListBuilder::new(compositor_info.pipeline_id);
+ webrender_display_list_builder.begin();
+
+ // `dump_serialized_display_list` doesn't actually print anything. It sets up
+ // the display list for printing the serialized version when `finalize()` is called.
+ // We need to call this before adding any display items so that they are printed
+ // during `finalize()`.
+ if debug.dump_display_list {
+ webrender_display_list_builder.dump_serialized_display_list();
+ }
+
#[cfg(feature = "tracing")]
- let _span = tracing::trace_span!("display_list::build", servo_profiling = true).entered();
+ let _span =
+ tracing::trace_span!("DisplayListBuilder::build", servo_profiling = true).entered();
let mut builder = DisplayListBuilder {
- current_scroll_node_id: self.compositor_info.root_reference_frame_id,
- current_reference_frame_scroll_node_id: self.compositor_info.root_reference_frame_id,
- current_clip_chain_id: ClipChainId::INVALID,
+ current_scroll_node_id: compositor_info.root_reference_frame_id,
+ current_reference_frame_scroll_node_id: compositor_info.root_reference_frame_id,
+ current_clip_id: ClipId::INVALID,
context,
- display_list: self,
+ webrender_display_list_builder: &mut webrender_display_list_builder,
+ compositor_info,
inspector_highlight: context
.highlighted_dom_node
.map(InspectorHighlight::for_node),
paint_body_background: true,
+ clip_map: Default::default(),
};
- fragment_tree.build_display_list(&mut builder, root_stacking_context);
- if let Some(highlight) = builder
- .inspector_highlight
- .take()
- .and_then(|highlight| highlight.state)
- {
- builder.paint_dom_inspector_highlight(highlight);
+ builder.add_all_spatial_nodes();
+
+ for clip in stacking_context_tree.clip_store.0.iter() {
+ builder.add_clip_to_display_list(clip);
}
+
+ // Paint the canvas’ background (if any) before/under everything else
+ stacking_context_tree
+ .root_stacking_context
+ .build_canvas_background_display_list(&mut builder, fragment_tree);
+ stacking_context_tree
+ .root_stacking_context
+ .build_display_list(&mut builder);
+ builder.paint_dom_inspector_highlight();
+
+ webrender_display_list_builder.end().1
}
-}
-impl DisplayListBuilder<'_> {
fn wr(&mut self) -> &mut wr::DisplayListBuilder {
- &mut self.display_list.wr
+ self.webrender_display_list_builder
+ }
+
+ fn pipeline_id(&mut self) -> wr::PipelineId {
+ self.compositor_info.pipeline_id
}
fn mark_is_contentful(&mut self) {
- self.display_list.compositor_info.is_contentful = true;
+ self.compositor_info.is_contentful = true;
+ }
+
+ fn spatial_id(&self, id: ScrollTreeNodeId) -> SpatialId {
+ self.compositor_info.scroll_tree.webrender_id(&id)
+ }
+
+ fn clip_chain_id(&self, id: ClipId) -> ClipChainId {
+ match id {
+ ClipId::INVALID => ClipChainId::INVALID,
+ _ => *self
+ .clip_map
+ .get(id.0)
+ .expect("Should never try to get clip before adding it to WebRender display list"),
+ }
+ }
+
+ pub(crate) fn add_all_spatial_nodes(&mut self) {
+ // A count of the number of SpatialTree nodes pushed to the WebRender display
+ // list. This is merely to ensure that the currently-unused SpatialTreeItemKey
+ // produced for every SpatialTree node is unique.
+ let mut spatial_tree_count = 0;
+ let mut scroll_tree = std::mem::take(&mut self.compositor_info.scroll_tree);
+ let mut mapping = Vec::with_capacity(scroll_tree.nodes.len());
+
+ mapping.push(SpatialId::root_reference_frame(self.pipeline_id()));
+ mapping.push(SpatialId::root_scroll_node(self.pipeline_id()));
+
+ let pipeline_id = self.pipeline_id();
+ let pipeline_tag = ((pipeline_id.0 as u64) << 32) | pipeline_id.1 as u64;
+
+ for node in scroll_tree.nodes.iter().skip(2) {
+ let parent_scroll_node_id = node
+ .parent
+ .expect("Should have already added root reference frame");
+ let parent_spatial_node_id = mapping
+ .get(parent_scroll_node_id.index)
+ .expect("Should add spatial nodes to display list in order");
+
+ // Produce a new SpatialTreeItemKey. This is currently unused by WebRender,
+ // but has to be unique to the entire scene.
+ spatial_tree_count += 1;
+ let spatial_tree_item_key = SpatialTreeItemKey::new(pipeline_tag, spatial_tree_count);
+
+ mapping.push(match &node.info {
+ SpatialTreeNodeInfo::ReferenceFrame(info) => {
+ let spatial_id = self.wr().push_reference_frame(
+ info.origin,
+ *parent_spatial_node_id,
+ info.transform_style,
+ PropertyBinding::Value(info.transform),
+ info.kind,
+ spatial_tree_item_key,
+ );
+ self.wr().pop_reference_frame();
+ spatial_id
+ },
+ SpatialTreeNodeInfo::Scroll(info) => {
+ self.wr().define_scroll_frame(
+ *parent_spatial_node_id,
+ info.external_id,
+ info.content_rect,
+ info.clip_rect,
+ LayoutVector2D::zero(), /* external_scroll_offset */
+ 0, /* scroll_offset_generation */
+ wr::HasScrollLinkedEffect::No,
+ spatial_tree_item_key,
+ )
+ },
+ SpatialTreeNodeInfo::Sticky(info) => {
+ self.wr().define_sticky_frame(
+ *parent_spatial_node_id,
+ info.frame_rect,
+ info.margins,
+ info.vertical_offset_bounds,
+ info.horizontal_offset_bounds,
+ LayoutVector2D::zero(), /* previously_applied_offset */
+ spatial_tree_item_key,
+ None, /* transform */
+ )
+ },
+ });
+ }
+
+ scroll_tree.update_mapping(mapping);
+ self.compositor_info.scroll_tree = scroll_tree;
+ }
+
+ /// Add the given [`Clip`] to the WebRender display list and create a mapping from
+ /// its [`ClipId`] to a WebRender [`ClipChainId`]. This happens:
+ /// - When WebRender display list construction starts: All clips created during the
+ /// `StackingContextTree` construction are added in one batch. These clips are used
+ /// for things such as `overflow: scroll` elements.
+ /// - When a clip is added during WebRender display list construction for individual
+ /// items. In that case, this is called by [`Self::maybe_create_clip`].
+ pub(crate) fn add_clip_to_display_list(&mut self, clip: &Clip) -> ClipChainId {
+ assert_eq!(
+ clip.id.0,
+ self.clip_map.len(),
+ "Clips should be added in order"
+ );
+
+ let spatial_id = self.spatial_id(clip.parent_scroll_node_id);
+ let new_clip_id = if clip.radii.is_zero() {
+ self.wr().define_clip_rect(spatial_id, clip.rect)
+ } else {
+ self.wr().define_clip_rounded_rect(
+ spatial_id,
+ ComplexClipRegion {
+ rect: clip.rect,
+ radii: clip.radii,
+ mode: ClipMode::Clip,
+ },
+ )
+ };
+
+ // WebRender has two different ways of expressing "no clip." ClipChainId::INVALID should be
+ // used for primitives, but `None` is used for stacking contexts and clip chains. We convert
+ // to the `Option<ClipChainId>` representation here. Just passing Some(ClipChainId::INVALID)
+ // leads to a crash.
+ let parent_clip_chain_id = match self.clip_chain_id(clip.parent_clip_id) {
+ ClipChainId::INVALID => None,
+ parent => Some(parent),
+ };
+ let clip_chain_id = self
+ .wr()
+ .define_clip_chain(parent_clip_chain_id, [new_clip_id]);
+ self.clip_map.push(clip_chain_id);
+ clip_chain_id
+ }
+
+ /// Add a new clip to the WebRender display list being built. This only happens during
+ /// WebRender display list building and these clips should be added after all clips
+ /// from the `StackingContextTree` have already been processed.
+ fn maybe_create_clip(
+ &mut self,
+ radii: wr::BorderRadius,
+ rect: units::LayoutRect,
+ force_clip_creation: bool,
+ ) -> Option<ClipChainId> {
+ if radii.is_zero() && !force_clip_creation {
+ return None;
+ }
+
+ Some(self.add_clip_to_display_list(&Clip {
+ id: ClipId(self.clip_map.len()),
+ radii,
+ rect,
+ parent_scroll_node_id: self.current_scroll_node_id,
+ parent_clip_id: self.current_clip_id,
+ }))
}
fn common_properties(
@@ -258,8 +385,8 @@ impl DisplayListBuilder<'_> {
// for fragments that paint their entire border rectangle.
wr::CommonItemProperties {
clip_rect,
- spatial_id: self.current_scroll_node_id.spatial_id,
- clip_chain_id: self.current_clip_chain_id,
+ spatial_id: self.spatial_id(self.current_scroll_node_id),
+ clip_chain_id: self.clip_chain_id(self.current_clip_id),
flags: style.get_webrender_primitive_flags(),
}
}
@@ -277,19 +404,24 @@ impl DisplayListBuilder<'_> {
return None;
}
- let hit_test_index = self.display_list.compositor_info.add_hit_test_info(
+ let hit_test_index = self.compositor_info.add_hit_test_info(
tag?.node.0 as u64,
Some(cursor(inherited_ui.cursor.keyword, auto_cursor)),
self.current_scroll_node_id,
);
- Some((
- hit_test_index as u64,
- self.display_list.compositor_info.epoch.as_u16(),
- ))
+ Some((hit_test_index as u64, self.compositor_info.epoch.as_u16()))
}
/// Draw highlights around the node that is currently hovered in the devtools.
- fn paint_dom_inspector_highlight(&mut self, highlight: HighlightTraversalState) {
+ fn paint_dom_inspector_highlight(&mut self) {
+ let Some(highlight) = self
+ .inspector_highlight
+ .take()
+ .and_then(|highlight| highlight.state)
+ else {
+ return;
+ };
+
const CONTENT_BOX_HIGHLIGHT_COLOR: webrender_api::ColorF = webrender_api::ColorF {
r: 0.23,
g: 0.7,
@@ -327,8 +459,7 @@ impl DisplayListBuilder<'_> {
flags: wr::PrimitiveFlags::default(),
};
- self.display_list
- .wr
+ self.wr()
.push_rect(&properties, content_box, CONTENT_BOX_HIGHLIGHT_COLOR);
// Highlight margin, border and padding
@@ -442,12 +573,14 @@ impl Fragment {
is_hit_test_for_scrollable_overflow: bool,
is_collapsed_table_borders: bool,
) {
+ let spatial_id = builder.spatial_id(builder.current_scroll_node_id);
+ let clip_chain_id = builder.clip_chain_id(builder.current_clip_id);
if let Some(inspector_highlight) = &mut builder.inspector_highlight {
if self.tag() == Some(inspector_highlight.tag) {
inspector_highlight.register_fragment_of_highlighted_dom_node(
self,
- builder.current_scroll_node_id.spatial_id,
- builder.current_clip_chain_id,
+ spatial_id,
+ clip_chain_id,
containing_block,
);
}
@@ -574,8 +707,8 @@ impl Fragment {
None => return,
};
- let clip_chain_id = builder.current_clip_chain_id;
- let spatial_id = builder.current_scroll_node_id.spatial_id;
+ let clip_chain_id = builder.clip_chain_id(builder.current_clip_id);
+ let spatial_id = builder.spatial_id(builder.current_scroll_node_id);
builder.wr().push_hit_test(
rect.to_webrender(),
clip_chain_id,
@@ -765,8 +898,9 @@ impl Fragment {
if text_decoration_style == ComputedTextDecorationStyle::MozNone {
return;
}
- builder.display_list.wr.push_line(
- &builder.common_properties(rect, parent_style),
+ let common_properties = builder.common_properties(rect, parent_style);
+ builder.wr().push_line(
+ &common_properties,
&rect,
wavy_line_thickness,
wr::LineOrientation::Horizontal,
@@ -878,12 +1012,8 @@ impl<'a> BuilderForBoxFragment<'a> {
return Some(clip);
}
- let maybe_clip = create_clip_chain(
- self.border_radius,
- self.border_rect,
- builder,
- force_clip_creation,
- );
+ let maybe_clip =
+ builder.maybe_create_clip(self.border_radius, self.border_rect, force_clip_creation);
*self.border_edge_clip_chain_id.borrow_mut() = maybe_clip;
maybe_clip
}
@@ -899,7 +1029,7 @@ impl<'a> BuilderForBoxFragment<'a> {
let radii = inner_radii(self.border_radius, self.fragment.border.to_webrender());
let maybe_clip =
- create_clip_chain(radii, *self.padding_rect(), builder, force_clip_creation);
+ builder.maybe_create_clip(radii, *self.padding_rect(), force_clip_creation);
*self.padding_edge_clip_chain_id.borrow_mut() = maybe_clip;
maybe_clip
}
@@ -918,7 +1048,7 @@ impl<'a> BuilderForBoxFragment<'a> {
(self.fragment.border + self.fragment.padding).to_webrender(),
);
let maybe_clip =
- create_clip_chain(radii, *self.content_rect(), builder, force_clip_creation);
+ builder.maybe_create_clip(radii, *self.content_rect(), force_clip_creation);
*self.content_edge_clip_chain_id.borrow_mut() = maybe_clip;
maybe_clip
}
@@ -1553,38 +1683,6 @@ fn offset_radii(mut radii: wr::BorderRadius, offset: f32) -> wr::BorderRadius {
radii
}
-fn create_clip_chain(
- radii: wr::BorderRadius,
- rect: units::LayoutRect,
- builder: &mut DisplayListBuilder,
- force_clip_creation: bool,
-) -> Option<ClipChainId> {
- if radii.is_zero() && !force_clip_creation {
- return None;
- }
-
- let spatial_id = builder.current_scroll_node_id.spatial_id;
- let parent_clip_chain_id = builder.current_clip_chain_id;
- let new_clip_id = if radii.is_zero() {
- builder.wr().define_clip_rect(spatial_id, rect)
- } else {
- builder.wr().define_clip_rounded_rect(
- spatial_id,
- wr::ComplexClipRegion {
- rect,
- radii,
- mode: wr::ClipMode::Clip,
- },
- )
- };
-
- Some(
- builder
- .display_list
- .define_clip_chain(parent_clip_chain_id, [new_clip_id]),
- )
-}
-
/// Resolve the WebRender border-image outset area from the style values.
fn resolve_border_image_outset(
outset: BorderImageOutset,
diff --git a/components/layout/display_list/stacking_context.rs b/components/layout/display_list/stacking_context.rs
index 27fa73a680c..bcd882e3fcc 100644
--- a/components/layout/display_list/stacking_context.rs
+++ b/components/layout/display_list/stacking_context.rs
@@ -9,18 +9,19 @@ use std::mem;
use app_units::Au;
use base::id::ScrollTreeNodeId;
use base::print_tree::PrintTree;
-use compositing_traits::display_list::{AxesScrollSensitivity, ScrollableNodeInfo};
+use compositing_traits::display_list::{
+ AxesScrollSensitivity, CompositorDisplayListInfo, ReferenceFrameNodeInfo, ScrollableNodeInfo,
+ SpatialTreeNodeInfo, StickyNodeInfo,
+};
use euclid::SideOffsets2D;
use euclid::default::{Point2D, Rect, Size2D};
use log::warn;
-use servo_arc::Arc as ServoArc;
use servo_config::opts::DebugOptions;
use style::Zero;
use style::computed_values::float::T as ComputedFloat;
use style::computed_values::mix_blend_mode::T as ComputedMixBlendMode;
use style::computed_values::overflow_x::T as ComputedOverflow;
use style::computed_values::position::T as ComputedPosition;
-use style::properties::ComputedValues;
use style::values::computed::angle::Angle;
use style::values::computed::basic_shape::ClipPath;
use style::values::computed::{ClipRectOrAuto, Length};
@@ -29,11 +30,12 @@ use style::values::generics::transform::{self, GenericRotate, GenericScale, Gene
use style::values::specified::box_::DisplayOutside;
use webrender_api::units::{LayoutPoint, LayoutRect, LayoutTransform, LayoutVector2D};
use webrender_api::{self as wr, BorderRadius};
+use wr::StickyOffsetBounds;
use wr::units::{LayoutPixel, LayoutSize};
-use wr::{ClipChainId, SpatialTreeItemKey, StickyOffsetBounds};
-use super::DisplayList;
-use super::clip_path::build_clip_path_clip_chain_if_necessary;
+use super::ClipId;
+use super::clip::StackingContextTreeClipStore;
+use crate::ArcRefCell;
use crate::display_list::conversions::{FilterToWebRender, ToWebRender};
use crate::display_list::{BuilderForBoxFragment, DisplayListBuilder, offset_radii};
use crate::fragment_tree::{
@@ -54,9 +56,8 @@ pub(crate) struct ContainingBlock {
/// frame and sticky positioning isn't taken into account.
scroll_frame_size: Option<LayoutSize>,
- /// The WebRender ClipId to use for this children of this containing
- /// block.
- clip_chain_id: wr::ClipChainId,
+ /// The [`ClipId`] to use for the children of this containing block.
+ clip_id: ClipId,
/// The physical rect of this containing block.
rect: PhysicalRect<Au>,
@@ -67,12 +68,12 @@ impl ContainingBlock {
rect: PhysicalRect<Au>,
scroll_node_id: ScrollTreeNodeId,
scroll_frame_size: Option<LayoutSize>,
- clip_chain_id: wr::ClipChainId,
+ clip_id: ClipId,
) -> Self {
ContainingBlock {
scroll_node_id,
scroll_frame_size,
- clip_chain_id,
+ clip_id,
rect,
}
}
@@ -95,40 +96,56 @@ pub(crate) enum StackingContextSection {
Outline,
}
-impl DisplayList {
- /// Produce a new SpatialTreeItemKey. This is currently unused by WebRender,
- /// but has to be unique to the entire scene.
- fn get_next_spatial_tree_item_key(&mut self) -> SpatialTreeItemKey {
- self.spatial_tree_count += 1;
- let pipeline_tag = ((self.wr.pipeline_id.0 as u64) << 32) | self.wr.pipeline_id.1 as u64;
- SpatialTreeItemKey::new(pipeline_tag, self.spatial_tree_count)
- }
+pub(crate) struct StackingContextTree {
+ /// The root stacking context of this [`StackingContextTree`].
+ pub root_stacking_context: StackingContext,
- #[cfg_attr(
- feature = "tracing",
- tracing::instrument(
- name = "display_list::build_stacking_context_tree",
- skip_all,
- fields(servo_profiling = true),
- level = "trace",
- )
- )]
- pub fn build_stacking_context_tree(
- &mut self,
+ /// 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,
+
+ /// All of the clips collected for this [`StackingContextTree`]. These are added
+ /// for things like `overflow`. More clips may be created later during WebRender
+ /// display list construction, but they are never added here.
+ pub clip_store: StackingContextTreeClipStore,
+}
+
+impl StackingContextTree {
+ /// Create a new [DisplayList] given the dimensions of the layout and the WebRender
+ /// pipeline id.
+ pub fn new(
fragment_tree: &FragmentTree,
+ viewport_size: LayoutSize,
+ content_size: LayoutSize,
+ pipeline_id: wr::PipelineId,
+ viewport_scroll_sensitivity: AxesScrollSensitivity,
+ first_reflow: bool,
debug: &DebugOptions,
- ) -> StackingContext {
+ ) -> Self {
+ let compositor_info = CompositorDisplayListInfo::new(
+ viewport_size,
+ content_size,
+ pipeline_id,
+ // This epoch is set when the WebRender display list is built. For now use a dummy value.
+ wr::Epoch(0),
+ viewport_scroll_sensitivity,
+ first_reflow,
+ );
+
+ let root_scroll_node_id = compositor_info.root_scroll_node_id;
let cb_for_non_fixed_descendants = ContainingBlock::new(
fragment_tree.initial_containing_block,
- self.compositor_info.root_scroll_node_id,
- Some(self.compositor_info.viewport_size),
- ClipChainId::INVALID,
+ root_scroll_node_id,
+ Some(compositor_info.viewport_size),
+ ClipId::INVALID,
);
let cb_for_fixed_descendants = ContainingBlock::new(
fragment_tree.initial_containing_block,
- self.compositor_info.root_reference_frame_id,
+ compositor_info.root_reference_frame_id,
None,
- ClipChainId::INVALID,
+ ClipId::INVALID,
);
// We need to specify all three containing blocks here, because absolute
@@ -143,17 +160,31 @@ impl DisplayList {
for_absolute_and_fixed_descendants: &cb_for_fixed_descendants,
};
- let mut root_stacking_context = StackingContext::create_root(&self.wr, debug);
+ let mut stacking_context_tree = Self {
+ // This is just a temporary value that will be replaced once we have finished building the tree.
+ root_stacking_context: StackingContext::create_root(root_scroll_node_id, debug),
+ compositor_info,
+ clip_store: Default::default(),
+ };
+
+ let mut root_stacking_context = StackingContext::create_root(root_scroll_node_id, debug);
for fragment in &fragment_tree.root_fragments {
fragment.build_stacking_context_tree(
- self,
+ &mut stacking_context_tree,
&containing_block_info,
&mut root_stacking_context,
StackingContextBuildMode::SkipHoisted,
);
}
root_stacking_context.sort();
- root_stacking_context
+
+ if debug.dump_stacking_context_tree {
+ root_stacking_context.debug_print();
+ }
+
+ stacking_context_tree.root_stacking_context = root_stacking_context;
+
+ stacking_context_tree
}
fn push_reference_frame(
@@ -161,53 +192,20 @@ impl DisplayList {
origin: LayoutPoint,
parent_scroll_node_id: &ScrollTreeNodeId,
transform_style: wr::TransformStyle,
- transform: wr::PropertyBinding<LayoutTransform>,
+ transform: LayoutTransform,
kind: wr::ReferenceFrameKind,
) -> ScrollTreeNodeId {
- let spatial_tree_item_key = self.get_next_spatial_tree_item_key();
- let new_spatial_id = self.wr.push_reference_frame(
- origin,
- parent_scroll_node_id.spatial_id,
- transform_style,
- transform,
- kind,
- spatial_tree_item_key,
- );
self.compositor_info.scroll_tree.add_scroll_tree_node(
Some(parent_scroll_node_id),
- new_spatial_id,
- None,
+ SpatialTreeNodeInfo::ReferenceFrame(ReferenceFrameNodeInfo {
+ origin,
+ transform_style,
+ transform,
+ kind,
+ }),
)
}
- fn pop_reference_frame(&mut self) {
- self.wr.pop_reference_frame();
- }
-
- fn clip_overflow_frame(
- &mut self,
- parent_scroll_node_id: &ScrollTreeNodeId,
- parent_clip_id: &ClipChainId,
- clip_rect: LayoutRect,
- radii: wr::BorderRadius,
- ) -> ClipChainId {
- let new_clip_id = if radii.is_zero() {
- self.wr
- .define_clip_rect(parent_scroll_node_id.spatial_id, clip_rect)
- } else {
- self.wr.define_clip_rounded_rect(
- parent_scroll_node_id.spatial_id,
- webrender_api::ComplexClipRegion {
- rect: clip_rect,
- radii,
- mode: webrender_api::ClipMode::Clip,
- },
- )
- };
-
- self.define_clip_chain(*parent_clip_id, [new_clip_id])
- }
-
fn define_scroll_frame(
&mut self,
parent_scroll_node_id: &ScrollTreeNodeId,
@@ -216,25 +214,12 @@ impl DisplayList {
clip_rect: LayoutRect,
scroll_sensitivity: AxesScrollSensitivity,
) -> ScrollTreeNodeId {
- let spatial_tree_item_key = self.get_next_spatial_tree_item_key();
-
- let new_spatial_id = self.wr.define_scroll_frame(
- parent_scroll_node_id.spatial_id,
- external_id,
- content_rect,
- clip_rect,
- LayoutVector2D::zero(), /* external_scroll_offset */
- 0, /* scroll_offset_generation */
- wr::HasScrollLinkedEffect::No,
- spatial_tree_item_key,
- );
-
self.compositor_info.scroll_tree.add_scroll_tree_node(
Some(parent_scroll_node_id),
- new_spatial_id,
- Some(ScrollableNodeInfo {
+ SpatialTreeNodeInfo::Scroll(ScrollableNodeInfo {
external_id,
- scrollable_size: content_rect.size() - clip_rect.size(),
+ content_rect,
+ clip_rect,
scroll_sensitivity,
offset: LayoutVector2D::zero(),
}),
@@ -249,21 +234,14 @@ impl DisplayList {
vertical_offset_bounds: StickyOffsetBounds,
horizontal_offset_bounds: StickyOffsetBounds,
) -> ScrollTreeNodeId {
- let spatial_tree_item_key = self.get_next_spatial_tree_item_key();
- let new_spatial_id = self.wr.define_sticky_frame(
- parent_scroll_node_id.spatial_id,
- frame_rect,
- margins,
- vertical_offset_bounds,
- horizontal_offset_bounds,
- LayoutVector2D::zero(), /* previously_applied_offset */
- spatial_tree_item_key,
- None, /* transform */
- );
self.compositor_info.scroll_tree.add_scroll_tree_node(
Some(parent_scroll_node_id),
- new_spatial_id,
- None,
+ SpatialTreeNodeInfo::Sticky(StickyNodeInfo {
+ frame_rect,
+ margins,
+ vertical_offset_bounds,
+ horizontal_offset_bounds,
+ }),
)
}
}
@@ -277,7 +255,7 @@ pub(crate) enum StackingContextContent {
Fragment {
scroll_node_id: ScrollTreeNodeId,
reference_frame_scroll_node_id: ScrollTreeNodeId,
- clip_chain_id: wr::ClipChainId,
+ clip_id: ClipId,
section: StackingContextSection,
containing_block: PhysicalRect<Au>,
fragment: Fragment,
@@ -308,7 +286,7 @@ impl StackingContextContent {
Self::Fragment {
scroll_node_id,
reference_frame_scroll_node_id,
- clip_chain_id,
+ clip_id,
section,
containing_block,
fragment,
@@ -317,7 +295,7 @@ impl StackingContextContent {
} => {
builder.current_scroll_node_id = *scroll_node_id;
builder.current_reference_frame_scroll_node_id = *reference_frame_scroll_node_id;
- builder.current_clip_chain_id = *clip_chain_id;
+ builder.current_clip_id = *clip_id;
fragment.build_display_list(
builder,
containing_block,
@@ -349,16 +327,14 @@ pub(crate) enum StackingContextType {
pub struct StackingContext {
/// The spatial id of this fragment. This is used to properly handle
/// things like preserve-3d.
- spatial_id: wr::SpatialId,
+ scroll_tree_node_id: ScrollTreeNodeId,
/// The clip chain id of this stacking context if it has one. Used for filter clipping.
- clip_chain_id: Option<wr::ClipChainId>,
-
- /// The style of the fragment that established this stacking context.
- initializing_fragment_style: Option<ServoArc<ComputedValues>>,
+ clip_id: Option<ClipId>,
- /// The [`FragmentFlags`] of the [`Fragment`] that established this stacking context.
- initializing_fragment_flags: FragmentFlags,
+ /// The [`BoxFragment`] that established this stacking context. We store the fragment here
+ /// rather than just the style, so that incremental layout can automatically update the style.
+ initializing_fragment: Option<ArcRefCell<BoxFragment>>,
/// The type of this stacking context. Used for collecting and sorting.
context_type: StackingContextType,
@@ -415,25 +391,23 @@ pub enum DebugPrintField {
impl StackingContext {
fn create_descendant(
&self,
- spatial_id: wr::SpatialId,
- clip_chain_id: wr::ClipChainId,
- initializing_fragment_style: ServoArc<ComputedValues>,
- initializing_fragment_flags: FragmentFlags,
+ spatial_id: ScrollTreeNodeId,
+ clip_id: ClipId,
+ initializing_fragment: ArcRefCell<BoxFragment>,
context_type: StackingContextType,
) -> Self {
// WebRender has two different ways of expressing "no clip." ClipChainId::INVALID should be
// used for primitives, but `None` is used for stacking contexts and clip chains. We convert
- // to the `Option<ClipChainId>` representation here. Just passing Some(ClipChainId::INVALID)
+ // to the `Option<ClipId>` representation here. Just passing Some(ClipChainId::INVALID)
// leads to a crash.
- let clip_chain_id: Option<ClipChainId> = match clip_chain_id {
- ClipChainId::INVALID => None,
- clip_chain_id => Some(clip_chain_id),
+ let clip_id = match clip_id {
+ ClipId::INVALID => None,
+ clip_id => Some(clip_id),
};
Self {
- spatial_id,
- clip_chain_id,
- initializing_fragment_style: Some(initializing_fragment_style),
- initializing_fragment_flags,
+ scroll_tree_node_id: spatial_id,
+ clip_id,
+ initializing_fragment: Some(initializing_fragment),
context_type,
contents: vec![],
real_stacking_contexts_and_positioned_stacking_containers: vec![],
@@ -443,12 +417,11 @@ impl StackingContext {
}
}
- pub(crate) fn create_root(wr: &wr::DisplayListBuilder, debug: &DebugOptions) -> Self {
+ fn create_root(root_scroll_node_id: ScrollTreeNodeId, debug: &DebugOptions) -> Self {
Self {
- spatial_id: wr::SpaceAndClipInfo::root_scroll(wr.pipeline_id).spatial_id,
- clip_chain_id: None,
- initializing_fragment_style: None,
- initializing_fragment_flags: FragmentFlags::empty(),
+ scroll_tree_node_id: root_scroll_node_id,
+ clip_id: None,
+ initializing_fragment: None,
context_type: StackingContextType::RealStackingContext,
contents: vec![],
real_stacking_contexts_and_positioned_stacking_containers: vec![],
@@ -476,11 +449,10 @@ impl StackingContext {
}
fn z_index(&self) -> i32 {
- self.initializing_fragment_style
- .as_ref()
- .map_or(0, |style| {
- style.effective_z_index(self.initializing_fragment_flags)
- })
+ self.initializing_fragment.as_ref().map_or(0, |fragment| {
+ let fragment = fragment.borrow();
+ fragment.style.effective_z_index(fragment.base.flags)
+ })
}
pub(crate) fn sort(&mut self) {
@@ -519,13 +491,14 @@ impl StackingContext {
&self,
builder: &mut DisplayListBuilder,
) -> bool {
- let style = match self.initializing_fragment_style.as_ref() {
- Some(style) => style,
+ let fragment = match self.initializing_fragment.as_ref() {
+ Some(fragment) => fragment.borrow(),
None => return false,
};
// WebRender only uses the stacking context to apply certain effects. If we don't
// actually need to create a stacking context, just avoid creating one.
+ let style = &fragment.style;
let effects = style.get_effects();
if effects.filter.0.is_empty() &&
effects.opacity == 1.0 &&
@@ -557,11 +530,13 @@ 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.
+ let spatial_id = builder.spatial_id(self.scroll_tree_node_id);
+ let clip_chain_id = self.clip_id.map(|clip_id| builder.clip_chain_id(clip_id));
builder.wr().push_stacking_context(
LayoutPoint::zero(), // origin
- self.spatial_id,
+ spatial_id,
style.get_webrender_primitive_flags(),
- self.clip_chain_id,
+ clip_chain_id,
style.get_used_transform_style().to_webrender(),
effects.mix_blend_mode.to_webrender(),
&filters,
@@ -635,10 +610,7 @@ impl StackingContext {
if background_color.alpha > 0.0 {
let common = builder.common_properties(painting_area, &source_style);
let color = super::rgba(background_color);
- builder
- .display_list
- .wr
- .push_rect(&common, painting_area, color)
+ builder.wr().push_rect(&common, painting_area, color)
}
let mut fragment_builder = BuilderForBoxFragment::new(
@@ -741,7 +713,7 @@ impl StackingContext {
}
if pushed_context {
- builder.display_list.wr.pop_stacking_context();
+ builder.wr().pop_stacking_context();
}
}
@@ -824,7 +796,7 @@ pub(crate) enum StackingContextBuildMode {
impl Fragment {
pub(crate) fn build_stacking_context_tree(
&self,
- display_list: &mut DisplayList,
+ stacking_context_tree: &mut StackingContextTree,
containing_block_info: &ContainingBlockInfo,
stacking_context: &mut StackingContext,
mode: StackingContextBuildMode,
@@ -852,7 +824,7 @@ impl Fragment {
fragment.build_stacking_context_tree(
fragment_clone,
- display_list,
+ stacking_context_tree,
containing_block,
containing_block_info,
stacking_context,
@@ -866,7 +838,7 @@ impl Fragment {
};
fragment_ref.build_stacking_context_tree(
- display_list,
+ stacking_context_tree,
containing_block_info,
stacking_context,
StackingContextBuildMode::IncludeHoisted,
@@ -875,7 +847,7 @@ impl Fragment {
Fragment::Positioning(fragment) => {
let fragment = fragment.borrow();
fragment.build_stacking_context_tree(
- display_list,
+ stacking_context_tree,
containing_block,
containing_block_info,
stacking_context,
@@ -890,7 +862,7 @@ impl Fragment {
reference_frame_scroll_node_id: containing_block_info
.for_absolute_and_fixed_descendants
.scroll_node_id,
- clip_chain_id: containing_block.clip_chain_id,
+ clip_id: containing_block.clip_id,
containing_block: containing_block.rect,
fragment: fragment_clone,
is_hit_test_for_scrollable_overflow: false,
@@ -912,7 +884,7 @@ struct ScrollFrameData {
}
struct OverflowFrameData {
- clip_chain_id: wr::ClipChainId,
+ clip_id: ClipId,
scroll_frame_data: Option<ScrollFrameData>,
}
@@ -953,14 +925,14 @@ impl BoxFragment {
fn build_stacking_context_tree(
&self,
fragment: Fragment,
- display_list: &mut DisplayList,
+ stacking_context_tree: &mut StackingContextTree,
containing_block: &ContainingBlock,
containing_block_info: &ContainingBlockInfo,
parent_stacking_context: &mut StackingContext,
) {
self.build_stacking_context_tree_maybe_creating_reference_frame(
fragment,
- display_list,
+ stacking_context_tree,
containing_block,
containing_block_info,
parent_stacking_context,
@@ -970,7 +942,7 @@ impl BoxFragment {
fn build_stacking_context_tree_maybe_creating_reference_frame(
&self,
fragment: Fragment,
- display_list: &mut DisplayList,
+ stacking_context_tree: &mut StackingContextTree,
containing_block: &ContainingBlock,
containing_block_info: &ContainingBlockInfo,
parent_stacking_context: &mut StackingContext,
@@ -981,7 +953,7 @@ impl BoxFragment {
None => {
return self.build_stacking_context_tree_maybe_creating_stacking_context(
fragment,
- display_list,
+ stacking_context_tree,
containing_block,
containing_block_info,
parent_stacking_context,
@@ -989,11 +961,11 @@ impl BoxFragment {
},
};
- let new_spatial_id = display_list.push_reference_frame(
+ let new_spatial_id = stacking_context_tree.push_reference_frame(
reference_frame_data.origin.to_webrender(),
&containing_block.scroll_node_id,
self.style.get_box().transform_style.to_webrender(),
- wr::PropertyBinding::Value(reference_frame_data.transform),
+ reference_frame_data.transform,
reference_frame_data.kind,
);
@@ -1016,26 +988,24 @@ impl BoxFragment {
.translate(-reference_frame_data.origin.to_vector()),
new_spatial_id,
None,
- containing_block.clip_chain_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,
- display_list,
+ stacking_context_tree,
&adjusted_containing_block,
&new_containing_block_info,
parent_stacking_context,
);
-
- display_list.pop_reference_frame();
}
fn build_stacking_context_tree_maybe_creating_stacking_context(
&self,
fragment: Fragment,
- display_list: &mut DisplayList,
+ stacking_context_tree: &mut StackingContextTree,
containing_block: &ContainingBlock,
containing_block_info: &ContainingBlockInfo,
parent_stacking_context: &mut StackingContext,
@@ -1045,7 +1015,7 @@ impl BoxFragment {
None => {
self.build_stacking_context_tree_for_children(
fragment,
- display_list,
+ stacking_context_tree,
containing_block,
containing_block_info,
parent_stacking_context,
@@ -1068,30 +1038,37 @@ impl BoxFragment {
// `clip-path` needs to be applied before filters and creates a stacking context, so it can be
// applied directly to the stacking context itself.
// before
- let stacking_context_clip_chain_id = build_clip_path_clip_chain_if_necessary(
- self.style.clone_clip_path(),
- display_list,
- &containing_block.scroll_node_id,
- &containing_block.clip_chain_id,
- BuilderForBoxFragment::new(
- self,
- &containing_block.rect,
- false, /* is_hit_test_for_scrollable_overflow */
- false, /* is_collapsed_table_borders */
- ),
- )
- .unwrap_or(containing_block.clip_chain_id);
+ let stacking_context_clip_id = stacking_context_tree
+ .clip_store
+ .add_for_clip_path(
+ self.style.clone_clip_path(),
+ &containing_block.scroll_node_id,
+ &containing_block.clip_id,
+ BuilderForBoxFragment::new(
+ self,
+ &containing_block.rect,
+ false, /* is_hit_test_for_scrollable_overflow */
+ false, /* is_collapsed_table_borders */
+ ),
+ )
+ .unwrap_or(containing_block.clip_id);
+
+ let box_fragment = match fragment {
+ Fragment::Box(ref box_fragment) | Fragment::Float(ref box_fragment) => {
+ box_fragment.clone()
+ },
+ _ => unreachable!("Should never try to make stacking context for non-BoxFragment"),
+ };
let mut child_stacking_context = parent_stacking_context.create_descendant(
- containing_block.scroll_node_id.spatial_id,
- stacking_context_clip_chain_id,
- self.style.clone(),
- self.base.flags,
+ containing_block.scroll_node_id,
+ stacking_context_clip_id,
+ box_fragment,
context_type,
);
self.build_stacking_context_tree_for_children(
fragment,
- display_list,
+ stacking_context_tree,
containing_block,
containing_block_info,
&mut child_stacking_context,
@@ -1116,19 +1093,19 @@ impl BoxFragment {
fn build_stacking_context_tree_for_children(
&self,
fragment: Fragment,
- display_list: &mut DisplayList,
+ stacking_context_tree: &mut StackingContextTree,
containing_block: &ContainingBlock,
containing_block_info: &ContainingBlockInfo,
stacking_context: &mut StackingContext,
) {
let mut new_scroll_node_id = containing_block.scroll_node_id;
- let mut new_clip_chain_id = containing_block.clip_chain_id;
+ let mut new_clip_id = containing_block.clip_id;
let mut new_scroll_frame_size = containing_block_info
.for_non_absolute_descendants
.scroll_frame_size;
if let Some(scroll_node_id) = self.build_sticky_frame_if_necessary(
- display_list,
+ stacking_context_tree,
&new_scroll_node_id,
&containing_block.rect,
&new_scroll_frame_size,
@@ -1136,20 +1113,19 @@ impl BoxFragment {
new_scroll_node_id = scroll_node_id;
}
- if let Some(clip_chain_id) = self.build_clip_frame_if_necessary(
- display_list,
+ if let Some(clip_id) = self.build_clip_frame_if_necessary(
+ stacking_context_tree,
&new_scroll_node_id,
- &new_clip_chain_id,
+ new_clip_id,
&containing_block.rect,
) {
- new_clip_chain_id = clip_chain_id;
+ new_clip_id = clip_id;
}
- if let Some(clip_chain_id) = build_clip_path_clip_chain_if_necessary(
+ if let Some(clip_id) = stacking_context_tree.clip_store.add_for_clip_path(
self.style.clone_clip_path(),
- display_list,
&new_scroll_node_id,
- &new_clip_chain_id,
+ &new_clip_id,
BuilderForBoxFragment::new(
self,
&containing_block.rect,
@@ -1157,7 +1133,7 @@ impl BoxFragment {
false, /* is_collapsed_table_borders */
),
) {
- new_clip_chain_id = clip_chain_id;
+ new_clip_id = clip_id;
}
let establishes_containing_block_for_all_descendants = self
@@ -1182,7 +1158,7 @@ impl BoxFragment {
.push(StackingContextContent::Fragment {
scroll_node_id: new_scroll_node_id,
reference_frame_scroll_node_id: reference_frame_scroll_node_id_for_fragments,
- clip_chain_id: new_clip_chain_id,
+ clip_id: new_clip_id,
section,
containing_block: containing_block.rect,
fragment: fragment.clone(),
@@ -1200,12 +1176,12 @@ 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(overflow_frame_data) = self.build_overflow_frame_if_necessary(
- display_list,
+ stacking_context_tree,
&new_scroll_node_id,
- &new_clip_chain_id,
+ new_clip_id,
&containing_block.rect,
) {
- new_clip_chain_id = overflow_frame_data.clip_chain_id;
+ new_clip_id = overflow_frame_data.clip_id;
if let Some(scroll_frame_data) = overflow_frame_data.scroll_frame_data {
new_scroll_node_id = scroll_frame_data.scroll_tree_node_id;
new_scroll_frame_size = Some(scroll_frame_data.scroll_frame_rect.size());
@@ -1216,7 +1192,7 @@ impl BoxFragment {
scroll_node_id: new_scroll_node_id,
reference_frame_scroll_node_id:
reference_frame_scroll_node_id_for_fragments,
- clip_chain_id: new_clip_chain_id,
+ clip_id: new_clip_id,
section,
containing_block: containing_block.rect,
fragment: fragment.clone(),
@@ -1237,13 +1213,13 @@ impl BoxFragment {
padding_rect,
new_scroll_node_id,
new_scroll_frame_size,
- new_clip_chain_id,
+ new_clip_id,
);
let for_non_absolute_descendants = ContainingBlock::new(
content_rect,
new_scroll_node_id,
new_scroll_frame_size,
- new_clip_chain_id,
+ new_clip_id,
);
// Create a new `ContainingBlockInfo` for descendants depending on
@@ -1265,7 +1241,7 @@ impl BoxFragment {
for child in &self.children {
child.build_stacking_context_tree(
- display_list,
+ stacking_context_tree,
&new_containing_block_info,
stacking_context,
StackingContextBuildMode::SkipHoisted,
@@ -1281,7 +1257,7 @@ impl BoxFragment {
.push(StackingContextContent::Fragment {
scroll_node_id: new_scroll_node_id,
reference_frame_scroll_node_id: reference_frame_scroll_node_id_for_fragments,
- clip_chain_id: new_clip_chain_id,
+ clip_id: new_clip_id,
section,
containing_block: containing_block.rect,
fragment: fragment.clone(),
@@ -1293,11 +1269,11 @@ impl BoxFragment {
fn build_clip_frame_if_necessary(
&self,
- display_list: &mut DisplayList,
+ stacking_context_tree: &mut StackingContextTree,
parent_scroll_node_id: &ScrollTreeNodeId,
- parent_clip_chain_id: &wr::ClipChainId,
+ parent_clip_id: ClipId,
containing_block_rect: &PhysicalRect<Au>,
- ) -> Option<wr::ClipChainId> {
+ ) -> Option<ClipId> {
let position = self.style.get_box().position;
// https://drafts.csswg.org/css2/#clipping
// The clip property applies only to absolutely positioned elements
@@ -1316,18 +1292,19 @@ impl BoxFragment {
.for_border_rect(border_rect)
.translate(containing_block_rect.origin.to_vector())
.to_webrender();
-
- let clip_id = display_list
- .wr
- .define_clip_rect(parent_scroll_node_id.spatial_id, clip_rect);
- Some(display_list.define_clip_chain(*parent_clip_chain_id, [clip_id]))
+ Some(stacking_context_tree.clip_store.add(
+ BorderRadius::zero(),
+ clip_rect,
+ *parent_scroll_node_id,
+ parent_clip_id,
+ ))
}
fn build_overflow_frame_if_necessary(
&self,
- display_list: &mut DisplayList,
+ stacking_context_tree: &mut StackingContextTree,
parent_scroll_node_id: &ScrollTreeNodeId,
- parent_clip_chain_id: &wr::ClipChainId,
+ parent_clip_id: ClipId,
containing_block_rect: &PhysicalRect<Au>,
) -> Option<OverflowFrameData> {
let overflow = self.style.effective_overflow(self.base.flags);
@@ -1367,15 +1344,15 @@ impl BoxFragment {
radii = BorderRadius::zero();
}
- let clip_chain_id = display_list.clip_overflow_frame(
- parent_scroll_node_id,
- parent_clip_chain_id,
- overflow_clip_rect,
+ let clip_id = stacking_context_tree.clip_store.add(
radii,
+ overflow_clip_rect,
+ *parent_scroll_node_id,
+ parent_clip_id,
);
return Some(OverflowFrameData {
- clip_chain_id,
+ clip_id,
scroll_frame_data: None,
});
}
@@ -1404,17 +1381,17 @@ impl BoxFragment {
.translate(containing_block_rect.origin.to_vector())
.to_webrender();
- let clip_chain_id = display_list.clip_overflow_frame(
- parent_scroll_node_id,
- parent_clip_chain_id,
- scroll_frame_rect,
+ let clip_id = stacking_context_tree.clip_store.add(
BuilderForBoxFragment::new(self, containing_block_rect, false, false).border_radius,
+ scroll_frame_rect,
+ *parent_scroll_node_id,
+ parent_clip_id,
);
let tag = self.base.tag?;
let external_id = wr::ExternalScrollId(
tag.to_display_list_fragment_id(),
- display_list.wr.pipeline_id,
+ stacking_context_tree.compositor_info.pipeline_id,
);
let sensitivity = AxesScrollSensitivity {
@@ -1424,7 +1401,7 @@ impl BoxFragment {
let content_rect = self.reachable_scrollable_overflow_region().to_webrender();
- let scroll_tree_node_id = display_list.define_scroll_frame(
+ let scroll_tree_node_id = stacking_context_tree.define_scroll_frame(
parent_scroll_node_id,
external_id,
content_rect,
@@ -1433,7 +1410,7 @@ impl BoxFragment {
);
Some(OverflowFrameData {
- clip_chain_id,
+ clip_id,
scroll_frame_data: Some(ScrollFrameData {
scroll_tree_node_id,
scroll_frame_rect,
@@ -1443,7 +1420,7 @@ impl BoxFragment {
fn build_sticky_frame_if_necessary(
&self,
- display_list: &mut DisplayList,
+ stacking_context_tree: &mut StackingContextTree,
parent_scroll_node_id: &ScrollTreeNodeId,
containing_block_rect: &PhysicalRect<Au>,
scroll_frame_size: &Option<LayoutSize>,
@@ -1456,7 +1433,7 @@ impl BoxFragment {
Some(size) => size,
None => {
// This is a direct descendant of a reference frame.
- &display_list.compositor_info.viewport_size
+ &stacking_context_tree.compositor_info.viewport_size
},
};
@@ -1513,7 +1490,7 @@ impl BoxFragment {
offsets.left.non_auto().map(|v| v.to_f32_px()),
);
- let sticky_node_id = display_list.define_sticky_frame(
+ let sticky_node_id = stacking_context_tree.define_sticky_frame(
parent_scroll_node_id,
frame_rect,
margins,
@@ -1665,7 +1642,7 @@ impl BoxFragment {
impl PositioningFragment {
fn build_stacking_context_tree(
&self,
- display_list: &mut DisplayList,
+ stacking_context_tree: &mut StackingContextTree,
containing_block: &ContainingBlock,
containing_block_info: &ContainingBlockInfo,
stacking_context: &mut StackingContext,
@@ -1679,7 +1656,7 @@ impl PositioningFragment {
for child in &self.children {
child.build_stacking_context_tree(
- display_list,
+ stacking_context_tree,
&new_containing_block_info,
stacking_context,
StackingContextBuildMode::SkipHoisted,