Backout bug 1022612 (all 47 parts). It provides no benefit on Aurora. a=sylvestre
authorRobert O'Callahan <robert@ocallahan.org>
Fri, 25 Jul 2014 00:51:26 +1200
changeset 216126 1a817719d9ea6ff8ace09ae660a87810deb81f7c
parent 216125 bd29e4e816332a2348715917cf7823a1f26d93be
child 216127 8e8546266e99f8687e0775dce33a45b1c0edfa15
push id3857
push userraliiev@mozilla.com
push dateTue, 02 Sep 2014 16:39:23 +0000
treeherdermozilla-beta@5638b907b505 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssylvestre
bugs1022612
milestone33.0a2
Backout bug 1022612 (all 47 parts). It provides no benefit on Aurora. a=sylvestre
gfx/ipc/GfxMessageUtils.h
gfx/src/nsRegion.h
layout/base/FrameLayerBuilder.cpp
layout/base/FrameLayerBuilder.h
layout/base/nsDisplayList.cpp
layout/base/nsDisplayList.h
layout/base/nsLayoutDebugger.cpp
layout/base/nsLayoutUtils.cpp
layout/base/nsLayoutUtils.h
layout/base/nsPresShell.cpp
layout/forms/nsSelectsAreaFrame.cpp
layout/generic/nsCanvasFrame.h
layout/generic/nsFrame.cpp
layout/generic/nsHTMLCanvasFrame.cpp
layout/generic/nsIFrame.h
layout/generic/nsImageFrame.cpp
layout/generic/nsObjectFrame.cpp
layout/generic/nsObjectFrame.h
layout/generic/nsPageFrame.cpp
layout/generic/nsSimplePageSequenceFrame.cpp
layout/generic/nsSubDocumentFrame.cpp
layout/generic/nsVideoFrame.cpp
layout/ipc/RenderFrameParent.cpp
layout/reftests/bugs/1022612-1-ref.html
layout/reftests/bugs/1022612-1.html
layout/reftests/bugs/reftest.list
layout/reftests/forms/fieldset/positioned-container-1-ref.html
layout/reftests/forms/fieldset/positioned-container-1.html
layout/reftests/text/reftest.list
layout/tables/nsTableFrame.cpp
layout/tables/nsTableFrame.h
layout/xul/nsBoxFrame.cpp
layout/xul/nsImageBoxFrame.cpp
testing/testsuite-targets.mk
--- a/gfx/ipc/GfxMessageUtils.h
+++ b/gfx/ipc/GfxMessageUtils.h
@@ -484,20 +484,18 @@ struct ParamTraits<nsIntRect>
 template<typename Region, typename Rect, typename Iter>
 struct RegionParamTraits
 {
   typedef Region paramType;
 
   static void Write(Message* msg, const paramType& param)
   {
     Iter it(param);
-    while (const Rect* r = it.Next()) {
-      MOZ_ASSERT(!r->IsEmpty());
+    while (const Rect* r = it.Next())
       WriteParam(msg, *r);
-    }
     // empty rects are sentinel values because nsRegions will never
     // contain them
     WriteParam(msg, Rect());
   }
 
   static bool Read(const Message* msg, void** iter, paramType* result)
   {
     Rect rect;
--- a/gfx/src/nsRegion.h
+++ b/gfx/src/nsRegion.h
@@ -207,23 +207,17 @@ public:
   }
 
   bool IsEmpty () const { return !pixman_region32_not_empty(Impl()); }
   bool IsComplex () const { return GetNumRects() > 1; }
   bool IsEqual (const nsRegion& aRegion) const
   {
     return pixman_region32_equal(Impl(), aRegion.Impl());
   }
-  uint32_t GetNumRects () const
-  {
-    // Work around pixman bug. Sometimes pixman creates regions with 1 rect
-    // that's empty.
-    uint32_t result = pixman_region32_n_rects(Impl());
-    return (result == 1 && GetBounds().IsEmpty()) ? 0 : result;
-  }
+  uint32_t GetNumRects () const { return pixman_region32_n_rects(Impl()); }
   const nsRect GetBounds () const { return BoxToRect(mImpl.extents); }
   uint64_t Area () const;
   // Converts this region from aFromAPP, an appunits per pixel ratio, to
   // aToAPP. This applies nsRect::ConvertAppUnitsRoundOut/In to each rect of
   // the region.
   nsRegion ConvertAppUnitsRoundOut (int32_t aFromAPP, int32_t aToAPP) const;
   nsRegion ConvertAppUnitsRoundIn (int32_t aFromAPP, int32_t aToAPP) const;
   nsRegion& ScaleRoundOut(float aXScale, float aYScale);
@@ -339,39 +333,32 @@ class NS_GFX nsRegionRectIterator
   pixman_box32_t *boxes;
 
 public:
   nsRegionRectIterator (const nsRegion& aRegion)
   {
     mRegion = &aRegion;
     i = 0;
     boxes = pixman_region32_rectangles(aRegion.Impl(), &n);
-    // Work around pixman bug. Sometimes pixman creates regions with 1 rect
-    // that's empty.
-    if (n == 1 && nsRegion::BoxToRect(boxes[0]).IsEmpty()) {
-      n = 0;
-    }
   }
 
   const nsRect* Next ()
   {
     if (i == n)
       return nullptr;
     rect = nsRegion::BoxToRect(boxes[i]);
-    NS_ASSERTION(!rect.IsEmpty(), "Shouldn't return empty rect");
     i++;
     return &rect;
   }
 
   const nsRect* Prev ()
   {
     if (i == -1)
       return nullptr;
     rect = nsRegion::BoxToRect(boxes[i]);
-    NS_ASSERTION(!rect.IsEmpty(), "Shouldn't return empty rect");
     i--;
     return &rect;
   }
 
   void Reset ()
   {
     i = 0;
   }
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -18,30 +18,31 @@
 #include "MaskLayerImageCache.h"
 #include "nsIScrollableFrame.h"
 #include "nsPrintfCString.h"
 #include "LayerTreeInvalidation.h"
 #include "nsSVGIntegrationUtils.h"
 #include "ImageContainer.h"
 #include "ActiveLayerTracker.h"
 #include "gfx2DGlue.h"
-#include "mozilla/LookAndFeel.h"
 
 #include "GeckoProfiler.h"
 #include "mozilla/gfx/Tools.h"
 #include "mozilla/gfx/2D.h"
 #include "gfxPrefs.h"
 
 #include <algorithm>
 
 using namespace mozilla::layers;
 using namespace mozilla::gfx;
 
 namespace mozilla {
 
+class ContainerState;
+
 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)
@@ -237,20 +238,18 @@ public:
     mAnimatedGeometryRoot(nullptr),
     mFixedPosFrameForLayerData(nullptr),
     mReferenceFrame(nullptr),
     mLayer(nullptr),
     mIsSolidColorInVisibleRegion(false),
     mSingleItemFixedToViewport(false),
     mNeedComponentAlpha(false),
     mForceTransparentSurface(false),
-    mHideAllLayersBelow(false),
     mImage(nullptr),
     mCommonClipCount(-1),
-    mNewChildLayersIndex(-1),
     mAllDrawingAbove(false)
   {}
   /**
    * Record that an item has been added to the ThebesLayer, so we
    * need to update our regions.
    * @param aVisibleRect the area of the item that's visible
    * @param aDrawRect the area of the item that would be drawn if it
    * was completely visible
@@ -258,17 +257,16 @@ public:
    * We pass in a separate opaque rect because the opaque rect can be
    * bigger than the visible rect, and we want to have the biggest
    * opaque rect that we can.
    * @param aSolidColor if non-null, the visible area of the item is
    * a constant color given by *aSolidColor
    */
   void Accumulate(ContainerState* aState,
                   nsDisplayItem* aItem,
-                  const nsIntRegion& aClippedOpaqueRegion,
                   const nsIntRect& aVisibleRect,
                   const nsIntRect& aDrawRect,
                   const DisplayItemClip& aClip);
   const nsIFrame* GetAnimatedGeometryRoot() { return mAnimatedGeometryRoot; }
 
   /**
    * Add aHitRegion, aMaybeHitRegion, and aDispatchToContentHitRegion to the
    * hit regions for this ThebesLayer.
@@ -288,40 +286,40 @@ public:
    * an ImageContainer for the image.
    */
   already_AddRefed<ImageContainer> CanOptimizeImageLayer(nsDisplayListBuilder* aBuilder);
 
   void AddDrawAboveRegion(const nsIntRegion& aAbove)
   {
     if (!mAllDrawingAbove) {
       mDrawAboveRegion.Or(mDrawAboveRegion, aAbove);
-      mDrawAboveRegion.SimplifyOutward(8);
+      mDrawAboveRegion.SimplifyOutward(4);
     }
   }
 
   void AddVisibleAboveRegion(const nsIntRegion& aAbove)
   {
     if (!mAllDrawingAbove) {
       mVisibleAboveRegion.Or(mVisibleAboveRegion, aAbove);
-      mVisibleAboveRegion.SimplifyOutward(8);
+      mVisibleAboveRegion.SimplifyOutward(4);
     }
   }
 
   void CopyAboveRegion(ThebesLayerData* aOther)
   {
     if (aOther->mAllDrawingAbove || mAllDrawingAbove) {
       SetAllDrawingAbove();
     } else {
       mVisibleAboveRegion.Or(mVisibleAboveRegion, aOther->mVisibleAboveRegion);
       mVisibleAboveRegion.Or(mVisibleAboveRegion, aOther->mVisibleRegion);
-      mVisibleAboveRegion.SimplifyOutward(8);
+      mVisibleAboveRegion.SimplifyOutward(4);
       mDrawAboveRegion.Or(mDrawAboveRegion, aOther->mDrawAboveRegion);
       mDrawAboveRegion.Or(mDrawAboveRegion, aOther->mDrawRegion);
-      mDrawAboveRegion.SimplifyOutward(8);
-    }
+      mDrawAboveRegion.SimplifyOutward(4);
+   }
   }
 
   void SetAllDrawingAbove()
   {
     mAllDrawingAbove = true;
     mDrawAboveRegion.SetEmpty();
     mVisibleAboveRegion.SetEmpty();
   }
@@ -419,20 +417,16 @@ public:
   bool mNeedComponentAlpha;
   /**
    * Set if the layer should be treated as transparent, even if its entire
    * area is covered by opaque display items. For example, this needs to
    * be set if something is going to "punch holes" in the layer by clearing
    * part of its surface.
    */
   bool mForceTransparentSurface;
-  /**
-   * Set if all layers below this ThebesLayer should be hidden.
-   */
-  bool mHideAllLayersBelow;
 
   /**
    * Stores the pointer to the nsDisplayImage if we want to
    * convert this to an ImageLayer.
    */
   nsDisplayImageContainer* mImage;
   /**
    * Stores the clip that we need to apply to the image or, if there is no
@@ -445,20 +439,16 @@ public:
   DisplayItemClip mItemClip;
   /**
    * The first mCommonClipCount rounded rectangle clips are identical for
    * all items in the layer.
    * -1 if there are no items in the layer; must be >=0 by the time that this
    * data is popped from the stack.
    */
   int32_t mCommonClipCount;
-  /**
-   * Index of this layer in mNewChildLayers.
-   */
-  int32_t mNewChildLayersIndex;
   /*
    * Updates mCommonClipCount by checking for rounded rect clips in common
    * between the clip on a new item (aCurrentClip) and the common clips
    * on items already in the layer (the first mCommonClipCount rounded rects
    * in mItemClip).
    */
   void UpdateCommonClipCount(const DisplayItemClip& aCurrentClip);
 
@@ -482,111 +472,72 @@ private:
   nsIntRegion  mDrawAboveRegion;
   /**
    * True if mDrawAboveRegion and mVisibleAboveRegion should be treated
    * as infinite, and all display items should be considered 'above' this layer.
    */
   bool mAllDrawingAbove;
 };
 
-struct NewLayerEntry {
-  NewLayerEntry()
-    : mAnimatedGeometryRoot(nullptr)
-    , mFixedPosFrameForLayerData(nullptr)
-    , mLayerContentsVisibleRect(0, 0, -1, -1)
-    , mHideAllLayersBelow(false)
-    , mOpaqueForAnimatedGeometryRootParent(false)
-  {}
-  // mLayer is null if the previous entry is for a ThebesLayer that hasn't
-  // been optimized to some other form (yet).
-  nsRefPtr<Layer> mLayer;
-  const nsIFrame* mAnimatedGeometryRoot;
-  const nsIFrame* mFixedPosFrameForLayerData;
-  // The following are only used for retained layers (for occlusion
-  // culling of those layers). These regions are all relative to the
-  // container reference frame.
-  nsIntRegion mVisibleRegion;
-  nsIntRegion mOpaqueRegion;
-  // This rect is in the layer's own coordinate space. The computed visible
-  // region for the layer cannot extend beyond this rect.
-  nsIntRect mLayerContentsVisibleRect;
-  bool mHideAllLayersBelow;
-  // When mOpaqueForAnimatedGeometryRootParent is true, the opaque region of
-  // this layer is opaque in the same position even subject to the animation of
-  // geometry of mAnimatedGeometryRoot. For example when mAnimatedGeometryRoot
-  // is a scrolled frame and the scrolled content is opaque everywhere in the
-  // displayport, we can set this flag.
-  // When this flag is set, we can treat this opaque region as covering
-  // content whose animated geometry root is the animated geometry root for
-  // mAnimatedGeometryRoot->GetParent().
-  bool mOpaqueForAnimatedGeometryRootParent;
-};
-
 /**
  * This is a helper object used to build up the layer children for
  * a ContainerLayer.
  */
 class ContainerState {
 public:
   ContainerState(nsDisplayListBuilder* aBuilder,
                  LayerManager* aManager,
                  FrameLayerBuilder* aLayerBuilder,
                  nsIFrame* aContainerFrame,
                  nsDisplayItem* aContainerItem,
-                 const nsRect& aContainerBounds,
                  ContainerLayer* aContainerLayer,
                  const ContainerLayerParameters& aParameters) :
     mBuilder(aBuilder), mManager(aManager),
     mLayerBuilder(aLayerBuilder),
     mContainerFrame(aContainerFrame),
     mContainerLayer(aContainerLayer),
-    mContainerBounds(aContainerBounds),
     mParameters(aParameters),
     mNextFreeRecycledThebesLayer(0)
   {
     nsPresContext* presContext = aContainerFrame->PresContext();
     mAppUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
     mContainerReferenceFrame =
       const_cast<nsIFrame*>(aContainerItem ? aContainerItem->ReferenceFrameForChildren() :
                                              mBuilder->FindReferenceFrameFor(mContainerFrame));
     mContainerAnimatedGeometryRoot = aContainerItem
       ? nsLayoutUtils::GetAnimatedGeometryRootFor(aContainerItem, aBuilder)
       : mContainerReferenceFrame;
-    NS_ASSERTION(!aContainerItem || !aContainerItem->ShouldFixToViewport(aBuilder),
-                 "Container items never return true for ShouldFixToViewport");
-    mContainerFixedPosFrame =
-        FindFixedPosFrameForLayerData(mContainerAnimatedGeometryRoot, false);
     // When AllowResidualTranslation is false, display items will be drawn
     // scaled with a translation by integer pixels, so we know how the snapping
     // will work.
     mSnappingEnabled = aManager->IsSnappingEffectiveTransforms() &&
       !mParameters.AllowResidualTranslation();
     CollectOldLayers();
   }
 
   enum ProcessDisplayItemsFlags {
     NO_COMPONENT_ALPHA = 0x01,
   };
 
   /**
    * This is the method that actually walks a display list and builds
    * the child layers.
    */
-  void ProcessDisplayItems(nsDisplayList* aList, uint32_t aFlags);
+  void ProcessDisplayItems(const nsDisplayList& aList, uint32_t aFlags);
   /**
    * This finalizes all the open ThebesLayers by popping every element off
    * mThebesLayerDataStack, then sets the children of the container layer
    * to be all the layers in mNewChildLayers in that order and removes any
    * layers as children of the container that aren't in mNewChildLayers.
    * @param aTextContentFlags if any child layer has CONTENT_COMPONENT_ALPHA,
    * set *aTextContentFlags to CONTENT_COMPONENT_ALPHA
    */
-  void Finish(uint32_t *aTextContentFlags, LayerManagerData* aData,
-              const nsIntRect& aContainerPixelBounds,
-              nsDisplayList* aChildItems, bool& aHasComponentAlphaChildren);
+  void Finish(uint32_t *aTextContentFlags, LayerManagerData* aData, bool& aHasComponentAlphaChildren);
+
+  nsRect GetChildrenBounds() { return mBounds; }
 
   nscoord GetAppUnitsPerDevPixel() { return mAppUnitsPerDevPixel; }
 
   nsIntRect ScaleToNearestPixels(const nsRect& aRect)
   {
     return aRect.ScaleToNearestPixels(mParameters.mXScale, mParameters.mYScale,
                                       mAppUnitsPerDevPixel);
   }
@@ -625,28 +576,16 @@ public:
   {
     if (aSnap && mSnappingEnabled) {
       return ScaleRegionToNearestPixels(aRegion);
     }
     return aRegion.ScaleToOutsidePixels(mParameters.mXScale, mParameters.mYScale,
                                         mAppUnitsPerDevPixel);
   }
 
-  nsIFrame* GetContainerFrame() const { return mContainerFrame; }
-
-  /**
-   * Sets aOuterVisibleRegion as aLayer's visible region. aOuterVisibleRegion
-   * is in the coordinate space of the container reference frame.
-   * aLayerContentsVisibleRect, if non-null, is in the layer's own
-   * coordinate system.
-   */
-  void SetOuterVisibleRegionForLayer(Layer* aLayer,
-                                     const nsIntRegion& aOuterVisibleRegion,
-                                     const nsIntRect* aLayerContentsVisibleRect = nullptr) const;
-
 protected:
   friend class ThebesLayerData;
 
   /**
    * Grab the next recyclable ThebesLayer, or create one if there are no
    * more recyclable ThebesLayers. Does any necessary invalidation of
    * a recycled ThebesLayer, and sets up the transform on the ThebesLayer
    * to account for scrolling.
@@ -709,46 +648,16 @@ protected:
                                           const nsIntRegion& aDrawRegion,
                                           nsIntRegion* aVisibleRegion,
                                           bool* aIsSolidColorInVisibleRegion = nullptr);
   /**
    * Set fixed-pos layer metadata on aLayer according to the data for aFixedPosFrame.
    */
   void SetFixedPositionLayerData(Layer* aLayer,
                                  const nsIFrame* aFixedPosFrame);
-
-  /**
-   * Returns true if aItem's opaque area (in aOpaque) covers the entire
-   * scrollable area of its presshell.
-   */
-  bool ItemCoversScrollableArea(nsDisplayItem* aItem, const nsRegion& aOpaque);
-
-  /**
-   * For each layer in mNewChildLayers, remove from its visible region the
-   * opaque regions of the layers at higher z-index, but only if they have
-   * the same animated geometry root and fixed-pos frame ancestor.
-   * The opaque region for the child layers that share the same animated
-   * geometry root as the container frame is returned in
-   * *aOpaqueRegionForContainer.
-   */
-  void ApplyOcclusionCulling(nsIntRegion* aOpaqueRegionForContainer);
-
-  /**
-   * Computes the snapped opaque area of aItem. Sets aList's opaque flag
-   * if it covers the entire list bounds. Sets *aHideAllLayersBelow to true
-   * this item covers the entire viewport so that all layers below are
-   * permanently invisible.
-   */
-  nsIntRegion ComputeOpaqueRect(nsDisplayItem* aItem,
-                                const nsIFrame* aAnimatedGeometryRoot,
-                                const nsIFrame* aFixedPosFrame,
-                                const DisplayItemClip& aClip,
-                                nsDisplayList* aList,
-                                bool* aHideAllLayersBelow);
-
   /**
    * Indicate that we are done adding items to the ThebesLayer at the top of
    * mThebesLayerDataStack. Set the final visible region and opaque-content
    * flag, and pop it off the stack.
    */
   void PopThebesLayerData();
   /**
    * Find the ThebesLayer to which we should assign the next display item.
@@ -781,56 +690,47 @@ protected:
         : mThebesLayerDataStack[mThebesLayerDataStack.Length() - 1].get();
   }
 
   /* Build a mask layer to represent the clipping region. Will return null if
    * there is no clipping specified or a mask layer cannot be built.
    * Builds an ImageLayer for the appropriate backend; the mask is relative to
    * aLayer's visible region.
    * aLayer is the layer to be clipped.
-   * aLayerVisibleRegion is the region that will be set as aLayer's visible region,
-   * relative to the container reference frame
    * aRoundedRectClipCount is used when building mask layers for ThebesLayers,
    * SetupMaskLayer will build a mask layer for only the first
    * aRoundedRectClipCount rounded rects in aClip
    */
   void SetupMaskLayer(Layer *aLayer, const DisplayItemClip& aClip,
-                      const nsIntRegion& aLayerVisibleRegion,
                       uint32_t aRoundedRectClipCount = UINT32_MAX);
 
   bool ChooseAnimatedGeometryRoot(const nsDisplayList& aList,
                                   const nsIFrame **aAnimatedGeometryRoot);
 
   nsDisplayListBuilder*            mBuilder;
   LayerManager*                    mManager;
   FrameLayerBuilder*               mLayerBuilder;
   nsIFrame*                        mContainerFrame;
   nsIFrame*                        mContainerReferenceFrame;
   const nsIFrame*                  mContainerAnimatedGeometryRoot;
-  const nsIFrame*                  mContainerFixedPosFrame;
   ContainerLayer*                  mContainerLayer;
-  nsRect                           mContainerBounds;
-  DebugOnly<nsRect>                mAccumulatedChildBounds;
   ContainerLayerParameters         mParameters;
   /**
    * The region of ThebesLayers that should be invalidated every time
    * we recycle one.
    */
   nsIntRegion                      mInvalidThebesContent;
+  nsRect                           mBounds;
   nsAutoTArray<nsAutoPtr<ThebesLayerData>,1>  mThebesLayerDataStack;
   /**
    * We collect the list of children in here. During ProcessDisplayItems,
    * the layers in this array either have mContainerLayer as their parent,
    * or no parent.
-   * ThebesLayers have two entries in this array: the second one is used only if
-   * the ThebesLayer is optimized away to a ColorLayer or ImageLayer.
-   * It's essential that this array is only appended to, since ThebesLayerData
-   * records the index of its ThebesLayer in this array.
    */
-  typedef nsAutoTArray<NewLayerEntry,1> AutoLayersArray;
+  typedef nsAutoTArray<nsRefPtr<Layer>,1> AutoLayersArray;
   AutoLayersArray                  mNewChildLayers;
   nsTArray<nsRefPtr<ThebesLayer> > mRecycledThebesLayers;
   nsDataHashtable<nsPtrHashKey<Layer>, nsRefPtr<ImageLayer> >
     mRecycledMaskImageLayers;
   uint32_t                         mNextFreeRecycledThebesLayer;
   nscoord                          mAppUnitsPerDevPixel;
   bool                             mSnappingEnabled;
 };
@@ -1696,72 +1596,51 @@ AppUnitsPerDevPixel(nsDisplayItem* aItem
   if (aItem->GetType() == nsDisplayItem::TYPE_ZOOM) {
     return static_cast<nsDisplayZoom*>(aItem)->GetParentAppUnitsPerDevPixel();
   }
   return aItem->Frame()->PresContext()->AppUnitsPerDevPixel();
 }
 #endif
 
 /**
- * Set the visible region for aLayer.
- * aOuterVisibleRegion is the visible region relative to the parent layer.
- * aLayerContentsVisibleRect, if non-null, is a rectangle in the layer's
- * own coordinate system to which the layer's visible region is restricted.
- * Consumes *aOuterVisibleRegion.
+ * Restrict the visible region of aLayer to the region that is actually visible.
+ * Because we only reduce the visible region here, we don't need to worry
+ * about whether CONTENT_OPAQUE is set; if layer was opaque in the old
+ * visible region, it will still be opaque in the new one.
+ * @param aLayerVisibleRegion the visible region of the layer, in the layer's
+ * coordinate space
+ * @param aRestrictToRect the rect to restrict the visible region to, in the
+ * parent's coordinate system
  */
 static void
