Bug 1421088 - Don't pass an nsIFrame* to DrawMeter. r?spohl draft
authorMarkus Stange <mstange@themasta.com>
Thu, 30 Nov 2017 18:59:27 -0500
changeset 782251 a1ecc026e5772f0e17d25c498a2cc979c3bcd942
parent 782250 7e319dffa6547425dd228aa038ea7cc669008345
child 782252 7e837f64d6870f413c0ad4efea2b1b354e645d8a
push id106506
push userbmo:mstange@themasta.com
push dateSun, 15 Apr 2018 03:32:46 +0000
reviewersspohl
bugs1421088
milestone61.0a1
Bug 1421088 - Don't pass an nsIFrame* to DrawMeter. r?spohl MozReview-Commit-ID: 63ZuRb6VRSY
widget/cocoa/nsNativeThemeCocoa.h
widget/cocoa/nsNativeThemeCocoa.mm
--- a/widget/cocoa/nsNativeThemeCocoa.h
+++ b/widget/cocoa/nsNativeThemeCocoa.h
@@ -79,16 +79,22 @@ public:
     eDown
   };
 
   enum class SegmentType : uint8_t {
     eToolbarButton,
     eTab
   };
 
+  enum class OptimumState : uint8_t {
+    eOptimum,
+    eSubOptimum,
+    eSubSubOptimum
+  };
+
   struct ControlParams {
     ControlParams()
       : disabled(false)
       , insideActiveWindow(false)
       , pressed(false)
       , focused(false)
       , rtl(false)
     {}
@@ -181,16 +187,26 @@ public:
     double max = 0.0;
     float verticalAlignFactor = 0.5f;
     bool insideActiveWindow = false;
     bool indeterminate = false;
     bool horizontal = false;
     bool rtl = false;
   };
 
+  struct MeterParams {
+    double value = 0;
+    double min = 0;
+    double max = 0;
+    OptimumState optimumState = OptimumState::eOptimum;
+    float verticalAlignFactor = 0.5f;
+    bool horizontal = true;
+    bool rtl = false;
+  };
+
   struct TreeHeaderCellParams {
     ControlParams controlParams;
     TreeSortDirection sortDirection = eTreeSortDirection_Natural;
     bool lastTreeHeaderCell = false;
   };
 
   nsNativeThemeCocoa();
 
@@ -265,24 +281,25 @@ protected:
   SegmentParams ComputeSegmentParams(nsIFrame* aFrame,
                                      mozilla::EventStates aEventState,
                                      SegmentType aSegmentType);
   SearchFieldParams ComputeSearchFieldParams(nsIFrame* aFrame,
                                              mozilla::EventStates aEventState);
   ProgressParams ComputeProgressParams(nsIFrame* aFrame,
                                        mozilla::EventStates aEventState,
                                        bool aIsHorizontal);
+  MeterParams ComputeMeterParams(nsIFrame* aFrame);
   TreeHeaderCellParams ComputeTreeHeaderCellParams(nsIFrame* aFrame,
                                                    mozilla::EventStates aEventState);
 
   // HITheme drawing routines
   void DrawTextBox(CGContextRef context, const HIRect& inBoxRect,
                    TextBoxParams aParams);
   void DrawMeter(CGContextRef context, const HIRect& inBoxRect,
-                 nsIFrame* aFrame);
+                 const MeterParams& aParams);
   void DrawSegment(CGContextRef cgContext, const HIRect& inBoxRect,
                    const SegmentParams& aParams);
   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,
--- a/widget/cocoa/nsNativeThemeCocoa.mm
+++ b/widget/cocoa/nsNativeThemeCocoa.mm
@@ -2166,66 +2166,78 @@ static const CellRenderSettings meterSet
     { // Yosemite
       {1, 1, 1, 1},     // mini
       {1, 1, 1, 1},     // small
       {1, 1, 1, 1}      // regular
     }
   }
 };
 
