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/layers/solid_color_scrollbar_layer_impl.h"
10 #include "cc/test/fake_impl_proxy.h"
11 #include "cc/test/fake_layer_tree_host_impl.h"
12 #include "cc/test/fake_output_surface.h"
13 #include "cc/test/geometry_test_utils.h"
14 #include "cc/test/layer_tree_host_common_test.h"
15 #include "cc/test/test_shared_bitmap_manager.h"
16 #include "cc/test/test_task_graph_runner.h"
17 #include "cc/trees/layer_tree_host_impl.h"
18 #include "ui/gfx/geometry/size_conversions.h"
23 class LayerTreeImplTest
: public LayerTreeHostCommonTest
{
26 LayerTreeSettings settings
;
27 settings
.layer_transforms_should_scale_layer_contents
= true;
28 host_impl_
.reset(new FakeLayerTreeHostImpl(
29 settings
, &proxy_
, &shared_bitmap_manager_
, &task_graph_runner_
));
30 EXPECT_TRUE(host_impl_
->InitializeRenderer(FakeOutputSurface::Create3d()));
33 FakeLayerTreeHostImpl
& host_impl() { return *host_impl_
; }
35 LayerImpl
* root_layer() { return host_impl_
->active_tree()->root_layer(); }
37 const LayerImplList
& RenderSurfaceLayerList() const {
38 return host_impl_
->active_tree()->RenderSurfaceLayerList();
42 TestSharedBitmapManager shared_bitmap_manager_
;
43 TestTaskGraphRunner task_graph_runner_
;
45 scoped_ptr
<FakeLayerTreeHostImpl
> host_impl_
;
48 TEST_F(LayerTreeImplTest
, HitTestingForSingleLayer
) {
49 scoped_ptr
<LayerImpl
> root
=
50 LayerImpl::Create(host_impl().active_tree(), 12345);
52 gfx::Transform identity_matrix
;
53 gfx::Point3F transform_origin
;
55 gfx::Size
bounds(100, 100);
56 SetLayerPropertiesForTesting(root
.get(), identity_matrix
, transform_origin
,
57 position
, bounds
, true, false, true);
58 root
->SetDrawsContent(true);
60 host_impl().SetViewportSize(root
->bounds());
61 host_impl().active_tree()->SetRootLayer(root
.Pass());
62 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
64 // Sanity check the scenario we just created.
65 ASSERT_EQ(1u, RenderSurfaceLayerList().size());
66 ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
68 // Hit testing for a point outside the layer should return a null pointer.
69 gfx::Point
test_point(101, 101);
70 LayerImpl
* result_layer
=
71 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
72 EXPECT_FALSE(result_layer
);
74 test_point
= gfx::Point(-1, -1);
76 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
77 EXPECT_FALSE(result_layer
);
79 // Hit testing for a point inside should return the root layer.
80 test_point
= gfx::Point(1, 1);
82 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
83 ASSERT_TRUE(result_layer
);
84 EXPECT_EQ(12345, result_layer
->id());
86 test_point
= gfx::Point(99, 99);
88 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
89 ASSERT_TRUE(result_layer
);
90 EXPECT_EQ(12345, result_layer
->id());
93 TEST_F(LayerTreeImplTest
, HitTestingForSingleLayerAndHud
) {
94 scoped_ptr
<LayerImpl
> root
=
95 LayerImpl::Create(host_impl().active_tree(), 12345);
96 scoped_ptr
<HeadsUpDisplayLayerImpl
> hud
=
97 HeadsUpDisplayLayerImpl::Create(host_impl().active_tree(), 11111);
99 gfx::Transform identity_matrix
;
100 gfx::Point3F transform_origin
;
101 gfx::PointF position
;
102 gfx::Size
bounds(100, 100);
103 SetLayerPropertiesForTesting(root
.get(), identity_matrix
, transform_origin
,
104 position
, bounds
, true, false, true);
105 root
->SetDrawsContent(true);
107 // Create hud and add it as a child of root.
108 gfx::Size
hud_bounds(200, 200);
109 SetLayerPropertiesForTesting(hud
.get(), identity_matrix
, transform_origin
,
110 position
, hud_bounds
, true, false, false);
111 hud
->SetDrawsContent(true);
113 host_impl().active_tree()->set_hud_layer(hud
.get());
114 root
->AddChild(hud
.Pass());
116 host_impl().SetViewportSize(hud_bounds
);
117 host_impl().active_tree()->SetRootLayer(root
.Pass());
118 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
120 // Sanity check the scenario we just created.
121 ASSERT_EQ(1u, RenderSurfaceLayerList().size());
122 ASSERT_EQ(2u, root_layer()->render_surface()->layer_list().size());
124 // Hit testing for a point inside HUD, but outside root should return null
125 gfx::Point
test_point(101, 101);
126 LayerImpl
* result_layer
=
127 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
128 EXPECT_FALSE(result_layer
);
130 test_point
= gfx::Point(-1, -1);
132 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
133 EXPECT_FALSE(result_layer
);
135 // Hit testing for a point inside should return the root layer, never the HUD
137 test_point
= gfx::Point(1, 1);
139 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
140 ASSERT_TRUE(result_layer
);
141 EXPECT_EQ(12345, result_layer
->id());
143 test_point
= gfx::Point(99, 99);
145 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
146 ASSERT_TRUE(result_layer
);
147 EXPECT_EQ(12345, result_layer
->id());
150 TEST_F(LayerTreeImplTest
, HitTestingForUninvertibleTransform
) {
151 scoped_ptr
<LayerImpl
> root
=
152 LayerImpl::Create(host_impl().active_tree(), 12345);
154 gfx::Transform uninvertible_transform
;
155 uninvertible_transform
.matrix().set(0, 0, 0.0);
156 uninvertible_transform
.matrix().set(1, 1, 0.0);
157 uninvertible_transform
.matrix().set(2, 2, 0.0);
158 uninvertible_transform
.matrix().set(3, 3, 0.0);
159 ASSERT_FALSE(uninvertible_transform
.IsInvertible());
161 gfx::Transform identity_matrix
;
162 gfx::Point3F transform_origin
;
163 gfx::PointF position
;
164 gfx::Size
bounds(100, 100);
165 SetLayerPropertiesForTesting(root
.get(), uninvertible_transform
,
166 transform_origin
, position
, bounds
, true, false,
168 root
->SetDrawsContent(true);
170 host_impl().SetViewportSize(root
->bounds());
171 host_impl().active_tree()->SetRootLayer(root
.Pass());
172 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
173 // Sanity check the scenario we just created.
174 ASSERT_EQ(1u, RenderSurfaceLayerList().size());
175 ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
176 ASSERT_FALSE(root_layer()->screen_space_transform().IsInvertible());
178 // Hit testing any point should not hit the layer. If the invertible matrix is
179 // accidentally ignored and treated like an identity, then the hit testing
180 // will incorrectly hit the layer when it shouldn't.
181 gfx::Point
test_point(1, 1);
182 LayerImpl
* result_layer
=
183 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
184 EXPECT_FALSE(result_layer
);
186 test_point
= gfx::Point(10, 10);
188 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
189 EXPECT_FALSE(result_layer
);
191 test_point
= gfx::Point(10, 30);
193 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
194 EXPECT_FALSE(result_layer
);
196 test_point
= gfx::Point(50, 50);
198 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
199 EXPECT_FALSE(result_layer
);
201 test_point
= gfx::Point(67, 48);
203 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
204 EXPECT_FALSE(result_layer
);
206 test_point
= gfx::Point(99, 99);
208 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
209 EXPECT_FALSE(result_layer
);
211 test_point
= gfx::Point(-1, -1);
213 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
214 EXPECT_FALSE(result_layer
);
217 TEST_F(LayerTreeImplTest
, HitTestingForSinglePositionedLayer
) {
218 scoped_ptr
<LayerImpl
> root
=
219 LayerImpl::Create(host_impl().active_tree(), 12345);
221 gfx::Transform identity_matrix
;
222 gfx::Point3F transform_origin
;
223 // this layer is positioned, and hit testing should correctly know where the
225 gfx::PointF
position(50.f
, 50.f
);
226 gfx::Size
bounds(100, 100);
227 SetLayerPropertiesForTesting(root
.get(), identity_matrix
, transform_origin
,
228 position
, bounds
, true, false, true);
229 root
->SetDrawsContent(true);
231 host_impl().SetViewportSize(root
->bounds());
232 host_impl().active_tree()->SetRootLayer(root
.Pass());
233 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
235 // Sanity check the scenario we just created.
236 ASSERT_EQ(1u, RenderSurfaceLayerList().size());
237 ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
239 // Hit testing for a point outside the layer should return a null pointer.
240 gfx::Point
test_point(49, 49);
241 LayerImpl
* result_layer
=
242 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
243 EXPECT_FALSE(result_layer
);
245 // Even though the layer exists at (101, 101), it should not be visible there
246 // since the root render surface would clamp it.
247 test_point
= gfx::Point(101, 101);
249 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
250 EXPECT_FALSE(result_layer
);
252 // Hit testing for a point inside should return the root layer.
253 test_point
= gfx::Point(51, 51);
255 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
256 ASSERT_TRUE(result_layer
);
257 EXPECT_EQ(12345, result_layer
->id());
259 test_point
= gfx::Point(99, 99);
261 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
262 ASSERT_TRUE(result_layer
);
263 EXPECT_EQ(12345, result_layer
->id());
266 TEST_F(LayerTreeImplTest
, HitTestingForSingleRotatedLayer
) {
267 scoped_ptr
<LayerImpl
> root
=
268 LayerImpl::Create(host_impl().active_tree(), 12345);
270 gfx::Transform identity_matrix
;
271 gfx::Transform rotation45_degrees_about_center
;
272 rotation45_degrees_about_center
.Translate(50.0, 50.0);
273 rotation45_degrees_about_center
.RotateAboutZAxis(45.0);
274 rotation45_degrees_about_center
.Translate(-50.0, -50.0);
275 gfx::Point3F transform_origin
;
276 gfx::PointF position
;
277 gfx::Size
bounds(100, 100);
278 SetLayerPropertiesForTesting(root
.get(), rotation45_degrees_about_center
,
279 transform_origin
, position
, bounds
, true, false,
281 root
->SetDrawsContent(true);
283 host_impl().SetViewportSize(root
->bounds());
284 host_impl().active_tree()->SetRootLayer(root
.Pass());
285 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
287 // Sanity check the scenario we just created.
288 ASSERT_EQ(1u, RenderSurfaceLayerList().size());
289 ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
291 // Hit testing for points outside the layer.
292 // These corners would have been inside the un-transformed layer, but they
293 // should not hit the correctly transformed layer.
294 gfx::Point
test_point(99, 99);
295 LayerImpl
* result_layer
=
296 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
297 EXPECT_FALSE(result_layer
);
299 test_point
= gfx::Point(1, 1);
301 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
302 EXPECT_FALSE(result_layer
);
304 // Hit testing for a point inside should return the root layer.
305 test_point
= gfx::Point(1, 50);
307 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
308 ASSERT_TRUE(result_layer
);
309 EXPECT_EQ(12345, result_layer
->id());
311 // Hit testing the corners that would overlap the unclipped layer, but are
312 // outside the clipped region.
313 test_point
= gfx::Point(50, -1);
315 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
316 ASSERT_FALSE(result_layer
);
318 test_point
= gfx::Point(-1, 50);
320 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
321 ASSERT_FALSE(result_layer
);
324 TEST_F(LayerTreeImplTest
, HitTestingForSinglePerspectiveLayer
) {
325 scoped_ptr
<LayerImpl
> root
=
326 LayerImpl::Create(host_impl().active_tree(), 12345);
328 gfx::Transform identity_matrix
;
330 // perspective_projection_about_center * translation_by_z is designed so that
331 // the 100 x 100 layer becomes 50 x 50, and remains centered at (50, 50).
332 gfx::Transform perspective_projection_about_center
;
333 perspective_projection_about_center
.Translate(50.0, 50.0);
334 perspective_projection_about_center
.ApplyPerspectiveDepth(1.0);
335 perspective_projection_about_center
.Translate(-50.0, -50.0);
336 gfx::Transform translation_by_z
;
337 translation_by_z
.Translate3d(0.0, 0.0, -1.0);
339 gfx::Point3F transform_origin
;
340 gfx::PointF position
;
341 gfx::Size
bounds(100, 100);
342 SetLayerPropertiesForTesting(
343 root
.get(), perspective_projection_about_center
* translation_by_z
,
344 transform_origin
, position
, bounds
, true, false, true);
345 root
->SetDrawsContent(true);
347 host_impl().SetViewportSize(root
->bounds());
348 host_impl().active_tree()->SetRootLayer(root
.Pass());
349 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
351 // Sanity check the scenario we just created.
352 ASSERT_EQ(1u, RenderSurfaceLayerList().size());
353 ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
355 // Hit testing for points outside the layer.
356 // These corners would have been inside the un-transformed layer, but they
357 // should not hit the correctly transformed layer.
358 gfx::Point
test_point(24, 24);
359 LayerImpl
* result_layer
=
360 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
361 EXPECT_FALSE(result_layer
);
363 test_point
= gfx::Point(76, 76);
365 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
366 EXPECT_FALSE(result_layer
);
368 // Hit testing for a point inside should return the root layer.
369 test_point
= gfx::Point(26, 26);
371 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
372 ASSERT_TRUE(result_layer
);
373 EXPECT_EQ(12345, result_layer
->id());
375 test_point
= gfx::Point(74, 74);
377 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
378 ASSERT_TRUE(result_layer
);
379 EXPECT_EQ(12345, result_layer
->id());
382 TEST_F(LayerTreeImplTest
, HitTestingForSimpleClippedLayer
) {
383 // Test that hit-testing will only work for the visible portion of a layer,
384 // and not the entire layer bounds. Here we just test the simple axis-aligned
386 gfx::Transform identity_matrix
;
387 gfx::Point3F transform_origin
;
389 scoped_ptr
<LayerImpl
> root
= LayerImpl::Create(host_impl().active_tree(), 1);
390 SetLayerPropertiesForTesting(root
.get(), identity_matrix
, transform_origin
,
391 gfx::PointF(), gfx::Size(100, 100), true, false,
394 scoped_ptr
<LayerImpl
> clipping_layer
=
395 LayerImpl::Create(host_impl().active_tree(), 123);
396 // this layer is positioned, and hit testing should correctly know where the
398 gfx::PointF
position(25.f
, 25.f
);
399 gfx::Size
bounds(50, 50);
400 SetLayerPropertiesForTesting(clipping_layer
.get(), identity_matrix
,
401 transform_origin
, position
, bounds
, true,
403 clipping_layer
->SetMasksToBounds(true);
405 scoped_ptr
<LayerImpl
> child
=
406 LayerImpl::Create(host_impl().active_tree(), 456);
407 position
= gfx::PointF(-50.f
, -50.f
);
408 bounds
= gfx::Size(300, 300);
409 SetLayerPropertiesForTesting(child
.get(), identity_matrix
, transform_origin
,
410 position
, bounds
, true, false, false);
411 child
->SetDrawsContent(true);
412 clipping_layer
->AddChild(child
.Pass());
413 root
->AddChild(clipping_layer
.Pass());
416 host_impl().SetViewportSize(root
->bounds());
417 host_impl().active_tree()->SetRootLayer(root
.Pass());
418 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
420 // Sanity check the scenario we just created.
421 ASSERT_EQ(1u, RenderSurfaceLayerList().size());
422 ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
423 ASSERT_EQ(456, root_layer()->render_surface()->layer_list().at(0)->id());
425 // Hit testing for a point outside the layer should return a null pointer.
426 // Despite the child layer being very large, it should be clipped to the root
428 gfx::Point
test_point(24, 24);
429 LayerImpl
* result_layer
=
430 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
431 EXPECT_FALSE(result_layer
);
433 // Even though the layer exists at (101, 101), it should not be visible there
434 // since the clipping_layer would clamp it.
435 test_point
= gfx::Point(76, 76);
437 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
438 EXPECT_FALSE(result_layer
);
440 // Hit testing for a point inside should return the child layer.
441 test_point
= gfx::Point(26, 26);
443 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
444 ASSERT_TRUE(result_layer
);
445 EXPECT_EQ(456, result_layer
->id());
447 test_point
= gfx::Point(74, 74);
449 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
450 ASSERT_TRUE(result_layer
);
451 EXPECT_EQ(456, result_layer
->id());
454 TEST_F(LayerTreeImplTest
, HitTestingForMultiClippedRotatedLayer
) {
455 // This test checks whether hit testing correctly avoids hit testing with
456 // multiple ancestors that clip in non axis-aligned ways. To pass this test,
457 // the hit testing algorithm needs to recognize that multiple parent layers
458 // may clip the layer, and should not actually hit those clipped areas.
460 // The child and grand_child layers are both initialized to clip the
461 // rotated_leaf. The child layer is rotated about the top-left corner, so that
462 // the root + child clips combined create a triangle. The rotated_leaf will
463 // only be visible where it overlaps this triangle.
465 scoped_ptr
<LayerImpl
> root
=
466 LayerImpl::Create(host_impl().active_tree(), 123);
468 gfx::Transform identity_matrix
;
469 gfx::Point3F transform_origin
;
470 gfx::PointF position
;
471 gfx::Size
bounds(100, 100);
472 SetLayerPropertiesForTesting(root
.get(), identity_matrix
, transform_origin
,
473 position
, bounds
, true, false, true);
474 root
->SetMasksToBounds(true);
476 scoped_ptr
<LayerImpl
> child
=
477 LayerImpl::Create(host_impl().active_tree(), 456);
478 scoped_ptr
<LayerImpl
> grand_child
=
479 LayerImpl::Create(host_impl().active_tree(), 789);
480 scoped_ptr
<LayerImpl
> rotated_leaf
=
481 LayerImpl::Create(host_impl().active_tree(), 2468);
483 position
= gfx::PointF(10.f
, 10.f
);
484 bounds
= gfx::Size(80, 80);
485 SetLayerPropertiesForTesting(child
.get(), identity_matrix
, transform_origin
,
486 position
, bounds
, true, false, false);
487 child
->SetMasksToBounds(true);
489 gfx::Transform rotation45_degrees_about_corner
;
490 rotation45_degrees_about_corner
.RotateAboutZAxis(45.0);
492 // remember, positioned with respect to its parent which is already at 10,
494 position
= gfx::PointF();
496 gfx::Size(200, 200); // to ensure it covers at least sqrt(2) * 100.
497 SetLayerPropertiesForTesting(
498 grand_child
.get(), rotation45_degrees_about_corner
, transform_origin
,
499 position
, bounds
, true, false, false);
500 grand_child
->SetMasksToBounds(true);
502 // Rotates about the center of the layer
503 gfx::Transform rotated_leaf_transform
;
504 rotated_leaf_transform
.Translate(
505 -10.0, -10.0); // cancel out the grand_parent's position
506 rotated_leaf_transform
.RotateAboutZAxis(
507 -45.0); // cancel out the corner 45-degree rotation of the parent.
508 rotated_leaf_transform
.Translate(50.0, 50.0);
509 rotated_leaf_transform
.RotateAboutZAxis(45.0);
510 rotated_leaf_transform
.Translate(-50.0, -50.0);
511 position
= gfx::PointF();
512 bounds
= gfx::Size(100, 100);
513 SetLayerPropertiesForTesting(rotated_leaf
.get(), rotated_leaf_transform
,
514 transform_origin
, position
, bounds
, true,
516 rotated_leaf
->SetDrawsContent(true);
518 grand_child
->AddChild(rotated_leaf
.Pass());
519 child
->AddChild(grand_child
.Pass());
520 root
->AddChild(child
.Pass());
523 host_impl().SetViewportSize(root
->bounds());
524 host_impl().active_tree()->SetRootLayer(root
.Pass());
525 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
527 // (11, 89) is close to the the bottom left corner within the clip, but it is
528 // not inside the layer.
529 gfx::Point
test_point(11, 89);
530 LayerImpl
* result_layer
=
531 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
532 EXPECT_FALSE(result_layer
);
534 // Closer inwards from the bottom left will overlap the layer.
535 test_point
= gfx::Point(25, 75);
537 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
538 ASSERT_TRUE(result_layer
);
539 EXPECT_EQ(2468, result_layer
->id());
541 // (4, 50) is inside the unclipped layer, but that corner of the layer should
542 // be clipped away by the grandparent and should not get hit. If hit testing
543 // blindly uses visible content rect without considering how parent may clip
544 // the layer, then hit testing would accidentally think that the point
545 // successfully hits the layer.
546 test_point
= gfx::Point(4, 50);
548 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
549 EXPECT_FALSE(result_layer
);
551 // (11, 50) is inside the layer and within the clipped area.
552 test_point
= gfx::Point(11, 50);
554 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
555 ASSERT_TRUE(result_layer
);
556 EXPECT_EQ(2468, result_layer
->id());
558 // Around the middle, just to the right and up, would have hit the layer
559 // except that that area should be clipped away by the parent.
560 test_point
= gfx::Point(51, 49);
562 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
563 EXPECT_FALSE(result_layer
);
565 // Around the middle, just to the left and down, should successfully hit the
567 test_point
= gfx::Point(49, 51);
569 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
570 ASSERT_TRUE(result_layer
);
571 EXPECT_EQ(2468, result_layer
->id());
574 TEST_F(LayerTreeImplTest
, HitTestingForNonClippingIntermediateLayer
) {
575 // This test checks that hit testing code does not accidentally clip to layer
576 // bounds for a layer that actually does not clip.
577 gfx::Transform identity_matrix
;
578 gfx::Point3F transform_origin
;
580 scoped_ptr
<LayerImpl
> root
= LayerImpl::Create(host_impl().active_tree(), 1);
581 SetLayerPropertiesForTesting(root
.get(), identity_matrix
, transform_origin
,
582 gfx::PointF(), gfx::Size(100, 100), true, false,
585 scoped_ptr
<LayerImpl
> intermediate_layer
=
586 LayerImpl::Create(host_impl().active_tree(), 123);
587 // this layer is positioned, and hit testing should correctly know where the
589 gfx::PointF
position(10.f
, 10.f
);
590 gfx::Size
bounds(50, 50);
591 SetLayerPropertiesForTesting(intermediate_layer
.get(), identity_matrix
,
592 transform_origin
, position
, bounds
, true,
594 // Sanity check the intermediate layer should not clip.
595 ASSERT_FALSE(intermediate_layer
->masks_to_bounds());
596 ASSERT_FALSE(intermediate_layer
->mask_layer());
598 // The child of the intermediate_layer is translated so that it does not
599 // overlap intermediate_layer at all. If child is incorrectly clipped, we
600 // would not be able to hit it successfully.
601 scoped_ptr
<LayerImpl
> child
=
602 LayerImpl::Create(host_impl().active_tree(), 456);
603 position
= gfx::PointF(60.f
, 60.f
); // 70, 70 in screen space
604 bounds
= gfx::Size(20, 20);
605 SetLayerPropertiesForTesting(child
.get(), identity_matrix
, transform_origin
,
606 position
, bounds
, true, false, false);
607 child
->SetDrawsContent(true);
608 intermediate_layer
->AddChild(child
.Pass());
609 root
->AddChild(intermediate_layer
.Pass());
612 host_impl().SetViewportSize(root
->bounds());
613 host_impl().active_tree()->SetRootLayer(root
.Pass());
614 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
616 // Sanity check the scenario we just created.
617 ASSERT_EQ(1u, RenderSurfaceLayerList().size());
618 ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
619 ASSERT_EQ(456, root_layer()->render_surface()->layer_list().at(0)->id());
621 // Hit testing for a point outside the layer should return a null pointer.
622 gfx::Point
test_point(69, 69);
623 LayerImpl
* result_layer
=
624 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
625 EXPECT_FALSE(result_layer
);
627 test_point
= gfx::Point(91, 91);
629 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
630 EXPECT_FALSE(result_layer
);
632 // Hit testing for a point inside should return the child layer.
633 test_point
= gfx::Point(71, 71);
635 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
636 ASSERT_TRUE(result_layer
);
637 EXPECT_EQ(456, result_layer
->id());
639 test_point
= gfx::Point(89, 89);
641 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
642 ASSERT_TRUE(result_layer
);
643 EXPECT_EQ(456, result_layer
->id());
646 TEST_F(LayerTreeImplTest
, HitTestingForMultipleLayers
) {
647 scoped_ptr
<LayerImpl
> root
= LayerImpl::Create(host_impl().active_tree(), 1);
649 gfx::Transform identity_matrix
;
650 gfx::Point3F transform_origin
;
651 gfx::PointF position
;
652 gfx::Size
bounds(100, 100);
653 SetLayerPropertiesForTesting(root
.get(), identity_matrix
, transform_origin
,
654 position
, bounds
, true, false, true);
655 root
->SetDrawsContent(true);
657 // child 1 and child2 are initialized to overlap between x=50 and x=60.
658 // grand_child is set to overlap both child1 and child2 between y=50 and
659 // y=60. The expected stacking order is: (front) child2, (second)
660 // grand_child, (third) child1, and (back) the root layer behind all other
663 scoped_ptr
<LayerImpl
> child1
=
664 LayerImpl::Create(host_impl().active_tree(), 2);
665 scoped_ptr
<LayerImpl
> child2
=
666 LayerImpl::Create(host_impl().active_tree(), 3);
667 scoped_ptr
<LayerImpl
> grand_child1
=
668 LayerImpl::Create(host_impl().active_tree(), 4);
670 position
= gfx::PointF(10.f
, 10.f
);
671 bounds
= gfx::Size(50, 50);
672 SetLayerPropertiesForTesting(child1
.get(), identity_matrix
,
673 transform_origin
, position
, bounds
, true,
675 child1
->SetDrawsContent(true);
677 position
= gfx::PointF(50.f
, 10.f
);
678 bounds
= gfx::Size(50, 50);
679 SetLayerPropertiesForTesting(child2
.get(), identity_matrix
,
680 transform_origin
, position
, bounds
, true,
682 child2
->SetDrawsContent(true);
684 // Remember that grand_child is positioned with respect to its parent (i.e.
685 // child1). In screen space, the intended position is (10, 50), with size
687 position
= gfx::PointF(0.f
, 40.f
);
688 bounds
= gfx::Size(100, 50);
689 SetLayerPropertiesForTesting(grand_child1
.get(), identity_matrix
,
690 transform_origin
, position
, bounds
, true,
692 grand_child1
->SetDrawsContent(true);
694 child1
->AddChild(grand_child1
.Pass());
695 root
->AddChild(child1
.Pass());
696 root
->AddChild(child2
.Pass());
699 LayerImpl
* child1
= root
->children()[0];
700 LayerImpl
* child2
= root
->children()[1];
701 LayerImpl
* grand_child1
= child1
->children()[0];
703 host_impl().SetViewportSize(root
->bounds());
704 host_impl().active_tree()->SetRootLayer(root
.Pass());
705 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
707 // Sanity check the scenario we just created.
710 ASSERT_TRUE(grand_child1
);
711 ASSERT_EQ(1u, RenderSurfaceLayerList().size());
713 RenderSurfaceImpl
* root_render_surface
= root_layer()->render_surface();
714 ASSERT_EQ(4u, root_render_surface
->layer_list().size());
715 ASSERT_EQ(1, root_render_surface
->layer_list().at(0)->id()); // root layer
716 ASSERT_EQ(2, root_render_surface
->layer_list().at(1)->id()); // child1
717 ASSERT_EQ(4, root_render_surface
->layer_list().at(2)->id()); // grand_child1
718 ASSERT_EQ(3, root_render_surface
->layer_list().at(3)->id()); // child2
720 // Nothing overlaps the root_layer at (1, 1), so hit testing there should find
722 gfx::Point test_point
= gfx::Point(1, 1);
723 LayerImpl
* result_layer
=
724 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
725 ASSERT_TRUE(result_layer
);
726 EXPECT_EQ(1, result_layer
->id());
728 // At (15, 15), child1 and root are the only layers. child1 is expected to be
730 test_point
= gfx::Point(15, 15);
732 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
733 ASSERT_TRUE(result_layer
);
734 EXPECT_EQ(2, result_layer
->id());
736 // At (51, 20), child1 and child2 overlap. child2 is expected to be on top.
737 test_point
= gfx::Point(51, 20);
739 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
740 ASSERT_TRUE(result_layer
);
741 EXPECT_EQ(3, result_layer
->id());
743 // At (80, 51), child2 and grand_child1 overlap. child2 is expected to be on
745 test_point
= gfx::Point(80, 51);
747 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
748 ASSERT_TRUE(result_layer
);
749 EXPECT_EQ(3, result_layer
->id());
751 // At (51, 51), all layers overlap each other. child2 is expected to be on top
752 // of all other layers.
753 test_point
= gfx::Point(51, 51);
755 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
756 ASSERT_TRUE(result_layer
);
757 EXPECT_EQ(3, result_layer
->id());
759 // At (20, 51), child1 and grand_child1 overlap. grand_child1 is expected to
761 test_point
= gfx::Point(20, 51);
763 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
764 ASSERT_TRUE(result_layer
);
765 EXPECT_EQ(4, result_layer
->id());
768 TEST_F(LayerTreeImplTest
, HitTestingForMultipleLayersAtVaryingDepths
) {
769 scoped_ptr
<LayerImpl
> root
= LayerImpl::Create(host_impl().active_tree(), 1);
771 gfx::Transform identity_matrix
;
772 gfx::Point3F transform_origin
;
773 gfx::PointF position
;
774 gfx::Size
bounds(100, 100);
775 SetLayerPropertiesForTesting(root
.get(), identity_matrix
, transform_origin
,
776 position
, bounds
, true, false, true);
777 root
->SetDrawsContent(true);
778 root
->SetShouldFlattenTransform(false);
779 root
->Set3dSortingContextId(1);
781 // child 1 and child2 are initialized to overlap between x=50 and x=60.
782 // grand_child is set to overlap both child1 and child2 between y=50 and
783 // y=60. The expected stacking order is: (front) child2, (second)
784 // grand_child, (third) child1, and (back) the root layer behind all other
787 scoped_ptr
<LayerImpl
> child1
=
788 LayerImpl::Create(host_impl().active_tree(), 2);
789 scoped_ptr
<LayerImpl
> child2
=
790 LayerImpl::Create(host_impl().active_tree(), 3);
791 scoped_ptr
<LayerImpl
> grand_child1
=
792 LayerImpl::Create(host_impl().active_tree(), 4);
794 position
= gfx::PointF(10.f
, 10.f
);
795 bounds
= gfx::Size(50, 50);
796 SetLayerPropertiesForTesting(child1
.get(), identity_matrix
,
797 transform_origin
, position
, bounds
, true,
799 child1
->SetDrawsContent(true);
800 child1
->SetShouldFlattenTransform(false);
801 child1
->Set3dSortingContextId(1);
803 position
= gfx::PointF(50.f
, 10.f
);
804 bounds
= gfx::Size(50, 50);
805 gfx::Transform translate_z
;
806 translate_z
.Translate3d(0, 0, -10.f
);
807 SetLayerPropertiesForTesting(child2
.get(), translate_z
, transform_origin
,
808 position
, bounds
, true, false, false);
809 child2
->SetDrawsContent(true);
810 child2
->SetShouldFlattenTransform(false);
811 child2
->Set3dSortingContextId(1);
813 // Remember that grand_child is positioned with respect to its parent (i.e.
814 // child1). In screen space, the intended position is (10, 50), with size
816 position
= gfx::PointF(0.f
, 40.f
);
817 bounds
= gfx::Size(100, 50);
818 SetLayerPropertiesForTesting(grand_child1
.get(), identity_matrix
,
819 transform_origin
, position
, bounds
, true,
821 grand_child1
->SetDrawsContent(true);
822 grand_child1
->SetShouldFlattenTransform(false);
824 child1
->AddChild(grand_child1
.Pass());
825 root
->AddChild(child1
.Pass());
826 root
->AddChild(child2
.Pass());
829 LayerImpl
* child1
= root
->children()[0];
830 LayerImpl
* child2
= root
->children()[1];
831 LayerImpl
* grand_child1
= child1
->children()[0];
833 host_impl().SetViewportSize(root
->bounds());
834 host_impl().active_tree()->SetRootLayer(root
.Pass());
835 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
837 // Sanity check the scenario we just created.
840 ASSERT_TRUE(grand_child1
);
841 ASSERT_EQ(1u, RenderSurfaceLayerList().size());
843 // Nothing overlaps the root_layer at (1, 1), so hit testing there should find
845 gfx::Point test_point
= gfx::Point(1, 1);
846 LayerImpl
* result_layer
=
847 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
848 ASSERT_TRUE(result_layer
);
849 EXPECT_EQ(1, result_layer
->id());
851 // At (15, 15), child1 and root are the only layers. child1 is expected to be
853 test_point
= gfx::Point(15, 15);
855 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
856 ASSERT_TRUE(result_layer
);
857 EXPECT_EQ(2, result_layer
->id());
859 // At (51, 20), child1 and child2 overlap. child2 is expected to be on top.
860 // (because 3 is transformed to the back).
861 test_point
= gfx::Point(51, 20);
863 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
864 ASSERT_TRUE(result_layer
);
865 EXPECT_EQ(2, result_layer
->id());
867 // 3 Would have been on top if it hadn't been transformed to the background.
868 // Make sure that it isn't hit.
869 test_point
= gfx::Point(80, 51);
871 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
872 ASSERT_TRUE(result_layer
);
873 EXPECT_EQ(4, result_layer
->id());
875 // 3 Would have been on top if it hadn't been transformed to the background.
876 // Make sure that it isn't hit.
877 test_point
= gfx::Point(51, 51);
879 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
880 ASSERT_TRUE(result_layer
);
881 EXPECT_EQ(4, result_layer
->id());
883 // At (20, 51), child1 and grand_child1 overlap. grand_child1 is expected to
885 test_point
= gfx::Point(20, 51);
887 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
888 ASSERT_TRUE(result_layer
);
889 EXPECT_EQ(4, result_layer
->id());
892 TEST_F(LayerTreeImplTest
, HitTestingRespectsClipParents
) {
893 scoped_ptr
<LayerImpl
> root
= LayerImpl::Create(host_impl().active_tree(), 1);
894 gfx::Transform identity_matrix
;
895 gfx::Point3F transform_origin
;
896 gfx::PointF position
;
897 gfx::Size
bounds(100, 100);
898 SetLayerPropertiesForTesting(root
.get(), identity_matrix
, transform_origin
,
899 position
, bounds
, true, false, true);
900 root
->SetDrawsContent(true);
902 scoped_ptr
<LayerImpl
> child
=
903 LayerImpl::Create(host_impl().active_tree(), 2);
904 scoped_ptr
<LayerImpl
> grand_child
=
905 LayerImpl::Create(host_impl().active_tree(), 4);
907 position
= gfx::PointF(10.f
, 10.f
);
908 bounds
= gfx::Size(1, 1);
909 SetLayerPropertiesForTesting(child
.get(), identity_matrix
, transform_origin
,
910 position
, bounds
, true, false, false);
911 child
->SetDrawsContent(true);
912 child
->SetMasksToBounds(true);
914 position
= gfx::PointF(0.f
, 40.f
);
915 bounds
= gfx::Size(100, 50);
916 SetLayerPropertiesForTesting(grand_child
.get(), identity_matrix
,
917 transform_origin
, position
, bounds
, true,
919 grand_child
->SetDrawsContent(true);
920 grand_child
->SetHasRenderSurface(true);
922 // This should let |grand_child| "escape" |child|'s clip.
923 grand_child
->SetClipParent(root
.get());
925 child
->AddChild(grand_child
.Pass());
926 root
->AddChild(child
.Pass());
929 host_impl().SetViewportSize(root
->bounds());
930 host_impl().active_tree()->SetRootLayer(root
.Pass());
931 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
933 gfx::Point test_point
= gfx::Point(12, 52);
934 LayerImpl
* result_layer
=
935 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
936 ASSERT_TRUE(result_layer
);
937 EXPECT_EQ(4, result_layer
->id());
940 TEST_F(LayerTreeImplTest
, HitTestingRespectsScrollParents
) {
941 scoped_ptr
<LayerImpl
> root
= LayerImpl::Create(host_impl().active_tree(), 1);
942 gfx::Transform identity_matrix
;
943 gfx::Point3F transform_origin
;
944 gfx::PointF position
;
945 gfx::Size
bounds(100, 100);
946 SetLayerPropertiesForTesting(root
.get(), identity_matrix
, transform_origin
,
947 position
, bounds
, true, false, true);
948 root
->SetDrawsContent(true);
950 scoped_ptr
<LayerImpl
> child
=
951 LayerImpl::Create(host_impl().active_tree(), 2);
952 scoped_ptr
<LayerImpl
> scroll_child
=
953 LayerImpl::Create(host_impl().active_tree(), 3);
954 scoped_ptr
<LayerImpl
> grand_child
=
955 LayerImpl::Create(host_impl().active_tree(), 4);
957 position
= gfx::PointF(10.f
, 10.f
);
958 bounds
= gfx::Size(1, 1);
959 SetLayerPropertiesForTesting(child
.get(), identity_matrix
, transform_origin
,
960 position
, bounds
, true, false, false);
961 child
->SetDrawsContent(true);
962 child
->SetMasksToBounds(true);
964 position
= gfx::PointF();
965 bounds
= gfx::Size(200, 200);
966 SetLayerPropertiesForTesting(scroll_child
.get(), identity_matrix
,
967 transform_origin
, position
, bounds
, true,
969 scroll_child
->SetDrawsContent(true);
971 // This should cause scroll child and its descendants to be affected by
973 scroll_child
->SetScrollParent(child
.get());
974 scoped_ptr
<std::set
<LayerImpl
*>> scroll_children(new std::set
<LayerImpl
*>);
975 scroll_children
->insert(scroll_child
.get());
976 child
->SetScrollChildren(scroll_children
.release());
978 SetLayerPropertiesForTesting(grand_child
.get(), identity_matrix
,
979 transform_origin
, position
, bounds
, true,
981 grand_child
->SetDrawsContent(true);
982 grand_child
->SetHasRenderSurface(true);
984 scroll_child
->AddChild(grand_child
.Pass());
985 root
->AddChild(scroll_child
.Pass());
986 root
->AddChild(child
.Pass());
989 host_impl().SetViewportSize(root
->bounds());
990 host_impl().active_tree()->SetRootLayer(root
.Pass());
991 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
993 gfx::Point test_point
= gfx::Point(12, 52);
994 LayerImpl
* result_layer
=
995 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
996 // The |test_point| should have been clipped away by |child|, the scroll
997 // parent, so the only thing that should be hit is |root|.
998 ASSERT_TRUE(result_layer
);
999 ASSERT_EQ(1, result_layer
->id());
1001 TEST_F(LayerTreeImplTest
, HitTestingForMultipleLayerLists
) {
1003 // The geometry is set up similarly to the previous case, but
1004 // all layers are forced to be render surfaces now.
1006 scoped_ptr
<LayerImpl
> root
= LayerImpl::Create(host_impl().active_tree(), 1);
1008 gfx::Transform identity_matrix
;
1009 gfx::Point3F transform_origin
;
1010 gfx::PointF position
;
1011 gfx::Size
bounds(100, 100);
1012 SetLayerPropertiesForTesting(root
.get(), identity_matrix
, transform_origin
,
1013 position
, bounds
, true, false, true);
1014 root
->SetDrawsContent(true);
1016 // child 1 and child2 are initialized to overlap between x=50 and x=60.
1017 // grand_child is set to overlap both child1 and child2 between y=50 and
1018 // y=60. The expected stacking order is: (front) child2, (second)
1019 // grand_child, (third) child1, and (back) the root layer behind all other
1022 scoped_ptr
<LayerImpl
> child1
=
1023 LayerImpl::Create(host_impl().active_tree(), 2);
1024 scoped_ptr
<LayerImpl
> child2
=
1025 LayerImpl::Create(host_impl().active_tree(), 3);
1026 scoped_ptr
<LayerImpl
> grand_child1
=
1027 LayerImpl::Create(host_impl().active_tree(), 4);
1029 position
= gfx::PointF(10.f
, 10.f
);
1030 bounds
= gfx::Size(50, 50);
1031 SetLayerPropertiesForTesting(child1
.get(), identity_matrix
,
1032 transform_origin
, position
, bounds
, true,
1034 child1
->SetDrawsContent(true);
1035 child1
->SetHasRenderSurface(true);
1037 position
= gfx::PointF(50.f
, 10.f
);
1038 bounds
= gfx::Size(50, 50);
1039 SetLayerPropertiesForTesting(child2
.get(), identity_matrix
,
1040 transform_origin
, position
, bounds
, true,
1042 child2
->SetDrawsContent(true);
1043 child2
->SetHasRenderSurface(true);
1045 // Remember that grand_child is positioned with respect to its parent (i.e.
1046 // child1). In screen space, the intended position is (10, 50), with size
1048 position
= gfx::PointF(0.f
, 40.f
);
1049 bounds
= gfx::Size(100, 50);
1050 SetLayerPropertiesForTesting(grand_child1
.get(), identity_matrix
,
1051 transform_origin
, position
, bounds
, true,
1053 grand_child1
->SetDrawsContent(true);
1054 grand_child1
->SetHasRenderSurface(true);
1056 child1
->AddChild(grand_child1
.Pass());
1057 root
->AddChild(child1
.Pass());
1058 root
->AddChild(child2
.Pass());
1061 LayerImpl
* child1
= root
->children()[0];
1062 LayerImpl
* child2
= root
->children()[1];
1063 LayerImpl
* grand_child1
= child1
->children()[0];
1065 host_impl().SetViewportSize(root
->bounds());
1066 host_impl().active_tree()->SetRootLayer(root
.Pass());
1067 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
1069 // Sanity check the scenario we just created.
1070 ASSERT_TRUE(child1
);
1071 ASSERT_TRUE(child2
);
1072 ASSERT_TRUE(grand_child1
);
1073 ASSERT_TRUE(child1
->render_surface());
1074 ASSERT_TRUE(child2
->render_surface());
1075 ASSERT_TRUE(grand_child1
->render_surface());
1076 ASSERT_EQ(4u, RenderSurfaceLayerList().size());
1077 // The root surface has the root layer, and child1's and child2's render
1079 ASSERT_EQ(3u, root_layer()->render_surface()->layer_list().size());
1080 // The child1 surface has the child1 layer and grand_child1's render surface.
1081 ASSERT_EQ(2u, child1
->render_surface()->layer_list().size());
1082 ASSERT_EQ(1u, child2
->render_surface()->layer_list().size());
1083 ASSERT_EQ(1u, grand_child1
->render_surface()->layer_list().size());
1084 ASSERT_EQ(1, RenderSurfaceLayerList().at(0)->id()); // root layer
1085 ASSERT_EQ(2, RenderSurfaceLayerList()[1]->id()); // child1
1086 ASSERT_EQ(4, RenderSurfaceLayerList().at(2)->id()); // grand_child1
1087 ASSERT_EQ(3, RenderSurfaceLayerList()[3]->id()); // child2
1089 // Nothing overlaps the root_layer at (1, 1), so hit testing there should find
1091 gfx::Point test_point
= gfx::Point(1, 1);
1092 LayerImpl
* result_layer
=
1093 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
1094 ASSERT_TRUE(result_layer
);
1095 EXPECT_EQ(1, result_layer
->id());
1097 // At (15, 15), child1 and root are the only layers. child1 is expected to be
1099 test_point
= gfx::Point(15, 15);
1101 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
1102 ASSERT_TRUE(result_layer
);
1103 EXPECT_EQ(2, result_layer
->id());
1105 // At (51, 20), child1 and child2 overlap. child2 is expected to be on top.
1106 test_point
= gfx::Point(51, 20);
1108 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
1109 ASSERT_TRUE(result_layer
);
1110 EXPECT_EQ(3, result_layer
->id());
1112 // At (80, 51), child2 and grand_child1 overlap. child2 is expected to be on
1114 test_point
= gfx::Point(80, 51);
1116 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
1117 ASSERT_TRUE(result_layer
);
1118 EXPECT_EQ(3, result_layer
->id());
1120 // At (51, 51), all layers overlap each other. child2 is expected to be on top
1121 // of all other layers.
1122 test_point
= gfx::Point(51, 51);
1124 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
1125 ASSERT_TRUE(result_layer
);
1126 EXPECT_EQ(3, result_layer
->id());
1128 // At (20, 51), child1 and grand_child1 overlap. grand_child1 is expected to
1130 test_point
= gfx::Point(20, 51);
1132 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
1133 ASSERT_TRUE(result_layer
);
1134 EXPECT_EQ(4, result_layer
->id());
1137 TEST_F(LayerTreeImplTest
, HitCheckingTouchHandlerRegionsForSingleLayer
) {
1138 scoped_ptr
<LayerImpl
> root
=
1139 LayerImpl::Create(host_impl().active_tree(), 12345);
1141 gfx::Transform identity_matrix
;
1142 Region
touch_handler_region(gfx::Rect(10, 10, 50, 50));
1143 gfx::Point3F transform_origin
;
1144 gfx::PointF position
;
1145 gfx::Size
bounds(100, 100);
1146 SetLayerPropertiesForTesting(root
.get(), identity_matrix
, transform_origin
,
1147 position
, bounds
, true, false, true);
1148 root
->SetDrawsContent(true);
1150 host_impl().SetViewportSize(root
->bounds());
1151 host_impl().active_tree()->SetRootLayer(root
.Pass());
1152 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
1154 // Sanity check the scenario we just created.
1155 ASSERT_EQ(1u, RenderSurfaceLayerList().size());
1156 ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
1158 // Hit checking for any point should return a null pointer for a layer without
1159 // any touch event handler regions.
1160 gfx::Point
test_point(11, 11);
1161 LayerImpl
* result_layer
=
1162 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1164 EXPECT_FALSE(result_layer
);
1166 host_impl().active_tree()->root_layer()->SetTouchEventHandlerRegion(
1167 touch_handler_region
);
1168 // Hit checking for a point outside the layer should return a null pointer.
1169 test_point
= gfx::Point(101, 101);
1171 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1173 EXPECT_FALSE(result_layer
);
1175 test_point
= gfx::Point(-1, -1);
1177 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1179 EXPECT_FALSE(result_layer
);
1181 // Hit checking for a point inside the layer, but outside the touch handler
1182 // region should return a null pointer.
1183 test_point
= gfx::Point(1, 1);
1185 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1187 EXPECT_FALSE(result_layer
);
1189 test_point
= gfx::Point(99, 99);
1191 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1193 EXPECT_FALSE(result_layer
);
1195 // Hit checking for a point inside the touch event handler region should
1196 // return the root layer.
1197 test_point
= gfx::Point(11, 11);
1199 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1201 ASSERT_TRUE(result_layer
);
1202 EXPECT_EQ(12345, result_layer
->id());
1204 test_point
= gfx::Point(59, 59);
1206 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1208 ASSERT_TRUE(result_layer
);
1209 EXPECT_EQ(12345, result_layer
->id());
1212 TEST_F(LayerTreeImplTest
,
1213 HitCheckingTouchHandlerRegionsForUninvertibleTransform
) {
1214 scoped_ptr
<LayerImpl
> root
=
1215 LayerImpl::Create(host_impl().active_tree(), 12345);
1217 gfx::Transform uninvertible_transform
;
1218 uninvertible_transform
.matrix().set(0, 0, 0.0);
1219 uninvertible_transform
.matrix().set(1, 1, 0.0);
1220 uninvertible_transform
.matrix().set(2, 2, 0.0);
1221 uninvertible_transform
.matrix().set(3, 3, 0.0);
1222 ASSERT_FALSE(uninvertible_transform
.IsInvertible());
1224 gfx::Transform identity_matrix
;
1225 Region
touch_handler_region(gfx::Rect(10, 10, 50, 50));
1226 gfx::Point3F transform_origin
;
1227 gfx::PointF position
;
1228 gfx::Size
bounds(100, 100);
1229 SetLayerPropertiesForTesting(root
.get(), uninvertible_transform
,
1230 transform_origin
, position
, bounds
, true, false,
1232 root
->SetDrawsContent(true);
1233 root
->SetTouchEventHandlerRegion(touch_handler_region
);
1235 host_impl().SetViewportSize(root
->bounds());
1236 host_impl().active_tree()->SetRootLayer(root
.Pass());
1237 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
1239 // Sanity check the scenario we just created.
1240 ASSERT_EQ(1u, RenderSurfaceLayerList().size());
1241 ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
1242 ASSERT_FALSE(root_layer()->screen_space_transform().IsInvertible());
1244 // Hit checking any point should not hit the touch handler region on the
1245 // layer. If the invertible matrix is accidentally ignored and treated like an
1246 // identity, then the hit testing will incorrectly hit the layer when it
1248 gfx::Point
test_point(1, 1);
1249 LayerImpl
* result_layer
=
1250 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1252 EXPECT_FALSE(result_layer
);
1254 test_point
= gfx::Point(10, 10);
1256 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1258 EXPECT_FALSE(result_layer
);
1260 test_point
= gfx::Point(10, 30);
1262 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1264 EXPECT_FALSE(result_layer
);
1266 test_point
= gfx::Point(50, 50);
1268 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1270 EXPECT_FALSE(result_layer
);
1272 test_point
= gfx::Point(67, 48);
1274 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1276 EXPECT_FALSE(result_layer
);
1278 test_point
= gfx::Point(99, 99);
1280 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1282 EXPECT_FALSE(result_layer
);
1284 test_point
= gfx::Point(-1, -1);
1286 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1288 EXPECT_FALSE(result_layer
);
1291 TEST_F(LayerTreeImplTest
, MakeScrollbarsInvisibleNearMinPageScale
) {
1292 const int kThumbThickness
= 10;
1293 const int kTrackStart
= 0;
1294 const bool kIsLeftSideVerticalScrollbar
= false;
1295 const bool kIsOverlayScrollbar
= true;
1297 LayerTreeImpl
* active_tree
= host_impl().active_tree();
1298 active_tree
->set_hide_pinch_scrollbars_near_min_scale(true);
1300 scoped_ptr
<LayerImpl
> scroll_layer
= LayerImpl::Create(active_tree
, 1);
1301 scoped_ptr
<SolidColorScrollbarLayerImpl
> vertical_scrollbar_layer
=
1302 SolidColorScrollbarLayerImpl::Create(active_tree
,
1307 kIsLeftSideVerticalScrollbar
,
1308 kIsOverlayScrollbar
);
1309 scoped_ptr
<SolidColorScrollbarLayerImpl
> horizontal_scrollbar_layer
=
1310 SolidColorScrollbarLayerImpl::Create(active_tree
,
1315 kIsLeftSideVerticalScrollbar
,
1316 kIsOverlayScrollbar
);
1318 scoped_ptr
<LayerImpl
> clip_layer
= LayerImpl::Create(active_tree
, 4);
1319 scoped_ptr
<LayerImpl
> page_scale_layer
= LayerImpl::Create(active_tree
, 5);
1321 scroll_layer
->SetScrollClipLayer(clip_layer
->id());
1323 LayerImpl
* scroll_layer_ptr
= scroll_layer
.get();
1324 LayerImpl
* page_scale_layer_ptr
= page_scale_layer
.get();
1326 clip_layer
->AddChild(page_scale_layer
.Pass());
1327 page_scale_layer_ptr
->AddChild(scroll_layer
.Pass());
1329 vertical_scrollbar_layer
->SetScrollLayerAndClipLayerByIds(
1330 scroll_layer_ptr
->id(),
1332 horizontal_scrollbar_layer
->SetScrollLayerAndClipLayerByIds(
1333 scroll_layer_ptr
->id(),
1336 active_tree
->PushPageScaleFromMainThread(1.0f
, 1.0f
, 4.0f
);
1337 active_tree
->SetViewportLayersFromIds(
1338 Layer::INVALID_ID
, // Overscroll
1339 page_scale_layer_ptr
->id(),
1340 scroll_layer_ptr
->id(),
1341 Layer::INVALID_ID
); // Outer Scroll
1343 EXPECT_TRUE(vertical_scrollbar_layer
->hide_layer_and_subtree());
1344 EXPECT_TRUE(horizontal_scrollbar_layer
->hide_layer_and_subtree());
1346 active_tree
->PushPageScaleFromMainThread(1.04f
, 1.0f
, 4.0f
);
1347 EXPECT_TRUE(vertical_scrollbar_layer
->hide_layer_and_subtree());
1348 EXPECT_TRUE(horizontal_scrollbar_layer
->hide_layer_and_subtree());
1350 active_tree
->PushPageScaleFromMainThread(1.06f
, 1.0f
, 4.0f
);
1351 EXPECT_FALSE(vertical_scrollbar_layer
->hide_layer_and_subtree());
1352 EXPECT_FALSE(horizontal_scrollbar_layer
->hide_layer_and_subtree());
1354 active_tree
->PushPageScaleFromMainThread(1.5f
, 1.0f
, 4.0f
);
1355 EXPECT_FALSE(vertical_scrollbar_layer
->hide_layer_and_subtree());
1356 EXPECT_FALSE(horizontal_scrollbar_layer
->hide_layer_and_subtree());
1359 TEST_F(LayerTreeImplTest
,
1360 HitCheckingTouchHandlerRegionsForSinglePositionedLayer
) {
1361 scoped_ptr
<LayerImpl
> root
=
1362 LayerImpl::Create(host_impl().active_tree(), 12345);
1364 gfx::Transform identity_matrix
;
1365 Region
touch_handler_region(gfx::Rect(10, 10, 50, 50));
1366 gfx::Point3F transform_origin
;
1367 // this layer is positioned, and hit testing should correctly know where the
1368 // layer is located.
1369 gfx::PointF
position(50.f
, 50.f
);
1370 gfx::Size
bounds(100, 100);
1371 SetLayerPropertiesForTesting(root
.get(), identity_matrix
, transform_origin
,
1372 position
, bounds
, true, false, true);
1373 root
->SetDrawsContent(true);
1374 root
->SetTouchEventHandlerRegion(touch_handler_region
);
1376 host_impl().SetViewportSize(root
->bounds());
1377 host_impl().active_tree()->SetRootLayer(root
.Pass());
1378 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
1380 // Sanity check the scenario we just created.
1381 ASSERT_EQ(1u, RenderSurfaceLayerList().size());
1382 ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
1384 // Hit checking for a point outside the layer should return a null pointer.
1385 gfx::Point
test_point(49, 49);
1386 LayerImpl
* result_layer
=
1387 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1389 EXPECT_FALSE(result_layer
);
1391 // Even though the layer has a touch handler region containing (101, 101), it
1392 // should not be visible there since the root render surface would clamp it.
1393 test_point
= gfx::Point(101, 101);
1395 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1397 EXPECT_FALSE(result_layer
);
1399 // Hit checking for a point inside the layer, but outside the touch handler
1400 // region should return a null pointer.
1401 test_point
= gfx::Point(51, 51);
1403 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1405 EXPECT_FALSE(result_layer
);
1407 // Hit checking for a point inside the touch event handler region should
1408 // return the root layer.
1409 test_point
= gfx::Point(61, 61);
1411 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1413 ASSERT_TRUE(result_layer
);
1414 EXPECT_EQ(12345, result_layer
->id());
1416 test_point
= gfx::Point(99, 99);
1418 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1420 ASSERT_TRUE(result_layer
);
1421 EXPECT_EQ(12345, result_layer
->id());
1424 TEST_F(LayerTreeImplTest
,
1425 HitCheckingTouchHandlerRegionsForSingleLayerWithDeviceScale
) {
1426 // The layer's device_scale_factor and page_scale_factor should scale the
1427 // content rect and we should be able to hit the touch handler region by
1428 // scaling the points accordingly.
1429 scoped_ptr
<LayerImpl
> root
= LayerImpl::Create(host_impl().active_tree(), 1);
1431 gfx::Transform identity_matrix
;
1432 gfx::Point3F transform_origin
;
1433 // Set the bounds of the root layer big enough to fit the child when scaled.
1434 SetLayerPropertiesForTesting(root
.get(), identity_matrix
, transform_origin
,
1435 gfx::PointF(), gfx::Size(100, 100), true, false,
1438 Region
touch_handler_region(gfx::Rect(10, 10, 30, 30));
1439 gfx::PointF
position(25.f
, 25.f
);
1440 gfx::Size
bounds(50, 50);
1441 scoped_ptr
<LayerImpl
> test_layer
=
1442 LayerImpl::Create(host_impl().active_tree(), 12345);
1443 SetLayerPropertiesForTesting(test_layer
.get(), identity_matrix
,
1444 transform_origin
, position
, bounds
, true,
1447 test_layer
->SetDrawsContent(true);
1448 test_layer
->SetTouchEventHandlerRegion(touch_handler_region
);
1449 root
->AddChild(test_layer
.Pass());
1452 float device_scale_factor
= 3.f
;
1453 float page_scale_factor
= 5.f
;
1454 gfx::Size scaled_bounds_for_root
= gfx::ToCeiledSize(
1455 gfx::ScaleSize(root
->bounds(), device_scale_factor
* page_scale_factor
));
1456 host_impl().SetViewportSize(scaled_bounds_for_root
);
1458 host_impl().SetDeviceScaleFactor(device_scale_factor
);
1459 host_impl().active_tree()->PushPageScaleFromMainThread(
1460 page_scale_factor
, page_scale_factor
, page_scale_factor
);
1461 host_impl().SetPageScaleOnActiveTree(page_scale_factor
);
1462 host_impl().active_tree()->SetRootLayer(root
.Pass());
1463 host_impl().active_tree()->SetViewportLayersFromIds(Layer::INVALID_ID
, 1, 1,
1465 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
1467 // Sanity check the scenario we just created.
1468 // The visible content rect for test_layer is actually 100x100, even though
1469 // its layout size is 50x50, positioned at 25x25.
1470 LayerImpl
* test_layer
=
1471 host_impl().active_tree()->root_layer()->children()[0];
1472 ASSERT_EQ(1u, RenderSurfaceLayerList().size());
1473 ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
1475 // Check whether the child layer fits into the root after scaled.
1476 EXPECT_EQ(gfx::Rect(test_layer
->bounds()), test_layer
->visible_layer_rect());
1478 // Hit checking for a point outside the layer should return a null pointer
1479 // (the root layer does not draw content, so it will not be tested either).
1480 gfx::PointF
test_point(76.f
, 76.f
);
1482 gfx::ScalePoint(test_point
, device_scale_factor
* page_scale_factor
);
1483 LayerImpl
* result_layer
=
1484 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1486 EXPECT_FALSE(result_layer
);
1488 // Hit checking for a point inside the layer, but outside the touch handler
1489 // region should return a null pointer.
1490 test_point
= gfx::Point(26, 26);
1492 gfx::ScalePoint(test_point
, device_scale_factor
* page_scale_factor
);
1494 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1496 EXPECT_FALSE(result_layer
);
1498 test_point
= gfx::Point(34, 34);
1500 gfx::ScalePoint(test_point
, device_scale_factor
* page_scale_factor
);
1502 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1504 EXPECT_FALSE(result_layer
);
1506 test_point
= gfx::Point(65, 65);
1508 gfx::ScalePoint(test_point
, device_scale_factor
* page_scale_factor
);
1510 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1512 EXPECT_FALSE(result_layer
);
1514 test_point
= gfx::Point(74, 74);
1516 gfx::ScalePoint(test_point
, device_scale_factor
* page_scale_factor
);
1518 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1520 EXPECT_FALSE(result_layer
);
1522 // Hit checking for a point inside the touch event handler region should
1523 // return the root layer.
1524 test_point
= gfx::Point(35, 35);
1526 gfx::ScalePoint(test_point
, device_scale_factor
* page_scale_factor
);
1528 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1530 ASSERT_TRUE(result_layer
);
1531 EXPECT_EQ(12345, result_layer
->id());
1533 test_point
= gfx::Point(64, 64);
1535 gfx::ScalePoint(test_point
, device_scale_factor
* page_scale_factor
);
1537 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1539 ASSERT_TRUE(result_layer
);
1540 EXPECT_EQ(12345, result_layer
->id());
1543 TEST_F(LayerTreeImplTest
, HitCheckingTouchHandlerRegionsForSimpleClippedLayer
) {
1544 // Test that hit-checking will only work for the visible portion of a layer,
1545 // and not the entire layer bounds. Here we just test the simple axis-aligned
1547 gfx::Transform identity_matrix
;
1548 gfx::Point3F transform_origin
;
1550 scoped_ptr
<LayerImpl
> root
= LayerImpl::Create(host_impl().active_tree(), 1);
1551 SetLayerPropertiesForTesting(root
.get(), identity_matrix
, transform_origin
,
1552 gfx::PointF(), gfx::Size(100, 100), true, false,
1555 scoped_ptr
<LayerImpl
> clipping_layer
=
1556 LayerImpl::Create(host_impl().active_tree(), 123);
1557 // this layer is positioned, and hit testing should correctly know where the
1558 // layer is located.
1559 gfx::PointF
position(25.f
, 25.f
);
1560 gfx::Size
bounds(50, 50);
1561 SetLayerPropertiesForTesting(clipping_layer
.get(), identity_matrix
,
1562 transform_origin
, position
, bounds
, true,
1564 clipping_layer
->SetMasksToBounds(true);
1566 scoped_ptr
<LayerImpl
> child
=
1567 LayerImpl::Create(host_impl().active_tree(), 456);
1568 Region
touch_handler_region(gfx::Rect(10, 10, 50, 50));
1569 position
= gfx::PointF(-50.f
, -50.f
);
1570 bounds
= gfx::Size(300, 300);
1571 SetLayerPropertiesForTesting(child
.get(), identity_matrix
, transform_origin
,
1572 position
, bounds
, true, false, false);
1573 child
->SetDrawsContent(true);
1574 child
->SetTouchEventHandlerRegion(touch_handler_region
);
1575 clipping_layer
->AddChild(child
.Pass());
1576 root
->AddChild(clipping_layer
.Pass());
1579 host_impl().SetViewportSize(root
->bounds());
1580 host_impl().active_tree()->SetRootLayer(root
.Pass());
1581 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
1583 // Sanity check the scenario we just created.
1584 ASSERT_EQ(1u, RenderSurfaceLayerList().size());
1585 ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
1586 ASSERT_EQ(456, root_layer()->render_surface()->layer_list().at(0)->id());
1588 // Hit checking for a point outside the layer should return a null pointer.
1589 // Despite the child layer being very large, it should be clipped to the root
1591 gfx::Point
test_point(24, 24);
1592 LayerImpl
* result_layer
=
1593 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1595 EXPECT_FALSE(result_layer
);
1597 // Hit checking for a point inside the layer, but outside the touch handler
1598 // region should return a null pointer.
1599 test_point
= gfx::Point(35, 35);
1601 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1603 EXPECT_FALSE(result_layer
);
1605 test_point
= gfx::Point(74, 74);
1607 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1609 EXPECT_FALSE(result_layer
);
1611 // Hit checking for a point inside the touch event handler region should
1612 // return the root layer.
1613 test_point
= gfx::Point(25, 25);
1615 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1617 ASSERT_TRUE(result_layer
);
1618 EXPECT_EQ(456, result_layer
->id());
1620 test_point
= gfx::Point(34, 34);
1622 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1624 ASSERT_TRUE(result_layer
);
1625 EXPECT_EQ(456, result_layer
->id());
1628 TEST_F(LayerTreeImplTest
, HitCheckingTouchHandlerOverlappingRegions
) {
1629 gfx::Transform identity_matrix
;
1630 gfx::Point3F transform_origin
;
1632 scoped_ptr
<LayerImpl
> root
= LayerImpl::Create(host_impl().active_tree(), 1);
1633 SetLayerPropertiesForTesting(root
.get(), identity_matrix
, transform_origin
,
1634 gfx::PointF(), gfx::Size(100, 100), true, false,
1637 scoped_ptr
<LayerImpl
> touch_layer
=
1638 LayerImpl::Create(host_impl().active_tree(), 123);
1639 // this layer is positioned, and hit testing should correctly know where the
1640 // layer is located.
1641 gfx::PointF position
;
1642 gfx::Size
bounds(50, 50);
1643 SetLayerPropertiesForTesting(touch_layer
.get(), identity_matrix
,
1644 transform_origin
, position
, bounds
, true,
1646 touch_layer
->SetDrawsContent(true);
1647 touch_layer
->SetTouchEventHandlerRegion(gfx::Rect(0, 0, 50, 50));
1648 root
->AddChild(touch_layer
.Pass());
1652 scoped_ptr
<LayerImpl
> notouch_layer
=
1653 LayerImpl::Create(host_impl().active_tree(), 1234);
1654 // this layer is positioned, and hit testing should correctly know where the
1655 // layer is located.
1656 gfx::PointF
position(0, 25);
1657 gfx::Size
bounds(50, 50);
1658 SetLayerPropertiesForTesting(notouch_layer
.get(), identity_matrix
,
1659 transform_origin
, position
, bounds
, true,
1661 notouch_layer
->SetDrawsContent(true);
1662 root
->AddChild(notouch_layer
.Pass());
1665 host_impl().SetViewportSize(root
->bounds());
1666 host_impl().active_tree()->SetRootLayer(root
.Pass());
1667 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
1669 // Sanity check the scenario we just created.
1670 ASSERT_EQ(1u, RenderSurfaceLayerList().size());
1671 ASSERT_EQ(2u, root_layer()->render_surface()->layer_list().size());
1672 ASSERT_EQ(123, root_layer()->render_surface()->layer_list().at(0)->id());
1673 ASSERT_EQ(1234, root_layer()->render_surface()->layer_list().at(1)->id());
1675 gfx::Point
test_point(35, 35);
1676 LayerImpl
* result_layer
=
1677 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1680 // We should have passed through the no-touch layer and found the layer
1682 EXPECT_TRUE(result_layer
);
1684 host_impl().active_tree()->LayerById(1234)->SetContentsOpaque(true);
1686 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1689 // Even with an opaque layer in the middle, we should still find the layer
1691 // the touch handler behind it (since we can't assume that opaque layers are
1692 // opaque to hit testing).
1693 EXPECT_TRUE(result_layer
);
1695 test_point
= gfx::Point(35, 15);
1697 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1699 ASSERT_TRUE(result_layer
);
1700 EXPECT_EQ(123, result_layer
->id());
1702 test_point
= gfx::Point(35, 65);
1704 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1706 EXPECT_FALSE(result_layer
);
1709 TEST_F(LayerTreeImplTest
, SelectionBoundsForSingleLayer
) {
1710 int root_layer_id
= 12345;
1711 scoped_ptr
<LayerImpl
> root
=
1712 LayerImpl::Create(host_impl().active_tree(), root_layer_id
);
1714 gfx::Transform identity_matrix
;
1715 gfx::Point3F transform_origin
;
1716 gfx::PointF position
;
1717 gfx::Size
bounds(100, 100);
1718 SetLayerPropertiesForTesting(root
.get(), identity_matrix
, transform_origin
,
1719 position
, bounds
, true, false, true);
1720 root
->SetDrawsContent(true);
1722 host_impl().SetViewportSize(root
->bounds());
1723 host_impl().active_tree()->SetRootLayer(root
.Pass());
1724 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
1726 // Sanity check the scenario we just created.
1727 ASSERT_EQ(1u, RenderSurfaceLayerList().size());
1728 ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
1730 LayerSelection input
;
1732 input
.start
.type
= SELECTION_BOUND_LEFT
;
1733 input
.start
.edge_top
= gfx::PointF(10, 10);
1734 input
.start
.edge_bottom
= gfx::PointF(10, 20);
1735 input
.start
.layer_id
= root_layer_id
;
1737 input
.end
.type
= SELECTION_BOUND_RIGHT
;
1738 input
.end
.edge_top
= gfx::PointF(50, 10);
1739 input
.end
.edge_bottom
= gfx::PointF(50, 30);
1740 input
.end
.layer_id
= root_layer_id
;
1742 ViewportSelection output
;
1744 // Empty input bounds should produce empty output bounds.
1745 host_impl().active_tree()->GetViewportSelection(&output
);
1746 EXPECT_EQ(ViewportSelectionBound(), output
.start
);
1747 EXPECT_EQ(ViewportSelectionBound(), output
.end
);
1749 // Selection bounds should produce distinct left and right bounds.
1750 host_impl().active_tree()->RegisterSelection(input
);
1751 host_impl().active_tree()->GetViewportSelection(&output
);
1752 EXPECT_EQ(input
.start
.type
, output
.start
.type
);
1753 EXPECT_EQ(input
.start
.edge_bottom
, output
.start
.edge_bottom
);
1754 EXPECT_EQ(input
.start
.edge_top
, output
.start
.edge_top
);
1755 EXPECT_TRUE(output
.start
.visible
);
1756 EXPECT_EQ(input
.end
.type
, output
.end
.type
);
1757 EXPECT_EQ(input
.end
.edge_bottom
, output
.end
.edge_bottom
);
1758 EXPECT_EQ(input
.end
.edge_top
, output
.end
.edge_top
);
1759 EXPECT_TRUE(output
.end
.visible
);
1760 EXPECT_EQ(input
.is_editable
, output
.is_editable
);
1761 EXPECT_EQ(input
.is_empty_text_form_control
,
1762 output
.is_empty_text_form_control
);
1764 // Insertion bounds should produce identical left and right bounds.
1765 LayerSelection insertion_input
;
1766 insertion_input
.start
.type
= SELECTION_BOUND_CENTER
;
1767 insertion_input
.start
.edge_top
= gfx::PointF(15, 10);
1768 insertion_input
.start
.edge_bottom
= gfx::PointF(15, 30);
1769 insertion_input
.start
.layer_id
= root_layer_id
;
1770 insertion_input
.is_editable
= true;
1771 insertion_input
.is_empty_text_form_control
= true;
1772 insertion_input
.end
= insertion_input
.start
;
1773 host_impl().active_tree()->RegisterSelection(insertion_input
);
1774 host_impl().active_tree()->GetViewportSelection(&output
);
1775 EXPECT_EQ(insertion_input
.start
.type
, output
.start
.type
);
1776 EXPECT_EQ(insertion_input
.start
.edge_bottom
, output
.start
.edge_bottom
);
1777 EXPECT_EQ(insertion_input
.start
.edge_top
, output
.start
.edge_top
);
1778 EXPECT_EQ(insertion_input
.is_editable
, output
.is_editable
);
1779 EXPECT_EQ(insertion_input
.is_empty_text_form_control
,
1780 output
.is_empty_text_form_control
);
1781 EXPECT_TRUE(output
.start
.visible
);
1782 EXPECT_EQ(output
.start
, output
.end
);
1785 TEST_F(LayerTreeImplTest
, SelectionBoundsForPartialOccludedLayers
) {
1786 int root_layer_id
= 12345;
1787 int clip_layer_id
= 1234;
1788 int clipped_layer_id
= 123;
1789 scoped_ptr
<LayerImpl
> root
=
1790 LayerImpl::Create(host_impl().active_tree(), root_layer_id
);
1791 root
->SetDrawsContent(true);
1793 gfx::Transform identity_matrix
;
1794 gfx::Point3F transform_origin
;
1795 gfx::PointF position
;
1796 gfx::Size
bounds(100, 100);
1797 SetLayerPropertiesForTesting(root
.get(), identity_matrix
, transform_origin
,
1798 position
, bounds
, true, false, true);
1800 gfx::Vector2dF
clipping_offset(10, 10);
1802 scoped_ptr
<LayerImpl
> clipping_layer
=
1803 LayerImpl::Create(host_impl().active_tree(), clip_layer_id
);
1804 // The clipping layer should occlude the right selection bound.
1805 gfx::PointF position
= gfx::PointF() + clipping_offset
;
1806 gfx::Size
bounds(50, 50);
1807 SetLayerPropertiesForTesting(clipping_layer
.get(), identity_matrix
,
1808 transform_origin
, position
, bounds
, true,
1810 clipping_layer
->SetMasksToBounds(true);
1812 scoped_ptr
<LayerImpl
> clipped_layer
=
1813 LayerImpl::Create(host_impl().active_tree(), clipped_layer_id
);
1814 position
= gfx::PointF();
1815 bounds
= gfx::Size(100, 100);
1816 SetLayerPropertiesForTesting(clipped_layer
.get(), identity_matrix
,
1817 transform_origin
, position
, bounds
, true,
1819 clipped_layer
->SetDrawsContent(true);
1820 clipping_layer
->AddChild(clipped_layer
.Pass());
1821 root
->AddChild(clipping_layer
.Pass());
1824 host_impl().SetViewportSize(root
->bounds());
1825 host_impl().active_tree()->SetRootLayer(root
.Pass());
1826 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
1828 // Sanity check the scenario we just created.
1829 ASSERT_EQ(1u, RenderSurfaceLayerList().size());
1831 LayerSelection input
;
1832 input
.start
.type
= SELECTION_BOUND_LEFT
;
1833 input
.start
.edge_top
= gfx::PointF(25, 10);
1834 input
.start
.edge_bottom
= gfx::PointF(25, 30);
1835 input
.start
.layer_id
= clipped_layer_id
;
1837 input
.end
.type
= SELECTION_BOUND_RIGHT
;
1838 input
.end
.edge_top
= gfx::PointF(75, 10);
1839 input
.end
.edge_bottom
= gfx::PointF(75, 30);
1840 input
.end
.layer_id
= clipped_layer_id
;
1841 host_impl().active_tree()->RegisterSelection(input
);
1843 // The left bound should be occluded by the clip layer.
1844 ViewportSelection output
;
1845 host_impl().active_tree()->GetViewportSelection(&output
);
1846 EXPECT_EQ(input
.start
.type
, output
.start
.type
);
1847 gfx::PointF expected_output_start_top
= input
.start
.edge_top
;
1848 gfx::PointF expected_output_edge_botom
= input
.start
.edge_bottom
;
1849 expected_output_start_top
.Offset(clipping_offset
.x(), clipping_offset
.y());
1850 expected_output_edge_botom
.Offset(clipping_offset
.x(), clipping_offset
.y());
1851 EXPECT_EQ(expected_output_start_top
, output
.start
.edge_top
);
1852 EXPECT_EQ(expected_output_edge_botom
, output
.start
.edge_bottom
);
1853 EXPECT_TRUE(output
.start
.visible
);
1854 EXPECT_EQ(input
.end
.type
, output
.end
.type
);
1855 gfx::PointF expected_output_end_top
= input
.end
.edge_top
;
1856 gfx::PointF expected_output_end_bottom
= input
.end
.edge_bottom
;
1857 expected_output_end_bottom
.Offset(clipping_offset
.x(), clipping_offset
.y());
1858 expected_output_end_top
.Offset(clipping_offset
.x(), clipping_offset
.y());
1859 EXPECT_EQ(expected_output_end_top
, output
.end
.edge_top
);
1860 EXPECT_EQ(expected_output_end_bottom
, output
.end
.edge_bottom
);
1861 EXPECT_FALSE(output
.end
.visible
);
1863 // Handles outside the viewport bounds should be marked invisible.
1864 input
.start
.edge_top
= gfx::PointF(-25, 0);
1865 input
.start
.edge_bottom
= gfx::PointF(-25, 20);
1866 host_impl().active_tree()->RegisterSelection(input
);
1867 host_impl().active_tree()->GetViewportSelection(&output
);
1868 EXPECT_FALSE(output
.start
.visible
);
1870 input
.start
.edge_top
= gfx::PointF(0, -25);
1871 input
.start
.edge_bottom
= gfx::PointF(0, -5);
1872 host_impl().active_tree()->RegisterSelection(input
);
1873 host_impl().active_tree()->GetViewportSelection(&output
);
1874 EXPECT_FALSE(output
.start
.visible
);
1876 // If the handle bottom is partially visible, the handle is marked visible.
1877 input
.start
.edge_top
= gfx::PointF(0, -20);
1878 input
.start
.edge_bottom
= gfx::PointF(0, 1);
1879 host_impl().active_tree()->RegisterSelection(input
);
1880 host_impl().active_tree()->GetViewportSelection(&output
);
1881 EXPECT_TRUE(output
.start
.visible
);
1884 TEST_F(LayerTreeImplTest
, SelectionBoundsForScaledLayers
) {
1885 int root_layer_id
= 1;
1886 int sub_layer_id
= 2;
1887 scoped_ptr
<LayerImpl
> root
=
1888 LayerImpl::Create(host_impl().active_tree(), root_layer_id
);
1889 root
->SetDrawsContent(true);
1891 gfx::Transform identity_matrix
;
1892 gfx::Point3F transform_origin
;
1893 gfx::PointF position
;
1894 gfx::Size
bounds(100, 100);
1895 SetLayerPropertiesForTesting(root
.get(), identity_matrix
, transform_origin
,
1896 position
, bounds
, true, false, true);
1898 gfx::Vector2dF
sub_layer_offset(10, 0);
1900 scoped_ptr
<LayerImpl
> sub_layer
=
1901 LayerImpl::Create(host_impl().active_tree(), sub_layer_id
);
1902 gfx::PointF position
= gfx::PointF() + sub_layer_offset
;
1903 gfx::Size
bounds(50, 50);
1904 SetLayerPropertiesForTesting(sub_layer
.get(), identity_matrix
,
1905 transform_origin
, position
, bounds
, true,
1907 sub_layer
->SetDrawsContent(true);
1908 root
->AddChild(sub_layer
.Pass());
1911 float device_scale_factor
= 3.f
;
1912 float page_scale_factor
= 5.f
;
1913 gfx::Size scaled_bounds_for_root
= gfx::ToCeiledSize(
1914 gfx::ScaleSize(root
->bounds(), device_scale_factor
* page_scale_factor
));
1915 host_impl().SetViewportSize(scaled_bounds_for_root
);
1917 host_impl().SetDeviceScaleFactor(device_scale_factor
);
1918 host_impl().active_tree()->PushPageScaleFromMainThread(
1919 page_scale_factor
, page_scale_factor
, page_scale_factor
);
1920 host_impl().SetPageScaleOnActiveTree(page_scale_factor
);
1921 host_impl().active_tree()->SetRootLayer(root
.Pass());
1922 host_impl().active_tree()->SetViewportLayersFromIds(Layer::INVALID_ID
, 1, 1,
1924 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
1926 // Sanity check the scenario we just created.
1927 ASSERT_EQ(1u, RenderSurfaceLayerList().size());
1929 LayerSelection input
;
1930 input
.start
.type
= SELECTION_BOUND_LEFT
;
1931 input
.start
.edge_top
= gfx::PointF(10, 10);
1932 input
.start
.edge_bottom
= gfx::PointF(10, 30);
1933 input
.start
.layer_id
= root_layer_id
;
1935 input
.end
.type
= SELECTION_BOUND_RIGHT
;
1936 input
.end
.edge_top
= gfx::PointF(0, 0);
1937 input
.end
.edge_bottom
= gfx::PointF(0, 20);
1938 input
.end
.layer_id
= sub_layer_id
;
1939 host_impl().active_tree()->RegisterSelection(input
);
1941 // The viewport bounds should be properly scaled by the page scale, but should
1942 // remain in DIP coordinates.
1943 ViewportSelection output
;
1944 host_impl().active_tree()->GetViewportSelection(&output
);
1945 EXPECT_EQ(input
.start
.type
, output
.start
.type
);
1946 gfx::PointF expected_output_start_top
= input
.start
.edge_top
;
1947 gfx::PointF expected_output_edge_bottom
= input
.start
.edge_bottom
;
1948 expected_output_start_top
.Scale(page_scale_factor
);
1949 expected_output_edge_bottom
.Scale(page_scale_factor
);
1950 EXPECT_EQ(expected_output_start_top
, output
.start
.edge_top
);
1951 EXPECT_EQ(expected_output_edge_bottom
, output
.start
.edge_bottom
);
1952 EXPECT_TRUE(output
.start
.visible
);
1953 EXPECT_EQ(input
.end
.type
, output
.end
.type
);
1955 gfx::PointF expected_output_end_top
= input
.end
.edge_top
;
1956 gfx::PointF expected_output_end_bottom
= input
.end
.edge_bottom
;
1957 expected_output_end_top
.Offset(sub_layer_offset
.x(), sub_layer_offset
.y());
1958 expected_output_end_bottom
.Offset(sub_layer_offset
.x(), sub_layer_offset
.y());
1959 expected_output_end_top
.Scale(page_scale_factor
);
1960 expected_output_end_bottom
.Scale(page_scale_factor
);
1961 EXPECT_EQ(expected_output_end_top
, output
.end
.edge_top
);
1962 EXPECT_EQ(expected_output_end_bottom
, output
.end
.edge_bottom
);
1963 EXPECT_TRUE(output
.end
.visible
);
1966 TEST_F(LayerTreeImplTest
, NumLayersTestOne
) {
1967 EXPECT_EQ(0u, host_impl().active_tree()->NumLayers());
1968 scoped_ptr
<LayerImpl
> root
= LayerImpl::Create(host_impl().active_tree(), 1);
1969 EXPECT_EQ(1u, host_impl().active_tree()->NumLayers());
1972 TEST_F(LayerTreeImplTest
, NumLayersSmallTree
) {
1973 EXPECT_EQ(0u, host_impl().active_tree()->NumLayers());
1974 scoped_ptr
<LayerImpl
> root
= LayerImpl::Create(host_impl().active_tree(), 1);
1975 root
->AddChild(LayerImpl::Create(host_impl().active_tree(), 2));
1976 root
->AddChild(LayerImpl::Create(host_impl().active_tree(), 3));
1977 root
->child_at(1)->AddChild(LayerImpl::Create(host_impl().active_tree(), 4));
1978 EXPECT_EQ(4u, host_impl().active_tree()->NumLayers());