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 |