tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

desktop_and_cursor_composer.cc (10251B)


      1 /*
      2 *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
      3 *
      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
      6 *  tree. An additional intellectual property rights grant can be found
      7 *  in the file PATENTS.  All contributing project authors may
      8 *  be found in the AUTHORS file in the root of the source tree.
      9 */
     10 
     11 #include "modules/desktop_capture/desktop_and_cursor_composer.h"
     12 
     13 #include <cstdint>
     14 #include <cstring>
     15 #include <memory>
     16 #include <utility>
     17 
     18 #include "modules/desktop_capture/desktop_capture_metadata.h"
     19 #include "modules/desktop_capture/desktop_capture_types.h"
     20 #include "modules/desktop_capture/desktop_capturer.h"
     21 #include "modules/desktop_capture/desktop_frame.h"
     22 #include "modules/desktop_capture/desktop_geometry.h"
     23 #include "modules/desktop_capture/mouse_cursor.h"
     24 #include "modules/desktop_capture/mouse_cursor_monitor.h"
     25 #include "modules/desktop_capture/shared_memory.h"
     26 #include "rtc_base/checks.h"
     27 #include "rtc_base/logging.h"
     28 
     29 namespace webrtc {
     30 
     31 namespace {
     32 
     33 // Helper function that blends one image into another. Source image must be
     34 // pre-multiplied with the alpha channel. Destination is assumed to be opaque.
     35 void AlphaBlend(uint8_t* dest,
     36                int dest_stride,
     37                const uint8_t* src,
     38                int src_stride,
     39                const DesktopSize& size) {
     40  for (int y = 0; y < size.height(); ++y) {
     41    for (int x = 0; x < size.width(); ++x) {
     42      uint32_t base_alpha = 255 - src[x * DesktopFrame::kBytesPerPixel + 3];
     43      if (base_alpha == 255) {
     44        continue;
     45      } else if (base_alpha == 0) {
     46        memcpy(dest + x * DesktopFrame::kBytesPerPixel,
     47               src + x * DesktopFrame::kBytesPerPixel,
     48               DesktopFrame::kBytesPerPixel);
     49      } else {
     50        dest[x * DesktopFrame::kBytesPerPixel] =
     51            dest[x * DesktopFrame::kBytesPerPixel] * base_alpha / 255 +
     52            src[x * DesktopFrame::kBytesPerPixel];
     53        dest[x * DesktopFrame::kBytesPerPixel + 1] =
     54            dest[x * DesktopFrame::kBytesPerPixel + 1] * base_alpha / 255 +
     55            src[x * DesktopFrame::kBytesPerPixel + 1];
     56        dest[x * DesktopFrame::kBytesPerPixel + 2] =
     57            dest[x * DesktopFrame::kBytesPerPixel + 2] * base_alpha / 255 +
     58            src[x * DesktopFrame::kBytesPerPixel + 2];
     59      }
     60    }
     61    src += src_stride;
     62    dest += dest_stride;
     63  }
     64 }
     65 
     66 // DesktopFrame wrapper that draws mouse on a frame and restores original
     67 // content before releasing the underlying frame.
     68 class DesktopFrameWithCursor : public DesktopFrame {
     69 public:
     70  // Takes ownership of `frame`.
     71  DesktopFrameWithCursor(std::unique_ptr<DesktopFrame> frame,
     72                         const MouseCursor& cursor,
     73                         const DesktopVector& position,
     74                         const DesktopRect& previous_cursor_rect,
     75                         bool cursor_changed);
     76  ~DesktopFrameWithCursor() override;
     77 
     78  DesktopFrameWithCursor(const DesktopFrameWithCursor&) = delete;
     79  DesktopFrameWithCursor& operator=(const DesktopFrameWithCursor&) = delete;
     80 
     81  DesktopRect cursor_rect() const { return cursor_rect_; }
     82 
     83 private:
     84  const std::unique_ptr<DesktopFrame> original_frame_;
     85 
     86  DesktopVector restore_position_;
     87  std::unique_ptr<DesktopFrame> restore_frame_;
     88  DesktopRect cursor_rect_;
     89 };
     90 
     91 DesktopFrameWithCursor::DesktopFrameWithCursor(
     92    std::unique_ptr<DesktopFrame> frame,
     93    const MouseCursor& cursor,
     94    const DesktopVector& position,
     95    const DesktopRect& previous_cursor_rect,
     96    bool cursor_changed)
     97    : DesktopFrame(frame->size(),
     98                   frame->stride(),
     99                   frame->pixel_format(),
    100                   frame->data(),
    101                   frame->shared_memory()),
    102      original_frame_(std::move(frame)) {
    103  MoveFrameInfoFrom(original_frame_.get());
    104 
    105  DesktopVector image_pos = position.subtract(cursor.hotspot());
    106  cursor_rect_ = DesktopRect::MakeSize(cursor.image()->size());
    107  cursor_rect_.Translate(image_pos);
    108  DesktopVector cursor_origin = cursor_rect_.top_left();
    109  cursor_rect_.IntersectWith(DesktopRect::MakeSize(size()));
    110 
    111  if (!previous_cursor_rect.equals(cursor_rect_)) {
    112    mutable_updated_region()->AddRect(cursor_rect_);
    113    // TODO(crbug:1323241) Update this code to properly handle the case where
    114    // |previous_cursor_rect| is outside of the boundaries of |frame|.
    115    // Any boundary check has to take into account the fact that
    116    // |previous_cursor_rect| can be in DPI or in pixels, based on the platform
    117    // we're running on.
    118    mutable_updated_region()->AddRect(previous_cursor_rect);
    119  } else if (cursor_changed) {
    120    mutable_updated_region()->AddRect(cursor_rect_);
    121  }
    122 
    123  if (cursor_rect_.is_empty())
    124    return;
    125 
    126  // Copy original screen content under cursor to `restore_frame_`.
    127  restore_position_ = cursor_rect_.top_left();
    128  restore_frame_.reset(new BasicDesktopFrame(cursor_rect_.size(), FOURCC_ARGB));
    129  restore_frame_->CopyPixelsFrom(*this, cursor_rect_.top_left(),
    130                                 DesktopRect::MakeSize(restore_frame_->size()));
    131 
    132  // Blit the cursor.
    133  uint8_t* cursor_rect_data =
    134      reinterpret_cast<uint8_t*>(data()) + cursor_rect_.top() * stride() +
    135      cursor_rect_.left() * DesktopFrame::kBytesPerPixel;
    136  DesktopVector origin_shift = cursor_rect_.top_left().subtract(cursor_origin);
    137  AlphaBlend(cursor_rect_data, stride(),
    138             cursor.image()->data() +
    139                 origin_shift.y() * cursor.image()->stride() +
    140                 origin_shift.x() * DesktopFrame::kBytesPerPixel,
    141             cursor.image()->stride(), cursor_rect_.size());
    142 }
    143 
    144 DesktopFrameWithCursor::~DesktopFrameWithCursor() {
    145  // Restore original content of the frame.
    146  if (restore_frame_) {
    147    DesktopRect target_rect = DesktopRect::MakeSize(restore_frame_->size());
    148    target_rect.Translate(restore_position_);
    149    CopyPixelsFrom(restore_frame_->data(), restore_frame_->stride(),
    150                   target_rect);
    151  }
    152 }
    153 
    154 }  // namespace
    155 
    156 DesktopAndCursorComposer::DesktopAndCursorComposer(
    157    std::unique_ptr<DesktopCapturer> desktop_capturer,
    158    const DesktopCaptureOptions& options)
    159    : DesktopAndCursorComposer(desktop_capturer.release(),
    160                               MouseCursorMonitor::Create(options).release()) {}
    161 
    162 DesktopAndCursorComposer::DesktopAndCursorComposer(
    163    DesktopCapturer* desktop_capturer,
    164    MouseCursorMonitor* mouse_monitor)
    165    : desktop_capturer_(desktop_capturer), mouse_monitor_(mouse_monitor) {
    166  RTC_DCHECK(desktop_capturer_);
    167 }
    168 
    169 DesktopAndCursorComposer::~DesktopAndCursorComposer() = default;
    170 
    171 std::unique_ptr<DesktopAndCursorComposer>
    172 DesktopAndCursorComposer::CreateWithoutMouseCursorMonitor(
    173    std::unique_ptr<DesktopCapturer> desktop_capturer) {
    174  return std::unique_ptr<DesktopAndCursorComposer>(
    175      new DesktopAndCursorComposer(desktop_capturer.release(), nullptr));
    176 }
    177 
    178 void DesktopAndCursorComposer::Start(DesktopCapturer::Callback* callback) {
    179  callback_ = callback;
    180  if (mouse_monitor_)
    181    mouse_monitor_->Init(this, MouseCursorMonitor::SHAPE_AND_POSITION);
    182  desktop_capturer_->Start(this);
    183 }
    184 
    185 void DesktopAndCursorComposer::SetMaxFrameRate(uint32_t max_frame_rate) {
    186  desktop_capturer_->SetMaxFrameRate(max_frame_rate);
    187 }
    188 
    189 void DesktopAndCursorComposer::SetSharedMemoryFactory(
    190    std::unique_ptr<SharedMemoryFactory> shared_memory_factory) {
    191  desktop_capturer_->SetSharedMemoryFactory(std::move(shared_memory_factory));
    192 }
    193 
    194 void DesktopAndCursorComposer::CaptureFrame() {
    195  if (mouse_monitor_)
    196    mouse_monitor_->Capture();
    197  desktop_capturer_->CaptureFrame();
    198 }
    199 
    200 void DesktopAndCursorComposer::SetExcludedWindow(WindowId window) {
    201  desktop_capturer_->SetExcludedWindow(window);
    202 }
    203 
    204 bool DesktopAndCursorComposer::GetSourceList(SourceList* sources) {
    205  return desktop_capturer_->GetSourceList(sources);
    206 }
    207 
    208 bool DesktopAndCursorComposer::SelectSource(SourceId id) {
    209  return desktop_capturer_->SelectSource(id);
    210 }
    211 
    212 bool DesktopAndCursorComposer::FocusOnSelectedSource() {
    213  return desktop_capturer_->FocusOnSelectedSource();
    214 }
    215 
    216 bool DesktopAndCursorComposer::IsOccluded(const DesktopVector& pos) {
    217  return desktop_capturer_->IsOccluded(pos);
    218 }
    219 
    220 #if defined(WEBRTC_USE_GIO)
    221 DesktopCaptureMetadata DesktopAndCursorComposer::GetMetadata() {
    222  return desktop_capturer_->GetMetadata();
    223 }
    224 #endif  // defined(WEBRTC_USE_GIO)
    225 
    226 void DesktopAndCursorComposer::OnFrameCaptureStart() {
    227  callback_->OnFrameCaptureStart();
    228 }
    229 
    230 void DesktopAndCursorComposer::OnCaptureResult(
    231    DesktopCapturer::Result result,
    232    std::unique_ptr<DesktopFrame> frame) {
    233  if (frame && cursor_) {
    234    if (!frame->may_contain_cursor() &&
    235        frame->rect().Contains(cursor_position_) &&
    236        !desktop_capturer_->IsOccluded(cursor_position_)) {
    237      DesktopVector relative_position =
    238          cursor_position_.subtract(frame->top_left());
    239 #if defined(WEBRTC_MAC) || defined(CHROMEOS)
    240      // On OSX, the logical(DIP) and physical coordinates are used mixingly.
    241      // For example, the captured cursor has its size in physical pixels(2x)
    242      // and location in logical(DIP) pixels on Retina monitor. This will cause
    243      // problem when the desktop is mixed with Retina and non-Retina monitors.
    244      // So we use DIP pixel for all location info and compensate with the scale
    245      // factor of current frame to the `relative_position`.
    246      const float scale = frame->scale_factor();
    247      relative_position.set(relative_position.x() * scale,
    248                            relative_position.y() * scale);
    249 #endif
    250      auto frame_with_cursor = std::make_unique<DesktopFrameWithCursor>(
    251          std::move(frame), *cursor_, relative_position, previous_cursor_rect_,
    252          cursor_changed_);
    253      previous_cursor_rect_ = frame_with_cursor->cursor_rect();
    254      cursor_changed_ = false;
    255      frame = std::move(frame_with_cursor);
    256      frame->set_may_contain_cursor(true);
    257    }
    258  }
    259 
    260  callback_->OnCaptureResult(result, std::move(frame));
    261 }
    262 
    263 void DesktopAndCursorComposer::OnMouseCursor(MouseCursor* cursor) {
    264  cursor_changed_ = true;
    265  cursor_.reset(cursor);
    266 }
    267 
    268 void DesktopAndCursorComposer::OnMouseCursorPosition(
    269    const DesktopVector& position) {
    270  cursor_position_ = position;
    271 }
    272 
    273 }  // namespace webrtc