Diff
Modified: trunk/Source/WebCore/ChangeLog (275640 => 275641)
--- trunk/Source/WebCore/ChangeLog 2021-04-07 22:55:54 UTC (rev 275640)
+++ trunk/Source/WebCore/ChangeLog 2021-04-07 23:06:56 UTC (rev 275641)
@@ -1,5 +1,54 @@
2021-04-07 Simon Fraser <[email protected]>
+ Remove RepaintLayoutRectsMap
+ https://bugs.webkit.org/show_bug.cgi?id=224217
+
+ Reviewed by Zalan Bujtas.
+
+ RepaintLayoutRectsMap was a side table used to map RenderLayerModelObjects to
+ repaint rects for their corresponding layers. However, this HashMap could
+ get large, and waste more space than if we just stored the repaint rects
+ on RenderLayer.
+
+ For example, on twitter.com we could have about 2000 RenderLayers; increasing
+ their size by 32 bytes (the size of the two LayoutRects) adds 62KB, but RepaintLayoutRectsMap
+ would contain about 1950 entries with a capacity of 8192, wasting around 200KB.
+
+ So moving repaint rects into RenderLayer is a memory saving. This patch does so
+ without using Optional<> since that introduces extra padding.
+
+ * rendering/ComplexLineLayout.cpp:
+ (WebCore::ComplexLineLayout::layoutRunsAndFloats):
+ * rendering/RenderLayer.cpp:
+ (WebCore::RenderLayer::RenderLayer):
+ (WebCore::RenderLayer::updateLayerPositions):
+ (WebCore::RenderLayer::repaintRectIncludingNonCompositingDescendants const):
+ (WebCore::RenderLayer::computeRepaintRects):
+ (WebCore::RenderLayer::setRepaintRects):
+ (WebCore::RenderLayer::clearRepaintRects):
+ (WebCore::RenderLayer::updateLayerPositionsAfterScroll):
+ (WebCore::RenderLayer::calculateClipRects const):
+ * rendering/RenderLayer.h:
+ (WebCore::RenderLayer::repaintRects const):
+ (WebCore::RenderLayer::hasComputedRepaintRects const): Deleted.
+ * rendering/RenderLayerModelObject.cpp:
+ (WebCore::RenderLayerModelObject::willBeDestroyed):
+ (WebCore::RenderLayerModelObject::destroyLayer):
+ (WebCore::RenderLayerModelObject::styleDidChange):
+ (WebCore::RenderLayerModelObject::layerRepaintRects const):
+ (WebCore::RepaintLayoutRects::RepaintLayoutRects): Deleted.
+ (WebCore::RenderLayerModelObject::hasRepaintLayoutRects const): Deleted.
+ (WebCore::RenderLayerModelObject::setRepaintLayoutRects): Deleted.
+ (WebCore::RenderLayerModelObject::clearRepaintLayoutRects): Deleted.
+ (WebCore::RenderLayerModelObject::repaintLayoutRects const): Deleted.
+ (WebCore::RenderLayerModelObject::computeRepaintLayoutRects): Deleted.
+ * rendering/RenderLayerModelObject.h:
+ (WebCore::RepaintLayoutRects::RepaintLayoutRects): Deleted.
+ * rendering/RenderLayerScrollableArea.cpp:
+ (WebCore::RenderLayerScrollableArea::scrollTo):
+
+2021-04-07 Simon Fraser <[email protected]>
+
Wasted vector capacity in various DisplayList related code paths
https://bugs.webkit.org/show_bug.cgi?id=224304
Modified: trunk/Source/WebCore/rendering/ComplexLineLayout.cpp (275640 => 275641)
--- trunk/Source/WebCore/rendering/ComplexLineLayout.cpp 2021-04-07 22:55:54 UTC (rev 275640)
+++ trunk/Source/WebCore/rendering/ComplexLineLayout.cpp 2021-04-07 23:06:56 UTC (rev 275641)
@@ -1325,12 +1325,12 @@
// determineStartPosition first will break fast/repaint/line-flow-with-floats-9.html.
if (layoutState.isFullLayout() && hasInlineChild && !m_flow.selfNeedsLayout()) {
m_flow.setNeedsLayout(MarkOnlyThis); // Mark as needing a full layout to force us to repaint.
- if (!layoutContext().needsFullRepaint() && m_flow.hasSelfPaintingLayer() && m_flow.hasRepaintLayoutRects()) {
+ if (!layoutContext().needsFullRepaint() && m_flow.layerRepaintRects()) {
// Because we waited until we were already inside layout to discover
// 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.repaintLayoutRects().m_repaintRect);
+ m_flow.repaintUsingContainer(m_flow.containerForRepaint(), m_flow.layerRepaintRects()->clippedOverflowRect);
}
}
Modified: trunk/Source/WebCore/rendering/RenderLayer.cpp (275640 => 275641)
--- trunk/Source/WebCore/rendering/RenderLayer.cpp 2021-04-07 22:55:54 UTC (rev 275640)
+++ trunk/Source/WebCore/rendering/RenderLayer.cpp 2021-04-07 23:06:56 UTC (rev 275641)
@@ -333,6 +333,7 @@
, m_hasNotIsolatedBlendingDescendants(false)
, m_hasNotIsolatedBlendingDescendantsStatusDirty(false)
#endif
+ , m_repaintRectsValid(false)
, m_renderer(rendererLayerModelObject)
{
setIsNormalFlowOnly(shouldBeNormalFlowOnly());
@@ -945,25 +946,28 @@
RenderLayerModelObject* repaintContainer = renderer().containerForRepaint();
- auto hadRepaintLayoutRects = renderer().hasRepaintLayoutRects();
- RepaintLayoutRects oldRects = hadRepaintLayoutRects ? renderer().repaintLayoutRects() : RepaintLayoutRects();
+ auto oldRects = repaintRects();
computeRepaintRects(repaintContainer, geometryMap);
- auto hasRepaintLayoutRects = renderer().hasRepaintLayoutRects();
- RepaintLayoutRects newRects = hasRepaintLayoutRects ? renderer().repaintLayoutRects() : RepaintLayoutRects();
+ auto newRects = repaintRects();
+
// FIXME: Should ASSERT that value calculated for m_outlineBox using the cached offset is the same
// as the value not using the cached offset, but we can't due to https://bugs.webkit.org/show_bug.cgi?id=37048
- if ((flags & CheckForRepaint) && hasRepaintLayoutRects) {
+ if ((flags & CheckForRepaint) && newRects) {
if (!renderer().view().printing()) {
if (m_repaintStatus & NeedsFullRepaint) {
- if (hadRepaintLayoutRects)
- renderer().repaintUsingContainer(repaintContainer, oldRects.m_repaintRect);
- if (!hadRepaintLayoutRects || newRects.m_repaintRect != oldRects.m_repaintRect)
- renderer().repaintUsingContainer(repaintContainer, newRects.m_repaintRect);
+ if (oldRects)
+ renderer().repaintUsingContainer(repaintContainer, oldRects->clippedOverflowRect);
+
+ if (!oldRects || newRects->clippedOverflowRect != oldRects->clippedOverflowRect)
+ renderer().repaintUsingContainer(repaintContainer, newRects->clippedOverflowRect);
+
} else if (shouldRepaintAfterLayout()) {
// FIXME: We will convert this to just take the old and new RepaintLayoutRects once
// we change other callers to use RepaintLayoutRects.
- renderer().repaintAfterLayoutIfNeeded(repaintContainer, oldRects.m_repaintRect, oldRects.m_outlineBox, &newRects.m_repaintRect, &newRects.m_outlineBox);
+ auto resolvedOldRects = oldRects.valueOr(LayerRepaintRects { });
+ renderer().repaintAfterLayoutIfNeeded(repaintContainer, resolvedOldRects.clippedOverflowRect, resolvedOldRects.outlineBoundsRect,
+ &newRects->clippedOverflowRect, &newRects->outlineBoundsRect);
}
}
}
@@ -1025,7 +1029,9 @@
LayoutRect RenderLayer::repaintRectIncludingNonCompositingDescendants() const
{
- LayoutRect repaintRect = renderer().repaintLayoutRects().m_repaintRect;
+ LayoutRect repaintRect;
+ if (m_repaintRectsValid)
+ repaintRect = m_repaintRects.clippedOverflowRect;
for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
// Don't include repaint rects for composited child layers; they will paint themselves and have a different origin.
if (child->isComposited())
@@ -1063,7 +1069,15 @@
void RenderLayer::computeRepaintRects(const RenderLayerModelObject* repaintContainer, const RenderGeometryMap* geometryMap)
{
ASSERT(!m_visibleContentStatusDirty);
- renderer().computeRepaintLayoutRects(repaintContainer, geometryMap);
+
+ if (!isSelfPaintingLayer())
+ clearRepaintRects();
+ else {
+ setRepaintRects({
+ renderer().clippedOverflowRectForRepaint(repaintContainer),
+ renderer().outlineBoundsForRepaint(repaintContainer, geometryMap)
+ });
+ }
}
void RenderLayer::computeRepaintRectsIncludingDescendants()
@@ -1077,11 +1091,16 @@
layer->computeRepaintRectsIncludingDescendants();
}
+void RenderLayer::setRepaintRects(const LayerRepaintRects& rects)
+{
+ m_repaintRects = rects;
+ m_repaintRectsValid = true;
+}
+
void RenderLayer::clearRepaintRects()
{
ASSERT(!m_visibleContentStatusDirty);
-
- renderer().clearRepaintLayoutRects();
+ m_repaintRectsValid = false;
}
void RenderLayer::updateLayerPositionsAfterScroll(RenderGeometryMap* geometryMap, OptionSet<UpdateLayerPositionsAfterScrollFlag> flags)
@@ -1125,8 +1144,8 @@
// 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(!renderer().hasRepaintLayoutRects() || renderer().repaintLayoutRects().m_repaintRect == renderer().clippedOverflowRectForRepaint(renderer().containerForRepaint()));
- ASSERT(!renderer().hasRepaintLayoutRects() || renderer().repaintLayoutRects().m_outlineBox == renderer().outlineBoundsForRepaint(renderer().containerForRepaint()));
+ ASSERT_IMPLIES(m_repaintRectsValid, m_repaintRects.clippedOverflowRect == renderer().clippedOverflowRectForRepaint(renderer().containerForRepaint()));
+ ASSERT_IMPLIES(m_repaintRectsValid, m_repaintRects.outlineBoundsRect == renderer().outlineBoundsForRepaint(renderer().containerForRepaint()));
}
for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
@@ -5140,10 +5159,13 @@
m_isSelfPaintingLayer = isSelfPaintingLayer;
if (!parent())
return;
+
if (isSelfPaintingLayer)
parent()->setAncestorChainHasSelfPaintingLayerDescendant();
- else
+ else {
parent()->dirtyAncestorChainHasSelfPaintingLayerDescendantStatus();
+ clearRepaintRects();
+ }
}
static bool hasVisibleBoxDecorationsOrBackground(const RenderElement& renderer)
Modified: trunk/Source/WebCore/rendering/RenderLayer.h (275640 => 275641)
--- trunk/Source/WebCore/rendering/RenderLayer.h 2021-04-07 22:55:54 UTC (rev 275640)
+++ trunk/Source/WebCore/rendering/RenderLayer.h 2021-04-07 23:06:56 UTC (rev 275641)
@@ -216,6 +216,14 @@
RenderLayer* paintOrderParent() const;
+ Optional<LayerRepaintRects> repaintRects() const
+ {
+ if (m_repaintRectsValid)
+ return m_repaintRects;
+
+ return { };
+ }
+
void dirtyNormalFlowList();
void dirtyZOrderLists();
void dirtyStackingContextZOrderLists();
@@ -699,8 +707,6 @@
// Can pass offsetFromRoot if known.
LayoutRect calculateLayerBounds(const RenderLayer* ancestorLayer, const LayoutSize& offsetFromRoot, OptionSet<CalculateLayerBoundsFlag> = defaultCalculateLayerBoundsFlags()) const;
- // Return a cached repaint rect, computed relative to the layer renderer's containerForRepaint.
- bool hasComputedRepaintRects() const { return renderer().hasRepaintLayoutRects(); }
LayoutRect repaintRectIncludingNonCompositingDescendants() const;
void setRepaintStatus(RepaintStatus status) { m_repaintStatus = status; }
@@ -910,6 +916,8 @@
void computeRepaintRects(const RenderLayerModelObject* repaintContainer, const RenderGeometryMap* = nullptr);
void computeRepaintRectsIncludingDescendants();
+
+ void setRepaintRects(const LayerRepaintRects&);
void clearRepaintRects();
LayoutRect clipRectRelativeToAncestor(RenderLayer* ancestor, LayoutSize offsetFromAncestor, const LayoutRect& constrainingRect) const;
@@ -1136,6 +1144,7 @@
bool m_hasNotIsolatedBlendingDescendants : 1;
bool m_hasNotIsolatedBlendingDescendantsStatusDirty : 1;
#endif
+ bool m_repaintRectsValid : 1;
RenderLayerModelObject& m_renderer;
@@ -1157,6 +1166,9 @@
// This list contains child layers that cannot create stacking contexts and appear in normal flow order.
std::unique_ptr<Vector<RenderLayer*>> m_normalFlowList;
+ // Only valid if m_repaintRectsValid is set (Optional<> not used to avoid padding).
+ LayerRepaintRects m_repaintRects;
+
// Our current relative position offset.
LayoutSize m_offsetForInFlowPosition;
@@ -1188,7 +1200,7 @@
std::unique_ptr<RenderLayerFilters> m_filters;
std::unique_ptr<RenderLayerBacking> m_backing;
std::unique_ptr<RenderLayerScrollableArea> m_scrollableArea;
-
+
PaintFrequencyTracker m_paintFrequencyTracker;
};
Modified: trunk/Source/WebCore/rendering/RenderLayerModelObject.cpp (275640 => 275641)
--- trunk/Source/WebCore/rendering/RenderLayerModelObject.cpp 2021-04-07 22:55:54 UTC (rev 275640)
+++ trunk/Source/WebCore/rendering/RenderLayerModelObject.cpp 2021-04-07 23:06:56 UTC (rev 275641)
@@ -43,15 +43,6 @@
bool RenderLayerModelObject::s_hadTransform = false;
bool RenderLayerModelObject::s_layerWasSelfPainting = false;
-typedef WTF::HashMap<const RenderLayerModelObject*, RepaintLayoutRects> RepaintLayoutRectsMap;
-static RepaintLayoutRectsMap* gRepaintLayoutRectsMap = nullptr;
-
-RepaintLayoutRects::RepaintLayoutRects(const RenderLayerModelObject& renderer, const RenderLayerModelObject* repaintContainer, const RenderGeometryMap* geometryMap)
- : m_repaintRect(renderer.clippedOverflowRectForRepaint(repaintContainer))
- , m_outlineBox(renderer.outlineBoundsForRepaint(repaintContainer, geometryMap))
-{
-}
-
RenderLayerModelObject::RenderLayerModelObject(Element& element, RenderStyle&& style, BaseTypeFlags baseTypeFlags)
: RenderElement(element, WTFMove(style), baseTypeFlags | RenderLayerModelObjectFlag)
{
@@ -80,8 +71,6 @@
}
RenderElement::willBeDestroyed();
-
- clearRepaintLayoutRects();
}
void RenderLayerModelObject::destroyLayer()
@@ -88,8 +77,6 @@
{
ASSERT(!hasLayer());
ASSERT(m_layer);
- if (m_layer->isSelfPaintingLayer())
- clearRepaintLayoutRects();
m_layer = nullptr;
}
@@ -147,9 +134,10 @@
#endif
setHasTransformRelatedProperty(false); // All transform-related properties force layers, so we know we don't have one or the object doesn't support them.
setHasReflection(false);
+
// Repaint the about to be destroyed self-painting layer when style change also triggers repaint.
- if (layer()->isSelfPaintingLayer() && layer()->repaintStatus() == NeedsFullRepaint && hasRepaintLayoutRects())
- repaintUsingContainer(containerForRepaint(), repaintLayoutRects().m_repaintRect);
+ if (layer()->isSelfPaintingLayer() && layer()->repaintStatus() == NeedsFullRepaint && layer()->repaintRects())
+ repaintUsingContainer(containerForRepaint(), layer()->repaintRects()->clippedOverflowRect);
layer()->removeOnlyThisLayer(RenderLayer::LayerChangeTiming::StyleChange); // calls destroyLayer() which clears m_layer
if (s_wasFloating && isFloating())
@@ -236,39 +224,11 @@
#endif
}
-bool RenderLayerModelObject::hasRepaintLayoutRects() const
+Optional<LayerRepaintRects> RenderLayerModelObject::layerRepaintRects() const
{
- return gRepaintLayoutRectsMap && gRepaintLayoutRectsMap->contains(this);
+ return hasLayer() ? layer()->repaintRects() : WTF::nullopt;
}
-void RenderLayerModelObject::setRepaintLayoutRects(const RepaintLayoutRects& rects)
-{
- if (!gRepaintLayoutRectsMap)
- gRepaintLayoutRectsMap = new RepaintLayoutRectsMap();
- gRepaintLayoutRectsMap->set(this, rects);
-}
-
-void RenderLayerModelObject::clearRepaintLayoutRects()
-{
- if (gRepaintLayoutRectsMap)
- gRepaintLayoutRectsMap->remove(this);
-}
-
-RepaintLayoutRects RenderLayerModelObject::repaintLayoutRects() const
-{
- if (!hasRepaintLayoutRects())
- return RepaintLayoutRects();
- return gRepaintLayoutRectsMap->get(this);
-}
-
-void RenderLayerModelObject::computeRepaintLayoutRects(const RenderLayerModelObject* repaintContainer, const RenderGeometryMap* geometryMap)
-{
- if (!m_layer || !m_layer->isSelfPaintingLayer())
- clearRepaintLayoutRects();
- else
- setRepaintLayoutRects(RepaintLayoutRects(*this, repaintContainer, geometryMap));
-}
-
bool RenderLayerModelObject::startAnimation(double timeOffset, const Animation& animation, const KeyframeList& keyframes)
{
if (!layer() || !layer()->backing())
Modified: trunk/Source/WebCore/rendering/RenderLayerModelObject.h (275640 => 275641)
--- trunk/Source/WebCore/rendering/RenderLayerModelObject.h 2021-04-07 22:55:54 UTC (rev 275640)
+++ trunk/Source/WebCore/rendering/RenderLayerModelObject.h 2021-04-07 23:06:56 UTC (rev 275641)
@@ -29,12 +29,9 @@
class KeyframeList;
class RenderLayer;
-struct RepaintLayoutRects {
- LayoutRect m_repaintRect; // This rect is clipped by enclosing objects (e.g., overflow:hidden).
- LayoutRect m_outlineBox; // This rect is unclipped.
-
- RepaintLayoutRects(const RenderLayerModelObject& renderer, const RenderLayerModelObject* repaintContainer, const RenderGeometryMap* = nullptr);
- RepaintLayoutRects() { };
+struct LayerRepaintRects {
+ LayoutRect clippedOverflowRect;
+ LayoutRect outlineBoundsRect;
};
class RenderLayerModelObject : public RenderElement {
@@ -60,14 +57,8 @@
virtual bool isScrollableOrRubberbandableBox() const { return false; }
bool shouldPlaceBlockDirectionScrollbarOnLeft() const;
-
- void computeRepaintLayoutRects(const RenderLayerModelObject* repaintContainer, const RenderGeometryMap* = nullptr);
- RepaintLayoutRects repaintLayoutRects() const;
-
- bool hasRepaintLayoutRects() const;
- void setRepaintLayoutRects(const RepaintLayoutRects&);
- void clearRepaintLayoutRects();
+ Optional<LayerRepaintRects> layerRepaintRects() const;
bool startAnimation(double timeOffset, const Animation&, const KeyframeList&) override;
void animationPaused(double timeOffset, const String& name) override;
Modified: trunk/Source/WebCore/rendering/RenderLayerScrollableArea.cpp (275640 => 275641)
--- trunk/Source/WebCore/rendering/RenderLayerScrollableArea.cpp 2021-04-07 22:55:54 UTC (rev 275640)
+++ trunk/Source/WebCore/rendering/RenderLayerScrollableArea.cpp 2021-04-07 23:06:56 UTC (rev 275641)
@@ -359,7 +359,7 @@
// The caret rect needs to be invalidated after scrolling
frame.selection().setCaretRectNeedsUpdate();
- LayoutRect rectForRepaint = renderer.hasRepaintLayoutRects() ? renderer.repaintLayoutRects().m_repaintRect : renderer.clippedOverflowRectForRepaint(repaintContainer);
+ LayoutRect rectForRepaint = layer().repaintRects() ? layer().repaintRects()->clippedOverflowRect : renderer.clippedOverflowRectForRepaint(repaintContainer);
FloatQuad quadForFakeMouseMoveEvent = FloatQuad(rectForRepaint);
if (repaintContainer)