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 "base/numerics/ranges.h"
8 #include "cc/layers/heads_up_display_layer_impl.h"
9 #include "cc/test/fake_layer_tree_host_impl.h"
10 #include "cc/test/fake_raster_source.h"
11 #include "cc/test/geometry_test_utils.h"
12 #include "cc/test/layer_tree_impl_test_base.h"
13 #include "cc/trees/clip_node.h"
14 #include "cc/trees/draw_property_utils.h"
15 #include "cc/trees/layer_tree_host_impl.h"
16 #include "testing/gmock/include/gmock/gmock.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18
19 namespace cc {
20 namespace {
21
GetVisibleSelectionEndPoints(const gfx::RectF & rect,const gfx::PointF & top,const gfx::PointF & bottom)22 std::pair<gfx::PointF, gfx::PointF> GetVisibleSelectionEndPoints(
23 const gfx::RectF& rect,
24 const gfx::PointF& top,
25 const gfx::PointF& bottom) {
26 gfx::PointF start(base::ClampToRange(top.x(), rect.x(), rect.right()),
27 base::ClampToRange(top.y(), rect.y(), rect.bottom()));
28 gfx::PointF end =
29 start + gfx::Vector2dF(bottom.x() - top.x(), bottom.y() - top.y());
30 return {start, end};
31 }
32
33 class LayerTreeImplTest : public LayerTreeImplTestBase, public testing::Test {
34 public:
35 LayerTreeImplTest() = default;
LayerTreeImplTest(const LayerTreeSettings & settings)36 explicit LayerTreeImplTest(const LayerTreeSettings& settings)
37 : LayerTreeImplTestBase(settings) {}
38
SetUp()39 void SetUp() override {
40 root_layer()->SetBounds(gfx::Size(100, 100));
41 UpdateDrawProperties(host_impl().active_tree());
42 }
43
host_impl() const44 FakeLayerTreeHostImpl& host_impl() const {
45 return *LayerTreeImplTestBase::host_impl();
46 }
47
GetRenderSurfaceList() const48 const RenderSurfaceList& GetRenderSurfaceList() const {
49 return host_impl().active_tree()->GetRenderSurfaceList();
50 }
51
HitTestSimpleTree(int top_sorting_context,int left_child_sorting_context,int right_child_sorting_context,float top_depth,float left_child_depth,float right_child_depth)52 LayerImpl* HitTestSimpleTree(int top_sorting_context,
53 int left_child_sorting_context,
54 int right_child_sorting_context,
55 float top_depth,
56 float left_child_depth,
57 float right_child_depth) {
58 top_ = AddLayer<LayerImpl>();
59 left_child_ = AddLayer<LayerImpl>();
60 right_child_ = AddLayer<LayerImpl>();
61
62 gfx::Size bounds(100, 100);
63 {
64 gfx::Transform translate_z;
65 translate_z.Translate3d(0, 0, top_depth);
66 top_->SetBounds(bounds);
67 top_->SetDrawsContent(true);
68 top_->SetHitTestable(true);
69
70 CopyProperties(root_layer(), top_);
71 auto& transform_node = CreateTransformNode(top_);
72 transform_node.local = translate_z;
73 transform_node.sorting_context_id = top_sorting_context;
74 }
75 {
76 gfx::Transform translate_z;
77 translate_z.Translate3d(0, 0, left_child_depth);
78 left_child_->SetBounds(bounds);
79 left_child_->SetDrawsContent(true);
80 left_child_->SetHitTestable(true);
81
82 CopyProperties(top_, left_child_);
83 auto& transform_node = CreateTransformNode(left_child_);
84 transform_node.local = translate_z;
85 transform_node.sorting_context_id = left_child_sorting_context;
86 transform_node.flattens_inherited_transform = false;
87 }
88 {
89 gfx::Transform translate_z;
90 translate_z.Translate3d(0, 0, right_child_depth);
91 right_child_->SetBounds(bounds);
92 right_child_->SetDrawsContent(true);
93 right_child_->SetHitTestable(true);
94
95 CopyProperties(top_, right_child_);
96 auto& transform_node = CreateTransformNode(right_child_);
97 transform_node.local = translate_z;
98 transform_node.sorting_context_id = right_child_sorting_context;
99 }
100
101 root_layer()->SetBounds(top_->bounds());
102 host_impl().active_tree()->SetDeviceViewportRect(gfx::Rect(top_->bounds()));
103
104 UpdateDrawProperties(host_impl().active_tree());
105 CHECK_EQ(1u, GetRenderSurfaceList().size());
106
107 gfx::PointF test_point = gfx::PointF(1.f, 1.f);
108 LayerImpl* result_layer =
109 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
110
111 CHECK(result_layer);
112 return result_layer;
113 }
114
115 // These layers are created by HitTestSimpleTree().
116 LayerImpl* top_ = nullptr;
117 LayerImpl* left_child_ = nullptr;
118 LayerImpl* right_child_ = nullptr;
119 };
120
TEST_F(LayerTreeImplTest,HitTestingForSingleLayer)121 TEST_F(LayerTreeImplTest, HitTestingForSingleLayer) {
122 gfx::Size bounds(100, 100);
123 LayerImpl* root = root_layer();
124 root->SetBounds(bounds);
125 root->SetDrawsContent(true);
126 root->SetHitTestable(true);
127
128 host_impl().active_tree()->SetDeviceViewportRect(gfx::Rect(root->bounds()));
129 UpdateDrawProperties(host_impl().active_tree());
130
131 // Sanity check the scenario we just created.
132 ASSERT_EQ(1u, GetRenderSurfaceList().size());
133 ASSERT_EQ(1, GetRenderSurface(root_layer())->num_contributors());
134
135 // Hit testing for a point outside the layer should return a null pointer.
136 gfx::PointF test_point(101.f, 101.f);
137 LayerImpl* result_layer =
138 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
139 EXPECT_FALSE(result_layer);
140
141 test_point = gfx::PointF(-1.f, -1.f);
142 result_layer =
143 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
144 EXPECT_FALSE(result_layer);
145
146 // Hit testing for a point inside should return the root layer.
147 test_point = gfx::PointF(1.f, 1.f);
148 result_layer =
149 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
150 ASSERT_TRUE(result_layer);
151 EXPECT_EQ(root, result_layer);
152
153 test_point = gfx::PointF(99.f, 99.f);
154 result_layer =
155 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
156 ASSERT_TRUE(result_layer);
157 EXPECT_EQ(root, result_layer);
158 }
159
TEST_F(LayerTreeImplTest,UpdateViewportAndHitTest)160 TEST_F(LayerTreeImplTest, UpdateViewportAndHitTest) {
161 // Ensures that the viewport rect is correctly updated by the clip tree.
162 gfx::Size bounds(100, 100);
163 LayerImpl* root = root_layer();
164 root->SetBounds(bounds);
165 root->SetDrawsContent(true);
166 root->SetHitTestable(true);
167
168 host_impl().active_tree()->SetDeviceViewportRect(gfx::Rect(root->bounds()));
169 UpdateDrawProperties(host_impl().active_tree());
170 EXPECT_EQ(
171 gfx::RectF(gfx::SizeF(bounds)),
172 host_impl().active_tree()->property_trees()->clip_tree.ViewportClip());
173 EXPECT_EQ(gfx::Rect(bounds), root->visible_layer_rect());
174
175 gfx::Size new_bounds(50, 50);
176 host_impl().active_tree()->SetDeviceViewportRect(gfx::Rect(new_bounds));
177 gfx::PointF test_point(51.f, 51.f);
178 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
179 EXPECT_EQ(
180 gfx::RectF(gfx::SizeF(new_bounds)),
181 host_impl().active_tree()->property_trees()->clip_tree.ViewportClip());
182 EXPECT_EQ(gfx::Rect(new_bounds), root->visible_layer_rect());
183 }
184
TEST_F(LayerTreeImplTest,HitTestingForSingleLayerAndHud)185 TEST_F(LayerTreeImplTest, HitTestingForSingleLayerAndHud) {
186 LayerImpl* root = root_layer();
187 root->SetBounds(gfx::Size(100, 100));
188 root->SetDrawsContent(true);
189 root->SetHitTestable(true);
190
191 // Create hud and add it as a child of root.
192 auto* hud = AddLayer<HeadsUpDisplayLayerImpl>();
193 hud->SetBounds(gfx::Size(200, 200));
194 hud->SetDrawsContent(true);
195 hud->SetHitTestable(true);
196
197 host_impl().active_tree()->SetDeviceViewportRect(gfx::Rect(hud->bounds()));
198 host_impl().active_tree()->set_hud_layer(hud);
199 CopyProperties(root, hud);
200 UpdateDrawProperties(host_impl().active_tree());
201
202 // Sanity check the scenario we just created.
203 ASSERT_EQ(1u, GetRenderSurfaceList().size());
204 ASSERT_EQ(2, GetRenderSurface(root_layer())->num_contributors());
205
206 // Hit testing for a point inside HUD, but outside root should return null
207 gfx::PointF test_point(101.f, 101.f);
208 LayerImpl* result_layer =
209 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
210 EXPECT_FALSE(result_layer);
211
212 test_point = gfx::PointF(-1.f, -1.f);
213 result_layer =
214 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
215 EXPECT_FALSE(result_layer);
216
217 // Hit testing for a point inside should return the root layer, never the HUD
218 // layer.
219 test_point = gfx::PointF(1.f, 1.f);
220 result_layer =
221 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
222 ASSERT_TRUE(result_layer);
223 EXPECT_EQ(root, result_layer);
224
225 test_point = gfx::PointF(99.f, 99.f);
226 result_layer =
227 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
228 ASSERT_TRUE(result_layer);
229 EXPECT_EQ(root, result_layer);
230 }
231
TEST_F(LayerTreeImplTest,HitTestingForUninvertibleTransform)232 TEST_F(LayerTreeImplTest, HitTestingForUninvertibleTransform) {
233 gfx::Transform uninvertible_transform;
234 uninvertible_transform.matrix().set(0, 0, 0.0);
235 uninvertible_transform.matrix().set(1, 1, 0.0);
236 uninvertible_transform.matrix().set(2, 2, 0.0);
237 uninvertible_transform.matrix().set(3, 3, 0.0);
238 ASSERT_FALSE(uninvertible_transform.IsInvertible());
239
240 LayerImpl* root = root_layer();
241
242 LayerImpl* layer = AddLayer<LayerImpl>();
243 layer->SetBounds(gfx::Size(100, 100));
244 layer->SetDrawsContent(true);
245 layer->SetHitTestable(true);
246 root->SetBounds(layer->bounds());
247 CopyProperties(root, layer);
248 CreateTransformNode(layer).local = uninvertible_transform;
249
250 host_impl().active_tree()->SetDeviceViewportRect(gfx::Rect(root->bounds()));
251 UpdateDrawProperties(host_impl().active_tree());
252 // Sanity check the scenario we just created.
253 ASSERT_EQ(1u, GetRenderSurfaceList().size());
254 ASSERT_FALSE(layer->ScreenSpaceTransform().IsInvertible());
255
256 // Hit testing any point should not hit the layer. If the invertible matrix is
257 // accidentally ignored and treated like an identity, then the hit testing
258 // will incorrectly hit the layer when it shouldn't.
259 gfx::PointF test_point(1.f, 1.f);
260 LayerImpl* result_layer =
261 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
262 EXPECT_FALSE(result_layer);
263
264 test_point = gfx::PointF(10.f, 10.f);
265 result_layer =
266 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
267 EXPECT_FALSE(result_layer);
268
269 test_point = gfx::PointF(10.f, 30.f);
270 result_layer =
271 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
272 EXPECT_FALSE(result_layer);
273
274 test_point = gfx::PointF(50.f, 50.f);
275 result_layer =
276 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
277 EXPECT_FALSE(result_layer);
278
279 test_point = gfx::PointF(67.f, 48.f);
280 result_layer =
281 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
282 EXPECT_FALSE(result_layer);
283
284 test_point = gfx::PointF(99.f, 99.f);
285 result_layer =
286 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
287 EXPECT_FALSE(result_layer);
288
289 test_point = gfx::PointF(-1.f, -1.f);
290 result_layer =
291 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
292 EXPECT_FALSE(result_layer);
293 }
294
TEST_F(LayerTreeImplTest,HitTestingForSinglePositionedLayer)295 TEST_F(LayerTreeImplTest, HitTestingForSinglePositionedLayer) {
296 // This layer is positioned, and hit testing should correctly know where the
297 // layer is located.
298 LayerImpl* test_layer = AddLayer<LayerImpl>();
299 test_layer->SetBounds(gfx::Size(100, 100));
300 test_layer->SetDrawsContent(true);
301 test_layer->SetHitTestable(true);
302 CopyProperties(root_layer(), test_layer);
303 test_layer->SetOffsetToTransformParent(gfx::Vector2dF(50.f, 50.f));
304
305 host_impl().active_tree()->SetDeviceViewportRect(
306 gfx::Rect(test_layer->bounds()));
307 UpdateDrawProperties(host_impl().active_tree());
308
309 // Sanity check the scenario we just created.
310 ASSERT_EQ(1u, GetRenderSurfaceList().size());
311 ASSERT_EQ(1, GetRenderSurface(test_layer)->num_contributors());
312
313 // Hit testing for a point outside the layer should return a null pointer.
314 gfx::PointF test_point(49.f, 49.f);
315 LayerImpl* result_layer =
316 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
317 EXPECT_FALSE(result_layer);
318
319 // Even though the layer exists at (101, 101), it should not be visible there
320 // since the root render surface would clamp it.
321 test_point = gfx::PointF(101.f, 101.f);
322 result_layer =
323 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
324 EXPECT_FALSE(result_layer);
325
326 // Hit testing for a point inside should return the root layer.
327 test_point = gfx::PointF(51.f, 51.f);
328 result_layer =
329 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
330 ASSERT_TRUE(result_layer);
331 EXPECT_EQ(test_layer, result_layer);
332
333 test_point = gfx::PointF(99.f, 99.f);
334 result_layer =
335 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
336 ASSERT_TRUE(result_layer);
337 EXPECT_EQ(test_layer, result_layer);
338 }
339
TEST_F(LayerTreeImplTest,HitTestingForSingleRotatedLayer)340 TEST_F(LayerTreeImplTest, HitTestingForSingleRotatedLayer) {
341 LayerImpl* root = root_layer();
342
343 gfx::Transform rotation45_degrees_about_center;
344 rotation45_degrees_about_center.Translate(50.0, 50.0);
345 rotation45_degrees_about_center.RotateAboutZAxis(45.0);
346 rotation45_degrees_about_center.Translate(-50.0, -50.0);
347
348 LayerImpl* layer = AddLayer<LayerImpl>();
349 layer->SetBounds(gfx::Size(100, 100));
350 layer->SetDrawsContent(true);
351 layer->SetHitTestable(true);
352 root->SetBounds(layer->bounds());
353 CopyProperties(root, layer);
354 CreateTransformNode(layer).local = rotation45_degrees_about_center;
355
356 host_impl().active_tree()->SetDeviceViewportRect(gfx::Rect(root->bounds()));
357 UpdateDrawProperties(host_impl().active_tree());
358
359 // Sanity check the scenario we just created.
360 ASSERT_EQ(1u, GetRenderSurfaceList().size());
361 ASSERT_EQ(1, GetRenderSurface(root_layer())->num_contributors());
362
363 // Hit testing for points outside the layer.
364 // These corners would have been inside the un-transformed layer, but they
365 // should not hit the correctly transformed layer.
366 gfx::PointF test_point(99.f, 99.f);
367 LayerImpl* result_layer =
368 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
369 EXPECT_FALSE(result_layer);
370
371 test_point = gfx::PointF(1.f, 1.f);
372 result_layer =
373 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
374 EXPECT_FALSE(result_layer);
375
376 // Hit testing for a point inside should return the root layer.
377 test_point = gfx::PointF(1.f, 50.f);
378 result_layer =
379 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
380 ASSERT_TRUE(result_layer);
381 EXPECT_EQ(layer, result_layer);
382
383 // Hit testing the corners that would overlap the unclipped layer, but are
384 // outside the clipped region.
385 test_point = gfx::PointF(50.f, -1.f);
386 result_layer =
387 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
388 ASSERT_FALSE(result_layer);
389
390 test_point = gfx::PointF(-1.f, 50.f);
391 result_layer =
392 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
393 ASSERT_FALSE(result_layer);
394 }
395
TEST_F(LayerTreeImplTest,HitTestingClipNodeDifferentTransformAndTargetIds)396 TEST_F(LayerTreeImplTest, HitTestingClipNodeDifferentTransformAndTargetIds) {
397 // Tests hit testing on a layer whose clip node has different transform and
398 // target id.
399 LayerImpl* root = root_layer();
400 root->SetBounds(gfx::Size(500, 500));
401
402 gfx::Transform translation;
403 translation.Translate(100, 100);
404 LayerImpl* render_surface = AddLayer<LayerImpl>();
405 render_surface->SetBounds(gfx::Size(100, 100));
406 CopyProperties(root, render_surface);
407 CreateTransformNode(render_surface).local = translation;
408 CreateEffectNode(render_surface).render_surface_reason =
409 RenderSurfaceReason::kTest;
410
411 gfx::Transform scale_matrix;
412 scale_matrix.Scale(2, 2);
413 LayerImpl* scale = AddLayer<LayerImpl>();
414 scale->SetBounds(gfx::Size(50, 50));
415 CopyProperties(render_surface, scale);
416 CreateTransformNode(scale).local = scale_matrix;
417
418 LayerImpl* clip = AddLayer<LayerImpl>();
419 clip->SetBounds(gfx::Size(25, 25));
420 CopyProperties(scale, clip);
421 CreateClipNode(clip);
422
423 LayerImpl* test = AddLayer<LayerImpl>();
424 test->SetBounds(gfx::Size(100, 100));
425 test->SetDrawsContent(true);
426 test->SetHitTestable(true);
427 CopyProperties(clip, test);
428
429 host_impl().active_tree()->SetDeviceViewportRect(gfx::Rect(root->bounds()));
430 UpdateDrawProperties(host_impl().active_tree());
431
432 gfx::PointF test_point(160.f, 160.f);
433 LayerImpl* result_layer =
434 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
435 EXPECT_FALSE(result_layer);
436
437 test_point = gfx::PointF(140.f, 140.f);
438 result_layer =
439 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
440 ASSERT_TRUE(result_layer);
441 EXPECT_EQ(test, result_layer);
442 }
443
TEST_F(LayerTreeImplTest,HitTestingSiblings)444 TEST_F(LayerTreeImplTest, HitTestingSiblings) {
445 // This tests hit testing when the test point hits only one of the siblings.
446 LayerImpl* root = root_layer();
447 root->SetBounds(gfx::Size(100, 100));
448
449 LayerImpl* child1 = AddLayer<LayerImpl>();
450 child1->SetBounds(gfx::Size(25, 25));
451 child1->SetDrawsContent(true);
452 child1->SetHitTestable(true);
453 CopyProperties(root, child1);
454 CreateClipNode(child1);
455
456 LayerImpl* child2 = AddLayer<LayerImpl>();
457 child2->SetBounds(gfx::Size(75, 75));
458 child2->SetDrawsContent(true);
459 child2->SetHitTestable(true);
460 CopyProperties(root, child2);
461 CreateClipNode(child2);
462
463 host_impl().active_tree()->SetDeviceViewportRect(gfx::Rect(root->bounds()));
464 UpdateDrawProperties(host_impl().active_tree());
465
466 gfx::PointF test_point(50.f, 50.f);
467 LayerImpl* result_layer =
468 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
469 ASSERT_TRUE(result_layer);
470 EXPECT_EQ(child2, result_layer);
471 }
472
TEST_F(LayerTreeImplTest,HitTestingForSinglePerspectiveLayer)473 TEST_F(LayerTreeImplTest, HitTestingForSinglePerspectiveLayer) {
474 LayerImpl* root = root_layer();
475
476 // perspective_projection_about_center * translation_by_z is designed so
477 // that the 100 x 100 layer becomes 50 x 50, and remains centered at (50,
478 // 50).
479 gfx::Transform perspective_projection_about_center;
480 perspective_projection_about_center.Translate(50.0, 50.0);
481 perspective_projection_about_center.ApplyPerspectiveDepth(1.0);
482 perspective_projection_about_center.Translate(-50.0, -50.0);
483 gfx::Transform translation_by_z;
484 translation_by_z.Translate3d(0.0, 0.0, -1.0);
485
486 LayerImpl* layer = AddLayer<LayerImpl>();
487 layer->SetBounds(gfx::Size(100, 100));
488 layer->SetDrawsContent(true);
489 layer->SetHitTestable(true);
490 root->SetBounds(layer->bounds());
491 CopyProperties(root, layer);
492 CreateTransformNode(layer).local =
493 (perspective_projection_about_center * translation_by_z);
494
495 host_impl().active_tree()->SetDeviceViewportRect(gfx::Rect(root->bounds()));
496 UpdateDrawProperties(host_impl().active_tree());
497
498 // Sanity check the scenario we just created.
499 ASSERT_EQ(1u, GetRenderSurfaceList().size());
500 ASSERT_EQ(1, GetRenderSurface(root_layer())->num_contributors());
501
502 // Hit testing for points outside the layer.
503 // These corners would have been inside the un-transformed layer, but they
504 // should not hit the correctly transformed layer.
505 gfx::PointF test_point(24.f, 24.f);
506 LayerImpl* result_layer =
507 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
508 EXPECT_FALSE(result_layer);
509
510 test_point = gfx::PointF(76.f, 76.f);
511 result_layer =
512 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
513 EXPECT_FALSE(result_layer);
514
515 // Hit testing for a point inside should return the root layer.
516 test_point = gfx::PointF(26.f, 26.f);
517 result_layer =
518 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
519 EXPECT_EQ(layer, result_layer);
520
521 test_point = gfx::PointF(74.f, 74.f);
522 result_layer =
523 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
524 EXPECT_EQ(layer, result_layer);
525 }
526
TEST_F(LayerTreeImplTest,HitTestingForSimpleClippedLayer)527 TEST_F(LayerTreeImplTest, HitTestingForSimpleClippedLayer) {
528 // Test that hit-testing will only work for the visible portion of a layer,
529 // and not the entire layer bounds. Here we just test the simple axis-aligned
530 // case.
531 LayerImpl* root = root_layer();
532 root->SetBounds(gfx::Size(100, 100));
533
534 LayerImpl* clipping_layer = AddLayer<LayerImpl>();
535 // this layer is positioned, and hit testing should correctly know where the
536 // layer is located.
537 clipping_layer->SetBounds(gfx::Size(50, 50));
538 CopyProperties(root, clipping_layer);
539 clipping_layer->SetOffsetToTransformParent(gfx::Vector2dF(25.f, 25.f));
540 CreateClipNode(clipping_layer);
541
542 LayerImpl* child = AddLayer<LayerImpl>();
543 child->SetBounds(gfx::Size(300, 300));
544 child->SetDrawsContent(true);
545 child->SetHitTestable(true);
546 CopyProperties(clipping_layer, child);
547 child->SetOffsetToTransformParent(gfx::Vector2dF(-50.f, -50.f));
548
549 host_impl().active_tree()->SetDeviceViewportRect(gfx::Rect(root->bounds()));
550 UpdateDrawProperties(host_impl().active_tree());
551
552 // Sanity check the scenario we just created.
553 ASSERT_EQ(1u, GetRenderSurfaceList().size());
554 ASSERT_EQ(1, GetRenderSurface(root_layer())->num_contributors());
555 EXPECT_TRUE(child->contributes_to_drawn_render_surface());
556
557 // Hit testing for a point outside the layer should return a null pointer.
558 // Despite the child layer being very large, it should be clipped to the root
559 // layer's bounds.
560 gfx::PointF test_point(24.f, 24.f);
561 LayerImpl* result_layer =
562 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
563 EXPECT_FALSE(result_layer);
564
565 // Even though the layer exists at (101, 101), it should not be visible there
566 // since the clipping_layer would clamp it.
567 test_point = gfx::PointF(76.f, 76.f);
568 result_layer =
569 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
570 EXPECT_FALSE(result_layer);
571
572 // Hit testing for a point inside should return the child layer.
573 test_point = gfx::PointF(26.f, 26.f);
574 result_layer =
575 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
576 EXPECT_EQ(child, result_layer);
577
578 test_point = gfx::PointF(74.f, 74.f);
579 result_layer =
580 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
581 EXPECT_EQ(child, result_layer);
582 }
583
TEST_F(LayerTreeImplTest,HitTestingForMultiClippedRotatedLayer)584 TEST_F(LayerTreeImplTest, HitTestingForMultiClippedRotatedLayer) {
585 // This test checks whether hit testing correctly avoids hit testing with
586 // multiple ancestors that clip in non axis-aligned ways. To pass this test,
587 // the hit testing algorithm needs to recognize that multiple parent layers
588 // may clip the layer, and should not actually hit those clipped areas.
589 //
590 // The child and grand_child layers are both initialized to clip the
591 // rotated_leaf. The child layer is rotated about the top-left corner, so that
592 // the root + child clips combined create a triangle. The rotated_leaf will
593 // only be visible where it overlaps this triangle.
594 //
595 LayerImpl* root = root_layer();
596
597 root->SetBounds(gfx::Size(100, 100));
598 CreateClipNode(root);
599
600 // Visible rects computed by combinig clips in target space and root space
601 // don't match because of rotation transforms. So, we skip
602 // verify_visible_rect_calculations.
603 LayerImpl* child = AddLayer<LayerImpl>();
604 LayerImpl* grand_child = AddLayer<LayerImpl>();
605 LayerImpl* rotated_leaf = AddLayer<LayerImpl>();
606
607 child->SetBounds(gfx::Size(80, 80));
608 CopyProperties(root, child);
609 child->SetOffsetToTransformParent(gfx::Vector2dF(10.f, 10.f));
610 CreateClipNode(child);
611
612 gfx::Transform rotation45_degrees_about_corner;
613 rotation45_degrees_about_corner.RotateAboutZAxis(45.0);
614
615 // This is positioned with respect to its parent which is already at
616 // position (10, 10).
617 // The size is to ensure it covers at least sqrt(2) * 100.
618 grand_child->SetBounds(gfx::Size(200, 200));
619 CopyProperties(child, grand_child);
620 CreateTransformNode(grand_child).local = rotation45_degrees_about_corner;
621 CreateClipNode(grand_child);
622
623 // Rotates about the center of the layer
624 gfx::Transform rotated_leaf_transform;
625 rotated_leaf_transform.Translate(
626 -10.0, -10.0); // cancel out the grand_parent's position
627 rotated_leaf_transform.RotateAboutZAxis(
628 -45.0); // cancel out the corner 45-degree rotation of the parent.
629 rotated_leaf_transform.Translate(50.0, 50.0);
630 rotated_leaf_transform.RotateAboutZAxis(45.0);
631 rotated_leaf_transform.Translate(-50.0, -50.0);
632 rotated_leaf->SetBounds(gfx::Size(100, 100));
633 rotated_leaf->SetDrawsContent(true);
634 rotated_leaf->SetHitTestable(true);
635 CopyProperties(grand_child, rotated_leaf);
636 CreateTransformNode(rotated_leaf).local = rotated_leaf_transform;
637
638 host_impl().active_tree()->SetDeviceViewportRect(gfx::Rect(root->bounds()));
639 UpdateDrawProperties(host_impl().active_tree());
640 // (11, 89) is close to the the bottom left corner within the clip, but it is
641 // not inside the layer.
642 gfx::PointF test_point(11.f, 89.f);
643 LayerImpl* result_layer =
644 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
645 EXPECT_FALSE(result_layer);
646
647 // Closer inwards from the bottom left will overlap the layer.
648 test_point = gfx::PointF(25.f, 75.f);
649 result_layer =
650 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
651 EXPECT_EQ(rotated_leaf, result_layer);
652
653 // (4, 50) is inside the unclipped layer, but that corner of the layer should
654 // be clipped away by the grandparent and should not get hit. If hit testing
655 // blindly uses visible content rect without considering how parent may clip
656 // the layer, then hit testing would accidentally think that the point
657 // successfully hits the layer.
658 test_point = gfx::PointF(4.f, 50.f);
659 result_layer =
660 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
661 EXPECT_FALSE(result_layer);
662
663 // (11, 50) is inside the layer and within the clipped area.
664 test_point = gfx::PointF(11.f, 50.f);
665 result_layer =
666 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
667 EXPECT_EQ(rotated_leaf, result_layer);
668
669 // Around the middle, just to the right and up, would have hit the layer
670 // except that that area should be clipped away by the parent.
671 test_point = gfx::PointF(51.f, 49.f);
672 result_layer =
673 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
674 EXPECT_FALSE(result_layer);
675
676 // Around the middle, just to the left and down, should successfully hit the
677 // layer.
678 test_point = gfx::PointF(49.f, 51.f);
679 result_layer =
680 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
681 EXPECT_EQ(rotated_leaf, result_layer);
682 }
683
TEST_F(LayerTreeImplTest,HitTestingForNonClippingIntermediateLayer)684 TEST_F(LayerTreeImplTest, HitTestingForNonClippingIntermediateLayer) {
685 // This test checks that hit testing code does not accidentally clip to layer
686 // bounds for a layer that actually does not clip.
687
688 LayerImpl* root = root_layer();
689 root->SetBounds(gfx::Size(100, 100));
690
691 LayerImpl* intermediate_layer = AddLayer<LayerImpl>();
692 intermediate_layer->SetBounds(gfx::Size(50, 50));
693 CopyProperties(root, intermediate_layer);
694 // this layer is positioned, and hit testing should correctly know where the
695 // layer is located.
696 intermediate_layer->SetOffsetToTransformParent(gfx::Vector2dF(10.f, 10.f));
697
698 // The child of the intermediate_layer is translated so that it does not
699 // overlap intermediate_layer at all. If child is incorrectly clipped, we
700 // would not be able to hit it successfully.
701 LayerImpl* child = AddLayer<LayerImpl>();
702 child->SetBounds(gfx::Size(20, 20));
703 child->SetDrawsContent(true);
704 child->SetHitTestable(true);
705 CopyProperties(intermediate_layer, child);
706 child->SetOffsetToTransformParent(gfx::Vector2dF(70.f, 70.f));
707
708 host_impl().active_tree()->SetDeviceViewportRect(gfx::Rect(root->bounds()));
709 UpdateDrawProperties(host_impl().active_tree());
710
711 // Sanity check the scenario we just created.
712 ASSERT_EQ(1u, GetRenderSurfaceList().size());
713 ASSERT_EQ(1, GetRenderSurface(root_layer())->num_contributors());
714 EXPECT_TRUE(child->contributes_to_drawn_render_surface());
715
716 // Hit testing for a point outside the layer should return a null pointer.
717 gfx::PointF test_point(69.f, 69.f);
718 LayerImpl* result_layer =
719 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
720 EXPECT_FALSE(result_layer);
721
722 test_point = gfx::PointF(91.f, 91.f);
723 result_layer =
724 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
725 EXPECT_FALSE(result_layer);
726
727 // Hit testing for a point inside should return the child layer.
728 test_point = gfx::PointF(71.f, 71.f);
729 result_layer =
730 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
731 EXPECT_EQ(child, result_layer);
732
733 test_point = gfx::PointF(89.f, 89.f);
734 result_layer =
735 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
736 EXPECT_EQ(child, result_layer);
737 }
738
TEST_F(LayerTreeImplTest,HitTestingForMultipleLayers)739 TEST_F(LayerTreeImplTest, HitTestingForMultipleLayers) {
740 LayerImpl* root = root_layer();
741 root->SetBounds(gfx::Size(100, 100));
742 root->SetDrawsContent(true);
743 root->SetHitTestable(true);
744
745 // child1 and child2 are initialized to overlap between x=50 and x=60.
746 // grand_child is set to overlap both child1 and child2 between y=50 and
747 // y=60. The expected stacking order is: (front) child2, (second)
748 // grand_child, (third) child1, and (back) the root layer behind all other
749 // layers.
750
751 LayerImpl* child1 = AddLayer<LayerImpl>();
752 child1->SetBounds(gfx::Size(50, 50));
753 child1->SetDrawsContent(true);
754 child1->SetHitTestable(true);
755 CopyProperties(root, child1);
756 child1->SetOffsetToTransformParent(gfx::Vector2dF(10.f, 10.f));
757
758 // Remember that grand_child is positioned with respect to its parent (i.e.
759 // child1). In screen space, the intended position is (10, 50), with size
760 // 100 x 50.
761 LayerImpl* grand_child1 = AddLayer<LayerImpl>();
762 grand_child1->SetBounds(gfx::Size(100, 50));
763 grand_child1->SetDrawsContent(true);
764 grand_child1->SetHitTestable(true);
765 CopyProperties(child1, grand_child1);
766 grand_child1->SetOffsetToTransformParent(
767 gfx::Vector2dF(0.f, 40.f) + child1->offset_to_transform_parent());
768
769 LayerImpl* child2 = AddLayer<LayerImpl>();
770 child2->SetBounds(gfx::Size(50, 50));
771 child2->SetDrawsContent(true);
772 child2->SetHitTestable(true);
773 CopyProperties(root, child2);
774 child2->SetOffsetToTransformParent(gfx::Vector2dF(50.f, 10.f));
775
776 host_impl().active_tree()->SetDeviceViewportRect(gfx::Rect(root->bounds()));
777 UpdateDrawProperties(host_impl().active_tree());
778
779 // Sanity check the scenario we just created.
780 ASSERT_TRUE(child1);
781 ASSERT_TRUE(child2);
782 ASSERT_TRUE(grand_child1);
783 ASSERT_EQ(1u, GetRenderSurfaceList().size());
784
785 RenderSurfaceImpl* root_render_surface = GetRenderSurface(root);
786 ASSERT_EQ(4, root_render_surface->num_contributors());
787 EXPECT_TRUE(root_layer()->contributes_to_drawn_render_surface());
788 EXPECT_TRUE(child1->contributes_to_drawn_render_surface());
789 EXPECT_TRUE(child2->contributes_to_drawn_render_surface());
790 EXPECT_TRUE(grand_child1->contributes_to_drawn_render_surface());
791
792 // Nothing overlaps the root at (1, 1), so hit testing there should find
793 // the root layer.
794 gfx::PointF test_point = gfx::PointF(1.f, 1.f);
795 LayerImpl* result_layer =
796 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
797 EXPECT_EQ(root, result_layer);
798
799 // At (15, 15), child1 and root are the only layers. child1 is expected to be
800 // on top.
801 test_point = gfx::PointF(15.f, 15.f);
802 result_layer =
803 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
804 EXPECT_EQ(child1, result_layer);
805
806 // At (51, 20), child1 and child2 overlap. child2 is expected to be on top.
807 test_point = gfx::PointF(51.f, 20.f);
808 result_layer =
809 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
810 EXPECT_EQ(child2, result_layer);
811
812 // At (80, 51), child2 and grand_child1 overlap. child2 is expected to be on
813 // top.
814 test_point = gfx::PointF(80.f, 51.f);
815 result_layer =
816 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
817 EXPECT_EQ(child2, result_layer);
818
819 // At (51, 51), all layers overlap each other. child2 is expected to be on top
820 // of all other layers.
821 test_point = gfx::PointF(51.f, 51.f);
822 result_layer =
823 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
824 EXPECT_EQ(child2, result_layer);
825
826 // At (20, 51), child1 and grand_child1 overlap. grand_child1 is expected to
827 // be on top.
828 test_point = gfx::PointF(20.f, 51.f);
829 result_layer =
830 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
831 EXPECT_EQ(grand_child1, result_layer);
832 }
833
TEST_F(LayerTreeImplTest,HitTestingSameSortingContextTied)834 TEST_F(LayerTreeImplTest, HitTestingSameSortingContextTied) {
835 LayerImpl* hit_layer = HitTestSimpleTree(/* sorting_contexts */ 10, 10, 10,
836 /* depths */ 0, 0, 0);
837 // 3 is the last in tree order, and so should be on top.
838 EXPECT_EQ(right_child_, hit_layer);
839 }
840
TEST_F(LayerTreeImplTest,HitTestingSameSortingContextChildWins)841 TEST_F(LayerTreeImplTest, HitTestingSameSortingContextChildWins) {
842 LayerImpl* hit_layer = HitTestSimpleTree(/* sorting_contexts */ 10, 10, 10,
843 /* depths */ 0, 1, 0);
844 EXPECT_EQ(left_child_, hit_layer);
845 }
846
TEST_F(LayerTreeImplTest,HitTestingWithoutSortingContext)847 TEST_F(LayerTreeImplTest, HitTestingWithoutSortingContext) {
848 LayerImpl* hit_layer = HitTestSimpleTree(/* sorting_contexts */ 0, 0, 0,
849 /* depths */ 0, 1, 0);
850 EXPECT_EQ(right_child_, hit_layer);
851 }
852
TEST_F(LayerTreeImplTest,HitTestingDistinctSortingContext)853 TEST_F(LayerTreeImplTest, HitTestingDistinctSortingContext) {
854 LayerImpl* hit_layer = HitTestSimpleTree(/* sorting_contexts */ 10, 11, 12,
855 /* depths */ 0, 1, 0);
856 EXPECT_EQ(right_child_, hit_layer);
857 }
858
TEST_F(LayerTreeImplTest,HitTestingSameSortingContextParentWins)859 TEST_F(LayerTreeImplTest, HitTestingSameSortingContextParentWins) {
860 LayerImpl* hit_layer = HitTestSimpleTree(/* sorting_contexts */ 10, 10, 10,
861 /* depths */ 0, -1, -1);
862 EXPECT_EQ(top_, hit_layer);
863 }
864
TEST_F(LayerTreeImplTest,HitTestingForMultipleLayersAtVaryingDepths)865 TEST_F(LayerTreeImplTest, HitTestingForMultipleLayersAtVaryingDepths) {
866 LayerImpl* root = root_layer();
867 root->SetBounds(gfx::Size(100, 100));
868 root->SetDrawsContent(true);
869 root->SetHitTestable(true);
870 GetTransformNode(root)->flattens_inherited_transform = false;
871 GetTransformNode(root)->sorting_context_id = 1;
872
873 // child 1 and child2 are initialized to overlap between x=50 and x=60.
874 // grand_child is set to overlap both child1 and child2 between y=50 and
875 // y=60. The expected stacking order is: (front) child2, (second)
876 // grand_child, (third) child1, and (back) the root layer behind all other
877 // layers.
878
879 LayerImpl* child1 = AddLayer<LayerImpl>();
880 child1->SetBounds(gfx::Size(50, 50));
881 child1->SetDrawsContent(true);
882 child1->SetHitTestable(true);
883 CopyProperties(root, child1);
884 auto& child1_transform_node = CreateTransformNode(child1);
885 child1_transform_node.post_translation = gfx::Vector2dF(10.f, 10.f);
886 child1_transform_node.flattens_inherited_transform = false;
887 child1_transform_node.sorting_context_id = 1;
888
889 // Remember that grand_child is positioned with respect to its parent (i.e.
890 // child1). In screen space, the intended position is (10, 50), with size
891 // 100 x 50.
892 LayerImpl* grand_child1 = AddLayer<LayerImpl>();
893 grand_child1->SetBounds(gfx::Size(100, 50));
894 grand_child1->SetDrawsContent(true);
895 grand_child1->SetHitTestable(true);
896 CopyProperties(child1, grand_child1);
897 auto& grand_child1_transform_node = CreateTransformNode(grand_child1);
898 grand_child1_transform_node.post_translation = gfx::Vector2dF(0.f, 40.f);
899 grand_child1_transform_node.flattens_inherited_transform = false;
900
901 LayerImpl* child2 = AddLayer<LayerImpl>();
902 child2->SetBounds(gfx::Size(50, 50));
903 gfx::Transform translate_z;
904 translate_z.Translate3d(0, 0, 10.f);
905 child2->SetDrawsContent(true);
906 child2->SetHitTestable(true);
907 CopyProperties(root, child2);
908 auto& child2_transform_node = CreateTransformNode(child2);
909 child2_transform_node.local = translate_z;
910 child2_transform_node.post_translation = gfx::Vector2dF(50.f, 10.f);
911 child2_transform_node.flattens_inherited_transform = false;
912 child2_transform_node.sorting_context_id = 1;
913
914 host_impl().active_tree()->SetDeviceViewportRect(gfx::Rect(root->bounds()));
915 UpdateDrawProperties(host_impl().active_tree());
916
917 // Sanity check the scenario we just created.
918 ASSERT_TRUE(child1);
919 ASSERT_TRUE(child2);
920 ASSERT_TRUE(grand_child1);
921 ASSERT_EQ(1u, GetRenderSurfaceList().size());
922
923 // Nothing overlaps the root_layer at (1, 1), so hit testing there should find
924 // the root layer.
925 gfx::PointF test_point = gfx::PointF(1.f, 1.f);
926 LayerImpl* result_layer =
927 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
928 EXPECT_EQ(root, result_layer);
929
930 // At (15, 15), child1 and root are the only layers. child1 is expected to be
931 // on top.
932 test_point = gfx::PointF(15.f, 15.f);
933 result_layer =
934 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
935 EXPECT_EQ(child1, result_layer);
936
937 // At (51, 20), child1 and child2 overlap. child2 is expected to be on top,
938 // as it was transformed to the foreground.
939 test_point = gfx::PointF(51.f, 20.f);
940 result_layer =
941 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
942 EXPECT_EQ(child2, result_layer);
943
944 // At (80, 51), child2 and grand_child1 overlap. child2 is expected to
945 // be on top, as it was transformed to the foreground.
946 test_point = gfx::PointF(80.f, 51.f);
947 result_layer =
948 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
949 EXPECT_EQ(child2, result_layer);
950
951 // At (51, 51), child1, child2 and grand_child1 overlap. child2 is expected to
952 // be on top, as it was transformed to the foreground.
953 test_point = gfx::PointF(51.f, 51.f);
954 result_layer =
955 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
956 EXPECT_EQ(child2, result_layer);
957
958 // At (20, 51), child1 and grand_child1 overlap. grand_child1 is expected to
959 // be on top, as it descends from child1.
960 test_point = gfx::PointF(20.f, 51.f);
961 result_layer =
962 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
963 EXPECT_EQ(grand_child1, result_layer);
964 }
965
TEST_F(LayerTreeImplTest,HitTestingRespectsClipParents)966 TEST_F(LayerTreeImplTest, HitTestingRespectsClipParents) {
967 LayerImpl* root = root_layer();
968 root->SetBounds(gfx::Size(100, 100));
969 root->SetDrawsContent(true);
970 root->SetHitTestable(true);
971
972 LayerImpl* child = AddLayer<LayerImpl>();
973 child->SetBounds(gfx::Size(1, 1));
974 child->SetDrawsContent(true);
975 child->SetHitTestable(true);
976 CopyProperties(root, child);
977 child->SetOffsetToTransformParent(gfx::Vector2dF(10.f, 10.f));
978 CreateClipNode(child);
979
980 LayerImpl* scroll_child = AddLayer<LayerImpl>();
981 scroll_child->SetBounds(gfx::Size(200, 200));
982 scroll_child->SetDrawsContent(true);
983 scroll_child->SetHitTestable(true);
984 CopyProperties(root, scroll_child);
985 scroll_child->SetClipTreeIndex(child->clip_tree_index());
986
987 LayerImpl* grand_child = AddLayer<LayerImpl>();
988 grand_child->SetBounds(gfx::Size(200, 200));
989 grand_child->SetDrawsContent(true);
990 grand_child->SetHitTestable(true);
991 CopyProperties(scroll_child, grand_child);
992 CreateEffectNode(grand_child).render_surface_reason =
993 RenderSurfaceReason::kTest;
994
995 host_impl().active_tree()->SetDeviceViewportRect(gfx::Rect(root->bounds()));
996 UpdateDrawProperties(host_impl().active_tree());
997
998 gfx::PointF test_point(12.f, 52.f);
999 LayerImpl* result_layer =
1000 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
1001 // The |test_point| should have been clipped away by |child|, so the only
1002 // thing that should be hit is |root|.
1003 EXPECT_EQ(root, result_layer);
1004 }
1005
TEST_F(LayerTreeImplTest,HitTestingForMultipleLayerLists)1006 TEST_F(LayerTreeImplTest, HitTestingForMultipleLayerLists) {
1007 //
1008 // The geometry is set up similarly to the previous case, but
1009 // all layers are forced to be render surfaces now.
1010 //
1011 LayerImpl* root = root_layer();
1012 root->SetBounds(gfx::Size(100, 100));
1013 root->SetDrawsContent(true);
1014 root->SetHitTestable(true);
1015
1016 // child 1 and child2 are initialized to overlap between x=50 and x=60.
1017 // grand_child is set to overlap both child1 and child2 between y=50 and
1018 // y=60. The expected stacking order is: (front) child2, (second)
1019 // grand_child, (third) child1, and (back) the root layer behind all other
1020 // layers.
1021
1022 LayerImpl* child1 = AddLayer<LayerImpl>();
1023 child1->SetBounds(gfx::Size(50, 50));
1024 child1->SetDrawsContent(true);
1025 child1->SetHitTestable(true);
1026 CopyProperties(root, child1);
1027 CreateTransformNode(child1).post_translation = gfx::Vector2dF(10.f, 10.f);
1028 CreateEffectNode(child1).render_surface_reason = RenderSurfaceReason::kTest;
1029
1030 // Remember that grand_child is positioned with respect to its parent (i.e.
1031 // child1). In screen space, the intended position is (10, 50), with size
1032 // 100 x 50.
1033 LayerImpl* grand_child1 = AddLayer<LayerImpl>();
1034 grand_child1->SetBounds(gfx::Size(100, 50));
1035 grand_child1->SetDrawsContent(true);
1036 grand_child1->SetHitTestable(true);
1037 CopyProperties(child1, grand_child1);
1038 CreateTransformNode(grand_child1).post_translation =
1039 gfx::Vector2dF(0.f, 40.f);
1040 CreateEffectNode(grand_child1).render_surface_reason =
1041 RenderSurfaceReason::kTest;
1042
1043 LayerImpl* child2 = AddLayer<LayerImpl>();
1044 child2->SetBounds(gfx::Size(50, 50));
1045 child2->SetDrawsContent(true);
1046 child2->SetHitTestable(true);
1047 CopyProperties(root, child2);
1048 CreateTransformNode(child2).post_translation = gfx::Vector2dF(50.f, 10.f);
1049 CreateEffectNode(child2).render_surface_reason = RenderSurfaceReason::kTest;
1050
1051 host_impl().active_tree()->SetDeviceViewportRect(gfx::Rect(root->bounds()));
1052 UpdateDrawProperties(host_impl().active_tree());
1053
1054 // Sanity check the scenario we just created.
1055 ASSERT_TRUE(child1);
1056 ASSERT_TRUE(child2);
1057 ASSERT_TRUE(grand_child1);
1058 ASSERT_TRUE(GetRenderSurface(child1));
1059 ASSERT_TRUE(GetRenderSurface(child2));
1060 ASSERT_TRUE(GetRenderSurface(grand_child1));
1061 ASSERT_EQ(4u, GetRenderSurfaceList().size());
1062 // The root surface has the root layer, and child1's and child2's render
1063 // surfaces.
1064 ASSERT_EQ(3, GetRenderSurface(root)->num_contributors());
1065 // The child1 surface has the child1 layer and grand_child1's render surface.
1066 ASSERT_EQ(2, GetRenderSurface(child1)->num_contributors());
1067 ASSERT_EQ(1, GetRenderSurface(child2)->num_contributors());
1068 ASSERT_EQ(1, GetRenderSurface(grand_child1)->num_contributors());
1069 EXPECT_TRUE(root_layer()->contributes_to_drawn_render_surface());
1070 EXPECT_TRUE(child1->contributes_to_drawn_render_surface());
1071 EXPECT_TRUE(grand_child1->contributes_to_drawn_render_surface());
1072 EXPECT_TRUE(child2->contributes_to_drawn_render_surface());
1073
1074 // Nothing overlaps the root at (1, 1), so hit testing there should find
1075 // the root layer.
1076 gfx::PointF test_point(1.f, 1.f);
1077 LayerImpl* result_layer =
1078 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
1079 EXPECT_EQ(root, result_layer);
1080
1081 // At (15, 15), child1 and root are the only layers. child1 is expected to be
1082 // on top.
1083 test_point = gfx::PointF(15.f, 15.f);
1084 result_layer =
1085 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
1086 EXPECT_EQ(child1, result_layer);
1087
1088 // At (51, 20), child1 and child2 overlap. child2 is expected to be on top.
1089 test_point = gfx::PointF(51.f, 20.f);
1090 result_layer =
1091 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
1092 EXPECT_EQ(child2, result_layer);
1093
1094 // At (80, 51), child2 and grand_child1 overlap. child2 is expected to be on
1095 // top.
1096 test_point = gfx::PointF(80.f, 51.f);
1097 result_layer =
1098 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
1099 EXPECT_EQ(child2, result_layer);
1100
1101 // At (51, 51), all layers overlap each other. child2 is expected to be on top
1102 // of all other layers.
1103 test_point = gfx::PointF(51.f, 51.f);
1104 result_layer =
1105 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
1106 EXPECT_EQ(child2, result_layer);
1107
1108 // At (20, 51), child1 and grand_child1 overlap. grand_child1 is expected to
1109 // be on top.
1110 test_point = gfx::PointF(20.f, 51.f);
1111 result_layer =
1112 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
1113 EXPECT_EQ(grand_child1, result_layer);
1114 }
1115
TEST_F(LayerTreeImplTest,HitCheckingTouchHandlerRegionsForSingleLayer)1116 TEST_F(LayerTreeImplTest, HitCheckingTouchHandlerRegionsForSingleLayer) {
1117 TouchActionRegion touch_action_region;
1118 touch_action_region.Union(TouchAction::kNone, gfx::Rect(10, 10, 50, 50));
1119
1120 LayerImpl* root = root_layer();
1121 root->SetBounds(gfx::Size(100, 100));
1122 root->SetDrawsContent(true);
1123 root->SetHitTestable(true);
1124
1125 host_impl().active_tree()->SetDeviceViewportRect(gfx::Rect(root->bounds()));
1126 UpdateDrawProperties(host_impl().active_tree());
1127
1128 // Sanity check the scenario we just created.
1129 ASSERT_EQ(1u, GetRenderSurfaceList().size());
1130 ASSERT_EQ(1, GetRenderSurface(root)->num_contributors());
1131
1132 // Hit checking for any point should return a null pointer for a layer without
1133 // any touch event handler regions.
1134 gfx::PointF test_point(11.f, 11.f);
1135 LayerImpl* result_layer =
1136 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1137 test_point);
1138 EXPECT_FALSE(result_layer);
1139
1140 root->SetTouchActionRegion(touch_action_region);
1141 // Hit checking for a point outside the layer should return a null pointer.
1142 test_point = gfx::PointF(101.f, 101.f);
1143 result_layer =
1144 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1145 test_point);
1146 EXPECT_FALSE(result_layer);
1147
1148 test_point = gfx::PointF(-1.f, -1.f);
1149 result_layer =
1150 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1151 test_point);
1152 EXPECT_FALSE(result_layer);
1153
1154 // Hit checking for a point inside the layer, but outside the touch handler
1155 // region should return a null pointer.
1156 test_point = gfx::PointF(1.f, 1.f);
1157 result_layer =
1158 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1159 test_point);
1160 EXPECT_FALSE(result_layer);
1161
1162 test_point = gfx::PointF(99.f, 99.f);
1163 result_layer =
1164 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1165 test_point);
1166 EXPECT_FALSE(result_layer);
1167
1168 // Hit checking for a point inside the touch event handler region should
1169 // return the root layer.
1170 test_point = gfx::PointF(11.f, 11.f);
1171 result_layer =
1172 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1173 test_point);
1174 EXPECT_EQ(root, result_layer);
1175
1176 test_point = gfx::PointF(59.f, 59.f);
1177 result_layer =
1178 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1179 test_point);
1180 EXPECT_EQ(root, result_layer);
1181 }
1182
TEST_F(LayerTreeImplTest,HitCheckingTouchHandlerRegionsForUninvertibleTransform)1183 TEST_F(LayerTreeImplTest,
1184 HitCheckingTouchHandlerRegionsForUninvertibleTransform) {
1185 LayerImpl* root = root_layer();
1186
1187 gfx::Transform uninvertible_transform;
1188 uninvertible_transform.matrix().set(0, 0, 0.0);
1189 uninvertible_transform.matrix().set(1, 1, 0.0);
1190 uninvertible_transform.matrix().set(2, 2, 0.0);
1191 uninvertible_transform.matrix().set(3, 3, 0.0);
1192 ASSERT_FALSE(uninvertible_transform.IsInvertible());
1193
1194 TouchActionRegion touch_action_region;
1195 touch_action_region.Union(TouchAction::kNone, gfx::Rect(10, 10, 50, 50));
1196
1197 LayerImpl* layer = AddLayer<LayerImpl>();
1198 layer->SetBounds(gfx::Size(100, 100));
1199 layer->SetDrawsContent(true);
1200 layer->SetHitTestable(true);
1201 layer->SetTouchActionRegion(touch_action_region);
1202 root->SetBounds(layer->bounds());
1203 CopyProperties(root, layer);
1204 CreateTransformNode(layer).local = uninvertible_transform;
1205
1206 host_impl().active_tree()->SetDeviceViewportRect(gfx::Rect(root->bounds()));
1207 UpdateDrawProperties(host_impl().active_tree());
1208
1209 // Sanity check the scenario we just created.
1210 ASSERT_EQ(1u, GetRenderSurfaceList().size());
1211 ASSERT_FALSE(layer->ScreenSpaceTransform().IsInvertible());
1212
1213 // Hit checking any point should not hit the touch handler region on the
1214 // layer. If the invertible matrix is accidentally ignored and treated like an
1215 // identity, then the hit testing will incorrectly hit the layer when it
1216 // shouldn't.
1217 gfx::PointF test_point(1.f, 1.f);
1218 LayerImpl* result_layer =
1219 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1220 test_point);
1221 EXPECT_FALSE(result_layer);
1222
1223 test_point = gfx::PointF(10.f, 10.f);
1224 result_layer =
1225 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1226 test_point);
1227 EXPECT_FALSE(result_layer);
1228
1229 test_point = gfx::PointF(10.f, 30.f);
1230 result_layer =
1231 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1232 test_point);
1233 EXPECT_FALSE(result_layer);
1234
1235 test_point = gfx::PointF(50.f, 50.f);
1236 result_layer =
1237 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1238 test_point);
1239 EXPECT_FALSE(result_layer);
1240
1241 test_point = gfx::PointF(67.f, 48.f);
1242 result_layer =
1243 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1244 test_point);
1245 EXPECT_FALSE(result_layer);
1246
1247 test_point = gfx::PointF(99.f, 99.f);
1248 result_layer =
1249 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1250 test_point);
1251 EXPECT_FALSE(result_layer);
1252
1253 test_point = gfx::PointF(-1.f, -1.f);
1254 result_layer =
1255 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1256 test_point);
1257 EXPECT_FALSE(result_layer);
1258 }
1259
TEST_F(LayerTreeImplTest,HitCheckingTouchHandlerRegionsForSinglePositionedLayer)1260 TEST_F(LayerTreeImplTest,
1261 HitCheckingTouchHandlerRegionsForSinglePositionedLayer) {
1262 TouchActionRegion touch_action_region;
1263 touch_action_region.Union(TouchAction::kNone, gfx::Rect(10, 10, 50, 50));
1264
1265 // This layer is positioned, and hit testing should correctly know where the
1266 // layer is located.
1267 LayerImpl* test_layer = AddLayer<LayerImpl>();
1268 test_layer->SetBounds(gfx::Size(100, 100));
1269 test_layer->SetDrawsContent(true);
1270 test_layer->SetHitTestable(true);
1271 test_layer->SetTouchActionRegion(touch_action_region);
1272 CopyProperties(root_layer(), test_layer);
1273 test_layer->SetOffsetToTransformParent(gfx::Vector2dF(50.f, 50.f));
1274
1275 host_impl().active_tree()->SetDeviceViewportRect(
1276 gfx::Rect(test_layer->bounds()));
1277 UpdateDrawProperties(host_impl().active_tree());
1278
1279 // Sanity check the scenario we just created.
1280 ASSERT_EQ(1u, GetRenderSurfaceList().size());
1281 ASSERT_EQ(1, GetRenderSurface(test_layer)->num_contributors());
1282
1283 // Hit checking for a point outside the layer should return a null pointer.
1284 gfx::PointF test_point(49.f, 49.f);
1285 LayerImpl* result_layer =
1286 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1287 test_point);
1288 EXPECT_FALSE(result_layer);
1289
1290 // Even though the layer has a touch handler region containing (101, 101), it
1291 // should not be visible there since the root render surface would clamp it.
1292 test_point = gfx::PointF(101.f, 101.f);
1293 result_layer =
1294 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1295 test_point);
1296 EXPECT_FALSE(result_layer);
1297
1298 // Hit checking for a point inside the layer, but outside the touch handler
1299 // region should return a null pointer.
1300 test_point = gfx::PointF(51.f, 51.f);
1301 result_layer =
1302 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1303 test_point);
1304 EXPECT_FALSE(result_layer);
1305
1306 // Hit checking for a point inside the touch event handler region should
1307 // return the test layer.
1308 test_point = gfx::PointF(61.f, 61.f);
1309 result_layer =
1310 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1311 test_point);
1312 EXPECT_EQ(test_layer, result_layer);
1313
1314 test_point = gfx::PointF(99.f, 99.f);
1315 result_layer =
1316 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1317 test_point);
1318 EXPECT_EQ(test_layer, result_layer);
1319 }
1320
TEST_F(LayerTreeImplTest,HitCheckingTouchHandlerRegionsForSingleLayerWithDeviceScale)1321 TEST_F(LayerTreeImplTest,
1322 HitCheckingTouchHandlerRegionsForSingleLayerWithDeviceScale) {
1323 // The layer's device_scale_factor and page_scale_factor should scale the
1324 // content rect and we should be able to hit the touch handler region by
1325 // scaling the points accordingly.
1326
1327 // Set the bounds of the root layer big enough to fit the child when scaled.
1328 LayerImpl* root = root_layer();
1329 root->SetBounds(gfx::Size(100, 100));
1330
1331 LayerImpl* page_scale_layer = AddLayer<LayerImpl>();
1332 CopyProperties(root, page_scale_layer);
1333 CreateTransformNode(page_scale_layer);
1334
1335 TouchActionRegion touch_action_region;
1336 touch_action_region.Union(TouchAction::kNone, gfx::Rect(10, 10, 30, 30));
1337 LayerImpl* test_layer = AddLayer<LayerImpl>();
1338 test_layer->SetBounds(gfx::Size(50, 50));
1339 test_layer->SetDrawsContent(true);
1340 test_layer->SetHitTestable(true);
1341 test_layer->SetTouchActionRegion(touch_action_region);
1342 CopyProperties(page_scale_layer, test_layer);
1343 test_layer->SetOffsetToTransformParent(gfx::Vector2dF(25.f, 25.f));
1344
1345 float device_scale_factor = 3.f;
1346 float page_scale_factor = 5.f;
1347 float max_page_scale_factor = 10.f;
1348 gfx::Size scaled_bounds_for_root = gfx::ScaleToCeiledSize(
1349 root->bounds(), device_scale_factor * page_scale_factor);
1350 host_impl().active_tree()->SetDeviceViewportRect(
1351 gfx::Rect(scaled_bounds_for_root));
1352
1353 host_impl().active_tree()->SetDeviceScaleFactor(device_scale_factor);
1354 LayerTreeImpl::ViewportPropertyIds viewport_property_ids;
1355 viewport_property_ids.page_scale_transform =
1356 page_scale_layer->transform_tree_index();
1357 host_impl().active_tree()->SetViewportPropertyIds(viewport_property_ids);
1358 host_impl().active_tree()->PushPageScaleFromMainThread(
1359 page_scale_factor, page_scale_factor, max_page_scale_factor);
1360 host_impl().active_tree()->SetPageScaleOnActiveTree(page_scale_factor);
1361 UpdateDrawProperties(host_impl().active_tree());
1362
1363 // Sanity check the scenario we just created.
1364 // The visible content rect for test_layer is actually 100x100, even though
1365 // its layout size is 50x50, positioned at 25x25.
1366 ASSERT_EQ(1u, GetRenderSurfaceList().size());
1367 ASSERT_EQ(1, GetRenderSurface(root)->num_contributors());
1368
1369 // Check whether the child layer fits into the root after scaled.
1370 EXPECT_EQ(gfx::Rect(test_layer->bounds()), test_layer->visible_layer_rect());
1371
1372 // Hit checking for a point outside the layer should return a null pointer
1373 // (the root layer does not have a touch event handler, so it will not be
1374 // tested either).
1375 gfx::PointF test_point(76.f, 76.f);
1376 test_point =
1377 gfx::ScalePoint(test_point, device_scale_factor * page_scale_factor);
1378 LayerImpl* result_layer =
1379 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1380 test_point);
1381 EXPECT_FALSE(result_layer);
1382
1383 // Hit checking for a point inside the layer, but outside the touch handler
1384 // region should return a null pointer.
1385 test_point = gfx::PointF(26.f, 26.f);
1386 test_point =
1387 gfx::ScalePoint(test_point, device_scale_factor * page_scale_factor);
1388 result_layer =
1389 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1390 test_point);
1391 EXPECT_FALSE(result_layer);
1392
1393 test_point = gfx::PointF(34.f, 34.f);
1394 test_point =
1395 gfx::ScalePoint(test_point, device_scale_factor * page_scale_factor);
1396 result_layer =
1397 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1398 test_point);
1399 EXPECT_FALSE(result_layer);
1400
1401 test_point = gfx::PointF(65.f, 65.f);
1402 test_point =
1403 gfx::ScalePoint(test_point, device_scale_factor * page_scale_factor);
1404 result_layer =
1405 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1406 test_point);
1407 EXPECT_FALSE(result_layer);
1408
1409 test_point = gfx::PointF(74.f, 74.f);
1410 test_point =
1411 gfx::ScalePoint(test_point, device_scale_factor * page_scale_factor);
1412 result_layer =
1413 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1414 test_point);
1415 EXPECT_FALSE(result_layer);
1416
1417 // Hit checking for a point inside the touch event handler region should
1418 // return the root layer.
1419 test_point = gfx::PointF(35.f, 35.f);
1420 test_point =
1421 gfx::ScalePoint(test_point, device_scale_factor * page_scale_factor);
1422 result_layer =
1423 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1424 test_point);
1425 EXPECT_EQ(test_layer, result_layer);
1426
1427 test_point = gfx::PointF(64.f, 64.f);
1428 test_point =
1429 gfx::ScalePoint(test_point, device_scale_factor * page_scale_factor);
1430 result_layer =
1431 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1432 test_point);
1433 EXPECT_EQ(test_layer, result_layer);
1434
1435 // Check update of page scale factor on the active tree when page scale layer
1436 // is also the root layer.
1437 page_scale_factor *= 1.5f;
1438 host_impl().active_tree()->SetPageScaleOnActiveTree(page_scale_factor);
1439 EXPECT_EQ(page_scale_layer->transform_tree_index(),
1440 host_impl().active_tree()->PageScaleTransformNode()->id);
1441
1442 test_point = gfx::PointF(35.f, 35.f);
1443 test_point =
1444 gfx::ScalePoint(test_point, device_scale_factor * page_scale_factor);
1445 result_layer =
1446 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1447 test_point);
1448 EXPECT_EQ(test_layer, result_layer);
1449
1450 test_point = gfx::PointF(64.f, 64.f);
1451 test_point =
1452 gfx::ScalePoint(test_point, device_scale_factor * page_scale_factor);
1453 result_layer =
1454 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1455 test_point);
1456 EXPECT_EQ(test_layer, result_layer);
1457 }
1458
TEST_F(LayerTreeImplTest,HitCheckingTouchHandlerRegionsForSimpleClippedLayer)1459 TEST_F(LayerTreeImplTest, HitCheckingTouchHandlerRegionsForSimpleClippedLayer) {
1460 // Test that hit-checking will only work for the visible portion of a layer,
1461 // and not the entire layer bounds. Here we just test the simple axis-aligned
1462 // case.
1463 LayerImpl* root = root_layer();
1464 root->SetBounds(gfx::Size(100, 100));
1465
1466 LayerImpl* clipping_layer = AddLayer<LayerImpl>();
1467 // this layer is positioned, and hit testing should correctly know where
1468 // the layer is located.
1469 clipping_layer->SetBounds(gfx::Size(50, 50));
1470 clipping_layer->SetOffsetToTransformParent(gfx::Vector2dF(25.f, 25.f));
1471 CopyProperties(root, clipping_layer);
1472 CreateClipNode(clipping_layer);
1473
1474 TouchActionRegion touch_action_region;
1475 touch_action_region.Union(TouchAction::kNone, gfx::Rect(10, 10, 50, 50));
1476
1477 LayerImpl* child = AddLayer<LayerImpl>();
1478 child->SetBounds(gfx::Size(300, 300));
1479 child->SetDrawsContent(true);
1480 child->SetHitTestable(true);
1481 child->SetTouchActionRegion(touch_action_region);
1482 CopyProperties(clipping_layer, child);
1483 child->SetOffsetToTransformParent(
1484 gfx::Vector2dF(-50.f, -50.f) +
1485 clipping_layer->offset_to_transform_parent());
1486
1487 host_impl().active_tree()->SetDeviceViewportRect(gfx::Rect(root->bounds()));
1488 UpdateDrawProperties(host_impl().active_tree());
1489
1490 // Sanity check the scenario we just created.
1491 ASSERT_EQ(1u, GetRenderSurfaceList().size());
1492 ASSERT_EQ(1, GetRenderSurface(root)->num_contributors());
1493 EXPECT_TRUE(child->contributes_to_drawn_render_surface());
1494
1495 // Hit checking for a point outside the layer should return a null pointer.
1496 // Despite the child layer being very large, it should be clipped to the root
1497 // layer's bounds.
1498 gfx::PointF test_point(24.f, 24.f);
1499 LayerImpl* result_layer =
1500 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1501 test_point);
1502 EXPECT_FALSE(result_layer);
1503
1504 // Hit checking for a point inside the layer, but outside the touch handler
1505 // region should return a null pointer.
1506 test_point = gfx::PointF(35.f, 35.f);
1507 result_layer =
1508 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1509 test_point);
1510 EXPECT_FALSE(result_layer);
1511
1512 test_point = gfx::PointF(74.f, 74.f);
1513 result_layer =
1514 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1515 test_point);
1516 EXPECT_FALSE(result_layer);
1517
1518 // Hit checking for a point inside the touch event handler region should
1519 // return the root layer.
1520 test_point = gfx::PointF(25.f, 25.f);
1521 result_layer =
1522 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1523 test_point);
1524 EXPECT_EQ(child, result_layer);
1525
1526 test_point = gfx::PointF(34.f, 34.f);
1527 result_layer =
1528 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1529 test_point);
1530 EXPECT_EQ(child, result_layer);
1531 }
1532
TEST_F(LayerTreeImplTest,HitCheckingTouchHandlerRegionsForClippedLayerWithDeviceScale)1533 TEST_F(LayerTreeImplTest,
1534 HitCheckingTouchHandlerRegionsForClippedLayerWithDeviceScale) {
1535 // The layer's device_scale_factor and page_scale_factor should scale the
1536 // content rect and we should be able to hit the touch handler region by
1537 // scaling the points accordingly.
1538
1539 // Set the bounds of the root layer big enough to fit the child when scaled.
1540 LayerImpl* root = root_layer();
1541 root->SetBounds(gfx::Size(100, 100));
1542
1543 LayerImpl* surface = AddLayer<LayerImpl>();
1544 surface->SetBounds(gfx::Size(100, 100));
1545 CopyProperties(root, surface);
1546 CreateEffectNode(surface).render_surface_reason = RenderSurfaceReason::kTest;
1547
1548 LayerImpl* clipping_layer = AddLayer<LayerImpl>();
1549 // This layer is positioned, and hit testing should correctly know where
1550 // the layer is located.
1551 clipping_layer->SetBounds(gfx::Size(50, 50));
1552 CopyProperties(surface, clipping_layer);
1553 clipping_layer->SetOffsetToTransformParent(gfx::Vector2dF(25.f, 20.f));
1554 CreateClipNode(clipping_layer);
1555
1556 TouchActionRegion touch_action_region;
1557 touch_action_region.Union(TouchAction::kNone, gfx::Rect(0, 0, 300, 300));
1558
1559 LayerImpl* child = AddLayer<LayerImpl>();
1560 child->SetBounds(gfx::Size(300, 300));
1561 child->SetDrawsContent(true);
1562 child->SetHitTestable(true);
1563 child->SetTouchActionRegion(touch_action_region);
1564 CopyProperties(clipping_layer, child);
1565 child->SetOffsetToTransformParent(
1566 gfx::Vector2dF(-50.f, -50.f) +
1567 clipping_layer->offset_to_transform_parent());
1568
1569 float device_scale_factor = 3.f;
1570 float page_scale_factor = 1.f;
1571 float max_page_scale_factor = 1.f;
1572 gfx::Size scaled_bounds_for_root = gfx::ScaleToCeiledSize(
1573 root->bounds(), device_scale_factor * page_scale_factor);
1574 host_impl().active_tree()->SetDeviceViewportRect(
1575 gfx::Rect(scaled_bounds_for_root));
1576
1577 host_impl().active_tree()->SetDeviceScaleFactor(device_scale_factor);
1578 host_impl().active_tree()->PushPageScaleFromMainThread(
1579 page_scale_factor, page_scale_factor, max_page_scale_factor);
1580 host_impl().active_tree()->SetPageScaleOnActiveTree(page_scale_factor);
1581 UpdateDrawProperties(host_impl().active_tree());
1582
1583 // Sanity check the scenario we just created.
1584 ASSERT_EQ(2u, GetRenderSurfaceList().size());
1585
1586 // Hit checking for a point outside the layer should return a null pointer.
1587 // Despite the child layer being very large, it should be clipped to the root
1588 // layer's bounds.
1589 gfx::PointF test_point(24.f, 24.f);
1590 test_point =
1591 gfx::ScalePoint(test_point, device_scale_factor * page_scale_factor);
1592 LayerImpl* result_layer =
1593 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1594 test_point);
1595 EXPECT_FALSE(result_layer);
1596
1597 // Hit checking for a point inside the touch event handler region should
1598 // return the child layer.
1599 test_point = gfx::PointF(25.f, 25.f);
1600 test_point =
1601 gfx::ScalePoint(test_point, device_scale_factor * page_scale_factor);
1602 result_layer =
1603 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1604 test_point);
1605 EXPECT_EQ(child, result_layer);
1606 }
1607
TEST_F(LayerTreeImplTest,HitCheckingTouchHandlerOverlappingRegions)1608 TEST_F(LayerTreeImplTest, HitCheckingTouchHandlerOverlappingRegions) {
1609 LayerImpl* root = root_layer();
1610 root->SetBounds(gfx::Size(100, 100));
1611
1612 LayerImpl* touch_layer = AddLayer<LayerImpl>();
1613 // this layer is positioned, and hit testing should correctly know where
1614 // the layer is located.
1615 touch_layer->SetBounds(gfx::Size(50, 50));
1616 touch_layer->SetDrawsContent(true);
1617 touch_layer->SetHitTestable(true);
1618 TouchActionRegion touch_action_region;
1619 touch_action_region.Union(TouchAction::kNone, gfx::Rect(0, 0, 50, 50));
1620 touch_layer->SetTouchActionRegion(touch_action_region);
1621 CopyProperties(root, touch_layer);
1622
1623 LayerImpl* notouch_layer = AddLayer<LayerImpl>();
1624 // this layer is positioned, and hit testing should correctly know where
1625 // the layer is located.
1626 notouch_layer->SetBounds(gfx::Size(50, 50));
1627 notouch_layer->SetDrawsContent(true);
1628 notouch_layer->SetHitTestable(true);
1629 CopyProperties(root, notouch_layer);
1630 notouch_layer->SetOffsetToTransformParent(gfx::Vector2dF(0, 25));
1631
1632 host_impl().active_tree()->SetDeviceViewportRect(gfx::Rect(root->bounds()));
1633 UpdateDrawProperties(host_impl().active_tree());
1634
1635 // Sanity check the scenario we just created.
1636 ASSERT_EQ(1u, GetRenderSurfaceList().size());
1637 ASSERT_EQ(2, GetRenderSurface(root)->num_contributors());
1638 EXPECT_TRUE(touch_layer->contributes_to_drawn_render_surface());
1639 EXPECT_TRUE(notouch_layer->contributes_to_drawn_render_surface());
1640
1641 gfx::PointF test_point(35.f, 35.f);
1642 LayerImpl* result_layer =
1643 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1644 test_point);
1645
1646 // We should have passed through the no-touch layer and found the layer
1647 // behind it.
1648 EXPECT_TRUE(result_layer);
1649
1650 notouch_layer->SetContentsOpaque(true);
1651 result_layer =
1652 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1653 test_point);
1654
1655 // Even with an opaque layer in the middle, we should still find the layer
1656 // with
1657 // the touch handler behind it (since we can't assume that opaque layers are
1658 // opaque to hit testing).
1659 EXPECT_TRUE(result_layer);
1660
1661 test_point = gfx::PointF(35.f, 15.f);
1662 result_layer =
1663 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1664 test_point);
1665 EXPECT_EQ(touch_layer, result_layer);
1666
1667 test_point = gfx::PointF(35.f, 65.f);
1668 result_layer =
1669 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1670 test_point);
1671 EXPECT_FALSE(result_layer);
1672 }
1673
TEST_F(LayerTreeImplTest,HitTestingTouchHandlerRegionsForLayerThatIsNotDrawn)1674 TEST_F(LayerTreeImplTest, HitTestingTouchHandlerRegionsForLayerThatIsNotDrawn) {
1675 LayerImpl* root = root_layer();
1676 root->SetBounds(gfx::Size(100, 100));
1677 root->SetDrawsContent(true);
1678 root->SetHitTestable(true);
1679
1680 TouchActionRegion touch_action_region;
1681 touch_action_region.Union(TouchAction::kNone, gfx::Rect(10, 10, 30, 30));
1682 LayerImpl* test_layer = AddLayer<LayerImpl>();
1683 test_layer->SetBounds(gfx::Size(50, 50));
1684 test_layer->SetDrawsContent(false);
1685 test_layer->SetHitTestable(false);
1686 test_layer->SetTouchActionRegion(touch_action_region);
1687 CopyProperties(root, test_layer);
1688
1689 host_impl().active_tree()->SetDeviceViewportRect(gfx::Rect(root->bounds()));
1690 UpdateDrawProperties(host_impl().active_tree());
1691
1692 // As test_layer doesn't draw content, it shouldn't contribute content to the
1693 // root surface.
1694 ASSERT_EQ(1u, GetRenderSurfaceList().size());
1695 EXPECT_FALSE(test_layer->contributes_to_drawn_render_surface());
1696
1697 // Hit testing for a point outside the test layer should return null pointer.
1698 // We also implicitly check that the updated screen space transform of a layer
1699 // that is not in drawn render surface layer list (test_layer) is used during
1700 // hit testing (becuase the point is inside test_layer with respect to the old
1701 // screen space transform).
1702 gfx::PointF test_point(24.f, 24.f);
1703 test_layer->SetOffsetToTransformParent(gfx::Vector2dF(25.f, 25.f));
1704 gfx::Transform expected_screen_space_transform;
1705 expected_screen_space_transform.Translate(25.f, 25.f);
1706
1707 UpdateDrawProperties(host_impl().active_tree());
1708 LayerImpl* result_layer =
1709 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1710 test_point);
1711 EXPECT_FALSE(result_layer);
1712 EXPECT_FALSE(test_layer->contributes_to_drawn_render_surface());
1713 EXPECT_TRANSFORMATION_MATRIX_EQ(
1714 expected_screen_space_transform,
1715 draw_property_utils::ScreenSpaceTransform(
1716 test_layer,
1717 host_impl().active_tree()->property_trees()->transform_tree));
1718
1719 // We change the position of the test layer such that the test point is now
1720 // inside the test_layer.
1721 test_layer->SetOffsetToTransformParent(gfx::Vector2dF(10.f, 10.f));
1722 test_layer->NoteLayerPropertyChanged();
1723 expected_screen_space_transform.MakeIdentity();
1724 expected_screen_space_transform.Translate(10.f, 10.f);
1725
1726 UpdateDrawProperties(host_impl().active_tree());
1727 result_layer =
1728 host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
1729 test_point);
1730 ASSERT_TRUE(result_layer);
1731 ASSERT_EQ(test_layer, result_layer);
1732 EXPECT_FALSE(result_layer->contributes_to_drawn_render_surface());
1733 EXPECT_TRANSFORMATION_MATRIX_EQ(
1734 expected_screen_space_transform,
1735 draw_property_utils::ScreenSpaceTransform(
1736 test_layer,
1737 host_impl().active_tree()->property_trees()->transform_tree));
1738 }
1739
TEST_F(LayerTreeImplTest,SelectionBoundsForSingleLayer)1740 TEST_F(LayerTreeImplTest, SelectionBoundsForSingleLayer) {
1741 LayerImpl* root = root_layer();
1742 root->SetBounds(gfx::Size(100, 100));
1743 root->SetDrawsContent(true);
1744
1745 host_impl().active_tree()->SetDeviceViewportRect(gfx::Rect(root->bounds()));
1746 UpdateDrawProperties(host_impl().active_tree());
1747
1748 // Sanity check the scenario we just created.
1749 ASSERT_EQ(1u, GetRenderSurfaceList().size());
1750 ASSERT_EQ(1, GetRenderSurface(root)->num_contributors());
1751
1752 LayerSelection input;
1753
1754 input.start.type = gfx::SelectionBound::LEFT;
1755 input.start.edge_start = gfx::Point(10, 10);
1756 input.start.edge_end = gfx::Point(10, 20);
1757 input.start.layer_id = root->id();
1758
1759 input.end.type = gfx::SelectionBound::RIGHT;
1760 input.end.edge_start = gfx::Point(50, 10);
1761 input.end.edge_end = gfx::Point(50, 30);
1762 input.end.layer_id = root->id();
1763
1764 viz::Selection<gfx::SelectionBound> output;
1765
1766 // Empty input bounds should produce empty output bounds.
1767 host_impl().active_tree()->GetViewportSelection(&output);
1768 EXPECT_EQ(gfx::SelectionBound(), output.start);
1769 EXPECT_EQ(gfx::SelectionBound(), output.end);
1770
1771 // Selection bounds should produce distinct left and right bounds.
1772 host_impl().active_tree()->RegisterSelection(input);
1773 host_impl().active_tree()->GetViewportSelection(&output);
1774 EXPECT_EQ(input.start.type, output.start.type());
1775 EXPECT_EQ(gfx::PointF(input.start.edge_end), output.start.edge_end());
1776 EXPECT_EQ(gfx::PointF(input.start.edge_start), output.start.edge_start());
1777 EXPECT_EQ(gfx::PointF(input.start.edge_end), output.start.visible_edge_end());
1778 EXPECT_EQ(gfx::PointF(input.start.edge_start),
1779 output.start.visible_edge_start());
1780 EXPECT_TRUE(output.start.visible());
1781 EXPECT_EQ(input.end.type, output.end.type());
1782 EXPECT_EQ(gfx::PointF(input.end.edge_end), output.end.edge_end());
1783 EXPECT_EQ(gfx::PointF(input.end.edge_start), output.end.edge_start());
1784 EXPECT_EQ(gfx::PointF(input.end.edge_end), output.end.visible_edge_end());
1785 EXPECT_EQ(gfx::PointF(input.end.edge_start), output.end.visible_edge_start());
1786 EXPECT_TRUE(output.end.visible());
1787
1788 // Selection bounds should produce distinct left and right bounds for the
1789 // vertical text.
1790 input.start.type = gfx::SelectionBound::LEFT;
1791 input.start.edge_start = gfx::Point(20, 10);
1792 input.start.edge_end = gfx::Point(10, 10);
1793 input.start.layer_id = root->id();
1794
1795 input.end.type = gfx::SelectionBound::RIGHT;
1796 input.end.edge_start = gfx::Point(30, 20);
1797 input.end.edge_end = gfx::Point(50, 20);
1798 input.end.layer_id = root->id();
1799
1800 host_impl().active_tree()->RegisterSelection(input);
1801 host_impl().active_tree()->GetViewportSelection(&output);
1802 EXPECT_EQ(input.start.type, output.start.type());
1803 EXPECT_EQ(gfx::PointF(input.start.edge_end), output.start.edge_end());
1804 EXPECT_EQ(gfx::PointF(input.start.edge_start), output.start.edge_start());
1805 EXPECT_EQ(gfx::PointF(input.start.edge_end), output.start.visible_edge_end());
1806 EXPECT_EQ(gfx::PointF(input.start.edge_start),
1807 output.start.visible_edge_start());
1808 EXPECT_TRUE(output.start.visible());
1809 EXPECT_EQ(input.end.type, output.end.type());
1810 EXPECT_EQ(gfx::PointF(input.end.edge_end), output.end.edge_end());
1811 EXPECT_EQ(gfx::PointF(input.end.edge_start), output.end.edge_start());
1812 EXPECT_EQ(gfx::PointF(input.end.edge_end), output.end.visible_edge_end());
1813 EXPECT_EQ(gfx::PointF(input.end.edge_start), output.end.visible_edge_start());
1814 EXPECT_TRUE(output.end.visible());
1815
1816 // Insertion bounds should produce identical left and right bounds.
1817 LayerSelection insertion_input;
1818 insertion_input.start.type = gfx::SelectionBound::CENTER;
1819 insertion_input.start.edge_start = gfx::Point(15, 10);
1820 insertion_input.start.edge_end = gfx::Point(15, 30);
1821 insertion_input.start.layer_id = root->id();
1822 insertion_input.end = insertion_input.start;
1823 host_impl().active_tree()->RegisterSelection(insertion_input);
1824 host_impl().active_tree()->GetViewportSelection(&output);
1825 EXPECT_EQ(insertion_input.start.type, output.start.type());
1826 EXPECT_EQ(gfx::PointF(insertion_input.start.edge_end),
1827 output.start.edge_end());
1828 EXPECT_EQ(gfx::PointF(insertion_input.start.edge_start),
1829 output.start.edge_start());
1830 EXPECT_EQ(gfx::PointF(insertion_input.start.edge_end),
1831 output.start.visible_edge_end());
1832 EXPECT_EQ(gfx::PointF(insertion_input.start.edge_start),
1833 output.start.visible_edge_start());
1834 EXPECT_TRUE(output.start.visible());
1835 EXPECT_EQ(output.start, output.end);
1836 }
1837
TEST_F(LayerTreeImplTest,SelectionBoundsForPartialOccludedLayers)1838 TEST_F(LayerTreeImplTest, SelectionBoundsForPartialOccludedLayers) {
1839 LayerImpl* root = root_layer();
1840 root->SetDrawsContent(true);
1841 root->SetBounds(gfx::Size(100, 100));
1842
1843 gfx::Vector2dF clipping_offset(10, 10);
1844
1845 LayerImpl* clipping_layer = AddLayer<LayerImpl>();
1846 // The clipping layer should occlude the right selection bound.
1847 clipping_layer->SetBounds(gfx::Size(50, 50));
1848 CopyProperties(root, clipping_layer);
1849 clipping_layer->SetOffsetToTransformParent(clipping_offset);
1850 CreateClipNode(clipping_layer);
1851
1852 LayerImpl* clipped_layer = AddLayer<LayerImpl>();
1853 clipped_layer->SetBounds(gfx::Size(100, 100));
1854 clipped_layer->SetDrawsContent(true);
1855 CopyProperties(clipping_layer, clipped_layer);
1856 clipped_layer->SetOffsetToTransformParent(
1857 clipping_layer->offset_to_transform_parent());
1858
1859 host_impl().active_tree()->SetDeviceViewportRect(gfx::Rect(root->bounds()));
1860 UpdateDrawProperties(host_impl().active_tree());
1861
1862 // Sanity check the scenario we just created.
1863 ASSERT_EQ(1u, GetRenderSurfaceList().size());
1864
1865 LayerSelection input;
1866 input.start.type = gfx::SelectionBound::LEFT;
1867 input.start.edge_start = gfx::Point(25, 10);
1868 input.start.edge_end = gfx::Point(25, 30);
1869 input.start.layer_id = clipped_layer->id();
1870
1871 input.end.type = gfx::SelectionBound::RIGHT;
1872 input.end.edge_start = gfx::Point(75, 10);
1873 input.end.edge_end = gfx::Point(75, 30);
1874 input.end.layer_id = clipped_layer->id();
1875 host_impl().active_tree()->RegisterSelection(input);
1876
1877 // The right bound should be occluded by the clip layer.
1878 viz::Selection<gfx::SelectionBound> output;
1879 host_impl().active_tree()->GetViewportSelection(&output);
1880 EXPECT_EQ(input.start.type, output.start.type());
1881 auto expected_output_edge_start = gfx::PointF(input.start.edge_start);
1882 auto expected_output_edge_end = gfx::PointF(input.start.edge_end);
1883 expected_output_edge_start.Offset(clipping_offset.x(), clipping_offset.y());
1884 expected_output_edge_end.Offset(clipping_offset.x(), clipping_offset.y());
1885 EXPECT_EQ(expected_output_edge_start, output.start.edge_start());
1886 EXPECT_EQ(expected_output_edge_end, output.start.edge_end());
1887 EXPECT_EQ(expected_output_edge_start, output.start.visible_edge_start());
1888 EXPECT_EQ(expected_output_edge_end, output.start.visible_edge_end());
1889 EXPECT_TRUE(output.start.visible());
1890 EXPECT_EQ(input.end.type, output.end.type());
1891 expected_output_edge_start = gfx::PointF(input.end.edge_start);
1892 expected_output_edge_end = gfx::PointF(input.end.edge_end);
1893 expected_output_edge_end.Offset(clipping_offset.x(), clipping_offset.y());
1894 expected_output_edge_start.Offset(clipping_offset.x(), clipping_offset.y());
1895 EXPECT_EQ(expected_output_edge_start, output.end.edge_start());
1896 EXPECT_EQ(expected_output_edge_end, output.end.edge_end());
1897
1898 gfx::RectF visible_layer_rect(clipped_layer->visible_layer_rect());
1899 gfx::PointF expected_output_visible_edge_start;
1900 gfx::PointF expected_output_visible_edge_end;
1901 std::tie(expected_output_visible_edge_start,
1902 expected_output_visible_edge_end) =
1903 GetVisibleSelectionEndPoints(visible_layer_rect,
1904 gfx::PointF(input.end.edge_start),
1905 gfx::PointF(input.end.edge_end));
1906 expected_output_visible_edge_start.Offset(clipping_offset.x(),
1907 clipping_offset.y());
1908 expected_output_visible_edge_end.Offset(clipping_offset.x(),
1909 clipping_offset.y());
1910
1911 EXPECT_EQ(expected_output_visible_edge_start,
1912 output.end.visible_edge_start());
1913 EXPECT_EQ(expected_output_visible_edge_end, output.end.visible_edge_end());
1914 EXPECT_FALSE(output.end.visible());
1915
1916 // The right bound should be occluded by the clip layer for the vertical text.
1917 input.start.type = gfx::SelectionBound::LEFT;
1918 input.start.edge_start = gfx::Point(25, 10);
1919 input.start.edge_end = gfx::Point(15, 10);
1920 input.start.layer_id = clipped_layer->id();
1921
1922 input.end.type = gfx::SelectionBound::RIGHT;
1923 input.end.edge_start = gfx::Point(75, 30);
1924 input.end.edge_end = gfx::Point(85, 30);
1925 input.end.layer_id = clipped_layer->id();
1926 host_impl().active_tree()->RegisterSelection(input);
1927
1928 host_impl().active_tree()->GetViewportSelection(&output);
1929 EXPECT_EQ(input.start.type, output.start.type());
1930 expected_output_edge_start = gfx::PointF(input.start.edge_start);
1931 expected_output_edge_end = gfx::PointF(input.start.edge_end);
1932 expected_output_edge_start.Offset(clipping_offset.x(), clipping_offset.y());
1933 expected_output_edge_end.Offset(clipping_offset.x(), clipping_offset.y());
1934 EXPECT_EQ(expected_output_edge_start, output.start.edge_start());
1935 EXPECT_EQ(expected_output_edge_end, output.start.edge_end());
1936 EXPECT_EQ(expected_output_edge_start, output.start.visible_edge_start());
1937 EXPECT_EQ(expected_output_edge_end, output.start.visible_edge_end());
1938 EXPECT_TRUE(output.start.visible());
1939 EXPECT_EQ(input.end.type, output.end.type());
1940 expected_output_edge_start = gfx::PointF(input.end.edge_start);
1941 expected_output_edge_end = gfx::PointF(input.end.edge_end);
1942 expected_output_edge_end.Offset(clipping_offset.x(), clipping_offset.y());
1943 expected_output_edge_start.Offset(clipping_offset.x(), clipping_offset.y());
1944 EXPECT_EQ(expected_output_edge_start, output.end.edge_start());
1945 EXPECT_EQ(expected_output_edge_end, output.end.edge_end());
1946
1947 std::tie(expected_output_visible_edge_start,
1948 expected_output_visible_edge_end) =
1949 GetVisibleSelectionEndPoints(visible_layer_rect,
1950 gfx::PointF(input.end.edge_start),
1951 gfx::PointF(input.end.edge_end));
1952 expected_output_visible_edge_start.Offset(clipping_offset.x(),
1953 clipping_offset.y());
1954 expected_output_visible_edge_end.Offset(clipping_offset.x(),
1955 clipping_offset.y());
1956
1957 EXPECT_EQ(expected_output_visible_edge_start,
1958 output.end.visible_edge_start());
1959 EXPECT_EQ(expected_output_visible_edge_end, output.end.visible_edge_end());
1960 EXPECT_FALSE(output.end.visible());
1961
1962 // Handles outside the viewport bounds should be marked invisible.
1963 input.start.edge_start = gfx::Point(-25, 0);
1964 input.start.edge_end = gfx::Point(-25, 20);
1965 host_impl().active_tree()->RegisterSelection(input);
1966 host_impl().active_tree()->GetViewportSelection(&output);
1967 EXPECT_FALSE(output.start.visible());
1968
1969 input.start.edge_start = gfx::Point(0, -25);
1970 input.start.edge_end = gfx::Point(0, -5);
1971 host_impl().active_tree()->RegisterSelection(input);
1972 host_impl().active_tree()->GetViewportSelection(&output);
1973 EXPECT_FALSE(output.start.visible());
1974
1975 // If the handle end is partially visible, the handle is marked visible.
1976 input.start.edge_start = gfx::Point(0, -20);
1977 input.start.edge_end = gfx::Point(0, 1);
1978 host_impl().active_tree()->RegisterSelection(input);
1979 host_impl().active_tree()->GetViewportSelection(&output);
1980 EXPECT_TRUE(output.start.visible());
1981 }
1982
TEST_F(LayerTreeImplTest,SelectionBoundsForScaledLayers)1983 TEST_F(LayerTreeImplTest, SelectionBoundsForScaledLayers) {
1984 LayerImpl* root = root_layer();
1985 root->SetDrawsContent(true);
1986 root->SetBounds(gfx::Size(100, 100));
1987
1988 LayerImpl* page_scale_layer = AddLayer<LayerImpl>();
1989 page_scale_layer->SetBounds(gfx::Size(50, 50));
1990 CopyProperties(root, page_scale_layer);
1991 CreateTransformNode(page_scale_layer);
1992
1993 gfx::Vector2dF sub_layer_offset(10, 0);
1994 LayerImpl* sub_layer = AddLayer<LayerImpl>();
1995 sub_layer->SetBounds(gfx::Size(50, 50));
1996 sub_layer->SetDrawsContent(true);
1997 CopyProperties(page_scale_layer, sub_layer);
1998 sub_layer->SetOffsetToTransformParent(sub_layer_offset);
1999
2000 UpdateDrawProperties(host_impl().active_tree());
2001
2002 float device_scale_factor = 3.f;
2003 float page_scale_factor = 5.f;
2004 gfx::Size scaled_bounds_for_root = gfx::ScaleToCeiledSize(
2005 root->bounds(), device_scale_factor * page_scale_factor);
2006
2007 LayerTreeImpl::ViewportPropertyIds viewport_property_ids;
2008 viewport_property_ids.page_scale_transform =
2009 page_scale_layer->transform_tree_index();
2010 host_impl().active_tree()->SetViewportPropertyIds(viewport_property_ids);
2011 host_impl().active_tree()->SetDeviceViewportRect(
2012 gfx::Rect(scaled_bounds_for_root));
2013 host_impl().active_tree()->SetDeviceScaleFactor(device_scale_factor);
2014 host_impl().active_tree()->SetPageScaleOnActiveTree(page_scale_factor);
2015
2016 host_impl().active_tree()->PushPageScaleFromMainThread(
2017 page_scale_factor, page_scale_factor, page_scale_factor);
2018 host_impl().active_tree()->SetPageScaleOnActiveTree(page_scale_factor);
2019 UpdateDrawProperties(host_impl().active_tree());
2020
2021 // Sanity check the scenario we just created.
2022 ASSERT_EQ(1u, GetRenderSurfaceList().size());
2023
2024 LayerSelection input;
2025 input.start.type = gfx::SelectionBound::LEFT;
2026 input.start.edge_start = gfx::Point(10, 10);
2027 input.start.edge_end = gfx::Point(10, 30);
2028 input.start.layer_id = page_scale_layer->id();
2029
2030 input.end.type = gfx::SelectionBound::RIGHT;
2031 input.end.edge_start = gfx::Point(0, 0);
2032 input.end.edge_end = gfx::Point(0, 20);
2033 input.end.layer_id = sub_layer->id();
2034 host_impl().active_tree()->RegisterSelection(input);
2035
2036 // The viewport bounds should be properly scaled by the page scale, but should
2037 // remain in DIP coordinates.
2038 viz::Selection<gfx::SelectionBound> output;
2039 host_impl().active_tree()->GetViewportSelection(&output);
2040 EXPECT_EQ(input.start.type, output.start.type());
2041 auto expected_output_edge_start = gfx::PointF(input.start.edge_start);
2042 auto expected_output_edge_end = gfx::PointF(input.start.edge_end);
2043 expected_output_edge_start.Scale(page_scale_factor);
2044 expected_output_edge_end.Scale(page_scale_factor);
2045 EXPECT_EQ(expected_output_edge_start, output.start.edge_start());
2046 EXPECT_EQ(expected_output_edge_end, output.start.edge_end());
2047 EXPECT_EQ(expected_output_edge_start, output.start.visible_edge_start());
2048 EXPECT_EQ(expected_output_edge_end, output.start.visible_edge_end());
2049 EXPECT_TRUE(output.start.visible());
2050 EXPECT_EQ(input.end.type, output.end.type());
2051
2052 expected_output_edge_start = gfx::PointF(input.end.edge_start);
2053 expected_output_edge_end = gfx::PointF(input.end.edge_end);
2054 expected_output_edge_start.Offset(sub_layer_offset.x(), sub_layer_offset.y());
2055 expected_output_edge_end.Offset(sub_layer_offset.x(), sub_layer_offset.y());
2056 expected_output_edge_start.Scale(page_scale_factor);
2057 expected_output_edge_end.Scale(page_scale_factor);
2058 EXPECT_EQ(expected_output_edge_start, output.end.edge_start());
2059 EXPECT_EQ(expected_output_edge_end, output.end.edge_end());
2060 EXPECT_EQ(expected_output_edge_start, output.end.visible_edge_start());
2061 EXPECT_EQ(expected_output_edge_end, output.end.visible_edge_end());
2062 EXPECT_TRUE(output.end.visible());
2063 }
2064
TEST_F(LayerTreeImplTest,SelectionBoundsForDSFEnabled)2065 TEST_F(LayerTreeImplTest, SelectionBoundsForDSFEnabled) {
2066 LayerImpl* root = root_layer();
2067 root->SetDrawsContent(true);
2068 root->SetBounds(gfx::Size(100, 100));
2069 host_impl().active_tree()->SetDeviceViewportRect(gfx::Rect(root->bounds()));
2070
2071 gfx::Vector2dF sub_layer_offset(10, 0);
2072 LayerImpl* sub_layer = AddLayer<LayerImpl>();
2073 sub_layer->SetBounds(gfx::Size(50, 50));
2074 sub_layer->SetDrawsContent(true);
2075 CopyProperties(root, sub_layer);
2076 sub_layer->SetOffsetToTransformParent(sub_layer_offset);
2077
2078 UpdateDrawProperties(host_impl().active_tree());
2079
2080 float device_scale_factor = 3.f;
2081 float painted_device_scale_factor = 5.f;
2082 host_impl().active_tree()->SetDeviceScaleFactor(device_scale_factor);
2083 host_impl().active_tree()->set_painted_device_scale_factor(
2084 painted_device_scale_factor);
2085
2086 LayerSelection input;
2087 input.start.type = gfx::SelectionBound::LEFT;
2088 input.start.edge_start = gfx::Point(10, 10);
2089 input.start.edge_end = gfx::Point(10, 30);
2090 input.start.layer_id = root->id();
2091
2092 input.end.type = gfx::SelectionBound::RIGHT;
2093 input.end.edge_start = gfx::Point(0, 0);
2094 input.end.edge_end = gfx::Point(0, 20);
2095 input.end.layer_id = sub_layer->id();
2096 host_impl().active_tree()->RegisterSelection(input);
2097
2098 // The viewport bounds should be properly scaled by the page scale, but should
2099 // remain in DIP coordinates.
2100 viz::Selection<gfx::SelectionBound> output;
2101 host_impl().active_tree()->GetViewportSelection(&output);
2102 EXPECT_EQ(input.start.type, output.start.type());
2103 auto expected_output_edge_start = gfx::PointF(input.start.edge_start);
2104 auto expected_output_edge_end = gfx::PointF(input.start.edge_end);
2105 expected_output_edge_start.Scale(
2106 1.f / (device_scale_factor * painted_device_scale_factor));
2107 expected_output_edge_end.Scale(
2108 1.f / (device_scale_factor * painted_device_scale_factor));
2109 EXPECT_EQ(expected_output_edge_start, output.start.edge_start());
2110 EXPECT_EQ(expected_output_edge_end, output.start.edge_end());
2111 EXPECT_EQ(expected_output_edge_start, output.start.visible_edge_start());
2112 EXPECT_EQ(expected_output_edge_end, output.start.visible_edge_end());
2113 EXPECT_TRUE(output.start.visible());
2114 EXPECT_EQ(input.end.type, output.end.type());
2115
2116 expected_output_edge_start = gfx::PointF(input.end.edge_start);
2117 expected_output_edge_end = gfx::PointF(input.end.edge_end);
2118 expected_output_edge_start.Offset(sub_layer_offset.x(), sub_layer_offset.y());
2119 expected_output_edge_end.Offset(sub_layer_offset.x(), sub_layer_offset.y());
2120 expected_output_edge_start.Scale(
2121 1.f / (device_scale_factor * painted_device_scale_factor));
2122 expected_output_edge_end.Scale(
2123 1.f / (device_scale_factor * painted_device_scale_factor));
2124 EXPECT_EQ(expected_output_edge_start, output.end.edge_start());
2125 EXPECT_EQ(expected_output_edge_end, output.end.edge_end());
2126 EXPECT_EQ(expected_output_edge_start, output.end.visible_edge_start());
2127 EXPECT_EQ(expected_output_edge_end, output.end.visible_edge_end());
2128 EXPECT_TRUE(output.end.visible());
2129 }
2130
TEST_F(LayerTreeImplTest,SelectionBoundsWithLargeTransforms)2131 TEST_F(LayerTreeImplTest, SelectionBoundsWithLargeTransforms) {
2132 LayerImpl* root = root_layer();
2133 root->SetBounds(gfx::Size(100, 100));
2134
2135 gfx::Transform large_transform;
2136 large_transform.Scale(SkDoubleToScalar(1e37), SkDoubleToScalar(1e37));
2137 large_transform.RotateAboutYAxis(30);
2138
2139 LayerImpl* child = AddLayer<LayerImpl>();
2140 child->SetBounds(gfx::Size(100, 100));
2141 CopyProperties(root, child);
2142 CreateTransformNode(child).local = large_transform;
2143
2144 LayerImpl* grand_child = AddLayer<LayerImpl>();
2145 grand_child->SetBounds(gfx::Size(100, 100));
2146 grand_child->SetDrawsContent(true);
2147 CopyProperties(child, grand_child);
2148 CreateTransformNode(grand_child).local = large_transform;
2149
2150 host_impl().active_tree()->SetDeviceViewportRect(gfx::Rect(root->bounds()));
2151 UpdateDrawProperties(host_impl().active_tree());
2152
2153 LayerSelection input;
2154
2155 input.start.type = gfx::SelectionBound::LEFT;
2156 input.start.edge_start = gfx::Point(10, 10);
2157 input.start.edge_end = gfx::Point(10, 20);
2158 input.start.layer_id = grand_child->id();
2159
2160 input.end.type = gfx::SelectionBound::RIGHT;
2161 input.end.edge_start = gfx::Point(50, 10);
2162 input.end.edge_end = gfx::Point(50, 30);
2163 input.end.layer_id = grand_child->id();
2164
2165 host_impl().active_tree()->RegisterSelection(input);
2166
2167 viz::Selection<gfx::SelectionBound> output;
2168 host_impl().active_tree()->GetViewportSelection(&output);
2169
2170 // edge_end and edge_start aren't allowed to have NaNs, so the selection
2171 // should be empty.
2172 EXPECT_EQ(gfx::SelectionBound(), output.start);
2173 EXPECT_EQ(gfx::SelectionBound(), output.end);
2174 }
2175
TEST_F(LayerTreeImplTest,NumLayersTestOne)2176 TEST_F(LayerTreeImplTest, NumLayersTestOne) {
2177 // Root is created by the test harness.
2178 EXPECT_EQ(1u, host_impl().active_tree()->NumLayers());
2179 EXPECT_TRUE(root_layer());
2180 // Create another layer, should increment.
2181 AddLayer<LayerImpl>();
2182 EXPECT_EQ(2u, host_impl().active_tree()->NumLayers());
2183 }
2184
TEST_F(LayerTreeImplTest,NumLayersSmallTree)2185 TEST_F(LayerTreeImplTest, NumLayersSmallTree) {
2186 EXPECT_EQ(1u, host_impl().active_tree()->NumLayers());
2187 AddLayer<LayerImpl>();
2188 AddLayer<LayerImpl>();
2189 AddLayer<LayerImpl>();
2190 EXPECT_EQ(4u, host_impl().active_tree()->NumLayers());
2191 }
2192
TEST_F(LayerTreeImplTest,DeviceScaleFactorNeedsDrawPropertiesUpdate)2193 TEST_F(LayerTreeImplTest, DeviceScaleFactorNeedsDrawPropertiesUpdate) {
2194 host_impl().active_tree()->UpdateDrawProperties();
2195 EXPECT_FALSE(host_impl().active_tree()->needs_update_draw_properties());
2196 host_impl().active_tree()->SetDeviceScaleFactor(1.f);
2197 EXPECT_FALSE(host_impl().active_tree()->needs_update_draw_properties());
2198 host_impl().active_tree()->SetDeviceScaleFactor(2.f);
2199 EXPECT_TRUE(host_impl().active_tree()->needs_update_draw_properties());
2200 }
2201
TEST_F(LayerTreeImplTest,RasterColorSpaceDoesNotNeedDrawPropertiesUpdate)2202 TEST_F(LayerTreeImplTest, RasterColorSpaceDoesNotNeedDrawPropertiesUpdate) {
2203 host_impl().active_tree()->SetRasterColorSpace(
2204 gfx::ColorSpace::CreateXYZD50());
2205 host_impl().active_tree()->UpdateDrawProperties();
2206 EXPECT_FALSE(host_impl().active_tree()->needs_update_draw_properties());
2207 host_impl().active_tree()->SetRasterColorSpace(gfx::ColorSpace::CreateSRGB());
2208 EXPECT_FALSE(host_impl().active_tree()->needs_update_draw_properties());
2209 }
2210
TEST_F(LayerTreeImplTest,HitTestingCorrectLayerWheelListener)2211 TEST_F(LayerTreeImplTest, HitTestingCorrectLayerWheelListener) {
2212 host_impl().active_tree()->set_event_listener_properties(
2213 EventListenerClass::kMouseWheel, EventListenerProperties::kBlocking);
2214
2215 LayerImpl* root = root_layer();
2216 LayerImpl* top = AddLayer<LayerImpl>();
2217 LayerImpl* left_child = AddLayer<LayerImpl>();
2218 LayerImpl* right_child = AddLayer<LayerImpl>();
2219
2220 {
2221 gfx::Transform translate_z;
2222 translate_z.Translate3d(0, 0, 10);
2223 top->SetBounds(gfx::Size(100, 100));
2224 top->SetDrawsContent(true);
2225 top->SetHitTestable(true);
2226 CopyProperties(root, top);
2227 CreateTransformNode(top).local = translate_z;
2228 }
2229 {
2230 gfx::Transform translate_z;
2231 translate_z.Translate3d(0, 0, 10);
2232 left_child->SetBounds(gfx::Size(100, 100));
2233 left_child->SetDrawsContent(true);
2234 left_child->SetHitTestable(true);
2235 CopyProperties(top, left_child);
2236 CreateTransformNode(left_child).local = translate_z;
2237 }
2238 {
2239 gfx::Transform translate_z;
2240 translate_z.Translate3d(0, 0, 10);
2241 right_child->SetBounds(gfx::Size(100, 100));
2242 CopyProperties(top, right_child);
2243 CreateTransformNode(right_child).local = translate_z;
2244 }
2245
2246 host_impl().active_tree()->SetDeviceViewportRect(gfx::Rect(root->bounds()));
2247 UpdateDrawProperties(host_impl().active_tree());
2248 CHECK_EQ(1u, GetRenderSurfaceList().size());
2249
2250 gfx::PointF test_point = gfx::PointF(1.f, 1.f);
2251 LayerImpl* result_layer =
2252 host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
2253
2254 EXPECT_EQ(left_child, result_layer);
2255 }
2256
2257 namespace {
2258
2259 class PersistentSwapPromise
2260 : public SwapPromise,
2261 public base::SupportsWeakPtr<PersistentSwapPromise> {
2262 public:
2263 PersistentSwapPromise() = default;
2264 ~PersistentSwapPromise() override = default;
2265
DidActivate()2266 void DidActivate() override {}
2267 MOCK_METHOD1(WillSwap, void(viz::CompositorFrameMetadata* metadata));
2268 MOCK_METHOD0(DidSwap, void());
2269
DidNotSwap(DidNotSwapReason reason)2270 DidNotSwapAction DidNotSwap(DidNotSwapReason reason) override {
2271 return DidNotSwapAction::KEEP_ACTIVE;
2272 }
2273
OnCommit()2274 void OnCommit() override {}
TraceId() const2275 int64_t TraceId() const override { return 0; }
2276 };
2277
2278 class NotPersistentSwapPromise
2279 : public SwapPromise,
2280 public base::SupportsWeakPtr<NotPersistentSwapPromise> {
2281 public:
2282 NotPersistentSwapPromise() = default;
2283 ~NotPersistentSwapPromise() override = default;
2284
DidActivate()2285 void DidActivate() override {}
WillSwap(viz::CompositorFrameMetadata * metadata)2286 void WillSwap(viz::CompositorFrameMetadata* metadata) override {}
DidSwap()2287 void DidSwap() override {}
2288
DidNotSwap(DidNotSwapReason reason)2289 DidNotSwapAction DidNotSwap(DidNotSwapReason reason) override {
2290 return DidNotSwapAction::BREAK_PROMISE;
2291 }
2292
OnCommit()2293 void OnCommit() override {}
TraceId() const2294 int64_t TraceId() const override { return 0; }
2295 };
2296
2297 } // namespace
2298
TEST_F(LayerTreeImplTest,PersistentSwapPromisesAreKeptAlive)2299 TEST_F(LayerTreeImplTest, PersistentSwapPromisesAreKeptAlive) {
2300 const size_t promises_count = 2;
2301
2302 std::vector<base::WeakPtr<PersistentSwapPromise>> persistent_promises;
2303 std::vector<std::unique_ptr<PersistentSwapPromise>>
2304 persistent_promises_to_pass;
2305 for (size_t i = 0; i < promises_count; ++i) {
2306 persistent_promises_to_pass.push_back(
2307 std::make_unique<PersistentSwapPromise>());
2308 }
2309
2310 for (auto& promise : persistent_promises_to_pass) {
2311 persistent_promises.push_back(promise->AsWeakPtr());
2312 host_impl().active_tree()->QueueSwapPromise(std::move(promise));
2313 }
2314
2315 std::vector<std::unique_ptr<SwapPromise>> promises;
2316 host_impl().active_tree()->PassSwapPromises(std::move(promises));
2317 host_impl().active_tree()->BreakSwapPromises(
2318 SwapPromise::DidNotSwapReason::SWAP_FAILS);
2319
2320 ASSERT_EQ(promises_count, persistent_promises.size());
2321 for (size_t i = 0; i < persistent_promises.size(); ++i) {
2322 SCOPED_TRACE(testing::Message() << "While checking case #" << i);
2323 ASSERT_TRUE(persistent_promises[i]);
2324 EXPECT_CALL(*persistent_promises[i], WillSwap(testing::_));
2325 }
2326 host_impl().active_tree()->FinishSwapPromises(nullptr);
2327 }
2328
TEST_F(LayerTreeImplTest,NotPersistentSwapPromisesAreDroppedWhenSwapFails)2329 TEST_F(LayerTreeImplTest, NotPersistentSwapPromisesAreDroppedWhenSwapFails) {
2330 const size_t promises_count = 2;
2331
2332 std::vector<base::WeakPtr<NotPersistentSwapPromise>> not_persistent_promises;
2333 std::vector<std::unique_ptr<NotPersistentSwapPromise>>
2334 not_persistent_promises_to_pass;
2335 for (size_t i = 0; i < promises_count; ++i) {
2336 not_persistent_promises_to_pass.push_back(
2337 std::make_unique<NotPersistentSwapPromise>());
2338 }
2339
2340 for (auto& promise : not_persistent_promises_to_pass) {
2341 not_persistent_promises.push_back(promise->AsWeakPtr());
2342 host_impl().active_tree()->QueueSwapPromise(std::move(promise));
2343 }
2344 std::vector<std::unique_ptr<SwapPromise>> promises;
2345 host_impl().active_tree()->PassSwapPromises(std::move(promises));
2346
2347 ASSERT_EQ(promises_count, not_persistent_promises.size());
2348 for (size_t i = 0; i < not_persistent_promises.size(); ++i) {
2349 EXPECT_FALSE(not_persistent_promises[i]) << "While checking case #" << i;
2350 }
2351
2352 // Finally, check that not persistent promise doesn't survive
2353 // |LayerTreeImpl::BreakSwapPromises|.
2354 {
2355 std::unique_ptr<NotPersistentSwapPromise> promise(
2356 new NotPersistentSwapPromise());
2357 auto weak_promise = promise->AsWeakPtr();
2358 host_impl().active_tree()->QueueSwapPromise(std::move(promise));
2359 host_impl().active_tree()->BreakSwapPromises(
2360 SwapPromise::DidNotSwapReason::SWAP_FAILS);
2361 EXPECT_FALSE(weak_promise);
2362 }
2363 }
2364
TEST_F(LayerTreeImplTest,TrackPictureLayersWithPaintWorklets)2365 TEST_F(LayerTreeImplTest, TrackPictureLayersWithPaintWorklets) {
2366 host_impl().CreatePendingTree();
2367 LayerTreeImpl* pending_tree = host_impl().pending_tree();
2368
2369 // Initially there are no layers in the set.
2370 EXPECT_EQ(pending_tree->picture_layers_with_paint_worklets().size(), 0u);
2371
2372 auto* root = EnsureRootLayerInPendingTree();
2373 root->SetBounds(gfx::Size(100, 100));
2374
2375 // Add three layers; two with PaintWorklets and one without.
2376 auto* child1 = AddLayerInPendingTree<PictureLayerImpl>();
2377 child1->SetBounds(gfx::Size(100, 100));
2378 auto* child2 = AddLayerInPendingTree<PictureLayerImpl>();
2379 child2->SetBounds(gfx::Size(100, 100));
2380 auto* child3 = AddLayerInPendingTree<PictureLayerImpl>();
2381 child3->SetBounds(gfx::Size(100, 100));
2382
2383 CopyProperties(root, child1);
2384 CopyProperties(root, child2);
2385 CopyProperties(root, child3);
2386
2387 Region empty_invalidation;
2388 scoped_refptr<RasterSource> raster_source1(
2389 FakeRasterSource::CreateFilledWithPaintWorklet(child1->bounds()));
2390 child1->UpdateRasterSource(raster_source1, &empty_invalidation, nullptr,
2391 nullptr);
2392 scoped_refptr<RasterSource> raster_source3(
2393 FakeRasterSource::CreateFilledWithPaintWorklet(child3->bounds()));
2394 child3->UpdateRasterSource(raster_source3, &empty_invalidation, nullptr,
2395 nullptr);
2396
2397 // The set should correctly track which layers are in it.
2398 const base::flat_set<PictureLayerImpl*>& layers =
2399 pending_tree->picture_layers_with_paint_worklets();
2400 EXPECT_EQ(layers.size(), 2u);
2401 EXPECT_TRUE(layers.contains(child1));
2402 EXPECT_TRUE(layers.contains(child3));
2403
2404 // Test explicitly removing a layer from the set.
2405 scoped_refptr<RasterSource> empty_raster_source(
2406 FakeRasterSource::CreateFilled(child1->bounds()));
2407 child1->UpdateRasterSource(empty_raster_source, &empty_invalidation, nullptr,
2408 nullptr);
2409 EXPECT_EQ(layers.size(), 1u);
2410 EXPECT_FALSE(layers.contains(child1));
2411
2412 pending_tree->DetachLayers();
2413 EXPECT_EQ(layers.size(), 0u);
2414 }
2415
2416 namespace {
2417 class CommitToPendingTreeLayerTreeImplTestSettings : public LayerListSettings {
2418 public:
CommitToPendingTreeLayerTreeImplTestSettings()2419 CommitToPendingTreeLayerTreeImplTestSettings() {
2420 commit_to_active_tree = false;
2421 }
2422 };
2423
2424 class CommitToPendingTreeLayerTreeImplTest : public LayerTreeImplTest {
2425 public:
CommitToPendingTreeLayerTreeImplTest()2426 CommitToPendingTreeLayerTreeImplTest()
2427 : LayerTreeImplTest(CommitToPendingTreeLayerTreeImplTestSettings()) {}
2428 };
2429 } // namespace
2430
TEST_F(CommitToPendingTreeLayerTreeImplTest,ElementIdToAnimationMapsTrackOnlyOnSyncTree)2431 TEST_F(CommitToPendingTreeLayerTreeImplTest,
2432 ElementIdToAnimationMapsTrackOnlyOnSyncTree) {
2433 ASSERT_FALSE(host_impl().CommitToActiveTree());
2434
2435 // When we have a pending tree (e.g. commit_to_active_tree is false), the
2436 // various ElementId to animation maps should not track anything for the
2437 // active tree (as they are only used on the sync tree).
2438 LayerTreeImpl* active_tree = host_impl().active_tree();
2439 UpdateDrawProperties(active_tree);
2440 LayerImpl* active_root = active_tree->root_layer();
2441
2442 auto& active_opacity_map =
2443 active_tree->element_id_to_opacity_animations_for_testing();
2444 ASSERT_EQ(active_opacity_map.size(), 0u);
2445 active_tree->SetOpacityMutated(active_root->element_id(), 0.5f);
2446 EXPECT_EQ(active_opacity_map.size(), 0u);
2447
2448 auto& active_transform_map =
2449 active_tree->element_id_to_transform_animations_for_testing();
2450 ASSERT_EQ(active_transform_map.size(), 0u);
2451 active_tree->SetTransformMutated(active_root->element_id(), gfx::Transform());
2452 EXPECT_EQ(active_transform_map.size(), 0u);
2453
2454 auto& active_filter_map =
2455 active_tree->element_id_to_filter_animations_for_testing();
2456 ASSERT_EQ(active_filter_map.size(), 0u);
2457 active_tree->SetFilterMutated(active_root->element_id(), FilterOperations());
2458 EXPECT_EQ(active_filter_map.size(), 0u);
2459
2460 // The pending/recycle tree however should track them. Here we need two nodes
2461 // (the root and a child) as we will be adding entries for both the pending
2462 // and recycle tree cases.
2463 host_impl().CreatePendingTree();
2464 LayerTreeImpl* pending_tree = host_impl().pending_tree();
2465 LayerImpl* pending_root = EnsureRootLayerInPendingTree();
2466 pending_root->SetBounds(gfx::Size(1, 1));
2467 LayerImpl* child = AddLayerInPendingTree<LayerImpl>();
2468 pending_tree->SetElementIdsForTesting();
2469
2470 // A scale transform forces a TransformNode.
2471 gfx::Transform scale3d;
2472 scale3d.Scale3d(1, 1, 0.5);
2473 CopyProperties(pending_root, child);
2474 CreateTransformNode(child).local = scale3d;
2475 // A non-one opacity forces an EffectNode.
2476 CreateEffectNode(child).opacity = 0.9f;
2477
2478 UpdateDrawProperties(pending_tree);
2479
2480 auto& pending_opacity_map =
2481 pending_tree->element_id_to_opacity_animations_for_testing();
2482 ASSERT_EQ(pending_opacity_map.size(), 0u);
2483 pending_tree->SetOpacityMutated(pending_root->element_id(), 0.5f);
2484 EXPECT_EQ(pending_opacity_map.size(), 1u);
2485
2486 auto& pending_transform_map =
2487 pending_tree->element_id_to_transform_animations_for_testing();
2488 ASSERT_EQ(pending_transform_map.size(), 0u);
2489 pending_tree->SetTransformMutated(pending_root->element_id(),
2490 gfx::Transform());
2491 EXPECT_EQ(pending_transform_map.size(), 1u);
2492
2493 auto& pending_filter_map =
2494 pending_tree->element_id_to_filter_animations_for_testing();
2495 ASSERT_EQ(pending_filter_map.size(), 0u);
2496 pending_tree->SetFilterMutated(pending_root->element_id(),
2497 FilterOperations());
2498 EXPECT_EQ(pending_filter_map.size(), 1u);
2499
2500 // Finally, check the recycle tree - this should still track them.
2501 host_impl().ActivateSyncTree();
2502 LayerTreeImpl* recycle_tree = host_impl().recycle_tree();
2503 ASSERT_TRUE(recycle_tree);
2504
2505 auto& recycle_opacity_map =
2506 recycle_tree->element_id_to_opacity_animations_for_testing();
2507 ASSERT_EQ(recycle_opacity_map.size(), 1u);
2508 recycle_tree->SetOpacityMutated(child->element_id(), 0.5f);
2509 EXPECT_EQ(recycle_opacity_map.size(), 2u);
2510
2511 auto& recycle_transform_map =
2512 recycle_tree->element_id_to_transform_animations_for_testing();
2513 ASSERT_EQ(recycle_transform_map.size(), 1u);
2514 recycle_tree->SetTransformMutated(child->element_id(), gfx::Transform());
2515 EXPECT_EQ(recycle_transform_map.size(), 2u);
2516
2517 auto& recycle_filter_map =
2518 recycle_tree->element_id_to_filter_animations_for_testing();
2519 ASSERT_EQ(recycle_filter_map.size(), 1u);
2520 recycle_tree->SetFilterMutated(child->element_id(), FilterOperations());
2521 EXPECT_EQ(recycle_filter_map.size(), 2u);
2522 }
2523
TEST_F(LayerTreeImplTest,ElementIdToAnimationMapsTrackOnlyOnSyncTree)2524 TEST_F(LayerTreeImplTest, ElementIdToAnimationMapsTrackOnlyOnSyncTree) {
2525 ASSERT_TRUE(host_impl().CommitToActiveTree());
2526
2527 // When we are commiting directly to the active tree, the various ElementId to
2528 // animation maps should track on the active tree (as it is the sync tree, and
2529 // they are used on the sync tree).
2530 LayerTreeImpl* active_tree = host_impl().active_tree();
2531 UpdateDrawProperties(active_tree);
2532 LayerImpl* root = active_tree->root_layer();
2533
2534 auto& opacity_map =
2535 active_tree->element_id_to_opacity_animations_for_testing();
2536 ASSERT_EQ(opacity_map.size(), 0u);
2537 active_tree->SetOpacityMutated(root->element_id(), 0.5f);
2538 EXPECT_EQ(opacity_map.size(), 1u);
2539
2540 auto& transform_map =
2541 active_tree->element_id_to_transform_animations_for_testing();
2542 ASSERT_EQ(transform_map.size(), 0u);
2543 active_tree->SetTransformMutated(root->element_id(), gfx::Transform());
2544 EXPECT_EQ(transform_map.size(), 1u);
2545
2546 auto& filter_map = active_tree->element_id_to_filter_animations_for_testing();
2547 ASSERT_EQ(filter_map.size(), 0u);
2548 active_tree->SetFilterMutated(root->element_id(), FilterOperations());
2549 EXPECT_EQ(filter_map.size(), 1u);
2550 }
2551
TEST_F(LayerTreeImplTest,FrameElementIdHitTestSimple)2552 TEST_F(LayerTreeImplTest, FrameElementIdHitTestSimple) {
2553 LayerImpl* frame_layer = AddLayer<LayerImpl>();
2554 frame_layer->SetBounds(gfx::Size(50, 50));
2555 frame_layer->SetDrawsContent(true);
2556 frame_layer->SetHitTestable(true);
2557 frame_layer->SetFrameElementId(ElementId(0x10));
2558 CopyProperties(root_layer(), frame_layer);
2559
2560 UpdateDrawProperties(host_impl().active_tree());
2561
2562 EXPECT_EQ(host_impl().FindFrameElementIdAtPoint(gfx::PointF(10, 10)),
2563 ElementId(0x10));
2564 }
2565
TEST_F(LayerTreeImplTest,FrameElementIdHitTestOverlap)2566 TEST_F(LayerTreeImplTest, FrameElementIdHitTestOverlap) {
2567 LayerImpl* frame_layer = AddLayer<LayerImpl>();
2568 frame_layer->SetBounds(gfx::Size(50, 50));
2569 frame_layer->SetHitTestable(true);
2570 frame_layer->SetFrameElementId(ElementId(0x10));
2571 CopyProperties(root_layer(), frame_layer);
2572
2573 LayerImpl* occluding_frame_layer = AddLayer<LayerImpl>();
2574 occluding_frame_layer->SetBounds(gfx::Size(50, 50));
2575 occluding_frame_layer->SetHitTestable(true);
2576 occluding_frame_layer->SetFrameElementId(ElementId(0x20));
2577 CopyProperties(root_layer(), occluding_frame_layer);
2578 occluding_frame_layer->SetOffsetToTransformParent(gfx::Vector2dF(25, 25));
2579
2580 UpdateDrawProperties(host_impl().active_tree());
2581
2582 EXPECT_EQ(host_impl().FindFrameElementIdAtPoint(gfx::PointF(30, 30)),
2583 ElementId(0x20));
2584 }
2585
TEST_F(LayerTreeImplTest,FrameElementIdHitTestOverlapSimpleClip)2586 TEST_F(LayerTreeImplTest, FrameElementIdHitTestOverlapSimpleClip) {
2587 LayerImpl* frame_layer = AddLayer<LayerImpl>();
2588 frame_layer->SetBounds(gfx::Size(50, 50));
2589 frame_layer->SetHitTestable(true);
2590 frame_layer->SetFrameElementId(ElementId(0x10));
2591 CopyProperties(root_layer(), frame_layer);
2592
2593 LayerImpl* clipped_frame_layer = AddLayer<LayerImpl>();
2594 clipped_frame_layer->SetBounds(gfx::Size(50, 50));
2595 clipped_frame_layer->SetHitTestable(true);
2596 clipped_frame_layer->SetFrameElementId(ElementId(0x20));
2597 CopyProperties(root_layer(), clipped_frame_layer);
2598 clipped_frame_layer->SetOffsetToTransformParent(gfx::Vector2dF(25, 25));
2599
2600 // Create a clip excluding the overlapped region.
2601 auto& clip_node = CreateClipNode(clipped_frame_layer);
2602 clip_node.clip = gfx::RectF(40, 40, 10, 10);
2603
2604 UpdateDrawProperties(host_impl().active_tree());
2605
2606 // Ensure that the overlapping (clipped) layer isn't targeted.
2607 EXPECT_EQ(host_impl().FindFrameElementIdAtPoint(gfx::PointF(30, 30)),
2608 ElementId(0x10));
2609 }
2610
TEST_F(LayerTreeImplTest,FrameElementIdHitTestOverlapRoundedCorners)2611 TEST_F(LayerTreeImplTest, FrameElementIdHitTestOverlapRoundedCorners) {
2612 LayerImpl* frame_layer = AddLayer<LayerImpl>();
2613 frame_layer->SetBounds(gfx::Size(50, 50));
2614 frame_layer->SetHitTestable(true);
2615 frame_layer->SetFrameElementId(ElementId(0x10));
2616 CopyProperties(root_layer(), frame_layer);
2617
2618 LayerImpl* rounded_frame_layer = AddLayer<LayerImpl>();
2619 rounded_frame_layer->SetBounds(gfx::Size(50, 50));
2620 rounded_frame_layer->SetHitTestable(true);
2621 rounded_frame_layer->SetFrameElementId(ElementId(0x20));
2622 CopyProperties(root_layer(), rounded_frame_layer);
2623 rounded_frame_layer->SetOffsetToTransformParent(gfx::Vector2dF(25, 25));
2624
2625 // Add rounded corners to the layer, which are unable to be hit tested by the
2626 // simple quad-based logic.
2627 CreateEffectNode(rounded_frame_layer).rounded_corner_bounds =
2628 gfx::RRectF(25, 25, 50, 50, 5);
2629
2630 UpdateDrawProperties(host_impl().active_tree());
2631
2632 // The lookup should bail out in the presence of a complex clip/mask on the
2633 // target chain.
2634 EXPECT_FALSE(host_impl().FindFrameElementIdAtPoint(gfx::PointF(30, 30)));
2635 }
2636
2637 class LayerTreeImplOcclusionSettings : public LayerListSettings {
2638 public:
LayerTreeImplOcclusionSettings(bool enabled)2639 explicit LayerTreeImplOcclusionSettings(bool enabled) {
2640 enable_occlusion = enabled;
2641 minimum_occlusion_tracking_size = gfx::Size(1, 1);
2642 }
2643 };
2644
2645 class LayerTreeImplOcclusionTest : public LayerTreeImplTest {
2646 public:
LayerTreeImplOcclusionTest(bool enable_occlusion)2647 explicit LayerTreeImplOcclusionTest(bool enable_occlusion)
2648 : LayerTreeImplTest(LayerTreeImplOcclusionSettings(enable_occlusion)),
2649 enable_occlusion_(enable_occlusion) {}
2650
TestOcclusion()2651 void TestOcclusion() {
2652 LayerImpl* root = root_layer();
2653 root->SetBounds(gfx::Size(100, 100));
2654
2655 // Create a 50x50 layer in the center of our root bounds.
2656 LayerImpl* bottom_layer = AddLayer<LayerImpl>();
2657 bottom_layer->SetBounds(gfx::Size(50, 50));
2658 bottom_layer->SetDrawsContent(true);
2659 bottom_layer->SetContentsOpaque(true);
2660 CopyProperties(root, bottom_layer);
2661 bottom_layer->SetOffsetToTransformParent(gfx::Vector2dF(25, 25));
2662
2663 // Create a full-bounds 100x100 layer which occludes the 50x50 layer.
2664 LayerImpl* occluding_layer = AddLayer<LayerImpl>();
2665 occluding_layer->SetBounds(gfx::Size(100, 100));
2666 occluding_layer->SetDrawsContent(true);
2667 occluding_layer->SetContentsOpaque(true);
2668 CopyProperties(root, occluding_layer);
2669
2670 host_impl().active_tree()->SetDeviceViewportRect(gfx::Rect(root->bounds()));
2671 UpdateDrawProperties(host_impl().active_tree());
2672
2673 LayerTreeImpl* active_tree = host_impl().active_tree();
2674 if (enable_occlusion_) {
2675 // With occlusion on, the root is fully occluded, as is the bottom layer.
2676 EXPECT_TRUE(active_tree->UnoccludedScreenSpaceRegion().IsEmpty());
2677 EXPECT_TRUE(bottom_layer->draw_properties()
2678 .occlusion_in_content_space.HasOcclusion());
2679 } else {
2680 // With occlusion off, the full root should be unoccluded and the bottom
2681 // layer should have no occlusion.
2682 EXPECT_TRUE(active_tree->UnoccludedScreenSpaceRegion().Contains(
2683 gfx::Rect(root->bounds())));
2684 EXPECT_FALSE(bottom_layer->draw_properties()
2685 .occlusion_in_content_space.HasOcclusion());
2686 }
2687 }
2688
2689 private:
2690 bool enable_occlusion_;
2691 };
2692
2693 class LayerTreeImplOcclusionDisabledTest : public LayerTreeImplOcclusionTest {
2694 public:
LayerTreeImplOcclusionDisabledTest()2695 LayerTreeImplOcclusionDisabledTest() : LayerTreeImplOcclusionTest(false) {}
2696 };
2697
2698 class LayerTreeImplOcclusionEnabledTest : public LayerTreeImplOcclusionTest {
2699 public:
LayerTreeImplOcclusionEnabledTest()2700 LayerTreeImplOcclusionEnabledTest() : LayerTreeImplOcclusionTest(true) {}
2701 };
2702
TEST_F(LayerTreeImplOcclusionDisabledTest,OcclusionDisabled)2703 TEST_F(LayerTreeImplOcclusionDisabledTest, OcclusionDisabled) {
2704 TestOcclusion();
2705 }
2706
TEST_F(LayerTreeImplOcclusionEnabledTest,OcclusionEnabled)2707 TEST_F(LayerTreeImplOcclusionEnabledTest, OcclusionEnabled) {
2708 TestOcclusion();
2709 }
2710
2711 } // namespace
2712 } // namespace cc
2713