From 137091cd8ff39166f484dd8236eb0e4238c33fef Mon Sep 17 00:00:00 2001 From: roytam1 Date: Tue, 5 Sep 2023 16:52:50 +0800 Subject: [PATCH] import changes from `dev' branch of rmottola/Arctic-Fox: - Bug 912337 - Followup: fix missing #include on a CLOSED TREE. (da77dc4ba0) - Bug 1232977 - Remove redundant bitand with uint{8,16} and an all-bits-set mask. r=nbp, r=sunfish (164579d9d7) - Bug 1249235 - Store RegExp flags into single slot. r=h4writer (6f030c9f06) - Bug 1237445 - Use GCHashSet for RegExpShared sweeping, r=terrence (3aab1397e8) - Bug 1238536 part 1 - Do not automatically exit fullscreen if restored from minimized state. r=jimm (05dd086d29) - Bug 1238536 part 2 - Do not trigger fullscreen changed when switching between fullscreen and minimized. r=karlt (83e862cc7a) - Bug 1233598 - HTMLInputElement must traverse/unlink the getFilesAndDirectories promise, r=smaug (1ff7260803) - Bug 1187157 - new FormData::get() should return an empty string if the file is not set - part 1, r=smaug (9a255fd884) - Bug 1187157 - new FormData::get() should return an empty string if the file is not set - part 2, r=smaug (f26712d951) - Bug 1216793 - check against tracking protection list in XHR. r=gcp (3a827250bc) - Bug 1203588 - Return the same Promise object from HTMLInputElement.getFilesAndDirectories when possible. r=baku (f036876c1b) - Bug 1207088 - Don't show the "Choose folder..." button for a directory picking on platforms that don't have a directory picker. r=jfkthame (c5742f75c9) - Bug 1234192 - OSFileSystem should not be shared between Directory objects, r=smaug (ba258935b7) - Bug 1202964 - Use the correct nsIFilePicker API for directory picking in HTMLInputElement::nsFilePickerShownCallback::Done. r=baku (ce11a83ace) - Bug 1237674 - Rename nsFormData to mozilla::dom::FormData, r=smaug (0a18825b2b) - Bug 1237595 - FormData ctor and form submission should create empty Blob/File when a input type=file is not set, r=smaug (2bce85bbe8) - cleanup some stuff (cbd553db88) - Bug 1238515 - nsIFilePicker methods should clearly say when they return directories and files, r=smaug (e903765f0c) - Bug 1198256 - Replace deprecated GtkColorSelectionDialog with GtkColorChooserDialog in Gtk3. r=karlt (2ff87896a6) - Bug 1198256 - Reactivate the old Gtk color picker for now. r=karlt (ea42685de9) - Bug 1213632: Prevent WebExtensions from using versioned JavaScript. r=billm (9d3a9b7511) - Bug 1219855, Part 1 - Make nsXULAlerts implement nsIAlertsService. r=MattN,wchen (6b21425554) - Bug 1219855, Part 2 - Always use XUL notifications if the system backend fails. r=wchen (7c5b30fd2c) - Bug 1219855, Part 3 - Fix variable shadowing in `OSXNotificationCenter::ShowAlert`. r=me (29e442fe45) - Bug 1241377 - Part 1: Implement nsIFormPOSTActionChannel for the channel accepts form POST. r=mayhemer (f03e9dbece) - Bug 1241377 - Part 2: Add test for nsIFormPOSTActionChannel. r=mayhemer (0a9e7aab1f) - Bug 1207824: Add Telemetry for WebRTC call type, simultaneous tracks, and renegotiations r=bwc (38085ce155) - Bug 1175609 - Bring onnegotiationneeded in line with spec. r=mt (398c03db6e) - Bug 1209252 - Part 2: typo fix for compile issue. r=bustage on a CLOSED TREE (e1b8f43993) - Bug 1221786: clear about:webrtc logs for private browsing sessions. r=jib (49615cc3c6) - Bug 1232082 - add RTCRtpReceiver for each remote track. r=jesup (1231223782) - Bug 1219711 - Remove fakeness from webrtc tests. r=jib (b421c55124) - Bug 1232082 - add pc.ontrack and RTCTrackEvent r=jesup,smaug (f915ecc77c) - Bug 1222127: Use the inner window to compute style. r=baku (a3ea812154) - Bug 1209634 - Remove unused WindowTarget. r=past (1f2d218cb4) - Bug 1209634 - Remove unused target.version. r=past (7ddf6cdfb1) - Bug 1209634 - Reformat target.js to match ESLint rules. r=past (8fe93b4737) - Bug 1168853 - Implement WorkerDebugger.isInitialized;r=khuey (318bd9516c) - Bug 1150444 - Intermittent test_WorkerDebugger.isFrozen.xul;r=khuey (e787b9c935) - Mark test_bug883784.jsm as a support file, no bug (c6c987138d) - Bug 1178726 - Simplify how we deal with freezing/thawing workers;r=jlongster,khuey (88c7341f8f) - Bug 1228382 - Expose an API to relate nsIWorkerDebugger to its nsIServiceWorkerInfo instance. r=ejpbruel (26ce55693f) --- accessible/windows/msaa/nsWinUtils.cpp | 4 +- b2g/components/FilePicker.js | 5 +- docshell/base/nsDocShell.cpp | 86 ++--- dom/base/File.cpp | 26 ++ dom/base/File.h | 25 ++ dom/base/{nsFormData.cpp => FormData.cpp} | 110 ++++--- dom/base/{nsFormData.h => FormData.h} | 95 +++--- dom/base/Navigator.cpp | 4 +- dom/base/StructuredCloneHolder.cpp | 10 +- dom/base/moz.build | 4 +- dom/base/nsXMLHttpRequest.cpp | 5 +- dom/base/nsXMLHttpRequest.h | 9 +- dom/base/test/mochitest.ini | 1 + dom/base/test/test_bug1187157.html | 30 ++ dom/bindings/Bindings.conf | 4 - dom/events/DataTransfer.cpp | 29 +- .../test/test_all_synthetic_events.html | 3 + dom/fetch/Fetch.cpp | 10 +- dom/fetch/FetchUtil.cpp | 20 +- dom/fetch/FetchUtil.h | 4 +- dom/html/HTMLFormElement.cpp | 2 +- dom/html/HTMLInputElement.cpp | 64 ++-- dom/html/HTMLInputElement.h | 1 + dom/html/nsFormSubmission.cpp | 101 +++--- dom/html/test/test_formSubmission.html | 3 +- .../base/nsIServiceWorkerManager.idl | 13 +- dom/media/PeerConnection.js | 40 ++- .../mochitest/identity/identityPcTest.js | 1 - ...st_peerConnection_asymmetricIsolation.html | 3 +- .../mochitest/test_enumerateDevices.html | 9 +- .../test_getUserMedia_basicTabshare.html | 70 +++++ .../test_getUserMedia_constraints.html | 14 +- .../test_getUserMedia_peerIdentity.html | 2 +- .../test_peerConnection_callbacks.html | 2 +- .../test_peerConnection_promiseSendOnly.html | 38 ++- ..._peerConnection_remoteReofferRollback.html | 5 +- .../test_peerConnection_remoteRollback.html | 4 + .../test_peerConnection_replaceTrack.html | 18 +- ...onnection_replaceVideoThenRenegotiate.html | 2 +- .../test_peerConnection_throwInCallbacks.html | 2 +- .../mochitest/general/test_interfaces.html | 2 + dom/webidl/PeerConnectionObserver.webidl | 2 +- dom/webidl/RTCPeerConnection.webidl | 5 +- dom/webidl/RTCTrackEvent.webidl | 27 ++ dom/webidl/moz.build | 1 + dom/workers/ServiceWorkerManager.cpp | 38 +++ dom/workers/WorkerPrivate.cpp | 91 +++--- dom/workers/WorkerPrivate.h | 13 - dom/workers/XMLHttpRequest.cpp | 4 +- dom/workers/XMLHttpRequest.h | 2 +- dom/workers/nsIWorkerDebugger.idl | 15 +- ...tml => WorkerDebugger_frozen_iframe1.html} | 2 +- ...tml => WorkerDebugger_frozen_iframe2.html} | 2 +- ...r1.js => WorkerDebugger_frozen_worker1.js} | 0 ...r2.js => WorkerDebugger_frozen_worker2.js} | 0 dom/workers/test/chrome.ini | 13 +- dom/workers/test/dom_worker_helper.js | 23 +- .../serviceworkers/test_serviceworkerinfo.xul | 16 +- ...zen.xul => test_WorkerDebugger_frozen.xul} | 44 ++- js/src/jit/IonBuilder.cpp | 12 + js/src/jit/IonBuilder.h | 2 + js/src/jit/MCallOptimize.cpp | 25 +- js/src/jit/MIR.cpp | 10 + js/src/jit/MIR.h | 25 +- js/src/jit/RangeAnalysis.cpp | 38 +++ js/src/vm/Debugger.cpp | 1 + js/src/vm/RegExpObject.cpp | 71 ++--- js/src/vm/RegExpObject.h | 58 +--- layout/build/nsLayoutModule.cpp | 6 +- layout/forms/nsFileControlFrame.cpp | 9 +- media/mtransport/nricectx.cpp | 1 - media/mtransport/rlogringbuffer.cpp | 41 ++- media/mtransport/rlogringbuffer.h | 9 +- media/webrtc/signaling/src/jsep/JsepSession.h | 30 +- .../signaling/src/jsep/JsepSessionImpl.cpp | 2 + .../src/peerconnection/PeerConnectionImpl.cpp | 179 ++++++++++- .../src/peerconnection/PeerConnectionImpl.h | 12 +- .../signaling/src/sdp/SdpMediaSection.h | 2 + netwerk/base/moz.build | 1 + netwerk/base/nsIFormPOSTActionChannel.idl | 17 + netwerk/protocol/http/HttpBaseChannel.cpp | 1 + netwerk/protocol/http/HttpBaseChannel.h | 5 +- netwerk/protocol/http/nsHttpChannel.cpp | 1 + .../viewsource/nsViewSourceChannel.cpp | 2 + .../protocol/viewsource/nsViewSourceChannel.h | 6 +- netwerk/test/browser/browser.ini | 2 + .../browser_nsIFormPOSTActionChannel.js | 284 +++++++++++++++++ .../specialpowers/content/MockFilePicker.jsm | 6 +- .../rtcpeerconnection-idl.html.ini | 280 ++++++++++++++++- .../components/alerts/AlertNotification.cpp | 16 + toolkit/components/alerts/nsAlertsService.cpp | 108 +++---- toolkit/components/alerts/nsAlertsService.h | 3 +- .../components/alerts/nsIAlertsService.idl | 18 +- toolkit/components/alerts/nsXULAlerts.cpp | 127 ++++++-- toolkit/components/alerts/nsXULAlerts.h | 26 +- toolkit/components/build/nsToolkitCompsCID.h | 6 + .../components/build/nsToolkitCompsModule.cpp | 13 +- .../test/mochitest/test_ext_jsversion.html | 84 +++++ toolkit/components/filepicker/nsFilePicker.js | 10 +- toolkit/components/telemetry/Histograms.json | 92 ++++++ toolkit/devtools/client/dbg-client.jsm | 24 +- .../devtools/debugger/debugger-controller.js | 49 +-- toolkit/devtools/framework/gDevTools.jsm | 8 - toolkit/devtools/framework/target.js | 295 +++++------------- toolkit/devtools/server/actors/worker.js | 9 - .../mozapps/extensions/AddonContentPolicy.cpp | 145 +++++++++ .../mozapps/extensions/AddonContentPolicy.h | 19 ++ toolkit/mozapps/extensions/moz.build | 4 +- widget/cocoa/OSXNotificationCenter.mm | 106 +++---- widget/gtk/mozgtk/mozgtk.c | 6 + widget/gtk/nsColorPicker.cpp | 122 ++++++-- widget/gtk/nsColorPicker.h | 32 +- widget/gtk/nsWindow.cpp | 8 +- widget/nsBaseFilePicker.cpp | 13 +- widget/nsBaseFilePicker.h | 4 +- widget/nsFilePickerProxy.cpp | 26 +- widget/nsFilePickerProxy.h | 12 +- widget/nsIFilePicker.idl | 14 +- widget/windows/nsWindow.cpp | 20 +- 119 files changed, 2616 insertions(+), 1119 deletions(-) rename dom/base/{nsFormData.cpp => FormData.cpp} (73%) rename dom/base/{nsFormData.h => FormData.h} (65%) create mode 100644 dom/base/test/test_bug1187157.html create mode 100644 dom/media/tests/mochitest/test_getUserMedia_basicTabshare.html create mode 100644 dom/webidl/RTCTrackEvent.webidl rename dom/workers/test/{WorkerDebugger.isFrozen_iframe1.html => WorkerDebugger_frozen_iframe1.html} (77%) rename dom/workers/test/{WorkerDebugger.isFrozen_iframe2.html => WorkerDebugger_frozen_iframe2.html} (77%) rename dom/workers/test/{WorkerDebugger.isFrozen_worker1.js => WorkerDebugger_frozen_worker1.js} (100%) rename dom/workers/test/{WorkerDebugger.isFrozen_worker2.js => WorkerDebugger_frozen_worker2.js} (100%) rename dom/workers/test/{test_WorkerDebugger.isFrozen.xul => test_WorkerDebugger_frozen.xul} (65%) create mode 100644 netwerk/base/nsIFormPOSTActionChannel.idl create mode 100644 netwerk/test/browser/browser_nsIFormPOSTActionChannel.js create mode 100644 toolkit/components/extensions/test/mochitest/test_ext_jsversion.html create mode 100644 toolkit/mozapps/extensions/AddonContentPolicy.cpp create mode 100644 toolkit/mozapps/extensions/AddonContentPolicy.h diff --git a/accessible/windows/msaa/nsWinUtils.cpp b/accessible/windows/msaa/nsWinUtils.cpp index 96a2ddb32f..7e3a892740 100644 --- a/accessible/windows/msaa/nsWinUtils.cpp +++ b/accessible/windows/msaa/nsWinUtils.cpp @@ -43,8 +43,8 @@ nsWinUtils::GetComputedStyleDeclaration(nsIContent* aContent) return nullptr; // Returns number of items in style declaration - nsCOMPtr window = - do_QueryInterface(elm->OwnerDoc()->GetWindow()); + nsCOMPtr window = + do_QueryInterface(elm->OwnerDoc()->GetInnerWindow()); if (!window) return nullptr; diff --git a/b2g/components/FilePicker.js b/b2g/components/FilePicker.js index b538cb17c0..803eef6818 100644 --- a/b2g/components/FilePicker.js +++ b/b2g/components/FilePicker.js @@ -71,11 +71,12 @@ FilePicker.prototype = { /* readonly attribute nsISimpleEnumerator files - not implemented; */ /* readonly attribute nsIURI fileURL - not implemented; */ - get domfiles() { + get domFileOrDirectoryEnumerator() { return this.mFilesEnumerator; }, - get domfile() { + // We don't support directory selection yet. + get domFileOrDirectory() { return this.mFilesEnumerator ? this.mFilesEnumerator.mFiles[0] : null; }, diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 83d67585d6..7277377e05 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -104,6 +104,7 @@ #include "nsEscape.h" // Interfaces Needed +#include "nsIFormPOSTActionChannel.h" #include "nsIUploadChannel.h" #include "nsIUploadChannel2.h" #include "nsIWebProgress.h" @@ -10777,23 +10778,21 @@ nsDocShell::DoURILoad(nsIURI* aURI, aReferrerURI); } - // - // If this is a HTTP channel, then set up the HTTP specific information - // (ie. POST data, referrer, ...) - // - if (httpChannel) { - nsCOMPtr cacheChannel(do_QueryInterface(httpChannel)); - /* Get the cache Key from SH */ - nsCOMPtr cacheKey; + nsCOMPtr cacheChannel(do_QueryInterface(channel)); + /* Get the cache Key from SH */ + nsCOMPtr cacheKey; + if (cacheChannel) { if (mLSHE) { mLSHE->GetCacheKey(getter_AddRefs(cacheKey)); } else if (mOSHE) { // for reload cases mOSHE->GetCacheKey(getter_AddRefs(cacheKey)); } + } - // figure out if we need to set the post data stream on the channel... - // right now, this is only done for http channels..... - if (aPostData) { + // figure out if we need to set the post data stream on the channel... + if (aPostData) { + nsCOMPtr postChannel(do_QueryInterface(channel)); + if (postChannel) { // XXX it's a bit of a hack to rewind the postdata stream here but // it has to be done in case the post data is being reused multiple // times. @@ -10804,44 +10803,45 @@ nsDocShell::DoURILoad(nsIURI* aURI, NS_ENSURE_SUCCESS(rv, rv); } - nsCOMPtr uploadChannel(do_QueryInterface(httpChannel)); - NS_ASSERTION(uploadChannel, "http must support nsIUploadChannel"); - // we really need to have a content type associated with this stream!! - uploadChannel->SetUploadStream(aPostData, EmptyCString(), -1); - /* If there is a valid postdata *and* it is a History Load, - * set up the cache key on the channel, to retrieve the - * data *only* from the cache. If it is a normal reload, the - * cache is free to go to the server for updated postdata. - */ - if (cacheChannel && cacheKey) { - if (mLoadType == LOAD_HISTORY || - mLoadType == LOAD_RELOAD_CHARSET_CHANGE) { - cacheChannel->SetCacheKey(cacheKey); - uint32_t loadFlags; - if (NS_SUCCEEDED(channel->GetLoadFlags(&loadFlags))) { - channel->SetLoadFlags( - loadFlags | nsICachingChannel::LOAD_ONLY_FROM_CACHE); - } - } else if (mLoadType == LOAD_RELOAD_NORMAL) { - cacheChannel->SetCacheKey(cacheKey); - } - } - } else { - /* If there is no postdata, set the cache key on the channel, and - * do not set the LOAD_ONLY_FROM_CACHE flag, so that the channel - * will be free to get it from net if it is not found in cache. - * New cache may use it creatively on CGI pages with GET - * method and even on those that say "no-cache" - */ + postChannel->SetUploadStream(aPostData, EmptyCString(), -1); + } + + /* If there is a valid postdata *and* it is a History Load, + * set up the cache key on the channel, to retrieve the + * data *only* from the cache. If it is a normal reload, the + * cache is free to go to the server for updated postdata. + */ + if (cacheChannel && cacheKey) { if (mLoadType == LOAD_HISTORY || - mLoadType == LOAD_RELOAD_NORMAL || mLoadType == LOAD_RELOAD_CHARSET_CHANGE) { - if (cacheChannel && cacheKey) { - cacheChannel->SetCacheKey(cacheKey); + cacheChannel->SetCacheKey(cacheKey); + uint32_t loadFlags; + if (NS_SUCCEEDED(channel->GetLoadFlags(&loadFlags))) { + channel->SetLoadFlags( + loadFlags | nsICachingChannel::LOAD_ONLY_FROM_CACHE); } + } else if (mLoadType == LOAD_RELOAD_NORMAL) { + cacheChannel->SetCacheKey(cacheKey); } } + } else { + /* If there is no postdata, set the cache key on the channel, and + * do not set the LOAD_ONLY_FROM_CACHE flag, so that the channel + * will be free to get it from net if it is not found in cache. + * New cache may use it creatively on CGI pages with GET + * method and even on those that say "no-cache" + */ + if (mLoadType == LOAD_HISTORY || + mLoadType == LOAD_RELOAD_NORMAL || + mLoadType == LOAD_RELOAD_CHARSET_CHANGE) { + if (cacheChannel && cacheKey) { + cacheChannel->SetCacheKey(cacheKey); + } + } + } + + if (httpChannel) { if (aHeadersData) { rv = AddHeadersToChannel(aHeadersData, httpChannel); } diff --git a/dom/base/File.cpp b/dom/base/File.cpp index 5cc20a76e4..7168d4ef27 100644 --- a/dom/base/File.cpp +++ b/dom/base/File.cpp @@ -966,6 +966,32 @@ BlobImplFile::LookupAndCacheIsDirectory() mDirState = isDir ? BlobDirState::eIsDir : BlobDirState::eIsNotDir; } +//////////////////////////////////////////////////////////////////////////// +// BlobImplEmptyFile implementation + +NS_IMPL_ISUPPORTS_INHERITED0(BlobImplEmptyFile, BlobImpl) + +already_AddRefed +BlobImplEmptyFile::CreateSlice(uint64_t aStart, uint64_t aLength, + const nsAString& aContentType, + ErrorResult& aRv) +{ + MOZ_ASSERT(!aStart && !aLength); + RefPtr impl = new BlobImplEmptyFile(aContentType); + return impl.forget(); +} + +void +BlobImplEmptyFile::GetInternalStream(nsIInputStream** aStream, + ErrorResult& aRv) +{ + nsresult rv = NS_NewCStringInputStream(aStream, EmptyCString()); + if (NS_WARN_IF(NS_FAILED(rv))) { + aRv.Throw(rv); + return; + } +} + //////////////////////////////////////////////////////////////////////////// // BlobImplMemory implementation diff --git a/dom/base/File.h b/dom/base/File.h index ef7e5016d5..f6c004b212 100644 --- a/dom/base/File.h +++ b/dom/base/File.h @@ -837,6 +837,31 @@ private: bool mIsTemporary; }; +class BlobImplEmptyFile final : public BlobImplBase +{ +public: + NS_DECL_ISUPPORTS_INHERITED + + explicit BlobImplEmptyFile(const nsAString& aContentType) + : BlobImplBase(EmptyString(), aContentType, 0 /* aLength */) + {} + + virtual void GetInternalStream(nsIInputStream** aStream, + ErrorResult& aRv) override; + + virtual already_AddRefed + CreateSlice(uint64_t aStart, uint64_t aLength, + const nsAString& aContentType, ErrorResult& aRv) override; + + virtual bool IsMemoryFile() const override + { + return true; + } + +private: + ~BlobImplEmptyFile() {} +}; + } // namespace dom } // namespace mozilla diff --git a/dom/base/nsFormData.cpp b/dom/base/FormData.cpp similarity index 73% rename from dom/base/nsFormData.cpp rename to dom/base/FormData.cpp index ef93974699..5f4e352620 100644 --- a/dom/base/nsFormData.cpp +++ b/dom/base/FormData.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 "nsFormData.h" +#include "FormData.h" #include "nsIVariant.h" #include "nsIInputStream.h" #include "mozilla/dom/File.h" @@ -15,7 +15,7 @@ using namespace mozilla; using namespace mozilla::dom; -nsFormData::nsFormData(nsISupports* aOwner) +FormData::FormData(nsISupports* aOwner) : nsFormSubmission(NS_LITERAL_CSTRING("UTF-8"), nullptr) , mOwner(aOwner) { @@ -61,9 +61,9 @@ CreateNewFileInstance(Blob& aBlob, const Optional& aFilename, // ------------------------------------------------------------------------- // nsISupports -NS_IMPL_CYCLE_COLLECTION_CLASS(nsFormData) +NS_IMPL_CYCLE_COLLECTION_CLASS(FormData) -NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsFormData) +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(FormData) NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner) for (uint32_t i = 0, len = tmp->mFormData.Length(); i < len; ++i) { @@ -73,7 +73,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsFormData) NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER NS_IMPL_CYCLE_COLLECTION_UNLINK_END -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsFormData) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(FormData) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner) for (uint32_t i = 0, len = tmp->mFormData.Length(); i < len; ++i) { @@ -84,12 +84,12 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsFormData) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END -NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(nsFormData) +NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(FormData) -NS_IMPL_CYCLE_COLLECTING_ADDREF(nsFormData) -NS_IMPL_CYCLE_COLLECTING_RELEASE(nsFormData) +NS_IMPL_CYCLE_COLLECTING_ADDREF(FormData) +NS_IMPL_CYCLE_COLLECTING_RELEASE(FormData) -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsFormData) +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FormData) NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY NS_INTERFACE_MAP_ENTRY(nsIDOMFormData) NS_INTERFACE_MAP_ENTRY(nsIXHRSendable) @@ -99,23 +99,23 @@ NS_INTERFACE_MAP_END // ------------------------------------------------------------------------- // nsFormSubmission nsresult -nsFormData::GetEncodedSubmission(nsIURI* aURI, - nsIInputStream** aPostDataStream) +FormData::GetEncodedSubmission(nsIURI* aURI, + nsIInputStream** aPostDataStream) { - NS_NOTREACHED("Shouldn't call nsFormData::GetEncodedSubmission"); + NS_NOTREACHED("Shouldn't call FormData::GetEncodedSubmission"); return NS_OK; } void -nsFormData::Append(const nsAString& aName, const nsAString& aValue, - ErrorResult& aRv) +FormData::Append(const nsAString& aName, const nsAString& aValue, + ErrorResult& aRv) { AddNameValuePair(aName, aValue); } void -nsFormData::Append(const nsAString& aName, Blob& aBlob, - const Optional& aFilename, +FormData::Append(const nsAString& aName, Blob& aBlob, + const Optional& aFilename, ErrorResult& aRv) { RefPtr file = CreateNewFileInstance(aBlob, aFilename, aRv); @@ -127,7 +127,7 @@ nsFormData::Append(const nsAString& aName, Blob& aBlob, } void -nsFormData::Delete(const nsAString& aName) +FormData::Delete(const nsAString& aName) { // We have to use this slightly awkward for loop since uint32_t >= 0 is an // error for being always true. @@ -139,8 +139,8 @@ nsFormData::Delete(const nsAString& aName) } void -nsFormData::Get(const nsAString& aName, - Nullable& aOutValue) +FormData::Get(const nsAString& aName, + Nullable& aOutValue) { for (uint32_t i = 0; i < mFormData.Length(); ++i) { if (aName.Equals(mFormData[i].name)) { @@ -153,8 +153,8 @@ nsFormData::Get(const nsAString& aName, } void -nsFormData::GetAll(const nsAString& aName, - nsTArray& aValues) +FormData::GetAll(const nsAString& aName, + nsTArray& aValues) { for (uint32_t i = 0; i < mFormData.Length(); ++i) { if (aName.Equals(mFormData[i].name)) { @@ -165,7 +165,7 @@ nsFormData::GetAll(const nsAString& aName, } bool -nsFormData::Has(const nsAString& aName) +FormData::Has(const nsAString& aName) { for (uint32_t i = 0; i < mFormData.Length(); ++i) { if (aName.Equals(mFormData[i].name)) { @@ -177,15 +177,17 @@ nsFormData::Has(const nsAString& aName) } nsresult -nsFormData::AddNameFilePair(const nsAString& aName, File* aFile) +FormData::AddNameFilePair(const nsAString& aName, File* aFile) { + MOZ_ASSERT(aFile); + FormDataTuple* data = mFormData.AppendElement(); SetNameFilePair(data, aName, aFile); return NS_OK; } -nsFormData::FormDataTuple* -nsFormData::RemoveAllOthersAndGetFirstFormDataTuple(const nsAString& aName) +FormData::FormDataTuple* +FormData::RemoveAllOthersAndGetFirstFormDataTuple(const nsAString& aName) { FormDataTuple* lastFoundTuple = nullptr; uint32_t lastFoundIndex = mFormData.Length(); @@ -207,9 +209,9 @@ nsFormData::RemoveAllOthersAndGetFirstFormDataTuple(const nsAString& aName) } void -nsFormData::Set(const nsAString& aName, Blob& aBlob, - const Optional& aFilename, - ErrorResult& aRv) +FormData::Set(const nsAString& aName, Blob& aBlob, + const Optional& aFilename, + ErrorResult& aRv) { FormDataTuple* tuple = RemoveAllOthersAndGetFirstFormDataTuple(aName); if (tuple) { @@ -225,8 +227,8 @@ nsFormData::Set(const nsAString& aName, Blob& aBlob, } void -nsFormData::Set(const nsAString& aName, const nsAString& aValue, - ErrorResult& aRv) +FormData::Set(const nsAString& aName, const nsAString& aValue, + ErrorResult& aRv) { FormDataTuple* tuple = RemoveAllOthersAndGetFirstFormDataTuple(aName); if (tuple) { @@ -237,30 +239,52 @@ nsFormData::Set(const nsAString& aName, const nsAString& aValue, } uint32_t -nsFormData::GetIterableLength() const +FormData::GetIterableLength() const { return mFormData.Length(); } const nsAString& -nsFormData::GetKeyAtIndex(uint32_t aIndex) const +FormData::GetKeyAtIndex(uint32_t aIndex) const { MOZ_ASSERT(aIndex < mFormData.Length()); return mFormData[aIndex].name; } const OwningFileOrUSVString& -nsFormData::GetValueAtIndex(uint32_t aIndex) const +FormData::GetValueAtIndex(uint32_t aIndex) const { MOZ_ASSERT(aIndex < mFormData.Length()); return mFormData[aIndex].value; } +void +FormData::SetNameValuePair(FormDataTuple* aData, + const nsAString& aName, + const nsAString& aValue) +{ + MOZ_ASSERT(aData); + aData->name = aName; + aData->value.SetAsUSVString() = aValue; +} + +void +FormData::SetNameFilePair(FormDataTuple* aData, + const nsAString& aName, + File* aFile) +{ + MOZ_ASSERT(aData); + MOZ_ASSERT(aFile); + + aData->name = aName; + aData->value.SetAsFile() = aFile; +} + // ------------------------------------------------------------------------- // nsIDOMFormData NS_IMETHODIMP -nsFormData::Append(const nsAString& aName, nsIVariant* aValue) +FormData::Append(const nsAString& aName, nsIVariant* aValue) { uint16_t dataType; nsresult rv = aValue->GetDataType(&dataType); @@ -307,17 +331,17 @@ nsFormData::Append(const nsAString& aName, nsIVariant* aValue) } /* virtual */ JSObject* -nsFormData::WrapObject(JSContext* aCx, JS::Handle aGivenProto) +FormData::WrapObject(JSContext* aCx, JS::Handle aGivenProto) { return FormDataBinding::Wrap(aCx, this, aGivenProto); } -/* static */ already_AddRefed -nsFormData::Constructor(const GlobalObject& aGlobal, - const Optional >& aFormElement, - ErrorResult& aRv) +/* static */ already_AddRefed +FormData::Constructor(const GlobalObject& aGlobal, + const Optional >& aFormElement, + ErrorResult& aRv) { - RefPtr formData = new nsFormData(aGlobal.GetAsSupports()); + RefPtr formData = new FormData(aGlobal.GetAsSupports()); if (aFormElement.WasPassed()) { aRv = aFormElement.Value().WalkFormElements(formData); } @@ -328,8 +352,8 @@ nsFormData::Constructor(const GlobalObject& aGlobal, // nsIXHRSendable NS_IMETHODIMP -nsFormData::GetSendInfo(nsIInputStream** aBody, uint64_t* aContentLength, - nsACString& aContentType, nsACString& aCharset) +FormData::GetSendInfo(nsIInputStream** aBody, uint64_t* aContentLength, + nsACString& aContentType, nsACString& aCharset) { nsFSMultipartFormData fs(NS_LITERAL_CSTRING("UTF-8"), nullptr); @@ -340,7 +364,7 @@ nsFormData::GetSendInfo(nsIInputStream** aBody, uint64_t* aContentLength, fs.AddNameValuePair(mFormData[i].name, mFormData[i].value.GetAsUSVString()); } else { - fs.AddNameFilePair(mFormData[i].name, nullptr); + MOZ_CRASH("This should no be possible."); } } diff --git a/dom/base/nsFormData.h b/dom/base/FormData.h similarity index 65% rename from dom/base/nsFormData.h rename to dom/base/FormData.h index d6e06b05e5..1ca88ae9f1 100644 --- a/dom/base/nsFormData.h +++ b/dom/base/FormData.h @@ -4,40 +4,33 @@ * 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 nsFormData_h__ -#define nsFormData_h__ +#ifndef mozilla_dom_FormData_h +#define mozilla_dom_FormData_h #include "mozilla/Attributes.h" -#include "nsIDOMFormData.h" -#include "nsIXMLHttpRequest.h" -#include "nsFormSubmission.h" -#include "nsWrapperCache.h" -#include "nsTArray.h" #include "mozilla/ErrorResult.h" #include "mozilla/dom/BindingDeclarations.h" #include "mozilla/dom/File.h" #include "mozilla/dom/FormDataBinding.h" +#include "nsIDOMFormData.h" +#include "nsIXMLHttpRequest.h" +#include "nsFormSubmission.h" +#include "nsTArray.h" +#include "nsWrapperCache.h" namespace mozilla { -class ErrorResult; - namespace dom { + class HTMLFormElement; class GlobalObject; -} // namespace dom -} // namespace mozilla -class nsFormData final : public nsIDOMFormData, - public nsIXHRSendable, - public nsFormSubmission, - public nsWrapperCache +class FormData final : public nsIDOMFormData, + public nsIXHRSendable, + public nsFormSubmission, + public nsWrapperCache { private: - ~nsFormData() {} - - typedef mozilla::dom::Blob Blob; - typedef mozilla::dom::File File; - typedef mozilla::dom::OwningFileOrUSVString OwningFileOrUSVString; + ~FormData() {} struct FormDataTuple { @@ -52,29 +45,17 @@ private: void SetNameValuePair(FormDataTuple* aData, const nsAString& aName, - const nsAString& aValue) - { - MOZ_ASSERT(aData); - aData->name = aName; - aData->value.SetAsUSVString() = aValue; - } + const nsAString& aValue); void SetNameFilePair(FormDataTuple* aData, const nsAString& aName, - File* aFile) - { - MOZ_ASSERT(aData); - aData->name = aName; - if (aFile) { - aData->value.SetAsFile() = aFile; - } - } + File* aFile); public: - explicit nsFormData(nsISupports* aOwner = nullptr); + explicit FormData(nsISupports* aOwner = nullptr); NS_DECL_CYCLE_COLLECTING_ISUPPORTS - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsFormData, + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(FormData, nsIDOMFormData) NS_DECL_NSIDOMFORMDATA @@ -89,32 +70,42 @@ public: { return mOwner; } - static already_AddRefed - Constructor(const mozilla::dom::GlobalObject& aGlobal, - const mozilla::dom::Optional >& aFormElement, - mozilla::ErrorResult& aRv); + + static already_AddRefed + Constructor(const GlobalObject& aGlobal, + const Optional >& aFormElement, + ErrorResult& aRv); + void Append(const nsAString& aName, const nsAString& aValue, - mozilla::ErrorResult& aRv); + ErrorResult& aRv); void Append(const nsAString& aName, Blob& aBlob, - const mozilla::dom::Optional& aFilename, - mozilla::ErrorResult& aRv); + const Optional& aFilename, + ErrorResult& aRv); + void Delete(const nsAString& aName); - void Get(const nsAString& aName, mozilla::dom::Nullable& aOutValue); + + void Get(const nsAString& aName, Nullable& aOutValue); + void GetAll(const nsAString& aName, nsTArray& aValues); + bool Has(const nsAString& aName); + void Set(const nsAString& aName, Blob& aBlob, - const mozilla::dom::Optional& aFilename, - mozilla::ErrorResult& aRv); + const Optional& aFilename, + ErrorResult& aRv); void Set(const nsAString& aName, const nsAString& aValue, - mozilla::ErrorResult& aRv); + ErrorResult& aRv); uint32_t GetIterableLength() const; + const nsAString& GetKeyAtIndex(uint32_t aIndex) const; + const OwningFileOrUSVString& GetValueAtIndex(uint32_t aIndex) const; // nsFormSubmission - virtual nsresult GetEncodedSubmission(nsIURI* aURI, - nsIInputStream** aPostDataStream) override; + virtual nsresult + GetEncodedSubmission(nsIURI* aURI, nsIInputStream** aPostDataStream) override; + virtual nsresult AddNameValuePair(const nsAString& aName, const nsAString& aValue) override { @@ -122,6 +113,7 @@ public: SetNameValuePair(data, aName, aValue); return NS_OK; } + virtual nsresult AddNameFilePair(const nsAString& aName, File* aFile) override; @@ -156,4 +148,7 @@ private: nsTArray mFormData; }; -#endif // nsFormData_h__ +} // dom namespace +} // mozilla namepsace + +#endif // mozilla_dom_FormData_h diff --git a/dom/base/Navigator.cpp b/dom/base/Navigator.cpp index e781224981..03ca24ad79 100644 --- a/dom/base/Navigator.cpp +++ b/dom/base/Navigator.cpp @@ -105,7 +105,7 @@ #include "mozilla/dom/Promise.h" #include "nsIUploadChannel2.h" -#include "nsFormData.h" +#include "mozilla/dom/FormData.h" #include "nsIDocShell.h" #include "WorkerPrivate.h" @@ -1276,7 +1276,7 @@ Navigator::SendBeacon(const nsAString& aUrl, mimeType = NS_ConvertUTF16toUTF8(type); } else if (aData.Value().IsFormData()) { - nsFormData& form = aData.Value().GetAsFormData(); + FormData& form = aData.Value().GetAsFormData(); uint64_t len; nsAutoCString charset; form.GetSendInfo(getter_AddRefs(in), diff --git a/dom/base/StructuredCloneHolder.cpp b/dom/base/StructuredCloneHolder.cpp index 056deeaae8..96e57a6fa5 100644 --- a/dom/base/StructuredCloneHolder.cpp +++ b/dom/base/StructuredCloneHolder.cpp @@ -13,6 +13,7 @@ #include "mozilla/dom/File.h" #include "mozilla/dom/FileList.h" #include "mozilla/dom/FileListBinding.h" +#include "mozilla/dom/FormData.h" #include "mozilla/dom/ImageBitmap.h" #include "mozilla/dom/ImageBitmapBinding.h" #include "mozilla/dom/ImageData.h" @@ -33,7 +34,6 @@ #include "mozilla/ipc/BackgroundUtils.h" #include "mozilla/ipc/PBackgroundSharedTypes.h" #include "MultipartBlobImpl.h" -#include "nsFormData.h" #include "nsIRemoteBlob.h" #include "nsQueryObject.h" @@ -816,8 +816,8 @@ ReadFormData(JSContext* aCx, // See the serialization of the FormData for the format. JS::Rooted val(aCx); { - RefPtr formData = - new nsFormData(aHolder->ParentDuringRead()); + RefPtr formData = + new FormData(aHolder->ParentDuringRead()); Optional thirdArg; for (uint32_t i = 0; i < aCount; ++i) { @@ -887,7 +887,7 @@ ReadFormData(JSContext* aCx, // - value string bool WriteFormData(JSStructuredCloneWriter* aWriter, - nsFormData* aFormData, + FormData* aFormData, StructuredCloneHolder* aHolder) { MOZ_ASSERT(aWriter); @@ -1010,7 +1010,7 @@ StructuredCloneHolder::CustomWriteHandler(JSContext* aCx, // See if this is a FormData object. { - nsFormData* formData = nullptr; + FormData* formData = nullptr; if (NS_SUCCEEDED(UNWRAP_OBJECT(FormData, aObj, formData))) { return WriteFormData(aWriter, formData, this); } diff --git a/dom/base/moz.build b/dom/base/moz.build index 575cfd482e..62b1e1c1bf 100644 --- a/dom/base/moz.build +++ b/dom/base/moz.build @@ -75,7 +75,6 @@ EXPORTS += [ 'nsDOMNavigationTiming.h', 'nsDOMString.h', 'nsFocusManager.h', - 'nsFormData.h', 'nsFrameMessageManager.h', 'nsGenericDOMDataNode.h', 'nsGkAtomList.h', @@ -180,6 +179,7 @@ EXPORTS.mozilla.dom += [ 'File.h', 'FileList.h', 'FileReader.h', + 'FormData.h', 'FragmentOrElement.h', 'FromParser.h', 'ImageEncoder.h', @@ -247,6 +247,7 @@ UNIFIED_SOURCES += [ 'File.cpp', 'FileList.cpp', 'FileReader.cpp', + 'FormData.cpp', 'FragmentOrElement.cpp', 'ImageEncoder.cpp', 'ImportManager.cpp', @@ -281,7 +282,6 @@ UNIFIED_SOURCES += [ 'nsDOMTokenList.cpp', 'nsDOMWindowList.cpp', 'nsFocusManager.cpp', - 'nsFormData.cpp', 'nsFrameLoader.cpp', 'nsGenConImageContent.cpp', 'nsGenericDOMDataNode.cpp', diff --git a/dom/base/nsXMLHttpRequest.cpp b/dom/base/nsXMLHttpRequest.cpp index b88598460e..b001665d0e 100644 --- a/dom/base/nsXMLHttpRequest.cpp +++ b/dom/base/nsXMLHttpRequest.cpp @@ -14,6 +14,7 @@ #include "mozilla/dom/BlobSet.h" #include "mozilla/dom/File.h" #include "mozilla/dom/FetchUtil.h" +#include "mozilla/dom/FormData.h" #include "mozilla/dom/XMLDocument.h" #include "mozilla/dom/XMLHttpRequestUploadBinding.h" #include "mozilla/EventDispatcher.h" @@ -74,7 +75,6 @@ #include "nsIHttpChannelInternal.h" #include "nsIClassOfService.h" #include "nsCharSeparatedTokenizer.h" -#include "nsFormData.h" #include "nsStreamListenerWrapper.h" #include "xpcjsid.h" #include "nsITimedChannel.h" @@ -1665,7 +1665,8 @@ nsXMLHttpRequest::Open(const nsACString& inMethod, const nsACString& url, nsCOMPtr loadGroup = GetLoadGroup(); nsSecurityFlags secFlags; - nsLoadFlags loadFlags = nsIRequest::LOAD_BACKGROUND; + nsLoadFlags loadFlags = nsIRequest::LOAD_BACKGROUND | + nsIChannel::LOAD_CLASSIFY_URI; if (nsContentUtils::IsSystemPrincipal(mPrincipal)) { // When chrome is loading we want to make sure to sandbox any potential // result document. We also want to allow cross-origin loads. diff --git a/dom/base/nsXMLHttpRequest.h b/dom/base/nsXMLHttpRequest.h index ffc60a5d47..20624828e7 100644 --- a/dom/base/nsXMLHttpRequest.h +++ b/dom/base/nsXMLHttpRequest.h @@ -41,7 +41,6 @@ #undef Status #endif -class nsFormData; class nsIJARChannel; class nsILoadGroup; class nsIUnicodeDecoder; @@ -52,6 +51,7 @@ namespace mozilla { namespace dom { class Blob; class BlobSet; +class FormData; } // namespace dom // A helper for building up an ArrayBuffer object's data @@ -363,7 +363,7 @@ private: { mValue.mString = &aString; } - explicit RequestBody(nsFormData& aFormData) : mType(FormData) + explicit RequestBody(mozilla::dom::FormData& aFormData) : mType(FormData) { mValue.mFormData = &aFormData; } @@ -388,7 +388,7 @@ private: mozilla::dom::Blob* mBlob; nsIDocument* mDocument; const nsAString* mString; - nsFormData* mFormData; + mozilla::dom::FormData* mFormData; nsIInputStream* mStream; }; @@ -467,7 +467,8 @@ public: aRv = Send(RequestBody(aString)); } } - void Send(JSContext* /*aCx*/, nsFormData& aFormData, ErrorResult& aRv) + void Send(JSContext* /*aCx*/, mozilla::dom::FormData& aFormData, + ErrorResult& aRv) { aRv = Send(RequestBody(aFormData)); } diff --git a/dom/base/test/mochitest.ini b/dom/base/test/mochitest.ini index 4b0b245cd8..1a6e33aff7 100644 --- a/dom/base/test/mochitest.ini +++ b/dom/base/test/mochitest.ini @@ -848,3 +848,4 @@ skip-if = buildapp == 'b2g' #no ssl support [test_document.all_iteration.html] [test_performance_translate.html] [test_bug1198095.html] +[test_bug1187157.html] diff --git a/dom/base/test/test_bug1187157.html b/dom/base/test/test_bug1187157.html new file mode 100644 index 0000000000..a5e64e17d0 --- /dev/null +++ b/dom/base/test/test_bug1187157.html @@ -0,0 +1,30 @@ + + + + + + Test for Bug 789315 + + + + +Mozilla Bug 789315 +
+ + + + + diff --git a/dom/bindings/Bindings.conf b/dom/bindings/Bindings.conf index 7c3a862f7b..4b46a89bc4 100644 --- a/dom/bindings/Bindings.conf +++ b/dom/bindings/Bindings.conf @@ -529,10 +529,6 @@ DOMInterfaces = { 'wrapperCache': False, }, -'FormData': { - 'nativeType': 'nsFormData' -}, - 'Geolocation': { 'headerFile': 'nsGeolocation.h' }, diff --git a/dom/events/DataTransfer.cpp b/dom/events/DataTransfer.cpp index cb487269e5..78fe254590 100644 --- a/dom/events/DataTransfer.cpp +++ b/dom/events/DataTransfer.cpp @@ -853,27 +853,6 @@ DataTransfer::SetDragImage(nsIDOMElement* aImage, int32_t aX, int32_t aY) return rv.StealNSResult(); } -static already_AddRefed -MakeOrReuseFileSystem(const nsAString& aNewLocalRootPath, - OSFileSystem* aFS, - nsPIDOMWindow* aWindow) -{ - MOZ_ASSERT(aWindow); - - RefPtr fs; - if (aFS) { - const nsAString& prevLocalRootPath = aFS->GetLocalRootPath(); - if (aNewLocalRootPath == prevLocalRootPath) { - fs = aFS; - } - } - if (!fs) { - fs = new OSFileSystem(aNewLocalRootPath); - fs->Init(aWindow); - } - return fs.forget(); -} - already_AddRefed DataTransfer::GetFilesAndDirectories(ErrorResult& aRv) { @@ -910,9 +889,6 @@ DataTransfer::GetFilesAndDirectories(ErrorResult& aRv) return p.forget(); } - nsPIDOMWindow* window = parentNode->OwnerDoc()->GetInnerWindow(); - - RefPtr fs; for (uint32_t i = 0; i < mFiles->Length(); ++i) { if (mFiles->Item(i)->Impl()->IsDirectory()) { #if defined(ANDROID) || defined(MOZ_B2G) @@ -929,7 +905,10 @@ DataTransfer::GetFilesAndDirectories(ErrorResult& aRv) int32_t leafSeparatorIndex = path.RFind(FILE_PATH_SEPARATOR); nsDependentSubstring dirname = Substring(path, 0, leafSeparatorIndex); nsDependentSubstring basename = Substring(path, leafSeparatorIndex); - fs = MakeOrReuseFileSystem(dirname, fs, window); + + RefPtr fs = new OSFileSystem(dirname); + fs->Init(parentNode->OwnerDoc()->GetInnerWindow()); + RefPtr directory = new Directory(fs, basename); directory->SetContentFilters(NS_LITERAL_STRING("filter-out-sensitive")); filesAndDirsSeq[i].SetAsDirectory() = directory; diff --git a/dom/events/test/test_all_synthetic_events.html b/dom/events/test/test_all_synthetic_events.html index b2543c7ea1..50d15c4311 100644 --- a/dom/events/test/test_all_synthetic_events.html +++ b/dom/events/test/test_all_synthetic_events.html @@ -449,6 +449,9 @@ const kEventConstructors = { return new RTCPeerConnectionIceEvent(aName, aProps); }, }, + RTCTrackEvent: { + // Difficult to test required arguments. + }, ScrollAreaEvent: { create: function (aName, aProps) { var e = document.createEvent("scrollareaevent"); e.initScrollAreaEvent(aName, aProps.bubbles, aProps.cancelable, diff --git a/dom/fetch/Fetch.cpp b/dom/fetch/Fetch.cpp index 9133dc86d4..37e010c70d 100644 --- a/dom/fetch/Fetch.cpp +++ b/dom/fetch/Fetch.cpp @@ -25,6 +25,7 @@ #include "mozilla/dom/Exceptions.h" #include "mozilla/dom/FetchDriver.h" #include "mozilla/dom/File.h" +#include "mozilla/dom/FormData.h" #include "mozilla/dom/Headers.h" #include "mozilla/dom/Promise.h" #include "mozilla/dom/PromiseWorkerProxy.h" @@ -37,7 +38,6 @@ #include "InternalRequest.h" #include "InternalResponse.h" -#include "nsFormData.h" #include "WorkerPrivate.h" #include "WorkerRunnable.h" #include "WorkerScope.h" @@ -393,7 +393,7 @@ ExtractFromBlob(const Blob& aBlob, nsIInputStream** aStream, } nsresult -ExtractFromFormData(nsFormData& aFormData, nsIInputStream** aStream, +ExtractFromFormData(FormData& aFormData, nsIInputStream** aStream, nsCString& aContentType) { uint64_t unusedContentLength; @@ -468,7 +468,7 @@ ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrBlobOrFormDa const Blob& blob = aBodyInit.GetAsBlob(); return ExtractFromBlob(blob, aStream, aContentType); } else if (aBodyInit.IsFormData()) { - nsFormData& form = aBodyInit.GetAsFormData(); + FormData& form = aBodyInit.GetAsFormData(); return ExtractFromFormData(form, aStream, aContentType); } else if (aBodyInit.IsUSVString()) { nsAutoString str; @@ -500,7 +500,7 @@ ExtractByteStreamFromBody(const ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUS const Blob& blob = aBodyInit.GetAsBlob(); return ExtractFromBlob(blob, aStream, aContentType); } else if (aBodyInit.IsFormData()) { - nsFormData& form = aBodyInit.GetAsFormData(); + FormData& form = aBodyInit.GetAsFormData(); return ExtractFromFormData(form, aStream, aContentType); } else if (aBodyInit.IsUSVString()) { nsAutoString str; @@ -1039,7 +1039,7 @@ FetchBody::ContinueConsumeBody(nsresult aStatus, uint32_t aResultLength data.Adopt(reinterpret_cast(aResult), aResultLength); autoFree.Reset(); - RefPtr fd = FetchUtil::ConsumeFormData( + RefPtr fd = FetchUtil::ConsumeFormData( DerivedClass()->GetParentObject(), mMimeType, data, error); if (!error.Failed()) { diff --git a/dom/fetch/FetchUtil.cpp b/dom/fetch/FetchUtil.cpp index 943e63707b..eb2a6f95a2 100644 --- a/dom/fetch/FetchUtil.cpp +++ b/dom/fetch/FetchUtil.cpp @@ -194,7 +194,7 @@ class MOZ_STACK_CLASS FillFormIterator final : public URLSearchParams::ForEachIterator { public: - explicit FillFormIterator(nsFormData* aFormData) + explicit FillFormIterator(FormData* aFormData) : mFormData(aFormData) { MOZ_ASSERT(aFormData); @@ -210,7 +210,7 @@ public: } private: - nsFormData* mFormData; + FormData* mFormData; }; /** @@ -224,7 +224,7 @@ private: * never return a partially filled FormData. * The content-disposition header is used to figure out the name and filename * entries. The inclusion of the filename parameter decides if the entry is - * inserted into the nsFormData as a string or a File. + * inserted into the FormData as a string or a File. * * File blobs are copies of the underlying data string since we cannot adopt * char* chunks embedded within the larger body without significant effort. @@ -235,7 +235,7 @@ private: class MOZ_STACK_CLASS FormDataParser { private: - RefPtr mFormData; + RefPtr mFormData; nsCString mMimeType; nsCString mData; @@ -388,7 +388,7 @@ private: aStart.advance(2); if (!mFormData) { - mFormData = new nsFormData(); + mFormData = new FormData(); } NS_ConvertUTF8toUTF16 name(mName); @@ -488,7 +488,7 @@ public: if (start != end && *start == '-') { // End of data. if (!mFormData) { - mFormData = new nsFormData(); + mFormData = new FormData(); } return true; } @@ -535,7 +535,7 @@ public: return false; } - already_AddRefed FormData() + already_AddRefed GetFormData() { return mFormData.forget(); } @@ -543,7 +543,7 @@ public: } // static -already_AddRefed +already_AddRefed FetchUtil::ConsumeFormData(nsIGlobalObject* aParent, const nsCString& aMimeType, const nsCString& aStr, ErrorResult& aRv) { @@ -564,7 +564,7 @@ FetchUtil::ConsumeFormData(nsIGlobalObject* aParent, const nsCString& aMimeType, return nullptr; } - RefPtr fd = parser.FormData(); + RefPtr fd = parser.GetFormData(); MOZ_ASSERT(fd); return fd.forget(); } @@ -580,7 +580,7 @@ FetchUtil::ConsumeFormData(nsIGlobalObject* aParent, const nsCString& aMimeType, URLParams params; params.ParseInput(aStr); - RefPtr fd = new nsFormData(aParent); + RefPtr fd = new FormData(aParent); FillFormIterator iterator(fd); DebugOnly status = params.ForEach(iterator); MOZ_ASSERT(status); diff --git a/dom/fetch/FetchUtil.h b/dom/fetch/FetchUtil.h index 79b14f7257..53d41383c3 100644 --- a/dom/fetch/FetchUtil.h +++ b/dom/fetch/FetchUtil.h @@ -3,10 +3,10 @@ #include "nsString.h" #include "nsError.h" -#include "nsFormData.h" #include "mozilla/ErrorResult.h" #include "mozilla/dom/File.h" +#include "mozilla/dom/FormData.h" namespace mozilla { namespace dom { @@ -47,7 +47,7 @@ public: * Creates a form data object from a UTF-8 encoded |aStr|. Returns |nullptr| * and sets |aRv| to MSG_BAD_FORMDATA if |aStr| contains invalid data. */ - static already_AddRefed + static already_AddRefed ConsumeFormData(nsIGlobalObject* aParent, const nsCString& aMimeType, const nsCString& aStr, ErrorResult& aRv); diff --git a/dom/html/HTMLFormElement.cpp b/dom/html/HTMLFormElement.cpp index 6a624f0c04..43cceead6c 100644 --- a/dom/html/HTMLFormElement.cpp +++ b/dom/html/HTMLFormElement.cpp @@ -36,6 +36,7 @@ #include "nsQueryObject.h" // form submission +#include "mozilla/dom/FormData.h" #include "mozilla/Telemetry.h" #include "nsIFormSubmitObserver.h" #include "nsIObserverService.h" @@ -49,7 +50,6 @@ #include "nsIInterfaceRequestorUtils.h" #include "nsIWebProgress.h" #include "nsIDocShell.h" -#include "nsFormData.h" #include "nsFormSubmissionConstants.h" #include "nsIPrompt.h" #include "nsISecurityUITelemetry.h" diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp index c0a489385d..00702c0894 100644 --- a/dom/html/HTMLInputElement.cpp +++ b/dom/html/HTMLInputElement.cpp @@ -384,10 +384,10 @@ HTMLInputElement::nsFilePickerShownCallback::Done(int16_t aResult) // Collect new selected filenames nsTArray> newFiles; - if (mode == static_cast(nsIFilePicker::modeOpenMultiple) || - mode == static_cast(nsIFilePicker::modeGetFolder)) { + if (mode == static_cast(nsIFilePicker::modeOpenMultiple)) { nsCOMPtr iter; - nsresult rv = mFilePicker->GetDomfiles(getter_AddRefs(iter)); + nsresult rv = + mFilePicker->GetDomFileOrDirectoryEnumerator(getter_AddRefs(iter)); NS_ENSURE_SUCCESS(rv, rv); if (!iter) { @@ -407,9 +407,10 @@ HTMLInputElement::nsFilePickerShownCallback::Done(int16_t aResult) } } } else { - MOZ_ASSERT(mode == static_cast(nsIFilePicker::modeOpen)); + MOZ_ASSERT(mode == static_cast(nsIFilePicker::modeOpen) || + mode == static_cast(nsIFilePicker::modeGetFolder)); nsCOMPtr tmp; - nsresult rv = mFilePicker->GetDomfile(getter_AddRefs(tmp)); + nsresult rv = mFilePicker->GetDomFileOrDirectory(getter_AddRefs(tmp)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr blob = do_QueryInterface(tmp); @@ -937,6 +938,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLInputElement, } NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFiles) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFileList) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFilesAndDirectoriesPromise) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLInputElement, @@ -945,6 +947,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLInputElement, NS_IMPL_CYCLE_COLLECTION_UNLINK(mControllers) NS_IMPL_CYCLE_COLLECTION_UNLINK(mFiles) NS_IMPL_CYCLE_COLLECTION_UNLINK(mFileList) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mFilesAndDirectoriesPromise) if (tmp->IsSingleLineTextControl(false)) { tmp->mInputData.mState->Unlink(); } @@ -2529,6 +2532,9 @@ HTMLInputElement::UpdateFileList() } } + // Make sure we (lazily) create a new Promise for GetFilesAndDirectories: + mFilesAndDirectoriesPromise = nullptr; + return NS_OK; } @@ -4831,6 +4837,9 @@ HTMLInputElement::ChooseDirectory(ErrorResult& aRv) aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return; } + // Script can call this method directly, so even though we don't show the + // "Pick Folder..." button on platforms that don't have a directory picker + // we have to redirect to the file picker here. InitFilePicker( #if defined(ANDROID) || defined(MOZ_B2G) // No native directory picker - redirect to plain file picker @@ -4841,30 +4850,13 @@ HTMLInputElement::ChooseDirectory(ErrorResult& aRv) ); } -static already_AddRefed -MakeOrReuseFileSystem(const nsAString& aNewLocalRootPath, - OSFileSystem* aFS, - nsPIDOMWindow* aWindow) -{ - MOZ_ASSERT(aWindow); - - RefPtr fs; - if (aFS) { - const nsAString& prevLocalRootPath = aFS->GetLocalRootPath(); - if (aNewLocalRootPath == prevLocalRootPath) { - fs = aFS; - } - } - if (!fs) { - fs = new OSFileSystem(aNewLocalRootPath); - fs->Init(aWindow); - } - return fs.forget(); -} - already_AddRefed HTMLInputElement::GetFilesAndDirectories(ErrorResult& aRv) { + if (mFilesAndDirectoriesPromise) { + return RefPtr(mFilesAndDirectoriesPromise).forget(); + } + nsCOMPtr global = OwnerDoc()->GetScopeObject(); MOZ_ASSERT(global); if (!global) { @@ -4885,8 +4877,6 @@ HTMLInputElement::GetFilesAndDirectories(ErrorResult& aRv) return p.forget(); } - nsPIDOMWindow* window = OwnerDoc()->GetInnerWindow(); - RefPtr fs; for (uint32_t i = 0; i < filesAndDirs.Length(); ++i) { if (filesAndDirs[i]->IsDirectory()) { #if defined(ANDROID) || defined(MOZ_B2G) @@ -4902,7 +4892,10 @@ HTMLInputElement::GetFilesAndDirectories(ErrorResult& aRv) } int32_t leafSeparatorIndex = path.RFind(FILE_PATH_SEPARATOR); nsDependentSubstring dirname = Substring(path, 0, leafSeparatorIndex); - fs = MakeOrReuseFileSystem(dirname, fs, window); + + RefPtr fs = new OSFileSystem(dirname); + fs->Init(OwnerDoc()->GetInnerWindow()); + nsAutoString dompath(NS_LITERAL_STRING(FILESYSTEM_DOM_PATH_SEPARATOR)); dompath.Append(Substring(path, leafSeparatorIndex + 1)); RefPtr directory = new Directory(fs, dompath); @@ -4919,6 +4912,11 @@ HTMLInputElement::GetFilesAndDirectories(ErrorResult& aRv) p->MaybeResolve(filesAndDirsSeq); + // Cache the Promise so that repeat getFilesAndDirectories() calls return + // the same Promise and array of File and Directory objects until the user + // picks different files/directories: + mFilesAndDirectoriesPromise = p; + return p.forget(); } @@ -5549,10 +5547,10 @@ HTMLInputElement::SubmitNamesValues(nsFormSubmission* aFormSubmission) } if (files.IsEmpty()) { - // If no file was selected, pretend we had an empty file with an - // empty filename. - aFormSubmission->AddNameFilePair(name, nullptr); - + RefPtr blobImpl = + new BlobImplEmptyFile(NS_LITERAL_STRING("application/octet-stream")); + RefPtr file = File::Create(OwnerDoc()->GetInnerWindow(), blobImpl); + aFormSubmission->AddNameFilePair(name, file); } return NS_OK; diff --git a/dom/html/HTMLInputElement.h b/dom/html/HTMLInputElement.h index f9370b0529..7a297ada0b 100644 --- a/dom/html/HTMLInputElement.h +++ b/dom/html/HTMLInputElement.h @@ -1300,6 +1300,7 @@ protected: #endif RefPtr mFileList; + RefPtr mFilesAndDirectoriesPromise; nsString mStaticDocFileList; diff --git a/dom/html/nsFormSubmission.cpp b/dom/html/nsFormSubmission.cpp index 8fac3f3931..f5389865e5 100644 --- a/dom/html/nsFormSubmission.cpp +++ b/dom/html/nsFormSubmission.cpp @@ -167,15 +167,15 @@ nsresult nsFSURLEncoded::AddNameFilePair(const nsAString& aName, mozilla::dom::File* aFile) { + MOZ_ASSERT(aFile); + if (!mWarnedFileControl) { SendJSWarning(mDocument, "ForgotFileEnctypeWarning", nullptr, 0); mWarnedFileControl = true; } nsAutoString filename; - if (aFile) { - aFile->GetName(filename); - } + aFile->GetName(filename); return AddNameValuePair(aName, filename); } @@ -441,61 +441,60 @@ nsresult nsFSMultipartFormData::AddNameFilePair(const nsAString& aName, mozilla::dom::File* aFile) { + MOZ_ASSERT(aFile); + // Encode the control name nsAutoCString nameStr; nsresult rv = EncodeVal(aName, nameStr, true); NS_ENSURE_SUCCESS(rv, rv); - nsCString filename, contentType; + nsAutoString filename16; + aFile->GetName(filename16); + + ErrorResult error; + nsAutoString filepath16; + aFile->GetPath(filepath16, error); + if (NS_WARN_IF(error.Failed())) { + return error.StealNSResult(); + } + + if (!filepath16.IsEmpty()) { + // File.path includes trailing "/" + filename16 = filepath16 + filename16; + } + + nsAutoCString filename; + rv = EncodeVal(filename16, filename, true); + NS_ENSURE_SUCCESS(rv, rv); + + // Get content type + nsAutoString contentType16; + aFile->GetType(contentType16); + if (contentType16.IsEmpty()) { + contentType16.AssignLiteral("application/octet-stream"); + } + + nsAutoCString contentType; + contentType.Adopt(nsLinebreakConverter:: + ConvertLineBreaks(NS_ConvertUTF16toUTF8(contentType16).get(), + nsLinebreakConverter::eLinebreakAny, + nsLinebreakConverter::eLinebreakSpace)); + + // Get input stream nsCOMPtr fileStream; - if (aFile) { - nsAutoString filename16; - aFile->GetName(filename16); + aFile->GetInternalStream(getter_AddRefs(fileStream), error); + if (NS_WARN_IF(error.Failed())) { + return error.StealNSResult(); + } - ErrorResult error; - nsAutoString filepath16; - aFile->GetPath(filepath16, error); - if (NS_WARN_IF(error.Failed())) { - return error.StealNSResult(); - } - - if (!filepath16.IsEmpty()) { - // File.path includes trailing "/" - filename16 = filepath16 + filename16; - } - - rv = EncodeVal(filename16, filename, true); + if (fileStream) { + // Create buffered stream (for efficiency) + nsCOMPtr bufferedStream; + rv = NS_NewBufferedInputStream(getter_AddRefs(bufferedStream), + fileStream, 8192); NS_ENSURE_SUCCESS(rv, rv); - // Get content type - nsAutoString contentType16; - aFile->GetType(contentType16); - if (contentType16.IsEmpty()) { - contentType16.AssignLiteral("application/octet-stream"); - } - contentType.Adopt(nsLinebreakConverter:: - ConvertLineBreaks(NS_ConvertUTF16toUTF8(contentType16).get(), - nsLinebreakConverter::eLinebreakAny, - nsLinebreakConverter::eLinebreakSpace)); - - // Get input stream - aFile->GetInternalStream(getter_AddRefs(fileStream), error); - if (NS_WARN_IF(error.Failed())) { - return error.StealNSResult(); - } - - if (fileStream) { - // Create buffered stream (for efficiency) - nsCOMPtr bufferedStream; - rv = NS_NewBufferedInputStream(getter_AddRefs(bufferedStream), - fileStream, 8192); - NS_ENSURE_SUCCESS(rv, rv); - - fileStream = bufferedStream; - } - } - else { - contentType.AssignLiteral("application/octet-stream"); + fileStream = bufferedStream; } // @@ -619,9 +618,7 @@ nsFSTextPlain::AddNameFilePair(const nsAString& aName, mozilla::dom::File* aFile) { nsAutoString filename; - if (aFile) { - aFile->GetName(filename); - } + aFile->GetName(filename); AddNameValuePair(aName, filename); return NS_OK; diff --git a/dom/html/test/test_formSubmission.html b/dom/html/test/test_formSubmission.html index db7da4ed84..0edfeaeb85 100644 --- a/dom/html/test/test_formSubmission.html +++ b/dom/html/test/test_formSubmission.html @@ -433,8 +433,7 @@ function onFilesOpened(files) { while (input = addList[i++]) { if (input.classList.contains("multi")) { SpecialPowers.wrap(input).mozSetFileArray(multiFile); - } - else { + } else { SpecialPowers.wrap(input).mozSetFileArray([singleFile]); } } diff --git a/dom/interfaces/base/nsIServiceWorkerManager.idl b/dom/interfaces/base/nsIServiceWorkerManager.idl index 8cb6aaf133..2c1e8fef1f 100644 --- a/dom/interfaces/base/nsIServiceWorkerManager.idl +++ b/dom/interfaces/base/nsIServiceWorkerManager.idl @@ -42,7 +42,7 @@ interface nsIServiceWorkerRegistrationInfoListener : nsISupports void onChange(); }; -[scriptable, builtinclass, uuid(72faba24-0a1b-4284-bad3-d44c044d6d95)] +[scriptable, builtinclass, uuid(ddbc1fd4-2f2e-4fca-a395-6e010bbedfe3)] interface nsIServiceWorkerRegistrationInfo : nsISupports { readonly attribute nsIPrincipal principal; @@ -54,6 +54,12 @@ interface nsIServiceWorkerRegistrationInfo : nsISupports readonly attribute nsIServiceWorkerInfo waitingWorker; readonly attribute nsIServiceWorkerInfo activeWorker; + // Allows to get the related nsIServiceWorkerInfo for a given + // nsIWorkerDebugger. Over time we shouldn't need this anymore, + // and instead always control then nsIWorkerDebugger from + // nsIServiceWorkerInfo and not the other way around. + nsIServiceWorkerInfo getWorkerByID(in unsigned long long aID); + void addListener(in nsIServiceWorkerRegistrationInfoListener listener); void removeListener(in nsIServiceWorkerRegistrationInfoListener listener); @@ -67,7 +73,7 @@ interface nsIServiceWorkerManagerListener : nsISupports void onUnregister(in nsIServiceWorkerRegistrationInfo aInfo); }; -[scriptable, builtinclass, uuid(a03f2b64-7aaf-423a-97b0-e1f733cce0f6)] +[scriptable, builtinclass, uuid(12381ddf-9b51-4c0a-9123-9e7754393a5a)] interface nsIServiceWorkerManager : nsISupports { /** @@ -100,6 +106,9 @@ interface nsIServiceWorkerManager : nsISupports // Remove ready pending Promise void removeReadyPromise(in nsIDOMWindow aWindow); + nsIServiceWorkerRegistrationInfo getRegistrationByPrincipal(in nsIPrincipal aPrincipal, + in DOMString aScope); + /** * Call this to request that document `aDoc` be controlled by a ServiceWorker * if a registration exists for it's scope. diff --git a/dom/media/PeerConnection.js b/dom/media/PeerConnection.js index 5600f4f366..378d374f51 100644 --- a/dom/media/PeerConnection.js +++ b/dom/media/PeerConnection.js @@ -405,8 +405,9 @@ RTCPeerConnection.prototype = { "InvalidStateError"); } - this.makeGetterSetterEH("onaddstream"); - this.makeGetterSetterEH("onaddtrack"); + this.makeGetterSetterEH("ontrack"); + this.makeLegacyGetterSetterEH("onaddstream", "Use peerConnection.ontrack instead."); + this.makeLegacyGetterSetterEH("onaddtrack", "Use peerConnection.ontrack instead."); this.makeGetterSetterEH("onicecandidate"); this.makeGetterSetterEH("onnegotiationneeded"); this.makeGetterSetterEH("onsignalingstatechange"); @@ -659,6 +660,18 @@ RTCPeerConnection.prototype = { }); }, + makeLegacyGetterSetterEH: function(name, msg) { + Object.defineProperty(this, name, + { + get:function() { return this.getEH(name); }, + set:function(h) { + this.logWarning(name + " is deprecated! " + msg, + null, 0); + return this.setEH(name, h); + } + }); + }, + _addIdentityAssertion: function(sdpPromise, origin) { if (!this._localIdp.enabled) { return sdpPromise; @@ -1406,13 +1419,28 @@ PeerConnectionObserver.prototype = { { stream: stream })); }, - onAddTrack: function(track) { - let ev = new this._dompc._win.MediaStreamTrackEvent("addtrack", - { track: track }); + onAddTrack: function(track, streams) { + let pc = this._dompc; + let receiver = pc._win.RTCRtpReceiver._create(pc._win, + new RTCRtpReceiver(this, + track)); + pc._receivers.push(receiver); + let ev = new this._dompc._win.RTCTrackEvent("track", + { receiver: receiver, + track: track, + streams: streams }); + this.dispatchEvent(ev); + + // Fire legacy event as well for a little bit. + ev = new this._dompc._win.MediaStreamTrackEvent("addtrack", { track: track }); this.dispatchEvent(ev); }, onRemoveTrack: function(track, type) { + let i = this._dompc._receivers.findIndex(receiver => receiver.track == track); + if (i >= 0) { + this._receivers.splice(i, 1); + } this.dispatchEvent(new this._dompc._win.MediaStreamTrackEvent("removetrack", { track: track })); }, @@ -1480,7 +1508,7 @@ RTCRtpSender.prototype = { }; function RTCRtpReceiver(pc, track) { - this.pc = pc; + this._pc = pc; this.track = track; } RTCRtpReceiver.prototype = { diff --git a/dom/media/tests/mochitest/identity/identityPcTest.js b/dom/media/tests/mochitest/identity/identityPcTest.js index e5c9d9b423..e5fcbc5db8 100644 --- a/dom/media/tests/mochitest/identity/identityPcTest.js +++ b/dom/media/tests/mochitest/identity/identityPcTest.js @@ -20,7 +20,6 @@ function identityPcTest(remoteOptions) { }], [remoteOptions || { audio: true, video: true, - fake: true, peerIdentity: id1 }]); test.pcLocal.setIdentityProvider('test1.example.com', 'idp.js'); diff --git a/dom/media/tests/mochitest/identity/test_peerConnection_asymmetricIsolation.html b/dom/media/tests/mochitest/identity/test_peerConnection_asymmetricIsolation.html index 1d686f533f..5ea0f5c779 100644 --- a/dom/media/tests/mochitest/identity/test_peerConnection_asymmetricIsolation.html +++ b/dom/media/tests/mochitest/identity/test_peerConnection_asymmetricIsolation.html @@ -20,8 +20,7 @@ function theTest() { // side is isolated anyway. identityPcTest({ audio: true, - video: true, - fake: true + video: true }); } runNetworkTest(theTest); diff --git a/dom/media/tests/mochitest/test_enumerateDevices.html b/dom/media/tests/mochitest/test_enumerateDevices.html index 06565e26ab..5a160cf4a9 100644 --- a/dom/media/tests/mochitest/test_enumerateDevices.html +++ b/dom/media/tests/mochitest/test_enumerateDevices.html @@ -46,27 +46,24 @@ runTest(() => .then(() => mustSucceed("unknown plain deviceId on video", () => navigator.mediaDevices.getUserMedia({ video: { deviceId: "unknown9qHr8B0JIbcHlbl9xR+jMbZZ8WyoPfpCXPfc=" }, - fake: true, }))) .then(() => mustSucceed("unknown plain deviceId on audio", () => navigator.mediaDevices.getUserMedia({ audio: { deviceId: "unknown9qHr8B0JIbcHlbl9xR+jMbZZ8WyoPfpCXPfc=" }, - fake: true, }))) .then(() => mustFailWith("unknown exact deviceId on video", "OverconstrainedError", "deviceId", () => navigator.mediaDevices.getUserMedia({ video: { deviceId: { exact: "unknown9qHr8B0JIbcHlbl9xR+jMbZZ8WyoPfpCXPfc=" } }, - fake: true, }))) .then(() => mustFailWith("unknown exact deviceId on audio", "OverconstrainedError", "deviceId", () => navigator.mediaDevices.getUserMedia({ audio: { deviceId: { exact: "unknown9qHr8B0JIbcHlbl9xR+jMbZZ8WyoPfpCXPfc=" } }, - fake: true, }))) - // Check the special case of no devices found (these prefs override fake). - .then(() => pushPrefs(["media.audio_loopback_dev", "none"], + // Check the special case of no devices found. + .then(() => pushPrefs(["media.navigator.streams.fake", false], + ["media.audio_loopback_dev", "none"], ["media.video_loopback_dev", "none"])) .then(() => navigator.mediaDevices.enumerateDevices()) .then(devices => ok(devices.length === 0, "No devices found"))); diff --git a/dom/media/tests/mochitest/test_getUserMedia_basicTabshare.html b/dom/media/tests/mochitest/test_getUserMedia_basicTabshare.html new file mode 100644 index 0000000000..9753c669b3 --- /dev/null +++ b/dom/media/tests/mochitest/test_getUserMedia_basicTabshare.html @@ -0,0 +1,70 @@ + + + + + + +
+
+
+ + diff --git a/dom/media/tests/mochitest/test_getUserMedia_constraints.html b/dom/media/tests/mochitest/test_getUserMedia_constraints.html index 88d0d8993c..9acb61a253 100644 --- a/dom/media/tests/mochitest/test_getUserMedia_constraints.html +++ b/dom/media/tests/mochitest/test_getUserMedia_constraints.html @@ -16,16 +16,13 @@ createHTML({ title: "Test getUserMedia constraints", bug: "882145" }); var tests = [ // Each test here tests a different constraint or codepath. { message: "unknown required constraint on video ignored", - constraints: { video: { somethingUnknown: { exact: 0 } }, - fake: true }, + constraints: { video: { somethingUnknown: { exact: 0 } } }, error: null }, { message: "unknown required constraint on audio ignored", - constraints: { audio: { somethingUnknown: { exact: 0 } }, - fake: true }, + constraints: { audio: { somethingUnknown: { exact: 0 } } }, error: null }, { message: "audio overconstrained by facingMode ignored", - constraints: { audio: { facingMode: { exact: 'left' } }, - fake: true }, + constraints: { audio: { facingMode: { exact: 'left' } } }, error: null }, { message: "full screensharing requires permission", constraints: { video: { mediaSource: 'screen' } }, @@ -51,8 +48,7 @@ var tests = [ constraints: { }, error: "NotSupportedError" }, { message: "Success-path: optional video facingMode + audio ignoring facingMode", - constraints: { fake: true, - audio: { mediaSource: 'microphone', + constraints: { audio: { mediaSource: 'microphone', facingMode: 'left', foo: 0, advanced: [{ facingMode: 'environment' }, @@ -66,7 +62,7 @@ var tests = [ { bar: 0 }] } }, error: null }, { message: "legacy facingMode ignored", - constraints: { video: { mandatory: { facingMode: 'left' } }, fake: true }, + constraints: { video: { mandatory: { facingMode: 'left' } } }, error: null }, ]; diff --git a/dom/media/tests/mochitest/test_getUserMedia_peerIdentity.html b/dom/media/tests/mochitest/test_getUserMedia_peerIdentity.html index 108e4f83a1..f680beb533 100644 --- a/dom/media/tests/mochitest/test_getUserMedia_peerIdentity.html +++ b/dom/media/tests/mochitest/test_getUserMedia_peerIdentity.html @@ -13,7 +13,7 @@ createHTML({ }); function theTest() { function testPeerIdentityConstraint(withConstraint) { - var config = { audio: true, video: true, fake: true }; + var config = { audio: true, video: true }; if (withConstraint) { config.peerIdentity = 'user@example.com'; } diff --git a/dom/media/tests/mochitest/test_peerConnection_callbacks.html b/dom/media/tests/mochitest/test_peerConnection_callbacks.html index fb634f1e00..8bf4b106da 100644 --- a/dom/media/tests/mochitest/test_peerConnection_callbacks.html +++ b/dom/media/tests/mochitest/test_peerConnection_callbacks.html @@ -65,7 +65,7 @@ runNetworkTest(function() { is(v2.currentTime, 0, "v2.currentTime is zero at outset"); // not testing legacy gUM here - navigator.mediaDevices.getUserMedia({ fake: true, video: true, audio: true }) + navigator.mediaDevices.getUserMedia({ video: true, audio: true }) .then(stream => pc1.addStream(v1.mozSrcObject = stream)) .then(() => pcall(pc1, pc1.createOffer)) .then(offer => pcall(pc1, pc1.setLocalDescription, offer)) diff --git a/dom/media/tests/mochitest/test_peerConnection_promiseSendOnly.html b/dom/media/tests/mochitest/test_peerConnection_promiseSendOnly.html index 52f0f77e12..3e3e3365d9 100644 --- a/dom/media/tests/mochitest/test_peerConnection_promiseSendOnly.html +++ b/dom/media/tests/mochitest/test_peerConnection_promiseSendOnly.html @@ -15,19 +15,33 @@ var pc1 = new RTCPeerConnection(); var pc2 = new RTCPeerConnection(); - var pc2_haveRemoteOffer = new Promise(resolve => pc2.onsignalingstatechange = - e => (e.target.signalingState == "have-remote-offer") && resolve()); - var pc1_stable = new Promise(resolve => pc1.onsignalingstatechange = - e => (e.target.signalingState == "stable") && resolve()); + var add = (pc, can, failed) => can && pc.addIceCandidate(can).catch(failed); + pc1.onicecandidate = e => add(pc2, e.candidate, generateErrorCallback()); + pc2.onicecandidate = e => add(pc1, e.candidate, generateErrorCallback()); - pc1.onicecandidate = e => pc2_haveRemoteOffer.then(() => !e.candidate || - pc2.addIceCandidate(e.candidate)).catch(generateErrorCallback()); - pc2.onicecandidate = e => pc1_stable.then(() => !e.candidate || - pc1.addIceCandidate(e.candidate)).catch(generateErrorCallback()); + function mustThrowWith(msg, reason, f) { + try { + f(); + ok(false, msg + " must throw"); + } catch (e) { + is(e.name, reason, msg + " must throw: " + e.message); + } + }; var v1, v2; - var delivered = new Promise(resolve => - pc2.onaddstream = e => resolve(v2.srcObject = e.stream)); + var delivered = new Promise(resolve => pc2.ontrack = e => { + // Test RTCTrackEvent here. + ok(e.streams.length > 0, "has streams"); + ok(e.streams[0].getTracks().some(track => track == e.track), "has track"); + ok(pc2.getReceivers().some(receiver => receiver == e.receiver), "has receiver"); + if (e.streams[0].getTracks().length == 2) { + // Test RTCTrackEvent required args here. + mustThrowWith("RTCTrackEvent wo/required args", + "TypeError", () => new RTCTrackEvent("track", {})); + v2.srcObject = e.streams[0]; + resolve(); + } + }); runNetworkTest(function() { v1 = createMediaElement('video', 'v1'); @@ -36,8 +50,8 @@ is(v2.currentTime, 0, "v2.currentTime is zero at outset"); - navigator.mediaDevices.getUserMedia({ fake: true, video: true, audio: true }) - .then(stream => pc1.addStream(v1.srcObject = stream)) + navigator.mediaDevices.getUserMedia({ video: true, audio: true }) + .then(stream => (v1.srcObject = stream).getTracks().forEach(t => pc1.addTrack(t, stream))) .then(() => pc1.createOffer({})) // check that createOffer accepts arg. .then(offer => pc1.setLocalDescription(offer)) .then(() => pc2.setRemoteDescription(pc1.localDescription)) diff --git a/dom/media/tests/mochitest/test_peerConnection_remoteReofferRollback.html b/dom/media/tests/mochitest/test_peerConnection_remoteReofferRollback.html index 2cf4729d66..55fcb8f844 100644 --- a/dom/media/tests/mochitest/test_peerConnection_remoteReofferRollback.html +++ b/dom/media/tests/mochitest/test_peerConnection_remoteReofferRollback.html @@ -14,6 +14,7 @@ var test; runNetworkTest(function (options) { test = new PeerConnectionTest(options); + var firstNegotiationSize = test.chain.commands.length; addRenegotiation(test.chain, [ function PC_LOCAL_ADD_SECOND_STREAM(test) { @@ -42,6 +43,8 @@ }, function PC_LOCAL_ROLLBACK(test) { + // We haven't negotiated the new stream yet. + test.pcLocal.expectNegotiationNeeded(); return test.setLocalDescription( test.pcLocal, new RTCSessionDescription({ type: "rollback", sdp: ""}), @@ -53,7 +56,7 @@ return test.pcLocal.endOfTrickleIce; }, ], - 1 // Second PC_REMOTE_SET_REMOTE_DESCRIPTION + firstNegotiationSize // Second PC_REMOTE_SET_REMOTE_DESCRIPTION ); test.chain.append(commandsPeerConnectionOfferAnswer); test.setMediaConstraints([{audio: true}], [{audio: true}]); diff --git a/dom/media/tests/mochitest/test_peerConnection_remoteRollback.html b/dom/media/tests/mochitest/test_peerConnection_remoteRollback.html index 091a28de93..830fb64412 100644 --- a/dom/media/tests/mochitest/test_peerConnection_remoteRollback.html +++ b/dom/media/tests/mochitest/test_peerConnection_remoteRollback.html @@ -18,6 +18,8 @@ test.chain.removeAfter('PC_REMOTE_SET_REMOTE_DESCRIPTION'); test.chain.append([ function PC_REMOTE_ROLLBACK(test) { + // We still haven't negotiated the tracks + test.pcRemote.expectNegotiationNeeded(); return test.setRemoteDescription( test.pcRemote, new RTCSessionDescription({ type: "rollback" }), @@ -25,6 +27,8 @@ }, function PC_LOCAL_ROLLBACK(test) { + // We still haven't negotiated the tracks + test.pcLocal.expectNegotiationNeeded(); return test.setLocalDescription( test.pcLocal, new RTCSessionDescription({ type: "rollback", sdp: ""}), diff --git a/dom/media/tests/mochitest/test_peerConnection_replaceTrack.html b/dom/media/tests/mochitest/test_peerConnection_replaceTrack.html index 38e69c5523..402403f928 100644 --- a/dom/media/tests/mochitest/test_peerConnection_replaceTrack.html +++ b/dom/media/tests/mochitest/test_peerConnection_replaceTrack.html @@ -19,6 +19,13 @@ .some(sn => sn.track == t))) // that's being sent over |pc|. } + function allRemoteStreamsHaveReceiver(pc) { + return pc.getRemoteStreams() + .every(s => s.getTracks() // Every remote stream, + .some(t => pc.getReceivers() // should have some track, + .some(sn => sn.track == t))) // that's being received over |pc|. + } + function replacetest(wrapper) { var pc = wrapper._pc; var oldSenderCount = pc.getSenders().length; @@ -26,11 +33,13 @@ var oldTrack = sender.track; ok(sender, "We have a sender for video"); ok(allLocalStreamsHaveSender(pc), - "Shouldn't have any streams without a corresponding sender"); + "Shouldn't have any local streams without a corresponding sender"); + ok(allRemoteStreamsHaveReceiver(pc), + "Shouldn't have any remote streams without a corresponding receiver"); var newTrack; var audiotrack; - return navigator.mediaDevices.getUserMedia({video:true, audio:true, fake:true}) + return navigator.mediaDevices.getUserMedia({video:true, audio:true}) .then(newStream => { newTrack = newStream.getVideoTracks()[0]; audiotrack = newStream.getAudioTracks()[0]; @@ -109,7 +118,8 @@ var sourceNode = test.audioCtx.createOscillator(); sourceNode.type = 'sine'; - // We need a frequency not too close to the fake audio track (1kHz). + // We need a frequency not too close to the fake audio track + // (440Hz for loopback devices, 1kHz for fake tracks). sourceNode.frequency.value = 2000; sourceNode.start(); @@ -153,7 +163,7 @@ is(e.name, "InvalidParameterError", "addTrack existing track should fail"); } - return navigator.mediaDevices.getUserMedia({video:true, fake: true}) + return navigator.mediaDevices.getUserMedia({video:true}) .then(differentStream => { var track = differentStream.getVideoTracks()[0]; try { diff --git a/dom/media/tests/mochitest/test_peerConnection_replaceVideoThenRenegotiate.html b/dom/media/tests/mochitest/test_peerConnection_replaceVideoThenRenegotiate.html index 1693e9e78e..5e36d7a5e0 100644 --- a/dom/media/tests/mochitest/test_peerConnection_replaceVideoThenRenegotiate.html +++ b/dom/media/tests/mochitest/test_peerConnection_replaceVideoThenRenegotiate.html @@ -21,7 +21,7 @@ var oldstream = test.pcLocal._pc.getLocalStreams()[0]; var oldtrack = oldstream.getVideoTracks()[0]; var sender = test.pcLocal._pc.getSenders()[0]; - return navigator.mediaDevices.getUserMedia({video:true, fake:true}) + return navigator.mediaDevices.getUserMedia({video:true}) .then(newstream => { var newtrack = newstream.getVideoTracks()[0]; return test.pcLocal.senderReplaceTrack(0, newtrack, newstream.id); diff --git a/dom/media/tests/mochitest/test_peerConnection_throwInCallbacks.html b/dom/media/tests/mochitest/test_peerConnection_throwInCallbacks.html index 7c0dec1859..ad5cb7d868 100644 --- a/dom/media/tests/mochitest/test_peerConnection_throwInCallbacks.html +++ b/dom/media/tests/mochitest/test_peerConnection_throwInCallbacks.html @@ -48,7 +48,7 @@ runNetworkTest(function () { pc2 = new RTCPeerConnection(); // Test success callbacks (happy path) - navigator.mozGetUserMedia({video:true, fake: true}, function(video1) { + navigator.mozGetUserMedia({video:true}, function(video1) { pc1.addStream(video1); pc1.createOffer(function(offer) { pc1.setLocalDescription(offer, function() { diff --git a/dom/tests/mochitest/general/test_interfaces.html b/dom/tests/mochitest/general/test_interfaces.html index dc8ea1b3d7..9d3e5d754c 100644 --- a/dom/tests/mochitest/general/test_interfaces.html +++ b/dom/tests/mochitest/general/test_interfaces.html @@ -999,6 +999,8 @@ var interfaceNamesInGlobalScope = "RTCSessionDescription", // IMPORTANT: Do not change this list without review from a DOM peer! "RTCStatsReport", +// IMPORTANT: Do not change this list without review from a DOM peer! + "RTCTrackEvent", // IMPORTANT: Do not change this list without review from a DOM peer! "Screen", // IMPORTANT: Do not change this list without review from a DOM peer! diff --git a/dom/webidl/PeerConnectionObserver.webidl b/dom/webidl/PeerConnectionObserver.webidl index 0b0d61ce89..ab82870a35 100644 --- a/dom/webidl/PeerConnectionObserver.webidl +++ b/dom/webidl/PeerConnectionObserver.webidl @@ -42,6 +42,6 @@ interface PeerConnectionObserver /* Changes to MediaStreamTracks */ void onAddStream(MediaStream stream); void onRemoveStream(MediaStream stream); - void onAddTrack(MediaStreamTrack track); + void onAddTrack(MediaStreamTrack track, sequence streams); void onRemoveTrack(MediaStreamTrack track); }; diff --git a/dom/webidl/RTCPeerConnection.webidl b/dom/webidl/RTCPeerConnection.webidl index 923b38a215..9dc946a396 100644 --- a/dom/webidl/RTCPeerConnection.webidl +++ b/dom/webidl/RTCPeerConnection.webidl @@ -141,8 +141,9 @@ interface RTCPeerConnection : EventTarget { attribute EventHandler onnegotiationneeded; attribute EventHandler onicecandidate; attribute EventHandler onsignalingstatechange; - attribute EventHandler onaddstream; - attribute EventHandler onaddtrack; // replaces onaddstream; see AddTrackEvent + attribute EventHandler onaddstream; // obsolete + attribute EventHandler onaddtrack; // obsolete + attribute EventHandler ontrack; // replaces onaddtrack and onaddstream. attribute EventHandler onremovestream; attribute EventHandler oniceconnectionstatechange; diff --git a/dom/webidl/RTCTrackEvent.webidl b/dom/webidl/RTCTrackEvent.webidl new file mode 100644 index 0000000000..a87915bbed --- /dev/null +++ b/dom/webidl/RTCTrackEvent.webidl @@ -0,0 +1,27 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/. + * + * The origin of this IDL file is + * http://w3c.github.io/webrtc-pc/#idl-def-RTCTrackEvent + */ + +dictionary RTCTrackEventInit : EventInit { + required RTCRtpReceiver receiver; + required MediaStreamTrack track; + sequence streams = []; +}; + +[Pref="media.peerconnection.enabled", + Constructor(DOMString type, RTCTrackEventInit eventInitDict)] +interface RTCTrackEvent : Event { + readonly attribute RTCRtpReceiver receiver; + readonly attribute MediaStreamTrack track; + +// TODO: Use FrozenArray once available. (Bug 1236777) +// readonly attribute FrozenArray streams; + + [Frozen, Cached, Pure] + readonly attribute sequence streams; // workaround +}; diff --git a/dom/webidl/moz.build b/dom/webidl/moz.build index 433ddf9287..b38f13c7bf 100644 --- a/dom/webidl/moz.build +++ b/dom/webidl/moz.build @@ -837,6 +837,7 @@ if CONFIG['MOZ_WEBRTC']: 'MediaStreamTrackEvent.webidl', 'RTCDataChannelEvent.webidl', 'RTCPeerConnectionIceEvent.webidl', + 'RTCTrackEvent.webidl', ] if CONFIG['MOZ_WEBSPEECH']: diff --git a/dom/workers/ServiceWorkerManager.cpp b/dom/workers/ServiceWorkerManager.cpp index aba599a28b..398fa6d080 100644 --- a/dom/workers/ServiceWorkerManager.cpp +++ b/dom/workers/ServiceWorkerManager.cpp @@ -496,6 +496,20 @@ ServiceWorkerRegistrationInfo::GetActiveWorker(nsIServiceWorkerInfo **aResult) return NS_OK; } +NS_IMETHODIMP +ServiceWorkerRegistrationInfo::GetWorkerByID(uint64_t aID, nsIServiceWorkerInfo **aResult) +{ + AssertIsOnMainThread(); + MOZ_ASSERT(aResult); + + RefPtr info = GetServiceWorkerInfoById(aID); + if (NS_WARN_IF(!info)) { + return NS_ERROR_FAILURE; + } + info.forget(aResult); + return NS_OK; +} + NS_IMETHODIMP ServiceWorkerRegistrationInfo::AddListener( nsIServiceWorkerRegistrationInfoListener *aListener) @@ -4057,6 +4071,30 @@ ServiceWorkerManager::GetRegistration(nsIPrincipal* aPrincipal, return GetRegistration(scopeKey, aScope); } +NS_IMETHODIMP +ServiceWorkerManager::GetRegistrationByPrincipal(nsIPrincipal* aPrincipal, + const nsAString& aScope, + nsIServiceWorkerRegistrationInfo** aInfo) +{ + MOZ_ASSERT(aPrincipal); + MOZ_ASSERT(aInfo); + + nsCOMPtr scopeURI; + nsresult rv = NS_NewURI(getter_AddRefs(scopeURI), aScope, nullptr, nullptr); + if (NS_FAILED(rv)) { + return NS_ERROR_FAILURE; + } + + RefPtr info = + GetServiceWorkerRegistrationInfo(aPrincipal, scopeURI); + if (!info) { + return NS_ERROR_FAILURE; + } + info.forget(aInfo); + + return NS_OK; +} + already_AddRefed ServiceWorkerManager::GetRegistration(const nsACString& aScopeKey, const nsACString& aScope) const diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp index c543112402..36051338c8 100644 --- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -2304,6 +2304,8 @@ WorkerPrivateParent::DisableDebugger() if (NS_FAILED(UnregisterWorkerDebugger(self->mDebugger))) { NS_WARNING("Failed to unregister worker debugger!"); } + + self->mDebugger = nullptr; } template @@ -2551,6 +2553,8 @@ WorkerPrivateParent::Freeze(JSContext* aCx, nsPIDOMWindow* aWindow) } } + DisableDebugger(); + RefPtr runnable = new FreezeRunnable(ParentAsWorkerPrivate()); if (!runnable->Dispatch(aCx)) { @@ -2617,6 +2621,8 @@ WorkerPrivateParent::Thaw(JSContext* aCx, nsPIDOMWindow* aWindow) } } + EnableDebugger(); + // Execute queued runnables before waking up the worker, otherwise the worker // could post new messages before we run those that have been queued. if (!IsSuspended() && !mQueuedRunnables.IsEmpty()) { @@ -3550,8 +3556,7 @@ WorkerDebugger::WorkerDebugger(WorkerPrivate* aWorkerPrivate) mCondVar(mMutex, "WorkerDebugger::mCondVar"), mWorkerPrivate(aWorkerPrivate), mIsEnabled(false), - mIsInitialized(false), - mIsFrozen(false) + mIsInitialized(false) { mWorkerPrivate->AssertIsOnParentThread(); } @@ -3606,7 +3611,7 @@ WorkerDebugger::GetIsChrome(bool* aResult) } NS_IMETHODIMP -WorkerDebugger::GetIsFrozen(bool* aResult) +WorkerDebugger::GetIsInitialized(bool* aResult) { AssertIsOnMainThread(); @@ -3616,7 +3621,7 @@ WorkerDebugger::GetIsFrozen(bool* aResult) return NS_ERROR_UNEXPECTED; } - *aResult = mIsFrozen; + *aResult = mIsInitialized; return NS_OK; } @@ -3695,6 +3700,36 @@ WorkerDebugger::GetWindow(nsIDOMWindow** aResult) return NS_OK; } +NS_IMETHODIMP +WorkerDebugger::GetPrincipal(nsIPrincipal** aResult) +{ + AssertIsOnMainThread(); + MOZ_ASSERT(aResult); + + if (!mWorkerPrivate) { + return NS_ERROR_UNEXPECTED; + } + + nsCOMPtr prin = mWorkerPrivate->GetPrincipal(); + prin.forget(aResult); + + return NS_OK; +} + +NS_IMETHODIMP +WorkerDebugger::GetServiceWorkerID(uint32_t* aResult) +{ + AssertIsOnMainThread(); + MOZ_ASSERT(aResult); + + if (!mWorkerPrivate || !mWorkerPrivate->IsServiceWorker()) { + return NS_ERROR_UNEXPECTED; + } + + *aResult = mWorkerPrivate->ServiceWorkerID(); + return NS_OK; +} + NS_IMETHODIMP WorkerDebugger::Initialize(const nsAString& aURL, JSContext* aCx) { @@ -3817,52 +3852,6 @@ WorkerDebugger::Disable() NotifyIsEnabled(false); } -void -WorkerDebugger::Freeze() -{ - mWorkerPrivate->AssertIsOnWorkerThread(); - - nsCOMPtr runnable = - NS_NewRunnableMethod(this, &WorkerDebugger::FreezeOnMainThread); - MOZ_ALWAYS_TRUE(NS_SUCCEEDED( - NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL))); -} - -void -WorkerDebugger::FreezeOnMainThread() -{ - AssertIsOnMainThread(); - - mIsFrozen = true; - - for (size_t index = 0; index < mListeners.Length(); ++index) { - mListeners[index]->OnFreeze(); - } -} - -void -WorkerDebugger::Thaw() -{ - mWorkerPrivate->AssertIsOnWorkerThread(); - - nsCOMPtr runnable = - NS_NewRunnableMethod(this, &WorkerDebugger::ThawOnMainThread); - MOZ_ALWAYS_TRUE(NS_SUCCEEDED( - NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL))); -} - -void -WorkerDebugger::ThawOnMainThread() -{ - AssertIsOnMainThread(); - - mIsFrozen = false; - - for (size_t index = 0; index < mListeners.Length(); ++index) { - mListeners[index]->OnThaw(); - } -} - void WorkerDebugger::PostMessageToDebugger(const nsAString& aMessage) { @@ -5045,7 +5034,6 @@ WorkerPrivate::FreezeInternal(JSContext* aCx) NS_ASSERTION(!mFrozen, "Already frozen!"); mFrozen = true; - mDebugger->Freeze(); return true; } @@ -5057,7 +5045,6 @@ WorkerPrivate::ThawInternal(JSContext* aCx) NS_ASSERTION(mFrozen, "Not yet frozen!"); mFrozen = false; - mDebugger->Thaw(); return true; } diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h index d315eb8eee..d57f030fc8 100644 --- a/dom/workers/WorkerPrivate.h +++ b/dom/workers/WorkerPrivate.h @@ -813,7 +813,6 @@ class WorkerDebugger : public nsIWorkerDebugger { // Only touched on the main thread. bool mIsInitialized; - bool mIsFrozen; nsTArray> mListeners; public: @@ -834,12 +833,6 @@ public: void Disable(); - void - Freeze(); - - void - Thaw(); - void PostMessageToDebugger(const nsAString& aMessage); @@ -854,12 +847,6 @@ private: void NotifyIsEnabled(bool aIsEnabled); - void - FreezeOnMainThread(); - - void - ThawOnMainThread(); - void PostMessageToDebuggerOnMainThread(const nsAString& aMessage); diff --git a/dom/workers/XMLHttpRequest.cpp b/dom/workers/XMLHttpRequest.cpp index 66e39847df..252e961660 100644 --- a/dom/workers/XMLHttpRequest.cpp +++ b/dom/workers/XMLHttpRequest.cpp @@ -16,11 +16,11 @@ #include "mozilla/ArrayUtils.h" #include "mozilla/dom/Exceptions.h" #include "mozilla/dom/File.h" +#include "mozilla/dom/FormData.h" #include "mozilla/dom/ProgressEvent.h" #include "mozilla/dom/StructuredCloneHolder.h" #include "nsComponentManagerUtils.h" #include "nsContentUtils.h" -#include "nsFormData.h" #include "nsJSUtils.h" #include "nsThreadUtils.h" #include "nsVariant.h" @@ -2203,7 +2203,7 @@ XMLHttpRequest::Send(Blob& aBody, ErrorResult& aRv) } void -XMLHttpRequest::Send(nsFormData& aBody, ErrorResult& aRv) +XMLHttpRequest::Send(FormData& aBody, ErrorResult& aRv) { mWorkerPrivate->AssertIsOnWorkerThread(); JSContext* cx = mWorkerPrivate->GetJSContext(); diff --git a/dom/workers/XMLHttpRequest.h b/dom/workers/XMLHttpRequest.h index 64d3acb8e0..452ec1cb8a 100644 --- a/dom/workers/XMLHttpRequest.h +++ b/dom/workers/XMLHttpRequest.h @@ -174,7 +174,7 @@ public: Send(Blob& aBody, ErrorResult& aRv); void - Send(nsFormData& aBody, ErrorResult& aRv); + Send(FormData& aBody, ErrorResult& aRv); void Send(const ArrayBuffer& aBody, ErrorResult& aRv); diff --git a/dom/workers/nsIWorkerDebugger.idl b/dom/workers/nsIWorkerDebugger.idl index e8052b226d..5a4981041c 100644 --- a/dom/workers/nsIWorkerDebugger.idl +++ b/dom/workers/nsIWorkerDebugger.idl @@ -1,8 +1,9 @@ #include "nsISupports.idl" interface nsIDOMWindow; +interface nsIPrincipal; -[scriptable, uuid(530db841-1b2c-485a-beeb-f2b1acb9714e)] +[scriptable, uuid(9cf3b48e-361d-486a-8917-55cf8d00bb41)] interface nsIWorkerDebuggerListener : nsISupports { void onClose(); @@ -10,14 +11,10 @@ interface nsIWorkerDebuggerListener : nsISupports void onError(in DOMString filename, in unsigned long lineno, in DOMString message); - void onFreeze(); - void onMessage(in DOMString message); - - void onThaw(); }; -[scriptable, builtinclass, uuid(d7c73e54-3c41-4393-9d13-fa2ed4Ba6764)] +[scriptable, builtinclass, uuid(2fe71e0d-3a39-40a3-b809-8418b72328b4)] interface nsIWorkerDebugger : nsISupports { const unsigned long TYPE_DEDICATED = 0; @@ -28,7 +25,7 @@ interface nsIWorkerDebugger : nsISupports readonly attribute bool isChrome; - readonly attribute bool isFrozen; + readonly attribute bool isInitialized; readonly attribute nsIWorkerDebugger parent; @@ -38,6 +35,10 @@ interface nsIWorkerDebugger : nsISupports readonly attribute nsIDOMWindow window; + readonly attribute nsIPrincipal principal; + + readonly attribute unsigned long serviceWorkerID; + [implicit_jscontext] void initialize(in DOMString url); diff --git a/dom/workers/test/WorkerDebugger.isFrozen_iframe1.html b/dom/workers/test/WorkerDebugger_frozen_iframe1.html similarity index 77% rename from dom/workers/test/WorkerDebugger.isFrozen_iframe1.html rename to dom/workers/test/WorkerDebugger_frozen_iframe1.html index d971892708..5919231215 100644 --- a/dom/workers/test/WorkerDebugger.isFrozen_iframe1.html +++ b/dom/workers/test/WorkerDebugger_frozen_iframe1.html @@ -3,7 +3,7 @@ +`; + } else if (this.uri.spec.startsWith(ACTION_BASE)) { + var postData = ""; + if (this._uploadStream) { + var bstream = Cc["@mozilla.org/binaryinputstream;1"] + .createInstance(Ci.nsIBinaryInputStream); + bstream.setInputStream(this._uploadStream); + postData = bstream.readBytes(bstream.available()); + } + data += ` + + +`; + } + + data += ` + + +`; + + var stream = Cc["@mozilla.org/io/string-input-stream;1"] + .createInstance(Ci.nsIStringInputStream); + stream.setData(data, data.length); + + var runnable = { + run: () => { + try { + aListener.onStartRequest(this, aContext); + } catch(e) {} + try { + aListener.onDataAvailable(this, aContext, stream, 0, stream.available()); + } catch(e) {} + try { + aListener.onStopRequest(this, aContext, Cr.NS_OK); + } catch(e) {} + } + }; + Services.tm.currentThread.dispatch(runnable, Ci.nsIEventTarget.DISPATCH_NORMAL); + }, + asyncOpen2: function(aListener) { + this.asyncOpen(aListener, null); + }, + + /** nsIRequest */ + get name() { + return this.uri.spec; + }, + isPending: function () { + return false; + }, + get status() { + return Cr.NS_OK; + }, + cancel: function(status) {}, + loadGroup: null, + loadFlags: Ci.nsIRequest.LOAD_NORMAL | + Ci.nsIRequest.INHIBIT_CACHING | + Ci.nsIRequest.LOAD_BYPASS_CACHE, +}; + +function frameScript() { + addMessageListener("Test:WaitForIFrame", function() { + var check = function() { + if (content) { + var frame = content.document.getElementById("frame"); + if (frame) { + var upload_stream = frame.contentDocument.getElementById("upload_stream"); + var post_data = frame.contentDocument.getElementById("post_data"); + if (upload_stream && post_data) { + sendAsyncMessage("Test:IFrameLoaded", [upload_stream.value, post_data.value]); + return; + } + } + } + + setTimeout(check, 100); + }; + + check(); + }); +} + +function loadTestTab(uri) { + gBrowser.selectedTab = gBrowser.addTab(uri); + var browser = gBrowser.selectedBrowser; + + let manager = browser.messageManager; + browser.messageManager.loadFrameScript("data:,(" + frameScript.toString() + ")();", true); + + return new Promise(resolve => { + function listener({ data: [hasUploadStream, postData] }) { + manager.removeMessageListener("Test:IFrameLoaded", listener); + resolve([hasUploadStream, atob(postData)]); + } + + manager.addMessageListener("Test:IFrameLoaded", listener); + manager.sendAsyncMessage("Test:WaitForIFrame"); + }); +} + +add_task(function*() { + var handler = new CustomProtocolHandler(); + var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar); + registrar.registerFactory(handler.classID, "", + "@mozilla.org/network/protocol;1?name=" + handler.scheme, + handler); + registerCleanupFunction(function() { + registrar.unregisterFactory(handler.classID, handler); + }); +}); + +add_task(function*() { + var [hasUploadStream, postData] = yield loadTestTab(NORMAL_FORM_URI); + is(hasUploadStream, "no", "normal action should not have uploadStream"); + + gBrowser.removeCurrentTab(); +}); + +add_task(function*() { + var [hasUploadStream, postData] = yield loadTestTab(UPLOAD_FORM_URI); + is(hasUploadStream, "no", "upload action should not have uploadStream"); + + gBrowser.removeCurrentTab(); +}); + +add_task(function*() { + var [hasUploadStream, postData] = yield loadTestTab(POST_FORM_URI); + is(hasUploadStream, "yes", "post action should have uploadStream"); + is(postData, + "Content-Type: text/plain\r\n" + + "Content-Length: 9\r\n" + + "\r\n" + + "foo=bar\r\n", "POST data is received correctly"); + + gBrowser.removeCurrentTab(); +}); diff --git a/testing/specialpowers/content/MockFilePicker.jsm b/testing/specialpowers/content/MockFilePicker.jsm index c1de2bcaed..efa8b973f3 100644 --- a/testing/specialpowers/content/MockFilePicker.jsm +++ b/testing/specialpowers/content/MockFilePicker.jsm @@ -146,7 +146,9 @@ MockFilePickerInstance.prototype = { return null; }, - get domfile() { + + // We don't support directories here. + get domFileOrDirectory() { if (MockFilePicker.returnFiles.length >= 1) { // window.File does not implement nsIFile if (!MockFilePicker.isNsIFile(MockFilePicker.returnFiles[0])) { @@ -184,7 +186,7 @@ MockFilePickerInstance.prototype = { } }; }, - get domfiles() { + get domFileOrDirectoryEnumerator() { let utils = this.parent.QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIDOMWindowUtils); return { diff --git a/testing/web-platform/meta/webrtc/rtcpeerconnection/rtcpeerconnection-idl.html.ini b/testing/web-platform/meta/webrtc/rtcpeerconnection/rtcpeerconnection-idl.html.ini index b60455db08..2feef2ad53 100644 --- a/testing/web-platform/meta/webrtc/rtcpeerconnection/rtcpeerconnection-idl.html.ini +++ b/testing/web-platform/meta/webrtc/rtcpeerconnection/rtcpeerconnection-idl.html.ini @@ -1,3 +1,281 @@ [rtcpeerconnection-idl.html] type: testharness - expected: ERROR + [RTCPeerConnection interface: operation createOffer(RTCOfferOptions)] + expected: FAIL + + [RTCPeerConnection interface: operation setLocalDescription(RTCSessionDescription)] + expected: FAIL + + [RTCPeerConnection interface: operation setRemoteDescription(RTCSessionDescription)] + expected: FAIL + + [RTCPeerConnection interface: operation addIceCandidate(RTCIceCandidate)] + expected: FAIL + + [RTCPeerConnection interface: attribute canTrickleIceCandidates] + expected: FAIL + + [RTCPeerConnection interface: attribute onicegatheringstatechange] + expected: FAIL + + [RTCPeerConnection interface: operation createOffer(RTCSessionDescriptionCallback,RTCPeerConnectionErrorCallback,RTCOfferOptions)] + expected: FAIL + + [RTCPeerConnection interface: operation setLocalDescription(RTCSessionDescription,VoidFunction,RTCPeerConnectionErrorCallback)] + expected: FAIL + + [RTCPeerConnection interface: operation createAnswer(RTCSessionDescriptionCallback,RTCPeerConnectionErrorCallback)] + expected: FAIL + + [RTCPeerConnection interface: operation setRemoteDescription(RTCSessionDescription,VoidFunction,RTCPeerConnectionErrorCallback)] + expected: FAIL + + [RTCPeerConnection interface: operation addIceCandidate(RTCIceCandidate,VoidFunction,RTCPeerConnectionErrorCallback)] + expected: FAIL + + [RTCPeerConnection interface: operation addTrack(MediaStreamTrack,MediaStream)] + expected: FAIL + + [RTCPeerConnection interface: operation getStats(MediaStreamTrack,RTCStatsCallback,RTCPeerConnectionErrorCallback)] + expected: FAIL + + [RTCPeerConnection interface: operation getIdentityAssertion()] + expected: FAIL + + [RTCPeerConnection interface: calling setLocalDescription(RTCSessionDescription) on pc with too few arguments must throw TypeError] + expected: FAIL + + [RTCPeerConnection interface: calling setRemoteDescription(RTCSessionDescription) on pc with too few arguments must throw TypeError] + expected: FAIL + + [RTCPeerConnection interface: calling addIceCandidate(RTCIceCandidate) on pc with too few arguments must throw TypeError] + expected: FAIL + + [RTCPeerConnection interface: calling setLocalDescription(RTCSessionDescription,VoidFunction,RTCPeerConnectionErrorCallback) on pc with too few arguments must throw TypeError] + expected: FAIL + + [RTCPeerConnection interface: calling setRemoteDescription(RTCSessionDescription,VoidFunction,RTCPeerConnectionErrorCallback) on pc with too few arguments must throw TypeError] + expected: FAIL + + [RTCPeerConnection interface: calling addIceCandidate(RTCIceCandidate,VoidFunction,RTCPeerConnectionErrorCallback) on pc with too few arguments must throw TypeError] + expected: FAIL + + [RTCPeerConnection interface: operation createAnswer(RTCAnswerOptions)] + expected: FAIL + + [RTCPeerConnection interface: attribute currentLocalDescription] + expected: FAIL + + [RTCPeerConnection interface: attribute pendingLocalDescription] + expected: FAIL + + [RTCPeerConnection interface: attribute currentRemoteDescription] + expected: FAIL + + [RTCPeerConnection interface: attribute pendingRemoteDescription] + expected: FAIL + + [RTCPeerConnection interface: operation setConfiguration(RTCConfiguration)] + expected: FAIL + + [RTCPeerConnection interface: attribute dtmf] + expected: FAIL + + [RTCPeerConnection interface: operation getStats(MediaStreamTrack)] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "currentLocalDescription" with the proper type (4)] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "pendingLocalDescription" with the proper type (5)] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "currentRemoteDescription" with the proper type (8)] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "pendingRemoteDescription" with the proper type (9)] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "signalingState" with the proper type (11)] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "iceGatheringState" with the proper type (12)] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "iceConnectionState" with the proper type (13)] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "canTrickleIceCandidates" with the proper type (14)] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "setConfiguration" with the proper type (16)] + expected: FAIL + + [RTCPeerConnection interface: calling setConfiguration(RTCConfiguration) on pc with too few arguments must throw TypeError] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "onnegotiationneeded" with the proper type (18)] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "onicecandidate" with the proper type (19)] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "onsignalingstatechange" with the proper type (20)] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "oniceconnectionstatechange" with the proper type (21)] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "onicegatheringstatechange" with the proper type (22)] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "ontrack" with the proper type (34)] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "ondatachannel" with the proper type (36)] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "dtmf" with the proper type (37)] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "peerIdentity" with the proper type (41)] + expected: FAIL + + [RTCPeerConnection interface: operation createOffer(RTCOfferOptions)] + expected: FAIL + + [RTCPeerConnection interface: operation createAnswer()] + expected: FAIL + + [RTCPeerConnection interface: operation setLocalDescription(RTCSessionDescription)] + expected: FAIL + + [RTCPeerConnection interface: operation setRemoteDescription(RTCSessionDescription)] + expected: FAIL + + [RTCPeerConnection interface: operation updateIce(RTCConfiguration)] + expected: FAIL + + [RTCPeerConnection interface: operation addIceCandidate(RTCIceCandidate)] + expected: FAIL + + [RTCPeerConnection interface: attribute canTrickleIceCandidates] + expected: FAIL + + [RTCPeerConnection interface: attribute onicegatheringstatechange] + expected: FAIL + + [RTCPeerConnection interface: operation createOffer(RTCSessionDescriptionCallback,RTCPeerConnectionErrorCallback,RTCOfferOptions)] + expected: FAIL + + [RTCPeerConnection interface: operation setLocalDescription(RTCSessionDescription,VoidFunction,RTCPeerConnectionErrorCallback)] + expected: FAIL + + [RTCPeerConnection interface: operation createAnswer(RTCSessionDescriptionCallback,RTCPeerConnectionErrorCallback)] + expected: FAIL + + [RTCPeerConnection interface: operation setRemoteDescription(RTCSessionDescription,VoidFunction,RTCPeerConnectionErrorCallback)] + expected: FAIL + + [RTCPeerConnection interface: operation addIceCandidate(RTCIceCandidate,VoidFunction,RTCPeerConnectionErrorCallback)] + expected: FAIL + + [RTCPeerConnection interface: operation addTrack(MediaStreamTrack,MediaStream)] + expected: FAIL + + [RTCPeerConnection interface: operation createDTMFSender(MediaStreamTrack)] + expected: FAIL + + [RTCPeerConnection interface: operation getStats(MediaStreamTrack,RTCStatsCallback,RTCPeerConnectionErrorCallback)] + expected: FAIL + + [RTCPeerConnection interface: operation getIdentityAssertion()] + expected: FAIL + + [RTCPeerConnection interface: attribute onidentityresult] + expected: FAIL + + [RTCPeerConnection interface: attribute onpeeridentity] + expected: FAIL + + [RTCPeerConnection interface: attribute onidpassertionerror] + expected: FAIL + + [RTCPeerConnection interface: attribute onidpvalidationerror] + expected: FAIL + + [RTCPeerConnection interface: calling setLocalDescription(RTCSessionDescription) on pc with too few arguments must throw TypeError] + expected: FAIL + + [RTCPeerConnection interface: calling setRemoteDescription(RTCSessionDescription) on pc with too few arguments must throw TypeError] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "signalingState" with the proper type (6)] + expected: FAIL + + [RTCPeerConnection interface: calling updateIce(RTCConfiguration) on pc with too few arguments must throw TypeError] + expected: FAIL + + [RTCPeerConnection interface: calling addIceCandidate(RTCIceCandidate) on pc with too few arguments must throw TypeError] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "iceGatheringState" with the proper type (9)] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "iceConnectionState" with the proper type (10)] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "canTrickleIceCandidates" with the proper type (11)] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "onnegotiationneeded" with the proper type (14)] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "onicecandidate" with the proper type (15)] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "onsignalingstatechange" with the proper type (16)] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "oniceconnectionstatechange" with the proper type (17)] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "onicegatheringstatechange" with the proper type (18)] + expected: FAIL + + [RTCPeerConnection interface: calling setLocalDescription(RTCSessionDescription,VoidFunction,RTCPeerConnectionErrorCallback) on pc with too few arguments must throw TypeError] + expected: FAIL + + [RTCPeerConnection interface: calling setRemoteDescription(RTCSessionDescription,VoidFunction,RTCPeerConnectionErrorCallback) on pc with too few arguments must throw TypeError] + expected: FAIL + + [RTCPeerConnection interface: calling addIceCandidate(RTCIceCandidate,VoidFunction,RTCPeerConnectionErrorCallback) on pc with too few arguments must throw TypeError] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "ontrack" with the proper type (28)] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "ondatachannel" with the proper type (30)] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "createDTMFSender" with the proper type (31)] + expected: FAIL + + [RTCPeerConnection interface: calling createDTMFSender(MediaStreamTrack) on pc with too few arguments must throw TypeError] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "peerIdentity" with the proper type (35)] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "onidentityresult" with the proper type (36)] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "onpeeridentity" with the proper type (37)] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "onidpassertionerror" with the proper type (38)] + expected: FAIL + + [RTCPeerConnection interface: pc must inherit property "onidpvalidationerror" with the proper type (39)] + expected: FAIL + diff --git a/toolkit/components/alerts/AlertNotification.cpp b/toolkit/components/alerts/AlertNotification.cpp index c3e1e85aca..ef443f714a 100644 --- a/toolkit/components/alerts/AlertNotification.cpp +++ b/toolkit/components/alerts/AlertNotification.cpp @@ -4,6 +4,8 @@ #include "mozilla/AlertNotification.h" +#include "nsAlertsUtils.h" + namespace mozilla { NS_IMPL_CYCLE_COLLECTION(AlertNotification, mPrincipal) @@ -122,4 +124,18 @@ AlertNotification::GetInPrivateBrowsing(bool* aInPrivateBrowsing) return NS_OK; } +NS_IMETHODIMP +AlertNotification::GetActionable(bool* aActionable) +{ + *aActionable = nsAlertsUtils::IsActionablePrincipal(mPrincipal); + return NS_OK; +} + +NS_IMETHODIMP +AlertNotification::GetSource(nsAString& aSource) +{ + nsAlertsUtils::GetSourceHostPort(mPrincipal, aSource); + return NS_OK; +} + } // namespace mozilla diff --git a/toolkit/components/alerts/nsAlertsService.cpp b/toolkit/components/alerts/nsAlertsService.cpp index 7506751ce2..d6765770ec 100644 --- a/toolkit/components/alerts/nsAlertsService.cpp +++ b/toolkit/components/alerts/nsAlertsService.cpp @@ -28,8 +28,12 @@ using mozilla::dom::ContentChild; NS_IMPL_ISUPPORTS(nsAlertsService, nsIAlertsService, nsIAlertsDoNotDisturb, nsIAlertsProgressListener) -nsAlertsService::nsAlertsService() +nsAlertsService::nsAlertsService() : + mBackend(nullptr) { +#ifndef MOZ_WIDGET_ANDROID + mBackend = do_GetService(NS_SYSTEMALERTSERVICE_CONTRACTID); +#endif // MOZ_WIDGET_ANDROID } nsAlertsService::~nsAlertsService() @@ -104,6 +108,7 @@ NS_IMETHODIMP nsAlertsService::ShowAlert(nsIAlertNotification * aAlert, return NS_OK; } +#ifdef MOZ_WIDGET_ANDROID nsAutoString imageUrl; rv = aAlert->GetImageURL(imageUrl); NS_ENSURE_SUCCESS(rv, rv); @@ -124,17 +129,19 @@ NS_IMETHODIMP nsAlertsService::ShowAlert(nsIAlertNotification * aAlert, rv = aAlert->GetPrincipal(getter_AddRefs(principal)); NS_ENSURE_SUCCESS(rv, rv); -#ifdef MOZ_WIDGET_ANDROID mozilla::AndroidBridge::Bridge()->ShowAlertNotification(imageUrl, title, text, cookie, aAlertListener, name, principal); return NS_OK; #else // Check if there is an optional service that handles system-level notifications - nsCOMPtr sysAlerts(do_GetService(NS_SYSTEMALERTSERVICE_CONTRACTID)); - if (sysAlerts) { - rv = sysAlerts->ShowAlert(aAlert, aAlertListener); - if (NS_SUCCEEDED(rv)) - return NS_OK; + if (mBackend) { + rv = mBackend->ShowAlert(aAlert, aAlertListener); + if (NS_SUCCEEDED(rv)) { + return rv; + } + // If the system backend failed to show the alert, clear the backend and + // retry with XUL notifications. Future alerts will always use XUL. + mBackend = nullptr; } if (!ShouldShowAlert()) { @@ -144,27 +151,10 @@ NS_IMETHODIMP nsAlertsService::ShowAlert(nsIAlertNotification * aAlert, return NS_OK; } - bool textClickable; - rv = aAlert->GetTextClickable(&textClickable); - NS_ENSURE_SUCCESS(rv, rv); - - nsAutoString bidi; - rv = aAlert->GetDir(bidi); - NS_ENSURE_SUCCESS(rv, rv); - - nsAutoString lang; - rv = aAlert->GetLang(lang); - NS_ENSURE_SUCCESS(rv, rv); - - bool inPrivateBrowsing; - rv = aAlert->GetInPrivateBrowsing(&inPrivateBrowsing); - NS_ENSURE_SUCCESS(rv, rv); - // Use XUL notifications as a fallback if above methods have failed. - rv = mXULAlerts.ShowAlertNotification(imageUrl, title, text, textClickable, - cookie, aAlertListener, name, - bidi, lang, principal, inPrivateBrowsing); - return rv; + nsCOMPtr xulBackend(nsXULAlerts::GetInstance()); + NS_ENSURE_TRUE(xulBackend, NS_ERROR_FAILURE); + return xulBackend->ShowAlert(aAlert, aAlertListener); #endif // !MOZ_WIDGET_ANDROID } @@ -182,13 +172,21 @@ NS_IMETHODIMP nsAlertsService::CloseAlert(const nsAString& aAlertName, return NS_OK; #else + nsresult rv; // Try the system notification service. - nsCOMPtr sysAlerts(do_GetService(NS_SYSTEMALERTSERVICE_CONTRACTID)); - if (sysAlerts) { - return sysAlerts->CloseAlert(aAlertName, nullptr); + if (mBackend) { + rv = mBackend->CloseAlert(aAlertName, aPrincipal); + if (NS_WARN_IF(NS_FAILED(rv))) { + // If the system backend failed to close the alert, fall back to XUL for + // future alerts. + mBackend = nullptr; + } + } else { + nsCOMPtr xulBackend(nsXULAlerts::GetInstance()); + NS_ENSURE_TRUE(xulBackend, NS_ERROR_FAILURE); + rv = xulBackend->CloseAlert(aAlertName, aPrincipal); } - - return mXULAlerts.CloseAlert(aAlertName); + return rv; #endif // !MOZ_WIDGET_ANDROID } @@ -199,17 +197,9 @@ NS_IMETHODIMP nsAlertsService::GetManualDoNotDisturb(bool* aRetVal) #ifdef MOZ_WIDGET_ANDROID return NS_ERROR_NOT_IMPLEMENTED; #else - // Try the system notification service. - nsCOMPtr sysAlerts(do_GetService(NS_SYSTEMALERTSERVICE_CONTRACTID)); - if (sysAlerts) { - nsCOMPtr alertsDND(do_GetService(NS_SYSTEMALERTSERVICE_CONTRACTID)); - if (!alertsDND) { - return NS_ERROR_NOT_IMPLEMENTED; - } - return alertsDND->GetManualDoNotDisturb(aRetVal); - } - - return mXULAlerts.GetManualDoNotDisturb(aRetVal); + nsCOMPtr alertsDND(GetDNDBackend()); + NS_ENSURE_TRUE(alertsDND, NS_ERROR_NOT_IMPLEMENTED); + return alertsDND->GetManualDoNotDisturb(aRetVal); #endif } @@ -218,20 +208,13 @@ NS_IMETHODIMP nsAlertsService::SetManualDoNotDisturb(bool aDoNotDisturb) #ifdef MOZ_WIDGET_ANDROID return NS_ERROR_NOT_IMPLEMENTED; #else - // Try the system notification service. - nsCOMPtr sysAlerts(do_GetService(NS_SYSTEMALERTSERVICE_CONTRACTID)); - nsresult rv; - if (sysAlerts) { - nsCOMPtr alertsDND(do_GetService(NS_SYSTEMALERTSERVICE_CONTRACTID)); - if (!alertsDND) { - return NS_ERROR_NOT_IMPLEMENTED; - } - rv = alertsDND->SetManualDoNotDisturb(aDoNotDisturb); - } else { - rv = mXULAlerts.SetManualDoNotDisturb(aDoNotDisturb); - } + nsCOMPtr alertsDND(GetDNDBackend()); + NS_ENSURE_TRUE(alertsDND, NS_ERROR_NOT_IMPLEMENTED); - Telemetry::Accumulate(Telemetry::ALERTS_SERVICE_DND_ENABLED, 1); + nsresult rv = alertsDND->SetManualDoNotDisturb(aDoNotDisturb); + if (NS_SUCCEEDED(rv)) { + Telemetry::Accumulate(Telemetry::ALERTS_SERVICE_DND_ENABLED, 1); + } return rv; #endif } @@ -260,3 +243,16 @@ NS_IMETHODIMP nsAlertsService::OnCancel(const nsAString & aAlertName) return NS_ERROR_NOT_IMPLEMENTED; #endif // !MOZ_WIDGET_ANDROID } + +already_AddRefed +nsAlertsService::GetDNDBackend() +{ + // Try the system notification service. + nsCOMPtr backend = mBackend; + if (!backend) { + backend = nsXULAlerts::GetInstance(); + } + + nsCOMPtr alertsDND(do_QueryInterface(backend)); + return alertsDND.forget(); +} diff --git a/toolkit/components/alerts/nsAlertsService.h b/toolkit/components/alerts/nsAlertsService.h index 71921da397..0af4b9d2ec 100644 --- a/toolkit/components/alerts/nsAlertsService.h +++ b/toolkit/components/alerts/nsAlertsService.h @@ -43,7 +43,8 @@ protected: virtual ~nsAlertsService(); bool ShouldShowAlert(); - nsXULAlerts mXULAlerts; + already_AddRefed GetDNDBackend(); + nsCOMPtr mBackend; }; #endif /* nsAlertsService_h__ */ diff --git a/toolkit/components/alerts/nsIAlertsService.idl b/toolkit/components/alerts/nsIAlertsService.idl index ac703d019f..f11848f566 100644 --- a/toolkit/components/alerts/nsIAlertsService.idl +++ b/toolkit/components/alerts/nsIAlertsService.idl @@ -12,7 +12,7 @@ interface nsIPrincipal; #define ALERT_NOTIFICATION_CONTRACTID "@mozilla.org/alert-notification;1" %} -[scriptable, uuid(b26b4a67-81b0-4270-8311-1e00a097ef92)] +[scriptable, uuid(9e87fc34-8dbb-4b14-a724-b27be6822ec8)] interface nsIAlertNotification : nsISupports { /** Initializes an alert notification. */ @@ -81,8 +81,7 @@ interface nsIAlertNotification : nsISupports /** * The principal of the page that created the alert. Used for IPC security - * checks, and to determine whether the alert should show the source string - * and action buttons. + * checks, and to determine whether the alert is actionable. */ readonly attribute nsIPrincipal principal; @@ -91,6 +90,19 @@ interface nsIAlertNotification : nsISupports * in private browsing mode. */ readonly attribute boolean inPrivateBrowsing; + + /** + * Indicates whether this alert should show the source string and action + * buttons. False for system alerts (which can omit the principal), or + * expanded, system, and null principals. + */ + readonly attribute boolean actionable; + + /** + * The host and port of the originating page, or an empty string if the alert + * is not actionable. + */ + readonly attribute AString source; }; [scriptable, uuid(f7a36392-d98b-4141-a7d7-4e46642684e3)] diff --git a/toolkit/components/alerts/nsXULAlerts.cpp b/toolkit/components/alerts/nsXULAlerts.cpp index a57b96edf7..d7ed0f5d85 100644 --- a/toolkit/components/alerts/nsXULAlerts.cpp +++ b/toolkit/components/alerts/nsXULAlerts.cpp @@ -5,12 +5,13 @@ #include "nsXULAlerts.h" -#include "nsAutoPtr.h" +#include "nsComponentManagerUtils.h" +#include "nsCOMPtr.h" +#include "mozilla/ClearOnShutdown.h" #include "mozilla/LookAndFeel.h" #include "mozilla/dom/Notification.h" #include "mozilla/unused.h" #include "nsIServiceManager.h" -#include "nsAlertsUtils.h" #include "nsISupportsArray.h" #include "nsISupportsPrimitives.h" #include "nsPIDOMWindow.h" @@ -21,6 +22,10 @@ using mozilla::dom::NotificationTelemetryService; #define ALERT_CHROME_URL "chrome://global/content/alerts/alert.xul" +namespace { +StaticRefPtr gXULAlerts; +} // anonymous namespace + NS_IMPL_ISUPPORTS(nsXULAlertObserver, nsIObserver) NS_IMETHODIMP @@ -43,16 +48,52 @@ nsXULAlertObserver::Observe(nsISupports* aSubject, const char* aTopic, return rv; } -nsresult +NS_IMPL_ISUPPORTS(nsXULAlerts, nsIAlertsService, nsIAlertsDoNotDisturb) + +/* static */ already_AddRefed +nsXULAlerts::GetInstance() +{ + if (!gXULAlerts) { + gXULAlerts = new nsXULAlerts(); + ClearOnShutdown(&gXULAlerts); + } + RefPtr instance = gXULAlerts.get(); + return instance.forget(); +} + +NS_IMETHODIMP nsXULAlerts::ShowAlertNotification(const nsAString& aImageUrl, const nsAString& aAlertTitle, const nsAString& aAlertText, bool aAlertTextClickable, const nsAString& aAlertCookie, nsIObserver* aAlertListener, const nsAString& aAlertName, const nsAString& aBidi, - const nsAString& aLang, nsIPrincipal* aPrincipal, - bool aInPrivateBrowsing) + const nsAString& aLang, const nsAString & aData, + nsIPrincipal* aPrincipal, bool aInPrivateBrowsing) { + nsCOMPtr alert = + do_CreateInstance(ALERT_NOTIFICATION_CONTRACTID); + NS_ENSURE_TRUE(alert, NS_ERROR_FAILURE); + nsresult rv = alert->Init(aAlertName, aImageUrl, aAlertTitle, + aAlertText, aAlertTextClickable, + aAlertCookie, aBidi, aLang, aData, + aPrincipal, aInPrivateBrowsing); + NS_ENSURE_SUCCESS(rv, rv); + return ShowAlert(alert, aAlertListener); +} + +NS_IMETHODIMP +nsXULAlerts::ShowAlert(nsIAlertNotification* aAlert, + nsIObserver* aAlertListener) +{ + bool inPrivateBrowsing; + nsresult rv = aAlert->GetInPrivateBrowsing(&inPrivateBrowsing); + NS_ENSURE_SUCCESS(rv, rv); + + nsAutoString cookie; + rv = aAlert->GetCookie(cookie); + NS_ENSURE_SUCCESS(rv, rv); + if (mDoNotDisturb) { - if (!aInPrivateBrowsing) { + if (!inPrivateBrowsing) { RefPtr telemetry = NotificationTelemetryService::GetInstance(); if (telemetry) { @@ -60,51 +101,88 @@ nsXULAlerts::ShowAlertNotification(const nsAString& aImageUrl, const nsAString& // libnotify backends will fire `alertshow` even if "do not disturb" // is enabled. In that case, `NotificationObserver` will record the // sender. - Unused << NS_WARN_IF(NS_FAILED(telemetry->RecordSender(aPrincipal))); + nsCOMPtr principal; + if (NS_SUCCEEDED(aAlert->GetPrincipal(getter_AddRefs(principal)))) { + Unused << NS_WARN_IF(NS_FAILED(telemetry->RecordSender(principal))); + } } } + if (aAlertListener) + aAlertListener->Observe(nullptr, "alertfinished", cookie.get()); return NS_OK; } + nsAutoString name; + rv = aAlert->GetName(name); + NS_ENSURE_SUCCESS(rv, rv); + + nsAutoString imageUrl; + rv = aAlert->GetImageURL(imageUrl); + NS_ENSURE_SUCCESS(rv, rv); + + nsAutoString title; + rv = aAlert->GetTitle(title); + NS_ENSURE_SUCCESS(rv, rv); + + nsAutoString text; + rv = aAlert->GetText(text); + NS_ENSURE_SUCCESS(rv, rv); + + bool textClickable; + rv = aAlert->GetTextClickable(&textClickable); + NS_ENSURE_SUCCESS(rv, rv); + + nsAutoString bidi; + rv = aAlert->GetDir(bidi); + NS_ENSURE_SUCCESS(rv, rv); + + nsAutoString lang; + rv = aAlert->GetLang(lang); + NS_ENSURE_SUCCESS(rv, rv); + + nsAutoString source; + rv = aAlert->GetSource(source); + NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID)); nsCOMPtr argsArray; - nsresult rv = NS_NewISupportsArray(getter_AddRefs(argsArray)); + rv = NS_NewISupportsArray(getter_AddRefs(argsArray)); NS_ENSURE_SUCCESS(rv, rv); // create scriptable versions of our strings that we can store in our nsISupportsArray.... nsCOMPtr scriptableImageUrl (do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID)); NS_ENSURE_TRUE(scriptableImageUrl, NS_ERROR_FAILURE); - scriptableImageUrl->SetData(aImageUrl); + scriptableImageUrl->SetData(imageUrl); rv = argsArray->AppendElement(scriptableImageUrl); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr scriptableAlertTitle (do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID)); NS_ENSURE_TRUE(scriptableAlertTitle, NS_ERROR_FAILURE); - scriptableAlertTitle->SetData(aAlertTitle); + scriptableAlertTitle->SetData(title); rv = argsArray->AppendElement(scriptableAlertTitle); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr scriptableAlertText (do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID)); NS_ENSURE_TRUE(scriptableAlertText, NS_ERROR_FAILURE); - scriptableAlertText->SetData(aAlertText); + scriptableAlertText->SetData(text); rv = argsArray->AppendElement(scriptableAlertText); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr scriptableIsClickable (do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID)); NS_ENSURE_TRUE(scriptableIsClickable, NS_ERROR_FAILURE); - scriptableIsClickable->SetData(aAlertTextClickable); + scriptableIsClickable->SetData(textClickable); rv = argsArray->AppendElement(scriptableIsClickable); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr scriptableAlertCookie (do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID)); NS_ENSURE_TRUE(scriptableAlertCookie, NS_ERROR_FAILURE); - scriptableAlertCookie->SetData(aAlertCookie); + scriptableAlertCookie->SetData(cookie); rv = argsArray->AppendElement(scriptableAlertCookie); NS_ENSURE_SUCCESS(rv, rv); @@ -121,14 +199,14 @@ nsXULAlerts::ShowAlertNotification(const nsAString& aImageUrl, const nsAString& nsCOMPtr scriptableBidi (do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID)); NS_ENSURE_TRUE(scriptableBidi, NS_ERROR_FAILURE); - scriptableBidi->SetData(aBidi); + scriptableBidi->SetData(bidi); rv = argsArray->AppendElement(scriptableBidi); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr scriptableLang (do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID)); NS_ENSURE_TRUE(scriptableLang, NS_ERROR_FAILURE); - scriptableLang->SetData(aLang); + scriptableLang->SetData(lang); rv = argsArray->AppendElement(scriptableLang); NS_ENSURE_SUCCESS(rv, rv); @@ -137,7 +215,7 @@ nsXULAlerts::ShowAlertNotification(const nsAString& aImageUrl, const nsAString& // it may take the same position. nsCOMPtr replacedWindow = do_CreateInstance(NS_SUPPORTS_INTERFACE_POINTER_CONTRACTID, &rv); NS_ENSURE_TRUE(replacedWindow, NS_ERROR_FAILURE); - nsIDOMWindow* previousAlert = mNamedWindows.GetWeak(aAlertName); + nsIDOMWindow* previousAlert = mNamedWindows.GetWeak(name); replacedWindow->SetData(previousAlert); replacedWindow->SetDataIID(&NS_GET_IID(nsIDOMWindow)); rv = argsArray->AppendElement(replacedWindow); @@ -147,7 +225,7 @@ nsXULAlerts::ShowAlertNotification(const nsAString& aImageUrl, const nsAString& // mNamedWindows when it is closed. nsCOMPtr ifptr = do_CreateInstance(NS_SUPPORTS_INTERFACE_POINTER_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); - RefPtr alertObserver = new nsXULAlertObserver(this, aAlertName, aAlertListener); + RefPtr alertObserver = new nsXULAlertObserver(this, name, aAlertListener); nsCOMPtr iSupports(do_QueryInterface(alertObserver)); ifptr->SetData(iSupports); ifptr->SetDataIID(&NS_GET_IID(nsIObserver)); @@ -158,43 +236,42 @@ nsXULAlerts::ShowAlertNotification(const nsAString& aImageUrl, const nsAString& // notification. It is empty for system alerts. nsCOMPtr scriptableAlertSource (do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID)); NS_ENSURE_TRUE(scriptableAlertSource, NS_ERROR_FAILURE); - nsAutoString source; - nsAlertsUtils::GetSourceHostPort(aPrincipal, source); scriptableAlertSource->SetData(source); rv = argsArray->AppendElement(scriptableAlertSource); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr newWindow; nsAutoCString features("chrome,dialog=yes,titlebar=no,popup=yes"); - if (aInPrivateBrowsing) { + if (inPrivateBrowsing) { features.AppendLiteral(",private"); } rv = wwatch->OpenWindow(0, ALERT_CHROME_URL, "_blank", features.get(), argsArray, getter_AddRefs(newWindow)); NS_ENSURE_SUCCESS(rv, rv); - mNamedWindows.Put(aAlertName, newWindow); + mNamedWindows.Put(name, newWindow); alertObserver->SetAlertWindow(newWindow); return NS_OK; } -nsresult +NS_IMETHODIMP nsXULAlerts::SetManualDoNotDisturb(bool aDoNotDisturb) { mDoNotDisturb = aDoNotDisturb; return NS_OK; } -nsresult +NS_IMETHODIMP nsXULAlerts::GetManualDoNotDisturb(bool* aRetVal) { *aRetVal = mDoNotDisturb; return NS_OK; } -nsresult -nsXULAlerts::CloseAlert(const nsAString& aAlertName) +NS_IMETHODIMP +nsXULAlerts::CloseAlert(const nsAString& aAlertName, + nsIPrincipal* aPrincipal) { nsIDOMWindow* alert = mNamedWindows.GetWeak(aAlertName); nsCOMPtr domWindow = do_QueryInterface(alert); diff --git a/toolkit/components/alerts/nsXULAlerts.h b/toolkit/components/alerts/nsXULAlerts.h index 06e55bd62e..6dfebd86da 100644 --- a/toolkit/components/alerts/nsXULAlerts.h +++ b/toolkit/components/alerts/nsXULAlerts.h @@ -12,28 +12,24 @@ #include "nsIDOMWindow.h" #include "nsIObserver.h" -class nsXULAlerts { +class nsXULAlerts : public nsIAlertsService, + public nsIAlertsDoNotDisturb +{ friend class nsXULAlertObserver; public: + NS_DECL_NSIALERTSDONOTDISTURB + NS_DECL_NSIALERTSSERVICE + NS_DECL_ISUPPORTS + nsXULAlerts() { } - virtual ~nsXULAlerts() {} - - nsresult ShowAlertNotification(const nsAString& aImageUrl, const nsAString& aAlertTitle, - const nsAString& aAlertText, bool aAlertTextClickable, - const nsAString& aAlertCookie, nsIObserver* aAlertListener, - const nsAString& aAlertName, const nsAString& aBidi, - const nsAString& aLang, nsIPrincipal* aPrincipal, - bool aInPrivateBrowsing); - - nsresult CloseAlert(const nsAString& aAlertName); - - nsresult GetManualDoNotDisturb(bool* aRetVal); - nsresult SetManualDoNotDisturb(bool aDoNotDisturb); + static already_AddRefed GetInstance(); protected: + virtual ~nsXULAlerts() {} + nsInterfaceHashtable mNamedWindows; bool mDoNotDisturb = false; }; @@ -58,7 +54,7 @@ public: protected: virtual ~nsXULAlertObserver() {} - nsXULAlerts* mXULAlerts; + RefPtr mXULAlerts; nsString mAlertName; nsCOMPtr mAlertWindow; nsCOMPtr mObserver; diff --git a/toolkit/components/build/nsToolkitCompsCID.h b/toolkit/components/build/nsToolkitCompsCID.h index 1f2075d260..ff76ac2128 100644 --- a/toolkit/components/build/nsToolkitCompsCID.h +++ b/toolkit/components/build/nsToolkitCompsCID.h @@ -89,6 +89,9 @@ "@mozilla.org/updates/update-processor;1" #endif +#define NS_ADDONCONTENTPOLICY_CONTRACTID \ + "@mozilla.org/addons/content-policy;1" + #define NS_ADDONPATHSERVICE_CONTRACTID \ "@mozilla.org/addon-path-service;1" @@ -181,5 +184,8 @@ #define NS_APPLICATION_REPUTATION_SERVICE_CID \ { 0x8576c950, 0xf4a2, 0x11e2, { 0xb7, 0x78, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66 } } +#define NS_ADDONCONTENTPOLICY_CID \ +{ 0xc26a8241, 0xecf4, 0x4aed, { 0x9f, 0x3c, 0xf1, 0xf5, 0xc7, 0x13, 0xb9, 0xa5 } } + #define NS_ADDON_PATH_SERVICE_CID \ { 0xa39f39d0, 0xdfb6, 0x11e3, { 0x8b, 0x68, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66 } } diff --git a/toolkit/components/build/nsToolkitCompsModule.cpp b/toolkit/components/build/nsToolkitCompsModule.cpp index b701daee21..c9db119f0e 100644 --- a/toolkit/components/build/nsToolkitCompsModule.cpp +++ b/toolkit/components/build/nsToolkitCompsModule.cpp @@ -29,6 +29,7 @@ #include "nsBrowserStatusFilter.h" #include "mozilla/FinalizationWitnessService.h" #include "mozilla/NativeOSFileInternals.h" +#include "mozilla/AddonContentPolicy.h" #include "mozilla/AddonPathService.h" #if defined(XP_WIN) @@ -84,6 +85,7 @@ NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(FinalizationWitnessService, Init) NS_GENERIC_FACTORY_CONSTRUCTOR(NativeOSFileInternalsService) NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(NativeFileWatcherService, Init) +NS_GENERIC_FACTORY_CONSTRUCTOR(AddonContentPolicy) NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(AddonPathService, AddonPathService::GetInstance) NS_DEFINE_NAMED_CID(NS_TOOLKIT_APPSTARTUP_CID); @@ -108,6 +110,7 @@ NS_DEFINE_NAMED_CID(NS_UPDATEPROCESSOR_CID); #endif NS_DEFINE_NAMED_CID(FINALIZATIONWITNESSSERVICE_CID); NS_DEFINE_NAMED_CID(NATIVE_OSFILE_INTERNALS_SERVICE_CID); +NS_DEFINE_NAMED_CID(NS_ADDONCONTENTPOLICY_CID); NS_DEFINE_NAMED_CID(NS_ADDON_PATH_SERVICE_CID); NS_DEFINE_NAMED_CID(NATIVE_FILEWATCHER_SERVICE_CID); @@ -134,6 +137,7 @@ static const Module::CIDEntry kToolkitCIDs[] = { #endif { &kFINALIZATIONWITNESSSERVICE_CID, false, nullptr, FinalizationWitnessServiceConstructor }, { &kNATIVE_OSFILE_INTERNALS_SERVICE_CID, false, nullptr, NativeOSFileInternalsServiceConstructor }, + { &kNS_ADDONCONTENTPOLICY_CID, false, nullptr, AddonContentPolicyConstructor }, { &kNS_ADDON_PATH_SERVICE_CID, false, nullptr, AddonPathServiceConstructor }, { &kNATIVE_FILEWATCHER_SERVICE_CID, false, nullptr, NativeFileWatcherServiceConstructor }, { nullptr } @@ -161,15 +165,22 @@ static const Module::ContractIDEntry kToolkitContracts[] = { #endif { FINALIZATIONWITNESSSERVICE_CONTRACTID, &kFINALIZATIONWITNESSSERVICE_CID }, { NATIVE_OSFILE_INTERNALS_SERVICE_CONTRACTID, &kNATIVE_OSFILE_INTERNALS_SERVICE_CID }, + { NS_ADDONCONTENTPOLICY_CONTRACTID, &kNS_ADDONCONTENTPOLICY_CID }, { NS_ADDONPATHSERVICE_CONTRACTID, &kNS_ADDON_PATH_SERVICE_CID }, { NATIVE_FILEWATCHER_SERVICE_CONTRACTID, &kNATIVE_FILEWATCHER_SERVICE_CID }, { nullptr } }; +static const mozilla::Module::CategoryEntry kToolkitCategories[] = { + { "content-policy", NS_ADDONCONTENTPOLICY_CONTRACTID, NS_ADDONCONTENTPOLICY_CONTRACTID }, + { nullptr } +}; + static const Module kToolkitModule = { Module::kVersion, kToolkitCIDs, - kToolkitContracts + kToolkitContracts, + kToolkitCategories }; NSMODULE_DEFN(nsToolkitCompsModule) = &kToolkitModule; diff --git a/toolkit/components/extensions/test/mochitest/test_ext_jsversion.html b/toolkit/components/extensions/test/mochitest/test_ext_jsversion.html new file mode 100644 index 0000000000..aeaead1479 --- /dev/null +++ b/toolkit/components/extensions/test/mochitest/test_ext_jsversion.html @@ -0,0 +1,84 @@ + + + + Test for simple WebExtension + + + + + + + + + + + + + diff --git a/toolkit/components/filepicker/nsFilePicker.js b/toolkit/components/filepicker/nsFilePicker.js index dc3ad70e4b..1010cde0d0 100644 --- a/toolkit/components/filepicker/nsFilePicker.js +++ b/toolkit/components/filepicker/nsFilePicker.js @@ -93,14 +93,14 @@ nsFilePicker.prototype = { /* readonly attribute nsISimpleEnumerator files; */ get files() { return this.mFilesEnumerator; }, - /* readonly attribute DOM File domfile; */ - get domfile() { - let enumerator = this.domfiles; + /* we don't support directories, yet */ + get domFileOrDirectory() { + let enumerator = this.domFileOrDirectoryEnumerator; return enumerator ? enumerator.mFiles[0] : null; }, - /* readonly attribute nsISimpleEnumerator domfiles; */ - get domfiles() { + /* readonly attribute nsISimpleEnumerator domFileOrDirectoryEnumerator; */ + get domFileOrDirectoryEnumerator() { if (!this.mFilesEnumerator) { return null; } diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index 8170d5154c..fe1d763209 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -6191,6 +6191,52 @@ "n_buckets": "25", "description": "Percentage of time spent in the Stressed load state in calls 5-30 seconds." }, + "WEBRTC_RENEGOTIATIONS": { + "expires_in_version": "never", + "kind": "linear", + "high": "21", + "n_buckets": "20", + "description": "Number of Renegotiations during each call" + }, + "WEBRTC_MAX_VIDEO_SEND_TRACK": { + "expires_in_version": "never", + "kind": "linear", + "high": "10", + "n_buckets": "9", + "description": "Number of Video tracks sent simultaneously" + }, + "WEBRTC_MAX_VIDEO_RECEIVE_TRACK": { + "expires_in_version": "never", + "kind": "linear", + "high": "20", + "n_buckets": "19", + "description": "Number of Video tracks received simultaneously" + }, + "WEBRTC_MAX_AUDIO_SEND_TRACK": { + "expires_in_version": "never", + "kind": "linear", + "high": "20", + "n_buckets": "19", + "description": "Number of Audio tracks sent simultaneously" + }, + "WEBRTC_MAX_AUDIO_RECEIVE_TRACK": { + "expires_in_version": "never", + "kind": "linear", + "high": "30", + "n_buckets": "29", + "description": "Number of Audio tracks received simultaneously" + }, + "WEBRTC_DATACHANNEL_NEGOTIATED": { + "expires_in_version": "never", + "kind": "boolean", + "description": "Was DataChannels negotiated" + }, + "WEBRTC_CALL_TYPE": { + "expires_in_version": "never", + "kind": "enumerated", + "n_values": "8", + "description": "Type of call: (Bitmask) Audio = 1, Video = 2, DataChannels = 4" + }, "DEVTOOLS_DEBUGGER_RDP_LOCAL_TRACERDETACH_MS": { "expires_in_version": "never", "kind": "exponential", @@ -8856,6 +8902,52 @@ "n_values": 8, "description": "Type for media in getUserMedia calls (0=Camera, 1=Screen, 2=Application, 3=Window, 4=Browser, 5=Microphone, 6=AudioCapture, 7=Other)" }, + "LOOP_RENEGOTIATIONS": { + "expires_in_version": "never", + "kind": "linear", + "high": "21", + "n_buckets": "20", + "description": "Number of Renegotiations during each call" + }, + "LOOP_MAX_VIDEO_SEND_TRACK": { + "expires_in_version": "never", + "kind": "linear", + "high": "10", + "n_buckets": "9", + "description": "Number of Video tracks sent simultaneously" + }, + "LOOP_MAX_VIDEO_RECEIVE_TRACK": { + "expires_in_version": "never", + "kind": "linear", + "high": "20", + "n_buckets": "19", + "description": "Number of Video tracks received simultaneously" + }, + "LOOP_MAX_AUDIO_SEND_TRACK": { + "expires_in_version": "never", + "kind": "linear", + "high": "20", + "n_buckets": "19", + "description": "Number of Audio tracks sent simultaneously" + }, + "LOOP_MAX_AUDIO_RECEIVE_TRACK": { + "expires_in_version": "never", + "kind": "linear", + "high": "30", + "n_buckets": "29", + "description": "Number of Audio tracks received simultaneously" + }, + "LOOP_DATACHANNEL_NEGOTIATED": { + "expires_in_version": "never", + "kind": "boolean", + "description": "Was DataChannels negotiated" + }, + "LOOP_CALL_TYPE": { + "expires_in_version": "never", + "kind": "enumerated", + "n_values": "8", + "description": "Type of call: (Bitmask) Audio = 1, Video = 2, DataChannels = 4" + }, "PERF_MONITORING_TEST_CPU_RESCHEDULING_PROPORTION_MOVED": { "alert_emails": ["dteller@mozilla.com"], "expires_in_version": "48", diff --git a/toolkit/devtools/client/dbg-client.jsm b/toolkit/devtools/client/dbg-client.jsm index 5d53d53002..2a2f50287b 100644 --- a/toolkit/devtools/client/dbg-client.jsm +++ b/toolkit/devtools/client/dbg-client.jsm @@ -493,7 +493,6 @@ DebuggerClient.prototype = { executeSoon(() => aOnResponse({ from: workerClient.actor, type: "attached", - isFrozen: workerClient.isFrozen, url: workerClient.url }, workerClient)); return; @@ -1334,16 +1333,11 @@ function WorkerClient(aClient, aForm) { this.client = aClient; this._actor = aForm.from; this._isClosed = false; - this._isFrozen = aForm.isFrozen; this._url = aForm.url; this._onClose = this._onClose.bind(this); - this._onFreeze = this._onFreeze.bind(this); - this._onThaw = this._onThaw.bind(this); this.addListener("close", this._onClose); - this.addListener("freeze", this._onFreeze); - this.addListener("thaw", this._onThaw); this.traits = {}; } @@ -1369,10 +1363,6 @@ WorkerClient.prototype = { return this._isClosed; }, - get isFrozen() { - return this._isFrozen; - }, - detach: DebuggerClient.requester({ type: "detach" }, { after: function (aResponse) { this.client.unregisterClient(this); @@ -1406,26 +1396,16 @@ WorkerClient.prototype = { _onClose: function () { this.removeListener("close", this._onClose); - this.removeListener("freeze", this._onFreeze); - this.removeListener("thaw", this._onThaw); this.client.unregisterClient(this); - this._closed = true; - }, - - _onFreeze: function () { - this._isFrozen = true; - }, - - _onThaw: function () { - this._isFrozen = false; + this._isClosed = true; }, reconfigure: function () { return Promise.resolve(); }, - events: ["close", "freeze", "thaw"] + events: ["close"] }; eventSource(WorkerClient.prototype); diff --git a/toolkit/devtools/debugger/debugger-controller.js b/toolkit/devtools/debugger/debugger-controller.js index b15e59ee48..b65351b9bc 100644 --- a/toolkit/devtools/debugger/debugger-controller.js +++ b/toolkit/devtools/debugger/debugger-controller.js @@ -451,10 +451,8 @@ let DebuggerController = { }; function Workers() { - this._workerClients = new Map(); + this._workerForms = Object.create(null); this._onWorkerListChanged = this._onWorkerListChanged.bind(this); - this._onWorkerFreeze = this._onWorkerFreeze.bind(this); - this._onWorkerThaw = this._onWorkerThaw.bind(this); this._onWorkerSelect = this._onWorkerSelect.bind(this); } @@ -482,29 +480,23 @@ Workers.prototype = { } this._tabClient.listWorkers((response) => { - let workerActors = new Set(); + let workerForms = Object.create(null); for (let worker of response.workers) { - workerActors.add(worker.actor); + workerForms[worker.actor] = worker; } - for (let [workerActor, workerClient] of this._workerClients) { - if (!workerActors.has(workerActor)) { - workerClient.removeListener("freeze", this._onWorkerFreeze); - workerClient.removeListener("thaw", this._onWorkerThaw); - this._workerClients.delete(workerActor); + for (let workerActor in this._workerForms) { + if (!(workerActor in workerForms)) { + delete this._workerForms[workerActor]; DebuggerView.Workers.removeWorker(workerActor); } } - for (let actor of workerActors) { - let workerActor = actor - if (!this._workerClients.has(workerActor)) { - this._tabClient.attachWorker(workerActor, (response, workerClient) => { - workerClient.addListener("freeze", this._onWorkerFreeze); - workerClient.addListener("thaw", this._onWorkerThaw); - this._workerClients.set(workerActor, workerClient); - DebuggerView.Workers.addWorker(workerActor, workerClient.url); - }); + for (let workerActor in workerForms) { + if (!(workerActor in this._workerForms)) { + let workerForm = workerForms[workerActor]; + this._workerForms[workerActor] = workerForm; + DebuggerView.Workers.addWorker(workerActor, workerForm.url); } } }); @@ -514,20 +506,11 @@ Workers.prototype = { this._updateWorkerList(); }, - _onWorkerFreeze: function (type, packet) { - DebuggerView.Workers.removeWorker(packet.from); - }, - - _onWorkerThaw: function (type, packet) { - let workerClient = this._workerClients.get(packet.from); - DebuggerView.Workers.addWorker(packet.from, workerClient.url); - }, - - _onWorkerSelect: function (workerActor) { - let workerClient = this._workerClients.get(workerActor); - gDevTools.showToolbox(devtools.TargetFactory.forWorker(workerClient), - "jsdebugger", - devtools.Toolbox.HostType.WINDOW); + _onWorkerSelect: function (type, workerActor) { + DebuggerController.client.attachWorker(workerActor, (response, workerClient) => { + gDevTools.showToolbox(devtools.TargetFactory.forWorker(workerClient), + "jsdebugger", devtools.Toolbox.HostType.WINDOW); + }); } }; diff --git a/toolkit/devtools/framework/gDevTools.jsm b/toolkit/devtools/framework/gDevTools.jsm index b3e4e70c19..ec300efbf2 100644 --- a/toolkit/devtools/framework/gDevTools.jsm +++ b/toolkit/devtools/framework/gDevTools.jsm @@ -566,14 +566,6 @@ let gDevToolsBrowser = { toolbox ? toolbox.destroy() : gDevTools.showToolbox(target); }, - toggleBrowserToolboxCommand: function(gBrowser) { - let target = devtools.TargetFactory.forWindow(gBrowser.ownerDocument.defaultView); - let toolbox = gDevTools.getToolbox(target); - - toolbox ? toolbox.destroy() - : gDevTools.showToolbox(target, "inspector", Toolbox.HostType.WINDOW); - }, - /** * This function ensures the right commands are enabled in a window, * depending on their relevant prefs. It gets run when a window is registered, diff --git a/toolkit/devtools/framework/target.js b/toolkit/devtools/framework/target.js index f40007684a..d7c24ad33b 100644 --- a/toolkit/devtools/framework/target.js +++ b/toolkit/devtools/framework/target.js @@ -4,7 +4,7 @@ "use strict"; -const {Cc, Ci, Cu} = require("chrome"); +const { Ci, Cu } = require("chrome"); const {Promise: promise} = require("resource://gre/modules/Promise.jsm"); const EventEmitter = require("devtools/toolkit/event-emitter"); @@ -28,7 +28,7 @@ exports.TargetFactory = { * * @return A target object */ - forTab: function TF_forTab(tab) { + forTab: function(tab) { let target = targets.get(tab); if (target == null) { target = new TabTarget(tab); @@ -50,7 +50,7 @@ exports.TargetFactory = { * * @return A promise of a target object */ - forRemoteTab: function TF_forRemoteTab(options) { + forRemoteTab: function(options) { let targetPromise = promiseTargets.get(options); if (targetPromise == null) { let target = new TabTarget(options); @@ -60,7 +60,7 @@ exports.TargetFactory = { return targetPromise; }, - forWorker: function TF_forWorker(workerClient) { + forWorker: function(workerClient) { let target = targets.get(workerClient); if (target == null) { target = new WorkerTarget(workerClient); @@ -76,56 +76,11 @@ exports.TargetFactory = { * target for a tab without creating a target * @return true/false */ - isKnownTab: function TF_isKnownTab(tab) { + isKnownTab: function(tab) { return targets.has(tab); }, - - /** - * Construct a Target - * @param {nsIDOMWindow} window - * The chromeWindow to use in creating a new target - * @return A target object - */ - forWindow: function TF_forWindow(window) { - let target = targets.get(window); - if (target == null) { - target = new WindowTarget(window); - targets.set(window, target); - } - return target; - }, - - /** - * Get all of the targets known to the local browser instance - * @return An array of target objects - */ - allTargets: function TF_allTargets() { - let windows = []; - let wm = Cc["@mozilla.org/appshell/window-mediator;1"] - .getService(Ci.nsIWindowMediator); - let en = wm.getXULWindowEnumerator(null); - while (en.hasMoreElements()) { - windows.push(en.getNext()); - } - - return windows.map(function(window) { - return TargetFactory.forWindow(window); - }); - }, }; -/** - * The 'version' property allows the developer tools equivalent of browser - * detection. Browser detection is evil, however while we don't know what we - * will need to detect in the future, it is an easy way to postpone work. - * We should be looking to use the support features added in bug 1069673 - * in place of version where possible. - */ -function getVersion() { - // FIXME: return something better - return 20; -} - /** * A Target represents something that we can debug. Targets are generally * read-only. Any changes that you wish to make to a target should be done via @@ -142,27 +97,19 @@ function getVersion() { * * Target extends EventEmitter and provides support for the following events: * - close: The target window has been closed. All tools attached to this - * target should close. This event is not currently cancelable. + * target should close. This event is not currently cancelable. * - navigate: The target window has navigated to a different URL * * Optional events: * - will-navigate: The target window will navigate to a different URL - * - hidden: The target is not visible anymore (for TargetTab, another tab is selected) + * - hidden: The target is not visible anymore (for TargetTab, another tab is + * selected) * - visible: The target is visible (for TargetTab, tab is selected) * * Comparing Targets: 2 instances of a Target object can point at the same * thing, so t1 !== t2 and t1 != t2 even when they represent the same object. * To compare to targets use 't1.equals(t2)'. */ -function Target() { - throw new Error("Use TargetFactory.newXXX or Target.getXXX to create a Target in place of 'new Target()'"); -} - -Object.defineProperty(Target.prototype, "version", { - get: getVersion, - enumerable: true -}); - /** * A TabTarget represents a page living in a browser tab. Generally these will @@ -185,18 +132,28 @@ function TabTarget(tab) { this._client = tab.client; this._chrome = tab.chrome; } - // Default isTabActor to true if not explicitely specified - this._isTabActor = typeof(tab.isTabActor) == "boolean" ? tab.isTabActor : true; + // Default isTabActor to true if not explicitly specified + if (typeof tab.isTabActor == "boolean") { + this._isTabActor = tab.isTabActor; + } else { + this._isTabActor = true; + } } TabTarget.prototype = { _webProgressListener: null, /** - * Returns a promise for the protocol description from the root actor. - * Used internally with `target.actorHasMethod`. Takes advantage of - * caching if definition was fetched previously with the corresponding - * actor information. Must be a remote target. + * Returns a promise for the protocol description from the root actor. Used + * internally with `target.actorHasMethod`. Takes advantage of caching if + * definition was fetched previously with the corresponding actor information. + * Actors are lazily loaded, so not only must the tool using a specific actor + * be in use, the actors are only registered after invoking a method (for + * performance reasons, added in bug 988237), so to use these actor detection + * methods, one must already be communicating with a specific actor of that + * type. + * + * Must be a remote target. * * @return {Promise} * { @@ -224,14 +181,16 @@ TabTarget.prototype = { * "events": {} * } */ - getActorDescription: function (actorName) { + getActorDescription: function(actorName) { if (!this.client) { - throw new Error("TabTarget#getActorDescription() can only be called on remote tabs."); + throw new Error("TabTarget#getActorDescription() can only be called on " + + "remote tabs."); } let deferred = promise.defer(); - if (this._protocolDescription && this._protocolDescription.types[actorName]) { + if (this._protocolDescription && + this._protocolDescription.types[actorName]) { deferred.resolve(this._protocolDescription.types[actorName]); } else { this.client.mainRoot.protocolDescription(description => { @@ -250,9 +209,10 @@ TabTarget.prototype = { * @param {String} actorName * @return {Boolean} */ - hasActor: function (actorName) { + hasActor: function(actorName) { if (!this.client) { - throw new Error("TabTarget#hasActor() can only be called on remote tabs."); + throw new Error("TabTarget#hasActor() can only be called on remote " + + "tabs."); } if (this.form) { return !!this.form[actorName + "Actor"]; @@ -270,9 +230,10 @@ TabTarget.prototype = { * @param {String} methodName * @return {Promise} */ - actorHasMethod: function (actorName, methodName) { + actorHasMethod: function(actorName, methodName) { if (!this.client) { - throw new Error("TabTarget#actorHasMethod() can only be called on remote tabs."); + throw new Error("TabTarget#actorHasMethod() can only be called on " + + "remote tabs."); } return this.getActorDescription(actorName).then(desc => { if (desc && desc.methods) { @@ -288,13 +249,14 @@ TabTarget.prototype = { * @param {String} traitName * @return {Mixed} */ - getTrait: function (traitName) { + getTrait: function(traitName) { if (!this.client) { - throw new Error("TabTarget#getTrait() can only be called on remote tabs."); + throw new Error("TabTarget#getTrait() can only be called on remote " + + "tabs."); } - // If the targeted actor exposes traits and has a defined value for this traits, - // override the root actor traits + // If the targeted actor exposes traits and has a defined value for this + // traits, override the root actor traits if (this.form.traits && traitName in this.form.traits) { return this.form.traits[traitName]; } @@ -302,8 +264,6 @@ TabTarget.prototype = { return this.client.traits[traitName]; }, - get version() { return getVersion(); }, - get tab() { return this._tab; }, @@ -341,8 +301,8 @@ TabTarget.prototype = { // in all contexts. Consumers of .window need to be refactored to not // rely on this. if (Services.appinfo.processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT) { - Cu.reportError("The .window getter on devtools' |target| object isn't e10s friendly!\n" - + Error().stack); + Cu.reportError("The .window getter on devtools' |target| object isn't " + + "e10s friendly!\n" + Error().stack); } // Be extra careful here, since this may be called by HS_getHudByWindow // during shutdown. @@ -354,12 +314,12 @@ TabTarget.prototype = { get name() { if (this._tab && this._tab.linkedBrowser.contentDocument) { - return this._tab.linkedBrowser.contentDocument.title - } else if (this.isAddon) { - return this._form.name; - } else { - return this._form.title; + return this._tab.linkedBrowser.contentDocument.title; } + if (this.isAddon) { + return this._form.name; + } + return this._form.title; }, get url() { @@ -393,7 +353,7 @@ TabTarget.prototype = { * for tools that support the Remote Debugging Protocol even for local * connections. */ - makeRemote: function TabTarget_makeRemote() { + makeRemote: function() { if (this._remote) { return this._remote.promise; } @@ -416,28 +376,30 @@ TabTarget.prototype = { this._setupRemoteListeners(); let attachTab = () => { - this._client.attachTab(this._form.actor, (aResponse, aTabClient) => { - if (!aTabClient) { + this._client.attachTab(this._form.actor, (response, tabClient) => { + if (!tabClient) { this._remote.reject("Unable to attach to the tab"); return; } - this.activeTab = aTabClient; - this.threadActor = aResponse.threadActor; + this.activeTab = tabClient; + this.threadActor = response.threadActor; attachConsole(); }); }; + let onConsoleAttached = (response, consoleClient) => { + if (!consoleClient) { + this._remote.reject("Unable to attach to the console"); + return; + } + this.activeConsole = consoleClient; + this._remote.resolve(null); + }; + let attachConsole = () => { this._client.attachConsole(this._form.consoleActor, [ "NetworkActivity" ], - (aResponse, aWebConsoleClient) => { - if (!aWebConsoleClient) { - this._remote.reject("Unable to attach to the console"); - return; - } - this.activeConsole = aWebConsoleClient; - this._remote.resolve(null); - }); + onConsoleAttached); }; if (this.isLocalTab) { @@ -470,8 +432,8 @@ TabTarget.prototype = { // already initialized in the connection screen code. attachTab(); } else { - // AddonActor and chrome debugging on RootActor doesn't inherits from TabActor and - // doesn't need to be attached. + // AddonActor and chrome debugging on RootActor doesn't inherits from + // TabActor and doesn't need to be attached. attachConsole(); } @@ -481,7 +443,7 @@ TabTarget.prototype = { /** * Listen to the different events. */ - _setupListeners: function TabTarget__setupListeners() { + _setupListeners: function() { this._webProgressListener = new TabWebProgressListener(this); this.tab.linkedBrowser.addProgressListener(this._webProgressListener); this.tab.addEventListener("TabClose", this); @@ -492,7 +454,7 @@ TabTarget.prototype = { /** * Teardown event listeners. */ - _teardownListeners: function TabTarget__teardownListeners() { + _teardownListeners: function() { if (this._webProgressListener) { this._webProgressListener.destroy(); } @@ -505,7 +467,7 @@ TabTarget.prototype = { /** * Setup listeners for remote debugging, updating existing ones as necessary. */ - _setupRemoteListeners: function TabTarget__setupRemoteListeners() { + _setupRemoteListeners: function() { this.client.addListener("closed", this.destroy); this._onTabDetached = (aType, aPacket) => { @@ -545,7 +507,7 @@ TabTarget.prototype = { /** * Teardown listeners for remote debugging. */ - _teardownRemoteListeners: function TabTarget__teardownRemoteListeners() { + _teardownRemoteListeners: function() { this.client.removeListener("closed", this.destroy); this.client.removeListener("tabNavigated", this._onTabNavigated); this.client.removeListener("tabDetached", this._onTabDetached); @@ -555,7 +517,7 @@ TabTarget.prototype = { /** * Handle tabs events. */ - handleEvent: function (event) { + handleEvent: function(event) { switch (event.type) { case "TabClose": case "unload": @@ -644,7 +606,7 @@ TabTarget.prototype = { /** * Clean up references to what this target points to. */ - _cleanup: function TabTarget__cleanup() { + _cleanup: function() { if (this._tab) { targets.delete(this._tab); } else { @@ -659,11 +621,11 @@ TabTarget.prototype = { }, toString: function() { - return 'TabTarget:' + (this._tab ? this._tab : (this._form && this._form.actor)); + let id = this._tab ? this._tab : (this._form && this._form.actor); + return `TabTarget:${id}`; }, }; - /** * WebProgressListener for TabTarget. * @@ -677,9 +639,10 @@ function TabWebProgressListener(aTarget) { TabWebProgressListener.prototype = { target: null, - QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener, Ci.nsISupportsWeakReference]), + QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener, + Ci.nsISupportsWeakReference]), - onStateChange: function TWPL_onStateChange(progress, request, flag, status) { + onStateChange: function(progress, request, flag) { let isStart = flag & Ci.nsIWebProgressListener.STATE_START; let isDocument = flag & Ci.nsIWebProgressListener.STATE_IS_DOCUMENT; let isNetwork = flag & Ci.nsIWebProgressListener.STATE_IS_NETWORK; @@ -706,7 +669,7 @@ TabWebProgressListener.prototype = { onSecurityChange: function() {}, onStatusChange: function() {}, - onLocationChange: function TWPL_onLocationChange(webProgress, request, URI, flags) { + onLocationChange: function(webProgress, request, URI, flags) { if (this.target && !(flags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT)) { let window = webProgress.DOMWindow; @@ -723,7 +686,7 @@ TabWebProgressListener.prototype = { /** * Destroy the progress listener instance. */ - destroy: function TWPL_destroy() { + destroy: function() { if (this.target.tab) { try { this.target.tab.linkedBrowser.removeProgressListener(this); @@ -738,87 +701,6 @@ TabWebProgressListener.prototype = { } }; - -/** - * A WindowTarget represents a page living in a xul window or panel. Generally - * these will have a chrome: URL - */ -function WindowTarget(window) { - EventEmitter.decorate(this); - this._window = window; - this._setupListeners(); -} - -WindowTarget.prototype = { - get version() { return getVersion(); }, - - get window() { - return this._window; - }, - - get name() { - return this._window.document.title; - }, - - get url() { - return this._window.document.location.href; - }, - - get isRemote() { - return false; - }, - - get isLocalTab() { - return false; - }, - - get isThreadPaused() { - return !!this._isThreadPaused; - }, - - /** - * Listen to the different events. - */ - _setupListeners: function() { - this._handleThreadState = this._handleThreadState.bind(this); - this.on("thread-paused", this._handleThreadState); - this.on("thread-resumed", this._handleThreadState); - }, - - _handleThreadState: function(event) { - switch (event) { - case "thread-resumed": - this._isThreadPaused = false; - break; - case "thread-paused": - this._isThreadPaused = true; - break; - } - }, - - /** - * Target is not alive anymore. - */ - destroy: function() { - if (!this._destroyed) { - this._destroyed = true; - - this.off("thread-paused", this._handleThreadState); - this.off("thread-resumed", this._handleThreadState); - this.emit("close"); - - targets.delete(this._window); - this._window = null; - } - - return promise.resolve(null); - }, - - toString: function() { - return 'WindowTarget:' + this.window; - }, -}; - function WorkerTarget(workerClient) { EventEmitter.decorate(this); this._workerClient = workerClient; @@ -831,17 +713,13 @@ function WorkerTarget(workerClient) { * for remote tabs (from which a TabClient can then be lazily obtained), * WorkerTarget is constructed with a WorkerClient directly. * - * The reason for this is that in order to get notifications when a worker - * closes/freezes/thaws, the UI needs to attach to each worker anyway, so by - * the time a WorkerTarget for a given worker is created, a WorkerClient for - * that worker will already be available. Consequently, there is no need to - * obtain a WorkerClient lazily. - * * WorkerClient is designed to mimic the interface of TabClient as closely as * possible. This allows us to debug workers as if they were ordinary tabs, * requiring only minimal changes to the rest of the frontend. */ WorkerTarget.prototype = { + destroy: function () {}, + get isRemote() { return true; }, @@ -851,12 +729,7 @@ WorkerTarget.prototype = { }, get form() { - return { - from: this._workerClient.actor, - type: "attached", - isFrozen: this._workerClient.isFrozen, - url: this._workerClient.url - }; + return {}; }, get activeTab() { @@ -867,15 +740,17 @@ WorkerTarget.prototype = { return this._workerClient.client; }, - destroy: function () {}, + destroy: function() {}, hasActor: function (name) { return false; }, - getTrait: function (name) { + getTrait: function() { return undefined; }, - makeRemote: function () {} + makeRemote: function () { + return Promise.resolve(); + } }; diff --git a/toolkit/devtools/server/actors/worker.js b/toolkit/devtools/server/actors/worker.js index 75691da410..8e49e66447 100644 --- a/toolkit/devtools/server/actors/worker.js +++ b/toolkit/devtools/server/actors/worker.js @@ -58,7 +58,6 @@ WorkerActor.prototype = { return { type: "attached", - isFrozen: this._dbg.isFrozen, url: this._dbg.url }; }, @@ -112,14 +111,6 @@ WorkerActor.prototype = { reportError("ERROR:" + filename + ":" + lineno + ":" + message + "\n"); }, - onFreeze: function () { - this.conn.sendActorEvent(this.actorID, "freeze"); - }, - - onThaw: function () { - this.conn.sendActorEvent(this.actorID, "thaw"); - }, - _detach: function () { if (this._threadActor !== null) { this._transport.close(); diff --git a/toolkit/mozapps/extensions/AddonContentPolicy.cpp b/toolkit/mozapps/extensions/AddonContentPolicy.cpp new file mode 100644 index 0000000000..40175fa70f --- /dev/null +++ b/toolkit/mozapps/extensions/AddonContentPolicy.cpp @@ -0,0 +1,145 @@ +/* -*- 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 "AddonContentPolicy.h" + +#include "nsCOMPtr.h" +#include "nsContentPolicyUtils.h" +#include "nsContentTypeParser.h" +#include "nsContentUtils.h" +#include "nsIConsoleService.h" +#include "nsIContent.h" +#include "nsIDocument.h" +#include "nsIScriptError.h" +#include "nsIURI.h" + +/* Enforces content policies for WebExtension scopes. Currently: + * + * - Prevents loading scripts with a non-default JavaScript version. + */ + +#define VERSIONED_JS_BLOCKED_MESSAGE \ + MOZ_UTF16("Versioned JavaScript is a non-standard, deprecated extension, and is ") \ + MOZ_UTF16("not supported in WebExtension code. For alternatives, please see: ") \ + MOZ_UTF16("https://developer.mozilla.org/Add-ons/WebExtensions/Tips") + +AddonContentPolicy::AddonContentPolicy() +{ +} + +AddonContentPolicy::~AddonContentPolicy() +{ +} + +NS_IMPL_ISUPPORTS(AddonContentPolicy, nsIContentPolicy) + +static nsresult +GetWindowIDFromContext(nsISupports* aContext, uint64_t *aResult) +{ + NS_ENSURE_TRUE(aContext, NS_ERROR_FAILURE); + + nsCOMPtr content = do_QueryInterface(aContext); + NS_ENSURE_TRUE(content, NS_ERROR_FAILURE); + + nsCOMPtr document = content->OwnerDoc(); + NS_ENSURE_TRUE(document, NS_ERROR_FAILURE); + + nsCOMPtr window = document->GetInnerWindow(); + NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); + + *aResult = window->WindowID(); + return NS_OK; +} + +static nsresult +LogMessage(const nsAString &aMessage, nsIURI* aSourceURI, const nsAString &aSourceSample, + nsISupports* aContext) +{ + nsCOMPtr error = do_CreateInstance(NS_SCRIPTERROR_CONTRACTID); + NS_ENSURE_TRUE(error, NS_ERROR_OUT_OF_MEMORY); + + nsAutoCString sourceName; + nsresult rv = aSourceURI->GetSpec(sourceName); + NS_ENSURE_SUCCESS(rv, rv); + + uint64_t windowID = 0; + GetWindowIDFromContext(aContext, &windowID); + + rv = error->InitWithWindowID(aMessage, NS_ConvertUTF8toUTF16(sourceName), + aSourceSample, 0, 0, nsIScriptError::errorFlag, + "JavaScript", windowID); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr console = do_GetService(NS_CONSOLESERVICE_CONTRACTID); + NS_ENSURE_TRUE(console, NS_ERROR_OUT_OF_MEMORY); + + console->LogMessage(error); + return NS_OK; +} + +NS_IMETHODIMP +AddonContentPolicy::ShouldLoad(uint32_t aContentType, + nsIURI* aContentLocation, + nsIURI* aRequestOrigin, + nsISupports* aContext, + const nsACString& aMimeTypeGuess, + nsISupports* aExtra, + nsIPrincipal* aRequestPrincipal, + int16_t* aShouldLoad) +{ + MOZ_ASSERT(aContentType == nsContentUtils::InternalContentPolicyTypeToExternal(aContentType), + "We should only see external content policy types here."); + + *aShouldLoad = nsIContentPolicy::ACCEPT; + + if (!aRequestOrigin) { + return NS_OK; + } + + // Only apply this policy to requests from documents loaded from + // moz-extension URLs, or to resources being loaded from moz-extension URLs. + bool equals; + if (!((NS_SUCCEEDED(aContentLocation->SchemeIs("moz-extension", &equals)) && equals) || + (NS_SUCCEEDED(aRequestOrigin->SchemeIs("moz-extension", &equals)) && equals))) { + return NS_OK; + } + + if (aContentType == nsIContentPolicy::TYPE_SCRIPT) { + NS_ConvertUTF8toUTF16 typeString(aMimeTypeGuess); + nsContentTypeParser mimeParser(typeString); + + // Reject attempts to load JavaScript scripts with a non-default version. + nsAutoString mimeType, version; + if (NS_SUCCEEDED(mimeParser.GetType(mimeType)) && + nsContentUtils::IsJavascriptMIMEType(mimeType) && + NS_SUCCEEDED(mimeParser.GetParameter("version", version))) { + *aShouldLoad = nsIContentPolicy::REJECT_REQUEST; + + LogMessage(NS_MULTILINE_LITERAL_STRING(VERSIONED_JS_BLOCKED_MESSAGE), + aRequestOrigin, typeString, aContext); + return NS_OK; + } + } + + return NS_OK; +} + +NS_IMETHODIMP +AddonContentPolicy::ShouldProcess(uint32_t aContentType, + nsIURI* aContentLocation, + nsIURI* aRequestOrigin, + nsISupports* aRequestingContext, + const nsACString& aMimeTypeGuess, + nsISupports* aExtra, + nsIPrincipal* aRequestPrincipal, + int16_t* aShouldProcess) +{ + MOZ_ASSERT(aContentType == nsContentUtils::InternalContentPolicyTypeToExternal(aContentType), + "We should only see external content policy types here."); + + *aShouldProcess = nsIContentPolicy::ACCEPT; + return NS_OK; +} diff --git a/toolkit/mozapps/extensions/AddonContentPolicy.h b/toolkit/mozapps/extensions/AddonContentPolicy.h new file mode 100644 index 0000000000..dc517b87d1 --- /dev/null +++ b/toolkit/mozapps/extensions/AddonContentPolicy.h @@ -0,0 +1,19 @@ +/* -*- 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 "nsIContentPolicy.h" + +class AddonContentPolicy : public nsIContentPolicy +{ +protected: + virtual ~AddonContentPolicy(); + +public: + AddonContentPolicy(); + + NS_DECL_ISUPPORTS + NS_DECL_NSICONTENTPOLICY +}; diff --git a/toolkit/mozapps/extensions/moz.build b/toolkit/mozapps/extensions/moz.build index 61990cfd50..9b12c0d782 100644 --- a/toolkit/mozapps/extensions/moz.build +++ b/toolkit/mozapps/extensions/moz.build @@ -45,11 +45,13 @@ if CONFIG['MOZ_EM_DEBUG']: JAR_MANIFESTS += ['jar.mn'] EXPORTS.mozilla += [ + 'AddonContentPolicy.h', 'AddonPathService.h', ] UNIFIED_SOURCES += [ - 'AddonPathService.cpp' + 'AddonContentPolicy.cpp', + 'AddonPathService.cpp', ] FINAL_LIBRARY = 'xul' diff --git a/widget/cocoa/OSXNotificationCenter.mm b/widget/cocoa/OSXNotificationCenter.mm index 3ac9ab5d92..98d63685c8 100644 --- a/widget/cocoa/OSXNotificationCenter.mm +++ b/widget/cocoa/OSXNotificationCenter.mm @@ -18,7 +18,6 @@ #include "nsCOMPtr.h" #include "nsIObserver.h" #include "nsIContentPolicy.h" -#include "nsAlertsUtils.h" #include "imgRequestProxy.h" using namespace mozilla; @@ -271,11 +270,9 @@ OSXNotificationCenter::ShowAlert(nsIAlertNotification* aAlert, NS_ENSURE_SUCCESS(rv, rv); notification.title = nsCocoaUtils::ToNSString(title); - nsCOMPtr principal; - rv = aAlert->GetPrincipal(getter_AddRefs(principal)); - NS_ENSURE_SUCCESS(rv, rv); nsAutoString hostPort; - nsAlertsUtils::GetSourceHostPort(principal, hostPort); + rv = aAlert->GetSource(hostPort); + NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr bundle; nsCOMPtr sbs = do_GetService(NS_STRINGBUNDLE_CONTRACTID); sbs->CreateBundle("chrome://alerts/locale/alert.properties", getter_AddRefs(bundle)); @@ -299,43 +296,42 @@ OSXNotificationCenter::ShowAlert(nsIAlertNotification* aAlert, notification.hasActionButton = NO; // If this is not an application/extension alert, show additional actions dealing with permissions. - if (nsAlertsUtils::IsActionablePrincipal(principal)) { - if (bundle) { - nsXPIDLString closeButtonTitle, actionButtonTitle, disableButtonTitle, settingsButtonTitle; - bundle->GetStringFromName(MOZ_UTF16("closeButton.title"), - getter_Copies(closeButtonTitle)); - bundle->GetStringFromName(MOZ_UTF16("actionButton.label"), - getter_Copies(actionButtonTitle)); - if (!hostPort.IsEmpty()) { - const char16_t* formatStrings[] = { hostPort.get() }; - bundle->FormatStringFromName(MOZ_UTF16("webActions.disableForOrigin.label"), - formatStrings, - ArrayLength(formatStrings), - getter_Copies(disableButtonTitle)); - } - bundle->GetStringFromName(MOZ_UTF16("webActions.settings.label"), - getter_Copies(settingsButtonTitle)); + bool isActionable; + if (bundle && NS_SUCCEEDED(aAlert->GetActionable(&isActionable)) && isActionable) { + nsXPIDLString closeButtonTitle, actionButtonTitle, disableButtonTitle, settingsButtonTitle; + bundle->GetStringFromName(MOZ_UTF16("closeButton.title"), + getter_Copies(closeButtonTitle)); + bundle->GetStringFromName(MOZ_UTF16("actionButton.label"), + getter_Copies(actionButtonTitle)); + if (!hostPort.IsEmpty()) { + const char16_t* formatStrings[] = { hostPort.get() }; + bundle->FormatStringFromName(MOZ_UTF16("webActions.disableForOrigin.label"), + formatStrings, + ArrayLength(formatStrings), + getter_Copies(disableButtonTitle)); + } + bundle->GetStringFromName(MOZ_UTF16("webActions.settings.label"), + getter_Copies(settingsButtonTitle)); - notification.otherButtonTitle = nsCocoaUtils::ToNSString(closeButtonTitle); + notification.otherButtonTitle = nsCocoaUtils::ToNSString(closeButtonTitle); - // OS X 10.8 only shows action buttons if the "Alerts" style is set in - // Notification Center preferences, and doesn't support the alternate - // action menu. - if ([notification respondsToSelector:@selector(set_showsButtons:)] && - [notification respondsToSelector:@selector(set_alwaysShowAlternateActionMenu:)] && - [notification respondsToSelector:@selector(set_alternateActionButtonTitles:)]) { + // OS X 10.8 only shows action buttons if the "Alerts" style is set in + // Notification Center preferences, and doesn't support the alternate + // action menu. + if ([notification respondsToSelector:@selector(set_showsButtons:)] && + [notification respondsToSelector:@selector(set_alwaysShowAlternateActionMenu:)] && + [notification respondsToSelector:@selector(set_alternateActionButtonTitles:)]) { - notification.hasActionButton = YES; - notification.actionButtonTitle = nsCocoaUtils::ToNSString(actionButtonTitle); + notification.hasActionButton = YES; + notification.actionButtonTitle = nsCocoaUtils::ToNSString(actionButtonTitle); - [(NSObject*)notification setValue:@(YES) forKey:@"_showsButtons"]; - [(NSObject*)notification setValue:@(YES) forKey:@"_alwaysShowAlternateActionMenu"]; - [(NSObject*)notification setValue:@[ - nsCocoaUtils::ToNSString(disableButtonTitle), - nsCocoaUtils::ToNSString(settingsButtonTitle) - ] - forKey:@"_alternateActionButtonTitles"]; - } + [(NSObject*)notification setValue:@(YES) forKey:@"_showsButtons"]; + [(NSObject*)notification setValue:@(YES) forKey:@"_alwaysShowAlternateActionMenu"]; + [(NSObject*)notification setValue:@[ + nsCocoaUtils::ToNSString(disableButtonTitle), + nsCocoaUtils::ToNSString(settingsButtonTitle) + ] + forKey:@"_alternateActionButtonTitles"]; } } nsAutoString name; @@ -383,22 +379,26 @@ OSXNotificationCenter::ShowAlert(nsIAlertNotification* aAlert, nsCOMPtr imageUri; NS_NewURI(getter_AddRefs(imageUri), imageUrl); if (imageUri) { - rv = il->LoadImage(imageUri, nullptr, nullptr, - mozilla::net::RP_Default, - principal, nullptr, - this, nullptr, - inPrivateBrowsing ? nsIRequest::LOAD_ANONYMOUS : - nsIRequest::LOAD_NORMAL, - nullptr, nsIContentPolicy::TYPE_INTERNAL_IMAGE, - EmptyString(), - getter_AddRefs(osxni->mIconRequest)); + nsCOMPtr principal; + rv = aAlert->GetPrincipal(getter_AddRefs(principal)); if (NS_SUCCEEDED(rv)) { - // Set a timer for six seconds. If we don't have an icon by the time this - // goes off then we go ahead without an icon. - nsCOMPtr timer = do_CreateInstance(NS_TIMER_CONTRACTID); - osxni->mIconTimeoutTimer = timer; - timer->InitWithCallback(this, 6000, nsITimer::TYPE_ONE_SHOT); - return NS_OK; + rv = il->LoadImage(imageUri, nullptr, nullptr, + mozilla::net::RP_Default, + principal, nullptr, + this, nullptr, + inPrivateBrowsing ? nsIRequest::LOAD_ANONYMOUS : + nsIRequest::LOAD_NORMAL, + nullptr, nsIContentPolicy::TYPE_INTERNAL_IMAGE, + EmptyString(), + getter_AddRefs(osxni->mIconRequest)); + if (NS_SUCCEEDED(rv)) { + // Set a timer for six seconds. If we don't have an icon by the time this + // goes off then we go ahead without an icon. + nsCOMPtr timer = do_CreateInstance(NS_TIMER_CONTRACTID); + osxni->mIconTimeoutTimer = timer; + timer->InitWithCallback(this, 6000, nsITimer::TYPE_ONE_SHOT); + return NS_OK; + } } } } diff --git a/widget/gtk/mozgtk/mozgtk.c b/widget/gtk/mozgtk/mozgtk.c index e8dec14ac7..6331d99767 100644 --- a/widget/gtk/mozgtk/mozgtk.c +++ b/widget/gtk/mozgtk/mozgtk.c @@ -561,6 +561,12 @@ STUB(gtk_app_chooser_get_type) STUB(gtk_app_chooser_get_app_info) STUB(gtk_app_chooser_dialog_get_type) STUB(gtk_app_chooser_dialog_set_heading) +STUB(gtk_color_chooser_dialog_new) +STUB(gtk_color_chooser_dialog_get_type) +STUB(gtk_color_chooser_get_type) +STUB(gtk_color_chooser_set_rgba) +STUB(gtk_color_chooser_get_rgba) +STUB(gtk_color_chooser_set_use_alpha) #endif #ifdef GTK2_SYMBOLS diff --git a/widget/gtk/nsColorPicker.cpp b/widget/gtk/nsColorPicker.cpp index 06a21e3cc3..169df146e8 100644 --- a/widget/gtk/nsColorPicker.cpp +++ b/widget/gtk/nsColorPicker.cpp @@ -13,6 +13,25 @@ NS_IMPL_ISUPPORTS(nsColorPicker, nsIColorPicker) +#if defined(ACTIVATE_GTK3_COLOR_PICKER) && GTK_CHECK_VERSION(3,4,0) +int nsColorPicker::convertGdkRgbaComponent(gdouble color_component) { + // GdkRGBA value is in range [0.0..1.0]. We need something in range [0..255] + return color_component * 255 + 0.5; +} + +gdouble nsColorPicker::convertToGdkRgbaComponent(int color_component) { + return color_component / 255.0; +} + +GdkRGBA nsColorPicker::convertToRgbaColor(nscolor color) { + GdkRGBA result = { convertToGdkRgbaComponent(NS_GET_R(color)), + convertToGdkRgbaComponent(NS_GET_G(color)), + convertToGdkRgbaComponent(NS_GET_B(color)), + convertToGdkRgbaComponent(NS_GET_A(color)) }; + + return result; +} +#else int nsColorPicker::convertGdkColorComponent(guint16 color_component) { // GdkColor value is in range [0..65535]. We need something in range [0..255] return (color_component * 255 + 127) / 65535; @@ -36,6 +55,7 @@ GtkColorSelection* nsColorPicker::WidgetGetColorSelection(GtkWidget* widget) return GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection( GTK_COLOR_SELECTION_DIALOG(widget))); } +#endif NS_IMETHODIMP nsColorPicker::Init(nsIDOMWindow *parent, const nsAString& title, @@ -63,8 +83,6 @@ NS_IMETHODIMP nsColorPicker::Open(nsIColorPickerShownCallback *aColorPickerShown return NS_ERROR_FAILURE; } - GdkColor color_gdk = convertToGdkColor(color); - if (mCallback) { // It means Open has already been called: this is not allowed NS_WARNING("mCallback is already set. Open called twice?"); @@ -74,21 +92,41 @@ NS_IMETHODIMP nsColorPicker::Open(nsIColorPickerShownCallback *aColorPickerShown nsXPIDLCString title; title.Adopt(ToNewUTF8String(mTitle)); - GtkWidget *color_chooser = gtk_color_selection_dialog_new(title); - GtkWindow *parent_window = GTK_WINDOW(mParentWidget->GetNativeData(NS_NATIVE_SHELLWIDGET)); + +#if defined(ACTIVATE_GTK3_COLOR_PICKER) && GTK_CHECK_VERSION(3,4,0) + GtkWidget* color_chooser = gtk_color_chooser_dialog_new(title, parent_window); + + if (parent_window) { + gtk_window_set_destroy_with_parent(GTK_WINDOW(color_chooser), TRUE); + } + + gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(color_chooser), FALSE); + GdkRGBA color_rgba = convertToRgbaColor(color); + gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(color_chooser), + &color_rgba); + + g_signal_connect(GTK_COLOR_CHOOSER(color_chooser), "color-activated", + G_CALLBACK(OnColorChanged), this); +#else + GtkWidget *color_chooser = gtk_color_selection_dialog_new(title); + if (parent_window) { GtkWindow *window = GTK_WINDOW(color_chooser); gtk_window_set_transient_for(window, parent_window); gtk_window_set_destroy_with_parent(window, TRUE); } + GdkColor color_gdk = convertToGdkColor(color); gtk_color_selection_set_current_color(WidgetGetColorSelection(color_chooser), &color_gdk); - - NS_ADDREF_THIS(); + g_signal_connect(WidgetGetColorSelection(color_chooser), "color-changed", G_CALLBACK(OnColorChanged), this); +#endif + + NS_ADDREF_THIS(); + g_signal_connect(color_chooser, "response", G_CALLBACK(OnResponse), this); g_signal_connect(color_chooser, "destroy", G_CALLBACK(OnDestroy), this); gtk_widget_show(color_chooser); @@ -96,6 +134,31 @@ NS_IMETHODIMP nsColorPicker::Open(nsIColorPickerShownCallback *aColorPickerShown return NS_OK; } +#if defined(ACTIVATE_GTK3_COLOR_PICKER) && GTK_CHECK_VERSION(3,4,0) +/* static */ void +nsColorPicker::OnColorChanged(GtkColorChooser* color_chooser, GdkRGBA* color, + gpointer user_data) +{ + static_cast(user_data)->Update(color); +} + +void +nsColorPicker::Update(GdkRGBA* color) +{ + SetColor(color); + if (mCallback) { + mCallback->Update(mColor); + } +} + +void nsColorPicker::SetColor(const GdkRGBA* color) +{ + mColor.Assign('#'); + mColor += ToHexString(convertGdkRgbaComponent(color->red)); + mColor += ToHexString(convertGdkRgbaComponent(color->green)); + mColor += ToHexString(convertGdkRgbaComponent(color->blue)); +} +#else /* static */ void nsColorPicker::OnColorChanged(GtkColorSelection* colorselection, gpointer user_data) @@ -103,6 +166,27 @@ nsColorPicker::OnColorChanged(GtkColorSelection* colorselection, static_cast(user_data)->Update(colorselection); } +void +nsColorPicker::Update(GtkColorSelection* colorselection) +{ + ReadValueFromColorSelection(colorselection); + if (mCallback) { + mCallback->Update(mColor); + } +} + +void nsColorPicker::ReadValueFromColorSelection(GtkColorSelection* colorselection) +{ + GdkColor rgba; + gtk_color_selection_get_current_color(colorselection, &rgba); + + mColor.Assign('#'); + mColor += ToHexString(convertGdkColorComponent(rgba.red)); + mColor += ToHexString(convertGdkColorComponent(rgba.green)); + mColor += ToHexString(convertGdkColorComponent(rgba.blue)); +} +#endif + /* static */ void nsColorPicker::OnResponse(GtkWidget* color_chooser, gint response_id, gpointer user_data) @@ -118,22 +202,19 @@ nsColorPicker::OnDestroy(GtkWidget* color_chooser, gpointer user_data) Done(color_chooser, GTK_RESPONSE_CANCEL); } -void -nsColorPicker::Update(GtkColorSelection* colorselection) -{ - ReadValueFromColorSelection(colorselection); - if (mCallback) { - mCallback->Update(mColor); - } -} - void nsColorPicker::Done(GtkWidget* color_chooser, gint response) { switch (response) { case GTK_RESPONSE_OK: case GTK_RESPONSE_ACCEPT: +#if defined(ACTIVATE_GTK3_COLOR_PICKER) && GTK_CHECK_VERSION(3,4,0) + GdkRGBA color; + gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(color_chooser), &color); + SetColor(&color); +#else ReadValueFromColorSelection(WidgetGetColorSelection(color_chooser)); +#endif break; case GTK_RESPONSE_CANCEL: case GTK_RESPONSE_CLOSE: @@ -167,14 +248,3 @@ nsString nsColorPicker::ToHexString(int n) result.AppendInt(n, 16); return result; } - -void nsColorPicker::ReadValueFromColorSelection(GtkColorSelection* colorselection) -{ - GdkColor rgba; - gtk_color_selection_get_current_color(colorselection, &rgba); - - mColor.Assign('#'); - mColor += ToHexString(convertGdkColorComponent(rgba.red)); - mColor += ToHexString(convertGdkColorComponent(rgba.green)); - mColor += ToHexString(convertGdkColorComponent(rgba.blue)); -} diff --git a/widget/gtk/nsColorPicker.h b/widget/gtk/nsColorPicker.h index 2c947246da..107e6f058f 100644 --- a/widget/gtk/nsColorPicker.h +++ b/widget/gtk/nsColorPicker.h @@ -12,6 +12,11 @@ #include "nsIColorPicker.h" #include "nsString.h" +// Don't activate the GTK3 color picker for now, because it is missing a few +// things, mainly the ability to let the user select a color on the screen. +// See bug 1198256. +#undef ACTIVATE_GTK3_COLOR_PICKER + class nsIWidget; class nsColorPicker final : public nsIColorPicker @@ -25,23 +30,38 @@ public: private: ~nsColorPicker() {}; - static void OnColorChanged(GtkColorSelection* colorselection, - gpointer user_data); + static nsString ToHexString(int n); + static void OnResponse(GtkWidget* dialog, gint response_id, gpointer user_data); static void OnDestroy(GtkWidget* dialog, gpointer user_data); + +#if defined(ACTIVATE_GTK3_COLOR_PICKER) && GTK_CHECK_VERSION(3,4,0) + static void OnColorChanged(GtkColorChooser* color_chooser, GdkRGBA* color, + gpointer user_data); + + static int convertGdkRgbaComponent(gdouble color_component); + static gdouble convertToGdkRgbaComponent(int color_component); + static GdkRGBA convertToRgbaColor(nscolor color); + + void Update(GdkRGBA* color); + void SetColor(const GdkRGBA* color); +#else + static void OnColorChanged(GtkColorSelection* colorselection, + gpointer user_data); // Conversion functions for color static int convertGdkColorComponent(guint16 color_component); static guint16 convertToGdkColorComponent(int color_component); - static GdkColor convertToGdkColor(nscolor color); - static nsString ToHexString(int n); + static GdkColor convertToGdkColor(nscolor color); static GtkColorSelection* WidgetGetColorSelection(GtkWidget* widget); - - void Done(GtkWidget* dialog, gint response_id); + void Update(GtkColorSelection* colorselection); void ReadValueFromColorSelection(GtkColorSelection* colorselection); +#endif + + void Done(GtkWidget* dialog, gint response_id); nsCOMPtr mParentWidget; nsCOMPtr mCallback; diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp index 8add3546d8..16e7c75ee2 100644 --- a/widget/gtk/nsWindow.cpp +++ b/widget/gtk/nsWindow.cpp @@ -3288,7 +3288,6 @@ nsWindow::OnWindowStateEvent(GtkWidget *aWidget, GdkEventWindowState *aEvent) return; } - bool wasInFullscreen = mSizeState == nsSizeMode_Fullscreen; if (aEvent->new_window_state & GDK_WINDOW_STATE_ICONIFIED) { LOG(("\tIconified\n")); mSizeState = nsSizeMode_Minimized; @@ -3317,10 +3316,9 @@ nsWindow::OnWindowStateEvent(GtkWidget *aWidget, GdkEventWindowState *aEvent) if (mWidgetListener) { mWidgetListener->SizeModeChanged(mSizeState); - - bool isInFullscreen = mSizeState == nsSizeMode_Fullscreen; - if (isInFullscreen != wasInFullscreen) { - mWidgetListener->FullscreenChanged(isInFullscreen); + if (aEvent->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) { + mWidgetListener->FullscreenChanged( + aEvent->new_window_state & GDK_WINDOW_STATE_FULLSCREEN); } } } diff --git a/widget/nsBaseFilePicker.cpp b/widget/nsBaseFilePicker.cpp index 1f574f591e..60d59224e0 100644 --- a/widget/nsBaseFilePicker.cpp +++ b/widget/nsBaseFilePicker.cpp @@ -337,24 +337,25 @@ nsBaseFilePicker::GetMode(int16_t* aMode) } NS_IMETHODIMP -nsBaseFilePicker::GetDomfile(nsISupports** aDomfile) +nsBaseFilePicker::GetDomFileOrDirectory(nsISupports** aValue) { nsCOMPtr localFile; nsresult rv = GetFile(getter_AddRefs(localFile)); NS_ENSURE_SUCCESS(rv, rv); if (!localFile) { - *aDomfile = nullptr; + *aValue = nullptr; return NS_OK; } - nsCOMPtr domFile = File::CreateFromFile(mParent, localFile); - domFile.forget(aDomfile); + RefPtr domFile = File::CreateFromFile(mParent, localFile); + domFile->Impl()->SetIsDirectory(mMode == nsIFilePicker::modeGetFolder); + nsCOMPtr(domFile).forget(aValue); return NS_OK; } NS_IMETHODIMP -nsBaseFilePicker::GetDomfiles(nsISimpleEnumerator** aDomfiles) +nsBaseFilePicker::GetDomFileOrDirectoryEnumerator(nsISimpleEnumerator** aValue) { nsCOMPtr iter; nsresult rv = GetFiles(getter_AddRefs(iter)); @@ -363,7 +364,7 @@ nsBaseFilePicker::GetDomfiles(nsISimpleEnumerator** aDomfiles) RefPtr retIter = new nsBaseFilePickerEnumerator(mParent, iter, mMode); - retIter.forget(aDomfiles); + retIter.forget(aValue); return NS_OK; } diff --git a/widget/nsBaseFilePicker.h b/widget/nsBaseFilePicker.h index b192a16257..ccdafd9f45 100644 --- a/widget/nsBaseFilePicker.h +++ b/widget/nsBaseFilePicker.h @@ -37,8 +37,8 @@ public: NS_IMETHOD SetAddToRecentDocs(bool aFlag); NS_IMETHOD GetMode(int16_t *aMode); - NS_IMETHOD GetDomfile(nsISupports** aDomfile); - NS_IMETHOD GetDomfiles(nsISimpleEnumerator** aDomfiles); + NS_IMETHOD GetDomFileOrDirectory(nsISupports** aValue); + NS_IMETHOD GetDomFileOrDirectoryEnumerator(nsISimpleEnumerator** aValue); protected: diff --git a/widget/nsFilePickerProxy.cpp b/widget/nsFilePickerProxy.cpp index 8e6e71e28f..4c0db8c041 100644 --- a/widget/nsFilePickerProxy.cpp +++ b/widget/nsFilePickerProxy.cpp @@ -103,21 +103,21 @@ nsFilePickerProxy::SetFilterIndex(int32_t aFilterIndex) NS_IMETHODIMP nsFilePickerProxy::GetFile(nsIFile** aFile) { - MOZ_ASSERT(false, "GetFile is unimplemented; use GetDomfile"); + MOZ_ASSERT(false, "GetFile is unimplemented; use GetDomFileOrDirectory"); return NS_ERROR_FAILURE; } NS_IMETHODIMP nsFilePickerProxy::GetFileURL(nsIURI** aFileURL) { - MOZ_ASSERT(false, "GetFileURL is unimplemented; use GetDomfile"); + MOZ_ASSERT(false, "GetFileURL is unimplemented; use GetDomFileOrDirectory"); return NS_ERROR_FAILURE; } NS_IMETHODIMP nsFilePickerProxy::GetFiles(nsISimpleEnumerator** aFiles) { - MOZ_ASSERT(false, "GetFiles is unimplemented; use GetDomfiles"); + MOZ_ASSERT(false, "GetFiles is unimplemented; use GetDomFileOrDirectoryEnumerator"); return NS_ERROR_FAILURE; } @@ -162,7 +162,7 @@ nsFilePickerProxy::Recv__delete__(const MaybeInputFiles& aFiles, RefPtr file = File::Create(mParent, blobImpl); MOZ_ASSERT(file); - mDomfiles.AppendElement(file); + mFilesOrDirectories.AppendElement(file); } } @@ -175,16 +175,16 @@ nsFilePickerProxy::Recv__delete__(const MaybeInputFiles& aFiles, } NS_IMETHODIMP -nsFilePickerProxy::GetDomfile(nsISupports** aDomfile) +nsFilePickerProxy::GetDomFileOrDirectory(nsISupports** aValue) { - *aDomfile = nullptr; - if (mDomfiles.IsEmpty()) { + *aValue = nullptr; + if (mFilesOrDirectories.IsEmpty()) { return NS_OK; } - MOZ_ASSERT(mDomfiles.Length() == 1); - nsCOMPtr blob = mDomfiles[0].get(); - blob.forget(aDomfile); + MOZ_ASSERT(mFilesOrDirectories.Length() == 1); + nsCOMPtr blob = mFilesOrDirectories[0].get(); + blob.forget(aValue); return NS_OK; } @@ -228,12 +228,12 @@ private: NS_IMPL_ISUPPORTS(SimpleEnumerator, nsISimpleEnumerator) -} // anonymous namespace +} // namespace NS_IMETHODIMP -nsFilePickerProxy::GetDomfiles(nsISimpleEnumerator** aDomfiles) +nsFilePickerProxy::GetDomFileOrDirectoryEnumerator(nsISimpleEnumerator** aDomfiles) { - RefPtr enumerator = new SimpleEnumerator(mDomfiles); + RefPtr enumerator = new SimpleEnumerator(mFilesOrDirectories); enumerator.forget(aDomfiles); return NS_OK; } diff --git a/widget/nsFilePickerProxy.h b/widget/nsFilePickerProxy.h index b8e1f9020f..c27b9ab834 100644 --- a/widget/nsFilePickerProxy.h +++ b/widget/nsFilePickerProxy.h @@ -21,8 +21,8 @@ class nsPIDOMWindow; namespace mozilla { namespace dom { class File; -} -} +} // namespace dom +} // namespace mozilla /** This class creates a proxy file picker to be used in content processes. @@ -51,8 +51,8 @@ public: NS_IMETHODIMP GetFileURL(nsIURI** aFileURL) override; NS_IMETHODIMP GetFiles(nsISimpleEnumerator** aFiles) override; - NS_IMETHODIMP GetDomfile(nsISupports** aFile) override; - NS_IMETHODIMP GetDomfiles(nsISimpleEnumerator** aFiles) override; + NS_IMETHODIMP GetDomFileOrDirectory(nsISupports** aValue) override; + NS_IMETHODIMP GetDomFileOrDirectoryEnumerator(nsISimpleEnumerator** aValue) override; NS_IMETHODIMP Show(int16_t* aReturn) override; NS_IMETHODIMP Open(nsIFilePickerShownCallback* aCallback) override; @@ -65,9 +65,7 @@ private: ~nsFilePickerProxy(); void InitNative(nsIWidget*, const nsAString&) override; - // This is an innerWindow. - nsCOMPtr mParent; - nsTArray> mDomfiles; + nsTArray> mFilesOrDirectories; nsCOMPtr mCallback; int16_t mSelectedType; diff --git a/widget/nsIFilePicker.idl b/widget/nsIFilePicker.idl index c51db99a33..b11e865541 100644 --- a/widget/nsIFilePicker.idl +++ b/widget/nsIFilePicker.idl @@ -23,7 +23,7 @@ interface nsIFilePickerShownCallback : nsISupports void done(in short aResult); }; -[scriptable, uuid(9840d564-42c8-4d78-9a4d-71002343c918)] +[scriptable, uuid(2a74ba0d-ffdd-4dad-b78a-98635e525a38)] interface nsIFilePicker : nsISupports { const short modeOpen = 0; // Load a file or directory @@ -142,19 +142,19 @@ interface nsIFilePicker : nsISupports readonly attribute nsISimpleEnumerator files; /** - * Get the DOM File for the file. + * Get the DOM File or the DOM Directory * - * @return Returns the file currently selected as File + * @return Returns the file or directory currently selected DOM object. */ - readonly attribute nsISupports domfile; + readonly attribute nsISupports domFileOrDirectory; /** - * Get the enumerator for the selected files + * Get the enumerator for the selected files or directories * only works in the modeOpenMultiple mode * - * @return Returns the files currently selected as Files + * @return Returns the files/directories currently selected as DOM object. */ - readonly attribute nsISimpleEnumerator domfiles; + readonly attribute nsISimpleEnumerator domFileOrDirectoryEnumerator; /** * Controls whether the chosen file(s) should be added to the system's recent diff --git a/widget/windows/nsWindow.cpp b/widget/windows/nsWindow.cpp index 5da4a63292..fa4edaeec9 100644 --- a/widget/windows/nsWindow.cpp +++ b/widget/windows/nsWindow.cpp @@ -1721,6 +1721,15 @@ NS_METHOD nsWindow::PlaceBehind(nsTopLevelWidgetZPlacement aPlacement, return NS_OK; } +static UINT +GetCurrentShowCmd(HWND aWnd) +{ + WINDOWPLACEMENT pl; + pl.length = sizeof(pl); + ::GetWindowPlacement(aWnd, &pl); + return pl.showCmd; +} + // Maximize, minimize or restore the window. NS_IMETHODIMP nsWindow::SetSizeMode(nsSizeMode aMode) { @@ -1762,14 +1771,11 @@ nsWindow::SetSizeMode(nsSizeMode aMode) { mode = SW_RESTORE; } - WINDOWPLACEMENT pl; - pl.length = sizeof(pl); - ::GetWindowPlacement(mWnd, &pl); // Don't call ::ShowWindow if we're trying to "restore" a window that is // already in a normal state. Prevents a bug where snapping to one side // of the screen and then minimizing would cause Windows to forget our // window's correct restored position/size. - if( !(pl.showCmd == SW_SHOWNORMAL && mode == SW_RESTORE) ) { + if(!(GetCurrentShowCmd(mWnd) == SW_SHOWNORMAL && mode == SW_RESTORE)) { ::ShowWindow(mWnd, mode); } // we activate here to ensure that the right child window is focused @@ -5332,8 +5338,10 @@ nsWindow::ProcessMessage(UINT msg, WPARAM& wParam, LPARAM& lParam, ::ShowWindow(mWnd, SW_SHOWMINIMIZED); result = true; } - - if (mSizeMode == nsSizeMode_Fullscreen && filteredWParam == SC_RESTORE) { + + if (mSizeMode == nsSizeMode_Fullscreen && + filteredWParam == SC_RESTORE && + GetCurrentShowCmd(mWnd) != SW_SHOWMINIMIZED) { MakeFullScreen(false); result = true; }