Bug 1442521 - Make width/height attr on <window> mean the inner size in nsXULWindow. r?smaug draft
authorXidorn Quan <me@upsuper.org>
Fri, 02 Mar 2018 22:42:57 +1100
changeset 762372 c5525f66a2cc2195e2caeda3784571655b9040ba
parent 762287 32a014591db37fae49e07ee3a1ca82cb84374983
push id101165
push userxquan@mozilla.com
push dateFri, 02 Mar 2018 11:43:32 +0000
reviewerssmaug
bugs1442521, 1439875
milestone60.0a1
Bug 1442521 - Make width/height attr on <window> mean the inner size in nsXULWindow. r?smaug It seems that the layout system assumes those attributes are for size of the <window> element, i.e. inner window size, not outer window size. See for example nsContainerFrame::SyncWindowProperties. It reads {min,max}{width,height} attributes from the element via nsIFrame::GetXUL{Min,Max}Size, and passes them into SetSizeConstraints. The latter inflates the sizes with window decoration size before calling into widget code. It can also be seen that various XUL size related methods on nsBox and nsIFrame put the same assumption. The test test_windowminmaxsize.xul apparently puts the same assumption as the layout system on the meaning of those properties. (Another test test_resize_move_windows.xul, which tests effectiveness of features of window.open, also fails if we size the window earlier than current in bug 1439875, and doesn't fail with this patch on top. It may indicate that it makes use of the same assumption, but I can't really figure out how it does so.) MozReview-Commit-ID: IdMwDc59Ltg
toolkit/content/tests/chrome/test_screenPersistence.xul
xpfe/appshell/nsXULWindow.cpp
--- a/toolkit/content/tests/chrome/test_screenPersistence.xul
+++ b/toolkit/content/tests/chrome/test_screenPersistence.xul
@@ -39,18 +39,18 @@
   }
   function checkTest2() {
     let runTime = Cc["@mozilla.org/xre/app-info;1"]
                     .getService(Ci.nsIXULRuntime);
     if (runTime.OS != "Linux") {
       is(win.screenX, 80, "The window should be placed now at x=80px");
       is(win.screenY, 80, "The window should be placed now at y=80px");
     }
-    is(win.outerHeight, 300, "The window size should be height=300px");
-    is(win.outerWidth, 300, "The window size should be width=300px");
+    is(win.innerHeight, 300, "The window size should be height=300px");
+    is(win.innerWidth, 300, "The window size should be width=300px");
     win.close();
     SimpleTest.finish();
   }
 ]]></script>
 
 <body xmlns="http://www.w3.org/1999/xhtml">
 <p id="display">
 </p>
--- a/xpfe/appshell/nsXULWindow.cpp
+++ b/xpfe/appshell/nsXULWindow.cpp
@@ -1059,37 +1059,55 @@ NS_IMETHODIMP nsXULWindow::ForceRoundedD
   SetPrimaryContentSize(targetContentWidth, targetContentHeight);
 
   mIgnoreXULSize = true;
   mIgnoreXULSizeMode = true;
 
   return NS_OK;
 }
 
+static LayoutDeviceIntSize
+GetWindowOuterInnerDiff(nsIWidget* aWindow)
+{
+  if (!aWindow) {
+    return LayoutDeviceIntSize();
+  }
+  LayoutDeviceIntSize baseSize(200, 200);
+  LayoutDeviceIntSize windowSize = aWindow->ClientToWindowSize(baseSize);
+  return windowSize - baseSize;
+}
+
 void nsXULWindow::OnChromeLoaded()
 {
   nsresult rv = EnsureContentTreeOwner();
 
   if (NS_SUCCEEDED(rv)) {
     mChromeLoaded = true;
     ApplyChromeFlags();
     SyncAttributesToWidget();
 
     int32_t specWidth = -1, specHeight = -1;
     bool gotSize = false;
     bool isContent = false;
 
     GetHasPrimaryContent(&isContent);
 
+    CSSIntSize windowDiff = mWindow
+      ? RoundedToInt(GetWindowOuterInnerDiff(mWindow) /
+                     mWindow->GetDefaultScale())
+      : CSSIntSize();
+
     // If this window has a primary content and fingerprinting resistance is
     // enabled, we enforce this window to rounded dimensions.
     if (isContent && nsContentUtils::ShouldResistFingerprinting()) {
       ForceRoundedDimensions();
     } else if (!mIgnoreXULSize) {
       gotSize = LoadSizeFromXUL(specWidth, specHeight);
+      specWidth += windowDiff.width;
+      specHeight += windowDiff.height;
     }
 
     bool positionSet = !mIgnoreXULPosition;
     nsCOMPtr<nsIXULWindow> parentWindow(do_QueryReferent(mParentWindow));
 #if defined(XP_UNIX) && !defined(XP_MACOSX)
     // don't override WM placement on unix for independent, top-level windows
     // (however, we think the benefits of intelligent dependent window placement
     // trump that override.)
@@ -1118,18 +1136,18 @@ void nsXULWindow::OnChromeLoaded()
         docShellAsItem->GetTreeOwner(getter_AddRefs(treeOwner));
         if (treeOwner) {
           // GetContentSize can fail, so initialise |width| and |height| to be
           // on the safe side.
           int32_t width = 0, height = 0;
           if (NS_SUCCEEDED(cv->GetContentSize(&width, &height))) {
             treeOwner->SizeShellTo(docShellAsItem, width, height);
             // Update specified size for the final LoadPositionFromXUL call.
-            specWidth = width;
-            specHeight = height;
+            specWidth = width + windowDiff.width;
+            specHeight = height + windowDiff.height;
           }
         }
       }
     }
 
     // Now that we have set the window's final size, we can re-do its
     // positioning so that it is properly constrained to the screen.
     if (positionSet) {
@@ -1653,27 +1671,30 @@ NS_IMETHODIMP nsXULWindow::SavePersisten
       if (shouldPersist) {
         IgnoredErrorResult err;
         ownerXULDoc->Persist(windowElementId, SCREENY_ATTRIBUTE, err);
       }
     }
   }
 
   if ((mPersistentAttributesDirty & PAD_SIZE) && gotRestoredBounds) {
+    LayoutDeviceIntSize winDiff = GetWindowOuterInnerDiff(mWindow);
     if (persistString.Find("width") >= 0) {
-      SprintfLiteral(sizeBuf, "%d", NSToIntRound(rect.Width() / sizeScale.scale));
+      auto width = rect.Width() - winDiff.width;
+      SprintfLiteral(sizeBuf, "%d", NSToIntRound(width / sizeScale.scale));
       CopyASCIItoUTF16(sizeBuf, sizeString);
       docShellElement->SetAttribute(WIDTH_ATTRIBUTE, sizeString, rv);
       if (shouldPersist) {
         IgnoredErrorResult err;
         ownerXULDoc->Persist(windowElementId, WIDTH_ATTRIBUTE, err);
       }
     }
     if (persistString.Find("height") >= 0) {
-      SprintfLiteral(sizeBuf, "%d", NSToIntRound(rect.Height() / sizeScale.scale));
+      auto height = rect.Height() - winDiff.height;
+      SprintfLiteral(sizeBuf, "%d", NSToIntRound(height / sizeScale.scale));
       CopyASCIItoUTF16(sizeBuf, sizeString);
       docShellElement->SetAttribute(HEIGHT_ATTRIBUTE, sizeString, rv);
       if (shouldPersist) {
         IgnoredErrorResult err;
         ownerXULDoc->Persist(windowElementId, HEIGHT_ATTRIBUTE, err);
       }
     }
   }