Skip to content
Permalink
Browse files
Do not issue repaint when the ancestor layer has already been schedul…
…ed 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
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@294902 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
alanbujtas committed May 26, 2022
1 parent e4b3efb commit 71524a1f562d04de5c96c88613d7540cf9d04579
Showing 5 changed files with 50 additions and 18 deletions.
@@ -2024,7 +2024,7 @@ RenderLayer* RenderLayer::enclosingCompositingLayer(IncludeSelfOrNot includeSelf
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 @@ RenderLayer* RenderLayer::enclosingCompositingLayerForRepaint(IncludeSelfOrNot i

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 @@ ClipRects* RenderLayer::clipRects(const ClipRectsContext& context) const
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 @@ static TextStream& operator<<(TextStream& ts, RenderLayer::EventRegionInvalidati
bool RenderLayer::invalidateEventRegion(EventRegionInvalidationReason reason)
{
#if ENABLE(ASYNC_SCROLLING)
auto* compositingLayer = enclosingCompositingLayerForRepaint();
auto* compositingLayer = enclosingCompositingLayerForRepaint().layer;

auto shouldInvalidate = [&] {
if (!compositingLayer)
@@ -590,7 +590,11 @@ class RenderLayer : public CanMakeWeakPtr<RenderLayer> {

// 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 @@ class RenderLayer : public CanMakeWeakPtr<RenderLayer> {

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(); }
@@ -1956,7 +1956,7 @@ void RenderLayerCompositor::repaintOnCompositingChange(RenderLayer& layer)
// 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;

@@ -860,19 +860,24 @@ LayoutRect RenderObject::paintingRootRect(LayoutRect& topLevelRect)
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 @@ RenderObject::RepaintContainerStatus RenderObject::containerForRepaint() const
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 @@ void RenderObject::repaintUsingContainer(const RenderLayerModelObject* repaintCo
}
}

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 @@ void RenderObject::repaint() const
return;

auto repaintContainer = containerForRepaint();
if (!repaintContainer.renderer)
repaintContainer = { fullRepaintIsScheduled(*this), &view };

if (!repaintContainer.fullRepaintIsScheduled)
repaintUsingContainer(repaintContainer.renderer, clippedOverflowRectForRepaint(repaintContainer.renderer));
}
@@ -992,6 +1011,9 @@ void RenderObject::repaintRectangle(const LayoutRect& r, bool shouldClipToLayer)
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);
}
@@ -380,7 +380,7 @@ void RenderView::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint&)
break;
}

if (RenderLayer* compositingLayer = layer->enclosingCompositingLayerForRepaint()) {
if (auto* compositingLayer = layer->enclosingCompositingLayerForRepaint().layer) {
if (!compositingLayer->backing()->paintsIntoWindow()) {
frameView().setCannotBlitToWindow();
break;

0 comments on commit 71524a1

Please sign in to comment.