Bug 795674 - Remove mNewDisplayItemData. r=roc
authorMatt Woodrow <mwoodrow@mozilla.com>
Fri, 12 Oct 2012 15:39:46 +1300
changeset 110376 007e3dea2e5721281e39c51a89929f7f3175b603
parent 110375 ef2e2d80053960791db0fca47ed8deef4519cfe6
child 110377 84446077c7e22830d32bba63f390fbace49d702b
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
reviewersroc
bugs795674
milestone19.0a1
Bug 795674 - Remove mNewDisplayItemData. r=roc
layout/base/FrameLayerBuilder.cpp
layout/base/FrameLayerBuilder.h
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -34,115 +34,86 @@
 //#define DEBUG_DISPLAY_ITEM_DATA
 #endif
 
 using namespace mozilla::layers;
 using namespace mozilla::gfx;
 
 namespace mozilla {
 
-FrameLayerBuilder::DisplayItemData::DisplayItemData(LayerManagerData* aParent, nsIFrame* aFrame, uint32_t aKey, 
+FrameLayerBuilder::DisplayItemData::DisplayItemData(LayerManagerData* aParent, uint32_t aKey, 
                                                     Layer* aLayer, LayerState aLayerState, uint32_t aGeneration)
 
   : mParent(aParent)
   , mLayer(aLayer)
   , mDisplayItemKey(aKey)
   , mContainerLayerGeneration(aGeneration)
   , mLayerState(aLayerState)
-  , mUsed(false)
-  , mCopiedInto(nullptr)
+  , mUsed(true)
 {
-  AddFrame(aFrame);
 }
 
 FrameLayerBuilder::DisplayItemData::DisplayItemData(DisplayItemData &toCopy)
 {
   // This isn't actually a copy-constructor; notice that it steals toCopy's
   // mGeometry pointer.  Be careful.
   mParent = toCopy.mParent;
   mLayer = toCopy.mLayer;
   mInactiveManager = toCopy.mInactiveManager;
   mFrameList = toCopy.mFrameList;
   mGeometry = toCopy.mGeometry;
   mDisplayItemKey = toCopy.mDisplayItemKey;
   mClip = toCopy.mClip;
   mContainerLayerGeneration = toCopy.mContainerLayerGeneration;
   mLayerState = toCopy.mLayerState;
   mUsed = toCopy.mUsed;
-  mCopiedInto = toCopy.mCopiedInto;
+}
+
+void
+FrameLayerBuilder::DisplayItemData::AddFrame(nsIFrame* aFrame)
+{
+  mFrameList.AppendElement(aFrame);
+
+  nsTArray<DisplayItemData*> *array = 
+    reinterpret_cast<nsTArray<DisplayItemData*>*>(aFrame->Properties().Get(FrameLayerBuilder::LayerManagerDataProperty()));
+  if (!array) {
+    array = new nsTArray<DisplayItemData*>();
+    aFrame->Properties().Set(FrameLayerBuilder::LayerManagerDataProperty(), array);
+  }
+  array->AppendElement(this);
 }
 
 void
-FrameLayerBuilder::DisplayItemData::CopyInto(DisplayItemData* aOther)
+FrameLayerBuilder::DisplayItemData::UpdateContents(Layer* aLayer, LayerState aState, uint32_t aContainerLayerGeneration)
 {
-  if (mCopiedInto) {
-    NS_ASSERTION(mCopiedInto == aOther, "Can't copy a single DisplayItemData into multiple places!");
-    return;
-  }
-  NS_ABORT_IF_FALSE(mParent == aOther->mParent, "Must be a matching display item to copy!");
-  aOther->mLayer = mLayer;
-  aOther->mOptLayer = mOptLayer;
-  aOther->mInactiveManager = mInactiveManager;
-  NS_ABORT_IF_FALSE(mDisplayItemKey == aOther->mDisplayItemKey, "Must be a matching display item to copy!");
-  NS_ABORT_IF_FALSE(FrameListMatches(aOther), "Must be a matching display item to copy!");
-  mFrameList.Clear();
-  aOther->mGeometry = mGeometry;
-  aOther->mClip = mClip;
-  aOther->mLayerState = mLayerState;
-  aOther->mUsed = false;
-  mCopiedInto = aOther;
+  mLayer = aLayer;
+  mOptLayer = nullptr;
+  mInactiveManager = nullptr;
+  mLayerState = aState;
+  mContainerLayerGeneration = aContainerLayerGeneration;
+  mGeometry = nullptr;
+  mClip.mHaveClipRect = false;
+  mClip.mRoundedClipRects.Clear();
+  mUsed = true;
 }
 
-void
-FrameLayerBuilder::DisplayItemData::RemoveFrameData(nsIFrame* aSkip /* = nullptr */)
+static nsIFrame* sDestroyedFrame = NULL;
+FrameLayerBuilder::DisplayItemData::~DisplayItemData()
 {
   for (uint32_t i = 0; i < mFrameList.Length(); i++) {
     nsIFrame* frame = mFrameList[i];
-    if (frame == aSkip) {
+    if (frame == sDestroyedFrame) {
       continue;
     }
     nsTArray<DisplayItemData*> *array = 
       reinterpret_cast<nsTArray<DisplayItemData*>*>(frame->Properties().Get(LayerManagerDataProperty()));
     array->RemoveElement(this);
   }
 }
 
-static nsIFrame* sDestroyedFrame = NULL;
-FrameLayerBuilder::DisplayItemData::~DisplayItemData()
-{
-#ifdef DEBUG
-  /* TODO: Sanity check that we've removed our reference from all frames in mFrameList */
-  for (uint32_t i = 0; i < mFrameList.Length(); i++) {
-    if (mFrameList[i] == sDestroyedFrame) {
-      continue;
-    }
-    nsTArray<DisplayItemData*> *array = 
-      reinterpret_cast<nsTArray<DisplayItemData*>*>(mFrameList[i]->Properties().Get(LayerManagerDataProperty()));
-    if (!array) {
-      continue;
-    }
-
-    NS_ABORT_IF_FALSE(!array->Contains(this), "Must have removed ourselves from the frames!");
-  }
-#endif
-}
-
-bool
-FrameLayerBuilder::DisplayItemData::FrameListMatches(DisplayItemData* aOther)
-{
-  nsAutoTArray<nsIFrame*, 4> copy = mFrameList;
-  for (uint32_t i = 0; i < aOther->mFrameList.Length(); ++i) {
-    if (!copy.RemoveElement(aOther->mFrameList[i])) {
-      return false;
-    }
-  }
-
-  return copy.IsEmpty();
-}
-
 bool
 FrameLayerBuilder::DisplayItemData::FrameListMatches(nsDisplayItem* aOther)
 {
   nsAutoTArray<nsIFrame*, 4> copy = mFrameList;
   if (!copy.RemoveElement(aOther->GetUnderlyingFrame())) {
     return false;
   }
 
@@ -159,28 +130,26 @@ FrameLayerBuilder::DisplayItemData::Fram
 
 /**
  * This is the userdata we associate with a layer manager.
  */
 class LayerManagerData : public LayerUserData {
 public:
   LayerManagerData(LayerManager *aManager)
     : mLayerManager(aManager)
+#ifdef DEBUG_DISPLAY_ITEM_DATA
     , mParent(nullptr)
+#endif
     , mInvalidateAllLayers(false)
   {
     MOZ_COUNT_CTOR(LayerManagerData);
     mDisplayItems.Init();
   }
   ~LayerManagerData() {
     MOZ_COUNT_DTOR(LayerManagerData);
-    // Remove display item data properties now, since we won't be able
-    // to find these frames again without mFramesWithLayers.
-    mDisplayItems.EnumerateEntries(
-        FrameLayerBuilder::RemoveDisplayItemDataForFrame, nullptr);
   }
  
 #ifdef DEBUG_DISPLAY_ITEM_DATA
   void Dump(const char *aPrefix = "") {
     printf("%sLayerManagerData %p\n", aPrefix, this);
     nsAutoCString prefix;
     prefix += aPrefix;
     prefix += "  ";
@@ -188,17 +157,19 @@ public:
         FrameLayerBuilder::DumpDisplayItemDataForFrame, (void*)prefix.get());
   }
 #endif
 
   /**
    * Tracks which frames have layers associated with them.
    */
   LayerManager *mLayerManager;
+#ifdef DEBUG_DISPLAY_ITEM_DATA
   LayerManagerData *mParent;
+#endif
   nsTHashtable<nsRefPtrHashKey<FrameLayerBuilder::DisplayItemData> > mDisplayItems;
   bool mInvalidateAllLayers;
 };
 
 /* static */ void
 FrameLayerBuilder::DestroyDisplayItemDataFor(nsIFrame* aFrame)
 {
   FrameProperties props = aFrame->Properties();
@@ -842,17 +813,17 @@ GetTranslationForThebesLayer(ThebesLayer
  * Some frames can have multiple, nested, retaining layer managers
  * associated with them (normal manager, inactive managers, SVG effects).
  * In these cases we store the 'outermost' LayerManager data property
  * on the frame since we can walk down the chain from there.
  *
  * If one of these frames has just been destroyed, we will free the inner
  * layer manager when removing the entry from mFramesWithLayers. Destroying
  * the layer manager destroys the LayerManagerData and calls into 
- * RemoveDisplayItemDataForFrame. If the inner layer manager had any
+ * the DisplayItemData destructor. If the inner layer manager had any
  * items with the same frame, then we attempt to retrieve properties
  * from the deleted frame.
  *
  * Cache the destroyed frame pointer here so we can avoid crashing in this case.
  */
 
 /* static */ void
 FrameLayerBuilder::RemoveFrameFromLayerManager(nsIFrame* aFrame,
@@ -890,17 +861,16 @@ FrameLayerBuilder::RemoveFrameFromLayerM
       if (thebesData) {
         nsRegion old = data->mGeometry->ComputeInvalidationRegion();
         nsIntRegion rgn = old.ScaleToOutsidePixels(thebesData->mXScale, thebesData->mYScale, thebesData->mAppUnitsPerDevPixel);
         rgn.MoveBy(-GetTranslationForThebesLayer(t));
         thebesData->mRegionToInvalidate.Or(thebesData->mRegionToInvalidate, rgn);
       }
     }
 
-    data->RemoveFrameData(aFrame);
     data->mParent->mDisplayItems.RemoveEntry(data);
   }
 
   arrayCopy.Clear();
   delete array;
   sDestroyedFrame = NULL;
 }
 
@@ -914,24 +884,25 @@ FrameLayerBuilder::DidBeginRetainedLayer
     mInvalidateAllLayers = data->mInvalidateAllLayers;
   } else {
     data = new LayerManagerData(aManager);
     aManager->SetUserData(&gLayerManagerUserData, data);
   }
 }
 
 void
-FrameLayerBuilder::StoreOptimizedLayerForFrame(nsIFrame* aFrame, uint32_t aDisplayItemKey, Layer* aImage)
+FrameLayerBuilder::StoreOptimizedLayerForFrame(nsDisplayItem* aItem, Layer* aLayer)
 {
-  DisplayItemKey key(aFrame, aDisplayItemKey);
-  DisplayItemHashData *entry = mNewDisplayItemData.GetEntry(key);
-  if (!entry)
+  if (!mRetainingManager) {
     return;
-
-  entry->mData->mOptLayer = aImage;
+  }
+
+  DisplayItemData* data = GetDisplayItemDataForManager(aItem, aLayer->Manager());
+  NS_ASSERTION(data, "Must have already stored data for this item!");
+  data->mOptLayer = aLayer;
 }
 
 void
 FrameLayerBuilder::DidEndTransaction()
 {
   GetMaskLayerImageCache()->Sweep();
 }
 
@@ -942,22 +913,17 @@ FrameLayerBuilder::WillEndTransaction()
     return;
   }
 
   // We need to save the data we'll need to support retaining.
   LayerManagerData* data = static_cast<LayerManagerData*>
     (mRetainingManager->GetUserData(&gLayerManagerUserData));
   NS_ASSERTION(data, "Must have data!");
   // Update all the frames that used to have layers.
