From a637810df39b05dd46c521ffdfba5ab66483520c Mon Sep 17 00:00:00 2001 From: Martin Robinson Date: Mon, 11 May 2020 14:56:35 +0200 Subject: [PATCH] layout_2020: Add support for transform-style This requires creating a matching stacking context for every reference frame and also properly placing those stacking contexts inside them. --- .../display_list/stacking_context.rs | 125 +++++++++++------- components/layout_2020/flow/root.rs | 2 +- .../css-transform-3d-transform-style.html.ini | 2 - .../transform3d-sorting-005.html.ini | 2 - 4 files changed, 79 insertions(+), 52 deletions(-) delete mode 100644 tests/wpt/metadata-layout-2020/css/css-transforms/css-transform-3d-transform-style.html.ini delete mode 100644 tests/wpt/metadata-layout-2020/css/css-transforms/transform3d-sorting-005.html.ini diff --git a/components/layout_2020/display_list/stacking_context.rs b/components/layout_2020/display_list/stacking_context.rs index da95531aecc2..c31e35aa637e 100644 --- a/components/layout_2020/display_list/stacking_context.rs +++ b/components/layout_2020/display_list/stacking_context.rs @@ -126,6 +126,10 @@ pub(crate) enum StackingContextType { } pub(crate) struct StackingContext { + /// The spatial id of this fragment. This is used to properly handle + /// things like preserve-3d. + spatial_id: wr::SpatialId, + /// The fragment that established this stacking context. initializing_fragment_style: Option>, @@ -145,10 +149,12 @@ pub(crate) struct StackingContext { impl StackingContext { pub(crate) fn new( + spatial_id: wr::SpatialId, initializing_fragment_style: ServoArc, context_type: StackingContextType, ) -> Self { Self { + spatial_id, initializing_fragment_style: Some(initializing_fragment_style), context_type, fragments: vec![], @@ -157,8 +163,9 @@ impl StackingContext { } } - pub(crate) fn create_root() -> Self { + pub(crate) fn create_root(wr: &wr::DisplayListBuilder) -> Self { Self { + spatial_id: wr::SpaceAndClipInfo::root_scroll(wr.pipeline_id).spatial_id, initializing_fragment_style: None, context_type: StackingContextType::Real, fragments: vec![], @@ -198,16 +205,18 @@ impl StackingContext { &self, builder: &'a mut DisplayListBuilder, ) -> bool { - let effects = match self.initializing_fragment_style.as_ref() { - Some(style) => style.get_effects(), + let style = match self.initializing_fragment_style.as_ref() { + Some(style) => style, 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 effects = style.get_effects(); if effects.filter.0.is_empty() && effects.opacity == 1.0 && - effects.mix_blend_mode == ComputedMixBlendMode::Normal + effects.mix_blend_mode == ComputedMixBlendMode::Normal && + !style.has_transform_or_perspective() { return false; } @@ -227,11 +236,11 @@ impl StackingContext { } builder.wr.push_stacking_context( - LayoutPoint::zero(), // origin - builder.current_space_and_clip.spatial_id, // spatial_id + LayoutPoint::zero(), // origin + self.spatial_id, wr::PrimitiveFlags::default(), None, // clip_id - wr::TransformStyle::Flat, + style.get_used_transform_style().to_webrender(), effects.mix_blend_mode.to_webrender(), &filters, &vec![], // filter_datas @@ -423,8 +432,16 @@ impl BoxFragment { builder.clipping_and_scrolling_scope(|builder| { self.adjust_spatial_id_for_positioning(builder); - let context_type = match self.get_stacking_context_type() { - Some(context_type) => context_type, + match self.get_stacking_context_type() { + Some(context_type) => { + self.build_stacking_context_tree_creating_stacking_context( + fragment, + builder, + containing_block_info, + stacking_context, + context_type, + ); + }, None => { self.build_stacking_context_tree_for_children( fragment, @@ -432,43 +449,21 @@ impl BoxFragment { containing_block_info, stacking_context, ); - return; }, - }; - - let mut child_stacking_context = StackingContext::new(self.style.clone(), context_type); - self.build_stacking_context_tree_for_children( - fragment, - builder, - containing_block_info, - &mut child_stacking_context, - ); - - let mut stolen_children = vec![]; - if context_type != StackingContextType::Real { - stolen_children = mem::replace( - &mut child_stacking_context.stacking_contexts, - stolen_children, - ); } - - child_stacking_context.sort(); - stacking_context - .stacking_contexts - .push(child_stacking_context); - stacking_context - .stacking_contexts - .append(&mut stolen_children); }); } - fn build_stacking_context_tree_for_children<'a>( - &'a self, + fn build_stacking_context_tree_creating_stacking_context( + &self, fragment: &ArcRefCell, builder: &mut StackingContextBuilder, containing_block_info: &ContainingBlockInfo, - stacking_context: &mut StackingContext, + parent_stacking_context: &mut StackingContext, + context_type: StackingContextType, ) { + // If we are creating a stacking context, we may also need to create a reference + // frame first. let relative_border_rect = self .border_rect() .to_physical(self.style.writing_mode, &containing_block_info.rect); @@ -477,32 +472,72 @@ impl BoxFragment { let established_reference_frame = self.build_reference_frame_if_necessary(builder, &border_rect); - let mut new_containing_block_info = containing_block_info.clone(); - // WebRender reference frames establish a new coordinate system at their origin // (the border box of the fragment). We need to ensure that any coordinates we // give to WebRender in this reference frame are relative to the fragment border // box. We do this by adjusting the containing block origin. + let mut new_containing_block_info = containing_block_info.clone(); if established_reference_frame { new_containing_block_info.rect.origin = (-relative_border_rect.origin.to_vector()).to_point(); } + let mut child_stacking_context = StackingContext::new( + builder.current_space_and_clip.spatial_id, + self.style.clone(), + context_type, + ); + self.build_stacking_context_tree_for_children( + fragment, + builder, + &new_containing_block_info, + &mut child_stacking_context, + ); + + let mut stolen_children = vec![]; + if context_type != StackingContextType::Real { + stolen_children = mem::replace( + &mut child_stacking_context.stacking_contexts, + stolen_children, + ); + } + + child_stacking_context.sort(); + parent_stacking_context + .stacking_contexts + .push(child_stacking_context); + parent_stacking_context + .stacking_contexts + .append(&mut stolen_children); + + if established_reference_frame { + builder.wr.pop_reference_frame(); + } + } + + fn build_stacking_context_tree_for_children<'a>( + &'a self, + fragment: &ArcRefCell, + builder: &mut StackingContextBuilder, + containing_block_info: &ContainingBlockInfo, + stacking_context: &mut StackingContext, + ) { stacking_context.fragments.push(StackingContextFragment { space_and_clip: builder.current_space_and_clip, section: self.get_stacking_context_section(), - containing_block: new_containing_block_info.rect, + containing_block: containing_block_info.rect, fragment: fragment.clone(), }); // We want to build the scroll frame after the background and border, because // they shouldn't scroll with the rest of the box content. - self.build_scroll_frame_if_necessary(builder, &new_containing_block_info); + self.build_scroll_frame_if_necessary(builder, containing_block_info); let padding_rect = self .padding_rect() - .to_physical(self.style.writing_mode, &new_containing_block_info.rect) - .translate(new_containing_block_info.rect.origin.to_vector()); + .to_physical(self.style.writing_mode, &containing_block_info.rect) + .translate(containing_block_info.rect.origin.to_vector()); + let mut new_containing_block_info = containing_block_info.clone(); new_containing_block_info.rect = self .content_rect .to_physical(self.style.writing_mode, &new_containing_block_info.rect) @@ -522,10 +557,6 @@ impl BoxFragment { StackingContextBuildMode::SkipHoisted, ); } - - if established_reference_frame { - builder.wr.pop_reference_frame(); - } } fn adjust_spatial_id_for_positioning(&self, builder: &mut StackingContextBuilder) { diff --git a/components/layout_2020/flow/root.rs b/components/layout_2020/flow/root.rs index adbcb26d4c9a..09b5b95bb984 100644 --- a/components/layout_2020/flow/root.rs +++ b/components/layout_2020/flow/root.rs @@ -196,7 +196,7 @@ impl BoxTreeRoot { impl FragmentTreeRoot { pub fn build_display_list(&self, builder: &mut crate::display_list::DisplayListBuilder) { - let mut stacking_context = StackingContext::create_root(); + let mut stacking_context = StackingContext::create_root(&builder.wr); { let mut stacking_context_builder = StackingContextBuilder::new(&mut builder.wr); let containing_block_info = ContainingBlockInfo { diff --git a/tests/wpt/metadata-layout-2020/css/css-transforms/css-transform-3d-transform-style.html.ini b/tests/wpt/metadata-layout-2020/css/css-transforms/css-transform-3d-transform-style.html.ini deleted file mode 100644 index 71847b8bbb14..000000000000 --- a/tests/wpt/metadata-layout-2020/css/css-transforms/css-transform-3d-transform-style.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[css-transform-3d-transform-style.html] - expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/css-transforms/transform3d-sorting-005.html.ini b/tests/wpt/metadata-layout-2020/css/css-transforms/transform3d-sorting-005.html.ini deleted file mode 100644 index a928b349949a..000000000000 --- a/tests/wpt/metadata-layout-2020/css/css-transforms/transform3d-sorting-005.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[transform3d-sorting-005.html] - expected: FAIL