Bug 800041 - Make nsDisplayWrapList set its own reference frame correctly, and sanity check during ComputeVisibilityForSublist. r=roc
authorMatt Woodrow <mwoodrow@mozilla.com>
Thu, 25 Oct 2012 18:32:25 +1300
changeset 111481 56ea8204864df62e250ebc18ab44d8b3c82f077a
parent 111480 612a40a222d7cd9cca0d50b80da075fac00b5c41
child 111482 5a4073fa0bbb7556d2c1ea4dd9ef5c0d73399e0d
push id23748
push userryanvm@gmail.com
push dateFri, 26 Oct 2012 11:29:12 +0000
treeherdermozilla-central@8586bd350875 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs800041
milestone19.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 800041 - Make nsDisplayWrapList set its own reference frame correctly, and sanity check during ComputeVisibilityForSublist. r=roc
layout/base/nsDisplayList.cpp
layout/base/nsDisplayList.h
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -847,17 +847,17 @@ nsDisplayList::GetBounds(nsDisplayListBu
 }
 
 bool
 nsDisplayList::ComputeVisibilityForRoot(nsDisplayListBuilder* aBuilder,
                                         nsRegion* aVisibleRegion) {
   SAMPLE_LABEL("nsDisplayList", "ComputeVisibilityForRoot");
   nsRegion r;
   r.And(*aVisibleRegion, GetBounds(aBuilder));
-  return ComputeVisibilityForSublist(aBuilder, aVisibleRegion, r.GetBounds(), r.GetBounds());
+  return ComputeVisibilityForSublist(aBuilder, nullptr, aVisibleRegion, r.GetBounds(), r.GetBounds());
 }
 
 static nsRegion
 TreatAsOpaque(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder)
 {
   bool snap;
   nsRegion opaque = aItem->GetOpaqueRegion(aBuilder, &snap);
   if (aBuilder->IsForPluginGeometry()) {
@@ -892,16 +892,17 @@ GetDisplayPortBounds(nsDisplayListBuilde
                     nsRect(0, 0, displayport->width, displayport->height),
                     aBuilder->FindReferenceFrameFor(frame));
   result.MoveBy(aBuilder->ToReferenceFrame(frame));
   return result;
 }
 
 bool
 nsDisplayList::ComputeVisibilityForSublist(nsDisplayListBuilder* aBuilder,
+                                           nsDisplayItem* aForItem,
                                            nsRegion* aVisibleRegion,
                                            const nsRect& aListVisibleBounds,
                                            const nsRect& aAllowVisibleRegionExpansion) {
   bool snap;
 #ifdef DEBUG
   nsRegion r;
   r.And(*aVisibleRegion, GetBounds(aBuilder));
   NS_ASSERTION(r.GetBounds().IsEqualInterior(aListVisibleBounds),
@@ -914,16 +915,23 @@ nsDisplayList::ComputeVisibilityForSubli
   FlattenTo(&elements);
 
   bool forceTransparentSurface = false;
 
   for (int32_t i = elements.Length() - 1; i >= 0; --i) {
     nsDisplayItem* item = elements[i];
     nsDisplayItem* belowItem = i < 1 ? nullptr : elements[i - 1];
 
+    NS_ASSERTION(!aForItem ||
+                 item->GetType() != nsDisplayItem::TYPE_TRANSFORM ||
+                 item->GetUnderlyingFrame() != aForItem->GetUnderlyingFrame() ||
+                 aForItem->ReferenceFrame() != aForItem->GetUnderlyingFrame(),
+                 "If we have an nsDisplayTransform child (for the same frame),"
+                 "then we shouldn't be our own reference frame!");
+
     nsDisplayList* list = item->GetList();
     if (aBuilder->AllowMergingAndFlattening()) {
       if (belowItem && item->TryMerge(aBuilder, belowItem)) {
         belowItem->~nsDisplayItem();
         elements.ReplaceElementsAt(i - 1, 1, item);
         continue;
       }
 
@@ -2369,28 +2377,89 @@ nsDisplayBoxShadowInner::ComputeVisibili
     return false;
   }
 
   // Store the actual visible region
   mVisibleRegion.And(*aVisibleRegion, mVisibleRect);
   return true;
 }
 
+nsIFrame *GetTransformRootFrame(nsIFrame* aFrame)
+{
+  nsIFrame *parent = nsLayoutUtils::GetCrossDocParentFrame(aFrame);
+  while (parent && parent->Preserves3DChildren()) {
+    parent = nsLayoutUtils::GetCrossDocParentFrame(parent);
+  }
+  return parent;
+}
+
 nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder,
                                      nsIFrame* aFrame, nsDisplayList* aList)
   : nsDisplayItem(aBuilder, aFrame) {
   mList.AppendToTop(aList);
   UpdateBounds(aBuilder);
+
+  if (!aFrame || !aFrame->IsTransformed()) {
+    return;
+  }
+
+  // If the frame is a preserve-3d parent, then we will create transforms
+  // inside this list afterwards (see WrapPreserve3DList in nsFrame.cpp).
+  // In this case we will always be outside of the transform, so share
+  // our parents reference frame.
+  if (aFrame->Preserves3DChildren()) {
+    mReferenceFrame = 
+      aBuilder->FindReferenceFrameFor(GetTransformRootFrame(aFrame));
+    mToReferenceFrame = aFrame->GetOffsetToCrossDoc(mReferenceFrame);
+    return;
+  }
+
+  // If we're a transformed frame, then we need to find out if we're inside
+  // the nsDisplayTransform or outside of it. Frames inside the transform
+  // need mReferenceFrame == mFrame, outside needs the next ancestor
+  // reference frame.
+  // If we're inside the transform, then the nsDisplayItem constructor
+  // will have done the right thing.
+  // If we're outside the transform, then we should have only one child
+  // (since nsDisplayTransform wraps all actual content), and that child
+  // will have the correct reference frame set (since nsDisplayTransform
+  // handles this explictly).
+  //
+  // Preserve-3d can cause us to have multiple nsDisplayTransform
+  // children.
+  nsDisplayItem *i = mList.GetBottom();
+  if (i && (!i->GetAbove() || i->GetType() == TYPE_TRANSFORM) && 
+      i->GetUnderlyingFrame() == mFrame) {
+    mReferenceFrame = i->ReferenceFrame();
+    mToReferenceFrame = i->ToReferenceFrame();
+  }
 }
 
 nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder,
                                      nsIFrame* aFrame, nsDisplayItem* aItem)
   : nsDisplayItem(aBuilder, aFrame) {
   mList.AppendToTop(aItem);
   UpdateBounds(aBuilder);
+  
+  if (!aFrame || !aFrame->IsTransformed()) {
+    return;
+  }
+
+  if (aFrame->Preserves3DChildren()) {
+    mReferenceFrame = 
+      aBuilder->FindReferenceFrameFor(GetTransformRootFrame(aFrame));
+    mToReferenceFrame = aFrame->GetOffsetToCrossDoc(mReferenceFrame);
+    return;
+  }
+
+  // See the previous nsDisplayWrapList constructor
+  if (aItem->GetUnderlyingFrame() == aFrame) {
+    mReferenceFrame = aItem->ReferenceFrame();
+    mToReferenceFrame = aItem->ToReferenceFrame();
+  }
 }
 
 nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder,
                                      nsIFrame* aFrame, nsDisplayItem* aItem,
                                      const nsIFrame* aReferenceFrame,
                                      const nsPoint& aToReferenceFrame)
   : nsDisplayItem(aBuilder, aFrame, aReferenceFrame, aToReferenceFrame) {
   mList.AppendToTop(aItem);
@@ -2412,17 +2481,17 @@ nsDisplayWrapList::GetBounds(nsDisplayLi
   *aSnap = false;
   return mBounds;
 }
 
 bool
 nsDisplayWrapList::ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                      nsRegion* aVisibleRegion,
                                      const nsRect& aAllowVisibleRegionExpansion) {
-  return mList.ComputeVisibilityForSublist(aBuilder, aVisibleRegion,
+  return mList.ComputeVisibilityForSublist(aBuilder, this, aVisibleRegion,
                                            mVisibleRect,
                                            aAllowVisibleRegionExpansion);
 }
 
 nsRegion
 nsDisplayWrapList::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
                                    bool* aSnap) {
   *aSnap = false;
@@ -2775,21 +2844,16 @@ nsDisplayScrollLayer::nsDisplayScrollLay
   , mScrolledFrame(aScrolledFrame)
 {
 #ifdef NS_BUILD_REFCNT_LOGGING
   MOZ_COUNT_CTOR(nsDisplayScrollLayer);
 #endif
 
   NS_ASSERTION(mScrolledFrame && mScrolledFrame->GetContent(),
                "Need a child frame with content");
-  nsIFrame *parent = nsLayoutUtils::GetCrossDocParentFrame(aForFrame);
-  NS_ASSERTION(parent, "Must have a parent!");
-  mReferenceFrame = 
-    aBuilder->FindReferenceFrameFor(parent);
-  mToReferenceFrame = aForFrame->GetOffsetToCrossDoc(mReferenceFrame);
 }
 
 nsDisplayScrollLayer::nsDisplayScrollLayer(nsDisplayListBuilder* aBuilder,
                                            nsDisplayItem* aItem,
                                            nsIFrame* aForFrame,
                                            nsIFrame* aScrolledFrame,
                                            nsIFrame* aScrollFrame)
   : nsDisplayWrapList(aBuilder, aForFrame, aItem)
@@ -2797,42 +2861,32 @@ nsDisplayScrollLayer::nsDisplayScrollLay
   , mScrolledFrame(aScrolledFrame)
 {
 #ifdef NS_BUILD_REFCNT_LOGGING
   MOZ_COUNT_CTOR(nsDisplayScrollLayer);
 #endif
 
   NS_ASSERTION(mScrolledFrame && mScrolledFrame->GetContent(),
                "Need a child frame with content");
-  nsIFrame *parent = nsLayoutUtils::GetCrossDocParentFrame(aForFrame);
-  NS_ASSERTION(parent, "Must have a parent!");
-  mReferenceFrame = 
-    aBuilder->FindReferenceFrameFor(parent);
-  mToReferenceFrame = aForFrame->GetOffsetToCrossDoc(mReferenceFrame);
 }
 
 nsDisplayScrollLayer::nsDisplayScrollLayer(nsDisplayListBuilder* aBuilder,
                                            nsIFrame* aForFrame,
                                            nsIFrame* aScrolledFrame,
                                            nsIFrame* aScrollFrame)
   : nsDisplayWrapList(aBuilder, aForFrame)
   , mScrollFrame(aScrollFrame)
   , mScrolledFrame(aScrolledFrame)
 {
 #ifdef NS_BUILD_REFCNT_LOGGING
   MOZ_COUNT_CTOR(nsDisplayScrollLayer);
 #endif
 
   NS_ASSERTION(mScrolledFrame && mScrolledFrame->GetContent(),
                "Need a child frame with content");
-  nsIFrame *parent = nsLayoutUtils::GetCrossDocParentFrame(aForFrame);
-  NS_ASSERTION(parent, "Must have a parent!");
-  mReferenceFrame = 
-    aBuilder->FindReferenceFrameFor(parent);
-  mToReferenceFrame = aForFrame->GetOffsetToCrossDoc(mReferenceFrame);
 }
 
 #ifdef NS_BUILD_REFCNT_LOGGING
 nsDisplayScrollLayer::~nsDisplayScrollLayer()
 {
   MOZ_COUNT_DTOR(nsDisplayScrollLayer);
 }
 #endif
@@ -2878,17 +2932,17 @@ nsDisplayScrollLayer::ComputeVisibility(
     // content to asynchronously pan while content is being refreshed.
 
     nsRegion childVisibleRegion = displayport + mScrollFrame->GetOffsetToCrossDoc(ReferenceFrame());
 
     nsRect boundedRect =
       childVisibleRegion.GetBounds().Intersect(mList.GetBounds(aBuilder));
     nsRect allowExpansion = boundedRect.Intersect(aAllowVisibleRegionExpansion);
     bool visible = mList.ComputeVisibilityForSublist(
-      aBuilder, &childVisibleRegion, boundedRect, allowExpansion);
+      aBuilder, this, &childVisibleRegion, boundedRect, allowExpansion);
     mVisibleRect = boundedRect;
 
     return visible;
 
   } else {
     return nsDisplayWrapList::ComputeVisibility(aBuilder, aVisibleRegion,
                                                 aAllowVisibleRegionExpansion);
   }
