Skip to content
Permalink
Browse files
RenderObject::containerForRepaint should be able to tell if a full re…
…paint has already been scheduled.

https://bugs.webkit.org/show_bug.cgi?id=240721

Reviewed by Simon Fraser.

This patch is in preparation for reducing redundant repaints when an ancestor layer (between the renderer and the repaint container) has already been scheduled for one.

* Source/WebCore/editing/SelectionGeometryGatherer.cpp:
(WebCore::SelectionGeometryGatherer::addQuad):
(WebCore::SelectionGeometryGatherer::addGapRects):
* Source/WebCore/editing/SelectionGeometryGatherer.h:
* Source/WebCore/page/FrameView.cpp:
(WebCore::FrameView::isEnclosedInCompositingLayer const):
* Source/WebCore/rendering/LayoutRepainter.cpp:
(WebCore::LayoutRepainter::LayoutRepainter):
(WebCore::LayoutRepainter::repaintAfterLayout):
* Source/WebCore/rendering/LayoutRepainter.h:
* Source/WebCore/rendering/LegacyLineLayout.cpp:
(WebCore::LegacyLineLayout::layoutRunsAndFloats):
* Source/WebCore/rendering/RenderElement.cpp:
(WebCore::RenderElement::issueRepaintForOutlineAuto):
* Source/WebCore/rendering/RenderFragmentedFlow.cpp:
(WebCore::RenderFragmentedFlow::mapLocalToContainer const):
* Source/WebCore/rendering/RenderFrameSet.cpp:
(WebCore::RenderFrameSet::layout):
* Source/WebCore/rendering/RenderLayer.cpp:
(WebCore::RenderLayer::recursiveUpdateLayerPositions):
(WebCore::RenderLayer::computeRepaintRectsIncludingDescendants):
(WebCore::RenderLayer::recursiveUpdateLayerPositionsAfterScroll):
(WebCore::RenderLayer::setHasVisibleContent):
(WebCore::RenderLayer::calculateClipRects const):
* Source/WebCore/rendering/RenderLayer.h:
* Source/WebCore/rendering/RenderLayerCompositor.cpp:
(WebCore::RenderLayerCompositor::repaintOnCompositingChange):
* Source/WebCore/rendering/RenderLayerModelObject.cpp:
(WebCore::RenderLayerModelObject::styleDidChange):
* Source/WebCore/rendering/RenderLayerScrollableArea.cpp:
(WebCore::RenderLayerScrollableArea::scrollTo):
* Source/WebCore/rendering/RenderObject.cpp:
(WebCore::RenderObject::containerForRepaint const):
(WebCore::RenderObject::repaint const):
(WebCore::RenderObject::repaintRectangle const):
(WebCore::RenderObject::repaintSlowRepaintObject const):
* Source/WebCore/rendering/RenderObject.h:
* Source/WebCore/rendering/RenderSelectionInfo.cpp:
(WebCore::RenderSelectionInfoBase::RenderSelectionInfoBase):
* Source/WebCore/rendering/RenderSelectionInfo.h:
(WebCore::RenderSelectionInfoBase::repaintContainer const):
* Source/WebCore/rendering/RenderView.cpp:
(WebCore::RenderView::repaintRootContents):

Canonical link: https://commits.webkit.org/250898@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@294699 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
alanbujtas committed May 24, 2022
1 parent ced7fb0 commit fd201ab9239c17ec6f23add3aa7af919ea07e4e0
Showing 19 changed files with 48 additions and 43 deletions.
@@ -43,13 +43,13 @@ SelectionGeometryGatherer::SelectionGeometryGatherer(RenderView& renderView)
{
}

void SelectionGeometryGatherer::addQuad(RenderLayerModelObject *repaintContainer, const FloatQuad& quad)
void SelectionGeometryGatherer::addQuad(const RenderLayerModelObject* repaintContainer, const FloatQuad& quad)
{
if (!quad.boundingBoxIsEmpty())
m_quads.append(repaintContainer ? repaintContainer->localToAbsoluteQuad(quad) : quad);
}

