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

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: No round Created 4 years, 2 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 | « webrtc/modules/desktop_capture/desktop_frame.cc ('k') | 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 // 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
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
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
OLDNEW
« no previous file with comments | « webrtc/modules/desktop_capture/desktop_frame.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698