Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1534)

Unified Diff: Source/core/rendering/RenderLayer.cpp

Issue 14863002: Only update composited-scrolling state once after layout. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Optimized. Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Source/core/rendering/RenderLayer.h ('k') | Source/core/rendering/RenderLayerCompositor.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Source/core/rendering/RenderLayer.cpp
diff --git a/Source/core/rendering/RenderLayer.cpp b/Source/core/rendering/RenderLayer.cpp
index 275b6e3a55f520bcb99e072fcf557cafde10ee70..c661b27ca22bdfa98f5026348ce1d2ff58618422 100644
--- a/Source/core/rendering/RenderLayer.cpp
+++ b/Source/core/rendering/RenderLayer.cpp
@@ -144,6 +144,7 @@ RenderLayer::RenderLayer(RenderLayerModelObject* renderer)
, m_hasSelfPaintingLayerDescendantDirty(false)
, m_hasOutOfFlowPositionedDescendant(false)
, m_hasOutOfFlowPositionedDescendantDirty(true)
+ , m_hasUnclippedDescendant(false)
, m_forceNeedsCompositedScrolling(DoNotForceCompositedScrolling)
, m_needsCompositedScrolling(false)
, m_descendantsAreContiguousInStackingOrder(false)
@@ -226,6 +227,9 @@ RenderLayer::~RenderLayer()
toElement(node)->setSavedLayerScrollOffset(m_scrollOffset);
}
+ if (!m_renderer->documentBeingDestroyed())
+ compositor()->removeOutOfFlowPositionedLayer(this);
Julien - ping for review 2013/05/03 21:15:13 It's weird that you try to remove |this| even if i
Ian Vollick 2013/05/04 03:33:00 The layer can get destructed when we cease to be o
+
destroyScrollbar(HorizontalScrollbar);
destroyScrollbar(VerticalScrollbar);
@@ -476,6 +480,35 @@ void RenderLayer::dirtyAncestorChainHasSelfPaintingLayerDescendantStatus()
}
}
+void RenderLayer::setAncestorChainHasOutOfFlowPositionedDescendant()
+{
+ for (RenderLayer* layer = this; layer; layer = layer->parent()) {
+ if (!layer->m_hasOutOfFlowPositionedDescendantDirty && layer->hasOutOfFlowPositionedDescendant())
+ break;
+
+ layer->m_hasOutOfFlowPositionedDescendantDirty = false;
+ layer->m_hasOutOfFlowPositionedDescendant = true;
+ }
+}
+
+void RenderLayer::dirtyAncestorChainHasOutOfFlowPositionedDescendantStatus()
+{
+ for (RenderLayer* layer = this; layer; layer = layer->parent()) {
+ layer->m_hasOutOfFlowPositionedDescendantDirty = true;
+
+ // We may or may not have an unclipped descendant. If we do, we'll reset
+ // this to true the next time composited scrolling state is updated.
+ layer->m_hasUnclippedDescendant = false;
+
+ // If we have reached an out of flow positioned layer, we know our parent should have an out-of-flow positioned descendant.
+ // In this case, there is no need to dirty our ancestors further.
+ if (layer->renderer()->isOutOfFlowPositioned()) {
+ ASSERT(!parent() || parent()->m_hasOutOfFlowPositionedDescendantDirty || parent()->hasOutOfFlowPositionedDescendant());
+ break;
+ }
+ }
+}
+
bool RenderLayer::acceleratedCompositingForOverflowScrollEnabled() const
{
return renderer()->frame()
@@ -565,9 +598,6 @@ void RenderLayer::updateDescendantsAreContiguousInStackingOrder()
if (!m_descendantsAreContiguousInStackingOrderDirty || !isStackingContext() || !acceleratedCompositingForOverflowScrollEnabled())
return;
- ASSERT(!m_normalFlowListDirty);
- ASSERT(!m_zOrderListsDirty);
Julien - ping for review 2013/05/03 21:15:13 It's the second time I see this ASSERT removed. Co
Ian Vollick 2013/05/04 03:33:00 I don't think these ASSERTS were ever useful. This
-
OwnPtr<Vector<RenderLayer*> > posZOrderList;
OwnPtr<Vector<RenderLayer*> > negZOrderList;
rebuildZOrderLists(StopAtStackingContexts, posZOrderList, negZOrderList);
@@ -629,13 +659,8 @@ void RenderLayer::updateDescendantsAreContiguousInStackingOrderRecursive(const H
}
}
- if (!isStackingContext()) {
- bool newValue = maxIndex - minIndex == count;
- bool didUpdate = newValue != m_descendantsAreContiguousInStackingOrder;
- m_descendantsAreContiguousInStackingOrder = newValue;
- if (didUpdate)
- updateNeedsCompositedScrolling();
- }
+ if (!isStackingContext())
+ m_descendantsAreContiguousInStackingOrder = maxIndex - minIndex == count;
Julien - ping for review 2013/05/03 21:15:13 As you touch this line, I would put some parenthes
Ian Vollick 2013/05/04 03:33:00 Done.
}
static inline bool isPositionedContainer(const RenderLayer* layer)
@@ -1063,6 +1088,7 @@ bool RenderLayer::canBeStackingContainer() const
if (isStackingContext() || !ancestorStackingContainer())
return true;
+ ASSERT(m_descendantsAreContiguousInStackingOrderDirty);
Julien - ping for review 2013/05/03 21:15:13 Isn't the ASSERT backwards? (I don't see a good ar
Ian Vollick 2013/05/04 03:33:00 Whoa! Yeah, it's backwards. The typo'd ASSERT was
return m_descendantsAreContiguousInStackingOrder;
}
@@ -1119,56 +1145,61 @@ void RenderLayer::setAncestorChainHasVisibleDescendant()
}
}
-void RenderLayer::updateDescendantDependentFlags(HashSet<const RenderObject*>* outOfFlowDescendantContainingBlocks)
+// This method is called on all out of flow positioned layers. It simply walks
+// up to its containing block marking every layer it passes as having an
+// 'unclipped' descendant. The map is used to prevent wasted walking. If we
+// have already passed layer A heading towards containing block B, there's no
+// need to do it again; we can early out.
+void RenderLayer::updateHasUnclippedDescendant(RenderLayer::AncestorContainingBlockMap& map)
{
- if (m_visibleDescendantStatusDirty || m_hasSelfPaintingLayerDescendantDirty || m_hasOutOfFlowPositionedDescendantDirty) {
- const bool hadVisibleDescendant = m_hasVisibleDescendant;
- const bool hadOutOfFlowPositionedDescendant = m_hasOutOfFlowPositionedDescendant;
+ ASSERT(renderer()->isOutOfFlowPositioned());
+ if (!m_hasVisibleContent && !m_hasVisibleDescendant)
+ return;
+
+ const RenderObject* containingBlock = renderer()->containingBlock();
+ for (RenderLayer* ancestor = parent(); ancestor && ancestor->renderer() != containingBlock; ancestor = ancestor->parent()) {
+ if (!map.contains(ancestor)) {
Julien - ping for review 2013/05/03 21:15:13 Ninja trick that avoids 3 hash lookups per call:
Ian Vollick 2013/05/04 03:33:00 Done.
Ian Vollick 2013/05/04 03:33:00 Done.
+ OwnPtr<HashSet<const RenderObject*> > containingBlocks = adoptPtr(new HashSet<const RenderObject*>);
+ containingBlocks->add(containingBlock);
+ map.add(ancestor, containingBlocks.release());
+ } else if (!map.get(ancestor)->contains(containingBlock)) {
+ map.get(ancestor)->add(containingBlock);
+ } else {
+ break;
+ }
+
+ ancestor->m_hasUnclippedDescendant = true;
+ }
+}
+void RenderLayer::updateDescendantDependentFlags()
+{
+ if (m_visibleDescendantStatusDirty || m_hasSelfPaintingLayerDescendantDirty || m_hasOutOfFlowPositionedDescendantDirty) {
m_hasVisibleDescendant = false;
m_hasSelfPaintingLayerDescendant = false;
m_hasOutOfFlowPositionedDescendant = false;
- HashSet<const RenderObject*> childOutOfFlowDescendantContainingBlocks;
for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
- childOutOfFlowDescendantContainingBlocks.clear();
- child->updateDescendantDependentFlags(&childOutOfFlowDescendantContainingBlocks);
-
- bool childIsOutOfFlowPositioned = child->renderer() && child->renderer()->isOutOfFlowPositioned();
- if (childIsOutOfFlowPositioned)
- childOutOfFlowDescendantContainingBlocks.add(child->renderer()->containingBlock());
-
- if (outOfFlowDescendantContainingBlocks) {
- HashSet<const RenderObject*>::const_iterator it = childOutOfFlowDescendantContainingBlocks.begin();
- for (; it != childOutOfFlowDescendantContainingBlocks.end(); ++it)
- outOfFlowDescendantContainingBlocks->add(*it);
- }
+ child->updateDescendantDependentFlags();
bool hasVisibleDescendant = child->m_hasVisibleContent || child->m_hasVisibleDescendant;
bool hasSelfPaintingLayerDescendant = child->isSelfPaintingLayer() || child->hasSelfPaintingLayerDescendant();
- bool hasOutOfFlowPositionedDescendant = hasVisibleDescendant && (!childOutOfFlowDescendantContainingBlocks.isEmpty() || child->hasOutOfFlowPositionedDescendant());
+ bool hasOutOfFlowPositionedDescendant = child->renderer()->isOutOfFlowPositioned() || child->hasOutOfFlowPositionedDescendant();
m_hasVisibleDescendant |= hasVisibleDescendant;
m_hasSelfPaintingLayerDescendant |= hasSelfPaintingLayerDescendant;
m_hasOutOfFlowPositionedDescendant |= hasOutOfFlowPositionedDescendant;
- if (m_hasVisibleDescendant && m_hasSelfPaintingLayerDescendant && m_hasOutOfFlowPositionedDescendant)
+ if (m_hasVisibleDescendant && m_hasSelfPaintingLayerDescendant && hasOutOfFlowPositionedDescendant)
break;
}
- if (outOfFlowDescendantContainingBlocks && renderer())
- outOfFlowDescendantContainingBlocks->remove(renderer());
-
m_visibleDescendantStatusDirty = false;
m_hasSelfPaintingLayerDescendantDirty = false;
m_hasOutOfFlowPositionedDescendantDirty = false;
-
- if (m_hasVisibleDescendant != hadVisibleDescendant || m_hasOutOfFlowPositionedDescendant != hadOutOfFlowPositionedDescendant)
- updateNeedsCompositedScrolling();
}
if (m_visibleContentStatusDirty) {
- const bool hadVisibleContent = m_hasVisibleContent;
if (renderer()->style()->visibility() == VISIBLE)
m_hasVisibleContent = true;
else {
@@ -1194,10 +1225,8 @@ void RenderLayer::updateDescendantDependentFlags(HashSet<const RenderObject*>* o
r = r->nextSibling();
}
}
- }
- m_visibleContentStatusDirty = false;
- if (hadVisibleContent != m_hasVisibleContent)
- updateNeedsCompositedScrolling();
+ }
+ m_visibleContentStatusDirty = false;
}
}
@@ -1768,16 +1797,6 @@ void RenderLayer::addChild(RenderLayer* child, RenderLayer* beforeChild)
// case where we're building up generated content layers. This is ok, since the lists will start
// off dirty in that case anyway.
child->dirtyStackingContainerZOrderLists();
-
- // Adding an out of flow positioned descendant can only affect
- // the opt-in decision for layers beneath and including our
- // containing block.
- RenderObject* containingBlock = child->renderer()->containingBlock();
- for (RenderLayer* layer = child; layer; layer = layer->parent()) {
- layer->updateNeedsCompositedScrolling();
- if (layer->renderer() == containingBlock)
- break;
- }
}
child->updateDescendantDependentFlags();
@@ -1787,8 +1806,14 @@ void RenderLayer::addChild(RenderLayer* child, RenderLayer* beforeChild)
if (child->isSelfPaintingLayer() || child->hasSelfPaintingLayerDescendant())
setAncestorChainHasSelfPaintingLayerDescendant();
- if (child->renderer() && (child->renderer()->isOutOfFlowPositioned() || child->hasOutOfFlowPositionedDescendant()))
- setAncestorChainHasOutOfFlowPositionedDescendant(child->renderer()->containingBlock());
+ if (child->renderer() && (child->renderer()->isOutOfFlowPositioned() || child->hasOutOfFlowPositionedDescendant())) {
+ // Now that the out of flow positioned descendant is in the tree, we
+ // need to tell the compositor to reevaluate the compositing
+ // requirements since we may be able to mark more layers as having
+ // an 'unclipped' descendant.
+ compositor()->setNeedsUpdateCompositingRequirementsState();
+ setAncestorChainHasOutOfFlowPositionedDescendant();
+ }
compositor()->layerWasAdded(this, child);
}
@@ -1816,28 +1841,21 @@ RenderLayer* RenderLayer::removeChild(RenderLayer* oldChild)
// reattachment process in removeOnlyThisLayer, the layer may already be disconnected
// from the main layer tree, so we need to null-check the |stackingContainer| value.
oldChild->dirtyStackingContainerZOrderLists();
-
- // This could affect whether or not a layer has an out of flow
- // positioned descendant so we need to schedule some updates.
- // Removing an out of flow positioned descendant can only affect
- // the opt-in decision for layers beneath and including the old child's
- // containing block.
- RenderObject* containingBlock = oldChild->renderer()->containingBlock();
- for (RenderLayer* layer = this; layer; layer = layer->parent()) {
- layer->updateNeedsCompositedScrolling();
- if (layer->renderer() == containingBlock)
- break;
- }
}
- if ((oldChild->renderer() && oldChild->renderer()->isOutOfFlowPositioned()) || oldChild->hasOutOfFlowPositionedDescendant())
- dirtyAncestorChainHasOutOfFlowPositionedDescendantStatus();
-
oldChild->setPreviousSibling(0);
oldChild->setNextSibling(0);
oldChild->setParent(0);
oldChild->updateDescendantDependentFlags();
+ if ((oldChild->renderer() && oldChild->renderer()->isOutOfFlowPositioned()) || oldChild->hasOutOfFlowPositionedDescendant()) {
+ // It may now be the case that a layer no longer has an unclipped
+ // descendant. Let the compositor know that it needs to reevaluate
+ // its compositing requirements to check this.
+ compositor()->setNeedsUpdateCompositingRequirementsState();
+ dirtyAncestorChainHasOutOfFlowPositionedDescendantStatus();
+ }
+
if (oldChild->m_hasVisibleContent || oldChild->m_hasVisibleDescendant)
dirtyAncestorChainVisibleDescendantStatus();
@@ -2066,6 +2084,9 @@ bool RenderLayer::needsCompositedScrolling() const
void RenderLayer::updateNeedsCompositedScrolling()
{
+ if (RenderLayer* ancestor = ancestorStackingContext())
+ ancestor->updateDescendantsAreContiguousInStackingOrder();
+
bool needsCompositedScrolling = false;
FrameView* frameView = renderer()->view()->frameView();
@@ -2074,7 +2095,7 @@ void RenderLayer::updateNeedsCompositedScrolling()
bool forceUseCompositedScrolling = acceleratedCompositingForOverflowScrollEnabled()
&& canBeStackingContainer()
- && !hasOutOfFlowPositionedDescendant();
+ && !hasUnclippedDescendant();
#if ENABLE(ACCELERATED_OVERFLOW_SCROLLING)
needsCompositedScrolling = forceUseCompositedScrolling || renderer()->style()->useTouchOverflowScrolling();
@@ -2089,6 +2110,11 @@ void RenderLayer::updateNeedsCompositedScrolling()
HistogramSupport::histogramEnumeration("Renderer.NeedsCompositedScrolling", needsCompositedScrolling, 2);
}
+ setNeedsCompositedScrolling(needsCompositedScrolling);
+}
+
+void RenderLayer::setNeedsCompositedScrolling(bool needsCompositedScrolling)
+{
if (m_needsCompositedScrolling == needsCompositedScrolling)
return;
@@ -5616,6 +5642,7 @@ void RenderLayer::dirtyZOrderLists()
m_descendantsAreContiguousInStackingOrderDirty = true;
if (!renderer()->documentBeingDestroyed()) {
+ compositor()->setNeedsUpdateCompositingRequirementsState();
compositor()->setCompositingLayersNeedRebuild();
if (acceleratedCompositingForOverflowScrollEnabled())
compositor()->setShouldReevaluateCompositingAfterLayout();
@@ -5754,7 +5781,6 @@ void RenderLayer::collectLayers(bool includeHiddenLayers, CollectLayersBehavior
void RenderLayer::updateLayerListsIfNeeded()
{
- bool shouldUpdateDescendantsAreContiguousInStackingOrder = acceleratedCompositingForOverflowScrollEnabled() && isStackingContext() && (m_zOrderListsDirty || m_normalFlowListDirty) && m_descendantsAreContiguousInStackingOrderDirty;
updateZOrderLists();
updateNormalFlowList();
@@ -5762,14 +5788,6 @@ void RenderLayer::updateLayerListsIfNeeded()
reflectionLayer->updateZOrderLists();
reflectionLayer->updateNormalFlowList();
}
-
- if (shouldUpdateDescendantsAreContiguousInStackingOrder) {
- updateDescendantsAreContiguousInStackingOrder();
- // The above function can cause us to update m_needsCompositedScrolling
- // and dirty our layer lists. Refresh them if necessary.
- updateZOrderLists();
- updateNormalFlowList();
- }
}
void RenderLayer::repaintIncludingDescendants()
@@ -5942,14 +5960,8 @@ bool RenderLayer::isVisuallyNonEmpty() const
void RenderLayer::updateVisibilityAfterStyleChange(const RenderStyle* oldStyle)
{
- EVisibility oldVisibility = oldStyle ? oldStyle->visibility() : VISIBLE;
- if (oldVisibility == renderer()->style()->visibility() || !renderer()->isOutOfFlowPositioned())
- return;
-
- if (renderer()->style()->visibility() == VISIBLE)
- setAncestorChainHasOutOfFlowPositionedDescendant(renderer()->containingBlock());
- else
- dirtyAncestorChainHasOutOfFlowPositionedDescendantStatus();
+ if (!oldStyle || (oldStyle->visibility() != renderer()->style()->visibility()))
+ compositor()->setNeedsUpdateCompositingRequirementsState();
}
void RenderLayer::updateStackingContextsAfterStyleChange(const RenderStyle* oldStyle)
@@ -5971,7 +5983,7 @@ void RenderLayer::updateStackingContextsAfterStyleChange(const RenderStyle* oldS
else
clearZOrderLists();
- updateNeedsCompositedScrolling();
+ compositor()->setNeedsUpdateCompositingRequirementsState();
}
static bool overflowRequiresScrollbar(EOverflow overflow)
@@ -6020,45 +6032,34 @@ void RenderLayer::updateScrollbarsAfterStyleChange(const RenderStyle* oldStyle)
updateScrollableAreaSet(hasScrollableHorizontalOverflow() || hasScrollableVerticalOverflow());
}
-void RenderLayer::setAncestorChainHasOutOfFlowPositionedDescendant(RenderObject* containingBlock)
+void RenderLayer::updateOutOfFlowPositioned(const RenderStyle* oldStyle)
{
- for (RenderLayer* layer = this; layer; layer = layer->parent()) {
- if (!layer->m_hasOutOfFlowPositionedDescendantDirty && layer->hasOutOfFlowPositionedDescendant())
- break;
+ if (oldStyle && (renderer()->style()->position() == oldStyle->position()))
+ return;
- layer->m_hasOutOfFlowPositionedDescendantDirty = false;
- layer->m_hasOutOfFlowPositionedDescendant = true;
- layer->updateNeedsCompositedScrolling();
+ bool wasOutOfFlowPositioned = oldStyle && (oldStyle->position() == AbsolutePosition || oldStyle->position() == FixedPosition);
+ bool isOutOfFlowPositioned = renderer()->isOutOfFlowPositioned();
+ if (!wasOutOfFlowPositioned && !isOutOfFlowPositioned)
+ return;
- if (layer->renderer() && layer->renderer() == containingBlock)
- break;
- }
-}
+ // Even if the layer remains out-of-flow, a change to this property
+ // will likely change its containing block. We must clear these bits
+ // so that they can be set properly by the RenderLayerCompositor.
+ for (RenderLayer* ancestor = parent(); ancestor; ancestor = ancestor->parent())
+ ancestor->m_hasUnclippedDescendant = false;
-void RenderLayer::dirtyAncestorChainHasOutOfFlowPositionedDescendantStatus()
-{
- if (m_hasOutOfFlowPositionedDescendant) {
- m_hasOutOfFlowPositionedDescendantDirty = true;
- // FIXME It would be nice to avoid this when we clean up render layer
- // updating. We shouldn't have to update the composited scrolling state
- // nearly as frequently if all the updates happen in a single, well
- // defined phase.
- updateNeedsCompositedScrolling();
- }
+ // Ensures that we reset the above bits correctly.
+ compositor()->setNeedsUpdateCompositingRequirementsState();
- if (parent())
- parent()->dirtyAncestorChainHasOutOfFlowPositionedDescendantStatus();
-}
+ if (wasOutOfFlowPositioned && isOutOfFlowPositioned)
+ return;
-void RenderLayer::updateOutOfFlowPositioned(const RenderStyle* oldStyle)
-{
- bool wasOutOfFlowPositioned = oldStyle && (oldStyle->position() == AbsolutePosition || oldStyle->position() == FixedPosition);
- bool isOutOfFlowPositioned = renderer()->isOutOfFlowPositioned();
- if (parent() && isOutOfFlowPositioned != wasOutOfFlowPositioned) {
- if (isOutOfFlowPositioned)
- parent()->setAncestorChainHasOutOfFlowPositionedDescendant(renderer()->containingBlock());
- else
- parent()->dirtyAncestorChainHasOutOfFlowPositionedDescendantStatus();
+ if (isOutOfFlowPositioned) {
+ setAncestorChainHasOutOfFlowPositionedDescendant();
+ compositor()->addOutOfFlowPositionedLayer(this);
+ } else {
+ dirtyAncestorChainHasSelfPaintingLayerDescendantStatus();
+ compositor()->removeOutOfFlowPositionedLayer(this);
}
}
@@ -6211,13 +6212,13 @@ void RenderLayer::updateScrollableAreaSet(bool hasOverflow)
isVisibleToHitTest &= owner->renderer() && owner->renderer()->visibleToHitTesting();
bool updatedScrollableAreaSet = false;
- if (hasOverflow && isVisibleToHitTest)
+ if (hasOverflow && isVisibleToHitTest) {
updatedScrollableAreaSet = frameView->addScrollableArea(this);
- else
+ compositor()->setNeedsUpdateCompositingRequirementsState();
+ } else {
updatedScrollableAreaSet = frameView->removeScrollableArea(this);
-
- if (updatedScrollableAreaSet)
- updateNeedsCompositedScrolling();
+ setNeedsCompositedScrolling(false);
+ }
}
void RenderLayer::updateScrollCornerStyle()
« no previous file with comments | « Source/core/rendering/RenderLayer.h ('k') | Source/core/rendering/RenderLayerCompositor.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698