Return translated position in MouseCursorMonitor

This change returns translated position in the newly added overload
MouseCursorMonitor::Callback::OnMouseCursorPosition(DesktopVector) callback.

Meanwhile it also reduces the duplicate logic in Windows capturer
implementations. So except for the deprecated logic in MouseCursorMonitorWin,
all GetSystemMetrics() function calls are merged into GetScreenRect(),
GetFullscreenRect() and GetFullscreenTopLeft() functions.

Bug: webrtc:7950
Change-Id: Ic2a85a80b6947367bdd20d8f96f11e0f5c269006
Reviewed-on: https://chromium-review.googlesource.com/581951
Reviewed-by: Jamie Walch <jamiewalch@chromium.org>
Reviewed-by: Zijie He <zijiehe@chromium.org>
Commit-Queue: Zijie He <zijiehe@chromium.org>
Cr-Commit-Position: refs/heads/master@{#19157}
diff --git a/webrtc/modules/desktop_capture/BUILD.gn b/webrtc/modules/desktop_capture/BUILD.gn
index 24140fa..59c3179 100644
--- a/webrtc/modules/desktop_capture/BUILD.gn
+++ b/webrtc/modules/desktop_capture/BUILD.gn
@@ -218,6 +218,8 @@
     "win/d3d_device.h",
     "win/desktop.cc",
     "win/desktop.h",
+    "win/display_configuration_monitor.cc",
+    "win/display_configuration_monitor.h",
     "win/dxgi_adapter_duplicator.cc",
     "win/dxgi_adapter_duplicator.h",
     "win/dxgi_context.cc",
diff --git a/webrtc/modules/desktop_capture/cropping_window_capturer_win.cc b/webrtc/modules/desktop_capture/cropping_window_capturer_win.cc
index 2d2dee2..b7c71c8 100644
--- a/webrtc/modules/desktop_capture/cropping_window_capturer_win.cc
+++ b/webrtc/modules/desktop_capture/cropping_window_capturer_win.cc
@@ -201,7 +201,7 @@
   window_rect.IntersectWith(window_region_rect_);
 
   // Convert |window_rect| to be relative to the top-left of the virtual screen.
-  DesktopRect screen_rect(GetScreenRect(kFullDesktopScreenId, L""));
+  DesktopRect screen_rect(GetFullscreenRect());
   window_rect.IntersectWith(screen_rect);
   window_rect.Translate(-screen_rect.left(), -screen_rect.top());
   return window_rect;
diff --git a/webrtc/modules/desktop_capture/desktop_capture_types.h b/webrtc/modules/desktop_capture/desktop_capture_types.h
index f816773..46346b0 100644
--- a/webrtc/modules/desktop_capture/desktop_capture_types.h
+++ b/webrtc/modules/desktop_capture/desktop_capture_types.h
@@ -29,6 +29,8 @@
 //   - On Windows: integer display device index.
 //   - On OSX: CGDirectDisplayID cast to intptr_t.
 //   - On Linux (with X11): TBD.
+// On Windows, ScreenId is implementation dependent: sending a ScreenId from one
+// implementation to another usually won't work correctly.
 typedef intptr_t ScreenId;
 
 // The screen id corresponds to all screen combined together.
diff --git a/webrtc/modules/desktop_capture/mac/desktop_configuration.h b/webrtc/modules/desktop_capture/mac/desktop_configuration.h
index d54d0fb..73550ac 100644
--- a/webrtc/modules/desktop_capture/mac/desktop_configuration.h
+++ b/webrtc/modules/desktop_capture/mac/desktop_configuration.h
@@ -57,9 +57,11 @@
   MacDesktopConfiguration& operator=(const MacDesktopConfiguration& other);
   MacDesktopConfiguration& operator=(MacDesktopConfiguration&& other);
 
-  // Returns the desktop & display configurations in Cocoa-style "bottom-up"
+  // Returns the desktop & display configurations.
+  // If BottomLeftOrigin is used, the output is in Cocoa-style "bottom-up"
   // (the origin is the bottom-left of the primary monitor, and coordinates
-  // increase as you move up the screen).
+  // increase as you move up the screen). Otherwise, the configuration will be
+  // converted to follow top-left coordinate system as Windows and X11.
   static MacDesktopConfiguration GetCurrent(Origin origin);
 
   // Returns true if the given desktop configuration equals this one.
diff --git a/webrtc/modules/desktop_capture/mouse_cursor_monitor_mac.mm b/webrtc/modules/desktop_capture/mouse_cursor_monitor_mac.mm
index 7bb6b2c..2bb06b7 100644
--- a/webrtc/modules/desktop_capture/mouse_cursor_monitor_mac.mm
+++ b/webrtc/modules/desktop_capture/mouse_cursor_monitor_mac.mm
@@ -241,15 +241,15 @@
         state = OUTSIDE;
         position.set(-1, -1);
       }
