Bug 970578: Add tests for preventDefault and long tap behavior to gtest. r=kats
authorDoug Sherk <bugzilla@sherk.me>
Thu, 13 Feb 2014 11:24:53 -0500
changeset 169287 3305c1509a286a24a07781b68fd9ebf586c9281c
parent 169286 d8462ffa097d7b3caf6b5ea4762aba6b097df410
child 169288 4fadd825bf81154bfece1b72abaca475ef6e4021
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
reviewerskats
bugs970578
milestone30.0a1
Bug 970578: Add tests for preventDefault and long tap behavior to gtest. r=kats
gfx/tests/gtest/TestAsyncPanZoomController.cpp
--- a/gfx/tests/gtest/TestAsyncPanZoomController.cpp
+++ b/gfx/tests/gtest/TestAsyncPanZoomController.cpp
@@ -19,16 +19,18 @@
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 using namespace mozilla::layers;
 using ::testing::_;
 using ::testing::NiceMock;
 using ::testing::AtLeast;
 using ::testing::AtMost;
+using ::testing::MockFunction;
+using ::testing::InSequence;
 
 class Task;
 
 class MockContentController : public GeckoContentController {
 public:
   MOCK_METHOD1(RequestContentRepaint, void(const FrameMetrics&));
   MOCK_METHOD2(AcknowledgeScrollUpdate, void(const FrameMetrics::ViewID&, const uint32_t& aScrollGeneration));
   MOCK_METHOD3(HandleDoubleTap, void(const CSSIntPoint&, int32_t, const ScrollableLayerGuid&));
@@ -141,62 +143,72 @@ FrameMetrics TestFrameMetrics() {
   return fm;
 }
 
 /*
  * Dispatches mock touch events to the apzc and checks whether apzc properly
  * consumed them and triggered scrolling behavior.
  */
 static
-void ApzcPan(AsyncPanZoomController* apzc, TestAPZCTreeManager* aTreeManager, int& aTime, int aTouchStartY, int aTouchEndY, bool expectIgnoredPan = false) {
+void ApzcPan(AsyncPanZoomController* apzc, TestAPZCTreeManager* aTreeManager, int& aTime, int aTouchStartY, int aTouchEndY, bool expectIgnoredPan = false, bool hasTouchListeners = false) {
 
   const int TIME_BETWEEN_TOUCH_EVENT = 100;
   const int OVERCOME_TOUCH_TOLERANCE = 100;
   MultiTouchInput mti;
   nsEventStatus status;
 
   // Since we're passing inputs directly to the APZC instead of going through
   // the tree manager, we need to build the overscroll handoff chain explicitly
   // for panning to work correctly.
   aTreeManager->BuildOverscrollHandoffChain(apzc);
 
+  nsEventStatus touchStartStatus;
+  if (hasTouchListeners) {
+    // APZC shouldn't consume the start event now, instead queueing it up
+    // waiting for content's response.
+    touchStartStatus = nsEventStatus_eIgnore;
+  } else {
+    // APZC should go into the touching state and therefore consume the event.
+    touchStartStatus = nsEventStatus_eConsumeNoDefault;
+  }
+
   mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_START, aTime, 0);
   aTime += TIME_BETWEEN_TOUCH_EVENT;
   // Make sure the move is large enough to not be handled as a tap
   mti.mTouches.AppendElement(SingleTouchData(0, ScreenIntPoint(10, aTouchStartY+OVERCOME_TOUCH_TOLERANCE), ScreenSize(0, 0), 0, 0));
-  status = apzc->HandleInputEvent(mti);
-  EXPECT_EQ(status, nsEventStatus_eConsumeNoDefault);
+  status = apzc->ReceiveInputEvent(mti);
+  EXPECT_EQ(status, touchStartStatus);
   // APZC should be in TOUCHING state
 
   nsEventStatus touchMoveStatus;
   if (expectIgnoredPan) {
     // APZC should ignore panning, be in TOUCHING state and therefore return eIgnore.
     // The same applies to all consequent touch move events.
     touchMoveStatus = nsEventStatus_eIgnore;
   } else {
     // APZC should go into the panning state and therefore consume the event.
     touchMoveStatus = nsEventStatus_eConsumeNoDefault;
   }
 
   mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, aTime, 0);
   aTime += TIME_BETWEEN_TOUCH_EVENT;
   mti.mTouches.AppendElement(SingleTouchData(0, ScreenIntPoint(10, aTouchStartY), ScreenSize(0, 0), 0, 0));
-  status = apzc->HandleInputEvent(mti);
+  status = apzc->ReceiveInputEvent(mti);
   EXPECT_EQ(status, touchMoveStatus);
 
   mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, aTime, 0);
   aTime += TIME_BETWEEN_TOUCH_EVENT;
   mti.mTouches.AppendElement(SingleTouchData(0, ScreenIntPoint(10, aTouchEndY), ScreenSize(0, 0), 0, 0));
