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
, UpdateViewportAndHitTest
) {
94 // Ensures that the viewport rect is correctly updated by the clip tree.
95 TestSharedBitmapManager shared_bitmap_manager
;
96 TestTaskGraphRunner task_graph_runner
;
98 LayerTreeSettings settings
;
99 settings
.verify_property_trees
= true;
100 scoped_ptr
<FakeLayerTreeHostImpl
> host_impl
;
101 host_impl
.reset(new FakeLayerTreeHostImpl(
102 settings
, &proxy
, &shared_bitmap_manager
, &task_graph_runner
));
103 EXPECT_TRUE(host_impl
->InitializeRenderer(FakeOutputSurface::Create3d()));
104 scoped_ptr
<LayerImpl
> root
=
105 LayerImpl::Create(host_impl
->active_tree(), 12345);
107 gfx::Transform identity_matrix
;
108 gfx::Point3F transform_origin
;
109 gfx::PointF position
;
110 gfx::Size
bounds(100, 100);
111 SetLayerPropertiesForTesting(root
.get(), identity_matrix
, transform_origin
,
112 position
, bounds
, true, false, true);
113 root
->SetDrawsContent(true);
115 host_impl
->SetViewportSize(root
->bounds());
116 host_impl
->active_tree()->SetRootLayer(root
.Pass());
117 host_impl
->UpdateNumChildrenAndDrawPropertiesForActiveTree();
120 host_impl
->active_tree()->property_trees()->clip_tree
.ViewportClip());
121 EXPECT_EQ(gfx::Rect(bounds
),
122 host_impl
->RootLayer()->visible_rect_from_property_trees());
124 gfx::Size
new_bounds(50, 50);
125 host_impl
->SetViewportSize(new_bounds
);
126 gfx::Point
test_point(51, 51);
127 host_impl
->active_tree()->FindLayerThatIsHitByPoint(test_point
);
129 gfx::RectF(new_bounds
),
130 host_impl
->active_tree()->property_trees()->clip_tree
.ViewportClip());
131 EXPECT_EQ(gfx::Rect(new_bounds
),
132 host_impl
->RootLayer()->visible_rect_from_property_trees());
135 TEST_F(LayerTreeImplTest
, HitTestingForSingleLayerAndHud
) {
136 scoped_ptr
<LayerImpl
> root
=
137 LayerImpl::Create(host_impl().active_tree(), 12345);
138 scoped_ptr
<HeadsUpDisplayLayerImpl
> hud
=
139 HeadsUpDisplayLayerImpl::Create(host_impl().active_tree(), 11111);
141 gfx::Transform identity_matrix
;
142 gfx::Point3F transform_origin
;
143 gfx::PointF position
;
144 gfx::Size
bounds(100, 100);
145 SetLayerPropertiesForTesting(root
.get(), identity_matrix
, transform_origin
,
146 position
, bounds
, true, false, true);
147 root
->SetDrawsContent(true);
149 // Create hud and add it as a child of root.
150 gfx::Size
hud_bounds(200, 200);
151 SetLayerPropertiesForTesting(hud
.get(), identity_matrix
, transform_origin
,
152 position
, hud_bounds
, true, false, false);
153 hud
->SetDrawsContent(true);
155 host_impl().active_tree()->set_hud_layer(hud
.get());
156 root
->AddChild(hud
.Pass());
158 host_impl().SetViewportSize(hud_bounds
);
159 host_impl().active_tree()->SetRootLayer(root
.Pass());
160 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
162 // Sanity check the scenario we just created.
163 ASSERT_EQ(1u, RenderSurfaceLayerList().size());
164 ASSERT_EQ(2u, root_layer()->render_surface()->layer_list().size());
166 // Hit testing for a point inside HUD, but outside root should return null
167 gfx::Point
test_point(101, 101);
168 LayerImpl
* result_layer
=
169 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
170 EXPECT_FALSE(result_layer
);
172 test_point
= gfx::Point(-1, -1);
174 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
175 EXPECT_FALSE(result_layer
);
177 // Hit testing for a point inside should return the root layer, never the HUD
179 test_point
= gfx::Point(1, 1);
181 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
182 ASSERT_TRUE(result_layer
);
183 EXPECT_EQ(12345, result_layer
->id());
185 test_point
= gfx::Point(99, 99);
187 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
188 ASSERT_TRUE(result_layer
);
189 EXPECT_EQ(12345, result_layer
->id());
192 TEST_F(LayerTreeImplTest
, HitTestingForUninvertibleTransform
) {
193 scoped_ptr
<LayerImpl
> root
=
194 LayerImpl::Create(host_impl().active_tree(), 12345);
196 gfx::Transform uninvertible_transform
;
197 uninvertible_transform
.matrix().set(0, 0, 0.0);
198 uninvertible_transform
.matrix().set(1, 1, 0.0);
199 uninvertible_transform
.matrix().set(2, 2, 0.0);
200 uninvertible_transform
.matrix().set(3, 3, 0.0);
201 ASSERT_FALSE(uninvertible_transform
.IsInvertible());
203 gfx::Transform identity_matrix
;
204 gfx::Point3F transform_origin
;
205 gfx::PointF position
;
206 gfx::Size
bounds(100, 100);
207 SetLayerPropertiesForTesting(root
.get(), uninvertible_transform
,
208 transform_origin
, position
, bounds
, true, false,
210 root
->SetDrawsContent(true);
212 host_impl().SetViewportSize(root
->bounds());
213 host_impl().active_tree()->SetRootLayer(root
.Pass());
214 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
215 // Sanity check the scenario we just created.
216 ASSERT_EQ(1u, RenderSurfaceLayerList().size());
217 ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
218 ASSERT_FALSE(root_layer()->screen_space_transform().IsInvertible());
220 // Hit testing any point should not hit the layer. If the invertible matrix is
221 // accidentally ignored and treated like an identity, then the hit testing
222 // will incorrectly hit the layer when it shouldn't.
223 gfx::Point
test_point(1, 1);
224 LayerImpl
* result_layer
=
225 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
226 EXPECT_FALSE(result_layer
);
228 test_point
= gfx::Point(10, 10);
230 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
231 EXPECT_FALSE(result_layer
);
233 test_point
= gfx::Point(10, 30);
235 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
236 EXPECT_FALSE(result_layer
);
238 test_point
= gfx::Point(50, 50);
240 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
241 EXPECT_FALSE(result_layer
);
243 test_point
= gfx::Point(67, 48);
245 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
246 EXPECT_FALSE(result_layer
);
248 test_point
= gfx::Point(99, 99);
250 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
251 EXPECT_FALSE(result_layer
);
253 test_point
= gfx::Point(-1, -1);
255 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
256 EXPECT_FALSE(result_layer
);
259 TEST_F(LayerTreeImplTest
, HitTestingForSinglePositionedLayer
) {
260 scoped_ptr
<LayerImpl
> root
=
261 LayerImpl::Create(host_impl().active_tree(), 12345);
263 gfx::Transform identity_matrix
;
264 gfx::Point3F transform_origin
;
265 // this layer is positioned, and hit testing should correctly know where the
267 gfx::PointF
position(50.f
, 50.f
);
268 gfx::Size
bounds(100, 100);
269 SetLayerPropertiesForTesting(root
.get(), identity_matrix
, transform_origin
,
270 position
, bounds
, true, false, true);
271 root
->SetDrawsContent(true);
273 host_impl().SetViewportSize(root
->bounds());
274 host_impl().active_tree()->SetRootLayer(root
.Pass());
275 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
277 // Sanity check the scenario we just created.
278 ASSERT_EQ(1u, RenderSurfaceLayerList().size());
279 ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
281 // Hit testing for a point outside the layer should return a null pointer.
282 gfx::Point
test_point(49, 49);
283 LayerImpl
* result_layer
=
284 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
285 EXPECT_FALSE(result_layer
);
287 // Even though the layer exists at (101, 101), it should not be visible there
288 // since the root render surface would clamp it.
289 test_point
= gfx::Point(101, 101);
291 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
292 EXPECT_FALSE(result_layer
);
294 // Hit testing for a point inside should return the root layer.
295 test_point
= gfx::Point(51, 51);
297 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
298 ASSERT_TRUE(result_layer
);
299 EXPECT_EQ(12345, result_layer
->id());
301 test_point
= gfx::Point(99, 99);
303 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
304 ASSERT_TRUE(result_layer
);
305 EXPECT_EQ(12345, result_layer
->id());
308 TEST_F(LayerTreeImplTest
, HitTestingForSingleRotatedLayer
) {
309 scoped_ptr
<LayerImpl
> root
=
310 LayerImpl::Create(host_impl().active_tree(), 12345);
312 gfx::Transform identity_matrix
;
313 gfx::Transform rotation45_degrees_about_center
;
314 rotation45_degrees_about_center
.Translate(50.0, 50.0);
315 rotation45_degrees_about_center
.RotateAboutZAxis(45.0);
316 rotation45_degrees_about_center
.Translate(-50.0, -50.0);
317 gfx::Point3F transform_origin
;
318 gfx::PointF position
;
319 gfx::Size
bounds(100, 100);
320 SetLayerPropertiesForTesting(root
.get(), rotation45_degrees_about_center
,
321 transform_origin
, position
, bounds
, true, false,
323 root
->SetDrawsContent(true);
325 host_impl().SetViewportSize(root
->bounds());
326 host_impl().active_tree()->SetRootLayer(root
.Pass());
327 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
329 // Sanity check the scenario we just created.
330 ASSERT_EQ(1u, RenderSurfaceLayerList().size());
331 ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
333 // Hit testing for points outside the layer.
334 // These corners would have been inside the un-transformed layer, but they
335 // should not hit the correctly transformed layer.
336 gfx::Point
test_point(99, 99);
337 LayerImpl
* result_layer
=
338 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
339 EXPECT_FALSE(result_layer
);
341 test_point
= gfx::Point(1, 1);
343 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
344 EXPECT_FALSE(result_layer
);
346 // Hit testing for a point inside should return the root layer.
347 test_point
= gfx::Point(1, 50);
349 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
350 ASSERT_TRUE(result_layer
);
351 EXPECT_EQ(12345, result_layer
->id());
353 // Hit testing the corners that would overlap the unclipped layer, but are
354 // outside the clipped region.
355 test_point
= gfx::Point(50, -1);
357 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
358 ASSERT_FALSE(result_layer
);
360 test_point
= gfx::Point(-1, 50);
362 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
363 ASSERT_FALSE(result_layer
);
366 TEST_F(LayerTreeImplTest
, HitTestingForSinglePerspectiveLayer
) {
367 scoped_ptr
<LayerImpl
> root
=
368 LayerImpl::Create(host_impl().active_tree(), 12345);
370 gfx::Transform identity_matrix
;
372 // perspective_projection_about_center * translation_by_z is designed so that
373 // the 100 x 100 layer becomes 50 x 50, and remains centered at (50, 50).
374 gfx::Transform perspective_projection_about_center
;
375 perspective_projection_about_center
.Translate(50.0, 50.0);
376 perspective_projection_about_center
.ApplyPerspectiveDepth(1.0);
377 perspective_projection_about_center
.Translate(-50.0, -50.0);
378 gfx::Transform translation_by_z
;
379 translation_by_z
.Translate3d(0.0, 0.0, -1.0);
381 gfx::Point3F transform_origin
;
382 gfx::PointF position
;
383 gfx::Size
bounds(100, 100);
384 SetLayerPropertiesForTesting(
385 root
.get(), perspective_projection_about_center
* translation_by_z
,
386 transform_origin
, position
, bounds
, true, false, true);
387 root
->SetDrawsContent(true);
389 host_impl().SetViewportSize(root
->bounds());
390 host_impl().active_tree()->SetRootLayer(root
.Pass());
391 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
393 // Sanity check the scenario we just created.
394 ASSERT_EQ(1u, RenderSurfaceLayerList().size());
395 ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
397 // Hit testing for points outside the layer.
398 // These corners would have been inside the un-transformed layer, but they
399 // should not hit the correctly transformed layer.
400 gfx::Point
test_point(24, 24);
401 LayerImpl
* result_layer
=
402 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
403 EXPECT_FALSE(result_layer
);
405 test_point
= gfx::Point(76, 76);
407 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
408 EXPECT_FALSE(result_layer
);
410 // Hit testing for a point inside should return the root layer.
411 test_point
= gfx::Point(26, 26);
413 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
414 ASSERT_TRUE(result_layer
);
415 EXPECT_EQ(12345, result_layer
->id());
417 test_point
= gfx::Point(74, 74);
419 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
420 ASSERT_TRUE(result_layer
);
421 EXPECT_EQ(12345, result_layer
->id());
424 TEST_F(LayerTreeImplTest
, HitTestingForSimpleClippedLayer
) {
425 // Test that hit-testing will only work for the visible portion of a layer,
426 // and not the entire layer bounds. Here we just test the simple axis-aligned
428 gfx::Transform identity_matrix
;
429 gfx::Point3F transform_origin
;
431 scoped_ptr
<LayerImpl
> root
= LayerImpl::Create(host_impl().active_tree(), 1);
432 SetLayerPropertiesForTesting(root
.get(), identity_matrix
, transform_origin
,
433 gfx::PointF(), gfx::Size(100, 100), true, false,
436 scoped_ptr
<LayerImpl
> clipping_layer
=
437 LayerImpl::Create(host_impl().active_tree(), 123);
438 // this layer is positioned, and hit testing should correctly know where the
440 gfx::PointF
position(25.f
, 25.f
);
441 gfx::Size
bounds(50, 50);
442 SetLayerPropertiesForTesting(clipping_layer
.get(), identity_matrix
,
443 transform_origin
, position
, bounds
, true,
445 clipping_layer
->SetMasksToBounds(true);
447 scoped_ptr
<LayerImpl
> child
=
448 LayerImpl::Create(host_impl().active_tree(), 456);
449 position
= gfx::PointF(-50.f
, -50.f
);
450 bounds
= gfx::Size(300, 300);
451 SetLayerPropertiesForTesting(child
.get(), identity_matrix
, transform_origin
,
452 position
, bounds
, true, false, false);
453 child
->SetDrawsContent(true);
454 clipping_layer
->AddChild(child
.Pass());
455 root
->AddChild(clipping_layer
.Pass());
458 host_impl().SetViewportSize(root
->bounds());
459 host_impl().active_tree()->SetRootLayer(root
.Pass());
460 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
462 // Sanity check the scenario we just created.
463 ASSERT_EQ(1u, RenderSurfaceLayerList().size());
464 ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
465 ASSERT_EQ(456, root_layer()->render_surface()->layer_list().at(0)->id());
467 // Hit testing for a point outside the layer should return a null pointer.
468 // Despite the child layer being very large, it should be clipped to the root
470 gfx::Point
test_point(24, 24);
471 LayerImpl
* result_layer
=
472 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
473 EXPECT_FALSE(result_layer
);
475 // Even though the layer exists at (101, 101), it should not be visible there
476 // since the clipping_layer would clamp it.
477 test_point
= gfx::Point(76, 76);
479 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
480 EXPECT_FALSE(result_layer
);
482 // Hit testing for a point inside should return the child layer.
483 test_point
= gfx::Point(26, 26);
485 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
486 ASSERT_TRUE(result_layer
);
487 EXPECT_EQ(456, result_layer
->id());
489 test_point
= gfx::Point(74, 74);
491 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
492 ASSERT_TRUE(result_layer
);
493 EXPECT_EQ(456, result_layer
->id());
496 TEST_F(LayerTreeImplTest
, HitTestingForMultiClippedRotatedLayer
) {
497 // This test checks whether hit testing correctly avoids hit testing with
498 // multiple ancestors that clip in non axis-aligned ways. To pass this test,
499 // the hit testing algorithm needs to recognize that multiple parent layers
500 // may clip the layer, and should not actually hit those clipped areas.
502 // The child and grand_child layers are both initialized to clip the
503 // rotated_leaf. The child layer is rotated about the top-left corner, so that
504 // the root + child clips combined create a triangle. The rotated_leaf will
505 // only be visible where it overlaps this triangle.
507 scoped_ptr
<LayerImpl
> root
=
508 LayerImpl::Create(host_impl().active_tree(), 123);
510 gfx::Transform identity_matrix
;
511 gfx::Point3F transform_origin
;
512 gfx::PointF position
;
513 gfx::Size
bounds(100, 100);
514 SetLayerPropertiesForTesting(root
.get(), identity_matrix
, transform_origin
,
515 position
, bounds
, true, false, true);
516 root
->SetMasksToBounds(true);
518 scoped_ptr
<LayerImpl
> child
=
519 LayerImpl::Create(host_impl().active_tree(), 456);
520 scoped_ptr
<LayerImpl
> grand_child
=
521 LayerImpl::Create(host_impl().active_tree(), 789);
522 scoped_ptr
<LayerImpl
> rotated_leaf
=
523 LayerImpl::Create(host_impl().active_tree(), 2468);
525 position
= gfx::PointF(10.f
, 10.f
);
526 bounds
= gfx::Size(80, 80);
527 SetLayerPropertiesForTesting(child
.get(), identity_matrix
, transform_origin
,
528 position
, bounds
, true, false, false);
529 child
->SetMasksToBounds(true);
531 gfx::Transform rotation45_degrees_about_corner
;
532 rotation45_degrees_about_corner
.RotateAboutZAxis(45.0);
534 // remember, positioned with respect to its parent which is already at 10,
536 position
= gfx::PointF();
538 gfx::Size(200, 200); // to ensure it covers at least sqrt(2) * 100.
539 SetLayerPropertiesForTesting(
540 grand_child
.get(), rotation45_degrees_about_corner
, transform_origin
,
541 position
, bounds
, true, false, false);
542 grand_child
->SetMasksToBounds(true);
544 // Rotates about the center of the layer
545 gfx::Transform rotated_leaf_transform
;
546 rotated_leaf_transform
.Translate(
547 -10.0, -10.0); // cancel out the grand_parent's position
548 rotated_leaf_transform
.RotateAboutZAxis(
549 -45.0); // cancel out the corner 45-degree rotation of the parent.
550 rotated_leaf_transform
.Translate(50.0, 50.0);
551 rotated_leaf_transform
.RotateAboutZAxis(45.0);
552 rotated_leaf_transform
.Translate(-50.0, -50.0);
553 position
= gfx::PointF();
554 bounds
= gfx::Size(100, 100);
555 SetLayerPropertiesForTesting(rotated_leaf
.get(), rotated_leaf_transform
,
556 transform_origin
, position
, bounds
, true,
558 rotated_leaf
->SetDrawsContent(true);
560 grand_child
->AddChild(rotated_leaf
.Pass());
561 child
->AddChild(grand_child
.Pass());
562 root
->AddChild(child
.Pass());
565 host_impl().SetViewportSize(root
->bounds());
566 host_impl().active_tree()->SetRootLayer(root
.Pass());
567 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
569 // (11, 89) is close to the the bottom left corner within the clip, but it is
570 // not inside the layer.
571 gfx::Point
test_point(11, 89);
572 LayerImpl
* result_layer
=
573 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
574 EXPECT_FALSE(result_layer
);
576 // Closer inwards from the bottom left will overlap the layer.
577 test_point
= gfx::Point(25, 75);
579 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
580 ASSERT_TRUE(result_layer
);
581 EXPECT_EQ(2468, result_layer
->id());
583 // (4, 50) is inside the unclipped layer, but that corner of the layer should
584 // be clipped away by the grandparent and should not get hit. If hit testing
585 // blindly uses visible content rect without considering how parent may clip
586 // the layer, then hit testing would accidentally think that the point
587 // successfully hits the layer.
588 test_point
= gfx::Point(4, 50);
590 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
591 EXPECT_FALSE(result_layer
);
593 // (11, 50) is inside the layer and within the clipped area.
594 test_point
= gfx::Point(11, 50);
596 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
597 ASSERT_TRUE(result_layer
);
598 EXPECT_EQ(2468, result_layer
->id());
600 // Around the middle, just to the right and up, would have hit the layer
601 // except that that area should be clipped away by the parent.
602 test_point
= gfx::Point(51, 49);
604 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
605 EXPECT_FALSE(result_layer
);
607 // Around the middle, just to the left and down, should successfully hit the
609 test_point
= gfx::Point(49, 51);
611 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
612 ASSERT_TRUE(result_layer
);
613 EXPECT_EQ(2468, result_layer
->id());
616 TEST_F(LayerTreeImplTest
, HitTestingForNonClippingIntermediateLayer
) {
617 // This test checks that hit testing code does not accidentally clip to layer
618 // bounds for a layer that actually does not clip.
619 gfx::Transform identity_matrix
;
620 gfx::Point3F transform_origin
;
622 scoped_ptr
<LayerImpl
> root
= LayerImpl::Create(host_impl().active_tree(), 1);
623 SetLayerPropertiesForTesting(root
.get(), identity_matrix
, transform_origin
,
624 gfx::PointF(), gfx::Size(100, 100), true, false,
627 scoped_ptr
<LayerImpl
> intermediate_layer
=
628 LayerImpl::Create(host_impl().active_tree(), 123);
629 // this layer is positioned, and hit testing should correctly know where the
631 gfx::PointF
position(10.f
, 10.f
);
632 gfx::Size
bounds(50, 50);
633 SetLayerPropertiesForTesting(intermediate_layer
.get(), identity_matrix
,
634 transform_origin
, position
, bounds
, true,
636 // Sanity check the intermediate layer should not clip.
637 ASSERT_FALSE(intermediate_layer
->masks_to_bounds());
638 ASSERT_FALSE(intermediate_layer
->mask_layer());
640 // The child of the intermediate_layer is translated so that it does not
641 // overlap intermediate_layer at all. If child is incorrectly clipped, we
642 // would not be able to hit it successfully.
643 scoped_ptr
<LayerImpl
> child
=
644 LayerImpl::Create(host_impl().active_tree(), 456);
645 position
= gfx::PointF(60.f
, 60.f
); // 70, 70 in screen space
646 bounds
= gfx::Size(20, 20);
647 SetLayerPropertiesForTesting(child
.get(), identity_matrix
, transform_origin
,
648 position
, bounds
, true, false, false);
649 child
->SetDrawsContent(true);
650 intermediate_layer
->AddChild(child
.Pass());
651 root
->AddChild(intermediate_layer
.Pass());
654 host_impl().SetViewportSize(root
->bounds());
655 host_impl().active_tree()->SetRootLayer(root
.Pass());
656 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
658 // Sanity check the scenario we just created.
659 ASSERT_EQ(1u, RenderSurfaceLayerList().size());
660 ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
661 ASSERT_EQ(456, root_layer()->render_surface()->layer_list().at(0)->id());
663 // Hit testing for a point outside the layer should return a null pointer.
664 gfx::Point
test_point(69, 69);
665 LayerImpl
* result_layer
=
666 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
667 EXPECT_FALSE(result_layer
);
669 test_point
= gfx::Point(91, 91);
671 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
672 EXPECT_FALSE(result_layer
);
674 // Hit testing for a point inside should return the child layer.
675 test_point
= gfx::Point(71, 71);
677 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
678 ASSERT_TRUE(result_layer
);
679 EXPECT_EQ(456, result_layer
->id());
681 test_point
= gfx::Point(89, 89);
683 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
684 ASSERT_TRUE(result_layer
);
685 EXPECT_EQ(456, result_layer
->id());
688 TEST_F(LayerTreeImplTest
, HitTestingForMultipleLayers
) {
689 scoped_ptr
<LayerImpl
> root
= LayerImpl::Create(host_impl().active_tree(), 1);
691 gfx::Transform identity_matrix
;
692 gfx::Point3F transform_origin
;
693 gfx::PointF position
;
694 gfx::Size
bounds(100, 100);
695 SetLayerPropertiesForTesting(root
.get(), identity_matrix
, transform_origin
,
696 position
, bounds
, true, false, true);
697 root
->SetDrawsContent(true);
699 // child 1 and child2 are initialized to overlap between x=50 and x=60.
700 // grand_child is set to overlap both child1 and child2 between y=50 and
701 // y=60. The expected stacking order is: (front) child2, (second)
702 // grand_child, (third) child1, and (back) the root layer behind all other
705 scoped_ptr
<LayerImpl
> child1
=
706 LayerImpl::Create(host_impl().active_tree(), 2);
707 scoped_ptr
<LayerImpl
> child2
=
708 LayerImpl::Create(host_impl().active_tree(), 3);
709 scoped_ptr
<LayerImpl
> grand_child1
=
710 LayerImpl::Create(host_impl().active_tree(), 4);
712 position
= gfx::PointF(10.f
, 10.f
);
713 bounds
= gfx::Size(50, 50);
714 SetLayerPropertiesForTesting(child1
.get(), identity_matrix
,
715 transform_origin
, position
, bounds
, true,
717 child1
->SetDrawsContent(true);
719 position
= gfx::PointF(50.f
, 10.f
);
720 bounds
= gfx::Size(50, 50);
721 SetLayerPropertiesForTesting(child2
.get(), identity_matrix
,
722 transform_origin
, position
, bounds
, true,
724 child2
->SetDrawsContent(true);
726 // Remember that grand_child is positioned with respect to its parent (i.e.
727 // child1). In screen space, the intended position is (10, 50), with size
729 position
= gfx::PointF(0.f
, 40.f
);
730 bounds
= gfx::Size(100, 50);
731 SetLayerPropertiesForTesting(grand_child1
.get(), identity_matrix
,
732 transform_origin
, position
, bounds
, true,
734 grand_child1
->SetDrawsContent(true);
736 child1
->AddChild(grand_child1
.Pass());
737 root
->AddChild(child1
.Pass());
738 root
->AddChild(child2
.Pass());
741 LayerImpl
* child1
= root
->children()[0];
742 LayerImpl
* child2
= root
->children()[1];
743 LayerImpl
* grand_child1
= child1
->children()[0];
745 host_impl().SetViewportSize(root
->bounds());
746 host_impl().active_tree()->SetRootLayer(root
.Pass());
747 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
749 // Sanity check the scenario we just created.
752 ASSERT_TRUE(grand_child1
);
753 ASSERT_EQ(1u, RenderSurfaceLayerList().size());
755 RenderSurfaceImpl
* root_render_surface
= root_layer()->render_surface();
756 ASSERT_EQ(4u, root_render_surface
->layer_list().size());
757 ASSERT_EQ(1, root_render_surface
->layer_list().at(0)->id()); // root layer
758 ASSERT_EQ(2, root_render_surface
->layer_list().at(1)->id()); // child1
759 ASSERT_EQ(4, root_render_surface
->layer_list().at(2)->id()); // grand_child1
760 ASSERT_EQ(3, root_render_surface
->layer_list().at(3)->id()); // child2
762 // Nothing overlaps the root_layer at (1, 1), so hit testing there should find
764 gfx::Point test_point
= gfx::Point(1, 1);
765 LayerImpl
* result_layer
=
766 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
767 ASSERT_TRUE(result_layer
);
768 EXPECT_EQ(1, result_layer
->id());
770 // At (15, 15), child1 and root are the only layers. child1 is expected to be
772 test_point
= gfx::Point(15, 15);
774 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
775 ASSERT_TRUE(result_layer
);
776 EXPECT_EQ(2, result_layer
->id());
778 // At (51, 20), child1 and child2 overlap. child2 is expected to be on top.
779 test_point
= gfx::Point(51, 20);
781 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
782 ASSERT_TRUE(result_layer
);
783 EXPECT_EQ(3, result_layer
->id());
785 // At (80, 51), child2 and grand_child1 overlap. child2 is expected to be on
787 test_point
= gfx::Point(80, 51);
789 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
790 ASSERT_TRUE(result_layer
);
791 EXPECT_EQ(3, result_layer
->id());
793 // At (51, 51), all layers overlap each other. child2 is expected to be on top
794 // of all other layers.
795 test_point
= gfx::Point(51, 51);
797 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
798 ASSERT_TRUE(result_layer
);
799 EXPECT_EQ(3, result_layer
->id());
801 // At (20, 51), child1 and grand_child1 overlap. grand_child1 is expected to
803 test_point
= gfx::Point(20, 51);
805 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
806 ASSERT_TRUE(result_layer
);
807 EXPECT_EQ(4, result_layer
->id());
810 TEST_F(LayerTreeImplTest
, HitTestingForMultipleLayersAtVaryingDepths
) {
811 scoped_ptr
<LayerImpl
> root
= LayerImpl::Create(host_impl().active_tree(), 1);
813 gfx::Transform identity_matrix
;
814 gfx::Point3F transform_origin
;
815 gfx::PointF position
;
816 gfx::Size
bounds(100, 100);
817 SetLayerPropertiesForTesting(root
.get(), identity_matrix
, transform_origin
,
818 position
, bounds
, true, false, true);
819 root
->SetDrawsContent(true);
820 root
->SetShouldFlattenTransform(false);
821 root
->Set3dSortingContextId(1);
823 // child 1 and child2 are initialized to overlap between x=50 and x=60.
824 // grand_child is set to overlap both child1 and child2 between y=50 and
825 // y=60. The expected stacking order is: (front) child2, (second)
826 // grand_child, (third) child1, and (back) the root layer behind all other
829 scoped_ptr
<LayerImpl
> child1
=
830 LayerImpl::Create(host_impl().active_tree(), 2);
831 scoped_ptr
<LayerImpl
> child2
=
832 LayerImpl::Create(host_impl().active_tree(), 3);
833 scoped_ptr
<LayerImpl
> grand_child1
=
834 LayerImpl::Create(host_impl().active_tree(), 4);
836 position
= gfx::PointF(10.f
, 10.f
);
837 bounds
= gfx::Size(50, 50);
838 SetLayerPropertiesForTesting(child1
.get(), identity_matrix
,
839 transform_origin
, position
, bounds
, true,
841 child1
->SetDrawsContent(true);
842 child1
->SetShouldFlattenTransform(false);
843 child1
->Set3dSortingContextId(1);
845 position
= gfx::PointF(50.f
, 10.f
);
846 bounds
= gfx::Size(50, 50);
847 gfx::Transform translate_z
;
848 translate_z
.Translate3d(0, 0, -10.f
);
849 SetLayerPropertiesForTesting(child2
.get(), translate_z
, transform_origin
,
850 position
, bounds
, true, false, false);
851 child2
->SetDrawsContent(true);
852 child2
->SetShouldFlattenTransform(false);
853 child2
->Set3dSortingContextId(1);
855 // Remember that grand_child is positioned with respect to its parent (i.e.
856 // child1). In screen space, the intended position is (10, 50), with size
858 position
= gfx::PointF(0.f
, 40.f
);
859 bounds
= gfx::Size(100, 50);
860 SetLayerPropertiesForTesting(grand_child1
.get(), identity_matrix
,
861 transform_origin
, position
, bounds
, true,
863 grand_child1
->SetDrawsContent(true);
864 grand_child1
->SetShouldFlattenTransform(false);
866 child1
->AddChild(grand_child1
.Pass());
867 root
->AddChild(child1
.Pass());
868 root
->AddChild(child2
.Pass());
871 LayerImpl
* child1
= root
->children()[0];
872 LayerImpl
* child2
= root
->children()[1];
873 LayerImpl
* grand_child1
= child1
->children()[0];
875 host_impl().SetViewportSize(root
->bounds());
876 host_impl().active_tree()->SetRootLayer(root
.Pass());
877 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
879 // Sanity check the scenario we just created.
882 ASSERT_TRUE(grand_child1
);
883 ASSERT_EQ(1u, RenderSurfaceLayerList().size());
885 // Nothing overlaps the root_layer at (1, 1), so hit testing there should find
887 gfx::Point test_point
= gfx::Point(1, 1);
888 LayerImpl
* result_layer
=
889 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
890 ASSERT_TRUE(result_layer
);
891 EXPECT_EQ(1, result_layer
->id());
893 // At (15, 15), child1 and root are the only layers. child1 is expected to be
895 test_point
= gfx::Point(15, 15);
897 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
898 ASSERT_TRUE(result_layer
);
899 EXPECT_EQ(2, result_layer
->id());
901 // At (51, 20), child1 and child2 overlap. child2 is expected to be on top.
902 // (because 3 is transformed to the back).
903 test_point
= gfx::Point(51, 20);
905 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
906 ASSERT_TRUE(result_layer
);
907 EXPECT_EQ(2, result_layer
->id());
909 // 3 Would have been on top if it hadn't been transformed to the background.
910 // Make sure that it isn't hit.
911 test_point
= gfx::Point(80, 51);
913 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
914 ASSERT_TRUE(result_layer
);
915 EXPECT_EQ(4, result_layer
->id());
917 // 3 Would have been on top if it hadn't been transformed to the background.
918 // Make sure that it isn't hit.
919 test_point
= gfx::Point(51, 51);
921 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
922 ASSERT_TRUE(result_layer
);
923 EXPECT_EQ(4, result_layer
->id());
925 // At (20, 51), child1 and grand_child1 overlap. grand_child1 is expected to
927 test_point
= gfx::Point(20, 51);
929 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
930 ASSERT_TRUE(result_layer
);
931 EXPECT_EQ(4, result_layer
->id());
934 TEST_F(LayerTreeImplTest
, HitTestingRespectsClipParents
) {
935 scoped_ptr
<LayerImpl
> root
= LayerImpl::Create(host_impl().active_tree(), 1);
936 gfx::Transform identity_matrix
;
937 gfx::Point3F transform_origin
;
938 gfx::PointF position
;
939 gfx::Size
bounds(100, 100);
940 SetLayerPropertiesForTesting(root
.get(), identity_matrix
, transform_origin
,
941 position
, bounds
, true, false, true);
942 root
->SetDrawsContent(true);
944 scoped_ptr
<LayerImpl
> child
=
945 LayerImpl::Create(host_impl().active_tree(), 2);
946 scoped_ptr
<LayerImpl
> grand_child
=
947 LayerImpl::Create(host_impl().active_tree(), 4);
949 position
= gfx::PointF(10.f
, 10.f
);
950 bounds
= gfx::Size(1, 1);
951 SetLayerPropertiesForTesting(child
.get(), identity_matrix
, transform_origin
,
952 position
, bounds
, true, false, false);
953 child
->SetDrawsContent(true);
954 child
->SetMasksToBounds(true);
956 position
= gfx::PointF(0.f
, 40.f
);
957 bounds
= gfx::Size(100, 50);
958 SetLayerPropertiesForTesting(grand_child
.get(), identity_matrix
,
959 transform_origin
, position
, bounds
, true,
961 grand_child
->SetDrawsContent(true);
962 grand_child
->SetHasRenderSurface(true);
964 // This should let |grand_child| "escape" |child|'s clip.
965 grand_child
->SetClipParent(root
.get());
967 child
->AddChild(grand_child
.Pass());
968 root
->AddChild(child
.Pass());
971 host_impl().SetViewportSize(root
->bounds());
972 host_impl().active_tree()->SetRootLayer(root
.Pass());
973 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
975 gfx::Point test_point
= gfx::Point(12, 52);
976 LayerImpl
* result_layer
=
977 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
978 ASSERT_TRUE(result_layer
);
979 EXPECT_EQ(4, result_layer
->id());
982 TEST_F(LayerTreeImplTest
, HitTestingRespectsScrollParents
) {
983 scoped_ptr
<LayerImpl
> root
= LayerImpl::Create(host_impl().active_tree(), 1);
984 gfx::Transform identity_matrix
;
985 gfx::Point3F transform_origin
;
986 gfx::PointF position
;
987 gfx::Size
bounds(100, 100);
988 SetLayerPropertiesForTesting(root
.get(), identity_matrix
, transform_origin
,
989 position
, bounds
, true, false, true);
990 root
->SetDrawsContent(true);
992 scoped_ptr
<LayerImpl
> child
=
993 LayerImpl::Create(host_impl().active_tree(), 2);
994 scoped_ptr
<LayerImpl
> scroll_child
=
995 LayerImpl::Create(host_impl().active_tree(), 3);
996 scoped_ptr
<LayerImpl
> grand_child
=
997 LayerImpl::Create(host_impl().active_tree(), 4);
999 position
= gfx::PointF(10.f
, 10.f
);
1000 bounds
= gfx::Size(1, 1);
1001 SetLayerPropertiesForTesting(child
.get(), identity_matrix
, transform_origin
,
1002 position
, bounds
, true, false, false);
1003 child
->SetDrawsContent(true);
1004 child
->SetMasksToBounds(true);
1006 position
= gfx::PointF();
1007 bounds
= gfx::Size(200, 200);
1008 SetLayerPropertiesForTesting(scroll_child
.get(), identity_matrix
,
1009 transform_origin
, position
, bounds
, true,
1011 scroll_child
->SetDrawsContent(true);
1013 // This should cause scroll child and its descendants to be affected by
1015 scroll_child
->SetScrollParent(child
.get());
1016 scoped_ptr
<std::set
<LayerImpl
*>> scroll_children(new std::set
<LayerImpl
*>);
1017 scroll_children
->insert(scroll_child
.get());
1018 child
->SetScrollChildren(scroll_children
.release());
1020 SetLayerPropertiesForTesting(grand_child
.get(), identity_matrix
,
1021 transform_origin
, position
, bounds
, true,
1023 grand_child
->SetDrawsContent(true);
1024 grand_child
->SetHasRenderSurface(true);
1026 scroll_child
->AddChild(grand_child
.Pass());
1027 root
->AddChild(scroll_child
.Pass());
1028 root
->AddChild(child
.Pass());
1031 host_impl().SetViewportSize(root
->bounds());
1032 host_impl().active_tree()->SetRootLayer(root
.Pass());
1033 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
1035 gfx::Point test_point
= gfx::Point(12, 52);
1036 LayerImpl
* result_layer
=
1037 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
1038 // The |test_point| should have been clipped away by |child|, the scroll
1039 // parent, so the only thing that should be hit is |root|.
1040 ASSERT_TRUE(result_layer
);
1041 ASSERT_EQ(1, result_layer
->id());
1043 TEST_F(LayerTreeImplTest
, HitTestingForMultipleLayerLists
) {
1045 // The geometry is set up similarly to the previous case, but
1046 // all layers are forced to be render surfaces now.
1048 scoped_ptr
<LayerImpl
> root
= LayerImpl::Create(host_impl().active_tree(), 1);
1050 gfx::Transform identity_matrix
;
1051 gfx::Point3F transform_origin
;
1052 gfx::PointF position
;
1053 gfx::Size
bounds(100, 100);
1054 SetLayerPropertiesForTesting(root
.get(), identity_matrix
, transform_origin
,
1055 position
, bounds
, true, false, true);
1056 root
->SetDrawsContent(true);
1058 // child 1 and child2 are initialized to overlap between x=50 and x=60.
1059 // grand_child is set to overlap both child1 and child2 between y=50 and
1060 // y=60. The expected stacking order is: (front) child2, (second)
1061 // grand_child, (third) child1, and (back) the root layer behind all other
1064 scoped_ptr
<LayerImpl
> child1
=
1065 LayerImpl::Create(host_impl().active_tree(), 2);
1066 scoped_ptr
<LayerImpl
> child2
=
1067 LayerImpl::Create(host_impl().active_tree(), 3);
1068 scoped_ptr
<LayerImpl
> grand_child1
=
1069 LayerImpl::Create(host_impl().active_tree(), 4);
1071 position
= gfx::PointF(10.f
, 10.f
);
1072 bounds
= gfx::Size(50, 50);
1073 SetLayerPropertiesForTesting(child1
.get(), identity_matrix
,
1074 transform_origin
, position
, bounds
, true,
1076 child1
->SetDrawsContent(true);
1077 child1
->SetHasRenderSurface(true);
1079 position
= gfx::PointF(50.f
, 10.f
);
1080 bounds
= gfx::Size(50, 50);
1081 SetLayerPropertiesForTesting(child2
.get(), identity_matrix
,
1082 transform_origin
, position
, bounds
, true,
1084 child2
->SetDrawsContent(true);
1085 child2
->SetHasRenderSurface(true);
1087 // Remember that grand_child is positioned with respect to its parent (i.e.
1088 // child1). In screen space, the intended position is (10, 50), with size
1090 position
= gfx::PointF(0.f
, 40.f
);
1091 bounds
= gfx::Size(100, 50);
1092 SetLayerPropertiesForTesting(grand_child1
.get(), identity_matrix
,
1093 transform_origin
, position
, bounds
, true,
1095 grand_child1
->SetDrawsContent(true);
1096 grand_child1
->SetHasRenderSurface(true);
1098 child1
->AddChild(grand_child1
.Pass());
1099 root
->AddChild(child1
.Pass());
1100 root
->AddChild(child2
.Pass());
1103 LayerImpl
* child1
= root
->children()[0];
1104 LayerImpl
* child2
= root
->children()[1];
1105 LayerImpl
* grand_child1
= child1
->children()[0];
1107 host_impl().SetViewportSize(root
->bounds());
1108 host_impl().active_tree()->SetRootLayer(root
.Pass());
1109 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
1111 // Sanity check the scenario we just created.
1112 ASSERT_TRUE(child1
);
1113 ASSERT_TRUE(child2
);
1114 ASSERT_TRUE(grand_child1
);
1115 ASSERT_TRUE(child1
->render_surface());
1116 ASSERT_TRUE(child2
->render_surface());
1117 ASSERT_TRUE(grand_child1
->render_surface());
1118 ASSERT_EQ(4u, RenderSurfaceLayerList().size());
1119 // The root surface has the root layer, and child1's and child2's render
1121 ASSERT_EQ(3u, root_layer()->render_surface()->layer_list().size());
1122 // The child1 surface has the child1 layer and grand_child1's render surface.
1123 ASSERT_EQ(2u, child1
->render_surface()->layer_list().size());
1124 ASSERT_EQ(1u, child2
->render_surface()->layer_list().size());
1125 ASSERT_EQ(1u, grand_child1
->render_surface()->layer_list().size());
1126 ASSERT_EQ(1, RenderSurfaceLayerList().at(0)->id()); // root layer
1127 ASSERT_EQ(2, RenderSurfaceLayerList()[1]->id()); // child1
1128 ASSERT_EQ(4, RenderSurfaceLayerList().at(2)->id()); // grand_child1
1129 ASSERT_EQ(3, RenderSurfaceLayerList()[3]->id()); // child2
1131 // Nothing overlaps the root_layer at (1, 1), so hit testing there should find
1133 gfx::Point test_point
= gfx::Point(1, 1);
1134 LayerImpl
* result_layer
=
1135 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
1136 ASSERT_TRUE(result_layer
);
1137 EXPECT_EQ(1, result_layer
->id());
1139 // At (15, 15), child1 and root are the only layers. child1 is expected to be
1141 test_point
= gfx::Point(15, 15);
1143 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
1144 ASSERT_TRUE(result_layer
);
1145 EXPECT_EQ(2, result_layer
->id());
1147 // At (51, 20), child1 and child2 overlap. child2 is expected to be on top.
1148 test_point
= gfx::Point(51, 20);
1150 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
1151 ASSERT_TRUE(result_layer
);
1152 EXPECT_EQ(3, result_layer
->id());
1154 // At (80, 51), child2 and grand_child1 overlap. child2 is expected to be on
1156 test_point
= gfx::Point(80, 51);
1158 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
1159 ASSERT_TRUE(result_layer
);
1160 EXPECT_EQ(3, result_layer
->id());
1162 // At (51, 51), all layers overlap each other. child2 is expected to be on top
1163 // of all other layers.
1164 test_point
= gfx::Point(51, 51);
1166 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
1167 ASSERT_TRUE(result_layer
);
1168 EXPECT_EQ(3, result_layer
->id());
1170 // At (20, 51), child1 and grand_child1 overlap. grand_child1 is expected to
1172 test_point
= gfx::Point(20, 51);
1174 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point
);
1175 ASSERT_TRUE(result_layer
);
1176 EXPECT_EQ(4, result_layer
->id());
1179 TEST_F(LayerTreeImplTest
, HitCheckingTouchHandlerRegionsForSingleLayer
) {
1180 scoped_ptr
<LayerImpl
> root
=
1181 LayerImpl::Create(host_impl().active_tree(), 12345);
1183 gfx::Transform identity_matrix
;
1184 Region
touch_handler_region(gfx::Rect(10, 10, 50, 50));
1185 gfx::Point3F transform_origin
;
1186 gfx::PointF position
;
1187 gfx::Size
bounds(100, 100);
1188 SetLayerPropertiesForTesting(root
.get(), identity_matrix
, transform_origin
,
1189 position
, bounds
, true, false, true);
1190 root
->SetDrawsContent(true);
1192 host_impl().SetViewportSize(root
->bounds());
1193 host_impl().active_tree()->SetRootLayer(root
.Pass());
1194 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
1196 // Sanity check the scenario we just created.
1197 ASSERT_EQ(1u, RenderSurfaceLayerList().size());
1198 ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
1200 // Hit checking for any point should return a null pointer for a layer without
1201 // any touch event handler regions.
1202 gfx::Point
test_point(11, 11);
1203 LayerImpl
* result_layer
=
1204 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1206 EXPECT_FALSE(result_layer
);
1208 host_impl().active_tree()->root_layer()->SetTouchEventHandlerRegion(
1209 touch_handler_region
);
1210 // Hit checking for a point outside the layer should return a null pointer.
1211 test_point
= gfx::Point(101, 101);
1213 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1215 EXPECT_FALSE(result_layer
);
1217 test_point
= gfx::Point(-1, -1);
1219 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1221 EXPECT_FALSE(result_layer
);
1223 // Hit checking for a point inside the layer, but outside the touch handler
1224 // region should return a null pointer.
1225 test_point
= gfx::Point(1, 1);
1227 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1229 EXPECT_FALSE(result_layer
);
1231 test_point
= gfx::Point(99, 99);
1233 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1235 EXPECT_FALSE(result_layer
);
1237 // Hit checking for a point inside the touch event handler region should
1238 // return the root layer.
1239 test_point
= gfx::Point(11, 11);
1241 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1243 ASSERT_TRUE(result_layer
);
1244 EXPECT_EQ(12345, result_layer
->id());
1246 test_point
= gfx::Point(59, 59);
1248 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1250 ASSERT_TRUE(result_layer
);
1251 EXPECT_EQ(12345, result_layer
->id());
1254 TEST_F(LayerTreeImplTest
,
1255 HitCheckingTouchHandlerRegionsForUninvertibleTransform
) {
1256 scoped_ptr
<LayerImpl
> root
=
1257 LayerImpl::Create(host_impl().active_tree(), 12345);
1259 gfx::Transform uninvertible_transform
;
1260 uninvertible_transform
.matrix().set(0, 0, 0.0);
1261 uninvertible_transform
.matrix().set(1, 1, 0.0);
1262 uninvertible_transform
.matrix().set(2, 2, 0.0);
1263 uninvertible_transform
.matrix().set(3, 3, 0.0);
1264 ASSERT_FALSE(uninvertible_transform
.IsInvertible());
1266 gfx::Transform identity_matrix
;
1267 Region
touch_handler_region(gfx::Rect(10, 10, 50, 50));
1268 gfx::Point3F transform_origin
;
1269 gfx::PointF position
;
1270 gfx::Size
bounds(100, 100);
1271 SetLayerPropertiesForTesting(root
.get(), uninvertible_transform
,
1272 transform_origin
, position
, bounds
, true, false,
1274 root
->SetDrawsContent(true);
1275 root
->SetTouchEventHandlerRegion(touch_handler_region
);
1277 host_impl().SetViewportSize(root
->bounds());
1278 host_impl().active_tree()->SetRootLayer(root
.Pass());
1279 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
1281 // Sanity check the scenario we just created.
1282 ASSERT_EQ(1u, RenderSurfaceLayerList().size());
1283 ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
1284 ASSERT_FALSE(root_layer()->screen_space_transform().IsInvertible());
1286 // Hit checking any point should not hit the touch handler region on the
1287 // layer. If the invertible matrix is accidentally ignored and treated like an
1288 // identity, then the hit testing will incorrectly hit the layer when it
1290 gfx::Point
test_point(1, 1);
1291 LayerImpl
* result_layer
=
1292 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1294 EXPECT_FALSE(result_layer
);
1296 test_point
= gfx::Point(10, 10);
1298 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1300 EXPECT_FALSE(result_layer
);
1302 test_point
= gfx::Point(10, 30);
1304 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1306 EXPECT_FALSE(result_layer
);
1308 test_point
= gfx::Point(50, 50);
1310 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1312 EXPECT_FALSE(result_layer
);
1314 test_point
= gfx::Point(67, 48);
1316 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1318 EXPECT_FALSE(result_layer
);
1320 test_point
= gfx::Point(99, 99);
1322 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1324 EXPECT_FALSE(result_layer
);
1326 test_point
= gfx::Point(-1, -1);
1328 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1330 EXPECT_FALSE(result_layer
);
1333 TEST_F(LayerTreeImplTest
, MakeScrollbarsInvisibleNearMinPageScale
) {
1334 const int kThumbThickness
= 10;
1335 const int kTrackStart
= 0;
1336 const bool kIsLeftSideVerticalScrollbar
= false;
1337 const bool kIsOverlayScrollbar
= true;
1339 LayerTreeImpl
* active_tree
= host_impl().active_tree();
1340 active_tree
->set_hide_pinch_scrollbars_near_min_scale(true);
1342 scoped_ptr
<LayerImpl
> scroll_layer
= LayerImpl::Create(active_tree
, 1);
1343 scoped_ptr
<SolidColorScrollbarLayerImpl
> vertical_scrollbar_layer
=
1344 SolidColorScrollbarLayerImpl::Create(active_tree
,
1349 kIsLeftSideVerticalScrollbar
,
1350 kIsOverlayScrollbar
);
1351 scoped_ptr
<SolidColorScrollbarLayerImpl
> horizontal_scrollbar_layer
=
1352 SolidColorScrollbarLayerImpl::Create(active_tree
,
1357 kIsLeftSideVerticalScrollbar
,
1358 kIsOverlayScrollbar
);
1360 scoped_ptr
<LayerImpl
> clip_layer
= LayerImpl::Create(active_tree
, 4);
1361 scoped_ptr
<LayerImpl
> page_scale_layer
= LayerImpl::Create(active_tree
, 5);
1363 scroll_layer
->SetScrollClipLayer(clip_layer
->id());
1365 LayerImpl
* scroll_layer_ptr
= scroll_layer
.get();
1366 LayerImpl
* page_scale_layer_ptr
= page_scale_layer
.get();
1368 clip_layer
->AddChild(page_scale_layer
.Pass());
1369 page_scale_layer_ptr
->AddChild(scroll_layer
.Pass());
1371 vertical_scrollbar_layer
->SetScrollLayerAndClipLayerByIds(
1372 scroll_layer_ptr
->id(),
1374 horizontal_scrollbar_layer
->SetScrollLayerAndClipLayerByIds(
1375 scroll_layer_ptr
->id(),
1378 active_tree
->PushPageScaleFromMainThread(1.0f
, 1.0f
, 4.0f
);
1379 active_tree
->SetViewportLayersFromIds(
1380 Layer::INVALID_ID
, // Overscroll
1381 page_scale_layer_ptr
->id(),
1382 scroll_layer_ptr
->id(),
1383 Layer::INVALID_ID
); // Outer Scroll
1385 EXPECT_TRUE(vertical_scrollbar_layer
->hide_layer_and_subtree());
1386 EXPECT_TRUE(horizontal_scrollbar_layer
->hide_layer_and_subtree());
1388 active_tree
->PushPageScaleFromMainThread(1.04f
, 1.0f
, 4.0f
);
1389 EXPECT_TRUE(vertical_scrollbar_layer
->hide_layer_and_subtree());
1390 EXPECT_TRUE(horizontal_scrollbar_layer
->hide_layer_and_subtree());
1392 active_tree
->PushPageScaleFromMainThread(1.06f
, 1.0f
, 4.0f
);
1393 EXPECT_FALSE(vertical_scrollbar_layer
->hide_layer_and_subtree());
1394 EXPECT_FALSE(horizontal_scrollbar_layer
->hide_layer_and_subtree());
1396 active_tree
->PushPageScaleFromMainThread(1.5f
, 1.0f
, 4.0f
);
1397 EXPECT_FALSE(vertical_scrollbar_layer
->hide_layer_and_subtree());
1398 EXPECT_FALSE(horizontal_scrollbar_layer
->hide_layer_and_subtree());
1401 TEST_F(LayerTreeImplTest
,
1402 HitCheckingTouchHandlerRegionsForSinglePositionedLayer
) {
1403 scoped_ptr
<LayerImpl
> root
=
1404 LayerImpl::Create(host_impl().active_tree(), 12345);
1406 gfx::Transform identity_matrix
;
1407 Region
touch_handler_region(gfx::Rect(10, 10, 50, 50));
1408 gfx::Point3F transform_origin
;
1409 // this layer is positioned, and hit testing should correctly know where the
1410 // layer is located.
1411 gfx::PointF
position(50.f
, 50.f
);
1412 gfx::Size
bounds(100, 100);
1413 SetLayerPropertiesForTesting(root
.get(), identity_matrix
, transform_origin
,
1414 position
, bounds
, true, false, true);
1415 root
->SetDrawsContent(true);
1416 root
->SetTouchEventHandlerRegion(touch_handler_region
);
1418 host_impl().SetViewportSize(root
->bounds());
1419 host_impl().active_tree()->SetRootLayer(root
.Pass());
1420 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
1422 // Sanity check the scenario we just created.
1423 ASSERT_EQ(1u, RenderSurfaceLayerList().size());
1424 ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
1426 // Hit checking for a point outside the layer should return a null pointer.
1427 gfx::Point
test_point(49, 49);
1428 LayerImpl
* result_layer
=
1429 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1431 EXPECT_FALSE(result_layer
);
1433 // Even though the layer has a touch handler region containing (101, 101), it
1434 // should not be visible there since the root render surface would clamp it.
1435 test_point
= gfx::Point(101, 101);
1437 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1439 EXPECT_FALSE(result_layer
);
1441 // Hit checking for a point inside the layer, but outside the touch handler
1442 // region should return a null pointer.
1443 test_point
= gfx::Point(51, 51);
1445 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1447 EXPECT_FALSE(result_layer
);
1449 // Hit checking for a point inside the touch event handler region should
1450 // return the root layer.
1451 test_point
= gfx::Point(61, 61);
1453 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1455 ASSERT_TRUE(result_layer
);
1456 EXPECT_EQ(12345, result_layer
->id());
1458 test_point
= gfx::Point(99, 99);
1460 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1462 ASSERT_TRUE(result_layer
);
1463 EXPECT_EQ(12345, result_layer
->id());
1466 TEST_F(LayerTreeImplTest
,
1467 HitCheckingTouchHandlerRegionsForSingleLayerWithDeviceScale
) {
1468 // The layer's device_scale_factor and page_scale_factor should scale the
1469 // content rect and we should be able to hit the touch handler region by
1470 // scaling the points accordingly.
1471 scoped_ptr
<LayerImpl
> root
= LayerImpl::Create(host_impl().active_tree(), 1);
1473 gfx::Transform identity_matrix
;
1474 gfx::Point3F transform_origin
;
1475 // Set the bounds of the root layer big enough to fit the child when scaled.
1476 SetLayerPropertiesForTesting(root
.get(), identity_matrix
, transform_origin
,
1477 gfx::PointF(), gfx::Size(100, 100), true, false,
1480 Region
touch_handler_region(gfx::Rect(10, 10, 30, 30));
1481 gfx::PointF
position(25.f
, 25.f
);
1482 gfx::Size
bounds(50, 50);
1483 scoped_ptr
<LayerImpl
> test_layer
=
1484 LayerImpl::Create(host_impl().active_tree(), 12345);
1485 SetLayerPropertiesForTesting(test_layer
.get(), identity_matrix
,
1486 transform_origin
, position
, bounds
, true,
1489 test_layer
->SetDrawsContent(true);
1490 test_layer
->SetTouchEventHandlerRegion(touch_handler_region
);
1491 root
->AddChild(test_layer
.Pass());
1494 float device_scale_factor
= 3.f
;
1495 float page_scale_factor
= 5.f
;
1496 gfx::Size scaled_bounds_for_root
= gfx::ToCeiledSize(
1497 gfx::ScaleSize(root
->bounds(), device_scale_factor
* page_scale_factor
));
1498 host_impl().SetViewportSize(scaled_bounds_for_root
);
1500 host_impl().SetDeviceScaleFactor(device_scale_factor
);
1501 host_impl().active_tree()->PushPageScaleFromMainThread(
1502 page_scale_factor
, page_scale_factor
, page_scale_factor
);
1503 host_impl().active_tree()->SetPageScaleOnActiveTree(page_scale_factor
);
1504 host_impl().active_tree()->SetRootLayer(root
.Pass());
1505 host_impl().active_tree()->SetViewportLayersFromIds(Layer::INVALID_ID
, 1, 1,
1507 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
1509 // Sanity check the scenario we just created.
1510 // The visible content rect for test_layer is actually 100x100, even though
1511 // its layout size is 50x50, positioned at 25x25.
1512 LayerImpl
* test_layer
=
1513 host_impl().active_tree()->root_layer()->children()[0];
1514 ASSERT_EQ(1u, RenderSurfaceLayerList().size());
1515 ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
1517 // Check whether the child layer fits into the root after scaled.
1518 EXPECT_EQ(gfx::Rect(test_layer
->bounds()), test_layer
->visible_layer_rect());
1520 // Hit checking for a point outside the layer should return a null pointer
1521 // (the root layer does not draw content, so it will not be tested either).
1522 gfx::PointF
test_point(76.f
, 76.f
);
1524 gfx::ScalePoint(test_point
, device_scale_factor
* page_scale_factor
);
1525 LayerImpl
* result_layer
=
1526 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1528 EXPECT_FALSE(result_layer
);
1530 // Hit checking for a point inside the layer, but outside the touch handler
1531 // region should return a null pointer.
1532 test_point
= gfx::Point(26, 26);
1534 gfx::ScalePoint(test_point
, device_scale_factor
* page_scale_factor
);
1536 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1538 EXPECT_FALSE(result_layer
);
1540 test_point
= gfx::Point(34, 34);
1542 gfx::ScalePoint(test_point
, device_scale_factor
* page_scale_factor
);
1544 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1546 EXPECT_FALSE(result_layer
);
1548 test_point
= gfx::Point(65, 65);
1550 gfx::ScalePoint(test_point
, device_scale_factor
* page_scale_factor
);
1552 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1554 EXPECT_FALSE(result_layer
);
1556 test_point
= gfx::Point(74, 74);
1558 gfx::ScalePoint(test_point
, device_scale_factor
* page_scale_factor
);
1560 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1562 EXPECT_FALSE(result_layer
);
1564 // Hit checking for a point inside the touch event handler region should
1565 // return the root layer.
1566 test_point
= gfx::Point(35, 35);
1568 gfx::ScalePoint(test_point
, device_scale_factor
* page_scale_factor
);
1570 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1572 ASSERT_TRUE(result_layer
);
1573 EXPECT_EQ(12345, result_layer
->id());
1575 test_point
= gfx::Point(64, 64);
1577 gfx::ScalePoint(test_point
, device_scale_factor
* page_scale_factor
);
1579 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1581 ASSERT_TRUE(result_layer
);
1582 EXPECT_EQ(12345, result_layer
->id());
1585 TEST_F(LayerTreeImplTest
, HitCheckingTouchHandlerRegionsForSimpleClippedLayer
) {
1586 // Test that hit-checking will only work for the visible portion of a layer,
1587 // and not the entire layer bounds. Here we just test the simple axis-aligned
1589 gfx::Transform identity_matrix
;
1590 gfx::Point3F transform_origin
;
1592 scoped_ptr
<LayerImpl
> root
= LayerImpl::Create(host_impl().active_tree(), 1);
1593 SetLayerPropertiesForTesting(root
.get(), identity_matrix
, transform_origin
,
1594 gfx::PointF(), gfx::Size(100, 100), true, false,
1597 scoped_ptr
<LayerImpl
> clipping_layer
=
1598 LayerImpl::Create(host_impl().active_tree(), 123);
1599 // this layer is positioned, and hit testing should correctly know where the
1600 // layer is located.
1601 gfx::PointF
position(25.f
, 25.f
);
1602 gfx::Size
bounds(50, 50);
1603 SetLayerPropertiesForTesting(clipping_layer
.get(), identity_matrix
,
1604 transform_origin
, position
, bounds
, true,
1606 clipping_layer
->SetMasksToBounds(true);
1608 scoped_ptr
<LayerImpl
> child
=
1609 LayerImpl::Create(host_impl().active_tree(), 456);
1610 Region
touch_handler_region(gfx::Rect(10, 10, 50, 50));
1611 position
= gfx::PointF(-50.f
, -50.f
);
1612 bounds
= gfx::Size(300, 300);
1613 SetLayerPropertiesForTesting(child
.get(), identity_matrix
, transform_origin
,
1614 position
, bounds
, true, false, false);
1615 child
->SetDrawsContent(true);
1616 child
->SetTouchEventHandlerRegion(touch_handler_region
);
1617 clipping_layer
->AddChild(child
.Pass());
1618 root
->AddChild(clipping_layer
.Pass());
1621 host_impl().SetViewportSize(root
->bounds());
1622 host_impl().active_tree()->SetRootLayer(root
.Pass());
1623 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
1625 // Sanity check the scenario we just created.
1626 ASSERT_EQ(1u, RenderSurfaceLayerList().size());
1627 ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
1628 ASSERT_EQ(456, root_layer()->render_surface()->layer_list().at(0)->id());
1630 // Hit checking for a point outside the layer should return a null pointer.
1631 // Despite the child layer being very large, it should be clipped to the root
1633 gfx::Point
test_point(24, 24);
1634 LayerImpl
* result_layer
=
1635 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1637 EXPECT_FALSE(result_layer
);
1639 // Hit checking for a point inside the layer, but outside the touch handler
1640 // region should return a null pointer.
1641 test_point
= gfx::Point(35, 35);
1643 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1645 EXPECT_FALSE(result_layer
);
1647 test_point
= gfx::Point(74, 74);
1649 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1651 EXPECT_FALSE(result_layer
);
1653 // Hit checking for a point inside the touch event handler region should
1654 // return the root layer.
1655 test_point
= gfx::Point(25, 25);
1657 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1659 ASSERT_TRUE(result_layer
);
1660 EXPECT_EQ(456, result_layer
->id());
1662 test_point
= gfx::Point(34, 34);
1664 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1666 ASSERT_TRUE(result_layer
);
1667 EXPECT_EQ(456, result_layer
->id());
1670 TEST_F(LayerTreeImplTest
, HitCheckingTouchHandlerOverlappingRegions
) {
1671 gfx::Transform identity_matrix
;
1672 gfx::Point3F transform_origin
;
1674 scoped_ptr
<LayerImpl
> root
= LayerImpl::Create(host_impl().active_tree(), 1);
1675 SetLayerPropertiesForTesting(root
.get(), identity_matrix
, transform_origin
,
1676 gfx::PointF(), gfx::Size(100, 100), true, false,
1679 scoped_ptr
<LayerImpl
> touch_layer
=
1680 LayerImpl::Create(host_impl().active_tree(), 123);
1681 // this layer is positioned, and hit testing should correctly know where the
1682 // layer is located.
1683 gfx::PointF position
;
1684 gfx::Size
bounds(50, 50);
1685 SetLayerPropertiesForTesting(touch_layer
.get(), identity_matrix
,
1686 transform_origin
, position
, bounds
, true,
1688 touch_layer
->SetDrawsContent(true);
1689 touch_layer
->SetTouchEventHandlerRegion(gfx::Rect(0, 0, 50, 50));
1690 root
->AddChild(touch_layer
.Pass());
1694 scoped_ptr
<LayerImpl
> notouch_layer
=
1695 LayerImpl::Create(host_impl().active_tree(), 1234);
1696 // this layer is positioned, and hit testing should correctly know where the
1697 // layer is located.
1698 gfx::PointF
position(0, 25);
1699 gfx::Size
bounds(50, 50);
1700 SetLayerPropertiesForTesting(notouch_layer
.get(), identity_matrix
,
1701 transform_origin
, position
, bounds
, true,
1703 notouch_layer
->SetDrawsContent(true);
1704 root
->AddChild(notouch_layer
.Pass());
1707 host_impl().SetViewportSize(root
->bounds());
1708 host_impl().active_tree()->SetRootLayer(root
.Pass());
1709 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
1711 // Sanity check the scenario we just created.
1712 ASSERT_EQ(1u, RenderSurfaceLayerList().size());
1713 ASSERT_EQ(2u, root_layer()->render_surface()->layer_list().size());
1714 ASSERT_EQ(123, root_layer()->render_surface()->layer_list().at(0)->id());
1715 ASSERT_EQ(1234, root_layer()->render_surface()->layer_list().at(1)->id());
1717 gfx::Point
test_point(35, 35);
1718 LayerImpl
* result_layer
=
1719 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1722 // We should have passed through the no-touch layer and found the layer
1724 EXPECT_TRUE(result_layer
);
1726 host_impl().active_tree()->LayerById(1234)->SetContentsOpaque(true);
1728 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1731 // Even with an opaque layer in the middle, we should still find the layer
1733 // the touch handler behind it (since we can't assume that opaque layers are
1734 // opaque to hit testing).
1735 EXPECT_TRUE(result_layer
);
1737 test_point
= gfx::Point(35, 15);
1739 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1741 ASSERT_TRUE(result_layer
);
1742 EXPECT_EQ(123, result_layer
->id());
1744 test_point
= gfx::Point(35, 65);
1746 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1748 EXPECT_FALSE(result_layer
);
1751 TEST_F(LayerTreeImplTest
, SelectionBoundsForSingleLayer
) {
1752 int root_layer_id
= 12345;
1753 scoped_ptr
<LayerImpl
> root
=
1754 LayerImpl::Create(host_impl().active_tree(), root_layer_id
);
1756 gfx::Transform identity_matrix
;
1757 gfx::Point3F transform_origin
;
1758 gfx::PointF position
;
1759 gfx::Size
bounds(100, 100);
1760 SetLayerPropertiesForTesting(root
.get(), identity_matrix
, transform_origin
,
1761 position
, bounds
, true, false, true);
1762 root
->SetDrawsContent(true);
1764 host_impl().SetViewportSize(root
->bounds());
1765 host_impl().active_tree()->SetRootLayer(root
.Pass());
1766 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
1768 // Sanity check the scenario we just created.
1769 ASSERT_EQ(1u, RenderSurfaceLayerList().size());
1770 ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
1772 LayerSelection input
;
1774 input
.start
.type
= SELECTION_BOUND_LEFT
;
1775 input
.start
.edge_top
= gfx::PointF(10, 10);
1776 input
.start
.edge_bottom
= gfx::PointF(10, 20);
1777 input
.start
.layer_id
= root_layer_id
;
1779 input
.end
.type
= SELECTION_BOUND_RIGHT
;
1780 input
.end
.edge_top
= gfx::PointF(50, 10);
1781 input
.end
.edge_bottom
= gfx::PointF(50, 30);
1782 input
.end
.layer_id
= root_layer_id
;
1784 ViewportSelection output
;
1786 // Empty input bounds should produce empty output bounds.
1787 host_impl().active_tree()->GetViewportSelection(&output
);
1788 EXPECT_EQ(ViewportSelectionBound(), output
.start
);
1789 EXPECT_EQ(ViewportSelectionBound(), output
.end
);
1791 // Selection bounds should produce distinct left and right bounds.
1792 host_impl().active_tree()->RegisterSelection(input
);
1793 host_impl().active_tree()->GetViewportSelection(&output
);
1794 EXPECT_EQ(input
.start
.type
, output
.start
.type
);
1795 EXPECT_EQ(input
.start
.edge_bottom
, output
.start
.edge_bottom
);
1796 EXPECT_EQ(input
.start
.edge_top
, output
.start
.edge_top
);
1797 EXPECT_TRUE(output
.start
.visible
);
1798 EXPECT_EQ(input
.end
.type
, output
.end
.type
);
1799 EXPECT_EQ(input
.end
.edge_bottom
, output
.end
.edge_bottom
);
1800 EXPECT_EQ(input
.end
.edge_top
, output
.end
.edge_top
);
1801 EXPECT_TRUE(output
.end
.visible
);
1802 EXPECT_EQ(input
.is_editable
, output
.is_editable
);
1803 EXPECT_EQ(input
.is_empty_text_form_control
,
1804 output
.is_empty_text_form_control
);
1806 // Insertion bounds should produce identical left and right bounds.
1807 LayerSelection insertion_input
;
1808 insertion_input
.start
.type
= SELECTION_BOUND_CENTER
;
1809 insertion_input
.start
.edge_top
= gfx::PointF(15, 10);
1810 insertion_input
.start
.edge_bottom
= gfx::PointF(15, 30);
1811 insertion_input
.start
.layer_id
= root_layer_id
;
1812 insertion_input
.is_editable
= true;
1813 insertion_input
.is_empty_text_form_control
= true;
1814 insertion_input
.end
= insertion_input
.start
;
1815 host_impl().active_tree()->RegisterSelection(insertion_input
);
1816 host_impl().active_tree()->GetViewportSelection(&output
);
1817 EXPECT_EQ(insertion_input
.start
.type
, output
.start
.type
);
1818 EXPECT_EQ(insertion_input
.start
.edge_bottom
, output
.start
.edge_bottom
);
1819 EXPECT_EQ(insertion_input
.start
.edge_top
, output
.start
.edge_top
);
1820 EXPECT_EQ(insertion_input
.is_editable
, output
.is_editable
);
1821 EXPECT_EQ(insertion_input
.is_empty_text_form_control
,
1822 output
.is_empty_text_form_control
);
1823 EXPECT_TRUE(output
.start
.visible
);
1824 EXPECT_EQ(output
.start
, output
.end
);
1827 TEST_F(LayerTreeImplTest
, SelectionBoundsForPartialOccludedLayers
) {
1828 int root_layer_id
= 12345;
1829 int clip_layer_id
= 1234;
1830 int clipped_layer_id
= 123;
1831 scoped_ptr
<LayerImpl
> root
=
1832 LayerImpl::Create(host_impl().active_tree(), root_layer_id
);
1833 root
->SetDrawsContent(true);
1835 gfx::Transform identity_matrix
;
1836 gfx::Point3F transform_origin
;
1837 gfx::PointF position
;
1838 gfx::Size
bounds(100, 100);
1839 SetLayerPropertiesForTesting(root
.get(), identity_matrix
, transform_origin
,
1840 position
, bounds
, true, false, true);
1842 gfx::Vector2dF
clipping_offset(10, 10);
1844 scoped_ptr
<LayerImpl
> clipping_layer
=
1845 LayerImpl::Create(host_impl().active_tree(), clip_layer_id
);
1846 // The clipping layer should occlude the right selection bound.
1847 gfx::PointF position
= gfx::PointF() + clipping_offset
;
1848 gfx::Size
bounds(50, 50);
1849 SetLayerPropertiesForTesting(clipping_layer
.get(), identity_matrix
,
1850 transform_origin
, position
, bounds
, true,
1852 clipping_layer
->SetMasksToBounds(true);
1854 scoped_ptr
<LayerImpl
> clipped_layer
=
1855 LayerImpl::Create(host_impl().active_tree(), clipped_layer_id
);
1856 position
= gfx::PointF();
1857 bounds
= gfx::Size(100, 100);
1858 SetLayerPropertiesForTesting(clipped_layer
.get(), identity_matrix
,
1859 transform_origin
, position
, bounds
, true,
1861 clipped_layer
->SetDrawsContent(true);
1862 clipping_layer
->AddChild(clipped_layer
.Pass());
1863 root
->AddChild(clipping_layer
.Pass());
1866 host_impl().SetViewportSize(root
->bounds());
1867 host_impl().active_tree()->SetRootLayer(root
.Pass());
1868 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
1870 // Sanity check the scenario we just created.
1871 ASSERT_EQ(1u, RenderSurfaceLayerList().size());
1873 LayerSelection input
;
1874 input
.start
.type
= SELECTION_BOUND_LEFT
;
1875 input
.start
.edge_top
= gfx::PointF(25, 10);
1876 input
.start
.edge_bottom
= gfx::PointF(25, 30);
1877 input
.start
.layer_id
= clipped_layer_id
;
1879 input
.end
.type
= SELECTION_BOUND_RIGHT
;
1880 input
.end
.edge_top
= gfx::PointF(75, 10);
1881 input
.end
.edge_bottom
= gfx::PointF(75, 30);
1882 input
.end
.layer_id
= clipped_layer_id
;
1883 host_impl().active_tree()->RegisterSelection(input
);
1885 // The left bound should be occluded by the clip layer.
1886 ViewportSelection output
;
1887 host_impl().active_tree()->GetViewportSelection(&output
);
1888 EXPECT_EQ(input
.start
.type
, output
.start
.type
);
1889 gfx::PointF expected_output_start_top
= input
.start
.edge_top
;
1890 gfx::PointF expected_output_edge_botom
= input
.start
.edge_bottom
;
1891 expected_output_start_top
.Offset(clipping_offset
.x(), clipping_offset
.y());
1892 expected_output_edge_botom
.Offset(clipping_offset
.x(), clipping_offset
.y());
1893 EXPECT_EQ(expected_output_start_top
, output
.start
.edge_top
);
1894 EXPECT_EQ(expected_output_edge_botom
, output
.start
.edge_bottom
);
1895 EXPECT_TRUE(output
.start
.visible
);
1896 EXPECT_EQ(input
.end
.type
, output
.end
.type
);
1897 gfx::PointF expected_output_end_top
= input
.end
.edge_top
;
1898 gfx::PointF expected_output_end_bottom
= input
.end
.edge_bottom
;
1899 expected_output_end_bottom
.Offset(clipping_offset
.x(), clipping_offset
.y());
1900 expected_output_end_top
.Offset(clipping_offset
.x(), clipping_offset
.y());
1901 EXPECT_EQ(expected_output_end_top
, output
.end
.edge_top
);
1902 EXPECT_EQ(expected_output_end_bottom
, output
.end
.edge_bottom
);
1903 EXPECT_FALSE(output
.end
.visible
);
1905 // Handles outside the viewport bounds should be marked invisible.
1906 input
.start
.edge_top
= gfx::PointF(-25, 0);
1907 input
.start
.edge_bottom
= gfx::PointF(-25, 20);
1908 host_impl().active_tree()->RegisterSelection(input
);
1909 host_impl().active_tree()->GetViewportSelection(&output
);
1910 EXPECT_FALSE(output
.start
.visible
);
1912 input
.start
.edge_top
= gfx::PointF(0, -25);
1913 input
.start
.edge_bottom
= gfx::PointF(0, -5);
1914 host_impl().active_tree()->RegisterSelection(input
);
1915 host_impl().active_tree()->GetViewportSelection(&output
);
1916 EXPECT_FALSE(output
.start
.visible
);
1918 // If the handle bottom is partially visible, the handle is marked visible.
1919 input
.start
.edge_top
= gfx::PointF(0, -20);
1920 input
.start
.edge_bottom
= gfx::PointF(0, 1);
1921 host_impl().active_tree()->RegisterSelection(input
);
1922 host_impl().active_tree()->GetViewportSelection(&output
);
1923 EXPECT_TRUE(output
.start
.visible
);
1926 TEST_F(LayerTreeImplTest
, SelectionBoundsForScaledLayers
) {
1927 int root_layer_id
= 1;
1928 int sub_layer_id
= 2;
1929 scoped_ptr
<LayerImpl
> root
=
1930 LayerImpl::Create(host_impl().active_tree(), root_layer_id
);
1931 root
->SetDrawsContent(true);
1933 gfx::Transform identity_matrix
;
1934 gfx::Point3F transform_origin
;
1935 gfx::PointF position
;
1936 gfx::Size
bounds(100, 100);
1937 SetLayerPropertiesForTesting(root
.get(), identity_matrix
, transform_origin
,
1938 position
, bounds
, true, false, true);
1940 gfx::Vector2dF
sub_layer_offset(10, 0);
1942 scoped_ptr
<LayerImpl
> sub_layer
=
1943 LayerImpl::Create(host_impl().active_tree(), sub_layer_id
);
1944 gfx::PointF position
= gfx::PointF() + sub_layer_offset
;
1945 gfx::Size
bounds(50, 50);
1946 SetLayerPropertiesForTesting(sub_layer
.get(), identity_matrix
,
1947 transform_origin
, position
, bounds
, true,
1949 sub_layer
->SetDrawsContent(true);
1950 root
->AddChild(sub_layer
.Pass());
1953 float device_scale_factor
= 3.f
;
1954 float page_scale_factor
= 5.f
;
1955 gfx::Size scaled_bounds_for_root
= gfx::ToCeiledSize(
1956 gfx::ScaleSize(root
->bounds(), device_scale_factor
* page_scale_factor
));
1957 host_impl().SetViewportSize(scaled_bounds_for_root
);
1959 host_impl().SetDeviceScaleFactor(device_scale_factor
);
1960 host_impl().active_tree()->PushPageScaleFromMainThread(
1961 page_scale_factor
, page_scale_factor
, page_scale_factor
);
1962 host_impl().active_tree()->SetPageScaleOnActiveTree(page_scale_factor
);
1963 host_impl().active_tree()->SetRootLayer(root
.Pass());
1964 host_impl().active_tree()->SetViewportLayersFromIds(Layer::INVALID_ID
, 1, 1,
1966 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
1968 // Sanity check the scenario we just created.
1969 ASSERT_EQ(1u, RenderSurfaceLayerList().size());
1971 LayerSelection input
;
1972 input
.start
.type
= SELECTION_BOUND_LEFT
;
1973 input
.start
.edge_top
= gfx::PointF(10, 10);
1974 input
.start
.edge_bottom
= gfx::PointF(10, 30);
1975 input
.start
.layer_id
= root_layer_id
;
1977 input
.end
.type
= SELECTION_BOUND_RIGHT
;
1978 input
.end
.edge_top
= gfx::PointF(0, 0);
1979 input
.end
.edge_bottom
= gfx::PointF(0, 20);
1980 input
.end
.layer_id
= sub_layer_id
;
1981 host_impl().active_tree()->RegisterSelection(input
);
1983 // The viewport bounds should be properly scaled by the page scale, but should
1984 // remain in DIP coordinates.
1985 ViewportSelection output
;
1986 host_impl().active_tree()->GetViewportSelection(&output
);
1987 EXPECT_EQ(input
.start
.type
, output
.start
.type
);
1988 gfx::PointF expected_output_start_top
= input
.start
.edge_top
;
1989 gfx::PointF expected_output_edge_bottom
= input
.start
.edge_bottom
;
1990 expected_output_start_top
.Scale(page_scale_factor
);
1991 expected_output_edge_bottom
.Scale(page_scale_factor
);
1992 EXPECT_EQ(expected_output_start_top
, output
.start
.edge_top
);
1993 EXPECT_EQ(expected_output_edge_bottom
, output
.start
.edge_bottom
);
1994 EXPECT_TRUE(output
.start
.visible
);
1995 EXPECT_EQ(input
.end
.type
, output
.end
.type
);
1997 gfx::PointF expected_output_end_top
= input
.end
.edge_top
;
1998 gfx::PointF expected_output_end_bottom
= input
.end
.edge_bottom
;
1999 expected_output_end_top
.Offset(sub_layer_offset
.x(), sub_layer_offset
.y());
2000 expected_output_end_bottom
.Offset(sub_layer_offset
.x(), sub_layer_offset
.y());
2001 expected_output_end_top
.Scale(page_scale_factor
);
2002 expected_output_end_bottom
.Scale(page_scale_factor
);
2003 EXPECT_EQ(expected_output_end_top
, output
.end
.edge_top
);
2004 EXPECT_EQ(expected_output_end_bottom
, output
.end
.edge_bottom
);
2005 EXPECT_TRUE(output
.end
.visible
);
2008 TEST_F(LayerTreeImplTest
, SelectionBoundsWithLargeTransforms
) {
2011 int grand_child_id
= 3;
2013 scoped_ptr
<LayerImpl
> root
=
2014 LayerImpl::Create(host_impl().active_tree(), root_id
);
2015 gfx::Size
bounds(100, 100);
2016 gfx::Transform identity_matrix
;
2017 gfx::Point3F transform_origin
;
2018 gfx::PointF position
;
2020 SetLayerPropertiesForTesting(root
.get(), identity_matrix
, transform_origin
,
2021 position
, bounds
, true, false, true);
2023 gfx::Transform large_transform
;
2024 large_transform
.Scale(SkDoubleToMScalar(1e37
), SkDoubleToMScalar(1e37
));
2025 large_transform
.RotateAboutYAxis(30);
2028 scoped_ptr
<LayerImpl
> child
=
2029 LayerImpl::Create(host_impl().active_tree(), child_id
);
2030 SetLayerPropertiesForTesting(child
.get(), large_transform
, transform_origin
,
2031 position
, bounds
, true, false, false);
2033 scoped_ptr
<LayerImpl
> grand_child
=
2034 LayerImpl::Create(host_impl().active_tree(), grand_child_id
);
2035 SetLayerPropertiesForTesting(grand_child
.get(), large_transform
,
2036 transform_origin
, position
, bounds
, true,
2038 grand_child
->SetDrawsContent(true);
2040 child
->AddChild(grand_child
.Pass());
2041 root
->AddChild(child
.Pass());
2044 host_impl().SetViewportSize(root
->bounds());
2045 host_impl().active_tree()->SetRootLayer(root
.Pass());
2046 host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
2048 LayerSelection input
;
2050 input
.start
.type
= SELECTION_BOUND_LEFT
;
2051 input
.start
.edge_top
= gfx::PointF(10, 10);
2052 input
.start
.edge_bottom
= gfx::PointF(10, 20);
2053 input
.start
.layer_id
= grand_child_id
;
2055 input
.end
.type
= SELECTION_BOUND_RIGHT
;
2056 input
.end
.edge_top
= gfx::PointF(50, 10);
2057 input
.end
.edge_bottom
= gfx::PointF(50, 30);
2058 input
.end
.layer_id
= grand_child_id
;
2060 host_impl().active_tree()->RegisterSelection(input
);
2062 ViewportSelection output
;
2063 host_impl().active_tree()->GetViewportSelection(&output
);
2065 // edge_bottom and edge_top aren't allowed to have NaNs, so the selection
2067 EXPECT_EQ(ViewportSelectionBound(), output
.start
);
2068 EXPECT_EQ(ViewportSelectionBound(), output
.end
);
2071 TEST_F(LayerTreeImplTest
, NumLayersTestOne
) {
2072 EXPECT_EQ(0u, host_impl().active_tree()->NumLayers());
2073 scoped_ptr
<LayerImpl
> root
= LayerImpl::Create(host_impl().active_tree(), 1);
2074 EXPECT_EQ(1u, host_impl().active_tree()->NumLayers());
2077 TEST_F(LayerTreeImplTest
, NumLayersSmallTree
) {
2078 EXPECT_EQ(0u, host_impl().active_tree()->NumLayers());
2079 scoped_ptr
<LayerImpl
> root
= LayerImpl::Create(host_impl().active_tree(), 1);
2080 root
->AddChild(LayerImpl::Create(host_impl().active_tree(), 2));
2081 root
->AddChild(LayerImpl::Create(host_impl().active_tree(), 3));
2082 root
->child_at(1)->AddChild(LayerImpl::Create(host_impl().active_tree(), 4));
2083 EXPECT_EQ(4u, host_impl().active_tree()->NumLayers());