mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
Refactor Layout 2020 layout for a compositor-side scroll tree
This change refactors how layout is done in Layout 2020 in preparation for a compositor-side scroll tree: 1. Now the SpatialId and ClipId of each fragment is stored separately. This will allow storing a scroll node id instead of only the handle to the WebRender spatial node. 2. Separate out stacking context tree construction and display list building. This change will make it possible to eventually build the stacking context tree without the full display list if we find that necessary. For instance, this might be useful to cache containing block boundaries. 3. Add a `DisplayList` struct that stores both the WebRender display list builder and the compositor info. This exposes the API to the layout thread for display list building. In addition, this change adds a lot of missing documentation. This should not change behavior.
This commit is contained in:
parent
c5d31c3ab6
commit
b60e105526
5 changed files with 326 additions and 178 deletions
|
@ -144,9 +144,9 @@ pub(super) fn build_linear(
|
||||||
|
|
||||||
let stops = fixup_stops(style, items, Length::new(gradient_line_length));
|
let stops = fixup_stops(style, items, Length::new(gradient_line_length));
|
||||||
let linear_gradient = builder
|
let linear_gradient = builder
|
||||||
.wr
|
.wr()
|
||||||
.create_gradient(start_point, end_point, stops, extend_mode);
|
.create_gradient(start_point, end_point, stops, extend_mode);
|
||||||
builder.wr.push_gradient(
|
builder.wr().push_gradient(
|
||||||
&layer.common,
|
&layer.common,
|
||||||
layer.bounds,
|
layer.bounds,
|
||||||
linear_gradient,
|
linear_gradient,
|
||||||
|
@ -244,9 +244,9 @@ pub(super) fn build_radial(
|
||||||
|
|
||||||
let stops = fixup_stops(style, items, Length::new(gradient_line_length));
|
let stops = fixup_stops(style, items, Length::new(gradient_line_length));
|
||||||
let radial_gradient = builder
|
let radial_gradient = builder
|
||||||
.wr
|
.wr()
|
||||||
.create_radial_gradient(center, radii, stops, extend_mode);
|
.create_radial_gradient(center, radii, stops, extend_mode);
|
||||||
builder.wr.push_radial_gradient(
|
builder.wr().push_radial_gradient(
|
||||||
&layer.common,
|
&layer.common,
|
||||||
layer.bounds,
|
layer.bounds,
|
||||||
radial_gradient,
|
radial_gradient,
|
||||||
|
|
|
@ -10,6 +10,7 @@ use crate::fragments::{BoxFragment, Fragment, TextFragment};
|
||||||
use crate::geom::{PhysicalPoint, PhysicalRect};
|
use crate::geom::{PhysicalPoint, PhysicalRect};
|
||||||
use crate::replaced::IntrinsicSizes;
|
use crate::replaced::IntrinsicSizes;
|
||||||
use crate::style_ext::ComputedValuesExt;
|
use crate::style_ext::ComputedValuesExt;
|
||||||
|
use crate::FragmentTree;
|
||||||
use embedder_traits::Cursor;
|
use embedder_traits::Cursor;
|
||||||
use euclid::{Point2D, SideOffsets2D, Size2D};
|
use euclid::{Point2D, SideOffsets2D, Size2D};
|
||||||
use fnv::FnvHashMap;
|
use fnv::FnvHashMap;
|
||||||
|
@ -32,7 +33,9 @@ use webrender_api::{self as wr, units};
|
||||||
mod background;
|
mod background;
|
||||||
mod conversions;
|
mod conversions;
|
||||||
mod gradient;
|
mod gradient;
|
||||||
pub mod stacking_context;
|
mod stacking_context;
|
||||||
|
|
||||||
|
pub use stacking_context::*;
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct WebRenderImageInfo {
|
pub struct WebRenderImageInfo {
|
||||||
|
@ -45,38 +48,99 @@ pub struct WebRenderImageInfo {
|
||||||
type ItemTag = (u64, u16);
|
type ItemTag = (u64, u16);
|
||||||
type HitInfo = Option<ItemTag>;
|
type HitInfo = Option<ItemTag>;
|
||||||
|
|
||||||
pub struct DisplayListBuilder<'a> {
|
/// Where the information that's used to build display lists is stored. This
|
||||||
/// The current SpatialId and ClipId information for this `DisplayListBuilder`.
|
/// includes both a [wr::DisplayListBuilder] for building up WebRender-specific
|
||||||
current_space_and_clip: wr::SpaceAndClipInfo,
|
/// display list information and a [CompositorDisplayListInfo] used to store
|
||||||
|
/// information used by the compositor, such as a compositor-side scroll tree.
|
||||||
element_for_canvas_background: OpaqueNode,
|
pub struct DisplayList {
|
||||||
pub context: &'a LayoutContext<'a>,
|
/// The [wr::DisplayListBuilder] used to collect display list items.
|
||||||
pub wr: wr::DisplayListBuilder,
|
pub wr: wr::DisplayListBuilder,
|
||||||
pub compositor_info: CompositorDisplayListInfo,
|
|
||||||
pub iframe_sizes: FnvHashMap<BrowsingContextId, Size2D<f32, CSSPixel>>,
|
|
||||||
|
|
||||||
/// Contentful paint, for the purpose of
|
/// The information about the WebRender display list that the compositor
|
||||||
/// https://w3c.github.io/paint-timing/#first-contentful-paint
|
/// consumes. This curerntly contains the out-of-band hit testing information
|
||||||
/// (i.e. the display list contains items of type text,
|
/// data structure that the compositor uses to map hit tests to information
|
||||||
/// image, non-white canvas or SVG). Used by metrics.
|
/// about the item hit.
|
||||||
pub is_contentful: bool,
|
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(
|
pub fn new(
|
||||||
|
_viewport_size: units::LayoutSize,
|
||||||
|
content_size: units::LayoutSize,
|
||||||
pipeline_id: wr::PipelineId,
|
pipeline_id: wr::PipelineId,
|
||||||
context: &'a LayoutContext,
|
|
||||||
fragment_tree: &crate::FragmentTree,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
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,
|
element_for_canvas_background: fragment_tree.canvas_background.from_element,
|
||||||
is_contentful: false,
|
is_contentful: false,
|
||||||
context,
|
context,
|
||||||
wr: wr::DisplayListBuilder::new(pipeline_id, fragment_tree.scrollable_overflow()),
|
display_list: self,
|
||||||
compositor_info: CompositorDisplayListInfo::default(),
|
|
||||||
iframe_sizes: FnvHashMap::default(),
|
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(
|
fn common_properties(
|
||||||
|
@ -89,8 +153,8 @@ impl<'a> DisplayListBuilder<'a> {
|
||||||
// for fragments that paint their entire border rectangle.
|
// for fragments that paint their entire border rectangle.
|
||||||
wr::CommonItemProperties {
|
wr::CommonItemProperties {
|
||||||
clip_rect,
|
clip_rect,
|
||||||
spatial_id: self.current_space_and_clip.spatial_id,
|
spatial_id: self.current_spatial_id,
|
||||||
clip_id: self.current_space_and_clip.clip_id,
|
clip_id: self.current_clip_id,
|
||||||
hit_info: None,
|
hit_info: None,
|
||||||
flags: style.get_webrender_primitive_flags(),
|
flags: style.get_webrender_primitive_flags(),
|
||||||
}
|
}
|
||||||
|
@ -109,7 +173,7 @@ impl<'a> DisplayListBuilder<'a> {
|
||||||
return None;
|
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,
|
tag?.node.0 as u64,
|
||||||
Some(cursor(inherited_ui.cursor.keyword, auto_cursor)),
|
Some(cursor(inherited_ui.cursor.keyword, auto_cursor)),
|
||||||
);
|
);
|
||||||
|
@ -143,7 +207,7 @@ impl Fragment {
|
||||||
.translate(containing_block.origin.to_vector());
|
.translate(containing_block.origin.to_vector());
|
||||||
|
|
||||||
let common = builder.common_properties(rect.to_webrender(), &i.style);
|
let common = builder.common_properties(rect.to_webrender(), &i.style);
|
||||||
builder.wr.push_image(
|
builder.wr().push_image(
|
||||||
&common,
|
&common,
|
||||||
rect.to_webrender(),
|
rect.to_webrender(),
|
||||||
image_rendering(i.style.get_inherited_box().image_rendering),
|
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);
|
let common = builder.common_properties(rect.to_webrender(), &iframe.style);
|
||||||
builder.wr.push_iframe(
|
builder.wr().push_iframe(
|
||||||
rect.to_webrender(),
|
rect.to_webrender(),
|
||||||
common.clip_rect,
|
common.clip_rect,
|
||||||
&wr::SpaceAndClipInfo {
|
&wr::SpaceAndClipInfo {
|
||||||
|
@ -248,7 +312,7 @@ impl Fragment {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Text.
|
// Text.
|
||||||
builder.wr.push_text(
|
builder.wr().push_text(
|
||||||
&common,
|
&common,
|
||||||
rect.to_webrender(),
|
rect.to_webrender(),
|
||||||
&glyphs,
|
&glyphs,
|
||||||
|
@ -287,7 +351,7 @@ impl Fragment {
|
||||||
if text_decoration_style == ComputedTextDecorationStyle::MozNone {
|
if text_decoration_style == ComputedTextDecorationStyle::MozNone {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
builder.wr.push_line(
|
builder.display_list.wr.push_line(
|
||||||
&builder.common_properties(rect, &fragment.parent_style),
|
&builder.common_properties(rect, &fragment.parent_style),
|
||||||
&rect,
|
&rect,
|
||||||
wavy_line_thickness,
|
wavy_line_thickness,
|
||||||
|
@ -448,7 +512,7 @@ impl<'a> BuilderForBoxFragment<'a> {
|
||||||
if let Some(clip_id) = self.border_edge_clip(builder) {
|
if let Some(clip_id) = self.border_edge_clip(builder) {
|
||||||
common.clip_id = clip_id
|
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 layer_index = b.background_image.0.len() - 1;
|
||||||
let (bounds, common) = background::painting_area(self, &source, builder, layer_index);
|
let (bounds, common) = background::painting_area(self, &source, builder, layer_index);
|
||||||
builder
|
builder
|
||||||
.wr
|
.wr()
|
||||||
.push_rect(&common, *bounds, rgba(background_color))
|
.push_rect(&common, *bounds, rgba(background_color))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -550,7 +614,7 @@ impl<'a> BuilderForBoxFragment<'a> {
|
||||||
{
|
{
|
||||||
let image_rendering = image_rendering(style.clone_image_rendering());
|
let image_rendering = image_rendering(style.clone_image_rendering());
|
||||||
if layer.repeat {
|
if layer.repeat {
|
||||||
builder.wr.push_repeating_image(
|
builder.wr().push_repeating_image(
|
||||||
&layer.common,
|
&layer.common,
|
||||||
layer.bounds,
|
layer.bounds,
|
||||||
layer.tile_size,
|
layer.tile_size,
|
||||||
|
@ -561,7 +625,7 @@ impl<'a> BuilderForBoxFragment<'a> {
|
||||||
wr::ColorF::WHITE,
|
wr::ColorF::WHITE,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
builder.wr.push_image(
|
builder.wr().push_image(
|
||||||
&layer.common,
|
&layer.common,
|
||||||
layer.bounds,
|
layer.bounds,
|
||||||
image_rendering,
|
image_rendering,
|
||||||
|
@ -620,7 +684,7 @@ impl<'a> BuilderForBoxFragment<'a> {
|
||||||
do_aa: true,
|
do_aa: true,
|
||||||
});
|
});
|
||||||
builder
|
builder
|
||||||
.wr
|
.wr()
|
||||||
.push_border(&common, self.border_rect, widths, details)
|
.push_border(&common, self.border_rect, widths, details)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -655,7 +719,7 @@ impl<'a> BuilderForBoxFragment<'a> {
|
||||||
do_aa: true,
|
do_aa: true,
|
||||||
});
|
});
|
||||||
builder
|
builder
|
||||||
.wr
|
.wr()
|
||||||
.push_border(&common, outline_rect, widths, details)
|
.push_border(&common, outline_rect, widths, details)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -801,8 +865,12 @@ fn clip_for_radii(
|
||||||
if radii.is_zero() {
|
if radii.is_zero() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(builder.wr.define_clip_rounded_rect(
|
let parent_space_and_clip = wr::SpaceAndClipInfo {
|
||||||
&builder.current_space_and_clip,
|
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 {
|
wr::ComplexClipRegion {
|
||||||
rect,
|
rect,
|
||||||
radii,
|
radii,
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use super::DisplayList;
|
||||||
use crate::cell::ArcRefCell;
|
use crate::cell::ArcRefCell;
|
||||||
use crate::display_list::conversions::ToWebRender;
|
use crate::display_list::conversions::ToWebRender;
|
||||||
use crate::display_list::DisplayListBuilder;
|
use crate::display_list::DisplayListBuilder;
|
||||||
|
@ -9,6 +10,7 @@ use crate::fragment_tree::ContainingBlockManager;
|
||||||
use crate::fragments::{AnonymousFragment, BoxFragment, Fragment};
|
use crate::fragments::{AnonymousFragment, BoxFragment, Fragment};
|
||||||
use crate::geom::PhysicalRect;
|
use crate::geom::PhysicalRect;
|
||||||
use crate::style_ext::ComputedValuesExt;
|
use crate::style_ext::ComputedValuesExt;
|
||||||
|
use crate::FragmentTree;
|
||||||
use euclid::default::Rect;
|
use euclid::default::Rect;
|
||||||
use servo_arc::Arc as ServoArc;
|
use servo_arc::Arc as ServoArc;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
@ -24,30 +26,39 @@ use style::values::generics::box_::Perspective;
|
||||||
use style::values::generics::transform;
|
use style::values::generics::transform;
|
||||||
use style::values::specified::box_::DisplayOutside;
|
use style::values::specified::box_::DisplayOutside;
|
||||||
use webrender_api as wr;
|
use webrender_api as wr;
|
||||||
use webrender_api::units::{LayoutPoint, LayoutTransform, LayoutVector2D};
|
use webrender_api::units::{LayoutPoint, LayoutRect, LayoutTransform, LayoutVector2D};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub(crate) struct ContainingBlock {
|
pub(crate) struct ContainingBlock {
|
||||||
/// The SpaceAndClipInfo that contains the children of the fragment that
|
/// The SpatialId of the spatial node that contains the children
|
||||||
/// established this containing block.
|
/// of this containing block.
|
||||||
space_and_clip: wr::SpaceAndClipInfo,
|
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.
|
/// The physical rect of this containing block.
|
||||||
rect: PhysicalRect<Length>,
|
rect: PhysicalRect<Length>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ContainingBlock {
|
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 {
|
ContainingBlock {
|
||||||
space_and_clip,
|
spatial_id,
|
||||||
|
clip_id,
|
||||||
rect: *rect,
|
rect: *rect,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn new_replacing_rect(&self, rect: &PhysicalRect<Length>) -> Self {
|
pub(crate) fn new_replacing_rect(&self, rect: &PhysicalRect<Length>) -> Self {
|
||||||
ContainingBlock {
|
ContainingBlock {
|
||||||
space_and_clip: self.space_and_clip,
|
|
||||||
rect: *rect,
|
rect: *rect,
|
||||||
|
..*self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,8 +73,89 @@ pub(crate) enum StackingContextSection {
|
||||||
Outline,
|
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 {
|
pub(crate) struct StackingContextFragment {
|
||||||
space_and_clip: wr::SpaceAndClipInfo,
|
spatial_id: wr::SpatialId,
|
||||||
|
clip_id: wr::ClipId,
|
||||||
section: StackingContextSection,
|
section: StackingContextSection,
|
||||||
containing_block: PhysicalRect<Length>,
|
containing_block: PhysicalRect<Length>,
|
||||||
fragment: ArcRefCell<Fragment>,
|
fragment: ArcRefCell<Fragment>,
|
||||||
|
@ -71,7 +163,8 @@ pub(crate) struct StackingContextFragment {
|
||||||
|
|
||||||
impl StackingContextFragment {
|
impl StackingContextFragment {
|
||||||
fn build_display_list(&self, builder: &mut DisplayListBuilder) {
|
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
|
self.fragment
|
||||||
.borrow()
|
.borrow()
|
||||||
.build_display_list(builder, &self.containing_block, self.section);
|
.build_display_list(builder, &self.containing_block, self.section);
|
||||||
|
@ -86,7 +179,7 @@ pub(crate) enum StackingContextType {
|
||||||
PseudoAtomicInline,
|
PseudoAtomicInline,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct StackingContext {
|
pub struct StackingContext {
|
||||||
/// The spatial id of this fragment. This is used to properly handle
|
/// The spatial id of this fragment. This is used to properly handle
|
||||||
/// things like preserve-3d.
|
/// things like preserve-3d.
|
||||||
spatial_id: wr::SpatialId,
|
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,
|
&self,
|
||||||
builder: &'a mut DisplayListBuilder,
|
builder: &mut DisplayListBuilder,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let style = match self.initializing_fragment_style.as_ref() {
|
let style = match self.initializing_fragment_style.as_ref() {
|
||||||
Some(style) => style,
|
Some(style) => style,
|
||||||
|
@ -202,7 +295,7 @@ impl StackingContext {
|
||||||
// This will require additional tracking during layout
|
// This will require additional tracking during layout
|
||||||
// before we start collecting stacking contexts so that
|
// before we start collecting stacking contexts so that
|
||||||
// information will be available when we reach this point.
|
// information will be available when we reach this point.
|
||||||
builder.wr.push_stacking_context(
|
builder.wr().push_stacking_context(
|
||||||
LayoutPoint::zero(), // origin
|
LayoutPoint::zero(), // origin
|
||||||
self.spatial_id,
|
self.spatial_id,
|
||||||
style.get_webrender_primitive_flags(),
|
style.get_webrender_primitive_flags(),
|
||||||
|
@ -251,7 +344,10 @@ impl StackingContext {
|
||||||
if background_color.alpha > 0 {
|
if background_color.alpha > 0 {
|
||||||
let common = builder.common_properties(painting_area, &style);
|
let common = builder.common_properties(painting_area, &style);
|
||||||
let color = super::rgba(background_color);
|
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,
|
// `background-color` was comparatively easy,
|
||||||
|
@ -299,11 +395,10 @@ impl StackingContext {
|
||||||
Some(fragment_tree.canvas_background.root_element),
|
Some(fragment_tree.canvas_background.root_element),
|
||||||
);
|
);
|
||||||
|
|
||||||
// The root element may have a CSS transform,
|
// The root element may have a CSS transform, and we want the canvas’
|
||||||
// and we want the canvas’ background image to be transformed.
|
// background image to be transformed. To do so, take its `SpatialId`
|
||||||
// To do so, take its `SpatialId` (but not its `ClipId`)
|
// (but not its `ClipId`)
|
||||||
builder.current_space_and_clip.spatial_id =
|
builder.current_spatial_id = first_stacking_context_fragment.spatial_id;
|
||||||
first_stacking_context_fragment.space_and_clip.spatial_id;
|
|
||||||
|
|
||||||
// Now we need express the painting area rectangle in the local coordinate system,
|
// Now we need express the painting area rectangle in the local coordinate system,
|
||||||
// which differs from the top-level coordinate system based on…
|
// which differs from the top-level coordinate system based on…
|
||||||
|
@ -393,7 +488,7 @@ impl StackingContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
if pushed_context {
|
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(
|
pub(crate) fn build_stacking_context_tree(
|
||||||
&self,
|
&self,
|
||||||
fragment_ref: &ArcRefCell<Fragment>,
|
fragment_ref: &ArcRefCell<Fragment>,
|
||||||
wr: &mut wr::DisplayListBuilder,
|
display_list: &mut DisplayList,
|
||||||
containing_block_info: &ContainingBlockInfo,
|
containing_block_info: &ContainingBlockInfo,
|
||||||
stacking_context: &mut StackingContext,
|
stacking_context: &mut StackingContext,
|
||||||
mode: StackingContextBuildMode,
|
mode: StackingContextBuildMode,
|
||||||
|
@ -432,7 +527,7 @@ impl Fragment {
|
||||||
|
|
||||||
fragment.build_stacking_context_tree(
|
fragment.build_stacking_context_tree(
|
||||||
fragment_ref,
|
fragment_ref,
|
||||||
wr,
|
display_list,
|
||||||
containing_block,
|
containing_block,
|
||||||
containing_block_info,
|
containing_block_info,
|
||||||
stacking_context,
|
stacking_context,
|
||||||
|
@ -447,7 +542,7 @@ impl Fragment {
|
||||||
|
|
||||||
fragment_ref.borrow().build_stacking_context_tree(
|
fragment_ref.borrow().build_stacking_context_tree(
|
||||||
fragment_ref,
|
fragment_ref,
|
||||||
wr,
|
display_list,
|
||||||
containing_block_info,
|
containing_block_info,
|
||||||
stacking_context,
|
stacking_context,
|
||||||
StackingContextBuildMode::IncludeHoisted,
|
StackingContextBuildMode::IncludeHoisted,
|
||||||
|
@ -455,7 +550,7 @@ impl Fragment {
|
||||||
},
|
},
|
||||||
Fragment::Anonymous(fragment) => {
|
Fragment::Anonymous(fragment) => {
|
||||||
fragment.build_stacking_context_tree(
|
fragment.build_stacking_context_tree(
|
||||||
wr,
|
display_list,
|
||||||
containing_block,
|
containing_block,
|
||||||
containing_block_info,
|
containing_block_info,
|
||||||
stacking_context,
|
stacking_context,
|
||||||
|
@ -464,7 +559,8 @@ impl Fragment {
|
||||||
Fragment::Text(_) | Fragment::Image(_) | Fragment::IFrame(_) => {
|
Fragment::Text(_) | Fragment::Image(_) | Fragment::IFrame(_) => {
|
||||||
stacking_context.fragments.push(StackingContextFragment {
|
stacking_context.fragments.push(StackingContextFragment {
|
||||||
section: StackingContextSection::Content,
|
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,
|
containing_block: containing_block.rect,
|
||||||
fragment: fragment_ref.clone(),
|
fragment: fragment_ref.clone(),
|
||||||
});
|
});
|
||||||
|
@ -516,14 +612,14 @@ impl BoxFragment {
|
||||||
fn build_stacking_context_tree(
|
fn build_stacking_context_tree(
|
||||||
&self,
|
&self,
|
||||||
fragment: &ArcRefCell<Fragment>,
|
fragment: &ArcRefCell<Fragment>,
|
||||||
wr: &mut wr::DisplayListBuilder,
|
display_list: &mut DisplayList,
|
||||||
containing_block: &ContainingBlock,
|
containing_block: &ContainingBlock,
|
||||||
containing_block_info: &ContainingBlockInfo,
|
containing_block_info: &ContainingBlockInfo,
|
||||||
parent_stacking_context: &mut StackingContext,
|
parent_stacking_context: &mut StackingContext,
|
||||||
) {
|
) {
|
||||||
self.build_stacking_context_tree_maybe_creating_reference_frame(
|
self.build_stacking_context_tree_maybe_creating_reference_frame(
|
||||||
fragment,
|
fragment,
|
||||||
wr,
|
display_list,
|
||||||
containing_block,
|
containing_block,
|
||||||
containing_block_info,
|
containing_block_info,
|
||||||
parent_stacking_context,
|
parent_stacking_context,
|
||||||
|
@ -533,7 +629,7 @@ impl BoxFragment {
|
||||||
fn build_stacking_context_tree_maybe_creating_reference_frame(
|
fn build_stacking_context_tree_maybe_creating_reference_frame(
|
||||||
&self,
|
&self,
|
||||||
fragment: &ArcRefCell<Fragment>,
|
fragment: &ArcRefCell<Fragment>,
|
||||||
wr: &mut wr::DisplayListBuilder,
|
display_list: &mut DisplayList,
|
||||||
containing_block: &ContainingBlock,
|
containing_block: &ContainingBlock,
|
||||||
containing_block_info: &ContainingBlockInfo,
|
containing_block_info: &ContainingBlockInfo,
|
||||||
parent_stacking_context: &mut StackingContext,
|
parent_stacking_context: &mut StackingContext,
|
||||||
|
@ -544,7 +640,7 @@ impl BoxFragment {
|
||||||
None => {
|
None => {
|
||||||
return self.build_stacking_context_tree_maybe_creating_stacking_context(
|
return self.build_stacking_context_tree_maybe_creating_stacking_context(
|
||||||
fragment,
|
fragment,
|
||||||
wr,
|
display_list,
|
||||||
containing_block,
|
containing_block,
|
||||||
containing_block_info,
|
containing_block_info,
|
||||||
parent_stacking_context,
|
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(),
|
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(),
|
self.style.get_box().transform_style.to_webrender(),
|
||||||
wr::PropertyBinding::Value(reference_frame_data.transform),
|
wr::PropertyBinding::Value(reference_frame_data.transform),
|
||||||
reference_frame_data.kind,
|
reference_frame_data.kind,
|
||||||
|
@ -576,29 +672,27 @@ impl BoxFragment {
|
||||||
&containing_block
|
&containing_block
|
||||||
.rect
|
.rect
|
||||||
.translate(-reference_frame_data.origin.to_vector()),
|
.translate(-reference_frame_data.origin.to_vector()),
|
||||||
wr::SpaceAndClipInfo {
|
new_spatial_id,
|
||||||
spatial_id: new_spatial_id,
|
containing_block.clip_id,
|
||||||
clip_id: containing_block.space_and_clip.clip_id,
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
let new_containing_block_info =
|
let new_containing_block_info =
|
||||||
containing_block_info.new_for_non_absolute_descendants(&adjusted_containing_block);
|
containing_block_info.new_for_non_absolute_descendants(&adjusted_containing_block);
|
||||||
|
|
||||||
self.build_stacking_context_tree_maybe_creating_stacking_context(
|
self.build_stacking_context_tree_maybe_creating_stacking_context(
|
||||||
fragment,
|
fragment,
|
||||||
wr,
|
display_list,
|
||||||
&adjusted_containing_block,
|
&adjusted_containing_block,
|
||||||
&new_containing_block_info,
|
&new_containing_block_info,
|
||||||
parent_stacking_context,
|
parent_stacking_context,
|
||||||
);
|
);
|
||||||
|
|
||||||
wr.pop_reference_frame();
|
display_list.pop_reference_frame();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_stacking_context_tree_maybe_creating_stacking_context(
|
fn build_stacking_context_tree_maybe_creating_stacking_context(
|
||||||
&self,
|
&self,
|
||||||
fragment: &ArcRefCell<Fragment>,
|
fragment: &ArcRefCell<Fragment>,
|
||||||
wr: &mut wr::DisplayListBuilder,
|
display_list: &mut DisplayList,
|
||||||
containing_block: &ContainingBlock,
|
containing_block: &ContainingBlock,
|
||||||
containing_block_info: &ContainingBlockInfo,
|
containing_block_info: &ContainingBlockInfo,
|
||||||
parent_stacking_context: &mut StackingContext,
|
parent_stacking_context: &mut StackingContext,
|
||||||
|
@ -608,7 +702,7 @@ impl BoxFragment {
|
||||||
None => {
|
None => {
|
||||||
self.build_stacking_context_tree_for_children(
|
self.build_stacking_context_tree_for_children(
|
||||||
fragment,
|
fragment,
|
||||||
wr,
|
display_list,
|
||||||
containing_block,
|
containing_block,
|
||||||
containing_block_info,
|
containing_block_info,
|
||||||
parent_stacking_context,
|
parent_stacking_context,
|
||||||
|
@ -618,13 +712,13 @@ impl BoxFragment {
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut child_stacking_context = StackingContext::new(
|
let mut child_stacking_context = StackingContext::new(
|
||||||
containing_block.space_and_clip.spatial_id,
|
containing_block.spatial_id,
|
||||||
self.style.clone(),
|
self.style.clone(),
|
||||||
context_type,
|
context_type,
|
||||||
);
|
);
|
||||||
self.build_stacking_context_tree_for_children(
|
self.build_stacking_context_tree_for_children(
|
||||||
fragment,
|
fragment,
|
||||||
wr,
|
display_list,
|
||||||
containing_block,
|
containing_block,
|
||||||
containing_block_info,
|
containing_block_info,
|
||||||
&mut child_stacking_context,
|
&mut child_stacking_context,
|
||||||
|
@ -647,30 +741,36 @@ impl BoxFragment {
|
||||||
.append(&mut stolen_children);
|
.append(&mut stolen_children);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_stacking_context_tree_for_children<'a>(
|
fn build_stacking_context_tree_for_children(
|
||||||
&'a self,
|
&self,
|
||||||
fragment: &ArcRefCell<Fragment>,
|
fragment: &ArcRefCell<Fragment>,
|
||||||
wr: &mut wr::DisplayListBuilder,
|
display_list: &mut DisplayList,
|
||||||
containing_block: &ContainingBlock,
|
containing_block: &ContainingBlock,
|
||||||
containing_block_info: &ContainingBlockInfo,
|
containing_block_info: &ContainingBlockInfo,
|
||||||
stacking_context: &mut StackingContext,
|
stacking_context: &mut StackingContext,
|
||||||
) {
|
) {
|
||||||
let mut new_space_and_clip = containing_block.space_and_clip;
|
let mut new_spatial_id = containing_block.spatial_id;
|
||||||
if let Some(new_clip_id) =
|
let mut new_clip_id = containing_block.clip_id;
|
||||||
self.build_clip_frame_if_necessary(wr, new_space_and_clip, &containing_block.rect)
|
if let Some(clip_id) = self.build_clip_frame_if_necessary(
|
||||||
{
|
display_list,
|
||||||
new_space_and_clip.clip_id = new_clip_id;
|
&new_spatial_id,
|
||||||
|
&new_clip_id,
|
||||||
|
&containing_block.rect,
|
||||||
|
) {
|
||||||
|
new_clip_id = clip_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
stacking_context.fragments.push(StackingContextFragment {
|
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(),
|
section: self.get_stacking_context_section(),
|
||||||
containing_block: containing_block.rect,
|
containing_block: containing_block.rect,
|
||||||
fragment: fragment.clone(),
|
fragment: fragment.clone(),
|
||||||
});
|
});
|
||||||
if self.style.get_outline().outline_width.px() > 0.0 {
|
if self.style.get_outline().outline_width.px() > 0.0 {
|
||||||
stacking_context.fragments.push(StackingContextFragment {
|
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,
|
section: StackingContextSection::Outline,
|
||||||
containing_block: containing_block.rect,
|
containing_block: containing_block.rect,
|
||||||
fragment: fragment.clone(),
|
fragment: fragment.clone(),
|
||||||
|
@ -679,10 +779,14 @@ impl BoxFragment {
|
||||||
|
|
||||||
// We want to build the scroll frame after the background and border, because
|
// We want to build the scroll frame after the background and border, because
|
||||||
// they shouldn't scroll with the rest of the box content.
|
// they shouldn't scroll with the rest of the box content.
|
||||||
if let Some(scroll_space_and_clip) =
|
if let Some((spatial_id, clip_id)) = self.build_scroll_frame_if_necessary(
|
||||||
self.build_scroll_frame_if_necessary(wr, new_space_and_clip, &containing_block.rect)
|
display_list,
|
||||||
{
|
&new_spatial_id,
|
||||||
new_space_and_clip = scroll_space_and_clip;
|
&new_clip_id,
|
||||||
|
&containing_block.rect,
|
||||||
|
) {
|
||||||
|
new_spatial_id = spatial_id;
|
||||||
|
new_clip_id = clip_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
let padding_rect = self
|
let padding_rect = self
|
||||||
|
@ -694,14 +798,10 @@ impl BoxFragment {
|
||||||
.to_physical(self.style.writing_mode, &containing_block.rect)
|
.to_physical(self.style.writing_mode, &containing_block.rect)
|
||||||
.translate(containing_block.rect.origin.to_vector());
|
.translate(containing_block.rect.origin.to_vector());
|
||||||
|
|
||||||
let for_absolute_descendants = ContainingBlock {
|
let for_absolute_descendants =
|
||||||
rect: padding_rect,
|
ContainingBlock::new(&padding_rect, new_spatial_id, new_clip_id);
|
||||||
space_and_clip: new_space_and_clip,
|
let for_non_absolute_descendants =
|
||||||
};
|
ContainingBlock::new(&content_rect, new_spatial_id, new_clip_id);
|
||||||
let for_non_absolute_descendants = ContainingBlock {
|
|
||||||
rect: content_rect,
|
|
||||||
space_and_clip: new_space_and_clip,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Create a new `ContainingBlockInfo` for descendants depending on
|
// Create a new `ContainingBlockInfo` for descendants depending on
|
||||||
// whether or not this fragment establishes a containing block for
|
// whether or not this fragment establishes a containing block for
|
||||||
|
@ -729,7 +829,7 @@ impl BoxFragment {
|
||||||
for child in &self.children {
|
for child in &self.children {
|
||||||
child.borrow().build_stacking_context_tree(
|
child.borrow().build_stacking_context_tree(
|
||||||
child,
|
child,
|
||||||
wr,
|
display_list,
|
||||||
&new_containing_block_info,
|
&new_containing_block_info,
|
||||||
stacking_context,
|
stacking_context,
|
||||||
StackingContextBuildMode::SkipHoisted,
|
StackingContextBuildMode::SkipHoisted,
|
||||||
|
@ -739,8 +839,9 @@ impl BoxFragment {
|
||||||
|
|
||||||
fn build_clip_frame_if_necessary(
|
fn build_clip_frame_if_necessary(
|
||||||
&self,
|
&self,
|
||||||
wr: &mut wr::DisplayListBuilder,
|
display_list: &mut DisplayList,
|
||||||
current_space_and_clip: wr::SpaceAndClipInfo,
|
parent_spatial_id: &wr::SpatialId,
|
||||||
|
parent_clip_id: &wr::ClipId,
|
||||||
containing_block_rect: &PhysicalRect<Length>,
|
containing_block_rect: &PhysicalRect<Length>,
|
||||||
) -> Option<wr::ClipId> {
|
) -> Option<wr::ClipId> {
|
||||||
let position = self.style.get_box().position;
|
let position = self.style.get_box().position;
|
||||||
|
@ -764,15 +865,22 @@ impl BoxFragment {
|
||||||
.translate(containing_block_rect.origin.to_vector())
|
.translate(containing_block_rect.origin.to_vector())
|
||||||
.to_webrender();
|
.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,
|
&self,
|
||||||
wr: &mut wr::DisplayListBuilder,
|
display_list: &mut DisplayList,
|
||||||
current_space_and_clip: wr::SpaceAndClipInfo,
|
parent_spatial_id: &wr::SpatialId,
|
||||||
|
parent_clip_id: &wr::ClipId,
|
||||||
containing_block_rect: &PhysicalRect<Length>,
|
containing_block_rect: &PhysicalRect<Length>,
|
||||||
) -> Option<wr::SpaceAndClipInfo> {
|
) -> Option<(wr::SpatialId, wr::ClipId)> {
|
||||||
let overflow_x = self.style.get_box().overflow_x;
|
let overflow_x = self.style.get_box().overflow_x;
|
||||||
let overflow_y = self.style.get_box().overflow_y;
|
let overflow_y = self.style.get_box().overflow_y;
|
||||||
if overflow_x == ComputedOverflow::Visible && overflow_y == ComputedOverflow::Visible {
|
if overflow_x == ComputedOverflow::Visible && overflow_y == ComputedOverflow::Visible {
|
||||||
|
@ -780,7 +888,10 @@ impl BoxFragment {
|
||||||
}
|
}
|
||||||
|
|
||||||
let tag = self.base.tag?;
|
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 =
|
let sensitivity =
|
||||||
if ComputedOverflow::Hidden == overflow_x && ComputedOverflow::Hidden == overflow_y {
|
if ComputedOverflow::Hidden == overflow_x && ComputedOverflow::Hidden == overflow_y {
|
||||||
|
@ -794,9 +905,11 @@ impl BoxFragment {
|
||||||
.to_physical(self.style.writing_mode, &containing_block_rect)
|
.to_physical(self.style.writing_mode, &containing_block_rect)
|
||||||
.translate(containing_block_rect.origin.to_vector())
|
.translate(containing_block_rect.origin.to_vector())
|
||||||
.to_webrender();
|
.to_webrender();
|
||||||
|
|
||||||
Some(
|
Some(
|
||||||
wr.define_scroll_frame(
|
display_list.define_scroll_frame(
|
||||||
¤t_space_and_clip,
|
parent_spatial_id,
|
||||||
|
parent_clip_id,
|
||||||
Some(external_id),
|
Some(external_id),
|
||||||
self.scrollable_overflow(&containing_block_rect)
|
self.scrollable_overflow(&containing_block_rect)
|
||||||
.to_webrender(),
|
.to_webrender(),
|
||||||
|
@ -937,7 +1050,7 @@ impl BoxFragment {
|
||||||
impl AnonymousFragment {
|
impl AnonymousFragment {
|
||||||
fn build_stacking_context_tree(
|
fn build_stacking_context_tree(
|
||||||
&self,
|
&self,
|
||||||
wr: &mut wr::DisplayListBuilder,
|
display_list: &mut DisplayList,
|
||||||
containing_block: &ContainingBlock,
|
containing_block: &ContainingBlock,
|
||||||
containing_block_info: &ContainingBlockInfo,
|
containing_block_info: &ContainingBlockInfo,
|
||||||
stacking_context: &mut StackingContext,
|
stacking_context: &mut StackingContext,
|
||||||
|
@ -953,7 +1066,7 @@ impl AnonymousFragment {
|
||||||
for child in &self.children {
|
for child in &self.children {
|
||||||
child.borrow().build_stacking_context_tree(
|
child.borrow().build_stacking_context_tree(
|
||||||
child,
|
child,
|
||||||
wr,
|
display_list,
|
||||||
&new_containing_block_info,
|
&new_containing_block_info,
|
||||||
stacking_context,
|
stacking_context,
|
||||||
StackingContextBuildMode::SkipHoisted,
|
StackingContextBuildMode::SkipHoisted,
|
||||||
|
|
|
@ -4,9 +4,7 @@
|
||||||
|
|
||||||
use crate::cell::ArcRefCell;
|
use crate::cell::ArcRefCell;
|
||||||
use crate::context::LayoutContext;
|
use crate::context::LayoutContext;
|
||||||
use crate::display_list::stacking_context::{
|
use crate::display_list::StackingContext;
|
||||||
ContainingBlock, ContainingBlockInfo, StackingContext, StackingContextBuildMode,
|
|
||||||
};
|
|
||||||
use crate::dom::{LayoutBox, NodeExt};
|
use crate::dom::{LayoutBox, NodeExt};
|
||||||
use crate::dom_traversal::{iter_child_nodes, Contents, NodeAndStyleInfo};
|
use crate::dom_traversal::{iter_child_nodes, Contents, NodeAndStyleInfo};
|
||||||
use crate::flexbox::FlexLevelBox;
|
use crate::flexbox::FlexLevelBox;
|
||||||
|
@ -38,7 +36,6 @@ use style::dom::OpaqueNode;
|
||||||
use style::properties::ComputedValues;
|
use style::properties::ComputedValues;
|
||||||
use style::values::computed::Length;
|
use style::values::computed::Length;
|
||||||
use style_traits::CSSPixel;
|
use style_traits::CSSPixel;
|
||||||
use webrender_api::{ClipId, SpaceAndClipInfo, SpatialId};
|
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
pub struct BoxTree {
|
pub struct BoxTree {
|
||||||
|
@ -60,7 +57,7 @@ pub struct FragmentTree {
|
||||||
/// * The first fragment is generated by the root element.
|
/// * The first fragment is generated by the root element.
|
||||||
/// * There may be additional fragments generated by positioned boxes
|
/// * There may be additional fragments generated by positioned boxes
|
||||||
/// that have the initial containing block.
|
/// 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
|
/// The scrollable overflow rectangle for the entire tree
|
||||||
/// https://drafts.csswg.org/css-overflow/#scrollable
|
/// https://drafts.csswg.org/css-overflow/#scrollable
|
||||||
|
@ -384,58 +381,18 @@ impl BoxTree {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FragmentTree {
|
impl FragmentTree {
|
||||||
pub fn build_display_list(&self, builder: &mut crate::display_list::DisplayListBuilder) {
|
pub(crate) fn build_display_list(
|
||||||
let stacking_context = self.build_stacking_context_tree(builder);
|
&self,
|
||||||
|
builder: &mut crate::display_list::DisplayListBuilder,
|
||||||
|
root_stacking_context: &StackingContext,
|
||||||
|
) {
|
||||||
// Paint the canvas’ background (if any) before/under everything else
|
// 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,
|
builder,
|
||||||
self,
|
self,
|
||||||
&self.initial_containing_block,
|
&self.initial_containing_block,
|
||||||
);
|
);
|
||||||
|
root_stacking_context.build_display_list(builder);
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn print(&self) {
|
pub fn print(&self) {
|
||||||
|
|
|
@ -29,7 +29,7 @@ use gfx_traits::{node_id_from_scroll_id, Epoch};
|
||||||
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
|
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
|
||||||
use ipc_channel::router::ROUTER;
|
use ipc_channel::router::ROUTER;
|
||||||
use layout::context::LayoutContext;
|
use layout::context::LayoutContext;
|
||||||
use layout::display_list::{DisplayListBuilder, WebRenderImageInfo};
|
use layout::display_list::{DisplayList, WebRenderImageInfo};
|
||||||
use layout::dom::DOMLayoutData;
|
use layout::dom::DOMLayoutData;
|
||||||
use layout::layout_debug;
|
use layout::layout_debug;
|
||||||
use layout::query::{
|
use layout::query::{
|
||||||
|
@ -1268,8 +1268,15 @@ impl LayoutThread {
|
||||||
document.will_paint();
|
document.will_paint();
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut display_list =
|
let viewport_size = webrender_api::units::LayoutSize::from_untyped(Size2D::new(
|
||||||
DisplayListBuilder::new(self.id.to_webrender(), context, &fragment_tree);
|
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
|
// `dump_serialized_display_list` doesn't actually print anything. It sets up
|
||||||
// the display list for printing the serialized version when `finalize()` is called.
|
// 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();
|
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 {
|
if self.debug.dump_flow_tree {
|
||||||
fragment_tree.print();
|
fragment_tree.print();
|
||||||
|
@ -1294,12 +1308,8 @@ impl LayoutThread {
|
||||||
// sending the display list to WebRender in order to set time related
|
// sending the display list to WebRender in order to set time related
|
||||||
// Progressive Web Metrics.
|
// Progressive Web Metrics.
|
||||||
self.paint_time_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(
|
self.webrender_api.send_display_list(
|
||||||
epoch,
|
epoch,
|
||||||
viewport_size,
|
viewport_size,
|
||||||
|
@ -1307,7 +1317,7 @@ impl LayoutThread {
|
||||||
display_list.wr.finalize(),
|
display_list.wr.finalize(),
|
||||||
);
|
);
|
||||||
|
|
||||||
self.update_iframe_sizes(display_list.iframe_sizes);
|
self.update_iframe_sizes(iframe_sizes);
|
||||||
|
|
||||||
if self.debug.trace_layout {
|
if self.debug.trace_layout {
|
||||||
layout_debug::end_trace(self.generation.get());
|
layout_debug::end_trace(self.generation.get());
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue