Commit f64411a3 authored by vollick@chromium.org's avatar vollick@chromium.org

Avoid tree walks when computing RenderLayer::scrollParent

This CL uses some memoization to avoid unnecessary tree walking when
computing scroll parent. Why memoization and not just passing down the
values? Because sad. It turns out that we recur on the stacking tree (we
have to - squashing demands processing stuff in paint order), but we
walk up the render tree asking questions. Different tree topologies; we
could very easily visit a RenderLayer before its great great
grandparent.

No functionality change -- covered by existing tests.
BUG=None

Review URL: https://codereview.chromium.org/206283003

git-svn-id: svn://svn.chromium.org/blink/trunk@169741 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 42ab21df
...@@ -1141,23 +1141,49 @@ RenderLayer* RenderLayer::enclosingCompositingLayerForRepaint(IncludeSelfOrNot i ...@@ -1141,23 +1141,49 @@ RenderLayer* RenderLayer::enclosingCompositingLayerForRepaint(IncludeSelfOrNot i
return 0; return 0;
} }
RenderLayer* RenderLayer::ancestorCompositedScrollingLayer() const void RenderLayer::clearAncestorDependentPropertyCache()
{ {
ASSERT(isAllowedToQueryCompositingState()); ASSERT(isInCompositingUpdate());
m_ancestorDependentPropertyCache.clear();
}
void RenderLayer::ensureAncestorDependentPropertyCache() const
{
ASSERT(isInCompositingUpdate());
if (m_ancestorDependentPropertyCache)
return;
m_ancestorDependentPropertyCache = adoptPtr(new AncestorDependentPropertyCache());
}
RenderLayer* RenderLayer::ancestorCompositedScrollingLayer() const
{
if (!renderer()->acceleratedCompositingForOverflowScrollEnabled()) if (!renderer()->acceleratedCompositingForOverflowScrollEnabled())
return 0; return 0;
ASSERT(isInCompositingUpdate() || !m_ancestorDependentPropertyCache);
if (m_ancestorDependentPropertyCache && !m_ancestorDependentPropertyCache->ancestorCompositedScrollingLayerDirty())
return m_ancestorDependentPropertyCache->ancestorCompositedScrollingLayer();
RenderObject* containingBlock = renderer()->containingBlock(); RenderObject* containingBlock = renderer()->containingBlock();
if (!containingBlock) if (!containingBlock)
return 0; return 0;
if (isInCompositingUpdate())
ensureAncestorDependentPropertyCache();
RenderLayer* ancestorCompositedScrollingLayer = 0;
for (RenderLayer* ancestorLayer = containingBlock->enclosingLayer(); ancestorLayer; ancestorLayer = ancestorLayer->parent()) { for (RenderLayer* ancestorLayer = containingBlock->enclosingLayer(); ancestorLayer; ancestorLayer = ancestorLayer->parent()) {
if (ancestorLayer->needsCompositedScrolling()) if (ancestorLayer->needsCompositedScrolling()) {
return ancestorLayer; ancestorCompositedScrollingLayer = ancestorLayer;
break;
}
} }
return 0; if (m_ancestorDependentPropertyCache)
m_ancestorDependentPropertyCache->setAncestorCompositedScrollingLayer(ancestorCompositedScrollingLayer);
return ancestorCompositedScrollingLayer;
} }
RenderLayer* RenderLayer::ancestorScrollingLayer() const RenderLayer* RenderLayer::ancestorScrollingLayer() const
...@@ -1689,6 +1715,10 @@ RenderLayer* RenderLayer::scrollParent() const ...@@ -1689,6 +1715,10 @@ RenderLayer* RenderLayer::scrollParent() const
if (stackingNode()->isNormalFlowOnly()) if (stackingNode()->isNormalFlowOnly())
return 0; return 0;
// We should never have an ancestor dependent property cache outside of the
// compositing update phase.
ASSERT(isInCompositingUpdate() || !m_ancestorDependentPropertyCache);
// A layer scrolls with its containing block. So to find the overflow scrolling layer // A layer scrolls with its containing block. So to find the overflow scrolling layer
// that we scroll with respect to, we must ascend the layer tree until we reach the // that we scroll with respect to, we must ascend the layer tree until we reach the
// first overflow scrolling div at or above our containing block. I will refer to this // first overflow scrolling div at or above our containing block. I will refer to this
...@@ -1701,8 +1731,10 @@ RenderLayer* RenderLayer::scrollParent() const ...@@ -1701,8 +1731,10 @@ RenderLayer* RenderLayer::scrollParent() const
// our scrolling ancestor, and we will therefore not scroll with it. In this case, we must // our scrolling ancestor, and we will therefore not scroll with it. In this case, we must
// be a composited layer since the compositor will need to take special measures to ensure // be a composited layer since the compositor will need to take special measures to ensure
// that we scroll with our scrolling ancestor and it cannot do this if we do not promote. // that we scroll with our scrolling ancestor and it cannot do this if we do not promote.
RenderLayer* scrollParent = ancestorCompositedScrollingLayer(); if (m_ancestorDependentPropertyCache && !m_ancestorDependentPropertyCache->scrollParentDirty())
return m_ancestorDependentPropertyCache->scrollParent();
RenderLayer* scrollParent = ancestorCompositedScrollingLayer();
if (!scrollParent || scrollParent->stackingNode()->isStackingContainer()) if (!scrollParent || scrollParent->stackingNode()->isStackingContainer())
return 0; return 0;
...@@ -1711,8 +1743,18 @@ RenderLayer* RenderLayer::scrollParent() const ...@@ -1711,8 +1743,18 @@ RenderLayer* RenderLayer::scrollParent() const
for (RenderLayer* ancestor = parent(); ancestor && ancestor != scrollParent; ancestor = ancestor->parent()) { for (RenderLayer* ancestor = parent(); ancestor && ancestor != scrollParent; ancestor = ancestor->parent()) {
if (ancestor->stackingNode()->isStackingContainer()) if (ancestor->stackingNode()->isStackingContainer())
return 0; return 0;
if (!isInCompositingUpdate())
continue;
if (AncestorDependentPropertyCache* ancestorCache = ancestor->m_ancestorDependentPropertyCache.get()) {
if (!ancestorCache->ancestorCompositedScrollingLayerDirty() && ancestorCache->ancestorCompositedScrollingLayer() == scrollParent) {
scrollParent = ancestorCache->scrollParent();
break;
}
}
} }
if (m_ancestorDependentPropertyCache)
m_ancestorDependentPropertyCache->setScrollParent(scrollParent);
return scrollParent; return scrollParent;
} }
...@@ -3527,6 +3569,11 @@ bool RenderLayer::isAllowedToQueryCompositingState() const ...@@ -3527,6 +3569,11 @@ bool RenderLayer::isAllowedToQueryCompositingState() const
return renderer()->document().lifecycle().state() >= DocumentLifecycle::InCompositingUpdate; return renderer()->document().lifecycle().state() >= DocumentLifecycle::InCompositingUpdate;
} }
bool RenderLayer::isInCompositingUpdate() const
{
return renderer()->document().lifecycle().state() == DocumentLifecycle::InCompositingUpdate;
}
CompositedLayerMappingPtr RenderLayer::compositedLayerMapping() const CompositedLayerMappingPtr RenderLayer::compositedLayerMapping() const
{ {
ASSERT(isAllowedToQueryCompositingState()); ASSERT(isAllowedToQueryCompositingState());
...@@ -4065,6 +4112,36 @@ DisableCompositingQueryAsserts::DisableCompositingQueryAsserts() ...@@ -4065,6 +4112,36 @@ DisableCompositingQueryAsserts::DisableCompositingQueryAsserts()
COMPILE_ASSERT(1 << RenderLayer::ViewportConstrainedNotCompositedReasonBits >= RenderLayer::NumNotCompositedReasons, too_many_viewport_constrained_not_compositing_reasons); COMPILE_ASSERT(1 << RenderLayer::ViewportConstrainedNotCompositedReasonBits >= RenderLayer::NumNotCompositedReasons, too_many_viewport_constrained_not_compositing_reasons);
RenderLayer::AncestorDependentPropertyCache::AncestorDependentPropertyCache()
: m_ancestorCompositedScrollingLayer(0)
, m_scrollParent(0)
, m_ancestorCompositedScrollingLayerDirty(true)
, m_scrollParentDirty(true) { }
RenderLayer* RenderLayer::AncestorDependentPropertyCache::scrollParent() const
{
ASSERT(!m_scrollParentDirty);
return m_scrollParent;
}
void RenderLayer::AncestorDependentPropertyCache::setScrollParent(RenderLayer* scrollParent)
{
m_scrollParent = scrollParent;
m_scrollParentDirty = false;
}
RenderLayer* RenderLayer::AncestorDependentPropertyCache::ancestorCompositedScrollingLayer() const
{
ASSERT(!m_ancestorCompositedScrollingLayerDirty);
return m_ancestorCompositedScrollingLayer;
}
void RenderLayer::AncestorDependentPropertyCache::setAncestorCompositedScrollingLayer(RenderLayer* layer)
{
m_ancestorCompositedScrollingLayer = layer;
m_ancestorCompositedScrollingLayerDirty = false;
}
} // namespace WebCore } // namespace WebCore
#ifndef NDEBUG #ifndef NDEBUG
......
...@@ -358,6 +358,9 @@ public: ...@@ -358,6 +358,9 @@ public:
// compositing state may legally be read. // compositing state may legally be read.
bool isAllowedToQueryCompositingState() const; bool isAllowedToQueryCompositingState() const;
// This returns true if our current phase is the compositing update.
bool isInCompositingUpdate() const;
CompositedLayerMappingPtr compositedLayerMapping() const; CompositedLayerMappingPtr compositedLayerMapping() const;
CompositedLayerMappingPtr ensureCompositedLayerMapping(); CompositedLayerMappingPtr ensureCompositedLayerMapping();
...@@ -479,7 +482,33 @@ public: ...@@ -479,7 +482,33 @@ public:
bool hasDirectReasonsForCompositing() const { return compositingReasons() & CompositingReasonComboAllDirectReasons; } bool hasDirectReasonsForCompositing() const { return compositingReasons() & CompositingReasonComboAllDirectReasons; }
void clearAncestorDependentPropertyCache();
private: private:
class AncestorDependentPropertyCache {
WTF_MAKE_NONCOPYABLE(AncestorDependentPropertyCache);
public:
AncestorDependentPropertyCache();
RenderLayer* ancestorCompositedScrollingLayer() const;
void setAncestorCompositedScrollingLayer(RenderLayer*);
RenderLayer* scrollParent() const;
void setScrollParent(RenderLayer*);
bool ancestorCompositedScrollingLayerDirty() const { return m_ancestorCompositedScrollingLayerDirty; }
bool scrollParentDirty() const { return m_scrollParentDirty; }
private:
RenderLayer* m_ancestorCompositedScrollingLayer;
RenderLayer* m_scrollParent;
bool m_ancestorCompositedScrollingLayerDirty;
bool m_scrollParentDirty;
};
void ensureAncestorDependentPropertyCache() const;
bool hasOverflowControls() const; bool hasOverflowControls() const;
void setIsUnclippedDescendant(bool isUnclippedDescendant) { m_isUnclippedDescendant = isUnclippedDescendant; } void setIsUnclippedDescendant(bool isUnclippedDescendant) { m_isUnclippedDescendant = isUnclippedDescendant; }
...@@ -578,7 +607,6 @@ private: ...@@ -578,7 +607,6 @@ private:
bool shouldBeSelfPaintingLayer() const; bool shouldBeSelfPaintingLayer() const;
private:
// FIXME: We should only create the stacking node if needed. // FIXME: We should only create the stacking node if needed.
bool requiresStackingNode() const { return true; } bool requiresStackingNode() const { return true; }
void updateStackingNode(); void updateStackingNode();
...@@ -630,7 +658,6 @@ private: ...@@ -630,7 +658,6 @@ private:
friend class RenderLayerCompositor; friend class RenderLayerCompositor;
friend class RenderLayerModelObject; friend class RenderLayerModelObject;
private:
LayerType m_layerType; LayerType m_layerType;
// Self-painting layer is an optimization where we avoid the heavy RenderLayer painting // Self-painting layer is an optimization where we avoid the heavy RenderLayer painting
...@@ -756,6 +783,8 @@ private: ...@@ -756,6 +783,8 @@ private:
OwnPtr<CompositedLayerMapping> m_compositedLayerMapping; OwnPtr<CompositedLayerMapping> m_compositedLayerMapping;
OwnPtr<RenderLayerScrollableArea> m_scrollableArea; OwnPtr<RenderLayerScrollableArea> m_scrollableArea;
mutable OwnPtr<AncestorDependentPropertyCache> m_ancestorDependentPropertyCache;
CompositedLayerMapping* m_groupedMapping; CompositedLayerMapping* m_groupedMapping;
RenderLayerRepainter m_repainter; RenderLayerRepainter m_repainter;
......
...@@ -389,6 +389,14 @@ void RenderLayerCompositor::setNeedsCompositingUpdate(CompositingUpdateType upda ...@@ -389,6 +389,14 @@ void RenderLayerCompositor::setNeedsCompositingUpdate(CompositingUpdateType upda
page()->animator().scheduleVisualUpdate(); page()->animator().scheduleVisualUpdate();
} }
static void clearAncestorDependentPropertyCacheRecursive(RenderLayer* layer)
{
layer->clearAncestorDependentPropertyCache();
RenderLayerStackingNodeIterator iterator(*layer->stackingNode(), AllChildren);
for (RenderLayer* child = layer->firstChild(); child; child = child->nextSibling())
clearAncestorDependentPropertyCacheRecursive(child);
}
void RenderLayerCompositor::updateCompositingLayers() void RenderLayerCompositor::updateCompositingLayers()
{ {
TRACE_EVENT0("blink_rendering", "RenderLayerCompositor::updateCompositingLayers"); TRACE_EVENT0("blink_rendering", "RenderLayerCompositor::updateCompositingLayers");
...@@ -406,6 +414,9 @@ void RenderLayerCompositor::updateCompositingLayers() ...@@ -406,6 +414,9 @@ void RenderLayerCompositor::updateCompositingLayers()
updateCompositingLayersInternal(); updateCompositingLayersInternal();
// Clear data only valid during compositing updates.
clearAncestorDependentPropertyCacheRecursive(rootRenderLayer());
lifecycle().advanceTo(DocumentLifecycle::CompositingClean); lifecycle().advanceTo(DocumentLifecycle::CompositingClean);
DocumentAnimations::startPendingAnimations(m_renderView.document()); DocumentAnimations::startPendingAnimations(m_renderView.document());
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment