Bug 618975 Followup: bitrot and remove mDisplayport from nsDisplayScrollLayer r=cjones r=tn a=blocking-fennec
authorBenjamin Stover <bstover@mozilla.com>
Wed, 09 Mar 2011 13:35:27 -0800
changeset 63414 d66b9df51efff8c07b7ffd43f051803d960a2f1b
parent 63413 dea535299cf25062dd34133fd4cfaf9f27d5e410
child 63415 1604da0cfed4bcd00ab926e04056be53ce8ba369
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscjones, tn, blocking-fennec
bugs618975
milestone2.0b13pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 618975 Followup: bitrot and remove mDisplayport from nsDisplayScrollLayer r=cjones r=tn a=blocking-fennec
dom/base/nsDOMWindowUtils.cpp
layout/base/nsDisplayList.cpp
layout/base/nsDisplayList.h
layout/base/nsPresShell.cpp
layout/generic/nsGfxScrollFrame.cpp
layout/generic/nsGfxScrollFrame.h
layout/ipc/RenderFrameParent.cpp
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -310,41 +310,37 @@ nsDOMWindowUtils::SetDisplayPortForEleme
   }
 
   content->SetProperty(nsGkAtoms::DisplayPort, new nsRect(displayport),
                        DestroyNsRect);
 
   nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame();
   if (rootScrollFrame) {
     if (content == rootScrollFrame->GetContent()) {
-      // We are setting the root displayport. The pres context needs a special
-      // flag to be set.
+      // We are setting a root displayport for a document.
+      // The pres shell needs a special flag set.
       presShell->SetIgnoreViewportScrolling(PR_TRUE);
+
+      // The root document currently has a widget, but we might end up
+      // painting content inside the displayport but outside the widget
+      // bounds. This ensures the document's view honors invalidations
+      // within the displayport.
+      nsPresContext* presContext = GetPresContext();
+      if (presContext && presContext->IsRoot()) {
+        nsIFrame* rootFrame = presShell->GetRootFrame();
+        nsIView* view = rootFrame->GetView();
+        if (view) {
+          view->SetInvalidationDimensions(&displayport);
+        }
+      }
     }
   }
 
