Source code

Revision control

Copy as Markdown

Other Tools

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at */
#include "FlingAccelerator.h"
#include "mozilla/StaticPrefs_apz.h"
#include "GenericFlingAnimation.h" // for FLING_LOG and FlingHandoffState
namespace mozilla {
namespace layers {
void FlingAccelerator::Reset() {
mPreviousFlingStartingVelocity = ParentLayerPoint{};
mPreviousFlingCancelVelocity = ParentLayerPoint{};
mIsTracking = false;
static bool SameDirection(float aVelocity1, float aVelocity2) {
return (aVelocity1 == 0.0f) || (aVelocity2 == 0.0f) ||
(IsNegative(aVelocity1) == IsNegative(aVelocity2));
static float Accelerate(float aBase, float aSupplemental) {
return (aBase * StaticPrefs::apz_fling_accel_base_mult()) +
(aSupplemental * StaticPrefs::apz_fling_accel_supplemental_mult());
ParentLayerPoint FlingAccelerator::GetFlingStartingVelocity(
const SampleTime& aNow, const ParentLayerPoint& aVelocity,
const FlingHandoffState& aHandoffState) {
// If the fling should be accelerated and is in the same direction as the
// previous fling, boost the velocity to be the sum of the two. Check separate
// axes separately because we could have two vertical flings with small
// horizontal components on the opposite side of zero, and we still want the
// y-fling to get accelerated.
ParentLayerPoint velocity = aVelocity;
if (ShouldAccelerate(aNow, aVelocity, aHandoffState)) {
if (velocity.x != 0 &&
SameDirection(velocity.x, mPreviousFlingStartingVelocity.x)) {
velocity.x = Accelerate(velocity.x, mPreviousFlingStartingVelocity.x);
FLING_LOG("%p Applying fling x-acceleration from %f to %f (delta %f)\n",
this, aVelocity.x.value, velocity.x.value,
if (velocity.y != 0 &&
SameDirection(velocity.y, mPreviousFlingStartingVelocity.y)) {
velocity.y = Accelerate(velocity.y, mPreviousFlingStartingVelocity.y);
FLING_LOG("%p Applying fling y-acceleration from %f to %f (delta %f)\n",
this, aVelocity.y.value, velocity.y.value,
mPreviousFlingStartingVelocity = velocity;
mIsTracking = true;
return velocity;
bool FlingAccelerator::ShouldAccelerate(
const SampleTime& aNow, const ParentLayerPoint& aVelocity,
const FlingHandoffState& aHandoffState) const {
if (!IsTracking()) {
FLING_LOG("%p Fling accelerator was reset, not accelerating.\n", this);
return false;
if (!aHandoffState.mTouchStartRestingTime) {
FLING_LOG("%p Don't have a touch start resting time, not accelerating.\n",
return false;
double msBetweenTouchStartAndPanStart =
"%p ShouldAccelerate with pan velocity %f pixels/ms, min pan velocity %f "
"pixels/ms, previous fling cancel velocity %f pixels/ms, time elapsed "
"since starting previous time between touch start and pan "
"start %fms.\n",
this, float(aVelocity.Length()), float(aHandoffState.mMinPanVelocity),
if (aVelocity.Length() < StaticPrefs::apz_fling_accel_min_fling_velocity()) {
FLING_LOG("%p Fling velocity too low (%f), not accelerating.\n", this,
return false;
if (aHandoffState.mMinPanVelocity <
StaticPrefs::apz_fling_accel_min_pan_velocity()) {
"%p Panning velocity was too slow at some point during the pan (%f), "
"not accelerating.\n",
this, float(aHandoffState.mMinPanVelocity));
return false;
if (mPreviousFlingCancelVelocity.Length() <
StaticPrefs::apz_fling_accel_min_fling_velocity()) {
"%p The previous fling animation had slowed down too much when it was "
"interrupted (%f), not accelerating.\n",
this, float(mPreviousFlingCancelVelocity.Length()));
return false;
if (msBetweenTouchStartAndPanStart >=
StaticPrefs::apz_fling_accel_max_pause_interval_ms()) {
"%p Too much time (%fms) elapsed between touch start and pan start, "
"not accelerating.\n",
this, msBetweenTouchStartAndPanStart);
return false;
return true;
} // namespace layers
} // namespace mozilla