Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/gfx/layers/apz/test/gtest/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 44 kB image not shown  

Quelle  TestGestureDetector.cpp   Sprache: C

 
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#include "gtest/gtest.h"
#include "gmock/gmock.h"

#include "APZCBasicTester.h"
#include "APZTestCommon.h"
#include "InputUtils.h"
#include "apz/src/InputBlockState.h"
#include "mozilla/StaticPrefs_apz.h"

// Note: There are additional tests that test gesture detection behaviour
//       with multiple APZCs in TestTreeManager.cpp.

class APZCGestureDetectorTester : public APZCBasicTester {
 public:
  APZCGestureDetectorTester()
      : APZCBasicTester(AsyncPanZoomController::USE_GESTURE_DETECTOR) {}

 protected:
  FrameMetrics GetPinchableFrameMetrics(float aZoom = 2.0f) {
    FrameMetrics fm;
    fm.SetCompositionBounds(ParentLayerRect(200, 200, 100, 200));
    fm.SetScrollableRect(CSSRect(0, 0, 980, 1000));
    fm.SetVisualScrollOffset(CSSPoint(300, 300));
    fm.SetZoom(CSSToParentLayerScale(aZoom));
    // APZC only allows zooming on the root scrollable frame.
    fm.SetIsRootContent(true);
    // the visible area of the document in CSS pixels is x=300 y=300 w=50 h=100
    return fm;
  }
};

#ifndef MOZ_WIDGET_ANDROID  // Currently fails on Android
TEST_F(APZCGestureDetectorTester, Pan_After_Pinch) {
  SCOPED_GFX_PREF_INT("apz.axis_lock.mode", 2);
  SCOPED_GFX_PREF_FLOAT("apz.axis_lock.lock_angle", M_PI / 6.0f);
  SCOPED_GFX_PREF_FLOAT("apz.axis_lock.breakout_angle", M_PI / 8.0f);

  FrameMetrics originalMetrics = GetPinchableFrameMetrics();
  apzc->SetFrameMetrics(originalMetrics);

  MakeApzcZoomable();

  // Test parameters
  float zoomAmount = 1.25;
  float pinchLength = 100.0;
  float pinchLengthScaled = pinchLength * zoomAmount;
  int focusX = 250;
  int focusY = 300;
  int panDistance = 20;
  const TimeDuration TIME_BETWEEN_TOUCH_EVENT =
      TimeDuration::FromMilliseconds(50);

  int firstFingerId = 0;
  int secondFingerId = firstFingerId + 1;

  // Put fingers down
  MultiTouchInput mti =
      MultiTouchInput(MultiTouchInput::MULTITOUCH_START, 0, mcc->Time(), 0);
  mti.mTouches.AppendElement(
      CreateSingleTouchData(firstFingerId, focusX, focusY));
  mti.mTouches.AppendElement(
      CreateSingleTouchData(secondFingerId, focusX, focusY));
  apzc->ReceiveInputEvent(mti, Some(nsTArray<uint32_t>{kDefaultTouchBehavior}));
  mcc->AdvanceBy(TIME_BETWEEN_TOUCH_EVENT);

  // Spread fingers out to enter the pinch state
  mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, 0, mcc->Time(), 0);
  mti.mTouches.AppendElement(CreateSingleTouchData(
      firstFingerId, static_cast<int32_t>(focusX - pinchLength), focusY));
  mti.mTouches.AppendElement(CreateSingleTouchData(
      secondFingerId, static_cast<int32_t>(focusX + pinchLength), focusY));
  apzc->ReceiveInputEvent(mti);
  mcc->AdvanceBy(TIME_BETWEEN_TOUCH_EVENT);

  // Do the actual pinch of 1.25x
  mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, 0, mcc->Time(), 0);
  mti.mTouches.AppendElement(CreateSingleTouchData(
      firstFingerId, static_cast<int32_t>(focusX - pinchLengthScaled), focusY));
  mti.mTouches.AppendElement(CreateSingleTouchData(
      secondFingerId, static_cast<int32_t>(focusX + pinchLengthScaled),
      focusY));
  apzc->ReceiveInputEvent(mti);
  mcc->AdvanceBy(TIME_BETWEEN_TOUCH_EVENT);

  // Verify that the zoom changed, just to make sure our code above did what it
  // was supposed to.
  FrameMetrics zoomedMetrics = apzc->GetFrameMetrics();
  float newZoom = zoomedMetrics.GetZoom().scale;
  EXPECT_EQ(originalMetrics.GetZoom().scale * zoomAmount, newZoom);

  // Now we lift one finger...
  mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_END, 0, mcc->Time(), 0);
  mti.mTouches.AppendElement(CreateSingleTouchData(
      secondFingerId, static_cast<int32_t>(focusX + pinchLengthScaled),
      focusY));
  apzc->ReceiveInputEvent(mti);
  mcc->AdvanceBy(TIME_BETWEEN_TOUCH_EVENT);

  // ... and pan with the remaining finger. This pan just breaks through the
  // distance threshold.
  focusY += StaticPrefs::apz_touch_start_tolerance() * tm->GetDPI();
  mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, 0, mcc->Time(), 0);
  mti.mTouches.AppendElement(CreateSingleTouchData(
      firstFingerId, static_cast<int32_t>(focusX - pinchLengthScaled), focusY));
  apzc->ReceiveInputEvent(mti);
  mcc->AdvanceBy(TIME_BETWEEN_TOUCH_EVENT);

  // This one does an actual pan of 20 pixels
  focusY += panDistance;
  mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, 0, mcc->Time(), 0);
  mti.mTouches.AppendElement(CreateSingleTouchData(
      firstFingerId, static_cast<int32_t>(focusX - pinchLengthScaled), focusY));
  apzc->ReceiveInputEvent(mti);
  mcc->AdvanceBy(TIME_BETWEEN_TOUCH_EVENT);

  // Lift the remaining finger
  mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_END, 0, mcc->Time(), 0);
  mti.mTouches.AppendElement(CreateSingleTouchData(
      firstFingerId, static_cast<int32_t>(focusX - pinchLengthScaled), focusY));
  apzc->ReceiveInputEvent(mti);
  mcc->AdvanceBy(TIME_BETWEEN_TOUCH_EVENT);

  // Verify that we scrolled
  FrameMetrics finalMetrics = apzc->GetFrameMetrics();
  EXPECT_EQ(zoomedMetrics.GetVisualScrollOffset().y - (panDistance / newZoom),
            finalMetrics.GetVisualScrollOffset().y);

  // Clear out any remaining fling animation and pending tasks
  apzc->AdvanceAnimationsUntilEnd();
  while (mcc->RunThroughDelayedTasks());
  apzc->AssertStateIsReset();
}
#endif

