From 34b000c86ebae8bc2b59cbceaa3b906cb04f04fb Mon Sep 17 00:00:00 2001 From: Daniel Hast <32797673+HastD@users.noreply.github.com> Date: Fri, 7 Mar 2025 12:39:59 -0500 Subject: [PATCH] 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: Signed-off-by: Daniel Hast * 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 * Use generic green square reference for reftest. Signed-off-by: Daniel Hast * 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 * Update clip-no-stacking-context test expectation to pass. Signed-off-by: Daniel Hast --------- Signed-off-by: Daniel Hast --- components/layout_2020/style_ext.rs | 36 ++++++++++++------- tests/wpt/meta/MANIFEST.json | 13 +++++++ .../clip/clip-no-stacking-context.html.ini | 2 -- .../preserve3d-containing-block.html | 13 +++++++ 4 files changed, 50 insertions(+), 14 deletions(-) delete mode 100644 tests/wpt/meta/css/css-masking/clip/clip-no-stacking-context.html.ini create mode 100644 tests/wpt/tests/css/css-transforms/preserve3d-containing-block.html diff --git a/components/layout_2020/style_ext.rs b/components/layout_2020/style_ext.rs index af612191172..c00998a469b 100644 --- a/components/layout_2020/style_ext.rs +++ b/components/layout_2020/style_ext.rs @@ -283,6 +283,7 @@ pub(crate) trait ComputedValuesExt { &self, 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 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; - } + // + // 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 . + 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 . + if self.is_transformable(fragment_flags) && + self.get_box().transform_style == ComputedTransformStyle::Preserve3d + { + return true; + } + // TODO: We need to handle CSS Contain here. false } diff --git a/tests/wpt/meta/MANIFEST.json b/tests/wpt/meta/MANIFEST.json index 9a27a0a6c3d..d4744c48760 100644 --- a/tests/wpt/meta/MANIFEST.json +++ b/tests/wpt/meta/MANIFEST.json @@ -276759,6 +276759,19 @@ {} ] ], + "preserve3d-containing-block.html": [ + "fc74e3874c67a2965b549036dd6699d593eeb3ef", + [ + null, + [ + [ + "/css/reference/ref-filled-green-100px-square.xht", + "==" + ] + ], + {} + ] + ], "preserve3d-nested-perspective.html": [ "368784c74f51c774cf8ea1b6f55127e72fd5854e", [ diff --git a/tests/wpt/meta/css/css-masking/clip/clip-no-stacking-context.html.ini b/tests/wpt/meta/css/css-masking/clip/clip-no-stacking-context.html.ini deleted file mode 100644 index d9d6ef6d208..00000000000 --- a/tests/wpt/meta/css/css-masking/clip/clip-no-stacking-context.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[clip-no-stacking-context.html] - expected: FAIL diff --git a/tests/wpt/tests/css/css-transforms/preserve3d-containing-block.html b/tests/wpt/tests/css/css-transforms/preserve3d-containing-block.html new file mode 100644 index 00000000000..fc74e3874c6 --- /dev/null +++ b/tests/wpt/tests/css/css-transforms/preserve3d-containing-block.html @@ -0,0 +1,13 @@ + + +CSS test: "transform-style: preserve-3d" should establish a containing block for all descendants + + + + +

Test passes if there is a filled green square and no red.

+