Bug 590468. Part 6: Fix setting of nsDisplayList::mOpaque, and return it from nsDisplayWrapList::IsOpaque. r=tnikkel
authorRobert O'Callahan <roc@ocallahan.org>
Fri, 27 Aug 2010 18:15:08 -0500
changeset 51633 4722b491cd0da4c979d82fe38d9acf1f73586487
parent 51632 28bf7628f0f1cfe75c9dfa32b9847c40e9683327
child 51634 ffacf623a9dff5f35e5e65334e64d6969f33a0ac
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstnikkel
bugs590468
milestone2.0b5pre
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 590468. Part 6: Fix setting of nsDisplayList::mOpaque, and return it from nsDisplayWrapList::IsOpaque. r=tnikkel
layout/base/nsDisplayList.cpp
layout/base/nsDisplayList.h
layout/base/nsLayoutDebugger.cpp
layout/base/nsLayoutUtils.cpp
layout/base/nsPresContext.cpp
layout/base/nsPresShell.cpp
layout/generic/nsGfxScrollFrame.cpp
layout/generic/nsPageContentFrame.cpp
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -282,19 +282,34 @@ nsDisplayList::GetBounds(nsDisplayListBu
   nsRect bounds;
   for (nsDisplayItem* i = GetBottom(); i != nsnull; i = i->GetAbove()) {
     bounds.UnionRect(bounds, i->GetBounds(aBuilder));
   }
   return bounds;
 }
 
 PRBool
