diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog index a9fefa71af69..5770980702a2 100644 --- a/Source/WebCore/ChangeLog +++ b/Source/WebCore/ChangeLog @@ -1,3 +1,41 @@ +2017-08-09 Dave Hyatt + + [Repaint from Layout Removal] Move layer repaint rects into a map + https://bugs.webkit.org/show_bug.cgi?id=175393 + + Reviewed by Zalan Bujtas. + + Move the two repaint rects held by RenderLayer into a RenderLayerModelObject -> RepaintLayoutRects hash map. + RepaintLayoutRects is a new struct that holds both rects. + + Eventually more objects than just self painting layers will be caching repaint rects, so this takes a first + step towards having a common cache for these repaint rects. In addition this change saves memory, since + layers that aren't self-painting no longer have empty repaint rects taking up space in RenderLayer. + + * rendering/RenderBlockLineLayout.cpp: + (WebCore::RenderBlockFlow::layoutRunsAndFloats): + * rendering/RenderLayer.cpp: + (WebCore::RenderLayer::RenderLayer): + (WebCore::RenderLayer::updateLayerPositions): + (WebCore::RenderLayer::repaintRectIncludingNonCompositingDescendants): + (WebCore::RenderLayer::computeRepaintRects): + (WebCore::RenderLayer::clearRepaintRects): + (WebCore::RenderLayer::updateLayerPositionsAfterScroll): + (WebCore::RenderLayer::scrollTo): + * rendering/RenderLayer.h: + * rendering/RenderLayerModelObject.cpp: + (WebCore::RepaintLayoutRects::RepaintLayoutRects): + (WebCore::RenderLayerModelObject::willBeDestroyed): + (WebCore::RenderLayerModelObject::destroyLayer): + (WebCore::RenderLayerModelObject::styleDidChange): + (WebCore::RenderLayerModelObject::hasRepaintLayoutRects): + (WebCore::RenderLayerModelObject::setRepaintLayoutRects): + (WebCore::RenderLayerModelObject::clearRepaintLayoutRects): + (WebCore::RenderLayerModelObject::repaintLayoutRects): + (WebCore::RenderLayerModelObject::computeRepaintLayoutRects): + * rendering/RenderLayerModelObject.h: + (WebCore::RepaintLayoutRects::RepaintLayoutRects): + 2017-08-09 Kirill Ovchinnikov Old subtitle track is not deleted on 'src' attribute change event diff --git a/Source/WebCore/rendering/RenderBlockLineLayout.cpp b/Source/WebCore/rendering/RenderBlockLineLayout.cpp index e2e35072a734..ac7cfbe05a34 100644 --- a/Source/WebCore/rendering/RenderBlockLineLayout.cpp +++ b/Source/WebCore/rendering/RenderBlockLineLayout.cpp @@ -1281,12 +1281,12 @@ void RenderBlockFlow::layoutRunsAndFloats(LineLayoutState& layoutState, bool has // determineStartPosition first will break fast/repaint/line-flow-with-floats-9.html. if (layoutState.isFullLayout() && hasInlineChild && !selfNeedsLayout()) { setNeedsLayout(MarkOnlyThis); // Mark as needing a full layout to force us to repaint. - if (!view().doingFullRepaint() && hasSelfPaintingLayer() && layer()->hasComputedRepaintRect()) { + if (!view().doingFullRepaint() && hasSelfPaintingLayer() && hasRepaintLayoutRects()) { // 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. - repaintUsingContainer(containerForRepaint(), layer()->repaintRect()); + repaintUsingContainer(containerForRepaint(), repaintLayoutRects().m_repaintRect); } } diff --git a/Source/WebCore/rendering/RenderLayer.cpp b/Source/WebCore/rendering/RenderLayer.cpp index 92ddde6b0f7e..1212c760dbca 100644 --- a/Source/WebCore/rendering/RenderLayer.cpp +++ b/Source/WebCore/rendering/RenderLayer.cpp @@ -310,7 +310,6 @@ RenderLayer::RenderLayer(RenderLayerModelObject& rendererLayerModelObject) , m_layerListMutationAllowed(true) #endif , m_hasFilterInfo(false) - , m_hasComputedRepaintRect(false) #if ENABLE(CSS_COMPOSITING) , m_blendMode(BlendModeNormal) , m_hasNotIsolatedCompositedBlendingDescendants(false) @@ -516,23 +515,29 @@ void RenderLayer::updateLayerPositions(RenderGeometryMap* geometryMap, UpdateLay ASSERT(!renderer().view().layoutStateEnabled()); RenderLayerModelObject* repaintContainer = renderer().containerForRepaint(); - LayoutRect oldRepaintRect = m_repaintRect; - LayoutRect oldOutlineBox = m_outlineBox; + + auto hadRepaintLayoutRects = renderer().hasRepaintLayoutRects(); + RepaintLayoutRects oldRects = hadRepaintLayoutRects ? renderer().repaintLayoutRects() : RepaintLayoutRects(); computeRepaintRects(repaintContainer, geometryMap); - + + auto hasRepaintLayoutRects = renderer().hasRepaintLayoutRects(); + RepaintLayoutRects newRects = hasRepaintLayoutRects ? renderer().repaintLayoutRects() : RepaintLayoutRects(); // 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) && m_hasComputedRepaintRect) { + if ((flags & CheckForRepaint) && hasRepaintLayoutRects) { if (!renderer().view().printing()) { bool didRepaint = false; if (m_repaintStatus & NeedsFullRepaint) { - renderer().repaintUsingContainer(repaintContainer, oldRepaintRect); - if (m_repaintRect != oldRepaintRect) { - renderer().repaintUsingContainer(repaintContainer, m_repaintRect); + if (hadRepaintLayoutRects) + renderer().repaintUsingContainer(repaintContainer, oldRects.m_repaintRect); + if (!hadRepaintLayoutRects || newRects.m_repaintRect != oldRects.m_repaintRect) { + renderer().repaintUsingContainer(repaintContainer, newRects.m_repaintRect); didRepaint = true; } } else if (shouldRepaintAfterLayout()) { - renderer().repaintAfterLayoutIfNeeded(repaintContainer, oldRepaintRect, oldOutlineBox, &m_repaintRect, &m_outlineBox); + // 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); didRepaint = true; } @@ -601,7 +606,7 @@ void RenderLayer::updateLayerPositions(RenderGeometryMap* geometryMap, UpdateLay LayoutRect RenderLayer::repaintRectIncludingNonCompositingDescendants() const { - LayoutRect repaintRect = m_repaintRect; + LayoutRect repaintRect = renderer().repaintLayoutRects().m_repaintRect; 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()) @@ -797,18 +802,9 @@ void RenderLayer::updateDescendantsAreContiguousInStackingOrderRecursive(const H void RenderLayer::computeRepaintRects(const RenderLayerModelObject* repaintContainer, const RenderGeometryMap* geometryMap) { ASSERT(!m_visibleContentStatusDirty); - - if (!isSelfPaintingLayer()) { - clearRepaintRects(); - return; - } - - m_hasComputedRepaintRect = true; - m_repaintRect = renderer().clippedOverflowRectForRepaint(repaintContainer); - m_outlineBox = renderer().outlineBoundsForRepaint(repaintContainer, geometryMap); + renderer().computeRepaintLayoutRects(repaintContainer, geometryMap); } - void RenderLayer::computeRepaintRectsIncludingDescendants() { // FIXME: computeRepaintRects() has to walk up the parent chain for every layer to compute the rects. @@ -824,9 +820,7 @@ void RenderLayer::clearRepaintRects() { ASSERT(!m_visibleContentStatusDirty); - m_hasComputedRepaintRect = false; - m_repaintRect = LayoutRect(); - m_outlineBox = LayoutRect(); + renderer().clearRepaintLayoutRects(); } void RenderLayer::updateLayerPositionsAfterDocumentScroll() @@ -889,8 +883,8 @@ void RenderLayer::updateLayerPositionsAfterScroll(RenderGeometryMap* geometryMap computeRepaintRects(renderer().containerForRepaint(), geometryMap); } else { // Check that our cached rects are correct. - ASSERT(!m_hasComputedRepaintRect || (m_repaintRect == renderer().clippedOverflowRectForRepaint(renderer().containerForRepaint()))); - ASSERT(!m_hasComputedRepaintRect || m_outlineBox == renderer().outlineBoundsForRepaint(renderer().containerForRepaint())); + ASSERT(!renderer().hasRepaintLayoutRects() || renderer().repaintLayoutRects().m_repaintRect == renderer().clippedOverflowRectForRepaint(renderer().containerForRepaint())); + ASSERT(!renderer().hasRepaintLayoutRects() || renderer().repaintLayoutRects().m_outlineBox == renderer().outlineBoundsForRepaint(renderer().containerForRepaint())); } for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) @@ -2440,7 +2434,7 @@ void RenderLayer::scrollTo(const ScrollPosition& position) // The caret rect needs to be invalidated after scrolling frame.selection().setCaretRectNeedsUpdate(); - LayoutRect rectForRepaint = m_hasComputedRepaintRect ? m_repaintRect : renderer().clippedOverflowRectForRepaint(repaintContainer); + LayoutRect rectForRepaint = renderer().hasRepaintLayoutRects() ? renderer().repaintLayoutRects().m_repaintRect : renderer().clippedOverflowRectForRepaint(repaintContainer); FloatQuad quadForFakeMouseMoveEvent = FloatQuad(rectForRepaint); if (repaintContainer) diff --git a/Source/WebCore/rendering/RenderLayer.h b/Source/WebCore/rendering/RenderLayer.h index 53b350cfc7cf..184199e306b1 100644 --- a/Source/WebCore/rendering/RenderLayer.h +++ b/Source/WebCore/rendering/RenderLayer.h @@ -581,8 +581,7 @@ class RenderLayer final : public ScrollableArea { LayoutRect calculateLayerBounds(const RenderLayer* ancestorLayer, const LayoutSize& offsetFromRoot, CalculateLayerBoundsFlags = DefaultCalculateLayerBoundsFlags) const; // Return a cached repaint rect, computed relative to the layer renderer's containerForRepaint. - bool hasComputedRepaintRect() const { return m_hasComputedRepaintRect; } - LayoutRect repaintRect() const { ASSERT(hasComputedRepaintRect()); return m_repaintRect; } + bool hasComputedRepaintRects() const { return renderer().hasRepaintLayoutRects(); } LayoutRect repaintRectIncludingNonCompositingDescendants() const; void setRepaintStatus(RepaintStatus status) { m_repaintStatus = status; } @@ -1115,8 +1114,6 @@ class RenderLayer final : public ScrollableArea { #endif bool m_hasFilterInfo : 1; - - bool m_hasComputedRepaintRect : 1; #if ENABLE(CSS_COMPOSITING) unsigned m_blendMode : 5; @@ -1133,9 +1130,6 @@ class RenderLayer final : public ScrollableArea { RenderLayer* m_first; RenderLayer* m_last; - LayoutRect m_repaintRect; // Cached repaint rects. Used by layout. - LayoutRect m_outlineBox; - // Our current relative position offset. LayoutSize m_offsetForInFlowPosition; diff --git a/Source/WebCore/rendering/RenderLayerModelObject.cpp b/Source/WebCore/rendering/RenderLayerModelObject.cpp index 343d14119783..45c052e30932 100644 --- a/Source/WebCore/rendering/RenderLayerModelObject.cpp +++ b/Source/WebCore/rendering/RenderLayerModelObject.cpp @@ -38,6 +38,15 @@ bool RenderLayerModelObject::s_hadLayer = false; bool RenderLayerModelObject::s_hadTransform = false; bool RenderLayerModelObject::s_layerWasSelfPainting = false; +typedef WTF::HashMap 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) { @@ -61,7 +70,9 @@ void RenderLayerModelObject::willBeDestroyed() } RenderElement::willBeDestroyed(); - + + clearRepaintLayoutRects(); + // Our layer should have been destroyed and cleared by now ASSERT(!hasLayer()); ASSERT(!m_layer); @@ -71,6 +82,8 @@ void RenderLayerModelObject::destroyLayer() { ASSERT(!hasLayer()); // Callers should have already called setHasLayer(false) ASSERT(m_layer); + if (m_layer->isSelfPaintingLayer()) + clearRepaintLayoutRects(); m_layer = nullptr; } @@ -166,8 +179,8 @@ void RenderLayerModelObject::styleDidChange(StyleDifference diff, const RenderSt setHasTransformRelatedProperty(false); // All transform-related propeties 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 && layer()->hasComputedRepaintRect()) - repaintUsingContainer(containerForRepaint(), layer()->repaintRect()); + if (layer()->isSelfPaintingLayer() && layer()->repaintStatus() == NeedsFullRepaint && hasRepaintLayoutRects()) + repaintUsingContainer(containerForRepaint(), repaintLayoutRects().m_repaintRect); layer()->removeOnlyThisLayer(); // calls destroyLayer() which clears m_layer if (s_wasFloating && isFloating()) setChildNeedsLayout(); @@ -235,5 +248,38 @@ bool RenderLayerModelObject::shouldPlaceBlockDirectionScrollbarOnLeft() const #endif } +bool RenderLayerModelObject::hasRepaintLayoutRects() const +{ + return gRepaintLayoutRectsMap && gRepaintLayoutRectsMap->contains(this); +} + +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)); +} + } // namespace WebCore diff --git a/Source/WebCore/rendering/RenderLayerModelObject.h b/Source/WebCore/rendering/RenderLayerModelObject.h index 590aa442ea8d..c1d672361c6f 100644 --- a/Source/WebCore/rendering/RenderLayerModelObject.h +++ b/Source/WebCore/rendering/RenderLayerModelObject.h @@ -28,6 +28,14 @@ namespace WebCore { 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() { }; +}; + class RenderLayerModelObject : public RenderElement { public: virtual ~RenderLayerModelObject(); @@ -51,6 +59,14 @@ class RenderLayerModelObject : public RenderElement { 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(); protected: RenderLayerModelObject(Element&, RenderStyle&&, BaseTypeFlags);