1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "cc/trees/layer_tree_host.h"
7 #include "cc/layers/layer.h"
8 #include "cc/test/layer_tree_test.h"
9 #include "cc/test/occlusion_tracker_test_common.h"
14 class TestLayer
: public Layer
{
16 static scoped_refptr
<TestLayer
> Create() {
17 return make_scoped_refptr(new TestLayer());
21 ResourceUpdateQueue
* update_queue
,
22 const OcclusionTracker
* occlusion
) OVERRIDE
{
26 // Gain access to internals of the OcclusionTracker.
27 const TestOcclusionTracker
* test_occlusion
=
28 static_cast<const TestOcclusionTracker
*>(occlusion
);
29 occlusion_
= UnionRegions(
30 test_occlusion
->occlusion_from_inside_target(),
31 test_occlusion
->occlusion_from_outside_target());
35 const Region
& occlusion() const { return occlusion_
; }
36 const Region
& expected_occlusion() const { return expected_occlusion_
; }
37 void set_expected_occlusion(const Region
& occlusion
) {
38 expected_occlusion_
= occlusion
;
42 TestLayer() : Layer() {
45 virtual ~TestLayer() {}
48 Region expected_occlusion_
;
51 class LayerTreeHostOcclusionTest
: public LayerTreeTest
{
53 LayerTreeHostOcclusionTest()
54 : root_(TestLayer::Create()),
55 child_(TestLayer::Create()),
56 child2_(TestLayer::Create()),
57 grand_child_(TestLayer::Create()),
58 mask_(TestLayer::Create()) {
61 virtual void BeginTest() OVERRIDE
{
62 PostSetNeedsCommitToMainThread();
65 virtual void DidCommit() OVERRIDE
{
66 TestLayer
* root
= static_cast<TestLayer
*>(layer_tree_host()->root_layer());
67 VerifyOcclusion(root
);
72 virtual void AfterTest() OVERRIDE
{}
74 void VerifyOcclusion(TestLayer
* layer
) const {
75 EXPECT_EQ(layer
->expected_occlusion().ToString(),
76 layer
->occlusion().ToString());
78 for (size_t i
= 0; i
< layer
->children().size(); ++i
) {
79 TestLayer
* child
= static_cast<TestLayer
*>(layer
->children()[i
].get());
80 VerifyOcclusion(child
);
84 void SetLayerPropertiesForTesting(TestLayer
* layer
,
86 const gfx::Transform
& transform
,
90 layer
->RemoveAllChildren();
92 parent
->AddChild(layer
);
93 layer
->SetTransform(transform
);
94 layer
->SetPosition(position
);
95 layer
->SetBounds(bounds
);
96 layer
->SetContentsOpaque(opaque
);
98 layer
->SetAnchorPoint(gfx::PointF());
102 scoped_refptr
<TestLayer
> root_
;
103 scoped_refptr
<TestLayer
> child_
;
104 scoped_refptr
<TestLayer
> child2_
;
105 scoped_refptr
<TestLayer
> grand_child_
;
106 scoped_refptr
<TestLayer
> mask_
;
108 gfx::Transform identity_matrix_
;
112 class LayerTreeHostOcclusionTestOcclusionSurfaceClipping
113 : public LayerTreeHostOcclusionTest
{
115 virtual void SetupTree() OVERRIDE
{
116 // The child layer is a surface and the grand_child is opaque, but clipped
117 // to the child and root
118 SetLayerPropertiesForTesting(
119 root_
.get(), NULL
, identity_matrix_
,
120 gfx::PointF(0.f
, 0.f
), gfx::Size(200, 200), true);
121 SetLayerPropertiesForTesting(
122 child_
.get(), root_
.get(), identity_matrix_
,
123 gfx::PointF(10.f
, 10.f
), gfx::Size(500, 500), false);
124 SetLayerPropertiesForTesting(
125 grand_child_
.get(), child_
.get(), identity_matrix_
,
126 gfx::PointF(-10.f
, -10.f
), gfx::Size(20, 500), true);
128 child_
->SetMasksToBounds(true);
129 child_
->SetForceRenderSurface(true);
131 child_
->set_expected_occlusion(gfx::Rect(0, 0, 10, 190));
132 root_
->set_expected_occlusion(gfx::Rect(10, 10, 10, 190));
134 layer_tree_host()->SetRootLayer(root_
);
135 LayerTreeTest::SetupTree();
139 SINGLE_AND_MULTI_THREAD_TEST_F(
140 LayerTreeHostOcclusionTestOcclusionSurfaceClipping
);
142 class LayerTreeHostOcclusionTestOcclusionSurfaceClippingOpaque
143 : public LayerTreeHostOcclusionTest
{
145 virtual void SetupTree() OVERRIDE
{
146 // If the child layer is opaque, then it adds to the occlusion seen by the
148 SetLayerPropertiesForTesting(
149 root_
.get(), NULL
, identity_matrix_
,
150 gfx::PointF(0.f
, 0.f
), gfx::Size(200, 200), true);
151 SetLayerPropertiesForTesting(
152 child_
.get(), root_
.get(), identity_matrix_
,
153 gfx::PointF(10.f
, 10.f
), gfx::Size(500, 500), true);
154 SetLayerPropertiesForTesting(
155 grand_child_
.get(), child_
.get(), identity_matrix_
,
156 gfx::PointF(-10.f
, -10.f
), gfx::Size(20, 500), true);
158 child_
->SetMasksToBounds(true);
159 child_
->SetForceRenderSurface(true);
161 child_
->set_expected_occlusion(gfx::Rect(0, 0, 10, 190));
162 root_
->set_expected_occlusion(gfx::Rect(10, 10, 190, 190));
164 layer_tree_host()->SetRootLayer(root_
);
165 LayerTreeTest::SetupTree();
169 SINGLE_AND_MULTI_THREAD_TEST_F(
170 LayerTreeHostOcclusionTestOcclusionSurfaceClippingOpaque
);
172 class LayerTreeHostOcclusionTestOcclusionTwoChildren
173 : public LayerTreeHostOcclusionTest
{
175 virtual void SetupTree() OVERRIDE
{
176 // Add a second child to the root layer and the regions should merge
177 SetLayerPropertiesForTesting(
178 root_
.get(), NULL
, identity_matrix_
,
179 gfx::PointF(0.f
, 0.f
), gfx::Size(200, 200), true);
180 SetLayerPropertiesForTesting(
181 child_
.get(), root_
.get(), identity_matrix_
,
182 gfx::PointF(10.f
, 10.f
), gfx::Size(500, 500), false);
183 SetLayerPropertiesForTesting(
184 grand_child_
.get(), child_
.get(), identity_matrix_
,
185 gfx::PointF(-10.f
, -10.f
), gfx::Size(20, 500), true);
186 SetLayerPropertiesForTesting(
187 child2_
.get(), root_
.get(), identity_matrix_
,
188 gfx::PointF(20.f
, 10.f
), gfx::Size(10, 500), true);
190 child_
->SetMasksToBounds(true);
191 child_
->SetForceRenderSurface(true);
193 grand_child_
->set_expected_occlusion(gfx::Rect(10, 0, 10, 190));
194 child_
->set_expected_occlusion(gfx::Rect(0, 0, 20, 190));
195 root_
->set_expected_occlusion(gfx::Rect(10, 10, 20, 190));
197 layer_tree_host()->SetRootLayer(root_
);
198 LayerTreeTest::SetupTree();
202 SINGLE_AND_MULTI_THREAD_TEST_F(
203 LayerTreeHostOcclusionTestOcclusionTwoChildren
);
205 class LayerTreeHostOcclusionTestOcclusionMask
206 : public LayerTreeHostOcclusionTest
{
208 virtual void SetupTree() OVERRIDE
{
209 // If the child layer has a mask on it, then it shouldn't contribute to
210 // occlusion on stuff below it.
211 SetLayerPropertiesForTesting(
212 root_
.get(), NULL
, identity_matrix_
,
213 gfx::PointF(0.f
, 0.f
), gfx::Size(200, 200), true);
214 SetLayerPropertiesForTesting(
215 child2_
.get(), root_
.get(), identity_matrix_
,
216 gfx::PointF(10.f
, 10.f
), gfx::Size(500, 500), true);
217 SetLayerPropertiesForTesting(
218 child_
.get(), root_
.get(), identity_matrix_
,
219 gfx::PointF(20.f
, 20.f
), gfx::Size(500, 500), true);
220 SetLayerPropertiesForTesting(
221 grand_child_
.get(), child_
.get(), identity_matrix_
,
222 gfx::PointF(-10.f
, -10.f
), gfx::Size(500, 500), true);
224 child_
->SetMasksToBounds(true);
225 child_
->SetForceRenderSurface(true);
226 child_
->SetMaskLayer(mask_
.get());
228 child_
->set_expected_occlusion(gfx::Rect(0, 0, 180, 180));
229 root_
->set_expected_occlusion(gfx::Rect(10, 10, 190, 190));
231 layer_tree_host()->SetRootLayer(root_
);
232 LayerTreeTest::SetupTree();
236 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostOcclusionTestOcclusionMask
);
238 class LayerTreeHostOcclusionTestOcclusionMaskBelowOcclusion
239 : public LayerTreeHostOcclusionTest
{
241 virtual void SetupTree() OVERRIDE
{
242 // If the child layer with a mask is below child2, then child2 should
243 // contribute to occlusion on everything, and child shouldn't contribute
245 SetLayerPropertiesForTesting(
246 root_
.get(), NULL
, identity_matrix_
,
247 gfx::PointF(0.f
, 0.f
), gfx::Size(200, 200), true);
248 SetLayerPropertiesForTesting(
249 child_
.get(), root_
.get(), identity_matrix_
,
250 gfx::PointF(10.f
, 10.f
), gfx::Size(500, 500), true);
251 SetLayerPropertiesForTesting(
252 grand_child_
.get(), child_
.get(), identity_matrix_
,
253 gfx::PointF(-10.f
, -10.f
), gfx::Size(20, 500), true);
254 SetLayerPropertiesForTesting(
255 child2_
.get(), root_
.get(), identity_matrix_
,
256 gfx::PointF(20.f
, 10.f
), gfx::Size(10, 500), true);
258 child_
->SetMasksToBounds(true);
259 child_
->SetForceRenderSurface(true);
260 child_
->SetMaskLayer(mask_
.get());
262 grand_child_
->set_expected_occlusion(gfx::Rect(10, 0, 10, 190));
263 child_
->set_expected_occlusion(gfx::Rect(0, 0, 20, 190));
264 root_
->set_expected_occlusion(gfx::Rect(20, 10, 10, 190));
266 layer_tree_host()->SetRootLayer(root_
);
267 LayerTreeTest::SetupTree();
271 SINGLE_AND_MULTI_THREAD_TEST_F(
272 LayerTreeHostOcclusionTestOcclusionMaskBelowOcclusion
);
274 class LayerTreeHostOcclusionTestOcclusionOpacity
275 : public LayerTreeHostOcclusionTest
{
277 virtual void SetupTree() OVERRIDE
{
278 // If the child layer has a non-opaque opacity, then it shouldn't
279 // contribute to occlusion on stuff below it
280 SetLayerPropertiesForTesting(
281 root_
.get(), NULL
, identity_matrix_
,
282 gfx::PointF(0.f
, 0.f
), gfx::Size(200, 200), true);
283 SetLayerPropertiesForTesting(
284 child2_
.get(), root_
.get(), identity_matrix_
,
285 gfx::PointF(20.f
, 10.f
), gfx::Size(10, 500), true);
286 SetLayerPropertiesForTesting(
287 child_
.get(), root_
.get(), identity_matrix_
,
288 gfx::PointF(10.f
, 10.f
), gfx::Size(500, 500), true);
289 SetLayerPropertiesForTesting(
290 grand_child_
.get(), child_
.get(), identity_matrix_
,
291 gfx::PointF(-10.f
, -10.f
), gfx::Size(20, 500), true);
293 child_
->SetMasksToBounds(true);
294 child_
->SetForceRenderSurface(true);
295 child_
->SetOpacity(0.5f
);
297 child_
->set_expected_occlusion(gfx::Rect(0, 0, 10, 190));
298 root_
->set_expected_occlusion(gfx::Rect(20, 10, 10, 190));
300 layer_tree_host()->SetRootLayer(root_
);
301 LayerTreeTest::SetupTree();
305 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostOcclusionTestOcclusionOpacity
);
307 class LayerTreeHostOcclusionTestOcclusionOpacityBelowOcclusion
308 : public LayerTreeHostOcclusionTest
{
310 virtual void SetupTree() OVERRIDE
{
311 // If the child layer with non-opaque opacity is below child2, then
312 // child2 should contribute to occlusion on everything, and child shouldn't
313 // contribute to the root_.
314 SetLayerPropertiesForTesting(
315 root_
.get(), NULL
, identity_matrix_
,
316 gfx::PointF(0.f
, 0.f
), gfx::Size(200, 200), true);
317 SetLayerPropertiesForTesting(
318 child_
.get(), root_
.get(), identity_matrix_
,
319 gfx::PointF(10.f
, 10.f
), gfx::Size(500, 500), true);
320 SetLayerPropertiesForTesting(
321 grand_child_
.get(), child_
.get(), identity_matrix_
,
322 gfx::PointF(-10.f
, -10.f
), gfx::Size(20, 500), true);
323 SetLayerPropertiesForTesting(
324 child2_
.get(), root_
.get(), identity_matrix_
,
325 gfx::PointF(20.f
, 10.f
), gfx::Size(10, 500), true);
327 child_
->SetMasksToBounds(true);
328 child_
->SetForceRenderSurface(true);
329 child_
->SetOpacity(0.5f
);
331 grand_child_
->set_expected_occlusion(gfx::Rect(10, 0, 10, 190));
332 child_
->set_expected_occlusion(gfx::Rect(0, 0, 20, 190));
333 root_
->set_expected_occlusion(gfx::Rect(20, 10, 10, 190));
335 layer_tree_host()->SetRootLayer(root_
);
336 LayerTreeTest::SetupTree();
340 SINGLE_AND_MULTI_THREAD_TEST_F(
341 LayerTreeHostOcclusionTestOcclusionOpacityBelowOcclusion
);
343 class LayerTreeHostOcclusionTestOcclusionOpacityFilter
344 : public LayerTreeHostOcclusionTest
{
346 virtual void SetupTree() OVERRIDE
{
347 gfx::Transform child_transform
;
348 child_transform
.Translate(250.0, 250.0);
349 child_transform
.Rotate(90.0);
350 child_transform
.Translate(-250.0, -250.0);
352 FilterOperations filters
;
353 filters
.Append(FilterOperation::CreateOpacityFilter(0.5f
));
355 // If the child layer has a filter that changes alpha values, and is below
356 // child2, then child2 should contribute to occlusion on everything,
357 // and child shouldn't contribute to the root
358 SetLayerPropertiesForTesting(
359 root_
.get(), NULL
, identity_matrix_
,
360 gfx::PointF(0.f
, 0.f
), gfx::Size(200, 200), true);
361 SetLayerPropertiesForTesting(
362 child_
.get(), root_
.get(), child_transform
,
363 gfx::PointF(30.f
, 30.f
), gfx::Size(500, 500), true);
364 SetLayerPropertiesForTesting(
365 grand_child_
.get(), child_
.get(), identity_matrix_
,
366 gfx::PointF(10.f
, 10.f
), gfx::Size(500, 500), true);
367 SetLayerPropertiesForTesting(
368 child2_
.get(), root_
.get(), identity_matrix_
,
369 gfx::PointF(10.f
, 70.f
), gfx::Size(500, 500), true);
371 child_
->SetMasksToBounds(true);
372 child_
->SetFilters(filters
);
374 grand_child_
->set_expected_occlusion(gfx::Rect(40, 330, 130, 190));
375 child_
->set_expected_occlusion(UnionRegions(
376 gfx::Rect(10, 330, 160, 170), gfx::Rect(40, 500, 130, 20)));
377 root_
->set_expected_occlusion(gfx::Rect(10, 70, 190, 130));
379 layer_tree_host()->SetRootLayer(root_
);
380 LayerTreeTest::SetupTree();
384 SINGLE_AND_MULTI_THREAD_TEST_F(
385 LayerTreeHostOcclusionTestOcclusionOpacityFilter
);
387 class LayerTreeHostOcclusionTestOcclusionBlurFilter
388 : public LayerTreeHostOcclusionTest
{
390 virtual void SetupTree() OVERRIDE
{
391 gfx::Transform child_transform
;
392 child_transform
.Translate(250.0, 250.0);
393 child_transform
.Rotate(90.0);
394 child_transform
.Translate(-250.0, -250.0);
396 FilterOperations filters
;
397 filters
.Append(FilterOperation::CreateBlurFilter(10.f
));
399 // If the child layer has a filter that moves pixels/changes alpha, and is
400 // below child2, then child should not inherit occlusion from outside its
401 // subtree, and should not contribute to the root
402 SetLayerPropertiesForTesting(
403 root_
.get(), NULL
, identity_matrix_
,
404 gfx::PointF(0.f
, 0.f
), gfx::Size(200, 200), true);
405 SetLayerPropertiesForTesting(
406 child_
.get(), root_
.get(), child_transform
,
407 gfx::PointF(30.f
, 30.f
), gfx::Size(500, 500), true);
408 SetLayerPropertiesForTesting(
409 grand_child_
.get(), child_
.get(), identity_matrix_
,
410 gfx::PointF(10.f
, 10.f
), gfx::Size(500, 500), true);
411 SetLayerPropertiesForTesting(
412 child2_
.get(), root_
.get(), identity_matrix_
,
413 gfx::PointF(10.f
, 70.f
), gfx::Size(500, 500), true);
415 child_
->SetMasksToBounds(true);
416 child_
->SetFilters(filters
);
418 child_
->set_expected_occlusion(gfx::Rect(10, 330, 160, 170));
419 root_
->set_expected_occlusion(gfx::Rect(10, 70, 190, 130));
421 layer_tree_host()->SetRootLayer(root_
);
422 LayerTreeTest::SetupTree();
426 SINGLE_AND_MULTI_THREAD_TEST_F(
427 LayerTreeHostOcclusionTestOcclusionBlurFilter
);
429 class LayerTreeHostOcclusionTestManySurfaces
430 : public LayerTreeHostOcclusionTest
{
432 virtual void SetupTree() OVERRIDE
{
433 // We create enough RenderSurfaces that it will trigger Vector reallocation
434 // while computing occlusion.
435 std::vector
<scoped_refptr
<TestLayer
> > layers
;
436 int num_surfaces
= 200;
437 int root_width
= 400;
438 int root_height
= 400;
440 for (int i
= 0; i
< num_surfaces
; ++i
) {
441 layers
.push_back(TestLayer::Create());
443 SetLayerPropertiesForTesting(
444 layers
.back().get(), NULL
, identity_matrix_
,
445 gfx::PointF(0.f
, 0.f
),
446 gfx::Size(root_width
, root_height
), true);
448 SetLayerPropertiesForTesting(
449 layers
.back().get(), layers
[layers
.size() - 2].get(),
451 gfx::PointF(1.f
, 1.f
),
452 gfx::Size(root_width
-i
, root_height
-i
), true);
453 layers
.back()->SetForceRenderSurface(true);
457 for (int i
= 1; i
< num_surfaces
; ++i
) {
458 scoped_refptr
<TestLayer
> child
= TestLayer::Create();
459 SetLayerPropertiesForTesting(
460 child
.get(), layers
[i
].get(), identity_matrix_
,
461 gfx::PointF(0.f
, 0.f
), gfx::Size(root_width
, root_height
), false);
464 for (int i
= 0; i
< num_surfaces
-1; ++i
) {
465 gfx::Rect
expected_occlusion(1, 1, root_width
-i
-1, root_height
-i
-1);
466 layers
[i
]->set_expected_occlusion(expected_occlusion
);
469 layer_tree_host()->SetRootLayer(layers
[0]);
470 LayerTreeTest::SetupTree();
474 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostOcclusionTestManySurfaces
);