Bug 1700051: part 28) Refactor `WordSplitState<T>::GetDOMWordSeparatorOffset` to...
[gecko.git] / widget / cocoa / VibrancyManager.mm
blob4044d8a2ebb5298f22572d9467733150070323d7
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5  * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "VibrancyManager.h"
9 #import <objc/message.h>
11 #include "nsChildView.h"
12 #include "nsCocoaFeatures.h"
13 #include "SDKDeclarations.h"
15 using namespace mozilla;
17 @interface MOZVibrantView : NSVisualEffectView {
18   VibrancyType mType;
20 - (instancetype)initWithFrame:(NSRect)aRect vibrancyType:(VibrancyType)aVibrancyType;
21 @end
23 @interface MOZVibrantLeafView : MOZVibrantView
24 @end
26 static NSAppearance* AppearanceForVibrancyType(VibrancyType aType) {
27   if (@available(macOS 10.14, *)) {
28     switch (aType) {
29       case VibrancyType::TITLEBAR_LIGHT:
30         // This must always be light (regular aqua), regardless of window appearance.
31         return [NSAppearance appearanceNamed:NSAppearanceNameAqua];
32       case VibrancyType::TITLEBAR_DARK:
33         // This must always be dark (dark aqua), regardless of window appearance.
34         return [NSAppearance appearanceNamed:NSAppearanceNameDarkAqua];
35       case VibrancyType::TOOLTIP:
36       case VibrancyType::MENU:
37       case VibrancyType::HIGHLIGHTED_MENUITEM:
38       case VibrancyType::SOURCE_LIST:
39       case VibrancyType::SOURCE_LIST_SELECTION:
40       case VibrancyType::ACTIVE_SOURCE_LIST_SELECTION:
41         // Inherit the appearance from the window. If the window is using Dark Mode, the vibrancy
42         // will automatically be dark, too. This is available starting with macOS 10.14.
43         return nil;
44     }
45   }
47   // For 10.13 and below, a vibrant appearance name must be used. There is no system dark mode and
48   // no automatic adaptation to the window; all windows are light.
49   switch (aType) {
50     case VibrancyType::TITLEBAR_LIGHT:
51     case VibrancyType::TOOLTIP:
52     case VibrancyType::MENU:
53     case VibrancyType::HIGHLIGHTED_MENUITEM:
54     case VibrancyType::SOURCE_LIST:
55     case VibrancyType::SOURCE_LIST_SELECTION:
56     case VibrancyType::ACTIVE_SOURCE_LIST_SELECTION:
57       return [NSAppearance appearanceNamed:NSAppearanceNameVibrantLight];
58     case VibrancyType::TITLEBAR_DARK:
59       return [NSAppearance appearanceNamed:NSAppearanceNameVibrantDark];
60   }
63 static NSVisualEffectState VisualEffectStateForVibrancyType(VibrancyType aType) {
64   switch (aType) {
65     case VibrancyType::TOOLTIP:
66     case VibrancyType::MENU:
67     case VibrancyType::HIGHLIGHTED_MENUITEM:
68       // Tooltip and menu windows are never "key", so we need to tell the vibrancy effect to look
69       // active regardless of window state.
70       return NSVisualEffectStateActive;
71     default:
72       return NSVisualEffectStateFollowsWindowActiveState;
73   }
76 static NSVisualEffectMaterial VisualEffectMaterialForVibrancyType(VibrancyType aType,
77                                                                   BOOL* aOutIsEmphasized) {
78   switch (aType) {
79     case VibrancyType::TITLEBAR_LIGHT:
80     case VibrancyType::TITLEBAR_DARK:
81       return NSVisualEffectMaterialTitlebar;
82     case VibrancyType::TOOLTIP:
83       if (@available(macOS 10.14, *)) {
84         return (NSVisualEffectMaterial)NSVisualEffectMaterialToolTip;
85       } else {
86         return NSVisualEffectMaterialMenu;
87       }
88     case VibrancyType::MENU:
89       return NSVisualEffectMaterialMenu;
90     case VibrancyType::SOURCE_LIST:
91       return NSVisualEffectMaterialSidebar;
92     case VibrancyType::SOURCE_LIST_SELECTION:
93       return NSVisualEffectMaterialSelection;
94     case VibrancyType::HIGHLIGHTED_MENUITEM:
95     case VibrancyType::ACTIVE_SOURCE_LIST_SELECTION:
96       *aOutIsEmphasized = YES;
97       return NSVisualEffectMaterialSelection;
98   }
101 static BOOL HasVibrantForeground(VibrancyType aType) {
102   switch (aType) {
103     case VibrancyType::MENU:
104       return YES;
105     default:
106       return NO;
107   }
110 @implementation MOZVibrantView
112 - (instancetype)initWithFrame:(NSRect)aRect vibrancyType:(VibrancyType)aType {
113   self = [super initWithFrame:aRect];
114   mType = aType;
116   self.appearance = AppearanceForVibrancyType(mType);
117   self.state = VisualEffectStateForVibrancyType(mType);
119   BOOL isEmphasized = NO;
120   self.material = VisualEffectMaterialForVibrancyType(mType, &isEmphasized);
121   self.emphasized = isEmphasized;
123   return self;
126 // Don't override allowsVibrancy here, because this view may have subviews, and
127 // returning YES from allowsVibrancy forces on foreground vibrancy for all
128 // descendant views, which can have unintended effects.
130 @end
132 @implementation MOZVibrantLeafView
134 - (NSView*)hitTest:(NSPoint)aPoint {
135   // This view must be transparent to mouse events.
136   return nil;
139 // MOZVibrantLeafView does not have subviews, so we can return YES here without
140 // having unintended effects on other contents of the window.
141 - (BOOL)allowsVibrancy {
142   return HasVibrantForeground(mType);
145 @end
147 bool VibrancyManager::UpdateVibrantRegion(VibrancyType aType,
148                                           const LayoutDeviceIntRegion& aRegion) {
149   if (aRegion.IsEmpty()) {
150     return mVibrantRegions.Remove(uint32_t(aType));
151   }
152   auto& vr = *mVibrantRegions.GetOrInsertNew(uint32_t(aType));
153   return vr.UpdateRegion(aRegion, mCoordinateConverter, mContainerView, ^() {
154     return this->CreateEffectView(aType);
155   });
158 LayoutDeviceIntRegion VibrancyManager::GetUnionOfVibrantRegions() const {
159   LayoutDeviceIntRegion result;
160   for (const auto& region : mVibrantRegions.Values()) {
161     result.OrWith(region->Region());
162   }
163   return result;
166 /* static */ NSView* VibrancyManager::CreateEffectView(VibrancyType aType, BOOL aIsContainer) {
167   return aIsContainer ? [[MOZVibrantView alloc] initWithFrame:NSZeroRect vibrancyType:aType]
168                       : [[MOZVibrantLeafView alloc] initWithFrame:NSZeroRect vibrancyType:aType];