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