Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(766)

Side by Side Diff: content/renderer/input/input_handler_proxy.cc

Issue 473053002: Properly resume scrolling if a fling ends during a suppressed scroll (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Cleanup Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/renderer/input/input_handler_proxy.h" 5 #include "content/renderer/input/input_handler_proxy.h"
6 6
7 #include "base/auto_reset.h" 7 #include "base/auto_reset.h"
8 #include "base/command_line.h" 8 #include "base/command_line.h"
9 #include "base/debug/trace_event.h" 9 #include "base/debug/trace_event.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
(...skipping 318 matching lines...) Expand 10 before | Expand all | Expand 10 after
329 *static_cast<const WebGestureEvent*>(&event); 329 *static_cast<const WebGestureEvent*>(&event);
330 input_handler_->PinchGestureUpdate( 330 input_handler_->PinchGestureUpdate(
331 gesture_event.data.pinchUpdate.scale, 331 gesture_event.data.pinchUpdate.scale,
332 gfx::Point(gesture_event.x, gesture_event.y)); 332 gfx::Point(gesture_event.x, gesture_event.y));
333 return DID_HANDLE; 333 return DID_HANDLE;
334 } else if (event.type == WebInputEvent::GestureFlingStart) { 334 } else if (event.type == WebInputEvent::GestureFlingStart) {
335 const WebGestureEvent& gesture_event = 335 const WebGestureEvent& gesture_event =
336 *static_cast<const WebGestureEvent*>(&event); 336 *static_cast<const WebGestureEvent*>(&event);
337 return HandleGestureFling(gesture_event); 337 return HandleGestureFling(gesture_event);
338 } else if (event.type == WebInputEvent::GestureFlingCancel) { 338 } else if (event.type == WebInputEvent::GestureFlingCancel) {
339 if (CancelCurrentFling(true)) 339 if (CancelCurrentFling())
340 return DID_HANDLE; 340 return DID_HANDLE;
341 else if (!fling_may_be_active_on_main_thread_) 341 else if (!fling_may_be_active_on_main_thread_)
342 return DROP_EVENT; 342 return DROP_EVENT;
343 } else if (event.type == WebInputEvent::TouchStart) { 343 } else if (event.type == WebInputEvent::TouchStart) {
344 const WebTouchEvent& touch_event = 344 const WebTouchEvent& touch_event =
345 *static_cast<const WebTouchEvent*>(&event); 345 *static_cast<const WebTouchEvent*>(&event);
346 for (size_t i = 0; i < touch_event.touchesLength; ++i) { 346 for (size_t i = 0; i < touch_event.touchesLength; ++i) {
347 if (touch_event.touches[i].state != WebTouchPoint::StatePressed) 347 if (touch_event.touches[i].state != WebTouchPoint::StatePressed)
348 continue; 348 continue;
349 if (input_handler_->HaveTouchEventHandlersAt( 349 if (input_handler_->HaveTouchEventHandlersAt(
350 gfx::Point(touch_event.touches[i].position.x, 350 gfx::Point(touch_event.touches[i].position.x,
351 touch_event.touches[i].position.y))) { 351 touch_event.touches[i].position.y))) {
352 return DID_NOT_HANDLE; 352 return DID_NOT_HANDLE;
353 } 353 }
354 } 354 }
355 return DROP_EVENT; 355 return DROP_EVENT;
356 } else if (WebInputEvent::isKeyboardEventType(event.type)) { 356 } else if (WebInputEvent::isKeyboardEventType(event.type)) {
357 // Only call |CancelCurrentFling()| if a fling was active, as it will 357 // Only call |CancelCurrentFling()| if a fling was active, as it will
358 // otherwise disrupt an in-progress touch scroll. 358 // otherwise disrupt an in-progress touch scroll.
359 if (fling_curve_) 359 if (fling_curve_)
360 CancelCurrentFling(true); 360 CancelCurrentFling();
361 } else if (event.type == WebInputEvent::MouseMove) { 361 } else if (event.type == WebInputEvent::MouseMove) {
362 const WebMouseEvent& mouse_event = 362 const WebMouseEvent& mouse_event =
363 *static_cast<const WebMouseEvent*>(&event); 363 *static_cast<const WebMouseEvent*>(&event);
364 // TODO(tony): Ignore when mouse buttons are down? 364 // TODO(tony): Ignore when mouse buttons are down?
365 // TODO(davemoore): This should never happen, but bug #326635 showed some 365 // TODO(davemoore): This should never happen, but bug #326635 showed some
366 // surprising crashes. 366 // surprising crashes.
367 CHECK(input_handler_); 367 CHECK(input_handler_);
368 input_handler_->MouseMoveAt(gfx::Point(mouse_event.x, mouse_event.y)); 368 input_handler_->MouseMoveAt(gfx::Point(mouse_event.x, mouse_event.y));
369 } 369 }
370 370
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
478 return true; 478 return true;
479 } 479 }
480 480
481 // A fling is either inactive or is "free spinning", i.e., has yet to be 481 // A fling is either inactive or is "free spinning", i.e., has yet to be
482 // interrupted by a touch gesture, in which case there is nothing to filter. 482 // interrupted by a touch gesture, in which case there is nothing to filter.
483 if (!deferred_fling_cancel_time_seconds_) 483 if (!deferred_fling_cancel_time_seconds_)
484 return false; 484 return false;
485 485
486 // Gestures from a different source should immediately interrupt the fling. 486 // Gestures from a different source should immediately interrupt the fling.
487 if (gesture_event.sourceDevice != fling_parameters_.sourceDevice) { 487 if (gesture_event.sourceDevice != fling_parameters_.sourceDevice) {
488 FlingBoostCancelAndResumeScrollingIfNecessary(); 488 CancelCurrentFling();
489 return false; 489 return false;
490 } 490 }
491 491
492 switch (gesture_event.type) { 492 switch (gesture_event.type) {
493 case WebInputEvent::GestureTapCancel: 493 case WebInputEvent::GestureTapCancel:
494 case WebInputEvent::GestureTapDown: 494 case WebInputEvent::GestureTapDown:
495 return false; 495 return false;
496 496
497 case WebInputEvent::GestureScrollBegin: 497 case WebInputEvent::GestureScrollBegin:
498 if (!input_handler_->IsCurrentlyScrollingLayerAt( 498 if (!input_handler_->IsCurrentlyScrollingLayerAt(
499 gfx::Point(gesture_event.x, gesture_event.y), 499 gfx::Point(gesture_event.x, gesture_event.y),
500 fling_parameters_.sourceDevice == blink::WebGestureDeviceTouchpad 500 fling_parameters_.sourceDevice == blink::WebGestureDeviceTouchpad
501 ? cc::InputHandler::NonBubblingGesture 501 ? cc::InputHandler::NonBubblingGesture
502 : cc::InputHandler::Gesture)) { 502 : cc::InputHandler::Gesture)) {
503 CancelCurrentFling(true); 503 CancelCurrentFling();
504 return false; 504 return false;
505 } 505 }
506 506
507 // TODO(jdduke): Use |gesture_event.data.scrollBegin.delta{X,Y}Hint| to 507 // TODO(jdduke): Use |gesture_event.data.scrollBegin.delta{X,Y}Hint| to
508 // determine if the ScrollBegin should immediately cancel the fling. 508 // determine if the ScrollBegin should immediately cancel the fling.
509 FlingBoostExtend(gesture_event); 509 ExtendBoostedFlingTimeout(gesture_event);
510 return true; 510 return true;
511 511
512 case WebInputEvent::GestureScrollUpdate: { 512 case WebInputEvent::GestureScrollUpdate: {
513 const double time_since_last_boost_event = 513 const double time_since_last_boost_event =
514 event.timeStampSeconds - last_fling_boost_event_.timeStampSeconds; 514 event.timeStampSeconds - last_fling_boost_event_.timeStampSeconds;
515 if (ShouldSuppressScrollForFlingBoosting(current_fling_velocity_, 515 if (ShouldSuppressScrollForFlingBoosting(current_fling_velocity_,
516 gesture_event, 516 gesture_event,
517 time_since_last_boost_event)) { 517 time_since_last_boost_event)) {
518 FlingBoostExtend(gesture_event); 518 ExtendBoostedFlingTimeout(gesture_event);
519 return true; 519 return true;
520 } 520 }
521 521
522 FlingBoostCancelAndResumeScrollingIfNecessary(); 522 CancelCurrentFling();
523 return false; 523 return false;
524 } 524 }
525 525
526 case WebInputEvent::GestureScrollEnd: 526 case WebInputEvent::GestureScrollEnd:
527 CancelCurrentFling(true); 527 // Clear the last fling boost event *prior* to fling cancellation,
528 // preventing insertion of a synthetic GestureScrollBegin.
529 last_fling_boost_event_ = WebGestureEvent();
530 CancelCurrentFling();
528 return true; 531 return true;
529 532
530 case WebInputEvent::GestureFlingStart: { 533 case WebInputEvent::GestureFlingStart: {
531 DCHECK_EQ(fling_parameters_.sourceDevice, gesture_event.sourceDevice); 534 DCHECK_EQ(fling_parameters_.sourceDevice, gesture_event.sourceDevice);
532 535
533 bool fling_boosted = 536 bool fling_boosted =
534 fling_parameters_.modifiers == gesture_event.modifiers && 537 fling_parameters_.modifiers == gesture_event.modifiers &&
535 ShouldBoostFling(current_fling_velocity_, gesture_event); 538 ShouldBoostFling(current_fling_velocity_, gesture_event);
536 539
537 gfx::Vector2dF new_fling_velocity( 540 gfx::Vector2dF new_fling_velocity(
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
569 // The client expects balanced calls between a consumed GestureFlingStart 572 // The client expects balanced calls between a consumed GestureFlingStart
570 // and |DidStopFlinging()|. TODO(jdduke): Provide a count parameter to 573 // and |DidStopFlinging()|. TODO(jdduke): Provide a count parameter to
571 // |DidStopFlinging()| and only send after the accumulated fling ends. 574 // |DidStopFlinging()| and only send after the accumulated fling ends.
572 client_->DidStopFlinging(); 575 client_->DidStopFlinging();
573 return true; 576 return true;
574 } 577 }
575 578
576 default: 579 default:
577 // All other types of gestures (taps, presses, etc...) will complete the 580 // All other types of gestures (taps, presses, etc...) will complete the
578 // deferred fling cancellation. 581 // deferred fling cancellation.
579 FlingBoostCancelAndResumeScrollingIfNecessary(); 582 CancelCurrentFling();
580 return false; 583 return false;
581 } 584 }
582 } 585 }
583 586
584 void InputHandlerProxy::FlingBoostExtend(const blink::WebGestureEvent& event) { 587 void InputHandlerProxy::ExtendBoostedFlingTimeout(
585 TRACE_EVENT_INSTANT0( 588 const blink::WebGestureEvent& event) {
586 "input", "InputHandlerProxy::FlingBoostExtend", TRACE_EVENT_SCOPE_THREAD); 589 TRACE_EVENT_INSTANT0("input",
590 "InputHandlerProxy::ExtendBoostedFlingTimeout",
591 TRACE_EVENT_SCOPE_THREAD);
587 deferred_fling_cancel_time_seconds_ = 592 deferred_fling_cancel_time_seconds_ =
588 event.timeStampSeconds + kFlingBoostTimeoutDelaySeconds; 593 event.timeStampSeconds + kFlingBoostTimeoutDelaySeconds;
589 last_fling_boost_event_ = event; 594 last_fling_boost_event_ = event;
590 } 595 }
591 596
592 void InputHandlerProxy::FlingBoostCancelAndResumeScrollingIfNecessary() {
593 TRACE_EVENT_INSTANT0(
594 "input", "InputHandlerProxy::FlingBoostCancel", TRACE_EVENT_SCOPE_THREAD);
595 DCHECK(deferred_fling_cancel_time_seconds_);
596
597 // Note: |last_fling_boost_event_| is cleared by |CancelCurrentFling()|.
598 WebGestureEvent last_fling_boost_event = last_fling_boost_event_;
599
600 CancelCurrentFling(true);
601
602 if (last_fling_boost_event.type == WebInputEvent::GestureScrollBegin ||
603 last_fling_boost_event.type == WebInputEvent::GestureScrollUpdate) {
604 // Synthesize a GestureScrollBegin, as the original was suppressed.
605 HandleInputEvent(ObtainGestureScrollBegin(last_fling_boost_event));
606 }
607 }
608
609 void InputHandlerProxy::Animate(base::TimeTicks time) { 597 void InputHandlerProxy::Animate(base::TimeTicks time) {
610 if (!fling_curve_) 598 if (!fling_curve_)
611 return; 599 return;
612 600
613 double monotonic_time_sec = InSecondsF(time); 601 double monotonic_time_sec = InSecondsF(time);
614 602
615 if (deferred_fling_cancel_time_seconds_ && 603 if (deferred_fling_cancel_time_seconds_ &&
616 monotonic_time_sec > deferred_fling_cancel_time_seconds_) { 604 monotonic_time_sec > deferred_fling_cancel_time_seconds_) {
617 FlingBoostCancelAndResumeScrollingIfNecessary(); 605 CancelCurrentFling();
618 return; 606 return;
619 } 607 }
620 608
621 if (!has_fling_animation_started_) { 609 if (!has_fling_animation_started_) {
622 has_fling_animation_started_ = true; 610 has_fling_animation_started_ = true;
623 // Guard against invalid, future or sufficiently stale start times, as there 611 // Guard against invalid, future or sufficiently stale start times, as there
624 // are no guarantees fling event and animation timestamps are compatible. 612 // are no guarantees fling event and animation timestamps are compatible.
625 if (!fling_parameters_.startTime || 613 if (!fling_parameters_.startTime ||
626 monotonic_time_sec <= fling_parameters_.startTime || 614 monotonic_time_sec <= fling_parameters_.startTime ||
627 monotonic_time_sec >= fling_parameters_.startTime + 615 monotonic_time_sec >= fling_parameters_.startTime +
(...skipping 10 matching lines...) Expand all
638 626
639 if (disallow_vertical_fling_scroll_ && disallow_horizontal_fling_scroll_) 627 if (disallow_vertical_fling_scroll_ && disallow_horizontal_fling_scroll_)
640 fling_is_active = false; 628 fling_is_active = false;
641 629
642 if (fling_is_active) { 630 if (fling_is_active) {
643 input_handler_->SetNeedsAnimate(); 631 input_handler_->SetNeedsAnimate();
644 } else { 632 } else {
645 TRACE_EVENT_INSTANT0("input", 633 TRACE_EVENT_INSTANT0("input",
646 "InputHandlerProxy::animate::flingOver", 634 "InputHandlerProxy::animate::flingOver",
647 TRACE_EVENT_SCOPE_THREAD); 635 TRACE_EVENT_SCOPE_THREAD);
648 CancelCurrentFling(true); 636 CancelCurrentFling();
649 } 637 }
650 } 638 }
651 639
652 void InputHandlerProxy::MainThreadHasStoppedFlinging() { 640 void InputHandlerProxy::MainThreadHasStoppedFlinging() {
653 fling_may_be_active_on_main_thread_ = false; 641 fling_may_be_active_on_main_thread_ = false;
654 client_->DidStopFlinging(); 642 client_->DidStopFlinging();
655 } 643 }
656 644
657 void InputHandlerProxy::DidOverscroll( 645 void InputHandlerProxy::DidOverscroll(
658 const gfx::Vector2dF& accumulated_overscroll, 646 const gfx::Vector2dF& accumulated_overscroll,
(...skipping 19 matching lines...) Expand all
678 std::abs(params.accumulated_overscroll.x()) >= 666 std::abs(params.accumulated_overscroll.x()) >=
679 kFlingOverscrollThreshold; 667 kFlingOverscrollThreshold;
680 disallow_vertical_fling_scroll_ |= 668 disallow_vertical_fling_scroll_ |=
681 std::abs(params.accumulated_overscroll.y()) >= 669 std::abs(params.accumulated_overscroll.y()) >=
682 kFlingOverscrollThreshold; 670 kFlingOverscrollThreshold;
683 } 671 }
684 672
685 client_->DidOverscroll(params); 673 client_->DidOverscroll(params);
686 } 674 }
687 675
688 bool InputHandlerProxy::CancelCurrentFling( 676 bool InputHandlerProxy::CancelCurrentFling() {
689 bool send_fling_stopped_notification) { 677 if (CancelCurrentFlingWithoutNotifyingClient()) {
678 client_->DidStopFlinging();
679 return true;
680 }
681 return false;
682 }
683
684 bool InputHandlerProxy::CancelCurrentFlingWithoutNotifyingClient() {
690 bool had_fling_animation = fling_curve_; 685 bool had_fling_animation = fling_curve_;
691 if (had_fling_animation && 686 if (had_fling_animation &&
692 fling_parameters_.sourceDevice == blink::WebGestureDeviceTouchscreen) { 687 fling_parameters_.sourceDevice == blink::WebGestureDeviceTouchscreen) {
693 input_handler_->ScrollEnd(); 688 input_handler_->ScrollEnd();
694 TRACE_EVENT_ASYNC_END0( 689 TRACE_EVENT_ASYNC_END0(
695 "input", 690 "input",
696 "InputHandlerProxy::HandleGestureFling::started", 691 "InputHandlerProxy::HandleGestureFling::started",
697 this); 692 this);
698 } 693 }
699 694
700 TRACE_EVENT_INSTANT1("input", 695 TRACE_EVENT_INSTANT1("input",
701 "InputHandlerProxy::CancelCurrentFling", 696 "InputHandlerProxy::CancelCurrentFling",
702 TRACE_EVENT_SCOPE_THREAD, 697 TRACE_EVENT_SCOPE_THREAD,
703 "had_fling_animation", 698 "had_fling_animation",
704 had_fling_animation); 699 had_fling_animation);
705 fling_curve_.reset(); 700 fling_curve_.reset();
706 has_fling_animation_started_ = false; 701 has_fling_animation_started_ = false;
707 gesture_scroll_on_impl_thread_ = false; 702 gesture_scroll_on_impl_thread_ = false;
708 current_fling_velocity_ = gfx::Vector2dF(); 703 current_fling_velocity_ = gfx::Vector2dF();
709 fling_parameters_ = blink::WebActiveWheelFlingParameters(); 704 fling_parameters_ = blink::WebActiveWheelFlingParameters();
710 deferred_fling_cancel_time_seconds_ = 0; 705
711 last_fling_boost_event_ = WebGestureEvent(); 706 if (deferred_fling_cancel_time_seconds_) {
712 if (send_fling_stopped_notification && had_fling_animation) 707 deferred_fling_cancel_time_seconds_ = 0;
713 client_->DidStopFlinging(); 708
709 WebGestureEvent last_fling_boost_event = last_fling_boost_event_;
710 last_fling_boost_event_ = WebGestureEvent();
711 if (last_fling_boost_event.type == WebInputEvent::GestureScrollBegin ||
712 last_fling_boost_event.type == WebInputEvent::GestureScrollUpdate) {
713 // Synthesize a GestureScrollBegin, as the original was suppressed.
714 HandleInputEvent(ObtainGestureScrollBegin(last_fling_boost_event));
715 }
716 }
717
714 return had_fling_animation; 718 return had_fling_animation;
715 } 719 }
716 720
717 bool InputHandlerProxy::TouchpadFlingScroll( 721 bool InputHandlerProxy::TouchpadFlingScroll(
718 const WebFloatSize& increment) { 722 const WebFloatSize& increment) {
719 WebMouseWheelEvent synthetic_wheel; 723 WebMouseWheelEvent synthetic_wheel;
720 synthetic_wheel.type = WebInputEvent::MouseWheel; 724 synthetic_wheel.type = WebInputEvent::MouseWheel;
721 synthetic_wheel.deltaX = increment.width; 725 synthetic_wheel.deltaX = increment.width;
722 synthetic_wheel.deltaY = increment.height; 726 synthetic_wheel.deltaY = increment.height;
723 synthetic_wheel.hasPreciseScrollingDeltas = true; 727 synthetic_wheel.hasPreciseScrollingDeltas = true;
(...skipping 15 matching lines...) Expand all
739 "InputHandlerProxy::scrollBy::AbortFling", 743 "InputHandlerProxy::scrollBy::AbortFling",
740 TRACE_EVENT_SCOPE_THREAD); 744 TRACE_EVENT_SCOPE_THREAD);
741 // If we got a DID_NOT_HANDLE, that means we need to deliver wheels on the 745 // If we got a DID_NOT_HANDLE, that means we need to deliver wheels on the
742 // main thread. In this case we need to schedule a commit and transfer the 746 // main thread. In this case we need to schedule a commit and transfer the
743 // fling curve over to the main thread and run the rest of the wheels from 747 // fling curve over to the main thread and run the rest of the wheels from
744 // there. This can happen when flinging a page that contains a scrollable 748 // there. This can happen when flinging a page that contains a scrollable
745 // subarea that we can't scroll on the thread if the fling starts outside 749 // subarea that we can't scroll on the thread if the fling starts outside
746 // the subarea but then is flung "under" the pointer. 750 // the subarea but then is flung "under" the pointer.
747 client_->TransferActiveWheelFlingAnimation(fling_parameters_); 751 client_->TransferActiveWheelFlingAnimation(fling_parameters_);
748 fling_may_be_active_on_main_thread_ = true; 752 fling_may_be_active_on_main_thread_ = true;
749 CancelCurrentFling(false); 753 CancelCurrentFlingWithoutNotifyingClient();
750 break; 754 break;
751 } 755 }
752 756
753 return false; 757 return false;
754 } 758 }
755 759
756 bool InputHandlerProxy::scrollBy(const WebFloatSize& increment, 760 bool InputHandlerProxy::scrollBy(const WebFloatSize& increment,
757 const WebFloatSize& velocity) { 761 const WebFloatSize& velocity) {
758 WebFloatSize clipped_increment; 762 WebFloatSize clipped_increment;
759 WebFloatSize clipped_velocity; 763 WebFloatSize clipped_velocity;
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
802 // trigger a scroll, e.g., with a trivial time delta between fling updates. 806 // trigger a scroll, e.g., with a trivial time delta between fling updates.
803 // Return true in this case to prevent early fling termination. 807 // Return true in this case to prevent early fling termination.
804 if (std::abs(clipped_increment.width) < kScrollEpsilon && 808 if (std::abs(clipped_increment.width) < kScrollEpsilon &&
805 std::abs(clipped_increment.height) < kScrollEpsilon) 809 std::abs(clipped_increment.height) < kScrollEpsilon)
806 return true; 810 return true;
807 811
808 return did_scroll; 812 return did_scroll;
809 } 813 }
810 814
811 } // namespace content 815 } // namespace content
OLDNEW
« no previous file with comments | « content/renderer/input/input_handler_proxy.h ('k') | content/renderer/input/input_handler_proxy_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698