MouseCursorMonitor implementation for OSX and Windows.

BUG=crbug.com/173265
R=wez@chromium.org

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk/webrtc@4994 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/modules/desktop_capture/desktop_frame.cc b/modules/desktop_capture/desktop_frame.cc
index 90e1fbd..f293baf 100644
--- a/modules/desktop_capture/desktop_frame.cc
+++ b/modules/desktop_capture/desktop_frame.cc
@@ -10,6 +10,8 @@
 
 #include "webrtc/modules/desktop_capture/desktop_frame.h"
 
+#include <string.h>
+
 namespace webrtc {
 
 DesktopFrame::DesktopFrame(DesktopSize size,
@@ -35,6 +37,20 @@
   delete[] data_;
 }
 
+DesktopFrame* BasicDesktopFrame::CopyOf(const DesktopFrame& frame) {
+  DesktopFrame* result = new BasicDesktopFrame(frame.size());
+  for (int y = 0; y < frame.size().height(); ++y) {
+    memcpy(result->data() + y * result->stride(),
+           frame.data() + y * frame.stride(),
+           frame.size().width() * kBytesPerPixel);
+  }
+  result->set_dpi(frame.dpi());
+  result->set_capture_time_ms(frame.capture_time_ms());
+  *result->mutable_updated_region() = frame.updated_region();
+  return result;
+}
+
+
 SharedMemoryDesktopFrame::SharedMemoryDesktopFrame(
     DesktopSize size,
     int stride,
diff --git a/modules/desktop_capture/desktop_frame.h b/modules/desktop_capture/desktop_frame.h
index a39eff7..b420a3c 100644
--- a/modules/desktop_capture/desktop_frame.h
+++ b/modules/desktop_capture/desktop_frame.h
@@ -83,6 +83,9 @@
   explicit BasicDesktopFrame(DesktopSize size);
   virtual ~BasicDesktopFrame();
 
+  // Creates a BasicDesktopFrame that contains copy of |frame|.
+  static DesktopFrame* CopyOf(const DesktopFrame& frame);
+
  private:
   DISALLOW_COPY_AND_ASSIGN(BasicDesktopFrame);
 };
diff --git a/modules/desktop_capture/mouse_cursor.cc b/modules/desktop_capture/mouse_cursor.cc
index 67eb4bf..3f1ab3d 100644
--- a/modules/desktop_capture/mouse_cursor.cc
+++ b/modules/desktop_capture/mouse_cursor.cc
@@ -23,4 +23,10 @@
 
 MouseCursor::~MouseCursor() {}
 
+// static
+MouseCursor* MouseCursor::CopyOf(const MouseCursor& cursor) {
+  return new MouseCursor(BasicDesktopFrame::CopyOf(cursor.image()),
+                         cursor.hotspot());
+}
+
 }  // namespace webrtc
diff --git a/modules/desktop_capture/mouse_cursor.h b/modules/desktop_capture/mouse_cursor.h
index f37eeb3..4cf7708 100644
--- a/modules/desktop_capture/mouse_cursor.h
+++ b/modules/desktop_capture/mouse_cursor.h
@@ -25,8 +25,10 @@
   MouseCursor(DesktopFrame* image, const DesktopVector& hotspot);
   ~MouseCursor();
 
-  const DesktopFrame& image() { return *image_; }
-  const DesktopVector& hotspot() { return hotspot_; }
+  static MouseCursor* CopyOf(const MouseCursor& cursor);
+
+  const DesktopFrame& image() const { return *image_; }
+  const DesktopVector& hotspot() const { return hotspot_; }
 
  private:
   scoped_ptr<DesktopFrame> image_;
diff --git a/modules/desktop_capture/mouse_cursor_monitor_mac.mm b/modules/desktop_capture/mouse_cursor_monitor_mac.mm
index f742dfa..6f9380a 100644
--- a/modules/desktop_capture/mouse_cursor_monitor_mac.mm
+++ b/modules/desktop_capture/mouse_cursor_monitor_mac.mm
@@ -10,19 +10,209 @@
 
 #include "webrtc/modules/desktop_capture/mouse_cursor_monitor.h"
 