TEST_F(APZCGestureDetectorTester, Pan_With_Tap) {
  SCOPED_GFX_PREF_FLOAT("apz.touch_start_tolerance", 0.1);

  FrameMetrics originalMetrics = GetPinchableFrameMetrics();
  apzc->SetFrameMetrics(originalMetrics);

  // Making the APZC zoomable isn't really needed for the correct operation of
  // this test, but it could help catch regressions where we accidentally enter
  // a pinch state.
  MakeApzcZoomable();

  // Test parameters
  int touchX = 250;
  int touchY = 300;
  int panDistance = 20;

  int firstFingerId = 0;
  int secondFingerId = firstFingerId + 1;

  const float panThreshold =
      StaticPrefs::apz_touch_start_tolerance() * tm->GetDPI();

  // Put finger down
  MultiTouchInput mti =
      CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_START, mcc->Time());
  mti.mTouches.AppendElement(
      CreateSingleTouchData(firstFingerId, touchX, touchY));
  apzc->ReceiveInputEvent(mti, Some(nsTArray<uint32_t>{kDefaultTouchBehavior}));

  // Start a pan, break through the threshold
  touchY += panThreshold;
  mti = CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, mcc->Time());
  mti.mTouches.AppendElement(
      CreateSingleTouchData(firstFingerId, touchX, touchY));
  apzc->ReceiveInputEvent(mti);

  // Do an actual pan for a bit
  touchY += panDistance;
  mti = CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, mcc->Time());
  mti.mTouches.AppendElement(
      CreateSingleTouchData(firstFingerId, touchX, touchY));
  apzc->ReceiveInputEvent(mti);

  // Put a second finger down
  mti = CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_START, mcc->Time());
  mti.mTouches.AppendElement(
      CreateSingleTouchData(firstFingerId, touchX, touchY));
  mti.mTouches.AppendElement(
      CreateSingleTouchData(secondFingerId, touchX + 10, touchY));
  apzc->ReceiveInputEvent(mti, Some(nsTArray<uint32_t>{kDefaultTouchBehavior}));

  // Lift the second finger
  mti = CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_END, mcc->Time());
  mti.mTouches.AppendElement(
      CreateSingleTouchData(secondFingerId, touchX + 10, touchY));
  apzc->ReceiveInputEvent(mti);

  // Bust through the threshold again
  touchY += panThreshold;
  mti = CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, mcc->Time());
  mti.mTouches.AppendElement(
      CreateSingleTouchData(firstFingerId, touchX, touchY));
  apzc->ReceiveInputEvent(mti);

  // Do some more actual panning
  touchY += panDistance;
  mti = CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, mcc->Time());
  mti.mTouches.AppendElement(
      CreateSingleTouchData(firstFingerId, touchX, touchY));
  apzc->ReceiveInputEvent(mti);

  // Lift the first finger
  mti = CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_END, mcc->Time());
  mti.mTouches.AppendElement(
      CreateSingleTouchData(firstFingerId, touchX, touchY));
  apzc->ReceiveInputEvent(mti);

  // Verify that we scrolled
  FrameMetrics finalMetrics = apzc->GetFrameMetrics();
  float zoom = finalMetrics.GetZoom().scale;
  EXPECT_EQ(
      originalMetrics.GetVisualScrollOffset().y - (panDistance * 2 / zoom),
      finalMetrics.GetVisualScrollOffset().y);

  // Clear out any remaining fling animation and pending tasks
  apzc->AdvanceAnimationsUntilEnd();
  while (mcc->RunThroughDelayedTasks());
  apzc->AssertStateIsReset();
}

TEST_F(APZCGestureDetectorTester, SecondTapIsFar_Bug1586496) {
  // Test that we receive two single-tap events when two tap gestures are
  // close in time but far in distance.
  EXPECT_CALL(*mcc, HandleTap(TapType::eSingleTap, _, 0, apzc->GetGuid(), _, _))
      .Times(2);

  TimeDuration brief =
      TimeDuration::FromMilliseconds(StaticPrefs::apz_max_tap_time() / 10.0);

  ScreenIntPoint point(10, 10);
  Tap(apzc, point, brief);

  mcc->AdvanceBy(brief);

  point.x += static_cast<int32_t>(apzc->GetSecondTapTolerance() * 2);
  point.y += static_cast<int32_t>(apzc->GetSecondTapTolerance() * 2);

  Tap(apzc, point, brief);
}

class APZCFlingStopTester : public APZCGestureDetectorTester {
 protected:
  // Start a fling, and then tap while the fling is ongoing. When
  // aSlow is false, the tap will happen while the fling is at a
  // high velocity, and we check that the tap doesn't trigger sending a tap
  // to content. If aSlow is true, the tap will happen while the fling
  // is at a slow velocity, and we check that the tap does trigger sending
  // a tap to content. See bug 1022956.
  void DoFlingStopTest(bool aSlow) {
    int touchStart = 50;
    int touchEnd = 10;

    // Start the fling down.
    Pan(apzc, touchStart, touchEnd);
    // The touchstart from the pan will leave some cancelled tasks in the queue,
    // clear them out

    // If we want to tap while the fling is fast, let the fling advance for 10ms
    // only. If we want the fling to slow down more, advance to 2000ms. These
    // numbers may need adjusting if our friction and threshold values change,
    // but they should be deterministic at least.
    int timeDelta = aSlow ? 2000 : 10;
    int tapCallsExpected = aSlow ? 2 : 1;

    // Advance the fling animation by timeDelta milliseconds.
    ParentLayerPoint pointOut;
    AsyncTransform viewTransformOut;
    apzc->SampleContentTransformForFrame(
        &viewTransformOut, pointOut, TimeDuration::FromMilliseconds(timeDelta));

    // Deliver a tap to abort the fling. Ensure that we get a SingleTap
    // call out of it if and only if the fling is slow.
    EXPECT_CALL(*mcc,
                HandleTap(TapType::eSingleTap, _, 0, apzc->GetGuid(), _, _))
        .Times(tapCallsExpected);
    Tap(apzc, ScreenIntPoint(10, 10), 0);
    while (mcc->RunThroughDelayedTasks());

    // Deliver another tap, to make sure that taps are flowing properly once
    // the fling is aborted.
    Tap(apzc, ScreenIntPoint(100, 100), 0);
    while (mcc->RunThroughDelayedTasks());

    // Verify that we didn't advance any further after the fling was aborted, in
    // either case.
    ParentLayerPoint finalPointOut;
    apzc->SampleContentTransformForFrame(&viewTransformOut, finalPointOut);
    EXPECT_EQ(pointOut.x, finalPointOut.x);
    EXPECT_EQ(pointOut.y, finalPointOut.y);

    apzc->AssertStateIsReset();
  }

