Bug 795674 - Handled merged frame changes with minimal invalidations. r=roc
authorMatt Woodrow <mwoodrow@mozilla.com>
Tue, 16 Oct 2012 14:23:07 +1300
changeset 110603 b6cd3108731bbd8b94ef4386332aa2f3729db237
parent 110602 5013505b39301834fb3180b71d742bea30234152
child 110604 000af356f5255eaeb507f50e98dd112faa9aa6b5
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
reviewersroc
bugs795674
milestone19.0a1
Bug 795674 - Handled merged frame changes with minimal invalidations. r=roc
layout/base/FrameLayerBuilder.cpp
layout/base/FrameLayerBuilder.h
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -77,60 +77,97 @@ FrameLayerBuilder::DisplayItemData::AddF
   if (!array) {
     array = new nsTArray<DisplayItemData*>();
     aFrame->Properties().Set(FrameLayerBuilder::LayerManagerDataProperty(), array);
   }
   array->AppendElement(this);
 }
 
 void
-FrameLayerBuilder::DisplayItemData::UpdateContents(Layer* aLayer, LayerState aState, uint32_t aContainerLayerGeneration)
+FrameLayerBuilder::DisplayItemData::RemoveFrame(nsIFrame* aFrame)
+{
+  DebugOnly<bool> result = mFrameList.RemoveElement(aFrame);
+  NS_ASSERTION(result, "Can't remove a frame that wasn't added!");
+
+  nsTArray<DisplayItemData*> *array = 
+    reinterpret_cast<nsTArray<DisplayItemData*>*>(aFrame->Properties().Get(FrameLayerBuilder::LayerManagerDataProperty()));
+  NS_ASSERTION(array, "Must be already stored on the frame!");
+  array->RemoveElement(this);
+}
+
+void
+FrameLayerBuilder::DisplayItemData::UpdateContents(Layer* aLayer, LayerState aState, 
+                                                   uint32_t aContainerLayerGeneration,
+                                                   nsDisplayItem* aItem /* = nullptr */)
 {
   mLayer = aLayer;
   mOptLayer = nullptr;
   mInactiveManager = nullptr;
   mLayerState = aState;
   mContainerLayerGeneration = aContainerLayerGeneration;
   mGeometry = nullptr;
   mClip.mHaveClipRect = false;
   mClip.mRoundedClipRects.Clear();
   mUsed = true;
+
+  if (!aItem) {
+    return;
+  }
+
+  nsAutoTArray<nsIFrame*, 4> copy = mFrameList;
+  if (!copy.RemoveElement(aItem->GetUnderlyingFrame())) {
+    AddFrame(aItem->GetUnderlyingFrame());
+  }
+
+  nsAutoTArray<nsIFrame*,4> mergedFrames;
+  aItem->GetMergedFrames(&mergedFrames);
+  for (uint32_t i = 0; i < mergedFrames.Length(); ++i) {
+    if (!copy.RemoveElement(mergedFrames[i])) {
+      AddFrame(mergedFrames[i]);
+    }
+  }
+
+  for (uint32_t i = 0; i < copy.Length(); i++) {
+    RemoveFrame(copy[i]); 
+  }
 }
 
 static nsIFrame* sDestroyedFrame = NULL;
 FrameLayerBuilder::DisplayItemData::~DisplayItemData()
 {
   for (uint32_t i = 0; i < mFrameList.Length(); i++) {
     nsIFrame* frame = mFrameList[i];
     if (frame == sDestroyedFrame) {
       continue;
     }
     nsTArray<DisplayItemData*> *array = 
       reinterpret_cast<nsTArray<DisplayItemData*>*>(frame->Properties().Get(LayerManagerDataProperty()));
     array->RemoveElement(this);
   }
 }
 
