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 18 matching lines...) Expand all Loading... |
29 } // namespace | 29 } // namespace |
30 | 30 |
31 namespace ui { | 31 namespace ui { |
32 | 32 |
33 Layer::Layer(Compositor* compositor) | 33 Layer::Layer(Compositor* compositor) |
34 : type_(LAYER_HAS_TEXTURE), | 34 : type_(LAYER_HAS_TEXTURE), |
35 compositor_(compositor), | 35 compositor_(compositor), |
36 parent_(NULL), | 36 parent_(NULL), |
37 visible_(true), | 37 visible_(true), |
38 fills_bounds_opaquely_(true), | 38 fills_bounds_opaquely_(true), |
| 39 recompute_hole_(false), |
39 layer_updated_externally_(false), | 40 layer_updated_externally_(false), |
40 opacity_(1.0f), | 41 opacity_(1.0f), |
41 delegate_(NULL) { | 42 delegate_(NULL) { |
42 #if defined(USE_WEBKIT_COMPOSITOR) | 43 #if defined(USE_WEBKIT_COMPOSITOR) |
43 CreateWebLayer(); | 44 CreateWebLayer(); |
44 #endif | 45 #endif |
45 } | 46 } |
46 | 47 |
47 Layer::Layer(Compositor* compositor, LayerType type) | 48 Layer::Layer(Compositor* compositor, LayerType type) |
48 : type_(type), | 49 : type_(type), |
49 compositor_(compositor), | 50 compositor_(compositor), |
50 parent_(NULL), | 51 parent_(NULL), |
51 visible_(true), | 52 visible_(true), |
52 fills_bounds_opaquely_(true), | 53 fills_bounds_opaquely_(true), |
| 54 recompute_hole_(false), |
53 layer_updated_externally_(false), | 55 layer_updated_externally_(false), |
54 opacity_(1.0f), | 56 opacity_(1.0f), |
55 delegate_(NULL) { | 57 delegate_(NULL) { |
56 #if defined(USE_WEBKIT_COMPOSITOR) | 58 #if defined(USE_WEBKIT_COMPOSITOR) |
57 CreateWebLayer(); | 59 CreateWebLayer(); |
58 #endif | 60 #endif |
59 } | 61 } |
60 | 62 |
61 Layer::~Layer() { | 63 Layer::~Layer() { |
62 if (parent_) | 64 if (parent_) |
(...skipping 20 matching lines...) Expand all Loading... |
83 | 85 |
84 void Layer::Add(Layer* child) { | 86 void Layer::Add(Layer* child) { |
85 if (child->parent_) | 87 if (child->parent_) |
86 child->parent_->Remove(child); | 88 child->parent_->Remove(child); |
87 child->parent_ = this; | 89 child->parent_ = this; |
88 children_.push_back(child); | 90 children_.push_back(child); |
89 #if defined(USE_WEBKIT_COMPOSITOR) | 91 #if defined(USE_WEBKIT_COMPOSITOR) |
90 web_layer_.addChild(child->web_layer_); | 92 web_layer_.addChild(child->web_layer_); |
91 #endif | 93 #endif |
92 | 94 |
93 RecomputeHole(); | 95 SetNeedsToRecomputeHole(); |
94 } | 96 } |
95 | 97 |
96 void Layer::Remove(Layer* child) { | 98 void Layer::Remove(Layer* child) { |
97 std::vector<Layer*>::iterator i = | 99 std::vector<Layer*>::iterator i = |
98 std::find(children_.begin(), children_.end(), child); | 100 std::find(children_.begin(), children_.end(), child); |
99 DCHECK(i != children_.end()); | 101 DCHECK(i != children_.end()); |
100 children_.erase(i); | 102 children_.erase(i); |
101 child->parent_ = NULL; | 103 child->parent_ = NULL; |
102 #if defined(USE_WEBKIT_COMPOSITOR) | 104 #if defined(USE_WEBKIT_COMPOSITOR) |
103 child->web_layer_.removeFromParent(); | 105 child->web_layer_.removeFromParent(); |
104 #endif | 106 #endif |
105 | 107 |
106 RecomputeHole(); | 108 SetNeedsToRecomputeHole(); |
107 | 109 |
108 child->DropTextures(); | 110 child->DropTextures(); |
109 } | 111 } |
110 | 112 |
111 void Layer::MoveToFront(Layer* child) { | 113 void Layer::MoveToFront(Layer* child) { |
112 std::vector<Layer*>::iterator i = | 114 std::vector<Layer*>::iterator i = |
113 std::find(children_.begin(), children_.end(), child); | 115 std::find(children_.begin(), children_.end(), child); |
114 DCHECK(i != children_.end()); | 116 DCHECK(i != children_.end()); |
115 children_.erase(i); | 117 children_.erase(i); |
116 children_.push_back(child); | 118 children_.push_back(child); |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
178 return; | 180 return; |
179 | 181 |
180 bool was_drawn = IsDrawn(); | 182 bool was_drawn = IsDrawn(); |
181 visible_ = visible; | 183 visible_ = visible; |
182 bool is_drawn = IsDrawn(); | 184 bool is_drawn = IsDrawn(); |
183 if (was_drawn == is_drawn) | 185 if (was_drawn == is_drawn) |
184 return; | 186 return; |
185 | 187 |
186 if (!is_drawn) | 188 if (!is_drawn) |
187 DropTextures(); | 189 DropTextures(); |
188 if (parent_) | 190 SetNeedsToRecomputeHole(); |
189 parent_->RecomputeHole(); | |
190 #if defined(USE_WEBKIT_COMPOSITOR) | 191 #if defined(USE_WEBKIT_COMPOSITOR) |
191 // TODO(piman): Expose a visibility flag on WebLayer. | 192 // TODO(piman): Expose a visibility flag on WebLayer. |
192 web_layer_.setOpacity(visible_ ? opacity_ : 0.f); | 193 web_layer_.setOpacity(visible_ ? opacity_ : 0.f); |
193 #endif | 194 #endif |
194 } | 195 } |
195 | 196 |
196 bool Layer::IsDrawn() const { | 197 bool Layer::IsDrawn() const { |
197 const Layer* layer = this; | 198 const Layer* layer = this; |
198 while (layer && layer->visible_) | 199 while (layer && layer->visible_) |
199 layer = layer->parent_; | 200 layer = layer->parent_; |
(...skipping 23 matching lines...) Expand all Loading... |
223 NOTREACHED(); // |source| and |target| are in unrelated hierarchies. | 224 NOTREACHED(); // |source| and |target| are in unrelated hierarchies. |
224 } | 225 } |
225 } | 226 } |
226 | 227 |
227 void Layer::SetFillsBoundsOpaquely(bool fills_bounds_opaquely) { | 228 void Layer::SetFillsBoundsOpaquely(bool fills_bounds_opaquely) { |
228 if (fills_bounds_opaquely_ == fills_bounds_opaquely) | 229 if (fills_bounds_opaquely_ == fills_bounds_opaquely) |
229 return; | 230 return; |
230 | 231 |
231 fills_bounds_opaquely_ = fills_bounds_opaquely; | 232 fills_bounds_opaquely_ = fills_bounds_opaquely; |
232 | 233 |
233 if (parent()) | 234 SetNeedsToRecomputeHole(); |
234 parent()->RecomputeHole(); | |
235 #if defined(USE_WEBKIT_COMPOSITOR) | 235 #if defined(USE_WEBKIT_COMPOSITOR) |
236 web_layer_.setOpaque(fills_bounds_opaquely); | 236 web_layer_.setOpaque(fills_bounds_opaquely); |
237 #endif | 237 #endif |
238 } | 238 } |
239 | 239 |
240 void Layer::SetExternalTexture(ui::Texture* texture) { | 240 void Layer::SetExternalTexture(ui::Texture* texture) { |
241 DCHECK(texture); | 241 DCHECK(texture); |
242 layer_updated_externally_ = true; | 242 layer_updated_externally_ = true; |
243 texture_ = texture; | 243 texture_ = texture; |
244 } | 244 } |
(...skipping 29 matching lines...) Expand all Loading... |
274 Compositor* compositor = GetCompositor(); | 274 Compositor* compositor = GetCompositor(); |
275 if (compositor) | 275 if (compositor) |
276 compositor->ScheduleDraw(); | 276 compositor->ScheduleDraw(); |
277 } | 277 } |
278 | 278 |
279 void Layer::Draw() { | 279 void Layer::Draw() { |
280 #if defined(USE_WEBKIT_COMPOSITOR) | 280 #if defined(USE_WEBKIT_COMPOSITOR) |
281 NOTREACHED(); | 281 NOTREACHED(); |
282 #else | 282 #else |
283 DCHECK(GetCompositor()); | 283 DCHECK(GetCompositor()); |
| 284 |
| 285 if (recompute_hole_ && !parent_) |
| 286 RecomputeHole(); |
| 287 |
284 if (!ShouldDraw()) | 288 if (!ShouldDraw()) |
285 return; | 289 return; |
286 | 290 |
287 UpdateLayerCanvas(); | 291 UpdateLayerCanvas(); |
288 | 292 |
289 // Layer drew nothing, no texture was created. | 293 // Layer drew nothing, no texture was created. |
290 if (!texture_.get()) | 294 if (!texture_.get()) |
291 return; | 295 return; |
292 | 296 |
293 ui::TextureDrawParams texture_draw_params; | 297 ui::TextureDrawParams texture_draw_params; |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
379 return; | 383 return; |
380 } | 384 } |
381 scoped_ptr<gfx::Canvas> canvas(gfx::Canvas::CreateCanvas( | 385 scoped_ptr<gfx::Canvas> canvas(gfx::Canvas::CreateCanvas( |
382 draw_rect.width(), draw_rect.height(), false)); | 386 draw_rect.width(), draw_rect.height(), false)); |
383 canvas->TranslateInt(-draw_rect.x(), -draw_rect.y()); | 387 canvas->TranslateInt(-draw_rect.x(), -draw_rect.y()); |
384 delegate_->OnPaintLayer(canvas.get()); | 388 delegate_->OnPaintLayer(canvas.get()); |
385 SetCanvas(*canvas->GetSkCanvas(), draw_rect.origin()); | 389 SetCanvas(*canvas->GetSkCanvas(), draw_rect.origin()); |
386 #endif | 390 #endif |
387 } | 391 } |
388 | 392 |
389 void Layer::RecomputeHole() { | 393 void Layer::SetNeedsToRecomputeHole() { |
390 if (type_ == LAYER_HAS_NO_TEXTURE) | 394 Layer* root_layer = this; |
| 395 while (root_layer->parent_) |
| 396 root_layer = root_layer->parent_; |
| 397 |
| 398 root_layer->recompute_hole_ = true; |
| 399 } |
| 400 |
| 401 void Layer::ClearHoleRects() { |
| 402 hole_rect_ = gfx::Rect(); |
| 403 |
| 404 for (size_t i = 0; i < children_.size(); i++) |
| 405 children_[i]->ClearHoleRects(); |
| 406 } |
| 407 |
| 408 void Layer::GetLayerProperties(std::vector<LayerProperties>* traversal, |
| 409 const ui::Transform& parent_transform) { |
| 410 if (!visible_ || opacity_ != 1.0f) |
391 return; | 411 return; |
392 | 412 |
393 // Reset to default. | 413 ui::Transform current_transform; |
394 hole_rect_ = gfx::Rect(); | 414 current_transform.ConcatTransform(parent_transform); |
| 415 if (transform().HasChange()) |
| 416 current_transform.ConcatTransform(transform()); |
| 417 current_transform.ConcatTranslate( |
| 418 static_cast<float>(bounds().x()), |
| 419 static_cast<float>(bounds().y())); |
395 | 420 |
396 // Find the largest hole | 421 if (fills_bounds_opaquely_ && type_ == LAYER_HAS_TEXTURE) { |
397 for (size_t i = 0; i < children_.size(); ++i) { | 422 LayerProperties properties; |
398 // Ignore non-opaque and hidden children. | 423 properties.layer = this; |
399 if (!children_[i]->IsCompletelyOpaque() || !children_[i]->visible_) | 424 properties.transform_relative_to_root = current_transform; |
400 continue; | 425 traversal->push_back(properties); |
401 | |
402 // Ignore children that aren't rotated by multiples of 90 degrees. | |
403 float degrees; | |
404 if (!InterpolatedTransform::FactorTRS(children_[i]->transform(), | |
405 NULL, °rees, NULL) || | |
406 !IsApproximateMultilpleOf(degrees, 90.0f)) | |
407 continue; | |
408 | |
409 // The reason why we don't just take the bounds and apply the transform is | |
410 // that the bounds encodes a position, too, so the effective transformation | |
411 // matrix is actually different that the one reported. As well, the bounds | |
412 // will not necessarily be at the origin. | |
413 gfx::Rect candidate_hole(children_[i]->bounds_.size()); | |
414 ui::Transform transform = children_[i]->transform(); | |
415 transform.ConcatTranslate(static_cast<float>(children_[i]->bounds_.x()), | |
416 static_cast<float>(children_[i]->bounds_.y())); | |
417 transform.TransformRect(&candidate_hole); | |
418 | |
419 // This layer might not contain the child (e.g., a portion of the child may | |
420 // be offscreen). Only the portion of the child that overlaps this layer is | |
421 // of any importance, so take the intersection. | |
422 candidate_hole = gfx::Rect(bounds().size()).Intersect(candidate_hole); | |
423 | |
424 // Ensure we have the largest hole. | |
425 if (candidate_hole.size().GetArea() > hole_rect_.size().GetArea()) | |
426 hole_rect_ = candidate_hole; | |
427 } | 426 } |
428 | 427 |
429 // Free up texture memory if the hole fills bounds of layer. | 428 for (size_t i = 0; i < children_.size(); i++) |
430 if (!ShouldDraw() && !layer_updated_externally_) | 429 children_[i]->GetLayerProperties(traversal, current_transform); |
431 texture_ = NULL; | 430 } |
| 431 |
| 432 void Layer::RecomputeHole() { |
| 433 std::vector<LayerProperties> traversal; |
| 434 ui::Transform transform; |
| 435 |
| 436 ClearHoleRects(); |
| 437 GetLayerProperties(&traversal, transform); |
| 438 |
| 439 for (size_t i = 0; i < traversal.size(); i++) { |
| 440 Layer* layer = traversal[i].layer; |
| 441 gfx::Rect bounds = gfx::Rect(layer->bounds().size()); |
| 442 |
| 443 // Iterate through layers which are after traversal[i] in draw order |
| 444 // and find the largest candidate hole. |
| 445 for (size_t j = i + 1; j < traversal.size(); j++) { |
| 446 gfx::Rect candidate_hole = gfx::Rect(traversal[j].layer->bounds().size()); |
| 447 |
| 448 // Compute transform to go from bounds of layer |j| to local bounds of |
| 449 // layer |i|. |
| 450 ui::Transform candidate_hole_transform; |
| 451 ui::Transform inverted; |
| 452 |
| 453 candidate_hole_transform.ConcatTransform( |
| 454 traversal[j].transform_relative_to_root); |
| 455 |
| 456 if (!traversal[i].transform_relative_to_root.GetInverse(&inverted)) |
| 457 continue; |
| 458 |
| 459 candidate_hole_transform.ConcatTransform(inverted); |
| 460 |
| 461 // cannot punch a hole if the relative transform between the two layers |
| 462 // is not multiple of 90. |
| 463 float degrees; |
| 464 gfx::Point p; |
| 465 if (!InterpolatedTransform::FactorTRS(candidate_hole_transform, &p, |
| 466 °rees, NULL) || !IsApproximateMultilpleOf(degrees, 90.0f)) |
| 467 continue; |
| 468 |
| 469 candidate_hole_transform.TransformRect(&candidate_hole); |
| 470 candidate_hole = candidate_hole.Intersect(bounds); |
| 471 |
| 472 if (candidate_hole.size().GetArea() > layer->hole_rect().size().GetArea()) |
| 473 layer->set_hole_rect(candidate_hole); |
| 474 } |
| 475 // Free up texture memory if the hole fills bounds of layer. |
| 476 if (!layer->ShouldDraw() && !layer_updated_externally()) |
| 477 layer->DropTexture(); |
432 | 478 |
433 #if defined(USE_WEBKIT_COMPOSITOR) | 479 #if defined(USE_WEBKIT_COMPOSITOR) |
434 RecomputeDrawsContent(); | 480 layer->RecomputeDrawsContent(); |
435 #endif | 481 #endif |
436 } | 482 } |
437 | 483 |
438 bool Layer::IsCompletelyOpaque() const { | 484 recompute_hole_ = false; |
439 return fills_bounds_opaquely() && GetCombinedOpacity() == 1.0f; | |
440 } | 485 } |
441 | 486 |
442 // static | 487 // static |
443 void Layer::PunchHole(const gfx::Rect& rect, | 488 void Layer::PunchHole(const gfx::Rect& rect, |
444 const gfx::Rect& region_to_punch_out, | 489 const gfx::Rect& region_to_punch_out, |
445 std::vector<gfx::Rect>* sides) { | 490 std::vector<gfx::Rect>* sides) { |
446 gfx::Rect trimmed_rect = rect.Intersect(region_to_punch_out); | 491 gfx::Rect trimmed_rect = rect.Intersect(region_to_punch_out); |
447 | 492 |
448 if (trimmed_rect.IsEmpty()) { | 493 if (trimmed_rect.IsEmpty()) { |
449 sides->push_back(rect); | 494 sides->push_back(rect); |
(...skipping 18 matching lines...) Expand all Loading... |
468 rect.right() - trimmed_rect.right(), | 513 rect.right() - trimmed_rect.right(), |
469 trimmed_rect.height())); | 514 trimmed_rect.height())); |
470 | 515 |
471 // Bottom (below the hole). | 516 // Bottom (below the hole). |
472 sides->push_back(gfx::Rect(rect.x(), | 517 sides->push_back(gfx::Rect(rect.x(), |
473 trimmed_rect.bottom(), | 518 trimmed_rect.bottom(), |
474 rect.width(), | 519 rect.width(), |
475 rect.bottom() - trimmed_rect.bottom())); | 520 rect.bottom() - trimmed_rect.bottom())); |
476 } | 521 } |
477 | 522 |
478 void Layer::DropTextures() { | 523 void Layer::DropTexture() { |
479 if (!layer_updated_externally_) | 524 if (!layer_updated_externally_) |
480 texture_ = NULL; | 525 texture_ = NULL; |
| 526 } |
| 527 |
| 528 void Layer::DropTextures() { |
| 529 DropTexture(); |
481 for (size_t i = 0; i < children_.size(); ++i) | 530 for (size_t i = 0; i < children_.size(); ++i) |
482 children_[i]->DropTextures(); | 531 children_[i]->DropTextures(); |
483 } | 532 } |
484 | 533 |
485 bool Layer::ConvertPointForAncestor(const Layer* ancestor, | 534 bool Layer::ConvertPointForAncestor(const Layer* ancestor, |
486 gfx::Point* point) const { | 535 gfx::Point* point) const { |
487 ui::Transform transform; | 536 ui::Transform transform; |
488 bool result = GetTransformRelativeTo(ancestor, &transform); | 537 bool result = GetTransformRelativeTo(ancestor, &transform); |
489 gfx::Point3f p(*point); | 538 gfx::Point3f p(*point); |
490 transform.TransformPoint(p); | 539 transform.TransformPoint(p); |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
533 if (property != LayerAnimationManager::TRANSFORM && | 582 if (property != LayerAnimationManager::TRANSFORM && |
534 animator_->IsAnimating(LayerAnimationManager::TRANSFORM)) { | 583 animator_->IsAnimating(LayerAnimationManager::TRANSFORM)) { |
535 SetTransformImmediately(animator_->GetTargetTransform()); | 584 SetTransformImmediately(animator_->GetTargetTransform()); |
536 } | 585 } |
537 animator_.reset(); | 586 animator_.reset(); |
538 } | 587 } |
539 | 588 |
540 void Layer::SetBoundsImmediately(const gfx::Rect& bounds) { | 589 void Layer::SetBoundsImmediately(const gfx::Rect& bounds) { |
541 bounds_ = bounds; | 590 bounds_ = bounds; |
542 | 591 |
543 if (parent()) | 592 SetNeedsToRecomputeHole(); |
544 parent()->RecomputeHole(); | |
545 #if defined(USE_WEBKIT_COMPOSITOR) | 593 #if defined(USE_WEBKIT_COMPOSITOR) |
546 web_layer_.setBounds(bounds.size()); | 594 web_layer_.setBounds(bounds.size()); |
547 RecomputeTransform(); | 595 RecomputeTransform(); |
548 RecomputeDrawsContent(); | 596 RecomputeDrawsContent(); |
549 #endif | 597 #endif |
550 } | 598 } |
551 | 599 |
552 void Layer::SetTransformImmediately(const ui::Transform& transform) { | 600 void Layer::SetTransformImmediately(const ui::Transform& transform) { |
553 transform_ = transform; | 601 transform_ = transform; |
554 | 602 |
555 if (parent()) | 603 SetNeedsToRecomputeHole(); |
556 parent()->RecomputeHole(); | |
557 #if defined(USE_WEBKIT_COMPOSITOR) | 604 #if defined(USE_WEBKIT_COMPOSITOR) |
558 RecomputeTransform(); | 605 RecomputeTransform(); |
559 #endif | 606 #endif |
560 } | 607 } |
561 | 608 |
562 void Layer::SetOpacityImmediately(float opacity) { | 609 void Layer::SetOpacityImmediately(float opacity) { |
563 bool was_opaque = GetCombinedOpacity() == 1.0f; | |
564 opacity_ = opacity; | 610 opacity_ = opacity; |
565 bool is_opaque = GetCombinedOpacity() == 1.0f; | 611 SetNeedsToRecomputeHole(); |
566 | |
567 // If our opacity has changed we need to recompute our hole, our parent's hole | |
568 // and the holes of all our descendants. | |
569 if (was_opaque != is_opaque) { | |
570 if (parent_) | |
571 parent_->RecomputeHole(); | |
572 std::queue<Layer*> to_process; | |
573 to_process.push(this); | |
574 while (!to_process.empty()) { | |
575 Layer* current = to_process.front(); | |
576 to_process.pop(); | |
577 current->RecomputeHole(); | |
578 for (size_t i = 0; i < current->children_.size(); ++i) | |
579 to_process.push(current->children_.at(i)); | |
580 } | |
581 } | |
582 #if defined(USE_WEBKIT_COMPOSITOR) | 612 #if defined(USE_WEBKIT_COMPOSITOR) |
583 if (visible_) | 613 if (visible_) |
584 web_layer_.setOpacity(opacity); | 614 web_layer_.setOpacity(opacity); |
585 RecomputeDrawsContent(); | 615 RecomputeDrawsContent(); |
586 #endif | 616 #endif |
587 } | 617 } |
588 | 618 |
589 void Layer::SetBoundsFromAnimator(const gfx::Rect& bounds) { | 619 void Layer::SetBoundsFromAnimator(const gfx::Rect& bounds) { |
590 SetBoundsImmediately(bounds); | 620 SetBoundsImmediately(bounds); |
591 } | 621 } |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
680 result.append(", color=red"); | 710 result.append(", color=red"); |
681 | 711 |
682 if (fills_bounds_opaquely()) | 712 if (fills_bounds_opaquely()) |
683 result.append(", style=filled"); | 713 result.append(", style=filled"); |
684 | 714 |
685 return result; | 715 return result; |
686 } | 716 } |
687 | 717 |
688 #endif | 718 #endif |
689 | 719 |
690 //////////////////////////////////////////////////////////////////////////////// | |
691 | |
692 } // namespace ui | 720 } // namespace ui |
OLD | NEW |