Bug 1073250 - Gtest for stuck-in-apz-overscroll bug. r=kats, a=bajaj
authorBotond Ballo <botond@mozilla.com>
Fri, 03 Oct 2014 20:35:16 -0400
changeset 225516 cf80dc75fc512549bffbd883752a144426a65cc2
parent 225515 cecf4403ba9d5ce87b4f942df36a7c7dc73c11c5
child 225517 1a276040b6ba7e98c79a2869fd84bc0af2300aa5
push id3979
push userraliiev@mozilla.com
push dateMon, 13 Oct 2014 16:35:44 +0000
treeherdermozilla-beta@30f2cc610691 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskats, bajaj
bugs1073250
milestone34.0a2
Bug 1073250 - Gtest for stuck-in-apz-overscroll bug. r=kats, a=bajaj
gfx/tests/gtest/TestAsyncPanZoomController.cpp
--- a/gfx/tests/gtest/TestAsyncPanZoomController.cpp
+++ b/gfx/tests/gtest/TestAsyncPanZoomController.cpp
@@ -1502,16 +1502,65 @@ protected:
     SetScrollableFrameMetrics(layers[0], FrameMetrics::START_SCROLL_ID);
     SetScrollableFrameMetrics(layers[2], FrameMetrics::START_SCROLL_ID + 1);
     SetScrollableFrameMetrics(layers[5], FrameMetrics::START_SCROLL_ID + 1);
     SetScrollableFrameMetrics(layers[3], FrameMetrics::START_SCROLL_ID + 2);
     SetScrollableFrameMetrics(layers[6], FrameMetrics::START_SCROLL_ID + 3);
   }
 };
 
