mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-30 00:01:50 +00:00
Bug 776226: Implement axis locking when panning along one axis r=roc
This commit is contained in:
parent
9c6ec8dfc6
commit
64c27116c3
@ -17,6 +17,10 @@
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
static const float EPSILON = 0.0001;
|
||||
|
||||
/**
|
||||
@ -37,6 +41,11 @@ static const PRInt32 FLING_REPAINT_INTERVAL = 75;
|
||||
*/
|
||||
static const float MIN_SKATE_SPEED = 0.5f;
|
||||
|
||||
/**
|
||||
* Angle from axis within which we stay axis-locked.
|
||||
*/
|
||||
static const float AXIS_LOCK_ANGLE = M_PI / 6.0;
|
||||
|
||||
AsyncPanZoomController::AsyncPanZoomController(GeckoContentController* aGeckoContentController,
|
||||
GestureBehavior aGestures)
|
||||
: mGeckoContentController(aGeckoContentController),
|
||||
@ -214,10 +223,6 @@ nsEventStatus AsyncPanZoomController::OnTouchStart(const MultiTouchInput& aEvent
|
||||
}
|
||||
|
||||
nsEventStatus AsyncPanZoomController::OnTouchMove(const MultiTouchInput& aEvent) {
|
||||
SingleTouchData& touch = GetFirstSingleTouch(aEvent);
|
||||
nsIntPoint point = touch.mScreenPoint;
|
||||
PRInt32 xPos = point.x, yPos = point.y;
|
||||
|
||||
switch (mState) {
|
||||
case FLING:
|
||||
case NOTHING:
|
||||
@ -226,14 +231,12 @@ nsEventStatus AsyncPanZoomController::OnTouchMove(const MultiTouchInput& aEvent)
|
||||
return nsEventStatus_eIgnore;
|
||||
|
||||
case TOUCHING: {
|
||||
float panThreshold = 1.0f/16.0f * mDPI;
|
||||
if (PanDistance(aEvent) < panThreshold) {
|
||||
float panThreshold = 1.0f/2.0f * mDPI;
|
||||
UpdateWithTouchAtDevicePoint(aEvent);
|
||||
if (PanDistance() < panThreshold) {
|
||||
return nsEventStatus_eIgnore;
|
||||
}
|
||||
mLastRepaint = aEvent.mTime;
|
||||
mX.StartTouch(xPos);
|
||||
mY.StartTouch(yPos);
|
||||
mState = PANNING;
|
||||
StartPanning(aEvent);
|
||||
return nsEventStatus_eConsumeNoDefault;
|
||||
}
|
||||
|
||||
@ -428,12 +431,7 @@ nsEventStatus AsyncPanZoomController::OnCancelTap(const TapGestureInput& aEvent)
|
||||
return nsEventStatus_eIgnore;
|
||||
}
|
||||
|
||||
float AsyncPanZoomController::PanDistance(const MultiTouchInput& aEvent) {
|
||||
SingleTouchData& touch = GetFirstSingleTouch(aEvent);
|
||||
nsIntPoint point = touch.mScreenPoint;
|
||||
PRInt32 xPos = point.x, yPos = point.y;
|
||||
mX.UpdateWithTouchAtDevicePoint(xPos, TimeDuration(0));
|
||||
mY.UpdateWithTouchAtDevicePoint(yPos, TimeDuration(0));
|
||||
float AsyncPanZoomController::PanDistance() {
|
||||
return NS_hypot(mX.PanDistance(), mY.PanDistance()) * mFrameMetrics.mResolution.width;
|
||||
}
|
||||
|
||||
@ -444,7 +442,28 @@ const nsPoint AsyncPanZoomController::GetVelocityVector() {
|
||||
);
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::TrackTouch(const MultiTouchInput& aEvent) {
|
||||
void AsyncPanZoomController::StartPanning(const MultiTouchInput& aEvent) {
|
||||
SingleTouchData& touch = GetFirstSingleTouch(aEvent);
|
||||
|
||||
float dx = mX.PanDistance(),
|
||||
dy = mY.PanDistance();
|
||||
|
||||
double angle = atan2(dy, dx); // range [-pi, pi]
|
||||
angle = fabs(angle); // range [0, pi]
|
||||
|
||||
mX.StartTouch(touch.mScreenPoint.x);
|
||||
mY.StartTouch(touch.mScreenPoint.y);
|
||||
mState = PANNING;
|
||||
mLastRepaint = aEvent.mTime;
|
||||
|
||||
if (angle < AXIS_LOCK_ANGLE || angle > (M_PI - AXIS_LOCK_ANGLE)) {
|
||||
mY.LockPanning();
|
||||
} else if (fabsf(angle - M_PI / 2) < AXIS_LOCK_ANGLE) {
|
||||
mX.LockPanning();
|
||||
}
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::UpdateWithTouchAtDevicePoint(const MultiTouchInput& aEvent) {
|
||||
SingleTouchData& touch = GetFirstSingleTouch(aEvent);
|
||||
nsIntPoint point = touch.mScreenPoint;
|
||||
PRInt32 xPos = point.x, yPos = point.y;
|
||||
@ -455,10 +474,22 @@ void AsyncPanZoomController::TrackTouch(const MultiTouchInput& aEvent) {
|
||||
return;
|
||||
}
|
||||
|
||||
mX.UpdateWithTouchAtDevicePoint(xPos, timeDelta);
|
||||
mY.UpdateWithTouchAtDevicePoint(yPos, timeDelta);
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::TrackTouch(const MultiTouchInput& aEvent) {
|
||||
TimeDuration timeDelta = TimeDuration().FromMilliseconds(aEvent.mTime - mLastEventTime);
|
||||
|
||||
// Probably a duplicate event, just throw it away.
|
||||
if (timeDelta.ToMilliseconds() <= EPSILON) {
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateWithTouchAtDevicePoint(aEvent);
|
||||
|
||||
{
|
||||
MonitorAutoLock monitor(mMonitor);
|
||||
mX.UpdateWithTouchAtDevicePoint(xPos, timeDelta);
|
||||
mY.UpdateWithTouchAtDevicePoint(yPos, timeDelta);
|
||||
|
||||
// We want to inversely scale it because when you're zoomed further in, a
|
||||
// larger swipe should move you a shorter distance.
|
||||
|
@ -264,7 +264,7 @@ protected:
|
||||
* current touch (this only makes sense if a touch is currently happening and
|
||||
* OnTouchMove() is being invoked).
|
||||
*/
|
||||
float PanDistance(const MultiTouchInput& aEvent);
|
||||
float PanDistance();
|
||||
|
||||
/**
|
||||
* Gets a vector of the velocities of each axis.
|
||||
@ -278,6 +278,18 @@ protected:
|
||||
*/
|
||||
SingleTouchData& GetFirstSingleTouch(const MultiTouchInput& aEvent);
|
||||
|
||||
/**
|
||||
* Sets up anything needed for panning. This may lock one of the axes if the
|
||||
* angle of movement is heavily skewed towards it.
|
||||
*/
|
||||
void StartPanning(const MultiTouchInput& aStartPoint);
|
||||
|
||||
/**
|
||||
* Wrapper for Axis::UpdateWithTouchAtDevicePoint(). Calls this function for
|
||||
* both axes and factors in the time delta from the last update.
|
||||
*/
|
||||
void UpdateWithTouchAtDevicePoint(const MultiTouchInput& aEvent);
|
||||
|
||||
/**
|
||||
* Does any panning required due to a new touch event.
|
||||
*/
|
||||
|
@ -47,12 +47,17 @@ static const float FLING_STOPPED_THRESHOLD = 0.01f;
|
||||
Axis::Axis(AsyncPanZoomController* aAsyncPanZoomController)
|
||||
: mPos(0.0f),
|
||||
mVelocity(0.0f),
|
||||
mAsyncPanZoomController(aAsyncPanZoomController)
|
||||
mAsyncPanZoomController(aAsyncPanZoomController),
|
||||
mLockPanning(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Axis::UpdateWithTouchAtDevicePoint(PRInt32 aPos, const TimeDuration& aTimeDelta) {
|
||||
if (mLockPanning) {
|
||||
return;
|
||||
}
|
||||
|
||||
float newVelocity = (mPos - aPos) / aTimeDelta.ToMilliseconds();
|
||||
|
||||
bool curVelocityIsLow = fabsf(newVelocity) < 0.01f;
|
||||
@ -75,6 +80,7 @@ void Axis::StartTouch(PRInt32 aPos) {
|
||||
mStartPos = aPos;
|
||||
mPos = aPos;
|
||||
mVelocity = 0.0f;
|
||||
mLockPanning = false;
|
||||
}
|
||||
|
||||
PRInt32 Axis::GetDisplacementForDuration(float aScale, const TimeDuration& aDelta) {
|
||||
@ -95,6 +101,10 @@ void Axis::StopTouch() {
|
||||
mVelocity = 0.0f;
|
||||
}
|
||||
|
||||
void Axis::LockPanning() {
|
||||
mLockPanning = true;
|
||||
}
|
||||
|
||||
bool Axis::FlingApplyFrictionOrCancel(const TimeDuration& aDelta) {
|
||||
if (fabsf(mVelocity) <= FLING_STOPPED_THRESHOLD) {
|
||||
// If the velocity is very low, just set it to 0 and stop the fling,
|
||||
|
@ -58,6 +58,14 @@ public:
|
||||
*/
|
||||
void StopTouch();
|
||||
|
||||
/**
|
||||
* Sets axis locking. This prevents any panning along this axis. If the
|
||||
* current touch point is updated and the axis is locked, the velocity will
|
||||
* not be recalculated. Any already-existing velocity will however stay the
|
||||
* same.
|
||||
*/
|
||||
void LockPanning();
|
||||
|
||||
/**
|
||||
* Gets displacement that should have happened since the previous touch.
|
||||
* Note: Does not reset the displacement. It gets recalculated on the next
|
||||
@ -164,6 +172,7 @@ protected:
|
||||
PRInt32 mStartPos;
|
||||
float mVelocity;
|
||||
nsRefPtr<AsyncPanZoomController> mAsyncPanZoomController;
|
||||
bool mLockPanning;
|
||||
};
|
||||
|
||||
class AxisX : public Axis {
|
||||
|
Loading…
Reference in New Issue
Block a user