Bug 618975 Pan overflow elements in parent process r=cjones r=tn sr=roc a=blocking-fennec
authorBenjamin Stover <bstover@mozilla.com>
Tue, 15 Mar 2011 16:20:19 -0700
changeset 63413 dea535299cf25062dd34133fd4cfaf9f27d5e410
parent 63412 5f7f9a0d61621f77c974ddaa1da8bcef058f6d31
child 63414 d66b9df51efff8c07b7ffd43f051803d960a2f1b
push idunknown
push userunknown
push dateunknown
reviewerscjones, tn, roc, 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 Pan overflow elements in parent process r=cjones r=tn sr=roc a=blocking-fennec
content/base/src/nsGkAtomList.h
dom/base/nsDOMWindowUtils.cpp
dom/interfaces/base/nsIDOMWindowUtils.idl
layout/base/FrameLayerBuilder.cpp
layout/base/FrameLayerBuilder.h
layout/base/nsDisplayList.cpp
layout/base/nsDisplayList.h
layout/base/nsIPresShell.h
layout/base/nsLayoutUtils.cpp
layout/base/nsLayoutUtils.h
layout/base/nsPresShell.cpp
layout/generic/nsGfxScrollFrame.cpp
layout/generic/nsSubDocumentFrame.cpp
layout/ipc/test-ipcbrowser-content.js
layout/tools/reftest/reftest-content.js
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -1744,16 +1744,17 @@ GK_ATOM(Unicode, "x-unicode")
 // Names for editor transactions
 GK_ATOM(TypingTxnName, "Typing")
 GK_ATOM(IMETxnName, "IME")
 GK_ATOM(DeleteTxnName, "Deleting")
 
 // IPC stuff
 GK_ATOM(Remote, "remote")
 GK_ATOM(RemoteId, "_remote_id")
+GK_ATOM(DisplayPort, "_displayport")
 
 // Names for system metrics
 GK_ATOM(scrollbar_start_backward, "scrollbar-start-backward")
 GK_ATOM(scrollbar_start_forward, "scrollbar-start-forward")
 GK_ATOM(scrollbar_end_backward, "scrollbar-end-backward")
 GK_ATOM(scrollbar_end_forward, "scrollbar-end-forward")
 GK_ATOM(scrollbar_thumb_proportional, "scrollbar-thumb-proportional")
 GK_ATOM(images_in_menus, "images-in-menus")
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -43,16 +43,17 @@
 #include "nsIPrivateDOMEvent.h"
 #include "nsDOMWindowUtils.h"
 #include "nsQueryContentEventResult.h"
 #include "nsGlobalWindow.h"
 #include "nsIDocument.h"
 #include "nsFocusManager.h"
 #include "nsIEventStateManager.h"
 #include "nsEventStateManager.h"
+#include "nsFrameManager.h"
 
 #include "nsIScrollableFrame.h"
 
 #include "nsContentUtils.h"
 #include "nsLayoutUtils.h"
 
 #include "nsIFrame.h"
 #include "nsIWidget.h"
@@ -253,36 +254,102 @@ nsDOMWindowUtils::SetCSSViewport(float a
   nscoord width = nsPresContext::CSSPixelsToAppUnits(aWidthPx);
   nscoord height = nsPresContext::CSSPixelsToAppUnits(aHeightPx);
 
   presShell->ResizeReflowOverride(width, height);
 
   return NS_OK;
 }
 
