Fix macOS 11.0 Big Sur issues.

master
Fedor 2020-11-26 05:41:57 +02:00
parent 8cadc693be
commit 5136ec6010
12 changed files with 327 additions and 614 deletions

View File

@ -310,6 +310,9 @@ typedef long ssize_t;
#include <mach/mach_init.h>
#include <mach/vm_map.h>
#include <malloc/malloc.h>
#ifndef _pthread_self
#define _pthread_self() pthread_self()
#endif
#endif
#endif

View File

@ -776,6 +776,9 @@ pr_LoadLibraryByPathname(const char *name, PRIntn flags)
int dl_flags = 0;
#endif
void *h = NULL;
#if defined(DARWIN)
PRBool okToLoad = PR_FALSE;
#endif
if (flags & PR_LD_LAZY) {
dl_flags |= RTLD_LAZY;
@ -790,12 +793,36 @@ pr_LoadLibraryByPathname(const char *name, PRIntn flags)
dl_flags |= RTLD_LOCAL;
}
#if defined(DARWIN)
/* ensure the file exists if it contains a slash character i.e. path */
/* DARWIN's dlopen ignores the provided path and checks for the */
/* plain filename in DYLD_LIBRARY_PATH */
if (strchr(name, PR_DIRECTORY_SEPARATOR) == NULL ||
PR_Access(name, PR_ACCESS_EXISTS) == PR_SUCCESS) {
h = dlopen(name, dl_flags);
/* If the file contains an absolute or relative path (slash)
* and the path doesn't look like a System path, then require
* the file exists.
* The reason is that DARWIN's dlopen ignores the provided path
* and checks for the plain filename in DYLD_LIBRARY_PATH,
* which could load an unexpected version of a library. */
if (strchr(name, PR_DIRECTORY_SEPARATOR) == NULL) {
/* no slash, allow to load from any location */
okToLoad = PR_TRUE;
} else {
const char systemPrefix1[] = "/System/";
const size_t systemPrefixLen1 = strlen(systemPrefix1);
const char systemPrefix2[] = "/usr/lib/";
const size_t systemPrefixLen2 = strlen(systemPrefix2);
const name_len = strlen(name);
if (((name_len > systemPrefixLen1) &&
(strncmp(name, systemPrefix1, systemPrefixLen1) == 0)) ||
((name_len > systemPrefixLen2) &&
(strncmp(name, systemPrefix2, systemPrefixLen2) == 0))) {
/* found at beginning, it's a system library.
* Skip filesystem check (required for macOS 11),
* allow loading from any location */
okToLoad = PR_TRUE;
} else if (PR_Access(name, PR_ACCESS_EXISTS) == PR_SUCCESS) {
/* file exists, allow to load */
okToLoad = PR_TRUE;
}
}
if (okToLoad) {
h = dlopen(name, dl_flags);
}
#else
h = dlopen(name, dl_flags);

View File

@ -76,14 +76,6 @@ public:
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:].
@ -105,10 +97,19 @@ public:
*/
static bool SystemSupportsVibrancy();
protected:
void ClearVibrantRegion(const LayoutDeviceIntRegion& aVibrantRegion) const;
NSView* CreateEffectView(VibrancyType aType);
/**
* 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;

View File

@ -23,24 +23,6 @@ VibrancyManager::UpdateVibrantRegion(VibrancyType aType,
});
}
void
VibrancyManager::ClearVibrantAreas() const
{
for (auto iter = mVibrantRegions.ConstIter(); !iter.Done(); iter.Next()) {
ClearVibrantRegion(iter.UserData()->Region());
}
}
void
VibrancyManager::ClearVibrantRegion(const LayoutDeviceIntRegion& aVibrantRegion) const
{
[[NSColor clearColor] set];
for (auto iter = aVibrantRegion.RectIter(); !iter.Done(); iter.Next()) {
NSRectFill(mCoordinateConverter.DevPixelsToCocoaPoints(iter.Get()));
}
}
@interface NSView(CurrentFillColor)
- (NSColor*)_currentFillColor;
@end
@ -64,9 +46,8 @@ VibrancyManager::VibrancyFillColorForType(VibrancyType aType)
NSView* view = mVibrantRegions.LookupOrAdd(uint32_t(aType))->GetAnyView();
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.
// -[NSVisualEffectView _currentFillColor] is the color that the view
// draws in its drawRect implementation.
return AdjustedColor([view _currentFillColor], aType);
}
return [NSColor whiteColor];
@ -87,19 +68,6 @@ VibrancyManager::VibrancyFontSmoothingBackgroundColorForType(VibrancyType aType)
return [NSColor clearColor];
}
static void
DrawRectNothing(id self, SEL _cmd, NSRect aRect)
{
// The super implementation would clear the background.
// That's fine for views that are placed below their content, but our
// setup is different: Our drawn content is drawn to mContainerView, which
// sits below this EffectView. So we must not clear the background here,
// because we'd erase that drawn content.
// Of course the regular content drawing still needs to clear the background
// behind vibrant areas. This is taken care of by having nsNativeThemeCocoa
// return true from NeedToClearBackgroundBehindWidget for vibrant widgets.
}
static NSView*
HitTestNil(id self, SEL _cmd, NSPoint aPoint)
{
@ -115,21 +83,20 @@ AllowsVibrancyYes(id self, SEL _cmd)
}
static Class
CreateEffectViewClass(BOOL aForegroundVibrancy)
CreateEffectViewClass(BOOL aForegroundVibrancy, BOOL aIsContainer)
{
// Create a class called EffectView that inherits from NSVisualEffectView
// and overrides the methods -[NSVisualEffectView drawRect:] and
// -[NSView hitTest:].
// 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);
class_addMethod(EffectViewClass, @selector(drawRect:), (IMP)DrawRectNothing,
"v@:{CGRect={CGPoint=dd}{CGSize=dd}}");
class_addMethod(EffectViewClass, @selector(hitTest:), (IMP)HitTestNil,
"@@:{CGPoint=dd}");
if (!aIsContainer) {
class_addMethod(EffectViewClass, @selector(hitTest:), (IMP)HitTestNil,
"@@:{CGPoint=dd}");
}
if (aForegroundVibrancy) {
// Also override the -[NSView allowsVibrancy] method to return YES.
// Override the -[NSView allowsVibrancy] method to return YES.
class_addMethod(EffectViewClass, @selector(allowsVibrancy), (IMP)AllowsVibrancyYes, "I@:");
}
return EffectViewClass;
@ -216,13 +183,20 @@ enum {
@end
NSView*
VibrancyManager::CreateEffectView(VibrancyType aType)
VibrancyManager::CreateEffectView(VibrancyType aType, BOOL aIsContainer)
{
static Class EffectViewClassWithoutForegroundVibrancy = CreateEffectViewClass(NO);
static Class EffectViewClassWithForegroundVibrancy = CreateEffectViewClass(YES);
static Class EffectViewWithoutForegroundVibrancy = CreateEffectViewClass(NO, NO);
static Class EffectViewWithForegroundVibrancy = CreateEffectViewClass(YES, NO);
static Class EffectViewContainer = CreateEffectViewClass(NO, YES);
Class EffectViewClass = HasVibrantForeground(aType)
? EffectViewClassWithForegroundVibrancy : EffectViewClassWithoutForegroundVibrancy;
// 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)];

View File

@ -34,11 +34,6 @@ class TextInputHandler;
// return a context menu for this view
- (NSMenu*)contextMenu;
// Allows callers to do a delayed invalidate (e.g., if an invalidate
// happens during drawing)
- (void)setNeedsPendingDisplay;
- (void)setNeedsPendingDisplayInRect:(NSRect)invalidRect;
// called when our corresponding Gecko view goes away
- (void)widgetDestroyed;

View File

@ -56,6 +56,8 @@ class WidgetRenderingContext;
} // namespace widget
} // namespace mozilla
@class PixelHostingView;
@interface NSEvent (Undocumented)
// Return Cocoa event's corresponding Carbon event. Not initialized (on
@ -139,11 +141,6 @@ class WidgetRenderingContext;
// when acceptsFirstMouse: is called, we store the event here (strong)
NSEvent* mClickThroughMouseDownEvent;
// rects that were invalidated during a draw, so have pending drawing
NSMutableArray* mPendingDirtyRects;
BOOL mPendingFullDisplay;
BOOL mPendingDisplay;
// WheelStart/Stop events should always come in pairs. This BOOL records the
// last received event so that, when we receive one of the events, we make sure
// to send its pair event first, in case we didn't yet for any reason.
@ -185,8 +182,6 @@ class WidgetRenderingContext;
float mCumulativeMagnification;
float mCumulativeRotation;
BOOL mWaitingForPaint;
#ifdef __LP64__
// Support for fluid swipe tracking.
BOOL* mCancelSwipeAnimation;
@ -198,6 +193,15 @@ class WidgetRenderingContext;
// The mask image that's used when painting into the titlebar using basic
// CGContext painting (i.e. non-accelerated).
CGImageRef mTopLeftCornerMask;
// Subviews of self, which act as container views for vibrancy views and
// non-draggable views.
NSView* mVibrancyViewsContainer; // [STRONG]
NSView* mNonDraggableViewsContainer; // [STRONG]
// The view that does our drawing. This is a subview of self so that it can
// be ordered on top of mVibrancyViewsContainer.
PixelHostingView* mPixelHostingView;
}
// class initialization
@ -226,6 +230,10 @@ class WidgetRenderingContext;
- (bool)preRender:(NSOpenGLContext *)aGLContext;
- (void)postRender:(NSOpenGLContext *)aGLContext;
- (NSView*)vibrancyViewsContainer;
- (NSView*)nonDraggableViewsContainer;
- (NSView*)pixelHostingView;
- (BOOL)isCoveringTitlebar;
- (void)viewWillStartLiveResize;
@ -252,7 +260,6 @@ class WidgetRenderingContext;
- (void)endGestureWithEvent:(NSEvent *)anEvent;
- (void)scrollWheel:(NSEvent *)anEvent;
- (void)handleAsyncScrollEvent:(CGEventRef)cgEvent ofType:(CGEventType)type;
- (void)setUsingOMTCompositor:(BOOL)aUseOMTC;
@ -507,8 +514,6 @@ public:
void CleanupRemoteDrawing() override;
bool InitCompositor(mozilla::layers::Compositor* aCompositor) override;
IAPZCTreeManager* APZCTM() { return mAPZC ; }
NS_IMETHOD StartPluginIME(const mozilla::WidgetKeyboardEvent& aKeyboardEvent,
int32_t aPanelX, int32_t aPanelY,
nsString& aCommitted) override;
@ -529,9 +534,6 @@ protected:
void ReportMoveEvent();
void ReportSizeEvent();
// override to create different kinds of child views. Autoreleases, so
// caller must retain.
virtual NSView* CreateCocoaView(NSRect inFrame);
void TearDownView();
virtual already_AddRefed<nsIWidget>
@ -574,7 +576,7 @@ protected:
protected:
NSView<mozView>* mView; // my parallel cocoa view (ChildView or NativeScrollbarView), [STRONG]
ChildView<mozView>* mView; // my parallel cocoa view, [STRONG]
RefPtr<mozilla::widget::TextInputHandler> mTextInputHandler;
InputContext mInputContext;

View File

@ -146,7 +146,10 @@ bool gUserCancelledDrag = false;
uint32_t nsChildView::sLastInputEventCount = 0;
static uint32_t gNumberOfWidgetsNeedingEventThread = 0;
// The view that will do our drawing or host our NSOpenGLContext or Core Animation layer.
@interface PixelHostingView : NSView {
}
@end
@interface ChildView(Private)
@ -163,14 +166,9 @@ static uint32_t gNumberOfWidgetsNeedingEventThread = 0;
- (BOOL)isRectObscuredBySubview:(NSRect)inRect;
- (void)processPendingRedraws;
- (void)drawRect:(NSRect)aRect inContext:(CGContextRef)aContext;
- (LayoutDeviceIntRegion)nativeDirtyRegionWithBoundingRect:(NSRect)aRect;
- (BOOL)isUsingMainThreadOpenGL;
- (BOOL)isUsingOpenGL;
- (void)drawUsingOpenGL;
- (void)drawUsingOpenGLCallback;
- (BOOL)hasRoundedBottomCorners;
- (CGFloat)cornerRadius;
@ -195,7 +193,6 @@ static uint32_t gNumberOfWidgetsNeedingEventThread = 0;
- (LayoutDeviceIntPoint)convertWindowCoordinates:(NSPoint)aPoint;
- (LayoutDeviceIntPoint)convertWindowCoordinatesRoundDown:(NSPoint)aPoint;
- (IAPZCTreeManager*)apzctm;
- (BOOL)inactiveWindowAcceptsMouseEvent:(NSEvent*)aEvent;
- (void)updateWindowDraggableState;
@ -204,26 +201,10 @@ static uint32_t gNumberOfWidgetsNeedingEventThread = 0;
@end
@interface EventThreadRunner : NSObject
{
NSThread* mThread;
}
- (id)init;
+ (void)start;
+ (void)stop;
@end
@interface NSView(NSThemeFrameCornerRadius)
- (float)roundedCornerRadius;
@end
@interface NSView(DraggableRegion)
- (CGSRegionObj)_regionForOpaqueDescendants:(NSRect)aRect forMove:(BOOL)aForMove;
- (CGSRegionObj)_regionForOpaqueDescendants:(NSRect)aRect forMove:(BOOL)aForMove forUnderTitlebar:(BOOL)aForUnderTitlebar;
@end
@interface NSWindow(NSWindowShouldZoomOnDoubleClick)
+ (BOOL)_shouldZoomOnDoubleClick; // present on 10.7 and above
@end
@ -380,13 +361,6 @@ nsChildView::~nsChildView()
DestroyCompositor();
if (mAPZC && gfxPrefs::AsyncPanZoomSeparateEventThread()) {
gNumberOfWidgetsNeedingEventThread--;
if (gNumberOfWidgetsNeedingEventThread == 0) {
[EventThreadRunner stop];
}
}
// An nsChildView object that was in use can be destroyed without Destroy()
// ever being called on it. So we also need to do a quick, safe cleanup
// here (it's too late to just call Destroy(), which can cause crashes).
@ -455,7 +429,8 @@ nsChildView::Create(nsIWidget* aParent,
// that NS_NATIVE_WIDGET is the NSView.
CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(mParentView);
NSRect r = nsCocoaUtils::DevPixelsToCocoaPoints(mBounds, scaleFactor);
mView = [(NSView<mozView>*)CreateCocoaView(r) retain];
mView = [[[[ChildView alloc] initWithFrame:r geckoChild:this] autorelease] retain];
if (!mView) {
return NS_ERROR_FAILURE;
}
@ -488,17 +463,6 @@ nsChildView::Create(nsIWidget* aParent,
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
}
// Creates the appropriate child view. Override to create something other than
// our |ChildView| object. Autoreleases, so caller must retain.
NSView*
nsChildView::CreateCocoaView(NSRect inFrame)
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
return [[[ChildView alloc] initWithFrame:inFrame geckoChild:this] autorelease];
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
}
void nsChildView::TearDownView()
{
@ -982,8 +946,9 @@ NS_IMETHODIMP nsChildView::Resize(double aWidth, double aHeight, bool aRepaint)
[mView setFrame:DevPixelsToCocoaPoints(mBounds)];
});
if (mVisible && aRepaint)
[mView setNeedsDisplay:YES];
if (mVisible && aRepaint) {
[[mView pixelHostingView] setNeedsDisplay:YES];
}
NotifyRollupGeometryChange();
ReportSizeEvent();
@ -1021,8 +986,9 @@ NS_IMETHODIMP nsChildView::Resize(double aX, double aY,
[mView setFrame:DevPixelsToCocoaPoints(mBounds)];
});
if (mVisible && aRepaint)
[mView setNeedsDisplay:YES];
if (mVisible && aRepaint) {
[[mView pixelHostingView] setNeedsDisplay:YES];
}
NotifyRollupGeometryChange();
if (isMoving) {
@ -1341,14 +1307,7 @@ NS_IMETHODIMP nsChildView::Invalidate(const LayoutDeviceIntRect& aRect)
NS_ASSERTION(GetLayerManager()->GetBackendType() != LayersBackend::LAYERS_CLIENT,
"Shouldn't need to invalidate with accelerated OMTC layers!");
if ([NSView focusView]) {
// if a view is focussed (i.e. being drawn), then postpone the invalidate so that we
// don't lose it.
[mView setNeedsPendingDisplayInRect:DevPixelsToCocoaPoints(aRect)];
}
else {
[mView setNeedsDisplayInRect:DevPixelsToCocoaPoints(aRect)];
}
[[mView pixelHostingView] setNeedsDisplayInRect:DevPixelsToCocoaPoints(aRect)];
return NS_OK;
@ -1920,13 +1879,6 @@ void
nsChildView::ConfigureAPZCTreeManager()
{
nsBaseWidget::ConfigureAPZCTreeManager();
if (gfxPrefs::AsyncPanZoomSeparateEventThread()) {
if (gNumberOfWidgetsNeedingEventThread == 0) {
[EventThreadRunner start];
}
gNumberOfWidgetsNeedingEventThread++;
}
}
void
@ -2557,14 +2509,6 @@ nsChildView::UpdateVibrancy(const nsTArray<ThemeGeometry>& aThemeGeometries)
vm.UpdateVibrantRegion(VibrancyType::DARK, vibrantDarkRegion);
}
void
nsChildView::ClearVibrantAreas()
{
if (VibrancyManager::SystemSupportsVibrancy()) {
EnsureVibrancyManager().ClearVibrantAreas();
}
}
static VibrancyType
ThemeGeometryTypeToVibrancyType(nsITheme::ThemeGeometryType aThemeGeometryType)
{
@ -2617,7 +2561,7 @@ nsChildView::EnsureVibrancyManager()
{
MOZ_ASSERT(mView, "Only call this once we have a view!");
if (!mVibrancyManager) {
mVibrancyManager = MakeUnique<VibrancyManager>(*this, mView);
mVibrancyManager = MakeUnique<VibrancyManager>(*this, [mView vibrancyViewsContainer]);
}
return *mVibrancyManager;
}
@ -2787,9 +2731,10 @@ nsChildView::UpdateWindowDraggingRegion(const LayoutDeviceIntRegion& aRegion)
// Suppress calls to setNeedsDisplay during NSView geometry changes.
ManipulateViewWithoutNeedingDisplay(mView, ^() {
changed = mNonDraggableRegion.UpdateRegion(nonDraggable, *this, mView, ^() {
return [[NonDraggableView alloc] initWithFrame:NSZeroRect];
});
changed = mNonDraggableRegion.UpdateRegion(
nonDraggable, *this, [mView nonDraggableViewsContainer], ^() {
return [[NonDraggableView alloc] initWithFrame:NSZeroRect];
});
});
if (changed) {
@ -3160,6 +3105,31 @@ private:
#pragma mark -
// ViewRegionContainerView is a view class for certain subviews of ChildView
// which contain the NSViews created for ViewRegions (see ViewRegion.h).
// It doesn't do anything interesting, it only acts as a container so that it's
// easier for ChildView to control the z order of its children.
@interface ViewRegionContainerView : NSView {
}
@end
@implementation ViewRegionContainerView
- (NSView*)hitTest:(NSPoint)aPoint {
return nil; // Be transparent to mouse events.
}
- (BOOL)isFlipped {
return [[self superview] isFlipped];
}
- (BOOL)mouseDownCanMoveWindow {
return [[self superview] mouseDownCanMoveWindow];
}
@end
;
@implementation ChildView
// globalDragPboard is non-null during native drag sessions that did not originate
@ -3215,7 +3185,6 @@ NSEvent* gLastDragMouseDownEvent = nil;
if ((self = [super initWithFrame:inFrame])) {
mGeckoChild = inChild;
mPendingDisplay = NO;
mBlockedLastMouseDown = NO;
mExpectingWheelStop = NO;
@ -3236,6 +3205,20 @@ NSEvent* gLastDragMouseDownEvent = nil;
mCancelSwipeAnimation = nil;
#endif
mNonDraggableViewsContainer = [[ViewRegionContainerView alloc] initWithFrame:[self bounds]];
mVibrancyViewsContainer = [[ViewRegionContainerView alloc] initWithFrame:[self bounds]];
[mNonDraggableViewsContainer setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
[mVibrancyViewsContainer setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
[self addSubview:mNonDraggableViewsContainer];
[self addSubview:mVibrancyViewsContainer];
mPixelHostingView = [[PixelHostingView alloc] initWithFrame:[self bounds]];
[mPixelHostingView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
[self addSubview:mPixelHostingView];
mTopLeftCornerMask = NULL;
}
@ -3250,10 +3233,9 @@ NSEvent* gLastDragMouseDownEvent = nil;
selector:@selector(systemMetricsChanged)
name:NSSystemColorsDidChangeNotification
object:nil];
// TODO: replace the string with the constant once we build with the 10.7 SDK
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(scrollbarSystemMetricChanged)
name:@"NSPreferredScrollerStyleDidChangeNotification"
name:NSPreferredScrollerStyleDidChangeNotification
object:nil];
[[NSDistributedNotificationCenter defaultCenter] addObserver:self
selector:@selector(systemMetricsChanged)
@ -3263,7 +3245,7 @@ NSEvent* gLastDragMouseDownEvent = nil;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(_surfaceNeedsUpdate:)
name:NSViewGlobalFrameDidChangeNotification
object:self];
object:mPixelHostingView];
return self;
@ -3348,12 +3330,23 @@ NSEvent* gLastDragMouseDownEvent = nil;
NS_OBJC_END_TRY_ABORT_BLOCK;
}
- (NSView*)vibrancyViewsContainer {
return mVibrancyViewsContainer;
}
- (NSView*)nonDraggableViewsContainer {
return mNonDraggableViewsContainer;
}
- (NSView*)pixelHostingView {
return mPixelHostingView;
}
- (void)dealloc
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
[mGLContext release];
[mPendingDirtyRects release];
[mLastMouseDownEvent release];
[mLastKeyDownEvent release];
[mClickThroughMouseDownEvent release];
@ -3362,6 +3355,12 @@ NSEvent* gLastDragMouseDownEvent = nil;
[[NSNotificationCenter defaultCenter] removeObserver:self];
[[NSDistributedNotificationCenter defaultCenter] removeObserver:self];
[mVibrancyViewsContainer removeFromSuperview];
[mVibrancyViewsContainer release];
[mNonDraggableViewsContainer removeFromSuperview];
[mNonDraggableViewsContainer release];
[mPixelHostingView removeFromSuperview];
[mPixelHostingView release];
[super dealloc];
@ -3408,82 +3407,6 @@ NSEvent* gLastDragMouseDownEvent = nil;
}
}
- (void)setNeedsPendingDisplay
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
mPendingFullDisplay = YES;
if (!mPendingDisplay) {
[self performSelector:@selector(processPendingRedraws) withObject:nil afterDelay:0];
mPendingDisplay = YES;
}
NS_OBJC_END_TRY_ABORT_BLOCK;
}
- (void)setNeedsPendingDisplayInRect:(NSRect)invalidRect
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
if (!mPendingDirtyRects)
mPendingDirtyRects = [[NSMutableArray alloc] initWithCapacity:1];
[mPendingDirtyRects addObject:[NSValue valueWithRect:invalidRect]];
if (!mPendingDisplay) {
[self performSelector:@selector(processPendingRedraws) withObject:nil afterDelay:0];
mPendingDisplay = YES;
}
NS_OBJC_END_TRY_ABORT_BLOCK;
}
// Clears the queue of any pending invalides
- (void)processPendingRedraws
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
if (mPendingFullDisplay) {
[self setNeedsDisplay:YES];
}
else if (mPendingDirtyRects) {
unsigned int count = [mPendingDirtyRects count];
for (unsigned int i = 0; i < count; ++i) {
[self setNeedsDisplayInRect:[[mPendingDirtyRects objectAtIndex:i] rectValue]];
}
}
mPendingFullDisplay = NO;
mPendingDisplay = NO;
[mPendingDirtyRects release];
mPendingDirtyRects = nil;
NS_OBJC_END_TRY_ABORT_BLOCK;
}
- (void)setNeedsDisplayInRect:(NSRect)aRect
{
if (![self isUsingOpenGL]) {
[super setNeedsDisplayInRect:aRect];
return;
}
if ([[self window] isVisible] && [self isUsingMainThreadOpenGL]) {
// Draw without calling drawRect. This prevent us from
// needing to access the normal window buffer surface unnecessarily, so we
// waste less time synchronizing the two surfaces. (These synchronizations
// show up in a profiler as CGSDeviceLock / _CGSLockWindow /
// _CGSSynchronizeWindowBackingStore.) It also means that Cocoa doesn't
// have any potentially expensive invalid rect management for us.
if (!mWaitingForPaint) {
mWaitingForPaint = YES;
// Use NSRunLoopCommonModes instead of the default NSDefaultRunLoopMode
// so that the timer also fires while a native menu is open.
[self performSelector:@selector(drawUsingOpenGLCallback)
withObject:nil
afterDelay:0
inModes:[NSArray arrayWithObject:NSRunLoopCommonModes]];
}
}
}
- (NSString*)description
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
@ -3537,25 +3460,6 @@ NSEvent* gLastDragMouseDownEvent = nil;
return YES;
}
- (void)scrollRect:(NSRect)aRect by:(NSSize)offset
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
// Update any pending dirty rects to reflect the new scroll position
if (mPendingDirtyRects) {
unsigned int count = [mPendingDirtyRects count];
for (unsigned int i = 0; i < count; ++i) {
NSRect oldRect = [[mPendingDirtyRects objectAtIndex:i] rectValue];
NSRect newRect = NSOffsetRect(oldRect, offset.width, offset.height);
[mPendingDirtyRects replaceObjectAtIndex:i
withObject:[NSValue valueWithRect:newRect]];
}
}
[super scrollRect:aRect by:offset];
NS_OBJC_END_TRY_ABORT_BLOCK;
}
- (BOOL)mouseDownCanMoveWindow
{
// Return YES so that parts of this view can be draggable. The non-draggable
@ -3567,7 +3471,7 @@ NSEvent* gLastDragMouseDownEvent = nil;
-(void)updateGLContext
{
[mGLContext setView:self];
[mGLContext setView:mPixelHostingView];
[mGLContext update];
}
@ -3580,11 +3484,6 @@ NSEvent* gLastDragMouseDownEvent = nil;
}
}
- (BOOL)wantsBestResolutionOpenGLSurface
{
return nsCocoaUtils::HiDPIEnabled() ? YES : NO;
}
- (void)viewDidChangeBackingProperties
{
[super viewDidChangeBackingProperties];
@ -3646,7 +3545,7 @@ NSEvent* gLastDragMouseDownEvent = nil;
LayoutDeviceIntRect boundingRect = mGeckoChild->CocoaPointsToDevPixels(aRect);
const NSRect *rects;
NSInteger count;
[self getRectsBeingDrawn:&rects count:&count];
[mPixelHostingView getRectsBeingDrawn:&rects count:&count];
if (count > MAX_RECTS_IN_REGION) {
return boundingRect;
@ -3662,53 +3561,34 @@ NSEvent* gLastDragMouseDownEvent = nil;
// The display system has told us that a portion of our view is dirty. Tell
// gecko to paint it
- (void)drawRect:(NSRect)aRect
// This method is called from mPixelHostingView's drawRect handler.
- (void)doDrawRect:(NSRect)aRect
{
CGContextRef cgContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
[self drawRect:aRect inContext:cgContext];
// If we're a transparent window and our contents have changed, we need
// to make sure the shadow is updated to the new contents.
if ([[self window] isKindOfClass:[BaseWindow class]]) {
[(BaseWindow*)[self window] deferredInvalidateShadow];
if (!NS_IsMainThread()) {
// In the presence of CoreAnimation, this method can sometimes be called on
// a non-main thread. Ignore those calls because Gecko can only react to
// them on the main thread.
return;
}
}
- (void)drawRect:(NSRect)aRect inContext:(CGContextRef)aContext
{
if (!mGeckoChild || !mGeckoChild->IsVisible())
return;
#ifdef DEBUG_UPDATE
LayoutDeviceIntRect geckoBounds = mGeckoChild->GetBounds();
fprintf (stderr, "---- Update[%p][%p] [%f %f %f %f] cgc: %p\n gecko bounds: [%d %d %d %d]\n",
self, mGeckoChild,
aRect.origin.x, aRect.origin.y, aRect.size.width, aRect.size.height, aContext,
geckoBounds.x, geckoBounds.y, geckoBounds.width, geckoBounds.height);
CGAffineTransform xform = CGContextGetCTM(aContext);
fprintf (stderr, " xform in: [%f %f %f %f %f %f]\n", xform.a, xform.b, xform.c, xform.d, xform.tx, xform.ty);
#endif
CGContextRef cgContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
if ([self isUsingOpenGL]) {
// For Gecko-initiated repaints in OpenGL mode, drawUsingOpenGL is
// directly called from a delayed perform callback - without going through
// drawRect.
// Paints that come through here are triggered by something that Cocoa
// controls, for example by window resizing or window focus changes.
// Since this view is usually declared as opaque, the window's pixel
// buffer may now contain garbage which we need to prevent from reaching
// the screen. The only place where garbage can show is in the window
// corners and the vibrant regions of the window - the rest of the window
// is covered by opaque content in our OpenGL surface.
// So we need to clear the pixel buffer contents in these areas.
mGeckoChild->ClearVibrantAreas();
[self clearCorners];
// Do GL composition and return.
[self drawUsingOpenGL];
// Force a sync OMTC composite into the OpenGL context and return.
LayoutDeviceIntRect geckoBounds = mGeckoChild->GetBounds();
LayoutDeviceIntRegion region(geckoBounds);
mGeckoChild->PaintWindow(region);
return;
}
@ -3720,54 +3600,31 @@ NSEvent* gLastDragMouseDownEvent = nil;
// multiple dev pixels. But Gecko expects its supplied context to be scaled
// to device pixels, so we need to reverse the scaling.
double scale = mGeckoChild->BackingScaleFactor();
CGContextSaveGState(aContext);
CGContextScaleCTM(aContext, 1.0 / scale, 1.0 / scale);
CGContextSaveGState(cgContext);
CGContextScaleCTM(cgContext, 1.0 / scale, 1.0 / scale);
NSSize viewSize = [self bounds].size;
gfx::IntSize backingSize = gfx::IntSize::Truncate(viewSize.width * scale, viewSize.height * scale);
LayoutDeviceIntRegion region = [self nativeDirtyRegionWithBoundingRect:aRect];
bool painted = mGeckoChild->PaintWindowInContext(aContext, region, backingSize);
bool painted = mGeckoChild->PaintWindowInContext(cgContext, region, backingSize);
// Undo the scale transform so that from now on the context is in
// CocoaPoints again.
CGContextRestoreGState(aContext);
CGContextRestoreGState(cgContext);
if (!painted && [self isOpaque]) {
if (!painted && [mPixelHostingView isOpaque]) {
// Gecko refused to draw, but we've claimed to be opaque, so we have to
// draw something--fill with white.
CGContextSetRGBFillColor(aContext, 1, 1, 1, 1);
CGContextFillRect(aContext, NSRectToCGRect(aRect));
CGContextSetRGBFillColor(cgContext, 1, 1, 1, 1);
CGContextFillRect(cgContext, NSRectToCGRect(aRect));
}
if ([self isCoveringTitlebar]) {
[self drawTitleString];
[self drawTitlebarHighlight];
[self maskTopCornersInContext:aContext];
[self maskTopCornersInContext:cgContext];
}
#ifdef DEBUG_UPDATE
fprintf (stderr, "---- update done ----\n");
#if 0
CGContextSetRGBStrokeColor (aContext,
((((unsigned long)self) & 0xff)) / 255.0,
((((unsigned long)self) & 0xff00) >> 8) / 255.0,
((((unsigned long)self) & 0xff0000) >> 16) / 255.0,
0.5);
#endif
CGContextSetRGBStrokeColor(aContext, 1, 0, 0, 0.8);
CGContextSetLineWidth(aContext, 4.0);
CGContextStrokeRect(aContext, NSRectToCGRect(aRect));
#endif
}
- (BOOL)isUsingMainThreadOpenGL
{
if (!mGeckoChild || ![self window])
return NO;
return mGeckoChild->GetLayerManager(nullptr)->GetBackendType() == mozilla::layers::LayersBackend::LAYERS_OPENGL;
}
- (BOOL)isUsingOpenGL
@ -3775,33 +3632,9 @@ NSEvent* gLastDragMouseDownEvent = nil;
if (!mGeckoChild || ![self window])
return NO;
return mGLContext || mUsingOMTCompositor || [self isUsingMainThreadOpenGL];
return mGLContext || mUsingOMTCompositor;
}
- (void)drawUsingOpenGL
{
PROFILER_LABEL("ChildView", "drawUsingOpenGL",
js::ProfileEntry::Category::GRAPHICS);
if (![self isUsingOpenGL] || !mGeckoChild->IsVisible())
return;
mWaitingForPaint = NO;
LayoutDeviceIntRect geckoBounds = mGeckoChild->GetBounds();
LayoutDeviceIntRegion region(geckoBounds);
mGeckoChild->PaintWindow(region);
}
// Called asynchronously after setNeedsDisplay in order to avoid entering the
// normal drawing machinery.
- (void)drawUsingOpenGLCallback
{
if (mWaitingForPaint) {
[self drawUsingOpenGL];
}
}
- (BOOL)hasRoundedBottomCorners
{
@ -4803,12 +4636,6 @@ GetIntegerDeltaForEvent(NSEvent* aEvent)
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
if (gfxPrefs::AsyncPanZoomSeparateEventThread() && [self apzctm]) {
// Disable main-thread scrolling completely when using APZ with the
// separate event thread. This is bug 1013412.
return;
}
nsAutoRetainCocoaObject kungFuDeathGrip(self);
ChildViewMouseTracker::MouseScrolled(theEvent);
@ -4928,105 +4755,6 @@ GetIntegerDeltaForEvent(NSEvent* aEvent)
NS_OBJC_END_TRY_ABORT_BLOCK;
}
- (void)handleAsyncScrollEvent:(CGEventRef)cgEvent ofType:(CGEventType)type
{
IAPZCTreeManager* apzctm = [self apzctm];
if (!apzctm) {
return;
}
CGPoint loc = CGEventGetLocation(cgEvent);
loc.y = nsCocoaUtils::FlippedScreenY(loc.y);
NSPoint locationInWindow =
nsCocoaUtils::ConvertPointFromScreen([self window], NSPointFromCGPoint(loc));
ScreenIntPoint location = ViewAs<ScreenPixel>(
[self convertWindowCoordinates:locationInWindow],
PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent);
static NSTimeInterval sStartTime = [NSDate timeIntervalSinceReferenceDate];
static TimeStamp sStartTimeStamp = TimeStamp::Now();
if (type == kCGEventScrollWheel) {
NSEvent* event = [NSEvent eventWithCGEvent:cgEvent];
NSEventPhase phase = nsCocoaUtils::EventPhase(event);
NSEventPhase momentumPhase = nsCocoaUtils::EventMomentumPhase(event);
CGFloat pixelDeltaX = 0, pixelDeltaY = 0;
nsCocoaUtils::GetScrollingDeltas(event, &pixelDeltaX, &pixelDeltaY);
uint32_t eventTime = ([event timestamp] - sStartTime) * 1000;
TimeStamp eventTimeStamp = sStartTimeStamp +
TimeDuration::FromSeconds([event timestamp] - sStartTime);
NSPoint locationInWindowMoved = NSMakePoint(
locationInWindow.x + pixelDeltaX,
locationInWindow.y - pixelDeltaY);
ScreenIntPoint locationMoved = ViewAs<ScreenPixel>(
[self convertWindowCoordinates:locationInWindowMoved],
PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent);
ScreenPoint delta = ScreenPoint(locationMoved - location);
ScrollableLayerGuid guid;
// MayBegin and Cancelled are dispatched when the fingers start or stop
// touching the touchpad before any scrolling has occurred. These events
// can be used to control scrollbar visibility or interrupt scroll
// animations. They are only dispatched on 10.8 or later, and only by
// relatively modern devices.
if (phase == NSEventPhaseMayBegin) {
PanGestureInput panInput(PanGestureInput::PANGESTURE_MAYSTART, eventTime,
eventTimeStamp, location, ScreenPoint(0, 0), 0);
apzctm->ReceiveInputEvent(panInput, &guid, nullptr);
return;
}
if (phase == NSEventPhaseCancelled) {
PanGestureInput panInput(PanGestureInput::PANGESTURE_CANCELLED, eventTime,
eventTimeStamp, location, ScreenPoint(0, 0), 0);
apzctm->ReceiveInputEvent(panInput, &guid, nullptr);
return;
}
// Legacy scroll events are dispatched by devices that do not have a
// concept of a scroll gesture, for example by USB mice with
// traditional mouse wheels.
// For these kinds of scrolls, we want to surround every single scroll
// event with a PANGESTURE_START and a PANGESTURE_END event. The APZC
// needs to know that the real scroll gesture can end abruptly after any
// one of these events.
bool isLegacyScroll = (phase == NSEventPhaseNone &&
momentumPhase == NSEventPhaseNone && delta != ScreenPoint(0, 0));
if (phase == NSEventPhaseBegan || isLegacyScroll) {
PanGestureInput panInput(PanGestureInput::PANGESTURE_START, eventTime,
eventTimeStamp, location, ScreenPoint(0, 0), 0);
apzctm->ReceiveInputEvent(panInput, &guid, nullptr);
}
if (momentumPhase == NSEventPhaseNone && delta != ScreenPoint(0, 0)) {
PanGestureInput panInput(PanGestureInput::PANGESTURE_PAN, eventTime,
eventTimeStamp, location, delta, 0);
apzctm->ReceiveInputEvent(panInput, &guid, nullptr);
}
if (phase == NSEventPhaseEnded || isLegacyScroll) {
PanGestureInput panInput(PanGestureInput::PANGESTURE_END, eventTime,
eventTimeStamp, location, ScreenPoint(0, 0), 0);
apzctm->ReceiveInputEvent(panInput, &guid, nullptr);
}
// Any device that can dispatch momentum events supports all three momentum phases.
if (momentumPhase == NSEventPhaseBegan) {
PanGestureInput panInput(PanGestureInput::PANGESTURE_MOMENTUMSTART, eventTime,
eventTimeStamp, location, ScreenPoint(0, 0), 0);
apzctm->ReceiveInputEvent(panInput, &guid, nullptr);
}
if (momentumPhase == NSEventPhaseChanged && delta != ScreenPoint(0, 0)) {
PanGestureInput panInput(PanGestureInput::PANGESTURE_MOMENTUMPAN, eventTime,
eventTimeStamp, location, delta, 0);
apzctm->ReceiveInputEvent(panInput, &guid, nullptr);
}
if (momentumPhase == NSEventPhaseEnded) {
PanGestureInput panInput(PanGestureInput::PANGESTURE_MOMENTUMEND, eventTime,
eventTimeStamp, location, ScreenPoint(0, 0), 0);
apzctm->ReceiveInputEvent(panInput, &guid, nullptr);
}
}
}
-(NSMenu*)menuForEvent:(NSEvent*)theEvent
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
@ -5571,11 +5299,6 @@ GetIntegerDeltaForEvent(NSEvent* aEvent)
return mGeckoChild->CocoaPointsToDevPixelsRoundDown(localPoint);
}
- (IAPZCTreeManager*)apzctm
{
return mGeckoChild ? mGeckoChild->APZCTM() : nullptr;
}
// This is a utility function used by NSView drag event methods
// to send events. It contains all of the logic needed for Gecko
// dragging to work. Returns the appropriate cocoa drag operation code.
@ -6209,6 +5932,26 @@ nsChildView::GetSelectionAsPlaintext(nsAString& aResult)
@end
@implementation PixelHostingView
- (BOOL)isFlipped {
return YES;
}
- (NSView*)hitTest:(NSPoint)aPoint {
return nil;
}
- (void)drawRect:(NSRect)aRect {
[(ChildView*)[self superview] doDrawRect:aRect];
}
- (BOOL)wantsBestResolutionOpenGLSurface {
return nsCocoaUtils::HiDPIEnabled() ? YES : NO;
}
@end
#pragma mark -
void
@ -6377,106 +6120,6 @@ ChildViewMouseTracker::WindowAcceptsEvent(NSWindow* aWindow, NSEvent* aEvent,
#pragma mark -
@interface EventThreadRunner(Private)
- (void)runEventThread;
- (void)shutdownAndReleaseCalledOnEventThread;
- (void)shutdownAndReleaseCalledOnAnyThread;
- (void)handleEvent:(CGEventRef)cgEvent type:(CGEventType)type;
@end
static EventThreadRunner* sEventThreadRunner = nil;
@implementation EventThreadRunner
+ (void)start
{
sEventThreadRunner = [[EventThreadRunner alloc] init];
}
+ (void)stop
{
if (sEventThreadRunner) {
[sEventThreadRunner shutdownAndReleaseCalledOnAnyThread];
sEventThreadRunner = nil;
}
}
- (id)init
{
if ((self = [super init])) {
mThread = nil;
[NSThread detachNewThreadSelector:@selector(runEventThread)
toTarget:self
withObject:nil];
}
return self;
}
static CGEventRef
HandleEvent(CGEventTapProxy aProxy, CGEventType aType,
CGEventRef aEvent, void* aClosure)
{
[(EventThreadRunner*)aClosure handleEvent:aEvent type:aType];
return aEvent;
}
- (void)runEventThread
{
char aLocal;
profiler_register_thread("APZC Event Thread", &aLocal);
PR_SetCurrentThreadName("APZC Event Thread");
mThread = [NSThread currentThread];
ProcessSerialNumber currentProcess;
GetCurrentProcess(&currentProcess);
CFMachPortRef eventPort =
CGEventTapCreateForPSN(&currentProcess,
kCGHeadInsertEventTap,
kCGEventTapOptionListenOnly,
CGEventMaskBit(kCGEventScrollWheel),
HandleEvent,
self);
CFRunLoopSourceRef eventPortSource =
CFMachPortCreateRunLoopSource(kCFAllocatorSystemDefault, eventPort, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), eventPortSource, kCFRunLoopCommonModes);
CFRunLoopRun();
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), eventPortSource, kCFRunLoopCommonModes);
CFRelease(eventPortSource);
CFRelease(eventPort);
[self release];
}
- (void)shutdownAndReleaseCalledOnEventThread
{
CFRunLoopStop(CFRunLoopGetCurrent());
}
- (void)shutdownAndReleaseCalledOnAnyThread
{
[self performSelector:@selector(shutdownAndReleaseCalledOnEventThread) onThread:mThread withObject:nil waitUntilDone:NO];
}
static const CGEventField kCGWindowNumberField = (const CGEventField) 51;
// Called on scroll thread
- (void)handleEvent:(CGEventRef)cgEvent type:(CGEventType)type
{
if (type != kCGEventScrollWheel) {
return;
}
int windowNumber = CGEventGetIntegerValueField(cgEvent, kCGWindowNumberField);
NSWindow* window = [NSApp windowWithWindowNumber:windowNumber];
if (!window || ![window isKindOfClass:[BaseWindow class]]) {
return;
}
ChildView* childView = [(BaseWindow*)window mainChildView];
[childView handleAsyncScrollEvent:cgEvent ofType:type];
}
@end
@interface NSView (MethodSwizzling)
- (BOOL)nsChildView_NSView_mouseDownCanMoveWindow;
@end

View File

@ -24,6 +24,7 @@ public:
static bool OnHighSierraOrLater();
static bool OnMojaveOrLater();
static bool OnCatalinaOrLater();
static bool OnBigSurOrLater();
static bool IsAtLeastVersion(int32_t aMajor, int32_t aMinor, int32_t aBugFix=0);

View File

@ -22,6 +22,8 @@
#define MAC_OS_X_VERSION_10_13_HEX 0x000010D0
#define MAC_OS_X_VERSION_10_14_HEX 0x000010E0
#define MAC_OS_X_VERSION_10_15_HEX 0x000010F0
#define MAC_OS_X_VERSION_10_16_HEX 0x000A1000
#define MAC_OS_X_VERSION_11_0_HEX 0x000B0000
#include "nsCocoaFeatures.h"
#include "nsCocoaUtils.h"
@ -188,6 +190,14 @@ nsCocoaFeatures::OnCatalinaOrLater()
return (OSXVersion() >= MAC_OS_X_VERSION_10_15_HEX);
}
/* static */ bool
nsCocoaFeatures::OnBigSurOrLater() {
// Account for the version being 10.16 (which occurs when the
// application is linked with an older SDK) or 11.0 on Big Sur.
return ((OSXVersion() >= MAC_OS_X_VERSION_10_16_HEX) ||
(OSXVersion() >= MAC_OS_X_VERSION_11_0_HEX));
}
/* static */ bool
nsCocoaFeatures::IsAtLeastVersion(int32_t aMajor, int32_t aMinor, int32_t aBugFix)
{

View File

@ -359,7 +359,8 @@ protected:
nsresult CreateNativeWindow(const NSRect &aRect,
nsBorderStyle aBorderStyle,
bool aRectIsFrameRect);
nsresult CreatePopupContentView(const LayoutDeviceIntRect &aRect);
nsresult CreatePopupContentView(const LayoutDeviceIntRect &aRect,
nsWidgetInitData* aInitData);
void DestroyNativeWindow();
void AdjustWindowShadow();
void SetWindowBackgroundBlur();
@ -416,6 +417,8 @@ protected:
bool mInReportMoveEvent; // true if in a call to ReportMoveEvent().
bool mInResize; // true if in a call to DoResize().
bool mAlwaysOnTop;
int32_t mNumModalDescendents;
InputContext mInputContext;
};

