cc: Ensure changes to a Layer's content bounds or scale get pushed

This changes UpdateLayerContentsScale(Layer* layer, ...) so that if
the layer's content bounds or contents scale are changed, then its
needs_push_properties() flag is set.

BUG=345267

Review URL: https://codereview.chromium.org/178303002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@253140 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/cc/layers/layer.h b/cc/layers/layer.h
index 2f891ec..37772e9 100644
--- a/cc/layers/layer.h
+++ b/cc/layers/layer.h
@@ -440,10 +440,14 @@
 
   virtual bool SupportsLCDText() const;
 
+  void SetNeedsPushProperties();
   bool needs_push_properties() const { return needs_push_properties_; }
   bool descendant_needs_push_properties() const {
     return num_dependents_need_push_properties_ > 0;
   }
+  void reset_needs_push_properties_for_testing() {
+    needs_push_properties_ = false;
+  }
 
   virtual void RunMicroBenchmark(MicroBenchmark* benchmark);
 
@@ -476,7 +480,6 @@
   // Called when the blend mode or filters have been changed.
   void SetNeedsFilterContextIfNeeded();
 
-  void SetNeedsPushProperties();
   void AddDependentNeedsPushProperties();
   void RemoveDependentNeedsPushProperties();
   bool parent_should_know_need_push_properties() const {
diff --git a/cc/trees/layer_tree_host_common.cc b/cc/trees/layer_tree_host_common.cc
index 9f652d9..ddee3930 100644
--- a/cc/trees/layer_tree_host_common.cc
+++ b/cc/trees/layer_tree_host_common.cc
@@ -989,6 +989,9 @@
   if (!layer->raster_scale_is_unknown())
     raster_scale = layer->raster_scale();
 
+  gfx::Size old_content_bounds = layer->content_bounds();
+  float old_contents_scale_x = layer->contents_scale_x();
+  float old_contents_scale_y = layer->contents_scale_y();
 
   float contents_scale = raster_scale * device_scale_factor * page_scale_factor;
   CalculateContentsScale(layer,
@@ -996,6 +999,11 @@
                          device_scale_factor,
                          page_scale_factor,
                          animating_transform_to_screen);
+
+  if (layer->content_bounds() != old_content_bounds ||
+      layer->contents_scale_x() != old_contents_scale_x ||
+      layer->contents_scale_y() != old_contents_scale_y)
+    layer->SetNeedsPushProperties();
 }
 
 static inline RenderSurface* CreateOrReuseRenderSurface(Layer* layer) {
diff --git a/cc/trees/layer_tree_host_common_unittest.cc b/cc/trees/layer_tree_host_common_unittest.cc
index 43df32ae..7099883 100644
--- a/cc/trees/layer_tree_host_common_unittest.cc
+++ b/cc/trees/layer_tree_host_common_unittest.cc
@@ -7223,6 +7223,58 @@
   }
 }
 
