diff --git a/webrtc/modules/BUILD.gn b/webrtc/modules/BUILD.gn index 676160ae65..f79e2f6779 100644 --- a/webrtc/modules/BUILD.gn +++ b/webrtc/modules/BUILD.gn @@ -369,6 +369,11 @@ if (rtc_include_tests) { "desktop_capture/screen_capturer_mac_unittest.cc", "desktop_capture/screen_capturer_mock_objects.h", "desktop_capture/screen_capturer_unittest.cc", + "desktop_capture/screen_drawer.h", + "desktop_capture/screen_drawer_linux.cc", + "desktop_capture/screen_drawer_mac.cc", + "desktop_capture/screen_drawer_unittest.cc", + "desktop_capture/screen_drawer_win.cc", "desktop_capture/win/cursor_unittest.cc", "desktop_capture/win/cursor_unittest_resources.h", "desktop_capture/win/cursor_unittest_resources.rc", diff --git a/webrtc/modules/desktop_capture/screen_drawer.h b/webrtc/modules/desktop_capture/screen_drawer.h new file mode 100644 index 0000000000..899fc0f043 --- /dev/null +++ b/webrtc/modules/desktop_capture/screen_drawer.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2016 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. + */ + +#ifndef WEBRTC_MODULES_DESKTOP_CAPTURE_SCREEN_DRAWER_H_ +#define WEBRTC_MODULES_DESKTOP_CAPTURE_SCREEN_DRAWER_H_ + +#include + +#include + +#include "webrtc/modules/desktop_capture/desktop_geometry.h" + +namespace webrtc { + +// A set of platform independent functions to draw various of shapes on the +// screen. This class is for testing ScreenCapturer* implementations only, and +// should not be used in production logic. +class ScreenDrawer { + public: + // Creates a ScreenDrawer for the current platform. + static std::unique_ptr Create(); + + ScreenDrawer() {} + virtual ~ScreenDrawer() {} + + // Returns a rect, on which this instance can draw. + virtual DesktopRect DrawableRegion() = 0; + + // Draws a rectangle to cover |rect| with color |rgba|. Note, rect.bottom() + // and rect.right() two lines are not included. + virtual void DrawRectangle(DesktopRect rect, uint32_t rgba) = 0; + + // Clears all content on the screen. + virtual void Clear() = 0; +}; + +} // namespace webrtc + +#endif // WEBRTC_MODULES_DESKTOP_CAPTURE_SCREEN_DRAWER_H_ diff --git a/webrtc/modules/desktop_capture/screen_drawer_linux.cc b/webrtc/modules/desktop_capture/screen_drawer_linux.cc new file mode 100644 index 0000000000..2aff80b6c7 --- /dev/null +++ b/webrtc/modules/desktop_capture/screen_drawer_linux.cc @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2016 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 + +#include "webrtc/base/checks.h" +#include "webrtc/modules/desktop_capture/screen_drawer.h" +#include "webrtc/modules/desktop_capture/x11/shared_x_display.h" + +namespace webrtc { + +namespace { + +// A ScreenDrawer implementation for X11. +class ScreenDrawerLinux : public ScreenDrawer { + public: + ScreenDrawerLinux(); + ~ScreenDrawerLinux() override; + + // ScreenDrawer interface. + DesktopRect DrawableRegion() override; + void DrawRectangle(DesktopRect rect, uint32_t rgba) override; + void Clear() override; + + private: + rtc::scoped_refptr display_; + Screen* screen_; + int screen_num_; + DesktopRect rect_; + Window window_; + GC context_; + Colormap colormap_; +}; + +ScreenDrawerLinux::ScreenDrawerLinux() { + display_ = SharedXDisplay::CreateDefault(); + RTC_CHECK(display_.get()); + screen_ = DefaultScreenOfDisplay(display_->display()); + RTC_CHECK(screen_); + screen_num_ = DefaultScreen(display_->display()); + rect_ = DesktopRect::MakeWH(screen_->width, screen_->height); + window_ = XCreateSimpleWindow(display_->display(), + RootWindow(display_->display(), screen_num_), 0, + 0, rect_.width(), rect_.height(), 0, + BlackPixel(display_->display(), screen_num_), + BlackPixel(display_->display(), screen_num_)); + XSelectInput(display_->display(), window_, StructureNotifyMask); + XMapWindow(display_->display(), window_); + while (true) { + XEvent event; + XNextEvent(display_->display(), &event); + if (event.type == MapNotify) { + break; + } + } + XFlush(display_->display()); + context_ = DefaultGC(display_->display(), screen_num_); + colormap_ = DefaultColormap(display_->display(), screen_num_); +} + +ScreenDrawerLinux::~ScreenDrawerLinux() { + XUnmapWindow(display_->display(), window_); + XDestroyWindow(display_->display(), window_); +} + +DesktopRect ScreenDrawerLinux::DrawableRegion() { + return rect_; +} + +void ScreenDrawerLinux::DrawRectangle(DesktopRect rect, uint32_t rgba) { + int r = (rgba & 0xff00) >> 8; + int g = (rgba & 0xff0000) >> 16; + int b = (rgba & 0xff000000) >> 24; + // X11 does not support Alpha. + XColor color; + // X11 uses 16 bits for each primary color. + color.red = r * 256; + color.green = g * 256; + color.blue = b * 256; + color.flags = DoRed | DoGreen | DoBlue; + XAllocColor(display_->display(), colormap_, &color); + XSetForeground(display_->display(), context_, color.pixel); + XFillRectangle(display_->display(), window_, context_, rect.left(), + rect.top(), rect.width(), rect.height()); + XFlush(display_->display()); +} + +void ScreenDrawerLinux::Clear() { + DrawRectangle(DrawableRegion(), 0); +} + +} // namespace + +// static +std::unique_ptr ScreenDrawer::Create() { + return std::unique_ptr(new ScreenDrawerLinux()); +} + +} // namespace webrtc diff --git a/webrtc/modules/desktop_capture/screen_drawer_mac.cc b/webrtc/modules/desktop_capture/screen_drawer_mac.cc new file mode 100644 index 0000000000..1d0437b5a1 --- /dev/null +++ b/webrtc/modules/desktop_capture/screen_drawer_mac.cc @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2016 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. + */ + +// TODO(zijiehe): Implement ScreenDrawerMac + +#include "webrtc/modules/desktop_capture/screen_drawer.h" + +namespace webrtc { + +// static +std::unique_ptr ScreenDrawer::Create() { + return nullptr; +} + +} // namespace webrtc diff --git a/webrtc/modules/desktop_capture/screen_drawer_unittest.cc b/webrtc/modules/desktop_capture/screen_drawer_unittest.cc new file mode 100644 index 0000000000..345a962223 --- /dev/null +++ b/webrtc/modules/desktop_capture/screen_drawer_unittest.cc @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2016 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 "webrtc/modules/desktop_capture/screen_drawer.h" + +#include + +#include "testing/gtest/include/gtest/gtest.h" +#include "webrtc/base/random.h" +#include "webrtc/base/timeutils.h" +#include "webrtc/system_wrappers/include/sleep.h" + +namespace webrtc { + +// These are a set of manual test cases, as we do not have an automatical way to +// detect whether a ScreenDrawer on a certain platform works well without +// ScreenCapturer(s). So you may execute these test cases with +// --gtest_also_run_disabled_tests --gtest_filter=ScreenDrawerTest.*. +TEST(ScreenDrawerTest, DISABLED_DrawRectangles) { + std::unique_ptr drawer = ScreenDrawer::Create(); + if (!drawer) { + // No ScreenDrawer implementation for current platform. + return; + } + + drawer->Clear(); + DesktopRect rect = drawer->DrawableRegion(); + Random random(rtc::TimeMicros()); + for (int i = 0; i < 100; i++) { + // Make sure we at least draw one pixel. + int left = random.Rand(rect.left(), rect.right() - 2); + int top = random.Rand(rect.top(), rect.bottom() - 2); + drawer->DrawRectangle( + DesktopRect::MakeLTRB(left, top, random.Rand(left + 1, rect.right()), + random.Rand(top + 1, rect.bottom())), + random.Rand()); + + if (i == 50) { + SleepMs(10000); + drawer->Clear(); + } + } + + SleepMs(10000); + drawer->Clear(); +} + +} // namespace webrtc diff --git a/webrtc/modules/desktop_capture/screen_drawer_win.cc b/webrtc/modules/desktop_capture/screen_drawer_win.cc new file mode 100644 index 0000000000..061a40539e --- /dev/null +++ b/webrtc/modules/desktop_capture/screen_drawer_win.cc @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2016 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 + +#include + +#include "webrtc/modules/desktop_capture/screen_drawer.h" + +namespace webrtc { + +namespace { + +DesktopRect GetScreenRect() { + HDC hdc = GetDC(NULL); + DesktopRect rect = DesktopRect::MakeWH(GetDeviceCaps(hdc, HORZRES), + GetDeviceCaps(hdc, VERTRES)); + ReleaseDC(NULL, hdc); + return rect; +} + +HWND CreateDrawerWindow(DesktopRect rect) { + HWND hwnd = CreateWindowA( + "STATIC", "DrawerWindow", WS_POPUPWINDOW | WS_VISIBLE, rect.left(), + rect.top(), rect.width(), rect.height(), NULL, NULL, NULL, NULL); + SetForegroundWindow(hwnd); + return hwnd; +} + +// A ScreenDrawer implementation for Windows. +class ScreenDrawerWin : public ScreenDrawer { + public: + ScreenDrawerWin(); + ~ScreenDrawerWin() override; + + // ScreenDrawer interface. + DesktopRect DrawableRegion() override; + void DrawRectangle(DesktopRect rect, uint32_t rgba) override; + void Clear() override; + + private: + const DesktopRect rect_; + HWND window_; + HDC hdc_; +}; + +ScreenDrawerWin::ScreenDrawerWin() + : ScreenDrawer(), + rect_(GetScreenRect()), + window_(CreateDrawerWindow(rect_)), + hdc_(GetWindowDC(window_)) { + // We do not need to handle any messages for the |window_|, so disable Windows + // process windows ghosting feature. + DisableProcessWindowsGhosting(); +} + +ScreenDrawerWin::~ScreenDrawerWin() { + ReleaseDC(NULL, hdc_); + DestroyWindow(window_); + // Unfortunately there is no EnableProcessWindowsGhosting() API. +} + +DesktopRect ScreenDrawerWin::DrawableRegion() { + return rect_; +} + +void ScreenDrawerWin::DrawRectangle(DesktopRect rect, uint32_t rgba) { + int r = (rgba & 0xff00) >> 8; + int g = (rgba & 0xff0000) >> 16; + int b = (rgba & 0xff000000) >> 24; + // Windows device context does not support Alpha. + SelectObject(hdc_, GetStockObject(DC_PEN)); + SelectObject(hdc_, GetStockObject(DC_BRUSH)); + SetDCBrushColor(hdc_, RGB(r, g, b)); + SetDCPenColor(hdc_, RGB(r, g, b)); + Rectangle(hdc_, rect.left(), rect.top(), rect.right(), rect.bottom()); +} + +void ScreenDrawerWin::Clear() { + DrawRectangle(DrawableRegion(), 0); +} + +} // namespace + +// static +std::unique_ptr ScreenDrawer::Create() { + return std::unique_ptr(new ScreenDrawerWin()); +} + +} // namespace webrtc diff --git a/webrtc/modules/modules.gyp b/webrtc/modules/modules.gyp index 094204f723..6718d8ff63 100644 --- a/webrtc/modules/modules.gyp +++ b/webrtc/modules/modules.gyp @@ -428,6 +428,11 @@ 'desktop_capture/screen_capturer_mac_unittest.cc', 'desktop_capture/screen_capturer_mock_objects.h', 'desktop_capture/screen_capturer_unittest.cc', + 'desktop_capture/screen_drawer.h', + 'desktop_capture/screen_drawer_linux.cc', + 'desktop_capture/screen_drawer_mac.cc', + 'desktop_capture/screen_drawer_unittest.cc', + 'desktop_capture/screen_drawer_win.cc', 'desktop_capture/window_capturer_unittest.cc', 'desktop_capture/win/cursor_unittest.cc', 'desktop_capture/win/cursor_unittest_resources.h',