1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #ifndef nsNativeThemeCocoa_h_
7 #define nsNativeThemeCocoa_h_
8 
9 #import <Carbon/Carbon.h>
10 #import <Cocoa/Cocoa.h>
11 
12 #include "mozilla/Variant.h"
13 
14 #include "nsITheme.h"
15 #include "ThemeCocoa.h"
16 
17 @class MOZCellDrawWindow;
18 @class MOZCellDrawView;
19 @class MOZSearchFieldCell;
20 @class NSProgressBarCell;
21 class nsDeviceContext;
22 struct SegmentedControlRenderSettings;
23 
24 namespace mozilla {
25 class EventStates;
26 namespace gfx {
27 class DrawTarget;
28 }  // namespace gfx
29 }  // namespace mozilla
30 
31 class nsNativeThemeCocoa : public mozilla::widget::ThemeCocoa {
32   using ThemeCocoa = mozilla::widget::ThemeCocoa;
33 
34  public:
35   enum class MenuIcon : uint8_t {
36     eCheckmark,
37     eMenuArrow,
38     eMenuDownScrollArrow,
39     eMenuUpScrollArrow
40   };
41 
42   enum class CheckboxOrRadioState : uint8_t { eOff, eOn, eIndeterminate };
43 
44   enum class ButtonType : uint8_t {
45     eRegularPushButton,
46     eDefaultPushButton,
47     eSquareBezelPushButton,
48     eArrowButton,
49     eHelpButton,
50     eTreeTwistyPointingRight,
51     eTreeTwistyPointingDown,
52     eDisclosureButtonClosed,
53     eDisclosureButtonOpen
54   };
55 
56   enum class SpinButton : uint8_t { eUp, eDown };
57 
58   enum class SegmentType : uint8_t { eToolbarButton, eTab };
59 
60   enum class OptimumState : uint8_t { eOptimum, eSubOptimum, eSubSubOptimum };
61 
62   struct ControlParams {
ControlParamsControlParams63     ControlParams()
64         : disabled(false), insideActiveWindow(false), pressed(false), focused(false), rtl(false) {}
65 
66     bool disabled : 1;
67     bool insideActiveWindow : 1;
68     bool pressed : 1;
69     bool focused : 1;
70     bool rtl : 1;
71   };
72 
73   struct MenuIconParams {
74     MenuIcon icon = MenuIcon::eCheckmark;
75     bool disabled = false;
76     bool insideActiveMenuItem = false;
77     bool centerHorizontally = false;
78     bool rtl = false;
79   };
80 
81   struct MenuItemParams {
82     bool checked = false;
83     bool disabled = false;
84     bool selected = false;
85     bool rtl = false;
86   };
87 
88   struct CheckboxOrRadioParams {
89     ControlParams controlParams;
90     CheckboxOrRadioState state = CheckboxOrRadioState::eOff;
91     float verticalAlignFactor = 0.5f;
92   };
93 
94   struct ButtonParams {
95     ControlParams controlParams;
96     ButtonType button = ButtonType::eRegularPushButton;
97   };
98 
99   struct DropdownParams {
100     ControlParams controlParams;
101     bool pullsDown = false;
102     bool editable = false;
103   };
104 
105   struct SpinButtonParams {
106     mozilla::Maybe<SpinButton> pressedButton;
107     bool disabled = false;
108     bool insideActiveWindow = false;
109   };
110 
111   struct SegmentParams {
112     SegmentType segmentType = SegmentType::eToolbarButton;
113     bool insideActiveWindow = false;
114     bool pressed = false;
115     bool selected = false;
116     bool focused = false;
117     bool atLeftEnd = false;
118     bool atRightEnd = false;
119     bool drawsLeftSeparator = false;
120     bool drawsRightSeparator = false;
121     bool rtl = false;
122   };
123 
124   struct TextFieldParams {
125     float verticalAlignFactor = 0.5f;
126     bool insideToolbar = false;
127     bool disabled = false;
128     bool focused = false;
129     bool rtl = false;
130   };
131 
132   struct ProgressParams {
133     double value = 0.0;
134     double max = 0.0;
135     float verticalAlignFactor = 0.5f;
136     bool insideActiveWindow = false;
137     bool indeterminate = false;
138     bool horizontal = false;
139     bool rtl = false;
140   };
141 
142   struct MeterParams {
143     double value = 0;
144     double min = 0;
145     double max = 0;
146     OptimumState optimumState = OptimumState::eOptimum;
147     float verticalAlignFactor = 0.5f;
148     bool horizontal = true;
149     bool rtl = false;
150   };
151 
152   struct TreeHeaderCellParams {
153     ControlParams controlParams;
154     TreeSortDirection sortDirection = eTreeSortDirection_Natural;
155     bool lastTreeHeaderCell = false;
156   };
157 
158   struct ScaleParams {
159     int32_t value = 0;
160     int32_t min = 0;
161     int32_t max = 0;
162     bool insideActiveWindow = false;
163     bool disabled = false;
164     bool focused = false;
165     bool horizontal = true;
166     bool reverse = false;
167   };
168 
169   enum Widget : uint8_t {
170     eColorFill,      // mozilla::gfx::sRGBColor
171     eMenuIcon,       // MenuIconParams
172     eMenuItem,       // MenuItemParams
173     eMenuSeparator,  // MenuItemParams
174     eCheckbox,       // CheckboxOrRadioParams
175     eRadio,          // CheckboxOrRadioParams
176     eButton,         // ButtonParams
177     eDropdown,       // DropdownParams
178     eFocusOutline,
179     eSpinButtons,     // SpinButtonParams
180     eSpinButtonUp,    // SpinButtonParams
181     eSpinButtonDown,  // SpinButtonParams
182     eSegment,         // SegmentParams
183     eSeparator,
184     eToolbar,    // bool
185     eStatusBar,  // bool
186     eGroupBox,
187     eTextField,           // TextFieldParams
188     eSearchField,         // TextFieldParams
189     eProgressBar,         // ProgressParams
190     eMeter,               // MeterParams
191     eTreeHeaderCell,      // TreeHeaderCellParams
192     eScale,               // ScaleParams
193     eMultilineTextField,  // bool
194     eListBox,
195     eActiveSourceListSelection,    // bool
196     eInactiveSourceListSelection,  // bool
197     eTabPanel,
198     eResizer
199   };
200 
201   struct WidgetInfo {
ColorFillWidgetInfo202     static WidgetInfo ColorFill(const mozilla::gfx::sRGBColor& aParams) {
203       return WidgetInfo(Widget::eColorFill, aParams);
204     }
MenuIconWidgetInfo205     static WidgetInfo MenuIcon(const MenuIconParams& aParams) {
206       return WidgetInfo(Widget::eMenuIcon, aParams);
207     }
MenuItemWidgetInfo208     static WidgetInfo MenuItem(const MenuItemParams& aParams) {
209       return WidgetInfo(Widget::eMenuItem, aParams);
210     }
MenuSeparatorWidgetInfo211     static WidgetInfo MenuSeparator(const MenuItemParams& aParams) {
212       return WidgetInfo(Widget::eMenuSeparator, aParams);
213     }
CheckboxWidgetInfo214     static WidgetInfo Checkbox(const CheckboxOrRadioParams& aParams) {
215       return WidgetInfo(Widget::eCheckbox, aParams);
216     }
RadioWidgetInfo217     static WidgetInfo Radio(const CheckboxOrRadioParams& aParams) {
218       return WidgetInfo(Widget::eRadio, aParams);
219     }
ButtonWidgetInfo220     static WidgetInfo Button(const ButtonParams& aParams) {
221       return WidgetInfo(Widget::eButton, aParams);
222     }
DropdownWidgetInfo223     static WidgetInfo Dropdown(const DropdownParams& aParams) {
224       return WidgetInfo(Widget::eDropdown, aParams);
225     }
FocusOutlineWidgetInfo226     static WidgetInfo FocusOutline() { return WidgetInfo(Widget::eFocusOutline, false); }
SpinButtonsWidgetInfo227     static WidgetInfo SpinButtons(const SpinButtonParams& aParams) {
228       return WidgetInfo(Widget::eSpinButtons, aParams);
229     }
SpinButtonUpWidgetInfo230     static WidgetInfo SpinButtonUp(const SpinButtonParams& aParams) {
231       return WidgetInfo(Widget::eSpinButtonUp, aParams);
232     }
SpinButtonDownWidgetInfo233     static WidgetInfo SpinButtonDown(const SpinButtonParams& aParams) {
234       return WidgetInfo(Widget::eSpinButtonDown, aParams);
235     }
SegmentWidgetInfo236     static WidgetInfo Segment(const SegmentParams& aParams) {
237       return WidgetInfo(Widget::eSegment, aParams);
238     }
SeparatorWidgetInfo239     static WidgetInfo Separator() { return WidgetInfo(Widget::eSeparator, false); }
ToolbarWidgetInfo240     static WidgetInfo Toolbar(bool aParams) { return WidgetInfo(Widget::eToolbar, aParams); }
StatusBarWidgetInfo241     static WidgetInfo StatusBar(bool aParams) { return WidgetInfo(Widget::eStatusBar, aParams); }
GroupBoxWidgetInfo242     static WidgetInfo GroupBox() { return WidgetInfo(Widget::eGroupBox, false); }
TextFieldWidgetInfo243     static WidgetInfo TextField(const TextFieldParams& aParams) {
244       return WidgetInfo(Widget::eTextField, aParams);
245     }
SearchFieldWidgetInfo246     static WidgetInfo SearchField(const TextFieldParams& aParams) {
247       return WidgetInfo(Widget::eSearchField, aParams);
248     }
ProgressBarWidgetInfo249     static WidgetInfo ProgressBar(const ProgressParams& aParams) {
250       return WidgetInfo(Widget::eProgressBar, aParams);
251     }
MeterWidgetInfo252     static WidgetInfo Meter(const MeterParams& aParams) {
253       return WidgetInfo(Widget::eMeter, aParams);
254     }
TreeHeaderCellWidgetInfo255     static WidgetInfo TreeHeaderCell(const TreeHeaderCellParams& aParams) {
256       return WidgetInfo(Widget::eTreeHeaderCell, aParams);
257     }
ScaleWidgetInfo258     static WidgetInfo Scale(const ScaleParams& aParams) {
259       return WidgetInfo(Widget::eScale, aParams);
260     }
MultilineTextFieldWidgetInfo261     static WidgetInfo MultilineTextField(bool aParams) {
262       return WidgetInfo(Widget::eMultilineTextField, aParams);
263     }
ListBoxWidgetInfo264     static WidgetInfo ListBox() { return WidgetInfo(Widget::eListBox, false); }
ActiveSourceListSelectionWidgetInfo265     static WidgetInfo ActiveSourceListSelection(bool aParams) {
266       return WidgetInfo(Widget::eActiveSourceListSelection, aParams);
267     }
InactiveSourceListSelectionWidgetInfo268     static WidgetInfo InactiveSourceListSelection(bool aParams) {
269       return WidgetInfo(Widget::eInactiveSourceListSelection, aParams);
270     }
TabPanelWidgetInfo271     static WidgetInfo TabPanel(bool aParams) { return WidgetInfo(Widget::eTabPanel, aParams); }
ResizerWidgetInfo272     static WidgetInfo Resizer(bool aParams) { return WidgetInfo(Widget::eResizer, aParams); }
273 
274     template <typename T>
ParamsWidgetInfo275     T Params() const {
276       MOZ_RELEASE_ASSERT(mVariant.is<T>());
277       return mVariant.as<T>();
278     }
279 
WidgetWidgetInfo280     enum Widget Widget() const { return mWidget; }
281 
282    private:
283     template <typename T>
WidgetInfoWidgetInfo284     WidgetInfo(enum Widget aWidget, const T& aParams) : mVariant(aParams), mWidget(aWidget) {}
285 
286     mozilla::Variant<mozilla::gfx::sRGBColor, MenuIconParams, MenuItemParams, CheckboxOrRadioParams,
287                      ButtonParams, DropdownParams, SpinButtonParams, SegmentParams, TextFieldParams,
288                      ProgressParams, MeterParams, TreeHeaderCellParams, ScaleParams, bool>
289         mVariant;
290 
291     enum Widget mWidget;
292   };
293 
294   explicit nsNativeThemeCocoa();
295 
296   NS_DECL_ISUPPORTS_INHERITED
297 
298   // The nsITheme interface.
299   NS_IMETHOD DrawWidgetBackground(gfxContext* aContext, nsIFrame* aFrame,
300                                   StyleAppearance aAppearance, const nsRect& aRect,
301                                   const nsRect& aDirtyRect, DrawOverflow) override;
302   bool CreateWebRenderCommandsForWidget(mozilla::wr::DisplayListBuilder& aBuilder,
303                                         mozilla::wr::IpcResourceUpdateQueue& aResources,
304                                         const mozilla::layers::StackingContextHelper& aSc,
305                                         mozilla::layers::RenderRootStateManager* aManager,
306                                         nsIFrame* aFrame, StyleAppearance aAppearance,
307                                         const nsRect& aRect) override;
308   [[nodiscard]] LayoutDeviceIntMargin GetWidgetBorder(nsDeviceContext* aContext, nsIFrame* aFrame,
309                                                       StyleAppearance aAppearance) override;
310 
311   bool GetWidgetPadding(nsDeviceContext* aContext, nsIFrame* aFrame, StyleAppearance aAppearance,
312                         LayoutDeviceIntMargin* aResult) override;
313 
314   virtual bool GetWidgetOverflow(nsDeviceContext* aContext, nsIFrame* aFrame,
315                                  StyleAppearance aAppearance, nsRect* aOverflowRect) override;
316 
317   NS_IMETHOD GetMinimumWidgetSize(nsPresContext* aPresContext, nsIFrame* aFrame,
318                                   StyleAppearance aAppearance,
319                                   mozilla::LayoutDeviceIntSize* aResult,
320                                   bool* aIsOverridable) override;
321   NS_IMETHOD WidgetStateChanged(nsIFrame* aFrame, StyleAppearance aAppearance, nsAtom* aAttribute,
322                                 bool* aShouldRepaint, const nsAttrValue* aOldValue) override;
323   NS_IMETHOD ThemeChanged() override;
324   bool ThemeSupportsWidget(nsPresContext* aPresContext, nsIFrame* aFrame,
325                            StyleAppearance aAppearance) override;
326   bool WidgetIsContainer(StyleAppearance aAppearance) override;
327   bool ThemeDrawsFocusForWidget(nsIFrame*, StyleAppearance) override;
328   bool ThemeNeedsComboboxDropmarker() override;
329   virtual bool WidgetAppearanceDependsOnWindowFocus(StyleAppearance aAppearance) override;
330   virtual ThemeGeometryType ThemeGeometryTypeForWidget(nsIFrame* aFrame,
331                                                        StyleAppearance aAppearance) override;
332   virtual Transparency GetWidgetTransparency(nsIFrame* aFrame,
333                                              StyleAppearance aAppearance) override;
334   mozilla::Maybe<WidgetInfo> ComputeWidgetInfo(nsIFrame* aFrame, StyleAppearance aAppearance,
335                                                const nsRect& aRect);
336   void DrawProgress(CGContextRef context, const HIRect& inBoxRect, const ProgressParams& aParams);
337 
338  protected:
339   virtual ~nsNativeThemeCocoa();
340 
341   LayoutDeviceIntMargin DirectionAwareMargin(const LayoutDeviceIntMargin& aMargin,
342                                              nsIFrame* aFrame);
343   nsIFrame* SeparatorResponsibility(nsIFrame* aBefore, nsIFrame* aAfter);
344   ControlParams ComputeControlParams(nsIFrame* aFrame, mozilla::EventStates aEventState);
345   MenuIconParams ComputeMenuIconParams(nsIFrame* aParams, mozilla::EventStates aEventState,
346                                        MenuIcon aIcon);
347   MenuItemParams ComputeMenuItemParams(nsIFrame* aFrame, mozilla::EventStates aEventState,
348                                        bool aIsChecked);
349   SegmentParams ComputeSegmentParams(nsIFrame* aFrame, mozilla::EventStates aEventState,
350                                      SegmentType aSegmentType);
351   TextFieldParams ComputeTextFieldParams(nsIFrame* aFrame, mozilla::EventStates aEventState);
352   ProgressParams ComputeProgressParams(nsIFrame* aFrame, mozilla::EventStates aEventState,
353                                        bool aIsHorizontal);
354   MeterParams ComputeMeterParams(nsIFrame* aFrame);
355   TreeHeaderCellParams ComputeTreeHeaderCellParams(nsIFrame* aFrame,
356                                                    mozilla::EventStates aEventState);
357   mozilla::Maybe<ScaleParams> ComputeHTMLScaleParams(nsIFrame* aFrame,
358                                                      mozilla::EventStates aEventState);
359 
360   // HITheme drawing routines
361   void DrawMeter(CGContextRef context, const HIRect& inBoxRect, const MeterParams& aParams);
362   void DrawSegment(CGContextRef cgContext, const HIRect& inBoxRect, const SegmentParams& aParams);
363   void DrawSegmentBackground(CGContextRef cgContext, const HIRect& inBoxRect,
364                              const SegmentParams& aParams);
365   void DrawTabPanel(CGContextRef context, const HIRect& inBoxRect, bool aIsInsideActiveWindow);
366   void DrawScale(CGContextRef context, const HIRect& inBoxRect, const ScaleParams& aParams);
367   void DrawCheckboxOrRadio(CGContextRef cgContext, bool inCheckbox, const HIRect& inBoxRect,
368                            const CheckboxOrRadioParams& aParams);
369   void DrawSearchField(CGContextRef cgContext, const HIRect& inBoxRect,
370                        const TextFieldParams& aParams);
371   void DrawTextField(CGContextRef cgContext, const HIRect& inBoxRect,
372                      const TextFieldParams& aParams);
373   void DrawPushButton(CGContextRef cgContext, const HIRect& inBoxRect, ButtonType aButtonType,
374                       ControlParams aControlParams);
375   void DrawSquareBezelPushButton(CGContextRef cgContext, const HIRect& inBoxRect,
376                                  ControlParams aControlParams);
377   void DrawHelpButton(CGContextRef cgContext, const HIRect& inBoxRect,
378                       ControlParams aControlParams);
379   void DrawDisclosureButton(CGContextRef cgContext, const HIRect& inBoxRect,
380                             ControlParams aControlParams, NSCellStateValue aState);
381   NSString* GetMenuIconName(const MenuIconParams& aParams);
382   NSSize GetMenuIconSize(MenuIcon aIcon);
383   void DrawMenuIcon(CGContextRef cgContext, const CGRect& aRect, const MenuIconParams& aParams);
384   void DrawMenuItem(CGContextRef cgContext, const CGRect& inBoxRect, const MenuItemParams& aParams);
385   void DrawMenuSeparator(CGContextRef cgContext, const CGRect& inBoxRect,
386                          const MenuItemParams& aParams);
387   void DrawHIThemeButton(CGContextRef cgContext, const HIRect& aRect, ThemeButtonKind aKind,
388                          ThemeButtonValue aValue, ThemeDrawState aState,
389                          ThemeButtonAdornment aAdornment, const ControlParams& aParams);
390   void DrawButton(CGContextRef context, const HIRect& inBoxRect, const ButtonParams& aParams);
391   void DrawTreeHeaderCell(CGContextRef context, const HIRect& inBoxRect,
392                           const TreeHeaderCellParams& aParams);
393   void DrawFocusOutline(CGContextRef cgContext, const HIRect& inBoxRect);
394   void DrawDropdown(CGContextRef context, const HIRect& inBoxRect, const DropdownParams& aParams);
395   HIThemeButtonDrawInfo SpinButtonDrawInfo(ThemeButtonKind aKind, const SpinButtonParams& aParams);
396   void DrawSpinButtons(CGContextRef context, const HIRect& inBoxRect,
397                        const SpinButtonParams& aParams);
398   void DrawSpinButton(CGContextRef context, const HIRect& inBoxRect, SpinButton aDrawnButton,
399                       const SpinButtonParams& aParams);
400   void DrawToolbar(CGContextRef cgContext, const CGRect& inBoxRect, bool aIsMain);
401   void DrawStatusBar(CGContextRef cgContext, const HIRect& inBoxRect, bool aIsMain);
402   void DrawResizer(CGContextRef cgContext, const HIRect& aRect, bool aIsRTL);
403   void DrawMultilineTextField(CGContextRef cgContext, const CGRect& inBoxRect, bool aIsFocused);
404   void DrawSourceListSelection(CGContextRef aContext, const CGRect& aRect, bool aWindowIsActive,
405                                bool aSelectionIsActive);
406 
407   void RenderWidget(const WidgetInfo& aWidgetInfo, mozilla::ColorScheme,
408                     mozilla::gfx::DrawTarget& aDrawTarget, const mozilla::gfx::Rect& aWidgetRect,
409                     const mozilla::gfx::Rect& aDirtyRect, float aScale);
410 
411  private:
412   NSButtonCell* mDisclosureButtonCell;
413   NSButtonCell* mHelpButtonCell;
414   NSButtonCell* mPushButtonCell;
415   NSButtonCell* mRadioButtonCell;
416   NSButtonCell* mCheckboxCell;
417   NSTextFieldCell* mTextFieldCell;
418   MOZSearchFieldCell* mSearchFieldCell;
419   NSPopUpButtonCell* mDropdownCell;
420   NSComboBoxCell* mComboBoxCell;
421   NSProgressBarCell* mProgressBarCell;
422   NSLevelIndicatorCell* mMeterBarCell;
423   NSTableHeaderCell* mTreeHeaderCell;
424   MOZCellDrawWindow* mCellDrawWindow = nil;
425   MOZCellDrawView* mCellDrawView;
426 };
427 
428 #endif  // nsNativeThemeCocoa_h_
429