Title: [293504] trunk/Source/WebCore
Revision
293504
Author
commit-qu...@webkit.org
Date
2022-04-27 04:14:44 -0700 (Wed, 27 Apr 2022)

Log Message

[LBSE] Fix origin of transformations in SVG
https://bugs.webkit.org/show_bug.cgi?id=239717

Patch by Nikolas Zimmermann <nzimmerm...@igalia.com> on 2022-04-27
Reviewed by Rob Buis.

Fix the majority of SVG transform issues in LBSE. webkit.org/b/237711 laid the groundwork for SVG
transforms in LBSE, however there are still issues:

- SVG transforms specified alone on SVG elements, w/o any additional style/perspective related property
  such as transform-box / transform-origin / ... do not trigger layer creation, fix by adapting StyleAdjuster.

- Switching on/off transforms for a SVG element, was not tracking updates to both 'HasSVGTransform' and
  'HasTransformRelatedProperty' flags correctly, fix that by introducing an 'updateHasSVGTransformFlags' helper.

- Modify SVGContainerLayout to avoid a dependency on the children transformations when computing container
  boundaries. In the legacy engine, we always have to mark the whole ancestor chain as 'need to recompute boundaries'
  and invoking a re-layout, to perform the recomputation. This change avoids the invalidation of the whole ancestor
  chain, when an elements transform changes in a non-accelerated way (e.g. SVGTransformList manipulation, SMIL
  <animateTransform> / <animate> / <set>). In CSS transformations do not affect layout, only hit-testing and painting.

  -> SVG/CSS transforms applied on SVG elements is conceptually equivalent to CSS transformations on CSS boxes now.
     Transformation changes no longer affect the 'internal geometry' (objectBoundingBoxWithoutTransformations()).
     currentSVGLayoutLocation() / nominalSVGLayoutLocation() are computed using the 'internal geometry' and used
     throughout layout.

  This avoids most of the RenderLayer / RenderLayerBacking specific changes that were present in the downstream
  LBSE implementation, while also solving an important design issue: no back-splash from children to parents.
  Large, deep nested documents -- as seen in the wild -- will benefit the most, avoiding the frequent ancestor
  walks to mark the containing block / parent hierachy for re-layout.

Covered by existing tests, no change in behaviour. (However testability for LBSE is ready soon!).

* rendering/RenderElement.cpp:
(WebCore::RenderElement::referenceBoxRect const):
* rendering/RenderLayer.cpp:
(WebCore::RenderLayer::RenderLayer):
(WebCore::canCreateStackingContext):
(WebCore::RenderLayer::paintLayerByApplyingTransform):
* rendering/RenderLayer.h:
(WebCore::RenderLayer::rendererLocation const):
* rendering/RenderLayerModelObject.cpp:
(WebCore::RenderLayerModelObject::styleDidChange):
(WebCore::RenderLayerModelObject::computeVisibleRectInSVGContainer const):
(WebCore::RenderLayerModelObject::updateHasSVGTransformFlags):
* rendering/RenderLayerModelObject.h:
(WebCore::RenderLayerModelObject::nominalSVGLayoutLocation const):
(WebCore::RenderLayerModelObject::currentSVGLayoutLocation const):
(WebCore::RenderLayerModelObject::setCurrentSVGLayoutLocation):
* rendering/RenderObject.h:
(WebCore::RenderObject::objectBoundingBoxWithoutTransformations const):
* rendering/svg/RenderSVGBlock.h:
* rendering/svg/RenderSVGContainer.cpp:
(WebCore::RenderSVGContainer::layoutChildren):
(WebCore::RenderSVGContainer::paint):
(WebCore::RenderSVGContainer::nodeAtPoint):
(WebCore::RenderSVGContainer::styleDidChange): Deleted.
* rendering/svg/RenderSVGContainer.h:
* rendering/svg/RenderSVGInline.h:
* rendering/svg/RenderSVGModelObject.cpp:
(WebCore::RenderSVGModelObject::updateFromStyle):
(WebCore::RenderSVGModelObject::absoluteRects const):
* rendering/svg/RenderSVGModelObject.h:
(WebCore::RenderSVGModelObject::currentSVGLayoutRect const):
(WebCore::RenderSVGModelObject::setCurrentSVGLayoutRect):
(WebCore::RenderSVGModelObject::frameRectEquivalent const):
(WebCore::RenderSVGModelObject::applyTopLeftLocationOffsetEquivalent const):
(WebCore::RenderSVGModelObject::layoutRect const): Deleted.
(WebCore::RenderSVGModelObject::setLayoutRect): Deleted.
(WebCore::RenderSVGModelObject::setLayoutLocation): Deleted.
(WebCore::RenderSVGModelObject::paintingLocation const): Deleted.
(WebCore::RenderSVGModelObject::layoutLocation const): Deleted.
(WebCore::RenderSVGModelObject::layoutLocationOffset const): Deleted.
(WebCore::RenderSVGModelObject::layoutSize const): Deleted.
* rendering/svg/RenderSVGRoot.cpp:
(WebCore::RenderSVGRoot::layout):
(WebCore::RenderSVGRoot::updateFromStyle):
* rendering/svg/RenderSVGRoot.h:
* rendering/svg/RenderSVGShape.cpp:
(WebCore::RenderSVGShape::layout):
(WebCore::RenderSVGShape::paint):
(WebCore::RenderSVGShape::nodeAtPoint):
* rendering/svg/RenderSVGTransformableContainer.cpp:
(WebCore::RenderSVGTransformableContainer::updateFromStyle):
* rendering/svg/SVGBoundingBoxComputation.cpp:
(WebCore::SVGBoundingBoxComputation::handleRootOrContainer const):
* rendering/svg/SVGBoundingBoxComputation.h:
(WebCore::SVGBoundingBoxComputation::computeVisualOverflowRect):
* rendering/svg/SVGContainerLayout.cpp:
(WebCore::SVGContainerLayout::positionChildrenRelativeToContainer):
(WebCore::SVGContainerLayout::verifyLayoutLocationConsistency):
(WebCore::layoutLocationFromRenderer): Deleted.
(WebCore::setLayoutLocationForRenderer): Deleted.
* rendering/svg/SVGContainerLayout.h:
* style/StyleAdjuster.cpp:
(WebCore::Style::Adjuster::adjust const):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (293503 => 293504)


