summaryrefslogtreecommitdiffstats
path: root/ui/gfx
diff options
context:
space:
mode:
Diffstat (limited to 'ui/gfx')
-rw-r--r--ui/gfx/compositor/layer.cc132
-rw-r--r--ui/gfx/compositor/layer.h44
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_,
+ &regions_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.