diff --git a/AUTHORS b/AUTHORS
index 479f949..93a5671e 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -591,6 +591,7 @@
 Salvatore Iovene <salvatore.iovene@intel.com>
 Sam Larison <qufighter@gmail.com>
 Sam McDonald <sam@sammcd.com>
+Sanggi Hong <sanggi.hong11@gmail.com>
 Sanghee Lee <sanghee.lee1992@gmail.com>
 Sanghyun Park <sh919.park@samsung.com>
 Sanghyup Lee <sh53.lee@samsung.com>
diff --git a/DEPS b/DEPS
index e2fcb3b..70a6856 100644
--- a/DEPS
+++ b/DEPS
@@ -44,7 +44,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '8ed0d57f4e2428b7c9c350a3f8c13be472b9f62e',
+  'v8_revision': 'cbeeb3ce17cc1b22c1adf850c6514525f617e149',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -64,7 +64,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '61f8e9c5aeb0d8cb5477e0248b685214746bada7',
+  'pdfium_revision': '50feafc7f367a87b7e4e689421eb7ae1484660d9',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
diff --git a/chrome/test/data/extensions/hangout_services_test.html b/chrome/test/data/extensions/hangout_services_test.html
index 8b9b9a73..ed1fcc5 100644
--- a/chrome/test/data/extensions/hangout_services_test.html
+++ b/chrome/test/data/extensions/hangout_services_test.html
@@ -20,7 +20,7 @@
 // Populates UI elements with initial contents.
 function populate() {
   populateSinks();
-  navigator.mediaDevices.enumerateDevices().then(populateSources);
+  MediaStreamTrack.getSources(populateSources);
 }
 
 // Populates the select box with information on all sinks and the
@@ -42,14 +42,14 @@
     });
 }
 
