diff options
author | khushalsagar <khushalsagar@chromium.org> | 2015-11-23 14:50:36 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-11-23 22:51:42 +0000 |
commit | 3a8d056562f51c44bbbf8a1b7dd670af4d058350 (patch) | |
tree | e93a16aa0a9bc971abf92c10fe5da0e3d0b87e9e /content/renderer/input | |
parent | e7325fc3acb3de298d65726950c4e040b7ac9ab4 (diff) | |
download | chromium_src-3a8d056562f51c44bbbf8a1b7dd670af4d058350.zip chromium_src-3a8d056562f51c44bbbf8a1b7dd670af4d058350.tar.gz chromium_src-3a8d056562f51c44bbbf8a1b7dd670af4d058350.tar.bz2 |
Move content/renderer input handling for web input events to ui.
The InputHandlerProxy in content/renderer implements the logic for
sending the intercepted web input events to the compositor. Move this
logic to ui to be used by mus/blimp.
BUG=550531
Review URL: https://codereview.chromium.org/1415953004
Cr-Commit-Position: refs/heads/master@{#361207}
Diffstat (limited to 'content/renderer/input')
-rw-r--r-- | content/renderer/input/input_event_filter.cc | 4 | ||||
-rw-r--r-- | content/renderer/input/input_event_filter.h | 9 | ||||
-rw-r--r-- | content/renderer/input/input_handler_manager.cc | 8 | ||||
-rw-r--r-- | content/renderer/input/input_handler_manager_client.h | 7 | ||||
-rw-r--r-- | content/renderer/input/input_handler_proxy.cc | 1048 | ||||
-rw-r--r-- | content/renderer/input/input_handler_proxy.h | 189 | ||||
-rw-r--r-- | content/renderer/input/input_handler_proxy_client.h | 49 | ||||
-rw-r--r-- | content/renderer/input/input_handler_proxy_unittest.cc | 2478 | ||||
-rw-r--r-- | content/renderer/input/input_handler_wrapper.cc | 17 | ||||
-rw-r--r-- | content/renderer/input/input_handler_wrapper.h | 23 | ||||
-rw-r--r-- | content/renderer/input/input_scroll_elasticity_controller.cc | 410 | ||||
-rw-r--r-- | content/renderer/input/input_scroll_elasticity_controller.h | 148 | ||||
-rw-r--r-- | content/renderer/input/input_scroll_elasticity_controller_unittest.cc | 387 | ||||
-rw-r--r-- | content/renderer/input/synchronous_input_handler_proxy.h | 73 |
14 files changed, 52 insertions, 4798 deletions
diff --git a/content/renderer/input/input_event_filter.cc b/content/renderer/input/input_event_filter.cc index 6b648c7..0647685 100644 --- a/content/renderer/input/input_event_filter.cc +++ b/content/renderer/input/input_event_filter.cc @@ -17,6 +17,7 @@ #include "content/public/common/content_switches.h" #include "ipc/ipc_listener.h" #include "ipc/ipc_sender.h" +#include "ui/events/blink/synchronous_input_handler_proxy.h" #include "ui/gfx/geometry/vector2d_f.h" using blink::WebInputEvent; @@ -57,7 +58,8 @@ void InputEventFilter::SetBoundHandler(const Handler& handler) { void InputEventFilter::DidAddInputHandler( int routing_id, - SynchronousInputHandlerProxy* synchronous_input_handler_proxy) { + ui::SynchronousInputHandlerProxy* + synchronous_input_handler_proxy) { base::AutoLock locked(routes_lock_); routes_.insert(routing_id); } diff --git a/content/renderer/input/input_event_filter.h b/content/renderer/input/input_event_filter.h index 2f87d57..e2d18f3 100644 --- a/content/renderer/input/input_event_filter.h +++ b/content/renderer/input/input_event_filter.h @@ -20,8 +20,8 @@ namespace base { class SingleThreadTaskRunner; } -namespace cc { -class InputHandler; +namespace ui { +class SynchronousInputHandlerProxy; } namespace IPC { @@ -39,8 +39,6 @@ class Sender; namespace content { -class SynchronousInputHandlerProxy; - class CONTENT_EXPORT InputEventFilter : public InputHandlerManagerClient, public IPC::MessageFilter { public: @@ -62,7 +60,8 @@ class CONTENT_EXPORT InputEventFilter : public InputHandlerManagerClient, void SetBoundHandler(const Handler& handler) override; void DidAddInputHandler( int routing_id, - SynchronousInputHandlerProxy* synchronous_input_handler_proxy) override; + ui::SynchronousInputHandlerProxy* + synchronous_input_handler_proxy) override; void DidRemoveInputHandler(int routing_id) override; void DidOverscroll(int routing_id, const DidOverscrollParams& params) override; diff --git a/content/renderer/input/input_handler_manager.cc b/content/renderer/input/input_handler_manager.cc index cbc9a15..85f229d 100644 --- a/content/renderer/input/input_handler_manager.cc +++ b/content/renderer/input/input_handler_manager.cc @@ -11,12 +11,14 @@ #include "base/trace_event/trace_event.h" #include "cc/input/input_handler.h" #include "components/scheduler/renderer/renderer_scheduler.h" +#include "content/common/input/web_input_event_traits.h" #include "content/renderer/input/input_event_filter.h" #include "content/renderer/input/input_handler_manager_client.h" #include "content/renderer/input/input_handler_wrapper.h" -#include "content/renderer/input/input_scroll_elasticity_controller.h" +#include "ui/events/blink/input_handler_proxy.h" using blink::WebInputEvent; +using ui::InputHandlerProxy; using scheduler::RendererScheduler; namespace content { @@ -137,6 +139,8 @@ InputEventAckState InputHandlerManager::HandleInputEvent( const WebInputEvent* input_event, ui::LatencyInfo* latency_info) { DCHECK(task_runner_->BelongsToCurrentThread()); + TRACE_EVENT1("input,benchmark", "InputHandlerManager::HandleInputEvent", + "type", WebInputEventTraits::GetName(input_event->type)); auto it = input_handlers_.find(routing_id); if (it == input_handlers_.end()) { @@ -146,6 +150,8 @@ InputEventAckState InputHandlerManager::HandleInputEvent( return INPUT_EVENT_ACK_STATE_NOT_CONSUMED; } + TRACE_EVENT1("input", "InputHandlerManager::HandleInputEvent", + "result", "EventSentToInputHandlerProxy"); InputHandlerProxy* proxy = it->second->input_handler_proxy(); InputEventAckState input_event_ack_state = InputEventDispositionToAck( proxy->HandleInputEventWithLatencyInfo(*input_event, latency_info)); diff --git a/content/renderer/input/input_handler_manager_client.h b/content/renderer/input/input_handler_manager_client.h index 61cc5e6..9455af3 100644 --- a/content/renderer/input/input_handler_manager_client.h +++ b/content/renderer/input/input_handler_manager_client.h @@ -24,9 +24,12 @@ namespace blink { class WebInputEvent; } +namespace ui { +class SynchronousInputHandlerProxy; +} + namespace content { struct DidOverscrollParams; -class SynchronousInputHandlerProxy; class CONTENT_EXPORT InputHandlerManagerClient { public: @@ -46,7 +49,7 @@ class CONTENT_EXPORT InputHandlerManagerClient { // Called from the compositor thread. virtual void DidAddInputHandler( int routing_id, - SynchronousInputHandlerProxy* synchronous_handler) = 0; + ui::SynchronousInputHandlerProxy* synchronous_handler) = 0; virtual void DidRemoveInputHandler(int routing_id) = 0; virtual void DidOverscroll(int routing_id, const DidOverscrollParams& params) = 0; diff --git a/content/renderer/input/input_handler_proxy.cc b/content/renderer/input/input_handler_proxy.cc deleted file mode 100644 index 255492f..0000000 --- a/content/renderer/input/input_handler_proxy.cc +++ /dev/null @@ -1,1048 +0,0 @@ -// Copyright 2013 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 "content/renderer/input/input_handler_proxy.h" - -#include <algorithm> - -#include "base/auto_reset.h" -#include "base/command_line.h" -#include "base/location.h" -#include "base/logging.h" -#include "base/metrics/histogram.h" -#include "base/single_thread_task_runner.h" -#include "base/thread_task_runner_handle.h" -#include "base/trace_event/trace_event.h" -#include "content/common/input/did_overscroll_params.h" -#include "content/common/input/web_input_event_traits.h" -#include "content/public/common/content_switches.h" -#include "content/renderer/input/input_handler_proxy_client.h" -#include "content/renderer/input/input_scroll_elasticity_controller.h" -#include "third_party/WebKit/public/platform/Platform.h" -#include "third_party/WebKit/public/web/WebInputEvent.h" -#include "ui/events/latency_info.h" -#include "ui/gfx/geometry/point_conversions.h" - -using blink::WebFloatPoint; -using blink::WebFloatSize; -using blink::WebGestureEvent; -using blink::WebInputEvent; -using blink::WebMouseEvent; -using blink::WebMouseWheelEvent; -using blink::WebPoint; -using blink::WebTouchEvent; -using blink::WebTouchPoint; - -namespace { - -// Maximum time between a fling event's timestamp and the first |Animate| call -// for the fling curve to use the fling timestamp as the initial animation time. -// Two frames allows a minor delay between event creation and the first animate. -const double kMaxSecondsFromFlingTimestampToFirstAnimate = 2. / 60.; - -// Threshold for determining whether a fling scroll delta should have caused the -// client to scroll. -const float kScrollEpsilon = 0.1f; - -// Minimum fling velocity required for the active fling and new fling for the -// two to accumulate. -const double kMinBoostFlingSpeedSquare = 350. * 350.; - -// Minimum velocity for the active touch scroll to preserve (boost) an active -// fling for which cancellation has been deferred. -const double kMinBoostTouchScrollSpeedSquare = 150 * 150.; - -// Timeout window after which the active fling will be cancelled if no animation -// ticks, scrolls or flings of sufficient velocity relative to the current fling -// are received. The default value on Android native views is 40ms, but we use a -// slightly increased value to accomodate small IPC message delays. -const double kFlingBoostTimeoutDelaySeconds = 0.05; - -gfx::Vector2dF ToClientScrollIncrement(const WebFloatSize& increment) { - return gfx::Vector2dF(-increment.width, -increment.height); -} - -double InSecondsF(const base::TimeTicks& time) { - return (time - base::TimeTicks()).InSecondsF(); -} - -bool ShouldSuppressScrollForFlingBoosting( - const gfx::Vector2dF& current_fling_velocity, - const WebGestureEvent& scroll_update_event, - double time_since_last_boost_event, - double time_since_last_fling_animate) { - DCHECK_EQ(WebInputEvent::GestureScrollUpdate, scroll_update_event.type); - - gfx::Vector2dF dx(scroll_update_event.data.scrollUpdate.deltaX, - scroll_update_event.data.scrollUpdate.deltaY); - if (gfx::DotProduct(current_fling_velocity, dx) <= 0) - return false; - - if (time_since_last_fling_animate > kFlingBoostTimeoutDelaySeconds) - return false; - - if (time_since_last_boost_event < 0.001) - return true; - - // TODO(jdduke): Use |scroll_update_event.data.scrollUpdate.velocity{X,Y}|. - // The scroll must be of sufficient velocity to maintain the active fling. - const gfx::Vector2dF scroll_velocity = - gfx::ScaleVector2d(dx, 1. / time_since_last_boost_event); - if (scroll_velocity.LengthSquared() < kMinBoostTouchScrollSpeedSquare) - return false; - - return true; -} - -bool ShouldBoostFling(const gfx::Vector2dF& current_fling_velocity, - const WebGestureEvent& fling_start_event) { - DCHECK_EQ(WebInputEvent::GestureFlingStart, fling_start_event.type); - - gfx::Vector2dF new_fling_velocity( - fling_start_event.data.flingStart.velocityX, - fling_start_event.data.flingStart.velocityY); - - if (gfx::DotProduct(current_fling_velocity, new_fling_velocity) <= 0) - return false; - - if (current_fling_velocity.LengthSquared() < kMinBoostFlingSpeedSquare) - return false; - - if (new_fling_velocity.LengthSquared() < kMinBoostFlingSpeedSquare) - return false; - - return true; -} - -WebGestureEvent ObtainGestureScrollBegin(const WebGestureEvent& event) { - WebGestureEvent scroll_begin_event = event; - scroll_begin_event.type = WebInputEvent::GestureScrollBegin; - scroll_begin_event.data.scrollBegin.deltaXHint = 0; - scroll_begin_event.data.scrollBegin.deltaYHint = 0; - return scroll_begin_event; -} - -void ReportInputEventLatencyUma(const WebInputEvent& event, - const ui::LatencyInfo& latency_info) { - if (!(event.type == WebInputEvent::GestureScrollBegin || - event.type == WebInputEvent::GestureScrollUpdate || - event.type == WebInputEvent::GesturePinchBegin || - event.type == WebInputEvent::GesturePinchUpdate || - event.type == WebInputEvent::GestureFlingStart)) { - return; - } - - ui::LatencyInfo::LatencyMap::const_iterator it = - latency_info.latency_components().find(std::make_pair( - ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 0)); - - if (it == latency_info.latency_components().end()) - return; - - base::TimeDelta delta = base::TimeTicks::Now() - it->second.event_time; - for (size_t i = 0; i < it->second.event_count; ++i) { - switch (event.type) { - case blink::WebInputEvent::GestureScrollBegin: - UMA_HISTOGRAM_CUSTOM_COUNTS( - "Event.Latency.RendererImpl.GestureScrollBegin", - delta.InMicroseconds(), 1, 1000000, 100); - break; - case blink::WebInputEvent::GestureScrollUpdate: - UMA_HISTOGRAM_CUSTOM_COUNTS( - // So named for historical reasons. - "Event.Latency.RendererImpl.GestureScroll2", - delta.InMicroseconds(), 1, 1000000, 100); - break; - case blink::WebInputEvent::GesturePinchBegin: - UMA_HISTOGRAM_CUSTOM_COUNTS( - "Event.Latency.RendererImpl.GesturePinchBegin", - delta.InMicroseconds(), 1, 1000000, 100); - break; - case blink::WebInputEvent::GesturePinchUpdate: - UMA_HISTOGRAM_CUSTOM_COUNTS( - "Event.Latency.RendererImpl.GesturePinchUpdate", - delta.InMicroseconds(), 1, 1000000, 100); - break; - case blink::WebInputEvent::GestureFlingStart: - UMA_HISTOGRAM_CUSTOM_COUNTS( - "Event.Latency.RendererImpl.GestureFlingStart", - delta.InMicroseconds(), 1, 1000000, 100); - break; - default: - NOTREACHED(); - break; - } - } -} - -} // namespace - -namespace content { - -InputHandlerProxy::InputHandlerProxy(cc::InputHandler* input_handler, - InputHandlerProxyClient* client) - : client_(client), - input_handler_(input_handler), - deferred_fling_cancel_time_seconds_(0), - synchronous_input_handler_(nullptr), - allow_root_animate_(true), -#ifndef NDEBUG - expect_scroll_update_end_(false), -#endif - gesture_scroll_on_impl_thread_(false), - gesture_pinch_on_impl_thread_(false), - fling_may_be_active_on_main_thread_(false), - disallow_horizontal_fling_scroll_(false), - disallow_vertical_fling_scroll_(false), - has_fling_animation_started_(false), - uma_latency_reporting_enabled_(base::TimeTicks::IsHighResolution()) { - DCHECK(client); - input_handler_->BindToClient(this); - smooth_scroll_enabled_ = base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kEnableSmoothScrolling); - cc::ScrollElasticityHelper* scroll_elasticity_helper = - input_handler_->CreateScrollElasticityHelper(); - if (scroll_elasticity_helper) { - scroll_elasticity_controller_.reset( - new InputScrollElasticityController(scroll_elasticity_helper)); - } -} - -InputHandlerProxy::~InputHandlerProxy() {} - -void InputHandlerProxy::WillShutdown() { - scroll_elasticity_controller_.reset(); - input_handler_ = NULL; - client_->WillShutdown(); -} - -InputHandlerProxy::EventDisposition -InputHandlerProxy::HandleInputEventWithLatencyInfo( - const WebInputEvent& event, - ui::LatencyInfo* latency_info) { - DCHECK(input_handler_); - - if (uma_latency_reporting_enabled_) - ReportInputEventLatencyUma(event, *latency_info); - - TRACE_EVENT_WITH_FLOW1("input,benchmark", - "LatencyInfo.Flow", - TRACE_ID_DONT_MANGLE(latency_info->trace_id()), - TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, - "step", "HandleInputEventImpl"); - - scoped_ptr<cc::SwapPromiseMonitor> latency_info_swap_promise_monitor = - input_handler_->CreateLatencyInfoSwapPromiseMonitor(latency_info); - InputHandlerProxy::EventDisposition disposition = HandleInputEvent(event); - return disposition; -} - -InputHandlerProxy::EventDisposition InputHandlerProxy::HandleInputEvent( - const WebInputEvent& event) { - DCHECK(input_handler_); - TRACE_EVENT1("input,benchmark", "InputHandlerProxy::HandleInputEvent", - "type", WebInputEventTraits::GetName(event.type)); - - if (FilterInputEventForFlingBoosting(event)) - return DID_HANDLE; - - switch (event.type) { - case WebInputEvent::MouseWheel: - return HandleMouseWheel(static_cast<const WebMouseWheelEvent&>(event)); - - case WebInputEvent::GestureScrollBegin: - return HandleGestureScrollBegin( - static_cast<const WebGestureEvent&>(event)); - - case WebInputEvent::GestureScrollUpdate: - return HandleGestureScrollUpdate( - static_cast<const WebGestureEvent&>(event)); - - case WebInputEvent::GestureScrollEnd: - return HandleGestureScrollEnd(static_cast<const WebGestureEvent&>(event)); - - case WebInputEvent::GesturePinchBegin: { - DCHECK(!gesture_pinch_on_impl_thread_); - const WebGestureEvent& gesture_event = - static_cast<const WebGestureEvent&>(event); - if (gesture_event.sourceDevice == blink::WebGestureDeviceTouchpad && - input_handler_->HaveWheelEventHandlersAt( - gfx::Point(gesture_event.x, gesture_event.y))) { - return DID_NOT_HANDLE; - } else { - input_handler_->PinchGestureBegin(); - gesture_pinch_on_impl_thread_ = true; - return DID_HANDLE; - } - } - - case WebInputEvent::GesturePinchEnd: - if (gesture_pinch_on_impl_thread_) { - gesture_pinch_on_impl_thread_ = false; - input_handler_->PinchGestureEnd(); - return DID_HANDLE; - } else { - return DID_NOT_HANDLE; - } - - case WebInputEvent::GesturePinchUpdate: { - if (gesture_pinch_on_impl_thread_) { - const WebGestureEvent& gesture_event = - static_cast<const WebGestureEvent&>(event); - if (gesture_event.data.pinchUpdate.zoomDisabled) - return DROP_EVENT; - input_handler_->PinchGestureUpdate( - gesture_event.data.pinchUpdate.scale, - gfx::Point(gesture_event.x, gesture_event.y)); - return DID_HANDLE; - } else { - return DID_NOT_HANDLE; - } - } - - case WebInputEvent::GestureFlingStart: - return HandleGestureFlingStart( - *static_cast<const WebGestureEvent*>(&event)); - - case WebInputEvent::GestureFlingCancel: - if (CancelCurrentFling()) - return DID_HANDLE; - else if (!fling_may_be_active_on_main_thread_) - return DROP_EVENT; - return DID_NOT_HANDLE; - - case WebInputEvent::TouchStart: - return HandleTouchStart(static_cast<const WebTouchEvent&>(event)); - - case WebInputEvent::MouseMove: { - const WebMouseEvent& mouse_event = - static_cast<const WebMouseEvent&>(event); - // TODO(tony): Ignore when mouse buttons are down? - // TODO(davemoore): This should never happen, but bug #326635 showed some - // surprising crashes. - CHECK(input_handler_); - input_handler_->MouseMoveAt(gfx::Point(mouse_event.x, mouse_event.y)); - return DID_NOT_HANDLE; - } - - default: - if (WebInputEvent::isKeyboardEventType(event.type)) { - // Only call |CancelCurrentFling()| if a fling was active, as it will - // otherwise disrupt an in-progress touch scroll. - if (fling_curve_) - CancelCurrentFling(); - } - break; - } - - return DID_NOT_HANDLE; -} - -InputHandlerProxy::EventDisposition InputHandlerProxy::HandleMouseWheel( - const WebMouseWheelEvent& wheel_event) { - InputHandlerProxy::EventDisposition result = DID_NOT_HANDLE; - cc::InputHandlerScrollResult scroll_result; - - // TODO(ccameron): The rail information should be pushed down into - // InputHandler. - gfx::Vector2dF scroll_delta( - wheel_event.railsMode != WebInputEvent::RailsModeVertical - ? -wheel_event.deltaX - : 0, - wheel_event.railsMode != WebInputEvent::RailsModeHorizontal - ? -wheel_event.deltaY - : 0); - - if (wheel_event.scrollByPage) { - // TODO(jamesr): We don't properly handle scroll by page in the compositor - // thread, so punt it to the main thread. http://crbug.com/236639 - result = DID_NOT_HANDLE; - } else if (!wheel_event.canScroll) { - // Wheel events with |canScroll| == false will not trigger scrolling, - // only event handlers. Forward to the main thread. - result = DID_NOT_HANDLE; - } else if (smooth_scroll_enabled_ && !wheel_event.hasPreciseScrollingDeltas) { - cc::InputHandler::ScrollStatus scroll_status = - input_handler_->ScrollAnimated(gfx::Point(wheel_event.x, wheel_event.y), - scroll_delta); - switch (scroll_status) { - case cc::InputHandler::SCROLL_STARTED: - result = DID_HANDLE; - break; - case cc::InputHandler::SCROLL_IGNORED: - result = DROP_EVENT; - break; - default: - result = DID_NOT_HANDLE; - break; - } - } else { - cc::InputHandler::ScrollStatus scroll_status = input_handler_->ScrollBegin( - gfx::Point(wheel_event.x, wheel_event.y), cc::InputHandler::WHEEL); - switch (scroll_status) { - case cc::InputHandler::SCROLL_STARTED: { - TRACE_EVENT_INSTANT2("input", - "InputHandlerProxy::handle_input wheel scroll", - TRACE_EVENT_SCOPE_THREAD, "deltaX", - scroll_delta.x(), "deltaY", scroll_delta.y()); - gfx::Point scroll_point(wheel_event.x, wheel_event.y); - scroll_result = input_handler_->ScrollBy(scroll_point, scroll_delta); - HandleOverscroll(scroll_point, scroll_result); - input_handler_->ScrollEnd(); - result = scroll_result.did_scroll ? DID_HANDLE : DROP_EVENT; - break; - } - case cc::InputHandler::SCROLL_IGNORED: - // TODO(jamesr): This should be DROP_EVENT, but in cases where we fail - // to properly sync scrollability it's safer to send the event to the - // main thread. Change back to DROP_EVENT once we have synchronization - // bugs sorted out. - result = DID_NOT_HANDLE; - break; - case cc::InputHandler::SCROLL_UNKNOWN: - case cc::InputHandler::SCROLL_ON_MAIN_THREAD: - result = DID_NOT_HANDLE; - break; - case cc::InputHandler::ScrollStatusCount: - NOTREACHED(); - break; - } - } - - // Send the event and its disposition to the elasticity controller to update - // the over-scroll animation. If the event is to be handled on the main - // thread, the event and its disposition will be sent to the elasticity - // controller after being handled on the main thread. - if (scroll_elasticity_controller_ && result != DID_NOT_HANDLE) { - // Note that the call to the elasticity controller is made asynchronously, - // to minimize divergence between main thread and impl thread event - // handling paths. - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::Bind(&InputScrollElasticityController::ObserveWheelEventAndResult, - scroll_elasticity_controller_->GetWeakPtr(), wheel_event, - scroll_result)); - } - return result; -} - -InputHandlerProxy::EventDisposition InputHandlerProxy::HandleGestureScrollBegin( - const WebGestureEvent& gesture_event) { - if (gesture_scroll_on_impl_thread_) - CancelCurrentFling(); - -#ifndef NDEBUG - DCHECK(!expect_scroll_update_end_); - expect_scroll_update_end_ = true; -#endif - cc::InputHandler::ScrollStatus scroll_status; - if (gesture_event.data.scrollBegin.targetViewport) { - scroll_status = input_handler_->RootScrollBegin(cc::InputHandler::GESTURE); - } else { - scroll_status = input_handler_->ScrollBegin( - gfx::Point(gesture_event.x, gesture_event.y), - cc::InputHandler::GESTURE); - } - UMA_HISTOGRAM_ENUMERATION("Renderer4.CompositorScrollHitTestResult", - scroll_status, - cc::InputHandler::ScrollStatusCount); - switch (scroll_status) { - case cc::InputHandler::SCROLL_STARTED: - TRACE_EVENT_INSTANT0("input", - "InputHandlerProxy::handle_input gesture scroll", - TRACE_EVENT_SCOPE_THREAD); - gesture_scroll_on_impl_thread_ = true; - return DID_HANDLE; - case cc::InputHandler::SCROLL_UNKNOWN: - case cc::InputHandler::SCROLL_ON_MAIN_THREAD: - return DID_NOT_HANDLE; - case cc::InputHandler::SCROLL_IGNORED: - return DROP_EVENT; - case cc::InputHandler::ScrollStatusCount: - NOTREACHED(); - break; - } - return DID_NOT_HANDLE; -} - -InputHandlerProxy::EventDisposition -InputHandlerProxy::HandleGestureScrollUpdate( - const WebGestureEvent& gesture_event) { -#ifndef NDEBUG - DCHECK(expect_scroll_update_end_); -#endif - - if (!gesture_scroll_on_impl_thread_ && !gesture_pinch_on_impl_thread_) - return DID_NOT_HANDLE; - - gfx::Point scroll_point(gesture_event.x, gesture_event.y); - gfx::Vector2dF scroll_delta(-gesture_event.data.scrollUpdate.deltaX, - -gesture_event.data.scrollUpdate.deltaY); - cc::InputHandlerScrollResult scroll_result = input_handler_->ScrollBy( - scroll_point, scroll_delta); - HandleOverscroll(scroll_point, scroll_result); - return scroll_result.did_scroll ? DID_HANDLE : DROP_EVENT; -} - -InputHandlerProxy::EventDisposition InputHandlerProxy::HandleGestureScrollEnd( - const WebGestureEvent& gesture_event) { -#ifndef NDEBUG - DCHECK(expect_scroll_update_end_); - expect_scroll_update_end_ = false; -#endif - input_handler_->ScrollEnd(); - if (!gesture_scroll_on_impl_thread_) - return DID_NOT_HANDLE; - gesture_scroll_on_impl_thread_ = false; - return DID_HANDLE; -} - -InputHandlerProxy::EventDisposition InputHandlerProxy::HandleGestureFlingStart( - const WebGestureEvent& gesture_event) { - cc::InputHandler::ScrollStatus scroll_status = - cc::InputHandler::SCROLL_ON_MAIN_THREAD; - switch (gesture_event.sourceDevice) { - case blink::WebGestureDeviceTouchpad: - if (gesture_event.data.flingStart.targetViewport) { - scroll_status = input_handler_->RootScrollBegin( - cc::InputHandler::NON_BUBBLING_GESTURE); - } else { - scroll_status = input_handler_->ScrollBegin( - gfx::Point(gesture_event.x, gesture_event.y), - cc::InputHandler::NON_BUBBLING_GESTURE); - } - break; - case blink::WebGestureDeviceTouchscreen: - if (!gesture_scroll_on_impl_thread_) - scroll_status = cc::InputHandler::SCROLL_ON_MAIN_THREAD; - else - scroll_status = input_handler_->FlingScrollBegin(); - break; - case blink::WebGestureDeviceUninitialized: - NOTREACHED(); - return DID_NOT_HANDLE; - } - -#ifndef NDEBUG - expect_scroll_update_end_ = false; -#endif - - switch (scroll_status) { - case cc::InputHandler::SCROLL_STARTED: { - if (gesture_event.sourceDevice == blink::WebGestureDeviceTouchpad) - input_handler_->ScrollEnd(); - - const float vx = gesture_event.data.flingStart.velocityX; - const float vy = gesture_event.data.flingStart.velocityY; - current_fling_velocity_ = gfx::Vector2dF(vx, vy); - DCHECK(!current_fling_velocity_.IsZero()); - fling_curve_.reset(client_->CreateFlingAnimationCurve( - gesture_event.sourceDevice, - WebFloatPoint(vx, vy), - blink::WebSize())); - disallow_horizontal_fling_scroll_ = !vx; - disallow_vertical_fling_scroll_ = !vy; - TRACE_EVENT_ASYNC_BEGIN2("input,benchmark", - "InputHandlerProxy::HandleGestureFling::started", - this, "vx", vx, "vy", vy); - // Note that the timestamp will only be used to kickstart the animation if - // its sufficiently close to the timestamp of the first call |Animate()|. - has_fling_animation_started_ = false; - fling_parameters_.startTime = gesture_event.timeStampSeconds; - fling_parameters_.delta = WebFloatPoint(vx, vy); - fling_parameters_.point = WebPoint(gesture_event.x, gesture_event.y); - fling_parameters_.globalPoint = - WebPoint(gesture_event.globalX, gesture_event.globalY); - fling_parameters_.modifiers = gesture_event.modifiers; - fling_parameters_.sourceDevice = gesture_event.sourceDevice; - RequestAnimation(); - return DID_HANDLE; - } - case cc::InputHandler::SCROLL_UNKNOWN: - case cc::InputHandler::SCROLL_ON_MAIN_THREAD: { - TRACE_EVENT_INSTANT0("input", - "InputHandlerProxy::HandleGestureFling::" - "scroll_on_main_thread", - TRACE_EVENT_SCOPE_THREAD); - gesture_scroll_on_impl_thread_ = false; - fling_may_be_active_on_main_thread_ = true; - return DID_NOT_HANDLE; - } - case cc::InputHandler::SCROLL_IGNORED: { - TRACE_EVENT_INSTANT0( - "input", - "InputHandlerProxy::HandleGestureFling::ignored", - TRACE_EVENT_SCOPE_THREAD); - gesture_scroll_on_impl_thread_ = false; - if (gesture_event.sourceDevice == blink::WebGestureDeviceTouchpad) { - // We still pass the curve to the main thread if there's nothing - // scrollable, in case something - // registers a handler before the curve is over. - return DID_NOT_HANDLE; - } - return DROP_EVENT; - } - case cc::InputHandler::ScrollStatusCount: - NOTREACHED(); - break; - } - return DID_NOT_HANDLE; -} - -InputHandlerProxy::EventDisposition InputHandlerProxy::HandleTouchStart( - const blink::WebTouchEvent& touch_event) { - for (size_t i = 0; i < touch_event.touchesLength; ++i) { - if (touch_event.touches[i].state != WebTouchPoint::StatePressed) - continue; - if (input_handler_->DoTouchEventsBlockScrollAt( - gfx::Point(touch_event.touches[i].position.x, - touch_event.touches[i].position.y))) { - // TODO(rbyers): We should consider still sending the touch events to - // main asynchronously (crbug.com/455539). - return DID_NOT_HANDLE; - } - } - return DROP_EVENT; -} - -bool InputHandlerProxy::FilterInputEventForFlingBoosting( - const WebInputEvent& event) { - if (!WebInputEvent::isGestureEventType(event.type)) - return false; - - if (!fling_curve_) { - DCHECK(!deferred_fling_cancel_time_seconds_); - return false; - } - - const WebGestureEvent& gesture_event = - static_cast<const WebGestureEvent&>(event); - if (gesture_event.type == WebInputEvent::GestureFlingCancel) { - if (gesture_event.data.flingCancel.preventBoosting) - return false; - - if (current_fling_velocity_.LengthSquared() < kMinBoostFlingSpeedSquare) - return false; - - TRACE_EVENT_INSTANT0("input", - "InputHandlerProxy::FlingBoostStart", - TRACE_EVENT_SCOPE_THREAD); - deferred_fling_cancel_time_seconds_ = - event.timeStampSeconds + kFlingBoostTimeoutDelaySeconds; - return true; - } - - // A fling is either inactive or is "free spinning", i.e., has yet to be - // interrupted by a touch gesture, in which case there is nothing to filter. - if (!deferred_fling_cancel_time_seconds_) - return false; - - // Gestures from a different source should immediately interrupt the fling. - if (gesture_event.sourceDevice != fling_parameters_.sourceDevice) { - CancelCurrentFling(); - return false; - } - - switch (gesture_event.type) { - case WebInputEvent::GestureTapCancel: - case WebInputEvent::GestureTapDown: - return false; - - case WebInputEvent::GestureScrollBegin: - if (!input_handler_->IsCurrentlyScrollingLayerAt( - gfx::Point(gesture_event.x, gesture_event.y), - fling_parameters_.sourceDevice == blink::WebGestureDeviceTouchpad - ? cc::InputHandler::NON_BUBBLING_GESTURE - : cc::InputHandler::GESTURE)) { - CancelCurrentFling(); - return false; - } - - // TODO(jdduke): Use |gesture_event.data.scrollBegin.delta{X,Y}Hint| to - // determine if the ScrollBegin should immediately cancel the fling. - ExtendBoostedFlingTimeout(gesture_event); - return true; - - case WebInputEvent::GestureScrollUpdate: { - const double time_since_last_boost_event = - event.timeStampSeconds - last_fling_boost_event_.timeStampSeconds; - const double time_since_last_fling_animate = std::max( - 0.0, event.timeStampSeconds - InSecondsF(last_fling_animate_time_)); - if (ShouldSuppressScrollForFlingBoosting(current_fling_velocity_, - gesture_event, - time_since_last_boost_event, - time_since_last_fling_animate)) { - ExtendBoostedFlingTimeout(gesture_event); - return true; - } - - CancelCurrentFling(); - return false; - } - - case WebInputEvent::GestureScrollEnd: - // Clear the last fling boost event *prior* to fling cancellation, - // preventing insertion of a synthetic GestureScrollBegin. - last_fling_boost_event_ = WebGestureEvent(); - CancelCurrentFling(); - return true; - - case WebInputEvent::GestureFlingStart: { - DCHECK_EQ(fling_parameters_.sourceDevice, gesture_event.sourceDevice); - - bool fling_boosted = - fling_parameters_.modifiers == gesture_event.modifiers && - ShouldBoostFling(current_fling_velocity_, gesture_event); - - gfx::Vector2dF new_fling_velocity( - gesture_event.data.flingStart.velocityX, - gesture_event.data.flingStart.velocityY); - DCHECK(!new_fling_velocity.IsZero()); - - if (fling_boosted) - current_fling_velocity_ += new_fling_velocity; - else - current_fling_velocity_ = new_fling_velocity; - - WebFloatPoint velocity(current_fling_velocity_.x(), - current_fling_velocity_.y()); - deferred_fling_cancel_time_seconds_ = 0; - disallow_horizontal_fling_scroll_ = !velocity.x; - disallow_vertical_fling_scroll_ = !velocity.y; - last_fling_boost_event_ = WebGestureEvent(); - fling_curve_.reset(client_->CreateFlingAnimationCurve( - gesture_event.sourceDevice, - velocity, - blink::WebSize())); - fling_parameters_.startTime = gesture_event.timeStampSeconds; - fling_parameters_.delta = velocity; - fling_parameters_.point = WebPoint(gesture_event.x, gesture_event.y); - fling_parameters_.globalPoint = - WebPoint(gesture_event.globalX, gesture_event.globalY); - - TRACE_EVENT_INSTANT2("input", - fling_boosted ? "InputHandlerProxy::FlingBoosted" - : "InputHandlerProxy::FlingReplaced", - TRACE_EVENT_SCOPE_THREAD, - "vx", - current_fling_velocity_.x(), - "vy", - current_fling_velocity_.y()); - - // The client expects balanced calls between a consumed GestureFlingStart - // and |DidStopFlinging()|. - client_->DidStopFlinging(); - return true; - } - - default: - // All other types of gestures (taps, presses, etc...) will complete the - // deferred fling cancellation. - CancelCurrentFling(); - return false; - } -} - -void InputHandlerProxy::ExtendBoostedFlingTimeout( - const blink::WebGestureEvent& event) { - TRACE_EVENT_INSTANT0("input", - "InputHandlerProxy::ExtendBoostedFlingTimeout", - TRACE_EVENT_SCOPE_THREAD); - deferred_fling_cancel_time_seconds_ = - event.timeStampSeconds + kFlingBoostTimeoutDelaySeconds; - last_fling_boost_event_ = event; -} - -void InputHandlerProxy::Animate(base::TimeTicks time) { - // If using synchronous animate, then only expect Animate attempts started by - // the synchronous system. Don't let the InputHandler try to Animate also. - DCHECK(!input_handler_->IsCurrentlyScrollingInnerViewport() || - allow_root_animate_); - - if (scroll_elasticity_controller_) - scroll_elasticity_controller_->Animate(time); - - if (!fling_curve_) - return; - - last_fling_animate_time_ = time; - double monotonic_time_sec = InSecondsF(time); - - if (deferred_fling_cancel_time_seconds_ && - monotonic_time_sec > deferred_fling_cancel_time_seconds_) { - CancelCurrentFling(); - return; - } - - client_->DidAnimateForInput(); - - if (!has_fling_animation_started_) { - has_fling_animation_started_ = true; - // Guard against invalid, future or sufficiently stale start times, as there - // are no guarantees fling event and animation timestamps are compatible. - if (!fling_parameters_.startTime || - monotonic_time_sec <= fling_parameters_.startTime || - monotonic_time_sec >= fling_parameters_.startTime + - kMaxSecondsFromFlingTimestampToFirstAnimate) { - fling_parameters_.startTime = monotonic_time_sec; - RequestAnimation(); - return; - } - } - - bool fling_is_active = - fling_curve_->apply(monotonic_time_sec - fling_parameters_.startTime, - this); - - if (disallow_vertical_fling_scroll_ && disallow_horizontal_fling_scroll_) - fling_is_active = false; - - if (fling_is_active) { - RequestAnimation(); - } else { - TRACE_EVENT_INSTANT0("input", - "InputHandlerProxy::animate::flingOver", - TRACE_EVENT_SCOPE_THREAD); - CancelCurrentFling(); - } -} - -void InputHandlerProxy::MainThreadHasStoppedFlinging() { - fling_may_be_active_on_main_thread_ = false; - client_->DidStopFlinging(); -} - -void InputHandlerProxy::ReconcileElasticOverscrollAndRootScroll() { - if (scroll_elasticity_controller_) - scroll_elasticity_controller_->ReconcileStretchAndScroll(); -} - -void InputHandlerProxy::UpdateRootLayerStateForSynchronousInputHandler( - const gfx::ScrollOffset& total_scroll_offset, - const gfx::ScrollOffset& max_scroll_offset, - const gfx::SizeF& scrollable_size, - float page_scale_factor, - float min_page_scale_factor, - float max_page_scale_factor) { - if (synchronous_input_handler_) { - synchronous_input_handler_->UpdateRootLayerState( - total_scroll_offset, max_scroll_offset, scrollable_size, - page_scale_factor, min_page_scale_factor, max_page_scale_factor); - } -} - -void InputHandlerProxy::SetOnlySynchronouslyAnimateRootFlings( - SynchronousInputHandler* synchronous_input_handler) { - allow_root_animate_ = !synchronous_input_handler; - synchronous_input_handler_ = synchronous_input_handler; - if (synchronous_input_handler_) - input_handler_->RequestUpdateForSynchronousInputHandler(); -} - -void InputHandlerProxy::SynchronouslyAnimate(base::TimeTicks time) { - // When this function is used, SetOnlySynchronouslyAnimate() should have been - // previously called. IOW you should either be entirely in synchronous mode or - // not. - DCHECK(synchronous_input_handler_); - DCHECK(!allow_root_animate_); - base::AutoReset<bool> reset(&allow_root_animate_, true); - Animate(time); -} - -void InputHandlerProxy::SynchronouslySetRootScrollOffset( - const gfx::ScrollOffset& root_offset) { - DCHECK(synchronous_input_handler_); - input_handler_->SetSynchronousInputHandlerRootScrollOffset(root_offset); -} - -void InputHandlerProxy::HandleOverscroll( - const gfx::Point& causal_event_viewport_point, - const cc::InputHandlerScrollResult& scroll_result) { - DCHECK(client_); - if (!scroll_result.did_overscroll_root) - return; - - TRACE_EVENT2("input", - "InputHandlerProxy::DidOverscroll", - "dx", - scroll_result.unused_scroll_delta.x(), - "dy", - scroll_result.unused_scroll_delta.y()); - - DidOverscrollParams params; - params.accumulated_overscroll = scroll_result.accumulated_root_overscroll; - params.latest_overscroll_delta = scroll_result.unused_scroll_delta; - params.current_fling_velocity = - ToClientScrollIncrement(current_fling_velocity_); - params.causal_event_viewport_point = gfx::PointF(causal_event_viewport_point); - - if (fling_curve_) { - static const int kFlingOverscrollThreshold = 1; - disallow_horizontal_fling_scroll_ |= - std::abs(params.accumulated_overscroll.x()) >= - kFlingOverscrollThreshold; - disallow_vertical_fling_scroll_ |= - std::abs(params.accumulated_overscroll.y()) >= - kFlingOverscrollThreshold; - } - - client_->DidOverscroll(params); -} - -bool InputHandlerProxy::CancelCurrentFling() { - if (CancelCurrentFlingWithoutNotifyingClient()) { - client_->DidStopFlinging(); - return true; - } - return false; -} - -bool InputHandlerProxy::CancelCurrentFlingWithoutNotifyingClient() { - bool had_fling_animation = fling_curve_; - if (had_fling_animation && - fling_parameters_.sourceDevice == blink::WebGestureDeviceTouchscreen) { - input_handler_->ScrollEnd(); - TRACE_EVENT_ASYNC_END0( - "input", - "InputHandlerProxy::HandleGestureFling::started", - this); - } - - TRACE_EVENT_INSTANT1("input", - "InputHandlerProxy::CancelCurrentFling", - TRACE_EVENT_SCOPE_THREAD, - "had_fling_animation", - had_fling_animation); - fling_curve_.reset(); - has_fling_animation_started_ = false; - gesture_scroll_on_impl_thread_ = false; - current_fling_velocity_ = gfx::Vector2dF(); - fling_parameters_ = blink::WebActiveWheelFlingParameters(); - - if (deferred_fling_cancel_time_seconds_) { - deferred_fling_cancel_time_seconds_ = 0; - - WebGestureEvent last_fling_boost_event = last_fling_boost_event_; - last_fling_boost_event_ = WebGestureEvent(); - if (last_fling_boost_event.type == WebInputEvent::GestureScrollBegin || - last_fling_boost_event.type == WebInputEvent::GestureScrollUpdate) { - // Synthesize a GestureScrollBegin, as the original was suppressed. - HandleInputEvent(ObtainGestureScrollBegin(last_fling_boost_event)); - } - } - - return had_fling_animation; -} - -void InputHandlerProxy::RequestAnimation() { - // When a SynchronousInputHandler is present, root flings should go through - // it to allow it to control when or if the root fling is animated. Non-root - // flings always go through the normal InputHandler. - if (synchronous_input_handler_ && - input_handler_->IsCurrentlyScrollingInnerViewport()) - synchronous_input_handler_->SetNeedsSynchronousAnimateInput(); - else - input_handler_->SetNeedsAnimateInput(); -} - -bool InputHandlerProxy::TouchpadFlingScroll( - const WebFloatSize& increment) { - WebMouseWheelEvent synthetic_wheel; - synthetic_wheel.type = WebInputEvent::MouseWheel; - synthetic_wheel.deltaX = increment.width; - synthetic_wheel.deltaY = increment.height; - synthetic_wheel.hasPreciseScrollingDeltas = true; - synthetic_wheel.x = fling_parameters_.point.x; - synthetic_wheel.y = fling_parameters_.point.y; - synthetic_wheel.globalX = fling_parameters_.globalPoint.x; - synthetic_wheel.globalY = fling_parameters_.globalPoint.y; - synthetic_wheel.modifiers = fling_parameters_.modifiers; - - InputHandlerProxy::EventDisposition disposition = - HandleInputEvent(synthetic_wheel); - switch (disposition) { - case DID_HANDLE: - return true; - case DROP_EVENT: - break; - case DID_NOT_HANDLE: - TRACE_EVENT_INSTANT0("input", - "InputHandlerProxy::scrollBy::AbortFling", - TRACE_EVENT_SCOPE_THREAD); - // If we got a DID_NOT_HANDLE, that means we need to deliver wheels on the - // main thread. In this case we need to schedule a commit and transfer the - // fling curve over to the main thread and run the rest of the wheels from - // there. This can happen when flinging a page that contains a scrollable - // subarea that we can't scroll on the thread if the fling starts outside - // the subarea but then is flung "under" the pointer. - client_->TransferActiveWheelFlingAnimation(fling_parameters_); - fling_may_be_active_on_main_thread_ = true; - CancelCurrentFlingWithoutNotifyingClient(); - break; - } - - return false; -} - -bool InputHandlerProxy::scrollBy(const WebFloatSize& increment, - const WebFloatSize& velocity) { - WebFloatSize clipped_increment; - WebFloatSize clipped_velocity; - if (!disallow_horizontal_fling_scroll_) { - clipped_increment.width = increment.width; - clipped_velocity.width = velocity.width; - } - if (!disallow_vertical_fling_scroll_) { - clipped_increment.height = increment.height; - clipped_velocity.height = velocity.height; - } - - current_fling_velocity_ = clipped_velocity; - - // Early out if the increment is zero, but avoid early terimination if the - // velocity is still non-zero. - if (clipped_increment == WebFloatSize()) - return clipped_velocity != WebFloatSize(); - - TRACE_EVENT2("input", - "InputHandlerProxy::scrollBy", - "x", - clipped_increment.width, - "y", - clipped_increment.height); - - bool did_scroll = false; - - switch (fling_parameters_.sourceDevice) { - case blink::WebGestureDeviceTouchpad: - did_scroll = TouchpadFlingScroll(clipped_increment); - break; - case blink::WebGestureDeviceTouchscreen: { - clipped_increment = ToClientScrollIncrement(clipped_increment); - cc::InputHandlerScrollResult scroll_result = input_handler_->ScrollBy( - fling_parameters_.point, clipped_increment); - HandleOverscroll(fling_parameters_.point, scroll_result); - did_scroll = scroll_result.did_scroll; - } break; - case blink::WebGestureDeviceUninitialized: - NOTREACHED(); - return false; - } - - if (did_scroll) { - fling_parameters_.cumulativeScroll.width += clipped_increment.width; - fling_parameters_.cumulativeScroll.height += clipped_increment.height; - } - - // It's possible the provided |increment| is sufficiently small as to not - // trigger a scroll, e.g., with a trivial time delta between fling updates. - // Return true in this case to prevent early fling termination. - if (std::abs(clipped_increment.width) < kScrollEpsilon && - std::abs(clipped_increment.height) < kScrollEpsilon) - return true; - - return did_scroll; -} - -} // namespace content diff --git a/content/renderer/input/input_handler_proxy.h b/content/renderer/input/input_handler_proxy.h deleted file mode 100644 index d234511..0000000 --- a/content/renderer/input/input_handler_proxy.h +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright 2013 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. - -#ifndef CONTENT_RENDERER_INPUT_INPUT_HANDLER_PROXY_H_ -#define CONTENT_RENDERER_INPUT_INPUT_HANDLER_PROXY_H_ - -#include "base/basictypes.h" -#include "base/containers/hash_tables.h" -#include "base/memory/scoped_ptr.h" -#include "cc/input/input_handler.h" -#include "content/common/content_export.h" -#include "content/renderer/input/synchronous_input_handler_proxy.h" -#include "third_party/WebKit/public/platform/WebGestureCurve.h" -#include "third_party/WebKit/public/platform/WebGestureCurveTarget.h" -#include "third_party/WebKit/public/web/WebActiveWheelFlingParameters.h" -#include "third_party/WebKit/public/web/WebInputEvent.h" - -namespace content { - -namespace test { -class InputHandlerProxyTest; -} - -class InputHandlerProxyClient; -class InputScrollElasticityController; - -// This class is a proxy between the content input event filtering and the -// compositor's input handling logic. InputHandlerProxy instances live entirely -// on the compositor thread. Each InputHandler instance handles input events -// intended for a specific WebWidget. -class CONTENT_EXPORT InputHandlerProxy - : public cc::InputHandlerClient, - public SynchronousInputHandlerProxy, - public NON_EXPORTED_BASE(blink::WebGestureCurveTarget) { - public: - InputHandlerProxy(cc::InputHandler* input_handler, - InputHandlerProxyClient* client); - ~InputHandlerProxy() override; - - InputScrollElasticityController* scroll_elasticity_controller() { - return scroll_elasticity_controller_.get(); - } - - enum EventDisposition { - DID_HANDLE, - DID_NOT_HANDLE, - DROP_EVENT - }; - EventDisposition HandleInputEventWithLatencyInfo( - const blink::WebInputEvent& event, - ui::LatencyInfo* latency_info); - EventDisposition HandleInputEvent(const blink::WebInputEvent& event); - - // cc::InputHandlerClient implementation. - void WillShutdown() override; - void Animate(base::TimeTicks time) override; - void MainThreadHasStoppedFlinging() override; - void ReconcileElasticOverscrollAndRootScroll() override; - void UpdateRootLayerStateForSynchronousInputHandler( - const gfx::ScrollOffset& total_scroll_offset, - const gfx::ScrollOffset& max_scroll_offset, - const gfx::SizeF& scrollable_size, - float page_scale_factor, - float min_page_scale_factor, - float max_page_scale_factor) override; - - // SynchronousInputHandlerProxy implementation. - void SetOnlySynchronouslyAnimateRootFlings( - SynchronousInputHandler* synchronous_input_handler) override; - void SynchronouslyAnimate(base::TimeTicks time) override; - void SynchronouslySetRootScrollOffset( - const gfx::ScrollOffset& root_offset) override; - - // blink::WebGestureCurveTarget implementation. - bool scrollBy(const blink::WebFloatSize& offset, - const blink::WebFloatSize& velocity) override; - - bool gesture_scroll_on_impl_thread_for_testing() const { - return gesture_scroll_on_impl_thread_; - } - - private: - friend class test::InputHandlerProxyTest; - - // Helper functions for handling more complicated input events. - EventDisposition HandleMouseWheel( - const blink::WebMouseWheelEvent& event); - EventDisposition HandleGestureScrollBegin( - const blink::WebGestureEvent& event); - EventDisposition HandleGestureScrollUpdate( - const blink::WebGestureEvent& event); - EventDisposition HandleGestureScrollEnd( - const blink::WebGestureEvent& event); - EventDisposition HandleGestureFlingStart( - const blink::WebGestureEvent& event); - EventDisposition HandleTouchStart( - const blink::WebTouchEvent& event); - - // Returns true if the event should be suppressed due to to an active, - // boost-enabled fling, in which case further processing should cease. - bool FilterInputEventForFlingBoosting(const blink::WebInputEvent& event); - - // Schedule a time in the future after which a boost-enabled fling will - // terminate without further momentum from the user (see |Animate()|). - void ExtendBoostedFlingTimeout(const blink::WebGestureEvent& event); - - // Returns true if we scrolled by the increment. - bool TouchpadFlingScroll(const blink::WebFloatSize& increment); - - // Returns true if we actually had an active fling to cancel, also notifying - // the client that the fling has ended. Note that if a boosted fling is active - // and suppressing an active scroll sequence, a synthetic GestureScrollBegin - // will be injected to resume scrolling. - bool CancelCurrentFling(); - - // Returns true if we actually had an active fling to cancel. - bool CancelCurrentFlingWithoutNotifyingClient(); - - // Request a frame of animation from the InputHandler or - // SynchronousInputHandler. They can provide that by calling Animate(). - void RequestAnimation(); - - // Used to send overscroll messages to the browser. - void HandleOverscroll( - const gfx::Point& causal_event_viewport_point, - const cc::InputHandlerScrollResult& scroll_result); - - scoped_ptr<blink::WebGestureCurve> fling_curve_; - // Parameters for the active fling animation, stored in case we need to - // transfer it out later. - blink::WebActiveWheelFlingParameters fling_parameters_; - - InputHandlerProxyClient* client_; - cc::InputHandler* input_handler_; - - // Time at which an active fling should expire due to a deferred cancellation - // event. A call to |Animate()| after this time will end the fling. - double deferred_fling_cancel_time_seconds_; - - // The last event that extended the lifetime of the boosted fling. If the - // event was a scroll gesture, a GestureScrollBegin will be inserted if the - // fling terminates (via |CancelCurrentFling()|). - blink::WebGestureEvent last_fling_boost_event_; - - // When present, Animates are not requested to the InputHandler, but to this - // SynchronousInputHandler instead. And all Animate() calls are expected to - // happen via the SynchronouslyAnimate() call instead of coming directly from - // the InputHandler. - SynchronousInputHandler* synchronous_input_handler_; - bool allow_root_animate_; - -#ifndef NDEBUG - bool expect_scroll_update_end_; -#endif - bool gesture_scroll_on_impl_thread_; - bool gesture_pinch_on_impl_thread_; - // This is always false when there are no flings on the main thread, but - // conservative in the sense that we might not be actually flinging when it is - // true. - bool fling_may_be_active_on_main_thread_; - // The axes on which the current fling is allowed to scroll. If a given fling - // has overscrolled on a particular axis, further fling scrolls on that axis - // will be disabled. - bool disallow_horizontal_fling_scroll_; - bool disallow_vertical_fling_scroll_; - - // Whether an active fling has seen an |Animate()| call. This is useful for - // determining if the fling start time should be re-initialized. - bool has_fling_animation_started_; - - // Non-zero only within the scope of |scrollBy|. - gfx::Vector2dF current_fling_velocity_; - - // Used to animate rubber-band over-scroll effect on Mac. - scoped_ptr<InputScrollElasticityController> scroll_elasticity_controller_; - - bool smooth_scroll_enabled_; - - bool uma_latency_reporting_enabled_; - - base::TimeTicks last_fling_animate_time_; - - DISALLOW_COPY_AND_ASSIGN(InputHandlerProxy); -}; - -} // namespace content - -#endif // CONTENT_RENDERER_INPUT_INPUT_HANDLER_PROXY_H_ diff --git a/content/renderer/input/input_handler_proxy_client.h b/content/renderer/input/input_handler_proxy_client.h deleted file mode 100644 index 53b4bc9..0000000 --- a/content/renderer/input/input_handler_proxy_client.h +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2013 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. - -#ifndef CONTENT_RENDERER_INPUT_INPUT_HANDLER_PROXY_CLIENT_H_ -#define CONTENT_RENDERER_INPUT_INPUT_HANDLER_PROXY_CLIENT_H_ - -namespace blink { -class WebGestureCurve; -struct WebActiveWheelFlingParameters; -struct WebFloatPoint; -struct WebSize; -} - -namespace content { - -struct DidOverscrollParams; - -// All callbacks invoked from the compositor thread. -class InputHandlerProxyClient { - public: - // Called just before the InputHandlerProxy shuts down. - virtual void WillShutdown() = 0; - - // Transfers an active wheel fling animation initiated by a previously - // handled input event out to the client. - virtual void TransferActiveWheelFlingAnimation( - const blink::WebActiveWheelFlingParameters& params) = 0; - - // Creates a new fling animation curve instance for device |device_source| - // with |velocity| and already scrolled |cumulative_scroll| pixels. - virtual blink::WebGestureCurve* CreateFlingAnimationCurve( - blink::WebGestureDevice device_source, - const blink::WebFloatPoint& velocity, - const blink::WebSize& cumulative_scroll) = 0; - - virtual void DidOverscroll(const DidOverscrollParams& params) = 0; - - virtual void DidStopFlinging() = 0; - - virtual void DidAnimateForInput() = 0; - - protected: - virtual ~InputHandlerProxyClient() {} -}; - -} // namespace content - -#endif // CONTENT_RENDERER_INPUT_INPUT_HANDLER_PROXY_CLIENT_H_ diff --git a/content/renderer/input/input_handler_proxy_unittest.cc b/content/renderer/input/input_handler_proxy_unittest.cc deleted file mode 100644 index aee95d8..0000000 --- a/content/renderer/input/input_handler_proxy_unittest.cc +++ /dev/null @@ -1,2478 +0,0 @@ -// Copyright 2013 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 "content/renderer/input/input_handler_proxy.h" - -#include "base/basictypes.h" -#include "base/memory/scoped_ptr.h" -#include "cc/trees/swap_promise_monitor.h" -#include "content/common/input/did_overscroll_params.h" -#include "content/renderer/input/input_handler_proxy_client.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "third_party/WebKit/public/platform/WebFloatPoint.h" -#include "third_party/WebKit/public/platform/WebFloatSize.h" -#include "third_party/WebKit/public/platform/WebGestureCurve.h" -#include "third_party/WebKit/public/platform/WebPoint.h" -#include "third_party/WebKit/public/web/WebInputEvent.h" -#include "ui/events/latency_info.h" -#include "ui/gfx/geometry/scroll_offset.h" -#include "ui/gfx/geometry/size_f.h" - -using blink::WebActiveWheelFlingParameters; -using blink::WebFloatPoint; -using blink::WebFloatSize; -using blink::WebGestureDevice; -using blink::WebGestureEvent; -using blink::WebInputEvent; -using blink::WebKeyboardEvent; -using blink::WebMouseWheelEvent; -using blink::WebPoint; -using blink::WebSize; -using blink::WebTouchEvent; -using blink::WebTouchPoint; -using testing::Field; - -namespace content { -namespace test { - -namespace { - -enum InputHandlerProxyTestType { - ROOT_SCROLL_NORMAL_HANDLER, - ROOT_SCROLL_SYNCHRONOUS_HANDLER, - CHILD_SCROLL_NORMAL_HANDLER, - CHILD_SCROLL_SYNCHRONOUS_HANDLER, -}; -static const InputHandlerProxyTestType test_types[] = { - ROOT_SCROLL_NORMAL_HANDLER, ROOT_SCROLL_SYNCHRONOUS_HANDLER, - CHILD_SCROLL_NORMAL_HANDLER, CHILD_SCROLL_SYNCHRONOUS_HANDLER}; - -double InSecondsF(const base::TimeTicks& time) { - return (time - base::TimeTicks()).InSecondsF(); -} - -WebGestureEvent CreateFling(base::TimeTicks timestamp, - WebGestureDevice source_device, - WebFloatPoint velocity, - WebPoint point, - WebPoint global_point, - int modifiers) { - WebGestureEvent fling; - fling.type = WebInputEvent::GestureFlingStart; - fling.sourceDevice = source_device; - fling.timeStampSeconds = (timestamp - base::TimeTicks()).InSecondsF(); - fling.data.flingStart.velocityX = velocity.x; - fling.data.flingStart.velocityY = velocity.y; - fling.x = point.x; - fling.y = point.y; - fling.globalX = global_point.x; - fling.globalY = global_point.y; - fling.modifiers = modifiers; - return fling; -} - -WebGestureEvent CreateFling(WebGestureDevice source_device, - WebFloatPoint velocity, - WebPoint point, - WebPoint global_point, - int modifiers) { - return CreateFling(base::TimeTicks(), - source_device, - velocity, - point, - global_point, - modifiers); -} - -class MockInputHandler : public cc::InputHandler { - public: - MockInputHandler() {} - ~MockInputHandler() override {} - - MOCK_METHOD0(PinchGestureBegin, void()); - MOCK_METHOD2(PinchGestureUpdate, - void(float magnify_delta, const gfx::Point& anchor)); - MOCK_METHOD0(PinchGestureEnd, void()); - - MOCK_METHOD0(SetNeedsAnimateInput, void()); - - MOCK_METHOD2(ScrollBegin, - ScrollStatus(const gfx::Point& viewport_point, - cc::InputHandler::ScrollInputType type)); - MOCK_METHOD1(RootScrollBegin, - ScrollStatus(cc::InputHandler::ScrollInputType type)); - MOCK_METHOD2(ScrollAnimated, - ScrollStatus(const gfx::Point& viewport_point, - const gfx::Vector2dF& scroll_delta)); - MOCK_METHOD2(ScrollBy, - cc::InputHandlerScrollResult( - const gfx::Point& viewport_point, - const gfx::Vector2dF& scroll_delta)); - MOCK_METHOD2(ScrollVerticallyByPage, - bool(const gfx::Point& viewport_point, - cc::ScrollDirection direction)); - MOCK_METHOD0(ScrollEnd, void()); - MOCK_METHOD0(FlingScrollBegin, cc::InputHandler::ScrollStatus()); - - scoped_ptr<cc::SwapPromiseMonitor> CreateLatencyInfoSwapPromiseMonitor( - ui::LatencyInfo* latency) override { - return scoped_ptr<cc::SwapPromiseMonitor>(); - } - - cc::ScrollElasticityHelper* CreateScrollElasticityHelper() override { - return NULL; - } - - void BindToClient(cc::InputHandlerClient* client) override {} - - void MouseMoveAt(const gfx::Point& mouse_position) override {} - - MOCK_CONST_METHOD2(IsCurrentlyScrollingLayerAt, - bool(const gfx::Point& point, - cc::InputHandler::ScrollInputType type)); - - MOCK_METHOD1(HaveWheelEventHandlersAt, bool(const gfx::Point& point)); - MOCK_METHOD1(DoTouchEventsBlockScrollAt, bool(const gfx::Point& point)); - - MOCK_METHOD0(RequestUpdateForSynchronousInputHandler, void()); - MOCK_METHOD1(SetSynchronousInputHandlerRootScrollOffset, - void(const gfx::ScrollOffset& root_offset)); - - bool IsCurrentlyScrollingInnerViewport() const override { - return is_scrolling_root_; - } - void set_is_scrolling_root(bool is) { is_scrolling_root_ = is; } - - private: - bool is_scrolling_root_ = true; - DISALLOW_COPY_AND_ASSIGN(MockInputHandler); -}; - -class MockSynchronousInputHandler : public content::SynchronousInputHandler { - public: - MOCK_METHOD0(SetNeedsSynchronousAnimateInput, void()); - MOCK_METHOD6(UpdateRootLayerState, - void(const gfx::ScrollOffset& total_scroll_offset, - const gfx::ScrollOffset& max_scroll_offset, - const gfx::SizeF& scrollable_size, - float page_scale_factor, - float min_page_scale_factor, - float max_page_scale_factor)); -}; - -// A simple WebGestureCurve implementation that flings at a constant velocity -// indefinitely. -class FakeWebGestureCurve : public blink::WebGestureCurve { - public: - FakeWebGestureCurve(const blink::WebFloatSize& velocity, - const blink::WebFloatSize& cumulative_scroll) - : velocity_(velocity), cumulative_scroll_(cumulative_scroll) {} - - ~FakeWebGestureCurve() override {} - - // Returns false if curve has finished and can no longer be applied. - bool apply(double time, blink::WebGestureCurveTarget* target) override { - blink::WebFloatSize displacement(velocity_.width * time, - velocity_.height * time); - blink::WebFloatSize increment( - displacement.width - cumulative_scroll_.width, - displacement.height - cumulative_scroll_.height); - cumulative_scroll_ = displacement; - // scrollBy() could delete this curve if the animation is over, so don't - // touch any member variables after making that call. - return target->scrollBy(increment, velocity_); - } - - private: - blink::WebFloatSize velocity_; - blink::WebFloatSize cumulative_scroll_; - - DISALLOW_COPY_AND_ASSIGN(FakeWebGestureCurve); -}; - -class MockInputHandlerProxyClient - : public content::InputHandlerProxyClient { - public: - MockInputHandlerProxyClient() {} - ~MockInputHandlerProxyClient() override {} - - void WillShutdown() override {} - - MOCK_METHOD1(TransferActiveWheelFlingAnimation, - void(const WebActiveWheelFlingParameters&)); - - blink::WebGestureCurve* CreateFlingAnimationCurve( - WebGestureDevice deviceSource, - const WebFloatPoint& velocity, - const WebSize& cumulative_scroll) override { - return new FakeWebGestureCurve( - blink::WebFloatSize(velocity.x, velocity.y), - blink::WebFloatSize(cumulative_scroll.width, cumulative_scroll.height)); - } - - MOCK_METHOD1(DidOverscroll, void(const DidOverscrollParams&)); - void DidStopFlinging() override {} - void DidAnimateForInput() override {} - - private: - DISALLOW_COPY_AND_ASSIGN(MockInputHandlerProxyClient); -}; - -class MockInputHandlerProxyClientWithDidAnimateForInput - : public MockInputHandlerProxyClient { - public: - MockInputHandlerProxyClientWithDidAnimateForInput() {} - ~MockInputHandlerProxyClientWithDidAnimateForInput() override {} - - MOCK_METHOD0(DidAnimateForInput, void()); - - private: - DISALLOW_COPY_AND_ASSIGN(MockInputHandlerProxyClientWithDidAnimateForInput); -}; - -WebTouchPoint CreateWebTouchPoint(WebTouchPoint::State state, float x, - float y) { - WebTouchPoint point; - point.state = state; - point.screenPosition = WebFloatPoint(x, y); - point.position = WebFloatPoint(x, y); - return point; -} - -} // namespace - -class InputHandlerProxyTest - : public testing::Test, - public testing::WithParamInterface<InputHandlerProxyTestType> { - public: - InputHandlerProxyTest() - : synchronous_root_scroll_(GetParam() == ROOT_SCROLL_SYNCHRONOUS_HANDLER), - install_synchronous_handler_( - GetParam() == ROOT_SCROLL_SYNCHRONOUS_HANDLER || - GetParam() == CHILD_SCROLL_SYNCHRONOUS_HANDLER), - expected_disposition_(InputHandlerProxy::DID_HANDLE) { - input_handler_.reset( - new content::InputHandlerProxy(&mock_input_handler_, &mock_client_)); - scroll_result_did_scroll_.did_scroll = true; - scroll_result_did_not_scroll_.did_scroll = false; - - if (install_synchronous_handler_) { - EXPECT_CALL(mock_input_handler_, - RequestUpdateForSynchronousInputHandler()) - .Times(1); - input_handler_->SetOnlySynchronouslyAnimateRootFlings( - &mock_synchronous_input_handler_); - } - - mock_input_handler_.set_is_scrolling_root(synchronous_root_scroll_); - - // Set a default device so tests don't always have to set this. - gesture_.sourceDevice = blink::WebGestureDeviceTouchpad; - } - - ~InputHandlerProxyTest() { - input_handler_.reset(); - } - -// This is defined as a macro so the line numbers can be traced back to the -// correct spot when it fails. -#define EXPECT_SET_NEEDS_ANIMATE_INPUT(times) \ - do { \ - if (synchronous_root_scroll_) { \ - EXPECT_CALL(mock_synchronous_input_handler_, \ - SetNeedsSynchronousAnimateInput()) \ - .Times(times); \ - EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput()).Times(0); \ - } else { \ - EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput()).Times(times); \ - EXPECT_CALL(mock_synchronous_input_handler_, \ - SetNeedsSynchronousAnimateInput()) \ - .Times(0); \ - } \ - } while (false) - -// This is defined as a macro because when an expectation is not satisfied the -// only output you get out of gmock is the line number that set the expectation. -#define VERIFY_AND_RESET_MOCKS() \ - do { \ - testing::Mock::VerifyAndClearExpectations(&mock_input_handler_); \ - testing::Mock::VerifyAndClearExpectations( \ - &mock_synchronous_input_handler_); \ - testing::Mock::VerifyAndClearExpectations(&mock_client_); \ - } while (false) - - void Animate(base::TimeTicks time) { - if (synchronous_root_scroll_) { - input_handler_->SynchronouslyAnimate(time); - } else { - input_handler_->Animate(time); - } - } - - void StartFling(base::TimeTicks timestamp, - WebGestureDevice source_device, - WebFloatPoint velocity, - WebPoint position) { - expected_disposition_ = InputHandlerProxy::DID_HANDLE; - VERIFY_AND_RESET_MOCKS(); - - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); - gesture_.type = WebInputEvent::GestureScrollBegin; - gesture_.sourceDevice = source_device; - EXPECT_EQ(expected_disposition_, - input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); - - EXPECT_CALL(mock_input_handler_, FlingScrollBegin()) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - - gesture_ = - CreateFling(timestamp, source_device, velocity, position, position, 0); - EXPECT_EQ(expected_disposition_, - input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); - } - - void CancelFling(base::TimeTicks timestamp) { - gesture_.timeStampSeconds = InSecondsF(timestamp); - gesture_.type = WebInputEvent::GestureFlingCancel; - EXPECT_EQ(expected_disposition_, - input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); - } - - void SetSmoothScrollEnabled(bool value) { - input_handler_->smooth_scroll_enabled_ = value; - } - - protected: - const bool synchronous_root_scroll_; - const bool install_synchronous_handler_; - testing::StrictMock<MockInputHandler> mock_input_handler_; - testing::StrictMock<MockSynchronousInputHandler> - mock_synchronous_input_handler_; - scoped_ptr<content::InputHandlerProxy> input_handler_; - testing::StrictMock<MockInputHandlerProxyClient> mock_client_; - WebGestureEvent gesture_; - InputHandlerProxy::EventDisposition expected_disposition_; - cc::InputHandlerScrollResult scroll_result_did_scroll_; - cc::InputHandlerScrollResult scroll_result_did_not_scroll_; -}; - -TEST_P(InputHandlerProxyTest, MouseWheelByPageMainThread) { - expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE; - WebMouseWheelEvent wheel; - wheel.type = WebInputEvent::MouseWheel; - wheel.scrollByPage = true; - - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(wheel)); - VERIFY_AND_RESET_MOCKS(); -} - -TEST_P(InputHandlerProxyTest, MouseWheelWithCtrlNotScroll) { - expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE; - WebMouseWheelEvent wheel; - wheel.type = WebInputEvent::MouseWheel; - wheel.modifiers = WebInputEvent::ControlKey; - wheel.canScroll = false; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(wheel)); - VERIFY_AND_RESET_MOCKS(); -} - -TEST_P(InputHandlerProxyTest, MouseWheelWithPreciseScrollingDeltas) { - SetSmoothScrollEnabled(true); - expected_disposition_ = InputHandlerProxy::DID_HANDLE; - WebMouseWheelEvent wheel; - wheel.type = WebInputEvent::MouseWheel; - - VERIFY_AND_RESET_MOCKS(); - - // Smooth scroll because hasPreciseScrollingDeltas is set to false. - wheel.hasPreciseScrollingDeltas = false; - EXPECT_CALL(mock_input_handler_, ScrollAnimated(::testing::_, ::testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(wheel)); - - VERIFY_AND_RESET_MOCKS(); - - // No smooth scroll because hasPreciseScrollingDeltas is set to true. - wheel.hasPreciseScrollingDeltas = true; - EXPECT_CALL(mock_input_handler_, ScrollBegin(::testing::_, ::testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); - EXPECT_CALL(mock_input_handler_, ScrollBy(::testing::_, ::testing::_)) - .WillOnce(testing::Return(scroll_result_did_scroll_)); - EXPECT_CALL(mock_input_handler_, ScrollEnd()); - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(wheel)); - - VERIFY_AND_RESET_MOCKS(); -} - -TEST_P(InputHandlerProxyTest, MouseWheelScrollIgnored) { - SetSmoothScrollEnabled(true); - expected_disposition_ = InputHandlerProxy::DROP_EVENT; - WebMouseWheelEvent wheel; - wheel.type = WebInputEvent::MouseWheel; - - EXPECT_CALL(mock_input_handler_, ScrollAnimated(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_IGNORED)); - - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(wheel)); - VERIFY_AND_RESET_MOCKS(); -} - -TEST_P(InputHandlerProxyTest, GestureScrollStarted) { - // We shouldn't send any events to the widget for this gesture. - expected_disposition_ = InputHandlerProxy::DID_HANDLE; - VERIFY_AND_RESET_MOCKS(); - - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); - - gesture_.type = WebInputEvent::GestureScrollBegin; - EXPECT_EQ(expected_disposition_,input_handler_->HandleInputEvent(gesture_)); - - // The event should not be marked as handled if scrolling is not possible. - expected_disposition_ = InputHandlerProxy::DROP_EVENT; - VERIFY_AND_RESET_MOCKS(); - - gesture_.type = WebInputEvent::GestureScrollUpdate; - gesture_.data.scrollUpdate.deltaY = - -40; // -Y means scroll down - i.e. in the +Y direction. - EXPECT_CALL(mock_input_handler_, - ScrollBy(testing::_, - testing::Property(&gfx::Vector2dF::y, testing::Gt(0)))) - .WillOnce(testing::Return(scroll_result_did_not_scroll_)); - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - // Mark the event as handled if scroll happens. - expected_disposition_ = InputHandlerProxy::DID_HANDLE; - VERIFY_AND_RESET_MOCKS(); - - gesture_.type = WebInputEvent::GestureScrollUpdate; - gesture_.data.scrollUpdate.deltaY = - -40; // -Y means scroll down - i.e. in the +Y direction. - EXPECT_CALL(mock_input_handler_, - ScrollBy(testing::_, - testing::Property(&gfx::Vector2dF::y, testing::Gt(0)))) - .WillOnce(testing::Return(scroll_result_did_scroll_)); - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); - - gesture_.type = WebInputEvent::GestureScrollEnd; - gesture_.data.scrollUpdate.deltaY = 0; - EXPECT_CALL(mock_input_handler_, ScrollEnd()); - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); -} - -TEST_P(InputHandlerProxyTest, GestureScrollOnMainThread) { - // We should send all events to the widget for this gesture. - expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE; - VERIFY_AND_RESET_MOCKS(); - - EXPECT_CALL(mock_input_handler_, ScrollBegin(::testing::_, ::testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_ON_MAIN_THREAD)); - - gesture_.type = WebInputEvent::GestureScrollBegin; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); - - gesture_.type = WebInputEvent::GestureScrollUpdate; - gesture_.data.scrollUpdate.deltaY = 40; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); - - gesture_.type = WebInputEvent::GestureScrollEnd; - gesture_.data.scrollUpdate.deltaY = 0; - EXPECT_CALL(mock_input_handler_, ScrollEnd()).WillOnce(testing::Return()); - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); -} - -TEST_P(InputHandlerProxyTest, GestureScrollIgnored) { - // We shouldn't handle the GestureScrollBegin. - // Instead, we should get a DROP_EVENT result, indicating - // that we could determine that there's nothing that could scroll or otherwise - // react to this gesture sequence and thus we should drop the whole gesture - // sequence on the floor, except for the ScrollEnd. - expected_disposition_ = InputHandlerProxy::DROP_EVENT; - VERIFY_AND_RESET_MOCKS(); - - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_IGNORED)); - - gesture_.type = WebInputEvent::GestureScrollBegin; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE; - gesture_.type = WebInputEvent::GestureScrollEnd; - EXPECT_CALL(mock_input_handler_, ScrollEnd()).WillOnce(testing::Return()); - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); -} - -TEST_P(InputHandlerProxyTest, GestureScrollBeginThatTargetViewport) { - // We shouldn't send any events to the widget for this gesture. - expected_disposition_ = InputHandlerProxy::DID_HANDLE; - VERIFY_AND_RESET_MOCKS(); - - EXPECT_CALL(mock_input_handler_, RootScrollBegin(testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); - - gesture_.type = WebInputEvent::GestureScrollBegin; - gesture_.data.scrollBegin.targetViewport = true; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); -} - -TEST_P(InputHandlerProxyTest, GesturePinch) { - // We shouldn't send any events to the widget for this gesture. - expected_disposition_ = InputHandlerProxy::DID_HANDLE; - VERIFY_AND_RESET_MOCKS(); - - gesture_.type = WebInputEvent::GesturePinchBegin; - EXPECT_CALL(mock_input_handler_, HaveWheelEventHandlersAt(testing::_)) - .WillOnce(testing::Return(false)); - EXPECT_CALL(mock_input_handler_, PinchGestureBegin()); - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); - - gesture_.type = WebInputEvent::GesturePinchUpdate; - gesture_.data.pinchUpdate.scale = 1.5; - gesture_.x = 7; - gesture_.y = 13; - EXPECT_CALL(mock_input_handler_, PinchGestureUpdate(1.5, gfx::Point(7, 13))); - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); - - gesture_.type = WebInputEvent::GesturePinchUpdate; - gesture_.data.pinchUpdate.scale = 0.5; - gesture_.data.pinchUpdate.zoomDisabled = true; - gesture_.x = 9; - gesture_.y = 6; - EXPECT_EQ(InputHandlerProxy::DROP_EVENT, - input_handler_->HandleInputEvent(gesture_)); - gesture_.data.pinchUpdate.zoomDisabled = false; - - VERIFY_AND_RESET_MOCKS(); - - gesture_.type = WebInputEvent::GesturePinchUpdate; - gesture_.data.pinchUpdate.scale = 0.5; - gesture_.x = 9; - gesture_.y = 6; - EXPECT_CALL(mock_input_handler_, PinchGestureUpdate(.5, gfx::Point(9, 6))); - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); - - gesture_.type = WebInputEvent::GesturePinchEnd; - EXPECT_CALL(mock_input_handler_, PinchGestureEnd()); - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); -} - -TEST_P(InputHandlerProxyTest, GesturePinchWithWheelHandler) { - // We will send the synthetic wheel event to the widget. - expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE; - VERIFY_AND_RESET_MOCKS(); - - gesture_.type = WebInputEvent::GesturePinchBegin; - EXPECT_CALL(mock_input_handler_, HaveWheelEventHandlersAt(testing::_)) - .WillOnce(testing::Return(true)); - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); - - gesture_.type = WebInputEvent::GesturePinchUpdate; - gesture_.data.pinchUpdate.scale = 1.5; - gesture_.x = 7; - gesture_.y = 13; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); - - gesture_.type = WebInputEvent::GesturePinchUpdate; - gesture_.data.pinchUpdate.scale = 0.5; - gesture_.x = 9; - gesture_.y = 6; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); - - gesture_.type = WebInputEvent::GesturePinchEnd; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); -} - -TEST_P(InputHandlerProxyTest, GesturePinchAfterScrollOnMainThread) { - // Scrolls will start by being sent to the main thread. - expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE; - VERIFY_AND_RESET_MOCKS(); - - EXPECT_CALL(mock_input_handler_, ScrollBegin(::testing::_, ::testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_ON_MAIN_THREAD)); - - gesture_.type = WebInputEvent::GestureScrollBegin; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); - - gesture_.type = WebInputEvent::GestureScrollUpdate; - gesture_.data.scrollUpdate.deltaY = 40; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - // However, after the pinch gesture starts, they should go to the impl - // thread. - expected_disposition_ = InputHandlerProxy::DID_HANDLE; - VERIFY_AND_RESET_MOCKS(); - - gesture_.type = WebInputEvent::GesturePinchBegin; - EXPECT_CALL(mock_input_handler_, HaveWheelEventHandlersAt(testing::_)) - .WillOnce(testing::Return(false)); - EXPECT_CALL(mock_input_handler_, PinchGestureBegin()); - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); - - gesture_.type = WebInputEvent::GesturePinchUpdate; - gesture_.data.pinchUpdate.scale = 1.5; - gesture_.x = 7; - gesture_.y = 13; - EXPECT_CALL(mock_input_handler_, PinchGestureUpdate(1.5, gfx::Point(7, 13))); - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); - - gesture_.type = WebInputEvent::GestureScrollUpdate; - gesture_.data.scrollUpdate.deltaY = - -40; // -Y means scroll down - i.e. in the +Y direction. - EXPECT_CALL(mock_input_handler_, - ScrollBy(testing::_, - testing::Property(&gfx::Vector2dF::y, testing::Gt(0)))) - .WillOnce(testing::Return(scroll_result_did_scroll_)); - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); - - gesture_.type = WebInputEvent::GesturePinchUpdate; - gesture_.data.pinchUpdate.scale = 0.5; - gesture_.x = 9; - gesture_.y = 6; - EXPECT_CALL(mock_input_handler_, PinchGestureUpdate(.5, gfx::Point(9, 6))); - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); - - gesture_.type = WebInputEvent::GesturePinchEnd; - EXPECT_CALL(mock_input_handler_, PinchGestureEnd()); - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - // After the pinch gesture ends, they should go to back to the main - // thread. - expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE; - VERIFY_AND_RESET_MOCKS(); - - gesture_.type = WebInputEvent::GestureScrollEnd; - gesture_.data.scrollUpdate.deltaY = 0; - EXPECT_CALL(mock_input_handler_, ScrollEnd()) - .WillOnce(testing::Return()); - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); -} - -TEST_P(InputHandlerProxyTest, GestureFlingStartedTouchpad) { - // We shouldn't send any events to the widget for this gesture. - expected_disposition_ = InputHandlerProxy::DID_HANDLE; - VERIFY_AND_RESET_MOCKS(); - - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); - EXPECT_CALL(mock_input_handler_, ScrollEnd()); - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - - gesture_.type = WebInputEvent::GestureFlingStart; - gesture_.data.flingStart.velocityX = 10; - gesture_.sourceDevice = blink::WebGestureDeviceTouchpad; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); - - // Verify that a GestureFlingCancel during an animation cancels it. - gesture_.type = WebInputEvent::GestureFlingCancel; - gesture_.sourceDevice = blink::WebGestureDeviceTouchpad; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); -} - -TEST_P(InputHandlerProxyTest, GestureFlingOnMainThreadTouchpad) { - // We should send all events to the widget for this gesture. - expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE; - VERIFY_AND_RESET_MOCKS(); - - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_ON_MAIN_THREAD)); - - gesture_.type = WebInputEvent::GestureFlingStart; - gesture_.sourceDevice = blink::WebGestureDeviceTouchpad; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - // Since we returned ScrollStatusOnMainThread from scrollBegin, ensure the - // input handler knows it's scrolling off the impl thread - ASSERT_FALSE(input_handler_->gesture_scroll_on_impl_thread_for_testing()); - - VERIFY_AND_RESET_MOCKS(); - - // Even if we didn't start a fling ourselves, we still need to send the cancel - // event to the widget. - gesture_.type = WebInputEvent::GestureFlingCancel; - gesture_.sourceDevice = blink::WebGestureDeviceTouchpad; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); -} - -TEST_P(InputHandlerProxyTest, GestureFlingIgnoredTouchpad) { - expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE; - VERIFY_AND_RESET_MOCKS(); - - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_IGNORED)); - - gesture_.type = WebInputEvent::GestureFlingStart; - gesture_.sourceDevice = blink::WebGestureDeviceTouchpad; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - expected_disposition_ = InputHandlerProxy::DROP_EVENT; - VERIFY_AND_RESET_MOCKS(); - - // Since the previous fling was ignored, we should also be dropping the next - // fling_cancel. - gesture_.type = WebInputEvent::GestureFlingCancel; - gesture_.sourceDevice = blink::WebGestureDeviceTouchpad; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); -} - -TEST_P(InputHandlerProxyTest, GestureFlingAnimatesTouchpad) { - // We shouldn't send any events to the widget for this gesture. - expected_disposition_ = InputHandlerProxy::DID_HANDLE; - VERIFY_AND_RESET_MOCKS(); - - // On the fling start, we should schedule an animation but not actually start - // scrolling. - gesture_.type = WebInputEvent::GestureFlingStart; - WebFloatPoint fling_delta = WebFloatPoint(1000, 0); - WebPoint fling_point = WebPoint(7, 13); - WebPoint fling_global_point = WebPoint(17, 23); - // Note that for trackpad, wheel events with the Control modifier are - // special (reserved for zoom), so don't set that here. - int modifiers = WebInputEvent::ShiftKey | WebInputEvent::AltKey; - gesture_ = CreateFling(blink::WebGestureDeviceTouchpad, - fling_delta, - fling_point, - fling_global_point, - modifiers); - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); - EXPECT_CALL(mock_input_handler_, ScrollEnd()); - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); - // The first animate call should let us pick up an animation start time, but - // we shouldn't actually move anywhere just yet. The first frame after the - // fling start will typically include the last scroll from the gesture that - // lead to the scroll (either wheel or gesture scroll), so there should be no - // visible hitch. - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .Times(0); - base::TimeTicks time = base::TimeTicks() + base::TimeDelta::FromSeconds(10); - Animate(time); - - VERIFY_AND_RESET_MOCKS(); - - // The second call should start scrolling in the -X direction. - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); - EXPECT_CALL(mock_input_handler_, - ScrollBy(testing::_, - testing::Property(&gfx::Vector2dF::x, testing::Lt(0)))) - .WillOnce(testing::Return(scroll_result_did_scroll_)); - EXPECT_CALL(mock_input_handler_, ScrollEnd()); - time += base::TimeDelta::FromMilliseconds(100); - Animate(time); - - VERIFY_AND_RESET_MOCKS(); - - // Let's say on the third call we hit a non-scrollable region. We should abort - // the fling and not scroll. - // We also should pass the current fling parameters out to the client so the - // rest of the fling can be - // transferred to the main thread. - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_ON_MAIN_THREAD)); - EXPECT_CALL(mock_input_handler_, ScrollBy(testing::_, testing::_)).Times(0); - EXPECT_CALL(mock_input_handler_, ScrollEnd()).Times(0); - // Expected wheel fling animation parameters: - // *) fling_delta and fling_point should match the original GestureFlingStart - // event - // *) startTime should be 10 to match the time parameter of the first - // Animate() call after the GestureFlingStart - // *) cumulativeScroll depends on the curve, but since we've animated in the - // -X direction the X value should be < 0 - EXPECT_CALL( - mock_client_, - TransferActiveWheelFlingAnimation(testing::AllOf( - testing::Field(&WebActiveWheelFlingParameters::delta, - testing::Eq(fling_delta)), - testing::Field(&WebActiveWheelFlingParameters::point, - testing::Eq(fling_point)), - testing::Field(&WebActiveWheelFlingParameters::globalPoint, - testing::Eq(fling_global_point)), - testing::Field(&WebActiveWheelFlingParameters::modifiers, - testing::Eq(modifiers)), - testing::Field(&WebActiveWheelFlingParameters::startTime, - testing::Eq(10)), - testing::Field(&WebActiveWheelFlingParameters::cumulativeScroll, - testing::Field(&WebSize::width, testing::Gt(0)))))); - time += base::TimeDelta::FromMilliseconds(100); - Animate(time); - - VERIFY_AND_RESET_MOCKS(); - - // Since we've aborted the fling, the next animation should be a no-op and - // should not result in another - // frame being requested. - EXPECT_SET_NEEDS_ANIMATE_INPUT(0); - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .Times(0); - time += base::TimeDelta::FromMilliseconds(100); - Animate(time); - - // Since we've transferred the fling to the main thread, we need to pass the - // next GestureFlingCancel to the main - // thread as well. - expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE; - gesture_.type = WebInputEvent::GestureFlingCancel; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); -} - -TEST_P(InputHandlerProxyTest, GestureFlingTransferResetsTouchpad) { - // We shouldn't send any events to the widget for this gesture. - expected_disposition_ = InputHandlerProxy::DID_HANDLE; - VERIFY_AND_RESET_MOCKS(); - - // Start a gesture fling in the -X direction with zero Y movement. - WebFloatPoint fling_delta = WebFloatPoint(1000, 0); - WebPoint fling_point = WebPoint(7, 13); - WebPoint fling_global_point = WebPoint(17, 23); - // Note that for trackpad, wheel events with the Control modifier are - // special (reserved for zoom), so don't set that here. - int modifiers = WebInputEvent::ShiftKey | WebInputEvent::AltKey; - gesture_ = CreateFling(blink::WebGestureDeviceTouchpad, - fling_delta, - fling_point, - fling_global_point, - modifiers); - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); - EXPECT_CALL(mock_input_handler_, ScrollEnd()); - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); - - // Start the fling animation at time 10. This shouldn't actually scroll, just - // establish a start time. - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .Times(0); - base::TimeTicks time = base::TimeTicks() + base::TimeDelta::FromSeconds(10); - Animate(time); - - VERIFY_AND_RESET_MOCKS(); - - // The second call should start scrolling in the -X direction. - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); - EXPECT_CALL(mock_input_handler_, - ScrollBy(testing::_, - testing::Property(&gfx::Vector2dF::x, testing::Lt(0)))) - .WillOnce(testing::Return(scroll_result_did_scroll_)); - EXPECT_CALL(mock_input_handler_, ScrollEnd()); - time += base::TimeDelta::FromMilliseconds(100); - Animate(time); - - VERIFY_AND_RESET_MOCKS(); - - // Let's say on the third call we hit a non-scrollable region. We should abort - // the fling and not scroll. - // We also should pass the current fling parameters out to the client so the - // rest of the fling can be - // transferred to the main thread. - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_ON_MAIN_THREAD)); - EXPECT_CALL(mock_input_handler_, ScrollBy(testing::_, testing::_)).Times(0); - EXPECT_CALL(mock_input_handler_, ScrollEnd()).Times(0); - - // Expected wheel fling animation parameters: - // *) fling_delta and fling_point should match the original GestureFlingStart - // event - // *) startTime should be 10 to match the time parameter of the first - // Animate() call after the GestureFlingStart - // *) cumulativeScroll depends on the curve, but since we've animated in the - // -X direction the X value should be < 0 - EXPECT_CALL( - mock_client_, - TransferActiveWheelFlingAnimation(testing::AllOf( - testing::Field(&WebActiveWheelFlingParameters::delta, - testing::Eq(fling_delta)), - testing::Field(&WebActiveWheelFlingParameters::point, - testing::Eq(fling_point)), - testing::Field(&WebActiveWheelFlingParameters::globalPoint, - testing::Eq(fling_global_point)), - testing::Field(&WebActiveWheelFlingParameters::modifiers, - testing::Eq(modifiers)), - testing::Field(&WebActiveWheelFlingParameters::startTime, - testing::Eq(10)), - testing::Field(&WebActiveWheelFlingParameters::cumulativeScroll, - testing::Field(&WebSize::width, testing::Gt(0)))))); - time += base::TimeDelta::FromMilliseconds(100); - Animate(time); - - VERIFY_AND_RESET_MOCKS(); - - // Since we've aborted the fling, the next animation should be a no-op and - // should not result in another - // frame being requested. - EXPECT_SET_NEEDS_ANIMATE_INPUT(0); - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .Times(0); - time += base::TimeDelta::FromMilliseconds(100); - Animate(time); - - VERIFY_AND_RESET_MOCKS(); - - // Since we've transferred the fling to the main thread, we need to pass the - // next GestureFlingCancel to the main - // thread as well. - expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE; - gesture_.type = WebInputEvent::GestureFlingCancel; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); - input_handler_->MainThreadHasStoppedFlinging(); - - // Start a second gesture fling, this time in the +Y direction with no X. - fling_delta = WebFloatPoint(0, -1000); - fling_point = WebPoint(95, 87); - fling_global_point = WebPoint(32, 71); - modifiers = WebInputEvent::AltKey; - gesture_ = CreateFling(blink::WebGestureDeviceTouchpad, - fling_delta, - fling_point, - fling_global_point, - modifiers); - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); - EXPECT_CALL(mock_input_handler_, ScrollEnd()); - expected_disposition_ = InputHandlerProxy::DID_HANDLE; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); - - // Start the second fling animation at time 30. - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .Times(0); - time = base::TimeTicks() + base::TimeDelta::FromSeconds(30); - Animate(time); - - VERIFY_AND_RESET_MOCKS(); - - // Tick the second fling once normally. - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); - EXPECT_CALL(mock_input_handler_, - ScrollBy(testing::_, - testing::Property(&gfx::Vector2dF::y, testing::Gt(0)))) - .WillOnce(testing::Return(scroll_result_did_scroll_)); - EXPECT_CALL(mock_input_handler_, ScrollEnd()); - time += base::TimeDelta::FromMilliseconds(100); - Animate(time); - - VERIFY_AND_RESET_MOCKS(); - - // Then abort the second fling. - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_ON_MAIN_THREAD)); - EXPECT_CALL(mock_input_handler_, ScrollBy(testing::_, testing::_)).Times(0); - EXPECT_CALL(mock_input_handler_, ScrollEnd()).Times(0); - - // We should get parameters from the second fling, nothing from the first - // fling should "leak". - EXPECT_CALL( - mock_client_, - TransferActiveWheelFlingAnimation(testing::AllOf( - testing::Field(&WebActiveWheelFlingParameters::delta, - testing::Eq(fling_delta)), - testing::Field(&WebActiveWheelFlingParameters::point, - testing::Eq(fling_point)), - testing::Field(&WebActiveWheelFlingParameters::globalPoint, - testing::Eq(fling_global_point)), - testing::Field(&WebActiveWheelFlingParameters::modifiers, - testing::Eq(modifiers)), - testing::Field(&WebActiveWheelFlingParameters::startTime, - testing::Eq(30)), - testing::Field(&WebActiveWheelFlingParameters::cumulativeScroll, - testing::Field(&WebSize::height, testing::Lt(0)))))); - time += base::TimeDelta::FromMilliseconds(100); - Animate(time); - - VERIFY_AND_RESET_MOCKS(); -} - -TEST_P(InputHandlerProxyTest, GestureFlingStartedTouchscreen) { - // We shouldn't send any events to the widget for this gesture. - expected_disposition_ = InputHandlerProxy::DID_HANDLE; - VERIFY_AND_RESET_MOCKS(); - - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); - gesture_.type = WebInputEvent::GestureScrollBegin; - gesture_.sourceDevice = blink::WebGestureDeviceTouchscreen; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); - - EXPECT_CALL(mock_input_handler_, FlingScrollBegin()) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - - gesture_.type = WebInputEvent::GestureFlingStart; - gesture_.data.flingStart.velocityX = 10; - gesture_.sourceDevice = blink::WebGestureDeviceTouchscreen; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); - - EXPECT_CALL(mock_input_handler_, ScrollEnd()); - - // Verify that a GestureFlingCancel during an animation cancels it. - gesture_.type = WebInputEvent::GestureFlingCancel; - gesture_.sourceDevice = blink::WebGestureDeviceTouchscreen; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); -} - -TEST_P(InputHandlerProxyTest, GestureFlingOnMainThreadTouchscreen) { - // We should send all events to the widget for this gesture. - expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE; - VERIFY_AND_RESET_MOCKS(); - - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_ON_MAIN_THREAD)); - - gesture_.type = WebInputEvent::GestureScrollBegin; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); - - EXPECT_CALL(mock_input_handler_, FlingScrollBegin()).Times(0); - - gesture_.type = WebInputEvent::GestureFlingStart; - gesture_.sourceDevice = blink::WebGestureDeviceTouchscreen; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); - - // Even if we didn't start a fling ourselves, we still need to send the cancel - // event to the widget. - gesture_.type = WebInputEvent::GestureFlingCancel; - gesture_.sourceDevice = blink::WebGestureDeviceTouchscreen; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); -} - -TEST_P(InputHandlerProxyTest, GestureFlingIgnoredTouchscreen) { - expected_disposition_ = InputHandlerProxy::DID_HANDLE; - VERIFY_AND_RESET_MOCKS(); - - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); - - gesture_.type = WebInputEvent::GestureScrollBegin; - gesture_.sourceDevice = blink::WebGestureDeviceTouchscreen; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - expected_disposition_ = InputHandlerProxy::DROP_EVENT; - VERIFY_AND_RESET_MOCKS(); - - // Flings ignored by the InputHandler should be dropped, signalling the end - // of the touch scroll sequence. - EXPECT_CALL(mock_input_handler_, FlingScrollBegin()) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_IGNORED)); - - gesture_.type = WebInputEvent::GestureFlingStart; - gesture_.sourceDevice = blink::WebGestureDeviceTouchscreen; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); - - // Subsequent scrolls should behave normally, even without an intervening - // GestureFlingCancel, as the original GestureFlingStart was dropped. - expected_disposition_ = InputHandlerProxy::DID_HANDLE; - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); - gesture_.type = WebInputEvent::GestureScrollBegin; - gesture_.sourceDevice = blink::WebGestureDeviceTouchscreen; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); -} - -TEST_P(InputHandlerProxyTest, GestureFlingAnimatesTouchscreen) { - // We shouldn't send any events to the widget for this gesture. - expected_disposition_ = InputHandlerProxy::DID_HANDLE; - VERIFY_AND_RESET_MOCKS(); - - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); - - gesture_.type = WebInputEvent::GestureScrollBegin; - gesture_.sourceDevice = blink::WebGestureDeviceTouchscreen; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); - - // On the fling start, we should schedule an animation but not actually start - // scrolling. - WebFloatPoint fling_delta = WebFloatPoint(100, 0); - WebPoint fling_point = WebPoint(7, 13); - WebPoint fling_global_point = WebPoint(17, 23); - // Note that for touchscreen the control modifier is not special. - int modifiers = WebInputEvent::ControlKey; - gesture_ = CreateFling(blink::WebGestureDeviceTouchscreen, - fling_delta, - fling_point, - fling_global_point, - modifiers); - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - EXPECT_CALL(mock_input_handler_, FlingScrollBegin()) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); - // The first animate call should let us pick up an animation start time, but - // we shouldn't actually move anywhere just yet. The first frame after the - // fling start will typically include the last scroll from the gesture that - // lead to the scroll (either wheel or gesture scroll), so there should be no - // visible hitch. - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - base::TimeTicks time = base::TimeTicks() + base::TimeDelta::FromSeconds(10); - Animate(time); - - VERIFY_AND_RESET_MOCKS(); - - // The second call should start scrolling in the -X direction. - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - EXPECT_CALL(mock_input_handler_, - ScrollBy(testing::_, - testing::Property(&gfx::Vector2dF::x, testing::Lt(0)))) - .WillOnce(testing::Return(scroll_result_did_scroll_)); - time += base::TimeDelta::FromMilliseconds(100); - Animate(time); - - VERIFY_AND_RESET_MOCKS(); - - EXPECT_CALL(mock_input_handler_, ScrollEnd()); - gesture_.type = WebInputEvent::GestureFlingCancel; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); -} - -TEST_P(InputHandlerProxyTest, GestureFlingWithValidTimestamp) { - // We shouldn't send any events to the widget for this gesture. - expected_disposition_ = InputHandlerProxy::DID_HANDLE; - VERIFY_AND_RESET_MOCKS(); - - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); - - gesture_.type = WebInputEvent::GestureScrollBegin; - gesture_.sourceDevice = blink::WebGestureDeviceTouchscreen; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); - - // On the fling start, we should schedule an animation but not actually start - // scrolling. - base::TimeDelta dt = base::TimeDelta::FromMilliseconds(10); - base::TimeTicks time = base::TimeTicks() + dt; - WebFloatPoint fling_delta = WebFloatPoint(100, 0); - WebPoint fling_point = WebPoint(7, 13); - WebPoint fling_global_point = WebPoint(17, 23); - int modifiers = WebInputEvent::ControlKey; - gesture_ = CreateFling(time, - blink::WebGestureDeviceTouchscreen, - fling_delta, - fling_point, - fling_global_point, - modifiers); - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - EXPECT_CALL(mock_input_handler_, FlingScrollBegin()) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); - // With a valid time stamp, the first animate call should skip start time - // initialization and immediately begin scroll update production. This reduces - // the likelihood of a hitch between the scroll preceding the fling and - // the first scroll generated by the fling. - // Scrolling should start in the -X direction. - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - EXPECT_CALL(mock_input_handler_, - ScrollBy(testing::_, - testing::Property(&gfx::Vector2dF::x, testing::Lt(0)))) - .WillOnce(testing::Return(scroll_result_did_scroll_)); - time += dt; - Animate(time); - - VERIFY_AND_RESET_MOCKS(); - - EXPECT_CALL(mock_input_handler_, ScrollEnd()); - gesture_.type = WebInputEvent::GestureFlingCancel; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); -} - -TEST_P(InputHandlerProxyTest, GestureFlingWithInvalidTimestamp) { - // We shouldn't send any events to the widget for this gesture. - expected_disposition_ = InputHandlerProxy::DID_HANDLE; - VERIFY_AND_RESET_MOCKS(); - - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); - - gesture_.type = WebInputEvent::GestureScrollBegin; - gesture_.sourceDevice = blink::WebGestureDeviceTouchscreen; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); - - // On the fling start, we should schedule an animation but not actually start - // scrolling. - base::TimeDelta start_time_offset = base::TimeDelta::FromMilliseconds(10); - gesture_.type = WebInputEvent::GestureFlingStart; - WebFloatPoint fling_delta = WebFloatPoint(100, 0); - WebPoint fling_point = WebPoint(7, 13); - WebPoint fling_global_point = WebPoint(17, 23); - int modifiers = WebInputEvent::ControlKey; - gesture_.timeStampSeconds = start_time_offset.InSecondsF(); - gesture_.data.flingStart.velocityX = fling_delta.x; - gesture_.data.flingStart.velocityY = fling_delta.y; - gesture_.sourceDevice = blink::WebGestureDeviceTouchscreen; - gesture_.x = fling_point.x; - gesture_.y = fling_point.y; - gesture_.globalX = fling_global_point.x; - gesture_.globalY = fling_global_point.y; - gesture_.modifiers = modifiers; - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - EXPECT_CALL(mock_input_handler_, FlingScrollBegin()) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); - // Event though a time stamp was provided for the fling event, it will be - // ignored as its too far in the past relative to the first animate call's - // timestamp. - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - base::TimeTicks time = - base::TimeTicks() + start_time_offset + base::TimeDelta::FromSeconds(1); - Animate(time); - - VERIFY_AND_RESET_MOCKS(); - - // Further animation ticks should update the fling as usual. - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - EXPECT_CALL(mock_input_handler_, - ScrollBy(testing::_, - testing::Property(&gfx::Vector2dF::x, testing::Lt(0)))) - .WillOnce(testing::Return(scroll_result_did_scroll_)); - time += base::TimeDelta::FromMilliseconds(10); - Animate(time); - - VERIFY_AND_RESET_MOCKS(); - - EXPECT_CALL(mock_input_handler_, ScrollEnd()); - gesture_.type = WebInputEvent::GestureFlingCancel; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); -} - -TEST_P(InputHandlerProxyTest, GestureScrollOnImplThreadFlagClearedAfterFling) { - // We shouldn't send any events to the widget for this gesture. - expected_disposition_ = InputHandlerProxy::DID_HANDLE; - VERIFY_AND_RESET_MOCKS(); - - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); - - gesture_.type = WebInputEvent::GestureScrollBegin; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - // After sending a GestureScrollBegin, the member variable - // |gesture_scroll_on_impl_thread_| should be true. - EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing()); - - expected_disposition_ = InputHandlerProxy::DID_HANDLE; - VERIFY_AND_RESET_MOCKS(); - - // On the fling start, we should schedule an animation but not actually start - // scrolling. - WebFloatPoint fling_delta = WebFloatPoint(100, 0); - WebPoint fling_point = WebPoint(7, 13); - WebPoint fling_global_point = WebPoint(17, 23); - int modifiers = WebInputEvent::ControlKey | WebInputEvent::AltKey; - gesture_ = CreateFling(blink::WebGestureDeviceTouchscreen, - fling_delta, - fling_point, - fling_global_point, - modifiers); - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - EXPECT_CALL(mock_input_handler_, FlingScrollBegin()) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - // |gesture_scroll_on_impl_thread_| should still be true after - // a GestureFlingStart is sent. - EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing()); - - VERIFY_AND_RESET_MOCKS(); - // The first animate call should let us pick up an animation start time, but - // we shouldn't actually move anywhere just yet. The first frame after the - // fling start will typically include the last scroll from the gesture that - // lead to the scroll (either wheel or gesture scroll), so there should be no - // visible hitch. - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - base::TimeTicks time = base::TimeTicks() + base::TimeDelta::FromSeconds(10); - Animate(time); - - VERIFY_AND_RESET_MOCKS(); - - // The second call should start scrolling in the -X direction. - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - EXPECT_CALL(mock_input_handler_, - ScrollBy(testing::_, - testing::Property(&gfx::Vector2dF::x, testing::Lt(0)))) - .WillOnce(testing::Return(scroll_result_did_scroll_)); - time += base::TimeDelta::FromMilliseconds(100); - Animate(time); - - VERIFY_AND_RESET_MOCKS(); - - EXPECT_CALL(mock_input_handler_, ScrollEnd()); - gesture_.type = WebInputEvent::GestureFlingCancel; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - // |gesture_scroll_on_impl_thread_| should be false once - // the fling has finished (note no GestureScrollEnd has been sent). - EXPECT_TRUE(!input_handler_->gesture_scroll_on_impl_thread_for_testing()); - - VERIFY_AND_RESET_MOCKS(); -} - -TEST_P(InputHandlerProxyTest, - BeginScrollWhenGestureScrollOnImplThreadFlagIsSet) { - // We shouldn't send any events to the widget for this gesture. - expected_disposition_ = InputHandlerProxy::DID_HANDLE; - VERIFY_AND_RESET_MOCKS(); - - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); - - gesture_.type = WebInputEvent::GestureScrollBegin; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - // After sending a GestureScrollBegin, the member variable - // |gesture_scroll_on_impl_thread_| should be true. - EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing()); - - expected_disposition_ = InputHandlerProxy::DID_HANDLE; - VERIFY_AND_RESET_MOCKS(); - - // On the fling start, we should schedule an animation but not actually start - // scrolling. - WebFloatPoint fling_delta = WebFloatPoint(100, 0); - WebPoint fling_point = WebPoint(7, 13); - WebPoint fling_global_point = WebPoint(17, 23); - int modifiers = WebInputEvent::ControlKey | WebInputEvent::AltKey; - gesture_ = CreateFling(blink::WebGestureDeviceTouchscreen, fling_delta, - fling_point, fling_global_point, modifiers); - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - EXPECT_CALL(mock_input_handler_, FlingScrollBegin()) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - // |gesture_scroll_on_impl_thread_| should still be true after - // a GestureFlingStart is sent. - EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing()); - - VERIFY_AND_RESET_MOCKS(); - - // gesture_scroll_on_impl_thread_ is still true when this scroll begins. As a - // result, this scroll begin will cancel the previous fling. - EXPECT_CALL(mock_input_handler_, ScrollEnd()); - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); - - gesture_.type = WebInputEvent::GestureScrollBegin; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - // After sending a GestureScrollBegin, the member variable - // |gesture_scroll_on_impl_thread_| should be true. - EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing()); - VERIFY_AND_RESET_MOCKS(); -} - -TEST_P(InputHandlerProxyTest, GestureFlingStopsAtContentEdge) { - // We shouldn't send any events to the widget for this gesture. - expected_disposition_ = InputHandlerProxy::DID_HANDLE; - VERIFY_AND_RESET_MOCKS(); - - // On the fling start, we should schedule an animation but not actually start - // scrolling. - gesture_.type = WebInputEvent::GestureFlingStart; - WebFloatPoint fling_delta = WebFloatPoint(100, 100); - gesture_.data.flingStart.velocityX = fling_delta.x; - gesture_.data.flingStart.velocityY = fling_delta.y; - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); - EXPECT_CALL(mock_input_handler_, ScrollEnd()); - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - VERIFY_AND_RESET_MOCKS(); - - // The first animate doesn't cause any scrolling. - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - base::TimeTicks time = base::TimeTicks() + base::TimeDelta::FromSeconds(10); - Animate(time); - VERIFY_AND_RESET_MOCKS(); - - // The second animate starts scrolling in the positive X and Y directions. - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); - EXPECT_CALL(mock_input_handler_, - ScrollBy(testing::_, - testing::Property(&gfx::Vector2dF::y, testing::Lt(0)))) - .WillOnce(testing::Return(scroll_result_did_scroll_)); - EXPECT_CALL(mock_input_handler_, ScrollEnd()); - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - time += base::TimeDelta::FromMilliseconds(100); - Animate(time); - VERIFY_AND_RESET_MOCKS(); - - // The third animate overscrolls in the positive Y direction but scrolls - // somewhat. - cc::InputHandlerScrollResult overscroll; - overscroll.did_scroll = true; - overscroll.did_overscroll_root = true; - overscroll.accumulated_root_overscroll = gfx::Vector2dF(0, 100); - overscroll.unused_scroll_delta = gfx::Vector2dF(0, 10); - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); - EXPECT_CALL(mock_input_handler_, - ScrollBy(testing::_, - testing::Property(&gfx::Vector2dF::y, testing::Lt(0)))) - .WillOnce(testing::Return(overscroll)); - EXPECT_CALL( - mock_client_, - DidOverscroll(testing::AllOf( - testing::Field( - &DidOverscrollParams::accumulated_overscroll, - testing::Eq(overscroll.accumulated_root_overscroll)), - testing::Field( - &DidOverscrollParams::latest_overscroll_delta, - testing::Eq(overscroll.unused_scroll_delta)), - testing::Field( - &DidOverscrollParams::current_fling_velocity, - testing::Property(&gfx::Vector2dF::y, testing::Lt(0)))))); - EXPECT_CALL(mock_input_handler_, ScrollEnd()); - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - time += base::TimeDelta::FromMilliseconds(100); - Animate(time); - VERIFY_AND_RESET_MOCKS(); - - // The next call to animate will no longer scroll vertically. - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); - EXPECT_CALL(mock_input_handler_, - ScrollBy(testing::_, - testing::Property(&gfx::Vector2dF::y, testing::Eq(0)))) - .WillOnce(testing::Return(scroll_result_did_scroll_)); - EXPECT_CALL(mock_input_handler_, ScrollEnd()); - time += base::TimeDelta::FromMilliseconds(100); - Animate(time); - VERIFY_AND_RESET_MOCKS(); -} - -TEST_P(InputHandlerProxyTest, GestureFlingNotCancelledBySmallTimeDelta) { - // We shouldn't send any events to the widget for this gesture. - expected_disposition_ = InputHandlerProxy::DID_HANDLE; - VERIFY_AND_RESET_MOCKS(); - - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); - - gesture_.type = WebInputEvent::GestureScrollBegin; - gesture_.sourceDevice = blink::WebGestureDeviceTouchscreen; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); - - // On the fling start, we should schedule an animation but not actually start - // scrolling. - base::TimeDelta dt = base::TimeDelta::FromMilliseconds(10); - base::TimeTicks time = base::TimeTicks() + dt; - WebFloatPoint fling_delta = WebFloatPoint(100, 0); - WebPoint fling_point = WebPoint(7, 13); - WebPoint fling_global_point = WebPoint(17, 23); - int modifiers = WebInputEvent::ControlKey; - gesture_ = CreateFling(time, - blink::WebGestureDeviceTouchscreen, - fling_delta, - fling_point, - fling_global_point, - modifiers); - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - EXPECT_CALL(mock_input_handler_, FlingScrollBegin()) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); - // With an animation timestamp equivalent to the starting timestamp, the - // animation will simply be rescheduled. - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - Animate(time); - - VERIFY_AND_RESET_MOCKS(); - EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing()); - - // A small time delta should not stop the fling, even if the client - // reports no scrolling. - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - EXPECT_CALL(mock_input_handler_, - ScrollBy(testing::_, - testing::Property(&gfx::Vector2dF::x, testing::Lt(0)))) - .WillOnce(testing::Return(scroll_result_did_not_scroll_)); - time += base::TimeDelta::FromMicroseconds(5); - Animate(time); - - VERIFY_AND_RESET_MOCKS(); - EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing()); - - // A time delta of zero should not stop the fling, and neither should it - // trigger scrolling on the client. - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - Animate(time); - - VERIFY_AND_RESET_MOCKS(); - EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing()); - - // Lack of movement on the client, with a non-trivial scroll delta, should - // terminate the fling. - EXPECT_CALL(mock_input_handler_, ScrollEnd()); - EXPECT_CALL(mock_input_handler_, - ScrollBy(testing::_, - testing::Property(&gfx::Vector2dF::x, testing::Lt(1)))) - .WillOnce(testing::Return(scroll_result_did_not_scroll_)); - time += base::TimeDelta::FromMilliseconds(100); - Animate(time); - - VERIFY_AND_RESET_MOCKS(); - EXPECT_FALSE(input_handler_->gesture_scroll_on_impl_thread_for_testing()); -} - -TEST_P(InputHandlerProxyTest, GestureFlingCancelledAfterBothAxesStopScrolling) { - cc::InputHandlerScrollResult overscroll; - overscroll.did_scroll = true; - overscroll.did_overscroll_root = true; - - // We shouldn't send any events to the widget for this gesture. - expected_disposition_ = InputHandlerProxy::DID_HANDLE; - VERIFY_AND_RESET_MOCKS(); - - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); - gesture_.type = WebInputEvent::GestureScrollBegin; - gesture_.sourceDevice = blink::WebGestureDeviceTouchscreen; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - VERIFY_AND_RESET_MOCKS(); - - // On the fling start, we should schedule an animation but not actually start - // scrolling. - gesture_.type = WebInputEvent::GestureFlingStart; - WebFloatPoint fling_delta = WebFloatPoint(100, 100); - gesture_.data.flingStart.velocityX = fling_delta.x; - gesture_.data.flingStart.velocityY = fling_delta.y; - EXPECT_CALL(mock_input_handler_, FlingScrollBegin()) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - VERIFY_AND_RESET_MOCKS(); - - // The first animate doesn't cause any scrolling. - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - base::TimeTicks time = base::TimeTicks() + base::TimeDelta::FromSeconds(10); - Animate(time); - VERIFY_AND_RESET_MOCKS(); - - // The second animate starts scrolling in the positive X and Y directions. - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - EXPECT_CALL(mock_input_handler_, - ScrollBy(testing::_, - testing::Property(&gfx::Vector2dF::y, testing::Lt(0)))) - .WillOnce(testing::Return(scroll_result_did_scroll_)); - time += base::TimeDelta::FromMilliseconds(10); - Animate(time); - VERIFY_AND_RESET_MOCKS(); - - // The third animate hits the bottom content edge. - overscroll.accumulated_root_overscroll = gfx::Vector2dF(0, 100); - overscroll.unused_scroll_delta = gfx::Vector2dF(0, 100); - EXPECT_CALL(mock_input_handler_, - ScrollBy(testing::_, - testing::Property(&gfx::Vector2dF::y, testing::Lt(0)))) - .WillOnce(testing::Return(overscroll)); - EXPECT_CALL( - mock_client_, - DidOverscroll(testing::AllOf( - testing::Field( - &DidOverscrollParams::accumulated_overscroll, - testing::Eq(overscroll.accumulated_root_overscroll)), - testing::Field( - &DidOverscrollParams::latest_overscroll_delta, - testing::Eq(overscroll.unused_scroll_delta)), - testing::Field( - &DidOverscrollParams::current_fling_velocity, - testing::Property(&gfx::Vector2dF::y, testing::Lt(0)))))); - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - time += base::TimeDelta::FromMilliseconds(10); - Animate(time); - VERIFY_AND_RESET_MOCKS(); - - // The next call to animate will no longer scroll vertically. - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - EXPECT_CALL(mock_input_handler_, - ScrollBy(testing::_, - testing::Property(&gfx::Vector2dF::y, testing::Eq(0)))) - .WillOnce(testing::Return(scroll_result_did_scroll_)); - time += base::TimeDelta::FromMilliseconds(10); - Animate(time); - VERIFY_AND_RESET_MOCKS(); - - // The next call will hit the right edge. - overscroll.accumulated_root_overscroll = gfx::Vector2dF(100, 100); - overscroll.unused_scroll_delta = gfx::Vector2dF(100, 0); - EXPECT_CALL(mock_input_handler_, - ScrollBy(testing::_, - testing::Property(&gfx::Vector2dF::x, testing::Lt(0)))) - .WillOnce(testing::Return(overscroll)); - EXPECT_CALL( - mock_client_, - DidOverscroll(testing::AllOf( - testing::Field( - &DidOverscrollParams::accumulated_overscroll, - testing::Eq(overscroll.accumulated_root_overscroll)), - testing::Field( - &DidOverscrollParams::latest_overscroll_delta, - testing::Eq(overscroll.unused_scroll_delta)), - testing::Field( - &DidOverscrollParams::current_fling_velocity, - testing::Property(&gfx::Vector2dF::x, testing::Lt(0)))))); - EXPECT_CALL(mock_input_handler_, ScrollEnd()); - time += base::TimeDelta::FromMilliseconds(10); - Animate(time); - VERIFY_AND_RESET_MOCKS(); - - // The next call to animate will no longer scroll horizontally or vertically, - // and the fling should be cancelled. - EXPECT_SET_NEEDS_ANIMATE_INPUT(0); - EXPECT_CALL(mock_input_handler_, ScrollBy(testing::_, testing::_)).Times(0); - time += base::TimeDelta::FromMilliseconds(10); - Animate(time); - VERIFY_AND_RESET_MOCKS(); - EXPECT_FALSE(input_handler_->gesture_scroll_on_impl_thread_for_testing()); -} - -TEST_P(InputHandlerProxyTest, MultiTouchPointHitTestNegative) { - // None of the three touch points fall in the touch region. So the event - // should be dropped. - expected_disposition_ = InputHandlerProxy::DROP_EVENT; - VERIFY_AND_RESET_MOCKS(); - - EXPECT_CALL(mock_input_handler_, - DoTouchEventsBlockScrollAt( - testing::Property(&gfx::Point::x, testing::Gt(0)))) - .WillOnce(testing::Return(false)); - EXPECT_CALL(mock_input_handler_, - DoTouchEventsBlockScrollAt( - testing::Property(&gfx::Point::x, testing::Lt(0)))) - .WillOnce(testing::Return(false)); - - WebTouchEvent touch; - touch.type = WebInputEvent::TouchStart; - - touch.touchesLength = 3; - touch.touches[0] = CreateWebTouchPoint(WebTouchPoint::StateStationary, 0, 0); - touch.touches[1] = CreateWebTouchPoint(WebTouchPoint::StatePressed, 10, 10); - touch.touches[2] = CreateWebTouchPoint(WebTouchPoint::StatePressed, -10, 10); - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(touch)); - - VERIFY_AND_RESET_MOCKS(); -} - -TEST_P(InputHandlerProxyTest, MultiTouchPointHitTestPositive) { - // One of the touch points is on a touch-region. So the event should be sent - // to the main thread. - expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE; - VERIFY_AND_RESET_MOCKS(); - - EXPECT_CALL(mock_input_handler_, - DoTouchEventsBlockScrollAt( - testing::Property(&gfx::Point::x, testing::Eq(0)))) - .WillOnce(testing::Return(false)); - EXPECT_CALL(mock_input_handler_, - DoTouchEventsBlockScrollAt( - testing::Property(&gfx::Point::x, testing::Gt(0)))) - .WillOnce(testing::Return(true)); - // Since the second touch point hits a touch-region, there should be no - // hit-testing for the third touch point. - - WebTouchEvent touch; - touch.type = WebInputEvent::TouchStart; - - touch.touchesLength = 3; - touch.touches[0] = CreateWebTouchPoint(WebTouchPoint::StatePressed, 0, 0); - touch.touches[1] = CreateWebTouchPoint(WebTouchPoint::StatePressed, 10, 10); - touch.touches[2] = CreateWebTouchPoint(WebTouchPoint::StatePressed, -10, 10); - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(touch)); - - VERIFY_AND_RESET_MOCKS(); -} - -TEST_P(InputHandlerProxyTest, GestureFlingCancelledByKeyboardEvent) { - // We shouldn't send any events to the widget for this gesture. - expected_disposition_ = InputHandlerProxy::DID_HANDLE; - VERIFY_AND_RESET_MOCKS(); - - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); - gesture_.type = WebInputEvent::GestureScrollBegin; - gesture_.sourceDevice = blink::WebGestureDeviceTouchscreen; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing()); - VERIFY_AND_RESET_MOCKS(); - - // Keyboard events received during a scroll should have no effect. - WebKeyboardEvent key_event; - key_event.type = WebInputEvent::KeyDown; - EXPECT_EQ(InputHandlerProxy::DID_NOT_HANDLE, - input_handler_->HandleInputEvent(key_event)); - EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing()); - VERIFY_AND_RESET_MOCKS(); - - // On the fling start, animation should be scheduled, but no scrolling occurs. - gesture_.type = WebInputEvent::GestureFlingStart; - WebFloatPoint fling_delta = WebFloatPoint(100, 100); - gesture_.data.flingStart.velocityX = fling_delta.x; - gesture_.data.flingStart.velocityY = fling_delta.y; - EXPECT_CALL(mock_input_handler_, FlingScrollBegin()) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing()); - VERIFY_AND_RESET_MOCKS(); - - // Keyboard events received during a fling should cancel the active fling. - EXPECT_CALL(mock_input_handler_, ScrollEnd()); - EXPECT_EQ(InputHandlerProxy::DID_NOT_HANDLE, - input_handler_->HandleInputEvent(key_event)); - EXPECT_FALSE(input_handler_->gesture_scroll_on_impl_thread_for_testing()); - VERIFY_AND_RESET_MOCKS(); - - // The call to animate should have no effect, as the fling was cancelled. - base::TimeTicks time = base::TimeTicks() + base::TimeDelta::FromSeconds(10); - Animate(time); - VERIFY_AND_RESET_MOCKS(); - - // A fling cancel should be dropped, as there is nothing to cancel. - gesture_.type = WebInputEvent::GestureFlingCancel; - EXPECT_EQ(InputHandlerProxy::DROP_EVENT, - input_handler_->HandleInputEvent(gesture_)); - EXPECT_FALSE(input_handler_->gesture_scroll_on_impl_thread_for_testing()); -} - -TEST_P(InputHandlerProxyTest, GestureFlingWithNegativeTimeDelta) { - // We shouldn't send any events to the widget for this gesture. - expected_disposition_ = InputHandlerProxy::DID_HANDLE; - VERIFY_AND_RESET_MOCKS(); - - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); - - gesture_.type = WebInputEvent::GestureScrollBegin; - gesture_.sourceDevice = blink::WebGestureDeviceTouchscreen; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); - - // On the fling start, we should schedule an animation but not actually start - // scrolling. - base::TimeDelta dt = base::TimeDelta::FromMilliseconds(10); - base::TimeTicks time = base::TimeTicks() + dt; - WebFloatPoint fling_delta = WebFloatPoint(100, 0); - WebPoint fling_point = WebPoint(7, 13); - WebPoint fling_global_point = WebPoint(17, 23); - int modifiers = WebInputEvent::ControlKey; - gesture_ = CreateFling(time, - blink::WebGestureDeviceTouchscreen, - fling_delta, - fling_point, - fling_global_point, - modifiers); - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - EXPECT_CALL(mock_input_handler_, FlingScrollBegin()) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); - - // If we get a negative time delta, that is, the Animation tick time happens - // before the fling's start time then we should *not* try scrolling and - // instead reset the fling start time. - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - EXPECT_CALL(mock_input_handler_, - ScrollBy(testing::_, - testing::_)).Times(0); - time -= base::TimeDelta::FromMilliseconds(5); - Animate(time); - - VERIFY_AND_RESET_MOCKS(); - - // The first call should have reset the start time so subsequent calls should - // generate scroll events. - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - EXPECT_CALL(mock_input_handler_, - ScrollBy(testing::_, - testing::Property(&gfx::Vector2dF::x, testing::Lt(0)))) - .WillOnce(testing::Return(scroll_result_did_scroll_)); - - Animate(time + base::TimeDelta::FromMilliseconds(1)); - - VERIFY_AND_RESET_MOCKS(); - - EXPECT_CALL(mock_input_handler_, ScrollEnd()); - gesture_.type = WebInputEvent::GestureFlingCancel; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); -} - -TEST_P(InputHandlerProxyTest, FlingBoost) { - base::TimeDelta dt = base::TimeDelta::FromMilliseconds(10); - base::TimeTicks time = base::TimeTicks() + dt; - base::TimeTicks last_animate_time = time; - WebFloatPoint fling_delta = WebFloatPoint(1000, 0); - WebPoint fling_point = WebPoint(7, 13); - StartFling( - time, blink::WebGestureDeviceTouchscreen, fling_delta, fling_point); - - // Now cancel the fling. The fling cancellation should be deferred to allow - // fling boosting events to arrive. - time += dt; - CancelFling(time); - - // The GestureScrollBegin should be swallowed by the fling if it hits the same - // scrolling layer. - EXPECT_CALL(mock_input_handler_, - IsCurrentlyScrollingLayerAt(testing::_, testing::_)) - .WillOnce(testing::Return(true)); - - time += dt; - gesture_.timeStampSeconds = InSecondsF(time); - gesture_.type = WebInputEvent::GestureScrollBegin; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); - - // Animate calls within the deferred cancellation window should continue. - time += dt; - float expected_delta = - (time - last_animate_time).InSecondsF() * -fling_delta.x; - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - EXPECT_CALL(mock_input_handler_, - ScrollBy(testing::_, - testing::Property(&gfx::Vector2dF::x, - testing::Eq(expected_delta)))) - .WillOnce(testing::Return(scroll_result_did_scroll_)); - Animate(time); - last_animate_time = time; - - VERIFY_AND_RESET_MOCKS(); - - // GestureScrollUpdates in the same direction and at sufficient speed should - // be swallowed by the fling. - time += dt; - gesture_.timeStampSeconds = InSecondsF(time); - gesture_.type = WebInputEvent::GestureScrollUpdate; - gesture_.data.scrollUpdate.deltaX = fling_delta.x; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); - - // Animate calls within the deferred cancellation window should continue. - time += dt; - expected_delta = (time - last_animate_time).InSecondsF() * -fling_delta.x; - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - EXPECT_CALL(mock_input_handler_, - ScrollBy(testing::_, - testing::Property(&gfx::Vector2dF::x, - testing::Eq(expected_delta)))) - .WillOnce(testing::Return(scroll_result_did_scroll_)); - Animate(time); - last_animate_time = time; - - VERIFY_AND_RESET_MOCKS(); - - // GestureFlingStart in the same direction and at sufficient speed should - // boost the active fling. - - gesture_ = CreateFling(time, - blink::WebGestureDeviceTouchscreen, - fling_delta, - fling_point, - fling_point, - 0); - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - VERIFY_AND_RESET_MOCKS(); - - time += dt; - // Note we get *2x* as much delta because 2 flings have combined. - expected_delta = 2 * (time - last_animate_time).InSecondsF() * -fling_delta.x; - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - EXPECT_CALL(mock_input_handler_, - ScrollBy(testing::_, - testing::Property(&gfx::Vector2dF::x, - testing::Eq(expected_delta)))) - .WillOnce(testing::Return(scroll_result_did_scroll_)); - Animate(time); - last_animate_time = time; - - VERIFY_AND_RESET_MOCKS(); - - // Repeated GestureFlingStarts should accumulate. - - CancelFling(time); - gesture_ = CreateFling(time, - blink::WebGestureDeviceTouchscreen, - fling_delta, - fling_point, - fling_point, - 0); - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - VERIFY_AND_RESET_MOCKS(); - - time += dt; - // Note we get *3x* as much delta because 3 flings have combined. - expected_delta = 3 * (time - last_animate_time).InSecondsF() * -fling_delta.x; - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - EXPECT_CALL(mock_input_handler_, - ScrollBy(testing::_, - testing::Property(&gfx::Vector2dF::x, - testing::Eq(expected_delta)))) - .WillOnce(testing::Return(scroll_result_did_scroll_)); - Animate(time); - last_animate_time = time; - - VERIFY_AND_RESET_MOCKS(); - - // GestureFlingCancel should terminate the fling if no boosting gestures are - // received within the timeout window. - - time += dt; - gesture_.timeStampSeconds = InSecondsF(time); - gesture_.type = WebInputEvent::GestureFlingCancel; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); - - time += base::TimeDelta::FromMilliseconds(100); - EXPECT_CALL(mock_input_handler_, ScrollEnd()); - Animate(time); - - VERIFY_AND_RESET_MOCKS(); -} - -TEST_P(InputHandlerProxyTest, NoFlingBoostIfScrollTargetsDifferentLayer) { - base::TimeDelta dt = base::TimeDelta::FromMilliseconds(10); - base::TimeTicks time = base::TimeTicks() + dt; - WebFloatPoint fling_delta = WebFloatPoint(1000, 0); - WebPoint fling_point = WebPoint(7, 13); - StartFling( - time, blink::WebGestureDeviceTouchscreen, fling_delta, fling_point); - - // Cancel the fling. The fling cancellation should be deferred to allow - // fling boosting events to arrive. - time += dt; - CancelFling(time); - - // If the GestureScrollBegin targets a different layer, the fling should be - // cancelled and the scroll should be handled as usual. - EXPECT_CALL(mock_input_handler_, - IsCurrentlyScrollingLayerAt(testing::_, testing::_)) - .WillOnce(testing::Return(false)); - EXPECT_CALL(mock_input_handler_, ScrollEnd()); - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); - - time += dt; - gesture_.timeStampSeconds = InSecondsF(time); - gesture_.type = WebInputEvent::GestureScrollBegin; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); -} - -TEST_P(InputHandlerProxyTest, NoFlingBoostIfScrollDelayed) { - base::TimeDelta dt = base::TimeDelta::FromMilliseconds(10); - base::TimeTicks time = base::TimeTicks() + dt; - WebFloatPoint fling_delta = WebFloatPoint(1000, 0); - WebPoint fling_point = WebPoint(7, 13); - StartFling( - time, blink::WebGestureDeviceTouchscreen, fling_delta, fling_point); - - // Cancel the fling. The fling cancellation should be deferred to allow - // fling boosting events to arrive. - time += dt; - CancelFling(time); - - // The GestureScrollBegin should be swallowed by the fling if it hits the same - // scrolling layer. - EXPECT_CALL(mock_input_handler_, - IsCurrentlyScrollingLayerAt(testing::_, testing::_)) - .WillOnce(testing::Return(true)); - - time += dt; - gesture_.timeStampSeconds = InSecondsF(time); - gesture_.type = WebInputEvent::GestureScrollBegin; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); - - // If no GestureScrollUpdate or GestureFlingStart is received within the - // timeout window, the fling should be cancelled and scrolling should resume. - time += base::TimeDelta::FromMilliseconds(100); - EXPECT_CALL(mock_input_handler_, ScrollEnd()); - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); - Animate(time); - - VERIFY_AND_RESET_MOCKS(); -} - -TEST_P(InputHandlerProxyTest, NoFlingBoostIfNotAnimated) { - base::TimeDelta dt = base::TimeDelta::FromMilliseconds(10); - base::TimeTicks time = base::TimeTicks() + dt; - WebFloatPoint fling_delta = WebFloatPoint(1000, 0); - WebPoint fling_point = WebPoint(7, 13); - StartFling( - time, blink::WebGestureDeviceTouchscreen, fling_delta, fling_point); - - // Animate fling once. - time += dt; - EXPECT_CALL(mock_input_handler_, ScrollBy(testing::_, testing::_)) - .WillOnce(testing::Return(scroll_result_did_scroll_)); - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - Animate(time); - - // Cancel the fling after long delay of no animate. The fling cancellation - // should be deferred to allow fling boosting events to arrive. - time += base::TimeDelta::FromMilliseconds(100); - CancelFling(time); - - // The GestureScrollBegin should be swallowed by the fling if it hits the same - // scrolling layer. - EXPECT_CALL(mock_input_handler_, - IsCurrentlyScrollingLayerAt(testing::_, testing::_)) - .WillOnce(testing::Return(true)); - - time += dt; - gesture_.timeStampSeconds = InSecondsF(time); - gesture_.type = WebInputEvent::GestureScrollBegin; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); - - // Should exit scroll bosting on GestureScrollUpdate due to long delay - // since last animate. Cancel old fling and start new scroll. - gesture_.type = WebInputEvent::GestureScrollUpdate; - gesture_.data.scrollUpdate.deltaY = -40; - EXPECT_CALL(mock_input_handler_, ScrollEnd()); - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); - EXPECT_CALL(mock_input_handler_, ScrollBy(testing::_, testing::_)) - .WillOnce(testing::Return(scroll_result_did_scroll_)); - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); -} - -TEST_P(InputHandlerProxyTest, NoFlingBoostIfFlingInDifferentDirection) { - base::TimeDelta dt = base::TimeDelta::FromMilliseconds(10); - base::TimeTicks time = base::TimeTicks() + dt; - WebFloatPoint fling_delta = WebFloatPoint(1000, 0); - WebPoint fling_point = WebPoint(7, 13); - StartFling( - time, blink::WebGestureDeviceTouchscreen, fling_delta, fling_point); - - // Cancel the fling. The fling cancellation should be deferred to allow - // fling boosting events to arrive. - time += dt; - CancelFling(time); - - // If the new fling is orthogonal to the existing fling, no boosting should - // take place, with the new fling replacing the old. - WebFloatPoint orthogonal_fling_delta = - WebFloatPoint(fling_delta.y, -fling_delta.x); - gesture_ = CreateFling(time, - blink::WebGestureDeviceTouchscreen, - orthogonal_fling_delta, - fling_point, - fling_point, - 0); - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); - - // Note that the new fling delta uses the orthogonal, unboosted fling - // velocity. - time += dt; - float expected_delta = dt.InSecondsF() * -orthogonal_fling_delta.y; - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - EXPECT_CALL(mock_input_handler_, - ScrollBy(testing::_, - testing::Property(&gfx::Vector2dF::y, - testing::Eq(expected_delta)))) - .WillOnce(testing::Return(scroll_result_did_scroll_)); - Animate(time); - - VERIFY_AND_RESET_MOCKS(); -} - -TEST_P(InputHandlerProxyTest, NoFlingBoostIfScrollInDifferentDirection) { - base::TimeDelta dt = base::TimeDelta::FromMilliseconds(10); - base::TimeTicks time = base::TimeTicks() + dt; - WebFloatPoint fling_delta = WebFloatPoint(1000, 0); - WebPoint fling_point = WebPoint(7, 13); - StartFling( - time, blink::WebGestureDeviceTouchscreen, fling_delta, fling_point); - - // Cancel the fling. The fling cancellation should be deferred to allow - // fling boosting events to arrive. - time += dt; - CancelFling(time); - - // The GestureScrollBegin should be swallowed by the fling if it hits the same - // scrolling layer. - EXPECT_CALL(mock_input_handler_, - IsCurrentlyScrollingLayerAt(testing::_, testing::_)) - .WillOnce(testing::Return(true)); - - time += dt; - gesture_.timeStampSeconds = InSecondsF(time); - gesture_.type = WebInputEvent::GestureScrollBegin; - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); - - // If the GestureScrollUpdate is in a different direction than the fling, - // the fling should be cancelled and scrolling should resume. - time += dt; - gesture_.timeStampSeconds = InSecondsF(time); - gesture_.type = WebInputEvent::GestureScrollUpdate; - gesture_.data.scrollUpdate.deltaX = -fling_delta.x; - EXPECT_CALL(mock_input_handler_, ScrollEnd()); - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); - EXPECT_CALL(mock_input_handler_, - ScrollBy(testing::_, - testing::Property(&gfx::Vector2dF::x, - testing::Eq(fling_delta.x)))) - .WillOnce(testing::Return(scroll_result_did_scroll_)); - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); -} - -TEST_P(InputHandlerProxyTest, NoFlingBoostIfFlingTooSlow) { - base::TimeDelta dt = base::TimeDelta::FromMilliseconds(10); - base::TimeTicks time = base::TimeTicks() + dt; - WebFloatPoint fling_delta = WebFloatPoint(1000, 0); - WebPoint fling_point = WebPoint(7, 13); - StartFling( - time, blink::WebGestureDeviceTouchscreen, fling_delta, fling_point); - - // Cancel the fling. The fling cancellation should be deferred to allow - // fling boosting events to arrive. - time += dt; - CancelFling(time); - - // If the new fling is too slow, no boosting should take place, with the new - // fling replacing the old. - WebFloatPoint small_fling_delta = WebFloatPoint(100, 0); - gesture_ = CreateFling(time, - blink::WebGestureDeviceTouchscreen, - small_fling_delta, - fling_point, - fling_point, - 0); - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); - - // Note that the new fling delta uses the *slow*, unboosted fling velocity. - time += dt; - float expected_delta = dt.InSecondsF() * -small_fling_delta.x; - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - EXPECT_CALL(mock_input_handler_, - ScrollBy(testing::_, - testing::Property(&gfx::Vector2dF::x, - testing::Eq(expected_delta)))) - .WillOnce(testing::Return(scroll_result_did_scroll_)); - Animate(time); - - VERIFY_AND_RESET_MOCKS(); -} - -TEST_P(InputHandlerProxyTest, NoFlingBoostIfPreventBoostingFlagIsSet) { - base::TimeDelta dt = base::TimeDelta::FromMilliseconds(10); - base::TimeTicks time = base::TimeTicks() + dt; - WebFloatPoint fling_delta = WebFloatPoint(1000, 0); - WebPoint fling_point = WebPoint(7, 13); - - StartFling( - time, blink::WebGestureDeviceTouchscreen, fling_delta, fling_point); - - EXPECT_CALL(mock_input_handler_, ScrollEnd()); - - // Cancel the fling. The fling cancellation should not be deferred because of - // prevent boosting flag set. - gesture_.data.flingCancel.preventBoosting = true; - time += dt; - CancelFling(time); - - // VERIFY_AND_RESET_MOCKS already called by CancelFling -} - -TEST_P(InputHandlerProxyTest, FlingBoostTerminatedDuringScrollSequence) { - base::TimeDelta dt = base::TimeDelta::FromMilliseconds(10); - base::TimeTicks time = base::TimeTicks() + dt; - base::TimeTicks last_animate_time = time; - WebFloatPoint fling_delta = WebFloatPoint(1000, 0); - WebPoint fling_point = WebPoint(7, 13); - StartFling( - time, blink::WebGestureDeviceTouchscreen, fling_delta, fling_point); - - // Now cancel the fling. The fling cancellation should be deferred to allow - // fling boosting events to arrive. - time += dt; - CancelFling(time); - - // The GestureScrollBegin should be swallowed by the fling. - time += dt; - gesture_.timeStampSeconds = InSecondsF(time); - gesture_.type = WebInputEvent::GestureScrollBegin; - EXPECT_CALL(mock_input_handler_, - IsCurrentlyScrollingLayerAt(testing::_, testing::_)) - .WillOnce(testing::Return(true)); - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); - - // Now animate the fling to completion (in this case, the fling should - // terminate because the input handler reports a failed scroll). As the fling - // was cancelled during an active scroll sequence, a synthetic - // GestureScrollBegin should be processed, resuming the scroll. - time += dt; - float expected_delta = - (time - last_animate_time).InSecondsF() * -fling_delta.x; - EXPECT_CALL(mock_input_handler_, - ScrollBy(testing::_, - testing::Property(&gfx::Vector2dF::x, - testing::Eq(expected_delta)))) - .WillOnce(testing::Return(scroll_result_did_not_scroll_)); - EXPECT_CALL(mock_input_handler_, ScrollEnd()); - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); - Animate(time); - - VERIFY_AND_RESET_MOCKS(); - - // Subsequent GestureScrollUpdates after the cancelled, boosted fling should - // cause scrolling as usual. - time += dt; - expected_delta = 7.3f; - gesture_.timeStampSeconds = InSecondsF(time); - gesture_.type = WebInputEvent::GestureScrollUpdate; - gesture_.data.scrollUpdate.deltaX = -expected_delta; - EXPECT_CALL(mock_input_handler_, - ScrollBy(testing::_, - testing::Property(&gfx::Vector2dF::x, - testing::Eq(expected_delta)))) - .WillOnce(testing::Return(scroll_result_did_scroll_)); - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); - - // GestureScrollEnd should terminate the resumed scroll properly. - time += dt; - gesture_.timeStampSeconds = InSecondsF(time); - gesture_.type = WebInputEvent::GestureScrollEnd; - EXPECT_CALL(mock_input_handler_, ScrollEnd()); - EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_)); - - VERIFY_AND_RESET_MOCKS(); -} - -TEST_P(InputHandlerProxyTest, DidReceiveInputEvent_ForFling) { - testing::StrictMock<MockInputHandlerProxyClientWithDidAnimateForInput> - mock_client; - input_handler_.reset( - new content::InputHandlerProxy(&mock_input_handler_, &mock_client)); - if (install_synchronous_handler_) { - EXPECT_CALL(mock_input_handler_, RequestUpdateForSynchronousInputHandler()) - .Times(1); - input_handler_->SetOnlySynchronouslyAnimateRootFlings( - &mock_synchronous_input_handler_); - } - mock_input_handler_.set_is_scrolling_root(synchronous_root_scroll_); - - gesture_.type = WebInputEvent::GestureFlingStart; - WebFloatPoint fling_delta = WebFloatPoint(100, 100); - gesture_.data.flingStart.velocityX = fling_delta.x; - gesture_.data.flingStart.velocityY = fling_delta.y; - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_)) - .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED)); - EXPECT_CALL(mock_input_handler_, ScrollEnd()); - EXPECT_EQ(InputHandlerProxy::DID_HANDLE, - input_handler_->HandleInputEvent(gesture_)); - VERIFY_AND_RESET_MOCKS(); - - EXPECT_SET_NEEDS_ANIMATE_INPUT(1); - EXPECT_CALL(mock_client, DidAnimateForInput()); - base::TimeTicks time = base::TimeTicks() + base::TimeDelta::FromSeconds(10); - Animate(time); - - VERIFY_AND_RESET_MOCKS(); -} - -TEST(SynchronousInputHandlerProxyTest, StartupShutdown) { - testing::StrictMock<MockInputHandler> mock_input_handler; - testing::StrictMock<MockInputHandlerProxyClient> mock_client; - testing::StrictMock<MockSynchronousInputHandler> - mock_synchronous_input_handler; - content::InputHandlerProxy proxy(&mock_input_handler, &mock_client); - - // When adding a SynchronousInputHandler, immediately request an - // UpdateRootLayerStateForSynchronousInputHandler() call. - EXPECT_CALL(mock_input_handler, RequestUpdateForSynchronousInputHandler()) - .Times(1); - proxy.SetOnlySynchronouslyAnimateRootFlings(&mock_synchronous_input_handler); - - testing::Mock::VerifyAndClearExpectations(&mock_input_handler); - testing::Mock::VerifyAndClearExpectations(&mock_client); - testing::Mock::VerifyAndClearExpectations(&mock_synchronous_input_handler); - - EXPECT_CALL(mock_input_handler, RequestUpdateForSynchronousInputHandler()) - .Times(0); - proxy.SetOnlySynchronouslyAnimateRootFlings(nullptr); - - testing::Mock::VerifyAndClearExpectations(&mock_input_handler); - testing::Mock::VerifyAndClearExpectations(&mock_client); - testing::Mock::VerifyAndClearExpectations(&mock_synchronous_input_handler); -} - -TEST(SynchronousInputHandlerProxyTest, UpdateRootLayerState) { - testing::NiceMock<MockInputHandler> mock_input_handler; - testing::StrictMock<MockInputHandlerProxyClient> mock_client; - testing::StrictMock<MockSynchronousInputHandler> - mock_synchronous_input_handler; - content::InputHandlerProxy proxy(&mock_input_handler, &mock_client); - - proxy.SetOnlySynchronouslyAnimateRootFlings(&mock_synchronous_input_handler); - - // When adding a SynchronousInputHandler, immediately request an - // UpdateRootLayerStateForSynchronousInputHandler() call. - EXPECT_CALL( - mock_synchronous_input_handler, - UpdateRootLayerState(gfx::ScrollOffset(1, 2), gfx::ScrollOffset(3, 4), - gfx::SizeF(5, 6), 7, 8, 9)) - .Times(1); - proxy.UpdateRootLayerStateForSynchronousInputHandler( - gfx::ScrollOffset(1, 2), gfx::ScrollOffset(3, 4), gfx::SizeF(5, 6), 7, 8, - 9); - - testing::Mock::VerifyAndClearExpectations(&mock_input_handler); - testing::Mock::VerifyAndClearExpectations(&mock_client); - testing::Mock::VerifyAndClearExpectations(&mock_synchronous_input_handler); -} - -TEST(SynchronousInputHandlerProxyTest, SetOffset) { - testing::NiceMock<MockInputHandler> mock_input_handler; - testing::StrictMock<MockInputHandlerProxyClient> mock_client; - testing::StrictMock<MockSynchronousInputHandler> - mock_synchronous_input_handler; - content::InputHandlerProxy proxy(&mock_input_handler, &mock_client); - - proxy.SetOnlySynchronouslyAnimateRootFlings(&mock_synchronous_input_handler); - - EXPECT_CALL(mock_input_handler, SetSynchronousInputHandlerRootScrollOffset( - gfx::ScrollOffset(5, 6))); - proxy.SynchronouslySetRootScrollOffset(gfx::ScrollOffset(5, 6)); - - testing::Mock::VerifyAndClearExpectations(&mock_input_handler); - testing::Mock::VerifyAndClearExpectations(&mock_client); - testing::Mock::VerifyAndClearExpectations(&mock_synchronous_input_handler); -} - -INSTANTIATE_TEST_CASE_P(AnimateInput, - InputHandlerProxyTest, - testing::ValuesIn(test_types)); -} // namespace test -} // namespace content diff --git a/content/renderer/input/input_handler_wrapper.cc b/content/renderer/input/input_handler_wrapper.cc index d5596bd..5995d99 100644 --- a/content/renderer/input/input_handler_wrapper.cc +++ b/content/renderer/input/input_handler_wrapper.cc @@ -4,7 +4,10 @@ #include "content/renderer/input/input_handler_wrapper.h" +#include "base/command_line.h" #include "base/location.h" +#include "content/common/input/did_overscroll_params.h" +#include "content/public/common/content_switches.h" #include "content/renderer/input/input_event_filter.h" #include "content/renderer/input/input_handler_manager.h" #include "third_party/WebKit/public/platform/Platform.h" @@ -23,6 +26,9 @@ InputHandlerWrapper::InputHandlerWrapper( main_task_runner_(main_task_runner), render_view_impl_(render_view_impl) { DCHECK(input_handler); + input_handler_proxy_.set_smooth_scroll_enabled( + base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableSmoothScrolling)); } InputHandlerWrapper::~InputHandlerWrapper() { @@ -47,7 +53,16 @@ blink::WebGestureCurve* InputHandlerWrapper::CreateFlingAnimationCurve( deviceSource, velocity, cumulative_scroll); } -void InputHandlerWrapper::DidOverscroll(const DidOverscrollParams& params) { +void InputHandlerWrapper::DidOverscroll( + const gfx::Vector2dF& accumulated_overscroll, + const gfx::Vector2dF& latest_overscroll_delta, + const gfx::Vector2dF& current_fling_velocity, + const gfx::PointF& causal_event_viewport_point) { + DidOverscrollParams params; + params.accumulated_overscroll = accumulated_overscroll; + params.latest_overscroll_delta = latest_overscroll_delta; + params.current_fling_velocity = current_fling_velocity; + params.causal_event_viewport_point = causal_event_viewport_point; input_handler_manager_->DidOverscroll(routing_id_, params); } diff --git a/content/renderer/input/input_handler_wrapper.h b/content/renderer/input/input_handler_wrapper.h index 5c925d0..69ff5c67 100644 --- a/content/renderer/input/input_handler_wrapper.h +++ b/content/renderer/input/input_handler_wrapper.h @@ -8,13 +8,18 @@ #include "base/memory/weak_ptr.h" #include "base/single_thread_task_runner.h" #include "content/renderer/input/input_handler_manager.h" -#include "content/renderer/input/input_handler_proxy.h" -#include "content/renderer/input/input_handler_proxy_client.h" +#include "ui/events/blink/input_handler_proxy.h" +#include "ui/events/blink/input_handler_proxy_client.h" + +namespace ui { +class InputHandlerProxy; +class InputHandlerProxyClient; +} namespace content { // This class lives on the compositor thread. -class InputHandlerWrapper : public InputHandlerProxyClient { +class InputHandlerWrapper : public ui::InputHandlerProxyClient { public: InputHandlerWrapper( InputHandlerManager* input_handler_manager, @@ -25,7 +30,9 @@ class InputHandlerWrapper : public InputHandlerProxyClient { ~InputHandlerWrapper() override; int routing_id() const { return routing_id_; } - InputHandlerProxy* input_handler_proxy() { return &input_handler_proxy_; } + ui::InputHandlerProxy* input_handler_proxy() { + return &input_handler_proxy_; + } // InputHandlerProxyClient implementation. void WillShutdown() override; @@ -35,14 +42,18 @@ class InputHandlerWrapper : public InputHandlerProxyClient { blink::WebGestureDevice deviceSource, const blink::WebFloatPoint& velocity, const blink::WebSize& cumulativeScroll) override; - void DidOverscroll(const DidOverscrollParams& params) override; + void DidOverscroll( + const gfx::Vector2dF& accumulated_overscroll, + const gfx::Vector2dF& latest_overscroll_delta, + const gfx::Vector2dF& current_fling_velocity, + const gfx::PointF& causal_event_viewport_point) override; void DidStopFlinging() override; void DidAnimateForInput() override; private: InputHandlerManager* input_handler_manager_; int routing_id_; - InputHandlerProxy input_handler_proxy_; + ui::InputHandlerProxy input_handler_proxy_; scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_; // Can only be accessed on the main thread. diff --git a/content/renderer/input/input_scroll_elasticity_controller.cc b/content/renderer/input/input_scroll_elasticity_controller.cc deleted file mode 100644 index 00d078f..0000000 --- a/content/renderer/input/input_scroll_elasticity_controller.cc +++ /dev/null @@ -1,410 +0,0 @@ -// 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 "content/renderer/input/input_scroll_elasticity_controller.h" - -#include <math.h> - -#include "base/bind.h" -#include "cc/input/input_handler.h" -#include "ui/gfx/geometry/vector2d_conversions.h" - -// InputScrollElasticityController is based on -// WebKit/Source/platform/mac/InputScrollElasticityController.mm -/* - * Copyright (C) 2011 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -namespace content { - -namespace { - -const float kScrollVelocityZeroingTimeout = 0.10f; -const float kRubberbandMinimumRequiredDeltaBeforeStretch = 10; - -const float kRubberbandStiffness = 20; -const float kRubberbandAmplitude = 0.31f; -const float kRubberbandPeriod = 1.6f; - -// For these functions which compute the stretch amount, always return a -// rounded value, instead of a floating-point value. The reason for this is -// that Blink's scrolling can become erratic with fractional scroll amounts (in -// particular, if you have a scroll offset of 0.5, Blink will never actually -// bring that value back to 0, which breaks the logic used to determine if a -// layer is pinned in a direction). - -gfx::Vector2d StretchAmountForTimeDelta(const gfx::Vector2dF& initial_position, - const gfx::Vector2dF& initial_velocity, - float elapsed_time) { - // Compute the stretch amount at a given time after some initial conditions. - // Do this by first computing an intermediary position given the initial - // position, initial velocity, time elapsed, and no external forces. Then - // take the intermediary position and damp it towards zero by multiplying - // against a negative exponential. - float amplitude = kRubberbandAmplitude; - float period = kRubberbandPeriod; - float critical_dampening_factor = - expf((-elapsed_time * kRubberbandStiffness) / period); - - return gfx::ToRoundedVector2d(gfx::ScaleVector2d( - initial_position + - gfx::ScaleVector2d(initial_velocity, elapsed_time * amplitude), - critical_dampening_factor)); -} - -gfx::Vector2d StretchAmountForReboundDelta(const gfx::Vector2dF& delta) { - float stiffness = std::max(kRubberbandStiffness, 1.0f); - return gfx::ToRoundedVector2d(gfx::ScaleVector2d(delta, 1.0f / stiffness)); -} - -gfx::Vector2d StretchScrollForceForStretchAmount(const gfx::Vector2dF& delta) { - return gfx::ToRoundedVector2d( - gfx::ScaleVector2d(delta, kRubberbandStiffness)); -} - -} // namespace - -InputScrollElasticityController::InputScrollElasticityController( - cc::ScrollElasticityHelper* helper) - : helper_(helper), - state_(kStateInactive), - momentum_animation_reset_at_next_frame_(false), - weak_factory_(this) { -} - -InputScrollElasticityController::~InputScrollElasticityController() { -} - -base::WeakPtr<InputScrollElasticityController> -InputScrollElasticityController::GetWeakPtr() { - if (helper_) - return weak_factory_.GetWeakPtr(); - return base::WeakPtr<InputScrollElasticityController>(); -} - -void InputScrollElasticityController::ObserveWheelEventAndResult( - const blink::WebMouseWheelEvent& wheel_event, - const cc::InputHandlerScrollResult& scroll_result) { - // We should only get PhaseMayBegin or PhaseBegan events while in the - // Inactive or MomentumAnimated states, but in case we get bad input (e.g, - // abbreviated by tab-switch), always re-set the state to ActiveScrolling - // when those events are received. - if (wheel_event.phase == blink::WebMouseWheelEvent::PhaseMayBegin || - wheel_event.phase == blink::WebMouseWheelEvent::PhaseBegan) { - scroll_velocity = gfx::Vector2dF(); - last_scroll_event_timestamp_ = base::TimeTicks(); - state_ = kStateActiveScroll; - pending_overscroll_delta_ = gfx::Vector2dF(); - return; - } - - gfx::Vector2dF event_delta(-wheel_event.deltaX, -wheel_event.deltaY); - base::TimeTicks event_timestamp = - base::TimeTicks() + - base::TimeDelta::FromSecondsD(wheel_event.timeStampSeconds); - switch (state_) { - case kStateInactive: { - // The PhaseMayBegin and PhaseBegan cases are handled at the top of the - // function. - if (wheel_event.momentumPhase == blink::WebMouseWheelEvent::PhaseBegan) - state_ = kStateMomentumScroll; - break; - } - case kStateActiveScroll: - if (wheel_event.phase == blink::WebMouseWheelEvent::PhaseChanged) { - UpdateVelocity(event_delta, event_timestamp); - Overscroll(event_delta, scroll_result.unused_scroll_delta); - } else if (wheel_event.phase == blink::WebMouseWheelEvent::PhaseEnded || - wheel_event.phase == - blink::WebMouseWheelEvent::PhaseCancelled) { - if (helper_->StretchAmount().IsZero()) { - EnterStateInactive(); - } else { - EnterStateMomentumAnimated(event_timestamp); - } - } - break; - case kStateMomentumScroll: - if (wheel_event.momentumPhase == - blink::WebMouseWheelEvent::PhaseChanged) { - UpdateVelocity(event_delta, event_timestamp); - Overscroll(event_delta, scroll_result.unused_scroll_delta); - if (!helper_->StretchAmount().IsZero()) { - EnterStateMomentumAnimated(event_timestamp); - } - } else if (wheel_event.momentumPhase == - blink::WebMouseWheelEvent::PhaseEnded) { - EnterStateInactive(); - } - case kStateMomentumAnimated: - // The PhaseMayBegin and PhaseBegan cases are handled at the top of the - // function. - break; - } -} - -void InputScrollElasticityController::UpdateVelocity( - const gfx::Vector2dF& event_delta, - const base::TimeTicks& event_timestamp) { - float time_delta = - (event_timestamp - last_scroll_event_timestamp_).InSecondsF(); - if (time_delta < kScrollVelocityZeroingTimeout && time_delta > 0) { - scroll_velocity = gfx::Vector2dF(event_delta.x() / time_delta, - event_delta.y() / time_delta); - } else { - scroll_velocity = gfx::Vector2dF(); - } - last_scroll_event_timestamp_ = event_timestamp; -} - -void InputScrollElasticityController::Overscroll( - const gfx::Vector2dF& input_delta, - const gfx::Vector2dF& overscroll_delta) { - // The effect can be dynamically disabled by setting disallowing user - // scrolling. When disabled, disallow active or momentum overscrolling, but - // allow any current overscroll to animate back. - if (!helper_->IsUserScrollable()) - return; - - gfx::Vector2dF adjusted_overscroll_delta = - pending_overscroll_delta_ + overscroll_delta; - pending_overscroll_delta_ = gfx::Vector2dF(); - - // Only allow one direction to overscroll at a time, and slightly prefer - // scrolling vertically by applying the equal case to delta_y. - if (fabsf(input_delta.y()) >= fabsf(input_delta.x())) - adjusted_overscroll_delta.set_x(0); - else - adjusted_overscroll_delta.set_y(0); - - // Don't allow overscrolling in a direction where scrolling is possible. - if (!PinnedHorizontally(adjusted_overscroll_delta.x())) - adjusted_overscroll_delta.set_x(0); - if (!PinnedVertically(adjusted_overscroll_delta.y())) { - adjusted_overscroll_delta.set_y(0); - } - - // Require a minimum of 10 units of overscroll before starting the rubber-band - // stretch effect, so that small stray motions don't trigger it. If that - // minimum isn't met, save what remains in |pending_overscroll_delta_| for - // the next event. - gfx::Vector2dF old_stretch_amount = helper_->StretchAmount(); - gfx::Vector2dF stretch_scroll_force_delta; - if (old_stretch_amount.x() != 0 || - fabsf(adjusted_overscroll_delta.x()) >= - kRubberbandMinimumRequiredDeltaBeforeStretch) { - stretch_scroll_force_delta.set_x(adjusted_overscroll_delta.x()); - } else { - pending_overscroll_delta_.set_x(adjusted_overscroll_delta.x()); - } - if (old_stretch_amount.y() != 0 || - fabsf(adjusted_overscroll_delta.y()) >= - kRubberbandMinimumRequiredDeltaBeforeStretch) { - stretch_scroll_force_delta.set_y(adjusted_overscroll_delta.y()); - } else { - pending_overscroll_delta_.set_y(adjusted_overscroll_delta.y()); - } - - // Update the stretch amount according to the spring equations. - if (stretch_scroll_force_delta.IsZero()) - return; - stretch_scroll_force_ += stretch_scroll_force_delta; - gfx::Vector2dF new_stretch_amount = - StretchAmountForReboundDelta(stretch_scroll_force_); - helper_->SetStretchAmount(new_stretch_amount); -} - -void InputScrollElasticityController::EnterStateInactive() { - DCHECK_NE(kStateInactive, state_); - DCHECK(helper_->StretchAmount().IsZero()); - state_ = kStateInactive; - stretch_scroll_force_ = gfx::Vector2dF(); -} - -void InputScrollElasticityController::EnterStateMomentumAnimated( - const base::TimeTicks& triggering_event_timestamp) { - DCHECK_NE(kStateMomentumAnimated, state_); - state_ = kStateMomentumAnimated; - - momentum_animation_start_time_ = triggering_event_timestamp; - momentum_animation_initial_stretch_ = helper_->StretchAmount(); - momentum_animation_initial_velocity_ = scroll_velocity; - momentum_animation_reset_at_next_frame_ = false; - - // Similarly to the logic in Overscroll, prefer vertical scrolling to - // horizontal scrolling. - if (fabsf(momentum_animation_initial_velocity_.y()) >= - fabsf(momentum_animation_initial_velocity_.x())) - momentum_animation_initial_velocity_.set_x(0); - - if (!CanScrollHorizontally()) - momentum_animation_initial_velocity_.set_x(0); - - if (!CanScrollVertically()) - momentum_animation_initial_velocity_.set_y(0); - - helper_->RequestAnimate(); -} - -void InputScrollElasticityController::Animate(base::TimeTicks time) { - if (state_ != kStateMomentumAnimated) - return; - - if (momentum_animation_reset_at_next_frame_) { - momentum_animation_start_time_ = time; - momentum_animation_initial_stretch_ = helper_->StretchAmount(); - momentum_animation_initial_velocity_ = gfx::Vector2dF(); - momentum_animation_reset_at_next_frame_ = false; - } - - float time_delta = - std::max((time - momentum_animation_start_time_).InSecondsF(), 0.0); - - gfx::Vector2dF old_stretch_amount = helper_->StretchAmount(); - gfx::Vector2dF new_stretch_amount = StretchAmountForTimeDelta( - momentum_animation_initial_stretch_, momentum_animation_initial_velocity_, - time_delta); - gfx::Vector2dF stretch_delta = new_stretch_amount - old_stretch_amount; - - // If the new stretch amount is near zero, set it directly to zero and enter - // the inactive state. - if (fabs(new_stretch_amount.x()) < 1 && fabs(new_stretch_amount.y()) < 1) { - helper_->SetStretchAmount(gfx::Vector2dF()); - EnterStateInactive(); - return; - } - - // If we are not pinned in the direction of the delta, then the delta is only - // allowed to decrease the existing stretch -- it cannot increase a stretch - // until it is pinned. - if (!PinnedHorizontally(stretch_delta.x())) { - if (stretch_delta.x() > 0 && old_stretch_amount.x() < 0) - stretch_delta.set_x(std::min(stretch_delta.x(), -old_stretch_amount.x())); - else if (stretch_delta.x() < 0 && old_stretch_amount.x() > 0) - stretch_delta.set_x(std::max(stretch_delta.x(), -old_stretch_amount.x())); - else - stretch_delta.set_x(0); - } - if (!PinnedVertically(stretch_delta.y())) { - if (stretch_delta.y() > 0 && old_stretch_amount.y() < 0) - stretch_delta.set_y(std::min(stretch_delta.y(), -old_stretch_amount.y())); - else if (stretch_delta.y() < 0 && old_stretch_amount.y() > 0) - stretch_delta.set_y(std::max(stretch_delta.y(), -old_stretch_amount.y())); - else - stretch_delta.set_y(0); - } - new_stretch_amount = old_stretch_amount + stretch_delta; - - stretch_scroll_force_ = - StretchScrollForceForStretchAmount(new_stretch_amount); - helper_->SetStretchAmount(new_stretch_amount); - helper_->RequestAnimate(); -} - -bool InputScrollElasticityController::PinnedHorizontally( - float direction) const { - gfx::ScrollOffset scroll_offset = helper_->ScrollOffset(); - gfx::ScrollOffset max_scroll_offset = helper_->MaxScrollOffset(); - if (direction < 0) - return scroll_offset.x() <= 0; - if (direction > 0) - return scroll_offset.x() >= max_scroll_offset.x(); - return false; -} - -bool InputScrollElasticityController::PinnedVertically(float direction) const { - gfx::ScrollOffset scroll_offset = helper_->ScrollOffset(); - gfx::ScrollOffset max_scroll_offset = helper_->MaxScrollOffset(); - if (direction < 0) - return scroll_offset.y() <= 0; - if (direction > 0) - return scroll_offset.y() >= max_scroll_offset.y(); - return false; -} - -bool InputScrollElasticityController::CanScrollHorizontally() const { - return helper_->MaxScrollOffset().x() > 0; -} - -bool InputScrollElasticityController::CanScrollVertically() const { - return helper_->MaxScrollOffset().y() > 0; -} - -void InputScrollElasticityController::ReconcileStretchAndScroll() { - gfx::Vector2dF stretch = helper_->StretchAmount(); - if (stretch.IsZero()) - return; - - gfx::ScrollOffset scroll_offset = helper_->ScrollOffset(); - gfx::ScrollOffset max_scroll_offset = helper_->MaxScrollOffset(); - - // Compute stretch_adjustment which will be added to |stretch| and subtracted - // from the |scroll_offset|. - gfx::Vector2dF stretch_adjustment; - if (stretch.x() < 0 && scroll_offset.x() > 0) { - stretch_adjustment.set_x( - std::min(-stretch.x(), static_cast<float>(scroll_offset.x()))); - } - if (stretch.x() > 0 && scroll_offset.x() < max_scroll_offset.x()) { - stretch_adjustment.set_x(std::max( - -stretch.x(), - static_cast<float>(scroll_offset.x() - max_scroll_offset.x()))); - } - if (stretch.y() < 0 && scroll_offset.y() > 0) { - stretch_adjustment.set_y( - std::min(-stretch.y(), static_cast<float>(scroll_offset.y()))); - } - if (stretch.y() > 0 && scroll_offset.y() < max_scroll_offset.y()) { - stretch_adjustment.set_y(std::max( - -stretch.y(), - static_cast<float>(scroll_offset.y() - max_scroll_offset.y()))); - } - - if (stretch_adjustment.IsZero()) - return; - - gfx::Vector2dF new_stretch_amount = stretch + stretch_adjustment; - helper_->ScrollBy(-stretch_adjustment); - helper_->SetStretchAmount(new_stretch_amount); - - // Update the internal state for the active scroll or animation to avoid - // discontinuities. - switch (state_) { - case kStateActiveScroll: - stretch_scroll_force_ = - StretchScrollForceForStretchAmount(new_stretch_amount); - break; - case kStateMomentumAnimated: - momentum_animation_reset_at_next_frame_ = true; - break; - default: - // These cases should not be hit because the stretch must be zero in the - // Inactive and MomentumScroll states. - NOTREACHED(); - break; - } -} - -} // namespace content diff --git a/content/renderer/input/input_scroll_elasticity_controller.h b/content/renderer/input/input_scroll_elasticity_controller.h deleted file mode 100644 index c60a86e..0000000 --- a/content/renderer/input/input_scroll_elasticity_controller.h +++ /dev/null @@ -1,148 +0,0 @@ -// 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. - -#ifndef CONTENT_RENDERER_INPUT_INPUT_SCROLL_ELASTICITY_CONTROLLER_H_ -#define CONTENT_RENDERER_INPUT_INPUT_SCROLL_ELASTICITY_CONTROLLER_H_ - -#include "base/macros.h" -#include "base/memory/weak_ptr.h" -#include "cc/input/scroll_elasticity_helper.h" -#include "content/common/content_export.h" -#include "third_party/WebKit/public/web/WebInputEvent.h" - -// InputScrollElasticityController is based on -// WebKit/Source/platform/mac/ScrollElasticityController.h -/* - * Copyright (C) 2011 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -namespace cc { -struct InputHandlerScrollResult; -} // namespace cc - -namespace content { - -class CONTENT_EXPORT InputScrollElasticityController { - public: - explicit InputScrollElasticityController(cc::ScrollElasticityHelper* helper); - virtual ~InputScrollElasticityController(); - - base::WeakPtr<InputScrollElasticityController> GetWeakPtr(); - - // Update the overscroll state based a wheel event that has been processed. - // Note that this assumes that all events are coming from a single input - // device. If the user simultaneously uses multiple input devices, Cocoa may - // not correctly pass all the gesture begin and end events. In this case, - // this class may disregard some scrolls that come in at unexpected times. - void ObserveWheelEventAndResult( - const blink::WebMouseWheelEvent& wheel_event, - const cc::InputHandlerScrollResult& scroll_result); - void Animate(base::TimeTicks time); - - void ReconcileStretchAndScroll(); - - private: - enum State { - // The initial state, during which the overscroll amount is zero and - // there are no active or momentum scroll events coming in. This state - // is briefly returned to between the active and momentum phases of a - // scroll (if there is no overscroll). - kStateInactive, - // The state between receiving PhaseBegan/MayBegin and PhaseEnd/Cancelled, - // corresponding to the period during which the user has fingers on the - // trackpad. The overscroll amount is updated as input events are received. - // When PhaseEnd is received, the state transitions to Inactive if there is - // no overscroll and MomentumAnimated if there is non-zero overscroll. - kStateActiveScroll, - // The state between receiving a momentum PhaseBegan and PhaseEnd, while - // there is no overscroll. The overscroll amount is updated as input events - // are received. If the overscroll is ever non-zero then the state - // immediately transitions to kStateMomentumAnimated. - kStateMomentumScroll, - // The state while the overscroll amount is updated by an animation. If - // the user places fingers on the trackpad (a PhaseMayBegin is received) - // then the state transition to kStateActiveScroll. Otherwise the state - // transitions to Inactive when the overscroll amount becomes zero. - kStateMomentumAnimated, - }; - - void UpdateVelocity(const gfx::Vector2dF& event_delta, - const base::TimeTicks& event_timestamp); - void Overscroll(const gfx::Vector2dF& input_delta, - const gfx::Vector2dF& overscroll_delta); - void EnterStateMomentumAnimated( - const base::TimeTicks& triggering_event_timestamp); - void EnterStateInactive(); - - // Returns true if |direction| is pointing in a direction in which it is not - // possible to scroll any farther horizontally (or vertically). It is only in - // this circumstance that an overscroll in that direction may begin. - bool PinnedHorizontally(float direction) const; - bool PinnedVertically(float direction) const; - // Whether or not the content of the page is scrollable horizontaly (or - // vertically). - bool CanScrollHorizontally() const; - bool CanScrollVertically() const; - - cc::ScrollElasticityHelper* helper_; - State state_; - - // If there is no overscroll, require a minimum overscroll delta before - // starting the rubber-band effect. Track the amount of scrolling that has - // has occurred but has not yet caused rubber-band stretching in - // |pending_overscroll_delta_|. - gfx::Vector2dF pending_overscroll_delta_; - - // Maintain a calculation of the velocity of the scroll, based on the input - // scroll delta divide by the time between input events. Track this velocity - // in |scroll_velocity| and the previous input event timestamp for finite - // differencing in |last_scroll_event_timestamp_|. - gfx::Vector2dF scroll_velocity; - base::TimeTicks last_scroll_event_timestamp_; - - // The force of the rubber-band spring. This is equal to the cumulative sum - // of all overscroll offsets since entering a non-Inactive state. This is - // reset to zero only when entering the Inactive state. - gfx::Vector2dF stretch_scroll_force_; - - // Momentum animation state. This state is valid only while the state is - // MomentumAnimated, and is initialized in EnterStateMomentumAnimated. - base::TimeTicks momentum_animation_start_time_; - gfx::Vector2dF momentum_animation_initial_stretch_; - gfx::Vector2dF momentum_animation_initial_velocity_; - - // This is set in response to a scroll (most likely programmatic) occuring - // while animating the momentum phase. In this case, re-set the initial - // velocity, stretch, and start time at the next frame (this is the same - // behavior as would happen if the scroll were caused by an active scroll). - bool momentum_animation_reset_at_next_frame_; - - base::WeakPtrFactory<InputScrollElasticityController> weak_factory_; - DISALLOW_COPY_AND_ASSIGN(InputScrollElasticityController); -}; - -} // namespace content - -#endif // CONTENT_RENDERER_INPUT_INPUT_SCROLL_ELASTICITY_CONTROLLER_H_ diff --git a/content/renderer/input/input_scroll_elasticity_controller_unittest.cc b/content/renderer/input/input_scroll_elasticity_controller_unittest.cc deleted file mode 100644 index fa2c7f1..0000000 --- a/content/renderer/input/input_scroll_elasticity_controller_unittest.cc +++ /dev/null @@ -1,387 +0,0 @@ -// 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 "cc/input/input_handler.h" -#include "content/renderer/input/input_scroll_elasticity_controller.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "third_party/WebKit/public/web/WebInputEvent.h" - -namespace content { -namespace { - -enum Phase { - PhaseNone = blink::WebMouseWheelEvent::PhaseNone, - PhaseBegan = blink::WebMouseWheelEvent::PhaseBegan, - PhaseStationary = blink::WebMouseWheelEvent::PhaseStationary, - PhaseChanged = blink::WebMouseWheelEvent::PhaseChanged, - PhaseEnded = blink::WebMouseWheelEvent::PhaseEnded, - PhaseCancelled = blink::WebMouseWheelEvent::PhaseCancelled, - PhaseMayBegin = blink::WebMouseWheelEvent::PhaseMayBegin, -}; - -class MockScrollElasticityHelper : public cc::ScrollElasticityHelper { - public: - MockScrollElasticityHelper() - : is_user_scrollable_(true), - set_stretch_amount_count_(0), - request_animate_count_(0) {} - ~MockScrollElasticityHelper() override {} - - // cc::ScrollElasticityHelper implementation: - bool IsUserScrollable() const override { return is_user_scrollable_; } - gfx::Vector2dF StretchAmount() const override { return stretch_amount_; } - void SetStretchAmount(const gfx::Vector2dF& stretch_amount) override { - set_stretch_amount_count_ += 1; - stretch_amount_ = stretch_amount; - } - gfx::ScrollOffset ScrollOffset() const override { return scroll_offset_; } - gfx::ScrollOffset MaxScrollOffset() const override { - return max_scroll_offset_; - } - void ScrollBy(const gfx::Vector2dF& delta) override { - scroll_offset_ += gfx::ScrollOffset(delta); - } - void RequestAnimate() override { request_animate_count_ += 1; } - - // Counters for number of times functions were called. - int request_animate_count() const { return request_animate_count_; } - int set_stretch_amount_count() const { return set_stretch_amount_count_; } - - void SetScrollOffsetAndMaxScrollOffset( - const gfx::ScrollOffset& scroll_offset, - const gfx::ScrollOffset& max_scroll_offset) { - scroll_offset_ = scroll_offset; - max_scroll_offset_ = max_scroll_offset; - } - void SetUserScrollable(bool is_user_scrollable) { - is_user_scrollable_ = is_user_scrollable; - } - - private: - bool is_user_scrollable_; - gfx::Vector2dF stretch_amount_; - int set_stretch_amount_count_; - int request_animate_count_; - - gfx::ScrollOffset scroll_offset_; - gfx::ScrollOffset max_scroll_offset_; -}; - -class ScrollElasticityControllerTest : public testing::Test { - public: - ScrollElasticityControllerTest() - : controller_(&helper_), - input_event_count_(0), - current_time_(base::TimeTicks::FromInternalValue(100000000ull)) {} - ~ScrollElasticityControllerTest() override {} - - void SendMouseWheelEvent( - Phase phase, - Phase momentum_phase, - const gfx::Vector2dF& event_delta = gfx::Vector2dF(), - const gfx::Vector2dF& overscroll_delta = gfx::Vector2dF()) { - blink::WebMouseWheelEvent event; - event.phase = static_cast<blink::WebMouseWheelEvent::Phase>(phase); - event.momentumPhase = - static_cast<blink::WebMouseWheelEvent::Phase>(momentum_phase); - event.deltaX = -event_delta.x(); - event.deltaY = -event_delta.y(); - TickCurrentTime(); - event.timeStampSeconds = (current_time_ - base::TimeTicks()).InSecondsF(); - - cc::InputHandlerScrollResult scroll_result; - scroll_result.did_overscroll_root = !overscroll_delta.IsZero(); - scroll_result.unused_scroll_delta = overscroll_delta; - - controller_.ObserveWheelEventAndResult(event, scroll_result); - input_event_count_ += 1; - } - - const base::TimeTicks& TickCurrentTime() { - current_time_ += base::TimeDelta::FromSecondsD(1 / 60.f); - return current_time_; - } - void TickCurrentTimeAndAnimate() { - TickCurrentTime(); - controller_.Animate(current_time_); - } - - MockScrollElasticityHelper helper_; - InputScrollElasticityController controller_; - int input_event_count_; - base::TimeTicks current_time_; -}; - -// Verify that stretching only occurs in one axis at a time, and that it -// is biased to the Y axis. -TEST_F(ScrollElasticityControllerTest, Axis) { - helper_.SetScrollOffsetAndMaxScrollOffset(gfx::ScrollOffset(0, 0), - gfx::ScrollOffset(0, 0)); - - // If we push equally in the X and Y directions, we should see a stretch only - // in the Y direction. - SendMouseWheelEvent(PhaseBegan, PhaseNone); - SendMouseWheelEvent(PhaseChanged, PhaseNone, gfx::Vector2dF(10, 10), - gfx::Vector2dF(10, 10)); - EXPECT_EQ(1, helper_.set_stretch_amount_count()); - EXPECT_EQ(0.f, helper_.StretchAmount().x()); - EXPECT_LT(0.f, helper_.StretchAmount().y()); - helper_.SetStretchAmount(gfx::Vector2dF()); - EXPECT_EQ(2, helper_.set_stretch_amount_count()); - SendMouseWheelEvent(PhaseEnded, PhaseNone); - EXPECT_EQ(0, helper_.request_animate_count()); - - // If we push more in the X direction than the Y direction, we should see a - // stretch only in the X direction. This decision should be based on the - // input delta, not the actual overscroll delta. - SendMouseWheelEvent(PhaseBegan, PhaseNone); - SendMouseWheelEvent(PhaseChanged, PhaseNone, gfx::Vector2dF(-25, 10), - gfx::Vector2dF(-25, 40)); - EXPECT_EQ(3, helper_.set_stretch_amount_count()); - EXPECT_GT(0.f, helper_.StretchAmount().x()); - EXPECT_EQ(0.f, helper_.StretchAmount().y()); - helper_.SetStretchAmount(gfx::Vector2dF()); - EXPECT_EQ(4, helper_.set_stretch_amount_count()); - SendMouseWheelEvent(PhaseEnded, PhaseNone); - EXPECT_EQ(0, helper_.request_animate_count()); -} - -// Verify that we need a total overscroll delta of at least 10 in a pinned -// direction before we start stretching. -TEST_F(ScrollElasticityControllerTest, MinimumDeltaBeforeStretch) { - // We should not start stretching while we are not pinned in the direction - // of the scroll (even if there is an overscroll delta). We have to wait for - // the regular scroll to eat all of the events. - helper_.SetScrollOffsetAndMaxScrollOffset(gfx::ScrollOffset(5, 5), - gfx::ScrollOffset(10, 10)); - SendMouseWheelEvent(PhaseMayBegin, PhaseNone); - SendMouseWheelEvent(PhaseBegan, PhaseNone); - SendMouseWheelEvent(PhaseChanged, PhaseNone, gfx::Vector2dF(0, 10), - gfx::Vector2dF(0, 10)); - SendMouseWheelEvent(PhaseChanged, PhaseNone, gfx::Vector2dF(0, 10), - gfx::Vector2dF(0, 10)); - EXPECT_EQ(0, helper_.set_stretch_amount_count()); - - // Now pin the -X and +Y direction. The first event will not generate a - // stretch - // because it is below the delta threshold of 10. - helper_.SetScrollOffsetAndMaxScrollOffset(gfx::ScrollOffset(0, 10), - gfx::ScrollOffset(10, 10)); - SendMouseWheelEvent(PhaseChanged, PhaseNone, gfx::Vector2dF(0, 10), - gfx::Vector2dF(0, 8)); - EXPECT_EQ(0, helper_.set_stretch_amount_count()); - - // Make the next scroll be in the -X direction more than the +Y direction, - // which will erase the memory of the previous unused delta of 8. - SendMouseWheelEvent(PhaseChanged, PhaseNone, gfx::Vector2dF(-10, 5), - gfx::Vector2dF(-8, 10)); - EXPECT_EQ(0, helper_.set_stretch_amount_count()); - - // Now push against the pinned +Y direction again by 8. We reset the - // previous delta, so this will not generate a stretch. - SendMouseWheelEvent(PhaseChanged, PhaseNone, gfx::Vector2dF(0, 10), - gfx::Vector2dF(0, 8)); - EXPECT_EQ(0, helper_.set_stretch_amount_count()); - - // Push against +Y by another 8. This gets us above the delta threshold of - // 10, so we should now have had the stretch set, and it should be in the - // +Y direction. The scroll in the -X direction should have been forgotten. - SendMouseWheelEvent(PhaseChanged, PhaseNone, gfx::Vector2dF(0, 10), - gfx::Vector2dF(0, 8)); - EXPECT_EQ(1, helper_.set_stretch_amount_count()); - EXPECT_EQ(0.f, helper_.StretchAmount().x()); - EXPECT_LT(0.f, helper_.StretchAmount().y()); - - // End the gesture. Because there is a non-zero stretch, we should be in the - // animated state, and should have had a frame requested. - EXPECT_EQ(0, helper_.request_animate_count()); - SendMouseWheelEvent(PhaseEnded, PhaseNone); - EXPECT_EQ(1, helper_.request_animate_count()); -} - -// Verify that an stretch caused by a momentum scroll will switch to the -// animating mode, where input events are ignored, and the stretch is updated -// while animating. -TEST_F(ScrollElasticityControllerTest, MomentumAnimate) { - // Do an active scroll, then switch to the momentum phase and scroll for a - // bit. - helper_.SetScrollOffsetAndMaxScrollOffset(gfx::ScrollOffset(5, 5), - gfx::ScrollOffset(10, 10)); - SendMouseWheelEvent(PhaseBegan, PhaseNone); - SendMouseWheelEvent(PhaseChanged, PhaseNone, gfx::Vector2dF(0, -80), - gfx::Vector2dF(0, 0)); - SendMouseWheelEvent(PhaseChanged, PhaseNone, gfx::Vector2dF(0, -80), - gfx::Vector2dF(0, 0)); - SendMouseWheelEvent(PhaseChanged, PhaseNone, gfx::Vector2dF(0, -80), - gfx::Vector2dF(0, 0)); - SendMouseWheelEvent(PhaseEnded, PhaseNone); - SendMouseWheelEvent(PhaseNone, PhaseBegan); - SendMouseWheelEvent(PhaseNone, PhaseChanged, gfx::Vector2dF(0, -80), - gfx::Vector2dF(0, 0)); - SendMouseWheelEvent(PhaseNone, PhaseChanged, gfx::Vector2dF(0, -80), - gfx::Vector2dF(0, 0)); - SendMouseWheelEvent(PhaseNone, PhaseChanged, gfx::Vector2dF(0, -80), - gfx::Vector2dF(0, 0)); - EXPECT_EQ(0, helper_.set_stretch_amount_count()); - - // Hit the -Y edge and overscroll slightly, but not enough to go over the - // threshold to cause a stretch. - helper_.SetScrollOffsetAndMaxScrollOffset(gfx::ScrollOffset(5, 0), - gfx::ScrollOffset(10, 10)); - SendMouseWheelEvent(PhaseNone, PhaseChanged, gfx::Vector2dF(0, -80), - gfx::Vector2dF(0, -8)); - EXPECT_EQ(0, helper_.set_stretch_amount_count()); - EXPECT_EQ(0, helper_.request_animate_count()); - - // Take another step, this time going over the threshold. This should update - // the stretch amount, and then switch to the animating mode. - SendMouseWheelEvent(PhaseNone, PhaseChanged, gfx::Vector2dF(0, -80), - gfx::Vector2dF(0, -80)); - EXPECT_EQ(1, helper_.set_stretch_amount_count()); - EXPECT_EQ(1, helper_.request_animate_count()); - EXPECT_GT(-1.f, helper_.StretchAmount().y()); - - // Subsequent momentum events should do nothing. - SendMouseWheelEvent(PhaseNone, PhaseChanged, gfx::Vector2dF(0, -80), - gfx::Vector2dF(0, -80)); - SendMouseWheelEvent(PhaseNone, PhaseChanged, gfx::Vector2dF(0, -80), - gfx::Vector2dF(0, -80)); - SendMouseWheelEvent(PhaseNone, PhaseEnded, gfx::Vector2dF(0, -80), - gfx::Vector2dF(0, -80)); - EXPECT_EQ(1, helper_.set_stretch_amount_count()); - EXPECT_EQ(1, helper_.request_animate_count()); - - // Subsequent animate events should update the stretch amount and request - // another frame. - TickCurrentTimeAndAnimate(); - EXPECT_EQ(2, helper_.set_stretch_amount_count()); - EXPECT_EQ(2, helper_.request_animate_count()); - EXPECT_GT(-1.f, helper_.StretchAmount().y()); - - // Touching the trackpad (a PhaseMayBegin event) should disable animation. - SendMouseWheelEvent(PhaseMayBegin, PhaseNone); - TickCurrentTimeAndAnimate(); - EXPECT_EQ(2, helper_.set_stretch_amount_count()); - EXPECT_EQ(2, helper_.request_animate_count()); - - // Releasing the trackpad should re-enable animation. - SendMouseWheelEvent(PhaseCancelled, PhaseNone); - EXPECT_EQ(2, helper_.set_stretch_amount_count()); - EXPECT_EQ(3, helper_.request_animate_count()); - TickCurrentTimeAndAnimate(); - EXPECT_EQ(3, helper_.set_stretch_amount_count()); - EXPECT_EQ(4, helper_.request_animate_count()); - - // Keep animating frames until the stretch returns to rest. - int stretch_count = 3; - int animate_count = 4; - while (1) { - TickCurrentTimeAndAnimate(); - if (helper_.StretchAmount().IsZero()) { - stretch_count += 1; - EXPECT_EQ(stretch_count, helper_.set_stretch_amount_count()); - EXPECT_EQ(animate_count, helper_.request_animate_count()); - break; - } - stretch_count += 1; - animate_count += 1; - EXPECT_EQ(stretch_count, helper_.set_stretch_amount_count()); - EXPECT_EQ(animate_count, helper_.request_animate_count()); - } - - // After coming to rest, no subsequent animate calls change anything. - TickCurrentTimeAndAnimate(); - EXPECT_EQ(stretch_count, helper_.set_stretch_amount_count()); - EXPECT_EQ(animate_count, helper_.request_animate_count()); -} - -// Verify that an stretch opposing a scroll is correctly resolved. -TEST_F(ScrollElasticityControllerTest, ReconcileStretchAndScroll) { - SendMouseWheelEvent(PhaseBegan, PhaseNone); - - // Verify completely knocking out the scroll in the -Y direction. - helper_.SetScrollOffsetAndMaxScrollOffset(gfx::ScrollOffset(5, 5), - gfx::ScrollOffset(10, 10)); - helper_.SetStretchAmount(gfx::Vector2dF(0, -10)); - controller_.ReconcileStretchAndScroll(); - EXPECT_EQ(helper_.StretchAmount(), gfx::Vector2dF(0, -5)); - EXPECT_EQ(helper_.ScrollOffset(), gfx::ScrollOffset(5, 0)); - - // Verify partially knocking out the scroll in the -Y direction. - helper_.SetScrollOffsetAndMaxScrollOffset(gfx::ScrollOffset(5, 8), - gfx::ScrollOffset(10, 10)); - helper_.SetStretchAmount(gfx::Vector2dF(0, -5)); - controller_.ReconcileStretchAndScroll(); - EXPECT_EQ(helper_.StretchAmount(), gfx::Vector2dF(0, 0)); - EXPECT_EQ(helper_.ScrollOffset(), gfx::ScrollOffset(5, 3)); - - // Verify completely knocking out the scroll in the +X direction. - helper_.SetScrollOffsetAndMaxScrollOffset(gfx::ScrollOffset(5, 5), - gfx::ScrollOffset(10, 10)); - helper_.SetStretchAmount(gfx::Vector2dF(10, 0)); - controller_.ReconcileStretchAndScroll(); - EXPECT_EQ(helper_.StretchAmount(), gfx::Vector2dF(5, 0)); - EXPECT_EQ(helper_.ScrollOffset(), gfx::ScrollOffset(10, 5)); - - // Verify partially knocking out the scroll in the +X and +Y directions. - helper_.SetScrollOffsetAndMaxScrollOffset(gfx::ScrollOffset(2, 3), - gfx::ScrollOffset(10, 10)); - helper_.SetStretchAmount(gfx::Vector2dF(5, 5)); - controller_.ReconcileStretchAndScroll(); - EXPECT_EQ(helper_.StretchAmount(), gfx::Vector2dF(0, 0)); - EXPECT_EQ(helper_.ScrollOffset(), gfx::ScrollOffset(7, 8)); -} - -// Verify that stretching only happens when the area is user scrollable. -TEST_F(ScrollElasticityControllerTest, UserScrollableRequiredForStretch) { - helper_.SetScrollOffsetAndMaxScrollOffset(gfx::ScrollOffset(0, 0), - gfx::ScrollOffset(10, 10)); - gfx::Vector2dF delta(0, -15); - - // Do an active scroll, and ensure that the stretch amount doesn't change, - // and also that the stretch amount isn't even ever changed. - helper_.SetUserScrollable(false); - SendMouseWheelEvent(PhaseBegan, PhaseNone); - SendMouseWheelEvent(PhaseChanged, PhaseNone, delta, delta); - SendMouseWheelEvent(PhaseChanged, PhaseNone, delta, delta); - SendMouseWheelEvent(PhaseEnded, PhaseNone); - EXPECT_EQ(helper_.StretchAmount(), gfx::Vector2dF(0, 0)); - EXPECT_EQ(0, helper_.set_stretch_amount_count()); - SendMouseWheelEvent(PhaseNone, PhaseBegan); - SendMouseWheelEvent(PhaseNone, PhaseChanged, delta, delta); - SendMouseWheelEvent(PhaseNone, PhaseChanged, delta, delta); - SendMouseWheelEvent(PhaseNone, PhaseEnded); - EXPECT_EQ(helper_.StretchAmount(), gfx::Vector2dF(0, 0)); - EXPECT_EQ(0, helper_.set_stretch_amount_count()); - - // Re-enable user scrolling and ensure that stretching is re-enabled. - helper_.SetUserScrollable(true); - SendMouseWheelEvent(PhaseBegan, PhaseNone); - SendMouseWheelEvent(PhaseChanged, PhaseNone, delta, delta); - SendMouseWheelEvent(PhaseChanged, PhaseNone, delta, delta); - SendMouseWheelEvent(PhaseEnded, PhaseNone); - EXPECT_NE(helper_.StretchAmount(), gfx::Vector2dF(0, 0)); - EXPECT_GT(helper_.set_stretch_amount_count(), 0); - SendMouseWheelEvent(PhaseNone, PhaseBegan); - SendMouseWheelEvent(PhaseNone, PhaseChanged, delta, delta); - SendMouseWheelEvent(PhaseNone, PhaseChanged, delta, delta); - SendMouseWheelEvent(PhaseNone, PhaseEnded); - EXPECT_NE(helper_.StretchAmount(), gfx::Vector2dF(0, 0)); - EXPECT_GT(helper_.set_stretch_amount_count(), 0); - - // Disable user scrolling and tick the timer until the stretch goes back - // to zero. Ensure that the return to zero doesn't happen immediately. - helper_.SetUserScrollable(false); - int ticks_to_zero = 0; - while (1) { - TickCurrentTimeAndAnimate(); - if (helper_.StretchAmount().IsZero()) - break; - ticks_to_zero += 1; - } - EXPECT_GT(ticks_to_zero, 3); -} - -} // namespace -} // namespace content diff --git a/content/renderer/input/synchronous_input_handler_proxy.h b/content/renderer/input/synchronous_input_handler_proxy.h deleted file mode 100644 index 3bf3990..0000000 --- a/content/renderer/input/synchronous_input_handler_proxy.h +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2015 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. - -#ifndef CONTENT_RENDERER_INPUT_SYNCHRONOUS_INPUT_HANDLER_PROXY_H_ -#define CONTENT_RENDERER_INPUT_SYNCHRONOUS_INPUT_HANDLER_PROXY_H_ - -#include "base/time/time.h" -#include "content/common/content_export.h" - -namespace gfx { -class ScrollOffset; -class SizeF; -} - -namespace content { - -class CONTENT_EXPORT SynchronousInputHandler { - public: - virtual ~SynchronousInputHandler() {} - - // Informs the Android WebView embedder that a fling animation is running, and - // that it should call SynchronouslyAnimate() if it wants to execute that - // animation. The embedder/app may choose to override and ignore the - // request for animation. - virtual void SetNeedsSynchronousAnimateInput() = 0; - - // Informs the Android WebView embedder of the current root scroll and page - // scale state. - virtual void UpdateRootLayerState( - const gfx::ScrollOffset& total_scroll_offset, - const gfx::ScrollOffset& max_scroll_offset, - const gfx::SizeF& scrollable_size, - float page_scale_factor, - float min_page_scale_factor, - float max_page_scale_factor) = 0; -}; - -// Android WebView requires synchronous scrolling from the WebView application. -// This interface provides support for that behaviour. The WebView embedder will -// act as the InputHandler for controlling the timing of input (fling) -// animations. -class CONTENT_EXPORT SynchronousInputHandlerProxy { - public: - virtual ~SynchronousInputHandlerProxy() {} - - // Tell the proxy that we will control the timing of root fling animations - // from the SynchronousInputHandler. Once this is set, the InputHandler is - // not requested to Animate() the InputHandlerProxy for root layer flings. - // Instead, requests for animation will go to the SynchronousInputHandler and - // animation ticks will only come back through SynchronouslyAnimate(). - // Non-root flings are not affected. - virtual void SetOnlySynchronouslyAnimateRootFlings( - SynchronousInputHandler* synchronous_input_handler) = 0; - - // Tick input (fling) animations. This may happen out of phase with the frame - // timing, or not at all, as it is controlled by the WebView application. When - // it returns, it expects the animation scroll offsets to be visible to the - // application. - virtual void SynchronouslyAnimate(base::TimeTicks time) = 0; - - // Called when the synchronous input handler wants to change the root scroll - // offset. Since it has the final say, this overrides values from compositor- - // controlled behaviour. After the offset is applied, the - // SynchronousInputHandler should be given back the result in case it differs - // from what was sent. - virtual void SynchronouslySetRootScrollOffset( - const gfx::ScrollOffset& root_offset) = 0; -}; - -} // namespace content - -#endif // CONTENT_RENDERER_INPUT_SYNCHRONOUS_INPUT_HANDLER_PROXY_H_ |