-SetOuterVisibleRegion(Layer* aLayer, nsIntRegion* aOuterVisibleRegion,
-                      const nsIntRect* aLayerContentsVisibleRect = nullptr)
+SetVisibleRegionForLayer(Layer* aLayer, const nsIntRegion& aLayerVisibleRegion,
+                         const nsIntRect& aRestrictToRect)
 {
   gfx3DMatrix transform;
   To3DMatrix(aLayer->GetTransform(), transform);
-  gfxMatrix transform2D;
-  if (transform.Is2D(&transform2D) && !transform2D.HasNonIntegerTranslation()) {
-    aOuterVisibleRegion->MoveBy(-int(transform2D._31), -int(transform2D._32));
-    if (aLayerContentsVisibleRect) {
-      aOuterVisibleRegion->And(*aOuterVisibleRegion, *aLayerContentsVisibleRect);
-    }
+
+  // if 'transform' is not invertible, then nothing will be displayed
+  // for the layer, so it doesn't really matter what we do here
+  gfxRect itemVisible(aRestrictToRect.x, aRestrictToRect.y,
+                      aRestrictToRect.width, aRestrictToRect.height);
+  nsIntRect childBounds = aLayerVisibleRegion.GetBounds();
+  gfxRect childGfxBounds(childBounds.x, childBounds.y,
+                         childBounds.width, childBounds.height);
+  gfxRect layerVisible = transform.Inverse().ProjectRectBounds(itemVisible);
+  layerVisible = layerVisible.Intersect(childGfxBounds);
+  layerVisible.RoundOut();
+
+  nsIntRect visibleRect;
+  if (!gfxUtils::GfxRectToIntRect(layerVisible, &visibleRect)) {
+    aLayer->SetVisibleRegion(nsIntRegion());
   } else {
-    nsIntRect outerRect = aOuterVisibleRegion->GetBounds();
-    // if 'transform' is not invertible, then nothing will be displayed
-    // for the layer, so it doesn't really matter what we do here
-    gfxRect outerVisible(outerRect.x, outerRect.y, outerRect.width, outerRect.height);
-    gfxRect layerVisible = transform.Inverse().ProjectRectBounds(outerVisible);
-    if (aLayerContentsVisibleRect) {
-      NS_ASSERTION(aLayerContentsVisibleRect->width >= 0 &&
-                   aLayerContentsVisibleRect->height >= 0,
-                   "Bad layer contents rectangle");
-      // restrict to aLayerContentsVisibleRect before call GfxRectToIntRect,
-      // in case layerVisible is extremely large (as it can be when
-      // projecting through the inverse of a 3D transform)
-      gfxRect layerContentsVisible(
-          aLayerContentsVisibleRect->x, aLayerContentsVisibleRect->y,
-          aLayerContentsVisibleRect->width, aLayerContentsVisibleRect->height);
-      layerVisible.IntersectRect(layerVisible, layerContentsVisible);
-    }
-    layerVisible.RoundOut();
-    nsIntRect visRect;
-    if (gfxUtils::GfxRectToIntRect(layerVisible, &visRect)) {
-      *aOuterVisibleRegion = visRect;
-    } else  {
-      aOuterVisibleRegion->SetEmpty();
-    }
+    nsIntRegion rgn;
+    rgn.And(aLayerVisibleRegion, visibleRect);
+    aLayer->SetVisibleRegion(rgn);
   }
-
-  aLayer->SetVisibleRegion(*aOuterVisibleRegion);
-}
-
-void
-ContainerState::SetOuterVisibleRegionForLayer(Layer* aLayer,
-                                              const nsIntRegion& aOuterVisibleRegion,
-                                              const nsIntRect* aLayerContentsVisibleRect) const
-{
-  nsIntRegion visRegion = aOuterVisibleRegion;
-  visRegion.MoveBy(mParameters.mOffset);
-  SetOuterVisibleRegion(aLayer, &visRegion, aLayerContentsVisibleRect);
 }
 
 nscolor
 ContainerState::FindOpaqueBackgroundColorFor(int32_t aThebesLayerIndex)
 {
   ThebesLayerData* target = mThebesLayerDataStack[aThebesLayerIndex];
   for (int32_t i = aThebesLayerIndex - 1; i >= 0; --i) {
     ThebesLayerData* candidate = mThebesLayerDataStack[i];
@@ -1960,17 +1839,18 @@ ContainerState::SetFixedPositionLayerDat
   nsLayoutUtils::SetFixedPositionLayerData(aLayer,
       viewportFrame, anchorRect, aFixedPosFrame, presContext, mParameters);
 }
 
 static bool
 CanOptimizeAwayThebesLayer(ThebesLayerData* aData,
                            FrameLayerBuilder* aLayerBuilder)
 {
-  if (!aLayerBuilder->IsBuildingRetainedLayers()) {
+  bool isRetained = aData->mLayer->Manager()->IsWidgetLayerManager();
+  if (!isRetained) {
     return false;
   }
 
   // If there's no thebes layer with valid content in it that we can reuse,
   // always create a color or image layer (and potentially throw away an
   // existing completely invalid thebes layer).
   if (aData->mLayer->GetValidRegion().IsEmpty()) {
     return true;
@@ -1978,45 +1858,31 @@ CanOptimizeAwayThebesLayer(ThebesLayerDa
 
   // There is an existing thebes layer we can reuse. Throwing it away can make
   // compositing cheaper (see bug 946952), but it might cause us to re-allocate
   // the thebes layer frequently due to an animation. So we only discard it if
   // we're in tree compression mode, which is triggered at a low frequency.
   return aLayerBuilder->CheckInLayerTreeCompressionMode();
 }
 
-#ifdef DEBUG
-static int32_t FindIndexOfLayerIn(nsTArray<NewLayerEntry>& aArray,
-                                  Layer* aLayer)
-{
-  for (uint32_t i = 0; i < aArray.Length(); ++i) {
-    if (aArray[i].mLayer == aLayer) {
-      return i;
-    }
-  }
-  return -1;
-}
-#endif
-
 void
 ContainerState::PopThebesLayerData()
 {
   NS_ASSERTION(!mThebesLayerDataStack.IsEmpty(), "Can't pop");
 
   int32_t lastIndex = mThebesLayerDataStack.Length() - 1;
   ThebesLayerData* data = mThebesLayerDataStack[lastIndex];
 
   AdjustLayerDataForFixedPositioning(data->mFixedPosFrameForLayerData,
                                      data->mDrawRegion,
                                      &data->mVisibleRegion,
                                      &data->mIsSolidColorInVisibleRegion);
-
-  NewLayerEntry* newLayerEntry = &mNewChildLayers[data->mNewChildLayersIndex];
   nsRefPtr<Layer> layer;
   nsRefPtr<ImageContainer> imageContainer = data->CanOptimizeImageLayer(mBuilder);
+
   if ((data->mIsSolidColorInVisibleRegion || imageContainer) &&
       CanOptimizeAwayThebesLayer(data, mLayerBuilder)) {
     NS_ASSERTION(!(data->mIsSolidColorInVisibleRegion && imageContainer),
                  "Can't be a solid color as well as an image!");
     if (imageContainer) {
       nsRefPtr<ImageLayer> imageLayer = CreateOrRecycleImageLayer(data->mLayer);
       imageLayer->SetContainer(imageContainer);
       data->mImage->ConfigureLayer(imageLayer, mParameters.mOffset);
@@ -2042,51 +1908,47 @@ ContainerState::PopThebesLayerData()
 
       nsIntRect visibleRect = data->mVisibleRegion.GetBounds();
       visibleRect.MoveBy(-GetTranslationForThebesLayer(data->mLayer));
       colorLayer->SetBounds(visibleRect);
 
       layer = colorLayer;
     }
 
-    NS_ASSERTION(FindIndexOfLayerIn(mNewChildLayers, layer) < 0,
-                 "Layer already in list???");
-    NS_ASSERTION(newLayerEntry->mLayer == data->mLayer,
-                 "Thebes layer at wrong index");
-    // Store optimized layer in reserved slot
-    newLayerEntry = &mNewChildLayers[data->mNewChildLayersIndex + 1];
-    NS_ASSERTION(!newLayerEntry->mLayer, "Slot already occupied?");
-    newLayerEntry->mLayer = layer;
-    newLayerEntry->mAnimatedGeometryRoot = data->mAnimatedGeometryRoot;
-    newLayerEntry->mFixedPosFrameForLayerData = data->mFixedPosFrameForLayerData;
+    NS_ASSERTION(!mNewChildLayers.Contains(layer), "Layer already in list???");
+    AutoLayersArray::index_type index = mNewChildLayers.IndexOf(data->mLayer);
+    NS_ASSERTION(index != AutoLayersArray::NoIndex, "Thebes layer not found?");
+    mNewChildLayers.InsertElementAt(index + 1, layer);
 
     // Hide the ThebesLayer. We leave it in the layer tree so that we
     // can find and recycle it later.
     nsIntRect emptyRect;
     data->mLayer->SetClipRect(&emptyRect);
     data->mLayer->SetVisibleRegion(nsIntRegion());
     data->mLayer->SetEventRegions(EventRegions());
   } else {
     layer = data->mLayer;
     imageContainer = nullptr;
     layer->SetClipRect(nullptr);
   }
 
-  if (mLayerBuilder->IsBuildingRetainedLayers()) {
-    newLayerEntry->mVisibleRegion = data->mVisibleRegion;
-    newLayerEntry->mOpaqueRegion = data->mOpaqueRegion;
-    newLayerEntry->mHideAllLayersBelow = data->mHideAllLayersBelow;
-    if (nsLayoutUtils::GetScrollableFrameFor(newLayerEntry->mAnimatedGeometryRoot) &&
-        !nsDisplayScrollLayer::IsConstructingScrollLayerForScrolledFrame(newLayerEntry->mAnimatedGeometryRoot)) {
-      // Async scrolling not currently active so we can propagate our opaque region
-      // up to the parent animated geometry root.
-      newLayerEntry->mOpaqueForAnimatedGeometryRootParent = true;
-    }
-  } else {
-    SetOuterVisibleRegionForLayer(layer, data->mVisibleRegion);
+  Matrix transform;
+  if (!layer->GetTransform().Is2D(&transform)) {
+    NS_ERROR("Only 2D transformations currently supported");
+  }
+
+  // ImageLayers are already configured with a visible region
+  if (!imageContainer) {
+    NS_ASSERTION(!transform.HasNonIntegerTranslation(),
+                 "Matrix not just an integer translation?");
+    // Convert from relative to the container to relative to the
+    // ThebesLayer itself.
+    nsIntRegion rgn = data->mVisibleRegion;
+    rgn.MoveBy(-GetTranslationForThebesLayer(data->mLayer));
+    layer->SetVisibleRegion(rgn);
   }
 
   nsIntRegion transparentRegion;
   transparentRegion.Sub(data->mVisibleRegion, data->mOpaqueRegion);
   bool isOpaque = transparentRegion.IsEmpty();
   // For translucent ThebesLayers, try to find an opaque background
   // color that covers the entire area beneath it so we can pull that
   // color into this layer to make it opaque.
@@ -2118,24 +1980,24 @@ ContainerState::PopThebesLayerData()
       data->mLayer->InvalidateRegion(data->mLayer->GetValidRegion());
     }
     userData->mForcedBackgroundColor = backgroundColor;
 
     // use a mask layer for rounded rect clipping.
     // data->mCommonClipCount may be -1 if we haven't put any actual
     // drawable items in this layer (i.e. it's only catching events).
     int32_t commonClipCount = std::max(0, data->mCommonClipCount);
-    SetupMaskLayer(layer, data->mItemClip, data->mVisibleRegion, commonClipCount);
+    SetupMaskLayer(layer, data->mItemClip, commonClipCount);
     // copy commonClipCount to the entry
     FrameLayerBuilder::ThebesLayerItemsEntry* entry = mLayerBuilder->
       GetThebesLayerItemsEntry(static_cast<ThebesLayer*>(layer.get()));
     entry->mCommonClipCount = commonClipCount;
   } else {
     // mask layer for image and color layers
-    SetupMaskLayer(layer, data->mItemClip, data->mVisibleRegion);
+    SetupMaskLayer(layer, data->mItemClip);
   }
 
   uint32_t flags = 0;
   nsIWidget* widget = mContainerReferenceFrame->PresContext()->GetRootWidget();
   // See bug 941095. Not quite ready to disable this.
   bool hidpi = false && widget && widget->GetDefaultScale().scale >= 2;
   if (hidpi) {
     flags |= Layer::CONTENT_DISABLE_SUBPIXEL_AA;
@@ -2207,38 +2069,49 @@ ContainerState::PopThebesLayerData()
     ThebesLayerData* nextData = mThebesLayerDataStack[lastIndex - 1];
     nextData->CopyAboveRegion(data);
   }
 
   mThebesLayerDataStack.RemoveElementAt(lastIndex);
 }
 
 static bool
-IsItemAreaInWindowOpaqueRegion(nsDisplayListBuilder* aBuilder,
-                               nsDisplayItem* aItem,
-                               const nsRect& aComponentAlphaBounds)
+SuppressComponentAlpha(nsDisplayListBuilder* aBuilder,
+                       nsDisplayItem* aItem,
+                       const nsRect& aComponentAlphaBounds)
 {
-  if (!aItem->Frame()->PresContext()->IsChrome()) {
-    // Assume that Web content is always in the window opaque region.
-    return true;
+  const nsRegion* windowTransparentRegion = aBuilder->GetFinalTransparentRegion();
+  if (!windowTransparentRegion || windowTransparentRegion->IsEmpty())
+    return false;
+
+  // Suppress component alpha for items in the toplevel window that are over
+  // the window translucent area
+  nsIFrame* f = aItem->Frame();
+  nsIFrame* ref = aBuilder->RootReferenceFrame();
+  if (f->PresContext() != ref->PresContext())
+    return false;
+
+  for (nsIFrame* t = f; t; t = t->GetParent()) {
+    if (t->IsTransformed())
+      return false;
   }
-  if (aItem->ReferenceFrame() != aBuilder->RootReferenceFrame()) {
-    // aItem is probably in some transformed subtree.
-    // We're not going to bother figuring out where this landed, we're just
-    // going to assume it might have landed over a transparent part of
-    // the window.
-    return false;
-  }
-  return aBuilder->GetWindowOpaqueRegion().Contains(aComponentAlphaBounds);
+
+  return windowTransparentRegion->Intersects(aComponentAlphaBounds);
+}
+
+static bool
+WindowHasTransparency(nsDisplayListBuilder* aBuilder)
+{
+  const nsRegion* windowTransparentRegion = aBuilder->GetFinalTransparentRegion();
+  return windowTransparentRegion && !windowTransparentRegion->IsEmpty();
 }
 
 void
 ThebesLayerData::Accumulate(ContainerState* aState,
                             nsDisplayItem* aItem,
-                            const nsIntRegion& aClippedOpaqueRegion,
                             const nsIntRect& aVisibleRect,
                             const nsIntRect& aDrawRect,
                             const DisplayItemClip& aClip)
 {
   if (aState->mBuilder->NeedToForceTransparentSurfaceForItem(aItem)) {
     mForceTransparentSurface = true;
   }
   if (aState->mParameters.mDisableSubpixelAntialiasingInDescendants) {
@@ -2309,46 +2182,57 @@ ThebesLayerData::Accumulate(ContainerSta
     }
 
     mVisibleRegion.Or(mVisibleRegion, aVisibleRect);
     mVisibleRegion.SimplifyOutward(4);
     mDrawRegion.Or(mDrawRegion, aDrawRect);
     mDrawRegion.SimplifyOutward(4);
   }
 
-  if (!aClippedOpaqueRegion.IsEmpty()) {
-    nsIntRegionRectIterator iter(aClippedOpaqueRegion);
-    for (const nsIntRect* r = iter.Next(); r; r = iter.Next()) {
+  bool snap;
+  nsRegion opaque = aItem->GetOpaqueRegion(aState->mBuilder, &snap);
+  if (!opaque.IsEmpty()) {
+    nsRegion opaqueClipped;
+    nsRegionRectIterator iter(opaque);
+    for (const nsRect* r = iter.Next(); r; r = iter.Next()) {
+      opaqueClipped.Or(opaqueClipped, aClip.ApproximateIntersectInward(*r));
+    }
+
+    nsIntRegion opaquePixels = aState->ScaleRegionToInsidePixels(opaqueClipped, snap);
+
+    nsIntRegionRectIterator iter2(opaquePixels);
+    for (const nsIntRect* r = iter2.Next(); r; r = iter2.Next()) {
       // We don't use SimplifyInward here since it's not defined exactly
       // what it will discard. For our purposes the most important case
       // is a large opaque background at the bottom of z-order (e.g.,
       // a canvas background), so we need to make sure that the first rect
       // we see doesn't get discarded.
       nsIntRegion tmp;
       tmp.Or(mOpaqueRegion, *r);
        // Opaque display items in chrome documents whose window is partially
        // transparent are always added to the opaque region. This helps ensure
        // that we get as much subpixel-AA as possible in the chrome.
-       if (tmp.GetNumRects() <= 4 || aItem->Frame()->PresContext()->IsChrome()) {
+       if (tmp.GetNumRects() <= 4 ||
+           (WindowHasTransparency(aState->mBuilder) &&
+            aItem->Frame()->PresContext()->IsChrome())) {
         mOpaqueRegion = tmp;
       }
     }
   }
 
   if (!aState->mParameters.mDisableSubpixelAntialiasingInDescendants) {
     nsRect componentAlpha = aItem->GetComponentAlphaBounds(aState->mBuilder);
     if (!componentAlpha.IsEmpty()) {
       nsIntRect componentAlphaRect =
         aState->ScaleToOutsidePixels(componentAlpha, false).Intersect(aVisibleRect);
       if (!mOpaqueRegion.Contains(componentAlphaRect)) {
-        if (IsItemAreaInWindowOpaqueRegion(aState->mBuilder, aItem,
-              componentAlpha.Intersect(aItem->GetVisibleRect()))) {
+        if (SuppressComponentAlpha(aState->mBuilder, aItem, componentAlpha)) {
+          aItem->DisableComponentAlpha();
+        } else {
           mNeedComponentAlpha = true;
-        } else {
-          aItem->DisableComponentAlpha();
         }
       }
     }
   }
 }
 
 ThebesLayerData*
 ContainerState::FindThebesLayerFor(nsDisplayItem* aItem,
@@ -2415,28 +2299,18 @@ ContainerState::FindThebesLayerFor(nsDis
     mThebesLayerDataStack.AppendElement(thebesLayerData);
     thebesLayerData->mLayer = layer;
     thebesLayerData->mAnimatedGeometryRoot = aAnimatedGeometryRoot;
     thebesLayerData->mFixedPosFrameForLayerData =
       FindFixedPosFrameForLayerData(aAnimatedGeometryRoot, aShouldFixToViewport);
     thebesLayerData->mReferenceFrame = aItem->ReferenceFrame();
     thebesLayerData->mSingleItemFixedToViewport = aShouldFixToViewport;
 
-    NS_ASSERTION(FindIndexOfLayerIn(mNewChildLayers, layer) < 0,
-                 "Layer already in list???");
-    thebesLayerData->mNewChildLayersIndex = mNewChildLayers.Length();
-    NewLayerEntry* newLayerEntry = mNewChildLayers.AppendElement();
-    newLayerEntry->mLayer = layer.forget();
-    newLayerEntry->mAnimatedGeometryRoot = aAnimatedGeometryRoot;
-    newLayerEntry->mFixedPosFrameForLayerData = thebesLayerData->mFixedPosFrameForLayerData;
-    // newLayerEntry->mOpaqueRegion is filled in later from
-    // thebesLayerData->mOpaqueRegion, if necessary.
-
-    // Allocate another entry for this layer's optimization to ColorLayer/ImageLayer
-    mNewChildLayers.AppendElement();
+    NS_ASSERTION(!mNewChildLayers.Contains(layer), "Layer already in list???");
+    *mNewChildLayers.AppendElement() = layer.forget();
   } else {
     thebesLayerData = mThebesLayerDataStack[lowestUsableLayerWithScrolledRoot];
   }
 
   return thebesLayerData;
 }
 
 #ifdef MOZ_DUMP_PAINTING
@@ -2531,168 +2405,53 @@ ContainerState::ChooseAnimatedGeometryRo
     // should result in the least invalidation when scrolling.
     *aAnimatedGeometryRoot =
       nsLayoutUtils::GetAnimatedGeometryRootFor(item, mBuilder);
     return true;
   }
   return false;
 }
 
-/* Checks if aPotentialScrollItem is a scroll layer item and aPotentialScrollbarItem
- * is an overlay scrollbar item for the same scroll frame.
- */
-static bool
-IsScrollLayerItemAndOverlayScrollbarForScrollFrame(
-  nsDisplayItem* aPotentialScrollItem, nsDisplayItem* aPotentialScrollbarItem)
-{
-  if (aPotentialScrollItem->GetType() == nsDisplayItem::TYPE_SCROLL_LAYER &&
-      aPotentialScrollbarItem &&
-      aPotentialScrollbarItem->GetType() == nsDisplayItem::TYPE_OWN_LAYER &&
-      LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars)) {
-    nsDisplayScrollLayer* scrollItem =
-      static_cast<nsDisplayScrollLayer*>(aPotentialScrollItem);
-    nsDisplayOwnLayer* layerItem =
-      static_cast<nsDisplayOwnLayer*>(aPotentialScrollbarItem);
-    if ((layerItem->GetFlags() &
-         (nsDisplayOwnLayer::VERTICAL_SCROLLBAR |
-          nsDisplayOwnLayer::HORIZONTAL_SCROLLBAR)) &&
-        layerItem->Frame()->GetParent() == scrollItem->GetScrollFrame()) {
-      return true;
-    }
-  }
-  return false;
-}
-
-bool
-ContainerState::ItemCoversScrollableArea(nsDisplayItem* aItem, const nsRegion& aOpaque)
-{
-  nsIPresShell* presShell = aItem->Frame()->PresContext()->PresShell();
-  nsIFrame* rootFrame = presShell->GetRootFrame();
-  if (mContainerFrame != rootFrame) {
-    return false;
-  }
-  nsRect scrollableArea;
-  if (presShell->IsScrollPositionClampingScrollPortSizeSet()) {
-    scrollableArea = nsRect(nsPoint(0, 0),
-      presShell->GetScrollPositionClampingScrollPortSize());
-  } else {
-    scrollableArea = rootFrame->GetRectRelativeToSelf();
-  }
-  return aOpaque.Contains(scrollableArea);
-}
-
-nsIntRegion
-ContainerState::ComputeOpaqueRect(nsDisplayItem* aItem,
-                                  const nsIFrame* aAnimatedGeometryRoot,
-                                  const nsIFrame* aFixedPosFrame,
-                                  const DisplayItemClip& aClip,
-                                  nsDisplayList* aList,
-                                  bool* aHideAllLayersBelow)
-{
-  bool snapOpaque;
-  nsRegion opaque = aItem->GetOpaqueRegion(mBuilder, &snapOpaque);
-  nsIntRegion opaquePixels;
-  if (!opaque.IsEmpty()) {
-    nsRegion opaqueClipped;
-    nsRegionRectIterator iter(opaque);
-    for (const nsRect* r = iter.Next(); r; r = iter.Next()) {
-      opaqueClipped.Or(opaqueClipped, aClip.ApproximateIntersectInward(*r));
-    }
-    if (aAnimatedGeometryRoot == mContainerAnimatedGeometryRoot &&
-        aFixedPosFrame == mContainerFixedPosFrame &&
-        !aList->IsOpaque() &&
-        opaqueClipped.Contains(mContainerBounds)) {
-      aList->SetIsOpaque();
-    }
-    // Add opaque areas to the "exclude glass" region. Only do this for
-    // ThebesLayers which are direct children of the root layer; this means
-    // they can't have transforms or opacity wrapping them.
-    if (!mContainerLayer->GetParent()) {
-      mBuilder->AddWindowOpaqueRegion(opaqueClipped);
-    }
-    opaquePixels = ScaleRegionToInsidePixels(opaqueClipped, snapOpaque);
-    if (aFixedPosFrame && ItemCoversScrollableArea(aItem, opaque)) {
-      *aHideAllLayersBelow = true;
-    }
-  }
-  return opaquePixels;
-}
-
 /*
  * Iterate through the non-clip items in aList and its descendants.
  * For each item we compute the effective clip rect. Each item is assigned
  * to a layer. We invalidate the areas in ThebesLayers where an item
  * has moved from one ThebesLayer to another. Also,
  * aState->mInvalidThebesContent is invalidated in every ThebesLayer.
  * We set the clip rect for items that generated their own layer, and
  * create a mask layer to do any rounded rect clipping.
  * (ThebesLayers don't need a clip rect on the layer, we clip the items
  * individually when we draw them.)
  * We set the visible rect for all layers, although the actual setting
  * of visible rects for some ThebesLayers is deferred until the calling
  * of ContainerState::Finish.
  */
 void
-ContainerState::ProcessDisplayItems(nsDisplayList* aList,
+ContainerState::ProcessDisplayItems(const nsDisplayList& aList,
                                     uint32_t aFlags)
 {
   PROFILER_LABEL("ContainerState", "ProcessDisplayItems",
     js::ProfileEntry::Category::GRAPHICS);
 
   const nsIFrame* lastAnimatedGeometryRoot = mContainerReferenceFrame;
   nsPoint topLeft(0,0);
 
   // When NO_COMPONENT_ALPHA is set, items will be flattened into a single
   // layer, so we need to choose which active scrolled root to use for all
   // items.
   if (aFlags & NO_COMPONENT_ALPHA) {
-    if (ChooseAnimatedGeometryRoot(*aList, &lastAnimatedGeometryRoot)) {
+    if (ChooseAnimatedGeometryRoot(aList, &lastAnimatedGeometryRoot)) {
       topLeft = lastAnimatedGeometryRoot->GetOffsetToCrossDoc(mContainerReferenceFrame);
     }
   }
 
   int32_t maxLayers = nsDisplayItem::MaxActiveLayers();
   int layerCount = 0;
 
-  nsDisplayList savedItems;
-  nsDisplayItem* item;
-  while ((item = aList->RemoveBottom()) != nullptr) {
-    // Peek ahead to the next item and try merging with it or swapping with it
-    // if necessary.
-    nsDisplayItem* aboveItem;
-    while ((aboveItem = aList->GetBottom()) != nullptr) {
-      if (aboveItem->TryMerge(mBuilder, item)) {
-        aList->RemoveBottom();
-        item->~nsDisplayItem();
-        item = aboveItem;
-      } else if (IsScrollLayerItemAndOverlayScrollbarForScrollFrame(aboveItem, item)) {
-        // If an overlay scrollbar item is between a scroll layer item and the
-        // other scroll layer items that we need to merge with just move the
-        // scrollbar item up, that way it will be on top of the scrolled content
-        // and we can try to merge all the scroll layer items.
-        aList->RemoveBottom();
-        aList->AppendToBottom(item);
-        item = aboveItem;
-      } else {
-        break;
-      }
-    }
-
-    nsDisplayList* itemSameCoordinateSystemChildren
-      = item->GetSameCoordinateSystemChildren();
-    if (itemSameCoordinateSystemChildren) {
-      if (item->ShouldFlattenAway(mBuilder)) {
-        aList->AppendToBottom(itemSameCoordinateSystemChildren);
-        item->~nsDisplayItem();
-        continue;
-      }
-    }
-
-    savedItems.AppendToTop(item);
-
+  for (nsDisplayItem* item = aList.GetBottom(); item; item = item->GetAbove()) {
     NS_ASSERTION(mAppUnitsPerDevPixel == AppUnitsPerDevPixel(item),
       "items in a container layer should all have the same app units per dev pixel");
 
     nsIntRect itemVisibleRect =
       ScaleToOutsidePixels(item->GetVisibleRect(), false);
     bool snap;
     nsRect itemContent = item->GetBounds(mBuilder, &snap);
     nsIntRect itemDrawRect = ScaleToOutsidePixels(itemContent, snap);
@@ -2700,19 +2459,17 @@ ContainerState::ProcessDisplayItems(nsDi
     nsIntRect clipRect;
     const DisplayItemClip& itemClip = item->GetClip();
     if (itemClip.HasClip()) {
       itemContent.IntersectRect(itemContent, itemClip.GetClipRect());
       clipRect = ScaleToNearestPixels(itemClip.GetClipRect());
       itemDrawRect.IntersectRect(itemDrawRect, clipRect);
       clipRect.MoveBy(mParameters.mOffset);
     }
-#ifdef DEBUG
-    ((nsRect&)mAccumulatedChildBounds).UnionRect(mAccumulatedChildBounds, itemContent);
-#endif
+    mBounds.UnionRect(mBounds, itemContent);
     itemVisibleRect.IntersectRect(itemVisibleRect, itemDrawRect);
 
     LayerState layerState = item->GetLayerState(mBuilder, mManager, mParameters);
     if (layerState == LAYER_INACTIVE &&
         nsDisplayItem::ForceActiveLayers()) {
       layerState = LAYER_ACTIVE;
     }
 
@@ -2768,22 +2525,23 @@ ContainerState::ProcessDisplayItems(nsDi
       // 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() &&
           !item->ShouldBuildLayerEvenIfInvisible(mBuilder)) {
         continue;
       }
 
+      if (itemType == nsDisplayItem::TYPE_TRANSFORM) {
+        mParameters.mAncestorClipRect = itemClip.HasClip() ? &clipRect : nullptr;
+      } else {
+        mParameters.mAncestorClipRect = nullptr;
+      }
+
       // Just use its layer.
-      // Set layerContentsVisibleRect.width/height to -1 to indicate we
-      // currently don't know. If BuildContainerLayerFor gets called by
-      // item->BuildLayer, this will be set to a proper rect.
-      nsIntRect layerContentsVisibleRect(0, 0, -1, -1);
-      mParameters.mLayerContentsVisibleRect = &layerContentsVisibleRect;
       nsRefPtr<Layer> ownLayer = item->BuildLayer(mBuilder, mManager, mParameters);
       if (!ownLayer) {
         continue;
       }
 
       NS_ASSERTION(!ownLayer->AsThebesLayer(),
                    "Should never have created a dedicated Thebes layer!");
 
@@ -2823,17 +2581,17 @@ ContainerState::ProcessDisplayItems(nsDi
         ownLayer->SetClipRect(nullptr);
       }
       ThebesLayerData* data = GetTopThebesLayerData();
       if (data) {
         // Prerendered transform items can be updated without layer building
         // (async animations or an empty transaction), so we need to put items
         // that the transform item can potentially move under into a layer
         // above this item.
-        if (itemType == nsDisplayItem::TYPE_TRANSFORM &&
+        if (item->GetType() == nsDisplayItem::TYPE_TRANSFORM &&
             nsDisplayTransform::ShouldPrerenderTransformedContent(mBuilder,
                                                                   item->Frame(),
                                                                   false)) {
           if (!itemClip.HasClip()) {
             // The transform item can move anywhere, treat all other content
             // as being above this item.
             data->SetAllDrawingAbove();
           } else {
@@ -2848,102 +2606,72 @@ ContainerState::ProcessDisplayItems(nsDi
 
           // Add the entire bounds rect to the mDrawAboveRegion.
           // The visible region may be excluding opaque content above the
           // item, and we need to ensure that that content is not placed
           // in a ThebesLayer below the item!
           data->AddDrawAboveRegion(itemDrawRect);
         }
       }
+      itemVisibleRect.MoveBy(mParameters.mOffset);
+      if (item->SetVisibleRegionOnLayer()) {
+        SetVisibleRegionForLayer(ownLayer, ownLayer->GetVisibleRegion(), itemVisibleRect);
+      }
 
       // rounded rectangle clipping using mask layers
       // (must be done after visible rect is set on layer)
       if (itemClip.IsRectClippedByRoundedCorner(itemContent)) {
-        SetupMaskLayer(ownLayer, itemClip, itemVisibleRect);
+        SetupMaskLayer(ownLayer, itemClip);
       }
 
       ContainerLayer* oldContainer = ownLayer->GetParent();
       if (oldContainer && oldContainer != mContainerLayer) {
         oldContainer->RemoveChild(ownLayer);
       }
-      NS_ASSERTION(FindIndexOfLayerIn(mNewChildLayers, ownLayer) < 0,
+      NS_ASSERTION(!mNewChildLayers.Contains(ownLayer),
                    "Layer already in list???");
 
-      NewLayerEntry* newLayerEntry = mNewChildLayers.AppendElement();
-      newLayerEntry->mLayer = ownLayer;
-      newLayerEntry->mAnimatedGeometryRoot = animatedGeometryRoot;
-      newLayerEntry->mFixedPosFrameForLayerData = fixedPosFrame;
-      // nsDisplayTransform::BuildLayer must set layerContentsVisibleRect.
-      // We rely on this to ensure 3D transforms compute a reasonable
-      // layer visible region.
-      NS_ASSERTION(itemType != nsDisplayItem::TYPE_TRANSFORM ||
-                   layerContentsVisibleRect.width >= 0,
-                   "Transform items must set layerContentsVisibleRect!");
-      if (mLayerBuilder->IsBuildingRetainedLayers()) {
-        newLayerEntry->mLayerContentsVisibleRect = layerContentsVisibleRect;
-        newLayerEntry->mVisibleRegion = itemVisibleRect;
-        newLayerEntry->mOpaqueRegion = ComputeOpaqueRect(item,
-          animatedGeometryRoot, fixedPosFrame, itemClip, aList,
-          &newLayerEntry->mHideAllLayersBelow);
-      } else {
-        SetOuterVisibleRegionForLayer(ownLayer, itemVisibleRect,
-            layerContentsVisibleRect.width >= 0 ? &layerContentsVisibleRect : nullptr);
-      }
-      if (itemType == nsDisplayItem::TYPE_SCROLL_LAYER) {
-        nsDisplayScrollLayer* scrollItem = static_cast<nsDisplayScrollLayer*>(item);
-        newLayerEntry->mOpaqueForAnimatedGeometryRootParent =
-            scrollItem->IsDisplayPortOpaque();
-      }
+      mNewChildLayers.AppendElement(ownLayer);
 
       /**
        * No need to allocate geometry for items that aren't
        * part of a ThebesLayer.
        */
       nsAutoPtr<nsDisplayItemGeometry> dummy;
       mLayerBuilder->AddLayerDisplayItem(ownLayer, item,
                                          itemClip, layerState,
                                          topLeft, nullptr,
                                          dummy);
     } else {
-      ThebesLayerData* thebesLayerData =
+      ThebesLayerData* data =
         FindThebesLayerFor(item, itemVisibleRect, animatedGeometryRoot, topLeft,
                            shouldFixToViewport);
 
       if (itemType == nsDisplayItem::TYPE_LAYER_EVENT_REGIONS) {
         nsDisplayLayerEventRegions* eventRegions =
             static_cast<nsDisplayLayerEventRegions*>(item);
-        thebesLayerData->AccumulateEventRegions(eventRegions->HitRegion(),
-                                                eventRegions->MaybeHitRegion(),
-                                                eventRegions->DispatchToContentHitRegion());
+        data->AccumulateEventRegions(eventRegions->HitRegion(),
+                                     eventRegions->MaybeHitRegion(),
+                                     eventRegions->DispatchToContentHitRegion());
       } else {
         // check to see if the new item has rounded rect clips in common with
         // other items in the layer
-        thebesLayerData->UpdateCommonClipCount(itemClip);
+        data->UpdateCommonClipCount(itemClip);
+        data->Accumulate(this, item, itemVisibleRect, itemDrawRect, itemClip);
 
         nsAutoPtr<nsDisplayItemGeometry> geometry(item->AllocateGeometry(mBuilder));
-        InvalidateForLayerChange(item, thebesLayerData->mLayer, itemClip, topLeft, geometry);
-
-        mLayerBuilder->AddThebesDisplayItem(thebesLayerData, item, itemClip, itemVisibleRect,
-                                            *this, layerState, topLeft, geometry);
-        nsIntRegion opaquePixels = ComputeOpaqueRect(item,
-            animatedGeometryRoot, thebesLayerData->mFixedPosFrameForLayerData,
-            itemClip, aList,
-            &thebesLayerData->mHideAllLayersBelow);
-        thebesLayerData->Accumulate(this, item, opaquePixels,
-            itemVisibleRect, itemDrawRect, itemClip);
+        InvalidateForLayerChange(item, data->mLayer, itemClip, topLeft, geometry);
+
+        mLayerBuilder->AddThebesDisplayItem(data, item, itemClip,
+                                            mContainerFrame,
+                                            layerState, topLeft,
+                                            geometry);
       }
     }
-
-    if (itemSameCoordinateSystemChildren &&
-        itemSameCoordinateSystemChildren->NeedsTransparentSurface()) {
-      aList->SetNeedsTransparentSurface();
-    }
   }
-
-  aList->AppendToTop(&savedItems);
 }
 
 void
 ContainerState::InvalidateForLayerChange(nsDisplayItem* aItem,
                                          Layer* aNewLayer,
                                          const DisplayItemClip& aClip,
                                          const nsPoint& aTopLeft,
                                          nsDisplayItemGeometry *aGeometry)
@@ -3075,18 +2803,17 @@ ContainerState::InvalidateForLayerChange
         GetTranslationForThebesLayer(newThebesLayer));
   }
 }
 
 void
 FrameLayerBuilder::AddThebesDisplayItem(ThebesLayerData* aLayerData,
                                         nsDisplayItem* aItem,
                                         const DisplayItemClip& aClip,
-                                        const nsIntRect& aItemVisibleRect,
-                                        const ContainerState& aContainerState,
+                                        nsIFrame* aContainerLayerFrame,
                                         LayerState aLayerState,
                                         const nsPoint& aTopLeft,
                                         nsAutoPtr<nsDisplayItemGeometry> aGeometry)
 {
   ThebesLayer* layer = aLayerData->mLayer;
   ThebesDisplayItemLayerUserData* thebesData =
     static_cast<ThebesDisplayItemLayerUserData*>
       (layer->GetUserData(&gThebesDisplayItemLayerUserData));
@@ -3116,17 +2843,17 @@ FrameLayerBuilder::AddThebesDisplayItem(
                                                       thebesData->mAppUnitsPerDevPixel);
     }
   }
 
   AddLayerDisplayItem(layer, aItem, aClip, aLayerState, aTopLeft, tempManager, aGeometry);
 
   ThebesLayerItemsEntry* entry = mThebesLayerItems.PutEntry(layer);
   if (entry) {
-    entry->mContainerLayerFrame = aContainerState.GetContainerFrame();
+    entry->mContainerLayerFrame = aContainerLayerFrame;
     if (entry->mContainerLayerGeneration == 0) {
       entry->mContainerLayerGeneration = mContainerLayerGeneration;
     }
     if (tempManager) {
       FrameLayerBuilder* layerBuilder = new FrameLayerBuilder();
       layerBuilder->Init(mDisplayListBuilder, tempManager, aLayerData);
 
       tempManager->BeginTransaction();
@@ -3140,22 +2867,16 @@ FrameLayerBuilder::AddThebesDisplayItem(
       // We have no easy way of detecting if this transaction will ever actually get finished.
       // For now, I've just silenced the warning with nested transactions in BasicLayers.cpp
       if (!tmpLayer) {
         tempManager->EndTransaction(nullptr, nullptr);
         tempManager->SetUserData(&gLayerManagerLayerBuilder, nullptr);
         return;
       }
 
-      bool snap;
-      nsRect visibleRect =
-        aItem->GetVisibleRect().Intersect(aItem->GetBounds(mDisplayListBuilder, &snap));
-      nsIntRegion rgn = visibleRect.ToOutsidePixels(thebesData->mAppUnitsPerDevPixel);
-      SetOuterVisibleRegion(tmpLayer, &rgn);
-
       // 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*>
           (layer->Manager()->GetUserData(&gLayerManagerUserData));
         LayerManagerData* lmd = static_cast<LayerManagerData*>
           (tempManager->GetUserData(&gLayerManagerUserData));
@@ -3338,137 +3059,31 @@ ContainerState::CollectOldLayers()
     if (Layer* maskLayer = layer->GetMaskLayer()) {
       NS_ASSERTION(maskLayer->GetType() == Layer::TYPE_IMAGE,
                    "Could not recycle mask layer, unsupported layer type.");
       mRecycledMaskImageLayers.Put(layer, static_cast<ImageLayer*>(maskLayer));
     }
   }
 }
 
-struct OpaqueRegionEntry {
-  const nsIFrame* mAnimatedGeometryRoot;
-  const nsIFrame* mFixedPosFrameForLayerData;
-  nsIntRegion mOpaqueRegion;
-};
-
-static OpaqueRegionEntry*
-FindOpaqueRegionEntry(nsTArray<OpaqueRegionEntry>& aEntries,
-                      const nsIFrame* aAnimatedGeometryRoot,
-                      const nsIFrame* aFixedPosFrameForLayerData)
-{
-  for (uint32_t i = 0; i < aEntries.Length(); ++i) {
-    OpaqueRegionEntry* d = &aEntries[i];
-    if (d->mAnimatedGeometryRoot == aAnimatedGeometryRoot &&
-        d->mFixedPosFrameForLayerData == aFixedPosFrameForLayerData) {
-      return d;
-    }
-  }
-  return nullptr;
-}
-
 void
-ContainerState::ApplyOcclusionCulling(nsIntRegion* aOpaqueRegionForContainer)
-{
-  nsAutoTArray<OpaqueRegionEntry,4> opaqueRegions;
-  bool hideAll = false;
-  int32_t opaqueRegionForContainer = -1;
-
-  for (int32_t i = mNewChildLayers.Length() - 1; i >= 0; --i) {
-    NewLayerEntry* e = &mNewChildLayers.ElementAt(i);
-    if (!e->mLayer) {
-      continue;
-    }
-
-    OpaqueRegionEntry* data = FindOpaqueRegionEntry(opaqueRegions,
-        e->mAnimatedGeometryRoot, e->mFixedPosFrameForLayerData);
-
-    if (hideAll) {
-      e->mVisibleRegion.SetEmpty();
-    } else if (data) {
-      e->mVisibleRegion.Sub(e->mVisibleRegion, data->mOpaqueRegion);
-    }
-
-    if (!e->mOpaqueRegion.IsEmpty()) {
-      const nsIFrame* animatedGeometryRootToCover = e->mAnimatedGeometryRoot;
-      if (e->mOpaqueForAnimatedGeometryRootParent &&
-          nsLayoutUtils::GetAnimatedGeometryRootForFrame(e->mAnimatedGeometryRoot->GetParent(),
-                                                         mContainerAnimatedGeometryRoot)
-            == mContainerAnimatedGeometryRoot) {
-        animatedGeometryRootToCover = mContainerAnimatedGeometryRoot;
-        data = FindOpaqueRegionEntry(opaqueRegions,
-            animatedGeometryRootToCover, e->mFixedPosFrameForLayerData);
-      }
-
-      if (!data) {
-        if (animatedGeometryRootToCover == mContainerAnimatedGeometryRoot &&
-            !e->mFixedPosFrameForLayerData) {
-          NS_ASSERTION(opaqueRegionForContainer == -1, "Already found it?");
-          opaqueRegionForContainer = opaqueRegions.Length();
-        }
-        data = opaqueRegions.AppendElement();
-        data->mAnimatedGeometryRoot = animatedGeometryRootToCover;
-        data->mFixedPosFrameForLayerData = e->mFixedPosFrameForLayerData;
-      }
-      data->mOpaqueRegion.Or(data->mOpaqueRegion, e->mOpaqueRegion);
-      if (e->mHideAllLayersBelow) {
-        hideAll = true;
-      }
-    }
-
-    SetOuterVisibleRegionForLayer(e->mLayer, e->mVisibleRegion,
-	  e->mLayerContentsVisibleRect.width >= 0 ? &e->mLayerContentsVisibleRect : nullptr);
-
-    if (e->mLayer->GetType() == Layer::TYPE_READBACK) {
-      // ReadbackLayers need to accurately read what's behind them. So,
-      // we don't want to do any occlusion culling of layers behind them.
-      // Theoretically we could just punch out the ReadbackLayer's rectangle
-      // from all mOpaqueRegions, but that's probably not worth doing.
-      opaqueRegions.Clear();
-      opaqueRegionForContainer = -1;
-    }
-  }
-
-  if (opaqueRegionForContainer >= 0) {
-    aOpaqueRegionForContainer->Or(*aOpaqueRegionForContainer,
-        opaqueRegions[opaqueRegionForContainer].mOpaqueRegion);
-  }
-}
-
-void
-ContainerState::Finish(uint32_t* aTextContentFlags, LayerManagerData* aData,
-                       const nsIntRect& aContainerPixelBounds,
-                       nsDisplayList* aChildItems, bool& aHasComponentAlphaChildren)
+ContainerState::Finish(uint32_t* aTextContentFlags, LayerManagerData* aData, bool& aHasComponentAlphaChildren)
 {
   while (!mThebesLayerDataStack.IsEmpty()) {
     PopThebesLayerData();
   }
 
-  NS_ASSERTION(mContainerBounds.IsEqualInterior(mAccumulatedChildBounds),
-               "Bounds computation mismatch");
-
-  if (mLayerBuilder->IsBuildingRetainedLayers()) {
-    nsIntRegion containerOpaqueRegion;
-    ApplyOcclusionCulling(&containerOpaqueRegion);
-    if (containerOpaqueRegion.Contains(aContainerPixelBounds)) {
-      aChildItems->SetIsOpaque();
-    }
-  }
-
   uint32_t textContentFlags = 0;
 
   // Make sure that current/existing layers are added to the parent and are
   // in the correct order.
   Layer* layer = nullptr;
-  Layer* prevChild = nullptr;
-  for (uint32_t i = 0; i < mNewChildLayers.Length(); ++i, prevChild = layer) {
-    if (!mNewChildLayers[i].mLayer) {
-      continue;
-    }
-
-    layer = mNewChildLayers[i].mLayer;
+  for (uint32_t i = 0; i < mNewChildLayers.Length(); ++i) {
+    Layer* prevChild = i == 0 ? nullptr : mNewChildLayers[i - 1].get();
+    layer = mNewChildLayers[i];
 
     if (!layer->GetVisibleRegion().IsEmpty()) {
       textContentFlags |=
         layer->GetContentFlags() & (Layer::CONTENT_COMPONENT_ALPHA |
                                     Layer::CONTENT_COMPONENT_ALPHA_DESCENDANT);
 
       // Notify the parent of component alpha children unless it's coming from
       // within a transformed child since we don't want flattening of component
@@ -3658,18 +3273,18 @@ ChooseScaleAndSetTransform(FrameLayerBui
   aOutgoingScale =
     ContainerLayerParameters(scale.width, scale.height, -offset, aIncomingScale);
   if (aTransform) {
     aOutgoingScale.mInTransformedSubtree = true;
     if (ActiveLayerTracker::IsStyleAnimated(aContainerFrame, eCSSProperty_transform)) {
       aOutgoingScale.mInActiveTransformedSubtree = true;
     }
   }
-  if (aLayerBuilder->IsBuildingRetainedLayers() &&
-      (!canDraw2D || transform2d.HasNonIntegerTranslation())) {
+  bool isRetained = aLayer->Manager()->IsWidgetLayerManager();
+  if (isRetained && (!canDraw2D || transform2d.HasNonIntegerTranslation())) {
     aOutgoingScale.mDisableSubpixelAntialiasingInDescendants = true;
   }
   return true;
 }
 
 /* static */ PLDHashOperator
 FrameLayerBuilder::RestoreDisplayItemData(nsRefPtrHashKey<DisplayItemData>* aEntry, void* aUserArg)
 {
@@ -3705,17 +3320,17 @@ FrameLayerBuilder::RestoreThebesLayerIte
   return PL_DHASH_NEXT;
 }
 
 already_AddRefed<ContainerLayer>
 FrameLayerBuilder::BuildContainerLayerFor(nsDisplayListBuilder* aBuilder,
                                           LayerManager* aManager,
                                           nsIFrame* aContainerFrame,
                                           nsDisplayItem* aContainerItem,
-                                          nsDisplayList* aChildren,
+                                          const nsDisplayList& aChildren,
                                           const ContainerLayerParameters& aParameters,
                                           const gfx3DMatrix* aTransform,
                                           uint32_t aFlags)
 {
   uint32_t containerDisplayItemKey =
     aContainerItem ? aContainerItem->GetPerFrameKey() : nsDisplayItem::TYPE_ZERO;
   NS_ASSERTION(aContainerFrame, "Container display items here should have a frame");
   NS_ASSERTION(!aContainerItem ||
@@ -3769,29 +3384,23 @@ FrameLayerBuilder::BuildContainerLayerFo
     state = LAYER_ACTIVE;
   }
 
   if (aContainerItem && state == LAYER_ACTIVE_EMPTY) {
     // Empty layers only have metadata and should never have display items. We
     // early exit because later, invalidation will walk up the frame tree to
     // determine which thebes layer gets invalidated. Since an empty layer
     // should never have anything to paint, it should never be invalidated.
-    NS_ASSERTION(aChildren->IsEmpty(), "Should have no children");
+    NS_ASSERTION(aChildren.IsEmpty(), "Should have no children");
     return containerLayer.forget();
   }
 
   ContainerLayerParameters scaleParameters;
-  nsRect bounds = aChildren->GetBounds(aBuilder);
-  nsRect childrenVisible =
-      aContainerItem ? aContainerItem->GetVisibleRectForChildren() :
-          aContainerFrame->GetVisualOverflowRectRelativeToSelf();
-  if (!ChooseScaleAndSetTransform(this, aBuilder, aContainerFrame,
-                                  bounds.Intersect(childrenVisible),
-                                  aTransform, aParameters,
-                                  containerLayer, state, scaleParameters)) {
+  if (!ChooseScaleAndSetTransform(this, aBuilder, aContainerFrame, aChildren.GetVisibleRect(),
+                                  aTransform, aParameters, containerLayer, state, scaleParameters)) {
     return nullptr;
   }
 
   uint32_t oldGeneration = mContainerLayerGeneration;
   mContainerLayerGeneration = ++mMaxContainerLayerGeneration;
 
   nsRefPtr<RefCountedRegion> thebesLayerInvalidRegion = nullptr;
   if (mRetainingManager) {
@@ -3800,38 +3409,40 @@ FrameLayerBuilder::BuildContainerLayerFo
     } else {
       StoreDataForFrame(aContainerFrame, containerDisplayItemKey, containerLayer, LAYER_ACTIVE);
     }
   }
 
   LayerManagerData* data = static_cast<LayerManagerData*>
     (aManager->GetUserData(&gLayerManagerUserData));
 
+  nsRect bounds;
   nsIntRect pixBounds;
-  nscoord appUnitsPerDevPixel;
+  int32_t appUnitsPerDevPixel;
   uint32_t stateFlags = 0;
   if ((aContainerFrame->GetStateBits() & NS_FRAME_NO_COMPONENT_ALPHA) &&
       mRetainingManager && mRetainingManager->ShouldAvoidComponentAlphaLayers()) {
     stateFlags = ContainerState::NO_COMPONENT_ALPHA;
   }
   uint32_t flags;
   while (true) {
     ContainerState state(aBuilder, aManager, aManager->GetLayerBuilder(),
-                         aContainerFrame, aContainerItem, bounds,
+                         aContainerFrame, aContainerItem,
                          containerLayer, scaleParameters);
 
     state.ProcessDisplayItems(aChildren, stateFlags);
 
     // Set CONTENT_COMPONENT_ALPHA if any of our children have it.
     // This is suboptimal ... a child could have text that's over transparent
     // pixels in its own layer, but over opaque parts of previous siblings.
     bool hasComponentAlphaChildren = false;
+    state.Finish(&flags, data, hasComponentAlphaChildren);
+    bounds = state.GetChildrenBounds();
     pixBounds = state.ScaleToOutsidePixels(bounds, false);
     appUnitsPerDevPixel = state.GetAppUnitsPerDevPixel();
-    state.Finish(&flags, data, pixBounds, aChildren, hasComponentAlphaChildren);
 
     if (hasComponentAlphaChildren &&
         mRetainingManager &&
         mRetainingManager->ShouldAvoidComponentAlphaLayers() &&
         containerLayer->HasMultipleChildren() &&
         !stateFlags) {
       // Since we don't want any component alpha layers on BasicLayers, we repeat
       // the layer building process with this explicitely forced off.
@@ -3843,44 +3454,45 @@ FrameLayerBuilder::BuildContainerLayerFo
       mThebesLayerItems.EnumerateEntries(RestoreThebesLayerItemEntries,
                                          &mContainerLayerGeneration);
       aContainerFrame->AddStateBits(NS_FRAME_NO_COMPONENT_ALPHA);
       continue;
     }
     break;
   }
 
+  NS_ASSERTION(bounds.IsEqualInterior(aChildren.GetBounds(aBuilder)), "Wrong bounds");
+  pixBounds.MoveBy(nsIntPoint(scaleParameters.mOffset.x, scaleParameters.mOffset.y));
+  if (aParameters.mAncestorClipRect && !(aFlags & CONTAINER_NOT_CLIPPED_BY_ANCESTORS)) {
+    SetVisibleRegionForLayer(containerLayer, nsIntRegion(pixBounds),
+                             *aParameters.mAncestorClipRect);
+  } else {
+    containerLayer->SetVisibleRegion(pixBounds);
+  }
+
   // CONTENT_COMPONENT_ALPHA is propogated up to the nearest CONTENT_OPAQUE
   // ancestor so that BasicLayerManager knows when to copy the background into
   // pushed groups. Accelerated layers managers can't necessarily do this (only
   // when the visible region is a simple rect), so we propogate
   // CONTENT_COMPONENT_ALPHA_DESCENDANT all the way to the root.
   if (flags & Layer::CONTENT_COMPONENT_ALPHA) {
     flags |= Layer::CONTENT_COMPONENT_ALPHA_DESCENDANT;
   }
 
   // Make sure that rounding the visible region out didn't add any area
   // we won't paint
-  if (aChildren->IsOpaque() && !aChildren->NeedsTransparentSurface()) {
+  if (aChildren.IsOpaque() && !aChildren.NeedsTransparentSurface()) {
     bounds.ScaleRoundIn(scaleParameters.mXScale, scaleParameters.mYScale);
     if (bounds.Contains(pixBounds.ToAppUnits(appUnitsPerDevPixel))) {
       // Clear CONTENT_COMPONENT_ALPHA and add CONTENT_OPAQUE instead.
       flags &= ~Layer::CONTENT_COMPONENT_ALPHA;
       flags |= Layer::CONTENT_OPAQUE;
     }
   }
   containerLayer->SetContentFlags(flags);
-  // If aContainerItem is non-null some BuildContainerLayer further up the
-  // call stack is responsible for setting containerLayer's visible region.
-  if (!aContainerItem) {
-    containerLayer->SetVisibleRegion(pixBounds);
-  }
-  if (aParameters.mLayerContentsVisibleRect) {
-    *aParameters.mLayerContentsVisibleRect = pixBounds + scaleParameters.mOffset;
-  }
 
   mContainerLayerGeneration = oldGeneration;
   nsPresContext::ClearNotifySubDocInvalidationData(containerLayer);
 
   return containerLayer.forget();
 }
 
 Layer*
@@ -4052,18 +3664,21 @@ FrameLayerBuilder::RecomputeVisibilityFo
                                                nsDisplayListBuilder *aBuilder,
                                                const nsIntRegion& aRegionToDraw,
                                                const nsIntPoint& aOffset,
                                                int32_t aAppUnitsPerDevPixel,
                                                float aXScale,
                                                float aYScale)
 {
   uint32_t i;
-  // Update visible regions. We perform visibility analysis to take account
-  // of occlusion culling.
+  // Update visible regions. We need perform visibility analysis again
+  // because we may be asked to draw into part of a ThebesLayer that
+  // isn't actually visible in the window (e.g., because a ThebesLayer
+  // expanded its visible region to a rectangle internally), in which
+  // case the mVisibleRect stored in the display item may be wrong.
   nsRegion visible = aRegionToDraw.ToAppUnits(aAppUnitsPerDevPixel);
   visible.MoveBy(NSIntPixelsToAppUnits(aOffset.x, aAppUnitsPerDevPixel),
                  NSIntPixelsToAppUnits(aOffset.y, aAppUnitsPerDevPixel));
   visible.ScaleInverseRoundOut(aXScale, aYScale);
 
   for (i = aItems.Length(); i > 0; --i) {
     ClippedDisplayItem* cdi = &aItems[i - 1];
     const DisplayItemClip& clip = cdi->mItem->GetClip();
@@ -4284,27 +3899,23 @@ FrameLayerBuilder::DrawThebesLayer(Thebe
 
     DrawForcedBackgroundColor(aContext, aLayer, userData->mForcedBackgroundColor);
   }
 
   // make the origin of the context coincide with the origin of the
   // ThebesLayer
   gfxContextMatrixAutoSaveRestore saveMatrix(aContext);
   nsIntPoint offset = GetTranslationForThebesLayer(aLayer);
+
   nsPresContext* presContext = entry->mContainerLayerFrame->PresContext();
-
-  if (!layerBuilder->GetContainingThebesLayerData()) {
-    // Recompute visibility of items in our ThebesLayer. Note that this
-    // recomputes visibility for all descendants of our display items too,
-    // so there's no need to do this for the items in inactive ThebesLayers.
-    int32_t appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
-    RecomputeVisibilityForItems(entry->mItems, builder, aRegionToDraw,
-                                offset, appUnitsPerDevPixel,
-                                userData->mXScale, userData->mYScale);
-  }
+  int32_t appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
+
+  RecomputeVisibilityForItems(entry->mItems, builder, aRegionToDraw,
+                              offset, appUnitsPerDevPixel,
+                              userData->mXScale, userData->mYScale);
 
   nsRefPtr<nsRenderingContext> rc = new nsRenderingContext();
   rc->Init(presContext->DeviceContext(), aContext);
 
   if (shouldDrawRectsSeparately) {
     nsIntRegionRectIterator it(aRegionToDraw);
     while (const nsIntRect* iterRect = it.Next()) {
       gfxContextAutoSaveRestore save(aContext);
@@ -4398,33 +4009,31 @@ SetClipCount(ThebesDisplayItemLayerUserD
              uint32_t aClipCount)
 {
   if (aThebesData) {
     aThebesData->mMaskClipCount = aClipCount;
   }
 }
 
 void
-ContainerState::SetupMaskLayer(Layer *aLayer,
-                               const DisplayItemClip& aClip,
-                               const nsIntRegion& aLayerVisibleRegion,
+ContainerState::SetupMaskLayer(Layer *aLayer, const DisplayItemClip& aClip,
                                uint32_t aRoundedRectClipCount)
 {
   // if the number of clips we are going to mask has decreased, then aLayer might have
   // cached graphics which assume the existence of a soon-to-be non-existent mask layer
   // in that case, invalidate the whole layer.
   ThebesDisplayItemLayerUserData* thebesData = GetThebesDisplayItemLayerUserData(aLayer);
   if (thebesData &&
       aRoundedRectClipCount < thebesData->mMaskClipCount) {
     ThebesLayer* thebes = aLayer->AsThebesLayer();
     thebes->InvalidateRegion(thebes->GetValidRegion().GetBounds());
   }
 
   // don't build an unnecessary mask
-  nsIntRect layerBounds = aLayerVisibleRegion.GetBounds();
+  nsIntRect layerBounds = aLayer->GetVisibleRegion().GetBounds();
   if (aClip.GetRoundedRectCount() == 0 ||
       aRoundedRectClipCount == 0 ||
       layerBounds.IsEmpty()) {
     SetClipCount(thebesData, 0);
     return;
   }
 
   // check if we can re-use the mask layer
--- a/layout/base/FrameLayerBuilder.h
+++ b/layout/base/FrameLayerBuilder.h
@@ -27,17 +27,16 @@ class ContainerLayer;
 class LayerManager;
 class BasicLayerManager;
 class ThebesLayer;
 }
 
 class FrameLayerBuilder;
 class LayerManagerData;
 class ThebesLayerData;
-class ContainerState;
 
 enum LayerState {
   LAYER_NONE,
   LAYER_INACTIVE,
   LAYER_ACTIVE,
   // Force an active layer even if it causes incorrect rendering, e.g.
   // when the layer has rounded rect clips.
   LAYER_ACTIVE_FORCE,
@@ -53,54 +52,44 @@ private:
 public:
   NS_INLINE_DECL_REFCOUNTING(RefCountedRegion)
 
   RefCountedRegion() : mIsInfinite(false) {}
   nsRegion mRegion;
   bool mIsInfinite;
 };
 
-struct NewLayerEntry;
-
 struct ContainerLayerParameters {
-  ContainerLayerParameters()
-    : mXScale(1)
-    , mYScale(1)
-    , mLayerContentsVisibleRect(nullptr)
-    , mInTransformedSubtree(false)
-    , mInActiveTransformedSubtree(false)
-    , mDisableSubpixelAntialiasingInDescendants(false)
+  ContainerLayerParameters() :
+    mXScale(1), mYScale(1), mAncestorClipRect(nullptr),
+    mInTransformedSubtree(false), mInActiveTransformedSubtree(false),
+    mDisableSubpixelAntialiasingInDescendants(false)
   {}
-  ContainerLayerParameters(float aXScale, float aYScale)
-    : mXScale(aXScale)
-    , mYScale(aYScale)
-    , mLayerContentsVisibleRect(nullptr)
-    , mInTransformedSubtree(false)
-    , mInActiveTransformedSubtree(false)
-    , mDisableSubpixelAntialiasingInDescendants(false)
+  ContainerLayerParameters(float aXScale, float aYScale) :
+    mXScale(aXScale), mYScale(aYScale), mAncestorClipRect(nullptr),
+    mInTransformedSubtree(false), mInActiveTransformedSubtree(false),
+    mDisableSubpixelAntialiasingInDescendants(false)
   {}
   ContainerLayerParameters(float aXScale, float aYScale,
                            const nsIntPoint& aOffset,
-                           const ContainerLayerParameters& aParent)
-    : mXScale(aXScale)
-    , mYScale(aYScale)
-    , mLayerContentsVisibleRect(nullptr)
-    , mOffset(aOffset)
-    , mInTransformedSubtree(aParent.mInTransformedSubtree)
-    , mInActiveTransformedSubtree(aParent.mInActiveTransformedSubtree)
-    , mDisableSubpixelAntialiasingInDescendants(aParent.mDisableSubpixelAntialiasingInDescendants)
+                           const ContainerLayerParameters& aParent) :
+    mXScale(aXScale), mYScale(aYScale), mAncestorClipRect(nullptr),
+    mOffset(aOffset),
+    mInTransformedSubtree(aParent.mInTransformedSubtree),
+    mInActiveTransformedSubtree(aParent.mInActiveTransformedSubtree),
+    mDisableSubpixelAntialiasingInDescendants(aParent.mDisableSubpixelAntialiasingInDescendants)
   {}
   float mXScale, mYScale;
   /**
-   * If non-null, the rectangle in which BuildContainerLayerFor stores the
-   * visible rect of the layer, in the coordinate system of the created layer.
+   * An ancestor clip rect that can be applied to restrict the visibility
+   * of this container. Null if none available.
    */
-  nsIntRect* mLayerContentsVisibleRect;
+  const nsIntRect* mAncestorClipRect;
   /**
-   * An offset to apply to all child layers created.
+   * An offset to append to the transform set on all child layers created.
    */
   nsIntPoint mOffset;
 
   bool mInTransformedSubtree;
   bool mInActiveTransformedSubtree;
   bool mDisableSubpixelAntialiasingInDescendants;
   /**
    * When this is false, ThebesLayer coordinates are drawn to with an integer
@@ -213,26 +202,23 @@ public:
    * items in the display list, making items with their own layers
    * children of the new container, and assigning all other items to
    * ThebesLayer children created and managed by the FrameLayerBuilder.
    * Returns a layer with clip rect cleared; it is the
    * caller's responsibility to add any clip rect. The visible region
    * is set based on what's in the layer.
    * The container layer is transformed by aTransform (if non-null), and
    * the result is transformed by the scale factors in aContainerParameters.
-   * aChildren is modified due to display item merging and flattening.
-   * The visible region of the returned layer is set only if aContainerItem
-   * is null.
    */
   already_AddRefed<ContainerLayer>
   BuildContainerLayerFor(nsDisplayListBuilder* aBuilder,
                          LayerManager* aManager,
                          nsIFrame* aContainerFrame,
                          nsDisplayItem* aContainerItem,
-                         nsDisplayList* aChildren,
+                         const nsDisplayList& aChildren,
                          const ContainerLayerParameters& aContainerParameters,
                          const gfx3DMatrix* aTransform,
                          uint32_t aFlags = 0);
 
   /**
    * Get a retained layer for a display item that needs to create its own
    * layer for rendering (i.e. under nsDisplayItem::BuildLayer). Returns
    * null if no retained layer is available, which usually means that this
@@ -308,18 +294,17 @@ public:
    * aLayer, with aClipRect, where aContainerLayerFrame is the frame
    * for the container layer this ThebesItem belongs to.
    * aItem must have an underlying frame.
    * @param aTopLeft offset from active scrolled root to reference frame
    */
   void AddThebesDisplayItem(ThebesLayerData* aLayer,
                             nsDisplayItem* aItem,
                             const DisplayItemClip& aClip,
-                            const nsIntRect& aItemVisibleRect,
-                            const ContainerState& aContainerState,
+                            nsIFrame* aContainerLayerFrame,
                             LayerState aLayerState,
                             const nsPoint& aTopLeft,
                             nsAutoPtr<nsDisplayItemGeometry> aGeometry);
 
   /**
    * Gets the frame property descriptor for the given manager, or for the current
    * widget layer manager if nullptr is passed.
    */
@@ -606,21 +591,16 @@ public:
     return mThebesLayerItems.GetEntry(aLayer);
   }
 
   ThebesLayerData* GetContainingThebesLayerData()
   {
     return mContainingThebesLayer;
   }
 
-  bool IsBuildingRetainedLayers()
-  {
-    return !mContainingThebesLayer && mRetainingManager;
-  }
-
   /**
    * Attempt to build the most compressed layer tree possible, even if it means
    * throwing away existing retained buffers.
    */
   void SetLayerTreeCompressionMode() { mInLayerTreeCompressionMode = true; }
   bool CheckInLayerTreeCompressionMode();
 
 protected:
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -486,35 +486,37 @@ nsDisplayListBuilder::AddAnimationsAndTr
 }
 
 nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
     Mode aMode, bool aBuildCaret)
     : mReferenceFrame(aReferenceFrame),
       mIgnoreScrollFrame(nullptr),
       mLayerEventRegions(nullptr),
       mCurrentTableItem(nullptr),
-      mCurrentFrame(aReferenceFrame),
-      mCurrentReferenceFrame(aReferenceFrame),
-      mDirtyRect(-1,-1,-1,-1),
+      mFinalTransparentRegion(nullptr),
+      mCachedOffsetFrame(aReferenceFrame),
+      mCachedReferenceFrame(aReferenceFrame),
+      mCachedOffset(0, 0),
       mGlassDisplayItem(nullptr),
       mMode(aMode),
       mCurrentScrollParentId(FrameMetrics::NULL_SCROLL_ID),
       mCurrentScrollbarTarget(FrameMetrics::NULL_SCROLL_ID),
       mCurrentScrollbarFlags(0),
       mBuildCaret(aBuildCaret),
       mIgnoreSuppression(false),
       mHadToIgnoreSuppression(false),
       mIsAtRootOfPseudoStackingContext(false),
       mIncludeAllOutOfFlows(false),
       mDescendIntoSubdocuments(true),
       mSelectedFramesOnly(false),
       mAccurateVisibleRegions(false),
       mAllowMergingAndFlattening(true),
       mWillComputePluginGeometry(false),
       mInTransform(false),
+      mInFixedPos(false),
       mSyncDecodeImages(false),
       mIsPaintingToWindow(false),
       mIsCompositingCheap(false),
       mContainsPluginItem(false),
       mAncestorHasTouchEventHandler(false),
       mHaveScrollableDisplayPort(false)
 {
   MOZ_COUNT_CTOR(nsDisplayListBuilder);
@@ -610,24 +612,29 @@ static void UnmarkFrameForDisplay(nsIFra
     f->RemoveStateBits(NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO);
   }
 }
 
 static void RecordFrameMetrics(nsIFrame* aForFrame,
                                nsIFrame* aScrollFrame,
                                const nsIFrame* aReferenceFrame,
                                ContainerLayer* aRoot,
+                               const nsRect& aVisibleRect,
                                const nsRect& aViewport,
                                bool aForceNullScrollId,
                                bool aIsRoot,
                                const ContainerLayerParameters& aContainerParameters) {
   nsPresContext* presContext = aForFrame->PresContext();
   int32_t auPerDevPixel = presContext->AppUnitsPerDevPixel();
   LayoutDeviceToLayerScale resolution(aContainerParameters.mXScale, aContainerParameters.mYScale);
 
+  nsIntRect visible = aVisibleRect.ScaleToNearestPixels(
+    resolution.scale, resolution.scale, auPerDevPixel);
+  aRoot->SetVisibleRegion(visible);
+
   nsIPresShell* presShell = presContext->GetPresShell();
   FrameMetrics metrics;
   metrics.mViewport = CSSRect::FromAppUnits(aViewport);
 
   ViewID scrollId = FrameMetrics::NULL_SCROLL_ID;
   nsIContent* content = aScrollFrame ? aScrollFrame->GetContent() : nullptr;
   if (content) {
     if (!aForceNullScrollId) {
@@ -875,21 +882,21 @@ nsDisplayListBuilder::GetCaret() {
   nsRefPtr<nsCaret> caret = CurrentPresShellState()->mPresShell->GetCaret();
   return caret;
 }
 
 void
 nsDisplayListBuilder::EnterPresShell(nsIFrame* aReferenceFrame,
                                      const nsRect& aDirtyRect) {
   PresShellState* state = mPresShellStates.AppendElement();
+  if (!state)
+    return;
   state->mPresShell = aReferenceFrame->PresContext()->PresShell();
   state->mCaretFrame = nullptr;
   state->mFirstFrameMarkedForDisplay = mFramesMarkedForDisplay.Length();
-  state->mPrevDirtyRect = mDirtyRect;
-  mDirtyRect = aDirtyRect;
 
   state->mPresShell->UpdateCanvasBackground();
 
   if (mIsPaintingToWindow) {
     mReferenceFrame->AddPaintedPresShell(state->mPresShell);
 
     state->mPresShell->IncrementPaintCount();
   }
@@ -923,20 +930,22 @@ nsDisplayListBuilder::EnterPresShell(nsI
       MarkFrameForDisplay(state->mCaretFrame, nullptr);
     }
   }
 }
 
 void
 nsDisplayListBuilder::LeavePresShell(nsIFrame* aReferenceFrame,
                                      const nsRect& aDirtyRect) {
-  NS_ASSERTION(CurrentPresShellState()->mPresShell ==
-      aReferenceFrame->PresContext()->PresShell(),
-      "Presshell mismatch");
-  mDirtyRect = CurrentPresShellState()->mPrevDirtyRect;
+  if (CurrentPresShellState()->mPresShell != aReferenceFrame->PresContext()->PresShell()) {
+    // Must have not allocated a state for this presshell, presumably due
+    // to OOM.
+    return;
+  }
+
   ResetMarkedFramesForDisplayList();
   mPresShellStates.SetLength(mPresShellStates.Length() - 1);
 }
 
 void
 nsDisplayListBuilder::ResetMarkedFramesForDisplayList()
 {
   // Unmark and pop off the frames marked for display in this pres shell.
@@ -1011,53 +1020,50 @@ void nsDisplayListSet::MoveTo(const nsDi
   aDestination.BorderBackground()->AppendToTop(BorderBackground());
   aDestination.BlockBorderBackgrounds()->AppendToTop(BlockBorderBackgrounds());
   aDestination.Floats()->AppendToTop(Floats());
   aDestination.Content()->AppendToTop(Content());
   aDestination.PositionedDescendants()->AppendToTop(PositionedDescendants());
   aDestination.Outlines()->AppendToTop(Outlines());
 }
 
-static void
-MoveListTo(nsDisplayList* aList, nsTArray<nsDisplayItem*>* aElements) {
+void
+nsDisplayList::FlattenTo(nsTArray<nsDisplayItem*>* aElements) {
   nsDisplayItem* item;
-  while ((item = aList->RemoveBottom()) != nullptr) {
-    aElements->AppendElement(item);
+  while ((item = RemoveBottom()) != nullptr) {
+    if (item->GetType() == nsDisplayItem::TYPE_WRAP_LIST) {
+      item->GetSameCoordinateSystemChildren()->FlattenTo(aElements);
+      item->~nsDisplayItem();
+    } else {
+      aElements->AppendElement(item);
+    }
   }
 }
 
 nsRect
 nsDisplayList::GetBounds(nsDisplayListBuilder* aBuilder) const {
   nsRect bounds;
   for (nsDisplayItem* i = GetBottom(); i != nullptr; i = i->GetAbove()) {
     bounds.UnionRect(bounds, i->GetClippedBounds(aBuilder));
   }
   return bounds;
 }
 
-nsRect
-nsDisplayList::GetVisibleRect() const {
-  nsRect result;
-  for (nsDisplayItem* i = GetBottom(); i != nullptr; i = i->GetAbove()) {
-    result.UnionRect(result, i->GetVisibleRect());
-  }
-  return result;
-}
-
 bool
 nsDisplayList::ComputeVisibilityForRoot(nsDisplayListBuilder* aBuilder,
                                         nsRegion* aVisibleRegion,
                                         nsIFrame* aDisplayPortFrame) {
   PROFILER_LABEL("nsDisplayList", "ComputeVisibilityForRoot",
     js::ProfileEntry::Category::GRAPHICS);
 
   nsRegion r;
   r.And(*aVisibleRegion, GetBounds(aBuilder));
   return ComputeVisibilityForSublist(aBuilder, aVisibleRegion,
-                                     r.GetBounds(), aDisplayPortFrame);
+                                     r.GetBounds(), r.GetBounds(),
+                                     aDisplayPortFrame);
 }
 
 static nsRegion
 TreatAsOpaque(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder)
 {
   bool snap;
   nsRegion opaque = aItem->GetOpaqueRegion(aBuilder, &snap);
   if (aBuilder->IsForPluginGeometry()) {
@@ -1082,72 +1088,176 @@ TreatAsOpaque(nsDisplayItem* aItem, nsDi
   nsRegion opaqueClipped;
   nsRegionRectIterator iter(opaque);
   for (const nsRect* r = iter.Next(); r; r = iter.Next()) {
     opaqueClipped.Or(opaqueClipped, aItem->GetClip().ApproximateIntersectInward(*r));
   }
   return opaqueClipped;
 }
 
+/* Checks if aPotentialScrollItem is a scroll layer item and aPotentialScrollbarItem
+ * is an overlay scrollbar item for the same scroll frame.
+ */
+static bool
+IsScrollLayerItemAndOverlayScrollbarForScrollFrame(
+  nsDisplayItem* aPotentialScrollItem, nsDisplayItem* aPotentialScrollbarItem)
+{
+  if (aPotentialScrollItem->GetType() == nsDisplayItem::TYPE_SCROLL_LAYER &&
+      aPotentialScrollbarItem &&
+      aPotentialScrollbarItem->GetType() == nsDisplayItem::TYPE_OWN_LAYER &&
+      LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars)) {
+    nsDisplayScrollLayer* scrollItem =
+      static_cast<nsDisplayScrollLayer*>(aPotentialScrollItem);
+    nsDisplayOwnLayer* layerItem =
+      static_cast<nsDisplayOwnLayer*>(aPotentialScrollbarItem);
+    if ((layerItem->GetFlags() &
+         (nsDisplayOwnLayer::VERTICAL_SCROLLBAR |
+          nsDisplayOwnLayer::HORIZONTAL_SCROLLBAR)) &&
+        layerItem->Frame()->GetParent() == scrollItem->GetScrollFrame()) {
+      return true;
+    }
+  }
+  return false;
+}
+
 bool
 nsDisplayList::ComputeVisibilityForSublist(nsDisplayListBuilder* aBuilder,
                                            nsRegion* aVisibleRegion,
                                            const nsRect& aListVisibleBounds,
+                                           const nsRect& aAllowVisibleRegionExpansion,
                                            nsIFrame* aDisplayPortFrame) {
 #ifdef DEBUG
   nsRegion r;
   r.And(*aVisibleRegion, GetBounds(aBuilder));
   NS_ASSERTION(r.GetBounds().IsEqualInterior(aListVisibleBounds),
                "bad aListVisibleBounds");
 #endif
 
+  mVisibleRect = aListVisibleBounds;
   bool anyVisible = false;
 
   nsAutoTArray<nsDisplayItem*, 512> elements;
-  MoveListTo(this, &elements);
+  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];
+
+    nsDisplayList* list = item->GetSameCoordinateSystemChildren();
+    if (aBuilder->AllowMergingAndFlattening()) {
+      if (belowItem && item->TryMerge(aBuilder, belowItem)) {
+        belowItem->~nsDisplayItem();
+        elements.ReplaceElementsAt(i - 1, 1, item);
+        continue;
+      }
+
+      // If an overlay scrollbar item is between a scroll layer item and the
+      // other scroll layer items that we need to merge with just move the
+      // scrollbar item up, that way it will be on top of the scrolled content
+      // and we can try to merge all the scroll layer items.
+      if (IsScrollLayerItemAndOverlayScrollbarForScrollFrame(item, belowItem)) {
+        elements[i] = belowItem;
+        elements[i-1] = item;
+        i++;
+        continue;
+      }
+
+      if (list && item->ShouldFlattenAway(aBuilder)) {
+        // The elements on the list >= i no longer serve any use.
+        elements.SetLength(i);
+        list->FlattenTo(&elements);
+        i = elements.Length();
+        item->~nsDisplayItem();
+        continue;
+      }
+    }
+
     nsRect bounds = item->GetClippedBounds(aBuilder);
 
     nsRegion itemVisible;
     itemVisible.And(*aVisibleRegion, bounds);
     item->mVisibleRect = itemVisible.GetBounds();
 
-    if (item->ComputeVisibility(aBuilder, aVisibleRegion)) {
+    if (item->ComputeVisibility(aBuilder, aVisibleRegion,
+                                aAllowVisibleRegionExpansion.Intersect(bounds))) {
       anyVisible = true;
 
+      // If we're in a displayport, we need to make sure that fixed position
+      // items do not subtract from the visible region, as async scrolling
+      // may expose these occluded areas.
+      // If the item is fixed pos in the same document as the displayport
+      // then don't let it occlude this list. The only other case possible
+      // is that the fixed pos content is in a child document, in which it
+      // would scroll with the rest of the content.
+      bool occlude = true;
+      nsIPresShell* presShell = nullptr;
+      if (aDisplayPortFrame && item->IsInFixedPos()) {
+        if (item->Frame()->PresContext() == aDisplayPortFrame->PresContext()) {
+          occlude = false;
+          presShell = aDisplayPortFrame->PresContext()->PresShell();
+        }
+      }
+
       nsRegion opaque = TreatAsOpaque(item, aBuilder);
-      // Subtract opaque item from the visible region
-      aBuilder->SubtractFromVisibleRegion(aVisibleRegion, opaque);
+      if (occlude) {
+        // Subtract opaque item from the visible region
+        aBuilder->SubtractFromVisibleRegion(aVisibleRegion, opaque);
+      } else if (presShell &&
+                 presShell->IsScrollPositionClampingScrollPortSizeSet() &&
+                 !opaque.IsEmpty()) {
+        // We make an exception if the fixed position item would fully occlude
+        // the scroll position clamping scroll-port. In that case, it's very
+        // unlikely that it will become visible via async scrolling, so we let
+        // it occlude.
+        nsRect scrollClampingScrollPort(nsPoint(0, 0),
+          presShell->GetScrollPositionClampingScrollPortSize());
+        if (opaque.Contains(scrollClampingScrollPort)) {
+          aVisibleRegion->SetEmpty();
+        }
+      }
+
+      if (aBuilder->NeedToForceTransparentSurfaceForItem(item) ||
+          (list && list->NeedsTransparentSurface())) {
+        forceTransparentSurface = true;
+      }
     }
     AppendToBottom(item);
   }
 
-  mIsOpaque = !aVisibleRegion->Intersects(aListVisibleBounds);
+  mIsOpaque = !aVisibleRegion->Intersects(mVisibleRect);
+  mForceTransparentSurface = forceTransparentSurface;
+#if defined(DEBUG) || defined(MOZ_DUMP_PAINTING)
+  mDidComputeVisibility = true;
+#endif
   return anyVisible;
 }
 
 void nsDisplayList::PaintRoot(nsDisplayListBuilder* aBuilder,
                               nsRenderingContext* aCtx,
-                              uint32_t aFlags) {
+                              uint32_t aFlags) const {
   PROFILER_LABEL("nsDisplayList", "PaintRoot",
     js::ProfileEntry::Category::GRAPHICS);
+
   PaintForFrame(aBuilder, aCtx, aBuilder->RootReferenceFrame(), aFlags);
 }
 
 /**
  * We paint by executing a layer manager transaction, constructing a
  * single layer representing the display list, and then making it the
  * root of the layer manager, drawing into the ThebesLayers.
  */
 void nsDisplayList::PaintForFrame(nsDisplayListBuilder* aBuilder,
                                   nsRenderingContext* aCtx,
                                   nsIFrame* aForFrame,
-                                  uint32_t aFlags) {
+                                  uint32_t aFlags) const {
+  NS_ASSERTION(mDidComputeVisibility,
+               "Must call ComputeVisibility before calling Paint");
+
   nsRefPtr<LayerManager> layerManager;
   bool widgetTransaction = false;
   bool allowRetaining = false;
   bool doBeginTransaction = true;
   nsView *view = nullptr;
   if (aFlags & PAINT_USE_WIDGET_LAYERS) {
     nsIFrame* rootReferenceFrame = aBuilder->RootReferenceFrame();
     view = rootReferenceFrame->GetView();
@@ -1206,17 +1316,17 @@ void nsDisplayList::PaintForFrame(nsDisp
 
   nsAutoPtr<LayerProperties> props(computeInvalidRect ? 
                                      LayerProperties::CloneFrom(layerManager->GetRoot()) : 
                                      nullptr);
 
   ContainerLayerParameters containerParameters
     (presShell->GetXResolution(), presShell->GetYResolution());
   nsRefPtr<ContainerLayer> root = layerBuilder->
-    BuildContainerLayerFor(aBuilder, layerManager, aForFrame, nullptr, this,
+    BuildContainerLayerFor(aBuilder, layerManager, aForFrame, nullptr, *this,
                            containerParameters, nullptr);
 
   nsIDocument* document = nullptr;
   if (presShell) {
     document = presShell->GetDocument();
   }
 
   if (widgetTransaction ||
@@ -1245,17 +1355,17 @@ void nsDisplayList::PaintForFrame(nsDisp
       usingDisplayport = nsLayoutUtils::GetDisplayPort(content, nullptr);
     }
   }
 
   nsRect viewport(aBuilder->ToReferenceFrame(aForFrame), aForFrame->GetSize());
 
   RecordFrameMetrics(aForFrame, rootScrollFrame,
                      aBuilder->FindReferenceFrameFor(aForFrame),
-                     root, viewport,
+                     root, mVisibleRect, viewport,
                      !isRoot, isRoot, containerParameters);
   if (usingDisplayport &&
       !(root->GetContentFlags() & Layer::CONTENT_OPAQUE)) {
     // See bug 693938, attachment 567017
     NS_WARNING("Transparent content with displayports can be expensive.");
   }
 
   layerManager->SetRoot(root);
@@ -1609,17 +1719,18 @@ nsDisplayItem::ZIndex() const
     return position->mZIndex.GetIntValue();
 
   // sort the auto and 0 elements together
   return 0;
 }
 
 bool
 nsDisplayItem::ComputeVisibility(nsDisplayListBuilder* aBuilder,
-                                 nsRegion* aVisibleRegion)
+                                 nsRegion* aVisibleRegion,
+                                 const nsRect& aAllowVisibleRegionExpansion)
 {
   return !mVisibleRect.IsEmpty() &&
     !IsInvisibleInRect(aVisibleRegion->GetBounds());
 }
 
 bool
 nsDisplayItem::RecomputeVisibility(nsDisplayListBuilder* aBuilder,
                                    nsRegion* aVisibleRegion) {
@@ -1627,20 +1738,18 @@ nsDisplayItem::RecomputeVisibility(nsDis
 
   nsRegion itemVisible;
   itemVisible.And(*aVisibleRegion, bounds);
   mVisibleRect = itemVisible.GetBounds();
 
   // When we recompute visibility within layers we don't need to
   // expand the visible region for content behind plugins (the plugin
   // is not in the layer).
-  if (!ComputeVisibility(aBuilder, aVisibleRegion)) {
-    mVisibleRect = nsRect();
+  if (!ComputeVisibility(aBuilder, aVisibleRegion, nsRect()))
     return false;
-  }
 
   nsRegion opaque = TreatAsOpaque(this, aBuilder);
   aBuilder->SubtractFromVisibleRegion(aVisibleRegion, opaque);
   return true;
 }
 
 nsRect
 nsDisplayItem::GetClippedBounds(nsDisplayListBuilder* aBuilder)
@@ -2025,34 +2134,37 @@ nsDisplayBackgroundImage::ConfigureLayer
   NS_ASSERTION(imageSize.width != 0 && imageSize.height != 0, "Invalid image size!");
 
   gfxPoint p = mDestRect.TopLeft() + aOffset;
   gfx::Matrix transform;
   transform.Translate(p.x, p.y);
   transform.Scale(mDestRect.width/imageSize.width,
                   mDestRect.height/imageSize.height);
   aLayer->SetBaseTransform(gfx::Matrix4x4::From2D(transform));
+  aLayer->SetVisibleRegion(nsIntRect(0, 0, imageSize.width, imageSize.height));
 }
 
 void
 nsDisplayBackgroundImage::HitTest(nsDisplayListBuilder* aBuilder,
                                   const nsRect& aRect,
                                   HitTestState* aState,
                                   nsTArray<nsIFrame*> *aOutFrames)
 {
   if (RoundedBorderIntersectsRect(mFrame, ToReferenceFrame(), aRect)) {
     aOutFrames->AppendElement(mFrame);
   }
 }
 
 bool
 nsDisplayBackgroundImage::ComputeVisibility(nsDisplayListBuilder* aBuilder,
-                                            nsRegion* aVisibleRegion)
+                                            nsRegion* aVisibleRegion,
+                                            const nsRect& aAllowVisibleRegionExpansion)
 {
-  if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion)) {
+  if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion,
+                                        aAllowVisibleRegionExpansion)) {
     return false;
   }
 
   // Return false if the background was propagated away from this
   // frame. We don't want this display item to show up and confuse
   // anything.
   return mBackgroundStyle;
 }
@@ -2139,16 +2251,33 @@ bool
 nsDisplayBackgroundImage::IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) {
   if (!mBackgroundStyle) {
     *aColor = NS_RGBA(0,0,0,0);
     return true;
   }
   return false;
 }
 
+bool
+nsDisplayBackgroundImage::IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuilder,
+                                                         nsIFrame* aFrame)
+{
+  if (!mBackgroundStyle)
+    return false;
+  if (!mBackgroundStyle->HasFixedBackground())
+    return false;
+
+  // If aFrame is mFrame or an ancestor in this document, and aFrame is
+  // not the viewport frame, then moving aFrame will move mFrame
+  // relative to the viewport, so our fixed-pos background will change.
+  return aFrame->GetParent() &&
+    (aFrame == mFrame ||
+     nsLayoutUtils::IsProperAncestorFrame(aFrame, mFrame));
+}
+
 nsRect
 nsDisplayBackgroundImage::GetPositioningArea()
 {
   if (!mBackgroundStyle) {
     return nsRect();
   }
   nsIFrame* attachedToFrame;
   return nsCSSRendering::ComputeBackgroundPositioningArea(
@@ -2787,18 +2916,20 @@ nsDisplayBoxShadowOuter::IsInvisibleInRe
   if (!hasBorderRadii)
     return true;
 
   return RoundedRectContainsRect(frameRect, twipsRadii, aRect);
 }
 
 bool
 nsDisplayBoxShadowOuter::ComputeVisibility(nsDisplayListBuilder* aBuilder,
-                                           nsRegion* aVisibleRegion) {
-  if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion)) {
+                                           nsRegion* aVisibleRegion,
+                                           const nsRect& aAllowVisibleRegionExpansion) {
+  if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion,
+                                        aAllowVisibleRegionExpansion)) {
     return false;
   }
 
   // Store the actual visible region
   mVisibleRegion.And(*aVisibleRegion, mVisibleRect);
   return true;
 }
 
@@ -2847,130 +2978,139 @@ nsDisplayBoxShadowInner::Paint(nsDisplay
     nsCSSRendering::PaintBoxShadowInner(presContext, *aCtx, mFrame,
                                         borderRect, rects[i]);
     aCtx->PopState();
   }
 }
 
 bool
 nsDisplayBoxShadowInner::ComputeVisibility(nsDisplayListBuilder* aBuilder,
-                                           nsRegion* aVisibleRegion) {
-  if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion)) {
+                                           nsRegion* aVisibleRegion,
+                                           const nsRect& aAllowVisibleRegionExpansion) {
+  if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion,
+                                        aAllowVisibleRegionExpansion)) {
     return false;
   }
 
   // Store the actual visible region
   mVisibleRegion.And(*aVisibleRegion, mVisibleRect);
   return true;
 }
 
 nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder,
                                      nsIFrame* aFrame, nsDisplayList* aList)
   : nsDisplayItem(aBuilder, aFrame)
   , mOverrideZIndex(0)
 {
-  MOZ_COUNT_CTOR(nsDisplayWrapList);
-
   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);
-  } else {
-    // 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->Frame() == mFrame) {
-      mReferenceFrame = i->ReferenceFrame();
-      mToReferenceFrame = i->ToReferenceFrame();
-    }
-  }
-  mVisibleRect = aBuilder->GetDirtyRect() + mToReferenceFrame;
+    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->Frame() == mFrame) {
+    mReferenceFrame = i->ReferenceFrame();
+    mToReferenceFrame = i->ToReferenceFrame();
+  }
 }
 
 nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder,
                                      nsIFrame* aFrame, nsDisplayItem* aItem)
   : nsDisplayItem(aBuilder, aFrame)
   , mOverrideZIndex(0)
 {
-  MOZ_COUNT_CTOR(nsDisplayWrapList);
-
   mList.AppendToTop(aItem);
   UpdateBounds(aBuilder);
   
   if (!aFrame || !aFrame->IsTransformed()) {
     return;
   }
 
   if (aFrame->Preserves3DChildren()) {
     mReferenceFrame = 
       aBuilder->FindReferenceFrameFor(GetTransformRootFrame(aFrame));
     mToReferenceFrame = aFrame->GetOffsetToCrossDoc(mReferenceFrame);
-  } else {
-    // See the previous nsDisplayWrapList constructor
-    if (aItem->Frame() == aFrame) {
-      mReferenceFrame = aItem->ReferenceFrame();
-      mToReferenceFrame = aItem->ToReferenceFrame();
-    }
-  }
-  mVisibleRect = aBuilder->GetDirtyRect() + mToReferenceFrame;
+    return;
+  }
+
+  // See the previous nsDisplayWrapList constructor
+  if (aItem->Frame() == 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)
+  , mOverrideZIndex(0)
+{
+  mList.AppendToTop(aItem);
+  mBounds = mList.GetBounds(aBuilder);
 }
 
 nsDisplayWrapList::~nsDisplayWrapList() {
   mList.DeleteAll();
-
-  MOZ_COUNT_DTOR(nsDisplayWrapList);
 }
 
 void
 nsDisplayWrapList::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
                            HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) {
   mList.HitTest(aBuilder, aRect, aState, aOutFrames);
 }
 
 nsRect
 nsDisplayWrapList::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
   *aSnap = false;
   return mBounds;
 }
 
 bool
 nsDisplayWrapList::ComputeVisibility(nsDisplayListBuilder* aBuilder,
-                                     nsRegion* aVisibleRegion) {
+                                     nsRegion* aVisibleRegion,
+                                     const nsRect& aAllowVisibleRegionExpansion) {
   // Convert the passed in visible region to our appunits.
   nsRegion visibleRegion;
   // mVisibleRect has been clipped to GetClippedBounds
   visibleRegion.And(*aVisibleRegion, mVisibleRect);
   nsRegion originalVisibleRegion = visibleRegion;
 
   bool retval =
     mList.ComputeVisibilityForSublist(aBuilder, &visibleRegion,
-                                      mVisibleRect);
+                                      mVisibleRect,
+                                      aAllowVisibleRegionExpansion);
 
   nsRegion removed;
   // removed = originalVisibleRegion - visibleRegion
   removed.Sub(originalVisibleRegion, visibleRegion);
   // aVisibleRegion = aVisibleRegion - removed (modulo any simplifications
   // SubtractFromVisibleRegion does)
   aBuilder->SubtractFromVisibleRegion(aVisibleRegion, removed);
 
@@ -2989,16 +3129,23 @@ nsDisplayWrapList::GetOpaqueRegion(nsDis
   return result;
 }
 
 bool nsDisplayWrapList::IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) {
   // We could try to do something but let's conservatively just return false.
   return false;
 }
 
+bool nsDisplayWrapList::IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuilder,
+                                                         nsIFrame* aFrame) {
+  NS_WARNING("nsDisplayWrapList::IsVaryingRelativeToMovingFrame called unexpectedly");
+  // We could try to do something but let's conservatively just return true.
+  return true;
+}
+
 void nsDisplayWrapList::Paint(nsDisplayListBuilder* aBuilder,
                               nsRenderingContext* aCtx) {
   NS_ERROR("nsDisplayWrapList should have been flattened away for painting");
 }
 
 /**
  * Returns true if all descendant display items can be placed in the same
  * ThebesLayer --- GetLayerState returns LAYER_INACTIVE or LAYER_NONE,
@@ -3149,17 +3296,17 @@ already_AddRefed<Layer>
 nsDisplayOpacity::BuildLayer(nsDisplayListBuilder* aBuilder,
                              LayerManager* aManager,
                              const ContainerLayerParameters& aContainerParameters) {
   if (mOpacity == 0 && mFrame->GetContent() &&
       !nsLayoutUtils::HasAnimations(mFrame->GetContent(), eCSSProperty_opacity)) {
     return nullptr;
   }
   nsRefPtr<Layer> container = aManager->GetLayerBuilder()->
-    BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList,
+    BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList,
                            aContainerParameters, nullptr);
   if (!container)
     return nullptr;
 
   container->SetOpacity(mOpacity);
   nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(container, aBuilder,
                                                            this, mFrame,
                                                            eCSSProperty_opacity);
@@ -3233,27 +3380,30 @@ nsDisplayOpacity::GetLayerState(nsDispla
     return LAYER_ACTIVE;
 
   return RequiredLayerStateForChildren(aBuilder, aManager, aParameters, mList,
     nsLayoutUtils::GetAnimatedGeometryRootFor(this, aBuilder));
 }
 
 bool
 nsDisplayOpacity::ComputeVisibility(nsDisplayListBuilder* aBuilder,
-                                    nsRegion* aVisibleRegion) {
+                                    nsRegion* aVisibleRegion,
+                                    const nsRect& aAllowVisibleRegionExpansion) {
   // Our children are translucent so we should not allow them to subtract
   // area from aVisibleRegion. We do need to find out what is visible under
   // our children in the temporary compositing buffer, because if our children
   // paint our entire bounds opaquely then we don't need an alpha channel in
   // the temporary compositing buffer.
   nsRect bounds = GetClippedBounds(aBuilder);
   nsRegion visibleUnderChildren;
   visibleUnderChildren.And(*aVisibleRegion, bounds);
+  nsRect allowExpansion = bounds.Intersect(aAllowVisibleRegionExpansion);
   return
-    nsDisplayWrapList::ComputeVisibility(aBuilder, &visibleUnderChildren);
+    nsDisplayWrapList::ComputeVisibility(aBuilder, &visibleUnderChildren,
+                                         allowExpansion);
 }
 
 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
@@ -3309,38 +3459,42 @@ nsDisplayMixBlendMode::GetLayerState(nsD
 already_AddRefed<Layer>
 nsDisplayMixBlendMode::BuildLayer(nsDisplayListBuilder* aBuilder,
                                   LayerManager* aManager,
                                   const ContainerLayerParameters& aContainerParameters) {
   ContainerLayerParameters newContainerParameters = aContainerParameters;
   newContainerParameters.mDisableSubpixelAntialiasingInDescendants = true;
 
   nsRefPtr<Layer> container = aManager->GetLayerBuilder()->
-  BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList,
+  BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList,
                          newContainerParameters, nullptr);
   if (!container) {
     return nullptr;
   }
 
   container->DeprecatedSetMixBlendMode(nsCSSRendering::GetGFXBlendMode(mFrame->StyleDisplay()->mMixBlendMode));
 
   return container.forget();
 }
 
 bool nsDisplayMixBlendMode::ComputeVisibility(nsDisplayListBuilder* aBuilder,
-                                              nsRegion* aVisibleRegion) {
+                                              nsRegion* aVisibleRegion,
+                                              const nsRect& aAllowVisibleRegionExpansion) {
   // Our children are need their backdrop so we should not allow them to subtract
   // area from aVisibleRegion. We do need to find out what is visible under
   // our children in the temporary compositing buffer, because if our children
   // paint our entire bounds opaquely then we don't need an alpha channel in
   // the temporary compositing buffer.
   nsRect bounds = GetClippedBounds(aBuilder);
   nsRegion visibleUnderChildren;
   visibleUnderChildren.And(*aVisibleRegion, bounds);
-  return nsDisplayWrapList::ComputeVisibility(aBuilder, &visibleUnderChildren);
+  nsRect allowExpansion = bounds.Intersect(aAllowVisibleRegionExpansion);
+  return
+  nsDisplayWrapList::ComputeVisibility(aBuilder, &visibleUnderChildren,
+                                       allowExpansion);
 }
 
 bool nsDisplayMixBlendMode::TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) {
   if (aItem->GetType() != TYPE_MIX_BLEND_MODE)
     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
@@ -3382,17 +3536,17 @@ nsDisplayBlendContainer::BuildLayer(nsDi
                                     LayerManager* aManager,
                                     const ContainerLayerParameters& aContainerParameters) {
   // turn off anti-aliasing in the parent stacking context because it changes
   // how the group is initialized.
   ContainerLayerParameters newContainerParameters = aContainerParameters;
   newContainerParameters.mDisableSubpixelAntialiasingInDescendants = true;
 
   nsRefPtr<Layer> container = aManager->GetLayerBuilder()->
-  BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList,
+  BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList,
                          newContainerParameters, nullptr);
   if (!container) {
     return nullptr;
   }
   
   container->SetForceIsolatedGroup(true);
   return container.forget();
 }
@@ -3427,17 +3581,17 @@ nsDisplayOwnLayer::~nsDisplayOwnLayer() 
 #endif
 
 // nsDisplayOpacity uses layers for rendering
 already_AddRefed<Layer>
 nsDisplayOwnLayer::BuildLayer(nsDisplayListBuilder* aBuilder,
                               LayerManager* aManager,
                               const ContainerLayerParameters& aContainerParameters) {
   nsRefPtr<ContainerLayer> layer = aManager->GetLayerBuilder()->
-    BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList,
+    BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList,
                            aContainerParameters, nullptr);
   if (mFlags & VERTICAL_SCROLLBAR) {
     layer->SetScrollbarData(mScrollTarget, Layer::ScrollDirection::VERTICAL);
   }
   if (mFlags & HORIZONTAL_SCROLLBAR) {
     layer->SetScrollbarData(mScrollTarget, Layer::ScrollDirection::HORIZONTAL);
   }
 
@@ -3480,17 +3634,17 @@ nsDisplaySubDocument::BuildLayer(nsDispl
     bool isRootContentDocument = presContext->IsRootContentDocument();
 
     nsRect viewport = mFrame->GetRect() -
                       mFrame->GetPosition() +
                       mFrame->GetOffsetToCrossDoc(ReferenceFrame());
 
     container->SetScrollHandoffParentId(mScrollParentId);
     RecordFrameMetrics(mFrame, rootScrollFrame, ReferenceFrame(),
-                       container, viewport,
+                       container, mList.GetVisibleRect(), viewport,
                        false, isRootContentDocument, aContainerParameters);
   }
 
   return layer.forget();
 }
 
 nsRect
 nsDisplaySubDocument::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
@@ -3503,36 +3657,39 @@ nsDisplaySubDocument::GetBounds(nsDispla
     return mFrame->GetRect() + aBuilder->ToReferenceFrame(mFrame);
   }
 
   return nsDisplayOwnLayer::GetBounds(aBuilder, aSnap);
 }
 
 bool
 nsDisplaySubDocument::ComputeVisibility(nsDisplayListBuilder* aBuilder,
-                                        nsRegion* aVisibleRegion)
+                                        nsRegion* aVisibleRegion,
+                                        const nsRect& aAllowVisibleRegionExpansion)
 {
   nsRect displayport;
   bool usingDisplayPort =
     nsLayoutUtils::ViewportHasDisplayPort(mFrame->PresContext(), &displayport);
 
   if (!(mFlags & GENERATE_SCROLLABLE_LAYER) || !usingDisplayPort) {
-    return nsDisplayWrapList::ComputeVisibility(aBuilder, aVisibleRegion);
+    return nsDisplayWrapList::ComputeVisibility(aBuilder, aVisibleRegion,
+                                                aAllowVisibleRegionExpansion);
   }
 
   nsRegion childVisibleRegion;
   // The visible region for the children may be much bigger than the hole we
   // are viewing the children from, so that the compositor process has enough
   // content to asynchronously pan while content is being refreshed.
   childVisibleRegion = displayport + mFrame->GetOffsetToCrossDoc(ReferenceFrame());
 
   nsRect boundedRect =
     childVisibleRegion.GetBounds().Intersect(mList.GetBounds(aBuilder));
+  nsRect allowExpansion = boundedRect.Intersect(aAllowVisibleRegionExpansion);
   bool visible = mList.ComputeVisibilityForSublist(
-    aBuilder, &childVisibleRegion, boundedRect,
+    aBuilder, &childVisibleRegion, boundedRect, allowExpansion,
     usingDisplayPort ? mFrame : nullptr);
   // We don't allow this computation to influence aVisibleRegion, on the
   // assumption that the layer can be asynchronously scrolled so we'll
   // definitely need all the content under it.
 
   return visible;
 }
 
@@ -3680,17 +3837,16 @@ nsDisplayScrollLayer::nsDisplayScrollLay
                                            nsDisplayList* aList,
                                            nsIFrame* aForFrame,
                                            nsIFrame* aScrolledFrame,
                                            nsIFrame* aScrollFrame)
   : nsDisplayWrapList(aBuilder, aForFrame, aList)
   , mScrollFrame(aScrollFrame)
   , mScrolledFrame(aScrolledFrame)
   , mScrollParentId(aBuilder->GetCurrentScrollParentId())
-  , mDisplayPortContentsOpaque(false)
 {
 #ifdef NS_BUILD_REFCNT_LOGGING
   MOZ_COUNT_CTOR(nsDisplayScrollLayer);
 #endif
 
   NS_ASSERTION(mScrolledFrame && mScrolledFrame->GetContent(),
                "Need a child frame with content");
 }
@@ -3699,17 +3855,16 @@ nsDisplayScrollLayer::nsDisplayScrollLay
                                            nsDisplayItem* aItem,
                                            nsIFrame* aForFrame,
                                            nsIFrame* aScrolledFrame,
                                            nsIFrame* aScrollFrame)
   : nsDisplayWrapList(aBuilder, aForFrame, aItem)
   , mScrollFrame(aScrollFrame)
   , mScrolledFrame(aScrolledFrame)
   , mScrollParentId(aBuilder->GetCurrentScrollParentId())
-  , mDisplayPortContentsOpaque(false)
 {
 #ifdef NS_BUILD_REFCNT_LOGGING
   MOZ_COUNT_CTOR(nsDisplayScrollLayer);
 #endif
 
   NS_ASSERTION(mScrolledFrame && mScrolledFrame->GetContent(),
                "Need a child frame with content");
 }
@@ -3717,17 +3872,16 @@ nsDisplayScrollLayer::nsDisplayScrollLay
 nsDisplayScrollLayer::nsDisplayScrollLayer(nsDisplayListBuilder* aBuilder,
                                            nsIFrame* aForFrame,
                                            nsIFrame* aScrolledFrame,
                                            nsIFrame* aScrollFrame)
   : nsDisplayWrapList(aBuilder, aForFrame)
   , mScrollFrame(aScrollFrame)
   , mScrolledFrame(aScrolledFrame)
   , mScrollParentId(aBuilder->GetCurrentScrollParentId())
-  , mDisplayPortContentsOpaque(false)
 {
 #ifdef NS_BUILD_REFCNT_LOGGING
   MOZ_COUNT_CTOR(nsDisplayScrollLayer);
 #endif
 
   NS_ASSERTION(mScrolledFrame && mScrolledFrame->GetContent(),
                "Need a child frame with content");
 }
@@ -3745,92 +3899,70 @@ nsDisplayScrollLayer::GetBounds(nsDispla
   nsIScrollableFrame* sf = do_QueryFrame(mScrollFrame);
   if (sf) {
     *aSnap = false;
     return sf->GetScrollPortRect() + aBuilder->ToReferenceFrame(mScrollFrame);
   }
   return nsDisplayWrapList::GetBounds(aBuilder, aSnap);
 }
 
-nsRect
-nsDisplayScrollLayer::GetScrolledContentRectToDraw(nsDisplayListBuilder* aBuilder,
-                                                   nsRect* aDisplayPort)
-{
-  if (aDisplayPort) {
-    // The visible region for the children may be much bigger than the hole we
-    // are viewing the children from, so that the compositor process has enough
-    // content to asynchronously pan while content is being refreshed.
-    // XXX mScrollFrame seems wrong here; we should add the offset of the
-    // scrollport
-    return *aDisplayPort + mScrollFrame->GetOffsetToCrossDoc(ReferenceFrame());
-  }
-  bool snap;
-  return GetBounds(aBuilder, &snap);
-}
-
 already_AddRefed<Layer>
 nsDisplayScrollLayer::BuildLayer(nsDisplayListBuilder* aBuilder,
                                  LayerManager* aManager,
                                  const ContainerLayerParameters& aContainerParameters) {
   nsRefPtr<ContainerLayer> layer = aManager->GetLayerBuilder()->
-    BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList,
+    BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList,
                            aContainerParameters, nullptr);
 
   nsRect viewport = mScrollFrame->GetRect() -
                     mScrollFrame->GetPosition() +
                     mScrollFrame->GetOffsetToCrossDoc(ReferenceFrame());
 
   layer->SetScrollHandoffParentId(mScrollParentId);
   RecordFrameMetrics(mScrolledFrame, mScrollFrame, ReferenceFrame(), layer,
-                     viewport, false, false, aContainerParameters);
-
-  if (mList.IsOpaque()) {
-    nsRect displayport;
-    bool usingDisplayport =
-      nsLayoutUtils::GetDisplayPort(mScrolledFrame->GetContent(), &displayport);
-    mDisplayPortContentsOpaque = mList.GetBounds(aBuilder).Contains(
-        GetScrolledContentRectToDraw(aBuilder, usingDisplayport ? &displayport : nullptr));
-  } else {
-    mDisplayPortContentsOpaque = false;
-  }
+                     mList.GetVisibleRect(), viewport,
+                     false, false, aContainerParameters);
 
   return layer.forget();
 }
 
 bool
-nsDisplayScrollLayer::IsConstructingScrollLayerForScrolledFrame(const nsIFrame* aScrolledFrame)
-{
-  FrameProperties props = aScrolledFrame->Properties();
-  return reinterpret_cast<intptr_t>(props.Get(nsIFrame::ScrollLayerCount())) != 0;
-}
-
-bool
 nsDisplayScrollLayer::ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder)
 {
   if (nsLayoutUtils::GetDisplayPort(mScrolledFrame->GetContent(), nullptr)) {
     return true;
   }
 
   return nsDisplayWrapList::ShouldBuildLayerEvenIfInvisible(aBuilder);
 }
 
 bool
 nsDisplayScrollLayer::ComputeVisibility(nsDisplayListBuilder* aBuilder,
-                                        nsRegion* aVisibleRegion)
+                                        nsRegion* aVisibleRegion,
+                                        const nsRect& aAllowVisibleRegionExpansion)
 {
   nsRect displayport;
   bool usingDisplayPort =
     nsLayoutUtils::GetDisplayPort(mScrolledFrame->GetContent(), &displayport);
-  nsRect scrolledContentRect = GetScrolledContentRectToDraw(aBuilder,
-      usingDisplayPort ? &displayport : nullptr);
-
-  nsRect boundedRect = scrolledContentRect.Intersect(mList.GetBounds(aBuilder));
-  nsRegion childVisibleRegion = scrolledContentRect;
+  nsRegion childVisibleRegion;
+  if (usingDisplayPort) {
+    // The visible region for the children may be much bigger than the hole we
+    // are viewing the children from, so that the compositor process has enough
+    // content to asynchronously pan while content is being refreshed.
+    childVisibleRegion = displayport + mScrollFrame->GetOffsetToCrossDoc(ReferenceFrame());
+  } else {
+    bool snap;
+    childVisibleRegion = GetBounds(aBuilder, &snap);
+  }
+
+  nsRect boundedRect =
+    childVisibleRegion.GetBounds().Intersect(mList.GetBounds(aBuilder));
+  nsRect allowExpansion = boundedRect.Intersect(aAllowVisibleRegionExpansion);
   bool visible = mList.ComputeVisibilityForSublist(
-    aBuilder, &childVisibleRegion, boundedRect,
+    aBuilder, &childVisibleRegion, boundedRect, allowExpansion,
     usingDisplayPort ? mScrollFrame : nullptr);
   // We don't allow this computation to influence aVisibleRegion, on the
   // assumption that the layer can be asynchronously scrolled so we'll
   // definitely need all the content under it.
 
   return visible;
 }
 
@@ -3998,16 +4130,18 @@ nsDisplayScrollInfoLayer::nsDisplayScrol
 {
 #ifdef NS_BUILD_REFCNT_LOGGING
   MOZ_COUNT_CTOR(nsDisplayScrollInfoLayer);
 #endif
 }
 
 nsDisplayScrollInfoLayer::~nsDisplayScrollInfoLayer()
 {
+  FrameProperties props = mScrolledFrame->Properties();
+  props.Remove(nsIFrame::ScrollLayerCount());
   MOZ_COUNT_DTOR(nsDisplayScrollInfoLayer);
 }
 
 nsRect
 nsDisplayScrollInfoLayer::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
 {
   return nsDisplayWrapList::GetBounds(aBuilder, aSnap);
 }
@@ -4078,40 +4212,45 @@ void nsDisplayZoom::HitTest(nsDisplayLis
 
 void nsDisplayZoom::Paint(nsDisplayListBuilder* aBuilder,
                           nsRenderingContext* aCtx)
 {
   mList.PaintForFrame(aBuilder, aCtx, mFrame, nsDisplayList::PAINT_DEFAULT);
 }
 
 bool nsDisplayZoom::ComputeVisibility(nsDisplayListBuilder *aBuilder,
-                                      nsRegion *aVisibleRegion)
+                                      nsRegion *aVisibleRegion,
+                                      const nsRect& aAllowVisibleRegionExpansion)
 {
   // Convert the passed in visible region to our appunits.
   nsRegion visibleRegion;
   // mVisibleRect has been clipped to GetClippedBounds
   visibleRegion.And(*aVisibleRegion, mVisibleRect);
   visibleRegion = visibleRegion.ConvertAppUnitsRoundOut(mParentAPD, mAPD);
   nsRegion originalVisibleRegion = visibleRegion;
 
   nsRect transformedVisibleRect =
     mVisibleRect.ConvertAppUnitsRoundOut(mParentAPD, mAPD);
+  nsRect allowExpansion =
+    aAllowVisibleRegionExpansion.ConvertAppUnitsRoundIn(mParentAPD, mAPD);
   bool retval;
   // If we are to generate a scrollable layer we call
   // nsDisplaySubDocument::ComputeVisibility to make the necessary adjustments
   // for ComputeVisibility, it does all it's calculations in the child APD.
   bool usingDisplayPort =
     nsLayoutUtils::ViewportHasDisplayPort(mFrame->PresContext());
   if (!(mFlags & GENERATE_SCROLLABLE_LAYER) || !usingDisplayPort) {
     retval =
       mList.ComputeVisibilityForSublist(aBuilder, &visibleRegion,
-                                        transformedVisibleRect);
+                                        transformedVisibleRect,
+                                        allowExpansion);
   } else {
     retval =
-      nsDisplaySubDocument::ComputeVisibility(aBuilder, &visibleRegion);
+      nsDisplaySubDocument::ComputeVisibility(aBuilder, &visibleRegion,
+                                              allowExpansion);
   }
 
   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
@@ -4188,71 +4327,57 @@ nsDisplayTransform::GetFrameBoundsForTra
                                       currFrame->GetSize()));
     }
 
   return result;
 }
 
 #endif
 
-nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder,
-                                       nsIFrame *aFrame, nsDisplayList *aList,
-                                       const nsRect& aChildrenVisibleRect,
-                                       ComputeTransformFunction aTransformGetter,
+nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame *aFrame,
+                                       nsDisplayList *aList, ComputeTransformFunction aTransformGetter, 
                                        uint32_t aIndex) 
   : nsDisplayItem(aBuilder, aFrame)
   , mStoredList(aBuilder, aFrame, aList)
   , mTransformGetter(aTransformGetter)
-  , mChildrenVisibleRect(aChildrenVisibleRect)
   , mIndex(aIndex)
 {
   MOZ_COUNT_CTOR(nsDisplayTransform);
   NS_ABORT_IF_FALSE(aFrame, "Must have a frame!");
   NS_ABORT_IF_FALSE(!aFrame->IsTransformed(), "Can't specify a transform getter for a transformed frame!");
   mStoredList.SetClip(aBuilder, DisplayItemClip::NoClip());
 }
 
-void
-nsDisplayTransform::SetReferenceFrameToAncestor(nsDisplayListBuilder* aBuilder)
-{
-  mReferenceFrame =
-    aBuilder->FindReferenceFrameFor(GetTransformRootFrame(mFrame));
-  mToReferenceFrame = mFrame->GetOffsetToCrossDoc(mReferenceFrame);
-  mVisibleRect = aBuilder->GetDirtyRect() + mToReferenceFrame;
-}
-
-nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder,
-                                       nsIFrame *aFrame, nsDisplayList *aList,
-                                       const nsRect& aChildrenVisibleRect,
-                                       uint32_t aIndex)
+nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame *aFrame,
+                                       nsDisplayList *aList, uint32_t aIndex) 
   : nsDisplayItem(aBuilder, aFrame)
   , mStoredList(aBuilder, aFrame, aList)
   , mTransformGetter(nullptr)
-  , mChildrenVisibleRect(aChildrenVisibleRect)
   , mIndex(aIndex)
 {
   MOZ_COUNT_CTOR(nsDisplayTransform);
   NS_ABORT_IF_FALSE(aFrame, "Must have a frame!");
-  SetReferenceFrameToAncestor(aBuilder);
+  mReferenceFrame = 
+    aBuilder->FindReferenceFrameFor(GetTransformRootFrame(aFrame));
+  mToReferenceFrame = aFrame->GetOffsetToCrossDoc(mReferenceFrame);
   mStoredList.SetClip(aBuilder, DisplayItemClip::NoClip());
 }
 
-nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder,
-                                       nsIFrame *aFrame, nsDisplayItem *aItem,
-                                       const nsRect& aChildrenVisibleRect,
-                                       uint32_t aIndex)
+nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame *aFrame,
+                                       nsDisplayItem *aItem, uint32_t aIndex)
   : nsDisplayItem(aBuilder, aFrame)
   , mStoredList(aBuilder, aFrame, aItem)
   , mTransformGetter(nullptr)
-  , mChildrenVisibleRect(aChildrenVisibleRect)
   , mIndex(aIndex)
 {
   MOZ_COUNT_CTOR(nsDisplayTransform);
   NS_ABORT_IF_FALSE(aFrame, "Must have a frame!");
-  SetReferenceFrameToAncestor(aBuilder);
+  mReferenceFrame =
+    aBuilder->FindReferenceFrameFor(GetTransformRootFrame(aFrame));
+  mToReferenceFrame = aFrame->GetOffsetToCrossDoc(mReferenceFrame);
   mStoredList.SetClip(aBuilder, DisplayItemClip::NoClip());
 }
 
 /* Returns the delta specified by the -moz-transform-origin property.
  * This is a positive delta, meaning that it indicates the direction to move
  * to get from (0, 0) of the frame to the transform origin.  This function is
  * called off the main thread.
  */
@@ -4677,21 +4802,20 @@ already_AddRefed<Layer> nsDisplayTransfo
 {
   const gfx3DMatrix& newTransformMatrix = GetTransform();
 
   if (mFrame->StyleDisplay()->mBackfaceVisibility == NS_STYLE_BACKFACE_VISIBILITY_HIDDEN &&
       newTransformMatrix.IsBackfaceVisible()) {
     return nullptr;
   }
 
-  bool prerender = ShouldPrerenderTransformedContent(aBuilder, mFrame, false);
-  uint32_t flags = prerender ?
+  uint32_t flags = ShouldPrerenderTransformedContent(aBuilder, mFrame, false) ?
     FrameLayerBuilder::CONTAINER_NOT_CLIPPED_BY_ANCESTORS : 0;
   nsRefPtr<ContainerLayer> container = aManager->GetLayerBuilder()->
-    BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mStoredList.GetChildren(),
+    BuildContainerLayerFor(aBuilder, aManager, mFrame, this, *mStoredList.GetChildren(),
                            aContainerParameters, &newTransformMatrix, flags);
 
   if (!container) {
     return nullptr;
   }
 
   // Add the preserve-3d flag for this layer, BuildContainerLayerFor clears all flags,
   // so we never need to explicitely unset this flag.
@@ -4699,17 +4823,17 @@ already_AddRefed<Layer> nsDisplayTransfo
     container->SetContentFlags(container->GetContentFlags() | Layer::CONTENT_PRESERVE_3D);
   } else {
     container->SetContentFlags(container->GetContentFlags() & ~Layer::CONTENT_PRESERVE_3D);
   }
 
   nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(container, aBuilder,
                                                            this, mFrame,
                                                            eCSSProperty_transform);
-  if (prerender) {
+  if (ShouldPrerenderTransformedContent(aBuilder, mFrame, false)) {
     container->SetUserData(nsIFrame::LayerIsPrerenderedDataKey(),
                            /*the value is irrelevant*/nullptr);
     container->SetContentFlags(container->GetContentFlags() | Layer::CONTENT_MAY_CHANGE_TRANSFORM);
   } else {
     container->RemoveUserData(nsIFrame::LayerIsPrerenderedDataKey());
     container->SetContentFlags(container->GetContentFlags() & ~Layer::CONTENT_MAY_CHANGE_TRANSFORM);
   }
   return container.forget();
@@ -4745,17 +4869,18 @@ nsDisplayTransform::GetLayerState(nsDisp
   // geometry root (since it will be their reference frame). If they have a
   // different animated geometry root, we'll make this an active layer so the
   // animation can be accelerated.
   return RequiredLayerStateForChildren(aBuilder, aManager, aParameters,
     *mStoredList.GetChildren(), Frame());
 }
 
 bool nsDisplayTransform::ComputeVisibility(nsDisplayListBuilder *aBuilder,
-                                             nsRegion *aVisibleRegion)
+                                             nsRegion *aVisibleRegion,
+                                             const nsRect& aAllowVisibleRegionExpansion)
 {
   /* 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.
    * If we can't untransform, take the entire overflow rect */
   nsRect untransformedVisibleRect;
   if (ShouldPrerenderTransformedContent(aBuilder, mFrame) ||
       !UntransformVisibleRect(aBuilder, &untransformedVisibleRect))
@@ -4931,17 +5056,17 @@ nsRegion nsDisplayTransform::GetOpaqueRe
   const gfx3DMatrix& matrix = GetTransform();
 
   nsRegion result;
   gfxMatrix matrix2d;
   bool tmpSnap;
   if (matrix.Is2D(&matrix2d) &&
       matrix2d.PreservesAxisAlignedRectangles() &&
       mStoredList.GetOpaqueRegion(aBuilder, &tmpSnap).Contains(untransformedVisible)) {
-    result = mVisibleRect.Intersect(GetBounds(aBuilder, &tmpSnap));
+    result = mVisibleRect;
   }
   return result;
 }
 
 /* The transform is uniform if it fills the entire bounding rect and the
  * wrapped list is uniform.  See GetOpaqueRegion for discussion of why this
  * works.
  */
@@ -4991,17 +5116,17 @@ nsDisplayTransform::TryMerge(nsDisplayLi
     return false;
 
   if (aItem->GetClip() != GetClip())
     return false;
 
   /* Now, move everything over to this frame and signal that
    * we merged things!
    */
-  mStoredList.MergeFromTrackingMergedFrames(&static_cast<nsDisplayTransform*>(aItem)->mStoredList);
+  mStoredList.MergeFrom(&static_cast<nsDisplayTransform*>(aItem)->mStoredList);
   return true;
 }
 
 #endif
 
 /* TransformRect takes in as parameters a rectangle (in app space) and returns
  * the smallest rectangle (in app space) containing the transformed image of
  * that rectangle.  That is, it takes the four corners of the rectangle,
@@ -5204,35 +5329,36 @@ nsDisplaySVGEffects::BuildLayer(nsDispla
   }
 
   ContainerLayerParameters newContainerParameters = aContainerParameters;
   if (effectProperties.HasValidFilter()) {
     newContainerParameters.mDisableSubpixelAntialiasingInDescendants = true;
   }
 
   nsRefPtr<ContainerLayer> container = aManager->GetLayerBuilder()->
-    BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList,
+    BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList,
                            newContainerParameters, nullptr);
 
   return container.forget();
 }
 
 bool nsDisplaySVGEffects::ComputeVisibility(nsDisplayListBuilder* aBuilder,
-                                              nsRegion* aVisibleRegion) {
+                                              nsRegion* aVisibleRegion,
+                                              const nsRect& aAllowVisibleRegionExpansion) {
   nsPoint offset = ToReferenceFrame();
   nsRect dirtyRect =
     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);
+  mList.ComputeVisibilityForSublist(aBuilder, &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
@@ -196,59 +196,57 @@ public:
    * in the normal unrestricted case)
    */
   nsISelection* GetBoundingSelection() { return mBoundingSelection; }
 
   /**
    * @return the root of given frame's (sub)tree, whose origin
    * establishes the coordinate system for the child display items.
    */
-  const nsIFrame* FindReferenceFrameFor(const nsIFrame *aFrame,
-                                        nsPoint* aOffset = nullptr)
+  const nsIFrame* FindReferenceFrameFor(const nsIFrame *aFrame)
   {
-    if (aFrame == mCurrentFrame) {
-      if (aOffset) {
-        *aOffset = mCurrentOffsetToReferenceFrame;
-      }
-      return mCurrentReferenceFrame;
+    if (aFrame == mCachedOffsetFrame) {
+      return mCachedReferenceFrame;
     }
     for (const nsIFrame* f = aFrame; f; f = nsLayoutUtils::GetCrossDocParentFrame(f))
     {
       if (f == mReferenceFrame || f->IsTransformed()) {
-        if (aOffset) {
-          *aOffset = aFrame->GetOffsetToCrossDoc(f);
-        }
+        mCachedOffsetFrame = aFrame;
+        mCachedReferenceFrame = f;
+        mCachedOffset = aFrame->GetOffsetToCrossDoc(f);
         return f;
       }
     }
-    if (aOffset) {
-      *aOffset = aFrame->GetOffsetToCrossDoc(mReferenceFrame);
-    }
+    mCachedOffsetFrame = aFrame;
+    mCachedReferenceFrame = mReferenceFrame;
+    mCachedOffset = aFrame->GetOffsetToCrossDoc(mReferenceFrame);
     return mReferenceFrame;
   }
   
   /**
    * @return the root of the display list's frame (sub)tree, whose origin
    * establishes the coordinate system for the display list
    */
   nsIFrame* RootReferenceFrame() 
   {
     return mReferenceFrame;
   }
 
   /**
    * @return a point pt such that adding pt to a coordinate relative to aFrame
    * makes it relative to ReferenceFrame(), i.e., returns 
    * aFrame->GetOffsetToCrossDoc(ReferenceFrame()). The returned point is in
-   * the appunits of aFrame.
+   * the appunits of aFrame. It may be optimized to be faster than
+   * aFrame->GetOffsetToCrossDoc(ReferenceFrame()) (but currently isn't).
    */
-  const nsPoint ToReferenceFrame(const nsIFrame* aFrame) {
-    nsPoint result;
-    FindReferenceFrameFor(aFrame, &result);
-    return result;
+  const nsPoint& ToReferenceFrame(const nsIFrame* aFrame) {
+    if (aFrame != mCachedOffsetFrame) {
+      FindReferenceFrameFor(aFrame);
+    }
+    return mCachedOffset;
   }
   /**
    * When building the display list, the scrollframe aFrame will be "ignored"
    * for the purposes of clipping, and its scrollbars will be hidden. We use
    * this to allow RenderOffscreen to render a whole document without beign
    * clipped by the viewport or drawing the viewport scrollbars.
    */
   void SetIgnoreScrollFrame(nsIFrame* aFrame) { mIgnoreScrollFrame = aFrame; }
@@ -309,24 +307,16 @@ public:
   bool IsPaintingToWindow() const { return mIsPaintingToWindow; }
   /**
    * Call this to prevent descending into subdocuments.
    */
   void SetDescendIntoSubdocuments(bool aDescend) { mDescendIntoSubdocuments = aDescend; }
   bool GetDescendIntoSubdocuments() { return mDescendIntoSubdocuments; }
 
   /**
-   * Get dirty rect relative to current frame (the frame that we're calling
-   * BuildDisplayList on right now).
-   */
-  const nsRect& GetDirtyRect() { return mDirtyRect; }
-  const nsIFrame* GetCurrentFrame() { return mCurrentFrame; }
-  const nsIFrame* GetCurrentReferenceFrame() { return mCurrentReferenceFrame; }
-
-  /**
    * Returns true if merging and flattening of display lists should be
    * performed while computing visibility.
    */
   bool AllowMergingAndFlattening() { return mAllowMergingAndFlattening; }
   void SetAllowMergingAndFlattening(bool aAllow) { mAllowMergingAndFlattening = aAllow; }
 
   nsDisplayLayerEventRegions* GetLayerEventRegions() { return mLayerEventRegions; }
   void SetLayerEventRegions(nsDisplayLayerEventRegions* aItem)
@@ -402,16 +392,22 @@ public:
   bool IsInTransform() const { return mInTransform; }
   /**
    * Indicate whether or not we're directly or indirectly under and
    * nsDisplayTransform or SVG foreignObject.
    */
   void SetInTransform(bool aInTransform) { mInTransform = aInTransform; }
 
   /**
+   * Returns true if we're currently building display items that are in
+   * true fixed position subtree.
+   */
+  bool IsInFixedPos() const { return mInFixedPos; }
+
+  /**
    * @return true if images have been set to decode synchronously.
    */
   bool ShouldSyncDecodeImages() { return mSyncDecodeImages; }
 
   /**
    * Indicates whether we should synchronously decode images. If true, we decode
    * and draw whatever image data has been loaded. If false, we just draw
    * whatever has already been decoded.
@@ -449,16 +445,29 @@ public:
                                 const nsRect& aDirtyRect);
   /**
    * Mark all child frames that Preserve3D() as needing display.
    * Because these frames include transforms set on their parent, dirty rects
    * for intermediate frames may be empty, yet child frames could still be visible.
    */
   void MarkPreserve3DFramesForDisplayList(nsIFrame* aDirtyFrame, const nsRect& aDirtyRect);
 
+  /**
+   * Get the area of the final transparent region.
+   */
+  const nsRegion* GetFinalTransparentRegion() { return mFinalTransparentRegion; }
+  /**
+   * Record the area of the final transparent region after all visibility
+   * calculations were performed.
+   */
+  void SetFinalTransparentRegion(const nsRegion& aFinalTransparentRegion)
+  {
+    mFinalTransparentRegion = &aFinalTransparentRegion;
+  }
+
   const nsTArray<ThemeGeometry>& GetThemeGeometries() { return mThemeGeometries; }
 
   /**
    * Returns true if we need to descend into this frame when building
    * the display list, even though it doesn't intersect the dirty
    * rect, because it may have out-of-flows that do so.
    */
   bool ShouldDescendIntoFrame(nsIFrame* aFrame) const {
@@ -512,68 +521,69 @@ public:
   static void AddAnimationsAndTransitionsToLayer(Layer* aLayer,
                                                  nsDisplayListBuilder* aBuilder,
                                                  nsDisplayItem* aItem,
                                                  nsIFrame* aFrame,
                                                  nsCSSProperty aProperty);
   /**
    * A helper class to temporarily set the value of
    * mIsAtRootOfPseudoStackingContext, and temporarily
-   * set mCurrentFrame and related state. Also temporarily sets mDirtyRect.
-   * aDirtyRect is relative to aForChild.
+   * update mCachedOffsetFrame/mCachedOffset from a frame to its child.
+   * Also saves and restores mClipState.
    */
   class AutoBuildingDisplayList;
   friend class AutoBuildingDisplayList;
   class AutoBuildingDisplayList {
   public:
-    AutoBuildingDisplayList(nsDisplayListBuilder* aBuilder,
-                            nsIFrame* aForChild,
-                            const nsRect& aDirtyRect, bool aIsRoot)
+    AutoBuildingDisplayList(nsDisplayListBuilder* aBuilder, bool aIsRoot)
       : mBuilder(aBuilder),
-        mPrevFrame(aBuilder->mCurrentFrame),
-        mPrevReferenceFrame(aBuilder->mCurrentReferenceFrame),
+        mPrevCachedOffsetFrame(aBuilder->mCachedOffsetFrame),
+        mPrevCachedReferenceFrame(aBuilder->mCachedReferenceFrame),
         mPrevLayerEventRegions(aBuilder->mLayerEventRegions),
-        mPrevOffset(aBuilder->mCurrentOffsetToReferenceFrame),
-        mPrevDirtyRect(aBuilder->mDirtyRect),
+        mPrevCachedOffset(aBuilder->mCachedOffset),
+        mPrevIsAtRootOfPseudoStackingContext(aBuilder->mIsAtRootOfPseudoStackingContext),
+        mPrevAncestorHasTouchEventHandler(aBuilder->mAncestorHasTouchEventHandler)
+    {
+      aBuilder->mIsAtRootOfPseudoStackingContext = aIsRoot;
+    }
+    AutoBuildingDisplayList(nsDisplayListBuilder* aBuilder,
+                            nsIFrame* aForChild, bool aIsRoot)
+      : mBuilder(aBuilder),
+        mPrevCachedOffsetFrame(aBuilder->mCachedOffsetFrame),
+        mPrevCachedReferenceFrame(aBuilder->mCachedReferenceFrame),
+        mPrevLayerEventRegions(aBuilder->mLayerEventRegions),
+        mPrevCachedOffset(aBuilder->mCachedOffset),
         mPrevIsAtRootOfPseudoStackingContext(aBuilder->mIsAtRootOfPseudoStackingContext),
         mPrevAncestorHasTouchEventHandler(aBuilder->mAncestorHasTouchEventHandler)
     {
       if (aForChild->IsTransformed()) {
-        aBuilder->mCurrentOffsetToReferenceFrame = nsPoint();
-        aBuilder->mCurrentReferenceFrame = aForChild;
-      } else if (aBuilder->mCurrentFrame == aForChild->GetParent()) {
-        aBuilder->mCurrentOffsetToReferenceFrame += aForChild->GetPosition();
+        aBuilder->mCachedOffset = nsPoint();
+        aBuilder->mCachedReferenceFrame = aForChild;
+      } else if (mPrevCachedOffsetFrame == aForChild->GetParent()) {
+        aBuilder->mCachedOffset += aForChild->GetPosition();
       } else {
-        aBuilder->mCurrentReferenceFrame =
-          aBuilder->FindReferenceFrameFor(aForChild,
-              &aBuilder->mCurrentOffsetToReferenceFrame);
+        aBuilder->mCachedOffset = aBuilder->ToReferenceFrame(aForChild);
       }
-      aBuilder->mCurrentFrame = aForChild;
-      aBuilder->mDirtyRect = aDirtyRect;
+      aBuilder->mCachedOffsetFrame = aForChild;
       aBuilder->mIsAtRootOfPseudoStackingContext = aIsRoot;
     }
-    void SetDirtyRect(const nsRect& aRect) {
-      mBuilder->mDirtyRect = aRect;
-    }
     ~AutoBuildingDisplayList() {
-      mBuilder->mCurrentFrame = mPrevFrame;
-      mBuilder->mCurrentReferenceFrame = mPrevReferenceFrame;
+      mBuilder->mCachedOffsetFrame = mPrevCachedOffsetFrame;
+      mBuilder->mCachedReferenceFrame = mPrevCachedReferenceFrame;
       mBuilder->mLayerEventRegions = mPrevLayerEventRegions;
-      mBuilder->mCurrentOffsetToReferenceFrame = mPrevOffset;
-      mBuilder->mDirtyRect = mPrevDirtyRect;
+      mBuilder->mCachedOffset = mPrevCachedOffset;
       mBuilder->mIsAtRootOfPseudoStackingContext = mPrevIsAtRootOfPseudoStackingContext;
       mBuilder->mAncestorHasTouchEventHandler = mPrevAncestorHasTouchEventHandler;
     }
   private:
     nsDisplayListBuilder* mBuilder;
-    const nsIFrame*       mPrevFrame;
-    const nsIFrame*       mPrevReferenceFrame;
+    const nsIFrame*       mPrevCachedOffsetFrame;
+    const nsIFrame*       mPrevCachedReferenceFrame;
     nsDisplayLayerEventRegions* mPrevLayerEventRegions;
-    nsPoint               mPrevOffset;
-    nsRect                mPrevDirtyRect;
+    nsPoint               mPrevCachedOffset;
     bool                  mPrevIsAtRootOfPseudoStackingContext;
     bool                  mPrevAncestorHasTouchEventHandler;
   };
 
   /**
    * A helper class to temporarily set the value of mInTransform.
    */
   class AutoInTransformSetter;
@@ -588,16 +598,35 @@ public:
       mBuilder->mInTransform = mOldValue;
     }
   private:
     nsDisplayListBuilder* mBuilder;
     bool                  mOldValue;
   };
 
   /**
+   * A helper class to temporarily set the value of mInFixedPos.
+   */
+  class AutoInFixedPosSetter;
+  friend class AutoInFixedPosSetter;
+  class AutoInFixedPosSetter {
+  public:
+    AutoInFixedPosSetter(nsDisplayListBuilder* aBuilder, bool aInFixedPos)
+      : mBuilder(aBuilder), mOldValue(aBuilder->mInFixedPos) {
+      aBuilder->mInFixedPos = aInFixedPos;
+    }
+    ~AutoInFixedPosSetter() {
+      mBuilder->mInFixedPos = mOldValue;
+    }
+  private:
+    nsDisplayListBuilder* mBuilder;
+    bool                  mOldValue;
+  };
+
+  /**
    * A helper class to temporarily set the value of mCurrentScrollParentId.
    */
   class AutoCurrentScrollParentIdSetter;
   friend class AutoCurrentScrollParentIdSetter;
   class AutoCurrentScrollParentIdSetter {
   public:
     AutoCurrentScrollParentIdSetter(nsDisplayListBuilder* aBuilder, ViewID aScrollId)
       : mBuilder(aBuilder), mOldValue(aBuilder->mCurrentScrollParentId) {
@@ -662,25 +691,21 @@ public:
     return CurrentPresShellState()->mPresShell->GetPresContext();
   }
 
   /**
    * Accumulates the bounds of box frames that have moz-appearance
    * -moz-win-exclude-glass style. Used in setting glass margins on
    * Windows.
    */  
-  void AddWindowOpaqueRegion(const nsRegion& bounds) {
-    mWindowOpaqueRegion.Or(mWindowOpaqueRegion, bounds);
+  void AddExcludedGlassRegion(nsRect &bounds) {
+    mExcludedGlassRegion.Or(mExcludedGlassRegion, bounds);
   }
-  /**
-   * Returns the window opaque region built so far. This may be incomplete
-   * since the opaque region is built during layer construction.
-   */
-  const nsRegion& GetWindowOpaqueRegion() {
-    return mWindowOpaqueRegion;
+  const nsRegion& GetExcludedGlassRegion() {
+    return mExcludedGlassRegion;
   }
   void SetGlassDisplayItem(nsDisplayItem* aItem) {
     if (mGlassDisplayItem) {
       // Web pages or extensions could trigger this by using
       // -moz-appearance:win-borderless-glass etc on their own elements.
       // Keep the first one, since that will be the background of the root
       // window
       NS_WARNING("Multiple glass backgrounds found?");
@@ -713,17 +738,16 @@ public:
 
 private:
   void MarkOutOfFlowFrameForDisplay(nsIFrame* aDirtyFrame, nsIFrame* aFrame,
                                     const nsRect& aDirtyRect);
 
   struct PresShellState {
     nsIPresShell* mPresShell;
     nsIFrame*     mCaretFrame;
-    nsRect        mPrevDirtyRect;
     uint32_t      mFirstFrameMarkedForDisplay;
     bool          mIsBackgroundOnly;
   };
   PresShellState* CurrentPresShellState() {
     NS_ASSERTION(mPresShellStates.Length() > 0,
                  "Someone forgot to enter a presshell");
     return &mPresShellStates[mPresShellStates.Length() - 1];
   }
@@ -733,26 +757,23 @@ private:
   nsDisplayLayerEventRegions*    mLayerEventRegions;
   PLArenaPool                    mPool;
   nsCOMPtr<nsISelection>         mBoundingSelection;
   nsAutoTArray<PresShellState,8> mPresShellStates;
   nsAutoTArray<nsIFrame*,100>    mFramesMarkedForDisplay;
   nsAutoTArray<ThemeGeometry,2>  mThemeGeometries;
   nsDisplayTableItem*            mCurrentTableItem;
   DisplayListClipState           mClipState;
-  // mCurrentFrame is the frame that we're currently calling (or about to call)
-  // BuildDisplayList on.
-  const nsIFrame*                mCurrentFrame;
-  // The reference frame for mCurrentFrame.
-  const nsIFrame*                mCurrentReferenceFrame;
-  // The offset from mCurrentFrame to mCurrentReferenceFrame.
-  nsPoint                        mCurrentOffsetToReferenceFrame;
-  // Relative to mCurrentFrame.
-  nsRect                         mDirtyRect;
-  nsRegion                       mWindowOpaqueRegion;
+  const nsRegion*                mFinalTransparentRegion;
+  // When mCachedOffsetFrame is non-null, mCachedOffset is the offset from
+  // mCachedOffsetFrame to mReferenceFrame.
+  const nsIFrame*                mCachedOffsetFrame;
+  const nsIFrame*                mCachedReferenceFrame;
+  nsPoint                        mCachedOffset;
+  nsRegion                       mExcludedGlassRegion;
   // The display item for the Windows window glass background, if any
   nsDisplayItem*                 mGlassDisplayItem;
   nsTArray<DisplayItemClip*>     mDisplayItemClipsToDestroy;
   Mode                           mMode;
   ViewID                         mCurrentScrollParentId;
   ViewID                         mCurrentScrollbarTarget;
   uint32_t                       mCurrentScrollbarFlags;
   BlendModeSet                   mContainedBlendModes;
@@ -764,16 +785,17 @@ private:
   bool                           mDescendIntoSubdocuments;
   bool                           mSelectedFramesOnly;
   bool                           mAccurateVisibleRegions;
   bool                           mAllowMergingAndFlattening;
   bool                           mWillComputePluginGeometry;
   // True when we're building a display list that's directly or indirectly
   // under an nsDisplayTransform
   bool                           mInTransform;
+  bool                           mInFixedPos;
   bool                           mSyncDecodeImages;
   bool                           mIsPaintingToWindow;
   bool                           mIsCompositingCheap;
   bool                           mContainsPluginItem;
   bool                           mAncestorHasTouchEventHandler;
   // True when the first async-scrollable scroll frame for which we build a
   // display list has a display port. An async-scrollable scroll frame is one
   // which WantsAsyncScroll().
@@ -821,40 +843,53 @@ public:
   typedef mozilla::layers::LayerManager LayerManager;
   typedef mozilla::LayerState LayerState;
 
   // This is never instantiated directly (it has pure virtual methods), so no
   // need to count constructors and destructors.
   nsDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
     : mFrame(aFrame)
     , mClip(aBuilder->ClipState().GetCurrentCombinedClip(aBuilder))
+    , mInFixedPos(aBuilder->IsInFixedPos())
 #ifdef MOZ_DUMP_PAINTING
     , mPainted(false)
 #endif
   {
-    mReferenceFrame = aBuilder->FindReferenceFrameFor(aFrame, &mToReferenceFrame);
-    NS_ASSERTION(aBuilder->GetDirtyRect().width >= 0 ||
-                 !aBuilder->IsForPainting(), "dirty rect not set");
-    mVisibleRect = aBuilder->GetDirtyRect() + mToReferenceFrame;
+    mReferenceFrame = aBuilder->FindReferenceFrameFor(aFrame);
+    mToReferenceFrame = aBuilder->ToReferenceFrame(aFrame);
+  }
+  nsDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+                const nsIFrame* aReferenceFrame,
+                const nsPoint& aToReferenceFrame)
+    : mFrame(aFrame)
+    , mClip(aBuilder->ClipState().GetCurrentCombinedClip(aBuilder))
+    , mReferenceFrame(aReferenceFrame)
+    , mToReferenceFrame(aToReferenceFrame)
+    , mInFixedPos(aBuilder->IsInFixedPos())
+#ifdef MOZ_DUMP_PAINTING
+    , mPainted(false)
+#endif
+  {
   }
   /**
    * This constructor is only used in rare cases when we need to construct
    * temporary items.
    */
   nsDisplayItem(nsIFrame* aFrame)
     : mFrame(aFrame)
     , mClip(nullptr)
     , mReferenceFrame(nullptr)
+    , mInFixedPos(false)
 #ifdef MOZ_DUMP_PAINTING
     , mPainted(false)
 #endif
   {
   }
   virtual ~nsDisplayItem() {}
-
+  
   void* operator new(size_t aSize,
                      nsDisplayListBuilder* aBuilder) CPP_THROW_NEW {
     return aBuilder->Allocate(aSize);
   }
 
 // Contains all the type integers for each display list item type
 #include "nsDisplayItemTypes.h"
 
@@ -1054,17 +1089,17 @@ public:
    * call this method on.
    */
   virtual void NotifyRenderingChanged() {}
 
   /**
    * @param aSnap set to true if the edges of the rectangles of the opaque
    * region would be snapped to device pixels when drawing
    * @return a region of the item that is opaque --- that is, every pixel
-   * that is visible is painted with an opaque
+   * that is visible (according to ComputeVisibility) is painted with an opaque
    * color. This is useful for determining when one piece
    * of content completely obscures another so that we can do occlusion
    * culling.
    * This does not take clipping into account.
    */
   virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
                                    bool* aSnap)
   {
@@ -1073,16 +1108,26 @@ public:
   }
   /**
    * If this returns true, then aColor is set to the uniform color
    * @return true if the item is guaranteed to paint every pixel in its
    * bounds with the same (possibly translucent) color
    */
   virtual bool IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) { return false; }
   /**
+   * @return false if the painting performed by the item is invariant
+   * when the item's underlying frame is moved relative to aFrame.
+   * In other words, if you render the item at locations P and P', the rendering
+   * only differs by the translation.
+   * It return true for all wrapped lists.
+   */
+  virtual bool IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuilder,
+                                                nsIFrame* aFrame)
+  { return false; }
+  /**
    * @return true if the contents of this item are rendered fixed relative
    * to the nearest viewport.
    */
   virtual bool ShouldFixToViewport(nsDisplayListBuilder* aBuilder)
   { return false; }
 
   /**
    * Returns true if all layers that can be active should be forced to be
@@ -1183,17 +1228,18 @@ public:
    * expand the visible region and is only used for making sure the
    * background behind a plugin is visible.
    * This method needs to be idempotent.
    *
    * @return true if the item is visible, false if no part of the item
    * is visible.
    */
   virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
-                                 nsRegion* aVisibleRegion);
+                                   nsRegion* aVisibleRegion,
+                                   const nsRect& aAllowVisibleRegionExpansion);
 
   /**
    * Try to merge with the other item (which is below us in the display
    * list). This gets used by nsDisplayClip to coalesce clipping operations
    * (optimization), by nsDisplayOpacity to merge rendering for the same
    * content element into a single opacity group (correctness), and will be
    * used by nsDisplayOutline to merge multiple outlines for the same element
    * (also for correctness).
@@ -1230,27 +1276,20 @@ public:
 
   /**
    * If this has a child list, return it, even if the children are in
    * a different coordinate system to this item.
    */
   virtual nsDisplayList* GetChildren() { return nullptr; }
 
   /**
-   * Returns the visible rect.
+   * Returns the visible rect. Should only be called after ComputeVisibility
+   * has happened.
    */
-  const nsRect& GetVisibleRect() const { return mVisibleRect; }
-
-  /**
-   * Returns the visible rect for the children, relative to their
-   * reference frame. Can be different from mVisibleRect for nsDisplayTransform,
-   * since the reference frame for the children is different from the reference
-   * frame for the item itself.
-   */
-  virtual const nsRect& GetVisibleRectForChildren() const { return mVisibleRect; }
+  const nsRect& GetVisibleRect() { return mVisibleRect; }
 
   /**
    * Stores the given opacity value to be applied when drawing. Returns
    * false if this isn't supported for this display item.
    */
   virtual bool ApplyOpacity(nsDisplayListBuilder* aBuilder,
                             float aOpacity,
                             const DisplayItemClip* aClip) {
@@ -1271,17 +1310,17 @@ public:
   /**
    * Like ComputeVisibility, but does the work that nsDisplayList
    * does per-item:
    * -- Intersects GetBounds with aVisibleRegion and puts the result
    * in mVisibleRect
    * -- Subtracts bounds from aVisibleRegion if the item is opaque
    */
   bool RecomputeVisibility(nsDisplayListBuilder* aBuilder,
-                           nsRegion* aVisibleRegion);
+                             nsRegion* aVisibleRegion);
 
   /**
    * Returns the result of aBuilder->ToReferenceFrame(GetUnderlyingFrame())
    */
   const nsPoint& ToReferenceFrame() const {
     NS_ASSERTION(mFrame, "No frame?");
     return mToReferenceFrame;
   }
@@ -1337,34 +1376,41 @@ public:
       DisplayItemClip temp = *mClip;
       temp.IntersectWith(aClip);
       SetClip(aBuilder, temp);
     } else {
       SetClip(aBuilder, aClip);
     }
   }
 
