Bug 1096513 - Disallow underscroll in APZC. r=botond

This commit is contained in:
Chris Lord 2015-01-19 17:39:20 +00:00
Родитель fa5c39586f
Коммит c86dcd22c0
3 изменённых файлов: 60 добавлений и 58 удалений

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

@ -2513,30 +2513,19 @@ Matrix4x4 AsyncPanZoomController::GetOverscrollTransform() const {
float scaleX = 1 + kStretchFactor * fabsf(mX.GetOverscroll()) / mX.GetCompositionLength();
float scaleY = 1 + kStretchFactor * fabsf(mY.GetOverscroll()) / mY.GetCompositionLength();
// If an axis is in underscroll, the interpretation of its overscroll
// amount changes: instead of stretching along that axis, we compress.
if (mX.IsInUnderscroll()) {
scaleX = 1 / scaleX;
}
if (mY.IsInUnderscroll()) {
scaleY = 1 / scaleY;
}
// The scale is applied relative to the origin of the composition bounds, i.e.
// it keeps the top-left corner of the content in place. This is fine if we
// are overscrolling at the top or on the left, but if we are overscrolling
// at the bottom or on the right, we want the bottom or right edge of the
// content to stay in place instead, so we add a translation to compensate.
ParentLayerPoint translation;
bool overscrolledOnRight = (mX.GetOverscroll() > 0 && !mX.IsInUnderscroll())
|| (mX.GetOverscroll() < 0 && mX.IsInUnderscroll());
bool overscrolledOnRight = mX.GetOverscroll() > 0;
if (overscrolledOnRight) {
ParentLayerCoord overscrolledCompositionWidth = scaleX * compositionSize.width;
ParentLayerCoord extraCompositionWidth = overscrolledCompositionWidth - compositionSize.width;
translation.x = -extraCompositionWidth;
}
bool overscrolledAtBottom = (mY.GetOverscroll() > 0 && !mY.IsInUnderscroll())
|| (mY.GetOverscroll() < 0 && mY.IsInUnderscroll());
bool overscrolledAtBottom = mY.GetOverscroll() > 0;
if (overscrolledAtBottom) {
ParentLayerCoord overscrolledCompositionHeight = scaleY * compositionSize.height;
ParentLayerCoord extraCompositionHeight = overscrolledCompositionHeight - compositionSize.height;

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

@ -38,7 +38,9 @@ Axis::Axis(AsyncPanZoomController* aAsyncPanZoomController)
mAxisLocked(false),
mAsyncPanZoomController(aAsyncPanZoomController),
mOverscroll(0),
mInUnderscroll(false)
mFirstOverscrollAnimationSample(0),
mOverscrollOffset(0),
mOverscrollScale(1.0f)
{
}
@ -190,11 +192,12 @@ void Axis::OverscrollBy(ParentLayerCoord aOverscroll) {
}
ParentLayerCoord Axis::GetOverscroll() const {
return mOverscroll;
}
ParentLayerCoord result = (mOverscroll - mOverscrollOffset) / mOverscrollScale;
bool Axis::IsInUnderscroll() const {
return mInUnderscroll;
// Assert that we return overscroll in the correct direction
MOZ_ASSERT((result * mOverscrollOffset) >= 0.0f);
return result;
}
void Axis::StepOverscrollAnimation(double aStepDurationMilliseconds) {
@ -218,6 +221,7 @@ void Axis::StepOverscrollAnimation(double aStepDurationMilliseconds) {
// Apply spring force.
float springForce = -1 * kSpringStiffness * mOverscroll;
// Assume unit mass, so force = acceleration.
float oldVelocity = mVelocity;
mVelocity += springForce * aStepDurationMilliseconds;
// Apply dampening.
@ -225,21 +229,38 @@ void Axis::StepOverscrollAnimation(double aStepDurationMilliseconds) {
AXIS_LOG("%p|%s sampled overscroll animation, leaving velocity at %f\n",
mAsyncPanZoomController, Name(), mVelocity);
// Adjust the amount of overscroll based on the velocity.
// Note that we allow for oscillations. mInUnderscroll tracks whether
// we are currently in a state where we have overshot and the spring is
// displaced in the other direction.
float oldOverscroll = mOverscroll;
mOverscroll += (mVelocity * aStepDurationMilliseconds);
bool signChange = (oldOverscroll * mOverscroll) < 0;
if (signChange) {
// If the sign of mOverscroll changed, we have either entered underscroll
// or exited it.
mInUnderscroll = !mInUnderscroll;
// At the peak of each oscillation, record new offset and scaling factors for
// overscroll, to ensure that GetOverscroll always returns a value of the
// same sign, and that this value is correctly adjusted as the spring is
// dampened.
bool velocitySignChange = (oldVelocity * mVelocity) < 0;
if (mFirstOverscrollAnimationSample == 0.0f) {
mFirstOverscrollAnimationSample = mOverscroll;
// It's possible to start sampling overscroll with velocity == 0, or
// velocity in the opposite direction of overscroll, so make sure we
// correctly record the peak in this case.
if ((mOverscroll >= 0 ? oldVelocity : -oldVelocity) <= 0.0f) {
velocitySignChange = true;
}
}
if (velocitySignChange) {
bool oddOscillation = (mOverscroll.value * mFirstOverscrollAnimationSample.value) < 0.0f;
mOverscrollOffset = oddOscillation ? mOverscroll : -mOverscroll;
mOverscrollScale = 2.0f;
}
// Adjust the amount of overscroll based on the velocity.
// Note that we allow for oscillations.
mOverscroll += (mVelocity * aStepDurationMilliseconds);
}
bool Axis::SampleOverscrollAnimation(const TimeDuration& aDelta) {
// Short-circuit early rather than running through all the sampling code.
if (mVelocity == 0.0f && mOverscroll == 0.0f) {
return false;
}
// We approximate the curve traced out by the velocity of the spring
// over time by breaking up the curve into small segments over which we
// consider the velocity to be constant. If the animation is sampled
@ -267,9 +288,8 @@ bool Axis::SampleOverscrollAnimation(const TimeDuration& aDelta) {
// velocity and overscroll are already low.
AXIS_LOG("%p|%s oscillation dropped below threshold, going to rest\n",
mAsyncPanZoomController, Name());
mOverscroll = 0;
ClearOverscroll();
mVelocity = 0;
mInUnderscroll = false;
return false;
}
@ -283,6 +303,9 @@ bool Axis::IsOverscrolled() const {
void Axis::ClearOverscroll() {
mOverscroll = 0;
mFirstOverscrollAnimationSample = 0;
mOverscrollOffset = 0;
mOverscrollScale = 1.0f;
}
ParentLayerCoord Axis::PanStart() const {

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

@ -91,34 +91,9 @@ public:
* extreme allowed value in the relevant direction (that is, it must be at
* its maximum value if we are overscrolled at our composition length, and
* at its minimum value if we are overscrolled at the origin).
* Note that if |mInUnderscroll| is true, the interpretation of this field
* changes slightly (see below).
*/
ParentLayerCoord GetOverscroll() const;
/**
* Return whether the axis is in underscroll.
*
* This flag is set when an overscroll animation is in a state where the
* spring physics caused a snap-back movement to "overshoot" its target and
* as a result the spring is stretched in a direction opposite to the one
* when we were in overscroll. We call this situation "underscroll". When in
* underscroll, GetOverscroll() can be nonzero, but rather than being
* interpreted as overscroll (stretch) at the other end of the composition
* bounds, it's interpeted as an "underscroll" (compression) at the same end.
* This table summarizes what the possible combinations of GetOverscroll()
* and IsInUnderscroll() mean:
*
* GetOverscroll() | IsInUnderscroll() | Description
*-------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------
* negative | false | The axis is overscrolled at its origin. A stretch is applied with the content fixed in place at the origin.
* positive | false | The axis is overscrolled at its composition end. A stretch is applied with the content fixed in place at the composition end.
* positive | true | The axis is underscrolled at its origin. A compression is applied with the content fixed in place at the origin.
* negative | true | The axis is underscrolled at its composition end. A compression is applied with the content fixed in place at the composition end.
*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
*/
bool IsInUnderscroll() const;
/**
* Sample the snap-back animation to relieve overscroll.
* |aDelta| is the time since the last sample.
@ -247,8 +222,23 @@ protected:
float mVelocity; // Units: ParentLayerCoords per millisecond
bool mAxisLocked; // Whether movement on this axis is locked.
AsyncPanZoomController* mAsyncPanZoomController;
ParentLayerCoord mOverscroll; // See GetOverscroll().
bool mInUnderscroll; // See IsInUnderscroll().
// mOverscroll is the displacement of an oscillating spring from its resting
// state. The resting state moves as the overscroll animation progresses.
ParentLayerCoord mOverscroll;
// Used to record the initial overscroll when we start sampling for animation.
ParentLayerCoord mFirstOverscrollAnimationSample;
// These two variables are used in combination to make sure that
// GetOverscroll() never changes sign during animation. This is necessary,
// as mOverscroll itself oscillates around zero during animation.
// If we're not sampling overscroll animation, mOverscrollScale will be 1.0
// and mOverscrollOffset will be zero.
// If we are animating, after the overscroll reaches its peak,
// mOverscrollScale will be 2.0 and mOverscrollOffset will store a value that
// guarantees that the result of GetOverscroll() never changes sign.
ParentLayerCoord mOverscrollOffset;
float mOverscrollScale;
// A queue of (timestamp, velocity) pairs; these are the historical
// velocities at the given timestamps. Timestamps are in milliseconds,
// velocities are in screen pixels per ms. This member can only be