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

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

Issue 2908853002: desktopCapture: scale the cursor image according to screen scale factor on OSX (Closed)
Patch Set: address comments Created 3 years, 6 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 29
30 namespace webrtc { 30 namespace webrtc {
31 31
32 namespace { 32 namespace {
33 // Paint the image, so that we can get a bitmap representation compatible with 33 CGImageRef CreateScaledCGImage(CGImageRef image, int width, int height) {
34 // current context. For example, in the retina display, we are going to get an 34 // create context, keeping original image properties
35 // image with same visual size but underlying pixel size conforms to the retina 35 CGColorSpaceRef colorspace = CGImageGetColorSpace(image);
36 // setting. 36 CGContextRef context =
37 NSImage* PaintInCurrentContext(NSImage* source) { 37 CGBitmapContextCreate(NULL,
Do not use (sergeyu) 2017/06/01 00:22:00 s/NULL/nullptr/
braveyao1 2017/06/01 17:50:14 Done.
38 NSSize size = [source size]; 38 width,
Do not use (sergeyu) 2017/06/01 00:22:00 Please run 'git cl format'. It should format this
braveyao1 2017/06/01 17:50:14 Actually I tried to run "git cl format" before fil
Do not use (sergeyu) 2017/06/01 18:08:08 That's by design. Style guide for ObjC allows 100-
braveyao1 2017/06/01 18:17:56 Done. I think 'git cl format' won't be wrong. :)
39 NSImage* new_image = [[NSImage alloc] initWithSize:size]; 39 height,
40 [new_image lockFocus]; 40 CGImageGetBitsPerComponent(image),
41 NSRect frame = NSMakeRect(0, 0, size.width, size.height); 41 width * 4,
Do not use (sergeyu) 2017/06/01 00:22:00 width * DesktopFrame::kBytesPerPixel;
braveyao1 2017/06/01 17:50:14 Done.
42 [source drawInRect:frame 42 colorspace,
43 fromRect:frame 43 CGImageGetBitmapInfo(image));
44 operation:NSCompositeCopy 44
45 fraction:1.0]; 45 if (context == NULL) return nil;
Do not use (sergeyu) 2017/06/01 00:21:59 if (!context) return nil;
braveyao1 2017/06/01 17:50:14 Done.
46 [new_image unlockFocus]; 46
47 return new_image; 47 // draw image to context (resizing it)
Do not use (sergeyu) 2017/06/01 00:21:59 Please reformat this as follows: // Draw image t
braveyao1 2017/06/01 17:50:15 Done.
48 CGContextDrawImage(context, CGRectMake(0, 0, width, height), image);
49 // extract resulting image from context
Do not use (sergeyu) 2017/06/01 00:21:59 // Extract resulting image from context.
braveyao1 2017/06/01 17:50:14 Done.
50 CGImageRef imgRef = CGBitmapContextCreateImage(context);
51 CGContextRelease(context);
52
53 return imgRef;
48 } 54 }
49 } // namespace 55 } // namespace
50 56
51 class MouseCursorMonitorMac : public MouseCursorMonitor { 57 class MouseCursorMonitorMac : public MouseCursorMonitor {
52 public: 58 public:
53 MouseCursorMonitorMac(const DesktopCaptureOptions& options, 59 MouseCursorMonitorMac(const DesktopCaptureOptions& options,
54 CGWindowID window_id, 60 CGWindowID window_id,
55 ScreenId screen_id); 61 ScreenId screen_id);
56 ~MouseCursorMonitorMac() override; 62 ~MouseCursorMonitorMac() override;
57 63
58 void Init(Callback* callback, Mode mode) override; 64 void Init(Callback* callback, Mode mode) override;
59 void Capture() override; 65 void Capture() override;
60 66
61 private: 67 private:
62 static void DisplaysReconfiguredCallback(CGDirectDisplayID display, 68 static void DisplaysReconfiguredCallback(CGDirectDisplayID display,
63 CGDisplayChangeSummaryFlags flags, 69 CGDisplayChangeSummaryFlags flags,
64 void *user_parameter); 70 void *user_parameter);
65 void DisplaysReconfigured(CGDirectDisplayID display, 71 void DisplaysReconfigured(CGDirectDisplayID display,
66 CGDisplayChangeSummaryFlags flags); 72 CGDisplayChangeSummaryFlags flags);
67 73
68 void CaptureImage(float scale); 74 void CaptureImage(float scale);
69 75
70 rtc::scoped_refptr<DesktopConfigurationMonitor> configuration_monitor_; 76 rtc::scoped_refptr<DesktopConfigurationMonitor> configuration_monitor_;
71 CGWindowID window_id_; 77 CGWindowID window_id_;
72 ScreenId screen_id_; 78 ScreenId screen_id_;
73 Callback* callback_; 79 Callback* callback_;
74 Mode mode_; 80 Mode mode_;
75 std::unique_ptr<MouseCursor> last_cursor_; 81 __strong NSImage* last_cursor_;
76 rtc::scoped_refptr<FullScreenChromeWindowDetector> 82 rtc::scoped_refptr<FullScreenChromeWindowDetector>
77 full_screen_chrome_window_detector_; 83 full_screen_chrome_window_detector_;
78 }; 84 };
79 85
80 MouseCursorMonitorMac::MouseCursorMonitorMac( 86 MouseCursorMonitorMac::MouseCursorMonitorMac(
81 const DesktopCaptureOptions& options, 87 const DesktopCaptureOptions& options,
82 CGWindowID window_id, 88 CGWindowID window_id,
83 ScreenId screen_id) 89 ScreenId screen_id)
84 : configuration_monitor_(options.configuration_monitor()), 90 : configuration_monitor_(options.configuration_monitor()),
85 window_id_(window_id), 91 window_id_(window_id),
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after
246 } 252 }
247 callback_->OnMouseCursorPosition(state, position); 253 callback_->OnMouseCursorPosition(state, position);
248 } 254 }
249 255
250 void MouseCursorMonitorMac::CaptureImage(float scale) { 256 void MouseCursorMonitorMac::CaptureImage(float scale) {
251 NSCursor* nscursor = [NSCursor currentSystemCursor]; 257 NSCursor* nscursor = [NSCursor currentSystemCursor];
252 258
253 NSImage* nsimage = [nscursor image]; 259 NSImage* nsimage = [nscursor image];
254 NSSize nssize = [nsimage size]; // DIP size 260 NSSize nssize = [nsimage size]; // DIP size
255 261
256 // For retina screen, we need to paint the cursor in current graphic context 262 if ([[nsimage TIFFRepresentation] isEqual: [last_cursor_ TIFFRepresentation]])
Do not use (sergeyu) 2017/06/01 00:21:59 Add a comment, to make it clear clear what happens
braveyao1 2017/06/01 17:50:14 Done.
257 // to get retina representation. 263 return;
258 if (scale != 1.0) 264 last_cursor_ = nsimage;
259 nsimage = PaintInCurrentContext(nsimage);
260 265
261 DesktopSize size(round(nssize.width * scale), 266 DesktopSize size(round(nssize.width * scale),
262 round(nssize.height * scale)); // Pixel size 267 round(nssize.height * scale)); // Pixel size
263 NSPoint nshotspot = [nscursor hotSpot]; 268 NSPoint nshotspot = [nscursor hotSpot];
264 DesktopVector hotspot( 269 DesktopVector hotspot(
265 std::max(0, 270 std::max(0,
266 std::min(size.width(), static_cast<int>(nshotspot.x * scale))), 271 std::min(size.width(), static_cast<int>(nshotspot.x * scale))),
267 std::max(0, 272 std::max(0,
268 std::min(size.height(), static_cast<int>(nshotspot.y * scale)))); 273 std::min(size.height(), static_cast<int>(nshotspot.y * scale))));
269 CGImageRef cg_image = 274 CGImageRef cg_image =
270 [nsimage CGImageForProposedRect:NULL context:nil hints:nil]; 275 [nsimage CGImageForProposedRect:NULL context:nil hints:nil];
271 if (!cg_image) 276 if (!cg_image)
272 return; 277 return;
273 278
279 // Before 10.12, OSX may report 1X cursor on Retina screen. (See
280 // crbug.com/632995.) After 10.12, OSX may report 2X cursor on non-Retina
281 // screen. (See crbug.com/671436.) So scaling the cursor if needed.
282 CGImageRef scaled_cg_image = nil;
283 if (CGImageGetWidth(cg_image) != static_cast<size_t>(size.width())) {
284 scaled_cg_image =
285 CreateScaledCGImage(cg_image, size.width(), size.height());
286 if (scaled_cg_image != nil) {
287 cg_image = scaled_cg_image;
288 }
289 }
274 if (CGImageGetBitsPerPixel(cg_image) != DesktopFrame::kBytesPerPixel * 8 || 290 if (CGImageGetBitsPerPixel(cg_image) != DesktopFrame::kBytesPerPixel * 8 ||
275 CGImageGetWidth(cg_image) != static_cast<size_t>(size.width()) || 291 CGImageGetWidth(cg_image) != static_cast<size_t>(size.width()) ||
276 CGImageGetBitsPerComponent(cg_image) != 8) { 292 CGImageGetBitsPerComponent(cg_image) != 8) {
293 if (scaled_cg_image != nil) CGImageRelease(scaled_cg_image);
277 return; 294 return;
278 } 295 }
279 296
280 CGDataProviderRef provider = CGImageGetDataProvider(cg_image); 297 CGDataProviderRef provider = CGImageGetDataProvider(cg_image);
281 CFDataRef image_data_ref = CGDataProviderCopyData(provider); 298 CFDataRef image_data_ref = CGDataProviderCopyData(provider);
282 if (image_data_ref == NULL) 299 if (image_data_ref == NULL) {
300 if (scaled_cg_image != nil) CGImageRelease(scaled_cg_image);
283 return; 301 return;
302 }
284 303
285 const uint8_t* src_data = 304 const uint8_t* src_data =
286 reinterpret_cast<const uint8_t*>(CFDataGetBytePtr(image_data_ref)); 305 reinterpret_cast<const uint8_t*>(CFDataGetBytePtr(image_data_ref));
287 306
288 // Compare the cursor with the previous one.
289 if (last_cursor_.get() &&
290 last_cursor_->image()->size().equals(size) &&
291 last_cursor_->hotspot().equals(hotspot) &&
292 memcmp(last_cursor_->image()->data(), src_data,
293 last_cursor_->image()->stride() * size.height()) == 0) {
294 CFRelease(image_data_ref);
295 return;
296 }
297
298 // Create a MouseCursor that describes the cursor and pass it to 307 // Create a MouseCursor that describes the cursor and pass it to
299 // the client. 308 // the client.
300 std::unique_ptr<DesktopFrame> image( 309 std::unique_ptr<DesktopFrame> image(
301 new BasicDesktopFrame(DesktopSize(size.width(), size.height()))); 310 new BasicDesktopFrame(DesktopSize(size.width(), size.height())));
302 311
303 int src_stride = CGImageGetBytesPerRow(cg_image); 312 int src_stride = CGImageGetBytesPerRow(cg_image);
304 image->CopyPixelsFrom(src_data, src_stride, DesktopRect::MakeSize(size)); 313 image->CopyPixelsFrom(src_data, src_stride, DesktopRect::MakeSize(size));
305 314
306 CFRelease(image_data_ref); 315 CFRelease(image_data_ref);
316 if (scaled_cg_image != nil) CGImageRelease(scaled_cg_image);
307 317
308 std::unique_ptr<MouseCursor> cursor( 318 std::unique_ptr<MouseCursor> cursor(
309 new MouseCursor(image.release(), hotspot)); 319 new MouseCursor(image.release(), hotspot));
310 last_cursor_.reset(MouseCursor::CopyOf(*cursor));
311 320
312 callback_->OnMouseCursor(cursor.release()); 321 callback_->OnMouseCursor(cursor.release());
313 } 322 }
314 323
315 MouseCursorMonitor* MouseCursorMonitor::CreateForWindow( 324 MouseCursorMonitor* MouseCursorMonitor::CreateForWindow(
316 const DesktopCaptureOptions& options, WindowId window) { 325 const DesktopCaptureOptions& options, WindowId window) {
317 return new MouseCursorMonitorMac(options, window, kInvalidScreenId); 326 return new MouseCursorMonitorMac(options, window, kInvalidScreenId);
318 } 327 }
319 328
329 // ScreenCapture already contains current cursor in the captured frame on OSX.
Do not use (sergeyu) 2017/06/01 00:21:59 This is not the right place to fix this. This clas
braveyao1 2017/06/01 17:50:14 OK. Then a separated cl is needed. This is under W
320 MouseCursorMonitor* MouseCursorMonitor::CreateForScreen( 330 MouseCursorMonitor* MouseCursorMonitor::CreateForScreen(
321 const DesktopCaptureOptions& options, 331 const DesktopCaptureOptions& options,
322 ScreenId screen) { 332 ScreenId screen) {
323 return new MouseCursorMonitorMac(options, kCGNullWindowID, screen); 333 return nil;
324 } 334 }
325 335
326 } // namespace webrtc 336 } // 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