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
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())
return 0;
ASSERT(isInCompositingUpdate() || !m_ancestorDependentPropertyCache);
if (m_ancestorDependentPropertyCache && !m_ancestorDependentPropertyCache->ancestorCompositedScrollingLayerDirty())
return m_ancestorDependentPropertyCache->ancestorCompositedScrollingLayer();
RenderObject* containingBlock = renderer()->containingBlock();
if (!containingBlock)
return 0;
if (isInCompositingUpdate())
ensureAncestorDependentPropertyCache();
RenderLayer* ancestorCompositedScrollingLayer = 0;
for (RenderLayer* ancestorLayer = containingBlock->enclosingLayer(); ancestorLayer; ancestorLayer = ancestorLayer->parent()) {
if (ancestorLayer->needsCompositedScrolling())
return ancestorLayer;
if (ancestorLayer->needsCompositedScrolling()) {
ancestorCompositedScrollingLayer = ancestorLayer;
break;
}
}
return 0;
if (m_ancestorDependentPropertyCache)
m_ancestorDependentPropertyCache->setAncestorCompositedScrollingLayer(ancestorCompositedScrollingLayer);
return ancestorCompositedScrollingLayer;
}
RenderLayer* RenderLayer::ancestorScrollingLayer() const
......@@ -1689,6 +1715,10 @@ RenderLayer* RenderLayer::scrollParent() const
if (stackingNode()->isNormalFlowOnly())
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
// 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
......@@ -1701,8 +1731,10 @@ RenderLayer* RenderLayer::scrollParent() const
// 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
// 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())
return 0;
......@@ -1711,8 +1743,18 @@ RenderLayer* RenderLayer::scrollParent() const
for (RenderLayer* ancestor = parent(); ancestor && ancestor != scrollParent; ancestor = ancestor->parent()) {
if (ancestor->stackingNode()->isStackingContainer())
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;
}
......@@ -3527,6 +3569,11 @@ bool RenderLayer::isAllowedToQueryCompositingState() const
return renderer()->document().lifecycle().state() >= DocumentLifecycle::InCompositingUpdate;
}
bool RenderLayer::isInCompositingUpdate() const
{
return renderer()->document().lifecycle().state() == DocumentLifecycle::InCompositingUpdate;
}
CompositedLayerMappingPtr RenderLayer::compositedLayerMapping() const
{
ASSERT(isAllowedToQueryCompositingState());
......@@ -4065,6 +4112,36 @@ DisableCompositingQueryAsserts::DisableCompositingQueryAsserts()
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
#ifndef NDEBUG
......
......@@ -358,6 +358,9 @@ public:
// compositing state may legally be read.
bool isAllowedToQueryCompositingState() const;
// This returns true if our current phase is the compositing update.
bool isInCompositingUpdate() const;
CompositedLayerMappingPtr compositedLayerMapping() const;
CompositedLayerMappingPtr ensureCompositedLayerMapping();
......@@ -479,7 +482,33 @@ public:
bool hasDirectReasonsForCompositing() const { return compositingReasons() & CompositingReasonComboAllDirectReasons; }
void clearAncestorDependentPropertyCache();
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;
void setIsUnclippedDescendant(bool isUnclippedDescendant) { m_isUnclippedDescendant = isUnclippedDescendant; }
......@@ -578,7 +607,6 @@ private:
bool shouldBeSelfPaintingLayer() const;
private:
// FIXME: We should only create the stacking node if needed.
bool requiresStackingNode() const { return true; }
void updateStackingNode();
......@@ -630,7 +658,6 @@ private:
friend class RenderLayerCompositor;
friend class RenderLayerModelObject;
private:
LayerType m_layerType;
// Self-painting layer is an optimization where we avoid the heavy RenderLayer painting
......@@ -756,6 +783,8 @@ private:
OwnPtr<CompositedLayerMapping> m_compositedLayerMapping;
OwnPtr<RenderLayerScrollableArea> m_scrollableArea;
mutable OwnPtr<AncestorDependentPropertyCache> m_ancestorDependentPropertyCache;
CompositedLayerMapping* m_groupedMapping;
RenderLayerRepainter m_repainter;
......
......@@ -389,6 +389,14 @@ void RenderLayerCompositor::setNeedsCompositingUpdate(CompositingUpdateType upda
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()
{
TRACE_EVENT0("blink_rendering", "RenderLayerCompositor::updateCompositingLayers");
......@@ -406,6 +414,9 @@ void RenderLayerCompositor::updateCompositingLayers()
updateCompositingLayersInternal();
// Clear data only valid during compositing updates.
clearAncestorDependentPropertyCacheRecursive(rootRenderLayer());
lifecycle().advanceTo(DocumentLifecycle::CompositingClean);
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