From dab31ce1fa39c2fe3ce0f9f7b3a2054bc9344a5d Mon Sep 17 00:00:00 2001 From: Zijie He Date: Wed, 23 Aug 2017 11:21:09 -0700 Subject: [PATCH] Detect whether a window is out of screen when using cropping window capturer We are still using cropping window capturer even the window is out of the screen. See the bug for details. Bug: webrtc:8134 Change-Id: I5161b1a17a3a1f8244697eea5eb78975be6908f9 Reviewed-on: https://chromium-review.googlesource.com/627338 Commit-Queue: Zijie He Reviewed-by: Jamie Walch Cr-Commit-Position: refs/heads/master@{#19474} --- .../cropping_window_capturer_win.cc | 49 ++++++++++++------- .../win/window_capture_utils.cc | 15 ++++++ .../win/window_capture_utils.h | 4 ++ 3 files changed, 50 insertions(+), 18 deletions(-) diff --git a/webrtc/modules/desktop_capture/cropping_window_capturer_win.cc b/webrtc/modules/desktop_capture/cropping_window_capturer_win.cc index 27be392651..6b046d8149 100644 --- a/webrtc/modules/desktop_capture/cropping_window_capturer_win.cc +++ b/webrtc/modules/desktop_capture/cropping_window_capturer_win.cc @@ -10,7 +10,6 @@ #include "webrtc/modules/desktop_capture/cropping_window_capturer.h" -#include "webrtc/modules/desktop_capture/win/scoped_gdi_object.h" #include "webrtc/modules/desktop_capture/win/screen_capture_utils.h" #include "webrtc/modules/desktop_capture/win/window_capture_utils.h" #include "webrtc/rtc_base/logging.h" @@ -134,14 +133,14 @@ bool CroppingWindowCapturerWin::ShouldUseScreenCapturer() { return false; } - HWND selected = reinterpret_cast(selected_window()); + const HWND selected = reinterpret_cast(selected_window()); // Check if the window is hidden or minimized. if (IsIconic(selected) || !IsWindowVisible(selected)) { return false; } // Check if the window is a translucent layered window. - LONG window_ex_style = GetWindowLong(selected, GWL_EXSTYLE); + const LONG window_ex_style = GetWindowLong(selected, GWL_EXSTYLE); if (window_ex_style & WS_EX_LAYERED) { COLORREF color_ref_key = 0; BYTE alpha = 0; @@ -165,10 +164,15 @@ bool CroppingWindowCapturerWin::ShouldUseScreenCapturer() { return false; } + DesktopRect content_rect; + if (!GetWindowContentRect(selected, &content_rect)) { + return false; + } + + DesktopRect region_rect; // Get the window region and check if it is rectangular. - win::ScopedGDIObject > - scoped_hrgn(CreateRectRgn(0, 0, 0, 0)); - int region_type = GetWindowRgn(selected, scoped_hrgn.Get()); + const int region_type = + GetWindowRegionTypeWithBoundary(selected, ®ion_rect); // Do not use the screen capturer if the region is empty or not rectangular. if (region_type == COMPLEXREGION || region_type == NULLREGION) { @@ -176,20 +180,29 @@ bool CroppingWindowCapturerWin::ShouldUseScreenCapturer() { } if (region_type == SIMPLEREGION) { - RECT region_rect; - GetRgnBox(scoped_hrgn.Get(), ®ion_rect); - DesktopRect rgn_rect = - DesktopRect::MakeLTRB(region_rect.left, - region_rect.top, - region_rect.right, - region_rect.bottom); - DesktopRect translated_rect = rgn_rect; - translated_rect.Translate(window_region_rect_.left(), - window_region_rect_.top()); - window_region_rect_.IntersectWith(translated_rect); + // The |region_rect| returned from GetRgnBox() is always in window + // coordinate. + region_rect.Translate( + window_region_rect_.left(), window_region_rect_.top()); + // MSDN: The window region determines the area *within* the window where the + // system permits drawing. + // https://msdn.microsoft.com/en-us/library/windows/desktop/dd144950(v=vs.85).aspx. + // + // |region_rect| should always be inside of |window_region_rect_|. So after + // the intersection, |window_region_rect_| == |region_rect|. If so, what's + // the point of the intersecting operations? Why cannot we directly retrieve + // |window_region_rect_| from GetWindowRegionTypeWithBoundary() function? + // TODO(zijiehe): Figure out the purpose of these intersections. + window_region_rect_.IntersectWith(region_rect); + content_rect.IntersectWith(region_rect); } - // TODO(zijiehe): Check whether the client area is out of the screen area. + // Check if the client area is out of the screen area. When the window is + // maximized, only its client area is visible in the screen, the border will + // be hidden. So we are using |content_rect| here. + if (!GetFullscreenRect().ContainsRect(content_rect)) { + return false; + } // Check if the window is occluded by any other window, excluding the child // windows, context menus, and |excluded_window_|. diff --git a/webrtc/modules/desktop_capture/win/window_capture_utils.cc b/webrtc/modules/desktop_capture/win/window_capture_utils.cc index abcb6a641a..07da6ee6af 100644 --- a/webrtc/modules/desktop_capture/win/window_capture_utils.cc +++ b/webrtc/modules/desktop_capture/win/window_capture_utils.cc @@ -10,6 +10,7 @@ #include "webrtc/modules/desktop_capture/win/window_capture_utils.h" +#include "webrtc/modules/desktop_capture/win/scoped_gdi_object.h" #include "webrtc/rtc_base/checks.h" #include "webrtc/rtc_base/win32.h" @@ -98,6 +99,20 @@ bool GetWindowContentRect(HWND window, DesktopRect* result) { return true; } +int GetWindowRegionTypeWithBoundary(HWND window, DesktopRect* result) { + win::ScopedGDIObject> + scoped_hrgn(CreateRectRgn(0, 0, 0, 0)); + const int region_type = GetWindowRgn(window, scoped_hrgn.Get()); + + if (region_type == SIMPLEREGION) { + RECT rect; + GetRgnBox(scoped_hrgn.Get(), &rect); + *result = DesktopRect::MakeLTRB( + rect.left, rect.top, rect.right, rect.bottom); + } + return region_type; +} + AeroChecker::AeroChecker() : dwmapi_library_(nullptr), func_(nullptr) { // Try to load dwmapi.dll dynamically since it is not available on XP. dwmapi_library_ = LoadLibrary(L"dwmapi.dll"); diff --git a/webrtc/modules/desktop_capture/win/window_capture_utils.h b/webrtc/modules/desktop_capture/win/window_capture_utils.h index 255963e054..c889c16aed 100644 --- a/webrtc/modules/desktop_capture/win/window_capture_utils.h +++ b/webrtc/modules/desktop_capture/win/window_capture_utils.h @@ -37,6 +37,10 @@ bool GetCroppedWindowRect(HWND window, // APIs fail. bool GetWindowContentRect(HWND window, DesktopRect* result); +// Returns the region type of the |window| and fill |rect| with the region of +// |window| if region type is SIMPLEREGION. +int GetWindowRegionTypeWithBoundary(HWND window, DesktopRect* result); + typedef HRESULT (WINAPI *DwmIsCompositionEnabledFunc)(BOOL* enabled); class AeroChecker { public: