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