diff --git a/webrtc/modules/desktop_capture/desktop_frame.cc b/webrtc/modules/desktop_capture/desktop_frame.cc index 51cf568aa0..dfc0928b66 100644 --- a/webrtc/modules/desktop_capture/desktop_frame.cc +++ b/webrtc/modules/desktop_capture/desktop_frame.cc @@ -31,7 +31,7 @@ DesktopFrame::DesktopFrame(DesktopSize size, DesktopFrame::~DesktopFrame() {} -void DesktopFrame::CopyPixelsFrom(uint8_t* src_buffer, int src_stride, +void DesktopFrame::CopyPixelsFrom(const uint8_t* src_buffer, int src_stride, const DesktopRect& dest_rect) { RTC_CHECK(DesktopRect::MakeSize(size()).ContainsRect(dest_rect)); diff --git a/webrtc/modules/desktop_capture/desktop_frame.h b/webrtc/modules/desktop_capture/desktop_frame.h index 632bcfc2e7..d491135029 100644 --- a/webrtc/modules/desktop_capture/desktop_frame.h +++ b/webrtc/modules/desktop_capture/desktop_frame.h @@ -58,7 +58,7 @@ class DesktopFrame { // Copies pixels from a buffer or another frame. |dest_rect| rect must lay // within bounds of this frame. - void CopyPixelsFrom(uint8_t* src_buffer, + void CopyPixelsFrom(const uint8_t* src_buffer, int src_stride, const DesktopRect& dest_rect); void CopyPixelsFrom(const DesktopFrame& src_frame, diff --git a/webrtc/modules/desktop_capture/mouse_cursor_monitor_mac.mm b/webrtc/modules/desktop_capture/mouse_cursor_monitor_mac.mm index 5d6a9b0089..6e079b6662 100644 --- a/webrtc/modules/desktop_capture/mouse_cursor_monitor_mac.mm +++ b/webrtc/modules/desktop_capture/mouse_cursor_monitor_mac.mm @@ -30,6 +30,25 @@ namespace webrtc { +namespace { +// Paint the image, so that we can get a bitmap representation compatible with +// current context. For example, in the retina display, we are going to get an +// image with same visual size but underlying pixel size conforms to the retina +// setting. +NSImage* PaintInCurrentContext(NSImage* source) { + NSSize size = [source size]; + NSImage* new_image = [[[NSImage alloc] initWithSize:size] autorelease]; + [new_image lockFocus]; + NSRect frame = NSMakeRect(0, 0, size.width, size.height); + [source drawInRect:frame + fromRect:frame + operation:NSCompositeCopy + fraction:1.0]; + [new_image unlockFocus]; + return new_image; +} +} // namespace + class MouseCursorMonitorMac : public MouseCursorMonitor { public: MouseCursorMonitorMac(const DesktopCaptureOptions& options, @@ -47,7 +66,7 @@ class MouseCursorMonitorMac : public MouseCursorMonitor { void DisplaysReconfigured(CGDirectDisplayID display, CGDisplayChangeSummaryFlags flags); - void CaptureImage(); + void CaptureImage(float scale); rtc::scoped_refptr configuration_monitor_; CGWindowID window_id_; @@ -91,11 +110,6 @@ void MouseCursorMonitorMac::Init(Callback* callback, Mode mode) { void MouseCursorMonitorMac::Capture() { assert(callback_); - CaptureImage(); - - if (mode_ != SHAPE_AND_POSITION) - return; - CursorState state = INSIDE; CGEventRef event = CGEventCreate(NULL); @@ -113,12 +127,18 @@ void MouseCursorMonitorMac::Capture() { // Find the dpi to physical pixel scale for the screen where the mouse cursor // is. for (MacDisplayConfigurations::iterator it = configuration.displays.begin(); - it != configuration.displays.end(); ++it) { + it != configuration.displays.end(); ++it) { if (it->bounds.Contains(position)) { scale = it->dip_to_pixel_scale; break; } } + + CaptureImage(scale); + + if (mode_ != SHAPE_AND_POSITION) + return; + // 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. @@ -228,24 +248,32 @@ void MouseCursorMonitorMac::Capture() { callback_->OnMouseCursorPosition(state, position); } -void MouseCursorMonitorMac::CaptureImage() { +void MouseCursorMonitorMac::CaptureImage(float scale) { NSCursor* nscursor = [NSCursor currentSystemCursor]; NSImage* nsimage = [nscursor image]; - NSSize nssize = [nsimage size]; - DesktopSize size(nssize.width, nssize.height); + NSSize nssize = [nsimage size]; // DIP size + + // For retina screen, we need to paint the cursor in current graphic context + // to get retina representation. + if (scale != 1.0) + nsimage = PaintInCurrentContext(nsimage); + + DesktopSize size(round(nssize.width * scale), + round(nssize.height * scale)); // Pixel size NSPoint nshotspot = [nscursor hotSpot]; DesktopVector hotspot( - std::max(0, std::min(size.width(), static_cast(nshotspot.x))), - std::max(0, std::min(size.height(), static_cast(nshotspot.y)))); + std::max(0, + std::min(size.width(), static_cast(nshotspot.x * scale))), + std::max(0, + std::min(size.height(), static_cast(nshotspot.y * scale)))); 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(DesktopFrame::kBytesPerPixel * size.width()) || + CGImageGetWidth(cg_image) != static_cast(size.width()) || CGImageGetBitsPerComponent(cg_image) != 8) { return; } @@ -272,8 +300,9 @@ void MouseCursorMonitorMac::CaptureImage() { // the client. std::unique_ptr image( new BasicDesktopFrame(DesktopSize(size.width(), size.height()))); - memcpy(image->data(), src_data, - size.width() * size.height() * DesktopFrame::kBytesPerPixel); + + int src_stride = CGImageGetBytesPerRow(cg_image); + image->CopyPixelsFrom(src_data, src_stride, DesktopRect::MakeSize(size)); CFRelease(image_data_ref);