Bug 1131749 - Correct for errors in our approximation of the spring equation for overscroll physics that might otherwise violate an assumption. r=kats

This commit is contained in:
Botond Ballo 2015-02-18 15:12:50 -05:00
parent a0b3157fb7
commit 271bb512e3
2 changed files with 23 additions and 9 deletions

View File

@ -40,7 +40,7 @@ Axis::Axis(AsyncPanZoomController* aAsyncPanZoomController)
mAsyncPanZoomController(aAsyncPanZoomController),
mOverscroll(0),
mFirstOverscrollAnimationSample(0),
mOverscrollOffset(0),
mLastOverscrollPeak(0),
mOverscrollScale(1.0f)
{
}
@ -196,7 +196,7 @@ void Axis::OverscrollBy(ParentLayerCoord aOverscroll) {
}
ParentLayerCoord Axis::GetOverscroll() const {
ParentLayerCoord result = (mOverscroll - mOverscrollOffset) / mOverscrollScale;
ParentLayerCoord result = (mOverscroll - mLastOverscrollPeak) / mOverscrollScale;
// Assert that we return overscroll in the correct direction
MOZ_ASSERT((result.value * mFirstOverscrollAnimationSample.value) >= 0.0f);
@ -250,19 +250,32 @@ void Axis::StepOverscrollAnimation(double aStepDurationMilliseconds) {
// 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) {
if (mOverscroll != 0 && ((mOverscroll > 0 ? oldVelocity : -oldVelocity) <= 0.0f)) {
velocitySignChange = true;
}
}
if (velocitySignChange) {
bool oddOscillation = (mOverscroll.value * mFirstOverscrollAnimationSample.value) < 0.0f;
mOverscrollOffset = oddOscillation ? mOverscroll : -mOverscroll;
mLastOverscrollPeak = oddOscillation ? mOverscroll : -mOverscroll;
mOverscrollScale = 2.0f;
}
// Adjust the amount of overscroll based on the velocity.
// Note that we allow for oscillations.
mOverscroll += (mVelocity * aStepDurationMilliseconds);
// Our mechanism for translating a set of mOverscroll values that oscillate
// around zero to a set of GetOverscroll() values that have the same sign
// (so content is always stretched, never compressed) assumes that
// mOverscroll does not exceed mLastOverscrollPeak in magnitude. If our
// calculations were exact, this would be the case, as a dampened spring
// should never attain a displacement greater in magnitude than a previous
// peak. In our approximation calculations, however, this may not hold
// exactly. To ensure the assumption is not violated, we clamp the magnitude
// of mOverscroll.
if (mLastOverscrollPeak != 0 && fabs(mOverscroll) > fabs(mLastOverscrollPeak)) {
mOverscroll = (mOverscroll >= 0) ? fabs(mLastOverscrollPeak) : -fabs(mLastOverscrollPeak);
}
}
bool Axis::SampleOverscrollAnimation(const TimeDuration& aDelta) {
@ -314,7 +327,7 @@ bool Axis::IsOverscrolled() const {
void Axis::ClearOverscroll() {
mOverscroll = 0;
mFirstOverscrollAnimationSample = 0;
mOverscrollOffset = 0;
mLastOverscrollPeak = 0;
mOverscrollScale = 1.0f;
}

View File

@ -232,11 +232,12 @@ protected:
// 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.
// and mLastOverscrollPeak 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;
// mOverscrollScale will be 2.0 and mLastOverscrollPeak will store the amount
// of overscroll at the last peak of the oscillation. Together, these values
// guarantee that the result of GetOverscroll() never changes sign.
ParentLayerCoord mLastOverscrollPeak;
float mOverscrollScale;
// A queue of (timestamp, velocity) pairs; these are the historical