-function populateSources(devices) {
+function populateSources(sources) {
   var select = document.getElementById('selectSource');
-  for (var i = 0; i < devices.length; ++i) {
-    var device = devices[i];
-    if (device.kind == 'audioinput') {
+  for (var i = 0; i < sources.length; ++i) {
+    var source = sources[i];
+    if (source.kind == 'audio') {
       var option = document.createElement('option');
-      option.value = device.deviceId;
-      option.text = device.label + ' (' + device.deviceId + ')';
+      option.value = source.id;
+      option.text = source.label + ' (' + source.id + ')';
       select.add(option);
     }
   }
diff --git a/chrome/test/data/extensions/platform_apps/web_view/media_access/media_check_guest.html b/chrome/test/data/extensions/platform_apps/web_view/media_access/media_check_guest.html
index 85d7276..07164c0d 100644
--- a/chrome/test/data/extensions/platform_apps/web_view/media_access/media_check_guest.html
+++ b/chrome/test/data/extensions/platform_apps/web_view/media_access/media_check_guest.html
@@ -6,7 +6,7 @@
 <html>
   <head>
     <script type="text/javascript">
-      // A guest that requests media devices, which in turn checks for media
+      // A guest that requests media sources, which in turn checks for media
       // access permission.
       // Notifies the embedder when done via post message. Note that the
       // embedder has to initiate a postMessage first so that guest has a
@@ -23,7 +23,7 @@
         notifyEmbedder(JSON.stringify(['got-sources']));
       };
       var startTest = function() {
-        navigator.mediaDevices.enumerateDevices().then(onSourceInfo);
+        MediaStreamTrack.getSources(onSourceInfo);
       };
       var onPostMessageReceived = function(e) {
         var data = JSON.parse(e.data);
diff --git a/chrome/test/data/webrtc/media_devices.js b/chrome/test/data/webrtc/media_devices.js
index 0780dd5e..38a7238 100644
--- a/chrome/test/data/webrtc/media_devices.js
+++ b/chrome/test/data/webrtc/media_devices.js
@@ -11,7 +11,19 @@
  * Returns the list of devices available.
  */
 function getMediaDevices() {
-  navigator.mediaDevices.enumerateDevices().then(function(devices) {
+  navigator.getMediaDevices(function(devices) {
     returnToTest(JSON.stringify(devices));
   });
 }
+
+/**
+ * Queries for media sources on the current system using the getSources API.
+ *
+ * Returns the list of sources available.
+ */
+function getSources() {
+  MediaStreamTrack.getSources(function(sources) {
+    returnToTest(JSON.stringify(sources));
+  });
+}
+
diff --git a/components/test_runner/mock_web_media_stream_center.cc b/components/test_runner/mock_web_media_stream_center.cc
index 3848448..55c0c94 100644
--- a/components/test_runner/mock_web_media_stream_center.cc
+++ b/components/test_runner/mock_web_media_stream_center.cc
@@ -16,6 +16,8 @@
 #include "third_party/WebKit/public/platform/WebMediaStreamCenterClient.h"
 #include "third_party/WebKit/public/platform/WebMediaStreamSource.h"
 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
+#include "third_party/WebKit/public/platform/WebMediaStreamTrackSourcesRequest.h"
+#include "third_party/WebKit/public/platform/WebSourceInfo.h"
 #include "third_party/WebKit/public/platform/WebVector.h"
 
 namespace test_runner {
diff --git a/components/test_runner/mock_web_user_media_client.cc b/components/test_runner/mock_web_user_media_client.cc
index 3eace86..bc4e1bba 100644
--- a/components/test_runner/mock_web_user_media_client.cc
+++ b/components/test_runner/mock_web_user_media_client.cc
@@ -16,6 +16,8 @@
 #include "third_party/WebKit/public/platform/WebMediaStream.h"
 #include "third_party/WebKit/public/platform/WebMediaStreamSource.h"
 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
+#include "third_party/WebKit/public/platform/WebMediaStreamTrackSourcesRequest.h"
+#include "third_party/WebKit/public/platform/WebSourceInfo.h"
 #include "third_party/WebKit/public/platform/WebVector.h"
 #include "third_party/WebKit/public/web/WebDocument.h"
 #include "third_party/WebKit/public/web/WebMediaDevicesRequest.h"
@@ -27,6 +29,8 @@
 using blink::WebMediaStream;
 using blink::WebMediaStreamSource;
 using blink::WebMediaStreamTrack;
+using blink::WebMediaStreamTrackSourcesRequest;
+using blink::WebSourceInfo;
 using blink::WebString;
 using blink::WebUserMediaRequest;
 using blink::WebVector;
@@ -147,6 +151,41 @@
     media_device_change_observer_.didChangeMediaDevices();
 }
 
+void MockWebUserMediaClient::requestSources(
+    const blink::WebMediaStreamTrackSourcesRequest& request) {
+  struct {
+    const char* id;
+    WebSourceInfo::SourceKind kind;
+    const char* label;
+    WebSourceInfo::VideoFacingMode facing;
+  } test_sources[] = {
+    {
+      "device1",
+      WebSourceInfo::SourceKindAudio,
+      "Built-in microphone",
+      WebSourceInfo::VideoFacingModeNone,
+    },
+    {
+      "device2",
+      WebSourceInfo::SourceKindVideo,
+      "Build-in webcam",
+      WebSourceInfo::VideoFacingModeEnvironment,
+    },
+  };
+
+  WebVector<WebSourceInfo> sources(arraysize(test_sources));
+  for (size_t i = 0; i < arraysize(test_sources); ++i) {
+  sources[i].initialize(WebString::fromUTF8(test_sources[i].id),
+                        test_sources[i].kind,
+                        WebString::fromUTF8(test_sources[i].label),
+                        test_sources[i].facing);
+  }
+
+  delegate_->PostTask(base::Bind(
+      &WebMediaStreamTrackSourcesRequest::requestSucceeded,
+      base::Owned(new WebMediaStreamTrackSourcesRequest(request)), sources));
+}
+
 void MockWebUserMediaClient::setMediaDeviceChangeObserver(
     const blink::WebMediaDeviceChangeObserver& observer) {
   media_device_change_observer_ = observer;
diff --git a/components/test_runner/mock_web_user_media_client.h b/components/test_runner/mock_web_user_media_client.h
index 818db92..374e336 100644
--- a/components/test_runner/mock_web_user_media_client.h
+++ b/components/test_runner/mock_web_user_media_client.h
@@ -22,6 +22,7 @@
   void requestUserMedia(const blink::WebUserMediaRequest&) override;
   void cancelUserMediaRequest(const blink::WebUserMediaRequest&) override;
   void requestMediaDevices(const blink::WebMediaDevicesRequest&) override;
+  void requestSources(const blink::WebMediaStreamTrackSourcesRequest&) override;
   void setMediaDeviceChangeObserver(
       const blink::WebMediaDeviceChangeObserver&) override;
 
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 79cb7c2..2e0ca436 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -2241,7 +2241,7 @@
                  routing_id_));
 
 #if defined(ENABLE_WEBVR)
-  GetInterfaceRegistry()->AddInterface<device::VRService>(
+  GetInterfaceRegistry()->AddInterface<device::mojom::VRService>(
       base::Bind(&device::VRServiceImpl::BindRequest));
 #endif
   if (base::FeatureList::IsEnabled(features::kGenericSensor)) {
diff --git a/content/browser/renderer_host/render_message_filter.cc b/content/browser/renderer_host/render_message_filter.cc
index ca456956..78db5e2 100644
--- a/content/browser/renderer_host/render_message_filter.cc
+++ b/content/browser/renderer_host/render_message_filter.cc
@@ -183,9 +183,11 @@
         ViewHostMsg_SetNeedsBeginFrames,
         ResizeHelperPostMsgToUIThread(render_process_id_, message))
 #endif
-    // NB: The SyncAllocateGpuMemoryBuffer and DeletedGpuMemoryBuffer IPCs are
-    // handled here for renderer processes. For non-renderer child processes,
-    // they are handled in ChildProcessHostImpl.
+    // NB: The SyncAllocateSharedMemory, SyncAllocateGpuMemoryBuffer, and
+    // DeletedGpuMemoryBuffer IPCs are handled here for renderer processes. For
+    // non-renderer child processes, they are handled in ChildProcessHostImpl.
+    IPC_MESSAGE_HANDLER_DELAY_REPLY(
+        ChildProcessHostMsg_SyncAllocateSharedMemory, OnAllocateSharedMemory)
     IPC_MESSAGE_HANDLER_DELAY_REPLY(
         ChildProcessHostMsg_SyncAllocateSharedBitmap, OnAllocateSharedBitmap)
     IPC_MESSAGE_HANDLER_DELAY_REPLY(
@@ -334,6 +336,25 @@
 
 #endif  // defined(OS_MACOSX)
 
+void RenderMessageFilter::AllocateSharedMemoryOnFileThread(
+    uint32_t buffer_size,
+    IPC::Message* reply_msg) {
+  base::SharedMemoryHandle handle;
+  ChildProcessHostImpl::AllocateSharedMemory(buffer_size, PeerHandle(),
+                                             &handle);
+  ChildProcessHostMsg_SyncAllocateSharedMemory::WriteReplyParams(reply_msg,
+                                                                 handle);
+  Send(reply_msg);
+}
+
+void RenderMessageFilter::OnAllocateSharedMemory(uint32_t buffer_size,
+                                                 IPC::Message* reply_msg) {
+  BrowserThread::PostTask(
+      BrowserThread::FILE_USER_BLOCKING, FROM_HERE,
+      base::Bind(&RenderMessageFilter::AllocateSharedMemoryOnFileThread, this,
+                 buffer_size, reply_msg));
+}
+
 void RenderMessageFilter::AllocateSharedBitmapOnFileThread(
     uint32_t buffer_size,
     const cc::SharedBitmapId& id,
diff --git a/content/browser/renderer_host/render_message_filter.h b/content/browser/renderer_host/render_message_filter.h
index 99fcd05..1aa7961 100644
--- a/content/browser/renderer_host/render_message_filter.h
+++ b/content/browser/renderer_host/render_message_filter.h
@@ -149,6 +149,9 @@
   // Used to ask the browser to allocate a block of shared memory for the
   // renderer to send back data in, since shared memory can't be created
   // in the renderer on POSIX due to the sandbox.
+  void AllocateSharedMemoryOnFileThread(uint32_t buffer_size,
+                                        IPC::Message* reply_msg);
+  void OnAllocateSharedMemory(uint32_t buffer_size, IPC::Message* reply_msg);
   void AllocateSharedBitmapOnFileThread(uint32_t buffer_size,
                                         const cc::SharedBitmapId& id,
                                         IPC::Message* reply_msg);
diff --git a/content/child/child_thread_impl.cc b/content/child/child_thread_impl.cc
index 8d8b6bd..927427d 100644
--- a/content/child/child_thread_impl.cc
+++ b/content/child/child_thread_impl.cc
@@ -65,8 +65,6 @@
 #include "mojo/edk/embedder/named_platform_channel_pair.h"
 #include "mojo/edk/embedder/platform_channel_pair.h"
 #include "mojo/edk/embedder/scoped_ipc_support.h"
-#include "mojo/public/cpp/system/buffer.h"
-#include "mojo/public/cpp/system/platform_handle.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "services/service_manager/public/cpp/interface_factory.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
@@ -731,23 +729,27 @@
     size_t buf_size,
     IPC::Sender* sender,
     bool* out_of_memory) {
-  mojo::ScopedSharedBufferHandle mojo_buf =
-      mojo::SharedBufferHandle::Create(buf_size);
-  if (!mojo_buf->is_valid()) {
-    LOG(WARNING) << "Browser failed to allocate shared memory";
+  std::unique_ptr<base::SharedMemory> shared_buf;
+  // Ask the browser to create the shared memory, since this is blocked by the
+  // sandbox on most platforms.
+  base::SharedMemoryHandle shared_mem_handle;
+  if (sender->Send(new ChildProcessHostMsg_SyncAllocateSharedMemory(
+          buf_size, &shared_mem_handle))) {
+    if (base::SharedMemory::IsHandleValid(shared_mem_handle)) {
+      shared_buf.reset(new base::SharedMemory(shared_mem_handle, false));
+    } else {
+      LOG(WARNING) << "Browser failed to allocate shared memory";
+      if (out_of_memory)
+        *out_of_memory = true;
+      return nullptr;
+    }
+  } else {
+    // Send is allowed to fail during shutdown. Return null in this case.
     if (out_of_memory)
-      *out_of_memory = true;
+      *out_of_memory = false;
     return nullptr;
   }
-
-  base::SharedMemoryHandle shared_buf;
-  if (mojo::UnwrapSharedMemoryHandle(std::move(mojo_buf), &shared_buf,
-                                     nullptr, nullptr) != MOJO_RESULT_OK) {
-    LOG(WARNING) << "Browser failed to allocate shared memory";
-    return nullptr;
-  }
-
-  return base::MakeUnique<base::SharedMemory>(shared_buf, false);
+  return shared_buf;
 }
 
 #if defined(OS_LINUX)
diff --git a/content/common/child_process_host_impl.cc b/content/common/child_process_host_impl.cc
index 59325c33..71a34fc 100644
--- a/content/common/child_process_host_impl.cc
+++ b/content/common/child_process_host_impl.cc
@@ -185,6 +185,18 @@
   return channel_->Send(message);
 }
 
+void ChildProcessHostImpl::AllocateSharedMemory(
+      size_t buffer_size, base::ProcessHandle child_process_handle,
+      base::SharedMemoryHandle* shared_memory_handle) {
+  base::SharedMemory shared_buf;
+  if (!shared_buf.CreateAnonymous(buffer_size)) {
+    *shared_memory_handle = base::SharedMemory::NULLHandle();
+    NOTREACHED() << "Cannot create shared memory buffer";
+    return;
+  }
+  shared_buf.GiveToProcess(child_process_handle, shared_memory_handle);
+}
+
 int ChildProcessHostImpl::GenerateChildProcessUniqueId() {
   // This function must be threadsafe.
   //
@@ -243,9 +255,12 @@
     IPC_BEGIN_MESSAGE_MAP(ChildProcessHostImpl, msg)
       IPC_MESSAGE_HANDLER(ChildProcessHostMsg_ShutdownRequest,
                           OnShutdownRequest)
-      // NB: The SyncAllocateGpuMemoryBuffer and DeletedGpuMemoryBuffer IPCs are
-      // handled here for non-renderer child processes. For renderer processes,
-      // they are handled in RenderMessageFilter.
+      // NB: The SyncAllocateSharedMemory, SyncAllocateGpuMemoryBuffer, and
+      // DeletedGpuMemoryBuffer IPCs are handled here for non-renderer child
+      // processes. For renderer processes, they are handled in
+      // RenderMessageFilter.
+      IPC_MESSAGE_HANDLER(ChildProcessHostMsg_SyncAllocateSharedMemory,
+                          OnAllocateSharedMemory)
       IPC_MESSAGE_HANDLER(ChildProcessHostMsg_SyncAllocateGpuMemoryBuffer,
                           OnAllocateGpuMemoryBuffer)
       IPC_MESSAGE_HANDLER(ChildProcessHostMsg_DeletedGpuMemoryBuffer,
@@ -292,6 +307,12 @@
   delegate_->OnBadMessageReceived(message);
 }
 
+void ChildProcessHostImpl::OnAllocateSharedMemory(
+    uint32_t buffer_size,
+    base::SharedMemoryHandle* handle) {
+  AllocateSharedMemory(buffer_size, peer_process_.Handle(), handle);
+}
+
 void ChildProcessHostImpl::OnShutdownRequest() {
   if (delegate_->CanShutdown())
     Send(new ChildProcessMsg_Shutdown());
diff --git a/content/common/child_process_host_impl.h b/content/common/child_process_host_impl.h
index 1576489a..2cd9967 100644
--- a/content/common/child_process_host_impl.h
+++ b/content/common/child_process_host_impl.h
@@ -41,6 +41,11 @@
  public:
   ~ChildProcessHostImpl() override;
 
+  // Public and static for reuse by RenderMessageFilter.
+  static void AllocateSharedMemory(
+      size_t buffer_size, base::ProcessHandle child_process,
+      base::SharedMemoryHandle* handle);
+
   // Returns a unique ID to identify a child process. On construction, this
   // function will be used to generate the id_, but it is also used to generate
   // IDs for the RenderProcessHost, which doesn't inherit from us, and whose IDs
@@ -88,6 +93,8 @@
 
   // Message handlers:
   void OnShutdownRequest();
+  void OnAllocateSharedMemory(uint32_t buffer_size,
+                              base::SharedMemoryHandle* handle);
   void OnAllocateGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
                                  uint32_t width,
                                  uint32_t height,
diff --git a/content/common/child_process_messages.h b/content/common/child_process_messages.h
index fefc94f..c74214a 100644
--- a/content/common/child_process_messages.h
+++ b/content/common/child_process_messages.h
@@ -176,6 +176,12 @@
 
 // Asks the browser to create a block of shared memory for the child process to
 // fill in and pass back to the browser.
+IPC_SYNC_MESSAGE_CONTROL1_1(ChildProcessHostMsg_SyncAllocateSharedMemory,
+                            uint32_t /* buffer size */,
+                            base::SharedMemoryHandle)
+
+// Asks the browser to create a block of shared memory for the child process to
+// fill in and pass back to the browser.
 IPC_SYNC_MESSAGE_CONTROL2_1(ChildProcessHostMsg_SyncAllocateSharedBitmap,
                             uint32_t /* buffer size */,
                             cc::SharedBitmapId,
diff --git a/content/public/app/mojo/content_browser_manifest.json b/content/public/app/mojo/content_browser_manifest.json
index 7799cb5..75a1e49 100644
--- a/content/public/app/mojo/content_browser_manifest.json
+++ b/content/public/app/mojo/content_browser_manifest.json
@@ -76,7 +76,7 @@
           "blink::mojom::WebSocket",
           // TODO(beng): figure out how to overlay test interfaces like this.
           "content::mojom::BrowserTarget",
-          "device::VRService",
+          "device::mojom::VRService",
           "device::VibrationManager",
           "device::mojom::GeolocationService",
           "device::mojom::SensorProvider",
diff --git a/content/renderer/media/media_stream_center.cc b/content/renderer/media/media_stream_center.cc
index 2a2a7a3..2f5e1a40 100644
--- a/content/renderer/media/media_stream_center.cc
+++ b/content/renderer/media/media_stream_center.cc
@@ -26,6 +26,8 @@
 #include "third_party/WebKit/public/platform/WebMediaStreamCenterClient.h"
 #include "third_party/WebKit/public/platform/WebMediaStreamSource.h"
 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
+#include "third_party/WebKit/public/platform/WebMediaStreamTrackSourcesRequest.h"
+#include "third_party/WebKit/public/platform/WebSourceInfo.h"
 #include "third_party/WebKit/public/platform/WebVector.h"
 #include "third_party/WebKit/public/web/WebFrame.h"
 
diff --git a/content/renderer/media/media_stream_center.h b/content/renderer/media/media_stream_center.h
index 24b3aac..8b58afd3 100644
--- a/content/renderer/media/media_stream_center.h
+++ b/content/renderer/media/media_stream_center.h
@@ -14,6 +14,7 @@
 #include "third_party/WebKit/public/platform/WebMediaStream.h"
 #include "third_party/WebKit/public/platform/WebMediaStreamCenter.h"
 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
+#include "third_party/WebKit/public/platform/WebMediaStreamTrackSourcesRequest.h"
 
 namespace blink {
 class WebAudioSourceProvider;
diff --git a/content/renderer/media/user_media_client_impl.cc b/content/renderer/media/user_media_client_impl.cc
index c3fdcac..290a18a 100644
--- a/content/renderer/media/user_media_client_impl.cc
+++ b/content/renderer/media/user_media_client_impl.cc
@@ -36,6 +36,7 @@
 #include "third_party/WebKit/public/platform/WebMediaConstraints.h"
 #include "third_party/WebKit/public/platform/WebMediaDeviceInfo.h"
 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
+#include "third_party/WebKit/public/platform/WebMediaStreamTrackSourcesRequest.h"
 #include "third_party/WebKit/public/web/WebDocument.h"
 #include "third_party/WebKit/public/web/WebLocalFrame.h"
 
@@ -146,6 +147,18 @@
   }
 }
 
+blink::WebSourceInfo::VideoFacingMode ToVideoFacingMode(
+    const std::string& device_label) {
+#if defined(OS_ANDROID)
+  if (device_label.find("front") != std::string::npos) {
+    return blink::WebSourceInfo::VideoFacingModeUser;
+  } else if (device_label.find("back") != std::string::npos) {
+    return blink::WebSourceInfo::VideoFacingModeEnvironment;
+  }
+#endif
+  return blink::WebSourceInfo::VideoFacingModeNone;
+}
+
 static int g_next_request_id = 0;
 
 }  // namespace
@@ -283,6 +296,25 @@
                  weak_factory_.GetWeakPtr(), media_devices_request));
 }
 
+void UserMediaClientImpl::requestSources(
+    const blink::WebMediaStreamTrackSourcesRequest& sources_request) {
+  // We don't call UpdateWebRTCMethodCount() here to track the API count in UMA
+  // stats. This is instead counted in MediaStreamTrack::getSources in blink.
+  DCHECK(CalledOnValidThread());
+
+  // |sources_request| can't be mocked, so in tests it will be empty (the
+  // underlying pointer is null). In order to use this function in a test we
+  // need to check if it isNull.
+  url::Origin security_origin;
+  if (!sources_request.isNull())
+    security_origin = sources_request.origin();
+
+  GetMediaDevicesDispatcher()->EnumerateDevices(
+      true /* audio input */, true /* video input */, false /* audio output */,
+      security_origin, base::Bind(&UserMediaClientImpl::FinalizeGetSources,
+                                  weak_factory_.GetWeakPtr(), sources_request));
+}
+
 void UserMediaClientImpl::setMediaDeviceChangeObserver(
     const blink::WebMediaDeviceChangeObserver& observer) {
   media_device_change_observer_ = observer;
@@ -408,6 +440,34 @@
   EnumerateDevicesSucceded(&request, devices);
 }
 
+void UserMediaClientImpl::FinalizeGetSources(
+    blink::WebMediaStreamTrackSourcesRequest request,
+    const EnumerationResult& result) {
+  DCHECK_EQ(static_cast<size_t>(NUM_MEDIA_DEVICE_TYPES), result.size());
+
+  blink::WebVector<blink::WebSourceInfo> sources(
+      result[MEDIA_DEVICE_TYPE_AUDIO_INPUT].size() +
+      result[MEDIA_DEVICE_TYPE_VIDEO_INPUT].size());
+  size_t index = 0;
+  for (const auto& device_info : result[MEDIA_DEVICE_TYPE_AUDIO_INPUT]) {
+    sources[index++].initialize(
+        blink::WebString::fromUTF8(device_info.device_id),
+        blink::WebSourceInfo::SourceKindAudio,
+        blink::WebString::fromUTF8(device_info.label),
+        blink::WebSourceInfo::VideoFacingModeNone);
+  }
+
+  for (const auto& device_info : result[MEDIA_DEVICE_TYPE_VIDEO_INPUT]) {
+    sources[index++].initialize(
+        blink::WebString::fromUTF8(device_info.device_id),
+        blink::WebSourceInfo::SourceKindVideo,
+        blink::WebString::fromUTF8(device_info.label),
+        ToVideoFacingMode(device_info.label));
+  }
+
+  EnumerateSourcesSucceded(&request, sources);
+}
+
 // Callback from MediaStreamDispatcher.
 // The requested stream failed to be generated.
 void UserMediaClientImpl::OnStreamGenerationFailed(
@@ -744,6 +804,12 @@
   request->requestSucceeded(devices);
 }
 
+void UserMediaClientImpl::EnumerateSourcesSucceded(
+    blink::WebMediaStreamTrackSourcesRequest* request,
+    blink::WebVector<blink::WebSourceInfo>& sources) {
+  request->requestSucceeded(sources);
+}
+
 const blink::WebMediaStreamSource* UserMediaClientImpl::FindLocalSource(
     const StreamDeviceInfo& device) const {
   for (LocalStreamSources::const_iterator it = local_sources_.begin();
diff --git a/content/renderer/media/user_media_client_impl.h b/content/renderer/media/user_media_client_impl.h
index 6931e7b6..6199c9e9 100644
--- a/content/renderer/media/user_media_client_impl.h
+++ b/content/renderer/media/user_media_client_impl.h
@@ -25,6 +25,7 @@
 #include "services/service_manager/public/cpp/interface_provider.h"
 #include "third_party/WebKit/public/platform/WebMediaStream.h"
 #include "third_party/WebKit/public/platform/WebMediaStreamSource.h"
+#include "third_party/WebKit/public/platform/WebSourceInfo.h"
 #include "third_party/WebKit/public/platform/WebVector.h"
 #include "third_party/WebKit/public/web/WebMediaDeviceChangeObserver.h"
 #include "third_party/WebKit/public/web/WebMediaDevicesRequest.h"
@@ -66,6 +67,8 @@
       const blink::WebUserMediaRequest& user_media_request) override;
   void requestMediaDevices(
       const blink::WebMediaDevicesRequest& media_devices_request) override;
+  void requestSources(
+      const blink::WebMediaStreamTrackSourcesRequest& sources_request) override;
   void setMediaDeviceChangeObserver(
       const blink::WebMediaDeviceChangeObserver& observer) override;
 
@@ -117,6 +120,9 @@
   virtual void EnumerateDevicesSucceded(
       blink::WebMediaDevicesRequest* request,
       blink::WebVector<blink::WebMediaDeviceInfo>& devices);
+  virtual void EnumerateSourcesSucceded(
+      blink::WebMediaStreamTrackSourcesRequest* request,
+      blink::WebVector<blink::WebSourceInfo>& sources);
 
   // Creates a MediaStreamAudioSource/MediaStreamVideoSource objects.
   // These are virtual for test purposes.
@@ -228,6 +234,8 @@
   using EnumerationResult = std::vector<MediaDeviceInfoArray>;
   void FinalizeEnumerateDevices(blink::WebMediaDevicesRequest request,
                                 const EnumerationResult& result);
+  void FinalizeGetSources(blink::WebMediaStreamTrackSourcesRequest request,
+                          const EnumerationResult& result);
 
   void DeleteAllUserMediaRequests();
 
diff --git a/content/renderer/media/user_media_client_impl_unittest.cc b/content/renderer/media/user_media_client_impl_unittest.cc
index c0de733a..bcd05ae 100644
--- a/content/renderer/media/user_media_client_impl_unittest.cc
+++ b/content/renderer/media/user_media_client_impl_unittest.cc
@@ -28,6 +28,7 @@
 #include "third_party/WebKit/public/platform/WebMediaStream.h"
 #include "third_party/WebKit/public/platform/WebMediaStreamSource.h"
 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
+#include "third_party/WebKit/public/platform/WebMediaStreamTrackSourcesRequest.h"
 #include "third_party/WebKit/public/platform/WebString.h"
 #include "third_party/WebKit/public/platform/WebVector.h"
 #include "third_party/WebKit/public/web/WebHeap.h"
@@ -123,6 +124,12 @@
     requestMediaDevices(media_devices_request);
   }
 
+  void RequestSources() {
+    blink::WebMediaStreamTrackSourcesRequest sources_request;
+    state_ = REQUEST_NOT_COMPLETE;
+    requestSources(sources_request);
+  }
+
   void SetMediaDeviceChangeObserver() {
     blink::WebMediaDeviceChangeObserver observer(true);
     setMediaDeviceChangeObserver(observer);
@@ -156,6 +163,13 @@
     last_devices_ = devices;
   }
 
+  void EnumerateSourcesSucceded(
+      blink::WebMediaStreamTrackSourcesRequest* request,
+      blink::WebVector<blink::WebSourceInfo>& sources) override {
+    state_ = REQUEST_SUCCEEDED;
+    last_sources_ = sources;
+  }
+
   void SetCreateSourceThatFails(bool should_fail) {
     create_source_that_fails_ = should_fail;
   }
@@ -199,6 +213,10 @@
     return last_devices_;
   }
 
+  const blink::WebVector<blink::WebSourceInfo>& last_sources() {
+    return last_sources_;
+  }
+
   void ClearLastGeneratedStream() {
     last_generated_stream_.reset();
   }
@@ -229,6 +247,7 @@
   content::MediaStreamRequestResult result_;
   blink::WebString result_name_;
   blink::WebVector<blink::WebMediaDeviceInfo> last_devices_;
+  blink::WebVector<blink::WebSourceInfo> last_sources_;
   PeerConnectionDependencyFactory* factory_;
   bool create_source_that_fails_;
   MockMediaStreamVideoCapturerSource* video_source_;
@@ -625,6 +644,42 @@
                    used_media_impl_->last_devices()[4].groupId()));
 }
 
+TEST_F(UserMediaClientImplTest, EnumerateSources) {
+  used_media_impl_->RequestSources();
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(UserMediaClientImplUnderTest::REQUEST_SUCCEEDED,
+            used_media_impl_->request_state());
+  EXPECT_EQ(static_cast<size_t>(4), used_media_impl_->last_sources().size());
+
+  // Audio input devices.
+  const blink::WebSourceInfo* source = &used_media_impl_->last_sources()[0];
+  EXPECT_FALSE(source->id().isEmpty());
+  EXPECT_EQ(blink::WebSourceInfo::SourceKindAudio, source->kind());
+  EXPECT_FALSE(source->label().isEmpty());
+  EXPECT_EQ(blink::WebSourceInfo::VideoFacingModeNone, source->facing());
+
+  source = &used_media_impl_->last_sources()[1];
+  EXPECT_FALSE(source->id().isEmpty());
+  EXPECT_EQ(blink::WebSourceInfo::SourceKindAudio, source->kind());
+  EXPECT_FALSE(source->label().isEmpty());
+  EXPECT_EQ(blink::WebSourceInfo::VideoFacingModeNone, source->facing());
+
+  // Video input device user facing.
+  source = &used_media_impl_->last_sources()[2];
+  EXPECT_FALSE(source->id().isEmpty());
+  EXPECT_EQ(blink::WebSourceInfo::SourceKindVideo, source->kind());
+  EXPECT_FALSE(source->label().isEmpty());
+  EXPECT_EQ(blink::WebSourceInfo::VideoFacingModeNone, source->facing());
+
+  // Video input device environment facing.
+  source = &used_media_impl_->last_sources()[3];
+  EXPECT_FALSE(source->id().isEmpty());
+  EXPECT_EQ(blink::WebSourceInfo::SourceKindVideo, source->kind());
+  EXPECT_FALSE(source->label().isEmpty());
+  EXPECT_EQ(blink::WebSourceInfo::VideoFacingModeNone, source->facing());
+}
+
 TEST_F(UserMediaClientImplTest, RenderToAssociatedSinkConstraint) {
   // For a null UserMediaRequest (no audio requested), we expect false.
   used_media_impl_->RequestUserMedia();
diff --git a/content/test/data/media/getusermedia.html b/content/test/data/media/getusermedia.html
index 49b2bece..e8aac18f 100644
--- a/content/test/data/media/getusermedia.html
+++ b/content/test/data/media/getusermedia.html
@@ -11,17 +11,15 @@
   });
 
   function getSources() {
-    navigator.mediaDevices.enumerateDevices().then(function(devices) {
+    MediaStreamTrack.getSources(function(devices) {
       document.title = 'Media devices available';
       var results = [];
       for (var device, i = 0; device = devices[i]; ++i) {
-        if (device.kind != "audioinput" && device.kind != "videoinput")
-          continue;
         results.push({
-          'id': device.deviceId,
-          'kind': device.kind == "audioinput" ? "audio" : "video",
+          'id': device.id,
+          'kind': device.kind,
           'label': device.label,
-          'facing': ""
+          'facing': device.facing
         });
       }
       sendValueToTest(JSON.stringify(results));
diff --git a/device/gamepad/gamepad_standard_mappings_linux.cc b/device/gamepad/gamepad_standard_mappings_linux.cc
index 990abec..c4b64221 100644
--- a/device/gamepad/gamepad_standard_mappings_linux.cc
+++ b/device/gamepad/gamepad_standard_mappings_linux.cc
@@ -331,6 +331,7 @@
     {"046d", "c21f", MapperXInputStyleGamepad},  // Logitech F710
     {"054c", "0268", MapperPlaystationSixAxis},  // Playstation SIXAXIS
     {"054c", "05c4", MapperDualshock4},          // Playstation Dualshock 4
+    {"054c", "09cc", MapperDualshock4},          // Dualshock 4 (PS4 Slim)
     {"0583", "2060", MapperIBuffalo},            // iBuffalo Classic
     {"0925", "0005", MapperLakeviewResearch},    // SmartJoy PLUS Adapter
     {"0925", "8866", MapperLakeviewResearch},    // WiseGroup MP-8866
diff --git a/device/gamepad/gamepad_standard_mappings_mac.mm b/device/gamepad/gamepad_standard_mappings_mac.mm
index ef2b158..a25ab4e 100644
--- a/device/gamepad/gamepad_standard_mappings_mac.mm
+++ b/device/gamepad/gamepad_standard_mappings_mac.mm
@@ -387,6 +387,7 @@
     {"046d", "c219", MapperDirectInputStyle},    // Logitech F710, D mode
     {"054c", "0268", MapperPlaystationSixAxis},  // Playstation SIXAXIS
     {"054c", "05c4", MapperDualshock4},          // Playstation Dualshock 4
+    {"054c", "09cc", MapperDualshock4},          // Dualshock 4 (PS4 Slim)
     {"0583", "2060", MapperIBuffalo},            // iBuffalo Classic
     {"0925", "0005", MapperSmartJoyPLUS},        // SmartJoy PLUS Adapter
     {"0955", "7210", MapperNvShield},            // Nvidia Shield gamepad
diff --git a/device/gamepad/gamepad_standard_mappings_win.cc b/device/gamepad/gamepad_standard_mappings_win.cc
index 0d5943f..0748a6b9 100644
--- a/device/gamepad/gamepad_standard_mappings_win.cc
+++ b/device/gamepad/gamepad_standard_mappings_win.cc
@@ -242,6 +242,7 @@
     {"0079", "0011", Mapper2Axes8Keys},          // 2Axes 8Keys Game Pad
     {"046d", "c216", MapperLogitechDualAction},  // Logitech DualAction
     {"054c", "05c4", MapperDualshock4},          // Playstation Dualshock 4
+    {"054c", "09cc", MapperDualshock4},          // Dualshock 4 (PS4 Slim)
     {"0583", "2060", MapperIBuffalo},            // iBuffalo Classic
     {"0955", "7210", MapperNvShield},            // Nvidia Shield gamepad
     {"0b05", "4500", MapperADT1},                // Nexus Player Controller
diff --git a/device/vr/BUILD.gn b/device/vr/BUILD.gn
index 317c898..d07f626 100644
--- a/device/vr/BUILD.gn
+++ b/device/vr/BUILD.gn
@@ -13,12 +13,13 @@
   output_name = "device_vr"
 
   sources = [
-    "vr_client_dispatcher.h",
     "vr_device.cc",
     "vr_device.h",
     "vr_device_manager.cc",
     "vr_device_manager.h",
     "vr_device_provider.h",
+    "vr_display_impl.cc",
+    "vr_display_impl.h",
     "vr_service_impl.cc",
     "vr_service_impl.h",
   ]
diff --git a/device/vr/android/gvr/gvr_device.cc b/device/vr/android/gvr/gvr_device.cc
index 57cb7292..be3d657 100644
--- a/device/vr/android/gvr/gvr_device.cc
+++ b/device/vr/android/gvr/gvr_device.cc
@@ -29,26 +29,26 @@
 
 GvrDevice::~GvrDevice() {}
 
-VRDisplayPtr GvrDevice::GetVRDevice() {
+mojom::VRDisplayInfoPtr GvrDevice::GetVRDevice() {
   TRACE_EVENT0("input", "GvrDevice::GetVRDevice");
 
-  VRDisplayPtr device = VRDisplay::New();
+  mojom::VRDisplayInfoPtr device = mojom::VRDisplayInfo::New();
 
   device->index = id();
 
-  device->capabilities = VRDisplayCapabilities::New();
+  device->capabilities = mojom::VRDisplayCapabilities::New();
   device->capabilities->hasOrientation = true;
   device->capabilities->hasPosition = false;
   device->capabilities->hasExternalDisplay = false;
   device->capabilities->canPresent = true;
 
-  device->leftEye = VREyeParameters::New();
-  device->rightEye = VREyeParameters::New();
-  VREyeParametersPtr& left_eye = device->leftEye;
-  VREyeParametersPtr& right_eye = device->rightEye;
+  device->leftEye = mojom::VREyeParameters::New();
+  device->rightEye = mojom::VREyeParameters::New();
+  mojom::VREyeParametersPtr& left_eye = device->leftEye;
+  mojom::VREyeParametersPtr& right_eye = device->rightEye;
 
-  left_eye->fieldOfView = VRFieldOfView::New();
-  right_eye->fieldOfView = VRFieldOfView::New();
+  left_eye->fieldOfView = mojom::VRFieldOfView::New();
+  right_eye->fieldOfView = mojom::VRFieldOfView::New();
 
   left_eye->offset = mojo::Array<float>::New(3);
   right_eye->offset = mojo::Array<float>::New(3);
@@ -127,10 +127,13 @@
   return device;
 }
 
-VRPosePtr GvrDevice::GetPose() {
+mojom::VRPosePtr GvrDevice::GetPose(VRServiceImpl* service) {
   TRACE_EVENT0("input", "GvrDevice::GetSensorState");
 
-  VRPosePtr pose = VRPose::New();
+  if (!IsAccessAllowed(service))
+    return nullptr;
+
+  mojom::VRPosePtr pose = mojom::VRPose::New();
 
   pose->timestamp = base::Time::Now().ToJsTime();
 
@@ -186,7 +189,10 @@
   return pose;
 }
 
-void GvrDevice::ResetPose() {
+void GvrDevice::ResetPose(VRServiceImpl* service) {
+  if (!IsAccessAllowed(service))
+    return;
+
   gvr::GvrApi* gvr_api = GetGvrApi();
 
   // Should never call RecenterTracking when using with Daydream viewers. On
@@ -195,25 +201,40 @@
     gvr_api->RecenterTracking();
 }
 
-bool GvrDevice::RequestPresent(bool secure_origin) {
+bool GvrDevice::RequestPresent(VRServiceImpl* service, bool secure_origin) {
+  if (!IsAccessAllowed(service))
+    return false;
+
+  // One service could present on several devices at the same time
+  // and different service could present on different devices the same time
+  if (presenting_service_ == nullptr)
+    presenting_service_ = service;
+
   secure_origin_ = secure_origin;
   if (delegate_)
     delegate_->SetWebVRSecureOrigin(secure_origin_);
+
   return gvr_provider_->RequestPresent();
 }
 
-void GvrDevice::ExitPresent() {
+void GvrDevice::ExitPresent(VRServiceImpl* service) {
+  if (IsPresentingService(service))
+    presenting_service_ = nullptr;
+
   gvr_provider_->ExitPresent();
+  OnExitPresent(service);
 }
 
-void GvrDevice::SubmitFrame(VRPosePtr pose) {
-  if (delegate_)
-    delegate_->SubmitWebVRFrame();
+void GvrDevice::SubmitFrame(VRServiceImpl* service, mojom::VRPosePtr pose) {
+  if (!IsPresentingService(service) || !delegate_)
+    return;
+  delegate_->SubmitWebVRFrame();
 }
 
-void GvrDevice::UpdateLayerBounds(VRLayerBoundsPtr leftBounds,
-                                  VRLayerBoundsPtr rightBounds) {
-  if (!delegate_)
+void GvrDevice::UpdateLayerBounds(VRServiceImpl* service,
+                                  mojom::VRLayerBoundsPtr leftBounds,
+                                  mojom::VRLayerBoundsPtr rightBounds) {
+  if (!IsAccessAllowed(service) || !delegate_)
     return;
 
   delegate_->UpdateWebVRTextureBounds(0,  // Left eye
@@ -230,7 +251,7 @@
   // Notify the clients that this device has changed
   if (delegate_) {
     delegate_->SetWebVRSecureOrigin(secure_origin_);
-    VRDeviceManager::GetInstance()->OnDeviceChanged(GetVRDevice());
+    OnDisplayChanged();
   }
 }
 
diff --git a/device/vr/android/gvr/gvr_device.h b/device/vr/android/gvr/gvr_device.h
index 2f7baaa..339b30d 100644
--- a/device/vr/android/gvr/gvr_device.h
+++ b/device/vr/android/gvr/gvr_device.h
@@ -23,16 +23,17 @@
   ~GvrDevice() override;
 
   // VRDevice
-  VRDisplayPtr GetVRDevice() override;
-  VRPosePtr GetPose() override;
-  void ResetPose() override;
+  mojom::VRDisplayInfoPtr GetVRDevice() override;
+  mojom::VRPosePtr GetPose(VRServiceImpl* service) override;
+  void ResetPose(VRServiceImpl* service) override;
 
-  bool RequestPresent(bool secure_origin) override;
-  void ExitPresent() override;
+  bool RequestPresent(VRServiceImpl* service, bool secure_origin) override;
+  void ExitPresent(VRServiceImpl* service) override;
 
-  void SubmitFrame(VRPosePtr pose) override;
-  void UpdateLayerBounds(VRLayerBoundsPtr leftBounds,
-                         VRLayerBoundsPtr rightBounds) override;
+  void SubmitFrame(VRServiceImpl* service, mojom::VRPosePtr pose) override;
+  void UpdateLayerBounds(VRServiceImpl* service,
+                         mojom::VRLayerBoundsPtr leftBounds,
+                         mojom::VRLayerBoundsPtr rightBounds) override;
 
   void SetDelegate(GvrDelegate* delegate);
 
diff --git a/device/vr/android/gvr/gvr_device_provider.cc b/device/vr/android/gvr/gvr_device_provider.cc
index 252aa117..8a3637d 100644
--- a/device/vr/android/gvr/gvr_device_provider.cc
+++ b/device/vr/android/gvr/gvr_device_provider.cc
@@ -43,11 +43,6 @@
     devices->push_back(vr_device_.get());
 }
 
-void GvrDeviceProvider::SetClient(VRClientDispatcher* client) {
-  if (!client_)
-    client_.reset(client);
-}
-
 void GvrDeviceProvider::Initialize() {
   device::GvrDelegateProvider* delegate_provider =
       device::GvrDelegateProvider::GetInstance();
@@ -57,7 +52,6 @@
   if (!vr_device_) {
     vr_device_.reset(
         new GvrDevice(this, delegate_provider->GetNonPresentingDelegate()));
-    client_->OnDeviceConnectionStatusChanged(vr_device_.get(), true);
   }
 }
 
@@ -88,9 +82,6 @@
       GAMEPAD_SOURCE_GVR);
 
   delegate_provider->ExitWebVRPresent();
-
-  if (client_)
-    client_->OnPresentEnded(vr_device_.get());
 }
 
 void GvrDeviceProvider::OnGvrDelegateReady(GvrDelegate* delegate) {
diff --git a/device/vr/android/gvr/gvr_device_provider.h b/device/vr/android/gvr/gvr_device_provider.h
index 23f8cb0..02f7758 100644
--- a/device/vr/android/gvr/gvr_device_provider.h
+++ b/device/vr/android/gvr/gvr_device_provider.h
@@ -9,7 +9,6 @@
 
 #include "base/macros.h"
 #include "base/single_thread_task_runner.h"
-#include "device/vr/vr_client_dispatcher.h"
 #include "device/vr/vr_device.h"
 #include "device/vr/vr_device_provider.h"
 #include "device/vr/vr_export.h"
@@ -18,6 +17,7 @@
 
 class GvrDelegate;
 class GvrDevice;
+class VRServiceImpl;
 
 class DEVICE_VR_EXPORT GvrDeviceProvider : public VRDeviceProvider {
  public:
@@ -35,13 +35,10 @@
   void OnGvrDelegateReady(GvrDelegate* delegate);
   void OnGvrDelegateRemoved();
 
-  void SetClient(VRClientDispatcher* client) override;
-
  private:
   void GvrDelegateReady(GvrDelegate* delegate);
   void GvrDelegateRemoved();
 
-  std::unique_ptr<VRClientDispatcher> client_;
   std::unique_ptr<GvrDevice> vr_device_;
 
   scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
diff --git a/device/vr/test/fake_vr_device.cc b/device/vr/test/fake_vr_device.cc
index 48e7138..a011c77 100644
--- a/device/vr/test/fake_vr_device.cc
+++ b/device/vr/test/fake_vr_device.cc
@@ -7,8 +7,8 @@
 namespace device {
 
 FakeVRDevice::FakeVRDevice(VRDeviceProvider* provider) : VRDevice(provider) {
-  device_ = VRDisplay::New();
-  pose_ = VRPose::New();
+  device_ = mojom::VRDisplayInfo::New();
+  pose_ = mojom::VRPose::New();
 
   InitBasicDevice();
 }
@@ -18,7 +18,7 @@
 void FakeVRDevice::InitBasicDevice() {
   device_->displayName = "FakeVRDevice";
 
-  device_->capabilities = VRDisplayCapabilities::New();
+  device_->capabilities = mojom::VRDisplayCapabilities::New();
   device_->capabilities->hasOrientation = true;
   device_->capabilities->hasPosition = false;
   device_->capabilities->hasExternalDisplay = false;
@@ -28,12 +28,12 @@
   device_->rightEye = InitEye(45, 0.03f, 1024);
 }
 
-VREyeParametersPtr FakeVRDevice::InitEye(float fov,
-                                         float offset,
-                                         uint32_t size) {
-  VREyeParametersPtr eye = VREyeParameters::New();
+mojom::VREyeParametersPtr FakeVRDevice::InitEye(float fov,
+                                                float offset,
+                                                uint32_t size) {
+  mojom::VREyeParametersPtr eye = mojom::VREyeParameters::New();
 
-  eye->fieldOfView = VRFieldOfView::New();
+  eye->fieldOfView = mojom::VRFieldOfView::New();
   eye->fieldOfView->upDegrees = fov;
   eye->fieldOfView->downDegrees = fov;
   eye->fieldOfView->leftDegrees = fov;
@@ -50,24 +50,36 @@
   return eye;
 }
 
-void FakeVRDevice::SetVRDevice(const VRDisplayPtr& device) {
+void FakeVRDevice::SetVRDevice(const mojom::VRDisplayInfoPtr& device) {
   device_ = device.Clone();
 }
 
-void FakeVRDevice::SetPose(const VRPosePtr& pose) {
+void FakeVRDevice::SetPose(const mojom::VRPosePtr& pose) {
   pose_ = pose.Clone();
 }
 
-VRDisplayPtr FakeVRDevice::GetVRDevice() {
-  VRDisplayPtr display = device_.Clone();
-  display->index = id();
+mojom::VRDisplayInfoPtr FakeVRDevice::GetVRDevice() {
+  mojom::VRDisplayInfoPtr display = device_.Clone();
   return display.Clone();
 }
 
-VRPosePtr FakeVRDevice::GetPose() {
+mojom::VRPosePtr FakeVRDevice::GetPose(VRServiceImpl* service) {
   return pose_.Clone();
 }
 
-void FakeVRDevice::ResetPose() {}
+void FakeVRDevice::ResetPose(VRServiceImpl* service) {}
+
+// TODO(shaobo.yan@intel.com): Will implemenate for VRDeviceServiceImpl tests.
+bool FakeVRDevice::RequestPresent(VRServiceImpl* service, bool secure_origin) {
+  return true;
+}
+
+void FakeVRDevice::ExitPresent(VRServiceImpl* service) {}
+
+void FakeVRDevice::SubmitFrame(VRServiceImpl* service, mojom::VRPosePtr pose) {}
+
+void FakeVRDevice::UpdateLayerBounds(VRServiceImpl* service,
+                                     mojom::VRLayerBoundsPtr leftBounds,
+                                     mojom::VRLayerBoundsPtr rightBounds) {}
 
 }  // namespace device
diff --git a/device/vr/test/fake_vr_device.h b/device/vr/test/fake_vr_device.h
index a72a194..8b3d31d 100644
--- a/device/vr/test/fake_vr_device.h
+++ b/device/vr/test/fake_vr_device.h
@@ -18,18 +18,25 @@
 
   void InitBasicDevice();
 
-  void SetVRDevice(const VRDisplayPtr& device);
-  void SetPose(const VRPosePtr& state);
+  void SetVRDevice(const mojom::VRDisplayInfoPtr& device);
+  void SetPose(const mojom::VRPosePtr& state);
 
-  VRDisplayPtr GetVRDevice() override;
-  VRPosePtr GetPose() override;
-  void ResetPose() override;
+  mojom::VRDisplayInfoPtr GetVRDevice() override;
+  mojom::VRPosePtr GetPose(VRServiceImpl* service) override;
+  void ResetPose(VRServiceImpl* service) override;
+
+  bool RequestPresent(VRServiceImpl* service, bool secure_origin) override;
+  void ExitPresent(VRServiceImpl* service) override;
+  void SubmitFrame(VRServiceImpl* service, mojom::VRPosePtr pose) override;
+  void UpdateLayerBounds(VRServiceImpl* service,
+                         mojom::VRLayerBoundsPtr leftBounds,
+                         mojom::VRLayerBoundsPtr rightBounds) override;
 
  private:
-  VREyeParametersPtr InitEye(float fov, float offset, uint32_t size);
+  mojom::VREyeParametersPtr InitEye(float fov, float offset, uint32_t size);
 
-  VRDisplayPtr device_;
-  VRPosePtr pose_;
+  mojom::VRDisplayInfoPtr device_;
+  mojom::VRPosePtr pose_;
 
   DISALLOW_COPY_AND_ASSIGN(FakeVRDevice);
 };
diff --git a/device/vr/vr_client_dispatcher.h b/device/vr/vr_client_dispatcher.h
deleted file mode 100644
index fc81525..0000000
--- a/device/vr/vr_client_dispatcher.h
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2016 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 DEVICE_VR_VR_CLIENT_DISPATCHER_H
-#define DEVICE_VR_VR_CLIENT_DISPATCHER_H
-
-#include "device/vr/vr_service.mojom.h"
-
-namespace device {
-
-class VRDevice;
-
-class VRClientDispatcher {
- public:
-  virtual void OnDeviceChanged(VRDisplayPtr device) = 0;
-  virtual void OnDeviceConnectionStatusChanged(VRDevice* device,
-                                               bool is_connected) = 0;
-  virtual void OnPresentEnded(VRDevice* device) = 0;
-};
-
-}  // namespace device
-
-#endif  // DEVICE_VR_VR_CLIENT_DISPATCHER_H
diff --git a/device/vr/vr_device.cc b/device/vr/vr_device.cc
index 5e3d7fc..c580d5f 100644
--- a/device/vr/vr_device.cc
+++ b/device/vr/vr_device.cc
@@ -4,13 +4,14 @@
 
 #include "device/vr/vr_device.h"
 #include "device/vr/vr_device_provider.h"
+#include "device/vr/vr_service_impl.h"
 
 namespace device {
 
 unsigned int VRDevice::next_id_ = 1;
 
 VRDevice::VRDevice(VRDeviceProvider* provider)
-    : provider_(provider), id_(next_id_) {
+    : presenting_service_(nullptr), provider_(provider), id_(next_id_) {
   // Prevent wraparound. Devices with this ID will be treated as invalid.
   if (next_id_ != VR_DEVICE_LAST_ID)
     next_id_++;
@@ -18,8 +19,48 @@
 
 VRDevice::~VRDevice() {}
 
-bool VRDevice::RequestPresent(bool secure_origin) {
+bool VRDevice::RequestPresent(VRServiceImpl* service, bool secure_origin) {
   return true;
 };
 
+void VRDevice::AddService(VRServiceImpl* service) {
+  // Create a VRDisplayImpl for this service/device pair
+  VRDisplayImpl* display_impl = service->GetVRDisplayImpl(this);
+  displays_.insert(std::make_pair(service, display_impl));
+}
+
+void VRDevice::RemoveService(VRServiceImpl* service) {
+  ExitPresent(service);
+  displays_.erase(service);
+}
+
+bool VRDevice::IsAccessAllowed(VRServiceImpl* service) {
+  return (!presenting_service_ || presenting_service_ == service);
+}
+
+bool VRDevice::IsPresentingService(VRServiceImpl* service) {
+  return (presenting_service_ && presenting_service_ == service);
+}
+
+void VRDevice::OnDisplayChanged() {
+  mojom::VRDisplayInfoPtr vr_device_info = GetVRDevice();
+  if (vr_device_info.is_null())
+    return;
+
+  for (const auto& display : displays_) {
+    mojom::VRDisplayClient* client = display.second->client();
+    if (client)
+      client->OnDisplayChanged(vr_device_info.Clone());
+  }
+}
+
+void VRDevice::OnExitPresent(VRServiceImpl* service) {
+  DisplayClientMap::iterator it = displays_.find(service);
+  if (it != displays_.end()) {
+    mojom::VRDisplayClient* client = it->second->client();
+    if (client)
+      client->OnExitPresent();
+  }
+}
+
 }  // namespace device
diff --git a/device/vr/vr_device.h b/device/vr/vr_device.h
index 4121cfc..81bbf5e 100644
--- a/device/vr/vr_device.h
+++ b/device/vr/vr_device.h
@@ -20,6 +20,8 @@
 namespace device {
 
 class VRDeviceProvider;
+class VRDisplayImpl;
+class VRServiceImpl;
 
 const unsigned int VR_DEVICE_LAST_ID = 0xFFFFFFFF;
 
@@ -31,15 +33,38 @@
   VRDeviceProvider* provider() const { return provider_; }
   unsigned int id() const { return id_; }
 
-  virtual VRDisplayPtr GetVRDevice() = 0;
-  virtual VRPosePtr GetPose() = 0;
-  virtual void ResetPose() = 0;
+  virtual mojom::VRDisplayInfoPtr GetVRDevice() = 0;
+  virtual mojom::VRPosePtr GetPose(VRServiceImpl* service) = 0;
+  virtual void ResetPose(VRServiceImpl* service) = 0;
 
-  virtual bool RequestPresent(bool secure_origin);
-  virtual void ExitPresent(){};
-  virtual void SubmitFrame(VRPosePtr pose){};
-  virtual void UpdateLayerBounds(VRLayerBoundsPtr leftBounds,
-                                 VRLayerBoundsPtr rightBounds){};
+  virtual bool RequestPresent(VRServiceImpl* service, bool secure_origin) = 0;
+  virtual void ExitPresent(VRServiceImpl* service) = 0;
+  virtual void SubmitFrame(VRServiceImpl* service, mojom::VRPosePtr pose) = 0;
+  virtual void UpdateLayerBounds(VRServiceImpl* service,
+                                 mojom::VRLayerBoundsPtr leftBounds,
+                                 mojom::VRLayerBoundsPtr rightBounds) = 0;
+
+  virtual void AddService(VRServiceImpl* service);
+  virtual void RemoveService(VRServiceImpl* service);
+
+  // TODO(shaobo.yan@intel.com): Checks should be done against VRDisplayImpl and
+  // the name should be considered.
+  virtual bool IsAccessAllowed(VRServiceImpl* service);
+  virtual bool IsPresentingService(VRServiceImpl* service);
+
+  virtual void OnDisplayChanged();
+  virtual void OnExitPresent(VRServiceImpl* service);
+
+ protected:
+  // Each Service have one VRDisplay with one VRDevice.
+  // TODO(shaobo.yan@intel.com): Since the VRDisplayImpl knows its VRServiceImpl
+  // we should
+  // only need to store the VRDisplayImpl.
+  using DisplayClientMap = std::map<VRServiceImpl*, VRDisplayImpl*>;
+  DisplayClientMap displays_;
+
+  // TODO(shaobo.yan@intel.com): Should track presenting VRDisplayImpl instead.
+  VRServiceImpl* presenting_service_;
 
  private:
   VRDeviceProvider* provider_;
diff --git a/device/vr/vr_device_manager.cc b/device/vr/vr_device_manager.cc
index b8c99ea..bea824e 100644
--- a/device/vr/vr_device_manager.cc
+++ b/device/vr/vr_device_manager.cc
@@ -23,8 +23,6 @@
 
 VRDeviceManager::VRDeviceManager()
     : vr_initialized_(false),
-      presenting_service_(nullptr),
-      presenting_device_(nullptr),
       keep_alive_(false),
       has_scheduled_poll_(false) {
 // Register VRDeviceProviders for the current platform
@@ -35,8 +33,6 @@
 
 VRDeviceManager::VRDeviceManager(std::unique_ptr<VRDeviceProvider> provider)
     : vr_initialized_(false),
-      presenting_service_(nullptr),
-      presenting_device_(nullptr),
       keep_alive_(true),
       has_scheduled_poll_(false) {
   thread_checker_.DetachFromThread();
@@ -56,26 +52,6 @@
   return g_vr_device_manager;
 }
 
-// Returns the requested device with the requested id if the specified service
-// is allowed to access it.
-VRDevice* VRDeviceManager::GetAllowedDevice(VRServiceImpl* service,
-                                            unsigned int index) {
-  VRDeviceManager* device_manager = GetInstance();
-
-  // If another service is presenting to the requested device don't allow other
-  // services to access it. That could potentially allow them to spy on
-  // where the user is looking on another page, spam another application with
-  // pose resets, etc.
-  if (device_manager->presenting_service_ &&
-      device_manager->presenting_service_ != service) {
-    if (device_manager->presenting_device_ &&
-        device_manager->presenting_device_->id() == index)
-      return nullptr;
-  }
-
-  return device_manager->GetDevice(index);
-}
-
 void VRDeviceManager::SetInstance(VRDeviceManager* instance) {
   // Unit tests can create multiple instances but only one should exist at any
   // given time so g_vr_device_manager should only go from nullptr to
@@ -90,21 +66,20 @@
 }
 
 void VRDeviceManager::AddService(VRServiceImpl* service) {
-  services_.push_back(service);
+  // Loop through any currently active devices and send Connected messages to
+  // the service. Future devices that come online will send a Connected message
+  // when they are created.
+  GetVRDevices(service);
 
-  // Ensure that the device providers are initialized
-  InitializeProviders();
+  services_.push_back(service);
 }
 
 void VRDeviceManager::RemoveService(VRServiceImpl* service) {
   services_.erase(std::remove(services_.begin(), services_.end(), service),
                   services_.end());
 
-  if (service == presenting_service_) {
-    presenting_device_->ExitPresent();
-
-    presenting_service_ = nullptr;
-    presenting_device_ = nullptr;
+  for (auto device : devices_) {
+    device.second->RemoveService(service);
   }
 
   if (services_.empty() && !keep_alive_) {
@@ -113,7 +88,7 @@
   }
 }
 
-mojo::Array<VRDisplayPtr> VRDeviceManager::GetVRDevices() {
+bool VRDeviceManager::GetVRDevices(VRServiceImpl* service) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
   InitializeProviders();
@@ -122,7 +97,9 @@
   for (const auto& provider : providers_)
     provider->GetDevices(&devices);
 
-  mojo::Array<VRDisplayPtr> out_devices;
+  if (devices.empty())
+    return false;
+
   for (auto* device : devices) {
     if (device->id() == VR_DEVICE_LAST_ID)
       continue;
@@ -130,17 +107,16 @@
     if (devices_.find(device->id()) == devices_.end())
       devices_[device->id()] = device;
 
-    VRDisplayPtr vr_device_info = device->GetVRDevice();
-    if (vr_device_info.is_null())
-      continue;
-
-    // GetVRDevice should always set the index of the VRDisplay to its own id.
-    DCHECK(vr_device_info->index == device->id());
-
-    out_devices.push_back(std::move(vr_device_info));
+    device->AddService(service);
   }
 
-  return out_devices;
+  return true;
+}
+
+unsigned int VRDeviceManager::GetNumberOfConnectedDevices() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  return devices_.size();
 }
 
 VRDevice* VRDeviceManager::GetDevice(unsigned int index) {
@@ -157,143 +133,12 @@
   return iter->second;
 }
 
-// These dispatchers must use Clone() instead of std::move to ensure that
-// if there are multiple registered services they all get a copy of the data.
-void VRDeviceManager::OnDeviceChanged(VRDisplayPtr device) {
-  for (const auto& service : services_)
-    service->client()->OnDisplayChanged(device.Clone());
-}
-
-bool VRDeviceManager::RequestPresent(VRServiceImpl* service,
-                                     unsigned int index,
-                                     bool secure_origin) {
-  // Is anything presenting currently?
-  if (presenting_service_) {
-    // Should never have a presenting service without a presenting device.
-    DCHECK(presenting_device_);
-
-    // Fail if the currently presenting service is not the one making the
-    // request.
-    if (presenting_service_ != service)
-      return false;
-
-    // If we are switching presentation from the currently presenting service to
-    // a new device stop presening to the previous one.
-    if (presenting_device_->id() != index) {
-      // Tell the device to stop presenting.
-      presenting_device_->ExitPresent();
-
-      // Only the presenting service needs to be notified that presentation is
-      // ending on the previous device.
-      presenting_service_->client()->OnExitPresent(presenting_device_->id());
-      presenting_device_ = nullptr;
-    }
-
-    presenting_service_ = nullptr;
-  }
-
-  VRDevice* requested_device = GetDevice(index);
-  // Can't present to a device that doesn't exist.
-  if (!requested_device)
-    return false;
-
-  // Attempt to begin presenting to this device. This could fail for any number
-  // of device-specific reasons.
-  if (!requested_device->RequestPresent(secure_origin))
-    return false;
-
-  // Successfully began presenting!
-  presenting_service_ = service;
-  presenting_device_ = requested_device;
-
-  return true;
-}
-
-void VRDeviceManager::ExitPresent(VRServiceImpl* service, unsigned int index) {
-  // Don't allow services other than the currently presenting one to exit
-  // presentation.
-  if (presenting_service_ != service)
-    return;
-
-  // Should never have a presenting service without a presenting device.
-  DCHECK(presenting_device_);
-
-  // Fail if the specified device is not currently presenting.
-  if (presenting_device_->id() != index)
-    return;
-
-  // Tell the client we're done. This must happen before the device's
-  // ExitPresent to avoid invalid mojo state.
-  if (presenting_service_->client()) {
-    presenting_service_->client()->OnExitPresent(index);
-  }
-
-  // Tell the device to stop presenting.
-  presenting_device_->ExitPresent();
-
-  // Clear the presenting service and device.
-  presenting_service_ = nullptr;
-  presenting_device_ = nullptr;
-}
-
-void VRDeviceManager::SubmitFrame(VRServiceImpl* service,
-                                  unsigned int index,
-                                  VRPosePtr pose) {
-  // Don't allow services other than the currently presenting one to submit any
-  // frames.
-  if (presenting_service_ != service)
-    return;
-
-  // Should never have a presenting service without a presenting device.
-  DCHECK(presenting_device_);
-
-  // Don't submit frames to devices other than the currently presenting one.
-  if (presenting_device_->id() != index)
-    return;
-
-  presenting_device_->SubmitFrame(std::move(pose));
-}
-
-void VRDeviceManager::OnDeviceConnectionStatusChanged(VRDevice* device,
-                                                      bool is_connected) {
-  if (is_connected) {
-    VRDisplayPtr vr_device_info = device->GetVRDevice();
-    if (vr_device_info.is_null())
-      return;
-
-    vr_device_info->index = device->id();
-
-    for (const auto& service : services_)
-      service->client()->OnDisplayConnected(vr_device_info.Clone());
-  } else {
-    for (const auto& service : services_)
-      service->client()->OnDisplayDisconnected(device->id());
-  }
-}
-
-void VRDeviceManager::OnPresentEnded(VRDevice* device) {
-  // Ensure the presenting device is the one that we've been requested to stop.
-  if (!presenting_device_ || presenting_device_ != device)
-    return;
-
-  // Should never have a presenting device without a presenting service.
-  DCHECK(presenting_service_);
-
-  // Notify the presenting service that it's been forced to end presentation.
-  presenting_service_->client()->OnExitPresent(device->id());
-
-  // Clear the presenting service and device.
-  presenting_service_ = nullptr;
-  presenting_device_ = nullptr;
-}
-
 void VRDeviceManager::InitializeProviders() {
   if (vr_initialized_) {
     return;
   }
 
   for (const auto& provider : providers_) {
-    provider->SetClient(this);
     provider->Initialize();
   }
 
diff --git a/device/vr/vr_device_manager.h b/device/vr/vr_device_manager.h
index 2a3bc206..b8b9fda 100644
--- a/device/vr/vr_device_manager.h
+++ b/device/vr/vr_device_manager.h
@@ -15,7 +15,6 @@
 #include "base/memory/linked_ptr.h"
 #include "base/threading/thread_checker.h"
 #include "base/timer/timer.h"
-#include "device/vr/vr_client_dispatcher.h"
 #include "device/vr/vr_device.h"
 #include "device/vr/vr_device_provider.h"
 #include "device/vr/vr_export.h"
@@ -25,36 +24,20 @@
 
 namespace device {
 
-class VRDeviceManager : public VRClientDispatcher {
+class VRDeviceManager {
  public:
   DEVICE_VR_EXPORT virtual ~VRDeviceManager();
 
   // Returns the VRDeviceManager singleton.
   static VRDeviceManager* GetInstance();
 
-  // Gets a VRDevice instance if the specified service is allowed to access it.
-  DEVICE_VR_EXPORT static VRDevice* GetAllowedDevice(VRServiceImpl* service,
-                                                     unsigned int index);
-
   // Adds a listener for device manager events. VRDeviceManager does not own
   // this object.
   void AddService(VRServiceImpl* service);
   void RemoveService(VRServiceImpl* service);
 
-  DEVICE_VR_EXPORT mojo::Array<VRDisplayPtr> GetVRDevices();
-
-  // Manage presentation to only allow a single service and device at a time.
-  DEVICE_VR_EXPORT bool RequestPresent(VRServiceImpl* service,
-                                       unsigned int index,
-                                       bool secure_origin);
-  DEVICE_VR_EXPORT void ExitPresent(VRServiceImpl* service, unsigned int index);
-  void SubmitFrame(VRServiceImpl* service, unsigned int index, VRPosePtr pose);
-
-  // VRClientDispatcher implementation
-  void OnDeviceChanged(VRDisplayPtr device) override;
-  void OnDeviceConnectionStatusChanged(VRDevice* device,
-                                       bool is_connected) override;
-  void OnPresentEnded(VRDevice* device) override;
+  DEVICE_VR_EXPORT bool GetVRDevices(VRServiceImpl* service);
+  DEVICE_VR_EXPORT unsigned int GetNumberOfConnectedDevices();
 
  private:
   friend class VRDeviceManagerTest;
@@ -89,10 +72,6 @@
   using ServiceList = std::vector<VRServiceImpl*>;
   ServiceList services_;
 
-  // Only one service and device is allowed to present at a time.
-  VRServiceImpl* presenting_service_;
-  VRDevice* presenting_device_;
-
   // For testing. If true will not delete self when consumer count reaches 0.
   bool keep_alive_;
 
diff --git a/device/vr/vr_device_manager_unittest.cc b/device/vr/vr_device_manager_unittest.cc
index 454f6c4..5298f72 100644
--- a/device/vr/vr_device_manager_unittest.cc
+++ b/device/vr/vr_device_manager_unittest.cc
@@ -32,6 +32,7 @@
  protected:
   FakeVRDeviceProvider* provider_;
   std::unique_ptr<VRDeviceManager> device_manager_;
+  std::unique_ptr<VRServiceImpl> vr_service_;
 
   DISALLOW_COPY_AND_ASSIGN(VRDeviceManagerTest);
 };
@@ -44,6 +45,7 @@
   std::unique_ptr<FakeVRDeviceProvider> provider(new FakeVRDeviceProvider());
   provider_ = provider.get();
   device_manager_.reset(new VRDeviceManager(std::move(provider)));
+  vr_service_.reset(new VRServiceImpl());
 }
 
 TEST_F(VRDeviceManagerTest, InitializationTest) {
@@ -53,18 +55,15 @@
   // initialized yet or the providesr have been released.
   // The mojom::VRService should initialize each of it's providers upon it's own
   // initialization.
-  mojo::Array<VRDisplayPtr> webvr_devices;
-  webvr_devices = device_manager_->GetVRDevices();
+  device_manager_->GetVRDevices(vr_service_.get());
   EXPECT_TRUE(provider_->IsInitialized());
 }
 
 TEST_F(VRDeviceManagerTest, GetDevicesBasicTest) {
-  mojo::Array<VRDisplayPtr> webvr_devices;
-  webvr_devices = device_manager_->GetVRDevices();
+  bool success = device_manager_->GetVRDevices(vr_service_.get());
   // Calling GetVRDevices should initialize the providers.
   EXPECT_TRUE(provider_->IsInitialized());
-  // Should successfully return zero devices when none are available.
-  EXPECT_EQ(0u, webvr_devices.size());
+  EXPECT_FALSE(success);
 
   // GetDeviceByIndex should return nullptr if an invalid index in queried.
   VRDevice* queried_device = GetDevice(1);
@@ -72,31 +71,21 @@
 
   std::unique_ptr<FakeVRDevice> device1(new FakeVRDevice(provider_));
   provider_->AddDevice(device1.get());
-  webvr_devices = device_manager_->GetVRDevices();
+  success = device_manager_->GetVRDevices(vr_service_.get());
+  EXPECT_TRUE(success);
   // Should have successfully returned one device.
-  EXPECT_EQ(1u, webvr_devices.size());
-  // The WebVRDevice index should match the device id.
-  EXPECT_EQ(webvr_devices[0]->index, device1->id());
+  EXPECT_EQ(device1.get(), GetDevice(device1->id()));
 
   std::unique_ptr<FakeVRDevice> device2(new FakeVRDevice(provider_));
   provider_->AddDevice(device2.get());
-  webvr_devices = device_manager_->GetVRDevices();
-  // Should have successfully returned two devices.
-  EXPECT_EQ(2u, webvr_devices.size());
-  // NOTE: Returned WebVRDevices are not required to be in any particular order.
+  success = device_manager_->GetVRDevices(vr_service_.get());
+  EXPECT_TRUE(success);
 
   // Querying the WebVRDevice index should return the correct device.
-  queried_device = GetDevice(device1->id());
-  EXPECT_EQ(device1.get(), queried_device);
-  queried_device = GetDevice(device2->id());
-  EXPECT_EQ(device2.get(), queried_device);
-
-  provider_->RemoveDevice(device1.get());
-  webvr_devices = device_manager_->GetVRDevices();
-  // Should have successfully returned one device.
-  EXPECT_EQ(1u, webvr_devices.size());
-  // The WebVRDevice index should match the only remaining device id.
-  EXPECT_EQ(webvr_devices[0]->index, device2->id());
+  VRDevice* queried_device1 = GetDevice(device1->id());
+  EXPECT_EQ(device1.get(), queried_device1);
+  VRDevice* queried_device2 = GetDevice(device2->id());
+  EXPECT_EQ(device2.get(), queried_device2);
 }
 
 }  // namespace device
diff --git a/device/vr/vr_device_provider.h b/device/vr/vr_device_provider.h
index f388278..2793cbc 100644
--- a/device/vr/vr_device_provider.h
+++ b/device/vr/vr_device_provider.h
@@ -9,8 +9,8 @@
 
 namespace device {
 
-class VRClientDispatcher;
 class VRDevice;
+class VRServiceImpl;
 
 class VRDeviceProvider {
  public:
@@ -23,8 +23,6 @@
   virtual void Initialize() = 0;
 
   virtual void PollEvents() {}
-
-  virtual void SetClient(VRClientDispatcher* client) {}
 };
 
 }  // namespace device
diff --git a/device/vr/vr_display_impl.cc b/device/vr/vr_display_impl.cc
new file mode 100644
index 0000000..c074205
--- /dev/null
+++ b/device/vr/vr_display_impl.cc
@@ -0,0 +1,49 @@
+// Copyright 2016 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 <utility>
+
+#include "base/bind.h"
+#include "device/vr/vr_device.h"
+#include "device/vr/vr_service_impl.h"
+
+namespace device {
+
+VRDisplayImpl::VRDisplayImpl(device::VRDevice* device, VRServiceImpl* service)
+    : binding_(this), device_(device), service_(service) {
+  mojom::VRDisplayInfoPtr display_info = device->GetVRDevice();
+  service->client()->OnDisplayConnected(binding_.CreateInterfacePtrAndBind(),
+                                        mojo::GetProxy(&client_),
+                                        std::move(display_info));
+}
+
+VRDisplayImpl::~VRDisplayImpl() {}
+
+void VRDisplayImpl::GetPose(const GetPoseCallback& callback) {
+  callback.Run(device_->GetPose(service_.get()));
+}
+
+void VRDisplayImpl::ResetPose() {
+  device_->ResetPose(service_.get());
+}
+
+void VRDisplayImpl::RequestPresent(bool secureOrigin,
+                                   const RequestPresentCallback& callback) {
+  callback.Run(device_->RequestPresent(service_.get(), secureOrigin));
+}
+
+void VRDisplayImpl::ExitPresent() {
+  device_->ExitPresent(service_.get());
+}
+
+void VRDisplayImpl::SubmitFrame(mojom::VRPosePtr pose) {
+  device_->SubmitFrame(service_.get(), std::move(pose));
+}
+
+void VRDisplayImpl::UpdateLayerBounds(mojom::VRLayerBoundsPtr leftBounds,
+                                      mojom::VRLayerBoundsPtr rightBounds) {
+  device_->UpdateLayerBounds(service_.get(), std::move(leftBounds),
+                             std::move(rightBounds));
+}
+}
diff --git a/device/vr/vr_display_impl.h b/device/vr/vr_display_impl.h
new file mode 100644
index 0000000..dc34ed1
--- /dev/null
+++ b/device/vr/vr_display_impl.h
@@ -0,0 +1,47 @@
+// Copyright 2016 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 DEVICE_VR_VR_DISPLAY_IMPL_H
+#define DEVICE_VR_VR_DISPLAY_IMPL_H
+
+#include <memory>
+
+#include "base/macros.h"
+
+#include "device/vr/vr_device.h"
+#include "device/vr/vr_export.h"
+#include "device/vr/vr_service.mojom.h"
+#include "mojo/public/cpp/bindings/binding.h"
+
+namespace device {
+
+class VRDisplayImpl : public mojom::VRDisplay {
+ public:
+  VRDisplayImpl(device::VRDevice* device, VRServiceImpl* service);
+  ~VRDisplayImpl() override;
+
+  mojom::VRDisplayClient* client() { return client_.get(); }
+
+ private:
+  friend class VRServiceImpl;
+
+  void GetPose(const GetPoseCallback& callback) override;
+  void ResetPose() override;
+
+  void RequestPresent(bool secureOrigin,
+                      const RequestPresentCallback& callback) override;
+  void ExitPresent() override;
+  void SubmitFrame(mojom::VRPosePtr pose) override;
+  void UpdateLayerBounds(mojom::VRLayerBoundsPtr leftBounds,
+                         mojom::VRLayerBoundsPtr rightBounds) override;
+
+  mojo::Binding<mojom::VRDisplay> binding_;
+  mojom::VRDisplayClientPtr client_;
+  device::VRDevice* device_;
+  std::unique_ptr<VRServiceImpl> service_;
+};
+
+}  // namespace device
+
+#endif  //  DEVICE_VR_VR_DISPLAY_IMPL_H
diff --git a/device/vr/vr_service.mojom b/device/vr/vr_service.mojom
index 5dbf702..ca297d3 100644
--- a/device/vr/vr_service.mojom
+++ b/device/vr/vr_service.mojom
@@ -1,8 +1,7 @@
 // Copyright 2015 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.
+// Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file.
 
-module device;
+module device.mojom;
 
 // A field of view, given by 4 degrees describing the view from a center point.
 struct VRFieldOfView {
@@ -48,39 +47,46 @@
   float sizeZ;
 };
 
-struct VRDisplay {
-   uint32 index;
-   string displayName;
-   VRDisplayCapabilities capabilities;
-   VRStageParameters? stageParameters;
-   VREyeParameters leftEye;
-   VREyeParameters rightEye;
+struct VRDisplayInfo {
+  uint32 index;
+  string displayName;
+  VRDisplayCapabilities capabilities;
+  VRStageParameters? stageParameters;
+  VREyeParameters leftEye;
+  VREyeParameters rightEye;
 };
 
 struct VRLayerBounds {
-   float left;
-   float top;
-   float width;
-   float height;
+  float left;
+  float top;
+  float width;
+  float height;
 };
 
+// TODO(shaobo.yan@intel.com) : Add comments to describe these interfaces about how to use and where they live.
 interface VRService {
-  SetClient(VRServiceClient client);
-
-  GetDisplays() => (array<VRDisplay> displays);
-  [Sync]
-  GetPose(uint32 index) => (VRPose? pose);
-  ResetPose(uint32 index);
-
-  RequestPresent(uint32 index, bool secureOrigin) => (bool success);
-  ExitPresent(uint32 index);
-  SubmitFrame(uint32 index, VRPose? pose);
-  UpdateLayerBounds(uint32 index, VRLayerBounds leftBounds, VRLayerBounds rightBounds);
+  // TODO(shaobo.yan@intel.com) : Use a factory function which took a VRServiceClient
+  // so we would never have a half-initialized VRService.
+  SetClient(VRServiceClient client) => (uint32 numberOfConnectedDevices);
 };
 
 interface VRServiceClient {
-  OnDisplayChanged(VRDisplay display);
-  OnExitPresent(uint32 index);
-  OnDisplayConnected(VRDisplay display);
-  OnDisplayDisconnected(uint32 index);
+  OnDisplayConnected(VRDisplay display, VRDisplayClient& request, VRDisplayInfo displayInfo);
+};
+
+interface VRDisplay {
+
+  [Sync]
+  GetPose() => (VRPose? pose);
+  ResetPose();
+
+  RequestPresent(bool secureOrigin) => (bool success);
+  ExitPresent();
+  SubmitFrame(VRPose? pose);
+  UpdateLayerBounds(VRLayerBounds leftBounds, VRLayerBounds rightBounds);
+};
+
+interface VRDisplayClient {
+  OnDisplayChanged(VRDisplayInfo display);
+  OnExitPresent();
 };
diff --git a/device/vr/vr_service_impl.cc b/device/vr/vr_service_impl.cc
index 6ea486de..ad12ace 100644
--- a/device/vr/vr_service_impl.cc
+++ b/device/vr/vr_service_impl.cc
@@ -18,74 +18,53 @@
   RemoveFromDeviceManager();
 }
 
-void VRServiceImpl::BindRequest(mojo::InterfaceRequest<VRService> request) {
+void VRServiceImpl::BindRequest(
+    mojo::InterfaceRequest<mojom::VRService> request) {
   VRServiceImpl* service = new VRServiceImpl();
   service->Bind(std::move(request));
 }
 
-void VRServiceImpl::Bind(mojo::InterfaceRequest<VRService> request) {
-  binding_.reset(new mojo::Binding<VRService>(this, std::move(request)));
+// Gets a VRDisplayPtr unique to this service so that the associated page can
+// communicate with the VRDevice.
+VRDisplayImpl* VRServiceImpl::GetVRDisplayImpl(VRDevice* device) {
+  DisplayImplMap::iterator it = displays_.find(device);
+  if (it != displays_.end())
+    return it->second.get();
+
+  VRDisplayImpl* display_impl = new VRDisplayImpl(device, this);
+  displays_[device] = base::WrapUnique(display_impl);
+  return display_impl;
+}
+
+void VRServiceImpl::Bind(mojo::InterfaceRequest<mojom::VRService> request) {
+  // TODO(shaobo.yan@intel.com) : Keep one binding_ and use close and rebind.
+  binding_.reset(new mojo::Binding<mojom::VRService>(this, std::move(request)));
   binding_->set_connection_error_handler(base::Bind(
       &VRServiceImpl::RemoveFromDeviceManager, base::Unretained(this)));
 }
 
 void VRServiceImpl::RemoveFromDeviceManager() {
+  displays_.clear();
   VRDeviceManager* device_manager = VRDeviceManager::GetInstance();
   device_manager->RemoveService(this);
 }
 
-void VRServiceImpl::SetClient(VRServiceClientPtr client) {
+void VRServiceImpl::RemoveDevice(VRDevice* device) {
+  displays_.erase(device);
+}
+
+void VRServiceImpl::SetClient(mojom::VRServiceClientPtr service_client,
+                              const SetClientCallback& callback) {
   DCHECK(!client_.get());
 
-  client_ = std::move(client);
+  client_ = std::move(service_client);
   VRDeviceManager* device_manager = VRDeviceManager::GetInstance();
+  // Once a client has been connected AddService will force any VRDisplays to
+  // send OnConnected to it so that it's populated with the currently active
+  // displays. Thereafer it will stay up to date by virtue of listening for new
+  // connected events.
   device_manager->AddService(this);
-}
-
-void VRServiceImpl::GetDisplays(const GetDisplaysCallback& callback) {
-  VRDeviceManager* device_manager = VRDeviceManager::GetInstance();
-  callback.Run(device_manager->GetVRDevices());
-}
-
-void VRServiceImpl::GetPose(uint32_t index, const GetPoseCallback& callback) {
-  VRDevice* device = VRDeviceManager::GetAllowedDevice(this, index);
-
-  if (device) {
-    callback.Run(device->GetPose());
-  } else {
-    callback.Run(nullptr);
-  }
-}
-
-void VRServiceImpl::ResetPose(uint32_t index) {
-  VRDevice* device = VRDeviceManager::GetAllowedDevice(this, index);
-  if (device)
-    device->ResetPose();
-}
-
-void VRServiceImpl::RequestPresent(uint32_t index,
-                                   bool secureOrigin,
-                                   const RequestPresentCallback& callback) {
-  VRDeviceManager* device_manager = VRDeviceManager::GetInstance();
-  callback.Run(device_manager->RequestPresent(this, index, secureOrigin));
-}
-
-void VRServiceImpl::ExitPresent(uint32_t index) {
-  VRDeviceManager* device_manager = VRDeviceManager::GetInstance();
-  device_manager->ExitPresent(this, index);
-}
-
-void VRServiceImpl::SubmitFrame(uint32_t index, VRPosePtr pose) {
-  VRDeviceManager* device_manager = VRDeviceManager::GetInstance();
-  device_manager->SubmitFrame(this, index, std::move(pose));
-}
-
-void VRServiceImpl::UpdateLayerBounds(uint32_t index,
-                                      VRLayerBoundsPtr leftBounds,
-                                      VRLayerBoundsPtr rightBounds) {
-  VRDevice* device = VRDeviceManager::GetAllowedDevice(this, index);
-  if (device)
-    device->UpdateLayerBounds(std::move(leftBounds), std::move(rightBounds));
+  callback.Run(device_manager->GetNumberOfConnectedDevices());
 }
 
 }  // namespace device
diff --git a/device/vr/vr_service_impl.h b/device/vr/vr_service_impl.h
index 50a4471..778dc518 100644
--- a/device/vr/vr_service_impl.h
+++ b/device/vr/vr_service_impl.h
@@ -9,47 +9,47 @@
 
 #include "base/macros.h"
 
+#include "device/vr/vr_device.h"
+#include "device/vr/vr_display_impl.h"
 #include "device/vr/vr_export.h"
 #include "device/vr/vr_service.mojom.h"
 #include "mojo/public/cpp/bindings/binding.h"
 
 namespace device {
 
-class VRServiceImpl : public VRService {
+class VRServiceImpl : public mojom::VRService {
  public:
   DEVICE_VR_EXPORT ~VRServiceImpl() override;
 
   DEVICE_VR_EXPORT static void BindRequest(
-      mojo::InterfaceRequest<VRService> request);
+      mojo::InterfaceRequest<mojom::VRService> request);
 
-  VRServiceClientPtr& client() { return client_; }
+  mojom::VRServiceClient* client() { return client_.get(); }
+
+  VRDisplayImpl* GetVRDisplayImpl(VRDevice* device);
 
  private:
   friend class VRServiceTestBinding;
+  friend class VRDeviceManagerTest;
+  friend class VRDisplayImpl;
 
   DEVICE_VR_EXPORT VRServiceImpl();
 
   // Mojo connection handling.
-  DEVICE_VR_EXPORT void Bind(mojo::InterfaceRequest<VRService> request);
+  DEVICE_VR_EXPORT void Bind(mojo::InterfaceRequest<mojom::VRService> request);
   void RemoveFromDeviceManager();
+  void RemoveDevice(VRDevice* device);
 
   // mojom::VRService implementation
-  void SetClient(VRServiceClientPtr client) override;
-  void GetDisplays(const GetDisplaysCallback& callback) override;
-  void GetPose(uint32_t index, const GetPoseCallback& callback) override;
-  void ResetPose(uint32_t index) override;
+  void SetClient(mojom::VRServiceClientPtr service_client,
+                 const SetClientCallback& callback) override;
 
-  void RequestPresent(uint32_t index,
-                      bool secureOrigin,
-                      const RequestPresentCallback& callback) override;
-  void ExitPresent(uint32_t index) override;
-  void SubmitFrame(uint32_t index, VRPosePtr pose) override;
-  void UpdateLayerBounds(uint32_t index,
-                         VRLayerBoundsPtr leftBounds,
-                         VRLayerBoundsPtr rightBounds) override;
+  using DisplayImplMap = std::map<VRDevice*, std::unique_ptr<VRDisplayImpl>>;
+  DisplayImplMap displays_;
 
-  std::unique_ptr<mojo::Binding<VRService>> binding_;
-  VRServiceClientPtr client_;
+  mojom::VRServiceClientPtr client_;
+
+  std::unique_ptr<mojo::Binding<mojom::VRService>> binding_;
 
   DISALLOW_COPY_AND_ASSIGN(VRServiceImpl);
 };
diff --git a/device/vr/vr_service_impl_unittest.cc b/device/vr/vr_service_impl_unittest.cc
index 300bf0dbf..f0b8ce2 100644
--- a/device/vr/vr_service_impl_unittest.cc
+++ b/device/vr/vr_service_impl_unittest.cc
@@ -17,28 +17,8 @@
 
 namespace device {
 
-class MockVRServiceClient : public VRServiceClient {
- public:
-  MOCK_METHOD1(OnDisplayChanged, void(const VRDisplay& display));
-  void OnDisplayChanged(VRDisplayPtr display) override {
-    OnDisplayChanged(*display);
-    last_display_ = std::move(display);
-  }
-
-  MOCK_METHOD1(OnExitPresent, void(uint32_t index));
-
-  MOCK_METHOD1(OnDisplayConnected, void(const VRDisplay& display));
-  void OnDisplayConnected(VRDisplayPtr display) override {
-    OnDisplayConnected(*display);
-    last_display_ = std::move(display);
-  }
-  void OnDisplayDisconnected(unsigned index) override {}
-
-  const VRDisplayPtr& LastDisplay() { return last_display_; }
-
- private:
-  VRDisplayPtr last_display_;
-};
+// TODO(shaobo.yan@intel.com) : Update the whole unittest.
+class MockVRServiceClient : public mojom::VRServiceClient {};
 
 class VRServiceTestBinding {
  public:
@@ -47,10 +27,19 @@
     service_impl_.reset(new VRServiceImpl());
     service_impl_->Bind(std::move(request));
 
-    VRServiceClientPtr client_ptr;
-    client_binding_.reset(new mojo::Binding<VRServiceClient>(
-        &mock_client_, mojo::GetProxy(&client_ptr)));
-    service_impl_->SetClient(std::move(client_ptr));
+    client_binding_.reset(new mojo::Binding<mojom::VRServiceClient>(
+        mock_client_, mojo::GetProxy(&client_ptr_)));
+  }
+
+  void SetClient() {
+    service_impl_->SetClient(
+        std::move(client_ptr_),
+        base::Bind(&device::VRServiceTestBinding::SetNumberOfDevices,
+                   base::Unretained(this)));
+  }
+
+  void SetNumberOfDevices(unsigned int number_of_devices) {
+    number_of_devices_ = number_of_devices;
   }
 
   void Close() {
@@ -58,15 +47,17 @@
     service_impl_.reset();
   }
 
-  MockVRServiceClient& client() { return mock_client_; }
+  MockVRServiceClient* client() { return mock_client_; }
   VRServiceImpl* service() { return service_impl_.get(); }
 
  private:
+  mojom::VRServiceClientPtr client_ptr_;
   std::unique_ptr<VRServiceImpl> service_impl_;
-  mojo::InterfacePtr<VRService> service_ptr_;
+  mojo::InterfacePtr<mojom::VRService> service_ptr_;
 
-  MockVRServiceClient mock_client_;
-  std::unique_ptr<mojo::Binding<VRServiceClient>> client_binding_;
+  MockVRServiceClient* mock_client_;
+  std::unique_ptr<mojo::Binding<mojom::VRServiceClient>> client_binding_;
+  unsigned int number_of_devices_;
 
   DISALLOW_COPY_AND_ASSIGN(VRServiceTestBinding);
 };
@@ -86,13 +77,13 @@
   void TearDown() override { base::RunLoop().RunUntilIdle(); }
 
   std::unique_ptr<VRServiceTestBinding> BindService() {
-    return std::unique_ptr<VRServiceTestBinding>(new VRServiceTestBinding());
+    auto test_binding = base::WrapUnique(new VRServiceTestBinding());
+    test_binding->SetClient();
+    return test_binding;
   }
 
   size_t ServiceCount() { return device_manager_->services_.size(); }
 
-  bool presenting() { return !!device_manager_->presenting_service_; }
-
   base::MessageLoop message_loop_;
   FakeVRDeviceProvider* provider_;
   std::unique_ptr<VRDeviceManager> device_manager_;
@@ -122,86 +113,4 @@
   EXPECT_EQ(0u, ServiceCount());
 }
 
-// Ensure that DeviceChanged calls are dispatched to all active services.
-TEST_F(VRServiceImplTest, DeviceChangedDispatched) {
-  std::unique_ptr<VRServiceTestBinding> service_1 = BindService();
-  std::unique_ptr<VRServiceTestBinding> service_2 = BindService();
-
-  EXPECT_CALL(service_1->client(), OnDisplayChanged(_));
-  EXPECT_CALL(service_2->client(), OnDisplayChanged(_));
-
-  std::unique_ptr<FakeVRDevice> device(new FakeVRDevice(provider_));
-  device_manager_->OnDeviceChanged(device->GetVRDevice());
-
-  base::RunLoop().RunUntilIdle();
-
-  EXPECT_EQ(device->id(), service_1->client().LastDisplay()->index);
-  EXPECT_EQ(device->id(), service_2->client().LastDisplay()->index);
-}
-
-// Ensure that presenting devices cannot be accessed by other services
-TEST_F(VRServiceImplTest, DevicePresentationIsolation) {
-  std::unique_ptr<VRServiceTestBinding> service_1 = BindService();
-  std::unique_ptr<VRServiceTestBinding> service_2 = BindService();
-
-  std::unique_ptr<FakeVRDevice> device(new FakeVRDevice(provider_));
-  provider_->AddDevice(device.get());
-
-  // Ensure the device manager has seen the fake device
-  device_manager_->GetVRDevices();
-
-  // When not presenting either service should be able to access the device
-  EXPECT_EQ(device.get(), VRDeviceManager::GetAllowedDevice(
-                              service_1->service(), device->id()));
-  EXPECT_EQ(device.get(), VRDeviceManager::GetAllowedDevice(
-                              service_2->service(), device->id()));
-
-  // Begin presenting to the fake device with service 1
-  EXPECT_TRUE(device_manager_->RequestPresent(service_1->service(),
-                                              device->id(), true));
-
-  EXPECT_TRUE(presenting());
-
-  // Service 2 should not be able to present to the device while service 1
-  // is still presenting.
-  EXPECT_FALSE(device_manager_->RequestPresent(service_2->service(),
-                                               device->id(), true));
-
-  // Only the presenting service should be able to access the device
-  EXPECT_EQ(device.get(), VRDeviceManager::GetAllowedDevice(
-                              service_1->service(), device->id()));
-  EXPECT_EQ(nullptr, VRDeviceManager::GetAllowedDevice(service_2->service(),
-                                                       device->id()));
-
-  // Service 2 should not be able to exit presentation to the device
-  device_manager_->ExitPresent(service_2->service(), device->id());
-  EXPECT_TRUE(presenting());
-
-  // Service 1 should be able to exit the presentation it initiated.
-  device_manager_->ExitPresent(service_1->service(), device->id());
-  EXPECT_FALSE(presenting());
-
-  // Once presention had ended both services should be able to access the device
-  EXPECT_EQ(device.get(), VRDeviceManager::GetAllowedDevice(
-                              service_1->service(), device->id()));
-  EXPECT_EQ(device.get(), VRDeviceManager::GetAllowedDevice(
-                              service_2->service(), device->id()));
-}
-
-// Ensure that DeviceChanged calls are dispatched to all active services.
-TEST_F(VRServiceImplTest, DeviceConnectedDispatched) {
-  std::unique_ptr<VRServiceTestBinding> service_1 = BindService();
-  std::unique_ptr<VRServiceTestBinding> service_2 = BindService();
-
-  EXPECT_CALL(service_1->client(), OnDisplayConnected(_));
-  EXPECT_CALL(service_2->client(), OnDisplayConnected(_));
-
-  std::unique_ptr<FakeVRDevice> device(new FakeVRDevice(provider_));
-  device_manager_->OnDeviceConnectionStatusChanged(device.get(), true);
-
-  base::RunLoop().RunUntilIdle();
-
-  EXPECT_EQ(device->id(), service_1->client().LastDisplay()->index);
-  EXPECT_EQ(device->id(), service_2->client().LastDisplay()->index);
-}
 }
diff --git a/docs/ozone_overview.md b/docs/ozone_overview.md
index db4d0e44..b32fd7b 100644
--- a/docs/ozone_overview.md
+++ b/docs/ozone_overview.md
@@ -130,7 +130,7 @@
 Then to run for example the X11 platform:
 
 ``` shell
-./out/OzoneChromeOS/chrome --ozone-platform=x11 --disable-setuid-sandbox
+./out/OzoneChromeOS/chrome --ozone-platform=x11
 ```
 
 ### Embedded
@@ -155,8 +155,7 @@
 Then to run for example the headless platform:
 
 ``` shell
-./out/OzoneEmbedded/content_shell --disable-setuid-sandbox \
-                                  --ozone-platform=headless \
+./out/OzoneEmbedded/content_shell --ozone-platform=headless \
                                   --ozone-dump-file=/tmp/
 ```
 
@@ -178,7 +177,6 @@
 
 ``` shell
 ./out/OzoneLinuxDesktop/chrome --ozone-platform=x11 \
-                               --disable-setuid-sandbox \
                                --mash
 ```
 
@@ -202,12 +200,10 @@
 ## Running with Ozone
 
 Specify the platform you want to use at runtime using the `--ozone-platform`
-flag. Disabling the setuid sandbox may be required during development.
-
-For example, to run content_shell with the GBM platform:
+flag. For example, to run `content_shell` with the GBM platform:
 
 ``` shell
-content_shell --disable-setuid-sandbox --ozone-platform=gbm
+content_shell --ozone-platform=gbm
 ```
 
 Caveats:
@@ -215,6 +211,8 @@
 * `content_shell` always runs at 800x600 resolution.
 * For the GBM platform, you may need to terminate your X server (or any other
   display server) prior to testing.
+* During development, you may need to configure
+  [sandboxing](linux_sandboxing.md) or to disable it.
 
 ## Ozone Platforms
 
@@ -228,8 +226,7 @@
 command line:
 
 ``` shell
-content_shell --disable-setuid-sandbox \
-              --ozone-platform=headless \
+content_shell --ozone-platform=headless \
               --ozone-dump-file=/tmp/
 ```
 
@@ -270,8 +267,7 @@
 gn args out/OzoneWayland --args="use_ozone=true enable_package_mash_services=true"
 ninja -C out/OzoneWayland chrome
 ./out/OzoneWayland/chrome --ozone-platform=wayland \
-                          --mash \
-                          --disable-setuid-sandbox
+                          --mash
 ```
 
 ### Caca
@@ -298,7 +294,7 @@
 gn args out/OzoneCaca \
         --args="use_ozone=true ozone_platform_caca=true use_sysroot=false ozone_auto_platforms=false toolkit_views=false"
 ninja -C out/OzoneCaca content_shell
-./out/OzoneCaca/content_shell --disable-setuid-sandbox
+./out/OzoneCaca/content_shell
 ```
 
   Note: traditional TTYs are not the ideal browsing experience.<br/>
diff --git a/extensions/test/data/web_view/media_access/check/media_check_guest.html b/extensions/test/data/web_view/media_access/check/media_check_guest.html
index 85d7276..07164c0d 100644
--- a/extensions/test/data/web_view/media_access/check/media_check_guest.html
+++ b/extensions/test/data/web_view/media_access/check/media_check_guest.html
@@ -6,7 +6,7 @@
 <html>
   <head>
     <script type="text/javascript">
-      // A guest that requests media devices, which in turn checks for media
+      // A guest that requests media sources, which in turn checks for media
       // access permission.
       // Notifies the embedder when done via post message. Note that the
       // embedder has to initiate a postMessage first so that guest has a
@@ -23,7 +23,7 @@
         notifyEmbedder(JSON.stringify(['got-sources']));
       };
       var startTest = function() {
-        navigator.mediaDevices.enumerateDevices().then(onSourceInfo);
+        MediaStreamTrack.getSources(onSourceInfo);
       };
       var onPostMessageReceived = function(e) {
         var data = JSON.parse(e.data);
diff --git a/infra/config/recipes.cfg b/infra/config/recipes.cfg
index 9009aef..1fa1a6b 100644
--- a/infra/config/recipes.cfg
+++ b/infra/config/recipes.cfg
@@ -5,7 +5,7 @@
   project_id: "build"
   url: "https://chromium.googlesource.com/chromium/tools/build.git"
   branch: "master"
-  revision: "bac681250e8cb2f4e17ae68dca934d127d3e0b0f"
+  revision: "e506cb3b37b72ec3e696eddf27ec514b069c80a2"
 }
 deps {
   project_id: "depot_tools"
diff --git a/ios/chrome/browser/reading_list/reading_list_model.h b/ios/chrome/browser/reading_list/reading_list_model.h
index 417237e..f84f861 100644
--- a/ios/chrome/browser/reading_list/reading_list_model.h
+++ b/ios/chrome/browser/reading_list/reading_list_model.h
@@ -80,9 +80,6 @@
   // immediately.
   virtual void RemoveEntryByURL(const GURL& url) = 0;
 
-  // Temporary method
-  virtual void RemoveEntryByUrl(const GURL& url) = 0;
-
   // If the |url| is in the reading list and unread, mark it read. If it is in
   // the reading list and read, move it to the top of unread if it is not here
   // already. This may trigger deletion of old read entries.
diff --git a/ios/chrome/browser/reading_list/reading_list_model_factory.cc b/ios/chrome/browser/reading_list/reading_list_model_factory.cc
index ec56e68..5be0560 100644
--- a/ios/chrome/browser/reading_list/reading_list_model_factory.cc
+++ b/ios/chrome/browser/reading_list/reading_list_model_factory.cc
@@ -54,9 +54,9 @@
   auto storage = base::MakeUnique<ReadingListModelStorageDefaults>();
   ios::ChromeBrowserState* chrome_browser_state =
       ios::ChromeBrowserState::FromBrowserState(context);
-  std::unique_ptr<ReadingListModelImpl> reading_list_model(
-      new ReadingListModelImpl(std::move(storage),
-                               chrome_browser_state->GetPrefs()));
+  std::unique_ptr<KeyedService> reading_list_model =
+      base::MakeUnique<ReadingListModelImpl>(std::move(storage),
+                                             chrome_browser_state->GetPrefs());
   return reading_list_model;
 }
 
diff --git a/ios/chrome/browser/reading_list/reading_list_model_impl.cc b/ios/chrome/browser/reading_list/reading_list_model_impl.cc
index 2012052..adb0c8c6 100644
--- a/ios/chrome/browser/reading_list/reading_list_model_impl.cc
+++ b/ios/chrome/browser/reading_list/reading_list_model_impl.cc
@@ -97,11 +97,6 @@
   return false;
 }
 
-// Temporary method
-void ReadingListModelImpl::RemoveEntryByUrl(const GURL& url) {
-  return RemoveEntryByURL(url);
-}
-
 void ReadingListModelImpl::RemoveEntryByURL(const GURL& url) {
   DCHECK(loaded());
   const ReadingListEntry entry(url, std::string());
diff --git a/ios/chrome/browser/reading_list/reading_list_model_impl.h b/ios/chrome/browser/reading_list/reading_list_model_impl.h
index d073d32..a558d9e 100644
--- a/ios/chrome/browser/reading_list/reading_list_model_impl.h
+++ b/ios/chrome/browser/reading_list/reading_list_model_impl.h
@@ -51,9 +51,6 @@
 
   void RemoveEntryByURL(const GURL& url) override;
 
-  // Temporary method
-  void RemoveEntryByUrl(const GURL& url) override;
-
   const ReadingListEntry& AddEntry(const GURL& url,
                                    const std::string& title) override;
 
diff --git a/ios/chrome/browser/reading_list/reading_list_pref_names.cc b/ios/chrome/browser/reading_list/reading_list_pref_names.cc
index d35f822..61f06b17 100644
--- a/ios/chrome/browser/reading_list/reading_list_pref_names.cc
+++ b/ios/chrome/browser/reading_list/reading_list_pref_names.cc
@@ -7,6 +7,8 @@
 namespace reading_list {
 namespace prefs {
 
+// Boolean to track if some reading list entries have never been seen on this
+// device. Not synced.
 const char kReadingListHasUnseenEntries[] = "reading_list.has_unseen_entries";
 
 }  // namespace prefs
diff --git a/ios/chrome/browser/reading_list/reading_list_pref_names.h b/ios/chrome/browser/reading_list/reading_list_pref_names.h
index 81539a90..9a00693 100644
--- a/ios/chrome/browser/reading_list/reading_list_pref_names.h
+++ b/ios/chrome/browser/reading_list/reading_list_pref_names.h
@@ -10,8 +10,6 @@
 namespace reading_list {
 namespace prefs {
 
-// Boolean to track if some reading list entries have never been seen on this
-// device. Not synced.
 extern const char kReadingListHasUnseenEntries[];
 
 }  // namespace prefs
diff --git a/ios/public/provider/chrome/browser/BUILD.gn b/ios/public/provider/chrome/browser/BUILD.gn
index 13002e741..61bab28 100644
--- a/ios/public/provider/chrome/browser/BUILD.gn
+++ b/ios/public/provider/chrome/browser/BUILD.gn
@@ -34,8 +34,6 @@
     "ui/infobar_view_protocol.h",
     "ui/logo_vendor.h",
     "ui/text_field_styling.h",
-    "updatable_resource_provider.h",
-    "updatable_resource_provider.mm",
     "voice/audio_session_controller.h",
     "voice/logo_animation_controller.h",
     "voice/voice_search_bar.h",
@@ -96,8 +94,6 @@
     "test_chrome_browser_provider.mm",
     "test_chrome_provider_initializer.h",
     "test_chrome_provider_initializer.mm",
-    "test_updatable_resource_provider.h",
-    "test_updatable_resource_provider.mm",
     "voice/test_voice_search_provider.h",
     "voice/test_voice_search_provider.mm",
   ]
diff --git a/ios/public/provider/chrome/browser/chrome_browser_provider.h b/ios/public/provider/chrome/browser/chrome_browser_provider.h
index 4fddf096..b94ec3e 100644
--- a/ios/public/provider/chrome/browser/chrome_browser_provider.h
+++ b/ios/public/provider/chrome/browser/chrome_browser_provider.h
@@ -65,7 +65,6 @@
 class SigninErrorProvider;
 class SigninResourcesProvider;
 class LiveTabContextProvider;
-class UpdatableResourceProvider;
 
 // Setter and getter for the provider. The provider should be set early, before
 // any browser code is called.
@@ -84,8 +83,6 @@
   // Registers all prefs that will be used via a PrefService attached to a
   // Profile.
   virtual void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
-  // Returns an UpdatableResourceProvider instance.
-  virtual UpdatableResourceProvider* GetUpdatableResourceProvider();
   // Returns an infobar view conforming to the InfoBarViewProtocol. The returned
   // object is retained.
   virtual InfoBarViewPlaceholder CreateInfoBarView(
diff --git a/ios/public/provider/chrome/browser/chrome_browser_provider.mm b/ios/public/provider/chrome/browser/chrome_browser_provider.mm
index 66a1941..e1d9939 100644
--- a/ios/public/provider/chrome/browser/chrome_browser_provider.mm
+++ b/ios/public/provider/chrome/browser/chrome_browser_provider.mm
@@ -35,11 +35,6 @@
 void ChromeBrowserProvider::RegisterProfilePrefs(
     user_prefs::PrefRegistrySyncable* registry) {}
 
-UpdatableResourceProvider*
-ChromeBrowserProvider::GetUpdatableResourceProvider() {
-  return nullptr;
-}
-
 InfoBarViewPlaceholder ChromeBrowserProvider::CreateInfoBarView(
     CGRect frame,
     InfoBarViewDelegate* delegate) {
diff --git a/ios/public/provider/chrome/browser/test_chrome_browser_provider.h b/ios/public/provider/chrome/browser/test_chrome_browser_provider.h
index cfa4a2d..895ee338 100644
--- a/ios/public/provider/chrome/browser/test_chrome_browser_provider.h
+++ b/ios/public/provider/chrome/browser/test_chrome_browser_provider.h
@@ -25,7 +25,6 @@
   void SetChromeIdentityServiceForTesting(
       std::unique_ptr<ChromeIdentityService> service) override;
   ChromeIdentityService* GetChromeIdentityService() override;
-  UpdatableResourceProvider* GetUpdatableResourceProvider() override;
   UITextField<TextFieldStyling>* CreateStyledTextField(
       CGRect frame) const override NS_RETURNS_RETAINED;
   NSArray* GetAvailableVoiceSearchLanguages() const override;
@@ -37,7 +36,6 @@
   std::unique_ptr<AppDistributionProvider> app_distribution_provider_;
   std::unique_ptr<ChromeIdentityService> chrome_identity_service_;
   std::unique_ptr<OmahaServiceProvider> omaha_service_provider_;
-  std::unique_ptr<UpdatableResourceProvider> updatable_resource_provider_;
   std::unique_ptr<VoiceSearchProvider> voice_search_provider_;
 
   DISALLOW_COPY_AND_ASSIGN(TestChromeBrowserProvider);
diff --git a/ios/public/provider/chrome/browser/test_chrome_browser_provider.mm b/ios/public/provider/chrome/browser/test_chrome_browser_provider.mm
index faa284e..ca81298 100644
--- a/ios/public/provider/chrome/browser/test_chrome_browser_provider.mm
+++ b/ios/public/provider/chrome/browser/test_chrome_browser_provider.mm
@@ -12,7 +12,6 @@
 #include "ios/public/provider/chrome/browser/distribution/test_app_distribution_provider.h"
 #include "ios/public/provider/chrome/browser/omaha/omaha_service_provider.h"
 #include "ios/public/provider/chrome/browser/signin/fake_chrome_identity_service.h"
-#import "ios/public/provider/chrome/browser/test_updatable_resource_provider.h"
 #import "ios/public/provider/chrome/browser/voice/test_voice_search_provider.h"
 #import "ios/public/provider/chrome/browser/voice/voice_search_language.h"
 
@@ -33,8 +32,6 @@
     : app_distribution_provider_(
           base::MakeUnique<TestAppDistributionProvider>()),
       omaha_service_provider_(base::MakeUnique<OmahaServiceProvider>()),
-      updatable_resource_provider_(
-          base::MakeUnique<TestUpdatableResourceProvider>()),
       voice_search_provider_(base::MakeUnique<TestVoiceSearchProvider>()) {}
 
 TestChromeBrowserProvider::~TestChromeBrowserProvider() {}
@@ -58,11 +55,6 @@
   return chrome_identity_service_.get();
 }
 
-UpdatableResourceProvider*
-TestChromeBrowserProvider::GetUpdatableResourceProvider() {
-  return updatable_resource_provider_.get();
-}
-
 UITextField<TextFieldStyling>* TestChromeBrowserProvider::CreateStyledTextField(
     CGRect frame) const {
   return [[TestStyledTextField alloc] initWithFrame:frame];
diff --git a/ios/public/provider/chrome/browser/test_updatable_resource_provider.h b/ios/public/provider/chrome/browser/test_updatable_resource_provider.h
deleted file mode 100644
index 7df789d..0000000
--- a/ios/public/provider/chrome/browser/test_updatable_resource_provider.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2015 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 IOS_PUBLIC_PROVIDER_CHROME_BROWSER_TEST_UPDATABLE_RESOURCE_PROVIDER_H_
-#define IOS_PUBLIC_PROVIDER_CHROME_BROWSER_TEST_UPDATABLE_RESOURCE_PROVIDER_H_
-
-#import "ios/public/provider/chrome/browser/updatable_resource_provider.h"
-
-namespace ios {
-
-// Dummy UpdatableResourceProvider implementation that simply loads data from
-// the specified plist file.
-class TestUpdatableResourceProvider : public ios::UpdatableResourceProvider {
- private:
-  // UpdatableResourceProvider implementation.
-  NSString* GetUpdateNotificationName() override;
-  id<UpdatableResourceBridge> CreateUpdatableResource(
-      NSString* resource_identifier,
-      id<UpdatableResourceDelegate> delegate) override;
-};
-
-}  // namespace ios
-
-#endif  // IOS_PUBLIC_PROVIDER_CHROME_BROWSER_TEST_UPDATABLE_RESOURCE_PROVIDER_H_
diff --git a/ios/public/provider/chrome/browser/test_updatable_resource_provider.mm b/ios/public/provider/chrome/browser/test_updatable_resource_provider.mm
deleted file mode 100644
index 0c6b7f4..0000000
--- a/ios/public/provider/chrome/browser/test_updatable_resource_provider.mm
+++ /dev/null
@@ -1,108 +0,0 @@
-// Copyright 2015 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.
-
-#import "ios/public/provider/chrome/browser/test_updatable_resource_provider.h"
-
-#include "base/logging.h"
-#include "base/mac/scoped_nsobject.h"
-
-#pragma mark - TestUpdatabeResourceDescriptor
-
-// Dummy UpdatableResourceDescriptorBridge implementation.
-@interface TestUpdatabeResourceDescriptor
-    : NSObject<UpdatableResourceDescriptorBridge>
-@property(nonatomic, readonly) NSURL* updateURL;
-@property(nonatomic, copy) NSString* applicationIdentifier;
-@property(nonatomic, copy) NSString* applicationVersion;
-@property(nonatomic, copy) NSString* bundleResourcePath;
-@property(nonatomic, copy) NSString* updateResourcePath;
-@end
-
-@implementation TestUpdatabeResourceDescriptor
-@synthesize updateURL;
-@synthesize applicationIdentifier;
-@synthesize applicationVersion;
-@synthesize bundleResourcePath;
-@synthesize updateResourcePath;
-
-- (void)updateCheckDidFinishWithSuccess:(BOOL)wasSuccessful {
-}
-
-- (NSString*)resourcePath {
-  return nil;
-}
-@end
-
-#pragma mark - TestUpdatableResource
-
-// Dummy UpdatableResourceDescriptorBridge implementation that simply loads data
-// from the specified plist file.
-@interface TestUpdatableResource : NSObject<UpdatableResourceBridge>
-@property(nonatomic, readonly) id<UpdatableResourceDescriptorBridge> descriptor;
-- (instancetype)initWithDelegate:(id<UpdatableResourceDelegate>)delegate
-                           plist:(NSString*)resource_identifier
-    NS_DESIGNATED_INITIALIZER;
-- (instancetype)init NS_UNAVAILABLE;
-@end
-
-@implementation TestUpdatableResource {
-  base::scoped_nsprotocol<id<UpdatableResourceDelegate>> _delegate;
-  base::scoped_nsprotocol<id<UpdatableResourceDescriptorBridge>> _descriptor;
-}
-
-- (instancetype)initWithDelegate:(id<UpdatableResourceDelegate>)delegate
-                           plist:(NSString*)resourceIdentifier {
-  if (self = [super init]) {
-    _delegate.reset([delegate retain]);
-    _descriptor.reset([[TestUpdatabeResourceDescriptor alloc] init]);
-    DCHECK([resourceIdentifier hasSuffix:@".plist"])
-        << "TestUpdatableResource supports only the plist format";
-    [_descriptor setBundleResourcePath:resourceIdentifier];
-  }
-  return self;
-}
-
-- (instancetype)init {
-  NOTREACHED();
-  return nil;
-}
-
-- (id<UpdatableResourceDescriptorBridge>)descriptor {
-  return _descriptor.get();
-}
-
-- (id<UpdatableResourceDelegate>)delegate {
-  return _delegate;
-}
-
-- (NSDictionary*)resourceData {
-  return [NSDictionary
-      dictionaryWithContentsOfFile:[_descriptor bundleResourcePath]];
-}
-- (void)loadDefaults {
-  [_delegate loadDefaults:self];
-}
-
-@end
-
-#pragma mark - TestUpdatableResourceProvider
-
-namespace ios {
-
-NSString* TestUpdatableResourceProvider::GetUpdateNotificationName() {
-  return @"ResourceUpdatedTest";
-}
-
-id<UpdatableResourceBridge>
-TestUpdatableResourceProvider::CreateUpdatableResource(
-    NSString* resource_identifier,
-    id<UpdatableResourceDelegate> delegate) {
-  NSString* path =
-      [NSString stringWithFormat:@"%@/gm-config/ANY/%@",
-                                 [[NSBundle mainBundle] resourcePath],
-                                 resource_identifier];
-  return [[TestUpdatableResource alloc] initWithDelegate:delegate plist:path];
-}
-
-}  // namespace ios
diff --git a/ios/public/provider/chrome/browser/updatable_resource_provider.h b/ios/public/provider/chrome/browser/updatable_resource_provider.h
deleted file mode 100644
index 906ea8c3d..0000000
--- a/ios/public/provider/chrome/browser/updatable_resource_provider.h
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright 2015 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 IOS_PUBLIC_PROVIDER_CHROME_BROWSER_UPDATABLE_RESOURCE_PROVIDER_H_
-#define IOS_PUBLIC_PROVIDER_CHROME_BROWSER_UPDATABLE_RESOURCE_PROVIDER_H_
-
-#import <Foundation/Foundation.h>
-
-#include "base/macros.h"
-
-@protocol UpdatableResourceDelegate;
-@protocol UpdatableResourceDescriptorBridge;
-
-#pragma mark - UpdatableResourceBridge
-
-// UpdatableResourceBridge represents an updatable resource.
-@protocol UpdatableResourceBridge<NSObject>
-
-// Returns the UpdatableResourceDescriptorBridge associated to this resource.
-@property(nonatomic, readonly) id<UpdatableResourceDescriptorBridge> descriptor;
-
-// Returns the UpdatableResourceDelegate associated to this resource.
-- (id<UpdatableResourceDelegate>)delegate;
-
-// The data provided by this resource.
-- (NSDictionary*)resourceData;
-
-// Initializes this updatable resource with default values.
-- (void)loadDefaults;
-@end
-
-#pragma mark - UpdatableResourceDescriptorBridge
-
-// This class encapsulates identification and versioning information
-// for an updatable resource.
-@protocol UpdatableResourceDescriptorBridge<NSObject>
-
-@property(nonatomic, copy) NSString* applicationIdentifier;
-@property(nonatomic, copy) NSString* applicationVersion;
-
-// URL where an update to this resource may be downloaded.
-@property(nonatomic, readonly) NSURL* updateURL;
-
-// Search path for the default file.
-@property(nonatomic, copy) NSString* bundleResourcePath;
-// Search path for the downloaded file.
-@property(nonatomic, copy) NSString* updateResourcePath;
-
-// This method must be called after an update check has been made. Either
-// successfully or not.
-- (void)updateCheckDidFinishWithSuccess:(BOOL)wasSuccessful;
-
-// Returns the full path of the latest and greatest version of the resource
-// currently residing on the device. If there is no version of the resource
-// currently stored on the device, returns |nil|.
-- (NSString*)resourcePath;
-
-@end
-
-#pragma mark - UpdatableResourceDelegate
-
-// Delegate for UpdatableResourceBridge.
-@protocol UpdatableResourceDelegate<NSObject>
-
-// This method can be reimplemented to override the behavior of the
-// UpdatableResourceBridge method.
-- (void)loadDefaults:(id<UpdatableResourceBridge>)resource;
-
-// Merges the latest values defined in the file into the values currently stored
-// by the updatable resource.
-- (void)mergeUpdate:(id<UpdatableResourceBridge>)resource;
-
-// Parses file at |path| and returns an NSDictionary with the values stored
-// therein.
-- (NSDictionary*)parseFileAt:(NSString*)path;
-@end
-
-#pragma mark - UpdatableResourceProvider
-
-namespace ios {
-
-// Provider for UpdatableResourceBridge.
-class UpdatableResourceProvider {
- public:
-  UpdatableResourceProvider();
-  virtual ~UpdatableResourceProvider();
-
-  // Returns the name of the notification that is sent through the notification
-  // center when a resource is updated.
-  virtual NSString* GetUpdateNotificationName();
-
-  // Creates a new UpdatableResourceBrige.
-  // The user is responsible for releasing it.
-  // The UpdatableResourceBridge takes ownership of the delegate.
-  // |delegate| may be nil.
-  virtual id<UpdatableResourceBridge> CreateUpdatableResource(
-      NSString* resource_identifier,
-      id<UpdatableResourceDelegate> delegate) NS_RETURNS_RETAINED;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(UpdatableResourceProvider);
-};
-
-}  // namespace ios
-
-#endif  // IOS_PUBLIC_PROVIDER_CHROME_BROWSER_UPDATABLE_RESOURCE_PROVIDER_H_
diff --git a/ios/public/provider/chrome/browser/updatable_resource_provider.mm b/ios/public/provider/chrome/browser/updatable_resource_provider.mm
deleted file mode 100644
index 7172695..0000000
--- a/ios/public/provider/chrome/browser/updatable_resource_provider.mm
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2015 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.
-
-#import "ios/public/provider/chrome/browser/updatable_resource_provider.h"
-
-namespace ios {
-
-UpdatableResourceProvider::UpdatableResourceProvider() {
-}
-
-UpdatableResourceProvider::~UpdatableResourceProvider() {
-}
-
-NSString* UpdatableResourceProvider::GetUpdateNotificationName() {
-  return nil;
-}
-
-id<UpdatableResourceBridge> UpdatableResourceProvider::CreateUpdatableResource(
-    NSString* resource_identifier,
-    id<UpdatableResourceDelegate> delegate) {
-  return nil;
-}
-
-}  // namespace ios
diff --git a/media/cdm/aes_decryptor.cc b/media/cdm/aes_decryptor.cc
index b040351..d6a720d 100644
--- a/media/cdm/aes_decryptor.cc
+++ b/media/cdm/aes_decryptor.cc
@@ -463,8 +463,7 @@
   CHECK(encrypted->decrypt_config());
 
   scoped_refptr<DecoderBuffer> decrypted;
-  // An empty iv string signals that the frame is unencrypted.
-  if (encrypted->decrypt_config()->iv().empty()) {
+  if (!encrypted->decrypt_config()->is_encrypted()) {
     decrypted = DecoderBuffer::CopyFrom(encrypted->data(),
                                         encrypted->data_size());
   } else {
diff --git a/media/filters/decrypting_demuxer_stream.cc b/media/filters/decrypting_demuxer_stream.cc
index fc92fa5..00e70e2 100644
--- a/media/filters/decrypting_demuxer_stream.cc
+++ b/media/filters/decrypting_demuxer_stream.cc
@@ -235,8 +235,7 @@
   }
 
   DCHECK(buffer->decrypt_config());
-  // An empty iv string signals that the frame is unencrypted.
-  if (buffer->decrypt_config()->iv().empty()) {
+  if (!buffer->decrypt_config()->is_encrypted()) {
     DVLOG(2) << "DoDecryptBuffer() - clear buffer.";
     scoped_refptr<DecoderBuffer> decrypted = DecoderBuffer::CopyFrom(
         buffer->data(), buffer->data_size());
diff --git a/mojo/edk/embedder/named_platform_channel_pair.h b/mojo/edk/embedder/named_platform_channel_pair.h
index ebc8eaa..71688861 100644
--- a/mojo/edk/embedder/named_platform_channel_pair.h
+++ b/mojo/edk/embedder/named_platform_channel_pair.h
@@ -58,6 +58,8 @@
   void PrepareToPassClientHandleToChildProcess(
       base::CommandLine* command_line) const;
 
+  const NamedPlatformHandle& handle() const { return pipe_handle_; }
+
  private:
   NamedPlatformHandle pipe_handle_;
   ScopedPlatformHandle server_handle_;
diff --git a/mojo/edk/system/broker_host.cc b/mojo/edk/system/broker_host.cc
index 5b2071ad..a5a5f9cf 100644
--- a/mojo/edk/system/broker_host.cc
+++ b/mojo/edk/system/broker_host.cc
@@ -10,6 +10,8 @@
 #include "base/memory/ref_counted.h"
 #include "base/message_loop/message_loop.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "mojo/edk/embedder/named_platform_channel_pair.h"
+#include "mojo/edk/embedder/named_platform_handle.h"
 #include "mojo/edk/embedder/platform_handle_vector.h"
 #include "mojo/edk/embedder/platform_shared_buffer.h"
 #include "mojo/edk/system/broker_messages.h"
@@ -48,7 +50,7 @@
     channel_->ShutDown();
 }
 
-void BrokerHost::PrepareHandlesForClient(PlatformHandleVector* handles) {
+bool BrokerHost::PrepareHandlesForClient(PlatformHandleVector* handles) {
 #if defined(OS_WIN)
   if (!Channel::Message::RewriteHandles(
       base::GetCurrentProcessHandle(), client_process_, handles)) {
@@ -56,24 +58,54 @@
     // prevent any message from being sent. The client should handle unexpected
     // invalid handles appropriately.
     DLOG(ERROR) << "Failed to rewrite one or more handles to broker client.";
+    return false;
   }
 #endif
+  return true;
 }
 
-void BrokerHost::SendChannel(ScopedPlatformHandle handle) {
+bool BrokerHost::SendChannel(ScopedPlatformHandle handle) {
   CHECK(handle.is_valid());
   CHECK(channel_);
 
+#if defined(OS_WIN)
+  InitData* data;
+  Channel::MessagePtr message =
+      CreateBrokerMessage(BrokerMessageType::INIT, 1, 0, &data);
+  data->pipe_name_length = 0;
+#else
   Channel::MessagePtr message =
       CreateBrokerMessage(BrokerMessageType::INIT, 1, nullptr);
+#endif
   ScopedPlatformHandleVectorPtr handles;
   handles.reset(new PlatformHandleVector(1));
   handles->at(0) = handle.release();
-  PrepareHandlesForClient(handles.get());
-  message->SetHandles(std::move(handles));
+
+  // This may legitimately fail on Windows if the client process is in another
+  // session, e.g., is an elevated process.
+  if (!PrepareHandlesForClient(handles.get()))
+    return false;
+
+   message->SetHandles(std::move(handles));
+  channel_->Write(std::move(message));
+  return true;
+}
+
+#if defined(OS_WIN)
+
+void BrokerHost::SendNamedChannel(const base::StringPiece16& pipe_name) {
+  InitData* data;
+  base::char16* name_data;
+  Channel::MessagePtr message = CreateBrokerMessage(
+      BrokerMessageType::INIT, 0, sizeof(*name_data) * pipe_name.length(),
+      &data, reinterpret_cast<void**>(&name_data));
+  data->pipe_name_length = static_cast<uint32_t>(pipe_name.length());
+  std::copy(pipe_name.begin(), pipe_name.end(), name_data);
   channel_->Write(std::move(message));
 }
 
+#endif  // defined(OS_WIN)
+
 void BrokerHost::OnBufferRequest(uint32_t num_bytes) {
   scoped_refptr<PlatformSharedBuffer> buffer;
   scoped_refptr<PlatformSharedBuffer> read_only_buffer;
diff --git a/mojo/edk/system/broker_host.h b/mojo/edk/system/broker_host.h
index 7f5212ad..a7995d2b 100644
--- a/mojo/edk/system/broker_host.h
+++ b/mojo/edk/system/broker_host.h
@@ -10,6 +10,7 @@
 #include "base/macros.h"
 #include "base/message_loop/message_loop.h"
 #include "base/process/process_handle.h"
+#include "base/strings/string_piece.h"
 #include "mojo/edk/embedder/platform_handle_vector.h"
 #include "mojo/edk/embedder/scoped_platform_handle.h"
 #include "mojo/edk/system/channel.h"
@@ -25,12 +26,17 @@
   BrokerHost(base::ProcessHandle client_process, ScopedPlatformHandle handle);
 
   // Send |handle| to the child, to be used to establish a NodeChannel to us.
-  void SendChannel(ScopedPlatformHandle handle);
+  bool SendChannel(ScopedPlatformHandle handle);
+
+#if defined(OS_WIN)
+  // Sends a named channel to the child. Like above, but for named pipes.
+  void SendNamedChannel(const base::StringPiece16& pipe_name);
+#endif
 
  private:
   ~BrokerHost() override;
 
-  void PrepareHandlesForClient(PlatformHandleVector* handles);
+  bool PrepareHandlesForClient(PlatformHandleVector* handles);
 
   // Channel::Delegate:
   void OnChannelMessage(const void* payload,
diff --git a/mojo/edk/system/broker_messages.h b/mojo/edk/system/broker_messages.h
index a67be15d8..19b757e 100644
--- a/mojo/edk/system/broker_messages.h
+++ b/mojo/edk/system/broker_messages.h
@@ -30,19 +30,34 @@
   uint32_t size;
 };
 
+#if defined(OS_WIN)
+struct InitData {
+  // NOTE: InitData in the payload is followed by string16 data with exactly
+  // |pipe_name_length| wide characters (i.e., |pipe_name_length|*2 bytes.)
+  // This applies to Windows only.
+  uint32_t pipe_name_length;
+};
+#endif
+
 #pragma pack(pop)
 
 template <typename T>
-inline Channel::MessagePtr CreateBrokerMessage(BrokerMessageType type,
-                                               size_t num_handles,
-                                               T** out_message_data) {
-  const size_t message_size = sizeof(BrokerMessageHeader) + sizeof(T);
+inline Channel::MessagePtr CreateBrokerMessage(
+    BrokerMessageType type,
+    size_t num_handles,
+    size_t extra_data_size,
+    T** out_message_data,
+    void** out_extra_data = nullptr) {
+  const size_t message_size = sizeof(BrokerMessageHeader) +
+      sizeof(**out_message_data) + extra_data_size;
   Channel::MessagePtr message(new Channel::Message(message_size, num_handles));
   BrokerMessageHeader* header =
       reinterpret_cast<BrokerMessageHeader*>(message->mutable_payload());
   header->type = type;
   header->padding = 0;
   *out_message_data = reinterpret_cast<T*>(header + 1);
+  if (out_extra_data)
+    *out_extra_data = *out_message_data + 1;
   return message;
 }
 
diff --git a/mojo/edk/system/broker_posix.cc b/mojo/edk/system/broker_posix.cc
index 5400ed2..8742f70 100644
--- a/mojo/edk/system/broker_posix.cc
+++ b/mojo/edk/system/broker_posix.cc
@@ -94,7 +94,7 @@
 
   BufferRequestData* buffer_request;
   Channel::MessagePtr out_message = CreateBrokerMessage(
-      BrokerMessageType::BUFFER_REQUEST, 0, &buffer_request);
+      BrokerMessageType::BUFFER_REQUEST, 0, 0, &buffer_request);
   buffer_request->size = num_bytes;
   ssize_t write_result = PlatformChannelWrite(
       sync_channel_.get(), out_message->data(), out_message->data_num_bytes());
diff --git a/mojo/edk/system/broker_win.cc b/mojo/edk/system/broker_win.cc
index 4b99e39..cfee14e2 100644
--- a/mojo/edk/system/broker_win.cc
+++ b/mojo/edk/system/broker_win.cc
@@ -8,6 +8,9 @@
 #include <utility>
 
 #include "base/numerics/safe_conversions.h"
+#include "base/strings/string_piece.h"
+#include "mojo/edk/embedder/named_platform_handle.h"
+#include "mojo/edk/embedder/named_platform_handle_utils.h"
 #include "mojo/edk/embedder/platform_handle.h"
 #include "mojo/edk/embedder/platform_handle_vector.h"
 #include "mojo/edk/embedder/platform_shared_buffer.h"
@@ -23,56 +26,77 @@
 // 256 bytes should be enough for anyone!
 const size_t kMaxBrokerMessageSize = 256;
 
-bool WaitForBrokerMessage(PlatformHandle platform_handle,
-                          BrokerMessageType expected_type,
-                          size_t expected_num_handles,
-                          ScopedPlatformHandle* out_handles) {
+bool TakeHandlesFromBrokerMessage(Channel::Message* message,
+                                  size_t num_handles,
+                                  ScopedPlatformHandle* out_handles) {
+  if (message->num_handles() != num_handles) {
+    DLOG(ERROR) << "Received unexpected number of handles in broker message";
+    return false;
+  }
+
+  ScopedPlatformHandleVectorPtr handles = message->TakeHandles();
+  DCHECK(handles);
+  DCHECK_EQ(handles->size(), num_handles);
+  DCHECK(out_handles);
+
+  for (size_t i = 0; i < num_handles; ++i)
+    out_handles[i] = ScopedPlatformHandle((*handles)[i]);
+  handles->clear();
+  return true;
+}
+
+Channel::MessagePtr WaitForBrokerMessage(PlatformHandle platform_handle,
+                                         BrokerMessageType expected_type) {
   char buffer[kMaxBrokerMessageSize];
   DWORD bytes_read = 0;
   BOOL result = ::ReadFile(platform_handle.handle, buffer,
                            kMaxBrokerMessageSize, &bytes_read, nullptr);
   if (!result) {
     PLOG(ERROR) << "Error reading broker pipe";
-    return false;
+    return nullptr;
   }
 
   Channel::MessagePtr message =
       Channel::Message::Deserialize(buffer, static_cast<size_t>(bytes_read));
   if (!message || message->payload_size() < sizeof(BrokerMessageHeader)) {
     LOG(ERROR) << "Invalid broker message";
-    return false;
-  }
-
-  if (message->num_handles() != expected_num_handles) {
-    LOG(ERROR) << "Received unexpected number of handles in broker message";
-    return false;
+    return nullptr;
   }
 
   const BrokerMessageHeader* header =
       reinterpret_cast<const BrokerMessageHeader*>(message->payload());
   if (header->type != expected_type) {
-    LOG(ERROR) << "Unknown broker message type";
-    return false;
+    LOG(ERROR) << "Unexpected broker message type";
+    return nullptr;
   }
 
-  ScopedPlatformHandleVectorPtr handles = message->TakeHandles();
-  DCHECK(handles);
-  DCHECK_EQ(handles->size(), expected_num_handles);
-  DCHECK(out_handles);
-
-  for (size_t i = 0; i < expected_num_handles; ++i)
-    out_handles[i] = ScopedPlatformHandle(handles->at(i));
-  handles->clear();
-  return true;
+  return message;
 }
 
 }  // namespace
 
 Broker::Broker(ScopedPlatformHandle handle) : sync_channel_(std::move(handle)) {
   CHECK(sync_channel_.is_valid());
-  bool result = WaitForBrokerMessage(
-      sync_channel_.get(), BrokerMessageType::INIT, 1, &parent_channel_);
-  DCHECK(result);
+  Channel::MessagePtr message =
+      WaitForBrokerMessage(sync_channel_.get(), BrokerMessageType::INIT);
+  CHECK(message);
+
+  if (!TakeHandlesFromBrokerMessage(message.get(), 1, &parent_channel_)) {
+    // If the message has no handles, we expect it to carry pipe name instead.
+    const BrokerMessageHeader* header =
+        static_cast<const BrokerMessageHeader*>(message->payload());
+    CHECK_GE(message->payload_size(),
+             sizeof(BrokerMessageHeader) + sizeof(InitData));
+    const InitData* data = reinterpret_cast<const InitData*>(header + 1);
+    CHECK_EQ(message->payload_size(),
+             sizeof(BrokerMessageHeader) + sizeof(InitData) +
+             data->pipe_name_length * sizeof(base::char16));
+    const base::char16* name_data =
+        reinterpret_cast<const base::char16*>(data + 1);
+    CHECK(data->pipe_name_length);
+    parent_channel_ = CreateClientHandle(NamedPlatformHandle(
+        base::StringPiece16(name_data, data->pipe_name_length)));
+  }
 }
 
 Broker::~Broker() {}
@@ -85,7 +109,7 @@
   base::AutoLock lock(lock_);
   BufferRequestData* buffer_request;
   Channel::MessagePtr out_message = CreateBrokerMessage(
-      BrokerMessageType::BUFFER_REQUEST, 0, &buffer_request);
+      BrokerMessageType::BUFFER_REQUEST, 0, 0, &buffer_request);
   buffer_request->size = base::checked_cast<uint32_t>(num_bytes);
   DWORD bytes_written = 0;
   BOOL result = ::WriteFile(sync_channel_.get().handle, out_message->data(),
@@ -98,9 +122,10 @@
   }
 
   ScopedPlatformHandle handles[2];
-  if (WaitForBrokerMessage(sync_channel_.get(),
-                           BrokerMessageType::BUFFER_RESPONSE, 2,
-                           &handles[0])) {
+  Channel::MessagePtr response = WaitForBrokerMessage(
+      sync_channel_.get(), BrokerMessageType::BUFFER_RESPONSE);
+  if (response &&
+      TakeHandlesFromBrokerMessage(response.get(), 2, &handles[0])) {
     return PlatformSharedBuffer::CreateFromPlatformHandlePair(
         num_bytes, std::move(handles[0]), std::move(handles[1]));
   }
diff --git a/mojo/edk/system/node_controller.cc b/mojo/edk/system/node_controller.cc
index 8dd1824..1a48154 100644
--- a/mojo/edk/system/node_controller.cc
+++ b/mojo/edk/system/node_controller.cc
@@ -18,6 +18,8 @@
 #include "base/time/time.h"
 #include "base/timer/elapsed_timer.h"
 #include "mojo/edk/embedder/embedder_internal.h"
+#include "mojo/edk/embedder/named_platform_channel_pair.h"
+#include "mojo/edk/embedder/named_platform_handle.h"
 #include "mojo/edk/embedder/platform_channel_pair.h"
 #include "mojo/edk/system/broker.h"
 #include "mojo/edk/system/broker_host.h"
@@ -400,18 +402,32 @@
 
 #if !defined(OS_MACOSX) && !defined(OS_NACL)
   PlatformChannelPair node_channel;
+  ScopedPlatformHandle server_handle = node_channel.PassServerHandle();
   // BrokerHost owns itself.
   BrokerHost* broker_host =
       new BrokerHost(process_handle, std::move(platform_handle));
-  broker_host->SendChannel(node_channel.PassClientHandle());
-  scoped_refptr<NodeChannel> channel = NodeChannel::Create(
-      this, node_channel.PassServerHandle(), io_task_runner_,
-      process_error_callback);
+  bool channel_ok = broker_host->SendChannel(node_channel.PassClientHandle());
+
+#if defined(OS_WIN)
+  if (!channel_ok) {
+    // On Windows the above operation may fail if the channel is crossing a
+    // session boundary. In that case we fall back to a named pipe.
+    NamedPlatformChannelPair named_channel;
+    server_handle = named_channel.PassServerHandle();
+    broker_host->SendNamedChannel(named_channel.handle().name);
+  }
 #else
+  CHECK(channel_ok);
+#endif  // defined(OS_WIN)
+
+  scoped_refptr<NodeChannel> channel = NodeChannel::Create(
+      this, std::move(server_handle), io_task_runner_, process_error_callback);
+
+#else  // !defined(OS_MACOSX) && !defined(OS_NACL)
   scoped_refptr<NodeChannel> channel =
       NodeChannel::Create(this, std::move(platform_handle), io_task_runner_,
                           process_error_callback);
-#endif
+#endif  // !defined(OS_MACOSX) && !defined(OS_NACL)
 
   // We set up the child channel with a temporary name so it can be identified
   // as a pending child if it writes any messages to the channel. We may start
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 42d46f69..ffe0f94e 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -1593,3 +1593,5 @@
 crbug.com/657646 [ Win ] fast/text/international/thai-line-breaks.html [ Failure Pass ]
 
 crbug.com/664005 [ Linux Win ] fast/hidpi/scrollbar-appearance-increase-device-scale-factor.html [ Timeout ]
+
+crbug.com/664059 [ Precise Mac10.11 Debug ] imported/wpt/html/browsers/history/the-location-interface/reload_post_1.html [ Failure ]
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/mediastream/MediaStreamTrack-getSources-expected.txt b/third_party/WebKit/LayoutTests/fast/mediastream/MediaStreamTrack-getSources-expected.txt
new file mode 100644
index 0000000..13ecd81
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/mediastream/MediaStreamTrack-getSources-expected.txt
@@ -0,0 +1,19 @@
+CONSOLE WARNING: line 1: MediaStreamTrack.getSources is deprecated and will be removed in M56, around January 2017. See https://www.chromestatus.com/features/4765305641369600 for more details.
+Tests MediaStreamTrack::getSources.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS MediaStreamTrack.getSources(gotSources1); did not throw exception.
+PASS gotSources1 was called.
+PASS sources.length > 0 is true
+PASS gotStream was called.
+PASS MediaStreamTrack.getSources(gotSources2); did not throw exception.
+PASS gotSources2 was called.
+PASS sources.length > 0 is true
+PASS sources[0].id === previousId is true
+PASS sources[0].label.length > 0 is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/third_party/WebKit/LayoutTests/fast/mediastream/MediaStreamTrack-getSources.html b/third_party/WebKit/LayoutTests/fast/mediastream/MediaStreamTrack-getSources.html
new file mode 100644
index 0000000..4dcbece
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/mediastream/MediaStreamTrack-getSources.html
@@ -0,0 +1,60 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test.js"></script>
+</head>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+<script>
+description("Tests MediaStreamTrack::getSources.");
+
+var sources = null;
+var previousId;
+
+function error() {
+    testFailed('Stream generation failed.');
+    finishJSTest();
+}
+
+function getUserMedia(constraints, callback) {
+    try {
+        navigator.webkitGetUserMedia(constraints, callback, error);
+    } catch (e) {
+        testFailed('webkitGetUserMedia threw exception :' + e);
+        finishJSTest();
+    }
+}
+
+function gotSources2(s) {
+    testPassed('gotSources2 was called.');
+    sources = s;
+    shouldBeTrue('sources.length > 0');
+    shouldBeTrue('sources[0].id === previousId');
+    shouldBeTrue('sources[0].label.length > 0');
+
+    finishJSTest();
+}
+
+function gotStream(s) {
+    testPassed('gotStream was called.');
+
+    shouldNotThrow('MediaStreamTrack.getSources(gotSources2);');
+}
+
+function gotSources1(s) {
+    testPassed('gotSources1 was called.');
+    sources = s;
+    shouldBeTrue('sources.length > 0');
+    previousId = sources[0].id;
+
+    getUserMedia({audio:true, video:true}, gotStream);
+}
+
+shouldNotThrow('MediaStreamTrack.getSources(gotSources1);');
+
+window.jsTestIsAsync = true;
+window.successfullyParsed = true;
+</script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/speechsynthesis/speech-synthesis-utterance-voice.html b/third_party/WebKit/LayoutTests/fast/speechsynthesis/speech-synthesis-utterance-voice.html
new file mode 100644
index 0000000..f0fa6ea
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/speechsynthesis/speech-synthesis-utterance-voice.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<title>SpeechSynthesisUtterance voice attribute</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+test(() => {
+  const u = new SpeechSynthesisUtterance();
+  assert_equals(u.voice, null);
+}, 'initial state');
+
+test(() => {
+  const u = new SpeechSynthesisUtterance();
+  u.voice = null;
+  assert_equals(u.voice, null);
+  u.voice = undefined;
+  assert_equals(u.voice, null);
+}, 'setting to null/undefined');
+
+test(() => {
+  const u = new SpeechSynthesisUtterance();
+  for (const value of [{}, "", window]) {
+    assert_throws(new TypeError, () => { u.voice = value; } );
+    assert_equals(u.voice, null);
+  }
+}, 'setting to non-SpeechSynthesisVoice values');
+
+test(() => {
+  internals.enableMockSpeechSynthesizer(document);
+
+  const u = new SpeechSynthesisUtterance();
+  const voice = speechSynthesis.getVoices()[0];
+  // TODO(foolip): This should test instanceof SpeechSynthesisVoice when that
+  // interface is exposed.
+  assert_equals(typeof voice, "object");
+  u.voice = voice;
+  assert_equals(u.voice, voice);
+}, 'setting to SpeechSynthesisVoice');
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/child-src/worker-blocked-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/child-src/worker-blocked-expected.txt
index dfd5cb3..f15c63e 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/child-src/worker-blocked-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/child-src/worker-blocked-expected.txt
@@ -1,4 +1,4 @@
-CONSOLE ERROR: line 1: Refused to create a child context containing 'http://127.0.0.1:8000/security/contentSecurityPolicy/resources/alert-fail.js' because it violates the following Content Security Policy directive: "child-src 'none'".
+CONSOLE ERROR: line 1: Refused to create a worker from 'http://127.0.0.1:8000/security/contentSecurityPolicy/resources/alert-fail.js' because it violates the following Content Security Policy directive: "child-src 'none'".
 
 Workers should be governed by 'child-src'.
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/child-src/worker-shared-blocked-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/child-src/worker-shared-blocked-expected.txt
index 02e2545..df93a58 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/child-src/worker-shared-blocked-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/child-src/worker-shared-blocked-expected.txt
@@ -1,4 +1,4 @@
-CONSOLE ERROR: line 1: Refused to create a child context containing 'http://127.0.0.1:8000/security/contentSecurityPolicy/resources/alert-fail.js' because it violates the following Content Security Policy directive: "child-src 'none'".
+CONSOLE ERROR: line 1: Refused to create a worker from 'http://127.0.0.1:8000/security/contentSecurityPolicy/resources/alert-fail.js' because it violates the following Content Security Policy directive: "child-src 'none'".
 
 SharedWorkers should be governed by 'child-src'.
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/resources/ping.js b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/resources/ping.js
new file mode 100644
index 0000000..750ae45f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/resources/ping.js
@@ -0,0 +1,12 @@
+if (typeof ServiceWorkerGlobalScope === "function") {
+  self.onmessage = function (e) { e.source.postMessage("ping"); };
+} else if (typeof SharedWorkerGlobalScope === "function") {
+  onconnect = function (e) {
+    var port = e.ports[0];
+
+    port.onmessage = function () { port.postMessage("ping"); }
+    port.postMessage("ping");
+  };
+} else if (typeof DedicatedWorkerGlobalScope === "function") {
+  self.postMessage("ping");
+}
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/resources/testharness-helper.js b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/resources/testharness-helper.js
new file mode 100644
index 0000000..a1eaa891e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/resources/testharness-helper.js
@@ -0,0 +1,131 @@
+function assert_no_csp_event_for_url(test, url) {
+  document.addEventListener("securitypolicyviolation", test.step_func(e => {
+    if (e.blockedURI !== url)
+      return;
+    assert_unreached("SecurityPolicyViolation event fired for " + url);
+  }));
+}
+
+function assert_no_event(test, obj, name) {
+  obj.addEventListener(name, test.unreached_func("The '" + name + "' event should not have fired."));
+}
+
+function waitUntilCSPEventForURL(test, url) {
+  return new Promise((resolve, reject) => {
+    document.addEventListener("securitypolicyviolation", test.step_func(e => {
+      if (e.blockedURI == url)
+        resolve(e);
+    }));
+  });
+}
+
+function waitUntilEvent(obj, name) {
+  return new Promise((resolve, reject) => {
+    obj.addEventListener(name, resolve);
+  });
+}
+
+// Given the URL of a worker that pings its opener upon load, this
+// function builds a test that asserts that the ping is received,
+// and that no CSP event fires.
+function assert_worker_is_loaded(url, description) {
+  async_test(t => {
+    assert_no_csp_event_for_url(t, url);
+    var w = new Worker(url);
+    assert_no_event(t, w, "error");
+    waitUntilEvent(w, "message")
+      .then(t.step_func_done(e => {
+        assert_equals(e.data, "ping");
+      }));
+  }, description);
+}
+
+function assert_shared_worker_is_loaded(url, description) {
+  async_test(t => {
+    assert_no_csp_event_for_url(t, url);
+    var w = new SharedWorker(url);
+    assert_no_event(t, w, "error");
+    waitUntilEvent(w.port, "message")
+      .then(t.step_func_done(e => {
+        assert_equals(e.data, "ping");
+      }));
+    w.port.start();
+  }, description);
+}
+
+function assert_service_worker_is_loaded(url, description) {
+  promise_test(t => {
+    assert_no_csp_event_for_url(t, url);
+    return Promise.all([
+      waitUntilEvent(navigator.serviceWorker, "message")
+        .then(e => {
+          assert_equals(e.data, "ping");
+        }),
+      navigator.serviceWorker.register(url, { scope: url })
+        .then(r => {
+          var sw = r.active || r.installing || r.waiting;
+          t.add_cleanup(_ => r.unregister());
+          sw.postMessage("pong?");
+        })
+    ]);
+  }, description);
+}
+
+// Given the URL of a worker that pings its opener upon load, this
+// function builds a test that asserts that the constructor throws
+// a SecurityError, and that a CSP event fires.
+function assert_worker_is_blocked(url, description) {
+  async_test(t => {
+    // If |url| is a blob, it will be stripped down to "blob" for reporting.
+    var reportedURL = new URL(url).protocol == "blob:" ? "blob" : url;
+    waitUntilCSPEventForURL(t, reportedURL)
+      .then(t.step_func_done(e => {
+        assert_equals(e.blockedURI, reportedURL);
+        assert_equals(e.violatedDirective, "worker-src");
+        assert_equals(e.effectiveDirective, "worker-src");
+      }));
+
+    // TODO(mkwst): We shouldn't be throwing here. We should be firing an
+    // `error` event on the Worker. https://crbug.com/663298
+    assert_throws("SecurityError", function () {
+      var w = new Worker(url);
+    });
+  }, description);
+}
+
+function assert_shared_worker_is_blocked(url, description) {
+  async_test(t => {
+    // If |url| is a blob, it will be stripped down to "blob" for reporting.
+    var reportedURL = new URL(url).protocol == "blob:" ? "blob" : url;
+    waitUntilCSPEventForURL(t, reportedURL)
+      .then(t.step_func_done(e => {
+        assert_equals(e.blockedURI, reportedURL);
+        assert_equals(e.violatedDirective, "worker-src");
+        assert_equals(e.effectiveDirective, "worker-src");
+      }));
+
+    // TODO(mkwst): We shouldn't be throwing here. We should be firing an
+    // `error` event on the SharedWorker. https://crbug.com/663298
+    assert_throws("SecurityError", function () {
+      var w = new SharedWorker(url);
+    });
+  }, description);
+}
+
+function assert_service_worker_is_blocked(url, description) {
+  promise_test(t => {
+    assert_no_event(t, navigator.serviceWorker, "message");
+    // If |url| is a blob, it will be stripped down to "blob" for reporting.
+    var reportedURL = new URL(url).protocol == "blob:" ? "blob" : url;
+    return Promise.all([
+      waitUntilCSPEventForURL(t, reportedURL)
+        .then(t.step_func_done(e => {
+          assert_equals(e.blockedURI, reportedURL);
+          assert_equals(e.violatedDirective, "worker-src");
+          assert_equals(e.effectiveDirective, "worker-src");
+        })),
+      promise_rejects(t, "SecurityError", navigator.serviceWorker.register(url, { scope: url }))
+    ]);
+  }, description);
+}
+
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/service-worker-blocked-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/service-worker-blocked-expected.txt
index 212517a..935ff994 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/service-worker-blocked-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/service-worker-blocked-expected.txt
@@ -1,4 +1,4 @@
-CONSOLE ERROR: line 9: Refused to create a child context containing 'http://127.0.0.1:8000/security/contentSecurityPolicy/resources/service-worker.js' because it violates the following Content Security Policy directive: "child-src 'none'".
+CONSOLE ERROR: line 9: Refused to create a worker from 'http://127.0.0.1:8000/security/contentSecurityPolicy/resources/service-worker.js' because it violates the following Content Security Policy directive: "child-src 'none'".
 
 This is a testharness.js-based test.
 PASS Test that a service worker cannot be registered if the CSP does not allow it 
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/worker-src/dedicated-child.html b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/worker-src/dedicated-child.html
new file mode 100644
index 0000000..da1fbc1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/worker-src/dedicated-child.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testharness-helper.js"></script>
+<meta http-equiv="Content-Security-Policy" content="child-src http://127.0.0.1:8000 blob:">
+<script>
+  var url = new URL("/security/contentSecurityPolicy/resources/ping.js", document.baseURI).toString();
+  assert_worker_is_loaded(url, "Same-origin dedicated worker allowed by host-source expression.");
+
+  var b = new Blob(["postMessage('ping');"], {type: "text/javascript"});
+  var url = URL.createObjectURL(b);
+  assert_worker_is_loaded(url, "blob: dedicated worker allowed by 'blob:'.");
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/worker-src/dedicated-fallback.html b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/worker-src/dedicated-fallback.html
new file mode 100644
index 0000000..6de1985
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/worker-src/dedicated-fallback.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testharness-helper.js"></script>
+<meta http-equiv="Content-Security-Policy" content="worker-src http://127.0.0.1:8000 blob:; child-src 'none'">
+<script>
+  var url = new URL("/security/contentSecurityPolicy/resources/ping.js", document.baseURI).toString();
+  assert_worker_is_loaded(url, "Same-origin dedicated worker allowed by host-source expression.");
+
+  var b = new Blob(["postMessage('ping');"], {type: "text/javascript"});
+  var url = URL.createObjectURL(b);
+  assert_worker_is_loaded(url, "blob: dedicated worker allowed by 'blob:'.");
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/worker-src/dedicated-list.html b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/worker-src/dedicated-list.html
new file mode 100644
index 0000000..8b19f53
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/worker-src/dedicated-list.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testharness-helper.js"></script>
+<meta http-equiv="Content-Security-Policy" content="worker-src http://127.0.0.1:8000 blob:">
+<script>
+  var url = new URL("/security/contentSecurityPolicy/resources/ping.js", document.baseURI).toString();
+  assert_worker_is_loaded(url, "Same-origin dedicated worker allowed by host-source expression.");
+
+  var b = new Blob(["postMessage('ping');"], {type: "text/javascript"});
+  var url = URL.createObjectURL(b);
+  assert_worker_is_loaded(url, "blob: dedicated worker allowed by 'blob:'.");
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/worker-src/dedicated-none.html b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/worker-src/dedicated-none.html
new file mode 100644
index 0000000..3377775
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/worker-src/dedicated-none.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testharness-helper.js"></script>
+<meta http-equiv="Content-Security-Policy" content="worker-src 'none'">
+<script>
+  var url = new URL("/security/contentSecurityPolicy/resources/ping.js", document.baseURI).toString();
+  assert_worker_is_blocked(url, "Same-origin dedicated worker blocked by host-source expression.");
+
+  var b = new Blob(["postMessage('ping');"], {type: "text/javascript"});
+  var url = URL.createObjectURL(b);
+  assert_worker_is_blocked(url, "blob: dedicated worker blocked by 'blob:'.");
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/worker-src/dedicated-self.html b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/worker-src/dedicated-self.html
new file mode 100644
index 0000000..b504a6de
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/worker-src/dedicated-self.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testharness-helper.js"></script>
+<meta http-equiv="Content-Security-Policy" content="worker-src 'self'">
+<script>
+  var url = new URL("/security/contentSecurityPolicy/resources/ping.js", document.baseURI).toString();
+  assert_worker_is_loaded(url, "Same-origin dedicated worker allowed by 'self'.");
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/worker-src/service-child.html b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/worker-src/service-child.html
new file mode 100644
index 0000000..9b897fc
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/worker-src/service-child.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testharness-helper.js"></script>
+<meta http-equiv="Content-Security-Policy" content="child-src http://127.0.0.1:8000">
+<script>
+  var url = new URL("/security/contentSecurityPolicy/resources/ping.js", document.baseURI).toString();
+  assert_service_worker_is_loaded(url, "Same-origin service worker allowed by host-source expression.");
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/worker-src/service-fallback.html b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/worker-src/service-fallback.html
new file mode 100644
index 0000000..3ce8e542
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/worker-src/service-fallback.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testharness-helper.js"></script>
+<meta http-equiv="Content-Security-Policy" content="worker-src http://127.0.0.1:8000; child-src 'none'">
+<script>
+  var url = new URL("/security/contentSecurityPolicy/resources/ping.js", document.baseURI).toString();
+  assert_service_worker_is_loaded(url, "Same-origin service worker allowed by host-source expression.");
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/worker-src/service-list.html b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/worker-src/service-list.html
new file mode 100644
index 0000000..6f71549
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/worker-src/service-list.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testharness-helper.js"></script>
+<meta http-equiv="Content-Security-Policy" content="worker-src http://127.0.0.1:8000">
+<script>
+  var url = new URL("/security/contentSecurityPolicy/resources/ping.js", document.baseURI).toString();
+  assert_service_worker_is_loaded(url, "Same-origin service worker allowed by host-source expression.");
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/worker-src/service-none.html b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/worker-src/service-none.html
new file mode 100644
index 0000000..2b239e2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/worker-src/service-none.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testharness-helper.js"></script>
+<meta http-equiv="Content-Security-Policy" content="worker-src 'none'">
+<script>
+  var url = new URL("/security/contentSecurityPolicy/resources/ping.js", document.baseURI).toString();
+  assert_service_worker_is_blocked(url, "Same-origin service worker blocked by 'none'.");
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/worker-src/service-self.html b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/worker-src/service-self.html
new file mode 100644
index 0000000..5fdccae
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/worker-src/service-self.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testharness-helper.js"></script>
+<meta http-equiv="Content-Security-Policy" content="worker-src 'self'">
+<script>
+  var url = new URL("/security/contentSecurityPolicy/resources/ping.js", document.baseURI).toString();
+  assert_service_worker_is_loaded(url, "Same-origin service worker allowed by 'self'.");
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/worker-src/shared-child.html b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/worker-src/shared-child.html
new file mode 100644
index 0000000..8376498
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/worker-src/shared-child.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testharness-helper.js"></script>
+<meta http-equiv="Content-Security-Policy" content="child-src http://127.0.0.1:8000 blob:">
+<script>
+  var url = new URL("/security/contentSecurityPolicy/resources/ping.js", document.baseURI).toString();
+  assert_shared_worker_is_loaded(url, "Same-origin dedicated worker allowed by 'self'.");
+
+  var b = new Blob(["onconnect = e => { e.ports[0].postMessage('ping'); }"], {type: "text/javascript"});
+  var url = URL.createObjectURL(b);
+  assert_shared_worker_is_loaded(url, "blob: dedicated worker allowed by 'blob:'.");
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/worker-src/shared-fallback.html b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/worker-src/shared-fallback.html
new file mode 100644
index 0000000..2a8754b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/worker-src/shared-fallback.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testharness-helper.js"></script>
+<meta http-equiv="Content-Security-Policy" content="worker-src http://127.0.0.1:8000 blob:; child-src 'none'">
+<script>
+  var url = new URL("/security/contentSecurityPolicy/resources/ping.js", document.baseURI).toString();
+  assert_shared_worker_is_loaded(url, "Same-origin dedicated worker allowed by 'self'.");
+
+  var b = new Blob(["onconnect = e => { e.ports[0].postMessage('ping'); }"], {type: "text/javascript"});
+  var url = URL.createObjectURL(b);
+  assert_shared_worker_is_loaded(url, "blob: dedicated worker allowed by 'blob:'.");
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/worker-src/shared-list.html b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/worker-src/shared-list.html
new file mode 100644
index 0000000..43d7481
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/worker-src/shared-list.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testharness-helper.js"></script>
+<meta http-equiv="Content-Security-Policy" content="worker-src http://127.0.0.1:8000 blob:">
+<script>
+  var url = new URL("/security/contentSecurityPolicy/resources/ping.js", document.baseURI).toString();
+  assert_shared_worker_is_loaded(url, "Same-origin dedicated worker allowed by 'self'.");
+
+  var b = new Blob(["onconnect = e => { e.ports[0].postMessage('ping'); }"], {type: "text/javascript"});
+  var url = URL.createObjectURL(b);
+  assert_shared_worker_is_loaded(url, "blob: dedicated worker allowed by 'blob:'.");
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/worker-src/shared-none.html b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/worker-src/shared-none.html
new file mode 100644
index 0000000..9a24cf7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/worker-src/shared-none.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testharness-helper.js"></script>
+<meta http-equiv="Content-Security-Policy" content="worker-src 'none'">
+<script>
+  var url = new URL("/security/contentSecurityPolicy/resources/ping.js", document.baseURI).toString();
+  assert_shared_worker_is_blocked(url, "Same-origin shared worker blocked by 'none'.");
+
+  var b = new Blob(["onconnect = e => { e.ports[0].postMessage('ping'); }"], {type: "text/javascript"});
+  var url = URL.createObjectURL(b);
+  assert_shared_worker_is_blocked(url, "blob: shared worker blocked by 'none'.");
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/worker-src/shared-self.html b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/worker-src/shared-self.html
new file mode 100644
index 0000000..42d3da25
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/worker-src/shared-self.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testharness-helper.js"></script>
+<meta http-equiv="Content-Security-Policy" content="worker-src 'self'">
+<script>
+  var url = new URL("/security/contentSecurityPolicy/resources/ping.js", document.baseURI).toString();
+  assert_shared_worker_is_loaded(url, "Same-origin dedicated worker allowed by 'self'.");
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/stable/webexposed/global-interface-listing-expected.txt
index e80d54c..2fc7626b 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/stable/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -3343,6 +3343,7 @@
     getter stream
     method constructor
 interface MediaStreamTrack : EventTarget
+    static method getSources
     attribute @@toStringTag
     getter enabled
     getter id
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/stable/webexposed/global-interface-listing-expected.txt
index e80d54c..2fc7626b 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/stable/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -3343,6 +3343,7 @@
     getter stream
     method constructor
 interface MediaStreamTrack : EventTarget
+    static method getSources
     attribute @@toStringTag
     getter enabled
     getter id
diff --git a/third_party/WebKit/LayoutTests/shadow-dom/event-composed-ua.html b/third_party/WebKit/LayoutTests/shadow-dom/event-composed-ua.html
index 6e9f3ba..bedaed43 100644
--- a/third_party/WebKit/LayoutTests/shadow-dom/event-composed-ua.html
+++ b/third_party/WebKit/LayoutTests/shadow-dom/event-composed-ua.html
@@ -69,6 +69,12 @@
     eventSender.mouseUp();
 }
 
+function click(x, y) {
+    eventSender.mouseMoveTo(x, y);
+    eventSender.mouseDown();
+    eventSender.mouseUp();
+}
+
 async_test((test) => {
   input.addEventListener('dblclick', test.step_func_done((e) => {
     assert_true(e.composed);
@@ -76,4 +82,12 @@
 }, 'A dblclick event should be a composed event');
 
 doubleClick(input.offsetLeft, input.offsetTop);
+
+async_test((test) => {
+  input.addEventListener('DOMActivate', test.step_func_done((e) => {
+    assert_true(e.composed);
+  }));
+}, 'A DOMActivate event should be a composed event');
+
+click(input.offsetLeft, input.offsetTop);
 </script>
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
index 8ed92d6..10938d8 100644
--- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -3400,6 +3400,7 @@
     getter stream
     method constructor
 interface MediaStreamTrack : EventTarget
+    static method getSources
     attribute @@toStringTag
     getter enabled
     getter id
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 35a2e8a..6fb3063 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -3987,6 +3987,7 @@
     getter stream
     method constructor
 interface MediaStreamTrack : EventTarget
+    static method getSources
     attribute @@toStringTag
     getter enabled
     getter id
diff --git a/third_party/WebKit/Source/core/css/ActiveStyleSheets.cpp b/third_party/WebKit/Source/core/css/ActiveStyleSheets.cpp
index 271359d..5c53263 100644
--- a/third_party/WebKit/Source/core/css/ActiveStyleSheets.cpp
+++ b/third_party/WebKit/Source/core/css/ActiveStyleSheets.cpp
@@ -103,94 +103,4 @@
   return changedRuleSets.size() ? ActiveSheetsChanged : NoActiveSheetsChanged;
 }
 
-namespace {
-
-enum RuleSetFlags {
-  FontFaceRules = 1 << 0,
-  KeyframesRules = 1 << 1,
-  FullRecalcRules = 1 << 2
-};
-
-unsigned getRuleSetFlags(const HeapVector<Member<RuleSet>> ruleSets) {
-  unsigned flags = 0;
-  for (auto& ruleSet : ruleSets) {
-    ruleSet->compactRulesIfNeeded();
-    if (!ruleSet->keyframesRules().isEmpty())
-      flags |= KeyframesRules;
-    if (!ruleSet->fontFaceRules().isEmpty())
-      flags |= FontFaceRules;
-    if (ruleSet->needsFullRecalcForRuleSetInvalidation())
-      flags |= FullRecalcRules;
-  }
-  return flags;
-}
-
-}  // namespace
-
-void applyRuleSetChanges(StyleEngine& engine,
-                         TreeScope& treeScope,
-                         const ActiveStyleSheetVector& oldStyleSheets,
-                         const ActiveStyleSheetVector& newStyleSheets) {
-  HeapVector<Member<RuleSet>> changedRuleSets;
-
-  ActiveSheetsChange change =
-      compareActiveStyleSheets(oldStyleSheets, newStyleSheets, changedRuleSets);
-  if (change == NoActiveSheetsChanged)
-    return;
-
-  // TODO(rune@opera.com): engine.setNeedsGlobalRuleSetUpdate();
-
-  unsigned changedRuleFlags = getRuleSetFlags(changedRuleSets);
-  bool fontsChanged = treeScope.rootNode().isDocumentNode() &&
-                      (changedRuleFlags & FontFaceRules);
-  unsigned appendStartIndex = 0;
-
-  // We don't need to clear the font cache if new sheets are appended.
-  if (fontsChanged && change == ActiveSheetsChanged)
-    engine.clearFontCache();
-
-  // - If all sheets were removed, we remove the ScopedStyleResolver.
-  // - If new sheets were appended to existing ones, start appending after the
-  //   common prefix.
-  // - For other diffs, reset author style and re-add all sheets for the
-  //   TreeScope.
-  if (treeScope.scopedStyleResolver()) {
-    if (newStyleSheets.isEmpty())
-      engine.resetAuthorStyle(treeScope);
-    else if (change == ActiveSheetsAppended)
-      appendStartIndex = oldStyleSheets.size();
-    else
-      treeScope.scopedStyleResolver()->resetAuthorStyle();
-  }
-
-  if (!newStyleSheets.isEmpty()) {
-    treeScope.ensureScopedStyleResolver().appendActiveStyleSheets(
-        appendStartIndex, newStyleSheets);
-  }
-
-  if (treeScope.document().hasPendingForcedStyleRecalc())
-    return;
-
-  if (!treeScope.document().body() ||
-      treeScope.document().hasNodesWithPlaceholderStyle()) {
-    treeScope.document().setNeedsStyleRecalc(
-        SubtreeStyleChange, StyleChangeReasonForTracing::create(
-                                StyleChangeReason::CleanupPlaceholderStyles));
-    return;
-  }
-
-  if (changedRuleFlags & KeyframesRules)
-    ScopedStyleResolver::keyframesRulesAdded(treeScope);
-
-  if (fontsChanged || (changedRuleFlags & FullRecalcRules)) {
-    ScopedStyleResolver::invalidationRootForTreeScope(treeScope)
-        .setNeedsStyleRecalc(SubtreeStyleChange,
-                             StyleChangeReasonForTracing::create(
-                                 StyleChangeReason::ActiveStylesheetsUpdate));
-    return;
-  }
-
-  engine.scheduleInvalidationsForRuleSets(treeScope, changedRuleSets);
-}
-
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/ActiveStyleSheets.h b/third_party/WebKit/Source/core/css/ActiveStyleSheets.h
index c17057a..3078615 100644
--- a/third_party/WebKit/Source/core/css/ActiveStyleSheets.h
+++ b/third_party/WebKit/Source/core/css/ActiveStyleSheets.h
@@ -29,12 +29,6 @@
                          const ActiveStyleSheetVector& newStyleSheets,
                          HeapVector<Member<RuleSet>>& changedRuleSets);
 
-CORE_EXPORT void applyRuleSetChanges(
-    StyleEngine&,
-    TreeScope&,
-    const ActiveStyleSheetVector& oldStyleSheets,
-    const ActiveStyleSheetVector& newStyleSheets);
-
 }  // namespace blink
 
 #endif  // ActiveStyleSheets_h
diff --git a/third_party/WebKit/Source/core/css/ActiveStyleSheetsTest.cpp b/third_party/WebKit/Source/core/css/ActiveStyleSheetsTest.cpp
index 9bd36650..7e298285 100644
--- a/third_party/WebKit/Source/core/css/ActiveStyleSheetsTest.cpp
+++ b/third_party/WebKit/Source/core/css/ActiveStyleSheetsTest.cpp
@@ -310,8 +310,8 @@
   ActiveStyleSheetVector newStyleSheets;
   newStyleSheets.append(std::make_pair(sheet, &sheet->contents()->ruleSet()));
 
-  applyRuleSetChanges(styleEngine(), document(), ActiveStyleSheetVector(),
-                      newStyleSheets);
+  styleEngine().applyRuleSetChanges(document(), ActiveStyleSheetVector(),
+                                    newStyleSheets);
 
   EXPECT_EQ(SubtreeStyleChange, document().getStyleChangeType());
 }
@@ -329,8 +329,8 @@
   ActiveStyleSheetVector newStyleSheets;
   newStyleSheets.append(std::make_pair(sheet, &sheet->contents()->ruleSet()));
 
-  applyRuleSetChanges(styleEngine(), shadowRoot, ActiveStyleSheetVector(),
-                      newStyleSheets);
+  styleEngine().applyRuleSetChanges(shadowRoot, ActiveStyleSheetVector(),
+                                    newStyleSheets);
 
   EXPECT_FALSE(document().needsStyleRecalc());
   EXPECT_EQ(SubtreeStyleChange, host->getStyleChangeType());
@@ -344,8 +344,8 @@
   ActiveStyleSheetVector newStyleSheets;
   newStyleSheets.append(std::make_pair(sheet, &sheet->contents()->ruleSet()));
 
-  applyRuleSetChanges(styleEngine(), document(), ActiveStyleSheetVector(),
-                      newStyleSheets);
+  styleEngine().applyRuleSetChanges(document(), ActiveStyleSheetVector(),
+                                    newStyleSheets);
 
   EXPECT_EQ(SubtreeStyleChange, document().getStyleChangeType());
 }
@@ -363,8 +363,8 @@
   ActiveStyleSheetVector newStyleSheets;
   newStyleSheets.append(std::make_pair(sheet, &sheet->contents()->ruleSet()));
 
-  applyRuleSetChanges(styleEngine(), shadowRoot, ActiveStyleSheetVector(),
-                      newStyleSheets);
+  styleEngine().applyRuleSetChanges(shadowRoot, ActiveStyleSheetVector(),
+                                    newStyleSheets);
 
   EXPECT_FALSE(document().needsStyleRecalc());
   EXPECT_EQ(SubtreeStyleChange, host->getStyleChangeType());
@@ -379,8 +379,8 @@
   ActiveStyleSheetVector newStyleSheets;
   newStyleSheets.append(std::make_pair(sheet, &sheet->contents()->ruleSet()));
 
-  applyRuleSetChanges(styleEngine(), document(), ActiveStyleSheetVector(),
-                      newStyleSheets);
+  styleEngine().applyRuleSetChanges(document(), ActiveStyleSheetVector(),
+                                    newStyleSheets);
 
   EXPECT_EQ(SubtreeStyleChange, document().getStyleChangeType());
 }
@@ -399,8 +399,8 @@
   ActiveStyleSheetVector newStyleSheets;
   newStyleSheets.append(std::make_pair(sheet, &sheet->contents()->ruleSet()));
 
-  applyRuleSetChanges(styleEngine(), shadowRoot, ActiveStyleSheetVector(),
-                      newStyleSheets);
+  styleEngine().applyRuleSetChanges(shadowRoot, ActiveStyleSheetVector(),
+                                    newStyleSheets);
 
   EXPECT_FALSE(document().needsLayoutTreeUpdate());
 }
@@ -426,8 +426,8 @@
   ActiveStyleSheetVector oldStyleSheets;
   oldStyleSheets.append(
       std::make_pair(cssSheet, &cssSheet->contents()->ruleSet()));
-  applyRuleSetChanges(styleEngine(), shadowRoot, oldStyleSheets,
-                      ActiveStyleSheetVector());
+  styleEngine().applyRuleSetChanges(shadowRoot, oldStyleSheets,
+                                    ActiveStyleSheetVector());
 
   EXPECT_TRUE(styleEngine().treeBoundaryCrossingScopes().isEmpty());
 }
diff --git a/third_party/WebKit/Source/core/dom/Node.cpp b/third_party/WebKit/Source/core/dom/Node.cpp
index ff6ea84..8e03757a 100644
--- a/third_party/WebKit/Source/core/dom/Node.cpp
+++ b/third_party/WebKit/Source/core/dom/Node.cpp
@@ -2095,14 +2095,15 @@
 }
 
 DispatchEventResult Node::dispatchDOMActivateEvent(int detail,
-                                                   Event* underlyingEvent) {
+                                                   Event& underlyingEvent) {
 #if DCHECK_IS_ON()
   DCHECK(!EventDispatchForbiddenScope::isEventDispatchForbidden());
 #endif
   UIEvent* event = UIEvent::create();
   event->initUIEvent(EventTypeNames::DOMActivate, true, true,
                      document().domWindow(), detail);
-  event->setUnderlyingEvent(underlyingEvent);
+  event->setUnderlyingEvent(&underlyingEvent);
+  event->setComposed(underlyingEvent.composed());
   dispatchScopedEvent(event);
 
   // TODO(dtapuska): Dispatching scoped events shouldn't check the return
@@ -2146,7 +2147,7 @@
   } else if (eventType == EventTypeNames::click) {
     int detail =
         event->isUIEvent() ? static_cast<UIEvent*>(event)->detail() : 0;
-    if (dispatchDOMActivateEvent(detail, event) !=
+    if (dispatchDOMActivateEvent(detail, *event) !=
         DispatchEventResult::NotCanceled)
       event->setDefaultHandled();
   } else if (eventType == EventTypeNames::contextmenu) {
diff --git a/third_party/WebKit/Source/core/dom/Node.h b/third_party/WebKit/Source/core/dom/Node.h
index 0dca87a2..dc3f9c7 100644
--- a/third_party/WebKit/Source/core/dom/Node.h
+++ b/third_party/WebKit/Source/core/dom/Node.h
@@ -728,7 +728,7 @@
 
   void dispatchSubtreeModifiedEvent();
   DispatchEventResult dispatchDOMActivateEvent(int detail,
-                                               Event* underlyingEvent);
+                                               Event& underlyingEvent);
 
   DispatchEventResult dispatchMouseEvent(const PlatformMouseEvent&,
                                          const AtomicString& eventType,
diff --git a/third_party/WebKit/Source/core/dom/StyleEngine.cpp b/third_party/WebKit/Source/core/dom/StyleEngine.cpp
index 683057e..4c36822 100644
--- a/third_party/WebKit/Source/core/dom/StyleEngine.cpp
+++ b/third_party/WebKit/Source/core/dom/StyleEngine.cpp
@@ -1029,6 +1029,96 @@
              m_globalRuleSet.uncommonAttributeRuleSet(), *m_resolver)
       .findSharedStyle();
 }
+namespace {
+
+enum RuleSetFlags {
+  FontFaceRules = 1 << 0,
+  KeyframesRules = 1 << 1,
+  FullRecalcRules = 1 << 2
+};
+
+unsigned getRuleSetFlags(const HeapVector<Member<RuleSet>> ruleSets) {
+  unsigned flags = 0;
+  for (auto& ruleSet : ruleSets) {
+    ruleSet->compactRulesIfNeeded();
+    if (!ruleSet->keyframesRules().isEmpty())
+      flags |= KeyframesRules;
+    if (!ruleSet->fontFaceRules().isEmpty())
+      flags |= FontFaceRules;
+    if (ruleSet->needsFullRecalcForRuleSetInvalidation())
+      flags |= FullRecalcRules;
+  }
+  return flags;
+}
+
+}  // namespace
+
+void StyleEngine::applyRuleSetChanges(
+    TreeScope& treeScope,
+    const ActiveStyleSheetVector& oldStyleSheets,
+    const ActiveStyleSheetVector& newStyleSheets) {
+  HeapVector<Member<RuleSet>> changedRuleSets;
+
+  ActiveSheetsChange change =
+      compareActiveStyleSheets(oldStyleSheets, newStyleSheets, changedRuleSets);
+  if (change == NoActiveSheetsChanged)
+    return;
+
+  // With rules added or removed, we need to re-aggregate rule meta data.
+  m_globalRuleSet.markDirty();
+
+  unsigned changedRuleFlags = getRuleSetFlags(changedRuleSets);
+  bool fontsChanged = treeScope.rootNode().isDocumentNode() &&
+                      (changedRuleFlags & FontFaceRules);
+  unsigned appendStartIndex = 0;
+
+  // We don't need to clear the font cache if new sheets are appended.
+  if (fontsChanged && change == ActiveSheetsChanged)
+    clearFontCache();
+
+  // - If all sheets were removed, we remove the ScopedStyleResolver.
+  // - If new sheets were appended to existing ones, start appending after the
+  //   common prefix.
+  // - For other diffs, reset author style and re-add all sheets for the
+  //   TreeScope.
+  if (treeScope.scopedStyleResolver()) {
+    if (newStyleSheets.isEmpty())
+      resetAuthorStyle(treeScope);
+    else if (change == ActiveSheetsAppended)
+      appendStartIndex = oldStyleSheets.size();
+    else
+      treeScope.scopedStyleResolver()->resetAuthorStyle();
+  }
+
+  if (!newStyleSheets.isEmpty()) {
+    treeScope.ensureScopedStyleResolver().appendActiveStyleSheets(
+        appendStartIndex, newStyleSheets);
+  }
+
+  if (treeScope.document().hasPendingForcedStyleRecalc())
+    return;
+
+  if (!treeScope.document().body() ||
+      treeScope.document().hasNodesWithPlaceholderStyle()) {
+    treeScope.document().setNeedsStyleRecalc(
+        SubtreeStyleChange, StyleChangeReasonForTracing::create(
+                                StyleChangeReason::CleanupPlaceholderStyles));
+    return;
+  }
+
+  if (changedRuleFlags & KeyframesRules)
+    ScopedStyleResolver::keyframesRulesAdded(treeScope);
+
+  if (fontsChanged || (changedRuleFlags & FullRecalcRules)) {
+    ScopedStyleResolver::invalidationRootForTreeScope(treeScope)
+        .setNeedsStyleRecalc(SubtreeStyleChange,
+                             StyleChangeReasonForTracing::create(
+                                 StyleChangeReason::ActiveStylesheetsUpdate));
+    return;
+  }
+
+  scheduleInvalidationsForRuleSets(treeScope, changedRuleSets);
+}
 
 DEFINE_TRACE(StyleEngine) {
   visitor->trace(m_document);
diff --git a/third_party/WebKit/Source/core/dom/StyleEngine.h b/third_party/WebKit/Source/core/dom/StyleEngine.h
index d0912d9..c3f47d5 100644
--- a/third_party/WebKit/Source/core/dom/StyleEngine.h
+++ b/third_party/WebKit/Source/core/dom/StyleEngine.h
@@ -33,6 +33,7 @@
 #include "bindings/core/v8/ScriptWrappable.h"
 #include "bindings/core/v8/TraceWrapperMember.h"
 #include "core/CoreExport.h"
+#include "core/css/ActiveStyleSheets.h"
 #include "core/css/CSSFontSelectorClient.h"
 #include "core/css/CSSGlobalRuleSet.h"
 #include "core/css/invalidation/StyleInvalidator.h"
@@ -247,6 +248,10 @@
 
   PassRefPtr<ComputedStyle> findSharedStyle(const ElementResolveContext&);
 
+  void applyRuleSetChanges(TreeScope&,
+                           const ActiveStyleSheetVector& oldStyleSheets,
+                           const ActiveStyleSheetVector& newStyleSheets);
+
   DECLARE_VIRTUAL_TRACE();
   DECLARE_TRACE_WRAPPERS();
 
diff --git a/third_party/WebKit/Source/core/events/Event.h b/third_party/WebKit/Source/core/events/Event.h
index 479e499..d1c8fdda 100644
--- a/third_party/WebKit/Source/core/events/Event.h
+++ b/third_party/WebKit/Source/core/events/Event.h
@@ -233,6 +233,11 @@
   bool isTrusted() const { return m_isTrusted; }
   void setTrusted(bool value) { m_isTrusted = value; }
 
+  void setComposed(bool composed) {
+    DCHECK(!isBeingDispatched());
+    m_composed = composed;
+  }
+
   void setHandlingPassive(PassiveMode);
 
   bool preventDefaultCalledDuringPassive() const {
@@ -265,10 +270,6 @@
   virtual void receivedTarget();
 
   void setCanBubble(bool bubble) { m_canBubble = bubble; }
-  void setComposed(bool composed) {
-    DCHECK(!isBeingDispatched());
-    m_composed = composed;
-  }
 
   PassiveMode handlingPassive() const { return m_handlingPassive; }
 
diff --git a/third_party/WebKit/Source/core/fetch/ResourceFetcher.cpp b/third_party/WebKit/Source/core/fetch/ResourceFetcher.cpp
index 4d8e5611..30b47b8c9 100644
--- a/third_party/WebKit/Source/core/fetch/ResourceFetcher.cpp
+++ b/third_party/WebKit/Source/core/fetch/ResourceFetcher.cpp
@@ -1204,6 +1204,12 @@
       // safe because of http://crbug.com/604084 the
       // wasFallbackRequiredByServiceWorker flag is never set when foreign fetch
       // handled a request.
+      if (!context().shouldLoadNewResource(resource->getType())) {
+        // Cancel the request if we should not trigger a reload now.
+        resource->loader()->didFail(
+            ResourceError::cancelledError(response.url()));
+        return;
+      }
       request.setSkipServiceWorker(
           WebURLRequest::SkipServiceWorker::Controlling);
       resource->loader()->restart(request, context().loadingTaskRunner(),
diff --git a/third_party/WebKit/Source/core/fetch/ResourceLoader.cpp b/third_party/WebKit/Source/core/fetch/ResourceLoader.cpp
index 019e575..bc6dddb0 100644
--- a/third_party/WebKit/Source/core/fetch/ResourceLoader.cpp
+++ b/third_party/WebKit/Source/core/fetch/ResourceLoader.cpp
@@ -246,7 +246,8 @@
 }
 
 void ResourceLoader::didFail(const ResourceError& error) {
-  if (m_isCacheAwareLoadingActivated && error.isCacheMiss()) {
+  if (m_isCacheAwareLoadingActivated && error.isCacheMiss() &&
+      m_fetcher->context().shouldLoadNewResource(m_resource->getType())) {
     m_resource->willReloadAfterDiskCacheMiss();
     m_isCacheAwareLoadingActivated = false;
     restart(m_resource->resourceRequest(),
diff --git a/third_party/WebKit/Source/core/frame/Deprecation.cpp b/third_party/WebKit/Source/core/frame/Deprecation.cpp
index 7cf0c123..0e1022e9 100644
--- a/third_party/WebKit/Source/core/frame/Deprecation.cpp
+++ b/third_party/WebKit/Source/core/frame/Deprecation.cpp
@@ -402,6 +402,10 @@
       return replacedBy("'Performance.onwebkitresourcetimingbufferfull'",
                         "'Performance.onresourcetimingbufferfull'");
 
+    case UseCounter::MediaStreamTrackGetSources:
+      return willBeRemoved("MediaStreamTrack.getSources", M56,
+                           "4765305641369600");
+
     case UseCounter::WebAnimationHyphenatedProperty:
       return "Hyphenated property names in Web Animations keyframes are "
              "invalid and therefore ignored. Please use camelCase instead.";
diff --git a/third_party/WebKit/Source/core/frame/UseCounter.h b/third_party/WebKit/Source/core/frame/UseCounter.h
index 66ba14d..8f30b76 100644
--- a/third_party/WebKit/Source/core/frame/UseCounter.h
+++ b/third_party/WebKit/Source/core/frame/UseCounter.h
@@ -362,6 +362,7 @@
     UseAsm = 473,
     DOMWindowOpen = 475,
     DOMWindowOpenFeatures = 476,
+    MediaStreamTrackGetSources = 478,
     AspectRatioFlexItem = 479,
     DetailsElement = 480,
     DialogElement = 481,
diff --git a/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.cpp b/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.cpp
index 9d232e9..4bdfefc 100644
--- a/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.cpp
+++ b/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.cpp
@@ -430,11 +430,17 @@
   if (checkSource(directive, url, redirectStatus) && !checkDynamic(directive))
     return true;
 
+  // We should never have a violation against `child-src` or `default-src`
+  // directly; the effective directive should always be one of the explicit
+  // fetch directives.
+  DCHECK_NE(ContentSecurityPolicy::ChildSrc, effectiveDirective);
+  DCHECK_NE(ContentSecurityPolicy::DefaultSrc, effectiveDirective);
+
   String prefix;
   if (ContentSecurityPolicy::BaseURI == effectiveDirective)
     prefix = "Refused to set the document's base URI to '";
-  else if (ContentSecurityPolicy::ChildSrc == effectiveDirective)
-    prefix = "Refused to create a child context containing '";
+  else if (ContentSecurityPolicy::WorkerSrc == effectiveDirective)
+    prefix = "Refused to create a worker from '";
   else if (ContentSecurityPolicy::ConnectSrc == effectiveDirective)
     prefix = "Refused to connect to '";
   else if (ContentSecurityPolicy::FontSrc == effectiveDirective)
@@ -626,15 +632,14 @@
                            redirectStatus);
 }
 
-bool CSPDirectiveList::allowChildFrameFromSource(
+bool CSPDirectiveList::allowFrameFromSource(
     const KURL& url,
     ResourceRequest::RedirectStatus redirectStatus,
     ContentSecurityPolicy::ReportingStatus reportingStatus) const {
   if (url.protocolIsAbout())
     return true;
 
-  // 'frame-src' is the only directive which overrides something other than the
-  // default sources.  It overrides 'child-src', which overrides the default
+  // 'frame-src' overrides 'child-src', which overrides the default
   // sources. So, we do this nested set of calls to 'operativeDirective()' to
   // grab 'frame-src' if it exists, 'child-src' if it doesn't, and 'defaut-src'
   // if neither are available.
@@ -745,16 +750,22 @@
              : checkSource(m_baseURI.get(), url, redirectStatus);
 }
 
-bool CSPDirectiveList::allowChildContextFromSource(
+bool CSPDirectiveList::allowWorkerFromSource(
     const KURL& url,
     ResourceRequest::RedirectStatus redirectStatus,
     ContentSecurityPolicy::ReportingStatus reportingStatus) const {
+  // 'worker-src' overrides 'child-src', which overrides the default
+  // sources. So, we do this nested set of calls to 'operativeDirective()' to
+  // grab 'worker-src' if it exists, 'child-src' if it doesn't, and 'defaut-src'
+  // if neither are available.
+  SourceListDirective* whichDirective = operativeDirective(
+      m_workerSrc.get(), operativeDirective(m_childSrc.get()));
+
   return reportingStatus == ContentSecurityPolicy::SendReport
-             ? checkSourceAndReportViolation(
-                   operativeDirective(m_childSrc.get()), url,
-                   ContentSecurityPolicy::ChildSrc, redirectStatus)
-             : checkSource(operativeDirective(m_childSrc.get()), url,
-                           redirectStatus);
+             ? checkSourceAndReportViolation(whichDirective, url,
+                                             ContentSecurityPolicy::WorkerSrc,
+                                             redirectStatus)
+             : checkSource(whichDirective, url, redirectStatus);
 }
 
 bool CSPDirectiveList::allowAncestors(
@@ -1106,6 +1117,8 @@
     setCSPDirective<SourceListDirective>(name, value, m_baseURI);
   } else if (equalIgnoringCase(name, ContentSecurityPolicy::ChildSrc)) {
     setCSPDirective<SourceListDirective>(name, value, m_childSrc);
+  } else if (equalIgnoringCase(name, ContentSecurityPolicy::WorkerSrc)) {
+    setCSPDirective<SourceListDirective>(name, value, m_workerSrc);
   } else if (equalIgnoringCase(name, ContentSecurityPolicy::FormAction)) {
     setCSPDirective<SourceListDirective>(name, value, m_formAction);
   } else if (equalIgnoringCase(name, ContentSecurityPolicy::PluginTypes)) {
@@ -1146,6 +1159,7 @@
   visitor->trace(m_objectSrc);
   visitor->trace(m_scriptSrc);
   visitor->trace(m_styleSrc);
+  visitor->trace(m_workerSrc);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.h b/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.h
index c4c9215..b305e5b81 100644
--- a/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.h
+++ b/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.h
@@ -83,9 +83,9 @@
   bool allowObjectFromSource(const KURL&,
                              ResourceRequest::RedirectStatus,
                              ContentSecurityPolicy::ReportingStatus) const;
-  bool allowChildFrameFromSource(const KURL&,
-                                 ResourceRequest::RedirectStatus,
-                                 ContentSecurityPolicy::ReportingStatus) const;
+  bool allowFrameFromSource(const KURL&,
+                            ResourceRequest::RedirectStatus,
+                            ContentSecurityPolicy::ReportingStatus) const;
   bool allowImageFromSource(const KURL&,
                             ResourceRequest::RedirectStatus,
                             ContentSecurityPolicy::ReportingStatus) const;
@@ -107,10 +107,9 @@
   bool allowBaseURI(const KURL&,
                     ResourceRequest::RedirectStatus,
                     ContentSecurityPolicy::ReportingStatus) const;
-  bool allowChildContextFromSource(
-      const KURL&,
-      ResourceRequest::RedirectStatus,
-      ContentSecurityPolicy::ReportingStatus) const;
+  bool allowWorkerFromSource(const KURL&,
+                             ResourceRequest::RedirectStatus,
+                             ContentSecurityPolicy::ReportingStatus) const;
   // |allowAncestors| does not need to know whether the resource was a
   // result of a redirect. After a redirect, source paths are usually
   // ignored to stop a page from learning the path to which the
@@ -294,6 +293,7 @@
   Member<SourceListDirective> m_objectSrc;
   Member<SourceListDirective> m_scriptSrc;
   Member<SourceListDirective> m_styleSrc;
+  Member<SourceListDirective> m_workerSrc;
 
   uint8_t m_requireSRIFor;
 
diff --git a/third_party/WebKit/Source/core/frame/csp/CSPDirectiveListTest.cpp b/third_party/WebKit/Source/core/frame/csp/CSPDirectiveListTest.cpp
index de8284a..2fcde83 100644
--- a/third_party/WebKit/Source/core/frame/csp/CSPDirectiveListTest.cpp
+++ b/third_party/WebKit/Source/core/frame/csp/CSPDirectiveListTest.cpp
@@ -391,4 +391,48 @@
   }
 }
 
+TEST_F(CSPDirectiveListTest, workerSrc) {
+  struct TestCase {
+    const char* list;
+    bool allowed;
+  } cases[] = {
+      {"worker-src 'none'", false},
+      {"worker-src http://not.example.test", false},
+      {"worker-src https://example.test", true},
+      {"default-src *; worker-src 'none'", false},
+      {"default-src *; worker-src http://not.example.test", false},
+      {"default-src *; worker-src https://example.test", true},
+      {"child-src *; worker-src 'none'", false},
+      {"child-src *; worker-src http://not.example.test", false},
+      {"child-src *; worker-src https://example.test", true},
+      {"default-src *; child-src *; worker-src 'none'", false},
+      {"default-src *; child-src *; worker-src http://not.example.test", false},
+      {"default-src *; child-src *; worker-src https://example.test", true},
+
+      // Fallback to child-src.
+      {"child-src 'none'", false},
+      {"child-src http://not.example.test", false},
+      {"child-src https://example.test", true},
+      {"default-src *; child-src 'none'", false},
+      {"default-src *; child-src http://not.example.test", false},
+      {"default-src *; child-src https://example.test", true},
+
+      // Fallback to default-src.
+      {"default-src 'none'", false},
+      {"default-src http://not.example.test", false},
+      {"default-src https://example.test", true},
+  };
+
+  for (const auto& test : cases) {
+    SCOPED_TRACE(test.list);
+    KURL resource = KURL(KURL(), "https://example.test/worker.js");
+    Member<CSPDirectiveList> directiveList =
+        createList(test.list, ContentSecurityPolicyHeaderTypeEnforce);
+    EXPECT_EQ(test.allowed,
+              directiveList->allowWorkerFromSource(
+                  resource, ResourceRequest::RedirectStatus::NoRedirect,
+                  ContentSecurityPolicy::SuppressReport));
+  }
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicy.cpp b/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicy.cpp
index 52ef1de..3450842 100644
--- a/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicy.cpp
+++ b/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicy.cpp
@@ -92,9 +92,9 @@
 const char ContentSecurityPolicy::FrameAncestors[] = "frame-ancestors";
 const char ContentSecurityPolicy::PluginTypes[] = "plugin-types";
 
-// CSP Editor's Draft:
-// https://w3c.github.io/webappsec/specs/content-security-policy
+// CSP Level 3 Directives
 const char ContentSecurityPolicy::ManifestSrc[] = "manifest-src";
+const char ContentSecurityPolicy::WorkerSrc[] = "worker-src";
 
 // Mixed Content Directive
 // https://w3c.github.io/webappsec/specs/mixedcontent/#strict-mode
@@ -125,6 +125,7 @@
       equalIgnoringCase(name, FrameAncestors) ||
       equalIgnoringCase(name, PluginTypes) ||
       equalIgnoringCase(name, ManifestSrc) ||
+      equalIgnoringCase(name, WorkerSrc) ||
       equalIgnoringCase(name, BlockAllMixedContent) ||
       equalIgnoringCase(name, UpgradeInsecureRequests) ||
       equalIgnoringCase(name, TreatAsPublicAddress) ||
@@ -844,7 +845,7 @@
       return allowFormAction(url, redirectStatus, reportingStatus);
     case WebURLRequest::RequestContextFrame:
     case WebURLRequest::RequestContextIframe:
-      return allowChildFrameFromSource(url, redirectStatus, reportingStatus);
+      return allowFrameFromSource(url, redirectStatus, reportingStatus);
     case WebURLRequest::RequestContextImport:
     case WebURLRequest::RequestContextScript:
       return allowScriptFromSource(url, nonce, parserDisposition,
@@ -892,11 +893,11 @@
       m_policies, url, redirectStatus, reportingStatus);
 }
 
-bool ContentSecurityPolicy::allowChildFrameFromSource(
+bool ContentSecurityPolicy::allowFrameFromSource(
     const KURL& url,
     RedirectStatus redirectStatus,
     ContentSecurityPolicy::ReportingStatus reportingStatus) const {
-  return isAllowedByAll<&CSPDirectiveList::allowChildFrameFromSource>(
+  return isAllowedByAll<&CSPDirectiveList::allowFrameFromSource>(
       m_policies, url, redirectStatus, reportingStatus);
 }
 
@@ -971,7 +972,7 @@
   // impact of this backwards-incompatible change.
   if (Document* document = this->document()) {
     UseCounter::count(*document, UseCounter::WorkerSubjectToCSP);
-    if (isAllowedByAll<&CSPDirectiveList::allowChildContextFromSource>(
+    if (isAllowedByAll<&CSPDirectiveList::allowWorkerFromSource>(
             m_policies, url, redirectStatus, SuppressReport) &&
         !isAllowedByAll<&CSPDirectiveList::allowScriptFromSource>(
             m_policies, url, AtomicString(), NotParserInserted, redirectStatus,
@@ -981,7 +982,7 @@
     }
   }
 
-  return isAllowedByAll<&CSPDirectiveList::allowChildContextFromSource>(
+  return isAllowedByAll<&CSPDirectiveList::allowWorkerFromSource>(
       m_policies, url, redirectStatus, reportingStatus);
 }
 
diff --git a/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicy.h b/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicy.h
index 2bb64ac..87ee3397 100644
--- a/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicy.h
+++ b/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicy.h
@@ -92,9 +92,9 @@
   static const char FrameAncestors[];
   static const char PluginTypes[];
 
-  // Manifest Directives (to be merged into CSP Level 2)
-  // https://w3c.github.io/manifest/#content-security-policy
+  // CSP Level 3 Directives
   static const char ManifestSrc[];
+  static const char WorkerSrc[];
 
   // Mixed Content Directive
   // https://w3c.github.io/webappsec/specs/mixedcontent/#strict-mode
@@ -182,9 +182,9 @@
   bool allowObjectFromSource(const KURL&,
                              RedirectStatus = RedirectStatus::NoRedirect,
                              ReportingStatus = SendReport) const;
-  bool allowChildFrameFromSource(const KURL&,
-                                 RedirectStatus = RedirectStatus::NoRedirect,
-                                 ReportingStatus = SendReport) const;
+  bool allowFrameFromSource(const KURL&,
+                            RedirectStatus = RedirectStatus::NoRedirect,
+                            ReportingStatus = SendReport) const;
   bool allowImageFromSource(const KURL&,
                             RedirectStatus = RedirectStatus::NoRedirect,
                             ReportingStatus = SendReport) const;
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_inline_box.cc b/third_party/WebKit/Source/core/layout/ng/ng_inline_box.cc
index b58270b..0229e6a 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_inline_box.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_inline_box.cc
@@ -16,6 +16,7 @@
 #include "core/layout/ng/ng_fragment_builder.h"
 #include "core/layout/ng/ng_length_utils.h"
 #include "core/layout/ng/ng_writing_mode.h"
+#include "wtf/text/CharacterNames.h"
 
 namespace blink {
 
@@ -29,14 +30,8 @@
   // Scan list of siblings collecting all in-flow non-atomic inlines. A single
   // NGInlineBox represent a collection of adjacent non-atomic inlines.
   last_inline_ = start_inline_;
-  for (LayoutObject* curr = start_inline_; curr; curr = curr->nextSibling()) {
-    // TODO(layout-dev): We may want to include floating and OOF positioned
-    // objects.
-    if (curr->isAtomicInlineLevel() && !curr->isFloating() &&
-        !curr->isOutOfFlowPositioned())
-      break;
+  for (LayoutObject* curr = start_inline_; curr; curr = curr->nextSibling())
     last_inline_ = curr;
-  }
 
   CollectInlines(start_inline_, last_inline_);
   CollapseWhiteSpace();
@@ -49,14 +44,24 @@
 // parent LayoutInline where possible, and joining all text content in a single
 // string to allow bidi resolution and shaping of the entire block.
 void NGInlineBox::CollectNode(LayoutObject* node, unsigned* offset) {
+  unsigned length = 0;
   if (node->isText()) {
     const String& text = toLayoutText(node)->text();
-    unsigned length = text.length();
+    length = text.length();
     text_content_.append(text);
+  }
 
+  // For atomic inlines add a unicode "object replacement character" to signal
+  // the presence of a non-text object to the unicode bidi algorithm.
+  else if (node->isAtomicInlineLevel()) {
+    text_content_.append(objectReplacementCharacter);
+    length = 1;
+  }
+
+  if (length) {
     unsigned start_offset = *offset;
     *offset = *offset + length;
-    items_.append(NGLayoutInlineItem(node->style(), start_offset, *offset));
+    items_.append(NGLayoutInlineItem(start_offset, *offset));
   }
 }
 
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_inline_box.h b/third_party/WebKit/Source/core/layout/ng/ng_inline_box.h
index b5eca422..1c76f34 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_inline_box.h
+++ b/third_party/WebKit/Source/core/layout/ng/ng_inline_box.h
@@ -83,12 +83,11 @@
 // element where possible.
 class NGLayoutInlineItem {
  public:
-  NGLayoutInlineItem(const ComputedStyle* style, unsigned start, unsigned end)
+  NGLayoutInlineItem(unsigned start, unsigned end)
       : start_offset_(start),
         end_offset_(end),
         direction_(LTR),
-        script_(USCRIPT_INVALID_CODE),
-        style_(style) {
+        script_(USCRIPT_INVALID_CODE) {
     DCHECK(end >= start);
   }
 
@@ -104,7 +103,6 @@
   UScriptCode script_;
   // FontFallbackPriority fallback_priority_;
   // bool rotate_sideways_;
-  const ComputedStyle* style_;
   RefPtr<ShapeResult> shape_result_;
 
   friend class NGInlineBox;
diff --git a/third_party/WebKit/Source/core/loader/FrameLoader.cpp b/third_party/WebKit/Source/core/loader/FrameLoader.cpp
index 23c0121c..d9ba74a92 100644
--- a/third_party/WebKit/Source/core/loader/FrameLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/FrameLoader.cpp
@@ -1596,8 +1596,8 @@
     if (parentFrame) {
       ContentSecurityPolicy* parentPolicy =
           parentFrame->securityContext()->contentSecurityPolicy();
-      if (!parentPolicy->allowChildFrameFromSource(request.url(),
-                                                   request.redirectStatus())) {
+      if (!parentPolicy->allowFrameFromSource(request.url(),
+                                              request.redirectStatus())) {
         // Fire a load event, as timing attacks would otherwise reveal that the
         // frame was blocked. This way, it looks like every other cross-origin
         // page load.
diff --git a/third_party/WebKit/Source/core/svg/SVGAnimatedLength.h b/third_party/WebKit/Source/core/svg/SVGAnimatedLength.h
index 0d852f0e..35db400 100644
--- a/third_party/WebKit/Source/core/svg/SVGAnimatedLength.h
+++ b/third_party/WebKit/Source/core/svg/SVGAnimatedLength.h
@@ -42,10 +42,13 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  static SVGAnimatedLength* create(SVGElement* contextElement,
-                                   const QualifiedName& attributeName,
-                                   SVGLength* initialValue) {
-    return new SVGAnimatedLength(contextElement, attributeName, initialValue);
+  static SVGAnimatedLength* create(
+      SVGElement* contextElement,
+      const QualifiedName& attributeName,
+      SVGLength* initialValue,
+      CSSPropertyID cssPropertyId = CSSPropertyInvalid) {
+    return new SVGAnimatedLength(contextElement, attributeName, initialValue,
+                                 cssPropertyId);
   }
 
   void setDefaultValueAsString(const String&);
@@ -56,10 +59,12 @@
  protected:
   SVGAnimatedLength(SVGElement* contextElement,
                     const QualifiedName& attributeName,
-                    SVGLength* initialValue)
+                    SVGLength* initialValue,
+                    CSSPropertyID cssPropertyId = CSSPropertyInvalid)
       : SVGAnimatedProperty<SVGLength>(contextElement,
                                        attributeName,
-                                       initialValue) {}
+                                       initialValue,
+                                       cssPropertyId) {}
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/svg/SVGAnimatedPath.cpp b/third_party/WebKit/Source/core/svg/SVGAnimatedPath.cpp
index 91529ef3..a282154 100644
--- a/third_party/WebKit/Source/core/svg/SVGAnimatedPath.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGAnimatedPath.cpp
@@ -33,10 +33,12 @@
 namespace blink {
 
 SVGAnimatedPath::SVGAnimatedPath(SVGElement* contextElement,
-                                 const QualifiedName& attributeName)
+                                 const QualifiedName& attributeName,
+                                 CSSPropertyID cssPropertyId)
     : SVGAnimatedProperty<SVGPath>(contextElement,
                                    attributeName,
-                                   SVGPath::create()) {}
+                                   SVGPath::create(),
+                                   cssPropertyId) {}
 
 SVGAnimatedPath::~SVGAnimatedPath() {}
 
diff --git a/third_party/WebKit/Source/core/svg/SVGAnimatedPath.h b/third_party/WebKit/Source/core/svg/SVGAnimatedPath.h
index ccf2461..4502c6b 100644
--- a/third_party/WebKit/Source/core/svg/SVGAnimatedPath.h
+++ b/third_party/WebKit/Source/core/svg/SVGAnimatedPath.h
@@ -40,13 +40,17 @@
  public:
   ~SVGAnimatedPath() override;
 
-  static SVGAnimatedPath* create(SVGElement* contextElement,
-                                 const QualifiedName& attributeName) {
-    return new SVGAnimatedPath(contextElement, attributeName);
+  static SVGAnimatedPath* create(
+      SVGElement* contextElement,
+      const QualifiedName& attributeName,
+      CSSPropertyID cssPropertyId = CSSPropertyInvalid) {
+    return new SVGAnimatedPath(contextElement, attributeName, cssPropertyId);
   }
 
  protected:
-  SVGAnimatedPath(SVGElement*, const QualifiedName&);
+  SVGAnimatedPath(SVGElement*,
+                  const QualifiedName&,
+                  CSSPropertyID = CSSPropertyInvalid);
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/svg/SVGAnimatedTypeAnimator.cpp b/third_party/WebKit/Source/core/svg/SVGAnimatedTypeAnimator.cpp
index 9efefd6..5b9430a 100644
--- a/third_party/WebKit/Source/core/svg/SVGAnimatedTypeAnimator.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGAnimatedTypeAnimator.cpp
@@ -131,6 +131,8 @@
     case AnimatedTransformList:
     case AnimatedUnknown:
       break;
+    default:
+      break;
   }
   NOTREACHED();
   return nullptr;
diff --git a/third_party/WebKit/Source/core/svg/SVGCircleElement.cpp b/third_party/WebKit/Source/core/svg/SVGCircleElement.cpp
index fdc7b58..5ab3a9a 100644
--- a/third_party/WebKit/Source/core/svg/SVGCircleElement.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGCircleElement.cpp
@@ -30,13 +30,16 @@
     : SVGGeometryElement(SVGNames::circleTag, document),
       m_cx(SVGAnimatedLength::create(this,
                                      SVGNames::cxAttr,
-                                     SVGLength::create(SVGLengthMode::Width))),
+                                     SVGLength::create(SVGLengthMode::Width),
+                                     CSSPropertyCx)),
       m_cy(SVGAnimatedLength::create(this,
                                      SVGNames::cyAttr,
-                                     SVGLength::create(SVGLengthMode::Height))),
+                                     SVGLength::create(SVGLengthMode::Height),
+                                     CSSPropertyCy)),
       m_r(SVGAnimatedLength::create(this,
                                     SVGNames::rAttr,
-                                    SVGLength::create(SVGLengthMode::Other))) {
+                                    SVGLength::create(SVGLengthMode::Other),
+                                    CSSPropertyR)) {
   addToPropertyMap(m_cx);
   addToPropertyMap(m_cy);
   addToPropertyMap(m_r);
@@ -74,22 +77,6 @@
   return path;
 }
 
-bool SVGCircleElement::isPresentationAttribute(
-    const QualifiedName& attrName) const {
-  if (attrName == SVGNames::cxAttr || attrName == SVGNames::cyAttr ||
-      attrName == SVGNames::rAttr)
-    return true;
-  return SVGGeometryElement::isPresentationAttribute(attrName);
-}
-
-bool SVGCircleElement::isPresentationAttributeWithSVGDOM(
-    const QualifiedName& attrName) const {
-  if (attrName == SVGNames::cxAttr || attrName == SVGNames::cyAttr ||
-      attrName == SVGNames::rAttr)
-    return true;
-  return SVGGeometryElement::isPresentationAttributeWithSVGDOM(attrName);
-}
-
 void SVGCircleElement::collectStyleForPresentationAttribute(
     const QualifiedName& name,
     const AtomicString& value,
diff --git a/third_party/WebKit/Source/core/svg/SVGCircleElement.h b/third_party/WebKit/Source/core/svg/SVGCircleElement.h
index 758c7ab..f02d178 100644
--- a/third_party/WebKit/Source/core/svg/SVGCircleElement.h
+++ b/third_party/WebKit/Source/core/svg/SVGCircleElement.h
@@ -47,8 +47,6 @@
 
   void svgAttributeChanged(const QualifiedName&) override;
 
-  bool isPresentationAttribute(const QualifiedName&) const override;
-  bool isPresentationAttributeWithSVGDOM(const QualifiedName&) const override;
   void collectStyleForPresentationAttribute(const QualifiedName&,
                                             const AtomicString&,
                                             MutableStylePropertySet*) override;
diff --git a/third_party/WebKit/Source/core/svg/SVGElement.cpp b/third_party/WebKit/Source/core/svg/SVGElement.cpp
index db5921d..846f72c0 100644
--- a/third_party/WebKit/Source/core/svg/SVGElement.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGElement.cpp
@@ -744,9 +744,17 @@
 }
 
 bool SVGElement::isPresentationAttribute(const QualifiedName& name) const {
+  if (const SVGAnimatedPropertyBase* property = propertyFromAttribute(name))
+    return property->hasPresentationAttributeMapping();
   return cssPropertyIdForSVGAttributeName(name) > 0;
 }
 
+bool SVGElement::isPresentationAttributeWithSVGDOM(
+    const QualifiedName& name) const {
+  const SVGAnimatedPropertyBase* property = propertyFromAttribute(name);
+  return property && property->hasPresentationAttributeMapping();
+}
+
 void SVGElement::collectStyleForPresentationAttribute(
     const QualifiedName& name,
     const AtomicString& value,
diff --git a/third_party/WebKit/Source/core/svg/SVGElement.h b/third_party/WebKit/Source/core/svg/SVGElement.h
index 22e5590..0dd6c833a 100644
--- a/third_party/WebKit/Source/core/svg/SVGElement.h
+++ b/third_party/WebKit/Source/core/svg/SVGElement.h
@@ -206,9 +206,7 @@
   static const AtomicString& eventParameterName();
 
   bool isPresentationAttribute(const QualifiedName&) const override;
-  virtual bool isPresentationAttributeWithSVGDOM(const QualifiedName&) const {
-    return false;
-  }
+  virtual bool isPresentationAttributeWithSVGDOM(const QualifiedName&) const;
 
  protected:
   SVGElement(const QualifiedName&,
diff --git a/third_party/WebKit/Source/core/svg/SVGEllipseElement.cpp b/third_party/WebKit/Source/core/svg/SVGEllipseElement.cpp
index 489598c0..c2161df 100644
--- a/third_party/WebKit/Source/core/svg/SVGEllipseElement.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGEllipseElement.cpp
@@ -30,17 +30,20 @@
     : SVGGeometryElement(SVGNames::ellipseTag, document),
       m_cx(SVGAnimatedLength::create(this,
                                      SVGNames::cxAttr,
-                                     SVGLength::create(SVGLengthMode::Width))),
+                                     SVGLength::create(SVGLengthMode::Width),
+                                     CSSPropertyCx)),
       m_cy(SVGAnimatedLength::create(this,
                                      SVGNames::cyAttr,
-                                     SVGLength::create(SVGLengthMode::Height))),
+                                     SVGLength::create(SVGLengthMode::Height),
+                                     CSSPropertyCy)),
       m_rx(SVGAnimatedLength::create(this,
                                      SVGNames::rxAttr,
-                                     SVGLength::create(SVGLengthMode::Width))),
-      m_ry(
-          SVGAnimatedLength::create(this,
-                                    SVGNames::ryAttr,
-                                    SVGLength::create(SVGLengthMode::Height))) {
+                                     SVGLength::create(SVGLengthMode::Width),
+                                     CSSPropertyRx)),
+      m_ry(SVGAnimatedLength::create(this,
+                                     SVGNames::ryAttr,
+                                     SVGLength::create(SVGLengthMode::Height),
+                                     CSSPropertyRy)) {
   addToPropertyMap(m_cx);
   addToPropertyMap(m_cy);
   addToPropertyMap(m_rx);
@@ -87,22 +90,6 @@
   return path;
 }
 
-bool SVGEllipseElement::isPresentationAttribute(
-    const QualifiedName& attrName) const {
-  if (attrName == SVGNames::cxAttr || attrName == SVGNames::cyAttr ||
-      attrName == SVGNames::rxAttr || attrName == SVGNames::ryAttr)
-    return true;
-  return SVGGeometryElement::isPresentationAttribute(attrName);
-}
-
-bool SVGEllipseElement::isPresentationAttributeWithSVGDOM(
-    const QualifiedName& attrName) const {
-  if (attrName == SVGNames::cxAttr || attrName == SVGNames::cyAttr ||
-      attrName == SVGNames::rxAttr || attrName == SVGNames::ryAttr)
-    return true;
-  return SVGGeometryElement::isPresentationAttributeWithSVGDOM(attrName);
-}
-
 void SVGEllipseElement::collectStyleForPresentationAttribute(
     const QualifiedName& name,
     const AtomicString& value,
diff --git a/third_party/WebKit/Source/core/svg/SVGEllipseElement.h b/third_party/WebKit/Source/core/svg/SVGEllipseElement.h
index 1878d6f4..710ea32 100644
--- a/third_party/WebKit/Source/core/svg/SVGEllipseElement.h
+++ b/third_party/WebKit/Source/core/svg/SVGEllipseElement.h
@@ -46,8 +46,6 @@
  private:
   explicit SVGEllipseElement(Document&);
 
-  bool isPresentationAttribute(const QualifiedName&) const override;
-  bool isPresentationAttributeWithSVGDOM(const QualifiedName&) const override;
   void collectStyleForPresentationAttribute(const QualifiedName&,
                                             const AtomicString&,
                                             MutableStylePropertySet*) override;
diff --git a/third_party/WebKit/Source/core/svg/SVGForeignObjectElement.cpp b/third_party/WebKit/Source/core/svg/SVGForeignObjectElement.cpp
index 16d5897..d5966e2 100644
--- a/third_party/WebKit/Source/core/svg/SVGForeignObjectElement.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGForeignObjectElement.cpp
@@ -32,18 +32,21 @@
     : SVGGraphicsElement(SVGNames::foreignObjectTag, document),
       m_x(SVGAnimatedLength::create(this,
                                     SVGNames::xAttr,
-                                    SVGLength::create(SVGLengthMode::Width))),
+                                    SVGLength::create(SVGLengthMode::Width),
+                                    CSSPropertyX)),
       m_y(SVGAnimatedLength::create(this,
                                     SVGNames::yAttr,
-                                    SVGLength::create(SVGLengthMode::Height))),
-      m_width(
-          SVGAnimatedLength::create(this,
-                                    SVGNames::widthAttr,
-                                    SVGLength::create(SVGLengthMode::Width))),
+                                    SVGLength::create(SVGLengthMode::Height),
+                                    CSSPropertyY)),
+      m_width(SVGAnimatedLength::create(this,
+                                        SVGNames::widthAttr,
+                                        SVGLength::create(SVGLengthMode::Width),
+                                        CSSPropertyWidth)),
       m_height(
           SVGAnimatedLength::create(this,
                                     SVGNames::heightAttr,
-                                    SVGLength::create(SVGLengthMode::Height))) {
+                                    SVGLength::create(SVGLengthMode::Height),
+                                    CSSPropertyHeight)) {
   addToPropertyMap(m_x);
   addToPropertyMap(m_y);
   addToPropertyMap(m_width);
@@ -62,22 +65,6 @@
 
 DEFINE_NODE_FACTORY(SVGForeignObjectElement)
 
-bool SVGForeignObjectElement::isPresentationAttribute(
-    const QualifiedName& name) const {
-  if (name == SVGNames::xAttr || name == SVGNames::yAttr ||
-      name == SVGNames::widthAttr || name == SVGNames::heightAttr)
-    return true;
-  return SVGGraphicsElement::isPresentationAttribute(name);
-}
-
-bool SVGForeignObjectElement::isPresentationAttributeWithSVGDOM(
-    const QualifiedName& attrName) const {
-  if (attrName == SVGNames::xAttr || attrName == SVGNames::yAttr ||
-      attrName == SVGNames::widthAttr || attrName == SVGNames::heightAttr)
-    return true;
-  return SVGGraphicsElement::isPresentationAttributeWithSVGDOM(attrName);
-}
-
 void SVGForeignObjectElement::collectStyleForPresentationAttribute(
     const QualifiedName& name,
     const AtomicString& value,
diff --git a/third_party/WebKit/Source/core/svg/SVGForeignObjectElement.h b/third_party/WebKit/Source/core/svg/SVGForeignObjectElement.h
index f4a4b20..065840cb 100644
--- a/third_party/WebKit/Source/core/svg/SVGForeignObjectElement.h
+++ b/third_party/WebKit/Source/core/svg/SVGForeignObjectElement.h
@@ -43,8 +43,6 @@
  private:
   explicit SVGForeignObjectElement(Document&);
 
-  bool isPresentationAttribute(const QualifiedName&) const override;
-  bool isPresentationAttributeWithSVGDOM(const QualifiedName&) const override;
   void collectStyleForPresentationAttribute(const QualifiedName&,
                                             const AtomicString&,
                                             MutableStylePropertySet*) override;
diff --git a/third_party/WebKit/Source/core/svg/SVGImageElement.cpp b/third_party/WebKit/Source/core/svg/SVGImageElement.cpp
index 634111a..0e1b5c8 100644
--- a/third_party/WebKit/Source/core/svg/SVGImageElement.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGImageElement.cpp
@@ -33,18 +33,21 @@
       SVGURIReference(this),
       m_x(SVGAnimatedLength::create(this,
                                     SVGNames::xAttr,
-                                    SVGLength::create(SVGLengthMode::Width))),
+                                    SVGLength::create(SVGLengthMode::Width),
+                                    CSSPropertyX)),
       m_y(SVGAnimatedLength::create(this,
                                     SVGNames::yAttr,
-                                    SVGLength::create(SVGLengthMode::Height))),
-      m_width(
-          SVGAnimatedLength::create(this,
-                                    SVGNames::widthAttr,
-                                    SVGLength::create(SVGLengthMode::Width))),
+                                    SVGLength::create(SVGLengthMode::Height),
+                                    CSSPropertyY)),
+      m_width(SVGAnimatedLength::create(this,
+                                        SVGNames::widthAttr,
+                                        SVGLength::create(SVGLengthMode::Width),
+                                        CSSPropertyWidth)),
       m_height(
           SVGAnimatedLength::create(this,
                                     SVGNames::heightAttr,
-                                    SVGLength::create(SVGLengthMode::Height))),
+                                    SVGLength::create(SVGLengthMode::Height),
+                                    CSSPropertyHeight)),
       m_preserveAspectRatio(SVGAnimatedPreserveAspectRatio::create(
           this,
           SVGNames::preserveAspectRatioAttr)),
@@ -82,22 +85,6 @@
   return true;
 }
 
-bool SVGImageElement::isPresentationAttribute(
-    const QualifiedName& attrName) const {
-  if (attrName == SVGNames::xAttr || attrName == SVGNames::yAttr ||
-      attrName == SVGNames::widthAttr || attrName == SVGNames::heightAttr)
-    return true;
-  return SVGGraphicsElement::isPresentationAttribute(attrName);
-}
-
-bool SVGImageElement::isPresentationAttributeWithSVGDOM(
-    const QualifiedName& attrName) const {
-  if (attrName == SVGNames::xAttr || attrName == SVGNames::yAttr ||
-      attrName == SVGNames::widthAttr || attrName == SVGNames::heightAttr)
-    return true;
-  return SVGGraphicsElement::isPresentationAttributeWithSVGDOM(attrName);
-}
-
 void SVGImageElement::collectStyleForPresentationAttribute(
     const QualifiedName& name,
     const AtomicString& value,
diff --git a/third_party/WebKit/Source/core/svg/SVGImageElement.h b/third_party/WebKit/Source/core/svg/SVGImageElement.h
index 167d3a6..663b72b 100644
--- a/third_party/WebKit/Source/core/svg/SVGImageElement.h
+++ b/third_party/WebKit/Source/core/svg/SVGImageElement.h
@@ -60,8 +60,6 @@
     return !hrefString().isNull();
   }
 
-  bool isPresentationAttribute(const QualifiedName&) const override;
-  bool isPresentationAttributeWithSVGDOM(const QualifiedName&) const override;
   void collectStyleForPresentationAttribute(const QualifiedName&,
                                             const AtomicString&,
                                             MutableStylePropertySet*) override;
diff --git a/third_party/WebKit/Source/core/svg/SVGMaskElement.cpp b/third_party/WebKit/Source/core/svg/SVGMaskElement.cpp
index 483cd2d..95b071a 100644
--- a/third_party/WebKit/Source/core/svg/SVGMaskElement.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGMaskElement.cpp
@@ -33,18 +33,21 @@
       SVGTests(this),
       m_x(SVGAnimatedLength::create(this,
                                     SVGNames::xAttr,
-                                    SVGLength::create(SVGLengthMode::Width))),
+                                    SVGLength::create(SVGLengthMode::Width),
+                                    CSSPropertyX)),
       m_y(SVGAnimatedLength::create(this,
                                     SVGNames::yAttr,
-                                    SVGLength::create(SVGLengthMode::Height))),
-      m_width(
-          SVGAnimatedLength::create(this,
-                                    SVGNames::widthAttr,
-                                    SVGLength::create(SVGLengthMode::Width))),
+                                    SVGLength::create(SVGLengthMode::Height),
+                                    CSSPropertyY)),
+      m_width(SVGAnimatedLength::create(this,
+                                        SVGNames::widthAttr,
+                                        SVGLength::create(SVGLengthMode::Width),
+                                        CSSPropertyWidth)),
       m_height(
           SVGAnimatedLength::create(this,
                                     SVGNames::heightAttr,
-                                    SVGLength::create(SVGLengthMode::Height))),
+                                    SVGLength::create(SVGLengthMode::Height),
+                                    CSSPropertyHeight)),
       m_maskUnits(SVGAnimatedEnumeration<SVGUnitTypes::SVGUnitType>::create(
           this,
           SVGNames::maskUnitsAttr,
@@ -85,22 +88,6 @@
 
 DEFINE_NODE_FACTORY(SVGMaskElement)
 
-bool SVGMaskElement::isPresentationAttribute(
-    const QualifiedName& attrName) const {
-  if (attrName == SVGNames::xAttr || attrName == SVGNames::yAttr ||
-      attrName == SVGNames::widthAttr || attrName == SVGNames::heightAttr)
-    return true;
-  return SVGElement::isPresentationAttribute(attrName);
-}
-
-bool SVGMaskElement::isPresentationAttributeWithSVGDOM(
-    const QualifiedName& attrName) const {
-  if (attrName == SVGNames::xAttr || attrName == SVGNames::yAttr ||
-      attrName == SVGNames::widthAttr || attrName == SVGNames::heightAttr)
-    return true;
-  return SVGElement::isPresentationAttributeWithSVGDOM(attrName);
-}
-
 void SVGMaskElement::collectStyleForPresentationAttribute(
     const QualifiedName& name,
     const AtomicString& value,
diff --git a/third_party/WebKit/Source/core/svg/SVGMaskElement.h b/third_party/WebKit/Source/core/svg/SVGMaskElement.h
index e3f7c2b..e72c23c 100644
--- a/third_party/WebKit/Source/core/svg/SVGMaskElement.h
+++ b/third_party/WebKit/Source/core/svg/SVGMaskElement.h
@@ -56,8 +56,6 @@
   bool isValid() const override { return SVGTests::isValid(); }
   bool needsPendingResourceHandling() const override { return false; }
 
-  bool isPresentationAttribute(const QualifiedName&) const override;
-  bool isPresentationAttributeWithSVGDOM(const QualifiedName&) const override;
   void collectStyleForPresentationAttribute(const QualifiedName&,
                                             const AtomicString&,
                                             MutableStylePropertySet*) override;
diff --git a/third_party/WebKit/Source/core/svg/SVGPathElement.cpp b/third_party/WebKit/Source/core/svg/SVGPathElement.cpp
index 7b734ea..d65a3788 100644
--- a/third_party/WebKit/Source/core/svg/SVGPathElement.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGPathElement.cpp
@@ -54,7 +54,7 @@
 inline SVGPathElement::SVGPathElement(Document& document)
     : SVGGeometryElement(SVGNames::pathTag, document),
       m_pathLength(SVGAnimatedPathLength::create(this)),
-      m_path(SVGAnimatedPath::create(this, SVGNames::dAttr)) {
+      m_path(SVGAnimatedPath::create(this, SVGNames::dAttr, CSSPropertyD)) {
   addToPropertyMap(m_pathLength);
   addToPropertyMap(m_path);
 }
@@ -116,20 +116,6 @@
   return SVGPathQuery(pathByteStream()).getPathSegIndexAtLength(length);
 }
 
-bool SVGPathElement::isPresentationAttribute(
-    const QualifiedName& attrName) const {
-  if (attrName == SVGNames::dAttr)
-    return true;
-  return SVGGeometryElement::isPresentationAttribute(attrName);
-}
-
-bool SVGPathElement::isPresentationAttributeWithSVGDOM(
-    const QualifiedName& attrName) const {
-  if (attrName == SVGNames::dAttr)
-    return true;
-  return SVGGeometryElement::isPresentationAttributeWithSVGDOM(attrName);
-}
-
 void SVGPathElement::svgAttributeChanged(const QualifiedName& attrName) {
   if (attrName == SVGNames::dAttr) {
     SVGElement::InvalidationGuard invalidationGuard(this);
diff --git a/third_party/WebKit/Source/core/svg/SVGPathElement.h b/third_party/WebKit/Source/core/svg/SVGPathElement.h
index 06c4dc3..cd33a84 100644
--- a/third_party/WebKit/Source/core/svg/SVGPathElement.h
+++ b/third_party/WebKit/Source/core/svg/SVGPathElement.h
@@ -51,9 +51,6 @@
     return stylePath()->byteStream();
   }
 
-  bool isPresentationAttribute(const QualifiedName&) const override;
-  bool isPresentationAttributeWithSVGDOM(const QualifiedName&) const override;
-
   FloatRect getBBox() override;
 
   DECLARE_VIRTUAL_TRACE();
diff --git a/third_party/WebKit/Source/core/svg/SVGRectElement.cpp b/third_party/WebKit/Source/core/svg/SVGRectElement.cpp
index ce116b41..c7e08f7 100644
--- a/third_party/WebKit/Source/core/svg/SVGRectElement.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGRectElement.cpp
@@ -30,25 +30,29 @@
     : SVGGeometryElement(SVGNames::rectTag, document),
       m_x(SVGAnimatedLength::create(this,
                                     SVGNames::xAttr,
-                                    SVGLength::create(SVGLengthMode::Width))),
+                                    SVGLength::create(SVGLengthMode::Width),
+                                    CSSPropertyX)),
       m_y(SVGAnimatedLength::create(this,
                                     SVGNames::yAttr,
-                                    SVGLength::create(SVGLengthMode::Height))),
-      m_width(
-          SVGAnimatedLength::create(this,
-                                    SVGNames::widthAttr,
-                                    SVGLength::create(SVGLengthMode::Width))),
+                                    SVGLength::create(SVGLengthMode::Height),
+                                    CSSPropertyY)),
+      m_width(SVGAnimatedLength::create(this,
+                                        SVGNames::widthAttr,
+                                        SVGLength::create(SVGLengthMode::Width),
+                                        CSSPropertyWidth)),
       m_height(
           SVGAnimatedLength::create(this,
                                     SVGNames::heightAttr,
-                                    SVGLength::create(SVGLengthMode::Height))),
+                                    SVGLength::create(SVGLengthMode::Height),
+                                    CSSPropertyHeight)),
       m_rx(SVGAnimatedLength::create(this,
                                      SVGNames::rxAttr,
-                                     SVGLength::create(SVGLengthMode::Width))),
-      m_ry(
-          SVGAnimatedLength::create(this,
-                                    SVGNames::ryAttr,
-                                    SVGLength::create(SVGLengthMode::Height))) {
+                                     SVGLength::create(SVGLengthMode::Width),
+                                     CSSPropertyRx)),
+      m_ry(SVGAnimatedLength::create(this,
+                                     SVGNames::ryAttr,
+                                     SVGLength::create(SVGLengthMode::Height),
+                                     CSSPropertyRy)) {
   addToPropertyMap(m_x);
   addToPropertyMap(m_y);
   addToPropertyMap(m_width);
@@ -112,24 +116,6 @@
   return path;
 }
 
-bool SVGRectElement::isPresentationAttribute(
-    const QualifiedName& attrName) const {
-  if (attrName == SVGNames::xAttr || attrName == SVGNames::yAttr ||
-      attrName == SVGNames::widthAttr || attrName == SVGNames::heightAttr ||
-      attrName == SVGNames::rxAttr || attrName == SVGNames::ryAttr)
-    return true;
-  return SVGGeometryElement::isPresentationAttribute(attrName);
-}
-
-bool SVGRectElement::isPresentationAttributeWithSVGDOM(
-    const QualifiedName& attrName) const {
-  if (attrName == SVGNames::xAttr || attrName == SVGNames::yAttr ||
-      attrName == SVGNames::widthAttr || attrName == SVGNames::heightAttr ||
-      attrName == SVGNames::rxAttr || attrName == SVGNames::ryAttr)
-    return true;
-  return SVGGeometryElement::isPresentationAttributeWithSVGDOM(attrName);
-}
-
 void SVGRectElement::collectStyleForPresentationAttribute(
     const QualifiedName& name,
     const AtomicString& value,
diff --git a/third_party/WebKit/Source/core/svg/SVGRectElement.h b/third_party/WebKit/Source/core/svg/SVGRectElement.h
index fa0db667..e5c8986 100644
--- a/third_party/WebKit/Source/core/svg/SVGRectElement.h
+++ b/third_party/WebKit/Source/core/svg/SVGRectElement.h
@@ -48,8 +48,6 @@
  private:
   explicit SVGRectElement(Document&);
 
-  bool isPresentationAttribute(const QualifiedName&) const override;
-  bool isPresentationAttributeWithSVGDOM(const QualifiedName&) const override;
   void collectStyleForPresentationAttribute(const QualifiedName&,
                                             const AtomicString&,
                                             MutableStylePropertySet*) override;
diff --git a/third_party/WebKit/Source/core/svg/SVGSVGElement.cpp b/third_party/WebKit/Source/core/svg/SVGSVGElement.cpp
index 1ed4a6b..f49fb084 100644
--- a/third_party/WebKit/Source/core/svg/SVGSVGElement.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGSVGElement.cpp
@@ -67,18 +67,21 @@
       SVGFitToViewBox(this),
       m_x(SVGAnimatedLength::create(this,
                                     SVGNames::xAttr,
-                                    SVGLength::create(SVGLengthMode::Width))),
+                                    SVGLength::create(SVGLengthMode::Width),
+                                    CSSPropertyX)),
       m_y(SVGAnimatedLength::create(this,
                                     SVGNames::yAttr,
-                                    SVGLength::create(SVGLengthMode::Height))),
-      m_width(
-          SVGAnimatedLength::create(this,
-                                    SVGNames::widthAttr,
-                                    SVGLength::create(SVGLengthMode::Width))),
+                                    SVGLength::create(SVGLengthMode::Height),
+                                    CSSPropertyY)),
+      m_width(SVGAnimatedLength::create(this,
+                                        SVGNames::widthAttr,
+                                        SVGLength::create(SVGLengthMode::Width),
+                                        CSSPropertyWidth)),
       m_height(
           SVGAnimatedLength::create(this,
                                     SVGNames::heightAttr,
-                                    SVGLength::create(SVGLengthMode::Height))),
+                                    SVGLength::create(SVGLengthMode::Height),
+                                    CSSPropertyHeight)),
       m_useCurrentView(false),
       m_timeContainer(SMILTimeContainer::create(*this)),
       m_translation(SVGPoint::create()),
@@ -217,19 +220,16 @@
 }
 
 bool SVGSVGElement::isPresentationAttribute(const QualifiedName& name) const {
-  if (isOutermostSVGSVGElement() &&
-      (name == SVGNames::widthAttr || name == SVGNames::heightAttr))
-    return true;
-  else if (name == SVGNames::xAttr || name == SVGNames::yAttr)
-    return true;
-
+  if ((name == SVGNames::widthAttr || name == SVGNames::heightAttr) &&
+      !isOutermostSVGSVGElement())
+    return false;
   return SVGGraphicsElement::isPresentationAttribute(name);
 }
 
 bool SVGSVGElement::isPresentationAttributeWithSVGDOM(
     const QualifiedName& attrName) const {
-  if (attrName == SVGNames::xAttr || attrName == SVGNames::yAttr)
-    return true;
+  if (attrName == SVGNames::widthAttr || attrName == SVGNames::heightAttr)
+    return false;
   return SVGGraphicsElement::isPresentationAttributeWithSVGDOM(attrName);
 }
 
diff --git a/third_party/WebKit/Source/core/svg/SVGUseElement.cpp b/third_party/WebKit/Source/core/svg/SVGUseElement.cpp
index 4e3aae13..0091e379 100644
--- a/third_party/WebKit/Source/core/svg/SVGUseElement.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGUseElement.cpp
@@ -53,10 +53,12 @@
       SVGURIReference(this),
       m_x(SVGAnimatedLength::create(this,
                                     SVGNames::xAttr,
-                                    SVGLength::create(SVGLengthMode::Width))),
+                                    SVGLength::create(SVGLengthMode::Width),
+                                    CSSPropertyX)),
       m_y(SVGAnimatedLength::create(this,
                                     SVGNames::yAttr,
-                                    SVGLength::create(SVGLengthMode::Height))),
+                                    SVGLength::create(SVGLengthMode::Height),
+                                    CSSPropertyY)),
       m_width(
           SVGAnimatedLength::create(this,
                                     SVGNames::widthAttr,
@@ -172,20 +174,6 @@
   }
 }
 
-bool SVGUseElement::isPresentationAttribute(
-    const QualifiedName& attrName) const {
-  if (attrName == SVGNames::xAttr || attrName == SVGNames::yAttr)
-    return true;
-  return SVGGraphicsElement::isPresentationAttribute(attrName);
-}
-
-bool SVGUseElement::isPresentationAttributeWithSVGDOM(
-    const QualifiedName& attrName) const {
-  if (attrName == SVGNames::xAttr || attrName == SVGNames::yAttr)
-    return true;
-  return SVGGraphicsElement::isPresentationAttributeWithSVGDOM(attrName);
-}
-
 void SVGUseElement::collectStyleForPresentationAttribute(
     const QualifiedName& name,
     const AtomicString& value,
diff --git a/third_party/WebKit/Source/core/svg/SVGUseElement.h b/third_party/WebKit/Source/core/svg/SVGUseElement.h
index b7a6358..24ae828e 100644
--- a/third_party/WebKit/Source/core/svg/SVGUseElement.h
+++ b/third_party/WebKit/Source/core/svg/SVGUseElement.h
@@ -67,11 +67,9 @@
 
   FloatRect getBBox() override;
 
-  bool isPresentationAttribute(const QualifiedName&) const override;
   void collectStyleForPresentationAttribute(const QualifiedName&,
                                             const AtomicString&,
                                             MutableStylePropertySet*) override;
-  bool isPresentationAttributeWithSVGDOM(const QualifiedName&) const override;
 
   bool isStructurallyExternal() const override;
 
diff --git a/third_party/WebKit/Source/core/svg/properties/SVGAnimatedProperty.cpp b/third_party/WebKit/Source/core/svg/properties/SVGAnimatedProperty.cpp
index 95ebbe8..bd62abb 100644
--- a/third_party/WebKit/Source/core/svg/properties/SVGAnimatedProperty.cpp
+++ b/third_party/WebKit/Source/core/svg/properties/SVGAnimatedProperty.cpp
@@ -37,13 +37,17 @@
 SVGAnimatedPropertyBase::SVGAnimatedPropertyBase(
     AnimatedPropertyType type,
     SVGElement* contextElement,
-    const QualifiedName& attributeName)
+    const QualifiedName& attributeName,
+    CSSPropertyID cssPropertyId)
     : m_type(type),
+      m_cssPropertyId(cssPropertyId),
       m_isReadOnly(false),
       m_contextElement(contextElement),
       m_attributeName(attributeName) {
-  ASSERT(m_contextElement);
-  ASSERT(m_attributeName != QualifiedName::null());
+  DCHECK(m_contextElement);
+  DCHECK(m_attributeName != QualifiedName::null());
+  DCHECK_EQ(this->type(), type);
+  DCHECK_EQ(this->cssPropertyId(), cssPropertyId);
 }
 
 SVGAnimatedPropertyBase::~SVGAnimatedPropertyBase() {}
diff --git a/third_party/WebKit/Source/core/svg/properties/SVGAnimatedProperty.h b/third_party/WebKit/Source/core/svg/properties/SVGAnimatedProperty.h
index 22100a5..f39ec0f 100644
--- a/third_party/WebKit/Source/core/svg/properties/SVGAnimatedProperty.h
+++ b/third_party/WebKit/Source/core/svg/properties/SVGAnimatedProperty.h
@@ -62,12 +62,22 @@
   virtual bool needsSynchronizeAttribute() = 0;
   virtual void synchronizeAttribute();
 
-  AnimatedPropertyType type() const { return m_type; }
+  AnimatedPropertyType type() const {
+    return static_cast<AnimatedPropertyType>(m_type);
+  }
 
   SVGElement* contextElement() const { return m_contextElement; }
 
   const QualifiedName& attributeName() const { return m_attributeName; }
 
+  CSSPropertyID cssPropertyId() const {
+    return static_cast<CSSPropertyID>(m_cssPropertyId);
+  }
+
+  bool hasPresentationAttributeMapping() const {
+    return cssPropertyId() != CSSPropertyInvalid;
+  }
+
   bool isReadOnly() const { return m_isReadOnly; }
 
   void setReadOnly() { m_isReadOnly = true; }
@@ -79,11 +89,19 @@
  protected:
   SVGAnimatedPropertyBase(AnimatedPropertyType,
                           SVGElement*,
-                          const QualifiedName& attributeName);
+                          const QualifiedName& attributeName,
+                          CSSPropertyID = CSSPropertyInvalid);
 
  private:
