Bug 1421088 - Split DrawPushButton into four functions and group the frame-dependent information into a struct. r=spohl
authorMarkus Stange <mstange@themasta.com>
Sat, 14 Apr 2018 21:13:10 -0400
changeset 466931 03a6d5b78824286d1af0f847a1dbab4152cab892
parent 466930 3718eabad30ea80c67a183ae379b94ee8710764a
child 466932 bb00ac312fd2ebab88fbc7edd89b7f66c396798e
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 - Split DrawPushButton into four functions and group the frame-dependent information into a struct. r=spohl MozReview-Commit-ID: COs3yaGTqMv
widget/cocoa/nsNativeThemeCocoa.h
widget/cocoa/nsNativeThemeCocoa.mm
--- a/widget/cocoa/nsNativeThemeCocoa.h
+++ b/widget/cocoa/nsNativeThemeCocoa.h
@@ -41,16 +41,32 @@ public:
     eThemeGeometryTypeVibrantTitlebarDark,
     eThemeGeometryTypeTooltip,
     eThemeGeometryTypeSheet,
     eThemeGeometryTypeSourceList,
     eThemeGeometryTypeSourceListSelection,
     eThemeGeometryTypeActiveSourceListSelection
   };
 
+  struct ControlParams {
+    ControlParams()
+      : disabled(false)
+      , insideActiveWindow(false)
+      , pressed(false)
+      , focused(false)
+      , rtl(false)
+    {}
+
+    bool disabled : 1;
+    bool insideActiveWindow : 1;
+    bool pressed : 1;
+    bool focused : 1;
+    bool rtl : 1;
+  };
+
   nsNativeThemeCocoa();
 
   NS_DECL_ISUPPORTS_INHERITED
 
   // The nsITheme interface.
   NS_IMETHOD DrawWidgetBackground(gfxContext* aContext,
                                   nsIFrame* aFrame,
                                   uint8_t aWidgetType,
@@ -104,16 +120,18 @@ public:
 protected:
   virtual ~nsNativeThemeCocoa();
 
   nsIntMargin DirectionAwareMargin(const nsIntMargin& aMargin, nsIFrame* aFrame);
   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);
 
   // HITheme drawing routines
   void DrawFrame(CGContextRef context, HIThemeFrameKind inKind,
                  const HIRect& inBoxRect, bool inReadOnly,
                  mozilla::EventStates inState);
   void DrawMeter(CGContextRef context, const HIRect& inBoxRect,
                  nsIFrame* aFrame);
   void DrawSegment(CGContextRef cgContext, const HIRect& inBoxRect,
@@ -124,19 +142,26 @@ protected:
                  mozilla::EventStates inState, bool inDirection,
                  bool inIsReverse, int32_t inCurrentValue, int32_t inMinValue,
                  int32_t inMaxValue, nsIFrame* aFrame);
   void DrawCheckboxOrRadio(CGContextRef cgContext, bool inCheckbox,
                            const HIRect& inBoxRect, bool inSelected,
                            mozilla::EventStates inState, nsIFrame* aFrame);
   void DrawSearchField(CGContextRef cgContext, const HIRect& inBoxRect,
                        nsIFrame* aFrame, mozilla::EventStates inState);
-  void DrawPushButton(CGContextRef cgContext, const HIRect& inBoxRect,
-                      mozilla::EventStates inState, uint8_t aWidgetType,
-                      nsIFrame* aFrame, float aOriginalHeight);
+  void DrawRoundedBezelPushButton(CGContextRef cgContext,
+                                  const HIRect& inBoxRect,
+                                  ControlParams aControlParams);
+  void DrawSquareBezelPushButton(CGContextRef cgContext,
+                                 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 DrawMenuIcon(CGContextRef cgContext, const CGRect& aRect,
                     mozilla::EventStates inState, nsIFrame* aFrame,
                     const NSSize& aIconSize, NSString* aImageName,
                     bool aCenterHorizontally);
   void DrawButton(CGContextRef context, ThemeButtonKind inKind,
                   const HIRect& inBoxRect, bool inIsDefault, 
                   ThemeButtonValue inValue, ThemeButtonAdornment inAdornment,
                   mozilla::EventStates inState, nsIFrame* aFrame);
--- a/widget/cocoa/nsNativeThemeCocoa.mm
+++ b/widget/cocoa/nsNativeThemeCocoa.mm
@@ -934,16 +934,26 @@ static float VerticalAlignFactor(nsIFram
       return 1.0f;
 
     default:
       NS_NOTREACHED("invalid vertical-align");
       return 0.5f;
   }
 }
 
