Fix DesktopAndCursorComposer not to crash

DesktopAndCursorComposer was crashing when screen/window
capturer returns a NULL frame due to an error.

BUG=crbug.com/344093
R=jiayl@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/8769004

git-svn-id: http://webrtc.googlecode.com/svn/trunk/webrtc@5573 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/modules/desktop_capture/desktop_and_cursor_composer.cc b/modules/desktop_capture/desktop_and_cursor_composer.cc
index 59d564e..05e2a9b 100644
--- a/modules/desktop_capture/desktop_and_cursor_composer.cc
+++ b/modules/desktop_capture/desktop_and_cursor_composer.cc
@@ -147,7 +147,7 @@
 }
 
 void DesktopAndCursorComposer::OnCaptureCompleted(DesktopFrame* frame) {
-  if (cursor_.get() && cursor_state_ == MouseCursorMonitor::INSIDE) {
+  if (frame && cursor_.get() && cursor_state_ == MouseCursorMonitor::INSIDE) {
     DesktopFrameWithCursor* frame_with_cursor =
         new DesktopFrameWithCursor(frame, *cursor_, cursor_position_);
     frame = frame_with_cursor;
diff --git a/modules/desktop_capture/desktop_and_cursor_composer_unittest.cc b/modules/desktop_capture/desktop_and_cursor_composer_unittest.cc
index 15d6f54..b482a29 100644
--- a/modules/desktop_capture/desktop_and_cursor_composer_unittest.cc
+++ b/modules/desktop_capture/desktop_and_cursor_composer_unittest.cc
@@ -58,6 +58,18 @@
   return b + (g << 8) + (r << 16) + 0xff000000;
 }
 
+DesktopFrame* CreateTestFrame() {
+  DesktopFrame* frame =
+      new BasicDesktopFrame(DesktopSize(kScreenWidth, kScreenHeight));
+  uint32_t* data = reinterpret_cast<uint32_t*>(frame->data());
+  for (int y = 0; y < kScreenHeight; ++y) {
+    for (int x = 0; x < kScreenWidth; ++x) {
+      *(data++) = GetFakeFramePixelValue(DesktopVector(x, y));
+    }
+  }
+  return frame;
+}
+
 class FakeScreenCapturer : public DesktopCapturer {
  public:
   FakeScreenCapturer() {}
@@ -67,27 +79,17 @@
   }
 
   virtual void Capture(const DesktopRegion& region) OVERRIDE {
-    DesktopFrame* frame =
-        new BasicDesktopFrame(DesktopSize(kScreenWidth, kScreenHeight));
-    uint32_t* data = reinterpret_cast<uint32_t*>(frame->data());
-    for (int y = 0; y < kScreenHeight; ++y) {
-      for (int x = 0; x < kScreenWidth; ++x) {
-        *(data++) = GetFakeFramePixelValue(DesktopVector(x, y));
-      }
-    }
-
-    last_frame_.reset(SharedDesktopFrame::Wrap(frame));
-
-    callback_->OnCaptureCompleted(last_frame_->Share());
+    callback_->OnCaptureCompleted(next_frame_.release());
   }
 
-  // Returns last fake captured frame.
-  SharedDesktopFrame* last_frame() { return last_frame_.get(); }
+  void SetNextFrame(DesktopFrame* next_frame) {
+    next_frame_.reset(next_frame);
+  }
 
  private:
   Callback* callback_;
 
-  scoped_ptr<SharedDesktopFrame> last_frame_;
+  scoped_ptr<DesktopFrame> next_frame_;
 };
 
 class FakeMouseMonitor : public MouseCursorMonitor {
@@ -187,6 +189,20 @@
   scoped_ptr<DesktopFrame> frame_;
 };
 
+// Verify DesktopAndCursorComposer can handle the case when the screen capturer
+// fails.
+TEST_F(DesktopAndCursorComposerTest, Error) {
+  blender_.Start(this);
+
+  fake_cursor_->SetHotspot(DesktopVector());
+  fake_cursor_->SetState(MouseCursorMonitor::INSIDE, DesktopVector());
+  fake_screen_->SetNextFrame(NULL);
+
+  blender_.Capture(DesktopRegion());
+
+  EXPECT_EQ(frame_, static_cast<DesktopFrame*>(NULL));
+}
+
 TEST_F(DesktopAndCursorComposerTest, Blend) {
   struct {
     int x, y;
@@ -222,6 +238,10 @@
     DesktopVector pos(tests[i].x, tests[i].y);
     fake_cursor_->SetState(state, pos);
 
+    scoped_ptr<SharedDesktopFrame> frame(
+        SharedDesktopFrame::Wrap(CreateTestFrame()));
+    fake_screen_->SetNextFrame(frame->Share());
+
     blender_.Capture(DesktopRegion());
 
     VerifyFrame(*frame_, state, pos);
@@ -229,9 +249,7 @@
     // Verify that the cursor is erased before the frame buffer is returned to
     // the screen capturer.
     frame_.reset();
-    VerifyFrame(*fake_screen_->last_frame(),
-                MouseCursorMonitor::OUTSIDE,
-                DesktopVector());
+    VerifyFrame(*frame, MouseCursorMonitor::OUTSIDE, DesktopVector());
   }
 }