| Index: content/renderer/input/input_handler_proxy.cc
|
| diff --git a/content/renderer/input/input_handler_proxy.cc b/content/renderer/input/input_handler_proxy.cc
|
| deleted file mode 100644
|
| index 255492f0d4d2556ead2a4e7d15058fe7689ea0fe..0000000000000000000000000000000000000000
|
| --- 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
|
|
|