-    } else {
-      position.subtract(configuration.bounds.top_left());
     }
   }
   // Convert Density Independent Pixel to physical pixel.
   position = DesktopVector(round(position.x() * scale),
                            round(position.y() * scale));
+  // TODO(zijiehe): Remove this overload.
   callback_->OnMouseCursorPosition(state, position);
-  callback_->OnMouseCursorPosition(position);
+  callback_->OnMouseCursorPosition(
+      position.subtract(configuration.bounds.top_left()));
 }
 
 void MouseCursorMonitorMac::CaptureImage(float scale) {
diff --git a/webrtc/modules/desktop_capture/mouse_cursor_monitor_win.cc b/webrtc/modules/desktop_capture/mouse_cursor_monitor_win.cc
index ebf00ac..43174cb 100644
--- a/webrtc/modules/desktop_capture/mouse_cursor_monitor_win.cc
+++ b/webrtc/modules/desktop_capture/mouse_cursor_monitor_win.cc
@@ -20,6 +20,7 @@
 #include "webrtc/modules/desktop_capture/desktop_geometry.h"
 #include "webrtc/modules/desktop_capture/mouse_cursor.h"
 #include "webrtc/modules/desktop_capture/win/cursor.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"
 
@@ -162,8 +163,10 @@
     position = position.subtract(rect.top_left());
   }
 
+  // TODO(zijiehe): Remove this overload.
   callback_->OnMouseCursorPosition(inside ? INSIDE : OUTSIDE, position);
-  callback_->OnMouseCursorPosition(position);
+  callback_->OnMouseCursorPosition(
+      position.subtract(GetFullscreenRect().top_left()));
 }
 
 DesktopRect MouseCursorMonitorWin::GetScreenRect() {
diff --git a/webrtc/modules/desktop_capture/mouse_cursor_monitor_x11.cc b/webrtc/modules/desktop_capture/mouse_cursor_monitor_x11.cc
index 9b30c49..edde01c 100644
--- a/webrtc/modules/desktop_capture/mouse_cursor_monitor_x11.cc
+++ b/webrtc/modules/desktop_capture/mouse_cursor_monitor_x11.cc
@@ -202,7 +202,10 @@
     }
 
     const DesktopVector position(win_x, win_y);
+    // TODO(zijiehe): Remove this overload.
     callback_->OnMouseCursorPosition(state, position);
+    // X11 always starts the coordinate from (0, 0), so we do not need to
+    // translate here.
     callback_->OnMouseCursorPosition(position);
   }
 }
