[go: nahoru, domu]

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