Bug 785333 - Store container layers against merged frames. r=roc
authorChris Lord <chrislord.net@gmail.com>
Wed, 29 Aug 2012 11:53:20 +0100
changeset 105790 7d39a94c966a8e282dd053a9be27c78748215c8b
parent 105789 2466826796a95cc6ca0a4e07e6b4d8bd92cc8c58
child 105791 d1ab93cb1541f77af5e62aab6f3eb65a0e39db82
push id55
push usershu@rfrn.org
push dateThu, 30 Aug 2012 01:33:09 +0000
reviewersroc
bugs785333
milestone18.0a1
Bug 785333 - Store container layers against merged frames. r=roc As well as storing the container layer against the underlying frame of the container item, store it against its merged frames as well. In addition, check for old container layers against merged frames when building a container layer. This protects against losing the layer when the underlying frame of a container item changes to either a new frame or an existing, merged frame.
layout/base/FrameLayerBuilder.cpp
layout/base/nsDisplayList.cpp
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -2278,16 +2278,32 @@ FrameLayerBuilder::BuildContainerLayerFo
   NS_ASSERTION(aContainerFrame, "Container display items here should have a frame");
   NS_ASSERTION(!aContainerItem ||
                aContainerItem->GetUnderlyingFrame() == aContainerFrame,
                "Container display item must match given frame");
 
   nsRefPtr<ContainerLayer> containerLayer;
   if (aManager == mRetainingManager) {
     Layer* oldLayer = GetOldLayerFor(aContainerFrame, containerDisplayItemKey);
+
+    // If a layer isn't found, see if we can find one for a merged frame. The
+    // underlying frame can change when a page scrolls, this avoids layer
+    // recreation in the situation that a new underlying frame is picked for
+    // a layer.
+    if (!oldLayer && aContainerItem) {
+      nsAutoTArray<nsIFrame*,4> mergedFrames;
+      aContainerItem->GetMergedFrames(&mergedFrames);
+      for (uint32_t i = 0; i < mergedFrames.Length(); ++i) {
+        oldLayer = GetOldLayerFor(mergedFrames[i], containerDisplayItemKey);
+        if (oldLayer) {
+          break;
+        }
+      }
+    }
+
     if (oldLayer) {
       NS_ASSERTION(oldLayer->Manager() == aManager, "Wrong manager");
       if (oldLayer->HasUserData(&gThebesDisplayItemLayerUserData)) {
         // The old layer for this item is actually our ThebesLayer
         // because we rendered its layer into that ThebesLayer. So we
         // don't actually have a retained container layer.
       } else {
         NS_ASSERTION(oldLayer->GetType() == Layer::TYPE_CONTAINER,
@@ -2371,16 +2387,23 @@ FrameLayerBuilder::BuildContainerLayerFo
       nsAutoTArray<nsIFrame*,4> mergedFrames;
       if (aContainerItem) {
         aContainerItem->GetMergedFrames(&mergedFrames);
       }
       for (uint32_t i = 0; i < mergedFrames.Length(); ++i) {
         nsIFrame* mergedFrame = mergedFrames[i];
         DisplayItemDataEntry* entry = mNewDisplayItemData.PutEntry(mergedFrame);
         if (entry) {
+          // Append the container layer so we don't regenerate layers when
+          // the underlying frame of an item changes to one of the existing
+          // merged frames.
+          entry->mData.AppendElement(
+              DisplayItemData(containerLayer, containerDisplayItemKey,
+                              LAYER_ACTIVE, mContainerLayerGeneration));
+
           // Ensure that UpdateDisplayItemDataForFrame recognizes that we
           // still have a container layer associated with this frame.
           entry->mIsSharingContainerLayer = true;
 
           // Store the invalid region property in case this frame is represented
           // by multiple container layers. This is cleared and set when iterating
           // over the DisplayItemDataEntry's in WillEndTransaction.
           entry->mInvalidRegion = thebesLayerInvalidRegion;
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -2687,24 +2687,16 @@ nsDisplayScrollLayer::TryMerge(nsDisplay
   if (other->mScrolledFrame != this->mScrolledFrame) {
     return false;
   }
 
   FrameProperties props = mScrolledFrame->Properties();
   props.Set(nsIFrame::ScrollLayerCount(),
     reinterpret_cast<void*>(GetScrollLayerCount() - 1));
 
-  // Swap frames with the other item before doing MergeFrom.
-  // XXX - This ensures that the frame associated with a scroll layer after
-  // merging is the first, rather than the last. This tends to change less,
-  // ensuring we're more likely to retain the associated gfx layer.
-  // See Bug 729534 and Bug 731641.
-  nsIFrame* tmp = mFrame;
-  mFrame = other->mFrame;
-  other->mFrame = tmp;
   MergeFromTrackingMergedFrames(other);
   return true;
 }
 
 bool
 nsDisplayScrollLayer::ShouldFlattenAway(nsDisplayListBuilder* aBuilder)
 {
   return GetScrollLayerCount() > 1;