summaryrefslogtreecommitdiffstats
path: root/ui/gfx
diff options
context:
space:
mode:
authorvollick@chromium.org <vollick@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-10-06 15:37:23 +0000
committervollick@chromium.org <vollick@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-10-06 15:37:23 +0000
commit9eaf8bc9df2a137422596890399576464cecc375 (patch)
tree0feab4370e8bbf4a4ec7bbb804b9da38f06b6953 /ui/gfx
parent78c33fd194c947c0da1868edabfe4bb7779ce1bf (diff)
downloadchromium_src-9eaf8bc9df2a137422596890399576464cecc375.zip
chromium_src-9eaf8bc9df2a137422596890399576464cecc375.tar.gz
chromium_src-9eaf8bc9df2a137422596890399576464cecc375.tar.bz2
Avoid overdraw in views desktop.
Make sure that we still allow a view to punch a hole in its parent if it is rotated by a multiple of 90 degrees. BUG=None TEST=None Review URL: http://codereview.chromium.org/7941017 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@104304 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui/gfx')
-rw-r--r--ui/gfx/compositor/layer.cc59
-rw-r--r--ui/gfx/compositor/layer_unittest.cc56
2 files changed, 53 insertions, 62 deletions
diff --git a/ui/gfx/compositor/layer.cc b/ui/gfx/compositor/layer.cc
index af3514fc..b9b1cd3 100644
--- a/ui/gfx/compositor/layer.cc
+++ b/ui/gfx/compositor/layer.cc
@@ -11,8 +11,20 @@
#include "ui/base/animation/animation.h"
#include "ui/gfx/compositor/layer_animator.h"
#include "ui/gfx/canvas_skia.h"
+#include "ui/gfx/interpolated_transform.h"
#include "ui/gfx/point3.h"
+namespace {
+
+const float EPSILON = 1e-3f;
+
+bool IsApproximateMultilpleOf(float value, float base) {
+ float remainder = fmod(fabs(value), base);
+ return remainder < EPSILON || base - remainder < EPSILON;
+}
+
+} // namespace
+
namespace ui {
Layer::Layer(Compositor* compositor)
@@ -303,48 +315,33 @@ void Layer::RecomputeHole() {
// 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]->transform().HasChange() && children_[i]->visible_)
- return;
- }
-
- // 2) Find the largest hole.
+ // 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();
- }
- }
-
- // 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_)
+ // Ignore children that aren't rotated by multiples of 90 degrees.
+ float degrees;
+ if (!InterpolatedTransform::FactorTRS(children_[i]->transform(),
+ NULL, &degrees, NULL) ||
+ !IsApproximateMultilpleOf(degrees, 90.0f))
continue;
- // Ignore non-intersecting children.
- if (!hole_rect_.Intersects(children_[i]->bounds()))
- continue;
+ gfx::Rect candidate_hole = children_[i]->bounds();
+ children_[i]->transform().TransformRect(&candidate_hole);
- // Compute surrounding fragments.
- std::vector<gfx::Rect> fragments;
- PunchHole(hole_rect_, children_[i]->bounds(), &fragments);
+ // 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 = bounds().Intersect(candidate_hole);
- // 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());
+ // Ensure we have the largest hole.
+ if (candidate_hole.size().GetArea() > hole_rect_.size().GetArea())
+ hole_rect_ = candidate_hole;
}
- // 4) Free up texture memory if the hole fills bounds of layer.
+ // Free up texture memory if the hole fills bounds of layer.
if (!ShouldDraw() && !layer_updated_externally_)
texture_ = NULL;
}
diff --git a/ui/gfx/compositor/layer_unittest.cc b/ui/gfx/compositor/layer_unittest.cc
index 59ccfdd..953eaba 100644
--- a/ui/gfx/compositor/layer_unittest.cc
+++ b/ui/gfx/compositor/layer_unittest.cc
@@ -506,36 +506,6 @@ TEST_F(LayerWithNullDelegateTest, LayerTextureNonEmptySchedulePaint) {
EXPECT_TRUE(layer->texture() != NULL);
}
-// Verifies that a hole in a layer does not intersect non completely-opaque
-// layers.
-TEST_F(LayerWithNullDelegateTest, HoleDoesNotIntersectNonOpaque) {
- scoped_ptr<Layer> parent(CreateTextureRootLayer(gfx::Rect(0, 0, 400, 400)));
- scoped_ptr<Layer> child1(CreateTextureLayer(gfx::Rect(50, 50, 100, 100)));
- parent->Add(child1.get());
-
- scoped_ptr<Layer> child2(CreateLayer(Layer::LAYER_HAS_NO_TEXTURE));
- child2->SetFillsBoundsOpaquely(false);
- parent->Add(child2.get());
- Draw();
-
- // Ensure largest non intersecting hole picked.
- // largest fragment on bottom.
- child2->SetBounds(gfx::Rect(20, 20, 60, 80));
- EXPECT_EQ(gfx::Rect(50, 100, 100, 50), parent->hole_rect());
-
- // largest fragment on right.
- child2->SetBounds(gfx::Rect(20, 20, 60, 200));
- EXPECT_EQ(gfx::Rect(80, 50, 70, 100), parent->hole_rect());
-
- // largest fragment on top.
- child2->SetBounds(gfx::Rect(130, 110, 50, 50));
- EXPECT_EQ(gfx::Rect(50, 50, 100, 60), parent->hole_rect());
-
- // largest fragment on left.
- child2->SetBounds(gfx::Rect(130, 20, 50, 200));
- EXPECT_EQ(gfx::Rect(50, 50, 80, 100), parent->hole_rect());
-}
-
// Verifies that when there are many potential holes, the largest one is picked.
TEST_F(LayerWithNullDelegateTest, LargestHole) {
scoped_ptr<Layer> parent(CreateTextureRootLayer(gfx::Rect(0, 0, 400, 400)));
@@ -559,12 +529,36 @@ TEST_F(LayerWithNullDelegateTest, NoHoleWithTransform) {
EXPECT_TRUE(!parent->hole_rect().IsEmpty());
ui::Transform t;
- t.SetRotate(90.0f);
+ t.SetTranslate(-75, -75);
+ t.ConcatRotate(45.0f);
+ t.ConcatTranslate(75, 75);
child->SetTransform(t);
EXPECT_EQ(gfx::Rect(0, 0, 0, 0), parent->hole_rect());
}
+// Verifies that if the child layer is rotated by a multiple of ninety degrees
+// we punch a hole
+TEST_F(LayerWithNullDelegateTest, HoleWithNinetyDegreeTransforms) {
+ scoped_ptr<Layer> parent(CreateTextureLayer(gfx::Rect(0, 0, 400, 400)));
+ scoped_ptr<Layer> child(CreateTextureLayer(gfx::Rect(50, 50, 50, 50)));
+ parent->Add(child.get());
+
+ EXPECT_TRUE(!parent->hole_rect().IsEmpty());
+
+ for (int i = -4; i <= 4; ++i) {
+ ui::Transform t;
+ t.SetTranslate(-75, -75);
+ t.ConcatRotate(90.0f * i);
+ t.ConcatTranslate(75, 75);
+ child->SetTransform(t);
+
+ gfx::Rect target_rect = child->bounds();
+ child->transform().TransformRect(&target_rect);
+ EXPECT_EQ(target_rect, parent->hole_rect());
+ }
+}
+
// Create this hierarchy:
// L1 (no texture)
// +- L11 (texture)