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
->Set3dSortingContextId(1);
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
->Set3dSortingContextId(1);
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
->Set3dSortingContextId(1);
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
, 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(),
1133 root
->SetDrawsContent(true);
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);
1140 position
= gfx::PointF(10.f
, 10.f
);
1141 bounds
= gfx::Size(1, 1);
1142 SetLayerPropertiesForTesting(child
.get(),
1149 child
->SetDrawsContent(true);
1150 child
->SetMasksToBounds(true);
1152 position
= gfx::PointF(0.f
, 40.f
);
1153 bounds
= gfx::Size(100, 50);
1154 SetLayerPropertiesForTesting(grand_child
.get(),
1161 grand_child
->SetDrawsContent(true);
1162 grand_child
->SetForceRenderSurface(true);
1164 // This should let |grand_child| "escape" |child|'s clip.
1165 grand_child
->SetClipParent(root
.get());
1167 child
->AddChild(grand_child
.Pass());
1168 root
->AddChild(child
.Pass());
1171 host_impl().SetViewportSize(root
->bounds());
1172 host_impl().active_tree()->SetRootLayer(root
.Pass());
1173 host_impl().active_tree()->UpdateDrawProperties();
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());
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(),
1195 root
->SetDrawsContent(true);
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);
1204 position
= gfx::PointF(10.f
, 10.f
);
1205 bounds
= gfx::Size(1, 1);
1206 SetLayerPropertiesForTesting(child
.get(),
1213 child
->SetDrawsContent(true);
1214 child
->SetMasksToBounds(true);
1216 position
= gfx::PointF();
1217 bounds
= gfx::Size(200, 200);
1218 SetLayerPropertiesForTesting(scroll_child
.get(),
1225 scroll_child
->SetDrawsContent(true);
1227 // This should cause scroll child and its descendants to be affected by
1229 scroll_child
->SetScrollParent(child
.get());
1231 SetLayerPropertiesForTesting(grand_child
.get(),
1238 grand_child
->SetDrawsContent(true);
1239 grand_child
->SetForceRenderSurface(true);
1241 scroll_child
->AddChild(grand_child
.Pass());
1242 root
->AddChild(scroll_child
.Pass());
1243 root
->AddChild(child
.Pass());
1246 host_impl().SetViewportSize(root
->bounds());
1247 host_impl().active_tree()->SetRootLayer(root
.Pass());
1248 host_impl().active_tree()->UpdateDrawProperties();
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());
1258 TEST_F(LayerTreeImplTest
, HitTestingForMultipleLayerLists
) {
1260 // The geometry is set up similarly to the previous case, but
1261 // all layers are forced to be render surfaces now.
1263 scoped_ptr
<LayerImpl
> root
= LayerImpl::Create(host_impl().active_tree(), 1);
1265 gfx::Transform identity_matrix
;
1266 gfx::Point3F transform_origin
;
1267 gfx::PointF position
;
1268 gfx::Size
bounds(100, 100);
1269 SetLayerPropertiesForTesting(root
.get(),
1276 root
->SetDrawsContent(true);
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
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);
1291 position
= gfx::PointF(10.f
, 10.f
);
1292 bounds
= gfx::Size(50, 50);
1293 SetLayerPropertiesForTesting(child1
.get(),
1300 child1
->SetDrawsContent(true);
1301 child1
->SetForceRenderSurface(true);
1303 position
= gfx::PointF(50.f
, 10.f
);
1304 bounds
= gfx::Size(50, 50);
1305 SetLayerPropertiesForTesting(child2
.get(),
1312 child2
->SetDrawsContent(true);
1313 child2
->SetForceRenderSurface(true);
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
1318 position
= gfx::PointF(0.f
, 40.f
);
1319 bounds
= gfx::Size(100, 50);
1320 SetLayerPropertiesForTesting(grand_child1
.get(),
1327 grand_child1
->SetDrawsContent(true);
1328 grand_child1
->SetForceRenderSurface(true);
1330 child1
->AddChild(grand_child1
.Pass());
1331 root
->AddChild(child1
.Pass());
1332 root
->AddChild(child2
.Pass());
1335 LayerImpl
* child1
= root
->children()[0];
1336 LayerImpl
* child2
= root
->children()[1];
1337 LayerImpl
* grand_child1
= child1
->children()[0];
1339 host_impl().SetViewportSize(root
->bounds());
1340 host_impl().active_tree()->SetRootLayer(root
.Pass());
1341 host_impl().active_tree()->UpdateDrawProperties();
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
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
1363 // Nothing overlaps the root_layer at (1, 1), so hit testing there should find
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());
1371 // At (15, 15), child1 and root are the only layers. child1 is expected to be
1373 test_point
= gfx::Point(15, 15);
1375 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
1376 ASSERT_TRUE(result_layer
);
1377 EXPECT_EQ(2, result_layer
->id());
1379 // At (51, 20), child1 and child2 overlap. child2 is expected to be on top.
1380 test_point
= gfx::Point(51, 20);
1382 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
1383 ASSERT_TRUE(result_layer
);
1384 EXPECT_EQ(3, result_layer
->id());
1386 // At (80, 51), child2 and grand_child1 overlap. child2 is expected to be on
1388 test_point
= gfx::Point(80, 51);
1390 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
1391 ASSERT_TRUE(result_layer
);
1392 EXPECT_EQ(3, result_layer
->id());
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);
1398 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
1399 ASSERT_TRUE(result_layer
);
1400 EXPECT_EQ(3, result_layer
->id());
1402 // At (20, 51), child1 and grand_child1 overlap. grand_child1 is expected to
1404 test_point
= gfx::Point(20, 51);
1406 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
1407 ASSERT_TRUE(result_layer
);
1408 EXPECT_EQ(4, result_layer
->id());
1411 TEST_F(LayerTreeImplTest
, HitCheckingTouchHandlerRegionsForSingleLayer
) {
1412 scoped_ptr
<LayerImpl
> root
=
1413 LayerImpl::Create(host_impl().active_tree(), 12345);
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(),
1427 root
->SetDrawsContent(true);
1429 host_impl().SetViewportSize(root
->bounds());
1430 host_impl().active_tree()->SetRootLayer(root
.Pass());
1431 host_impl().active_tree()->UpdateDrawProperties();
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());
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(
1443 EXPECT_FALSE(result_layer
);
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);
1450 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1452 EXPECT_FALSE(result_layer
);
1454 test_point
= gfx::Point(-1, -1);
1456 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1458 EXPECT_FALSE(result_layer
);
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);
1464 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1466 EXPECT_FALSE(result_layer
);
1468 test_point
= gfx::Point(99, 99);
1470 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1472 EXPECT_FALSE(result_layer
);
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);
1478 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1480 ASSERT_TRUE(result_layer
);
1481 EXPECT_EQ(12345, result_layer
->id());
1483 test_point
= gfx::Point(59, 59);
1485 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1487 ASSERT_TRUE(result_layer
);
1488 EXPECT_EQ(12345, result_layer
->id());
1491 TEST_F(LayerTreeImplTest
,
1492 HitCheckingTouchHandlerRegionsForUninvertibleTransform
) {
1493 scoped_ptr
<LayerImpl
> root
=
1494 LayerImpl::Create(host_impl().active_tree(), 12345);
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());
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
,
1515 root
->SetDrawsContent(true);
1516 root
->SetTouchEventHandlerRegion(touch_handler_region
);
1518 host_impl().SetViewportSize(root
->bounds());
1519 host_impl().active_tree()->SetRootLayer(root
.Pass());
1520 host_impl().active_tree()->UpdateDrawProperties();
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());
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
1531 gfx::Point
test_point(1, 1);
1532 LayerImpl
* result_layer
=
1533 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1535 EXPECT_FALSE(result_layer
);
1537 test_point
= gfx::Point(10, 10);
1539 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1541 EXPECT_FALSE(result_layer
);
1543 test_point
= gfx::Point(10, 30);
1545 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1547 EXPECT_FALSE(result_layer
);
1549 test_point
= gfx::Point(50, 50);
1551 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1553 EXPECT_FALSE(result_layer
);
1555 test_point
= gfx::Point(67, 48);
1557 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1559 EXPECT_FALSE(result_layer
);
1561 test_point
= gfx::Point(99, 99);
1563 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1565 EXPECT_FALSE(result_layer
);
1567 test_point
= gfx::Point(-1, -1);
1569 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1571 EXPECT_FALSE(result_layer
);
1574 TEST_F(LayerTreeImplTest
,
1575 HitCheckingTouchHandlerRegionsForSinglePositionedLayer
) {
1576 scoped_ptr
<LayerImpl
> root
=
1577 LayerImpl::Create(host_impl().active_tree(), 12345);
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(),
1593 root
->SetDrawsContent(true);
1594 root
->SetTouchEventHandlerRegion(touch_handler_region
);
1596 host_impl().SetViewportSize(root
->bounds());
1597 host_impl().active_tree()->SetRootLayer(root
.Pass());
1598 host_impl().active_tree()->UpdateDrawProperties();
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());
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(
1609 EXPECT_FALSE(result_layer
);
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);
1615 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1617 EXPECT_FALSE(result_layer
);
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);
1623 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1625 EXPECT_FALSE(result_layer
);
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);
1631 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1633 ASSERT_TRUE(result_layer
);
1634 EXPECT_EQ(12345, result_layer
->id());
1636 test_point
= gfx::Point(99, 99);
1638 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1640 ASSERT_TRUE(result_layer
);
1641 EXPECT_EQ(12345, result_layer
->id());
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.
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.
1657 scoped_ptr
<LayerImpl
> root
= LayerImpl::Create(host_impl().active_tree(), 1);
1659 gfx::Transform identity_matrix
;
1660 gfx::Point3F transform_origin
;
1662 SetLayerPropertiesForTesting(root
.get(),
1666 gfx::Size(100, 100),
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(),
1683 // override content bounds and contents scale
1684 test_layer
->SetContentBounds(gfx::Size(100, 100));
1685 test_layer
->SetContentsScale(2, 2);
1687 test_layer
->SetDrawsContent(true);
1688 test_layer
->SetTouchEventHandlerRegion(touch_handler_region
);
1689 root
->AddChild(test_layer
.Pass());
1692 host_impl().SetViewportSize(root
->bounds());
1693 host_impl().active_tree()->SetRootLayer(root
.Pass());
1694 host_impl().active_tree()->UpdateDrawProperties();
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());
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(
1711 EXPECT_FALSE(result_layer
);
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);
1717 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1719 EXPECT_FALSE(result_layer
);
1721 test_point
= gfx::Point(34, 34);
1723 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1725 EXPECT_FALSE(result_layer
);
1727 test_point
= gfx::Point(65, 65);
1729 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1731 EXPECT_FALSE(result_layer
);
1733 test_point
= gfx::Point(74, 74);
1735 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1737 EXPECT_FALSE(result_layer
);
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);
1743 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1745 ASSERT_TRUE(result_layer
);
1746 EXPECT_EQ(12345, result_layer
->id());
1748 test_point
= gfx::Point(64, 64);
1750 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1752 ASSERT_TRUE(result_layer
);
1753 EXPECT_EQ(12345, result_layer
->id());
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);
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(),
1770 gfx::Size(100, 100),
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(),
1787 test_layer
->SetDrawsContent(true);
1788 test_layer
->SetTouchEventHandlerRegion(touch_handler_region
);
1789 root
->AddChild(test_layer
.Pass());
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
);
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().active_tree()->UpdateDrawProperties();
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());
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());
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
);
1821 gfx::ScalePoint(test_point
, device_scale_factor
* page_scale_factor
);
1822 LayerImpl
* result_layer
=
1823 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1825 EXPECT_FALSE(result_layer
);
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);
1831 gfx::ScalePoint(test_point
, device_scale_factor
* page_scale_factor
);
1833 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1835 EXPECT_FALSE(result_layer
);
1837 test_point
= gfx::Point(34, 34);
1839 gfx::ScalePoint(test_point
, device_scale_factor
* page_scale_factor
);
1841 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1843 EXPECT_FALSE(result_layer
);
1845 test_point
= gfx::Point(65, 65);
1847 gfx::ScalePoint(test_point
, device_scale_factor
* page_scale_factor
);
1849 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1851 EXPECT_FALSE(result_layer
);
1853 test_point
= gfx::Point(74, 74);
1855 gfx::ScalePoint(test_point
, device_scale_factor
* page_scale_factor
);
1857 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1859 EXPECT_FALSE(result_layer
);
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);
1865 gfx::ScalePoint(test_point
, device_scale_factor
* page_scale_factor
);
1867 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1869 ASSERT_TRUE(result_layer
);
1870 EXPECT_EQ(12345, result_layer
->id());
1872 test_point
= gfx::Point(64, 64);
1874 gfx::ScalePoint(test_point
, device_scale_factor
* page_scale_factor
);
1876 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1878 ASSERT_TRUE(result_layer
);
1879 EXPECT_EQ(12345, result_layer
->id());
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
1886 gfx::Transform identity_matrix
;
1887 gfx::Point3F transform_origin
;
1889 scoped_ptr
<LayerImpl
> root
= LayerImpl::Create(host_impl().active_tree(), 1);
1890 SetLayerPropertiesForTesting(root
.get(),
1894 gfx::Size(100, 100),
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(),
1911 clipping_layer
->SetMasksToBounds(true);
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(),
1925 child
->SetDrawsContent(true);
1926 child
->SetTouchEventHandlerRegion(touch_handler_region
);
1927 clipping_layer
->AddChild(child
.Pass());
1928 root
->AddChild(clipping_layer
.Pass());
1931 host_impl().SetViewportSize(root
->bounds());
1932 host_impl().active_tree()->SetRootLayer(root
.Pass());
1933 host_impl().active_tree()->UpdateDrawProperties();
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());
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
1943 gfx::Point
test_point(24, 24);
1944 LayerImpl
* result_layer
=
1945 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1947 EXPECT_FALSE(result_layer
);
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);
1953 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1955 EXPECT_FALSE(result_layer
);
1957 test_point
= gfx::Point(74, 74);
1959 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1961 EXPECT_FALSE(result_layer
);
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);
1967 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1969 ASSERT_TRUE(result_layer
);
1970 EXPECT_EQ(456, result_layer
->id());
1972 test_point
= gfx::Point(34, 34);
1974 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1976 ASSERT_TRUE(result_layer
);
1977 EXPECT_EQ(456, result_layer
->id());
1980 TEST_F(LayerTreeImplTest
, HitCheckingTouchHandlerOverlappingRegions
) {
1981 gfx::Transform identity_matrix
;
1982 gfx::Point3F transform_origin
;
1984 scoped_ptr
<LayerImpl
> root
= LayerImpl::Create(host_impl().active_tree(), 1);
1985 SetLayerPropertiesForTesting(root
.get(),
1989 gfx::Size(100, 100),
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(),
2006 touch_layer
->SetDrawsContent(true);
2007 touch_layer
->SetTouchEventHandlerRegion(gfx::Rect(0, 0, 50, 50));
2008 root
->AddChild(touch_layer
.Pass());
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(),
2025 notouch_layer
->SetDrawsContent(true);
2026 root
->AddChild(notouch_layer
.Pass());
2029 host_impl().SetViewportSize(root
->bounds());
2030 host_impl().active_tree()->SetRootLayer(root
.Pass());
2031 host_impl().active_tree()->UpdateDrawProperties();
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());
2039 gfx::Point
test_point(35, 35);
2040 LayerImpl
* result_layer
=
2041 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
2044 // We should have passed through the no-touch layer and found the layer
2046 EXPECT_TRUE(result_layer
);
2048 host_impl().active_tree()->LayerById(1234)->SetContentsOpaque(true);
2050 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
2053 // Even with an opaque layer in the middle, we should still find the layer
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
);
2059 test_point
= gfx::Point(35, 15);
2061 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
2063 ASSERT_TRUE(result_layer
);
2064 EXPECT_EQ(123, result_layer
->id());
2066 test_point
= gfx::Point(35, 65);
2068 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
2070 EXPECT_FALSE(result_layer
);
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
);
2078 gfx::Transform identity_matrix
;
2079 gfx::Point3F transform_origin
;
2080 gfx::PointF position
;
2081 gfx::Size
bounds(100, 100);
2082 SetLayerPropertiesForTesting(root
.get(),
2089 root
->SetDrawsContent(true);
2091 host_impl().SetViewportSize(root
->bounds());
2092 host_impl().active_tree()->SetRootLayer(root
.Pass());
2093 host_impl().active_tree()->UpdateDrawProperties();
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());
2099 LayerSelectionBound left_input
;
2100 left_input
.type
= SELECTION_BOUND_LEFT
;
2101 left_input
.layer_rect
= gfx::RectF(10, 10, 5, 20);
2102 left_input
.layer_id
= root_layer_id
;
2104 LayerSelectionBound right_input
;
2105 right_input
.type
= SELECTION_BOUND_RIGHT
;
2106 right_input
.layer_rect
= gfx::RectF(50, 10, 5, 20);
2107 right_input
.layer_id
= root_layer_id
;
2109 ViewportSelectionBound left_output
, right_output
;
2111 // Empty input bounds should produce empty output bounds.
2112 host_impl().active_tree()->GetViewportSelection(&left_output
, &right_output
);
2113 EXPECT_EQ(ViewportSelectionBound(), left_output
);
2114 EXPECT_EQ(ViewportSelectionBound(), right_output
);
2116 // Selection bounds should produce distinct left and right bounds.
2117 host_impl().active_tree()->RegisterSelection(left_input
, right_input
);
2118 host_impl().active_tree()->GetViewportSelection(&left_output
, &right_output
);
2119 EXPECT_EQ(left_input
.type
, left_output
.type
);
2120 EXPECT_EQ(left_input
.layer_rect
, left_output
.viewport_rect
);
2121 EXPECT_TRUE(left_output
.visible
);
2122 EXPECT_EQ(right_input
.type
, right_output
.type
);
2123 EXPECT_EQ(right_input
.layer_rect
, right_output
.viewport_rect
);
2124 EXPECT_TRUE(right_output
.visible
);
2126 // Insertion bounds should produce identical left and right bounds.
2127 LayerSelectionBound insertion_input
;
2128 insertion_input
.type
= SELECTION_BOUND_CENTER
;
2129 insertion_input
.layer_rect
= gfx::RectF(10, 10, 5, 20);
2130 insertion_input
.layer_id
= root_layer_id
;
2131 host_impl().active_tree()->RegisterSelection(insertion_input
,
2132 LayerSelectionBound());
2133 host_impl().active_tree()->GetViewportSelection(&left_output
, &right_output
);
2134 EXPECT_EQ(insertion_input
.type
, left_output
.type
);
2135 EXPECT_EQ(insertion_input
.layer_rect
, left_output
.viewport_rect
);
2136 EXPECT_TRUE(left_output
.visible
);
2137 EXPECT_EQ(left_output
, right_output
);
2140 TEST_F(LayerTreeImplTest
, SelectionBoundsForPartialOccludedLayers
) {
2141 int root_layer_id
= 12345;
2142 int clip_layer_id
= 1234;
2143 int clipped_layer_id
= 123;
2144 scoped_ptr
<LayerImpl
> root
=
2145 LayerImpl::Create(host_impl().active_tree(), root_layer_id
);
2146 root
->SetDrawsContent(true);
2148 gfx::Transform identity_matrix
;
2149 gfx::Point3F transform_origin
;
2150 gfx::PointF position
;
2151 gfx::Size
bounds(100, 100);
2152 SetLayerPropertiesForTesting(root
.get(),
2160 gfx::Vector2dF
clipping_offset(10, 10);
2162 scoped_ptr
<LayerImpl
> clipping_layer
=
2163 LayerImpl::Create(host_impl().active_tree(), clip_layer_id
);
2164 // The clipping layer should occlude the right selection bound.
2165 gfx::PointF position
= gfx::PointF() + clipping_offset
;
2166 gfx::Size
bounds(50, 50);
2167 SetLayerPropertiesForTesting(clipping_layer
.get(),
2174 clipping_layer
->SetMasksToBounds(true);
2176 scoped_ptr
<LayerImpl
> clipped_layer
=
2177 LayerImpl::Create(host_impl().active_tree(), clipped_layer_id
);
2178 position
= gfx::PointF();
2179 bounds
= gfx::Size(100, 100);
2180 SetLayerPropertiesForTesting(clipped_layer
.get(),
2187 clipped_layer
->SetDrawsContent(true);
2188 clipping_layer
->AddChild(clipped_layer
.Pass());
2189 root
->AddChild(clipping_layer
.Pass());
2192 host_impl().SetViewportSize(root
->bounds());
2193 host_impl().active_tree()->SetRootLayer(root
.Pass());
2194 host_impl().active_tree()->UpdateDrawProperties();
2196 // Sanity check the scenario we just created.
2197 ASSERT_EQ(1u, RenderSurfaceLayerList().size());
2199 LayerSelectionBound left_input
;
2200 left_input
.type
= SELECTION_BOUND_LEFT
;
2201 left_input
.layer_rect
= gfx::RectF(25, 10, 5, 20);
2202 left_input
.layer_id
= clipped_layer_id
;
2204 LayerSelectionBound right_input
;
2205 right_input
.type
= SELECTION_BOUND_RIGHT
;
2206 right_input
.layer_rect
= gfx::RectF(75, 10, 5, 20);
2207 right_input
.layer_id
= clipped_layer_id
;
2208 host_impl().active_tree()->RegisterSelection(left_input
, right_input
);
2210 // The left bound should be occluded by the clip layer.
2211 ViewportSelectionBound left_output
, right_output
;
2212 host_impl().active_tree()->GetViewportSelection(&left_output
, &right_output
);
2213 EXPECT_EQ(left_input
.type
, left_output
.type
);
2214 gfx::RectF expected_left_output_rect
= left_input
.layer_rect
;
2215 expected_left_output_rect
.Offset(clipping_offset
);
2216 EXPECT_EQ(expected_left_output_rect
, left_output
.viewport_rect
);
2217 EXPECT_TRUE(left_output
.visible
);
2218 EXPECT_EQ(right_input
.type
, right_output
.type
);
2219 gfx::RectF expected_right_output_rect
= right_input
.layer_rect
;
2220 expected_right_output_rect
.Offset(clipping_offset
);
2221 EXPECT_EQ(expected_right_output_rect
, right_output
.viewport_rect
);
2222 EXPECT_FALSE(right_output
.visible
);
2224 // Handles outside the viewport bounds should be marked invisible.
2225 left_input
.layer_rect
= gfx::RectF(-25, 0, 5, 20);
2226 host_impl().active_tree()->RegisterSelection(left_input
, right_input
);
2227 host_impl().active_tree()->GetViewportSelection(&left_output
, &right_output
);
2228 EXPECT_FALSE(left_output
.visible
);
2230 left_input
.layer_rect
= gfx::RectF(0, -25, 5, 20);
2231 host_impl().active_tree()->RegisterSelection(left_input
, right_input
);
2232 host_impl().active_tree()->GetViewportSelection(&left_output
, &right_output
);
2233 EXPECT_FALSE(left_output
.visible
);
2235 // If the handle bottom is partially visible, the handle is marked visible.
2236 left_input
.layer_rect
= gfx::RectF(0, -20, 5, 21);
2237 host_impl().active_tree()->RegisterSelection(left_input
, right_input
);
2238 host_impl().active_tree()->GetViewportSelection(&left_output
, &right_output
);
2239 EXPECT_TRUE(left_output
.visible
);
2242 TEST_F(LayerTreeImplTest
, SelectionBoundsForScaledLayers
) {
2243 int root_layer_id
= 1;
2244 int sub_layer_id
= 2;
2245 scoped_ptr
<LayerImpl
> root
=
2246 LayerImpl::Create(host_impl().active_tree(), root_layer_id
);
2247 root
->SetDrawsContent(true);
2249 gfx::Transform identity_matrix
;
2250 gfx::Point3F transform_origin
;
2251 gfx::PointF position
;
2252 gfx::Size
bounds(100, 100);
2253 SetLayerPropertiesForTesting(root
.get(),
2261 gfx::Vector2dF
sub_layer_offset(10, 0);
2263 scoped_ptr
<LayerImpl
> sub_layer
=
2264 LayerImpl::Create(host_impl().active_tree(), sub_layer_id
);
2265 gfx::PointF position
= gfx::PointF() + sub_layer_offset
;
2266 gfx::Size
bounds(50, 50);
2267 SetLayerPropertiesForTesting(sub_layer
.get(),
2274 sub_layer
->SetDrawsContent(true);
2275 root
->AddChild(sub_layer
.Pass());
2278 float device_scale_factor
= 3.f
;
2279 float page_scale_factor
= 5.f
;
2280 gfx::Size scaled_bounds_for_root
= gfx::ToCeiledSize(
2281 gfx::ScaleSize(root
->bounds(), device_scale_factor
* page_scale_factor
));
2282 host_impl().SetViewportSize(scaled_bounds_for_root
);
2284 host_impl().SetDeviceScaleFactor(device_scale_factor
);
2285 host_impl().active_tree()->SetPageScaleFactorAndLimits(
2286 page_scale_factor
, page_scale_factor
, page_scale_factor
);
2287 host_impl().active_tree()->SetRootLayer(root
.Pass());
2288 host_impl().active_tree()->SetViewportLayersFromIds(1, 1, Layer::INVALID_ID
);
2289 host_impl().active_tree()->UpdateDrawProperties();
2291 // Sanity check the scenario we just created.
2292 ASSERT_EQ(1u, RenderSurfaceLayerList().size());
2294 LayerSelectionBound left_input
;
2295 left_input
.type
= SELECTION_BOUND_LEFT
;
2296 left_input
.layer_rect
= gfx::RectF(10, 10, 5, 20);
2297 left_input
.layer_id
= root_layer_id
;
2299 LayerSelectionBound right_input
;
2300 right_input
.type
= SELECTION_BOUND_RIGHT
;
2301 right_input
.layer_rect
= gfx::RectF(0, 0, 5, 20);
2302 right_input
.layer_id
= sub_layer_id
;
2303 host_impl().active_tree()->RegisterSelection(left_input
, right_input
);
2305 // The viewport bounds should be properly scaled by the page scale, but should
2306 // remain in DIP coordinates.
2307 ViewportSelectionBound left_output
, right_output
;
2308 host_impl().active_tree()->GetViewportSelection(&left_output
, &right_output
);
2309 EXPECT_EQ(left_input
.type
, left_output
.type
);
2310 gfx::RectF expected_left_output_rect
= left_input
.layer_rect
;
2311 expected_left_output_rect
.Scale(page_scale_factor
);
2312 EXPECT_EQ(left_input
.layer_rect
, left_output
.viewport_rect
);
2313 EXPECT_TRUE(left_output
.visible
);
2314 EXPECT_EQ(right_input
.type
, right_output
.type
);
2315 gfx::RectF expected_right_output_rect
= right_input
.layer_rect
;
2316 expected_right_output_rect
.Offset(sub_layer_offset
);
2317 expected_right_output_rect
.Scale(page_scale_factor
);
2318 EXPECT_EQ(expected_right_output_rect
, right_output
.viewport_rect
);
2319 EXPECT_TRUE(right_output
.visible
);