mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 795567 - Part 3: Add panning restriction and retrieving of touch-action value to apzc. r=kats
This commit is contained in:
parent
3bc8322d83
commit
7ee05aa952
@ -18,7 +18,6 @@
|
||||
#include "mozilla/TouchEvents.h"
|
||||
#include "nsDebug.h" // for NS_WARNING
|
||||
#include "nsPoint.h" // for nsIntPoint
|
||||
#include "nsTArray.h" // for nsTArray, nsTArray_Impl, etc
|
||||
#include "nsThreadUtils.h" // for NS_IsMainThread
|
||||
|
||||
#include <algorithm> // for std::stable_sort
|
||||
@ -43,6 +42,38 @@ APZCTreeManager::~APZCTreeManager()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
APZCTreeManager::GetAllowedTouchBehavior(WidgetInputEvent* aEvent,
|
||||
nsTArray<TouchBehaviorFlags>& aOutValues)
|
||||
{
|
||||
WidgetTouchEvent *touchEvent = aEvent->AsTouchEvent();
|
||||
|
||||
aOutValues.Clear();
|
||||
|
||||
for (size_t i = 0; i < touchEvent->touches.Length(); i++) {
|
||||
// If aEvent wasn't transformed previously we might need to
|
||||
// add transforming of the spt here.
|
||||
mozilla::ScreenIntPoint spt;
|
||||
spt.x = touchEvent->touches[i]->mRefPoint.x;
|
||||
spt.y = touchEvent->touches[i]->mRefPoint.y;
|
||||
|
||||
nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(spt);
|
||||
aOutValues.AppendElement(apzc
|
||||
? apzc->GetAllowedTouchBehavior(spt)
|
||||
: AllowedTouchBehavior::UNKNOWN);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
APZCTreeManager::SetAllowedTouchBehavior(const ScrollableLayerGuid& aGuid,
|
||||
const nsTArray<TouchBehaviorFlags> &aValues)
|
||||
{
|
||||
nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(aGuid);
|
||||
if (apzc) {
|
||||
apzc->SetAllowedTouchBehavior(aValues);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
APZCTreeManager::AssertOnCompositorThread()
|
||||
{
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsTraceRefcnt.h" // for MOZ_COUNT_CTOR, etc
|
||||
#include "mozilla/Vector.h" // for mozilla::Vector
|
||||
#include "nsTArray.h" // for nsTArray, nsTArray_Impl, etc
|
||||
|
||||
class gfx3DMatrix;
|
||||
template <class E> class nsTArray;
|
||||
@ -28,6 +29,14 @@ class InputData;
|
||||
|
||||
namespace layers {
|
||||
|
||||
enum AllowedTouchBehavior {
|
||||
NONE = 0,
|
||||
VERTICAL_PAN = 1 << 0,
|
||||
HORIZONTAL_PAN = 1 << 1,
|
||||
ZOOM = 1 << 2,
|
||||
UNKNOWN = 1 << 3
|
||||
};
|
||||
|
||||
class Layer;
|
||||
class AsyncPanZoomController;
|
||||
class CompositorParent;
|
||||
@ -57,6 +66,9 @@ class CompositorParent;
|
||||
class APZCTreeManager {
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(APZCTreeManager)
|
||||
|
||||
typedef mozilla::layers::AllowedTouchBehavior AllowedTouchBehavior;
|
||||
typedef uint32_t TouchBehaviorFlags;
|
||||
|
||||
public:
|
||||
APZCTreeManager();
|
||||
virtual ~APZCTreeManager();
|
||||
@ -189,6 +201,22 @@ public:
|
||||
*/
|
||||
static float GetDPI() { return sDPI; }
|
||||
|
||||
/**
|
||||
* Returns values of allowed touch-behavior for the touches of aEvent via out parameter.
|
||||
* Internally performs asks appropriate AsyncPanZoomController to perform
|
||||
* hit testing on its own.
|
||||
*/
|
||||
void GetAllowedTouchBehavior(WidgetInputEvent* aEvent,
|
||||
nsTArray<TouchBehaviorFlags>& aOutValues);
|
||||
|
||||
/**
|
||||
* Sets allowed touch behavior values for current touch-session for specific apzc (determined by guid).
|
||||
* Should be invoked by the widget. Each value of the aValues arrays corresponds to the different
|
||||
* touch point that is currently active.
|
||||
*/
|
||||
void SetAllowedTouchBehavior(const ScrollableLayerGuid& aGuid,
|
||||
const nsTArray<TouchBehaviorFlags>& aValues);
|
||||
|
||||
/**
|
||||
* This is a callback for AsyncPanZoomController to call when it wants to
|
||||
* scroll in response to a touch-move event, or when it needs to hand off
|
||||
|
@ -127,6 +127,13 @@ using namespace mozilla::css;
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
typedef mozilla::layers::AllowedTouchBehavior AllowedTouchBehavior;
|
||||
|
||||
/**
|
||||
* Specifies whether touch-action property is in force.
|
||||
*/
|
||||
static bool gTouchActionPropertyEnabled = false;
|
||||
|
||||
/**
|
||||
* 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
|
||||
@ -135,6 +142,13 @@ namespace layers {
|
||||
*/
|
||||
static float gTouchStartTolerance = 1.0f/2.0f;
|
||||
|
||||
/**
|
||||
* Default touch behavior (is used when not touch behavior is set).
|
||||
*/
|
||||
static const uint32_t DefaultTouchBehavior = AllowedTouchBehavior::VERTICAL_PAN |
|
||||
AllowedTouchBehavior::HORIZONTAL_PAN |
|
||||
AllowedTouchBehavior::ZOOM;
|
||||
|
||||
/**
|
||||
* Angle from axis within which we stay axis-locked
|
||||
*/
|
||||
@ -150,6 +164,15 @@ static const float AXIS_BREAKOUT_THRESHOLD = 1.0f/32.0f;
|
||||
*/
|
||||
static const double AXIS_BREAKOUT_ANGLE = M_PI / 8.0; // 22.5 degrees
|
||||
|
||||
/**
|
||||
* Angle from axis to the line drawn by pan move.
|
||||
* If angle is less than this value we can assume that panning
|
||||
* can be done in allowed direction (horizontal or vertical).
|
||||
* Currently used only for touch-action css property stuff and was
|
||||
* added to keep behavior consistent with IE.
|
||||
*/
|
||||
static const double ALLOWED_DIRECT_PAN_ANGLE = M_PI / 3.0; // 60 degrees
|
||||
|
||||
/**
|
||||
* The preferred axis locking style. See AxisLockMode for possible values.
|
||||
*/
|
||||
@ -358,6 +381,7 @@ AsyncPanZoomController::InitializeGlobalState()
|
||||
return;
|
||||
sInitialized = true;
|
||||
|
||||
Preferences::AddBoolVarCache(&gTouchActionPropertyEnabled, "layout.css.touch_action.enabled", gTouchActionPropertyEnabled);
|
||||
Preferences::AddIntVarCache(&gPanRepaintInterval, "apz.pan_repaint_interval", gPanRepaintInterval);
|
||||
Preferences::AddIntVarCache(&gFlingRepaintInterval, "apz.fling_repaint_interval", gFlingRepaintInterval);
|
||||
Preferences::AddFloatVarCache(&gMinSkateSpeed, "apz.min_skate_speed", gMinSkateSpeed);
|
||||
@ -390,9 +414,11 @@ AsyncPanZoomController::AsyncPanZoomController(uint64_t aLayersId,
|
||||
mGeckoContentController(aGeckoContentController),
|
||||
mRefPtrMonitor("RefPtrMonitor"),
|
||||
mMonitor("AsyncPanZoomController"),
|
||||
mTouchActionPropertyEnabled(gTouchActionPropertyEnabled),
|
||||
mTouchListenerTimeoutTask(nullptr),
|
||||
mX(MOZ_THIS_IN_INITIALIZER_LIST()),
|
||||
mY(MOZ_THIS_IN_INITIALIZER_LIST()),
|
||||
mPanDirRestricted(false),
|
||||
mZoomConstraints(false, MIN_ZOOM, MAX_ZOOM),
|
||||
mLastSampleTime(GetFrameTime()),
|
||||
mState(NOTHING),
|
||||
@ -561,6 +587,7 @@ nsEventStatus AsyncPanZoomController::HandleInputEvent(const InputData& aEvent)
|
||||
|
||||
nsEventStatus AsyncPanZoomController::OnTouchStart(const MultiTouchInput& aEvent) {
|
||||
APZC_LOG("%p got a touch-start in state %d\n", this, mState);
|
||||
mPanDirRestricted = false;
|
||||
ScreenIntPoint point = GetFirstTouchScreenPoint(aEvent);
|
||||
|
||||
switch (mState) {
|
||||
@ -624,6 +651,17 @@ nsEventStatus AsyncPanZoomController::OnTouchMove(const MultiTouchInput& aEvent)
|
||||
return nsEventStatus_eIgnore;
|
||||
}
|
||||
|
||||
if (mTouchActionPropertyEnabled &&
|
||||
(GetTouchBehavior(0) & AllowedTouchBehavior::VERTICAL_PAN) &&
|
||||
(GetTouchBehavior(0) & AllowedTouchBehavior::HORIZONTAL_PAN)) {
|
||||
// User tries to trigger a touch behavior. If allowed touch behavior is vertical pan
|
||||
// + horizontal pan (touch-action value is equal to AUTO) we can return ConsumeNoDefault
|
||||
// status immediately to trigger cancel event further. It should happen independent of
|
||||
// the parent type (whether it is scrolling or not).
|
||||
StartPanning(aEvent);
|
||||
return nsEventStatus_eConsumeNoDefault;
|
||||
}
|
||||
|
||||
return StartPanning(aEvent);
|
||||
}
|
||||
|
||||
@ -648,7 +686,13 @@ nsEventStatus AsyncPanZoomController::OnTouchMove(const MultiTouchInput& aEvent)
|
||||
|
||||
nsEventStatus AsyncPanZoomController::OnTouchEnd(const MultiTouchInput& aEvent) {
|
||||
APZC_LOG("%p got a touch-end in state %d\n", this, mState);
|
||||
{
|
||||
|
||||
// In case no touch behavior triggered previously we can avoid sending
|
||||
// scroll events or requesting content repaint. This condition is added
|
||||
// to make tests consistent - in case touch-action is NONE (and therefore
|
||||
// no pans/zooms can be performed) we expected neither scroll or repaint
|
||||
// events.
|
||||
if (mState != NOTHING) {
|
||||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
SendAsyncScrollEvent();
|
||||
}
|
||||
@ -934,6 +978,74 @@ const gfx::Point AsyncPanZoomController::GetAccelerationVector() {
|
||||
return gfx::Point(mX.GetAccelerationFactor(), mY.GetAccelerationFactor());
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::HandlePanningWithTouchAction(double aAngle, TouchBehaviorFlags aBehavior) {
|
||||
// Handling of cross sliding will need to be added in this method after touch-action released
|
||||
// enabled by default.
|
||||
if ((aBehavior & AllowedTouchBehavior::VERTICAL_PAN) && (aBehavior & AllowedTouchBehavior::HORIZONTAL_PAN)) {
|
||||
if (mX.Scrollable() && mY.Scrollable()) {
|
||||
if (IsCloseToHorizontal(aAngle, AXIS_LOCK_ANGLE)) {
|
||||
mY.SetScrollingDisabled(true);
|
||||
SetState(PANNING_LOCKED_X);
|
||||
} else if (IsCloseToVertical(aAngle, AXIS_LOCK_ANGLE)) {
|
||||
mX.SetScrollingDisabled(true);
|
||||
SetState(PANNING_LOCKED_Y);
|
||||
} else {
|
||||
SetState(PANNING);
|
||||
}
|
||||
} else if (mX.Scrollable() || mY.Scrollable()) {
|
||||
SetState(PANNING);
|
||||
} else {
|
||||
SetState(NOTHING);
|
||||
}
|
||||
} else if (aBehavior & AllowedTouchBehavior::HORIZONTAL_PAN) {
|
||||
// Using bigger angle for panning to keep behavior consistent
|
||||
// with IE.
|
||||
if (IsCloseToHorizontal(aAngle, ALLOWED_DIRECT_PAN_ANGLE)) {
|
||||
mY.SetScrollingDisabled(true);
|
||||
SetState(PANNING_LOCKED_X);
|
||||
mPanDirRestricted = true;
|
||||
} else {
|
||||
// Don't treat these touches as pan/zoom movements since 'touch-action' value
|
||||
// requires it.
|
||||
SetState(NOTHING);
|
||||
}
|
||||
} else if (aBehavior & AllowedTouchBehavior::VERTICAL_PAN) {
|
||||
if (IsCloseToVertical(aAngle, ALLOWED_DIRECT_PAN_ANGLE)) {
|
||||
mX.SetScrollingDisabled(true);
|
||||
SetState(PANNING_LOCKED_Y);
|
||||
mPanDirRestricted = true;
|
||||
} else {
|
||||
SetState(NOTHING);
|
||||
}
|
||||
} else {
|
||||
SetState(NOTHING);
|
||||
}
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::HandlePanning(double aAngle) {
|
||||
if (!gCrossSlideEnabled && (!mX.Scrollable() || !mY.Scrollable())) {
|
||||
SetState(PANNING);
|
||||
} else if (IsCloseToHorizontal(aAngle, AXIS_LOCK_ANGLE)) {
|
||||
mY.SetScrollingDisabled(true);
|
||||
if (mX.Scrollable()) {
|
||||
SetState(PANNING_LOCKED_X);
|
||||
} else {
|
||||
SetState(CROSS_SLIDING_X);
|
||||
mX.SetScrollingDisabled(true);
|
||||
}
|
||||
} else if (IsCloseToVertical(aAngle, AXIS_LOCK_ANGLE)) {
|
||||
mX.SetScrollingDisabled(true);
|
||||
if (mY.Scrollable()) {
|
||||
SetState(PANNING_LOCKED_Y);
|
||||
} else {
|
||||
SetState(CROSS_SLIDING_Y);
|
||||
mY.SetScrollingDisabled(true);
|
||||
}
|
||||
} else {
|
||||
SetState(PANNING);
|
||||
}
|
||||
}
|
||||
|
||||
nsEventStatus AsyncPanZoomController::StartPanning(const MultiTouchInput& aEvent) {
|
||||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
|
||||
@ -947,37 +1059,21 @@ nsEventStatus AsyncPanZoomController::StartPanning(const MultiTouchInput& aEvent
|
||||
mY.StartTouch(point.y);
|
||||
mLastEventTime = aEvent.mTime;
|
||||
|
||||
if (GetAxisLockMode() == FREE) {
|
||||
SetState(PANNING);
|
||||
return nsEventStatus_eConsumeNoDefault;
|
||||
}
|
||||
|
||||
double angle = atan2(dy, dx); // range [-pi, pi]
|
||||
angle = fabs(angle); // range [0, pi]
|
||||
|
||||
if (!gCrossSlideEnabled && (!mX.Scrollable() || !mY.Scrollable())) {
|
||||
SetState(PANNING);
|
||||
} else if (IsCloseToHorizontal(angle, AXIS_LOCK_ANGLE)) {
|
||||
mY.SetScrollingDisabled(true);
|
||||
if (mX.Scrollable()) {
|
||||
SetState(PANNING_LOCKED_X);
|
||||
} else {
|
||||
SetState(CROSS_SLIDING_X);
|
||||
mX.SetScrollingDisabled(true);
|
||||
}
|
||||
} else if (IsCloseToVertical(angle, AXIS_LOCK_ANGLE)) {
|
||||
mX.SetScrollingDisabled(true);
|
||||
if (mY.Scrollable()) {
|
||||
SetState(PANNING_LOCKED_Y);
|
||||
} else {
|
||||
SetState(CROSS_SLIDING_Y);
|
||||
mY.SetScrollingDisabled(true);
|
||||
}
|
||||
if (mTouchActionPropertyEnabled) {
|
||||
HandlePanningWithTouchAction(angle, GetTouchBehavior(0));
|
||||
} else {
|
||||
SetState(PANNING);
|
||||
if (GetAxisLockMode() == FREE) {
|
||||
SetState(PANNING);
|
||||
return nsEventStatus_eConsumeNoDefault;
|
||||
}
|
||||
|
||||
HandlePanning(angle);
|
||||
}
|
||||
|
||||
// Don't consume an event that starts a cross-slide.
|
||||
// Don't consume an event that didn't trigger a panning.
|
||||
return IsPanningState(mState) ? nsEventStatus_eConsumeNoDefault
|
||||
: nsEventStatus_eIgnore;
|
||||
}
|
||||
@ -1060,7 +1156,7 @@ void AsyncPanZoomController::TrackTouch(const MultiTouchInput& aEvent) {
|
||||
}
|
||||
|
||||
// If we're axis-locked, check if the user is trying to break the lock
|
||||
if (GetAxisLockMode() == STICKY) {
|
||||
if (GetAxisLockMode() == STICKY && !mPanDirRestricted) {
|
||||
ScreenIntPoint point = GetFirstTouchScreenPoint(aEvent);
|
||||
float dx = mX.PanDistance(point.x);
|
||||
float dy = mY.PanDistance(point.y);
|
||||
@ -1607,6 +1703,27 @@ void AsyncPanZoomController::ContentReceivedTouch(bool aPreventDefault) {
|
||||
}
|
||||
}
|
||||
|
||||
AsyncPanZoomController::TouchBehaviorFlags
|
||||
AsyncPanZoomController::GetTouchBehavior(uint32_t touchIndex) {
|
||||
if (touchIndex < mAllowedTouchBehaviors.Length()) {
|
||||
return mAllowedTouchBehaviors[touchIndex];
|
||||
}
|
||||
return DefaultTouchBehavior;
|
||||
}
|
||||
|
||||
AsyncPanZoomController::TouchBehaviorFlags
|
||||
AsyncPanZoomController::GetAllowedTouchBehavior(ScreenIntPoint& aPoint) {
|
||||
// Here we need to perform a hit testing over the touch-action regions attached to the
|
||||
// layer associated with current apzc.
|
||||
// Currently they are in progress, for more info see bug 928833.
|
||||
return AllowedTouchBehavior::UNKNOWN;
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::SetAllowedTouchBehavior(const nsTArray<TouchBehaviorFlags>& aBehaviors) {
|
||||
mAllowedTouchBehaviors.Clear();
|
||||
mAllowedTouchBehaviors.AppendElements(aBehaviors);
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::SetState(PanZoomState aNewState) {
|
||||
|
||||
PanZoomState oldState;
|
||||
|
@ -65,6 +65,7 @@ class AsyncPanZoomController {
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AsyncPanZoomController)
|
||||
|
||||
typedef mozilla::MonitorAutoLock MonitorAutoLock;
|
||||
typedef uint32_t TouchBehaviorFlags;
|
||||
|
||||
public:
|
||||
enum GestureBehavior {
|
||||
@ -292,6 +293,24 @@ public:
|
||||
void AttemptScroll(const ScreenPoint& aStartPoint, const ScreenPoint& aEndPoint,
|
||||
uint32_t aOverscrollHandoffChainIndex = 0);
|
||||
|
||||
/**
|
||||
* Returns allowed touch behavior for the given point on the scrollable layer.
|
||||
* Internally performs a kind of hit testing based on the regions constructed
|
||||
* on the main thread and attached to the current scrollable layer. Each of such regions
|
||||
* contains info about allowed touch behavior. If regions info isn't enough it returns
|
||||
* UNKNOWN value and we should switch to the fallback approach - asking content.
|
||||
* TODO: for now it's only a stub and returns hardcoded magic value. As soon as bug 928833
|
||||
* is done we should integrate its logic here.
|
||||
*/
|
||||
TouchBehaviorFlags GetAllowedTouchBehavior(ScreenIntPoint& aPoint);
|
||||
|
||||
/**
|
||||
* Sets allowed touch behavior for current touch session.
|
||||
* This method is invoked by the APZCTreeManager which in its turn invoked by
|
||||
* the widget after performing touch-action values retrieving.
|
||||
*/
|
||||
void SetAllowedTouchBehavior(const nsTArray<TouchBehaviorFlags>& aBehaviors);
|
||||
|
||||
/**
|
||||
* A helper function for calling APZCTreeManager::DispatchScroll().
|
||||
* Guards against the case where the APZC is being concurrently destroyed
|
||||
@ -422,6 +441,16 @@ protected:
|
||||
*/
|
||||
ScreenIntPoint& GetFirstTouchScreenPoint(const MultiTouchInput& aEvent);
|
||||
|
||||
/**
|
||||
* Sets the panning state basing on the pan direction angle and current touch-action value.
|
||||
*/
|
||||
void HandlePanningWithTouchAction(double angle, TouchBehaviorFlags value);
|
||||
|
||||
/**
|
||||
* Sets the panning state ignoring the touch action value.
|
||||
*/
|
||||
void HandlePanning(double angle);
|
||||
|
||||
/**
|
||||
* Sets up anything needed for panning. This takes us out of the "TOUCHING"
|
||||
* state and starts actually panning us.
|
||||
@ -508,6 +537,13 @@ private:
|
||||
prevented the default actions yet. we still need to abort animations. */
|
||||
};
|
||||
|
||||
/*
|
||||
* Returns allowed touch behavior from the mAllowedTouchBehavior array.
|
||||
* In case apzc didn't receive touch behavior values within the timeout
|
||||
* it returns default value.
|
||||
*/
|
||||
TouchBehaviorFlags GetTouchBehavior(uint32_t touchIndex);
|
||||
|
||||
/**
|
||||
* Helper to set the current state. Holds the monitor before actually setting
|
||||
* it and fires content controller events based on state changes. Always set
|
||||
@ -564,6 +600,12 @@ protected:
|
||||
// function can be used, or the monitor can be held and then |mState| updated.
|
||||
ReentrantMonitor mMonitor;
|
||||
|
||||
// Specifies whether we should use touch-action css property. Initialized from
|
||||
// the preferences. This property (in comparison with the global one) simplifies
|
||||
// testing apzc with (and without) touch-action property enabled concurrently
|
||||
// (e.g. with the gtest framework).
|
||||
bool mTouchActionPropertyEnabled;
|
||||
|
||||
private:
|
||||
// Metrics of the container layer corresponding to this APZC. This is
|
||||
// stored here so that it is accessible from the UI/controller thread.
|
||||
@ -584,6 +626,10 @@ private:
|
||||
AxisX mX;
|
||||
AxisY mY;
|
||||
|
||||
// This flag is set to true when we are in a axis-locked pan as a result of
|
||||
// the touch-action CSS property.
|
||||
bool mPanDirRestricted;
|
||||
|
||||
// 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
|
||||
// to happen.
|
||||
@ -622,6 +668,12 @@ private:
|
||||
// and we don't want to queue the events back up again.
|
||||
bool mHandlingTouchQueue;
|
||||
|
||||
// Values of allowed touch behavior for current touch points.
|
||||
// Since there are maybe a few current active touch points per time (multitouch case)
|
||||
// and each touch point should have its own value of allowed touch behavior- we're
|
||||
// keeping an array of allowed touch behavior values, not the single value.
|
||||
nsTArray<TouchBehaviorFlags> mAllowedTouchBehaviors;
|
||||
|
||||
RefPtr<AsyncPanZoomAnimation> mAnimation;
|
||||
|
||||
friend class Axis;
|
||||
|
Loading…
Reference in New Issue
Block a user