+static void DestroyNsRect(void* aObject, nsIAtom* aPropertyName,
+                          void* aPropertyValue, void* aData)
+{
+  nsRect* rect = static_cast<nsRect*>(aPropertyValue);
+  delete rect;
+}
+
 NS_IMETHODIMP
 nsDOMWindowUtils::SetDisplayPort(float aXPx, float aYPx,
                                  float aWidthPx, float aHeightPx)
 {
+  NS_ABORT_IF_FALSE(false, "This interface is deprecated.");
+  return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+nsDOMWindowUtils::SetDisplayPortForElement(float aXPx, float aYPx,
+                                           float aWidthPx, float aHeightPx,
+                                           nsIDOMElement* aElement)
+{
   if (!IsUniversalXPConnectCapable()) {
     return NS_ERROR_DOM_SECURITY_ERR;
   }
 
   nsIPresShell* presShell = GetPresShell();
   if (!presShell) {
     return NS_ERROR_FAILURE;
   } 
 
   nsRect displayport(nsPresContext::CSSPixelsToAppUnits(aXPx),
                      nsPresContext::CSSPixelsToAppUnits(aYPx),
                      nsPresContext::CSSPixelsToAppUnits(aWidthPx),
                      nsPresContext::CSSPixelsToAppUnits(aHeightPx));
-  presShell->SetDisplayPort(displayport);
+
+  if (!aElement) {
+    return NS_ERROR_INVALID_ARG;
+  }
+
+  nsCOMPtr<nsIContent> content = do_QueryInterface(aElement);
+
+  if (!content) {
+    return NS_ERROR_INVALID_ARG;
+  }
+
+  nsRect lastDisplayPort;
+  if (nsLayoutUtils::GetDisplayPort(content, &lastDisplayPort) &&
+      displayport == lastDisplayPort) {
+    return NS_OK;
+  }
+
+  content->SetProperty(nsGkAtoms::DisplayPort, new nsRect(displayport),
+                       DestroyNsRect);
 
-  presShell->SetIgnoreViewportScrolling(PR_TRUE);
+  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.
+      presShell->SetIgnoreViewportScrolling(PR_TRUE);
+    }
+  }
+
+  // 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 (rootFrame) {
+      rootFrame->InvalidateWithFlags(rootFrame->GetVisualOverflowRectRelativeToSelf(),
+                                     nsIFrame::INVALIDATE_NO_THEBES_LAYERS);
+    }
+  }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::SetResolution(float aXResolution, float aYResolution)
 {
   if (!IsUniversalXPConnectCapable()) {
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -124,40 +124,17 @@ interface nsIDOMWindowUtils : nsISupport
    * This will trigger reflow.
    *
    * The caller of this method must have UniversalXPConnect
    * privileges.
    */
   void setCSSViewport(in float aWidthPx, in float aHeightPx);
 
   /**
-   * Set the "displayport" to be <xPx, yPx, widthPx, heightPx> in
-   * units of CSS pixels, regardless of the size of the enclosing
-   * widget/view.  This will *not* trigger reflow.
-   *
-   * <x, y> is relative to the top-left of the CSS viewport.  This
-   * means that the pixels rendered to the displayport take scrolling
-   * into account, for example.
-   *
-   * The displayport will be used as the window's visible region for
-   * the purposes of invalidation and painting.  The displayport can
-   * approximately be thought of as a "persistent" drawWindow()
-   * (albeit with coordinates relative to the CSS viewport): the
-   * bounds are remembered by the platform, and layer pixels are
-   * retained and updated inside the viewport bounds.
-   *
-   * It's legal to set a displayport that extends beyond the CSS
-   * viewport in any direction (left/right/top/bottom).
-   * 
-   * It's also legal to set a displayport that extends beyond the
-   * document's bounds.  The value of the pixels rendered outside the
-   * document bounds is not yet defined.
-   *
-   * The caller of this method must have UniversalXPConnect
-   * privileges.
+   * @DEPRECATED See nsIDOMWindowUtils_MOZILLA_2_0_BRANCH.
    */
   void setDisplayPort(in float aXPx, in float aYPx,
                       in float aWidthPx, in float aHeightPx);
 
   /**
    * Get/set the resolution at which rescalable web content is drawn.
    * Currently this is only (some) thebes content.
    *
@@ -819,31 +796,61 @@ interface nsIDOMWindowUtils : nsISupport
   double computeAnimationDistance(in nsIDOMElement element,
                                   in AString property,
                                   in AString value1,
                                   in AString value2);
 };
 
 typedef unsigned long long nsViewID;
 
-[scriptable, uuid(be2e28c8-64f8-4100-906d-8a451ddd6835)]
+[scriptable, uuid(7ad49829-e631-4cdd-a237-95847d9bcbe6)]
 interface nsIDOMWindowUtils_MOZILLA_2_0_BRANCH : nsISupports {
   /**
    * Get the type of the currently focused html input, if any.
    */
   readonly attribute string focusedInputType;
 
   /**
    * Given a view ID from the compositor process, retrieve the element
    * associated with a view. For scrollpanes for documents, the root
    * element of the document is returned.
    */
   nsIDOMElement findElementWithViewId(in nsViewID aId);
 
   /**
+   * For any scrollable element, this allows you to override the
+   * visible region and draw more than what is visible, which is
+   * useful for asynchronous drawing. The "displayport" will be
+   * <xPx, yPx, widthPx, heightPx> in units of CSS pixels,
+   * regardless of the size of the enclosing container.  This
+   * will *not* trigger reflow.
+   *
+   * For the root scroll area, pass in the root document element.
+   * For scrollable elements, pass in the container element (for
+   * instance, the element with overflow: scroll).
+   *
+   * <x, y> is relative to the top-left of what would normally be
+   * the visible area of the element. This means that the pixels
+   * rendered to the displayport take scrolling into account,
+   * for example.
+   *
+   * It's legal to set a displayport that extends beyond the overflow
+   * area in any direction (left/right/top/bottom).
+   * 
+   * It's also legal to set a displayport that extends beyond the
+   * area's bounds.  No pixels are rendered outside the area bounds.
+   *
+   * The caller of this method must have UniversalXPConnect
+   * privileges.
+   */
+  void setDisplayPortForElement(in float aXPx, in float aYPx,
+                                in float aWidthPx, in float aHeightPx,
+                                in nsIDOMElement aElement);
+
+  /**
    * Same as enterModalState, but returns the window associated with the
    * current JS context.
    */
   nsIDOMWindow enterModalStateWithWindow();
 
   /**
    * Same as leaveModalState, but takes a window associated with the active
    * context when enterModalStateWithWindow was called. The currently context
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -1290,17 +1290,18 @@ ContainerState::ProcessDisplayItems(cons
       itemContent.IntersectRect(aClip.mClipRect, itemContent);
     }
     mBounds.UnionRect(mBounds, itemContent);
     nsIntRect itemDrawRect = itemContent.ToOutsidePixels(appUnitsPerDevPixel);
     nsDisplayItem::LayerState layerState =
       item->GetLayerState(mBuilder, mManager);
 
     // Assign the item to a layer
-    if (layerState == LAYER_ACTIVE && (aClip.mRoundedClipRects.IsEmpty() ||
+    if (layerState == LAYER_ACTIVE_FORCE ||
+        layerState == LAYER_ACTIVE && (aClip.mRoundedClipRects.IsEmpty() ||
         // We can use the visible rect here only because the item has its own
         // layer, like the comment below.
         !aClip.IsRectClippedByRoundedCorner(item->GetVisibleRect()))) {
       // If the item would have its own layer but is invisible, just hide it.
       // Note that items without their own layers can't be skipped this
       // way, since their ThebesLayer may decide it wants to draw them
       // into its buffer even if they're currently covered.
       if (itemVisibleRect.IsEmpty()) {
--- a/layout/base/FrameLayerBuilder.h
+++ b/layout/base/FrameLayerBuilder.h
@@ -51,17 +51,20 @@ class nsDisplayItem;
 class gfxContext;
 class nsRootPresContext;
 
 namespace mozilla {
 
 enum LayerState {
   LAYER_NONE,
   LAYER_INACTIVE,
-  LAYER_ACTIVE
+  LAYER_ACTIVE,
+  // Force an active layer even if it causes incorrect rendering, e.g.
+  // when the layer has rounded rect clips.
+  LAYER_ACTIVE_FORCE
 };
 
 /**
  * The FrameLayerBuilder belongs to an nsDisplayListBuilder and is
  * responsible for converting display lists into layer trees.
  * 
  * The most important API in this class is BuildContainerLayerFor. This
  * method takes a display list as input and constructs a ContainerLayer
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -144,47 +144,48 @@ static void UnmarkFrameForDisplay(nsIFra
        f = nsLayoutUtils::GetParentOrPlaceholderFor(frameManager, f)) {
     if (!(f->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO))
       return;
     f->RemoveStateBits(NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO);
   }
 }
 
 static void RecordFrameMetrics(nsIFrame* aForFrame,
+                               nsIFrame* aViewportFrame,
                                ContainerLayer* aRoot,
                                nsRect aVisibleRect,
                                nsRect aViewport,
+                               nsRect aDisplayPort,
                                ViewID aScrollId) {
   nsPresContext* presContext = aForFrame->PresContext();
-  nsIPresShell* presShell = presContext->GetPresShell();
 
   nsIntRect visible = aVisibleRect.ToNearestPixels(presContext->AppUnitsPerDevPixel());
   aRoot->SetVisibleRegion(nsIntRegion(visible));
 
   FrameMetrics metrics;
 
   PRInt32 auPerDevPixel = presContext->AppUnitsPerDevPixel();
   metrics.mViewport = aViewport.ToNearestPixels(auPerDevPixel);
-  if (presShell->UsingDisplayPort()) {
-    metrics.mDisplayPort =
-      presShell->GetDisplayPort().ToNearestPixels(auPerDevPixel);
+  if (aViewport != aDisplayPort) {
+    metrics.mDisplayPort = aDisplayPort.ToNearestPixels(auPerDevPixel);
   }
 
-  nsIScrollableFrame* rootScrollableFrame =
-    presShell->GetRootScrollFrameAsScrollable();
-  if (rootScrollableFrame) {
-    nsSize contentSize = 
-      rootScrollableFrame->GetScrollRange().Size() +
-      rootScrollableFrame->GetScrollPortRect().Size();
+  nsIScrollableFrame* scrollableFrame = NULL;
+  if (aViewportFrame)
+    scrollableFrame = aViewportFrame->GetScrollTargetFrame();
+
+  if (scrollableFrame) {
+    nsSize contentSize =
+      scrollableFrame->GetScrollRange().Size() +
+      scrollableFrame->GetScrollPortRect().Size();
     metrics.mContentSize = nsIntSize(NSAppUnitsToIntPixels(contentSize.width, auPerDevPixel),
                                      NSAppUnitsToIntPixels(contentSize.height, auPerDevPixel));
 
     metrics.mViewportScrollOffset =
-      rootScrollableFrame->GetScrollPosition().ToNearestPixels(auPerDevPixel);
-    
+      scrollableFrame->GetScrollPosition().ToNearestPixels(auPerDevPixel);
   }
   else {
     nsSize contentSize = aForFrame->GetSize();
     metrics.mContentSize = nsIntSize(NSAppUnitsToIntPixels(contentSize.width, auPerDevPixel),
                                      NSAppUnitsToIntPixels(contentSize.height, auPerDevPixel));
   }
 
   metrics.mScrollId = aScrollId;
@@ -518,17 +519,28 @@ void nsDisplayList::PaintForFrame(nsDisp
     return;
 
   nsPresContext* presContext = aForFrame->PresContext();
   nsIPresShell* presShell = presContext->GetPresShell();
 
   ViewID id = presContext->IsRootContentDocument() ? FrameMetrics::ROOT_SCROLL_ID
                                                    : FrameMetrics::NULL_SCROLL_ID;
 
-  RecordFrameMetrics(aForFrame, root, mVisibleRect, mVisibleRect, id);
+  nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame();
+  nsRect visibleRect = mVisibleRect;
+  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);
+    }
+  }
+  RecordFrameMetrics(aForFrame, presShell->GetRootScrollFrame(),
+                     root, mVisibleRect, mVisibleRect, visibleRect, 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(),
@@ -1689,19 +1701,21 @@ nsDisplayOwnLayer::BuildLayer(nsDisplayL
   return layer.forget();
 }
 
 #ifdef MOZ_IPC
 
 nsDisplayScrollLayer::nsDisplayScrollLayer(nsDisplayListBuilder* aBuilder,
                                            nsDisplayList* aList,
                                            nsIFrame* aForFrame,
-                                           nsIFrame* aViewportFrame)
+                                           nsIFrame* aViewportFrame,
+                                           const nsRect& aDisplayPort)
   : 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");
 }
@@ -1716,36 +1730,40 @@ 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);
 
-  RecordFrameMetrics(mFrame, layer, mVisibleRect, viewport, scrollId);
+  RecordFrameMetrics(mFrame, mViewportFrame, layer, mVisibleRect, viewport,
+                     mDisplayPort, scrollId);
 
   return layer.forget();
 }
 
 PRBool
 nsDisplayScrollLayer::ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                         nsRegion* aVisibleRegion,
                                         const nsRect& aAllowVisibleRegionExpansion,
                                         PRBool& aContainsRootContentDocBG)
 {
   nsPresContext* presContext = mFrame->PresContext();
-  nsIPresShell* presShell = presContext->GetPresShell();
 
-  if (presShell->UsingDisplayPort()) {
+  nsRect viewport = mViewportFrame->GetRect() -
+                    mViewportFrame->GetPosition() +
+                    aBuilder->ToReferenceFrame(mViewportFrame);
+
+  if (mDisplayPort != viewport) {
     // 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 = presShell->GetDisplayPort() + aBuilder->ToReferenceFrame(mViewportFrame);
+    nsRegion childVisibleRegion = mDisplayPort + 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,35 +1785,46 @@ 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);
+                       nsIFrame* aForFrame, nsIFrame* aViewportFrame,
+                       const nsRect& aDisplayPort);
   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);
 
   virtual PRBool ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                    nsRegion* aVisibleRegion,
                                    const nsRect& aAllowVisibleRegionExpansion,
                                    PRBool& aContainsRootContentDocBG);
 
+  virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
+                                   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/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -1149,29 +1149,31 @@ public:
   virtual void SetIgnoreViewportScrolling(PRBool aIgnore) = 0;
   PRBool IgnoringViewportScrolling() const
   { return mRenderFlags & STATE_IGNORING_VIEWPORT_SCROLLING; }
 
   /**
    * Set up a "displayport", which overrides what everything else thinks
    * is the visible region of this document with the specified
    * displayport rect.
+   * @DEPRECATED Use nsLayoutUtils displayport methods
    */
   virtual void SetDisplayPort(const nsRect& aDisplayPort) = 0;
   PRBool UsingDisplayPort() const
-  { return mRenderFlags & STATE_USING_DISPLAYPORT; }
+  { NS_ABORT_IF_FALSE(false, "UsingDisplayPort is deprecated"); return false; }
 
   /**
    * Return the displayport being used.  |UsingDisplayPort()| must be
    * true.
+   * @DEPRECATED Use nsLayoutUtils displayport methods
    */
   nsRect GetDisplayPort()
   {
-    NS_ABORT_IF_FALSE(UsingDisplayPort(), "no displayport defined!");
-    return mDisplayPort;
+    NS_ABORT_IF_FALSE(false, "GetDisplayPort is deprecated");
+    return nsRect();
   }
 
    /**
    * Set a "resolution" for the document, which if not 1.0 will
    * allocate more or fewer pixels for rescalable content by a factor
    * of |resolution| in both dimensions.  Return NS_OK iff the
    * resolution bounds are sane, and the resolution of this was
    * actually updated.
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -138,16 +138,20 @@ static ContentMap& GetContentMap() {
 static void DestroyViewID(void* aObject, nsIAtom* aPropertyName,
                           void* aPropertyValue, void* aData)
 {
   ViewID* id = static_cast<ViewID*>(aPropertyValue);
   GetContentMap().Remove(*id);
   delete id;
 }
 
+/**
+ * A namespace class for static layout utilities.
+ */
+
 ViewID
 nsLayoutUtils::FindIDFor(nsIContent* aContent)
 {
   ViewID scrollId;
 
   void* scrollIdProperty = aContent->GetProperty(nsGkAtoms::RemoteId);
   if (scrollIdProperty) {
     scrollId = *static_cast<ViewID*>(scrollIdProperty);
@@ -172,19 +176,29 @@ nsLayoutUtils::FindContentFor(ViewID aId
 
   if (exists) {
     return content;
   } else {
     return nsnull;
   }
 }
 
-/**
- * A namespace class for static layout utilities.
- */
+bool
+nsLayoutUtils::GetDisplayPort(nsIContent* aContent, nsRect *aResult)
+{
+  void* property = aContent->GetProperty(nsGkAtoms::DisplayPort);
+  if (!property) {
+    return false;
+  }
+
+  if (aResult) {
+    *aResult = *static_cast<nsRect*>(property);
+  }
+  return true;
+}
 
 nsIFrame*
 nsLayoutUtils::GetLastContinuationWithChild(nsIFrame* aFrame)
 {
   NS_PRECONDITION(aFrame, "NULL frame pointer");
   aFrame = aFrame->GetLastContinuation();
   while (!aFrame->GetFirstChild(nsnull) &&
          aFrame->GetPrevContinuation()) {
@@ -1363,29 +1377,39 @@ nsLayoutUtils::PaintFrame(nsIRenderingCo
       aFlags &= ~PAINT_WIDGET_LAYERS;
       NS_ASSERTION(aRenderingContext, "need a rendering context");
     }
   }
 
   nsPresContext* presContext = aFrame->PresContext();
   nsIPresShell* presShell = presContext->PresShell();
 
+  nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame();
+  bool usingDisplayPort = false;
+  nsRect displayport;
+  if (rootScrollFrame) {
+    nsIContent* content = rootScrollFrame->GetContent();
+    if (content) {
+      usingDisplayPort = nsLayoutUtils::GetDisplayPort(content, &displayport);
+    }
+  }
+
   PRBool ignoreViewportScrolling = presShell->IgnoringViewportScrolling();
   nsRegion visibleRegion;
   if (aFlags & PAINT_WIDGET_LAYERS) {
     // This layer tree will be reused, so we'll need to calculate it
     // for the whole "visible" area of the window
     // 
     // |ignoreViewportScrolling| and |usingDisplayPort| are persistent
     // document-rendering state.  We rely on PresShell to flush
     // retained layers as needed when that persistent state changes.
-    if (!presShell->UsingDisplayPort()) {
+    if (!usingDisplayPort) {
       visibleRegion = aFrame->GetVisualOverflowRectRelativeToSelf();
     } else {
-      visibleRegion = presShell->GetDisplayPort();
+      visibleRegion = displayport;
     }
   } else {
     visibleRegion = aDirtyRegion;
   }
 
   // If we're going to display something different from what we'd normally
   // paint in a window then we will flush out any retained layer trees before
   // *and after* we draw.
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -90,16 +90,21 @@ public:
   static ViewID FindIDFor(nsIContent* aContent);
 
   /**
    * Find content for given ID.
    */
   static nsIContent* FindContentFor(ViewID aId);
 
   /**
+   * Get display port for the given element.
+   */
+  static bool GetDisplayPort(nsIContent* aContent, nsRect *aResult);
+
+  /**
    * Use heuristics to figure out the name of the child list that
    * aChildFrame is currently in.
    */
   static nsIAtom* GetChildListNameFor(nsIFrame* aChildFrame);
 
   /**
    * GetBeforeFrame returns the outermost :before frame of the given frame, if
    * one exists.  This is typically O(1).  The frame passed in must be
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -1032,36 +1032,33 @@ protected:
                                PRUint32    aFlags);
 
   friend struct AutoRenderingStateSaveRestore;
   friend struct RenderingState;
 
   struct RenderingState {
     RenderingState(PresShell* aPresShell) 
       : mRenderFlags(aPresShell->mRenderFlags)
-      , mDisplayPort(aPresShell->mDisplayPort)
       , mXResolution(aPresShell->mXResolution)
       , mYResolution(aPresShell->mYResolution)
     { }
     PRUint32 mRenderFlags;
-    nsRect mDisplayPort;
     float mXResolution;
     float mYResolution;
   };
 
   struct AutoSaveRestoreRenderingState {
     AutoSaveRestoreRenderingState(PresShell* aPresShell)
       : mPresShell(aPresShell)
       , mOldState(aPresShell)
     {}
 
     ~AutoSaveRestoreRenderingState()
     {
       mPresShell->mRenderFlags = mOldState.mRenderFlags;
-      mPresShell->mDisplayPort = mOldState.mDisplayPort;
       mPresShell->mXResolution = mOldState.mXResolution;
       mPresShell->mYResolution = mOldState.mYResolution;
     }
 
     PresShell* mPresShell;
     RenderingState mOldState;
   };
 
@@ -6012,24 +6009,17 @@ void PresShell::SetIgnoreViewportScrolli
   RenderingState state(this);
   state.mRenderFlags = ChangeFlag(state.mRenderFlags, aIgnore,
                                   STATE_IGNORING_VIEWPORT_SCROLLING);
   SetRenderingState(state);
 }
 
 void PresShell::SetDisplayPort(const nsRect& aDisplayPort)
 {
-  if (UsingDisplayPort() && mDisplayPort == aDisplayPort) {
-    return;
-  }
-  RenderingState state(this);
-  state.mRenderFlags = ChangeFlag(mRenderFlags, PR_TRUE,
-                                  STATE_USING_DISPLAYPORT);
-  state.mDisplayPort = aDisplayPort;
-  SetRenderingState(state);
+  NS_ABORT_IF_FALSE(false, "SetDisplayPort is deprecated");
 }
 
 nsresult PresShell::SetResolution(float aXResolution, float aYResolution)
 {
   if (!(aXResolution > 0.0 && aXResolution > 0.0)) {
     return NS_ERROR_ILLEGAL_VALUE;
   }
   if (aXResolution == mXResolution && aYResolution == mYResolution) {
@@ -6049,38 +6039,23 @@ void PresShell::SetRenderingState(const 
     // retained layers we might already have.
     LayerManager* manager = GetLayerManager();
     if (manager) {
       FrameLayerBuilder::InvalidateAllLayers(manager);
     }
   }
 
   mRenderFlags = aState.mRenderFlags;
-  if (UsingDisplayPort()) {
-    mDisplayPort = aState.mDisplayPort;
-  } else {
-    mDisplayPort = nsRect();
-  }
   mXResolution = aState.mXResolution;
   mYResolution = aState.mYResolution;
 
   nsIView* rootView;
   if (NS_SUCCEEDED(mViewManager->GetRootView(rootView)) && rootView) {
     rootView->SetInvalidationDimensions(&mDisplayPort);
   }
-
-  nsPresContext* rootPresContext = mPresContext->GetRootPresContext();
-  if (rootPresContext) {
-    nsIPresShell* rootPresShell = rootPresContext->GetPresShell();
-    nsIFrame* rootFrame = rootPresShell->FrameManager()->GetRootFrame();
-    if (rootFrame) {
-      rootFrame->InvalidateWithFlags(rootFrame->GetVisualOverflowRectRelativeToSelf(),
-                                     nsIFrame::INVALIDATE_NO_THEBES_LAYERS);
-    }
-  }
 }
 
 void PresShell::SynthesizeMouseMove(PRBool aFromScroll)
 {
   if (mViewManager && !mPaintingSuppressed && mIsActive) {
     mViewManager->SynthesizeMouseMove(aFromScroll);
   }
 }
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -1874,41 +1874,95 @@ 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);
   }
 
-  nsIPresShell* presShell = mOuter->PresContext()->GetPresShell();
-  nsRect scrollPort = (mIsRoot && presShell->UsingDisplayPort()) ?
-                      (presShell->GetDisplayPort()) : mScrollPort;
+  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, scrollPort);
+  dirtyRect.IntersectRect(aDirtyRect, mScrollPort);
+
+  if (usingDisplayPort) {
+    dirtyRect = displayport;
+  }
 
   nsDisplayListCollection set;
-  rv = mOuter->BuildDisplayListForChild(aBuilder, mScrolledFrame, dirtyRect, 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.
+  //
+  nsRect scrollRange = GetScrollRange();
+  PRBool buildingLayer =
+     (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) {
+    // Note that using StackingContext breaks z order, so the resulting
+    // rendering can be incorrect for weird edge cases!
+
+    rv = mScrolledFrame->BuildDisplayListForStackingContext(
+      aBuilder,
+      dirtyRect + mOuter->GetOffsetTo(mScrolledFrame),
+      set.Content()
+    );
+
+    nsDisplayScrollLayer* layerItem = new (aBuilder) nsDisplayScrollLayer(
+      aBuilder,
+      set.Content(),
+      mScrolledFrame,
+      mOuter,
+      displayport
+    );
+    set.Content()->AppendNewToTop(layerItem);
+  } else {
+    rv = mOuter->BuildDisplayListForChild(aBuilder, mScrolledFrame, dirtyRect, set);
+  }
+
   NS_ENSURE_SUCCESS(rv, rv);
   nsRect clip;
-  clip = scrollPort + aBuilder->ToReferenceFrame(mOuter);
+  clip = mScrollPort + aBuilder->ToReferenceFrame(mOuter);
 
   nscoord radii[8];
   // Our override of GetBorderRadii ensures we never have a radius at
   // the corners where we have a scrollbar.
   mOuter->GetPaddingBoxBorderRadii(radii);
+
   // mScrolledFrame may have given us a background, e.g., the scrolled canvas
   // frame below the viewport. If so, we want it to be clipped. We also want
   // to end up on our BorderBackground list.
   // If we are the viewport scrollframe, then clip all our descendants (to ensure
   // that fixed-pos elements get clipped by us).
   rv = mOuter->OverflowClip(aBuilder, set, aLists, clip, radii,
                             PR_TRUE, mIsRoot);
   NS_ENSURE_SUCCESS(rv, rv);
--- a/layout/generic/nsSubDocumentFrame.cpp
+++ b/layout/generic/nsSubDocumentFrame.cpp
@@ -335,42 +335,22 @@ nsSubDocumentFrame::BuildDisplayList(nsD
 
   nsPresContext* presContext = presShell->GetPresContext();
 
   nsDisplayList childItems;
 
   PRInt32 parentAPD = PresContext()->AppUnitsPerDevPixel();
   PRInt32 subdocAPD = presContext->AppUnitsPerDevPixel();
 
-  nsIFrame* subdocRootScrollFrame = presShell->GetRootScrollFrame();
-
   nsRect dirty;
   if (subdocRootFrame) {
-    if (presShell->UsingDisplayPort() && subdocRootScrollFrame) {
-      dirty = presShell->GetDisplayPort();
-
-      // The visual overflow rect of our viewport frame unfortunately may not
-      // intersect with the displayport of that frame. For example, the scroll
-      // offset of the frame may be (0, 0) so that the visual overflow rect
-      // is (0, 0, 800px, 500px) while the display port may have its top-left
-      // corner below y=500px.
-      //
-      // We have to force the frame to have a little faith and build a display
-      // list anyway. (see nsIFrame::BuildDisplayListForChild for the short-
-      // circuit code we are evading here).
-      //
-      subdocRootScrollFrame->AddStateBits(
-        NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO);
-
-    } else {
-      // get the dirty rect relative to the root frame of the subdoc
-      dirty = aDirtyRect + GetOffsetToCrossDoc(subdocRootFrame);
-      // and convert into the appunits of the subdoc
-      dirty = dirty.ConvertAppUnitsRoundOut(parentAPD, subdocAPD);
-    }
+    // get the dirty rect relative to the root frame of the subdoc
+    dirty = aDirtyRect + GetOffsetToCrossDoc(subdocRootFrame);
+    // and convert into the appunits of the subdoc
+    dirty = dirty.ConvertAppUnitsRoundOut(parentAPD, subdocAPD);
 
     aBuilder->EnterPresShell(subdocRootFrame, dirty);
   }
 
   // The subdocView's bounds are in appunits of the subdocument, so adjust
   // them.
   nsRect subdocBoundsInParentUnits =
     subdocView->GetBounds().ConvertAppUnitsRoundOut(subdocAPD, parentAPD);
@@ -420,42 +400,16 @@ nsSubDocumentFrame::BuildDisplayList(nsD
              bounds, NS_RGBA(0,0,0,0), flags);
     }
   }
 
   if (NS_SUCCEEDED(rv)) {
 
     bool addedLayer = false;
 
-#ifdef MOZ_IPC
-    // Make a scrollable layer in the child process so it can be manipulated
-    // with transforms in the parent process.
-    if (XRE_GetProcessType() == GeckoProcessType_Content) {
-      nsIScrollableFrame* scrollFrame = presShell->GetRootScrollFrameAsScrollable();
-
-      if (scrollFrame) {
-        NS_ASSERTION(subdocRootFrame, "Root scroll frame should be non-null");
-        nsRect scrollRange = scrollFrame->GetScrollRange();
-        
-        // Since making new layers is expensive, only use nsDisplayScrollLayer
-        // if the area is scrollable.
-        if (scrollRange.width != 0 || scrollRange.height != 0) {
-          addedLayer = true;
-          nsDisplayScrollLayer* layerItem = new (aBuilder) nsDisplayScrollLayer(
-            aBuilder,
-            &childItems,
-            subdocRootScrollFrame,
-            subdocRootFrame
-          );
-          childItems.AppendToTop(layerItem);
-        }
-      }
-    }
-#endif
-
     if (subdocRootFrame && parentAPD != subdocAPD) {
       NS_WARN_IF_FALSE(!addedLayer,
                        "Two container layers have been added. "
                        "Performance may suffer.");
       addedLayer = true;
 
       nsDisplayZoom* zoomItem =
         new (aBuilder) nsDisplayZoom(aBuilder, subdocRootFrame, &childItems,
--- a/layout/ipc/test-ipcbrowser-content.js
+++ b/layout/ipc/test-ipcbrowser-content.js
@@ -1,25 +1,30 @@
 function windowUtils() {
     return content.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
                .getInterface(Components.interfaces.nsIDOMWindowUtils);
 }
 
+function windowUtils20() {
+    return windowUtils()
+               .QueryInterface(Components.interfaces.nsIDOMWindowUtils_MOZILLA_2_0_BRANCH);
+}
+
 function recvSetViewport(w, h) {
 
     dump("setting viewport to "+ w +"x"+ h +"\n");
 
     windowUtils().setCSSViewport(w, h);
 }
 
 function recvSetDisplayPort(x, y, w, h) {
 
     dump("setting displayPort to <"+ x +", "+ y +", "+ w +", "+ h +">\n");
 
-    windowUtils().setDisplayPort(x, y, w, h);
+    windowUtils20().setDisplayPortForElement(x, y, w, h, content.document.documentElement);
 }
 
 function recvSetResolution(xres, yres) {
 
     dump("setting xres="+ xres +" yres="+ yres +"\n");
 
     windowUtils().setResolution(xres, yres);
 }
--- a/layout/tools/reftest/reftest-content.js
+++ b/layout/tools/reftest/reftest-content.js
@@ -115,16 +115,21 @@ function webNavigation() {
     return docShell.QueryInterface(CI.nsIWebNavigation);
 }
 
 function windowUtils() {
     return content.QueryInterface(CI.nsIInterfaceRequestor)
                   .getInterface(CI.nsIDOMWindowUtils);
 }
 
+function windowUtils20() {
+    return windowUtils()
+               .QueryInterface(Components.interfaces.nsIDOMWindowUtils_MOZILLA_2_0_BRANCH);
+}
+
 function IDForEventTarget(event)
 {
     try {
         return "'" + event.target.getAttribute('id') + "'";
     } catch (ex) {
         return "<unknown>";
     }
 }
@@ -248,17 +253,17 @@ function setupDisplayport(contentRootEle
         windowUtils().setCSSViewport(vw, vh);
     }
 
     // XXX support displayPortX/Y when needed
     var dpw = attrOrDefault("reftest-displayport-w", 0);
     var dph = attrOrDefault("reftest-displayport-h", 0);
     if (dpw !== 0 || dph !== 0) {
         LogInfo("Setting displayport to <x=0, y=0, w="+ dpw +", h="+ dph +">");
-        windowUtils().setDisplayPort(0, 0, dpw, dph);
+        windowUtils20().setDisplayPortForElement(0, 0, dpw, dph, content.document.documentElement);
     }
 
     // XXX support resolution when needed
 
     // XXX support viewconfig when needed
 }
 
 function resetDisplayport() {