--- trunk/Source/WebCore/ChangeLog	2022-04-27 10:36:07 UTC (rev 293503)
+++ trunk/Source/WebCore/ChangeLog	2022-04-27 11:14:44 UTC (rev 293504)
@@ -1,3 +1,101 @@
+2022-04-27  Nikolas Zimmermann  <nzimmerm...@igalia.com>
+
+        [LBSE] Fix origin of transformations in SVG
+        https://bugs.webkit.org/show_bug.cgi?id=239717
+
+        Reviewed by Rob Buis.
+
+        Fix the majority of SVG transform issues in LBSE. webkit.org/b/237711 laid the groundwork for SVG
+        transforms in LBSE, however there are still issues:
+
+        - SVG transforms specified alone on SVG elements, w/o any additional style/perspective related property
+          such as transform-box / transform-origin / ... do not trigger layer creation, fix by adapting StyleAdjuster.
+
+        - Switching on/off transforms for a SVG element, was not tracking updates to both 'HasSVGTransform' and
+          'HasTransformRelatedProperty' flags correctly, fix that by introducing an 'updateHasSVGTransformFlags' helper.
+
+        - Modify SVGContainerLayout to avoid a dependency on the children transformations when computing container
+          boundaries. In the legacy engine, we always have to mark the whole ancestor chain as 'need to recompute boundaries'
+          and invoking a re-layout, to perform the recomputation. This change avoids the invalidation of the whole ancestor
+          chain, when an elements transform changes in a non-accelerated way (e.g. SVGTransformList manipulation, SMIL
+          <animateTransform> / <animate> / <set>). In CSS transformations do not affect layout, only hit-testing and painting.
+
+          -> SVG/CSS transforms applied on SVG elements is conceptually equivalent to CSS transformations on CSS boxes now.
+             Transformation changes no longer affect the 'internal geometry' (objectBoundingBoxWithoutTransformations()).
+             currentSVGLayoutLocation() / nominalSVGLayoutLocation() are computed using the 'internal geometry' and used
+             throughout layout.
+
+          This avoids most of the RenderLayer / RenderLayerBacking specific changes that were present in the downstream
+          LBSE implementation, while also solving an important design issue: no back-splash from children to parents.
+          Large, deep nested documents -- as seen in the wild -- will benefit the most, avoiding the frequent ancestor
+          walks to mark the containing block / parent hierachy for re-layout.
+
+        Covered by existing tests, no change in behaviour. (However testability for LBSE is ready soon!).
+
+        * rendering/RenderElement.cpp:
+        (WebCore::RenderElement::referenceBoxRect const):
+        * rendering/RenderLayer.cpp:
+        (WebCore::RenderLayer::RenderLayer):
+        (WebCore::canCreateStackingContext):
+        (WebCore::RenderLayer::paintLayerByApplyingTransform):
+        * rendering/RenderLayer.h:
+        (WebCore::RenderLayer::rendererLocation const):
+        * rendering/RenderLayerModelObject.cpp:
+        (WebCore::RenderLayerModelObject::styleDidChange):
+        (WebCore::RenderLayerModelObject::computeVisibleRectInSVGContainer const):
+        (WebCore::RenderLayerModelObject::updateHasSVGTransformFlags):
+        * rendering/RenderLayerModelObject.h:
+        (WebCore::RenderLayerModelObject::nominalSVGLayoutLocation const):
+        (WebCore::RenderLayerModelObject::currentSVGLayoutLocation const):
+        (WebCore::RenderLayerModelObject::setCurrentSVGLayoutLocation):
+        * rendering/RenderObject.h:
+        (WebCore::RenderObject::objectBoundingBoxWithoutTransformations const):
+        * rendering/svg/RenderSVGBlock.h:
+        * rendering/svg/RenderSVGContainer.cpp:
+        (WebCore::RenderSVGContainer::layoutChildren):
+        (WebCore::RenderSVGContainer::paint):
+        (WebCore::RenderSVGContainer::nodeAtPoint):
+        (WebCore::RenderSVGContainer::styleDidChange): Deleted.
+        * rendering/svg/RenderSVGContainer.h:
+        * rendering/svg/RenderSVGInline.h:
+        * rendering/svg/RenderSVGModelObject.cpp:
+        (WebCore::RenderSVGModelObject::updateFromStyle):
+        (WebCore::RenderSVGModelObject::absoluteRects const):
+        * rendering/svg/RenderSVGModelObject.h:
+        (WebCore::RenderSVGModelObject::currentSVGLayoutRect const):
+        (WebCore::RenderSVGModelObject::setCurrentSVGLayoutRect):
+        (WebCore::RenderSVGModelObject::frameRectEquivalent const):
+        (WebCore::RenderSVGModelObject::applyTopLeftLocationOffsetEquivalent const):
+        (WebCore::RenderSVGModelObject::layoutRect const): Deleted.
+        (WebCore::RenderSVGModelObject::setLayoutRect): Deleted.
+        (WebCore::RenderSVGModelObject::setLayoutLocation): Deleted.
+        (WebCore::RenderSVGModelObject::paintingLocation const): Deleted.
+        (WebCore::RenderSVGModelObject::layoutLocation const): Deleted.
+        (WebCore::RenderSVGModelObject::layoutLocationOffset const): Deleted.
+        (WebCore::RenderSVGModelObject::layoutSize const): Deleted.
+        * rendering/svg/RenderSVGRoot.cpp:
+        (WebCore::RenderSVGRoot::layout):
+        (WebCore::RenderSVGRoot::updateFromStyle):
+        * rendering/svg/RenderSVGRoot.h:
+        * rendering/svg/RenderSVGShape.cpp:
+        (WebCore::RenderSVGShape::layout):
+        (WebCore::RenderSVGShape::paint):
+        (WebCore::RenderSVGShape::nodeAtPoint):
+        * rendering/svg/RenderSVGTransformableContainer.cpp:
+        (WebCore::RenderSVGTransformableContainer::updateFromStyle):
+        * rendering/svg/SVGBoundingBoxComputation.cpp:
+        (WebCore::SVGBoundingBoxComputation::handleRootOrContainer const):
+        * rendering/svg/SVGBoundingBoxComputation.h:
+        (WebCore::SVGBoundingBoxComputation::computeVisualOverflowRect):
+        * rendering/svg/SVGContainerLayout.cpp:
+        (WebCore::SVGContainerLayout::positionChildrenRelativeToContainer):
+        (WebCore::SVGContainerLayout::verifyLayoutLocationConsistency):
+        (WebCore::layoutLocationFromRenderer): Deleted.
+        (WebCore::setLayoutLocationForRenderer): Deleted.
+        * rendering/svg/SVGContainerLayout.h:
+        * style/StyleAdjuster.cpp:
+        (WebCore::Style::Adjuster::adjust const):
+
 2022-04-27  Youenn Fablet  <you...@apple.com>
 
         <link rel=preconnect> always sends credentials to different-origin, ignoring crossorigin=anonymous

Modified: trunk/Source/WebCore/rendering/RenderElement.cpp (293503 => 293504)


--- trunk/Source/WebCore/rendering/RenderElement.cpp	2022-04-27 10:36:07 UTC (rev 293503)
+++ trunk/Source/WebCore/rendering/RenderElement.cpp	2022-04-27 11:14:44 UTC (rev 293504)
@@ -2418,21 +2418,43 @@
     if (!is<SVGElement>(element()))
         return { };
 
