Bug 1421088 - Change the API of DrawMenuIcon and add DrawMenuItem. r=spohl
authorMarkus Stange <mstange@themasta.com>
Sat, 14 Apr 2018 22:00:18 -0400
changeset 466936 9fdfc9fd39e5f719dce5a2eef1ed67104f59bf9a
parent 466935 7d5825e533547ce882c3a132b430211bb0b99359
child 466937 50dff2a5018ddd53d753cadad405978fa0a7ac04
push id9165
push userasasaki@mozilla.com
push dateThu, 26 Apr 2018 21:04:54 +0000
treeherdermozilla-beta@064c3804de2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersspohl
bugs1421088
milestone61.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1421088 - Change the API of DrawMenuIcon and add DrawMenuItem. r=spohl MozReview-Commit-ID: 3JedJfgx9pZ
widget/cocoa/nsNativeThemeCocoa.h
widget/cocoa/nsNativeThemeCocoa.mm
--- a/widget/cocoa/nsNativeThemeCocoa.h
+++ b/widget/cocoa/nsNativeThemeCocoa.h
@@ -41,16 +41,23 @@ public:
     eThemeGeometryTypeVibrantTitlebarDark,
     eThemeGeometryTypeTooltip,
     eThemeGeometryTypeSheet,
     eThemeGeometryTypeSourceList,
     eThemeGeometryTypeSourceListSelection,
     eThemeGeometryTypeActiveSourceListSelection
   };
 
+  enum class MenuIcon : uint8_t {
+    eCheckmark,
+    eMenuArrow,
+    eMenuDownScrollArrow,
+    eMenuUpScrollArrow
+  };
+
   enum class ButtonType : uint8_t {
     eRegularPushButton,
     eDefaultPushButton,
     eRegularBevelButton,
     eDefaultBevelButton,
     eRoundedBezelPushButton,
     eSquareBezelPushButton,
     eArrowButton,
@@ -78,16 +85,32 @@ public:
   };
 
   struct MenuBackgroundParams {
     mozilla::Maybe<mozilla::gfx::Color> vibrancyColor;
     bool disabled = false;
     bool submenuRightOfParent = false;
   };
 
+  struct MenuIconParams {
+    MenuIcon icon = MenuIcon::eCheckmark;
+    bool disabled = false;
+    bool insideActiveMenuItem = false;
+    bool centerHorizontally = false;
+    bool rtl = false;
+  };
+
+  struct MenuItemParams {
+    mozilla::Maybe<mozilla::gfx::Color> vibrancyColor;
+    bool checked = false;
+    bool disabled = false;
+    bool selected = false;
+    bool rtl = false;
+  };
+
   struct ButtonParams {
     ControlParams controlParams;
     ButtonType button = ButtonType::eRegularPushButton;
   };
 
   struct TreeHeaderCellParams {
     ControlParams controlParams;
     TreeSortDirection sortDirection = eTreeSortDirection_Natural;
@@ -156,16 +179,22 @@ protected:
   nsIFrame* SeparatorResponsibility(nsIFrame* aBefore, nsIFrame* aAfter);
   CGRect SeparatorAdjustedRect(CGRect aRect, nsIFrame* aLeft,
                                nsIFrame* aCurrent, nsIFrame* aRight);
   bool IsWindowSheet(nsIFrame* aFrame);
   ControlParams ComputeControlParams(nsIFrame* aFrame,
                                      mozilla::EventStates aEventState);
   MenuBackgroundParams ComputeMenuBackgroundParams(nsIFrame* aFrame,
                                                    mozilla::EventStates aEventState);
+  MenuIconParams ComputeMenuIconParams(nsIFrame* aParams,
+                                       mozilla::EventStates aEventState,
+                                       MenuIcon aIcon);
+  MenuItemParams ComputeMenuItemParams(nsIFrame* aFrame,
+                                       mozilla::EventStates aEventState,
+                                       bool aIsChecked);
   TreeHeaderCellParams ComputeTreeHeaderCellParams(nsIFrame* aFrame,
                                                    mozilla::EventStates aEventState);
 
   // HITheme drawing routines
   void DrawFrame(CGContextRef context, HIThemeFrameKind inKind,
                  const HIRect& inBoxRect, bool inReadOnly,
                  mozilla::EventStates inState);
   void DrawMeter(CGContextRef context, const HIRect& inBoxRect,
@@ -190,20 +219,22 @@ protected:
                                  const HIRect& inBoxRect,
                                  ControlParams aControlParams);
   void DrawHelpButton(CGContextRef cgContext, const HIRect& inBoxRect,
                       ControlParams aControlParams);
   void DrawDisclosureButton(CGContextRef cgContext, const HIRect& inBoxRect,
                             ControlParams aControlParams, NSCellStateValue aState);
   void DrawMenuBackground(CGContextRef cgContext, const CGRect& inBoxRect,
                           const MenuBackgroundParams& aParams);
+  NSString* GetMenuIconName(const MenuIconParams& aParams);
+  NSSize GetMenuIconSize(MenuIcon aIcon);
   void DrawMenuIcon(CGContextRef cgContext, const CGRect& aRect,
-                    mozilla::EventStates inState, nsIFrame* aFrame,
-                    const NSSize& aIconSize, NSString* aImageName,
-                    bool aCenterHorizontally);
+                    const MenuIconParams& aParams);
+  void DrawMenuItem(CGContextRef cgContext, const CGRect& inBoxRect,
+                    const MenuItemParams& aParams);
   void DrawHIThemeButton(CGContextRef cgContext, const HIRect& aRect,
                          ThemeButtonKind aKind, ThemeButtonValue aValue,
                          ThemeDrawState aState, ThemeButtonAdornment aAdornment,
                          const ControlParams& aParams);
   void DrawButton(CGContextRef context, const HIRect& inBoxRect,
                   const ButtonParams& aParams);
   void DrawTreeHeaderCell(CGContextRef context, const HIRect& inBoxRect,
                           const TreeHeaderCellParams& aParams);
