Merge inbound to mozilla-central. a=merge
authorMihai Alexandru Michis <malexandru@mozilla.com>
Fri, 17 May 2019 12:29:41 +0300
changeset 474306 839cdad764d741ab4438b6feabeec749a22b34d5
parent 474305 cd02c0486c2ee3ffc03618955b6232b8be4aab0d (current diff)
parent 474193 afd2db10c864309a1e58f055e380c98248fb25a1 (diff)
child 474311 57c801a17dd68d815240cd760336aee21d247717
push id113144
push usershindli@mozilla.com
push dateFri, 17 May 2019 16:44:55 +0000
treeherdermozilla-inbound@f4c4b796f845 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone68.0a1
first release with
nightly linux32
839cdad764d7 / 68.0a1 / 20190517093040 / files
nightly linux64
839cdad764d7 / 68.0a1 / 20190517093040 / files
nightly mac
839cdad764d7 / 68.0a1 / 20190517093040 / files
nightly win32
839cdad764d7 / 68.0a1 / 20190517093040 / files
nightly win64
839cdad764d7 / 68.0a1 / 20190517093040 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central. a=merge
layout/printing/nsPrintPreviewListener.cpp
layout/printing/nsPrintPreviewListener.h
media/libcubeb/disable-device-switching.patch
--- a/devtools/client/netmonitor/test/browser.ini
+++ b/devtools/client/netmonitor/test/browser.ini
@@ -39,16 +39,19 @@ support-files =
   html_sorting-test-page.html
   html_statistics-test-page.html
   html_status-codes-test-page.html
   html_tracking-protection.html
   html_api-calls-test-page.html
   html_copy-as-curl.html
   html_curl-utils.html
   html_open-request-in-tab.html
+  html_worker-test-page.html
+  js_worker-test.js
+  js_worker-test2.js
   sjs_content-type-test-server.sjs
   sjs_cors-test-server.sjs
   sjs_https-redirect-test-server.sjs
   sjs_hsts-test-server.sjs
   sjs_json-test-server.sjs
   sjs_method-test-server.sjs
   sjs_set-cookie-same-site.sjs
   sjs_simple-test-server.sjs
@@ -216,8 +219,9 @@ skip-if = true # Bug 1373558
 [browser_net_timeline_ticks.js]
 skip-if = true # TODO: fix the test
 [browser_net_timing-division.js]
 [browser_net_tracking-resources.js]
 [browser_net_truncate-post-data.js]
 [browser_net_truncate.js]
 [browser_net_view-source-debugger.js]
 [browser_net_waterfall-click.js]