+    auto alignReferenceBox = [&](FloatRect referenceBox) {
+        // The CSS borderBoxRect() is defined to start at an origin of (0, 0).
+        // A possible shift of a CSS box (e.g. due to non-static position + top/left properties)
+        // does not effect the borderBoxRect() location. The location information
+        // is propagated upon paint time, e.g. via 'paintOffset' when calling RenderObject::paint(),
+        // or by altering the RenderLayer TransformationMatrix to include the 'offsetFromAncestor'
+        // right in the transformation matrix, when CSS transformations are present (see RenderLayer
+        // paintLayerByApplyingTransform() for details).
+        //
+        // To mimic the expectation for SVG, 'fill-box' must behave the same: if we'd include
+        // the 'referenceBox' location in the returned rect, we'd apply the (x, y) location
+        // information for the SVG renderer twice. We would shift the 'transform-origin' by (x, y)
+        // and at the same time alter the CTM in RenderLayer::paintLayerByApplyingTransform() by
+        // including a translation to the enclosing transformed ancestor ('offsetFromAncestor').
+        // Avoid that, and move by -nominalSVGLayoutLocation().
+#if ENABLE(LAYER_BASED_SVG_ENGINE)
+        if (isSVGLayerAwareRenderer() && !isSVGRoot() && document().settings().layerBasedSVGEngineEnabled())
+            referenceBox.moveBy(-downcast<RenderLayerModelObject>(*this).nominalSVGLayoutLocation());
+#endif
+        return referenceBox;
+    };
+
     switch (boxType) {
     case CSSBoxType::BoxMissing:
     case CSSBoxType::ContentBox:
     case CSSBoxType::PaddingBox:
     case CSSBoxType::FillBox:
-        return objectBoundingBox();
+        return alignReferenceBox(objectBoundingBox());
     case CSSBoxType::BorderBox:
     case CSSBoxType::MarginBox:
     case CSSBoxType::StrokeBox:
-        return strokeBoundingBox();
+        return alignReferenceBox(strokeBoundingBox());
     case CSSBoxType::ViewBox:
         // FIXME: [LBSE] Upstream: Cache the immutable SVGLengthContext per SVGElement, to avoid the repeated RenderSVGRoot size queries in determineViewport().
         FloatSize viewportSize;
         SVGLengthContext(downcast<SVGElement>(element())).determineViewport(viewportSize);
-        return { { }, viewportSize };
+        return alignReferenceBox({ { }, viewportSize });
     }
 
     ASSERT_NOT_REACHED();

Modified: trunk/Source/WebCore/rendering/RenderLayer.cpp (293503 => 293504)


--- trunk/Source/WebCore/rendering/RenderLayer.cpp	2022-04-27 10:36:07 UTC (rev 293503)
+++ trunk/Source/WebCore/rendering/RenderLayer.cpp	2022-04-27 11:14:44 UTC (rev 293504)
@@ -302,9 +302,9 @@
 
 DEFINE_ALLOCATOR_WITH_HEAP_IDENTIFIER(RenderLayer);
 
-RenderLayer::RenderLayer(RenderLayerModelObject& rendererLayerModelObject)
-    : m_isRenderViewLayer(rendererLayerModelObject.isRenderView())
-    , m_forcedStackingContext(rendererLayerModelObject.isMedia())
+RenderLayer::RenderLayer(RenderLayerModelObject& renderer)
+    : m_isRenderViewLayer(renderer.isRenderView())
+    , m_forcedStackingContext(renderer.isMedia())
     , m_isNormalFlowOnly(false)
     , m_isCSSStackingContext(false)
     , m_isOpportunisticStackingContext(false)
@@ -343,7 +343,7 @@
     , m_hasNotIsolatedBlendingDescendantsStatusDirty(false)
 #endif
     , m_repaintRectsValid(false)