-void
-nsNativeThemeCocoa::DrawMeter(CGContextRef cgContext, const HIRect& inBoxRect,
-                              nsIFrame* aFrame)
+nsNativeThemeCocoa::MeterParams
+nsNativeThemeCocoa::ComputeMeterParams(nsIFrame* aFrame)
 {
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK
-
-  NS_PRECONDITION(aFrame, "aFrame should not be null here!");
-
-  // When using -moz-meterbar on an non meter element, we will not be able to
-  // get all the needed information so we just draw an empty meter.
   nsIContent* content = aFrame->GetContent();
   if (!(content && content->IsHTMLElement(nsGkAtoms::meter))) {
-    DrawCellWithSnapping(mMeterBarCell, cgContext, inBoxRect,
-                         meterSetting, VerticalAlignFactor(aFrame),
-                         mCellDrawView, IsFrameRTL(aFrame));
-    return;
+    return MeterParams();
   }
 
   HTMLMeterElement* meterElement = static_cast<HTMLMeterElement*>(content);
-  double value = meterElement->Value();
-  double min = meterElement->Min();
-  double max = meterElement->Max();
+  MeterParams params;
+  params.value = meterElement->Value();
+  params.min = meterElement->Min();
+  params.max = meterElement->Max();
+  EventStates states = meterElement->State();
+  if (states.HasState(NS_EVENT_STATE_SUB_OPTIMUM)) {
+    params.optimumState = OptimumState::eSubOptimum;
+  } else if (states.HasState(NS_EVENT_STATE_SUB_SUB_OPTIMUM)) {
+    params.optimumState = OptimumState::eSubSubOptimum;
+  }
+  params.horizontal = !IsVerticalMeter(aFrame);
+  params.verticalAlignFactor = VerticalAlignFactor(aFrame);
+  params.rtl = IsFrameRTL(aFrame);
+
+  return params;
+}
+
+void
+nsNativeThemeCocoa::DrawMeter(CGContextRef cgContext, const HIRect& inBoxRect,
+                              const MeterParams& aParams)
+{
+  NS_OBJC_BEGIN_TRY_ABORT_BLOCK
 
   NSLevelIndicatorCell* cell = mMeterBarCell;
 
-  [cell setMinValue:min];
-  [cell setMaxValue:max];
-  [cell setDoubleValue:value];
+  [cell setMinValue:aParams.min];
+  [cell setMaxValue:aParams.max];
+  [cell setDoubleValue:aParams.value];
 
   /**
    * The way HTML and Cocoa defines the meter/indicator widget are different.
    * So, we are going to use a trick to get the Cocoa widget showing what we
    * are expecting: we set the warningValue or criticalValue to the current
    * value when we want to have the widget to be in the warning or critical
    * state.
    */
-  EventStates states = aFrame->GetContent()->AsElement()->State();
-
-  // Reset previously set warning and critical values.
-  [cell setWarningValue:max+1];
-  [cell setCriticalValue:max+1];
-
-  if (states.HasState(NS_EVENT_STATE_SUB_OPTIMUM)) {
-    [cell setWarningValue:value];
-  } else if (states.HasState(NS_EVENT_STATE_SUB_SUB_OPTIMUM)) {
-    [cell setCriticalValue:value];
+  switch (aParams.optimumState) {
+    case OptimumState::eOptimum:
+      [cell setWarningValue:aParams.max+1];
+      [cell setCriticalValue:aParams.max+1];
+      break;
+    case OptimumState::eSubOptimum:
+      [cell setWarningValue:aParams.value];
+      [cell setCriticalValue:aParams.max+1];
+      break;
+    case OptimumState::eSubSubOptimum:
+      [cell setWarningValue:aParams.max+1];
+      [cell setCriticalValue:aParams.value];
+      break;
   }
 
   HIRect rect = CGRectStandardize(inBoxRect);
-  BOOL vertical = IsVerticalMeter(aFrame);
+  BOOL vertical = !aParams.horizontal;
 
   CGContextSaveGState(cgContext);
 
   if (vertical) {
     /**
      * Cocoa doesn't provide a vertical meter bar so to show one, we have to
      * show a rotated horizontal meter bar.
      * Given that we want to show a vertical meter bar, we assume that the rect
@@ -2242,18 +2254,18 @@ nsNativeThemeCocoa::DrawMeter(CGContextR
     rect.origin.y += rect.size.width / 2.f - rect.size.height / 2.f;
 
     CGContextTranslateCTM(cgContext, CGRectGetMidX(rect), CGRectGetMidY(rect));
     CGContextRotateCTM(cgContext, -M_PI / 2.f);
     CGContextTranslateCTM(cgContext, -CGRectGetMidX(rect), -CGRectGetMidY(rect));
   }
 
   DrawCellWithSnapping(cell, cgContext, rect,
-                       meterSetting, VerticalAlignFactor(aFrame),
-                       mCellDrawView, !vertical && IsFrameRTL(aFrame));
+                       meterSetting, aParams.verticalAlignFactor,
+                       mCellDrawView, !vertical && aParams.rtl);
 
   CGContextRestoreGState(cgContext);
 
   NS_OBJC_END_TRY_ABORT_BLOCK
 }
 
 void
 nsNativeThemeCocoa::DrawTabPanel(CGContextRef cgContext, const HIRect& inBoxRect,
@@ -3031,17 +3043,17 @@ nsNativeThemeCocoa::DrawWidgetBackground
     }
 
     case NS_THEME_PROGRESSBAR_VERTICAL:
       DrawProgress(cgContext, macRect,
                    ComputeProgressParams(aFrame, eventState, false));
       break;
 
     case NS_THEME_METERBAR:
-      DrawMeter(cgContext, macRect, aFrame);
+      DrawMeter(cgContext, macRect, ComputeMeterParams(aFrame));
       break;
 
     case NS_THEME_PROGRESSCHUNK:
     case NS_THEME_PROGRESSCHUNK_VERTICAL:
     case NS_THEME_METERCHUNK:
       // Do nothing: progress and meter bars cases will draw chunks.
       break;