@@ -3227,17 +3281,17 @@ bool nsDisplayZoom::ComputeVisibility(ns
     aVisibleRegion->ConvertAppUnitsRoundOut(mParentAPD, mAPD);
   nsRegion originalVisibleRegion = visibleRegion;
 
   nsRect transformedVisibleRect =
     mVisibleRect.ConvertAppUnitsRoundOut(mParentAPD, mAPD);
   nsRect allowExpansion =
     aAllowVisibleRegionExpansion.ConvertAppUnitsRoundIn(mParentAPD, mAPD);
   bool retval =
-    mList.ComputeVisibilityForSublist(aBuilder, &visibleRegion,
+    mList.ComputeVisibilityForSublist(aBuilder, this, &visibleRegion,
                                       transformedVisibleRect,
                                       allowExpansion);
 
   nsRegion removed;
   // removed = originalVisibleRegion - visibleRegion
   removed.Sub(originalVisibleRegion, visibleRegion);
   // Convert removed region to parent appunits.
   removed = removed.ConvertAppUnitsRoundIn(mAPD, mParentAPD);
@@ -3315,25 +3369,16 @@ nsDisplayTransform::GetFrameBoundsForTra
                                       currFrame->GetSize()));
     }
 
   return result;
 }
 
 #endif
 