-    , m_renderer(rendererLayerModelObject)
+    , m_renderer(renderer)
 {
     setIsNormalFlowOnly(shouldBeNormalFlowOnly());
     setIsCSSStackingContext(shouldBeCSSStackingContext());
@@ -353,9 +353,9 @@
     if (isRenderViewLayer())
         m_boxScrollingScope = m_contentsScrollingScope = nextScrollingScope();
 
-    if (!renderer().firstChild()) {
+    if (!renderer.firstChild()) {
         m_visibleContentStatusDirty = false;
-        m_hasVisibleContent = renderer().style().visibility() == Visibility::Visible;
+        m_hasVisibleContent = renderer.style().visibility() == Visibility::Visible;
     }
 }
 
@@ -552,9 +552,6 @@
 {
     auto& renderer = layer.renderer();
     return renderer.hasTransformRelatedProperty()
-#if ENABLE(LAYER_BASED_SVG_ENGINE)
-        || renderer.hasSVGTransform()
-#endif
         || renderer.hasClipPath()
         || renderer.hasFilter()
         || renderer.hasMask()
@@ -3545,8 +3542,18 @@
 
 void RenderLayer::paintLayerByApplyingTransform(GraphicsContext& context, const LayerPaintingInfo& paintingInfo, OptionSet<PaintLayerFlag> paintFlags, const LayoutSize& translationOffset)
 {
+    auto usesSVGSubtreeTransformRules = [](const RenderLayerModelObject& renderer) {
+#if ENABLE(LAYER_BASED_SVG_ENGINE)
+        return renderer.document().settings().layerBasedSVGEngineEnabled() && renderer.isSVGLayerAwareRenderer() && !renderer.isSVGRoot();
+#else
+        UNUSED_PARAM(renderer);
+#endif
+        return false;
+    };
+
     // This involves subtracting out the position of the layer in our current coordinate space, but preserving
     // the accumulated error for sub-pixel layout.
+    // Note: The pixel-snapping logic is disabled for the whole SVG render tree, except the outermost <svg>.
     float deviceScaleFactor = renderer().document().deviceScaleFactor();
     LayoutSize offsetFromParent = offsetFromAncestor(paintingInfo.rootLayer);
     offsetFromParent += translationOffset;
@@ -3553,11 +3560,11 @@
     TransformationMatrix transform(renderableTransform(paintingInfo.paintBehavior));
     // Add the subpixel accumulation to the current layer's offset so that we can always snap the translateRight value to where the renderer() is supposed to be painting.
     LayoutSize offsetForThisLayer = offsetFromParent + paintingInfo.subpixelOffset;
-    FloatSize devicePixelSnappedOffsetForThisLayer = toFloatSize(roundPointToDevicePixels(toLayoutPoint(offsetForThisLayer), deviceScaleFactor));
+    FloatSize alignedOffsetForThisLayer = usesSVGSubtreeTransformRules(renderer()) ? offsetForThisLayer : toFloatSize(roundPointToDevicePixels(toLayoutPoint(offsetForThisLayer), deviceScaleFactor));
     // We handle accumulated subpixels through nested layers here. Since the context gets translated to device pixels,
     // all we need to do is add the delta to the accumulated pixels coming from ancestor layers.
     // Translate the graphics context to the snapping position to avoid off-device-pixel positing.
-    transform.translateRight(devicePixelSnappedOffsetForThisLayer.width(), devicePixelSnappedOffsetForThisLayer.height());
+    transform.translateRight(alignedOffsetForThisLayer.width(), alignedOffsetForThisLayer.height());
     // Apply the transform.
     auto oldTransform = context.getCTM();
     auto affineTransform = transform.toAffineTransform();
@@ -3567,7 +3574,10 @@
         paintingInfo.eventRegionContext->pushTransform(affineTransform);
 
     // Now do a paint with the root layer shifted to be us.
-    LayoutSize adjustedSubpixelOffset = offsetForThisLayer - LayoutSize(devicePixelSnappedOffsetForThisLayer);
+    LayoutSize adjustedSubpixelOffset;
+    if (!usesSVGSubtreeTransformRules(renderer()) && !renderer().isSVGRoot())
+        adjustedSubpixelOffset = offsetForThisLayer - LayoutSize(alignedOffsetForThisLayer);
+
     LayerPaintingInfo transformedPaintingInfo(paintingInfo);
     transformedPaintingInfo.rootLayer = this;
     transformedPaintingInfo.paintDirtyRect = LayoutRect(encloseRectToDevicePixels(valueOrDefault(transform.inverse()).mapRect(paintingInfo.paintDirtyRect), deviceScaleFactor));

Modified: trunk/Source/WebCore/rendering/RenderLayer.h (293503 => 293504)


--- trunk/Source/WebCore/rendering/RenderLayer.h	2022-04-27 10:36:07 UTC (rev 293503)
+++ trunk/Source/WebCore/rendering/RenderLayer.h	2022-04-27 11:14:44 UTC (rev 293504)
@@ -984,7 +984,7 @@
             return downcast<RenderBox>(renderer()).location();
 #if ENABLE(LAYER_BASED_SVG_ENGINE)
         if (is<RenderSVGModelObject>(renderer()))
-            return downcast<RenderSVGModelObject>(renderer()).layoutLocation();
+            return downcast<RenderSVGModelObject>(renderer()).currentSVGLayoutLocation();
 #endif
 
         return LayoutPoint();

Modified: trunk/Source/WebCore/rendering/RenderLayerModelObject.cpp (293503 => 293504)


--- trunk/Source/WebCore/rendering/RenderLayerModelObject.cpp	2022-04-27 10:36:07 UTC (rev 293503)
+++ trunk/Source/WebCore/rendering/RenderLayerModelObject.cpp	2022-04-27 11:14:44 UTC (rev 293504)
@@ -129,6 +129,9 @@
             layer()->willRemoveChildWithBlendMode();
 #endif
         setHasTransformRelatedProperty(false); // All transform-related properties force layers, so we know we don't have one or the object doesn't support them.
+#if ENABLE(LAYER_BASED_SVG_ENGINE)
+        setHasSVGTransform(false); // Same reason as for setHasTransformRelatedProperty().
+#endif
         setHasReflection(false);
 
         // Repaint the about to be destroyed self-painting layer when style change also triggers repaint.
@@ -275,7 +278,7 @@
     */
 
     if (moveToOrigin)
-        adjustedRect.moveBy(flooredLayoutPoint(objectBoundingBox().minXMinYCorner()));
+        adjustedRect.moveBy(nominalSVGLayoutLocation());
 
     if (auto* transform = layer()->transform())
         adjustedRect = transform->mapRect(adjustedRect);
@@ -356,6 +359,13 @@
 
     style.unapplyTransformOrigin(transform, originTranslate);
 }
+
+void RenderLayerModelObject::updateHasSVGTransformFlags(const SVGGraphicsElement& graphicsElement)
+{
+    bool hasSVGTransform = !graphicsElement.animatedLocalTransform().isIdentity();
+    setHasTransformRelatedProperty(style().hasTransformRelatedProperty() || hasSVGTransform);
+    setHasSVGTransform(hasSVGTransform);
+}
 #endif
 
 bool rendererNeedsPixelSnapping(const RenderLayerModelObject& renderer)

Modified: trunk/Source/WebCore/rendering/RenderLayerModelObject.h (293503 => 293504)


--- trunk/Source/WebCore/rendering/RenderLayerModelObject.h	2022-04-27 10:36:07 UTC (rev 293503)
+++ trunk/Source/WebCore/rendering/RenderLayerModelObject.h	2022-04-27 11:14:44 UTC (rev 293504)
@@ -78,6 +78,11 @@
     void mapLocalToSVGContainer(const RenderLayerModelObject* ancestorContainer, TransformState&, OptionSet<MapCoordinatesMode>, bool* wasFixed) const;
 
     void applySVGTransform(TransformationMatrix&, SVGGraphicsElement&, const RenderStyle&, const FloatRect& boundingBox, OptionSet<RenderStyle::TransformOperationOption>) const;
+    void updateHasSVGTransformFlags(const SVGGraphicsElement&);
+
+    LayoutPoint nominalSVGLayoutLocation() const { return flooredLayoutPoint(objectBoundingBoxWithoutTransformations().minXMinYCorner()); }
+    virtual LayoutPoint currentSVGLayoutLocation() const { ASSERT_NOT_REACHED(); return { }; }
+    virtual void setCurrentSVGLayoutLocation(const LayoutPoint&) { ASSERT_NOT_REACHED(); }
 #endif
 
     void updateLayerTransform();

Modified: trunk/Source/WebCore/rendering/RenderObject.h (293503 => 293504)


--- trunk/Source/WebCore/rendering/RenderObject.h	2022-04-27 10:36:07 UTC (rev 293503)
+++ trunk/Source/WebCore/rendering/RenderObject.h	2022-04-27 11:14:44 UTC (rev 293504)
@@ -367,6 +367,19 @@
     virtual FloatRect objectBoundingBox() const;
     virtual FloatRect strokeBoundingBox() const;
 
+#if ENABLE(LAYER_BASED_SVG_ENGINE)
+    // The objectBoundingBox of a SVG container is affected by the transformations applied on its children -- the container
+    // bounding box is a union of all child bounding boxes, mapped through their transformation matrices.
+    //
+    // This method ignores all transformations and computes the objectBoundingBox, without mapping through the child
+    // transformation matrices. The SVG render tree is constructed in such a way, that it can be mapped to CSS equivalents:
+    // The SVG render tree underneath the outermost <svg> behaves as a set of absolutely positioned, possibly nested, boxes.
+    // They are laid out in such a way that transformations do NOT affect layout, as in HTML/CSS world, but take affect during
+    // painting, hit-testing etc. This allows to minimize the amount of re-layouts when animating transformations in SVG
+    // (not using CSS Animations/Transitions / Web Animations, but e.g. SMIL <animateTransform>, JS, ...).
+    virtual FloatRect objectBoundingBoxWithoutTransformations() const { return objectBoundingBox(); }
+#endif
+
     // Returns the smallest rectangle enclosing all of the painted content
     // respecting clipping, masking, filters, opacity, stroke-width and markers
     virtual FloatRect repaintRectInLocalCoordinates() const;

Modified: trunk/Source/WebCore/rendering/svg/RenderSVGBlock.h (293503 => 293504)


--- trunk/Source/WebCore/rendering/svg/RenderSVGBlock.h	2022-04-27 10:36:07 UTC (rev 293503)
+++ trunk/Source/WebCore/rendering/svg/RenderSVGBlock.h	2022-04-27 11:14:44 UTC (rev 293504)
@@ -48,6 +48,11 @@
 
     void styleDidChange(StyleDifference, const RenderStyle* oldStyle) final;
 
+#if ENABLE(LAYER_BASED_SVG_ENGINE)
+    LayoutPoint currentSVGLayoutLocation() const final { return location(); }
+    void setCurrentSVGLayoutLocation(const LayoutPoint& location) final { setLocation(location); }
+#endif
+
     LayoutRect clippedOverflowRect(const RenderLayerModelObject* repaintContainer, VisibleRectContext) const final;
     std::optional<FloatRect> computeFloatVisibleRectInContainer(const FloatRect&, const RenderLayerModelObject* container, VisibleRectContext) const final;
     std::optional<LayoutRect> computeVisibleRectInContainer(const LayoutRect&, const RenderLayerModelObject* container, VisibleRectContext) const final;

Modified: trunk/Source/WebCore/rendering/svg/RenderSVGContainer.cpp (293503 => 293504)


--- trunk/Source/WebCore/rendering/svg/RenderSVGContainer.cpp	2022-04-27 10:36:07 UTC (rev 293503)
+++ trunk/Source/WebCore/rendering/svg/RenderSVGContainer.cpp	2022-04-27 11:14:44 UTC (rev 293504)
@@ -119,21 +119,16 @@
 
     SVGBoundingBoxComputation boundingBoxComputation(*this);
     m_objectBoundingBox = boundingBoxComputation.computeDecoratedBoundingBox(SVGBoundingBoxComputation::objectBoundingBoxDecoration, &m_objectBoundingBoxValid);
+
+    constexpr auto objectBoundingBoxDecorationWithoutTransformations = SVGBoundingBoxComputation::objectBoundingBoxDecoration | SVGBoundingBoxComputation::DecorationOption::IgnoreTransformations;
+    m_objectBoundingBoxWithoutTransformations = boundingBoxComputation.computeDecoratedBoundingBox(objectBoundingBoxDecorationWithoutTransformations);
+
     m_strokeBoundingBox = boundingBoxComputation.computeDecoratedBoundingBox(SVGBoundingBoxComputation::strokeBoundingBoxDecoration);
-    setLayoutRect(enclosingLayoutRect(m_objectBoundingBox));
+    setCurrentSVGLayoutRect(enclosingLayoutRect(m_objectBoundingBoxWithoutTransformations));
 
     containerLayout.positionChildrenRelativeToContainer();
 }
 
-void RenderSVGContainer::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
-{
-    RenderSVGModelObject::styleDidChange(diff, oldStyle);
-
-    // FIXME: [LBSE] Upstream RenderLayer changes
-    // if (hasLayer())
-    //     layer()->setIsOpportunisticStackingContext(true);
-}
-
 bool RenderSVGContainer::selfWillPaint()
 {
     auto* resources = SVGResourcesCache::cachedResourcesForRenderer(*this);
@@ -165,7 +160,7 @@
         return;
     }
 
-    auto adjustedPaintOffset = paintOffset + layoutLocation();
+    auto adjustedPaintOffset = paintOffset + currentSVGLayoutLocation();
     if (paintInfo.phase == PaintPhase::Mask) {
         // FIXME: [LBSE] Upstream SVGRenderSupport changes
         // SVGRenderSupport::paintSVGMask(*this, paintInfo, adjustedPaintOffset);
@@ -185,7 +180,7 @@
 
 bool RenderSVGContainer::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
 {
-    auto adjustedLocation = accumulatedOffset + layoutLocation();
+    auto adjustedLocation = accumulatedOffset + currentSVGLayoutLocation();
 
     auto visualOverflowRect = visualOverflowRectEquivalent();
     visualOverflowRect.moveBy(adjustedLocation);
@@ -193,8 +188,7 @@
         return false;
 
     auto localPoint = locationInContainer.point();
-    auto boundingBoxTopLeftCorner = flooredLayoutPoint(objectBoundingBox().minXMinYCorner());
-    auto coordinateSystemOriginTranslation = boundingBoxTopLeftCorner - adjustedLocation;
+    auto coordinateSystemOriginTranslation = nominalSVGLayoutLocation() - adjustedLocation;
     localPoint.move(coordinateSystemOriginTranslation);
 
     if (!SVGRenderSupport::pointInClippingArea(*this, localPoint))

Modified: trunk/Source/WebCore/rendering/svg/RenderSVGContainer.h (293503 => 293504)


--- trunk/Source/WebCore/rendering/svg/RenderSVGContainer.h	2022-04-27 10:36:07 UTC (rev 293503)
+++ trunk/Source/WebCore/rendering/svg/RenderSVGContainer.h	2022-04-27 11:14:44 UTC (rev 293504)
@@ -40,6 +40,7 @@
     bool isObjectBoundingBoxValid() const { return m_objectBoundingBoxValid; }
 
     FloatRect objectBoundingBox() const final { return m_objectBoundingBox; }
+    FloatRect objectBoundingBoxWithoutTransformations() const final { return m_objectBoundingBoxWithoutTransformations; }
     FloatRect strokeBoundingBox() const final { return m_strokeBoundingBox; }
     FloatRect repaintRectInLocalCoordinates() const final { return SVGBoundingBoxComputation::computeRepaintBoundingBox(*this); }
 
@@ -49,8 +50,6 @@
     ASCIILiteral renderName() const override { return "RenderSVGContainer"_s; }
     bool canHaveChildren() const final { return true; }
 
-    void styleDidChange(StyleDifference, const RenderStyle* oldStyle) override;
-
     void layout() override;
     virtual void layoutChildren();
     bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) override;
@@ -62,6 +61,7 @@
 
     bool m_objectBoundingBoxValid { false };
     FloatRect m_objectBoundingBox;
+    FloatRect m_objectBoundingBoxWithoutTransformations;
     FloatRect m_strokeBoundingBox;
 
 private:

Modified: trunk/Source/WebCore/rendering/svg/RenderSVGInline.h (293503 => 293504)


--- trunk/Source/WebCore/rendering/svg/RenderSVGInline.h	2022-04-27 10:36:07 UTC (rev 293503)
+++ trunk/Source/WebCore/rendering/svg/RenderSVGInline.h	2022-04-27 11:14:44 UTC (rev 293504)
@@ -51,6 +51,11 @@
     FloatRect strokeBoundingBox() const final;
     FloatRect repaintRectInLocalCoordinates() const final;
 
+#if ENABLE(LAYER_BASED_SVG_ENGINE)
+    LayoutPoint currentSVGLayoutLocation() const final { return { }; }
+    void setCurrentSVGLayoutLocation(const LayoutPoint&) final { ASSERT_NOT_REACHED(); }
+#endif
+
     LayoutRect clippedOverflowRect(const RenderLayerModelObject* repaintContainer, VisibleRectContext) const final;
     std::optional<FloatRect> computeFloatVisibleRectInContainer(const FloatRect&, const RenderLayerModelObject* container, VisibleRectContext) const final;
     void mapLocalToContainer(const RenderLayerModelObject* ancestorContainer, TransformState&, OptionSet<MapCoordinatesMode>, bool* wasFixed) const final;

Modified: trunk/Source/WebCore/rendering/svg/RenderSVGModelObject.cpp (293503 => 293504)


--- trunk/Source/WebCore/rendering/svg/RenderSVGModelObject.cpp	2022-04-27 10:36:07 UTC (rev 293503)
+++ trunk/Source/WebCore/rendering/svg/RenderSVGModelObject.cpp	2022-04-27 11:14:44 UTC (rev 293504)
@@ -61,12 +61,8 @@
 {
     RenderLayerModelObject::updateFromStyle();
 
-    bool hasSVGTransform = false;
     if (is<SVGGraphicsElement>(element()))
-        hasSVGTransform = !downcast<SVGGraphicsElement>(element()).animatedLocalTransform().isIdentity();
-
-    setHasTransformRelatedProperty(style().hasTransformRelatedProperty() || hasSVGTransform);
-    setHasSVGTransform(hasSVGTransform);
+        updateHasSVGTransformFlags(downcast<SVGGraphicsElement>(element()));
 }
 
 FloatRect RenderSVGModelObject::borderBoxRectInFragmentEquivalent(RenderFragmentContainer*, RenderBox::RenderBoxFragmentInfoFlags) const
@@ -141,7 +137,7 @@
 
 void RenderSVGModelObject::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) const
 {
-    rects.append(snappedIntRect(LayoutRect(accumulatedOffset + layoutLocation(), layoutSize())));
+    rects.append(snappedIntRect(LayoutRect(accumulatedOffset + m_layoutRect.location(), m_layoutRect.size())));
 }
 
 void RenderSVGModelObject::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const

Modified: trunk/Source/WebCore/rendering/svg/RenderSVGModelObject.h (293503 => 293504)


--- trunk/Source/WebCore/rendering/svg/RenderSVGModelObject.h	2022-04-27 10:36:07 UTC (rev 293503)
+++ trunk/Source/WebCore/rendering/svg/RenderSVGModelObject.h	2022-04-27 11:14:44 UTC (rev 293504)
@@ -58,26 +58,21 @@
 
     inline SVGElement& element() const;
 
+    LayoutRect currentSVGLayoutRect() const { return m_layoutRect; }
+    void setCurrentSVGLayoutRect(const LayoutRect& layoutRect) { m_layoutRect = layoutRect; }
+
+    LayoutPoint currentSVGLayoutLocation() const final { return m_layoutRect.location(); }
+    void setCurrentSVGLayoutLocation(const LayoutPoint& location) final { m_layoutRect.setLocation(location); }
+
     // Mimic the RenderBox accessors - by sharing the same terminology the painting / hit testing / layout logic is
     // similar to read compared to non-SVG renderers such as RenderBox & friends.
     LayoutRect borderBoxRectEquivalent() const { return { LayoutPoint(), m_layoutRect.size() }; }
     LayoutRect contentBoxRectEquivalent() const { return borderBoxRectEquivalent(); }
     LayoutRect frameRectEquivalent() const { return m_layoutRect; }
-
     LayoutRect visualOverflowRectEquivalent() const { return SVGBoundingBoxComputation::computeVisualOverflowRect(*this); }
 
-    void applyTopLeftLocationOffsetEquivalent(LayoutPoint& point) const { point.moveBy(layoutLocation()); }
-
-    LayoutRect layoutRect() const { return m_layoutRect; }
-    void setLayoutRect(const LayoutRect& layoutRect) { m_layoutRect = layoutRect; }
-    void setLayoutLocation(const LayoutPoint& layoutLocation) { m_layoutRect.setLocation(layoutLocation); }
-
-    LayoutPoint paintingLocation() const { return toLayoutPoint(layoutLocation() - flooredLayoutPoint(objectBoundingBox().minXMinYCorner())); }
-    LayoutPoint layoutLocation() const { return m_layoutRect.location(); }
-    LayoutSize layoutLocationOffset() const { return toLayoutSize(m_layoutRect.location()); }
-    LayoutSize layoutSize() const { return m_layoutRect.size(); }
-
     // For RenderLayer only
+    void applyTopLeftLocationOffsetEquivalent(LayoutPoint& point) const { point.moveBy(currentSVGLayoutLocation()); }
     FloatRect borderBoxRectInFragmentEquivalent(RenderFragmentContainer*, RenderBox::RenderBoxFragmentInfoFlags = RenderBox::CacheRenderBoxFragmentInfo) const;
     virtual LayoutRect overflowClipRect(const LayoutPoint& location, RenderFragmentContainer* = nullptr, OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize, PaintPhase = PaintPhase::BlockBackground) const;
     LayoutRect overflowClipRectForChildLayers(const LayoutPoint& location, RenderFragmentContainer* fragment, OverlayScrollbarSizeRelevancy relevancy) { return overflowClipRect(location, fragment, relevancy); }

Modified: trunk/Source/WebCore/rendering/svg/RenderSVGRoot.cpp (293503 => 293504)


--- trunk/Source/WebCore/rendering/svg/RenderSVGRoot.cpp	2022-04-27 10:36:07 UTC (rev 293503)
+++ trunk/Source/WebCore/rendering/svg/RenderSVGRoot.cpp	2022-04-27 11:14:44 UTC (rev 293504)
@@ -196,6 +196,10 @@
 
         SVGBoundingBoxComputation boundingBoxComputation(*this);
         m_objectBoundingBox = boundingBoxComputation.computeDecoratedBoundingBox(SVGBoundingBoxComputation::objectBoundingBoxDecoration);
+
+        constexpr auto objectBoundingBoxDecorationWithoutTransformations = SVGBoundingBoxComputation::objectBoundingBoxDecoration | SVGBoundingBoxComputation::DecorationOption::IgnoreTransformations;
+        m_objectBoundingBoxWithoutTransformations = boundingBoxComputation.computeDecoratedBoundingBox(objectBoundingBoxDecorationWithoutTransformations);
+
         m_strokeBoundingBox = boundingBoxComputation.computeDecoratedBoundingBox(SVGBoundingBoxComputation::strokeBoundingBoxDecoration);
     }
 
