layout: Make transform-style: preserve-3d establish a containing block for all descendants (#35808)

* layout: Fix behavior of `transform-style: preserve-3d`

This makes `transform-style: preserve-3d` establish a containing block
for all descendants, as specified here:
<https://drafts.csswg.org/css-transforms-2/#transform-style-property>

Signed-off-by: Daniel Hast <hast.daniel@protonmail.com>

* layout: Check for transformable elements

Adds a new `is_transformable` helper method and use this in several other
methods, including the methods for whether the fragment establishes a
new stacking context or a containing block for all descendants.

Signed-off-by: Daniel Hast <hast.daniel@protonmail.com>

* Use generic green square reference for reftest.

Signed-off-by: Daniel Hast <hast.daniel@protonmail.com>

* layout: Fix stacking context & containing block checks.

Only the computed value of `transform-style` should be used to determine
whether the element establishes a stacking context and/or a containing
block, not the used value.

Signed-off-by: Daniel Hast <hast.daniel@protonmail.com>

* Update clip-no-stacking-context test expectation to pass.

Signed-off-by: Daniel Hast <hast.daniel@protonmail.com>

---------

Signed-off-by: Daniel Hast <hast.daniel@protonmail.com>
This commit is contained in:
Daniel Hast 2025-03-07 12:39:59 -05:00 committed by GitHub
parent 991635eefb
commit 34b000c86e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 50 additions and 14 deletions

View file

@ -283,6 +283,7 @@ pub(crate) trait ComputedValuesExt {
&self,
containing_block_writing_mode: WritingMode,
) -> LogicalSides<LengthPercentageOrAuto<'_>>;
fn is_transformable(&self, fragment_flags: FragmentFlags) -> bool;
fn has_transform_or_perspective(&self, fragment_flags: FragmentFlags) -> bool;
fn effective_z_index(&self, fragment_flags: FragmentFlags) -> i32;
fn effective_overflow(&self, fragment_flags: FragmentFlags) -> AxesOverflow;
@ -463,9 +464,8 @@ impl ComputedValuesExt for ComputedValues {
LogicalSides::from_physical(&self.physical_margin(), containing_block_writing_mode)
}
/// 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 {
/// Returns true if this is a transformable element.
fn is_transformable(&self, fragment_flags: FragmentFlags) -> bool {
// "A transformable element is an element in one of these categories:
// * all elements whose layout is governed by the CSS box model except for
// non-replaced inline boxes, table-column boxes, and table-column-group
@ -473,14 +473,18 @@ impl ComputedValuesExt for ComputedValues {
// * all SVG paint server elements, the clipPath element and SVG renderable
// elements with the exception of any descendant element of text content
// elements."
// https://drafts.csswg.org/css-transforms/#transformable-element
if self.get_box().display.is_inline_flow() &&
!fragment_flags.contains(FragmentFlags::IS_REPLACED)
{
return false;
}
// <https://drafts.csswg.org/css-transforms/#transformable-element>
// TODO: check for all cases listed in the above spec.
!self.get_box().display.is_inline_flow() ||
fragment_flags.contains(FragmentFlags::IS_REPLACED)
}
!self.get_box().transform.0.is_empty() || 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().perspective != Perspective::None)
}
/// Get the effective z-index of this fragment. Z-indices only apply to positioned elements
@ -614,8 +618,9 @@ impl ComputedValuesExt for ComputedValues {
return true;
}
if self.get_box().transform_style == ComputedTransformStyle::Preserve3d ||
self.overrides_transform_style()
// See <https://drafts.csswg.org/css-transforms-2/#transform-style-property>.
if self.is_transformable(fragment_flags) &&
self.get_box().transform_style == ComputedTransformStyle::Preserve3d
{
return true;
}
@ -688,6 +693,13 @@ impl ComputedValuesExt for ComputedValues {
return true;
}
// See <https://drafts.csswg.org/css-transforms-2/#transform-style-property>.
if self.is_transformable(fragment_flags) &&
self.get_box().transform_style == ComputedTransformStyle::Preserve3d
{
return true;
}
// TODO: We need to handle CSS Contain here.
false
}