-bool
-FrameLayerBuilder::DisplayItemData::FrameListMatches(nsDisplayItem* aOther)
+void
+FrameLayerBuilder::DisplayItemData::GetFrameListChanges(nsDisplayItem* aOther, 
+                                                        nsTArray<nsIFrame*>& aOut)
 {
-  nsAutoTArray<nsIFrame*, 4> copy = mFrameList;
-  if (!copy.RemoveElement(aOther->GetUnderlyingFrame())) {
-    return false;
+  aOut = mFrameList;
+  nsAutoTArray<nsIFrame*, 4> added;
+  if (!aOut.RemoveElement(aOther->GetUnderlyingFrame())) {
+    added.AppendElement(aOther->GetUnderlyingFrame());
   }
 
   nsAutoTArray<nsIFrame*,4> mergedFrames;
   aOther->GetMergedFrames(&mergedFrames);
   for (uint32_t i = 0; i < mergedFrames.Length(); ++i) {
-    if (!copy.RemoveElement(mergedFrames[i])) {
-      return false;
+    if (!aOut.RemoveElement(mergedFrames[i])) {
+      added.AppendElement(mergedFrames[i]);
     }
   }
 
-  return copy.IsEmpty();
+  aOut.AppendElements(added); 
 }
 
 /**
  * This is the userdata we associate with a layer manager.
  */
 class LayerManagerData : public LayerUserData {
 public:
   LayerManagerData(LayerManager *aManager)
@@ -1047,18 +1084,17 @@ FrameLayerBuilder::GetDisplayItemDataFor
                                                 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++) {
       DisplayItemData* item = array->ElementAt(i);
       if (item->mDisplayItemKey == aItem->GetPerFrameKey() &&
-          item->mLayer->Manager() == aManager &&
-          item->FrameListMatches(aItem)) {
+          item->mLayer->Manager() == aManager) {
         return item;
       }
     }
   }
   return nullptr;
 }
 
 bool
@@ -1088,30 +1124,36 @@ FrameLayerBuilder::GetOldLayerForFrame(n
 
   if (data && data->mLayer->Manager() == mRetainingManager) {
     return data;
   }
   return nullptr;
 }
 
 Layer*
