summaryrefslogtreecommitdiffstats
path: root/ui/gfx
diff options
context:
space:
mode:
authorpkotwicz@chromium.org <pkotwicz@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-09-29 17:41:20 +0000
committerpkotwicz@chromium.org <pkotwicz@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-09-29 17:41:20 +0000
commit6b29ebb643bf629715f5e3093c99e407c111a5ca (patch)
tree90d95a0ef605c91b1a3df0832987b17c49b67bfb /ui/gfx
parent7dcd166e8b0e63cfb63e4bbeb93a034e915d887e (diff)
downloadchromium_src-6b29ebb643bf629715f5e3093c99e407c111a5ca.zip
chromium_src-6b29ebb643bf629715f5e3093c99e407c111a5ca.tar.gz
chromium_src-6b29ebb643bf629715f5e3093c99e407c111a5ca.tar.bz2
In views desktop, it is possible for child layers to intersect. (This situation occurs when the omnibox is open)
Refactored logic for hole such that the hole does not overlap immediate child layers which cannot have a hole. Review URL: http://codereview.chromium.org/7976040 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@103305 0039d316-1c4b-4281-b951-d872f2087c98
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.