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. 4 5 #include "cc/trees/layer_tree_host.h" 6 7 #include "cc/layers/layer.h" 8 #include "cc/test/layer_tree_test.h" 9 #include "cc/test/occlusion_tracker_test_common.h" 10 11 namespace cc { 12 namespace { 13 14 class TestLayer : public Layer { 15 public: 16 static scoped_refptr<TestLayer> Create() { 17 return make_scoped_refptr(new TestLayer()); 18 } 19 20 virtual bool Update( 21 ResourceUpdateQueue* update_queue, 22 const OcclusionTracker* occlusion) OVERRIDE { 23 if (!occlusion) 24 return false; 25 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()); 32 return false; 33 } 34 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; 39 } 40 41 private: 42 TestLayer() : Layer() { 43 SetIsDrawable(true); 44 } 45 virtual ~TestLayer() {} 46 47 Region occlusion_; 48 Region expected_occlusion_; 49 }; 50 51 class LayerTreeHostOcclusionTest : public LayerTreeTest { 52 public: 53 LayerTreeHostOcclusionTest() 54 : root_(TestLayer::Create()), 55 child_(TestLayer::Create()), 56 child2_(TestLayer::Create()), 57 grand_child_(TestLayer::Create()), 58 mask_(TestLayer::Create()) { 59 } 60 61 virtual void BeginTest() OVERRIDE { 62 PostSetNeedsCommitToMainThread(); 63 } 64 65 virtual void DidCommit() OVERRIDE { 66 TestLayer* root = static_cast<TestLayer*>(layer_tree_host()->root_layer()); 67 VerifyOcclusion(root); 68 69 EndTest(); 70 } 71 72 virtual void AfterTest() OVERRIDE {} 73 74 void VerifyOcclusion(TestLayer* layer) const { 75 EXPECT_EQ(layer->expected_occlusion().ToString(), 76 layer->occlusion().ToString()); 77 78 for (size_t i = 0; i < layer->children().size(); ++i) { 79 TestLayer* child = static_cast<TestLayer*>(layer->children()[i].get()); 80 VerifyOcclusion(child); 81 } 82 } 83 84 void SetLayerPropertiesForTesting(TestLayer* layer, 85 TestLayer* parent, 86 const gfx::Transform& transform, 87 gfx::PointF position, 88 gfx::Size bounds, 89 bool opaque) const { 90 layer->RemoveAllChildren(); 91 if (parent) 92 parent->AddChild(layer); 93 layer->SetTransform(transform); 94 layer->SetPosition(position); 95 layer->SetBounds(bounds); 96 layer->SetContentsOpaque(opaque); 97 98 layer->SetAnchorPoint(gfx::PointF()); 99 } 100 101 protected: 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_; 107 108 gfx::Transform identity_matrix_; 109 }; 110 111 112 class LayerTreeHostOcclusionTestOcclusionSurfaceClipping 113 : public LayerTreeHostOcclusionTest { 114 public: 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); 127 128 child_->SetMasksToBounds(true); 129 child_->SetForceRenderSurface(true); 130 131 child_->set_expected_occlusion(gfx::Rect(0, 0, 10, 190)); 132 root_->set_expected_occlusion(gfx::Rect(10, 10, 10, 190)); 133 134 layer_tree_host()->SetRootLayer(root_); 135 LayerTreeTest::SetupTree(); 136 } 137 }; 138 139 SINGLE_AND_MULTI_THREAD_TEST_F( 140 LayerTreeHostOcclusionTestOcclusionSurfaceClipping); 141 142 class LayerTreeHostOcclusionTestOcclusionSurfaceClippingOpaque 143 : public LayerTreeHostOcclusionTest { 144 public: 145 virtual void SetupTree() OVERRIDE { 146 // If the child layer is opaque, then it adds to the occlusion seen by the 147 // root_. 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); 157 158 child_->SetMasksToBounds(true); 159 child_->SetForceRenderSurface(true); 160 161 child_->set_expected_occlusion(gfx::Rect(0, 0, 10, 190)); 162 root_->set_expected_occlusion(gfx::Rect(10, 10, 190, 190)); 163 164 layer_tree_host()->SetRootLayer(root_); 165 LayerTreeTest::SetupTree(); 166 } 167 }; 168 169 SINGLE_AND_MULTI_THREAD_TEST_F( 170 LayerTreeHostOcclusionTestOcclusionSurfaceClippingOpaque); 171 172 class LayerTreeHostOcclusionTestOcclusionTwoChildren 173 : public LayerTreeHostOcclusionTest { 174 public: 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); 189 190 child_->SetMasksToBounds(true); 191 child_->SetForceRenderSurface(true); 192 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)); 196 197 layer_tree_host()->SetRootLayer(root_); 198 LayerTreeTest::SetupTree(); 199 } 200 }; 201 202 SINGLE_AND_MULTI_THREAD_TEST_F( 203 LayerTreeHostOcclusionTestOcclusionTwoChildren); 204 205 class LayerTreeHostOcclusionTestOcclusionMask 206 : public LayerTreeHostOcclusionTest { 207 public: 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); 223 224 child_->SetMasksToBounds(true); 225 child_->SetForceRenderSurface(true); 226 child_->SetMaskLayer(mask_.get()); 227 228 child_->set_expected_occlusion(gfx::Rect(0, 0, 180, 180)); 229 root_->set_expected_occlusion(gfx::Rect(10, 10, 190, 190)); 230 231 layer_tree_host()->SetRootLayer(root_); 232 LayerTreeTest::SetupTree(); 233 } 234 }; 235 236 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostOcclusionTestOcclusionMask); 237 238 class LayerTreeHostOcclusionTestOcclusionMaskBelowOcclusion 239 : public LayerTreeHostOcclusionTest { 240 public: 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 244 // to the root_. 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); 257 258 child_->SetMasksToBounds(true); 259 child_->SetForceRenderSurface(true); 260 child_->SetMaskLayer(mask_.get()); 261 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)); 265 266 layer_tree_host()->SetRootLayer(root_); 267 LayerTreeTest::SetupTree(); 268 } 269 }; 270 271 SINGLE_AND_MULTI_THREAD_TEST_F( 272 LayerTreeHostOcclusionTestOcclusionMaskBelowOcclusion); 273 274 class LayerTreeHostOcclusionTestOcclusionOpacity 275 : public LayerTreeHostOcclusionTest { 276 public: 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); 292 293 child_->SetMasksToBounds(true); 294 child_->SetForceRenderSurface(true); 295 child_->SetOpacity(0.5f); 296 297 child_->set_expected_occlusion(gfx::Rect(0, 0, 10, 190)); 298 root_->set_expected_occlusion(gfx::Rect(20, 10, 10, 190)); 299 300 layer_tree_host()->SetRootLayer(root_); 301 LayerTreeTest::SetupTree(); 302 } 303 }; 304 305 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostOcclusionTestOcclusionOpacity); 306 307 class LayerTreeHostOcclusionTestOcclusionOpacityBelowOcclusion 308 : public LayerTreeHostOcclusionTest { 309 public: 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); 326 327 child_->SetMasksToBounds(true); 328 child_->SetForceRenderSurface(true); 329 child_->SetOpacity(0.5f); 330 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)); 334 335 layer_tree_host()->SetRootLayer(root_); 336 LayerTreeTest::SetupTree(); 337 } 338 }; 339 340 SINGLE_AND_MULTI_THREAD_TEST_F( 341 LayerTreeHostOcclusionTestOcclusionOpacityBelowOcclusion); 342 343 class LayerTreeHostOcclusionTestOcclusionOpacityFilter 344 : public LayerTreeHostOcclusionTest { 345 public: 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); 351 352 FilterOperations filters; 353 filters.Append(FilterOperation::CreateOpacityFilter(0.5f)); 354 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); 370 371 child_->SetMasksToBounds(true); 372 child_->SetFilters(filters); 373 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)); 378 379 layer_tree_host()->SetRootLayer(root_); 380 LayerTreeTest::SetupTree(); 381 } 382 }; 383 384 SINGLE_AND_MULTI_THREAD_TEST_F( 385 LayerTreeHostOcclusionTestOcclusionOpacityFilter); 386 387 class LayerTreeHostOcclusionTestOcclusionBlurFilter 388 : public LayerTreeHostOcclusionTest { 389 public: 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); 395 396 FilterOperations filters; 397 filters.Append(FilterOperation::CreateBlurFilter(10.f)); 398 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); 414 415 child_->SetMasksToBounds(true); 416 child_->SetFilters(filters); 417 418 child_->set_expected_occlusion(gfx::Rect(10, 330, 160, 170)); 419 root_->set_expected_occlusion(gfx::Rect(10, 70, 190, 130)); 420 421 layer_tree_host()->SetRootLayer(root_); 422 LayerTreeTest::SetupTree(); 423 } 424 }; 425 426 SINGLE_AND_MULTI_THREAD_TEST_F( 427 LayerTreeHostOcclusionTestOcclusionBlurFilter); 428 429 class LayerTreeHostOcclusionTestManySurfaces 430 : public LayerTreeHostOcclusionTest { 431 public: 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; 439 440 for (int i = 0; i < num_surfaces; ++i) { 441 layers.push_back(TestLayer::Create()); 442 if (i == 0) { 443 SetLayerPropertiesForTesting( 444 layers.back().get(), NULL, identity_matrix_, 445 gfx::PointF(0.f, 0.f), 446 gfx::Size(root_width, root_height), true); 447 } else { 448 SetLayerPropertiesForTesting( 449 layers.back().get(), layers[layers.size() - 2].get(), 450 identity_matrix_, 451 gfx::PointF(1.f, 1.f), 452 gfx::Size(root_width-i, root_height-i), true); 453 layers.back()->SetForceRenderSurface(true); 454 } 455 } 456 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); 462 } 463 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); 467 } 468 469 layer_tree_host()->SetRootLayer(layers[0]); 470 LayerTreeTest::SetupTree(); 471 } 472 }; 473 474 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostOcclusionTestManySurfaces); 475 476 } // namespace 477 } // namespace cc 478