Bug 1421088 - Change the API of DrawMenuIcon and add DrawMenuItem. r?spohl draft
authorMarkus Stange <mstange@themasta.com>
Sat, 14 Apr 2018 22:00:18 -0400
changeset 782224 89b9dcf889ea3922e48afbea8b27a3be9c6d146f
parent 782223 5656421d647e14f52730195444cae3d1bb1d4adc
child 782225 958a6466b5e108f00960c6f339a3734479eef9a5
push id106503
push userbmo:mstange@themasta.com
push dateSun, 15 Apr 2018 02:35:01 +0000
reviewersspohl
bugs1421088
milestone61.0a1
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);