Backed out 3 changesets (bug 967844) for robopan bustage
authorPhil Ringnalda <philringnalda@gmail.com>
Mon, 01 Sep 2014 15:20:13 -0700
changeset 224528 b03db711b80ff403b3609b866fe9be581e43461e
parent 224527 a8cddc6bdffcc9163d2fa3abf9c0968ec49243cf
child 224529 c23b8418e6beeb79462471ed5aa7fbcda3b164a2
push id3979
push userraliiev@mozilla.com
push dateMon, 13 Oct 2014 16:35:44 +0000
treeherdermozilla-beta@30f2cc610691 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs967844
milestone34.0a1
backs out6b53305f1c420766f6c41a93716be2af31e49588
dff3eb181f33576c4362feb63d24afb145405567
4d4b03442eaf93587475a9bfce82e68b99055f0f
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out 3 changesets (bug 967844) for robopan bustage Backed out changeset 6b53305f1c42 (bug 967844) Backed out changeset dff3eb181f33 (bug 967844) Backed out changeset 4d4b03442eaf (bug 967844)
dom/base/nsDOMWindowUtils.cpp
gfx/ipc/GfxMessageUtils.h
gfx/layers/FrameMetrics.h
gfx/layers/LayerMetricsWrapper.h
gfx/layers/Layers.cpp
gfx/layers/Layers.h
gfx/layers/LayersLogging.cpp
gfx/layers/apz/src/APZCTreeManager.cpp
gfx/layers/composite/ContainerLayerComposite.cpp
gfx/layers/composite/TiledContentHost.cpp
gfx/layers/ipc/LayerTransactionParent.cpp
gfx/layers/ipc/LayerTransactionParent.h
gfx/layers/ipc/LayersMessages.ipdlh
gfx/layers/ipc/PLayerTransaction.ipdl
gfx/layers/ipc/ShadowLayers.cpp
layout/base/FrameLayerBuilder.cpp
layout/base/nsDisplayList.cpp
layout/base/nsDisplayList.h
layout/generic/nsGfxScrollFrame.cpp
layout/generic/nsGfxScrollFrame.h
layout/generic/nsIScrollableFrame.h
layout/reftests/async-scrolling/nested-1-ref.html
layout/reftests/async-scrolling/nested-1.html
layout/reftests/async-scrolling/reftest.list
layout/reftests/async-scrolling/split-layers-1-ref.html
layout/reftests/async-scrolling/split-layers-1.html
layout/reftests/async-scrolling/split-layers-multi-scrolling-1-ref.html
layout/reftests/async-scrolling/split-layers-multi-scrolling-1.html
layout/reftests/async-scrolling/split-opacity-layers-1-ref.html
layout/reftests/async-scrolling/split-opacity-layers-1.html
modules/libpref/init/all.js
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -2665,33 +2665,58 @@ nsDOMWindowUtils::GetIsTestControllingRe
 NS_IMETHODIMP
 nsDOMWindowUtils::SetAsyncScrollOffset(nsIDOMNode* aNode,
                                        int32_t aX, int32_t aY)
 {
   nsCOMPtr<Element> element = do_QueryInterface(aNode);
   if (!element) {
     return NS_ERROR_INVALID_ARG;
   }
+  nsIFrame* frame = element->GetPrimaryFrame();
+  if (!frame) {
+    return NS_ERROR_UNEXPECTED;
+  }
+  nsIScrollableFrame* scrollable = do_QueryFrame(frame);
+  nsPresContext* presContext = frame->PresContext();
+  nsIFrame* rootScrollFrame = presContext->PresShell()->GetRootScrollFrame();
+  if (!scrollable) {
+    if (rootScrollFrame && rootScrollFrame->GetContent() == element) {
+      frame = rootScrollFrame;
+      scrollable = do_QueryFrame(frame);
+    }
+  }
+  if (!scrollable) {
+    return NS_ERROR_UNEXPECTED;
+  }
+  Layer* layer = FrameLayerBuilder::GetDedicatedLayer(scrollable->GetScrolledFrame(),
+    nsDisplayItem::TYPE_SCROLL_LAYER);
+  if (!layer) {
+    if (rootScrollFrame == frame && !presContext->GetParentPresContext()) {
+      nsIWidget* widget = GetWidget();
+      if (widget) {
+        LayerManager* manager = widget->GetLayerManager();
+        if (manager) {
+          layer = manager->GetRoot();
+        }
+      }
+    }
+    if (!layer) {
+      return NS_ERROR_UNEXPECTED;
+    }
+  }
   FrameMetrics::ViewID viewId;
   if (!nsLayoutUtils::FindIDFor(element, &viewId)) {
     return NS_ERROR_UNEXPECTED;
   }
-  nsIWidget* widget = GetWidget();
-  if (!widget) {
-    return NS_ERROR_FAILURE;
-  }
-  LayerManager* manager = widget->GetLayerManager();
-  if (!manager) {
-    return NS_ERROR_FAILURE;
-  }
-  ShadowLayerForwarder* forwarder = manager->AsShadowForwarder();
+  ShadowLayerForwarder* forwarder = layer->Manager()->AsShadowForwarder();
   if (!forwarder || !forwarder->HasShadowManager()) {
     return NS_ERROR_UNEXPECTED;
   }
-  forwarder->GetShadowManager()->SendSetAsyncScrollOffset(viewId, aX, aY);
+  forwarder->GetShadowManager()->SendSetAsyncScrollOffset(
+    layer->AsShadowableLayer()->GetShadow(), viewId, aX, aY);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::ComputeAnimationDistance(nsIDOMElement* aElement,
                                            const nsAString& aProperty,
                                            const nsAString& aValue1,
                                            const nsAString& aValue2,
--- a/gfx/ipc/GfxMessageUtils.h
+++ b/gfx/ipc/GfxMessageUtils.h
@@ -748,28 +748,16 @@ struct ParamTraits<mozilla::layers::Fram
     WriteParam(aMsg, aParam.mMayHaveTouchListeners);
     WriteParam(aMsg, aParam.mMayHaveTouchCaret);
     WriteParam(aMsg, aParam.mPresShellId);
     WriteParam(aMsg, aParam.mIsRoot);
     WriteParam(aMsg, aParam.mHasScrollgrab);
     WriteParam(aMsg, aParam.mUpdateScrollOffset);
     WriteParam(aMsg, aParam.mScrollGeneration);
     WriteParam(aMsg, aParam.mTransformScale);
-    WriteParam(aMsg, aParam.mBackgroundColor);
-    WriteParam(aMsg, aParam.GetContentDescription());
-  }
-
-  static bool ReadContentDescription(const Message* aMsg, void** aIter, paramType* aResult)
-  {
-    nsCString str;
-    if (!ReadParam(aMsg, aIter, &str)) {
-      return false;
-    }
-    aResult->SetContentDescription(str);
-    return true;
   }
 
   static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
   {
     return (ReadParam(aMsg, aIter, &aResult->mScrollableRect) &&
             ReadParam(aMsg, aIter, &aResult->mViewport) &&
             ReadParam(aMsg, aIter, &aResult->mScrollOffset) &&
             ReadParam(aMsg, aIter, &aResult->mDisplayPort) &&
@@ -786,19 +774,17 @@ struct ParamTraits<mozilla::layers::Fram
             ReadParam(aMsg, aIter, &aResult->mDevPixelsPerCSSPixel) &&
             ReadParam(aMsg, aIter, &aResult->mMayHaveTouchListeners) &&
             ReadParam(aMsg, aIter, &aResult->mMayHaveTouchCaret) &&
             ReadParam(aMsg, aIter, &aResult->mPresShellId) &&
             ReadParam(aMsg, aIter, &aResult->mIsRoot) &&
             ReadParam(aMsg, aIter, &aResult->mHasScrollgrab) &&
             ReadParam(aMsg, aIter, &aResult->mUpdateScrollOffset) &&
             ReadParam(aMsg, aIter, &aResult->mScrollGeneration) &&
-            ReadParam(aMsg, aIter, &aResult->mTransformScale) &&
-            ReadParam(aMsg, aIter, &aResult->mBackgroundColor) &&
-            ReadContentDescription(aMsg, aIter, aResult));
+            ReadParam(aMsg, aIter, &aResult->mTransformScale));
   }
 };
 
 template<>
 struct ParamTraits<mozilla::layers::TextureFactoryIdentifier>
 {
   typedef mozilla::layers::TextureFactoryIdentifier paramType;
 
--- a/gfx/layers/FrameMetrics.h
+++ b/gfx/layers/FrameMetrics.h
@@ -7,18 +7,16 @@
 #define GFX_FRAMEMETRICS_H
 
 #include <stdint.h>                     // for uint32_t, uint64_t
 #include "Units.h"                      // for CSSRect, CSSPixel, etc
 #include "mozilla/gfx/BasePoint.h"      // for BasePoint
 #include "mozilla/gfx/Rect.h"           // for RoundedIn
 #include "mozilla/gfx/ScaleFactor.h"    // for ScaleFactor
 #include "mozilla/gfx/Logging.h"        // for Log
-#include "gfxColor.h"
-#include "nsString.h"
 
 namespace IPC {
 template <typename T> struct ParamTraits;
 } // namespace IPC
 
 namespace mozilla {
 
 // The layer coordinates of the parent layer.
@@ -94,20 +92,17 @@ public:
     , mZoom(1)
     , mUpdateScrollOffset(false)
     , mScrollGeneration(0)
     , mRootCompositionSize(0, 0)
     , mDisplayPortMargins(0, 0, 0, 0)
     , mUseDisplayPortMargins(false)
     , mPresShellId(-1)
     , mViewport(0, 0, 0, 0)
-    , mBackgroundColor(0, 0, 0, 0)
-  {
-    mContentDescription[0] = '\0';
-  }
+  {}
 
   // Default copy ctor and operator= are fine
 
   bool operator==(const FrameMetrics& aOther) const
   {
     return mCompositionBounds.IsEqualEdges(aOther.mCompositionBounds) &&
            mRootCompositionSize == aOther.mRootCompositionSize &&
            mDisplayPort.IsEqualEdges(aOther.mDisplayPort) &&
@@ -122,19 +117,17 @@ public:
            mMayHaveTouchListeners == aOther.mMayHaveTouchListeners &&
            mMayHaveTouchCaret == aOther.mMayHaveTouchCaret &&
            mPresShellId == aOther.mPresShellId &&
            mIsRoot == aOther.mIsRoot &&
            mScrollId == aOther.mScrollId &&
            mScrollParentId == aOther.mScrollParentId &&
            mScrollOffset == aOther.mScrollOffset &&
            mHasScrollgrab == aOther.mHasScrollgrab &&
-           mUpdateScrollOffset == aOther.mUpdateScrollOffset &&
-           mBackgroundColor == aOther.mBackgroundColor &&
-           !strcmp(mContentDescription, aOther.mContentDescription);
+           mUpdateScrollOffset == aOther.mUpdateScrollOffset;
   }
   bool operator!=(const FrameMetrics& aOther) const
   {
     return !operator==(aOther);
   }
 
   bool IsDefault() const
   {
@@ -469,38 +462,16 @@ public:
     mViewport = aViewport;
   }
 
   const CSSRect& GetViewport() const
   {
     return mViewport;
   }
 
-  const gfxRGBA& GetBackgroundColor() const
-  {
-    return mBackgroundColor;
-  }
-
-  void SetBackgroundColor(const gfxRGBA& aBackgroundColor)
-  {
-    mBackgroundColor = aBackgroundColor;
-  }
-
-  nsCString GetContentDescription() const
-  {
-    return nsCString(mContentDescription);
-  }
-
-  void SetContentDescription(const nsCString& aContentDescription)
-  {
-    strncpy(mContentDescription, aContentDescription.get(),
-            sizeof(mContentDescription));
-    mContentDescription[sizeof(mContentDescription) - 1] = 0;
-  }
-
 private:
   // New fields from now on should be made private and old fields should
   // be refactored to be private.
 
   // Whether or not this is the root scroll frame for the root content document.
   bool mIsRoot;
 
   // Whether or not this frame is for an element marked 'scrollgrab'.
@@ -559,24 +530,16 @@ private:
   // that its offset is structured in such a way that it doesn't depend on the
   // method layout uses to scroll content.
   //
   // This is mainly useful on the root layer, however nested iframes can have
   // their own viewport, which will just be the size of the window of the
   // iframe. For layers that don't correspond to a document, this metric is
   // meaningless and invalid.
   CSSRect mViewport;
-
-  // The background color to use when overscrolling.
-  gfxRGBA mBackgroundColor;
-
-  // A description of the content element corresponding to this frame.
-  // This is empty unless this is a scrollable ContainerLayer and the
-  // apz.printtree pref is turned on.
-  char mContentDescription[20];
 };
 
 /**
  * This class allows us to uniquely identify a scrollable layer. The
  * mLayersId identifies the layer tree (corresponding to a child process
  * and/or tab) that the scrollable layer belongs to. The mPresShellId
  * is a temporal identifier (corresponding to the document loaded that
  * contains the scrollable layer, which may change over time). The
--- a/gfx/layers/LayerMetricsWrapper.h
+++ b/gfx/layers/LayerMetricsWrapper.h
@@ -323,16 +323,23 @@ public:
 
   const nsIntRect* GetClipRect() const
   {
     MOZ_ASSERT(IsValid());
 
     return mLayer->GetClipRect();
   }
 
+  const std::string& GetContentDescription() const
+  {
+    MOZ_ASSERT(IsValid());
+
+    return mLayer->GetContentDescription();
+  }
+
   // Expose an opaque pointer to the layer. Mostly used for printf
   // purposes. This is not intended to be a general-purpose accessor
   // for the underlying layer.
   const void* GetLayer() const
   {
     MOZ_ASSERT(IsValid());
 
     return (void*)mLayer;
--- a/gfx/layers/Layers.cpp
+++ b/gfx/layers/Layers.cpp
@@ -204,17 +204,18 @@ Layer::Layer(LayerManager* aManager, voi
   mUseClipRect(false),
   mUseTileSourceRect(false),
   mIsFixedPosition(false),
   mMargins(0, 0, 0, 0),
   mStickyPositionData(nullptr),
   mScrollbarTargetId(FrameMetrics::NULL_SCROLL_ID),
   mScrollbarDirection(ScrollDirection::NONE),
   mDebugColorIndex(0),
-  mAnimationGeneration(0)
+  mAnimationGeneration(0),
+  mBackgroundColor(0, 0, 0, 0)
 {}
 
 Layer::~Layer()
 {}
 
 Animation*
 Layer::AddAnimation()
 {
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -1166,16 +1166,38 @@ public:
         mScrollbarDirection != aDir) {
       MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) ScrollbarData", this));
       mScrollbarTargetId = aScrollId;
       mScrollbarDirection = aDir;
       Mutated();
     }
   }
 
+  void SetBackgroundColor(const gfxRGBA& aColor)
+  {
+    if (mBackgroundColor == aColor) {
+      return;
+    }
+
+    MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) BackgroundColor", this));
+    mBackgroundColor = aColor;
+    Mutated();
+  }
+
+  void SetContentDescription(const std::string& aContentDescription)
+  {
+    if (mContentDescription == aContentDescription) {
+      return;
+    }
+
+    MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) ContentDescription", this));
+    mContentDescription = aContentDescription;
+    Mutated();
+  }
+
   // These getters can be used anytime.
   float GetOpacity() { return mOpacity; }
   gfx::CompositionOp GetMixBlendMode() const { return mMixBlendMode; }
   const nsIntRect* GetClipRect() { return mUseClipRect ? &mClipRect : nullptr; }
   uint32_t GetContentFlags() { return mContentFlags; }
   const nsIntRegion& GetVisibleRegion() const { return mVisibleRegion; }
   const FrameMetrics& GetFrameMetrics(uint32_t aIndex) const;
   uint32_t GetFrameMetricsCount() const { return mFrameMetrics.Length(); }
@@ -1199,16 +1221,18 @@ public:
   LayerPoint GetFixedPositionAnchor() { return mAnchor; }
   const LayerMargin& GetFixedPositionMargins() { return mMargins; }
   FrameMetrics::ViewID GetStickyScrollContainerId() { return mStickyPositionData->mScrollId; }
   const LayerRect& GetStickyScrollRangeOuter() { return mStickyPositionData->mOuter; }
   const LayerRect& GetStickyScrollRangeInner() { return mStickyPositionData->mInner; }
   FrameMetrics::ViewID GetScrollbarTargetContainerId() { return mScrollbarTargetId; }
   ScrollDirection GetScrollbarDirection() { return mScrollbarDirection; }
   Layer* GetMaskLayer() const { return mMaskLayer; }
+  gfxRGBA GetBackgroundColor() const { return mBackgroundColor; }
+  const std::string& GetContentDescription() const { return mContentDescription; }
 
 
   // Note that all lengths in animation data are either in CSS pixels or app
   // units and must be converted to device pixels by the compositor.
   AnimationArray& GetAnimations() { return mAnimations; }
   InfallibleTArray<AnimData>& GetAnimationData() { return mAnimationData; }
 
   uint64_t GetAnimationGeneration() { return mAnimationGeneration; }
@@ -1626,16 +1650,22 @@ protected:
   };
   nsAutoPtr<StickyPositionData> mStickyPositionData;
   FrameMetrics::ViewID mScrollbarTargetId;
   ScrollDirection mScrollbarDirection;
   DebugOnly<uint32_t> mDebugColorIndex;
   // If this layer is used for OMTA, then this counter is used to ensure we
   // stay in sync with the animation manager
   uint64_t mAnimationGeneration;
+  // This is currently set and used only for scrollable container layers.
+  gfxRGBA mBackgroundColor;
+  // A description of the content element corresponding to this frame.
+  // This is empty unless this is a scrollable ContainerLayer and the
+  // apz.printtree pref is turned on.
+  std::string mContentDescription;
 #ifdef MOZ_DUMP_PAINTING
   nsTArray<nsCString> mExtraDumpInfo;
 #endif
 };
 
 /**
  * A Layer which we can draw into using Thebes. It is a conceptually
  * infinite surface, but each ThebesLayer has an associated "valid region"
--- a/gfx/layers/LayersLogging.cpp
+++ b/gfx/layers/LayersLogging.cpp
@@ -118,17 +118,16 @@ AppendToString(std::stringstream& aStrea
                const char* pfx, const char* sfx, bool detailed)
 {
   aStream << pfx;
   AppendToString(aStream, m.mCompositionBounds, "{ cb=");
   AppendToString(aStream, m.mScrollableRect, " sr=");
   AppendToString(aStream, m.GetScrollOffset(), " s=");
   AppendToString(aStream, m.mDisplayPort, " dp=");
   AppendToString(aStream, m.mCriticalDisplayPort, " cdp=");
-  AppendToString(aStream, m.GetBackgroundColor(), " color=");
   if (!detailed) {
     AppendToString(aStream, m.GetScrollId(), " scrollId=");
     if (m.GetScrollParentId() != FrameMetrics::NULL_SCROLL_ID) {
       AppendToString(aStream, m.GetScrollParentId(), " scrollParent=");
     }
     aStream << nsPrintfCString(" z=%.3f }", m.GetZoom().scale).get();
   } else {
     AppendToString(aStream, m.GetDisplayPortMargins(), " dpm=");
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -303,17 +303,17 @@ APZCTreeManager::PrepareAPZCForLayer(con
     APZCTM_LOG("Setting region %s as visible region for APZC %p\n",
         Stringify(unobscured).c_str(), apzc);
 
     mApzcTreeLog << "APZC " << guid
                  << "\tcb=" << aMetrics.mCompositionBounds
                  << "\tsr=" << aMetrics.mScrollableRect
                  << (aLayer.GetVisibleRegion().IsEmpty() ? "\tscrollinfo" : "")
                  << (apzc->HasScrollgrab() ? "\tscrollgrab" : "")
-                 << "\t" << aMetrics.GetContentDescription().get();
+                 << "\t" << aLayer.GetContentDescription();
 
     // Bind the APZC instance into the tree of APZCs
     if (aNextSibling) {
       aNextSibling->SetPrevSibling(apzc);
     } else if (aOutParent) {
       aOutParent->SetLastChild(apzc);
     } else {
       mRootApzc = apzc;
--- a/gfx/layers/composite/ContainerLayerComposite.cpp
+++ b/gfx/layers/composite/ContainerLayerComposite.cpp
@@ -263,26 +263,25 @@ RenderLayers(ContainerT* aContainer,
   // contents are transformed in a way that would leave blank regions in the
   // composited area. If the layer has a background color, fill these areas
   // with the background color by drawing a rectangle of the background color
   // over the entire composited area before drawing the container contents.
   // Make sure not to do this on a "scrollinfo" layer because it's just a
   // placeholder for APZ purposes.
   if (aContainer->HasScrollableFrameMetrics() && !aContainer->IsScrollInfoLayer()) {
     bool overscrolled = false;
-    gfxRGBA color;
     for (uint32_t i = 0; i < aContainer->GetFrameMetricsCount(); i++) {
       AsyncPanZoomController* apzc = aContainer->GetAsyncPanZoomController(i);
       if (apzc && apzc->IsOverscrolled()) {
         overscrolled = true;
-        color = aContainer->GetFrameMetrics(i).GetBackgroundColor();
         break;
       }
     }
     if (overscrolled) {
+      gfxRGBA color = aContainer->GetBackgroundColor();
       // If the background is completely transparent, there's no point in
       // drawing anything for it. Hopefully the layers behind, if any, will
       // provide suitable content for the overscroll effect.
       if (color.a != 0.0) {
         EffectChain effectChain(aContainer);
         effectChain.mPrimaryEffect = new EffectSolidColor(ToColor(color));
         gfx::Rect clipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height);
         compositor->DrawQuad(
--- a/gfx/layers/composite/TiledContentHost.cpp
+++ b/gfx/layers/composite/TiledContentHost.cpp
@@ -362,19 +362,19 @@ TiledContentHost::Composite(EffectChain&
   // However, in cases where the background is transparent, or the layer
   // already has some opacity, we want to skip this behaviour. Otherwise
   // we end up changing the expected overall transparency of the content,
   // and it just looks wrong.
   gfxRGBA backgroundColor(0);
   if (aOpacity == 1.0f && gfxPrefs::LowPrecisionOpacity() < 1.0f) {
     // Background colors are only stored on scrollable layers. Grab
     // the one from the nearest scrollable ancestor layer.
-    for (LayerMetricsWrapper ancestor(GetLayer(), LayerMetricsWrapper::StartAt::BOTTOM); ancestor; ancestor = ancestor.GetParent()) {
-      if (ancestor.Metrics().IsScrollable()) {
-        backgroundColor = ancestor.Metrics().GetBackgroundColor();
+    for (Layer* ancestor = GetLayer(); ancestor; ancestor = ancestor->GetParent()) {
+      if (ancestor->HasScrollableFrameMetrics()) {
+        backgroundColor = ancestor->GetBackgroundColor();
         break;
       }
     }
   }
   float lowPrecisionOpacityReduction =
         (aOpacity == 1.0f && backgroundColor.a == 1.0f)
         ? gfxPrefs::LowPrecisionOpacity() : 1.0f;
 
--- a/gfx/layers/ipc/LayerTransactionParent.cpp
+++ b/gfx/layers/ipc/LayerTransactionParent.cpp
@@ -316,16 +316,18 @@ LayerTransactionParent::RecvUpdate(const
       if (PLayerParent* maskLayer = common.maskLayerParent()) {
         layer->SetMaskLayer(cast(maskLayer)->AsLayer());
       } else {
         layer->SetMaskLayer(nullptr);
       }
       layer->SetAnimations(common.animations());
       layer->SetInvalidRegion(common.invalidRegion());
       layer->SetFrameMetrics(common.metrics());
+      layer->SetBackgroundColor(common.backgroundColor().value());
+      layer->SetContentDescription(common.contentDescription());
 
       typedef SpecificLayerAttributes Specific;
       const SpecificLayerAttributes& specific = attrs.specific();
       switch (specific.type()) {
       case Specific::Tnull_t:
         break;
 
       case Specific::TThebesLayerAttributes: {
@@ -682,45 +684,36 @@ LayerTransactionParent::RecvGetAnimation
   transform._41 *= devPerCss;
   transform._42 *= devPerCss;
   transform._43 *= devPerCss;
 
   *aTransform = transform;
   return true;
 }
 
-static AsyncPanZoomController*
-GetAPZCForViewID(Layer* aLayer, FrameMetrics::ViewID aScrollID)
-{
-  for (uint32_t i = 0; i < aLayer->GetFrameMetricsCount(); i++) {
-    if (aLayer->GetFrameMetrics(i).GetScrollId() == aScrollID) {
-      return aLayer->GetAsyncPanZoomController(i);
-    }
-  }
-  ContainerLayer* container = aLayer->AsContainerLayer();
-  if (container) {
-    for (Layer* l = container->GetFirstChild(); l; l = l->GetNextSibling()) {
-      AsyncPanZoomController* c = GetAPZCForViewID(l, aScrollID);
-      if (c) {
-        return c;
-      }
-    }
-  }
-  return nullptr;
-}
-
 bool
-LayerTransactionParent::RecvSetAsyncScrollOffset(const FrameMetrics::ViewID& aScrollID,
+LayerTransactionParent::RecvSetAsyncScrollOffset(PLayerParent* aLayer,
+                                                 const FrameMetrics::ViewID& aId,
                                                  const int32_t& aX, const int32_t& aY)
 {
   if (mDestroyed || !layer_manager() || layer_manager()->IsDestroyed()) {
     return false;
   }
 
-  AsyncPanZoomController* controller = GetAPZCForViewID(mRoot, aScrollID);
+  Layer* layer = cast(aLayer)->AsLayer();
+  if (!layer) {
+    return false;
+  }
+  AsyncPanZoomController* controller = nullptr;
+  for (uint32_t i = 0; i < layer->GetFrameMetricsCount(); i++) {
+    if (layer->GetFrameMetrics(i).GetScrollId() == aId) {
+      controller = layer->GetAsyncPanZoomController(i);
+      break;
+    }
+  }
   if (!controller) {
     return false;
   }
   controller->SetTestAsyncScrollOffset(CSSPoint(aX, aY));
   return true;
 }
 
 bool
--- a/gfx/layers/ipc/LayerTransactionParent.h
+++ b/gfx/layers/ipc/LayerTransactionParent.h
@@ -121,17 +121,17 @@ protected:
   virtual bool RecvForceComposite() MOZ_OVERRIDE;
   virtual bool RecvSetTestSampleTime(const TimeStamp& aTime) MOZ_OVERRIDE;
   virtual bool RecvLeaveTestMode() MOZ_OVERRIDE;
   virtual bool RecvGetOpacity(PLayerParent* aParent,
                               float* aOpacity) MOZ_OVERRIDE;
   virtual bool RecvGetAnimationTransform(PLayerParent* aParent,
                                          MaybeTransform* aTransform)
                                          MOZ_OVERRIDE;
-  virtual bool RecvSetAsyncScrollOffset(const FrameMetrics::ViewID& aId,
+  virtual bool RecvSetAsyncScrollOffset(PLayerParent* aLayer, const FrameMetrics::ViewID& aId,
                                         const int32_t& aX, const int32_t& aY) MOZ_OVERRIDE;
   virtual bool RecvGetAPZTestData(APZTestData* aOutData);
 
   virtual PLayerParent* AllocPLayerParent() MOZ_OVERRIDE;
   virtual bool DeallocPLayerParent(PLayerParent* actor) MOZ_OVERRIDE;
 
   virtual PCompositableParent* AllocPCompositableParent(const TextureInfo& aInfo) MOZ_OVERRIDE;
   virtual bool DeallocPCompositableParent(PCompositableParent* actor) MOZ_OVERRIDE;
--- a/gfx/layers/ipc/LayersMessages.ipdlh
+++ b/gfx/layers/ipc/LayersMessages.ipdlh
@@ -211,16 +211,17 @@ struct CommonLayerAttributes {
   uint32_t scrollbarDirection;
   int8_t mixBlendMode;
   bool forceIsolatedGroup;
   nullable PLayer maskLayer;
   // Animated colors will only honored for ColorLayers.
   Animation[] animations;
   nsIntRegion invalidRegion;
   FrameMetrics[] metrics;
+  LayerColor backgroundColor;
   string contentDescription;
 };
 
 struct ThebesLayerAttributes {
   nsIntRegion validRegion;
 };
 struct ContainerLayerAttributes {
   float preXScale;
--- a/gfx/layers/ipc/PLayerTransaction.ipdl
+++ b/gfx/layers/ipc/PLayerTransaction.ipdl
@@ -76,20 +76,20 @@ parent:
 
   // Returns the value of the transform applied to the layer by animation after
   // factoring out translation components introduced to account for the offset
   // of the corresponding frame and transform origin and after converting to CSS
   // pixels. If the layer is not transformed by animation, the return value will
   // be void_t.
   sync GetAnimationTransform(PLayer layer) returns (MaybeTransform transform);
 
-  // The next time the layer tree is composited, add this async scroll offset in
-  // CSS pixels for the given ViewID.
+  // The next time this layer is composited, add this async scroll offset in
+  // CSS pixels.
   // Useful for testing rendering of async scrolling.
-  async SetAsyncScrollOffset(ViewID id, int32_t x, int32_t y);
+  async SetAsyncScrollOffset(PLayer layer, ViewID id, int32_t x, int32_t y);
 
   // Drop any front buffers that might be retained on the compositor
   // side.
   async ClearCachedResources();
 
   // Schedule a composite if one isn't already scheduled.
   async ForceComposite();
 
--- a/gfx/layers/ipc/ShadowLayers.cpp
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -604,16 +604,18 @@ ShadowLayerForwarder::EndTransaction(Inf
       common.maskLayerChild() = Shadow(maskLayer->AsShadowableLayer());
     } else {
       common.maskLayerChild() = nullptr;
     }
     common.maskLayerParent() = nullptr;
     common.animations() = mutant->GetAnimations();
     common.invalidRegion() = mutant->GetInvalidRegion();
     common.metrics() = mutant->GetAllFrameMetrics();
+    common.backgroundColor() = mutant->GetBackgroundColor();
+    common.contentDescription() = mutant->GetContentDescription();
     attrs.specific() = null_t();
     mutant->FillSpecificAttributes(attrs.specific());
 
     MOZ_LAYERS_LOG(("[LayersForwarder] OpSetLayerAttributes(%p)\n", mutant));
 
     mTxn->AddEdit(OpSetLayerAttributes(nullptr, Shadow(shadow), attrs));
   }
 
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -254,17 +254,16 @@ public:
     mFixedPosFrameForLayerData(nullptr),
     mReferenceFrame(nullptr),
     mLayer(nullptr),
     mIsSolidColorInVisibleRegion(false),
     mSingleItemFixedToViewport(false),
     mNeedComponentAlpha(false),
     mForceTransparentSurface(false),
     mHideAllLayersBelow(false),
-    mOpaqueForAnimatedGeometryRootParent(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.
@@ -454,23 +453,16 @@ public:
    * 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;
-  /**
-   * Set if the opaque region for this layer can be applied to the parent
-   * animated geometry root of this layer's animated geometry root.
-   * We set this when a ThebesLayer's animated geometry root is a scrollframe
-   * and the ThebesLayer completely fills the displayport of the scrollframe.
-   */
-  bool mOpaqueForAnimatedGeometryRootParent;
 
   /**
    * 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
@@ -535,19 +527,16 @@ struct NewLayerEntry {
     , mOpaqueForAnimatedGeometryRootParent(false)
     , mPropagateComponentAlphaFlattening(true)
   {}
   // 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;
-  // If non-null, this FrameMetrics is set to the be the first FrameMetrics
-  // on the layer.
-  UniquePtr<FrameMetrics> mBaseFrameMetrics;
   // 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;
@@ -762,46 +751,37 @@ protected:
 
   /**
    * Returns true if aItem's opaque area (in aOpaque) covers the entire
    * scrollable area of its presshell.
    */
   bool ItemCoversScrollableArea(nsDisplayItem* aItem, const nsRegion& aOpaque);
 
   /**
-   * Set FrameMetrics and scroll-induced clipping on aEntry's layer.
-   */
-  void SetupScrollingMetadata(NewLayerEntry* aEntry);
-
-  /**
-   * Applies occlusion culling.
    * 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.
-   *
-   * Also sets scroll metadata on the layers.
    */
-  void PostprocessRetainedLayers(nsIntRegion* 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,
-                                bool* aOpaqueForAnimatedGeometryRootParent);
+                                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();
   /**
@@ -2155,17 +2135,22 @@ ContainerState::PopThebesLayerData()
     layer->SetClipRect(nullptr);
     FLB_LOG_THEBES_DECISION(data, "  Selected thebes layer=%p\n", layer.get());
   }
 
   if (mLayerBuilder->IsBuildingRetainedLayers()) {
     newLayerEntry->mVisibleRegion = data->mVisibleRegion;
     newLayerEntry->mOpaqueRegion = data->mOpaqueRegion;
     newLayerEntry->mHideAllLayersBelow = data->mHideAllLayersBelow;
-    newLayerEntry->mOpaqueForAnimatedGeometryRootParent = data->mOpaqueForAnimatedGeometryRootParent;
+    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);
   }
 
 #ifdef MOZ_DUMP_PAINTING
   layer->AddExtraDumpInfo(nsCString(data->mLog));
 #endif
 
@@ -2672,18 +2657,17 @@ ContainerState::ItemCoversScrollableArea
 }
 
 nsIntRegion
 ContainerState::ComputeOpaqueRect(nsDisplayItem* aItem,
                                   const nsIFrame* aAnimatedGeometryRoot,
                                   const nsIFrame* aFixedPosFrame,
                                   const DisplayItemClip& aClip,
                                   nsDisplayList* aList,
-                                  bool* aHideAllLayersBelow,
-                                  bool* aOpaqueForAnimatedGeometryRootParent)
+                                  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()) {
@@ -2701,33 +2685,16 @@ ContainerState::ComputeOpaqueRect(nsDisp
     // not needed).
     if (!nsLayoutUtils::GetCrossDocParentFrame(mContainerFrame)) {
       mBuilder->AddWindowOpaqueRegion(opaqueClipped);
     }
     opaquePixels = ScaleRegionToInsidePixels(opaqueClipped, snapOpaque);
     if (aFixedPosFrame && ItemCoversScrollableArea(aItem, opaque)) {
       *aHideAllLayersBelow = true;
     }
-
-    nsIScrollableFrame* sf = nsLayoutUtils::GetScrollableFrameFor(aAnimatedGeometryRoot);
-    if (sf) {
-      nsRect displayport;
-      bool usingDisplayport =
-        nsLayoutUtils::GetDisplayPort(aAnimatedGeometryRoot->GetContent(), &displayport);
-      if (!usingDisplayport) {
-        // No async scrolling, so all that matters is that the layer contents
-        // cover the scrollport.
-        displayport = sf->GetScrollPortRect();
-      }
-      nsIFrame* scrollFrame = do_QueryFrame(sf);
-      displayport += scrollFrame->GetOffsetToCrossDoc(mContainerReferenceFrame);
-      if (opaque.Contains(displayport)) {
-        *aOpaqueForAnimatedGeometryRootParent = 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
@@ -2998,32 +2965,25 @@ ContainerState::ProcessDisplayItems(nsDi
       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,
-          &newLayerEntry->mOpaqueForAnimatedGeometryRootParent);
+          &newLayerEntry->mHideAllLayersBelow);
       } else {
         SetOuterVisibleRegionForLayer(ownLayer, itemVisibleRect,
             layerContentsVisibleRect.width >= 0 ? &layerContentsVisibleRect : nullptr);
       }
-      if (itemType == nsDisplayItem::TYPE_SCROLL_LAYER ||
-          itemType == nsDisplayItem::TYPE_SCROLL_INFO_LAYER) {
+      if (itemType == nsDisplayItem::TYPE_SCROLL_LAYER) {
         nsDisplayScrollLayer* scrollItem = static_cast<nsDisplayScrollLayer*>(item);
         newLayerEntry->mOpaqueForAnimatedGeometryRootParent =
             scrollItem->IsDisplayPortOpaque();
-        newLayerEntry->mBaseFrameMetrics =
-            scrollItem->ComputeFrameMetrics(ownLayer, mParameters);
-      } else if (itemType == nsDisplayItem::TYPE_SUBDOCUMENT) {
-        newLayerEntry->mBaseFrameMetrics =
-          static_cast<nsDisplaySubDocument*>(item)->ComputeFrameMetrics(ownLayer, mParameters);
       }
 
       /**
        * No need to allocate geometry for items that aren't
        * part of a ThebesLayer.
        */
       mLayerBuilder->AddLayerDisplayItem(ownLayer, item,
                                          layerState,
@@ -3046,18 +3006,17 @@ ContainerState::ProcessDisplayItems(nsDi
 
         InvalidateForLayerChange(item, thebesLayerData->mLayer);
 
         mLayerBuilder->AddThebesDisplayItem(thebesLayerData, item, itemClip, itemVisibleRect,
                                             *this, layerState, topLeft);
         nsIntRegion opaquePixels = ComputeOpaqueRect(item,
             animatedGeometryRoot, thebesLayerData->mFixedPosFrameForLayerData,
             itemClip, aList,
-            &thebesLayerData->mHideAllLayersBelow,
-            &thebesLayerData->mOpaqueForAnimatedGeometryRootParent);
+            &thebesLayerData->mHideAllLayersBelow);
         thebesLayerData->Accumulate(this, item, opaquePixels,
             itemVisibleRect, itemDrawRect, itemClip);
       }
     }
 
     if (itemSameCoordinateSystemChildren &&
         itemSameCoordinateSystemChildren->NeedsTransparentSurface()) {
       aList->SetNeedsTransparentSurface();
@@ -3473,73 +3432,17 @@ FindOpaqueRegionEntry(nsTArray<OpaqueReg
         d->mFixedPosFrameForLayerData == aFixedPosFrameForLayerData) {
       return d;
     }
   }
   return nullptr;
 }
 
 void
