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:
Martin Robinson 2023-05-15 10:35:45 +02:00
parent c5d31c3ab6
commit b60e105526
5 changed files with 326 additions and 178 deletions

View file

@ -4,9 +4,7 @@
use crate::cell::ArcRefCell;
use crate::context::LayoutContext;
use crate::display_list::stacking_context::{
ContainingBlock, ContainingBlockInfo, StackingContext, StackingContextBuildMode,
};
use crate::display_list::StackingContext;
use crate::dom::{LayoutBox, NodeExt};
use crate::dom_traversal::{iter_child_nodes, Contents, NodeAndStyleInfo};
use crate::flexbox::FlexLevelBox;
@ -38,7 +36,6 @@ use style::dom::OpaqueNode;
use style::properties::ComputedValues;
use style::values::computed::Length;
use style_traits::CSSPixel;
use webrender_api::{ClipId, SpaceAndClipInfo, SpatialId};
#[derive(Serialize)]
pub struct BoxTree {
@ -60,7 +57,7 @@ pub struct FragmentTree {
/// * The first fragment is generated by the root element.
/// * There may be additional fragments generated by positioned boxes
/// that have the initial containing block.
root_fragments: Vec<ArcRefCell<Fragment>>,
pub(crate) root_fragments: Vec<ArcRefCell<Fragment>>,
/// The scrollable overflow rectangle for the entire tree
/// https://drafts.csswg.org/css-overflow/#scrollable
@ -384,58 +381,18 @@ impl BoxTree {
}
impl FragmentTree {
pub fn build_display_list(&self, builder: &mut crate::display_list::DisplayListBuilder) {
let stacking_context = self.build_stacking_context_tree(builder);
pub(crate) fn build_display_list(
&self,
builder: &mut crate::display_list::DisplayListBuilder,
root_stacking_context: &StackingContext,
) {
// Paint the canvas background (if any) before/under everything else
stacking_context.build_canvas_background_display_list(
root_stacking_context.build_canvas_background_display_list(
builder,
self,
&self.initial_containing_block,
);
stacking_context.build_display_list(builder);
}
fn build_stacking_context_tree(
&self,
builder: &mut crate::display_list::DisplayListBuilder,
) -> StackingContext {
let mut stacking_context = StackingContext::create_root(&builder.wr);
let pipeline_id = builder.wr.pipeline_id;
let cb_for_non_fixed_descendants = ContainingBlock::new(
&self.initial_containing_block,
SpaceAndClipInfo::root_scroll(pipeline_id),
);
let cb_for_fixed_descendants = ContainingBlock::new(
&self.initial_containing_block,
SpaceAndClipInfo {
spatial_id: SpatialId::root_reference_frame(pipeline_id),
clip_id: ClipId::root(pipeline_id),
},
);
for fragment in &self.root_fragments {
fragment.borrow().build_stacking_context_tree(
fragment,
&mut builder.wr,
// We need to specify all three containing blocks here, because absolute
// descdendants of the root cannot share the containing block we specify
// for fixed descendants. In this case, they need to have the spatial
// id of the root scroll frame, whereas fixed descendants need the
// spatial id of the root reference frame so that they do not scroll with
// page content.
&ContainingBlockInfo {
for_non_absolute_descendants: &cb_for_non_fixed_descendants,
for_absolute_descendants: Some(&cb_for_non_fixed_descendants),
for_absolute_and_fixed_descendants: &cb_for_fixed_descendants,
},
&mut stacking_context,
StackingContextBuildMode::SkipHoisted,
);
}
stacking_context.sort();
stacking_context
root_stacking_context.build_display_list(builder);
}
pub fn print(&self) {