tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

TestPanning.cpp (22943B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "APZCBasicTester.h"
      8 #include "APZCTreeManagerTester.h"
      9 #include "APZTestCommon.h"
     10 #include "FrameMetrics.h"
     11 #include "InputUtils.h"
     12 #include "gtest/gtest.h"
     13 #include "mozilla/ScrollSnapInfo.h"
     14 #include "mozilla/ServoComputedData.h"
     15 #include "mozilla/gfx/CompositorHitTestInfo.h"
     16 #include "mozilla/layers/ScrollableLayerGuid.h"
     17 
     18 class APZCPanningTester : public APZCBasicTester {
     19 protected:
     20  void DoPanTest(bool aShouldTriggerScroll, bool aShouldBeConsumed,
     21                 uint32_t aBehavior) {
     22    if (aShouldTriggerScroll) {
     23      // Three repaint request for each pan.
     24      EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(6);
     25    } else {
     26      EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(0);
     27    }
     28 
     29    int touchStart = 50;
     30    int touchEnd = 10;
     31    ParentLayerPoint pointOut;
     32    AsyncTransform viewTransformOut;
     33 
     34    nsTArray<uint32_t> allowedTouchBehaviors;
     35    allowedTouchBehaviors.AppendElement(aBehavior);
     36 
     37    // Pan down
     38    PanAndCheckStatus(apzc, touchStart, touchEnd, aShouldBeConsumed,
     39                      &allowedTouchBehaviors);
     40    apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut);
     41 
     42    if (aShouldTriggerScroll) {
     43      EXPECT_EQ(ParentLayerPoint(0, -(touchEnd - touchStart)), pointOut);
     44      EXPECT_NE(AsyncTransform(), viewTransformOut);
     45    } else {
     46      EXPECT_EQ(ParentLayerPoint(), pointOut);
     47      EXPECT_EQ(AsyncTransform(), viewTransformOut);
     48    }
     49 
     50    // Clear the fling from the previous pan, or stopping it will
     51    // consume the next touchstart
     52    apzc->CancelAnimation();
     53 
     54    // Pan back
     55    PanAndCheckStatus(apzc, touchEnd, touchStart, aShouldBeConsumed,
     56                      &allowedTouchBehaviors);
     57    apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut);
     58 
     59    EXPECT_EQ(ParentLayerPoint(), pointOut);
     60    EXPECT_EQ(AsyncTransform(), viewTransformOut);
     61  }
     62 
     63  void DoPanWithPreventDefaultTest() {
     64    MakeApzcWaitForMainThread();
     65 
     66    int touchStart = 50;
     67    int touchEnd = 10;
     68    ParentLayerPoint pointOut;
     69    AsyncTransform viewTransformOut;
     70    uint64_t blockId = 0;
     71 
     72    // Pan down
     73    nsTArray<uint32_t> allowedTouchBehaviors;
     74    allowedTouchBehaviors.AppendElement(
     75        mozilla::layers::AllowedTouchBehavior::VERTICAL_PAN);
     76    PanAndCheckStatus(apzc, touchStart, touchEnd, true, &allowedTouchBehaviors,
     77                      &blockId);
     78 
     79    // Send the signal that content has handled and preventDefaulted the touch
     80    // events. This flushes the event queue.
     81    apzc->ContentReceivedInputBlock(blockId, true);
     82 
     83    apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut);
     84    EXPECT_EQ(ParentLayerPoint(), pointOut);
     85    EXPECT_EQ(AsyncTransform(), viewTransformOut);
     86 
     87    apzc->AssertStateIsReset();
     88  }
     89 
     90  void PanWithFling() {
     91    // Send a pan gesture that triggers a fling animation at the end.
     92    // Note that we need at least two _PAN events to have enough samples
     93    // in the velocity tracker to compute a fling velocity.
     94    PanGesture(PanGestureInput::PANGESTURE_START, apzc, ScreenIntPoint(50, 80),
     95               ScreenPoint(0, 2), mcc->Time());
     96    mcc->AdvanceByMillis(5);
     97    apzc->AdvanceAnimations(mcc->GetSampleTime());
     98    PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80),
     99               ScreenPoint(0, 10), mcc->Time());
    100    mcc->AdvanceByMillis(5);
    101    apzc->AdvanceAnimations(mcc->GetSampleTime());
    102    PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80),
    103               ScreenPoint(0, 10), mcc->Time());
    104    mcc->AdvanceByMillis(5);
    105    apzc->AdvanceAnimations(mcc->GetSampleTime());
    106    PanGesture(PanGestureInput::PANGESTURE_END, apzc, ScreenIntPoint(50, 80),
    107               ScreenPoint(0, 0), mcc->Time(), MODIFIER_NONE,
    108               /*aSimulateMomentum=*/true);
    109  }
    110 };
    111 
    112 // In the each of the following 4 pan tests we are performing two pan gestures:
    113 // vertical pan from top to bottom and back - from bottom to top. According to
    114 // the pointer-events/touch-action spec AUTO and PAN_Y touch-action values allow
    115 // vertical scrolling while NONE and PAN_X forbid it. The first parameter of
    116 // DoPanTest method specifies this behavior. However, the events will be marked
    117 // as consumed even if the behavior in PAN_X, because the user could move their
    118 // finger horizontally too - APZ has no way of knowing beforehand and so must
    119 // consume the events.
    120 TEST_F(APZCPanningTester, PanWithTouchActionAuto) {
    121  // Velocity bias can cause extra repaint requests.
    122  SCOPED_GFX_PREF_FLOAT("apz.velocity_bias", 0.0);
    123  DoPanTest(true, true,
    124            mozilla::layers::AllowedTouchBehavior::HORIZONTAL_PAN |
    125                mozilla::layers::AllowedTouchBehavior::VERTICAL_PAN);
    126 }
    127 
    128 TEST_F(APZCPanningTester, PanWithTouchActionNone) {
    129  // Velocity bias can cause extra repaint requests.
    130  SCOPED_GFX_PREF_FLOAT("apz.velocity_bias", 0.0);
    131  DoPanTest(false, false, 0);
    132 }
    133 
    134 TEST_F(APZCPanningTester, PanWithTouchActionPanX) {
    135  // Velocity bias can cause extra repaint requests.
    136  SCOPED_GFX_PREF_FLOAT("apz.velocity_bias", 0.0);
    137  DoPanTest(false, false,
    138            mozilla::layers::AllowedTouchBehavior::HORIZONTAL_PAN);
    139 }
    140 
    141 TEST_F(APZCPanningTester, PanWithTouchActionPanY) {
    142  // Velocity bias can cause extra repaint requests.
    143  SCOPED_GFX_PREF_FLOAT("apz.velocity_bias", 0.0);
    144  DoPanTest(true, true, mozilla::layers::AllowedTouchBehavior::VERTICAL_PAN);
    145 }
    146 
    147 TEST_F(APZCPanningTester, PanWithPreventDefault) {
    148  DoPanWithPreventDefaultTest();
    149 }
    150 
    151 TEST_F(APZCPanningTester, PanWithHistoricalTouchData) {
    152  SCOPED_GFX_PREF_FLOAT("apz.fling_min_velocity_threshold", 0.0);
    153 
    154  // Simulate the same pan gesture, in three different ways.
    155  // We start at y=50, with a 50ms resting period at the start of the pan.
    156  // Then we accelerate the finger upwards towards y=10, reaching a 10px/10ms
    157  // velocity towards the end of the panning motion.
    158  //
    159  // The first simulation fires touch move events with 10ms gaps.
    160  // The second simulation skips two of the touch move events, simulating
    161  // "jank". The third simulation also skips those two events, but reports the
    162  // missed positions in the following event's historical coordinates.
    163  //
    164  // Consequently, the first and third simulation should estimate the same
    165  // velocities, whereas the second simulation should estimate a different
    166  // velocity because it is missing data.
    167 
    168  // First simulation: full data
    169 
    170  APZEventResult result = TouchDown(apzc, ScreenIntPoint(0, 50), mcc->Time());
    171  if (result.GetStatus() != nsEventStatus_eConsumeNoDefault) {
    172    SetDefaultAllowedTouchBehavior(apzc, result.mInputBlockId);
    173  }
    174 
    175  mcc->AdvanceByMillis(50);
    176  result = TouchMove(apzc, ScreenIntPoint(0, 45), mcc->Time());
    177  mcc->AdvanceByMillis(10);
    178  result = TouchMove(apzc, ScreenIntPoint(0, 40), mcc->Time());
    179  mcc->AdvanceByMillis(10);
    180  result = TouchMove(apzc, ScreenIntPoint(0, 30), mcc->Time());
    181  mcc->AdvanceByMillis(10);
    182  result = TouchMove(apzc, ScreenIntPoint(0, 20), mcc->Time());
    183  result = TouchUp(apzc, ScreenIntPoint(0, 20), mcc->Time());
    184  auto velocityFromFullDataAsSeparateEvents = apzc->GetVelocityVector();
    185  apzc->CancelAnimation();
    186 
    187  mcc->AdvanceByMillis(100);
    188 
    189  // Second simulation: partial data
    190 
    191  result = TouchDown(apzc, ScreenIntPoint(0, 50), mcc->Time());
    192  if (result.GetStatus() != nsEventStatus_eConsumeNoDefault) {
    193    SetDefaultAllowedTouchBehavior(apzc, result.mInputBlockId);
    194  }
    195 
    196  mcc->AdvanceByMillis(50);
    197  result = TouchMove(apzc, ScreenIntPoint(0, 45), mcc->Time());
    198  mcc->AdvanceByMillis(30);
    199  result = TouchMove(apzc, ScreenIntPoint(0, 20), mcc->Time());
    200  result = TouchUp(apzc, ScreenIntPoint(0, 20), mcc->Time());
    201  auto velocityFromPartialData = apzc->GetVelocityVector();
    202  apzc->CancelAnimation();
    203 
    204  mcc->AdvanceByMillis(100);
    205 
    206  // Third simulation: full data via historical data
    207 
    208  result = TouchDown(apzc, ScreenIntPoint(0, 50), mcc->Time());
    209  if (result.GetStatus() != nsEventStatus_eConsumeNoDefault) {
    210    SetDefaultAllowedTouchBehavior(apzc, result.mInputBlockId);
    211  }
    212 
    213  mcc->AdvanceByMillis(50);
    214  result = TouchMove(apzc, ScreenIntPoint(0, 45), mcc->Time());
    215  mcc->AdvanceByMillis(30);
    216 
    217  MultiTouchInput mti =
    218      CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, mcc->Time());
    219  auto singleTouchData = CreateSingleTouchData(0, ScreenIntPoint(0, 20));
    220  singleTouchData.mHistoricalData.AppendElement(
    221      SingleTouchData::HistoricalTouchData{
    222          mcc->Time() - TimeDuration::FromMilliseconds(20),
    223          ScreenIntPoint(0, 40),
    224          {},
    225          {},
    226          0.0f,
    227          0.0f});
    228  singleTouchData.mHistoricalData.AppendElement(
    229      SingleTouchData::HistoricalTouchData{
    230          mcc->Time() - TimeDuration::FromMilliseconds(10),
    231          ScreenIntPoint(0, 30),
    232          {},
    233          {},
    234          0.0f,
    235          0.0f});
    236  mti.mTouches.AppendElement(singleTouchData);
    237  result = apzc->ReceiveInputEvent(mti);
    238 
    239  result = TouchUp(apzc, ScreenIntPoint(0, 20), mcc->Time());
    240  auto velocityFromFullDataViaHistory = apzc->GetVelocityVector();
    241  apzc->CancelAnimation();
    242 
    243  EXPECT_EQ(velocityFromFullDataAsSeparateEvents,
    244            velocityFromFullDataViaHistory);
    245  EXPECT_NE(velocityFromPartialData, velocityFromFullDataViaHistory);
    246 }
    247 
    248 TEST_F(APZCPanningTester, DuplicatePanEndEvents_Bug1833950) {
    249  // Send a pan gesture that triggers a fling animation at the end.
    250  PanWithFling();
    251 
    252  // Give the fling animation a chance to start.
    253  SampleAnimationOnce();
    254  apzc->AssertStateIsFling();
    255 
    256  // Send a duplicate pan-end event.
    257  // This test is just intended to check that doing this doesn't
    258  // trigger an assertion failure in debug mode.
    259  PanGesture(PanGestureInput::PANGESTURE_END, apzc, ScreenIntPoint(50, 80),
    260             ScreenPoint(0, 0), mcc->Time(), MODIFIER_NONE,
    261             /*aSimulateMomentum=*/true);
    262 }
    263 
    264 class APZCPanningTesterMock : public APZCTreeManagerTester {
    265 public:
    266  APZCPanningTesterMock() { CreateMockHitTester(); }
    267 };
    268 
    269 TEST_F(APZCPanningTester, HoldGesture_HoldAndRelease) {
    270  // Send a pan gesture that triggers a fling animation at the end.
    271  PanWithFling();
    272 
    273  // Give the fling animation a chance to start.
    274  SampleAnimationOnce();
    275  apzc->AssertStateIsFling();
    276 
    277  // Send a PANGESTURE_MAYSTART event, signifying that the fingers went back
    278  // down on the touchpad.
    279  PanGesture(PanGestureInput::PANGESTURE_MAYSTART, apzc, ScreenIntPoint(50, 80),
    280             ScreenPoint(0, 0), mcc->Time());
    281 
    282  // This should have had the effect of cancelling the fling animation.
    283  apzc->AssertStateIsReset();
    284 
    285  // Send a PANGESTURE_CANCELLED event, signifying that the fingers have been
    286  // lifted without any scrolling. This should have no effect on the gesture
    287  // state.
    288  mcc->AdvanceByMillis(5);
    289  apzc->AdvanceAnimations(mcc->GetSampleTime());
    290  PanGesture(PanGestureInput::PANGESTURE_CANCELLED, apzc,
    291             ScreenIntPoint(50, 80), ScreenPoint(0, 0), mcc->Time());
    292  apzc->AssertStateIsReset();
    293 }
    294 
    295 TEST_F(APZCPanningTester, HoldGesture_HoldAndScroll) {
    296  // Send a pan gesture that triggers a fling animation at the end.
    297  PanWithFling();
    298 
    299  // Give the fling animation a chance to start.
    300  SampleAnimationOnce();
    301  apzc->AssertStateIsFling();
    302 
    303  // Record the scroll offset before the fingers go back.
    304  float scrollYBefore = apzc->GetFrameMetrics().GetVisualScrollOffset().y;
    305  EXPECT_GT(scrollYBefore, 0);
    306 
    307  // Send a PANGESTURE_MAYSTART event, signifying that the fingers went back
    308  // down on the touchpad.
    309  PanGesture(PanGestureInput::PANGESTURE_MAYSTART, apzc, ScreenIntPoint(50, 80),
    310             ScreenPoint(0, 0), mcc->Time());
    311 
    312  // This should have had the effect of cancelling the fling animation.
    313  apzc->AssertStateIsReset();
    314 
    315  // Do actual panning as part of the same gesture.
    316  mcc->AdvanceByMillis(5);
    317  apzc->AdvanceAnimations(mcc->GetSampleTime());
    318  PanGesture(PanGestureInput::PANGESTURE_START, apzc, ScreenIntPoint(50, 80),
    319             ScreenPoint(0, 2), mcc->Time());
    320  mcc->AdvanceByMillis(5);
    321  apzc->AdvanceAnimations(mcc->GetSampleTime());
    322  PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80),
    323             ScreenPoint(0, 10), mcc->Time());
    324  mcc->AdvanceByMillis(5);
    325  apzc->AdvanceAnimations(mcc->GetSampleTime());
    326  PanGesture(PanGestureInput::PANGESTURE_END, apzc, ScreenIntPoint(50, 80),
    327             ScreenPoint(0, 0), mcc->Time(), MODIFIER_NONE,
    328             /*aSimulateMomentum=*/true);
    329 
    330  // Check that we've done additional scrolling.
    331  float scrollYAfter = apzc->GetFrameMetrics().GetVisualScrollOffset().y;
    332  EXPECT_GT(scrollYAfter, scrollYBefore);
    333 }
    334 
    335 TEST_F(APZCPanningTesterMock, HoldGesture_ActiveWheelListener) {
    336  // Explicitly set the content response timeout.
    337  // The value should be greater than the sum of the AdvanceByMillis()
    338  // intervals from the MAYSTART event until the content response.
    339  SCOPED_GFX_PREF_INT("apz.content_response_timeout", 100);
    340 
    341  CreateSimpleScrollingLayer();
    342  ScopedLayerTreeRegistration registration(LayersId{0}, mcc);
    343  UpdateHitTestingTree();
    344 
    345  RefPtr<TestAsyncPanZoomController> apzc = ApzcOf(root);
    346  ScrollableLayerGuid::ViewID scrollId = ScrollableLayerGuid::START_SCROLL_ID;
    347  ScreenIntPoint panPoint(50, 80);
    348 
    349  // Simulate an active wheel listener by having the MockHitTester
    350  // return eApzAwareListeners as the hit-test result for every event.
    351  gfx::CompositorHitTestInfo dispatchToContent{
    352      CompositorHitTestFlags::eVisibleToHitTest,
    353      CompositorHitTestFlags::eApzAwareListeners};
    354 
    355  // Send a MAYSTART. Note that this has zero delta and does not
    356  // result in an event sent to web content (so it will not itself
    357  // result in a content response).
    358  QueueMockHitResult(scrollId, dispatchToContent);
    359  PanGesture(PanGestureInput::PANGESTURE_MAYSTART, manager, panPoint,
    360             ScreenPoint(0, 0), mcc->Time());
    361 
    362 #ifdef MOZ_WIDGET_GTK
    363  // On Linux, send a CANCELLED. This signifies the end of the hold gesture.
    364  // (On Mac the widget code goes directly to sending START.)
    365  mcc->AdvanceByMillis(5);
    366  QueueMockHitResult(scrollId, dispatchToContent);
    367  PanGesture(PanGestureInput::PANGESTURE_CANCELLED, manager, panPoint,
    368             ScreenPoint(0, 0), mcc->Time());
    369 #endif
    370 
    371  // Send a START. This does result in an event sent to web
    372  // content if there is a nonzero delta.
    373  mcc->AdvanceByMillis(5);
    374  QueueMockHitResult(scrollId, dispatchToContent);
    375  auto startResult = PanGesture(PanGestureInput::PANGESTURE_START, manager,
    376                                panPoint, ScreenPoint(0, 10), mcc->Time());
    377 
    378  // Send a couple of PAN events.
    379  mcc->AdvanceByMillis(5);
    380  QueueMockHitResult(scrollId, dispatchToContent);
    381  PanGesture(PanGestureInput::PANGESTURE_PAN, manager, panPoint,
    382             ScreenPoint(0, 10), mcc->Time());
    383  mcc->AdvanceByMillis(5);
    384  QueueMockHitResult(scrollId, dispatchToContent);
    385  PanGesture(PanGestureInput::PANGESTURE_PAN, manager, panPoint,
    386             ScreenPoint(0, 10), mcc->Time());
    387 
    388  // Simulate a content response which allows the scroll.
    389  manager->SetTargetAPZC(startResult.mInputBlockId, {startResult.mTargetGuid});
    390  manager->ContentReceivedInputBlock(startResult.mInputBlockId,
    391                                     /*aPreventDefault=*/false);
    392 
    393  // Check that we did scroll.
    394  // In the buggy scenario for which this test case is written,
    395  // the input block for the hold gesture was never confirmed,
    396  // stalling the input queue so that we don't scroll until that input
    397  // block is timed out.
    398  EXPECT_GT(apzc->GetFrameMetrics().GetVisualScrollOffset().y, 0);
    399 
    400  // Clean up by sending an END event.
    401  QueueMockHitResult(scrollId, dispatchToContent);
    402  PanGesture(PanGestureInput::PANGESTURE_END, manager, panPoint,
    403             ScreenPoint(0, 0), mcc->Time());
    404  apzc->AssertStateIsReset();
    405 }
    406 
    407 TEST_F(APZCPanningTesterMock, HoldGesture_PreventDefaultAfterLongHold) {
    408  // Explicitly set a content response timeout.
    409  SCOPED_GFX_PREF_INT("apz.content_response_timeout", 20);
    410 
    411  CreateSimpleScrollingLayer();
    412  ScopedLayerTreeRegistration registration(LayersId{0}, mcc);
    413  UpdateHitTestingTree();
    414 
    415  RefPtr<TestAsyncPanZoomController> apzc = ApzcOf(root);
    416  ScrollableLayerGuid::ViewID scrollId = ScrollableLayerGuid::START_SCROLL_ID;
    417  ScreenIntPoint panPoint(50, 80);
    418 
    419  // Simulate an active wheel listener by having the MockHitTester
    420  // return eApzAwareListeners as the hit-test result for every event.
    421  gfx::CompositorHitTestInfo dispatchToContent{
    422      CompositorHitTestFlags::eVisibleToHitTest,
    423      CompositorHitTestFlags::eApzAwareListeners};
    424 
    425  // Send a MAYSTART. Note that this has zero delta and does not
    426  // result in an event sent to web content (so it will not itself
    427  // result in a content response).
    428  QueueMockHitResult(scrollId, dispatchToContent);
    429  PanGesture(PanGestureInput::PANGESTURE_MAYSTART, manager, panPoint,
    430             ScreenPoint(0, 0), mcc->Time());
    431 
    432  // Allow enough time to pass for the content response timeout to be reached.
    433  mcc->AdvanceByMillis(30);
    434 
    435 #ifdef MOZ_WIDGET_GTK
    436  // On Linux, send a CANCELLED. This signifies the end of the hold gesture.
    437  // (On Mac the widget code goes directly to sending START.)
    438  QueueMockHitResult(scrollId, dispatchToContent);
    439  PanGesture(PanGestureInput::PANGESTURE_CANCELLED, manager, panPoint,
    440             ScreenPoint(0, 0), mcc->Time());
    441 #endif
    442 
    443  // Send a START. This does result in an event sent to web
    444  // content if there is a nonzero delta.
    445  mcc->AdvanceByMillis(5);
    446  QueueMockHitResult(scrollId, dispatchToContent);
    447  auto startResult = PanGesture(PanGestureInput::PANGESTURE_START, manager,
    448                                panPoint, ScreenPoint(0, 10), mcc->Time());
    449 
    450  // Send a couple of PAN events.
    451  mcc->AdvanceByMillis(5);
    452  QueueMockHitResult(scrollId, dispatchToContent);
    453  PanGesture(PanGestureInput::PANGESTURE_PAN, manager, panPoint,
    454             ScreenPoint(0, 10), mcc->Time());
    455  mcc->AdvanceByMillis(5);
    456  QueueMockHitResult(scrollId, dispatchToContent);
    457  PanGesture(PanGestureInput::PANGESTURE_PAN, manager, panPoint,
    458             ScreenPoint(0, 10), mcc->Time());
    459 
    460  // Simulate a content response which does NOT allow the scroll.
    461  manager->SetTargetAPZC(startResult.mInputBlockId, {startResult.mTargetGuid});
    462  manager->ContentReceivedInputBlock(startResult.mInputBlockId,
    463                                     /*aPreventDefault=*/true);
    464 
    465  // Check that we did NOT scroll.
    466  // In the buggy scenario for which this test case is written,
    467  // the hold gesture and the scroll go into the same input block,
    468  // for which the content response times out during the hold gesture,
    469  // and we don't wait for the content response for the scroll.
    470  EXPECT_EQ(apzc->GetFrameMetrics().GetVisualScrollOffset().y, 0);
    471 
    472  // Clean up by sending an END event.
    473  QueueMockHitResult(scrollId, dispatchToContent);
    474  PanGesture(PanGestureInput::PANGESTURE_END, manager, panPoint,
    475             ScreenPoint(0, 0), mcc->Time());
    476  apzc->AssertStateIsReset();
    477 }
    478 
    479 TEST_F(APZCPanningTesterMock, HoldGesture_SubframeTargeting) {
    480  // Set up a layer tree with a scrollable subframe handing off to a root frame.
    481  const char* treeShape = "x(x)";
    482  LayerIntRect layerVisibleRect[] = {
    483      LayerIntRect(0, 0, 100, 100),
    484      LayerIntRect(0, 0, 100, 100),
    485  };
    486  CreateScrollData(treeShape, layerVisibleRect);
    487  SetScrollableFrameMetrics(root, ScrollableLayerGuid::START_SCROLL_ID,
    488                            CSSRect(0, 0, 100, 100));
    489  SetScrollableFrameMetrics(layers[1], ScrollableLayerGuid::START_SCROLL_ID + 1,
    490                            CSSRect(0, 0, 100, 200));
    491  SetScrollHandoff(layers[1], root);
    492  ScopedLayerTreeRegistration registration(LayersId{0}, mcc);
    493  UpdateHitTestingTree();
    494 
    495  auto* rootApzc = ApzcOf(root);
    496  auto* subframeApzc = ApzcOf(layers[1]);
    497  rootApzc->GetFrameMetrics().SetIsRootContent(true);
    498 
    499  // Mark the subframe as overscroll-behavior:none. This is important to
    500  // trigger the codepath in FindFirstScrollable() that exposes the bug.
    501  subframeApzc->GetScrollMetadata().SetOverscrollBehavior(
    502      OverscrollBehaviorInfo::FromStyleConstants(
    503          StyleOverscrollBehavior::None, StyleOverscrollBehavior::None));
    504 
    505  ScrollableLayerGuid::ViewID subframeScrollId =
    506      ScrollableLayerGuid::START_SCROLL_ID + 1;
    507  ScreenIntPoint panPoint(50, 50);
    508 
    509  // Send a MAYSTART. Note that this has zero delta, and causes its input
    510  // block to be marked as having empty mAllowedScrollDirections because the
    511  // subframe fails the "can this APZC be scrolled by this event" check
    512  // and is overscroll-behavior:none.
    513  QueueMockHitResult(subframeScrollId,
    514                     CompositorHitTestFlags::eVisibleToHitTest);
    515  PanGesture(PanGestureInput::PANGESTURE_MAYSTART, manager, panPoint,
    516             ScreenPoint(0, 0), mcc->Time());
    517 
    518 #ifdef MOZ_WIDGET_GTK
    519  // On Linux, send a CANCELLED. This signifies the end of the hold gesture.
    520  // (On Mac the widget code goes directly to sending START.)
    521  mcc->AdvanceByMillis(5);
    522  QueueMockHitResult(subframeScrollId,
    523                     CompositorHitTestFlags::eVisibleToHitTest);
    524  PanGesture(PanGestureInput::PANGESTURE_CANCELLED, manager, panPoint,
    525             ScreenPoint(0, 0), mcc->Time());
    526 #endif
    527 
    528  // Send a START. In the buggy scenario, this gets added to the same input
    529  // block as the MAYSTART, which has been marked as having empty
    530  // mAllowedScrollDirections, and thus fails to scroll anything.
    531  mcc->AdvanceByMillis(5);
    532  QueueMockHitResult(subframeScrollId,
    533                     CompositorHitTestFlags::eVisibleToHitTest);
    534  PanGesture(PanGestureInput::PANGESTURE_START, manager, panPoint,
    535             ScreenPoint(0, 10), mcc->Time());
    536 
    537  // Check that the subframe scrolled.
    538  EXPECT_GT(subframeApzc->GetFrameMetrics().GetVisualScrollOffset().y, 0);
    539 
    540  // Clean up by sending an END event.
    541  QueueMockHitResult(subframeScrollId,
    542                     CompositorHitTestFlags::eVisibleToHitTest);
    543  PanGesture(PanGestureInput::PANGESTURE_END, manager, panPoint,
    544             ScreenPoint(0, 0), mcc->Time());
    545 }
    546 
    547 TEST_F(APZCPanningTester, HoldGesture_DuringAutoscrollAnimation) {
    548  // Tell APZ about the current mouse position. This is needed for
    549  // autoscroll to work correctly.
    550  tm->SetCurrentMousePosition(ScreenPoint(5, 5));
    551 
    552  // Start an autoscroll animation.
    553  apzc->StartAutoscroll(ScreenPoint(5, 5));
    554  apzc->AssertStateIsAutoscroll();
    555 
    556  // Send a PANGESTURE_MAYSTART event. With a touchpad, this can happen
    557  // when you start moving the cursor after a three-finger gesture to
    558  // start autoscroll.
    559  PanGesture(PanGestureInput::PANGESTURE_MAYSTART, apzc, ScreenIntPoint(50, 80),
    560             ScreenPoint(0, 0), mcc->Time());
    561 
    562  // Check that this did NOT cancel the autoscroll animation.
    563  apzc->AssertStateIsAutoscroll();
    564 }