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 <zijiehe@chromium.org>
Reviewed-by: Jamie Walch <jamiewalch@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#19474}
Cr-Mirrored-From: https://chromium.googlesource.com/external/webrtc
Cr-Mirrored-Commit: dab31ce1fa39c2fe3ce0f9f7b3a2054bc9344a5d
diff --git a/modules/desktop_capture/cropping_window_capturer_win.cc b/modules/desktop_capture/cropping_window_capturer_win.cc
index 27be392..6b046d8 100644
--- a/modules/desktop_capture/cropping_window_capturer_win.cc
+++ b/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 @@
     return false;
   }
 
-  HWND selected = reinterpret_cast<HWND>(selected_window());
+  const HWND selected = reinterpret_cast<HWND>(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 @@
     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<HRGN, win::DeleteObjectTraits<HRGN> >
-      scoped_hrgn(CreateRectRgn(0, 0, 0, 0));
-  int region_type = GetWindowRgn(selected, scoped_hrgn.Get());
+  const int region_type =
+      GetWindowRegionTypeWithBoundary(selected, &region_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 @@
   }
 
   if (region_type == SIMPLEREGION) {
-    RECT region_rect;
-    GetRgnBox(scoped_hrgn.Get(), &region_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/modules/desktop_capture/win/window_capture_utils.cc b/modules/desktop_capture/win/window_capture_utils.cc
index abcb6a6..07da6ee 100644
--- a/modules/desktop_capture/win/window_capture_utils.cc
+++ b/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 @@
   return true;
 }
 
+int GetWindowRegionTypeWithBoundary(HWND window, DesktopRect* result) {
+  win::ScopedGDIObject<HRGN, win::DeleteObjectTraits<HRGN>>
+      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/modules/desktop_capture/win/window_capture_utils.h b/modules/desktop_capture/win/window_capture_utils.h
index 255963e..c889c16 100644
--- a/modules/desktop_capture/win/window_capture_utils.h
+++ b/modules/desktop_capture/win/window_capture_utils.h
@@ -37,6 +37,10 @@
 // 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: