Skip to content

Commit 6f39fe0

Browse files
committed
Repaint should only be called on attached renderers
https://bugs.webkit.org/show_bug.cgi?id=272292 Reviewed by Antti Koivisto. 1. In some cases (e.g. pseudo content) a subtree root gets detached first followed by the descendant renderers 2. Repaint functions start with traversing all the way to the RenderView just to check if dispatching repaint is safe -which in most cases comes back true (normal at-layout repaint, invalidation, standard tree teardown) This patch fixes a correctness and a performance issue: correctness: In case of #1, when calling willBeRemovedFromTree() (right before deleting the descendant renderer), the renderer is already detached from the render tree. It is still attached to the root of the subtree (which is already detached), but has no access to the rest of the render tree (i.e. willBeRemovedFromTree is technically just willBeRemovedFromParent) performance: ensuring correctness eliminates the need for checking if the renderer is still attached. (Sadly ::imageChanged gets called indirectly through initializeStyle before the initial attach) * Source/WebCore/rendering/RenderObject.cpp: (WebCore::RenderObject::repaint const): Use isDescendantOf instead of isRooted() as I am planning on completely remove isRooted(). (WebCore::RenderObject::repaintRectangle const): (WebCore::RenderObject::repaintSlowRepaintObject const): * Source/WebCore/rendering/updating/RenderTreeBuilder.cpp: (WebCore::RenderTreeBuilder::destroy): (WebCore::RenderTreeBuilder::detachFromRenderElement): * Source/WebCore/rendering/updating/RenderTreeBuilder.h: Canonical link: https://commits.webkit.org/277186@main
1 parent 1f93f36 commit 6f39fe0

File tree

12 files changed

+69
-37
lines changed

12 files changed

+69
-37
lines changed

