Add cc::LayerClient::OnLayerOpacityChanged.
This method is called when the opacity of a cc::Layer changes.
It is used to ensure that ui::LayerDelegate::OnLayerOpacityChanged()
is called even when the opacity of a layer changes without going
through ui::Layer::SetOpacityFromAnimation().
TBR=junov@chromium.org
Bug: 728208
Cq-Include-Trybots: master.tryserver.blink:linux_trusty_blink_rel
Change-Id: I0d7055591748c824687b93700aec9d38045b7c9e
Reviewed-on: https://chromium-review.googlesource.com/671116
Commit-Queue: Francois Doray <fdoray@chromium.org>
Reviewed-by: danakj <danakj@chromium.org>
Cr-Commit-Position: refs/heads/master@{#502994}
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index 8555592..b1414ef 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -458,6 +458,8 @@
"test/layer_tree_pixel_test.h",
"test/layer_tree_test.cc",
"test/layer_tree_test.h",
+ "test/mock_layer_client.cc",
+ "test/mock_layer_client.h",
"test/mock_occlusion_tracker.h",
"test/ordered_texture_map.cc",
"test/ordered_texture_map.h",
diff --git a/cc/layers/layer.cc b/cc/layers/layer.cc
index 3c830cc..5931f8b 100644
--- a/cc/layers/layer.cc
+++ b/cc/layers/layer.cc
@@ -202,6 +202,13 @@
return !layer_tree_host_->in_paint_layer_contents();
}
+void Layer::SetOpacityInternal(float new_opacity) {
+ float old_opacity = inputs_.opacity;
+ inputs_.opacity = new_opacity;
+ if (new_opacity != old_opacity && inputs_.client)
+ inputs_.client->DidChangeLayerOpacity(old_opacity, new_opacity);
+}
+
sk_sp<SkPicture> Layer::GetPicture() const {
return nullptr;
}
@@ -504,7 +511,7 @@
// We need to force a property tree rebuild when opacity changes from 1 to a
// non-1 value or vice-versa as render surfaces can change.
bool force_rebuild = opacity == 1.f || inputs_.opacity == 1.f;
- inputs_.opacity = opacity;
+ SetOpacityInternal(opacity);
SetSubtreePropertyChanged();
if (layer_tree_host_ && !force_rebuild) {
PropertyTrees* property_trees = layer_tree_host_->property_trees();
@@ -1329,7 +1336,7 @@
}
void Layer::OnOpacityAnimated(float opacity) {
- inputs_.opacity = opacity;
+ SetOpacityInternal(opacity);
}
TransformNode* Layer::GetTransformNode() const {
diff --git a/cc/layers/layer.h b/cc/layers/layer.h
index 72a040a6..98a9062 100644
--- a/cc/layers/layer.h
+++ b/cc/layers/layer.h
@@ -477,6 +477,10 @@
bool IsPropertyChangeAllowed() const;
+ // Sets |inputs_.opacity| to |new_opacity| and notifies |inputs_.client| if
+ // the opacity has changed.
+ void SetOpacityInternal(float new_opacity);
+
// When true, the layer is about to perform an update. Any commit requests
// will be handled implicitly after the update completes.
bool ignore_set_needs_commit_;
diff --git a/cc/layers/layer_client.h b/cc/layers/layer_client.h
index 85c9772..59fe5b91 100644
--- a/cc/layers/layer_client.h
+++ b/cc/layers/layer_client.h
@@ -33,6 +33,9 @@
virtual void didUpdateMainThreadScrollingReasons() = 0;
virtual void didChangeScrollbarsHidden(bool) = 0;
+ // Invoked when the layer's opacity has changed.
+ virtual void DidChangeLayerOpacity(float old_opacity, float new_opacity) = 0;
+
protected:
virtual ~LayerClient() {}
};
diff --git a/cc/layers/layer_unittest.cc b/cc/layers/layer_unittest.cc
index 5ba8c40..05e0066d 100644
--- a/cc/layers/layer_unittest.cc
+++ b/cc/layers/layer_unittest.cc
@@ -22,6 +22,7 @@
#include "cc/test/fake_layer_tree_host_impl.h"
#include "cc/test/geometry_test_utils.h"
#include "cc/test/layer_test_common.h"
+#include "cc/test/mock_layer_client.h"
#include "cc/test/stub_layer_tree_host_single_thread_client.h"
#include "cc/test/test_task_graph_runner.h"
#include "cc/trees/layer_tree_host.h"
@@ -1486,6 +1487,26 @@
test_layer->SetLayerTreeHost(nullptr);
}
+// Verify that LayerClient::DidChangeLayerOpacity() is called when
+// Layer::SetOpacity() is called and the opacity changes.
+TEST_F(LayerTest, SetOpacityNotifiesClient) {
+ testing::StrictMock<MockLayerClient> client;
+ scoped_refptr<Layer> layer = Layer::Create();
+ layer->SetLayerClient(&client);
+ EXPECT_CALL(client, DidChangeLayerOpacity(1.0f, 0.5f));
+ layer->SetOpacity(0.5f);
+}
+
+// Verify that LayerClient::DidChangeLayerOpacity() is not called when
+// Layer::SetOpacity() is called but the opacity does not change.
+TEST_F(LayerTest, SetOpacityNoChangeDoesNotNotifyClient) {
+ testing::StrictMock<MockLayerClient> client;
+ scoped_refptr<Layer> layer = Layer::Create();
+ layer->SetLayerClient(&client);
+ // Since |client| is a StrictMock, the test will fail if it is notified.
+ layer->SetOpacity(1.0f);
+}
+
class LayerTestWithLayerLists : public LayerTest {
protected:
void SetUp() override {
diff --git a/cc/test/mock_layer_client.cc b/cc/test/mock_layer_client.cc
new file mode 100644
index 0000000..ce2e034
--- /dev/null
+++ b/cc/test/mock_layer_client.cc
@@ -0,0 +1,12 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/test/mock_layer_client.h"
+
+namespace cc {
+
+MockLayerClient::MockLayerClient() = default;
+MockLayerClient::~MockLayerClient() = default;
+
+} // namespace cc
diff --git a/cc/test/mock_layer_client.h b/cc/test/mock_layer_client.h
new file mode 100644
index 0000000..3feb1eb
--- /dev/null
+++ b/cc/test/mock_layer_client.h
@@ -0,0 +1,33 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_TEST_MOCK_LAYER_CLIENT_H_
+#define CC_TEST_MOCK_LAYER_CLIENT_H_
+
+#include "base/macros.h"
+#include "base/trace_event/trace_event_impl.h"
+#include "cc/layers/layer_client.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace cc {
+
+class MockLayerClient : public LayerClient {
+ public:
+ MockLayerClient();
+ ~MockLayerClient() override;
+
+ MOCK_METHOD1(
+ TakeDebugInfo,
+ std::unique_ptr<base::trace_event::ConvertableToTraceFormat>(Layer*));
+ MOCK_METHOD0(didUpdateMainThreadScrollingReasons, void());
+ MOCK_METHOD1(didChangeScrollbarsHidden, void(bool));
+ MOCK_METHOD2(DidChangeLayerOpacity, void(float, float));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockLayerClient);
+};
+
+} // namespace cc
+
+#endif // CC_TEST_MOCK_LAYER_CLIENT_H_
diff --git a/cc/trees/layer_tree_host_unittest_animation.cc b/cc/trees/layer_tree_host_unittest_animation.cc
index 36cfb9ae..682fdd4 100644
--- a/cc/trees/layer_tree_host_unittest_animation.cc
+++ b/cc/trees/layer_tree_host_unittest_animation.cc
@@ -7,6 +7,7 @@
#include <stdint.h>
#include <climits>
+#include "base/bind.h"
#include "cc/animation/animation_curve.h"
#include "cc/animation/animation_host.h"
#include "cc/animation/animation_id_provider.h"
@@ -24,6 +25,7 @@
#include "cc/test/fake_content_layer_client.h"
#include "cc/test/fake_picture_layer.h"
#include "cc/test/layer_tree_test.h"
+#include "cc/test/mock_layer_client.h"
#include "cc/trees/layer_tree_impl.h"
#include "cc/trees/transform_node.h"
@@ -425,6 +427,41 @@
SINGLE_AND_MULTI_THREAD_TEST_F(
LayerTreeHostAnimationTestAnimationFinishedEvents);
+// Ensures that LayerClient::DidChangeLayerOpacity() is notified when an
+// animation changes the opacity of a Layer.
+class LayerTreeHostAnimationTestOpacityAnimationNotifiesClient
+ : public LayerTreeHostAnimationTest {
+ public:
+ void BeginTest() override {
+ AttachPlayersToTimeline();
+ Layer* layer = layer_tree_host()->root_layer();
+ layer->SetLayerClient(&layer_client_);
+ player_->AttachElement(layer->element_id());
+ MainThreadTaskRunner()->PostTask(
+ FROM_HERE,
+ base::BindOnce(base::IgnoreResult(&AddOpacityTransitionToPlayer),
+ base::Unretained(player_.get()), 0.0, 1.0f, 0.5f, true));
+ EXPECT_CALL(layer_client_, DidChangeLayerOpacity(1.0f, 0.5f));
+ }
+
+ void NotifyAnimationFinished(base::TimeTicks monotonic_time,
+ int target_property,
+ int group) override {
+ Animation* animation = player_->GetAnimation(TargetProperty::OPACITY);
+ if (animation)
+ player_->RemoveAnimation(animation->id());
+ EndTest();
+ }
+
+ void AfterTest() override {}
+
+ private:
+ MockLayerClient layer_client_;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(
+ LayerTreeHostAnimationTestOpacityAnimationNotifiesClient);
+
// Ensures that when opacity is being animated, this value does not cause the
// subtree to be skipped.
class LayerTreeHostAnimationTestDoNotSkipLayersWithAnimatedOpacity