| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
| 5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
| 6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ | 9 */ |
| 10 | 10 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 23 #include "webrtc/modules/desktop_capture/desktop_capture_options.h" | 23 #include "webrtc/modules/desktop_capture/desktop_capture_options.h" |
| 24 #include "webrtc/modules/desktop_capture/desktop_frame.h" | 24 #include "webrtc/modules/desktop_capture/desktop_frame.h" |
| 25 #include "webrtc/modules/desktop_capture/mac/desktop_configuration.h" | 25 #include "webrtc/modules/desktop_capture/mac/desktop_configuration.h" |
| 26 #include "webrtc/modules/desktop_capture/mac/desktop_configuration_monitor.h" | 26 #include "webrtc/modules/desktop_capture/mac/desktop_configuration_monitor.h" |
| 27 #include "webrtc/modules/desktop_capture/mac/full_screen_chrome_window_detector.
h" | 27 #include "webrtc/modules/desktop_capture/mac/full_screen_chrome_window_detector.
h" |
| 28 #include "webrtc/modules/desktop_capture/mouse_cursor.h" | 28 #include "webrtc/modules/desktop_capture/mouse_cursor.h" |
| 29 | 29 |
| 30 namespace webrtc { | 30 namespace webrtc { |
| 31 | 31 |
| 32 namespace { | 32 namespace { |
| 33 // Paint the image, so that we can get a bitmap representation compatible with | 33 CGImageRef CreateScaledCGImage(CGImageRef image, int width, int height) { |
| 34 // current context. For example, in the retina display, we are going to get an | 34 // Create context, keeping original image properties. |
| 35 // image with same visual size but underlying pixel size conforms to the retina | 35 CGColorSpaceRef colorspace = CGImageGetColorSpace(image); |
| 36 // setting. | 36 CGContextRef context = CGBitmapContextCreate(nullptr, |
| 37 NSImage* PaintInCurrentContext(NSImage* source) { | 37 width, |
| 38 NSSize size = [source size]; | 38 height, |
| 39 NSImage* new_image = [[NSImage alloc] initWithSize:size]; | 39 CGImageGetBitsPerComponent(image)
, |
| 40 [new_image lockFocus]; | 40 width * DesktopFrame::kBytesPerPi
xel, |
| 41 NSRect frame = NSMakeRect(0, 0, size.width, size.height); | 41 colorspace, |
| 42 [source drawInRect:frame | 42 CGImageGetBitmapInfo(image)); |
| 43 fromRect:frame | 43 |
| 44 operation:NSCompositeCopy | 44 if (!context) return nil; |
| 45 fraction:1.0]; | 45 |
| 46 [new_image unlockFocus]; | 46 // Draw image to context, resizing it. |
| 47 return new_image; | 47 CGContextDrawImage(context, CGRectMake(0, 0, width, height), image); |
| 48 // Extract resulting image from context. |
| 49 CGImageRef imgRef = CGBitmapContextCreateImage(context); |
| 50 CGContextRelease(context); |
| 51 |
| 52 return imgRef; |
| 48 } | 53 } |
| 49 } // namespace | 54 } // namespace |
| 50 | 55 |
| 51 class MouseCursorMonitorMac : public MouseCursorMonitor { | 56 class MouseCursorMonitorMac : public MouseCursorMonitor { |
| 52 public: | 57 public: |
| 53 MouseCursorMonitorMac(const DesktopCaptureOptions& options, | 58 MouseCursorMonitorMac(const DesktopCaptureOptions& options, |
| 54 CGWindowID window_id, | 59 CGWindowID window_id, |
| 55 ScreenId screen_id); | 60 ScreenId screen_id); |
| 56 ~MouseCursorMonitorMac() override; | 61 ~MouseCursorMonitorMac() override; |
| 57 | 62 |
| 58 void Init(Callback* callback, Mode mode) override; | 63 void Init(Callback* callback, Mode mode) override; |
| 59 void Capture() override; | 64 void Capture() override; |
| 60 | 65 |
| 61 private: | 66 private: |
| 62 static void DisplaysReconfiguredCallback(CGDirectDisplayID display, | 67 static void DisplaysReconfiguredCallback(CGDirectDisplayID display, |
| 63 CGDisplayChangeSummaryFlags flags, | 68 CGDisplayChangeSummaryFlags flags, |
| 64 void *user_parameter); | 69 void *user_parameter); |
| 65 void DisplaysReconfigured(CGDirectDisplayID display, | 70 void DisplaysReconfigured(CGDirectDisplayID display, |
| 66 CGDisplayChangeSummaryFlags flags); | 71 CGDisplayChangeSummaryFlags flags); |
| 67 | 72 |
| 68 void CaptureImage(float scale); | 73 void CaptureImage(float scale); |
| 69 | 74 |
| 70 rtc::scoped_refptr<DesktopConfigurationMonitor> configuration_monitor_; | 75 rtc::scoped_refptr<DesktopConfigurationMonitor> configuration_monitor_; |
| 71 CGWindowID window_id_; | 76 CGWindowID window_id_; |
| 72 ScreenId screen_id_; | 77 ScreenId screen_id_; |
| 73 Callback* callback_; | 78 Callback* callback_; |
| 74 Mode mode_; | 79 Mode mode_; |
| 75 std::unique_ptr<MouseCursor> last_cursor_; | 80 __strong NSImage* last_cursor_; |
| 76 rtc::scoped_refptr<FullScreenChromeWindowDetector> | 81 rtc::scoped_refptr<FullScreenChromeWindowDetector> |
| 77 full_screen_chrome_window_detector_; | 82 full_screen_chrome_window_detector_; |
| 78 }; | 83 }; |
| 79 | 84 |
| 80 MouseCursorMonitorMac::MouseCursorMonitorMac( | 85 MouseCursorMonitorMac::MouseCursorMonitorMac( |
| 81 const DesktopCaptureOptions& options, | 86 const DesktopCaptureOptions& options, |
| 82 CGWindowID window_id, | 87 CGWindowID window_id, |
| 83 ScreenId screen_id) | 88 ScreenId screen_id) |
| 84 : configuration_monitor_(options.configuration_monitor()), | 89 : configuration_monitor_(options.configuration_monitor()), |
| 85 window_id_(window_id), | 90 window_id_(window_id), |
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 246 } | 251 } |
| 247 callback_->OnMouseCursorPosition(state, position); | 252 callback_->OnMouseCursorPosition(state, position); |
| 248 } | 253 } |
| 249 | 254 |
| 250 void MouseCursorMonitorMac::CaptureImage(float scale) { | 255 void MouseCursorMonitorMac::CaptureImage(float scale) { |
| 251 NSCursor* nscursor = [NSCursor currentSystemCursor]; | 256 NSCursor* nscursor = [NSCursor currentSystemCursor]; |
| 252 | 257 |
| 253 NSImage* nsimage = [nscursor image]; | 258 NSImage* nsimage = [nscursor image]; |
| 254 NSSize nssize = [nsimage size]; // DIP size | 259 NSSize nssize = [nsimage size]; // DIP size |
| 255 | 260 |
| 256 // For retina screen, we need to paint the cursor in current graphic context | 261 // No need to caputre cursor image if it's unchanged since last capture. |
| 257 // to get retina representation. | 262 if ([[nsimage TIFFRepresentation] isEqual:[last_cursor_ TIFFRepresentation]])
return; |
| 258 if (scale != 1.0) | 263 last_cursor_ = nsimage; |
| 259 nsimage = PaintInCurrentContext(nsimage); | |
| 260 | 264 |
| 261 DesktopSize size(round(nssize.width * scale), | 265 DesktopSize size(round(nssize.width * scale), |
| 262 round(nssize.height * scale)); // Pixel size | 266 round(nssize.height * scale)); // Pixel size |
| 263 NSPoint nshotspot = [nscursor hotSpot]; | 267 NSPoint nshotspot = [nscursor hotSpot]; |
| 264 DesktopVector hotspot( | 268 DesktopVector hotspot( |
| 265 std::max(0, | 269 std::max(0, |
| 266 std::min(size.width(), static_cast<int>(nshotspot.x * scale))), | 270 std::min(size.width(), static_cast<int>(nshotspot.x * scale))), |
| 267 std::max(0, | 271 std::max(0, |
| 268 std::min(size.height(), static_cast<int>(nshotspot.y * scale)))); | 272 std::min(size.height(), static_cast<int>(nshotspot.y * scale)))); |
| 269 CGImageRef cg_image = | 273 CGImageRef cg_image = |
| 270 [nsimage CGImageForProposedRect:NULL context:nil hints:nil]; | 274 [nsimage CGImageForProposedRect:NULL context:nil hints:nil]; |
| 271 if (!cg_image) | 275 if (!cg_image) |
| 272 return; | 276 return; |
| 273 | 277 |
| 278 // Before 10.12, OSX may report 1X cursor on Retina screen. (See |
| 279 // crbug.com/632995.) After 10.12, OSX may report 2X cursor on non-Retina |
| 280 // screen. (See crbug.com/671436.) So scaling the cursor if needed. |
| 281 CGImageRef scaled_cg_image = nil; |
| 282 if (CGImageGetWidth(cg_image) != static_cast<size_t>(size.width())) { |
| 283 scaled_cg_image = CreateScaledCGImage(cg_image, size.width(), size.height())
; |
| 284 if (scaled_cg_image != nil) { |
| 285 cg_image = scaled_cg_image; |
| 286 } |
| 287 } |
| 274 if (CGImageGetBitsPerPixel(cg_image) != DesktopFrame::kBytesPerPixel * 8 || | 288 if (CGImageGetBitsPerPixel(cg_image) != DesktopFrame::kBytesPerPixel * 8 || |
| 275 CGImageGetWidth(cg_image) != static_cast<size_t>(size.width()) || | 289 CGImageGetWidth(cg_image) != static_cast<size_t>(size.width()) || |
| 276 CGImageGetBitsPerComponent(cg_image) != 8) { | 290 CGImageGetBitsPerComponent(cg_image) != 8) { |
| 291 if (scaled_cg_image != nil) CGImageRelease(scaled_cg_image); |
| 277 return; | 292 return; |
| 278 } | 293 } |
| 279 | 294 |
| 280 CGDataProviderRef provider = CGImageGetDataProvider(cg_image); | 295 CGDataProviderRef provider = CGImageGetDataProvider(cg_image); |
| 281 CFDataRef image_data_ref = CGDataProviderCopyData(provider); | 296 CFDataRef image_data_ref = CGDataProviderCopyData(provider); |
| 282 if (image_data_ref == NULL) | 297 if (image_data_ref == NULL) { |
| 298 if (scaled_cg_image != nil) CGImageRelease(scaled_cg_image); |
| 283 return; | 299 return; |
| 300 } |
| 284 | 301 |
| 285 const uint8_t* src_data = | 302 const uint8_t* src_data = |
| 286 reinterpret_cast<const uint8_t*>(CFDataGetBytePtr(image_data_ref)); | 303 reinterpret_cast<const uint8_t*>(CFDataGetBytePtr(image_data_ref)); |
| 287 | 304 |
| 288 // Compare the cursor with the previous one. | |
| 289 if (last_cursor_.get() && | |
| 290 last_cursor_->image()->size().equals(size) && | |
| 291 last_cursor_->hotspot().equals(hotspot) && | |
| 292 memcmp(last_cursor_->image()->data(), src_data, | |
| 293 last_cursor_->image()->stride() * size.height()) == 0) { | |
| 294 CFRelease(image_data_ref); | |
| 295 return; | |
| 296 } | |
| 297 | |
| 298 // Create a MouseCursor that describes the cursor and pass it to | 305 // Create a MouseCursor that describes the cursor and pass it to |
| 299 // the client. | 306 // the client. |
| 300 std::unique_ptr<DesktopFrame> image( | 307 std::unique_ptr<DesktopFrame> image( |
| 301 new BasicDesktopFrame(DesktopSize(size.width(), size.height()))); | 308 new BasicDesktopFrame(DesktopSize(size.width(), size.height()))); |
| 302 | 309 |
| 303 int src_stride = CGImageGetBytesPerRow(cg_image); | 310 int src_stride = CGImageGetBytesPerRow(cg_image); |
| 304 image->CopyPixelsFrom(src_data, src_stride, DesktopRect::MakeSize(size)); | 311 image->CopyPixelsFrom(src_data, src_stride, DesktopRect::MakeSize(size)); |
| 305 | 312 |
| 306 CFRelease(image_data_ref); | 313 CFRelease(image_data_ref); |
| 314 if (scaled_cg_image != nil) CGImageRelease(scaled_cg_image); |
| 307 | 315 |
| 308 std::unique_ptr<MouseCursor> cursor( | 316 std::unique_ptr<MouseCursor> cursor( |
| 309 new MouseCursor(image.release(), hotspot)); | 317 new MouseCursor(image.release(), hotspot)); |
| 310 last_cursor_.reset(MouseCursor::CopyOf(*cursor)); | |
| 311 | 318 |
| 312 callback_->OnMouseCursor(cursor.release()); | 319 callback_->OnMouseCursor(cursor.release()); |
| 313 } | 320 } |
| 314 | 321 |
| 315 MouseCursorMonitor* MouseCursorMonitor::CreateForWindow( | 322 MouseCursorMonitor* MouseCursorMonitor::CreateForWindow( |
| 316 const DesktopCaptureOptions& options, WindowId window) { | 323 const DesktopCaptureOptions& options, WindowId window) { |
| 317 return new MouseCursorMonitorMac(options, window, kInvalidScreenId); | 324 return new MouseCursorMonitorMac(options, window, kInvalidScreenId); |
| 318 } | 325 } |
| 319 | 326 |
| 320 MouseCursorMonitor* MouseCursorMonitor::CreateForScreen( | 327 MouseCursorMonitor* MouseCursorMonitor::CreateForScreen( |
| 321 const DesktopCaptureOptions& options, | 328 const DesktopCaptureOptions& options, |
| 322 ScreenId screen) { | 329 ScreenId screen) { |
| 323 return new MouseCursorMonitorMac(options, kCGNullWindowID, screen); | 330 return new MouseCursorMonitorMac(options, kCGNullWindowID, screen); |
| 324 } | 331 } |
| 325 | 332 |
| 326 } // namespace webrtc | 333 } // namespace webrtc |
| OLD | NEW |