-  const AnimatedPropertyType m_type;
-  bool m_isReadOnly;
+  static_assert(NumberOfAnimatedPropertyTypes <= (1u << 5),
+                "enough bits for AnimatedPropertyType (m_type)");
+  static constexpr int kCssPropertyBits = 9;
+  static_assert((1u << kCssPropertyBits) - 1 >= lastCSSProperty,
+                "enough bits for CSS property ids");
+
+  const unsigned m_type : 5;
+  const unsigned m_cssPropertyId : kCssPropertyBits;
+  unsigned m_isReadOnly : 1;
 
   // This raw pointer is safe since the SVG element is guaranteed to be kept
   // alive by a V8 wrapper.
@@ -140,10 +158,12 @@
  protected:
   SVGAnimatedPropertyCommon(SVGElement* contextElement,
                             const QualifiedName& attributeName,
-                            Property* initialValue)
+                            Property* initialValue,
+                            CSSPropertyID cssPropertyId = CSSPropertyInvalid)
       : SVGAnimatedPropertyBase(Property::classType(),
                                 contextElement,
-                                attributeName),
+                                attributeName,
+                                cssPropertyId),
         m_baseValue(initialValue) {}
 
  private:
@@ -200,10 +220,12 @@
  protected:
   SVGAnimatedProperty(SVGElement* contextElement,
                       const QualifiedName& attributeName,
-                      Property* initialValue)
+                      Property* initialValue,
+                      CSSPropertyID cssPropertyId = CSSPropertyInvalid)
       : SVGAnimatedPropertyCommon<Property>(contextElement,
                                             attributeName,
-                                            initialValue),
+                                            initialValue,
+                                            cssPropertyId),
         m_baseValueUpdated(false) {}
 
   bool m_baseValueUpdated;
