diff --git a/components/layout/display_list/stacking_context.rs b/components/layout/display_list/stacking_context.rs index 0c0def9a563..9809e428d6e 100644 --- a/components/layout/display_list/stacking_context.rs +++ b/components/layout/display_list/stacking_context.rs @@ -530,7 +530,7 @@ impl StackingContext { if effects.filter.0.is_empty() && effects.opacity == 1.0 && effects.mix_blend_mode == ComputedMixBlendMode::Normal && - !style.has_transform_or_perspective(FragmentFlags::empty()) && + !style.has_effective_transform_or_perspective(FragmentFlags::empty()) && style.clone_clip_path() == ClipPath::None { return false; @@ -1584,7 +1584,10 @@ impl BoxFragment { &self, containing_block_rect: &PhysicalRect, ) -> Option { - if !self.style.has_transform_or_perspective(self.base.flags) { + if !self + .style + .has_effective_transform_or_perspective(self.base.flags) + { return None; } diff --git a/components/layout/style_ext.rs b/components/layout/style_ext.rs index c28511766b2..b157be914e0 100644 --- a/components/layout/style_ext.rs +++ b/components/layout/style_ext.rs @@ -320,7 +320,8 @@ pub(crate) trait ComputedValuesExt { containing_block_writing_mode: WritingMode, ) -> LogicalSides>; fn is_transformable(&self, fragment_flags: FragmentFlags) -> bool; - fn has_transform_or_perspective(&self, fragment_flags: FragmentFlags) -> bool; + fn has_transform_or_perspective_style(&self) -> bool; + fn has_effective_transform_or_perspective(&self, fragment_flags: FragmentFlags) -> bool; fn z_index_applies(&self, fragment_flags: FragmentFlags) -> bool; fn effective_z_index(&self, fragment_flags: FragmentFlags) -> i32; fn effective_overflow(&self, fragment_flags: FragmentFlags) -> AxesOverflow; @@ -522,15 +523,20 @@ impl ComputedValuesExt for ComputedValues { !self.is_inline_box(fragment_flags) } - /// Returns true if this style has a transform, or perspective property set and + /// Returns true if this style has a transform or perspective property set. + fn has_transform_or_perspective_style(&self) -> bool { + !self.get_box().transform.0.is_empty() || + self.get_box().scale != GenericScale::None || + self.get_box().rotate != GenericRotate::None || + self.get_box().translate != GenericTranslate::None || + self.get_box().perspective != Perspective::None + } + + /// Returns true if this style has a transform or perspective property set, and /// it applies to this element. - fn has_transform_or_perspective(&self, fragment_flags: FragmentFlags) -> bool { - self.is_transformable(fragment_flags) && - (!self.get_box().transform.0.is_empty() || - self.get_box().scale != GenericScale::None || - self.get_box().rotate != GenericRotate::None || - self.get_box().translate != GenericTranslate::None || - self.get_box().perspective != Perspective::None) + #[inline] + fn has_effective_transform_or_perspective(&self, fragment_flags: FragmentFlags) -> bool { + self.is_transformable(fragment_flags) && self.has_transform_or_perspective_style() } /// Whether the `z-index` property applies to this fragment. @@ -705,7 +711,6 @@ impl ComputedValuesExt for ComputedValues { if self.is_transformable(fragment_flags) && (!self.get_box().transform.0.is_empty() || self.get_box().transform_style == ComputedTransformStyle::Preserve3d || - self.get_box().perspective != Perspective::None || will_change_bits .intersects(WillChangeBits::TRANSFORM | WillChangeBits::PERSPECTIVE)) { @@ -795,29 +800,43 @@ impl ComputedValuesExt for ComputedValues { &self, fragment_flags: FragmentFlags, ) -> bool { - if self.has_transform_or_perspective(fragment_flags) { - return true; - } - - if !self.get_effects().filter.0.is_empty() { - return true; - } - - // See . - if self.is_transformable(fragment_flags) && - self.get_box().transform_style == ComputedTransformStyle::Preserve3d - { - return true; - } // From : // > If any non-initial value of a property would cause the element to generate a // > containing block for fixed positioned elements, specifying that property in will-change // > must cause the element to generate a containing block for fixed positioned elements. let will_change_bits = self.clone_will_change().bits; - if will_change_bits.intersects(WillChangeBits::FIXPOS_CB_NON_SVG) || - (will_change_bits - .intersects(WillChangeBits::TRANSFORM | WillChangeBits::PERSPECTIVE) && - self.is_transformable(fragment_flags)) + + // From : + // > any value other than `none` for the `transform` property also causes the element + // > to establish a containing block for all descendants. + // + // From + // > all other values […] create a stacking context and containing block for all + // > descendants, per usual for transforms. + // + // From : + // > The use of this property with any value other than `none` […] establishes a + // > containing block for all descendants, just like the `transform` property does. + // + // From : + // > A computed value of `preserve-3d` for `transform-style` on a transformable element + // > establishes both a stacking context and a containing block for all descendants. + if self.is_transformable(fragment_flags) && + (self.has_transform_or_perspective_style() || + self.get_box().transform_style == ComputedTransformStyle::Preserve3d || + will_change_bits + .intersects(WillChangeBits::TRANSFORM | WillChangeBits::PERSPECTIVE)) + { + return true; + } + + // From : + // > A value other than none for the filter property results in the creation of a containing + // > block for absolute and fixed positioned descendants unless the element it applies to is + // > a document root element in the current browsing context. + // FIXME(#35391): Need to check if this is the root element. + if !self.get_effects().filter.0.is_empty() || + will_change_bits.intersects(WillChangeBits::FIXPOS_CB_NON_SVG) { return true; }