diff options
Diffstat (limited to 'gfx/layers/apz/test/gtest/TestAxisLock.cpp')
-rw-r--r-- | gfx/layers/apz/test/gtest/TestAxisLock.cpp | 645 |
1 files changed, 645 insertions, 0 deletions
diff --git a/gfx/layers/apz/test/gtest/TestAxisLock.cpp b/gfx/layers/apz/test/gtest/TestAxisLock.cpp new file mode 100644 index 0000000000..8b0df3e8a2 --- /dev/null +++ b/gfx/layers/apz/test/gtest/TestAxisLock.cpp @@ -0,0 +1,645 @@ +/* -*- 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 "APZCTreeManagerTester.h" +#include "APZTestCommon.h" + +#include "InputUtils.h" +#include "gtest/gtest.h" + +#include <cmath> + +class APZCAxisLockCompatTester : public APZCTreeManagerTester, + public testing::WithParamInterface<int> { + public: + APZCAxisLockCompatTester() : oldAxisLockMode(0) { CreateMockHitTester(); } + + int oldAxisLockMode; + + UniquePtr<ScopedLayerTreeRegistration> registration; + + RefPtr<TestAsyncPanZoomController> apzc; + + void SetUp() { + APZCTreeManagerTester::SetUp(); + + oldAxisLockMode = Preferences::GetInt("apz.axis_lock.mode"); + + Preferences::SetInt("apz.axis_lock.mode", GetParam()); + } + + void TearDown() { + APZCTreeManagerTester::TearDown(); + + Preferences::SetInt("apz.axis_lock.mode", oldAxisLockMode); + } + + static std::string PrintFromParam(const testing::TestParamInfo<int>& info) { + switch (info.param) { + case 0: + return "FREE"; + case 1: + return "STANDARD"; + case 2: + return "STICKY"; + case 3: + return "DOMINANT_AXIS"; + default: + return "UNKNOWN"; + } + } +}; + +class APZCAxisLockTester : public APZCTreeManagerTester { + public: + APZCAxisLockTester() { CreateMockHitTester(); } + + UniquePtr<ScopedLayerTreeRegistration> registration; + + RefPtr<TestAsyncPanZoomController> apzc; + + void SetupBasicTest() { + const char* treeShape = "x"; + LayerIntRegion layerVisibleRegion[] = { + LayerIntRect(0, 0, 100, 100), + }; + CreateScrollData(treeShape, layerVisibleRegion); + SetScrollableFrameMetrics(root, ScrollableLayerGuid::START_SCROLL_ID, + CSSRect(0, 0, 500, 500)); + + registration = MakeUnique<ScopedLayerTreeRegistration>(LayersId{0}, mcc); + + UpdateHitTestingTree(); + } + + void BreakStickyAxisLockTestGesture(const ScrollDirections& aDirections) { + float panX = 0; + float panY = 0; + + if (aDirections.contains(ScrollDirection::eVertical)) { + panY = 30; + } + if (aDirections.contains(ScrollDirection::eHorizontal)) { + panX = 30; + } + + // Kick off the gesture that may lock onto an axis + QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); + PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 50), + ScreenPoint(panX, panY), mcc->Time()); + mcc->AdvanceByMillis(5); + apzc->AdvanceAnimations(mcc->GetSampleTime()); + + QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); + PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 50), + ScreenPoint(panX, panY), mcc->Time()); + } + + void BreakStickyAxisLockTest(const ScrollDirections& aDirections) { + // Create the gesture for the test. + BreakStickyAxisLockTestGesture(aDirections); + + // Based on the scroll direction(s) ensure the state is what we expect. + if (aDirections == ScrollDirection::eVertical) { + apzc->AssertStateIsPanningLockedY(); + apzc->AssertAxisLocked(ScrollDirection::eVertical); + EXPECT_GT(apzc->GetVelocityVector().y, 0); + EXPECT_EQ(apzc->GetVelocityVector().x, 0); + } else if (aDirections == ScrollDirection::eHorizontal) { + apzc->AssertStateIsPanningLockedX(); + apzc->AssertAxisLocked(ScrollDirection::eHorizontal); + EXPECT_GT(apzc->GetVelocityVector().x, 0); + EXPECT_EQ(apzc->GetVelocityVector().y, 0); + } else { + apzc->AssertStateIsPanning(); + apzc->AssertNotAxisLocked(); + EXPECT_GT(apzc->GetVelocityVector().x, 0); + EXPECT_GT(apzc->GetVelocityVector().y, 0); + } + + // Cleanup for next test. + apzc->AdvanceAnimationsUntilEnd(); + } +}; + +TEST_F(APZCAxisLockTester, BasicDominantAxisUse) { + SCOPED_GFX_PREF_INT("apz.axis_lock.mode", 1); + SCOPED_GFX_PREF_FLOAT("apz.axis_lock.lock_angle", M_PI / 4.0f); + + SetupBasicTest(); + + apzc = ApzcOf(root); + + // Kick off the initial gesture that triggers the momentum scroll. + QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); + PanGesture(PanGestureInput::PANGESTURE_START, manager, ScreenIntPoint(50, 50), + ScreenIntPoint(1, 2), mcc->Time()); + mcc->AdvanceByMillis(5); + apzc->AdvanceAnimations(mcc->GetSampleTime()); + + QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); + PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 50), + ScreenPoint(15, 30), mcc->Time()); + mcc->AdvanceByMillis(5); + apzc->AdvanceAnimations(mcc->GetSampleTime()); + + QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); + PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 50), + ScreenPoint(15, 30), mcc->Time()); + + // Should be in a PANNING_LOCKED_Y state with no horizontal velocity. + apzc->AssertStateIsPanningLockedY(); + apzc->AssertAxisLocked(ScrollDirection::eVertical); + EXPECT_GT(apzc->GetVelocityVector().y, 0); + EXPECT_EQ(apzc->GetVelocityVector().x, 0); + + mcc->AdvanceByMillis(5); + apzc->AdvanceAnimations(mcc->GetSampleTime()); + + QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); + PanGesture(PanGestureInput::PANGESTURE_END, manager, ScreenIntPoint(50, 50), + ScreenPoint(0, 0), mcc->Time()); + mcc->AdvanceByMillis(5); + apzc->AdvanceAnimations(mcc->GetSampleTime()); + + // Ensure that we have not panned on the horizontal axis. + ParentLayerPoint panEndOffset = apzc->GetCurrentAsyncScrollOffset( + AsyncPanZoomController::AsyncTransformConsumer::eForHitTesting); + EXPECT_EQ(panEndOffset.x, 0); + + // The lock onto the Y axis extends into momentum scroll. + apzc->AssertAxisLocked(ScrollDirection::eVertical); + + // Start the momentum scroll. + QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); + PanGesture(PanGestureInput::PANGESTURE_MOMENTUMSTART, manager, + ScreenIntPoint(50, 50), ScreenPoint(30, 90), mcc->Time()); + mcc->AdvanceByMillis(10); + apzc->AdvanceAnimations(mcc->GetSampleTime()); + + QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); + PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, manager, + ScreenIntPoint(50, 50), ScreenPoint(10, 30), mcc->Time()); + mcc->AdvanceByMillis(10); + apzc->AdvanceAnimations(mcc->GetSampleTime()); + + QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); + PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, manager, + ScreenIntPoint(50, 50), ScreenPoint(10, 30), mcc->Time()); + mcc->AdvanceByMillis(10); + apzc->AdvanceAnimations(mcc->GetSampleTime()); + + // In momentum locking mode, we should still be locked onto the Y axis. + apzc->AssertStateIsPanMomentum(); + apzc->AssertAxisLocked(ScrollDirection::eVertical); + EXPECT_GT(apzc->GetVelocityVector().y, 0); + EXPECT_EQ(apzc->GetVelocityVector().x, 0); + + QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); + PanGesture(PanGestureInput::PANGESTURE_MOMENTUMEND, manager, + ScreenIntPoint(50, 50), ScreenPoint(0, 0), mcc->Time()); + + // After momentum scroll end, ensure we are no longer locked onto an axis. + apzc->AssertNotAxisLocked(); + + // Wait until the end of the animation and ensure the final state is + // reasonable. + apzc->AdvanceAnimationsUntilEnd(); + ParentLayerPoint finalOffset = apzc->GetCurrentAsyncScrollOffset( + AsyncPanZoomController::AsyncTransformConsumer::eForHitTesting); + + // Ensure we have scrolled some amount on the Y axis in momentum scroll. + EXPECT_GT(finalOffset.y, panEndOffset.y); + EXPECT_EQ(finalOffset.x, 0.0f); +} + +TEST_F(APZCAxisLockTester, NewGestureBreaksMomentumAxisLock) { + SCOPED_GFX_PREF_INT("apz.axis_lock.mode", 1); + SCOPED_GFX_PREF_FLOAT("apz.axis_lock.lock_angle", M_PI / 4.0f); + + SetupBasicTest(); + + apzc = ApzcOf(root); + + // Kick off the initial gesture that triggers the momentum scroll. + QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); + PanGesture(PanGestureInput::PANGESTURE_START, manager, ScreenIntPoint(50, 50), + ScreenIntPoint(2, 1), mcc->Time()); + mcc->AdvanceByMillis(5); + apzc->AdvanceAnimations(mcc->GetSampleTime()); + + QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); + PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 50), + ScreenPoint(30, 15), mcc->Time()); + mcc->AdvanceByMillis(5); + apzc->AdvanceAnimations(mcc->GetSampleTime()); + + QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); + PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 50), + ScreenPoint(30, 15), mcc->Time()); + + // Should be in a PANNING_LOCKED_X state with no vertical velocity. + apzc->AssertStateIsPanningLockedX(); + apzc->AssertAxisLocked(ScrollDirection::eHorizontal); + EXPECT_GT(apzc->GetVelocityVector().x, 0); + EXPECT_EQ(apzc->GetVelocityVector().y, 0); + + mcc->AdvanceByMillis(5); + apzc->AdvanceAnimations(mcc->GetSampleTime()); + + QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); + PanGesture(PanGestureInput::PANGESTURE_END, manager, ScreenIntPoint(50, 50), + ScreenPoint(0, 0), mcc->Time()); + mcc->AdvanceByMillis(5); + apzc->AdvanceAnimations(mcc->GetSampleTime()); + + // Double check that we have not panned on the vertical axis. + ParentLayerPoint panEndOffset = apzc->GetCurrentAsyncScrollOffset( + AsyncPanZoomController::AsyncTransformConsumer::eForHitTesting); + EXPECT_EQ(panEndOffset.y, 0); + + // Ensure that the axis locks extends into momentum scroll. + apzc->AssertAxisLocked(ScrollDirection::eHorizontal); + + // Start the momentum scroll. + QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); + PanGesture(PanGestureInput::PANGESTURE_MOMENTUMSTART, manager, + ScreenIntPoint(50, 50), ScreenPoint(80, 40), mcc->Time()); + mcc->AdvanceByMillis(10); + apzc->AdvanceAnimations(mcc->GetSampleTime()); + + QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); + PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, manager, + ScreenIntPoint(50, 50), ScreenPoint(20, 10), mcc->Time()); + mcc->AdvanceByMillis(10); + apzc->AdvanceAnimations(mcc->GetSampleTime()); + + QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); + PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, manager, + ScreenIntPoint(50, 50), ScreenPoint(20, 10), mcc->Time()); + mcc->AdvanceByMillis(10); + apzc->AdvanceAnimations(mcc->GetSampleTime()); + + // In momentum locking mode, we should still be locked onto the X axis. + apzc->AssertStateIsPanMomentum(); + apzc->AssertAxisLocked(ScrollDirection::eHorizontal); + EXPECT_GT(apzc->GetVelocityVector().x, 0); + EXPECT_EQ(apzc->GetVelocityVector().y, 0); + + ParentLayerPoint beforeBreakOffset = apzc->GetCurrentAsyncScrollOffset( + AsyncPanZoomController::AsyncTransformConsumer::eForHitTesting); + EXPECT_EQ(beforeBreakOffset.y, 0); + // Ensure we have scrolled some amount on the X axis in momentum scroll. + EXPECT_GT(beforeBreakOffset.x, panEndOffset.x); + + // Kick off the gesture that breaks the lock onto the X axis. + QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); + PanGesture(PanGestureInput::PANGESTURE_START, manager, ScreenIntPoint(50, 50), + ScreenIntPoint(1, 2), mcc->Time()); + mcc->AdvanceByMillis(5); + apzc->AdvanceAnimations(mcc->GetSampleTime()); + + ParentLayerPoint afterBreakOffset = apzc->GetCurrentAsyncScrollOffset( + AsyncPanZoomController::AsyncTransformConsumer::eForHitTesting); + + QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); + PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 50), + ScreenPoint(15, 30), mcc->Time()); + mcc->AdvanceByMillis(5); + apzc->AdvanceAnimations(mcc->GetSampleTime()); + + QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); + PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 50), + ScreenPoint(15, 30), mcc->Time()); + + // The lock onto the X axis should be broken and we now should be locked + // onto the Y axis. + apzc->AssertStateIsPanningLockedY(); + apzc->AssertAxisLocked(ScrollDirection::eVertical); + EXPECT_GT(apzc->GetVelocityVector().y, 0); + EXPECT_EQ(apzc->GetVelocityVector().x, 0); + + mcc->AdvanceByMillis(5); + apzc->AdvanceAnimations(mcc->GetSampleTime()); + + QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); + PanGesture(PanGestureInput::PANGESTURE_END, manager, ScreenIntPoint(50, 50), + ScreenPoint(0, 0), mcc->Time()); + mcc->AdvanceByMillis(5); + apzc->AdvanceAnimations(mcc->GetSampleTime()); + + // The lock onto the Y axis extends into momentum scroll. + apzc->AssertAxisLocked(ScrollDirection::eVertical); + + // Wait until the end of the animation and ensure the final state is + // reasonable. + apzc->AdvanceAnimationsUntilEnd(); + ParentLayerPoint finalOffset = apzc->GetCurrentAsyncScrollOffset( + AsyncPanZoomController::AsyncTransformConsumer::eForHitTesting); + + EXPECT_GT(finalOffset.y, 0); + // Ensure that we did not scroll on the X axis after the vertical scroll + // started. + EXPECT_EQ(finalOffset.x, afterBreakOffset.x); +} + +TEST_F(APZCAxisLockTester, BreakStickyAxisLock) { + 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 / 6.0f); + + SetupBasicTest(); + + apzc = ApzcOf(root); + + // Start a gesture to get us locked onto the Y axis. + QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); + PanGesture(PanGestureInput::PANGESTURE_START, manager, ScreenIntPoint(50, 50), + ScreenIntPoint(0, 2), mcc->Time()); + mcc->AdvanceByMillis(5); + apzc->AdvanceAnimations(mcc->GetSampleTime()); + + // Ensure that we have locked onto the Y axis. + apzc->AssertStateIsPanningLockedY(); + + // Test switch to locking onto the X axis. + BreakStickyAxisLockTest(ScrollDirection::eHorizontal); + + // Test switch back to locking onto the Y axis. + BreakStickyAxisLockTest(ScrollDirection::eVertical); + + // Test breaking all axis locks from a Y axis lock. + BreakStickyAxisLockTest(ScrollDirections(ScrollDirection::eHorizontal, + ScrollDirection::eVertical)); + + // We should be in a panning state. + apzc->AssertStateIsPanning(); + apzc->AssertNotAxisLocked(); + + // Lock back to the X axis. + BreakStickyAxisLockTestGesture(ScrollDirection::eHorizontal); + + // End the gesture. + QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); + PanGesture(PanGestureInput::PANGESTURE_END, manager, ScreenIntPoint(50, 50), + ScreenPoint(0, 0), mcc->Time()); + mcc->AdvanceByMillis(5); + apzc->AdvanceAnimations(mcc->GetSampleTime()); + + // Start a gesture to get us locked onto the X axis. + QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); + PanGesture(PanGestureInput::PANGESTURE_START, manager, ScreenIntPoint(50, 50), + ScreenIntPoint(2, 0), mcc->Time()); + mcc->AdvanceByMillis(5); + apzc->AdvanceAnimations(mcc->GetSampleTime()); + + // Ensure that we have locked onto the X axis. + apzc->AssertStateIsPanningLockedX(); + + // Test breaking all axis locks from a X axis lock. + BreakStickyAxisLockTest(ScrollDirections(ScrollDirection::eHorizontal, + ScrollDirection::eVertical)); + + // We should be in a panning state. + apzc->AssertStateIsPanning(); + apzc->AssertNotAxisLocked(); + + // Test switch back to locking onto the Y axis. + BreakStickyAxisLockTest(ScrollDirection::eVertical); +} + +TEST_F(APZCAxisLockTester, BreakAxisLockByLockAngle) { + SCOPED_GFX_PREF_INT("apz.axis_lock.mode", 2); + SCOPED_GFX_PREF_FLOAT("apz.axis_lock.lock_angle", M_PI / 4.0f); + SCOPED_GFX_PREF_FLOAT("apz.axis_lock.breakout_angle", M_PI / 8.0f); + + SetupBasicTest(); + + apzc = ApzcOf(root); + + // Start a gesture to get us locked onto the Y axis. + QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); + PanGesture(PanGestureInput::PANGESTURE_START, manager, ScreenIntPoint(50, 50), + ScreenIntPoint(1, 10), mcc->Time()); + mcc->AdvanceByMillis(5); + apzc->AdvanceAnimations(mcc->GetSampleTime()); + + // Ensure that we have locked onto the Y axis. + apzc->AssertStateIsPanningLockedY(); + + // Stay within 45 degrees from the X axis, and more than 22.5 degrees from + // the Y axis. This should break the Y lock and lock us to the X axis. + QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); + PanGesture(PanGestureInput::PANGESTURE_PAN, manager, ScreenIntPoint(50, 50), + ScreenIntPoint(12, 10), mcc->Time()); + apzc->AdvanceAnimations(mcc->GetSampleTime()); + + // Ensure that we have locked onto the X axis. + apzc->AssertStateIsPanningLockedX(); + + // End the gesture. + QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); + PanGesture(PanGestureInput::PANGESTURE_END, manager, ScreenIntPoint(50, 50), + ScreenPoint(0, 0), mcc->Time()); + apzc->AdvanceAnimations(mcc->GetSampleTime()); +} + +TEST_F(APZCAxisLockTester, TestDominantAxisScrolling) { + SCOPED_GFX_PREF_INT("apz.axis_lock.mode", 3); + + int panY; + int panX; + + SetupBasicTest(); + + apzc = ApzcOf(root); + + ParentLayerPoint lastOffset = + apzc->GetCurrentAsyncScrollOffset(AsyncPanZoomController::eForHitTesting); + + // In dominant axis mode, test pan gesture events with varying gesture + // angles and ensure that we only pan on one axis. + for (panX = 0, panY = 50; panY >= 0; panY -= 10, panX += 5) { + // Gesture that should be locked onto one axis + QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); + PanGesture(PanGestureInput::PANGESTURE_START, manager, + ScreenIntPoint(50, 50), ScreenIntPoint(panX, panY), mcc->Time()); + mcc->AdvanceByMillis(5); + apzc->AdvanceAnimations(mcc->GetSampleTime()); + + QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); + PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 50), + ScreenPoint(static_cast<float>(panX), static_cast<float>(panY)), + mcc->Time()); + mcc->AdvanceByMillis(5); + apzc->AdvanceAnimations(mcc->GetSampleTime()); + + QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); + PanGesture(PanGestureInput::PANGESTURE_END, manager, ScreenIntPoint(50, 50), + ScreenPoint(0, 0), mcc->Time()); + apzc->AdvanceAnimationsUntilEnd(); + + ParentLayerPoint scrollOffset = apzc->GetCurrentAsyncScrollOffset( + AsyncPanZoomController::eForHitTesting); + + if (panX > panY) { + // If we're closer to the X axis ensure that we moved on the horizontal + // axis and there was no movement on the vertical axis. + EXPECT_GT(scrollOffset.x, lastOffset.x); + EXPECT_EQ(scrollOffset.y, lastOffset.y); + } else { + // If we're closer to the Y axis ensure that we moved on the vertical + // axis and there was no movement on the horizontal axis. + EXPECT_GT(scrollOffset.y, lastOffset.y); + EXPECT_EQ(scrollOffset.x, lastOffset.x); + } + + lastOffset = scrollOffset; + } +} + +TEST_F(APZCAxisLockTester, TestCanScrollWithAxisLock) { + SCOPED_GFX_PREF_INT("apz.axis_lock.mode", 2); + + SetupBasicTest(); + + apzc = ApzcOf(root); + + // The axis locks do not impact CanScroll() + apzc->SetAxisLocked(ScrollDirection::eHorizontal, true); + EXPECT_EQ(apzc->CanScroll(ParentLayerPoint(10, 0)), true); + + apzc->SetAxisLocked(ScrollDirection::eHorizontal, false); + apzc->SetAxisLocked(ScrollDirection::eVertical, true); + EXPECT_EQ(apzc->CanScroll(ParentLayerPoint(0, 10)), true); +} + +TEST_F(APZCAxisLockTester, TestScrollHandoffAxisLockConflict) { + SCOPED_GFX_PREF_INT("apz.axis_lock.mode", 2); + + // Create two scrollable frames. One parent frame with one child. + const char* treeShape = "x(x)"; + LayerIntRegion layerVisibleRegion[] = { + LayerIntRect(0, 0, 100, 100), + LayerIntRect(0, 0, 100, 100), + }; + CreateScrollData(treeShape, layerVisibleRegion); + SetScrollableFrameMetrics(root, ScrollableLayerGuid::START_SCROLL_ID, + CSSRect(0, 0, 500, 500)); + SetScrollableFrameMetrics(layers[1], ScrollableLayerGuid::START_SCROLL_ID + 1, + CSSRect(0, 0, 500, 500)); + SetScrollHandoff(layers[1], root); + + registration = MakeUnique<ScopedLayerTreeRegistration>(LayersId{0}, mcc); + + UpdateHitTestingTree(); + + RefPtr<TestAsyncPanZoomController> rootApzc = ApzcOf(root); + apzc = ApzcOf(layers[1]); + + // Create a gesture on the y-axis that should lock the x axis. + QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1); + PanGesture(PanGestureInput::PANGESTURE_START, manager, ScreenIntPoint(50, 50), + ScreenIntPoint(0, 2), mcc->Time()); + mcc->AdvanceByMillis(5); + apzc->AdvanceAnimations(mcc->GetSampleTime()); + + QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1); + PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 50), + ScreenPoint(0, 15), mcc->Time()); + mcc->AdvanceByMillis(5); + apzc->AdvanceAnimations(mcc->GetSampleTime()); + + QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1); + PanGesture(PanGestureInput::PANGESTURE_END, manager, ScreenIntPoint(50, 50), + ScreenPoint(0, 0), mcc->Time()); + mcc->AdvanceByMillis(5); + apzc->AdvanceAnimationsUntilEnd(); + + // We are locked onto the y-axis. + apzc->AssertAxisLocked(ScrollDirection::eVertical); + + // There should be movement in the child. + ParentLayerPoint childCurrentOffset = apzc->GetCurrentAsyncScrollOffset( + AsyncPanZoomController::AsyncTransformConsumer::eForHitTesting); + EXPECT_GT(childCurrentOffset.y, 0); + EXPECT_EQ(childCurrentOffset.x, 0); + + // There should be no movement in the parent. + ParentLayerPoint parentCurrentOffset = rootApzc->GetCurrentAsyncScrollOffset( + AsyncPanZoomController::AsyncTransformConsumer::eForHitTesting); + EXPECT_EQ(parentCurrentOffset.y, 0); + EXPECT_EQ(parentCurrentOffset.x, 0); + + // Create a gesture on the x-axis, that should be directed + // at the child, even if the x-axis is locked. + QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1); + PanGesture(PanGestureInput::PANGESTURE_START, manager, ScreenIntPoint(50, 50), + ScreenIntPoint(2, 0), mcc->Time()); + mcc->AdvanceByMillis(5); + apzc->AdvanceAnimations(mcc->GetSampleTime()); + + QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1); + PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 50), + ScreenPoint(15, 0), mcc->Time()); + mcc->AdvanceByMillis(5); + apzc->AdvanceAnimations(mcc->GetSampleTime()); + + QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1); + PanGesture(PanGestureInput::PANGESTURE_END, manager, ScreenIntPoint(50, 50), + ScreenPoint(0, 0), mcc->Time()); + mcc->AdvanceByMillis(5); + apzc->AdvanceAnimationsUntilEnd(); + + // We broke the y-axis lock and are now locked onto the x-axis. + apzc->AssertAxisLocked(ScrollDirection::eHorizontal); + + // There should be some movement in the child on the x-axis. + ParentLayerPoint childFinalOffset = apzc->GetCurrentAsyncScrollOffset( + AsyncPanZoomController::AsyncTransformConsumer::eForHitTesting); + EXPECT_GT(childFinalOffset.x, 0); + + // There should still be no movement in the parent. + ParentLayerPoint parentFinalOffset = rootApzc->GetCurrentAsyncScrollOffset( + AsyncPanZoomController::AsyncTransformConsumer::eForHitTesting); + EXPECT_EQ(parentFinalOffset.y, 0); + EXPECT_EQ(parentFinalOffset.x, 0); +} + +// The delta from the initial pan gesture should be reflected in the +// current offset for all axis locking modes. +TEST_P(APZCAxisLockCompatTester, TestPanGestureStart) { + const char* treeShape = "x"; + LayerIntRegion layerVisibleRegion[] = { + LayerIntRect(0, 0, 100, 100), + }; + CreateScrollData(treeShape, layerVisibleRegion); + SetScrollableFrameMetrics(root, ScrollableLayerGuid::START_SCROLL_ID, + CSSRect(0, 0, 500, 500)); + + registration = MakeUnique<ScopedLayerTreeRegistration>(LayersId{0}, mcc); + + UpdateHitTestingTree(); + + apzc = ApzcOf(root); + + QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); + PanGesture(PanGestureInput::PANGESTURE_START, manager, ScreenIntPoint(50, 50), + ScreenIntPoint(0, 10), mcc->Time()); + mcc->AdvanceByMillis(5); + apzc->AdvanceAnimationsUntilEnd(); + ParentLayerPoint currentOffset = apzc->GetCurrentAsyncScrollOffset( + AsyncPanZoomController::AsyncTransformConsumer::eForHitTesting); + + EXPECT_EQ(currentOffset.x, 0); + EXPECT_EQ(currentOffset.y, 10); +} + +// All APZCAxisLockCompatTester tests should be run for each apz.axis_lock.mode. +// If another mode is added, the value should be added to this list. +INSTANTIATE_TEST_SUITE_P(APZCAxisLockCompat, APZCAxisLockCompatTester, + testing::Values(0, 1, 2, 3), + APZCAxisLockCompatTester::PrintFromParam); |