Add blink code handling getDisplayMedia()

This is the first CL in adding getDisplayMedia() support in chromium. See the
bug and linked design doc for the detailed plan.

This CL adds getDisplayMedia() interface behind runtime enabled features flag
"GetDisplayMedia". This call will use the same call stack as getUserMedia() but
have different media request type and handling of constraints.
- Adds WebUserMediaRequest enums to differentiate this call.
- Adds specific handling of constraints in UserMediaRequest::Create(). As
defined in the spec, this accepts empty constraints.
- Currently ends up in a NotSupported error as chromium changes are landing.
- Adds first set of Layout Tests to check these expectations.

Intent To Implement:
https://groups.google.com/a/chromium.org/forum/#!msg/Blink-dev/j7k2nI_9nng/OE6IvgJyAQAJ

Bug: 326740
Change-Id: I03c54cab259a57db99449d9c4510c484f22c5b93
Reviewed-on: https://chromium-review.googlesource.com/1155942
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Reviewed-by: Guido Urdaneta <guidou@chromium.org>
Commit-Queue: Emircan Uysaler <emircan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#580733}
diff --git a/third_party/WebKit/LayoutTests/fast/mediastream/getdisplaymedia.html b/third_party/WebKit/LayoutTests/fast/mediastream/getdisplaymedia.html
new file mode 100644
index 0000000..32c1b38
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/mediastream/getdisplaymedia.html
@@ -0,0 +1,22 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+</head>
+<body>
+<script>
+
+promise_test(function() {
+  assert_idl_attribute(navigator, 'getDisplayMedia');
+
+  return navigator.getDisplayMedia().then(function(s) {
+    fail('getDisplayMedia should have failed');
+  }).catch(function(e) {
+    assert_equals(e.name, 'NotSupportedError');
+  });
+}, 'getDisplayMedia() call');
+
+</script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
index 99a7720..7870392 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -4665,6 +4665,7 @@
     getter xr
     method constructor
     method getBattery
+    method getDisplayMedia
     method getGamepads
     method getInstalledRelatedApps
     method getUserMedia
diff --git a/third_party/blink/public/web/web_user_media_request.h b/third_party/blink/public/web/web_user_media_request.h
index f7d6242..0196f53f 100644
--- a/third_party/blink/public/web/web_user_media_request.h
+++ b/third_party/blink/public/web/web_user_media_request.h
@@ -60,6 +60,11 @@
     kKillSwitchOn
   };
 
+  enum class MediaType {
+    kUserMedia,
+    kDisplayMedia,
+  };
+
   WebUserMediaRequest() = default;
   WebUserMediaRequest(const WebUserMediaRequest& request) { Assign(request); }
   ~WebUserMediaRequest() { Reset(); }
@@ -74,6 +79,7 @@
   bool Equals(const WebUserMediaRequest&) const;
   void Assign(const WebUserMediaRequest&);
 
+  MediaType MediaRequestType() const;
   bool Audio() const;
   bool Video() const;
   WebMediaConstraints AudioConstraints() const;
diff --git a/third_party/blink/renderer/modules/exported/web_user_media_request.cc b/third_party/blink/renderer/modules/exported/web_user_media_request.cc
index ad2a312..20f62db 100644
--- a/third_party/blink/renderer/modules/exported/web_user_media_request.cc
+++ b/third_party/blink/renderer/modules/exported/web_user_media_request.cc
@@ -57,6 +57,11 @@
   private_.Reset();
 }
 