-#include <cstddef>
+#include <assert.h>
+#include <ApplicationServices/ApplicationServices.h>
+#include <Cocoa/Cocoa.h>
+#include <CoreFoundation/CoreFoundation.h>
+
+#include "webrtc/modules/desktop_capture/desktop_frame.h"
+#include "webrtc/modules/desktop_capture/mouse_cursor.h"
+#include "webrtc/system_wrappers/interface/scoped_ptr.h"
 
 namespace webrtc {
 
-// TODO(sergeyu): Implement MouseCursorMonitor for Mac.
+class MouseCursorMonitorMac : public MouseCursorMonitor {
+ public:
+  MouseCursorMonitorMac(CGWindowID window_id);
+  virtual ~MouseCursorMonitorMac();
+
+  virtual void Init(Callback* callback, Mode mode) OVERRIDE;
+  virtual void Capture() OVERRIDE;
+
+ private:
+  void CaptureImage();
+
+  CGWindowID window_id_;
+
+  Callback* callback_;
+  Mode mode_;
+
+  scoped_ptr<MouseCursor> last_cursor_;
+};
+
+MouseCursorMonitorMac::MouseCursorMonitorMac(CGWindowID window_id)
+    : window_id_(window_id),
+      callback_(NULL),
+      mode_(SHAPE_AND_POSITION) {
+}
+
+MouseCursorMonitorMac::~MouseCursorMonitorMac() {}
+
+void MouseCursorMonitorMac::Init(Callback* callback, Mode mode) {
+  assert(!callback_);
+  assert(callback);
+
+  callback_ = callback;
+  mode_ = mode;
+}
+
+void MouseCursorMonitorMac::Capture() {
+  assert(callback_);
+
+  CaptureImage();
+
+  if (mode_ != SHAPE_AND_POSITION)
+    return;
+
+  CursorState state = INSIDE;
+
+  CGEventRef event = CGEventCreate(NULL);
+  CGPoint gc_position = CGEventGetLocation(event);
+  CFRelease(event);
+
+  DesktopVector position(gc_position.x, gc_position.y);
+
+  // If we are capturing cursor for a specific window then we need to figure out
+  // if the current mouse position is covered by another window and also adjust
+  // |position| to make it relative to the window origin.
+  if (window_id_ != kCGNullWindowID) {
+    // Get list of windows that may be covering parts of |window_id_|.
+    // CGWindowListCopyWindowInfo() returns windows in order from front to back,
+    // so |window_id_| is expected to be the last in the list.
+    CFArrayRef window_array =
+        CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly |
+                                       kCGWindowListOptionOnScreenAboveWindow |
+                                       kCGWindowListOptionIncludingWindow,
+                                   window_id_);
+    bool found_window = false;
+    if (window_array) {
+      CFIndex count = CFArrayGetCount(window_array);
+      for (CFIndex i = 0; i < count; ++i) {
+        CFDictionaryRef window = reinterpret_cast<CFDictionaryRef>(
+            CFArrayGetValueAtIndex(window_array, i));
+
+        // Skip the Dock window. Dock window covers the whole screen, but it is
+        // transparent.
+        CFStringRef window_name = reinterpret_cast<CFStringRef>(
+            CFDictionaryGetValue(window, kCGWindowName));
+        if (window_name && CFStringCompare(window_name, CFSTR("Dock"), 0) == 0)
+          continue;
+
+        CFDictionaryRef window_bounds = reinterpret_cast<CFDictionaryRef>(
+            CFDictionaryGetValue(window, kCGWindowBounds));
+        CFNumberRef window_number = reinterpret_cast<CFNumberRef>(
+            CFDictionaryGetValue(window, kCGWindowNumber));
+
+        if (window_bounds && window_number) {
+          CGRect gc_window_rect;
+          if (!CGRectMakeWithDictionaryRepresentation(window_bounds,
+                                                      &gc_window_rect)) {
+            continue;
+          }
+          DesktopRect window_rect =
+              DesktopRect::MakeXYWH(gc_window_rect.origin.x,
+                                    gc_window_rect.origin.y,
+                                    gc_window_rect.size.width,
+                                    gc_window_rect.size.height);
+
+          CGWindowID window_id;
+          if (!CFNumberGetValue(window_number, kCFNumberIntType, &window_id))
+            continue;
+
+          if (window_id == window_id_) {
+            found_window = true;
+            if (!window_rect.Contains(position))
+              state = OUTSIDE;
+            position = position.subtract(window_rect.top_left());
+
+            assert(i == count - 1);
+            break;
+          } else if (window_rect.Contains(position)) {
+            state = OUTSIDE;
+            position.set(-1, -1);
+            break;
+          }
+        }
+      }
+
+      CFRelease(window_array);
+    }
+
+    if (!found_window) {
+      // If we failed to get list of windows or the window wasn't in the list
+      // pretend that the cursor is outside the window. This can happen, e.g. if
+      // the window was closed.
+      state = OUTSIDE;
+      position.set(-1, -1);
+    }
+  }
+
+  callback_->OnMouseCursorPosition(state, position);
+}
+
+void MouseCursorMonitorMac::CaptureImage() {
+  NSCursor* nscursor = [NSCursor currentSystemCursor];
+
+  NSImage* nsimage = [nscursor image];
+  NSSize nssize = [nsimage size];
+  DesktopSize size(nssize.width, nssize.height);
+  NSPoint nshotspot = [nscursor hotSpot];
+  DesktopVector hotspot(
+      std::min(0, std::max(size.width(), static_cast<int>(nshotspot.x))),
+      std::min(0, std::max(size.height(), static_cast<int>(nshotspot.y))));
+  CGImageRef cg_image =
+      [nsimage CGImageForProposedRect:NULL context:nil hints:nil];
+  if (!cg_image)
+    return;
+
+  if (CGImageGetBitsPerPixel(cg_image) != DesktopFrame::kBytesPerPixel * 8 ||
+      CGImageGetBytesPerRow(cg_image) !=
+          static_cast<size_t>(DesktopFrame::kBytesPerPixel * size.width()) ||
+      CGImageGetBitsPerComponent(cg_image) != 8) {
+    return;
+  }
+
+  CGDataProviderRef provider = CGImageGetDataProvider(cg_image);
+  CFDataRef image_data_ref = CGDataProviderCopyData(provider);
+  if (image_data_ref == NULL)
+    return;
+
+  const uint8_t* src_data =
+      reinterpret_cast<const uint8_t*>(CFDataGetBytePtr(image_data_ref));
+
+  // Compare the cursor with the previous one.
+  if (last_cursor_.get() &&
+      last_cursor_->image().size().equals(size) &&
+      last_cursor_->hotspot().equals(hotspot) &&
+      memcmp(last_cursor_->image().data(), src_data,
+             last_cursor_->image().stride() * size.height()) == 0) {
+    return;
+  }
+
+  // Create a MouseCursor that describes the cursor and pass it to
+  // the client.
+  scoped_ptr<DesktopFrame> image(
+      new BasicDesktopFrame(DesktopSize(size.width(), size.height())));
+  memcpy(image->data(), src_data,
+         size.width() * size.height() * DesktopFrame::kBytesPerPixel);
+
+  CFRelease(image_data_ref);
+
+  scoped_ptr<MouseCursor> cursor(new MouseCursor(image.release(), hotspot));
+  last_cursor_.reset(MouseCursor::CopyOf(*cursor));
+
+  callback_->OnMouseCursor(cursor.release());
+}
+
+
 MouseCursorMonitor* MouseCursorMonitor::CreateForWindow(
     const DesktopCaptureOptions& options, WindowId window) {
-  return NULL;
+  return new MouseCursorMonitorMac(window);
 }
 
 MouseCursorMonitor* MouseCursorMonitor::CreateForScreen(
     const DesktopCaptureOptions& options) {
-  return NULL;
+  return new MouseCursorMonitorMac(kCGNullWindowID);
 }
 
 }  // namespace webrtc