-  data->mDisplayItems.EnumerateEntries(UpdateDisplayItemDataForFrame, this);
-  
-  // Now go through all the frames that didn't have any retained
-  // display items before, and record those retained display items.
-  // This also empties mNewDisplayItemData.
-  mNewDisplayItemData.EnumerateEntries(StoreNewDisplayItemData, data);
+  data->mDisplayItems.EnumerateEntries(UpdateDisplayItemDataForFrame, nullptr);
   data->mInvalidateAllLayers = false;
 }
 
 struct ProcessRemovedDisplayItemsData
 {
   ProcessRemovedDisplayItemsData(Layer* aLayer, FrameLayerBuilder* aLayerBuilder)
     : mLayer(aLayer)
     , mLayerBuilder(aLayerBuilder)
@@ -992,55 +958,27 @@ FrameLayerBuilder::ProcessRemovedDisplay
   }
   return PL_DHASH_NEXT;
 }
 
 /* static */ PLDHashOperator
 FrameLayerBuilder::UpdateDisplayItemDataForFrame(nsRefPtrHashKey<DisplayItemData>* aEntry,
                                                  void* aUserArg)
 {
-  FrameLayerBuilder* builder = static_cast<FrameLayerBuilder*>(aUserArg);
   DisplayItemData* data = aEntry->GetKey();
-  DisplayItemKey key(data->mFrameList[0], data->mDisplayItemKey);
-
-  DisplayItemHashData* newDisplayItems =
-    builder ? builder->mNewDisplayItemData.GetEntry(key) : nullptr;
-
-  if (!newDisplayItems || !newDisplayItems->mData->FrameListMatches(data)) {
+  if (!data->mUsed) {
     // This item was visible, but isn't anymore.
-
-    // Go through all frames on the DisplayItemData, and then remove ourselves from that frame.
-    data->RemoveFrameData();
     return PL_DHASH_REMOVE;
   }
 
-  // Our frame(s) already have a pointer to the current DisplayItemData, so
-  // copy the contents of the new into it rather than replacing it.
-  newDisplayItems->mData->CopyInto(data);
-  // Don't need to process this frame again
-  builder->mNewDisplayItemData.RawRemoveEntry(newDisplayItems);
-  for (uint32_t i = 1; i < data->mFrameList.Length(); i++) {
-    key.mFrame = data->mFrameList[i];
-    builder->mNewDisplayItemData.RemoveEntry(key);
-  }
+  data->mUsed = false;
   return PL_DHASH_NEXT;
 }
   
 /* static */ PLDHashOperator 
-FrameLayerBuilder::RemoveDisplayItemDataForFrame(nsRefPtrHashKey<DisplayItemData>* aEntry,
-                                                 void* aClosure)
-{
-  DisplayItemData* data = aEntry->GetKey();
-  // If this was called from a frame destructor then the prop is definitely already gone,
-  // and we could crash trying to check. See the definition of sDestroyedFrame.
-  data->RemoveFrameData(sDestroyedFrame);
-  return PL_DHASH_REMOVE;
-}
-
-/* static */ PLDHashOperator 
 FrameLayerBuilder::DumpDisplayItemDataForFrame(nsRefPtrHashKey<DisplayItemData>* aEntry,
                                                void* aClosure)
 {
 #ifdef DEBUG_DISPLAY_ITEM_DATA
   DisplayItemData *data = aEntry->GetKey();
 
   nsAutoCString prefix;
   prefix += static_cast<const char*>(aClosure);
@@ -1086,36 +1024,16 @@ FrameLayerBuilder::DumpDisplayItemDataFo
     LayerManagerData* lmd = static_cast<LayerManagerData*>
       (data->mInactiveManager->GetUserData(&gLayerManagerUserData));
     lmd->Dump(prefix.get());
   }
 #endif
   return PL_DHASH_NEXT;
 }
 
