Bug 1421088 - Split DrawPushButton into four functions and group the frame-dependent information into a struct. r?spohl draft
authorMarkus Stange <mstange@themasta.com>
Sat, 14 Apr 2018 21:13:10 -0400
changeset 782219 e6d041191beeda2788b0e26ad4b6aab6a5c31999
parent 782218 85dc8a3e1f3a92755039b31a68019ad6e1b3a077
child 782220 a3ca5dbf78bab09837db2a8831faaa8e5e39d9ff
push id106503
push userbmo:mstange@themasta.com
push dateSun, 15 Apr 2018 02:35:01 +0000
reviewersspohl
bugs1421088
milestone61.0a1
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;