diff --git a/modules/desktop_capture/mouse_cursor_monitor_unittest.cc b/modules/desktop_capture/mouse_cursor_monitor_unittest.cc
index bbd5be4..18bf1ca 100644
--- a/modules/desktop_capture/mouse_cursor_monitor_unittest.cc
+++ b/modules/desktop_capture/mouse_cursor_monitor_unittest.cc
@@ -46,8 +46,11 @@
   bool position_received_;
 };
 
-// TODO(sergeyu): Enable tests on all platforms.
-#if defined(USE_X11)
+// TODO(sergeyu): On Mac we need to initialize NSApplication before running the
+// tests. Figure out how to do that without breaking other tests in
+// modules_unittests and enable these tests on Mac.
+// https://code.google.com/p/webrtc/issues/detail?id=2532
+#if !defined(WEBRTC_MAC)
 #define MAYBE(x) x
 #else
 #define MAYBE(x) DISABLED_##x
diff --git a/modules/desktop_capture/mouse_cursor_monitor_win.cc b/modules/desktop_capture/mouse_cursor_monitor_win.cc
index 907129b..82f7d24 100644
--- a/modules/desktop_capture/mouse_cursor_monitor_win.cc
+++ b/modules/desktop_capture/mouse_cursor_monitor_win.cc
@@ -10,19 +10,103 @@
 
 #include "webrtc/modules/desktop_capture/mouse_cursor_monitor.h"
 
