Bug 618975 Pan overflow elements in parent process r=cjones r=tn sr=roc a=blocking-fennec
authorBenjamin Stover <bstover@mozilla.com>
Tue, 08 Mar 2011 21:28:18 -0800
changeset 63360 99f6b3acc464b2ca1d519de7a8c381def4005463
parent 63359 475ae5b4954071824abd78dc504996f03c859b7a
child 63361 3268032022693d48024c06c721ab88add032e1cb
push idunknown
push userunknown
push dateunknown
reviewerscjones, tn, roc, blocking-fennec
bugs618975
milestone2.0b13pre
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
--- 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,101 @@ 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->InvalidateFrameSubtree();
+    }
+  }
 
   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
@@ -1247,17 +1247,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,47 +6039,18 @@ 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;
-
-  // 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 = mPresContext->GetRootPresContext();
-  if (rootPresContext) {
-    nsIPresShell* rootPresShell = rootPresContext->GetPresShell();
-    nsIFrame* rootFrame = rootPresShell->FrameManager()->GetRootFrame();
-    if (rootFrame) {
-      rootFrame->InvalidateFrameSubtree();
-    }
-  }
 }
 
 void PresShell::SynthesizeMouseMove(PRBool aFromScroll)
 {
   if (mViewManager && !mPaintingSuppressed && mIsActive) {
     mViewManager->SynthesizeMouseMove(aFromScroll);
   }
 }
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -1858,41 +1858,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,