Bug Fix: Mac Retina Screen Capture's Mouse Cursor Too Small
On retina display, when we do screen capture, the mouse cursor looks too small. The reason is that we painted the cursor with low resolution on to the frame directly. This CL fixes the bug. BUG=632995 Review-Url: https://codereview.webrtc.org/2350743003 Cr-Commit-Position: refs/heads/master@{#14340}
This commit is contained in:
parent
e35d329315
commit
6f79d840ba
@ -31,7 +31,7 @@ DesktopFrame::DesktopFrame(DesktopSize size,
|
||||
|
||||
DesktopFrame::~DesktopFrame() {}
|
||||
|
||||
void DesktopFrame::CopyPixelsFrom(uint8_t* src_buffer, int src_stride,
|
||||
void DesktopFrame::CopyPixelsFrom(const uint8_t* src_buffer, int src_stride,
|
||||
const DesktopRect& dest_rect) {
|
||||
RTC_CHECK(DesktopRect::MakeSize(size()).ContainsRect(dest_rect));
|
||||
|
||||
|
||||
@ -58,7 +58,7 @@ class DesktopFrame {
|
||||
|
||||
// Copies pixels from a buffer or another frame. |dest_rect| rect must lay
|
||||
// within bounds of this frame.
|
||||
void CopyPixelsFrom(uint8_t* src_buffer,
|
||||
void CopyPixelsFrom(const uint8_t* src_buffer,
|
||||
int src_stride,
|
||||
const DesktopRect& dest_rect);
|
||||
void CopyPixelsFrom(const DesktopFrame& src_frame,
|
||||
|
||||
@ -30,6 +30,25 @@
|
||||
|
||||
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] autorelease];
|
||||
[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;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
class MouseCursorMonitorMac : public MouseCursorMonitor {
|
||||
public:
|
||||
MouseCursorMonitorMac(const DesktopCaptureOptions& options,
|
||||
@ -47,7 +66,7 @@ class MouseCursorMonitorMac : public MouseCursorMonitor {
|
||||
void DisplaysReconfigured(CGDirectDisplayID display,
|
||||
CGDisplayChangeSummaryFlags flags);
|
||||
|
||||
void CaptureImage();
|
||||
void CaptureImage(float scale);
|
||||
|
||||
rtc::scoped_refptr<DesktopConfigurationMonitor> configuration_monitor_;
|
||||
CGWindowID window_id_;
|
||||
@ -91,11 +110,6 @@ void MouseCursorMonitorMac::Init(Callback* callback, Mode mode) {
|
||||
void MouseCursorMonitorMac::Capture() {
|
||||
assert(callback_);
|
||||
|
||||
CaptureImage();
|
||||
|
||||
if (mode_ != SHAPE_AND_POSITION)
|
||||
return;
|
||||
|
||||
CursorState state = INSIDE;
|
||||
|
||||
CGEventRef event = CGEventCreate(NULL);
|
||||
@ -113,12 +127,18 @@ void MouseCursorMonitorMac::Capture() {
|
||||
// Find the dpi to physical pixel scale for the screen where the mouse cursor
|
||||
// is.
|
||||
for (MacDisplayConfigurations::iterator it = configuration.displays.begin();
|
||||
it != configuration.displays.end(); ++it) {
|
||||
it != configuration.displays.end(); ++it) {
|
||||
if (it->bounds.Contains(position)) {
|
||||
scale = it->dip_to_pixel_scale;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CaptureImage(scale);
|
||||
|
||||
if (mode_ != SHAPE_AND_POSITION)
|
||||
return;
|
||||
|
||||
// If we are capturing cursor for a specific window then we need to figure out
|
||||
// if the current mouse position is covered by another window and also adjust
|
||||
// |position| to make it relative to the window origin.
|
||||
@ -228,24 +248,32 @@ void MouseCursorMonitorMac::Capture() {
|
||||
callback_->OnMouseCursorPosition(state, position);
|
||||
}
|
||||
|
||||
void MouseCursorMonitorMac::CaptureImage() {
|
||||
void MouseCursorMonitorMac::CaptureImage(float scale) {
|
||||
NSCursor* nscursor = [NSCursor currentSystemCursor];
|
||||
|
||||
NSImage* nsimage = [nscursor image];
|
||||
NSSize nssize = [nsimage size];
|
||||
DesktopSize size(nssize.width, nssize.height);
|
||||
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);
|
||||
|
||||
DesktopSize size(round(nssize.width * scale),
|
||||
round(nssize.height * scale)); // Pixel size
|
||||
NSPoint nshotspot = [nscursor hotSpot];
|
||||
DesktopVector hotspot(
|
||||
std::max(0, std::min(size.width(), static_cast<int>(nshotspot.x))),
|
||||
std::max(0, std::min(size.height(), static_cast<int>(nshotspot.y))));
|
||||
std::max(0,
|
||||
std::min(size.width(), static_cast<int>(nshotspot.x * scale))),
|
||||
std::max(0,
|
||||
std::min(size.height(), static_cast<int>(nshotspot.y * scale))));
|
||||
CGImageRef cg_image =
|
||||
[nsimage CGImageForProposedRect:NULL context:nil hints:nil];
|
||||
if (!cg_image)
|
||||
return;
|
||||
|
||||
if (CGImageGetBitsPerPixel(cg_image) != DesktopFrame::kBytesPerPixel * 8 ||
|
||||
CGImageGetBytesPerRow(cg_image) !=
|
||||
static_cast<size_t>(DesktopFrame::kBytesPerPixel * size.width()) ||
|
||||
CGImageGetWidth(cg_image) != static_cast<size_t>(size.width()) ||
|
||||
CGImageGetBitsPerComponent(cg_image) != 8) {
|
||||
return;
|
||||
}
|
||||
@ -272,8 +300,9 @@ void MouseCursorMonitorMac::CaptureImage() {
|
||||
// the client.
|
||||
std::unique_ptr<DesktopFrame> image(
|
||||
new BasicDesktopFrame(DesktopSize(size.width(), size.height())));
|
||||
memcpy(image->data(), src_data,
|
||||
size.width() * size.height() * DesktopFrame::kBytesPerPixel);
|
||||
|
||||
int src_stride = CGImageGetBytesPerRow(cg_image);
|
||||
image->CopyPixelsFrom(src_data, src_stride, DesktopRect::MakeSize(size));
|
||||
|
||||
CFRelease(image_data_ref);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user