  void DoFlingStopWithSlowListener(bool aPreventDefault) {
    MakeApzcWaitForMainThread();

    int touchStart = 50;
    int touchEnd = 10;
    uint64_t blockId = 0;

    // Start the fling down.
    Pan(apzc, touchStart, touchEnd, PanOptions::None, nullptr, nullptr,
        &blockId);
    apzc->ConfirmTarget(blockId);
    apzc->ContentReceivedInputBlock(blockId, false);

    // Sample the fling a couple of times to ensure it's going.
    ParentLayerPoint point, finalPoint;
    AsyncTransform viewTransform;
    apzc->SampleContentTransformForFrame(&viewTransform, point,
                                         TimeDuration::FromMilliseconds(10));
    apzc->SampleContentTransformForFrame(&viewTransform, finalPoint,
                                         TimeDuration::FromMilliseconds(10));
    EXPECT_GT(finalPoint.y, point.y);

    // Now we put our finger down to stop the fling
    blockId =
        TouchDown(apzc, ScreenIntPoint(10, 10), mcc->Time()).mInputBlockId;

    // Re-sample to make sure it hasn't moved
    apzc->SampleContentTransformForFrame(&viewTransform, point,
                                         TimeDuration::FromMilliseconds(10));
    EXPECT_EQ(finalPoint.x, point.x);
    EXPECT_EQ(finalPoint.y, point.y);

    // respond to the touchdown that stopped the fling.
    // even if we do a prevent-default on it, the animation should remain
    // stopped.
    apzc->ContentReceivedInputBlock(blockId, aPreventDefault);

    // Verify the page hasn't moved
    apzc->SampleContentTransformForFrame(&viewTransform, point,
                                         TimeDuration::FromMilliseconds(70));
    EXPECT_EQ(finalPoint.x, point.x);
    EXPECT_EQ(finalPoint.y, point.y);

    // clean up
    TouchUp(apzc, ScreenIntPoint(10, 10), mcc->Time());

    apzc->AssertStateIsReset();
  }
};

TEST_F(APZCFlingStopTester, FlingStop) {
  SCOPED_GFX_PREF_FLOAT("apz.fling_min_velocity_threshold", 0.0f);
  DoFlingStopTest(false);
}

TEST_F(APZCFlingStopTester, FlingStopTap) {
  SCOPED_GFX_PREF_FLOAT("apz.fling_min_velocity_threshold", 0.0f);
  DoFlingStopTest(true);
}

TEST_F(APZCFlingStopTester, FlingStopSlowListener) {
  SCOPED_GFX_PREF_FLOAT("apz.fling_min_velocity_threshold", 0.0f);
  DoFlingStopWithSlowListener(false);
}

TEST_F(APZCFlingStopTester, FlingStopPreventDefault) {
  SCOPED_GFX_PREF_FLOAT("apz.fling_min_velocity_threshold", 0.0f);
  DoFlingStopWithSlowListener(true);
}

TEST_F(APZCGestureDetectorTester, ShortPress) {
  MakeApzcUnzoomable();

  MockFunction<void(std::string checkPointName)> check;
  {
    InSequence s;
    // This verifies that the single tap notification is sent after the
    // touchup is fully processed. The ordering here is important.
    EXPECT_CALL(check, Call("pre-tap"));
    EXPECT_CALL(check, Call("post-tap"));
    EXPECT_CALL(*mcc, HandleTap(TapType::eSingleTap, LayoutDevicePoint(10, 10),
                                0, apzc->GetGuid(), _, _))
        .Times(1);
  }

  check.Call("pre-tap");
  TapAndCheckStatus(apzc, ScreenIntPoint(10, 10),
                    TimeDuration::FromMilliseconds(100));
  check.Call("post-tap");

  apzc->AssertStateIsReset();
}

TEST_F(APZCGestureDetectorTester, MediumPress) {
  MakeApzcUnzoomable();

  MockFunction<void(std::string checkPointName)> check;
  {
    InSequence s;
    // This verifies that the single tap notification is sent after the
    // touchup is fully processed. The ordering here is important.
    EXPECT_CALL(check, Call("pre-tap"));
    EXPECT_CALL(check, Call("post-tap"));
    EXPECT_CALL(*mcc, HandleTap(TapType::eSingleTap, LayoutDevicePoint(10, 10),
                                0, apzc->GetGuid(), _, _))
        .Times(1);
  }

  check.Call("pre-tap");
  TapAndCheckStatus(apzc, ScreenIntPoint(10, 10),
                    TimeDuration::FromMilliseconds(400));
  check.Call("post-tap");

  apzc->AssertStateIsReset();
}

