Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(929)

Side by Side Diff: webrtc/modules/desktop_capture/mouse_cursor_monitor_mac.mm

Issue 2350743003: Bug Fix: Mac Retina Screen Capture's Mouse Cursor Too Small (Closed)
Patch Set: Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698