chrome_render_widget_host_view_mac_history_swiper_browsertest.mm revision cedac228d2dd51db4b79ea1e72c7f249408ee061
1// Copyright 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <Cocoa/Cocoa.h> 6 7#include "base/files/file_path.h" 8#include "base/logging.h" 9#include "base/mac/scoped_nsobject.h" 10#import "base/mac/sdk_forward_declarations.h" 11#include "base/message_loop/message_loop.h" 12#include "chrome/browser/ui/browser.h" 13#include "chrome/browser/ui/tabs/tab_strip_model.h" 14#include "chrome/test/base/in_process_browser_test.h" 15#include "chrome/test/base/ui_test_utils.h" 16#include "content/public/browser/render_view_host.h" 17#include "content/public/browser/render_widget_host_view.h" 18#include "content/public/browser/web_contents.h" 19#include "content/public/test/browser_test_utils.h" 20#import "third_party/ocmock/OCMock/OCMock.h" 21#import "third_party/ocmock/ocmock_extensions.h" 22#include "url/gurl.h" 23 24namespace { 25 26// Refers to how the event is going to be sent to the NSView. There are 3 27// relevant sets of APIs. The current code relies on all three sets of APIs. 28// There is significant information duplication between the three sets of APIs, 29// but the timing of the callbacks of the three APIs differ significantly. 30enum Deployment { 31 // -[NSView touchesBeganWithEvent:] 32 DEPLOYMENT_TOUCHES_BEGAN, 33 // -[NSView touchesMovedWithEvent:] 34 DEPLOYMENT_TOUCHES_MOVED, 35 // -[NSView touchesEndedWithEvent:] 36 DEPLOYMENT_TOUCHES_ENDED, 37 // -[NSView scrollWheel:] 38 DEPLOYMENT_SCROLL_WHEEL, 39 // -[NSView beginGestureWithEvent:] 40 DEPLOYMENT_GESTURE_BEGIN, 41 // -[NSView endGestureWithEvent:] 42 DEPLOYMENT_GESTURE_END, 43}; 44 45} // namespace 46 47// A wrapper object for events queued for replay. 48@interface QueuedEvent : NSObject { 49 BOOL _runMessageLoop; 50 Deployment _deployment; 51 NSEvent* _event; 52} 53// Whether the message loop should be run after this event has been replayed. 54@property(nonatomic, assign) BOOL runMessageLoop; 55// How this event should be replayed. 56@property(nonatomic, assign) Deployment deployment; 57// The event to be replayed. 58@property(nonatomic, retain) NSEvent* event; 59@end 60 61@implementation QueuedEvent 62@synthesize deployment = _deployment; 63@synthesize event = _event; 64@synthesize runMessageLoop = _runMessageLoop; 65- (void)dealloc { 66 [_event release]; 67 [super dealloc]; 68} 69@end 70 71class ChromeRenderWidgetHostViewMacHistorySwiperTest 72 : public InProcessBrowserTest { 73 public: 74 ChromeRenderWidgetHostViewMacHistorySwiperTest() 75 : event_queue_(), touch_(CGPointMake(0, 0)) { 76 const base::FilePath base_path(FILE_PATH_LITERAL("scroll")); 77 url1_ = ui_test_utils::GetTestUrl( 78 base_path, base::FilePath(FILE_PATH_LITERAL("text.html"))); 79 url2_ = ui_test_utils::GetTestUrl( 80 base_path, base::FilePath(FILE_PATH_LITERAL("blank.html"))); 81 } 82 83 virtual void SetUpOnMainThread() OVERRIDE { 84 event_queue_.reset([[NSMutableArray alloc] init]); 85 touch_ = CGPointMake(0.5, 0.5); 86 87 // Ensure that the navigation stack is not empty. 88 ui_test_utils::NavigateToURL(browser(), url1_); 89 ASSERT_EQ(url1_, GetWebContents()->GetURL()); 90 ui_test_utils::NavigateToURL(browser(), url2_); 91 ASSERT_EQ(url2_, GetWebContents()->GetURL()); 92 } 93 94 virtual void TearDownOnMainThread() OVERRIDE { 95 event_queue_.reset(); 96 } 97 98 protected: 99 // Returns the active web contents. 100 content::WebContents* GetWebContents() { 101 return browser()->tab_strip_model()->GetActiveWebContents(); 102 } 103 104 // Returns the value of |query| from Javascript as an int. 105 int GetScriptIntValue(const std::string& query) { 106 int value = 0; 107 EXPECT_TRUE(content::ExecuteScriptAndExtractInt( 108 GetWebContents(), 109 "domAutomationController.send(" + query + ")", 110 &value)); 111 return value; 112 } 113 114 // Returns the vertical scroll offset of the current page. 115 int GetScrollTop() { 116 return GetScriptIntValue("document.body.scrollTop"); 117 } 118 119 bool IsHistorySwipingSupported() { 120 // These tests require 10.7+ APIs. 121 return [NSEvent 122 respondsToSelector:@selector(isSwipeTrackingFromScrollEventsEnabled)]; 123 } 124 125 // Create mock events -------------------------------------------------------- 126 127 // Creates a mock scroll wheel event that is backed by a real CGEvent. 128 id MockScrollWheelEvent(NSPoint delta, NSEventType type) { 129 CGEventRef cg_event = 130 CGEventCreateScrollWheelEvent(NULL, kCGScrollEventUnitLine, 2, 0, 0); 131 CGEventSetIntegerValueField(cg_event, kCGScrollWheelEventIsContinuous, 1); 132 CGEventSetIntegerValueField( 133 cg_event, kCGScrollWheelEventPointDeltaAxis2, delta.x); 134 CGEventSetIntegerValueField( 135 cg_event, kCGScrollWheelEventPointDeltaAxis1, delta.y); 136 NSEvent* event = [NSEvent eventWithCGEvent:cg_event]; 137 CFRelease(cg_event); 138 139 id mock_event = [OCMockObject partialMockForObject:event]; 140 [[[mock_event stub] andReturnBool:NO] isDirectionInvertedFromDevice]; 141 [(NSEvent*)[[mock_event stub] andReturnValue:OCMOCK_VALUE(type)] type]; 142 143 return mock_event; 144 } 145 146 // Returns a scroll wheel event with the given parameters. 147 id ScrollWheelEventWithPhase(NSEventPhase phase, 148 NSEventPhase momentum_phase, 149 CGFloat scrolling_delta_x, 150 CGFloat scrolling_delta_y) { 151 id event = MockScrollWheelEvent( 152 NSMakePoint(scrolling_delta_x, scrolling_delta_y), NSScrollWheel); 153 [(NSEvent*)[[event stub] andReturnValue:OCMOCK_VALUE(phase)] phase]; 154 [(NSEvent*)[[event stub] 155 andReturnValue:OCMOCK_VALUE(momentum_phase)] momentumPhase]; 156 [(NSEvent*)[[event stub] 157 andReturnValue:OCMOCK_VALUE(scrolling_delta_x)] scrollingDeltaX]; 158 [(NSEvent*)[[event stub] 159 andReturnValue:OCMOCK_VALUE(scrolling_delta_y)] scrollingDeltaY]; 160 NSUInteger modifierFlags = 0; 161 [(NSEvent*)[[event stub] 162 andReturnValue:OCMOCK_VALUE(modifierFlags)] modifierFlags]; 163 NSView* view = 164 GetWebContents()->GetRenderViewHost()->GetView()->GetNativeView(); 165 NSWindow* window = [view window]; 166 [(NSEvent*)[[event stub] andReturnValue:OCMOCK_VALUE(window)] window]; 167 168 return event; 169 } 170 171 // Queue events for playback ------------------------------------------------- 172 173 void QueueEvent(id event, Deployment deployment, BOOL run_message_loop) { 174 QueuedEvent* queued_event = [[[QueuedEvent alloc] init] autorelease]; 175 queued_event.event = event; 176 queued_event.deployment = deployment; 177 queued_event.runMessageLoop = run_message_loop; 178 [event_queue_ addObject:queued_event]; 179 } 180 181 // Queues a trackpad scroll event (e.g. [NSView scrollWheel:]) 182 void QueueTrackpadScroll(int dx, 183 int dy, 184 NSEventPhase phase, 185 BOOL run_message_loop) { 186 id event = ScrollWheelEventWithPhase(phase, NSEventPhaseNone, dx, dy); 187 QueueEvent(event, DEPLOYMENT_SCROLL_WHEEL, run_message_loop); 188 } 189 190 // Queues a gesture begin event (e.g. [NSView gestureDidBegin:]) 191 void QueueGestureBegin() { 192 id event = [OCMockObject mockForClass:[NSEvent class]]; 193 NSEventType type = NSEventTypeBeginGesture; 194 [(NSEvent*)[[event stub] andReturnValue:OCMOCK_VALUE(type)] type]; 195 QueueEvent(event, DEPLOYMENT_GESTURE_BEGIN, NO); 196 } 197 198 // Queues a gesture end event (e.g. [NSView gestureDidEnd:]) 199 void QueueGestureEnd() { 200 id event = [OCMockObject mockForClass:[NSEvent class]]; 201 NSEventType type = NSEventTypeEndGesture; 202 [(NSEvent*)[[event stub] andReturnValue:OCMOCK_VALUE(type)] type]; 203 QueueEvent(event, DEPLOYMENT_GESTURE_END, NO); 204 } 205 206 // Queues a touch event with absolute coordinates |x| and |y|. 207 void QueueTouch(CGFloat x, 208 CGFloat y, 209 Deployment deployment, 210 NSEventType type, 211 short subtype, 212 BOOL run_message_loop) { 213 id event = [OCMockObject mockForClass:[NSEvent class]]; 214 [(NSEvent*)[[event stub] andReturnValue:OCMOCK_VALUE(type)] type]; 215 [(NSEvent*)[[event stub] andReturnValue:OCMOCK_VALUE(subtype)] subtype]; 216 217 id mock_touch = [OCMockObject mockForClass:[NSTouch class]]; 218 [[[mock_touch stub] andReturnNSPoint:NSMakePoint(x, y)] normalizedPosition]; 219 NSArray* touches = @[ mock_touch ]; 220 [[[event stub] andReturn:touches] touchesMatchingPhase:NSTouchPhaseAny 221 inView:[OCMArg any]]; 222 [[[event stub] andReturnBool:NO] isDirectionInvertedFromDevice]; 223 QueueEvent(event, deployment, run_message_loop); 224 } 225 226 // Convenience methods for event queuing ------------------------------------- 227 228 // Trackpad scroll events are roughly related to touch events. Given a 229 // trackpad scroll delta, approximate the change to the touch event. 230 void UpdateTouchLocationFromTrackpadScroll(int dx, int dy) { 231 touch_.x -= dx * 0.001; 232 touch_.y -= dy * 0.001; 233 } 234 235 // Queue the typical events at the beginning of a new swipe gesture. The 236 // ordering and values were determined by recording real swipe events. 237 void QueueBeginningEvents(int dx, int dy) { 238 QueueTouch( 239 DEPLOYMENT_TOUCHES_BEGAN, NSEventTypeGesture, NSMouseEventSubtype, NO); 240 QueueTrackpadScroll(0, 0, NSEventPhaseMayBegin, YES); 241 QueueTouch( 242 DEPLOYMENT_TOUCHES_MOVED, NSEventTypeGesture, NSMouseEventSubtype, NO); 243 244 QueueTrackpadScroll(dx, dy, NSEventPhaseBegan, NO); 245 QueueGestureBegin(); 246 QueueTouch(DEPLOYMENT_TOUCHES_MOVED, 247 NSEventTypeBeginGesture, 248 NSTouchEventSubtype, 249 NO); 250 QueueTouch( 251 DEPLOYMENT_TOUCHES_MOVED, NSEventTypeGesture, NSTouchEventSubtype, YES); 252 UpdateTouchLocationFromTrackpadScroll(dx, dy); 253 QueueTouch( 254 DEPLOYMENT_TOUCHES_MOVED, NSEventTypeGesture, NSTouchEventSubtype, NO); 255 } 256 257 // Queue the typical events at the end of a new swipe gesture. The ordering 258 // and values were determined by recording real swipe events. 259 void QueueEndEvents() { 260 QueueTouch(DEPLOYMENT_TOUCHES_MOVED, 261 NSEventTypeEndGesture, 262 NSMouseEventSubtype, 263 NO); 264 QueueTouch(DEPLOYMENT_TOUCHES_ENDED, 265 NSEventTypeEndGesture, 266 NSMouseEventSubtype, 267 NO); 268 QueueGestureEnd(); 269 QueueTrackpadScroll(0, 0, NSEventPhaseEnded, YES); 270 } 271 272 // Queues a trackpad scroll movement and a touch movement event. 273 void QueueScrollAndTouchMoved(int dx, int dy) { 274 QueueTrackpadScroll(dx, dy, NSEventPhaseChanged, NO); 275 UpdateTouchLocationFromTrackpadScroll(dx, dy); 276 QueueTouch( 277 DEPLOYMENT_TOUCHES_MOVED, NSEventTypeGesture, NSTouchEventSubtype, YES); 278 } 279 280 // Queues a touch event with the stored touch coordinates. 281 void QueueTouch(Deployment deployment, 282 NSEventType type, 283 short subtype, 284 BOOL run_message_loop) { 285 QueueTouch(touch_.x, touch_.y, deployment, type, subtype, run_message_loop); 286 } 287 288 // Replays the events from the queue. 289 void RunQueuedEvents() { 290 while ([event_queue_ count] > 0) { 291 QueuedEvent* queued_event = [event_queue_ objectAtIndex:0]; 292 NSEvent* event = queued_event.event; 293 NSView* view = 294 GetWebContents()->GetRenderViewHost()->GetView()->GetNativeView(); 295 BOOL run_loop = queued_event.runMessageLoop; 296 switch (queued_event.deployment) { 297 case DEPLOYMENT_GESTURE_BEGIN: 298 [view beginGestureWithEvent:event]; 299 break; 300 case DEPLOYMENT_GESTURE_END: 301 [view endGestureWithEvent:event]; 302 break; 303 case DEPLOYMENT_SCROLL_WHEEL: 304 [view scrollWheel:event]; 305 break; 306 case DEPLOYMENT_TOUCHES_BEGAN: 307 [view touchesBeganWithEvent:event]; 308 break; 309 case DEPLOYMENT_TOUCHES_ENDED: 310 [view touchesEndedWithEvent:event]; 311 break; 312 case DEPLOYMENT_TOUCHES_MOVED: 313 [view touchesMovedWithEvent:event]; 314 break; 315 } 316 317 [event_queue_ removeObjectAtIndex:0]; 318 319 if (!run_loop) 320 continue; 321 // Give time for the IPC to make it to the renderer process. If the IPC 322 // doesn't have time to make it to the renderer process, that's okay, 323 // since that simulates realistic conditions. 324 [[NSRunLoop currentRunLoop] 325 runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.001]]; 326 // The renderer process returns an IPC, which needs to be handled. 327 base::MessageLoop::current()->RunUntilIdle(); 328 } 329 } 330 331 void ExpectUrlAndOffset(const GURL& url, int offset) { 332 content::WaitForLoadStop(GetWebContents()); 333 EXPECT_EQ(url, GetWebContents()->GetURL()); 334 335 const int scroll_offset = GetScrollTop(); 336 EXPECT_EQ(offset, scroll_offset); 337 } 338 339 GURL url1_; 340 GURL url2_; 341 base::scoped_nsobject<NSMutableArray> event_queue_; 342 // The current location of the user's fingers on the track pad. 343 CGPoint touch_; 344 345 private: 346 DISALLOW_COPY_AND_ASSIGN(ChromeRenderWidgetHostViewMacHistorySwiperTest); 347}; 348 349// The ordering, timing, and parameters of the events was determined by 350// recording a real swipe. 351IN_PROC_BROWSER_TEST_F(ChromeRenderWidgetHostViewMacHistorySwiperTest, 352 TestBackwardsHistoryNavigationRealData) { 353 if (!IsHistorySwipingSupported()) 354 return; 355 356 QueueTouch(0.510681, 357 0.444672, 358 DEPLOYMENT_TOUCHES_BEGAN, 359 NSEventTypeGesture, 360 NSMouseEventSubtype, 361 NO); 362 QueueTrackpadScroll(0, 0, NSEventPhaseMayBegin, YES); 363 QueueTouch(0.510681, 364 0.444672, 365 DEPLOYMENT_TOUCHES_MOVED, 366 NSEventTypeGesture, 367 NSMouseEventSubtype, 368 NO); 369 370 QueueTrackpadScroll(1, 0, NSEventPhaseBegan, NO); 371 QueueGestureBegin(); 372 QueueTouch(0.510681, 373 0.444672, 374 DEPLOYMENT_TOUCHES_MOVED, 375 NSEventTypeBeginGesture, 376 NSTouchEventSubtype, 377 NO); 378 QueueTouch(0.510681, 379 0.444672, 380 DEPLOYMENT_TOUCHES_MOVED, 381 NSEventTypeGesture, 382 NSTouchEventSubtype, 383 YES); 384 385 QueueTouch(0.507019, 386 0.444092, 387 DEPLOYMENT_TOUCHES_MOVED, 388 NSEventTypeGesture, 389 NSTouchEventSubtype, 390 NO); 391 QueueTrackpadScroll(3, 0, NSEventPhaseChanged, YES); 392 393 QueueTrackpadScroll(3, -1, NSEventPhaseChanged, NO); 394 QueueTouch(0.502861, 395 0.443512, 396 DEPLOYMENT_TOUCHES_MOVED, 397 NSEventTypeGesture, 398 NSTouchEventSubtype, 399 YES); 400 401 QueueTrackpadScroll(6, -1, NSEventPhaseChanged, NO); 402 QueueTouch(0.497002, 403 0.44294, 404 DEPLOYMENT_TOUCHES_MOVED, 405 NSEventTypeGesture, 406 NSTouchEventSubtype, 407 YES); 408 409 QueueTrackpadScroll(5, -1, NSEventPhaseChanged, NO); 410 QueueTouch(0.487236, 411 0.44149, 412 DEPLOYMENT_TOUCHES_MOVED, 413 NSEventTypeGesture, 414 NSTouchEventSubtype, 415 YES); 416 417 QueueTrackpadScroll(8, -1, NSEventPhaseChanged, NO); 418 QueueTouch(0.480392, 419 0.440628, 420 DEPLOYMENT_TOUCHES_MOVED, 421 NSEventTypeGesture, 422 NSTouchEventSubtype, 423 NO); 424 QueueTouch(0.475266, 425 0.440338, 426 DEPLOYMENT_TOUCHES_MOVED, 427 NSEventTypeGesture, 428 NSTouchEventSubtype, 429 YES); 430 431 QueueTrackpadScroll(6, -1, NSEventPhaseChanged, NO); 432 QueueTrackpadScroll(10, -1, NSEventPhaseChanged, NO); 433 QueueTouch(0.467934, 434 0.439758, 435 DEPLOYMENT_TOUCHES_MOVED, 436 NSEventTypeGesture, 437 NSTouchEventSubtype, 438 YES); 439 440 QueueTrackpadScroll(6, -1, NSEventPhaseChanged, NO); 441 QueueTouch(0.462807, 442 0.439186, 443 DEPLOYMENT_TOUCHES_MOVED, 444 NSEventTypeGesture, 445 NSTouchEventSubtype, 446 YES); 447 QueueTrackpadScroll(12, -1, NSEventPhaseChanged, NO); 448 QueueTouch(0.454018, 449 0.438316, 450 DEPLOYMENT_TOUCHES_MOVED, 451 NSEventTypeGesture, 452 NSTouchEventSubtype, 453 YES); 454 455 QueueTrackpadScroll(6, -1, NSEventPhaseChanged, NO); 456 QueueTouch(0.449623, 457 0.438026, 458 DEPLOYMENT_TOUCHES_MOVED, 459 NSEventTypeGesture, 460 NSTouchEventSubtype, 461 YES); 462 463 QueueTrackpadScroll(9, 0, NSEventPhaseChanged, NO); 464 QueueTouch(0.443275, 465 0.437744, 466 DEPLOYMENT_TOUCHES_MOVED, 467 NSEventTypeGesture, 468 NSTouchEventSubtype, 469 YES); 470 QueueTouch(0.437164, 471 0.437164, 472 DEPLOYMENT_TOUCHES_MOVED, 473 NSEventTypeGesture, 474 NSTouchEventSubtype, 475 YES); 476 477 QueueTrackpadScroll(9, -1, NSEventPhaseChanged, NO); 478 QueueTouch(0.431305, 479 0.436874, 480 DEPLOYMENT_TOUCHES_MOVED, 481 NSEventTypeGesture, 482 NSTouchEventSubtype, 483 YES); 484 QueueTrackpadScroll(8, -1, NSEventPhaseChanged, NO); 485 QueueTouch(0.425926, 486 0.436295, 487 DEPLOYMENT_TOUCHES_MOVED, 488 NSEventTypeGesture, 489 NSTouchEventSubtype, 490 YES); 491 QueueTrackpadScroll(7, -1, NSEventPhaseChanged, NO); 492 QueueTouch(0.420311, 493 0.43573, 494 DEPLOYMENT_TOUCHES_MOVED, 495 NSEventTypeGesture, 496 NSTouchEventSubtype, 497 YES); 498 499 QueueTrackpadScroll(7, -1, NSEventPhaseChanged, NO); 500 QueueTouch(0.415184, 501 0.43544, 502 DEPLOYMENT_TOUCHES_MOVED, 503 NSEventTypeGesture, 504 NSTouchEventSubtype, 505 YES); 506 QueueTrackpadScroll(6, -1, NSEventPhaseChanged, NO); 507 QueueTouch(0.410057, 508 0.43457, 509 DEPLOYMENT_TOUCHES_MOVED, 510 NSEventTypeGesture, 511 NSTouchEventSubtype, 512 YES); 513 QueueTouch(0.40493, 514 0.43399, 515 DEPLOYMENT_TOUCHES_MOVED, 516 NSEventTypeGesture, 517 NSTouchEventSubtype, 518 YES); 519 QueueTrackpadScroll(7, -1, NSEventPhaseChanged, YES); 520 QueueTrackpadScroll(3, -1, NSEventPhaseChanged, NO); 521 QueueTouch(0.402489, 522 0.433701, 523 DEPLOYMENT_TOUCHES_MOVED, 524 NSEventTypeGesture, 525 NSTouchEventSubtype, 526 YES); 527 QueueTrackpadScroll(5, 0, NSEventPhaseChanged, NO); 528 QueueTouch(0.398094, 529 0.433418, 530 DEPLOYMENT_TOUCHES_MOVED, 531 NSEventTypeGesture, 532 NSTouchEventSubtype, 533 YES); 534 535 QueueTrackpadScroll(4, -1, NSEventPhaseChanged, NO); 536 QueueTouch(0.394669, 537 0.433128, 538 DEPLOYMENT_TOUCHES_MOVED, 539 NSEventTypeGesture, 540 NSTouchEventSubtype, 541 YES); 542 QueueTouch(0.391006, 543 0.432549, 544 DEPLOYMENT_TOUCHES_MOVED, 545 NSEventTypeGesture, 546 NSTouchEventSubtype, 547 YES); 548 QueueTrackpadScroll(4, -1, NSEventPhaseChanged, NO); 549 QueueTrackpadScroll(5, 0, NSEventPhaseChanged, YES); 550 QueueTouch(0.386848, 551 0.432259, 552 DEPLOYMENT_TOUCHES_MOVED, 553 NSEventTypeGesture, 554 NSTouchEventSubtype, 555 YES); 556 QueueTouch(0.38343, 557 0.432259, 558 DEPLOYMENT_TOUCHES_MOVED, 559 NSEventTypeGesture, 560 NSTouchEventSubtype, 561 YES); 562 563 // Skipped a bunch of events. The data on the gesture end events are fudged. 564 565 QueueTouch(0.38343, 566 0.432259, 567 DEPLOYMENT_TOUCHES_MOVED, 568 NSEventTypeEndGesture, 569 NSMouseEventSubtype, 570 NO); 571 QueueTouch(0.38343, 572 0.432259, 573 DEPLOYMENT_TOUCHES_ENDED, 574 NSEventTypeEndGesture, 575 NSMouseEventSubtype, 576 NO); 577 QueueGestureEnd(); 578 QueueTrackpadScroll(0, 0, NSEventPhaseEnded, YES); 579 580 RunQueuedEvents(); 581 ExpectUrlAndOffset(url1_, 0); 582} 583 584// Each movement event that has non-zero parameters has both horizontal and 585// vertical motion. This should not trigger history navigation. 586IN_PROC_BROWSER_TEST_F(ChromeRenderWidgetHostViewMacHistorySwiperTest, 587 TestAllDiagonalSwipes) { 588 if (!IsHistorySwipingSupported()) 589 return; 590 591 QueueBeginningEvents(1, -1); 592 for (int i = 0; i < 150; ++i) 593 QueueScrollAndTouchMoved(1, -1); 594 595 QueueEndEvents(); 596 RunQueuedEvents(); 597 ExpectUrlAndOffset(url2_, 150); 598} 599 600// The movements are equal part diagonal, horizontal, and vertical. This should 601// not trigger history navigation. 602IN_PROC_BROWSER_TEST_F(ChromeRenderWidgetHostViewMacHistorySwiperTest, 603 TestStaggeredDiagonalSwipe) { 604 if (!IsHistorySwipingSupported()) 605 return; 606 607 QueueBeginningEvents(1, 0); 608 for (int i = 0; i < 150; ++i) { 609 switch (i % 3) { 610 case 0: 611 QueueScrollAndTouchMoved(1, -1); 612 break; 613 case 1: 614 QueueScrollAndTouchMoved(0, -1); 615 break; 616 case 2: 617 QueueScrollAndTouchMoved(1, 0); 618 break; 619 default: 620 NOTREACHED(); 621 } 622 } 623 624 QueueEndEvents(); 625 RunQueuedEvents(); 626 627 content::WaitForLoadStop(GetWebContents()); 628 EXPECT_EQ(url2_, GetWebContents()->GetURL()); 629 630 // Depending on the timing of the IPCs, some of the initial events might be 631 // recognized as part of the history swipe, and not forwarded to the renderer, 632 // resulting in a non-deterministic scroll offset. This is bad, as some 633 // vertical motion is lost. Once the history swiper logic is fixed, this 634 // should become a direct comparison between 'scroll_offset' and 100. 635 // crbug.com/375514 636 const int scroll_offset = GetScrollTop(); 637 // TODO(erikchen): Depending on the timing of the IPCs between Chrome and the 638 // renderer, more than 15% of the vertical motion can be lost. This assertion 639 // should eventually become an equality comparison against 100. 640 // crbug.com/378158 641 EXPECT_GT(scroll_offset, 1); 642} 643 644// The movement events are mostly in the horizontal direction, which should 645// trigger a history swipe. This should trigger history navigation. 646IN_PROC_BROWSER_TEST_F(ChromeRenderWidgetHostViewMacHistorySwiperTest, 647 TestMostlyHorizontal) { 648 if (!IsHistorySwipingSupported()) 649 return; 650 651 QueueBeginningEvents(1, -1); 652 for (int i = 0; i < 150; ++i) { 653 if (i % 10 == 0) { 654 QueueScrollAndTouchMoved(0, -1); 655 } else if (i % 5 == 0) { 656 QueueScrollAndTouchMoved(1, -1); 657 } else { 658 QueueScrollAndTouchMoved(1, 0); 659 } 660 } 661 662 QueueEndEvents(); 663 RunQueuedEvents(); 664 ExpectUrlAndOffset(url1_, 0); 665} 666 667// Each movement event is horizontal, except the first two. This should trigger 668// history navigation. This test is DISABLED because it has never worked. Once 669// the flaw in the history swiper logic has been corrected, this test should be 670// enabled. 671// crbug.com/375512 672IN_PROC_BROWSER_TEST_F(ChromeRenderWidgetHostViewMacHistorySwiperTest, 673 DISABLED_TestAllHorizontalButFirst) { 674 if (!IsHistorySwipingSupported()) 675 return; 676 677 QueueBeginningEvents(0, -1); 678 QueueScrollAndTouchMoved(0, -1); 679 for (int i = 0; i < 149; ++i) 680 QueueScrollAndTouchMoved(1, 0); 681 682 QueueEndEvents(); 683 RunQueuedEvents(); 684 ExpectUrlAndOffset(url1_, 0); 685} 686