-#include <cstddef>
+#include "webrtc/modules/desktop_capture/desktop_frame.h"
+#include "webrtc/modules/desktop_capture/mouse_cursor.h"
+#include "webrtc/modules/desktop_capture/win/cursor.h"
+#include "webrtc/system_wrappers/interface/logging.h"
 
 namespace webrtc {
 
-// TODO(sergeyu): Implement MouseCursorMonitor for Windows.
+class MouseCursorMonitorWin : public MouseCursorMonitor {
+ public:
+  explicit MouseCursorMonitorWin(HWND window);
+  virtual ~MouseCursorMonitorWin();
+
+  virtual void Init(Callback* callback, Mode mode) OVERRIDE;
+  virtual void Capture() OVERRIDE;
+
+ private:
+  HWND window_;
+
+  Callback* callback_;
+  Mode mode_;
+
+  HDC desktop_dc_;
+
+  HCURSOR last_cursor_;
+};
+
+MouseCursorMonitorWin::MouseCursorMonitorWin(HWND window)
+    : window_(window),
+      callback_(NULL),
+      mode_(SHAPE_AND_POSITION),
+      desktop_dc_(NULL),
+      last_cursor_(NULL) {
+}
+
+MouseCursorMonitorWin::~MouseCursorMonitorWin() {
+  if (desktop_dc_)
+    ReleaseDC(NULL, desktop_dc_);
+}
+
+void MouseCursorMonitorWin::Init(Callback* callback, Mode mode) {
+  assert(!callback_);
+  assert(callback);
+
+  callback_ = callback;
+  mode_ = mode;
+
+  desktop_dc_ = GetDC(NULL);
+}
+
+void MouseCursorMonitorWin::Capture() {
+  assert(callback_);
+
+  CURSORINFO cursor_info;
+  cursor_info.cbSize = sizeof(CURSORINFO);
+  if (!GetCursorInfo(&cursor_info)) {
+    LOG_F(LS_ERROR) << "Unable to get cursor info. Error = " << GetLastError();
+    return;
+  }
+
+  if (last_cursor_ != cursor_info.hCursor) {
+    last_cursor_ = cursor_info.hCursor;
+    // Note that |cursor_info.hCursor| does not need to be freed.
+    scoped_ptr<MouseCursor> cursor(
+        CreateMouseCursorFromHCursor(desktop_dc_, cursor_info.hCursor));
+    if (cursor.get())
+      callback_->OnMouseCursor(cursor.release());
+  }
+
+  if (mode_ != SHAPE_AND_POSITION)
+    return;
+
+  DesktopVector position(cursor_info.ptScreenPos.x, cursor_info.ptScreenPos.y);
+  bool inside = cursor_info.flags == CURSOR_SHOWING;
+
+  if (window_) {
+    RECT rect;
+    if (!GetWindowRect(window_, &rect)) {
+      position.set(0, 0);
+      inside = false;
+    } else {
+      position = position.subtract(DesktopVector(rect.left, rect.top));
+      if (inside)
+        inside = (window_ == WindowFromPoint(cursor_info.ptScreenPos));
+    }
+  }
+
+  callback_->OnMouseCursorPosition(inside ? INSIDE : OUTSIDE, position);
+}
+
 MouseCursorMonitor* MouseCursorMonitor::CreateForWindow(
     const DesktopCaptureOptions& options, WindowId window) {
-  return NULL;
+  return new MouseCursorMonitorWin(reinterpret_cast<HWND>(window));
 }
 
 MouseCursorMonitor* MouseCursorMonitor::CreateForScreen(
     const DesktopCaptureOptions& options) {
-  return NULL;
+  return new MouseCursorMonitorWin(NULL);
 }
 
 }  // namespace webrtc
