Upstream version 11.39.250.0
[platform/framework/web/crosswalk.git] / src / cc / scheduler / scheduler_unittest.cc
index 2099b8a..0a08c5b 100644 (file)
@@ -6,48 +6,51 @@
 #include <string>
 #include <vector>
 
+#include "base/debug/trace_event.h"
 #include "base/logging.h"
 #include "base/memory/scoped_vector.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/time/time.h"
+#include "cc/test/begin_frame_args_test.h"
+#include "cc/test/ordered_simple_task_runner.h"
 #include "cc/test/scheduler_test_common.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 #define EXPECT_ACTION(action, client, action_index, expected_num_actions) \
-  EXPECT_EQ(expected_num_actions, client.num_actions_());                 \
-  ASSERT_LT(action_index, client.num_actions_());                         \
   do {                                                                    \
-    EXPECT_STREQ(action, client.Action(action_index));                    \
+    EXPECT_EQ(expected_num_actions, client.num_actions_());               \
+    if (action_index >= 0) {                                              \
+      ASSERT_LT(action_index, client.num_actions_()) << scheduler;        \
+      EXPECT_STREQ(action, client.Action(action_index));                  \
+    }                                                                     \
     for (int i = expected_num_actions; i < client.num_actions_(); ++i)    \
-      ADD_FAILURE() << "Unexpected action: " << client.Action(i) <<       \
-          " with state:\n" << client.StateForAction(action_index);        \
+      ADD_FAILURE() << "Unexpected action: " << client.Action(i)          \
+                    << " with state:\n" << client.StateForAction(i);      \
   } while (false)
 
