diff --git a/devtools/client/netmonitor/test/browser.ini b/devtools/client/netmonitor/test/browser.ini
index 369ca0317aa3c..bf0b1cbf36e11 100644
--- a/devtools/client/netmonitor/test/browser.ini
+++ b/devtools/client/netmonitor/test/browser.ini
@@ -44,6 +44,9 @@ support-files =
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
@@ -221,3 +224,4 @@ skip-if = true # TODO: fix the test
[browser_net_truncate.js]
[browser_net_view-source-debugger.js]
[browser_net_waterfall-click.js]
+[browser_net_worker_stacks.js]
diff --git a/devtools/client/netmonitor/test/browser_net_cause.js b/devtools/client/netmonitor/test/browser_net_cause.js
index bcb66cadffe00..dee628e7b87c7 100644
--- a/devtools/client/netmonitor/test/browser_net_cause.js
+++ b/devtools/client/netmonitor/test/browser_net_cause.js
@@ -93,7 +93,6 @@ add_task(async function() {
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");
@@ -110,44 +109,7 @@ add_task(async function() {
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" },
diff --git a/devtools/client/netmonitor/test/browser_net_worker_stacks.js b/devtools/client/netmonitor/test/browser_net_worker_stacks.js
new file mode 100644
index 0000000000000..238d20628e22c
--- /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);
+});
diff --git a/devtools/client/netmonitor/test/head.js b/devtools/client/netmonitor/test/head.js
index 29201c1c1130c..ca788ad425e81 100644
--- a/devtools/client/netmonitor/test/head.js
+++ b/devtools/client/netmonitor/test/head.js
@@ -869,6 +869,53 @@ function queryTelemetryEvents(query) {
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.
diff --git a/devtools/client/netmonitor/test/html_worker-test-page.html b/devtools/client/netmonitor/test/html_worker-test-page.html
new file mode 100644
index 0000000000000..46f64368a194f
--- /dev/null
+++ b/devtools/client/netmonitor/test/html_worker-test-page.html
@@ -0,0 +1,13 @@
+
diff --git a/devtools/client/netmonitor/test/js_worker-test.js b/devtools/client/netmonitor/test/js_worker-test.js
new file mode 100644
index 0000000000000..cf48ac6f9437e
--- /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);
+}
diff --git a/devtools/client/netmonitor/test/js_worker-test2.js b/devtools/client/netmonitor/test/js_worker-test2.js
new file mode 100644
index 0000000000000..9ee307f2ec9ab
--- /dev/null
+++ b/devtools/client/netmonitor/test/js_worker-test2.js
@@ -0,0 +1,3 @@
+"use strict";
+
+console.log("I AM A WORKER");
diff --git a/devtools/server/actors/network-monitor/stack-trace-collector.js b/devtools/server/actors/network-monitor/stack-trace-collector.js
index d1e28e9821518..46f59908ce9a2 100644
--- a/devtools/server/actors/network-monitor/stack-trace-collector.js
+++ b/devtools/server/actors/network-monitor/stack-trace-collector.js
@@ -25,6 +25,7 @@ function StackTraceCollector(filters, 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) {
@@ -34,6 +35,7 @@ StackTraceCollector.prototype = {
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",
@@ -42,6 +44,12 @@ StackTraceCollector.prototype = {
},
_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,
@@ -51,29 +59,66 @@ StackTraceCollector.prototype = {
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);
diff --git a/dom/base/nsDOMDataChannel.cpp b/dom/base/nsDOMDataChannel.cpp
index 1aa409b95fe4d..f1019258165e4 100644
--- a/dom/base/nsDOMDataChannel.cpp
+++ b/dom/base/nsDOMDataChannel.cpp
@@ -142,6 +142,8 @@ mozilla::dom::Nullable nsDOMDataChannel::GetMaxRetransmits() const {
return mDataChannel->GetMaxRetransmits();
}
+bool nsDOMDataChannel::Negotiated() const { return mDataChannel->GetNegotiated(); }
+
bool nsDOMDataChannel::Ordered() const { return mDataChannel->GetOrdered(); }
RTCDataChannelState nsDOMDataChannel::ReadyState() const {
diff --git a/dom/base/nsDOMDataChannel.h b/dom/base/nsDOMDataChannel.h
index 0de40f55b0a82..d6cbbc6638780 100644
--- a/dom/base/nsDOMDataChannel.h
+++ b/dom/base/nsDOMDataChannel.h
@@ -74,6 +74,7 @@ class nsDOMDataChannel final : public mozilla::DOMEventTargetHelper,
void Send(const mozilla::dom::ArrayBufferView& aData,
mozilla::ErrorResult& aRv);
+ bool Negotiated() const;
bool Ordered() const;
mozilla::dom::Nullable GetId() const;
diff --git a/dom/webidl/RTCDataChannel.webidl b/dom/webidl/RTCDataChannel.webidl
index 8d83d5f1f0d2b..551e64919c748 100644
--- a/dom/webidl/RTCDataChannel.webidl
+++ b/dom/webidl/RTCDataChannel.webidl
@@ -17,6 +17,7 @@ enum RTCDataChannelType {
interface RTCDataChannel : EventTarget
{
readonly attribute DOMString label;
+ readonly attribute boolean negotiated;
readonly attribute boolean ordered;
readonly attribute boolean reliable;
readonly attribute unsigned short? maxPacketLifeTime;
diff --git a/layout/printing/nsPrintPreviewListener.cpp b/layout/printing/PrintPreviewUserEventSuppressor.cpp
similarity index 84%
rename from layout/printing/nsPrintPreviewListener.cpp
rename to layout/printing/PrintPreviewUserEventSuppressor.cpp
index 37d184903f771..60bae773c2b74 100644
--- a/layout/printing/nsPrintPreviewListener.cpp
+++ b/layout/printing/PrintPreviewUserEventSuppressor.cpp
@@ -4,7 +4,7 @@
* 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"
@@ -17,28 +17,19 @@
#include "nsFocusManager.h"
#include "nsLiteralString.h"
-using namespace mozilla;
using namespace mozilla::dom;
-NS_IMPL_ISUPPORTS(nsPrintPreviewListener, nsIDOMEventListener)
+namespace mozilla {
-//
-// nsPrintPreviewListener ctor
-//
-nsPrintPreviewListener::nsPrintPreviewListener(EventTarget* aTarget)
+PrintPreviewUserEventSuppressor::PrintPreviewUserEventSuppressor(
+ EventTarget* aTarget)
: mEventTarget(aTarget) {
- NS_ADDREF_THIS();
-} // ctor
-
-nsPrintPreviewListener::~nsPrintPreviewListener() {}
-
-//-------------------------------------------------------
-//
-// AddListeners
-//
-// Subscribe to the events that will allow us to track various events.
-//
-nsresult nsPrintPreviewListener::AddListeners() {
+ 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,
@@ -55,17 +46,9 @@ nsresult nsPrintPreviewListener::AddListeners() {
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,
@@ -87,16 +70,8 @@ nsresult nsPrintPreviewListener::RemoveListeners() {
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,
@@ -105,6 +80,7 @@ enum eEventAction {
eEventAction_StopPropagation
};
+// Helper function to let certain key events through
static eEventAction GetActionForEvent(Event* aEvent) {
WidgetKeyboardEvent* keyEvent = aEvent->WidgetEventPtr()->AsKeyboardEvent();
if (!keyEvent) {
@@ -150,11 +126,11 @@ static eEventAction GetActionForEvent(Event* aEvent) {
}
NS_IMETHODIMP
-nsPrintPreviewListener::HandleEvent(Event* aEvent) {
+PrintPreviewUserEventSuppressor::HandleEvent(Event* aEvent) {
nsCOMPtr 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: {
@@ -173,10 +149,9 @@ nsPrintPreviewListener::HandleEvent(Event* aEvent) {
nsIFocusManager* fm = nsFocusManager::GetFocusManager();
if (fm && win) {
- dom::Element* fromElement =
- parentDoc->FindContentForSubDocument(doc);
+ Element* fromElement = parentDoc->FindContentForSubDocument(doc);
bool forward = (action == eEventAction_Tab);
- RefPtr result;
+ RefPtr result;
fm->MoveFocus(win, fromElement,
forward ? nsIFocusManager::MOVEFOCUS_FORWARD
: nsIFocusManager::MOVEFOCUS_BACKWARD,
@@ -199,3 +174,5 @@ nsPrintPreviewListener::HandleEvent(Event* aEvent) {
}
return NS_OK;
}
+
+} // namespace mozilla
diff --git a/layout/printing/PrintPreviewUserEventSuppressor.h b/layout/printing/PrintPreviewUserEventSuppressor.h
new file mode 100644
index 0000000000000..1a4f1649c5791
--- /dev/null
+++ b/layout/printing/PrintPreviewUserEventSuppressor.h
@@ -0,0 +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 mozilla_PrintPreviewUserEventSuppressor_h
+#define mozilla_PrintPreviewUserEventSuppressor_h
+
+#include "nsCOMPtr.h"
+#include "nsIDOMEventListener.h"
+#include "mozilla/Attributes.h"
+
+namespace mozilla {
+
+namespace dom {
+class EventTarget;
+} // namespace dom
+
+/**
+ * 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 PrintPreviewUserEventSuppressor(dom::EventTarget* aTarget);
+
+ /**
+ * 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:
+ ~PrintPreviewUserEventSuppressor() { RemoveListeners(); }
+
+ void AddListeners();
+ void RemoveListeners();
+
+ nsCOMPtr mEventTarget;
+};
+
+} // namespace mozilla
+
+#endif // mozilla_PrintPreviewUserEventSuppressor_h
diff --git a/layout/printing/moz.build b/layout/printing/moz.build
index a63a8a909c6d2..37b859757087b 100644
--- a/layout/printing/moz.build
+++ b/layout/printing/moz.build
@@ -28,7 +28,7 @@ UNIFIED_SOURCES += [
'nsPrintData.cpp',
'nsPrintJob.cpp',
'nsPrintObject.cpp',
- 'nsPrintPreviewListener.cpp',
+ 'PrintPreviewUserEventSuppressor.cpp',
'PrintTranslator.cpp',
]
diff --git a/layout/printing/nsPrintData.cpp b/layout/printing/nsPrintData.cpp
index 012b3be0143ea..e0ac4e9421ab7 100644
--- a/layout/printing/nsPrintData.cpp
+++ b/layout/printing/nsPrintData.cpp
@@ -10,9 +10,9 @@
#include "nsIServiceManager.h"
#include "nsIWidget.h"
#include "nsPrintObject.h"
-#include "nsPrintPreviewListener.h"
#include "nsIWebProgressListener.h"
#include "mozilla/Services.h"
+#include "PrintPreviewUserEventSuppressor.h"
//-----------------------------------------------------
// PR LOGGING
@@ -38,8 +38,7 @@ nsPrintData::nsPrintData(ePrintDataType aType)
mPrintFrameType(nsIPrintSettings::kFramesAsIs),
mNumPrintablePages(0),
mNumPagesPrinted(0),
- mShrinkRatio(1.0),
- mPPEventListeners(nullptr) {
+ mShrinkRatio(1.0) {
nsCOMPtr brandBundle;
nsCOMPtr svc =
mozilla::services::GetStringBundleService();
@@ -57,10 +56,9 @@ nsPrintData::nsPrintData(ePrintDataType aType)
}
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
diff --git a/layout/printing/nsPrintData.h b/layout/printing/nsPrintData.h
index e8b2a58024402..c3c599e71905b 100644
--- a/layout/printing/nsPrintData.h
+++ b/layout/printing/nsPrintData.h
@@ -18,11 +18,13 @@
#include "nsTArray.h"
#include "nsCOMArray.h"
-// Classes
class nsPrintObject;
-class nsPrintPreviewListener;
class nsIWebProgressListener;
+namespace mozilla {
+class PrintPreviewUserEventSuppressor;
+} // namespace mozilla
+
//------------------------------------------------------------------------
// nsPrintData Class
//
@@ -38,6 +40,9 @@ class nsIWebProgressListener;
//
//------------------------------------------------------------------------
class nsPrintData {
+ typedef mozilla::PrintPreviewUserEventSuppressor
+ PrintPreviewUserEventSuppressor;
+
public:
typedef enum { eIsPrinting, eIsPrintPreview } ePrintDataType;
@@ -82,7 +87,7 @@ class nsPrintData {
float mShrinkRatio;
nsCOMPtr mPrintSettings;
- nsPrintPreviewListener* mPPEventListeners;
+ RefPtr mPPEventSuppressor;
nsString mBrandName; // needed as a substitute name for a document
diff --git a/layout/printing/nsPrintJob.cpp b/layout/printing/nsPrintJob.cpp
index c0f17f37188c5..32cdc482d58c8 100644
--- a/layout/printing/nsPrintJob.cpp
+++ b/layout/printing/nsPrintJob.cpp
@@ -38,8 +38,6 @@
static const char sPrintSettingsServiceContractID[] =
"@mozilla.org/gfx/printsettings-service;1";
-// Printing Events
-#include "nsPrintPreviewListener.h"
#include "nsThreadUtils.h"
// Printing
@@ -116,6 +114,7 @@ static const char kPrintingPromptService[] =
#include "mozilla/dom/HTMLFrameElement.h"
#include "nsContentList.h"
#include "nsIChannel.h"
+#include "PrintPreviewUserEventSuppressor.h"
#include "xpcpublic.h"
#include "nsVariant.h"
#include "mozilla/ServoStyleSet.h"
@@ -571,8 +570,8 @@ nsresult nsPrintJob::Cancelled() {
// 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 docShell = do_QueryReferent(mContainer);
if (!docShell) {
return;
@@ -580,8 +579,7 @@ void nsPrintJob::InstallPrintPreviewListener() {
if (nsPIDOMWindowOuter* win = docShell->GetWindow()) {
nsCOMPtr target = win->GetFrameElementInternal();
- mPrt->mPPEventListeners = new nsPrintPreviewListener(target);
- mPrt->mPPEventListeners->AddListeners();
+ mPrt->mPPEventSuppressor = new PrintPreviewUserEventSuppressor(target);
}
}
}
@@ -1007,7 +1005,7 @@ nsresult nsPrintJob::DoCommonPrint(bool aIsPrintPreview,
TurnScriptingOn(false);
if (!notifyOnInit) {
- InstallPrintPreviewListener();
+ SuppressPrintPreviewUserEvents();
rv = InitPrintDocConstruction(false);
} else {
rv = NS_OK;
diff --git a/layout/printing/nsPrintJob.h b/layout/printing/nsPrintJob.h
index 9f5b3b635d424..c03359b2a7130 100644
--- a/layout/printing/nsPrintJob.h
+++ b/layout/printing/nsPrintJob.h
@@ -109,7 +109,13 @@ class nsPrintJob final : public nsIObserver,
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();
diff --git a/layout/printing/nsPrintPreviewListener.h b/layout/printing/nsPrintPreviewListener.h
deleted file mode 100644
index 1db187d244ecd..0000000000000
--- a/layout/printing/nsPrintPreviewListener.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/* -*- 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__
-
-// Interfaces needed to be included
-#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
-
-{
- public:
- NS_DECL_ISUPPORTS
- NS_DECL_NSIDOMEVENTLISTENER
-
- explicit nsPrintPreviewListener(mozilla::dom::EventTarget* aTarget);
-
- // Add/remove the relevant listeners, based on what interfaces
- // the embedding chrome implements.
- nsresult AddListeners();
- nsresult RemoveListeners();
-
- private:
- ~nsPrintPreviewListener();
-
- nsCOMPtr mEventTarget;
-
-}; // class nsPrintPreviewListener
-
-#endif /* nsPrintPreviewListener_h__ */
diff --git a/layout/reftests/display-list/reftest.list b/layout/reftests/display-list/reftest.list
index 3ce01d7811726..0856e1760fec2 100644
--- a/layout/reftests/display-list/reftest.list
+++ b/layout/reftests/display-list/reftest.list
@@ -41,4 +41,4 @@ fuzzy(0-2,0-40000) skip-if(!asyncPan) == 1464288-1.html 1464288-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
diff --git a/layout/reftests/w3c-css/submitted/contain/reftest.list b/layout/reftests/w3c-css/submitted/contain/reftest.list
index e544aef5dacac..744554a7d3000 100644
--- a/layout/reftests/w3c-css/submitted/contain/reftest.list
+++ b/layout/reftests/w3c-css/submitted/contain/reftest.list
@@ -48,7 +48,7 @@ fuzzy-if(webrender&&winWidget,0-24,0-2) == contain-size-inline-flex-001.html con
== 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
diff --git a/media/libcubeb/disable-device-switching.patch b/media/libcubeb/disable-device-switching.patch
deleted file mode 100644
index 630a21f5c8b0f..0000000000000
--- 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;
-
diff --git a/media/libcubeb/moz.yaml b/media/libcubeb/moz.yaml
index 370a4c27052c0..3097706412557 100644
--- a/media/libcubeb/moz.yaml
+++ b/media/libcubeb/moz.yaml
@@ -19,5 +19,5 @@ origin:
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)"
diff --git a/media/libcubeb/update.sh b/media/libcubeb/update.sh
index 08f91d2ac31db..3e36ba99c1678 100755
--- a/media/libcubeb/update.sh
+++ b/media/libcubeb/update.sh
@@ -90,6 +90,3 @@ 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
diff --git a/netwerk/sctp/datachannel/DataChannel.h b/netwerk/sctp/datachannel/DataChannel.h
index fa74124bd2015..5f9d24211538c 100644
--- a/netwerk/sctp/datachannel/DataChannel.h
+++ b/netwerk/sctp/datachannel/DataChannel.h
@@ -384,6 +384,7 @@ class DataChannel {
mStream(stream),
mPrPolicy(policy),
mPrValue(value),
+ mNegotiated(negotiated),
mOrdered(ordered),
mFlags(0),
mId(0),
@@ -439,6 +440,8 @@ class DataChannel {
dom::Nullable GetMaxRetransmits() const;
+ bool GetNegotiated() { return mNegotiated; }
+
bool GetOrdered() { return mOrdered; }
void IncrementBufferedAmount(uint32_t aSize, ErrorResult& aRv);
@@ -493,6 +496,7 @@ class DataChannel {
uint16_t mStream;
uint16_t mPrPolicy;
uint32_t mPrValue;
+ const bool mNegotiated;
const bool mOrdered;
uint32_t mFlags;
uint32_t mId;
diff --git a/testing/web-platform/meta/webrtc/RTCPeerConnection-createDataChannel.html.ini b/testing/web-platform/meta/webrtc/RTCPeerConnection-createDataChannel.html.ini
index 359a92245578c..594ba1065a264 100644
--- a/testing/web-platform/meta/webrtc/RTCPeerConnection-createDataChannel.html.ini
+++ b/testing/web-platform/meta/webrtc/RTCPeerConnection-createDataChannel.html.ini
@@ -1,7 +1,7 @@
[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
@@ -23,14 +23,6 @@
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
diff --git a/testing/web-platform/meta/webrtc/idlharness.https.window.js.ini b/testing/web-platform/meta/webrtc/idlharness.https.window.js.ini
index 6a6606441533a..911c7193f831f 100644
--- a/testing/web-platform/meta/webrtc/idlharness.https.window.js.ini
+++ b/testing/web-platform/meta/webrtc/idlharness.https.window.js.ini
@@ -281,9 +281,6 @@
[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
@@ -401,9 +398,6 @@
[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