-ContainerState::SetupScrollingMetadata(NewLayerEntry* aEntry)
-{
-  nsAutoTArray<FrameMetrics,2> metricsArray;
-  if (aEntry->mBaseFrameMetrics) {
-    metricsArray.AppendElement(*aEntry->mBaseFrameMetrics);
-  }
-  uint32_t baseLength = metricsArray.Length();
-
-  nsIntRect tmpClipRect;
-  const nsIntRect* layerClip = aEntry->mLayer->GetClipRect();
-  nsIFrame* fParent;
-  for (const nsIFrame* f = aEntry->mAnimatedGeometryRoot;
-       f != mContainerAnimatedGeometryRoot;
-       f = nsLayoutUtils::GetAnimatedGeometryRootForFrame(
-           fParent, mContainerAnimatedGeometryRoot)) {
-    fParent = nsLayoutUtils::GetCrossDocParentFrame(f);
-    if (!fParent) {
-      // This means mContainerAnimatedGeometryRoot was not an ancestor
-      // of aEntry->mAnimatedGeometryRoot. This is a weird case but it
-      // can happen, e.g. when a scrolled frame contains a frame with opacity
-      // which contains a frame that is not scrolled by the scrolled frame.
-      // For now, we just don't apply any specific async scrolling to this layer.
-      // It will async-scroll with mContainerAnimatedGeometryRoot, which
-      // is substandard but not fatal.
-      metricsArray.SetLength(baseLength);
-      aEntry->mLayer->SetFrameMetrics(metricsArray);
-      return;
-    }
-
-    nsIScrollableFrame* scrollFrame = nsLayoutUtils::GetScrollableFrameFor(f);
-    if (!scrollFrame) {
-      continue;
-    }
-
-    nsRect clipRect(0, 0, -1, -1);
-    scrollFrame->ComputeFrameMetrics(aEntry->mLayer, mContainerReferenceFrame,
-                                     mParameters, &clipRect, &metricsArray);
-    if (clipRect.width >= 0) {
-      nsIntRect pixClip = ScaleToNearestPixels(clipRect);
-      if (layerClip) {
-        tmpClipRect.IntersectRect(pixClip, *layerClip);
-      } else {
-        tmpClipRect = pixClip;
-      }
-      layerClip = &tmpClipRect;
-      // XXX this could cause IPC churn due to cliprects being updated
-      // twice during layer building --- for non-ThebesLayers that have
-      // both CSS and scroll clipping.
-    }
-  }
-  aEntry->mLayer->SetClipRect(layerClip);
-  // Watch out for FrameMetrics copies in profiles
-  aEntry->mLayer->SetFrameMetrics(metricsArray);
-}
-
-void
-ContainerState::PostprocessRetainedLayers(nsIntRegion* aOpaqueRegionForContainer)
+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) {
@@ -3550,20 +3453,16 @@ ContainerState::PostprocessRetainedLayer
         e->mAnimatedGeometryRoot, e->mFixedPosFrameForLayerData);
 
     if (hideAll) {
       e->mVisibleRegion.SetEmpty();
     } else if (data) {
       e->mVisibleRegion.Sub(e->mVisibleRegion, data->mOpaqueRegion);
     }
 
