Index: chrome/browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper_browsertest.mm |
diff --git a/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper_browsertest.mm b/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper_browsertest.mm |
new file mode 100644 |
index 0000000000000000000000000000000000000000..6680cf82efd401976b81e0d6dbe60995b046ae8a |
--- /dev/null |
+++ b/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper_browsertest.mm |
@@ -0,0 +1,681 @@ |
+// Copyright 2014 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include <Cocoa/Cocoa.h> |
+ |
+#include "base/files/file_path.h" |
+#include "base/logging.h" |
+#include "base/mac/scoped_nsobject.h" |
+#import "base/mac/sdk_forward_declarations.h" |
+#include "base/message_loop/message_loop.h" |
+#include "chrome/browser/ui/browser.h" |
+#include "chrome/browser/ui/tabs/tab_strip_model.h" |
+#include "chrome/test/base/in_process_browser_test.h" |
+#include "chrome/test/base/ui_test_utils.h" |
+#include "content/public/browser/render_view_host.h" |
+#include "content/public/browser/render_widget_host_view.h" |
+#include "content/public/browser/web_contents.h" |
+#include "content/public/test/browser_test_utils.h" |
+#import "third_party/ocmock/OCMock/OCMock.h" |
+#import "third_party/ocmock/ocmock_extensions.h" |
+#include "url/gurl.h" |
+ |
+namespace { |
+ |
+// Refers to how the event is going to be sent to the NSView. There are 3 |
+// relevant sets of APIs. The current code relies on all three sets of APIs. |
+// There is significant information duplication between the three sets of APIs, |
+// but the timing of the callbacks of the three APIs differ significantly. |
+enum Deployment { |
+ // -[NSView touchesBeganWithEvent:] |
+ DEPLOYMENT_TOUCHES_BEGAN, |
+ // -[NSView touchesMovedWithEvent:] |
+ DEPLOYMENT_TOUCHES_MOVED, |
+ // -[NSView touchesEndedWithEvent:] |
+ DEPLOYMENT_TOUCHES_ENDED, |
+ // -[NSView scrollWheel:] |
+ DEPLOYMENT_SCROLL_WHEEL, |
+ // -[NSView beginGestureWithEvent:] |
+ DEPLOYMENT_GESTURE_BEGIN, |
+ // -[NSView endGestureWithEvent:] |
+ DEPLOYMENT_GESTURE_END, |
+}; |
+ |
+} // namespace |
+ |
+// A wrapper object for events queued for replay. |
+@interface QueuedEvent : NSObject { |
+ BOOL _runMessageLoop; |
+ Deployment _deployment; |
+ NSEvent* _event; |
+} |
+// Whether the message loop should be run after this event has been replayed. |
+@property(nonatomic, assign) BOOL runMessageLoop; |
+// How this event should be replayed. |
+@property(nonatomic, assign) Deployment deployment; |
+// The event to be replayed. |
+@property(nonatomic, retain) NSEvent* event; |
+@end |
+ |
+@implementation QueuedEvent |
+@synthesize deployment = _deployment; |
+@synthesize event = _event; |
+@synthesize runMessageLoop = _runMessageLoop; |
+- (void)dealloc { |
+ [_event release]; |
+ [super dealloc]; |
+} |
+@end |
+ |
+class ChromeRenderWidgetHostViewMacHistorySwiperTest |
+ : public InProcessBrowserTest { |
+ public: |
+ ChromeRenderWidgetHostViewMacHistorySwiperTest() |
+ : event_queue_(), touch_(CGPointMake(0, 0)) { |
+ const base::FilePath base_path(FILE_PATH_LITERAL("scroll")); |
+ url1_ = ui_test_utils::GetTestUrl( |
+ base_path, base::FilePath(FILE_PATH_LITERAL("text.html"))); |
+ url2_ = ui_test_utils::GetTestUrl( |
+ base_path, base::FilePath(FILE_PATH_LITERAL("blank.html"))); |
+ } |
+ |
+ virtual void SetUpOnMainThread() OVERRIDE { |
+ event_queue_.reset([[NSMutableArray alloc] init]); |
+ touch_ = CGPointMake(0.5, 0.5); |
+ |
+ // Ensure that the navigation stack is not empty. |
+ ui_test_utils::NavigateToURL(browser(), url1_); |
+ ASSERT_EQ(url1_, GetWebContents()->GetURL()); |
+ ui_test_utils::NavigateToURL(browser(), url2_); |
+ ASSERT_EQ(url2_, GetWebContents()->GetURL()); |
+ } |
+ |
+ virtual void TearDownOnMainThread() OVERRIDE { |
+ event_queue_.reset(); |
+ } |
+ |
+ protected: |
+ // Returns the active web contents. |
+ content::WebContents* GetWebContents() { |
+ return browser()->tab_strip_model()->GetActiveWebContents(); |
+ } |
+ |
+ // Returns the value of |query| from Javascript as an int. |
+ int GetScriptIntValue(const std::string& query) { |
+ int value = 0; |
+ EXPECT_TRUE(content::ExecuteScriptAndExtractInt( |
+ GetWebContents(), |
+ "domAutomationController.send(" + query + ")", |
+ &value)); |
+ return value; |
+ } |
+ |
+ // Returns the vertical scroll offset of the current page. |
+ int GetScrollTop() { |
+ return GetScriptIntValue("document.body.scrollTop"); |
+ } |
+ |
+ bool IsHistorySwipingSupported() { |
+ // These tests require 10.7+ APIs. |
+ return [NSEvent |
+ respondsToSelector:@selector(isSwipeTrackingFromScrollEventsEnabled)]; |
+ } |
+ |
+ // Create mock events -------------------------------------------------------- |
+ |
+ // Creates a mock scroll wheel event that is backed by a real CGEvent. |
+ id MockScrollWheelEvent(NSPoint delta, NSEventType type) { |
+ CGEventRef cg_event = |
+ CGEventCreateScrollWheelEvent(NULL, kCGScrollEventUnitLine, 2, 0, 0); |
+ CGEventSetIntegerValueField(cg_event, kCGScrollWheelEventIsContinuous, 1); |
+ CGEventSetIntegerValueField( |
+ cg_event, kCGScrollWheelEventPointDeltaAxis2, delta.x); |
+ CGEventSetIntegerValueField( |
+ cg_event, kCGScrollWheelEventPointDeltaAxis1, delta.y); |
+ NSEvent* event = [NSEvent eventWithCGEvent:cg_event]; |
+ CFRelease(cg_event); |
+ |
+ id mock_event = [OCMockObject partialMockForObject:event]; |
+ [[[mock_event stub] andReturnBool:NO] isDirectionInvertedFromDevice]; |
+ [(NSEvent*)[[mock_event stub] andReturnValue:OCMOCK_VALUE(type)] type]; |
+ |
+ return mock_event; |
+ } |
+ |
+ // Returns a scroll wheel event with the given parameters. |
+ id ScrollWheelEventWithPhase(NSEventPhase phase, |
+ NSEventPhase momentum_phase, |
+ CGFloat scrolling_delta_x, |
+ CGFloat scrolling_delta_y) { |
+ id event = MockScrollWheelEvent( |
+ NSMakePoint(scrolling_delta_x, scrolling_delta_y), NSScrollWheel); |
+ [(NSEvent*)[[event stub] andReturnValue:OCMOCK_VALUE(phase)] phase]; |
+ [(NSEvent*)[[event stub] |
+ andReturnValue:OCMOCK_VALUE(momentum_phase)] momentumPhase]; |
+ [(NSEvent*)[[event stub] |
+ andReturnValue:OCMOCK_VALUE(scrolling_delta_x)] scrollingDeltaX]; |
+ [(NSEvent*)[[event stub] |
+ andReturnValue:OCMOCK_VALUE(scrolling_delta_y)] scrollingDeltaY]; |
+ NSUInteger modifierFlags = 0; |
+ [(NSEvent*)[[event stub] |
+ andReturnValue:OCMOCK_VALUE(modifierFlags)] modifierFlags]; |
+ NSView* view = |
+ GetWebContents()->GetRenderViewHost()->GetView()->GetNativeView(); |
+ NSWindow* window = [view window]; |
+ [(NSEvent*)[[event stub] andReturnValue:OCMOCK_VALUE(window)] window]; |
+ |
+ return event; |
+ } |
+ |
+ // Queue events for playback ------------------------------------------------- |
+ |
+ void QueueEvent(id event, Deployment deployment, BOOL run_message_loop) { |
+ QueuedEvent* queued_event = [[[QueuedEvent alloc] init] autorelease]; |
+ queued_event.event = event; |
+ queued_event.deployment = deployment; |
+ queued_event.runMessageLoop = run_message_loop; |
+ [event_queue_ addObject:queued_event]; |
+ } |
+ |
+ // Queues a trackpad scroll event (e.g. [NSView scrollWheel:]) |
+ void QueueTrackpadScroll(int dx, |
+ int dy, |
+ NSEventPhase phase, |
+ BOOL run_message_loop) { |
+ id event = ScrollWheelEventWithPhase(phase, NSEventPhaseNone, dx, dy); |
+ QueueEvent(event, DEPLOYMENT_SCROLL_WHEEL, run_message_loop); |
+ } |
+ |
+ // Queues a gesture begin event (e.g. [NSView gestureDidBegin:]) |
+ void QueueGestureBegin() { |
+ id event = [OCMockObject mockForClass:[NSEvent class]]; |
+ NSEventType type = NSEventTypeBeginGesture; |
+ [(NSEvent*)[[event stub] andReturnValue:OCMOCK_VALUE(type)] type]; |
+ QueueEvent(event, DEPLOYMENT_GESTURE_BEGIN, NO); |
+ } |
+ |
+ // Queues a gesture end event (e.g. [NSView gestureDidEnd:]) |
+ void QueueGestureEnd() { |
+ id event = [OCMockObject mockForClass:[NSEvent class]]; |
+ NSEventType type = NSEventTypeEndGesture; |
+ [(NSEvent*)[[event stub] andReturnValue:OCMOCK_VALUE(type)] type]; |
+ QueueEvent(event, DEPLOYMENT_GESTURE_END, NO); |
+ } |
+ |
+ // Queues a touch event with absolute coordinates |x| and |y|. |
+ void QueueTouch(CGFloat x, |
+ CGFloat y, |
+ Deployment deployment, |
+ NSEventType type, |
+ short subtype, |
+ BOOL run_message_loop) { |
+ id event = [OCMockObject mockForClass:[NSEvent class]]; |
+ [(NSEvent*)[[event stub] andReturnValue:OCMOCK_VALUE(type)] type]; |
+ [(NSEvent*)[[event stub] andReturnValue:OCMOCK_VALUE(subtype)] subtype]; |
+ |
+ id mock_touch = [OCMockObject mockForClass:[NSTouch class]]; |
+ [[[mock_touch stub] andReturnNSPoint:NSMakePoint(x, y)] normalizedPosition]; |
+ NSArray* touches = @[ mock_touch ]; |
+ [[[event stub] andReturn:touches] touchesMatchingPhase:NSTouchPhaseAny |
+ inView:[OCMArg any]]; |
+ [[[event stub] andReturnBool:NO] isDirectionInvertedFromDevice]; |
+ QueueEvent(event, deployment, run_message_loop); |
+ } |
+ |
+ // Convenience methods for event queuing ------------------------------------- |
+ |
+ // Trackpad scroll events are roughly related to touch events. Given a |
+ // trackpad scroll delta, approximate the change to the touch event. |
+ void UpdateTouchLocationFromTrackpadScroll(int dx, int dy) { |
+ touch_.x -= dx * 0.001; |
+ touch_.y -= dy * 0.001; |
+ } |
+ |
+ // Queue the typical events at the beginning of a new swipe gesture. The |
+ // ordering and values were determined by recording real swipe events. |
+ void QueueBeginningEvents(int dx, int dy) { |
+ QueueTouch( |
+ DEPLOYMENT_TOUCHES_BEGAN, NSEventTypeGesture, NSMouseEventSubtype, NO); |
+ QueueTrackpadScroll(0, 0, NSEventPhaseMayBegin, YES); |
+ QueueTouch( |
+ DEPLOYMENT_TOUCHES_MOVED, NSEventTypeGesture, NSMouseEventSubtype, NO); |
+ |
+ QueueTrackpadScroll(dx, dy, NSEventPhaseBegan, NO); |
+ QueueGestureBegin(); |
+ QueueTouch(DEPLOYMENT_TOUCHES_MOVED, |
+ NSEventTypeBeginGesture, |
+ NSTouchEventSubtype, |
+ NO); |
+ QueueTouch( |
+ DEPLOYMENT_TOUCHES_MOVED, NSEventTypeGesture, NSTouchEventSubtype, YES); |
+ UpdateTouchLocationFromTrackpadScroll(dx, dy); |
+ QueueTouch( |
+ DEPLOYMENT_TOUCHES_MOVED, NSEventTypeGesture, NSTouchEventSubtype, NO); |
+ } |
+ |
+ // Queue the typical events at the end of a new swipe gesture. The ordering |
+ // and values were determined by recording real swipe events. |
+ void QueueEndEvents() { |
+ QueueTouch(DEPLOYMENT_TOUCHES_MOVED, |
+ NSEventTypeEndGesture, |
+ NSMouseEventSubtype, |
+ NO); |
+ QueueTouch(DEPLOYMENT_TOUCHES_ENDED, |
+ NSEventTypeEndGesture, |
+ NSMouseEventSubtype, |
+ NO); |
+ QueueGestureEnd(); |
+ QueueTrackpadScroll(0, 0, NSEventPhaseEnded, YES); |
+ } |
+ |
+ // Queues a trackpad scroll movement and a touch movement event. |
+ void QueueScrollAndTouchMoved(int dx, int dy) { |
+ QueueTrackpadScroll(dx, dy, NSEventPhaseChanged, NO); |
+ UpdateTouchLocationFromTrackpadScroll(dx, dy); |
+ QueueTouch( |
+ DEPLOYMENT_TOUCHES_MOVED, NSEventTypeGesture, NSTouchEventSubtype, YES); |
+ } |
+ |
+ // Queues a touch event with the stored touch coordinates. |
+ void QueueTouch(Deployment deployment, |
+ NSEventType type, |
+ short subtype, |
+ BOOL run_message_loop) { |
+ QueueTouch(touch_.x, touch_.y, deployment, type, subtype, run_message_loop); |
+ } |
+ |
+ // Replays the events from the queue. |
+ void RunQueuedEvents() { |
+ while ([event_queue_ count] > 0) { |
+ QueuedEvent* queued_event = [event_queue_ objectAtIndex:0]; |
+ NSEvent* event = queued_event.event; |
+ NSView* view = |
+ GetWebContents()->GetRenderViewHost()->GetView()->GetNativeView(); |
+ BOOL run_loop = queued_event.runMessageLoop; |
+ switch (queued_event.deployment) { |
+ case DEPLOYMENT_GESTURE_BEGIN: |
+ [view beginGestureWithEvent:event]; |
+ break; |
+ case DEPLOYMENT_GESTURE_END: |
+ [view endGestureWithEvent:event]; |
+ break; |
+ case DEPLOYMENT_SCROLL_WHEEL: |
+ [view scrollWheel:event]; |
+ break; |
+ case DEPLOYMENT_TOUCHES_BEGAN: |
+ [view touchesBeganWithEvent:event]; |
+ break; |
+ case DEPLOYMENT_TOUCHES_ENDED: |
+ [view touchesEndedWithEvent:event]; |
+ break; |
+ case DEPLOYMENT_TOUCHES_MOVED: |
+ [view touchesMovedWithEvent:event]; |
+ break; |
+ } |
+ |
+ [event_queue_ removeObjectAtIndex:0]; |
+ |
+ if (!run_loop) |
+ continue; |
+ // Give time for the IPC to make it to the renderer process. If the IPC |
+ // doesn't have time to make it to the renderer process, that's okay, |
+ // since that simulates realistic conditions. |
+ [[NSRunLoop currentRunLoop] |
+ runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.001]]; |
+ // The renderer process returns an IPC, which needs to be handled. |
+ base::MessageLoop::current()->RunUntilIdle(); |
+ } |
+ } |
+ |
+ void ExpectUrlAndOffset(const GURL& url, int offset) { |
+ content::WaitForLoadStop(GetWebContents()); |
+ EXPECT_EQ(url, GetWebContents()->GetURL()); |
+ |
+ const int scroll_offset = GetScrollTop(); |
+ EXPECT_EQ(offset, scroll_offset); |
+ } |
+ |
+ GURL url1_; |
+ GURL url2_; |
+ base::scoped_nsobject<NSMutableArray> event_queue_; |
+ // The current location of the user's fingers on the track pad. |
+ CGPoint touch_; |
+ |
+ private: |
+ DISALLOW_COPY_AND_ASSIGN(ChromeRenderWidgetHostViewMacHistorySwiperTest); |
+}; |
+ |
+// The ordering, timing, and parameters of the events was determined by |
+// recording a real swipe. |
+IN_PROC_BROWSER_TEST_F(ChromeRenderWidgetHostViewMacHistorySwiperTest, |
+ TestBackwardsHistoryNavigationRealData) { |
+ if (!IsHistorySwipingSupported()) |
+ return; |
+ |
+ QueueTouch(0.510681, |
+ 0.444672, |
+ DEPLOYMENT_TOUCHES_BEGAN, |
+ NSEventTypeGesture, |
+ NSMouseEventSubtype, |
+ NO); |
+ QueueTrackpadScroll(0, 0, NSEventPhaseMayBegin, YES); |
+ QueueTouch(0.510681, |
+ 0.444672, |
+ DEPLOYMENT_TOUCHES_MOVED, |
+ NSEventTypeGesture, |
+ NSMouseEventSubtype, |
+ NO); |
+ |
+ QueueTrackpadScroll(1, 0, NSEventPhaseBegan, NO); |
+ QueueGestureBegin(); |
+ QueueTouch(0.510681, |
+ 0.444672, |
+ DEPLOYMENT_TOUCHES_MOVED, |
+ NSEventTypeBeginGesture, |
+ NSTouchEventSubtype, |
+ NO); |
+ QueueTouch(0.510681, |
+ 0.444672, |
+ DEPLOYMENT_TOUCHES_MOVED, |
+ NSEventTypeGesture, |
+ NSTouchEventSubtype, |
+ YES); |
+ |
+ QueueTouch(0.507019, |
+ 0.444092, |
+ DEPLOYMENT_TOUCHES_MOVED, |
+ NSEventTypeGesture, |
+ NSTouchEventSubtype, |
+ NO); |
+ QueueTrackpadScroll(3, 0, NSEventPhaseChanged, YES); |
+ |
+ QueueTrackpadScroll(3, -1, NSEventPhaseChanged, NO); |
+ QueueTouch(0.502861, |
+ 0.443512, |
+ DEPLOYMENT_TOUCHES_MOVED, |
+ NSEventTypeGesture, |
+ NSTouchEventSubtype, |
+ YES); |
+ |
+ QueueTrackpadScroll(6, -1, NSEventPhaseChanged, NO); |
+ QueueTouch(0.497002, |
+ 0.44294, |
+ DEPLOYMENT_TOUCHES_MOVED, |
+ NSEventTypeGesture, |
+ NSTouchEventSubtype, |
+ YES); |
+ |
+ QueueTrackpadScroll(5, -1, NSEventPhaseChanged, NO); |
+ QueueTouch(0.487236, |
+ 0.44149, |
+ DEPLOYMENT_TOUCHES_MOVED, |
+ NSEventTypeGesture, |
+ NSTouchEventSubtype, |
+ YES); |
+ |
+ QueueTrackpadScroll(8, -1, NSEventPhaseChanged, NO); |
+ QueueTouch(0.480392, |
+ 0.440628, |
+ DEPLOYMENT_TOUCHES_MOVED, |
+ NSEventTypeGesture, |
+ NSTouchEventSubtype, |
+ NO); |
+ QueueTouch(0.475266, |
+ 0.440338, |
+ DEPLOYMENT_TOUCHES_MOVED, |
+ NSEventTypeGesture, |
+ NSTouchEventSubtype, |
+ YES); |
+ |
+ QueueTrackpadScroll(6, -1, NSEventPhaseChanged, NO); |
+ QueueTrackpadScroll(10, -1, NSEventPhaseChanged, NO); |
+ QueueTouch(0.467934, |
+ 0.439758, |
+ DEPLOYMENT_TOUCHES_MOVED, |
+ NSEventTypeGesture, |
+ NSTouchEventSubtype, |
+ YES); |
+ |
+ QueueTrackpadScroll(6, -1, NSEventPhaseChanged, NO); |
+ QueueTouch(0.462807, |
+ 0.439186, |
+ DEPLOYMENT_TOUCHES_MOVED, |
+ NSEventTypeGesture, |
+ NSTouchEventSubtype, |
+ YES); |
+ QueueTrackpadScroll(12, -1, NSEventPhaseChanged, NO); |
+ QueueTouch(0.454018, |
+ 0.438316, |
+ DEPLOYMENT_TOUCHES_MOVED, |
+ NSEventTypeGesture, |
+ NSTouchEventSubtype, |
+ YES); |
+ |
+ QueueTrackpadScroll(6, -1, NSEventPhaseChanged, NO); |
+ QueueTouch(0.449623, |
+ 0.438026, |
+ DEPLOYMENT_TOUCHES_MOVED, |
+ NSEventTypeGesture, |
+ NSTouchEventSubtype, |
+ YES); |
+ |
+ QueueTrackpadScroll(9, 0, NSEventPhaseChanged, NO); |
+ QueueTouch(0.443275, |
+ 0.437744, |
+ DEPLOYMENT_TOUCHES_MOVED, |
+ NSEventTypeGesture, |
+ NSTouchEventSubtype, |
+ YES); |
+ QueueTouch(0.437164, |
+ 0.437164, |
+ DEPLOYMENT_TOUCHES_MOVED, |
+ NSEventTypeGesture, |
+ NSTouchEventSubtype, |
+ YES); |
+ |
+ QueueTrackpadScroll(9, -1, NSEventPhaseChanged, NO); |
+ QueueTouch(0.431305, |
+ 0.436874, |
+ DEPLOYMENT_TOUCHES_MOVED, |
+ NSEventTypeGesture, |
+ NSTouchEventSubtype, |
+ YES); |
+ QueueTrackpadScroll(8, -1, NSEventPhaseChanged, NO); |
+ QueueTouch(0.425926, |
+ 0.436295, |
+ DEPLOYMENT_TOUCHES_MOVED, |
+ NSEventTypeGesture, |
+ NSTouchEventSubtype, |
+ YES); |
+ QueueTrackpadScroll(7, -1, NSEventPhaseChanged, NO); |
+ QueueTouch(0.420311, |
+ 0.43573, |
+ DEPLOYMENT_TOUCHES_MOVED, |
+ NSEventTypeGesture, |
+ NSTouchEventSubtype, |
+ YES); |
+ |
+ QueueTrackpadScroll(7, -1, NSEventPhaseChanged, NO); |
+ QueueTouch(0.415184, |
+ 0.43544, |
+ DEPLOYMENT_TOUCHES_MOVED, |
+ NSEventTypeGesture, |
+ NSTouchEventSubtype, |
+ YES); |
+ QueueTrackpadScroll(6, -1, NSEventPhaseChanged, NO); |
+ QueueTouch(0.410057, |
+ 0.43457, |
+ DEPLOYMENT_TOUCHES_MOVED, |
+ NSEventTypeGesture, |
+ NSTouchEventSubtype, |
+ YES); |
+ QueueTouch(0.40493, |
+ 0.43399, |
+ DEPLOYMENT_TOUCHES_MOVED, |
+ NSEventTypeGesture, |
+ NSTouchEventSubtype, |
+ YES); |
+ QueueTrackpadScroll(7, -1, NSEventPhaseChanged, YES); |
+ QueueTrackpadScroll(3, -1, NSEventPhaseChanged, NO); |
+ QueueTouch(0.402489, |
+ 0.433701, |
+ DEPLOYMENT_TOUCHES_MOVED, |
+ NSEventTypeGesture, |
+ NSTouchEventSubtype, |
+ YES); |
+ QueueTrackpadScroll(5, 0, NSEventPhaseChanged, NO); |
+ QueueTouch(0.398094, |
+ 0.433418, |
+ DEPLOYMENT_TOUCHES_MOVED, |
+ NSEventTypeGesture, |
+ NSTouchEventSubtype, |
+ YES); |
+ |
+ QueueTrackpadScroll(4, -1, NSEventPhaseChanged, NO); |
+ QueueTouch(0.394669, |
+ 0.433128, |
+ DEPLOYMENT_TOUCHES_MOVED, |
+ NSEventTypeGesture, |
+ NSTouchEventSubtype, |
+ YES); |
+ QueueTouch(0.391006, |
+ 0.432549, |
+ DEPLOYMENT_TOUCHES_MOVED, |
+ NSEventTypeGesture, |
+ NSTouchEventSubtype, |
+ YES); |
+ QueueTrackpadScroll(4, -1, NSEventPhaseChanged, NO); |
+ QueueTrackpadScroll(5, 0, NSEventPhaseChanged, YES); |
+ QueueTouch(0.386848, |
+ 0.432259, |
+ DEPLOYMENT_TOUCHES_MOVED, |
+ NSEventTypeGesture, |
+ NSTouchEventSubtype, |
+ YES); |
+ QueueTouch(0.38343, |
+ 0.432259, |
+ DEPLOYMENT_TOUCHES_MOVED, |
+ NSEventTypeGesture, |
+ NSTouchEventSubtype, |
+ YES); |
+ |
+ // Skipped a bunch of events. The data on the gesture end events are fudged. |
+ |
+ QueueTouch(0.38343, |
+ 0.432259, |
+ DEPLOYMENT_TOUCHES_MOVED, |
+ NSEventTypeEndGesture, |
+ NSMouseEventSubtype, |
+ NO); |
+ QueueTouch(0.38343, |
+ 0.432259, |
+ DEPLOYMENT_TOUCHES_ENDED, |
+ NSEventTypeEndGesture, |
+ NSMouseEventSubtype, |
+ NO); |
+ QueueGestureEnd(); |
+ QueueTrackpadScroll(0, 0, NSEventPhaseEnded, YES); |
+ |
+ RunQueuedEvents(); |
+ ExpectUrlAndOffset(url1_, 0); |
+} |
+ |
+// Each movement event that has non-zero parameters has both horizontal and |
+// vertical motion. This should not trigger history navigation. |
+IN_PROC_BROWSER_TEST_F(ChromeRenderWidgetHostViewMacHistorySwiperTest, |
+ TestAllDiagonalSwipes) { |
+ if (!IsHistorySwipingSupported()) |
+ return; |
+ |
+ QueueBeginningEvents(1, -1); |
+ for (int i = 0; i < 150; ++i) |
+ QueueScrollAndTouchMoved(1, -1); |
+ |
+ QueueEndEvents(); |
+ RunQueuedEvents(); |
+ ExpectUrlAndOffset(url2_, 150); |
+} |
+ |
+// The movements are equal part diagonal, horizontal, and vertical. This should |
+// not trigger history navigation. |
+IN_PROC_BROWSER_TEST_F(ChromeRenderWidgetHostViewMacHistorySwiperTest, |
+ TestStaggeredDiagonalSwipe) { |
+ if (!IsHistorySwipingSupported()) |
+ return; |
+ |
+ QueueBeginningEvents(1, 0); |
+ for (int i = 0; i < 150; ++i) { |
+ switch (i % 3) { |
+ case 0: |
+ QueueScrollAndTouchMoved(1, -1); |
+ break; |
+ case 1: |
+ QueueScrollAndTouchMoved(0, -1); |
+ break; |
+ case 2: |
+ QueueScrollAndTouchMoved(1, 0); |
+ break; |
+ default: |
+ NOTREACHED(); |
+ } |
+ } |
+ |
+ QueueEndEvents(); |
+ RunQueuedEvents(); |
+ |
+ content::WaitForLoadStop(GetWebContents()); |
+ EXPECT_EQ(url2_, GetWebContents()->GetURL()); |
+ |
+ // Depending on the timing of the IPCs, some of the initial events might be |
+ // recognized as part of the history swipe, and not forwarded to the renderer, |
+ // resulting in a non-deterministic scroll offset. This is bad, as some |
+ // vertical motion is lost. Once the history swiper logic is fixed, this |
+ // should become a direct comparison between 'scroll_offset' and 100. |
+ // crbug.com/375514 |
+ const int scroll_offset = GetScrollTop(); |
+ EXPECT_GT(scroll_offset, 85); |
+} |
+ |
+// The movement events are mostly in the horizontal direction, which should |
+// trigger a history swipe. This should trigger history navigation. |
+IN_PROC_BROWSER_TEST_F(ChromeRenderWidgetHostViewMacHistorySwiperTest, |
+ TestMostlyHorizontal) { |
+ if (!IsHistorySwipingSupported()) |
+ return; |
+ |
+ QueueBeginningEvents(1, -1); |
+ for (int i = 0; i < 150; ++i) { |
+ if (i % 10 == 0) { |
+ QueueScrollAndTouchMoved(0, -1); |
+ } else if (i % 5 == 0) { |
+ QueueScrollAndTouchMoved(1, -1); |
+ } else { |
+ QueueScrollAndTouchMoved(1, 0); |
+ } |
+ } |
+ |
+ QueueEndEvents(); |
+ RunQueuedEvents(); |
+ ExpectUrlAndOffset(url1_, 0); |
+} |
+ |
+// Each movement event is horizontal, except the first two. This should trigger |
+// history navigation. This test is DISABLED because it has never worked. Once |
+// the flaw in the history swiper logic has been corrected, this test should be |
+// enabled. |
+// crbug.com/375512 |
+IN_PROC_BROWSER_TEST_F(ChromeRenderWidgetHostViewMacHistorySwiperTest, |
+ DISABLED_TestAllHorizontalButFirst) { |
+ if (!IsHistorySwipingSupported()) |
+ return; |
+ |
+ QueueBeginningEvents(0, -1); |
+ QueueScrollAndTouchMoved(0, -1); |
+ for (int i = 0; i < 149; ++i) |
+ QueueScrollAndTouchMoved(1, 0); |
+ |
+ QueueEndEvents(); |
+ RunQueuedEvents(); |
+ ExpectUrlAndOffset(url1_, 0); |
+} |