Bug 618353 - Provide content with the ability to shrink the size of glass borders for glass windows and shrink the fx border by 2 pixels. r=felipe
authorJim Mathies <jmathies@mozilla.com>
Fri, 13 Jan 2012 09:10:05 -0600
changeset 85644 0ab265a621483849a275383f92ff80b3f8c35e73
parent 85643 9fdf008925cec4032b0bc8be859176e5d1ea3d4f
child 85645 63c3d103610c3febbd8dd20748c077a0b5935a03
push id805
push userakeybl@mozilla.com
push dateWed, 01 Feb 2012 18:17:35 +0000
treeherdermozilla-aurora@6fb3bf232436 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfelipe
bugs618353
milestone12.0a1
Bug 618353 - Provide content with the ability to shrink the size of glass borders for glass windows and shrink the fx border by 2 pixels. r=felipe
browser/base/content/browser.js
widget/windows/nsNativeThemeWin.cpp
widget/windows/nsWindow.cpp
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -5483,17 +5483,17 @@ function updateAppButtonDisplay() {
     !gInPrintPreviewMode &&
     window.menubar.visible &&
     document.getElementById("toolbar-menubar").getAttribute("autohide") == "true";
 
 #ifdef CAN_DRAW_IN_TITLEBAR
   document.getElementById("titlebar").hidden = !displayAppButton;
 
   if (displayAppButton)
-    document.documentElement.setAttribute("chromemargin", "0,-1,-1,-1");
+    document.documentElement.setAttribute("chromemargin", "0,2,2,2");
   else
     document.documentElement.removeAttribute("chromemargin");
 
   TabsInTitlebar.allowedBy("drawing-in-titlebar", displayAppButton);
 #else
   document.getElementById("appmenu-toolbar-button").hidden =
     !displayAppButton;
 #endif
--- a/widget/windows/nsNativeThemeWin.cpp
+++ b/widget/windows/nsNativeThemeWin.cpp
@@ -1798,18 +1798,19 @@ nsNativeThemeWin::GetWidgetPadding(nsDev
     }
     return true;
   }
 
   // Content padding
   if (aWidgetType == NS_THEME_WINDOW_TITLEBAR ||
       aWidgetType == NS_THEME_WINDOW_TITLEBAR_MAXIMIZED) {
     aResult->SizeTo(0, 0, 0, 0);
-    // Maximized windows have an offscreen offset equal to
-    // the border padding. (windows quirk)
+    // XXX Maximized windows have an offscreen offset equal to
+    // the border padding. This should be addressed in nsWindow,
+    // but currently can't be, see UpdateNonClientMargins.
     if (aWidgetType == NS_THEME_WINDOW_TITLEBAR_MAXIMIZED)
       aResult->top = GetSystemMetrics(SM_CXFRAME);
     return true;
   }
 
   if (!theme)
     return ClassicGetWidgetPadding(aContext, aFrame, aWidgetType, aResult);
 
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -336,20 +336,26 @@ static bool     gWindowsVisible         
 // True if we have sent a notification that we are suspending/sleeping.
 static bool     gIsSleepMode                      = false;
 
 static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID);
 
 // General purpose user32.dll hook object
 static WindowsDllInterceptor sUser32Intercept;
 
-// 2 pixel offset for eTransparencyBorderlessGlass which equals
-// the size of the default window border Windows paints.
+// 2 pixel offset for eTransparencyBorderlessGlass which equals the size of
+// the default window border Windows paints. Glass will be extended inward
+// this distance to remove the border.
 static const PRInt32 kGlassMarginAdjustment = 2;
 
+// When the client area is extended out into the default window frame area,
+// this is the minimum amount of space along the edge of resizable windows
+// we will always display a resize cursor in, regardless of the underlying
+// content.
+static const PRInt32 kResizableBorderMinSize = 3;
 
 // We should never really try to accelerate windows bigger than this. In some
 // cases this might lead to no D3D9 acceleration where we could have had it
 // but D3D9 does not reliably report when it supports bigger windows. 8192
 // is as safe as we can get, we know at least D3D10 hardware always supports
 // this, other hardware we expect to report correctly in D3D9.
 #define MAX_ACCELERATED_DIMENSION 8192
 
