summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--base/mac/sdk_forward_declarations.h1
-rw-r--r--chrome/browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper.mm16
-rw-r--r--chrome/browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper_unit_test.mm55
3 files changed, 68 insertions, 4 deletions
diff --git a/base/mac/sdk_forward_declarations.h b/base/mac/sdk_forward_declarations.h
index 2fadf10..c2383f8 100644
--- a/base/mac/sdk_forward_declarations.h
+++ b/base/mac/sdk_forward_declarations.h
@@ -43,6 +43,7 @@ typedef NSInteger NSWindowAnimationBehavior;
@interface NSEvent (LionSDK)
+ (BOOL)isSwipeTrackingFromScrollEventsEnabled;
+- (NSEventPhase)momentumPhase;
- (NSEventPhase)phase;
- (CGFloat)scrollingDeltaX;
- (CGFloat)scrollingDeltaY;
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 306ff08..08c758e 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
@@ -225,8 +225,10 @@
- (void)beginHistorySwipeInDirection:
(history_swiper::NavigationDirection)direction
event:(NSEvent*)event {
- // There shouldn't be an existing history overlay.
- DCHECK(historyOverlay_ == nil);
+ // 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];
HistoryOverlayController* historyOverlay = [[HistoryOverlayController alloc]
initForMode:(direction == history_swiper::kForwards)
@@ -302,7 +304,15 @@
if (![theEvent respondsToSelector:@selector(phase)])
return NO;
- if ([theEvent phase] != NSEventPhaseChanged)
+ // If the window has a horizontal scroll bar, sometimes Cocoa gets confused
+ // and sends us momentum scroll wheel events instead of gesture scroll events
+ // (even though the user is still actively swiping).
+ if ([theEvent phase] != NSEventPhaseChanged &&
+ [theEvent momentumPhase] != NSEventPhaseChanged) {
+ return NO;
+ }
+
+ if (!inGesture_)
return NO;
CGFloat yDelta = gestureCurrentPoint_.y - gestureStartPoint_.y;
diff --git a/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper_unit_test.mm b/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper_unit_test.mm
index 9765041..bd2d382 100644
--- a/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper_unit_test.mm
+++ b/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper_unit_test.mm
@@ -48,11 +48,15 @@ class MacHistorySwiperTest : public CocoaTest {
event:[OCMArg any]];
[[[[mockHistorySwiper stub] andDo:^(NSInvocation* invocation) {
++begin_count_;
+ // beginHistorySwipeInDirection: calls endHistorySwipe internally.
+ --end_count_;
}] andForwardToRealObject]
beginHistorySwipeInDirection:history_swiper::kForwards
event:[OCMArg any]];
[[[[mockHistorySwiper stub] andDo:^(NSInvocation* invocation) {
++begin_count_;
+ // beginHistorySwipeInDirection: calls endHistorySwipe internally.
+ --end_count_;
}] andForwardToRealObject]
beginHistorySwipeInDirection:history_swiper::kBackwards
event:[OCMArg any]];
@@ -82,6 +86,7 @@ class MacHistorySwiperTest : public CocoaTest {
void startGestureInMiddle();
void moveGestureInMiddle();
void moveGestureAtPoint(NSPoint point);
+ void momentumMoveGestureAtPoint(NSPoint point);
void endGestureAtPoint(NSPoint point);
HistorySwiper* historySwiper_;
@@ -112,13 +117,19 @@ id mockEventWithPoint(NSPoint point, NSEventType type) {
return mockEvent;
}
-id scrollWheelEventWithPhase(NSEventPhase phase) {
+id scrollWheelEventWithPhase(NSEventPhase phase, NSEventPhase momentumPhase) {
// The point isn't used, so we pass in bogus data.
id event = mockEventWithPoint(makePoint(0,0), NSScrollWheel);
[(NSEvent*)[[event stub] andReturnValue:OCMOCK_VALUE(phase)] phase];
+ [(NSEvent*)
+ [[event stub] andReturnValue:OCMOCK_VALUE(momentumPhase)] momentumPhase];
return event;
}
+id scrollWheelEventWithPhase(NSEventPhase phase) {
+ return scrollWheelEventWithPhase(phase, NSEventPhaseNone);
+}
+
void MacHistorySwiperTest::startGestureInMiddle() {
NSEvent* event = mockEventWithPoint(makePoint(0.5, 0.5), NSEventTypeGesture);
[historySwiper_ touchesBeganWithEvent:event];
@@ -144,6 +155,15 @@ void MacHistorySwiperTest::moveGestureAtPoint(NSPoint point) {
[historySwiper_ handleEvent:scrollEvent];
}
+void MacHistorySwiperTest::momentumMoveGestureAtPoint(NSPoint point) {
+ NSEvent* event = mockEventWithPoint(point, NSEventTypeGesture);
+ [historySwiper_ touchesMovedWithEvent:event];
+
+ NSEvent* scrollEvent =
+ scrollWheelEventWithPhase(NSEventPhaseNone, NSEventPhaseChanged);
+ [historySwiper_ handleEvent:scrollEvent];
+}
+
void MacHistorySwiperTest::endGestureAtPoint(NSPoint point) {
NSEvent* event = mockEventWithPoint(point, NSEventTypeGesture);
[historySwiper_ touchesEndedWithEvent:event];
@@ -260,6 +280,39 @@ TEST_F(MacHistorySwiperTest, SwipeLeftThenDown) {
EXPECT_FALSE(navigated_left_);
}
+// Sometimes Cocoa gets confused and sends us a momentum swipe event instead of
+// a swipe gesture event. We should still function appropriately.
+TEST_F(MacHistorySwiperTest, MomentumSwipeLeft) {
+ // These tests require 10.7+ APIs.
+ if (![NSEvent
+ respondsToSelector:@selector(isSwipeTrackingFromScrollEventsEnabled)])
+ return;
+
+ startGestureInMiddle();
+
+ // Send a momentum move gesture.
+ momentumMoveGestureAtPoint(makePoint(0.5, 0.5));
+ EXPECT_EQ(begin_count_, 0);
+ EXPECT_EQ(end_count_, 0);
+
+ // Callbacks from blink to set the relevant state for history swiping.
+ [historySwiper_ gotUnhandledWheelEvent];
+ [historySwiper_ scrollOffsetPinnedToLeft:YES toRight:YES];
+ [historySwiper_ setHasHorizontalScrollbar:NO];
+
+ momentumMoveGestureAtPoint(makePoint(0.2, 0.5));
+ EXPECT_EQ(begin_count_, 1);
+ EXPECT_EQ(end_count_, 0);
+ EXPECT_FALSE(navigated_right_);
+ EXPECT_FALSE(navigated_left_);
+
+ endGestureAtPoint(makePoint(0.2, 0.5));
+ EXPECT_EQ(begin_count_, 1);
+ EXPECT_EQ(end_count_, 1);
+ EXPECT_FALSE(navigated_right_);
+ EXPECT_TRUE(navigated_left_);
+}
+
// User starts a swipe but doesn't move.
TEST_F(MacHistorySwiperTest, NoSwipe) {
// These tests require 10.7+ APIs.