+// A version of ApzcPan() that routes the pan through the tree manager,
+// so that the tree manager has the appropriate state for testing.
+static void
+ApzctmPan(APZCTreeManager* aTreeManager,
+          int& aTime,
+          int aTouchStartY,
+          int aTouchEndY,
+          bool aKeepFingerDown = false)
+{
+  // TODO: Reuse some code between this and ApzcPan().
+
+  // Reduce the touch start tolerance to a tiny value.
+  // We can't do what ApzcPan() does to overcome the tolerance (send the
+  // touch-start at (aTouchStartY + some_large_value)) because the tree manager
+  // does hit testing based on the touch-start coordinates, and a different
+  // APZC than the one we intend might be hit.
+  SCOPED_GFX_PREF(APZTouchStartTolerance, float, 1.0f / 1000.0f);
+  const int OVERCOME_TOUCH_TOLERANCE = 1;
+
+  const int TIME_BETWEEN_TOUCH_EVENT = 100;
+
+  // Make sure the move is large enough to not be handled as a tap
+  MultiTouchInput mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_START, aTime, TimeStamp(), 0);
+  mti.mTouches.AppendElement(SingleTouchData(0, ScreenIntPoint(10, aTouchStartY), ScreenSize(0, 0), 0, 0));
+  aTreeManager->ReceiveInputEvent(mti, nullptr);
+
+  aTime += TIME_BETWEEN_TOUCH_EVENT;
+
+  mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, aTime, TimeStamp(), 0);
+  mti.mTouches.AppendElement(SingleTouchData(0, ScreenIntPoint(10, aTouchStartY + OVERCOME_TOUCH_TOLERANCE), ScreenSize(0, 0), 0, 0));
+  aTreeManager->ReceiveInputEvent(mti, nullptr);
+
+  aTime += TIME_BETWEEN_TOUCH_EVENT;
+
+  mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, aTime, TimeStamp(), 0);
+  mti.mTouches.AppendElement(SingleTouchData(0, ScreenIntPoint(10, aTouchEndY), ScreenSize(0, 0), 0, 0));
+  aTreeManager->ReceiveInputEvent(mti, nullptr);
+
+  aTime += TIME_BETWEEN_TOUCH_EVENT;
+
+  if (!aKeepFingerDown) {
+    mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_END, aTime, TimeStamp(), 0);
+    mti.mTouches.AppendElement(SingleTouchData(0, ScreenIntPoint(10, aTouchEndY), ScreenSize(0, 0), 0, 0));
+    aTreeManager->ReceiveInputEvent(mti, nullptr);
+  }
+
+  aTime += TIME_BETWEEN_TOUCH_EVENT;
+}
+
 class APZHitTestingTester : public APZCTreeManagerTester {
 protected:
   Matrix4x4 transformToApzc;
   Matrix4x4 transformToGecko;
 
   already_AddRefed<AsyncPanZoomController> GetTargetAPZC(const ScreenPoint& aPoint) {
     nsRefPtr<AsyncPanZoomController> hit = manager->GetTargetAPZC(aPoint, nullptr);
     if (hit) {
@@ -2011,16 +2060,53 @@ TEST_F(APZOverscrollHandoffTester, Layer
 
   // Make sure things have scrolled according to the handoff chain in
   // place at the time the touch-start of the second pan was queued.
   EXPECT_EQ(0, childApzc->GetFrameMetrics().GetScrollOffset().y);
   EXPECT_EQ(10, rootApzc->GetFrameMetrics().GetScrollOffset().y);
   EXPECT_EQ(-10, middleApzc->GetFrameMetrics().GetScrollOffset().y);
 }
 
+// Test that putting a second finger down on an APZC while a down-chain APZC
+// is overscrolled doesn't result in being stuck in overscroll.
+TEST_F(APZOverscrollHandoffTester, StuckInOverscroll_Bug1073250) {
+  // Enable overscrolling.
+  SCOPED_GFX_PREF(APZOverscrollEnabled, bool, true);
+
+  CreateOverscrollHandoffLayerTree1();
+
+  TestAsyncPanZoomController* child = ApzcOf(layers[1]);
+
+  // Pan, causing the parent APZC to overscroll.
+  int time = 0;
+  ApzctmPan(manager, time, 10, 40, true /* keep finger down */);
+  EXPECT_FALSE(child->IsOverscrolled());
+  EXPECT_TRUE(rootApzc->IsOverscrolled());
+
+  // Put a second finger down.
+  MultiTouchInput secondFingerDown(MultiTouchInput::MULTITOUCH_START, 0, TimeStamp(), 0);
+  // Use the same touch identifier for the first touch (0) as ApzctmPan(). (A bit hacky.)
+  secondFingerDown.mTouches.AppendElement(SingleTouchData(0, ScreenIntPoint(10, 40), ScreenSize(0, 0), 0, 0));
+  secondFingerDown.mTouches.AppendElement(SingleTouchData(1, ScreenIntPoint(30, 20), ScreenSize(0, 0), 0, 0));
+  manager->ReceiveInputEvent(secondFingerDown, nullptr);
+
+  // Release the fingers.
+  MultiTouchInput fingersUp = secondFingerDown;
+  fingersUp.mType = MultiTouchInput::MULTITOUCH_END;
+  manager->ReceiveInputEvent(fingersUp, nullptr);
+
+  // Allow any animations to run their course.
+  child->AdvanceAnimationsUntilEnd(testStartTime);
+  rootApzc->AdvanceAnimationsUntilEnd(testStartTime);
+
+  // Make sure nothing is overscrolled.
+  EXPECT_FALSE(child->IsOverscrolled());
+  EXPECT_FALSE(rootApzc->IsOverscrolled());
+}
+
 // Here we test that if two flings are happening simultaneously, overscroll
 // is handed off correctly for each.
 TEST_F(APZOverscrollHandoffTester, SimultaneousFlings) {
   // Set up an initial APZC tree.
   CreateOverscrollHandoffLayerTree3();
 
   TestAsyncPanZoomController* parent1 = ApzcOf(layers[1]);
   TestAsyncPanZoomController* child1 = ApzcOf(layers[2]);