diff --git a/webrtc/modules/desktop_capture/resolution_change_detector.h b/webrtc/modules/desktop_capture/resolution_change_detector.h
index 6ccf8a7..f82c390 100644
--- a/webrtc/modules/desktop_capture/resolution_change_detector.h
+++ b/webrtc/modules/desktop_capture/resolution_change_detector.h
@@ -17,7 +17,12 @@
 
 class ResolutionChangeDetector {
  public:
+  // Checks whether the |size| has been changed comparing to the |size| passed
+  // in during last IsChanged() call. This function won't return false for the
+  // first time after construction or Reset() call.
   bool IsChanged(DesktopSize size);
+
+  // Resets to the initial state.
   void Reset();
 
  private:
diff --git a/webrtc/modules/desktop_capture/win/display_configuration_monitor.cc b/webrtc/modules/desktop_capture/win/display_configuration_monitor.cc
new file mode 100644
index 0000000..5685d95
--- /dev/null
+++ b/webrtc/modules/desktop_capture/win/display_configuration_monitor.cc
@@ -0,0 +1,37 @@
+/*
+ *  Copyright (c) 2017 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/win/display_configuration_monitor.h"
+
+#include "webrtc/modules/desktop_capture/win/screen_capture_utils.h"
+
+namespace webrtc {
+
+bool DisplayConfigurationMonitor::IsChanged() {
+  DesktopRect rect = GetFullscreenRect();
+  if (!initialized_) {
+    initialized_ = true;
+    rect_ = rect;
+    return false;
+  }
+
+  if (rect.equals(rect_)) {
+    return false;
+  }
+
+  rect_ = rect;
+  return true;
+}
+
+void DisplayConfigurationMonitor::Reset() {
+  initialized_ = false;
+}
+
+}  // namespace webrtc
diff --git a/webrtc/modules/desktop_capture/win/display_configuration_monitor.h b/webrtc/modules/desktop_capture/win/display_configuration_monitor.h
new file mode 100644
index 0000000..d13b45e
--- /dev/null
+++ b/webrtc/modules/desktop_capture/win/display_configuration_monitor.h
@@ -0,0 +1,38 @@
+/*
+ *  Copyright (c) 2017 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_WIN_DISPLAY_CONFIGURATION_MONITOR_H_
+#define WEBRTC_MODULES_DESKTOP_CAPTURE_WIN_DISPLAY_CONFIGURATION_MONITOR_H_
+
+#include "webrtc/modules/desktop_capture/desktop_geometry.h"
+
+namespace webrtc {
+
+// A passive monitor to detect the change of display configuration on a Windows
+// system.
+// TODO(zijiehe): Also check for pixel format changes.
+class DisplayConfigurationMonitor {
+ public:
+  // Checks whether the change of display configuration has happened after last
+  // IsChanged() call. This function won't return false for the first time after
+  // constructor or Reset() call.
+  bool IsChanged();
+
+  // Resets to the initial state.
+  void Reset();
+
+ private:
+  DesktopRect rect_;
+  bool initialized_ = false;
+};
+
+}  // namespace webrtc
+
+#endif  // WEBRTC_MODULES_DESKTOP_CAPTURE_WIN_DISPLAY_CONFIGURATION_MONITOR_H_
diff --git a/webrtc/modules/desktop_capture/win/dxgi_duplicator_controller.cc b/webrtc/modules/desktop_capture/win/dxgi_duplicator_controller.cc
index 0cefb86..4a6ab8e 100644
--- a/webrtc/modules/desktop_capture/win/dxgi_duplicator_controller.cc
+++ b/webrtc/modules/desktop_capture/win/dxgi_duplicator_controller.cc
@@ -137,8 +137,7 @@
   // TODO(zijiehe): Confirm whether IDXGIOutput::GetDesc() and
   // IDXGIOutputDuplication::GetDesc() can detect the resolution change without
   // reinitialization.
-  if (resolution_change_detector_.IsChanged(
-          GetScreenRect(kFullDesktopScreenId, std::wstring()).size())) {
+  if (display_configuration_monitor_.IsChanged()) {
     Deinitialize();
   }
 
@@ -266,7 +265,7 @@
 void DxgiDuplicatorController::Deinitialize() {
   desktop_rect_ = DesktopRect();
   duplicators_.clear();
-  resolution_change_detector_.Reset();
+  display_configuration_monitor_.Reset();
 }
 
 bool DxgiDuplicatorController::ContextExpired(
diff --git a/webrtc/modules/desktop_capture/win/dxgi_duplicator_controller.h b/webrtc/modules/desktop_capture/win/dxgi_duplicator_controller.h
index 8ea7f18..ddf02a8 100644
--- a/webrtc/modules/desktop_capture/win/dxgi_duplicator_controller.h
+++ b/webrtc/modules/desktop_capture/win/dxgi_duplicator_controller.h
@@ -18,9 +18,9 @@
 #include <vector>
 
 #include "webrtc/modules/desktop_capture/desktop_geometry.h"
-#include "webrtc/modules/desktop_capture/resolution_change_detector.h"
 #include "webrtc/modules/desktop_capture/shared_desktop_frame.h"
 #include "webrtc/modules/desktop_capture/win/d3d_device.h"
+#include "webrtc/modules/desktop_capture/win/display_configuration_monitor.h"
 #include "webrtc/modules/desktop_capture/win/dxgi_adapter_duplicator.h"
 #include "webrtc/modules/desktop_capture/win/dxgi_context.h"
 #include "webrtc/modules/desktop_capture/win/dxgi_frame.h"
@@ -224,7 +224,7 @@
   DesktopVector dpi_;
   std::vector<DxgiAdapterDuplicator> duplicators_;
   D3dInfo d3d_info_;
-  ResolutionChangeDetector resolution_change_detector_;
+  DisplayConfigurationMonitor display_configuration_monitor_;
   // A number to indicate how many succeeded duplications have been performed.
   uint32_t succeeded_duplications_ = 0;
 };
diff --git a/webrtc/modules/desktop_capture/win/screen_capture_utils.cc b/webrtc/modules/desktop_capture/win/screen_capture_utils.cc
index e640bde..a871845 100644
--- a/webrtc/modules/desktop_capture/win/screen_capture_utils.cc
+++ b/webrtc/modules/desktop_capture/win/screen_capture_utils.cc
@@ -65,13 +65,17 @@
   return !!enum_result;
 }
 
+DesktopRect GetFullscreenRect() {
+  return DesktopRect::MakeXYWH(GetSystemMetrics(SM_XVIRTUALSCREEN),
+                               GetSystemMetrics(SM_YVIRTUALSCREEN),
+                               GetSystemMetrics(SM_CXVIRTUALSCREEN),
+                               GetSystemMetrics(SM_CYVIRTUALSCREEN));
+}
+
 DesktopRect GetScreenRect(DesktopCapturer::SourceId screen,
                           const std::wstring& device_key) {
   if (screen == kFullDesktopScreenId) {
-    return DesktopRect::MakeXYWH(GetSystemMetrics(SM_XVIRTUALSCREEN),
-                                 GetSystemMetrics(SM_YVIRTUALSCREEN),
-                                 GetSystemMetrics(SM_CXVIRTUALSCREEN),
-                                 GetSystemMetrics(SM_CYVIRTUALSCREEN));
+    return GetFullscreenRect();
   }
 
   DISPLAY_DEVICE device;
diff --git a/webrtc/modules/desktop_capture/win/screen_capture_utils.h b/webrtc/modules/desktop_capture/win/screen_capture_utils.h
index 73754b2..fdbf633 100644
--- a/webrtc/modules/desktop_capture/win/screen_capture_utils.h
+++ b/webrtc/modules/desktop_capture/win/screen_capture_utils.h
@@ -32,6 +32,10 @@
 // id.
 bool IsScreenValid(DesktopCapturer::SourceId screen, std::wstring* device_key);
 
+// Get the rect of the entire system in system coordinate system. I.e. the
+// primary monitor always starts from (0, 0).
+DesktopRect GetFullscreenRect();
+
 // Get the rect of the screen identified by |screen|, relative to the primary
 // display's top-left. If the screen device key does not match |device_key|, or
 // the screen does not exist, or any error happens, an empty rect is returned.
diff --git a/webrtc/modules/desktop_capture/win/screen_capturer_win_gdi.cc b/webrtc/modules/desktop_capture/win/screen_capturer_win_gdi.cc
index 44c81ff..427cb93 100644
--- a/webrtc/modules/desktop_capture/win/screen_capturer_win_gdi.cc
+++ b/webrtc/modules/desktop_capture/win/screen_capturer_win_gdi.cc
@@ -148,14 +148,8 @@
     }
   }
 
-  // If the display bounds have changed then recreate GDI resources.
-  // TODO(wez): Also check for pixel format changes.
-  DesktopRect screen_rect(DesktopRect::MakeXYWH(
-      GetSystemMetrics(SM_XVIRTUALSCREEN),
-      GetSystemMetrics(SM_YVIRTUALSCREEN),
-      GetSystemMetrics(SM_CXVIRTUALSCREEN),
-      GetSystemMetrics(SM_CYVIRTUALSCREEN)));
-  if (!screen_rect.equals(desktop_dc_rect_)) {
+  // If the display configurations have changed then recreate GDI resources.
+  if (display_configuration_monitor_.IsChanged()) {
     if (desktop_dc_) {
       ReleaseDC(NULL, desktop_dc_);
       desktop_dc_ = nullptr;
@@ -164,7 +158,6 @@
       DeleteDC(memory_dc_);
       memory_dc_ = nullptr;
     }
-    desktop_dc_rect_ = DesktopRect();
   }
 
   if (!desktop_dc_) {
@@ -176,8 +169,6 @@
     memory_dc_ = CreateCompatibleDC(desktop_dc_);
     RTC_CHECK(memory_dc_);
 
-    desktop_dc_rect_ = screen_rect;
-
     // Make sure the frame buffers will be reallocated.
     queue_.Reset();
   }
diff --git a/webrtc/modules/desktop_capture/win/screen_capturer_win_gdi.h b/webrtc/modules/desktop_capture/win/screen_capturer_win_gdi.h
index 70a939d..6822895 100644
--- a/webrtc/modules/desktop_capture/win/screen_capturer_win_gdi.h
+++ b/webrtc/modules/desktop_capture/win/screen_capturer_win_gdi.h
@@ -18,6 +18,7 @@
 #include "webrtc/modules/desktop_capture/desktop_capturer.h"
 #include "webrtc/modules/desktop_capture/screen_capture_frame_queue.h"
 #include "webrtc/modules/desktop_capture/shared_desktop_frame.h"
+#include "webrtc/modules/desktop_capture/win/display_configuration_monitor.h"
 #include "webrtc/modules/desktop_capture/win/scoped_thread_desktop.h"
 #include "webrtc/rtc_base/constructormagic.h"
 
@@ -69,9 +70,7 @@
   // Queue of the frames buffers.
   ScreenCaptureFrameQueue<SharedDesktopFrame> queue_;
 
-  // Rectangle describing the bounds of the desktop device context, relative to
-  // the primary display's top-left.
-  DesktopRect desktop_dc_rect_;
+  DisplayConfigurationMonitor display_configuration_monitor_;
 
   HMODULE dwmapi_library_ = NULL;
   DwmEnableCompositionFunc composition_func_ = nullptr;
diff --git a/webrtc/modules/desktop_capture/win/window_capture_utils.h b/webrtc/modules/desktop_capture/win/window_capture_utils.h
index c13cad7..8f59c12 100644
--- a/webrtc/modules/desktop_capture/win/window_capture_utils.h
+++ b/webrtc/modules/desktop_capture/win/window_capture_utils.h
@@ -18,7 +18,9 @@
 // Output the window rect, with the left/right/bottom frame border cropped if
 // the window is maximized. |cropped_rect| is the cropped rect relative to the
 // desktop. |original_rect| is the original rect returned from GetWindowRect.
-// Returns true if all API calls succeeded.
+// Returns true if all API calls succeeded. The returned DesktopRect is in
+// system coordinates, i.e. the primary monitor on the system always starts from
+// (0, 0).
 bool GetCroppedWindowRect(HWND window,
                           DesktopRect* cropped_rect,
                           DesktopRect* original_rect);