View File

@ -34,6 +34,7 @@
#include "nsIWidgetListener.h"
#include "nsIPresShell.h"
#include "nsScreenCocoa.h"
#include "VibrancyManager.h"
#include "gfxPlatform.h"
#include "qcms.h"
@ -127,6 +128,7 @@ nsCocoaWindow::nsCocoaWindow()
, mIsAnimationSuppressed(false)
, mInReportMoveEvent(false)
, mInResize(false)
, mAlwaysOnTop(false)
, mNumModalDescendents(0)
{
if ([NSWindow respondsToSelector:@selector(setAllowsAutomaticWindowTabbing:)]) {
@ -301,12 +303,14 @@ nsCocoaWindow::Create(nsIWidget* aParent,
if (mWindowType == eWindowType_popup) {
if (aInitData->mMouseTransparent) {
[mWindow setIgnoresMouseEvents:YES];
} else {
[mWindow setIgnoresMouseEvents:NO];
}
// now we can convert newBounds to device pixels for the window we created,
// as the child view expects a rect expressed in the dev pix of its parent
LayoutDeviceIntRect devRect =
RoundedToInt(newBounds * GetDesktopToDeviceScale());
return CreatePopupContentView(devRect);
return CreatePopupContentView(devRect, aInitData);
}
mIsAnimationSuppressed = aInitData->mIsAnimationSuppressed;
@ -455,6 +459,11 @@ nsresult nsCocoaWindow::CreateNativeWindow(const NSRect &aRect,
mWindow = [[windowClass alloc] initWithContentRect:contentRect styleMask:features
backing:NSBackingStoreBuffered defer:YES];
// Make sure that window titles don't leak to disk in private browsing mode
// due to macOS' resume feature.
[mWindow setRestorable:NO];
[mWindow disableSnapshotRestoration];
// setup our notification delegate. Note that setDelegate: does NOT retain.
mDelegate = [[WindowDelegate alloc] initWithGeckoWindow:this];
[mWindow setDelegate:mDelegate];
@ -473,7 +482,6 @@ nsresult nsCocoaWindow::CreateNativeWindow(const NSRect &aRect,
if (mWindowType == eWindowType_popup) {
SetPopupWindowLevel();
[mWindow setHasShadow:YES];
[mWindow setBackgroundColor:[NSColor clearColor]];
[mWindow setOpaque:NO];
} else {
@ -482,6 +490,13 @@ nsresult nsCocoaWindow::CreateNativeWindow(const NSRect &aRect,
[mWindow setOpaque:YES];
}
NSWindowCollectionBehavior newBehavior = [mWindow collectionBehavior];
if (mAlwaysOnTop) {
[mWindow setLevel:NSFloatingWindowLevel];
newBehavior |= NSWindowCollectionBehaviorCanJoinAllSpaces;
}
[mWindow setCollectionBehavior:newBehavior];
[mWindow setContentMinSize:NSMakeSize(60, 60)];
[mWindow disableCursorRects];
@ -498,7 +513,8 @@ nsresult nsCocoaWindow::CreateNativeWindow(const NSRect &aRect,
}
NS_IMETHODIMP
nsCocoaWindow::CreatePopupContentView(const LayoutDeviceIntRect &aRect)
nsCocoaWindow::CreatePopupContentView(const LayoutDeviceIntRect &aRect,
nsWidgetInitData* aInitData)
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
@ -511,13 +527,16 @@ nsCocoaWindow::CreatePopupContentView(const LayoutDeviceIntRect &aRect)
nsIWidget* thisAsWidget = static_cast<nsIWidget*>(this);
nsresult rv = mPopupContentView->Create(thisAsWidget, nullptr, aRect,
nullptr);
aInitData);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
ChildView* newContentView = (ChildView*)mPopupContentView->GetNativeData(NS_NATIVE_WIDGET);
[mWindow setContentView:newContentView];
NSView* contentView = [mWindow contentView];
ChildView* childView = (ChildView*)mPopupContentView->GetNativeData(NS_NATIVE_WIDGET);
[childView setFrame:NSZeroRect];
[childView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
[contentView addSubview:childView];
return NS_OK;
@ -756,6 +775,13 @@ NS_IMETHODIMP nsCocoaWindow::Show(bool bState)
(NSWindow*)parentWidget->GetNativeData(NS_NATIVE_WINDOW) : nil;
if (bState && !mBounds.IsEmpty()) {
// Don't try to show a popup when the parent isn't visible or is minimized.
if (mWindowType == eWindowType_popup && nativeParentWindow) {
if (![nativeParentWindow isVisible] || [nativeParentWindow isMiniaturized]) {
return NS_ERROR_FAILURE;
}
}
if (mPopupContentView) {
// Ensure our content view is visible. We never need to hide it.
mPopupContentView->Show(true);
@ -2789,12 +2815,6 @@ static NSMutableSet *gSwizzledFrameViewClasses = nil;
- (void)_addKnownSubview:(NSView*)aView positioned:(NSWindowOrderingMode)place relativeTo:(NSView*)otherView;
@end
// Available on 10.10
@interface NSWindow(PrivateCornerMaskMethod)
- (id)_cornerMask;
- (void)_cornerMaskChanged;
@end
#if !defined(MAC_OS_X_VERSION_10_10) || \
MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_10
@ -2815,6 +2835,10 @@ static NSMutableSet *gSwizzledFrameViewClasses = nil;
#endif
@interface NSView(NSVisualEffectViewSetMaskImage)
- (void)setMaskImage:(NSImage*)image;
@end
@interface BaseWindow(Private)
- (void)removeTrackingArea;
- (void)cursorUpdated:(NSEvent*)aEvent;
@ -2824,25 +2848,6 @@ static NSMutableSet *gSwizzledFrameViewClasses = nil;
@implementation BaseWindow
- (id)_cornerMask
{
if (!mUseMenuStyle) {
return [super _cornerMask];
}
CGFloat radius = 4.0f;
NSEdgeInsets insets = { 5, 5, 5, 5 };
NSSize maskSize = { 12, 12 };
NSImage* maskImage = [NSImage imageWithSize:maskSize flipped:YES drawingHandler:^BOOL(NSRect dstRect) {
NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect:dstRect xRadius:radius yRadius:radius];
[[NSColor colorWithDeviceWhite:1.0 alpha:1.0] set];
[path fill];
return YES;
}];
[maskImage setCapInsets:insets];
return maskImage;
}
// The frame of a window is implemented using undocumented NSView subclasses.
// We offset the window buttons by overriding the methods _closeButtonOrigin
// and _fullScreenButtonOrigin on these frame view classes. The class which is
@ -2915,14 +2920,54 @@ static NSMutableSet *gSwizzledFrameViewClasses = nil;
return self;
}
// Returns an autoreleased NSImage.
static NSImage*
GetMenuMaskImage()
{
CGFloat radius = 4.0f;
NSEdgeInsets insets = { 5, 5, 5, 5 };
NSSize maskSize = { 12, 12 };
NSImage* maskImage = [NSImage imageWithSize:maskSize flipped:YES drawingHandler:^BOOL(NSRect dstRect) {
NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect:dstRect xRadius:radius yRadius:radius];
[[NSColor colorWithDeviceWhite:1.0 alpha:1.0] set];
[path fill];
return YES;
}];
[maskImage setCapInsets:insets];
return maskImage;
}
- (void)swapOutChildViewWrapper:(NSView*)aNewWrapper
{
[aNewWrapper setFrame:[[self contentView] frame]];
NSView* childView = [[self mainChildView] retain];
[childView removeFromSuperview];
[aNewWrapper addSubview:childView];
[childView release];
[super setContentView:aNewWrapper];
}
- (void)setUseMenuStyle:(BOOL)aValue
{
if (aValue != mUseMenuStyle) {
mUseMenuStyle = aValue;
if ([self respondsToSelector:@selector(_cornerMaskChanged)]) {
[self _cornerMaskChanged];
}
if (!VibrancyManager::SystemSupportsVibrancy()) {
return;
}
if (aValue && !mUseMenuStyle) {
// Turn on rounded corner masking.
NSView* effectView = VibrancyManager::CreateEffectView(VibrancyType::MENU, YES);
if ([effectView respondsToSelector:@selector(setMaskImage:)]) {
[effectView setMaskImage:GetMenuMaskImage()];
}
[self swapOutChildViewWrapper:effectView];
[effectView release];
} else if (mUseMenuStyle && !aValue) {
// Turn off rounded corner masking.
NSView* wrapper = [[NSView alloc] initWithFrame:NSZeroRect];
[self swapOutChildViewWrapper:wrapper];
[wrapper release];
}
mUseMenuStyle = aValue;
}
- (void)setBeingShown:(BOOL)aValue
@ -3080,10 +3125,6 @@ static const NSString* kStateCollectionBehavior = @"collectionBehavior";
- (ChildView*)mainChildView
{
NSView *contentView = [self contentView];
// A PopupWindow's contentView is a ChildView object.
if ([contentView isKindOfClass:[ChildView class]]) {
return (ChildView*)contentView;
}
NSView* lastView = [[contentView subviews] lastObject];
if ([lastView isKindOfClass:[ChildView class]]) {
return (ChildView*)lastView;

View File

@ -443,8 +443,8 @@ static ChildView* ChildViewForFrame(nsIFrame* aFrame)
if (!widget)
return nil;
NSView* view = (NSView*)widget->GetNativeData(NS_NATIVE_WIDGET);
return [view isKindOfClass:[ChildView class]] ? (ChildView*)view : nil;
NSWindow* window = (NSWindow*)widget->GetNativeData(NS_NATIVE_WINDOW);
return [window isKindOfClass:[BaseWindow class]] ? [(BaseWindow*)window mainChildView] : nil;
}
static NSWindow* NativeWindowForFrame(nsIFrame* aFrame,
@ -2437,17 +2437,30 @@ nsNativeThemeCocoa::DrawWidgetBackground(nsRenderingContext* aContext,
break;
case NS_THEME_MENUSEPARATOR: {
ThemeMenuState menuState;
if (IsDisabled(aFrame, eventState)) {
menuState = kThemeMenuDisabled;
// Workaround for visual artifacts issues with
// HIThemeDrawMenuSeparator on macOS Big Sur.
if (nsCocoaFeatures::OnBigSurOrLater()) {
CGRect separatorRect = macRect;
separatorRect.size.height = 1;
separatorRect.size.width -= 42;
separatorRect.origin.x += 21;
// Use a gray color similar to the native separator
CGContextSetRGBFillColor(cgContext, 0.816, 0.816, 0.816, 1.0);
CGContextFillRect(cgContext, separatorRect);
}
else {
menuState = CheckBooleanAttr(aFrame, nsGkAtoms::menuactive) ?
kThemeMenuSelected : kThemeMenuActive;
else
{
ThemeMenuState menuState;
if (IsDisabled(aFrame, eventState)) {
menuState = kThemeMenuDisabled;
}
else {
menuState = CheckBooleanAttr(aFrame, nsGkAtoms::menuactive) ?
kThemeMenuSelected : kThemeMenuActive;
}
HIThemeMenuItemDrawInfo midi = { 0, kThemeMenuItemPlain, menuState };
HIThemeDrawMenuSeparator(&macRect, &macRect, &midi, cgContext, HITHEME_ORIENTATION);
}
HIThemeMenuItemDrawInfo midi = { 0, kThemeMenuItemPlain, menuState };
HIThemeDrawMenuSeparator(&macRect, &macRect, &midi, cgContext, HITHEME_ORIENTATION);
}
break;