Bug 1045213 - Make the highlighted menu item vibrant. r=smichaud
authorMarkus Stange <mstange@themasta.com>
Wed, 04 Feb 2015 17:25:19 -0500
changeset 227516 fa950339690a9d96d9894de0df350cc09de2ed2d
parent 227515 4e3291b79e574b4f2b922455143b9287657b01dc
child 227517 c07194e580ced108e81f17ca0f924ac4664c6d0b
push id55145
push usermstange@themasta.com
push dateWed, 04 Feb 2015 22:25:37 +0000
treeherdermozilla-inbound@b46cb1ef16f8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmichaud
bugs1045213
milestone38.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1045213 - Make the highlighted menu item vibrant. r=smichaud
widget/cocoa/VibrancyManager.h
widget/cocoa/VibrancyManager.mm
widget/cocoa/nsChildView.mm
widget/cocoa/nsNativeThemeCocoa.mm
--- a/widget/cocoa/VibrancyManager.h
+++ b/widget/cocoa/VibrancyManager.h
@@ -20,17 +20,18 @@ class nsChildView;
 class nsIntRegion;
 
 namespace mozilla {
 
 enum class VibrancyType {
   LIGHT,
   DARK,
   TOOLTIP,
-  MENU
+  MENU,
+  HIGHLIGHTED_MENUITEM
 };
 
 /**
  * VibrancyManager takes care of updating the vibrant regions of a window.
  * Vibrancy is a visual look that was introduced on OS X starting with 10.10.
  * An app declares vibrant window regions to the window server, and the window
  * server will display a blurred rendering of the screen contents from behind
  * the window in these areas, behind the actual window contents. Consequently,
--- a/widget/cocoa/VibrancyManager.mm
+++ b/widget/cocoa/VibrancyManager.mm
@@ -158,47 +158,72 @@ CreateEffectViewClass()
 static id
 AppearanceForVibrancyType(VibrancyType aType)
 {
   Class NSAppearanceClass = NSClassFromString(@"NSAppearance");
   switch (aType) {
     case VibrancyType::LIGHT:
     case VibrancyType::TOOLTIP:
     case VibrancyType::MENU:
+    case VibrancyType::HIGHLIGHTED_MENUITEM:
       return [NSAppearanceClass performSelector:@selector(appearanceNamed:)
                                      withObject:@"NSAppearanceNameVibrantLight"];
     case VibrancyType::DARK:
       return [NSAppearanceClass performSelector:@selector(appearanceNamed:)
                                      withObject:@"NSAppearanceNameVibrantDark"];
   }
 }
 
 #if !defined(MAC_OS_X_VERSION_10_10) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_10
 enum {
   NSVisualEffectStateFollowsWindowActiveState,
   NSVisualEffectStateActive,
   NSVisualEffectStateInactive
 };
 #endif
 
-@interface NSView(NSVisualEffectViewSetState)
+static NSUInteger
+VisualEffectStateForVibrancyType(VibrancyType aType)
+{
+  switch (aType) {
+    case VibrancyType::TOOLTIP:
+    case VibrancyType::MENU:
+    case VibrancyType::HIGHLIGHTED_MENUITEM:
+      // Tooltip and menu windows are never "key", so we need to tell the
+      // vibrancy effect to look active regardless of window state.
+      return NSVisualEffectStateActive;
+    default:
+      return NSVisualEffectStateFollowsWindowActiveState;
+  }
+}
+
+enum {
+  NSVisualEffectMaterialMenuItem = 4
+};
+
+@interface NSView(NSVisualEffectViewMethods)
 - (void)setState:(NSUInteger)state;
+- (void)setMaterial:(NSUInteger)material;
+- (void)setEmphasized:(BOOL)emphasized;
 @end
 
 NSView*
 VibrancyManager::CreateEffectView(VibrancyType aType, NSRect aRect)
 {
   static Class EffectViewClass = CreateEffectViewClass();
   NSView* effectView = [[EffectViewClass alloc] initWithFrame:aRect];
   [effectView performSelector:@selector(setAppearance:)
                    withObject:AppearanceForVibrancyType(aType)];
-  if (aType == VibrancyType::TOOLTIP || aType == VibrancyType::MENU) {
-    // Tooltip and menu windows never become active, so we need to tell the
-    // vibrancy effect to look active regardless of window state.
-    [effectView setState:NSVisualEffectStateActive];
+  [effectView setState:VisualEffectStateForVibrancyType(aType)];
+
+  if (aType == VibrancyType::HIGHLIGHTED_MENUITEM) {
+    [effectView setMaterial:NSVisualEffectMaterialMenuItem];
+    if ([effectView respondsToSelector:@selector(setEmphasized:)]) {
+      [effectView setEmphasized:YES];
+    }
   }
   return effectView;
 }
 
 static bool
 ComputeSystemSupportsVibrancy()
 {
 #ifdef __x86_64__
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -2372,28 +2372,35 @@ nsChildView::UpdateVibrancy(const nsTArr
   nsIntRegion vibrantLightRegion =
     GatherThemeGeometryRegion(aThemeGeometries, nsNativeThemeCocoa::eThemeGeometryTypeVibrancyLight);
   nsIntRegion vibrantDarkRegion =
     GatherThemeGeometryRegion(aThemeGeometries, nsNativeThemeCocoa::eThemeGeometryTypeVibrancyDark);
   nsIntRegion menuRegion =
     GatherThemeGeometryRegion(aThemeGeometries, nsNativeThemeCocoa::eThemeGeometryTypeMenu);
   nsIntRegion tooltipRegion =
     GatherThemeGeometryRegion(aThemeGeometries, nsNativeThemeCocoa::eThemeGeometryTypeTooltip);
+  nsIntRegion highlightedMenuItemRegion =
+    GatherThemeGeometryRegion(aThemeGeometries, nsNativeThemeCocoa::eThemeGeometryTypeHighlightedMenuItem);
 
   vibrantDarkRegion.SubOut(vibrantLightRegion);
   vibrantDarkRegion.SubOut(menuRegion);
   vibrantDarkRegion.SubOut(tooltipRegion);
+  vibrantDarkRegion.SubOut(highlightedMenuItemRegion);
   vibrantLightRegion.SubOut(menuRegion);
   vibrantLightRegion.SubOut(tooltipRegion);
+  vibrantLightRegion.SubOut(highlightedMenuItemRegion);
   menuRegion.SubOut(tooltipRegion);
+  menuRegion.SubOut(highlightedMenuItemRegion);
+  tooltipRegion.SubOut(highlightedMenuItemRegion);
 
   auto& vm = EnsureVibrancyManager();
   vm.UpdateVibrantRegion(VibrancyType::LIGHT, vibrantLightRegion);
   vm.UpdateVibrantRegion(VibrancyType::TOOLTIP, tooltipRegion);
   vm.UpdateVibrantRegion(VibrancyType::MENU, menuRegion);
+  vm.UpdateVibrantRegion(VibrancyType::HIGHLIGHTED_MENUITEM, highlightedMenuItemRegion);
   vm.UpdateVibrantRegion(VibrancyType::DARK, vibrantDarkRegion);
 }
 
 void
 nsChildView::ClearVibrantAreas()
 {
   if (VibrancyManager::SystemSupportsVibrancy()) {
     EnsureVibrancyManager().ClearVibrantAreas();
@@ -2407,16 +2414,18 @@ ThemeGeometryTypeToVibrancyType(nsITheme
     case nsNativeThemeCocoa::eThemeGeometryTypeVibrancyLight:
       return VibrancyType::LIGHT;
     case nsNativeThemeCocoa::eThemeGeometryTypeVibrancyDark:
       return VibrancyType::DARK;
     case nsNativeThemeCocoa::eThemeGeometryTypeTooltip:
       return VibrancyType::TOOLTIP;
     case nsNativeThemeCocoa::eThemeGeometryTypeMenu:
       return VibrancyType::MENU;
+    case nsNativeThemeCocoa::eThemeGeometryTypeHighlightedMenuItem:
+      return VibrancyType::HIGHLIGHTED_MENUITEM;
     default:
       MOZ_CRASH();
   }
 }
 
 NSColor*
 nsChildView::VibrancyFillColorForThemeGeometryType(nsITheme::ThemeGeometryType aThemeGeometryType)
 {
--- a/widget/cocoa/nsNativeThemeCocoa.mm
+++ b/widget/cocoa/nsNativeThemeCocoa.mm
@@ -2416,21 +2416,22 @@ nsNativeThemeCocoa::DrawWidgetBackground
       bool isRTL = IsFrameRTL(aFrame);
       DrawMenuIcon(cgContext, macRect, eventState, aFrame, kMenuarrowSize,
                    isRTL ? kMenuarrowLeftImage : kMenuarrowRightImage, true);
     }
       break;
 
     case NS_THEME_MENUITEM:
     case NS_THEME_CHECKMENUITEM: {
-      bool isDisabled = IsDisabled(aFrame, eventState);
-      bool isSelected = !isDisabled && CheckBooleanAttr(aFrame, nsGkAtoms::menuactive);
-      if (!isSelected && VibrancyManager::SystemSupportsVibrancy()) {
-        DrawVibrancyBackground(cgContext, macRect, aFrame, eThemeGeometryTypeMenu);
+      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 ?
@@ -3822,19 +3823,24 @@ nsNativeThemeCocoa::ThemeGeometryTypeFor
       return eThemeGeometryTypeFullscreenButton;
     case NS_THEME_MAC_VIBRANCY_LIGHT:
       return eThemeGeometryTypeVibrancyLight;
     case NS_THEME_MAC_VIBRANCY_DARK:
       return eThemeGeometryTypeVibrancyDark;
     case NS_THEME_TOOLTIP:
       return eThemeGeometryTypeTooltip;
     case NS_THEME_MENUPOPUP:
+      return eThemeGeometryTypeMenu;
     case NS_THEME_MENUITEM:
-    case NS_THEME_CHECKMENUITEM:
-      return eThemeGeometryTypeMenu;
+    case NS_THEME_CHECKMENUITEM: {
+      EventStates eventState = GetContentState(aFrame, aWidgetType);
+      bool isDisabled = IsDisabled(aFrame, eventState);
+      bool isSelected = !isDisabled && CheckBooleanAttr(aFrame, nsGkAtoms::menuactive);
+      return isSelected ? eThemeGeometryTypeHighlightedMenuItem : eThemeGeometryTypeMenu;
+    }
     default:
       return eThemeGeometryTypeUnknown;
   }
 }
 
 nsITheme::Transparency
 nsNativeThemeCocoa::GetWidgetTransparency(nsIFrame* aFrame, uint8_t aWidgetType)
 {