Bug 826489 - Add preference based settings to AsyncZoomPanController. r=drs

This commit is contained in:
Oleg Romashin 2013-01-09 22:11:25 -08:00
parent bef2790ef8
commit 9a7f8ed729
4 changed files with 135 additions and 46 deletions

View File

@ -24,7 +24,13 @@ using namespace mozilla::css;
namespace mozilla {
namespace layers {
const float AsyncPanZoomController::TOUCH_START_TOLERANCE = 1.0f/16.0f;
/**
* Constant describing the tolerance in distance we use, multiplied by the
* device DPI, before we start panning the screen. This is to prevent us from
* accidentally processing taps as touch moves, and from very short/accidental
* touches moving the screen.
*/
static float gTouchStartTolerance = 1.0f/16.0f;
static const float EPSILON = 0.0001;
@ -32,19 +38,19 @@ static const float EPSILON = 0.0001;
* Maximum amount of time while panning before sending a viewport change. This
* will asynchronously repaint the page. It is also forced when panning stops.
*/
static const int32_t PAN_REPAINT_INTERVAL = 250;
static int32_t gPanRepaintInterval = 250;
/**
* Maximum amount of time flinging before sending a viewport change. This will
* asynchronously repaint the page.
*/
static const int32_t FLING_REPAINT_INTERVAL = 75;
static int32_t gFlingRepaintInterval = 75;
/**
* Minimum amount of speed along an axis before we begin painting far ahead by
* adjusting the displayport.
*/
static const float MIN_SKATE_SPEED = 0.7f;
static float gMinSkateSpeed = 0.7f;
/**
* Duration of a zoom to animation.
@ -72,13 +78,68 @@ static const double MIN_ZOOM = 0.125;
* time, we will just pretend that content did not preventDefault any touch
* events we dispatched to it.
*/
static const int TOUCH_LISTENER_TIMEOUT = 300;
static int gTouchListenerTimeout = 300;
/**
* Number of samples to store of how long it took to paint after the previous
* requests.
*/
static const int NUM_PAINT_DURATION_SAMPLES = 3;
static int gNumPaintDurationSamples = 3;
/** The multiplier we apply to a dimension's length if it is skating. That is,
* if it's going above sMinSkateSpeed. We prefer to increase the size of the
* Y axis because it is more natural in the case that a user is reading a page
* that scrolls up/down. Note that one, both or neither of these may be used
* at any instant.
*/
static float gXSkateSizeMultiplier = 3.0f;
static float gYSkateSizeMultiplier = 3.5f;
/** The multiplier we apply to a dimension's length if it is stationary. We
* prefer to increase the size of the Y axis because it is more natural in the
* case that a user is reading a page that scrolls up/down. Note that one,
* both or neither of these may be used at any instant.
*/
static float gXStationarySizeMultiplier = 1.5f;
static float gYStationarySizeMultiplier = 2.5f;
static void ReadAZPCPrefs()
{
Preferences::AddIntVarCache(&gPanRepaintInterval, "gfx.azpc.pan_repaint_interval", gPanRepaintInterval);
Preferences::AddIntVarCache(&gFlingRepaintInterval, "gfx.azpc.fling_repaint_interval", gFlingRepaintInterval);
Preferences::AddFloatVarCache(&gMinSkateSpeed, "gfx.azpc.min_skate_speed", gMinSkateSpeed);
Preferences::AddIntVarCache(&gTouchListenerTimeout, "gfx.azpc.touch_listener_timeout", gTouchListenerTimeout);
Preferences::AddIntVarCache(&gNumPaintDurationSamples, "gfx.azpc.num_paint_duration_samples", gNumPaintDurationSamples);
Preferences::AddFloatVarCache(&gTouchStartTolerance, "gfx.azpc.touch_start_tolerance", gTouchStartTolerance);
Preferences::AddFloatVarCache(&gXSkateSizeMultiplier, "gfx.azpc.x_skate_size_multiplier", gXSkateSizeMultiplier);
Preferences::AddFloatVarCache(&gYSkateSizeMultiplier, "gfx.azpc.y_skate_size_multiplier", gYSkateSizeMultiplier);
Preferences::AddFloatVarCache(&gXStationarySizeMultiplier, "gfx.azpc.x_stationary_size_multiplier", gXStationarySizeMultiplier);
Preferences::AddFloatVarCache(&gYStationarySizeMultiplier, "gfx.azpc.y_stationary_size_multiplier", gYStationarySizeMultiplier);
}
class ReadAZPCPref MOZ_FINAL : public nsRunnable {
public:
NS_IMETHOD Run()
{
ReadAZPCPrefs();
return NS_OK;
}
};
static void InitAZPCPrefs()
{
static bool sInitialized = false;
if (sInitialized)
return;
sInitialized = true;
if (NS_IsMainThread()) {
ReadAZPCPrefs();
} else {
// We have to dispatch an event to the main thread to read the pref.
NS_DispatchToMainThread(new ReadAZPCPref());
}
}
AsyncPanZoomController::AsyncPanZoomController(GeckoContentController* aGeckoContentController,
GestureBehavior aGestures)
@ -106,6 +167,9 @@ AsyncPanZoomController::AsyncPanZoomController(GeckoContentController* aGeckoCon
mDelayPanning(false)
{
MOZ_ASSERT(NS_IsMainThread());
InitAZPCPrefs();
if (aGestures == USE_GESTURE_DETECTOR) {
mGestureEventListener = new GestureEventListener(this);
}
@ -127,6 +191,12 @@ AsyncPanZoomController::~AsyncPanZoomController() {
}
/* static */float
AsyncPanZoomController::GetTouchStartTolerance()
{
return gTouchStartTolerance;
}
static gfx::Point
WidgetSpaceToCompensatedViewportSpace(const gfx::Point& aPoint,
gfxFloat aCurrentZoom)
@ -231,7 +301,7 @@ nsEventStatus AsyncPanZoomController::ReceiveInputEvent(const InputData& aEvent)
MessageLoop::current()->PostDelayedTask(
FROM_HERE,
mTouchListenerTimeoutTask,
TOUCH_LISTENER_TIMEOUT);
gTouchListenerTimeout);
}
}
return nsEventStatus_eConsumeNoDefault;
@ -263,7 +333,7 @@ nsEventStatus AsyncPanZoomController::HandleInputEvent(const InputData& aEvent)
MessageLoop::current()->PostDelayedTask(
FROM_HERE,
mTouchListenerTimeoutTask,
TOUCH_LISTENER_TIMEOUT);
gTouchListenerTimeout);
}
return nsEventStatus_eConsumeNoDefault;
}
@ -364,7 +434,7 @@ nsEventStatus AsyncPanZoomController::OnTouchMove(const MultiTouchInput& aEvent)
return nsEventStatus_eIgnore;
case TOUCHING: {
float panThreshold = TOUCH_START_TOLERANCE * mDPI;
float panThreshold = gTouchStartTolerance * mDPI;
UpdateWithTouchAtDevicePoint(aEvent);
if (PanDistance() < panThreshold) {
@ -697,7 +767,7 @@ void AsyncPanZoomController::TrackTouch(const MultiTouchInput& aEvent) {
ScheduleComposite();
TimeDuration timePaintDelta = TimeStamp::Now() - mPreviousPaintStartTime;
if (timePaintDelta.ToMilliseconds() > PAN_REPAINT_INTERVAL) {
if (timePaintDelta.ToMilliseconds() > gPanRepaintInterval) {
RequestContentRepaint();
}
}
@ -734,7 +804,7 @@ bool AsyncPanZoomController::DoFling(const TimeDuration& aDelta) {
mY.GetDisplacementForDuration(inverseResolution, aDelta)
));
TimeDuration timePaintDelta = TimeStamp::Now() - mPreviousPaintStartTime;
if (timePaintDelta.ToMilliseconds() > FLING_REPAINT_INTERVAL) {
if (timePaintDelta.ToMilliseconds() > gFlingRepaintInterval) {
RequestContentRepaint();
}
@ -803,7 +873,7 @@ bool AsyncPanZoomController::EnlargeDisplayPortAlongAxis(float aSkateSizeMultipl
float* aDisplayPortOffset,
float* aDisplayPortLength)
{
if (fabsf(aVelocity) > MIN_SKATE_SPEED) {
if (fabsf(aVelocity) > gMinSkateSpeed) {
// Enlarge the area we paint.
*aDisplayPortLength = aCompositionBounds * aSkateSizeMultiplier;
// Position the area we paint such that all of the excess that extends past
@ -835,21 +905,6 @@ const gfx::Rect AsyncPanZoomController::CalculatePendingDisplayPort(
const gfx::Point& aAcceleration,
double aEstimatedPaintDuration)
{
// The multiplier we apply to a dimension's length if it is skating. That is,
// if it's going above MIN_SKATE_SPEED. We prefer to increase the size of the
// Y axis because it is more natural in the case that a user is reading a page
// that scrolls up/down. Note that one, both or neither of these may be used
// at any instant.
const float X_SKATE_SIZE_MULTIPLIER = 3.0f;
const float Y_SKATE_SIZE_MULTIPLIER = 3.5f;
// The multiplier we apply to a dimension's length if it is stationary. We
// prefer to increase the size of the Y axis because it is more natural in the
// case that a user is reading a page that scrolls up/down. Note that one,
// both or neither of these may be used at any instant.
const float X_STATIONARY_SIZE_MULTIPLIER = 1.5f;
const float Y_STATIONARY_SIZE_MULTIPLIER = 2.5f;
// If we don't get an estimated paint duration, we probably don't have any
// data. In this case, we're dealing with either a stationary frame or a first
// paint. In either of these cases, we can just assume it'll take 1 second to
@ -866,18 +921,18 @@ const gfx::Rect AsyncPanZoomController::CalculatePendingDisplayPort(
gfx::Point scrollOffset = aFrameMetrics.mScrollOffset;
gfx::Rect displayPort(0, 0,
compositionBounds.width * X_STATIONARY_SIZE_MULTIPLIER,
compositionBounds.height * Y_STATIONARY_SIZE_MULTIPLIER);
compositionBounds.width * gXStationarySizeMultiplier,
compositionBounds.height * gYStationarySizeMultiplier);
// If there's motion along an axis of movement, and it's above a threshold,
// then we want to paint a larger area in the direction of that motion so that
// it's less likely to checkerboard.
bool enlargedX = EnlargeDisplayPortAlongAxis(
X_SKATE_SIZE_MULTIPLIER, estimatedPaintDuration,
gXSkateSizeMultiplier, estimatedPaintDuration,
compositionBounds.width, aVelocity.x, aAcceleration.x,
&displayPort.x, &displayPort.width);
bool enlargedY = EnlargeDisplayPortAlongAxis(
Y_SKATE_SIZE_MULTIPLIER, estimatedPaintDuration,
gYSkateSizeMultiplier, estimatedPaintDuration,
compositionBounds.height, aVelocity.y, aAcceleration.y,
&displayPort.y, &displayPort.height);
@ -1162,7 +1217,7 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aViewportFr
if (mWaitingForContentToPaint) {
// Remove the oldest sample we have if adding a new sample takes us over our
// desired number of samples.
if (mPreviousPaintDurations.Length() >= NUM_PAINT_DURATION_SAMPLES) {
if (mPreviousPaintDurations.Length() >= gNumPaintDurationSamples) {
mPreviousPaintDurations.RemoveElementAt(0);
}

View File

@ -68,7 +68,7 @@ public:
* accidentally processing taps as touch moves, and from very short/accidental
* touches moving the screen.
*/
static const float TOUCH_START_TOLERANCE;
static float GetTouchStartTolerance();
AsyncPanZoomController(GeckoContentController* aController,
GestureBehavior aGestures = DEFAULT_GESTURES);

View File

@ -6,6 +6,7 @@
#include "Axis.h"
#include "AsyncPanZoomController.h"
#include "mozilla/Preferences.h"
namespace mozilla {
namespace layers {
@ -18,18 +19,18 @@ static const float EPSILON = 0.0001f;
* or we get a touch point very far away from the previous position for some
* reason.
*/
static const float MAX_EVENT_ACCELERATION = 999.0f;
static float gMaxEventAcceleration = 999.0f;
/**
* Amount of friction applied during flings.
*/
static const float FLING_FRICTION = 0.007f;
static float gFlingFriction = 0.007f;
/**
* Threshold for velocity beneath which we turn off any acceleration we had
* during repeated flings.
*/
static const float VELOCITY_THRESHOLD = 0.14f;
static float gVelocityThreshold = 0.14f;
/**
* Amount of acceleration we multiply in each time the user flings in one
@ -39,14 +40,47 @@ static const float VELOCITY_THRESHOLD = 0.14f;
* slow down enough, or if they put their finger down without moving it for a
* moment (or in the opposite direction).
*/
static const float ACCELERATION_MULTIPLIER = 1.125f;
static float gAccelerationMultiplier = 1.125f;
/**
* 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.01f;
static float gFlingStoppedThreshold = 0.01f;
static void ReadAxisPrefs()
{
Preferences::AddFloatVarCache(&gMaxEventAcceleration, "gfx.axis.max_event_acceleration", gMaxEventAcceleration);
Preferences::AddFloatVarCache(&gFlingFriction, "gfx.axis.fling_friction", gFlingFriction);
Preferences::AddFloatVarCache(&gVelocityThreshold, "gfx.axis.velocity_threshold", gVelocityThreshold);
Preferences::AddFloatVarCache(&gAccelerationMultiplier, "gfx.axis.acceleration_multiplier", gAccelerationMultiplier);
Preferences::AddFloatVarCache(&gFlingStoppedThreshold, "gfx.axis.fling_stopped_threshold", gFlingStoppedThreshold);
}
class ReadAxisPref MOZ_FINAL : public nsRunnable {
public:
NS_IMETHOD Run()
{
ReadAxisPrefs();
return NS_OK;
}
};
static void InitAxisPrefs()
{
static bool sInitialized = false;
if (sInitialized)
return;
sInitialized = true;
if (NS_IsMainThread()) {
ReadAxisPrefs();
} else {
// We have to dispatch an event to the main thread to read the pref.
NS_DispatchToMainThread(new ReadAxisPref());
}
}
Axis::Axis(AsyncPanZoomController* aAsyncPanZoomController)
: mPos(0.0f),
@ -54,14 +88,14 @@ Axis::Axis(AsyncPanZoomController* aAsyncPanZoomController)
mAcceleration(0),
mAsyncPanZoomController(aAsyncPanZoomController)
{
InitAxisPrefs();
}
void Axis::UpdateWithTouchAtDevicePoint(int32_t aPos, const TimeDuration& aTimeDelta) {
float newVelocity = (mPos - aPos) / aTimeDelta.ToMilliseconds();
bool curVelocityIsLow = fabsf(newVelocity) < 0.01f;
bool curVelocityBelowThreshold = fabsf(newVelocity) < VELOCITY_THRESHOLD;
bool curVelocityBelowThreshold = fabsf(newVelocity) < gVelocityThreshold;
bool directionChange = (mVelocity > 0) != (newVelocity > 0);
// If we've changed directions, or the current velocity threshold, stop any
@ -75,7 +109,7 @@ void Axis::UpdateWithTouchAtDevicePoint(int32_t aPos, const TimeDuration& aTimeD
if (curVelocityIsLow || (directionChange && fabs(newVelocity) - EPSILON <= 0.0f)) {
mVelocity = newVelocity;
} else {
float maxChange = fabsf(mVelocity * aTimeDelta.ToMilliseconds() * MAX_EVENT_ACCELERATION);
float maxChange = fabsf(mVelocity * aTimeDelta.ToMilliseconds() * gMaxEventAcceleration);
mVelocity = NS_MIN(mVelocity + maxChange, NS_MAX(mVelocity - maxChange, newVelocity));
}
@ -89,7 +123,7 @@ void Axis::StartTouch(int32_t aPos) {
}
float Axis::GetDisplacementForDuration(float aScale, const TimeDuration& aDelta) {
if (fabsf(mVelocity) < VELOCITY_THRESHOLD) {
if (fabsf(mVelocity) < gVelocityThreshold) {
mAcceleration = 0;
}
@ -121,14 +155,14 @@ void Axis::CancelTouch() {
}
bool Axis::FlingApplyFrictionOrCancel(const TimeDuration& aDelta) {
if (fabsf(mVelocity) <= FLING_STOPPED_THRESHOLD) {
if (fabsf(mVelocity) <= gFlingStoppedThreshold) {
// If the velocity is very low, just set it to 0 and stop the fling,
// otherwise we'll just asymptotically approach 0 and the user won't
// actually see any changes.
mVelocity = 0.0f;
return false;
} else {
mVelocity *= NS_MAX(1.0f - FLING_FRICTION * aDelta.ToMilliseconds(), 0.0);
mVelocity *= NS_MAX(1.0f - gFlingFriction * aDelta.ToMilliseconds(), 0.0);
}
return true;
}
@ -226,7 +260,7 @@ float Axis::GetVelocity() {
}
float Axis::GetAccelerationFactor() {
return powf(ACCELERATION_MULTIPLIER, NS_MAX(0, (mAcceleration - 4) * 3));
return powf(gAccelerationMultiplier, NS_MAX(0, (mAcceleration - 4) * 3));
}
float Axis::GetCompositionEnd() {

View File

@ -105,7 +105,7 @@ nsEventStatus GestureEventListener::HandleInputEvent(const InputData& aEvent)
nsIntPoint touch = (nsIntPoint&)event.mTouches[0].mScreenPoint;
if (mTouches.Length() == 1 &&
NS_hypot(mTouchStartPosition.x - touch.x, mTouchStartPosition.y - touch.y) >
mAsyncPanZoomController->GetDPI() * AsyncPanZoomController::TOUCH_START_TOLERANCE)
mAsyncPanZoomController->GetDPI() * mAsyncPanZoomController->GetTouchStartTolerance())
{
HandleTapCancel(event);
}