aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Robinson <mrobinson@igalia.com>2020-05-11 14:56:35 +0200
committerMartin Robinson <mrobinson@igalia.com>2020-05-11 15:03:29 +0200
commita637810df39b05dd46c521ffdfba5ab66483520c (patch)
tree69ddd8b4aba23f0c64aed8e86ad25ec52000b95d
parent4d541e8e381e3b3388dd1d1378d147e22197b11d (diff)
downloadservo-a637810df39b05dd46c521ffdfba5ab66483520c.tar.gz
servo-a637810df39b05dd46c521ffdfba5ab66483520c.zip
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.
-rw-r--r--components/layout_2020/display_list/stacking_context.rs125
-rw-r--r--components/layout_2020/flow/root.rs2
-rw-r--r--tests/wpt/metadata-layout-2020/css/css-transforms/css-transform-3d-transform-style.html.ini2
-rw-r--r--tests/wpt/metadata-layout-2020/css/css-transforms/transform3d-sorting-005.html.ini2
4 files changed, 79 insertions, 52 deletions
diff --git a/components/layout_2020/display_list/stacking_context.rs b/components/layout_2020/display_list/stacking_context.rs
index da95531aecc..c31e35aa637 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<ServoArc<ComputedValues>>,
@@ -145,10 +149,12 @@ pub(crate) struct StackingContext {
impl StackingContext {
pub(crate) fn new(
+ spatial_id: wr::SpatialId,
initializing_fragment_style: ServoArc<ComputedValues>,
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<Fragment>,
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<Fragment>,
+ 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 adbcb26d4c9..09b5b95bb98 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 71847b8bbb1..00000000000
--- 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 a928b349949..00000000000
--- 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