void SelectionGeometryGatherer::addGapRects(RenderLayerModelObject *repaintContainer, const GapRects& rects)
void SelectionGeometryGatherer::addGapRects(const RenderLayerModelObject* repaintContainer, const GapRects& rects)
{
if (repaintContainer) {
GapRects absoluteGapRects;
@@ -45,8 +45,8 @@ class SelectionGeometryGatherer {
public:
SelectionGeometryGatherer(RenderView&);

void addQuad(RenderLayerModelObject *repaintContainer, const FloatQuad&);
void addGapRects(RenderLayerModelObject *repaintContainer, const GapRects&);
void addQuad(const RenderLayerModelObject* repaintContainer, const FloatQuad&);
void addGapRects(const RenderLayerModelObject* repaintContainer, const GapRects&);
void setTextOnly(bool isTextOnly) { m_isTextOnly = isTextOnly; }
bool isTextOnly() const { return m_isTextOnly; }

@@ -1185,7 +1185,7 @@ void FrameView::enterCompositingMode()
bool FrameView::isEnclosedInCompositingLayer() const
{
auto frameOwnerRenderer = frame().ownerRenderer();
if (frameOwnerRenderer && frameOwnerRenderer->containerForRepaint())
if (frameOwnerRenderer && frameOwnerRenderer->containerForRepaint().renderer)
return true;

if (FrameView* parentView = parentFrameView())
@@ -30,21 +30,20 @@

namespace WebCore {

LayoutRepainter::LayoutRepainter(RenderElement& object, bool checkForRepaint)
: m_object(object)
, m_repaintContainer(0)
LayoutRepainter::LayoutRepainter(RenderElement& renderer, bool checkForRepaint)
: m_renderer(renderer)
, m_checkForRepaint(checkForRepaint)
{
if (m_checkForRepaint) {
m_repaintContainer = m_object.containerForRepaint();
m_oldBounds = m_object.clippedOverflowRectForRepaint(m_repaintContainer);
m_oldOutlineBox = m_object.outlineBoundsForRepaint(m_repaintContainer);
m_repaintContainer = m_renderer.containerForRepaint().renderer;
m_oldBounds = m_renderer.clippedOverflowRectForRepaint(m_repaintContainer);
m_oldOutlineBox = m_renderer.outlineBoundsForRepaint(m_repaintContainer);
}
}

bool LayoutRepainter::repaintAfterLayout()
{
return m_checkForRepaint ? m_object.repaintAfterLayoutIfNeeded(m_repaintContainer, m_oldBounds, m_oldOutlineBox) : false;
return m_checkForRepaint ? m_renderer.repaintAfterLayoutIfNeeded(m_repaintContainer, m_oldBounds, m_oldOutlineBox) : false;
}

} // namespace WebCore
@@ -42,8 +42,8 @@ class LayoutRepainter {
bool repaintAfterLayout();

private:
RenderElement& m_object;
RenderLayerModelObject* m_repaintContainer;
RenderElement& m_renderer;
const RenderLayerModelObject* m_repaintContainer { nullptr };
// We store these values as LayoutRects, but the final invalidations will be pixel snapped
LayoutRect m_oldBounds;
LayoutRect m_oldOutlineBox;
@@ -1348,7 +1348,7 @@ void LegacyLineLayout::layoutRunsAndFloats(LineLayoutState& layoutState, bool ha
// that the block really needed a full layout, we missed our chance to repaint the layer
// before layout started. Luckily the layer has cached the repaint rect for its original
// position and size, and so we can use that to make a repaint happen now.
m_flow.repaintUsingContainer(m_flow.containerForRepaint(), m_flow.layerRepaintRects()->clippedOverflowRect);
m_flow.repaintUsingContainer(m_flow.containerForRepaint().renderer, m_flow.layerRepaintRects()->clippedOverflowRect);
}
}

@@ -2112,7 +2112,7 @@ void RenderElement::issueRepaintForOutlineAuto(float outlineSize)
{
LayoutRect repaintRect;
Vector<LayoutRect> focusRingRects;
addFocusRingRects(focusRingRects, LayoutPoint(), containerForRepaint());
addFocusRingRects(focusRingRects, LayoutPoint(), containerForRepaint().renderer);
for (auto rect : focusRingRects) {
rect.inflate(outlineSize);
repaintRect.unite(rect);
@@ -948,7 +948,7 @@ void RenderFragmentedFlow::mapLocalToContainer(const RenderLayerModelObject* anc

// If the repaint container is nullptr, we have to climb up to the RenderView, otherwise swap
// it with the fragment's repaint container.
ancestorContainer = ancestorContainer ? fragment->containerForRepaint() : nullptr;
ancestorContainer = ancestorContainer ? fragment->containerForRepaint().renderer : nullptr;

if (RenderFragmentedFlow* fragmentFragmentedFlow = fragment->enclosingFragmentedFlow()) {
RenderFragmentContainer* startFragment = nullptr;
@@ -436,9 +436,9 @@ void RenderFrameSet::layout()

bool doFullRepaint = selfNeedsLayout() && checkForRepaintDuringLayout();
LayoutRect oldBounds;
RenderLayerModelObject* repaintContainer = 0;
const RenderLayerModelObject* repaintContainer = nullptr;
if (doFullRepaint) {
repaintContainer = containerForRepaint();
repaintContainer = containerForRepaint().renderer;
oldBounds = clippedOverflowRectForRepaint(repaintContainer);
}

@@ -990,7 +990,7 @@ void RenderLayer::recursiveUpdateLayerPositions(RenderGeometryMap* geometryMap,
// LayoutState outside the layout() phase and use it here.
ASSERT(!renderer().view().frameView().layoutContext().isPaintOffsetCacheEnabled());

RenderLayerModelObject* repaintContainer = renderer().containerForRepaint();
auto* repaintContainer = renderer().containerForRepaint().renderer;

auto oldRects = repaintRects();
computeRepaintRects(repaintContainer, geometryMap);
@@ -1145,7 +1145,7 @@ void RenderLayer::computeRepaintRectsIncludingDescendants()
// FIXME: computeRepaintRects() has to walk up the parent chain for every layer to compute the rects.
// We should make this more efficient.
// FIXME: it's wrong to call this when layout is not up-to-date, which we do.
computeRepaintRects(renderer().containerForRepaint());
computeRepaintRects(renderer().containerForRepaint().renderer);

for (RenderLayer* layer = firstChild(); layer; layer = layer->nextSibling())
layer->computeRepaintRectsIncludingDescendants();
@@ -1222,13 +1222,13 @@ void RenderLayer::recursiveUpdateLayerPositionsAfterScroll(RenderGeometryMap* ge
if (isVisuallyEmpty)
clearRepaintRects();
else // FIXME: We could track the repaint container as we walk down the tree.
computeRepaintRects(renderer().containerForRepaint(), geometryMap);
computeRepaintRects(renderer().containerForRepaint().renderer, geometryMap);
} else if (!renderer().view().frameView().platformWidget()) {
// When ScrollView's m_paintsEntireContents flag flips due to layer backing changes, the repaint area transitions from
// visual to layout overflow. When this happens the cached repaint rects become invalid and they need to be recomputed (see webkit.org/b/188121).
// Check that our cached rects are correct.
ASSERT_IMPLIES(m_repaintRectsValid, m_repaintRects.clippedOverflowRect == renderer().clippedOverflowRectForRepaint(renderer().containerForRepaint()));
ASSERT_IMPLIES(m_repaintRectsValid, m_repaintRects.outlineBoundsRect == renderer().outlineBoundsForRepaint(renderer().containerForRepaint()));
ASSERT_IMPLIES(m_repaintRectsValid, m_repaintRects.clippedOverflowRect == renderer().clippedOverflowRectForRepaint(renderer().containerForRepaint().renderer));
ASSERT_IMPLIES(m_repaintRectsValid, m_repaintRects.outlineBoundsRect == renderer().outlineBoundsForRepaint(renderer().containerForRepaint().renderer));
}

for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
@@ -1506,7 +1506,7 @@ void RenderLayer::setHasVisibleContent()

m_visibleContentStatusDirty = false;
m_hasVisibleContent = true;
computeRepaintRects(renderer().containerForRepaint());
computeRepaintRects(renderer().containerForRepaint().renderer);
if (!isNormalFlowOnly()) {
// We don't collect invisible layers in z-order lists if we are not in compositing mode.
// As we became visible, we need to dirty our stacking containers ancestors to be properly
@@ -5347,7 +5347,7 @@ void RenderLayer::setBackingNeedsRepaintInRect(const LayoutRect& r, GraphicsLaye
}

// Since we're only painting non-composited layers, we know that they all share the same repaintContainer.
void RenderLayer::repaintIncludingNonCompositingDescendants(RenderLayerModelObject* repaintContainer)
void RenderLayer::repaintIncludingNonCompositingDescendants(const RenderLayerModelObject* repaintContainer)
{
auto clippedOverflowRect = m_repaintRectsValid ? m_repaintRects.clippedOverflowRect : renderer().clippedOverflowRectForRepaint(repaintContainer);
renderer().repaintUsingContainer(repaintContainer, clippedOverflowRect);
@@ -428,7 +428,7 @@ class RenderLayer : public CanMakeWeakPtr<RenderLayer> {

// The rect is in the coordinate space of the layer's render object.
void setBackingNeedsRepaintInRect(const LayoutRect&, GraphicsLayer::ShouldClipToLayer = GraphicsLayer::ClipToLayer);
void repaintIncludingNonCompositingDescendants(RenderLayerModelObject* repaintContainer);
void repaintIncludingNonCompositingDescendants(const RenderLayerModelObject* repaintContainer);

void styleChanged(StyleDifference, const RenderStyle* oldStyle);

@@ -1940,7 +1940,7 @@ void RenderLayerCompositor::repaintOnCompositingChange(RenderLayer& layer)
if (&layer.renderer() != &m_renderView && !layer.renderer().parent())
return;

auto* repaintContainer = layer.renderer().containerForRepaint();
auto* repaintContainer = layer.renderer().containerForRepaint().renderer;
if (!repaintContainer)
repaintContainer = &m_renderView;

@@ -137,7 +137,7 @@ void RenderLayerModelObject::styleDidChange(StyleDifference diff, const RenderSt

// Repaint the about to be destroyed self-painting layer when style change also triggers repaint.
if (layer()->isSelfPaintingLayer() && layer()->repaintStatus() == NeedsFullRepaint && layer()->repaintRects())
repaintUsingContainer(containerForRepaint(), layer()->repaintRects()->clippedOverflowRect);
repaintUsingContainer(containerForRepaint().renderer, layer()->repaintRects()->clippedOverflowRect);

layer()->removeOnlyThisLayer(RenderLayer::LayerChangeTiming::StyleChange); // calls destroyLayer() which clears m_layer
if (s_wasFloating && isFloating())
@@ -361,7 +361,7 @@ void RenderLayerScrollableArea::scrollTo(const ScrollPosition& position)
}

Frame& frame = renderer.frame();
RenderLayerModelObject* repaintContainer = renderer.containerForRepaint();
auto* repaintContainer = renderer.containerForRepaint().renderer;
// The caret rect needs to be invalidated after scrolling
frame.selection().setCaretRectNeedsUpdate();

@@ -857,7 +857,7 @@ LayoutRect RenderObject::paintingRootRect(LayoutRect& topLevelRect)
return result;
}

RenderLayerModelObject* RenderObject::containerForRepaint() const
RenderObject::RepaintContainerStatus RenderObject::containerForRepaint() const
{
RenderLayerModelObject* repaintContainer = nullptr;

@@ -872,7 +872,7 @@ RenderLayerModelObject* RenderObject::containerForRepaint() const
if (RenderLayer* parentLayer = enclosingLayer()) {
RenderLayer* enclosingFilterLayer = parentLayer->enclosingFilterLayer();
if (enclosingFilterLayer)
return &enclosingFilterLayer->renderer();
return { false, &enclosingFilterLayer->renderer() };
}
}

@@ -887,7 +887,7 @@ RenderLayerModelObject* RenderObject::containerForRepaint() const
if (!repaintContainerFragmentedFlow || repaintContainerFragmentedFlow != parentRenderFragmentedFlow)
repaintContainer = parentRenderFragmentedFlow;
}
return repaintContainer;
return { false, repaintContainer };
}

void RenderObject::propagateRepaintToParentWithOutlineAutoIfNeeded(const RenderLayerModelObject& repaintContainer, const LayoutRect& repaintRect) const
@@ -971,8 +971,9 @@ void RenderObject::repaint() const
if (view.printing())
return;

RenderLayerModelObject* repaintContainer = containerForRepaint();
repaintUsingContainer(repaintContainer, clippedOverflowRectForRepaint(repaintContainer));
auto repaintContainer = containerForRepaint();
if (!repaintContainer.fullRepaintIsScheduled)
repaintUsingContainer(repaintContainer.renderer, clippedOverflowRectForRepaint(repaintContainer.renderer));
}

void RenderObject::repaintRectangle(const LayoutRect& r, bool shouldClipToLayer) const
@@ -990,8 +991,9 @@ void RenderObject::repaintRectangle(const LayoutRect& r, bool shouldClipToLayer)
// repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308
dirtyRect.move(view.frameView().layoutContext().layoutDelta());

RenderLayerModelObject* repaintContainer = containerForRepaint();
repaintUsingContainer(repaintContainer, computeRectForRepaint(dirtyRect, repaintContainer), shouldClipToLayer);
auto repaintContainer = containerForRepaint();
if (!repaintContainer.fullRepaintIsScheduled)
repaintUsingContainer(repaintContainer.renderer, computeRectForRepaint(dirtyRect, repaintContainer.renderer), shouldClipToLayer);
}

void RenderObject::repaintSlowRepaintObject() const
@@ -1004,7 +1006,7 @@ void RenderObject::repaintSlowRepaintObject() const
if (view.printing())
return;

const RenderLayerModelObject* repaintContainer = containerForRepaint();
auto* repaintContainer = containerForRepaint().renderer;

bool shouldClipToLayer = true;
IntRect repaintRect;
@@ -630,7 +630,11 @@ class RenderObject : public CachedImageClient {

// Return the RenderLayerModelObject in the container chain which is responsible for painting this object, or nullptr
// if painting is root-relative. This is the container that should be passed to the 'forRepaint' functions.
RenderLayerModelObject* containerForRepaint() const;
struct RepaintContainerStatus {
bool fullRepaintIsScheduled { false }; // Either the repaint container or a layer in-between has aleady been scheduled for full repaint.
const RenderLayerModelObject* renderer { nullptr };
};
RepaintContainerStatus containerForRepaint() const;
// Actually do the repaint of rect r for this object which has been computed in the coordinate space
// of repaintContainer. If repaintContainer is nullptr, repaint via the view.
void repaintUsingContainer(const RenderLayerModelObject* repaintContainer, const LayoutRect&, bool shouldClipToLayer = true) const;
@@ -32,7 +32,7 @@ namespace WebCore {

RenderSelectionInfoBase::RenderSelectionInfoBase(RenderObject& renderer)
: m_renderer(renderer)
, m_repaintContainer(renderer.containerForRepaint())
, m_repaintContainer(renderer.containerForRepaint().renderer)
, m_state(renderer.selectionState())
{
}
@@ -34,14 +34,14 @@ class RenderSelectionInfoBase {
WTF_MAKE_NONCOPYABLE(RenderSelectionInfoBase); WTF_MAKE_FAST_ALLOCATED;
public:
explicit RenderSelectionInfoBase(RenderObject& renderer);
RenderLayerModelObject* repaintContainer() const { return m_repaintContainer; }
const RenderLayerModelObject* repaintContainer() const { return m_repaintContainer; }
RenderObject::HighlightState state() const { return m_state; }

protected:
void repaintRectangle(const LayoutRect& repaintRect);

RenderObject& m_renderer;
RenderLayerModelObject* m_repaintContainer;
const RenderLayerModelObject* m_repaintContainer;

private:
RenderObject::HighlightState m_state;
@@ -448,7 +448,7 @@ void RenderView::repaintRootContents()

// Always use layoutOverflowRect() to fix rdar://problem/27182267.
// This should be cleaned up via webkit.org/b/159913 and webkit.org/b/159914.
RenderLayerModelObject* repaintContainer = containerForRepaint();
auto* repaintContainer = containerForRepaint().renderer;
repaintUsingContainer(repaintContainer, computeRectForRepaint(layoutOverflowRect(), repaintContainer));
}

0 comments on commit fd201ab

Please sign in to comment.