diff options
-rw-r--r-- | ui/gfx/compositor/layer.cc | 132 | ||||
-rw-r--r-- | ui/gfx/compositor/layer.h | 44 |
2 files changed, 110 insertions, 66 deletions
diff --git a/ui/gfx/compositor/layer.cc b/ui/gfx/compositor/layer.cc index 9f6b661..7add41f 100644 --- a/ui/gfx/compositor/layer.cc +++ b/ui/gfx/compositor/layer.cc @@ -63,8 +63,7 @@ void Layer::Add(Layer* child) { child->parent_ = this; children_.push_back(child); - if (child->fills_bounds_opaquely()) - RecomputeHole(); + RecomputeHole(); } void Layer::Remove(Layer* child) { @@ -74,8 +73,7 @@ void Layer::Remove(Layer* child) { children_.erase(i); child->parent_ = NULL; - if (child->fills_bounds_opaquely()) - RecomputeHole(); + RecomputeHole(); child->DropTextures(); } @@ -221,35 +219,13 @@ void Layer::Draw() { texture_draw_params.opacity = combined_opacity; texture_draw_params.has_valid_alpha_channel = has_valid_alpha_channel(); - hole_rect_ = hole_rect_.Intersect( - gfx::Rect(0, 0, bounds_.width(), bounds_.height())); - if (hole_rect_.IsEmpty()) { - DrawRegion(texture_draw_params, - gfx::Rect(0, 0, bounds_.width(), bounds_.height())); - } else { - // Top (above the hole). - DrawRegion(texture_draw_params, gfx::Rect(0, - 0, - bounds_.width(), - hole_rect_.y())); - // Left (of the hole). - DrawRegion(texture_draw_params, gfx::Rect(0, - hole_rect_.y(), - hole_rect_.x(), - hole_rect_.height())); - // Right (of the hole). - DrawRegion(texture_draw_params, gfx::Rect( - hole_rect_.right(), - hole_rect_.y(), - bounds_.width() - hole_rect_.right(), - hole_rect_.height())); - - // Bottom (below the hole). - DrawRegion(texture_draw_params, gfx::Rect( - 0, - hole_rect_.bottom(), - bounds_.width(), - bounds_.height() - hole_rect_.bottom())); + std::vector<gfx::Rect> regions_to_draw; + PunchHole(gfx::Rect(gfx::Point(), bounds().size()), hole_rect_, + ®ions_to_draw); + + for (size_t i = 0; i < regions_to_draw.size(); ++i) { + if (!regions_to_draw[i].IsEmpty()) + texture_->Draw(texture_draw_params, regions_to_draw[i]); } } @@ -272,12 +248,6 @@ float Layer::GetCombinedOpacity() const { return opacity; } -void Layer::DrawRegion(const ui::TextureDrawParams& params, - const gfx::Rect& region_to_draw) { - if (!region_to_draw.IsEmpty()) - texture_->Draw(params, region_to_draw); -} - void Layer::UpdateLayerCanvas() { // If we have no delegate, that means that whoever constructed the Layer is // setting its canvas directly with SetCanvas(). @@ -301,23 +271,95 @@ void Layer::RecomputeHole() { if (type_ == LAYER_HAS_NO_TEXTURE) return; - // If there are no opaque child layers, hole_rect_ should remain empty. + // Reset to default. hole_rect_ = gfx::Rect(); + // 1) We cannot do any hole punching if any child has a transform. for (size_t i = 0; i < children_.size(); ++i) { - if (children_[i]->fills_bounds_opaquely() && - children_[i]->GetCombinedOpacity() == 1.0f && - !children_[i]->transform().HasChange()) { + if (children_[i]->transform().HasChange() && children_[i]->visible()) + return; + } + + // 2) 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; + + if (children_[i]->bounds().size().GetArea() > hole_rect_.size().GetArea()) { hole_rect_ = children_[i]->bounds(); - break; } } - // Free up texture memory if the hole fills bounds of layer + // 3) Make sure hole does not intersect with non-opaque children. + for (size_t i = 0; i < children_.size(); ++i) { + // Ignore opaque and hidden children. + if (children_[i]->IsCompletelyOpaque() || !children_[i]->visible()) + continue; + + // Ignore non-intersecting children. + if (!hole_rect_.Intersects(children_[i]->bounds())) + continue; + + // Compute surrounding fragments. + std::vector<gfx::Rect> fragments; + PunchHole(hole_rect_, children_[i]->bounds(), &fragments); + + // Pick the largest surrounding fragment as the new hole. + hole_rect_ = fragments[0]; + for (size_t j = 1; j < fragments.size(); ++j) { + if (fragments[j].size().GetArea() > hole_rect_.size().GetArea()) { + hole_rect_ = fragments[j]; + } + } + DCHECK(!hole_rect_.IsEmpty()); + } + + // 4) Free up texture memory if the hole fills bounds of layer. if (!ShouldDraw() && !layer_updated_externally_) texture_ = NULL; } +bool Layer::IsCompletelyOpaque() const { + return fills_bounds_opaquely() && GetCombinedOpacity() == 1.0f; +} + +// static +void Layer::PunchHole(const gfx::Rect& rect, + const gfx::Rect& region_to_punch_out, + std::vector<gfx::Rect>* sides) { + gfx::Rect trimmed_rect = rect.Intersect(region_to_punch_out); + + if (trimmed_rect.IsEmpty()) { + sides->push_back(rect); + return; + } + + // Top (above the hole). + sides->push_back(gfx::Rect(rect.x(), + rect.y(), + rect.width(), + trimmed_rect.y() - rect.y())); + + // Left (of the hole). + sides->push_back(gfx::Rect(rect.x(), + trimmed_rect.y(), + trimmed_rect.x() - rect.x(), + trimmed_rect.height())); + + // Right (of the hole). + sides->push_back(gfx::Rect(trimmed_rect.right(), + trimmed_rect.y(), + rect.right() - trimmed_rect.right(), + trimmed_rect.height())); + + // Bottom (below the hole). + sides->push_back(gfx::Rect(rect.x(), + trimmed_rect.bottom(), + rect.width(), + rect.bottom() - trimmed_rect.bottom())); +} + void Layer::DropTextures() { if (!layer_updated_externally_) texture_ = NULL; diff --git a/ui/gfx/compositor/layer.h b/ui/gfx/compositor/layer.h index 97f6909..625067a 100644 --- a/ui/gfx/compositor/layer.h +++ b/ui/gfx/compositor/layer.h @@ -140,23 +140,7 @@ class COMPOSITOR_EXPORT Layer : public LayerAnimatorDelegate { // repaint. void SchedulePaint(const gfx::Rect& invalid_rect); - // Draws the layer with hole if hole is non empty. - // hole looks like: - // - // layer____________________________ - // |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| - // |xxxxxxxxxxxxx top xxxxxxxxxxxxxx| - // |________________________________| - // |xxxxx| |xxxxx| - // |xxxxx| Hole Rect |xxxxx| - // |left | (not composited) |right| - // |_____|____________________|_____| - // |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| - // |xxxxxxxxxx bottom xxxxxxxxxxxxxx| - // |________________________________| - // - // Legend: - // composited area: x + // Does drawing for the layer. void Draw(); // Draws a tree of Layers, by calling Draw() on each in the hierarchy starting @@ -174,10 +158,6 @@ class COMPOSITOR_EXPORT Layer : public LayerAnimatorDelegate { // use the combined result, but this is only temporary. float GetCombinedOpacity() const; - // calls Texture::Draw only if the region to be drawn is non empty - void DrawRegion(const ui::TextureDrawParams& params, - const gfx::Rect& region_to_draw); - // Called during the Draw() pass to freshen the Layer's contents from the // delegate. void UpdateLayerCanvas(); @@ -191,6 +171,28 @@ class COMPOSITOR_EXPORT Layer : public LayerAnimatorDelegate { // view has no transform with respect to its parent. void RecomputeHole(); + // Returns true if the layer paints every pixel (fills_bounds_opaquely) + // and the alpha of the layer is 1.0f. + bool IsCompletelyOpaque() const; + + // Determines the regions that don't intersect |rect| and places the + // result in |sides|. + // + // rect_____________________________ + // |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| + // |xxxxxxxxxxxxx top xxxxxxxxxxxxxx| + // |________________________________| + // |xxxxx| |xxxxx| + // |xxxxx|region_to_punch_out |xxxxx| + // |left | |right| + // |_____|____________________|_____| + // |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| + // |xxxxxxxxxx bottom xxxxxxxxxxxxxx| + // |________________________________| + static void PunchHole(const gfx::Rect& rect, + const gfx::Rect& region_to_punch_out, + std::vector<gfx::Rect>* sides); + // Drop all textures for layers below and including this one. Called when // the layer is removed from a hierarchy. Textures will be re-generated if // the layer is subsequently re-attached and needs to be drawn. |