Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(672)

Side by Side Diff: ui/gfx/compositor/layer.cc

Issue 8368013: Improve Aura overdraw by changing hole calculation (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Nicer diff Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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
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::GeneratePreorderTraversal(
409 std::vector<LayerProperties>* traversal,
410 const ui::Transform& current_transform, float current_opacity) {
sky 2011/10/25 21:44:09 each param on its own line.
sky 2011/10/25 21:44:09 All of the params should be for the parent, not th
411 if (!visible_)
sky 2011/10/25 21:44:09 Should this return if opacity == 0 too?
391 return; 412 return;
392 413
393 // Reset to default. 414 if (fills_bounds_opaquely_ && type_ == LAYER_HAS_TEXTURE) {
394 hole_rect_ = gfx::Rect(); 415 LayerProperties properties;
395 416 properties.layer = this;
396 // Find the largest hole 417 properties.transform_relative_to_root = current_transform;
397 for (size_t i = 0; i < children_.size(); ++i) { 418 properties.combined_opacity = current_opacity;
398 // Ignore non-opaque and hidden children. 419 traversal->push_back(properties);
399 if (!children_[i]->IsCompletelyOpaque() || !children_[i]->visible_)
400 continue;
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, &degrees, 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 } 420 }
428 421
429 // Free up texture memory if the hole fills bounds of layer. 422 for (size_t i = 0; i < children_.size(); i++) {
430 if (!ShouldDraw() && !layer_updated_externally_) 423 Layer* child = children_[i];
431 texture_ = NULL; 424 ui::Transform child_transform;
425 child_transform.ConcatTransform(current_transform);
426 if (child->transform().HasChange())
427 child_transform.ConcatTransform(child->transform());
428 child_transform.ConcatTranslate(
429 static_cast<float>(child->bounds().x()),
sky 2011/10/25 21:44:09 Wrapped lines should be indented by 4.
430 static_cast<float>(child->bounds().y()));
431 float child_opacity = current_opacity * child->opacity();
432
433 child->GeneratePreorderTraversal(traversal, child_transform,
434 child_opacity);
435 }
436 }
437
438 void Layer::RecomputeHole() {
439 std::vector<LayerProperties> traversal;
440 ui::Transform transform;
441 float opacity = 1.0f;
442
443 ClearHoleRects();
444 GeneratePreorderTraversal(&traversal, transform, opacity);
445
446 for (size_t i = 0; i < traversal.size(); i++) {
447 Layer* layer = traversal[i].layer;
448 gfx::Rect bounds = gfx::Rect(layer->bounds().size());
sky 2011/10/25 21:44:09 These calculations are expensive. Is it worth only
449
450 // Iterate through layers which are after traversal[i] in draw order
451 // and find the largest candidate hole.
452 for (size_t j = i + 1; j < traversal.size(); j++) {
453 gfx::Rect candidate_hole = gfx::Rect(traversal[j].layer->bounds().size());
454
455 // Compute transform to go from bounds of layer |j| to local bounds of
456 // layer |i|.
457 ui::Transform candidate_hole_transform;
458 ui::Transform inverted;
459
460 candidate_hole_transform.ConcatTransform(
461 traversal[j].transform_relative_to_root);
462
463 if (!traversal[i].transform_relative_to_root.GetInverse(&inverted))
464 continue;
465
466 candidate_hole_transform.ConcatTransform(inverted);
467
468 // can only punch a hole if the two layers have 1.0f opacity.
469 if (traversal[i].combined_opacity != 1.0f ||
sky 2011/10/25 21:44:09 Shouldn't we make GeneratePreorderTraversal ignore
470 traversal[j].combined_opacity != 1.0f)
471 continue;
472
473 // cannot punch a hole if the relative transform between the two layers
474 // is not multiple of 90.
475 float degrees;
476 gfx::Point p;
477 if (!InterpolatedTransform::FactorTRS(candidate_hole_transform, &p,
478 &degrees, NULL) || !IsApproximateMultilpleOf(degrees, 90.0f))
479 continue;
480
481 candidate_hole_transform.TransformRect(&candidate_hole);
482 candidate_hole = candidate_hole.Intersect(bounds);
483
484 if (candidate_hole.size().GetArea() > layer->hole_rect().size().GetArea())
485 layer->set_hole_rect(candidate_hole);
486 }
487 // Free up texture memory if the hole fills bounds of layer.
488 if (!layer->ShouldDraw() && !layer_updated_externally())
489 layer->DropTexture();
432 490
433 #if defined(USE_WEBKIT_COMPOSITOR) 491 #if defined(USE_WEBKIT_COMPOSITOR)
434 RecomputeDrawsContent(); 492 layer->RecomputeDrawsContent();
435 #endif 493 #endif
436 } 494 }
437 495
438 bool Layer::IsCompletelyOpaque() const { 496 recompute_hole_ = false;
439 return fills_bounds_opaquely() && GetCombinedOpacity() == 1.0f;
440 } 497 }
441 498
442 // static 499 // static
443 void Layer::PunchHole(const gfx::Rect& rect, 500 void Layer::PunchHole(const gfx::Rect& rect,
444 const gfx::Rect& region_to_punch_out, 501 const gfx::Rect& region_to_punch_out,
445 std::vector<gfx::Rect>* sides) { 502 std::vector<gfx::Rect>* sides) {
446 gfx::Rect trimmed_rect = rect.Intersect(region_to_punch_out); 503 gfx::Rect trimmed_rect = rect.Intersect(region_to_punch_out);
447 504
448 if (trimmed_rect.IsEmpty()) { 505 if (trimmed_rect.IsEmpty()) {
449 sides->push_back(rect); 506 sides->push_back(rect);
(...skipping 18 matching lines...) Expand all
468 rect.right() - trimmed_rect.right(), 525 rect.right() - trimmed_rect.right(),
469 trimmed_rect.height())); 526 trimmed_rect.height()));
470 527
471 // Bottom (below the hole). 528 // Bottom (below the hole).
472 sides->push_back(gfx::Rect(rect.x(), 529 sides->push_back(gfx::Rect(rect.x(),
473 trimmed_rect.bottom(), 530 trimmed_rect.bottom(),
474 rect.width(), 531 rect.width(),
475 rect.bottom() - trimmed_rect.bottom())); 532 rect.bottom() - trimmed_rect.bottom()));
476 } 533 }
477 534
478 void Layer::DropTextures() { 535 void Layer::DropTexture() {
479 if (!layer_updated_externally_) 536 if (!layer_updated_externally_)
480 texture_ = NULL; 537 texture_ = NULL;
538 }
539
540 void Layer::DropTextures() {
541 DropTexture();
481 for (size_t i = 0; i < children_.size(); ++i) 542 for (size_t i = 0; i < children_.size(); ++i)
482 children_[i]->DropTextures(); 543 children_[i]->DropTextures();
483 } 544 }
484 545
485 bool Layer::ConvertPointForAncestor(const Layer* ancestor, 546 bool Layer::ConvertPointForAncestor(const Layer* ancestor,
486 gfx::Point* point) const { 547 gfx::Point* point) const {
487 ui::Transform transform; 548 ui::Transform transform;
488 bool result = GetTransformRelativeTo(ancestor, &transform); 549 bool result = GetTransformRelativeTo(ancestor, &transform);
489 gfx::Point3f p(*point); 550 gfx::Point3f p(*point);
490 transform.TransformPoint(p); 551 transform.TransformPoint(p);
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
533 if (property != LayerAnimationManager::TRANSFORM && 594 if (property != LayerAnimationManager::TRANSFORM &&
534 animator_->IsAnimating(LayerAnimationManager::TRANSFORM)) { 595 animator_->IsAnimating(LayerAnimationManager::TRANSFORM)) {
535 SetTransformImmediately(animator_->GetTargetTransform()); 596 SetTransformImmediately(animator_->GetTargetTransform());
536 } 597 }
537 animator_.reset(); 598 animator_.reset();
538 } 599 }
539 600
540 void Layer::SetBoundsImmediately(const gfx::Rect& bounds) { 601 void Layer::SetBoundsImmediately(const gfx::Rect& bounds) {
541 bounds_ = bounds; 602 bounds_ = bounds;
542 603
543 if (parent()) 604 SetNeedsToRecomputeHole();
544 parent()->RecomputeHole();
545 #if defined(USE_WEBKIT_COMPOSITOR) 605 #if defined(USE_WEBKIT_COMPOSITOR)
546 web_layer_.setBounds(bounds.size()); 606 web_layer_.setBounds(bounds.size());
547 RecomputeTransform(); 607 RecomputeTransform();
548 RecomputeDrawsContent(); 608 RecomputeDrawsContent();
549 #endif 609 #endif
550 } 610 }
551 611
552 void Layer::SetTransformImmediately(const ui::Transform& transform) { 612 void Layer::SetTransformImmediately(const ui::Transform& transform) {
553 transform_ = transform; 613 transform_ = transform;
554 614
555 if (parent()) 615 SetNeedsToRecomputeHole();
556 parent()->RecomputeHole();
557 #if defined(USE_WEBKIT_COMPOSITOR) 616 #if defined(USE_WEBKIT_COMPOSITOR)
558 RecomputeTransform(); 617 RecomputeTransform();
559 #endif 618 #endif
560 } 619 }
561 620
562 void Layer::SetOpacityImmediately(float opacity) { 621 void Layer::SetOpacityImmediately(float opacity) {
563 bool was_opaque = GetCombinedOpacity() == 1.0f;
564 opacity_ = opacity; 622 opacity_ = opacity;
565 bool is_opaque = GetCombinedOpacity() == 1.0f; 623 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) 624 #if defined(USE_WEBKIT_COMPOSITOR)
583 if (visible_) 625 if (visible_)
584 web_layer_.setOpacity(opacity); 626 web_layer_.setOpacity(opacity);
585 RecomputeDrawsContent(); 627 RecomputeDrawsContent();
586 #endif 628 #endif
587 } 629 }
588 630
589 void Layer::SetBoundsFromAnimator(const gfx::Rect& bounds) { 631 void Layer::SetBoundsFromAnimator(const gfx::Rect& bounds) {
590 SetBoundsImmediately(bounds); 632 SetBoundsImmediately(bounds);
591 } 633 }
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
680 result.append(", color=red"); 722 result.append(", color=red");
681 723
682 if (fills_bounds_opaquely()) 724 if (fills_bounds_opaquely())
683 result.append(", style=filled"); 725 result.append(", style=filled");
684 726
685 return result; 727 return result;
686 } 728 }
687 729
688 #endif 730 #endif
689 731
690 ////////////////////////////////////////////////////////////////////////////////
691
692 } // namespace ui 732 } // namespace ui
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698