Remove the extra, unneeded commits that TextureLayer::Update does.

BUG=

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@230587 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/cc/layers/texture_layer.cc b/cc/layers/texture_layer.cc
index 18410fb5..45a456e 100644
--- a/cc/layers/texture_layer.cc
+++ b/cc/layers/texture_layer.cc
@@ -132,9 +132,10 @@
   SetNextCommitWaitsForActivation();
 }
 
-void TextureLayer::SetTextureMailbox(
+void TextureLayer::SetTextureMailboxInternal(
     const TextureMailbox& mailbox,
-    scoped_ptr<SingleReleaseCallback> release_callback) {
+    scoped_ptr<SingleReleaseCallback> release_callback,
+    bool requires_commit) {
   DCHECK(uses_mailbox_);
   DCHECK(!mailbox.IsValid() || !holder_ref_ ||
          !mailbox.Equals(holder_ref_->holder()->mailbox()));
@@ -146,12 +147,26 @@
   else
     holder_ref_.reset();
   needs_set_mailbox_ = true;
-  SetNeedsCommit();
+  // If we are within a commit, no need to do it again immediately after.
+  if (requires_commit)
+    SetNeedsCommit();
+  else
+    SetNeedsPushProperties();
+
   // The active frame needs to be replaced and the mailbox returned before the
   // commit is called complete.
   SetNextCommitWaitsForActivation();
 }
 
+void TextureLayer::SetTextureMailbox(
+    const TextureMailbox& mailbox,
+    scoped_ptr<SingleReleaseCallback> release_callback) {
+  SetTextureMailboxInternal(
+      mailbox,
+      release_callback.Pass(),
+      true /* requires_commit */);
+}
+
 void TextureLayer::WillModifyTexture() {
   if (layer_tree_host() && (DrawsContent() || content_committed_)) {
     layer_tree_host()->AcquireLayerTextures();
@@ -209,7 +224,11 @@
               &mailbox,
               &release_callback,
               layer_tree_host()->UsingSharedMemoryResources())) {
-        SetTextureMailbox(mailbox, release_callback.Pass());
+        // Already within a commit, no need to do another one immediately.
+        SetTextureMailboxInternal(
+            mailbox,
+            release_callback.Pass(),
+            false /* requires_commit */);
         updated = true;
       }
     } else {
diff --git a/cc/layers/texture_layer.h b/cc/layers/texture_layer.h
index b0edb22..0a7fd4e3 100644
--- a/cc/layers/texture_layer.h
+++ b/cc/layers/texture_layer.h
@@ -148,6 +148,11 @@
   virtual ~TextureLayer();
 
  private:
+  void SetTextureMailboxInternal(
+      const TextureMailbox& mailbox,
+      scoped_ptr<SingleReleaseCallback> release_callback,
+      bool requires_commit);
+
   TextureLayerClient* client_;
   bool uses_mailbox_;
 
diff --git a/cc/layers/texture_layer_unittest.cc b/cc/layers/texture_layer_unittest.cc
index c576341..63cf132a 100644
--- a/cc/layers/texture_layer_unittest.cc
+++ b/cc/layers/texture_layer_unittest.cc
@@ -1695,6 +1695,109 @@
 // delegating renderer.
 SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(TextureLayerChangeInvisibleTest);
 
+// Checks that TextureLayer::Update does not cause an extra commit when setting
+// the texture mailbox.
+class TextureLayerNoExtraCommitForMailboxTest
+    : public LayerTreeTest,
+      public TextureLayerClient {
+ public:
+  TextureLayerNoExtraCommitForMailboxTest()
+      : prepare_mailbox_count_(0) {}
+
+  // TextureLayerClient implementation.
+  virtual unsigned PrepareTexture() OVERRIDE {
+    NOTREACHED();
+    return 0;
+  }
+
+  // TextureLayerClient implementation.
+  virtual WebKit::WebGraphicsContext3D* Context3d() OVERRIDE {
+    NOTREACHED();
+    return NULL;
+  }
+
+  virtual bool PrepareTextureMailbox(
+      cc::TextureMailbox* mailbox,
+      scoped_ptr<SingleReleaseCallback>* release_callback,
+      bool use_shared_memory) OVERRIDE {
+    prepare_mailbox_count_++;
+    // Alternate between two mailboxes to ensure that the TextureLayer updates
+    // and commits.
+    if (prepare_mailbox_count_ % 2 == 0)
+      *mailbox = MakeMailbox('1');
+    else
+      *mailbox = MakeMailbox('2');
+
+    // Non-zero mailboxes need a callback.
+    *release_callback = SingleReleaseCallback::Create(
+        base::Bind(&TextureLayerNoExtraCommitForMailboxTest::MailboxReleased,
+                   base::Unretained(this)));
+    // If the test fails, this would cause an infinite number of commits.
+    return true;
+  }
+
+  TextureMailbox MakeMailbox(char name) {
+    return TextureMailbox(std::string(64, name));
+  }
+
+  void MailboxReleased(unsigned sync_point, bool lost_resource) {
+  }
+
+  virtual void SetupTree() OVERRIDE {
+    scoped_refptr<Layer> root = Layer::Create();
+    root->SetBounds(gfx::Size(10, 10));
+    root->SetAnchorPoint(gfx::PointF());
+    root->SetIsDrawable(true);
+
+    solid_layer_ = SolidColorLayer::Create();
+    solid_layer_->SetBounds(gfx::Size(10, 10));
+    solid_layer_->SetIsDrawable(true);
+    solid_layer_->SetBackgroundColor(SK_ColorWHITE);
+    root->AddChild(solid_layer_);
+
+    parent_layer_ = Layer::Create();
+    parent_layer_->SetBounds(gfx::Size(10, 10));
+    parent_layer_->SetIsDrawable(true);
+    root->AddChild(parent_layer_);
+
+    texture_layer_ = TextureLayer::CreateForMailbox(this);
+    texture_layer_->SetBounds(gfx::Size(10, 10));
+    texture_layer_->SetAnchorPoint(gfx::PointF());
+    texture_layer_->SetIsDrawable(true);
+    parent_layer_->AddChild(texture_layer_);
+
+    layer_tree_host()->SetRootLayer(root);
+    LayerTreeTest::SetupTree();
+  }
+
+  virtual void BeginTest() OVERRIDE {
+    PostSetNeedsCommitToMainThread();
+  }
+
+
+  virtual void DidCommit() OVERRIDE {
+    switch (layer_tree_host()->source_frame_number()) {
+      case 1:
+        EndTest();
+        break;
+      default:
+        NOTREACHED();
+        break;
+    }
+  }
+
+  virtual void AfterTest() OVERRIDE {}
+
+ private:
+  scoped_refptr<SolidColorLayer> solid_layer_;
+  scoped_refptr<Layer> parent_layer_;
+  scoped_refptr<TextureLayer> texture_layer_;
+
+  int prepare_mailbox_count_;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(TextureLayerNoExtraCommitForMailboxTest);
+
 // Checks that changing a mailbox in the client for a TextureLayer that's
 // invisible correctly works and uses the new mailbox as soon as the layer
 // becomes visible (and returns the old one).