--- a/widget/cocoa/nsNativeThemeCocoa.mm
+++ b/widget/cocoa/nsNativeThemeCocoa.mm
@@ -1220,42 +1220,88 @@ static const NSSize kMenuarrowSize = NSM
 static const NSSize kMenuScrollArrowSize = NSMakeSize(10, 8);
 static NSString* kCheckmarkImage = @"MenuOnState";
 static NSString* kMenuarrowRightImage = @"MenuSubmenu";
 static NSString* kMenuarrowLeftImage = @"MenuSubmenuLeft";
 static NSString* kMenuDownScrollArrowImage = @"MenuScrollDown";
 static NSString* kMenuUpScrollArrowImage = @"MenuScrollUp";
 static const CGFloat kMenuIconIndent = 6.0f;
 
+NSString*
+nsNativeThemeCocoa::GetMenuIconName(const MenuIconParams& aParams)
+{
+  switch (aParams.icon) {
+    case MenuIcon::eCheckmark:
+      return kCheckmarkImage;
+    case MenuIcon::eMenuArrow:
+      return aParams.rtl ? kMenuarrowLeftImage : kMenuarrowRightImage;
+    case MenuIcon::eMenuDownScrollArrow:
+      return kMenuDownScrollArrowImage;
+    case MenuIcon::eMenuUpScrollArrow:
+      return kMenuUpScrollArrowImage;
+  }
+}
+
+NSSize
+nsNativeThemeCocoa::GetMenuIconSize(MenuIcon aIcon)
+{
+  switch (aIcon) {
+    case MenuIcon::eCheckmark:
+      return kCheckmarkSize;
+    case MenuIcon::eMenuArrow:
+      return kMenuarrowSize;
+    case MenuIcon::eMenuDownScrollArrow:
+    case MenuIcon::eMenuUpScrollArrow:
+      return kMenuScrollArrowSize;
+  }
+}
+
+nsNativeThemeCocoa::MenuIconParams
+nsNativeThemeCocoa::ComputeMenuIconParams(nsIFrame* aFrame,
+                                          EventStates aEventState,
+                                          MenuIcon aIcon)
+{
+  bool isDisabled = IsDisabled(aFrame, aEventState);
+
+  MenuIconParams params;
+  params.icon = aIcon;
+  params.disabled = isDisabled;
+  params.insideActiveMenuItem =
+    !isDisabled && CheckBooleanAttr(aFrame, nsGkAtoms::menuactive);
+  params.centerHorizontally = true;
+  params.rtl = IsFrameRTL(aFrame);
+  return params;
+}
+
 void
 nsNativeThemeCocoa::DrawMenuIcon(CGContextRef cgContext, const CGRect& aRect,
-                                 EventStates inState, nsIFrame* aFrame,
-                                 const NSSize& aIconSize, NSString* aImageName,
-                                 bool aCenterHorizontally)
+                                 const MenuIconParams& aParams)
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
 