class APZCLongPressTester : public APZCGestureDetectorTester {
 protected:
  void DoLongPressTest(uint32_t aBehavior) {
    MakeApzcUnzoomable();

    APZEventResult result =
        TouchDown(apzc, ScreenIntPoint(10, 10), mcc->Time());
    EXPECT_EQ(nsEventStatus_eConsumeDoDefault, result.GetStatus());
    uint64_t blockId = result.mInputBlockId;

    if (result.GetStatus() != nsEventStatus_eConsumeNoDefault) {
      // SetAllowedTouchBehavior() must be called after sending touch-start.
      nsTArray<uint32_t> allowedTouchBehaviors;
      allowedTouchBehaviors.AppendElement(aBehavior);
      apzc->SetAllowedTouchBehavior(blockId, allowedTouchBehaviors);
    }
    // Have content "respond" to the touchstart
    apzc->ContentReceivedInputBlock(blockId, false);

    MockFunction<void(std::string checkPointName)> check;

    {
      InSequence s;

      EXPECT_CALL(check, Call("preHandleLongTap"));
      blockId++;
      EXPECT_CALL(*mcc, HandleTap(TapType::eLongTap, LayoutDevicePoint(10, 10),
                                  0, apzc->GetGuid(), blockId, _))
          .Times(1);
      EXPECT_CALL(check, Call("postHandleLongTap"));

      EXPECT_CALL(check, Call("preHandleLongTapUp"));
      EXPECT_CALL(*mcc,
                  HandleTap(TapType::eLongTapUp, LayoutDevicePoint(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
    // needs a new content response and also has a pending timeout task
    // 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("preHandleLongTapUp");
    result = TouchUp(apzc, ScreenIntPoint(10, 10), mcc->Time());
    mcc->RunThroughDelayedTasks();
    EXPECT_EQ(nsEventStatus_eConsumeDoDefault, result.GetStatus());
    check.Call("postHandleLongTapUp");

    apzc->AssertStateIsReset();
  }

  void DoLongPressPreventDefaultTest(uint32_t aBehavior) {
    MakeApzcUnzoomable();

    EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(0);

    int touchX = 10, touchStartY = 50, touchEndY = 10;

    APZEventResult result =
        TouchDown(apzc, ScreenIntPoint(touchX, touchStartY), mcc->Time());
    EXPECT_EQ(nsEventStatus_eConsumeDoDefault, result.GetStatus());
    uint64_t blockId = result.mInputBlockId;

    if (result.GetStatus() != nsEventStatus_eConsumeNoDefault) {
      // SetAllowedTouchBehavior() must be called after sending touch-start.
      nsTArray<uint32_t> allowedTouchBehaviors;
      allowedTouchBehaviors.AppendElement(aBehavior);
      apzc->SetAllowedTouchBehavior(blockId, allowedTouchBehaviors);
    }
    // Have content "respond" to the touchstart
    apzc->ContentReceivedInputBlock(blockId, false);

    MockFunction<void(std::string checkPointName)> check;

    {
      InSequence s;

      EXPECT_CALL(check, Call("preHandleLongTap"));
      blockId++;
      EXPECT_CALL(*mcc, HandleTap(TapType::eLongTap,
                                  LayoutDevicePoint(touchX, touchStartY), 0,
                                  apzc->GetGuid(), blockId, _))
          .Times(1);
      EXPECT_CALL(check, Call("postHandleLongTap"));
    }

    // Manually invoke the longpress while the touch is currently down.
    check.Call("preHandleLongTap");
    mcc->RunThroughDelayedTasks();
    check.Call("postHandleLongTap");

    // There should be a TimeoutContentResponse task in the queue still,
    // waiting for the response from the longtap event dispatched above.
    // Send the signal that content has handled the long-tap, and then run
    // the timeout task (it will be a no-op because the content "wins" the
    // race. This takes the place of the "contextmenu" event.
    apzc->ContentReceivedInputBlock(blockId, true);
    mcc->AdvanceByMillis(1000);

    MultiTouchInput mti =
        CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, mcc->Time());
    mti.mTouches.AppendElement(CreateSingleTouchData(0, touchX, touchEndY));
    result = apzc->ReceiveInputEvent(mti);
    EXPECT_EQ(nsEventStatus_eConsumeDoDefault, result.GetStatus());

    EXPECT_CALL(*mcc, HandleTap(TapType::eSingleTap,
                                LayoutDevicePoint(touchX, touchEndY), 0,
                                apzc->GetGuid(), _, _))
        .Times(0);
    result = TouchUp(apzc, ScreenIntPoint(touchX, touchEndY), mcc->Time());
    EXPECT_EQ(nsEventStatus_eConsumeDoDefault, result.GetStatus());

    ParentLayerPoint pointOut;
    AsyncTransform viewTransformOut;
    apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut);

    EXPECT_EQ(ParentLayerPoint(), pointOut);
    EXPECT_EQ(AsyncTransform(), viewTransformOut);

    apzc->AssertStateIsReset();
  }

  // Tests a scenario that after a long-press event happened the original touch
  // block initiated by a touch-start event and the touch block initiated by a
  // long-tap event have been discarded when a new touch-start event happens.
  void DoLongPressDiscardTouchBlockTest(bool aWithTouchMove) {
    // Set apz.content_response_timeout > ui.click_hold_context_menus.delay and
    // apz.touch_start_tolerance explicitly to match Android preferences.
    SCOPED_GFX_PREF_INT("apz.content_response_timeout", 60);
    SCOPED_GFX_PREF_INT("ui.click_hold_context_menus.delay", 30);
    SCOPED_GFX_PREF_FLOAT("apz.touch_start_tolerance", 0.06);

    MockFunction<void(std::string checkPointName)> check;
    {
      InSequence s;
      EXPECT_CALL(check, Call("pre long-tap dispatch"));
      EXPECT_CALL(*mcc, HandleTap(TapType::eLongTap, LayoutDevicePoint(10, 10),
                                  0, apzc->GetGuid(), _, _))
          .Times(1);
      EXPECT_CALL(check, Call("post long-tap dispatch"));

      // If a touch-move happens while long-tap is happening, there's no
      // eLongTapUp event.
      if (!aWithTouchMove) {
        EXPECT_CALL(*mcc,
                    HandleTap(TapType::eLongTapUp, LayoutDevicePoint(10, 20), 0,
                              apzc->GetGuid(), _, _))
            .Times(1);
      }
      EXPECT_CALL(*mcc, HandleTap(TapType::eLongTap, LayoutDevicePoint(10, 10),
                                  0, apzc->GetGuid(), _, _))
          .Times(1);
    }

    // Keep touching for a while to trigger a long tap event.
    uint64_t firstTouchBlockId =
        TouchDown(apzc, ScreenIntPoint(10, 10), mcc->Time()).mInputBlockId;
    TouchBlockState* firstTouchBlock =
        tm->GetInputQueue()->GetCurrentTouchBlock();
    EXPECT_NE(firstTouchBlock, nullptr);
    EXPECT_EQ(tm->GetInputQueue()->GetBlockForId(firstTouchBlockId),
              firstTouchBlock);

    // Wait for a long tap.
    check.Call("pre long-tap dispatch");
    mcc->AdvanceByMillis(30);
    check.Call("post long-tap dispatch");

    // Now the current touch block is not the first touch block, it should be
    // a new touch block for the long tap event.
    TouchBlockState* secondTouchBlock =
        tm->GetInputQueue()->GetCurrentTouchBlock();
    EXPECT_NE(secondTouchBlock, firstTouchBlock);
    EXPECT_TRUE(secondTouchBlock->ForLongTap());
    uint64_t secondTouchBlockId = secondTouchBlock->GetBlockId();

    if (aWithTouchMove) {
      mcc->AdvanceByMillis(10);
      TouchMove(apzc, ScreenIntPoint(10, 20), mcc->Time());
    }

    // Finish the first touch block.
    mcc->AdvanceByMillis(10);
    TouchUp(apzc, ScreenIntPoint(10, 20), mcc->Time());

    // And start a new touch block.
    mcc->AdvanceByMillis(10);
    uint64_t newTouchBlockId =
        TouchDown(apzc, ScreenIntPoint(10, 10), mcc->Time()).mInputBlockId;

    mcc->AdvanceByMillis(10);
    // Now the original touch block and the touch block for long-tap should have
    // been discarded from the input queue.
    EXPECT_EQ(tm->GetInputQueue()->GetBlockForId(firstTouchBlockId), nullptr);
    EXPECT_EQ(tm->GetInputQueue()->GetBlockForId(secondTouchBlockId), nullptr);
    EXPECT_EQ(tm->GetInputQueue()->GetBlockForId(newTouchBlockId),
              tm->GetInputQueue()->GetCurrentBlock());
  }
};

TEST_F(APZCLongPressTester, LongPress) {
  DoLongPressTest(kDefaultTouchBehavior);
}

TEST_F(APZCLongPressTester, LongPressPreventDefault) {
  DoLongPressPreventDefaultTest(kDefaultTouchBehavior);
}

TEST_F(APZCLongPressTester, LongPressDiscardBlock) {
  DoLongPressDiscardTouchBlockTest(true /* with touch-move */);
}

// Similar to above LongPressDiscardBlock but APZ is waiting for responses from
// the content.
TEST_F(APZCLongPressTester, LongPressDiscardBlock2) {
  MakeApzcWaitForMainThread();
  DoLongPressDiscardTouchBlockTest(true /* with touch-move */);
}

// Similar to above LongPressDiscardBlock/LongPressDiscardBlock2 without
// touch-move events.
TEST_F(APZCLongPressTester, LongPressDiscardBlock3) {
  DoLongPressDiscardTouchBlockTest(false /* without touch-move */);
}

TEST_F(APZCLongPressTester, LongPressDiscardBlock4) {
  MakeApzcWaitForMainThread();
  DoLongPressDiscardTouchBlockTest(false /* without touch-move */);
}

TEST_F(APZCGestureDetectorTester, DoubleTap) {
  MakeApzcWaitForMainThread();
  MakeApzcZoomable();

  EXPECT_CALL(*mcc, HandleTap(TapType::eSingleTap, LayoutDevicePoint(10, 10), 0,
                              apzc->GetGuid(), _, _))
      .Times(0);
  EXPECT_CALL(*mcc, HandleTap(TapType::eDoubleTap, LayoutDevicePoint(10, 10), 0,
                              apzc->GetGuid(), _, _))
      .Times(1);

  uint64_t blockIds[2];
  DoubleTapAndCheckStatus(apzc, ScreenIntPoint(10, 10), &blockIds);

  // responses to the two touchstarts
  apzc->ContentReceivedInputBlock(blockIds[0], false);
  apzc->ContentReceivedInputBlock(blockIds[1], false);

  apzc->AssertStateIsReset();
}

TEST_F(APZCGestureDetectorTester, DoubleTapNotZoomable) {
  MakeApzcWaitForMainThread();
  MakeApzcUnzoomable();

  EXPECT_CALL(*mcc, HandleTap(TapType::eSingleTap, LayoutDevicePoint(10, 10), 0,
                              apzc->GetGuid(), _, _))
      .Times(1);
  EXPECT_CALL(*mcc, HandleTap(TapType::eSecondTap, LayoutDevicePoint(10, 10), 0,
                              apzc->GetGuid(), _, _))
      .Times(1);
  EXPECT_CALL(*mcc, HandleTap(TapType::eDoubleTap, LayoutDevicePoint(10, 10), 0,
                              apzc->GetGuid(), _, _))
      .Times(0);

  uint64_t blockIds[2];
  DoubleTapAndCheckStatus(apzc, ScreenIntPoint(10, 10), &blockIds);

  // responses to the two touchstarts
  apzc->ContentReceivedInputBlock(blockIds[0], false);
  apzc->ContentReceivedInputBlock(blockIds[1], false);

  apzc->AssertStateIsReset();
}

TEST_F(APZCGestureDetectorTester, DoubleTapPreventDefaultFirstOnly) {
  MakeApzcWaitForMainThread();
  MakeApzcZoomable();

  EXPECT_CALL(*mcc, HandleTap(TapType::eSingleTap, LayoutDevicePoint(10, 10), 0,
                              apzc->GetGuid(), _, _))
      .Times(1);
  EXPECT_CALL(*mcc, HandleTap(TapType::eDoubleTap, LayoutDevicePoint(10, 10), 0,
                              apzc->GetGuid(), _, _))
      .Times(0);

  uint64_t blockIds[2];
  DoubleTapAndCheckStatus(apzc, ScreenIntPoint(10, 10), &blockIds);

  // responses to the two touchstarts
  apzc->ContentReceivedInputBlock(blockIds[0], true);
  apzc->ContentReceivedInputBlock(blockIds[1], false);

  apzc->AssertStateIsReset();
}

TEST_F(APZCGestureDetectorTester, DoubleTapPreventDefaultBoth) {
  MakeApzcWaitForMainThread();
  MakeApzcZoomable();

  EXPECT_CALL(*mcc, HandleTap(TapType::eSingleTap, LayoutDevicePoint(10, 10), 0,
                              apzc->GetGuid(), _, _))
      .Times(0);
  EXPECT_CALL(*mcc, HandleTap(TapType::eDoubleTap, LayoutDevicePoint(10, 10), 0,
                              apzc->GetGuid(), _, _))
      .Times(0);

  uint64_t blockIds[2];
  DoubleTapAndCheckStatus(apzc, ScreenIntPoint(10, 10), &blockIds);

  // responses to the two touchstarts
  apzc->ContentReceivedInputBlock(blockIds[0], true);
  apzc->ContentReceivedInputBlock(blockIds[1], true);

  apzc->AssertStateIsReset();
}

// Test for bug 947892
// We test whether we dispatch tap event when the tap is followed by pinch.
// Additionally test that the pinch gesture successfully results in zooming.
TEST_F(APZCGestureDetectorTester, TapFollowedByPinch) {
  MakeApzcZoomable();

  EXPECT_CALL(*mcc, HandleTap(TapType::eSingleTap, LayoutDevicePoint(10, 10), 0,
                              apzc->GetGuid(), _, _))
      .Times(1);

  Tap(apzc, ScreenIntPoint(10, 10), TimeDuration::FromMilliseconds(100));

  PinchWithTouchInput(
      apzc, ScreenIntPoint(15, 15), 1.5,
      PinchOptions().TimeBetweenTouchEvents(
          // Time it so that the max tap timer expires while the fingers are
          // down for the pinch but haven't started to move yet.
          TimeDuration::FromMilliseconds(StaticPrefs::apz_max_tap_time() -
                                         90)));

  EXPECT_GT(apzc->GetFrameMetrics().GetZoom().scale, 1.0f);
  apzc->AssertStateIsReset();
}

TEST_F(APZCGestureDetectorTester, TapFollowedByMultipleTouches) {
  MakeApzcZoomable();

  EXPECT_CALL(*mcc, HandleTap(TapType::eSingleTap, LayoutDevicePoint(10, 10), 0,
                              apzc->GetGuid(), _, _))
      .Times(1);

  Tap(apzc, ScreenIntPoint(10, 10), TimeDuration::FromMilliseconds(100));

  int inputId = 0;
  MultiTouchInput mti;
  mti = CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_START, mcc->Time());
  mti.mTouches.AppendElement(SingleTouchData(inputId, ParentLayerPoint(20, 20),
                                             ScreenSize(0, 0), 0, 0));
  apzc->ReceiveInputEvent(mti, Some(nsTArray<uint32_t>{kDefaultTouchBehavior}));

  mti = CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_START, mcc->Time());
  mti.mTouches.AppendElement(SingleTouchData(inputId, ParentLayerPoint(20, 20),
                                             ScreenSize(0, 0), 0, 0));
  mti.mTouches.AppendElement(SingleTouchData(
      inputId + 1, ParentLayerPoint(10, 10), ScreenSize(0, 0), 0, 0));
  apzc->ReceiveInputEvent(mti, Some(nsTArray<uint32_t>{kDefaultTouchBehavior}));

