Bug 1673055 - Simplify VibrancyManager.mm. r=haik

This removes some code which was creating new Objective C classes at runtime.
I originally wrote this code because NSVisualEffectView was a new class that
was added in 10.10, and we were building with a pre-10.10 SDK.

These days we build with the 10.11 SDK, which has NSVisualEffectView, and we
only run on 10.12+.

Differential Revision: https://phabricator.services.mozilla.com/D94622
This commit is contained in:
Markus Stange 2020-10-26 23:17:03 +00:00
Родитель af68ac4a30
Коммит a15e11c85e
1 изменённых файлов: 118 добавлений и 141 удалений

Просмотреть файл

@ -12,6 +12,121 @@
using namespace mozilla;
#if !defined(MAC_OS_X_VERSION_10_12) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_12
enum { NSVisualEffectMaterialSelection = 4 };
@interface NSVisualEffectView (NSVisualEffectViewMethods)
- (void)setEmphasized:(BOOL)emphasized;
@end
#endif
@interface MOZVibrantView : NSVisualEffectView {
VibrancyType mType;
}
- (instancetype)initWithFrame:(NSRect)aRect vibrancyType:(VibrancyType)aVibrancyType;
@end
@interface MOZVibrantLeafView : MOZVibrantView
@end
static NSAppearance* AppearanceForVibrancyType(VibrancyType aType) {
switch (aType) {
case VibrancyType::LIGHT:
case VibrancyType::TOOLTIP:
case VibrancyType::MENU:
case VibrancyType::HIGHLIGHTED_MENUITEM:
case VibrancyType::SHEET:
case VibrancyType::SOURCE_LIST:
case VibrancyType::SOURCE_LIST_SELECTION:
case VibrancyType::ACTIVE_SOURCE_LIST_SELECTION:
return [NSAppearance appearanceNamed:@"NSAppearanceNameVibrantLight"];
case VibrancyType::DARK:
return [NSAppearance appearanceNamed:@"NSAppearanceNameVibrantDark"];
}
}
static NSVisualEffectState VisualEffectStateForVibrancyType(VibrancyType aType) {
switch (aType) {
case VibrancyType::TOOLTIP:
case VibrancyType::MENU:
case VibrancyType::HIGHLIGHTED_MENUITEM:
case VibrancyType::SHEET:
// Tooltip and menu windows are never "key" and sheets always looks
// active, so we need to tell the vibrancy effect to look active
// regardless of window state.
return NSVisualEffectStateActive;
default:
return NSVisualEffectStateFollowsWindowActiveState;
}
}
static NSVisualEffectMaterial VisualEffectMaterialForVibrancyType(VibrancyType aType,
BOOL* aOutIsEmphasized) {
switch (aType) {
case VibrancyType::MENU:
return NSVisualEffectMaterialMenu;
case VibrancyType::SOURCE_LIST:
return NSVisualEffectMaterialSidebar;
case VibrancyType::SOURCE_LIST_SELECTION:
return (NSVisualEffectMaterial)NSVisualEffectMaterialSelection;
case VibrancyType::HIGHLIGHTED_MENUITEM:
case VibrancyType::ACTIVE_SOURCE_LIST_SELECTION:
*aOutIsEmphasized = YES;
return (NSVisualEffectMaterial)NSVisualEffectMaterialSelection;
default:
return NSVisualEffectMaterialAppearanceBased;
}
}
static BOOL HasVibrantForeground(VibrancyType aType) {
switch (aType) {
case VibrancyType::MENU:
return YES;
default:
return NO;
}
}
@implementation MOZVibrantView
- (instancetype)initWithFrame:(NSRect)aRect vibrancyType:(VibrancyType)aType {
self = [super initWithFrame:aRect];
mType = aType;
self.appearance = AppearanceForVibrancyType(mType);
self.state = VisualEffectStateForVibrancyType(mType);
BOOL isEmphasized = NO;
self.material = VisualEffectMaterialForVibrancyType(mType, &isEmphasized);
if (isEmphasized && [self respondsToSelector:@selector(setEmphasized:)]) {
[self setEmphasized:YES];
}
return self;
}
// Don't override allowsVibrancy here, because this view may have subviews, and
// returning YES from allowsVibrancy forces on foreground vibrancy for all
// descendant views, which can have unintended effects.
@end
@implementation MOZVibrantLeafView
- (NSView*)hitTest:(NSPoint)aPoint {
// This view must be transparent to mouse events.
return nil;
}
// MOZVibrantLeafView does not have subviews, so we can return YES here without
// having unintended effects on other contents of the window.
- (BOOL)allowsVibrancy {
return HasVibrantForeground(mType);
}
@end
bool VibrancyManager::UpdateVibrantRegion(VibrancyType aType,
const LayoutDeviceIntRegion& aRegion) {
if (aRegion.IsEmpty()) {
@ -31,147 +146,9 @@ LayoutDeviceIntRegion VibrancyManager::GetUnionOfVibrantRegions() const {
return result;
}
static NSView* HitTestNil(id self, SEL _cmd, NSPoint aPoint) {
// This view must be transparent to mouse events.
return nil;
}
static BOOL AllowsVibrancyYes(id self, SEL _cmd) {
// Means that the foreground is blended using a vibrant blend mode.
return YES;
}
static Class CreateEffectViewClass(BOOL aForegroundVibrancy, BOOL aIsContainer) {
// Create a class that inherits from NSVisualEffectView and overrides the
// methods -[NSView hitTest:] and -[NSVisualEffectView allowsVibrancy].
Class NSVisualEffectViewClass = NSClassFromString(@"NSVisualEffectView");
const char* className = aForegroundVibrancy ? "EffectViewWithForegroundVibrancy"
: "EffectViewWithoutForegroundVibrancy";
Class EffectViewClass = objc_allocateClassPair(NSVisualEffectViewClass, className, 0);
if (!aIsContainer) {
// Make this view transparent to mouse events.
class_addMethod(EffectViewClass, @selector(hitTest:), (IMP)HitTestNil, "@@:{CGPoint=dd}");
}
if (aForegroundVibrancy) {
// Override the -[NSView allowsVibrancy] method to return YES.
class_addMethod(EffectViewClass, @selector(allowsVibrancy), (IMP)AllowsVibrancyYes, "I@:");
}
return EffectViewClass;
}
static id AppearanceForVibrancyType(VibrancyType aType) {
Class NSAppearanceClass = NSClassFromString(@"NSAppearance");
switch (aType) {
case VibrancyType::LIGHT:
case VibrancyType::TOOLTIP:
case VibrancyType::MENU:
case VibrancyType::HIGHLIGHTED_MENUITEM:
case VibrancyType::SHEET:
case VibrancyType::SOURCE_LIST:
case VibrancyType::SOURCE_LIST_SELECTION:
case VibrancyType::ACTIVE_SOURCE_LIST_SELECTION:
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
};
enum { NSVisualEffectMaterialTitlebar = 3 };
#endif
#if !defined(MAC_OS_X_VERSION_10_11) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_11
enum { NSVisualEffectMaterialMenu = 5, NSVisualEffectMaterialSidebar = 7 };
#endif
static NSUInteger VisualEffectStateForVibrancyType(VibrancyType aType) {
switch (aType) {
case VibrancyType::TOOLTIP:
case VibrancyType::MENU:
case VibrancyType::HIGHLIGHTED_MENUITEM:
case VibrancyType::SHEET:
// Tooltip and menu windows are never "key" and sheets always looks
// active, so we need to tell the vibrancy effect to look active
// regardless of window state.
return NSVisualEffectStateActive;
default:
return NSVisualEffectStateFollowsWindowActiveState;
}
}
static BOOL HasVibrantForeground(VibrancyType aType) {
switch (aType) {
case VibrancyType::MENU:
return YES;
default:
return NO;
}
}
#if !defined(MAC_OS_X_VERSION_10_12) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_12
enum { NSVisualEffectMaterialSelection = 4 };
#endif
@interface NSView (NSVisualEffectViewMethods)
- (void)setState:(NSUInteger)state;
- (void)setMaterial:(NSUInteger)material;
- (void)setEmphasized:(BOOL)emphasized;
@end
/* static */ NSView* VibrancyManager::CreateEffectView(VibrancyType aType, BOOL aIsContainer) {
static Class EffectViewWithoutForegroundVibrancy = CreateEffectViewClass(NO, NO);
static Class EffectViewWithForegroundVibrancy = CreateEffectViewClass(YES, NO);
static Class EffectViewContainer = CreateEffectViewClass(NO, YES);
// Pick the right NSVisualEffectView subclass for the desired vibrancy mode.
// For "container" views, never use foreground vibrancy, because returning
// YES from allowsVibrancy forces on foreground vibrancy for all descendant
// views which can have unintended effects.
Class EffectViewClass = aIsContainer
? EffectViewContainer
: (HasVibrantForeground(aType) ? EffectViewWithForegroundVibrancy
: EffectViewWithoutForegroundVibrancy);
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
// is the one that comes closest.
[effectView setMaterial:canUseElCapitanMaterials ? NSVisualEffectMaterialMenu
: NSVisualEffectMaterialTitlebar];
} else if (aType == VibrancyType::SOURCE_LIST && canUseElCapitanMaterials) {
[effectView setMaterial:NSVisualEffectMaterialSidebar];
} else if (aType == VibrancyType::HIGHLIGHTED_MENUITEM ||
aType == VibrancyType::SOURCE_LIST_SELECTION ||
aType == VibrancyType::ACTIVE_SOURCE_LIST_SELECTION) {
[effectView setMaterial:NSVisualEffectMaterialSelection];
if ([effectView respondsToSelector:@selector(setEmphasized:)] &&
aType != VibrancyType::SOURCE_LIST_SELECTION) {
[effectView setEmphasized:YES];
}
}
return effectView;
return aIsContainer ? [[MOZVibrantView alloc] initWithFrame:NSZeroRect vibrancyType:aType]
: [[MOZVibrantLeafView alloc] initWithFrame:NSZeroRect vibrancyType:aType];
}
static bool ComputeSystemSupportsVibrancy() {
return NSClassFromString(@"NSAppearance") && NSClassFromString(@"NSVisualEffectView");
}
/* static */ bool VibrancyManager::SystemSupportsVibrancy() {
static bool supportsVibrancy = ComputeSystemSupportsVibrancy();
return supportsVibrancy;
}
/* static */ bool VibrancyManager::SystemSupportsVibrancy() { return true; }