Attach top-left to DesktopFrames generated by DesktopCapturer implementations

This change attaches top-left to the DesktopFrames generated by DesktopCapturer
implementations. Some implementations won't need to attach the top-left because
of the platform specification, e.g. coordinates in X11 always starts from
(0, 0), and we support only one screen.

After this change, we can use the new MouseCursorMonitor::Create() function in
DesktopCaptureDevice.

Bug: webrtc:7950
Change-Id: I82c24f4dd9451e32afafb6474f82c32cadcb425c
Reviewed-on: https://chromium-review.googlesource.com/644787
Reviewed-by: Jamie Walch <jamiewalch@chromium.org>
Commit-Queue: Zijie He <zijiehe@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#19675}
Cr-Mirrored-From: https://chromium.googlesource.com/external/webrtc
Cr-Mirrored-Commit: 7fdf857d261539b4c03c90ddab1b1256b099dc6a
diff --git a/modules/desktop_capture/mac/window_list_utils.cc b/modules/desktop_capture/mac/window_list_utils.cc
index 10c12c1..0bd6d5a 100644
--- a/modules/desktop_capture/mac/window_list_utils.cc
+++ b/modules/desktop_capture/mac/window_list_utils.cc
@@ -21,6 +21,44 @@
 
 namespace webrtc {
 
+namespace {
+
+// Get CFDictionaryRef from |id| and call |on_window| against it. This function
+// returns false if native APIs fail, typically it indicates that the |id| does
+// not represent a window. |on_window| will not be called if false is returned
+// from this function.
+bool GetWindowRef(CGWindowID id,
+                  rtc::FunctionView<void(CFDictionaryRef)> on_window) {
+  RTC_DCHECK(on_window);
+
+  // TODO(zijiehe): |id| is a 32-bit integer, casting it to an array seems not
+  // safe enough. Maybe we should create a new
+  // const void* arr[] = {
+  //   reinterpret_cast<void*>(id) }
+  // };
+  CFArrayRef window_id_array =
+      CFArrayCreate(NULL, reinterpret_cast<const void**>(&id), 1, NULL);
+  CFArrayRef window_array =
+      CGWindowListCreateDescriptionFromArray(window_id_array);
+
+  bool result = false;
+  // TODO(zijiehe): CFArrayGetCount(window_array) should always return 1.
+  // Otherwise, we should treat it as failure.
+  if (window_array && CFArrayGetCount(window_array)) {
+    on_window(reinterpret_cast<CFDictionaryRef>(
+        CFArrayGetValueAtIndex(window_array, 0)));
+    result = true;
+  }
+
+  if (window_array) {
+    CFRelease(window_array);
+  }
+  CFRelease(window_id_array);
+  return result;
+}
+
+}  // namespace
+
 bool GetWindowList(rtc::FunctionView<bool(CFDictionaryRef)> on_window,
                    bool ignore_minimized) {
   RTC_DCHECK(on_window);
@@ -145,21 +183,14 @@
 }
 
 bool IsWindowOnScreen(CGWindowID id) {
-  CFArrayRef window_id_array =
-      CFArrayCreate(NULL, reinterpret_cast<const void **>(&id), 1, NULL);
-  CFArrayRef window_array =
-      CGWindowListCreateDescriptionFromArray(window_id_array);
-  bool on_screen = false;
-
-  if (window_array && CFArrayGetCount(window_array)) {
-    on_screen = IsWindowOnScreen(reinterpret_cast<CFDictionaryRef>(
-        CFArrayGetValueAtIndex(window_array, 0)));
+  bool on_screen;
+  if (GetWindowRef(id,
+                   [&on_screen](CFDictionaryRef window) {
+                     on_screen = IsWindowOnScreen(window);
+                   })) {
+    return on_screen;
   }
-
-  CFRelease(window_id_array);
-  CFRelease(window_array);
-
-  return on_screen;
+  return false;
 }
 
 std::string GetWindowTitle(CFDictionaryRef window) {
@@ -205,4 +236,15 @@
                                gc_window_rect.size.height);
 }
 
+DesktopRect GetWindowBounds(CGWindowID id) {
+  DesktopRect result;
+  if (GetWindowRef(id,
+                   [&result](CFDictionaryRef window) {
+                     result = GetWindowBounds(window);
+                   })) {
+    return result;
+  }
+  return DesktopRect();
+}
+
 }  // namespace webrtc
diff --git a/modules/desktop_capture/mac/window_list_utils.h b/modules/desktop_capture/mac/window_list_utils.h
index 5e204a7..be7aeea 100644
--- a/modules/desktop_capture/mac/window_list_utils.h
+++ b/modules/desktop_capture/mac/window_list_utils.h
@@ -58,6 +58,11 @@
 // from (0, 0).
 DesktopRect GetWindowBounds(CFDictionaryRef window);
 
+// Returns the bounds of window with |id|. If |id| does not represent a window
+// or the bounds cannot be retrieved, this function returns an empty
+// DesktopRect. The returned DesktopRect is in system coordinates.
+DesktopRect GetWindowBounds(CGWindowID id);
+
 }  // namespace webrtc
 
 #endif  // WEBRTC_MODULES_DESKTOP_CAPTURE_MAC_WINDOW_LIST_UTILS_H_