-/* static */ PLDHashOperator
-FrameLayerBuilder::StoreNewDisplayItemData(DisplayItemHashData* aEntry,
-                                           void* aUserArg)
-{
-  LayerManagerData* data = static_cast<LayerManagerData*>(aUserArg);
-  const DisplayItemKey& key = aEntry->GetKey();
-
-  // Remember that this frame has display items in retained layers
-  data->mDisplayItems.PutEntry(aEntry->mData);
-
-  nsTArray<DisplayItemData*> *array = 
-    reinterpret_cast<nsTArray<DisplayItemData*>*>(key.mFrame->Properties().Get(LayerManagerDataProperty()));
-  if (!array) {
-    array = new nsTArray<DisplayItemData*>();
-    key.mFrame->Properties().Set(LayerManagerDataProperty(), array);
-  }
-  array->AppendElement(aEntry->mData);
-  return PL_DHASH_REMOVE;
-}
-
 /* static */ FrameLayerBuilder::DisplayItemData*
 FrameLayerBuilder::GetDisplayItemDataForManager(nsDisplayItem* aItem, 
                                                 LayerManager* aManager)
 {
   nsTArray<DisplayItemData*> *array = 
     reinterpret_cast<nsTArray<DisplayItemData*>*>(aItem->GetUnderlyingFrame()->Properties().Get(LayerManagerDataProperty()));
   if (array) {
     for (uint32_t i = 0; i < array->Length(); i++) {
@@ -1562,18 +1480,17 @@ ContainerState::PopThebesLayerData()
       imageLayer->SetPostScale(mParameters.mXScale,
                                mParameters.mYScale);
       if (data->mItemClip.mHaveClipRect) {
         nsIntRect clip = ScaleToNearestPixels(data->mItemClip.mClipRect);
         clip.MoveBy(mParameters.mOffset);
         imageLayer->IntersectClipRect(clip);
       }
       layer = imageLayer;
-      mLayerBuilder->StoreOptimizedLayerForFrame(data->mImage->GetUnderlyingFrame(), 
-                                                 data->mImage->GetPerFrameKey(),
+      mLayerBuilder->StoreOptimizedLayerForFrame(data->mImage,
                                                  imageLayer);
     } else {
       nsRefPtr<ColorLayer> colorLayer = CreateOrRecycleColorLayer(data->mLayer);
       colorLayer->SetIsFixedPosition(data->mLayer->GetIsFixedPosition());
       colorLayer->SetColor(data->mSolidColor);
 
       // Copy transform
       colorLayer->SetBaseTransform(data->mLayer->GetBaseTransform());
@@ -2065,32 +1982,39 @@ ContainerState::ProcessDisplayItems(cons
           layerState == LAYER_ACTIVE))) {
 
       // LAYER_ACTIVE_EMPTY means the layer is created just for its metadata.
       // We should never see an empty layer with any visible content!
       NS_ASSERTION(layerState != LAYER_ACTIVE_EMPTY ||
                    itemVisibleRect.IsEmpty(),
                    "State is LAYER_ACTIVE_EMPTY but visible rect is not.");
 
+      // As long as the new layer isn't going to be a ThebesLayer, 
+      // InvalidateForLayerChange doesn't need the new layer pointer.
+      // We also need to check the old data now, because BuildLayer
+      // can overwrite it.
+      InvalidateForLayerChange(item, nullptr, aClip, topLeft, geometry);
+
       // If the item would have its own layer but is invisible, just hide it.
       // Note that items without their own layers can't be skipped this
       // way, since their ThebesLayer may decide it wants to draw them
       // into its buffer even if they're currently covered.
       if (itemVisibleRect.IsEmpty() && layerState != LAYER_ACTIVE_EMPTY) {
-        InvalidateForLayerChange(item, nullptr, aClip, topLeft, geometry);
         continue;
       }
 
       // Just use its layer.
       nsRefPtr<Layer> ownLayer = item->BuildLayer(mBuilder, mManager, mParameters);
       if (!ownLayer) {
-        InvalidateForLayerChange(item, ownLayer, aClip, topLeft, geometry);
         continue;
       }
 
+      NS_ASSERTION(!ownLayer->AsThebesLayer(), 
+                   "Should never have created a dedicated Thebes layer!");
+
       nsRect invalid;
       if (item->IsInvalid(invalid)) {
         ownLayer->SetInvalidRectToVisibleRegion();
       }
 
       // If it's not a ContainerLayer, we need to apply the scale transform
       // ourselves.
       if (!ownLayer->AsContainerLayer()) {
@@ -2135,18 +2059,16 @@ ContainerState::ProcessDisplayItems(cons
 
       ContainerLayer* oldContainer = ownLayer->GetParent();
       if (oldContainer && oldContainer != mContainerLayer) {
         oldContainer->RemoveChild(ownLayer);
       }
       NS_ASSERTION(!mNewChildLayers.Contains(ownLayer),
                    "Layer already in list???");
 
-      InvalidateForLayerChange(item, ownLayer, aClip, topLeft, geometry);
-
       mNewChildLayers.AppendElement(ownLayer);
       mLayerBuilder->AddLayerDisplayItem(ownLayer, item, 
                                          aClip, layerState, 
                                          topLeft, nullptr,
                                          geometry);
     } else {
       ThebesLayerData* data =
         FindThebesLayerFor(item, itemVisibleRect, itemDrawRect, aClip,
@@ -2341,25 +2263,24 @@ FrameLayerBuilder::AddThebesDisplayItem(
         tempManager->EndTransaction(nullptr, nullptr);
         tempManager->SetUserData(&gLayerManagerLayerBuilder, nullptr);
         return;
       }
 
       // If BuildLayer didn't call BuildContainerLayerFor, then our new layer won't have been
       // stored in layerBuilder. Manually add it now.
       if (mRetainingManager) {
+#ifdef DEBUG_DISPLAY_ITEM_DATA
         LayerManagerData* parentLmd = static_cast<LayerManagerData*>
           (aLayer->Manager()->GetUserData(&gLayerManagerUserData));
         LayerManagerData* lmd = static_cast<LayerManagerData*>
           (tempManager->GetUserData(&gLayerManagerUserData));
         lmd->mParent = parentLmd;
-        nsRefPtr<DisplayItemData> data = 
-          new DisplayItemData(lmd, aItem->GetUnderlyingFrame(), aItem->GetPerFrameKey(), 
-                              layer, LAYER_ACTIVE, mContainerLayerGeneration);
-        layerBuilder->StoreDataForFrame(aItem, data);
+#endif
+        layerBuilder->StoreDataForFrame(aItem, layer, LAYER_ACTIVE);
       }
 
       tempManager->SetRoot(layer);
       layerBuilder->WillEndTransaction();
 
       nsIntPoint offset = GetLastPaintOffset(aLayer) - GetTranslationForThebesLayer(aLayer);
       props->MoveBy(-offset);
       nsIntRect invalid = props->ComputeDifferences(layer, nullptr);
@@ -2379,43 +2300,69 @@ FrameLayerBuilder::AddThebesDisplayItem(
     }
     ClippedDisplayItem* cdi =
       entry->mItems.AppendElement(ClippedDisplayItem(aItem, aClip,
                                                      mContainerLayerGeneration));
     cdi->mInactiveLayer = tempManager;
   }
 }
 
-void
-FrameLayerBuilder::StoreDataForFrame(nsDisplayItem* aItem, DisplayItemData* aData)
+FrameLayerBuilder::DisplayItemData*
+FrameLayerBuilder::StoreDataForFrame(nsDisplayItem* aItem, Layer* aLayer, LayerState aState)
 {
-  DisplayItemKey key(aItem->GetUnderlyingFrame(), aItem->GetPerFrameKey());
-  DisplayItemHashData *entry = mNewDisplayItemData.GetEntry(key);
-  if (entry) {
-    return;
-  }
-  entry = mNewDisplayItemData.PutEntry(key);
-  if (entry) {
-    entry->mData = aData;
-    entry->mContainerLayerGeneration = mContainerLayerGeneration;
+  DisplayItemData* oldData = GetDisplayItemDataForManager(aItem, mRetainingManager);
+  if (oldData) {
+    if (!oldData->mUsed) {
+      oldData->UpdateContents(aLayer, aState, mContainerLayerGeneration);
+    }
+    return oldData;
   }
   
+  LayerManagerData* lmd = static_cast<LayerManagerData*>
+    (mRetainingManager->GetUserData(&gLayerManagerUserData));
+  
+  nsRefPtr<DisplayItemData> data = 
+    new DisplayItemData(lmd, aItem->GetPerFrameKey(),
+                        aLayer, aState, mContainerLayerGeneration);
+
+  data->AddFrame(aItem->GetUnderlyingFrame());
+
   nsAutoTArray<nsIFrame*,4> mergedFrames;
   aItem->GetMergedFrames(&mergedFrames);
 
   for (uint32_t i = 0; i < mergedFrames.Length(); ++i) {
-    nsIFrame* mergedFrame = mergedFrames[i];
-    DisplayItemKey key(mergedFrame, aItem->GetPerFrameKey());
-    entry = mNewDisplayItemData.PutEntry(key);
-    if (entry) {
-      entry->mData = aData;
-      entry->mContainerLayerGeneration = mContainerLayerGeneration;
-      aData->AddFrame(mergedFrame);
-    }
+    data->AddFrame(mergedFrames[i]);
   }
+
+  lmd->mDisplayItems.PutEntry(data);
+  return data;
+}
+
+void
+FrameLayerBuilder::StoreDataForFrame(nsIFrame* aFrame,
+                                     uint32_t aDisplayItemKey,
+                                     Layer* aLayer,
+                                     LayerState aState)
+{
+  DisplayItemData* oldData = GetDisplayItemData(aFrame, aDisplayItemKey);
+  if (oldData && oldData->mFrameList.Length() == 1) {
+    oldData->UpdateContents(aLayer, aState, mContainerLayerGeneration);
+    return;
+  }
+  
+  LayerManagerData* lmd = static_cast<LayerManagerData*>
+    (mRetainingManager->GetUserData(&gLayerManagerUserData));
+
+  nsRefPtr<DisplayItemData> data =
+    new DisplayItemData(lmd, aDisplayItemKey, aLayer,
+                        aState, mContainerLayerGeneration);
+
+  data->AddFrame(aFrame);
+
+  lmd->mDisplayItems.PutEntry(data);
 }
 
 FrameLayerBuilder::ClippedDisplayItem::~ClippedDisplayItem()
 {
   if (mInactiveLayer) {
     // We always start a transaction during layer construction for all inactive
     // layers, but we don't necessarily call EndTransaction during painting.
     // If the transaaction is still open, end it to avoid assertions.
@@ -2434,35 +2381,23 @@ FrameLayerBuilder::AddLayerDisplayItem(L
                                        LayerState aLayerState,
                                        const nsPoint& aTopLeft,
                                        LayerManager* aManager,
                                        nsAutoPtr<nsDisplayItemGeometry> aGeometry)
 {
   if (aLayer->Manager() != mRetainingManager)
     return;
 
-  LayerManagerData* lmd = static_cast<LayerManagerData*>
-    (aLayer->Manager()->GetUserData(&gLayerManagerUserData));
-  nsRefPtr<DisplayItemData> data = 
-    new DisplayItemData(lmd, aItem->GetUnderlyingFrame(), aItem->GetPerFrameKey(), 
-                        aLayer, aLayerState, mContainerLayerGeneration);
-    
+  DisplayItemData *data = StoreDataForFrame(aItem, aLayer, aLayerState);
   ThebesLayer *t = aLayer->AsThebesLayer();
   if (t) {
     data->mGeometry = aGeometry;
     data->mClip = aClip;
   }
   data->mInactiveManager = aManager;
-
-  StoreDataForFrame(aItem, data);
-
-  DisplayItemData* oldData = GetDisplayItemDataForManager(aItem, mRetainingManager);
-  if (oldData) {
-    oldData->mUsed = true;
-  }
 }
 
 nsIntPoint
 FrameLayerBuilder::GetLastPaintOffset(ThebesLayer* aLayer)
 {
   ThebesLayerItemsEntry* entry = mThebesLayerItems.PutEntry(aLayer);
   if (entry) {
     if (entry->mContainerLayerGeneration == 0) {
@@ -2674,33 +2609,37 @@ ChooseScaleAndSetTransform(FrameLayerBui
   }
   if (isRetained && (!canDraw2D || transform2d.HasNonIntegerTranslation())) {
     result.mDisableSubpixelAntialiasingInDescendants = true;
   }
   return result;
 }
 
 /* static */ PLDHashOperator
-FrameLayerBuilder::RestoreDisplayItemData(DisplayItemHashData* aEntry, void* aUserArg)
+FrameLayerBuilder::RestoreDisplayItemData(nsRefPtrHashKey<DisplayItemData>* aEntry, void* aUserArg)
 {
+  DisplayItemData* data = aEntry->GetKey();
   uint32_t *generation = static_cast<uint32_t*>(aUserArg);
 
-  if (aEntry->mContainerLayerGeneration >= *generation) {
+  if (data->mUsed && data->mContainerLayerGeneration >= *generation) {
     return PL_DHASH_REMOVE;
   }
 
   return PL_DHASH_NEXT;
 }
 
 /* static */ PLDHashOperator
 FrameLayerBuilder::RestoreThebesLayerItemEntries(ThebesLayerItemsEntry* aEntry, void* aUserArg)
 {
   uint32_t *generation = static_cast<uint32_t*>(aUserArg);
 
   if (aEntry->mContainerLayerGeneration >= *generation) {
+    // We can just remove these items rather than attempting to revert them
+    // because we're going to want to invalidate everything when transitioning
+    // to component alpha flattening.
     return PL_DHASH_REMOVE;
   }
 
   for (uint32_t i = 0; i < aEntry->mItems.Length(); i++) {
     if (aEntry->mItems[i].mContainerLayerGeneration >= *generation) {
       aEntry->mItems.TruncateLength(i);
       return PL_DHASH_NEXT;
     }
@@ -2720,20 +2659,16 @@ FrameLayerBuilder::BuildContainerLayerFo
 {
   uint32_t containerDisplayItemKey =
     aContainerItem ? aContainerItem->GetPerFrameKey() : 0;
   NS_ASSERTION(aContainerFrame, "Container display items here should have a frame");
   NS_ASSERTION(!aContainerItem ||
                aContainerItem->GetUnderlyingFrame() == aContainerFrame,
                "Container display item must match given frame");
 
-  
-  LayerManagerData* data = static_cast<LayerManagerData*>
-    (aManager->GetUserData(&gLayerManagerUserData));
-
   nsRefPtr<ContainerLayer> containerLayer;
   if (aManager == mRetainingManager) {
     // Using GetOldLayerFor will search merged frames, as well as the underlying
     // frame. The underlying frame can change when a page scrolls, so this
     // avoids layer recreation in the situation that a new underlying frame is
     // picked for a layer.
     Layer* oldLayer = nullptr;
     if (aContainerItem) {
@@ -2783,42 +2718,25 @@ FrameLayerBuilder::BuildContainerLayerFo
     ChooseScaleAndSetTransform(this, aBuilder, aContainerFrame, aTransform, aParameters,
                                containerLayer, state);
 
   uint32_t oldGeneration = mContainerLayerGeneration;
   mContainerLayerGeneration = ++mMaxContainerLayerGeneration;
 
   nsRefPtr<RefCountedRegion> thebesLayerInvalidRegion = nullptr;
   if (mRetainingManager) {
-    nsRefPtr<DisplayItemData> did =
-      new DisplayItemData(data, aContainerFrame, containerDisplayItemKey, containerLayer,
-                          LAYER_ACTIVE, mContainerLayerGeneration);
-
-    DisplayItemKey key(aContainerFrame, containerDisplayItemKey);
-    DisplayItemHashData* entry = mNewDisplayItemData.PutEntry(key);
-    if (entry) {
-      entry->mData = did;
-      entry->mContainerLayerGeneration = mContainerLayerGeneration;
-    }
-  
-    nsAutoTArray<nsIFrame*,4> mergedFrames;
     if (aContainerItem) {
-      aContainerItem->GetMergedFrames(&mergedFrames);
-    }
-    for (uint32_t i = 0; i < mergedFrames.Length(); ++i) {
-      nsIFrame* mergedFrame = mergedFrames[i];
-      DisplayItemKey key(mergedFrame, containerDisplayItemKey);
-      DisplayItemHashData* mergedEntry = mNewDisplayItemData.PutEntry(key);
-      if (mergedEntry) {
-        mergedEntry->mData = did;
-        mergedEntry->mContainerLayerGeneration = mContainerLayerGeneration;
-        did->AddFrame(mergedFrame);
-      }
+      StoreDataForFrame(aContainerItem, containerLayer, LAYER_ACTIVE);
+    } else {
+      StoreDataForFrame(aContainerFrame, containerDisplayItemKey, containerLayer, LAYER_ACTIVE);
     }
   }
+  
+  LayerManagerData* data = static_cast<LayerManagerData*>
+    (aManager->GetUserData(&gLayerManagerUserData));
 
   nsRect bounds;
   nsIntRect pixBounds;
   int32_t appUnitsPerDevPixel;
   uint32_t stateFlags =
     (aContainerFrame->GetStateBits() & NS_FRAME_NO_COMPONENT_ALPHA) ?
       ContainerState::NO_COMPONENT_ALPHA : 0;
   uint32_t flags;
@@ -2842,17 +2760,17 @@ FrameLayerBuilder::BuildContainerLayerFo
         mRetainingManager &&
         !mRetainingManager->AreComponentAlphaLayersEnabled() &&
         !stateFlags) {
       // Since we don't want any component alpha layers on BasicLayers, we repeat
       // the layer building process with this explicitely forced off.
       // We restore the previous FrameLayerBuilder state since the first set
       // of layer building will have changed it.
       stateFlags = ContainerState::NO_COMPONENT_ALPHA;
-      mNewDisplayItemData.EnumerateEntries(RestoreDisplayItemData,
+      data->mDisplayItems.EnumerateEntries(RestoreDisplayItemData,
                                            &mContainerLayerGeneration);
       mThebesLayerItems.EnumerateEntries(RestoreThebesLayerItemEntries,
                                          &mContainerLayerGeneration);
       aContainerFrame->AddStateBits(NS_FRAME_NO_COMPONENT_ALPHA);
       continue;
     }
     break;
   }
@@ -2927,22 +2845,26 @@ FrameLayerBuilder::GetDedicatedLayer(nsI
   //TODO: This isn't completely correct, since a frame could exist as a layer
   // in the normal widget manager, and as a different layer (or no layer)
   // in the secondary manager
 
   nsTArray<DisplayItemData*> *array = 
     reinterpret_cast<nsTArray<DisplayItemData*>*>(aFrame->Properties().Get(LayerManagerDataProperty()));
   if (array) {
     for (uint32_t i = 0; i < array->Length(); i++) {
-      if (array->ElementAt(i)->mDisplayItemKey == aDisplayItemKey) {
-        if (array->ElementAt(i)->mOptLayer) {
-          return array->ElementAt(i)->mOptLayer;
+      DisplayItemData *element = array->ElementAt(i);
+      if (!element->mParent->mLayerManager->IsWidgetLayerManager()) {
+        continue;
+      }
+      if (element->mDisplayItemKey == aDisplayItemKey) {
+        if (element->mOptLayer) {
+          return element->mOptLayer;
         }
 
-        Layer* layer = array->ElementAt(i)->mLayer;
+        Layer* layer = element->mLayer;
         if (!layer->HasUserData(&gColorLayerUserData) &&
             !layer->HasUserData(&gImageLayerUserData) &&
             !layer->HasUserData(&gThebesDisplayItemLayerUserData)) {
           return layer;
         }
       }
     }
   }
--- a/layout/base/FrameLayerBuilder.h
+++ b/layout/base/FrameLayerBuilder.h
@@ -100,17 +100,16 @@ public:
   FrameLayerBuilder() :
     mRetainingManager(nullptr),
     mDetectedDOMModification(false),
     mInvalidateAllLayers(false),
     mContainerLayerGeneration(0),
     mMaxContainerLayerGeneration(0)
   {
     MOZ_COUNT_CTOR(FrameLayerBuilder);
-    mNewDisplayItemData.Init();
     mThebesLayerItems.Init();
   }
   ~FrameLayerBuilder()
   {
     MOZ_COUNT_DTOR(FrameLayerBuilder);
   }
 
   static void Shutdown();
@@ -357,17 +356,17 @@ public:
   static gfxSize GetThebesLayerScaleForFrame(nsIFrame* aFrame);
 
   /**
    * Stores a Layer as the dedicated layer in the DisplayItemData for a given frame/key pair.
    *
    * Used when we optimize a ThebesLayer into an ImageLayer and want to retroactively update the 
    * DisplayItemData so we can retrieve the layer from within layout.
    */
-  void StoreOptimizedLayerForFrame(nsIFrame* aFrame, uint32_t aDisplayItemKey, Layer* aImage);
+  void StoreOptimizedLayerForFrame(nsDisplayItem* aItem, Layer* aLayer);
 
   /**
    * Clip represents the intersection of an optional rectangle with a
    * list of rounded rectangles.
    */
   struct Clip {
     struct RoundedRect {
       nsRect mRect;
@@ -462,139 +461,72 @@ public:
 
 protected:
   /**
    * Retained data storage:
    *
    * Each layer manager (widget, and inactive) stores a LayerManagerData object
    * that keeps a hash-set of DisplayItemData items that were drawn into it.
    * Each frame also keeps a list of DisplayItemData pointers that were
-   * created for that frame.
-   *
-   * During layer construction we build a hashtable of DisplayItemHashData items, keyed
-   * using (frame,display item key). Since some display items can be associated with multiple
-   * frames (because of merging), multiple entries in this hashtable can refer to the same
-   * DisplayItemData.
+   * created for that frame. DisplayItemData objects manage these lists automatically.
    *
-   * Once layer building is complete, we sync the new items into the retained storage and update
-   * any frames that have changed lists.
-   */
-
-  /**
-   * nsIFrame/display item 'per frame key' pair used to key  our hashtable of DisplayItemHashData items.
+   * During layer construction we update the data in the LayerManagerData object, marking
+   * items that are modified. At the end we sweep the LayerManagerData hash-set and remove
+   * all items that haven't been modified.
    */
-  class DisplayItemKey {
-  public:
-    DisplayItemKey(nsIFrame* aFrame, uint32_t aKey)
-      : mFrame(aFrame)
-      , mKey(aKey)
-    { }
-
-    bool operator==(const DisplayItemKey& aOther) const {
-      return mFrame == aOther.mFrame &&
-             mKey == aOther.mKey;
-    }
-
-    nsIFrame* mFrame;
-    uint32_t mKey;
-  };
 
   /**
    * Retained data for a display item.
    */
   class DisplayItemData {
   public:
 
-    DisplayItemData(LayerManagerData* aParent, nsIFrame* aFrame, uint32_t aKey, Layer* aLayer, LayerState aLayerState, uint32_t aGeneration);
+    DisplayItemData(LayerManagerData* aParent, uint32_t aKey, Layer* aLayer, LayerState aLayerState, uint32_t aGeneration);
     DisplayItemData(DisplayItemData &toCopy);
+
+    /**
+     * Removes any references to this object from frames
+     * in mFrameList.
+     */
     ~DisplayItemData();
 
     NS_INLINE_DECL_REFCOUNTING(DisplayItemData)
 
-    void AddFrame(nsIFrame* aFrame)
-    {
-      mFrameList.AppendElement(aFrame);
-    }
-
-    /** 
-     * Check for this item stored under the LayerManagerDataProperty
-     * for every frame in mFrameList and remove it.
-     * Optionally skips aSkip
+    /**
+     * Associates this DisplayItemData with a frame, and adds it
+     * to the LayerManagerDataProperty list on the frame.
      */
-    void RemoveFrameData(nsIFrame* aSkip = nullptr);
-
+    void AddFrame(nsIFrame* aFrame);
     bool FrameListMatches(nsDisplayItem* aOther);
-    bool FrameListMatches(DisplayItemData* aOther);
 
     /**
-     * Copies the contents of this item into aDest and
-     * leaves this item invalid.
+     * Updates the contents of this item to a new set of data, instead of allocating a new
+     * object.
+     * Set the passed in parameters, and clears the opt layer, inactive manager, geometry
+     * and clip.
+     * Parent, frame list and display item key are assumed to be the same.
      */
-    void CopyInto(DisplayItemData* aDest);
+    void UpdateContents(Layer* aLayer, LayerState aState, uint32_t aContainerLayerGeneration);
 
     LayerManagerData* mParent;
     nsRefPtr<Layer> mLayer;
     nsRefPtr<Layer> mOptLayer;
     nsRefPtr<LayerManager> mInactiveManager;
     nsAutoTArray<nsIFrame*, 1> mFrameList;
     nsAutoPtr<nsDisplayItemGeometry> mGeometry;
     Clip            mClip;
     uint32_t        mDisplayItemKey;
     uint32_t        mContainerLayerGeneration;
     LayerState      mLayerState;
 
     /**
      * Used to track if data currently stored in mFramesWithLayers (from an existing
-     * paint) is also used in the current paint and has an equivalent data object
-     * in mNewDisplayItemData.
+     * paint) has been updated in the current paint.
      */
     bool            mUsed;
-    DisplayItemData *mCopiedInto;
-  };
-
-  /**
-   * Hashtable entry wrapping a DisplayItemData.
-   * 
-   * Implemented as a separate class so that we can have multiple entries
-   * for a single DisplayItemData (in the case of merged display items).
-   */
-  class DisplayItemHashData : public PLDHashEntryHdr {
-  public:
-    typedef const DisplayItemKey& KeyType;
-    typedef const DisplayItemKey* KeyTypePointer;
-
-    DisplayItemHashData(KeyTypePointer aKey)
-      : mKey(*aKey)
-      , mContainerLayerGeneration(0)
-    { }
-    DisplayItemHashData(DisplayItemHashData &toCopy)
-      : mKey(toCopy.mKey)
-      , mData(toCopy.mData)
-      , mContainerLayerGeneration(toCopy.mContainerLayerGeneration)
-    { 
-      toCopy.mData = nullptr;
-    }
-
-    KeyType GetKey() const { 
-      return mKey; 
-    }
-    bool KeyEquals(KeyTypePointer aKey) const { 
-      return *aKey == mKey; 
-    }
-    static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; }
-
-    static PLDHashNumber HashKey(const KeyTypePointer aKey) {
-      return mozilla::HashGeneric(aKey->mFrame, aKey->mKey);
-    }
-                                       
-    enum { ALLOW_MEMMOVE = false };
-
-    DisplayItemKey mKey;
-    nsRefPtr<DisplayItemData> mData;
-    uint32_t mContainerLayerGeneration;
   };
 
   friend class LayerManagerData;
 
   static void RemoveFrameFromLayerManager(nsIFrame* aFrame, void* aPropertyValue);
 
   /**
    * Given a frame and a display item key that uniquely identifies a
@@ -604,17 +536,21 @@ protected:
    * that renders many display items.
    */
   DisplayItemData* GetOldLayerForFrame(nsIFrame* aFrame, uint32_t aDisplayItemKey);
 
   /**
    * Stores DisplayItemData associated with aFrame, stores the data in
    * mNewDisplayItemData.
    */
-  void StoreDataForFrame(nsDisplayItem* aItem, DisplayItemData* data);
+  DisplayItemData* StoreDataForFrame(nsDisplayItem* aItem, Layer* aLayer, LayerState aState);
+  void StoreDataForFrame(nsIFrame* aFrame,
+                         uint32_t aDisplayItemKey,
+                         Layer* aLayer,
+                         LayerState aState);
 
   // Flash the area within the context clip if paint flashing is enabled.
   static void FlashPaint(gfxContext *aContext);
 
   /*
    * Get the DisplayItemData array associated with this frame, or null if one
    * doesn't exist.
    *
@@ -632,24 +568,16 @@ protected:
                                                        LayerManager* aManager);
   static DisplayItemData* GetDisplayItemDataForManager(nsIFrame* aFrame, 
                                                        uint32_t aDisplayItemKey);
   static DisplayItemData* GetDisplayItemDataForManager(nsDisplayItem* aItem, LayerManager* aManager);
   static DisplayItemData* GetDisplayItemDataForManager(nsIFrame* aFrame, 
                                                        uint32_t aDisplayItemKey, 
                                                        LayerManagerData* aData);
 
-  /**
-   * A useful hashtable iteration function that removes the
-   * DisplayItemData property for the frame and returns PL_DHASH_REMOVE.
-   * aClosure is ignored.
-   */
-  static PLDHashOperator RemoveDisplayItemDataForFrame(nsRefPtrHashKey<DisplayItemData>* aEntry,
-                                                       void* aClosure);
-
   static PLDHashOperator DumpDisplayItemDataForFrame(nsRefPtrHashKey<DisplayItemData>* aEntry,
                                                      void* aClosure);
   /**
    * We store one of these for each display item associated with a
    * ThebesLayer, in a hashtable that maps each ThebesLayer to an array
    * of ClippedDisplayItems. (ThebesLayerItemsEntry is the hash entry
    * for that hashtable.)
    * These are only stored during the paint process, so that the
@@ -724,19 +652,17 @@ public:
                                                     void* aUserArg);
 protected:
   void RemoveThebesItemsAndOwnerDataForLayerSubtree(Layer* aLayer,
                                                     bool aRemoveThebesItems,
                                                     bool aRemoveOwnerData);
 
   static PLDHashOperator UpdateDisplayItemDataForFrame(nsRefPtrHashKey<DisplayItemData>* aEntry,
                                                        void* aUserArg);
-  static PLDHashOperator StoreNewDisplayItemData(DisplayItemHashData* aEntry,
-                                                 void* aUserArg);
-  static PLDHashOperator RestoreDisplayItemData(DisplayItemHashData* aEntry,
+  static PLDHashOperator RestoreDisplayItemData(nsRefPtrHashKey<DisplayItemData>* aEntry,
                                                 void *aUserArg);
 
   static PLDHashOperator RestoreThebesLayerItemEntries(ThebesLayerItemsEntry* aEntry,
                                                        void *aUserArg);
 
   /**
    * Returns true if the DOM has been modified since we started painting,
    * in which case we should bail out and not paint anymore. This should
@@ -754,21 +680,16 @@ protected:
    */
   nsRefPtr<nsRootPresContext>         mRootPresContext;
 
   /**
    * The display list builder being used.
    */
   nsDisplayListBuilder*               mDisplayListBuilder;
   /**
-   * A map from frames to a list of (display item key, layer) pairs that
-   * describes what layers various parts of the frame are assigned to.
-   */
-  nsTHashtable<DisplayItemHashData>  mNewDisplayItemData;
-  /**
    * A map from ThebesLayers to the list of display items (plus
    * clipping data) to be rendered in the layer.
    */
   nsTHashtable<ThebesLayerItemsEntry> mThebesLayerItems;
   /**
    * Saved generation counter so we can detect DOM changes.
    */
   uint32_t                            mInitialDOMGeneration;