@@ -397,6 +401,7 @@
     RenderReplaced::updateFromStyle();
 
     setHasSVGTransform();
+    setHasTransformRelatedProperty();
 
     if (shouldApplyViewportClip())
         setHasNonVisibleOverflow();

Modified: trunk/Source/WebCore/rendering/svg/RenderSVGRoot.h (293503 => 293504)


--- trunk/Source/WebCore/rendering/svg/RenderSVGRoot.h	2022-04-27 10:36:07 UTC (rev 293503)
+++ trunk/Source/WebCore/rendering/svg/RenderSVGRoot.h	2022-04-27 11:14:44 UTC (rev 293504)
@@ -67,6 +67,7 @@
     bool shouldApplyViewportClip() const;
 
     FloatRect objectBoundingBox() const final { return m_objectBoundingBox; }
+    FloatRect objectBoundingBoxWithoutTransformations() const final { return m_objectBoundingBoxWithoutTransformations; }
     FloatRect strokeBoundingBox() const final { return m_strokeBoundingBox; }
     FloatRect repaintRectInLocalCoordinates() const final { return SVGBoundingBoxComputation::computeRepaintBoundingBox(*this); }
 
@@ -123,6 +124,7 @@
 
     IntSize m_containerSize;
     FloatRect m_objectBoundingBox;
