1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "cc/trees/layer_tree_impl.h" 6 7 #include "cc/layers/heads_up_display_layer_impl.h" 8 #include "cc/layers/layer.h" 9 #include "cc/test/fake_impl_proxy.h" 10 #include "cc/test/fake_layer_tree_host_impl.h" 11 #include "cc/test/fake_output_surface.h" 12 #include "cc/test/geometry_test_utils.h" 13 #include "cc/test/layer_tree_host_common_test.h" 14 #include "cc/test/test_shared_bitmap_manager.h" 15 #include "cc/trees/layer_tree_host_impl.h" 16 #include "ui/gfx/size_conversions.h" 17 18 namespace cc { 19 namespace { 20 21 class LayerTreeImplTest : public LayerTreeHostCommonTest { 22 public: 23 LayerTreeImplTest() { 24 LayerTreeSettings settings; 25 settings.layer_transforms_should_scale_layer_contents = true; 26 host_impl_.reset( 27 new FakeLayerTreeHostImpl(settings, &proxy_, &shared_bitmap_manager_)); 28 EXPECT_TRUE(host_impl_->InitializeRenderer( 29 FakeOutputSurface::Create3d().PassAs<OutputSurface>())); 30 } 31 32 FakeLayerTreeHostImpl& host_impl() { return *host_impl_; } 33 34 LayerImpl* root_layer() { return host_impl_->active_tree()->root_layer(); } 35 36 const LayerImplList& RenderSurfaceLayerList() const { 37 return host_impl_->active_tree()->RenderSurfaceLayerList(); 38 } 39 40 private: 41 TestSharedBitmapManager shared_bitmap_manager_; 42 FakeImplProxy proxy_; 43 scoped_ptr<FakeLayerTreeHostImpl> host_impl_; 44 }; 45 46 TEST_F(LayerTreeImplTest, HitTestingForSingleLayer) { 47 scoped_ptr<LayerImpl> root = 48 LayerImpl::Create(host_impl().active_tree(), 12345); 49 50 gfx::Transform identity_matrix; 51 gfx::Point3F transform_origin; 52 gfx::PointF position; 53 gfx::Size bounds(100, 100); 54 SetLayerPropertiesForTesting(root.get(), 55 identity_matrix, 56 transform_origin, 57 position, 58 bounds, 59 true, 60 false); 61 root->SetDrawsContent(true); 62 63 host_impl().SetViewportSize(root->bounds()); 64 host_impl().active_tree()->SetRootLayer(root.Pass()); 65 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree(); 66 67 // Sanity check the scenario we just created. 68 ASSERT_EQ(1u, RenderSurfaceLayerList().size()); 69 ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size()); 70 71 // Hit testing for a point outside the layer should return a null pointer. 72 gfx::Point test_point(101, 101); 73 LayerImpl* result_layer = 74 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 75 EXPECT_FALSE(result_layer); 76 77 test_point = gfx::Point(-1, -1); 78 result_layer = 79 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 80 EXPECT_FALSE(result_layer); 81 82 // Hit testing for a point inside should return the root layer. 83 test_point = gfx::Point(1, 1); 84 result_layer = 85 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 86 ASSERT_TRUE(result_layer); 87 EXPECT_EQ(12345, result_layer->id()); 88 89 test_point = gfx::Point(99, 99); 90 result_layer = 91 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 92 ASSERT_TRUE(result_layer); 93 EXPECT_EQ(12345, result_layer->id()); 94 } 95 96 TEST_F(LayerTreeImplTest, HitTestingForSingleLayerAndHud) { 97 scoped_ptr<LayerImpl> root = 98 LayerImpl::Create(host_impl().active_tree(), 12345); 99 scoped_ptr<HeadsUpDisplayLayerImpl> hud = 100 HeadsUpDisplayLayerImpl::Create(host_impl().active_tree(), 11111); 101 102 gfx::Transform identity_matrix; 103 gfx::Point3F transform_origin; 104 gfx::PointF position; 105 gfx::Size bounds(100, 100); 106 SetLayerPropertiesForTesting(root.get(), 107 identity_matrix, 108 transform_origin, 109 position, 110 bounds, 111 true, 112 false); 113 root->SetDrawsContent(true); 114 115 // Create hud and add it as a child of root. 116 gfx::Size hud_bounds(200, 200); 117 SetLayerPropertiesForTesting(hud.get(), 118 identity_matrix, 119 transform_origin, 120 position, 121 hud_bounds, 122 true, 123 false); 124 hud->SetDrawsContent(true); 125 126 host_impl().active_tree()->set_hud_layer(hud.get()); 127 root->AddChild(hud.PassAs<LayerImpl>()); 128 129 host_impl().SetViewportSize(hud_bounds); 130 host_impl().active_tree()->SetRootLayer(root.Pass()); 131 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree(); 132 133 // Sanity check the scenario we just created. 134 ASSERT_EQ(1u, RenderSurfaceLayerList().size()); 135 ASSERT_EQ(2u, root_layer()->render_surface()->layer_list().size()); 136 137 // Hit testing for a point inside HUD, but outside root should return null 138 gfx::Point test_point(101, 101); 139 LayerImpl* result_layer = 140 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 141 EXPECT_FALSE(result_layer); 142 143 test_point = gfx::Point(-1, -1); 144 result_layer = 145 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 146 EXPECT_FALSE(result_layer); 147 148 // Hit testing for a point inside should return the root layer, never the HUD 149 // layer. 150 test_point = gfx::Point(1, 1); 151 result_layer = 152 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 153 ASSERT_TRUE(result_layer); 154 EXPECT_EQ(12345, result_layer->id()); 155 156 test_point = gfx::Point(99, 99); 157 result_layer = 158 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 159 ASSERT_TRUE(result_layer); 160 EXPECT_EQ(12345, result_layer->id()); 161 } 162 163 TEST_F(LayerTreeImplTest, HitTestingForUninvertibleTransform) { 164 scoped_ptr<LayerImpl> root = 165 LayerImpl::Create(host_impl().active_tree(), 12345); 166 167 gfx::Transform uninvertible_transform; 168 uninvertible_transform.matrix().set(0, 0, 0.0); 169 uninvertible_transform.matrix().set(1, 1, 0.0); 170 uninvertible_transform.matrix().set(2, 2, 0.0); 171 uninvertible_transform.matrix().set(3, 3, 0.0); 172 ASSERT_FALSE(uninvertible_transform.IsInvertible()); 173 174 gfx::Transform identity_matrix; 175 gfx::Point3F transform_origin; 176 gfx::PointF position; 177 gfx::Size bounds(100, 100); 178 SetLayerPropertiesForTesting(root.get(), 179 uninvertible_transform, 180 transform_origin, 181 position, 182 bounds, 183 true, 184 false); 185 root->SetDrawsContent(true); 186 187 host_impl().SetViewportSize(root->bounds()); 188 host_impl().active_tree()->SetRootLayer(root.Pass()); 189 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree(); 190 // Sanity check the scenario we just created. 191 ASSERT_EQ(1u, RenderSurfaceLayerList().size()); 192 ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size()); 193 ASSERT_FALSE(root_layer()->screen_space_transform().IsInvertible()); 194 195 // Hit testing any point should not hit the layer. If the invertible matrix is 196 // accidentally ignored and treated like an identity, then the hit testing 197 // will incorrectly hit the layer when it shouldn't. 198 gfx::Point test_point(1, 1); 199 LayerImpl* result_layer = 200 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 201 EXPECT_FALSE(result_layer); 202 203 test_point = gfx::Point(10, 10); 204 result_layer = 205 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 206 EXPECT_FALSE(result_layer); 207 208 test_point = gfx::Point(10, 30); 209 result_layer = 210 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 211 EXPECT_FALSE(result_layer); 212 213 test_point = gfx::Point(50, 50); 214 result_layer = 215 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 216 EXPECT_FALSE(result_layer); 217 218 test_point = gfx::Point(67, 48); 219 result_layer = 220 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 221 EXPECT_FALSE(result_layer); 222 223 test_point = gfx::Point(99, 99); 224 result_layer = 225 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 226 EXPECT_FALSE(result_layer); 227 228 test_point = gfx::Point(-1, -1); 229 result_layer = 230 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 231 EXPECT_FALSE(result_layer); 232 } 233 234 TEST_F(LayerTreeImplTest, HitTestingForSinglePositionedLayer) { 235 scoped_ptr<LayerImpl> root = 236 LayerImpl::Create(host_impl().active_tree(), 12345); 237 238 gfx::Transform identity_matrix; 239 gfx::Point3F transform_origin; 240 // this layer is positioned, and hit testing should correctly know where the 241 // layer is located. 242 gfx::PointF position(50.f, 50.f); 243 gfx::Size bounds(100, 100); 244 SetLayerPropertiesForTesting(root.get(), 245 identity_matrix, 246 transform_origin, 247 position, 248 bounds, 249 true, 250 false); 251 root->SetDrawsContent(true); 252 253 host_impl().SetViewportSize(root->bounds()); 254 host_impl().active_tree()->SetRootLayer(root.Pass()); 255 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree(); 256 257 // Sanity check the scenario we just created. 258 ASSERT_EQ(1u, RenderSurfaceLayerList().size()); 259 ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size()); 260 261 // Hit testing for a point outside the layer should return a null pointer. 262 gfx::Point test_point(49, 49); 263 LayerImpl* result_layer = 264 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 265 EXPECT_FALSE(result_layer); 266 267 // Even though the layer exists at (101, 101), it should not be visible there 268 // since the root render surface would clamp it. 269 test_point = gfx::Point(101, 101); 270 result_layer = 271 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 272 EXPECT_FALSE(result_layer); 273 274 // Hit testing for a point inside should return the root layer. 275 test_point = gfx::Point(51, 51); 276 result_layer = 277 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 278 ASSERT_TRUE(result_layer); 279 EXPECT_EQ(12345, result_layer->id()); 280 281 test_point = gfx::Point(99, 99); 282 result_layer = 283 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 284 ASSERT_TRUE(result_layer); 285 EXPECT_EQ(12345, result_layer->id()); 286 } 287 288 TEST_F(LayerTreeImplTest, HitTestingForSingleRotatedLayer) { 289 scoped_ptr<LayerImpl> root = 290 LayerImpl::Create(host_impl().active_tree(), 12345); 291 292 gfx::Transform identity_matrix; 293 gfx::Transform rotation45_degrees_about_center; 294 rotation45_degrees_about_center.Translate(50.0, 50.0); 295 rotation45_degrees_about_center.RotateAboutZAxis(45.0); 296 rotation45_degrees_about_center.Translate(-50.0, -50.0); 297 gfx::Point3F transform_origin; 298 gfx::PointF position; 299 gfx::Size bounds(100, 100); 300 SetLayerPropertiesForTesting(root.get(), 301 rotation45_degrees_about_center, 302 transform_origin, 303 position, 304 bounds, 305 true, 306 false); 307 root->SetDrawsContent(true); 308 309 host_impl().SetViewportSize(root->bounds()); 310 host_impl().active_tree()->SetRootLayer(root.Pass()); 311 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree(); 312 313 // Sanity check the scenario we just created. 314 ASSERT_EQ(1u, RenderSurfaceLayerList().size()); 315 ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size()); 316 317 // Hit testing for points outside the layer. 318 // These corners would have been inside the un-transformed layer, but they 319 // should not hit the correctly transformed layer. 320 gfx::Point test_point(99, 99); 321 LayerImpl* result_layer = 322 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 323 EXPECT_FALSE(result_layer); 324 325 test_point = gfx::Point(1, 1); 326 result_layer = 327 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 328 EXPECT_FALSE(result_layer); 329 330 // Hit testing for a point inside should return the root layer. 331 test_point = gfx::Point(1, 50); 332 result_layer = 333 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 334 ASSERT_TRUE(result_layer); 335 EXPECT_EQ(12345, result_layer->id()); 336 337 // Hit testing the corners that would overlap the unclipped layer, but are 338 // outside the clipped region. 339 test_point = gfx::Point(50, -1); 340 result_layer = 341 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 342 ASSERT_FALSE(result_layer); 343 344 test_point = gfx::Point(-1, 50); 345 result_layer = 346 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 347 ASSERT_FALSE(result_layer); 348 } 349 350 TEST_F(LayerTreeImplTest, HitTestingForSinglePerspectiveLayer) { 351 scoped_ptr<LayerImpl> root = 352 LayerImpl::Create(host_impl().active_tree(), 12345); 353 354 gfx::Transform identity_matrix; 355 356 // perspective_projection_about_center * translation_by_z is designed so that 357 // the 100 x 100 layer becomes 50 x 50, and remains centered at (50, 50). 358 gfx::Transform perspective_projection_about_center; 359 perspective_projection_about_center.Translate(50.0, 50.0); 360 perspective_projection_about_center.ApplyPerspectiveDepth(1.0); 361 perspective_projection_about_center.Translate(-50.0, -50.0); 362 gfx::Transform translation_by_z; 363 translation_by_z.Translate3d(0.0, 0.0, -1.0); 364 365 gfx::Point3F transform_origin; 366 gfx::PointF position; 367 gfx::Size bounds(100, 100); 368 SetLayerPropertiesForTesting( 369 root.get(), 370 perspective_projection_about_center * translation_by_z, 371 transform_origin, 372 position, 373 bounds, 374 true, 375 false); 376 root->SetDrawsContent(true); 377 378 host_impl().SetViewportSize(root->bounds()); 379 host_impl().active_tree()->SetRootLayer(root.Pass()); 380 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree(); 381 382 // Sanity check the scenario we just created. 383 ASSERT_EQ(1u, RenderSurfaceLayerList().size()); 384 ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size()); 385 386 // Hit testing for points outside the layer. 387 // These corners would have been inside the un-transformed layer, but they 388 // should not hit the correctly transformed layer. 389 gfx::Point test_point(24, 24); 390 LayerImpl* result_layer = 391 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 392 EXPECT_FALSE(result_layer); 393 394 test_point = gfx::Point(76, 76); 395 result_layer = 396 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 397 EXPECT_FALSE(result_layer); 398 399 // Hit testing for a point inside should return the root layer. 400 test_point = gfx::Point(26, 26); 401 result_layer = 402 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 403 ASSERT_TRUE(result_layer); 404 EXPECT_EQ(12345, result_layer->id()); 405 406 test_point = gfx::Point(74, 74); 407 result_layer = 408 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 409 ASSERT_TRUE(result_layer); 410 EXPECT_EQ(12345, result_layer->id()); 411 } 412 413 TEST_F(LayerTreeImplTest, HitTestingForSingleLayerWithScaledContents) { 414 // A layer's visible content rect is actually in the layer's content space. 415 // The screen space transform converts from the layer's origin space to screen 416 // space. This test makes sure that hit testing works correctly accounts for 417 // the contents scale. A contents scale that is not 1 effectively forces a 418 // non-identity transform between layer's content space and layer's origin 419 // space. The hit testing code must take this into account. 420 // 421 // To test this, the layer is positioned at (25, 25), and is size (50, 50). If 422 // contents scale is ignored, then hit testing will mis-interpret the visible 423 // content rect as being larger than the actual bounds of the layer. 424 // 425 scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl().active_tree(), 1); 426 427 gfx::Transform identity_matrix; 428 gfx::Point3F transform_origin; 429 430 SetLayerPropertiesForTesting(root.get(), 431 identity_matrix, 432 transform_origin, 433 gfx::PointF(), 434 gfx::Size(100, 100), 435 true, 436 false); 437 { 438 gfx::PointF position(25.f, 25.f); 439 gfx::Size bounds(50, 50); 440 scoped_ptr<LayerImpl> test_layer = 441 LayerImpl::Create(host_impl().active_tree(), 12345); 442 SetLayerPropertiesForTesting(test_layer.get(), 443 identity_matrix, 444 transform_origin, 445 position, 446 bounds, 447 true, 448 false); 449 450 // override content bounds and contents scale 451 test_layer->SetContentBounds(gfx::Size(100, 100)); 452 test_layer->SetContentsScale(2, 2); 453 454 test_layer->SetDrawsContent(true); 455 root->AddChild(test_layer.Pass()); 456 } 457 458 host_impl().SetViewportSize(root->bounds()); 459 host_impl().active_tree()->SetRootLayer(root.Pass()); 460 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree(); 461 462 // Sanity check the scenario we just created. 463 // The visible content rect for test_layer is actually 100x100, even though 464 // its layout size is 50x50, positioned at 25x25. 465 LayerImpl* test_layer = 466 host_impl().active_tree()->root_layer()->children()[0]; 467 EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100), test_layer->visible_content_rect()); 468 ASSERT_EQ(1u, RenderSurfaceLayerList().size()); 469 ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size()); 470 471 // Hit testing for a point outside the layer should return a null pointer (the 472 // root layer does not draw content, so it will not be hit tested either). 473 gfx::Point test_point(101, 101); 474 LayerImpl* result_layer = 475 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 476 EXPECT_FALSE(result_layer); 477 478 test_point = gfx::Point(24, 24); 479 result_layer = 480 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 481 EXPECT_FALSE(result_layer); 482 483 test_point = gfx::Point(76, 76); 484 result_layer = 485 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 486 EXPECT_FALSE(result_layer); 487 488 // Hit testing for a point inside should return the test layer. 489 test_point = gfx::Point(26, 26); 490 result_layer = 491 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 492 ASSERT_TRUE(result_layer); 493 EXPECT_EQ(12345, result_layer->id()); 494 495 test_point = gfx::Point(74, 74); 496 result_layer = 497 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 498 ASSERT_TRUE(result_layer); 499 EXPECT_EQ(12345, result_layer->id()); 500 } 501 502 TEST_F(LayerTreeImplTest, HitTestingForSimpleClippedLayer) { 503 // Test that hit-testing will only work for the visible portion of a layer, 504 // and not the entire layer bounds. Here we just test the simple axis-aligned 505 // case. 506 gfx::Transform identity_matrix; 507 gfx::Point3F transform_origin; 508 509 scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl().active_tree(), 1); 510 SetLayerPropertiesForTesting(root.get(), 511 identity_matrix, 512 transform_origin, 513 gfx::PointF(), 514 gfx::Size(100, 100), 515 true, 516 false); 517 { 518 scoped_ptr<LayerImpl> clipping_layer = 519 LayerImpl::Create(host_impl().active_tree(), 123); 520 // this layer is positioned, and hit testing should correctly know where the 521 // layer is located. 522 gfx::PointF position(25.f, 25.f); 523 gfx::Size bounds(50, 50); 524 SetLayerPropertiesForTesting(clipping_layer.get(), 525 identity_matrix, 526 transform_origin, 527 position, 528 bounds, 529 true, 530 false); 531 clipping_layer->SetMasksToBounds(true); 532 533 scoped_ptr<LayerImpl> child = 534 LayerImpl::Create(host_impl().active_tree(), 456); 535 position = gfx::PointF(-50.f, -50.f); 536 bounds = gfx::Size(300, 300); 537 SetLayerPropertiesForTesting(child.get(), 538 identity_matrix, 539 transform_origin, 540 position, 541 bounds, 542 true, 543 false); 544 child->SetDrawsContent(true); 545 clipping_layer->AddChild(child.Pass()); 546 root->AddChild(clipping_layer.Pass()); 547 } 548 549 host_impl().SetViewportSize(root->bounds()); 550 host_impl().active_tree()->SetRootLayer(root.Pass()); 551 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree(); 552 553 // Sanity check the scenario we just created. 554 ASSERT_EQ(1u, RenderSurfaceLayerList().size()); 555 ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size()); 556 ASSERT_EQ(456, root_layer()->render_surface()->layer_list().at(0)->id()); 557 558 // Hit testing for a point outside the layer should return a null pointer. 559 // Despite the child layer being very large, it should be clipped to the root 560 // layer's bounds. 561 gfx::Point test_point(24, 24); 562 LayerImpl* result_layer = 563 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 564 EXPECT_FALSE(result_layer); 565 566 // Even though the layer exists at (101, 101), it should not be visible there 567 // since the clipping_layer would clamp it. 568 test_point = gfx::Point(76, 76); 569 result_layer = 570 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 571 EXPECT_FALSE(result_layer); 572 573 // Hit testing for a point inside should return the child layer. 574 test_point = gfx::Point(26, 26); 575 result_layer = 576 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 577 ASSERT_TRUE(result_layer); 578 EXPECT_EQ(456, result_layer->id()); 579 580 test_point = gfx::Point(74, 74); 581 result_layer = 582 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 583 ASSERT_TRUE(result_layer); 584 EXPECT_EQ(456, result_layer->id()); 585 } 586 587 TEST_F(LayerTreeImplTest, HitTestingForMultiClippedRotatedLayer) { 588 // This test checks whether hit testing correctly avoids hit testing with 589 // multiple ancestors that clip in non axis-aligned ways. To pass this test, 590 // the hit testing algorithm needs to recognize that multiple parent layers 591 // may clip the layer, and should not actually hit those clipped areas. 592 // 593 // The child and grand_child layers are both initialized to clip the 594 // rotated_leaf. The child layer is rotated about the top-left corner, so that 595 // the root + child clips combined create a triangle. The rotated_leaf will 596 // only be visible where it overlaps this triangle. 597 // 598 scoped_ptr<LayerImpl> root = 599 LayerImpl::Create(host_impl().active_tree(), 123); 600 601 gfx::Transform identity_matrix; 602 gfx::Point3F transform_origin; 603 gfx::PointF position; 604 gfx::Size bounds(100, 100); 605 SetLayerPropertiesForTesting(root.get(), 606 identity_matrix, 607 transform_origin, 608 position, 609 bounds, 610 true, 611 false); 612 root->SetMasksToBounds(true); 613 { 614 scoped_ptr<LayerImpl> child = 615 LayerImpl::Create(host_impl().active_tree(), 456); 616 scoped_ptr<LayerImpl> grand_child = 617 LayerImpl::Create(host_impl().active_tree(), 789); 618 scoped_ptr<LayerImpl> rotated_leaf = 619 LayerImpl::Create(host_impl().active_tree(), 2468); 620 621 position = gfx::PointF(10.f, 10.f); 622 bounds = gfx::Size(80, 80); 623 SetLayerPropertiesForTesting(child.get(), 624 identity_matrix, 625 transform_origin, 626 position, 627 bounds, 628 true, 629 false); 630 child->SetMasksToBounds(true); 631 632 gfx::Transform rotation45_degrees_about_corner; 633 rotation45_degrees_about_corner.RotateAboutZAxis(45.0); 634 635 // remember, positioned with respect to its parent which is already at 10, 636 // 10 637 position = gfx::PointF(); 638 bounds = 639 gfx::Size(200, 200); // to ensure it covers at least sqrt(2) * 100. 640 SetLayerPropertiesForTesting(grand_child.get(), 641 rotation45_degrees_about_corner, 642 transform_origin, 643 position, 644 bounds, 645 true, 646 false); 647 grand_child->SetMasksToBounds(true); 648 649 // Rotates about the center of the layer 650 gfx::Transform rotated_leaf_transform; 651 rotated_leaf_transform.Translate( 652 -10.0, -10.0); // cancel out the grand_parent's position 653 rotated_leaf_transform.RotateAboutZAxis( 654 -45.0); // cancel out the corner 45-degree rotation of the parent. 655 rotated_leaf_transform.Translate(50.0, 50.0); 656 rotated_leaf_transform.RotateAboutZAxis(45.0); 657 rotated_leaf_transform.Translate(-50.0, -50.0); 658 position = gfx::PointF(); 659 bounds = gfx::Size(100, 100); 660 SetLayerPropertiesForTesting(rotated_leaf.get(), 661 rotated_leaf_transform, 662 transform_origin, 663 position, 664 bounds, 665 true, 666 false); 667 rotated_leaf->SetDrawsContent(true); 668 669 grand_child->AddChild(rotated_leaf.Pass()); 670 child->AddChild(grand_child.Pass()); 671 root->AddChild(child.Pass()); 672 } 673 674 host_impl().SetViewportSize(root->bounds()); 675 host_impl().active_tree()->SetRootLayer(root.Pass()); 676 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree(); 677 678 // Sanity check the scenario we just created. 679 // The grand_child is expected to create a render surface because it 680 // MasksToBounds and is not axis aligned. 681 ASSERT_EQ(2u, RenderSurfaceLayerList().size()); 682 ASSERT_EQ( 683 1u, 684 RenderSurfaceLayerList().at(0)->render_surface()->layer_list().size()); 685 ASSERT_EQ(789, 686 RenderSurfaceLayerList() 687 .at(0) 688 ->render_surface() 689 ->layer_list() 690 .at(0) 691 ->id()); // grand_child's surface. 692 ASSERT_EQ( 693 1u, 694 RenderSurfaceLayerList().at(1)->render_surface()->layer_list().size()); 695 ASSERT_EQ( 696 2468, 697 RenderSurfaceLayerList()[1]->render_surface()->layer_list().at(0)->id()); 698 699 // (11, 89) is close to the the bottom left corner within the clip, but it is 700 // not inside the layer. 701 gfx::Point test_point(11, 89); 702 LayerImpl* result_layer = 703 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 704 EXPECT_FALSE(result_layer); 705 706 // Closer inwards from the bottom left will overlap the layer. 707 test_point = gfx::Point(25, 75); 708 result_layer = 709 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 710 ASSERT_TRUE(result_layer); 711 EXPECT_EQ(2468, result_layer->id()); 712 713 // (4, 50) is inside the unclipped layer, but that corner of the layer should 714 // be clipped away by the grandparent and should not get hit. If hit testing 715 // blindly uses visible content rect without considering how parent may clip 716 // the layer, then hit testing would accidentally think that the point 717 // successfully hits the layer. 718 test_point = gfx::Point(4, 50); 719 result_layer = 720 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 721 EXPECT_FALSE(result_layer); 722 723 // (11, 50) is inside the layer and within the clipped area. 724 test_point = gfx::Point(11, 50); 725 result_layer = 726 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 727 ASSERT_TRUE(result_layer); 728 EXPECT_EQ(2468, result_layer->id()); 729 730 // Around the middle, just to the right and up, would have hit the layer 731 // except that that area should be clipped away by the parent. 732 test_point = gfx::Point(51, 49); 733 result_layer = 734 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 735 EXPECT_FALSE(result_layer); 736 737 // Around the middle, just to the left and down, should successfully hit the 738 // layer. 739 test_point = gfx::Point(49, 51); 740 result_layer = 741 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 742 ASSERT_TRUE(result_layer); 743 EXPECT_EQ(2468, result_layer->id()); 744 } 745 746 TEST_F(LayerTreeImplTest, HitTestingForNonClippingIntermediateLayer) { 747 // This test checks that hit testing code does not accidentally clip to layer 748 // bounds for a layer that actually does not clip. 749 gfx::Transform identity_matrix; 750 gfx::Point3F transform_origin; 751 752 scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl().active_tree(), 1); 753 SetLayerPropertiesForTesting(root.get(), 754 identity_matrix, 755 transform_origin, 756 gfx::PointF(), 757 gfx::Size(100, 100), 758 true, 759 false); 760 { 761 scoped_ptr<LayerImpl> intermediate_layer = 762 LayerImpl::Create(host_impl().active_tree(), 123); 763 // this layer is positioned, and hit testing should correctly know where the 764 // layer is located. 765 gfx::PointF position(10.f, 10.f); 766 gfx::Size bounds(50, 50); 767 SetLayerPropertiesForTesting(intermediate_layer.get(), 768 identity_matrix, 769 transform_origin, 770 position, 771 bounds, 772 true, 773 false); 774 // Sanity check the intermediate layer should not clip. 775 ASSERT_FALSE(intermediate_layer->masks_to_bounds()); 776 ASSERT_FALSE(intermediate_layer->mask_layer()); 777 778 // The child of the intermediate_layer is translated so that it does not 779 // overlap intermediate_layer at all. If child is incorrectly clipped, we 780 // would not be able to hit it successfully. 781 scoped_ptr<LayerImpl> child = 782 LayerImpl::Create(host_impl().active_tree(), 456); 783 position = gfx::PointF(60.f, 60.f); // 70, 70 in screen space 784 bounds = gfx::Size(20, 20); 785 SetLayerPropertiesForTesting(child.get(), 786 identity_matrix, 787 transform_origin, 788 position, 789 bounds, 790 true, 791 false); 792 child->SetDrawsContent(true); 793 intermediate_layer->AddChild(child.Pass()); 794 root->AddChild(intermediate_layer.Pass()); 795 } 796 797 host_impl().SetViewportSize(root->bounds()); 798 host_impl().active_tree()->SetRootLayer(root.Pass()); 799 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree(); 800 801 // Sanity check the scenario we just created. 802 ASSERT_EQ(1u, RenderSurfaceLayerList().size()); 803 ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size()); 804 ASSERT_EQ(456, root_layer()->render_surface()->layer_list().at(0)->id()); 805 806 // Hit testing for a point outside the layer should return a null pointer. 807 gfx::Point test_point(69, 69); 808 LayerImpl* result_layer = 809 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 810 EXPECT_FALSE(result_layer); 811 812 test_point = gfx::Point(91, 91); 813 result_layer = 814 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 815 EXPECT_FALSE(result_layer); 816 817 // Hit testing for a point inside should return the child layer. 818 test_point = gfx::Point(71, 71); 819 result_layer = 820 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 821 ASSERT_TRUE(result_layer); 822 EXPECT_EQ(456, result_layer->id()); 823 824 test_point = gfx::Point(89, 89); 825 result_layer = 826 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 827 ASSERT_TRUE(result_layer); 828 EXPECT_EQ(456, result_layer->id()); 829 } 830 831 TEST_F(LayerTreeImplTest, HitTestingForMultipleLayers) { 832 scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl().active_tree(), 1); 833 834 gfx::Transform identity_matrix; 835 gfx::Point3F transform_origin; 836 gfx::PointF position; 837 gfx::Size bounds(100, 100); 838 SetLayerPropertiesForTesting(root.get(), 839 identity_matrix, 840 transform_origin, 841 position, 842 bounds, 843 true, 844 false); 845 root->SetDrawsContent(true); 846 { 847 // child 1 and child2 are initialized to overlap between x=50 and x=60. 848 // grand_child is set to overlap both child1 and child2 between y=50 and 849 // y=60. The expected stacking order is: (front) child2, (second) 850 // grand_child, (third) child1, and (back) the root layer behind all other 851 // layers. 852 853 scoped_ptr<LayerImpl> child1 = 854 LayerImpl::Create(host_impl().active_tree(), 2); 855 scoped_ptr<LayerImpl> child2 = 856 LayerImpl::Create(host_impl().active_tree(), 3); 857 scoped_ptr<LayerImpl> grand_child1 = 858 LayerImpl::Create(host_impl().active_tree(), 4); 859 860 position = gfx::PointF(10.f, 10.f); 861 bounds = gfx::Size(50, 50); 862 SetLayerPropertiesForTesting(child1.get(), 863 identity_matrix, 864 transform_origin, 865 position, 866 bounds, 867 true, 868 false); 869 child1->SetDrawsContent(true); 870 871 position = gfx::PointF(50.f, 10.f); 872 bounds = gfx::Size(50, 50); 873 SetLayerPropertiesForTesting(child2.get(), 874 identity_matrix, 875 transform_origin, 876 position, 877 bounds, 878 true, 879 false); 880 child2->SetDrawsContent(true); 881 882 // Remember that grand_child is positioned with respect to its parent (i.e. 883 // child1). In screen space, the intended position is (10, 50), with size 884 // 100 x 50. 885 position = gfx::PointF(0.f, 40.f); 886 bounds = gfx::Size(100, 50); 887 SetLayerPropertiesForTesting(grand_child1.get(), 888 identity_matrix, 889 transform_origin, 890 position, 891 bounds, 892 true, 893 false); 894 grand_child1->SetDrawsContent(true); 895 896 child1->AddChild(grand_child1.Pass()); 897 root->AddChild(child1.Pass()); 898 root->AddChild(child2.Pass()); 899 } 900 901 LayerImpl* child1 = root->children()[0]; 902 LayerImpl* child2 = root->children()[1]; 903 LayerImpl* grand_child1 = child1->children()[0]; 904 905 host_impl().SetViewportSize(root->bounds()); 906 host_impl().active_tree()->SetRootLayer(root.Pass()); 907 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree(); 908 909 // Sanity check the scenario we just created. 910 ASSERT_TRUE(child1); 911 ASSERT_TRUE(child2); 912 ASSERT_TRUE(grand_child1); 913 ASSERT_EQ(1u, RenderSurfaceLayerList().size()); 914 915 RenderSurfaceImpl* root_render_surface = root_layer()->render_surface(); 916 ASSERT_EQ(4u, root_render_surface->layer_list().size()); 917 ASSERT_EQ(1, root_render_surface->layer_list().at(0)->id()); // root layer 918 ASSERT_EQ(2, root_render_surface->layer_list().at(1)->id()); // child1 919 ASSERT_EQ(4, root_render_surface->layer_list().at(2)->id()); // grand_child1 920 ASSERT_EQ(3, root_render_surface->layer_list().at(3)->id()); // child2 921 922 // Nothing overlaps the root_layer at (1, 1), so hit testing there should find 923 // the root layer. 924 gfx::Point test_point = gfx::Point(1, 1); 925 LayerImpl* result_layer = 926 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 927 ASSERT_TRUE(result_layer); 928 EXPECT_EQ(1, result_layer->id()); 929 930 // At (15, 15), child1 and root are the only layers. child1 is expected to be 931 // on top. 932 test_point = gfx::Point(15, 15); 933 result_layer = 934 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 935 ASSERT_TRUE(result_layer); 936 EXPECT_EQ(2, result_layer->id()); 937 938 // At (51, 20), child1 and child2 overlap. child2 is expected to be on top. 939 test_point = gfx::Point(51, 20); 940 result_layer = 941 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 942 ASSERT_TRUE(result_layer); 943 EXPECT_EQ(3, result_layer->id()); 944 945 // At (80, 51), child2 and grand_child1 overlap. child2 is expected to be on 946 // top. 947 test_point = gfx::Point(80, 51); 948 result_layer = 949 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 950 ASSERT_TRUE(result_layer); 951 EXPECT_EQ(3, result_layer->id()); 952 953 // At (51, 51), all layers overlap each other. child2 is expected to be on top 954 // of all other layers. 955 test_point = gfx::Point(51, 51); 956 result_layer = 957 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 958 ASSERT_TRUE(result_layer); 959 EXPECT_EQ(3, result_layer->id()); 960 961 // At (20, 51), child1 and grand_child1 overlap. grand_child1 is expected to 962 // be on top. 963 test_point = gfx::Point(20, 51); 964 result_layer = 965 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 966 ASSERT_TRUE(result_layer); 967 EXPECT_EQ(4, result_layer->id()); 968 } 969 970 TEST_F(LayerTreeImplTest, HitTestingForMultipleLayersAtVaryingDepths) { 971 scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl().active_tree(), 1); 972 973 gfx::Transform identity_matrix; 974 gfx::Point3F transform_origin; 975 gfx::PointF position; 976 gfx::Size bounds(100, 100); 977 SetLayerPropertiesForTesting(root.get(), 978 identity_matrix, 979 transform_origin, 980 position, 981 bounds, 982 true, 983 false); 984 root->SetDrawsContent(true); 985 root->SetShouldFlattenTransform(false); 986 root->Set3dSortingContextId(1); 987 { 988 // child 1 and child2 are initialized to overlap between x=50 and x=60. 989 // grand_child is set to overlap both child1 and child2 between y=50 and 990 // y=60. The expected stacking order is: (front) child2, (second) 991 // grand_child, (third) child1, and (back) the root layer behind all other 992 // layers. 993 994 scoped_ptr<LayerImpl> child1 = 995 LayerImpl::Create(host_impl().active_tree(), 2); 996 scoped_ptr<LayerImpl> child2 = 997 LayerImpl::Create(host_impl().active_tree(), 3); 998 scoped_ptr<LayerImpl> grand_child1 = 999 LayerImpl::Create(host_impl().active_tree(), 4); 1000 1001 position = gfx::PointF(10.f, 10.f); 1002 bounds = gfx::Size(50, 50); 1003 SetLayerPropertiesForTesting(child1.get(), 1004 identity_matrix, 1005 transform_origin, 1006 position, 1007 bounds, 1008 true, 1009 false); 1010 child1->SetDrawsContent(true); 1011 child1->SetShouldFlattenTransform(false); 1012 child1->Set3dSortingContextId(1); 1013 1014 position = gfx::PointF(50.f, 10.f); 1015 bounds = gfx::Size(50, 50); 1016 gfx::Transform translate_z; 1017 translate_z.Translate3d(0, 0, -10.f); 1018 SetLayerPropertiesForTesting(child2.get(), 1019 translate_z, 1020 transform_origin, 1021 position, 1022 bounds, 1023 true, 1024 false); 1025 child2->SetDrawsContent(true); 1026 child2->SetShouldFlattenTransform(false); 1027 child2->Set3dSortingContextId(1); 1028 1029 // Remember that grand_child is positioned with respect to its parent (i.e. 1030 // child1). In screen space, the intended position is (10, 50), with size 1031 // 100 x 50. 1032 position = gfx::PointF(0.f, 40.f); 1033 bounds = gfx::Size(100, 50); 1034 SetLayerPropertiesForTesting(grand_child1.get(), 1035 identity_matrix, 1036 transform_origin, 1037 position, 1038 bounds, 1039 true, 1040 false); 1041 grand_child1->SetDrawsContent(true); 1042 grand_child1->SetShouldFlattenTransform(false); 1043 1044 child1->AddChild(grand_child1.Pass()); 1045 root->AddChild(child1.Pass()); 1046 root->AddChild(child2.Pass()); 1047 } 1048 1049 LayerImpl* child1 = root->children()[0]; 1050 LayerImpl* child2 = root->children()[1]; 1051 LayerImpl* grand_child1 = child1->children()[0]; 1052 1053 host_impl().SetViewportSize(root->bounds()); 1054 host_impl().active_tree()->SetRootLayer(root.Pass()); 1055 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree(); 1056 1057 // Sanity check the scenario we just created. 1058 ASSERT_TRUE(child1); 1059 ASSERT_TRUE(child2); 1060 ASSERT_TRUE(grand_child1); 1061 ASSERT_EQ(1u, RenderSurfaceLayerList().size()); 1062 1063 RenderSurfaceImpl* root_render_surface = 1064 host_impl().active_tree()->root_layer()->render_surface(); 1065 ASSERT_EQ(4u, root_render_surface->layer_list().size()); 1066 ASSERT_EQ(3, root_render_surface->layer_list().at(0)->id()); 1067 ASSERT_EQ(1, root_render_surface->layer_list().at(1)->id()); 1068 ASSERT_EQ(2, root_render_surface->layer_list().at(2)->id()); 1069 ASSERT_EQ(4, root_render_surface->layer_list().at(3)->id()); 1070 1071 // Nothing overlaps the root_layer at (1, 1), so hit testing there should find 1072 // the root layer. 1073 gfx::Point test_point = gfx::Point(1, 1); 1074 LayerImpl* result_layer = 1075 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 1076 ASSERT_TRUE(result_layer); 1077 EXPECT_EQ(1, result_layer->id()); 1078 1079 // At (15, 15), child1 and root are the only layers. child1 is expected to be 1080 // on top. 1081 test_point = gfx::Point(15, 15); 1082 result_layer = 1083 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 1084 ASSERT_TRUE(result_layer); 1085 EXPECT_EQ(2, result_layer->id()); 1086 1087 // At (51, 20), child1 and child2 overlap. child2 is expected to be on top. 1088 // (because 3 is transformed to the back). 1089 test_point = gfx::Point(51, 20); 1090 result_layer = 1091 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 1092 ASSERT_TRUE(result_layer); 1093 EXPECT_EQ(2, result_layer->id()); 1094 1095 // 3 Would have been on top if it hadn't been transformed to the background. 1096 // Make sure that it isn't hit. 1097 test_point = gfx::Point(80, 51); 1098 result_layer = 1099 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 1100 ASSERT_TRUE(result_layer); 1101 EXPECT_EQ(4, result_layer->id()); 1102 1103 // 3 Would have been on top if it hadn't been transformed to the background. 1104 // Make sure that it isn't hit. 1105 test_point = gfx::Point(51, 51); 1106 result_layer = 1107 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 1108 ASSERT_TRUE(result_layer); 1109 EXPECT_EQ(4, result_layer->id()); 1110 1111 // At (20, 51), child1 and grand_child1 overlap. grand_child1 is expected to 1112 // be on top. 1113 test_point = gfx::Point(20, 51); 1114 result_layer = 1115 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 1116 ASSERT_TRUE(result_layer); 1117 EXPECT_EQ(4, result_layer->id()); 1118 } 1119 1120 TEST_F(LayerTreeImplTest, HitTestingRespectsClipParents) { 1121 scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl().active_tree(), 1); 1122 gfx::Transform identity_matrix; 1123 gfx::Point3F transform_origin; 1124 gfx::PointF position; 1125 gfx::Size bounds(100, 100); 1126 SetLayerPropertiesForTesting(root.get(), 1127 identity_matrix, 1128 transform_origin, 1129 position, 1130 bounds, 1131 true, 1132 false); 1133 root->SetDrawsContent(true); 1134 { 1135 scoped_ptr<LayerImpl> child = 1136 LayerImpl::Create(host_impl().active_tree(), 2); 1137 scoped_ptr<LayerImpl> grand_child = 1138 LayerImpl::Create(host_impl().active_tree(), 4); 1139 1140 position = gfx::PointF(10.f, 10.f); 1141 bounds = gfx::Size(1, 1); 1142 SetLayerPropertiesForTesting(child.get(), 1143 identity_matrix, 1144 transform_origin, 1145 position, 1146 bounds, 1147 true, 1148 false); 1149 child->SetDrawsContent(true); 1150 child->SetMasksToBounds(true); 1151 1152 position = gfx::PointF(0.f, 40.f); 1153 bounds = gfx::Size(100, 50); 1154 SetLayerPropertiesForTesting(grand_child.get(), 1155 identity_matrix, 1156 transform_origin, 1157 position, 1158 bounds, 1159 true, 1160 false); 1161 grand_child->SetDrawsContent(true); 1162 grand_child->SetForceRenderSurface(true); 1163 1164 // This should let |grand_child| "escape" |child|'s clip. 1165 grand_child->SetClipParent(root.get()); 1166 1167 child->AddChild(grand_child.Pass()); 1168 root->AddChild(child.Pass()); 1169 } 1170 1171 host_impl().SetViewportSize(root->bounds()); 1172 host_impl().active_tree()->SetRootLayer(root.Pass()); 1173 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree(); 1174 1175 gfx::Point test_point = gfx::Point(12, 52); 1176 LayerImpl* result_layer = 1177 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 1178 ASSERT_TRUE(result_layer); 1179 EXPECT_EQ(4, result_layer->id()); 1180 } 1181 1182 TEST_F(LayerTreeImplTest, HitTestingRespectsScrollParents) { 1183 scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl().active_tree(), 1); 1184 gfx::Transform identity_matrix; 1185 gfx::Point3F transform_origin; 1186 gfx::PointF position; 1187 gfx::Size bounds(100, 100); 1188 SetLayerPropertiesForTesting(root.get(), 1189 identity_matrix, 1190 transform_origin, 1191 position, 1192 bounds, 1193 true, 1194 false); 1195 root->SetDrawsContent(true); 1196 { 1197 scoped_ptr<LayerImpl> child = 1198 LayerImpl::Create(host_impl().active_tree(), 2); 1199 scoped_ptr<LayerImpl> scroll_child = 1200 LayerImpl::Create(host_impl().active_tree(), 3); 1201 scoped_ptr<LayerImpl> grand_child = 1202 LayerImpl::Create(host_impl().active_tree(), 4); 1203 1204 position = gfx::PointF(10.f, 10.f); 1205 bounds = gfx::Size(1, 1); 1206 SetLayerPropertiesForTesting(child.get(), 1207 identity_matrix, 1208 transform_origin, 1209 position, 1210 bounds, 1211 true, 1212 false); 1213 child->SetDrawsContent(true); 1214 child->SetMasksToBounds(true); 1215 1216 position = gfx::PointF(); 1217 bounds = gfx::Size(200, 200); 1218 SetLayerPropertiesForTesting(scroll_child.get(), 1219 identity_matrix, 1220 transform_origin, 1221 position, 1222 bounds, 1223 true, 1224 false); 1225 scroll_child->SetDrawsContent(true); 1226 1227 // This should cause scroll child and its descendants to be affected by 1228 // |child|'s clip. 1229 scroll_child->SetScrollParent(child.get()); 1230 1231 SetLayerPropertiesForTesting(grand_child.get(), 1232 identity_matrix, 1233 transform_origin, 1234 position, 1235 bounds, 1236 true, 1237 false); 1238 grand_child->SetDrawsContent(true); 1239 grand_child->SetForceRenderSurface(true); 1240 1241 scroll_child->AddChild(grand_child.Pass()); 1242 root->AddChild(scroll_child.Pass()); 1243 root->AddChild(child.Pass()); 1244 } 1245 1246 host_impl().SetViewportSize(root->bounds()); 1247 host_impl().active_tree()->SetRootLayer(root.Pass()); 1248 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree(); 1249 1250 gfx::Point test_point = gfx::Point(12, 52); 1251 LayerImpl* result_layer = 1252 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 1253 // The |test_point| should have been clipped away by |child|, the scroll 1254 // parent, so the only thing that should be hit is |root|. 1255 ASSERT_TRUE(result_layer); 1256 ASSERT_EQ(1, result_layer->id()); 1257 } 1258 TEST_F(LayerTreeImplTest, HitTestingForMultipleLayerLists) { 1259 // 1260 // The geometry is set up similarly to the previous case, but 1261 // all layers are forced to be render surfaces now. 1262 // 1263 scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl().active_tree(), 1); 1264 1265 gfx::Transform identity_matrix; 1266 gfx::Point3F transform_origin; 1267 gfx::PointF position; 1268 gfx::Size bounds(100, 100); 1269 SetLayerPropertiesForTesting(root.get(), 1270 identity_matrix, 1271 transform_origin, 1272 position, 1273 bounds, 1274 true, 1275 false); 1276 root->SetDrawsContent(true); 1277 { 1278 // child 1 and child2 are initialized to overlap between x=50 and x=60. 1279 // grand_child is set to overlap both child1 and child2 between y=50 and 1280 // y=60. The expected stacking order is: (front) child2, (second) 1281 // grand_child, (third) child1, and (back) the root layer behind all other 1282 // layers. 1283 1284 scoped_ptr<LayerImpl> child1 = 1285 LayerImpl::Create(host_impl().active_tree(), 2); 1286 scoped_ptr<LayerImpl> child2 = 1287 LayerImpl::Create(host_impl().active_tree(), 3); 1288 scoped_ptr<LayerImpl> grand_child1 = 1289 LayerImpl::Create(host_impl().active_tree(), 4); 1290 1291 position = gfx::PointF(10.f, 10.f); 1292 bounds = gfx::Size(50, 50); 1293 SetLayerPropertiesForTesting(child1.get(), 1294 identity_matrix, 1295 transform_origin, 1296 position, 1297 bounds, 1298 true, 1299 false); 1300 child1->SetDrawsContent(true); 1301 child1->SetForceRenderSurface(true); 1302 1303 position = gfx::PointF(50.f, 10.f); 1304 bounds = gfx::Size(50, 50); 1305 SetLayerPropertiesForTesting(child2.get(), 1306 identity_matrix, 1307 transform_origin, 1308 position, 1309 bounds, 1310 true, 1311 false); 1312 child2->SetDrawsContent(true); 1313 child2->SetForceRenderSurface(true); 1314 1315 // Remember that grand_child is positioned with respect to its parent (i.e. 1316 // child1). In screen space, the intended position is (10, 50), with size 1317 // 100 x 50. 1318 position = gfx::PointF(0.f, 40.f); 1319 bounds = gfx::Size(100, 50); 1320 SetLayerPropertiesForTesting(grand_child1.get(), 1321 identity_matrix, 1322 transform_origin, 1323 position, 1324 bounds, 1325 true, 1326 false); 1327 grand_child1->SetDrawsContent(true); 1328 grand_child1->SetForceRenderSurface(true); 1329 1330 child1->AddChild(grand_child1.Pass()); 1331 root->AddChild(child1.Pass()); 1332 root->AddChild(child2.Pass()); 1333 } 1334 1335 LayerImpl* child1 = root->children()[0]; 1336 LayerImpl* child2 = root->children()[1]; 1337 LayerImpl* grand_child1 = child1->children()[0]; 1338 1339 host_impl().SetViewportSize(root->bounds()); 1340 host_impl().active_tree()->SetRootLayer(root.Pass()); 1341 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree(); 1342 1343 // Sanity check the scenario we just created. 1344 ASSERT_TRUE(child1); 1345 ASSERT_TRUE(child2); 1346 ASSERT_TRUE(grand_child1); 1347 ASSERT_TRUE(child1->render_surface()); 1348 ASSERT_TRUE(child2->render_surface()); 1349 ASSERT_TRUE(grand_child1->render_surface()); 1350 ASSERT_EQ(4u, RenderSurfaceLayerList().size()); 1351 // The root surface has the root layer, and child1's and child2's render 1352 // surfaces. 1353 ASSERT_EQ(3u, root_layer()->render_surface()->layer_list().size()); 1354 // The child1 surface has the child1 layer and grand_child1's render surface. 1355 ASSERT_EQ(2u, child1->render_surface()->layer_list().size()); 1356 ASSERT_EQ(1u, child2->render_surface()->layer_list().size()); 1357 ASSERT_EQ(1u, grand_child1->render_surface()->layer_list().size()); 1358 ASSERT_EQ(1, RenderSurfaceLayerList().at(0)->id()); // root layer 1359 ASSERT_EQ(2, RenderSurfaceLayerList()[1]->id()); // child1 1360 ASSERT_EQ(4, RenderSurfaceLayerList().at(2)->id()); // grand_child1 1361 ASSERT_EQ(3, RenderSurfaceLayerList()[3]->id()); // child2 1362 1363 // Nothing overlaps the root_layer at (1, 1), so hit testing there should find 1364 // the root layer. 1365 gfx::Point test_point = gfx::Point(1, 1); 1366 LayerImpl* result_layer = 1367 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 1368 ASSERT_TRUE(result_layer); 1369 EXPECT_EQ(1, result_layer->id()); 1370 1371 // At (15, 15), child1 and root are the only layers. child1 is expected to be 1372 // on top. 1373 test_point = gfx::Point(15, 15); 1374 result_layer = 1375 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 1376 ASSERT_TRUE(result_layer); 1377 EXPECT_EQ(2, result_layer->id()); 1378 1379 // At (51, 20), child1 and child2 overlap. child2 is expected to be on top. 1380 test_point = gfx::Point(51, 20); 1381 result_layer = 1382 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 1383 ASSERT_TRUE(result_layer); 1384 EXPECT_EQ(3, result_layer->id()); 1385 1386 // At (80, 51), child2 and grand_child1 overlap. child2 is expected to be on 1387 // top. 1388 test_point = gfx::Point(80, 51); 1389 result_layer = 1390 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 1391 ASSERT_TRUE(result_layer); 1392 EXPECT_EQ(3, result_layer->id()); 1393 1394 // At (51, 51), all layers overlap each other. child2 is expected to be on top 1395 // of all other layers. 1396 test_point = gfx::Point(51, 51); 1397 result_layer = 1398 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 1399 ASSERT_TRUE(result_layer); 1400 EXPECT_EQ(3, result_layer->id()); 1401 1402 // At (20, 51), child1 and grand_child1 overlap. grand_child1 is expected to 1403 // be on top. 1404 test_point = gfx::Point(20, 51); 1405 result_layer = 1406 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); 1407 ASSERT_TRUE(result_layer); 1408 EXPECT_EQ(4, result_layer->id()); 1409 } 1410 1411 TEST_F(LayerTreeImplTest, HitCheckingTouchHandlerRegionsForSingleLayer) { 1412 scoped_ptr<LayerImpl> root = 1413 LayerImpl::Create(host_impl().active_tree(), 12345); 1414 1415 gfx::Transform identity_matrix; 1416 Region touch_handler_region(gfx::Rect(10, 10, 50, 50)); 1417 gfx::Point3F transform_origin; 1418 gfx::PointF position; 1419 gfx::Size bounds(100, 100); 1420 SetLayerPropertiesForTesting(root.get(), 1421 identity_matrix, 1422 transform_origin, 1423 position, 1424 bounds, 1425 true, 1426 false); 1427 root->SetDrawsContent(true); 1428 1429 host_impl().SetViewportSize(root->bounds()); 1430 host_impl().active_tree()->SetRootLayer(root.Pass()); 1431 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree(); 1432 1433 // Sanity check the scenario we just created. 1434 ASSERT_EQ(1u, RenderSurfaceLayerList().size()); 1435 ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size()); 1436 1437 // Hit checking for any point should return a null pointer for a layer without 1438 // any touch event handler regions. 1439 gfx::Point test_point(11, 11); 1440 LayerImpl* result_layer = 1441 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion( 1442 test_point); 1443 EXPECT_FALSE(result_layer); 1444 1445 host_impl().active_tree()->root_layer()->SetTouchEventHandlerRegion( 1446 touch_handler_region); 1447 // Hit checking for a point outside the layer should return a null pointer. 1448 test_point = gfx::Point(101, 101); 1449 result_layer = 1450 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion( 1451 test_point); 1452 EXPECT_FALSE(result_layer); 1453 1454 test_point = gfx::Point(-1, -1); 1455 result_layer = 1456 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion( 1457 test_point); 1458 EXPECT_FALSE(result_layer); 1459 1460 // Hit checking for a point inside the layer, but outside the touch handler 1461 // region should return a null pointer. 1462 test_point = gfx::Point(1, 1); 1463 result_layer = 1464 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion( 1465 test_point); 1466 EXPECT_FALSE(result_layer); 1467 1468 test_point = gfx::Point(99, 99); 1469 result_layer = 1470 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion( 1471 test_point); 1472 EXPECT_FALSE(result_layer); 1473 1474 // Hit checking for a point inside the touch event handler region should 1475 // return the root layer. 1476 test_point = gfx::Point(11, 11); 1477 result_layer = 1478 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion( 1479 test_point); 1480 ASSERT_TRUE(result_layer); 1481 EXPECT_EQ(12345, result_layer->id()); 1482 1483 test_point = gfx::Point(59, 59); 1484 result_layer = 1485 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion( 1486 test_point); 1487 ASSERT_TRUE(result_layer); 1488 EXPECT_EQ(12345, result_layer->id()); 1489 } 1490 1491 TEST_F(LayerTreeImplTest, 1492 HitCheckingTouchHandlerRegionsForUninvertibleTransform) { 1493 scoped_ptr<LayerImpl> root = 1494 LayerImpl::Create(host_impl().active_tree(), 12345); 1495 1496 gfx::Transform uninvertible_transform; 1497 uninvertible_transform.matrix().set(0, 0, 0.0); 1498 uninvertible_transform.matrix().set(1, 1, 0.0); 1499 uninvertible_transform.matrix().set(2, 2, 0.0); 1500 uninvertible_transform.matrix().set(3, 3, 0.0); 1501 ASSERT_FALSE(uninvertible_transform.IsInvertible()); 1502 1503 gfx::Transform identity_matrix; 1504 Region touch_handler_region(gfx::Rect(10, 10, 50, 50)); 1505 gfx::Point3F transform_origin; 1506 gfx::PointF position; 1507 gfx::Size bounds(100, 100); 1508 SetLayerPropertiesForTesting(root.get(), 1509 uninvertible_transform, 1510 transform_origin, 1511 position, 1512 bounds, 1513 true, 1514 false); 1515 root->SetDrawsContent(true); 1516 root->SetTouchEventHandlerRegion(touch_handler_region); 1517 1518 host_impl().SetViewportSize(root->bounds()); 1519 host_impl().active_tree()->SetRootLayer(root.Pass()); 1520 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree(); 1521 1522 // Sanity check the scenario we just created. 1523 ASSERT_EQ(1u, RenderSurfaceLayerList().size()); 1524 ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size()); 1525 ASSERT_FALSE(root_layer()->screen_space_transform().IsInvertible()); 1526 1527 // Hit checking any point should not hit the touch handler region on the 1528 // layer. If the invertible matrix is accidentally ignored and treated like an 1529 // identity, then the hit testing will incorrectly hit the layer when it 1530 // shouldn't. 1531 gfx::Point test_point(1, 1); 1532 LayerImpl* result_layer = 1533 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion( 1534 test_point); 1535 EXPECT_FALSE(result_layer); 1536 1537 test_point = gfx::Point(10, 10); 1538 result_layer = 1539 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion( 1540 test_point); 1541 EXPECT_FALSE(result_layer); 1542 1543 test_point = gfx::Point(10, 30); 1544 result_layer = 1545 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion( 1546 test_point); 1547 EXPECT_FALSE(result_layer); 1548 1549 test_point = gfx::Point(50, 50); 1550 result_layer = 1551 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion( 1552 test_point); 1553 EXPECT_FALSE(result_layer); 1554 1555 test_point = gfx::Point(67, 48); 1556 result_layer = 1557 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion( 1558 test_point); 1559 EXPECT_FALSE(result_layer); 1560 1561 test_point = gfx::Point(99, 99); 1562 result_layer = 1563 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion( 1564 test_point); 1565 EXPECT_FALSE(result_layer); 1566 1567 test_point = gfx::Point(-1, -1); 1568 result_layer = 1569 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion( 1570 test_point); 1571 EXPECT_FALSE(result_layer); 1572 } 1573 1574 TEST_F(LayerTreeImplTest, 1575 HitCheckingTouchHandlerRegionsForSinglePositionedLayer) { 1576 scoped_ptr<LayerImpl> root = 1577 LayerImpl::Create(host_impl().active_tree(), 12345); 1578 1579 gfx::Transform identity_matrix; 1580 Region touch_handler_region(gfx::Rect(10, 10, 50, 50)); 1581 gfx::Point3F transform_origin; 1582 // this layer is positioned, and hit testing should correctly know where the 1583 // layer is located. 1584 gfx::PointF position(50.f, 50.f); 1585 gfx::Size bounds(100, 100); 1586 SetLayerPropertiesForTesting(root.get(), 1587 identity_matrix, 1588 transform_origin, 1589 position, 1590 bounds, 1591 true, 1592 false); 1593 root->SetDrawsContent(true); 1594 root->SetTouchEventHandlerRegion(touch_handler_region); 1595 1596 host_impl().SetViewportSize(root->bounds()); 1597 host_impl().active_tree()->SetRootLayer(root.Pass()); 1598 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree(); 1599 1600 // Sanity check the scenario we just created. 1601 ASSERT_EQ(1u, RenderSurfaceLayerList().size()); 1602 ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size()); 1603 1604 // Hit checking for a point outside the layer should return a null pointer. 1605 gfx::Point test_point(49, 49); 1606 LayerImpl* result_layer = 1607 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion( 1608 test_point); 1609 EXPECT_FALSE(result_layer); 1610 1611 // Even though the layer has a touch handler region containing (101, 101), it 1612 // should not be visible there since the root render surface would clamp it. 1613 test_point = gfx::Point(101, 101); 1614 result_layer = 1615 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion( 1616 test_point); 1617 EXPECT_FALSE(result_layer); 1618 1619 // Hit checking for a point inside the layer, but outside the touch handler 1620 // region should return a null pointer. 1621 test_point = gfx::Point(51, 51); 1622 result_layer = 1623 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion( 1624 test_point); 1625 EXPECT_FALSE(result_layer); 1626 1627 // Hit checking for a point inside the touch event handler region should 1628 // return the root layer. 1629 test_point = gfx::Point(61, 61); 1630 result_layer = 1631 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion( 1632 test_point); 1633 ASSERT_TRUE(result_layer); 1634 EXPECT_EQ(12345, result_layer->id()); 1635 1636 test_point = gfx::Point(99, 99); 1637 result_layer = 1638 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion( 1639 test_point); 1640 ASSERT_TRUE(result_layer); 1641 EXPECT_EQ(12345, result_layer->id()); 1642 } 1643 1644 TEST_F(LayerTreeImplTest, 1645 HitCheckingTouchHandlerRegionsForSingleLayerWithScaledContents) { 1646 // A layer's visible content rect is actually in the layer's content space. 1647 // The screen space transform converts from the layer's origin space to screen 1648 // space. This test makes sure that hit testing works correctly accounts for 1649 // the contents scale. A contents scale that is not 1 effectively forces a 1650 // non-identity transform between layer's content space and layer's origin 1651 // space. The hit testing code must take this into account. 1652 // 1653 // To test this, the layer is positioned at (25, 25), and is size (50, 50). If 1654 // contents scale is ignored, then hit checking will mis-interpret the visible 1655 // content rect as being larger than the actual bounds of the layer. 1656 // 1657 scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl().active_tree(), 1); 1658 1659 gfx::Transform identity_matrix; 1660 gfx::Point3F transform_origin; 1661 1662 SetLayerPropertiesForTesting(root.get(), 1663 identity_matrix, 1664 transform_origin, 1665 gfx::PointF(), 1666 gfx::Size(100, 100), 1667 true, 1668 false); 1669 { 1670 Region touch_handler_region(gfx::Rect(10, 10, 30, 30)); 1671 gfx::PointF position(25.f, 25.f); 1672 gfx::Size bounds(50, 50); 1673 scoped_ptr<LayerImpl> test_layer = 1674 LayerImpl::Create(host_impl().active_tree(), 12345); 1675 SetLayerPropertiesForTesting(test_layer.get(), 1676 identity_matrix, 1677 transform_origin, 1678 position, 1679 bounds, 1680 true, 1681 false); 1682 1683 // override content bounds and contents scale 1684 test_layer->SetContentBounds(gfx::Size(100, 100)); 1685 test_layer->SetContentsScale(2, 2); 1686 1687 test_layer->SetDrawsContent(true); 1688 test_layer->SetTouchEventHandlerRegion(touch_handler_region); 1689 root->AddChild(test_layer.Pass()); 1690 } 1691 1692 host_impl().SetViewportSize(root->bounds()); 1693 host_impl().active_tree()->SetRootLayer(root.Pass()); 1694 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree(); 1695 1696 // Sanity check the scenario we just created. 1697 // The visible content rect for test_layer is actually 100x100, even though 1698 // its layout size is 50x50, positioned at 25x25. 1699 LayerImpl* test_layer = 1700 host_impl().active_tree()->root_layer()->children()[0]; 1701 EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100), test_layer->visible_content_rect()); 1702 ASSERT_EQ(1u, RenderSurfaceLayerList().size()); 1703 ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size()); 1704 1705 // Hit checking for a point outside the layer should return a null pointer 1706 // (the root layer does not draw content, so it will not be tested either). 1707 gfx::Point test_point(76, 76); 1708 LayerImpl* result_layer = 1709 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion( 1710 test_point); 1711 EXPECT_FALSE(result_layer); 1712 1713 // Hit checking for a point inside the layer, but outside the touch handler 1714 // region should return a null pointer. 1715 test_point = gfx::Point(26, 26); 1716 result_layer = 1717 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion( 1718 test_point); 1719 EXPECT_FALSE(result_layer); 1720 1721 test_point = gfx::Point(34, 34); 1722 result_layer = 1723 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion( 1724 test_point); 1725 EXPECT_FALSE(result_layer); 1726 1727 test_point = gfx::Point(65, 65); 1728 result_layer = 1729 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion( 1730 test_point); 1731 EXPECT_FALSE(result_layer); 1732 1733 test_point = gfx::Point(74, 74); 1734 result_layer = 1735 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion( 1736 test_point); 1737 EXPECT_FALSE(result_layer); 1738 1739 // Hit checking for a point inside the touch event handler region should 1740 // return the root layer. 1741 test_point = gfx::Point(35, 35); 1742 result_layer = 1743 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion( 1744 test_point); 1745 ASSERT_TRUE(result_layer); 1746 EXPECT_EQ(12345, result_layer->id()); 1747 1748 test_point = gfx::Point(64, 64); 1749 result_layer = 1750 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion( 1751 test_point); 1752 ASSERT_TRUE(result_layer); 1753 EXPECT_EQ(12345, result_layer->id()); 1754 } 1755 1756 TEST_F(LayerTreeImplTest, 1757 HitCheckingTouchHandlerRegionsForSingleLayerWithDeviceScale) { 1758 // The layer's device_scale_factor and page_scale_factor should scale the 1759 // content rect and we should be able to hit the touch handler region by 1760 // scaling the points accordingly. 1761 scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl().active_tree(), 1); 1762 1763 gfx::Transform identity_matrix; 1764 gfx::Point3F transform_origin; 1765 // Set the bounds of the root layer big enough to fit the child when scaled. 1766 SetLayerPropertiesForTesting(root.get(), 1767 identity_matrix, 1768 transform_origin, 1769 gfx::PointF(), 1770 gfx::Size(100, 100), 1771 true, 1772 false); 1773 { 1774 Region touch_handler_region(gfx::Rect(10, 10, 30, 30)); 1775 gfx::PointF position(25.f, 25.f); 1776 gfx::Size bounds(50, 50); 1777 scoped_ptr<LayerImpl> test_layer = 1778 LayerImpl::Create(host_impl().active_tree(), 12345); 1779 SetLayerPropertiesForTesting(test_layer.get(), 1780 identity_matrix, 1781 transform_origin, 1782 position, 1783 bounds, 1784 true, 1785 false); 1786 1787 test_layer->SetDrawsContent(true); 1788 test_layer->SetTouchEventHandlerRegion(touch_handler_region); 1789 root->AddChild(test_layer.Pass()); 1790 } 1791 1792 float device_scale_factor = 3.f; 1793 float page_scale_factor = 5.f; 1794 gfx::Size scaled_bounds_for_root = gfx::ToCeiledSize( 1795 gfx::ScaleSize(root->bounds(), device_scale_factor * page_scale_factor)); 1796 host_impl().SetViewportSize(scaled_bounds_for_root); 1797 1798 host_impl().SetDeviceScaleFactor(device_scale_factor); 1799 host_impl().active_tree()->SetPageScaleFactorAndLimits( 1800 page_scale_factor, page_scale_factor, page_scale_factor); 1801 host_impl().active_tree()->SetRootLayer(root.Pass()); 1802 host_impl().active_tree()->SetViewportLayersFromIds(1, 1, Layer::INVALID_ID); 1803 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree(); 1804 1805 // Sanity check the scenario we just created. 1806 // The visible content rect for test_layer is actually 100x100, even though 1807 // its layout size is 50x50, positioned at 25x25. 1808 LayerImpl* test_layer = 1809 host_impl().active_tree()->root_layer()->children()[0]; 1810 ASSERT_EQ(1u, RenderSurfaceLayerList().size()); 1811 ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size()); 1812 1813 // Check whether the child layer fits into the root after scaled. 1814 EXPECT_RECT_EQ(gfx::Rect(test_layer->content_bounds()), 1815 test_layer->visible_content_rect()); 1816 1817 // Hit checking for a point outside the layer should return a null pointer 1818 // (the root layer does not draw content, so it will not be tested either). 1819 gfx::PointF test_point(76.f, 76.f); 1820 test_point = 1821 gfx::ScalePoint(test_point, device_scale_factor * page_scale_factor); 1822 LayerImpl* result_layer = 1823 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion( 1824 test_point); 1825 EXPECT_FALSE(result_layer); 1826 1827 // Hit checking for a point inside the layer, but outside the touch handler 1828 // region should return a null pointer. 1829 test_point = gfx::Point(26, 26); 1830 test_point = 1831 gfx::ScalePoint(test_point, device_scale_factor * page_scale_factor); 1832 result_layer = 1833 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion( 1834 test_point); 1835 EXPECT_FALSE(result_layer); 1836 1837 test_point = gfx::Point(34, 34); 1838 test_point = 1839 gfx::ScalePoint(test_point, device_scale_factor * page_scale_factor); 1840 result_layer = 1841 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion( 1842 test_point); 1843 EXPECT_FALSE(result_layer); 1844 1845 test_point = gfx::Point(65, 65); 1846 test_point = 1847 gfx::ScalePoint(test_point, device_scale_factor * page_scale_factor); 1848 result_layer = 1849 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion( 1850 test_point); 1851 EXPECT_FALSE(result_layer); 1852 1853 test_point = gfx::Point(74, 74); 1854 test_point = 1855 gfx::ScalePoint(test_point, device_scale_factor * page_scale_factor); 1856 result_layer = 1857 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion( 1858 test_point); 1859 EXPECT_FALSE(result_layer); 1860 1861 // Hit checking for a point inside the touch event handler region should 1862 // return the root layer. 1863 test_point = gfx::Point(35, 35); 1864 test_point = 1865 gfx::ScalePoint(test_point, device_scale_factor * page_scale_factor); 1866 result_layer = 1867 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion( 1868 test_point); 1869 ASSERT_TRUE(result_layer); 1870 EXPECT_EQ(12345, result_layer->id()); 1871 1872 test_point = gfx::Point(64, 64); 1873 test_point = 1874 gfx::ScalePoint(test_point, device_scale_factor * page_scale_factor); 1875 result_layer = 1876 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion( 1877 test_point); 1878 ASSERT_TRUE(result_layer); 1879 EXPECT_EQ(12345, result_layer->id()); 1880 } 1881 1882 TEST_F(LayerTreeImplTest, HitCheckingTouchHandlerRegionsForSimpleClippedLayer) { 1883 // Test that hit-checking will only work for the visible portion of a layer, 1884 // and not the entire layer bounds. Here we just test the simple axis-aligned 1885 // case. 1886 gfx::Transform identity_matrix; 1887 gfx::Point3F transform_origin; 1888 1889 scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl().active_tree(), 1); 1890 SetLayerPropertiesForTesting(root.get(), 1891 identity_matrix, 1892 transform_origin, 1893 gfx::PointF(), 1894 gfx::Size(100, 100), 1895 true, 1896 false); 1897 { 1898 scoped_ptr<LayerImpl> clipping_layer = 1899 LayerImpl::Create(host_impl().active_tree(), 123); 1900 // this layer is positioned, and hit testing should correctly know where the 1901 // layer is located. 1902 gfx::PointF position(25.f, 25.f); 1903 gfx::Size bounds(50, 50); 1904 SetLayerPropertiesForTesting(clipping_layer.get(), 1905 identity_matrix, 1906 transform_origin, 1907 position, 1908 bounds, 1909 true, 1910 false); 1911 clipping_layer->SetMasksToBounds(true); 1912 1913 scoped_ptr<LayerImpl> child = 1914 LayerImpl::Create(host_impl().active_tree(), 456); 1915 Region touch_handler_region(gfx::Rect(10, 10, 50, 50)); 1916 position = gfx::PointF(-50.f, -50.f); 1917 bounds = gfx::Size(300, 300); 1918 SetLayerPropertiesForTesting(child.get(), 1919 identity_matrix, 1920 transform_origin, 1921 position, 1922 bounds, 1923 true, 1924 false); 1925 child->SetDrawsContent(true); 1926 child->SetTouchEventHandlerRegion(touch_handler_region); 1927 clipping_layer->AddChild(child.Pass()); 1928 root->AddChild(clipping_layer.Pass()); 1929 } 1930 1931 host_impl().SetViewportSize(root->bounds()); 1932 host_impl().active_tree()->SetRootLayer(root.Pass()); 1933 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree(); 1934 1935 // Sanity check the scenario we just created. 1936 ASSERT_EQ(1u, RenderSurfaceLayerList().size()); 1937 ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size()); 1938 ASSERT_EQ(456, root_layer()->render_surface()->layer_list().at(0)->id()); 1939 1940 // Hit checking for a point outside the layer should return a null pointer. 1941 // Despite the child layer being very large, it should be clipped to the root 1942 // layer's bounds. 1943 gfx::Point test_point(24, 24); 1944 LayerImpl* result_layer = 1945 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion( 1946 test_point); 1947 EXPECT_FALSE(result_layer); 1948 1949 // Hit checking for a point inside the layer, but outside the touch handler 1950 // region should return a null pointer. 1951 test_point = gfx::Point(35, 35); 1952 result_layer = 1953 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion( 1954 test_point); 1955 EXPECT_FALSE(result_layer); 1956 1957 test_point = gfx::Point(74, 74); 1958 result_layer = 1959 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion( 1960 test_point); 1961 EXPECT_FALSE(result_layer); 1962 1963 // Hit checking for a point inside the touch event handler region should 1964 // return the root layer. 1965 test_point = gfx::Point(25, 25); 1966 result_layer = 1967 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion( 1968 test_point); 1969 ASSERT_TRUE(result_layer); 1970 EXPECT_EQ(456, result_layer->id()); 1971 1972 test_point = gfx::Point(34, 34); 1973 result_layer = 1974 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion( 1975 test_point); 1976 ASSERT_TRUE(result_layer); 1977 EXPECT_EQ(456, result_layer->id()); 1978 } 1979 1980 TEST_F(LayerTreeImplTest, HitCheckingTouchHandlerOverlappingRegions) { 1981 gfx::Transform identity_matrix; 1982 gfx::Point3F transform_origin; 1983 1984 scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl().active_tree(), 1); 1985 SetLayerPropertiesForTesting(root.get(), 1986 identity_matrix, 1987 transform_origin, 1988 gfx::PointF(), 1989 gfx::Size(100, 100), 1990 true, 1991 false); 1992 { 1993 scoped_ptr<LayerImpl> touch_layer = 1994 LayerImpl::Create(host_impl().active_tree(), 123); 1995 // this layer is positioned, and hit testing should correctly know where the 1996 // layer is located. 1997 gfx::PointF position; 1998 gfx::Size bounds(50, 50); 1999 SetLayerPropertiesForTesting(touch_layer.get(), 2000 identity_matrix, 2001 transform_origin, 2002 position, 2003 bounds, 2004 true, 2005 false); 2006 touch_layer->SetDrawsContent(true); 2007 touch_layer->SetTouchEventHandlerRegion(gfx::Rect(0, 0, 50, 50)); 2008 root->AddChild(touch_layer.Pass()); 2009 } 2010 2011 { 2012 scoped_ptr<LayerImpl> notouch_layer = 2013 LayerImpl::Create(host_impl().active_tree(), 1234); 2014 // this layer is positioned, and hit testing should correctly know where the 2015 // layer is located. 2016 gfx::PointF position(0, 25); 2017 gfx::Size bounds(50, 50); 2018 SetLayerPropertiesForTesting(notouch_layer.get(), 2019 identity_matrix, 2020 transform_origin, 2021 position, 2022 bounds, 2023 true, 2024 false); 2025 notouch_layer->SetDrawsContent(true); 2026 root->AddChild(notouch_layer.Pass()); 2027 } 2028 2029 host_impl().SetViewportSize(root->bounds()); 2030 host_impl().active_tree()->SetRootLayer(root.Pass()); 2031 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree(); 2032 2033 // Sanity check the scenario we just created. 2034 ASSERT_EQ(1u, RenderSurfaceLayerList().size()); 2035 ASSERT_EQ(2u, root_layer()->render_surface()->layer_list().size()); 2036 ASSERT_EQ(123, root_layer()->render_surface()->layer_list().at(0)->id()); 2037 ASSERT_EQ(1234, root_layer()->render_surface()->layer_list().at(1)->id()); 2038 2039 gfx::Point test_point(35, 35); 2040 LayerImpl* result_layer = 2041 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion( 2042 test_point); 2043 2044 // We should have passed through the no-touch layer and found the layer 2045 // behind it. 2046 EXPECT_TRUE(result_layer); 2047 2048 host_impl().active_tree()->LayerById(1234)->SetContentsOpaque(true); 2049 result_layer = 2050 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion( 2051 test_point); 2052 2053 // Even with an opaque layer in the middle, we should still find the layer 2054 // with 2055 // the touch handler behind it (since we can't assume that opaque layers are 2056 // opaque to hit testing). 2057 EXPECT_TRUE(result_layer); 2058 2059 test_point = gfx::Point(35, 15); 2060 result_layer = 2061 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion( 2062 test_point); 2063 ASSERT_TRUE(result_layer); 2064 EXPECT_EQ(123, result_layer->id()); 2065 2066 test_point = gfx::Point(35, 65); 2067 result_layer = 2068 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion( 2069 test_point); 2070 EXPECT_FALSE(result_layer); 2071 } 2072 2073 TEST_F(LayerTreeImplTest, SelectionBoundsForSingleLayer) { 2074 int root_layer_id = 12345; 2075 scoped_ptr<LayerImpl> root = 2076 LayerImpl::Create(host_impl().active_tree(), root_layer_id); 2077 2078 gfx::Transform identity_matrix; 2079 gfx::Point3F transform_origin; 2080 gfx::PointF position; 2081 gfx::Size bounds(100, 100); 2082 SetLayerPropertiesForTesting(root.get(), 2083 identity_matrix, 2084 transform_origin, 2085 position, 2086 bounds, 2087 true, 2088 false); 2089 root->SetDrawsContent(true); 2090 2091 host_impl().SetViewportSize(root->bounds()); 2092 host_impl().active_tree()->SetRootLayer(root.Pass()); 2093 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree(); 2094 2095 // Sanity check the scenario we just created. 2096 ASSERT_EQ(1u, RenderSurfaceLayerList().size()); 2097 ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size()); 2098 2099 LayerSelectionBound left_input; 2100 left_input.type = SELECTION_BOUND_LEFT; 2101 left_input.edge_top = gfx::PointF(10, 10); 2102 left_input.edge_bottom = gfx::PointF(10, 20); 2103 left_input.layer_id = root_layer_id; 2104 2105 LayerSelectionBound right_input; 2106 right_input.type = SELECTION_BOUND_RIGHT; 2107 right_input.edge_top = gfx::PointF(50, 10); 2108 right_input.edge_bottom = gfx::PointF(50, 30); 2109 right_input.layer_id = root_layer_id; 2110 2111 ViewportSelectionBound left_output, right_output; 2112 2113 // Empty input bounds should produce empty output bounds. 2114 host_impl().active_tree()->GetViewportSelection(&left_output, &right_output); 2115 EXPECT_EQ(ViewportSelectionBound(), left_output); 2116 EXPECT_EQ(ViewportSelectionBound(), right_output); 2117 2118 // Selection bounds should produce distinct left and right bounds. 2119 host_impl().active_tree()->RegisterSelection(left_input, right_input); 2120 host_impl().active_tree()->GetViewportSelection(&left_output, &right_output); 2121 EXPECT_EQ(left_input.type, left_output.type); 2122 EXPECT_EQ(left_input.edge_bottom, left_output.edge_bottom); 2123 EXPECT_EQ(left_input.edge_top, left_output.edge_top); 2124 EXPECT_TRUE(left_output.visible); 2125 EXPECT_EQ(right_input.type, right_output.type); 2126 EXPECT_EQ(right_input.edge_bottom, right_output.edge_bottom); 2127 EXPECT_EQ(right_input.edge_top, right_output.edge_top); 2128 EXPECT_TRUE(right_output.visible); 2129 2130 // Insertion bounds should produce identical left and right bounds. 2131 LayerSelectionBound insertion_input; 2132 insertion_input.type = SELECTION_BOUND_CENTER; 2133 insertion_input.edge_top = gfx::PointF(15, 10); 2134 insertion_input.edge_bottom = gfx::PointF(15, 30); 2135 insertion_input.layer_id = root_layer_id; 2136 host_impl().active_tree()->RegisterSelection(insertion_input, 2137 LayerSelectionBound()); 2138 host_impl().active_tree()->GetViewportSelection(&left_output, &right_output); 2139 EXPECT_EQ(insertion_input.type, left_output.type); 2140 EXPECT_EQ(insertion_input.edge_bottom, left_output.edge_bottom); 2141 EXPECT_EQ(insertion_input.edge_top, left_output.edge_top); 2142 EXPECT_TRUE(left_output.visible); 2143 EXPECT_EQ(left_output, right_output); 2144 } 2145 2146 TEST_F(LayerTreeImplTest, SelectionBoundsForPartialOccludedLayers) { 2147 int root_layer_id = 12345; 2148 int clip_layer_id = 1234; 2149 int clipped_layer_id = 123; 2150 scoped_ptr<LayerImpl> root = 2151 LayerImpl::Create(host_impl().active_tree(), root_layer_id); 2152 root->SetDrawsContent(true); 2153 2154 gfx::Transform identity_matrix; 2155 gfx::Point3F transform_origin; 2156 gfx::PointF position; 2157 gfx::Size bounds(100, 100); 2158 SetLayerPropertiesForTesting(root.get(), 2159 identity_matrix, 2160 transform_origin, 2161 position, 2162 bounds, 2163 true, 2164 false); 2165 2166 gfx::Vector2dF clipping_offset(10, 10); 2167 { 2168 scoped_ptr<LayerImpl> clipping_layer = 2169 LayerImpl::Create(host_impl().active_tree(), clip_layer_id); 2170 // The clipping layer should occlude the right selection bound. 2171 gfx::PointF position = gfx::PointF() + clipping_offset; 2172 gfx::Size bounds(50, 50); 2173 SetLayerPropertiesForTesting(clipping_layer.get(), 2174 identity_matrix, 2175 transform_origin, 2176 position, 2177 bounds, 2178 true, 2179 false); 2180 clipping_layer->SetMasksToBounds(true); 2181 2182 scoped_ptr<LayerImpl> clipped_layer = 2183 LayerImpl::Create(host_impl().active_tree(), clipped_layer_id); 2184 position = gfx::PointF(); 2185 bounds = gfx::Size(100, 100); 2186 SetLayerPropertiesForTesting(clipped_layer.get(), 2187 identity_matrix, 2188 transform_origin, 2189 position, 2190 bounds, 2191 true, 2192 false); 2193 clipped_layer->SetDrawsContent(true); 2194 clipping_layer->AddChild(clipped_layer.Pass()); 2195 root->AddChild(clipping_layer.Pass()); 2196 } 2197 2198 host_impl().SetViewportSize(root->bounds()); 2199 host_impl().active_tree()->SetRootLayer(root.Pass()); 2200 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree(); 2201 2202 // Sanity check the scenario we just created. 2203 ASSERT_EQ(1u, RenderSurfaceLayerList().size()); 2204 2205 LayerSelectionBound left_input; 2206 left_input.type = SELECTION_BOUND_LEFT; 2207 left_input.edge_top = gfx::PointF(25, 10); 2208 left_input.edge_bottom = gfx::PointF(25, 30); 2209 left_input.layer_id = clipped_layer_id; 2210 2211 LayerSelectionBound right_input; 2212 right_input.type = SELECTION_BOUND_RIGHT; 2213 right_input.edge_top = gfx::PointF(75, 10); 2214 right_input.edge_bottom = gfx::PointF(75, 30); 2215 right_input.layer_id = clipped_layer_id; 2216 host_impl().active_tree()->RegisterSelection(left_input, right_input); 2217 2218 // The left bound should be occluded by the clip layer. 2219 ViewportSelectionBound left_output, right_output; 2220 host_impl().active_tree()->GetViewportSelection(&left_output, &right_output); 2221 EXPECT_EQ(left_input.type, left_output.type); 2222 gfx::PointF expected_left_output_top = left_input.edge_top; 2223 gfx::PointF expected_left_output_bottom = left_input.edge_bottom; 2224 expected_left_output_top.Offset(clipping_offset.x(), clipping_offset.y()); 2225 expected_left_output_bottom.Offset(clipping_offset.x(), clipping_offset.y()); 2226 EXPECT_EQ(expected_left_output_top, left_output.edge_top); 2227 EXPECT_EQ(expected_left_output_bottom, left_output.edge_bottom); 2228 EXPECT_TRUE(left_output.visible); 2229 EXPECT_EQ(right_input.type, right_output.type); 2230 gfx::PointF expected_right_output_top = right_input.edge_top; 2231 gfx::PointF expected_right_output_bottom = right_input.edge_bottom; 2232 expected_right_output_bottom.Offset(clipping_offset.x(), clipping_offset.y()); 2233 expected_right_output_top.Offset(clipping_offset.x(), clipping_offset.y()); 2234 EXPECT_EQ(expected_right_output_top, right_output.edge_top); 2235 EXPECT_EQ(expected_right_output_bottom, right_output.edge_bottom); 2236 EXPECT_FALSE(right_output.visible); 2237 2238 // Handles outside the viewport bounds should be marked invisible. 2239 left_input.edge_top = gfx::PointF(-25, 0); 2240 left_input.edge_bottom = gfx::PointF(-25, 20); 2241 host_impl().active_tree()->RegisterSelection(left_input, right_input); 2242 host_impl().active_tree()->GetViewportSelection(&left_output, &right_output); 2243 EXPECT_FALSE(left_output.visible); 2244 2245 left_input.edge_top = gfx::PointF(0, -25); 2246 left_input.edge_bottom = gfx::PointF(0, -5); 2247 host_impl().active_tree()->RegisterSelection(left_input, right_input); 2248 host_impl().active_tree()->GetViewportSelection(&left_output, &right_output); 2249 EXPECT_FALSE(left_output.visible); 2250 2251 // If the handle bottom is partially visible, the handle is marked visible. 2252 left_input.edge_top = gfx::PointF(0, -20); 2253 left_input.edge_bottom = gfx::PointF(0, 1); 2254 host_impl().active_tree()->RegisterSelection(left_input, right_input); 2255 host_impl().active_tree()->GetViewportSelection(&left_output, &right_output); 2256 EXPECT_TRUE(left_output.visible); 2257 } 2258 2259 TEST_F(LayerTreeImplTest, SelectionBoundsForScaledLayers) { 2260 int root_layer_id = 1; 2261 int sub_layer_id = 2; 2262 scoped_ptr<LayerImpl> root = 2263 LayerImpl::Create(host_impl().active_tree(), root_layer_id); 2264 root->SetDrawsContent(true); 2265 2266 gfx::Transform identity_matrix; 2267 gfx::Point3F transform_origin; 2268 gfx::PointF position; 2269 gfx::Size bounds(100, 100); 2270 SetLayerPropertiesForTesting(root.get(), 2271 identity_matrix, 2272 transform_origin, 2273 position, 2274 bounds, 2275 true, 2276 false); 2277 2278 gfx::Vector2dF sub_layer_offset(10, 0); 2279 { 2280 scoped_ptr<LayerImpl> sub_layer = 2281 LayerImpl::Create(host_impl().active_tree(), sub_layer_id); 2282 gfx::PointF position = gfx::PointF() + sub_layer_offset; 2283 gfx::Size bounds(50, 50); 2284 SetLayerPropertiesForTesting(sub_layer.get(), 2285 identity_matrix, 2286 transform_origin, 2287 position, 2288 bounds, 2289 true, 2290 false); 2291 sub_layer->SetDrawsContent(true); 2292 root->AddChild(sub_layer.Pass()); 2293 } 2294 2295 float device_scale_factor = 3.f; 2296 float page_scale_factor = 5.f; 2297 gfx::Size scaled_bounds_for_root = gfx::ToCeiledSize( 2298 gfx::ScaleSize(root->bounds(), device_scale_factor * page_scale_factor)); 2299 host_impl().SetViewportSize(scaled_bounds_for_root); 2300 2301 host_impl().SetDeviceScaleFactor(device_scale_factor); 2302 host_impl().active_tree()->SetPageScaleFactorAndLimits( 2303 page_scale_factor, page_scale_factor, page_scale_factor); 2304 host_impl().active_tree()->SetRootLayer(root.Pass()); 2305 host_impl().active_tree()->SetViewportLayersFromIds(1, 1, Layer::INVALID_ID); 2306 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree(); 2307 2308 // Sanity check the scenario we just created. 2309 ASSERT_EQ(1u, RenderSurfaceLayerList().size()); 2310 2311 LayerSelectionBound left_input; 2312 left_input.type = SELECTION_BOUND_LEFT; 2313 left_input.edge_top = gfx::PointF(10, 10); 2314 left_input.edge_bottom = gfx::PointF(10, 30); 2315 left_input.layer_id = root_layer_id; 2316 2317 LayerSelectionBound right_input; 2318 right_input.type = SELECTION_BOUND_RIGHT; 2319 right_input.edge_top = gfx::PointF(0, 0); 2320 right_input.edge_bottom = gfx::PointF(0, 20); 2321 right_input.layer_id = sub_layer_id; 2322 host_impl().active_tree()->RegisterSelection(left_input, right_input); 2323 2324 // The viewport bounds should be properly scaled by the page scale, but should 2325 // remain in DIP coordinates. 2326 ViewportSelectionBound left_output, right_output; 2327 host_impl().active_tree()->GetViewportSelection(&left_output, &right_output); 2328 EXPECT_EQ(left_input.type, left_output.type); 2329 gfx::PointF expected_left_output_top = left_input.edge_top; 2330 gfx::PointF expected_left_output_bottom = left_input.edge_bottom; 2331 expected_left_output_top.Scale(page_scale_factor); 2332 expected_left_output_bottom.Scale(page_scale_factor); 2333 EXPECT_EQ(left_input.edge_top, left_output.edge_top); 2334 EXPECT_EQ(left_input.edge_bottom, left_output.edge_bottom); 2335 EXPECT_TRUE(left_output.visible); 2336 EXPECT_EQ(right_input.type, right_output.type); 2337 2338 gfx::PointF expected_right_output_top = right_input.edge_top; 2339 gfx::PointF expected_right_output_bottom = right_input.edge_bottom; 2340 expected_right_output_top.Offset(sub_layer_offset.x(), sub_layer_offset.y()); 2341 expected_right_output_bottom.Offset(sub_layer_offset.x(), 2342 sub_layer_offset.y()); 2343 expected_right_output_top.Scale(page_scale_factor); 2344 expected_right_output_bottom.Scale(page_scale_factor); 2345 EXPECT_EQ(expected_right_output_top, right_output.edge_top); 2346 EXPECT_EQ(expected_right_output_bottom, right_output.edge_bottom); 2347 EXPECT_TRUE(right_output.visible); 2348 } 2349 2350 TEST_F(LayerTreeImplTest, NumLayersTestOne) { 2351 EXPECT_EQ(0u, host_impl().active_tree()->NumLayers()); 2352 scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl().active_tree(), 1); 2353 EXPECT_EQ(1u, host_impl().active_tree()->NumLayers()); 2354 } 2355 2356 TEST_F(LayerTreeImplTest, NumLayersSmallTree) { 2357 EXPECT_EQ(0u, host_impl().active_tree()->NumLayers()); 2358 scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl().active_tree(), 1); 2359 root->AddChild(LayerImpl::Create(host_impl().active_tree(), 2)); 2360 root->AddChild(LayerImpl::Create(host_impl().active_tree(), 3)); 2361 root->child_at(1)->AddChild(LayerImpl::Create(host_impl().active_tree(), 4)); 2362 EXPECT_EQ(4u, host_impl().active_tree()->NumLayers()); 2363 } 2364 2365 } // namespace 2366 } // namespace cc 2367