+#define EXPECT_NO_ACTION(client) EXPECT_ACTION("", client, -1, 0)
+
 #define EXPECT_SINGLE_ACTION(action, client) \
   EXPECT_ACTION(action, client, 0, 1)
 
 namespace cc {
 namespace {
 
-void InitializeOutputSurfaceAndFirstCommit(Scheduler* scheduler) {
-  scheduler->DidCreateAndInitializeOutputSurface();
-  scheduler->SetNeedsCommit();
-  scheduler->FinishCommit();
-  // Go through the motions to draw the commit.
-  scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
-  scheduler->OnBeginImplFrameDeadline();
-  // We need another BeginImplFrame so Scheduler calls
-  // SetNeedsBeginImplFrame(false).
-  scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
-  scheduler->OnBeginImplFrameDeadline();
-}
+class FakeSchedulerClient;
+
+void InitializeOutputSurfaceAndFirstCommit(Scheduler* scheduler,
+                                           FakeSchedulerClient* client);
 
 class FakeSchedulerClient : public SchedulerClient {
  public:
   FakeSchedulerClient()
-  : needs_begin_impl_frame_(false) {
+      : needs_begin_frame_(false),
+        automatic_swap_ack_(true),
+        swap_contains_incomplete_tile_(false),
+        redraw_will_happen_if_update_visible_tiles_happens_(false),
+        now_src_(TestNowSource::Create()) {
     Reset();
   }
 
@@ -60,8 +63,10 @@ class FakeSchedulerClient : public SchedulerClient {
     log_anticipated_draw_time_change_ = false;
   }
 
-  Scheduler* CreateScheduler(const SchedulerSettings& settings) {
-    scheduler_ = Scheduler::Create(this, settings, 0);
+  TestScheduler* CreateScheduler(const SchedulerSettings& settings) {
+    scheduler_ = TestScheduler::Create(now_src_, this, settings, 0);
+    // Fail if we need to run 100 tasks in a row.
+    task_runner().SetRunTaskLimit(100);
     return scheduler_.get();
   }
 
@@ -70,11 +75,30 @@ class FakeSchedulerClient : public SchedulerClient {
   void set_log_anticipated_draw_time_change(bool log) {
     log_anticipated_draw_time_change_ = log;
   }
-  bool needs_begin_impl_frame() { return needs_begin_impl_frame_; }
+  bool needs_begin_frame() { return needs_begin_frame_; }
   int num_draws() const { return num_draws_; }
   int num_actions_() const { return static_cast<int>(actions_.size()); }
   const char* Action(int i) const { return actions_[i]; }
-  base::Value& StateForAction(int i) const { return *states_[i]; }
+  std::string StateForAction(int i) const { return states_[i]->ToString(); }
+  base::TimeTicks posted_begin_impl_frame_deadline() const {
+    return posted_begin_impl_frame_deadline_;
+  }
+
+  void AdvanceFrame() {
+    bool external_begin_frame =
+        scheduler_->settings().begin_frame_scheduling_enabled &&
+        scheduler_->settings().throttle_frame_production;
+
+    if (external_begin_frame) {
+      scheduler_->BeginFrame(CreateBeginFrameArgsForTesting(now_src_));
+    }
+
+    EXPECT_TRUE(task_runner().RunTasksWhile(ImplFrameDeadlinePending(false)));
+    EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+  }
+
+  OrderedSimpleTaskRunner& task_runner() { return scheduler_->task_runner(); }
+  TestNowSource* now_src() { return now_src_.get(); }
 
   int ActionIndex(const char* action) const {
     for (size_t i = 0; i < actions_.size(); i++)
@@ -83,6 +107,10 @@ class FakeSchedulerClient : public SchedulerClient {
     return -1;
   }
 
+  void SetSwapContainsIncompleteTile(bool contain) {
+    swap_contains_incomplete_tile_ = contain;
+  }
+
   bool HasAction(const char* action) const {
     return ActionIndex(action) >= 0;
   }
@@ -93,71 +121,78 @@ class FakeSchedulerClient : public SchedulerClient {
   void SetSwapWillHappenIfDrawHappens(bool swap_will_happen_if_draw_happens) {
     swap_will_happen_if_draw_happens_ = swap_will_happen_if_draw_happens;
   }
-
+  void SetAutomaticSwapAck(bool automatic_swap_ack) {
+    automatic_swap_ack_ = automatic_swap_ack;
+  }
+  void SetRedrawWillHappenIfUpdateVisibleTilesHappens(bool redraw) {
+    redraw_will_happen_if_update_visible_tiles_happens_ = redraw;
+  }
   // SchedulerClient implementation.
-  virtual void SetNeedsBeginImplFrame(bool enable) OVERRIDE {
-    actions_.push_back("SetNeedsBeginImplFrame");
-    states_.push_back(scheduler_->StateAsValue().release());
-    needs_begin_impl_frame_ = enable;
+  virtual void SetNeedsBeginFrame(bool enable) OVERRIDE {
+    actions_.push_back("SetNeedsBeginFrame");
+    states_.push_back(scheduler_->AsValue());
+    needs_begin_frame_ = enable;
+  }
+  virtual void WillBeginImplFrame(const BeginFrameArgs& args) OVERRIDE {
+    actions_.push_back("WillBeginImplFrame");
+    states_.push_back(scheduler_->AsValue());
   }
   virtual void ScheduledActionSendBeginMainFrame() OVERRIDE {
     actions_.push_back("ScheduledActionSendBeginMainFrame");
-    states_.push_back(scheduler_->StateAsValue().release());
+    states_.push_back(scheduler_->AsValue());
   }
-  virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapIfPossible()
-      OVERRIDE {
+  virtual void ScheduledActionAnimate() OVERRIDE {
+    actions_.push_back("ScheduledActionAnimate");
+    states_.push_back(scheduler_->AsValue());
+  }
+  virtual DrawResult ScheduledActionDrawAndSwapIfPossible() OVERRIDE {
     actions_.push_back("ScheduledActionDrawAndSwapIfPossible");
-    states_.push_back(scheduler_->StateAsValue().release());
+    states_.push_back(scheduler_->AsValue());
     num_draws_++;
-    bool did_readback = false;
-    DrawSwapReadbackResult::DrawResult result =
-        draw_will_happen_
-            ? DrawSwapReadbackResult::DRAW_SUCCESS
-            : DrawSwapReadbackResult::DRAW_ABORTED_CHECKERBOARD_ANIMATIONS;
-    return DrawSwapReadbackResult(
-        result,
-        draw_will_happen_ && swap_will_happen_if_draw_happens_,
-        did_readback);
+    DrawResult result =
+        draw_will_happen_ ? DRAW_SUCCESS : DRAW_ABORTED_CHECKERBOARD_ANIMATIONS;
+    bool swap_will_happen =
+        draw_will_happen_ && swap_will_happen_if_draw_happens_;
+    if (swap_will_happen) {
+      scheduler_->DidSwapBuffers();
+      if (swap_contains_incomplete_tile_) {
+        scheduler_->SetSwapUsedIncompleteTile(true);
+        swap_contains_incomplete_tile_ = false;
+      } else {
+        scheduler_->SetSwapUsedIncompleteTile(false);
+      }
+
+      if (automatic_swap_ack_)
+        scheduler_->DidSwapBuffersComplete();
+    }
+    return result;
   }
-  virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapForced() OVERRIDE {
+  virtual DrawResult ScheduledActionDrawAndSwapForced() OVERRIDE {
     actions_.push_back("ScheduledActionDrawAndSwapForced");
-    states_.push_back(scheduler_->StateAsValue().release());
-    bool did_swap = swap_will_happen_if_draw_happens_;
-    bool did_readback = false;
-    return DrawSwapReadbackResult(
-        DrawSwapReadbackResult::DRAW_SUCCESS, did_swap, did_readback);
-  }
-  virtual DrawSwapReadbackResult ScheduledActionDrawAndReadback() OVERRIDE {
-    actions_.push_back("ScheduledActionDrawAndReadback");
-    states_.push_back(scheduler_->StateAsValue().release());
-    bool did_swap = false;
-    bool did_readback = true;
-    return DrawSwapReadbackResult(
-        DrawSwapReadbackResult::DRAW_SUCCESS, did_swap, did_readback);
+    states_.push_back(scheduler_->AsValue());
+    return DRAW_SUCCESS;
   }
   virtual void ScheduledActionCommit() OVERRIDE {
     actions_.push_back("ScheduledActionCommit");
-    states_.push_back(scheduler_->StateAsValue().release());
+    states_.push_back(scheduler_->AsValue());
   }
   virtual void ScheduledActionUpdateVisibleTiles() OVERRIDE {
     actions_.push_back("ScheduledActionUpdateVisibleTiles");
-    states_.push_back(scheduler_->StateAsValue().release());
+    states_.push_back(scheduler_->AsValue());
+    if (redraw_will_happen_if_update_visible_tiles_happens_)
+      scheduler_->SetNeedsRedraw();
   }
-  virtual void ScheduledActionActivatePendingTree() OVERRIDE {
-    actions_.push_back("ScheduledActionActivatePendingTree");
-    states_.push_back(scheduler_->StateAsValue().release());
+  virtual void ScheduledActionActivateSyncTree() OVERRIDE {
+    actions_.push_back("ScheduledActionActivateSyncTree");
+    states_.push_back(scheduler_->AsValue());
   }
   virtual void ScheduledActionBeginOutputSurfaceCreation() OVERRIDE {
     actions_.push_back("ScheduledActionBeginOutputSurfaceCreation");
-    states_.push_back(scheduler_->StateAsValue().release());
-  }
-  virtual void ScheduledActionAcquireLayerTexturesForMainThread() OVERRIDE {
-    actions_.push_back("ScheduledActionAcquireLayerTexturesForMainThread");
-    states_.push_back(scheduler_->StateAsValue().release());
+    states_.push_back(scheduler_->AsValue());
   }
   virtual void ScheduledActionManageTiles() OVERRIDE {
     actions_.push_back("ScheduledActionManageTiles");
-    states_.push_back(scheduler_->StateAsValue().release());
+    states_.push_back(scheduler_->AsValue());
   }
   virtual void DidAnticipatedDrawTimeChange(base::TimeTicks) OVERRIDE {
     if (log_anticipated_draw_time_change_)
@@ -173,29 +208,68 @@ class FakeSchedulerClient : public SchedulerClient {
     return base::TimeDelta();
   }
 
-  virtual void PostBeginImplFrameDeadline(const base::Closure& closure,
-                                          base::TimeTicks deadline) OVERRIDE {
-    actions_.push_back("PostBeginImplFrameDeadlineTask");
-    states_.push_back(scheduler_->StateAsValue().release());
-  }
-
   virtual void DidBeginImplFrameDeadline() OVERRIDE {}
 
+  base::Callback<bool(void)> ImplFrameDeadlinePending(bool state) {
+    return base::Bind(&FakeSchedulerClient::ImplFrameDeadlinePendingCallback,
+                      base::Unretained(this),
+                      state);
+  }
+
  protected:
-  bool needs_begin_impl_frame_;
+  bool ImplFrameDeadlinePendingCallback(bool state) {
+    return scheduler_->BeginImplFrameDeadlinePending() == state;
+  }
+
+  bool needs_begin_frame_;
   bool draw_will_happen_;
   bool swap_will_happen_if_draw_happens_;
+  bool automatic_swap_ack_;
   int num_draws_;
   bool log_anticipated_draw_time_change_;
+  bool swap_contains_incomplete_tile_;
+  bool redraw_will_happen_if_update_visible_tiles_happens_;
+  base::TimeTicks posted_begin_impl_frame_deadline_;
   std::vector<const char*> actions_;
-  ScopedVector<base::Value> states_;
-  scoped_ptr<Scheduler> scheduler_;
+  std::vector<scoped_refptr<base::debug::ConvertableToTraceFormat> > states_;
+  scoped_ptr<TestScheduler> scheduler_;
+  scoped_refptr<TestNowSource> now_src_;
 };
 
+void InitializeOutputSurfaceAndFirstCommit(Scheduler* scheduler,
+                                           FakeSchedulerClient* client) {
+  TRACE_EVENT0("cc",
+               "SchedulerUnitTest::InitializeOutputSurfaceAndFirstCommit");
+
+  scheduler->DidCreateAndInitializeOutputSurface();
+  scheduler->SetNeedsCommit();
+  scheduler->NotifyBeginMainFrameStarted();
+  scheduler->NotifyReadyToCommit();
+  if (scheduler->settings().impl_side_painting)
+    scheduler->NotifyReadyToActivate();
+
+  // Go through the motions to draw the commit.
+  client->AdvanceFrame();
+
+  // Run the posted deadline task.
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+  client->task_runner().RunTasksWhile(client->ImplFrameDeadlinePending(true));
+  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+
+  // We need another BeginImplFrame so Scheduler calls
+  // SetNeedsBeginFrame(false).
+  client->AdvanceFrame();
+
+  // Run the posted deadline task.
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+  client->task_runner().RunTasksWhile(client->ImplFrameDeadlinePending(true));
+  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+}
+
 TEST(SchedulerTest, InitializeOutputSurfaceDoesNotBeginImplFrame) {
   FakeSchedulerClient client;
   SchedulerSettings default_scheduler_settings;
-  Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+  TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
   scheduler->SetCanStart();
   scheduler->SetVisible(true);
   scheduler->SetCanDraw(true);
@@ -203,127 +277,99 @@ TEST(SchedulerTest, InitializeOutputSurfaceDoesNotBeginImplFrame) {
   EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
   client.Reset();
   scheduler->DidCreateAndInitializeOutputSurface();
-  EXPECT_EQ(0, client.num_actions_());
+  EXPECT_NO_ACTION(client);
 }
 
-void RequestCommit(bool deadline_scheduling_enabled) {
+TEST(SchedulerTest, RequestCommit) {
   FakeSchedulerClient client;
   SchedulerSettings scheduler_settings;
-  scheduler_settings.deadline_scheduling_enabled = deadline_scheduling_enabled;
-  Scheduler* scheduler = client.CreateScheduler(scheduler_settings);
+  TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
   scheduler->SetCanStart();
   scheduler->SetVisible(true);
   scheduler->SetCanDraw(true);
 
   EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
-  InitializeOutputSurfaceAndFirstCommit(scheduler);
+  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
 
   // SetNeedsCommit should begin the frame on the next BeginImplFrame.
   client.Reset();
   scheduler->SetNeedsCommit();
-  EXPECT_TRUE(client.needs_begin_impl_frame());
-  if (deadline_scheduling_enabled) {
-    EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
-  } else {
-    EXPECT_EQ(client.num_actions_(), 2);
-    EXPECT_TRUE(client.HasAction("ScheduledActionSendBeginMainFrame"));
-    EXPECT_TRUE(client.HasAction("SetNeedsBeginImplFrame"));
-  }
+  EXPECT_TRUE(client.needs_begin_frame());
+  EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
   client.Reset();
 
-  scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
-  if (deadline_scheduling_enabled) {
-    EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 2);
-    EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2);
-  } else {
-    EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
-  }
-  EXPECT_TRUE(client.needs_begin_impl_frame());
+  client.AdvanceFrame();
+  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+  EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+  EXPECT_TRUE(client.needs_begin_frame());
   client.Reset();
 
-  // If we don't swap on the deadline, we need to request another
-  // BeginImplFrame.
-  scheduler->OnBeginImplFrameDeadline();
-  EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
-  EXPECT_TRUE(client.needs_begin_impl_frame());
+  // If we don't swap on the deadline, we wait for the next BeginFrame.
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
+  EXPECT_NO_ACTION(client);
+  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+  EXPECT_TRUE(client.needs_begin_frame());
   client.Reset();
 
-  // FinishCommit should commit
-  scheduler->FinishCommit();
+  // NotifyReadyToCommit should trigger the commit.
+  scheduler->NotifyBeginMainFrameStarted();
+  scheduler->NotifyReadyToCommit();
   EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
-  EXPECT_TRUE(client.needs_begin_impl_frame());
+  EXPECT_TRUE(client.needs_begin_frame());
   client.Reset();
 
   // BeginImplFrame should prepare the draw.
-  scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
-  EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
-  EXPECT_TRUE(client.needs_begin_impl_frame());
+  client.AdvanceFrame();
+  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+  EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+  EXPECT_TRUE(client.needs_begin_frame());
   client.Reset();
 
   // BeginImplFrame deadline should draw.
-  scheduler->OnBeginImplFrameDeadline();
-  EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2);
-  EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2);
-  EXPECT_TRUE(client.needs_begin_impl_frame());
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
+  EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 1);
+  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+  EXPECT_TRUE(client.needs_begin_frame());
   client.Reset();
 
-  // The following BeginImplFrame deadline should SetNeedsBeginImplFrame(false)
+  // The following BeginImplFrame deadline should SetNeedsBeginFrame(false)
   // to avoid excessive toggles.
-  scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
-  EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
+  client.AdvanceFrame();
+  EXPECT_SINGLE_ACTION("WillBeginImplFrame", client);
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
   client.Reset();
 
-  scheduler->OnBeginImplFrameDeadline();
-  EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
-  EXPECT_FALSE(client.needs_begin_impl_frame());
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
+  EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
+  EXPECT_FALSE(client.needs_begin_frame());
   client.Reset();
 }
 
-TEST(SchedulerTest, RequestCommit) {
-  bool deadline_scheduling_enabled = false;
-  RequestCommit(deadline_scheduling_enabled);
-}
-
-TEST(SchedulerTest, RequestCommit_Deadline) {
-  bool deadline_scheduling_enabled = true;
-  RequestCommit(deadline_scheduling_enabled);
-}
-
-void RequestCommitAfterBeginMainFrameSent(
-    bool deadline_scheduling_enabled) {
+TEST(SchedulerTest, RequestCommitAfterBeginMainFrameSent) {
   FakeSchedulerClient client;
   SchedulerSettings scheduler_settings;
-  scheduler_settings.deadline_scheduling_enabled = deadline_scheduling_enabled;
-  Scheduler* scheduler = client.CreateScheduler(scheduler_settings);
+  TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
   scheduler->SetCanStart();
   scheduler->SetVisible(true);
   scheduler->SetCanDraw(true);
 
   EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
-  InitializeOutputSurfaceAndFirstCommit(scheduler);
+  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
   client.Reset();
 
   // SetNeedsCommit should begin the frame.
   scheduler->SetNeedsCommit();
-  if (deadline_scheduling_enabled) {
-    EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
-  } else {
-    EXPECT_EQ(client.num_actions_(), 2);
-    EXPECT_TRUE(client.HasAction("SetNeedsBeginImplFrame"));
-    EXPECT_TRUE(client.HasAction("ScheduledActionSendBeginMainFrame"));
-  }
+  EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
 
   client.Reset();
-  scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
-  if (deadline_scheduling_enabled) {
-    EXPECT_EQ(client.num_actions_(), 2);
-    EXPECT_TRUE(client.HasAction("ScheduledActionSendBeginMainFrame"));
-    EXPECT_TRUE(client.HasAction("PostBeginImplFrameDeadlineTask"));
-  } else {
-    EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
-  }
+  client.AdvanceFrame();
+  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+  EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
 
-  EXPECT_TRUE(client.needs_begin_impl_frame());
+  EXPECT_TRUE(client.needs_begin_frame());
   client.Reset();
 
   // Now SetNeedsCommit again. Calling here means we need a second commit.
@@ -332,358 +378,54 @@ void RequestCommitAfterBeginMainFrameSent(
   client.Reset();
 
   // Finish the first commit.
-  scheduler->FinishCommit();
-  EXPECT_ACTION("ScheduledActionCommit", client, 0, 2);
-  EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2);
-  client.Reset();
-  scheduler->OnBeginImplFrameDeadline();
-  if (deadline_scheduling_enabled) {
-    EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2);
-    EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2);
-  } else {
-    EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 3);
-    EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 3);
-    EXPECT_ACTION("SetNeedsBeginImplFrame", client, 2, 3);
-  }
+  scheduler->NotifyBeginMainFrameStarted();
+  scheduler->NotifyReadyToCommit();
+  EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+  client.Reset();
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
+  EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
+  EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
+  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
 
   // Because we just swapped, the Scheduler should also request the next
   // BeginImplFrame from the OutputSurface.
-  EXPECT_TRUE(client.needs_begin_impl_frame());
+  EXPECT_TRUE(client.needs_begin_frame());
   client.Reset();
-
   // Since another commit is needed, the next BeginImplFrame should initiate
   // the second commit.
-  scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
-  if (deadline_scheduling_enabled) {
-    EXPECT_EQ(client.num_actions_(), 2);
-    EXPECT_TRUE(client.HasAction("ScheduledActionSendBeginMainFrame"));
-    EXPECT_TRUE(client.HasAction("PostBeginImplFrameDeadlineTask"));
-  } else {
-    EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
-  }
+  client.AdvanceFrame();
+  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+  EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
   client.Reset();
 
   // Finishing the commit before the deadline should post a new deadline task
   // to trigger the deadline early.
-  scheduler->FinishCommit();
-  EXPECT_ACTION("ScheduledActionCommit", client, 0, 2);
-  EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2);
+  scheduler->NotifyBeginMainFrameStarted();
+  scheduler->NotifyReadyToCommit();
+  EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
   client.Reset();
-  scheduler->OnBeginImplFrameDeadline();
-  EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2);
-  EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2);
-  EXPECT_TRUE(client.needs_begin_impl_frame());
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
+  EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
+  EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
+  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+  EXPECT_TRUE(client.needs_begin_frame());
   client.Reset();
 
   // On the next BeginImplFrame, verify we go back to a quiescent state and
   // no longer request BeginImplFrames.
-  scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
-  scheduler->OnBeginImplFrameDeadline();
-  EXPECT_FALSE(client.needs_begin_impl_frame());
-  client.Reset();
-}
-
-TEST(SchedulerTest, RequestCommitAfterBeginMainFrameSent) {
-  bool deadline_scheduling_enabled = false;
-  RequestCommitAfterBeginMainFrameSent(deadline_scheduling_enabled);
-}
-
-TEST(SchedulerTest, RequestCommitAfterBeginMainFrameSent_Deadline) {
-  bool deadline_scheduling_enabled = true;
-  RequestCommitAfterBeginMainFrameSent(deadline_scheduling_enabled);
-}
-
-void TextureAcquisitionCausesCommitInsteadOfDraw(
-    bool deadline_scheduling_enabled) {
-  FakeSchedulerClient client;
-  SchedulerSettings scheduler_settings;
-  scheduler_settings.deadline_scheduling_enabled = deadline_scheduling_enabled;
-  Scheduler* scheduler = client.CreateScheduler(scheduler_settings);
-  scheduler->SetCanStart();
-  scheduler->SetVisible(true);
-  scheduler->SetCanDraw(true);
-  EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
-
-  InitializeOutputSurfaceAndFirstCommit(scheduler);
-  client.Reset();
-  scheduler->SetNeedsRedraw();
-  EXPECT_TRUE(scheduler->RedrawPending());
-  EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
-  EXPECT_TRUE(client.needs_begin_impl_frame());
-
-  client.Reset();
-  scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
-  EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
-  client.Reset();
-  scheduler->OnBeginImplFrameDeadline();
-  EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2);
-  EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2);
-  EXPECT_FALSE(scheduler->RedrawPending());
-  EXPECT_TRUE(client.needs_begin_impl_frame());
-
-  client.Reset();
-  scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
-  EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
-  client.Reset();
-  scheduler->OnBeginImplFrameDeadline();
-  EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
-  EXPECT_FALSE(scheduler->RedrawPending());
-  EXPECT_FALSE(client.needs_begin_impl_frame());
-
-  client.Reset();
-  scheduler->SetMainThreadNeedsLayerTextures();
-  EXPECT_SINGLE_ACTION("ScheduledActionAcquireLayerTexturesForMainThread",
-                       client);
-
-  // We should request a BeginImplFrame in anticipation of a draw.
-  client.Reset();
-  scheduler->SetNeedsRedraw();
-  EXPECT_TRUE(scheduler->RedrawPending());
-  EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
-  EXPECT_TRUE(client.needs_begin_impl_frame());
-
-  // No draw happens since the textures are acquired by the main thread.
-  client.Reset();
-  scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
-  EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
-  client.Reset();
-  scheduler->OnBeginImplFrameDeadline();
-  EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
-  EXPECT_TRUE(scheduler->RedrawPending());
-  EXPECT_TRUE(client.needs_begin_impl_frame());
-
-  client.Reset();
-  scheduler->SetNeedsCommit();
-  if (deadline_scheduling_enabled) {
-    EXPECT_EQ(0, client.num_actions_());
-  } else {
-    EXPECT_SINGLE_ACTION("ScheduledActionSendBeginMainFrame", client);
-  }
-
-  client.Reset();
-  scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
-  if (deadline_scheduling_enabled) {
-    EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 2);
-    EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2);
-  } else {
-    EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
-  }
-
-  // Commit will release the texture.
-  client.Reset();
-  scheduler->FinishCommit();
-  EXPECT_ACTION("ScheduledActionCommit", client, 0, 2);
-  EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2);
-  EXPECT_TRUE(scheduler->RedrawPending());
-
-  // Now we can draw again after the commit happens.
-  client.Reset();
-  scheduler->OnBeginImplFrameDeadline();
-  EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2);
-  EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2);
-  EXPECT_FALSE(scheduler->RedrawPending());
-  EXPECT_TRUE(client.needs_begin_impl_frame());
-
-  // Make sure we stop requesting BeginImplFrames if we don't swap.
-  client.Reset();
-  scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
-  EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
-  client.Reset();
-  scheduler->OnBeginImplFrameDeadline();
-  EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
-  EXPECT_FALSE(client.needs_begin_impl_frame());
-}
-
-TEST(SchedulerTest, TextureAcquisitionCausesCommitInsteadOfDraw) {
-  bool deadline_scheduling_enabled = false;
-  TextureAcquisitionCausesCommitInsteadOfDraw(deadline_scheduling_enabled);
-}
-
-TEST(SchedulerTest, TextureAcquisitionCausesCommitInsteadOfDraw_Deadline) {
-  bool deadline_scheduling_enabled = true;
-  TextureAcquisitionCausesCommitInsteadOfDraw(deadline_scheduling_enabled);
-}
-
-void TextureAcquisitionCollision(bool deadline_scheduling_enabled) {
-  FakeSchedulerClient client;
-  SchedulerSettings scheduler_settings;
-  scheduler_settings.deadline_scheduling_enabled = deadline_scheduling_enabled;
-  Scheduler* scheduler = client.CreateScheduler(scheduler_settings);
-  scheduler->SetCanStart();
-  scheduler->SetVisible(true);
-  scheduler->SetCanDraw(true);
-
-  EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
-  InitializeOutputSurfaceAndFirstCommit(scheduler);
-
-  client.Reset();
-  scheduler->SetNeedsCommit();
-if (deadline_scheduling_enabled) {
-    EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
-  } else {
-    EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 2);
-    EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2);
-  }
-
-  client.Reset();
-  scheduler->SetMainThreadNeedsLayerTextures();
-  EXPECT_SINGLE_ACTION(
-      "ScheduledActionAcquireLayerTexturesForMainThread", client);
-
-  client.Reset();
-  scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
-  if (deadline_scheduling_enabled) {
-    EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 2);
-    EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2);
-  } else {
-    EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
-  }
-
-  client.Reset();
-  scheduler->OnBeginImplFrameDeadline();
-  EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
-
-  // Although the compositor cannot draw because textures are locked by main
-  // thread, we continue requesting SetNeedsBeginImplFrame in anticipation of
-  // the unlock.
-  EXPECT_TRUE(client.needs_begin_impl_frame());
-
-  // Trigger the commit
-  scheduler->FinishCommit();
-  EXPECT_TRUE(client.needs_begin_impl_frame());
-
-  // Between commit and draw, texture acquisition for main thread delayed,
-  // and main thread blocks.
-  client.Reset();
-  scheduler->SetMainThreadNeedsLayerTextures();
-  EXPECT_EQ(0, client.num_actions_());
-
-  // No implicit commit is expected.
-  client.Reset();
-  scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
-  EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
-
-  client.Reset();
-  scheduler->OnBeginImplFrameDeadline();
-  EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 3);
-  EXPECT_ACTION(
-      "ScheduledActionAcquireLayerTexturesForMainThread", client, 1, 3);
-  EXPECT_ACTION("SetNeedsBeginImplFrame", client, 2, 3);
-  EXPECT_TRUE(client.needs_begin_impl_frame());
-
-  // The compositor should not draw because textures are locked by main
-  // thread.
-  client.Reset();
-  scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
-  EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
-  client.Reset();
-  scheduler->OnBeginImplFrameDeadline();
-  EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
-  EXPECT_FALSE(client.needs_begin_impl_frame());
-
-  // The impl thread need an explicit commit from the main thread to lock
-  // the textures.
-  client.Reset();
-  scheduler->SetNeedsCommit();
-  if (deadline_scheduling_enabled) {
-    EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
-  } else {
-    EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 2);
-    EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2);
-  }
-  EXPECT_TRUE(client.needs_begin_impl_frame());
-
-  client.Reset();
-  scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
-  if (deadline_scheduling_enabled) {
-    EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 2);
-    EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2);
-  } else {
-    EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
-  }
-  client.Reset();
-
-  // Trigger the commit, which will trigger the deadline task early.
-  scheduler->FinishCommit();
-  EXPECT_ACTION("ScheduledActionCommit", client, 0, 2);
-  EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2);
-  EXPECT_TRUE(client.needs_begin_impl_frame());
-  client.Reset();
-
-  // Verify we draw on the next BeginImplFrame deadline
-  scheduler->OnBeginImplFrameDeadline();
-  EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2);
-  EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2);
-  EXPECT_TRUE(client.needs_begin_impl_frame());
-  client.Reset();
-}
-
-TEST(SchedulerTest, TextureAcquisitionCollision) {
-  bool deadline_scheduling_enabled = false;
-  TextureAcquisitionCollision(deadline_scheduling_enabled);
-}
-
-TEST(SchedulerTest, TextureAcquisitionCollision_Deadline) {
-  bool deadline_scheduling_enabled = true;
-  TextureAcquisitionCollision(deadline_scheduling_enabled);
-}
-
-void VisibilitySwitchWithTextureAcquisition(bool deadline_scheduling_enabled) {
-  FakeSchedulerClient client;
-  SchedulerSettings scheduler_settings;
-  scheduler_settings.deadline_scheduling_enabled = deadline_scheduling_enabled;
-  Scheduler* scheduler = client.CreateScheduler(scheduler_settings);
-  scheduler->SetCanStart();
-  scheduler->SetVisible(true);
-  scheduler->SetCanDraw(true);
-
-  EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
-  client.Reset();
-  scheduler->DidCreateAndInitializeOutputSurface();
-
-  scheduler->SetNeedsCommit();
-  if (deadline_scheduling_enabled) {
-    scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
-    scheduler->OnBeginImplFrameDeadline();
-  }
-  scheduler->FinishCommit();
-  scheduler->SetMainThreadNeedsLayerTextures();
-  scheduler->SetNeedsCommit();
+  client.AdvanceFrame();
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
+  EXPECT_FALSE(client.needs_begin_frame());
   client.Reset();
-  // Verify that pending texture acquisition fires when visibility
-  // is lost in order to avoid a deadlock.
-  scheduler->SetVisible(false);
-  EXPECT_SINGLE_ACTION("ScheduledActionAcquireLayerTexturesForMainThread",
-                       client);
-
-  client.Reset();
-  scheduler->SetVisible(true);
-  EXPECT_EQ(0, client.num_actions_());
-  EXPECT_TRUE(client.needs_begin_impl_frame());
-
-  // Regaining visibility with textures acquired by main thread while
-  // compositor is waiting for first draw should result in a request
-  // for a new frame in order to escape a deadlock.
-  client.Reset();
-  scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
-  EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 2);
-  EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2);
-}
-
-TEST(SchedulerTest, VisibilitySwitchWithTextureAcquisition) {
-  bool deadline_scheduling_enabled = false;
-  VisibilitySwitchWithTextureAcquisition(deadline_scheduling_enabled);
-}
-
-TEST(SchedulerTest, VisibilitySwitchWithTextureAcquisition_Deadline) {
-  bool deadline_scheduling_enabled = true;
-  VisibilitySwitchWithTextureAcquisition(deadline_scheduling_enabled);
 }
 
 class SchedulerClientThatsetNeedsDrawInsideDraw : public FakeSchedulerClient {
  public:
   virtual void ScheduledActionSendBeginMainFrame() OVERRIDE {}
-  virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapIfPossible()
+  virtual DrawResult ScheduledActionDrawAndSwapIfPossible()
       OVERRIDE {
     // Only SetNeedsRedraw the first time this is called
     if (!num_draws_)
@@ -691,12 +433,9 @@ class SchedulerClientThatsetNeedsDrawInsideDraw : public FakeSchedulerClient {
     return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible();
   }
 
-  virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapForced() OVERRIDE {
+  virtual DrawResult ScheduledActionDrawAndSwapForced() OVERRIDE {
     NOTREACHED();
-    bool did_swap = true;
-    bool did_readback = false;
-    return DrawSwapReadbackResult(
-        DrawSwapReadbackResult::DRAW_SUCCESS, did_swap, did_readback);
+    return DRAW_SUCCESS;
   }
 
   virtual void ScheduledActionCommit() OVERRIDE {}
@@ -711,84 +450,84 @@ class SchedulerClientThatsetNeedsDrawInsideDraw : public FakeSchedulerClient {
 TEST(SchedulerTest, RequestRedrawInsideDraw) {
   SchedulerClientThatsetNeedsDrawInsideDraw client;
   SchedulerSettings default_scheduler_settings;
-  Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+  TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
   scheduler->SetCanStart();
   scheduler->SetVisible(true);
   scheduler->SetCanDraw(true);
-  InitializeOutputSurfaceAndFirstCommit(scheduler);
+  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
   client.Reset();
 
   scheduler->SetNeedsRedraw();
   EXPECT_TRUE(scheduler->RedrawPending());
-  EXPECT_TRUE(client.needs_begin_impl_frame());
+  EXPECT_TRUE(client.needs_begin_frame());
   EXPECT_EQ(0, client.num_draws());
 
-  scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
-  scheduler->OnBeginImplFrameDeadline();
+  client.AdvanceFrame();
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
   EXPECT_EQ(1, client.num_draws());
   EXPECT_TRUE(scheduler->RedrawPending());
-  EXPECT_TRUE(client.needs_begin_impl_frame());
+  EXPECT_TRUE(client.needs_begin_frame());
 
-  scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
-  scheduler->OnBeginImplFrameDeadline();
+  client.AdvanceFrame();
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
   EXPECT_EQ(2, client.num_draws());
   EXPECT_FALSE(scheduler->RedrawPending());
-  EXPECT_TRUE(client.needs_begin_impl_frame());
+  EXPECT_TRUE(client.needs_begin_frame());
 
   // We stop requesting BeginImplFrames after a BeginImplFrame where we don't
   // swap.
-  scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
-  scheduler->OnBeginImplFrameDeadline();
+  client.AdvanceFrame();
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
   EXPECT_EQ(2, client.num_draws());
   EXPECT_FALSE(scheduler->RedrawPending());
-  EXPECT_FALSE(client.needs_begin_impl_frame());
+  EXPECT_FALSE(client.needs_begin_frame());
 }
 
 // Test that requesting redraw inside a failed draw doesn't lose the request.
 TEST(SchedulerTest, RequestRedrawInsideFailedDraw) {
   SchedulerClientThatsetNeedsDrawInsideDraw client;
   SchedulerSettings default_scheduler_settings;
-  Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+  TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
   scheduler->SetCanStart();
   scheduler->SetVisible(true);
   scheduler->SetCanDraw(true);
-  InitializeOutputSurfaceAndFirstCommit(scheduler);
+  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
   client.Reset();
 
   client.SetDrawWillHappen(false);
 
   scheduler->SetNeedsRedraw();
   EXPECT_TRUE(scheduler->RedrawPending());
-  EXPECT_TRUE(client.needs_begin_impl_frame());
+  EXPECT_TRUE(client.needs_begin_frame());
   EXPECT_EQ(0, client.num_draws());
 
   // Fail the draw.
-  scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
-  scheduler->OnBeginImplFrameDeadline();
+  client.AdvanceFrame();
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
   EXPECT_EQ(1, client.num_draws());
 
   // We have a commit pending and the draw failed, and we didn't lose the redraw
   // request.
   EXPECT_TRUE(scheduler->CommitPending());
   EXPECT_TRUE(scheduler->RedrawPending());
-  EXPECT_TRUE(client.needs_begin_impl_frame());
+  EXPECT_TRUE(client.needs_begin_frame());
 
   // Fail the draw again.
-  scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
-  scheduler->OnBeginImplFrameDeadline();
+  client.AdvanceFrame();
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
   EXPECT_EQ(2, client.num_draws());
   EXPECT_TRUE(scheduler->CommitPending());
   EXPECT_TRUE(scheduler->RedrawPending());
-  EXPECT_TRUE(client.needs_begin_impl_frame());
+  EXPECT_TRUE(client.needs_begin_frame());
 
   // Draw successfully.
   client.SetDrawWillHappen(true);
-  scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
-  scheduler->OnBeginImplFrameDeadline();
+  client.AdvanceFrame();
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
   EXPECT_EQ(3, client.num_draws());
   EXPECT_TRUE(scheduler->CommitPending());
   EXPECT_FALSE(scheduler->RedrawPending());
-  EXPECT_TRUE(client.needs_begin_impl_frame());
+  EXPECT_TRUE(client.needs_begin_frame());
 }
 
 class SchedulerClientThatSetNeedsCommitInsideDraw : public FakeSchedulerClient {
@@ -797,7 +536,7 @@ class SchedulerClientThatSetNeedsCommitInsideDraw : public FakeSchedulerClient {
       : set_needs_commit_on_next_draw_(false) {}
 
   virtual void ScheduledActionSendBeginMainFrame() OVERRIDE {}
-  virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapIfPossible()
+  virtual DrawResult ScheduledActionDrawAndSwapIfPossible()
       OVERRIDE {
     // Only SetNeedsCommit the first time this is called
     if (set_needs_commit_on_next_draw_) {
@@ -807,12 +546,9 @@ class SchedulerClientThatSetNeedsCommitInsideDraw : public FakeSchedulerClient {
     return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible();
   }
 
-  virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapForced() OVERRIDE {
+  virtual DrawResult ScheduledActionDrawAndSwapForced() OVERRIDE {
     NOTREACHED();
-    bool did_swap = false;
-    bool did_readback = false;
-    return DrawSwapReadbackResult(
-        DrawSwapReadbackResult::DRAW_SUCCESS, did_swap, did_readback);
+    return DRAW_SUCCESS;
   }
 
   virtual void ScheduledActionCommit() OVERRIDE {}
@@ -830,172 +566,131 @@ class SchedulerClientThatSetNeedsCommitInsideDraw : public FakeSchedulerClient {
 TEST(SchedulerTest, RequestCommitInsideDraw) {
   SchedulerClientThatSetNeedsCommitInsideDraw client;
   SchedulerSettings default_scheduler_settings;
-  Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+  TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
   scheduler->SetCanStart();
   scheduler->SetVisible(true);
   scheduler->SetCanDraw(true);
-  InitializeOutputSurfaceAndFirstCommit(scheduler);
+  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
   client.Reset();
 
-  EXPECT_FALSE(client.needs_begin_impl_frame());
+  EXPECT_FALSE(client.needs_begin_frame());
   scheduler->SetNeedsRedraw();
   EXPECT_TRUE(scheduler->RedrawPending());
   EXPECT_EQ(0, client.num_draws());
-  EXPECT_TRUE(client.needs_begin_impl_frame());
+  EXPECT_TRUE(client.needs_begin_frame());
 
   client.SetNeedsCommitOnNextDraw();
-  scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
+  client.AdvanceFrame();
   client.SetNeedsCommitOnNextDraw();
-  scheduler->OnBeginImplFrameDeadline();
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
   EXPECT_EQ(1, client.num_draws());
   EXPECT_TRUE(scheduler->CommitPending());
-  EXPECT_TRUE(client.needs_begin_impl_frame());
-  scheduler->FinishCommit();
+  EXPECT_TRUE(client.needs_begin_frame());
+  scheduler->NotifyBeginMainFrameStarted();
+  scheduler->NotifyReadyToCommit();
 
-  scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
-  scheduler->OnBeginImplFrameDeadline();
+  client.AdvanceFrame();
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
   EXPECT_EQ(2, client.num_draws());
 
   EXPECT_FALSE(scheduler->RedrawPending());
   EXPECT_FALSE(scheduler->CommitPending());
-  EXPECT_TRUE(client.needs_begin_impl_frame());
+  EXPECT_TRUE(client.needs_begin_frame());
 
   // We stop requesting BeginImplFrames after a BeginImplFrame where we don't
   // swap.
-  scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
-  scheduler->OnBeginImplFrameDeadline();
+  client.AdvanceFrame();
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
   EXPECT_EQ(2, client.num_draws());
   EXPECT_FALSE(scheduler->RedrawPending());
   EXPECT_FALSE(scheduler->CommitPending());
-  EXPECT_FALSE(client.needs_begin_impl_frame());
+  EXPECT_FALSE(client.needs_begin_frame());
 }
 
 // Tests that when a draw fails then the pending commit should not be dropped.
 TEST(SchedulerTest, RequestCommitInsideFailedDraw) {
   SchedulerClientThatsetNeedsDrawInsideDraw client;
   SchedulerSettings default_scheduler_settings;
-  Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+  TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
   scheduler->SetCanStart();
   scheduler->SetVisible(true);
   scheduler->SetCanDraw(true);
-  InitializeOutputSurfaceAndFirstCommit(scheduler);
+  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
   client.Reset();
 
   client.SetDrawWillHappen(false);
 
   scheduler->SetNeedsRedraw();
   EXPECT_TRUE(scheduler->RedrawPending());
-  EXPECT_TRUE(client.needs_begin_impl_frame());
+  EXPECT_TRUE(client.needs_begin_frame());
   EXPECT_EQ(0, client.num_draws());
 
   // Fail the draw.
-  scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
-  scheduler->OnBeginImplFrameDeadline();
+  client.AdvanceFrame();
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
   EXPECT_EQ(1, client.num_draws());
 
   // We have a commit pending and the draw failed, and we didn't lose the commit
   // request.
   EXPECT_TRUE(scheduler->CommitPending());
   EXPECT_TRUE(scheduler->RedrawPending());
-  EXPECT_TRUE(client.needs_begin_impl_frame());
+  EXPECT_TRUE(client.needs_begin_frame());
 
   // Fail the draw again.
-  scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
-  scheduler->OnBeginImplFrameDeadline();
+  client.AdvanceFrame();
+
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
   EXPECT_EQ(2, client.num_draws());
   EXPECT_TRUE(scheduler->CommitPending());
   EXPECT_TRUE(scheduler->RedrawPending());
-  EXPECT_TRUE(client.needs_begin_impl_frame());
+  EXPECT_TRUE(client.needs_begin_frame());
 
   // Draw successfully.
   client.SetDrawWillHappen(true);
-  scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
-  scheduler->OnBeginImplFrameDeadline();
+  client.AdvanceFrame();
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
   EXPECT_EQ(3, client.num_draws());
   EXPECT_TRUE(scheduler->CommitPending());
   EXPECT_FALSE(scheduler->RedrawPending());
-  EXPECT_TRUE(client.needs_begin_impl_frame());
+  EXPECT_TRUE(client.needs_begin_frame());
 }
 
 TEST(SchedulerTest, NoSwapWhenDrawFails) {
   SchedulerClientThatSetNeedsCommitInsideDraw client;
   SchedulerSettings default_scheduler_settings;
-  Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+  TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
   scheduler->SetCanStart();
   scheduler->SetVisible(true);
   scheduler->SetCanDraw(true);
-  InitializeOutputSurfaceAndFirstCommit(scheduler);
+  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
   client.Reset();
 
   scheduler->SetNeedsRedraw();
   EXPECT_TRUE(scheduler->RedrawPending());
-  EXPECT_TRUE(client.needs_begin_impl_frame());
+  EXPECT_TRUE(client.needs_begin_frame());
   EXPECT_EQ(0, client.num_draws());
 
   // Draw successfully, this starts a new frame.
   client.SetNeedsCommitOnNextDraw();
-  scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
-  scheduler->OnBeginImplFrameDeadline();
+  client.AdvanceFrame();
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
   EXPECT_EQ(1, client.num_draws());
 
   scheduler->SetNeedsRedraw();
   EXPECT_TRUE(scheduler->RedrawPending());
-  EXPECT_TRUE(client.needs_begin_impl_frame());
+  EXPECT_TRUE(client.needs_begin_frame());
 
   // Fail to draw, this should not start a frame.
   client.SetDrawWillHappen(false);
   client.SetNeedsCommitOnNextDraw();
-  scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
-  scheduler->OnBeginImplFrameDeadline();
+  client.AdvanceFrame();
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
   EXPECT_EQ(2, client.num_draws());
 }
 
-TEST(SchedulerTest, NoSwapWhenSwapFailsDuringForcedCommit) {
-  FakeSchedulerClient client;
-  SchedulerSettings default_scheduler_settings;
-  Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
-
-  // Tell the client that it will fail to swap.
-  client.SetDrawWillHappen(true);
-  client.SetSwapWillHappenIfDrawHappens(false);
-
-  // Get the compositor to do a ScheduledActionDrawAndReadback.
-  scheduler->SetCanDraw(true);
-  scheduler->SetNeedsRedraw();
-  scheduler->SetNeedsForcedCommitForReadback();
-  scheduler->FinishCommit();
-  EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndReadback"));
-}
-
-TEST(SchedulerTest, BackToBackReadbackAllowed) {
-  // Some clients call readbacks twice in a row before the replacement
-  // commit comes in.  Make sure it is allowed.
-  FakeSchedulerClient client;
-  SchedulerSettings default_scheduler_settings;
-  Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
-
-  // Get the compositor to do 2 ScheduledActionDrawAndReadbacks before
-  // the replacement commit comes in.
-  scheduler->SetCanDraw(true);
-  scheduler->SetNeedsRedraw();
-  scheduler->SetNeedsForcedCommitForReadback();
-  scheduler->FinishCommit();
-  EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndReadback"));
-
-  client.Reset();
-  scheduler->SetNeedsForcedCommitForReadback();
-  scheduler->FinishCommit();
-  EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndReadback"));
-
-  // The replacement commit comes in after 2 readbacks.
-  client.Reset();
-  scheduler->FinishCommit();
-}
-
-
 class SchedulerClientNeedsManageTilesInDraw : public FakeSchedulerClient {
  public:
-  virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapIfPossible()
+  virtual DrawResult ScheduledActionDrawAndSwapIfPossible()
       OVERRIDE {
     scheduler_->SetNeedsManageTiles();
     return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible();
@@ -1006,11 +701,11 @@ class SchedulerClientNeedsManageTilesInDraw : public FakeSchedulerClient {
 TEST(SchedulerTest, ManageTiles) {
   SchedulerClientNeedsManageTilesInDraw client;
   SchedulerSettings default_scheduler_settings;
-  Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+  TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
   scheduler->SetCanStart();
   scheduler->SetVisible(true);
   scheduler->SetCanDraw(true);
-  InitializeOutputSurfaceAndFirstCommit(scheduler);
+  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
 
   // Request both draw and manage tiles. ManageTiles shouldn't
   // be trigged until BeginImplFrame.
@@ -1019,7 +714,7 @@ TEST(SchedulerTest, ManageTiles) {
   scheduler->SetNeedsRedraw();
   EXPECT_TRUE(scheduler->RedrawPending());
   EXPECT_TRUE(scheduler->ManageTilesPending());
-  EXPECT_TRUE(client.needs_begin_impl_frame());
+  EXPECT_TRUE(client.needs_begin_frame());
   EXPECT_EQ(0, client.num_draws());
   EXPECT_FALSE(client.HasAction("ScheduledActionManageTiles"));
   EXPECT_FALSE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
@@ -1027,12 +722,14 @@ TEST(SchedulerTest, ManageTiles) {
   // We have no immediate actions to perform, so the BeginImplFrame should post
   // the deadline task.
   client.Reset();
-  scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
-  EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
+  client.AdvanceFrame();
+  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+  EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
 
   // On the deadline, he actions should have occured in the right order.
   client.Reset();
-  scheduler->OnBeginImplFrameDeadline();
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
   EXPECT_EQ(1, client.num_draws());
   EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
   EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles"));
@@ -1040,26 +737,29 @@ TEST(SchedulerTest, ManageTiles) {
             client.ActionIndex("ScheduledActionManageTiles"));
   EXPECT_FALSE(scheduler->RedrawPending());
   EXPECT_FALSE(scheduler->ManageTilesPending());
+  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
 
   // Request a draw. We don't need a ManageTiles yet.
   client.Reset();
   scheduler->SetNeedsRedraw();
   EXPECT_TRUE(scheduler->RedrawPending());
   EXPECT_FALSE(scheduler->ManageTilesPending());
-  EXPECT_TRUE(client.needs_begin_impl_frame());
+  EXPECT_TRUE(client.needs_begin_frame());
   EXPECT_EQ(0, client.num_draws());
 
   // We have no immediate actions to perform, so the BeginImplFrame should post
   // the deadline task.
   client.Reset();
-  scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
-  EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
+  client.AdvanceFrame();
+  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+  EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
 
   // Draw. The draw will trigger SetNeedsManageTiles, and
   // then the ManageTiles action will be triggered after the Draw.
   // Afterwards, neither a draw nor ManageTiles are pending.
   client.Reset();
-  scheduler->OnBeginImplFrameDeadline();
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
   EXPECT_EQ(1, client.num_draws());
   EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
   EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles"));
@@ -1067,34 +767,40 @@ TEST(SchedulerTest, ManageTiles) {
             client.ActionIndex("ScheduledActionManageTiles"));
   EXPECT_FALSE(scheduler->RedrawPending());
   EXPECT_FALSE(scheduler->ManageTilesPending());
+  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
 
   // We need a BeginImplFrame where we don't swap to go idle.
   client.Reset();
-  scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
-  EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
+  client.AdvanceFrame();
+  EXPECT_SINGLE_ACTION("WillBeginImplFrame", client);
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
   client.Reset();
-  scheduler->OnBeginImplFrameDeadline();
-  EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);;
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
+  EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
+  EXPECT_FALSE(client.needs_begin_frame());
+  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
   EXPECT_EQ(0, client.num_draws());
 
   // Now trigger a ManageTiles outside of a draw. We will then need
   // a begin-frame for the ManageTiles, but we don't need a draw.
   client.Reset();
-  EXPECT_FALSE(client.needs_begin_impl_frame());
+  EXPECT_FALSE(client.needs_begin_frame());
   scheduler->SetNeedsManageTiles();
-  EXPECT_TRUE(client.needs_begin_impl_frame());
+  EXPECT_TRUE(client.needs_begin_frame());
   EXPECT_TRUE(scheduler->ManageTilesPending());
   EXPECT_FALSE(scheduler->RedrawPending());
 
   // BeginImplFrame. There will be no draw, only ManageTiles.
   client.Reset();
-  scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
-  EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
+  client.AdvanceFrame();
+  EXPECT_SINGLE_ACTION("WillBeginImplFrame", client);
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
   client.Reset();
-  scheduler->OnBeginImplFrameDeadline();
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
   EXPECT_EQ(0, client.num_draws());
   EXPECT_FALSE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
   EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles"));
+  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
 }
 
 // Test that ManageTiles only happens once per frame.  If an external caller
@@ -1102,40 +808,45 @@ TEST(SchedulerTest, ManageTiles) {
 TEST(SchedulerTest, ManageTilesOncePerFrame) {
   FakeSchedulerClient client;
   SchedulerSettings default_scheduler_settings;
-  Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+  TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
   scheduler->SetCanStart();
   scheduler->SetVisible(true);
   scheduler->SetCanDraw(true);
-  InitializeOutputSurfaceAndFirstCommit(scheduler);
+  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
 
   // If DidManageTiles during a frame, then ManageTiles should not occur again.
   scheduler->SetNeedsManageTiles();
   scheduler->SetNeedsRedraw();
   client.Reset();
-  scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
-  EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
+  client.AdvanceFrame();
+  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+  EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
 
   EXPECT_TRUE(scheduler->ManageTilesPending());
   scheduler->DidManageTiles();  // An explicit ManageTiles.
   EXPECT_FALSE(scheduler->ManageTilesPending());
 
   client.Reset();
-  scheduler->OnBeginImplFrameDeadline();
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
   EXPECT_EQ(1, client.num_draws());
   EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
   EXPECT_FALSE(client.HasAction("ScheduledActionManageTiles"));
   EXPECT_FALSE(scheduler->RedrawPending());
   EXPECT_FALSE(scheduler->ManageTilesPending());
+  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
 
   // Next frame without DidManageTiles should ManageTiles with draw.
   scheduler->SetNeedsManageTiles();
   scheduler->SetNeedsRedraw();
   client.Reset();
-  scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
-  EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
+  client.AdvanceFrame();
+  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+  EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
 
   client.Reset();
-  scheduler->OnBeginImplFrameDeadline();
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
   EXPECT_EQ(1, client.num_draws());
   EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
   EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles"));
@@ -1143,6 +854,7 @@ TEST(SchedulerTest, ManageTilesOncePerFrame) {
             client.ActionIndex("ScheduledActionManageTiles"));
   EXPECT_FALSE(scheduler->RedrawPending());
   EXPECT_FALSE(scheduler->ManageTilesPending());
+  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
   scheduler->DidManageTiles();  // Corresponds to ScheduledActionManageTiles
 
   // If we get another DidManageTiles within the same frame, we should
@@ -1151,17 +863,20 @@ TEST(SchedulerTest, ManageTilesOncePerFrame) {
   scheduler->SetNeedsManageTiles();
   scheduler->SetNeedsRedraw();
   client.Reset();
-  scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
-  EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
+  client.AdvanceFrame();
+  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+  EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
 
   EXPECT_TRUE(scheduler->ManageTilesPending());
 
   client.Reset();
-  scheduler->OnBeginImplFrameDeadline();
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
   EXPECT_EQ(1, client.num_draws());
   EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
   EXPECT_FALSE(client.HasAction("ScheduledActionManageTiles"));
   EXPECT_FALSE(scheduler->RedrawPending());
+  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
 
   // If we get another DidManageTiles, we should not ManageTiles on the next
   // frame. This verifies we don't alternate calling ManageTiles once and twice.
@@ -1171,27 +886,32 @@ TEST(SchedulerTest, ManageTilesOncePerFrame) {
   scheduler->SetNeedsManageTiles();
   scheduler->SetNeedsRedraw();
   client.Reset();
-  scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
-  EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
+  client.AdvanceFrame();
+  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+  EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
 
   EXPECT_TRUE(scheduler->ManageTilesPending());
 
   client.Reset();
-  scheduler->OnBeginImplFrameDeadline();
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
   EXPECT_EQ(1, client.num_draws());
   EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
   EXPECT_FALSE(client.HasAction("ScheduledActionManageTiles"));
   EXPECT_FALSE(scheduler->RedrawPending());
+  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
 
   // Next frame without DidManageTiles should ManageTiles with draw.
   scheduler->SetNeedsManageTiles();
   scheduler->SetNeedsRedraw();
   client.Reset();
-  scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
-  EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
+  client.AdvanceFrame();
+  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+  EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
 
   client.Reset();
-  scheduler->OnBeginImplFrameDeadline();
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
   EXPECT_EQ(1, client.num_draws());
   EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
   EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles"));
@@ -1199,38 +919,120 @@ TEST(SchedulerTest, ManageTilesOncePerFrame) {
             client.ActionIndex("ScheduledActionManageTiles"));
   EXPECT_FALSE(scheduler->RedrawPending());
   EXPECT_FALSE(scheduler->ManageTilesPending());
+  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
   scheduler->DidManageTiles();  // Corresponds to ScheduledActionManageTiles
 }
 
-class SchedulerClientWithFixedEstimates : public FakeSchedulerClient {
- public:
-  SchedulerClientWithFixedEstimates(
-      base::TimeDelta draw_duration,
-      base::TimeDelta begin_main_frame_to_commit_duration,
-      base::TimeDelta commit_to_activate_duration)
-      : draw_duration_(draw_duration),
-        begin_main_frame_to_commit_duration_(
-            begin_main_frame_to_commit_duration),
-        commit_to_activate_duration_(commit_to_activate_duration) {}
-
-  virtual base::TimeDelta DrawDurationEstimate() OVERRIDE {
-    return draw_duration_;
-  }
-  virtual base::TimeDelta BeginMainFrameToCommitDurationEstimate() OVERRIDE {
-    return begin_main_frame_to_commit_duration_;
-  }
-  virtual base::TimeDelta CommitToActivateDurationEstimate() OVERRIDE {
-    return commit_to_activate_duration_;
-  }
+TEST(SchedulerTest, ShouldUpdateVisibleTiles) {
+  FakeSchedulerClient client;
+  SchedulerSettings scheduler_settings;
+  scheduler_settings.impl_side_painting = true;
+  TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
+  scheduler->SetCanStart();
+  scheduler->SetVisible(true);
+  scheduler->SetCanDraw(true);
+  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
 
- private:
-    base::TimeDelta draw_duration_;
-    base::TimeDelta begin_main_frame_to_commit_duration_;
-    base::TimeDelta commit_to_activate_duration_;
-};
+  client.SetRedrawWillHappenIfUpdateVisibleTilesHappens(true);
 
-void MainFrameInHighLatencyMode(int64 begin_main_frame_to_commit_estimate_in_ms,
+  // SetNeedsCommit should begin the frame.
+  client.Reset();
+  scheduler->SetNeedsCommit();
+  EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
+
+  client.Reset();
+  client.AdvanceFrame();
+  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+  EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+
+  client.Reset();
+  scheduler->NotifyBeginMainFrameStarted();
+  scheduler->NotifyReadyToCommit();
+  EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
+
+  client.Reset();
+  scheduler->NotifyReadyToActivate();
+  EXPECT_SINGLE_ACTION("ScheduledActionActivateSyncTree", client);
+
+  client.Reset();
+  client.SetSwapContainsIncompleteTile(true);
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
+  EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
+  EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
+  EXPECT_FALSE(scheduler->RedrawPending());
+
+  client.Reset();
+  client.AdvanceFrame();
+  EXPECT_SINGLE_ACTION("WillBeginImplFrame", client);
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+
+  client.Reset();
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
+  EXPECT_ACTION("ScheduledActionUpdateVisibleTiles", client, 0, 3);
+  EXPECT_ACTION("ScheduledActionAnimate", client, 1, 3);
+  EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 2, 3);
+
+  client.Reset();
+  client.AdvanceFrame();
+  EXPECT_SINGLE_ACTION("WillBeginImplFrame", client);
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+
+  // No more UpdateVisibleTiles().
+  client.Reset();
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
+  EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
+  EXPECT_FALSE(client.needs_begin_frame());
+}
+
+TEST(SchedulerTest, TriggerBeginFrameDeadlineEarly) {
+  SchedulerClientNeedsManageTilesInDraw client;
+  SchedulerSettings default_scheduler_settings;
+  TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+  scheduler->SetCanStart();
+  scheduler->SetVisible(true);
+  scheduler->SetCanDraw(true);
+  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+
+  client.Reset();
+  scheduler->SetNeedsRedraw();
+  client.AdvanceFrame();
+
+  // The deadline should be zero since there is no work other than drawing
+  // pending.
+  EXPECT_EQ(base::TimeTicks(), client.posted_begin_impl_frame_deadline());
+}
+
+class SchedulerClientWithFixedEstimates : public FakeSchedulerClient {
+ public:
+  SchedulerClientWithFixedEstimates(
+      base::TimeDelta draw_duration,
+      base::TimeDelta begin_main_frame_to_commit_duration,
+      base::TimeDelta commit_to_activate_duration)
+      : draw_duration_(draw_duration),
+        begin_main_frame_to_commit_duration_(
+            begin_main_frame_to_commit_duration),
+        commit_to_activate_duration_(commit_to_activate_duration) {}
+
+  virtual base::TimeDelta DrawDurationEstimate() OVERRIDE {
+    return draw_duration_;
+  }
+  virtual base::TimeDelta BeginMainFrameToCommitDurationEstimate() OVERRIDE {
+    return begin_main_frame_to_commit_duration_;
+  }
+  virtual base::TimeDelta CommitToActivateDurationEstimate() OVERRIDE {
+    return commit_to_activate_duration_;
+  }
+
+ private:
+    base::TimeDelta draw_duration_;
+    base::TimeDelta begin_main_frame_to_commit_duration_;
+    base::TimeDelta commit_to_activate_duration_;
+};
+
+void MainFrameInHighLatencyMode(int64 begin_main_frame_to_commit_estimate_in_ms,
                                 int64 commit_to_activate_estimate_in_ms,
+                                bool impl_latency_takes_priority,
                                 bool should_send_begin_main_frame) {
   // Set up client with specified estimates (draw duration is set to 1).
   SchedulerClientWithFixedEstimates client(
@@ -1238,33 +1040,33 @@ void MainFrameInHighLatencyMode(int64 begin_main_frame_to_commit_estimate_in_ms,
       base::TimeDelta::FromMilliseconds(
           begin_main_frame_to_commit_estimate_in_ms),
       base::TimeDelta::FromMilliseconds(commit_to_activate_estimate_in_ms));
-  SchedulerSettings scheduler_settings;
-  scheduler_settings.deadline_scheduling_enabled = true;
-  scheduler_settings.switch_to_low_latency_if_possible = true;
-  Scheduler* scheduler = client.CreateScheduler(scheduler_settings);
+  SchedulerSettings default_scheduler_settings;
+  TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
   scheduler->SetCanStart();
   scheduler->SetVisible(true);
   scheduler->SetCanDraw(true);
-  InitializeOutputSurfaceAndFirstCommit(scheduler);
+  scheduler->SetImplLatencyTakesPriority(impl_latency_takes_priority);
+  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
 
   // Impl thread hits deadline before commit finishes.
   client.Reset();
   scheduler->SetNeedsCommit();
   EXPECT_FALSE(scheduler->MainThreadIsInHighLatencyMode());
-  scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
+  client.AdvanceFrame();
   EXPECT_FALSE(scheduler->MainThreadIsInHighLatencyMode());
-  scheduler->OnBeginImplFrameDeadline();
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
   EXPECT_TRUE(scheduler->MainThreadIsInHighLatencyMode());
-  scheduler->FinishCommit();
+  scheduler->NotifyBeginMainFrameStarted();
+  scheduler->NotifyReadyToCommit();
   EXPECT_TRUE(scheduler->MainThreadIsInHighLatencyMode());
   EXPECT_TRUE(client.HasAction("ScheduledActionSendBeginMainFrame"));
 
   client.Reset();
   scheduler->SetNeedsCommit();
   EXPECT_TRUE(scheduler->MainThreadIsInHighLatencyMode());
-  scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
+  client.AdvanceFrame();
   EXPECT_TRUE(scheduler->MainThreadIsInHighLatencyMode());
-  scheduler->OnBeginImplFrameDeadline();
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
   EXPECT_EQ(scheduler->MainThreadIsInHighLatencyMode(),
             should_send_begin_main_frame);
   EXPECT_EQ(client.HasAction("ScheduledActionSendBeginMainFrame"),
@@ -1275,36 +1077,38 @@ TEST(SchedulerTest,
     SkipMainFrameIfHighLatencyAndCanCommitAndActivateBeforeDeadline) {
   // Set up client so that estimates indicate that we can commit and activate
   // before the deadline (~8ms by default).
-  MainFrameInHighLatencyMode(1, 1, false);
+  MainFrameInHighLatencyMode(1, 1, false, false);
 }
 
 TEST(SchedulerTest, NotSkipMainFrameIfHighLatencyAndCanCommitTooLong) {
   // Set up client so that estimates indicate that the commit cannot finish
   // before the deadline (~8ms by default).
-  MainFrameInHighLatencyMode(10, 1, true);
+  MainFrameInHighLatencyMode(10, 1, false, true);
 }
 
 TEST(SchedulerTest, NotSkipMainFrameIfHighLatencyAndCanActivateTooLong) {
   // Set up client so that estimates indicate that the activate cannot finish
   // before the deadline (~8ms by default).
-  MainFrameInHighLatencyMode(1, 10, true);
+  MainFrameInHighLatencyMode(1, 10, false, true);
 }
 
-void SpinForMillis(int millis) {
-  base::RunLoop run_loop;
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      run_loop.QuitClosure(),
-      base::TimeDelta::FromMilliseconds(millis));
-  run_loop.Run();
+TEST(SchedulerTest, NotSkipMainFrameInPreferImplLatencyMode) {
+  // Set up client so that estimates indicate that we can commit and activate
+  // before the deadline (~8ms by default), but also enable impl latency takes
+  // priority mode.
+  MainFrameInHighLatencyMode(1, 1, true, true);
 }
 
 TEST(SchedulerTest, PollForCommitCompletion) {
-  FakeSchedulerClient client;
+  // Since we are simulating a long commit, set up a client with draw duration
+  // estimates that prevent skipping main frames to get to low latency mode.
+  SchedulerClientWithFixedEstimates client(
+      base::TimeDelta::FromMilliseconds(1),
+      base::TimeDelta::FromMilliseconds(32),
+      base::TimeDelta::FromMilliseconds(32));
   client.set_log_anticipated_draw_time_change(true);
-  SchedulerSettings settings = SchedulerSettings();
-  settings.throttle_frame_production = false;
-  Scheduler* scheduler = client.CreateScheduler(settings);
+  SchedulerSettings default_scheduler_settings;
+  TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
 
   scheduler->SetCanDraw(true);
   scheduler->SetCanStart();
@@ -1313,34 +1117,830 @@ TEST(SchedulerTest, PollForCommitCompletion) {
 
   scheduler->SetNeedsCommit();
   EXPECT_TRUE(scheduler->CommitPending());
-  scheduler->FinishCommit();
+  scheduler->NotifyBeginMainFrameStarted();
+  scheduler->NotifyReadyToCommit();
   scheduler->SetNeedsRedraw();
-  BeginFrameArgs impl_frame_args = BeginFrameArgs::CreateForTesting();
-  const int interval = 1;
-  impl_frame_args.interval = base::TimeDelta::FromMilliseconds(interval);
-  scheduler->BeginImplFrame(impl_frame_args);
-  scheduler->OnBeginImplFrameDeadline();
-
-  // At this point, we've drawn a frame.  Start another commit, but hold off on
-  // the FinishCommit for now.
+
+  BeginFrameArgs frame_args = CreateBeginFrameArgsForTesting(client.now_src());
+  frame_args.interval = base::TimeDelta::FromMilliseconds(1000);
+  scheduler->BeginFrame(frame_args);
+
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
+  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+
+  scheduler->DidSwapBuffers();
+  scheduler->DidSwapBuffersComplete();
+
+  // At this point, we've drawn a frame. Start another commit, but hold off on
+  // the NotifyReadyToCommit for now.
   EXPECT_FALSE(scheduler->CommitPending());
   scheduler->SetNeedsCommit();
+  scheduler->BeginFrame(frame_args);
   EXPECT_TRUE(scheduler->CommitPending());
 
+  // Draw and swap the frame, but don't ack the swap to simulate the Browser
+  // blocking on the renderer.
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
+  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+  scheduler->DidSwapBuffers();
+
   // Spin the event loop a few times and make sure we get more
   // DidAnticipateDrawTimeChange calls every time.
   int actions_so_far = client.num_actions_();
 
   // Does three iterations to make sure that the timer is properly repeating.
   for (int i = 0; i < 3; ++i) {
-    // Wait for 2x the frame interval to match
-    // Scheduler::advance_commit_state_timer_'s rate.
-    SpinForMillis(interval * 2);
+    EXPECT_EQ((frame_args.interval * 2).InMicroseconds(),
+              client.task_runner().DelayToNextTaskTime().InMicroseconds())
+        << scheduler->AsValue()->ToString();
+    client.task_runner().RunPendingTasks();
     EXPECT_GT(client.num_actions_(), actions_so_far);
     EXPECT_STREQ(client.Action(client.num_actions_() - 1),
                  "DidAnticipatedDrawTimeChange");
     actions_so_far = client.num_actions_();
   }
+
+  // Do the same thing after BeginMainFrame starts but still before activation.
+  scheduler->NotifyBeginMainFrameStarted();
+  for (int i = 0; i < 3; ++i) {
+    EXPECT_EQ((frame_args.interval * 2).InMicroseconds(),
+              client.task_runner().DelayToNextTaskTime().InMicroseconds())
+        << scheduler->AsValue()->ToString();
+    client.task_runner().RunPendingTasks();
+    EXPECT_GT(client.num_actions_(), actions_so_far);
+    EXPECT_STREQ(client.Action(client.num_actions_() - 1),
+                 "DidAnticipatedDrawTimeChange");
+    actions_so_far = client.num_actions_();
+  }
+}
+
+TEST(SchedulerTest, BeginRetroFrame) {
+  FakeSchedulerClient client;
+  SchedulerSettings scheduler_settings;
+  TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
+  scheduler->SetCanStart();
+  scheduler->SetVisible(true);
+  scheduler->SetCanDraw(true);
+  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+
+  // SetNeedsCommit should begin the frame on the next BeginImplFrame.
+  client.Reset();
+  scheduler->SetNeedsCommit();
+  EXPECT_TRUE(client.needs_begin_frame());
+  EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
+  client.Reset();
+
+  // Create a BeginFrame with a long deadline to avoid race conditions.
+  // This is the first BeginFrame, which will be handled immediately.
+  BeginFrameArgs args = CreateBeginFrameArgsForTesting(client.now_src());
+  args.deadline += base::TimeDelta::FromHours(1);
+  scheduler->BeginFrame(args);
+  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+  EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+  EXPECT_TRUE(client.needs_begin_frame());
+  client.Reset();
+
+  // Queue BeginFrames while we are still handling the previous BeginFrame.
+  args.frame_time += base::TimeDelta::FromSeconds(1);
+  scheduler->BeginFrame(args);
+  args.frame_time += base::TimeDelta::FromSeconds(1);
+  scheduler->BeginFrame(args);
+
+  // If we don't swap on the deadline, we wait for the next BeginImplFrame.
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
+  EXPECT_NO_ACTION(client);
+  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+  EXPECT_TRUE(client.needs_begin_frame());
+  client.Reset();
+
+  // NotifyReadyToCommit should trigger the commit.
+  scheduler->NotifyBeginMainFrameStarted();
+  scheduler->NotifyReadyToCommit();
+  EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
+  EXPECT_TRUE(client.needs_begin_frame());
+  client.Reset();
+
+  // BeginImplFrame should prepare the draw.
+  client.task_runner().RunPendingTasks();  // Run posted BeginRetroFrame.
+  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+  EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+  EXPECT_TRUE(client.needs_begin_frame());
+  client.Reset();
+
+  // BeginImplFrame deadline should draw.
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
+  EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 1);
+  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+  EXPECT_TRUE(client.needs_begin_frame());
+  client.Reset();
+
+  // The following BeginImplFrame deadline should SetNeedsBeginFrame(false)
+  // to avoid excessive toggles.
+  client.task_runner().RunPendingTasks();  // Run posted BeginRetroFrame.
+  EXPECT_SINGLE_ACTION("WillBeginImplFrame", client);
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+  client.Reset();
+
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
+  EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
+  EXPECT_FALSE(client.needs_begin_frame());
+  client.Reset();
+}
+
+TEST(SchedulerTest, BeginRetroFrame_SwapThrottled) {
+  FakeSchedulerClient client;
+  SchedulerSettings scheduler_settings;
+  TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
+  scheduler->SetCanStart();
+  scheduler->SetVisible(true);
+  scheduler->SetCanDraw(true);
+  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+
+  // To test swap ack throttling, this test disables automatic swap acks.
+  scheduler->SetMaxSwapsPending(1);
+  client.SetAutomaticSwapAck(false);
+
+  // SetNeedsCommit should begin the frame on the next BeginImplFrame.
+  client.Reset();
+  scheduler->SetNeedsCommit();
+  EXPECT_TRUE(client.needs_begin_frame());
+  EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
+  client.Reset();
+
+  // Create a BeginFrame with a long deadline to avoid race conditions.
+  // This is the first BeginFrame, which will be handled immediately.
+  BeginFrameArgs args = CreateBeginFrameArgsForTesting(client.now_src());
+  args.deadline += base::TimeDelta::FromHours(1);
+  scheduler->BeginFrame(args);
+  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+  EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+  EXPECT_TRUE(client.needs_begin_frame());
+  client.Reset();
+
+  // Queue BeginFrame while we are still handling the previous BeginFrame.
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+  args.frame_time += base::TimeDelta::FromSeconds(1);
+  scheduler->BeginFrame(args);
+  EXPECT_NO_ACTION(client);
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+  client.Reset();
+
+  // NotifyReadyToCommit should trigger the pending commit and draw.
+  scheduler->NotifyBeginMainFrameStarted();
+  scheduler->NotifyReadyToCommit();
+  EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
+  EXPECT_TRUE(client.needs_begin_frame());
+  client.Reset();
+
+  // Swapping will put us into a swap throttled state.
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
+  EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
+  EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
+  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+  EXPECT_TRUE(client.needs_begin_frame());
+  client.Reset();
+
+  // While swap throttled, BeginRetroFrames should trigger BeginImplFrames
+  // but not a BeginMainFrame or draw.
+  scheduler->SetNeedsCommit();
+  client.task_runner().RunPendingTasks();  // Run posted BeginRetroFrame.
+  EXPECT_ACTION("WillBeginImplFrame", client, 0, 1);
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+  EXPECT_TRUE(client.needs_begin_frame());
+  client.Reset();
+
+  // Queue BeginFrame while we are still handling the previous BeginFrame.
+  args.frame_time += base::TimeDelta::FromSeconds(1);
+  scheduler->BeginFrame(args);
+  EXPECT_NO_ACTION(client);
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+  EXPECT_TRUE(client.needs_begin_frame());
+  client.Reset();
+
+  // Take us out of a swap throttled state.
+  scheduler->DidSwapBuffersComplete();
+  EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 1);
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+  EXPECT_TRUE(client.needs_begin_frame());
+  client.Reset();
+
+  // BeginImplFrame deadline should draw.
+  scheduler->SetNeedsRedraw();
+
+  EXPECT_TRUE(client.task_runner().RunTasksWhile(
+      client.ImplFrameDeadlinePending(true)));
+
+  EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
+  EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
+  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+  EXPECT_TRUE(client.needs_begin_frame());
+  client.Reset();
+}
+
+void BeginFramesNotFromClient(bool begin_frame_scheduling_enabled,
+                              bool throttle_frame_production) {
+  FakeSchedulerClient client;
+  SchedulerSettings scheduler_settings;
+  scheduler_settings.begin_frame_scheduling_enabled =
+      begin_frame_scheduling_enabled;
+  scheduler_settings.throttle_frame_production = throttle_frame_production;
+  TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
+  scheduler->SetCanStart();
+  scheduler->SetVisible(true);
+  scheduler->SetCanDraw(true);
+  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+
+  // SetNeedsCommit should begin the frame on the next BeginImplFrame
+  // without calling SetNeedsBeginFrame.
+  client.Reset();
+  scheduler->SetNeedsCommit();
+  EXPECT_FALSE(client.needs_begin_frame());
+  EXPECT_NO_ACTION(client);
+  client.Reset();
+
+  // When the client-driven BeginFrame are disabled, the scheduler posts it's
+  // own BeginFrame tasks.
+  client.task_runner().RunPendingTasks();  // Run posted BeginFrame.
+  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+  EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+  EXPECT_FALSE(client.needs_begin_frame());
+  client.Reset();
+
+  // If we don't swap on the deadline, we wait for the next BeginFrame.
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
+  EXPECT_NO_ACTION(client);
+  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+  EXPECT_FALSE(client.needs_begin_frame());
+  client.Reset();
+
+  // NotifyReadyToCommit should trigger the commit.
+  scheduler->NotifyBeginMainFrameStarted();
+  scheduler->NotifyReadyToCommit();
+  EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
+  EXPECT_FALSE(client.needs_begin_frame());
+  client.Reset();
+
+  // BeginImplFrame should prepare the draw.
+  client.task_runner().RunPendingTasks();  // Run posted BeginFrame.
+  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+  EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+  EXPECT_FALSE(client.needs_begin_frame());
+  client.Reset();
+
+  // BeginImplFrame deadline should draw.
+  client.task_runner().RunTasksWhile(client.ImplFrameDeadlinePending(true));
+  EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 1);
+  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+  EXPECT_FALSE(client.needs_begin_frame());
+  client.Reset();
+
+  // The following BeginImplFrame deadline should SetNeedsBeginFrame(false)
+  // to avoid excessive toggles.
+  client.task_runner().RunPendingTasks();  // Run posted BeginFrame.
+  EXPECT_SINGLE_ACTION("WillBeginImplFrame", client);
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+  client.Reset();
+
+  // Make sure SetNeedsBeginFrame isn't called on the client
+  // when the BeginFrame is no longer needed.
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
+  EXPECT_NO_ACTION(client);
+  EXPECT_FALSE(client.needs_begin_frame());
+  client.Reset();
+}
+
+TEST(SchedulerTest, SyntheticBeginFrames) {
+  bool begin_frame_scheduling_enabled = false;
+  bool throttle_frame_production = true;
+  BeginFramesNotFromClient(begin_frame_scheduling_enabled,
+                           throttle_frame_production);
+}
+
+TEST(SchedulerTest, VSyncThrottlingDisabled) {
+  bool begin_frame_scheduling_enabled = true;
+  bool throttle_frame_production = false;
+  BeginFramesNotFromClient(begin_frame_scheduling_enabled,
+                           throttle_frame_production);
+}
+
+TEST(SchedulerTest, SyntheticBeginFrames_And_VSyncThrottlingDisabled) {
+  bool begin_frame_scheduling_enabled = false;
+  bool throttle_frame_production = false;
+  BeginFramesNotFromClient(begin_frame_scheduling_enabled,
+                           throttle_frame_production);
+}
+
+void BeginFramesNotFromClient_SwapThrottled(bool begin_frame_scheduling_enabled,
+                                            bool throttle_frame_production) {
+  FakeSchedulerClient client;
+  SchedulerSettings scheduler_settings;
+  scheduler_settings.begin_frame_scheduling_enabled =
+      begin_frame_scheduling_enabled;
+  scheduler_settings.throttle_frame_production = throttle_frame_production;
+  TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
+  scheduler->SetCanStart();
+  scheduler->SetVisible(true);
+  scheduler->SetCanDraw(true);
+  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+
+  // To test swap ack throttling, this test disables automatic swap acks.
+  scheduler->SetMaxSwapsPending(1);
+  client.SetAutomaticSwapAck(false);
+
+  // SetNeedsCommit should begin the frame on the next BeginImplFrame.
+  client.Reset();
+  scheduler->SetNeedsCommit();
+  EXPECT_FALSE(client.needs_begin_frame());
+  EXPECT_NO_ACTION(client);
+  client.Reset();
+
+  // Trigger the first BeginImplFrame and BeginMainFrame
+  client.task_runner().RunPendingTasks();  // Run posted BeginFrame.
+  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+  EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+  EXPECT_FALSE(client.needs_begin_frame());
+  client.Reset();
+
+  // NotifyReadyToCommit should trigger the pending commit and draw.
+  scheduler->NotifyBeginMainFrameStarted();
+  scheduler->NotifyReadyToCommit();
+  EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
+  EXPECT_FALSE(client.needs_begin_frame());
+  client.Reset();
+
+  // Swapping will put us into a swap throttled state.
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
+  EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
+  EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
+  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+  EXPECT_FALSE(client.needs_begin_frame());
+  client.Reset();
+
+  // While swap throttled, BeginFrames should trigger BeginImplFrames,
+  // but not a BeginMainFrame or draw.
+  scheduler->SetNeedsCommit();
+  client.task_runner().RunPendingTasks();  // Run posted BeginFrame.
+  EXPECT_ACTION("WillBeginImplFrame", client, 0, 1);
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+  EXPECT_FALSE(client.needs_begin_frame());
+  client.Reset();
+
+  // Take us out of a swap throttled state.
+  scheduler->DidSwapBuffersComplete();
+  EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 1);
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+  EXPECT_FALSE(client.needs_begin_frame());
+  client.Reset();
+
+  // BeginImplFrame deadline should draw.
+  scheduler->SetNeedsRedraw();
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
+  EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
+  EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
+  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+  EXPECT_FALSE(client.needs_begin_frame());
+  client.Reset();
+}
+
+TEST(SchedulerTest, SyntheticBeginFrames_SwapThrottled) {
+  bool begin_frame_scheduling_enabled = false;
+  bool throttle_frame_production = true;
+  BeginFramesNotFromClient_SwapThrottled(begin_frame_scheduling_enabled,
+                                         throttle_frame_production);
+}
+
+TEST(SchedulerTest, VSyncThrottlingDisabled_SwapThrottled) {
+  bool begin_frame_scheduling_enabled = true;
+  bool throttle_frame_production = false;
+  BeginFramesNotFromClient_SwapThrottled(begin_frame_scheduling_enabled,
+                                         throttle_frame_production);
+}
+
+TEST(SchedulerTest,
+     SyntheticBeginFrames_And_VSyncThrottlingDisabled_SwapThrottled) {
+  bool begin_frame_scheduling_enabled = false;
+  bool throttle_frame_production = false;
+  BeginFramesNotFromClient_SwapThrottled(begin_frame_scheduling_enabled,
+                                         throttle_frame_production);
+}
+
+TEST(SchedulerTest, DidLoseOutputSurfaceAfterOutputSurfaceIsInitialized) {
+  FakeSchedulerClient client;
+  SchedulerSettings scheduler_settings;
+  TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
+  scheduler->SetCanStart();
+  scheduler->SetVisible(true);
+  scheduler->SetCanDraw(true);
+
+  EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
+  client.Reset();
+  scheduler->DidCreateAndInitializeOutputSurface();
+  EXPECT_NO_ACTION(client);
+
+  scheduler->DidLoseOutputSurface();
+  EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
+}
+
+TEST(SchedulerTest, DidLoseOutputSurfaceAfterBeginFrameStarted) {
+  FakeSchedulerClient client;
+  SchedulerSettings scheduler_settings;
+  TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
+  scheduler->SetCanStart();
+  scheduler->SetVisible(true);
+  scheduler->SetCanDraw(true);
+
+  EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
+  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+  // SetNeedsCommit should begin the frame.
+  client.Reset();
+  scheduler->SetNeedsCommit();
+  EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
+
+  client.Reset();
+  client.AdvanceFrame();
+  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+  EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+
+  client.Reset();
+  scheduler->DidLoseOutputSurface();
+  // Do nothing when impl frame is in deadine pending state.
+  EXPECT_NO_ACTION(client);
+
+  client.Reset();
+  scheduler->NotifyBeginMainFrameStarted();
+  scheduler->NotifyReadyToCommit();
+  EXPECT_ACTION("ScheduledActionCommit", client, 0, 1);
+
+  client.Reset();
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
+  EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
+}
+
+void DidLoseOutputSurfaceAfterBeginFrameStartedWithHighLatency(
+    bool impl_side_painting) {
+  FakeSchedulerClient client;
+  SchedulerSettings scheduler_settings;
+  scheduler_settings.impl_side_painting = impl_side_painting;
+  TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
+  scheduler->SetCanStart();
+  scheduler->SetVisible(true);
+  scheduler->SetCanDraw(true);
+
+  EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
+  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+
+  // SetNeedsCommit should begin the frame.
+  client.Reset();
+  scheduler->SetNeedsCommit();
+  EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
+
+  client.Reset();
+  client.AdvanceFrame();
+  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+  EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+
+  client.Reset();
+  scheduler->DidLoseOutputSurface();
+  // Do nothing when impl frame is in deadine pending state.
+  EXPECT_NO_ACTION(client);
+
+  client.Reset();
+  // Run posted deadline.
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+  client.task_runner().RunTasksWhile(client.ImplFrameDeadlinePending(true));
+  // OnBeginImplFrameDeadline didn't schedule any actions because main frame is
+  // not yet completed.
+  EXPECT_NO_ACTION(client);
+  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+
+  // BeginImplFrame is not started.
+  client.task_runner().RunUntilTime(client.now_src()->Now() +
+                                    base::TimeDelta::FromMilliseconds(10));
+  EXPECT_NO_ACTION(client);
+  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+
+  client.Reset();
+  scheduler->NotifyBeginMainFrameStarted();
+  scheduler->NotifyReadyToCommit();
+  if (impl_side_painting) {
+    EXPECT_ACTION("ScheduledActionCommit", client, 0, 3);
+    EXPECT_ACTION("ScheduledActionActivateSyncTree", client, 1, 3);
+    EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client, 2, 3);
+  } else {
+    EXPECT_ACTION("ScheduledActionCommit", client, 0, 2);
+    EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client, 1, 2);
+  }
+}
+
+TEST(SchedulerTest, DidLoseOutputSurfaceAfterBeginFrameStartedWithHighLatency) {
+  bool impl_side_painting = false;
+  DidLoseOutputSurfaceAfterBeginFrameStartedWithHighLatency(impl_side_painting);
+}
+
+TEST(SchedulerTest,
+     DidLoseOutputSurfaceAfterBeginFrameStartedWithHighLatencyWithImplPaint) {
+  bool impl_side_painting = true;
+  DidLoseOutputSurfaceAfterBeginFrameStartedWithHighLatency(impl_side_painting);
+}
+
+void DidLoseOutputSurfaceAfterReadyToCommit(bool impl_side_painting) {
+  FakeSchedulerClient client;
+  SchedulerSettings scheduler_settings;
+  scheduler_settings.impl_side_painting = impl_side_painting;
+  TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
+  scheduler->SetCanStart();
+  scheduler->SetVisible(true);
+  scheduler->SetCanDraw(true);
+
+  EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
+  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+
+  // SetNeedsCommit should begin the frame.
+  client.Reset();
+  scheduler->SetNeedsCommit();
+  EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
+
+  client.Reset();
+  client.AdvanceFrame();
+  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+  EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+
+  client.Reset();
+  scheduler->NotifyBeginMainFrameStarted();
+  scheduler->NotifyReadyToCommit();
+  EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
+
+  client.Reset();
+  scheduler->DidLoseOutputSurface();
+  if (impl_side_painting) {
+    // Sync tree should be forced to activate.
+    EXPECT_SINGLE_ACTION("ScheduledActionActivateSyncTree", client);
+  } else {
+    // Do nothing when impl frame is in deadine pending state.
+    EXPECT_NO_ACTION(client);
+  }
+
+  client.Reset();
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
+  EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
+}
+
+TEST(SchedulerTest, DidLoseOutputSurfaceAfterReadyToCommit) {
+  DidLoseOutputSurfaceAfterReadyToCommit(false);
+}
+
+TEST(SchedulerTest, DidLoseOutputSurfaceAfterReadyToCommitWithImplPainting) {
+  DidLoseOutputSurfaceAfterReadyToCommit(true);
+}
+
+TEST(SchedulerTest, DidLoseOutputSurfaceAfterSetNeedsManageTiles) {
+  FakeSchedulerClient client;
+  SchedulerSettings scheduler_settings;
+  TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
+  scheduler->SetCanStart();
+  scheduler->SetVisible(true);
+  scheduler->SetCanDraw(true);
+  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+
+  client.Reset();
+  scheduler->SetNeedsManageTiles();
+  scheduler->SetNeedsRedraw();
+  EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
+  EXPECT_TRUE(client.needs_begin_frame());
+
+  client.Reset();
+  client.AdvanceFrame();
+  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+  EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+
+  client.Reset();
+  scheduler->DidLoseOutputSurface();
+  EXPECT_NO_ACTION(client);
+
+  client.Reset();
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
+  EXPECT_ACTION("ScheduledActionManageTiles", client, 0, 2);
+  EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client, 1, 2);
+}
+
+TEST(SchedulerTest, DidLoseOutputSurfaceAfterBeginRetroFramePosted) {
+  FakeSchedulerClient client;
+  SchedulerSettings scheduler_settings;
+  TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
+  scheduler->SetCanStart();
+  scheduler->SetVisible(true);
+  scheduler->SetCanDraw(true);
+  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+
+  // SetNeedsCommit should begin the frame on the next BeginImplFrame.
+  client.Reset();
+  scheduler->SetNeedsCommit();
+  EXPECT_TRUE(client.needs_begin_frame());
+  EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
+
+  // Create a BeginFrame with a long deadline to avoid race conditions.
+  // This is the first BeginFrame, which will be handled immediately.
+  client.Reset();
+  BeginFrameArgs args = CreateBeginFrameArgsForTesting(client.now_src());
+  args.deadline += base::TimeDelta::FromHours(1);
+  scheduler->BeginFrame(args);
+  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+  EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+  EXPECT_TRUE(client.needs_begin_frame());
+
+  // Queue BeginFrames while we are still handling the previous BeginFrame.
+  args.frame_time += base::TimeDelta::FromSeconds(1);
+  scheduler->BeginFrame(args);
+  args.frame_time += base::TimeDelta::FromSeconds(1);
+  scheduler->BeginFrame(args);
+
+  // If we don't swap on the deadline, we wait for the next BeginImplFrame.
+  client.Reset();
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
+  EXPECT_NO_ACTION(client);
+  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+  EXPECT_TRUE(client.needs_begin_frame());
+
+  // NotifyReadyToCommit should trigger the commit.
+  client.Reset();
+  scheduler->NotifyBeginMainFrameStarted();
+  scheduler->NotifyReadyToCommit();
+  EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
+  EXPECT_TRUE(client.needs_begin_frame());
+
+  client.Reset();
+  EXPECT_FALSE(scheduler->IsBeginRetroFrameArgsEmpty());
+  scheduler->DidLoseOutputSurface();
+  EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
+  EXPECT_TRUE(client.needs_begin_frame());
+  EXPECT_TRUE(scheduler->IsBeginRetroFrameArgsEmpty());
+
+  // Posted BeginRetroFrame is aborted.
+  client.Reset();
+  client.task_runner().RunPendingTasks();
+  EXPECT_NO_ACTION(client);
+}
+
+TEST(SchedulerTest, DidLoseOutputSurfaceDuringBeginRetroFrameRunning) {
+  FakeSchedulerClient client;
+  SchedulerSettings scheduler_settings;
+  TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
+  scheduler->SetCanStart();
+  scheduler->SetVisible(true);
+  scheduler->SetCanDraw(true);
+  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+
+  // SetNeedsCommit should begin the frame on the next BeginImplFrame.
+  client.Reset();
+  scheduler->SetNeedsCommit();
+  EXPECT_TRUE(client.needs_begin_frame());
+  EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
+
+  // Create a BeginFrame with a long deadline to avoid race conditions.
+  // This is the first BeginFrame, which will be handled immediately.
+  client.Reset();
+  BeginFrameArgs args = CreateBeginFrameArgsForTesting(client.now_src());
+  args.deadline += base::TimeDelta::FromHours(1);
+  scheduler->BeginFrame(args);
+  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+  EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+  EXPECT_TRUE(client.needs_begin_frame());
+
+  // Queue BeginFrames while we are still handling the previous BeginFrame.
+  args.frame_time += base::TimeDelta::FromSeconds(1);
+  scheduler->BeginFrame(args);
+  args.frame_time += base::TimeDelta::FromSeconds(1);
+  scheduler->BeginFrame(args);
+
+  // If we don't swap on the deadline, we wait for the next BeginImplFrame.
+  client.Reset();
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
+  EXPECT_NO_ACTION(client);
+  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+  EXPECT_TRUE(client.needs_begin_frame());
+
+  // NotifyReadyToCommit should trigger the commit.
+  client.Reset();
+  scheduler->NotifyBeginMainFrameStarted();
+  scheduler->NotifyReadyToCommit();
+  EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
+  EXPECT_TRUE(client.needs_begin_frame());
+
+  // BeginImplFrame should prepare the draw.
+  client.Reset();
+  client.task_runner().RunPendingTasks();  // Run posted BeginRetroFrame.
+  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+  EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+  EXPECT_TRUE(client.needs_begin_frame());
+
+  client.Reset();
+  EXPECT_FALSE(scheduler->IsBeginRetroFrameArgsEmpty());
+  scheduler->DidLoseOutputSurface();
+  EXPECT_NO_ACTION(client);
+  EXPECT_TRUE(scheduler->IsBeginRetroFrameArgsEmpty());
+
+  // BeginImplFrame deadline should abort drawing.
+  client.Reset();
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
+  EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
+  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+  EXPECT_TRUE(client.needs_begin_frame());
+
+  // No more BeginRetroFrame because BeginRetroFrame queue is cleared.
+  client.Reset();
+  client.task_runner().RunPendingTasks();
+  EXPECT_NO_ACTION(client);
+}
+
+TEST(SchedulerTest,
+     StopBeginFrameAfterDidLoseOutputSurfaceWithSyntheticBeginFrameSource) {
+  FakeSchedulerClient client;
+  SchedulerSettings scheduler_settings;
+  scheduler_settings.begin_frame_scheduling_enabled = false;
+  TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
+  scheduler->SetCanStart();
+  scheduler->SetVisible(true);
+  scheduler->SetCanDraw(true);
+  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+
+  // SetNeedsCommit should begin the frame on the next BeginImplFrame.
+  client.Reset();
+  EXPECT_FALSE(scheduler->IsSyntheticBeginFrameSourceActive());
+  scheduler->SetNeedsCommit();
+  EXPECT_TRUE(scheduler->IsSyntheticBeginFrameSourceActive());
+
+  client.Reset();
+  client.task_runner().RunPendingTasks();  // Run posted Tick.
+  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+  EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+  EXPECT_TRUE(scheduler->IsSyntheticBeginFrameSourceActive());
+
+  // NotifyReadyToCommit should trigger the commit.
+  client.Reset();
+  scheduler->NotifyBeginMainFrameStarted();
+  scheduler->NotifyReadyToCommit();
+  EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
+  EXPECT_TRUE(scheduler->IsSyntheticBeginFrameSourceActive());
+
+  client.Reset();
+  scheduler->DidLoseOutputSurface();
+  EXPECT_EQ(0, client.num_actions_());
+  EXPECT_FALSE(scheduler->IsSyntheticBeginFrameSourceActive());
+
+  client.Reset();
+  client.task_runner().RunPendingTasks();  // Run posted deadline.
+  EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
+  EXPECT_FALSE(scheduler->IsSyntheticBeginFrameSourceActive());
+}
+
+TEST(SchedulerTest, ScheduledActionActivateAfterBecomingInvisible) {
+  FakeSchedulerClient client;
+  SchedulerSettings scheduler_settings;
+  scheduler_settings.impl_side_painting = true;
+  TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
+  scheduler->SetCanStart();
+  scheduler->SetVisible(true);
+  scheduler->SetCanDraw(true);
+
+  EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
+  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+
+  // SetNeedsCommit should begin the frame.
+  client.Reset();
+  scheduler->SetNeedsCommit();
+  EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
+
+  client.Reset();
+  client.AdvanceFrame();
+  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+  EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+
+  client.Reset();
+  scheduler->NotifyBeginMainFrameStarted();
+  scheduler->NotifyReadyToCommit();
+  EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
+
+  client.Reset();
+  scheduler->SetVisible(false);
+  // Sync tree should be forced to activate.
+  EXPECT_SINGLE_ACTION("ScheduledActionActivateSyncTree", client);
 }
 
 }  // namespace