Index: content/renderer/input/input_scroll_elasticity_controller.cc |
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 00d078ff76c84ddb3b870c1ac0dd107bcaec0353..0000000000000000000000000000000000000000 |
--- 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 |