+    FloatRect m_objectBoundingBoxWithoutTransformations;
     FloatRect m_strokeBoundingBox;
     AffineTransform m_viewBoxTransform;
     AffineTransform m_supplementalLocalToParentTransform;

Modified: trunk/Source/WebCore/rendering/svg/RenderSVGShape.cpp (293503 => 293504)


--- trunk/Source/WebCore/rendering/svg/RenderSVGShape.cpp	2022-04-27 10:36:07 UTC (rev 293503)
+++ trunk/Source/WebCore/rendering/svg/RenderSVGShape.cpp	2022-04-27 11:14:44 UTC (rev 293504)
@@ -151,7 +151,7 @@
         updateShapeFromElement();
 
         m_needsShapeUpdate = false;
-        setLayoutRect(enclosingLayoutRect(m_fillBoundingBox));
+        setCurrentSVGLayoutRect(enclosingLayoutRect(m_fillBoundingBox));
     }
 
     updateLayerTransform();
@@ -288,7 +288,7 @@
         return;
     }
 
-    auto adjustedPaintOffset = paintOffset + layoutLocation();
+    auto adjustedPaintOffset = paintOffset + currentSVGLayoutLocation();
     if (paintInfo.phase == PaintPhase::Mask) {
         // FIXME: [LBSE] Upstream SVGRenderSupport changes
         // SVGRenderSupport::paintSVGMask(*this, paintInfo, adjustedPaintOffset);
@@ -308,7 +308,7 @@
 
     GraphicsContextStateSaver stateSaver(paintInfo.context());
 
-    auto coordinateSystemOriginTranslation = adjustedPaintOffset - flooredLayoutPoint(objectBoundingBox().location());
+    auto coordinateSystemOriginTranslation = adjustedPaintOffset - nominalSVGLayoutLocation();
     paintInfo.context().translate(coordinateSystemOriginTranslation.width(), coordinateSystemOriginTranslation.height());
 
     if (style().svgStyle().shapeRendering() == ShapeRendering::CrispEdges)
@@ -345,11 +345,10 @@
     if (hitTestAction != HitTestForeground)
         return false;
 
-    auto adjustedLocation = accumulatedOffset + layoutLocation();
+    auto adjustedLocation = accumulatedOffset + currentSVGLayoutLocation();
 
     auto localPoint = locationInContainer.point();
-    auto boundingBoxTopLeftCorner = flooredLayoutPoint(objectBoundingBox().minXMinYCorner());
-    auto coordinateSystemOriginTranslation = boundingBoxTopLeftCorner - adjustedLocation;
+    auto coordinateSystemOriginTranslation = nominalSVGLayoutLocation() - adjustedLocation;
     localPoint.move(coordinateSystemOriginTranslation);
 
     if (!SVGRenderSupport::pointInClippingArea(*this, localPoint))

Modified: trunk/Source/WebCore/rendering/svg/RenderSVGTransformableContainer.cpp (293503 => 293504)


--- trunk/Source/WebCore/rendering/svg/RenderSVGTransformableContainer.cpp	2022-04-27 10:36:07 UTC (rev 293503)
+++ trunk/Source/WebCore/rendering/svg/RenderSVGTransformableContainer.cpp	2022-04-27 11:14:44 UTC (rev 293504)
@@ -97,8 +97,10 @@
 {
     RenderSVGContainer::updateFromStyle();
 
-    if (associatedUseElement(graphicsElement()))
+    if (associatedUseElement(graphicsElement())) {
         setHasSVGTransform();
+        setHasTransformRelatedProperty();
+    }
 }
 
 void RenderSVGTransformableContainer::applyTransform(TransformationMatrix& transform, const RenderStyle& style, const FloatRect& boundingBox, OptionSet<RenderStyle::TransformOperationOption> options) const

Modified: trunk/Source/WebCore/rendering/svg/SVGBoundingBoxComputation.cpp (293503 => 293504)


--- trunk/Source/WebCore/rendering/svg/SVGBoundingBoxComputation.cpp	2022-04-27 10:36:07 UTC (rev 293503)
+++ trunk/Source/WebCore/rendering/svg/SVGBoundingBoxComputation.cpp	2022-04-27 11:14:44 UTC (rev 293504)
@@ -175,8 +175,10 @@
         if (options.contains(DecorationOption::OverrideBoxWithFilterBoxForChildren) && is<RenderSVGContainer>(child))
             childBoundingBoxComputation.adjustBoxForClippingAndEffects({ DecorationOption::OverrideBoxWithFilterBox }, childBox);
 
-        if (auto layerTransform = transformationMatrixFromChild(child))
-            childBox = layerTransform->mapRect(childBox);
+        if (!options.contains(DecorationOption::IgnoreTransformations)) {
+            if (auto layerTransform = transformationMatrixFromChild(child))
+                childBox = layerTransform->mapRect(childBox);
+        }
 
         if (options == objectBoundingBoxDecoration)
             uniteBoundingBoxRespectingValidity(boxValid, box, child, childBox);

Modified: trunk/Source/WebCore/rendering/svg/SVGBoundingBoxComputation.h (293503 => 293504)


--- trunk/Source/WebCore/rendering/svg/SVGBoundingBoxComputation.h	2022-04-27 10:36:07 UTC (rev 293503)
+++ trunk/Source/WebCore/rendering/svg/SVGBoundingBoxComputation.h	2022-04-27 11:14:44 UTC (rev 293504)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2021 Igalia S.L.
+ * Copyright (C) 2021, 2022 Igalia S.L.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -35,7 +35,7 @@
     explicit SVGBoundingBoxComputation(const RenderLayerModelObject&);
     ~SVGBoundingBoxComputation() = default;
 
-    enum class DecorationOption : uint8_t {
+    enum class DecorationOption : uint16_t {
         IncludeFillShape                    = 1 << 0, /* corresponds to 'bool fill'     */
         IncludeStrokeShape                  = 1 << 1, /* corresponds to 'bool stroke'   */
         IncludeMarkers                      = 1 << 2, /* corresponds to 'bool markers'  */
@@ -42,8 +42,9 @@
         IncludeClippers                     = 1 << 3, /* corresponds to 'bool clippers' */
         IncludeMaskers                      = 1 << 4, /* WebKit extension - internal    */
         IncludeOutline                      = 1 << 5, /* WebKit extension - internal    */
-        OverrideBoxWithFilterBox            = 1 << 6, /* WebKit extension - internal    */
-        OverrideBoxWithFilterBoxForChildren = 1 << 7  /* WebKit extension - internal    */
+        IgnoreTransformations               = 1 << 6, /* WebKit extension - internal    */
+        OverrideBoxWithFilterBox            = 1 << 7, /* WebKit extension - internal    */
+        OverrideBoxWithFilterBoxForChildren = 1 << 8  /* WebKit extension - internal    */
     };
 
     using DecorationOptions = OptionSet<DecorationOption>;
@@ -73,7 +74,7 @@
             return LayoutRect();
 
         auto visualOverflowRect = enclosingLayoutRect(repaintBoundingBox);
-        visualOverflowRect.moveBy(-flooredLayoutPoint(renderer.objectBoundingBox().minXMinYCorner()));
+        visualOverflowRect.moveBy(-renderer.nominalSVGLayoutLocation());
         return visualOverflowRect;
     }
 

Modified: trunk/Source/WebCore/rendering/svg/SVGContainerLayout.cpp (293503 => 293504)


--- trunk/Source/WebCore/rendering/svg/SVGContainerLayout.cpp	2022-04-27 10:36:07 UTC (rev 293503)
+++ trunk/Source/WebCore/rendering/svg/SVGContainerLayout.cpp	2022-04-27 11:14:44 UTC (rev 293504)
@@ -120,41 +120,6 @@
         ASSERT(elementsThatDidNotReceiveLayout.isEmpty());
 }
 