+  // If we return false here it means that if this item creates a layer then
+  // ProcessDisplayItems will not set the visible region on the layer. The item
+  // should set the visible region, usually in BuildContainerLayer.
+  virtual bool SetVisibleRegionOnLayer() { return true; }
+
+  bool IsInFixedPos() { return mInFixedPos; }
+
 protected:
   friend class nsDisplayList;
 
   nsDisplayItem() { mAbove = nullptr; }
 
   nsIFrame* mFrame;
   const DisplayItemClip* mClip;
   // Result of FindReferenceFrameFor(mFrame), if mFrame is non-null
   const nsIFrame* mReferenceFrame;
   // Result of ToReferenceFrame(mFrame), if mFrame is non-null
   nsPoint   mToReferenceFrame;
   // This is the rectangle that needs to be painted.
-  // Display item construction sets this to the dirty rect.
   // nsDisplayList::ComputeVisibility sets this to the visible region
   // of the item by intersecting the current visible region with the bounds
   // of the item. Paint implementations can use this to limit their drawing.
   // Guaranteed to be contained in GetBounds().
   nsRect    mVisibleRect;
+  bool      mInFixedPos;
 #ifdef MOZ_DUMP_PAINTING
   // True if this frame has been painted.
   bool      mPainted;
 #endif
 };
 
 /**
  * Manages a singly-linked list of display list items.
@@ -1385,22 +1431,24 @@ class nsDisplayList {
 public:
   typedef mozilla::layers::Layer Layer;
   typedef mozilla::layers::LayerManager LayerManager;
   typedef mozilla::layers::ThebesLayer ThebesLayer;
 
   /**
    * Create an empty list.
    */
