Bug 944938 - Add a 10.6 compatibility wrapper for event phases. r=smichaud
authorMarkus Stange <mstange@themasta.com>
Sat, 07 Jun 2014 00:49:59 +0200
changeset 207658 7eda6c9105c25dfa11e296ba6f130a691842c93b
parent 207657 c6cb512f1119fc26a585422548ae89a6a33c3ac9
child 207659 cde19559da0f6db9869a8586a55fe6d09cd248db
push id494
push userraliiev@mozilla.com
push dateMon, 25 Aug 2014 18:42:16 +0000
treeherdermozilla-release@a3cc3e46b571 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmichaud
bugs944938
milestone32.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 944938 - Add a 10.6 compatibility wrapper for event phases. r=smichaud
widget/cocoa/nsChildView.h
widget/cocoa/nsChildView.mm
widget/cocoa/nsCocoaUtils.h
widget/cocoa/nsCocoaUtils.mm
--- a/widget/cocoa/nsChildView.h
+++ b/widget/cocoa/nsChildView.h
@@ -172,26 +172,16 @@ MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_
 // will result in a compiler error because that functionality is not
 // available" (quoting from AvailabilityMacros.h).  The compiler initializes
 // it to the version of the SDK being used.  Its value does *not* prevent the
 // binary from running on higher OS versions.  MAC_OS_X_VERSION_10_7 and
 // friends are defined (in AvailabilityMacros.h) as decimal numbers (not
 // hexadecimal numbers).
 #if !defined(MAC_OS_X_VERSION_10_7) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
 enum {
-  NSEventPhaseNone        = 0,
-  NSEventPhaseBegan       = 0x1 << 0,
-  NSEventPhaseStationary  = 0x1 << 1,
-  NSEventPhaseChanged     = 0x1 << 2,
-  NSEventPhaseEnded       = 0x1 << 3,
-  NSEventPhaseCancelled   = 0x1 << 4,
-};
-typedef NSUInteger NSEventPhase;
-
-enum {
    NSFullScreenWindowMask = 1 << 14
 };
 
 @interface NSWindow (LionWindowFeatures)
 - (NSRect)convertRectToScreen:(NSRect)aRect;
 @end
 
 #ifdef __LP64__
@@ -217,31 +207,16 @@ typedef NSInteger NSEventGestureAxis;
 - (void)trackSwipeEventWithOptions:(NSEventSwipeTrackingOptions)options
           dampenAmountThresholdMin:(CGFloat)minDampenThreshold
                                max:(CGFloat)maxDampenThreshold
                       usingHandler:(void (^)(CGFloat gestureAmount, NSEventPhase phase, BOOL isComplete, BOOL *stop))trackingHandler;
 @end
 #endif // #ifdef __LP64__
 #endif // #if !defined(MAC_OS_X_VERSION_10_7) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
 
-#if !defined(MAC_OS_X_VERSION_10_8) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_8
-enum {
-  NSEventPhaseMayBegin    = 0x1 << 5
-};
-#endif // #if !defined(MAC_OS_X_VERSION_10_8) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_8
-
-// Undocumented scrollPhase flag that lets us discern between real scrolls and
-// automatically firing momentum scroll events.
-@interface NSEvent (ScrollPhase)
-// Leopard and SnowLeopard
-- (long long)_scrollPhase;
-// Lion and above
-- (NSEventPhase)momentumPhase;
-@end
-
 @interface ChildView : NSView<
 #ifdef ACCESSIBILITY
                               mozAccessible,
 #endif
                               mozView, NSTextInput, NSTextInputClient>
 {
 @private
   // the nsChildView that created the view. It retains this NSView, so
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -4444,19 +4444,20 @@ NSEvent* gLastDragMouseDownEvent = nil;
   }
 
   // We should only track scroll events as swipe if the viewport is being
   // overscrolled.
   if (!aViewPortIsOverscrolled) {
     return;
   }
 
+  NSEventPhase eventPhase = nsCocoaUtils::EventPhase(anEvent);
   // Verify that this is a scroll wheel event with proper phase to be tracked
   // by the OS.
