From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- .../desktop_capture/mouse_cursor_monitor_mac.mm | 213 +++++++++++++++++++++ 1 file changed, 213 insertions(+) create mode 100644 third_party/libwebrtc/modules/desktop_capture/mouse_cursor_monitor_mac.mm (limited to 'third_party/libwebrtc/modules/desktop_capture/mouse_cursor_monitor_mac.mm') diff --git a/third_party/libwebrtc/modules/desktop_capture/mouse_cursor_monitor_mac.mm b/third_party/libwebrtc/modules/desktop_capture/mouse_cursor_monitor_mac.mm new file mode 100644 index 0000000000..512103ab5e --- /dev/null +++ b/third_party/libwebrtc/modules/desktop_capture/mouse_cursor_monitor_mac.mm @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "modules/desktop_capture/mouse_cursor_monitor.h" + + +#include + +#include +#include +#include + +#include "api/scoped_refptr.h" +#include "modules/desktop_capture/desktop_capture_options.h" +#include "modules/desktop_capture/desktop_capture_types.h" +#include "modules/desktop_capture/desktop_frame.h" +#include "modules/desktop_capture/mac/desktop_configuration.h" +#include "modules/desktop_capture/mac/desktop_configuration_monitor.h" +#include "modules/desktop_capture/mac/window_list_utils.h" +#include "modules/desktop_capture/mouse_cursor.h" +#include "rtc_base/checks.h" + +namespace webrtc { + +namespace { +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 + +class MouseCursorMonitorMac : public MouseCursorMonitor { + public: + MouseCursorMonitorMac(const DesktopCaptureOptions& options, + CGWindowID window_id, + ScreenId screen_id); + ~MouseCursorMonitorMac() override; + + void Init(Callback* callback, Mode mode) override; + void Capture() override; + + private: + static void DisplaysReconfiguredCallback(CGDirectDisplayID display, + CGDisplayChangeSummaryFlags flags, + void *user_parameter); + void DisplaysReconfigured(CGDirectDisplayID display, + CGDisplayChangeSummaryFlags flags); + + void CaptureImage(float scale); + + rtc::scoped_refptr configuration_monitor_; + CGWindowID window_id_; + ScreenId screen_id_; + Callback* callback_ = NULL; + Mode mode_; + __strong NSImage* last_cursor_ = NULL; +}; + +MouseCursorMonitorMac::MouseCursorMonitorMac(const DesktopCaptureOptions& options, + CGWindowID window_id, + ScreenId screen_id) + : configuration_monitor_(options.configuration_monitor()), + window_id_(window_id), + screen_id_(screen_id), + mode_(SHAPE_AND_POSITION) { + RTC_DCHECK(window_id == kCGNullWindowID || screen_id == kInvalidScreenId); +} + +MouseCursorMonitorMac::~MouseCursorMonitorMac() {} + +void MouseCursorMonitorMac::Init(Callback* callback, Mode mode) { + RTC_DCHECK(!callback_); + RTC_DCHECK(callback); + + callback_ = callback; + mode_ = mode; +} + +void MouseCursorMonitorMac::Capture() { + RTC_DCHECK(callback_); + + CGEventRef event = CGEventCreate(NULL); + CGPoint gc_position = CGEventGetLocation(event); + CFRelease(event); + + DesktopVector position(gc_position.x, gc_position.y); + + MacDesktopConfiguration configuration = + configuration_monitor_->desktop_configuration(); + float scale = GetScaleFactorAtPosition(configuration, position); + + CaptureImage(scale); + + if (mode_ != SHAPE_AND_POSITION) + return; + + // Always report cursor position in DIP pixel. + callback_->OnMouseCursorPosition( + position.subtract(configuration.bounds.top_left())); +} + +void MouseCursorMonitorMac::CaptureImage(float scale) { + NSCursor* nscursor = [NSCursor currentSystemCursor]; + + NSImage* nsimage = [nscursor image]; + if (nsimage == nil || !nsimage.isValid) { + return; + } + NSSize nssize = [nsimage size]; // DIP size + + // No need to caputre cursor image if it's unchanged since last capture. + if (last_cursor_ && [[nsimage TIFFRepresentation] isEqual:[last_cursor_ TIFFRepresentation]]) return; + last_cursor_ = 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(nshotspot.x * scale))), + std::max(0, + std::min(size.height(), static_cast(nshotspot.y * scale)))); + CGImageRef cg_image = + [nsimage CGImageForProposedRect:NULL context:nil hints:nil]; + 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.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.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 (scaled_cg_image != nil) CGImageRelease(scaled_cg_image); + return; + } + + const uint8_t* src_data = + reinterpret_cast(CFDataGetBytePtr(image_data_ref)); + + // Create a MouseCursor that describes the cursor and pass it to + // the client. + std::unique_ptr image( + new BasicDesktopFrame(DesktopSize(size.width(), size.height()))); + + int src_stride = CGImageGetBytesPerRow(cg_image); + 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 cursor( + new MouseCursor(image.release(), hotspot)); + + callback_->OnMouseCursor(cursor.release()); +} + +MouseCursorMonitor* MouseCursorMonitor::CreateForWindow( + const DesktopCaptureOptions& options, WindowId window) { + return new MouseCursorMonitorMac(options, window, kInvalidScreenId); +} + +MouseCursorMonitor* MouseCursorMonitor::CreateForScreen( + const DesktopCaptureOptions& options, + ScreenId screen) { + return new MouseCursorMonitorMac(options, kCGNullWindowID, screen); +} + +std::unique_ptr MouseCursorMonitor::Create( + const DesktopCaptureOptions& options) { + return std::unique_ptr( + CreateForScreen(options, kFullDesktopScreenId)); +} + +} // namespace webrtc -- cgit v1.2.3