-    SetOuterVisibleRegionForLayer(e->mLayer, e->mVisibleRegion,
-      e->mLayerContentsVisibleRect.width >= 0 ? &e->mLayerContentsVisibleRect : nullptr);
-    SetupScrollingMetadata(e);
-
     if (!e->mOpaqueRegion.IsEmpty()) {
       const nsIFrame* animatedGeometryRootToCover = e->mAnimatedGeometryRoot;
       if (e->mOpaqueForAnimatedGeometryRootParent &&
           nsLayoutUtils::GetAnimatedGeometryRootForFrame(e->mAnimatedGeometryRoot->GetParent(),
                                                          mContainerAnimatedGeometryRoot)
             == mContainerAnimatedGeometryRoot) {
         animatedGeometryRootToCover = mContainerAnimatedGeometryRoot;
         data = FindOpaqueRegionEntry(opaqueRegions,
@@ -3581,16 +3480,19 @@ ContainerState::PostprocessRetainedLayer
         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;
     }
@@ -3611,17 +3513,17 @@ ContainerState::Finish(uint32_t* aTextCo
     PopThebesLayerData();
   }
 
   NS_ASSERTION(mContainerBounds.IsEqualInterior(mAccumulatedChildBounds),
                "Bounds computation mismatch");
 
   if (mLayerBuilder->IsBuildingRetainedLayers()) {
     nsIntRegion containerOpaqueRegion;
-    PostprocessRetainedLayers(&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
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -642,27 +642,25 @@ static void UnmarkFrameForDisplay(nsIFra
   for (nsIFrame* f = aFrame; f;
        f = nsLayoutUtils::GetParentOrPlaceholderFor(f)) {
     if (!(f->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO))
       return;
     f->RemoveStateBits(NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO);
   }
 }
 
-/* static */ FrameMetrics
-nsDisplayScrollLayer::ComputeFrameMetrics(nsIFrame* aForFrame,
-                                          nsIFrame* aScrollFrame,
-                                          const nsIFrame* aReferenceFrame,
-                                          Layer* aLayer,
-                                          ViewID aScrollParentId,
-                                          const nsRect& aViewport,
-                                          bool aForceNullScrollId,
-                                          bool aIsRoot,
-                                          const ContainerLayerParameters& aContainerParameters)
-{
+static void RecordFrameMetrics(nsIFrame* aForFrame,
+                               nsIFrame* aScrollFrame,
+                               const nsIFrame* aReferenceFrame,
+                               ContainerLayer* aRoot,
+                               ViewID aScrollParentId,
+                               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);
 
   nsIPresShell* presShell = presContext->GetPresShell();
   FrameMetrics metrics;
   metrics.SetViewport(CSSRect::FromAppUnits(aViewport));
 
@@ -670,17 +668,17 @@ nsDisplayScrollLayer::ComputeFrameMetric
   nsIContent* content = aScrollFrame ? aScrollFrame->GetContent() : nullptr;
   if (content) {
     if (!aForceNullScrollId) {
       scrollId = nsLayoutUtils::FindOrCreateIDFor(content);
     }
     nsRect dp;
     if (nsLayoutUtils::GetDisplayPort(content, &dp)) {
       metrics.mDisplayPort = CSSRect::FromAppUnits(dp);
-      nsLayoutUtils::LogTestDataForPaint(aLayer->Manager(), scrollId, "displayport",
+      nsLayoutUtils::LogTestDataForPaint(aRoot->Manager(), scrollId, "displayport",
           metrics.mDisplayPort);
     }
     if (nsLayoutUtils::GetCriticalDisplayPort(content, &dp)) {
       metrics.mCriticalDisplayPort = CSSRect::FromAppUnits(dp);
     }
     DisplayPortMarginsPropertyData* marginsData =
         static_cast<DisplayPortMarginsPropertyData*>(content->GetProperty(nsGkAtoms::DisplayPortMargins));
     if (marginsData) {
@@ -832,43 +830,43 @@ nsDisplayScrollLayer::ComputeFrameMetric
   metrics.SetRootCompositionSize(
     nsLayoutUtils::CalculateRootCompositionSize(aScrollFrame ? aScrollFrame : aForFrame,
                                                 isRootContentDocRootScrollFrame, metrics));
 
   if (gfxPrefs::APZPrintTree()) {
     if (nsIContent* content = frameForCompositionBoundsCalculation->GetContent()) {
       nsAutoString contentDescription;
       content->Describe(contentDescription);
-      metrics.SetContentDescription(NS_LossyConvertUTF16toASCII(contentDescription));
+      aRoot->SetContentDescription(NS_LossyConvertUTF16toASCII(contentDescription).get());
     }
   }
 
   metrics.SetPresShellId(presShell->GetPresShellId());
 
   // If the scroll frame's content is marked 'scrollgrab', record this
   // in the FrameMetrics so APZ knows to provide the scroll grabbing
   // behaviour.
   if (aScrollFrame && nsContentUtils::HasScrollgrab(aScrollFrame->GetContent())) {
     metrics.SetHasScrollgrab(true);
   }
 
-  // Also compute and set the background color.
+  aRoot->SetFrameMetrics(metrics);
+
+  // Also compute and set the background color on the container.
   // This is needed for APZ overscrolling support.
   if (aScrollFrame) {
     if (isRootScrollFrame) {
-      metrics.SetBackgroundColor(presShell->GetCanvasBackground());
+      aRoot->SetBackgroundColor(presShell->GetCanvasBackground());
     } else {
       nsStyleContext* backgroundStyle;
       if (nsCSSRendering::FindBackground(aScrollFrame, &backgroundStyle)) {
-        metrics.SetBackgroundColor(backgroundStyle->StyleBackground()->mBackgroundColor);
+        aRoot->SetBackgroundColor(backgroundStyle->StyleBackground()->mBackgroundColor);
       }
     }
   }
-
-  return metrics;
 }
 
 nsDisplayListBuilder::~nsDisplayListBuilder() {
   NS_ASSERTION(mFramesMarkedForDisplay.Length() == 0,
                "All frames should have been unmarked");
   NS_ASSERTION(mPresShellStates.Length() == 0,
                "All presshells should have been exited");
   NS_ASSERTION(!mCurrentTableItem, "No table item should be active");
@@ -1289,21 +1287,20 @@ void nsDisplayList::PaintForFrame(nsDisp
                      1.0f/containerParameters.mYScale);
 
   bool isRoot = presContext->IsRootContentDocument();
 
   nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame();
 
   nsRect viewport(aBuilder->ToReferenceFrame(aForFrame), aForFrame->GetSize());
 
-  root->SetFrameMetrics(
-    nsDisplayScrollLayer::ComputeFrameMetrics(aForFrame, rootScrollFrame,
-                       aBuilder->FindReferenceFrameFor(aForFrame),
-                       root, FrameMetrics::NULL_SCROLL_ID, viewport,
-                       !isRoot, isRoot, containerParameters));
+  RecordFrameMetrics(aForFrame, rootScrollFrame,
+                     aBuilder->FindReferenceFrameFor(aForFrame),
+                     root, FrameMetrics::NULL_SCROLL_ID, viewport,
+                     !isRoot, isRoot, containerParameters);
 
   // NS_WARNING is debug-only, so don't even bother checking the conditions in
   // a release build.
 #ifdef DEBUG
   bool usingDisplayport = false;
   if (rootScrollFrame) {
     nsIContent* content = rootScrollFrame->GetContent();
     if (content) {
@@ -3666,45 +3663,38 @@ nsDisplaySubDocument::BuildLayer(nsDispl
   nsIFrame* rootScrollFrame = presContext->PresShell()->GetRootScrollFrame();
   ContainerLayerParameters params = aContainerParameters;
   if ((mFlags & GENERATE_SCROLLABLE_LAYER) &&
       rootScrollFrame->GetContent() &&
       nsLayoutUtils::GetCriticalDisplayPort(rootScrollFrame->GetContent(), nullptr)) {
     params.mInLowPrecisionDisplayPort = true; 
   }
 
-  return nsDisplayOwnLayer::BuildLayer(aBuilder, aManager, params);
-}
-
-UniquePtr<FrameMetrics>
-nsDisplaySubDocument::ComputeFrameMetrics(Layer* aLayer,
-                                          const ContainerLayerParameters& aContainerParameters)
-{
+  nsRefPtr<Layer> layer = nsDisplayOwnLayer::BuildLayer(
+    aBuilder, aManager, params);
+
   if (!(mFlags & GENERATE_SCROLLABLE_LAYER)) {
-    return UniquePtr<FrameMetrics>(nullptr);
-  }
-
-  nsPresContext* presContext = mFrame->PresContext();
-  nsIFrame* rootScrollFrame = presContext->PresShell()->GetRootScrollFrame();
-  bool isRootContentDocument = presContext->IsRootContentDocument();
-  ContainerLayerParameters params = aContainerParameters;
-  if ((mFlags & GENERATE_SCROLLABLE_LAYER) &&
-      rootScrollFrame->GetContent() &&
-      nsLayoutUtils::GetCriticalDisplayPort(rootScrollFrame->GetContent(), nullptr)) {
-    params.mInLowPrecisionDisplayPort = true;
-  }
-
-  nsRect viewport = mFrame->GetRect() -
-                    mFrame->GetPosition() +
-                    mFrame->GetOffsetToCrossDoc(ReferenceFrame());
-
-  return MakeUnique<FrameMetrics>(
-    nsDisplayScrollLayer::ComputeFrameMetrics(mFrame, rootScrollFrame, ReferenceFrame(),
-                       aLayer, mScrollParentId, viewport,
-                       false, isRootContentDocument, params));
+    return layer.forget();
+  }
+
+  NS_ASSERTION(layer->AsContainerLayer(), "nsDisplayOwnLayer should have made a ContainerLayer");
+  if (ContainerLayer* container = layer->AsContainerLayer()) {
+    nsIFrame* rootScrollFrame = presContext->PresShell()->GetRootScrollFrame();
+    bool isRootContentDocument = presContext->IsRootContentDocument();
+
+    nsRect viewport = mFrame->GetRect() -
+                      mFrame->GetPosition() +
+                      mFrame->GetOffsetToCrossDoc(ReferenceFrame());
+
+    RecordFrameMetrics(mFrame, rootScrollFrame, ReferenceFrame(),
+                       container, mScrollParentId, viewport,
+                       false, isRootContentDocument, params);
+  }
+
+  return layer.forget();
 }
 
 nsRect
 nsDisplaySubDocument::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
 {
   bool usingDisplayPort =
     nsLayoutUtils::ViewportHasDisplayPort(mFrame->PresContext());
 
@@ -3983,56 +3973,53 @@ nsDisplayScrollLayer::GetScrolledContent
   }
   bool snap;
   return GetBounds(aBuilder, &snap);
 }
 
 already_AddRefed<Layer>
 nsDisplayScrollLayer::BuildLayer(nsDisplayListBuilder* aBuilder,
                                  LayerManager* aManager,
-                                 const ContainerLayerParameters& aContainerParameters)
-{
+                                 const ContainerLayerParameters& aContainerParameters) {
+
   ContainerLayerParameters params = aContainerParameters;
   if (mScrolledFrame->GetContent() &&
       nsLayoutUtils::GetCriticalDisplayPort(mScrolledFrame->GetContent(), nullptr)) {
-    params.mInLowPrecisionDisplayPort = true;
-  }
+    params.mInLowPrecisionDisplayPort = true; 
+  }
+
+  nsRefPtr<ContainerLayer> layer = aManager->GetLayerBuilder()->
+    BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList,
+                           params, nullptr);
+
+  nsRect viewport = mScrollFrame->GetRect() -
+                    mScrollFrame->GetPosition() +
+                    mScrollFrame->GetOffsetToCrossDoc(ReferenceFrame());
+
+  RecordFrameMetrics(mScrolledFrame, mScrollFrame, ReferenceFrame(), layer,
+                     mScrollParentId, viewport, false, false, params);
 
   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;
   }
 
-  return aManager->GetLayerBuilder()->
-    BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList,
-                           params, nullptr);
-}
-
-UniquePtr<FrameMetrics>
-nsDisplayScrollLayer::ComputeFrameMetrics(Layer* aLayer,
-                                          const ContainerLayerParameters& aContainerParameters)
+  return layer.forget();
+}
+
+bool
+nsDisplayScrollLayer::IsConstructingScrollLayerForScrolledFrame(const nsIFrame* aScrolledFrame)
 {
-  ContainerLayerParameters params = aContainerParameters;
-  if (mScrolledFrame->GetContent() &&
-      nsLayoutUtils::GetCriticalDisplayPort(mScrolledFrame->GetContent(), nullptr)) {
-    params.mInLowPrecisionDisplayPort = true; 
-  }
-
-  nsRect viewport = mScrollFrame->GetRect() -
-                    mScrollFrame->GetPosition() +
-                    mScrollFrame->GetOffsetToCrossDoc(ReferenceFrame());
-
-  return UniquePtr<FrameMetrics>(new FrameMetrics(
-    ComputeFrameMetrics(mScrolledFrame, mScrollFrame, ReferenceFrame(), aLayer,
-                        mScrollParentId, viewport, false, false, params)));
+  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;
   }
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -19,18 +19,16 @@
 #include "nsPoint.h"
 #include "nsRect.h"
 #include "plarena.h"
 #include "Layers.h"
 #include "nsRegion.h"
 #include "nsDisplayListInvalidation.h"
 #include "DisplayListClipState.h"
 #include "LayerState.h"
-#include "FrameMetrics.h"
-#include "mozilla/UniquePtr.h"
 
 #include <stdint.h>
 
 #include <stdlib.h>
 #include <algorithm>
 
 class nsIContent;
 class nsRenderingContext;
@@ -40,18 +38,18 @@ class nsDisplayLayerEventRegions;
 class nsCaret;
 
 namespace mozilla {
 class FrameLayerBuilder;
 namespace layers {
 class Layer;
 class ImageLayer;
 class ImageContainer;
-} //namespace
-} //namespace
+} //namepsace
+} //namepsace
 
 // A set of blend modes, that never includes OP_OVER (since it's
 // considered the default, rather than a specific blend mode).
 typedef mozilla::EnumSet<mozilla::gfx::CompositionOp> BlendModeSet;
 
 /*
  * An nsIFrame can have many different visual parts. For example an image frame
  * can have a background, border, and outline, the image itself, and a
@@ -803,17 +801,16 @@ protected:
  * 
  * Display items belong to a list at all times (except temporarily as they
  * move from one list to another).
  */
 class nsDisplayItem : public nsDisplayItemLink {
 public:
   typedef mozilla::ContainerLayerParameters ContainerLayerParameters;
   typedef mozilla::DisplayItemClip DisplayItemClip;
-  typedef mozilla::layers::FrameMetrics FrameMetrics;
   typedef mozilla::layers::FrameMetrics::ViewID ViewID;
   typedef mozilla::layers::Layer Layer;
   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);
@@ -2883,20 +2880,16 @@ public:
   virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                  nsRegion* aVisibleRegion) MOZ_OVERRIDE;
 
   virtual bool ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE;
 
   virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE;
 
   NS_DISPLAY_DECL_NAME("SubDocument", TYPE_SUBDOCUMENT)
