Bug 230079 - Some css-transforms tests assert in debug
Summary: Some css-transforms tests assert in debug
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: Layout and Rendering (show other bugs)
Version: Safari Technology Preview
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Martin Robinson
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2021-09-08 20:31 PDT by Simon Fraser (smfr)
Modified: 2022-01-11 05:47 PST (History)
14 users (show)

See Also:


Attachments
Patch (7.28 KB, patch)
2022-01-10 02:57 PST, Martin Robinson
no flags Details | Formatted Diff | Diff
Patch (7.37 KB, patch)
2022-01-10 08:57 PST, Martin Robinson
no flags Details | Formatted Diff | Diff
Patch (7.65 KB, patch)
2022-01-11 04:33 PST, Martin Robinson
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Simon Fraser (smfr) 2021-09-08 20:31:31 PDT
These tests:

imported/w3c/web-platform-tests/css/css-transforms/transform-transformed-tbody-contains-fixed-position.html
imported/w3c/web-platform-tests/css/css-transforms/transform-transformed-tfoot-contains-fixed-position.html
imported/w3c/web-platform-tests/css/css-transforms/transform-transformed-thead-contains-fixed-position.html
imported/w3c/web-platform-tests/css/css-transforms/transform-transformed-tr-contains-fixed-position.html
imported/w3c/web-platform-tests/css/css-transforms/transform-transformed-tr-percent-height-child.html

hit an assertion:

Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0   com.apple.JavaScriptCore      	0x00000003da6a4a9e WTFCrash + 14 (Assertions.cpp:321)
1   com.apple.WebCore             	0x00000003bb25c96b WTFCrashWithInfo(int, char const*, char const*, int) + 27 (Assertions.h:703)
2   com.apple.WebCore             	0x00000003bfa2b4c6 WebCore::RenderObject::offsetFromAncestorContainer(WebCore::RenderElement&) const + 262 (RenderObject.cpp:1446)
3   com.apple.WebCore             	0x00000003bf897dae WebCore::RenderBox::pushMappingToContainer(WebCore::RenderLayerModelObject const*, WebCore::RenderGeometryMap&) const + 238 (RenderBox.cpp:2291)
4   com.apple.WebCore             	0x00000003bf93bfab WebCore::RenderGeometryMap::pushMappingsToAncestor(WebCore::RenderObject const*, WebCore::RenderLayerModelObject const*) + 91 (RenderGeometryMap.cpp:140)
5   com.apple.WebCore             	0x00000003bf93c3a6 WebCore::RenderGeometryMap::pushMappingsToAncestor(WebCore::RenderLayer const*, WebCore::RenderLayer const*, bool) + 598 (RenderGeometryMap.cpp:197)
6   com.apple.WebCore             	0x00000003bf971313 WebCore::RenderLayer::updateLayerPositions(WebCore::RenderGeometryMap*, WTF::OptionSet<WebCore::RenderLayer::UpdateLayerPositionsFlag>) + 179 (RenderLayer.cpp:941)
7   com.apple.WebCore             	0x00000003bf971b28 WebCore::RenderLayer::updateLayerPositions(WebCore::RenderGeometryMap*, WTF::OptionSet<WebCore::RenderLayer::UpdateLayerPositionsFlag>) + 2248 (RenderLayer.cpp:1032)
8   com.apple.WebCore             	0x00000003bf971b28 WebCore::RenderLayer::updateLayerPositions(WebCore::RenderGeometryMap*, WTF::OptionSet<WebCore::RenderLayer::UpdateLayerPositionsFlag>) + 2248 (RenderLayer.cpp:1032)
9   com.apple.WebCore             	0x00000003bf971b28 WebCore::RenderLayer::updateLayerPositions(WebCore::RenderGeometryMap*, WTF::OptionSet<WebCore::RenderLayer::UpdateLayerPositionsFlag>) + 2248 (RenderLayer.cpp:1032)
10  com.apple.WebCore             	0x00000003bf971b28 WebCore::RenderLayer::updateLayerPositions(WebCore::RenderGeometryMap*, WTF::OptionSet<WebCore::RenderLayer::UpdateLayerPositionsFlag>) + 2248 (RenderLayer.cpp:1032)
11  com.apple.WebCore             	0x00000003bf971e0b WebCore::RenderLayer::updateLayerPositionsAfterLayout(bool, bool) + 219 (RenderLayer.cpp:931)
12  com.apple.WebCore             	0x00000003bef1179e WebCore::FrameView::didLayout(WTF::WeakPtr<WebCore::RenderElement, WTF::EmptyCounter>) + 142 (FrameView.cpp:1297)
13  com.apple.WebCore             	0x00000003bef06dac WebCore::FrameViewLayoutContext::layout() + 2828 (FrameViewLayoutContext.cpp:260)
14  com.apple.WebCore             	0x00000003bef1a8b0 WebCore::FrameView::updateContentsSize() + 112 (FrameView.cpp:2780)
15  com.apple.WebCore             	0x00000003bf15376c WebCore::ScrollView::updateScrollbars(WebCore::IntPoint const&) + 2668 (ScrollView.cpp:711)
16  com.apple.WebCore             	0x00000003bf155320 WebCore::ScrollView::setContentsSize(WebCore::IntSize const&) + 160 (ScrollView.cpp:403)
17  com.apple.WebCore             	0x00000003bef0c73f WebCore::FrameView::setContentsSize(WebCore::IntSize const&) + 111 (FrameView.cpp:590)
18  com.apple.WebCore             	0x00000003bef039bb WebCore::FrameView::adjustViewSize() + 747 (FrameView.cpp:622)
19  com.apple.WebCore             	0x00000003bef06c21 WebCore::FrameViewLayoutContext::layout() + 2433 (FrameViewLayoutContext.cpp:248)
...
Comment 1 Radar WebKit Bug Importer 2021-09-15 20:32:17 PDT
<rdar://problem/83179970>
Comment 2 Martin Robinson 2022-01-10 02:57:00 PST
Created attachment 448730 [details]
Patch
Comment 3 Nikolas Zimmermann 2022-01-10 06:15:48 PST
Comment on attachment 448730 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=448730&action=review

