desktopCapture: scale the cursor image according to screen scale factor on OSX
Before 10.12, OSX may report 1X cursor on Retina screen. (See crbug.com/632995.) After 10.12, OSX may report 2X cursor on non-Retina screen. (See crbug.com/671436.) So scaling the cursor if the image size doesn't meet the expected size on either Retina or non-Retina screen. Also corrects the cursor caching and change detection, so we can only do scalingat cursor changing for better performance. As to screen capture on OSX, the captured frame already contains the current cursor. So the MouseCursorMonitorMac is not needed for ScreenCapture for performance purpose. BUG=671436 Review-Url: https://codereview.webrtc.org/2908853002 Cr-Commit-Position: refs/heads/master@{#18393}
This commit is contained in:
parent
8e857d10fd
commit
0d1e27f00f
@ -30,21 +30,26 @@
|
||||
namespace webrtc {
|
||||
|
||||
namespace {
|
||||
// Paint the image, so that we can get a bitmap representation compatible with
|
||||
// current context. For example, in the retina display, we are going to get an
|
||||
// image with same visual size but underlying pixel size conforms to the retina
|
||||
// setting.
|
||||
NSImage* PaintInCurrentContext(NSImage* source) {
|
||||
NSSize size = [source size];
|
||||
NSImage* new_image = [[NSImage alloc] initWithSize:size];
|
||||
[new_image lockFocus];
|
||||
NSRect frame = NSMakeRect(0, 0, size.width, size.height);
|
||||
[source drawInRect:frame
|
||||
fromRect:frame
|
||||
operation:NSCompositeCopy
|
||||
fraction:1.0];
|
||||
[new_image unlockFocus];
|
||||
return new_image;
|
||||
CGImageRef CreateScaledCGImage(CGImageRef image, int width, int height) {
|
||||
// Create context, keeping original image properties.
|
||||
CGColorSpaceRef colorspace = CGImageGetColorSpace(image);
|
||||
CGContextRef context = CGBitmapContextCreate(nullptr,
|
||||
width,
|
||||
height,
|
||||
CGImageGetBitsPerComponent(image),
|
||||
width * DesktopFrame::kBytesPerPixel,
|
||||
colorspace,
|
||||
CGImageGetBitmapInfo(image));
|
||||
|
||||
if (!context) return nil;
|
||||
|
||||
// Draw image to context, resizing it.
|
||||
CGContextDrawImage(context, CGRectMake(0, 0, width, height), image);
|
||||
// Extract resulting image from context.
|
||||
CGImageRef imgRef = CGBitmapContextCreateImage(context);
|
||||
CGContextRelease(context);
|
||||
|
||||
return imgRef;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
@ -72,7 +77,7 @@ class MouseCursorMonitorMac : public MouseCursorMonitor {
|
||||
ScreenId screen_id_;
|
||||
Callback* callback_;
|
||||
Mode mode_;
|
||||
std::unique_ptr<MouseCursor> last_cursor_;
|
||||
__strong NSImage* last_cursor_;
|
||||
rtc::scoped_refptr<FullScreenChromeWindowDetector>
|
||||
full_screen_chrome_window_detector_;
|
||||
};
|
||||
@ -253,10 +258,9 @@ void MouseCursorMonitorMac::CaptureImage(float scale) {
|
||||
NSImage* nsimage = [nscursor image];
|
||||
NSSize nssize = [nsimage size]; // DIP size
|
||||
|
||||
// For retina screen, we need to paint the cursor in current graphic context
|
||||
// to get retina representation.
|
||||
if (scale != 1.0)
|
||||
nsimage = PaintInCurrentContext(nsimage);
|
||||
// No need to caputre cursor image if it's unchanged since last capture.
|
||||
if ([[nsimage TIFFRepresentation] isEqual:[last_cursor_ TIFFRepresentation]]) return;
|
||||
last_cursor_ = nsimage;
|
||||
|
||||
DesktopSize size(round(nssize.width * scale),
|
||||
round(nssize.height * scale)); // Pixel size
|
||||
@ -271,30 +275,33 @@ void MouseCursorMonitorMac::CaptureImage(float scale) {
|
||||
if (!cg_image)
|
||||
return;
|
||||
|
||||
// Before 10.12, OSX may report 1X cursor on Retina screen. (See
|
||||
// crbug.com/632995.) After 10.12, OSX may report 2X cursor on non-Retina
|
||||
// screen. (See crbug.com/671436.) So scaling the cursor if needed.
|
||||
CGImageRef scaled_cg_image = nil;
|
||||
if (CGImageGetWidth(cg_image) != static_cast<size_t>(size.width())) {
|
||||
scaled_cg_image = CreateScaledCGImage(cg_image, size.width(), size.height());
|
||||
if (scaled_cg_image != nil) {
|
||||
cg_image = scaled_cg_image;
|
||||
}
|
||||
}
|
||||
if (CGImageGetBitsPerPixel(cg_image) != DesktopFrame::kBytesPerPixel * 8 ||
|
||||
CGImageGetWidth(cg_image) != static_cast<size_t>(size.width()) ||
|
||||
CGImageGetBitsPerComponent(cg_image) != 8) {
|
||||
if (scaled_cg_image != nil) CGImageRelease(scaled_cg_image);
|
||||
return;
|
||||
}
|
||||
|
||||
CGDataProviderRef provider = CGImageGetDataProvider(cg_image);
|
||||
CFDataRef image_data_ref = CGDataProviderCopyData(provider);
|
||||
if (image_data_ref == NULL)
|
||||
if (image_data_ref == NULL) {
|
||||
if (scaled_cg_image != nil) CGImageRelease(scaled_cg_image);
|
||||
return;
|
||||
}
|
||||
|
||||
const uint8_t* src_data =
|
||||
reinterpret_cast<const uint8_t*>(CFDataGetBytePtr(image_data_ref));
|
||||
|
||||
// Compare the cursor with the previous one.
|
||||
if (last_cursor_.get() &&
|
||||
last_cursor_->image()->size().equals(size) &&
|
||||
last_cursor_->hotspot().equals(hotspot) &&
|
||||
memcmp(last_cursor_->image()->data(), src_data,
|
||||
last_cursor_->image()->stride() * size.height()) == 0) {
|
||||
CFRelease(image_data_ref);
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a MouseCursor that describes the cursor and pass it to
|
||||
// the client.
|
||||
std::unique_ptr<DesktopFrame> image(
|
||||
@ -304,10 +311,10 @@ void MouseCursorMonitorMac::CaptureImage(float scale) {
|
||||
image->CopyPixelsFrom(src_data, src_stride, DesktopRect::MakeSize(size));
|
||||
|
||||
CFRelease(image_data_ref);
|
||||
if (scaled_cg_image != nil) CGImageRelease(scaled_cg_image);
|
||||
|
||||
std::unique_ptr<MouseCursor> cursor(
|
||||
new MouseCursor(image.release(), hotspot));
|
||||
last_cursor_.reset(MouseCursor::CopyOf(*cursor));
|
||||
|
||||
callback_->OnMouseCursor(cursor.release());
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user