Bug 907123 - Implement fling acceleration on multiple consecutive flings. r=botond

This commit is contained in:
Kartikaya Gupta 2014-04-29 09:45:13 -04:00
Родитель 36cf99e744
Коммит a52f3f95dd
3 изменённых файлов: 68 добавлений и 4 удалений

Просмотреть файл

@ -163,6 +163,20 @@ typedef GeckoContentController::APZStateChange APZStateChange;
* generated displayport's size is beyond that of the scrollable rect on the
* opposite axis.
*
* "apz.fling_accel_interval_ms"
* The time in milliseconds that determines whether a second fling will be
* treated as accelerated. If two flings are started within this interval,
* the second one will be accelerated. Setting an interval of 0 means that
* acceleration will be disabled.
*
* "apz.fling_accel_base_mult"
* "apz.fling_accel_supplemental_mult"
* When applying an acceleration on a fling, the new computed velocity is
* (new_fling_velocity * base_mult) + (old_velocity * supplemental_mult).
* The base_mult and supplemental_mult multiplier values are controlled by
* these prefs. Note that "old_velocity" here is the initial velocity of the
* previous fling _after_ acceleration was applied to it (if applicable).
*
* "apz.fling_friction"
* Amount of friction applied during flings.
*
@ -330,10 +344,40 @@ GetFrameTime() {
class FlingAnimation: public AsyncPanZoomAnimation {
public:
FlingAnimation(AsyncPanZoomController& aApzc)
FlingAnimation(AsyncPanZoomController& aApzc, bool aApplyAcceleration)
: AsyncPanZoomAnimation(TimeDuration::FromMilliseconds(gfxPrefs::APZFlingRepaintInterval()))
, mApzc(aApzc)
{}
{
TimeStamp now = GetFrameTime();
ScreenPoint velocity(mApzc.mX.GetVelocity(), mApzc.mY.GetVelocity());
// If the last fling was very recent and in the same direction as this one,
// 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.
// Note that the acceleration code is only applied on the APZC that receives the
// actual touch event; the accelerated velocities are then handed off using the
// normal HandOffFling codepath.
if (aApplyAcceleration && !mApzc.mLastFlingTime.IsNull()
&& (now - mApzc.mLastFlingTime).ToMilliseconds() < gfxPrefs::APZFlingAccelInterval()) {
if (SameDirection(velocity.x, mApzc.mLastFlingVelocity.x)) {
velocity.x = Accelerate(velocity.x, mApzc.mLastFlingVelocity.x);
APZC_LOG("%p Applying fling x-acceleration from %f to %f (delta %f)\n",
&mApzc, mApzc.mX.GetVelocity(), velocity.x, mApzc.mLastFlingVelocity.x);
mApzc.mX.SetVelocity(velocity.x);
}
if (SameDirection(velocity.y, mApzc.mLastFlingVelocity.y)) {
velocity.y = Accelerate(velocity.y, mApzc.mLastFlingVelocity.y);
APZC_LOG("%p Applying fling y-acceleration from %f to %f (delta %f)\n",
&mApzc, mApzc.mY.GetVelocity(), velocity.y, mApzc.mLastFlingVelocity.y);
mApzc.mY.SetVelocity(velocity.y);
}
}
mApzc.mLastFlingTime = now;
mApzc.mLastFlingVelocity = velocity;
}
/**
* Advances a fling by an interpolated amount based on the passed in |aDelta|.
* This should be called whenever sampling the content transform for this
@ -344,6 +388,19 @@ public:
const TimeDuration& aDelta);
private:
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 * gfxPrefs::APZFlingAccelBaseMultiplier())
+ (aSupplemental * gfxPrefs::APZFlingAccelSupplementalMultiplier());
}
AsyncPanZoomController& mApzc;
};
@ -755,7 +812,7 @@ nsEventStatus AsyncPanZoomController::OnTouchEnd(const MultiTouchInput& aEvent)
mX.EndTouch();
mY.EndTouch();
SetState(FLING);
StartAnimation(new FlingAnimation(*this));
StartAnimation(new FlingAnimation(*this, true));
return nsEventStatus_eConsumeNoDefault;
case PINCHING:
@ -1183,7 +1240,7 @@ void AsyncPanZoomController::TakeOverFling(ScreenPoint aVelocity) {
mX.SetVelocity(mX.GetVelocity() + aVelocity.x);
mY.SetVelocity(mY.GetVelocity() + aVelocity.y);
SetState(FLING);
StartAnimation(new FlingAnimation(*this));
StartAnimation(new FlingAnimation(*this, false));
}
void AsyncPanZoomController::CallDispatchScroll(const ScreenPoint& aStartPoint, const ScreenPoint& aEndPoint,

Просмотреть файл

@ -778,6 +778,10 @@ public:
private:
friend class FlingAnimation;
// The initial velocity of the most recent fling.
ScreenPoint mLastFlingVelocity;
// The time at which the most recent fling started.
TimeStamp mLastFlingTime;
/* ===================================================================

Просмотреть файл

@ -111,6 +111,9 @@ private:
DECL_GFX_PREF(Live, "apz.content_response_timeout", APZContentResponseTimeout, int32_t, 300);
DECL_GFX_PREF(Live, "apz.cross_slide.enabled", APZCrossSlideEnabled, bool, false);
DECL_GFX_PREF(Live, "apz.enlarge_displayport_when_clipped", APZEnlargeDisplayPortWhenClipped, bool, false);
DECL_GFX_PREF(Live, "apz.fling_accel_interval_ms", APZFlingAccelInterval, int32_t, 500);
DECL_GFX_PREF(Live, "apz.fling_accel_base_mult", APZFlingAccelBaseMultiplier, float, 1.0f);
DECL_GFX_PREF(Live, "apz.fling_accel_supplemental_mult", APZFlingAccelSupplementalMultiplier, float, 1.0f);
DECL_GFX_PREF(Once, "apz.fling_friction", APZFlingFriction, float, 0.002f);
DECL_GFX_PREF(Live, "apz.fling_repaint_interval", APZFlingRepaintInterval, int32_t, 75);
DECL_GFX_PREF(Once, "apz.fling_stopped_threshold", APZFlingStoppedThreshold, float, 0.01f);