Thanks Martin for the patch. Here's an unofficial review / some thoughts:

> Source/WebCore/rendering/RenderElement.h:88
> +    // Whether or not this RenderObject is a "transformable element" as defined by the css-transforms-1 specification.

Strictly speaking this is mixing terminology: The "transformable element" definition refers to DOM elements, whereas you attempt to define whether or not a RenderElement is transformable (whatever this means).
The name 'isTransformable' is quite broad, whereas you only check CSS transformations here -- there are RenderElements in the render tree that are transformed by other means, such as RenderSVG* (inheriting from RenderElement, via LegacyRenderSVGModelObject). However SVG transforms aren't considered in your isTransformable() definition... the name needs to be re-visited.

> Source/WebCore/rendering/RenderElement.h:484
> +    return isBoxModelObject() && !isRenderInline() && !isRenderTableCol();

This is an observable change: any RenderBoxModelObject derived renderer is now considered transformable (if it's not RenderInline-derived or RenderTableCol). Observable in the sense, that you're potentially influencing the RenderLayer hierarchy creation, where these canContainXXX methods are used. Therefore we need to be very careful with the conditions that are checked here.
You return true in isTransformable() for basically all RenderBox-derived classes, such as Render{Replaced|TableRow|TableSection|...} (therefore also LegacyRenderSVGRoot), except the two cases that you excluded: RenderTableCol/RenderInline. Are all the cases covered by WPT tests? (need to make a list of affected renderers...)

However, do we really need to define isTransformable here?

To answer if an element "can contain fixed position / absolutely positioned objects", one needs to find out if the given renderer can establish a containing block for its descendants, which happens to be the case for all "transformed elements", according to CSS Transforms Level 1: "For elements whose layout is governed by the CSS box model, any value other than none for the transform property also causes the element to establish a containing block for all descendants."

You could move both "isTransformable() && hasTransform()" into a establishesContainingBlockDueToTransformations() method, that returns false if no CSS transform property is set, or otherwise consult an "accept list", to see if the current renderer respects CSS transformations (there you can return false for all SVG enderers, except RenderSVGForeignObject). In this way you can also fold the "|| isSVGForeignObject()" check from canContainXY into the new establishesContainingBlockDueToTransformations() method.

Alternatively you could also obtain the containingBlock() for the renderer, and check it's == this, however this is way more expensive than some is<RenderXY>() checks + hasTransform(), and potentially dangerous during render tree building, so ... stay away from it :-)

(Side-Note: I naively expected both canContainXY methods to check the same: hasTransform not hasTransformRelatedProperty -- that needs a careful check first, why these checks are not identical)
Comment 4 Martin Robinson 2022-01-10 08:15:40 PST
(In reply to Nikolas Zimmermann from comment #3)
> Comment on attachment 448730 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=448730&action=review
> 
> Thanks Martin for the patch. Here's an unofficial review / some thoughts:

Thanks for the review! 

> > Source/WebCore/rendering/RenderElement.h:88
> > +    // Whether or not this RenderObject is a "transformable element" as defined by the css-transforms-1 specification.
> 
> Strictly speaking this is mixing terminology: The "transformable element"
> definition refers to DOM elements, whereas you attempt to define whether or
> not a RenderElement is transformable (whatever this means).
> The name 'isTransformable' is quite broad, whereas you only check CSS
> transformations here -- there are RenderElements in the render tree that are
> transformed by other means, such as RenderSVG* (inheriting from
> RenderElement, via LegacyRenderSVGModelObject). However SVG transforms
> aren't considered in your isTransformable() definition... the name needs to
> be re-visited.

This is a good point. 
 
> > Source/WebCore/rendering/RenderElement.h:484
> > +    return isBoxModelObject() && !isRenderInline() && !isRenderTableCol();
> 
> This is an observable change: any RenderBoxModelObject derived renderer is
> now considered transformable (if it's not RenderInline-derived or
> RenderTableCol). Observable in the sense, that you're potentially
> influencing the RenderLayer hierarchy creation, where these canContainXXX
> methods are used. Therefore we need to be very careful with the conditions
> that are checked here.
> You return true in isTransformable() for basically all RenderBox-derived
> classes, such as Render{Replaced|TableRow|TableSection|...} (therefore also
> LegacyRenderSVGRoot), except the two cases that you excluded:
> RenderTableCol/RenderInline. Are all the cases covered by WPT tests? (need
> to make a list of affected renderers...)

You're right, I think. It's best to target this fix as much as possible until there's test coverage for other cases.

> You could move both "isTransformable() && hasTransform()" into a
> establishesContainingBlockDueToTransformations() method, that returns false
> if no CSS transform property is set, or otherwise consult an "accept list",
> to see if the current renderer respects CSS transformations (there you can
> return false for all SVG enderers, except RenderSVGForeignObject). In this
> way you can also fold the "|| isSVGForeignObject()" check from canContainXY
> into the new establishesContainingBlockDueToTransformations() method.

I've taken this approach and just explicitly added table parts. There is testing for table parts and this change leads to a progression for these tests (though doesn't completely fix them).

> 
> Alternatively you could also obtain the containingBlock() for the renderer,
> and check it's == this, however this is way more expensive than some
> is<RenderXY>() checks + hasTransform(), and potentially dangerous during
> render tree building, so ... stay away from it :-)

