Branch: refs/heads/main
  Home:   https://github.com/WebKit/WebKit
  Commit: ec9eb9ff1b64602920ebc3ffd9d238822c57be22
      
https://github.com/WebKit/WebKit/commit/ec9eb9ff1b64602920ebc3ffd9d238822c57be22
  Author: Nikolas Zimmermann <[email protected]>
  Date:   2026-06-03 (Wed, 03 Jun 2026)

  Changed paths:
    M Source/WebCore/dom/Document.cpp
    M Source/WebCore/dom/Document.h
    M Source/WebCore/page/LocalFrameViewLayoutContext.cpp
    M Source/WebCore/page/LocalFrameViewLayoutContext.h
    M Source/WebCore/rendering/RenderElement.h
    M Source/WebCore/rendering/RenderLayerModelObject.cpp
    M Source/WebCore/rendering/RenderLayerModelObject.h
    M Source/WebCore/rendering/svg/RenderSVGContainer.cpp
    M Source/WebCore/rendering/svg/RenderSVGContainer.h
    M Source/WebCore/rendering/svg/RenderSVGRoot.cpp
    M Source/WebCore/rendering/svg/RenderSVGRoot.h
    M Source/WebCore/rendering/svg/SVGBoundingBoxComputation.cpp
    M Source/WebCore/rendering/svg/SVGBoundingBoxComputation.h
    M Source/WebCore/style/StyleUpdate.h
    M Source/WebCore/svg/SVGAnimateMotionElement.cpp
    M Source/WebCore/svg/SVGElement.cpp
    M Source/WebCore/svg/SVGElement.h
    M Source/WebCore/svg/SVGGraphicsElement.cpp

  Log Message:
  -----------
  [LBSE] Defer per-element SVG transform-attribute work without style recalc
https://bugs.webkit.org/show_bug.cgi?id=315782

Reviewed by Rob Buis.

SVGGraphicsElement::svgAttributeChanged and SVGAnimateMotionElement used
to call repaintOrRelayoutAfterSVGTransformChange() synchronously per
attribute mutation. On MotionMark/Suits that produced 2N repaint() calls
per frame and dominated the profile.

To fix that, batch the per-element work into a once-per-frame queue on
LocalFrameViewLayoutContext, deduplicated by a single bit on RenderElement.
The queue is flushed from Document::updateLayout (after updateStyleIfNeeded,
so updateLayerTransform sees post-style geometry) and from
flushUpdateLayerPositions for scroll-driven walks.

The flush runs in three phases:

 1. Snapshot pre-mutation repaint rects for non-layered renderers.
 2. Mutate transforms - for layered renderers this just dirties the batched
    position-update bit.
 3. Emit a delta repaint from the snapshot via repaintAfterLayoutIfNeeded(),
    like the legacy engine's LayoutRepainter but spanning the whole flush.

I've experimented with single passes, batching, etc. in the end this approach
led to most improvments in MotionMark/Suits.

With this layout/style-recalc free approach, we need to ddress bounding-box
correctness: a container/root caches objectBoundingBox()/strokeBoundingBox(),
which fold in descendant transforms but were only refreshed at layout -- this
step is skipped in the new path, so getBBox() could go stale. A dirty bit on
RenderSVGContainer/RenderSVGRoot fixes this: the second phase marks the
container ancestor chain (walking parent(), so layered and non-layered renderers
are handled alike), and the boxes recompute lazily on _read_ via
SVGBoundingBoxComputation::recomputeTransformDependentBoundingBoxes().
layoutChildren() now defers them the same way, so the subtree walk is only
paid when something actually reads a box.

This again improves MotionMark/Suits performance by ~10% on LBSE.
Covered by existing tests (svg/repaint).

* Source/WebCore/dom/Document.cpp:
(WebCore::Document::updateSVGRenderer):
(WebCore::Document::updateLayout):
(WebCore::Document::updateLayoutIfDimensionsOutOfDate):
* Source/WebCore/dom/Document.h:
(WebCore::Document::updateSVGRenderer):
* Source/WebCore/page/LocalFrameViewLayoutContext.cpp:
(WebCore::LocalFrameViewLayoutContext::flushUpdateLayerPositions):
(WebCore::LocalFrameViewLayoutContext::addPendingSVGTransformAttributeUpdate):
(WebCore::LocalFrameViewLayoutContext::flushPendingSVGTransformAttributeUpdatesIfNeeded):
* Source/WebCore/page/LocalFrameViewLayoutContext.h:
* Source/WebCore/rendering/RenderElement.h:
(WebCore::RenderElement::isInPendingSVGTransformAttributeUpdates const):
(WebCore::RenderElement::setIsInPendingSVGTransformAttributeUpdates):
* Source/WebCore/rendering/RenderLayerModelObject.cpp:
(WebCore::RenderLayerModelObject::updateTransformAndRepaintForSVGAfterAttributeChange):
(WebCore::RenderLayerModelObject::repaintOrRelayoutAfterSVGTransformChange): 
Deleted.
* Source/WebCore/rendering/RenderLayerModelObject.h:
(WebCore::RenderLayerModelObject::invalidateCachedSVGTransformDependentBoundingBoxes):
* Source/WebCore/rendering/svg/RenderSVGContainer.cpp:
(WebCore::RenderSVGContainer::layoutChildren):
(WebCore::RenderSVGContainer::updateSVGTransformDependentBoundingBoxesIfNeeded 
const):
(WebCore::RenderSVGContainer::strokeBoundingBox const):
(WebCore::RenderSVGContainer::nodeAtPoint):
* Source/WebCore/rendering/svg/RenderSVGContainer.h:
(WebCore::RenderSVGContainer::isObjectBoundingBoxValid const):
* Source/WebCore/rendering/svg/RenderSVGRoot.cpp:
(WebCore::RenderSVGRoot::layoutChildren):
(WebCore::RenderSVGRoot::updateSVGTransformDependentBoundingBoxesIfNeeded 
const):
(WebCore::RenderSVGRoot::strokeBoundingBox const):
* Source/WebCore/rendering/svg/RenderSVGRoot.h:
* Source/WebCore/rendering/svg/SVGBoundingBoxComputation.cpp:
(WebCore::SVGBoundingBoxComputation::recomputeTransformDependentBoundingBoxes):
* Source/WebCore/rendering/svg/SVGBoundingBoxComputation.h:
* Source/WebCore/style/StyleUpdate.h:
* Source/WebCore/svg/SVGAnimateMotionElement.cpp:
(WebCore::SVGAnimateMotionElement::applyResultsToTarget):
* Source/WebCore/svg/SVGElement.cpp:
(WebCore::SVGElement::updateSVGRendererForElementChange):
* Source/WebCore/svg/SVGElement.h:
(WebCore::SVGElement::updateSVGRendererForElementChange):
* Source/WebCore/svg/SVGGraphicsElement.cpp:
(WebCore::SVGGraphicsElement::svgAttributeChanged):

Canonical link: https://commits.webkit.org/314458@main



To unsubscribe from these emails, change your notification settings at 
https://github.com/WebKit/WebKit/settings/notifications

Reply via email to