diff --git a/modules/desktop_capture/screen_capturer_win.cc b/modules/desktop_capture/screen_capturer_win.cc
index af9b18b..42a7192 100644
--- a/modules/desktop_capture/screen_capturer_win.cc
+++ b/modules/desktop_capture/screen_capturer_win.cc
@@ -17,6 +17,7 @@
 #include "webrtc/modules/desktop_capture/desktop_frame_win.h"
 #include "webrtc/modules/desktop_capture/desktop_region.h"
 #include "webrtc/modules/desktop_capture/differ.h"
+#include "webrtc/modules/desktop_capture/mouse_cursor.h"
 #include "webrtc/modules/desktop_capture/mouse_cursor_shape.h"
 #include "webrtc/modules/desktop_capture/screen_capture_frame_queue.h"
 #include "webrtc/modules/desktop_capture/screen_capturer_helper.h"
@@ -328,11 +329,19 @@
   }
 
   // Note that |cursor_info.hCursor| does not need to be freed.
-  scoped_ptr<MouseCursorShape> cursor(
-      CreateMouseCursorShapeFromCursor(desktop_dc_, cursor_info.hCursor));
-  if (!cursor.get())
+  scoped_ptr<MouseCursor> cursor_image(
+      CreateMouseCursorFromHCursor(desktop_dc_, cursor_info.hCursor));
+  if (!cursor_image.get())
     return;
 
+  scoped_ptr<MouseCursorShape> cursor(new MouseCursorShape);
+  cursor->hotspot = cursor_image->hotspot();
+  cursor->size = cursor_image->image().size();
+  cursor->data.assign(
+    cursor_image->image().data(),
+    cursor_image->image().data() +
+        cursor_image->image().stride() * DesktopFrame::kBytesPerPixel);
+
   // Compare the current cursor with the last one we sent to the client. If
   // they're the same, then don't bother sending the cursor again.
   if (last_cursor_.size.equals(cursor->size) &&
diff --git a/modules/desktop_capture/win/cursor.cc b/modules/desktop_capture/win/cursor.cc
index 76eed77..6e0fd4e 100644
--- a/modules/desktop_capture/win/cursor.cc
+++ b/modules/desktop_capture/win/cursor.cc
@@ -15,6 +15,7 @@
 #include "webrtc/modules/desktop_capture/win/scoped_gdi_object.h"
 #include "webrtc/modules/desktop_capture/desktop_frame.h"
 #include "webrtc/modules/desktop_capture/desktop_geometry.h"
+#include "webrtc/modules/desktop_capture/mouse_cursor.h"
 #include "webrtc/system_wrappers/interface/compile_assert.h"
 #include "webrtc/system_wrappers/interface/logging.h"
 #include "webrtc/system_wrappers/interface/scoped_ptr.h"
@@ -92,29 +93,24 @@
 }
 
 // Scans a 32bpp bitmap looking for any pixels with non-zero alpha component.
