TestPointerEventsConsumable.cpp (18794B)
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 "gtest/gtest.h" 8 9 #include "APZCTreeManagerTester.h" 10 #include "APZTestCommon.h" 11 #include "InputUtils.h" 12 #include "apz/src/AsyncPanZoomController.h" 13 #include "apz/src/InputBlockState.h" 14 #include "apz/src/OverscrollHandoffState.h" 15 #include "mozilla/layers/IAPZCTreeManager.h" 16 17 class APZCArePointerEventsConsumable : public APZCTreeManagerTester { 18 public: 19 APZCArePointerEventsConsumable() { CreateMockHitTester(); } 20 21 void CreateSingleElementTree() { 22 const char* treeShape = "x"; 23 LayerIntRect layerVisibleRect[] = { 24 LayerIntRect(0, 0, 100, 100), 25 }; 26 CreateScrollData(treeShape, layerVisibleRect); 27 SetScrollableFrameMetrics(root, ScrollableLayerGuid::START_SCROLL_ID, 28 CSSRect(0, 0, 500, 500)); 29 30 registration = MakeUnique<ScopedLayerTreeRegistration>(LayersId{0}, mcc); 31 32 UpdateHitTestingTree(); 33 34 ApzcOf(root)->GetFrameMetrics().SetIsRootContent(true); 35 } 36 37 void CreateScrollHandoffTree() { 38 const char* treeShape = "x(x)"; 39 LayerIntRect layerVisibleRect[] = {LayerIntRect(0, 0, 200, 200), 40 LayerIntRect(50, 50, 100, 100)}; 41 CreateScrollData(treeShape, layerVisibleRect); 42 SetScrollableFrameMetrics(root, ScrollableLayerGuid::START_SCROLL_ID, 43 CSSRect(0, 0, 300, 300)); 44 SetScrollableFrameMetrics(layers[1], 45 ScrollableLayerGuid::START_SCROLL_ID + 1, 46 CSSRect(0, 0, 200, 200)); 47 SetScrollHandoff(layers[1], root); 48 registration = MakeUnique<ScopedLayerTreeRegistration>(LayersId{0}, mcc); 49 UpdateHitTestingTree(); 50 51 ApzcOf(root)->GetFrameMetrics().SetIsRootContent(true); 52 } 53 54 RefPtr<TouchBlockState> CreateTouchBlockStateForApzc( 55 const RefPtr<TestAsyncPanZoomController>& aApzc) { 56 TouchCounter counter{}; 57 TargetConfirmationFlags flags{true}; 58 59 return new TouchBlockState(aApzc, flags, counter); 60 } 61 62 void UpdateOverscrollBehavior(ScrollableLayerGuid::ViewID aScrollId, 63 OverscrollBehavior aX, OverscrollBehavior aY) { 64 auto* layer = layers[aScrollId - ScrollableLayerGuid::START_SCROLL_ID]; 65 ModifyFrameMetrics(layer, [aX, aY](ScrollMetadata& sm, FrameMetrics& _) { 66 OverscrollBehaviorInfo overscroll; 67 overscroll.mBehaviorX = aX; 68 overscroll.mBehaviorY = aY; 69 sm.SetOverscrollBehavior(overscroll); 70 }); 71 UpdateHitTestingTree(); 72 } 73 74 UniquePtr<ScopedLayerTreeRegistration> registration; 75 }; 76 77 TEST_F(APZCArePointerEventsConsumable, EmptyInput) { 78 CreateSingleElementTree(); 79 80 RefPtr<TestAsyncPanZoomController> apzc = ApzcOf(root); 81 RefPtr<TouchBlockState> blockState = CreateTouchBlockStateForApzc(apzc); 82 83 MultiTouchInput touchInput = 84 CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_START, mcc->Time()); 85 86 const PointerEventsConsumableFlags expected{false, false}; 87 const PointerEventsConsumableFlags actual = 88 apzc->ArePointerEventsConsumable(blockState, touchInput); 89 EXPECT_EQ(expected, actual); 90 } 91 92 TEST_F(APZCArePointerEventsConsumable, ScrollHorizontally) { 93 CreateSingleElementTree(); 94 95 RefPtr<TestAsyncPanZoomController> apzc = ApzcOf(root); 96 RefPtr<TouchBlockState> blockState = CreateTouchBlockStateForApzc(apzc); 97 98 // Create touch with horizontal 20 unit scroll 99 MultiTouchInput touchStart = 100 CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_START, mcc->Time()); 101 touchStart.mTouches.AppendElement( 102 SingleTouchData(0, ScreenIntPoint(10, 10), ScreenSize(0, 0), 0, 0)); 103 104 MultiTouchInput touchMove = 105 CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, mcc->Time()); 106 touchMove.mTouches.AppendElement( 107 SingleTouchData(0, ScreenIntPoint(30, 10), ScreenSize(0, 0), 0, 0)); 108 109 blockState->UpdateSlopState(touchStart, false); 110 111 PointerEventsConsumableFlags actual{}; 112 PointerEventsConsumableFlags expected{}; 113 114 // Scroll area 500x500, room to pan x, room to pan y 115 expected = {true, true}; 116 actual = apzc->ArePointerEventsConsumable(blockState, touchMove); 117 EXPECT_EQ(expected, actual); 118 119 // Scroll area 100x100, no room to pan x, no room to pan y 120 apzc->GetFrameMetrics().SetScrollableRect(CSSRect{0, 0, 100, 100}); 121 expected = {false, true}; 122 actual = apzc->ArePointerEventsConsumable(blockState, touchMove); 123 EXPECT_EQ(expected, actual); 124 125 // Scroll area 500x100, room to pan x, no room to pan y 126 apzc->GetFrameMetrics().SetScrollableRect(CSSRect{0, 0, 500, 100}); 127 expected = {true, true}; 128 actual = apzc->ArePointerEventsConsumable(blockState, touchMove); 129 EXPECT_EQ(expected, actual); 130 131 // Scroll area 100x500, no room to pan x, room to pan y 132 apzc->GetFrameMetrics().SetScrollableRect(CSSRect{0, 0, 100, 500}); 133 expected = {false, true}; 134 actual = apzc->ArePointerEventsConsumable(blockState, touchMove); 135 EXPECT_EQ(expected, actual); 136 } 137 138 TEST_F(APZCArePointerEventsConsumable, ScrollVertically) { 139 CreateSingleElementTree(); 140 141 RefPtr<TestAsyncPanZoomController> apzc = ApzcOf(root); 142 RefPtr<TouchBlockState> blockState = CreateTouchBlockStateForApzc(apzc); 143 144 // Create touch with vertical 20 unit scroll 145 MultiTouchInput touchStart = 146 CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_START, mcc->Time()); 147 touchStart.mTouches.AppendElement( 148 SingleTouchData(0, ScreenIntPoint(10, 10), ScreenSize(0, 0), 0, 0)); 149 150 MultiTouchInput touchMove = 151 CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, mcc->Time()); 152 touchMove.mTouches.AppendElement( 153 SingleTouchData(0, ScreenIntPoint(10, 30), ScreenSize(0, 0), 0, 0)); 154 155 blockState->UpdateSlopState(touchStart, false); 156 157 PointerEventsConsumableFlags actual{}; 158 PointerEventsConsumableFlags expected{}; 159 160 // Scroll area 500x500, room to pan x, room to pan y 161 expected = {true, true}; 162 actual = apzc->ArePointerEventsConsumable(blockState, touchMove); 163 EXPECT_EQ(expected, actual); 164 165 // Scroll area 100x100, no room to pan x, no room to pan y 166 apzc->GetFrameMetrics().SetScrollableRect(CSSRect{0, 0, 100, 100}); 167 expected = {false, true}; 168 actual = apzc->ArePointerEventsConsumable(blockState, touchMove); 169 EXPECT_EQ(expected, actual); 170 171 // Scroll area 500x100, room to pan x, no room to pan y 172 apzc->GetFrameMetrics().SetScrollableRect(CSSRect{0, 0, 500, 100}); 173 expected = {false, true}; 174 actual = apzc->ArePointerEventsConsumable(blockState, touchMove); 175 EXPECT_EQ(expected, actual); 176 177 // Scroll area 100x500, no room to pan x, room to pan y 178 apzc->GetFrameMetrics().SetScrollableRect(CSSRect{0, 0, 100, 500}); 179 expected = {true, true}; 180 actual = apzc->ArePointerEventsConsumable(blockState, touchMove); 181 EXPECT_EQ(expected, actual); 182 } 183 184 TEST_F(APZCArePointerEventsConsumable, NestedElementCanScroll) { 185 CreateScrollHandoffTree(); 186 187 RefPtr<TestAsyncPanZoomController> apzc = ApzcOf(layers[1]); 188 RefPtr<TouchBlockState> blockState = CreateTouchBlockStateForApzc(apzc); 189 190 // Create touch with vertical 20 unit scroll 191 MultiTouchInput touchStart = 192 CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_START, mcc->Time()); 193 touchStart.mTouches.AppendElement( 194 SingleTouchData(0, ScreenIntPoint(60, 60), ScreenSize(0, 0), 0, 0)); 195 196 MultiTouchInput touchMove = 197 CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, mcc->Time()); 198 touchMove.mTouches.AppendElement( 199 SingleTouchData(0, ScreenIntPoint(60, 80), ScreenSize(0, 0), 0, 0)); 200 201 blockState->UpdateSlopState(touchStart, false); 202 203 const PointerEventsConsumableFlags expected{true, true}; 204 const PointerEventsConsumableFlags actual = 205 apzc->ArePointerEventsConsumable(blockState, touchMove); 206 EXPECT_EQ(expected, actual); 207 } 208 209 TEST_F(APZCArePointerEventsConsumable, NestedElementCannotScroll) { 210 CreateScrollHandoffTree(); 211 212 RefPtr<TestAsyncPanZoomController> apzc = ApzcOf(layers[1]); 213 RefPtr<TouchBlockState> blockState = CreateTouchBlockStateForApzc(apzc); 214 215 // Create touch with vertical 20 unit scroll 216 MultiTouchInput touchStart = 217 CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_START, mcc->Time()); 218 touchStart.mTouches.AppendElement( 219 SingleTouchData(0, ScreenIntPoint(60, 60), ScreenSize(0, 0), 0, 0)); 220 221 MultiTouchInput touchMove = 222 CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, mcc->Time()); 223 touchMove.mTouches.AppendElement( 224 SingleTouchData(0, ScreenIntPoint(60, 80), ScreenSize(0, 0), 0, 0)); 225 226 blockState->UpdateSlopState(touchStart, false); 227 228 PointerEventsConsumableFlags actual{}; 229 PointerEventsConsumableFlags expected{}; 230 231 // Set the nested element to have no room to scroll. 232 // Because of the overscroll handoff, we still have room to scroll 233 // in the parent element. 234 apzc->GetFrameMetrics().SetScrollableRect(CSSRect{0, 0, 100, 100}); 235 expected = {true, true}; 236 actual = apzc->ArePointerEventsConsumable(blockState, touchMove); 237 EXPECT_EQ(expected, actual); 238 239 // Set overscroll handoff for the nested element to none. 240 // Because no handoff will happen, we are not able to use the parent's 241 // room to scroll. 242 // Bug 1814886: Once fixed, change expected value to {false, true}. 243 UpdateOverscrollBehavior(ScrollableLayerGuid::START_SCROLL_ID + 1, 244 OverscrollBehavior::None, OverscrollBehavior::None); 245 expected = {true, true}; 246 actual = apzc->ArePointerEventsConsumable(blockState, touchMove); 247 EXPECT_EQ(expected, actual); 248 } 249 250 TEST_F(APZCArePointerEventsConsumable, NotScrollableButZoomable) { 251 CreateSingleElementTree(); 252 253 RefPtr<TestAsyncPanZoomController> apzc = ApzcOf(root); 254 RefPtr<TouchBlockState> blockState = CreateTouchBlockStateForApzc(apzc); 255 256 // Create touch with vertical 20 unit scroll 257 MultiTouchInput touchStart = 258 CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_START, mcc->Time()); 259 touchStart.mTouches.AppendElement( 260 SingleTouchData(0, ScreenIntPoint(60, 60), ScreenSize(0, 0), 0, 0)); 261 262 MultiTouchInput touchMove = 263 CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, mcc->Time()); 264 touchMove.mTouches.AppendElement( 265 SingleTouchData(0, ScreenIntPoint(60, 80), ScreenSize(0, 0), 0, 0)); 266 267 blockState->UpdateSlopState(touchStart, false); 268 269 // Make the root have no room to scroll 270 apzc->GetFrameMetrics().SetScrollableRect(CSSRect{0, 0, 100, 100}); 271 272 // Make zoomable 273 apzc->UpdateZoomConstraints(ZoomConstraints( 274 true, true, CSSToParentLayerScale(0.25f), CSSToParentLayerScale(4.0f))); 275 276 PointerEventsConsumableFlags actual{}; 277 PointerEventsConsumableFlags expected{}; 278 279 expected = {false, true}; 280 actual = apzc->ArePointerEventsConsumable(blockState, touchMove); 281 EXPECT_EQ(expected, actual); 282 283 // Add a second touch point and therefore make the APZC consider 284 // zoom use cases as well. 285 touchMove.mTouches.AppendElement( 286 SingleTouchData(0, ScreenIntPoint(60, 90), ScreenSize(0, 0), 0, 0)); 287 288 expected = {true, true}; 289 actual = apzc->ArePointerEventsConsumable(blockState, touchMove); 290 EXPECT_EQ(expected, actual); 291 } 292 293 TEST_F(APZCArePointerEventsConsumable, TouchActionsProhibitAll) { 294 CreateSingleElementTree(); 295 296 RefPtr<TestAsyncPanZoomController> apzc = ApzcOf(root); 297 298 // Create touch with vertical 20 unit scroll 299 MultiTouchInput touchStart = 300 CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_START, mcc->Time()); 301 touchStart.mTouches.AppendElement( 302 SingleTouchData(0, ScreenIntPoint(60, 60), ScreenSize(0, 0), 0, 0)); 303 304 MultiTouchInput touchMove = 305 CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, mcc->Time()); 306 touchMove.mTouches.AppendElement( 307 SingleTouchData(0, ScreenIntPoint(60, 80), ScreenSize(0, 0), 0, 0)); 308 309 PointerEventsConsumableFlags expected{}; 310 PointerEventsConsumableFlags actual{}; 311 312 { 313 RefPtr<TouchBlockState> blockState = CreateTouchBlockStateForApzc(apzc); 314 blockState->UpdateSlopState(touchStart, false); 315 316 blockState->SetAllowedTouchBehaviors({AllowedTouchBehavior::NONE}); 317 expected = {true, false}; 318 actual = apzc->ArePointerEventsConsumable(blockState, touchMove); 319 EXPECT_EQ(expected, actual); 320 } 321 322 // Convert touch input to two-finger pinch 323 touchStart.mTouches.AppendElement( 324 SingleTouchData(1, ScreenIntPoint(80, 80), ScreenSize(0, 0), 0, 0)); 325 touchMove.mTouches.AppendElement( 326 SingleTouchData(1, ScreenIntPoint(90, 90), ScreenSize(0, 0), 0, 0)); 327 328 { 329 RefPtr<TouchBlockState> blockState = CreateTouchBlockStateForApzc(apzc); 330 blockState->UpdateSlopState(touchStart, false); 331 332 blockState->SetAllowedTouchBehaviors({AllowedTouchBehavior::NONE}); 333 expected = {true, false}; 334 actual = apzc->ArePointerEventsConsumable(blockState, touchMove); 335 EXPECT_EQ(expected, actual); 336 } 337 } 338 339 TEST_F(APZCArePointerEventsConsumable, TouchActionsAllowVerticalScrolling) { 340 CreateSingleElementTree(); 341 342 RefPtr<TestAsyncPanZoomController> apzc = ApzcOf(root); 343 344 // Create touch with vertical 20 unit scroll 345 MultiTouchInput touchStart = 346 CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_START, mcc->Time()); 347 touchStart.mTouches.AppendElement( 348 SingleTouchData(0, ScreenIntPoint(60, 60), ScreenSize(0, 0), 0, 0)); 349 350 MultiTouchInput touchMove = 351 CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, mcc->Time()); 352 touchMove.mTouches.AppendElement( 353 SingleTouchData(0, ScreenIntPoint(60, 80), ScreenSize(0, 0), 0, 0)); 354 355 PointerEventsConsumableFlags expected{}; 356 PointerEventsConsumableFlags actual{}; 357 358 { 359 RefPtr<TouchBlockState> blockState = CreateTouchBlockStateForApzc(apzc); 360 blockState->UpdateSlopState(touchStart, false); 361 362 blockState->SetAllowedTouchBehaviors({AllowedTouchBehavior::NONE}); 363 expected = {true, false}; 364 actual = apzc->ArePointerEventsConsumable(blockState, touchMove); 365 EXPECT_EQ(expected, actual); 366 } 367 368 { 369 RefPtr<TouchBlockState> blockState = CreateTouchBlockStateForApzc(apzc); 370 blockState->UpdateSlopState(touchStart, false); 371 372 blockState->SetAllowedTouchBehaviors({AllowedTouchBehavior::VERTICAL_PAN}); 373 expected = {true, true}; 374 actual = apzc->ArePointerEventsConsumable(blockState, touchMove); 375 EXPECT_EQ(expected, actual); 376 } 377 } 378 379 TEST_F(APZCArePointerEventsConsumable, TouchActionsAllowHorizontalScrolling) { 380 CreateSingleElementTree(); 381 382 RefPtr<TestAsyncPanZoomController> apzc = ApzcOf(root); 383 384 // Create touch with horizontal 20 unit scroll 385 MultiTouchInput touchStart = 386 CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_START, mcc->Time()); 387 touchStart.mTouches.AppendElement( 388 SingleTouchData(0, ScreenIntPoint(60, 60), ScreenSize(0, 0), 0, 0)); 389 390 MultiTouchInput touchMove = 391 CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, mcc->Time()); 392 touchMove.mTouches.AppendElement( 393 SingleTouchData(0, ScreenIntPoint(80, 60), ScreenSize(0, 0), 0, 0)); 394 395 PointerEventsConsumableFlags expected{}; 396 PointerEventsConsumableFlags actual{}; 397 398 { 399 RefPtr<TouchBlockState> blockState = CreateTouchBlockStateForApzc(apzc); 400 blockState->UpdateSlopState(touchStart, false); 401 402 blockState->SetAllowedTouchBehaviors({AllowedTouchBehavior::NONE}); 403 expected = {true, false}; 404 actual = apzc->ArePointerEventsConsumable(blockState, touchMove); 405 EXPECT_EQ(expected, actual); 406 } 407 408 { 409 RefPtr<TouchBlockState> blockState = CreateTouchBlockStateForApzc(apzc); 410 blockState->UpdateSlopState(touchStart, false); 411 412 blockState->SetAllowedTouchBehaviors( 413 {AllowedTouchBehavior::HORIZONTAL_PAN}); 414 expected = {true, true}; 415 actual = apzc->ArePointerEventsConsumable(blockState, touchMove); 416 EXPECT_EQ(expected, actual); 417 } 418 } 419 420 TEST_F(APZCArePointerEventsConsumable, TouchActionsAllowPinchZoom) { 421 CreateSingleElementTree(); 422 423 RefPtr<TestAsyncPanZoomController> apzc = ApzcOf(root); 424 425 // Create two-finger pinch 426 MultiTouchInput touchStart = 427 CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_START, mcc->Time()); 428 touchStart.mTouches.AppendElement( 429 SingleTouchData(0, ScreenIntPoint(60, 60), ScreenSize(0, 0), 0, 0)); 430 touchStart.mTouches.AppendElement( 431 SingleTouchData(1, ScreenIntPoint(80, 80), ScreenSize(0, 0), 0, 0)); 432 433 MultiTouchInput touchMove = 434 CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, mcc->Time()); 435 touchMove.mTouches.AppendElement( 436 SingleTouchData(0, ScreenIntPoint(50, 50), ScreenSize(0, 0), 0, 0)); 437 touchMove.mTouches.AppendElement( 438 SingleTouchData(1, ScreenIntPoint(90, 90), ScreenSize(0, 0), 0, 0)); 439 440 PointerEventsConsumableFlags expected{}; 441 PointerEventsConsumableFlags actual{}; 442 443 { 444 RefPtr<TouchBlockState> blockState = CreateTouchBlockStateForApzc(apzc); 445 blockState->UpdateSlopState(touchStart, false); 446 447 blockState->SetAllowedTouchBehaviors({AllowedTouchBehavior::NONE}); 448 expected = {true, false}; 449 actual = apzc->ArePointerEventsConsumable(blockState, touchMove); 450 EXPECT_EQ(expected, actual); 451 } 452 453 { 454 RefPtr<TouchBlockState> blockState = CreateTouchBlockStateForApzc(apzc); 455 blockState->UpdateSlopState(touchStart, false); 456 457 blockState->SetAllowedTouchBehaviors({AllowedTouchBehavior::PINCH_ZOOM}); 458 expected = {true, true}; 459 actual = apzc->ArePointerEventsConsumable(blockState, touchMove); 460 EXPECT_EQ(expected, actual); 461 } 462 } 463 464 TEST_F(APZCArePointerEventsConsumable, DynamicToolbar) { 465 CreateSingleElementTree(); 466 467 RefPtr<TestAsyncPanZoomController> apzc = ApzcOf(root); 468 RefPtr<TouchBlockState> blockState = CreateTouchBlockStateForApzc(apzc); 469 470 // Create touch with vertical 20 unit scroll 471 MultiTouchInput touchStart = 472 CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_START, mcc->Time()); 473 touchStart.mTouches.AppendElement( 474 SingleTouchData(0, ScreenIntPoint(60, 30), ScreenSize(0, 0), 0, 0)); 475 476 MultiTouchInput touchMove = 477 CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, mcc->Time()); 478 touchMove.mTouches.AppendElement( 479 SingleTouchData(0, ScreenIntPoint(60, 40), ScreenSize(0, 0), 0, 0)); 480 481 blockState->UpdateSlopState(touchStart, false); 482 483 // Restrict size of scrollable area: No room to pan X, no room to pan Y 484 apzc->GetFrameMetrics().SetScrollableRect(CSSRect{0, 0, 100, 100}); 485 486 PointerEventsConsumableFlags actual{}; 487 PointerEventsConsumableFlags expected{}; 488 489 expected = {false, true}; 490 actual = apzc->ArePointerEventsConsumable(blockState, touchMove); 491 EXPECT_EQ(expected, actual); 492 493 apzc->GetFrameMetrics().SetCompositionSizeWithoutDynamicToolbar( 494 ParentLayerSize{100, 90}); 495 UpdateHitTestingTree(); 496 497 expected = {true, true}; 498 actual = apzc->ArePointerEventsConsumable(blockState, touchMove); 499 EXPECT_EQ(expected, actual); 500 }