Index: ui/gfx/compositor/layer.cc |
diff --git a/ui/gfx/compositor/layer.cc b/ui/gfx/compositor/layer.cc |
index 2b98d44e7a61015df987bcbf31fb4d9513761a49..e94e9c5065ab02063b6c3fab3586882f5b088bc3 100644 |
--- a/ui/gfx/compositor/layer.cc |
+++ b/ui/gfx/compositor/layer.cc |
@@ -42,6 +42,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) { |
@@ -56,6 +57,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) { |
@@ -96,7 +98,7 @@ void Layer::Add(Layer* child) { |
web_layer_.addChild(child->web_layer_); |
#endif |
- RecomputeHole(); |
+ SetNeedsToRecomputeHole(); |
} |
void Layer::Remove(Layer* child) { |
@@ -109,7 +111,7 @@ void Layer::Remove(Layer* child) { |
child->web_layer_.removeFromParent(); |
#endif |
- RecomputeHole(); |
+ SetNeedsToRecomputeHole(); |
child->DropTextures(); |
} |
@@ -118,6 +120,8 @@ void Layer::MoveToFront(Layer* child) { |
if (children_.size() <= 1 || child == children_.back()) |
return; // Already in front. |
MoveAbove(child, children_.back()); |
+ |
+ SetNeedsToRecomputeHole(); |
} |
void Layer::MoveAbove(Layer* child, Layer* other) { |
@@ -135,6 +139,8 @@ void Layer::MoveAbove(Layer* child, Layer* other) { |
children_.erase(children_.begin() + child_i); |
children_.insert(children_.begin() + other_i, child); |
+ SetNeedsToRecomputeHole(); |
+ |
#if defined(USE_WEBKIT_COMPOSITOR) |
child->web_layer_.removeFromParent(); |
web_layer_.insertChild(child->web_layer_, other_i); |
@@ -207,8 +213,7 @@ void Layer::SetVisible(bool visible) { |
if (!is_drawn) |
DropTextures(); |
- if (parent_) |
- parent_->RecomputeHole(); |
+ SetNeedsToRecomputeHole(); |
} |
bool Layer::IsDrawn() const { |
@@ -245,8 +250,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 |
@@ -325,6 +329,10 @@ void Layer::Draw() { |
NOTREACHED(); |
#else |
DCHECK(GetCompositor()); |
+ |
+ if (recompute_hole_ && !parent_) |
+ RecomputeHole(); |
+ |
if (!ShouldDraw()) |
return; |
@@ -432,57 +440,100 @@ 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, °rees, 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::GetLayerProperties(const ui::Transform& parent_transform, |
+ std::vector<LayerProperties>* traversal) { |
+ if (!visible_ || opacity_ != 1.0f) |
+ return; |
+ |
+ ui::Transform current_transform; |
+ if (transform().HasChange()) |
+ current_transform.ConcatTransform(transform()); |
+ current_transform.ConcatTranslate( |
+ static_cast<float>(bounds().x()), |
+ static_cast<float>(bounds().y())); |
+ current_transform.ConcatTransform(parent_transform); |
+ |
+ if (fills_bounds_opaquely_ && type_ == LAYER_HAS_TEXTURE) { |
+ LayerProperties properties; |
+ properties.layer = this; |
+ properties.transform_relative_to_root = current_transform; |
+ traversal->push_back(properties); |
} |
- // Free up texture memory if the hole fills bounds of layer. |
- if (!ShouldDraw() && !layer_updated_externally_) |
- texture_ = NULL; |
+ for (size_t i = 0; i < children_.size(); i++) |
+ children_[i]->GetLayerProperties(current_transform, traversal); |
+} |
+ |
+void Layer::RecomputeHole() { |
+ std::vector<LayerProperties> traversal; |
+ ui::Transform transform; |
+ |
+ ClearHoleRects(); |
+ GetLayerProperties(transform, &traversal); |
+ |
+ for (size_t i = 0; i < traversal.size(); i++) { |
+ Layer* layer = traversal[i].layer; |
+ gfx::Rect bounds = gfx::Rect(layer->bounds().size()); |
+ |
+ // Iterate through layers which are after traversal[i] in draw order |
+ // and find the largest candidate hole. |
+ for (size_t j = i + 1; j < traversal.size(); j++) { |
+ gfx::Rect candidate_hole = gfx::Rect(traversal[j].layer->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( |
+ traversal[j].transform_relative_to_root); |
+ |
+ if (!traversal[i].transform_relative_to_root.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, |
+ °rees, NULL) || !IsApproximateMultilpleOf(degrees, 90.0f)) |
+ 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(); |
+ layer->RecomputeDrawsContent(); |
#endif |
-} |
+ } |
-bool Layer::IsCompletelyOpaque() const { |
- return fills_bounds_opaquely() && GetCombinedOpacity() == 1.0f; |
+ recompute_hole_ = false; |
} |
// static |
@@ -521,9 +572,13 @@ void Layer::PunchHole(const gfx::Rect& rect, |
rect.bottom() - trimmed_rect.bottom())); |
} |
-void Layer::DropTextures() { |
+void Layer::DropTexture() { |
if (!layer_updated_externally_) |
texture_ = NULL; |
+} |
+ |
+void Layer::DropTextures() { |
+ DropTexture(); |
for (size_t i = 0; i < children_.size(); ++i) |
children_[i]->DropTextures(); |
} |
@@ -573,8 +628,7 @@ void Layer::SetBoundsImmediately(const gfx::Rect& bounds) { |
SchedulePaint(gfx::Rect(bounds.size())); |
} |
- if (parent()) |
- parent()->RecomputeHole(); |
+ SetNeedsToRecomputeHole(); |
#if defined(USE_WEBKIT_COMPOSITOR) |
web_layer_.setBounds(bounds.size()); |
RecomputeTransform(); |
@@ -585,8 +639,7 @@ 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 |
@@ -600,19 +653,8 @@ void Layer::SetOpacityImmediately(float opacity) { |
// 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)); |
- } |
- } |
+ if (was_opaque != is_opaque) |
+ SetNeedsToRecomputeHole(); |
#if defined(USE_WEBKIT_COMPOSITOR) |
if (visible_) |
web_layer_.setOpacity(opacity); |