--- a/widget/cocoa/nsNativeThemeCocoa.h
+++ b/widget/cocoa/nsNativeThemeCocoa.h
@@ -41,32 +41,47 @@ public:
eThemeGeometryTypeVibrantTitlebarDark,
eThemeGeometryTypeTooltip,
eThemeGeometryTypeSheet,
eThemeGeometryTypeSourceList,
eThemeGeometryTypeSourceListSelection,
eThemeGeometryTypeActiveSourceListSelection
};
+ enum class ButtonType : uint8_t {
+ eRegularPushButton,
+ eDefaultPushButton,
+ eRegularBevelButton,
+ eDefaultBevelButton,
+ eArrowButton,
+ eTreeTwistyPointingRight,
+ eTreeTwistyPointingDown
+ };
+
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;
};
+ struct ButtonParams {
+ ControlParams controlParams;
+ ButtonType button = ButtonType::eRegularPushButton;
+ };
+
struct TreeHeaderCellParams {
ControlParams controlParams;
TreeSortDirection sortDirection = eTreeSortDirection_Natural;
bool lastTreeHeaderCell = false;
};
nsNativeThemeCocoa();
@@ -164,20 +179,22 @@ protected:
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);
+ void DrawHIThemeButton(CGContextRef cgContext, const HIRect& aRect,
+ ThemeButtonKind aKind, ThemeButtonValue aValue,
+ ThemeDrawState aState, ThemeButtonAdornment aAdornment,
+ const ControlParams& aParams);
+ void DrawButton(CGContextRef context, const HIRect& inBoxRect,
+ const ButtonParams& aParams);
void DrawTreeHeaderCell(CGContextRef context, const HIRect& inBoxRect,
const TreeHeaderCellParams& aParams);
void DrawFocusOutline(CGContextRef cgContext, const HIRect& inBoxRect,
mozilla::EventStates inState, uint8_t aWidgetType,
nsIFrame* aFrame);
void DrawDropdown(CGContextRef context, const HIRect& inBoxRect,
mozilla::EventStates inState, uint8_t aWidgetType,
nsIFrame* aFrame);
--- a/widget/cocoa/nsNativeThemeCocoa.mm
+++ b/widget/cocoa/nsNativeThemeCocoa.mm
@@ -1377,82 +1377,120 @@ RenderTransformedHIThemeControl(CGContex
static void
RenderButton(CGContextRef cgContext, const HIRect& aRenderRect, void* aData)
{
HIThemeButtonDrawInfo* bdi = (HIThemeButtonDrawInfo*)aData;
HIThemeDrawButton(&aRenderRect, bdi, cgContext, kHIThemeOrientationNormal, NULL);
}
+static ThemeDrawState
+ToThemeDrawState(const nsNativeThemeCocoa::ControlParams& aParams)
+{
+ if (aParams.disabled) {
+ return kThemeStateUnavailable;
+ }
+ if (aParams.pressed) {
+ return kThemeStatePressed;
+ }
+ return kThemeStateActive;
+}
+
void
-nsNativeThemeCocoa::DrawButton(CGContextRef cgContext, ThemeButtonKind inKind,
- const HIRect& inBoxRect, bool inIsDefault,
- ThemeButtonValue inValue, ThemeButtonAdornment inAdornment,
- EventStates inState, nsIFrame* aFrame)
+nsNativeThemeCocoa::DrawHIThemeButton(CGContextRef cgContext, const HIRect& aRect,
+ ThemeButtonKind aKind, ThemeButtonValue aValue,
+ ThemeDrawState aState, ThemeButtonAdornment aAdornment,
+ const ControlParams& aParams)
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
- BOOL isActive = FrameIsInActiveWindow(aFrame);
- BOOL isDisabled = IsDisabled(aFrame, inState);
-
HIThemeButtonDrawInfo bdi;
bdi.version = 0;
- bdi.kind = inKind;
- bdi.value = inValue;
- bdi.adornment = inAdornment;
-
- if (isDisabled) {
- bdi.state = kThemeStateUnavailable;
- }
- else if (inState.HasAllStates(NS_EVENT_STATE_ACTIVE | NS_EVENT_STATE_HOVER)) {
- bdi.state = kThemeStatePressed;
+ bdi.kind = aKind;
+ bdi.value = aValue;
+ bdi.state = aState;
+ bdi.adornment = aAdornment;
+
+ if (aParams.focused && aParams.insideActiveWindow) {
+ bdi.adornment |= kThemeAdornmentFocus;
}
- else {
- if (inKind == kThemeArrowButton)
- bdi.state = kThemeStateUnavailable; // these are always drawn as unavailable
- else
- bdi.state = kThemeStateActive;
- }
-
- if (inState.HasState(NS_EVENT_STATE_FOCUS) && isActive)
- bdi.adornment |= kThemeAdornmentFocus;
-
- if (inIsDefault && !isDisabled &&
- !inState.HasState(NS_EVENT_STATE_ACTIVE)) {
- bdi.adornment |= kThemeAdornmentDefault;
+
+ if ((aAdornment & kThemeAdornmentDefault) && !aParams.disabled) {
bdi.animation.time.start = 0;
bdi.animation.time.current = CFAbsoluteTimeGetCurrent();
}
- HIRect drawFrame = inBoxRect;
-
- if (inKind == kThemePushButton) {
- drawFrame.size.height -= 2;
- if (inBoxRect.size.height < pushButtonSettings.naturalSizes[smallControlSize].height) {
- bdi.kind = kThemePushButtonMini;
- }
- else if (inBoxRect.size.height < pushButtonSettings.naturalSizes[regularControlSize].height) {
- bdi.kind = kThemePushButtonSmall;
- drawFrame.origin.y -= 1;
- drawFrame.origin.x += 1;
- drawFrame.size.width -= 2;
- }
- }
-
- RenderTransformedHIThemeControl(cgContext, drawFrame, RenderButton, &bdi,
- IsFrameRTL(aFrame));
+ RenderTransformedHIThemeControl(cgContext, aRect, RenderButton, &bdi,
+ aParams.rtl);
#if DRAW_IN_FRAME_DEBUG
CGContextSetRGBFillColor(cgContext, 0.0, 0.0, 0.5, 0.25);
CGContextFillRect(cgContext, inBoxRect);
#endif
NS_OBJC_END_TRY_ABORT_BLOCK;
}
+void
+nsNativeThemeCocoa::DrawButton(CGContextRef cgContext, const HIRect& inBoxRect,
+ const ButtonParams& aParams)
+{
+
+ ControlParams controlParams = aParams.controlParams;
+
+ switch (aParams.button) {
+ case ButtonType::eRegularPushButton:
+ case ButtonType::eDefaultPushButton: {
+ ThemeButtonAdornment adornment =
+ aParams.button == ButtonType::eDefaultPushButton ? kThemeAdornmentDefault
+ : kThemeAdornmentNone;
+ HIRect drawFrame = inBoxRect;
+ drawFrame.size.height -= 2;
+ if (inBoxRect.size.height >= pushButtonSettings.naturalSizes[regularControlSize].height) {
+ DrawHIThemeButton(cgContext, drawFrame, kThemePushButton, kThemeButtonOff,
+ ToThemeDrawState(controlParams), adornment, controlParams);
+ return;
+ }
+ if (inBoxRect.size.height >= pushButtonSettings.naturalSizes[smallControlSize].height) {
+ drawFrame.origin.y -= 1;
+ drawFrame.origin.x += 1;
+ drawFrame.size.width -= 2;
+ DrawHIThemeButton(cgContext, drawFrame, kThemePushButtonSmall, kThemeButtonOff,
+ ToThemeDrawState(controlParams), adornment, controlParams);
+ return;
+ }
+ DrawHIThemeButton(cgContext, drawFrame, kThemePushButtonMini, kThemeButtonOff,
+ ToThemeDrawState(controlParams), adornment, controlParams);
+ return;
+ }
+ case ButtonType::eRegularBevelButton:
+ case ButtonType::eDefaultBevelButton: {
+ ThemeButtonAdornment adornment =
+ aParams.button == ButtonType::eDefaultBevelButton ? kThemeAdornmentDefault
+ : kThemeAdornmentNone;
+ DrawHIThemeButton(cgContext, inBoxRect, kThemeMediumBevelButton, kThemeButtonOff,
+ ToThemeDrawState(controlParams), adornment, controlParams);
+ return;
+ }
+ case ButtonType::eArrowButton:
+ DrawHIThemeButton(cgContext, inBoxRect, kThemeArrowButton, kThemeButtonOn,
+ kThemeStateUnavailable, kThemeAdornmentArrowDownArrow,
+ controlParams);
+ return;
+ case ButtonType::eTreeTwistyPointingRight:
+ DrawHIThemeButton(cgContext, inBoxRect, kThemeDisclosureButton, kThemeDisclosureRight,
+ ToThemeDrawState(controlParams), kThemeAdornmentNone, controlParams);
+ return;
+ case ButtonType::eTreeTwistyPointingDown:
+ DrawHIThemeButton(cgContext, inBoxRect, kThemeDisclosureButton, kThemeDisclosureDown,
+ ToThemeDrawState(controlParams), kThemeAdornmentNone, controlParams);
+ return;
+ }
+}
+
nsNativeThemeCocoa::TreeHeaderCellParams
nsNativeThemeCocoa::ComputeTreeHeaderCellParams(nsIFrame* aFrame,
EventStates aEventState)
{
TreeHeaderCellParams params;
params.controlParams = ComputeControlParams(aFrame, aEventState);
params.sortDirection = GetTreeSortDirection(aFrame);
params.lastTreeHeaderCell = IsLastTreeHeaderCell(aFrame);
@@ -2568,18 +2606,24 @@ nsNativeThemeCocoa::DrawWidgetBackground
// text, and default buttons in inactive windows have white background
// and black text.)
EventStates docState = aFrame->GetContent()->OwnerDoc()->GetDocumentState();
bool isInActiveWindow = !docState.HasState(NS_DOCUMENT_STATE_WINDOW_INACTIVE);
if (!IsDisabled(aFrame, eventState) && isInActiveWindow &&
!QueueAnimatedContentForRefresh(aFrame->GetContent(), 10)) {
NS_WARNING("Unable to animate button!");
}
- DrawButton(cgContext, kThemePushButton, macRect, isInActiveWindow,
- kThemeButtonOff, kThemeAdornmentNone, eventState, aFrame);
+ bool hasDefaultButtonLook =
+ isInActiveWindow && !eventState.HasState(NS_EVENT_STATE_ACTIVE);
+ ButtonType buttonType =
+ hasDefaultButtonLook ? ButtonType::eDefaultPushButton
+ : ButtonType::eRegularPushButton;
+ ControlParams params = ComputeControlParams(aFrame, eventState);
+ params.insideActiveWindow = isInActiveWindow;
+ DrawButton(cgContext, macRect, ButtonParams{params, buttonType});
} 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
@@ -2605,20 +2649,25 @@ nsNativeThemeCocoa::DrawWidgetBackground
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);
+ case NS_THEME_BUTTON_BEVEL: {
+ bool isDefaultButton = IsDefaultButton(aFrame);
+ ButtonType buttonType =
+ isDefaultButton ? ButtonType::eDefaultBevelButton
+ : ButtonType::eRegularBevelButton;
+ DrawButton(cgContext, macRect,
+ ButtonParams{ComputeControlParams(aFrame, eventState),
+ buttonType});
+ }
break;
case NS_THEME_INNER_SPIN_BUTTON: {
case NS_THEME_SPINNER:
bool isSpinner = (aWidgetType == NS_THEME_SPINNER);
nsIContent* content = aFrame->GetContent();
if (isSpinner && content->IsHTMLElement()) {
// In HTML the theming for the spin buttons is drawn individually into
@@ -2708,18 +2757,19 @@ nsNativeThemeCocoa::DrawWidgetBackground
break;
case NS_THEME_MENULIST:
case NS_THEME_MENULIST_TEXTFIELD:
DrawDropdown(cgContext, macRect, eventState, aWidgetType, aFrame);
break;
case NS_THEME_MENULIST_BUTTON:
- DrawButton(cgContext, kThemeArrowButton, macRect, false, kThemeButtonOn,
- kThemeAdornmentArrowDownArrow, eventState, aFrame);
+ DrawButton(cgContext, macRect,
+ ButtonParams{ComputeControlParams(aFrame, eventState),
+ ButtonType::eArrowButton});
break;
case NS_THEME_GROUPBOX: {
HIThemeGroupBoxDrawInfo gdi = { 0, kThemeStateActive, kHIThemeGroupBoxKindPrimary };
HIThemeDrawGroupBox(&macRect, &gdi, cgContext, HITHEME_ORIENTATION);
break;
}
@@ -2774,23 +2824,25 @@ nsNativeThemeCocoa::DrawWidgetBackground
case NS_THEME_PROGRESSCHUNK:
case NS_THEME_PROGRESSCHUNK_VERTICAL:
case NS_THEME_METERCHUNK:
// Do nothing: progress and meter bars cases will draw chunks.
break;
case NS_THEME_TREETWISTY:
- DrawButton(cgContext, kThemeDisclosureButton, macRect, false,
- kThemeDisclosureRight, kThemeAdornmentNone, eventState, aFrame);
+ DrawButton(cgContext, macRect,
+ ButtonParams{ComputeControlParams(aFrame, eventState),
+ ButtonType::eTreeTwistyPointingRight});
break;
case NS_THEME_TREETWISTYOPEN:
- DrawButton(cgContext, kThemeDisclosureButton, macRect, false,
- kThemeDisclosureDown, kThemeAdornmentNone, eventState, aFrame);
+ DrawButton(cgContext, macRect,
+ ButtonParams{ComputeControlParams(aFrame, eventState),
+ ButtonType::eTreeTwistyPointingDown});
break;
case NS_THEME_TREEHEADERCELL:
DrawTreeHeaderCell(cgContext, macRect,
ComputeTreeHeaderCellParams(aFrame, eventState));
break;
case NS_THEME_TREEITEM: