Chromium Code Reviews| Index: Source/core/rendering/RenderLayerCompositor.cpp |
| diff --git a/Source/core/rendering/RenderLayerCompositor.cpp b/Source/core/rendering/RenderLayerCompositor.cpp |
| index e7b5a0f21a3d37333f34d10368c69e0914d43ea4..ae4e5150e2a46ea18e362a4119b80a968cb01529 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,44 @@ 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. Unfortunately, |
|
enne (OOO)
2013/09/10 23:45:01
I understand why you need HashSet visited for upda
Ian Vollick
2013/09/11 17:57:52
There are two recursive functions in the RLC which
enne (OOO)
2013/09/11 23:18:30
Sad times. I missed that they both call updateGra
|
| +// 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 +1100,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 +1144,30 @@ void RenderLayerCompositor::rebuildCompositingLayerTree(RenderLayer* layer, Vect |
| LayerListMutationDetector mutationChecker(layer); |
| #endif |
| + // Visit the normal flow descendants first. We do this for the sake of scroll |
| + // parents. A scroll parent is not a stacking context, so it will either appear |
| + // in the normal flow tree, or in the positive z-order list (if it had a positioned |
| + // ancestor). Visiting the scroll parent ahead of time if it appears in one |
| + // of these lists is a simple matter since we have the lists in hand at this |
| + // level of the recursion, but it's tricker for layers in the normal flow tree, |
| + // so it will be easier to just process this ahead of time. |
| + Vector<GraphicsLayer*> normalFlowChildList; |
| + |
| + if (Vector<RenderLayer*>* normalFlowList = layer->normalFlowList()) { |
| + size_t listSize = normalFlowList->size(); |
| + for (size_t i = 0; i < listSize; ++i) { |
| + RenderLayer* curLayer = normalFlowList->at(i); |
| + rebuildCompositingLayerTree(curLayer, normalFlowChildList, visited, depth + 1); |
| + } |
| + } |
| + |
| + 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); |
| } |
| } |
| @@ -1117,20 +1176,14 @@ void RenderLayerCompositor::rebuildCompositingLayerTree(RenderLayer* layer, Vect |
| childList.append(layerBacking->foregroundLayer()); |
| } |
| - if (Vector<RenderLayer*>* normalFlowList = layer->normalFlowList()) { |
| - size_t listSize = normalFlowList->size(); |
| - for (size_t i = 0; i < listSize; ++i) { |
| - RenderLayer* curLayer = normalFlowList->at(i); |
| - rebuildCompositingLayerTree(curLayer, childList, depth + 1); |
| - } |
| - } |
| + childList.append(normalFlowChildList); |
| if (layer->isStackingContainer()) { |
| if (Vector<RenderLayer*>* posZOrderList = layer->posZOrderList()) { |
| 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); |
| } |
| } |
| } |
| @@ -1311,9 +1364,28 @@ 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. |
| @@ -1341,25 +1413,25 @@ 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); |
| } |
| } |
| } |
| @@ -1750,22 +1822,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; |
| @@ -1977,34 +2053,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 |