TestEventRegions.cpp (8269B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "APZCTreeManagerTester.h" 8 #include "APZTestCommon.h" 9 #include "InputUtils.h" 10 #include "mozilla/layers/LayersTypes.h" 11 12 class APZEventRegionsTester : public APZCTreeManagerTester { 13 protected: 14 UniquePtr<ScopedLayerTreeRegistration> registration; 15 TestAsyncPanZoomController* rootApzc; 16 17 void CreateEventRegionsLayerTree1() { 18 const char* treeShape = "x(xx)"; 19 LayerIntRect layerVisibleRects[] = { 20 LayerIntRect(0, 0, 200, 200), // root 21 LayerIntRect(0, 0, 100, 200), // left half 22 LayerIntRect(0, 100, 200, 100), // bottom half 23 }; 24 CreateScrollData(treeShape, layerVisibleRects); 25 SetScrollableFrameMetrics(root, ScrollableLayerGuid::START_SCROLL_ID); 26 SetScrollableFrameMetrics(layers[1], 27 ScrollableLayerGuid::START_SCROLL_ID + 1); 28 SetScrollableFrameMetrics(layers[2], 29 ScrollableLayerGuid::START_SCROLL_ID + 2); 30 SetScrollHandoff(layers[1], root); 31 SetScrollHandoff(layers[2], root); 32 33 registration = MakeUnique<ScopedLayerTreeRegistration>(LayersId{0}, mcc); 34 UpdateHitTestingTree(); 35 rootApzc = ApzcOf(root); 36 } 37 38 void CreateEventRegionsLayerTree2() { 39 const char* treeShape = "x(x)"; 40 LayerIntRect layerVisibleRects[] = { 41 LayerIntRect(0, 0, 100, 500), 42 LayerIntRect(0, 150, 100, 100), 43 }; 44 CreateScrollData(treeShape, layerVisibleRects); 45 SetScrollableFrameMetrics(root, ScrollableLayerGuid::START_SCROLL_ID); 46 47 registration = MakeUnique<ScopedLayerTreeRegistration>(LayersId{0}, mcc); 48 UpdateHitTestingTree(); 49 rootApzc = ApzcOf(root); 50 } 51 52 void CreateBug1117712LayerTree() { 53 const char* treeShape = "x(x(x)x)"; 54 // LayerID 0 1 2 3 55 // 0 is the root 56 // 1 is a container layer whose sole purpose to make a non-empty ancestor 57 // transform for 2, so that 2's screen-to-apzc and apzc-to-gecko 58 // transforms are different from 3's. 59 // 2 is a small layer that is the actual target 60 // 3 is a big layer obscuring 2 with a dispatch-to-content region 61 LayerIntRect layerVisibleRects[] = { 62 LayerIntRect(0, 0, 100, 100), 63 LayerIntRect(0, 0, 0, 0), 64 LayerIntRect(0, 0, 10, 10), 65 LayerIntRect(0, 0, 100, 100), 66 }; 67 Matrix4x4 layerTransforms[] = { 68 Matrix4x4(), 69 Matrix4x4::Translation(50, 0, 0), 70 Matrix4x4(), 71 Matrix4x4(), 72 }; 73 CreateScrollData(treeShape, layerVisibleRects, layerTransforms); 74 75 SetScrollableFrameMetrics(layers[2], ScrollableLayerGuid::START_SCROLL_ID, 76 CSSRect(0, 0, 10, 10)); 77 SetScrollableFrameMetrics(layers[3], 78 ScrollableLayerGuid::START_SCROLL_ID + 1, 79 CSSRect(0, 0, 100, 100)); 80 SetScrollHandoff(layers[3], layers[2]); 81 82 registration = MakeUnique<ScopedLayerTreeRegistration>(LayersId{0}, mcc); 83 UpdateHitTestingTree(); 84 } 85 }; 86 87 class APZEventRegionsTesterMock : public APZEventRegionsTester { 88 public: 89 APZEventRegionsTesterMock() { CreateMockHitTester(); } 90 }; 91 92 TEST_F(APZEventRegionsTesterMock, HitRegionImmediateResponse) { 93 CreateEventRegionsLayerTree1(); 94 95 TestAsyncPanZoomController* root = ApzcOf(layers[0]); 96 TestAsyncPanZoomController* left = ApzcOf(layers[1]); 97 TestAsyncPanZoomController* bottom = ApzcOf(layers[2]); 98 99 MockFunction<void(std::string checkPointName)> check; 100 { 101 InSequence s; 102 EXPECT_CALL(*mcc, 103 HandleTap(TapType::eSingleTap, _, _, left->GetGuid(), _, _)) 104 .Times(1); 105 EXPECT_CALL(check, Call("Tapped on left")); 106 EXPECT_CALL(*mcc, 107 HandleTap(TapType::eSingleTap, _, _, bottom->GetGuid(), _, _)) 108 .Times(1); 109 EXPECT_CALL(check, Call("Tapped on bottom")); 110 EXPECT_CALL(*mcc, 111 HandleTap(TapType::eSingleTap, _, _, root->GetGuid(), _, _)) 112 .Times(1); 113 EXPECT_CALL(check, Call("Tapped on root")); 114 EXPECT_CALL(check, Call("Tap pending on d-t-c region")); 115 EXPECT_CALL(*mcc, 116 HandleTap(TapType::eSingleTap, _, _, bottom->GetGuid(), _, _)) 117 .Times(1); 118 EXPECT_CALL(check, Call("Tapped on bottom again")); 119 EXPECT_CALL(*mcc, 120 HandleTap(TapType::eSingleTap, _, _, left->GetGuid(), _, _)) 121 .Times(1); 122 EXPECT_CALL(check, Call("Tapped on left this time")); 123 } 124 125 TimeDuration tapDuration = TimeDuration::FromMilliseconds(100); 126 127 // Tap in the exposed hit regions of each of the layers once and ensure 128 // the clicks are dispatched right away 129 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1); 130 Tap(manager, ScreenIntPoint(10, 10), tapDuration); 131 mcc->RunThroughDelayedTasks(); // this runs the tap event 132 check.Call("Tapped on left"); 133 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 2); 134 Tap(manager, ScreenIntPoint(110, 110), tapDuration); 135 mcc->RunThroughDelayedTasks(); // this runs the tap event 136 check.Call("Tapped on bottom"); 137 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); 138 Tap(manager, ScreenIntPoint(110, 10), tapDuration); 139 mcc->RunThroughDelayedTasks(); // this runs the tap event 140 check.Call("Tapped on root"); 141 142 // Now tap on the dispatch-to-content region where the layers overlap 143 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 2, 144 {CompositorHitTestFlags::eVisibleToHitTest, 145 CompositorHitTestFlags::eIrregularArea}); 146 Tap(manager, ScreenIntPoint(10, 110), tapDuration); 147 mcc->RunThroughDelayedTasks(); // this runs the main-thread timeout 148 check.Call("Tap pending on d-t-c region"); 149 mcc->RunThroughDelayedTasks(); // this runs the tap event 150 check.Call("Tapped on bottom again"); 151 152 // Now let's do that again, but simulate a main-thread response 153 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 2, 154 {CompositorHitTestFlags::eVisibleToHitTest, 155 CompositorHitTestFlags::eIrregularArea}); 156 APZEventResult result = 157 Tap(manager, ScreenIntPoint(10, 110), tapDuration, nullptr); 158 nsTArray<ScrollableLayerGuid> targets; 159 targets.AppendElement(left->GetGuid()); 160 manager->SetTargetAPZC(result.mInputBlockId, targets); 161 while (mcc->RunThroughDelayedTasks()); // this runs the tap event 162 check.Call("Tapped on left this time"); 163 } 164 165 TEST_F(APZEventRegionsTesterMock, HitRegionAccumulatesChildren) { 166 CreateEventRegionsLayerTree2(); 167 168 // Tap in the area of the child layer that's not directly included in the 169 // parent layer's hit region. Verify that it comes out of the APZC's 170 // content controller, which indicates the input events got routed correctly 171 // to the APZC. 172 EXPECT_CALL(*mcc, 173 HandleTap(TapType::eSingleTap, _, _, rootApzc->GetGuid(), _, _)) 174 .Times(1); 175 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); 176 Tap(manager, ScreenIntPoint(10, 160), TimeDuration::FromMilliseconds(100)); 177 } 178 179 TEST_F(APZEventRegionsTesterMock, Bug1117712) { 180 CreateBug1117712LayerTree(); 181 182 TestAsyncPanZoomController* apzc2 = ApzcOf(layers[2]); 183 184 // These touch events should hit the dispatch-to-content region of layers[3] 185 // and so get queued with that APZC as the tentative target. 186 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1, 187 {CompositorHitTestFlags::eVisibleToHitTest, 188 CompositorHitTestFlags::eIrregularArea}); 189 APZEventResult result = Tap(manager, ScreenIntPoint(55, 5), 190 TimeDuration::FromMilliseconds(100), nullptr); 191 // But now we tell the APZ that really it hit layers[2], and expect the tap 192 // to be delivered at the correct coordinates. 193 EXPECT_CALL(*mcc, HandleTap(TapType::eSingleTap, LayoutDevicePoint(55, 5), 0, 194 apzc2->GetGuid(), _, _)) 195 .Times(1); 196 197 nsTArray<ScrollableLayerGuid> targets; 198 targets.AppendElement(apzc2->GetGuid()); 199 manager->SetTargetAPZC(result.mInputBlockId, targets); 200 }