Bug 1051522 - Create NSVisualEffectViews for vibrant window regions. r=smichaud
authorMarkus Stange <mstange@themasta.com>
Thu, 28 Aug 2014 02:15:33 +0200
changeset 223721 ad26257c3e0d1c62491c6ccd201f0363e7e364b6
parent 223720 d4bf1bdbf7ec313948c1f1e5324c129d05856b40
child 223722 badea3d50106acd0b920cc21803bc8f8421819dc
push id3979
push userraliiev@mozilla.com
push dateMon, 13 Oct 2014 16:35:44 +0000
treeherdermozilla-beta@30f2cc610691 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmichaud
bugs1051522
milestone34.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 1051522 - Create NSVisualEffectViews for vibrant window regions. r=smichaud
widget/cocoa/VibrancyManager.h
widget/cocoa/VibrancyManager.mm
widget/cocoa/moz.build
widget/cocoa/nsChildView.h
widget/cocoa/nsChildView.mm
widget/cocoa/nsNativeThemeCocoa.h
widget/cocoa/nsNativeThemeCocoa.mm
new file mode 100644
--- /dev/null
+++ b/widget/cocoa/VibrancyManager.h
@@ -0,0 +1,103 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef VibrancyManager_h
+#define VibrancyManager_h
+
+#include "mozilla/Assertions.h"
+#include "mozilla/TypedEnum.h"
+#include "nsClassHashtable.h"
+#include "nsRegion.h"
+#include "nsTArray.h"
+
+#import <Foundation/NSGeometry.h>
+
+@class NSView;
+class nsChildView;
+class nsIntRegion;
+
+namespace mozilla {
+
+MOZ_BEGIN_ENUM_CLASS(VibrancyType)
+  LIGHT,
+  DARK
+MOZ_END_ENUM_CLASS(VibrancyType)
+
+/**
+ * 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,
+ * the effect is only visible in areas where the window contents are not
+ * completely opaque. Usually this is achieved by clearing the background of
+ * the window prior to drawing in the vibrant areas. This is possible even if
+ * the window is declared as opaque.
+ */
+class VibrancyManager {
+public:
+  /**
+   * Create a new VibrancyManager instance and provide it with an NSView
+   * to attach NSVisualEffectViews to.
+   *
+   * @param aCoordinateConverter  The nsChildView to use for converting
+   *   nsIntRect device pixel coordinates into Cocoa NSRect coordinates. Must
+   *   outlive this VibrancyManager instance.
+   * @param aContainerView  The view that's going to be the superview of the
+   *   NSVisualEffectViews which will be created for vibrant regions.
+   */
+  VibrancyManager(const nsChildView& aCoordinateConverter,
+                  NSView* aContainerView)
+    : mCoordinateConverter(aCoordinateConverter)
+    , mContainerView(aContainerView)
+  {
+    MOZ_ASSERT(SystemSupportsVibrancy(),
+               "Don't instantiate this if !SystemSupportsVibrancy()");
+  }
+
+  /**
+   * Update the placement of the NSVisualEffectViews inside the container
+   * NSView so that they cover aRegion, and create new NSVisualEffectViews
+   * or remove existing ones as needed.
+   * @param aType   The vibrancy type to use in the region.
+   * @param aRegion The vibrant area, in device pixels.
+   */
+  void UpdateVibrantRegion(VibrancyType aType, const nsIntRegion& aRegion);
+
+  /**
+   * Clear the vibrant areas that we know about.
+   * The clearing happens in the current NSGraphicsContext. If you call this
+   * from within an -[NSView drawRect:] implementation, the currrent
+   * NSGraphicsContext is already correctly set to the window drawing context.
+   */
+  void ClearVibrantAreas() const;
+
+  /**
+   * Check whether the operating system supports vibrancy at all.
+   * You may only create a VibrancyManager instance if this returns true.
+   * @return Whether VibrancyManager can be used on this OS.
+   */
+  static bool SystemSupportsVibrancy();
+
+  // The following are only public because otherwise ClearVibrantRegionFunc
+  // can't see them.
+  struct VibrantRegion {
+    nsIntRegion region;
+    nsTArray<NSView*> effectViews;
+  };
+  void ClearVibrantRegion(const VibrantRegion& aVibrantRegion) const;
+
+protected:
+  NSView* CreateEffectView(VibrancyType aType, NSRect aRect);
+
+  const nsChildView& mCoordinateConverter;
+  NSView* mContainerView;
+  nsClassHashtable<nsUint32HashKey, VibrantRegion> mVibrantRegions;
+};
+
+}
+
+#endif // VibrancyManager_h
new file mode 100644
--- /dev/null
+++ b/widget/cocoa/VibrancyManager.mm
@@ -0,0 +1,157 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "VibrancyManager.h"
+#include "nsChildView.h"
+#import <objc/message.h>
+
+using namespace mozilla;
+
+void
+VibrancyManager::UpdateVibrantRegion(VibrancyType aType, const nsIntRegion& aRegion)
+{
+  auto& vr = *mVibrantRegions.LookupOrAdd(uint32_t(aType));
+  if (vr.region == aRegion) {
+    return;
+  }
+
+  // We need to construct the required region using as many EffectViews
+  // as necessary. We try to update the geometry of existing views if
+  // possible, or create new ones or remove old ones if the number of
+  // rects in the region has changed.
+
+  nsTArray<NSView*> viewsToRecycle;
+  vr.effectViews.SwapElements(viewsToRecycle);
+  // vr.effectViews is now empty.
+
+  nsIntRegionRectIterator iter(aRegion);
+  const nsIntRect* iterRect = nullptr;
+  for (size_t i = 0; (iterRect = iter.Next()) || i < viewsToRecycle.Length(); ++i) {
+    if (iterRect) {
+      NSView* view = nil;
+      NSRect rect = mCoordinateConverter.DevPixelsToCocoaPoints(*iterRect);
+      if (i < viewsToRecycle.Length()) {
+        view = viewsToRecycle[i];
+        [view setFrame:rect];
+      } else {
+        view = CreateEffectView(aType, rect);
+        [mContainerView addSubview:view];
+
+        // Now that the view is in the view hierarchy, it'll be kept alive by
+        // its superview, so we can drop our reference.
+        [view release];
+      }
+      vr.effectViews.AppendElement(view);
+    } else {
+      // Our new region is made of less rects than the old region, so we can
+      // remove this view. We only have a weak reference to it, so removing it
+      // from the view hierarchy will release it.
+      [viewsToRecycle[i] removeFromSuperview];
+    }
+  }
+
+  vr.region = aRegion;
+}
+
+static PLDHashOperator
+ClearVibrantRegionFunc(const uint32_t& aVibrancyType,
+                       VibrancyManager::VibrantRegion* aVibrantRegion,
+                       void* aVM)
+{
+  static_cast<VibrancyManager*>(aVM)->ClearVibrantRegion(*aVibrantRegion);
+  return PL_DHASH_NEXT;
+}
+
+void
+VibrancyManager::ClearVibrantAreas() const
+{
+  mVibrantRegions.EnumerateRead(ClearVibrantRegionFunc,
+                                const_cast<VibrancyManager*>(this));
+}
+
+void
+VibrancyManager::ClearVibrantRegion(const VibrantRegion& aVibrantRegion) const
+{
+  [[NSColor clearColor] set];
+
+  nsIntRegionRectIterator iter(aVibrantRegion.region);
+  while (const nsIntRect* rect = iter.Next()) {
+    NSRectFill(mCoordinateConverter.DevPixelsToCocoaPoints(*rect));
+  }
+}
+
+static void
+DrawRectNothing(id self, SEL _cmd, NSRect aRect)
+{
+  // The super implementation would clear the background.
+  // That's fine for views that are placed below their content, but our
+  // setup is different: Our drawn content is drawn to mContainerView, which
+  // sits below this EffectView. So we must not clear the background here,
+  // because we'd erase that drawn content.
+  // Of course the regular content drawing still needs to clear the background
+  // behind vibrant areas. This is taken care of by having nsNativeThemeCocoa
+  // return true from NeedToClearBackgroundBehindWidget for vibrant widgets.
+}
+
+static NSView*
+HitTestNil(id self, SEL _cmd, NSPoint aPoint)
+{
+  // This view must be transparent to mouse events.
+  return nil;
+}
+
+static Class
+CreateEffectViewClass()
+{
+  // Create a class called EffectView that inherits from NSVisualEffectView
+  // and overrides the methods -[NSVisualEffectView drawRect:] and
+  // -[NSView hitTest:].
+  Class NSVisualEffectViewClass = NSClassFromString(@"NSVisualEffectView");
+  Class EffectViewClass = objc_allocateClassPair(NSVisualEffectViewClass, "EffectView", 0);
+  class_addMethod(EffectViewClass, @selector(drawRect:), (IMP)DrawRectNothing,
+                  "v@:{CGRect={CGPoint=dd}{CGSize=dd}}");
+  class_addMethod(EffectViewClass, @selector(hitTest:), (IMP)HitTestNil,
+                  "@@:{CGPoint=dd}");
+  return EffectViewClass;
+}
+
+static id
+AppearanceForVibrancyType(VibrancyType aType)
+{
+  Class NSAppearanceClass = NSClassFromString(@"NSAppearance");
+  switch (aType) {
+    case VibrancyType::LIGHT:
+      return [NSAppearanceClass performSelector:@selector(appearanceNamed:)
+                                     withObject:@"NSAppearanceNameVibrantLight"];
+    case VibrancyType::DARK:
+      return [NSAppearanceClass performSelector:@selector(appearanceNamed:)
+                                     withObject:@"NSAppearanceNameVibrantDark"];
+  }
+}
+
+NSView*
+VibrancyManager::CreateEffectView(VibrancyType aType, NSRect aRect)
+{
+  static Class EffectViewClass = CreateEffectViewClass();
+  NSView* effectView = [[EffectViewClass alloc] initWithFrame:aRect];
+  [effectView performSelector:@selector(setAppearance:)
+                   withObject:AppearanceForVibrancyType(aType)];
+  return effectView;
+}
+
+static bool
+ComputeSystemSupportsVibrancy()
+{
+  return NSClassFromString(@"NSAppearance") &&
+      NSClassFromString(@"NSVisualEffectView");
+}
+
+/* static */ bool
+VibrancyManager::SystemSupportsVibrancy()
+{
+  static bool supportsVibrancy = ComputeSystemSupportsVibrancy();
+  return supportsVibrancy;
+}
--- a/widget/cocoa/moz.build
+++ b/widget/cocoa/moz.build
@@ -48,16 +48,17 @@ UNIFIED_SOURCES += [
     'nsScreenManagerCocoa.mm',
     'nsSound.mm',
     'nsStandaloneNativeMenu.mm',
     'nsSystemStatusBarCocoa.mm',
     'nsToolkit.mm',
     'nsWidgetFactory.mm',
     'nsWindowMap.mm',
     'OSXNotificationCenter.mm',
+    'VibrancyManager.mm',
     'WidgetTraceEvent.mm',
 ]
 
 # These files cannot be built in unified mode because they force NSPR logging.
 SOURCES += [
     'nsChildView.mm',
     'nsClipboard.mm',
     'nsDragService.mm',
--- a/widget/cocoa/nsChildView.h
+++ b/widget/cocoa/nsChildView.h
@@ -21,16 +21,17 @@
 #include "nsWeakPtr.h"
 #include "TextInputHandler.h"
 #include "nsCocoaUtils.h"
 #include "gfxQuartzSurface.h"
 #include "GLContextTypes.h"
 #include "mozilla/Mutex.h"
 #include "nsRegion.h"
 #include "mozilla/MouseEvents.h"
+#include "mozilla/UniquePtr.h"
 
 #include "nsString.h"
 #include "nsIDragService.h"
 
 #include "npapi.h"
 
 #import <Carbon/Carbon.h>
 #import <Cocoa/Cocoa.h>
@@ -88,16 +89,17 @@ class nsCocoaWindow;
 union nsPluginPort;
 
 namespace {
 class GLPresenter;
 class RectTextureImage;
 }
 
 namespace mozilla {
+class VibrancyManager;
 namespace layers {
 class GLManager;
 class APZCTreeManager;
 }
 }
 
 @interface NSEvent (Undocumented)
 
@@ -564,16 +566,17 @@ public:
   NS_IMETHOD        ReparentNativeWidget(nsIWidget* aNewParent);
 
   mozilla::widget::TextInputHandler* GetTextInputHandler()
   {
     return mTextInputHandler;
   }
 
   void              NotifyDirtyRegion(const nsIntRegion& aDirtyRegion);
+  void              ClearVibrantAreas();
 
   // unit conversion convenience functions
   int32_t           CocoaPointsToDevPixels(CGFloat aPts) const {
     return nsCocoaUtils::CocoaPointsToDevPixels(aPts, BackingScaleFactor());
   }
   nsIntPoint        CocoaPointsToDevPixels(const NSPoint& aPt) const {
     return nsCocoaUtils::CocoaPointsToDevPixels(aPt, BackingScaleFactor());
   }
@@ -620,16 +623,18 @@ protected:
   void MaybeDrawRoundedCorners(mozilla::layers::GLManager* aManager, const nsIntRect& aRect);
   void MaybeDrawTitlebar(mozilla::layers::GLManager* aManager, const nsIntRect& aRect);
 
   // Redraw the contents of mTitlebarCGContext on the main thread, as
   // determined by mDirtyTitlebarRegion.
   void UpdateTitlebarCGContext();
 
   nsIntRect RectContainingTitlebarControls();
+  void UpdateVibrancy(const nsTArray<ThemeGeometry>& aThemeGeometries);
+  mozilla::VibrancyManager& EnsureVibrancyManager();
 
   nsIWidget* GetWidgetForListenerEvents();
 
 protected:
 
   NSView<mozView>*      mView;      // my parallel cocoa view (ChildView or NativeScrollbarView), [STRONG]
   nsRefPtr<mozilla::widget::TextInputHandler> mTextInputHandler;
   InputContext          mInputContext;
@@ -689,16 +694,18 @@ protected:
   nsIPluginInstanceOwner* mPluginInstanceOwner; // [WEAK]
 
   // Used in OMTC BasicLayers mode. Presents the BasicCompositor result
   // surface to the screen using an OpenGL context.
   nsAutoPtr<GLPresenter> mGLPresenter;
 
   nsRefPtr<APZCTreeManager> mAPZCTreeManager;
 
+  mozilla::UniquePtr<mozilla::VibrancyManager> mVibrancyManager;
+
   static uint32_t sLastInputEventCount;
 
   void ReleaseTitlebarCGContext();
 };
 
 void NS_InstallPluginKeyEventsHandler();
 void NS_RemovePluginKeyEventsHandler();
 
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -89,16 +89,17 @@
 #include <ApplicationServices/ApplicationServices.h>
 
 #include "GeckoProfiler.h"
 
 #include "nsIDOMWheelEvent.h"
 #include "mozilla/layers/APZCCallbackHelper.h"
 #include "nsLayoutUtils.h"
 #include "InputData.h"
