diff options
Diffstat (limited to 'gfx/layers/apz/test/gtest/TestPointerEventsConsumable.cpp')
-rw-r--r-- | gfx/layers/apz/test/gtest/TestPointerEventsConsumable.cpp | 500 |
1 files changed, 500 insertions, 0 deletions
diff --git a/gfx/layers/apz/test/gtest/TestPointerEventsConsumable.cpp b/gfx/layers/apz/test/gtest/TestPointerEventsConsumable.cpp new file mode 100644 index 0000000000..1946baafe6 --- /dev/null +++ b/gfx/layers/apz/test/gtest/TestPointerEventsConsumable.cpp @@ -0,0 +1,500 @@ +/* -*- 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 "APZCTreeManagerTester.h" +#include "APZTestCommon.h" +#include "InputUtils.h" +#include "apz/src/AsyncPanZoomController.h" +#include "apz/src/InputBlockState.h" +#include "apz/src/OverscrollHandoffState.h" +#include "mozilla/layers/IAPZCTreeManager.h" + +class APZCArePointerEventsConsumable : public APZCTreeManagerTester { + public: + APZCArePointerEventsConsumable() { CreateMockHitTester(); } + + void CreateSingleElementTree() { + 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(); + + ApzcOf(root)->GetFrameMetrics().SetIsRootContent(true); + } + + void CreateScrollHandoffTree() { + const char* treeShape = "x(x)"; + LayerIntRegion layerVisibleRegion[] = {LayerIntRect(0, 0, 200, 200), + LayerIntRect(50, 50, 100, 100)}; + CreateScrollData(treeShape, layerVisibleRegion); + SetScrollableFrameMetrics(root, ScrollableLayerGuid::START_SCROLL_ID, + CSSRect(0, 0, 300, 300)); + SetScrollableFrameMetrics(layers[1], + ScrollableLayerGuid::START_SCROLL_ID + 1, + CSSRect(0, 0, 200, 200)); + SetScrollHandoff(layers[1], root); + registration = MakeUnique<ScopedLayerTreeRegistration>(LayersId{0}, mcc); + UpdateHitTestingTree(); + + ApzcOf(root)->GetFrameMetrics().SetIsRootContent(true); + } + + RefPtr<TouchBlockState> CreateTouchBlockStateForApzc( + const RefPtr<TestAsyncPanZoomController>& aApzc) { + TouchCounter counter{}; + TargetConfirmationFlags flags{true}; + + return new TouchBlockState(aApzc, flags, counter); + } + + void UpdateOverscrollBehavior(ScrollableLayerGuid::ViewID aScrollId, + OverscrollBehavior aX, OverscrollBehavior aY) { + auto* layer = layers[aScrollId - ScrollableLayerGuid::START_SCROLL_ID]; + ModifyFrameMetrics(layer, [aX, aY](ScrollMetadata& sm, FrameMetrics& _) { + OverscrollBehaviorInfo overscroll; + overscroll.mBehaviorX = aX; + overscroll.mBehaviorY = aY; + sm.SetOverscrollBehavior(overscroll); + }); + UpdateHitTestingTree(); + } + + UniquePtr<ScopedLayerTreeRegistration> registration; +}; + +TEST_F(APZCArePointerEventsConsumable, EmptyInput) { + CreateSingleElementTree(); + + RefPtr<TestAsyncPanZoomController> apzc = ApzcOf(root); + RefPtr<TouchBlockState> blockState = CreateTouchBlockStateForApzc(apzc); + + MultiTouchInput touchInput = + CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_START, mcc->Time()); + + const PointerEventsConsumableFlags expected{false, false}; + const PointerEventsConsumableFlags actual = + apzc->ArePointerEventsConsumable(blockState, touchInput); + EXPECT_EQ(expected, actual); +} + +TEST_F(APZCArePointerEventsConsumable, ScrollHorizontally) { + CreateSingleElementTree(); + + RefPtr<TestAsyncPanZoomController> apzc = ApzcOf(root); + RefPtr<TouchBlockState> blockState = CreateTouchBlockStateForApzc(apzc); + + // Create touch with horizontal 20 unit scroll + MultiTouchInput touchStart = + CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_START, mcc->Time()); + touchStart.mTouches.AppendElement( + SingleTouchData(0, ScreenIntPoint(10, 10), ScreenSize(0, 0), 0, 0)); + + MultiTouchInput touchMove = + CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, mcc->Time()); + touchMove.mTouches.AppendElement( + SingleTouchData(0, ScreenIntPoint(30, 10), ScreenSize(0, 0), 0, 0)); + + blockState->UpdateSlopState(touchStart, false); + + PointerEventsConsumableFlags actual{}; + PointerEventsConsumableFlags expected{}; + + // Scroll area 500x500, room to pan x, room to pan y + expected = {true, true}; + actual = apzc->ArePointerEventsConsumable(blockState, touchMove); + EXPECT_EQ(expected, actual); + + // Scroll area 100x100, no room to pan x, no room to pan y + apzc->GetFrameMetrics().SetScrollableRect(CSSRect{0, 0, 100, 100}); + expected = {false, true}; + actual = apzc->ArePointerEventsConsumable(blockState, touchMove); + EXPECT_EQ(expected, actual); + + // Scroll area 500x100, room to pan x, no room to pan y + apzc->GetFrameMetrics().SetScrollableRect(CSSRect{0, 0, 500, 100}); + expected = {true, true}; + actual = apzc->ArePointerEventsConsumable(blockState, touchMove); + EXPECT_EQ(expected, actual); + + // Scroll area 100x500, no room to pan x, room to pan y + apzc->GetFrameMetrics().SetScrollableRect(CSSRect{0, 0, 100, 500}); + expected = {false, true}; + actual = apzc->ArePointerEventsConsumable(blockState, touchMove); + EXPECT_EQ(expected, actual); +} + +TEST_F(APZCArePointerEventsConsumable, ScrollVertically) { + CreateSingleElementTree(); + + RefPtr<TestAsyncPanZoomController> apzc = ApzcOf(root); + RefPtr<TouchBlockState> blockState = CreateTouchBlockStateForApzc(apzc); + + // Create touch with vertical 20 unit scroll + MultiTouchInput touchStart = + CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_START, mcc->Time()); + touchStart.mTouches.AppendElement( + SingleTouchData(0, ScreenIntPoint(10, 10), ScreenSize(0, 0), 0, 0)); + + MultiTouchInput touchMove = + CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, mcc->Time()); + touchMove.mTouches.AppendElement( + SingleTouchData(0, ScreenIntPoint(10, 30), ScreenSize(0, 0), 0, 0)); + + blockState->UpdateSlopState(touchStart, false); + + PointerEventsConsumableFlags actual{}; + PointerEventsConsumableFlags expected{}; + + // Scroll area 500x500, room to pan x, room to pan y + expected = {true, true}; + actual = apzc->ArePointerEventsConsumable(blockState, touchMove); + EXPECT_EQ(expected, actual); + + // Scroll area 100x100, no room to pan x, no room to pan y + apzc->GetFrameMetrics().SetScrollableRect(CSSRect{0, 0, 100, 100}); + expected = {false, true}; + actual = apzc->ArePointerEventsConsumable(blockState, touchMove); + EXPECT_EQ(expected, actual); + + // Scroll area 500x100, room to pan x, no room to pan y + apzc->GetFrameMetrics().SetScrollableRect(CSSRect{0, 0, 500, 100}); + expected = {false, true}; + actual = apzc->ArePointerEventsConsumable(blockState, touchMove); + EXPECT_EQ(expected, actual); + + // Scroll area 100x500, no room to pan x, room to pan y + apzc->GetFrameMetrics().SetScrollableRect(CSSRect{0, 0, 100, 500}); + expected = {true, true}; + actual = apzc->ArePointerEventsConsumable(blockState, touchMove); + EXPECT_EQ(expected, actual); +} + +TEST_F(APZCArePointerEventsConsumable, NestedElementCanScroll) { + CreateScrollHandoffTree(); + + RefPtr<TestAsyncPanZoomController> apzc = ApzcOf(layers[1]); + RefPtr<TouchBlockState> blockState = CreateTouchBlockStateForApzc(apzc); + + // Create touch with vertical 20 unit scroll + MultiTouchInput touchStart = + CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_START, mcc->Time()); + touchStart.mTouches.AppendElement( + SingleTouchData(0, ScreenIntPoint(60, 60), ScreenSize(0, 0), 0, 0)); + + MultiTouchInput touchMove = + CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, mcc->Time()); + touchMove.mTouches.AppendElement( + SingleTouchData(0, ScreenIntPoint(60, 80), ScreenSize(0, 0), 0, 0)); + + blockState->UpdateSlopState(touchStart, false); + + const PointerEventsConsumableFlags expected{true, true}; + const PointerEventsConsumableFlags actual = + apzc->ArePointerEventsConsumable(blockState, touchMove); + EXPECT_EQ(expected, actual); +} + +TEST_F(APZCArePointerEventsConsumable, NestedElementCannotScroll) { + CreateScrollHandoffTree(); + + RefPtr<TestAsyncPanZoomController> apzc = ApzcOf(layers[1]); + RefPtr<TouchBlockState> blockState = CreateTouchBlockStateForApzc(apzc); + + // Create touch with vertical 20 unit scroll + MultiTouchInput touchStart = + CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_START, mcc->Time()); + touchStart.mTouches.AppendElement( + SingleTouchData(0, ScreenIntPoint(60, 60), ScreenSize(0, 0), 0, 0)); + + MultiTouchInput touchMove = + CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, mcc->Time()); + touchMove.mTouches.AppendElement( + SingleTouchData(0, ScreenIntPoint(60, 80), ScreenSize(0, 0), 0, 0)); + + blockState->UpdateSlopState(touchStart, false); + + PointerEventsConsumableFlags actual{}; + PointerEventsConsumableFlags expected{}; + + // Set the nested element to have no room to scroll. + // Because of the overscroll handoff, we still have room to scroll + // in the parent element. + apzc->GetFrameMetrics().SetScrollableRect(CSSRect{0, 0, 100, 100}); + expected = {true, true}; + actual = apzc->ArePointerEventsConsumable(blockState, touchMove); + EXPECT_EQ(expected, actual); + + // Set overscroll handoff for the nested element to none. + // Because no handoff will happen, we are not able to use the parent's + // room to scroll. + // Bug 1814886: Once fixed, change expected value to {false, true}. + UpdateOverscrollBehavior(ScrollableLayerGuid::START_SCROLL_ID + 1, + OverscrollBehavior::None, OverscrollBehavior::None); + expected = {true, true}; + actual = apzc->ArePointerEventsConsumable(blockState, touchMove); + EXPECT_EQ(expected, actual); +} + +TEST_F(APZCArePointerEventsConsumable, NotScrollableButZoomable) { + CreateSingleElementTree(); + + RefPtr<TestAsyncPanZoomController> apzc = ApzcOf(root); + RefPtr<TouchBlockState> blockState = CreateTouchBlockStateForApzc(apzc); + + // Create touch with vertical 20 unit scroll + MultiTouchInput touchStart = + CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_START, mcc->Time()); + touchStart.mTouches.AppendElement( + SingleTouchData(0, ScreenIntPoint(60, 60), ScreenSize(0, 0), 0, 0)); + + MultiTouchInput touchMove = + CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, mcc->Time()); + touchMove.mTouches.AppendElement( + SingleTouchData(0, ScreenIntPoint(60, 80), ScreenSize(0, 0), 0, 0)); + + blockState->UpdateSlopState(touchStart, false); + + // Make the root have no room to scroll + apzc->GetFrameMetrics().SetScrollableRect(CSSRect{0, 0, 100, 100}); + + // Make zoomable + apzc->UpdateZoomConstraints(ZoomConstraints( + true, true, CSSToParentLayerScale(0.25f), CSSToParentLayerScale(4.0f))); + + PointerEventsConsumableFlags actual{}; + PointerEventsConsumableFlags expected{}; + + expected = {false, true}; + actual = apzc->ArePointerEventsConsumable(blockState, touchMove); + EXPECT_EQ(expected, actual); + + // Add a second touch point and therefore make the APZC consider + // zoom use cases as well. + touchMove.mTouches.AppendElement( + SingleTouchData(0, ScreenIntPoint(60, 90), ScreenSize(0, 0), 0, 0)); + + expected = {true, true}; + actual = apzc->ArePointerEventsConsumable(blockState, touchMove); + EXPECT_EQ(expected, actual); +} + +TEST_F(APZCArePointerEventsConsumable, TouchActionsProhibitAll) { + CreateSingleElementTree(); + + RefPtr<TestAsyncPanZoomController> apzc = ApzcOf(root); + + // Create touch with vertical 20 unit scroll + MultiTouchInput touchStart = + CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_START, mcc->Time()); + touchStart.mTouches.AppendElement( + SingleTouchData(0, ScreenIntPoint(60, 60), ScreenSize(0, 0), 0, 0)); + + MultiTouchInput touchMove = + CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, mcc->Time()); + touchMove.mTouches.AppendElement( + SingleTouchData(0, ScreenIntPoint(60, 80), ScreenSize(0, 0), 0, 0)); + + PointerEventsConsumableFlags expected{}; + PointerEventsConsumableFlags actual{}; + + { + RefPtr<TouchBlockState> blockState = CreateTouchBlockStateForApzc(apzc); + blockState->UpdateSlopState(touchStart, false); + + blockState->SetAllowedTouchBehaviors({AllowedTouchBehavior::NONE}); + expected = {true, false}; + actual = apzc->ArePointerEventsConsumable(blockState, touchMove); + EXPECT_EQ(expected, actual); + } + + // Convert touch input to two-finger pinch + touchStart.mTouches.AppendElement( + SingleTouchData(1, ScreenIntPoint(80, 80), ScreenSize(0, 0), 0, 0)); + touchMove.mTouches.AppendElement( + SingleTouchData(1, ScreenIntPoint(90, 90), ScreenSize(0, 0), 0, 0)); + + { + RefPtr<TouchBlockState> blockState = CreateTouchBlockStateForApzc(apzc); + blockState->UpdateSlopState(touchStart, false); + + blockState->SetAllowedTouchBehaviors({AllowedTouchBehavior::NONE}); + expected = {true, false}; + actual = apzc->ArePointerEventsConsumable(blockState, touchMove); + EXPECT_EQ(expected, actual); + } +} + +TEST_F(APZCArePointerEventsConsumable, TouchActionsAllowVerticalScrolling) { + CreateSingleElementTree(); + + RefPtr<TestAsyncPanZoomController> apzc = ApzcOf(root); + + // Create touch with vertical 20 unit scroll + MultiTouchInput touchStart = + CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_START, mcc->Time()); + touchStart.mTouches.AppendElement( + SingleTouchData(0, ScreenIntPoint(60, 60), ScreenSize(0, 0), 0, 0)); + + MultiTouchInput touchMove = + CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, mcc->Time()); + touchMove.mTouches.AppendElement( + SingleTouchData(0, ScreenIntPoint(60, 80), ScreenSize(0, 0), 0, 0)); + + PointerEventsConsumableFlags expected{}; + PointerEventsConsumableFlags actual{}; + + { + RefPtr<TouchBlockState> blockState = CreateTouchBlockStateForApzc(apzc); + blockState->UpdateSlopState(touchStart, false); + + blockState->SetAllowedTouchBehaviors({AllowedTouchBehavior::NONE}); + expected = {true, false}; + actual = apzc->ArePointerEventsConsumable(blockState, touchMove); + EXPECT_EQ(expected, actual); + } + + { + RefPtr<TouchBlockState> blockState = CreateTouchBlockStateForApzc(apzc); + blockState->UpdateSlopState(touchStart, false); + + blockState->SetAllowedTouchBehaviors({AllowedTouchBehavior::VERTICAL_PAN}); + expected = {true, true}; + actual = apzc->ArePointerEventsConsumable(blockState, touchMove); + EXPECT_EQ(expected, actual); + } +} + +TEST_F(APZCArePointerEventsConsumable, TouchActionsAllowHorizontalScrolling) { + CreateSingleElementTree(); + + RefPtr<TestAsyncPanZoomController> apzc = ApzcOf(root); + + // Create touch with horizontal 20 unit scroll + MultiTouchInput touchStart = + CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_START, mcc->Time()); + touchStart.mTouches.AppendElement( + SingleTouchData(0, ScreenIntPoint(60, 60), ScreenSize(0, 0), 0, 0)); + + MultiTouchInput touchMove = + CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, mcc->Time()); + touchMove.mTouches.AppendElement( + SingleTouchData(0, ScreenIntPoint(80, 60), ScreenSize(0, 0), 0, 0)); + + PointerEventsConsumableFlags expected{}; + PointerEventsConsumableFlags actual{}; + + { + RefPtr<TouchBlockState> blockState = CreateTouchBlockStateForApzc(apzc); + blockState->UpdateSlopState(touchStart, false); + + blockState->SetAllowedTouchBehaviors({AllowedTouchBehavior::NONE}); + expected = {true, false}; + actual = apzc->ArePointerEventsConsumable(blockState, touchMove); + EXPECT_EQ(expected, actual); + } + + { + RefPtr<TouchBlockState> blockState = CreateTouchBlockStateForApzc(apzc); + blockState->UpdateSlopState(touchStart, false); + + blockState->SetAllowedTouchBehaviors( + {AllowedTouchBehavior::HORIZONTAL_PAN}); + expected = {true, true}; + actual = apzc->ArePointerEventsConsumable(blockState, touchMove); + EXPECT_EQ(expected, actual); + } +} + +TEST_F(APZCArePointerEventsConsumable, TouchActionsAllowPinchZoom) { + CreateSingleElementTree(); + + RefPtr<TestAsyncPanZoomController> apzc = ApzcOf(root); + + // Create two-finger pinch + MultiTouchInput touchStart = + CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_START, mcc->Time()); + touchStart.mTouches.AppendElement( + SingleTouchData(0, ScreenIntPoint(60, 60), ScreenSize(0, 0), 0, 0)); + touchStart.mTouches.AppendElement( + SingleTouchData(1, ScreenIntPoint(80, 80), ScreenSize(0, 0), 0, 0)); + + MultiTouchInput touchMove = + CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, mcc->Time()); + touchMove.mTouches.AppendElement( + SingleTouchData(0, ScreenIntPoint(50, 50), ScreenSize(0, 0), 0, 0)); + touchMove.mTouches.AppendElement( + SingleTouchData(1, ScreenIntPoint(90, 90), ScreenSize(0, 0), 0, 0)); + + PointerEventsConsumableFlags expected{}; + PointerEventsConsumableFlags actual{}; + + { + RefPtr<TouchBlockState> blockState = CreateTouchBlockStateForApzc(apzc); + blockState->UpdateSlopState(touchStart, false); + + blockState->SetAllowedTouchBehaviors({AllowedTouchBehavior::NONE}); + expected = {true, false}; + actual = apzc->ArePointerEventsConsumable(blockState, touchMove); + EXPECT_EQ(expected, actual); + } + + { + RefPtr<TouchBlockState> blockState = CreateTouchBlockStateForApzc(apzc); + blockState->UpdateSlopState(touchStart, false); + + blockState->SetAllowedTouchBehaviors({AllowedTouchBehavior::PINCH_ZOOM}); + expected = {true, true}; + actual = apzc->ArePointerEventsConsumable(blockState, touchMove); + EXPECT_EQ(expected, actual); + } +} + +TEST_F(APZCArePointerEventsConsumable, DynamicToolbar) { + CreateSingleElementTree(); + + RefPtr<TestAsyncPanZoomController> apzc = ApzcOf(root); + RefPtr<TouchBlockState> blockState = CreateTouchBlockStateForApzc(apzc); + + // Create touch with vertical 20 unit scroll + MultiTouchInput touchStart = + CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_START, mcc->Time()); + touchStart.mTouches.AppendElement( + SingleTouchData(0, ScreenIntPoint(60, 30), ScreenSize(0, 0), 0, 0)); + + MultiTouchInput touchMove = + CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, mcc->Time()); + touchMove.mTouches.AppendElement( + SingleTouchData(0, ScreenIntPoint(60, 40), ScreenSize(0, 0), 0, 0)); + + blockState->UpdateSlopState(touchStart, false); + + // Restrict size of scrollable area: No room to pan X, no room to pan Y + apzc->GetFrameMetrics().SetScrollableRect(CSSRect{0, 0, 100, 100}); + + PointerEventsConsumableFlags actual{}; + PointerEventsConsumableFlags expected{}; + + expected = {false, true}; + actual = apzc->ArePointerEventsConsumable(blockState, touchMove); + EXPECT_EQ(expected, actual); + + apzc->GetFrameMetrics().SetCompositionSizeWithoutDynamicToolbar( + ParentLayerSize{100, 90}); + UpdateHitTestingTree(); + + expected = {true, true}; + actual = apzc->ArePointerEventsConsumable(blockState, touchMove); + EXPECT_EQ(expected, actual); +} |