@@ -220,9 +242,10 @@
   static SVGAnimatedProperty<Property>* create(
       SVGElement* contextElement,
       const QualifiedName& attributeName,
-      Property* initialValue) {
+      Property* initialValue,
+      CSSPropertyID cssPropertyId = CSSPropertyInvalid) {
     return new SVGAnimatedProperty<Property>(contextElement, attributeName,
-                                             initialValue);
+                                             initialValue, cssPropertyId);
   }
 
   void setAnimatedValue(SVGPropertyBase* value) override {
@@ -276,10 +299,12 @@
  protected:
   SVGAnimatedProperty(SVGElement* contextElement,
                       const QualifiedName& attributeName,
-                      Property* initialValue)
+                      Property* initialValue,
+                      CSSPropertyID cssPropertyId = CSSPropertyInvalid)
       : SVGAnimatedPropertyCommon<Property>(contextElement,
                                             attributeName,
-                                            initialValue) {}
+                                            initialValue,
+                                            cssPropertyId) {}
 
  private:
   void updateAnimValTearOffIfNeeded() {
@@ -306,9 +331,10 @@
   static SVGAnimatedProperty<Property>* create(
       SVGElement* contextElement,
       const QualifiedName& attributeName,
-      Property* initialValue) {
+      Property* initialValue,
+      CSSPropertyID cssPropertyId = CSSPropertyInvalid) {
     return new SVGAnimatedProperty<Property>(contextElement, attributeName,
-                                             initialValue);
+                                             initialValue, cssPropertyId);
   }
 
   bool needsSynchronizeAttribute() override {
@@ -320,10 +346,12 @@
  protected:
   SVGAnimatedProperty(SVGElement* contextElement,
                       const QualifiedName& attributeName,
-                      Property* initialValue)
+                      Property* initialValue,
+                      CSSPropertyID cssPropertyId = CSSPropertyInvalid)
       : SVGAnimatedPropertyCommon<Property>(contextElement,
                                             attributeName,
-                                            initialValue) {}
+                                            initialValue,
+                                            cssPropertyId) {}
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/svg/properties/SVGPropertyInfo.h b/third_party/WebKit/Source/core/svg/properties/SVGPropertyInfo.h
index eeaf2d1..c788cf7 100644
--- a/third_party/WebKit/Source/core/svg/properties/SVGPropertyInfo.h
+++ b/third_party/WebKit/Source/core/svg/properties/SVGPropertyInfo.h
@@ -44,6 +44,7 @@
   AnimatedStringList,
   AnimatedTransform,
   AnimatedTransformList,
