diff options
Diffstat (limited to 'widget/cocoa/nsChildView.mm')
-rw-r--r-- | widget/cocoa/nsChildView.mm | 599 |
1 files changed, 121 insertions, 478 deletions
diff --git a/widget/cocoa/nsChildView.mm b/widget/cocoa/nsChildView.mm index 1a257d899..868687fe1 100644 --- a/widget/cocoa/nsChildView.mm +++ b/widget/cocoa/nsChildView.mm @@ -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]; -} - -- (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); + return mGLContext || mUsingOMTCompositor; } -// 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(¤tProcess); - CFMachPortRef eventPort = - CGEventTapCreateForPSN(¤tProcess, - 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 |