Bug 911409 - Properly handle rendering menu arrows on high-dpi displays on Windows. r=tabraldes, a=sledru
authorJim Mathies <jmathies@mozilla.com>
Mon, 05 May 2014 13:32:54 -0500
changeset 199092 b5b9227aad535b96689651b4550117bda30f7f58
parent 199091 d6e35353153e6bc94f91d3eeb6536e0c476b2477
child 199093 9a05f477124d834285040dbbf3e6d8d05271c0d3
push id3624
push userasasaki@mozilla.com
push dateMon, 09 Jun 2014 21:49:01 +0000
treeherdermozilla-beta@b1a5da15899a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstabraldes, sledru
bugs911409
milestone31.0a2
Bug 911409 - Properly handle rendering menu arrows on high-dpi displays on Windows. r=tabraldes, a=sledru
widget/windows/nsNativeThemeWin.cpp
--- a/widget/windows/nsNativeThemeWin.cpp
+++ b/widget/windows/nsNativeThemeWin.cpp
@@ -1770,19 +1770,53 @@ RENDER_AGAIN:
     RECT sepRect = widgetRect;
     if (IsFrameRTL(aFrame))
       sepRect.right -= gutterSize.cx;
     else
       sepRect.left += gutterSize.cx;
 
     DrawThemeBackground(theme, hdc, MENU_POPUPSEPARATOR, /* state */ 0, &sepRect, &clipRect);
   }
+  else if (aWidgetType == NS_THEME_MENUARROW)
+  {
+    // We're dpi aware and as such on systems that have dpi > 96 set, the
+    // theme library expects us to do proper positioning and scaling of glyphs.
+    // For NS_THEME_MENUARROW, layout may hand us a widget rect larger than the
+    // glyph rect we request in GetMinimumWidgetSize. To prevent distortion we
+    // have to position and scale what we draw.
+
+    SIZE glyphSize;
+    GetThemePartSize(theme, hdc, part, state, nullptr, TS_TRUE, &glyphSize);
+
+    int32_t widgetHeight = widgetRect.bottom - widgetRect.top;
+
+    RECT renderRect = widgetRect;
+
+    // We request (glyph width * 2, glyph height) in GetMinimumWidgetSize. In
+    // Firefox some menu items provide the full height of the item to us, in
+    // others our widget rect is the exact dims of our arrow glyph. Adjust the
+    // vertical position by the added space, if any exists.
+    renderRect.top += ((widgetHeight - glyphSize.cy) / 2);
+    renderRect.bottom = renderRect.top + glyphSize.cy;
+    // I'm using the width of the arrow glyph for the arrow-side padding.
+    // AFAICT there doesn't appear to be a theme constant we can query
+    // for this value. Generally this looks correct, and has the added
+    // benefit of being a dpi adjusted value.
+    if (!IsFrameRTL(aFrame)) {
+      renderRect.right = widgetRect.right - glyphSize.cx;
+      renderRect.left = renderRect.right - glyphSize.cx;
+    } else {
+      renderRect.left = glyphSize.cx;
+      renderRect.right = renderRect.left + glyphSize.cx;
+    }
+    DrawThemeBGRTLAware(theme, hdc, part, state, &renderRect, &clipRect,
+                        IsFrameRTL(aFrame));
+  }
   // The following widgets need to be RTL-aware
-  else if (aWidgetType == NS_THEME_MENUARROW ||
-           aWidgetType == NS_THEME_RESIZER ||
+  else if (aWidgetType == NS_THEME_RESIZER ||
            aWidgetType == NS_THEME_DROPDOWN_BUTTON)
   {
     DrawThemeBGRTLAware(theme, hdc, part, state,
                         &widgetRect, &clipRect, IsFrameRTL(aFrame));
   }
   else if (aWidgetType == NS_THEME_PROGRESSBAR ||
            aWidgetType == NS_THEME_PROGRESSBAR_VERTICAL) {
     // DrawThemeBackground renders each corner with a solid white pixel.
@@ -2234,21 +2268,16 @@ nsNativeThemeWin::GetMinimumWidgetSize(n
         aResult->width = boxSize.cx+2;
         aResult->height = boxSize.cy;
         *aIsOverridable = false;
       }
 
     case NS_THEME_MENUITEMTEXT:
       return NS_OK;
 
-    case NS_THEME_MENUARROW:
-      aResult->width = 26;
-      aResult->height = 16;
-      return NS_OK;
-
     case NS_THEME_PROGRESSBAR:
     case NS_THEME_PROGRESSBAR_VERTICAL:
       // Best-fit size for progress meters is too large for most 
       // themes. We want these widgets to be able to really shrink
       // down, so use the min-size request value (of 0).
       sizeReq = TS_MIN; 
       break;
 
@@ -2398,16 +2427,24 @@ nsNativeThemeWin::GetMinimumWidgetSize(n
       break;
 
     case NS_THEME_MENUSEPARATOR:
     {
       SIZE gutterSize(GetGutterSize(theme, hdc));
       aResult->width += gutterSize.cx;
       break;
     }
+
+    case NS_THEME_MENUARROW:
+    {
+      // Use the width of the arrow glyph as padding. See the drawing
+      // code for details.
+      aResult->width *= 2;
+      break;
+    }
   }
 
   ::ReleaseDC(nullptr, hdc);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsNativeThemeWin::WidgetStateChanged(nsIFrame* aFrame, uint8_t aWidgetType,