+WebUserMediaRequest::MediaType WebUserMediaRequest::MediaRequestType() const {
+  DCHECK(!IsNull());
+  return private_->MediaRequestType();
+}
+
 bool WebUserMediaRequest::Audio() const {
   DCHECK(!IsNull());
   return private_->Audio();
diff --git a/third_party/blink/renderer/modules/mediastream/BUILD.gn b/third_party/blink/renderer/modules/mediastream/BUILD.gn
index eac66d3..0503186 100644
--- a/third_party/blink/renderer/modules/mediastream/BUILD.gn
+++ b/third_party/blink/renderer/modules/mediastream/BUILD.gn
@@ -30,6 +30,8 @@
     "media_stream_track_content_hint.h",
     "media_stream_track_event.cc",
     "media_stream_track_event.h",
+    "navigator_display_media.cc",
+    "navigator_display_media.h",
     "navigator_media_stream.cc",
     "navigator_media_stream.h",
     "navigator_user_media.cc",
diff --git a/third_party/blink/renderer/modules/mediastream/media_devices.cc b/third_party/blink/renderer/modules/mediastream/media_devices.cc
index 0d83576..609d029b 100644
--- a/third_party/blink/renderer/modules/mediastream/media_devices.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_devices.cc
@@ -20,7 +20,6 @@
 #include "third_party/blink/renderer/modules/mediastream/media_stream_constraints.h"
 #include "third_party/blink/renderer/modules/mediastream/navigator_media_stream.h"
 #include "third_party/blink/renderer/modules/mediastream/user_media_controller.h"
-#include "third_party/blink/renderer/modules/mediastream/user_media_request.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 #include "third_party/blink/renderer/platform/wtf/functional.h"
 
@@ -105,6 +104,16 @@
 ScriptPromise MediaDevices::getUserMedia(ScriptState* script_state,
                                          const MediaStreamConstraints& options,
                                          ExceptionState& exception_state) {
+  return SendUserMediaRequest(script_state,
+                              WebUserMediaRequest::MediaType::kUserMedia,
+                              options, exception_state);
+}
+
+ScriptPromise MediaDevices::SendUserMediaRequest(
+    ScriptState* script_state,
+    WebUserMediaRequest::MediaType media_type,
+    const MediaStreamConstraints& options,
+    ExceptionState& exception_state) {
   ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
   PromiseResolverCallbacks* callbacks =
       PromiseResolverCallbacks::Create(resolver);
@@ -121,7 +130,7 @@
 
   MediaErrorState error_state;
   UserMediaRequest* request = UserMediaRequest::Create(
-      document, user_media, options, callbacks, error_state);
+      document, user_media, media_type, options, callbacks, error_state);
   if (!request) {
     DCHECK(error_state.HadException());
     if (error_state.CanGenerateException()) {
diff --git a/third_party/blink/renderer/modules/mediastream/media_devices.h b/third_party/blink/renderer/modules/mediastream/media_devices.h
index 00171c2..b8a99e5e3 100644
--- a/third_party/blink/renderer/modules/mediastream/media_devices.h
+++ b/third_party/blink/renderer/modules/mediastream/media_devices.h
@@ -13,6 +13,7 @@
 #include "third_party/blink/renderer/core/dom/pausable_object.h"
 #include "third_party/blink/renderer/modules/event_target_modules.h"
 #include "third_party/blink/renderer/modules/mediastream/media_device_info.h"
+#include "third_party/blink/renderer/modules/mediastream/user_media_request.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
 #include "third_party/blink/renderer/platform/async_method_runner.h"
 #include "third_party/blink/renderer/platform/heap/heap_allocator.h"
@@ -44,6 +45,10 @@
   ScriptPromise getUserMedia(ScriptState*,
                              const MediaStreamConstraints&,
                              ExceptionState&);
+  ScriptPromise SendUserMediaRequest(ScriptState*,
+                                     WebUserMediaRequest::MediaType,
+                                     const MediaStreamConstraints&,
+                                     ExceptionState&);
 
   // EventTarget overrides.
   const AtomicString& InterfaceName() const override;
diff --git a/third_party/blink/renderer/modules/mediastream/navigator_display_media.cc b/third_party/blink/renderer/modules/mediastream/navigator_display_media.cc
new file mode 100644
index 0000000..a78d87f
--- /dev/null
+++ b/third_party/blink/renderer/modules/mediastream/navigator_display_media.cc
@@ -0,0 +1,33 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/mediastream/navigator_display_media.h"
+
+#include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
+#include "third_party/blink/renderer/core/dom/dom_exception.h"
+#include "third_party/blink/renderer/modules/mediastream/media_devices.h"
+#include "third_party/blink/renderer/modules/mediastream/navigator_user_media.h"
+
+namespace blink {
+
+ScriptPromise NavigatorDisplayMedia::getDisplayMedia(
+    ScriptState* script_state,
+    Navigator& navigator,
+    const MediaStreamConstraints& options,
+    ExceptionState& exception_state) {
+  MediaDevices* const media_devices =
+      NavigatorUserMedia::mediaDevices(navigator);
+  if (!media_devices) {
+    return ScriptPromise::RejectWithDOMException(
+        script_state, DOMException::Create(DOMExceptionCode::kNotSupportedError,
+                                           "Current frame is detached."));
+  }
+
+  return media_devices->SendUserMediaRequest(
+      script_state, WebUserMediaRequest::MediaType::kDisplayMedia, options,
+      exception_state);
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/modules/mediastream/navigator_display_media.h b/third_party/blink/renderer/modules/mediastream/navigator_display_media.h
new file mode 100644
index 0000000..ab22babc
--- /dev/null
+++ b/third_party/blink/renderer/modules/mediastream/navigator_display_media.h
@@ -0,0 +1,31 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_NAVIGATOR_DISPLAY_MEDIA_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_NAVIGATOR_DISPLAY_MEDIA_H_
+
+#include "third_party/blink/renderer/platform/wtf/allocator.h"
+
+#include "third_party/blink/renderer/core/frame/navigator.h"
+
+namespace blink {
+
+class ExceptionState;
+class MediaStreamConstraints;
+class ScriptPromise;
+class ScriptState;
+
+class NavigatorDisplayMedia {
+  STATIC_ONLY(NavigatorDisplayMedia);
+
+ public:
+  static ScriptPromise getDisplayMedia(ScriptState*,
+                                       Navigator&,
+                                       const MediaStreamConstraints&,
+                                       ExceptionState&);
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_NAVIGATOR_DISPLAY_MEDIA_H_
diff --git a/third_party/blink/renderer/modules/mediastream/navigator_display_media.idl b/third_party/blink/renderer/modules/mediastream/navigator_display_media.idl
new file mode 100644
index 0000000..8afdc7e
--- /dev/null
+++ b/third_party/blink/renderer/modules/mediastream/navigator_display_media.idl
@@ -0,0 +1,12 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://w3c.github.io/mediacapture-screen-share/
+[
+    ImplementedAs = NavigatorDisplayMedia,
+    RuntimeEnabled = GetDisplayMedia
+] partial interface Navigator {
+    [CallWith = ScriptState, RaisesException] Promise<MediaStream>
+    getDisplayMedia(optional MediaStreamConstraints constraints);
+};
diff --git a/third_party/blink/renderer/modules/mediastream/user_media_client.cc b/third_party/blink/renderer/modules/mediastream/user_media_client.cc
index 2d82433..4573ac2 100644
--- a/third_party/blink/renderer/modules/mediastream/user_media_client.cc
+++ b/third_party/blink/renderer/modules/mediastream/user_media_client.cc
@@ -44,12 +44,14 @@
     : client_(client) {}
 
 void UserMediaClient::RequestUserMedia(UserMediaRequest* request) {
-  if (client_) {
+  // TODO(emircan): Hook up kDisplayMedia calls.
+  if (client_ && request->MediaRequestType() !=
+                     WebUserMediaRequest::MediaType::kDisplayMedia) {
     client_->RequestUserMedia(request);
-  } else {
-    request->Fail(WebUserMediaRequest::Error::kNotSupported,
-                  "User Media support is disabled");
+    return;
   }
+  request->Fail(WebUserMediaRequest::Error::kNotSupported,
+                "User Media support is disabled");
 }
 
 void UserMediaClient::CancelUserMediaRequest(UserMediaRequest* request) {
diff --git a/third_party/blink/renderer/modules/mediastream/user_media_request.cc b/third_party/blink/renderer/modules/mediastream/user_media_request.cc
index 71c2aa7..d145864 100644
--- a/third_party/blink/renderer/modules/mediastream/user_media_request.cc
+++ b/third_party/blink/renderer/modules/mediastream/user_media_request.cc
@@ -362,6 +362,7 @@
 UserMediaRequest* UserMediaRequest::Create(
     ExecutionContext* context,
     UserMediaController* controller,
+    WebUserMediaRequest::MediaType media_type,
     const MediaStreamConstraints& options,
     Callbacks* callbacks,
     MediaErrorState& error_state) {
@@ -375,10 +376,17 @@
   if (error_state.HadException())
     return nullptr;
 
-  if (audio.IsNull() && video.IsNull()) {
-    error_state.ThrowTypeError(
-        "At least one of audio and video must be requested");
-    return nullptr;
+  switch (media_type) {
+    case WebUserMediaRequest::MediaType::kUserMedia: {
+      if (audio.IsNull() && video.IsNull()) {
+        error_state.ThrowTypeError(
+            "At least one of audio and video must be requested");
+        return nullptr;
+      }
+      break;
+    }
+    case WebUserMediaRequest::MediaType::kDisplayMedia:
+      break;
   }
 
   if (!audio.IsNull())
@@ -386,7 +394,8 @@
   if (!video.IsNull())
     CountVideoConstraintUses(context, video);
 
-  return new UserMediaRequest(context, controller, audio, video, callbacks);
+  return new UserMediaRequest(context, controller, media_type, audio, video,
+                              callbacks);
 }
 
 UserMediaRequest* UserMediaRequest::Create(
@@ -396,23 +405,27 @@
     V8NavigatorUserMediaSuccessCallback* success_callback,
     V8NavigatorUserMediaErrorCallback* error_callback,
     MediaErrorState& error_state) {
-  return Create(context, controller, options,
-                V8Callbacks::Create(success_callback, error_callback),
+  return Create(context, controller, WebUserMediaRequest::MediaType::kUserMedia,
+                options, V8Callbacks::Create(success_callback, error_callback),
                 error_state);
 }
 
 UserMediaRequest* UserMediaRequest::CreateForTesting(
     const WebMediaConstraints& audio,
     const WebMediaConstraints& video) {
-  return new UserMediaRequest(nullptr, nullptr, audio, video, nullptr);
+  return new UserMediaRequest(nullptr, nullptr,
+                              WebUserMediaRequest::MediaType::kUserMedia, audio,
+                              video, nullptr);
 }
 
 UserMediaRequest::UserMediaRequest(ExecutionContext* context,
                                    UserMediaController* controller,
+                                   WebUserMediaRequest::MediaType media_type,
                                    WebMediaConstraints audio,
                                    WebMediaConstraints video,
                                    Callbacks* callbacks)
     : ContextLifecycleObserver(context),
+      media_type_(media_type),
       audio_(audio),
       video_(video),
       should_disable_hardware_noise_suppression_(
@@ -432,6 +445,10 @@
 
 UserMediaRequest::~UserMediaRequest() = default;
 
+WebUserMediaRequest::MediaType UserMediaRequest::MediaRequestType() const {
+  return media_type_;
+}
+
 bool UserMediaRequest::Audio() const {
   return !audio_.IsNull();
 }
diff --git a/third_party/blink/renderer/modules/mediastream/user_media_request.h b/third_party/blink/renderer/modules/mediastream/user_media_request.h
index 21c2f14..4809285 100644
--- a/third_party/blink/renderer/modules/mediastream/user_media_request.h
+++ b/third_party/blink/renderer/modules/mediastream/user_media_request.h
@@ -73,6 +73,7 @@
 
   static UserMediaRequest* Create(ExecutionContext*,
                                   UserMediaController*,
+                                  WebUserMediaRequest::MediaType media_type,
                                   const MediaStreamConstraints& options,
                                   Callbacks*,
                                   MediaErrorState&);
@@ -94,6 +95,7 @@
   void FailConstraint(const String& constraint_name, const String& message);
   void Fail(WebUserMediaRequest::Error name, const String& message);
 
+  WebUserMediaRequest::MediaType MediaRequestType() const;
   bool Audio() const;
   bool Video() const;
   WebMediaConstraints AudioConstraints() const;
@@ -115,10 +117,12 @@
  private:
   UserMediaRequest(ExecutionContext*,
                    UserMediaController*,
+                   WebUserMediaRequest::MediaType media_type,
                    WebMediaConstraints audio,
                    WebMediaConstraints video,
                    Callbacks*);
 
+  WebUserMediaRequest::MediaType media_type_;
   WebMediaConstraints audio_;
   WebMediaConstraints video_;
   bool should_disable_hardware_noise_suppression_;
diff --git a/third_party/blink/renderer/modules/modules_idl_files.gni b/third_party/blink/renderer/modules/modules_idl_files.gni
index d073108e..0eae7b43 100644
--- a/third_party/blink/renderer/modules/modules_idl_files.gni
+++ b/third_party/blink/renderer/modules/modules_idl_files.gni
@@ -737,6 +737,7 @@
           "mediasource/html_video_element_media_source.idl",
           "mediasource/url_media_source.idl",
           "mediastream/media_stream_track_content_hint.idl",
+          "mediastream/navigator_display_media.idl",
           "mediastream/navigator_media_stream.idl",
           "mediastream/navigator_user_media.idl",
           "mediastream/url_media_stream.idl",
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 324273ee..6f96506 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -564,6 +564,10 @@
       status: "experimental",
     },
     {
+      name: "GetDisplayMedia",
+      status: "experimental",
+    },
+    {
       name: "HeapCompaction",
       status: "stable",
     },