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/layer_tree_host.h"
8 #include "cc/test/layer_tree_test_common.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
,
23 RenderingStats
* stats
) OVERRIDE
{
27 // Gain access to internals of the OcclusionTracker.
28 const TestOcclusionTracker
* test_occlusion
=
29 static_cast<const TestOcclusionTracker
*>(occlusion
);
30 occlusion_
= UnionRegions(
31 test_occlusion
->occlusionFromInsideTarget(),
32 test_occlusion
->occlusionFromOutsideTarget());
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 ThreadedTest
{
54 LayerTreeHostOcclusionTest()
55 : root_(TestLayer::Create()),
56 child_(TestLayer::Create()),
57 child2_(TestLayer::Create()),
58 grand_child_(TestLayer::Create()),
59 mask_(TestLayer::Create()) {
62 virtual void beginTest() OVERRIDE
{
63 postSetNeedsCommitToMainThread();
66 virtual void didCommit() OVERRIDE
{
67 TestLayer
* root
= static_cast<TestLayer
*>(m_layerTreeHost
->rootLayer());
68 VerifyOcclusion(root
);
73 virtual void afterTest() OVERRIDE
{}
75 void VerifyOcclusion(TestLayer
* layer
) const {
76 EXPECT_EQ(layer
->expected_occlusion().ToString(),
77 layer
->occlusion().ToString());
79 for (size_t i
= 0; i
< layer
->children().size(); ++i
) {
80 TestLayer
* child
= static_cast<TestLayer
*>(layer
->children()[i
].get());
81 VerifyOcclusion(child
);
85 void SetLayerPropertiesForTesting(
86 TestLayer
* layer
, TestLayer
* parent
, const gfx::Transform
& transform
,
87 const gfx::PointF
& position
, const gfx::Size
& bounds
, bool opaque
) const {
88 layer
->removeAllChildren();
90 parent
->addChild(layer
);
91 layer
->setTransform(transform
);
92 layer
->setPosition(position
);
93 layer
->setBounds(bounds
);
94 layer
->setContentsOpaque(opaque
);
96 layer
->setAnchorPoint(gfx::PointF());
100 scoped_refptr
<TestLayer
> root_
;
101 scoped_refptr
<TestLayer
> child_
;
102 scoped_refptr
<TestLayer
> child2_
;
103 scoped_refptr
<TestLayer
> grand_child_
;
104 scoped_refptr
<TestLayer
> mask_
;
106 gfx::Transform identity_matrix_
;
110 class LayerTreeHostOcclusionTestOcclusionSurfaceClipping
:
111 public LayerTreeHostOcclusionTest
{
113 virtual void setupTree() OVERRIDE
{
114 // The child layer is a surface and the grandChild is opaque, but clipped to
115 // the child and root
116 SetLayerPropertiesForTesting(
117 root_
.get(), NULL
, identity_matrix_
,
118 gfx::PointF(0.f
, 0.f
), gfx::Size(200, 200), true);
119 SetLayerPropertiesForTesting(
120 child_
.get(), root_
.get(), identity_matrix_
,
121 gfx::PointF(10.f
, 10.f
), gfx::Size(500, 500), false);
122 SetLayerPropertiesForTesting(
123 grand_child_
.get(), child_
.get(), identity_matrix_
,
124 gfx::PointF(-10.f
, -10.f
), gfx::Size(20, 500), true);
126 child_
->setMasksToBounds(true);
127 child_
->setForceRenderSurface(true);
129 child_
->set_expected_occlusion(gfx::Rect(0, 0, 10, 190));
130 root_
->set_expected_occlusion(gfx::Rect(10, 10, 10, 190));
132 m_layerTreeHost
->setRootLayer(root_
);
133 ThreadedTest::setupTree();
137 SINGLE_AND_MULTI_THREAD_TEST_F(
138 LayerTreeHostOcclusionTestOcclusionSurfaceClipping
)
140 class LayerTreeHostOcclusionTestOcclusionSurfaceClippingOpaque
:
141 public LayerTreeHostOcclusionTest
{
143 virtual void setupTree() OVERRIDE
{
144 // If the child layer is opaque, then it adds to the occlusion seen by the
146 SetLayerPropertiesForTesting(
147 root_
.get(), NULL
, identity_matrix_
,
148 gfx::PointF(0.f
, 0.f
), gfx::Size(200, 200), true);
149 SetLayerPropertiesForTesting(
150 child_
.get(), root_
.get(), identity_matrix_
,
151 gfx::PointF(10.f
, 10.f
), gfx::Size(500, 500), true);
152 SetLayerPropertiesForTesting(
153 grand_child_
.get(), child_
.get(), identity_matrix_
,
154 gfx::PointF(-10.f
, -10.f
), gfx::Size(20, 500), true);
156 child_
->setMasksToBounds(true);
157 child_
->setForceRenderSurface(true);
159 child_
->set_expected_occlusion(gfx::Rect(0, 0, 10, 190));
160 root_
->set_expected_occlusion(gfx::Rect(10, 10, 190, 190));
162 m_layerTreeHost
->setRootLayer(root_
);
163 ThreadedTest::setupTree();
167 SINGLE_AND_MULTI_THREAD_TEST_F(
168 LayerTreeHostOcclusionTestOcclusionSurfaceClippingOpaque
);
170 class LayerTreeHostOcclusionTestOcclusionTwoChildren
:
171 public LayerTreeHostOcclusionTest
{
173 virtual void setupTree() OVERRIDE
{
174 // Add a second child to the root layer and the regions should merge
175 SetLayerPropertiesForTesting(
176 root_
.get(), NULL
, identity_matrix_
,
177 gfx::PointF(0.f
, 0.f
), gfx::Size(200, 200), true);
178 SetLayerPropertiesForTesting(
179 child_
.get(), root_
.get(), identity_matrix_
,
180 gfx::PointF(10.f
, 10.f
), gfx::Size(500, 500), false);
181 SetLayerPropertiesForTesting(
182 grand_child_
.get(), child_
.get(), identity_matrix_
,
183 gfx::PointF(-10.f
, -10.f
), gfx::Size(20, 500), true);
184 SetLayerPropertiesForTesting(
185 child2_
.get(), root_
.get(), identity_matrix_
,
186 gfx::PointF(20.f
, 10.f
), gfx::Size(10, 500), true);
188 child_
->setMasksToBounds(true);
189 child_
->setForceRenderSurface(true);
191 grand_child_
->set_expected_occlusion(gfx::Rect(10, 0, 10, 190));
192 child_
->set_expected_occlusion(gfx::Rect(0, 0, 20, 190));
193 root_
->set_expected_occlusion(gfx::Rect(10, 10, 20, 190));
195 m_layerTreeHost
->setRootLayer(root_
);
196 ThreadedTest::setupTree();
200 SINGLE_AND_MULTI_THREAD_TEST_F(
201 LayerTreeHostOcclusionTestOcclusionTwoChildren
)
203 class LayerTreeHostOcclusionTestOcclusionMask
:
204 public LayerTreeHostOcclusionTest
{
206 virtual void setupTree() OVERRIDE
{
207 // If the child layer has a mask on it, then it shouldn't contribute to
208 // occlusion on stuff below it.
209 SetLayerPropertiesForTesting(
210 root_
.get(), NULL
, identity_matrix_
,
211 gfx::PointF(0.f
, 0.f
), gfx::Size(200, 200), true);
212 SetLayerPropertiesForTesting(
213 child2_
.get(), root_
.get(), identity_matrix_
,
214 gfx::PointF(10.f
, 10.f
), gfx::Size(500, 500), true);
215 SetLayerPropertiesForTesting(
216 child_
.get(), root_
.get(), identity_matrix_
,
217 gfx::PointF(20.f
, 20.f
), gfx::Size(500, 500), true);
218 SetLayerPropertiesForTesting(
219 grand_child_
.get(), child_
.get(), identity_matrix_
,
220 gfx::PointF(-10.f
, -10.f
), gfx::Size(500, 500), true);
222 child_
->setMasksToBounds(true);
223 child_
->setForceRenderSurface(true);
224 child_
->setMaskLayer(mask_
.get());
226 child_
->set_expected_occlusion(gfx::Rect(0, 0, 180, 180));
227 root_
->set_expected_occlusion(gfx::Rect(10, 10, 190, 190));
229 m_layerTreeHost
->setRootLayer(root_
);
230 ThreadedTest::setupTree();
234 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostOcclusionTestOcclusionMask
)
236 class LayerTreeHostOcclusionTestOcclusionMaskBelowOcclusion
:
237 public LayerTreeHostOcclusionTest
{
239 virtual void setupTree() OVERRIDE
{
240 // If the child layer with a mask is below child2, then child2 should
241 // contribute to occlusion on everything, and child shouldn't contribute
243 SetLayerPropertiesForTesting(
244 root_
.get(), NULL
, identity_matrix_
,
245 gfx::PointF(0.f
, 0.f
), gfx::Size(200, 200), true);
246 SetLayerPropertiesForTesting(
247 child_
.get(), root_
.get(), identity_matrix_
,
248 gfx::PointF(10.f
, 10.f
), gfx::Size(500, 500), true);
249 SetLayerPropertiesForTesting(
250 grand_child_
.get(), child_
.get(), identity_matrix_
,
251 gfx::PointF(-10.f
, -10.f
), gfx::Size(20, 500), true);
252 SetLayerPropertiesForTesting(
253 child2_
.get(), root_
.get(), identity_matrix_
,
254 gfx::PointF(20.f
, 10.f
), gfx::Size(10, 500), true);
256 child_
->setMasksToBounds(true);
257 child_
->setForceRenderSurface(true);
258 child_
->setMaskLayer(mask_
.get());
260 grand_child_
->set_expected_occlusion(gfx::Rect(10, 0, 10, 190));
261 child_
->set_expected_occlusion(gfx::Rect(0, 0, 20, 190));
262 root_
->set_expected_occlusion(gfx::Rect(20, 10, 10, 190));
264 m_layerTreeHost
->setRootLayer(root_
);
265 ThreadedTest::setupTree();
269 SINGLE_AND_MULTI_THREAD_TEST_F(
270 LayerTreeHostOcclusionTestOcclusionMaskBelowOcclusion
)
272 class LayerTreeHostOcclusionTestOcclusionOpacity
:
273 public LayerTreeHostOcclusionTest
{
275 virtual void setupTree() OVERRIDE
{
276 // If the child layer has a non-opaque opacity, then it shouldn't
277 // contribute to occlusion on stuff below it
278 SetLayerPropertiesForTesting(
279 root_
.get(), NULL
, identity_matrix_
,
280 gfx::PointF(0.f
, 0.f
), gfx::Size(200, 200), true);
281 SetLayerPropertiesForTesting(
282 child2_
.get(), root_
.get(), identity_matrix_
,
283 gfx::PointF(20.f
, 10.f
), gfx::Size(10, 500), true);
284 SetLayerPropertiesForTesting(
285 child_
.get(), root_
.get(), identity_matrix_
,
286 gfx::PointF(10.f
, 10.f
), gfx::Size(500, 500), true);
287 SetLayerPropertiesForTesting(
288 grand_child_
.get(), child_
.get(), identity_matrix_
,
289 gfx::PointF(-10.f
, -10.f
), gfx::Size(20, 500), true);
291 child_
->setMasksToBounds(true);
292 child_
->setForceRenderSurface(true);
293 child_
->setOpacity(0.5f
);
295 child_
->set_expected_occlusion(gfx::Rect(0, 0, 10, 190));
296 root_
->set_expected_occlusion(gfx::Rect(20, 10, 10, 190));
298 m_layerTreeHost
->setRootLayer(root_
);
299 ThreadedTest::setupTree();
303 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostOcclusionTestOcclusionOpacity
)
305 class LayerTreeHostOcclusionTestOcclusionOpacityBelowOcclusion
:
306 public LayerTreeHostOcclusionTest
{
308 virtual void setupTree() OVERRIDE
{
309 // If the child layer with non-opaque opacity is below child2, then
310 // child2 should contribute to occlusion on everything, and child shouldn't
311 // contribute to the root_.
312 SetLayerPropertiesForTesting(
313 root_
.get(), NULL
, identity_matrix_
,
314 gfx::PointF(0.f
, 0.f
), gfx::Size(200, 200), true);
315 SetLayerPropertiesForTesting(
316 child_
.get(), root_
.get(), identity_matrix_
,
317 gfx::PointF(10.f
, 10.f
), gfx::Size(500, 500), true);
318 SetLayerPropertiesForTesting(
319 grand_child_
.get(), child_
.get(), identity_matrix_
,
320 gfx::PointF(-10.f
, -10.f
), gfx::Size(20, 500), true);
321 SetLayerPropertiesForTesting(
322 child2_
.get(), root_
.get(), identity_matrix_
,
323 gfx::PointF(20.f
, 10.f
), gfx::Size(10, 500), true);
325 child_
->setMasksToBounds(true);
326 child_
->setForceRenderSurface(true);
327 child_
->setOpacity(0.5f
);
329 grand_child_
->set_expected_occlusion(gfx::Rect(10, 0, 10, 190));
330 child_
->set_expected_occlusion(gfx::Rect(0, 0, 20, 190));
331 root_
->set_expected_occlusion(gfx::Rect(20, 10, 10, 190));
333 m_layerTreeHost
->setRootLayer(root_
);
334 ThreadedTest::setupTree();
338 SINGLE_AND_MULTI_THREAD_TEST_F(
339 LayerTreeHostOcclusionTestOcclusionOpacityBelowOcclusion
)
341 class LayerTreeHostOcclusionTestOcclusionOpacityFilter
:
342 public LayerTreeHostOcclusionTest
{
344 virtual void setupTree() OVERRIDE
{
345 gfx::Transform childTransform
;
346 childTransform
.Translate(250.0, 250.0);
347 childTransform
.Rotate(90.0);
348 childTransform
.Translate(-250.0, -250.0);
350 WebKit::WebFilterOperations filters
;
351 filters
.append(WebKit::WebFilterOperation::createOpacityFilter(0.5));
353 // If the child layer has a filter that changes alpha values, and is below
354 // child2, then child2 should contribute to occlusion on everything,
355 // and child shouldn't contribute to the root
356 SetLayerPropertiesForTesting(
357 root_
.get(), NULL
, identity_matrix_
,
358 gfx::PointF(0.f
, 0.f
), gfx::Size(200, 200), true);
359 SetLayerPropertiesForTesting(
360 child_
.get(), root_
.get(), childTransform
,
361 gfx::PointF(30.f
, 30.f
), gfx::Size(500, 500), true);
362 SetLayerPropertiesForTesting(
363 grand_child_
.get(), child_
.get(), identity_matrix_
,
364 gfx::PointF(10.f
, 10.f
), gfx::Size(500, 500), true);
365 SetLayerPropertiesForTesting(
366 child2_
.get(), root_
.get(), identity_matrix_
,
367 gfx::PointF(10.f
, 70.f
), gfx::Size(500, 500), true);
369 child_
->setMasksToBounds(true);
370 child_
->setFilters(filters
);
372 grand_child_
->set_expected_occlusion(gfx::Rect(40, 330, 130, 190));
373 child_
->set_expected_occlusion(UnionRegions(
374 gfx::Rect(10, 330, 160, 170), gfx::Rect(40, 500, 130, 20)));
375 root_
->set_expected_occlusion(gfx::Rect(10, 70, 190, 130));
377 m_layerTreeHost
->setRootLayer(root_
);
378 ThreadedTest::setupTree();
382 SINGLE_AND_MULTI_THREAD_TEST_F(
383 LayerTreeHostOcclusionTestOcclusionOpacityFilter
)
385 class LayerTreeHostOcclusionTestOcclusionBlurFilter
:
386 public LayerTreeHostOcclusionTest
{
388 virtual void setupTree() OVERRIDE
{
389 gfx::Transform childTransform
;
390 childTransform
.Translate(250.0, 250.0);
391 childTransform
.Rotate(90.0);
392 childTransform
.Translate(-250.0, -250.0);
394 WebKit::WebFilterOperations filters
;
395 filters
.append(WebKit::WebFilterOperation::createBlurFilter(10));
397 // If the child layer has a filter that moves pixels/changes alpha, and is
398 // below child2, then child should not inherit occlusion from outside its
399 // subtree, and should not contribute to the root
400 SetLayerPropertiesForTesting(
401 root_
.get(), NULL
, identity_matrix_
,
402 gfx::PointF(0.f
, 0.f
), gfx::Size(200, 200), true);
403 SetLayerPropertiesForTesting(
404 child_
.get(), root_
.get(), childTransform
,
405 gfx::PointF(30.f
, 30.f
), gfx::Size(500, 500), true);
406 SetLayerPropertiesForTesting(
407 grand_child_
.get(), child_
.get(), identity_matrix_
,
408 gfx::PointF(10.f
, 10.f
), gfx::Size(500, 500), true);
409 SetLayerPropertiesForTesting(
410 child2_
.get(), root_
.get(), identity_matrix_
,
411 gfx::PointF(10.f
, 70.f
), gfx::Size(500, 500), true);
413 child_
->setMasksToBounds(true);
414 child_
->setFilters(filters
);
416 child_
->set_expected_occlusion(gfx::Rect(10, 330, 160, 170));
417 root_
->set_expected_occlusion(gfx::Rect(10, 70, 190, 130));
419 m_layerTreeHost
->setRootLayer(root_
);
420 ThreadedTest::setupTree();
424 SINGLE_AND_MULTI_THREAD_TEST_F(
425 LayerTreeHostOcclusionTestOcclusionBlurFilter
)
427 class LayerTreeHostOcclusionTestManySurfaces
:
428 public LayerTreeHostOcclusionTest
{
430 virtual void setupTree() OVERRIDE
{
431 // We create enough RenderSurfaces that it will trigger Vector reallocation
432 // while computing occlusion.
433 std::vector
<scoped_refptr
<TestLayer
> > layers
;
434 int num_surfaces
= 200;
435 int root_width
= 400;
436 int root_height
= 400;
438 for (int i
= 0; i
< num_surfaces
; ++i
) {
439 layers
.push_back(TestLayer::Create());
441 SetLayerPropertiesForTesting(
442 layers
.back().get(), NULL
, identity_matrix_
,
443 gfx::PointF(0.f
, 0.f
),
444 gfx::Size(root_width
, root_height
), true);
445 layers
.back()->createRenderSurface();
447 SetLayerPropertiesForTesting(
448 layers
.back().get(), layers
[layers
.size() - 2].get(),
450 gfx::PointF(1.f
, 1.f
),
451 gfx::Size(root_width
-i
, root_height
-i
), true);
452 layers
.back()->setForceRenderSurface(true);
456 for (int i
= 1; i
< num_surfaces
; ++i
) {
457 scoped_refptr
<TestLayer
> child
= TestLayer::Create();
458 SetLayerPropertiesForTesting(
459 child
.get(), layers
[i
].get(), identity_matrix_
,
460 gfx::PointF(0.f
, 0.f
), gfx::Size(root_width
, root_height
), false);
463 for (int i
= 0; i
< num_surfaces
-1; ++i
) {
464 gfx::Rect
expected_occlusion(1, 1, root_width
-i
-1, root_height
-i
-1);
465 layers
[i
]->set_expected_occlusion(expected_occlusion
);
468 m_layerTreeHost
->setRootLayer(layers
[0].get());
469 ThreadedTest::setupTree();
473 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostOcclusionTestManySurfaces
)