Bug 728983. Part 1: Add nsDisplayItem::GetMergedFrames. r=mattwoodrow
authorRobert O'Callahan <robert@ocallahan.org>
Tue, 17 Apr 2012 17:44:32 +1200
changeset 91824 9157e2b139132e3325c4089ed9107364999ceacd
parent 91823 2745411f4bb99b58673b8cbc9bcde66fd25fc162
child 91825 6dbdb799fa6dd7161a05e1712e36c426bd192f5b
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersmattwoodrow
bugs728983
milestone14.0a1
Bug 728983. Part 1: Add nsDisplayItem::GetMergedFrames. r=mattwoodrow
layout/base/nsDisplayList.cpp
layout/base/nsDisplayList.h
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -1834,17 +1834,17 @@ nsDisplayOpacity::ComputeVisibility(nsDi
 bool nsDisplayOpacity::TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) {
   if (aItem->GetType() != TYPE_OPACITY)
     return false;
   // items for the same content element should be merged into a single
   // compositing group
   // aItem->GetUnderlyingFrame() returns non-null because it's nsDisplayOpacity
   if (aItem->GetUnderlyingFrame()->GetContent() != mFrame->GetContent())
     return false;
-  MergeFrom(static_cast<nsDisplayOpacity*>(aItem));
+  MergeFromTrackingMergedFrames(static_cast<nsDisplayOpacity*>(aItem));
   return true;
 }
 
 nsDisplayOwnLayer::nsDisplayOwnLayer(nsDisplayListBuilder* aBuilder,
                                      nsIFrame* aFrame, nsDisplayList* aList)
     : nsDisplayWrapList(aBuilder, aFrame, aList) {
   MOZ_COUNT_CTOR(nsDisplayOwnLayer);
 }
@@ -2002,22 +2002,25 @@ nsDisplayScrollLayer::TryMerge(nsDisplay
   if (other->mScrolledFrame != this->mScrolledFrame) {
     return false;
   }
 
   FrameProperties props = mScrolledFrame->Properties();
   props.Set(nsIFrame::ScrollLayerCount(),
     reinterpret_cast<void*>(GetScrollLayerCount() - 1));
 
-  MergeFrom(other);
+  // 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;
 }
@@ -2147,16 +2150,17 @@ bool nsDisplayClip::ComputeVisibility(ns
 
 bool nsDisplayClip::TryMerge(nsDisplayListBuilder* aBuilder,
                              nsDisplayItem* aItem) {
   if (aItem->GetType() != TYPE_CLIP)
     return false;
   nsDisplayClip* other = static_cast<nsDisplayClip*>(aItem);
   if (!other->mClip.IsEqualInterior(mClip))
     return false;
+  // No need to track merged frames for clipping
   MergeFrom(other);
   return true;
 }
 
 nsDisplayWrapList* nsDisplayClip::WrapWithClone(nsDisplayListBuilder* aBuilder,
                                                 nsDisplayItem* aItem) {
   return new (aBuilder)
     nsDisplayClip(aBuilder, aItem->GetUnderlyingFrame(), aItem, mClip);
@@ -2242,16 +2246,17 @@ bool nsDisplayClipRoundedRect::TryMerge(
 {
   if (aItem->GetType() != TYPE_CLIP_ROUNDED_RECT)
     return false;
   nsDisplayClipRoundedRect* other =
     static_cast<nsDisplayClipRoundedRect*>(aItem);
   if (!mClip.IsEqualInterior(other->mClip) ||
       memcmp(mRadii, other->mRadii, sizeof(mRadii)) != 0)
     return false;
+  // No need to track merged frames for clipping
   MergeFrom(other);
   return true;
 }
 
 nsDisplayZoom::nsDisplayZoom(nsDisplayListBuilder* aBuilder,
                              nsIFrame* aFrame, nsDisplayList* aList,
                              PRInt32 aAPD, PRInt32 aParentAPD)
     : nsDisplayOwnLayer(aBuilder, aFrame, aList), mAPD(aAPD),
@@ -3058,17 +3063,17 @@ bool nsDisplaySVGEffects::TryMerge(nsDis
   if (aItem->GetType() != TYPE_SVG_EFFECTS)
     return false;
   // items for the same content element should be merged into a single
   // compositing group
   // aItem->GetUnderlyingFrame() returns non-null because it's nsDisplaySVGEffects
   if (aItem->GetUnderlyingFrame()->GetContent() != mFrame->GetContent())
     return false;
   nsDisplaySVGEffects* other = static_cast<nsDisplaySVGEffects*>(aItem);
-  MergeFrom(other);
+  MergeFromTrackingMergedFrames(other);
   mEffectsBounds.UnionRect(mEffectsBounds,
     other->mEffectsBounds + other->mEffectsFrame->GetOffsetTo(mEffectsFrame));
   return true;
 }
 
 #ifdef MOZ_DUMP_PAINTING
 void
 nsDisplaySVGEffects::PrintEffects(FILE* aOutput)
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -786,16 +786,23 @@ public:
    * (also for correctness).
    * @return true if the merge was successful and the other item should be deleted
    */
   virtual bool TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) {
     return false;
   }
 
   /**
+   * Appends the underlying frames of all display items that have been
+   * merged into this one (excluding  this item's own underlying frame)
+   * to aFrames.
+   */
+  virtual void GetMergedFrames(nsTArray<nsIFrame*>* aFrames) {}
+
+  /**
    * During the visibility computation and after TryMerge, display lists may
    * return true here to flatten themselves away, removing them. This
    * flattening is distinctly different from FlattenTo, which occurs before
    * items are merged together.
    */
   virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) {
     return false;
   }
@@ -1707,16 +1714,20 @@ public:
   virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx);
   virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                  nsRegion* aVisibleRegion,
                                  const nsRect& aAllowVisibleRegionExpansion);
   virtual bool TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) {
     NS_WARNING("This list should already have been flattened!!!");
     return false;
   }
+  virtual void GetMergedFrames(nsTArray<nsIFrame*>* aFrames)
+  {
+    aFrames->AppendElements(mMergedFrames);
+  }
   NS_DISPLAY_DECL_NAME("WrapList", TYPE_WRAP_LIST)
 
   virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder);
                                     
   virtual nsDisplayList* GetList() { return &mList; }
   
   /**
    * This creates a copy of this item, but wrapping aItem instead of
@@ -1743,18 +1754,27 @@ public:
 protected:
   nsDisplayWrapList() {}
 
   void MergeFrom(nsDisplayWrapList* aOther)
   {
     mList.AppendToBottom(&aOther->mList);
     mBounds.UnionRect(mBounds, aOther->mBounds);
   }
+  void MergeFromTrackingMergedFrames(nsDisplayWrapList* aOther)
+  {
+    MergeFrom(aOther);
+    mMergedFrames.AppendElement(aOther->mFrame);
+    mMergedFrames.MoveElementsFrom(aOther->mMergedFrames);
+  }
 
   nsDisplayList mList;
+  // The frames from items that have been merged into this item, excluding
+  // this item's own frame.
+  nsTArray<nsIFrame*> mMergedFrames;
   nsRect mBounds;
 };
 
 /**
  * We call WrapDisplayList on the in-flow lists: BorderBackground(),
  * BlockBorderBackgrounds() and Content().
  * We call WrapDisplayItem on each item of Outlines(), PositionedDescendants(),
  * and Floats(). This is done to support special wrapping processing for frames