Index: Source/core/rendering/RenderLayer.cpp |
diff --git a/Source/core/rendering/RenderLayer.cpp b/Source/core/rendering/RenderLayer.cpp |
index dffb6999ea46b40e65a624eb5517db9e241a1a2c..d3fe9e617cccd35ad35c8460104e2f2af2a763db 100644 |
--- a/Source/core/rendering/RenderLayer.cpp |
+++ b/Source/core/rendering/RenderLayer.cpp |
@@ -69,6 +69,8 @@ |
#include "core/page/UseCounter.h" |
#include "core/page/animation/AnimationController.h" |
#include "core/page/scrolling/ScrollingCoordinator.h" |
+// PATCH 2 |
+#include "core/platform/chromium/TraceEvent.h" |
#include "core/platform/FloatConversion.h" |
#include "core/platform/HistogramSupport.h" |
#include "core/platform/PlatformMouseEvent.h" |
@@ -113,6 +115,8 @@ |
#include "core/rendering/svg/RenderSVGResourceClipper.h" |
#include <wtf/MemoryInstrumentationVector.h> |
#include <wtf/StdLibExtras.h> |
+// PATCH 2 |
+#include <wtf/TemporaryChange.h> |
#include <wtf/text/CString.h> |
#include <wtf/UnusedParam.h> |
@@ -143,10 +147,12 @@ RenderLayer::RenderLayer(RenderLayerModelObject* renderer) |
, m_hasSelfPaintingLayerDescendant(false) |
, m_hasSelfPaintingLayerDescendantDirty(false) |
, m_hasOutOfFlowPositionedDescendant(false) |
- , m_hasOutOfFlowPositionedDescendantDirty(true) |
+ // PATCH 1 |
+ , m_forceNeedsCompositedScrolling(DoNotForceCompositedScrolling) |
, m_needsCompositedScrolling(false) |
- , m_descendantsAreContiguousInStackingOrder(false) |
- , m_descendantsAreContiguousInStackingOrderDirty(true) |
+ // PATCH 3 |
+ , m_canBePromotedToStackingContainer(false) |
+ , m_canBePromotedToStackingContainerDirty(true) |
, m_isRootLayer(renderer->isRenderView()) |
, m_usedTransparency(false) |
, m_paintingInsideReflection(false) |
@@ -482,168 +488,196 @@ bool RenderLayer::acceleratedCompositingForOverflowScrollEnabled() const |
&& renderer()->frame()->page()->settings()->acceleratedCompositingForOverflowScrollEnabled(); |
} |
-// If we are a stacking container, then this function will determine if our |
-// descendants for a contiguous block in stacking order. This is required in |
-// order for an element to be safely promoted to a stacking container. It is safe |
-// to become a stacking container if this change would not alter the stacking |
-// order of layers on the page. That can only happen if a non-descendant appear |
-// between us and our descendants in stacking order. Here's an example: |
-// |
-// this |
-// / | \. |
-// A B C |
-// /\ | /\. |
-// 0 -8 D 2 7 |
-// | |
-// 5 |
-// |
-// I've labeled our normal flow descendants A, B, C, and D, our stacking |
-// container descendants with their z indices, and us with 'this' (we're a |
-// stacking container and our zIndex doesn't matter here). These nodes appear in |
-// three lists: posZOrder, negZOrder, and normal flow (keep in mind that normal |
-// flow layers don't overlap). So if we arrange these lists in order we get our |
-// stacking order: |
-// |
-// [-8], [A-D], [0, 2, 5, 7]--> pos z-order. |
-// | | |
-// Neg z-order. <-+ +--> Normal flow descendants. |
-// |
-// We can then assign new, 'stacking' order indices to these elements as follows: |
-// |
-// [-8], [A-D], [0, 2, 5, 7] |
-// 'Stacking' indices: -1 0 1 2 3 4 |
-// |
-// Note that the normal flow descendants can share an index because they don't |
-// stack/overlap. Now our problem becomes very simple: a layer can safely become |
-// a stacking container if the stacking-order indices of it and its descendants |
-// appear in a contiguous block in the list of stacking indices. This problem |
-// can be solved very efficiently by calculating the min/max stacking indices in |
-// the subtree, and the number stacking container descendants. Once we have this |
-// information, we know that the subtree's indices form a contiguous block if: |
-// |
-// maxStackIndex - minStackIndex == numSCDescendants |
+// PATCH 3 |
+static inline bool isPositionedContainer(const RenderLayer* layer) |
+{ |
+ // FIXME: This is not in sync with containingBlock. |
+ // RenderObject::canContainFixedPositionedObject() should probably be used |
+ // instead. |
+ RenderLayerModelObject* layerRenderer = layer->renderer(); |
+ return layer->isRootLayer() || layerRenderer->isPositioned() || layer->hasTransform(); |
+} |
+ |
+enum StackingOrderDirection { FromBackground, FromForeground }; |
+ |
+// We'd like to be able to iterate through a single paint order list, but for |
+// efficiency's sake, we hang onto two lists instead (namely, the pos and neg |
+// z-order lists produced by CollectLayers). This function allows us to index |
+// into these two lists as if they were one. It also allows us to index into |
+// this virtual list either from the start or from the end (i.e., in either |
+// stacking order direction). |
+static const RenderLayer* getStackingOrderElementAt(const Vector<RenderLayer*>* posZOrderList, const Vector<RenderLayer*>* negZOrderList, const StackingOrderDirection direction, const size_t index) |
+{ |
+ size_t negZOrderListSize = negZOrderList ? negZOrderList->size() : 0; |
+ |
+ if (direction == FromBackground) { |
+ if (index < negZOrderListSize) |
+ return negZOrderList->at(index); |
+ |
+ return posZOrderList->at(index - negZOrderListSize); |
+ } |
+ |
+ size_t posZOrderListSize = posZOrderList ? posZOrderList->size() : 0; |
+ |
+ if (index < posZOrderListSize) |
+ return posZOrderList->at(posZOrderListSize - index - 1); |
+ |
+ return negZOrderList->at(negZOrderListSize - (index - posZOrderListSize) - 1); |
+} |
+ |
+// After promotion, the paint order consists of |
+// a) the non-descendants which precede the promoted layer, |
+// b) the promoted layer, and |
+// c) the non-descendants which succeed the promoted layer. |
// |
-// So for node A in the example above we would have: |
-// maxStackIndex = 1 |
-// minStackIndex = -1 |
-// numSCDecendants = 2 |
+// If the current layer's descendants form a contiguous block in paint order |
+// before promotion, the paint order will consist of |
+// a) the non-descendants which precede the current layer and its descendants, |
+// b) the current layer and its descendants |
+// c) The non-descendants which succeed the current layer and its descendants. |
// |
-// and so, |
-// maxStackIndex - minStackIndex == numSCDescendants |
-// ===> 1 - (-1) == 2 |
-// ===> 2 == 2 |
+// Sub-lists (a) and (c) should be identical in both paint order lists if |
+// and only if the descendants form a contiguous block. In fact, this is the |
+// only check we need to perform since the order of the descendants with |
+// respect to each other cannot be affected by promotion (i.e., we don't |
+// need to worry about sub-list (b)). |
// |
-// Since this is true, A can safely become a stacking container. |
-// Now, for node C we have: |
+// Some examples: |
+// C = currentLayer |
+// - = negative z-order child of currentLayer |
+// + = positive z-order child of currentLayer |
+// A = positioned ancestor of currentLayer |
+// x = any other RenderLayer in the list |
// |
-// maxStackIndex = 4 |
-// minStackIndex = 0 <-- because C has stacking index 0. |
-// numSCDecendants = 2 |
+// original | zOrderListBeforePromote | zOrderListAfterPromote |
+// zOrderListBeforePromote | after inserting C as above | |
+// --------------------------------------------------------------------------------------- |
+// (1) x---+++x | x---C+++x | xCx |
+// (2) x---+A++x | x---+AC++x | xACx |
+// (3) x-x--+++x | x-x--C+++x | xxCx |
+// (4) xxA++x | xxAC++x | xxACx |
// |
-// and so, |
-// maxStackIndex - minStackIndex == numSCDescendants |
-// ===> 4 - 0 == 2 |
-// ===> 4 == 2 |
+// In example (1), we compare sub-list (a) by marching from the left of both |
+// lists (zOrderListBeforePromote after inserting C and |
+// zOrderListAfterPromote). The first mismatch is at index 1 when we hit '-' |
+// and 'C'. That means we have neg z-order descendants. This is a problem if |
+// we have a background. Before promotion, this bg would get painted with |
+// the current layer (i.e., after the neg z-order descendants), but after |
+// promotion the bg would get painted before them. This is a stacking order |
+// violation and we can't promote. However, if we don't have a background, |
+// we would continue on to the second pass. When comparing from the right, |
+// we mismatch on '+' and 'C'. Since we hit 'C' on zOrderListAfterPromote, |
+// we know that the children are contiguous, and we will promote. |
// |
-// Since this is false, C cannot be safely promoted to a stacking container. This |
-// happened because of the elements with z-index 5 and 0. Now if 5 had been a |
-// child of C rather than D, and A had no child with Z index 0, we would have had: |
+// In example (2), when marching from the left, we'll hit a mismatch again |
+// on the second element we look at. This time, since this element is an 'A' |
+// in zOrderListAfterPromote, this indicates that there is an extra layer |
+// (the 'A') mixed in with the children. This could cause a change in paint |
+// order if we promote, so we decide not to and break out of the loop. Note |
+// that if the current layer has a background, this would provide a second |
+// reason not to opt in, since again we have negative z-order children who |
+// would change paint order with respect to our background if we promoted. |
// |
-// maxStackIndex = 3 |
-// minStackIndex = 0 <-- because C has stacking index 0. |
-// numSCDecendants = 3 |
+// In example (3), the discontiguity of the negative z-order children causes |
+// us to fail early in our "FromBackground" pass when we try to compare '-' |
+// from zOrderListBeforePromote with 'x' in zOrderListAfterPromote. |
// |
-// and so, |
-// maxStackIndex - minStackIndex == numSCDescendants |
-// ===> 3 - 0 == 3 |
-// ===> 3 == 3 |
+// Finally in example (4), we would match 'xxAC' from the left, then stop |
+// since we hit 'C'. Then we would match 'x' from the right, and mismatch |
+// on '+' and 'C'. Since we're at 'C' on the zOrderListAfterPromote, we |
+// conclude that all the children are contiguous. Since there are no |
+// negative z-order children, a background layer is irrelevant in this case. |
+// We will opt in, keeping paint order constant. |
+static bool compareLayerListsBeforeAndAfterPromote(const RenderLayer* currentLayer, |
+ const Vector<RenderLayer*>* posZOrderListBeforePromote, |
+ const Vector<RenderLayer*>* negZOrderListBeforePromote, |
+ const Vector<RenderLayer*>* posZOrderListAfterPromote, |
+ const Vector<RenderLayer*>* negZOrderListAfterPromote, |
+ const size_t sizeBeforePromote, |
+ const size_t sizeAfterPromote, |
+ const StackingOrderDirection direction) |
+{ |
+ for (size_t index = 0; index < sizeBeforePromote && index < sizeAfterPromote; index++) { |
+ const RenderLayer* layerBeforePromote = getStackingOrderElementAt(posZOrderListBeforePromote, negZOrderListBeforePromote, direction, index); |
+ const RenderLayer* layerAfterPromote = getStackingOrderElementAt(posZOrderListAfterPromote, negZOrderListAfterPromote, direction, index); |
+ |
+ if (layerBeforePromote != layerAfterPromote) { |
+ // If we find a mismatch, the only situation where we haven't |
+ // necessarily changed paint order yet is if layerAfterPromote |
+ // is currentLayer. |
+ if (layerAfterPromote != currentLayer) |
+ return false; |
+ |
+ // Also, if the current layer has a background, then any |
+ // negative z-order children will get between the background |
+ // and the rest of the layer. |
+ if (direction == FromBackground && currentLayer->renderer()->hasBackground()) |
+ return false; |
+ } |
+ |
+ // To compare the sub-lists (a) and (c) from the comment above, we only |
+ // need to march until we hit the currentLayer in the |
+ // zOrderListAfterPromote from each direction. |
+ if (layerAfterPromote == currentLayer) |
+ break; |
+ } |
+ |
+ return true; |
+} |
+ |
+// Determine whether the current layer can be promoted to a stacking container, |
+// given its closest stacking context ancestor. We do this by computing what |
+// positive and negative z-order lists would look like before and after |
+// promotion, and ensuring that proper stacking order is preserved between the |
+// two sets of lists. |
// |
-// And we would conclude that C could be promoted. |
-void RenderLayer::updateDescendantsAreContiguousInStackingOrder() |
+// For more details on how the lists will be compared, see the comment and |
+// examples for compareLayerListsBeforeAndAfterPromote(). |
+void RenderLayer::updateCanBeStackingContainer(RenderLayer* ancestorStackingContext) |
{ |
- if (!m_descendantsAreContiguousInStackingOrderDirty || !isStackingContext() || !acceleratedCompositingForOverflowScrollEnabled()) |
- return; |
+ TRACE_EVENT0("blink", "RenderLayer::updateCanBeStackingContainer"); |
- ASSERT(!m_normalFlowListDirty); |
- ASSERT(!m_zOrderListsDirty); |
+ ASSERT(!isStackingContext()); |
- OwnPtr<Vector<RenderLayer*> > posZOrderList; |
- OwnPtr<Vector<RenderLayer*> > negZOrderList; |
- rebuildZOrderLists(StopAtStackingContexts, posZOrderList, negZOrderList); |
+ if (!m_canBePromotedToStackingContainerDirty || !acceleratedCompositingForOverflowScrollEnabled()) |
+ return; |
- // Create a reverse lookup. |
- HashMap<const RenderLayer*, int> lookup; |
+ FrameView* frameView = renderer()->view()->frameView(); |
+ if (!frameView || !frameView->containsScrollableArea(this)) |
+ return; |
- if (negZOrderList) { |
- int stackingOrderIndex = -1; |
- size_t listSize = negZOrderList->size(); |
- for (size_t i = 0; i < listSize; ++i) { |
- RenderLayer* currentLayer = negZOrderList->at(listSize - i - 1); |
- if (!currentLayer->isStackingContext()) |
- continue; |
- lookup.set(currentLayer, stackingOrderIndex--); |
- } |
- } |
+ OwnPtr<Vector<RenderLayer*> > posZOrderListBeforePromote; |
+ OwnPtr<Vector<RenderLayer*> > negZOrderListBeforePromote; |
+ OwnPtr<Vector<RenderLayer*> > posZOrderListAfterPromote; |
+ OwnPtr<Vector<RenderLayer*> > negZOrderListAfterPromote; |
+ size_t posZOrderListSizeBeforePromote, negZOrderListSizeBeforePromote, posZOrderListSizeAfterPromote, negZOrderListSizeAfterPromote; |
- if (posZOrderList) { |
- size_t listSize = posZOrderList->size(); |
- int stackingOrderIndex = 1; |
- for (size_t i = 0; i < listSize; ++i) { |
- RenderLayer* currentLayer = posZOrderList->at(i); |
- if (!currentLayer->isStackingContext()) |
- continue; |
- lookup.set(currentLayer, stackingOrderIndex++); |
- } |
- } |
+ collectBeforePromotionZOrderList(ancestorStackingContext, posZOrderListBeforePromote, negZOrderListBeforePromote); |
+ collectAfterPromotionZOrderList(ancestorStackingContext, posZOrderListAfterPromote, negZOrderListAfterPromote); |
- int minIndex = 0; |
- int maxIndex = 0; |
- int count = 0; |
- bool firstIteration = true; |
- updateDescendantsAreContiguousInStackingOrderRecursive(lookup, minIndex, maxIndex, count, firstIteration); |
+ size_t sizeBeforePromote = 0; |
+ if (posZOrderListBeforePromote) |
+ sizeBeforePromote += posZOrderListBeforePromote->size(); |
+ if (negZOrderListBeforePromote) |
+ sizeBeforePromote += negZOrderListBeforePromote->size(); |
- m_descendantsAreContiguousInStackingOrderDirty = false; |
-} |
+ size_t sizeAfterPromote = 0; |
+ if (posZOrderListAfterPromote) |
+ sizeAfterPromote += posZOrderListAfterPromote->size(); |
+ if (negZOrderListAfterPromote) |
+ sizeAfterPromote += negZOrderListAfterPromote->size(); |
-void RenderLayer::updateDescendantsAreContiguousInStackingOrderRecursive(const HashMap<const RenderLayer*, int>& lookup, int& minIndex, int& maxIndex, int& count, bool firstIteration) |
-{ |
- if (isStackingContext() && !firstIteration) { |
- if (lookup.contains(this)) { |
- minIndex = std::min(minIndex, lookup.get(this)); |
- maxIndex = std::max(maxIndex, lookup.get(this)); |
- count++; |
- } |
- return; |
- } |
+ bool canPromote = compareLayerListsBeforeAndAfterPromote(this, posZOrderListBeforePromote.get(), negZOrderListBeforePromote.get(), |
+ posZOrderListAfterPromote.get(), negZOrderListAfterPromote.get(), |
+ sizeBeforePromote, sizeAfterPromote, FromBackground) |
+ && compareLayerListsBeforeAndAfterPromote(this, posZOrderListBeforePromote.get(), negZOrderListBeforePromote.get(), |
+ posZOrderListAfterPromote.get(), negZOrderListAfterPromote.get(), |
+ sizeBeforePromote, sizeAfterPromote, FromForeground); |
- for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) { |
- int childMinIndex = 0; |
- int childMaxIndex = 0; |
- int childCount = 0; |
- child->updateDescendantsAreContiguousInStackingOrderRecursive(lookup, childMinIndex, childMaxIndex, childCount, false); |
- if (childCount) { |
- count += childCount; |
- minIndex = std::min(minIndex, childMinIndex); |
- maxIndex = std::max(maxIndex, childMaxIndex); |
- } |
- } |
+ bool didUpdate = (canPromote != m_canBePromotedToStackingContainer); |
- if (!isStackingContext()) { |
- bool newValue = maxIndex - minIndex == count; |
- bool didUpdate = newValue != m_descendantsAreContiguousInStackingOrder; |
- m_descendantsAreContiguousInStackingOrder = newValue; |
- if (didUpdate) |
- updateNeedsCompositedScrolling(); |
- } |
-} |
- |
-static inline bool isPositionedContainer(const RenderLayer* layer) |
-{ |
- // FIXME: This is not in sync with containingBlock. |
- // RenderObject::canContainFixedPositionedObject() should probably be used |
- // instead. |
- RenderLayerModelObject* layerRenderer = layer->renderer(); |
- return layer->isRootLayer() || layerRenderer->isPositioned() || layer->hasTransform(); |
+ m_canBePromotedToStackingContainer = canPromote; |
+ m_canBePromotedToStackingContainerDirty = false; |
} |
void RenderLayer::collectBeforePromotionZOrderList(RenderLayer* ancestorStackingContext, OwnPtr<Vector<RenderLayer*> >& posZOrderListBeforePromote, OwnPtr<Vector<RenderLayer*> >& negZOrderListBeforePromote) |
@@ -1062,7 +1096,8 @@ bool RenderLayer::canBeStackingContainer() const |
if (isStackingContext() || !ancestorStackingContainer()) |
return true; |
- return m_descendantsAreContiguousInStackingOrder; |
+ // PATCH 3 |
hartmanng
2013/05/02 14:04:01
There should be an assert in here, right?
|
+ return m_canBePromotedToStackingContainer; |
} |
void RenderLayer::setHasVisibleContent() |
@@ -1118,56 +1153,65 @@ void RenderLayer::setAncestorChainHasVisibleDescendant() |
} |
} |
-void RenderLayer::updateDescendantDependentFlags(HashSet<const RenderObject*>* outOfFlowDescendantContainingBlocks) |
+// PATCH 2 - requires a full tree walk. We *only* want to do this once after a style change, |
+// so it must be tied to the phase work. |
+void RenderLayer::updateHasOutOfFlowPositionedDescendant(HashSet<const RenderObject*>* containingBlocks) |
{ |
- if (m_visibleDescendantStatusDirty || m_hasSelfPaintingLayerDescendantDirty || m_hasOutOfFlowPositionedDescendantDirty) { |
- const bool hadVisibleDescendant = m_hasVisibleDescendant; |
- const bool hadOutOfFlowPositionedDescendant = m_hasOutOfFlowPositionedDescendant; |
+ const bool hadOutOfFlowPositionedDescendant = hasOutOfFlowPositionedDescendant(); |
+ m_hasOutOfFlowPositionedDescendant = false; |
+ |
+ HashSet<const RenderObject*> childContainingBlocks; |
+ for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) { |
+ childContainingBlocks.clear(); |
+ child->updateHasOutOfFlowPositionedDescendant(&childContainingBlocks); |
+ |
+ const bool childIsOutOfFlowPositioned = child->renderer() |
+ && child->renderer()->isOutOfFlowPositioned() |
+ && (child->hasVisibleDescendant() || child->hasVisibleContent()); |
+ |
+ if (childIsOutOfFlowPositioned) |
+ childContainingBlocks.add(child->renderer()->containingBlock()); |
+ |
+ size_t numContainingBlocks = childContainingBlocks.size(); |
+ childContainingBlocks.remove(renderer()); |
+ |
+ if (containingBlocks && !childContainingBlocks.isEmpty()) { |
+ HashSet<const RenderObject*>::const_iterator it = childContainingBlocks.begin(); |
+ for (; it != childContainingBlocks.end(); ++it) |
+ containingBlocks->add(*it); |
+ } |
+ m_hasOutOfFlowPositionedDescendant |= !childContainingBlocks.isEmpty(); |
+ } |
+ |
+ if (m_hasOutOfFlowPositionedDescendant != hadOutOfFlowPositionedDescendant) |
+ compositor()->setNeedsUpdateCompositingRequirementsState(); |
+} |
+ |
+void RenderLayer::updateDescendantDependentFlags() |
+{ |
+ if (m_visibleDescendantStatusDirty || m_hasSelfPaintingLayerDescendantDirty) { |
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()); |
m_hasVisibleDescendant |= hasVisibleDescendant; |
m_hasSelfPaintingLayerDescendant |= hasSelfPaintingLayerDescendant; |
- m_hasOutOfFlowPositionedDescendant |= hasOutOfFlowPositionedDescendant; |
- if (m_hasVisibleDescendant && m_hasSelfPaintingLayerDescendant && m_hasOutOfFlowPositionedDescendant) |
+ if (m_hasVisibleDescendant && m_hasSelfPaintingLayerDescendant) |
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 { |
@@ -1193,10 +1237,8 @@ void RenderLayer::updateDescendantDependentFlags(HashSet<const RenderObject*>* o |
r = r->nextSibling(); |
} |
} |
- } |
- m_visibleContentStatusDirty = false; |
- if (hadVisibleContent != m_hasVisibleContent) |
- updateNeedsCompositedScrolling(); |
+ } |
+ m_visibleContentStatusDirty = false; |
} |
} |
@@ -1767,16 +1809,7 @@ 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; |
- } |
+ // PATCH 2 |
} |
child->updateDescendantDependentFlags(); |
@@ -1787,7 +1820,8 @@ void RenderLayer::addChild(RenderLayer* child, RenderLayer* beforeChild) |
setAncestorChainHasSelfPaintingLayerDescendant(); |
if (child->renderer() && (child->renderer()->isOutOfFlowPositioned() || child->hasOutOfFlowPositionedDescendant())) |
- setAncestorChainHasOutOfFlowPositionedDescendant(child->renderer()->containingBlock()); |
+ // PATCH 2 |
+ compositor()->setNeedsUpdateCompositingRequirementsState(); |
compositor()->layerWasAdded(this, child); |
} |
@@ -1815,28 +1849,19 @@ 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; |
- } |
+ // PATCH 2 |
} |
- if ((oldChild->renderer() && oldChild->renderer()->isOutOfFlowPositioned()) || oldChild->hasOutOfFlowPositionedDescendant()) |
- dirtyAncestorChainHasOutOfFlowPositionedDescendantStatus(); |
- |
+ // PATCH 2 |
oldChild->setPreviousSibling(0); |
oldChild->setNextSibling(0); |
oldChild->setParent(0); |
oldChild->updateDescendantDependentFlags(); |
+ // PATCH 2 |
+ if ((oldChild->renderer() && oldChild->renderer()->isOutOfFlowPositioned()) || oldChild->hasOutOfFlowPositionedDescendant()) |
+ compositor()->setNeedsUpdateCompositingRequirementsState(); |
+ |
if (oldChild->m_hasVisibleContent || oldChild->m_hasVisibleDescendant) |
dirtyAncestorChainVisibleDescendantStatus(); |
@@ -2051,26 +2076,41 @@ bool RenderLayer::usesCompositedScrolling() const |
bool RenderLayer::needsCompositedScrolling() const |
{ |
+ // PATCH 1 |
+ switch (m_forceNeedsCompositedScrolling) { |
+ case DoNotForceCompositedScrolling: |
+ return m_needsCompositedScrolling; |
+ case ForceCompositedScrollingOn: |
+ return true; |
+ case ForceCompositedScrollingOff: |
+ return false; |
+ } |
+ |
return m_needsCompositedScrolling; |
} |
+// PATCH 1 |
void RenderLayer::updateNeedsCompositedScrolling() |
{ |
bool needsCompositedScrolling = false; |
FrameView* frameView = renderer()->view()->frameView(); |
- if (frameView && frameView->containsScrollableArea(this)) { |
- updateDescendantDependentFlags(); |
+ if (frameView && frameView->containsScrollableArea(this) && acceleratedCompositingForOverflowScrollEnabled()) { |
+ if (isStackingContext()) { |
+ needsCompositedScrolling = true; |
+ } else { |
+ RenderLayer* stackingContext = ancestorStackingContext(); |
+ updateCanBeStackingContainer(stackingContext); |
- bool forceUseCompositedScrolling = acceleratedCompositingForOverflowScrollEnabled() |
- && canBeStackingContainer() |
- && !hasOutOfFlowPositionedDescendant(); |
+ bool forceUseCompositedScrolling = canBeStackingContainer() && !hasOutOfFlowPositionedDescendant(); |
#if ENABLE(ACCELERATED_OVERFLOW_SCROLLING) |
- needsCompositedScrolling = forceUseCompositedScrolling || renderer()->style()->useTouchOverflowScrolling(); |
+ needsCompositedScrolling = forceUseCompositedScrolling || renderer()->style()->useTouchOverflowScrolling(); |
#else |
- needsCompositedScrolling = forceUseCompositedScrolling; |
+ needsCompositedScrolling = forceUseCompositedScrolling; |
#endif |
+ } |
+ |
// We gather a boolean value for use with Google UMA histograms to |
// quantify the actual effects of a set of patches attempting to |
// relax composited scrolling requirements, thereby increasing the |
@@ -2084,6 +2124,23 @@ void RenderLayer::updateNeedsCompositedScrolling() |
m_needsCompositedScrolling = needsCompositedScrolling; |
+ // Note, the z-order lists may need to be rebuilt, but our code guarantees |
+ // that we have not affected stacking, so we will not dirty |
+ // m_canBePromotedToStackingContainer for either us or our stacking context |
+ // or container. |
+ didUpdateNeedsCompositedScrolling(); |
+} |
+ |
+// PATCH 1 |
+void RenderLayer::setForceNeedsCompositedScrolling(RenderLayer::ForceNeedsCompositedScrollingMode mode) |
+{ |
+ m_forceNeedsCompositedScrolling = mode; |
+ didUpdateNeedsCompositedScrolling(); |
+} |
+ |
+// PATCH 1 |
+void RenderLayer::didUpdateNeedsCompositedScrolling() |
+{ |
updateIsNormalFlowOnly(); |
updateSelfPaintingLayer(); |
@@ -5607,7 +5664,10 @@ void RenderLayer::dirtyZOrderLists() |
m_negZOrderList->clear(); |
m_zOrderListsDirty = true; |
- m_descendantsAreContiguousInStackingOrderDirty = true; |
+ // PATCH 3 |
+ m_canBePromotedToStackingContainerDirty = true; |
+ // PATCH 2 |
+ compositor()->setNeedsUpdateCompositingRequirementsState(); |
if (!renderer()->documentBeingDestroyed()) { |
compositor()->setCompositingLayersNeedRebuild(); |
@@ -5702,6 +5762,7 @@ void RenderLayer::updateNormalFlowList() |
m_normalFlowListDirty = false; |
} |
+// PATCH 2 |
void RenderLayer::collectLayers(bool includeHiddenLayers, CollectLayersBehavior behavior, OwnPtr<Vector<RenderLayer*> >& posBuffer, OwnPtr<Vector<RenderLayer*> >& negBuffer, const RenderLayer* layerToForceAsStackingContainer) |
{ |
if (isInTopLayer()) |
@@ -5712,18 +5773,28 @@ void RenderLayer::collectLayers(bool includeHiddenLayers, CollectLayersBehavior |
bool isStacking = false; |
switch (behavior) { |
- case StopAtStackingContexts: |
- isStacking = (this == layerToForceAsStackingContainer) || isStackingContext(); |
- break; |
+ case StopAtStackingContexts: |
+ isStacking = (this == layerToForceAsStackingContainer) || isStackingContext(); |
+ break; |
- case StopAtStackingContainers: |
- isStacking = (this == layerToForceAsStackingContainer) || isStackingContainer(); |
- break; |
+ case StopAtStackingContainers: |
+ isStacking = (this == layerToForceAsStackingContainer) || isStackingContainer(); |
+ break; |
+ } |
+ |
+ // This value could be affected by opt in. What we really need to know is |
+ // are you normal flow only, regardless of your opt in status. This is very |
+ // similar to asking if a layer is a stacking context rather than a |
+ // stacking container. |
+ bool isNormalFlowWithoutCompositedScrolling = isNormalFlowOnly(); |
+ if (this != layerToForceAsStackingContainer && behavior == StopAtStackingContexts) { |
+ TemporaryChange<ForceNeedsCompositedScrollingMode> forceOff(m_forceNeedsCompositedScrolling, ForceCompositedScrollingOff); |
+ isNormalFlowWithoutCompositedScrolling = shouldBeNormalFlowOnly(); |
} |
// Overflow layers are just painted by their enclosing layers, so they don't get put in zorder lists. |
bool includeHiddenLayer = includeHiddenLayers || (m_hasVisibleContent || (m_hasVisibleDescendant && isStacking)); |
- if (includeHiddenLayer && !isNormalFlowOnly() && !isOutOfFlowRenderFlowThread()) { |
+ if (includeHiddenLayer && !isNormalFlowWithoutCompositedScrolling && !isOutOfFlowRenderFlowThread()) { |
// Determine which buffer the child should be in. |
OwnPtr<Vector<RenderLayer*> >& buffer = (zIndex() >= 0) ? posBuffer : negBuffer; |
@@ -5746,9 +5817,9 @@ void RenderLayer::collectLayers(bool includeHiddenLayers, CollectLayersBehavior |
} |
} |
+// PATCH 2 |
void RenderLayer::updateLayerListsIfNeeded() |
{ |
- bool shouldUpdateDescendantsAreContiguousInStackingOrder = acceleratedCompositingForOverflowScrollEnabled() && isStackingContext() && (m_zOrderListsDirty || m_normalFlowListDirty) && m_descendantsAreContiguousInStackingOrderDirty; |
updateZOrderLists(); |
updateNormalFlowList(); |
@@ -5756,14 +5827,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() |
@@ -5943,9 +6006,8 @@ void RenderLayer::updateVisibilityAfterStyleChange(const RenderStyle* oldStyle) |
return; |
if (renderer()->style()->visibility() == VISIBLE) |
- setAncestorChainHasOutOfFlowPositionedDescendant(renderer()->containingBlock()); |
- else |
- dirtyAncestorChainHasOutOfFlowPositionedDescendantStatus(); |
+ // PATCH 2 |
+ compositor()->setNeedsUpdateCompositingRequirementsState(); |
} |
void RenderLayer::updateStackingContextsAfterStyleChange(const RenderStyle* oldStyle) |
@@ -5967,7 +6029,8 @@ void RenderLayer::updateStackingContextsAfterStyleChange(const RenderStyle* oldS |
else |
clearZOrderLists(); |
- updateNeedsCompositedScrolling(); |
+ // PATCH 2 |
+ compositor()->setNeedsUpdateCompositingRequirementsState(); |
} |
static bool overflowRequiresScrollbar(EOverflow overflow) |
@@ -6016,46 +6079,11 @@ void RenderLayer::updateScrollbarsAfterStyleChange(const RenderStyle* oldStyle) |
updateScrollableAreaSet(hasScrollableHorizontalOverflow() || hasScrollableVerticalOverflow()); |
} |
-void RenderLayer::setAncestorChainHasOutOfFlowPositionedDescendant(RenderObject* containingBlock) |
-{ |
- for (RenderLayer* layer = this; layer; layer = layer->parent()) { |
- if (!layer->m_hasOutOfFlowPositionedDescendantDirty && layer->hasOutOfFlowPositionedDescendant()) |
- break; |
- |
- layer->m_hasOutOfFlowPositionedDescendantDirty = false; |
- layer->m_hasOutOfFlowPositionedDescendant = true; |
- layer->updateNeedsCompositedScrolling(); |
- |
- if (layer->renderer() && layer->renderer() == containingBlock) |
- break; |
- } |
-} |
- |
-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(); |
- } |
- |
- if (parent()) |
- parent()->dirtyAncestorChainHasOutOfFlowPositionedDescendantStatus(); |
-} |
- |
+// PATCH 2 |
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 (!oldStyle || (renderer()->style()->position() != oldStyle->position())) |
+ compositor()->setNeedsUpdateCompositingRequirementsState(); |
} |
static bool hasOrHadFilters(const RenderStyle* oldStyle, const RenderStyle* newStyle) |
@@ -6213,7 +6241,8 @@ void RenderLayer::updateScrollableAreaSet(bool hasOverflow) |
updatedScrollableAreaSet = frameView->removeScrollableArea(this); |
if (updatedScrollableAreaSet) |
- updateNeedsCompositedScrolling(); |
+ // PATCH 2 |
+ compositor()->setNeedsUpdateCompositingRequirementsState(); |
} |
void RenderLayer::updateScrollCornerStyle() |