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

Unified 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, 2 months 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « ui/gfx/compositor/layer.h ('k') | ui/gfx/compositor/layer_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ui/gfx/compositor/layer.cc
diff --git a/ui/gfx/compositor/layer.cc b/ui/gfx/compositor/layer.cc
index 884f80924008b5a8ea9e5da2f98de127f1505dc1..5b66239d58dd87da664e63e34ef2b2bda9bb5b8d 100644
--- a/ui/gfx/compositor/layer.cc
+++ b/ui/gfx/compositor/layer.cc
@@ -36,6 +36,7 @@ Layer::Layer(Compositor* compositor)
parent_(NULL),
visible_(true),
fills_bounds_opaquely_(true),
+ recompute_hole_(false),
layer_updated_externally_(false),
opacity_(1.0f),
delegate_(NULL) {
@@ -50,6 +51,7 @@ Layer::Layer(Compositor* compositor, LayerType type)
parent_(NULL),
visible_(true),
fills_bounds_opaquely_(true),
+ recompute_hole_(false),
layer_updated_externally_(false),
opacity_(1.0f),
delegate_(NULL) {
@@ -90,7 +92,7 @@ void Layer::Add(Layer* child) {
web_layer_.addChild(child->web_layer_);
#endif
- RecomputeHole();
+ SetNeedsToRecomputeHole();
}
void Layer::Remove(Layer* child) {
@@ -103,7 +105,7 @@ void Layer::Remove(Layer* child) {
child->web_layer_.removeFromParent();
#endif
- RecomputeHole();
+ SetNeedsToRecomputeHole();
child->DropTextures();
}
@@ -185,8 +187,7 @@ void Layer::SetVisible(bool visible) {
if (!is_drawn)
DropTextures();
- if (parent_)
- parent_->RecomputeHole();
+ SetNeedsToRecomputeHole();
#if defined(USE_WEBKIT_COMPOSITOR)
// TODO(piman): Expose a visibility flag on WebLayer.
web_layer_.setOpacity(visible_ ? opacity_ : 0.f);
@@ -230,8 +231,7 @@ void Layer::SetFillsBoundsOpaquely(bool fills_bounds_opaquely) {
fills_bounds_opaquely_ = fills_bounds_opaquely;
- if (parent())
- parent()->RecomputeHole();
+ SetNeedsToRecomputeHole();
#if defined(USE_WEBKIT_COMPOSITOR)
web_layer_.setOpaque(fills_bounds_opaquely);
#endif
@@ -281,6 +281,10 @@ void Layer::Draw() {
NOTREACHED();
#else
DCHECK(GetCompositor());
+
+ if (recompute_hole_ && !parent_)
+ RecomputeHole();
+
if (!ShouldDraw())
return;
@@ -386,57 +390,98 @@ void Layer::UpdateLayerCanvas() {
#endif
}
-void Layer::RecomputeHole() {
- if (type_ == LAYER_HAS_NO_TEXTURE)
- return;
+void Layer::SetNeedsToRecomputeHole() {
+ Layer* root_layer = this;
+ while (root_layer->parent_)
+ root_layer = root_layer->parent_;
- // Reset to default.
+ root_layer->recompute_hole_ = true;
+}
+
+void Layer::ClearHoleRects() {
hole_rect_ = gfx::Rect();
- // Find the largest hole
- for (size_t i = 0; i < children_.size(); ++i) {
- // Ignore non-opaque and hidden children.
- if (!children_[i]->IsCompletelyOpaque() || !children_[i]->visible_)
- continue;
-
- // Ignore children that aren't rotated by multiples of 90 degrees.
- float degrees;
- if (!InterpolatedTransform::FactorTRS(children_[i]->transform(),
- NULL, &degrees, NULL) ||
- !IsApproximateMultilpleOf(degrees, 90.0f))
- continue;
-
- // The reason why we don't just take the bounds and apply the transform is
- // that the bounds encodes a position, too, so the effective transformation
- // matrix is actually different that the one reported. As well, the bounds
- // will not necessarily be at the origin.
- gfx::Rect candidate_hole(children_[i]->bounds_.size());
- ui::Transform transform = children_[i]->transform();
- transform.ConcatTranslate(static_cast<float>(children_[i]->bounds_.x()),
- static_cast<float>(children_[i]->bounds_.y()));
- transform.TransformRect(&candidate_hole);
-
- // This layer might not contain the child (e.g., a portion of the child may
- // be offscreen). Only the portion of the child that overlaps this layer is
- // of any importance, so take the intersection.
- candidate_hole = gfx::Rect(bounds().size()).Intersect(candidate_hole);
-
- // Ensure we have the largest hole.
- if (candidate_hole.size().GetArea() > hole_rect_.size().GetArea())
- hole_rect_ = candidate_hole;
+ for (size_t i = 0; i < children_.size(); i++)
+ children_[i]->ClearHoleRects();
+}
+
+void Layer::GeneratePreorderTraversal(
+ std::vector<ui::Layer*>* layer_traversal) {
+ if (!visible_)
+ return;
+
+ if (fills_bounds_opaquely_ && type_ == LAYER_HAS_TEXTURE)
+ layer_traversal->push_back(this);
+
+ for (size_t i = 0; i < children_.size(); i++)
+ children_[i]->GeneratePreorderTraversal(layer_traversal);
+}
+
+void Layer::RecomputeHole() {
+ std::vector<ui::Layer*> layer_traversal;
+ std::vector<ui::Transform> transforms_relative_to_root;
+ std::vector<float> opacities;
+
+ ClearHoleRects();
+ GeneratePreorderTraversal(&layer_traversal);
+
+ for (size_t i = 0; i < layer_traversal.size(); i++) {
sky 2011/10/24 23:25:50 Seems a lot better to have GeneratePreorderTravers
+ Layer* layer = layer_traversal[i];
+ ui::Transform layer_transform;
+ layer->GetTransformRelativeTo(this, &layer_transform);
+ transforms_relative_to_root.push_back(layer_transform);
+ opacities.push_back(layer->GetCombinedOpacity());
}
- // Free up texture memory if the hole fills bounds of layer.
- if (!ShouldDraw() && !layer_updated_externally_)
- texture_ = NULL;
+ for (size_t i = 0; i < layer_traversal.size(); i++) {
+ Layer* layer = layer_traversal[i];
+ gfx::Rect bounds = gfx::Rect(layer->bounds().size());
+
+ // Iterate through layers which are after layer_traversal[i] in draw order
+ // and find the largest candidate hole.
+ for (size_t j = i + 1; j < layer_traversal.size(); j++) {
+ gfx::Rect candidate_hole = gfx::Rect(layer_traversal[j]->bounds().size());
+
+ // Compute transform to go from bounds of layer |j| to local bounds of
+ // layer |i|.
+ ui::Transform candidate_hole_transform;
+ ui::Transform inverted;
+
+ candidate_hole_transform.ConcatTransform(transforms_relative_to_root[j]);
+
+ if (!transforms_relative_to_root[i].GetInverse(&inverted))
+ continue;
+
+ candidate_hole_transform.ConcatTransform(inverted);
+
+ // cannot punch a hole if the relative transform between the two layers
+ // is not multiple of 90.
+ float degrees;
+ gfx::Point p;
+ if (!InterpolatedTransform::FactorTRS(candidate_hole_transform, &p,
+ &degrees, NULL) || !IsApproximateMultilpleOf(degrees, 90.0f))
+ continue;
+
+ // can only punch a hole if the two layers have 1.0f opacity.
+ if (opacities[i] != 1.0f || opacities[j] != 1.0f)
sky 2011/10/24 23:25:50 This check is cheap. We should do it first.
+ continue;
+
+ candidate_hole_transform.TransformRect(&candidate_hole);
+ candidate_hole = candidate_hole.Intersect(bounds);
+
+ if (candidate_hole.size().GetArea() > layer->hole_rect().size().GetArea())
+ layer->set_hole_rect(candidate_hole);
+ }
+ // Free up texture memory if the hole fills bounds of layer.
+ if (!layer->ShouldDraw() && !layer_updated_externally())
+ layer->DropTexture();
#if defined(USE_WEBKIT_COMPOSITOR)
- RecomputeDrawsContent();
+ RecomputeDrawsContent();
sky 2011/10/24 23:25:50 Shouldn't this be outside the for loop?
#endif
-}
-bool Layer::IsCompletelyOpaque() const {
- return fills_bounds_opaquely() && GetCombinedOpacity() == 1.0f;
+ recompute_hole_ = false;
sky 2011/10/24 23:25:50 Shouldn't this be outside the for loop?
+ }
}
// static
@@ -475,6 +520,11 @@ void Layer::PunchHole(const gfx::Rect& rect,
rect.bottom() - trimmed_rect.bottom()));
}
+void Layer::DropTexture() {
+ if (!layer_updated_externally_)
+ texture_ = NULL;
+}
+
void Layer::DropTextures() {
if (!layer_updated_externally_)
sky 2011/10/24 23:25:50 Change this to call DropTexture.
texture_ = NULL;
@@ -540,8 +590,7 @@ void Layer::StopAnimatingIfNecessary(
void Layer::SetBoundsImmediately(const gfx::Rect& bounds) {
bounds_ = bounds;
- if (parent())
- parent()->RecomputeHole();
+ SetNeedsToRecomputeHole();
#if defined(USE_WEBKIT_COMPOSITOR)
web_layer_.setBounds(bounds.size());
RecomputeTransform();
@@ -552,33 +601,15 @@ void Layer::SetBoundsImmediately(const gfx::Rect& bounds) {
void Layer::SetTransformImmediately(const ui::Transform& transform) {
transform_ = transform;
- if (parent())
- parent()->RecomputeHole();
+ SetNeedsToRecomputeHole();
#if defined(USE_WEBKIT_COMPOSITOR)
RecomputeTransform();
#endif
}
void Layer::SetOpacityImmediately(float opacity) {
- bool was_opaque = GetCombinedOpacity() == 1.0f;
opacity_ = opacity;
- bool is_opaque = GetCombinedOpacity() == 1.0f;
-
- // If our opacity has changed we need to recompute our hole, our parent's hole
- // and the holes of all our descendants.
- if (was_opaque != is_opaque) {
- if (parent_)
- parent_->RecomputeHole();
- std::queue<Layer*> to_process;
- to_process.push(this);
- while (!to_process.empty()) {
- Layer* current = to_process.front();
- to_process.pop();
- current->RecomputeHole();
- for (size_t i = 0; i < current->children_.size(); ++i)
- to_process.push(current->children_.at(i));
- }
- }
+ SetNeedsToRecomputeHole();
#if defined(USE_WEBKIT_COMPOSITOR)
if (visible_)
web_layer_.setOpacity(opacity);
@@ -687,6 +718,4 @@ std::string Layer::GetLayerInfo() {
#endif
-////////////////////////////////////////////////////////////////////////////////
-
} // namespace ui
« no previous file with comments | « ui/gfx/compositor/layer.h ('k') | ui/gfx/compositor/layer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698