+#include "VibrancyManager.h"
 
 using namespace mozilla;
 using namespace mozilla::layers;
 using namespace mozilla::gl;
 using namespace mozilla::widget;
 
 using mozilla::gfx::Matrix4x4;
 
@@ -2590,17 +2591,22 @@ FindFirstRectOfType(const nsTArray<nsIWi
     }
   }
   return nsIntRect();
 }
 
 void
 nsChildView::UpdateThemeGeometries(const nsTArray<ThemeGeometry>& aThemeGeometries)
 {
-  if (![mView window] || ![[mView window] isKindOfClass:[ToolbarWindow class]])
+  if (![mView window])
+    return;
+
+  UpdateVibrancy(aThemeGeometries);
+
+  if (![[mView window] isKindOfClass:[ToolbarWindow class]])
     return;
 
   // Update unified toolbar height.
   int32_t windowWidth = mBounds.width;
   int32_t titlebarBottom = FindTitlebarBottom(aThemeGeometries, windowWidth);
   int32_t unifiedToolbarBottom =
     FindUnifiedToolbarBottom(aThemeGeometries, windowWidth, titlebarBottom);
 
@@ -2613,16 +2619,68 @@ nsChildView::UpdateThemeGeometries(const
 
   // Update titlebar control offsets.
   nsIntRect windowButtonRect = FindFirstRectOfType(aThemeGeometries, NS_THEME_WINDOW_BUTTON_BOX);
   [win placeWindowButtons:[mView convertRect:DevPixelsToCocoaPoints(windowButtonRect) toView:nil]];
   nsIntRect fullScreenButtonRect = FindFirstRectOfType(aThemeGeometries, NS_THEME_MOZ_MAC_FULLSCREEN_BUTTON);
   [win placeFullScreenButton:[mView convertRect:DevPixelsToCocoaPoints(fullScreenButtonRect) toView:nil]];
 }
 
+static nsIntRegion
+GatherThemeGeometryRegion(const nsTArray<nsIWidget::ThemeGeometry>& aThemeGeometries,
+                          uint8_t aWidgetType)
+{
+  nsIntRegion region;
+  for (size_t i = 0; i < aThemeGeometries.Length(); ++i) {
+    const nsIWidget::ThemeGeometry& g = aThemeGeometries[i];
+    if (g.mWidgetType == aWidgetType) {
+      region.OrWith(g.mRect);
+    }
+  }
+  return region;
+}
+
+void
+nsChildView::UpdateVibrancy(const nsTArray<ThemeGeometry>& aThemeGeometries)
+{
+  if (!VibrancyManager::SystemSupportsVibrancy()) {
+    return;
+  }
+
+  nsIntRegion vibrantLightRegion =
+    GatherThemeGeometryRegion(aThemeGeometries, NS_THEME_MAC_VIBRANCY_LIGHT);
+  nsIntRegion vibrantDarkRegion =
+    GatherThemeGeometryRegion(aThemeGeometries, NS_THEME_MAC_VIBRANCY_DARK);
+
+  // Make light win over dark in disputed areas.
+  vibrantDarkRegion.SubOut(vibrantLightRegion);
+
+  auto& vm = EnsureVibrancyManager();
+  vm.UpdateVibrantRegion(VibrancyType::LIGHT, vibrantLightRegion);
+  vm.UpdateVibrantRegion(VibrancyType::DARK, vibrantDarkRegion);
+}
+
+void
+nsChildView::ClearVibrantAreas()
+{
+  if (VibrancyManager::SystemSupportsVibrancy()) {
+    EnsureVibrancyManager().ClearVibrantAreas();
+  }
+}
+
+mozilla::VibrancyManager&
+nsChildView::EnsureVibrancyManager()
+{
+  MOZ_ASSERT(mView, "Only call this once we have a view!");
+  if (!mVibrancyManager) {
+    mVibrancyManager = MakeUnique<VibrancyManager>(*this, mView);
+  }
+  return *mVibrancyManager;
+}
+
 TemporaryRef<gfx::DrawTarget>
 nsChildView::StartRemoteDrawing()
 {
   if (!mGLPresenter) {
     mGLPresenter = GLPresenter::CreateForWindow(this);
 
     if (!mGLPresenter) {
       return nullptr;
@@ -3640,19 +3698,20 @@ NSEvent* gLastDragMouseDownEvent = nil;
     // directly called from a delayed perform callback - without going through
     // drawRect.
     // Paints that come through here are triggered by something that Cocoa
     // controls, for example by window resizing or window focus changes.
 
     // Since this view is usually declared as opaque, the window's pixel
     // buffer may now contain garbage which we need to prevent from reaching
     // the screen. The only place where garbage can show is in the window
-    // corners - the rest of the window is covered by opaque content in our
-    // OpenGL surface.
-    // So we need to clear the pixel buffer contents in the corners.
+    // corners and the vibrant regions of the window - the rest of the window
+    // is covered by opaque content in our OpenGL surface.
+    // So we need to clear the pixel buffer contents in these areas.
+    mGeckoChild->ClearVibrantAreas();
     [self clearCorners];
 
     // Do GL composition and return.
     [self drawUsingOpenGL];
     return;
   }
 
   PROFILER_LABEL("ChildView", "drawRect",
--- a/widget/cocoa/nsNativeThemeCocoa.h
+++ b/widget/cocoa/nsNativeThemeCocoa.h
@@ -57,16 +57,17 @@ public:
   NS_IMETHOD WidgetStateChanged(nsIFrame* aFrame, uint8_t aWidgetType, 
                                 nsIAtom* aAttribute, bool* aShouldRepaint);
   NS_IMETHOD ThemeChanged();
   bool ThemeSupportsWidget(nsPresContext* aPresContext, nsIFrame* aFrame, uint8_t aWidgetType);
   bool WidgetIsContainer(uint8_t aWidgetType);
   bool ThemeDrawsFocusForWidget(uint8_t aWidgetType) MOZ_OVERRIDE;
   bool ThemeNeedsComboboxDropmarker();
   virtual bool WidgetAppearanceDependsOnWindowFocus(uint8_t aWidgetType) MOZ_OVERRIDE;
+  virtual bool NeedToClearBackgroundBehindWidget(uint8_t aWidgetType) MOZ_OVERRIDE;
   virtual Transparency GetWidgetTransparency(nsIFrame* aFrame, uint8_t aWidgetType);
 
   void DrawProgress(CGContextRef context, const HIRect& inBoxRect,
                     bool inIsIndeterminate, bool inIsHorizontal,
                     double inValue, double inMaxValue, nsIFrame* aFrame);
 
   static void DrawNativeTitlebar(CGContextRef aContext, CGRect aTitlebarRect,
                                  CGFloat aUnifiedHeight, BOOL aIsMain, BOOL aIsFlipped);
--- a/widget/cocoa/nsNativeThemeCocoa.mm
+++ b/widget/cocoa/nsNativeThemeCocoa.mm
@@ -23,16 +23,17 @@
 #include "nsCocoaFeatures.h"
 #include "nsCocoaWindow.h"
 #include "nsNativeThemeColors.h"
 #include "nsIScrollableFrame.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/HTMLMeterElement.h"
 #include "nsLookAndFeel.h"
+#include "VibrancyManager.h"
 
 #include "gfxContext.h"
 #include "gfxQuartzSurface.h"
 #include "gfxQuartzNativeDrawing.h"
 #include <algorithm>
 
 using namespace mozilla;
 using namespace mozilla::gfx;
@@ -3525,16 +3526,20 @@ nsNativeThemeCocoa::ThemeSupportsWidget(
       // scrollbars are not present.
       nsIScrollableFrame* scrollFrame = do_QueryFrame(parentFrame);
       return (!nsLookAndFeel::UseOverlayScrollbars() &&
               scrollFrame && scrollFrame->GetScrollbarVisibility());
       break;
     }
     case NS_THEME_FOCUS_OUTLINE:
       return true;
+
+    case NS_THEME_MAC_VIBRANCY_LIGHT:
+    case NS_THEME_MAC_VIBRANCY_DARK:
+      return VibrancyManager::SystemSupportsVibrancy();
   }
 
   return false;
 }
 
 bool
 nsNativeThemeCocoa::WidgetIsContainer(uint8_t aWidgetType)
 {
@@ -3599,16 +3604,28 @@ nsNativeThemeCocoa::WidgetAppearanceDepe
     case NS_THEME_LISTBOX:
     case NS_THEME_RESIZER:
       return false;
     default:
       return true;
   }
 }
 
+bool
+nsNativeThemeCocoa::NeedToClearBackgroundBehindWidget(uint8_t aWidgetType)
+{
+  switch (aWidgetType) {
+    case NS_THEME_MAC_VIBRANCY_LIGHT:
+    case NS_THEME_MAC_VIBRANCY_DARK:
+      return true;
+    default:
+      return false;
+  }
+}
+
 nsITheme::Transparency
 nsNativeThemeCocoa::GetWidgetTransparency(nsIFrame* aFrame, uint8_t aWidgetType)
 {
   switch (aWidgetType) {
   case NS_THEME_MENUPOPUP:
   case NS_THEME_TOOLTIP:
     return eTransparent;