-nsDisplayList::ComputeVisibility(nsDisplayListBuilder* aBuilder,
-                                 nsRegion* aVisibleRegion) {
-  mVisibleRect = aVisibleRegion->GetBounds();
+nsDisplayList::ComputeVisibilityForRoot(nsDisplayListBuilder* aBuilder,
+                                        nsRegion* aVisibleRegion) {
+  nsRegion r;
+  r.And(*aVisibleRegion, GetBounds(aBuilder));
+  return ComputeVisibilityForSublist(aBuilder, aVisibleRegion, r.GetBounds());
+}
+
+PRBool
+nsDisplayList::ComputeVisibilityForSublist(nsDisplayListBuilder* aBuilder,
+                                           nsRegion* aVisibleRegion,
+                                           const nsRect& aListVisibleBounds) {
+#ifdef DEBUG
+  nsRegion r;
+  r.And(*aVisibleRegion, GetBounds(aBuilder));
+  NS_ASSERTION(r.GetBounds() == aListVisibleBounds,
+               "bad aListVisibleBounds");
+#endif
+  mVisibleRect = aListVisibleBounds;
   PRBool anyVisible = PR_FALSE;
 
   nsAutoTArray<nsDisplayItem*, 512> elements;
   FlattenTo(&elements);
 
   for (PRInt32 i = elements.Length() - 1; i >= 0; --i) {
     nsDisplayItem* item = elements[i];
     nsDisplayItem* belowItem = i < 1 ? nsnull : elements[i - 1];
@@ -317,17 +332,17 @@ nsDisplayList::ComputeVisibility(nsDispl
       if (item->IsOpaque(aBuilder) && f) {
         // Subtract opaque item from the visible region
         aBuilder->SubtractFromVisibleRegion(aVisibleRegion, nsRegion(bounds));
       }
     }
     AppendToBottom(item);
   }
 
-  mIsOpaque = aVisibleRegion->IsEmpty();
+  mIsOpaque = !aVisibleRegion->Intersects(mVisibleRect);
 #ifdef DEBUG
   mDidComputeVisibility = PR_TRUE;
 #endif
   return anyVisible;
 }
 
 void nsDisplayList::PaintRoot(nsDisplayListBuilder* aBuilder,
                               nsIRenderingContext* aCtx,
@@ -1050,24 +1065,23 @@ nsDisplayWrapList::HitTest(nsDisplayList
 nsRect
 nsDisplayWrapList::GetBounds(nsDisplayListBuilder* aBuilder) {
   return mList.GetBounds(aBuilder);
 }
 
 PRBool
 nsDisplayWrapList::ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                      nsRegion* aVisibleRegion) {
-  return mList.ComputeVisibility(aBuilder, aVisibleRegion);
+  return mList.ComputeVisibilityForSublist(aBuilder, aVisibleRegion,
+                                           mVisibleRect);
 }
 
 PRBool
 nsDisplayWrapList::IsOpaque(nsDisplayListBuilder* aBuilder) {
-  // We could try to do something but let's conservatively just return PR_FALSE.
-  // We reimplement ComputeVisibility and that's what really matters
-  return PR_FALSE;
+  return mList.IsOpaque();
 }
 
 PRBool nsDisplayWrapList::IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) {
   // We could try to do something but let's conservatively just return PR_FALSE.
   return PR_FALSE;
 }
 
 PRBool nsDisplayWrapList::IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuilder,
@@ -1379,18 +1393,21 @@ void nsDisplayZoom::Paint(nsDisplayListB
 PRBool nsDisplayZoom::ComputeVisibility(nsDisplayListBuilder *aBuilder,
                                         nsRegion *aVisibleRegion)
 {
   // Convert the passed in visible region to our appunits.
   nsRegion visibleRegion =
     aVisibleRegion->ConvertAppUnitsRoundOut(mParentAPD, mAPD);
   nsRegion originalVisibleRegion = visibleRegion;
 
+  nsRect transformedVisibleRect =
+    mVisibleRect.ConvertAppUnitsRoundOut(mParentAPD, mAPD);
   PRBool retval =
-    nsDisplayWrapList::ComputeVisibility(aBuilder, &visibleRegion);
+    mList.ComputeVisibilityForSublist(aBuilder, &visibleRegion,
+                                      transformedVisibleRect);
 
   nsRegion removed;
   // removed = originalVisibleRegion - visibleRegion
   removed.Sub(originalVisibleRegion, visibleRegion);
   // Convert removed region to parent appunits.
   removed = removed.ConvertAppUnitsRoundIn(mAPD, mParentAPD);
   // aVisibleRegion = aVisibleRegion - removed (modulo any simplifications
   // SubtractFromVisibleRegion does)
@@ -1579,18 +1596,20 @@ nsDisplayTransform::GetLayerState(nsDisp
 PRBool nsDisplayTransform::ComputeVisibility(nsDisplayListBuilder *aBuilder,
                                              nsRegion *aVisibleRegion)
 {
   /* As we do this, we need to be sure to
    * untransform the visible rect, since we want everything that's painting to
    * think that it's painting in its original rectangular coordinate space. */
   nsRegion untransformedVisible =
     UntransformRect(mVisibleRect, mFrame, ToReferenceFrame());
-
-  mStoredList.ComputeVisibility(aBuilder, &untransformedVisible);
+  // Call RecomputeVisiblity instead of ComputeVisibilty since
+  // nsDisplayItem::ComputeVisibility should only be called from
+  // nsDisplayList::ComputeVisibility (which sets mVisibleRect on the item)
+  mStoredList.RecomputeVisibility(aBuilder, &untransformedVisible);
   return PR_TRUE;
 }
 
 #ifdef DEBUG_HIT
 #include <time.h>
 #endif
 
 /* HitTest does some fun stuff with matrix transforms to obtain the answer. */
@@ -1838,17 +1857,19 @@ PRBool nsDisplaySVGEffects::ComputeVisib
   nsRect dirtyRect =
     nsSVGIntegrationUtils::GetRequiredSourceForInvalidArea(mEffectsFrame,
                                                            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);
-  nsDisplayWrapList::ComputeVisibility(aBuilder, &childrenVisible);
+  nsRect r;
+  r.IntersectRect(dirtyRect, mList.GetBounds(aBuilder));
+  mList.ComputeVisibilityForSublist(aBuilder, &childrenVisible, r);
   return PR_TRUE;
 }
 
 PRBool nsDisplaySVGEffects::TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem)
 {
   if (aItem->GetType() != TYPE_SVG_EFFECTS)
     return PR_FALSE;
   // items for the same content element should be merged into a single
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -582,16 +582,18 @@ public:
    * nsDisplayList::ComputeVisibility automatically subtracts the bounds
    * of items that return true from IsOpaque(), and automatically
    * removes items whose bounds do not intersect the visible area,
    * so implementations of nsDisplayItem::ComputeVisibility do not
    * need to do these things.
    * nsDisplayList::ComputeVisibility will already have set mVisibleRect on
    * this item to the intersection of *aVisibleRegion (unioned with
    * *aVisibleRegionBeforeMove, if that's non-null) and this item's bounds.
+   * We rely on that, so this should only be called by
+   * nsDisplayList::ComputeVisibility or nsDisplayItem::RecomputeVisibility.
    * 
    * @return PR_TRUE if the item is visible, PR_FALSE if no part of the item
    * is visible
    */
   virtual PRBool ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                    nsRegion* aVisibleRegion)
   { return !mVisibleRect.IsEmpty(); }
 
@@ -837,27 +839,42 @@ public:
 
   /**
    * Compute visiblity for the items in the list.
    * We put this logic here so it can be shared by top-level
    * painting and also display items that maintain child lists.
    * This is also a good place to put ComputeVisibility-related logic
    * that must be applied to every display item. In particular, this
    * sets mVisibleRect on each display item.
-   * This also sets mIsOpaque to whether aVisibleRegion is empty on return.
+   * This sets mIsOpaque if the entire visible area of this list has
+   * been removed from aVisibleRegion when we return.
    * This does not remove any items from the list, so we can recompute
    * visiblity with different regions later (see
    * FrameLayerBuilder::DrawThebesLayer).
    * 
    * @param aVisibleRegion the area that is visible, relative to the
-   * reference frame; on return, this contains the area visible under the list
+   * 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
    */
-  PRBool ComputeVisibility(nsDisplayListBuilder* aBuilder,
-                           nsRegion* aVisibleRegion);
+  PRBool ComputeVisibilityForSublist(nsDisplayListBuilder* aBuilder,
+                                     nsRegion* aVisibleRegion,
+                                     const nsRect& aListVisibleBounds);
+
+  /**
+   * As ComputeVisibilityForSublist, but computes visibility for a root
+   * list (a list that does not belong to an nsDisplayItem).
+   *
+   * @param aVisibleRegion the area that is visible
+   */
+  PRBool ComputeVisibilityForRoot(nsDisplayListBuilder* aBuilder,
+                                  nsRegion* aVisibleRegion);
+
   /**
    * Returns true if the visible region output from ComputeVisiblity was
    * empty, i.e. everything visible in this list is opaque.
    */
   PRBool IsOpaque() const {
     NS_ASSERTION(mDidComputeVisibility, "Need to have called ComputeVisibility");
     return mIsOpaque;
   }
--- a/layout/base/nsLayoutDebugger.cpp
+++ b/layout/base/nsLayoutDebugger.cpp
@@ -171,23 +171,23 @@ PrintDisplayListTo(nsDisplayListBuilder*
         rect = c->GetClipRect();
         break;
       }
       default:
         break;
     }
     nscolor color;
     nsRect vis = i->GetVisibleRect();
+    nsDisplayList* list = i->GetList();
     fprintf(aOutput, "%s %p(%s) (%d,%d,%d,%d)(%d,%d,%d,%d)%s%s\n",
             i->Name(), (void*)f, NS_ConvertUTF16toUTF8(fName).get(),
             rect.x, rect.y, rect.width, rect.height,
             vis.x, vis.y, vis.width, vis.height,
-            i->IsOpaque(aBuilder) ? " opaque" : "",
+            ((!list || list->DidComputeVisibility()) && i->IsOpaque(aBuilder)) ? " opaque" : "",
             i->IsUniform(aBuilder, &color) ? " uniform" : "");
-    nsDisplayList* list = i->GetList();
     if (list) {
       PrintDisplayListTo(aBuilder, *list, aIndent + 4, aOutput);
     }
     if (i->GetType() == nsDisplayItem::TYPE_TRANSFORM) {
       nsDisplayTransform* t = static_cast<nsDisplayTransform*>(i);
       PrintDisplayListTo(aBuilder, *(t->GetStoredList()->GetList()), aIndent + 4, aOutput);
     }
   }
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -1372,17 +1372,17 @@ nsLayoutUtils::PaintFrame(nsIRenderingCo
 #ifdef DEBUG
   if (gDumpPaintList) {
     fprintf(stderr, "Painting --- before optimization (dirty %d,%d,%d,%d):\n",
             dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height);
     nsFrame::PrintDisplayList(&builder, list);
   }
 #endif
 
-  list.ComputeVisibility(&builder, &visibleRegion);
+  list.ComputeVisibilityForRoot(&builder, &visibleRegion);
 
 #ifdef DEBUG
   if (gDumpPaintList) {
     fprintf(stderr, "Painting --- after optimization:\n");
     nsFrame::PrintDisplayList(&builder, list);
   }
 #endif
 
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -2531,17 +2531,17 @@ nsRootPresContext::GetPluginGeometryUpda
     if (gDumpPluginList) {
       fprintf(stderr, "Plugins --- before optimization (bounds %d,%d,%d,%d):\n",
           bounds.x, bounds.y, bounds.width, bounds.height);
       nsFrame::PrintDisplayList(&builder, list);
     }
 #endif
 
     nsRegion visibleRegion(bounds);
-    list.ComputeVisibility(&builder, &visibleRegion);
+    list.ComputeVisibilityForRoot(&builder, &visibleRegion);
 
 #ifdef DEBUG
     if (gDumpPluginList) {
       fprintf(stderr, "Plugins --- after optimization:\n");
       nsFrame::PrintDisplayList(&builder, list);
     }
 #endif
 
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -5613,17 +5613,17 @@ PresShell::PaintRangePaintInfo(nsTArray<
     RangePaintInfo* rangeInfo = (*aItems)[i];
     // the display lists paint relative to the offset from the reference
     // frame, so translate the rendering context
     nsIRenderingContext::AutoPushTranslation
       translate(rc, rangeInfo->mRootOffset.x, rangeInfo->mRootOffset.y);
 
     aArea.MoveBy(-rangeInfo->mRootOffset.x, -rangeInfo->mRootOffset.y);
     nsRegion visible(aArea);
-    rangeInfo->mList.ComputeVisibility(&rangeInfo->mBuilder, &visible);
+    rangeInfo->mList.ComputeVisibilityForRoot(&rangeInfo->mBuilder, &visible);
     rangeInfo->mList.PaintRoot(&rangeInfo->mBuilder, rc, nsDisplayList::PAINT_DEFAULT);
     aArea.MoveBy(rangeInfo->mRootOffset.x, rangeInfo->mRootOffset.y);
   }
 
   // restore the old selection display state
   frameSelection->SetDisplaySelection(oldDisplaySelection);
 
   NS_ADDREF(surface);
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -1563,17 +1563,17 @@ InvalidateFixedBackgroundFrames(nsIFrame
   nsDisplayList list;
   nsresult rv =
     aRootFrame->BuildDisplayListForStackingContext(&builder, aUpdateRect, &list);
   builder.LeavePresShell(aRootFrame, aUpdateRect);
   if (NS_FAILED(rv))
     return;
 
   nsRegion visibleRegion(aUpdateRect);
-  list.ComputeVisibility(&builder, &visibleRegion);
+  list.ComputeVisibilityForRoot(&builder, &visibleRegion);
 
   InvalidateFixedBackgroundFramesFromList(&builder, aMovingFrame, list);
   list.DeleteAll();
 }
 
 PRBool nsGfxScrollFrameInner::IsAlwaysActive() const
 {
   // The root scrollframe for a non-chrome document which is the direct
--- a/layout/generic/nsPageContentFrame.cpp
+++ b/layout/generic/nsPageContentFrame.cpp
@@ -144,16 +144,18 @@ nsPageContentFrame::Reflow(nsPresContext
   NS_ASSERTION(NS_FRAME_IS_COMPLETE(fixedStatus), "fixed frames can be truncated, but not incomplete");
 
   // Return our desired size
   aDesiredSize.width = aReflowState.availableWidth;
   if (aReflowState.availableHeight != NS_UNCONSTRAINEDSIZE) {
     aDesiredSize.height = aReflowState.availableHeight;
   }
 
+  FinishAndStoreOverflow(&aDesiredSize);
+
   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
   return NS_OK;
 }
 
 nsIAtom*
 nsPageContentFrame::GetType() const
 {
   return nsGkAtoms::pageContentFrame;