Bug 1255138 - Window resize support from JS for e10s. r=mconley a=ritu
authorGabor Krizsanits <gkrizsanits@mozilla.com>
Wed, 11 May 2016 11:44:57 +0200
changeset 332985 a0f48f447f41503a403053dc6f6b88a045a9d3a8
parent 332984 6dc895b3dea4e53ca1aaeaa2acb778512152588e
child 332986 dfe3d2e9bdbe8568c92f17789c6bebec119bdd3e
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-beta@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmconley, ritu
bugs1255138
milestone48.0a2
Bug 1255138 - Window resize support from JS for e10s. r=mconley a=ritu
dom/interfaces/base/nsITabChild.idl
dom/ipc/PBrowser.ipdl
dom/ipc/TabChild.cpp
dom/ipc/TabParent.cpp
dom/ipc/TabParent.h
dom/tests/mochitest/bugs/mochitest.ini
dom/tests/mochitest/bugs/test_resize_move_windows.html
dom/tests/mochitest/bugs/test_sizetocontent_clamp.html
embedding/browser/nsDocShellTreeOwner.cpp
embedding/browser/nsIEmbeddingSiteWindow.idl
xpfe/appshell/nsIXULWindow.idl
xpfe/appshell/nsXULWindow.cpp
--- a/dom/interfaces/base/nsITabChild.idl
+++ b/dom/interfaces/base/nsITabChild.idl
@@ -20,11 +20,14 @@ interface nsITabChild : nsISupports
   [notxpcom] void sendRequestFocus(in boolean canFocus);
 
   [notxpcom] void sendGetTabCount(out uint32_t tabCount);
 
   [noscript, notxpcom] void enableDisableCommands(in AString action,
                                                   in CommandsArrayRef enabledCommands,
                                                   in CommandsArrayRef disabledCommands);
 
+  [noscript] void remoteSizeShellTo(in int32_t width, in int32_t height,
+                                    in int32_t shellItemWidth, in int32_t shellItemHeight);
+
   readonly attribute uint64_t tabId;
 };
 
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -153,16 +153,31 @@ parent:
 
 parent:
     /**
      * When child sends this message, parent should move focus to
      * the next or previous focusable element or document.
      */
     async MoveFocus(bool forward, bool forDocumentNavigation);
 
+    /**
+     * SizeShellTo request propagation to parent.
+     *
+     * aFlag            Can indicate if one of the dimensions should be ignored.
+     *                  If only one dimension has changed it has to be indicated
+     *                  by the nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_* flags.
+     * aShellItemWidth,
+     * aShellItemHeight On parent side we won't be able to decide the dimensions
+     *                  of the shell item parameter in the original SizeShellTo
+     *                  call so we send over its dimensions that will be used
+     *                  for the actual resize.
+     **/
+    async SizeShellTo(uint32_t aFlag, int32_t aWidth, int32_t aHeight,
+                      int32_t aShellItemWidth, int32_t aShellItemHeight);
+
     async Event(RemoteDOMEvent aEvent);
 
     sync SyncMessage(nsString aMessage, ClonedMessageData aData,
                      CpowEntry[] aCpows, Principal aPrincipal)
       returns (StructuredCloneData[] retval);
 
     prio(high) sync RpcMessage(nsString aMessage, ClonedMessageData aData,
                                CpowEntry[] aCpows, Principal aPrincipal)
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -47,16 +47,17 @@
 #include "mozilla/StaticPtr.h"
 #include "mozilla/TextEvents.h"
 #include "mozilla/TouchEvents.h"
 #include "mozilla/unused.h"
 #include "mozIApplication.h"
 #include "nsContentUtils.h"
 #include "nsDocShell.h"
 #include "nsEmbedCID.h"
+#include "nsGlobalWindow.h"
 #include <algorithm>
 #ifdef MOZ_CRASHREPORTER
 #include "nsExceptionHandler.h"
 #endif
 #include "nsFilePickerProxy.h"
 #include "mozilla/dom/Element.h"
 #include "nsIBaseWindow.h"
 #include "nsIBrowserDOMWindow.h"