-  status = apzc->HandleInputEvent(mti);
+  status = apzc->ReceiveInputEvent(mti);
   EXPECT_EQ(status, touchMoveStatus);
 
   mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_END, aTime, 0);
   aTime += TIME_BETWEEN_TOUCH_EVENT;
   mti.mTouches.AppendElement(SingleTouchData(0, ScreenIntPoint(10, aTouchEndY), ScreenSize(0, 0), 0, 0));
-  status = apzc->HandleInputEvent(mti);
+  status = apzc->ReceiveInputEvent(mti);
 }
 
 static
 void DoPanTest(bool aShouldTriggerScroll, bool aShouldUseTouchAction, uint32_t aBehavior)
 {
   TimeStamp testStartTime = TimeStamp::Now();
   AsyncPanZoomController::SetFrameTime(testStartTime);
 
@@ -553,16 +565,54 @@ TEST(AsyncPanZoomController, PanWithTouc
 TEST(AsyncPanZoomController, PanWithTouchActionPanX) {
   DoPanTest(false, true, mozilla::layers::AllowedTouchBehavior::HORIZONTAL_PAN);
 }
 
 TEST(AsyncPanZoomController, PanWithTouchActionPanY) {
   DoPanTest(true, true, mozilla::layers::AllowedTouchBehavior::VERTICAL_PAN);
 }
 
+TEST(AsyncPanZoomController, PanWithPreventDefault) {
+  TimeStamp testStartTime = TimeStamp::Now();
+  AsyncPanZoomController::SetFrameTime(testStartTime);
+
+  nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
+  nsRefPtr<TestAPZCTreeManager> tm = new TestAPZCTreeManager();
+  nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc, tm);
+
+  FrameMetrics frameMetrics(TestFrameMetrics());
+  frameMetrics.mMayHaveTouchListeners = true;
+
+  apzc->SetFrameMetrics(frameMetrics);
+  apzc->NotifyLayersUpdated(frameMetrics, true);
+
+  int time = 0;
+  int touchStart = 50;
+  int touchEnd = 10;
+  ScreenPoint pointOut;
+  ViewTransform viewTransformOut;
+
+  // Pan down
+  nsTArray<uint32_t> values;
+  values.AppendElement(mozilla::layers::AllowedTouchBehavior::VERTICAL_PAN);
+  apzc->SetTouchActionEnabled(true);
+  apzc->SetAllowedTouchBehavior(values);
+  ApzcPan(apzc, tm, time, touchStart, touchEnd, true, true);
+
+  // Send the signal that content has handled and preventDefaulted the touch
+  // events. This flushes the event queue.
+  apzc->ContentReceivedTouch(true);
+
+  apzc->SampleContentTransformForFrame(testStartTime, &viewTransformOut, pointOut);
+  EXPECT_EQ(pointOut, ScreenPoint());
+  EXPECT_EQ(viewTransformOut, ViewTransform());
+
+  apzc->Destroy();
+}
+
 TEST(AsyncPanZoomController, Fling) {
   TimeStamp testStartTime = TimeStamp::Now();
   AsyncPanZoomController::SetFrameTime(testStartTime);
 
   nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
   nsRefPtr<TestAPZCTreeManager> tm = new TestAPZCTreeManager();
   nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc, tm);
 
@@ -673,33 +723,123 @@ TEST(AsyncPanZoomController, LongPress) 
   apzc->NotifyLayersUpdated(TestFrameMetrics(), true);
   apzc->UpdateZoomConstraints(ZoomConstraints(false, CSSToScreenScale(1.0), CSSToScreenScale(1.0)));
 
   int time = 0;
 
   nsEventStatus status = ApzcDown(apzc, 10, 10, time);
   EXPECT_EQ(nsEventStatus_eConsumeNoDefault, status);
 
+  MockFunction<void(std::string checkPointName)> check;
+
+  {
+    InSequence s;
+
+    EXPECT_CALL(check, Call("preHandleLongTap"));
+    EXPECT_CALL(*mcc, HandleLongTap(CSSIntPoint(10, 10), 0, apzc->GetGuid())).Times(1);
+    EXPECT_CALL(check, Call("postHandleLongTap"));
+
+    EXPECT_CALL(check, Call("preHandleLongTapUp"));
+    EXPECT_CALL(*mcc, HandleLongTapUp(CSSIntPoint(10, 10), 0, apzc->GetGuid())).Times(1);
+    EXPECT_CALL(check, Call("postHandleLongTapUp"));
+  }
+
   mcc->CheckHasDelayedTask();
-  EXPECT_CALL(*mcc, HandleLongTap(CSSIntPoint(10, 10), 0, apzc->GetGuid())).Times(1);
 
   // Manually invoke the longpress while the touch is currently down.
+  check.Call("preHandleLongTap");
   mcc->RunDelayedTask();
+  check.Call("postHandleLongTap");
 
   time += 1000;
 
   status = ApzcUp(apzc, 10, 10, time);
   EXPECT_EQ(nsEventStatus_eIgnore, status);
 
-  EXPECT_CALL(*mcc, HandleLongTapUp(CSSIntPoint(10, 10), 0, apzc->GetGuid())).Times(1);
-
   // To get a LongTapUp event, we must kick APZC to flush its event queue. This
   // would normally happen if we had a (Tab|RenderFrame)(Parent|Child)
   // mechanism.
+  check.Call("preHandleLongTapUp");
   apzc->ContentReceivedTouch(false);
+  check.Call("postHandleLongTapUp");
+
+  apzc->Destroy();
+}
+
+TEST(AsyncPanZoomController, LongPressPreventDefault) {
+  // We have to initialize both an integer time and TimeStamp time because
+  // TimeStamp doesn't have any ToXXX() functions for converting back to
+  // primitives.
+  TimeStamp testStartTime = TimeStamp::Now();
+  int time = 0;
+  AsyncPanZoomController::SetFrameTime(testStartTime);
+
+  nsRefPtr<MockContentControllerDelayed> mcc = new MockContentControllerDelayed();
+  nsRefPtr<TestAPZCTreeManager> tm = new TestAPZCTreeManager();
+  nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(
+    0, mcc, tm, AsyncPanZoomController::USE_GESTURE_DETECTOR);
+
+  apzc->SetFrameMetrics(TestFrameMetrics());
+  apzc->NotifyLayersUpdated(TestFrameMetrics(), true);
+  apzc->UpdateZoomConstraints(ZoomConstraints(false, CSSToScreenScale(1.0), CSSToScreenScale(1.0)));
+
+  EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(0);
+  EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(0);
+
+  int touchX = 10,
+      touchStartY = 10,
+      touchEndY = 50;
+
+  nsEventStatus status = ApzcDown(apzc, touchX, touchStartY, time);
+  EXPECT_EQ(nsEventStatus_eConsumeNoDefault, status);
+
+  MockFunction<void(std::string checkPointName)> check;
+
+  {
+    InSequence s;
+
+    EXPECT_CALL(check, Call("preHandleLongTap"));
+    EXPECT_CALL(*mcc, HandleLongTap(CSSIntPoint(touchX, touchStartY), 0, apzc->GetGuid())).Times(1);
+    EXPECT_CALL(check, Call("postHandleLongTap"));
+  }
+
+  mcc->CheckHasDelayedTask();
+
+  // Manually invoke the longpress while the touch is currently down.
+  check.Call("preHandleLongTap");
+  mcc->RunDelayedTask();
+  check.Call("postHandleLongTap");
+
+  // Clear the waiting-for-content timeout task, then send the signal that
+  // content has handled this long tap. This takes the place of the
+  // "contextmenu" event.
+  mcc->ClearDelayedTask();
+  apzc->ContentReceivedTouch(true);
+
+  time += 1000;
+
+  MultiTouchInput mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, time, 0);
+  mti.mTouches.AppendElement(SingleTouchData(0, ScreenIntPoint(touchX, touchEndY), ScreenSize(0, 0), 0, 0));
+  status = apzc->ReceiveInputEvent(mti);
+  EXPECT_EQ(status, nsEventStatus_eIgnore);
+
+  status = ApzcUp(apzc, touchX, touchEndY, time);
+  EXPECT_EQ(nsEventStatus_eIgnore, status);
+
+  // Flush the event queue. Once the "contextmenu" event is handled, any touch
+  // events that come from the same series of start->n*move->end events should
+  // be discarded, even if only the "contextmenu" event is preventDefaulted.
+  apzc->ContentReceivedTouch(false);
+
+  ScreenPoint pointOut;
+  ViewTransform viewTransformOut;
+  apzc->SampleContentTransformForFrame(testStartTime, &viewTransformOut, pointOut);
+
+  EXPECT_EQ(pointOut, ScreenPoint());
+  EXPECT_EQ(viewTransformOut, ViewTransform());
 
   apzc->Destroy();
 }
 
 // Layer tree for HitTesting1
 static already_AddRefed<mozilla::layers::Layer>
 CreateTestLayerTree1(nsRefPtr<LayerManager>& aLayerManager, nsTArray<nsRefPtr<Layer> >& aLayers) {
   const char* layerTreeSyntax = "c(ttcc)";