Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ui/gfx/compositor/layer.h" | 5 #include "ui/gfx/compositor/layer.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/memory/scoped_ptr.h" | 10 #include "base/memory/scoped_ptr.h" |
| (...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 307 invalid_rect_ = gfx::Rect(); | 307 invalid_rect_ = gfx::Rect(); |
| 308 return; | 308 return; |
| 309 } | 309 } |
| 310 scoped_ptr<gfx::Canvas> canvas(gfx::Canvas::CreateCanvas( | 310 scoped_ptr<gfx::Canvas> canvas(gfx::Canvas::CreateCanvas( |
| 311 draw_rect.width(), draw_rect.height(), false)); | 311 draw_rect.width(), draw_rect.height(), false)); |
| 312 canvas->TranslateInt(-draw_rect.x(), -draw_rect.y()); | 312 canvas->TranslateInt(-draw_rect.x(), -draw_rect.y()); |
| 313 delegate_->OnPaintLayer(canvas.get()); | 313 delegate_->OnPaintLayer(canvas.get()); |
| 314 SetCanvas(*canvas->GetSkCanvas(), draw_rect.origin()); | 314 SetCanvas(*canvas->GetSkCanvas(), draw_rect.origin()); |
| 315 } | 315 } |
| 316 | 316 |
| 317 void Layer::RecomputeHole() { | 317 void Layer::ClearHoleRects() { |
| 318 if (type_ == LAYER_HAS_NO_TEXTURE) | 318 hole_rect_ = gfx::Rect(); |
| 319 | |
| 320 for (size_t i = 0; i < children_.size(); i++) | |
| 321 children_[i]->ClearHoleRects(); | |
| 322 } | |
| 323 | |
| 324 void Layer::GeneratePreorderTraversal( | |
| 325 std::vector<ui::Layer*>* layer_traversal) { | |
| 326 if (!visible_) | |
| 319 return; | 327 return; |
| 320 | 328 |
| 321 // Reset to default. | 329 if (fills_bounds_opaquely_ && type_ == LAYER_HAS_TEXTURE) |
| 322 hole_rect_ = gfx::Rect(); | 330 layer_traversal->push_back(this); |
| 323 | 331 |
| 324 // Find the largest hole | 332 for (size_t i = 0; i < children_.size(); i++) |
| 325 for (size_t i = 0; i < children_.size(); ++i) { | 333 children_[i]->GeneratePreorderTraversal(layer_traversal); |
| 326 // Ignore non-opaque and hidden children. | 334 } |
| 327 if (!children_[i]->IsCompletelyOpaque() || !children_[i]->visible_) | |
| 328 continue; | |
| 329 | 335 |
| 330 // Ignore children that aren't rotated by multiples of 90 degrees. | 336 void Layer::RecomputeHole() { |
|
sky
2011/10/24 15:44:52
I don't like all the tree walking we do on any int
| |
| 331 float degrees; | 337 Layer* root_layer = this; |
| 332 if (!InterpolatedTransform::FactorTRS(children_[i]->transform(), | 338 while (root_layer->parent_) { |
| 333 NULL, °rees, NULL) || | 339 root_layer = root_layer->parent_; |
| 334 !IsApproximateMultilpleOf(degrees, 90.0f)) | |
| 335 continue; | |
| 336 | |
| 337 // The reason why we don't just take the bounds and apply the transform is | |
| 338 // that the bounds encodes a position, too, so the effective transformation | |
| 339 // matrix is actually different that the one reported. As well, the bounds | |
| 340 // will not necessarily be at the origin. | |
| 341 gfx::Rect candidate_hole(children_[i]->bounds_.size()); | |
| 342 ui::Transform transform = children_[i]->transform(); | |
| 343 transform.ConcatTranslate(static_cast<float>(children_[i]->bounds_.x()), | |
| 344 static_cast<float>(children_[i]->bounds_.y())); | |
| 345 transform.TransformRect(&candidate_hole); | |
| 346 | |
| 347 // This layer might not contain the child (e.g., a portion of the child may | |
| 348 // be offscreen). Only the portion of the child that overlaps this layer is | |
| 349 // of any importance, so take the intersection. | |
| 350 candidate_hole = gfx::Rect(bounds().size()).Intersect(candidate_hole); | |
| 351 | |
| 352 // Ensure we have the largest hole. | |
| 353 if (candidate_hole.size().GetArea() > hole_rect_.size().GetArea()) | |
| 354 hole_rect_ = candidate_hole; | |
| 355 } | 340 } |
| 356 | 341 |
| 357 // Free up texture memory if the hole fills bounds of layer. | 342 std::vector<ui::Layer*> layer_traversal; |
| 358 if (!ShouldDraw() && !layer_updated_externally_) | 343 root_layer->ClearHoleRects(); |
| 359 texture_ = NULL; | 344 root_layer->GeneratePreorderTraversal(&layer_traversal); |
| 360 } | |
| 361 | 345 |
| 362 bool Layer::IsCompletelyOpaque() const { | 346 for (size_t i = 0; i < layer_traversal.size(); i++) { |
| 363 return fills_bounds_opaquely() && GetCombinedOpacity() == 1.0f; | 347 Layer* layer = layer_traversal[i]; |
| 348 gfx::Rect bounds = gfx::Rect(layer->bounds().size()); | |
| 349 ui::Transform layer_transform; | |
| 350 layer->GetTransformRelativeTo(root_layer, &layer_transform); | |
| 351 | |
| 352 // Iterate through layers which are after layer_traversal[i] in draw order | |
| 353 // and find the largest candidate hole. | |
| 354 for (size_t j = i + 1; j < layer_traversal.size(); j++) { | |
| 355 gfx::Rect candidate_hole = gfx::Rect(layer_traversal[j]->bounds().size()); | |
| 356 | |
| 357 // Compute transform to go from bounds of layer |j| to local bounds of lay er |i|. | |
|
sky
2011/10/24 15:44:52
This line is > 80 chars
| |
| 358 ui::Transform candidate_hole_transform; | |
| 359 layer_traversal[j]->GetTransformRelativeTo(root_layer, | |
|
sky
2011/10/24 15:44:52
This is a lot of transform building. Rather than h
| |
| 360 &candidate_hole_transform); | |
| 361 if (!layer_transform.Invert()) | |
| 362 continue; | |
| 363 candidate_hole_transform.ConcatTransform(layer_transform); | |
| 364 | |
| 365 // cannot punch a hole if the relative transform between the two layers | |
| 366 // is not multiple of 90. | |
| 367 float degrees; | |
| 368 if (!InterpolatedTransform::FactorTRS(candidate_hole_transform, NULL, | |
| 369 °rees, NULL) || !IsApproximateMultilpleOf(degrees, 90.0f)) | |
| 370 continue; | |
| 371 | |
| 372 // can only punch a hole if the two layers have the same opacity. | |
| 373 if (layer->GetCombinedOpacity() != | |
| 374 layer_traversal[j]->GetCombinedOpacity()) | |
|
Ian Vollick
2011/10/22 01:06:03
Shouldn't we punch a hole only if layer_traversal[
| |
| 375 continue; | |
| 376 | |
| 377 candidate_hole_transform.TransformRect(&candidate_hole); | |
| 378 candidate_hole = candidate_hole.Intersect(bounds); | |
| 379 | |
| 380 if (candidate_hole.size().GetArea() > layer->hole_rect().size().GetArea()) | |
| 381 layer->set_hole_rect(candidate_hole); | |
| 382 } | |
| 383 // Free up texture memory if the hole fills bounds of layer. | |
| 384 if (!layer->ShouldDraw() && !layer_updated_externally()) | |
| 385 layer->DropTexture(); | |
| 386 } | |
| 364 } | 387 } |
| 365 | 388 |
| 366 // static | 389 // static |
| 367 void Layer::PunchHole(const gfx::Rect& rect, | 390 void Layer::PunchHole(const gfx::Rect& rect, |
| 368 const gfx::Rect& region_to_punch_out, | 391 const gfx::Rect& region_to_punch_out, |
| 369 std::vector<gfx::Rect>* sides) { | 392 std::vector<gfx::Rect>* sides) { |
| 370 gfx::Rect trimmed_rect = rect.Intersect(region_to_punch_out); | 393 gfx::Rect trimmed_rect = rect.Intersect(region_to_punch_out); |
| 371 | 394 |
| 372 if (trimmed_rect.IsEmpty()) { | 395 if (trimmed_rect.IsEmpty()) { |
| 373 sides->push_back(rect); | 396 sides->push_back(rect); |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 392 rect.right() - trimmed_rect.right(), | 415 rect.right() - trimmed_rect.right(), |
| 393 trimmed_rect.height())); | 416 trimmed_rect.height())); |
| 394 | 417 |
| 395 // Bottom (below the hole). | 418 // Bottom (below the hole). |
| 396 sides->push_back(gfx::Rect(rect.x(), | 419 sides->push_back(gfx::Rect(rect.x(), |
| 397 trimmed_rect.bottom(), | 420 trimmed_rect.bottom(), |
| 398 rect.width(), | 421 rect.width(), |
| 399 rect.bottom() - trimmed_rect.bottom())); | 422 rect.bottom() - trimmed_rect.bottom())); |
| 400 } | 423 } |
| 401 | 424 |
| 425 void Layer::DropTexture() { | |
| 426 if (!layer_updated_externally_) | |
| 427 texture_ = NULL; | |
| 428 } | |
| 429 | |
| 402 void Layer::DropTextures() { | 430 void Layer::DropTextures() { |
| 403 if (!layer_updated_externally_) | 431 if (!layer_updated_externally_) |
| 404 texture_ = NULL; | 432 texture_ = NULL; |
| 405 for (size_t i = 0; i < children_.size(); ++i) | 433 for (size_t i = 0; i < children_.size(); ++i) |
| 406 children_[i]->DropTextures(); | 434 children_[i]->DropTextures(); |
| 407 } | 435 } |
| 408 | 436 |
| 409 bool Layer::ConvertPointForAncestor(const Layer* ancestor, | 437 bool Layer::ConvertPointForAncestor(const Layer* ancestor, |
| 410 gfx::Point* point) const { | 438 gfx::Point* point) const { |
| 411 ui::Transform transform; | 439 ui::Transform transform; |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 469 } | 497 } |
| 470 | 498 |
| 471 void Layer::SetTransformImmediately(const ui::Transform& transform) { | 499 void Layer::SetTransformImmediately(const ui::Transform& transform) { |
| 472 transform_ = transform; | 500 transform_ = transform; |
| 473 | 501 |
| 474 if (parent()) | 502 if (parent()) |
| 475 parent()->RecomputeHole(); | 503 parent()->RecomputeHole(); |
| 476 } | 504 } |
| 477 | 505 |
| 478 void Layer::SetOpacityImmediately(float opacity) { | 506 void Layer::SetOpacityImmediately(float opacity) { |
| 479 bool was_opaque = GetCombinedOpacity() == 1.0f; | |
| 480 opacity_ = opacity; | 507 opacity_ = opacity; |
| 481 bool is_opaque = GetCombinedOpacity() == 1.0f; | 508 if (parent_) |
| 482 | 509 parent_->RecomputeHole(); |
| 483 // If our opacity has changed we need to recompute our hole, our parent's hole | |
| 484 // and the holes of all our descendants. | |
| 485 if (was_opaque != is_opaque) { | |
| 486 if (parent_) | |
| 487 parent_->RecomputeHole(); | |
| 488 std::queue<Layer*> to_process; | |
| 489 to_process.push(this); | |
| 490 while (!to_process.empty()) { | |
| 491 Layer* current = to_process.front(); | |
| 492 to_process.pop(); | |
| 493 current->RecomputeHole(); | |
| 494 for (size_t i = 0; i < current->children_.size(); ++i) | |
| 495 to_process.push(current->children_.at(i)); | |
| 496 } | |
| 497 } | |
| 498 } | 510 } |
| 499 | 511 |
| 500 void Layer::SetBoundsFromAnimator(const gfx::Rect& bounds) { | 512 void Layer::SetBoundsFromAnimator(const gfx::Rect& bounds) { |
| 501 SetBoundsImmediately(bounds); | 513 SetBoundsImmediately(bounds); |
| 502 } | 514 } |
| 503 | 515 |
| 504 void Layer::SetTransformFromAnimator(const Transform& transform) { | 516 void Layer::SetTransformFromAnimator(const Transform& transform) { |
| 505 SetTransformImmediately(transform); | 517 SetTransformImmediately(transform); |
| 506 } | 518 } |
| 507 | 519 |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 575 result.append(", style=filled"); | 587 result.append(", style=filled"); |
| 576 | 588 |
| 577 return result; | 589 return result; |
| 578 } | 590 } |
| 579 | 591 |
| 580 #endif | 592 #endif |
| 581 | 593 |
| 582 //////////////////////////////////////////////////////////////////////////////// | 594 //////////////////////////////////////////////////////////////////////////////// |
| 583 | 595 |
| 584 } // namespace ui | 596 } // namespace ui |
| OLD | NEW |