+  NSSize size = GetMenuIconSize(aParams.icon);
+
   // Adjust size and position of our drawRect.
-  CGFloat paddingX = std::max(CGFloat(0.0), aRect.size.width - aIconSize.width);
-  CGFloat paddingY = std::max(CGFloat(0.0), aRect.size.height - aIconSize.height);
+  CGFloat paddingX = std::max(CGFloat(0.0), aRect.size.width - size.width);
+  CGFloat paddingY = std::max(CGFloat(0.0), aRect.size.height - size.height);
   CGFloat paddingStartX = std::min(paddingX, kMenuIconIndent);
   CGFloat paddingEndX = std::max(CGFloat(0.0), paddingX - kMenuIconIndent);
   CGRect drawRect = CGRectMake(
-    aRect.origin.x + (aCenterHorizontally ? ceil(paddingX / 2) :
-                      IsFrameRTL(aFrame) ? paddingEndX : paddingStartX),
+    aRect.origin.x + (aParams.centerHorizontally ? ceil(paddingX / 2) :
+                      aParams.rtl ? paddingEndX : paddingStartX),
     aRect.origin.y + ceil(paddingY / 2),
-    aIconSize.width, aIconSize.height);
-
-  NSString* state = IsDisabled(aFrame, inState) ? @"disabled" :
-    (CheckBooleanAttr(aFrame, nsGkAtoms::menuactive) ? @"pressed" : @"normal");
-
-  NSString* imageName = aImageName;
+    size.width, size.height);
+
+  NSString* state = aParams.disabled ? @"disabled" :
+    (aParams.insideActiveMenuItem ? @"pressed" : @"normal");
+
+  NSString* imageName = GetMenuIconName(aParams);
   if (!nsCocoaFeatures::OnElCapitanOrLater()) {
     // Pre-10.11, image names are prefixed with "image."
-    imageName = [@"image." stringByAppendingString:aImageName];
+    imageName = [@"image." stringByAppendingString:imageName];
   }
 
   RenderWithCoreUI(drawRect, cgContext,
           [NSDictionary dictionaryWithObjectsAndKeys:
             @"kCUIBackgroundTypeMenu", @"backgroundTypeKey",
             imageName, @"imageNameKey",
             state, @"state",
             @"image", @"widget",
@@ -1265,16 +1311,77 @@ nsNativeThemeCocoa::DrawMenuIcon(CGConte
 #if DRAW_IN_FRAME_DEBUG
   CGContextSetRGBFillColor(cgContext, 0.0, 0.0, 0.5, 0.25);
   CGContextFillRect(cgContext, drawRect);
 #endif
 
   NS_OBJC_END_TRY_ABORT_BLOCK;
 }
 
+nsNativeThemeCocoa::MenuItemParams
+nsNativeThemeCocoa::ComputeMenuItemParams(nsIFrame* aFrame,
+                                          EventStates aEventState,
+                                          bool aIsChecked)
+{
+  bool isDisabled = IsDisabled(aFrame, aEventState);
+
+  MenuItemParams params;
+  if (VibrancyManager::SystemSupportsVibrancy()) {
+    ThemeGeometryType type =
+      ThemeGeometryTypeForWidget(aFrame, NS_THEME_MENUITEM);
+    params.vibrancyColor = Some(VibrancyFillColor(aFrame, type));
+  }
+  params.checked = aIsChecked;
+  params.disabled = isDisabled;
+  params.selected =
+    !isDisabled && CheckBooleanAttr(aFrame, nsGkAtoms::menuactive);
+  params.rtl = IsFrameRTL(aFrame);
+  return params;
+}
+
+static void
+SetCGContextFillColor(CGContextRef cgContext, const Color& aColor)
+{
+  CGContextSetRGBFillColor(cgContext, aColor.r, aColor.g, aColor.b, aColor.a);
+}
+
+void
+nsNativeThemeCocoa::DrawMenuItem(CGContextRef cgContext,
+                                 const CGRect& inBoxRect,
+                                 const MenuItemParams& aParams)
+{
+  if (aParams.vibrancyColor) {
+    SetCGContextFillColor(cgContext, *aParams.vibrancyColor);
+    CGContextFillRect(cgContext, inBoxRect);
+  } else {
+    HIThemeMenuItemDrawInfo drawInfo;
+    memset(&drawInfo, 0, sizeof(drawInfo));
+    drawInfo.version = 0;
+    drawInfo.itemType = kThemeMenuItemPlain;
+    drawInfo.state = (aParams.disabled ?
+                        static_cast<ThemeMenuState>(kThemeMenuDisabled) :
+                        aParams.selected ?
+                          static_cast<ThemeMenuState>(kThemeMenuSelected) :
+                          static_cast<ThemeMenuState>(kThemeMenuActive));
+
+    HIRect ignored;
+    HIThemeDrawMenuItem(&inBoxRect, &inBoxRect, &drawInfo, cgContext,
+                        HITHEME_ORIENTATION, &ignored);
+  }
+
+  if (aParams.checked) {
+    MenuIconParams params;
+    params.disabled = aParams.disabled;
+    params.insideActiveMenuItem = aParams.selected;
+    params.rtl = aParams.rtl;
+    params.icon = MenuIcon::eCheckmark;
+    DrawMenuIcon(cgContext, inBoxRect, params);
+  }
+}
+
 nsNativeThemeCocoa::ControlParams
 nsNativeThemeCocoa::ComputeControlParams(nsIFrame* aFrame, EventStates aEventState)
 {
   ControlParams params;
   params.disabled = IsDisabled(aFrame, aEventState);
   params.insideActiveWindow = FrameIsInActiveWindow(aFrame);
   params.pressed = aEventState.HasAllStates(NS_EVENT_STATE_ACTIVE | NS_EVENT_STATE_HOVER);
   params.focused = aEventState.HasState(NS_EVENT_STATE_FOCUS);
@@ -2451,22 +2558,16 @@ nsNativeThemeCocoa::IsParentScrollbarRol
 
 static bool
 IsHiDPIContext(nsDeviceContext* aContext)
 {
   return nsPresContext::AppUnitsPerCSSPixel() >=
     2 * aContext->AppUnitsPerDevPixelAtUnitFullZoom();
 }
 
-static void
-SetCGContextFillColor(CGContextRef cgContext, const Color& aColor)
-{
-  CGContextSetRGBFillColor(cgContext, aColor.r, aColor.g, aColor.b, aColor.a);
-}
-
 static const Color kTooltipBackgroundColor(0.996, 1.000, 0.792, 0.950);
 static const Color kMultilineTextFieldTopBorderColor(0.4510, 0.4510, 0.4510, 1.0);
 static const Color kMultilineTextFieldSidesAndBottomBorderColor(0.6, 0.6, 0.6, 1.0);
 static const Color kListboxTopBorderColor(0.557, 0.557, 0.557, 1.0);
 static const Color kListBoxSidesAndBottomBorderColor(0.745, 0.745, 0.745, 1.0);
 
 NS_IMETHODIMP
 nsNativeThemeCocoa::DrawWidgetBackground(gfxContext* aContext,
@@ -2565,51 +2666,27 @@ nsNativeThemeCocoa::DrawWidgetBackground
     }
       break;
 
     case NS_THEME_MENUPOPUP:
       DrawMenuBackground(cgContext, macRect,
                          ComputeMenuBackgroundParams(aFrame, eventState));
       break;
 
-    case NS_THEME_MENUARROW: {
-      bool isRTL = IsFrameRTL(aFrame);
-      DrawMenuIcon(cgContext, macRect, eventState, aFrame, kMenuarrowSize,
-                   isRTL ? kMenuarrowLeftImage : kMenuarrowRightImage, true);
-    }
+    case NS_THEME_MENUARROW:
+      DrawMenuIcon(cgContext, macRect,
+                   ComputeMenuIconParams(aFrame, eventState,
+                                         MenuIcon::eMenuArrow));
       break;
 
     case NS_THEME_MENUITEM:
-    case NS_THEME_CHECKMENUITEM: {
-      if (VibrancyManager::SystemSupportsVibrancy()) {
-        ThemeGeometryType type = ThemeGeometryTypeForWidget(aFrame, aWidgetType);
-        DrawVibrancyBackground(cgContext, macRect, aFrame, type);
-      } else {
-        bool isDisabled = IsDisabled(aFrame, eventState);
-        bool isSelected = !isDisabled && CheckBooleanAttr(aFrame, nsGkAtoms::menuactive);
-        // maybe use kThemeMenuItemHierBackground or PopUpBackground instead of just Plain?
-        HIThemeMenuItemDrawInfo drawInfo;
-        memset(&drawInfo, 0, sizeof(drawInfo));
-        drawInfo.version = 0;
-        drawInfo.itemType = kThemeMenuItemPlain;
-        drawInfo.state = (isDisabled ?
-                           static_cast<ThemeMenuState>(kThemeMenuDisabled) :
-                           isSelected ?
-                             static_cast<ThemeMenuState>(kThemeMenuSelected) :
-                             static_cast<ThemeMenuState>(kThemeMenuActive));
-
-        // XXX pass in the menu rect instead of always using the item rect
-        HIRect ignored;
-        HIThemeDrawMenuItem(&macRect, &macRect, &drawInfo, cgContext, HITHEME_ORIENTATION, &ignored);
-      }
-
-      if (aWidgetType == NS_THEME_CHECKMENUITEM) {
-        DrawMenuIcon(cgContext, macRect, eventState, aFrame, kCheckmarkSize, kCheckmarkImage, false);
-      }
-    }
+    case NS_THEME_CHECKMENUITEM:
+      DrawMenuItem(cgContext, macRect,
+                   ComputeMenuItemParams(aFrame, eventState,
+                                         aWidgetType == NS_THEME_CHECKMENUITEM));
       break;
 
     case NS_THEME_MENUSEPARATOR: {
       ThemeMenuState menuState;
       if (IsDisabled(aFrame, eventState)) {
         menuState = kThemeMenuDisabled;
       }
       else {
@@ -2618,20 +2695,23 @@ nsNativeThemeCocoa::DrawWidgetBackground
       }
 
       HIThemeMenuItemDrawInfo midi = { 0, kThemeMenuItemPlain, menuState };
       HIThemeDrawMenuSeparator(&macRect, &macRect, &midi, cgContext, HITHEME_ORIENTATION);
     }
       break;
 
     case NS_THEME_BUTTON_ARROW_UP:
-    case NS_THEME_BUTTON_ARROW_DOWN:
-      DrawMenuIcon(cgContext, macRect, eventState, aFrame, kMenuScrollArrowSize,
-                   aWidgetType == NS_THEME_BUTTON_ARROW_UP ?
-                   kMenuUpScrollArrowImage : kMenuDownScrollArrowImage, true);
+    case NS_THEME_BUTTON_ARROW_DOWN: {
+      MenuIcon icon =
+        aWidgetType == NS_THEME_BUTTON_ARROW_UP ? MenuIcon::eMenuUpScrollArrow
+                                                : MenuIcon::eMenuDownScrollArrow;
+      DrawMenuIcon(cgContext, macRect,
+                   ComputeMenuIconParams(aFrame, eventState, icon));
+    }
       break;
 
     case NS_THEME_TOOLTIP:
       if (VibrancyManager::SystemSupportsVibrancy()) {
         DrawVibrancyBackground(cgContext, macRect, aFrame, ThemeGeometryTypeForWidget(aFrame, aWidgetType));
       } else {
         SetCGContextFillColor(cgContext, kTooltipBackgroundColor);
         CGContextFillRect(cgContext, macRect);