-  // FIXME (Bug 593243 should fix this.)
-  //
-  // Invalidated content does not pay any attention to the displayport, so
-  // invalidating the subdocument's root frame could end up not repainting
-  // visible content.
-  //
-  // For instance, imagine the iframe is located at y=1000. Even though the
-  // displayport may intersect the iframe's viewport, the visual overflow
-  // rect of the root content could be (0, 0, 800, 500). Since the dirty region
-  // does not intersect the visible overflow rect, the display list for the
-  // iframe will not even be generated.
-  //
-  // Here, we find the very top presShell and use its root frame for
-  // invalidation instead.
-  //
-  nsPresContext* rootPresContext = GetPresContext()->GetRootPresContext();
-  if (rootPresContext) {
-    nsIPresShell* rootPresShell = rootPresContext->GetPresShell();
-    nsIFrame* rootFrame = rootPresShell->FrameManager()->GetRootFrame();
+  if (presShell) {
+    nsIFrame* rootFrame = presShell->FrameManager()->GetRootFrame();
     if (rootFrame) {
       rootFrame->InvalidateWithFlags(rootFrame->GetVisualOverflowRectRelativeToSelf(),
                                      nsIFrame::INVALIDATE_NO_THEBES_LAYERS);
     }
   }
 
   return NS_OK;
 }
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -148,32 +148,32 @@ static void UnmarkFrameForDisplay(nsIFra
   }
 }
 
 static void RecordFrameMetrics(nsIFrame* aForFrame,
                                nsIFrame* aViewportFrame,
                                ContainerLayer* aRoot,
                                nsRect aVisibleRect,
                                nsRect aViewport,
-                               nsRect aDisplayPort,
+                               nsRect* aDisplayPort,
                                ViewID aScrollId) {
   nsPresContext* presContext = aForFrame->PresContext();
 
   nsIntRect visible = aVisibleRect.ToNearestPixels(presContext->AppUnitsPerDevPixel());
   aRoot->SetVisibleRegion(nsIntRegion(visible));
 
   FrameMetrics metrics;
 
   PRInt32 auPerDevPixel = presContext->AppUnitsPerDevPixel();
   metrics.mViewport = aViewport.ToNearestPixels(auPerDevPixel);
-  if (aViewport != aDisplayPort) {
-    metrics.mDisplayPort = aDisplayPort.ToNearestPixels(auPerDevPixel);
+  if (aDisplayPort) {
+    metrics.mDisplayPort = aDisplayPort->ToNearestPixels(auPerDevPixel);
   }
 
-  nsIScrollableFrame* scrollableFrame = NULL;
+  nsIScrollableFrame* scrollableFrame = nsnull;
   if (aViewportFrame)
     scrollableFrame = aViewportFrame->GetScrollTargetFrame();
 
   if (scrollableFrame) {
     nsSize contentSize =
       scrollableFrame->GetScrollRange().Size() +
       scrollableFrame->GetScrollPortRect().Size();
     metrics.mContentSize = nsIntSize(NSAppUnitsToIntPixels(contentSize.width, auPerDevPixel),
@@ -520,27 +520,27 @@ void nsDisplayList::PaintForFrame(nsDisp
 
   nsPresContext* presContext = aForFrame->PresContext();
   nsIPresShell* presShell = presContext->GetPresShell();
 
   ViewID id = presContext->IsRootContentDocument() ? FrameMetrics::ROOT_SCROLL_ID
                                                    : FrameMetrics::NULL_SCROLL_ID;
 
   nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame();
-  nsRect visibleRect = mVisibleRect;
+  nsRect displayport;
+  bool usingDisplayport = false;
   if (rootScrollFrame) {
     nsIContent* content = rootScrollFrame->GetContent();
     if (content) {
-      // If there is a displayport defined for the root content element,
-      // it will be stored in visibleRect.
-      nsLayoutUtils::GetDisplayPort(content, &visibleRect);
+      usingDisplayport = nsLayoutUtils::GetDisplayPort(content, &displayport);
     }
   }
-  RecordFrameMetrics(aForFrame, presShell->GetRootScrollFrame(),
-                     root, mVisibleRect, mVisibleRect, visibleRect, id);
+  RecordFrameMetrics(aForFrame, rootScrollFrame,
+                     root, mVisibleRect, mVisibleRect,
+                     (usingDisplayport ? &displayport : nsnull), id);
 
   // If the layer manager supports resolution scaling, set that up
   if (LayerManager::LAYERS_BASIC == layerManager->GetBackendType()) {
     BasicLayerManager* basicManager =
       static_cast<BasicLayerManager*>(layerManager.get());
     // This is free if both resolutions are 1.0, or neither resolution
     // has changed since the last transaction
     basicManager->SetResolution(presShell->GetXResolution(),
@@ -1701,21 +1701,19 @@ nsDisplayOwnLayer::BuildLayer(nsDisplayL
   return layer.forget();
 }
 
 #ifdef MOZ_IPC
 
 nsDisplayScrollLayer::nsDisplayScrollLayer(nsDisplayListBuilder* aBuilder,
                                            nsDisplayList* aList,
                                            nsIFrame* aForFrame,
-                                           nsIFrame* aViewportFrame,
-                                           const nsRect& aDisplayPort)
+                                           nsIFrame* aViewportFrame)
   : nsDisplayOwnLayer(aBuilder, aForFrame, aList)
   , mViewportFrame(aViewportFrame)
-  , mDisplayPort(aDisplayPort)
 {
 #ifdef NS_BUILD_REFCNT_LOGGING
   MOZ_COUNT_CTOR(nsDisplayScrollLayer);
 #endif
 
   NS_ASSERTION(mFrame && mFrame->GetContent(),
                "Need a child frame with content");
 }
@@ -1730,40 +1728,41 @@ nsDisplayScrollLayer::BuildLayer(nsDispl
   // Or, if not set, generate a new ID.
   nsIContent* content = mFrame->GetContent();
   ViewID scrollId = nsLayoutUtils::FindIDFor(content);
 
   nsRect viewport = mViewportFrame->GetRect() -
                     mViewportFrame->GetPosition() +
                     aBuilder->ToReferenceFrame(mViewportFrame);
 
+  bool usingDisplayport = false;
+  nsRect displayport;
+  if (content) {
+    usingDisplayport = nsLayoutUtils::GetDisplayPort(content, &displayport);
+  }
   RecordFrameMetrics(mFrame, mViewportFrame, layer, mVisibleRect, viewport,
-                     mDisplayPort, scrollId);
+                     (usingDisplayport ? &displayport : nsnull), scrollId);
 
   return layer.forget();
 }
 
 PRBool
 nsDisplayScrollLayer::ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                         nsRegion* aVisibleRegion,
                                         const nsRect& aAllowVisibleRegionExpansion,
                                         PRBool& aContainsRootContentDocBG)
 {
   nsPresContext* presContext = mFrame->PresContext();
-
-  nsRect viewport = mViewportFrame->GetRect() -
-                    mViewportFrame->GetPosition() +
-                    aBuilder->ToReferenceFrame(mViewportFrame);
-
-  if (mDisplayPort != viewport) {
+  nsRect displayport;
+  if (nsLayoutUtils::GetDisplayPort(mFrame->GetContent(), &displayport)) {
     // 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.
 
-    nsRegion childVisibleRegion = mDisplayPort + aBuilder->ToReferenceFrame(mViewportFrame);
+    nsRegion childVisibleRegion = displayport + aBuilder->ToReferenceFrame(mViewportFrame);
 
     nsRect boundedRect;
     boundedRect.IntersectRect(childVisibleRegion.GetBounds(), mList.GetBounds(aBuilder));
     nsRect allowExpansion;
     allowExpansion.IntersectRect(allowExpansion, boundedRect);
     PRBool visible = mList.ComputeVisibilityForSublist(
       aBuilder, &childVisibleRegion, boundedRect, allowExpansion, aContainsRootContentDocBG);
     mVisibleRect = boundedRect;
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -1785,22 +1785,19 @@ public:
  */
 class nsDisplayScrollLayer : public nsDisplayOwnLayer
 {
 public:
   /**
    * @param aForFrame This will determine what the displayport is. It should be
    *                  the root content frame of the scrolled area.
    * @param aViewportFrame The viewport frame you see this content through.
-   * @param aDisplayPort Overrides the visibility of the child items if it
-   *                     is not equal to the visible area.
    */
   nsDisplayScrollLayer(nsDisplayListBuilder* aBuilder, nsDisplayList* aList,
-                       nsIFrame* aForFrame, nsIFrame* aViewportFrame,
-                       const nsRect& aDisplayPort);
+                       nsIFrame* aForFrame, nsIFrame* aViewportFrame);
   NS_DISPLAY_DECL_NAME("ScrollLayer", TYPE_SCROLL_LAYER)
 
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayScrollLayer();
 #endif
 
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager);
@@ -1814,17 +1811,16 @@ public:
                                    LayerManager* aManager)
   {
     // Force this as a layer so we can scroll asynchronously.
     // This causes incorrect rendering for rounded clips!
     return mozilla::LAYER_ACTIVE_FORCE;
   }
 private:
   nsIFrame* mViewportFrame;
-  nsRect mDisplayPort;
 };
 #endif
 
 /**
  * nsDisplayClip can clip a list of items, but we take a single item
  * initially and then later merge other items into it when we merge
  * adjacent matching nsDisplayClips
  */
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -6041,21 +6041,16 @@ void PresShell::SetRenderingState(const 
     if (manager) {
       FrameLayerBuilder::InvalidateAllLayers(manager);
     }
   }
 
   mRenderFlags = aState.mRenderFlags;
   mXResolution = aState.mXResolution;
   mYResolution = aState.mYResolution;
-
-  nsIView* rootView;
-  if (NS_SUCCEEDED(mViewManager->GetRootView(rootView)) && rootView) {
-    rootView->SetInvalidationDimensions(&mDisplayPort);
-  }
 }
 
 void PresShell::SynthesizeMouseMove(PRBool aFromScroll)
 {
   if (mViewManager && !mPaintingSuppressed && mIsActive) {
     mViewManager->SynthesizeMouseMove(aFromScroll);
   }
 }
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -190,22 +190,24 @@ nsHTMLScrollFrame::InvalidateInternal(co
                                       nscoord aX, nscoord aY, nsIFrame* aForChild,
                                       PRUint32 aFlags)
 {
   if (aForChild) {
     if (aForChild == mInner.mScrolledFrame) {
       nsRect damage = aDamageRect + nsPoint(aX, aY);
       // This is the damage rect that we're going to pass up to our parent.
       nsRect parentDamage;
-      nsIPresShell* presShell = PresContext()->PresShell();
       // If we're using a displayport, we might be displaying an area
       // different than our scroll port and the damage needs to be
       // clipped to that instead.
-      if (mInner.mIsRoot && presShell->UsingDisplayPort()) {
-        parentDamage.IntersectRect(damage, presShell->GetDisplayPort());
+      nsRect displayport;
+      PRBool usingDisplayport = nsLayoutUtils::GetDisplayPort(GetContent(),
+                                                              &displayport);
+      if (usingDisplayport) {
+        parentDamage.IntersectRect(damage, displayport);
       } else {
         parentDamage.IntersectRect(damage, mInner.mScrollPort);
       }
 
       if (IsScrollingActive()) {
         // This is the damage rect that we're going to pass up and
         // only request invalidation of ThebesLayers for.
         // damage is now in our coordinate system, which means it was
@@ -1107,22 +1109,24 @@ void
 nsXULScrollFrame::InvalidateInternal(const nsRect& aDamageRect,
                                      nscoord aX, nscoord aY, nsIFrame* aForChild,
                                      PRUint32 aFlags)
 {
   if (aForChild == mInner.mScrolledFrame) {
     nsRect damage = aDamageRect + nsPoint(aX, aY);
     // This is the damage rect that we're going to pass up to our parent.
     nsRect parentDamage;
-    nsIPresShell* presShell = PresContext()->PresShell();
     // If we're using a displayport, we might be displaying an area
     // different than our scroll port and the damage needs to be
     // clipped to that instead.
-    if (mInner.mIsRoot && presShell->UsingDisplayPort()) {
-      parentDamage.IntersectRect(damage, presShell->GetDisplayPort());
+    nsRect displayport;
+    PRBool usingDisplayport = nsLayoutUtils::GetDisplayPort(GetContent(),
+                                                            &displayport);
+    if (usingDisplayport) {
+      parentDamage.IntersectRect(damage, displayport);
     } else {
       parentDamage.IntersectRect(damage, mInner.mScrollPort);
     }
 
     if (IsScrollingActive()) {
       // This is the damage rect that we're going to pass up and
       // only request invalidation of ThebesLayers for.
       // damage is now in our coordinate system, which means it was
@@ -1365,43 +1369,46 @@ public:
     aObject->MarkInactive();
   }
 };
 
 static ScrollFrameActivityTracker *gScrollFrameActivityTracker = nsnull;
 
 nsGfxScrollFrameInner::nsGfxScrollFrameInner(nsContainerFrame* aOuter,
                                              PRBool aIsRoot)
-  : mHScrollbarBox(nsnull),
-    mVScrollbarBox(nsnull),
-    mScrolledFrame(nsnull),
-    mScrollCornerBox(nsnull),
-    mResizerBox(nsnull),
-    mOuter(aOuter),
-    mAsyncScroll(nsnull),
-    mDestination(0, 0),
-    mScrollPosAtLastPaint(0, 0),
-    mRestorePos(-1, -1),
-    mLastPos(-1, -1),
-    mNeverHasVerticalScrollbar(PR_FALSE),
-    mNeverHasHorizontalScrollbar(PR_FALSE),
-    mHasVerticalScrollbar(PR_FALSE), 
-    mHasHorizontalScrollbar(PR_FALSE),
-    mFrameIsUpdatingScrollbar(PR_FALSE),
-    mDidHistoryRestore(PR_FALSE),
-    mIsRoot(aIsRoot),
-    mSupppressScrollbarUpdate(PR_FALSE),
-    mSkippedScrollbarLayout(PR_FALSE),
-    mHadNonInitialReflow(PR_FALSE),
-    mHorizontalOverflow(PR_FALSE),
-    mVerticalOverflow(PR_FALSE),
-    mPostedReflowCallback(PR_FALSE),
-    mMayHaveDirtyFixedChildren(PR_FALSE),
-    mUpdateScrollbarAttributes(PR_FALSE),
-    mCollapsedResizer(PR_FALSE)
+  : mHScrollbarBox(nsnull)
+  , mVScrollbarBox(nsnull)
+  , mScrolledFrame(nsnull)
+  , mScrollCornerBox(nsnull)
+  , mResizerBox(nsnull)
+  , mOuter(aOuter)
+  , mAsyncScroll(nsnull)
+  , mDestination(0, 0)
+  , mScrollPosAtLastPaint(0, 0)
+  , mRestorePos(-1, -1)
+  , mLastPos(-1, -1)
+  , mNeverHasVerticalScrollbar(PR_FALSE)
+  , mNeverHasHorizontalScrollbar(PR_FALSE)
+  , mHasVerticalScrollbar(PR_FALSE)
+  , mHasHorizontalScrollbar(PR_FALSE)
+  , mFrameIsUpdatingScrollbar(PR_FALSE)
+  , mDidHistoryRestore(PR_FALSE)
+  , mIsRoot(aIsRoot)
+  , mSupppressScrollbarUpdate(PR_FALSE)
+  , mSkippedScrollbarLayout(PR_FALSE)
+  , mHadNonInitialReflow(PR_FALSE)
+  , mHorizontalOverflow(PR_FALSE)
+  , mVerticalOverflow(PR_FALSE)
+  , mPostedReflowCallback(PR_FALSE)
+  , mMayHaveDirtyFixedChildren(PR_FALSE)
+  , mUpdateScrollbarAttributes(PR_FALSE)
+  , mCollapsedResizer(PR_FALSE)
+#ifdef MOZ_IPC
+  , mShouldBuildLayer(PR_FALSE)
+#endif
 {
   // lookup if we're allowed to overlap the content from the look&feel object
   PRBool canOverlap;
   nsPresContext* presContext = mOuter->PresContext();
   presContext->LookAndFeel()->
     GetMetric(nsILookAndFeel::eMetric_ScrollbarsCanOverlapContent, canOverlap);
   mScrollbarsCanOverlapContent = canOverlap;
   mScrollingActive = IsAlwaysActive();
@@ -1705,17 +1712,23 @@ void nsGfxScrollFrameInner::ScrollVisual
       MarkInactive();
     } else {
       flags |= nsIFrame::INVALIDATE_NO_THEBES_LAYERS;
     }
   }
   if (canScrollWithBlitting) {
     MarkActive();
   }
-  mOuter->InvalidateWithFlags(mScrollPort, flags);
+
+  nsRect invalidateRect, displayport;
+  invalidateRect =
+    (nsLayoutUtils::GetDisplayPort(mOuter->GetContent(), &displayport)) ?
+    displayport : mScrollPort;
+
+  mOuter->InvalidateWithFlags(invalidateRect, flags);
 
   if (flags & nsIFrame::INVALIDATE_NO_THEBES_LAYERS) {
     nsIFrame* displayRoot = nsLayoutUtils::GetDisplayRootFrame(mOuter);
     nsRect update =
       GetScrollPortRect() + mOuter->GetOffsetToCrossDoc(displayRoot);
     update = update.ConvertAppUnitsRoundOut(
       mOuter->PresContext()->AppUnitsPerDevPixel(),
       displayRoot->PresContext()->AppUnitsPerDevPixel());
@@ -1830,16 +1843,26 @@ nsGfxScrollFrameInner::AppendScrollParts
       ::AppendToTop(aBuilder, aLists.BorderBackground(),
                     aDest.PositionedDescendants(), kid,
                     aCreateLayer);
     }
   }
   return rv;
 }
 
+PRBool
+nsGfxScrollFrameInner::ShouldBuildLayer() const
+{
+#ifdef MOZ_IPC
+  return mShouldBuildLayer;
+#else
+  return PR_FALSE;
+#endif
+}
+
 nsresult
 nsGfxScrollFrameInner::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                         const nsRect&           aDirtyRect,
                                         const nsDisplayListSet& aLists)
 {
   nsresult rv = mOuter->DisplayBorderBackgroundOutline(aBuilder, aLists);
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -1874,81 +1897,63 @@ nsGfxScrollFrameInner::BuildDisplayList(
     // Now display the scrollbars and scrollcorner. These parts are drawn
     // in the border-background layer, on top of our own background and
     // borders and underneath borders and backgrounds of later elements
     // in the tree.
     AppendScrollPartsTo(aBuilder, aDirtyRect, aLists,
                         scrollParts, createLayersForScrollbars);
   }
 
-  nsRect displayport;
-  PRBool usingDisplayPort = nsLayoutUtils::GetDisplayPort(mOuter->GetContent(),
-                                                        &displayport);
-  if (!usingDisplayPort) {
-    displayport = mScrollPort;
-  }
-
   // Overflow clipping can never clip frames outside our subtree, so there
   // is no need to worry about whether we are a moving frame that might clip
   // non-moving frames.
   nsRect dirtyRect;
   // Not all our descendants will be clipped by overflow clipping, but all
   // the ones that aren't clipped will be out of flow frames that have already
   // had dirty rects saved for them by their parent frames calling
   // MarkOutOfFlowChildrenForDisplayList, so it's safe to restrict our
   // dirty rect here.
   dirtyRect.IntersectRect(aDirtyRect, mScrollPort);
 
-  if (usingDisplayPort) {
-    dirtyRect = displayport;
-  }
+  // Override the dirty rectangle if the displayport has been set.
+  nsLayoutUtils::GetDisplayPort(mOuter->GetContent(), &dirtyRect);
 
   nsDisplayListCollection set;
 
   nsPresContext* presContext = mOuter->PresContext();
-  PRInt32 appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
 
 #ifdef MOZ_IPC
   // Since making new layers is expensive, only use nsDisplayScrollLayer
   // if the area is scrollable.
   //
   // Scroll frames can be generated with a scroll range that is 0, 0.
   // Furthermore, it is not worth the memory tradeoff to allow asynchronous
   // scrolling of small scroll frames. We use an arbitrary minimum scroll
   // range of 20 pixels to eliminate many gfx scroll frames from becoming a
   // layer.
   //
+  PRInt32 appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
   nsRect scrollRange = GetScrollRange();
-  PRBool buildingLayer =
+  mShouldBuildLayer =
      (XRE_GetProcessType() == GeckoProcessType_Content &&
      (scrollRange.width >= NSIntPixelsToAppUnits(20, appUnitsPerDevPixel) ||
      scrollRange.height >= NSIntPixelsToAppUnits(20, appUnitsPerDevPixel))) &&
      (!mIsRoot || !mOuter->PresContext()->IsRootContentDocument());
-
-#else
-  PRBool buildingLayer = false;
 #endif
 
-  if (buildingLayer) {
+  if (ShouldBuildLayer()) {
     // Note that using StackingContext breaks z order, so the resulting
     // rendering can be incorrect for weird edge cases!
 
+    nsDisplayList list;
     rv = mScrolledFrame->BuildDisplayListForStackingContext(
-      aBuilder,
-      dirtyRect + mOuter->GetOffsetTo(mScrolledFrame),
-      set.Content()
-    );
+      aBuilder, dirtyRect + mOuter->GetOffsetTo(mScrolledFrame), &list);
 
     nsDisplayScrollLayer* layerItem = new (aBuilder) nsDisplayScrollLayer(
-      aBuilder,
-      set.Content(),
-      mScrolledFrame,
-      mOuter,
-      displayport
-    );
+      aBuilder, &list, mScrolledFrame, mOuter);
     set.Content()->AppendNewToTop(layerItem);
   } else {
     rv = mOuter->BuildDisplayListForChild(aBuilder, mScrolledFrame, dirtyRect, set);
   }
 
   NS_ENSURE_SUCCESS(rv, rv);
   nsRect clip;
   clip = mScrollPort + aBuilder->ToReferenceFrame(mOuter);
--- a/layout/generic/nsGfxScrollFrame.h
+++ b/layout/generic/nsGfxScrollFrame.h
@@ -82,16 +82,18 @@ public:
   void ReloadChildFrames();
 
   nsresult CreateAnonymousContent(nsTArray<nsIContent*>& aElements);
   void AppendAnonymousContentTo(nsBaseContentList& aElements, PRUint32 aFilter);
   nsresult FireScrollPortEvent();
   void PostOverflowEvent();
   void Destroy();
 
+  PRBool ShouldBuildLayer() const;
+
   nsresult BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                             const nsRect&           aDirtyRect,
                             const nsDisplayListSet& aLists);
 
   nsresult AppendScrollPartsTo(nsDisplayListBuilder*          aBuilder,
                                const nsRect&                  aDirtyRect,
                                const nsDisplayListSet&        aLists,
                                const nsDisplayListCollection& aDest,
@@ -232,17 +234,17 @@ public:
   PRUint32 GetScrollbarVisibility() const {
     return (mHasVerticalScrollbar ? nsIScrollableFrame::VERTICAL : 0) |
            (mHasHorizontalScrollbar ? nsIScrollableFrame::HORIZONTAL : 0);
   }
   nsMargin GetActualScrollbarSizes() const;
   nsMargin GetDesiredScrollbarSizes(nsBoxLayoutState* aState);
   PRBool IsLTR() const;
   PRBool IsScrollbarOnRight() const;
-  PRBool IsScrollingActive() const { return mScrollingActive; }
+  PRBool IsScrollingActive() const { return mScrollingActive || ShouldBuildLayer(); }
   // adjust the scrollbar rectangle aRect to account for any visible resizer.
   // aHasResizer specifies if there is a content resizer, however this method
   // will also check if a widget resizer is present as well.
   void AdjustScrollbarRectForResizer(nsIFrame* aFrame, nsPresContext* aPresContext,
                                      nsRect& aRect, PRBool aHasResizer, PRBool aVertical);
   // returns true if a resizer should be visible
   PRBool HasResizer() { return mResizerBox && !mCollapsedResizer; }
   void LayoutScrollbars(nsBoxLayoutState& aState,
@@ -315,16 +317,22 @@ public:
   // If true, we should be prepared to scroll using this scrollframe
   // by placing descendant content into its own layer(s)
   PRPackedBool mScrollingActive:1;
   // If true, scrollbars are stacked on the top of the display list and can
   // float above the content as a result
   PRPackedBool mScrollbarsCanOverlapContent:1;
   // If true, the resizer is collapsed and not displayed
   PRPackedBool mCollapsedResizer:1;
+
+#ifdef MOZ_IPC
+  // If true, the layer should always be active because we always build a layer.
+  // Used for asynchronous scrolling.
+  PRPackedBool mShouldBuildLayer:1;
+#endif
 };
 
 /**
  * The scroll frame creates and manages the scrolling view
  *
  * It only supports having a single child frame that typically is an area
  * frame, but doesn't have to be. The child frame must have a view, though
  *
--- a/layout/ipc/RenderFrameParent.cpp
+++ b/layout/ipc/RenderFrameParent.cpp
@@ -176,17 +176,21 @@ ComputeShadowTreeTransform(nsIFrame* aCo
   // So we set a compensating translation that moves the content document
   // pixels to where the user wants them to be.
   //
   nscoord auPerDevPixel = aContainerFrame->PresContext()->AppUnitsPerDevPixel();
   nsIntPoint scrollOffset =
     aConfig.mScrollOffset.ToNearestPixels(auPerDevPixel);
   nsIntPoint metricsScrollOffset = aMetrics->mViewportScrollOffset;
 
-  if (aRootFrameLoader->AsyncScrollEnabled()) {
+  if (aRootFrameLoader->AsyncScrollEnabled() && !aMetrics->mDisplayPort.IsEmpty()) {
+    // Only use asynchronous scrolling if it is enabled and there is a
+    // displayport defined. It is useful to have a scroll layer that is
+    // synchronously scrolled for identifying a scroll area before it is
+    // being actively scrolled.
     nsIntPoint scrollCompensation(
       scrollOffset.x * aInverseScaleX - metricsScrollOffset.x * aConfig.mXScale,
       scrollOffset.y * aInverseScaleY - metricsScrollOffset.y * aConfig.mYScale);
 
     return ViewTransform(-scrollCompensation, aConfig.mXScale, aConfig.mYScale);
   } else {
     return ViewTransform(nsIntPoint(0, 0), 1, 1);
   }