--- 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;