-// |*has_alpha| is set to true if non-zero alpha is found. |stride| is expressed
-// in pixels.
-bool HasAlphaChannel(const uint32_t* data, int stride, int width, int height,
-                     bool* has_alpha) {
+// Returns true if non-zero alpha is found. |stride| is expressed in pixels.
+bool HasAlphaChannel(const uint32_t* data, int stride, int width, int height) {
   const RGBQUAD* plane = reinterpret_cast<const RGBQUAD*>(data);
   for (int y = 0; y < height; ++y) {
     for (int x = 0; x < width; ++x) {
-      if (plane->rgbReserved != 0) {
-        *has_alpha = true;
+      if (plane->rgbReserved != 0)
         return true;
-      }
       plane += 1;
     }
     plane += stride - width;
   }
 
-  *has_alpha = false;
-  return true;
+  return false;
 }
 
 }  // namespace
 
-MouseCursorShape* CreateMouseCursorShapeFromCursor(HDC dc, HCURSOR cursor) {
+MouseCursor* CreateMouseCursorFromHCursor(HDC dc, HCURSOR cursor) {
   ICONINFO iinfo;
   if (!GetIconInfo(cursor, &iinfo)) {
     LOG_F(LS_ERROR) << "Unable to get cursor icon info. Error = "
@@ -167,20 +163,18 @@
   }
 
   uint32_t* mask_plane = mask_data.get();
-
-  scoped_array<uint32_t> color_data;
-  uint32_t* color_plane = NULL;
-  int color_stride = 0;
+  scoped_ptr<DesktopFrame> image(
+      new BasicDesktopFrame(DesktopSize(width, height)));
   bool has_alpha = false;
 
   if (is_color) {
+    image.reset(new BasicDesktopFrame(DesktopSize(width, height)));
     // Get the pixels from the color bitmap.
-    color_data.reset(new uint32_t[width * height]);
     if (!GetDIBits(dc,
                    scoped_color,
                    0,
                    height,
-                   color_data.get(),
+                   image->data(),
                    reinterpret_cast<BITMAPINFO*>(&bmi),
                    DIB_RGB_COLORS)) {
       LOG_F(LS_ERROR) << "Unable to get bitmap bits. Error = "
@@ -188,30 +182,28 @@
       return NULL;
     }
 
-    color_plane = color_data.get();
-    color_stride = width;
-
     // GetDIBits() does not provide any indication whether the bitmap has alpha
     // channel, so we use HasAlphaChannel() below to find it out.
-    if (!HasAlphaChannel(color_plane, color_stride, width, height, &has_alpha))
-      return NULL;
+    has_alpha = HasAlphaChannel(reinterpret_cast<uint32_t*>(image->data()),
+                                width, width, height);
   } else {
     // For non-color cursors, the mask contains both an AND and an XOR mask and
     // the height includes both. Thus, the width is correct, but we need to
     // divide by 2 to get the correct mask height.
     height /= 2;
 
+    image.reset(new BasicDesktopFrame(DesktopSize(width, height)));
+
     // The XOR mask becomes the color bitmap.
-    color_plane = mask_plane + (width * height);
-    color_stride = width;
+    memcpy(
+        image->data(), mask_plane + (width * height), image->stride() * width);
   }
 
   // Reconstruct transparency from the mask if the color image does not has
   // alpha channel.
   if (!has_alpha) {
     bool add_outline = false;
-    uint32_t* color = color_plane;
-    uint32_t* dst = color_plane;
+    uint32_t* dst = reinterpret_cast<uint32_t*>(image->data());
     uint32_t* mask = mask_plane;
     for (int y = 0; y < height; y++) {
       for (int x = 0; x < width; x++) {
@@ -226,36 +218,32 @@
         // with black. In this case, we also add an outline around the cursor
         // so that it is visible against a dark background.
         if (*mask == kPixelRgbWhite) {
-          if (*color != 0) {
+          if (*dst != 0) {
             add_outline = true;
             *dst = kPixelRgbaBlack;
           } else {
             *dst = kPixelRgbaTransparent;
           }
         } else {
-          *dst = kPixelRgbaBlack ^ *color;
+          *dst = kPixelRgbaBlack ^ *dst;
         }
 
-        ++color;
         ++dst;
         ++mask;
       }
     }
     if (add_outline) {
-      AddCursorOutline(width, height, color_plane);
+      AddCursorOutline(
+          width, height, reinterpret_cast<uint32_t*>(image->data()));
     }
   }
 
-  // Pre-multiply the resulting pixels since MouseCursorShape uses premultiplied
+  // Pre-multiply the resulting pixels since MouseCursor uses premultiplied
   // images.
-  AlphaMul(color_plane, width, height);
+  AlphaMul(reinterpret_cast<uint32_t*>(image->data()), width, height);
 
-  scoped_ptr<MouseCursorShape> result(new MouseCursorShape());
-  result->data.assign(reinterpret_cast<char*>(color_plane),
-                      height * width * kBytesPerPixel);
-  result->size.set(width, height);
-  result->hotspot.set(hotspot_x, hotspot_y);
-  return result.release();
+  return new MouseCursor(
+      image.release(), DesktopVector(hotspot_x, hotspot_y));
 }
 
 }  // namespace webrtc
diff --git a/modules/desktop_capture/win/cursor.h b/modules/desktop_capture/win/cursor.h
index 08a6c4a..d521cc0 100644
--- a/modules/desktop_capture/win/cursor.h
+++ b/modules/desktop_capture/win/cursor.h
@@ -13,13 +13,12 @@
 
 #include <windows.h>
 
-#include "webrtc/modules/desktop_capture/mouse_cursor_shape.h"
-
 namespace webrtc {
 
-// Converts a cursor into a |MouseCursorShape| instance.
-MouseCursorShape* CreateMouseCursorShapeFromCursor(
-    HDC dc, HCURSOR cursor);
+class MouseCursor;
+
+// Converts an HCURSOR into a |MouseCursor| instance.
+MouseCursor* CreateMouseCursorFromHCursor(HDC dc, HCURSOR cursor);
 
 }  // namespace webrtc
 
diff --git a/modules/desktop_capture/win/cursor_unittest.cc b/modules/desktop_capture/win/cursor_unittest.cc
index c1c7417..f590bd2 100644
--- a/modules/desktop_capture/win/cursor_unittest.cc
+++ b/modules/desktop_capture/win/cursor_unittest.cc
@@ -9,7 +9,9 @@
  */
 
 #include "testing/gmock/include/gmock/gmock.h"
+#include "webrtc/modules/desktop_capture/desktop_frame.h"
 #include "webrtc/modules/desktop_capture/desktop_geometry.h"
+#include "webrtc/modules/desktop_capture/mouse_cursor.h"
 #include "webrtc/modules/desktop_capture/win/cursor.h"
 #include "webrtc/modules/desktop_capture/win/cursor_unittest_resources.h"
 #include "webrtc/modules/desktop_capture/win/scoped_gdi_object.h"
@@ -19,9 +21,9 @@
 
 namespace {
 
-// Loads |left| from resources, converts it to a |MouseCursorShape| instance
-// and compares pixels with |right|. Returns true of MouseCursorShape bits
-// match |right|. |right| must be a 32bpp cursor with alpha channel.
+// Loads |left| from resources, converts it to a |MouseCursor| instance and
+// compares pixels with |right|. Returns true of MouseCursor bits match |right|.
+// |right| must be a 32bpp cursor with alpha channel.
 bool ConvertToMouseShapeAndCompare(unsigned left, unsigned right) {
   HMODULE instance = GetModuleHandle(NULL);
 
@@ -32,8 +34,8 @@
 
   // Convert |cursor| to |mouse_shape|.
   HDC dc = GetDC(NULL);
-  scoped_ptr<MouseCursorShape> mouse_shape(
-      CreateMouseCursorShapeFromCursor(dc, cursor));
+  scoped_ptr<MouseCursor> mouse_shape(
+      CreateMouseCursorFromHCursor(dc, cursor));
   ReleaseDC(NULL, dc);
 
   EXPECT_TRUE(mouse_shape.get());
@@ -56,7 +58,7 @@
 
   int width = bitmap_info.bmWidth;
   int height = bitmap_info.bmHeight;
-  EXPECT_TRUE(DesktopSize(width, height).equals(mouse_shape->size));
+  EXPECT_TRUE(DesktopSize(width, height).equals(mouse_shape->image().size()));
 
   // Get the pixels from |scoped_color|.
   int size = width * height;
@@ -64,13 +66,13 @@
   EXPECT_TRUE(GetBitmapBits(scoped_color, size * sizeof(uint32_t), data.get()));
 
   // Compare the 32bpp image in |mouse_shape| with the one loaded from |right|.
-  return memcmp(data.get(), mouse_shape->data.data(),
+  return memcmp(data.get(), mouse_shape->image().data(),
                 size * sizeof(uint32_t)) == 0;
 }
 
 }  // namespace
 
-TEST(MouseCursorShapeTest, MatchCursors) {
+TEST(MouseCursorTest, MatchCursors) {
   EXPECT_TRUE(ConvertToMouseShapeAndCompare(IDD_CURSOR1_24BPP,
                                             IDD_CURSOR1_32BPP));
 
diff --git a/modules/desktop_capture/window_capturer_mac.cc b/modules/desktop_capture/window_capturer_mac.cc
index 78f618d..6268fc0 100755
--- a/modules/desktop_capture/window_capturer_mac.cc
+++ b/modules/desktop_capture/window_capturer_mac.cc
@@ -41,29 +41,6 @@
   return true;
 }
 
-// DesktopFrame that stores data in CFData.
-class CFDataDesktopFrame : public DesktopFrame {
- public:
-  // Consumes |cf_data| reference.
-  //
-  // TODO(sergeyu): Here we const_cast<> the buffer used in CFDataRef. CFDataRef
-  // buffer is immutable, but DesktopFrame is always mutable. This shouldn't be
-  // a problem because frames generated by WindowCapturers are normally not
-  // mutated. To avoid this hack consider making DesktopFrame immutable and add
-  // MutableDesktopFrame.
-  CFDataDesktopFrame(DesktopSize size, int stride, CFDataRef cf_data)
-      : DesktopFrame(size, stride,
-                     const_cast<uint8_t*>(CFDataGetBytePtr(cf_data)), NULL),
-        cf_data_(cf_data) {
-  }
-  virtual ~CFDataDesktopFrame() {
-    CFRelease(cf_data_);
-  }
-
- private:
-  CFDataRef cf_data_;
-};
-
 class WindowCapturerMac : public WindowCapturer {
  public:
   WindowCapturerMac();
@@ -185,9 +162,18 @@
   int width = CGImageGetWidth(window_image);
   int height = CGImageGetHeight(window_image);
   CGDataProviderRef provider = CGImageGetDataProvider(window_image);
-  DesktopFrame* frame = new CFDataDesktopFrame(
-      DesktopSize(width, height), CGImageGetBytesPerRow(window_image),
-      CGDataProviderCopyData(provider));
+  CFDataRef cf_data = CGDataProviderCopyData(provider);
+  DesktopFrame* frame = new BasicDesktopFrame(
+      DesktopSize(width, height));
+
+  int src_stride = CGImageGetBytesPerRow(window_image);
+  const uint8_t* src_data = CFDataGetBytePtr(cf_data);
+  for (int y = 0; y < height; ++y) {
+    memcpy(frame->data() + frame->stride() * y, src_data + src_stride * y,
+           DesktopFrame::kBytesPerPixel * width);
+  }
+
+  CFRelease(cf_data);
   CFRelease(window_image);
 
   callback_->OnCaptureCompleted(frame);