-  nsDisplayList()
-    : mIsOpaque(false)
-    , mForceTransparentSurface(false)
+  nsDisplayList() :
+    mIsOpaque(false)
   {
     mTop = &mSentinel;
     mSentinel.mAbove = nullptr;
+#if defined(DEBUG) || defined(MOZ_DUMP_PAINTING)
+    mDidComputeVisibility = false;
+#endif
   }
   ~nsDisplayList() {
     if (mSentinel.mAbove) {
       NS_WARNING("Nonempty list left over?");
     }
     DeleteAll();
   }
 
@@ -1556,16 +1604,17 @@ public:
    * @param aDisplayPortFrame If the item for which this list corresponds is
    * within a displayport, the scroll frame for which that display port
    * applies. For root scroll frames, you can pass the the root frame instead.
    * @return true if any item in the list is visible.
    */
   bool ComputeVisibilityForSublist(nsDisplayListBuilder* aBuilder,
                                    nsRegion* aVisibleRegion,
                                    const nsRect& aListVisibleBounds,
+                                   const nsRect& aAllowVisibleRegionExpansion,
                                    nsIFrame* aDisplayPortFrame = nullptr);
 
   /**
    * As ComputeVisibilityForSublist, but computes visibility for a root
    * list (a list that does not belong to an nsDisplayItem).
    * This method needs to be idempotent.
    *
    * @param aVisibleRegion the area that is visible
@@ -1575,23 +1624,26 @@ public:
                                 nsRegion* aVisibleRegion,
                                 nsIFrame* aDisplayPortFrame = nullptr);
 
   /**
    * Returns true if the visible region output from ComputeVisiblity was
    * empty, i.e. everything visible in this list is opaque.
    */
   bool IsOpaque() const {
+    NS_ASSERTION(mDidComputeVisibility, "Need to have called ComputeVisibility");
     return mIsOpaque;
   }
 
   /**
-   * Returns true if any display item requires the surface to be transparent.
+   * Returns true if during ComputeVisibility any display item
+   * set the surface to be transparent.
    */
   bool NeedsTransparentSurface() const {
+    NS_ASSERTION(mDidComputeVisibility, "Need to have called ComputeVisibility");
     return mForceTransparentSurface;
   }
   /**
    * Paint the list to the rendering context. We assume that (0,0) in aCtx
    * corresponds to the origin of the reference frame. For best results,
    * aCtx's current transform should make (0,0) pixel-aligned. The
    * rectangle in aDirtyRect is painted, which *must* be contained in the
    * dirty rect used to construct the display list.
@@ -1621,67 +1673,64 @@ public:
     PAINT_DEFAULT = 0,
     PAINT_USE_WIDGET_LAYERS = 0x01,
     PAINT_FLUSH_LAYERS = 0x02,
     PAINT_EXISTING_TRANSACTION = 0x04,
     PAINT_NO_COMPOSITE = 0x08,
     PAINT_COMPRESSED = 0x10
   };
   void PaintRoot(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx,
-                 uint32_t aFlags);
+                 uint32_t aFlags) const;
   /**
    * Like PaintRoot, but used for internal display sublists.
    * aForFrame is the frame that the list is associated with.
    */
   void PaintForFrame(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx,
-                     nsIFrame* aForFrame, uint32_t aFlags);
+                     nsIFrame* aForFrame, uint32_t aFlags) const;
   /**
    * Get the bounds. Takes the union of the bounds of all children.
-   * The result is not cached.
    */
   nsRect GetBounds(nsDisplayListBuilder* aBuilder) const;
   /**
    * Find the topmost display item that returns a non-null frame, and return
    * the frame.
    */
   void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
                nsDisplayItem::HitTestState* aState,
                nsTArray<nsIFrame*> *aOutFrames) const;