LayoutTests/fast/repaint/full-repaint-on-content-change-expected.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
some text
22
(repaint rects
3+
(rect 144 0 64 116)
34
(rect 144 0 64 116)
45
(rect 0 0 64 116)
56
(rect 144 0 64 116)

Source/WebCore/rendering/RenderBox.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2030,12 +2030,10 @@ static StyleImage* findLayerUsedImage(WrappedImagePtr image, const FillLayer& la
20302030

20312031
void RenderBox::imageChanged(WrappedImagePtr image, const IntRect*)
20322032
{
2033-
if (!parent())
2034-
return;
2035-
20362033
if ((style().borderImage().image() && style().borderImage().image()->data() == image) ||
20372034
(style().maskBorder().image() && style().maskBorder().image()->data() == image)) {
2038-
repaint();
2035+
if (parent())
2036+
repaint();
20392037
return;
20402038
}
20412039

@@ -2048,6 +2046,9 @@ void RenderBox::imageChanged(WrappedImagePtr image, const IntRect*)
20482046
bool didFullRepaint = false;
20492047

20502048
auto repaintForBackgroundAndMask = [&](auto& style) {
2049+
if (!parent())
2050+
return;
2051+
20512052
if (!didFullRepaint)
20522053
didFullRepaint = repaintLayerRectsForImage(image, style.backgroundLayers(), true);
20532054
if (!didFullRepaint)

Source/WebCore/rendering/RenderImage.cpp

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -398,14 +398,15 @@ void RenderImage::repaintOrMarkForLayout(ImageSizeChangeType imageSizeChange, co
398398
updateInnerContentRect();
399399
}
400400

401-
LayoutRect repaintRect = contentBoxRect();
402-
if (rect) {
403-
// The image changed rect is in source image coordinates (pre-zooming),
404-
// so map from the bounds of the image to the contentsBox.
405-
repaintRect.intersect(enclosingIntRect(mapRect(*rect, FloatRect(FloatPoint(), imageResource().imageSize(1.0f)), repaintRect)));
401+
if (parent()) {
402+
auto repaintRect = contentBoxRect();
403+
if (rect) {
404+
// The image changed rect is in source image coordinates (pre-zooming),
405+
// so map from the bounds of the image to the contentsBox.
406+
repaintRect.intersect(enclosingIntRect(mapRect(*rect, FloatRect(FloatPoint(), imageResource().imageSize(1.0f)), repaintRect)));
407+
}
408+
repaintRectangle(repaintRect);
406409
}
407-
408-
repaintRectangle(repaintRect);
409410

410411
// Tell any potential compositing layers that the image needs updating.
411412
contentChanged(ImageChanged);

Source/WebCore/rendering/RenderListMarker.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -272,11 +272,13 @@ void RenderListMarker::layout()
272272

273273
void RenderListMarker::imageChanged(WrappedImagePtr o, const IntRect* rect)
274274
{
275-
if (m_image && o == m_image->data()) {
276-
if (width() != m_image->imageSize(this, style().usedZoom()).width() || height() != m_image->imageSize(this, style().usedZoom()).height() || m_image->errorOccurred())
277-
setNeedsLayoutAndPrefWidthsRecalc();
278-
else
279-
repaint();
275+
if (parent()) {
276+
if (m_image && o == m_image->data()) {
277+
if (width() != m_image->imageSize(this, style().usedZoom()).width() || height() != m_image->imageSize(this, style().usedZoom()).height() || m_image->errorOccurred())
278+
setNeedsLayoutAndPrefWidthsRecalc();
279+
else
280+
repaint();
281+
}
280282
}
281283
RenderBox::imageChanged(o, rect);
282284
}

Source/WebCore/rendering/RenderObject.cpp

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1039,21 +1039,24 @@ void RenderObject::issueRepaint(std::optional<LayoutRect> partialRepaintRect, Cl
10391039

10401040
void RenderObject::repaint(ForceRepaint forceRepaint) const
10411041
{
1042-
// Don't repaint if we're unrooted (note that view() still returns the view when unrooted)
1043-
if (!isRooted() || view().printing())
1042+
ASSERT(isDescendantOf(&view()) || is<RenderScrollbarPart>(this) || is<RenderReplica>(this));
1043+
1044+
if (view().printing())
10441045
return;
10451046
issueRepaint({ }, ClipRepaintToLayer::No, forceRepaint);
10461047
}
10471048

10481049
void RenderObject::repaintRectangle(const LayoutRect& repaintRect, bool shouldClipToLayer) const
10491050
{
1051+
ASSERT(isDescendantOf(&view()) || is<RenderScrollbarPart>(this));
10501052
return repaintRectangle(repaintRect, shouldClipToLayer ? ClipRepaintToLayer::Yes : ClipRepaintToLayer::No, ForceRepaint::No);
10511053
}
10521054

10531055
void RenderObject::repaintRectangle(const LayoutRect& repaintRect, ClipRepaintToLayer shouldClipToLayer, ForceRepaint forceRepaint, std::optional<LayoutBoxExtent> additionalRepaintOutsets) const
10541056
{
1055-
// Don't repaint if we're unrooted (note that view() still returns the view when unrooted)
1056-
if (!isRooted() || view().printing())
1057+
ASSERT(isDescendantOf(&view()) || is<RenderScrollbarPart>(this) || is<RenderReplica>(this));
1058+
1059+
if (view().printing())
10571060
return;
10581061
// FIXME: layoutDelta needs to be applied in parts before/after transforms and
10591062
// repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308
@@ -1064,9 +1067,7 @@ void RenderObject::repaintRectangle(const LayoutRect& repaintRect, ClipRepaintTo
10641067

10651068
void RenderObject::repaintSlowRepaintObject() const
10661069
{
1067-
// Don't repaint if we're unrooted (note that view() still returns the view when unrooted)
1068-
if (!isRooted())
1069-
return;
1070+
ASSERT(isDescendantOf(&view()) || is<RenderScrollbarPart>(this) || is<RenderReplica>(this));
10701071

10711072
CheckedRef view = this->view();
10721073
if (view->printing())

Source/WebCore/rendering/RenderTableCol.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,8 @@ auto RenderTableCol::rectsForRepaintingAfterLayout(const RenderLayerModelObject*
155155
void RenderTableCol::imageChanged(WrappedImagePtr, const IntRect*)
156156
{
157157
// FIXME: Repaint only the rect the image paints in.
158+
if (!parent())
159+
return;
158160
repaint();
159161
}
160162

Source/WebCore/rendering/RenderTableRow.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,8 @@ void RenderTableRow::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
242242
void RenderTableRow::imageChanged(WrappedImagePtr, const IntRect*)
243243
{
244244
// FIXME: Examine cells and repaint only the rect the image paints in.
245+
if (!parent())
246+
return;
245247
repaint();
246248
}
247249

Source/WebCore/rendering/RenderTableSection.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1336,6 +1336,8 @@ void RenderTableSection::paintObject(PaintInfo& paintInfo, const LayoutPoint& pa
13361336
void RenderTableSection::imageChanged(WrappedImagePtr, const IntRect*)
13371337
{
13381338
// FIXME: Examine cells and repaint only the rect the image paints in.
1339+
if (!parent())
1340+
return;
13391341
repaint();
13401342
}
13411343

Source/WebCore/rendering/svg/RenderSVGImage.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ void RenderSVGImage::notifyFinished(CachedResource& newImage, const NetworkLoadM
345345

346346
void RenderSVGImage::imageChanged(WrappedImagePtr newImage, const IntRect* rect)
347347
{
348-
if (renderTreeBeingDestroyed())
348+
if (renderTreeBeingDestroyed() || !parent())
349349
return;
350350

351351
repaintClientsOfReferencedSVGResources();

Source/WebCore/rendering/svg/legacy/LegacyRenderSVGImage.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,8 @@ bool LegacyRenderSVGImage::nodeAtFloatPoint(const HitTestRequest& request, HitTe
254254

255255
void LegacyRenderSVGImage::imageChanged(WrappedImagePtr, const IntRect*)
256256
{
257+
if (!parent())
258+
return;
257259
// The image resource defaults to nullImage until the resource arrives.
258260
// This empty image may be cached by SVG resources which must be invalidated.
259261
if (auto* resources = SVGResourcesCache::cachedResourcesForRenderer(*this))

0 commit comments

Comments
 (0)