-
-  mozilla::UniquePtr<FrameMetrics> ComputeFrameMetrics(Layer* aLayer,
-                                                       const ContainerLayerParameters& aContainerParameters);
-
 protected:
   ViewID mScrollParentId;
 };
 
 /**
  * A display item for subdocuments to capture the resolution from the presShell
  * and ensure that it gets applied to all the right elements. This item creates
  * a container layer.
@@ -3013,38 +3006,27 @@ public:
 
   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; }
 
 #ifdef MOZ_DUMP_PAINTING
   virtual void WriteDebugInfo(nsACString& aTo) MOZ_OVERRIDE;
 #endif
 
   bool IsDisplayPortOpaque() { return mDisplayPortContentsOpaque; }
 
-  static FrameMetrics ComputeFrameMetrics(nsIFrame* aForFrame,
-                                          nsIFrame* aScrollFrame,
-                                          const nsIFrame* aReferenceFrame,
-                                          Layer* aLayer,
-                                          ViewID aScrollParentId,
-                                          const nsRect& aViewport,
-                                          bool aForceNullScrollId,
-                                          bool aIsRoot,
-                                          const ContainerLayerParameters& aContainerParameters);
-
-  mozilla::UniquePtr<FrameMetrics> ComputeFrameMetrics(Layer* aLayer,
-                                                       const ContainerLayerParameters& aContainerParameters);
-
 protected:
   nsRect GetScrolledContentRectToDraw(nsDisplayListBuilder* aBuilder,
                                       nsRect* aDisplayPort);
 
   nsIFrame* mScrollFrame;
   nsIFrame* mScrolledFrame;
   ViewID mScrollParentId;
   bool mDisplayPortContentsOpaque;
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -58,32 +58,16 @@
 #include <algorithm>
 #include <cstdlib> // for std::abs(int/long)
 #include <cmath> // for std::abs(float/double)
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::layout;
 
-static bool
-BuildScrollContainerLayers()
-{
-  static bool sContainerlessScrollingEnabled;
-  static bool sContainerlessScrollingPrefCached = false;
-
-  if (!sContainerlessScrollingPrefCached) {
-    sContainerlessScrollingPrefCached = true;
-    Preferences::AddBoolVarCache(&sContainerlessScrollingEnabled,
-                                 "layout.async-containerless-scrolling.enabled",
-                                 true);
-  }
-
-  return !sContainerlessScrollingEnabled;
-}
-
 //----------------------------------------------------------------------
 
 //----------nsHTMLScrollFrame-------------------------------------------
 
 nsHTMLScrollFrame*
 NS_NewHTMLScrollFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, bool aIsRoot)
 {
   return new (aPresShell) nsHTMLScrollFrame(aPresShell, aContext, aIsRoot);
@@ -2897,18 +2881,16 @@ ScrollFrameHelper::BuildDisplayList(nsDi
       nsLayoutUtils::WantSubAPZC() &&
       WantAsyncScroll() &&
       // If we are the root scroll frame for the display root then we don't need a scroll
       // info layer to make a RecordFrameMetrics call for us as
       // nsDisplayList::PaintForFrame already calls RecordFrameMetrics for us.
       (!mIsRoot || aBuilder->RootReferenceFrame()->PresContext() != mOuter->PresContext());
   }
 
-  mScrollParentID = aBuilder->GetCurrentScrollParentId();
-
   nsDisplayListCollection scrolledContent;
   {
     // Note that setting the current scroll parent id here means that positioned children
     // of this scroll info layer will pick up the scroll info layer as their scroll handoff
     // parent. This is intentional because that is what happens for positioned children
     // of scroll layers, and we want to maintain consistent behaviour between scroll layers
     // and scroll info layers.
     nsDisplayListBuilder::AutoCurrentScrollParentIdSetter idSetter(
@@ -2967,17 +2949,17 @@ ScrollFrameHelper::BuildDisplayList(nsDi
     }
   }
 
   if (shouldBuildLayer) {
     // ScrollLayerWrapper must always be created because it initializes the
     // scroll layer count. The display lists depend on this.
     ScrollLayerWrapper wrapper(mOuter, mScrolledFrame);
 
-    if (mShouldBuildScrollableLayer && BuildScrollContainerLayers()) {
+    if (mShouldBuildScrollableLayer) {
       DisplayListClipState::AutoSaveRestore clipState(aBuilder);
 
       // For root scrollframes in documents where the CSS viewport has been
       // modified, the CSS viewport no longer corresponds to what is visible,
       // so we don't want to clip the content to it. For root scrollframes
       // in documents where the CSS viewport is NOT modified, the mScrollPort
       // is the same as the CSS viewport, modulo scrollbars.
       if (!(mIsRoot && mOuter->PresContext()->PresShell()->GetIsViewportOverridden())) {
@@ -3009,41 +2991,16 @@ ScrollFrameHelper::BuildDisplayList(nsDi
     }
   }
   // Now display overlay scrollbars and the resizer, if we have one.
   AppendScrollPartsTo(aBuilder, scrollbarDirty, scrolledContent,
                       createLayersForScrollbars, true);
   scrolledContent.MoveTo(aLists);
 }
 
-void
-ScrollFrameHelper::ComputeFrameMetrics(Layer* aLayer,
-                                       nsIFrame* aContainerReferenceFrame,
-                                       const ContainerLayerParameters& aParameters,
-                                       nsRect* aClipRect,
-                                       nsTArray<FrameMetrics>* aOutput) const
-{
-  if (!mShouldBuildScrollableLayer || BuildScrollContainerLayers()) {
-    return;
-  }
-
-  MOZ_ASSERT(mScrolledFrame->GetContent());
-
-  nsRect viewport = mScrollPort +
-    mOuter->GetOffsetToCrossDoc(aContainerReferenceFrame);
-
-  if (!(mIsRoot && mOuter->PresContext()->PresShell()->GetIsViewportOverridden())) {
-    *aClipRect = viewport;
-  }
-  *aOutput->AppendElement() =
-      nsDisplayScrollLayer::ComputeFrameMetrics(mScrolledFrame, mOuter,
-        aContainerReferenceFrame, aLayer, mScrollParentID,
-        viewport, false, false, aParameters);
-}
-
 bool
 ScrollFrameHelper::IsRectNearlyVisible(const nsRect& aRect) const
 {
   // Use the right rect depending on if a display port is set.
   nsRect displayPort;
   bool usingDisplayport = nsLayoutUtils::GetDisplayPort(mOuter->GetContent(), &displayPort);
   return aRect.Intersects(ExpandRectToNearlyVisible(usingDisplayport ? displayPort : mScrollPort));
 }
--- a/layout/generic/nsGfxScrollFrame.h
+++ b/layout/generic/nsGfxScrollFrame.h
@@ -26,33 +26,28 @@ class nsIPresShell;
 class nsIContent;
 class nsIAtom;
 class nsIScrollFrameInternal;
 class nsPresState;
 class nsIScrollPositionListener;
 struct ScrollReflowState;
 
 namespace mozilla {
-namespace layers {
-class Layer;
-}
 namespace layout {
 class ScrollbarActivity;
 }
 }
 
 namespace mozilla {
 
 class ScrollFrameHelper : public nsIReflowCallback {
 public:
   typedef nsIFrame::Sides Sides;
   typedef mozilla::CSSIntPoint CSSIntPoint;
   typedef mozilla::layout::ScrollbarActivity ScrollbarActivity;
-  typedef mozilla::layers::FrameMetrics FrameMetrics;
-  typedef mozilla::layers::Layer Layer;
 
   class AsyncScroll;
   class AsyncSmoothMSDScroll;
 
   ScrollFrameHelper(nsContainerFrame* aOuter, bool aIsRoot);
   ~ScrollFrameHelper();
 
   mozilla::ScrollbarStyles GetScrollbarStylesFromFrame() const;
@@ -325,20 +320,16 @@ public:
   nsIAtom* OriginOfLastScroll() const { return mOriginOfLastScroll; }
   uint32_t CurrentScrollGeneration() const { return mScrollGeneration; }
   void ResetOriginIfScrollAtGeneration(uint32_t aGeneration) {
     if (aGeneration == mScrollGeneration) {
       mOriginOfLastScroll = nullptr;
     }
   }
   bool WantAsyncScroll() const;
-  void ComputeFrameMetrics(Layer* aLayer, nsIFrame* aContainerReferenceFrame,
-                           const ContainerLayerParameters& aParameters,
-                           nsRect* aClipRect,
-                           nsTArray<FrameMetrics>* aOutput) const;
 
   // nsIScrollbarMediator
   void ScrollByPage(nsScrollbarFrame* aScrollbar, int32_t aDirection);
   void ScrollByWhole(nsScrollbarFrame* aScrollbar, int32_t aDirection);
   void ScrollByLine(nsScrollbarFrame* aScrollbar, int32_t aDirection);
   void RepeatButtonScroll(nsScrollbarFrame* aScrollbar);
   void ThumbMoved(nsScrollbarFrame* aScrollbar,
                   nscoord aOldPos,
@@ -393,18 +384,16 @@ public:
   nsExpirationState mActivityExpirationState;
 
   nsCOMPtr<nsITimer> mScrollActivityTimer;
   nsPoint mScrollPosForLayerPixelAlignment;
 
   // The scroll position where we last updated image visibility.
   nsPoint mLastUpdateImagesPos;
 
-  FrameMetrics::ViewID mScrollParentID;
-
   bool mNeverHasVerticalScrollbar:1;
   bool mNeverHasHorizontalScrollbar:1;
   bool mHasVerticalScrollbar:1;
   bool mHasHorizontalScrollbar:1;
   bool mFrameIsUpdatingScrollbar:1;
   bool mDidHistoryRestore:1;
   // Is this the scrollframe for the document's viewport?
   bool mIsRoot:1;
@@ -714,23 +703,16 @@ public:
     return mHelper.CurrentScrollGeneration();
   }
   virtual void ResetOriginIfScrollAtGeneration(uint32_t aGeneration) MOZ_OVERRIDE {
     mHelper.ResetOriginIfScrollAtGeneration(aGeneration);
   }
   virtual bool WantAsyncScroll() const MOZ_OVERRIDE {
     return mHelper.WantAsyncScroll();
   }
-  virtual void ComputeFrameMetrics(Layer* aLayer, nsIFrame* aContainerReferenceFrame,
-                                   const ContainerLayerParameters& aParameters,
-                                   nsRect* aClipRect,
-                                   nsTArray<FrameMetrics>* aOutput) const MOZ_OVERRIDE {
-    mHelper.ComputeFrameMetrics(aLayer, aContainerReferenceFrame,
-                                aParameters, aClipRect, aOutput);
-  }
 
   // nsIStatefulFrame
   NS_IMETHOD SaveState(nsPresState** aState) MOZ_OVERRIDE {
     NS_ENSURE_ARG_POINTER(aState);
     *aState = mHelper.SaveState();
     return NS_OK;
   }
   NS_IMETHOD RestoreState(nsPresState* aState) MOZ_OVERRIDE {
@@ -1060,23 +1042,16 @@ public:
     return mHelper.CurrentScrollGeneration();
   }
   virtual void ResetOriginIfScrollAtGeneration(uint32_t aGeneration) MOZ_OVERRIDE {
     mHelper.ResetOriginIfScrollAtGeneration(aGeneration);
   }
   virtual bool WantAsyncScroll() const MOZ_OVERRIDE {
     return mHelper.WantAsyncScroll();
   }
-  virtual void ComputeFrameMetrics(Layer* aLayer, nsIFrame* aContainerReferenceFrame,
-                                   const ContainerLayerParameters& aParameters,
-                                   nsRect* aClipRect,
-                                   nsTArray<FrameMetrics>* aOutput) const MOZ_OVERRIDE {
-    mHelper.ComputeFrameMetrics(aLayer, aContainerReferenceFrame,
-                                aParameters, aClipRect, aOutput);
-  }
 
   // nsIStatefulFrame
   NS_IMETHOD SaveState(nsPresState** aState) MOZ_OVERRIDE {
     NS_ENSURE_ARG_POINTER(aState);
     *aState = mHelper.SaveState();
     return NS_OK;
   }
   NS_IMETHOD RestoreState(nsPresState* aState) MOZ_OVERRIDE {
--- a/layout/generic/nsIScrollableFrame.h
+++ b/layout/generic/nsIScrollableFrame.h
@@ -10,46 +10,36 @@
 #ifndef nsIScrollFrame_h___
 #define nsIScrollFrame_h___
 
 #include "nsCoord.h"
 #include "ScrollbarStyles.h"
 #include "mozilla/gfx/Point.h"
 #include "nsIScrollbarMediator.h"
 #include "Units.h"
-#include "FrameMetrics.h"
 
 #define NS_DEFAULT_VERTICAL_SCROLL_DISTANCE   3
 #define NS_DEFAULT_HORIZONTAL_SCROLL_DISTANCE 5
 
 class nsBoxLayoutState;
 class nsIScrollPositionListener;
 class nsIFrame;
 class nsPresContext;
 class nsIContent;
 class nsRenderingContext;
 class nsIAtom;
 
-namespace mozilla {
-struct ContainerLayerParameters;
-namespace layers {
-class Layer;
-}
-}
-
 /**
  * Interface for frames that are scrollable. This interface exposes
  * APIs for examining scroll state, observing changes to scroll state,
  * and triggering scrolling.
  */
 class nsIScrollableFrame : public nsIScrollbarMediator {
 public:
   typedef mozilla::CSSIntPoint CSSIntPoint;
-  typedef mozilla::ContainerLayerParameters ContainerLayerParameters;
-  typedef mozilla::layers::FrameMetrics FrameMetrics;
 
   NS_DECL_QUERYFRAME_TARGET(nsIScrollableFrame)
 
   /**
    * Get the frame for the content that we are scrolling within
    * this scrollable frame.
    */
   virtual nsIFrame* GetScrolledFrame() const = 0;
@@ -345,20 +335,11 @@ public:
    * counter.
    */
   virtual void ResetOriginIfScrollAtGeneration(uint32_t aGeneration) = 0;
   /**
    * Determine whether it is desirable to be able to asynchronously scroll this
    * scroll frame.
    */
   virtual bool WantAsyncScroll() const = 0;
-  /**
-   * aLayer's animated geometry root is this frame. If there needs to be a
-   * FrameMetrics contributed by this frame, append it to aOutput.
-   */
-  virtual void ComputeFrameMetrics(mozilla::layers::Layer* aLayer,
-                                   nsIFrame* aContainerReferenceFrame,
-                                   const ContainerLayerParameters& aParameters,
-                                   nsRect* aOutClipRect,
-                                   nsTArray<FrameMetrics>* aOutput) const = 0;
 };
 
 #endif