-  /**
-   * Compute the union of the visible rects of the items in the list. The
-   * result is not cached.
-   */
-  nsRect GetVisibleRect() const;
-
-  void SetIsOpaque()
-  {
-    mIsOpaque = true;
-  }
-  void SetNeedsTransparentSurface()
-  {
-    mForceTransparentSurface = true;
-  }
+
+#if defined(DEBUG) || defined(MOZ_DUMP_PAINTING)
+  bool DidComputeVisibility() const { return mDidComputeVisibility; }
+#endif
+
+  nsRect GetVisibleRect() const { return mVisibleRect; }
 
 private:
   // This class is only used on stack, so we don't have to worry about leaking
   // it.  Don't let us be heap-allocated!
   void* operator new(size_t sz) CPP_THROW_NEW;
   
+  // Utility function used to massage the list during ComputeVisibility.
+  void FlattenTo(nsTArray<nsDisplayItem*>* aElements);
+  
   nsDisplayItemLink  mSentinel;
   nsDisplayItemLink* mTop;
 
   // This is set by ComputeVisibility
   nsRect mVisibleRect;
-  // This is set to true by FrameLayerBuilder if the final visible region
+  // This is set to true by ComputeVisibility if the final visible region
   // is empty (i.e. everything that was visible is covered by some
   // opaque content in this list).
   bool mIsOpaque;
