mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 04:41:11 +00:00
Bug 1891354
- Clean up VibrancyManager a bit. r=sam,mac-reviewers,bradwerth
Make the tooltip menupopup view not go through VibrancyManager at all (don't really need to). Use an EnumeratedArray for storage rather than a hashmap. Differential Revision: https://phabricator.services.mozilla.com/D207390
This commit is contained in:
parent
9d3a3d6b34
commit
cd7d835e04
@ -7,24 +7,24 @@
|
||||
#ifndef VibrancyManager_h
|
||||
#define VibrancyManager_h
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "nsClassHashtable.h"
|
||||
#include "nsRegion.h"
|
||||
#include "nsTArray.h"
|
||||
#include "ViewRegion.h"
|
||||
#include "mozilla/EnumeratedArray.h"
|
||||
#include "Units.h"
|
||||
|
||||
#import <Foundation/NSGeometry.h>
|
||||
|
||||
@class NSColor;
|
||||
@class NSView;
|
||||
class nsChildView;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class ViewRegion;
|
||||
|
||||
enum class VibrancyType {
|
||||
TOOLTIP,
|
||||
MENU,
|
||||
TITLEBAR,
|
||||
// Add new values here, or update MaxEnumValue below if you add them after.
|
||||
Titlebar,
|
||||
};
|
||||
|
||||
template <>
|
||||
struct MaxContiguousEnumValue<VibrancyType> {
|
||||
static constexpr auto value = VibrancyType::Titlebar;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -51,9 +51,9 @@ class VibrancyManager {
|
||||
* NSVisualEffectViews which will be created for vibrant regions.
|
||||
*/
|
||||
VibrancyManager(const nsChildView& aCoordinateConverter,
|
||||
NSView* aContainerView)
|
||||
: mCoordinateConverter(aCoordinateConverter),
|
||||
mContainerView(aContainerView) {}
|
||||
NSView* aContainerView);
|
||||
|
||||
~VibrancyManager();
|
||||
|
||||
/**
|
||||
* Update the placement of the NSVisualEffectViews inside the container
|
||||
@ -66,26 +66,10 @@ class VibrancyManager {
|
||||
bool UpdateVibrantRegion(VibrancyType aType,
|
||||
const LayoutDeviceIntRegion& aRegion);
|
||||
|
||||
bool HasVibrantRegions() { return !mVibrantRegions.IsEmpty(); }
|
||||
|
||||
LayoutDeviceIntRegion GetUnionOfVibrantRegions() const;
|
||||
|
||||
/**
|
||||
* Create an NSVisualEffectView for the specified vibrancy type. The return
|
||||
* value is not autoreleased. We return an object of type NSView* because we
|
||||
* compile with an SDK that does not contain a definition for
|
||||
* NSVisualEffectView.
|
||||
* @param aIsContainer Whether this NSView will have child views. This value
|
||||
* affects hit testing: Container views will pass through
|
||||
* hit testing requests to their children, and leaf views
|
||||
* will be transparent to hit testing.
|
||||
*/
|
||||
static NSView* CreateEffectView(VibrancyType aType, BOOL aIsContainer = NO);
|
||||
|
||||
protected:
|
||||
const nsChildView& mCoordinateConverter;
|
||||
NSView* mContainerView;
|
||||
nsClassHashtable<nsUint32HashKey, ViewRegion> mVibrantRegions;
|
||||
EnumeratedArray<VibrancyType, UniquePtr<ViewRegion>> mVibrantRegions;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -5,6 +5,9 @@
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "VibrancyManager.h"
|
||||
#include "ViewRegion.h"
|
||||
#include "nsRegion.h"
|
||||
#include "ViewRegion.h"
|
||||
|
||||
#import <objc/message.h>
|
||||
|
||||
@ -20,18 +23,10 @@ using namespace mozilla;
|
||||
vibrancyType:(VibrancyType)aVibrancyType;
|
||||
@end
|
||||
|
||||
@interface MOZVibrantLeafView : MOZVibrantView
|
||||
@end
|
||||
|
||||
static NSVisualEffectState VisualEffectStateForVibrancyType(
|
||||
VibrancyType aType) {
|
||||
switch (aType) {
|
||||
case VibrancyType::TOOLTIP:
|
||||
case VibrancyType::MENU:
|
||||
// Tooltip and menu windows are never "key", so we need to tell the
|
||||
// vibrancy effect to look active regardless of window state.
|
||||
return NSVisualEffectStateActive;
|
||||
case VibrancyType::TITLEBAR:
|
||||
case VibrancyType::Titlebar:
|
||||
break;
|
||||
}
|
||||
return NSVisualEffectStateFollowsWindowActiveState;
|
||||
@ -40,11 +35,7 @@ static NSVisualEffectState VisualEffectStateForVibrancyType(
|
||||
static NSVisualEffectMaterial VisualEffectMaterialForVibrancyType(
|
||||
VibrancyType aType) {
|
||||
switch (aType) {
|
||||
case VibrancyType::TOOLTIP:
|
||||
return (NSVisualEffectMaterial)NSVisualEffectMaterialToolTip;
|
||||
case VibrancyType::MENU:
|
||||
return NSVisualEffectMaterialMenu;
|
||||
case VibrancyType::TITLEBAR:
|
||||
case VibrancyType::Titlebar:
|
||||
return NSVisualEffectMaterialTitlebar;
|
||||
}
|
||||
}
|
||||
@ -52,10 +43,7 @@ static NSVisualEffectMaterial VisualEffectMaterialForVibrancyType(
|
||||
static NSVisualEffectBlendingMode VisualEffectBlendingModeForVibrancyType(
|
||||
VibrancyType aType) {
|
||||
switch (aType) {
|
||||
case VibrancyType::TOOLTIP:
|
||||
case VibrancyType::MENU:
|
||||
return NSVisualEffectBlendingModeBehindWindow;
|
||||
case VibrancyType::TITLEBAR:
|
||||
case VibrancyType::Titlebar:
|
||||
return StaticPrefs::widget_macos_titlebar_blend_mode_behind_window()
|
||||
? NSVisualEffectBlendingModeBehindWindow
|
||||
: NSVisualEffectBlendingModeWithinWindow;
|
||||
@ -63,7 +51,6 @@ static NSVisualEffectBlendingMode VisualEffectBlendingModeForVibrancyType(
|
||||
}
|
||||
|
||||
@implementation MOZVibrantView
|
||||
|
||||
- (instancetype)initWithFrame:(NSRect)aRect vibrancyType:(VibrancyType)aType {
|
||||
self = [super initWithFrame:aRect];
|
||||
mType = aType;
|
||||
@ -76,50 +63,31 @@ static NSVisualEffectBlendingMode VisualEffectBlendingModeForVibrancyType(
|
||||
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 NO;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
VibrancyManager::VibrancyManager(const nsChildView& aCoordinateConverter,
|
||||
NSView* aContainerView)
|
||||
: mCoordinateConverter(aCoordinateConverter),
|
||||
mContainerView(aContainerView) {}
|
||||
|
||||
VibrancyManager::~VibrancyManager() = default;
|
||||
|
||||
bool VibrancyManager::UpdateVibrantRegion(
|
||||
VibrancyType aType, const LayoutDeviceIntRegion& aRegion) {
|
||||
auto& slot = mVibrantRegions[aType];
|
||||
if (aRegion.IsEmpty()) {
|
||||
return mVibrantRegions.Remove(uint32_t(aType));
|
||||
bool hadRegion = !!slot;
|
||||
slot = nullptr;
|
||||
return hadRegion;
|
||||
}
|
||||
auto& vr = *mVibrantRegions.GetOrInsertNew(uint32_t(aType));
|
||||
return vr.UpdateRegion(aRegion, mCoordinateConverter, mContainerView, ^() {
|
||||
return CreateEffectView(aType);
|
||||
if (!slot) {
|
||||
slot = MakeUnique<ViewRegion>();
|
||||
}
|
||||
return slot->UpdateRegion(aRegion, mCoordinateConverter, mContainerView, ^() {
|
||||
return [[MOZVibrantView alloc] initWithFrame:NSZeroRect vibrancyType:aType];
|
||||
});
|
||||
}
|
||||
|
||||
LayoutDeviceIntRegion VibrancyManager::GetUnionOfVibrantRegions() const {
|
||||
LayoutDeviceIntRegion result;
|
||||
for (const auto& region : mVibrantRegions.Values()) {
|
||||
result.OrWith(region->Region());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* static */ NSView* VibrancyManager::CreateEffectView(VibrancyType aType,
|
||||
BOOL aIsContainer) {
|
||||
return aIsContainer ? [[MOZVibrantView alloc] initWithFrame:NSZeroRect
|
||||
vibrancyType:aType]
|
||||
: [[MOZVibrantLeafView alloc] initWithFrame:NSZeroRect
|
||||
vibrancyType:aType];
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
#define ViewRegion_h
|
||||
|
||||
#include "Units.h"
|
||||
#include "nsRegion.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
class nsChildView;
|
||||
|
@ -1726,32 +1726,52 @@ static Maybe<VibrancyType> ThemeGeometryTypeToVibrancyType(
|
||||
nsITheme::ThemeGeometryType aThemeGeometryType) {
|
||||
switch (aThemeGeometryType) {
|
||||
case eThemeGeometryTypeTitlebar:
|
||||
return Some(VibrancyType::TITLEBAR);
|
||||
return Some(VibrancyType::Titlebar);
|
||||
default:
|
||||
return Nothing();
|
||||
}
|
||||
}
|
||||
|
||||
static LayoutDeviceIntRegion GatherVibrantRegion(
|
||||
const nsTArray<nsIWidget::ThemeGeometry>& aThemeGeometries,
|
||||
VibrancyType aVibrancyType) {
|
||||
LayoutDeviceIntRegion region;
|
||||
static EnumeratedArray<VibrancyType, LayoutDeviceIntRegion>
|
||||
GatherVibrantRegions(Span<const nsIWidget::ThemeGeometry> aThemeGeometries) {
|
||||
EnumeratedArray<VibrancyType, LayoutDeviceIntRegion> regions;
|
||||
for (const auto& geometry : aThemeGeometries) {
|
||||
if (ThemeGeometryTypeToVibrancyType(geometry.mType) ==
|
||||
Some(aVibrancyType)) {
|
||||
region.OrWith(geometry.mRect);
|
||||
auto vibrancyType = ThemeGeometryTypeToVibrancyType(geometry.mType);
|
||||
if (!vibrancyType) {
|
||||
continue;
|
||||
}
|
||||
regions[*vibrancyType].OrWith(geometry.mRect);
|
||||
}
|
||||
return regions;
|
||||
}
|
||||
|
||||
// Subtracts parts from regions in such a way that they don't have any overlap.
|
||||
// Each region in the argument list will have the union of all the regions
|
||||
// *following* it subtracted from itself. In other words, the arguments are
|
||||
// treated as low priority to high priority.
|
||||
static void MakeRegionsNonOverlapping(Span<LayoutDeviceIntRegion> aRegions) {
|
||||
LayoutDeviceIntRegion unionOfAll;
|
||||
for (auto& region : aRegions) {
|
||||
region.SubOut(unionOfAll);
|
||||
unionOfAll.OrWith(region);
|
||||
}
|
||||
return region;
|
||||
}
|
||||
|
||||
void nsChildView::UpdateVibrancy(
|
||||
const nsTArray<ThemeGeometry>& aThemeGeometries) {
|
||||
LayoutDeviceIntRegion titlebarRegion =
|
||||
GatherVibrantRegion(aThemeGeometries, VibrancyType::TITLEBAR);
|
||||
auto regions = GatherVibrantRegions(aThemeGeometries);
|
||||
MakeRegionsNonOverlapping(Span(regions.begin(), regions.end()));
|
||||
|
||||
auto& vm = EnsureVibrancyManager();
|
||||
bool changed = vm.UpdateVibrantRegion(VibrancyType::TITLEBAR, titlebarRegion);
|
||||
bool changed = false;
|
||||
|
||||
// EnumeratedArray doesn't have an iterator that also yields the enum type,
|
||||
// but we rely on VibrancyType being contiguous and starting at 0, so we can
|
||||
// do that manually.
|
||||
size_t i = 0;
|
||||
for (const auto& region : regions) {
|
||||
changed |= vm.UpdateVibrantRegion(VibrancyType(i++), region);
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
SuspendAsyncCATransactions();
|
||||
|
@ -3071,10 +3071,6 @@ static NSMutableSet* gSwizzledFrameViewClasses = nil;
|
||||
- (void)_setNeedsDisplayInRect:(NSRect)aRect;
|
||||
@end
|
||||
|
||||
@interface NSView (NSVisualEffectViewSetMaskImage)
|
||||
- (void)setMaskImage:(NSImage*)image;
|
||||
@end
|
||||
|
||||
@interface BaseWindow (Private)
|
||||
- (void)removeTrackingArea;
|
||||
- (void)cursorUpdated:(NSEvent*)aEvent;
|
||||
@ -3174,35 +3170,38 @@ static NSImage* GetMenuMaskImage() {
|
||||
return maskImage;
|
||||
}
|
||||
|
||||
- (void)swapOutChildViewWrapper:(NSView*)aNewWrapper {
|
||||
aNewWrapper.frame = self.contentView.frame;
|
||||
// Add an effect view wrapper if needed so that the OS draws the appropriate
|
||||
// vibrancy effect and window border.
|
||||
- (void)setEffectViewWrapperForStyle:(WindowShadow)aStyle {
|
||||
NSView* wrapper = [&]() -> NSView* {
|
||||
if (aStyle == WindowShadow::Menu || aStyle == WindowShadow::Tooltip) {
|
||||
const bool isMenu = aStyle == WindowShadow::Menu;
|
||||
auto* effectView =
|
||||
[[NSVisualEffectView alloc] initWithFrame:self.contentView.frame];
|
||||
effectView.material =
|
||||
isMenu ? NSVisualEffectMaterialMenu : NSVisualEffectMaterialToolTip;
|
||||
// Tooltip and menu windows are never "key", so we need to tell the
|
||||
// vibrancy effect to look active regardless of window state.
|
||||
effectView.state = NSVisualEffectStateActive;
|
||||
effectView.blendingMode = NSVisualEffectBlendingModeBehindWindow;
|
||||
if (isMenu) {
|
||||
// Turn on rounded corner masking.
|
||||
effectView.maskImage = GetMenuMaskImage();
|
||||
}
|
||||
return effectView;
|
||||
}
|
||||
return [[NSView alloc] initWithFrame:self.contentView.frame];
|
||||
}();
|
||||
|
||||
wrapper.wantsLayer = YES;
|
||||
// Swap out our content view by the new view. Setting .contentView releases
|
||||
// the old view.
|
||||
NSView* childView = [self.mainChildView retain];
|
||||
[childView removeFromSuperview];
|
||||
[aNewWrapper addSubview:childView];
|
||||
[wrapper addSubview:childView];
|
||||
[childView release];
|
||||
[super setContentView:aNewWrapper];
|
||||
}
|
||||
|
||||
- (void)setEffectViewWrapperForStyle:(WindowShadow)aStyle {
|
||||
if (aStyle == WindowShadow::Menu || aStyle == WindowShadow::Tooltip) {
|
||||
// Add an effect view wrapper so that the OS draws the appropriate
|
||||
// vibrancy effect and window border.
|
||||
BOOL isMenu = aStyle == WindowShadow::Menu;
|
||||
NSView* effectView = VibrancyManager::CreateEffectView(
|
||||
isMenu ? VibrancyType::MENU : VibrancyType::TOOLTIP, YES);
|
||||
if (isMenu) {
|
||||
// Turn on rounded corner masking.
|
||||
[effectView setMaskImage:GetMenuMaskImage()];
|
||||
}
|
||||
[self swapOutChildViewWrapper:effectView];
|
||||
[effectView release];
|
||||
} else {
|
||||
// Remove the existing wrapper.
|
||||
NSView* wrapper = [[NSView alloc] initWithFrame:NSZeroRect];
|
||||
[wrapper setWantsLayer:YES];
|
||||
[self swapOutChildViewWrapper:wrapper];
|
||||
[wrapper release];
|
||||
}
|
||||
super.contentView = wrapper;
|
||||
[wrapper release];
|
||||
}
|
||||
|
||||
- (NSTouchBar*)makeTouchBar {
|
||||
|
Loading…
Reference in New Issue
Block a user