+  NumberOfAnimatedPropertyTypes
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/mediastream/BUILD.gn b/third_party/WebKit/Source/modules/mediastream/BUILD.gn
index d0787b6..006dd5c 100644
--- a/third_party/WebKit/Source/modules/mediastream/BUILD.gn
+++ b/third_party/WebKit/Source/modules/mediastream/BUILD.gn
@@ -26,6 +26,9 @@
     "MediaStreamTrack.h",
     "MediaStreamTrackEvent.cpp",
     "MediaStreamTrackEvent.h",
+    "MediaStreamTrackSourcesCallback.h",
+    "MediaStreamTrackSourcesRequestImpl.cpp",
+    "MediaStreamTrackSourcesRequestImpl.h",
     "NavigatorMediaStream.cpp",
     "NavigatorMediaStream.h",
     "NavigatorUserMedia.cpp",
@@ -34,6 +37,8 @@
     "NavigatorUserMediaError.h",
     "NavigatorUserMediaErrorCallback.h",
     "NavigatorUserMediaSuccessCallback.h",
+    "SourceInfo.cpp",
+    "SourceInfo.h",
     "URLMediaStream.cpp",
     "URLMediaStream.h",
     "UserMediaClient.h",
diff --git a/third_party/WebKit/Source/modules/mediastream/MediaStreamTrack.cpp b/third_party/WebKit/Source/modules/mediastream/MediaStreamTrack.cpp
index 0e4d5d1..9739d92 100644
--- a/third_party/WebKit/Source/modules/mediastream/MediaStreamTrack.cpp
+++ b/third_party/WebKit/Source/modules/mediastream/MediaStreamTrack.cpp
@@ -33,11 +33,14 @@
 #include "core/frame/Deprecation.h"
 #include "modules/mediastream/MediaConstraintsImpl.h"
 #include "modules/mediastream/MediaStream.h"