deleted file mode 100644
--- a/layout/reftests/async-scrolling/nested-1-ref.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<body>
-  <div style="width:400px; height:500px; overflow:hidden; border:2px solid black">
-    <div style="width:300px; height:800px; overflow:hidden; border:2px solid blue; margin-top:-50px">
-      <div style="height:450px"></div>
-      <div style="height:200px; background:purple"></div>
-    </div>
-  </div>
-</html>
deleted file mode 100644
--- a/layout/reftests/async-scrolling/nested-1.html
+++ /dev/null
@@ -1,17 +0,0 @@
-<!DOCTYPE HTML>
-<html reftest-async-scroll>
-<body>
-  <!-- Test that nested active scrolling elements work -->
-  <div style="width:400px; height:500px; overflow:hidden; border:2px solid black"
-       reftest-displayport-x="0" reftest-displayport-y="0"
-       reftest-displayport-w="800" reftest-displayport-h="2000"
-       reftest-async-scroll-x="0" reftest-async-scroll-y="50">
-    <div style="width:300px; height:800px; overflow:hidden; border:2px solid blue"
-         reftest-displayport-x="0" reftest-displayport-y="0"
-         reftest-displayport-w="800" reftest-displayport-h="2000"
-         reftest-async-scroll-x="0" reftest-async-scroll-y="50">
-      <div style="height:500px"></div>
-      <div style="height:200px; background:purple"></div>
-    </div>
-  </div>
-</html>
--- a/layout/reftests/async-scrolling/reftest.list
+++ b/layout/reftests/async-scrolling/reftest.list
@@ -1,26 +1,10 @@
-pref(layout.async-containerless-scrolling.enabled,true) pref(apz.subframe.enabled,true) skip-if(!asyncPanZoom) == bg-fixed-1.html bg-fixed-1-ref.html
-pref(layout.async-containerless-scrolling.enabled,true) pref(apz.subframe.enabled,true) skip-if(!asyncPanZoom) == bg-fixed-cover-1.html bg-fixed-cover-1-ref.html
-pref(layout.async-containerless-scrolling.enabled,true) pref(apz.subframe.enabled,true) skip-if(!asyncPanZoom) == bg-fixed-cover-2.html bg-fixed-cover-2-ref.html
-pref(layout.async-containerless-scrolling.enabled,true) pref(apz.subframe.enabled,true) skip-if(!asyncPanZoom) == bg-fixed-cover-3.html bg-fixed-cover-3-ref.html
-pref(layout.async-containerless-scrolling.enabled,true) pref(apz.subframe.enabled,true) skip-if(!asyncPanZoom) == element-1.html element-1-ref.html
-pref(layout.async-containerless-scrolling.enabled,true) pref(apz.subframe.enabled,true) skip-if(!asyncPanZoom) == nested-1.html nested-1-ref.html
-pref(layout.async-containerless-scrolling.enabled,true) pref(apz.subframe.enabled,true) skip-if(!asyncPanZoom) == position-fixed-1.html position-fixed-1-ref.html
-pref(layout.async-containerless-scrolling.enabled,true) pref(apz.subframe.enabled,true) skip-if(!asyncPanZoom) == position-fixed-2.html position-fixed-2-ref.html
-pref(layout.async-containerless-scrolling.enabled,true) pref(apz.subframe.enabled,true) skip-if(!asyncPanZoom) == position-fixed-cover-1.html position-fixed-cover-1-ref.html
-pref(layout.async-containerless-scrolling.enabled,true) pref(apz.subframe.enabled,true) skip-if(!asyncPanZoom) == position-fixed-cover-2.html position-fixed-cover-2-ref.html
-pref(layout.async-containerless-scrolling.enabled,true) pref(apz.subframe.enabled,true) skip-if(!asyncPanZoom) == position-fixed-cover-3.html position-fixed-cover-3-ref.html
-pref(layout.async-containerless-scrolling.enabled,true) pref(apz.subframe.enabled,true) skip-if(!asyncPanZoom) == split-layers-1.html split-layers-1-ref.html
-pref(layout.async-containerless-scrolling.enabled,true) pref(apz.subframe.enabled,true) skip-if(!asyncPanZoom) == split-layers-multi-scrolling-1.html split-layers-multi-scrolling-1-ref.html
-pref(layout.async-containerless-scrolling.enabled,true) pref(apz.subframe.enabled,true) skip-if(!asyncPanZoom) == split-opacity-layers-1.html split-opacity-layers-1-ref.html
-
-pref(layout.async-containerless-scrolling.enabled,false) skip-if(!asyncPanZoom) == bg-fixed-1.html bg-fixed-1-ref.html
-pref(layout.async-containerless-scrolling.enabled,false) skip-if(!asyncPanZoom) == bg-fixed-cover-1.html bg-fixed-cover-1-ref.html
-pref(layout.async-containerless-scrolling.enabled,false) skip-if(!asyncPanZoom) == bg-fixed-cover-2.html bg-fixed-cover-2-ref.html
-pref(layout.async-containerless-scrolling.enabled,false) skip-if(!asyncPanZoom) == bg-fixed-cover-3.html bg-fixed-cover-3-ref.html
-pref(layout.async-containerless-scrolling.enabled,false) skip-if(!asyncPanZoom) == element-1.html element-1-ref.html
-pref(layout.async-containerless-scrolling.enabled,false) skip-if(!asyncPanZoom) == position-fixed-1.html position-fixed-1-ref.html
-pref(layout.async-containerless-scrolling.enabled,false) skip-if(!asyncPanZoom) == position-fixed-2.html position-fixed-2-ref.html
-pref(layout.async-containerless-scrolling.enabled,false) skip-if(!asyncPanZoom) == position-fixed-cover-1.html position-fixed-cover-1-ref.html
-pref(layout.async-containerless-scrolling.enabled,false) skip-if(!asyncPanZoom) == position-fixed-cover-2.html position-fixed-cover-2-ref.html
-pref(layout.async-containerless-scrolling.enabled,false) skip-if(!asyncPanZoom) == position-fixed-cover-3.html position-fixed-cover-3-ref.html
-
+skip-if(!asyncPanZoom) == bg-fixed-1.html bg-fixed-1-ref.html
+skip-if(!asyncPanZoom) == bg-fixed-cover-1.html bg-fixed-cover-1-ref.html
+skip-if(!asyncPanZoom) == bg-fixed-cover-2.html bg-fixed-cover-2-ref.html
+skip-if(!asyncPanZoom) == bg-fixed-cover-3.html bg-fixed-cover-3-ref.html
+skip-if(!asyncPanZoom) == element-1.html element-1-ref.html
+skip-if(!asyncPanZoom) == position-fixed-1.html position-fixed-1-ref.html
+skip-if(!asyncPanZoom) == position-fixed-2.html position-fixed-2-ref.html
+skip-if(!asyncPanZoom) == position-fixed-cover-1.html position-fixed-cover-1-ref.html
+skip-if(!asyncPanZoom) == position-fixed-cover-2.html position-fixed-cover-2-ref.html
+skip-if(!asyncPanZoom) == position-fixed-cover-3.html position-fixed-cover-3-ref.html
deleted file mode 100644
--- a/layout/reftests/async-scrolling/split-layers-1-ref.html
+++ /dev/null
@@ -1,13 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<body>
-  <!-- Test that element content scrolls asynchronously even when content
-       has to be split into separate layers with non-scrolling content in
-       between -->
-  <div style="width:400px; height:500px; overflow:hidden; border:2px solid black">
-    <div style="height:450px"></div>
-    <div style="height:100px; width:200px; float:left; background:purple"></div>
-    <div style="left:200px; top:0; height:800px; width:300px; float:left; background:yellow; position:absolute; z-index:1;"></div>
-    <div style="height:100px; width:200px; float:left; background:purple; position:relative; z-index:2;"></div>
-  </div>
-</html>
deleted file mode 100644
--- a/layout/reftests/async-scrolling/split-layers-1.html
+++ /dev/null
@@ -1,16 +0,0 @@
-<!DOCTYPE HTML>
-<html reftest-async-scroll>
-<body>
-  <!-- Test that element content scrolls asynchronously even when content
-       has to be split into separate layers with non-scrolling content in
-       between -->
-  <div style="width:400px; height:500px; overflow:hidden; border:2px solid black"
-       reftest-displayport-x="0" reftest-displayport-y="0"
-       reftest-displayport-w="800" reftest-displayport-h="2000"
-       reftest-async-scroll-x="0" reftest-async-scroll-y="50">
-    <div style="height:500px"></div>
-    <div style="height:100px; width:200px; float:left; background:purple"></div>
-    <div style="left:200px; top:0; height:800px; width:300px; float:left; background:yellow; position:absolute; z-index:1;"></div>
-    <div style="height:100px; width:200px; float:left; background:purple; position:relative; z-index:2;"></div>
-  </div>
-
deleted file mode 100644
--- a/layout/reftests/async-scrolling/split-layers-multi-scrolling-1-ref.html
+++ /dev/null
@@ -1,14 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<body>
-  <!-- Test that element content scrolls asynchronously even when content
-       has to be split into separate layers with non-scrolling content in
-       between -->
-  <div style="width:400px; height:500px; overflow:hidden; border:2px solid black; margin-top:-50px;">
-    <div style="height:450px"></div>
-    <div style="height:100px; width:200px; float:left; background:purple"></div>
-    <div style="left:200px; top:-50px; height:800px; width:300px; float:left; background:yellow; position:absolute; z-index:1;"></div>
-    <div style="height:100px; width:200px; float:left; background:purple; position:relative; z-index:2;"></div>
-  </div>
-</html>
-
deleted file mode 100644
--- a/layout/reftests/async-scrolling/split-layers-multi-scrolling-1.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<!DOCTYPE HTML>
-<html reftest-async-scroll
-      reftest-displayport-x="0" reftest-displayport-y="0"
-      reftest-displayport-w="800" reftest-displayport-h="2000"
-      reftest-async-scroll-x="0" reftest-async-scroll-y="50">
-<body style="height:3000px; overflow:hidden">
-  <!-- Test that element content scrolls asynchronously even when content
-       has to be split into separate layers with non-scrolling content in
-       between -->
-  <div style="width:400px; height:500px; overflow:hidden; border:2px solid black"
-       reftest-displayport-x="0" reftest-displayport-y="0"
-       reftest-displayport-w="800" reftest-displayport-h="2000"
-       reftest-async-scroll-x="0" reftest-async-scroll-y="50">
-    <div style="height:500px"></div>
-    <div style="height:100px; width:200px; float:left; background:purple"></div>
-    <div style="left:200px; top:0; height:800px; width:300px; float:left; background:yellow; position:absolute; z-index:1;"></div>
-    <div style="height:100px; width:200px; float:left; background:purple; position:relative; z-index:2;"></div>
-  </div>
-
deleted file mode 100644
--- a/layout/reftests/async-scrolling/split-opacity-layers-1-ref.html
+++ /dev/null
@@ -1,12 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<body>
-  <div style="width:400px; height:500px; overflow:hidden; border:2px solid black">
-    <div style="height:450px"></div>
-    <div style="height:100px; width:200px; float:left; background:purple"></div>
-    <div style="opacity:0.5">
-      <div style="left:200px; top:0; height:800px; width:300px; float:left; background:yellow; position:absolute; z-index:1;"></div>
-      <div style="height:100px; width:200px; float:left; background:purple; position:relative; z-index:2;"></div>
-    </div>
-  </div>
-
deleted file mode 100644
--- a/layout/reftests/async-scrolling/split-opacity-layers-1.html
+++ /dev/null
@@ -1,15 +0,0 @@
-<!DOCTYPE HTML>
-<html reftest-async-scroll>
-<body>
-  <div style="width:400px; height:500px; overflow:hidden; border:2px solid black"
-       reftest-displayport-x="0" reftest-displayport-y="0"
-       reftest-displayport-w="800" reftest-displayport-h="2000"
-       reftest-async-scroll-x="0" reftest-async-scroll-y="50">
-    <div style="height:500px"></div>
-    <div style="height:100px; width:200px; float:left; background:purple"></div>
-    <div style="opacity:0.5">
-      <div style="left:200px; top:0; height:800px; width:300px; float:left; background:yellow; position:absolute; z-index:1;"></div>
-      <div style="height:100px; width:200px; float:left; background:purple; position:relative; z-index:2;"></div>
-    </div>
-  </div>
-
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -421,19 +421,16 @@ pref("media.video-queue.default-size", 1
 pref("media.video_stats.enabled", true);
 
 // Whether to enable the audio writing APIs on the audio element
 pref("media.audio_data.enabled", false);
 
 // Whether to use async panning and zooming
 pref("layers.async-pan-zoom.enabled", false);
 
-// Whether to enable containerless async scrolling
-pref("layout.async-containerless-scrolling.enabled", true);
-
 // APZ preferences. For documentation/details on what these prefs do, check 
 // gfx/layers/apz/src/AsyncPanZoomController.cpp.
 pref("apz.allow_checkerboarding", true);
 pref("apz.asyncscroll.throttle", 100);
 pref("apz.asyncscroll.timeout", 300);
 
 // Whether to lock touch scrolling to one axis at a time
 // 0 = FREE (No locking at all)