-static inline LayoutPoint layoutLocationFromRenderer(const RenderObject& renderer)
-{
-    if (is<RenderSVGModelObject>(renderer))
-        return downcast<RenderSVGModelObject>(renderer).layoutLocation();
-
-    if (is<RenderSVGBlock>(renderer)) // <foreignObject> / <text>
-        return downcast<RenderSVGBlock>(renderer).location();
-
-    if (is<RenderSVGInline>(renderer)) // <tspan> / <textPath>
-        return { };
-
-    ASSERT_NOT_REACHED();
-    return { };
-}
-
-static inline void setLayoutLocationForRenderer(RenderObject& renderer, const LayoutPoint& newLocation)
-{
-    if (is<RenderSVGModelObject>(renderer)) {
-        downcast<RenderSVGModelObject>(renderer).setLayoutLocation(newLocation);
-        return;
-    }
-
-    // <foreignObject> / <text>
-    if (is<RenderSVGBlock>(renderer)) {
-        downcast<RenderSVGBlock>(renderer).setLocation(newLocation);
-        return;
-    }
-
-    // <tspan> / <textPath>
-    if (is<RenderSVGInline>(renderer))
-        return;
-
-    ASSERT_NOT_REACHED();
-}
-
 void SVGContainerLayout::positionChildrenRelativeToContainer()
 {
     if (m_positionedChildren.isEmpty())
@@ -177,40 +142,36 @@
     };
 
     // Arrange layout location for all child renderers relative to the container layout location.