-  if ([anEvent type] != NSScrollWheel || [anEvent phase] == NSEventPhaseNone) {
+  if ([anEvent type] != NSScrollWheel || eventPhase == NSEventPhaseNone) {
     return;
   }
 
   // Only initiate tracking if the user has tried to scroll past the edge of
   // the current page (as indicated by 'anOverflowX' or 'anOverflowY' being
   // non-zero). Gecko only sets WidgetMouseScrollEvent.scrollOverflow when it's
   // processing NS_MOUSE_PIXEL_SCROLL events (not NS_MOUSE_SCROLL events).
   if (anOverflowX == 0.0 && anOverflowY == 0.0) {
@@ -4481,17 +4482,17 @@ NSEvent* gLastDragMouseDownEvent = nil;
   // that they'll be misinterpreted as horizontal swipes), while still
   // tolerating a small vertical element to a true horizontal swipe.  The number
   // '8' was arrived at by trial and error.
   if (anOverflowX != 0.0 && deltaX != 0.0 &&
       fabsf(deltaX) > fabsf(deltaY) * 8) {
     // Only initiate horizontal tracking for gestures that have just begun --
     // otherwise a scroll to one side of the page can have a swipe tacked on
     // to it.
-    if ([anEvent phase] != NSEventPhaseBegan) {
+    if (eventPhase != NSEventPhaseBegan) {
       return;
     }
 
     if (deltaX < 0.0) {
       direction = (uint32_t)nsIDOMSimpleGestureEvent::DIRECTION_RIGHT;
     } else {
       direction = (uint32_t)nsIDOMSimpleGestureEvent::DIRECTION_LEFT;
     }
@@ -5100,28 +5101,26 @@ static int32_t RoundUp(double aDouble)
   if ([self maybeRollup:theEvent]) {
     return;
   }
 
   if (!mGeckoChild) {
     return;
   }
 
-  if (nsCocoaFeatures::OnLionOrLater()) {
-    NSEventPhase phase = [theEvent phase];
-    // Fire NS_WHEEL_START/STOP events when 2 fingers touch/release the touchpad.
-    if (phase & NSEventPhaseMayBegin) {
-      [self sendWheelCondition:YES first:NS_WHEEL_STOP second:NS_WHEEL_START forEvent:theEvent];
-      return;
-    }
-
-    if (phase & (NSEventPhaseEnded | NSEventPhaseCancelled)) {
-      [self sendWheelCondition:NO first:NS_WHEEL_START second:NS_WHEEL_STOP forEvent:theEvent];
-      return;
-    }
+  NSEventPhase phase = nsCocoaUtils::EventPhase(theEvent);
+  // Fire NS_WHEEL_START/STOP events when 2 fingers touch/release the touchpad.
+  if (phase & NSEventPhaseMayBegin) {
+    [self sendWheelCondition:YES first:NS_WHEEL_STOP second:NS_WHEEL_START forEvent:theEvent];
+    return;
+  }
+
+  if (phase & (NSEventPhaseEnded | NSEventPhaseCancelled)) {
+    [self sendWheelCondition:NO first:NS_WHEEL_START second:NS_WHEEL_STOP forEvent:theEvent];
+    return;
   }
 
   WidgetWheelEvent wheelEvent(true, NS_WHEEL_WHEEL, mGeckoChild);
   [self convertCocoaMouseWheelEvent:theEvent toGeckoEvent:&wheelEvent];
 
   wheelEvent.lineOrPageDeltaX = RoundUp(-[theEvent deltaX]);
   wheelEvent.lineOrPageDeltaY = RoundUp(-[theEvent deltaY]);
 
--- a/widget/cocoa/nsCocoaUtils.h
+++ b/widget/cocoa/nsCocoaUtils.h
@@ -19,16 +19,35 @@
 #include "mozilla/EventForwards.h"
 
 // Declare the backingScaleFactor method that we want to call
 // on NSView/Window/Screen objects, if they recognize it.
 @interface NSObject (BackingScaleFactorCategory)
 - (CGFloat)backingScaleFactor;
 @end
 
+// When building with a pre-10.7 SDK, NSEventPhase is not defined.
+#if !defined(MAC_OS_X_VERSION_10_7) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
+enum {
+  NSEventPhaseNone        = 0,
+  NSEventPhaseBegan       = 0x1 << 0,
+  NSEventPhaseStationary  = 0x1 << 1,
+  NSEventPhaseChanged     = 0x1 << 2,
+  NSEventPhaseEnded       = 0x1 << 3,
+  NSEventPhaseCancelled   = 0x1 << 4,
+};
+typedef NSUInteger NSEventPhase;
+#endif // #if !defined(MAC_OS_X_VERSION_10_7) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
+
+#if !defined(MAC_OS_X_VERSION_10_8) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_8
+enum {
+  NSEventPhaseMayBegin    = 0x1 << 5
+};
+#endif // #if !defined(MAC_OS_X_VERSION_10_8) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_8
+
 class nsIWidget;
 
 namespace mozilla {
 namespace gfx {
 class SourceSurface;
 }
 }
 
@@ -209,16 +228,20 @@ public:
   static BOOL IsEventOverWindow(NSEvent* anEvent, NSWindow* aWindow);
 
   // Events are set up so that their coordinates refer to the window to which they
   // were originally sent. If we reroute the event somewhere else, we'll have
   // to get the window coordinates this way. Do not call this unless the window
   // the event was originally targeted at is still alive!
   static NSPoint EventLocationForWindow(NSEvent* anEvent, NSWindow* aWindow);
 
+  // Compatibility wrappers for the -[NSEvent phase] and -[NSEvent momentumPhase]
+  // APIs that became availaible starting with the 10.7 SDK.
+  static NSEventPhase EventPhase(NSEvent* aEvent);
+  static NSEventPhase EventMomentumPhase(NSEvent* aEvent);
   static BOOL IsMomentumScrollEvent(NSEvent* aEvent);
 
   // Hides the Menu bar and the Dock. Multiple hide/show requests can be nested.
   static void HideOSChromeOnScreen(bool aShouldHide, NSScreen* aScreen);
 
   static nsIWidget* GetHiddenWindowWidget();
 
   static void PrepareForNativeAppModalDialog();
--- a/widget/cocoa/nsCocoaUtils.mm
+++ b/widget/cocoa/nsCocoaUtils.mm
@@ -132,28 +132,52 @@ NSPoint nsCocoaUtils::EventLocationForWi
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
 
   return [aWindow convertScreenToBase:ScreenLocationForEvent(anEvent)];
 
   NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NSMakePoint(0.0, 0.0));
 }
 
+@interface NSEvent (ScrollPhase)
+// 10.5 and 10.6
+- (long long)_scrollPhase;
+// 10.7 and above
+- (NSEventPhase)phase;
+- (NSEventPhase)momentumPhase;
+@end
+
+NSEventPhase nsCocoaUtils::EventPhase(NSEvent* aEvent)
+{
+  if ([aEvent respondsToSelector:@selector(phase)]) {
+    return [aEvent phase];
+  }
+  return NSEventPhaseNone;
+}
+
+NSEventPhase nsCocoaUtils::EventMomentumPhase(NSEvent* aEvent)
+{
+  if ([aEvent respondsToSelector:@selector(momentumPhase)]) {
+    return [aEvent momentumPhase];
+  }
+  if ([aEvent respondsToSelector:@selector(_scrollPhase)]) {
+    switch ([aEvent _scrollPhase]) {
+      case 1: return NSEventPhaseBegan;
+      case 2: return NSEventPhaseChanged;
+      case 3: return NSEventPhaseEnded;
+      default: return NSEventPhaseNone;
+    }
+  }
+  return NSEventPhaseNone;
+}
+
 BOOL nsCocoaUtils::IsMomentumScrollEvent(NSEvent* aEvent)
 {
-  if ([aEvent type] != NSScrollWheel)
-    return NO;
-    
-  if ([aEvent respondsToSelector:@selector(momentumPhase)])
-    return ([aEvent momentumPhase] & NSEventPhaseChanged) != 0;
-    
-  if ([aEvent respondsToSelector:@selector(_scrollPhase)])
-    return [aEvent _scrollPhase] != 0;
-    
-  return NO;
+  return [aEvent type] == NSScrollWheel &&
+    EventMomentumPhase(aEvent) != NSEventPhaseNone;
 }
 
 void nsCocoaUtils::HideOSChromeOnScreen(bool aShouldHide, NSScreen* aScreen)
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
 
   // Keep track of how many hiding requests have been made, so that they can
   // be nested.