-nsIFrame *GetTransformRootFrame(nsIFrame* aFrame)
-{
-  nsIFrame *parent = nsLayoutUtils::GetCrossDocParentFrame(aFrame);
-  while (parent && parent->Preserves3DChildren()) {
-    parent = nsLayoutUtils::GetCrossDocParentFrame(parent);
-  }
-  return parent;
-}
-
 nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame *aFrame,
                                        nsDisplayList *aList, ComputeTransformFunction aTransformGetter, 
                                        uint32_t aIndex) 
   : nsDisplayItem(aBuilder, aFrame)
   , mStoredList(aBuilder, aFrame, aList)
   , mTransformGetter(aTransformGetter)
   , mIndex(aIndex)
 {
@@ -4235,17 +4280,17 @@ bool nsDisplaySVGEffects::ComputeVisibil
     nsSVGIntegrationUtils::GetRequiredSourceForInvalidArea(mFrame,
                                                            mVisibleRect - offset) +
     offset;
 
   // Our children may be made translucent or arbitrarily deformed so we should
   // not allow them to subtract area from aVisibleRegion.
   nsRegion childrenVisible(dirtyRect);
   nsRect r = dirtyRect.Intersect(mList.GetBounds(aBuilder));
-  mList.ComputeVisibilityForSublist(aBuilder, &childrenVisible, r, nsRect());
+  mList.ComputeVisibilityForSublist(aBuilder, this, &childrenVisible, r, nsRect());
   return true;
 }
 
 bool nsDisplaySVGEffects::TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem)
 {
   if (aItem->GetType() != TYPE_SVG_EFFECTS)
     return false;
   // items for the same content element should be merged into a single
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -687,16 +687,18 @@ public:
     : mFrame(aFrame)
 #ifdef MOZ_DUMP_PAINTING
     , mPainted(false)
 #endif
   {
     if (aFrame) {
       mReferenceFrame = aBuilder->FindReferenceFrameFor(aFrame);
       mToReferenceFrame = aBuilder->ToReferenceFrame(aFrame);
+    } else {
+      mReferenceFrame = nullptr;
     }
   }
   nsDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                 const nsIFrame* aReferenceFrame,
                 const nsPoint& aToReferenceFrame)
     : mFrame(aFrame)
     , mReferenceFrame(aReferenceFrame)
     , mToReferenceFrame(aToReferenceFrame)
@@ -1292,16 +1294,17 @@ public:
    * @param aVisibleRegion the area that is visible, relative to the
    * reference frame; on return, this contains the area visible under the list.
    * I.e., opaque contents of this list are subtracted from aVisibleRegion.
    * @param aListVisibleBounds must be equal to the bounds of the intersection
    * of aVisibleRegion and GetBounds() for this list.
    * @return true if any item in the list is visible.
    */
   bool ComputeVisibilityForSublist(nsDisplayListBuilder* aBuilder,
+                                   nsDisplayItem* aForItem,
                                    nsRegion* aVisibleRegion,
                                    const nsRect& aListVisibleBounds,
                                    const nsRect& aAllowVisibleRegionExpansion);
 
   /**
    * As ComputeVisibilityForSublist, but computes visibility for a root
    * list (a list that does not belong to an nsDisplayItem).
    * This method needs to be idempotent.