-    auto parentLayoutLocation = flooredLayoutPoint(m_container.objectBoundingBox().minXMinYCorner());
-    for (RenderObject& child : m_positionedChildren) {
+    auto parentLayoutLocation = m_container.nominalSVGLayoutLocation();
+    for (RenderLayerModelObject& child : m_positionedChildren) {
         verifyPositionedChildRendererExpectation(child);
 
-        auto objectBoundingBoxChild = child.objectBoundingBox();
-        auto layoutLocation = flooredLayoutPoint(objectBoundingBoxChild.minXMinYCorner());
-        auto desiredLayoutLocation = toLayoutPoint(layoutLocation - parentLayoutLocation);
-        auto currentLayoutLocation = layoutLocationFromRenderer(child);
-        if (currentLayoutLocation == desiredLayoutLocation)
-            continue;
-        setLayoutLocationForRenderer(child, desiredLayoutLocation);
+        auto desiredLayoutLocation = toLayoutPoint(child.nominalSVGLayoutLocation() - parentLayoutLocation);
+        if (child.currentSVGLayoutLocation() != desiredLayoutLocation)
+            child.setCurrentSVGLayoutLocation(desiredLayoutLocation);
     }
 }
 
-void SVGContainerLayout::verifyLayoutLocationConsistency(const RenderElement& renderer)
+void SVGContainerLayout::verifyLayoutLocationConsistency(const RenderLayerModelObject& renderer)
 {
     if (renderer.isSVGLayerAwareRenderer() && !renderer.isSVGRoot()) {
-        auto currentLayoutLocation = layoutLocationFromRenderer(renderer);
+        auto currentLayoutLocation = renderer.currentSVGLayoutLocation();
 
         auto expectedLayoutLocation = currentLayoutLocation;
-        for (auto& ancestor : ancestorsOfType<RenderElement>(renderer)) {
+        for (auto& ancestor : ancestorsOfType<RenderLayerModelObject>(renderer)) {
             ASSERT(ancestor.isSVGLayerAwareRenderer());
             if (ancestor.isSVGRoot())
                 break;
-            expectedLayoutLocation.moveBy(layoutLocationFromRenderer(ancestor));
+            expectedLayoutLocation.moveBy(ancestor.currentSVGLayoutLocation());
         }
 
-        auto initialLayoutLocation = flooredLayoutPoint(renderer.objectBoundingBox().minXMinYCorner());
+        auto initialLayoutLocation = renderer.nominalSVGLayoutLocation();
         if (expectedLayoutLocation == initialLayoutLocation) {
             LOG_WITH_STREAM(SVG, stream << "--> SVGContainerLayout renderer " << &renderer << " (" << renderer.renderName().characters() << ")"
-                << " - verifyLayoutLocationConsistency() objectBoundingBox / layoutLocation are in sync.");
+                << " - verifyLayoutLocationConsistency() currentSVGLayoutLocation / nominalSVGLayoutLocation are in sync.");
         } else {
             LOG_WITH_STREAM(SVG, stream << "--> SVGContainerLayout renderer " << &renderer << " (" << renderer.renderName().characters() << ")"
-                << " - verifyLayoutLocationConsistency() objectBoundingBox / layoutLocation invariant violated -- out of sync due to partial layout?"
+                << " - verifyLayoutLocationConsistency() currentSVGLayoutLocation / nominalSVGLayoutLocation invariant violated -- out of sync due to partial layout?"
                 << " currentLayoutLocation=" << currentLayoutLocation
                 << "  (expectedLayoutLocation=" << expectedLayoutLocation
                 << " != initialLayoutLocation=" << initialLayoutLocation << ")"
@@ -224,7 +185,7 @@
         }
     }
 
-    for (auto& child : childrenOfType<RenderElement>(renderer)) {
+    for (auto& child : childrenOfType<RenderLayerModelObject>(renderer)) {
         if (child.isSVGLayerAwareRenderer())
             verifyLayoutLocationConsistency(child);
     }

Modified: trunk/Source/WebCore/rendering/svg/SVGContainerLayout.h (293503 => 293504)


--- trunk/Source/WebCore/rendering/svg/SVGContainerLayout.h	2022-04-27 10:36:07 UTC (rev 293503)
+++ trunk/Source/WebCore/rendering/svg/SVGContainerLayout.h	2022-04-27 11:14:44 UTC (rev 293504)
@@ -40,7 +40,7 @@
 
     void positionChildrenRelativeToContainer();
 
-    static void verifyLayoutLocationConsistency(const RenderElement&);
+    static void verifyLayoutLocationConsistency(const RenderLayerModelObject&);
     static bool transformToRootChanged(const RenderObject* ancestor);
 
 private:

Modified: trunk/Source/WebCore/style/StyleAdjuster.cpp (293503 => 293504)


--- trunk/Source/WebCore/style/StyleAdjuster.cpp	2022-04-27 10:36:07 UTC (rev 293503)
+++ trunk/Source/WebCore/style/StyleAdjuster.cpp	2022-04-27 11:14:44 UTC (rev 293504)
@@ -54,6 +54,7 @@
 #include "RenderTheme.h"
 #include "RuntimeEnabledFeatures.h"
 #include "SVGElement.h"
+#include "SVGGraphicsElement.h"
 #include "SVGNames.h"
 #include "SVGURIReference.h"
 #include "Settings.h"
@@ -364,6 +365,22 @@
     else
         style.setUsedZIndex(style.specifiedZIndex());
 
+    // For SVG compatibility purposes we have to consider the 'animatedLocalTransform' besides the RenderStyle to query
+    // if an element has a transform. SVG transforms are not stored on the RenderStyle, and thus we need a special case here.
+    auto hasTransformRelatedProperty = [](const RenderStyle& style, const Element* element) {
+        if (style.hasTransformRelatedProperty())
+            return true;
+
+#if ENABLE(LAYER_BASED_SVG_ENGINE)
+        if (element && element->document().settings().layerBasedSVGEngineEnabled() && is<SVGGraphicsElement>(element))
+            return !downcast<SVGGraphicsElement>(*element).animatedLocalTransform().isIdentity();
+#else
+        UNUSED_PARAM(element);
+#endif
+
+        return false;
+    };
+
     // Auto z-index becomes 0 for the root element and transparent objects. This prevents
     // cases where objects that should be blended as a single unit end up with a non-transparent
     // object wedged in between them. Auto z-index also becomes 0 for objects that specify transforms/masks/reflections.
@@ -370,7 +387,7 @@
     if (style.hasAutoUsedZIndex()) {
         if ((m_element && m_document.documentElement() == m_element)
             || style.hasOpacity()
-            || style.hasTransformRelatedProperty()
+            || hasTransformRelatedProperty(style, m_element)
             || style.hasMask()
             || style.clipPath()
             || style.boxReflect()
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to