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