@@ -938,17 +939,40 @@ NS_IMETHODIMP
 TabChild::DestroyBrowserWindow()
 {
   NS_WARNING("TabChild::DestroyBrowserWindow not supported in TabChild");
 
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
-TabChild::SizeBrowserTo(int32_t aCX, int32_t aCY)
+TabChild::RemoteSizeShellTo(int32_t aWidth, int32_t aHeight,
+                            int32_t aShellItemWidth, int32_t aShellItemHeight)
+{
+  nsCOMPtr<nsIDocShell> ourDocShell = do_GetInterface(WebNavigation());
+  nsCOMPtr<nsIBaseWindow> docShellAsWin(do_QueryInterface(ourDocShell));
+  int32_t width, height;
+  docShellAsWin->GetSize(&width, &height);
+
+  uint32_t flags = 0;
+  if (width == aWidth) {
+    flags |= nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_CX;
+  }
+
+  if (height == aHeight) {
+    flags |= nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_CY;
+  }
+
+  bool sent = SendSizeShellTo(flags, aWidth, aHeight, aShellItemWidth, aShellItemHeight);
+
+  return sent ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+TabChild::SizeBrowserTo(int32_t aWidth, int32_t aHeight)
 {
   NS_WARNING("TabChild::SizeBrowserTo not supported in TabChild");
 
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 TabChild::ShowAsModal()
@@ -982,19 +1006,47 @@ TabChild::SetStatusWithContext(uint32_t 
   // mRemoteFrame is a good indicator.
   if (mRemoteFrame)
     SendSetStatus(aStatusType, nsString(aStatusText));
   return NS_OK;
 }
 
 NS_IMETHODIMP
 TabChild::SetDimensions(uint32_t aFlags, int32_t aX, int32_t aY,
-                             int32_t aCx, int32_t aCy)
+                        int32_t aCx, int32_t aCy)
 {
-  Unused << PBrowserChild::SendSetDimensions(aFlags, aX, aY, aCx, aCy);
+  // The parent is in charge of the dimension changes. If JS code wants to
+  // change the dimensions (moveTo, screenX, etc.) we send a message to the
+  // parent about the new requested dimension, the parent does the resize/move
+  // then send a message to the child to update itself. For APIs like screenX
+  // this function is called with the current value for the non-changed values.
+  // In a series of calls like window.screenX = 10; window.screenY = 10; for
+  // the second call, since screenX is not yet updated we might accidentally
+  // reset back screenX to it's old value. To avoid this if a parameter did not
+  // change we want the parent to ignore its value.
+  int32_t x, y, cx, cy;
+  GetDimensions(aFlags, &x, &y, &cx, &cy);
+
+  if (x == aX) {
+    aFlags |= nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_X;
+  }
+
+  if (y == aY) {
+    aFlags |= nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_Y;
+  }
+
+  if (cx == aCx) {
+    aFlags |= nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_CX;
+  }
+
+  if (cy == aCy) {
+    aFlags |= nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_CY;
+  }
+
+  Unused << SendSetDimensions(aFlags, aX, aY, aCx, aCy);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 TabChild::GetDimensions(uint32_t aFlags, int32_t* aX,
                              int32_t* aY, int32_t* aCx, int32_t* aCy)
 {
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -615,16 +615,47 @@ TabParent::RecvMoveFocus(const bool& aFo
     nsCOMPtr<nsIDOMElement> frame = do_QueryInterface(mFrameElement);
     fm->MoveFocus(nullptr, frame, type, nsIFocusManager::FLAG_BYKEY,
                   getter_AddRefs(dummy));
   }
   return true;
 }
 
 bool
+TabParent::RecvSizeShellTo(const uint32_t& aFlags, const int32_t& aWidth, const int32_t& aHeight,
+                           const int32_t& aShellItemWidth, const int32_t& aShellItemHeight)
+{
+  NS_ENSURE_TRUE(mFrameElement, true);
+
+  nsCOMPtr<nsIDocShell> docShell = mFrameElement->OwnerDoc()->GetDocShell();
+  NS_ENSURE_TRUE(docShell, true);
+
+  nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
+  nsresult rv = docShell->GetTreeOwner(getter_AddRefs(treeOwner));
+  NS_ENSURE_SUCCESS(rv, true);
+
+  int32_t width = aWidth;
+  int32_t height = aHeight;
+
+  if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_CX) {
+    width = mDimensions.width;
+  }
+
+  if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_CY) {
+    height = mDimensions.height;
+  }
+
+  nsCOMPtr<nsIXULWindow> xulWin(do_GetInterface(treeOwner));
+  NS_ENSURE_TRUE(xulWin, true);
+  xulWin->SizeShellToWithLimit(width, height, aShellItemWidth, aShellItemHeight);
+
+  return true;
+}
+
+bool
 TabParent::RecvEvent(const RemoteDOMEvent& aEvent)
 {
   nsCOMPtr<nsIDOMEvent> event = do_QueryInterface(aEvent.mEvent);
   NS_ENSURE_TRUE(event, true);
 
   nsCOMPtr<mozilla::dom::EventTarget> target = do_QueryInterface(mFrameElement);
   NS_ENSURE_TRUE(target, true);
 
@@ -809,29 +840,54 @@ TabParent::RecvSetDimensions(const uint3
   NS_ENSURE_TRUE(mFrameElement, true);
   nsCOMPtr<nsIDocShell> docShell = mFrameElement->OwnerDoc()->GetDocShell();
   NS_ENSURE_TRUE(docShell, true);
   nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
   docShell->GetTreeOwner(getter_AddRefs(treeOwner));
   nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = do_QueryInterface(treeOwner);
   NS_ENSURE_TRUE(treeOwnerAsWin, true);
 
+  // We only care about the parameters that actually changed, see more
+  // details in TabChild::SetDimensions.
+  int32_t unused;
+  int32_t x = aX;
+  if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_X) {
+    treeOwnerAsWin->GetPosition(&x, &unused);
+  }
+
+  int32_t y = aY;
+  if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_Y) {
+    treeOwnerAsWin->GetPosition(&unused, &y);
+  }
+
+  int32_t cx = aCx;
+  if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_CX) {
+    treeOwnerAsWin->GetSize(&cx, &unused);
+  }
+
+  int32_t cy = aCy;
+  if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_CY) {
+    treeOwnerAsWin->GetSize(&unused, &cy);
+  }
+
   if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION &&
       aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER) {
-    treeOwnerAsWin->SetPositionAndSize(aX, aY, aCx, aCy, true);
+    treeOwnerAsWin->SetPositionAndSize(x, y, cx, cy, true);
     return true;
   }
 
   if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION) {
-    treeOwnerAsWin->SetPosition(aX, aY);
+    treeOwnerAsWin->SetPosition(x, y);
+    mUpdatedDimensions = false;
+    UpdatePosition();
     return true;
   }
 
   if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER) {
-    treeOwnerAsWin->SetSize(aCx, aCy, true);
+    treeOwnerAsWin->SetSize(cx, cy, true);
     return true;
   }
 
   MOZ_ASSERT(false, "Unknown flags!");
   return false;
 }
 
 nsresult
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -156,16 +156,22 @@ public:
 
   void AddWindowListeners();
 
   void DidRefresh() override;
 
   virtual bool RecvMoveFocus(const bool& aForward,
                              const bool& aForDocumentNavigation) override;
 
