diff options
author | vollick@chromium.org <vollick@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-10-06 15:37:23 +0000 |
---|---|---|
committer | vollick@chromium.org <vollick@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-10-06 15:37:23 +0000 |
commit | 9eaf8bc9df2a137422596890399576464cecc375 (patch) | |
tree | 0feab4370e8bbf4a4ec7bbb804b9da38f06b6953 /ui/gfx | |
parent | 78c33fd194c947c0da1868edabfe4bb7779ce1bf (diff) | |
download | chromium_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.cc | 59 | ||||
-rw-r--r-- | ui/gfx/compositor/layer_unittest.cc | 56 |
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, °rees, 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) |