Bug 1256339 - Add a eLongTapUp tap type, which fires an observer notification rather than doing a click. r?botond draft
authorKartikaya Gupta <kgupta@mozilla.com>
Sat, 02 Jul 2016 18:29:09 -0400
changeset 383358 03e82976e79625b9dd7f5b8db4123759270b38cf
parent 383357 97585bb7b1a916cadb5b22ba3bdeaabe3dbe531f
child 383359 a091d39a12bbae496c6a2c6e6b90eac30dd9cf7e
push id21994
push userkgupta@mozilla.com
push dateSat, 02 Jul 2016 22:29:37 +0000
reviewersbotond
bugs1256339
milestone50.0a1
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
dom/ipc/TabChild.cpp
gfx/layers/apz/public/GeckoContentController.h
gfx/layers/apz/src/AsyncPanZoomController.cpp
gfx/layers/apz/src/AsyncPanZoomController.h
gfx/layers/apz/test/gtest/TestGestureDetector.cpp
gfx/layers/apz/util/APZEventState.cpp
gfx/layers/apz/util/APZEventState.h
gfx/layers/apz/util/ChromeProcessController.cpp
--- 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;
   }
 }