Bug 1421088 - Don't pass an nsIFrame* to DrawCheckboxOrRadio. r?spohl draft
authorMarkus Stange <mstange@themasta.com>
Thu, 30 Nov 2017 17:50:33 -0500
changeset 782225 958a6466b5e108f00960c6f339a3734479eef9a5
parent 782224 89b9dcf889ea3922e48afbea8b27a3be9c6d146f
child 782226 2ecf2682ed2b8f3e3b7ff55f261e1d8809ba5ccc
push id106503
push userbmo:mstange@themasta.com
push dateSun, 15 Apr 2018 02:35:01 +0000
reviewersspohl
bugs1421088
milestone61.0a1
Bug 1421088 - Don't pass an nsIFrame* to DrawCheckboxOrRadio. r?spohl MozReview-Commit-ID: 6LGIVGJAQ6W
widget/cocoa/nsNativeThemeCocoa.h
widget/cocoa/nsNativeThemeCocoa.mm
--- a/widget/cocoa/nsNativeThemeCocoa.h
+++ b/widget/cocoa/nsNativeThemeCocoa.h
@@ -48,16 +48,22 @@ public:
 
   enum class MenuIcon : uint8_t {
     eCheckmark,
     eMenuArrow,
     eMenuDownScrollArrow,
     eMenuUpScrollArrow
   };
 
+  enum class CheckboxOrRadioState : uint8_t {
+    eOff,
+    eOn,
+    eIndeterminate
+  };
+
   enum class ButtonType : uint8_t {
     eRegularPushButton,
     eDefaultPushButton,
     eRegularBevelButton,
     eDefaultBevelButton,
     eRoundedBezelPushButton,
     eSquareBezelPushButton,
     eArrowButton,
@@ -101,16 +107,22 @@ public:
   struct MenuItemParams {
     mozilla::Maybe<mozilla::gfx::Color> vibrancyColor;
     bool checked = false;
     bool disabled = false;
     bool selected = false;
     bool rtl = false;
   };
 
+  struct CheckboxOrRadioParams {
+    ControlParams controlParams;
+    CheckboxOrRadioState state = CheckboxOrRadioState::eOff;
+    float verticalAlignFactor = 0.5f;
+  };
+
   struct ButtonParams {
     ControlParams controlParams;
     ButtonType button = ButtonType::eRegularPushButton;
   };
 
   struct TreeHeaderCellParams {
     ControlParams controlParams;
     TreeSortDirection sortDirection = eTreeSortDirection_Natural;
@@ -203,18 +215,18 @@ protected:
                    mozilla::EventStates inState, nsIFrame* aFrame,
                    const SegmentedControlRenderSettings& aSettings);
   void DrawTabPanel(CGContextRef context, const HIRect& inBoxRect, nsIFrame* aFrame);
   void DrawScale(CGContextRef context, const HIRect& inBoxRect,
                  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);
+                           const HIRect& inBoxRect,
+                           const CheckboxOrRadioParams& aParams);
   void DrawSearchField(CGContextRef cgContext, const HIRect& inBoxRect,
                        nsIFrame* aFrame, mozilla::EventStates inState);
   void DrawRoundedBezelPushButton(CGContextRef cgContext,
                                   const HIRect& inBoxRect,
                                   ControlParams aControlParams);
   void DrawSquareBezelPushButton(CGContextRef cgContext,
                                  const HIRect& inBoxRect,
                                  ControlParams aControlParams);
--- a/widget/cocoa/nsNativeThemeCocoa.mm
+++ b/widget/cocoa/nsNativeThemeCocoa.mm
@@ -993,45 +993,51 @@ static const CellRenderSettings checkbox
     { // Yosemite
       {0, 1, 0, 0},     // mini
       {0, 1, 0, 1},     // small
       {0, 1, 0, 1}      // regular
     }
   }
 };
 
