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.
5 #include "cc/trees/layer_tree_impl.h"
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"
21 class LayerTreeImplTest
: public LayerTreeHostCommonTest
{
24 LayerTreeSettings settings
;
25 settings
.layer_transforms_should_scale_layer_contents
= true;
27 new FakeLayerTreeHostImpl(settings
, &proxy_
, &shared_bitmap_manager_
));
28 EXPECT_TRUE(host_impl_
->InitializeRenderer(
29 FakeOutputSurface::Create3d().PassAs
<OutputSurface
>()));
32 FakeLayerTreeHostImpl
& host_impl() { return *host_impl_
; }
34 LayerImpl
* root_layer() { return host_impl_
->active_tree()->root_layer(); }
36 const LayerImplList
& RenderSurfaceLayerList() const {
37 return host_impl_
->active_tree()->RenderSurfaceLayerList();
41 TestSharedBitmapManager shared_bitmap_manager_
;
43 scoped_ptr
<FakeLayerTreeHostImpl
> host_impl_
;
46 TEST_F(LayerTreeImplTest
, HitTestingForSingleLayer
) {
47 scoped_ptr
<LayerImpl
> root
=
48 LayerImpl::Create(host_impl().active_tree(), 12345);
50 gfx::Transform identity_matrix
;
51 gfx::Point3F transform_origin
;
53 gfx::Size
bounds(100, 100);
54 SetLayerPropertiesForTesting(root
.get(),
61 root
->SetDrawsContent(true);
63 host_impl().SetViewportSize(root
->bounds());
64 host_impl().active_tree()->SetRootLayer(root
.Pass());
65 host_impl().active_tree()->UpdateDrawProperties();
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());
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
);
77 test_point
= gfx::Point(-1, -1);
79 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
80 EXPECT_FALSE(result_layer
);
82 // Hit testing for a point inside should return the root layer.
83 test_point
= gfx::Point(1, 1);
85 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
86 ASSERT_TRUE(result_layer
);
87 EXPECT_EQ(12345, result_layer
->id());
89 test_point
= gfx::Point(99, 99);
91 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
92 ASSERT_TRUE(result_layer
);
93 EXPECT_EQ(12345, result_layer
->id());
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);
102 gfx::Transform identity_matrix
;
103 gfx::Point3F transform_origin
;
104 gfx::PointF position
;
105 gfx::Size
bounds(100, 100);
106 SetLayerPropertiesForTesting(root
.get(),
113 root
->SetDrawsContent(true);
115 // Create hud and add it as a child of root.
116 gfx::Size
hud_bounds(200, 200);
117 SetLayerPropertiesForTesting(hud
.get(),
124 hud
->SetDrawsContent(true);
126 host_impl().active_tree()->set_hud_layer(hud
.get());
127 root
->AddChild(hud
.PassAs
<LayerImpl
>());
129 host_impl().SetViewportSize(hud_bounds
);
130 host_impl().active_tree()->SetRootLayer(root
.Pass());
131 host_impl().active_tree()->UpdateDrawProperties();
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());
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
);
143 test_point
= gfx::Point(-1, -1);
145 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
146 EXPECT_FALSE(result_layer
);
148 // Hit testing for a point inside should return the root layer, never the HUD
150 test_point
= gfx::Point(1, 1);
152 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
153 ASSERT_TRUE(result_layer
);
154 EXPECT_EQ(12345, result_layer
->id());
156 test_point
= gfx::Point(99, 99);
158 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
159 ASSERT_TRUE(result_layer
);
160 EXPECT_EQ(12345, result_layer
->id());
163 TEST_F(LayerTreeImplTest
, HitTestingForUninvertibleTransform
) {
164 scoped_ptr
<LayerImpl
> root
=
165 LayerImpl::Create(host_impl().active_tree(), 12345);
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());
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
,
185 root
->SetDrawsContent(true);
187 host_impl().SetViewportSize(root
->bounds());
188 host_impl().active_tree()->SetRootLayer(root
.Pass());
189 host_impl().active_tree()->UpdateDrawProperties();
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());
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
);
203 test_point
= gfx::Point(10, 10);
205 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
206 EXPECT_FALSE(result_layer
);
208 test_point
= gfx::Point(10, 30);
210 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
211 EXPECT_FALSE(result_layer
);
213 test_point
= gfx::Point(50, 50);
215 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
216 EXPECT_FALSE(result_layer
);
218 test_point
= gfx::Point(67, 48);
220 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
221 EXPECT_FALSE(result_layer
);
223 test_point
= gfx::Point(99, 99);
225 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
226 EXPECT_FALSE(result_layer
);
228 test_point
= gfx::Point(-1, -1);
230 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
231 EXPECT_FALSE(result_layer
);
234 TEST_F(LayerTreeImplTest
, HitTestingForSinglePositionedLayer
) {
235 scoped_ptr
<LayerImpl
> root
=
236 LayerImpl::Create(host_impl().active_tree(), 12345);
238 gfx::Transform identity_matrix
;
239 gfx::Point3F transform_origin
;
240 // this layer is positioned, and hit testing should correctly know where the
242 gfx::PointF
position(50.f
, 50.f
);
243 gfx::Size
bounds(100, 100);
244 SetLayerPropertiesForTesting(root
.get(),
251 root
->SetDrawsContent(true);
253 host_impl().SetViewportSize(root
->bounds());
254 host_impl().active_tree()->SetRootLayer(root
.Pass());
255 host_impl().active_tree()->UpdateDrawProperties();
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());
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
);
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);
271 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
272 EXPECT_FALSE(result_layer
);
274 // Hit testing for a point inside should return the root layer.
275 test_point
= gfx::Point(51, 51);
277 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
278 ASSERT_TRUE(result_layer
);
279 EXPECT_EQ(12345, result_layer
->id());
281 test_point
= gfx::Point(99, 99);
283 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
284 ASSERT_TRUE(result_layer
);
285 EXPECT_EQ(12345, result_layer
->id());
288 TEST_F(LayerTreeImplTest
, HitTestingForSingleRotatedLayer
) {
289 scoped_ptr
<LayerImpl
> root
=
290 LayerImpl::Create(host_impl().active_tree(), 12345);
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
,
307 root
->SetDrawsContent(true);
309 host_impl().SetViewportSize(root
->bounds());
310 host_impl().active_tree()->SetRootLayer(root
.Pass());
311 host_impl().active_tree()->UpdateDrawProperties();
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());
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
);
325 test_point
= gfx::Point(1, 1);
327 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
328 EXPECT_FALSE(result_layer
);
330 // Hit testing for a point inside should return the root layer.
331 test_point
= gfx::Point(1, 50);
333 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
334 ASSERT_TRUE(result_layer
);
335 EXPECT_EQ(12345, result_layer
->id());
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);
341 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
342 ASSERT_FALSE(result_layer
);
344 test_point
= gfx::Point(-1, 50);
346 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
347 ASSERT_FALSE(result_layer
);
350 TEST_F(LayerTreeImplTest
, HitTestingForSinglePerspectiveLayer
) {
351 scoped_ptr
<LayerImpl
> root
=
352 LayerImpl::Create(host_impl().active_tree(), 12345);
354 gfx::Transform identity_matrix
;
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);
365 gfx::Point3F transform_origin
;
366 gfx::PointF position
;
367 gfx::Size
bounds(100, 100);
368 SetLayerPropertiesForTesting(
370 perspective_projection_about_center
* translation_by_z
,
376 root
->SetDrawsContent(true);
378 host_impl().SetViewportSize(root
->bounds());
379 host_impl().active_tree()->SetRootLayer(root
.Pass());
380 host_impl().active_tree()->UpdateDrawProperties();
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());
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
);
394 test_point
= gfx::Point(76, 76);
396 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
397 EXPECT_FALSE(result_layer
);
399 // Hit testing for a point inside should return the root layer.
400 test_point
= gfx::Point(26, 26);
402 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
403 ASSERT_TRUE(result_layer
);
404 EXPECT_EQ(12345, result_layer
->id());
406 test_point
= gfx::Point(74, 74);
408 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
409 ASSERT_TRUE(result_layer
);
410 EXPECT_EQ(12345, result_layer
->id());
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.
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.
425 scoped_ptr
<LayerImpl
> root
= LayerImpl::Create(host_impl().active_tree(), 1);
427 gfx::Transform identity_matrix
;
428 gfx::Point3F transform_origin
;
430 SetLayerPropertiesForTesting(root
.get(),
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(),
450 // override content bounds and contents scale
451 test_layer
->SetContentBounds(gfx::Size(100, 100));
452 test_layer
->SetContentsScale(2, 2);
454 test_layer
->SetDrawsContent(true);
455 root
->AddChild(test_layer
.Pass());
458 host_impl().SetViewportSize(root
->bounds());
459 host_impl().active_tree()->SetRootLayer(root
.Pass());
460 host_impl().active_tree()->UpdateDrawProperties();
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());
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
);
478 test_point
= gfx::Point(24, 24);
480 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
481 EXPECT_FALSE(result_layer
);
483 test_point
= gfx::Point(76, 76);
485 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
486 EXPECT_FALSE(result_layer
);
488 // Hit testing for a point inside should return the test layer.
489 test_point
= gfx::Point(26, 26);
491 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
492 ASSERT_TRUE(result_layer
);
493 EXPECT_EQ(12345, result_layer
->id());
495 test_point
= gfx::Point(74, 74);
497 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
498 ASSERT_TRUE(result_layer
);
499 EXPECT_EQ(12345, result_layer
->id());
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
506 gfx::Transform identity_matrix
;
507 gfx::Point3F transform_origin
;
509 scoped_ptr
<LayerImpl
> root
= LayerImpl::Create(host_impl().active_tree(), 1);
510 SetLayerPropertiesForTesting(root
.get(),
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
522 gfx::PointF
position(25.f
, 25.f
);
523 gfx::Size
bounds(50, 50);
524 SetLayerPropertiesForTesting(clipping_layer
.get(),
531 clipping_layer
->SetMasksToBounds(true);
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(),
544 child
->SetDrawsContent(true);
545 clipping_layer
->AddChild(child
.Pass());
546 root
->AddChild(clipping_layer
.Pass());
549 host_impl().SetViewportSize(root
->bounds());
550 host_impl().active_tree()->SetRootLayer(root
.Pass());
551 host_impl().active_tree()->UpdateDrawProperties();
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());
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
561 gfx::Point
test_point(24, 24);
562 LayerImpl
* result_layer
=
563 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
564 EXPECT_FALSE(result_layer
);
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);
570 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
571 EXPECT_FALSE(result_layer
);
573 // Hit testing for a point inside should return the child layer.
574 test_point
= gfx::Point(26, 26);
576 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
577 ASSERT_TRUE(result_layer
);
578 EXPECT_EQ(456, result_layer
->id());
580 test_point
= gfx::Point(74, 74);
582 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
583 ASSERT_TRUE(result_layer
);
584 EXPECT_EQ(456, result_layer
->id());
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.
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.
598 scoped_ptr
<LayerImpl
> root
=
599 LayerImpl::Create(host_impl().active_tree(), 123);
601 gfx::Transform identity_matrix
;
602 gfx::Point3F transform_origin
;
603 gfx::PointF position
;
604 gfx::Size
bounds(100, 100);
605 SetLayerPropertiesForTesting(root
.get(),
612 root
->SetMasksToBounds(true);
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);
621 position
= gfx::PointF(10.f
, 10.f
);
622 bounds
= gfx::Size(80, 80);
623 SetLayerPropertiesForTesting(child
.get(),
630 child
->SetMasksToBounds(true);
632 gfx::Transform rotation45_degrees_about_corner
;
633 rotation45_degrees_about_corner
.RotateAboutZAxis(45.0);
635 // remember, positioned with respect to its parent which is already at 10,
637 position
= gfx::PointF();
639 gfx::Size(200, 200); // to ensure it covers at least sqrt(2) * 100.
640 SetLayerPropertiesForTesting(grand_child
.get(),
641 rotation45_degrees_about_corner
,
647 grand_child
->SetMasksToBounds(true);
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
,
667 rotated_leaf
->SetDrawsContent(true);
669 grand_child
->AddChild(rotated_leaf
.Pass());
670 child
->AddChild(grand_child
.Pass());
671 root
->AddChild(child
.Pass());
674 host_impl().SetViewportSize(root
->bounds());
675 host_impl().active_tree()->SetRootLayer(root
.Pass());
676 host_impl().active_tree()->UpdateDrawProperties();
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());
684 RenderSurfaceLayerList().at(0)->render_surface()->layer_list().size());
686 RenderSurfaceLayerList()
691 ->id()); // grand_child's surface.
694 RenderSurfaceLayerList().at(1)->render_surface()->layer_list().size());
697 RenderSurfaceLayerList()[1]->render_surface()->layer_list().at(0)->id());
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
);
706 // Closer inwards from the bottom left will overlap the layer.
707 test_point
= gfx::Point(25, 75);
709 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
710 ASSERT_TRUE(result_layer
);
711 EXPECT_EQ(2468, result_layer
->id());
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);
720 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
721 EXPECT_FALSE(result_layer
);
723 // (11, 50) is inside the layer and within the clipped area.
724 test_point
= gfx::Point(11, 50);
726 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
727 ASSERT_TRUE(result_layer
);
728 EXPECT_EQ(2468, result_layer
->id());
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);
734 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
735 EXPECT_FALSE(result_layer
);
737 // Around the middle, just to the left and down, should successfully hit the
739 test_point
= gfx::Point(49, 51);
741 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
742 ASSERT_TRUE(result_layer
);
743 EXPECT_EQ(2468, result_layer
->id());
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
;
752 scoped_ptr
<LayerImpl
> root
= LayerImpl::Create(host_impl().active_tree(), 1);
753 SetLayerPropertiesForTesting(root
.get(),
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
765 gfx::PointF
position(10.f
, 10.f
);
766 gfx::Size
bounds(50, 50);
767 SetLayerPropertiesForTesting(intermediate_layer
.get(),
774 // Sanity check the intermediate layer should not clip.
775 ASSERT_FALSE(intermediate_layer
->masks_to_bounds());
776 ASSERT_FALSE(intermediate_layer
->mask_layer());
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(),
792 child
->SetDrawsContent(true);
793 intermediate_layer
->AddChild(child
.Pass());
794 root
->AddChild(intermediate_layer
.Pass());
797 host_impl().SetViewportSize(root
->bounds());
798 host_impl().active_tree()->SetRootLayer(root
.Pass());
799 host_impl().active_tree()->UpdateDrawProperties();
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());
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
);
812 test_point
= gfx::Point(91, 91);
814 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
815 EXPECT_FALSE(result_layer
);
817 // Hit testing for a point inside should return the child layer.
818 test_point
= gfx::Point(71, 71);
820 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
821 ASSERT_TRUE(result_layer
);
822 EXPECT_EQ(456, result_layer
->id());
824 test_point
= gfx::Point(89, 89);
826 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
827 ASSERT_TRUE(result_layer
);
828 EXPECT_EQ(456, result_layer
->id());
831 TEST_F(LayerTreeImplTest
, HitTestingForMultipleLayers
) {
832 scoped_ptr
<LayerImpl
> root
= LayerImpl::Create(host_impl().active_tree(), 1);
834 gfx::Transform identity_matrix
;
835 gfx::Point3F transform_origin
;
836 gfx::PointF position
;
837 gfx::Size
bounds(100, 100);
838 SetLayerPropertiesForTesting(root
.get(),
845 root
->SetDrawsContent(true);
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
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);
860 position
= gfx::PointF(10.f
, 10.f
);
861 bounds
= gfx::Size(50, 50);
862 SetLayerPropertiesForTesting(child1
.get(),
869 child1
->SetDrawsContent(true);
871 position
= gfx::PointF(50.f
, 10.f
);
872 bounds
= gfx::Size(50, 50);
873 SetLayerPropertiesForTesting(child2
.get(),
880 child2
->SetDrawsContent(true);
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
885 position
= gfx::PointF(0.f
, 40.f
);
886 bounds
= gfx::Size(100, 50);
887 SetLayerPropertiesForTesting(grand_child1
.get(),
894 grand_child1
->SetDrawsContent(true);
896 child1
->AddChild(grand_child1
.Pass());
897 root
->AddChild(child1
.Pass());
898 root
->AddChild(child2
.Pass());
901 LayerImpl
* child1
= root
->children()[0];
902 LayerImpl
* child2
= root
->children()[1];
903 LayerImpl
* grand_child1
= child1
->children()[0];
905 host_impl().SetViewportSize(root
->bounds());
906 host_impl().active_tree()->SetRootLayer(root
.Pass());
907 host_impl().active_tree()->UpdateDrawProperties();
909 // Sanity check the scenario we just created.
912 ASSERT_TRUE(grand_child1
);
913 ASSERT_EQ(1u, RenderSurfaceLayerList().size());
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
922 // Nothing overlaps the root_layer at (1, 1), so hit testing there should find
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());
930 // At (15, 15), child1 and root are the only layers. child1 is expected to be
932 test_point
= gfx::Point(15, 15);
934 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
935 ASSERT_TRUE(result_layer
);
936 EXPECT_EQ(2, result_layer
->id());
938 // At (51, 20), child1 and child2 overlap. child2 is expected to be on top.
939 test_point
= gfx::Point(51, 20);
941 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
942 ASSERT_TRUE(result_layer
);
943 EXPECT_EQ(3, result_layer
->id());
945 // At (80, 51), child2 and grand_child1 overlap. child2 is expected to be on
947 test_point
= gfx::Point(80, 51);
949 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
950 ASSERT_TRUE(result_layer
);
951 EXPECT_EQ(3, result_layer
->id());
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);
957 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
958 ASSERT_TRUE(result_layer
);
959 EXPECT_EQ(3, result_layer
->id());
961 // At (20, 51), child1 and grand_child1 overlap. grand_child1 is expected to
963 test_point
= gfx::Point(20, 51);
965 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
966 ASSERT_TRUE(result_layer
);
967 EXPECT_EQ(4, result_layer
->id());
970 TEST_F(LayerTreeImplTest
, HitTestingForMultipleLayersAtVaryingDepths
) {
971 scoped_ptr
<LayerImpl
> root
= LayerImpl::Create(host_impl().active_tree(), 1);
973 gfx::Transform identity_matrix
;
974 gfx::Point3F transform_origin
;
975 gfx::PointF position
;
976 gfx::Size
bounds(100, 100);
977 SetLayerPropertiesForTesting(root
.get(),
984 root
->SetDrawsContent(true);
985 root
->SetShouldFlattenTransform(false);
986 root
->SetIs3dSorted(true);
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
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);
1001 position
= gfx::PointF(10.f
, 10.f
);
1002 bounds
= gfx::Size(50, 50);
1003 SetLayerPropertiesForTesting(child1
.get(),
1010 child1
->SetDrawsContent(true);
1011 child1
->SetShouldFlattenTransform(false);
1012 child1
->SetIs3dSorted(true);
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(),
1025 child2
->SetDrawsContent(true);
1026 child2
->SetShouldFlattenTransform(false);
1027 child2
->SetIs3dSorted(true);
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
1032 position
= gfx::PointF(0.f
, 40.f
);
1033 bounds
= gfx::Size(100, 50);
1034 SetLayerPropertiesForTesting(grand_child1
.get(),
1041 grand_child1
->SetDrawsContent(true);
1042 grand_child1
->SetShouldFlattenTransform(false);
1044 child1
->AddChild(grand_child1
.Pass());
1045 root
->AddChild(child1
.Pass());
1046 root
->AddChild(child2
.Pass());
1049 LayerImpl
* child1
= root
->children()[0];
1050 LayerImpl
* child2
= root
->children()[1];
1051 LayerImpl
* grand_child1
= child1
->children()[0];
1053 host_impl().SetViewportSize(root
->bounds());
1054 host_impl().active_tree()->SetRootLayer(root
.Pass());
1055 host_impl().active_tree()->UpdateDrawProperties();
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());
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());
1071 // Nothing overlaps the root_layer at (1, 1), so hit testing there should find
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());
1079 // At (15, 15), child1 and root are the only layers. child1 is expected to be
1081 test_point
= gfx::Point(15, 15);
1083 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
1084 ASSERT_TRUE(result_layer
);
1085 EXPECT_EQ(2, result_layer
->id());
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);
1091 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
1092 ASSERT_TRUE(result_layer
);
1093 EXPECT_EQ(2, result_layer
->id());
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);
1099 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
1100 ASSERT_TRUE(result_layer
);
1101 EXPECT_EQ(4, result_layer
->id());
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);
1107 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
1108 ASSERT_TRUE(result_layer
);
1109 EXPECT_EQ(4, result_layer
->id());
1111 // At (20, 51), child1 and grand_child1 overlap. grand_child1 is expected to
1113 test_point
= gfx::Point(20, 51);
1115 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
1116 ASSERT_TRUE(result_layer
);
1117 EXPECT_EQ(4, result_layer
->id());
1120 TEST_F(LayerTreeImplTest
, HitTestingForMultipleLayerLists
) {
1122 // The geometry is set up similarly to the previous case, but
1123 // all layers are forced to be render surfaces now.
1125 scoped_ptr
<LayerImpl
> root
= LayerImpl::Create(host_impl().active_tree(), 1);
1127 gfx::Transform identity_matrix
;
1128 gfx::Point3F transform_origin
;
1129 gfx::PointF position
;
1130 gfx::Size
bounds(100, 100);
1131 SetLayerPropertiesForTesting(root
.get(),
1138 root
->SetDrawsContent(true);
1140 // child 1 and child2 are initialized to overlap between x=50 and x=60.
1141 // grand_child is set to overlap both child1 and child2 between y=50 and
1142 // y=60. The expected stacking order is: (front) child2, (second)
1143 // grand_child, (third) child1, and (back) the root layer behind all other
1146 scoped_ptr
<LayerImpl
> child1
=
1147 LayerImpl::Create(host_impl().active_tree(), 2);
1148 scoped_ptr
<LayerImpl
> child2
=
1149 LayerImpl::Create(host_impl().active_tree(), 3);
1150 scoped_ptr
<LayerImpl
> grand_child1
=
1151 LayerImpl::Create(host_impl().active_tree(), 4);
1153 position
= gfx::PointF(10.f
, 10.f
);
1154 bounds
= gfx::Size(50, 50);
1155 SetLayerPropertiesForTesting(child1
.get(),
1162 child1
->SetDrawsContent(true);
1163 child1
->SetForceRenderSurface(true);
1165 position
= gfx::PointF(50.f
, 10.f
);
1166 bounds
= gfx::Size(50, 50);
1167 SetLayerPropertiesForTesting(child2
.get(),
1174 child2
->SetDrawsContent(true);
1175 child2
->SetForceRenderSurface(true);
1177 // Remember that grand_child is positioned with respect to its parent (i.e.
1178 // child1). In screen space, the intended position is (10, 50), with size
1180 position
= gfx::PointF(0.f
, 40.f
);
1181 bounds
= gfx::Size(100, 50);
1182 SetLayerPropertiesForTesting(grand_child1
.get(),
1189 grand_child1
->SetDrawsContent(true);
1190 grand_child1
->SetForceRenderSurface(true);
1192 child1
->AddChild(grand_child1
.Pass());
1193 root
->AddChild(child1
.Pass());
1194 root
->AddChild(child2
.Pass());
1197 LayerImpl
* child1
= root
->children()[0];
1198 LayerImpl
* child2
= root
->children()[1];
1199 LayerImpl
* grand_child1
= child1
->children()[0];
1201 host_impl().SetViewportSize(root
->bounds());
1202 host_impl().active_tree()->SetRootLayer(root
.Pass());
1203 host_impl().active_tree()->UpdateDrawProperties();
1205 // Sanity check the scenario we just created.
1206 ASSERT_TRUE(child1
);
1207 ASSERT_TRUE(child2
);
1208 ASSERT_TRUE(grand_child1
);
1209 ASSERT_TRUE(child1
->render_surface());
1210 ASSERT_TRUE(child2
->render_surface());
1211 ASSERT_TRUE(grand_child1
->render_surface());
1212 ASSERT_EQ(4u, RenderSurfaceLayerList().size());
1213 // The root surface has the root layer, and child1's and child2's render
1215 ASSERT_EQ(3u, root_layer()->render_surface()->layer_list().size());
1216 // The child1 surface has the child1 layer and grand_child1's render surface.
1217 ASSERT_EQ(2u, child1
->render_surface()->layer_list().size());
1218 ASSERT_EQ(1u, child2
->render_surface()->layer_list().size());
1219 ASSERT_EQ(1u, grand_child1
->render_surface()->layer_list().size());
1220 ASSERT_EQ(1, RenderSurfaceLayerList().at(0)->id()); // root layer
1221 ASSERT_EQ(2, RenderSurfaceLayerList()[1]->id()); // child1
1222 ASSERT_EQ(4, RenderSurfaceLayerList().at(2)->id()); // grand_child1
1223 ASSERT_EQ(3, RenderSurfaceLayerList()[3]->id()); // child2
1225 // Nothing overlaps the root_layer at (1, 1), so hit testing there should find
1227 gfx::Point test_point
= gfx::Point(1, 1);
1228 LayerImpl
* result_layer
=
1229 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
1230 ASSERT_TRUE(result_layer
);
1231 EXPECT_EQ(1, result_layer
->id());
1233 // At (15, 15), child1 and root are the only layers. child1 is expected to be
1235 test_point
= gfx::Point(15, 15);
1237 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
1238 ASSERT_TRUE(result_layer
);
1239 EXPECT_EQ(2, result_layer
->id());
1241 // At (51, 20), child1 and child2 overlap. child2 is expected to be on top.
1242 test_point
= gfx::Point(51, 20);
1244 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
1245 ASSERT_TRUE(result_layer
);
1246 EXPECT_EQ(3, result_layer
->id());
1248 // At (80, 51), child2 and grand_child1 overlap. child2 is expected to be on
1250 test_point
= gfx::Point(80, 51);
1252 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
1253 ASSERT_TRUE(result_layer
);
1254 EXPECT_EQ(3, result_layer
->id());
1256 // At (51, 51), all layers overlap each other. child2 is expected to be on top
1257 // of all other layers.
1258 test_point
= gfx::Point(51, 51);
1260 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
1261 ASSERT_TRUE(result_layer
);
1262 EXPECT_EQ(3, result_layer
->id());
1264 // At (20, 51), child1 and grand_child1 overlap. grand_child1 is expected to
1266 test_point
= gfx::Point(20, 51);
1268 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
1269 ASSERT_TRUE(result_layer
);
1270 EXPECT_EQ(4, result_layer
->id());
1273 TEST_F(LayerTreeImplTest
, HitCheckingTouchHandlerRegionsForSingleLayer
) {
1274 scoped_ptr
<LayerImpl
> root
=
1275 LayerImpl::Create(host_impl().active_tree(), 12345);
1277 gfx::Transform identity_matrix
;
1278 Region
touch_handler_region(gfx::Rect(10, 10, 50, 50));
1279 gfx::Point3F transform_origin
;
1280 gfx::PointF position
;
1281 gfx::Size
bounds(100, 100);
1282 SetLayerPropertiesForTesting(root
.get(),
1289 root
->SetDrawsContent(true);
1291 host_impl().SetViewportSize(root
->bounds());
1292 host_impl().active_tree()->SetRootLayer(root
.Pass());
1293 host_impl().active_tree()->UpdateDrawProperties();
1295 // Sanity check the scenario we just created.
1296 ASSERT_EQ(1u, RenderSurfaceLayerList().size());
1297 ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
1299 // Hit checking for any point should return a null pointer for a layer without
1300 // any touch event handler regions.
1301 gfx::Point
test_point(11, 11);
1302 LayerImpl
* result_layer
=
1303 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1305 EXPECT_FALSE(result_layer
);
1307 host_impl().active_tree()->root_layer()->SetTouchEventHandlerRegion(
1308 touch_handler_region
);
1309 // Hit checking for a point outside the layer should return a null pointer.
1310 test_point
= gfx::Point(101, 101);
1312 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1314 EXPECT_FALSE(result_layer
);
1316 test_point
= gfx::Point(-1, -1);
1318 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1320 EXPECT_FALSE(result_layer
);
1322 // Hit checking for a point inside the layer, but outside the touch handler
1323 // region should return a null pointer.
1324 test_point
= gfx::Point(1, 1);
1326 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1328 EXPECT_FALSE(result_layer
);
1330 test_point
= gfx::Point(99, 99);
1332 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1334 EXPECT_FALSE(result_layer
);
1336 // Hit checking for a point inside the touch event handler region should
1337 // return the root layer.
1338 test_point
= gfx::Point(11, 11);
1340 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1342 ASSERT_TRUE(result_layer
);
1343 EXPECT_EQ(12345, result_layer
->id());
1345 test_point
= gfx::Point(59, 59);
1347 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1349 ASSERT_TRUE(result_layer
);
1350 EXPECT_EQ(12345, result_layer
->id());
1353 TEST_F(LayerTreeImplTest
,
1354 HitCheckingTouchHandlerRegionsForUninvertibleTransform
) {
1355 scoped_ptr
<LayerImpl
> root
=
1356 LayerImpl::Create(host_impl().active_tree(), 12345);
1358 gfx::Transform uninvertible_transform
;
1359 uninvertible_transform
.matrix().set(0, 0, 0.0);
1360 uninvertible_transform
.matrix().set(1, 1, 0.0);
1361 uninvertible_transform
.matrix().set(2, 2, 0.0);
1362 uninvertible_transform
.matrix().set(3, 3, 0.0);
1363 ASSERT_FALSE(uninvertible_transform
.IsInvertible());
1365 gfx::Transform identity_matrix
;
1366 Region
touch_handler_region(gfx::Rect(10, 10, 50, 50));
1367 gfx::Point3F transform_origin
;
1368 gfx::PointF position
;
1369 gfx::Size
bounds(100, 100);
1370 SetLayerPropertiesForTesting(root
.get(),
1371 uninvertible_transform
,
1377 root
->SetDrawsContent(true);
1378 root
->SetTouchEventHandlerRegion(touch_handler_region
);
1380 host_impl().SetViewportSize(root
->bounds());
1381 host_impl().active_tree()->SetRootLayer(root
.Pass());
1382 host_impl().active_tree()->UpdateDrawProperties();
1384 // Sanity check the scenario we just created.
1385 ASSERT_EQ(1u, RenderSurfaceLayerList().size());
1386 ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
1387 ASSERT_FALSE(root_layer()->screen_space_transform().IsInvertible());
1389 // Hit checking any point should not hit the touch handler region on the
1390 // layer. If the invertible matrix is accidentally ignored and treated like an
1391 // identity, then the hit testing will incorrectly hit the layer when it
1393 gfx::Point
test_point(1, 1);
1394 LayerImpl
* result_layer
=
1395 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1397 EXPECT_FALSE(result_layer
);
1399 test_point
= gfx::Point(10, 10);
1401 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1403 EXPECT_FALSE(result_layer
);
1405 test_point
= gfx::Point(10, 30);
1407 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1409 EXPECT_FALSE(result_layer
);
1411 test_point
= gfx::Point(50, 50);
1413 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1415 EXPECT_FALSE(result_layer
);
1417 test_point
= gfx::Point(67, 48);
1419 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1421 EXPECT_FALSE(result_layer
);
1423 test_point
= gfx::Point(99, 99);
1425 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1427 EXPECT_FALSE(result_layer
);
1429 test_point
= gfx::Point(-1, -1);
1431 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1433 EXPECT_FALSE(result_layer
);
1436 TEST_F(LayerTreeImplTest
,
1437 HitCheckingTouchHandlerRegionsForSinglePositionedLayer
) {
1438 scoped_ptr
<LayerImpl
> root
=
1439 LayerImpl::Create(host_impl().active_tree(), 12345);
1441 gfx::Transform identity_matrix
;
1442 Region
touch_handler_region(gfx::Rect(10, 10, 50, 50));
1443 gfx::Point3F transform_origin
;
1444 // this layer is positioned, and hit testing should correctly know where the
1445 // layer is located.
1446 gfx::PointF
position(50.f
, 50.f
);
1447 gfx::Size
bounds(100, 100);
1448 SetLayerPropertiesForTesting(root
.get(),
1455 root
->SetDrawsContent(true);
1456 root
->SetTouchEventHandlerRegion(touch_handler_region
);
1458 host_impl().SetViewportSize(root
->bounds());
1459 host_impl().active_tree()->SetRootLayer(root
.Pass());
1460 host_impl().active_tree()->UpdateDrawProperties();
1462 // Sanity check the scenario we just created.
1463 ASSERT_EQ(1u, RenderSurfaceLayerList().size());
1464 ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
1466 // Hit checking for a point outside the layer should return a null pointer.
1467 gfx::Point
test_point(49, 49);
1468 LayerImpl
* result_layer
=
1469 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1471 EXPECT_FALSE(result_layer
);
1473 // Even though the layer has a touch handler region containing (101, 101), it
1474 // should not be visible there since the root render surface would clamp it.
1475 test_point
= gfx::Point(101, 101);
1477 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1479 EXPECT_FALSE(result_layer
);
1481 // Hit checking for a point inside the layer, but outside the touch handler
1482 // region should return a null pointer.
1483 test_point
= gfx::Point(51, 51);
1485 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1487 EXPECT_FALSE(result_layer
);
1489 // Hit checking for a point inside the touch event handler region should
1490 // return the root layer.
1491 test_point
= gfx::Point(61, 61);
1493 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1495 ASSERT_TRUE(result_layer
);
1496 EXPECT_EQ(12345, result_layer
->id());
1498 test_point
= gfx::Point(99, 99);
1500 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1502 ASSERT_TRUE(result_layer
);
1503 EXPECT_EQ(12345, result_layer
->id());
1506 TEST_F(LayerTreeImplTest
,
1507 HitCheckingTouchHandlerRegionsForSingleLayerWithScaledContents
) {
1508 // A layer's visible content rect is actually in the layer's content space.
1509 // The screen space transform converts from the layer's origin space to screen
1510 // space. This test makes sure that hit testing works correctly accounts for
1511 // the contents scale. A contents scale that is not 1 effectively forces a
1512 // non-identity transform between layer's content space and layer's origin
1513 // space. The hit testing code must take this into account.
1515 // To test this, the layer is positioned at (25, 25), and is size (50, 50). If
1516 // contents scale is ignored, then hit checking will mis-interpret the visible
1517 // content rect as being larger than the actual bounds of the layer.
1519 scoped_ptr
<LayerImpl
> root
= LayerImpl::Create(host_impl().active_tree(), 1);
1521 gfx::Transform identity_matrix
;
1522 gfx::Point3F transform_origin
;
1524 SetLayerPropertiesForTesting(root
.get(),
1528 gfx::Size(100, 100),
1532 Region
touch_handler_region(gfx::Rect(10, 10, 30, 30));
1533 gfx::PointF
position(25.f
, 25.f
);
1534 gfx::Size
bounds(50, 50);
1535 scoped_ptr
<LayerImpl
> test_layer
=
1536 LayerImpl::Create(host_impl().active_tree(), 12345);
1537 SetLayerPropertiesForTesting(test_layer
.get(),
1545 // override content bounds and contents scale
1546 test_layer
->SetContentBounds(gfx::Size(100, 100));
1547 test_layer
->SetContentsScale(2, 2);
1549 test_layer
->SetDrawsContent(true);
1550 test_layer
->SetTouchEventHandlerRegion(touch_handler_region
);
1551 root
->AddChild(test_layer
.Pass());
1554 host_impl().SetViewportSize(root
->bounds());
1555 host_impl().active_tree()->SetRootLayer(root
.Pass());
1556 host_impl().active_tree()->UpdateDrawProperties();
1558 // Sanity check the scenario we just created.
1559 // The visible content rect for test_layer is actually 100x100, even though
1560 // its layout size is 50x50, positioned at 25x25.
1561 LayerImpl
* test_layer
=
1562 host_impl().active_tree()->root_layer()->children()[0];
1563 EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100), test_layer
->visible_content_rect());
1564 ASSERT_EQ(1u, RenderSurfaceLayerList().size());
1565 ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
1567 // Hit checking for a point outside the layer should return a null pointer
1568 // (the root layer does not draw content, so it will not be tested either).
1569 gfx::Point
test_point(76, 76);
1570 LayerImpl
* result_layer
=
1571 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1573 EXPECT_FALSE(result_layer
);
1575 // Hit checking for a point inside the layer, but outside the touch handler
1576 // region should return a null pointer.
1577 test_point
= gfx::Point(26, 26);
1579 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1581 EXPECT_FALSE(result_layer
);
1583 test_point
= gfx::Point(34, 34);
1585 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1587 EXPECT_FALSE(result_layer
);
1589 test_point
= gfx::Point(65, 65);
1591 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1593 EXPECT_FALSE(result_layer
);
1595 test_point
= gfx::Point(74, 74);
1597 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1599 EXPECT_FALSE(result_layer
);
1601 // Hit checking for a point inside the touch event handler region should
1602 // return the root layer.
1603 test_point
= gfx::Point(35, 35);
1605 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1607 ASSERT_TRUE(result_layer
);
1608 EXPECT_EQ(12345, result_layer
->id());
1610 test_point
= gfx::Point(64, 64);
1612 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1614 ASSERT_TRUE(result_layer
);
1615 EXPECT_EQ(12345, result_layer
->id());
1618 TEST_F(LayerTreeImplTest
,
1619 HitCheckingTouchHandlerRegionsForSingleLayerWithDeviceScale
) {
1620 // The layer's device_scale_factor and page_scale_factor should scale the
1621 // content rect and we should be able to hit the touch handler region by
1622 // scaling the points accordingly.
1623 scoped_ptr
<LayerImpl
> root
= LayerImpl::Create(host_impl().active_tree(), 1);
1625 gfx::Transform identity_matrix
;
1626 gfx::Point3F transform_origin
;
1627 // Set the bounds of the root layer big enough to fit the child when scaled.
1628 SetLayerPropertiesForTesting(root
.get(),
1632 gfx::Size(100, 100),
1636 Region
touch_handler_region(gfx::Rect(10, 10, 30, 30));
1637 gfx::PointF
position(25.f
, 25.f
);
1638 gfx::Size
bounds(50, 50);
1639 scoped_ptr
<LayerImpl
> test_layer
=
1640 LayerImpl::Create(host_impl().active_tree(), 12345);
1641 SetLayerPropertiesForTesting(test_layer
.get(),
1649 test_layer
->SetDrawsContent(true);
1650 test_layer
->SetTouchEventHandlerRegion(touch_handler_region
);
1651 root
->AddChild(test_layer
.Pass());
1654 float device_scale_factor
= 3.f
;
1655 float page_scale_factor
= 5.f
;
1656 gfx::Size scaled_bounds_for_root
= gfx::ToCeiledSize(
1657 gfx::ScaleSize(root
->bounds(), device_scale_factor
* page_scale_factor
));
1658 host_impl().SetViewportSize(scaled_bounds_for_root
);
1660 host_impl().SetDeviceScaleFactor(device_scale_factor
);
1661 host_impl().active_tree()->SetPageScaleFactorAndLimits(
1662 page_scale_factor
, page_scale_factor
, page_scale_factor
);
1663 host_impl().active_tree()->SetRootLayer(root
.Pass());
1664 host_impl().active_tree()->SetViewportLayersFromIds(1, 1, Layer::INVALID_ID
);
1665 host_impl().active_tree()->UpdateDrawProperties();
1667 // Sanity check the scenario we just created.
1668 // The visible content rect for test_layer is actually 100x100, even though
1669 // its layout size is 50x50, positioned at 25x25.
1670 LayerImpl
* test_layer
=
1671 host_impl().active_tree()->root_layer()->children()[0];
1672 ASSERT_EQ(1u, RenderSurfaceLayerList().size());
1673 ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
1675 // Check whether the child layer fits into the root after scaled.
1676 EXPECT_RECT_EQ(gfx::Rect(test_layer
->content_bounds()),
1677 test_layer
->visible_content_rect());
1679 // Hit checking for a point outside the layer should return a null pointer
1680 // (the root layer does not draw content, so it will not be tested either).
1681 gfx::PointF
test_point(76.f
, 76.f
);
1683 gfx::ScalePoint(test_point
, device_scale_factor
* page_scale_factor
);
1684 LayerImpl
* result_layer
=
1685 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1687 EXPECT_FALSE(result_layer
);
1689 // Hit checking for a point inside the layer, but outside the touch handler
1690 // region should return a null pointer.
1691 test_point
= gfx::Point(26, 26);
1693 gfx::ScalePoint(test_point
, device_scale_factor
* page_scale_factor
);
1695 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1697 EXPECT_FALSE(result_layer
);
1699 test_point
= gfx::Point(34, 34);
1701 gfx::ScalePoint(test_point
, device_scale_factor
* page_scale_factor
);
1703 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1705 EXPECT_FALSE(result_layer
);
1707 test_point
= gfx::Point(65, 65);
1709 gfx::ScalePoint(test_point
, device_scale_factor
* page_scale_factor
);
1711 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1713 EXPECT_FALSE(result_layer
);
1715 test_point
= gfx::Point(74, 74);
1717 gfx::ScalePoint(test_point
, device_scale_factor
* page_scale_factor
);
1719 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1721 EXPECT_FALSE(result_layer
);
1723 // Hit checking for a point inside the touch event handler region should
1724 // return the root layer.
1725 test_point
= gfx::Point(35, 35);
1727 gfx::ScalePoint(test_point
, device_scale_factor
* page_scale_factor
);
1729 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1731 ASSERT_TRUE(result_layer
);
1732 EXPECT_EQ(12345, result_layer
->id());
1734 test_point
= gfx::Point(64, 64);
1736 gfx::ScalePoint(test_point
, device_scale_factor
* page_scale_factor
);
1738 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1740 ASSERT_TRUE(result_layer
);
1741 EXPECT_EQ(12345, result_layer
->id());
1744 TEST_F(LayerTreeImplTest
, HitCheckingTouchHandlerRegionsForSimpleClippedLayer
) {
1745 // Test that hit-checking will only work for the visible portion of a layer,
1746 // and not the entire layer bounds. Here we just test the simple axis-aligned
1748 gfx::Transform identity_matrix
;
1749 gfx::Point3F transform_origin
;
1751 scoped_ptr
<LayerImpl
> root
= LayerImpl::Create(host_impl().active_tree(), 1);
1752 SetLayerPropertiesForTesting(root
.get(),
1756 gfx::Size(100, 100),
1760 scoped_ptr
<LayerImpl
> clipping_layer
=
1761 LayerImpl::Create(host_impl().active_tree(), 123);
1762 // this layer is positioned, and hit testing should correctly know where the
1763 // layer is located.
1764 gfx::PointF
position(25.f
, 25.f
);
1765 gfx::Size
bounds(50, 50);
1766 SetLayerPropertiesForTesting(clipping_layer
.get(),
1773 clipping_layer
->SetMasksToBounds(true);
1775 scoped_ptr
<LayerImpl
> child
=
1776 LayerImpl::Create(host_impl().active_tree(), 456);
1777 Region
touch_handler_region(gfx::Rect(10, 10, 50, 50));
1778 position
= gfx::PointF(-50.f
, -50.f
);
1779 bounds
= gfx::Size(300, 300);
1780 SetLayerPropertiesForTesting(child
.get(),
1787 child
->SetDrawsContent(true);
1788 child
->SetTouchEventHandlerRegion(touch_handler_region
);
1789 clipping_layer
->AddChild(child
.Pass());
1790 root
->AddChild(clipping_layer
.Pass());
1793 host_impl().SetViewportSize(root
->bounds());
1794 host_impl().active_tree()->SetRootLayer(root
.Pass());
1795 host_impl().active_tree()->UpdateDrawProperties();
1797 // Sanity check the scenario we just created.
1798 ASSERT_EQ(1u, RenderSurfaceLayerList().size());
1799 ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
1800 ASSERT_EQ(456, root_layer()->render_surface()->layer_list().at(0)->id());
1802 // Hit checking for a point outside the layer should return a null pointer.
1803 // Despite the child layer being very large, it should be clipped to the root
1805 gfx::Point
test_point(24, 24);
1806 LayerImpl
* result_layer
=
1807 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1809 EXPECT_FALSE(result_layer
);
1811 // Hit checking for a point inside the layer, but outside the touch handler
1812 // region should return a null pointer.
1813 test_point
= gfx::Point(35, 35);
1815 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1817 EXPECT_FALSE(result_layer
);
1819 test_point
= gfx::Point(74, 74);
1821 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1823 EXPECT_FALSE(result_layer
);
1825 // Hit checking for a point inside the touch event handler region should
1826 // return the root layer.
1827 test_point
= gfx::Point(25, 25);
1829 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1831 ASSERT_TRUE(result_layer
);
1832 EXPECT_EQ(456, result_layer
->id());
1834 test_point
= gfx::Point(34, 34);
1836 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1838 ASSERT_TRUE(result_layer
);
1839 EXPECT_EQ(456, result_layer
->id());
1842 TEST_F(LayerTreeImplTest
, HitCheckingTouchHandlerOverlappingRegions
) {
1843 gfx::Transform identity_matrix
;
1844 gfx::Point3F transform_origin
;
1846 scoped_ptr
<LayerImpl
> root
= LayerImpl::Create(host_impl().active_tree(), 1);
1847 SetLayerPropertiesForTesting(root
.get(),
1851 gfx::Size(100, 100),
1855 scoped_ptr
<LayerImpl
> touch_layer
=
1856 LayerImpl::Create(host_impl().active_tree(), 123);
1857 // this layer is positioned, and hit testing should correctly know where the
1858 // layer is located.
1859 gfx::PointF position
;
1860 gfx::Size
bounds(50, 50);
1861 SetLayerPropertiesForTesting(touch_layer
.get(),
1868 touch_layer
->SetDrawsContent(true);
1869 touch_layer
->SetTouchEventHandlerRegion(gfx::Rect(0, 0, 50, 50));
1870 root
->AddChild(touch_layer
.Pass());
1874 scoped_ptr
<LayerImpl
> notouch_layer
=
1875 LayerImpl::Create(host_impl().active_tree(), 1234);
1876 // this layer is positioned, and hit testing should correctly know where the
1877 // layer is located.
1878 gfx::PointF
position(0, 25);
1879 gfx::Size
bounds(50, 50);
1880 SetLayerPropertiesForTesting(notouch_layer
.get(),
1887 notouch_layer
->SetDrawsContent(true);
1888 root
->AddChild(notouch_layer
.Pass());
1891 host_impl().SetViewportSize(root
->bounds());
1892 host_impl().active_tree()->SetRootLayer(root
.Pass());
1893 host_impl().active_tree()->UpdateDrawProperties();
1895 // Sanity check the scenario we just created.
1896 ASSERT_EQ(1u, RenderSurfaceLayerList().size());
1897 ASSERT_EQ(2u, root_layer()->render_surface()->layer_list().size());
1898 ASSERT_EQ(123, root_layer()->render_surface()->layer_list().at(0)->id());
1899 ASSERT_EQ(1234, root_layer()->render_surface()->layer_list().at(1)->id());
1901 gfx::Point
test_point(35, 35);
1902 LayerImpl
* result_layer
=
1903 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1906 // We should have passed through the no-touch layer and found the layer
1908 EXPECT_TRUE(result_layer
);
1910 host_impl().active_tree()->LayerById(1234)->SetContentsOpaque(true);
1912 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1915 // Even with an opaque layer in the middle, we should still find the layer
1917 // the touch handler behind it (since we can't assume that opaque layers are
1918 // opaque to hit testing).
1919 EXPECT_TRUE(result_layer
);
1921 test_point
= gfx::Point(35, 15);
1923 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1925 ASSERT_TRUE(result_layer
);
1926 EXPECT_EQ(123, result_layer
->id());
1928 test_point
= gfx::Point(35, 65);
1930 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1932 EXPECT_FALSE(result_layer
);