  mti = CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_END, mcc->Time());
  mti.mTouches.AppendElement(SingleTouchData(inputId, ParentLayerPoint(20, 20),
                                             ScreenSize(0, 0), 0, 0));
  mti.mTouches.AppendElement(SingleTouchData(
      inputId + 1, ParentLayerPoint(10, 10), ScreenSize(0, 0), 0, 0));
  apzc->ReceiveInputEvent(mti);

  apzc->AssertStateIsReset();
}

TEST_F(APZCGestureDetectorTester, LongPressInterruptedByWheel) {
  // Since we try to allow concurrent input blocks of different types to
  // co-exist, the wheel block shouldn't interrupt the long-press detection.
  // But more importantly, this shouldn't crash, which is what it did at one
  // point in time.
  EXPECT_CALL(*mcc, HandleTap(TapType::eLongTap, _, _, _, _, _)).Times(1);

  APZEventResult result = TouchDown(apzc, ScreenIntPoint(10, 10), mcc->Time());
  uint64_t touchBlockId = result.mInputBlockId;
  if (result.GetStatus() != nsEventStatus_eConsumeNoDefault) {
    SetDefaultAllowedTouchBehavior(apzc, touchBlockId);
  }
  mcc->AdvanceByMillis(10);
  uint64_t wheelBlockId =
      Wheel(apzc, ScreenIntPoint(10, 10), ScreenPoint(0, -10), mcc->Time())
          .mInputBlockId;
  EXPECT_NE(touchBlockId, wheelBlockId);
  mcc->AdvanceByMillis(1000);
}