+static void
+ApplyControlParamsToNSCell(nsNativeThemeCocoa::ControlParams aControlParams, NSCell* aCell)
+{
+  [aCell setEnabled:!aControlParams.disabled];
+  [aCell setShowsFirstResponder:(aControlParams.focused &&
+                                 !aControlParams.disabled &&
+                                 aControlParams.insideActiveWindow)];
+  [aCell setHighlighted:aControlParams.pressed];
+}
+
 // These are the sizes that Gecko needs to request to draw if it wants
 // to get a standard-sized Aqua radio button drawn. Note that the rects
 // that draw these are actually a little bigger.
 static const CellRenderSettings radioSettings = {
   {
     NSMakeSize(11, 11), // mini
     NSMakeSize(13, 13), // small
     NSMakeSize(16, 16)  // regular
@@ -1152,16 +1162,28 @@ 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::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);
+  params.rtl = IsFrameRTL(aFrame);
+  return params;
+}
+
 static const NSSize kHelpButtonSize = NSMakeSize(20, 20);
 static const NSSize kDisclosureButtonSize = NSMakeSize(21, 21);
 
 static const CellRenderSettings pushButtonSettings = {
   {
     NSMakeSize(0, 16), // mini
     NSMakeSize(0, 19), // small
     NSMakeSize(0, 22)  // regular
@@ -1186,67 +1208,72 @@ static const CellRenderSettings pushButt
 };
 
 // The height at which we start doing square buttons instead of rounded buttons
 // Rounded buttons look bad if drawn at a height greater than 26, so at that point
 // we switch over to doing square buttons which looks fine at any size.
 #define DO_SQUARE_BUTTON_HEIGHT 26
 
 void
-nsNativeThemeCocoa::DrawPushButton(CGContextRef cgContext, const HIRect& inBoxRect,
-                                   EventStates inState, uint8_t aWidgetType,
-                                   nsIFrame* aFrame, float aOriginalHeight)
+nsNativeThemeCocoa::DrawRoundedBezelPushButton(CGContextRef cgContext,
+                                               const HIRect& inBoxRect,
+                                               ControlParams aControlParams)
+{
+  NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
+
+  ApplyControlParamsToNSCell(aControlParams, mPushButtonCell);
+  [mPushButtonCell setBezelStyle:NSRoundedBezelStyle];
+  DrawCellWithSnapping(mPushButtonCell, cgContext, inBoxRect, pushButtonSettings,
+                       0.5f, mCellDrawView, aControlParams.rtl, 1.0f);
+
+  NS_OBJC_END_TRY_ABORT_BLOCK;
+}
+
+void
+nsNativeThemeCocoa::DrawSquareBezelPushButton(CGContextRef cgContext,
+                                              const HIRect& inBoxRect,
+                                              ControlParams aControlParams)
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
 
-  BOOL isActive = FrameIsInActiveWindow(aFrame);
-  BOOL isDisabled = IsDisabled(aFrame, inState);
-
-  NSButtonCell* cell = (aWidgetType == NS_THEME_BUTTON) ? mPushButtonCell :
-    (aWidgetType == NS_THEME_MAC_HELP_BUTTON) ? mHelpButtonCell : mDisclosureButtonCell;
-  [cell setEnabled:!isDisabled];
-  [cell setHighlighted:isActive &&
-                       inState.HasAllStates(NS_EVENT_STATE_ACTIVE | NS_EVENT_STATE_HOVER)];
-  [cell setShowsFirstResponder:inState.HasState(NS_EVENT_STATE_FOCUS) && !isDisabled && isActive];
-
-  if (aWidgetType != NS_THEME_BUTTON) { // Help button or disclosure button.
-    NSSize buttonSize = NSMakeSize(0, 0);
-    if (aWidgetType == NS_THEME_MAC_HELP_BUTTON) {
-      buttonSize = kHelpButtonSize;
-    } else { // Disclosure button.
-      buttonSize = kDisclosureButtonSize;
-      [cell setState:(aWidgetType == NS_THEME_MAC_DISCLOSURE_BUTTON_CLOSED) ? NSOffState : NSOnState];
-    }
-
-    DrawCellWithScaling(cell, cgContext, inBoxRect, NSRegularControlSize,
-                        NSZeroSize, buttonSize, NULL, mCellDrawView,
-                        false); // Don't mirror icon in RTL.
-  } else {
-    // If the button is tall enough, draw the square button style so that
-    // buttons with non-standard content look good. Otherwise draw normal
-    // rounded aqua buttons.
-    // This comparison is done based on the height that is calculated without
-    // the top, because the snapped height can be affected by the top of the
-    // rect and that may result in different height depending on the top value.
-    if (aOriginalHeight > DO_SQUARE_BUTTON_HEIGHT) {
-      [cell setBezelStyle:NSShadowlessSquareBezelStyle];
-      DrawCellWithScaling(cell, cgContext, inBoxRect, NSRegularControlSize,
-                          NSZeroSize, NSMakeSize(14, 0), NULL, mCellDrawView,
-                          IsFrameRTL(aFrame));
-    } else {
-      [cell setBezelStyle:NSRoundedBezelStyle];
-      DrawCellWithSnapping(cell, cgContext, inBoxRect, pushButtonSettings, 0.5f,
-                           mCellDrawView, IsFrameRTL(aFrame), 1.0f);
-    }
-  }
-
-#if DRAW_IN_FRAME_DEBUG
-  CGContextSetRGBFillColor(cgContext, 0.0, 0.0, 0.5, 0.25);
-  CGContextFillRect(cgContext, inBoxRect);
-#endif
+  ApplyControlParamsToNSCell(aControlParams, mPushButtonCell);
+  [mPushButtonCell setBezelStyle:NSShadowlessSquareBezelStyle];
+  DrawCellWithScaling(mPushButtonCell, cgContext, inBoxRect, NSRegularControlSize,
+                      NSZeroSize, NSMakeSize(14, 0), NULL, mCellDrawView,
+                      aControlParams.rtl);
+
+  NS_OBJC_END_TRY_ABORT_BLOCK;
+}
+
+void
+nsNativeThemeCocoa::DrawHelpButton(CGContextRef cgContext, const HIRect& inBoxRect,
+                                   ControlParams aControlParams)
+{
+  NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
+
+  ApplyControlParamsToNSCell(aControlParams, mHelpButtonCell);
+  DrawCellWithScaling(mHelpButtonCell, cgContext, inBoxRect, NSRegularControlSize,
+                      NSZeroSize, kHelpButtonSize, NULL, mCellDrawView,
+                      false); // Don't mirror icon in RTL.
+
+  NS_OBJC_END_TRY_ABORT_BLOCK;
+}
+
+void
+nsNativeThemeCocoa::DrawDisclosureButton(CGContextRef cgContext, const HIRect& inBoxRect,
+                                         ControlParams aControlParams,
+                                         NSCellStateValue aCellState)
+{
+  NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
+
+  ApplyControlParamsToNSCell(aControlParams, mDisclosureButtonCell);
+  [mDisclosureButtonCell setState:aCellState];
+  DrawCellWithScaling(mDisclosureButtonCell, cgContext, inBoxRect, NSRegularControlSize,
+                      NSZeroSize, kDisclosureButtonSize, NULL, mCellDrawView,
+                      false); // Don't mirror icon in RTL.
 
   NS_OBJC_END_TRY_ABORT_BLOCK;
 }
 
 void
 nsNativeThemeCocoa::DrawFocusOutline(CGContextRef cgContext, const HIRect& inBoxRect,
                                      EventStates inState, uint8_t aWidgetType,
                                      nsIFrame* aFrame)
