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 |