TEST_F(APZCGestureDetectorTester, TapTimeoutInterruptedByWheel) {
  // In this test, even though the wheel block comes right after the tap, the
  // tap should still be dispatched because it completes fully before the wheel
  // block arrived.
  EXPECT_CALL(*mcc, HandleTap(TapType::eSingleTap, LayoutDevicePoint(10, 10), 0,
                              apzc->GetGuid(), _, _))
      .Times(1);

  // We make the APZC zoomable so the gesture detector needs to wait to
  // distinguish between tap and double-tap. During that timeout is when we
  // insert the wheel event.
  MakeApzcZoomable();

  APZEventResult result = Tap(apzc, ScreenIntPoint(10, 10),
                              TimeDuration::FromMilliseconds(100), nullptr);
  mcc->AdvanceByMillis(10);
  uint64_t wheelBlockId =
      Wheel(apzc, ScreenIntPoint(10, 10), ScreenPoint(0, -10), mcc->Time())
          .mInputBlockId;
  EXPECT_NE(result.mInputBlockId, wheelBlockId);
  while (mcc->RunThroughDelayedTasks());
}

TEST_F(APZCGestureDetectorTester, LongPressWithInputQueueDelay) {
  // In this test, we ensure that any time spent waiting in the input queue for
  // the content response is subtracted from the long-press timeout in the
  // GestureEventListener. In this test the content response timeout is longer
  // than the long-press timeout.
  SCOPED_GFX_PREF_INT("apz.content_response_timeout", 60);
  SCOPED_GFX_PREF_INT("ui.click_hold_context_menus.delay", 30);

  MakeApzcWaitForMainThread();

  MockFunction<void(std::string checkPointName)> check;

  {
    InSequence s;
    EXPECT_CALL(check, Call("pre long-tap dispatch"));
    EXPECT_CALL(*mcc, HandleTap(TapType::eLongTap, LayoutDevicePoint(10, 10), 0,
                                apzc->GetGuid(), _, _))
        .Times(1);
    EXPECT_CALL(check, Call("post long-tap dispatch"));
  }

  // Touch down
  APZEventResult result = TouchDown(apzc, ScreenIntPoint(10, 10), mcc->Time());
  uint64_t touchBlockId = result.mInputBlockId;
  // Simulate content response after 10ms
  mcc->AdvanceByMillis(10);
  apzc->ContentReceivedInputBlock(touchBlockId, false);
  apzc->SetAllowedTouchBehavior(touchBlockId, {kDefaultTouchBehavior});
  apzc->ConfirmTarget(touchBlockId);
  // Ensure long-tap event happens within 20ms after that
  check.Call("pre long-tap dispatch");
  mcc->AdvanceByMillis(20);
  check.Call("post long-tap dispatch");
}

TEST_F(APZCGestureDetectorTester, LongPressWithInputQueueDelay2) {
  // Similar to the previous test, except this time we don't simulate the
  // content response at all, and still expect the long-press to happen on
  // schedule.
  SCOPED_GFX_PREF_INT("apz.content_response_timeout", 60);
  SCOPED_GFX_PREF_INT("ui.click_hold_context_menus.delay", 30);

  MakeApzcWaitForMainThread();

  MockFunction<void(std::string checkPointName)> check;

  {
    InSequence s;
    EXPECT_CALL(check, Call("pre long-tap dispatch"));
    EXPECT_CALL(*mcc, HandleTap(TapType::eLongTap, LayoutDevicePoint(10, 10), 0,
                                apzc->GetGuid(), _, _))
        .Times(1);
    EXPECT_CALL(check, Call("post long-tap dispatch"));
  }

  // Touch down
  TouchDown(apzc, ScreenIntPoint(10, 10), mcc->Time());
  // Ensure the long-tap happens within 30ms even though there's no content
  // response.
  check.Call("pre long-tap dispatch");
  mcc->AdvanceByMillis(30);
  check.Call("post long-tap dispatch");
}