+static NSCellStateValue
+CellStateForCheckboxOrRadioState(nsNativeThemeCocoa::CheckboxOrRadioState aState)
+{
+  switch (aState) {
+    case nsNativeThemeCocoa::CheckboxOrRadioState::eOff:
+      return NSOffState;
+    case nsNativeThemeCocoa::CheckboxOrRadioState::eOn:
+      return NSOnState;
+    case nsNativeThemeCocoa::CheckboxOrRadioState::eIndeterminate:
+      return NSMixedState;
+  }
+}
+
 void
 nsNativeThemeCocoa::DrawCheckboxOrRadio(CGContextRef cgContext, bool inCheckbox,
-                                        const HIRect& inBoxRect, bool inSelected,
-                                        EventStates inState, nsIFrame* aFrame)
+                                        const HIRect& inBoxRect,
+                                        const CheckboxOrRadioParams& aParams)
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
 
   NSButtonCell *cell = inCheckbox ? mCheckboxCell : mRadioButtonCell;
-  NSCellStateValue state = inSelected ? NSOnState : NSOffState;
-
-  // Check if we have an indeterminate checkbox
-  if (inCheckbox && GetIndeterminate(aFrame))
-    state = NSMixedState;
-
-  [cell setEnabled:!IsDisabled(aFrame, inState)];
-  [cell setShowsFirstResponder:inState.HasState(NS_EVENT_STATE_FOCUS)];
-  [cell setState:state];
-  [cell setHighlighted:inState.HasAllStates(NS_EVENT_STATE_ACTIVE | NS_EVENT_STATE_HOVER)];
-  [cell setControlTint:(FrameIsInActiveWindow(aFrame) ? [NSColor currentControlTint] : NSClearControlTint)];
+  ApplyControlParamsToNSCell(aParams.controlParams, cell);
+
+  [cell setState:CellStateForCheckboxOrRadioState(aParams.state)];
+  [cell setControlTint:(aParams.controlParams.insideActiveWindow ? [NSColor currentControlTint] : NSClearControlTint)];
 
   // Ensure that the control is square.
   float length = std::min(inBoxRect.size.width, inBoxRect.size.height);
   HIRect drawRect = CGRectMake(inBoxRect.origin.x + (int)((inBoxRect.size.width - length) / 2.0f),
                                inBoxRect.origin.y + (int)((inBoxRect.size.height - length) / 2.0f),
                                length, length);
 
   DrawCellWithSnapping(cell, cgContext, drawRect,
                        inCheckbox ? checkboxSettings : radioSettings,
-                       VerticalAlignFactor(aFrame), mCellDrawView, NO);
+                       aParams.verticalAlignFactor, mCellDrawView, NO);
 
   NS_OBJC_END_TRY_ABORT_BLOCK;
 }
 
 static const CellRenderSettings searchFieldSettings = {
   {
     NSMakeSize(0, 16), // mini
     NSMakeSize(0, 19), // small
@@ -2716,18 +2722,27 @@ nsNativeThemeCocoa::DrawWidgetBackground
         SetCGContextFillColor(cgContext, kTooltipBackgroundColor);
         CGContextFillRect(cgContext, macRect);
       }
       break;
 
     case NS_THEME_CHECKBOX:
     case NS_THEME_RADIO: {
       bool isCheckbox = (aWidgetType == NS_THEME_CHECKBOX);
-      DrawCheckboxOrRadio(cgContext, isCheckbox, macRect, GetCheckedOrSelected(aFrame, !isCheckbox),
-                          eventState, aFrame);
+
+      CheckboxOrRadioParams params;
+      params.state = CheckboxOrRadioState::eOff;
+      if (isCheckbox && GetIndeterminate(aFrame)) {
+        params.state = CheckboxOrRadioState::eIndeterminate;
+      } else if (GetCheckedOrSelected(aFrame, !isCheckbox)) {
+        params.state = CheckboxOrRadioState::eOn;
+      }
+      params.controlParams = ComputeControlParams(aFrame, eventState);
+      params.verticalAlignFactor = VerticalAlignFactor(aFrame);
+      DrawCheckboxOrRadio(cgContext, isCheckbox, macRect, params);
     }
       break;
 
     case NS_THEME_BUTTON:
       if (IsDefaultButton(aFrame)) {
         // Check whether the default button is in a document that does not
         // match the :-moz-window-inactive pseudoclass. This activeness check
         // is different from the other "active window" checks in this file