+[browser_net_worker_stacks.js]
--- a/devtools/client/netmonitor/test/browser_net_cause.js
+++ b/devtools/client/netmonitor/test/browser_net_cause.js
@@ -88,71 +88,33 @@ add_task(async function() {
   // all the requests the page is making, not only the XHRs.
   // We can't use about:blank here, because initNetMonitor checks that the
   // page has actually made at least one request.
   const { tab, monitor } = await initNetMonitor(SIMPLE_URL);
 
   const { document, store, windowRequire, connector } = monitor.panelWin;
   const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
   const {
-    getDisplayedRequests,
     getSortedRequests,
   } = windowRequire("devtools/client/netmonitor/src/selectors/index");
 
   store.dispatch(Actions.batchEnable(false));
 
   const wait = waitForNetworkEvents(monitor, EXPECTED_REQUESTS.length);
   BrowserTestUtils.loadURI(tab.linkedBrowser, CAUSE_URL);
   await wait;
 
   const requests = getSortedRequests(store.getState());
   await Promise.all(requests.map(requestItem =>
     connector.requestData(requestItem.id, "stackTrace")));
 
   is(store.getState().requests.requests.size, EXPECTED_REQUESTS.length,
     "All the page events should be recorded.");
 
-  EXPECTED_REQUESTS.forEach((spec, i) => {
-    const { method, url, causeType, causeUri, stack } = spec;
-
-    const requestItem = getSortedRequests(store.getState()).get(i);
-    verifyRequestItemTarget(
-      document,
-      getDisplayedRequests(store.getState()),
-      requestItem,
-      method,
-      url,
-      { cause: { type: causeType, loadingDocumentUri: causeUri } }
-    );
-
-    const stacktrace = requestItem.stacktrace;
-    const stackLen = stacktrace ? stacktrace.length : 0;
-
-    if (stack) {
-      ok(stacktrace, `Request #${i} has a stacktrace`);
-      ok(stackLen > 0,
-        `Request #${i} (${causeType}) has a stacktrace with ${stackLen} items`);
-
-      // if "stack" is array, check the details about the top stack frames
-      if (Array.isArray(stack)) {
-        stack.forEach((frame, j) => {
-          is(stacktrace[j].functionName, frame.fn,
-            `Request #${i} has the correct function on JS stack frame #${j}`);
-          is(stacktrace[j].filename.split("/").pop(), frame.file,
-            `Request #${i} has the correct file on JS stack frame #${j}`);
-          is(stacktrace[j].lineNumber, frame.line,
-            `Request #${i} has the correct line number on JS stack frame #${j}`);
-          is(stacktrace[j].asyncCause, frame.asyncCause,
-            `Request #${i} has the correct async cause on JS stack frame #${j}`);
-        });
-      }
-    } else {
-      is(stackLen, 0, `Request #${i} (${causeType}) has an empty stacktrace`);
-    }
-  });
+  validateRequests(EXPECTED_REQUESTS, monitor);
 
   // Sort the requests by cause and check the order
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector("#requests-list-cause-button"));
   const expectedOrder = EXPECTED_REQUESTS.map(r => r.causeType).sort();
   expectedOrder.forEach((expectedCause, i) => {
     const cause = getSortedRequests(store.getState()).get(i).cause.type;
     is(cause, expectedCause, `The request #${i} has the expected cause after sorting`);
new file mode 100644
--- /dev/null
+++ b/devtools/client/netmonitor/test/browser_net_worker_stacks.js
@@ -0,0 +1,100 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that we get stack traces for the network requests made when starting or
+// running worker threads.
+
+const TOP_FILE_NAME = "html_worker-test-page.html";
+const TOP_URL = EXAMPLE_URL + TOP_FILE_NAME;
+const WORKER_FILE_NAME = "js_worker-test.js";
+const WORKER_URL = EXAMPLE_URL + WORKER_FILE_NAME;
+
+const EXPECTED_REQUESTS = [
+  {
+    method: "GET",
+    url: TOP_URL,
+    causeType: "document",
+    causeUri: null,
+    stack: true,
+  },
+  {
+    method: "GET",
+    url: WORKER_URL,
+    causeType: "script",
+    causeUri: TOP_URL,
+    stack: [
+      { fn: "startWorkerInner", file: TOP_FILE_NAME, line: 11 },
+      { fn: "startWorker", file: TOP_FILE_NAME, line: 8 },
+      { file: TOP_FILE_NAME, line: 4 },
+    ],
+  },
+  {
+    method: "GET",
+    url: EXAMPLE_URL + "missing1.js",
+    causeType: "script",
+    causeUri: TOP_URL,
+    stack: [
+      { fn: "importScriptsFromWorker", file: WORKER_FILE_NAME, line: 14 },
+      { file: WORKER_FILE_NAME, line: 10 },
+    ],
+  },
+  {
+    method: "GET",
+    url: EXAMPLE_URL + "missing2.js",
+    causeType: "script",
+    causeUri: TOP_URL,
+    stack: [
+      { fn: "importScriptsFromWorker", file: WORKER_FILE_NAME, line: 14 },
+      { file: WORKER_FILE_NAME, line: 10 },
+    ],
+  },
+  {
+    method: "GET",
+    url: EXAMPLE_URL + "js_worker-test2.js",
+    causeType: "script",
+    causeUri: TOP_URL,
+    stack: [
+      { fn: "startWorkerFromWorker", file: WORKER_FILE_NAME, line: 7 },
+      { file: WORKER_FILE_NAME, line: 3 },
+    ],
+  },
+  {
+    method: "GET",
+    url: EXAMPLE_URL + "missing.json",
+    causeType: "xhr",
+    causeUri: TOP_URL,
+    stack: [
+      { fn: "createJSONRequest", file: WORKER_FILE_NAME, line: 22 },
+      { file: WORKER_FILE_NAME, line: 18 },
+    ],
+  },
+];
+
+add_task(async function() {
+  // Load a different URL first to instantiate the network monitor before we
+  // load the page we're really interested in.
+  const { tab, monitor } = await initNetMonitor(SIMPLE_URL);
+
+  const { store, windowRequire, connector } = monitor.panelWin;
+  const {
+    getSortedRequests,
+  } = windowRequire("devtools/client/netmonitor/src/selectors/index");
+
+  BrowserTestUtils.loadURI(tab.linkedBrowser, TOP_URL);
+
+  await waitForNetworkEvents(monitor, EXPECTED_REQUESTS.length);
+
+  is(store.getState().requests.requests.size, EXPECTED_REQUESTS.length,
+    "All the page events should be recorded.");
+
+  // Wait for stack traces from all requests.
+  const requests = getSortedRequests(store.getState());
+  await Promise.all(requests.map(requestItem =>
+    connector.requestData(requestItem.id, "stackTrace")));
+
+  validateRequests(EXPECTED_REQUESTS, monitor);
+
+  await teardown(monitor);
+});
--- a/devtools/client/netmonitor/test/head.js
+++ b/devtools/client/netmonitor/test/head.js
@@ -864,16 +864,63 @@ function queryTelemetryEvents(query) {
     event[2] === query.method &&
     event[3] === object
   );
 
   // Return the `extra` field (which is event[5]e).
   return filtersChangedEvents.map(event => event[5]);
 }
 
+function validateRequests(requests, monitor) {
+  const { document, store, windowRequire } = monitor.panelWin;
+
+  const {
+    getDisplayedRequests,
+  } = windowRequire("devtools/client/netmonitor/src/selectors/index");
+
+  requests.forEach((spec, i) => {
+    const { method, url, causeType, causeUri, stack } = spec;
+
+    const requestItem = getSortedRequests(store.getState()).get(i);
+    verifyRequestItemTarget(
+      document,
+      getDisplayedRequests(store.getState()),
+      requestItem,
+      method,
+      url,
+      { cause: { type: causeType, loadingDocumentUri: causeUri } }
+    );
+
+    const stacktrace = requestItem.stacktrace;
+    const stackLen = stacktrace ? stacktrace.length : 0;
+
+    if (stack) {
+      ok(stacktrace, `Request #${i} has a stacktrace`);
+      ok(stackLen > 0,
+        `Request #${i} (${causeType}) has a stacktrace with ${stackLen} items`);
+
+      // if "stack" is array, check the details about the top stack frames
+      if (Array.isArray(stack)) {
+        stack.forEach((frame, j) => {
+          is(stacktrace[j].functionName, frame.fn,
+            `Request #${i} has the correct function on JS stack frame #${j}`);
+          is(stacktrace[j].filename.split("/").pop(), frame.file,
+            `Request #${i} has the correct file on JS stack frame #${j}`);
+          is(stacktrace[j].lineNumber, frame.line,
+            `Request #${i} has the correct line number on JS stack frame #${j}`);
+          is(stacktrace[j].asyncCause, frame.asyncCause,
+            `Request #${i} has the correct async cause on JS stack frame #${j}`);
+        });
+      }
+    } else {
+      is(stackLen, 0, `Request #${i} (${causeType}) has an empty stacktrace`);
+    }
+  });
+}
+
 /**
  * Retrieve the context menu element corresponding to the provided id, for the provided
  * netmonitor instance.
  */
 function getContextMenuItem(monitor, id) {
   const Menu = require("devtools/client/framework/menu");
   return Menu.getMenuElementById(id, monitor.panelWin.document);
 }
new file mode 100644
--- /dev/null
+++ b/devtools/client/netmonitor/test/html_worker-test-page.html
@@ -0,0 +1,13 @@
+<script>
+/* eslint-disable no-unused-vars */
+"use strict";
+startWorker();
+
+var w;
+function startWorker() {
+  startWorkerInner();
+}
+function startWorkerInner() {
+  w = new Worker("js_worker-test.js");
+}
+</script>
new file mode 100644
--- /dev/null
+++ b/devtools/client/netmonitor/test/js_worker-test.js
@@ -0,0 +1,24 @@
+/* eslint-disable no-unused-vars, no-undef */
+"use strict";
+startWorkerFromWorker();
+
+var w;
+function startWorkerFromWorker() {
+  w = new Worker("js_worker-test2.js");
+}
+
+importScriptsFromWorker();
+
+function importScriptsFromWorker() {
+  try {
+    importScripts("missing1.js", "missing2.js");
+  } catch (e) {}
+}
+
+createJSONRequest();
+
+function createJSONRequest() {
+  const request = new XMLHttpRequest();
+  request.open("GET", "missing.json", true);
+  request.send(null);
+}
new file mode 100644
--- /dev/null
+++ b/devtools/client/netmonitor/test/js_worker-test2.js
@@ -0,0 +1,3 @@
+"use strict";
+
+console.log("I AM A WORKER");
--- a/devtools/server/actors/network-monitor/stack-trace-collector.js
+++ b/devtools/server/actors/network-monitor/stack-trace-collector.js
@@ -20,65 +20,110 @@ function StackTraceCollector(filters, ne
   this.filters = filters;
   this.stacktracesById = new Map();
   this.netmonitors = netmonitors;
 }
 
 StackTraceCollector.prototype = {
   init() {
     Services.obs.addObserver(this, "http-on-opening-request");
+    Services.obs.addObserver(this, "network-monitor-alternate-stack");
     ChannelEventSinkFactory.getService().registerCollector(this);
     this.onGetStack = this.onGetStack.bind(this);
     for (const { messageManager } of this.netmonitors) {
       messageManager.addMessageListener("debug:request-stack:request", this.onGetStack);
     }
   },
 
   destroy() {
     Services.obs.removeObserver(this, "http-on-opening-request");
+    Services.obs.removeObserver(this, "network-monitor-alternate-stack");
     ChannelEventSinkFactory.getService().unregisterCollector(this);
     for (const { messageManager } of this.netmonitors) {
       messageManager.removeMessageListener("debug:request-stack:request",
         this.onGetStack);
     }
   },
 
   _saveStackTrace(channel, stacktrace) {
+    if (this.stacktracesById.has(channel.channelId)) {
+      // We can get up to two stack traces for the same channel: one each from
+      // the two observer topics we are listening to. Use the first stack trace
+      // which is specified, and ignore any later one.
+      return;
+    }
     for (const { messageManager } of this.netmonitors) {
       messageManager.sendAsyncMessage("debug:request-stack-available", {
         channelId: channel.channelId,
         stacktrace: stacktrace && stacktrace.length > 0,
       });
     }
     this.stacktracesById.set(channel.channelId, stacktrace);
   },
 
-  observe(subject) {
+  observe(subject, topic, data) {
     const channel = subject.QueryInterface(Ci.nsIHttpChannel);
 
     if (!matchRequest(channel, this.filters)) {
       return;
     }
 
-    // Convert the nsIStackFrame XPCOM objects to a nice JSON that can be
-    // passed around through message managers etc.
-    let frame = components.stack;
     const stacktrace = [];
-    if (frame && frame.caller) {
-      frame = frame.caller;
-      while (frame) {
-        stacktrace.push({
-          filename: frame.filename,
-          lineNumber: frame.lineNumber,
-          columnNumber: frame.columnNumber,
-          functionName: frame.name,
-          asyncCause: frame.asyncCause,
-        });
-        frame = frame.caller || frame.asyncCaller;
+    switch (topic) {
+      case "http-on-opening-request": {
+        // The channel is being opened on the main thread, associate the current
+        // stack with it.
+        //
+        // Convert the nsIStackFrame XPCOM objects to a nice JSON that can be
+        // passed around through message managers etc.
+        let frame = components.stack;
+        if (frame && frame.caller) {
+          frame = frame.caller;
+          while (frame) {
+            stacktrace.push({
+              filename: frame.filename,
+              lineNumber: frame.lineNumber,
+              columnNumber: frame.columnNumber,
+              functionName: frame.name,
+              asyncCause: frame.asyncCause,
+            });
+            frame = frame.caller || frame.asyncCaller;
+          }
+        }
+        break;
       }
+      case "network-monitor-alternate-stack": {
+        // An alternate stack trace is being specified for this channel.
+        // The topic data is the JSON for the saved frame stack we should use,
+        // so convert this into the expected format.
+        //
+        // This topic is used in the following cases:
+        //
+        // - The HTTP channel is opened asynchronously or on a different thread
+        //   from the code which triggered its creation, in which case the stack
+        //   from components.stack will be empty. The alternate stack will be
+        //   for the point we want to associate with the channel.
+        //
+        // - The channel is not a nsIHttpChannel, and we will receive no
+        //   opening request notification for it.
+        let frame = JSON.parse(data);
+        while (frame) {
+          stacktrace.push({
+            filename: frame.source,
+            lineNumber: frame.line,
+            columnNumber: frame.column,
+            functionName: frame.functionDisplayName,
+            asyncCause: frame.asyncCause,
+          });
+          frame = frame.parent || frame.asyncParent;
+        }
+        break;
+      }
+      default:
+        throw new Error("Unexpected observe() topic");
     }
 
     this._saveStackTrace(channel, stacktrace);
   },
 
   // eslint-disable-next-line no-shadow
   onChannelRedirect(oldChannel, newChannel, flags) {
     // We can be called with any nsIChannel, but are interested only in HTTP channels
--- a/dom/base/nsDOMDataChannel.cpp
+++ b/dom/base/nsDOMDataChannel.cpp
@@ -137,16 +137,18 @@ mozilla::dom::Nullable<uint16_t> nsDOMDa
     const {
   return mDataChannel->GetMaxPacketLifeTime();
 }
 
 mozilla::dom::Nullable<uint16_t> nsDOMDataChannel::GetMaxRetransmits() const {
   return mDataChannel->GetMaxRetransmits();
 }
 
+bool nsDOMDataChannel::Negotiated() const { return mDataChannel->GetNegotiated(); }
+
 bool nsDOMDataChannel::Ordered() const { return mDataChannel->GetOrdered(); }
 
 RTCDataChannelState nsDOMDataChannel::ReadyState() const {
   return static_cast<RTCDataChannelState>(mDataChannel->GetReadyState());
 }
 
 uint32_t nsDOMDataChannel::BufferedAmount() const {
   if (!mSentClose) {
--- a/dom/base/nsDOMDataChannel.h
+++ b/dom/base/nsDOMDataChannel.h
@@ -69,16 +69,17 @@ class nsDOMDataChannel final : public mo
     mBinaryType = static_cast<DataChannelBinaryType>(static_cast<int>(aType));
   }
   void Send(const nsAString& aData, mozilla::ErrorResult& aRv);
   void Send(mozilla::dom::Blob& aData, mozilla::ErrorResult& aRv);
   void Send(const mozilla::dom::ArrayBuffer& aData, mozilla::ErrorResult& aRv);
   void Send(const mozilla::dom::ArrayBufferView& aData,
             mozilla::ErrorResult& aRv);
 
+  bool Negotiated() const;
   bool Ordered() const;
   mozilla::dom::Nullable<uint16_t> GetId() const;
 
   nsresult DoOnMessageAvailable(const nsACString& aMessage, bool aBinary);
 
   virtual nsresult OnMessageAvailable(nsISupports* aContext,
                                       const nsACString& aMessage) override;
 
--- a/dom/webidl/RTCDataChannel.webidl
+++ b/dom/webidl/RTCDataChannel.webidl
@@ -12,16 +12,17 @@ enum RTCDataChannelState {
 enum RTCDataChannelType {
   "arraybuffer",
   "blob"
 };
 
 interface RTCDataChannel : EventTarget
 {
   readonly attribute DOMString label;
+  readonly attribute boolean negotiated;
   readonly attribute boolean ordered;
   readonly attribute boolean reliable;
   readonly attribute unsigned short? maxPacketLifeTime;
   readonly attribute unsigned short? maxRetransmits;
   readonly attribute USVString protocol;
   readonly attribute unsigned short? id;
   readonly attribute RTCDataChannelState readyState;
   readonly attribute unsigned long bufferedAmount;
rename from layout/printing/nsPrintPreviewListener.cpp
rename to layout/printing/PrintPreviewUserEventSuppressor.cpp
--- a/layout/printing/nsPrintPreviewListener.cpp
+++ b/layout/printing/PrintPreviewUserEventSuppressor.cpp
@@ -1,76 +1,59 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "nsPrintPreviewListener.h"
+#include "PrintPreviewUserEventSuppressor.h"
 
 #include "mozilla/TextEvents.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/Event.h"  // for Event
 #include "nsIDOMWindow.h"
 #include "nsPIDOMWindow.h"
 #include "mozilla/dom/Document.h"
 #include "nsIDocShell.h"
 #include "nsPresContext.h"
 #include "nsFocusManager.h"
 #include "nsLiteralString.h"
 
-using namespace mozilla;
 using namespace mozilla::dom;
 
-NS_IMPL_ISUPPORTS(nsPrintPreviewListener, nsIDOMEventListener)
-
-//
-// nsPrintPreviewListener ctor
-//
-nsPrintPreviewListener::nsPrintPreviewListener(EventTarget* aTarget)
-    : mEventTarget(aTarget) {
-  NS_ADDREF_THIS();
-}  // ctor
+namespace mozilla {
 
-nsPrintPreviewListener::~nsPrintPreviewListener() {}
+PrintPreviewUserEventSuppressor::PrintPreviewUserEventSuppressor(
+    EventTarget* aTarget)
+    : mEventTarget(aTarget) {
+  AddListeners();
+}
 
-//-------------------------------------------------------
-//
-// AddListeners
-//
-// Subscribe to the events that will allow us to track various events.
-//
-nsresult nsPrintPreviewListener::AddListeners() {
+NS_IMPL_ISUPPORTS(PrintPreviewUserEventSuppressor, nsIDOMEventListener)
+
+void PrintPreviewUserEventSuppressor::AddListeners() {
   if (mEventTarget) {
     mEventTarget->AddEventListener(NS_LITERAL_STRING("click"), this, true);
     mEventTarget->AddEventListener(NS_LITERAL_STRING("contextmenu"), this,
                                    true);
     mEventTarget->AddEventListener(NS_LITERAL_STRING("keydown"), this, true);
     mEventTarget->AddEventListener(NS_LITERAL_STRING("keypress"), this, true);
     mEventTarget->AddEventListener(NS_LITERAL_STRING("keyup"), this, true);
     mEventTarget->AddEventListener(NS_LITERAL_STRING("mousedown"), this, true);
     mEventTarget->AddEventListener(NS_LITERAL_STRING("mousemove"), this, true);
     mEventTarget->AddEventListener(NS_LITERAL_STRING("mouseout"), this, true);
     mEventTarget->AddEventListener(NS_LITERAL_STRING("mouseover"), this, true);
     mEventTarget->AddEventListener(NS_LITERAL_STRING("mouseup"), this, true);
 
     mEventTarget->AddSystemEventListener(NS_LITERAL_STRING("keydown"), this,
                                          true);
   }
-
-  return NS_OK;
 }
 
-//-------------------------------------------------------
-//
-// RemoveListeners
-//
-// Unsubscribe from all the various events that we were listening to.
-//
-nsresult nsPrintPreviewListener::RemoveListeners() {
+void PrintPreviewUserEventSuppressor::RemoveListeners() {
   if (mEventTarget) {
     mEventTarget->RemoveEventListener(NS_LITERAL_STRING("click"), this, true);
     mEventTarget->RemoveEventListener(NS_LITERAL_STRING("contextmenu"), this,
                                       true);
     mEventTarget->RemoveEventListener(NS_LITERAL_STRING("keydown"), this, true);
     mEventTarget->RemoveEventListener(NS_LITERAL_STRING("keypress"), this,
                                       true);
     mEventTarget->RemoveEventListener(NS_LITERAL_STRING("keyup"), this, true);
@@ -82,34 +65,27 @@ nsresult nsPrintPreviewListener::RemoveL
                                       true);
     mEventTarget->RemoveEventListener(NS_LITERAL_STRING("mouseover"), this,
                                       true);
     mEventTarget->RemoveEventListener(NS_LITERAL_STRING("mouseup"), this, true);
 
     mEventTarget->RemoveSystemEventListener(NS_LITERAL_STRING("keydown"), this,
                                             true);
   }
-
-  return NS_OK;
 }
 
-//-------------------------------------------------------
-//
-// GetActionForEvent
-//
-// Helper function to let certain key events through
-//
 enum eEventAction {
   eEventAction_Tab,
   eEventAction_ShiftTab,
   eEventAction_Propagate,
   eEventAction_Suppress,
   eEventAction_StopPropagation
 };
 
+// Helper function to let certain key events through
 static eEventAction GetActionForEvent(Event* aEvent) {
   WidgetKeyboardEvent* keyEvent = aEvent->WidgetEventPtr()->AsKeyboardEvent();
   if (!keyEvent) {
     return eEventAction_Suppress;
   }
 
   if (keyEvent->mFlags.mInSystemGroup) {
     NS_ASSERTION(keyEvent->mMessage == eKeyDown,
@@ -145,21 +121,21 @@ static eEventAction GetActionForEvent(Ev
       return eEventAction_Propagate;
     }
   }
 
   return eEventAction_Suppress;
 }
 
 NS_IMETHODIMP
-nsPrintPreviewListener::HandleEvent(Event* aEvent) {
+PrintPreviewUserEventSuppressor::HandleEvent(Event* aEvent) {
   nsCOMPtr<nsIContent> content =
       do_QueryInterface(aEvent ? aEvent->GetOriginalTarget() : nullptr);
   if (content && !content->IsXULElement()) {
-    eEventAction action = ::GetActionForEvent(aEvent);
+    eEventAction action = GetActionForEvent(aEvent);
     switch (action) {
       case eEventAction_Tab:
       case eEventAction_ShiftTab: {
         nsAutoString eventString;
         aEvent->GetType(eventString);
         if (eventString.EqualsLiteral("keydown")) {
           // Handle tabbing explicitly here since we don't want focus ending up
           // inside the content document, bug 244128.
@@ -168,20 +144,19 @@ nsPrintPreviewListener::HandleEvent(Even
 
           Document* parentDoc = doc->GetParentDocument();
           NS_ASSERTION(parentDoc, "no parent document");
 
           nsCOMPtr<nsPIDOMWindowOuter> win = parentDoc->GetWindow();
 
           nsIFocusManager* fm = nsFocusManager::GetFocusManager();
           if (fm && win) {
-            dom::Element* fromElement =
-                parentDoc->FindContentForSubDocument(doc);
+            Element* fromElement = parentDoc->FindContentForSubDocument(doc);
             bool forward = (action == eEventAction_Tab);
-            RefPtr<dom::Element> result;
+            RefPtr<Element> result;
             fm->MoveFocus(win, fromElement,
                           forward ? nsIFocusManager::MOVEFOCUS_FORWARD
                                   : nsIFocusManager::MOVEFOCUS_BACKWARD,
                           nsIFocusManager::FLAG_BYKEY, getter_AddRefs(result));
           }
         }
       }
         MOZ_FALLTHROUGH;
@@ -194,8 +169,10 @@ nsPrintPreviewListener::HandleEvent(Even
         break;
       case eEventAction_Propagate:
         // intentionally empty
         break;
     }
   }
   return NS_OK;
 }
+
+}  // namespace mozilla
rename from layout/printing/nsPrintPreviewListener.h
rename to layout/printing/PrintPreviewUserEventSuppressor.h
--- a/layout/printing/nsPrintPreviewListener.h
+++ b/layout/printing/PrintPreviewUserEventSuppressor.h
@@ -1,51 +1,53 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef nsPrintPreviewListener_h__
-#define nsPrintPreviewListener_h__
+#ifndef mozilla_PrintPreviewUserEventSuppressor_h
+#define mozilla_PrintPreviewUserEventSuppressor_h
 
-// Interfaces needed to be included
+#include "nsCOMPtr.h"
 #include "nsIDOMEventListener.h"
-// Helper Classes
-#include "nsCOMPtr.h"
 #include "mozilla/Attributes.h"
 
 namespace mozilla {
+
 namespace dom {
 class EventTarget;
 }  // namespace dom
-}  // namespace mozilla
 
-//
-// class nsPrintPreviewListener
-//
-// The class that listens to the chrome events and tells the embedding
-// chrome to show context menus, as appropriate. Handles registering itself
-// with the DOM with AddChromeListeners() and removing itself with
-// RemoveChromeListeners().
-//
-class nsPrintPreviewListener final : public nsIDOMEventListener
-
-{
+/**
+ * A class that filters out certain user events targeted at the given event
+ * target (a document).  Intended for use with the Print Preview document to
+ * stop users from doing anything that would break printing invariants.  (For
+ * example, blocks opening of the context menu, interaction with form controls,
+ * content selection, etc.)
+ */
+class PrintPreviewUserEventSuppressor final : public nsIDOMEventListener {
  public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDOMEVENTLISTENER
 
-  explicit nsPrintPreviewListener(mozilla::dom::EventTarget* aTarget);
+  explicit PrintPreviewUserEventSuppressor(dom::EventTarget* aTarget);
 
-  // Add/remove the relevant listeners, based on what interfaces
-  // the embedding chrome implements.
-  nsresult AddListeners();
-  nsresult RemoveListeners();
+  /**
+   * Must be called before releasing this object in order to break the strong
+   * reference cycle between ourselves and the document we're listening to,
+   * or else the objects in the cylce will be leaked (since this class does
+   * not participate in cycle collection).
+   */
+  void StopSuppressing() { RemoveListeners(); }
 
  private:
-  ~nsPrintPreviewListener();
+  ~PrintPreviewUserEventSuppressor() { RemoveListeners(); }
+
+  void AddListeners();
+  void RemoveListeners();
 
   nsCOMPtr<mozilla::dom::EventTarget> mEventTarget;
+};
 
-};  // class nsPrintPreviewListener
+}  // namespace mozilla
 
-#endif /* nsPrintPreviewListener_h__ */
+#endif  // mozilla_PrintPreviewUserEventSuppressor_h
--- a/layout/printing/moz.build
+++ b/layout/printing/moz.build
@@ -23,17 +23,17 @@ XPIDL_MODULE = 'layout_printing'
 UNIFIED_SOURCES += [
     'DrawEventRecorder.cpp',
     'ipc/RemotePrintJobChild.cpp',
     'ipc/RemotePrintJobParent.cpp',
     'nsPagePrintTimer.cpp',
     'nsPrintData.cpp',
     'nsPrintJob.cpp',
     'nsPrintObject.cpp',
-    'nsPrintPreviewListener.cpp',
+    'PrintPreviewUserEventSuppressor.cpp',
     'PrintTranslator.cpp',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
 LOCAL_INCLUDES += [
     '../base',
--- a/layout/printing/nsPrintData.cpp
+++ b/layout/printing/nsPrintData.cpp
@@ -5,19 +5,19 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsPrintData.h"
 
 #include "nsIStringBundle.h"
 #include "nsIServiceManager.h"
 #include "nsIWidget.h"
 #include "nsPrintObject.h"
-#include "nsPrintPreviewListener.h"
 #include "nsIWebProgressListener.h"
 #include "mozilla/Services.h"
+#include "PrintPreviewUserEventSuppressor.h"
 
 //-----------------------------------------------------
 // PR LOGGING
 #include "mozilla/Logging.h"
 
 static mozilla::LazyLogModule gPrintingLog("printing");
 
 #define PR_PL(_p1) MOZ_LOG(gPrintingLog, mozilla::LogLevel::Debug, _p1);
@@ -33,18 +33,17 @@ nsPrintData::nsPrintData(ePrintDataType 
       mOnStartSent(false),
       mIsAborted(false),
       mPreparingForPrint(false),
       mDocWasToBeDestroyed(false),
       mShrinkToFit(false),
       mPrintFrameType(nsIPrintSettings::kFramesAsIs),
       mNumPrintablePages(0),
       mNumPagesPrinted(0),
-      mShrinkRatio(1.0),
-      mPPEventListeners(nullptr) {
+      mShrinkRatio(1.0) {
   nsCOMPtr<nsIStringBundle> brandBundle;
   nsCOMPtr<nsIStringBundleService> svc =
       mozilla::services::GetStringBundleService();
   if (svc) {
     svc->CreateBundle("chrome://branding/locale/brand.properties",
                       getter_AddRefs(brandBundle));
     if (brandBundle) {
       brandBundle->GetStringFromName("brandShortName", mBrandName);
@@ -52,20 +51,19 @@ nsPrintData::nsPrintData(ePrintDataType 
   }
 
   if (mBrandName.IsEmpty()) {
     mBrandName.AssignLiteral(u"Mozilla Document");
   }
 }
 
 nsPrintData::~nsPrintData() {
-  // remove the event listeners
-  if (mPPEventListeners) {
-    mPPEventListeners->RemoveListeners();
-    NS_RELEASE(mPPEventListeners);
+  if (mPPEventSuppressor) {
+    mPPEventSuppressor->StopSuppressing();
+    mPPEventSuppressor = nullptr;
   }
 
   // Only Send an OnEndPrinting if we have started printing
   if (mOnStartSent && mType != eIsPrintPreview) {
     OnEndPrinting();
   }
 
   if (mPrintDC) {
--- a/layout/printing/nsPrintData.h
+++ b/layout/printing/nsPrintData.h
@@ -13,36 +13,41 @@
 // Interfaces
 #include "nsDeviceContext.h"
 #include "nsIPrintProgressParams.h"
 #include "nsIPrintSettings.h"
 #include "nsISupportsImpl.h"
 #include "nsTArray.h"
 #include "nsCOMArray.h"
 
-// Classes
 class nsPrintObject;
-class nsPrintPreviewListener;
 class nsIWebProgressListener;
 
+namespace mozilla {
+class PrintPreviewUserEventSuppressor;
+}  // namespace mozilla
+
 //------------------------------------------------------------------------
 // nsPrintData Class
 //
 // mPreparingForPrint - indicates that we have started Printing but
 //   have not gone to the timer to start printing the pages. It gets turned
 //   off right before we go to the timer.
 //
 // mDocWasToBeDestroyed - Gets set when "someone" tries to unload the document
 //   while we were prparing to Print. This typically happens if a user starts
 //   to print while a page is still loading. If they start printing and pause
 //   at the print dialog and then the page comes in, we then abort printing
 //   because the document is no longer stable.
 //
 //------------------------------------------------------------------------
 class nsPrintData {
+  typedef mozilla::PrintPreviewUserEventSuppressor
+      PrintPreviewUserEventSuppressor;
+
  public:
   typedef enum { eIsPrinting, eIsPrintPreview } ePrintDataType;
 
   explicit nsPrintData(ePrintDataType aType);
 
   NS_INLINE_DECL_REFCOUNTING(nsPrintData)
 
   // Listener Helper Methods
@@ -77,17 +82,17 @@ class nsPrintData {
   bool mDocWasToBeDestroyed;  // see comments above
   bool mShrinkToFit;
   int16_t mPrintFrameType;
   int32_t mNumPrintablePages;
   int32_t mNumPagesPrinted;
   float mShrinkRatio;
 
   nsCOMPtr<nsIPrintSettings> mPrintSettings;
-  nsPrintPreviewListener* mPPEventListeners;
+  RefPtr<PrintPreviewUserEventSuppressor> mPPEventSuppressor;
 
   nsString mBrandName;  //  needed as a substitute name for a document
 
  private:
   nsPrintData() = delete;
   nsPrintData& operator=(const nsPrintData& aOther) = delete;
 
   ~nsPrintData();  // non-virtual
--- a/layout/printing/nsPrintJob.cpp
+++ b/layout/printing/nsPrintJob.cpp
@@ -33,18 +33,16 @@
 #include "nsIServiceManager.h"
 #include "nsGkAtoms.h"
 #include "nsXPCOM.h"
 #include "nsISupportsPrimitives.h"
 
 static const char sPrintSettingsServiceContractID[] =
     "@mozilla.org/gfx/printsettings-service;1";
 
-// Printing Events
-#include "nsPrintPreviewListener.h"
 #include "nsThreadUtils.h"
 
 // Printing
 #include "nsIWebBrowserPrint.h"
 
 // Print Preview
 #include "imgIContainer.h"  // image animation mode constants
 
@@ -111,16 +109,17 @@ static const char kPrintingPromptService
 #include "nsFocusManager.h"
 #include "nsRange.h"
 #include "nsIURIFixup.h"
 #include "mozilla/Components.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/HTMLFrameElement.h"
 #include "nsContentList.h"
 #include "nsIChannel.h"
+#include "PrintPreviewUserEventSuppressor.h"
 #include "xpcpublic.h"
 #include "nsVariant.h"
 #include "mozilla/ServoStyleSet.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 //-----------------------------------------------------
@@ -566,27 +565,26 @@ nsresult nsPrintJob::Cancelled() {
   return NS_ERROR_FAILURE;
 }
 
 //-------------------------------------------------------
 // Install our event listeners on the document to prevent
 // some events from being processed while in PrintPreview
 //
 // No return code - if this fails, there isn't much we can do
-void nsPrintJob::InstallPrintPreviewListener() {
-  if (!mPrt->mPPEventListeners) {
+void nsPrintJob::SuppressPrintPreviewUserEvents() {
+  if (!mPrt->mPPEventSuppressor) {
     nsCOMPtr<nsIDocShell> docShell = do_QueryReferent(mContainer);
     if (!docShell) {
       return;
     }
 
     if (nsPIDOMWindowOuter* win = docShell->GetWindow()) {
       nsCOMPtr<EventTarget> target = win->GetFrameElementInternal();
-      mPrt->mPPEventListeners = new nsPrintPreviewListener(target);
-      mPrt->mPPEventListeners->AddListeners();
+      mPrt->mPPEventSuppressor = new PrintPreviewUserEventSuppressor(target);
     }
   }
 }
 
 //-----------------------------------------------------------------
 nsresult nsPrintJob::GetSeqFrameAndCountPages(nsIFrame*& aSeqFrame,
                                               int32_t& aCount) {
   MOZ_ASSERT(mPrtPreview);
@@ -1002,17 +1000,17 @@ nsresult nsPrintJob::DoCommonPrint(bool 
   if (aIsPrintPreview) {
     bool notifyOnInit = false;
     ShowPrintProgress(false, notifyOnInit);
 
     // Very important! Turn Off scripting
     TurnScriptingOn(false);
 
     if (!notifyOnInit) {
-      InstallPrintPreviewListener();
+      SuppressPrintPreviewUserEvents();
       rv = InitPrintDocConstruction(false);
     } else {
       rv = NS_OK;
     }
   } else {
     bool doNotify;
     ShowPrintProgress(true, doNotify);
     if (!doNotify) {
--- a/layout/printing/nsPrintJob.h
+++ b/layout/printing/nsPrintJob.h
@@ -104,17 +104,23 @@ class nsPrintJob final : public nsIObser
   bool PrintDocContent(const mozilla::UniquePtr<nsPrintObject>& aPO,
                        nsresult& aStatus);
   nsresult DoPrint(const mozilla::UniquePtr<nsPrintObject>& aPO);
 
   void SetPrintPO(nsPrintObject* aPO, bool aPrint);
 
   void TurnScriptingOn(bool aDoTurnOn);
   bool CheckDocumentForPPCaching();
-  void InstallPrintPreviewListener();
+
+  /**
+   * Filters out certain user events while Print Preview is open to prevent
+   * the user from interacting with the Print Preview document and breaking
+   * printing invariants.
+   */
+  void SuppressPrintPreviewUserEvents();
 
   // nsIDocumentViewerPrint Printing Methods
   bool HasPrintCallbackCanvas();
   bool PrePrintPage();
   bool PrintPage(nsPrintObject* aPOect, bool& aInRange);
   bool DonePrintingPages(nsPrintObject* aPO, nsresult aResult);
 
   //---------------------------------------------------------------------
--- a/layout/reftests/display-list/reftest.list
+++ b/layout/reftests/display-list/reftest.list
@@ -36,9 +36,9 @@ skip-if(!asyncPan) == 1437374-1.html 143
 == 1453541-2.html 1453541-ref.html
 == 1452805-1.html 1452805-ref.html
 == 1461231-1.html about:blank
 fuzzy(0-2,0-40000) skip-if(!asyncPan) == 1464288-1.html 1464288-ref.html
 == 1482403-1.html 1482403-1-ref.html
 == 1504233-1.html 1504233-1-ref.html
 == 1533317-1.html 1533317-1-ref.html
 == 1544948-1.html 1544948-1-ref.html
-skip-if(retainedDisplayList) == 1551053-1.html 1551053-1-ref.html
+== 1551053-1.html 1551053-1-ref.html
--- a/layout/reftests/w3c-css/submitted/contain/reftest.list
+++ b/layout/reftests/w3c-css/submitted/contain/reftest.list
@@ -43,16 +43,16 @@ fuzzy-if(webrender&&winWidget,0-24,0-2) 
 == contain-layout-formatting-context-margin-001.html contain-layout-formatting-context-margin-001-ref.html
 == contain-layout-containing-block-fixed-001.html contain-paint-containing-block-fixed-001-ref.html
 == contain-layout-containing-block-absolute-001.html contain-paint-containing-block-absolute-001-ref.html
 == contain-layout-ignored-cases-ib-split-001.html contain-layout-ignored-cases-ib-split-001-ref.html
 == contain-layout-ignored-cases-no-principal-box-001.html contain-paint-ignored-cases-no-principal-box-001-ref.html
 == contain-layout-ignored-cases-no-principal-box-002.html contain-layout-ignored-cases-no-principal-box-002-ref.html
 == contain-layout-ignored-cases-no-principal-box-003.html contain-layout-ignored-cases-no-principal-box-003-ref.html
 == contain-layout-suppress-baseline-001.html contain-layout-suppress-baseline-001-ref.html
-fails == contain-layout-suppress-baseline-002.html contain-layout-suppress-baseline-002-ref.html # bug 1508441
+fails == contain-layout-suppress-baseline-002.html contain-layout-suppress-baseline-002-ref.html # bug 1552287
 
 # The following lines are duplicates of other lines from further up in this
 # manifest. They're listed again here so we can re-run these tests with
 # column-span enabled. These lines can be removed once the pref becomes
 # default-enabled (Bug 1426010).
 pref(layout.css.column-span.enabled,true) == contain-size-multicol-002.html contain-size-multicol-002-ref.html
 pref(layout.css.column-span.enabled,true) == contain-size-multicol-003.html contain-size-multicol-003-ref.html
deleted file mode 100644
--- a/media/libcubeb/disable-device-switching.patch
+++ /dev/null
@@ -1,79 +0,0 @@
-diff --git a/media/libcubeb/src/cubeb_wasapi.cpp b/media/libcubeb/src/cubeb_wasapi.cpp
---- a/media/libcubeb/src/cubeb_wasapi.cpp
-+++ b/media/libcubeb/src/cubeb_wasapi.cpp
-@@ -1829,21 +1829,26 @@ wasapi_stream_init(cubeb * context, cube
-        assert that the lock is held in the function. */
-     auto_lock lock(stm->stream_reset_lock);
-     rv = setup_wasapi_stream(stm.get());
-   }
-   if (rv != CUBEB_OK) {
-     return rv;
-   }
- 
--  HRESULT hr = register_notification_client(stm.get());
--  if (FAILED(hr)) {
--    /* this is not fatal, we can still play audio, but we won't be able
--       to keep using the default audio endpoint if it changes. */
--    LOG("failed to register notification client, %lx", hr);
-+  if (!((input_stream_params ?
-+         (input_stream_params->prefs & CUBEB_STREAM_PREF_DISABLE_DEVICE_SWITCHING) : 0) ||
-+        (output_stream_params ?
-+         (output_stream_params->prefs & CUBEB_STREAM_PREF_DISABLE_DEVICE_SWITCHING) : 0))) {
-+    HRESULT hr = register_notification_client(stm.get());
-+    if (FAILED(hr)) {
-+      /* this is not fatal, we can still play audio, but we won't be able
-+         to keep using the default audio endpoint if it changes. */
-+      LOG("failed to register notification client, %lx", hr);
-+    }
-   }
- 
-   *stream = stm.release();
- 
-   LOG("Stream init succesfull (%p)", *stream);
-   return CUBEB_OK;
- }
- 
-@@ -1879,17 +1884,19 @@ void wasapi_stream_destroy(cubeb_stream 
-   // Only free stm->emergency_bailout if we could join the thread.
-   // If we could not join the thread, stm->emergency_bailout is true
-   // and is still alive until the thread wakes up and exits cleanly.
-   if (stop_and_join_render_thread(stm)) {
-     delete stm->emergency_bailout.load();
-     stm->emergency_bailout = nullptr;
-   }
- 
--  unregister_notification_client(stm);
-+  if (stm->notification_client) {
-+    unregister_notification_client(stm);
-+  }
- 
-   CloseHandle(stm->reconfigure_event);
-   CloseHandle(stm->refill_event);
-   CloseHandle(stm->input_available_event);
- 
-   // The variables intialized in wasapi_stream_init,
-   // must be destroyed in wasapi_stream_destroy.
-   stm->linear_input_buffer.reset();
-diff --git a/media/libcubeb/include/cubeb.h b/media/libcubeb/include/cubeb.h
---- a/media/libcubeb/include/cubeb.h
-+++ a/media/libcubeb/include/cubeb.h
-@@ -222,16 +222,19 @@
- 
- /** Miscellaneous stream preferences. */
- typedef enum {
-   CUBEB_STREAM_PREF_NONE     = 0x00, /**< No stream preferences are requested. */
-   CUBEB_STREAM_PREF_LOOPBACK = 0x01, /**< Request a loopback stream. Should be
-                                          specified on the input params and an
-                                          output device to loopback from should
-                                          be passed in place of an input device. */
-+  CUBEB_STREAM_PREF_DISABLE_DEVICE_SWITCHING = 0x02, /**< Disable switching
-+                                                          default device on OS
-+                                                          changes. */
-   CUBEB_STREAM_PREF_VOICE = 0x04  /**< This stream is going to transport voice data.
-                                        Depending on the backend and platform, this can
-                                        change the audio input or output devices
-                                        selected, as well as the quality of the stream,
-                                        for example to accomodate bluetooth SCO modes on
-                                        bluetooth devices. */
- } cubeb_stream_prefs;
- 
--- a/media/libcubeb/moz.yaml
+++ b/media/libcubeb/moz.yaml
@@ -14,10 +14,10 @@ bugzilla:
 origin:
   name: "cubeb"
   description: "Cross platform audio library"
 
   url: "https://github.com/kinetiknz/cubeb"
   license: "ISC"
 
   # update.sh will update this value
-  release: "64aa80f330a3dc510b1e3ac0e92cc6bed129a9a6 (2019-04-25 17:32:33 +0200)"
+  release: "b9e2c50e51fc58b31b553b5364efacec24ebb76e (2019-05-17 09:21:59 +1200)"
 
--- a/media/libcubeb/update.sh
+++ b/media/libcubeb/update.sh
@@ -85,11 +85,8 @@ if [ -n "$rev" ]; then
   rm moz.yaml.bak
   [[ -n "$commits" ]] && echo -e "Pick commits:\n$commits"
 else
   echo "Remember to update moz.yaml with the version details."
 fi
 
 echo "Applying disable-assert.patch on top of $rev"
 patch -p3 < disable-assert.patch
-
-echo "Applying disable-device-switching.patch on top of $rev"
-patch -p3 < disable-device-switching.patch
--- a/netwerk/sctp/datachannel/DataChannel.h
+++ b/netwerk/sctp/datachannel/DataChannel.h
@@ -379,16 +379,17 @@ class DataChannel {
         mContext(aContext),
         mConnection(connection),
         mLabel(label),
         mProtocol(protocol),
         mState(state),
         mStream(stream),
         mPrPolicy(policy),
         mPrValue(value),
+        mNegotiated(negotiated),
         mOrdered(ordered),
         mFlags(0),
         mId(0),
         mIsRecvBinary(false),
         mBufferedThreshold(0),  // default from spec
         mBufferedAmount(0),
         mMainThreadEventTarget(connection->GetNeckoTarget()) {
     if (!ordered) {
@@ -434,16 +435,18 @@ class DataChannel {
   void SendBinaryBlob(dom::Blob& aBlob, ErrorResult& aRv);
 
   uint16_t GetType() { return mPrPolicy; }
 
   dom::Nullable<uint16_t> GetMaxPacketLifeTime() const;
 
   dom::Nullable<uint16_t> GetMaxRetransmits() const;
 
+  bool GetNegotiated() { return mNegotiated; }
+
   bool GetOrdered() { return mOrdered; }
 
   void IncrementBufferedAmount(uint32_t aSize, ErrorResult& aRv);
   void DecrementBufferedAmount(uint32_t aSize);
 
   // Amount of data buffered to send
   uint32_t GetBufferedAmount() {
     MOZ_ASSERT(NS_IsMainThread());
@@ -488,16 +491,17 @@ class DataChannel {
 
   RefPtr<DataChannelConnection> mConnection;
   nsCString mLabel;
   nsCString mProtocol;
   uint16_t mState;
   uint16_t mStream;
   uint16_t mPrPolicy;
   uint32_t mPrValue;
+  const bool mNegotiated;
   const bool mOrdered;
   uint32_t mFlags;
   uint32_t mId;
   bool mIsRecvBinary;
   size_t mBufferedThreshold;
   // Read/written on main only. Decremented via message-passing, because the
   // spec requires us to queue a task for this.
   size_t mBufferedAmount;
--- a/testing/web-platform/meta/webrtc/RTCPeerConnection-createDataChannel.html.ini
+++ b/testing/web-platform/meta/webrtc/RTCPeerConnection-createDataChannel.html.ini
@@ -1,12 +1,12 @@
 [RTCPeerConnection-createDataChannel.html]
   [createDataChannel attribute default values]
     expected: FAIL
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1529695
+    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1531100
 
   [createDataChannel with provided parameters should initialize attributes to provided values]
     expected: FAIL
     bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1531900
 
   [createDataChannel with negotiated true should succeed]
     expected: FAIL
     bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1529695
@@ -18,24 +18,16 @@
   [createDataChannel with invalid priority should throw TypeError]
     expected: FAIL
     bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1531100
 
   [Channels created after SCTP transport is established should have id assigned]
     expected: FAIL
     bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1526253
 
-  [createDataChannel with negotiated false should succeed]
-    expected: FAIL
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1529695
-
-  [createDataChannel with negotiated false and id 42 should ignore the id]
-    expected: FAIL
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1529695
-
   [Reusing a data channel id that is in use (after setRemoteDescription, negotiated via DCEP) should throw OperationError]
     expected: FAIL
     bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1547106
 
   [Reusing a data channel id that is in use (after setRemoteDescription) should throw OperationError]
     expected: FAIL
     bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1547106
 
--- a/testing/web-platform/meta/webrtc/idlharness.https.window.js.ini
+++ b/testing/web-platform/meta/webrtc/idlharness.https.window.js.ini
@@ -276,19 +276,16 @@
     expected: FAIL
 
   [RTCRtpSender interface: operation getCapabilities(DOMString)]
     expected: FAIL
 
   [RTCPeerConnectionIceErrorEvent interface: new RTCPeerConnectionIceErrorEvent('ice-error', { errorCode: 701 }); must inherit property "errorText" with the proper type]
     expected: FAIL
 
-  [RTCDataChannel interface: attribute negotiated]
-    expected: FAIL
-
   [RTCRtpReceiver interface: attribute transport]
     expected: FAIL
 
   [Stringification of new RTCPeerConnectionIceErrorEvent('ice-error', { errorCode: 701 });]
     expected: FAIL
 
   [RTCIceTransport interface: idlTestObjects.iceTransport must inherit property "getLocalParameters()" with the proper type]
     expected: FAIL
@@ -396,19 +393,16 @@
     expected: FAIL
 
   [RTCCertificate interface: operation getSupportedAlgorithms()]
     expected: FAIL
 
   [RTCIceTransport interface: attribute onstatechange]
     expected: FAIL
 
-  [RTCDataChannel interface: new RTCPeerConnection().createDataChannel('') must inherit property "negotiated" with the proper type]
-    expected: FAIL
-
   [RTCStatsEvent interface: existence and properties of interface prototype object's "constructor" property]
     expected: FAIL
 
   [RTCStatsEvent interface: existence and properties of interface prototype object's @@unscopables property]
     expected: FAIL
 
   [RTCIceTransport interface: idlTestObjects.iceTransport must inherit property "role" with the proper type]
     expected: FAIL