diff options
author | sadrul@chromium.org <sadrul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-02 21:25:00 +0000 |
---|---|---|
committer | sadrul@chromium.org <sadrul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-02 21:25:00 +0000 |
commit | 02876f5fdafb3b6e500ba322715c3a848170763a (patch) | |
tree | 74d06087d2db6557625a414202a7e3e4367ea7a6 /ui | |
parent | 8f2bfca4401f094481cac8fab1fe80c853971d84 (diff) | |
download | chromium_src-02876f5fdafb3b6e500ba322715c3a848170763a.zip chromium_src-02876f5fdafb3b6e500ba322715c3a848170763a.tar.gz chromium_src-02876f5fdafb3b6e500ba322715c3a848170763a.tar.bz2 |
Revert r107440 because this causes a crash on touchui on page load.
The CL being reverted:
This patch lets the browser window punch a hole in the DesktopBackgroundView,
thus eliminating overdraw.
To do this, the hole punching logic was changed to look at the entire tree.
Drawing the screen is a preorder traversal through all the layers. Thus, to
compute the hole, we have to look at all of the layers after a particular layer
in the preorder traversal.
This is not an efficient algorithm, but it is simplest I could come up with.
Plus we will be moving to the WebKit compositor soon.
Hopefully this will improve the frame rate for the Aura demos
Note: I will put the changes to Transform into another patch.
Committed: http://src.chromium.org/viewvc/chrome?view=rev&revision=107360
Review URL: http://codereview.chromium.org/8368013
TBR=pkotwicz@chromium.org
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@108347 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui')
-rw-r--r-- | ui/gfx/compositor/layer.cc | 172 | ||||
-rw-r--r-- | ui/gfx/compositor/layer_unittest.cc | 180 |
2 files changed, 73 insertions, 279 deletions
diff --git a/ui/gfx/compositor/layer.cc b/ui/gfx/compositor/layer.cc index f632c65..7154a4d 100644 --- a/ui/gfx/compositor/layer.cc +++ b/ui/gfx/compositor/layer.cc @@ -42,7 +42,6 @@ Layer::Layer(Compositor* compositor) parent_(NULL), visible_(true), fills_bounds_opaquely_(true), - recompute_hole_(false), layer_updated_externally_(false), opacity_(1.0f), delegate_(NULL) { @@ -57,7 +56,6 @@ Layer::Layer(Compositor* compositor, LayerType type) parent_(NULL), visible_(true), fills_bounds_opaquely_(true), - recompute_hole_(false), layer_updated_externally_(false), opacity_(1.0f), delegate_(NULL) { @@ -98,7 +96,7 @@ void Layer::Add(Layer* child) { web_layer_.addChild(child->web_layer_); #endif - SetNeedsToRecomputeHole(); + RecomputeHole(); } void Layer::Remove(Layer* child) { @@ -111,7 +109,7 @@ void Layer::Remove(Layer* child) { child->web_layer_.removeFromParent(); #endif - SetNeedsToRecomputeHole(); + RecomputeHole(); child->DropTextures(); } @@ -194,7 +192,8 @@ void Layer::SetVisible(bool visible) { if (!is_drawn) DropTextures(); - SetNeedsToRecomputeHole(); + if (parent_) + parent_->RecomputeHole(); } bool Layer::IsDrawn() const { @@ -231,7 +230,8 @@ void Layer::SetFillsBoundsOpaquely(bool fills_bounds_opaquely) { fills_bounds_opaquely_ = fills_bounds_opaquely; - SetNeedsToRecomputeHole(); + if (parent()) + parent()->RecomputeHole(); #if defined(USE_WEBKIT_COMPOSITOR) web_layer_.setOpaque(fills_bounds_opaquely); #endif @@ -310,10 +310,6 @@ void Layer::Draw() { NOTREACHED(); #else DCHECK(GetCompositor()); - - if (recompute_hole_ && !parent_) - RecomputeHole(); - if (!ShouldDraw()) return; @@ -421,98 +417,57 @@ void Layer::UpdateLayerCanvas() { #endif } -void Layer::SetNeedsToRecomputeHole() { - Layer* root_layer = this; - while (root_layer->parent_) - root_layer = root_layer->parent_; - - root_layer->recompute_hole_ = true; -} +void Layer::RecomputeHole() { + if (type_ == LAYER_HAS_NO_TEXTURE) + return; -void Layer::ClearHoleRects() { + // Reset to default. hole_rect_ = gfx::Rect(); - for (size_t i = 0; i < children_.size(); i++) - children_[i]->ClearHoleRects(); -} - -void Layer::GetLayerProperties(const ui::Transform& parent_transform, - std::vector<LayerProperties>* traversal) { - if (!visible_ || opacity_ != 1.0f) - return; - - ui::Transform current_transform; - current_transform.ConcatTransform(parent_transform); - if (transform().HasChange()) - current_transform.ConcatTransform(transform()); - current_transform.ConcatTranslate( - static_cast<float>(bounds().x()), - static_cast<float>(bounds().y())); - - if (fills_bounds_opaquely_ && type_ == LAYER_HAS_TEXTURE) { - LayerProperties properties; - properties.layer = this; - properties.transform_relative_to_root = current_transform; - traversal->push_back(properties); + // 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; + + // 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; + + // The reason why we don't just take the bounds and apply the transform is + // that the bounds encodes a position, too, so the effective transformation + // matrix is actually different that the one reported. As well, the bounds + // will not necessarily be at the origin. + gfx::Rect candidate_hole(children_[i]->bounds_.size()); + ui::Transform transform = children_[i]->transform(); + transform.ConcatTranslate(static_cast<float>(children_[i]->bounds_.x()), + static_cast<float>(children_[i]->bounds_.y())); + transform.TransformRect(&candidate_hole); + + // 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 = gfx::Rect(bounds().size()).Intersect(candidate_hole); + + // Ensure we have the largest hole. + if (candidate_hole.size().GetArea() > hole_rect_.size().GetArea()) + hole_rect_ = candidate_hole; } - for (size_t i = 0; i < children_.size(); i++) - children_[i]->GetLayerProperties(current_transform, traversal); -} - -void Layer::RecomputeHole() { - std::vector<LayerProperties> traversal; - ui::Transform transform; - - ClearHoleRects(); - GetLayerProperties(transform, &traversal); - - for (size_t i = 0; i < traversal.size(); i++) { - Layer* layer = traversal[i].layer; - gfx::Rect bounds = gfx::Rect(layer->bounds().size()); - - // Iterate through layers which are after traversal[i] in draw order - // and find the largest candidate hole. - for (size_t j = i + 1; j < traversal.size(); j++) { - gfx::Rect candidate_hole = gfx::Rect(traversal[j].layer->bounds().size()); - - // Compute transform to go from bounds of layer |j| to local bounds of - // layer |i|. - ui::Transform candidate_hole_transform; - ui::Transform inverted; - - candidate_hole_transform.ConcatTransform( - traversal[j].transform_relative_to_root); - - if (!traversal[i].transform_relative_to_root.GetInverse(&inverted)) - continue; - - candidate_hole_transform.ConcatTransform(inverted); - - // cannot punch a hole if the relative transform between the two layers - // is not multiple of 90. - float degrees; - gfx::Point p; - if (!InterpolatedTransform::FactorTRS(candidate_hole_transform, &p, - °rees, NULL) || !IsApproximateMultilpleOf(degrees, 90.0f)) - continue; - - candidate_hole_transform.TransformRect(&candidate_hole); - candidate_hole = candidate_hole.Intersect(bounds); - - if (candidate_hole.size().GetArea() > layer->hole_rect().size().GetArea()) - layer->set_hole_rect(candidate_hole); - } - // Free up texture memory if the hole fills bounds of layer. - if (!layer->ShouldDraw() && !layer_updated_externally()) - layer->DropTexture(); + // Free up texture memory if the hole fills bounds of layer. + if (!ShouldDraw() && !layer_updated_externally_) + texture_ = NULL; #if defined(USE_WEBKIT_COMPOSITOR) - layer->RecomputeDrawsContent(); + RecomputeDrawsContent(); #endif - } +} - recompute_hole_ = false; +bool Layer::IsCompletelyOpaque() const { + return fills_bounds_opaquely() && GetCombinedOpacity() == 1.0f; } // static @@ -551,13 +506,9 @@ void Layer::PunchHole(const gfx::Rect& rect, rect.bottom() - trimmed_rect.bottom())); } -void Layer::DropTexture() { +void Layer::DropTextures() { if (!layer_updated_externally_) texture_ = NULL; -} - -void Layer::DropTextures() { - DropTexture(); for (size_t i = 0; i < children_.size(); ++i) children_[i]->DropTextures(); } @@ -597,7 +548,8 @@ bool Layer::GetTransformRelativeTo(const Layer* ancestor, void Layer::SetBoundsImmediately(const gfx::Rect& bounds) { bounds_ = bounds; - SetNeedsToRecomputeHole(); + if (parent()) + parent()->RecomputeHole(); #if defined(USE_WEBKIT_COMPOSITOR) web_layer_.setBounds(bounds.size()); RecomputeTransform(); @@ -608,7 +560,8 @@ void Layer::SetBoundsImmediately(const gfx::Rect& bounds) { void Layer::SetTransformImmediately(const ui::Transform& transform) { transform_ = transform; - SetNeedsToRecomputeHole(); + if (parent()) + parent()->RecomputeHole(); #if defined(USE_WEBKIT_COMPOSITOR) RecomputeTransform(); #endif @@ -616,8 +569,25 @@ void Layer::SetTransformImmediately(const ui::Transform& transform) { void Layer::SetOpacityImmediately(float opacity) { bool schedule_draw = (opacity != opacity_ && IsDrawn()); + bool was_opaque = GetCombinedOpacity() == 1.0f; opacity_ = opacity; - SetNeedsToRecomputeHole(); + bool is_opaque = GetCombinedOpacity() == 1.0f; + + // If our opacity has changed we need to recompute our hole, our parent's hole + // and the holes of all our descendants. + if (was_opaque != is_opaque) { + if (parent_) + parent_->RecomputeHole(); + std::queue<Layer*> to_process; + to_process.push(this); + while (!to_process.empty()) { + Layer* current = to_process.front(); + to_process.pop(); + current->RecomputeHole(); + for (size_t i = 0; i < current->children_.size(); ++i) + to_process.push(current->children_.at(i)); + } + } #if defined(USE_WEBKIT_COMPOSITOR) if (visible_) web_layer_.setOpacity(opacity); diff --git a/ui/gfx/compositor/layer_unittest.cc b/ui/gfx/compositor/layer_unittest.cc index fceb9c6..9443ab0 100644 --- a/ui/gfx/compositor/layer_unittest.cc +++ b/ui/gfx/compositor/layer_unittest.cc @@ -544,120 +544,9 @@ TEST_F(LayerWithNullDelegateTest, LargestHole) { scoped_ptr<Layer> child2(CreateTextureLayer(gfx::Rect(75, 75, 200, 200))); parent->Add(child2.get()); - Draw(); - EXPECT_EQ(gfx::Rect(75, 75, 200, 200), parent->hole_rect()); } -// Verifies that the largest hole in the draw order is picked -TEST_F(LayerWithNullDelegateTest, HoleGeneratedFromLeaf) { - // Layer tree looks like: - // node 1 - // |_ node 11 - // |_ node 111 - // |_ node 12 - // |_ node 121 - - scoped_ptr<Layer> node1(CreateTextureRootLayer(gfx::Rect(0, 0, 400, 400))); - - scoped_ptr<Layer> node11(CreateTextureLayer(gfx::Rect(50, 50, 100, 100))); - node1->Add(node11.get()); - - scoped_ptr<Layer> node12(CreateTextureLayer(gfx::Rect(75, 75, 200, 200))); - node1->Add(node12.get()); - - scoped_ptr<Layer> node111(CreateTextureLayer(gfx::Rect(10, 10, 20, 20))); - node11->Add(node111.get()); - - scoped_ptr<Layer> node121(CreateTextureLayer(gfx::Rect(10, 10, 190, 190))); - node12->Add(node121.get()); - - Draw(); - - EXPECT_EQ(gfx::Rect(75, 75, 200, 200), node1->hole_rect()); - EXPECT_EQ(gfx::Rect(25, 25, 75, 75), node11->hole_rect()); - EXPECT_EQ(gfx::Rect(10, 10, 190, 190), node12->hole_rect()); -} - -// Verifies that a hole can only punched into a layer with opacity = 1.0f. -TEST_F(LayerWithNullDelegateTest, NoHoleWhenPartialOpacity) { - // Layer tree looks like: - // node 1 - // |_ node 11 - // |_ node 111 - - scoped_ptr<Layer> node1(CreateTextureRootLayer(gfx::Rect(0, 0, 400, 400))); - - scoped_ptr<Layer> node11(CreateTextureLayer(gfx::Rect(50, 50, 100, 100))); - node1->Add(node11.get()); - - scoped_ptr<Layer> node111(CreateTextureLayer(gfx::Rect(10, 10, 20, 20))); - node11->Add(node111.get()); - - Draw(); - EXPECT_EQ(gfx::Rect(50, 50, 100, 100), node1->hole_rect()); - EXPECT_EQ(gfx::Rect(10, 10, 20, 20), node11->hole_rect()); - - - node11->SetOpacity(0.5f); - Draw(); - EXPECT_TRUE(node1->hole_rect().IsEmpty()); - EXPECT_TRUE(node11->hole_rect().IsEmpty()); -} - -// Verifies that a non visible layer or any of its children is not a hole. -TEST_F(LayerWithNullDelegateTest, NonVisibleLayerCannotBeHole) { - // Layer tree looks like: - // node 1 - // |_ node 11 - // |_ node 111 - - scoped_ptr<Layer> node1(CreateTextureRootLayer(gfx::Rect(0, 0, 400, 400))); - - scoped_ptr<Layer> node11(CreateTextureLayer(gfx::Rect(50, 50, 100, 100))); - node1->Add(node11.get()); - - scoped_ptr<Layer> node111(CreateTextureLayer(gfx::Rect(10, 10, 20, 20))); - node11->Add(node111.get()); - - Draw(); - EXPECT_EQ(gfx::Rect(50, 50, 100, 100), node1->hole_rect()); - EXPECT_EQ(gfx::Rect(10, 10, 20, 20), node11->hole_rect()); - - - node11->SetVisible(false); - Draw(); - EXPECT_TRUE(node1->hole_rect().IsEmpty()); - EXPECT_TRUE(node11->hole_rect().IsEmpty()); -} - -// Verifies that a layer which doesn't fill its bounds opaquely cannot punch a -// hole. However its children should still be able to punch a hole. -TEST_F(LayerWithNullDelegateTest, LayerNotFillingBoundsOpaquelyCannotBeHole) { - // Layer tree looks like: - // node 1 - // |_ node 11 - // |_ node 111 - - scoped_ptr<Layer> node1(CreateTextureRootLayer(gfx::Rect(0, 0, 400, 400))); - - scoped_ptr<Layer> node11(CreateTextureLayer(gfx::Rect(50, 50, 100, 100))); - node1->Add(node11.get()); - - scoped_ptr<Layer> node111(CreateTextureLayer(gfx::Rect(10, 10, 20, 20))); - node11->Add(node111.get()); - - Draw(); - EXPECT_EQ(gfx::Rect(50, 50, 100, 100), node1->hole_rect()); - EXPECT_EQ(gfx::Rect(10, 10, 20, 20), node11->hole_rect()); - - - node11->SetFillsBoundsOpaquely(false); - Draw(); - EXPECT_EQ(gfx::Rect(60, 60, 20, 20), node1->hole_rect()); - EXPECT_TRUE(node11->hole_rect().IsEmpty()); -} - // Verifies that the hole is with respect to the local bounds of its parent. TEST_F(LayerWithNullDelegateTest, HoleLocalBounds) { scoped_ptr<Layer> parent(CreateTextureRootLayer( @@ -666,20 +555,16 @@ TEST_F(LayerWithNullDelegateTest, HoleLocalBounds) { scoped_ptr<Layer> child(CreateTextureLayer(gfx::Rect(50, 50, 100, 100))); parent->Add(child.get()); - Draw(); - EXPECT_EQ(gfx::Rect(50, 50, 100, 100), parent->hole_rect()); } // Verifies that there is no hole present when one of the child layers has a // transform. TEST_F(LayerWithNullDelegateTest, NoHoleWithTransform) { - scoped_ptr<Layer> parent(CreateTextureRootLayer(gfx::Rect(0, 0, 400, 400))); + scoped_ptr<Layer> parent(CreateTextureLayer(gfx::Rect(0, 0, 400, 400))); scoped_ptr<Layer> child(CreateTextureLayer(gfx::Rect(50, 50, 100, 100))); parent->Add(child.get()); - Draw(); - EXPECT_TRUE(!parent->hole_rect().IsEmpty()); ui::Transform t; @@ -688,20 +573,16 @@ TEST_F(LayerWithNullDelegateTest, NoHoleWithTransform) { t.ConcatTranslate(50, 50); child->SetTransform(t); - Draw(); - 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(CreateTextureRootLayer(gfx::Rect(0, 0, 400, 400))); + 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()); - Draw(); - EXPECT_TRUE(!parent->hole_rect().IsEmpty()); for (int i = -4; i <= 4; ++i) { @@ -716,67 +597,10 @@ TEST_F(LayerWithNullDelegateTest, HoleWithNinetyDegreeTransforms) { t.ConcatTranslate(child->bounds().x(), child->bounds().y()); t.TransformRect(&target_rect); - Draw(); - EXPECT_EQ(target_rect, parent->hole_rect()); } } -// Verifies that a layer which doesn't have a texture cannot punch a -// hole. However its children should still be able to punch a hole. -TEST_F(LayerWithNullDelegateTest, HoleWithRelativeNinetyDegreeTransforms) { - // Layer tree looks like: - // node 1 - // |_ node 11 - // |_ node 12 - - scoped_ptr<Layer> node1(CreateTextureRootLayer(gfx::Rect(0, 0, 400, 400))); - - scoped_ptr<Layer> node11(CreateTextureLayer(gfx::Rect(50, 50, 50, 50))); - node1->Add(node11.get()); - - scoped_ptr<Layer> node12(CreateTextureLayer(gfx::Rect(50, 50, 50, 50))); - node1->Add(node12.get()); - - Draw(); - - EXPECT_EQ(gfx::Rect(0, 0, 50, 50), node11->hole_rect()); - EXPECT_TRUE(node12->hole_rect().IsEmpty()); - - ui::Transform t1; - // Need to rotate in local coordinates. - t1.SetTranslate(-25, -25); - t1.ConcatRotate(45.0f); - t1.ConcatTranslate(25, 25); - node11->SetTransform(t1); - - Draw(); - - EXPECT_TRUE(node12->hole_rect().IsEmpty()); - EXPECT_TRUE(node11->hole_rect().IsEmpty()); - - ui::Transform t2; - // Need to rotate in local coordinates. - t2.SetTranslate(-25, -25); - t2.ConcatRotate(-135.0f); - t2.ConcatTranslate(25, 25); - node12->SetTransform(t2); - - // Do translation of target rect in order to account for inprecision of - // using floating point matrices vs integer rects. - ui::Transform t3; - gfx::Rect target_rect = gfx::Rect(node11->bounds().size()); - t3.ConcatTransform(t2); - t1.GetInverse(&t1); - t3.ConcatTransform(t1); - t3.TransformRect(&target_rect); - - Draw(); - - EXPECT_TRUE(node12->hole_rect().IsEmpty()); - EXPECT_EQ(target_rect, node11->hole_rect()); -} - // Create this hierarchy: // L1 (no texture) // +- L11 (texture) |