Bug 776149: Fix Gecko panning code to account for time deltas for displacements r=cjones

This commit is contained in:
Doug Sherk 2012-07-22 21:43:37 -04:00
parent 5f6437da3b
commit c856c6237b
3 changed files with 24 additions and 29 deletions

View File

@ -427,8 +427,8 @@ float AsyncPanZoomController::PanDistance(const MultiTouchInput& aEvent) {
SingleTouchData& touch = GetFirstSingleTouch(aEvent);
nsIntPoint point = touch.mScreenPoint;
PRInt32 xPos = point.x, yPos = point.y;
mX.UpdateWithTouchAtDevicePoint(xPos, 0);
mY.UpdateWithTouchAtDevicePoint(yPos, 0);
mX.UpdateWithTouchAtDevicePoint(xPos, TimeDuration(0));
mY.UpdateWithTouchAtDevicePoint(yPos, TimeDuration(0));
return NS_hypot(mX.PanDistance(), mY.PanDistance()) * mFrameMetrics.mResolution.width;
}
@ -442,10 +442,11 @@ const nsPoint AsyncPanZoomController::GetVelocityVector() {
void AsyncPanZoomController::TrackTouch(const MultiTouchInput& aEvent) {
SingleTouchData& touch = GetFirstSingleTouch(aEvent);
nsIntPoint point = touch.mScreenPoint;
PRInt32 xPos = point.x, yPos = point.y, timeDelta = aEvent.mTime - mLastEventTime;
PRInt32 xPos = point.x, yPos = point.y;
TimeDuration timeDelta = TimeDuration().FromMilliseconds(aEvent.mTime - mLastEventTime);
// Probably a duplicate event, just throw it away.
if (!timeDelta) {
if (timeDelta.ToMilliseconds() <= EPSILON) {
return;
}
@ -458,8 +459,8 @@ void AsyncPanZoomController::TrackTouch(const MultiTouchInput& aEvent) {
// larger swipe should move you a shorter distance.
float inverseScale = 1 / mFrameMetrics.mResolution.width;
PRInt32 xDisplacement = mX.UpdateAndGetDisplacement(inverseScale);
PRInt32 yDisplacement = mY.UpdateAndGetDisplacement(inverseScale);
PRInt32 xDisplacement = mX.GetDisplacementForDuration(inverseScale, timeDelta);
PRInt32 yDisplacement = mY.GetDisplacementForDuration(inverseScale, timeDelta);
if (!xDisplacement && !yDisplacement) {
return;
}
@ -494,8 +495,8 @@ bool AsyncPanZoomController::DoFling(const TimeDuration& aDelta) {
float inverseScale = 1 / mFrameMetrics.mResolution.width;
ScrollBy(nsIntPoint(
mX.UpdateAndGetDisplacement(inverseScale),
mY.UpdateAndGetDisplacement(inverseScale)
mX.GetDisplacementForDuration(inverseScale, aDelta),
mY.GetDisplacementForDuration(inverseScale, aDelta)
));
RequestContentRepaint();

View File

@ -10,13 +10,7 @@
namespace mozilla {
namespace layers {
static const float EPSILON = 0.0001;
/**
* Milliseconds per frame, used to judge how much displacement should have
* happened every frame based on the velocity calculated from touch events.
*/
static const float MS_PER_FRAME = 1000.0f / 60.0f;
static const float EPSILON = 0.0001f;
/**
* Maximum acceleration that can happen between two frames. Velocity is
@ -24,31 +18,31 @@ static const float MS_PER_FRAME = 1000.0f / 60.0f;
* or we get a touch point very far away from the previous position for some
* reason.
*/
static const float MAX_EVENT_ACCELERATION = 12;
static const float MAX_EVENT_ACCELERATION = 0.5f;
/**
* Amount of friction applied during flings when going above
* VELOCITY_THRESHOLD.
*/
static const float FLING_FRICTION_FAST = 0.010;
static const float FLING_FRICTION_FAST = 0.010f;
/**
* Amount of friction applied during flings when going below
* VELOCITY_THRESHOLD.
*/
static const float FLING_FRICTION_SLOW = 0.008;
static const float FLING_FRICTION_SLOW = 0.008f;
/**
* Maximum velocity before fling friction increases.
*/
static const float VELOCITY_THRESHOLD = 10;
static const float VELOCITY_THRESHOLD = 0.5f;
/**
* When flinging, if the velocity goes below this number, we just stop the
* animation completely. This is to prevent asymptotically approaching 0
* velocity and rerendering unnecessarily.
*/
static const float FLING_STOPPED_THRESHOLD = 0.1f;
static const float FLING_STOPPED_THRESHOLD = 0.01f;
Axis::Axis(AsyncPanZoomController* aAsyncPanZoomController)
: mPos(0.0f),
@ -58,10 +52,10 @@ Axis::Axis(AsyncPanZoomController* aAsyncPanZoomController)
}
void Axis::UpdateWithTouchAtDevicePoint(PRInt32 aPos, PRInt32 aTimeDelta) {
float newVelocity = MS_PER_FRAME * (mPos - aPos) / aTimeDelta;
void Axis::UpdateWithTouchAtDevicePoint(PRInt32 aPos, const TimeDuration& aTimeDelta) {
float newVelocity = (mPos - aPos) / aTimeDelta.ToMilliseconds();
bool curVelocityIsLow = fabsf(newVelocity) < 1.0f;
bool curVelocityIsLow = fabsf(newVelocity) < 0.01f;
bool directionChange = (mVelocity > 0) != (newVelocity != 0);
// If a direction change has happened, or the current velocity due to this new
@ -69,7 +63,7 @@ void Axis::UpdateWithTouchAtDevicePoint(PRInt32 aPos, PRInt32 aTimeDelta) {
if (curVelocityIsLow || (directionChange && fabs(newVelocity) - EPSILON <= 0.0f)) {
mVelocity = newVelocity;
} else {
float maxChange = fabsf(mVelocity * aTimeDelta * MAX_EVENT_ACCELERATION);
float maxChange = fabsf(mVelocity * aTimeDelta.ToMilliseconds() * MAX_EVENT_ACCELERATION);
mVelocity = NS_MIN(mVelocity + maxChange, NS_MAX(mVelocity - maxChange, newVelocity));
}
@ -83,8 +77,8 @@ void Axis::StartTouch(PRInt32 aPos) {
mVelocity = 0.0f;
}
PRInt32 Axis::UpdateAndGetDisplacement(float aScale) {
PRInt32 displacement = NS_lround(mVelocity * aScale);
PRInt32 Axis::GetDisplacementForDuration(float aScale, const TimeDuration& aDelta) {
PRInt32 displacement = NS_lround(mVelocity * aScale * aDelta.ToMilliseconds());
// If this displacement will cause an overscroll, throttle it. Can potentially
// bring it to 0 even if the velocity is high.
if (DisplacementWillOverscroll(displacement) != OVERSCROLL_NONE) {

View File

@ -43,7 +43,7 @@ public:
* indicating how long it has been since the previous one. This triggers a
* recalculation of velocity.
*/
void UpdateWithTouchAtDevicePoint(PRInt32 aPos, PRInt32 aTimeDelta);
void UpdateWithTouchAtDevicePoint(PRInt32 aPos, const TimeDuration& aTimeDelta);
/**
* Notify this Axis that a touch has begun, i.e. the user has put their finger
@ -61,14 +61,14 @@ public:
/**
* Gets displacement that should have happened since the previous touch.
* Note: Does not reset the displacement. It gets recalculated on the next
* updateWithTouchAtDevicePoint(), however it is not safe to assume this will
* UpdateWithTouchAtDevicePoint(), however it is not safe to assume this will
* be the same on every call. This also checks for page boundaries and will
* return an adjusted displacement to prevent the viewport from overscrolling
* the page rect. An example of where this might matter is when you call it,
* apply a displacement that takes you to the boundary of the page, then call
* it again. The result will be different in this case.
*/
PRInt32 UpdateAndGetDisplacement(float aScale);
PRInt32 GetDisplacementForDuration(float aScale, const TimeDuration& aDelta);
/**
* Gets the distance between the starting position of the touch supplied in