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