-  // This is set to true by FrameLayerBuilder if any display item in this
+  // This is set to true by ComputeVisibility if any display item in this
   // list needs to force the surface containing this list to be transparent.
   bool mForceTransparentSurface;
+#if defined(DEBUG) || defined(MOZ_DUMP_PAINTING)
+  bool mDidComputeVisibility;
+#endif
 };
 
 /**
  * This is passed as a parameter to nsIFrame::BuildDisplayList. That method
  * will put any generated items onto the appropriate list given here. It's
  * basically just a collection with one list for each separate stacking layer.
  * The lists themselves are external to this object and thus can be shared
  * with others. Some of the list pointers may even refer to the same list.
@@ -2135,19 +2184,22 @@ public:
 
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
                                              const ContainerLayerParameters& aContainerParameters) MOZ_OVERRIDE;
 
   virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
                        HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) MOZ_OVERRIDE;
   virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
-                                 nsRegion* aVisibleRegion) MOZ_OVERRIDE;
+                                   nsRegion* aVisibleRegion,
+                                   const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE;
   virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
                                    bool* aSnap) MOZ_OVERRIDE;
+  virtual bool IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuilder,
+                                                nsIFrame* aFrame) MOZ_OVERRIDE;
   virtual bool IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) MOZ_OVERRIDE;
   /**
    * GetBounds() returns the background painting area.
    */
   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE;
   virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) MOZ_OVERRIDE;
   virtual uint32_t GetPerFrameKey() MOZ_OVERRIDE;
   NS_DISPLAY_DECL_NAME("Background", TYPE_BACKGROUND)
@@ -2339,17 +2391,18 @@ public:
     MOZ_COUNT_DTOR(nsDisplayBoxShadowOuter);
   }
 #endif
 
   virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) MOZ_OVERRIDE;
   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE;
   virtual bool IsInvisibleInRect(const nsRect& aRect) MOZ_OVERRIDE;
   virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
-                                 nsRegion* aVisibleRegion) MOZ_OVERRIDE;
+                                   nsRegion* aVisibleRegion,
+                                   const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE;
   NS_DISPLAY_DECL_NAME("BoxShadowOuter", TYPE_BOX_SHADOW_OUTER)
   
   virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
                                          const nsDisplayItemGeometry* aGeometry,
                                          nsRegion* aInvalidRegion) MOZ_OVERRIDE;
   
   virtual bool ApplyOpacity(nsDisplayListBuilder* aBuilder,
                             float aOpacity,
@@ -2382,17 +2435,18 @@ public:
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayBoxShadowInner() {
     MOZ_COUNT_DTOR(nsDisplayBoxShadowInner);
   }
 #endif
 
   virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) MOZ_OVERRIDE;
   virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
-                                 nsRegion* aVisibleRegion) MOZ_OVERRIDE;
+                                   nsRegion* aVisibleRegion,
+                                   const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE;
   NS_DISPLAY_DECL_NAME("BoxShadowInner", TYPE_BOX_SHADOW_INNER)
   
   virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE
   {
     return new nsDisplayBoxShadowInnerGeometry(this, aBuilder);
   }
 
   virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
@@ -2523,56 +2577,59 @@ private:
  * a list containing this item will not get at the children.
  * 
  * In some cases (e.g., clipping) we want to wrap a list but we don't have a
  * particular underlying frame that is a stacking context root. In that case
  * we allow the frame to be nullptr. Callers to GetUnderlyingFrame must
  * detect and handle this case.
  */
 class nsDisplayWrapList : public nsDisplayItem {
+  // This is never instantiated directly, so no need to count constructors and
+  // destructors.
+
 public:
   /**
    * Takes all the items from aList and puts them in our list.
    */
   nsDisplayWrapList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                     nsDisplayList* aList);
   nsDisplayWrapList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                     nsDisplayItem* aItem);
+  nsDisplayWrapList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+                    nsDisplayItem* aItem, const nsIFrame* aReferenceFrame, const nsPoint& aToReferenceFrame);
   nsDisplayWrapList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
-    : nsDisplayItem(aBuilder, aFrame), mOverrideZIndex(0)
-  {
-    MOZ_COUNT_CTOR(nsDisplayWrapList);
-  }
+    : nsDisplayItem(aBuilder, aFrame), mOverrideZIndex(0) {}
   virtual ~nsDisplayWrapList();
   /**
    * Call this if the wrapped list is changed.
    */
   virtual void UpdateBounds(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE
   {
     mBounds = mList.GetBounds(aBuilder);
   }
   virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
                        HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) MOZ_OVERRIDE;
   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE;
   virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
                                    bool* aSnap) MOZ_OVERRIDE;
   virtual bool IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) MOZ_OVERRIDE;
+  virtual bool IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuilder,
+                                                nsIFrame* aFrame) MOZ_OVERRIDE;
   virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) MOZ_OVERRIDE;
   virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
-                                 nsRegion* aVisibleRegion) MOZ_OVERRIDE;
+                                 nsRegion* aVisibleRegion,
+                                 const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE;
   virtual bool TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) MOZ_OVERRIDE {
+    NS_WARNING("This list should already have been flattened!!!");
     return false;
   }
   virtual void GetMergedFrames(nsTArray<nsIFrame*>* aFrames) MOZ_OVERRIDE
   {
     aFrames->AppendElements(mMergedFrames);
   }
-  virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) {
-    return true;
-  }
   virtual bool IsInvalid(nsRect& aRect) MOZ_OVERRIDE
   {
     if (mFrame->IsInvalid(aRect) && aRect.IsEmpty()) {
       return true;
     }
     nsRect temp;
     for (uint32_t i = 0; i < mMergedFrames.Length(); i++) {
       if (mMergedFrames[i]->IsInvalid(temp) && temp.IsEmpty()) {
@@ -2618,21 +2675,24 @@ public:
                                            nsDisplayItem* aItem) {
     NS_NOTREACHED("We never returned nullptr for GetUnderlyingFrame!");
     return nullptr;
   }
 
 protected:
   nsDisplayWrapList() {}
 
-  void MergeFromTrackingMergedFrames(nsDisplayWrapList* aOther)
+  void MergeFrom(nsDisplayWrapList* aOther)
   {
     mList.AppendToBottom(&aOther->mList);
     mBounds.UnionRect(mBounds, aOther->mBounds);
-    mVisibleRect.UnionRect(mVisibleRect, aOther->mVisibleRect);
+  }
+  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;
@@ -2683,17 +2743,18 @@ public:
                                    bool* aSnap) MOZ_OVERRIDE;
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
                                              const ContainerLayerParameters& aContainerParameters) MOZ_OVERRIDE;
   virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
                                    LayerManager* aManager,
                                    const ContainerLayerParameters& aParameters) MOZ_OVERRIDE;
   virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
-                                 nsRegion* aVisibleRegion) MOZ_OVERRIDE;
+                                   nsRegion* aVisibleRegion,
+                                   const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE;  
   virtual bool TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) MOZ_OVERRIDE;
   virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
                                          const nsDisplayItemGeometry* aGeometry,
                                          nsRegion* aInvalidRegion) MOZ_OVERRIDE
   {
     // We don't need to compute an invalidation region since we have LayerTreeInvalidation
   }
   virtual bool ApplyOpacity(nsDisplayListBuilder* aBuilder,
@@ -2731,21 +2792,19 @@ public:
                                          nsRegion* aInvalidRegion) MOZ_OVERRIDE
   {
     // We don't need to compute an invalidation region since we have LayerTreeInvalidation
   }
   virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
                                    LayerManager* aManager,
                                    const ContainerLayerParameters& aParameters) MOZ_OVERRIDE;
   virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
-                                 nsRegion* aVisibleRegion) MOZ_OVERRIDE;
+                                 nsRegion* aVisibleRegion,
+                                 const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE;
   virtual bool TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) MOZ_OVERRIDE;
-  virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE {
-    return false;
-  }
   NS_DISPLAY_DECL_NAME("MixBlendMode", TYPE_MIX_BLEND_MODE)
 };
 
 class nsDisplayBlendContainer : public nsDisplayWrapList {
 public:
     nsDisplayBlendContainer(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                             nsDisplayList* aList,
                             BlendModeSet& aContainedBlendModes);
@@ -2763,19 +2822,16 @@ public:
                                      const ContainerLayerParameters& aParameters) MOZ_OVERRIDE
     {
       if (mCanBeActive && aManager->SupportsMixBlendModes(mContainedBlendModes)) {
         return mozilla::LAYER_ACTIVE;
       }
       return mozilla::LAYER_INACTIVE;
     }
     virtual bool TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) MOZ_OVERRIDE;
-    virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE {
-      return false;
-    }
     NS_DISPLAY_DECL_NAME("BlendContainer", TYPE_BLEND_CONTAINER)
 
 private:
     // The set of all blend modes used by nsDisplayMixBlendMode descendents of this container.
     BlendModeSet mContainedBlendModes;
     // If this is true, then we should make the layer active if all contained blend
     // modes can be supported by the current layer manager.
     bool mCanBeActive;
@@ -2825,19 +2881,16 @@ public:
   {
     return mozilla::LAYER_ACTIVE_FORCE;
   }
   virtual bool TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) MOZ_OVERRIDE
   {
     // Don't allow merging, each sublist must have its own layer
     return false;
   }
-  virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE {
-    return false;
-  }
   uint32_t GetFlags() { return mFlags; }
   NS_DISPLAY_DECL_NAME("OwnLayer", TYPE_OWN_LAYER)
 protected:
   uint32_t mFlags;
   ViewID mScrollTarget;
 };
 
 /**
@@ -2855,17 +2908,20 @@ public:
 
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
                                              const ContainerLayerParameters& aContainerParameters) MOZ_OVERRIDE;
 
   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE;
 
   virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
-                                 nsRegion* aVisibleRegion) MOZ_OVERRIDE;
+                                 nsRegion* aVisibleRegion,
+                                 const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE;
+
+  virtual bool SetVisibleRegionOnLayer() MOZ_OVERRIDE { return !(mFlags & GENERATE_SCROLLABLE_LAYER); }
 
   virtual bool ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE;
 
   virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE;
 
   NS_DISPLAY_DECL_NAME("SubDocument", TYPE_SUBDOCUMENT)
 protected:
   ViewID mScrollParentId;
@@ -2914,17 +2970,17 @@ public:
     return mozilla::LAYER_ACTIVE;
   }
   virtual bool TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) MOZ_OVERRIDE;
 };
 
 /**
  * This potentially creates a layer for the given list of items, whose
  * visibility is determined by the displayport for the given frame instead of
- * normal visibility computation.
+ * what is passed in to ComputeVisibility.
  *
  * Here in content, we can use this to render more content than is actually
  * visible. Then, the compositing process can manipulate the generated layer
  * through transformations so that asynchronous scrolling can be implemented.
  *
  * Note that setting the displayport will not change any hit testing! The
  * content process will know nothing about what the user is actually seeing,
  * so it can only do hit testing for what is supposed to be the visible region.
@@ -2972,51 +3028,46 @@ public:
 
   virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
                                    bool* aSnap) MOZ_OVERRIDE {
     *aSnap = false;
     return nsRegion();
   }
 
   virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
-                                 nsRegion* aVisibleRegion) MOZ_OVERRIDE;
+                                   nsRegion* aVisibleRegion,
+                                   const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE;
 
   virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
                                    LayerManager* aManager,
                                    const ContainerLayerParameters& aParameters) MOZ_OVERRIDE;
 
   virtual bool TryMerge(nsDisplayListBuilder* aBuilder,
                           nsDisplayItem* aItem) MOZ_OVERRIDE;
 
   virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE;
 
   // Get the number of nsDisplayScrollLayers for a scroll frame. Note that this
   // number does not include nsDisplayScrollInfoLayers. If this number is not 1
   // after merging, all the nsDisplayScrollLayers should flatten away.
   intptr_t GetScrollLayerCount();
 
-  static bool IsConstructingScrollLayerForScrolledFrame(const nsIFrame* aScrolledFrame);
-
   virtual nsIFrame* GetScrollFrame() { return mScrollFrame; }
   virtual nsIFrame* GetScrolledFrame() { return mScrolledFrame; }
 
+  virtual bool SetVisibleRegionOnLayer() MOZ_OVERRIDE { return false; }
+
 #ifdef MOZ_DUMP_PAINTING
   virtual void WriteDebugInfo(nsACString& aTo) MOZ_OVERRIDE;
 #endif
 
-  bool IsDisplayPortOpaque() { return mDisplayPortContentsOpaque; }
-
 protected:
-  nsRect GetScrolledContentRectToDraw(nsDisplayListBuilder* aBuilder,
-                                      nsRect* aDisplayPort);
-
   nsIFrame* mScrollFrame;
   nsIFrame* mScrolledFrame;
   ViewID mScrollParentId;
-  bool mDisplayPortContentsOpaque;
 };
 
 /**
  * Like nsDisplayScrollLayer, but only has metadata on the scroll frame. This
  * creates a layer that has no Thebes child layer, but still allows the
  * compositor process to know of the scroll frame's existence.
  *
  * After visibility computation, nsDisplayScrollInfoLayers should only exist if
@@ -3071,17 +3122,18 @@ public:
   virtual ~nsDisplayZoom();
 #endif
   
   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE;
   virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) MOZ_OVERRIDE;
   virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
                        HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) MOZ_OVERRIDE;
   virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
-                                 nsRegion* aVisibleRegion) MOZ_OVERRIDE;
+                                   nsRegion* aVisibleRegion,
+                                   const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE;
   virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
                                    LayerManager* aManager,
                                    const ContainerLayerParameters& aParameters) MOZ_OVERRIDE
   {
     return mozilla::LAYER_ACTIVE;
   }
   NS_DISPLAY_DECL_NAME("Zoom", TYPE_ZOOM)
 
@@ -3112,22 +3164,20 @@ public:
                        HitTestState* aState,
                        nsTArray<nsIFrame*> *aOutFrames) MOZ_OVERRIDE;
   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
                            bool* aSnap) MOZ_OVERRIDE {
     *aSnap = false;
     return mEffectsBounds + ToReferenceFrame();
   }
   virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
-                                 nsRegion* aVisibleRegion) MOZ_OVERRIDE;
+                                   nsRegion* aVisibleRegion,
+                                   const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE;  
   virtual bool TryMerge(nsDisplayListBuilder* aBuilder,
                         nsDisplayItem* aItem) MOZ_OVERRIDE;
-  virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE {
-    return false;
-  }
   NS_DISPLAY_DECL_NAME("SVGEffects", TYPE_SVG_EFFECTS)
 
   virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
                                    LayerManager* aManager,
                                    const ContainerLayerParameters& aParameters) MOZ_OVERRIDE;
  
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
@@ -3177,24 +3227,21 @@ public:
    * @param aAppUnitsPerPixel The number of app units per graphics unit.
    */
   typedef gfx3DMatrix (* ComputeTransformFunction)(nsIFrame* aFrame, float aAppUnitsPerPixel);
 
   /* Constructor accepts a display list, empties it, and wraps it up.  It also
    * ferries the underlying frame to the nsDisplayItem constructor.
    */
   nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame *aFrame,
