Title: [294902] trunk/Source/WebCore/rendering
Revision
294902
Author
za...@apple.com
Date
2022-05-26 15:22:08 -0700 (Thu, 26 May 2022)

Log Message

Do not issue repaint when the ancestor layer has already been scheduled for one
https://bugs.webkit.org/show_bug.cgi?id=240728

Reviewed by Simon Fraser.

When a renderer needs repaint, we walk the layer tree to search for the repaint container (root for all the paints).
If we find a layer between the renderer and the repaint container that has already been scheduled for a full repaint
we know that this repaint is redundant and will be covered by the ancestor layer.
Since layers paint their overflow content, this works even when the renderer "sticks out" of the ancestor layer's renderer's border box (i.e. produces ink/scrollable overflow).

* Source/WebCore/rendering/RenderLayer.cpp:
(WebCore::RenderLayer::enclosingCompositingLayerForRepaint const):
(WebCore::RenderLayer::clipCrossesPaintingBoundary const):
(WebCore::RenderLayer::calculateClipRects const):
* Source/WebCore/rendering/RenderLayer.h:
(WebCore::RenderLayer::needsFullRepaint const):
* Source/WebCore/rendering/RenderLayerCompositor.cpp:
(WebCore::RenderLayerCompositor::repaintInCompositedAncestor):
* Source/WebCore/rendering/RenderObject.cpp:
(WebCore::RenderObject::containerForRepaint const):
(WebCore::fullRepaintIsScheduled): This covers the cases when the content is embedded inside an iframe and the iframe's view is not composited.
(WebCore::RenderObject::repaint const):
(WebCore::RenderObject::repaintRectangle const):
* Source/WebCore/rendering/RenderView.cpp:
(WebCore::RenderView::paintBoxDecorations):

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

Modified Paths

Diff

Modified: trunk/Source/WebCore/rendering/RenderLayer.cpp (294901 => 294902)


--- trunk/Source/WebCore/rendering/RenderLayer.cpp	2022-05-26 22:15:24 UTC (rev 294901)
+++ trunk/Source/WebCore/rendering/RenderLayer.cpp	2022-05-26 22:22:08 UTC (rev 294902)
@@ -2024,7 +2024,7 @@
     return nullptr;
 }
 
-RenderLayer* RenderLayer::enclosingCompositingLayerForRepaint(IncludeSelfOrNot includeSelf) const
+RenderLayer::EnclosingCompositingLayerStatus RenderLayer::enclosingCompositingLayerForRepaint(IncludeSelfOrNot includeSelf) const
 {
     auto repaintTargetForLayer = [](const RenderLayer& layer) -> RenderLayer* {
         if (compositedWithOwnBackingStore(layer))
@@ -2035,17 +2035,22 @@
         
         return nullptr;
     };
+    auto isEligibleForFullRepaintCheck = [&](const auto& layer) {
+        return layer.isSelfPaintingLayer() && !layer.renderer().hasPotentiallyScrollableOverflow() && !is<RenderView>(layer.renderer());
+    };
 
+    auto fullRepaintAlreadyScheduled = isEligibleForFullRepaintCheck(*this) && needsFullRepaint();
     RenderLayer* repaintTarget = nullptr;
     if (includeSelf == IncludeSelf && (repaintTarget = repaintTargetForLayer(*this)))
-        return repaintTarget;
+        return { fullRepaintAlreadyScheduled, repaintTarget };
 
     for (const RenderLayer* curr = paintOrderParent(); curr; curr = curr->paintOrderParent()) {
+        fullRepaintAlreadyScheduled = fullRepaintAlreadyScheduled || (isEligibleForFullRepaintCheck(*curr) && curr->needsFullRepaint());
         if ((repaintTarget = repaintTargetForLayer(*curr)))
-            return repaintTarget;
+            return { fullRepaintAlreadyScheduled, repaintTarget };
     }
          
-    return nullptr;
+    return { };
 }
 
 RenderLayer* RenderLayer::enclosingFilterLayer(IncludeSelfOrNot includeSelf) const