I'm not sure this will work, because `containingBlock()` calls `canContainAbsolutelyPositionedObjects()` and `canContainFixedPositionObjects()`. :)

> 
> (Side-Note: I naively expected both canContainXY methods to check the same:
> hasTransform not hasTransformRelatedProperty -- that needs a careful check
> first, why these checks are not identical)

Totally agree here. This should be investigated and addressed if it's wrong (though in a different change).
Comment 5 Martin Robinson 2022-01-10 08:57:00 PST
Created attachment 448756 [details]
Patch
Comment 6 Rob Buis 2022-01-10 11:08:52 PST
Martin, you may want to unskip top-layer-ancestor-opacity-and-transform-crash.html in this patch when landing this patch (see https://bugs.webkit.org/show_bug.cgi?id=234315).
Comment 7 Martin Robinson 2022-01-11 04:16:31 PST
(In reply to Rob Buis from comment #6)
> Martin, you may want to unskip
> top-layer-ancestor-opacity-and-transform-crash.html in this patch when
> landing this patch (see https://bugs.webkit.org/show_bug.cgi?id=234315).

I took a look at this test and it seems like it's a slightly different issue. This one is about table elements which are transformed and the assertion failure you mention is about top layer elements with a transformed body. I suspect that the fix will be a bit different for that issue.
Comment 8 EWS 2022-01-11 04:23:15 PST
Tools/Scripts/svn-apply failed to apply attachment 448756 [details] to trunk.
Please resolve the conflicts and upload a new patch.
Comment 9 Martin Robinson 2022-01-11 04:33:26 PST
Created attachment 448838 [details]
Patch
Comment 10 EWS 2022-01-11 05:47:00 PST
Committed r287875 (245919@main): <https://commits.webkit.org/245919@main>

All reviewed patches have been landed. Closing bug and clearing flags on attachment 448838 [details].