+  virtual bool RecvSizeShellTo(const uint32_t& aFlags,
+                               const int32_t& aWidth,
+                               const int32_t& aHeight,
+                               const int32_t& aShellItemWidth,
+                               const int32_t& aShellItemHeight) override;
+
   virtual bool RecvEvent(const RemoteDOMEvent& aEvent) override;
 
   virtual bool RecvReplyKeyEvent(const WidgetKeyboardEvent& aEvent) override;
 
   virtual bool
   RecvDispatchAfterKeyboardEvent(const WidgetKeyboardEvent& aEvent) override;
 
   virtual bool RecvBrowserFrameOpenWindow(PBrowserParent* aOpener,
--- a/dom/tests/mochitest/bugs/mochitest.ini
+++ b/dom/tests/mochitest/bugs/mochitest.ini
@@ -155,18 +155,18 @@ skip-if = (buildapp == 'b2g' && toolkit 
 [test_bug927901.html]
 [test_devicemotion_multiple_listeners.html]
 skip-if = toolkit == 'android' #bug 775227
 [test_domparser_after_blank.html]
 [test_errorReporting.html]
 [test_onerror_message.html]
 [test_protochains.html]
 [test_resize_move_windows.html]
-skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s #Windows can't change size and position on Android # b2g(Windows can't change size and position on B2G) b2g-debug(Windows can't change size and position on B2G) b2g-desktop(Windows can't change size and position on B2G)
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || os == 'linux' #Windows can't change size and position on Android # b2g(Windows can't change size and position on B2G) b2g-debug(Windows can't change size and position on B2G) b2g-desktop(Windows can't change size and position on B2G)
 [test_sizetocontent_clamp.html]
-skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s #Windows can't change size on Android # b2g(Windows can't change size on B2G) b2g-debug(Windows can't change size on B2G) b2g-desktop(Windows can't change size on B2G)
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' #Windows can't change size on Android # b2g(Windows can't change size on B2G) b2g-debug(Windows can't change size on B2G) b2g-desktop(Windows can't change size on B2G)
 [test_toJSON.html]
 [test_window_bar.html]
 skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android'
 [test_bug1022869.html]
 [test_bug1112040.html]
 [test_bug1160342_marquee.html]
 [test_bug1171215.html]
--- a/dom/tests/mochitest/bugs/test_resize_move_windows.html
+++ b/dom/tests/mochitest/bugs/test_resize_move_windows.html
@@ -232,95 +232,86 @@ function checkChangeIsEnabled(aWindow, a
 
   function outerChangeCondition() {
     return aWindow.outerWidth != oWidth && aWindow.outerHeight != oHeight;
   }
 
   function outerChangeTest() {
     isnot(aWindow.outerWidth, oWidth, "Window outerWidth should have changed");
     isnot(aWindow.outerHeight, oHeight, "Window outerHeight should have changed");
-
-    aWindow.outerWidth = oWidth;
-    aWindow.outerHeight = oHeight;
   }
 
   /**
    * Size checks.
    */
   prevWidth = aWindow.innerWidth;
   prevHeight = aWindow.innerHeight;
-
   aWindow.innerWidth = getNewWidth(aWindow);
   aWindow.innerHeight = getNewHeight(aWindow);
 
   hitEventLoop(sizeChangeCondition, sizeChangeTest, hits)
   .then(function() {
     aWindow.resizeTo(getNewWidth(aWindow), getNewHeight(aWindow));
-  })
-  .then(function() {
     return hitEventLoop(sizeChangeCondition, sizeChangeTest, hits);
   })
   .then(function () {
     aWindow.resizeBy(getNewWidth(aWindow) - aWindow.innerWidth,
                      getNewHeight(aWindow) - aWindow.innerHeight);
-  })
-  .then(function() {
     return hitEventLoop(sizeChangeCondition, sizeChangeTest, hits);
   })
-  .then(function () {
-    prevWidth = aWindow.innerWidth = getNewWidth(aWindow);
-    prevHeight = aWindow.innerHeight = getNewHeight(aWindow);
+  .then(function() {
     aWindow.sizeToContent();
-  })
-  .then(function() {
-    hitEventLoop(sizeChangeCondition, sizeChangeTest, hits);
+    return hitEventLoop(sizeChangeCondition, sizeChangeTest, hits);
   })
   .then(function() {
     /**
      * Position checks.
      */
     prevX = aWindow.screenX;
     prevY = aWindow.screenY;
 
     aWindow.screenX = getNewX(aWindow);
     aWindow.screenY = getNewY(aWindow);
-  })
-  .then(function() {
     return hitEventLoop(posChangeCondition, posChangeTest, hits);
   })
   .then(function() {
     prevX = aWindow.screenX;
     prevY = aWindow.screenY;
 
     aWindow.moveTo(getNewX(aWindow), getNewY(aWindow));
-  })
-  .then(function() {
     return hitEventLoop(posChangeCondition, posChangeTest, hits);
   })
   .then(function() {
     prevX = aWindow.screenX;
     prevY = aWindow.screenY;
 
     aWindow.moveBy(getNewX(aWindow) - aWindow.screenX,
                    getNewY(aWindow) - aWindow.screenY);
-  })
-  .then(function() {
     return hitEventLoop(posChangeCondition, posChangeTest, hits);
   })
   .then(function() {
     /**
      * Outer width/height checks.
      */
     oWidth = aWindow.outerWidth;
     oHeight = aWindow.outerHeight;
 
     aWindow.outerWidth = oWidth * 2;
     aWindow.outerHeight = oHeight * 2;
+    return hitEventLoop(outerChangeCondition, outerChangeTest, hits);
   })
   .then(function() {
+    let origWidth = oWidth;
+    let origHeight = oHeight;
+
+    oWidth = aWindow.outerWidth;
+    oHeight = aWindow.outerHeight;
+
+    aWindow.outerWidth = origWidth;
+    aWindow.outerHeight = origHeight;
     return hitEventLoop(outerChangeCondition, outerChangeTest, hits);
   })
   .then(aNext);
 }
 
 SpecialPowers.pushPrefEnv({"set": [["dom.disable_window_move_resize", false]]}, function() {
 SimpleTest.waitForFocus(function() {
   if (screen.width <= 200 || screen.height <= 200) {
--- a/dom/tests/mochitest/bugs/test_sizetocontent_clamp.html
+++ b/dom/tests/mochitest/bugs/test_sizetocontent_clamp.html
@@ -30,35 +30,34 @@ var epsilon =  navigator.platform.indexO
 
 // Windows 8 has a minimum 122 pixel inner window width due to
 // outer window chrome.
 var isWin8 = (navigator.userAgent.indexOf("Windows NT 6.2") != -1);
 
 var innerWidthMin = (isWin8 ? 120 : 100);
 var innerWidthMax = (isWin8 ? 125 : 100);
 
+var isExecuted = false;
+
 function test() {
   var w = window.open('data:text/html,null', null, 'width=300,height=300');
-  var nbResize = 0;
 
   SimpleTest.waitForFocus(function() {
     w.onresize = function() {
-      nbResize++;
 
-      if (nbResize == 1) {
+      if (w.innerWidth > 300 - epsilon || isExecuted) {
         return;
       }
 
+      isExecuted = true;
+
       ok(w.innerWidth + epsilon >= innerWidthMin && w.innerWidth - epsilon <= innerWidthMax,
-         "innerWidth should be between " + innerWidthMin + " and " + innerWidthMax);
+         "innerWidth should be between " + innerWidthMin + " and " + innerWidthMax + " but it was: " + w.innerWidth);
       ok(w.innerHeight + epsilon >= 100 && w.innerHeight - epsilon <= 100,
-         "innerHeight should be around 100");
-
-      // It's not clear why 2 events are coming...
-      is(nbResize, 2, "We should get 2 events.");
+         "innerHeight should be around 100" + " but it was: " + w.innerHeight);
 
       w.close();
 
       SimpleTest.waitForFocus(function() {
         SimpleTest.finish();
       });
     };
     w.sizeToContent();
--- a/embedding/browser/nsDocShellTreeOwner.cpp
+++ b/embedding/browser/nsDocShellTreeOwner.cpp
@@ -52,16 +52,17 @@
 #include "nsIStringBundle.h"
 #include "nsPIDOMWindow.h"
 #include "nsPIWindowRoot.h"
 #include "nsIDOMWindowCollection.h"
 #include "nsIWindowWatcher.h"
 #include "nsPIWindowWatcher.h"
 #include "nsIPrompt.h"
 #include "nsITabParent.h"
+#include "nsITabChild.h"
 #include "nsRect.h"
 #include "nsIWebBrowserChromeFocus.h"
 #include "nsIContent.h"
 #include "imgIContainer.h"
 #include "nsContextMenuInfo.h"
 #include "nsPresContext.h"
 #include "nsViewManager.h"
 #include "nsView.h"
@@ -450,16 +451,29 @@ nsDocShellTreeOwner::SizeShellTo(nsIDocS
 
   NS_ENSURE_STATE(mTreeOwner || webBrowserChrome);
 
   if (mTreeOwner) {
     return mTreeOwner->SizeShellTo(aShellItem, aCX, aCY);
   }
 
   if (aShellItem == mWebBrowser->mDocShell) {
+    nsCOMPtr<nsITabChild> tabChild = do_QueryInterface(webBrowserChrome);
+    if (tabChild) {
+      // The XUL window to resize is in the parent process, but there we
+      // won't be able to get aShellItem to do the hack in nsXULWindow::SizeShellTo,
+      // so let's send the width and height of aShellItem too.
+      nsCOMPtr<nsIBaseWindow> shellAsWin(do_QueryInterface(aShellItem));
+      NS_ENSURE_TRUE(shellAsWin, NS_ERROR_FAILURE);
+
+      int32_t width = 0;
+      int32_t height = 0;
+      shellAsWin->GetSize(&width, &height);
+      return tabChild->RemoteSizeShellTo(aCX, aCY, width, height);
+    }
     return webBrowserChrome->SizeBrowserTo(aCX, aCY);
   }
 
   nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(aShellItem));
   NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE);
 
   nsCOMPtr<nsIDOMDocument> domDocument;
   webNav->GetDocument(getter_AddRefs(domDocument));
@@ -573,17 +587,18 @@ nsDocShellTreeOwner::GetDevicePixelsPerD
   *aScale = 1.0;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShellTreeOwner::SetPositionDesktopPix(int32_t aX, int32_t aY)
 {
   if (mWebBrowser) {
-    return mWebBrowser->SetPositionDesktopPix(aX, aY);
+    nsresult rv = mWebBrowser->SetPositionDesktopPix(aX, aY);
+    NS_ENSURE_SUCCESS(rv, rv);
   }
 
   double scale = 1.0;
   GetDevicePixelsPerDesktopPixel(&scale);
   return SetPosition(NSToIntRound(aX * scale), NSToIntRound(aY * scale));
 }
 
 NS_IMETHODIMP
--- a/embedding/browser/nsIEmbeddingSiteWindow.idl
+++ b/embedding/browser/nsIEmbeddingSiteWindow.idl
@@ -42,23 +42,55 @@ interface nsIEmbeddingSiteWindow : nsISu
      *
      * @see setDimensions
      * @see getDimensions
      * @see DIM_FLAGS_SIZE_INNER
      */
     const unsigned long DIM_FLAGS_SIZE_OUTER = 4;
 
     /**
+     * Flag indicates that the x parameter should be ignored.
+     *
+     * @see setDimensions
+     */
+    const unsigned long DIM_FLAGS_IGNORE_X = 8;
+
+    /**
+     * Flag indicates that the y parameter should be ignored.
+     *
+     * @see setDimensions
+     */
+    const unsigned long DIM_FLAGS_IGNORE_Y = 16;
+
+    /**
+     * Flag indicates that the cx parameter should be ignored.
+     *
+     * @see setDimensions
+     */
+    const unsigned long DIM_FLAGS_IGNORE_CX = 32;
+
+    /**
+     * Flag indicates that the cy parameter should be ignored.
+     *
+     * @see setDimensions
+     */
+    const unsigned long DIM_FLAGS_IGNORE_CY = 64;
+
+
+    /**
      * Sets the dimensions for the window; the position & size. The
      * flags to indicate what the caller wants to set and whether the size
      * refers to the inner or outer area. The inner area refers to just
      * the embedded area, wheras the outer area can also include any 
      * surrounding chrome, window frame, title bar, and so on.
      *
      * @param flags  Combination of position, inner and outer size flags.
+     *               The ignore flags are telling the parent to use the
+     *               current values for those dimensions and ignore the
+     *               corresponding parameters the child sends.
      * @param x      Left hand corner of the outer area.
      * @param y      Top corner of the outer area.
      * @param cx     Width of the inner or outer area.
      * @param cy     Height of the inner or outer area.
      *
      * @return <code>NS_OK</code> if operation was performed correctly;
      *         <code>NS_ERROR_UNEXPECTED</code> if window could not be
      *           destroyed;
--- a/xpfe/appshell/nsIXULWindow.idl
+++ b/xpfe/appshell/nsIXULWindow.idl
@@ -129,9 +129,18 @@ interface nsIXULWindow : nsISupports
 
   /**
    * Back-door method to force application of chrome flags at a particular
    * time.  Do NOT call this unless you know what you're doing!  In particular,
    * calling this when this XUL window doesn't yet have a document in its
    * docshell could cause problems.
    */
   [noscript] void applyChromeFlags();
+
+
+  /**
+   * Sometimes the child's nsDocShellTreeOwner needs to propogate a SizeShellTo call to the parent. But the
+   * shellItem argument of the call will not be available on the parent side, so we pass its dimensions here.
+   * Note: this is an internal method, other consumers should never call this.
+   */
+  [noscript, notxpcom] void sizeShellToWithLimit(in int32_t aCx, in int32_t aCy,
+                                                 in int32_t shellItemCx, in int32_t shellItemCy);
 };
--- a/xpfe/appshell/nsXULWindow.cpp
+++ b/xpfe/appshell/nsXULWindow.cpp
@@ -1810,32 +1810,17 @@ NS_IMETHODIMP nsXULWindow::SizeShellTo(n
 
   nsCOMPtr<nsIBaseWindow> shellAsWin(do_QueryInterface(aShellItem));
   NS_ENSURE_TRUE(shellAsWin, NS_ERROR_FAILURE);
 
   int32_t width = 0;
   int32_t height = 0;
   shellAsWin->GetSize(&width, &height);
 
-  int32_t widthDelta = aCX - width;
-  int32_t heightDelta = aCY - height;
-
-  if (widthDelta || heightDelta) {
-    int32_t winCX = 0;
-    int32_t winCY = 0;
-
-    GetSize(&winCX, &winCY);
-    // There's no point in trying to make the window smaller than the
-    // desired docshell size --- that's not likely to work. This whole
-    // function assumes that the outer docshell is adding some constant
-    // "border" chrome to aShellItem.
-    winCX = std::max(winCX + widthDelta, aCX);
-    winCY = std::max(winCY + heightDelta, aCY);
-    SetSize(winCX, winCY, true);
-  }
+  SizeShellToWithLimit(aCX, aCY, width, height);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP nsXULWindow::ExitModalLoop(nsresult aStatus)
 {
   if (mContinueModalLoop)
     EnableParent(true);
@@ -2191,16 +2176,37 @@ NS_IMETHODIMP nsXULWindow::GetXULBrowser
 }
 
 NS_IMETHODIMP nsXULWindow::SetXULBrowserWindow(nsIXULBrowserWindow * aXULBrowserWindow)
 {
   mXULBrowserWindow = aXULBrowserWindow;
   return NS_OK;
 }
 
+void nsXULWindow::SizeShellToWithLimit(int32_t aCX, int32_t aCY,
+                                       int32_t shellItemCx, int32_t shellItemCy)
+{
+  int32_t widthDelta = aCX - shellItemCx;
+  int32_t heightDelta = aCY - shellItemCy;
+
+  if (widthDelta || heightDelta) {
+    int32_t winCX = 0;
+    int32_t winCY = 0;
+
+    GetSize(&winCX, &winCY);
+    // There's no point in trying to make the window smaller than the
+    // desired docshell size --- that's not likely to work. This whole
+    // function assumes that the outer docshell is adding some constant
+    // "border" chrome to aShellItem.
+    winCX = std::max(winCX + widthDelta, aCX);
+    winCY = std::max(winCY + heightDelta, aCY);
+    SetSize(winCX, winCY, true);
+  }
+}
+
 //*****************************************************************************
 //*** nsContentShellInfo: Object Management
 //*****************************************************************************   
 
 nsContentShellInfo::nsContentShellInfo(const nsAString& aID,
                                        nsIWeakReference* aContentShell)
   : id(aID),
     child(aContentShell)