@@ -2026,59 +2032,101 @@ nsWindow::UpdateGetWindowInfoCaptionStat
 bool
 nsWindow::UpdateNonClientMargins(PRInt32 aSizeMode, bool aReflowWindow)
 {
   if (!mCustomNonClient)
     return false;
 
   mNonClientOffset.top = mNonClientOffset.bottom =
     mNonClientOffset.left = mNonClientOffset.right = 0;
+  mCaptionHeight = mVertResizeMargin = mHorResizeMargin = 0;
 
   if (aSizeMode == -1)
     aSizeMode = mSizeMode;
 
   if (aSizeMode == nsSizeMode_Minimized ||
       aSizeMode == nsSizeMode_Fullscreen) {
-    mCaptionHeight = mVertResizeMargin = mHorResizeMargin = 0;
     return true;
   }
 
-  // Note, for maximized windows, we need to continue to offset the client by
-  // thick frame margins of a normal window, since windows expects this
-  // in it's DwmDefWndProc hit testing.
-  mCaptionHeight = GetSystemMetrics(SM_CYCAPTION);
+  bool hasCaption = (mBorderStyle & (eBorderStyle_all |
+                                     eBorderStyle_title |
+                                     eBorderStyle_menu |
+                                     eBorderStyle_default)) > 0 ? true : false;
+
+  if (hasCaption)
+    mCaptionHeight = GetSystemMetrics(SM_CYCAPTION);
   mHorResizeMargin = GetSystemMetrics(SM_CXFRAME);
   mVertResizeMargin = GetSystemMetrics(SM_CYFRAME);
-
   mCaptionHeight += mVertResizeMargin;
 
-  // If a margin value is 0, set the offset to the default size of the frame.
-  // If a margin is -1, leave as default, and if a margin > 0, set the offset
-  // so that the frame size is equal to the margin value.
+  // Custom margin offset calculations for the chrome margin attribute on a
+  // window. The offsets calculated here are added to the client area in the
+  // WM_NCCALCSIZE event:
+  // -1 - leave the default frame in place
+  //  0 - remove the frame, our frame offset equals the default frame size
+  // >0 - frame size equals (default frame size - margin value) with the
+  //      restriction that the offset <= default frame size.
   if (!mNonClientMargins.top)
     mNonClientOffset.top = mCaptionHeight;
   else if (mNonClientMargins.top > 0)
-    mNonClientOffset.top = mCaptionHeight - mNonClientMargins.top;
+    mNonClientOffset.top = NS_MIN(mCaptionHeight, mNonClientMargins.top);
 
   if (!mNonClientMargins.left)
     mNonClientOffset.left = mHorResizeMargin;
   else if (mNonClientMargins.left > 0)
-    mNonClientOffset.left = mHorResizeMargin - mNonClientMargins.left;
+    mNonClientOffset.left = NS_MIN(mHorResizeMargin, mNonClientMargins.left);
  
   if (!mNonClientMargins.right)
     mNonClientOffset.right = mHorResizeMargin;
   else if (mNonClientMargins.right > 0)
-    mNonClientOffset.right = mHorResizeMargin - mNonClientMargins.right;
+    mNonClientOffset.right = NS_MIN(mHorResizeMargin, mNonClientMargins.right);
 
   if (!mNonClientMargins.bottom)
     mNonClientOffset.bottom = mVertResizeMargin;
   else if (mNonClientMargins.bottom > 0)
-    mNonClientOffset.bottom = mVertResizeMargin - mNonClientMargins.bottom;
+    mNonClientOffset.bottom = NS_MIN(mVertResizeMargin, mNonClientMargins.bottom);
+
+  // Disable chrome margins > 0 in two cases:
+  // - For non-glass desktops: The window frame is painted with textures that
+  //   require the entire space of the default frame. We allow a full frame or
+  //   no frame at all.
+  // - For maximized windows: Windows positions maximized windows such that the
+  //   outer bounds sit off screen a distance equal to the standard frame size.
+  if(!nsUXThemeData::CheckForCompositor() || aSizeMode == nsSizeMode_Maximized) {
+    if (mNonClientMargins.top > 0)
+      mNonClientOffset.top = 0;
+    if (mNonClientMargins.bottom > 0)
+      mNonClientOffset.bottom = 0;
+    if (mNonClientMargins.left > 0)
+      mNonClientOffset.left = 0;
+    if (mNonClientMargins.right > 0)
+      mNonClientOffset.right = 0;
+  }
 
   if (aSizeMode == nsSizeMode_Maximized) {
+    // For chrome margins = 0 on maximized windows, Windows places the bounds
+    // off screen a distance equal to the standard frame size. Remove this
+    // area from our expanded client area.
+    if (!mNonClientMargins.bottom)
+      mNonClientOffset.bottom = 0;
+    if (!mNonClientMargins.left)
+      mNonClientOffset.left = 0;
+    if (!mNonClientMargins.right)
+      mNonClientOffset.right = 0;
+
+    // This should be (mCaptionHeight - mVertResizeMargin). But if we offset
+    // the client area by just SM_CYCAPTION (placing the top of the client
+    // area level with the visible screen) Windows dwm def proc fails to pick
+    // up mouse hover and clicks on the glass control buttons. To compensate,
+    // we position the client area off screen by mVertResizeMargin, and add
+    // widget padding in nsNativeThemeWin::GetWidgetPadding().
+    if (!mNonClientMargins.top)
+      mNonClientOffset.top = mCaptionHeight;
+
     // Address an issue with auto-hide taskbars which fall behind the window.
     // Ensure a 1 pixel margin at the bottom of the monitor so that unhiding
     // the taskbar works properly.
     MONITORINFO info = {sizeof(MONITORINFO)};
     if (::GetMonitorInfo(::MonitorFromWindow(mWnd, MONITOR_DEFAULTTOPRIMARY),
                          &info)) {
       RECT r;
       if (::GetWindowRect(mWnd, &r)) {
@@ -5538,16 +5586,21 @@ BOOL CALLBACK nsWindow::BroadcastMsg(HWN
  * Special processing for certain event types and 
  * synthesized events.
  *
  **************************************************************/
 
 PRInt32
 nsWindow::ClientMarginHitTestPoint(PRInt32 mx, PRInt32 my)
 {
+  if (mSizeMode == nsSizeMode_Minimized ||
+      mSizeMode == nsSizeMode_Fullscreen) {
+    return HTCLIENT;
+  }
+
   // Calculations are done in screen coords
   RECT winRect;
   GetWindowRect(mWnd, &winRect);
 
   // hit return constants:
   // HTBORDER                     - non-resizable border
   // HTBOTTOM, HTLEFT, HTRIGHT, HTTOP - resizable border
   // HTBOTTOMLEFT, HTBOTTOMRIGHT  - resizable corner
@@ -5555,82 +5608,100 @@ nsWindow::ClientMarginHitTestPoint(PRInt
   // HTCAPTION                    - general title bar area
   // HTCLIENT                     - area considered the client
   // HTCLOSE                      - hovering over the close button
   // HTMAXBUTTON                  - maximize button
   // HTMINBUTTON                  - minimize button
 
   PRInt32 testResult = HTCLIENT;
 
+  bool isResizable = (mBorderStyle & (eBorderStyle_all |
+                                      eBorderStyle_resizeh |
+                                      eBorderStyle_default)) > 0 ? true : false;
+  if (mSizeMode == nsSizeMode_Maximized)
+    isResizable = false;
+
   bool top    = false;
   bool bottom = false;
   bool left   = false;
   bool right  = false;
 
-  if (my >= winRect.top && my <
-      (winRect.top + mVertResizeMargin + (mCaptionHeight - mNonClientOffset.top)))
+  int topOffset = NS_MAX(mCaptionHeight - mNonClientOffset.top,
+                         kResizableBorderMinSize);
+  int bottomOffset = NS_MAX(mVertResizeMargin - mNonClientOffset.bottom,
+                            kResizableBorderMinSize);
+  int topBounds = winRect.top + topOffset;
+  int bottomBounds = winRect.bottom - bottomOffset;
+
+  if (my >= winRect.top && my < topBounds)
     top = true;
-  else if (my < winRect.bottom && my >= (winRect.bottom - mVertResizeMargin))
+  else if (my <= winRect.bottom && my > bottomBounds)
     bottom = true;
 
-  if (mx >= winRect.left && mx < (winRect.left +
-                                  (bottom ? (2*mHorResizeMargin) : mHorResizeMargin)))
+  int leftOffset = NS_MAX(mHorResizeMargin - mNonClientOffset.left,
+                          kResizableBorderMinSize);
+  int rightOffset = NS_MAX(mHorResizeMargin - mNonClientOffset.right,
+                           kResizableBorderMinSize);
+  // (the 2x case here doubles the resize area for corners)
+  int leftBounds = winRect.left +
+                   (bottom ? (2*leftOffset) : leftOffset);
+  int rightBounds = winRect.right -
+                    (bottom ? (2*rightOffset) : rightOffset);
+
+  if (mx >= winRect.left && mx < leftBounds)
     left = true;
-  else if (mx < winRect.right && mx >= (winRect.right -
-                                        (bottom ? (2*mHorResizeMargin) : mHorResizeMargin)))
+  else if (mx <= winRect.right && mx > rightBounds)
     right = true;
 
-  if (top) {
-    testResult = HTTOP;
-    if (left)
-      testResult = HTTOPLEFT;
-    else if (right)
-      testResult = HTTOPRIGHT;
-  } else if (bottom) {
-    testResult = HTBOTTOM;
-    if (left)
-      testResult = HTBOTTOMLEFT;
-    else if (right)
-      testResult = HTBOTTOMRIGHT;
+  if (isResizable) {
+    if (top) {
+      testResult = HTTOP;
+      if (left)
+        testResult = HTTOPLEFT;
+      else if (right)
+        testResult = HTTOPRIGHT;
+    } else if (bottom) {
+      testResult = HTBOTTOM;
+      if (left)
+        testResult = HTBOTTOMLEFT;
+      else if (right)
+        testResult = HTBOTTOMRIGHT;
+    } else {
+      if (left)
+        testResult = HTLEFT;
+      if (right)
+        testResult = HTRIGHT;
+    }
   } else {
-    if (left)
-      testResult = HTLEFT;
-    if (right)
-      testResult = HTRIGHT;
+    if (top)
+      testResult = HTCAPTION;
+    else if (bottom || left || right)
+      testResult = HTBORDER;
   }
 
   bool contentOverlap = true;
 
-  if (mSizeMode == nsSizeMode_Maximized) {
-    // There's no HTTOP in maximized state (bug 575493)
-    if (testResult == HTTOP) {
-      testResult = HTCAPTION;
-    }
-  } else {
-    PRInt32 leftMargin   = mNonClientMargins.left   == -1 ? mHorResizeMargin  : mNonClientMargins.left;
-    PRInt32 rightMargin  = mNonClientMargins.right  == -1 ? mHorResizeMargin  : mNonClientMargins.right;
-    PRInt32 topMargin    = mNonClientMargins.top    == -1 ? mVertResizeMargin : mNonClientMargins.top;
-    PRInt32 bottomMargin = mNonClientMargins.bottom == -1 ? mVertResizeMargin : mNonClientMargins.bottom;
-
-    contentOverlap = mx >= winRect.left + leftMargin &&
-                     mx <= winRect.right - rightMargin &&
-                     my >= winRect.top + topMargin &&
-                     my <= winRect.bottom - bottomMargin;
+  if (mSizeMode != nsSizeMode_Maximized) {
+    contentOverlap = mx >= winRect.left + leftOffset &&
+                     mx <= winRect.right - rightOffset &&
+                     my >= winRect.top + topOffset &&
+                     my <= winRect.bottom - bottomOffset;
   }
 
   if (!sIsInMouseCapture &&
       contentOverlap &&
       (testResult == HTCLIENT ||
        testResult == HTTOP ||
+       testResult == HTBORDER ||
        testResult == HTTOPLEFT ||
        testResult == HTCAPTION)) {
     LPARAM lParam = MAKELPARAM(mx, my);
     LPARAM lParamClient = lParamToClient(lParam);
     bool result = DispatchMouseEvent(NS_MOUSE_MOZHITTEST, 0, lParamClient,
-                                       false, nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
+                                     false, nsMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
     if (result) {
       // The mouse is over a blank area
       testResult = testResult == HTCLIENT ? HTCAPTION : testResult;
 
     } else {
       // There's content over the mouse pointer. Set HTCLIENT
       // to possibly override a resizer border.
       testResult = HTCLIENT;