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