tor-browser

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

screen_drawer_win.cc (5797B)


      1 /*
      2 *  Copyright (c) 2016 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 <windows.h>
     12 
     13 #include <cstddef>
     14 #include <memory>
     15 
     16 #include "modules/desktop_capture/desktop_capture_types.h"
     17 #include "modules/desktop_capture/desktop_geometry.h"
     18 #include "modules/desktop_capture/rgba_color.h"
     19 #include "modules/desktop_capture/screen_drawer.h"
     20 #include "rtc_base/thread.h"
     21 
     22 namespace webrtc {
     23 
     24 namespace {
     25 
     26 static constexpr TCHAR kMutexName[] =
     27    TEXT("Local\\ScreenDrawerWin-da834f82-8044-11e6-ac81-73dcdd1c1869");
     28 
     29 class ScreenDrawerLockWin : public ScreenDrawerLock {
     30 public:
     31  ScreenDrawerLockWin();
     32  ~ScreenDrawerLockWin() override;
     33 
     34 private:
     35  HANDLE mutex_;
     36 };
     37 
     38 ScreenDrawerLockWin::ScreenDrawerLockWin() {
     39  while (true) {
     40    mutex_ = CreateMutex(NULL, FALSE, kMutexName);
     41    if (GetLastError() != ERROR_ALREADY_EXISTS && mutex_ != NULL) {
     42      break;
     43    } else {
     44      if (mutex_) {
     45        CloseHandle(mutex_);
     46      }
     47      Thread::SleepMs(1000);
     48    }
     49  }
     50 }
     51 
     52 ScreenDrawerLockWin::~ScreenDrawerLockWin() {
     53  CloseHandle(mutex_);
     54 }
     55 
     56 DesktopRect GetScreenRect() {
     57  HDC hdc = GetDC(NULL);
     58  DesktopRect rect = DesktopRect::MakeWH(GetDeviceCaps(hdc, HORZRES),
     59                                         GetDeviceCaps(hdc, VERTRES));
     60  ReleaseDC(NULL, hdc);
     61  return rect;
     62 }
     63 
     64 HWND CreateDrawerWindow(DesktopRect rect) {
     65  HWND hwnd = CreateWindowA(
     66      "STATIC", "DrawerWindow", WS_POPUPWINDOW | WS_VISIBLE, rect.left(),
     67      rect.top(), rect.width(), rect.height(), NULL, NULL, NULL, NULL);
     68  SetForegroundWindow(hwnd);
     69  return hwnd;
     70 }
     71 
     72 COLORREF ColorToRef(RgbaColor color) {
     73  // Windows device context does not support alpha.
     74  return RGB(color.red, color.green, color.blue);
     75 }
     76 
     77 // A ScreenDrawer implementation for Windows.
     78 class ScreenDrawerWin : public ScreenDrawer {
     79 public:
     80  ScreenDrawerWin();
     81  ~ScreenDrawerWin() override;
     82 
     83  // ScreenDrawer interface.
     84  DesktopRect DrawableRegion() override;
     85  void DrawRectangle(DesktopRect rect, RgbaColor color) override;
     86  void Clear() override;
     87  void WaitForPendingDraws() override;
     88  bool MayDrawIncompleteShapes() override;
     89  WindowId window_id() const override;
     90 
     91 private:
     92  // Bring the window to the front, this can help to avoid the impact from other
     93  // windows or shadow effects.
     94  void BringToFront();
     95 
     96  // Draw a line with `color`.
     97  void DrawLine(DesktopVector start, DesktopVector end, RgbaColor color);
     98 
     99  // Draw a dot with `color`.
    100  void DrawDot(DesktopVector vect, RgbaColor color);
    101 
    102  const DesktopRect rect_;
    103  HWND window_;
    104  HDC hdc_;
    105 };
    106 
    107 ScreenDrawerWin::ScreenDrawerWin()
    108    : ScreenDrawer(),
    109      rect_(GetScreenRect()),
    110      window_(CreateDrawerWindow(rect_)),
    111      hdc_(GetWindowDC(window_)) {
    112  // We do not need to handle any messages for the `window_`, so disable Windows
    113  // from processing windows ghosting feature.
    114  DisableProcessWindowsGhosting();
    115 
    116  // Always use stock pen (DC_PEN) and brush (DC_BRUSH).
    117  SelectObject(hdc_, GetStockObject(DC_PEN));
    118  SelectObject(hdc_, GetStockObject(DC_BRUSH));
    119  BringToFront();
    120 }
    121 
    122 ScreenDrawerWin::~ScreenDrawerWin() {
    123  ReleaseDC(NULL, hdc_);
    124  DestroyWindow(window_);
    125  // Unfortunately there is no EnableProcessWindowsGhosting() API.
    126 }
    127 
    128 DesktopRect ScreenDrawerWin::DrawableRegion() {
    129  return rect_;
    130 }
    131 
    132 void ScreenDrawerWin::DrawRectangle(DesktopRect rect, RgbaColor color) {
    133  if (rect.width() == 1 && rect.height() == 1) {
    134    // Rectangle function cannot draw a 1 pixel rectangle.
    135    DrawDot(rect.top_left(), color);
    136    return;
    137  }
    138 
    139  if (rect.width() == 1 || rect.height() == 1) {
    140    // Rectangle function cannot draw a 1 pixel rectangle.
    141    DrawLine(rect.top_left(), DesktopVector(rect.right(), rect.bottom()),
    142             color);
    143    return;
    144  }
    145 
    146  SetDCBrushColor(hdc_, ColorToRef(color));
    147  SetDCPenColor(hdc_, ColorToRef(color));
    148  Rectangle(hdc_, rect.left(), rect.top(), rect.right(), rect.bottom());
    149 }
    150 
    151 void ScreenDrawerWin::Clear() {
    152  DrawRectangle(rect_, RgbaColor(0, 0, 0));
    153 }
    154 
    155 // TODO(zijiehe): Find the right signal to indicate the finish of all pending
    156 // paintings.
    157 void ScreenDrawerWin::WaitForPendingDraws() {
    158  BringToFront();
    159  Thread::SleepMs(50);
    160 }
    161 
    162 bool ScreenDrawerWin::MayDrawIncompleteShapes() {
    163  return true;
    164 }
    165 
    166 WindowId ScreenDrawerWin::window_id() const {
    167  return reinterpret_cast<WindowId>(window_);
    168 }
    169 
    170 void ScreenDrawerWin::DrawLine(DesktopVector start,
    171                               DesktopVector end,
    172                               RgbaColor color) {
    173  POINT points[2];
    174  points[0].x = start.x();
    175  points[0].y = start.y();
    176  points[1].x = end.x();
    177  points[1].y = end.y();
    178  SetDCPenColor(hdc_, ColorToRef(color));
    179  Polyline(hdc_, points, 2);
    180 }
    181 
    182 void ScreenDrawerWin::DrawDot(DesktopVector vect, RgbaColor color) {
    183  SetPixel(hdc_, vect.x(), vect.y(), ColorToRef(color));
    184 }
    185 
    186 void ScreenDrawerWin::BringToFront() {
    187  if (SetWindowPos(window_, HWND_TOPMOST, 0, 0, 0, 0,
    188                   SWP_NOMOVE | SWP_NOSIZE) != FALSE) {
    189    return;
    190  }
    191 
    192  long ex_style = GetWindowLong(window_, GWL_EXSTYLE);
    193  ex_style |= WS_EX_TOPMOST;
    194  if (SetWindowLong(window_, GWL_EXSTYLE, ex_style) != 0) {
    195    return;
    196  }
    197 
    198  BringWindowToTop(window_);
    199 }
    200 
    201 }  // namespace
    202 
    203 // static
    204 std::unique_ptr<ScreenDrawerLock> ScreenDrawerLock::Create() {
    205  return std::unique_ptr<ScreenDrawerLock>(new ScreenDrawerLockWin());
    206 }
    207 
    208 // static
    209 std::unique_ptr<ScreenDrawer> ScreenDrawer::Create() {
    210  return std::unique_ptr<ScreenDrawer>(new ScreenDrawerWin());
    211 }
    212 
    213 }  // namespace webrtc