Bug 1070710 - Use ViewRegion for vibrant areas in VibrancyManager. r?spohl draft
authorMarkus Stange <mstange@themasta.com>
Mon, 11 Jul 2016 14:47:05 -0400
changeset 386390 45b1816309915bb38ea4fd277025e10b97b0bb4f
parent 386389 3408c02d0b934bbd96c661c2c2de72a358754859
child 386391 991e3b613ed5fc6db6b03a806fa55fe3c94186a7
push id22695
push usermstange@themasta.com
push dateMon, 11 Jul 2016 20:18:37 +0000
reviewersspohl
bugs1070710
milestone50.0a1
Bug 1070710 - Use ViewRegion for vibrant areas in VibrancyManager. r?spohl MozReview-Commit-ID: 5qVo59SV7QG
widget/cocoa/VibrancyManager.h
widget/cocoa/VibrancyManager.mm
--- a/widget/cocoa/VibrancyManager.h
+++ b/widget/cocoa/VibrancyManager.h
@@ -6,16 +6,17 @@
 
 #ifndef VibrancyManager_h
 #define VibrancyManager_h
 
 #include "mozilla/Assertions.h"
 #include "nsClassHashtable.h"
 #include "nsRegion.h"
 #include "nsTArray.h"
+#include "ViewRegion.h"
 
 #import <Foundation/NSGeometry.h>
 
 @class NSColor;
 @class NSView;
 class nsChildView;
 
 namespace mozilla {
@@ -96,27 +97,20 @@ public:
 
   /**
    * 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 {
-    LayoutDeviceIntRegion region;
-    nsTArray<NSView*> effectViews;
-  };
-  void ClearVibrantRegion(const VibrantRegion& aVibrantRegion) const;
-
 protected:
-  NSView* CreateEffectView(VibrancyType aType, NSRect aRect);
+  void ClearVibrantRegion(const LayoutDeviceIntRegion& aVibrantRegion) const;
+  NSView* CreateEffectView(VibrancyType aType);
 
   const nsChildView& mCoordinateConverter;
   NSView* mContainerView;
-  nsClassHashtable<nsUint32HashKey, VibrantRegion> mVibrantRegions;
+  nsClassHashtable<nsUint32HashKey, ViewRegion> mVibrantRegions;
 };
 
 } // namespace mozilla
 
 #endif // VibrancyManager_h
--- a/widget/cocoa/VibrancyManager.mm
+++ b/widget/cocoa/VibrancyManager.mm
@@ -10,75 +10,35 @@
 
 using namespace mozilla;
 
 void
 VibrancyManager::UpdateVibrantRegion(VibrancyType aType,
                                      const LayoutDeviceIntRegion& 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.
-
-  size_t i = 0;
-  for (auto iter = aRegion.RectIter();
-       !iter.Done() || i < viewsToRecycle.Length();
-       i++) {
-    if (!iter.Done()) {
-      NSView* view = nil;
-      NSRect rect = mCoordinateConverter.DevPixelsToCocoaPoints(iter.Get());
-      if (i < viewsToRecycle.Length()) {
-        view = viewsToRecycle[i];
-        [view setFrame:rect];
-        [view setNeedsDisplay:YES];
-      } 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);
-      iter.Next();
-    } 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;
+  vr.UpdateRegion(aRegion, mCoordinateConverter, mContainerView, ^() {
+    return this->CreateEffectView(aType);
+  });
 }
 
 void
 VibrancyManager::ClearVibrantAreas() const
 {
   for (auto iter = mVibrantRegions.ConstIter(); !iter.Done(); iter.Next()) {
-    ClearVibrantRegion(*iter.UserData());
+    ClearVibrantRegion(iter.UserData()->Region());
   }
 }
 
 void
-VibrancyManager::ClearVibrantRegion(const VibrantRegion& aVibrantRegion) const
+VibrancyManager::ClearVibrantRegion(const LayoutDeviceIntRegion& aVibrantRegion) const
 {
   [[NSColor clearColor] set];
 
-  for (auto iter = aVibrantRegion.region.RectIter(); !iter.Done(); iter.Next()) {
+  for (auto iter = aVibrantRegion.RectIter(); !iter.Done(); iter.Next()) {
     NSRectFill(mCoordinateConverter.DevPixelsToCocoaPoints(iter.Get()));
   }
 }
 
 @interface NSView(CurrentFillColor)
 - (NSColor*)_currentFillColor;
 @end
 
@@ -93,42 +53,38 @@ AdjustedColor(NSColor* aFillColor, Vibra
     return [NSColor colorWithDeviceWhite:0.96 alpha:1.0];
   }
   return aFillColor;
 }
 
 NSColor*
 VibrancyManager::VibrancyFillColorForType(VibrancyType aType)
 {
-  const nsTArray<NSView*>& views =
-    mVibrantRegions.LookupOrAdd(uint32_t(aType))->effectViews;
+  NSView* view = mVibrantRegions.LookupOrAdd(uint32_t(aType))->GetAnyView();
 
-  if (!views.IsEmpty() &&
-      [views[0] respondsToSelector:@selector(_currentFillColor)]) {
+  if (view && [view respondsToSelector:@selector(_currentFillColor)]) {
     // -[NSVisualEffectView _currentFillColor] is the color that our view
     // would draw during its drawRect implementation, if we hadn't
     // disabled that.
-    return AdjustedColor([views[0] _currentFillColor], aType);
+    return AdjustedColor([view _currentFillColor], aType);
   }
   return [NSColor whiteColor];
 }
 
 @interface NSView(FontSmoothingBackgroundColor)
 - (NSColor*)fontSmoothingBackgroundColor;
 @end
 
 NSColor*
 VibrancyManager::VibrancyFontSmoothingBackgroundColorForType(VibrancyType aType)
 {
-  const nsTArray<NSView*>& views =
-    mVibrantRegions.LookupOrAdd(uint32_t(aType))->effectViews;
+  NSView* view = mVibrantRegions.LookupOrAdd(uint32_t(aType))->GetAnyView();
 
-  if (!views.IsEmpty() &&
-      [views[0] respondsToSelector:@selector(fontSmoothingBackgroundColor)]) {
-    return [views[0] fontSmoothingBackgroundColor];
+  if (view && [view respondsToSelector:@selector(fontSmoothingBackgroundColor)]) {
+    return [view fontSmoothingBackgroundColor];
   }
   return [NSColor clearColor];
 }
 
 static void
 DrawRectNothing(id self, SEL _cmd, NSRect aRect)
 {
   // The super implementation would clear the background.
@@ -248,24 +204,24 @@ enum {
 
 @interface NSView(NSVisualEffectViewMethods)
 - (void)setState:(NSUInteger)state;
 - (void)setMaterial:(NSUInteger)material;
 - (void)setEmphasized:(BOOL)emphasized;
 @end
 
 NSView*
-VibrancyManager::CreateEffectView(VibrancyType aType, NSRect aRect)
+VibrancyManager::CreateEffectView(VibrancyType aType)
 {
   static Class EffectViewClassWithoutForegroundVibrancy = CreateEffectViewClass(NO);
   static Class EffectViewClassWithForegroundVibrancy = CreateEffectViewClass(YES);
 
   Class EffectViewClass = HasVibrantForeground(aType)
     ? EffectViewClassWithForegroundVibrancy : EffectViewClassWithoutForegroundVibrancy;
-  NSView* effectView = [[EffectViewClass alloc] initWithFrame:aRect];
+  NSView* effectView = [[EffectViewClass alloc] initWithFrame:NSZeroRect];
   [effectView performSelector:@selector(setAppearance:)
                    withObject:AppearanceForVibrancyType(aType)];
   [effectView setState:VisualEffectStateForVibrancyType(aType)];
 
   BOOL canUseElCapitanMaterials = nsCocoaFeatures::OnElCapitanOrLater();
   if (aType == VibrancyType::MENU) {
     // Before 10.11 there is no material that perfectly matches the menu
     // look. Of all available material types, NSVisualEffectMaterialTitlebar