| 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 #include "webrtc/system_wrappers/include/logging.h" | 29 #include "webrtc/system_wrappers/include/logging.h" |
| 30 | 30 |
| 31 namespace webrtc { | 31 namespace webrtc { |
| 32 | 32 |
| 33 namespace { |
| 34 // Paint the image, so that we can get a bitmap representation compatible with |
| 35 // current context. For example, in the retina display, we are going to get an |
| 36 // image with same visual size but underlying pixel size conforms to the retina |
| 37 // setting. |
| 38 NSImage* PaintInCurrentContext(NSImage* source) { |
| 39 NSSize size = [source size]; |
| 40 NSImage* new_image = [[[NSImage alloc] initWithSize:size] autorelease]; |
| 41 [new_image lockFocus]; |
| 42 NSRect frame = NSMakeRect(0, 0, size.width, size.height); |
| 43 [source drawInRect:frame |
| 44 fromRect:frame |
| 45 operation:NSCompositeCopy |
| 46 fraction:1.0]; |
| 47 [new_image unlockFocus]; |
| 48 return new_image; |
| 49 } |
| 50 } // namespace |
| 51 |
| 33 class MouseCursorMonitorMac : public MouseCursorMonitor { | 52 class MouseCursorMonitorMac : public MouseCursorMonitor { |
| 34 public: | 53 public: |
| 35 MouseCursorMonitorMac(const DesktopCaptureOptions& options, | 54 MouseCursorMonitorMac(const DesktopCaptureOptions& options, |
| 36 CGWindowID window_id, | 55 CGWindowID window_id, |
| 37 ScreenId screen_id); | 56 ScreenId screen_id); |
| 38 virtual ~MouseCursorMonitorMac(); | 57 virtual ~MouseCursorMonitorMac(); |
| 39 | 58 |
| 40 void Init(Callback* callback, Mode mode) override; | 59 void Init(Callback* callback, Mode mode) override; |
| 41 void Capture() override; | 60 void Capture() override; |
| 42 | 61 |
| 43 private: | 62 private: |
| 44 static void DisplaysReconfiguredCallback(CGDirectDisplayID display, | 63 static void DisplaysReconfiguredCallback(CGDirectDisplayID display, |
| 45 CGDisplayChangeSummaryFlags flags, | 64 CGDisplayChangeSummaryFlags flags, |
| 46 void *user_parameter); | 65 void *user_parameter); |
| 47 void DisplaysReconfigured(CGDirectDisplayID display, | 66 void DisplaysReconfigured(CGDirectDisplayID display, |
| 48 CGDisplayChangeSummaryFlags flags); | 67 CGDisplayChangeSummaryFlags flags); |
| 49 | 68 |
| 50 void CaptureImage(); | 69 void CaptureImage(float scale); |
| 51 | 70 |
| 52 rtc::scoped_refptr<DesktopConfigurationMonitor> configuration_monitor_; | 71 rtc::scoped_refptr<DesktopConfigurationMonitor> configuration_monitor_; |
| 53 CGWindowID window_id_; | 72 CGWindowID window_id_; |
| 54 ScreenId screen_id_; | 73 ScreenId screen_id_; |
| 55 Callback* callback_; | 74 Callback* callback_; |
| 56 Mode mode_; | 75 Mode mode_; |
| 57 std::unique_ptr<MouseCursor> last_cursor_; | 76 std::unique_ptr<MouseCursor> last_cursor_; |
| 58 rtc::scoped_refptr<FullScreenChromeWindowDetector> | 77 rtc::scoped_refptr<FullScreenChromeWindowDetector> |
| 59 full_screen_chrome_window_detector_; | 78 full_screen_chrome_window_detector_; |
| 60 }; | 79 }; |
| (...skipping 23 matching lines...) Expand all Loading... |
| 84 assert(!callback_); | 103 assert(!callback_); |
| 85 assert(callback); | 104 assert(callback); |
| 86 | 105 |
| 87 callback_ = callback; | 106 callback_ = callback; |
| 88 mode_ = mode; | 107 mode_ = mode; |
| 89 } | 108 } |
| 90 | 109 |
| 91 void MouseCursorMonitorMac::Capture() { | 110 void MouseCursorMonitorMac::Capture() { |
| 92 assert(callback_); | 111 assert(callback_); |
| 93 | 112 |
| 94 CaptureImage(); | |
| 95 | |
| 96 if (mode_ != SHAPE_AND_POSITION) | |
| 97 return; | |
| 98 | |
| 99 CursorState state = INSIDE; | 113 CursorState state = INSIDE; |
| 100 | 114 |
| 101 CGEventRef event = CGEventCreate(NULL); | 115 CGEventRef event = CGEventCreate(NULL); |
| 102 CGPoint gc_position = CGEventGetLocation(event); | 116 CGPoint gc_position = CGEventGetLocation(event); |
| 103 CFRelease(event); | 117 CFRelease(event); |
| 104 | 118 |
| 105 DesktopVector position(gc_position.x, gc_position.y); | 119 DesktopVector position(gc_position.x, gc_position.y); |
| 106 | 120 |
| 107 configuration_monitor_->Lock(); | 121 configuration_monitor_->Lock(); |
| 108 MacDesktopConfiguration configuration = | 122 MacDesktopConfiguration configuration = |
| 109 configuration_monitor_->desktop_configuration(); | 123 configuration_monitor_->desktop_configuration(); |
| 110 configuration_monitor_->Unlock(); | 124 configuration_monitor_->Unlock(); |
| 111 float scale = 1.0f; | 125 float scale = 1.0f; |
| 112 | 126 |
| 113 // Find the dpi to physical pixel scale for the screen where the mouse cursor | 127 // Find the dpi to physical pixel scale for the screen where the mouse cursor |
| 114 // is. | 128 // is. |
| 115 for (MacDisplayConfigurations::iterator it = configuration.displays.begin(); | 129 for (MacDisplayConfigurations::iterator it = configuration.displays.begin(); |
| 116 it != configuration.displays.end(); ++it) { | 130 it != configuration.displays.end(); ++it) { |
| 117 if (it->bounds.Contains(position)) { | 131 if (it->bounds.Contains(position)) { |
| 118 scale = it->dip_to_pixel_scale; | 132 scale = it->dip_to_pixel_scale; |
| 119 break; | 133 break; |
| 120 } | 134 } |
| 121 } | 135 } |
| 136 |
| 137 CaptureImage(scale); |
| 138 |
| 139 if (mode_ != SHAPE_AND_POSITION) |
| 140 return; |
| 141 |
| 122 // If we are capturing cursor for a specific window then we need to figure out | 142 // If we are capturing cursor for a specific window then we need to figure out |
| 123 // if the current mouse position is covered by another window and also adjust | 143 // if the current mouse position is covered by another window and also adjust |
| 124 // |position| to make it relative to the window origin. | 144 // |position| to make it relative to the window origin. |
| 125 if (window_id_ != kCGNullWindowID) { | 145 if (window_id_ != kCGNullWindowID) { |
| 126 CGWindowID on_screen_window = window_id_; | 146 CGWindowID on_screen_window = window_id_; |
| 127 if (full_screen_chrome_window_detector_) { | 147 if (full_screen_chrome_window_detector_) { |
| 128 CGWindowID full_screen_window = | 148 CGWindowID full_screen_window = |
| 129 full_screen_chrome_window_detector_->FindFullScreenWindow(window_id_); | 149 full_screen_chrome_window_detector_->FindFullScreenWindow(window_id_); |
| 130 | 150 |
| 131 if (full_screen_window != kCGNullWindowID) | 151 if (full_screen_window != kCGNullWindowID) |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 221 } | 241 } |
| 222 } | 242 } |
| 223 if (state == INSIDE) { | 243 if (state == INSIDE) { |
| 224 // Convert Density Independent Pixel to physical pixel. | 244 // Convert Density Independent Pixel to physical pixel. |
| 225 position = DesktopVector(round(position.x() * scale), | 245 position = DesktopVector(round(position.x() * scale), |
| 226 round(position.y() * scale)); | 246 round(position.y() * scale)); |
| 227 } | 247 } |
| 228 callback_->OnMouseCursorPosition(state, position); | 248 callback_->OnMouseCursorPosition(state, position); |
| 229 } | 249 } |
| 230 | 250 |
| 231 void MouseCursorMonitorMac::CaptureImage() { | 251 void MouseCursorMonitorMac::CaptureImage(float scale) { |
| 232 NSCursor* nscursor = [NSCursor currentSystemCursor]; | 252 NSCursor* nscursor = [NSCursor currentSystemCursor]; |
| 233 | 253 |
| 234 NSImage* nsimage = [nscursor image]; | 254 NSImage* nsimage = [nscursor image]; |
| 235 NSSize nssize = [nsimage size]; | 255 NSSize nssize = [nsimage size]; // DIP size |
| 236 DesktopSize size(nssize.width, nssize.height); | 256 |
| 257 // For retina screen, we need to paint the cursor in current graphic context |
| 258 // to get retina representation. |
| 259 if (scale != 1.0) |
| 260 nsimage = PaintInCurrentContext(nsimage); |
| 261 |
| 262 DesktopSize size(round(nssize.width * scale), |
| 263 round(nssize.height * scale)); // Pixel size |
| 237 NSPoint nshotspot = [nscursor hotSpot]; | 264 NSPoint nshotspot = [nscursor hotSpot]; |
| 238 DesktopVector hotspot( | 265 DesktopVector hotspot( |
| 239 std::max(0, std::min(size.width(), static_cast<int>(nshotspot.x))), | 266 std::max(0, |
| 240 std::max(0, std::min(size.height(), static_cast<int>(nshotspot.y)))); | 267 std::min(size.width(), static_cast<int>(nshotspot.x * scale))), |
| 268 std::max(0, |
| 269 std::min(size.height(), static_cast<int>(nshotspot.y * scale)))); |
| 241 CGImageRef cg_image = | 270 CGImageRef cg_image = |
| 242 [nsimage CGImageForProposedRect:NULL context:nil hints:nil]; | 271 [nsimage CGImageForProposedRect:NULL context:nil hints:nil]; |
| 243 if (!cg_image) | 272 if (!cg_image) |
| 244 return; | 273 return; |
| 245 | 274 |
| 246 if (CGImageGetBitsPerPixel(cg_image) != DesktopFrame::kBytesPerPixel * 8 || | 275 if (CGImageGetBitsPerPixel(cg_image) != DesktopFrame::kBytesPerPixel * 8 || |
| 247 CGImageGetBytesPerRow(cg_image) != | 276 CGImageGetWidth(cg_image) != static_cast<size_t>(size.width()) || |
| 248 static_cast<size_t>(DesktopFrame::kBytesPerPixel * size.width()) || | |
| 249 CGImageGetBitsPerComponent(cg_image) != 8) { | 277 CGImageGetBitsPerComponent(cg_image) != 8) { |
| 250 return; | 278 return; |
| 251 } | 279 } |
| 252 | 280 |
| 253 CGDataProviderRef provider = CGImageGetDataProvider(cg_image); | 281 CGDataProviderRef provider = CGImageGetDataProvider(cg_image); |
| 254 CFDataRef image_data_ref = CGDataProviderCopyData(provider); | 282 CFDataRef image_data_ref = CGDataProviderCopyData(provider); |
| 255 if (image_data_ref == NULL) | 283 if (image_data_ref == NULL) |
| 256 return; | 284 return; |
| 257 | 285 |
| 258 const uint8_t* src_data = | 286 const uint8_t* src_data = |
| 259 reinterpret_cast<const uint8_t*>(CFDataGetBytePtr(image_data_ref)); | 287 reinterpret_cast<const uint8_t*>(CFDataGetBytePtr(image_data_ref)); |
| 260 | 288 |
| 261 // Compare the cursor with the previous one. | 289 // Compare the cursor with the previous one. |
| 262 if (last_cursor_.get() && | 290 if (last_cursor_.get() && |
| 263 last_cursor_->image()->size().equals(size) && | 291 last_cursor_->image()->size().equals(size) && |
| 264 last_cursor_->hotspot().equals(hotspot) && | 292 last_cursor_->hotspot().equals(hotspot) && |
| 265 memcmp(last_cursor_->image()->data(), src_data, | 293 memcmp(last_cursor_->image()->data(), src_data, |
| 266 last_cursor_->image()->stride() * size.height()) == 0) { | 294 last_cursor_->image()->stride() * size.height()) == 0) { |
| 267 CFRelease(image_data_ref); | 295 CFRelease(image_data_ref); |
| 268 return; | 296 return; |
| 269 } | 297 } |
| 270 | 298 |
| 271 // Create a MouseCursor that describes the cursor and pass it to | 299 // Create a MouseCursor that describes the cursor and pass it to |
| 272 // the client. | 300 // the client. |
| 273 std::unique_ptr<DesktopFrame> image( | 301 std::unique_ptr<DesktopFrame> image( |
| 274 new BasicDesktopFrame(DesktopSize(size.width(), size.height()))); | 302 new BasicDesktopFrame(DesktopSize(size.width(), size.height()))); |
| 275 memcpy(image->data(), src_data, | 303 |
| 276 size.width() * size.height() * DesktopFrame::kBytesPerPixel); | 304 int src_stride = CGImageGetBytesPerRow(cg_image); |
| 305 image->CopyPixelsFrom(src_data, src_stride, DesktopRect::MakeSize(size)); |
| 277 | 306 |
| 278 CFRelease(image_data_ref); | 307 CFRelease(image_data_ref); |
| 279 | 308 |
| 280 std::unique_ptr<MouseCursor> cursor( | 309 std::unique_ptr<MouseCursor> cursor( |
| 281 new MouseCursor(image.release(), hotspot)); | 310 new MouseCursor(image.release(), hotspot)); |
| 282 last_cursor_.reset(MouseCursor::CopyOf(*cursor)); | 311 last_cursor_.reset(MouseCursor::CopyOf(*cursor)); |
| 283 | 312 |
| 284 callback_->OnMouseCursor(cursor.release()); | 313 callback_->OnMouseCursor(cursor.release()); |
| 285 } | 314 } |
| 286 | 315 |
| 287 MouseCursorMonitor* MouseCursorMonitor::CreateForWindow( | 316 MouseCursorMonitor* MouseCursorMonitor::CreateForWindow( |
| 288 const DesktopCaptureOptions& options, WindowId window) { | 317 const DesktopCaptureOptions& options, WindowId window) { |
| 289 return new MouseCursorMonitorMac(options, window, kInvalidScreenId); | 318 return new MouseCursorMonitorMac(options, window, kInvalidScreenId); |
| 290 } | 319 } |
| 291 | 320 |
| 292 MouseCursorMonitor* MouseCursorMonitor::CreateForScreen( | 321 MouseCursorMonitor* MouseCursorMonitor::CreateForScreen( |
| 293 const DesktopCaptureOptions& options, | 322 const DesktopCaptureOptions& options, |
| 294 ScreenId screen) { | 323 ScreenId screen) { |
| 295 return new MouseCursorMonitorMac(options, kCGNullWindowID, screen); | 324 return new MouseCursorMonitorMac(options, kCGNullWindowID, screen); |
| 296 } | 325 } |
| 297 | 326 |
| 298 } // namespace webrtc | 327 } // namespace webrtc |
| OLD | NEW |