TEST_F(APZCGestureDetectorTester, LongPressWithInputQueueDelay3) {
  // Similar to the previous test, except now we have the long-press delay
  // being longer than the content response timeout.
  SCOPED_GFX_PREF_INT("apz.content_response_timeout", 30);
  SCOPED_GFX_PREF_INT("ui.click_hold_context_menus.delay", 60);

  MakeApzcWaitForMainThread();

  MockFunction<void(std::string checkPointName)> check;

  {
    InSequence s;
    EXPECT_CALL(check, Call("pre long-tap dispatch"));
    EXPECT_CALL(*mcc, HandleTap(TapType::eLongTap, LayoutDevicePoint(10, 10), 0,
                                apzc->GetGuid(), _, _))
        .Times(1);
    EXPECT_CALL(check, Call("post long-tap dispatch"));
  }

  // Touch down
  TouchDown(apzc, ScreenIntPoint(10, 10), mcc->Time());
  // Ensure the long-tap happens at the 60ms mark even though the input event
  // waits in the input queue for the full content response timeout of 30ms
  mcc->AdvanceByMillis(59);
  check.Call("pre long-tap dispatch");
  mcc->AdvanceByMillis(1);
  check.Call("post long-tap dispatch");
}

TEST_F(APZCGestureDetectorTester, OneTouchPinchGestureShort) {
  // Take less than StaticPrefs::apz_max_tap_time() until second touch down,
  // hold second touch down for a very short time, then move
  // and expect a successful one touch pinch gesture
  SCOPED_GFX_PREF_BOOL("apz.one_touch_pinch.enabled"true);

  MakeApzcZoomable();
  apzc->SetFrameMetrics(GetPinchableFrameMetrics());
  const auto oldZoom = apzc->GetFrameMetrics().GetZoom().scale;

  const auto tapResult =
      Tap(apzc, ScreenIntPoint(10, 10), TimeDuration::FromMilliseconds(10));
  apzc->SetAllowedTouchBehavior(tapResult.mInputBlockId,
                                {kDefaultTouchBehavior});

  mcc->AdvanceByMillis(10);
  const auto touchResult = TouchDown(apzc, ScreenIntPoint(10, 10), mcc->Time());
  apzc->SetAllowedTouchBehavior(touchResult.mInputBlockId,
                                {kDefaultTouchBehavior});

  // We should be able to hold down the second touch as long as we like
  // before beginning to move
  mcc->AdvanceByMillis(10);
  TouchMove(apzc, ScreenIntPoint(10, 50), mcc->Time());

  mcc->AdvanceByMillis(10);
  TouchMove(apzc, ScreenIntPoint(10, 150), mcc->Time());

  mcc->AdvanceByMillis(10);
  TouchUp(apzc, ScreenIntPoint(10, 150), mcc->Time());

  const auto newZoom = apzc->GetFrameMetrics().GetZoom().scale;
  EXPECT_NE(newZoom, oldZoom);
}

TEST_F(APZCGestureDetectorTester, OneTouchPinchGestureLong) {
  // Take less than StaticPrefs::apz_max_tap_time() until second touch down,
  // hold second touch down for a long time, then move
  // and expect a successful one touch pinch gesture
  SCOPED_GFX_PREF_BOOL("apz.one_touch_pinch.enabled"true);

  MakeApzcZoomable();
  apzc->SetFrameMetrics(GetPinchableFrameMetrics());
  const auto oldZoom = apzc->GetFrameMetrics().GetZoom().scale;

  const auto tapResult =
      Tap(apzc, ScreenIntPoint(10, 10), TimeDuration::FromMilliseconds(10));
  apzc->SetAllowedTouchBehavior(tapResult.mInputBlockId,
                                {kDefaultTouchBehavior});

  mcc->AdvanceByMillis(StaticPrefs::apz_max_tap_time() - 20);
  const auto touchResult = TouchDown(apzc, ScreenIntPoint(10, 10), mcc->Time());
  apzc->SetAllowedTouchBehavior(touchResult.mInputBlockId,
                                {kDefaultTouchBehavior});

  // We should be able to hold down the second touch as long as we like
  // before beginning to move
  mcc->AdvanceByMillis(StaticPrefs::apz_max_tap_time() + 100);
  TouchMove(apzc, ScreenIntPoint(10, 50), mcc->Time());

  mcc->AdvanceByMillis(10);
  TouchMove(apzc, ScreenIntPoint(10, 150), mcc->Time());

  mcc->AdvanceByMillis(10);
  TouchUp(apzc, ScreenIntPoint(10, 150), mcc->Time());

  const auto newZoom = apzc->GetFrameMetrics().GetZoom().scale;
  EXPECT_NE(newZoom, oldZoom);
}

TEST_F(APZCGestureDetectorTester, OneTouchPinchGestureNoMoveTriggersDoubleTap) {
  // Take less than StaticPrefs::apz_max_tap_time() until second touch down,
  // then wait longer than StaticPrefs::apz_max_tap_time(), lift finger up
  // and expect a successful double tap. No zooming should be performed
  // by the one-touch pinch codepath.
  SCOPED_GFX_PREF_BOOL("apz.one_touch_pinch.enabled"true);

  apzc->SetFrameMetrics(GetPinchableFrameMetrics());
  const auto oldZoom = apzc->GetFrameMetrics().GetZoom().scale;

  MakeApzcZoomable();

  EXPECT_CALL(*mcc, HandleTap(TapType::eSingleTap, _, 0, apzc->GetGuid(), _, _))
      .Times(0);
  EXPECT_CALL(*mcc,
              HandleTap(TapType::eDoubleTap, _, 0, apzc->GetGuid(), _, _));

  const auto tapResult =
      Tap(apzc, ScreenIntPoint(10, 10), TimeDuration::FromMilliseconds(10));
  apzc->SetAllowedTouchBehavior(tapResult.mInputBlockId,
                                {kDefaultTouchBehavior});

  mcc->AdvanceByMillis(StaticPrefs::apz_max_tap_time() - 20);
  const auto touchResult = TouchDown(apzc, ScreenIntPoint(10, 10), mcc->Time());
  apzc->SetAllowedTouchBehavior(touchResult.mInputBlockId,
                                {kDefaultTouchBehavior});

  // We should be able to hold down the second touch as long as we like
  // before lifting the finger
  mcc->AdvanceByMillis(StaticPrefs::apz_max_tap_time() + 100);
  TouchUp(apzc, ScreenIntPoint(10, 10), mcc->Time());

  const auto newZoom = apzc->GetFrameMetrics().GetZoom().scale;
  EXPECT_EQ(newZoom, oldZoom);
}