-                     nsDisplayList *aList, const nsRect& aChildrenVisibleRect,
-                     uint32_t aIndex = 0);
+                     nsDisplayList *aList, uint32_t aIndex = 0);
   nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame *aFrame,
-                     nsDisplayItem *aItem, const nsRect& aChildrenVisibleRect,
-                     uint32_t aIndex = 0);
+                     nsDisplayItem *aItem, uint32_t aIndex = 0);
   nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame *aFrame,
-                     nsDisplayList *aList, const nsRect& aChildrenVisibleRect,
-                     ComputeTransformFunction aTransformGetter, uint32_t aIndex = 0);
+                     nsDisplayList *aList, ComputeTransformFunction aTransformGetter, uint32_t aIndex = 0);
 
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayTransform()
   {
     MOZ_COUNT_DTOR(nsDisplayTransform);
   }
 #endif
 
@@ -3219,17 +3266,18 @@ public:
   virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
                                    LayerManager* aManager,
                                    const ContainerLayerParameters& aParameters) MOZ_OVERRIDE;
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
                                              const ContainerLayerParameters& aContainerParameters) MOZ_OVERRIDE;
   virtual bool ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE;
   virtual bool ComputeVisibility(nsDisplayListBuilder *aBuilder,
-                                 nsRegion *aVisibleRegion) MOZ_OVERRIDE;
+                                   nsRegion *aVisibleRegion,
+                                   const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE;
   virtual bool TryMerge(nsDisplayListBuilder *aBuilder, nsDisplayItem *aItem) MOZ_OVERRIDE;
   
   virtual uint32_t GetPerFrameKey() MOZ_OVERRIDE { return (mIndex << nsDisplayItem::TYPE_BITS) | nsDisplayItem::GetPerFrameKey(); }
   
   virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
                                          const nsDisplayItemGeometry* aGeometry,
                                          nsRegion* aInvalidRegion) MOZ_OVERRIDE
   {
@@ -3241,21 +3289,16 @@ public:
     // belong to a transformed frame, and aren't a reference frame
     // for our children.
     if (!mTransformGetter) {
       return mFrame;
     }
     return nsDisplayItem::ReferenceFrameForChildren(); 
   }
 
-  virtual const nsRect& GetVisibleRectForChildren() const MOZ_OVERRIDE
-  {
-    return mChildrenVisibleRect;
-  }
-
   enum {
     INDEX_MAX = UINT32_MAX >> nsDisplayItem::TYPE_BITS
   };
 
   const gfx3DMatrix& GetTransform();
 
   float GetHitDepthAtPoint(nsDisplayListBuilder* aBuilder, const nsPoint& aPoint);
 
@@ -3375,33 +3418,32 @@ public:
    * Return true when we should try to prerender the entire contents of the
    * transformed frame even when it's not completely visible (yet).
    */
   static bool ShouldPrerenderTransformedContent(nsDisplayListBuilder* aBuilder,
                                                 nsIFrame* aFrame,
                                                 bool aLogAnimations = false);
   bool CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE;
 
+  virtual bool SetVisibleRegionOnLayer() MOZ_OVERRIDE { return false; }
+
 #ifdef MOZ_DUMP_PAINTING
   virtual void WriteDebugInfo(nsACString& aTo) MOZ_OVERRIDE;
 #endif
 private:
-  void SetReferenceFrameToAncestor(nsDisplayListBuilder* aBuilder);
-
   static gfx3DMatrix GetResultingTransformMatrixInternal(const FrameTransformProperties& aProperties,
                                                          const nsPoint& aOrigin,
                                                          float aAppUnitsPerPixel,
                                                          const nsRect* aBoundsOverride,
                                                          nsIFrame** aOutAncestor,
                                                          bool aOffsetByOrigin);
 
   nsDisplayWrapList mStoredList;
   gfx3DMatrix mTransform;
   ComputeTransformFunction mTransformGetter;
-  nsRect mChildrenVisibleRect;
   uint32_t mIndex;
 };
 
 /**
  * This class adds basic support for limiting the rendering to the part inside
  * the specified edges.  It's a base class for the display item classes that
  * does the actual work.  The two members, mLeftEdge and mRightEdge, are
  * relative to the edges of the frame's scrollable overflow rectangle and is
--- a/layout/base/nsLayoutDebugger.cpp
+++ b/layout/base/nsLayoutDebugger.cpp
@@ -149,17 +149,20 @@ PrintDisplayItemTo(nsDisplayListBuilder*
 #endif
   bool snap;
   nsRect rect = aItem->GetBounds(aBuilder, &snap);
   nscolor color;
   nsRect vis = aItem->GetVisibleRect();
   nsRect component = aItem->GetComponentAlphaBounds(aBuilder);
   nsDisplayList* list = aItem->GetChildren();
   const DisplayItemClip& clip = aItem->GetClip();
-  nsRegion opaque = aItem->GetOpaqueRegion(aBuilder, &snap);
+  nsRegion opaque;
+  if (!list || list->DidComputeVisibility()) {
+    opaque = aItem->GetOpaqueRegion(aBuilder, &snap);
+  }
   if (aDumpHtml && aItem->Painted()) {
     nsCString string(aItem->Name());
     string.Append('-');
     string.AppendInt((uint64_t)aItem);
     aStream << nsPrintfCString("<a href=\"javascript:ViewImage('%s')\">", string.BeginReading());
   }
   aStream << nsPrintfCString("%s p=0x%p f=0x%p(%s) bounds(%d,%d,%d,%d) visible(%d,%d,%d,%d) componentAlpha(%d,%d,%d,%d) clip(%s) %s",
           aItem->Name(), aItem, (void*)f, NS_ConvertUTF16toUTF8(fName).get(),
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -1476,17 +1476,17 @@ nsLayoutUtils::FindSiblingViewFor(nsView
 }
 
 //static
 nsIScrollableFrame*
 nsLayoutUtils::GetScrollableFrameFor(const nsIFrame *aScrolledFrame)
 {
   nsIFrame *frame = aScrolledFrame->GetParent();
   nsIScrollableFrame *sf = do_QueryFrame(frame);
-  return (sf && sf->GetScrolledFrame() == aScrolledFrame) ? sf : nullptr;
+  return sf;
 }
 
 /* static */ void
 nsLayoutUtils::SetFixedPositionLayerData(Layer* aLayer,
                                          const nsIFrame* aViewportFrame,
                                          const nsRect& aAnchorRect,
                                          const nsIFrame* aFixedPosFrame,
                                          nsPresContext* aPresContext,
@@ -1598,19 +1598,19 @@ nsLayoutUtils::SetScrollbarThumbLayeriza
 }
 
 static bool
 IsScrollbarThumbLayerized(nsIFrame* aThumbFrame)
 {
   return reinterpret_cast<intptr_t>(aThumbFrame->Properties().Get(ScrollbarThumbLayerized()));
 }
 
-nsIFrame*
-nsLayoutUtils::GetAnimatedGeometryRootForFrame(nsIFrame* aFrame,
-                                               const nsIFrame* aStopAtAncestor)
+static nsIFrame*
+GetAnimatedGeometryRootForFrame(nsIFrame* aFrame,
+                                const nsIFrame* aStopAtAncestor)
 {
   nsIFrame* f = aFrame;
   nsIFrame* stickyFrame = nullptr;
   while (f != aStopAtAncestor) {
     if (nsLayoutUtils::IsPopup(f))
       break;
     if (ActiveLayerTracker::IsOffsetOrMarginStyleAnimated(f))
       break;
@@ -2318,17 +2318,17 @@ nsLayoutUtils::GetLayerTransformForFrame
   if (!aTransform) {
     return true;
   }
 
   nsDisplayListBuilder builder(root, nsDisplayListBuilder::OTHER,
                                false/*don't build caret*/);
   nsDisplayList list;  
   nsDisplayTransform* item =
-    new (&builder) nsDisplayTransform(&builder, aFrame, &list, nsRect());
+    new (&builder) nsDisplayTransform(&builder, aFrame, &list);
 
   *aTransform =
     item->GetTransform();
   item->~nsDisplayTransform();
 
   return true;
 }
 
@@ -2932,31 +2932,35 @@ nsLayoutUtils::PaintFrame(nsRenderingCon
             dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height).get();
     nsFrame::PrintDisplayList(&builder, list, ss, gfxUtils::sDumpPaintingToFile);
     if (gfxUtils::sDumpPaintingToFile) {
       ss << "<script>";
     }
   }
 #endif
 
+  list.ComputeVisibilityForRoot(&builder, &visibleRegion,
+                                usingDisplayPort ? rootScrollFrame : nullptr);
+
   uint32_t flags = nsDisplayList::PAINT_DEFAULT;
   if (aFlags & PAINT_WIDGET_LAYERS) {
     flags |= nsDisplayList::PAINT_USE_WIDGET_LAYERS;
     if (willFlushRetainedLayers) {
       // The caller wanted to paint from retained layers, but set up
       // the paint in such a way that we can't use them.  We're going
       // to display something different from what we'd normally paint
       // in a window, so make sure we flush out any retained layer
       // trees before *and after* we draw.  Callers should be fixed to
       // not do this.
       NS_WARNING("Flushing retained layers!");
       flags |= nsDisplayList::PAINT_FLUSH_LAYERS;
     } else if (!(aFlags & PAINT_DOCUMENT_RELATIVE)) {
       nsIWidget *widget = aFrame->GetNearestWidget();
       if (widget) {
+        builder.SetFinalTransparentRegion(visibleRegion);
         // If we're finished building display list items for painting of the outermost
         // pres shell, notify the widget about any toolbars we've encountered.
         widget->UpdateThemeGeometries(builder.GetThemeGeometries());
       }
     }
   }
   if (aFlags & PAINT_EXISTING_TRANSACTION) {
     flags |= nsDisplayList::PAINT_EXISTING_TRANSACTION;
@@ -3014,17 +3018,18 @@ nsLayoutUtils::PaintFrame(nsRenderingCon
 
   // Update the widget's opaque region information. This sets
   // glass boundaries on Windows. Also set up plugin clip regions and bounds.
   if ((aFlags & PAINT_WIDGET_LAYERS) &&
       !willFlushRetainedLayers &&
       !(aFlags & PAINT_DOCUMENT_RELATIVE)) {
     nsIWidget *widget = aFrame->GetNearestWidget();
     if (widget) {
-      nsRegion excludedRegion = builder.GetWindowOpaqueRegion();
+      nsRegion excludedRegion = builder.GetExcludedGlassRegion();
+      excludedRegion.Sub(excludedRegion, visibleRegion);
       nsIntRegion windowRegion(excludedRegion.ToNearestPixels(presContext->AppUnitsPerDevPixel()));
       widget->UpdateOpaqueRegion(windowRegion);
     }
   }
 
   if (builder.WillComputePluginGeometry()) {
     nsRefPtr<LayerManager> layerManager;
     nsIWidget* widget = aFrame->GetNearestWidget();
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -495,24 +495,16 @@ public:
    * aItem's ReferenceFrame(), which means that we will fall back to
    * returning aItem->ReferenceFrame() when we can't find another animated
    * geometry root.
    */
   static nsIFrame* GetAnimatedGeometryRootFor(nsDisplayItem* aItem,
                                               nsDisplayListBuilder* aBuilder);
 
   /**
-   * Finds the nearest ancestor frame to aFrame that is considered to have (or
-   * will have) "animated geometry". This could be aFrame. Returns
-   * aStopAtAncestor if no closer ancestor is found.
-   */
-  static nsIFrame* GetAnimatedGeometryRootForFrame(nsIFrame* aFrame,
-                                                   const nsIFrame* aStopAtAncestor);
-
-  /**
     * GetScrollableFrameFor returns the scrollable frame for a scrolled frame
     */
   static nsIScrollableFrame* GetScrollableFrameFor(const nsIFrame *aScrolledFrame);
 
   /**
    * GetNearestScrollableFrameForDirection locates the first ancestor of
    * aFrame (or aFrame itself) that is scrollable with overflow:scroll or
    * overflow:auto in the given direction and where either the scrollbar for
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -5150,16 +5150,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
     nsRenderingContext::AutoPushTranslation
       translate(rc, rangeInfo->mRootOffset);
 
     aArea.MoveBy(-rangeInfo->mRootOffset.x, -rangeInfo->mRootOffset.y);
     nsRegion visible(aArea);
+    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);
 
   return dt->Snapshot();
--- a/layout/forms/nsSelectsAreaFrame.cpp
+++ b/layout/forms/nsSelectsAreaFrame.cpp
@@ -32,19 +32,16 @@ public:
   nsDisplayOptionEventGrabber(nsDisplayListBuilder* aBuilder,
                               nsIFrame* aFrame, nsDisplayItem* aItem)
     : nsDisplayWrapList(aBuilder, aFrame, aItem) {}
   nsDisplayOptionEventGrabber(nsDisplayListBuilder* aBuilder,
                               nsIFrame* aFrame, nsDisplayList* aList)
     : nsDisplayWrapList(aBuilder, aFrame, aList) {}
   virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
                        HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames);
-  virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE {
-    return false;
-  }
   NS_DISPLAY_DECL_NAME("OptionEventGrabber", TYPE_OPTION_EVENT_GRABBER)
 };
 
 void nsDisplayOptionEventGrabber::HitTest(nsDisplayListBuilder* aBuilder,
     const nsRect& aRect, HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames)
 {
   nsTArray<nsIFrame*> outFrames;
   mList.HitTest(aBuilder, aRect, aState, &outFrames);
--- a/layout/generic/nsCanvasFrame.h
+++ b/layout/generic/nsCanvasFrame.h
@@ -150,17 +150,18 @@ class nsDisplayCanvasBackgroundColor : p
 public:
   nsDisplayCanvasBackgroundColor(nsDisplayListBuilder* aBuilder, nsIFrame *aFrame)
     : nsDisplayItem(aBuilder, aFrame)
     , mColor(NS_RGBA(0,0,0,0))
   {
   }
 
   virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
-                                 nsRegion* aVisibleRegion) MOZ_OVERRIDE
+                                 nsRegion* aVisibleRegion,
+                                 const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE
   {
     return NS_GET_A(mColor) > 0;
   }
   virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
                                    bool* aSnap) MOZ_OVERRIDE
   {
     if (NS_GET_A(mColor) == 255) {
       return nsRegion(GetBounds(aBuilder, aSnap));
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -1732,19 +1732,17 @@ DisplayDebugBorders(nsDisplayListBuilder
     aLists.Outlines()->AppendNewToTop(new (aBuilder)
         nsDisplayGeneric(aBuilder, aFrame, PaintEventTargetBorder, "EventTargetBorder",
                          nsDisplayItem::TYPE_EVENT_TARGET_BORDER));
   }
 }
 #endif
 
 static nsresult
-WrapPreserve3DListInternal(nsIFrame* aFrame, nsDisplayListBuilder *aBuilder,
-                           nsDisplayList *aList, nsDisplayList *aOutput,
-                           uint32_t& aIndex, nsDisplayList* aTemp)
+WrapPreserve3DListInternal(nsIFrame* aFrame, nsDisplayListBuilder *aBuilder, nsDisplayList *aList, nsDisplayList *aOutput, uint32_t& aIndex, nsDisplayList* aTemp)
 {
   if (aIndex > nsDisplayTransform::INDEX_MAX) {
     return NS_OK;
   }
 
   nsresult rv = NS_OK;
   while (nsDisplayItem *item = aList->RemoveBottom()) {
     nsIFrame *childFrame = item->Frame();
@@ -1753,18 +1751,17 @@ WrapPreserve3DListInternal(nsIFrame* aFr
     // and then flush this list into aOutput by wrapping the whole lot with a single
     // nsDisplayTransform.
 
     if (childFrame->GetParent() &&
         (childFrame->GetParent()->Preserves3DChildren() || childFrame == aFrame)) {
       switch (item->GetType()) {
         case nsDisplayItem::TYPE_TRANSFORM: {
           if (!aTemp->IsEmpty()) {
-            aOutput->AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder,
-                aFrame, aTemp, aTemp->GetVisibleRect(), aIndex++));
+            aOutput->AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, aFrame, aTemp, aIndex++));
           }
           // Override item's clipping with our current clip state (if any). Since we're
           // bubbling up a preserve-3d transformed child to a preserve-3d parent,
           // we can be sure the child doesn't have clip state of its own.
           NS_ASSERTION(!item->GetClip().HasClip(), "Unexpected clip on item");
           const DisplayItemClip* clip = aBuilder->ClipState().GetCurrentCombinedClip(aBuilder);
           if (clip) {
             item->SetClip(aBuilder, *clip);
@@ -1776,44 +1773,40 @@ WrapPreserve3DListInternal(nsIFrame* aFr
           nsDisplayWrapList *list = static_cast<nsDisplayWrapList*>(item);
           rv = WrapPreserve3DListInternal(aFrame, aBuilder,
               list->GetChildren(), aOutput, aIndex, aTemp);
           list->~nsDisplayWrapList();
           break;
         }
         case nsDisplayItem::TYPE_OPACITY: {
           if (!aTemp->IsEmpty()) {
-            aOutput->AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder,
-                aFrame, aTemp, aTemp->GetVisibleRect(), aIndex++));
+            aOutput->AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, aFrame, aTemp, aIndex++));
           }
           nsDisplayOpacity *opacity = static_cast<nsDisplayOpacity*>(item);
           nsDisplayList output;
           // Call GetChildren, not GetSameCoordinateSystemChildren, because
           // the preserve-3d children of 'opacity' are temporarily not in the
           // same coordinate system as the opacity --- until this wrapping is done.
           rv = WrapPreserve3DListInternal(aFrame, aBuilder,
               opacity->GetChildren(), &output, aIndex, aTemp);
           if (!aTemp->IsEmpty()) {
-            output.AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder,
-                aFrame, aTemp, aTemp->GetVisibleRect(), aIndex++));
+            output.AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, aFrame, aTemp, aIndex++));
           }
           opacity->GetChildren()->AppendToTop(&output);
           opacity->UpdateBounds(aBuilder);
           aOutput->AppendToTop(item);
           break;
         }
         default: {
           if (childFrame->StyleDisplay()->BackfaceIsHidden()) {
             if (!aTemp->IsEmpty()) {
-              aOutput->AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder,
-                  aFrame, aTemp, aTemp->GetVisibleRect(), aIndex++));
+              aOutput->AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, aFrame, aTemp, aIndex++));
             }
 
-            aOutput->AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder,
-                childFrame, item, item->GetVisibleRect(), aIndex++));
+            aOutput->AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, childFrame, item, aIndex++));
           } else {
             aTemp->AppendToTop(item);
           }
           break;
         }
       } 
     } else {
       aTemp->AppendToTop(item);
@@ -1828,28 +1821,25 @@ WrapPreserve3DListInternal(nsIFrame* aFr
 
 static bool
 IsScrollFrameActive(nsIScrollableFrame* aScrollableFrame)
 {
   return aScrollableFrame && aScrollableFrame->IsScrollingActive();
 }
 
 static nsresult
-WrapPreserve3DList(nsIFrame* aFrame, nsDisplayListBuilder* aBuilder,
-                   nsDisplayList *aList)
+WrapPreserve3DList(nsIFrame* aFrame, nsDisplayListBuilder* aBuilder, nsDisplayList *aList)
 {
   uint32_t index = 0;
   nsDisplayList temp;
   nsDisplayList output;
-  nsresult rv = WrapPreserve3DListInternal(aFrame, aBuilder, aList, &output,
-      index, &temp);
+  nsresult rv = WrapPreserve3DListInternal(aFrame, aBuilder, aList, &output, index, &temp);
 
   if (!temp.IsEmpty()) {
-    output.AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, aFrame,
-        &temp, temp.GetVisibleRect(), index++));
+    output.AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, aFrame, &temp, index++));
   }
 
   aList->AppendToTop(&output);
   return rv;
 }
 
 class AutoSaveRestoreBlendMode
 {
@@ -1912,32 +1902,31 @@ nsIFrame::BuildDisplayListForStackingCon
   bool inTransform = aBuilder->IsInTransform();
   bool isTransformed = IsTransformed();
   // reset blend mode so we can keep track if this stacking context needs have
   // a nsDisplayBlendContainer. Set the blend mode back when the routine exits
   // so we keep track if the parent stacking context needs a container too.
   AutoSaveRestoreBlendMode autoRestoreBlendMode(*aBuilder);
   aBuilder->SetContainsBlendModes(BlendModeSet());
  
-  nsPoint offsetToReferenceFrame = aBuilder->ToReferenceFrame(this);
-
   if (isTransformed) {
     const nsRect overflow = GetVisualOverflowRectRelativeToSelf();
     if (aBuilder->IsForPainting() &&
         nsDisplayTransform::ShouldPrerenderTransformedContent(aBuilder, this)) {
       dirtyRect = overflow;
     } else {
       if (overflow.IsEmpty() && !Preserves3DChildren()) {
         return;
       }
 
-      dirtyRect += offsetToReferenceFrame;
+      nsPoint offset = aBuilder->ToReferenceFrame(this);
+      dirtyRect += offset;
+
       nsRect untransformedDirtyRect;
-      if (nsDisplayTransform::UntransformRect(dirtyRect, overflow, this,
-            offsetToReferenceFrame, &untransformedDirtyRect)) {
+      if (nsDisplayTransform::UntransformRect(dirtyRect, overflow, this, offset, &untransformedDirtyRect)) {
         dirtyRect = untransformedDirtyRect;
       } else {
         NS_WARNING("Unable to untransform dirty rect!");
         // This should only happen if the transform is singular, in which case nothing is visible anyway
         dirtyRect.SetEmpty();
       }
     }
     inTransform = true;
@@ -1946,31 +1935,30 @@ nsIFrame::BuildDisplayListForStackingCon
   bool useOpacity = HasVisualOpacity() && !nsSVGUtils::CanOptimizeOpacity(this);
   bool useBlendMode = disp->mMixBlendMode != NS_STYLE_BLEND_NORMAL;
   bool usingSVGEffects = nsSVGIntegrationUtils::UsingEffectsForFrame(this);
   bool useStickyPosition = disp->mPosition == NS_STYLE_POSITION_STICKY &&
     IsScrollFrameActive(nsLayoutUtils::GetNearestScrollableFrame(GetParent(),
                         nsLayoutUtils::SCROLLABLE_SAME_DOC |
                         nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN));
 
-  nsDisplayListBuilder::AutoBuildingDisplayList
-    buildingDisplayList(aBuilder, this, dirtyRect, true);
   DisplayListClipState::AutoSaveRestore clipState(aBuilder);
 
   if (isTransformed || useOpacity || useBlendMode || usingSVGEffects || useStickyPosition) {
     // We don't need to pass ancestor clipping down to our children;
     // everything goes inside a display item's child list, and the display
     // item itself will be clipped.
     // For transforms we also need to clear ancestor clipping because it's
     // relative to the wrong display item reference frame anyway.
     clipState.Clear();
   }
 
   nsDisplayListCollection set;
-  {
+  {    
+    nsDisplayListBuilder::AutoBuildingDisplayList rootSetter(aBuilder, true);
     DisplayListClipState::AutoSaveRestore nestedClipState(aBuilder);
     nsDisplayListBuilder::AutoInTransformSetter
       inTransformSetter(aBuilder, inTransform);
     CheckForTouchEventHandler(aBuilder, this);
 
     if (usingSVGEffects) {
       dirtyRect =
         nsSVGIntegrationUtils::GetRequiredSourceForInvalidArea(this, dirtyRect);
@@ -2001,25 +1989,25 @@ nsIFrame::BuildDisplayListForStackingCon
 
   if (aBuilder->IsBackgroundOnly()) {
     set.BlockBorderBackgrounds()->DeleteAll();
     set.Floats()->DeleteAll();
     set.Content()->DeleteAll();
     set.PositionedDescendants()->DeleteAll();
     set.Outlines()->DeleteAll();
   }
-
+  
   // This z-order sort also sorts secondarily by content order. We need to do
   // this so that boxes produced by the same element are placed together
   // in the sort. Consider a position:relative inline element that breaks
   // across lines and has absolutely positioned children; all the abs-pos
   // children should be z-ordered after all the boxes for the position:relative
   // element itself.
   set.PositionedDescendants()->SortByZOrder(aBuilder, GetContent());
-
+  
   nsDisplayList resultList;
   // Now follow the rules of http://www.w3.org/TR/CSS21/zindex.html
   // 1,2: backgrounds and borders
   resultList.AppendToTop(set.BorderBackground());
   // 3: negative z-index children.
   for (;;) {
     nsDisplayItem* item = set.PositionedDescendants()->GetBottom();
     if (item && item->ZIndex() < 0) {
@@ -2079,39 +2067,36 @@ nsIFrame::BuildDisplayListForStackingCon
   }
   /* If we have sticky positioning, wrap it in a sticky position item.
    */
   if (useStickyPosition) {
     resultList.AppendNewToTop(
         new (aBuilder) nsDisplayStickyPosition(aBuilder, this, &resultList));
   }
 
-  /* If we're going to apply a transformation and don't have preserve-3d set, wrap
-   * everything in an nsDisplayTransform. If there's nothing in the list, don't add
+  /* If we're going to apply a transformation and don't have preserve-3d set, wrap 
+   * everything in an nsDisplayTransform. If there's nothing in the list, don't add 
    * anything.
    *
    * For the preserve-3d case we want to individually wrap every child in the list with
    * a separate nsDisplayTransform instead. When the child is already an nsDisplayTransform,
    * we can skip this step, as the computed transform will already include our own.
    *
    * We also traverse into sublists created by nsDisplayWrapList or nsDisplayOpacity, so that
    * we find all the correct children.
    */
   if (isTransformed && !resultList.IsEmpty()) {
     // Restore clip state now so nsDisplayTransform is clipped properly.
     clipState.Restore();
-    // Revert to the dirtyrect coming in from the parent, without our transform
-    // taken into account.
-    buildingDisplayList.SetDirtyRect(aDirtyRect + offsetToReferenceFrame);
 
     if (Preserves3DChildren()) {
       WrapPreserve3DList(this, aBuilder, &resultList);
     } else {
       resultList.AppendNewToTop(
-        new (aBuilder) nsDisplayTransform(aBuilder, this, &resultList, dirtyRect));
+        new (aBuilder) nsDisplayTransform(aBuilder, this, &resultList));
     }
   }
 
   /* If adding both a nsDisplayBlendContainer and a nsDisplayMixBlendMode to the
    * same list, the nsDisplayBlendContainer should be added first. This only
    * happens when the element creating this stacking context has mix-blend-mode
    * and also contains a child which has mix-blend-mode.
    * The nsDisplayBlendContainer must be added to the list first, so it does not
@@ -2295,18 +2280,25 @@ nsIFrame::BuildDisplayListForChild(nsDis
        (disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_STACKING_CONTEXT) ||
       (aFlags & DISPLAY_CHILD_FORCE_STACKING_CONTEXT)) {
     // If you change this, also change IsPseudoStackingContextFromStyle()
     pseudoStackingContext = true;
   }
   NS_ASSERTION(!isStackingContext || pseudoStackingContext,
                "Stacking contexts must also be pseudo-stacking-contexts");
 
+  bool isInFixedPos = aBuilder->IsInFixedPos() ||
+                        (isPositioned &&
+                         disp->mPosition == NS_STYLE_POSITION_FIXED &&
+                         nsLayoutUtils::IsReallyFixedPos(child));
+  nsDisplayListBuilder::AutoInFixedPosSetter
+    buildingInFixedPos(aBuilder, isInFixedPos);
+
   nsDisplayListBuilder::AutoBuildingDisplayList
-    buildingForChild(aBuilder, child, dirty, pseudoStackingContext);
+    buildingForChild(aBuilder, child, pseudoStackingContext);
   DisplayListClipState::AutoClipMultiple clipState(aBuilder);
   CheckForTouchEventHandler(aBuilder, child);
 
   if (savedOutOfFlowData) {
     clipState.SetClipForContainingBlockDescendants(
       &savedOutOfFlowData->mContainingBlockClip);
   }
 
@@ -5231,22 +5223,16 @@ nsIFrame::GetOverflowAreasRelativeToSelf
 
 nsRect
 nsIFrame::GetScrollableOverflowRectRelativeToParent() const
 {
   return GetScrollableOverflowRect() + mRect.TopLeft();
 }
 
 nsRect
-nsIFrame::GetVisualOverflowRectRelativeToParent() const
-{
-  return GetVisualOverflowRect() + mRect.TopLeft();
-}
-
-nsRect
 nsIFrame::GetScrollableOverflowRectRelativeToSelf() const
 {
   if (IsTransformed()) {
     nsOverflowAreas* preTransformOverflows = static_cast<nsOverflowAreas*>
       (Properties().Get(PreTransformOverflowAreasProperty()));
     if (preTransformOverflows)
       return preTransformOverflows->ScrollableOverflow();
   }
--- a/layout/generic/nsHTMLCanvasFrame.cpp
+++ b/layout/generic/nsHTMLCanvasFrame.cpp
@@ -266,16 +266,17 @@ nsHTMLCanvasFrame::BuildLayer(nsDisplayL
 
   // Transform the canvas into the right place
   gfx::Matrix transform;
   gfxPoint p = r.TopLeft() + aContainerParameters.mOffset;
   transform.Translate(p.x, p.y);
   transform.Scale(r.Width()/canvasSize.width, r.Height()/canvasSize.height);
   layer->SetBaseTransform(gfx::Matrix4x4::From2D(transform));
   layer->SetFilter(nsLayoutUtils::GetGraphicsFilterForFrame(this));
+  layer->SetVisibleRegion(nsIntRect(0, 0, canvasSize.width, canvasSize.height));
 
   return layer.forget();
 }
 
 void
 nsHTMLCanvasFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                     const nsRect&           aDirtyRect,
                                     const nsDisplayListSet& aLists)
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -2265,25 +2265,16 @@ public:
    * coordinate system (before transforms are applied).
    *
    * @return the rect relative to this frame, before any CSS transforms have
    * been applied, i.e. in this frame's coordinate system
    */
   nsRect GetVisualOverflowRectRelativeToSelf() const;
 
   /**
-   * Same as GetVisualOverflowRect, except relative to the parent
-   * frame.
-   *
-   * @return the rect relative to the parent frame, in the parent frame's
-   * coordinate system
-   */
-  nsRect GetVisualOverflowRectRelativeToParent() const;
-
-  /**
    * Returns this frame's visual overflow rect as it would be before taking
    * account of SVG effects or transforms. The rect returned is relative to
    * this frame.
    */
   nsRect GetPreEffectsVisualOverflowRect() const;
 
   /**
    * Store the overflow area in the frame's mOverflow.mVisualDeltas
--- a/layout/generic/nsImageFrame.cpp
+++ b/layout/generic/nsImageFrame.cpp
@@ -1420,16 +1420,17 @@ nsDisplayImage::ConfigureLayer(ImageLaye
   const gfxRect destRect = GetDestRect();
 
   gfx::Matrix transform;
   gfxPoint p = destRect.TopLeft() + aOffset;
   transform.Translate(p.x, p.y);
   transform.Scale(destRect.Width()/imageWidth,
                   destRect.Height()/imageHeight);
   aLayer->SetBaseTransform(gfx::Matrix4x4::From2D(transform));
+  aLayer->SetVisibleRegion(nsIntRect(0, 0, imageWidth, imageHeight));
 }
 
 void
 nsImageFrame::PaintImage(nsRenderingContext& aRenderingContext, nsPoint aPt,
                          const nsRect& aDirtyRect, imgIContainer* aImage,
                          uint32_t aFlags)
 {
   // Render the image into our content area (the area inside
--- a/layout/generic/nsObjectFrame.cpp
+++ b/layout/generic/nsObjectFrame.cpp
@@ -834,37 +834,34 @@ nsObjectFrame::PaintPrintPlugin(nsIFrame
                                 const nsRect& aDirtyRect, nsPoint aPt)
 {
   nsPoint pt = aPt + aFrame->GetContentRectRelativeToSelf().TopLeft();
   nsRenderingContext::AutoPushTranslation translate(aCtx, pt);
   // FIXME - Bug 385435: Doesn't aDirtyRect need translating too?
   static_cast<nsObjectFrame*>(aFrame)->PrintPlugin(*aCtx, aDirtyRect);
 }
 
-/**
- * nsDisplayPluginReadback creates an active ReadbackLayer. The ReadbackLayer
- * obtains from the compositor the contents of the window underneath
- * the ReadbackLayer, which we then use as an opaque buffer for plugins to
- * asynchronously draw onto.
- */
 class nsDisplayPluginReadback : public nsDisplayItem {
 public:
   nsDisplayPluginReadback(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
     : nsDisplayItem(aBuilder, aFrame)
   {
     MOZ_COUNT_CTOR(nsDisplayPluginReadback);
   }
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayPluginReadback() {
     MOZ_COUNT_DTOR(nsDisplayPluginReadback);
   }
 #endif
 
   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
                            bool* aSnap) MOZ_OVERRIDE;
+  virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
+                                   nsRegion* aVisibleRegion,
+                                   const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE;
 
   NS_DISPLAY_DECL_NAME("PluginReadback", TYPE_PLUGIN_READBACK)
 
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
                                              const ContainerLayerParameters& aContainerParameters) MOZ_OVERRIDE
   {
     return static_cast<nsObjectFrame*>(mFrame)->BuildLayer(aBuilder, aManager, this, aContainerParameters);
@@ -887,16 +884,35 @@ GetDisplayItemBounds(nsDisplayListBuilde
 
 nsRect
 nsDisplayPluginReadback::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
 {
   *aSnap = false;
   return GetDisplayItemBounds(aBuilder, this, mFrame);
 }
 
+bool
+nsDisplayPluginReadback::ComputeVisibility(nsDisplayListBuilder* aBuilder,
+                                           nsRegion* aVisibleRegion,
+                                           const nsRect& aAllowVisibleRegionExpansion)
+{
+  if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion,
+                                        aAllowVisibleRegionExpansion))
+    return false;
+
+  nsRect expand;
+  bool snap;
+  expand.IntersectRect(aAllowVisibleRegionExpansion, GetBounds(aBuilder, &snap));
+  // *Add* our bounds to the visible region so that stuff underneath us is
+  // likely to be made visible, so we can use it for a background! This is
+  // a bit crazy since we normally only subtract from the visible region.
+  aVisibleRegion->Or(*aVisibleRegion, expand);
+  return true;
+}
+
 #ifdef MOZ_WIDGET_ANDROID
 
 class nsDisplayPluginVideo : public nsDisplayItem {
 public:
   nsDisplayPluginVideo(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsNPAPIPluginInstance::VideoInfo* aVideoInfo)
     : nsDisplayItem(aBuilder, aFrame), mVideoInfo(aVideoInfo)
   {
     MOZ_COUNT_CTOR(nsDisplayPluginVideo);
@@ -904,16 +920,19 @@ public:
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayPluginVideo() {
     MOZ_COUNT_DTOR(nsDisplayPluginVideo);
   }
 #endif
 
   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
                            bool* aSnap) MOZ_OVERRIDE;
+  virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
+                                   nsRegion* aVisibleRegion,
+                                   const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE;
 
   NS_DISPLAY_DECL_NAME("PluginVideo", TYPE_PLUGIN_VIDEO)
 
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
                                              const ContainerLayerParameters& aContainerParameters) MOZ_OVERRIDE
   {
     return static_cast<nsObjectFrame*>(mFrame)->BuildLayer(aBuilder, aManager, this, aContainerParameters);
@@ -934,16 +953,25 @@ private:
 
 nsRect
 nsDisplayPluginVideo::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
 {
   *aSnap = false;
   return GetDisplayItemBounds(aBuilder, this, mFrame);
 }
 
+bool
+nsDisplayPluginVideo::ComputeVisibility(nsDisplayListBuilder* aBuilder,
+                                           nsRegion* aVisibleRegion,
+                                           const nsRect& aAllowVisibleRegionExpansion)
+{
+  return nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion,
+                                          aAllowVisibleRegionExpansion);
+}
+
 #endif
 
 nsRect
 nsDisplayPlugin::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
 {
   *aSnap = true;
   return GetDisplayItemBounds(aBuilder, this, mFrame);
 }
@@ -954,17 +982,18 @@ nsDisplayPlugin::Paint(nsDisplayListBuil
 {
   nsObjectFrame* f = static_cast<nsObjectFrame*>(mFrame);
   bool snap;
   f->PaintPlugin(aBuilder, *aCtx, mVisibleRect, GetBounds(aBuilder, &snap));
 }
 
 bool
 nsDisplayPlugin::ComputeVisibility(nsDisplayListBuilder* aBuilder,
-                                   nsRegion* aVisibleRegion)
+                                   nsRegion* aVisibleRegion,
+                                   const nsRect& aAllowVisibleRegionExpansion)
 {
   if (aBuilder->IsForPluginGeometry()) {
     nsObjectFrame* f = static_cast<nsObjectFrame*>(mFrame);
     if (!aBuilder->IsInTransform() || f->IsPaintedByGecko()) {
       // Since transforms induce reference frames, we don't need to worry
       // about this method fluffing out due to non-rectilinear transforms.
       nsRect rAncestor = nsLayoutUtils::TransformFrameRectToAncestor(f,
           f->GetContentRectRelativeToSelf(), ReferenceFrame());
@@ -993,17 +1022,18 @@ nsDisplayPlugin::ComputeVisibility(nsDis
     if (f->mInnerView) {
       // This should produce basically the same rectangle (but not relative
       // to the root frame). We only call this here for the side-effect of
       // setting mViewToWidgetOffset on the view.
       f->mInnerView->CalcWidgetBounds(eWindowType_plugin);
     }
   }
 
-  return nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion);
+  return nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion,
+                                          aAllowVisibleRegionExpansion);
 }
 
 nsRegion
 nsDisplayPlugin::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
                                  bool* aSnap)
 {
   *aSnap = false;
   nsRegion result;
@@ -1577,16 +1607,17 @@ nsObjectFrame::BuildLayer(nsDisplayListB
   }
 
   // Set a transform on the layer to draw the plugin in the right place
   Matrix transform;
   gfxPoint p = r.TopLeft() + aContainerParameters.mOffset;
   transform.Translate(p.x, p.y);
 
   layer->SetBaseTransform(Matrix4x4::From2D(transform));
+  layer->SetVisibleRegion(ThebesIntRect(IntRect(IntPoint(0, 0), size)));
   return layer.forget();
 }
 
 void
 nsObjectFrame::PaintPlugin(nsDisplayListBuilder* aBuilder,
                            nsRenderingContext& aRenderingContext,
                            const nsRect& aDirtyRect, const nsRect& aPluginRect)
 {
--- a/layout/generic/nsObjectFrame.h
+++ b/layout/generic/nsObjectFrame.h
@@ -314,17 +314,18 @@ public:
 #endif
 
   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE;
   virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
                                    bool* aSnap) MOZ_OVERRIDE;
   virtual void Paint(nsDisplayListBuilder* aBuilder,
                      nsRenderingContext* aCtx) MOZ_OVERRIDE;
   virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
-                                 nsRegion* aVisibleRegion) MOZ_OVERRIDE;
+                                   nsRegion* aVisibleRegion,
+                                   const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE;
 
   NS_DISPLAY_DECL_NAME("Plugin", TYPE_PLUGIN)
 
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
                                              const ContainerLayerParameters& aContainerParameters) MOZ_OVERRIDE
   {
     return static_cast<nsObjectFrame*>(mFrame)->BuildLayer(aBuilder,
--- a/layout/generic/nsPageFrame.cpp
+++ b/layout/generic/nsPageFrame.cpp
@@ -409,32 +409,32 @@ PruneDisplayListForExtraPage(nsDisplayLi
         continue;
       }
     }
     newList.AppendToTop(i);
   }
   aList->AppendToTop(&newList);
 }
 
