Index: chrome/browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper.mm |
diff --git a/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper.mm b/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper.mm |
index c8ccabc5f5007c6327a02aecca8b464e84566808..1d3be093c79539a9078005b550536715c30e3257 100644 |
--- a/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper.mm |
+++ b/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper.mm |
@@ -49,6 +49,46 @@ BOOL forceMagicMouse = NO; |
// Returns whether the wheel event should be consumed, and not passed to the |
// renderer. |
- (BOOL)shouldConsumeWheelEvent:(NSEvent*)event; |
+ |
+// Shows the history swiper overlay. |
+- (void)showHistoryOverlay:(history_swiper::NavigationDirection)direction; |
+ |
+// Removes the history swiper overlay. |
+- (void)removeHistoryOverlay; |
+ |
+// Returns YES if the event was consumed or NO if it should be passed on to the |
+// renderer. If |event| was generated by a Magic Mouse, this method forwards to |
+// handleMagicMouseWheelEvent. Otherwise, this method attempts to transition |
+// the state machine from kPending -> kPotential. If it performs the |
+// transition, it also shows the history overlay. In order for a history swipe |
+// gesture to be recognized, the transition must occur. |
+// |
+// There are 4 types of scroll wheel events: |
+// 1. Magic mouse swipe events. |
+// These are identical to magic trackpad events, except that there are no |
+// -[NSView touches*WithEvent:] callbacks. The only way to accurately |
+// track these events is with the `trackSwipeEventWithOptions:` API. |
+// scrollingDelta{X,Y} is not accurate over long distances (it is computed |
+// using the speed of the swipe, rather than just the distance moved by |
+// the fingers). |
+// 2. Magic trackpad swipe events. |
+// These are the most common history swipe events. The logic of this |
+// method is predominantly designed to handle this use case. |
+// 3. Traditional mouse scrollwheel events. |
+// These should not initiate scrolling. They can be distinguished by the |
+// fact that `phase` and `momentumPhase` both return NSEventPhaseNone. |
+// 4. Momentum swipe events. |
+// After a user finishes a swipe, the system continues to generate |
+// artificial callbacks. `phase` returns NSEventPhaseNone, but |
+// `momentumPhase` does not. Unfortunately, the callbacks don't work |
+// properly (OSX 10.9). Sometimes, the system start sending momentum swipe |
+// events instead of trackpad swipe events while the user is still |
+// 2-finger swiping. |
+- (BOOL)handleScrollWheelEvent:(NSEvent*)event; |
+ |
+// Returns YES if the event was consumed or NO if it should be passed on to the |
+// renderer. Attempts to initiate history swiping for Magic Mouse events. |
+- (BOOL)handleMagicMouseWheelEvent:(NSEvent*)theEvent; |
@end |
@implementation HistorySwiper |
@@ -57,25 +97,21 @@ BOOL forceMagicMouse = NO; |
- (id)initWithDelegate:(id<HistorySwiperDelegate>)delegate { |
self = [super init]; |
if (self) { |
- // Gesture ids start at 0. |
- currentGestureId_ = 0; |
- // No gestures have been processed |
- lastProcessedGestureId_ = -1; |
delegate_ = delegate; |
} |
return self; |
} |
- (void)dealloc { |
- [self endHistorySwipe]; |
+ [self removeHistoryOverlay]; |
[super dealloc]; |
} |
- (BOOL)handleEvent:(NSEvent*)event { |
- if ([event type] == NSScrollWheel) |
- return [self maybeHandleHistorySwiping:event]; |
+ if ([event type] != NSScrollWheel) |
+ return NO; |
- return NO; |
+ return [self handleScrollWheelEvent:event]; |
} |
- (void)rendererHandledWheelEvent:(const blink::WebMouseWheelEvent&)event |
@@ -155,8 +191,14 @@ BOOL forceMagicMouse = NO; |
} |
- (void)updateGestureCurrentPointFromEvent:(NSEvent*)event { |
+ NSPoint averagePosition = [self averagePositionInEvent:event]; |
+ |
+ // If the start point is valid, then so is the current point. |
+ if (gestureStartPointValid_) |
+ gestureTotalY_ += fabs(averagePosition.y - gestureCurrentPoint_.y); |
+ |
// Update the current point of the gesture. |
- gestureCurrentPoint_ = [self averagePositionInEvent:event]; |
+ gestureCurrentPoint_ = averagePosition; |
// If the gesture doesn't have a start point, set one. |
if (!gestureStartPointValid_) { |
@@ -170,10 +212,10 @@ BOOL forceMagicMouse = NO; |
// available after the gesture begins. |
- (void)touchesBeganWithEvent:(NSEvent*)event { |
receivingTouches_ = YES; |
- ++currentGestureId_; |
// Reset state pertaining to previous gestures. |
gestureStartPointValid_ = NO; |
+ gestureTotalY_ = 0; |
mouseScrollDelta_ = NSZeroSize; |
beganEventUnconsumed_ = NO; |
recognitionState_ = history_swiper::kPending; |
@@ -194,7 +236,6 @@ BOOL forceMagicMouse = NO; |
- (void)touchesEndedWithEvent:(NSEvent*)event { |
receivingTouches_ = NO; |
- |
if (![self processTouchEventForHistorySwiping:event]) |
return; |
@@ -205,8 +246,8 @@ BOOL forceMagicMouse = NO; |
if (finished) |
[self navigateBrowserInDirection:historySwipeDirection_]; |
- // Remove the history overlay. |
- [self endHistorySwipe]; |
+ [self removeHistoryOverlay]; |
+ |
// The gesture was completed. |
recognitionState_ = history_swiper::kCompleted; |
} |
@@ -224,8 +265,6 @@ BOOL forceMagicMouse = NO; |
case history_swiper::kCompleted: |
return NO; |
case history_swiper::kPending: |
- [self updateGestureCurrentPointFromEvent:event]; |
- return NO; |
case history_swiper::kPotential: |
case history_swiper::kTracking: |
break; |
@@ -240,6 +279,10 @@ BOOL forceMagicMouse = NO; |
return NO; |
} |
+ // Don't do any more processing if the state machine is in the pending state. |
+ if (recognitionState_ == history_swiper::kPending) |
+ return NO; |
+ |
if (recognitionState_ == history_swiper::kPotential) { |
// The user is in the process of doing history swiping. If the history |
// swipe has progressed sufficiently far, stop sending events to the |
@@ -259,7 +302,7 @@ BOOL forceMagicMouse = NO; |
// vertical swipe. |
- (BOOL)shouldCancelHorizontalSwipeWithCurrentPoint:(NSPoint)currentPoint |
startPoint:(NSPoint)startPoint { |
- CGFloat yDelta = fabs(currentPoint.y - startPoint.y); |
+ CGFloat yDelta = gestureTotalY_; |
CGFloat xDelta = fabs(currentPoint.x - startPoint.x); |
// The gesture is pretty clearly more vertical than horizontal. |
@@ -278,11 +321,11 @@ BOOL forceMagicMouse = NO; |
} |
- (void)cancelHistorySwipe { |
- [self endHistorySwipe]; |
+ [self removeHistoryOverlay]; |
recognitionState_ = history_swiper::kCancelled; |
} |
-- (void)endHistorySwipe { |
+- (void)removeHistoryOverlay { |
[historyOverlay_ dismiss]; |
[historyOverlay_ release]; |
historyOverlay_ = nil; |
@@ -323,19 +366,11 @@ BOOL forceMagicMouse = NO; |
return NO; |
} |
-// goForward indicates whether the user is starting a forward or backward |
-// history swipe. |
-// Creates and displays a history overlay controller. |
-// Responsible for cleaning up after itself when the gesture is finished. |
-// Responsible for starting a browser navigation if necessary. |
-// Does not prevent swipe events from propagating to other handlers. |
-- (void)beginHistorySwipeInDirection: |
- (history_swiper::NavigationDirection)direction |
- event:(NSEvent*)event { |
+- (void)showHistoryOverlay:(history_swiper::NavigationDirection)direction { |
// We cannot make any assumptions about the current state of the |
// historyOverlay_, since users may attempt to use multiple gesture input |
// devices simultaneously, which confuses Cocoa. |
- [self endHistorySwipe]; |
+ [self removeHistoryOverlay]; |
HistoryOverlayController* historyOverlay = [[HistoryOverlayController alloc] |
initForMode:(direction == history_swiper::kForwards) |
@@ -343,11 +378,6 @@ BOOL forceMagicMouse = NO; |
: kHistoryOverlayModeBack]; |
[historyOverlay showPanelForView:[delegate_ viewThatWantsHistoryOverlay]]; |
historyOverlay_ = historyOverlay; |
- |
- // Record whether the user was swiping forwards or backwards. |
- historySwipeDirection_ = direction; |
- // Record the user's settings. |
- historySwipeDirectionInverted_ = [self isEventDirectionInverted:event]; |
} |
- (BOOL)systemSettingsAllowHistorySwiping:(NSEvent*)event { |
@@ -383,9 +413,7 @@ BOOL forceMagicMouse = NO; |
} |
} |
-// We use an entirely different set of logic for magic mouse swipe events, |
-// since we do not get NSTouch callbacks. |
-- (BOOL)maybeHandleMagicMouseHistorySwiping:(NSEvent*)theEvent { |
+- (BOOL)handleMagicMouseWheelEvent:(NSEvent*)theEvent { |
// The 'trackSwipeEventWithOptions:' api doesn't handle momentum events. |
if ([theEvent phase] == NSEventPhaseNone) |
return NO; |
@@ -483,31 +511,7 @@ BOOL forceMagicMouse = NO; |
}]; |
} |
-// Checks if |theEvent| should trigger history swiping, and if so, does |
-// history swiping. Returns YES if the event was consumed or NO if it should |
-// be passed on to the renderer. |
-// |
-// There are 4 types of scroll wheel events: |
-// 1. Magic mouse swipe events. |
-// These are identical to magic trackpad events, except that there are no |
-// NSTouch callbacks. The only way to accurately track these events is |
-// with the `trackSwipeEventWithOptions:` API. scrollingDelta{X,Y} is not |
-// accurate over long distances (it is computed using the speed of the |
-// swipe, rather than just the distance moved by the fingers). |
-// 2. Magic trackpad swipe events. |
-// These are the most common history swipe events. Our logic is |
-// predominantly designed to handle this use case. |
-// 3. Traditional mouse scrollwheel events. |
-// These should not initiate scrolling. They can be distinguished by the |
-// fact that `phase` and `momentumPhase` both return NSEventPhaseNone. |
-// 4. Momentum swipe events. |
-// After a user finishes a swipe, the system continues to generate |
-// artificial callbacks. `phase` returns NSEventPhaseNone, but |
-// `momentumPhase` does not. Unfortunately, the callbacks don't work |
-// properly (OSX 10.9). Sometimes, the system start sending momentum swipe |
-// events instead of trackpad swipe events while the user is still |
-// 2-finger swiping. |
-- (BOOL)maybeHandleHistorySwiping:(NSEvent*)theEvent { |
+- (BOOL)handleScrollWheelEvent:(NSEvent*)theEvent { |
if (![theEvent respondsToSelector:@selector(phase)]) |
return NO; |
@@ -520,8 +524,7 @@ BOOL forceMagicMouse = NO; |
} |
// We've already processed this gesture. |
- if (lastProcessedGestureId_ == currentGestureId_ && |
- recognitionState_ != history_swiper::kPending) { |
+ if (recognitionState_ != history_swiper::kPending) { |
return [self shouldConsumeWheelEvent:theEvent]; |
} |
@@ -546,7 +549,7 @@ BOOL forceMagicMouse = NO; |
// callbacks to perform history swiping, magic mouse swipe events use an |
// entirely different set of logic. |
if ((inGesture_ && !receivingTouches_) || forceMagicMouse) |
- return [self maybeHandleMagicMouseHistorySwiping:theEvent]; |
+ return [self handleMagicMouseWheelEvent:theEvent]; |
// The scrollWheel: callback is only relevant if it happens while the user is |
// still actively using the touchpad. |
@@ -573,9 +576,10 @@ BOOL forceMagicMouse = NO; |
if (!browserCanMove) |
return NO; |
- lastProcessedGestureId_ = currentGestureId_; |
- [self beginHistorySwipeInDirection:direction event:theEvent]; |
+ historySwipeDirection_ = direction; |
+ historySwipeDirectionInverted_ = [self isEventDirectionInverted:theEvent]; |
recognitionState_ = history_swiper::kPotential; |
+ [self showHistoryOverlay:direction]; |
return [self shouldConsumeWheelEvent:theEvent]; |
} |
@@ -594,6 +598,7 @@ BOOL forceMagicMouse = NO; |
return event.scrollingDeltaY == 0; |
} |
} |
+ |
@end |
@implementation HistorySwiper (PrivateExposedForTesting) |