TEST_F(APZCGestureDetectorTester, OneTouchPinchGestureNonZoomablePage) {
  // Use a non-zoomable page. Perform a tap and a touch-drag
  // which on a zoomable page trigger a one touch pinch gesture,
  // and expect a single tap followed by a touch-scroll
  SCOPED_GFX_PREF_BOOL("apz.one_touch_pinch.enabled"true);

  apzc->SetFrameMetrics(GetPinchableFrameMetrics(1.0f));
  const auto oldZoom = apzc->GetFrameMetrics().GetZoom().scale;
  const auto oldScrollOffset = apzc->GetFrameMetrics().GetVisualScrollOffset();
  MakeApzcUnzoomable();

  EXPECT_CALL(*mcc, HandleTap(TapType::eSingleTap, _, 0, apzc->GetGuid(), _, _))
      .Times(1);
  EXPECT_CALL(*mcc, HandleTap(TapType::eDoubleTap, _, 0, apzc->GetGuid(), _, _))
      .Times(0);

  const auto tapResult =
      Tap(apzc, ScreenIntPoint(10, 10), TimeDuration::FromMilliseconds(10));
  apzc->SetAllowedTouchBehavior(tapResult.mInputBlockId,
                                {kDefaultTouchBehavior});

  mcc->AdvanceByMillis(StaticPrefs::apz_max_tap_time() - 20);
  const auto touchResult = TouchDown(apzc, ScreenIntPoint(10, 10), mcc->Time());
  apzc->SetAllowedTouchBehavior(touchResult.mInputBlockId,
                                {kDefaultTouchBehavior});

  // We should be able to hold down the second touch as long as we like
  // before beginning to move
  mcc->AdvanceByMillis(StaticPrefs::apz_max_tap_time() + 100);
  TouchMove(apzc, ScreenIntPoint(10, 50), mcc->Time());

  mcc->AdvanceByMillis(10);
  TouchMove(apzc, ScreenIntPoint(10, 100), mcc->Time());

  mcc->AdvanceByMillis(10);
  TouchUp(apzc, ScreenIntPoint(10, 100), mcc->Time());

  const auto newZoom = apzc->GetFrameMetrics().GetZoom().scale;
  EXPECT_EQ(newZoom, oldZoom);

  const auto newScrollOffset = apzc->GetFrameMetrics().GetVisualScrollOffset();
  EXPECT_NE(newScrollOffset, oldScrollOffset);
}

TEST_F(APZCGestureDetectorTester, OneTouchPinchGestureTimeout) {
  // Take longer than StaticPrefs::apz_max_tap_time() until second touch down
  // and expect no one touch pinch gesture being performed
  SCOPED_GFX_PREF_BOOL("apz.one_touch_pinch.enabled"true);

  MakeApzcZoomable();
  apzc->SetFrameMetrics(GetPinchableFrameMetrics());
  const auto oldZoom = apzc->GetFrameMetrics().GetZoom().scale;

  EXPECT_CALL(*mcc, HandleTap(TapType::eSingleTap, _, 0, apzc->GetGuid(), _, _))
      .Times(1);

  const auto tapResult =
      Tap(apzc, ScreenIntPoint(10, 10), TimeDuration::FromMilliseconds(10));
  apzc->SetAllowedTouchBehavior(tapResult.mInputBlockId,
                                {kDefaultTouchBehavior});

  mcc->AdvanceByMillis(StaticPrefs::apz_max_tap_time());
  const auto touchResult = TouchDown(apzc, ScreenIntPoint(10, 10), mcc->Time());
  apzc->SetAllowedTouchBehavior(touchResult.mInputBlockId,
                                {kDefaultTouchBehavior});

  mcc->AdvanceByMillis(10);
  TouchMove(apzc, ScreenIntPoint(10, 50), mcc->Time());

  mcc->AdvanceByMillis(10);
  TouchMove(apzc, ScreenIntPoint(10, 150), mcc->Time());

  mcc->AdvanceByMillis(10);
  TouchUp(apzc, ScreenIntPoint(10, 150), mcc->Time());

  const auto newZoom = apzc->GetFrameMetrics().GetZoom().scale;
  EXPECT_EQ(newZoom, oldZoom);
}

TEST_F(APZCGestureDetectorTester, OneTouchPinchGestureDisabled) {
  // With apz.one_touch_pinch disabled,
  // perform one touch pinch gesture within the time threshold,
  // and expect no zooming.
  SCOPED_GFX_PREF_BOOL("apz.one_touch_pinch.enabled"false);

  MakeApzcZoomable();
  apzc->SetFrameMetrics(GetPinchableFrameMetrics());
  const auto oldZoom = apzc->GetFrameMetrics().GetZoom().scale;
  const auto oldScrollOffset = apzc->GetFrameMetrics().GetVisualScrollOffset();

  // todo: enable following EXPECT_CALLs when fixing bug 1881794
  // EXPECT_CALL(*mcc, HandleTap(TapType::eSingleTap, _, 0, apzc->GetGuid(), _,
  // _))
  //     .Times(1);
  // EXPECT_CALL(*mcc, HandleTap(TapType::eDoubleTap, _, 0, apzc->GetGuid(), _,
  // _))
  //     .Times(0);

  const auto tapResult =
      Tap(apzc, ScreenIntPoint(10, 10), TimeDuration::FromMilliseconds(10));
  apzc->SetAllowedTouchBehavior(tapResult.mInputBlockId,
                                {kDefaultTouchBehavior});

  mcc->AdvanceByMillis(StaticPrefs::apz_max_tap_time() - 20);
  const auto touchResult = TouchDown(apzc, ScreenIntPoint(10, 10), mcc->Time());
  apzc->SetAllowedTouchBehavior(touchResult.mInputBlockId,
                                {kDefaultTouchBehavior});

  // We should be able to hold down the second touch as long as we like
  // before beginning to move
  mcc->AdvanceByMillis(StaticPrefs::apz_max_tap_time() + 100);
  TouchMove(apzc, ScreenIntPoint(10, 50), mcc->Time());

  mcc->AdvanceByMillis(10);
  TouchMove(apzc, ScreenIntPoint(10, 150), mcc->Time());

  mcc->AdvanceByMillis(10);
  TouchUp(apzc, ScreenIntPoint(10, 150), mcc->Time());

  const auto newZoom = apzc->GetFrameMetrics().GetZoom().scale;
  EXPECT_EQ(newZoom, oldZoom);

  const auto newScrollOffset = apzc->GetFrameMetrics().GetVisualScrollOffset();
  EXPECT_NE(newScrollOffset, oldScrollOffset);
}

Messung V0.5
C=86 H=94 G=89

¤ Dauer der Verarbeitung: 0.14 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.