+#include "modules/mediastream/MediaStreamTrackSourcesCallback.h"
+#include "modules/mediastream/MediaStreamTrackSourcesRequestImpl.h"
 #include "modules/mediastream/MediaTrackSettings.h"
 #include "modules/mediastream/UserMediaController.h"
 #include "platform/mediastream/MediaStreamCenter.h"
 #include "platform/mediastream/MediaStreamComponent.h"
 #include "public/platform/WebMediaStreamTrack.h"
+#include "public/platform/WebSourceInfo.h"
 #include "wtf/Assertions.h"
 #include <memory>
 
@@ -128,6 +131,24 @@
   return String();
 }
 
+void MediaStreamTrack::getSources(ExecutionContext* context,
+                                  MediaStreamTrackSourcesCallback* callback,
+                                  ExceptionState& exceptionState) {
+  LocalFrame* frame = toDocument(context)->frame();
+  UserMediaController* userMedia = UserMediaController::from(frame);
+  if (!userMedia) {
+    exceptionState.throwDOMException(
+        NotSupportedError,
+        "No sources controller available; is this a detached window?");
+    return;
+  }
+  Deprecation::countDeprecation(context,
+                                UseCounter::MediaStreamTrackGetSources);
+  MediaStreamTrackSourcesRequest* request =
+      MediaStreamTrackSourcesRequestImpl::create(*context, callback);
+  userMedia->requestSources(request);
+}
+
 void MediaStreamTrack::stopTrack(ExceptionState& exceptionState) {
   if (ended())
     return;
diff --git a/third_party/WebKit/Source/modules/mediastream/MediaStreamTrack.h b/third_party/WebKit/Source/modules/mediastream/MediaStreamTrack.h
index f9cde57..a18b7f6 100644
--- a/third_party/WebKit/Source/modules/mediastream/MediaStreamTrack.h
+++ b/third_party/WebKit/Source/modules/mediastream/MediaStreamTrack.h
@@ -30,6 +30,7 @@
 #include "core/dom/ActiveDOMObject.h"
 #include "modules/EventTargetModules.h"
 #include "modules/ModulesExport.h"
+#include "modules/mediastream/SourceInfo.h"
 #include "platform/mediastream/MediaStreamDescriptor.h"
 #include "platform/mediastream/MediaStreamSource.h"
 #include "public/platform/WebMediaConstraints.h"
@@ -68,6 +69,9 @@
 
   String readyState() const;
 
+  static void getSources(ExecutionContext*,
+                         MediaStreamTrackSourcesCallback*,
+                         ExceptionState&);
   void stopTrack(ExceptionState&);
   virtual MediaStreamTrack* clone(ExecutionContext*);
 
diff --git a/third_party/WebKit/Source/modules/mediastream/MediaStreamTrack.idl b/third_party/WebKit/Source/modules/mediastream/MediaStreamTrack.idl
index f96f1b2c..9a2b1c4e 100644
--- a/third_party/WebKit/Source/modules/mediastream/MediaStreamTrack.idl
+++ b/third_party/WebKit/Source/modules/mediastream/MediaStreamTrack.idl
@@ -54,4 +54,7 @@
 
     // Non-standard APIs
     [MeasureAs=MediaStreamTrackRemote] readonly attribute boolean remote;
+    // TODO(guidou): Remove MediaStreamTrack.getSources().
+    // https://crbug.com/649710
+    [CallWith=ExecutionContext, RaisesException, DeprecateAs=MediaStreamTrackGetSources] static void getSources(MediaStreamTrackSourcesCallback callback);
 };
