| 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);
|
|
|