+TEST_F(LayerTreeHostCommonTest,
+       ChangeInContentBoundsOrScaleTriggersPushProperties) {
+  MockContentLayerClient delegate;
+  scoped_refptr<Layer> root = Layer::Create();
+  scoped_refptr<Layer> child = CreateDrawableContentLayer(&delegate);
+  root->AddChild(child);
+
+  scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create();
+  host->SetRootLayer(root);
+
+  gfx::Transform identity_matrix;
+  SetLayerPropertiesForTesting(root.get(),
+                               identity_matrix,
+                               gfx::PointF(),
+                               gfx::PointF(),
+                               gfx::Size(100, 100),
+                               true,
+                               false);
+  SetLayerPropertiesForTesting(child.get(),
+                               identity_matrix,
+                               gfx::PointF(),
+                               gfx::PointF(),
+                               gfx::Size(100, 100),
+                               true,
+                               false);
+
+  root->reset_needs_push_properties_for_testing();
+  child->reset_needs_push_properties_for_testing();
+
+  // This will change both layers' content bounds.
+  ExecuteCalculateDrawProperties(root.get());
+  EXPECT_TRUE(root->needs_push_properties());
+  EXPECT_TRUE(child->needs_push_properties());
+
+  root->reset_needs_push_properties_for_testing();
+  child->reset_needs_push_properties_for_testing();
+
+  // This will change only the child layer's contents scale and content bounds,
+  // since the root layer is not a ContentsScalingLayer.
+  ExecuteCalculateDrawProperties(root.get(), 2.f);
+  EXPECT_FALSE(root->needs_push_properties());
+  EXPECT_TRUE(child->needs_push_properties());
+
+  root->reset_needs_push_properties_for_testing();
+  child->reset_needs_push_properties_for_testing();
+
+  // This will not change either layer's contents scale or content bounds.
+  ExecuteCalculateDrawProperties(root.get(), 2.f);
+  EXPECT_FALSE(root->needs_push_properties());
+  EXPECT_FALSE(child->needs_push_properties());
+}
+
 TEST_F(LayerTreeHostCommonTest, RenderSurfaceTransformsInHighDPI) {
   MockContentLayerClient delegate;
   gfx::Transform identity_matrix;
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index eb81d5b..d56ba21 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -817,6 +817,77 @@
 
 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestUndrawnLayersDamageLater);
 
+// Tests that if a layer is not drawn because of some reason in the parent,
+// causing its content bounds to not be computed, then when it is later drawn,
+// its content bounds get pushed.
+class LayerTreeHostTestUndrawnLayersPushContentBoundsLater
+    : public LayerTreeHostTest {
+ public:
+  LayerTreeHostTestUndrawnLayersPushContentBoundsLater()
+      : root_layer_(Layer::Create()) {}
+
+  virtual void SetupTree() OVERRIDE {
+    root_layer_->SetIsDrawable(true);
+    root_layer_->SetBounds(gfx::Size(20, 20));
+    layer_tree_host()->SetRootLayer(root_layer_);
+
+    parent_layer_ = Layer::Create();
+    parent_layer_->SetBounds(gfx::Size(20, 20));
+    parent_layer_->SetOpacity(0.0f);
+    root_layer_->AddChild(parent_layer_);
+
+    child_layer_ = Layer::Create();
+    child_layer_->SetBounds(gfx::Size(15, 15));
+    parent_layer_->AddChild(child_layer_);
+
+    LayerTreeHostTest::SetupTree();
+  }
+
+  virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
+
+  virtual void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
+    LayerImpl* root = host_impl->active_tree()->root_layer();
+    LayerImpl* parent = root->children()[0];
+    LayerImpl* child = parent->children()[0];
+
+    switch (host_impl->active_tree()->source_frame_number()) {
+      case 0:
+        EXPECT_EQ(0.f, parent->opacity());
+        EXPECT_EQ(gfx::SizeF(), child->content_bounds());
+        break;
+      case 1:
+        EXPECT_EQ(1.f, parent->opacity());
+        EXPECT_EQ(gfx::SizeF(15.f, 15.f), child->content_bounds());
+        EndTest();
+        break;
+      default:
+        NOTREACHED();
+    }
+  }
+
+  virtual void DidCommit() OVERRIDE {
+    switch (layer_tree_host()->source_frame_number()) {
+      case 1:
+        parent_layer_->SetOpacity(1.0f);
+        break;
+      case 2:
+        break;
+      default:
+        NOTREACHED();
+    }
+  }
+
+  virtual void AfterTest() OVERRIDE {}
+
+ private:
+  scoped_refptr<Layer> root_layer_;
+  scoped_refptr<Layer> parent_layer_;
+  scoped_refptr<Layer> child_layer_;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(
+    LayerTreeHostTestUndrawnLayersPushContentBoundsLater);
+
 // If the layerTreeHost says it can't draw, Then we should not try to draw.
 class LayerTreeHostTestCanDrawBlocksDrawing : public LayerTreeHostTest {
  public: