зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1451461 - Make pinch locking unaffected by input sensitivity. r=botond
Implements a 50ms buffer of scale events in APZC, so pinch locking code can consider gesture movement over a fixed length of time. Previously, pinch locking was sensitive to event frequency (which is determined by the sensitivity of the input device). * New class InputBuffer wraps std::deque * New field APZC::mPinchEventBuffer * New gfxPref APZPinchLockBufferMaxAge --HG-- extra : rebase_source : a44da4c3ce971fee1b0f401357f47f994a9145df
This commit is contained in:
Родитель
1b790f3246
Коммит
6123e5062e
|
@ -415,6 +415,13 @@ typedef PlatformSpecificStateBase
|
||||||
* and scrolls more than apz.pinch_lock.scroll_lock_threshold.\n
|
* and scrolls more than apz.pinch_lock.scroll_lock_threshold.\n
|
||||||
* Units: (real-world, i.e. screen) inches measured between two touch points
|
* Units: (real-world, i.e. screen) inches measured between two touch points
|
||||||
*
|
*
|
||||||
|
* \li\b apz.pinch_lock.buffer_max_age
|
||||||
|
* To ensure that pinch locking threshold calculations are not affected by
|
||||||
|
* variations in touch screen sensitivity, calculations draw from a buffer of
|
||||||
|
* recent events. This preference specifies the maximum time that events are
|
||||||
|
* held in this buffer.
|
||||||
|
* Units: milliseconds
|
||||||
|
*
|
||||||
* \li\b apz.popups.enabled
|
* \li\b apz.popups.enabled
|
||||||
* Determines whether APZ is used for XUL popup widgets with remote content.
|
* Determines whether APZ is used for XUL popup widgets with remote content.
|
||||||
* Ideally, this should always be true, but it is currently not well tested, and
|
* Ideally, this should always be true, but it is currently not well tested, and
|
||||||
|
@ -800,6 +807,8 @@ AsyncPanZoomController::AsyncPanZoomController(
|
||||||
mY(this),
|
mY(this),
|
||||||
mPanDirRestricted(false),
|
mPanDirRestricted(false),
|
||||||
mPinchLocked(false),
|
mPinchLocked(false),
|
||||||
|
mPinchEventBuffer(
|
||||||
|
TimeDuration::FromMilliseconds(gfxPrefs::APZPinchLockBufferMaxAge())),
|
||||||
mZoomConstraints(false, false,
|
mZoomConstraints(false, false,
|
||||||
Metrics().GetDevPixelsPerCSSPixel() * kViewportMinScale /
|
Metrics().GetDevPixelsPerCSSPixel() * kViewportMinScale /
|
||||||
ParentLayerToScreenScale(1),
|
ParentLayerToScreenScale(1),
|
||||||
|
@ -1515,6 +1524,8 @@ nsEventStatus AsyncPanZoomController::OnScaleBegin(
|
||||||
mLastZoomFocus =
|
mLastZoomFocus =
|
||||||
aEvent.mLocalFocusPoint - Metrics().GetCompositionBounds().TopLeft();
|
aEvent.mLocalFocusPoint - Metrics().GetCompositionBounds().TopLeft();
|
||||||
|
|
||||||
|
mPinchEventBuffer.push(aEvent);
|
||||||
|
|
||||||
return nsEventStatus_eConsumeNoDefault;
|
return nsEventStatus_eConsumeNoDefault;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1530,22 +1541,8 @@ nsEventStatus AsyncPanZoomController::OnScale(const PinchGestureInput& aEvent) {
|
||||||
return nsEventStatus_eConsumeNoDefault;
|
return nsEventStatus_eConsumeNoDefault;
|
||||||
}
|
}
|
||||||
|
|
||||||
ParentLayerCoord spanDistance =
|
mPinchEventBuffer.push(aEvent);
|
||||||
fabsf(aEvent.mPreviousSpan - aEvent.mCurrentSpan);
|
HandlePinchLocking();
|
||||||
ParentLayerPoint focusPoint, focusChange;
|
|
||||||
{
|
|
||||||
RecursiveMutexAutoLock lock(mRecursiveMutex);
|
|
||||||
|
|
||||||
focusPoint =
|
|
||||||
aEvent.mLocalFocusPoint - Metrics().GetCompositionBounds().TopLeft();
|
|
||||||
focusChange = mLastZoomFocus - focusPoint;
|
|
||||||
mLastZoomFocus = focusPoint;
|
|
||||||
}
|
|
||||||
|
|
||||||
HandlePinchLocking(
|
|
||||||
ToScreenCoordinates(ParentLayerPoint(0, spanDistance), focusPoint)
|
|
||||||
.Length(),
|
|
||||||
ToScreenCoordinates(focusChange, focusPoint));
|
|
||||||
bool allowZoom = mZoomConstraints.mAllowZoom && !mPinchLocked;
|
bool allowZoom = mZoomConstraints.mAllowZoom && !mPinchLocked;
|
||||||
|
|
||||||
// If zooming is not allowed, this is a two-finger pan.
|
// If zooming is not allowed, this is a two-finger pan.
|
||||||
|
@ -1581,8 +1578,12 @@ nsEventStatus AsyncPanZoomController::OnScale(const PinchGestureInput& aEvent) {
|
||||||
RecursiveMutexAutoLock lock(mRecursiveMutex);
|
RecursiveMutexAutoLock lock(mRecursiveMutex);
|
||||||
|
|
||||||
CSSToParentLayerScale userZoom = Metrics().GetZoom().ToScaleFactor();
|
CSSToParentLayerScale userZoom = Metrics().GetZoom().ToScaleFactor();
|
||||||
|
ParentLayerPoint focusPoint =
|
||||||
|
aEvent.mLocalFocusPoint - Metrics().GetCompositionBounds().TopLeft();
|
||||||
CSSPoint cssFocusPoint = focusPoint / Metrics().GetZoom();
|
CSSPoint cssFocusPoint = focusPoint / Metrics().GetZoom();
|
||||||
|
|
||||||
|
ParentLayerPoint focusChange = mLastZoomFocus - focusPoint;
|
||||||
|
mLastZoomFocus = focusPoint;
|
||||||
// If displacing by the change in focus point will take us off page bounds,
|
// If displacing by the change in focus point will take us off page bounds,
|
||||||
// then reduce the displacement such that it doesn't.
|
// then reduce the displacement such that it doesn't.
|
||||||
focusChange.x -= mX.DisplacementWillOverscrollAmount(focusChange.x);
|
focusChange.x -= mX.DisplacementWillOverscrollAmount(focusChange.x);
|
||||||
|
@ -1701,6 +1702,8 @@ nsEventStatus AsyncPanZoomController::OnScaleEnd(
|
||||||
UpdateSharedCompositorFrameMetrics();
|
UpdateSharedCompositorFrameMetrics();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mPinchEventBuffer.clear();
|
||||||
|
|
||||||
// Non-negative focus point would indicate that one finger is still down
|
// Non-negative focus point would indicate that one finger is still down
|
||||||
if (aEvent.mLocalFocusPoint != PinchGestureInput::BothFingersLifted()) {
|
if (aEvent.mLocalFocusPoint != PinchGestureInput::BothFingersLifted()) {
|
||||||
if (mZoomConstraints.mAllowZoom) {
|
if (mZoomConstraints.mAllowZoom) {
|
||||||
|
@ -2932,8 +2935,38 @@ void AsyncPanZoomController::HandlePanningUpdate(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncPanZoomController::HandlePinchLocking(ScreenCoord spanDistance,
|
void AsyncPanZoomController::HandlePinchLocking() {
|
||||||
ScreenPoint focusChange) {
|
// Focus change and span distance calculated from an event buffer
|
||||||
|
// Used to handle pinch locking irrespective of touch screen sensitivity
|
||||||
|
// Note: both values fall back to the same value as
|
||||||
|
// their un-buffered counterparts if there is only one (the latest)
|
||||||
|
// event in the buffer. ie: when the touch screen is dispatching
|
||||||
|
// events slower than the lifetime of the buffer
|
||||||
|
ParentLayerCoord bufferedSpanDistance;
|
||||||
|
ParentLayerPoint focusPoint, bufferedFocusChange;
|
||||||
|
{
|
||||||
|
RecursiveMutexAutoLock lock(mRecursiveMutex);
|
||||||
|
|
||||||
|
focusPoint = mPinchEventBuffer.back().mLocalFocusPoint -
|
||||||
|
Metrics().GetCompositionBounds().TopLeft();
|
||||||
|
ParentLayerPoint bufferedLastZoomFocus =
|
||||||
|
(mPinchEventBuffer.size() > 1)
|
||||||
|
? mPinchEventBuffer.front().mLocalFocusPoint -
|
||||||
|
Metrics().GetCompositionBounds().TopLeft()
|
||||||
|
: mLastZoomFocus;
|
||||||
|
|
||||||
|
bufferedFocusChange = bufferedLastZoomFocus - focusPoint;
|
||||||
|
bufferedSpanDistance = fabsf(mPinchEventBuffer.front().mPreviousSpan -
|
||||||
|
mPinchEventBuffer.back().mCurrentSpan);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert to screen coordinates
|
||||||
|
ScreenCoord spanDistance =
|
||||||
|
ToScreenCoordinates(ParentLayerPoint(0, bufferedSpanDistance), focusPoint)
|
||||||
|
.Length();
|
||||||
|
ScreenPoint focusChange =
|
||||||
|
ToScreenCoordinates(bufferedFocusChange, focusPoint);
|
||||||
|
|
||||||
if (mPinchLocked) {
|
if (mPinchLocked) {
|
||||||
if (GetPinchLockMode() == PINCH_STICKY) {
|
if (GetPinchLockMode() == PINCH_STICKY) {
|
||||||
ScreenCoord spanBreakoutThreshold =
|
ScreenCoord spanBreakoutThreshold =
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include "nsRegion.h"
|
#include "nsRegion.h"
|
||||||
#include "nsTArray.h"
|
#include "nsTArray.h"
|
||||||
#include "PotentialCheckerboardDurationTracker.h"
|
#include "PotentialCheckerboardDurationTracker.h"
|
||||||
|
#include "RecentEventsBuffer.h" // for RecentEventsBuffer
|
||||||
|
|
||||||
#include "base/message_loop.h"
|
#include "base/message_loop.h"
|
||||||
|
|
||||||
|
@ -795,7 +796,7 @@ class AsyncPanZoomController {
|
||||||
/**
|
/**
|
||||||
* Set and update the pinch lock
|
* Set and update the pinch lock
|
||||||
*/
|
*/
|
||||||
void HandlePinchLocking(ScreenCoord spanDistance, ScreenPoint focusChange);
|
void HandlePinchLocking();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets up anything needed for panning. This takes us out of the "TOUCHING"
|
* Sets up anything needed for panning. This takes us out of the "TOUCHING"
|
||||||
|
@ -983,6 +984,12 @@ class AsyncPanZoomController {
|
||||||
// is performing a two-finger pan rather than a pinch gesture
|
// is performing a two-finger pan rather than a pinch gesture
|
||||||
bool mPinchLocked;
|
bool mPinchLocked;
|
||||||
|
|
||||||
|
// Stores the pinch events that occured within a given timeframe. Used to
|
||||||
|
// calculate the focusChange and spanDistance within a fixed timeframe.
|
||||||
|
// RecentEventsBuffer is not threadsafe. Should only be accessed on the
|
||||||
|
// controller thread.
|
||||||
|
RecentEventsBuffer<PinchGestureInput> mPinchEventBuffer;
|
||||||
|
|
||||||
// Most up-to-date constraints on zooming. These should always be reasonable
|
// Most up-to-date constraints on zooming. These should always be reasonable
|
||||||
// values; for example, allowing a min zoom of 0.0 can cause very bad things
|
// values; for example, allowing a min zoom of 0.0 can cause very bad things
|
||||||
// to happen.
|
// to happen.
|
||||||
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef mozilla_layers_RecentEventsBuffer_h
|
||||||
|
#define mozilla_layers_RecentEventsBuffer_h
|
||||||
|
|
||||||
|
#include <deque>
|
||||||
|
|
||||||
|
#include "mozilla/TimeStamp.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace layers {
|
||||||
|
/**
|
||||||
|
* RecentEventsBuffer: maintains an age constrained buffer of events
|
||||||
|
*
|
||||||
|
* Intended for use with elements of type InputData, but the only requirement
|
||||||
|
* is a member "mTimeStamp" of type TimeStamp
|
||||||
|
*/
|
||||||
|
template <typename Event>
|
||||||
|
class RecentEventsBuffer {
|
||||||
|
public:
|
||||||
|
explicit RecentEventsBuffer(TimeDuration maxAge);
|
||||||
|
|
||||||
|
void push(Event event);
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
typedef typename std::deque<Event>::size_type size_type;
|
||||||
|
size_type size() { return mBuffer.size(); }
|
||||||
|
|
||||||
|
// Delegate to container for iterators
|
||||||
|
typedef typename std::deque<Event>::iterator iterator;
|
||||||
|
typedef typename std::deque<Event>::const_iterator const_iterator;
|
||||||
|
iterator begin() { return mBuffer.begin(); }
|
||||||
|
iterator end() { return mBuffer.end(); }
|
||||||
|
const_iterator cbegin() const { return mBuffer.cbegin(); }
|
||||||
|
const_iterator cend() const { return mBuffer.cend(); }
|
||||||
|
|
||||||
|
// Also delegate for front/back
|
||||||
|
typedef typename std::deque<Event>::reference reference;
|
||||||
|
typedef typename std::deque<Event>::const_reference const_reference;
|
||||||
|
reference front() { return mBuffer.front(); }
|
||||||
|
reference back() { return mBuffer.back(); }
|
||||||
|
const_reference front() const { return mBuffer.front(); }
|
||||||
|
const_reference back() const { return mBuffer.back(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
TimeDuration mMaxAge;
|
||||||
|
std::deque<Event> mBuffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Event>
|
||||||
|
RecentEventsBuffer<Event>::RecentEventsBuffer(TimeDuration maxAge)
|
||||||
|
: mMaxAge(maxAge), mBuffer() {}
|
||||||
|
|
||||||
|
template <typename Event>
|
||||||
|
void RecentEventsBuffer<Event>::push(Event event) {
|
||||||
|
// Events must be pushed in chronological order
|
||||||
|
MOZ_ASSERT(mBuffer.empty() || mBuffer.back().mTimeStamp <= event.mTimeStamp);
|
||||||
|
|
||||||
|
mBuffer.push_back(event);
|
||||||
|
|
||||||
|
// Flush all events older than the given lifetime
|
||||||
|
TimeStamp bound = event.mTimeStamp - mMaxAge;
|
||||||
|
while (!mBuffer.empty()) {
|
||||||
|
if (mBuffer.front().mTimeStamp >= bound) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
mBuffer.pop_front();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Event>
|
||||||
|
void RecentEventsBuffer<Event>::clear() {
|
||||||
|
mBuffer.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace layers
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif // mozilla_layers_RecentEventsBuffer_h
|
|
@ -62,6 +62,15 @@ inline SingleTouchData CreateSingleTouchData(int32_t aIdentifier,
|
||||||
return CreateSingleTouchData(aIdentifier, ScreenIntPoint(aX, aY));
|
return CreateSingleTouchData(aIdentifier, ScreenIntPoint(aX, aY));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline PinchGestureInput CreatePinchGestureInput(
|
||||||
|
PinchGestureInput::PinchGestureType aType, const ScreenPoint& aFocus,
|
||||||
|
float aCurrentSpan, float aPreviousSpan, TimeStamp timestamp) {
|
||||||
|
ParentLayerPoint localFocus(aFocus.x, aFocus.y);
|
||||||
|
PinchGestureInput result(aType, 0, timestamp, ExternalPoint(0, 0), aFocus,
|
||||||
|
aCurrentSpan, aPreviousSpan, 0);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
template <class SetArg, class Storage>
|
template <class SetArg, class Storage>
|
||||||
class ScopedGfxSetting {
|
class ScopedGfxSetting {
|
||||||
public:
|
public:
|
||||||
|
@ -450,6 +459,18 @@ class APZCTesterBase : public ::testing::Test {
|
||||||
float aScale, int& inputId, bool aShouldTriggerPinch,
|
float aScale, int& inputId, bool aShouldTriggerPinch,
|
||||||
nsTArray<uint32_t>* aAllowedTouchBehaviors);
|
nsTArray<uint32_t>* aAllowedTouchBehaviors);
|
||||||
|
|
||||||
|
template <class InputReceiver>
|
||||||
|
void PinchWithPinchInput(const RefPtr<InputReceiver>& aTarget,
|
||||||
|
const ScreenIntPoint& aFocus,
|
||||||
|
const ScreenIntPoint& aSecondFocus, float aScale,
|
||||||
|
nsEventStatus (*aOutEventStatuses)[3] = nullptr);
|
||||||
|
|
||||||
|
template <class InputReceiver>
|
||||||
|
void PinchWithPinchInputAndCheckStatus(const RefPtr<InputReceiver>& aTarget,
|
||||||
|
const ScreenIntPoint& aFocus,
|
||||||
|
float aScale,
|
||||||
|
bool aShouldTriggerPinch);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
RefPtr<MockContentControllerDelayed> mcc;
|
RefPtr<MockContentControllerDelayed> mcc;
|
||||||
};
|
};
|
||||||
|
@ -798,6 +819,57 @@ void APZCTesterBase::PinchWithTouchInputAndCheckStatus(
|
||||||
EXPECT_EQ(expectedMoveStatus, statuses[2]);
|
EXPECT_EQ(expectedMoveStatus, statuses[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class InputReceiver>
|
||||||
|
void APZCTesterBase::PinchWithPinchInput(
|
||||||
|
const RefPtr<InputReceiver>& aTarget, const ScreenIntPoint& aFocus,
|
||||||
|
const ScreenIntPoint& aSecondFocus, float aScale,
|
||||||
|
nsEventStatus (*aOutEventStatuses)[3]) {
|
||||||
|
const TimeDuration TIME_BETWEEN_PINCH_INPUT =
|
||||||
|
TimeDuration::FromMilliseconds(50);
|
||||||
|
|
||||||
|
nsEventStatus actualStatus = aTarget->ReceiveInputEvent(
|
||||||
|
CreatePinchGestureInput(PinchGestureInput::PINCHGESTURE_START, aFocus,
|
||||||
|
10.0, 10.0, mcc->Time()),
|
||||||
|
nullptr);
|
||||||
|
if (aOutEventStatuses) {
|
||||||
|
(*aOutEventStatuses)[0] = actualStatus;
|
||||||
|
}
|
||||||
|
mcc->AdvanceBy(TIME_BETWEEN_PINCH_INPUT);
|
||||||
|
|
||||||
|
actualStatus = aTarget->ReceiveInputEvent(
|
||||||
|
CreatePinchGestureInput(PinchGestureInput::PINCHGESTURE_SCALE,
|
||||||
|
aSecondFocus, 10.0 * aScale, 10.0, mcc->Time()),
|
||||||
|
nullptr);
|
||||||
|
if (aOutEventStatuses) {
|
||||||
|
(*aOutEventStatuses)[1] = actualStatus;
|
||||||
|
}
|
||||||
|
mcc->AdvanceBy(TIME_BETWEEN_PINCH_INPUT);
|
||||||
|
|
||||||
|
actualStatus = aTarget->ReceiveInputEvent(
|
||||||
|
CreatePinchGestureInput(
|
||||||
|
PinchGestureInput::PINCHGESTURE_END,
|
||||||
|
PinchGestureInput::BothFingersLifted<ScreenPixel>(), 10.0 * aScale,
|
||||||
|
10.0 * aScale, mcc->Time()),
|
||||||
|
nullptr);
|
||||||
|
if (aOutEventStatuses) {
|
||||||
|
(*aOutEventStatuses)[2] = actualStatus;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class InputReceiver>
|
||||||
|
void APZCTesterBase::PinchWithPinchInputAndCheckStatus(
|
||||||
|
const RefPtr<InputReceiver>& aTarget, const ScreenIntPoint& aFocus,
|
||||||
|
float aScale, bool aShouldTriggerPinch) {
|
||||||
|
nsEventStatus statuses[3]; // scalebegin, scale, scaleend
|
||||||
|
PinchWithPinchInput(aTarget, aFocus, aFocus, aScale, &statuses);
|
||||||
|
|
||||||
|
nsEventStatus expectedStatus = aShouldTriggerPinch
|
||||||
|
? nsEventStatus_eConsumeNoDefault
|
||||||
|
: nsEventStatus_eIgnore;
|
||||||
|
EXPECT_EQ(expectedStatus, statuses[0]);
|
||||||
|
EXPECT_EQ(expectedStatus, statuses[1]);
|
||||||
|
}
|
||||||
|
|
||||||
AsyncPanZoomController* TestAPZCTreeManager::NewAPZCInstance(
|
AsyncPanZoomController* TestAPZCTreeManager::NewAPZCInstance(
|
||||||
LayersId aLayersId, GeckoContentController* aController) {
|
LayersId aLayersId, GeckoContentController* aController) {
|
||||||
MockContentControllerDelayed* mcc =
|
MockContentControllerDelayed* mcc =
|
||||||
|
|
|
@ -28,15 +28,6 @@
|
||||||
* code to dispatch input events.
|
* code to dispatch input events.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
inline PinchGestureInput CreatePinchGestureInput(
|
|
||||||
PinchGestureInput::PinchGestureType aType, const ScreenPoint& aFocus,
|
|
||||||
float aCurrentSpan, float aPreviousSpan) {
|
|
||||||
ParentLayerPoint localFocus(aFocus.x, aFocus.y);
|
|
||||||
PinchGestureInput result(aType, 0, TimeStamp(), ExternalPoint(0, 0), aFocus,
|
|
||||||
aCurrentSpan, aPreviousSpan, 0);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class InputReceiver>
|
template <class InputReceiver>
|
||||||
void SetDefaultAllowedTouchBehavior(const RefPtr<InputReceiver>& aTarget,
|
void SetDefaultAllowedTouchBehavior(const RefPtr<InputReceiver>& aTarget,
|
||||||
uint64_t aInputBlockId,
|
uint64_t aInputBlockId,
|
||||||
|
@ -86,50 +77,6 @@ nsEventStatus TouchUp(const RefPtr<InputReceiver>& aTarget,
|
||||||
return aTarget->ReceiveInputEvent(mti, nullptr, nullptr);
|
return aTarget->ReceiveInputEvent(mti, nullptr, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class InputReceiver>
|
|
||||||
void PinchWithPinchInput(const RefPtr<InputReceiver>& aTarget,
|
|
||||||
const ScreenIntPoint& aFocus,
|
|
||||||
const ScreenIntPoint& aSecondFocus, float aScale,
|
|
||||||
nsEventStatus (*aOutEventStatuses)[3] = nullptr) {
|
|
||||||
nsEventStatus actualStatus = aTarget->ReceiveInputEvent(
|
|
||||||
CreatePinchGestureInput(PinchGestureInput::PINCHGESTURE_START, aFocus,
|
|
||||||
10.0, 10.0),
|
|
||||||
nullptr);
|
|
||||||
if (aOutEventStatuses) {
|
|
||||||
(*aOutEventStatuses)[0] = actualStatus;
|
|
||||||
}
|
|
||||||
actualStatus = aTarget->ReceiveInputEvent(
|
|
||||||
CreatePinchGestureInput(PinchGestureInput::PINCHGESTURE_SCALE,
|
|
||||||
aSecondFocus, 10.0 * aScale, 10.0),
|
|
||||||
nullptr);
|
|
||||||
if (aOutEventStatuses) {
|
|
||||||
(*aOutEventStatuses)[1] = actualStatus;
|
|
||||||
}
|
|
||||||
actualStatus = aTarget->ReceiveInputEvent(
|
|
||||||
CreatePinchGestureInput(
|
|
||||||
PinchGestureInput::PINCHGESTURE_END,
|
|
||||||
PinchGestureInput::BothFingersLifted<ScreenPixel>(), 10.0 * aScale,
|
|
||||||
10.0 * aScale),
|
|
||||||
nullptr);
|
|
||||||
if (aOutEventStatuses) {
|
|
||||||
(*aOutEventStatuses)[2] = actualStatus;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class InputReceiver>
|
|
||||||
void PinchWithPinchInputAndCheckStatus(const RefPtr<InputReceiver>& aTarget,
|
|
||||||
const ScreenIntPoint& aFocus,
|
|
||||||
float aScale, bool aShouldTriggerPinch) {
|
|
||||||
nsEventStatus statuses[3]; // scalebegin, scale, scaleend
|
|
||||||
PinchWithPinchInput(aTarget, aFocus, aFocus, aScale, &statuses);
|
|
||||||
|
|
||||||
nsEventStatus expectedStatus = aShouldTriggerPinch
|
|
||||||
? nsEventStatus_eConsumeNoDefault
|
|
||||||
: nsEventStatus_eIgnore;
|
|
||||||
EXPECT_EQ(expectedStatus, statuses[0]);
|
|
||||||
EXPECT_EQ(expectedStatus, statuses[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class InputReceiver>
|
template <class InputReceiver>
|
||||||
nsEventStatus Wheel(const RefPtr<InputReceiver>& aTarget,
|
nsEventStatus Wheel(const RefPtr<InputReceiver>& aTarget,
|
||||||
const ScreenIntPoint& aPoint, const ScreenPoint& aDelta,
|
const ScreenIntPoint& aPoint, const ScreenPoint& aDelta,
|
||||||
|
|
|
@ -42,34 +42,39 @@ TEST_F(APZCGestureDetectorTester, Pan_After_Pinch) {
|
||||||
int focusX = 250;
|
int focusX = 250;
|
||||||
int focusY = 300;
|
int focusY = 300;
|
||||||
int panDistance = 20;
|
int panDistance = 20;
|
||||||
|
const TimeDuration TIME_BETWEEN_TOUCH_EVENT =
|
||||||
|
TimeDuration::FromMilliseconds(50);
|
||||||
|
|
||||||
int firstFingerId = 0;
|
int firstFingerId = 0;
|
||||||
int secondFingerId = firstFingerId + 1;
|
int secondFingerId = firstFingerId + 1;
|
||||||
|
|
||||||
// Put fingers down
|
// Put fingers down
|
||||||
MultiTouchInput mti =
|
MultiTouchInput mti =
|
||||||
MultiTouchInput(MultiTouchInput::MULTITOUCH_START, 0, TimeStamp(), 0);
|
MultiTouchInput(MultiTouchInput::MULTITOUCH_START, 0, mcc->Time(), 0);
|
||||||
mti.mTouches.AppendElement(
|
mti.mTouches.AppendElement(
|
||||||
CreateSingleTouchData(firstFingerId, focusX, focusY));
|
CreateSingleTouchData(firstFingerId, focusX, focusY));
|
||||||
mti.mTouches.AppendElement(
|
mti.mTouches.AppendElement(
|
||||||
CreateSingleTouchData(secondFingerId, focusX, focusY));
|
CreateSingleTouchData(secondFingerId, focusX, focusY));
|
||||||
apzc->ReceiveInputEvent(mti, nullptr);
|
apzc->ReceiveInputEvent(mti, nullptr);
|
||||||
|
mcc->AdvanceBy(TIME_BETWEEN_TOUCH_EVENT);
|
||||||
|
|
||||||
// Spread fingers out to enter the pinch state
|
// Spread fingers out to enter the pinch state
|
||||||
mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, 0, TimeStamp(), 0);
|
mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, 0, mcc->Time(), 0);
|
||||||
mti.mTouches.AppendElement(
|
mti.mTouches.AppendElement(
|
||||||
CreateSingleTouchData(firstFingerId, focusX - pinchLength, focusY));
|
CreateSingleTouchData(firstFingerId, focusX - pinchLength, focusY));
|
||||||
mti.mTouches.AppendElement(
|
mti.mTouches.AppendElement(
|
||||||
CreateSingleTouchData(secondFingerId, focusX + pinchLength, focusY));
|
CreateSingleTouchData(secondFingerId, focusX + pinchLength, focusY));
|
||||||
apzc->ReceiveInputEvent(mti, nullptr);
|
apzc->ReceiveInputEvent(mti, nullptr);
|
||||||
|
mcc->AdvanceBy(TIME_BETWEEN_TOUCH_EVENT);
|
||||||
|
|
||||||
// Do the actual pinch of 1.25x
|
// Do the actual pinch of 1.25x
|
||||||
mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, 0, TimeStamp(), 0);
|
mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, 0, mcc->Time(), 0);
|
||||||
mti.mTouches.AppendElement(
|
mti.mTouches.AppendElement(
|
||||||
CreateSingleTouchData(firstFingerId, focusX - pinchLengthScaled, focusY));
|
CreateSingleTouchData(firstFingerId, focusX - pinchLengthScaled, focusY));
|
||||||
mti.mTouches.AppendElement(CreateSingleTouchData(
|
mti.mTouches.AppendElement(CreateSingleTouchData(
|
||||||
secondFingerId, focusX + pinchLengthScaled, focusY));
|
secondFingerId, focusX + pinchLengthScaled, focusY));
|
||||||
apzc->ReceiveInputEvent(mti, nullptr);
|
apzc->ReceiveInputEvent(mti, nullptr);
|
||||||
|
mcc->AdvanceBy(TIME_BETWEEN_TOUCH_EVENT);
|
||||||
|
|
||||||
// Verify that the zoom changed, just to make sure our code above did what it
|
// Verify that the zoom changed, just to make sure our code above did what it
|
||||||
// was supposed to.
|
// was supposed to.
|
||||||
|
@ -79,31 +84,35 @@ TEST_F(APZCGestureDetectorTester, Pan_After_Pinch) {
|
||||||
newZoom);
|
newZoom);
|
||||||
|
|
||||||
// Now we lift one finger...
|
// Now we lift one finger...
|
||||||
mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_END, 0, TimeStamp(), 0);
|
mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_END, 0, mcc->Time(), 0);
|
||||||
mti.mTouches.AppendElement(CreateSingleTouchData(
|
mti.mTouches.AppendElement(CreateSingleTouchData(
|
||||||
secondFingerId, focusX + pinchLengthScaled, focusY));
|
secondFingerId, focusX + pinchLengthScaled, focusY));
|
||||||
apzc->ReceiveInputEvent(mti, nullptr);
|
apzc->ReceiveInputEvent(mti, nullptr);
|
||||||
|
mcc->AdvanceBy(TIME_BETWEEN_TOUCH_EVENT);
|
||||||
|
|
||||||
// ... and pan with the remaining finger. This pan just breaks through the
|
// ... and pan with the remaining finger. This pan just breaks through the
|
||||||
// distance threshold.
|
// distance threshold.
|
||||||
focusY += 40;
|
focusY += 40;
|
||||||
mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, 0, TimeStamp(), 0);
|
mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, 0, mcc->Time(), 0);
|
||||||
mti.mTouches.AppendElement(
|
mti.mTouches.AppendElement(
|
||||||
CreateSingleTouchData(firstFingerId, focusX - pinchLengthScaled, focusY));
|
CreateSingleTouchData(firstFingerId, focusX - pinchLengthScaled, focusY));
|
||||||
apzc->ReceiveInputEvent(mti, nullptr);
|
apzc->ReceiveInputEvent(mti, nullptr);
|
||||||
|
mcc->AdvanceBy(TIME_BETWEEN_TOUCH_EVENT);
|
||||||
|
|
||||||
// This one does an actual pan of 20 pixels
|
// This one does an actual pan of 20 pixels
|
||||||
focusY += panDistance;
|
focusY += panDistance;
|
||||||
mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, 0, TimeStamp(), 0);
|
mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, 0, mcc->Time(), 0);
|
||||||
mti.mTouches.AppendElement(
|
mti.mTouches.AppendElement(
|
||||||
CreateSingleTouchData(firstFingerId, focusX - pinchLengthScaled, focusY));
|
CreateSingleTouchData(firstFingerId, focusX - pinchLengthScaled, focusY));
|
||||||
apzc->ReceiveInputEvent(mti, nullptr);
|
apzc->ReceiveInputEvent(mti, nullptr);
|
||||||
|
mcc->AdvanceBy(TIME_BETWEEN_TOUCH_EVENT);
|
||||||
|
|
||||||
// Lift the remaining finger
|
// Lift the remaining finger
|
||||||
mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_END, 0, TimeStamp(), 0);
|
mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_END, 0, mcc->Time(), 0);
|
||||||
mti.mTouches.AppendElement(
|
mti.mTouches.AppendElement(
|
||||||
CreateSingleTouchData(firstFingerId, focusX - pinchLengthScaled, focusY));
|
CreateSingleTouchData(firstFingerId, focusX - pinchLengthScaled, focusY));
|
||||||
apzc->ReceiveInputEvent(mti, nullptr);
|
apzc->ReceiveInputEvent(mti, nullptr);
|
||||||
|
mcc->AdvanceBy(TIME_BETWEEN_TOUCH_EVENT);
|
||||||
|
|
||||||
// Verify that we scrolled
|
// Verify that we scrolled
|
||||||
FrameMetrics finalMetrics = apzc->GetFrameMetrics();
|
FrameMetrics finalMetrics = apzc->GetFrameMetrics();
|
||||||
|
|
|
@ -154,8 +154,9 @@ class APZCPinchLockingTester : public APZCPinchTester {
|
||||||
|
|
||||||
apzc->ReceiveInputEvent(
|
apzc->ReceiveInputEvent(
|
||||||
CreatePinchGestureInput(PinchGestureInput::PINCHGESTURE_START, mFocus,
|
CreatePinchGestureInput(PinchGestureInput::PINCHGESTURE_START, mFocus,
|
||||||
mSpan, mSpan),
|
mSpan, mSpan, mcc->Time()),
|
||||||
nullptr);
|
nullptr);
|
||||||
|
mcc->AdvanceBy(TimeDuration::FromMilliseconds(51));
|
||||||
}
|
}
|
||||||
|
|
||||||
void twoFingerPan() {
|
void twoFingerPan() {
|
||||||
|
@ -166,8 +167,9 @@ class APZCPinchLockingTester : public APZCPinchTester {
|
||||||
|
|
||||||
apzc->ReceiveInputEvent(
|
apzc->ReceiveInputEvent(
|
||||||
CreatePinchGestureInput(PinchGestureInput::PINCHGESTURE_SCALE, mFocus,
|
CreatePinchGestureInput(PinchGestureInput::PINCHGESTURE_SCALE, mFocus,
|
||||||
mSpan, mSpan),
|
mSpan, mSpan, mcc->Time()),
|
||||||
nullptr);
|
nullptr);
|
||||||
|
mcc->AdvanceBy(TimeDuration::FromMilliseconds(51));
|
||||||
}
|
}
|
||||||
|
|
||||||
void twoFingerZoom() {
|
void twoFingerZoom() {
|
||||||
|
@ -178,8 +180,9 @@ class APZCPinchLockingTester : public APZCPinchTester {
|
||||||
|
|
||||||
apzc->ReceiveInputEvent(
|
apzc->ReceiveInputEvent(
|
||||||
CreatePinchGestureInput(PinchGestureInput::PINCHGESTURE_SCALE, mFocus,
|
CreatePinchGestureInput(PinchGestureInput::PINCHGESTURE_SCALE, mFocus,
|
||||||
newSpan, mSpan),
|
newSpan, mSpan, mcc->Time()),
|
||||||
nullptr);
|
nullptr);
|
||||||
|
mcc->AdvanceBy(TimeDuration::FromMilliseconds(51));
|
||||||
mSpan = newSpan;
|
mSpan = newSpan;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,7 +194,7 @@ class APZCPinchLockingTester : public APZCPinchTester {
|
||||||
gfxPrefs::APZPinchLockSpanBreakoutThreshold() * 0.8 * tm->GetDPI();
|
gfxPrefs::APZPinchLockSpanBreakoutThreshold() * 0.8 * tm->GetDPI();
|
||||||
apzc->ReceiveInputEvent(
|
apzc->ReceiveInputEvent(
|
||||||
CreatePinchGestureInput(PinchGestureInput::PINCHGESTURE_SCALE, mFocus,
|
CreatePinchGestureInput(PinchGestureInput::PINCHGESTURE_SCALE, mFocus,
|
||||||
mSpan + pinchDistance, mSpan),
|
mSpan + pinchDistance, mSpan, mcc->Time()),
|
||||||
nullptr);
|
nullptr);
|
||||||
|
|
||||||
FrameMetrics result = apzc->GetFrameMetrics();
|
FrameMetrics result = apzc->GetFrameMetrics();
|
||||||
|
@ -494,29 +497,35 @@ TEST_F(APZCPinchGestureDetectorTester, Pinch_NoSpan) {
|
||||||
|
|
||||||
// Do a pinch holding a zero span and moving the focus by y=100
|
// Do a pinch holding a zero span and moving the focus by y=100
|
||||||
|
|
||||||
|
const TimeDuration TIME_BETWEEN_TOUCH_EVENT =
|
||||||
|
TimeDuration::FromMilliseconds(50);
|
||||||
|
|
||||||
MultiTouchInput mtiStart =
|
MultiTouchInput mtiStart =
|
||||||
MultiTouchInput(MultiTouchInput::MULTITOUCH_START, 0, TimeStamp(), 0);
|
MultiTouchInput(MultiTouchInput::MULTITOUCH_START, 0, mcc->Time(), 0);
|
||||||
mtiStart.mTouches.AppendElement(CreateSingleTouchData(inputId, focus));
|
mtiStart.mTouches.AppendElement(CreateSingleTouchData(inputId, focus));
|
||||||
mtiStart.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, focus));
|
mtiStart.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, focus));
|
||||||
apzc->ReceiveInputEvent(mtiStart, nullptr);
|
apzc->ReceiveInputEvent(mtiStart, nullptr);
|
||||||
|
mcc->AdvanceBy(TIME_BETWEEN_TOUCH_EVENT);
|
||||||
|
|
||||||
focus.y -= 35 + 1; // this is to get over the PINCH_START_THRESHOLD in
|
focus.y -= 35 + 1; // this is to get over the PINCH_START_THRESHOLD in
|
||||||
// GestureEventListener.cpp
|
// GestureEventListener.cpp
|
||||||
MultiTouchInput mtiMove1 =
|
MultiTouchInput mtiMove1 =
|
||||||
MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, 0, TimeStamp(), 0);
|
MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, 0, mcc->Time(), 0);
|
||||||
mtiMove1.mTouches.AppendElement(CreateSingleTouchData(inputId, focus));
|
mtiMove1.mTouches.AppendElement(CreateSingleTouchData(inputId, focus));
|
||||||
mtiMove1.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, focus));
|
mtiMove1.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, focus));
|
||||||
apzc->ReceiveInputEvent(mtiMove1, nullptr);
|
apzc->ReceiveInputEvent(mtiMove1, nullptr);
|
||||||
|
mcc->AdvanceBy(TIME_BETWEEN_TOUCH_EVENT);
|
||||||
|
|
||||||
focus.y -= 100; // do a two-finger scroll of 100 screen pixels
|
focus.y -= 100; // do a two-finger scroll of 100 screen pixels
|
||||||
MultiTouchInput mtiMove2 =
|
MultiTouchInput mtiMove2 =
|
||||||
MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, 0, TimeStamp(), 0);
|
MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, 0, mcc->Time(), 0);
|
||||||
mtiMove2.mTouches.AppendElement(CreateSingleTouchData(inputId, focus));
|
mtiMove2.mTouches.AppendElement(CreateSingleTouchData(inputId, focus));
|
||||||
mtiMove2.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, focus));
|
mtiMove2.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, focus));
|
||||||
apzc->ReceiveInputEvent(mtiMove2, nullptr);
|
apzc->ReceiveInputEvent(mtiMove2, nullptr);
|
||||||
|
mcc->AdvanceBy(TIME_BETWEEN_TOUCH_EVENT);
|
||||||
|
|
||||||
MultiTouchInput mtiEnd =
|
MultiTouchInput mtiEnd =
|
||||||
MultiTouchInput(MultiTouchInput::MULTITOUCH_END, 0, TimeStamp(), 0);
|
MultiTouchInput(MultiTouchInput::MULTITOUCH_END, 0, mcc->Time(), 0);
|
||||||
mtiEnd.mTouches.AppendElement(CreateSingleTouchData(inputId, focus));
|
mtiEnd.mTouches.AppendElement(CreateSingleTouchData(inputId, focus));
|
||||||
mtiEnd.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, focus));
|
mtiEnd.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, focus));
|
||||||
apzc->ReceiveInputEvent(mtiEnd, nullptr);
|
apzc->ReceiveInputEvent(mtiEnd, nullptr);
|
||||||
|
@ -549,12 +558,12 @@ TEST_F(APZCPinchTester, Pinch_TwoFinger_APZZoom_Disabled_Bug1354185) {
|
||||||
float aScale = 10;
|
float aScale = 10;
|
||||||
apzc->ReceiveInputEvent(
|
apzc->ReceiveInputEvent(
|
||||||
CreatePinchGestureInput(PinchGestureInput::PINCHGESTURE_START, aFocus,
|
CreatePinchGestureInput(PinchGestureInput::PINCHGESTURE_START, aFocus,
|
||||||
10.0, 10.0),
|
10.0, 10.0, mcc->Time()),
|
||||||
nullptr);
|
nullptr);
|
||||||
|
|
||||||
apzc->ReceiveInputEvent(
|
apzc->ReceiveInputEvent(
|
||||||
CreatePinchGestureInput(PinchGestureInput::PINCHGESTURE_SCALE,
|
CreatePinchGestureInput(PinchGestureInput::PINCHGESTURE_SCALE,
|
||||||
aSecondFocus, 10.0 * aScale, 10.0),
|
aSecondFocus, 10.0 * aScale, 10.0, mcc->Time()),
|
||||||
nullptr);
|
nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -349,6 +349,7 @@ class gfxPrefs final {
|
||||||
DECL_GFX_PREF(Live, "apz.pinch_lock.scroll_lock_threshold", APZPinchLockScrollLockThreshold, float, 1.0f / 32.0f);
|
DECL_GFX_PREF(Live, "apz.pinch_lock.scroll_lock_threshold", APZPinchLockScrollLockThreshold, float, 1.0f / 32.0f);
|
||||||
DECL_GFX_PREF(Live, "apz.pinch_lock.span_breakout_threshold", APZPinchLockSpanBreakoutThreshold, float, 1.0f / 32.0f);
|
DECL_GFX_PREF(Live, "apz.pinch_lock.span_breakout_threshold", APZPinchLockSpanBreakoutThreshold, float, 1.0f / 32.0f);
|
||||||
DECL_GFX_PREF(Live, "apz.pinch_lock.span_lock_threshold", APZPinchLockSpanLockThreshold, float, 1.0f / 32.0f);
|
DECL_GFX_PREF(Live, "apz.pinch_lock.span_lock_threshold", APZPinchLockSpanLockThreshold, float, 1.0f / 32.0f);
|
||||||
|
DECL_GFX_PREF(Once, "apz.pinch_lock.buffer_max_age", APZPinchLockBufferMaxAge, int32_t, 50);
|
||||||
DECL_GFX_PREF(Live, "apz.popups.enabled", APZPopupsEnabled, bool, false);
|
DECL_GFX_PREF(Live, "apz.popups.enabled", APZPopupsEnabled, bool, false);
|
||||||
DECL_GFX_PREF(Live, "apz.printtree", APZPrintTree, bool, false);
|
DECL_GFX_PREF(Live, "apz.printtree", APZPrintTree, bool, false);
|
||||||
DECL_GFX_PREF(Live, "apz.record_checkerboarding", APZRecordCheckerboarding, bool, false);
|
DECL_GFX_PREF(Live, "apz.record_checkerboarding", APZRecordCheckerboarding, bool, false);
|
||||||
|
|
|
@ -758,6 +758,7 @@ pref("apz.pinch_lock.mode", 1);
|
||||||
pref("apz.pinch_lock.scoll_lock_threshold", "0.03125"); // 1/32 inches
|
pref("apz.pinch_lock.scoll_lock_threshold", "0.03125"); // 1/32 inches
|
||||||
pref("apz.pinch_lock.span_breakout_threshold", "0.03125"); // 1/32 inches
|
pref("apz.pinch_lock.span_breakout_threshold", "0.03125"); // 1/32 inches
|
||||||
pref("apz.pinch_lock.span_lock_threshold", "0.03125"); // 1/32 inches
|
pref("apz.pinch_lock.span_lock_threshold", "0.03125"); // 1/32 inches
|
||||||
|
pref("apz.pinch_lock.buffer_max_age", "50"); // milliseconds
|
||||||
pref("apz.popups.enabled", false);
|
pref("apz.popups.enabled", false);
|
||||||
pref("apz.relative-update.enabled", true);
|
pref("apz.relative-update.enabled", true);
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче