Bug 1256339 - Add a eLongTapUp tap type, which fires an observer notification rather than doing a click. r?botond
For B2G we had this "special" behaviour where a long-press that didn't trigger
a contextmenu or whose contextmenu event was cancelled would still trigger a
click event. No other browser does this, and so I think it doesn't make sense
for us to keep doing it either. It also makes it much harder to implement the
Windows-style contextmenu, where the contextmenu pops up when you *lift* your
finger after doing a long-press.
MozReview-Commit-ID: 7QfvSmawtzZ
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -1803,16 +1803,21 @@ TabChild::HandleTap(const GeckoContentCo
HandleDoubleTap(aPoint, aModifiers, aGuid);
break;
case GeckoContentController::TapType::eLongTap:
if (mGlobal && mTabChildGlobal) {
mAPZEventState->ProcessLongTap(GetPresShell(), aPoint, aModifiers, aGuid,
aInputBlockId);
}
break;
+ case GeckoContentController::TapType::eLongTapUp:
+ if (mGlobal && mTabChildGlobal) {
+ mAPZEventState->ProcessLongTapUp();
+ }
+ break;
case GeckoContentController::TapType::eSentinel:
// Should never happen, but we need to handle this case to make the compiler
// happy.
MOZ_ASSERT(false);
break;
}
}
--- a/gfx/layers/apz/public/GeckoContentController.h
+++ b/gfx/layers/apz/public/GeckoContentController.h
@@ -44,16 +44,17 @@ public:
* all eLongTap notifications will be followed by an eLongTapUp (for instance,
* if the user moves their finger after triggering the long-tap but before
* lifting it).
*/
enum class TapType {
eSingleTap,
eDoubleTap,
eLongTap,
+ eLongTapUp,
eSentinel,
};
/**
* Requests handling of a tap event. |aPoint| is in CSS pixels, relative to the
* current scroll offset.
*/
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -2000,20 +2000,21 @@ nsEventStatus AsyncPanZoomController::On
return nsEventStatus_eConsumeNoDefault;
}
}
return nsEventStatus_eIgnore;
}
nsEventStatus AsyncPanZoomController::OnLongPressUp(const TapGestureInput& aEvent) {
APZC_LOG("%p got a long-tap-up in state %d\n", this, mState);
- return GenerateSingleTap(aEvent.mPoint, aEvent.modifiers);
+ return GenerateSingleTap(TapType::eLongTapUp, aEvent.mPoint, aEvent.modifiers);
}
-nsEventStatus AsyncPanZoomController::GenerateSingleTap(const ScreenIntPoint& aPoint, mozilla::Modifiers aModifiers) {
+nsEventStatus AsyncPanZoomController::GenerateSingleTap(TapType aType,
+ const ScreenIntPoint& aPoint, mozilla::Modifiers aModifiers) {
RefPtr<GeckoContentController> controller = GetGeckoContentController();
if (controller) {
CSSPoint geckoScreenPoint;
if (ConvertToGecko(aPoint, &geckoScreenPoint)) {
CancelableBlockState* block = CurrentInputBlock();
MOZ_ASSERT(block);
TouchBlockState* touch = block->AsTouchBlock();
// |block| may be a non-touch block in the case where this function is
@@ -2033,17 +2034,17 @@ nsEventStatus AsyncPanZoomController::Ge
// calling controller->HandleTap directly might mean that content receives
// the single tap message before the corresponding touch-up. To avoid that we
// schedule the singletap message to run on the next spin of the event loop.
// See bug 965381 for the issue this was causing.
RefPtr<Runnable> runnable =
NewRunnableMethod<TapType, CSSPoint, mozilla::Modifiers,
ScrollableLayerGuid, uint64_t>(controller,
&GeckoContentController::HandleTap,
- TapType::eSingleTap, geckoScreenPoint,
+ aType, geckoScreenPoint,
aModifiers, GetGuid(),
touch ? touch->GetBlockId() : 0);
controller->PostDelayedTask(runnable.forget(), 0);
return nsEventStatus_eConsumeNoDefault;
}
}
return nsEventStatus_eIgnore;
@@ -2056,24 +2057,24 @@ void AsyncPanZoomController::OnTouchEndO
}
}
nsEventStatus AsyncPanZoomController::OnSingleTapUp(const TapGestureInput& aEvent) {
APZC_LOG("%p got a single-tap-up in state %d\n", this, mState);
// If mZoomConstraints.mAllowDoubleTapZoom is true we wait for a call to OnSingleTapConfirmed before
// sending event to content
if (!(mZoomConstraints.mAllowDoubleTapZoom && CurrentTouchBlock()->TouchActionAllowsDoubleTapZoom())) {
- return GenerateSingleTap(aEvent.mPoint, aEvent.modifiers);
+ return GenerateSingleTap(TapType::eSingleTap, aEvent.mPoint, aEvent.modifiers);
}
return nsEventStatus_eIgnore;
}
nsEventStatus AsyncPanZoomController::OnSingleTapConfirmed(const TapGestureInput& aEvent) {
APZC_LOG("%p got a single-tap-confirmed in state %d\n", this, mState);
- return GenerateSingleTap(aEvent.mPoint, aEvent.modifiers);
+ return GenerateSingleTap(TapType::eSingleTap, aEvent.mPoint, aEvent.modifiers);
}
nsEventStatus AsyncPanZoomController::OnDoubleTap(const TapGestureInput& aEvent) {
APZC_LOG("%p got a double-tap in state %d\n", this, mState);
RefPtr<GeckoContentController> controller = GetGeckoContentController();
if (controller) {
if (mZoomConstraints.mAllowDoubleTapZoom && CurrentTouchBlock()->TouchActionAllowsDoubleTapZoom()) {
CSSPoint geckoScreenPoint;
--- a/gfx/layers/apz/src/AsyncPanZoomController.h
+++ b/gfx/layers/apz/src/AsyncPanZoomController.h
@@ -619,17 +619,19 @@ protected:
FREE, /* No locking at all */
STANDARD, /* Default axis locking mode that remains locked until pan ends*/
STICKY, /* Allow lock to be broken, with hysteresis */
};
static AxisLockMode GetAxisLockMode();
// Helper function for OnSingleTapUp() and OnSingleTapConfirmed().
- nsEventStatus GenerateSingleTap(const ScreenIntPoint& aPoint, mozilla::Modifiers aModifiers);
+ nsEventStatus GenerateSingleTap(GeckoContentController::TapType aType,
+ const ScreenIntPoint& aPoint,
+ mozilla::Modifiers aModifiers);
// Common processing at the end of a touch block.
void OnTouchEndOrCancel();
uint64_t mLayersId;
RefPtr<CompositorBridgeParent> mCompositorBridgeParent;
/* Access to the following two fields is protected by the mRefPtrMonitor,
--- a/gfx/layers/apz/test/gtest/TestGestureDetector.cpp
+++ b/gfx/layers/apz/test/gtest/TestGestureDetector.cpp
@@ -354,19 +354,19 @@ protected:
{
InSequence s;
EXPECT_CALL(check, Call("preHandleLongTap"));
blockId++;
EXPECT_CALL(*mcc, HandleTap(TapType::eLongTap, CSSPoint(10, 10), 0, apzc->GetGuid(), blockId)).Times(1);
EXPECT_CALL(check, Call("postHandleLongTap"));
- EXPECT_CALL(check, Call("preHandleSingleTap"));
- EXPECT_CALL(*mcc, HandleTap(TapType::eSingleTap, CSSPoint(10, 10), 0, apzc->GetGuid(), _)).Times(1);
- EXPECT_CALL(check, Call("postHandleSingleTap"));
+ EXPECT_CALL(check, Call("preHandleLongTapUp"));
+ EXPECT_CALL(*mcc, HandleTap(TapType::eLongTapUp, CSSPoint(10, 10), 0, apzc->GetGuid(), _)).Times(1);
+ EXPECT_CALL(check, Call("postHandleLongTapUp"));
}
// Manually invoke the longpress while the touch is currently down.
check.Call("preHandleLongTap");
mcc->RunThroughDelayedTasks();
check.Call("postHandleLongTap");
// Dispatching the longpress event starts a new touch block, which
@@ -374,21 +374,21 @@ protected:
// in the queue. Deal with those here. We do the content response first
// with preventDefault=false, and then we run the timeout task which
// "loses the race" and does nothing.
apzc->ContentReceivedInputBlock(blockId, false);
mcc->AdvanceByMillis(1000);
// Finally, simulate lifting the finger. Since the long-press wasn't
// prevent-defaulted, we should get a long-tap-up event.
- check.Call("preHandleSingleTap");
+ check.Call("preHandleLongTapUp");
status = TouchUp(apzc, ScreenIntPoint(10, 10), mcc->Time());
mcc->RunThroughDelayedTasks();
EXPECT_EQ(nsEventStatus_eConsumeDoDefault, status);
- check.Call("postHandleSingleTap");
+ check.Call("postHandleLongTapUp");
apzc->AssertStateIsReset();
}
void DoLongPressPreventDefaultTest(uint32_t aBehavior) {
MakeApzcUnzoomable();
EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(0);
--- a/gfx/layers/apz/util/APZEventState.cpp
+++ b/gfx/layers/apz/util/APZEventState.cpp
@@ -259,16 +259,23 @@ APZEventState::ProcessLongTap(const nsCO
LayoutDeviceIntPoint ldPoint = RoundedToInt(point * widget->GetDefaultScale());
cancelTouchEvent.mTouches.AppendElement(new mozilla::dom::Touch(mLastTouchIdentifier,
ldPoint, LayoutDeviceIntPoint(), 0, 0));
APZCCallbackHelper::DispatchWidgetEvent(cancelTouchEvent);
}
}
void
+APZEventState::ProcessLongTapUp()
+{
+ nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
+ observerService->NotifyObservers(nullptr, "APZ:LongTapUp", nullptr);
+}
+
+void
APZEventState::ProcessTouchEvent(const WidgetTouchEvent& aEvent,
const ScrollableLayerGuid& aGuid,
uint64_t aInputBlockId,
nsEventStatus aApzResponse,
nsEventStatus aContentResponse)
{
if (aEvent.mMessage == eTouchStart && aEvent.mTouches.Length() > 0) {
mActiveElementManager->SetTargetElement(aEvent.mTouches[0]->GetTarget());
--- a/gfx/layers/apz/util/APZEventState.h
+++ b/gfx/layers/apz/util/APZEventState.h
@@ -49,16 +49,17 @@ public:
void ProcessSingleTap(const CSSPoint& aPoint,
Modifiers aModifiers,
const ScrollableLayerGuid& aGuid);
void ProcessLongTap(const nsCOMPtr<nsIPresShell>& aUtils,
const CSSPoint& aPoint,
Modifiers aModifiers,
const ScrollableLayerGuid& aGuid,
uint64_t aInputBlockId);
+ void ProcessLongTapUp();
void ProcessTouchEvent(const WidgetTouchEvent& aEvent,
const ScrollableLayerGuid& aGuid,
uint64_t aInputBlockId,
nsEventStatus aApzResponse,
nsEventStatus aContentResponse);
void ProcessWheelEvent(const WidgetWheelEvent& aEvent,
const ScrollableLayerGuid& aGuid,
uint64_t aInputBlockId);
--- a/gfx/layers/apz/util/ChromeProcessController.cpp
+++ b/gfx/layers/apz/util/ChromeProcessController.cpp
@@ -163,16 +163,19 @@ ChromeProcessController::HandleTap(TapTy
break;
case TapType::eDoubleTap:
HandleDoubleTap(aPoint, aModifiers, aGuid);
break;
case TapType::eLongTap:
mAPZEventState->ProcessLongTap(GetPresShell(), aPoint, aModifiers, aGuid,
aInputBlockId);
break;
+ case TapType::eLongTapUp:
+ mAPZEventState->ProcessLongTapUp();
+ break;
case TapType::eSentinel:
// Should never happen, but we need to handle this case branch for the
// compiler to be happy.
MOZ_ASSERT(false);
break;
}
}