-FrameLayerBuilder::GetOldLayerFor(nsDisplayItem* aItem, nsDisplayItemGeometry** aOldGeometry, Clip** aOldClip)
+FrameLayerBuilder::GetOldLayerFor(nsDisplayItem* aItem, 
+                                  nsDisplayItemGeometry** aOldGeometry, 
+                                  Clip** aOldClip,
+                                  nsTArray<nsIFrame*>* aChangedFrames)
 {
   uint32_t key = aItem->GetPerFrameKey();
   nsIFrame* frame = aItem->GetUnderlyingFrame();
 
   if (frame) {
     DisplayItemData* oldData = GetOldLayerForFrame(frame, key);
-    if (oldData && oldData->FrameListMatches(aItem)) {
+    if (oldData) {
       if (aOldGeometry) {
         *aOldGeometry = oldData->mGeometry.get();
       }
       if (aOldClip) {
         *aOldClip = &oldData->mClip;
       }
+      if (aChangedFrames) {
+        oldData->GetFrameListChanges(aItem, *aChangedFrames); 
+      }
       return oldData->mLayer;
     }
   }
 
   return nullptr;
 } 
 
 /* static */ Layer*
@@ -2143,17 +2185,18 @@ ContainerState::InvalidateForLayerChange
                                          nsDisplayItemGeometry *aGeometry)
 {
   NS_ASSERTION(aItem->GetUnderlyingFrame(),
                "Display items that render using Thebes must have a frame");
   NS_ASSERTION(aItem->GetPerFrameKey(),
                "Display items that render using Thebes must have a key");
   nsDisplayItemGeometry *oldGeometry = NULL;
   FrameLayerBuilder::Clip* oldClip = NULL;
-  Layer* oldLayer = mLayerBuilder->GetOldLayerFor(aItem, &oldGeometry, &oldClip);
+  nsAutoTArray<nsIFrame*,4> changedFrames;
+  Layer* oldLayer = mLayerBuilder->GetOldLayerFor(aItem, &oldGeometry, &oldClip, &changedFrames);
   if (aNewLayer != oldLayer && oldLayer) {
     // The item has changed layers.
     // Invalidate the old bounds in the old layer and new bounds in the new layer.
     ThebesLayer* t = oldLayer->AsThebesLayer();
     if (t) {
       // Note that whenever the layer's scale changes, we invalidate the whole thing,
       // so it doesn't matter whether we are using the old scale at last paint
       // or a new scale here
@@ -2214,16 +2257,20 @@ ContainerState::InvalidateForLayerChange
     oldGeometry->MoveBy(shift);
     aItem->ComputeInvalidationRegion(mBuilder, oldGeometry, &combined);
     oldClip->AddOffsetAndComputeDifference(shift, oldGeometry->ComputeInvalidationRegion(),
                                            aClip, aGeometry->ComputeInvalidationRegion(),
                                            &combined);
 
     // Add in any rect that the frame specified
     combined.Or(combined, invalid);
+ 
+    for (uint32_t i = 0; i < changedFrames.Length(); i++) {
+      combined.Or(combined, changedFrames[i]->GetVisualOverflowRect());
+    } 
 
     // Restrict invalidation to the clipped region
     nsRegion clip;
     if (ComputeCombinedClip(aClip, oldClip, shift, clip)) {
       combined.And(combined, clip);
     }
 #ifdef DEBUG_INVALIDATIONS
     if (!combined.IsEmpty()) {
--- a/layout/base/FrameLayerBuilder.h
+++ b/layout/base/FrameLayerBuilder.h
@@ -292,17 +292,20 @@ public:
    */
   static const FramePropertyDescriptor* GetDescriptorForManager(LayerManager* aManager);
 
   /**
    * Calls GetOldLayerForFrame on the underlying frame of the display item,
    * and each subsequent merged frame if no layer is found for the underlying
    * frame.
    */
-  Layer* GetOldLayerFor(nsDisplayItem* aItem, nsDisplayItemGeometry** aOldGeometry = nullptr, Clip** aOldClip = nullptr);
+  Layer* GetOldLayerFor(nsDisplayItem* aItem, 
+                        nsDisplayItemGeometry** aOldGeometry = nullptr, 
+                        Clip** aOldClip = nullptr,
+                        nsTArray<nsIFrame*>* aChangedFrames = nullptr);
 
   static Layer* GetDebugOldLayerFor(nsIFrame* aFrame, uint32_t aDisplayItemKey);
 
   /**
    * Try to determine whether the ThebesLayer aLayer paints an opaque
    * single color everywhere it's visible in aRect.
    * If successful, return that color, otherwise return NS_RGBA(0,0,0,0).
    */
@@ -494,26 +497,28 @@ protected:
 
     NS_INLINE_DECL_REFCOUNTING(DisplayItemData)
 
     /**
      * Associates this DisplayItemData with a frame, and adds it
      * to the LayerManagerDataProperty list on the frame.
      */
     void AddFrame(nsIFrame* aFrame);
-    bool FrameListMatches(nsDisplayItem* aOther);
+    void RemoveFrame(nsIFrame* aFrame);
+    void GetFrameListChanges(nsDisplayItem* aOther, nsTArray<nsIFrame*>& aOut);
 
     /**
      * 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 UpdateContents(Layer* aLayer, LayerState aState, uint32_t aContainerLayerGeneration);
+    void UpdateContents(Layer* aLayer, LayerState aState,
+                        uint32_t aContainerLayerGeneration, nsDisplayItem* aItem = nullptr);
 
     LayerManagerData* mParent;
     nsRefPtr<Layer> mLayer;
     nsRefPtr<Layer> mOptLayer;
     nsRefPtr<LayerManager> mInactiveManager;
     nsAutoTArray<nsIFrame*, 1> mFrameList;
     nsAutoPtr<nsDisplayItemGeometry> mGeometry;
     Clip            mClip;