tor-browser

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

screen_capture_utils.cc (6293B)


      1 /*
      2 *  Copyright (c) 2014 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/win/screen_capture_utils.h"
     12 
     13 #include <shellscalingapi.h>
     14 #include <windows.h>
     15 
     16 #include <cstddef>
     17 #include <optional>
     18 #include <string>
     19 #include <vector>
     20 
     21 #include "modules/desktop_capture/desktop_capture_types.h"
     22 #include "modules/desktop_capture/desktop_capturer.h"
     23 #include "modules/desktop_capture/desktop_geometry.h"
     24 #include "rtc_base/checks.h"
     25 #include "rtc_base/logging.h"
     26 #include "rtc_base/string_utils.h"
     27 #include "rtc_base/win32.h"
     28 
     29 namespace webrtc {
     30 
     31 bool HasActiveDisplay() {
     32  DesktopCapturer::SourceList screens;
     33 
     34  return GetScreenList(&screens) && !screens.empty();
     35 }
     36 
     37 bool GetScreenList(DesktopCapturer::SourceList* screens,
     38                   std::vector<std::string>* device_names /* = nullptr */) {
     39  RTC_DCHECK(screens->empty());
     40  RTC_DCHECK(!device_names || device_names->empty());
     41 
     42  BOOL enum_result = TRUE;
     43  for (int device_index = 0;; ++device_index) {
     44    DISPLAY_DEVICEW device;
     45    device.cb = sizeof(device);
     46    enum_result = EnumDisplayDevicesW(NULL, device_index, &device, 0);
     47 
     48    // `enum_result` is 0 if we have enumerated all devices.
     49    if (!enum_result) {
     50      break;
     51    }
     52 
     53    // We only care about active displays.
     54    if (!(device.StateFlags & DISPLAY_DEVICE_ACTIVE)) {
     55      continue;
     56    }
     57 
     58    screens->push_back({device_index, 0, std::string()});
     59    if (device_names) {
     60      device_names->push_back(ToUtf8(device.DeviceName));
     61    }
     62  }
     63  return true;
     64 }
     65 
     66 bool GetHmonitorFromDeviceIndex(const DesktopCapturer::SourceId device_index,
     67                                HMONITOR* hmonitor) {
     68  // A device index of `kFullDesktopScreenId` or -1 represents all screens, an
     69  // HMONITOR of 0 indicates the same.
     70  if (device_index == kFullDesktopScreenId) {
     71    *hmonitor = 0;
     72    return true;
     73  }
     74 
     75  DesktopRect screen_rect = GetScreenRect(device_index, std::nullopt);
     76  if (screen_rect.is_empty()) {
     77    return false;
     78  }
     79 
     80  RECT rect = {screen_rect.left(), screen_rect.top(), screen_rect.right(),
     81               screen_rect.bottom()};
     82 
     83  HMONITOR monitor = MonitorFromRect(&rect, MONITOR_DEFAULTTONULL);
     84  if (monitor == NULL) {
     85    RTC_LOG(LS_WARNING) << "No HMONITOR found for supplied device index.";
     86    return false;
     87  }
     88 
     89  *hmonitor = monitor;
     90  return true;
     91 }
     92 
     93 bool IsMonitorValid(const HMONITOR monitor) {
     94  // An HMONITOR of 0 refers to a virtual monitor that spans all physical
     95  // monitors.
     96  if (monitor == 0) {
     97    // There is a bug in a Windows OS API that causes a crash when capturing if
     98    // there are no active displays. We must ensure there is an active display
     99    // before returning true.
    100    if (!HasActiveDisplay())
    101      return false;
    102 
    103    return true;
    104  }
    105 
    106  MONITORINFO monitor_info;
    107  monitor_info.cbSize = sizeof(MONITORINFO);
    108  return GetMonitorInfoA(monitor, &monitor_info);
    109 }
    110 
    111 DesktopRect GetMonitorRect(const HMONITOR monitor) {
    112  MONITORINFO monitor_info;
    113  monitor_info.cbSize = sizeof(MONITORINFO);
    114  if (!GetMonitorInfoA(monitor, &monitor_info)) {
    115    return DesktopRect();
    116  }
    117 
    118  return DesktopRect::MakeLTRB(
    119      monitor_info.rcMonitor.left, monitor_info.rcMonitor.top,
    120      monitor_info.rcMonitor.right, monitor_info.rcMonitor.bottom);
    121 }
    122 
    123 bool IsScreenValid(const DesktopCapturer::SourceId screen,
    124                   std::wstring* device_key) {
    125  if (screen == kFullDesktopScreenId) {
    126    *device_key = L"";
    127    return true;
    128  }
    129 
    130  DISPLAY_DEVICEW device;
    131  device.cb = sizeof(device);
    132  BOOL enum_result = EnumDisplayDevicesW(NULL, screen, &device, 0);
    133  if (enum_result) {
    134    *device_key = device.DeviceKey;
    135  }
    136 
    137  return !!enum_result;
    138 }
    139 
    140 DesktopRect GetFullscreenRect() {
    141  return DesktopRect::MakeXYWH(GetSystemMetrics(SM_XVIRTUALSCREEN),
    142                               GetSystemMetrics(SM_YVIRTUALSCREEN),
    143                               GetSystemMetrics(SM_CXVIRTUALSCREEN),
    144                               GetSystemMetrics(SM_CYVIRTUALSCREEN));
    145 }
    146 
    147 DesktopVector GetDpiForMonitor(HMONITOR monitor) {
    148  UINT dpi_x, dpi_y;
    149  // MDT_EFFECTIVE_DPI includes the scale factor as well as the system DPI.
    150  HRESULT hr = ::GetDpiForMonitor(monitor, MDT_EFFECTIVE_DPI, &dpi_x, &dpi_y);
    151  if (SUCCEEDED(hr)) {
    152    return {static_cast<INT>(dpi_x), static_cast<INT>(dpi_y)};
    153  }
    154  RTC_LOG_GLE_EX(LS_WARNING, hr) << "GetDpiForMonitor() failed";
    155 
    156  // If we can't get the per-monitor DPI, then return the system DPI.
    157  HDC hdc = GetDC(nullptr);
    158  if (hdc) {
    159    DesktopVector dpi{GetDeviceCaps(hdc, LOGPIXELSX),
    160                      GetDeviceCaps(hdc, LOGPIXELSY)};
    161    ReleaseDC(nullptr, hdc);
    162    return dpi;
    163  }
    164 
    165  // If everything fails, then return the default DPI for Windows.
    166  return {96, 96};
    167 }
    168 
    169 DesktopRect GetScreenRect(const DesktopCapturer::SourceId screen,
    170                          const std::optional<std::wstring>& device_key) {
    171  if (screen == kFullDesktopScreenId) {
    172    return GetFullscreenRect();
    173  }
    174 
    175  DISPLAY_DEVICEW device;
    176  device.cb = sizeof(device);
    177  BOOL result = EnumDisplayDevicesW(NULL, screen, &device, 0);
    178  if (!result) {
    179    return DesktopRect();
    180  }
    181 
    182  // Verifies the device index still maps to the same display device, to make
    183  // sure we are capturing the same device when devices are added or removed.
    184  // DeviceKey is documented as reserved, but it actually contains the registry
    185  // key for the device and is unique for each monitor, while DeviceID is not.
    186  if (device_key.has_value() && *device_key != device.DeviceKey) {
    187    return DesktopRect();
    188  }
    189 
    190  DEVMODEW device_mode;
    191  device_mode.dmSize = sizeof(device_mode);
    192  device_mode.dmDriverExtra = 0;
    193  result = EnumDisplaySettingsExW(device.DeviceName, ENUM_CURRENT_SETTINGS,
    194                                  &device_mode, 0);
    195  if (!result) {
    196    return DesktopRect();
    197  }
    198 
    199  return DesktopRect::MakeXYWH(
    200      device_mode.dmPosition.x, device_mode.dmPosition.y,
    201      device_mode.dmPelsWidth, device_mode.dmPelsHeight);
    202 }
    203 
    204 }  // namespace webrtc