@@ -4612,7 +4617,7 @@
 bool RenderLayer::clipCrossesPaintingBoundary() const
 {
     return parent()->enclosingPaginationLayer(IncludeCompositedPaginatedLayers) != enclosingPaginationLayer(IncludeCompositedPaginatedLayers)
-        || parent()->enclosingCompositingLayerForRepaint() != enclosingCompositingLayerForRepaint();
+        || parent()->enclosingCompositingLayerForRepaint().layer != enclosingCompositingLayerForRepaint().layer;
 }
 
 void RenderLayer::calculateClipRects(const ClipRectsContext& clipRectsContext, ClipRects& clipRects) const
@@ -5811,7 +5816,7 @@
 bool RenderLayer::invalidateEventRegion(EventRegionInvalidationReason reason)
 {
 #if ENABLE(ASYNC_SCROLLING)
-    auto* compositingLayer = enclosingCompositingLayerForRepaint();
+    auto* compositingLayer = enclosingCompositingLayerForRepaint().layer;
 
     auto shouldInvalidate = [&] {
         if (!compositingLayer)

Modified: trunk/Source/WebCore/rendering/RenderLayer.h (294901 => 294902)


--- trunk/Source/WebCore/rendering/RenderLayer.h	2022-05-26 22:15:24 UTC (rev 294901)
+++ trunk/Source/WebCore/rendering/RenderLayer.h	2022-05-26 22:22:08 UTC (rev 294902)
@@ -590,7 +590,11 @@
 
     // Enclosing compositing layer; if includeSelf is true, may return this.
     RenderLayer* enclosingCompositingLayer(IncludeSelfOrNot = IncludeSelf) const;
-    RenderLayer* enclosingCompositingLayerForRepaint(IncludeSelfOrNot = IncludeSelf) const;
+    struct EnclosingCompositingLayerStatus {
+        bool fullRepaintAlreadyScheduled { false };
+        RenderLayer* layer { nullptr };
+    };
+    EnclosingCompositingLayerStatus enclosingCompositingLayerForRepaint(IncludeSelfOrNot = IncludeSelf) const;
     // Ancestor compositing layer, excluding this.
     RenderLayer* ancestorCompositingLayer() const { return enclosingCompositingLayer(ExcludeSelf); }
 
@@ -721,6 +725,7 @@
 
     void setRepaintStatus(RepaintStatus status) { m_repaintStatus = status; }
     RepaintStatus repaintStatus() const { return static_cast<RepaintStatus>(m_repaintStatus); }
+    bool needsFullRepaint() const { return m_repaintStatus == NeedsFullRepaint || m_repaintStatus == NeedsFullRepaintForPositionedMovementLayout; }
 
     LayoutUnit staticInlinePosition() const { return m_offsetForPosition.width(); }
     LayoutUnit staticBlockPosition() const { return m_offsetForPosition.height(); }

Modified: trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp (294901 => 294902)


--- trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp	2022-05-26 22:15:24 UTC (rev 294901)
+++ trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp	2022-05-26 22:22:08 UTC (rev 294902)
@@ -1956,7 +1956,7 @@
 // This method assumes that layout is up-to-date, unlike repaintOnCompositingChange().
 void RenderLayerCompositor::repaintInCompositedAncestor(RenderLayer& layer, const LayoutRect& rect)
 {
-    auto* compositedAncestor = layer.enclosingCompositingLayerForRepaint(ExcludeSelf);
+    auto* compositedAncestor = layer.enclosingCompositingLayerForRepaint(ExcludeSelf).layer;
     if (!compositedAncestor)
         return;
 

Modified: trunk/Source/WebCore/rendering/RenderObject.cpp (294901 => 294902)


--- trunk/Source/WebCore/rendering/RenderObject.cpp	2022-05-26 22:15:24 UTC (rev 294901)
+++ trunk/Source/WebCore/rendering/RenderObject.cpp	2022-05-26 22:22:08 UTC (rev 294902)
@@ -860,19 +860,24 @@
 RenderObject::RepaintContainerStatus RenderObject::containerForRepaint() const
 {
     RenderLayerModelObject* repaintContainer = nullptr;
+    auto fullRepaintAlreadyScheduled = false;
 
     if (view().usesCompositing()) {
-        if (RenderLayer* parentLayer = enclosingLayer()) {
-            RenderLayer* compLayer = parentLayer->enclosingCompositingLayerForRepaint();
-            if (compLayer)
-                repaintContainer = &compLayer->renderer();
+        if (auto* parentLayer = enclosingLayer()) {
+            auto compLayerStatus = parentLayer->enclosingCompositingLayerForRepaint();
+            if (compLayerStatus.layer) {
+                repaintContainer = &compLayerStatus.layer->renderer();
+                fullRepaintAlreadyScheduled = compLayerStatus.fullRepaintAlreadyScheduled;
+            }
         }
     }
     if (view().hasSoftwareFilters()) {
-        if (RenderLayer* parentLayer = enclosingLayer()) {
-            RenderLayer* enclosingFilterLayer = parentLayer->enclosingFilterLayer();
-            if (enclosingFilterLayer)
-                return { false, &enclosingFilterLayer->renderer() };
+        if (auto* parentLayer = enclosingLayer()) {
+            auto* enclosingFilterLayer = parentLayer->enclosingFilterLayer();
+            if (enclosingFilterLayer) {
+                fullRepaintAlreadyScheduled = parentLayer->needsFullRepaint();
+                return { fullRepaintAlreadyScheduled, &enclosingFilterLayer->renderer() };
+            }
         }
     }
 
@@ -887,7 +892,7 @@
         if (!repaintContainerFragmentedFlow || repaintContainerFragmentedFlow != parentRenderFragmentedFlow)
             repaintContainer = parentRenderFragmentedFlow;
     }
-    return { false, repaintContainer };
+    return { fullRepaintAlreadyScheduled, repaintContainer };
 }
 
 void RenderObject::propagateRepaintToParentWithOutlineAutoIfNeeded(const RenderLayerModelObject& repaintContainer, const LayoutRect& repaintRect) const
@@ -961,6 +966,17 @@
     }
 }
 
+static inline bool fullRepaintIsScheduled(const RenderObject& renderer)
+{
+    if (!renderer.view().usesCompositing() && !renderer.document().ownerElement())
+        return false;
+    for (auto* ancestorLayer = renderer.enclosingLayer(); ancestorLayer; ancestorLayer = ancestorLayer->paintOrderParent()) {
+        if (ancestorLayer->needsFullRepaint())
+            return true;
+    }
+    return false;
+}
+
 void RenderObject::repaint() const
 {
     // Don't repaint if we're unrooted (note that view() still returns the view when unrooted)
@@ -972,6 +988,9 @@
         return;
 
     auto repaintContainer = containerForRepaint();
+    if (!repaintContainer.renderer)
+        repaintContainer = { fullRepaintIsScheduled(*this), &view };
+
     if (!repaintContainer.fullRepaintIsScheduled)
         repaintUsingContainer(repaintContainer.renderer, clippedOverflowRectForRepaint(repaintContainer.renderer));
 }
@@ -992,6 +1011,9 @@
     dirtyRect.move(view.frameView().layoutContext().layoutDelta());
 
     auto repaintContainer = containerForRepaint();
+    if (!repaintContainer.renderer)
+        repaintContainer = { fullRepaintIsScheduled(*this), &view };
+
     if (!repaintContainer.fullRepaintIsScheduled)
         repaintUsingContainer(repaintContainer.renderer, computeRectForRepaint(dirtyRect, repaintContainer.renderer), shouldClipToLayer);
 }

Modified: trunk/Source/WebCore/rendering/RenderView.cpp (294901 => 294902)


--- trunk/Source/WebCore/rendering/RenderView.cpp	2022-05-26 22:15:24 UTC (rev 294901)
+++ trunk/Source/WebCore/rendering/RenderView.cpp	2022-05-26 22:22:08 UTC (rev 294902)
@@ -380,7 +380,7 @@
             break;
         }
 
-        if (RenderLayer* compositingLayer = layer->enclosingCompositingLayerForRepaint()) {
+        if (auto* compositingLayer = layer->enclosingCompositingLayerForRepaint().layer) {
             if (!compositingLayer->backing()->paintsIntoWindow()) {
                 frameView().setCannotBlitToWindow();
                 break;
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to