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