-static void
+static nsresult
 BuildDisplayListForExtraPage(nsDisplayListBuilder* aBuilder,
                              nsPageFrame* aPage, nsIFrame* aExtraPage,
-                             const nsRect& aDirtyRect, nsDisplayList* aList)
+                             nsDisplayList* aList)
 {
-  // The only content in aExtraPage we care about is out-of-flow content whose
-  // placeholders have occurred in aPage. If
-  // NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO is not set, then aExtraPage has
-  // no such content.
-  if (!aExtraPage->HasAnyStateBits(NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO)) {
-    return;
-  }
   nsDisplayList list;
-  aExtraPage->BuildDisplayListForStackingContext(aBuilder, aDirtyRect, &list);
+  // Pass an empty dirty rect since we're only interested in finding
+  // placeholders whose out-of-flows are in the page
+  // aBuilder->GetReferenceFrame(), and the paths to those placeholders
+  // have already been marked as NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO.
+  // Note that we should still do a prune step since we don't want to
+  // rely on dirty-rect checking for correctness.
+  aExtraPage->BuildDisplayListForStackingContext(aBuilder, nsRect(), &list);
   PruneDisplayListForExtraPage(aBuilder, aPage, aExtraPage, &list);
   aList->AppendToTop(&list);
+  return NS_OK;
 }
 
 static nsIFrame*
 GetNextPage(nsIFrame* aPageContentFrame)
 {
   // XXX ugh
   nsIFrame* pageFrame = aPageContentFrame->GetParent();
   NS_ASSERTION(pageFrame->GetType() == nsGkAtoms::pageFrame,
@@ -501,49 +501,41 @@ nsPageFrame::BuildDisplayList(nsDisplayL
   {
     DisplayListClipState::AutoSaveRestore clipState(aBuilder);
 
     // Overwrite current clip, since we're going to wrap in a transform
     // and the current clip is no longer meaningful.
     clipState.Clear();
     clipState.ClipContainingBlockDescendants(clipRect, nullptr);
 
-    nsRect dirtyRect = child->GetVisualOverflowRectRelativeToSelf();
-    child->BuildDisplayListForStackingContext(aBuilder, dirtyRect, &content);
+    child->BuildDisplayListForStackingContext(aBuilder,
+      child->GetVisualOverflowRectRelativeToSelf(), &content);
 
     // We may need to paint out-of-flow frames whose placeholders are
     // on other pages. Add those pages to our display list. Note that
     // out-of-flow frames can't be placed after their placeholders so
     // we don't have to process earlier pages. The display lists for
     // these extra pages are pruned so that only display items for the
     // page we currently care about (which we would have reached by
     // following placeholders to their out-of-flows) end up on the list.
     nsIFrame* page = child;
     while ((page = GetNextPage(page)) != nullptr) {
-      BuildDisplayListForExtraPage(aBuilder, this, page,
-          dirtyRect + child->GetOffsetTo(page), &content);
+      BuildDisplayListForExtraPage(aBuilder, this, page, &content);
     }
 
-    // Invoke AutoBuildingDisplayList to ensure that the correct dirtyRect
-    // is used to compute the visible rect if AddCanvasBackgroundColorItem
-    // creates a display item.
-    nsDisplayListBuilder::AutoBuildingDisplayList
-      building(aBuilder, child, dirtyRect, true);
-
     // Add the canvas background color to the bottom of the list. This
     // happens after we've built the list so that AddCanvasBackgroundColorItem
     // can monkey with the contents if necessary.
     nsRect backgroundRect =
       nsRect(aBuilder->ToReferenceFrame(child), child->GetSize());
     PresContext()->GetPresShell()->AddCanvasBackgroundColorItem(
       *aBuilder, content, child, backgroundRect, NS_RGBA(0,0,0,0));
   }
 
-  content.AppendNewToTop(new (aBuilder) nsDisplayTransform(aBuilder, child,
-      &content, content.GetVisibleRect(), ::ComputePageTransform));
+  content.AppendNewToTop(new (aBuilder) nsDisplayTransform(aBuilder, child, &content, ::ComputePageTransform));
 
   set.Content()->AppendToTop(&content);
 
   if (PresContext()->IsRootPaginatedDocument()) {
     set.Content()->AppendNewToTop(new (aBuilder)
         nsDisplayGeneric(aBuilder, this, ::PaintHeaderFooter,
                          "HeaderFooter",
                          nsDisplayItem::TYPE_HEADER_FOOTER));
--- a/layout/generic/nsSimplePageSequenceFrame.cpp
+++ b/layout/generic/nsSimplePageSequenceFrame.cpp
@@ -783,32 +783,26 @@ nsSimplePageSequenceFrame::BuildDisplayL
 
   {
     // Clear clip state while we construct the children of the
     // nsDisplayTransform, since they'll be in a different coordinate system.
     DisplayListClipState::AutoSaveRestore clipState(aBuilder);
     clipState.Clear();
 
     nsIFrame* child = GetFirstPrincipalChild();
-    nsRect dirty = aDirtyRect;
-    dirty.ScaleInverseRoundOut(PresContext()->GetPrintPreviewScale());
-
     while (child) {
-      if (child->GetVisualOverflowRectRelativeToParent().Intersects(dirty)) {
-        child->BuildDisplayListForStackingContext(aBuilder,
-            dirty - child->GetPosition(), &content);
-        aBuilder->ResetMarkedFramesForDisplayList();
-      }
+      child->BuildDisplayListForStackingContext(aBuilder,
+          child->GetVisualOverflowRectRelativeToSelf(), &content);
+      aBuilder->ResetMarkedFramesForDisplayList();
       child = child->GetNextSibling();
     }
   }
 
   content.AppendNewToTop(new (aBuilder)
-      nsDisplayTransform(aBuilder, this, &content, content.GetVisibleRect(),
-                         ::ComputePageSequenceTransform));
+      nsDisplayTransform(aBuilder, this, &content, ::ComputePageSequenceTransform));
 
   aLists.Content()->AppendToTop(&content);
 }
 
 nsIAtom*
 nsSimplePageSequenceFrame::GetType() const
 {
   return nsGkAtoms::sequenceFrame; 
--- a/layout/generic/nsSubDocumentFrame.cpp
+++ b/layout/generic/nsSubDocumentFrame.cpp
@@ -439,16 +439,23 @@ nsSubDocumentFrame::BuildDisplayList(nsD
   nsIScrollableFrame *sf = presShell->GetRootScrollFrameAsScrollable();
   bool constructResolutionItem = subdocRootFrame &&
     (presShell->GetXResolution() != 1.0 || presShell->GetYResolution() != 1.0);
   bool constructZoomItem = subdocRootFrame && parentAPD != subdocAPD;
   bool needsOwnLayer = constructResolutionItem || constructZoomItem ||
     haveDisplayPort ||
     presContext->IsRootContentDocument() || (sf && sf->IsScrollingActive());
 
+  // Don't let in fixed pos propagate down to child documents. This makes
+  // it a little less effective but doesn't regress an important case of a
+  // child document being in a fixed pos element where we would do no occlusion
+  // at all if we let it propagate down.
+  nsDisplayListBuilder::AutoInFixedPosSetter
+    buildingInFixedPos(aBuilder, false);
+
   nsDisplayList childItems;
 
   {
     DisplayListClipState::AutoSaveRestore nestedClipState(aBuilder);
     if (needsOwnLayer) {
       // Clear current clip. There's no point in propagating it down, since
       // the layer we will construct will be clipped by the current clip.
       // In fact for nsDisplayZoom propagating it down would be incorrect since
--- a/layout/generic/nsVideoFrame.cpp
+++ b/layout/generic/nsVideoFrame.cpp
@@ -214,16 +214,17 @@ nsVideoFrame::BuildLayer(nsDisplayListBu
   layer->SetFilter(nsLayoutUtils::GetGraphicsFilterForFrame(this));
   layer->SetContentFlags(Layer::CONTENT_OPAQUE);
   // Set a transform on the layer to draw the video in the right place
   gfx::Matrix transform;
   gfxPoint p = r.TopLeft() + aContainerParameters.mOffset;
   transform.Translate(p.x, p.y);
   transform.Scale(r.Width()/frameSize.width, r.Height()/frameSize.height);
   layer->SetBaseTransform(gfx::Matrix4x4::From2D(transform));
+  layer->SetVisibleRegion(nsIntRect(0, 0, frameSize.width, frameSize.height));
   nsRefPtr<Layer> result = layer.forget();
   return result.forget();
 }
 
 class DispatchResizeToControls : public nsRunnable
 {
 public:
   DispatchResizeToControls(nsIContent* aContent)
--- a/layout/ipc/RenderFrameParent.cpp
+++ b/layout/ipc/RenderFrameParent.cpp
@@ -868,16 +868,17 @@ RenderFrameParent::BuildLayer(nsDisplayL
     }
     if (!layer) {
       // Probably a temporary layer manager that doesn't know how to
       // use ref layers.
       return nullptr;
     }
     static_cast<RefLayer*>(layer.get())->SetReferentId(id);
     nsIntPoint offset = GetContentRectLayerOffset(aFrame, aBuilder);
+    layer->SetVisibleRegion(aVisibleRect - offset);
     // We can only have an offset if we're a child of an inactive
     // container, but our display item is LAYER_ACTIVE_FORCE which
     // forces all layers above to be active.
     MOZ_ASSERT(aContainerParameters.mOffset == nsIntPoint());
     gfx::Matrix4x4 m;
     m.Translate(offset.x, offset.y, 0.0);
     // Remote content can't be repainted by us, so we multiply down
     // the resolution that our container expects onto our container.
@@ -920,16 +921,17 @@ RenderFrameParent::BuildLayer(nsDisplayL
   if (mFrameLoader->AsyncScrollEnabled()) {
     const nsContentView* view = GetRootContentView();
     BuildBackgroundPatternFor(mContainer,
                               shadowRoot,
                               view->GetViewConfig(),
                               mBackgroundColor,
                               aManager, aFrame);
   }
+  mContainer->SetVisibleRegion(aVisibleRect);
 
   return nsRefPtr<Layer>(mContainer).forget();
 }
 
 void
 RenderFrameParent::OwnerContentChanged(nsIContent* aContent)
 {
   NS_ABORT_IF_FALSE(mFrameLoader->GetOwnerContent() == aContent,
deleted file mode 100644
--- a/layout/reftests/bugs/1022612-1-ref.html
+++ /dev/null
@@ -1,7 +0,0 @@
-<!DOCTYPE HTML>
-<div style="width:400px;">
-  <span style="opacity:0.5;">
-    <span style="position:relative; display:inline-block; width:400px; height:200px;"></span>
-    <span style="position:relative; top:-300px; display:inline-block; background:lime; width:400px; height:400px;"></span>
-  </span>
-</div>
deleted file mode 100644
--- a/layout/reftests/bugs/1022612-1.html
+++ /dev/null
@@ -1,7 +0,0 @@
-<!DOCTYPE HTML>
-<div style="width:400px;">
-  <span style="opacity:0.5;">
-    <span style="position:relative; display:inline-block; background:red; width:400px; height:200px;"></span>
-    <span style="position:relative; top:-300px; display:inline-block; background:lime; width:400px; height:400px;"></span>
-  </span>
-</div>
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1785,17 +1785,17 @@ test-pref(layout.css.sticky.enabled,true
 fuzzy-if(cocoaWidget,1,40) == 928607-1.html 928607-1-ref.html
 == 931464-1.html 931464-1-ref.html
 == 931853.html 931853-ref.html
 == 931853-quirks.html 931853-quirks-ref.html
 fuzzy-if(OSX==10.6,2,30) skip-if(B2G&&browserIsRemote) == 933264-1.html 933264-1-ref.html
 == 936670-1.svg 936670-1-ref.svg
 == 941940-1.html 941940-1-ref.html
 fails == 942017.html 942017-ref.html # bug 942017
-fuzzy-if(B2G,1,7) == 942672-1.html 942672-1-ref.html
+== 942672-1.html 942672-1-ref.html
 == 953334-win32-clipping.html 953334-win32-clipping-ref.html
 == 956513-1.svg 956513-1-ref.svg
 == 944291-1.html 944291-1-ref.html
 == 950436-1.html 950436-1-ref.html
 == 957770-1.svg 957770-1-ref.svg
 == 960277-1.html 960277-1-ref.html
 pref(layout.css.overflow-clip-box.enabled,true) fuzzy(50,31) == 966992-1.html 966992-1-ref.html
 skip-if(Android) == 966510-1.html 966510-1-ref.html # scrollable elements other than the root probably won't work well on android until bug 776030 is fixed
@@ -1808,10 +1808,9 @@ skip-if(Android) == 966510-2.html 966510
 == 985303-1a.html 985303-1-ref.html
 == 985303-1b.html 985303-1-ref.html
 == 987680-1.html 987680-1-ref.html
 fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,24) == 991046-1.html 991046-1-ref.html
 pref(layout.css.overflow-clip-box.enabled,true) == 992447.html 992447-ref.html
 pref(layout.css.sticky.enabled,true) == 1005405-1.html 1005405-1-ref.html
 pref(layout.css.will-change.enabled,true) == 1018522-1.html 1018522-1-ref.html
 pref(browser.display.use_document_fonts,0) == 1022481-1.html 1022481-1-ref.html
-== 1022612-1.html 1022612-1-ref.html
 == 1024473-1.html 1024473-1-ref.html
--- a/layout/reftests/forms/fieldset/positioned-container-1-ref.html
+++ b/layout/reftests/forms/fieldset/positioned-container-1-ref.html
@@ -1,11 +1,11 @@
 <!DOCTYPE HTML>
 <html>
 <body>
 <fieldset style="position:relative; overflow:hidden; width:500px; height:500px;">
   <legend>Legend</legend>
   <div style="height:1000px;">
-    <div style="position:absolute; padding:2px; left:20px; top:20px; background:yellow;">Abs-pos</div>
+    <div style="position:absolute; left:20px; top:20px; background:yellow;">Abs-pos</div>
   </div>
 </fieldset>
 </body>
 </html>
--- a/layout/reftests/forms/fieldset/positioned-container-1.html
+++ b/layout/reftests/forms/fieldset/positioned-container-1.html
@@ -1,14 +1,14 @@
 <!DOCTYPE HTML>
 <html>
 <body>
 <fieldset id="f" style="position:relative; overflow:hidden; width:500px; height:500px;">
   <legend>Legend</legend>
   <div style="height:1000px;">
-    <div style="position:absolute; padding:2px; left:20px; top:50px; background:yellow;">Abs-pos</div>
+    <div style="position:absolute; left:20px; top:50px; background:yellow;">Abs-pos</div>
   </div>
 </fieldset>
 <script>
 f.scrollTop = 30;
 </script>
 </body>
 </html>
--- a/layout/reftests/text/reftest.list
+++ b/layout/reftests/text/reftest.list
@@ -47,17 +47,17 @@ fails-if(Android) skip-if(d2d||cocoaWidg
 # Platforms with subpixel positioning already have inconsistent glyphs by
 # design, but that is considered more tolerable because they are subpixel
 # inconsistencies.  On those platforms we just test that glyph positions are
 # subpixel.
 # D2D/DirectWrite results depend on the rendering mode chosen, so considering this as random for now.
 skip-if(!(d2d||cocoaWidget)) random-if(d2d) != subpixel-glyphs-x-2a.html subpixel-glyphs-x-2b.html
 skip-if(B2G) HTTP(..) == subpixel-glyphs-x-3a.html subpixel-glyphs-x-3b.html
 # No platforms do subpixel positioning vertically
-fuzzy-if(Android,19,2) == subpixel-glyphs-y-1a.html subpixel-glyphs-y-1b.html
+== subpixel-glyphs-y-1a.html subpixel-glyphs-y-1b.html
 fuzzy-if((Android||B2G),231,653) == subpixel-lineheight-1a.html subpixel-lineheight-1b.html
 == swash-1.html swash-1-ref.html
 HTTP(..) != synthetic-bold-metrics-01.html synthetic-bold-metrics-01-notref.html
 HTTP(..) == synthetic-bold-papyrus-01.html synthetic-bold-papyrus-01-ref.html
 # Tests for text-align-last
 == text-align-last-start.html text-align-last-start-ref.html
 == text-align-last-end.html text-align-last-end-ref.html
 == text-align-last-center.html text-align-last-center-ref.html
--- a/layout/tables/nsTableFrame.cpp
+++ b/layout/tables/nsTableFrame.cpp
@@ -1083,16 +1083,30 @@ nsTableFrame::GetChildLists(nsTArray<Chi
 }
 
 nsRect
 nsDisplayTableItem::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
   *aSnap = false;
   return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame();
 }
 
+bool
+nsDisplayTableItem::IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuilder,
+                                                   nsIFrame* aFrame)
+{
+  if (!mPartHasFixedBackground)
+    return false;
+
+  // If aFrame is mFrame or an ancestor in this document, and aFrame is
+  // not the viewport frame, then moving aFrame will move mFrame
+  // relative to the viewport, so our fixed-pos background will change.
+  return mFrame == aFrame ||
+    nsLayoutUtils::IsProperAncestorFrame(aFrame, mFrame);
+}
+
 /* static */ void
 nsDisplayTableItem::UpdateForFrameBackground(nsIFrame* aFrame)
 {
   nsStyleContext *bgSC;
   if (!nsCSSRendering::FindBackground(aFrame, &bgSC))
     return;
   if (!bgSC->StyleBackground()->HasFixedBackground())
     return;
--- a/layout/tables/nsTableFrame.h
+++ b/layout/tables/nsTableFrame.h
@@ -45,16 +45,18 @@ static inline bool FrameHasBorderOrBackg
 
 class nsDisplayTableItem : public nsDisplayItem
 {
 public:
   nsDisplayTableItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) : 
       nsDisplayItem(aBuilder, aFrame),
       mPartHasFixedBackground(false) {}
 
+  virtual bool IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuilder,
+                                                nsIFrame* aFrame) MOZ_OVERRIDE;
   // With collapsed borders, parts of the collapsed border can extend outside
   // the table part frames, so allow this display element to blow out to our
   // overflow rect. This is also useful for row frames that have spanning
   // cells extending outside them.
   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE;
 
   void UpdateForFrameBackground(nsIFrame* aFrame);
 
--- a/layout/xul/nsBoxFrame.cpp
+++ b/layout/xul/nsBoxFrame.cpp
@@ -1315,18 +1315,18 @@ nsBoxFrame::BuildDisplayList(nsDisplayLi
         forceLayer = (scrollTargetId != layers::FrameMetrics::NULL_SCROLL_ID);
         nsLayoutUtils::SetScrollbarThumbLayerization(this, forceLayer);
       }
     }
     // Check for frames that are marked as a part of the region used
     // in calculating glass margins on Windows.
     const nsStyleDisplay* styles = StyleDisplay();
     if (styles && styles->mAppearance == NS_THEME_WIN_EXCLUDE_GLASS) {
-      aBuilder->AddWindowOpaqueRegion(
-          nsRect(aBuilder->ToReferenceFrame(this), GetSize()));
+      nsRect rect = nsRect(aBuilder->ToReferenceFrame(this), GetSize());
+      aBuilder->AddExcludedGlassRegion(rect);
     }
   }
 
   nsDisplayListCollection tempLists;
   const nsDisplayListSet& destination = forceLayer ? tempLists : aLists;
 
   DisplayBorderBackgroundOutline(aBuilder, destination);
 
@@ -2007,19 +2007,16 @@ public:
     : nsDisplayWrapList(aBuilder, aFrame, aItem), mTargetFrame(aTargetFrame) {}
   nsDisplayXULEventRedirector(nsDisplayListBuilder* aBuilder,
                               nsIFrame* aFrame, nsDisplayList* aList,
                               nsIFrame* aTargetFrame)
     : nsDisplayWrapList(aBuilder, aFrame, aList), mTargetFrame(aTargetFrame) {}
   virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
                        HitTestState* aState,
                        nsTArray<nsIFrame*> *aOutFrames) MOZ_OVERRIDE;
-  virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE {
-    return false;
-  }
   NS_DISPLAY_DECL_NAME("XULEventRedirector", TYPE_XUL_EVENT_REDIRECTOR)
 private:
   nsIFrame* mTargetFrame;
 };
 
 void nsDisplayXULEventRedirector::HitTest(nsDisplayListBuilder* aBuilder,
     const nsRect& aRect, HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames)
 {
--- a/layout/xul/nsImageBoxFrame.cpp
+++ b/layout/xul/nsImageBoxFrame.cpp
@@ -401,16 +401,18 @@ nsDisplayXULImage::ConfigureLayer(ImageL
   NS_ASSERTION(imageWidth != 0 && imageHeight != 0, "Invalid image size!");
 
   gfxPoint p = destRect.TopLeft() + aOffset;
   gfx::Matrix transform;
   transform.Translate(p.x, p.y);
   transform.Scale(destRect.Width()/imageWidth,
                   destRect.Height()/imageHeight);
   aLayer->SetBaseTransform(gfx::Matrix4x4::From2D(transform));
+
+  aLayer->SetVisibleRegion(nsIntRect(0, 0, imageWidth, imageHeight));
 }
 
 already_AddRefed<ImageContainer>
 nsDisplayXULImage::GetContainer(LayerManager* aManager, nsDisplayListBuilder* aBuilder)
 {
   return static_cast<nsImageBoxFrame*>(mFrame)->GetContainer(aManager);
 }
 
--- a/testing/testsuite-targets.mk
+++ b/testing/testsuite-targets.mk
@@ -201,20 +201,20 @@ REMOTE_REFTEST = rm -f ./$@.log && $(PYT
 RUN_REFTEST_B2G = rm -f ./$@.log && $(PYTHON) _tests/reftest/runreftestb2g.py \
   --remote-webserver=10.0.2.2 --b2gpath=${B2G_PATH} --adbpath=${ADB_PATH} \
   --xre-path=${MOZ_HOST_BIN} $(SYMBOLS_PATH) --ignore-window-size \
   --httpd-path=_tests/reftest/reftest/components \
   $(EXTRA_TEST_ARGS) '$(1)' | tee ./$@.log
 
 ifeq ($(OS_ARCH),WINNT) #{
 # GPU-rendered shadow layers are unsupported here
-OOP_CONTENT = --setpref=layers.async-pan-zoom.enabled=true --setpref=browser.tabs.remote=true --setpref=browser.tabs.remote.autostart=true --setpref=layers.acceleration.disabled=true
+OOP_CONTENT = --setpref=browser.tabs.remote=true --setpref=browser.tabs.remote.autostart=true --setpref=layers.acceleration.disabled=true
 GPU_RENDERING =
 else
-OOP_CONTENT = --setpref=layers.async-pan-zoom.enabled=true --setpref=browser.tabs.remote=true --setpref=browser.tabs.remote.autostart=true
+OOP_CONTENT = --setpref=browser.tabs.remote=true --setpref=browser.tabs.remote.autostart=true
 GPU_RENDERING = --setpref=layers.acceleration.force-enabled=true
 endif #}
 
 reftest: TEST_PATH?=layout/reftests/reftest.list
 reftest:
 	$(call RUN_REFTEST,'$(topsrcdir)/$(TEST_PATH)')
 	$(CHECK_TEST_ERROR)