gecko-dev/widget/cocoa/VibrancyManager.h
Markus Stange a0e9560488 Bug 1370040 - Use the public API -[NSVisualEffectView setMaskImage:] instead of the private API -[NSWindow _cornerMask]. r=spohl
The idea is the following:
Behind-window vibrancy is mostly rendered by the window server. For a given
vibrant region of a window, the window server renders a vibrancy "backdrop",
which is a blurred version of everything that's behind that region, modified
with a color tint and blended in some way. Then it puts our actual window
contents on top of that background.
The backdrop's shape is usually a rectangle. If we don't want it to be a
rectangle, we need to tell the window server about the shape that we want it to
be. We can't just "draw" a different shape in our own rendering, because our
own rendering is merely placed on top of the backdrop - but here we want to
modify the shape of the backdrop itself.

NSVisualEffectView lets us set a mask image on the view. If this view is the
content view of a window, then the view will automatically communicate the mask
image to the window server.

Traditionally, our popup windows have had a ChildView as their content view. If
we now want an NSVisualEffectView to be the content view of the window, then we
need to nest the ChildView inside that NSVisualEffectView.
But this NSVisualEffectView is only needed when the window is vibrant and the
vibrancy backdrop needs to have a certain shape. This is the case for our menus
which need to have rounded corners. If the window transitions to being
non-vibrant, or not needing a special shape, then we can go back to the way our
window's NSView hierarchy has worked traditionally. So we need to reparent
NSViews during those transitions.

MozReview-Commit-ID: Bo2VzjhhR0A

--HG--
extra : rebase_source : 9eb463cc68c16c3b9281b57455330969c5e2642c
2017-11-19 18:38:35 -05:00

126 lines
4.5 KiB
Objective-C

/* -*- 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 "nsClassHashtable.h"
#include "nsRegion.h"
#include "nsTArray.h"
#include "ViewRegion.h"
#import <Foundation/NSGeometry.h>
@class NSColor;
@class NSView;
class nsChildView;
namespace mozilla {
enum class VibrancyType {
LIGHT,
DARK,
TOOLTIP,
MENU,
HIGHLIGHTED_MENUITEM,
SHEET,
SOURCE_LIST,
SOURCE_LIST_SELECTION,
ACTIVE_SOURCE_LIST_SELECTION
};
/**
* 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 LayoutDeviceIntRegion& aRegion);
bool HasVibrantRegions() { return !mVibrantRegions.IsEmpty(); }
/**
* 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;
/**
* Return the fill color that should be drawn on top of the cleared window
* parts. Usually this would be drawn by -[NSVisualEffectView drawRect:].
* The returned color is opaque if the system-wide "Reduce transparency"
* preference is set.
*/
NSColor* VibrancyFillColorForType(VibrancyType aType);
/**
* 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();
/**
* 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:
void ClearVibrantRegion(const LayoutDeviceIntRegion& aVibrantRegion) const;
const nsChildView& mCoordinateConverter;
NSView* mContainerView;
nsClassHashtable<nsUint32HashKey, ViewRegion> mVibrantRegions;
};
} // namespace mozilla
#endif // VibrancyManager_h