@@ -2488,31 +2515,47 @@ nsNativeThemeCocoa::DrawWidgetBackground
         if (!IsDisabled(aFrame, eventState) && isInActiveWindow &&
             !QueueAnimatedContentForRefresh(aFrame->GetContent(), 10)) {
           NS_WARNING("Unable to animate button!");
         }
         DrawButton(cgContext, kThemePushButton, macRect, isInActiveWindow,
                    kThemeButtonOff, kThemeAdornmentNone, eventState, aFrame);
       } else if (IsButtonTypeMenu(aFrame)) {
         DrawDropdown(cgContext, macRect, eventState, aWidgetType, aFrame);
+      } else if (nativeWidgetHeight > DO_SQUARE_BUTTON_HEIGHT) {
+        // If the button is tall enough, draw the square button style so that
+        // buttons with non-standard content look good. Otherwise draw normal
+        // rounded aqua buttons.
+        // This comparison is done based on the height that is calculated without
+        // the top, because the snapped height can be affected by the top of the
+        // rect and that may result in different height depending on the top value.
+        DrawSquareBezelPushButton(cgContext, macRect,
+                                  ComputeControlParams(aFrame, eventState));
       } else {
-        DrawPushButton(cgContext, macRect, eventState, aWidgetType, aFrame,
-                       nativeWidgetHeight);
+        DrawRoundedBezelPushButton(cgContext, macRect,
+                                   ComputeControlParams(aFrame, eventState));
       }
       break;
 
     case NS_THEME_FOCUS_OUTLINE:
       DrawFocusOutline(cgContext, macRect, eventState, aWidgetType, aFrame);
       break;
 
     case NS_THEME_MAC_HELP_BUTTON:
+      DrawHelpButton(cgContext, macRect,
+                     ComputeControlParams(aFrame, eventState));
+      break;
+
     case NS_THEME_MAC_DISCLOSURE_BUTTON_OPEN:
-    case NS_THEME_MAC_DISCLOSURE_BUTTON_CLOSED:
-      DrawPushButton(cgContext, macRect, eventState, aWidgetType, aFrame,
-                     nativeWidgetHeight);
+    case NS_THEME_MAC_DISCLOSURE_BUTTON_CLOSED: {
+      NSCellStateValue value = (aWidgetType == NS_THEME_MAC_DISCLOSURE_BUTTON_CLOSED)
+        ? NSOffState : NSOnState;
+      DrawDisclosureButton(cgContext, macRect,
+                           ComputeControlParams(aFrame, eventState), value);
+    }
       break;
 
     case NS_THEME_BUTTON_BEVEL:
       DrawButton(cgContext, kThemeMediumBevelButton, macRect,
                  IsDefaultButton(aFrame), kThemeButtonOff, kThemeAdornmentNone,
                  eventState, aFrame);
       break;