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