Index: Source/core/rendering/RenderLayerCompositor.cpp |
diff --git a/Source/core/rendering/RenderLayerCompositor.cpp b/Source/core/rendering/RenderLayerCompositor.cpp |
index ca69154269837eb9da2c96fe8b1737e383ef9467..7e69cf5deac8b64d7d9594e6133848eb29a42eb1 100644 |
--- a/Source/core/rendering/RenderLayerCompositor.cpp |
+++ b/Source/core/rendering/RenderLayerCompositor.cpp |
@@ -439,9 +439,10 @@ void RenderLayerCompositor::updateCompositingLayers(CompositingUpdateType update |
if (needHierarchyUpdate) { |
// Update the hierarchy of the compositing layers. |
Vector<GraphicsLayer*> childList; |
+ HashSet<RenderLayer*> visited; |
{ |
TRACE_EVENT0("blink_rendering", "RenderLayerCompositor::rebuildCompositingLayerTree"); |
- rebuildCompositingLayerTree(updateRoot, childList, 0); |
+ rebuildCompositingLayerTree(updateRoot, childList, visited, 0); |
} |
// Host the document layer in the RenderView's root layer. |
@@ -456,7 +457,8 @@ void RenderLayerCompositor::updateCompositingLayers(CompositingUpdateType update |
} else if (needGeometryUpdate) { |
// We just need to do a geometry update. This is only used for position:fixed scrolling; |
// most of the time, geometry is updated via RenderLayer::styleChanged(). |
- updateLayerTreeGeometry(updateRoot, 0); |
+ HashSet<RenderLayer*> visited; |
+ updateLayerTreeGeometry(updateRoot, visited, 0); |
} |
#if !LOG_DISABLED |
@@ -1045,7 +1047,46 @@ bool RenderLayerCompositor::canAccelerateVideoRendering(RenderVideo* o) const |
return o->supportsAcceleratedRendering(); |
} |
-void RenderLayerCompositor::rebuildCompositingLayerTree(RenderLayer* layer, Vector<GraphicsLayer*>& childLayersOfEnclosingLayer, int depth) |
+// The purpose of this function is to ensure that we call rebuildCompostingLayerTree on curLayer's |
+// scroll parent (if it has one) before we call it on curLayer. This is necessary because rebuilding the |
+// compositing layer tree for curLayer will use values we computed for the scroll parent. More specifically, |
+// rebuildCompositingLayreTree will call RenderLayerBacking::updateGraphicsLayerGeometry, and it's this |
+// function that will pull values from a scroll parent's graphics layers. Unfortunately, |
+// the childList needs to be populated as if we'd visited all the layers in paint order. To work around |
+// this, when we visit a scroll parent out of order, we'll set its additions to childList aside (in |
+// scrollParentChildLists), and add them to the real childList when we visit the scroll parent in paint |
+// order. |
+void RenderLayerCompositor::rebuildCompositingLayerTreeForLayerAndScrollParents(RenderLayer* curLayer, Vector<GraphicsLayer*>& childList, HashSet<RenderLayer*>& visited, HashMap<RenderLayer*, Vector<GraphicsLayer*> >& scrollParentChildLists, int depth) |
+{ |
+ ASSERT(curLayer->zIndex() >= 0 || !visited.contains(curLayer)); |
+ if (visited.contains(curLayer)) { |
+ // We've already processed this layer, but since we processed it out of order, its |
+ // contribution to childList was not added. We must do that now. |
+ HashMap<RenderLayer*, Vector<GraphicsLayer*> >::iterator it = scrollParentChildLists.find(curLayer); |
+ ASSERT(it != scrollParentChildLists.end()); |
+ childList.append(it->value); |
+ scrollParentChildLists.remove(it); |
+ return; |
+ } |
+ |
+ if (requiresCompositingForOverflowScrollingParent(curLayer)) { |
+ RenderLayer* scrollParent = curLayer->ancestorScrollingLayer(); |
+ if (!visited.contains(scrollParent)) { |
+ ASSERT(!scrollParentChildLists.contains(scrollParent)); |
+ // We will populate scrollParentChildList rather than childList, since we're visiting it |
+ // out of order. |
+ Vector<GraphicsLayer*> scrollParentChildList; |
+ rebuildCompositingLayerTreeForLayerAndScrollParents(scrollParent, scrollParentChildList, visited, scrollParentChildLists, depth); |
+ // We will set aside the scrollParentChildList in scrollParentChildLists so that we can |
+ // add it to childList when we visit the scrollParent normally. |
+ scrollParentChildLists.add(scrollParent, scrollParentChildList); |
+ } |
+ } |
+ |
+ rebuildCompositingLayerTree(curLayer, childList, visited, depth); |
+} |
+ |
+void RenderLayerCompositor::rebuildCompositingLayerTree(RenderLayer* layer, Vector<GraphicsLayer*>& childLayersOfEnclosingLayer, HashSet<RenderLayer*>& visited, int depth) |
{ |
// Make the layer compositing if necessary, and set up clipping and content layers. |
// Note that we can only do work here that is independent of whether the descendant layers |
@@ -1061,6 +1102,8 @@ void RenderLayerCompositor::rebuildCompositingLayerTree(RenderLayer* layer, Vect |
pixelsAddedByPromotingAllTransitions = 0.0; |
} |
+ visited.add(layer); |
+ |
RenderLayerBacking* layerBacking = layer->backing(); |
if (layerBacking) { |
// The compositing state of all our children has been updated already, so now |
@@ -1103,12 +1146,13 @@ void RenderLayerCompositor::rebuildCompositingLayerTree(RenderLayer* layer, Vect |
LayerListMutationDetector mutationChecker(layer); |
#endif |
+ HashMap<RenderLayer*, Vector<GraphicsLayer*> > scrollParentChildLists; |
if (layer->isStackingContainer()) { |
if (Vector<RenderLayer*>* negZOrderList = layer->negZOrderList()) { |
size_t listSize = negZOrderList->size(); |
for (size_t i = 0; i < listSize; ++i) { |
RenderLayer* curLayer = negZOrderList->at(i); |
- rebuildCompositingLayerTree(curLayer, childList, depth + 1); |
+ rebuildCompositingLayerTreeForLayerAndScrollParents(curLayer, childList, visited, scrollParentChildLists, depth + 1); |
} |
} |
@@ -1121,7 +1165,7 @@ void RenderLayerCompositor::rebuildCompositingLayerTree(RenderLayer* layer, Vect |
size_t listSize = normalFlowList->size(); |
for (size_t i = 0; i < listSize; ++i) { |
RenderLayer* curLayer = normalFlowList->at(i); |
- rebuildCompositingLayerTree(curLayer, childList, depth + 1); |
+ rebuildCompositingLayerTreeForLayerAndScrollParents(curLayer, childList, visited, scrollParentChildLists, depth + 1); |
} |
} |
@@ -1130,7 +1174,7 @@ void RenderLayerCompositor::rebuildCompositingLayerTree(RenderLayer* layer, Vect |
size_t listSize = posZOrderList->size(); |
for (size_t i = 0; i < listSize; ++i) { |
RenderLayer* curLayer = posZOrderList->at(i); |
- rebuildCompositingLayerTree(curLayer, childList, depth + 1); |
+ rebuildCompositingLayerTreeForLayerAndScrollParents(curLayer, childList, visited, scrollParentChildLists, depth + 1); |
} |
} |
} |
@@ -1332,9 +1376,29 @@ bool RenderLayerCompositor::parentFrameContentLayers(RenderPart* renderer) |
return true; |
} |
+// The purpose of this function is to ensure that we call updateLayerTreeGeometry on layer's |
+// scroll parent (if it has one) before we call it on layer. This is necessary because updating |
+// layer tree geometry for layer will use values we computed for its scroll parent. |
+void RenderLayerCompositor::updateLayerTreeGeometryForLayerAndScrollParents(RenderLayer* layer, HashSet<RenderLayer*>& visited, int depth) |
+{ |
+ ASSERT(layer->zIndex() >= 0 || !visited.contains(layer)); |
+ if (visited.contains(layer)) |
+ return; |
+ |
+ if (requiresCompositingForOverflowScrollingParent(layer)) { |
+ RenderLayer* scrollParent = layer->ancestorScrollingLayer(); |
+ if (!visited.contains(scrollParent)) |
+ updateLayerTreeGeometryForLayerAndScrollParents(scrollParent, visited, depth); |
+ } |
+ |
+ updateLayerTreeGeometry(layer, visited, depth); |
+} |
+ |
// This just updates layer geometry without changing the hierarchy. |
-void RenderLayerCompositor::updateLayerTreeGeometry(RenderLayer* layer, int depth) |
+void RenderLayerCompositor::updateLayerTreeGeometry(RenderLayer* layer, HashSet<RenderLayer*>& visited, int depth) |
{ |
+ visited.add(layer); |
+ |
if (RenderLayerBacking* layerBacking = layer->backing()) { |
// The compositing state of all our children has been updated already, so now |
// we can compute and cache the composited bounds for this layer. |
@@ -1362,32 +1426,52 @@ void RenderLayerCompositor::updateLayerTreeGeometry(RenderLayer* layer, int dept |
LayerListMutationDetector mutationChecker(layer); |
#endif |
+ if (Vector<RenderLayer*>* normalFlowList = layer->normalFlowList()) { |
+ size_t listSize = normalFlowList->size(); |
+ for (size_t i = 0; i < listSize; ++i) |
+ updateLayerTreeGeometry(normalFlowList->at(i), visited, depth + 1); |
+ } |
+ |
if (layer->isStackingContainer()) { |
if (Vector<RenderLayer*>* negZOrderList = layer->negZOrderList()) { |
size_t listSize = negZOrderList->size(); |
for (size_t i = 0; i < listSize; ++i) |
- updateLayerTreeGeometry(negZOrderList->at(i), depth + 1); |
+ updateLayerTreeGeometryForLayerAndScrollParents(negZOrderList->at(i), visited, depth + 1); |
} |
} |
- if (Vector<RenderLayer*>* normalFlowList = layer->normalFlowList()) { |
- size_t listSize = normalFlowList->size(); |
- for (size_t i = 0; i < listSize; ++i) |
- updateLayerTreeGeometry(normalFlowList->at(i), depth + 1); |
- } |
- |
if (layer->isStackingContainer()) { |
if (Vector<RenderLayer*>* posZOrderList = layer->posZOrderList()) { |
size_t listSize = posZOrderList->size(); |
for (size_t i = 0; i < listSize; ++i) |
- updateLayerTreeGeometry(posZOrderList->at(i), depth + 1); |
+ updateLayerTreeGeometryForLayerAndScrollParents(posZOrderList->at(i), visited, depth + 1); |
} |
} |
} |
+// The purpose of this function is to ensure that we call updateCompositingDescendantGeometry on layer's |
+// scroll parent (if it has one) before we call it on layer. This is necessary because updating |
+// layer tree geometry for layer will use values we computed for its scroll parent. |
+void RenderLayerCompositor::updateCompositingDescendantGeometryForLayerAndScrollParents(RenderLayer* compositingAncestor, RenderLayer* layer, HashSet<RenderLayer*>& visited, bool compositedChildrenOnly) |
+{ |
+ ASSERT(layer->zIndex() >= 0 || !visited.contains(layer)); |
+ if (visited.contains(layer)) |
+ return; |
+ |
+ if (requiresCompositingForOverflowScrollingParent(layer)) { |
+ RenderLayer* scrollParent = layer->ancestorScrollingLayer(); |
+ if (!visited.contains(scrollParent)) |
+ updateCompositingDescendantGeometryForLayerAndScrollParents(compositingAncestor, scrollParent, visited, compositedChildrenOnly); |
+ } |
+ |
+ updateCompositingDescendantGeometry(compositingAncestor, layer, visited, compositedChildrenOnly); |
+} |
+ |
// Recurs down the RenderLayer tree until its finds the compositing descendants of compositingAncestor and updates their geometry. |
-void RenderLayerCompositor::updateCompositingDescendantGeometry(RenderLayer* compositingAncestor, RenderLayer* layer, bool compositedChildrenOnly) |
+void RenderLayerCompositor::updateCompositingDescendantGeometry(RenderLayer* compositingAncestor, RenderLayer* layer, HashSet<RenderLayer*>& visited, bool compositedChildrenOnly) |
{ |
+ visited.add(layer); |
+ |
if (layer != compositingAncestor) { |
if (RenderLayerBacking* layerBacking = layer->backing()) { |
layerBacking->updateCompositedBounds(); |
@@ -1404,7 +1488,7 @@ void RenderLayerCompositor::updateCompositingDescendantGeometry(RenderLayer* com |
} |
if (layer->reflectionLayer()) |
- updateCompositingDescendantGeometry(compositingAncestor, layer->reflectionLayer(), compositedChildrenOnly); |
+ updateCompositingDescendantGeometry(compositingAncestor, layer->reflectionLayer(), visited, compositedChildrenOnly); |
if (!layer->hasCompositingDescendant()) |
return; |
@@ -1417,21 +1501,21 @@ void RenderLayerCompositor::updateCompositingDescendantGeometry(RenderLayer* com |
if (Vector<RenderLayer*>* negZOrderList = layer->negZOrderList()) { |
size_t listSize = negZOrderList->size(); |
for (size_t i = 0; i < listSize; ++i) |
- updateCompositingDescendantGeometry(compositingAncestor, negZOrderList->at(i), compositedChildrenOnly); |
+ updateCompositingDescendantGeometryForLayerAndScrollParents(compositingAncestor, negZOrderList->at(i), visited, compositedChildrenOnly); |
} |
} |
if (Vector<RenderLayer*>* normalFlowList = layer->normalFlowList()) { |
size_t listSize = normalFlowList->size(); |
for (size_t i = 0; i < listSize; ++i) |
- updateCompositingDescendantGeometry(compositingAncestor, normalFlowList->at(i), compositedChildrenOnly); |
+ updateCompositingDescendantGeometryForLayerAndScrollParents(compositingAncestor, normalFlowList->at(i), visited, compositedChildrenOnly); |
} |
if (layer->isStackingContainer()) { |
if (Vector<RenderLayer*>* posZOrderList = layer->posZOrderList()) { |
size_t listSize = posZOrderList->size(); |
for (size_t i = 0; i < listSize; ++i) |
- updateCompositingDescendantGeometry(compositingAncestor, posZOrderList->at(i), compositedChildrenOnly); |
+ updateCompositingDescendantGeometryForLayerAndScrollParents(compositingAncestor, posZOrderList->at(i), visited, compositedChildrenOnly); |
} |
} |
} |
@@ -1771,22 +1855,26 @@ const char* RenderLayerCompositor::logReasonsForCompositing(const RenderLayer* l |
// according to the z-order hierarchy, yet clipping goes down the renderer hierarchy. |
// Thus, a RenderLayer can be clipped by a RenderLayer that is an ancestor in the renderer hierarchy, |
// but a sibling in the z-order hierarchy. |
-bool RenderLayerCompositor::clippedByAncestor(RenderLayer* layer) const |
+bool RenderLayerCompositor::clippedByAncestor(const RenderLayer* layer) const |
{ |
if (!layer->isComposited() || !layer->parent()) |
return false; |
- RenderLayer* compositingAncestor = layer->ancestorCompositingLayer(); |
+ // Scroll children use their scrolling ancestor as their clip root. |
+ RenderLayer* compositingAncestor = requiresCompositingForOverflowScrollingParent(layer) |
+ ? layer->ancestorScrollingLayer() |
+ : layer->ancestorCompositingLayer(); |
+ |
if (!compositingAncestor) |
return false; |
// If the compositingAncestor clips, that will be taken care of by clipsCompositingDescendants(), |
// so we only care about clipping between its first child that is our ancestor (the computeClipRoot), |
// and layer. |
- RenderLayer* computeClipRoot = 0; |
- RenderLayer* curr = layer; |
+ const RenderLayer* computeClipRoot = 0; |
+ const RenderLayer* curr = layer; |
while (curr) { |
- RenderLayer* next = curr->parent(); |
+ const RenderLayer* next = curr->parent(); |
if (next == compositingAncestor) { |
computeClipRoot = curr; |
break; |
@@ -1998,34 +2086,7 @@ bool RenderLayerCompositor::requiresCompositingForBlending(RenderObject* rendere |
bool RenderLayerCompositor::requiresCompositingForOverflowScrollingParent(const RenderLayer* layer) const |
{ |
- if (!layer->compositorDrivenAcceleratedScrollingEnabled()) |
- return false; |
- |
- // 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 |
- // layer as our 'scrolling ancestor'. |
- // |
- // Now, if we reside in a normal flow list, then we will naturally scroll with our scrolling |
- // ancestor, and we need not be composited. If, on the other hand, we reside in a z-order |
- // list, and on our walk upwards to our scrolling ancestor we find no layer that is a stacking |
- // context, then we know that in the stacking tree, we will not be in the subtree rooted at |
- // 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 = layer->ancestorScrollingLayer(); |
- |
- if (!scrollParent || scrollParent->isStackingContext()) |
- return false; |
- |
- // If we hit a stacking context on our way up to the ancestor scrolling layer, it will already |
- // be composited due to an overflow scrolling parent, so we don't need to. |
- for (RenderLayer* ancestor = layer->parent(); ancestor && ancestor != scrollParent; ancestor = ancestor->parent()) { |
- if (ancestor->isStackingContext()) |
- return false; |
- } |
- |
- return true; |
+ return !!layer->scrollParent(); |
} |
bool RenderLayerCompositor::requiresCompositingForOutOfFlowClipping(const RenderLayer* layer) const |