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);