--- a/widget/cocoa/nsNativeThemeCocoa.h
+++ b/widget/cocoa/nsNativeThemeCocoa.h
@@ -41,16 +41,23 @@ public:
eThemeGeometryTypeVibrantTitlebarDark,
eThemeGeometryTypeTooltip,
eThemeGeometryTypeSheet,
eThemeGeometryTypeSourceList,
eThemeGeometryTypeSourceListSelection,
eThemeGeometryTypeActiveSourceListSelection
};
+ enum class MenuIcon : uint8_t {
+ eCheckmark,
+ eMenuArrow,
+ eMenuDownScrollArrow,
+ eMenuUpScrollArrow
+ };
+
enum class ButtonType : uint8_t {
eRegularPushButton,
eDefaultPushButton,
eRegularBevelButton,
eDefaultBevelButton,
eRoundedBezelPushButton,
eSquareBezelPushButton,
eArrowButton,
@@ -78,16 +85,32 @@ public:
};
struct MenuBackgroundParams {
mozilla::Maybe<mozilla::gfx::Color> vibrancyColor;
bool disabled = false;
bool submenuRightOfParent = false;
};
+ struct MenuIconParams {
+ MenuIcon icon = MenuIcon::eCheckmark;
+ bool disabled = false;
+ bool insideActiveMenuItem = false;
+ bool centerHorizontally = false;
+ bool rtl = false;
+ };
+
+ struct MenuItemParams {
+ mozilla::Maybe<mozilla::gfx::Color> vibrancyColor;
+ bool checked = false;
+ bool disabled = false;
+ bool selected = false;
+ bool rtl = false;
+ };
+
struct ButtonParams {
ControlParams controlParams;
ButtonType button = ButtonType::eRegularPushButton;
};
struct TreeHeaderCellParams {
ControlParams controlParams;
TreeSortDirection sortDirection = eTreeSortDirection_Natural;
@@ -156,16 +179,22 @@ protected:
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);
MenuBackgroundParams ComputeMenuBackgroundParams(nsIFrame* aFrame,
mozilla::EventStates aEventState);
+ MenuIconParams ComputeMenuIconParams(nsIFrame* aParams,
+ mozilla::EventStates aEventState,
+ MenuIcon aIcon);
+ MenuItemParams ComputeMenuItemParams(nsIFrame* aFrame,
+ mozilla::EventStates aEventState,
+ bool aIsChecked);
TreeHeaderCellParams ComputeTreeHeaderCellParams(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,
@@ -190,20 +219,22 @@ protected:
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 DrawMenuBackground(CGContextRef cgContext, const CGRect& inBoxRect,
const MenuBackgroundParams& aParams);
+ NSString* GetMenuIconName(const MenuIconParams& aParams);
+ NSSize GetMenuIconSize(MenuIcon aIcon);
void DrawMenuIcon(CGContextRef cgContext, const CGRect& aRect,
- mozilla::EventStates inState, nsIFrame* aFrame,
- const NSSize& aIconSize, NSString* aImageName,
- bool aCenterHorizontally);
+ const MenuIconParams& aParams);
+ void DrawMenuItem(CGContextRef cgContext, const CGRect& inBoxRect,
+ const MenuItemParams& aParams);
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);
--- a/widget/cocoa/nsNativeThemeCocoa.mm
+++ b/widget/cocoa/nsNativeThemeCocoa.mm
@@ -1220,42 +1220,88 @@ static const NSSize kMenuarrowSize = NSM
static const NSSize kMenuScrollArrowSize = NSMakeSize(10, 8);
static NSString* kCheckmarkImage = @"MenuOnState";
static NSString* kMenuarrowRightImage = @"MenuSubmenu";
static NSString* kMenuarrowLeftImage = @"MenuSubmenuLeft";
static NSString* kMenuDownScrollArrowImage = @"MenuScrollDown";
static NSString* kMenuUpScrollArrowImage = @"MenuScrollUp";
static const CGFloat kMenuIconIndent = 6.0f;
+NSString*
+nsNativeThemeCocoa::GetMenuIconName(const MenuIconParams& aParams)
+{
+ switch (aParams.icon) {
+ case MenuIcon::eCheckmark:
+ return kCheckmarkImage;
+ case MenuIcon::eMenuArrow:
+ return aParams.rtl ? kMenuarrowLeftImage : kMenuarrowRightImage;
+ case MenuIcon::eMenuDownScrollArrow:
+ return kMenuDownScrollArrowImage;
+ case MenuIcon::eMenuUpScrollArrow:
+ return kMenuUpScrollArrowImage;
+ }
+}
+
+NSSize
+nsNativeThemeCocoa::GetMenuIconSize(MenuIcon aIcon)
+{
+ switch (aIcon) {
+ case MenuIcon::eCheckmark:
+ return kCheckmarkSize;
+ case MenuIcon::eMenuArrow:
+ return kMenuarrowSize;
+ case MenuIcon::eMenuDownScrollArrow:
+ case MenuIcon::eMenuUpScrollArrow:
+ return kMenuScrollArrowSize;
+ }
+}
+
+nsNativeThemeCocoa::MenuIconParams
+nsNativeThemeCocoa::ComputeMenuIconParams(nsIFrame* aFrame,
+ EventStates aEventState,
+ MenuIcon aIcon)
+{
+ bool isDisabled = IsDisabled(aFrame, aEventState);
+
+ MenuIconParams params;
+ params.icon = aIcon;
+ params.disabled = isDisabled;
+ params.insideActiveMenuItem =
+ !isDisabled && CheckBooleanAttr(aFrame, nsGkAtoms::menuactive);
+ params.centerHorizontally = true;
+ params.rtl = IsFrameRTL(aFrame);
+ return params;
+}
+
void
nsNativeThemeCocoa::DrawMenuIcon(CGContextRef cgContext, const CGRect& aRect,
- EventStates inState, nsIFrame* aFrame,
- const NSSize& aIconSize, NSString* aImageName,
- bool aCenterHorizontally)
+ const MenuIconParams& aParams)
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
+ NSSize size = GetMenuIconSize(aParams.icon);
+
// Adjust size and position of our drawRect.
- CGFloat paddingX = std::max(CGFloat(0.0), aRect.size.width - aIconSize.width);
- CGFloat paddingY = std::max(CGFloat(0.0), aRect.size.height - aIconSize.height);
+ CGFloat paddingX = std::max(CGFloat(0.0), aRect.size.width - size.width);
+ CGFloat paddingY = std::max(CGFloat(0.0), aRect.size.height - size.height);
CGFloat paddingStartX = std::min(paddingX, kMenuIconIndent);
CGFloat paddingEndX = std::max(CGFloat(0.0), paddingX - kMenuIconIndent);
CGRect drawRect = CGRectMake(
- aRect.origin.x + (aCenterHorizontally ? ceil(paddingX / 2) :
- IsFrameRTL(aFrame) ? paddingEndX : paddingStartX),
+ aRect.origin.x + (aParams.centerHorizontally ? ceil(paddingX / 2) :
+ aParams.rtl ? paddingEndX : paddingStartX),
aRect.origin.y + ceil(paddingY / 2),
- aIconSize.width, aIconSize.height);
-
- NSString* state = IsDisabled(aFrame, inState) ? @"disabled" :
- (CheckBooleanAttr(aFrame, nsGkAtoms::menuactive) ? @"pressed" : @"normal");
-
- NSString* imageName = aImageName;
+ size.width, size.height);
+
+ NSString* state = aParams.disabled ? @"disabled" :
+ (aParams.insideActiveMenuItem ? @"pressed" : @"normal");
+
+ NSString* imageName = GetMenuIconName(aParams);
if (!nsCocoaFeatures::OnElCapitanOrLater()) {
// Pre-10.11, image names are prefixed with "image."
- imageName = [@"image." stringByAppendingString:aImageName];
+ imageName = [@"image." stringByAppendingString:imageName];
}
RenderWithCoreUI(drawRect, cgContext,
[NSDictionary dictionaryWithObjectsAndKeys:
@"kCUIBackgroundTypeMenu", @"backgroundTypeKey",
imageName, @"imageNameKey",
state, @"state",
@"image", @"widget",
@@ -1265,16 +1311,77 @@ 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::MenuItemParams
+nsNativeThemeCocoa::ComputeMenuItemParams(nsIFrame* aFrame,
+ EventStates aEventState,
+ bool aIsChecked)
+{
+ bool isDisabled = IsDisabled(aFrame, aEventState);
+
+ MenuItemParams params;
+ if (VibrancyManager::SystemSupportsVibrancy()) {
+ ThemeGeometryType type =
+ ThemeGeometryTypeForWidget(aFrame, NS_THEME_MENUITEM);
+ params.vibrancyColor = Some(VibrancyFillColor(aFrame, type));
+ }
+ params.checked = aIsChecked;
+ params.disabled = isDisabled;
+ params.selected =
+ !isDisabled && CheckBooleanAttr(aFrame, nsGkAtoms::menuactive);
+ params.rtl = IsFrameRTL(aFrame);
+ return params;
+}
+
+static void
+SetCGContextFillColor(CGContextRef cgContext, const Color& aColor)
+{
+ CGContextSetRGBFillColor(cgContext, aColor.r, aColor.g, aColor.b, aColor.a);
+}
+
+void
+nsNativeThemeCocoa::DrawMenuItem(CGContextRef cgContext,
+ const CGRect& inBoxRect,
+ const MenuItemParams& aParams)
+{
+ if (aParams.vibrancyColor) {
+ SetCGContextFillColor(cgContext, *aParams.vibrancyColor);
+ CGContextFillRect(cgContext, inBoxRect);
+ } else {
+ HIThemeMenuItemDrawInfo drawInfo;
+ memset(&drawInfo, 0, sizeof(drawInfo));
+ drawInfo.version = 0;
+ drawInfo.itemType = kThemeMenuItemPlain;
+ drawInfo.state = (aParams.disabled ?
+ static_cast<ThemeMenuState>(kThemeMenuDisabled) :
+ aParams.selected ?
+ static_cast<ThemeMenuState>(kThemeMenuSelected) :
+ static_cast<ThemeMenuState>(kThemeMenuActive));
+
+ HIRect ignored;
+ HIThemeDrawMenuItem(&inBoxRect, &inBoxRect, &drawInfo, cgContext,
+ HITHEME_ORIENTATION, &ignored);
+ }
+
+ if (aParams.checked) {
+ MenuIconParams params;
+ params.disabled = aParams.disabled;
+ params.insideActiveMenuItem = aParams.selected;
+ params.rtl = aParams.rtl;
+ params.icon = MenuIcon::eCheckmark;
+ DrawMenuIcon(cgContext, inBoxRect, params);
+ }
+}
+
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);
@@ -2451,22 +2558,16 @@ nsNativeThemeCocoa::IsParentScrollbarRol
static bool
IsHiDPIContext(nsDeviceContext* aContext)
{
return nsPresContext::AppUnitsPerCSSPixel() >=
2 * aContext->AppUnitsPerDevPixelAtUnitFullZoom();
}
-static void
-SetCGContextFillColor(CGContextRef cgContext, const Color& aColor)
-{
- CGContextSetRGBFillColor(cgContext, aColor.r, aColor.g, aColor.b, aColor.a);
-}
-
static const Color kTooltipBackgroundColor(0.996, 1.000, 0.792, 0.950);
static const Color kMultilineTextFieldTopBorderColor(0.4510, 0.4510, 0.4510, 1.0);
static const Color kMultilineTextFieldSidesAndBottomBorderColor(0.6, 0.6, 0.6, 1.0);
static const Color kListboxTopBorderColor(0.557, 0.557, 0.557, 1.0);
static const Color kListBoxSidesAndBottomBorderColor(0.745, 0.745, 0.745, 1.0);
NS_IMETHODIMP
nsNativeThemeCocoa::DrawWidgetBackground(gfxContext* aContext,
@@ -2565,51 +2666,27 @@ nsNativeThemeCocoa::DrawWidgetBackground
}
break;
case NS_THEME_MENUPOPUP:
DrawMenuBackground(cgContext, macRect,
ComputeMenuBackgroundParams(aFrame, eventState));
break;
- case NS_THEME_MENUARROW: {
- bool isRTL = IsFrameRTL(aFrame);
- DrawMenuIcon(cgContext, macRect, eventState, aFrame, kMenuarrowSize,
- isRTL ? kMenuarrowLeftImage : kMenuarrowRightImage, true);
- }
+ case NS_THEME_MENUARROW:
+ DrawMenuIcon(cgContext, macRect,
+ ComputeMenuIconParams(aFrame, eventState,
+ MenuIcon::eMenuArrow));
break;
case NS_THEME_MENUITEM:
- case NS_THEME_CHECKMENUITEM: {
- if (VibrancyManager::SystemSupportsVibrancy()) {
- ThemeGeometryType type = ThemeGeometryTypeForWidget(aFrame, aWidgetType);
- DrawVibrancyBackground(cgContext, macRect, aFrame, type);
- } else {
- bool isDisabled = IsDisabled(aFrame, eventState);
- bool isSelected = !isDisabled && CheckBooleanAttr(aFrame, nsGkAtoms::menuactive);
- // maybe use kThemeMenuItemHierBackground or PopUpBackground instead of just Plain?
- HIThemeMenuItemDrawInfo drawInfo;
- memset(&drawInfo, 0, sizeof(drawInfo));
- drawInfo.version = 0;
- drawInfo.itemType = kThemeMenuItemPlain;
- drawInfo.state = (isDisabled ?
- static_cast<ThemeMenuState>(kThemeMenuDisabled) :
- isSelected ?
- static_cast<ThemeMenuState>(kThemeMenuSelected) :
- static_cast<ThemeMenuState>(kThemeMenuActive));
-
- // XXX pass in the menu rect instead of always using the item rect
- HIRect ignored;
- HIThemeDrawMenuItem(&macRect, &macRect, &drawInfo, cgContext, HITHEME_ORIENTATION, &ignored);
- }
-
- if (aWidgetType == NS_THEME_CHECKMENUITEM) {
- DrawMenuIcon(cgContext, macRect, eventState, aFrame, kCheckmarkSize, kCheckmarkImage, false);
- }
- }
+ case NS_THEME_CHECKMENUITEM:
+ DrawMenuItem(cgContext, macRect,
+ ComputeMenuItemParams(aFrame, eventState,
+ aWidgetType == NS_THEME_CHECKMENUITEM));
break;
case NS_THEME_MENUSEPARATOR: {
ThemeMenuState menuState;
if (IsDisabled(aFrame, eventState)) {
menuState = kThemeMenuDisabled;
}
else {
@@ -2618,20 +2695,23 @@ nsNativeThemeCocoa::DrawWidgetBackground
}
HIThemeMenuItemDrawInfo midi = { 0, kThemeMenuItemPlain, menuState };
HIThemeDrawMenuSeparator(&macRect, &macRect, &midi, cgContext, HITHEME_ORIENTATION);
}
break;
case NS_THEME_BUTTON_ARROW_UP:
- case NS_THEME_BUTTON_ARROW_DOWN:
- DrawMenuIcon(cgContext, macRect, eventState, aFrame, kMenuScrollArrowSize,
- aWidgetType == NS_THEME_BUTTON_ARROW_UP ?
- kMenuUpScrollArrowImage : kMenuDownScrollArrowImage, true);
+ case NS_THEME_BUTTON_ARROW_DOWN: {
+ MenuIcon icon =
+ aWidgetType == NS_THEME_BUTTON_ARROW_UP ? MenuIcon::eMenuUpScrollArrow
+ : MenuIcon::eMenuDownScrollArrow;
+ DrawMenuIcon(cgContext, macRect,
+ ComputeMenuIconParams(aFrame, eventState, icon));
+ }
break;
case NS_THEME_TOOLTIP:
if (VibrancyManager::SystemSupportsVibrancy()) {
DrawVibrancyBackground(cgContext, macRect, aFrame, ThemeGeometryTypeForWidget(aFrame, aWidgetType));
} else {
SetCGContextFillColor(cgContext, kTooltipBackgroundColor);
CGContextFillRect(cgContext, macRect);