diff --git a/third_party/WebKit/Source/modules/mediastream/MediaStreamTrackSourcesCallback.h b/third_party/WebKit/Source/modules/mediastream/MediaStreamTrackSourcesCallback.h
new file mode 100644
index 0000000..5d4b72395
--- /dev/null
+++ b/third_party/WebKit/Source/modules/mediastream/MediaStreamTrackSourcesCallback.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL GOOGLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef MediaStreamTrackSourcesCallback_h
+#define MediaStreamTrackSourcesCallback_h
+
+#include "modules/mediastream/SourceInfo.h"
+namespace blink {
+
+class MediaStreamTrackSourcesCallback
+    : public GarbageCollectedFinalized<MediaStreamTrackSourcesCallback> {
+ public:
+  virtual ~MediaStreamTrackSourcesCallback() {}
+  DEFINE_INLINE_VIRTUAL_TRACE() {}
+  virtual void handleEvent(const SourceInfoVector&) = 0;
+};
+
+}  // namespace blink
+
+#endif  // MediaStreamTrackSourcesCallback_h
diff --git a/third_party/WebKit/Source/modules/mediastream/MediaStreamTrackSourcesCallback.idl b/third_party/WebKit/Source/modules/mediastream/MediaStreamTrackSourcesCallback.idl
new file mode 100644
index 0000000..9756e09
--- /dev/null
+++ b/third_party/WebKit/Source/modules/mediastream/MediaStreamTrackSourcesCallback.idl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL GOOGLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// TODO(guidou): Remove MediaStreamTrack.getSources(). https://crbug.com/649710
+callback interface MediaStreamTrackSourcesCallback {
+    void handleEvent(sequence<SourceInfo> sources);
+};
diff --git a/third_party/WebKit/Source/modules/mediastream/MediaStreamTrackSourcesRequestImpl.cpp b/third_party/WebKit/Source/modules/mediastream/MediaStreamTrackSourcesRequestImpl.cpp
new file mode 100644
index 0000000..1f5dfa7
--- /dev/null
+++ b/third_party/WebKit/Source/modules/mediastream/MediaStreamTrackSourcesRequestImpl.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL GOOGLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "modules/mediastream/MediaStreamTrackSourcesRequestImpl.h"
+
+#include "core/dom/ExecutionContext.h"
+#include "core/dom/ExecutionContextTask.h"
+#include "modules/mediastream/MediaStreamTrackSourcesCallback.h"
+#include "platform/weborigin/SecurityOrigin.h"
+#include "public/platform/WebSourceInfo.h"
+#include "public/platform/WebTraceLocation.h"
+#include "wtf/Functional.h"
+
+namespace blink {
+
+MediaStreamTrackSourcesRequestImpl* MediaStreamTrackSourcesRequestImpl::create(
+    ExecutionContext& context,
+    MediaStreamTrackSourcesCallback* callback) {
+  return new MediaStreamTrackSourcesRequestImpl(context, callback);
+}
+
+MediaStreamTrackSourcesRequestImpl::MediaStreamTrackSourcesRequestImpl(
+    ExecutionContext& context,
+    MediaStreamTrackSourcesCallback* callback)
+    : m_callback(callback), m_executionContext(&context) {}
+
+MediaStreamTrackSourcesRequestImpl::~MediaStreamTrackSourcesRequestImpl() {}
+
+PassRefPtr<SecurityOrigin> MediaStreamTrackSourcesRequestImpl::origin() {
+  return m_executionContext->getSecurityOrigin()->isolatedCopy();
+}
+
+void MediaStreamTrackSourcesRequestImpl::requestSucceeded(
+    const WebVector<WebSourceInfo>& webSourceInfos) {
+  DCHECK(m_callback);
+
+  for (size_t i = 0; i < webSourceInfos.size(); ++i)
+    m_sourceInfos.append(SourceInfo::create(webSourceInfos[i]));
+  m_executionContext->postTask(
+      BLINK_FROM_HERE, createCrossThreadTask(
+                           &MediaStreamTrackSourcesRequestImpl::performCallback,
+                           wrapCrossThreadPersistent(this)));
+}
+
+void MediaStreamTrackSourcesRequestImpl::performCallback() {
+  m_callback->handleEvent(m_sourceInfos);
+  m_callback.clear();
+}
+
+DEFINE_TRACE(MediaStreamTrackSourcesRequestImpl) {
+  visitor->trace(m_callback);
+  visitor->trace(m_executionContext);
+  visitor->trace(m_sourceInfos);
+  MediaStreamTrackSourcesRequest::trace(visitor);
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/modules/mediastream/MediaStreamTrackSourcesRequestImpl.h b/third_party/WebKit/Source/modules/mediastream/MediaStreamTrackSourcesRequestImpl.h
new file mode 100644
index 0000000..fe59803
--- /dev/null
+++ b/third_party/WebKit/Source/modules/mediastream/MediaStreamTrackSourcesRequestImpl.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL GOOGLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef MediaStreamTrackSourcesRequestImpl_h
+#define MediaStreamTrackSourcesRequestImpl_h
+
+#include "modules/mediastream/SourceInfo.h"
+#include "platform/mediastream/MediaStreamTrackSourcesRequest.h"
+
+namespace blink {
+
+class ExecutionContext;
+class MediaStreamTrackSourcesCallback;
+class SecurityOrigin;
+class WebSourceInfo;
+template <typename T>
+class WebVector;
+
+class MediaStreamTrackSourcesRequestImpl final
+    : public MediaStreamTrackSourcesRequest {
+ public:
+  static MediaStreamTrackSourcesRequestImpl* create(
+      ExecutionContext&,
+      MediaStreamTrackSourcesCallback*);
+  ~MediaStreamTrackSourcesRequestImpl();
+
+  PassRefPtr<SecurityOrigin> origin() override;
+  void requestSucceeded(const WebVector<WebSourceInfo>&) override;
+
+  DECLARE_VIRTUAL_TRACE();
+
+ private:
+  MediaStreamTrackSourcesRequestImpl(ExecutionContext&,
+                                     MediaStreamTrackSourcesCallback*);
+
+  void performCallback();
+
+  Member<MediaStreamTrackSourcesCallback> m_callback;
+  Member<ExecutionContext> m_executionContext;
+  SourceInfoVector m_sourceInfos;
+};
+
+}  // namespace blink
+
+#endif  // MediaStreamTrackSourcesRequestImpl_h
diff --git a/third_party/WebKit/Source/modules/mediastream/SourceInfo.cpp b/third_party/WebKit/Source/modules/mediastream/SourceInfo.cpp
new file mode 100644
index 0000000..b8ec9acb
--- /dev/null
+++ b/third_party/WebKit/Source/modules/mediastream/SourceInfo.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL GOOGLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "modules/mediastream/SourceInfo.h"
+
+#include "wtf/text/WTFString.h"
+
+namespace blink {
+
+SourceInfo* SourceInfo::create(const WebSourceInfo& webSourceInfo) {
+  DCHECK(!webSourceInfo.isNull());
+  return new SourceInfo(webSourceInfo);
+}
+
+SourceInfo::SourceInfo(const WebSourceInfo& webSourceInfo)
+    : m_webSourceInfo(webSourceInfo) {}
+
+String SourceInfo::id() const {
+  return m_webSourceInfo.id();
+}
+
+String SourceInfo::kind() const {
+  switch (m_webSourceInfo.kind()) {
+    case WebSourceInfo::SourceKindAudio:
+      return "audio";
+    case WebSourceInfo::SourceKindVideo:
+      return "video";
+    case WebSourceInfo::SourceKindNone:
+      return "none";
+  }
+
+  NOTREACHED();
+  return String();
+}
+
+String SourceInfo::label() const {
+  return m_webSourceInfo.label();
+}
+
+String SourceInfo::facing() const {
+  switch (m_webSourceInfo.facing()) {
+    case WebSourceInfo::VideoFacingModeNone:
+      return String();
+    case WebSourceInfo::VideoFacingModeUser:
+      return "user";
+    case WebSourceInfo::VideoFacingModeEnvironment:
+      return "environment";
+  }
+
+  NOTREACHED();
+  return String();
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/modules/mediastream/SourceInfo.h b/third_party/WebKit/Source/modules/mediastream/SourceInfo.h
new file mode 100644
index 0000000..f6a92be
--- /dev/null
+++ b/third_party/WebKit/Source/modules/mediastream/SourceInfo.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL GOOGLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SourceInfo_h
+#define SourceInfo_h
+
+#include "bindings/core/v8/ScriptWrappable.h"
+#include "public/platform/WebSourceInfo.h"
+#include "wtf/Vector.h"
+
+namespace blink {
+
+class SourceInfo final : public GarbageCollectedFinalized<SourceInfo>,
+                         public ScriptWrappable {
+  DEFINE_WRAPPERTYPEINFO();
+
+ public:
+  static SourceInfo* create(const WebSourceInfo&);
+
+  String id() const;
+  String kind() const;
+  String label() const;
+  String facing() const;
+
+  DEFINE_INLINE_TRACE() {}
+
+ private:
+  explicit SourceInfo(const WebSourceInfo&);
+
+  WebSourceInfo m_webSourceInfo;
+};
+
+typedef HeapVector<Member<SourceInfo>> SourceInfoVector;
+
+}  // namespace blink
+
+#endif  // SourceInfo_h
diff --git a/third_party/WebKit/Source/modules/mediastream/SourceInfo.idl b/third_party/WebKit/Source/modules/mediastream/SourceInfo.idl
new file mode 100644
index 0000000..15a0e2e
--- /dev/null
+++ b/third_party/WebKit/Source/modules/mediastream/SourceInfo.idl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL GOOGLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// TODO(guidou): Remove MediaStreamTrack.getSources(). https://crbug.com/649710
+[
+    NoInterfaceObject
+] interface SourceInfo {
+    readonly attribute DOMString id;
+    readonly attribute DOMString kind;
+    readonly attribute DOMString label;
+    readonly attribute DOMString facing;
+};
diff --git a/third_party/WebKit/Source/modules/mediastream/UserMediaClient.h b/third_party/WebKit/Source/modules/mediastream/UserMediaClient.h
index 70b8fe1..43e5f19 100644
--- a/third_party/WebKit/Source/modules/mediastream/UserMediaClient.h
+++ b/third_party/WebKit/Source/modules/mediastream/UserMediaClient.h
@@ -34,6 +34,7 @@
 #include "modules/ModulesExport.h"
 #include "modules/mediastream/MediaDevicesRequest.h"
 #include "modules/mediastream/UserMediaRequest.h"
+#include "platform/mediastream/MediaStreamTrackSourcesRequest.h"
 #include "wtf/Allocator.h"
 
 namespace blink {
@@ -48,6 +49,7 @@
   virtual void requestUserMedia(UserMediaRequest*) = 0;
   virtual void cancelUserMediaRequest(UserMediaRequest*) = 0;
   virtual void requestMediaDevices(MediaDevicesRequest*) = 0;
+  virtual void requestSources(MediaStreamTrackSourcesRequest*) = 0;
   virtual void setMediaDeviceChangeObserver(MediaDevices*) = 0;
   virtual ~UserMediaClient() {}
 };
diff --git a/third_party/WebKit/Source/modules/mediastream/UserMediaController.h b/third_party/WebKit/Source/modules/mediastream/UserMediaController.h
index 6ec50e82..2d75eea 100644
--- a/third_party/WebKit/Source/modules/mediastream/UserMediaController.h
+++ b/third_party/WebKit/Source/modules/mediastream/UserMediaController.h
@@ -49,6 +49,7 @@
   void requestUserMedia(UserMediaRequest*);
   void cancelUserMediaRequest(UserMediaRequest*);
   void requestMediaDevices(MediaDevicesRequest*);
+  void requestSources(MediaStreamTrackSourcesRequest*);
   void setMediaDeviceChangeObserver(MediaDevices*);
 
   static const char* supplementName();
@@ -77,6 +78,11 @@
   m_client->requestMediaDevices(request);
 }
 
+inline void UserMediaController::requestSources(
+    MediaStreamTrackSourcesRequest* request) {
+  m_client->requestSources(request);
+}
+
 inline void UserMediaController::setMediaDeviceChangeObserver(
     MediaDevices* observer) {
   m_client->setMediaDeviceChangeObserver(observer);
diff --git a/third_party/WebKit/Source/modules/modules_idl_files.gni b/third_party/WebKit/Source/modules/modules_idl_files.gni
index 07b2c77..6fe5468d 100644
--- a/third_party/WebKit/Source/modules/modules_idl_files.gni
+++ b/third_party/WebKit/Source/modules/modules_idl_files.gni
@@ -159,9 +159,11 @@
                     "mediastream/MediaStreamEvent.idl",
                     "mediastream/MediaStreamTrack.idl",
                     "mediastream/MediaStreamTrackEvent.idl",
+                    "mediastream/MediaStreamTrackSourcesCallback.idl",
                     "mediastream/NavigatorUserMediaError.idl",
                     "mediastream/NavigatorUserMediaErrorCallback.idl",
                     "mediastream/NavigatorUserMediaSuccessCallback.idl",
+                    "mediastream/SourceInfo.idl",
                     "netinfo/NetworkInformation.idl",
                     "nfc/MessageCallback.idl",
                     "nfc/NFC.idl",
diff --git a/third_party/WebKit/Source/modules/speech/SpeechSynthesisUtterance.idl b/third_party/WebKit/Source/modules/speech/SpeechSynthesisUtterance.idl
index 8a052790..1021a743 100644
--- a/third_party/WebKit/Source/modules/speech/SpeechSynthesisUtterance.idl
+++ b/third_party/WebKit/Source/modules/speech/SpeechSynthesisUtterance.idl
@@ -23,6 +23,8 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+// https://dvcs.w3.org/hg/speech-api/raw-file/tip/webspeechapi.html#tts-section
+
 [
     Constructor(optional DOMString text = null),
     ConstructorCallWith=ExecutionContext,
@@ -30,7 +32,7 @@
 ] interface SpeechSynthesisUtterance : EventTarget {
     attribute DOMString text;
     attribute DOMString lang;
-    [LegacyInterfaceTypeChecking] attribute SpeechSynthesisVoice voice;
+    attribute SpeechSynthesisVoice? voice;
     attribute float volume;
     attribute float rate;
     attribute float pitch;
diff --git a/third_party/WebKit/Source/modules/vr/VRController.cpp b/third_party/WebKit/Source/modules/vr/VRController.cpp
index 6fa41fa..2092157f 100644
--- a/third_party/WebKit/Source/modules/vr/VRController.cpp
+++ b/third_party/WebKit/Source/modules/vr/VRController.cpp
@@ -18,10 +18,15 @@
 VRController::VRController(NavigatorVR* navigatorVR)
     : ContextLifecycleObserver(navigatorVR->document()),
       m_navigatorVR(navigatorVR),
+      m_displaySynced(false),
       m_binding(this) {
   navigatorVR->document()->frame()->interfaceProvider()->getInterface(
       mojo::GetProxy(&m_service));
-  m_service->SetClient(m_binding.CreateInterfacePtrAndBind());
+  m_service->SetClient(
+      m_binding.CreateInterfacePtrAndBind(),
+      convertToBaseCallback(
+          WTF::bind(&VRController::onDisplaysSynced, wrapPersistent(this))));
+  ThreadState::current()->registerPreFinalizer(this);
 }
 
 VRController::~VRController() {}
@@ -34,187 +39,72 @@
     return;
   }
 
+  // If we've previously synced the VRDisplays just return the current list.
+  if (m_displaySynced) {
+    resolver->resolve(m_displays);
+    return;
+  }
+
+  // Otherwise we're still waiting for the full list of displays to be populated
+  // so queue up the promise for resolution when onDisplaysSynced is called.
   m_pendingGetDevicesCallbacks.append(
-      WTF::wrapUnique(new VRGetDevicesCallback(resolver)));
-  m_service->GetDisplays(convertToBaseCallback(
-      WTF::bind(&VRController::onGetDisplays, wrapPersistent(this))));
+      wrapUnique(new VRGetDevicesCallback(resolver)));
 }
 
-device::blink::VRPosePtr VRController::getPose(unsigned index) {
-  if (!m_service)
-    return nullptr;
+// Each time a new VRDisplay is connected we'll recieve a VRDisplayPtr for it
+// here. Upon calling SetClient in the constructor we should receive one call
+// for each VRDisplay that was already connected at the time.
+void VRController::OnDisplayConnected(
+    device::mojom::blink::VRDisplayPtr display,
+    device::mojom::blink::VRDisplayClientRequest request,
+    device::mojom::blink::VRDisplayInfoPtr displayInfo) {
+  VRDisplay* vrDisplay =
+      new VRDisplay(m_navigatorVR, std::move(display), std::move(request));
+  vrDisplay->update(displayInfo);
+  vrDisplay->onDisplayConnected();
+  m_displays.append(vrDisplay);
 
-  device::blink::VRPosePtr pose;
-  m_service->GetPose(index, &pose);
-  return pose;
-}
-
-void VRController::resetPose(unsigned index) {
-  if (!m_service)
-    return;
-
-  m_service->ResetPose(index);
-}
-
-void VRController::requestPresent(ScriptPromiseResolver* resolver,
-                                  unsigned index,
-                                  bool secureOrigin) {
-  if (!m_service) {
-    DOMException* exception = DOMException::create(
-        InvalidStateError, "The service is no longer active.");
-    resolver->reject(exception);
-    ReportPresentationResult(PresentationResult::ServiceInactive);
-    return;
-  }
-
-  m_service->RequestPresent(
-      index, secureOrigin,
-      convertToBaseCallback(WTF::bind(&VRController::onPresentComplete,
-                                      wrapPersistent(this),
-                                      wrapPersistent(resolver), index)));
-}
-
-void VRController::exitPresent(unsigned index) {
-  if (!m_service)
-    return;
-
-  m_service->ExitPresent(index);
-}
-
-void VRController::submitFrame(unsigned index, device::blink::VRPosePtr pose) {
-  if (!m_service)
-    return;
-
-  m_service->SubmitFrame(index, std::move(pose));
-}
-
-void VRController::updateLayerBounds(
-    unsigned index,
-    device::blink::VRLayerBoundsPtr leftBounds,
-    device::blink::VRLayerBoundsPtr rightBounds) {
-  if (!m_service)
-    return;
-
-  m_service->UpdateLayerBounds(index, std::move(leftBounds),
-                               std::move(rightBounds));
-}
-
-VRDisplay* VRController::createOrUpdateDisplay(
-    const device::blink::VRDisplayPtr& display) {
-  VRDisplay* vrDisplay = getDisplayForIndex(display->index);
-  if (!vrDisplay) {
-    vrDisplay = new VRDisplay(m_navigatorVR);
-    m_displays.append(vrDisplay);
-  }
-
-  vrDisplay->update(display);
-  return vrDisplay;
-}
-
-VRDisplayVector VRController::updateDisplays(
-    mojo::WTFArray<device::blink::VRDisplayPtr> displays) {
-  VRDisplayVector vrDisplays;
-
-  for (const auto& display : displays.PassStorage()) {
-    VRDisplay* vrDisplay = createOrUpdateDisplay(display);
-    vrDisplays.append(vrDisplay);
-  }
-
-  return vrDisplays;
-}
-
-VRDisplay* VRController::getDisplayForIndex(unsigned index) {
-  VRDisplay* display;
-  for (size_t i = 0; i < m_displays.size(); ++i) {
-    display = m_displays[i];
-    if (display->displayId() == index) {
-      return display;
-    }
-  }
-
-  return 0;
-}
-
-void VRController::onGetDisplays(
-    mojo::WTFArray<device::blink::VRDisplayPtr> displays) {
-  VRDisplayVector outDisplays = updateDisplays(std::move(displays));
-
-  std::unique_ptr<VRGetDevicesCallback> callback =
-      m_pendingGetDevicesCallbacks.takeFirst();
-  if (!callback)
-    return;
-
-  callback->onSuccess(outDisplays);
-}
-
-void VRController::onPresentComplete(ScriptPromiseResolver* resolver,
-                                     unsigned index,
-                                     bool success) {
-  VRDisplay* vrDisplay = getDisplayForIndex(index);
-  if (!vrDisplay) {
-    DOMException* exception =
-        DOMException::create(InvalidStateError, "VRDisplay not found.");
-    resolver->reject(exception);
-    ReportPresentationResult(PresentationResult::VRDisplayNotFound);
-    return;
-  }
-
-  if (success) {
-    vrDisplay->beginPresent(resolver);
-  } else {
-    vrDisplay->forceExitPresent();
-    DOMException* exception = DOMException::create(
-        NotAllowedError, "Presentation request was denied.");
-    ReportPresentationResult(PresentationResult::RequestDenied);
-    resolver->reject(exception);
+  if (m_displays.size() == m_numberOfSyncedDisplays) {
+    m_displaySynced = true;
+    onGetDisplays();
   }
 }
 
-void VRController::OnDisplayChanged(device::blink::VRDisplayPtr display) {
-  VRDisplay* vrDisplay = getDisplayForIndex(display->index);
-  if (!vrDisplay)
-    return;
-
-  vrDisplay->update(display);
+// Called when the VRService has called OnDisplayConnected for all active
+// VRDisplays.
+void VRController::onDisplaysSynced(unsigned numberOfDisplays) {
+  m_numberOfSyncedDisplays = numberOfDisplays;
+  if (m_numberOfSyncedDisplays == m_displays.size()) {
+    m_displaySynced = true;
+    onGetDisplays();
+  }
 }
 
-void VRController::OnExitPresent(unsigned index) {
-  VRDisplay* vrDisplay = getDisplayForIndex(index);
-  if (vrDisplay)
-    vrDisplay->forceExitPresent();
-}
-
-void VRController::OnDisplayConnected(device::blink::VRDisplayPtr display) {
-  VRDisplay* vrDisplay = createOrUpdateDisplay(display);
-  if (!vrDisplay)
-    return;
-
-  m_navigatorVR->fireVREvent(VRDisplayEvent::create(
-      EventTypeNames::vrdisplayconnect, true, false, vrDisplay, "connect"));
-}
-
-void VRController::OnDisplayDisconnected(unsigned index) {
-  VRDisplay* vrDisplay = getDisplayForIndex(index);
-  if (!vrDisplay)
-    return;
-
-  vrDisplay->disconnected();
-
-  m_navigatorVR->fireVREvent(
-      VRDisplayEvent::create(EventTypeNames::vrdisplaydisconnect, true, false,
-                             vrDisplay, "disconnect"));
+void VRController::onGetDisplays() {
+  while (!m_pendingGetDevicesCallbacks.isEmpty()) {
+    std::unique_ptr<VRGetDevicesCallback> callback =
+        m_pendingGetDevicesCallbacks.takeFirst();
+    callback->onSuccess(m_displays);
+  }
 }
 
 void VRController::contextDestroyed() {
-  // If the document context was destroyed, shut down the client connection
-  // and never call the mojo service again.
-  m_binding.Close();
-  m_service.reset();
-
+  dispose();
   // The context is not automatically cleared, so do it manually.
   ContextLifecycleObserver::clearContext();
 }
 
+void VRController::dispose() {
+  // If the document context was destroyed, shut down the client connection
+  // and never call the mojo service again.
+  m_service.reset();
+  m_binding.Close();
+
+  // Shutdown all displays' message pipe
+  for (size_t i = 0; i < m_displays.size(); ++i)
+    m_displays[i]->dispose();
+}
+
 DEFINE_TRACE(VRController) {
   visitor->trace(m_navigatorVR);
   visitor->trace(m_displays);
diff --git a/third_party/WebKit/Source/modules/vr/VRController.h b/third_party/WebKit/Source/modules/vr/VRController.h
index 9c8b5b8..f7caf5f 100644
--- a/third_party/WebKit/Source/modules/vr/VRController.h
+++ b/third_party/WebKit/Source/modules/vr/VRController.h
@@ -21,54 +21,41 @@
 class VRGetDevicesCallback;
 
 class VRController final : public GarbageCollectedFinalized<VRController>,
-                           public device::blink::VRServiceClient,
+                           public device::mojom::blink::VRServiceClient,
                            public ContextLifecycleObserver {
   USING_GARBAGE_COLLECTED_MIXIN(VRController);
   WTF_MAKE_NONCOPYABLE(VRController);
+  USING_PRE_FINALIZER(VRController, dispose);
 
  public:
   VRController(NavigatorVR*);
   virtual ~VRController();
 
-  // VRService.
   void getDisplays(ScriptPromiseResolver*);
-  device::blink::VRPosePtr getPose(unsigned index);
-  void resetPose(unsigned index);
-  void requestPresent(ScriptPromiseResolver*,
-                      unsigned index,
-                      bool secureOrigin);
-  void exitPresent(unsigned index);
-  void submitFrame(unsigned index, device::blink::VRPosePtr);
-  void updateLayerBounds(unsigned index,
-                         device::blink::VRLayerBoundsPtr leftBounds,
-                         device::blink::VRLayerBoundsPtr rightBounds);
 
-  VRDisplay* createOrUpdateDisplay(const device::blink::VRDisplayPtr&);
-  VRDisplayVector updateDisplays(mojo::WTFArray<device::blink::VRDisplayPtr>);
-  VRDisplay* getDisplayForIndex(unsigned index);
+  void OnDisplayConnected(device::mojom::blink::VRDisplayPtr,
+                          device::mojom::blink::VRDisplayClientRequest,
+                          device::mojom::blink::VRDisplayInfoPtr) override;
 
   DECLARE_VIRTUAL_TRACE();
 
  private:
-  // Binding callbacks.
-  void onGetDisplays(mojo::WTFArray<device::blink::VRDisplayPtr>);
-  void onPresentComplete(ScriptPromiseResolver*, unsigned index, bool success);
-
-  // VRServiceClient.
-  void OnDisplayChanged(device::blink::VRDisplayPtr) override;
-  void OnExitPresent(unsigned index) override;
-  void OnDisplayConnected(device::blink::VRDisplayPtr) override;
-  void OnDisplayDisconnected(unsigned) override;
+  void onDisplaysSynced(unsigned);
+  void onGetDisplays();
 
   // ContextLifecycleObserver.
   void contextDestroyed() override;
+  void dispose();
 
   Member<NavigatorVR> m_navigatorVR;
   VRDisplayVector m_displays;
 
+  bool m_displaySynced;
+  unsigned m_numberOfSyncedDisplays;
+
   Deque<std::unique_ptr<VRGetDevicesCallback>> m_pendingGetDevicesCallbacks;
-  device::blink::VRServicePtr m_service;
-  mojo::Binding<device::blink::VRServiceClient> m_binding;
+  device::mojom::blink::VRServicePtr m_service;
+  mojo::Binding<device::mojom::blink::VRServiceClient> m_binding;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/vr/VRDisplay.cpp b/third_party/WebKit/Source/modules/vr/VRDisplay.cpp
index 1480df67..0a7c745 100644
--- a/third_party/WebKit/Source/modules/vr/VRDisplay.cpp
+++ b/third_party/WebKit/Source/modules/vr/VRDisplay.cpp
@@ -57,9 +57,10 @@
 
 }  // namespace
 
-VRDisplay::VRDisplay(NavigatorVR* navigatorVR)
+VRDisplay::VRDisplay(NavigatorVR* navigatorVR,
+                     device::mojom::blink::VRDisplayPtr display,
+                     device::mojom::blink::VRDisplayClientRequest request)
     : m_navigatorVR(navigatorVR),
-      m_displayId(0),
       m_isConnected(false),
       m_isPresenting(false),
       m_canUpdateFramePose(true),
@@ -70,7 +71,11 @@
       m_depthFar(10000.0),
       m_fullscreenCheckTimer(this, &VRDisplay::onFullscreenCheck),
       m_animationCallbackRequested(false),
-      m_inAnimationFrame(false) {}
+      m_inAnimationFrame(false),
+      m_display(std::move(display)),
+      m_binding(this, std::move(request)) {
+  ThreadState::current()->registerPreFinalizer(this);
+}
 
 VRDisplay::~VRDisplay() {}
 
@@ -78,7 +83,7 @@
   return m_navigatorVR->controller();
 }
 
-void VRDisplay::update(const device::blink::VRDisplayPtr& display) {
+void VRDisplay::update(const device::mojom::blink::VRDisplayInfoPtr& display) {
   m_displayId = display->index;
   m_displayName = display->displayName;
   m_isConnected = true;
@@ -133,14 +138,21 @@
 
 void VRDisplay::updatePose() {
   if (m_canUpdateFramePose) {
-    m_framePose = controller()->getPose(m_displayId);
+    if (!m_display)
+      return;
+    device::mojom::blink::VRPosePtr pose;
+    m_display->GetPose(&pose);
+    m_framePose = std::move(pose);
     if (m_isPresenting)
       m_canUpdateFramePose = false;
   }
 }
 
 void VRDisplay::resetPose() {
-  controller()->resetPose(m_displayId);
+  if (!m_display)
+    return;
+
+  m_display->ResetPose();
 }
 
 VREyeParameters* VRDisplay::getEyeParameters(const String& whichEye) {
@@ -299,7 +311,16 @@
 
   if (firstPresent) {
     bool secureContext = scriptState->getExecutionContext()->isSecureContext();
-    controller()->requestPresent(resolver, m_displayId, secureContext);
+    if (!m_display) {
+      DOMException* exception = DOMException::create(
+          InvalidStateError, "The service is no longer active.");
+      resolver->reject(exception);
+      return promise;
+    }
+    m_display->RequestPresent(
+        secureContext, convertToBaseCallback(WTF::bind(
+                           &VRDisplay::onPresentComplete, wrapPersistent(this),
+                           wrapPersistent(resolver))));
   } else {
     updateLayerBounds();
     resolver->resolve();
@@ -309,6 +330,18 @@
   return promise;
 }
 
+void VRDisplay::onPresentComplete(ScriptPromiseResolver* resolver,
+                                  bool success) {
+  if (success) {
+    this->beginPresent(resolver);
+  } else {
+    this->forceExitPresent();
+    DOMException* exception = DOMException::create(
+        NotAllowedError, "Presentation request was denied.");
+    resolver->reject(exception);
+  }
+}
+
 ScriptPromise VRDisplay::exitPresent(ScriptState* scriptState) {
   ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
   ScriptPromise promise = resolver->promise();
@@ -321,7 +354,13 @@
     return promise;
   }
 
-  controller()->exitPresent(m_displayId);
+  if (!m_display) {
+    DOMException* exception =
+        DOMException::create(InvalidStateError, "VRService is not available.");
+    resolver->reject(exception);
+    return promise;
+  }
+  m_display->ExitPresent();
 
   resolver->resolve();
 
@@ -368,11 +407,14 @@
 }
 
 void VRDisplay::updateLayerBounds() {
+  if (!m_display)
+    return;
+
   // Set up the texture bounds for the provided layer
-  device::blink::VRLayerBoundsPtr leftBounds =
-      device::blink::VRLayerBounds::New();
-  device::blink::VRLayerBoundsPtr rightBounds =
-      device::blink::VRLayerBounds::New();
+  device::mojom::blink::VRLayerBoundsPtr leftBounds =
+      device::mojom::blink::VRLayerBounds::New();
+  device::mojom::blink::VRLayerBoundsPtr rightBounds =
+      device::mojom::blink::VRLayerBounds::New();
 
   if (m_layer.leftBounds().size() == 4) {
     leftBounds->left = m_layer.leftBounds()[0];
@@ -400,8 +442,7 @@
     rightBounds->height = 1.0f;
   }
 
-  controller()->updateLayerBounds(m_displayId, std::move(leftBounds),
-                                  std::move(rightBounds));
+  m_display->UpdateLayerBounds(std::move(leftBounds), std::move(rightBounds));
 }
 
 HeapVector<VRLayer> VRDisplay::getLayers() {
@@ -415,6 +456,9 @@
 }
 
 void VRDisplay::submitFrame() {
+  if (!m_display)
+    return;
+
   Document* doc = m_navigatorVR->document();
   if (!m_isPresenting) {
     if (doc) {
@@ -468,10 +512,29 @@
   m_renderingContext->restoreColorMask();
   m_renderingContext->restoreClearColor();
 
-  controller()->submitFrame(m_displayId, m_framePose.Clone());
+  m_display->SubmitFrame(m_framePose.Clone());
   m_canUpdateFramePose = true;
 }
 
+void VRDisplay::OnDisplayChanged(
+    device::mojom::blink::VRDisplayInfoPtr display) {
+  update(display);
+}
+
+void VRDisplay::OnExitPresent() {
+  forceExitPresent();
+}
+
+void VRDisplay::onDisplayConnected() {
+  m_navigatorVR->fireVREvent(VRDisplayEvent::create(
+      EventTypeNames::vrdisplayconnect, true, false, this, "connect"));
+}
+
+void VRDisplay::onDisplayDisconnected() {
+  m_navigatorVR->fireVREvent(VRDisplayEvent::create(
+      EventTypeNames::vrdisplaydisconnect, true, false, this, "disconnect"));
+}
+
 void VRDisplay::onFullscreenCheck(TimerBase*) {
   // TODO: This is a temporary measure to track if fullscreen mode has been
   // exited by the UA. If so we need to end VR presentation. Soon we won't
@@ -482,7 +545,9 @@
     m_isPresenting = false;
     m_navigatorVR->fireVRDisplayPresentChange(this);
     m_fullscreenCheckTimer.stop();
-    controller()->exitPresent(m_displayId);
+    if (!m_display)
+      return;
+    m_display->ExitPresent();
   }
 }
 
@@ -494,6 +559,10 @@
   return *m_scriptedAnimationController;
 }
 
+void VRDisplay::dispose() {
+  m_binding.Close();
+}
+
 DEFINE_TRACE(VRDisplay) {
   visitor->trace(m_navigatorVR);
   visitor->trace(m_capabilities);
diff --git a/third_party/WebKit/Source/modules/vr/VRDisplay.h b/third_party/WebKit/Source/modules/vr/VRDisplay.h
index 9b12cfe..8c69834f 100644
--- a/third_party/WebKit/Source/modules/vr/VRDisplay.h
+++ b/third_party/WebKit/Source/modules/vr/VRDisplay.h
@@ -11,6 +11,7 @@
 #include "device/vr/vr_service.mojom-blink.h"
 #include "modules/vr/VRDisplayCapabilities.h"
 #include "modules/vr/VRLayer.h"
+#include "mojo/public/cpp/bindings/binding.h"
 #include "platform/Timer.h"
 #include "platform/heap/Handle.h"
 #include "public/platform/WebGraphicsContext3DProvider.h"
@@ -38,8 +39,10 @@
 enum VREye { VREyeNone, VREyeLeft, VREyeRight };
 
 class VRDisplay final : public GarbageCollectedFinalized<VRDisplay>,
+                        public device::mojom::blink::VRDisplayClient,
                         public ScriptWrappable {
   DEFINE_WRAPPERTYPEINFO();
+  USING_PRE_FINALIZER(VRDisplay, dispose);
 
  public:
   ~VRDisplay();
@@ -81,9 +84,11 @@
  protected:
   friend class VRController;
 
-  VRDisplay(NavigatorVR*);
+  VRDisplay(NavigatorVR*,
+            device::mojom::blink::VRDisplayPtr,
+            device::mojom::blink::VRDisplayClientRequest);
 
-  void update(const device::blink::VRDisplayPtr&);
+  void update(const device::mojom::blink::VRDisplayInfoPtr&);
 
   void updatePose();
 
@@ -97,6 +102,14 @@
 
  private:
   void onFullscreenCheck(TimerBase*);
+  void onPresentComplete(ScriptPromiseResolver*, bool);
+
+  void onDisplayConnected();
+  void onDisplayDisconnected();
+
+  // VRDisplayClient
+  void OnDisplayChanged(device::mojom::blink::VRDisplayInfoPtr) override;
+  void OnExitPresent() override;
 
   ScriptedAnimationController& ensureScriptedAnimationController(Document*);
 
@@ -111,11 +124,13 @@
   Member<VRStageParameters> m_stageParameters;
   Member<VREyeParameters> m_eyeParametersLeft;
   Member<VREyeParameters> m_eyeParametersRight;
-  device::blink::VRPosePtr m_framePose;
+  device::mojom::blink::VRPosePtr m_framePose;
   VRLayer m_layer;
   double m_depthNear;
   double m_depthFar;
 
+  void dispose();
+
   Timer<VRDisplay> m_fullscreenCheckTimer;
   gpu::gles2::GLES2Interface* m_contextGL;
   Member<WebGLRenderingContextBase> m_renderingContext;
@@ -123,6 +138,10 @@
   Member<ScriptedAnimationController> m_scriptedAnimationController;
   bool m_animationCallbackRequested;
   bool m_inAnimationFrame;
+
+  device::mojom::blink::VRDisplayPtr m_display;
+
+  mojo::Binding<device::mojom::blink::VRDisplayClient> m_binding;
 };
 
 using VRDisplayVector = HeapVector<Member<VRDisplay>>;
diff --git a/third_party/WebKit/Source/modules/vr/VREyeParameters.cpp b/third_party/WebKit/Source/modules/vr/VREyeParameters.cpp
index da88cb1..5a2640d 100644
--- a/third_party/WebKit/Source/modules/vr/VREyeParameters.cpp
+++ b/third_party/WebKit/Source/modules/vr/VREyeParameters.cpp
@@ -14,7 +14,7 @@
 }
 
 void VREyeParameters::update(
-    const device::blink::VREyeParametersPtr& eyeParameters) {
+    const device::mojom::blink::VREyeParametersPtr& eyeParameters) {
   m_offset->data()[0] = eyeParameters->offset[0];
   m_offset->data()[1] = eyeParameters->offset[1];
   m_offset->data()[2] = eyeParameters->offset[2];
diff --git a/third_party/WebKit/Source/modules/vr/VREyeParameters.h b/third_party/WebKit/Source/modules/vr/VREyeParameters.h
index 9d0e524f..6e34b5a 100644
--- a/third_party/WebKit/Source/modules/vr/VREyeParameters.h
+++ b/third_party/WebKit/Source/modules/vr/VREyeParameters.h
@@ -29,7 +29,7 @@
   unsigned long renderWidth() const { return m_renderWidth; }
   unsigned long renderHeight() const { return m_renderHeight; }
 
-  void update(const device::blink::VREyeParametersPtr&);
+  void update(const device::mojom::blink::VREyeParametersPtr&);
 
   DECLARE_VIRTUAL_TRACE()
 
diff --git a/third_party/WebKit/Source/modules/vr/VRFrameData.cpp b/third_party/WebKit/Source/modules/vr/VRFrameData.cpp
index 879c25f..f2c447b 100644
--- a/third_party/WebKit/Source/modules/vr/VRFrameData.cpp
+++ b/third_party/WebKit/Source/modules/vr/VRFrameData.cpp
@@ -174,7 +174,7 @@
   m_pose = VRPose::create();
 }
 
-bool VRFrameData::update(const device::blink::VRPosePtr& pose,
+bool VRFrameData::update(const device::mojom::blink::VRPosePtr& pose,
                          VREyeParameters* leftEye,
                          VREyeParameters* rightEye,
                          float depthNear,
diff --git a/third_party/WebKit/Source/modules/vr/VRFrameData.h b/third_party/WebKit/Source/modules/vr/VRFrameData.h
index 8da93ba..ef5e3ab 100644
--- a/third_party/WebKit/Source/modules/vr/VRFrameData.h
+++ b/third_party/WebKit/Source/modules/vr/VRFrameData.h
@@ -40,7 +40,7 @@
   // Populate a the VRFrameData with a pose and the necessary eye parameters.
   // TODO(bajones): The full frame data should be provided by the VRService,
   // not computed here.
-  bool update(const device::blink::VRPosePtr&,
+  bool update(const device::mojom::blink::VRPosePtr&,
               VREyeParameters* leftEye,
               VREyeParameters* rightEye,
               float depthNear,
diff --git a/third_party/WebKit/Source/modules/vr/VRPose.cpp b/third_party/WebKit/Source/modules/vr/VRPose.cpp
index 6c49d5e..3775522 100644
--- a/third_party/WebKit/Source/modules/vr/VRPose.cpp
+++ b/third_party/WebKit/Source/modules/vr/VRPose.cpp
@@ -19,7 +19,7 @@
 
 VRPose::VRPose() {}
 
-void VRPose::setPose(const device::blink::VRPosePtr& state) {
+void VRPose::setPose(const device::mojom::blink::VRPosePtr& state) {
   if (state.is_null())
     return;
 
diff --git a/third_party/WebKit/Source/modules/vr/VRPose.h b/third_party/WebKit/Source/modules/vr/VRPose.h
index fc7d85d..1678d29 100644
--- a/third_party/WebKit/Source/modules/vr/VRPose.h
+++ b/third_party/WebKit/Source/modules/vr/VRPose.h
@@ -26,7 +26,7 @@
   DOMFloat32Array* angularAcceleration() const { return m_angularAcceleration; }
   DOMFloat32Array* linearAcceleration() const { return m_linearAcceleration; }
 
-  void setPose(const device::blink::VRPosePtr&);
+  void setPose(const device::mojom::blink::VRPosePtr&);
 
   DECLARE_VIRTUAL_TRACE();
 
diff --git a/third_party/WebKit/Source/modules/vr/VRStageParameters.cpp b/third_party/WebKit/Source/modules/vr/VRStageParameters.cpp
index dc13abf..597ab4ef 100644
--- a/third_party/WebKit/Source/modules/vr/VRStageParameters.cpp
+++ b/third_party/WebKit/Source/modules/vr/VRStageParameters.cpp
@@ -16,7 +16,7 @@
 }
 
 void VRStageParameters::update(
-    const device::blink::VRStageParametersPtr& stage) {
+    const device::mojom::blink::VRStageParametersPtr& stage) {
   m_standingTransform =
       DOMFloat32Array::create(&(stage->standingTransform.front()), 16);
   m_sizeX = stage->sizeX;
diff --git a/third_party/WebKit/Source/modules/vr/VRStageParameters.h b/third_party/WebKit/Source/modules/vr/VRStageParameters.h
index 4f411c7d..50534d3 100644
--- a/third_party/WebKit/Source/modules/vr/VRStageParameters.h
+++ b/third_party/WebKit/Source/modules/vr/VRStageParameters.h
@@ -27,7 +27,7 @@
   float sizeX() const { return m_sizeX; }
   float sizeZ() const { return m_sizeZ; }
 
-  void update(const device::blink::VRStageParametersPtr&);
+  void update(const device::mojom::blink::VRStageParametersPtr&);
 
   DECLARE_VIRTUAL_TRACE()
 
diff --git a/third_party/WebKit/Source/platform/BUILD.gn b/third_party/WebKit/Source/platform/BUILD.gn
index d30b517d..49933c0 100644
--- a/third_party/WebKit/Source/platform/BUILD.gn
+++ b/third_party/WebKit/Source/platform/BUILD.gn
@@ -524,6 +524,7 @@
     "exported/WebMediaStream.cpp",
     "exported/WebMediaStreamSource.cpp",
     "exported/WebMediaStreamTrack.cpp",
+    "exported/WebMediaStreamTrackSourcesRequest.cpp",
     "exported/WebMemoryCoordinator.cpp",
     "exported/WebMessagePortChannelClient.cpp",
     "exported/WebMixedContent.cpp",
@@ -553,6 +554,7 @@
     "exported/WebServiceWorkerProxy.cpp",
     "exported/WebServiceWorkerRequest.cpp",
     "exported/WebServiceWorkerResponse.cpp",
+    "exported/WebSourceInfo.cpp",
     "exported/WebSpeechSynthesisUtterance.cpp",
     "exported/WebSpeechSynthesisVoice.cpp",
     "exported/WebSpeechSynthesizerClientImpl.cpp",
@@ -1076,6 +1078,7 @@
     "mediastream/MediaStreamDescriptor.h",
     "mediastream/MediaStreamSource.cpp",
     "mediastream/MediaStreamSource.h",
+    "mediastream/MediaStreamTrackSourcesRequest.h",
     "mediastream/MediaStreamWebAudioSource.cpp",
     "mediastream/MediaStreamWebAudioSource.h",
     "mhtml/ArchiveResource.cpp",
diff --git a/third_party/WebKit/Source/platform/exported/WebMediaStreamTrackSourcesRequest.cpp b/third_party/WebKit/Source/platform/exported/WebMediaStreamTrackSourcesRequest.cpp
new file mode 100644
index 0000000..128fbe4
--- /dev/null
+++ b/third_party/WebKit/Source/platform/exported/WebMediaStreamTrackSourcesRequest.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL GOOGLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "public/platform/WebMediaStreamTrackSourcesRequest.h"
+
+#include "platform/mediastream/MediaStreamTrackSourcesRequest.h"
+#include "platform/weborigin/SecurityOrigin.h"
+#include "public/platform/WebSourceInfo.h"
+#include "wtf/text/WTFString.h"
+
+namespace blink {
+
+WebMediaStreamTrackSourcesRequest::WebMediaStreamTrackSourcesRequest(
+    MediaStreamTrackSourcesRequest* request)
+    : m_private(request) {}
+
+void WebMediaStreamTrackSourcesRequest::assign(
+    const WebMediaStreamTrackSourcesRequest& other) {
+  m_private = other.m_private;
+}
+
+void WebMediaStreamTrackSourcesRequest::reset() {
+  m_private.reset();
+}
+
+WebSecurityOrigin WebMediaStreamTrackSourcesRequest::origin() const {
+  ASSERT(m_private.get());
+  return m_private->origin();
+}
+
+void WebMediaStreamTrackSourcesRequest::requestSucceeded(
+    const WebVector<WebSourceInfo>& sourceInfos) const {
+  ASSERT(m_private.get());
+  m_private->requestSucceeded(sourceInfos);
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/platform/exported/WebSourceInfo.cpp b/third_party/WebKit/Source/platform/exported/WebSourceInfo.cpp
new file mode 100644
index 0000000..e5f6cdd
--- /dev/null
+++ b/third_party/WebKit/Source/platform/exported/WebSourceInfo.cpp
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL GOOGLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "public/platform/WebSourceInfo.h"
+
+#include "public/platform/WebString.h"
+#include "wtf/PassRefPtr.h"
+#include "wtf/RefCounted.h"
+
+namespace blink {
+
+class WebSourceInfoPrivate final : public RefCounted<WebSourceInfoPrivate> {
+ public:
+  static PassRefPtr<WebSourceInfoPrivate> create(
+      const WebString& id,
+      WebSourceInfo::SourceKind,
+      const WebString& label,
+      WebSourceInfo::VideoFacingMode);
+
+  const WebString& id() const { return m_id; }
+  WebSourceInfo::SourceKind kind() const { return m_kind; }
+  const WebString& label() const { return m_label; }
+  WebSourceInfo::VideoFacingMode facing() const { return m_facing; }
+
+ private:
+  WebSourceInfoPrivate(const WebString& id,
+                       WebSourceInfo::SourceKind,
+                       const WebString& label,
+                       WebSourceInfo::VideoFacingMode);
+
+  WebString m_id;
+  WebSourceInfo::SourceKind m_kind;
+  WebString m_label;
+  WebSourceInfo::VideoFacingMode m_facing;
+};
+
+PassRefPtr<WebSourceInfoPrivate> WebSourceInfoPrivate::create(
+    const WebString& id,
+    WebSourceInfo::SourceKind kind,
+    const WebString& label,
+    WebSourceInfo::VideoFacingMode facing) {
+  return adoptRef(new WebSourceInfoPrivate(id, kind, label, facing));
+}
+
+WebSourceInfoPrivate::WebSourceInfoPrivate(
+    const WebString& id,
+    WebSourceInfo::SourceKind kind,
+    const WebString& label,
+    WebSourceInfo::VideoFacingMode facing)
+    : m_id(id), m_kind(kind), m_label(label), m_facing(facing) {}
+
+void WebSourceInfo::assign(const WebSourceInfo& other) {
+  m_private = other.m_private;
+}
+
+void WebSourceInfo::reset() {
+  m_private.reset();
+}
+
+void WebSourceInfo::initialize(const WebString& id,
+                               WebSourceInfo::SourceKind kind,
+                               const WebString& label,
+                               WebSourceInfo::VideoFacingMode facing) {
+  m_private = WebSourceInfoPrivate::create(id, kind, label, facing);
+}
+
+WebString WebSourceInfo::id() const {
+  ASSERT(!m_private.isNull());
+  return m_private->id();
+}
+
+WebSourceInfo::SourceKind WebSourceInfo::kind() const {
+  ASSERT(!m_private.isNull());
+  return m_private->kind();
+}
+
+WebString WebSourceInfo::label() const {
+  ASSERT(!m_private.isNull());
+  return m_private->label();
+}
+
+WebSourceInfo::VideoFacingMode WebSourceInfo::facing() const {
+  ASSERT(!m_private.isNull());
+  return m_private->facing();
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/platform/mediastream/MediaStreamCenter.cpp b/third_party/WebKit/Source/platform/mediastream/MediaStreamCenter.cpp
index 869d179..b3aae6b3 100644
--- a/third_party/WebKit/Source/platform/mediastream/MediaStreamCenter.cpp
+++ b/third_party/WebKit/Source/platform/mediastream/MediaStreamCenter.cpp
@@ -32,6 +32,7 @@
 #include "platform/mediastream/MediaStreamCenter.h"
 
 #include "platform/mediastream/MediaStreamDescriptor.h"
+#include "platform/mediastream/MediaStreamTrackSourcesRequest.h"
 #include "platform/mediastream/MediaStreamWebAudioSource.h"
 #include "public/platform/Platform.h"
 #include "public/platform/WebAudioSourceProvider.h"
diff --git a/third_party/WebKit/Source/platform/mediastream/MediaStreamTrackSourcesRequest.h b/third_party/WebKit/Source/platform/mediastream/MediaStreamTrackSourcesRequest.h
new file mode 100644
index 0000000..37f351a
--- /dev/null
+++ b/third_party/WebKit/Source/platform/mediastream/MediaStreamTrackSourcesRequest.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL GOOGLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef MediaStreamTrackSourcesRequest_h
+#define MediaStreamTrackSourcesRequest_h
+
+#include "platform/heap/Handle.h"
+#include "public/platform/WebVector.h"
+#include "wtf/Forward.h"
+
+namespace blink {
+
+class SecurityOrigin;
+class WebSourceInfo;
+
+class MediaStreamTrackSourcesRequest
+    : public GarbageCollectedFinalized<MediaStreamTrackSourcesRequest> {
+ public:
+  virtual ~MediaStreamTrackSourcesRequest() {}
+
+  virtual PassRefPtr<SecurityOrigin> origin() = 0;
+  virtual void requestSucceeded(const WebVector<WebSourceInfo>&) = 0;
+
+  DEFINE_INLINE_VIRTUAL_TRACE() {}
+
+ protected:
+  MediaStreamTrackSourcesRequest() {}
+};
+
+}  // namespace blink
+
+#endif  // MediaStreamTrackSourcesRequest_h
diff --git a/third_party/WebKit/Source/web/UserMediaClientImpl.cpp b/third_party/WebKit/Source/web/UserMediaClientImpl.cpp
index 90f2662..185f7612 100644
--- a/third_party/WebKit/Source/web/UserMediaClientImpl.cpp
+++ b/third_party/WebKit/Source/web/UserMediaClientImpl.cpp
@@ -30,6 +30,7 @@
 
 #include "web/UserMediaClientImpl.h"
 
+#include "public/platform/WebMediaStreamTrackSourcesRequest.h"
 #include "public/web/WebFrameClient.h"
 #include "public/web/WebMediaDeviceChangeObserver.h"
 #include "public/web/WebMediaDevicesRequest.h"
@@ -58,6 +59,12 @@
     m_client->requestMediaDevices(request);
 }
 
+void UserMediaClientImpl::requestSources(
+    MediaStreamTrackSourcesRequest* request) {
+  if (m_client)
+    m_client->requestSources(request);
+}
+
 void UserMediaClientImpl::setMediaDeviceChangeObserver(MediaDevices* observer) {
   if (m_client)
     m_client->setMediaDeviceChangeObserver(
diff --git a/third_party/WebKit/Source/web/UserMediaClientImpl.h b/third_party/WebKit/Source/web/UserMediaClientImpl.h
index 36994c5..855ea71 100644
--- a/third_party/WebKit/Source/web/UserMediaClientImpl.h
+++ b/third_party/WebKit/Source/web/UserMediaClientImpl.h
@@ -52,6 +52,7 @@
   void requestUserMedia(UserMediaRequest*) override;
   void cancelUserMediaRequest(UserMediaRequest*) override;
   void requestMediaDevices(MediaDevicesRequest*) override;
+  void requestSources(MediaStreamTrackSourcesRequest*) override;
   void setMediaDeviceChangeObserver(MediaDevices*) override;
 
  private:
diff --git a/third_party/WebKit/Source/web/tests/NGInlineLayoutTest.cpp b/third_party/WebKit/Source/web/tests/NGInlineLayoutTest.cpp
index 0384a82..965c11e 100644
--- a/third_party/WebKit/Source/web/tests/NGInlineLayoutTest.cpp
+++ b/third_party/WebKit/Source/web/tests/NGInlineLayoutTest.cpp
@@ -14,10 +14,24 @@
 #include "web/tests/sim/SimRequest.h"
 #include "web/tests/sim/SimTest.h"
 #include "wtf/CurrentTime.h"
+#include "wtf/text/CharacterNames.h"
 
 namespace blink {
 
-class NGInlineLayoutTest : public SimTest {};
+class NGInlineLayoutTest : public SimTest {
+ public:
+  NGConstraintSpace* constraintSpaceForElement(LayoutNGBlockFlow* blockFlow) {
+    NGConstraintSpaceBuilder builder(
+        FromPlatformWritingMode(blockFlow->style()->getWritingMode()));
+    builder.SetAvailableSize(NGLogicalSize(LayoutUnit(), LayoutUnit()));
+    builder.SetPercentageResolutionSize(
+        NGLogicalSize(LayoutUnit(), LayoutUnit()));
+    NGConstraintSpace* constraintSpace = new NGConstraintSpace(
+        FromPlatformWritingMode(blockFlow->style()->getWritingMode()),
+        blockFlow->style()->direction(), builder.ToConstraintSpace());
+    return constraintSpace;
+  }
+};
 
 TEST_F(NGInlineLayoutTest, BlockWithSingleTextNode) {
   RuntimeEnabledFeatures::setLayoutNGEnabled(true);
@@ -33,15 +47,7 @@
 
   Element* target = document().getElementById("target");
   LayoutNGBlockFlow* blockFlow = toLayoutNGBlockFlow(target->layoutObject());
-
-  NGConstraintSpaceBuilder builder(
-      FromPlatformWritingMode(blockFlow->style()->getWritingMode()));
-  builder.SetAvailableSize(NGLogicalSize(LayoutUnit(), LayoutUnit()));
-  builder.SetPercentageResolutionSize(
-      NGLogicalSize(LayoutUnit(), LayoutUnit()));
-  NGConstraintSpace* constraintSpace = new NGConstraintSpace(
-      FromPlatformWritingMode(blockFlow->style()->getWritingMode()),
-      blockFlow->style()->direction(), builder.ToConstraintSpace());
+  NGConstraintSpace* constraintSpace = constraintSpaceForElement(blockFlow);
 
   NGInlineBox* inlineBox = new NGInlineBox(blockFlow->firstChild());
   NGInlineLayoutAlgorithm* layoutAlgorithm = new NGInlineLayoutAlgorithm(
@@ -54,4 +60,32 @@
   layoutAlgorithm->Layout(&fragment);
 }
 
+TEST_F(NGInlineLayoutTest, BlockWithTextAndAtomicInline) {
+  RuntimeEnabledFeatures::setLayoutNGEnabled(true);
+  RuntimeEnabledFeatures::setLayoutNGInlineEnabled(true);
+
+  SimRequest mainResource("https://example.com/", "text/html");
+  loadURL("https://example.com/");
+  mainResource.complete("<div id=\"target\">Hello <img>.</div>");
+
+  compositor().beginFrame();
+  ASSERT_FALSE(compositor().needsBeginFrame());
+
+  Element* target = document().getElementById("target");
+  LayoutNGBlockFlow* blockFlow = toLayoutNGBlockFlow(target->layoutObject());
+  NGConstraintSpace* constraintSpace = constraintSpaceForElement(blockFlow);
+
+  NGInlineBox* inlineBox = new NGInlineBox(blockFlow->firstChild());
+  NGInlineLayoutAlgorithm* layoutAlgorithm = new NGInlineLayoutAlgorithm(
+      blockFlow->style(), inlineBox, constraintSpace);
+
+  String expectedText("Hello ");
+  expectedText.append(objectReplacementCharacter);
+  expectedText.append(".");
+  EXPECT_EQ(expectedText, inlineBox->Text(0, 8));
+
+  NGPhysicalFragmentBase* fragment;
+  layoutAlgorithm->Layout(&fragment);
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/public/BUILD.gn b/third_party/WebKit/public/BUILD.gn
index ea70003..ec7c2622 100644
--- a/third_party/WebKit/public/BUILD.gn
+++ b/third_party/WebKit/public/BUILD.gn
@@ -285,6 +285,7 @@
     "platform/WebSize.h",
     "platform/WebSourceBuffer.h",
     "platform/WebSourceBufferClient.h",
+    "platform/WebSourceInfo.h",
     "platform/WebSpeechSynthesisUtterance.h",
     "platform/WebSpeechSynthesisVoice.h",
     "platform/WebSpeechSynthesizer.h",
diff --git a/third_party/WebKit/public/platform/WebMediaStreamTrackSourcesRequest.h b/third_party/WebKit/public/platform/WebMediaStreamTrackSourcesRequest.h
new file mode 100644
index 0000000..b84dcab
--- /dev/null
+++ b/third_party/WebKit/public/platform/WebMediaStreamTrackSourcesRequest.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL GOOGLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef WebMediaStreamTrackSourcesRequest_h
+#define WebMediaStreamTrackSourcesRequest_h
+
+#include "WebCommon.h"
+#include "WebNonCopyable.h"
+#include "WebPrivatePtr.h"
+#include "WebSecurityOrigin.h"
+#include "WebVector.h"
+
+namespace blink {
+
+class MediaStreamTrackSourcesRequest;
+class WebSourceInfo;
+
+class WebMediaStreamTrackSourcesRequest {
+ public:
+  WebMediaStreamTrackSourcesRequest() {}
+  WebMediaStreamTrackSourcesRequest(
+      const WebMediaStreamTrackSourcesRequest& other) {
+    assign(other);
+  }
+  ~WebMediaStreamTrackSourcesRequest() { reset(); }
+
+  WebMediaStreamTrackSourcesRequest& operator=(
+      const WebMediaStreamTrackSourcesRequest& other) {
+    assign(other);
+    return *this;
+  }
+
+  BLINK_PLATFORM_EXPORT void assign(const WebMediaStreamTrackSourcesRequest&);
+
+  BLINK_PLATFORM_EXPORT void reset();
+  bool isNull() const { return m_private.isNull(); }
+
+  BLINK_PLATFORM_EXPORT WebSecurityOrigin origin() const;
+  BLINK_PLATFORM_EXPORT void requestSucceeded(
+      const WebVector<WebSourceInfo>&) const;
+
+#if INSIDE_BLINK
+  BLINK_PLATFORM_EXPORT WebMediaStreamTrackSourcesRequest(
+      MediaStreamTrackSourcesRequest*);
+#endif
+
+ private:
+  WebPrivatePtr<MediaStreamTrackSourcesRequest> m_private;
+};
+
+}  // namespace blink
+
+#endif  // WebMediaStreamTrackSourcesRequest_h
diff --git a/third_party/WebKit/public/platform/WebSourceInfo.h b/third_party/WebKit/public/platform/WebSourceInfo.h
new file mode 100644
index 0000000..7bf922e
--- /dev/null
+++ b/third_party/WebKit/public/platform/WebSourceInfo.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL GOOGLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef WebSourceInfo_h
+#define WebSourceInfo_h
+
+#include "WebCommon.h"
+#include "WebNonCopyable.h"
+#include "WebPrivatePtr.h"
+#include "WebString.h"
+
+namespace blink {
+
+class WebSourceInfoPrivate;
+
+class WebSourceInfo {
+ public:
+  enum SourceKind { SourceKindNone, SourceKindAudio, SourceKindVideo };
+
+  enum VideoFacingMode {
+    VideoFacingModeNone,
+    VideoFacingModeUser,
+    VideoFacingModeEnvironment
+  };
+
+  WebSourceInfo() {}
+  WebSourceInfo(const WebSourceInfo& other) { assign(other); }
+  ~WebSourceInfo() { reset(); }
+
+  WebSourceInfo& operator=(const WebSourceInfo& other) {
+    assign(other);
+    return *this;
+  }
+
+  BLINK_PLATFORM_EXPORT void assign(const WebSourceInfo&);
+
+  BLINK_PLATFORM_EXPORT void initialize(const WebString& id,
+                                        SourceKind,
+                                        const WebString& label,
+                                        VideoFacingMode);
+  BLINK_PLATFORM_EXPORT void reset();
+  bool isNull() const { return m_private.isNull(); }
+
+  BLINK_PLATFORM_EXPORT WebString id() const;
+  BLINK_PLATFORM_EXPORT SourceKind kind() const;
+  BLINK_PLATFORM_EXPORT WebString label() const;
+  BLINK_PLATFORM_EXPORT VideoFacingMode facing() const;
+
+ private:
+  WebPrivatePtr<WebSourceInfoPrivate> m_private;
+};
+
+}  // namespace blink
+
+#endif  // WebSourceInfo_h
diff --git a/third_party/WebKit/public/web/WebUserMediaClient.h b/third_party/WebKit/public/web/WebUserMediaClient.h
index 1c7ba63..2a50557 100644
--- a/third_party/WebKit/public/web/WebUserMediaClient.h
+++ b/third_party/WebKit/public/web/WebUserMediaClient.h
@@ -34,6 +34,7 @@
 namespace blink {
 
 class WebMediaDevicesRequest;
+class WebMediaStreamTrackSourcesRequest;
 class WebUserMediaRequest;
 class WebMediaDeviceChangeObserver;
 
@@ -44,6 +45,7 @@
   virtual void requestUserMedia(const WebUserMediaRequest&) = 0;
   virtual void cancelUserMediaRequest(const WebUserMediaRequest&) = 0;
   virtual void requestMediaDevices(const WebMediaDevicesRequest&) = 0;
+  virtual void requestSources(const WebMediaStreamTrackSourcesRequest&) = 0;
   virtual void setMediaDeviceChangeObserver(
       const WebMediaDeviceChangeObserver&) = 0;
 };