diff options
Diffstat (limited to '')
-rw-r--r-- | gfx/layers/apz/test/gtest/TestEventRegions.cpp | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/gfx/layers/apz/test/gtest/TestEventRegions.cpp b/gfx/layers/apz/test/gtest/TestEventRegions.cpp new file mode 100644 index 0000000000..0b4564b49f --- /dev/null +++ b/gfx/layers/apz/test/gtest/TestEventRegions.cpp @@ -0,0 +1,199 @@ +/* -*- 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 "mozilla/layers/LayersTypes.h" + +class APZEventRegionsTester : public APZCTreeManagerTester { + protected: + UniquePtr<ScopedLayerTreeRegistration> registration; + TestAsyncPanZoomController* rootApzc; + + void CreateEventRegionsLayerTree1() { + const char* treeShape = "x(xx)"; + LayerIntRegion layerVisibleRegions[] = { + LayerIntRect(0, 0, 200, 200), // root + LayerIntRect(0, 0, 100, 200), // left half + LayerIntRect(0, 100, 200, 100), // bottom half + }; + CreateScrollData(treeShape, layerVisibleRegions); + SetScrollableFrameMetrics(root, ScrollableLayerGuid::START_SCROLL_ID); + SetScrollableFrameMetrics(layers[1], + ScrollableLayerGuid::START_SCROLL_ID + 1); + SetScrollableFrameMetrics(layers[2], + ScrollableLayerGuid::START_SCROLL_ID + 2); + SetScrollHandoff(layers[1], root); + SetScrollHandoff(layers[2], root); + + registration = MakeUnique<ScopedLayerTreeRegistration>(LayersId{0}, mcc); + UpdateHitTestingTree(); + rootApzc = ApzcOf(root); + } + + void CreateEventRegionsLayerTree2() { + const char* treeShape = "x(x)"; + LayerIntRegion layerVisibleRegions[] = { + LayerIntRect(0, 0, 100, 500), + LayerIntRect(0, 150, 100, 100), + }; + CreateScrollData(treeShape, layerVisibleRegions); + SetScrollableFrameMetrics(root, ScrollableLayerGuid::START_SCROLL_ID); + + registration = MakeUnique<ScopedLayerTreeRegistration>(LayersId{0}, mcc); + UpdateHitTestingTree(); + rootApzc = ApzcOf(root); + } + + void CreateBug1117712LayerTree() { + const char* treeShape = "x(x(x)x)"; + // LayerID 0 1 2 3 + // 0 is the root + // 1 is a container layer whose sole purpose to make a non-empty ancestor + // transform for 2, so that 2's screen-to-apzc and apzc-to-gecko + // transforms are different from 3's. + // 2 is a small layer that is the actual target + // 3 is a big layer obscuring 2 with a dispatch-to-content region + LayerIntRegion layerVisibleRegions[] = { + LayerIntRect(0, 0, 100, 100), + LayerIntRect(0, 0, 0, 0), + LayerIntRect(0, 0, 10, 10), + LayerIntRect(0, 0, 100, 100), + }; + Matrix4x4 layerTransforms[] = { + Matrix4x4(), + Matrix4x4::Translation(50, 0, 0), + Matrix4x4(), + Matrix4x4(), + }; + CreateScrollData(treeShape, layerVisibleRegions, layerTransforms); + + SetScrollableFrameMetrics(layers[2], ScrollableLayerGuid::START_SCROLL_ID, + CSSRect(0, 0, 10, 10)); + SetScrollableFrameMetrics(layers[3], + ScrollableLayerGuid::START_SCROLL_ID + 1, + CSSRect(0, 0, 100, 100)); + SetScrollHandoff(layers[3], layers[2]); + + registration = MakeUnique<ScopedLayerTreeRegistration>(LayersId{0}, mcc); + UpdateHitTestingTree(); + } +}; + +class APZEventRegionsTesterMock : public APZEventRegionsTester { + public: + APZEventRegionsTesterMock() { CreateMockHitTester(); } +}; + +TEST_F(APZEventRegionsTesterMock, HitRegionImmediateResponse) { + CreateEventRegionsLayerTree1(); + + TestAsyncPanZoomController* root = ApzcOf(layers[0]); + TestAsyncPanZoomController* left = ApzcOf(layers[1]); + TestAsyncPanZoomController* bottom = ApzcOf(layers[2]); + + MockFunction<void(std::string checkPointName)> check; + { + InSequence s; + EXPECT_CALL(*mcc, HandleTap(TapType::eSingleTap, _, _, left->GetGuid(), _)) + .Times(1); + EXPECT_CALL(check, Call("Tapped on left")); + EXPECT_CALL(*mcc, + HandleTap(TapType::eSingleTap, _, _, bottom->GetGuid(), _)) + .Times(1); + EXPECT_CALL(check, Call("Tapped on bottom")); + EXPECT_CALL(*mcc, HandleTap(TapType::eSingleTap, _, _, root->GetGuid(), _)) + .Times(1); + EXPECT_CALL(check, Call("Tapped on root")); + EXPECT_CALL(check, Call("Tap pending on d-t-c region")); + EXPECT_CALL(*mcc, + HandleTap(TapType::eSingleTap, _, _, bottom->GetGuid(), _)) + .Times(1); + EXPECT_CALL(check, Call("Tapped on bottom again")); + EXPECT_CALL(*mcc, HandleTap(TapType::eSingleTap, _, _, left->GetGuid(), _)) + .Times(1); + EXPECT_CALL(check, Call("Tapped on left this time")); + } + + TimeDuration tapDuration = TimeDuration::FromMilliseconds(100); + + // Tap in the exposed hit regions of each of the layers once and ensure + // the clicks are dispatched right away + QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1); + Tap(manager, ScreenIntPoint(10, 10), tapDuration); + mcc->RunThroughDelayedTasks(); // this runs the tap event + check.Call("Tapped on left"); + QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 2); + Tap(manager, ScreenIntPoint(110, 110), tapDuration); + mcc->RunThroughDelayedTasks(); // this runs the tap event + check.Call("Tapped on bottom"); + QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); + Tap(manager, ScreenIntPoint(110, 10), tapDuration); + mcc->RunThroughDelayedTasks(); // this runs the tap event + check.Call("Tapped on root"); + + // Now tap on the dispatch-to-content region where the layers overlap + QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 2, + {CompositorHitTestFlags::eVisibleToHitTest, + CompositorHitTestFlags::eIrregularArea}); + Tap(manager, ScreenIntPoint(10, 110), tapDuration); + mcc->RunThroughDelayedTasks(); // this runs the main-thread timeout + check.Call("Tap pending on d-t-c region"); + mcc->RunThroughDelayedTasks(); // this runs the tap event + check.Call("Tapped on bottom again"); + + // Now let's do that again, but simulate a main-thread response + uint64_t inputBlockId = 0; + QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 2, + {CompositorHitTestFlags::eVisibleToHitTest, + CompositorHitTestFlags::eIrregularArea}); + Tap(manager, ScreenIntPoint(10, 110), tapDuration, nullptr, &inputBlockId); + nsTArray<ScrollableLayerGuid> targets; + targets.AppendElement(left->GetGuid()); + manager->SetTargetAPZC(inputBlockId, targets); + while (mcc->RunThroughDelayedTasks()) + ; // this runs the tap event + check.Call("Tapped on left this time"); +} + +TEST_F(APZEventRegionsTesterMock, HitRegionAccumulatesChildren) { + CreateEventRegionsLayerTree2(); + + // Tap in the area of the child layer that's not directly included in the + // parent layer's hit region. Verify that it comes out of the APZC's + // content controller, which indicates the input events got routed correctly + // to the APZC. + EXPECT_CALL(*mcc, + HandleTap(TapType::eSingleTap, _, _, rootApzc->GetGuid(), _)) + .Times(1); + QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); + Tap(manager, ScreenIntPoint(10, 160), TimeDuration::FromMilliseconds(100)); +} + +TEST_F(APZEventRegionsTesterMock, Bug1117712) { + CreateBug1117712LayerTree(); + + TestAsyncPanZoomController* apzc2 = ApzcOf(layers[2]); + + // These touch events should hit the dispatch-to-content region of layers[3] + // and so get queued with that APZC as the tentative target. + uint64_t inputBlockId = 0; + QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1, + {CompositorHitTestFlags::eVisibleToHitTest, + CompositorHitTestFlags::eIrregularArea}); + Tap(manager, ScreenIntPoint(55, 5), TimeDuration::FromMilliseconds(100), + nullptr, &inputBlockId); + // But now we tell the APZ that really it hit layers[2], and expect the tap + // to be delivered at the correct coordinates. + EXPECT_CALL(*mcc, HandleTap(TapType::eSingleTap, LayoutDevicePoint(55, 5), 0, + apzc2->GetGuid(), _)) + .Times(1); + + nsTArray<ScrollableLayerGuid> targets; + targets.AppendElement(apzc2->GetGuid()); + manager->SetTargetAPZC(inputBlockId, targets); +} |