diff --git a/modules/desktop_capture/screen_capturer_mac.mm b/modules/desktop_capture/screen_capturer_mac.mm
index 66b04f7..9fab819 100644
--- a/modules/desktop_capture/screen_capturer_mac.mm
+++ b/modules/desktop_capture/screen_capturer_mac.mm
@@ -373,9 +373,7 @@
             frame->data() + (frame->size().height() - 1) * frame->stride(),
             frame->shared_memory()) {
     original_frame_ = std::move(frame);
-    set_dpi(original_frame_->dpi());
-    set_capture_time_ms(original_frame_->capture_time_ms());
-    mutable_updated_region()->Swap(original_frame_->mutable_updated_region());
+    MoveFrameInfoFrom(original_frame_.get());
   }
   ~InvertedDesktopFrame() override {}
 
@@ -494,6 +492,15 @@
   if (flip)
     new_frame.reset(new InvertedDesktopFrame(std::move(new_frame)));
 
+  if (current_display_) {
+    const MacDisplayConfiguration* config =
+        desktop_config_.FindDisplayConfigurationById(current_display_);
+    if (config) {
+      new_frame->set_top_left(config->bounds.top_left().subtract(
+          desktop_config_.bounds.top_left()));
+    }
+  }
+
   helper_.set_size_most_recent(new_frame->size());
 
   // Signal that we are done capturing data from the display framebuffer,
diff --git a/modules/desktop_capture/win/dxgi_duplicator_controller.cc b/modules/desktop_capture/win/dxgi_duplicator_controller.cc
index 4a6ab8e..38bf437 100644
--- a/modules/desktop_capture/win/dxgi_duplicator_controller.cc
+++ b/modules/desktop_capture/win/dxgi_duplicator_controller.cc
@@ -333,6 +333,7 @@
     } else {
       if (duplicators_[i].DuplicateMonitor(&context->contexts[i], monitor_id,
                                            target)) {
+        target->set_top_left(duplicators_[i].ScreenRect(monitor_id).top_left());
         return true;
       }
       return false;
diff --git a/modules/desktop_capture/win/screen_capturer_win_gdi.cc b/modules/desktop_capture/win/screen_capturer_win_gdi.cc
index 427cb93..b342e9f 100644
--- a/modules/desktop_capture/win/screen_capturer_win_gdi.cc
+++ b/modules/desktop_capture/win/screen_capturer_win_gdi.cc
@@ -195,6 +195,7 @@
       return false;
     queue_.ReplaceCurrentFrame(SharedDesktopFrame::Wrap(std::move(buffer)));
   }
+  queue_.current_frame()->set_top_left(screen_rect.top_left());
 
   // Select the target bitmap into the memory dc and copy the rect from desktop
   // to memory.
diff --git a/modules/desktop_capture/window_capturer_mac.mm b/modules/desktop_capture/window_capturer_mac.mm
index 4f1c191..fa1ddcd 100644
--- a/modules/desktop_capture/window_capturer_mac.mm
+++ b/modules/desktop_capture/window_capturer_mac.mm
@@ -204,6 +204,14 @@
 
   frame->mutable_updated_region()->SetRect(
       DesktopRect::MakeSize(frame->size()));
+  DesktopVector top_left = GetWindowBounds(on_screen_window).top_left();
+  if (configuration_monitor_) {
+    configuration_monitor_->Lock();
+    auto configuration = configuration_monitor_->desktop_configuration();
+    configuration_monitor_->Unlock();
+    top_left = top_left.subtract(configuration.bounds.top_left());
+  }
+  frame->set_top_left(top_left);
 
   callback_->OnCaptureResult(Result::SUCCESS, std::move(frame));
 
diff --git a/modules/desktop_capture/window_capturer_win.cc b/modules/desktop_capture/window_capturer_win.cc
index 77a6cce..01b4e4d 100644
--- a/modules/desktop_capture/window_capturer_win.cc
+++ b/modules/desktop_capture/window_capturer_win.cc
@@ -316,6 +316,8 @@
 
   frame->mutable_updated_region()->SetRect(
       DesktopRect::MakeSize(frame->size()));
+  frame->set_top_left(
+      cropped_rect.top_left().subtract(GetFullscreenRect().top_left()));
 
   if (result) {
     callback_->OnCaptureResult(Result::SUCCESS, std::move(frame));
diff --git a/modules/desktop_capture/window_capturer_x11.cc b/modules/desktop_capture/window_capturer_x11.cc
index 5d01a15..987ceb7 100644
--- a/modules/desktop_capture/window_capturer_x11.cc
+++ b/modules/desktop_capture/window_capturer_x11.cc
@@ -216,6 +216,7 @@
 
   frame->mutable_updated_region()->SetRect(
       DesktopRect::MakeSize(frame->size()));
+  frame->set_top_left(x_server_pixel_buffer_.window_rect().top_left());
 
   callback_->OnCaptureResult(Result::SUCCESS, std::move(frame));
 }