From 3478c01fc84039b58aa0ae3120fb0adcb226d1ee Mon Sep 17 00:00:00 2001 From: Moonchild Date: Wed, 15 Nov 2023 21:53:16 +0100 Subject: [PATCH 1/9] Issue #2361 - Base implementation of Navigator.Clipboard This hard-refuses any reads from clipboard with a promise rejection. --- dom/base/Navigator.cpp | 10 ++ dom/base/Navigator.h | 4 + dom/bindings/Bindings.conf | 4 + dom/events/Clipboard.cpp | 202 ++++++++++++++++++++++++++++ dom/events/Clipboard.h | 60 +++++++++ dom/events/DataTransfer.cpp | 14 +- dom/events/DataTransfer.h | 1 + dom/events/DataTransferItemList.cpp | 3 +- dom/events/moz.build | 2 + dom/webidl/Clipboard.webidl | 25 ++++ dom/webidl/Navigator.webidl | 6 + dom/webidl/moz.build | 1 + modules/libpref/init/all.js | 6 + 13 files changed, 327 insertions(+), 11 deletions(-) create mode 100644 dom/events/Clipboard.cpp create mode 100644 dom/events/Clipboard.h create mode 100644 dom/webidl/Clipboard.webidl diff --git a/dom/base/Navigator.cpp b/dom/base/Navigator.cpp index a636a31ecb..a507dea841 100644 --- a/dom/base/Navigator.cpp +++ b/dom/base/Navigator.cpp @@ -30,6 +30,7 @@ #include "nsContentUtils.h" #include "nsUnicharUtils.h" #include "mozilla/Preferences.h" +#include "mozilla/dom/Clipboard.h" #ifdef MOZ_GAMEPAD #include "mozilla/dom/GamepadServiceTest.h" #endif @@ -1510,6 +1511,15 @@ Navigator::GetUserAgent(nsPIDOMWindowInner* aWindow, nsIURI* aURI, return siteSpecificUA->GetUserAgentForURIAndWindow(aURI, aWindow, aUserAgent); } +Clipboard* +Navigator::Clipboard() +{ + if (!mClipboard) { + mClipboard = new dom::Clipboard(GetWindow()); + } + return mClipboard; +} + #ifdef MOZ_EME static nsCString ToCString(const nsString& aString) diff --git a/dom/base/Navigator.h b/dom/base/Navigator.h index 3a0c9cc45f..69626d1a7c 100644 --- a/dom/base/Navigator.h +++ b/dom/base/Navigator.h @@ -40,6 +40,7 @@ class WakeLock; class ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams; class ServiceWorkerContainer; class DOMRequest; +class Clipboard; } // namespace dom } // namespace mozilla @@ -213,6 +214,8 @@ public: ErrorResult& aRv); already_AddRefed ServiceWorker(); + + dom::Clipboard* Clipboard(); void GetLanguages(nsTArray& aLanguages); @@ -277,6 +280,7 @@ private: RefPtr mNotification; RefPtr mPowerManager; RefPtr mConnection; + RefPtr mClipboard; #ifdef MOZ_AUDIO_CHANNEL_MANAGER RefPtr mAudioChannelManager; #endif diff --git a/dom/bindings/Bindings.conf b/dom/bindings/Bindings.conf index fcd84e28b6..26751ac8c6 100644 --- a/dom/bindings/Bindings.conf +++ b/dom/bindings/Bindings.conf @@ -169,6 +169,10 @@ DOMInterfaces = { 'headerFile': 'mozilla/dom/workers/bindings/ServiceWorkerClients.h', }, +'Clipboard' : { + 'implicitJSContext' : ['write', 'writeText', 'read', 'readText'], +}, + 'console': { 'nativeType': 'mozilla::dom::Console', }, diff --git a/dom/events/Clipboard.cpp b/dom/events/Clipboard.cpp new file mode 100644 index 0000000000..11b7388b8d --- /dev/null +++ b/dom/events/Clipboard.cpp @@ -0,0 +1,202 @@ +/* -*- Mode: C++; tab-width: 8; 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/. */ + +#include "mozilla/AbstractThread.h" +#include "mozilla/dom/Clipboard.h" +#include "mozilla/dom/ClipboardBinding.h" +#include "mozilla/dom/Promise.h" +#include "mozilla/dom/DataTransfer.h" +#include "mozilla/dom/DataTransferItemList.h" +#include "mozilla/dom/DataTransferItem.h" +#include "mozilla/dom/ContentChild.h" +#include "nsIClipboard.h" +#include "nsISupportsPrimitives.h" +#include "nsComponentManagerUtils.h" +#include "nsITransferable.h" +#include "nsArrayUtils.h" + + +static mozilla::LazyLogModule gClipboardLog("Clipboard"); + +namespace mozilla { +namespace dom { + +Clipboard::Clipboard(nsPIDOMWindowInner* aWindow) +: DOMEventTargetHelper(aWindow) +{ +} + +Clipboard::~Clipboard() +{ +} + +already_AddRefed +Clipboard::ReadHelper(JSContext* aCx, nsIPrincipal& aSubjectPrincipal, + ClipboardReadType aClipboardReadType, ErrorResult& aRv) +{ + // Create a new promise + RefPtr p = dom::Promise::Create(GetOwnerGlobal(), aRv); + if (aRv.Failed()) { + return nullptr; + } + + // We always reject reading from clipboard for sec reasons. + // below code kept in place in case we change our minds on that but will require + // permissions. + // e.g. if(!nsContentUtils::IsCallerChrome()) would allow add-ons... + if (true) { + MOZ_LOG(GetClipboardLog(), LogLevel::Debug, ("Clipboard, ReadHelper, " + "Don't have permissions for reading\n")); + p->MaybeRejectWithUndefined(); + return p.forget(); + } + + // Want isExternal = true in order to use the data transfer object to perform a read + RefPtr dataTransfer = new DataTransfer(this, ePaste, /* is external */ true, + nsIClipboard::kGlobalClipboard); + + // Create a new runnable + RefPtr r = NS_NewRunnableFunction( + [p, dataTransfer, &aSubjectPrincipal, aClipboardReadType]() { + IgnoredErrorResult ier; + switch (aClipboardReadType) { + case eRead: + MOZ_LOG(GetClipboardLog(), LogLevel::Debug, + ("Clipboard, ReadHelper, read case\n")); + dataTransfer->FillAllExternalData(); + // If there are items on the clipboard, data transfer will contain those, + // else, data transfer will be empty and we will be resolving with an empty data transfer + p->MaybeResolve(dataTransfer); + break; + case eReadText: + MOZ_LOG(GetClipboardLog(), LogLevel::Debug, + ("Clipboard, ReadHelper, read text case\n")); + nsAutoString str; + dataTransfer->GetData(NS_LITERAL_STRING(kTextMime), str, aSubjectPrincipal, ier); + // Either resolve with a string extracted from data transfer item + // or resolve with an empty string if nothing was found + p->MaybeResolve(str); + break; + } + }); + // Dispatch the runnable + NS_DispatchToCurrentThread(r.forget()); + return p.forget(); +} + +already_AddRefed +Clipboard::Read(JSContext* aCx, nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) +{ + return ReadHelper(aCx, aSubjectPrincipal, eRead, aRv); +} + +already_AddRefed +Clipboard::ReadText(JSContext* aCx, nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) +{ + return ReadHelper(aCx, aSubjectPrincipal, eReadText, aRv); +} + +already_AddRefed +Clipboard::Write(JSContext* aCx, DataTransfer& aData, nsIPrincipal& aSubjectPrincipal, + ErrorResult& aRv) +{ + // Create a promise + RefPtr p = dom::Promise::Create(GetOwnerGlobal(), aRv); + if (aRv.Failed()) { + return nullptr; + } + + // We want to disable this if dom.allow_cut_copy is false, or + // it doesn't meet the other requirements for copying to clipboard + if (!nsContentUtils::IsCutCopyAllowed()) { + MOZ_LOG(GetClipboardLog(), LogLevel::Debug, + ("Clipboard, Write, Not allowed to write to clipboard\n")); + p->MaybeRejectWithUndefined(); + return p.forget(); + } + + // Get the clipboard service + nsCOMPtr clipboard(do_GetService("@mozilla.org/widget/clipboard;1")); + if (!clipboard) { + p->MaybeRejectWithUndefined(); + return p.forget(); + } + + nsPIDOMWindowInner* owner = GetOwner(); + nsIDocument* doc = owner ? owner->GetDoc() : nullptr; + nsILoadContext* context = doc ? doc->GetLoadContext() : nullptr; + if (!context) { + p->MaybeRejectWithUndefined(); + return p.forget(); + } + + // Get the transferable + RefPtr transferable = aData.GetTransferable(0, context); + if (!transferable) { + p->MaybeRejectWithUndefined(); + return p.forget(); + } + + // Create a runnable + RefPtr r = NS_NewRunnableFunction( + [transferable, p, clipboard]() { + nsresult rv = clipboard->SetData(transferable, + /* owner of the transferable */ nullptr, + nsIClipboard::kGlobalClipboard); + if (NS_FAILED(rv)) { + p->MaybeRejectWithUndefined(); + return; + } + p->MaybeResolveWithUndefined(); + return; + }); + // Dispatch the runnable + NS_DispatchToCurrentThread(r.forget()); + return p.forget(); +} + +already_AddRefed +Clipboard::WriteText(JSContext* aCx, const nsAString& aData, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) +{ + // We create a data transfer with text/plain format so that + // we can reuse Clipboard::Write(...) member function + RefPtr dataTransfer = new DataTransfer(this, eCopy, + /* is external */ true, + /* clipboard type */ -1); + dataTransfer->SetData(NS_LITERAL_STRING(kTextMime), aData, aSubjectPrincipal, aRv); + return Write(aCx, *dataTransfer, aSubjectPrincipal, aRv); +} + +JSObject* +Clipboard::WrapObject(JSContext* aCx, JS::Handle aGivenProto) +{ + return ClipboardBinding::Wrap(aCx, this, aGivenProto); +} + +/* static */ LogModule* +Clipboard::GetClipboardLog() +{ + return gClipboardLog; +} + +NS_IMPL_CYCLE_COLLECTION_CLASS(Clipboard) + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(Clipboard, + DOMEventTargetHelper) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(Clipboard, + DOMEventTargetHelper) +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Clipboard) +NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) + +NS_IMPL_ADDREF_INHERITED(Clipboard, DOMEventTargetHelper) +NS_IMPL_RELEASE_INHERITED(Clipboard, DOMEventTargetHelper) + +} // namespace dom +} // namespace mozilla diff --git a/dom/events/Clipboard.h b/dom/events/Clipboard.h new file mode 100644 index 0000000000..9960de652b --- /dev/null +++ b/dom/events/Clipboard.h @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 8; 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/. */ + +#ifndef mozilla_dom_Clipboard_h_ +#define mozilla_dom_Clipboard_h_ + +#include "nsString.h" +#include "mozilla/DOMEventTargetHelper.h" +#include "mozilla/Logging.h" +#include "mozilla/dom/DataTransfer.h" + +namespace mozilla { +namespace dom { + +enum ClipboardReadType { + eRead, + eReadText, +}; + +class Promise; + +// https://www.w3.org/TR/clipboard-apis/#clipboard-interface +class Clipboard : public DOMEventTargetHelper +{ +public: + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(Clipboard, + DOMEventTargetHelper) + + IMPL_EVENT_HANDLER(message) + //IMPL_EVENT_HANDLER(messageerror) + + explicit Clipboard(nsPIDOMWindowInner* aWindow); + already_AddRefed Read(JSContext* aCx, nsIPrincipal& aSubjectPrincipal, + ErrorResult& aRv); + already_AddRefed ReadText(JSContext* aCx, nsIPrincipal& aSubjectPrincipal, + ErrorResult& aRv); + already_AddRefed Write(JSContext* aCx, DataTransfer& aData, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv); + already_AddRefed WriteText(JSContext* aCx, const nsAString& aData, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv); + + static LogModule* GetClipboardLog(); + + + virtual JSObject* + WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; + +private: + already_AddRefed ReadHelper(JSContext* aCx, nsIPrincipal& aSubjectPrincipal, + ClipboardReadType aClipboardReadType, ErrorResult& aRv); + + ~Clipboard(); +}; + +} // namespace dom +} // namespace mozilla +#endif // mozilla_dom_Clipboard_h_ diff --git a/dom/events/DataTransfer.cpp b/dom/events/DataTransfer.cpp index 3a3f5464d2..7ac154ea4b 100644 --- a/dom/events/DataTransfer.cpp +++ b/dom/events/DataTransfer.cpp @@ -1204,16 +1204,12 @@ DataTransfer::ConvertFromVariant(nsIVariant* aVariant, return true; } - char16_t* chrs; - uint32_t len = 0; - nsresult rv = aVariant->GetAsWStringWithSize(&len, &chrs); + nsAutoString str; + nsresult rv = aVariant->GetAsAString(str); if (NS_FAILED(rv)) { return false; } - nsAutoString str; - str.Adopt(chrs, len); - nsCOMPtr strSupports(do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID)); if (!strSupports) { @@ -1225,7 +1221,7 @@ DataTransfer::ConvertFromVariant(nsIVariant* aVariant, strSupports.forget(aSupports); // each character is two bytes - *aLength = str.Length() << 1; + *aLength = str.Length() * 2; return true; } @@ -1410,9 +1406,7 @@ DataTransfer::CacheExternalClipboardFormats() return; } - nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager(); - nsCOMPtr sysPrincipal; - ssm->GetSystemPrincipal(getter_AddRefs(sysPrincipal)); + nsCOMPtr sysPrincipal = nsContentUtils::GetSystemPrincipal(); // Check if the clipboard has any files bool hasFileData = false; diff --git a/dom/events/DataTransfer.h b/dom/events/DataTransfer.h index dbb4ec9bf8..f35020e111 100644 --- a/dom/events/DataTransfer.h +++ b/dom/events/DataTransfer.h @@ -315,6 +315,7 @@ protected: uint32_t aIndex, nsIPrincipal* aSubjectPrincipal); friend class ContentParent; + friend class Clipboard; void FillAllExternalData(); diff --git a/dom/events/DataTransferItemList.cpp b/dom/events/DataTransferItemList.cpp index ecea4968ce..630ae8a957 100644 --- a/dom/events/DataTransferItemList.cpp +++ b/dom/events/DataTransferItemList.cpp @@ -152,7 +152,8 @@ DataTransferItemList::Add(const nsAString& aData, return nullptr; } - nsCOMPtr data(new storage::TextVariant(aData)); + RefPtr data(new nsVariantCC()); + data->SetAsAString(aData); nsAutoString format; mDataTransfer->GetRealFormat(aType, format); diff --git a/dom/events/moz.build b/dom/events/moz.build index fcb59a2975..ae57e91fe3 100644 --- a/dom/events/moz.build +++ b/dom/events/moz.build @@ -37,6 +37,7 @@ EXPORTS.mozilla.dom += [ 'AnimationEvent.h', 'BeforeAfterKeyboardEvent.h', 'BeforeUnloadEvent.h', + 'Clipboard.h', 'ClipboardEvent.h', 'CommandEvent.h', 'CompositionEvent.h', @@ -78,6 +79,7 @@ UNIFIED_SOURCES += [ 'AsyncEventDispatcher.cpp', 'BeforeAfterKeyboardEvent.cpp', 'BeforeUnloadEvent.cpp', + 'Clipboard.cpp', 'ClipboardEvent.cpp', 'CommandEvent.cpp', 'CompositionEvent.cpp', diff --git a/dom/webidl/Clipboard.webidl b/dom/webidl/Clipboard.webidl new file mode 100644 index 0000000000..65fa976af6 --- /dev/null +++ b/dom/webidl/Clipboard.webidl @@ -0,0 +1,25 @@ +/* -*- 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://www.w3.org/TR/geolocation-API + * + * Copyright © 2018 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C + * liability, trademark and document use rules apply. + */ + + +[SecureContext, Exposed=Window, Pref="dom.events.asyncClipboard"] +interface Clipboard : EventTarget { + [Pref="dom.events.asyncClipboard.dataTransfer", Throws, NeedsSubjectPrincipal] + Promise read(); + [Throws, NeedsSubjectPrincipal] + Promise readText(); + [Pref="dom.events.asyncClipboard.dataTransfer", Throws, NeedsSubjectPrincipal] + Promise write(DataTransfer data); + [Throws, NeedsSubjectPrincipal] + Promise writeText(DOMString data); +}; + diff --git a/dom/webidl/Navigator.webidl b/dom/webidl/Navigator.webidl index eacb6c9443..60ed84d535 100644 --- a/dom/webidl/Navigator.webidl +++ b/dom/webidl/Navigator.webidl @@ -324,3 +324,9 @@ partial interface Navigator { interface NavigatorConcurrentHardware { readonly attribute unsigned long long hardwareConcurrency; }; + +// https://www.w3.org/TR/clipboard-apis/#navigator-interface +partial interface Navigator { + [Pref="dom.events.asyncClipboard", SecureContext, SameObject] + readonly attribute Clipboard clipboard; +}; diff --git a/dom/webidl/moz.build b/dom/webidl/moz.build index e69d4b77d0..0f47aabae4 100644 --- a/dom/webidl/moz.build +++ b/dom/webidl/moz.build @@ -74,6 +74,7 @@ WEBIDL_FILES = [ 'ChromeUtils.webidl', 'Client.webidl', 'Clients.webidl', + 'Clipboard.webidl', 'ClipboardEvent.webidl', 'CommandEvent.webidl', 'Comment.webidl', diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 5978669ce3..f8014c2dfc 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -5279,3 +5279,9 @@ pref("media.sourceErrorDetails.enabled", true); #else pref("media.sourceErrorDetails.enabled", false); #endif + +// Whether Navigator.Clipboard methods are a thing. +pref("dom.events.asyncClipboard", false); +// Whether arbitrary data transfer methods (not plaintext) are allowed. +pref("dom.events.asyncClipboard.dataTransfer", false); + From e0a7c35dcc5d86396f0445c67676f33e7c9707a7 Mon Sep 17 00:00:00 2001 From: Moonchild Date: Thu, 16 Nov 2023 01:34:40 +0100 Subject: [PATCH 2/9] Issue #2361 - Remove clipboard-read code Web content should never read the clipboard; extensions have other APIs they can use through XPCOM so do not need to go through Navigator.Clipboard, removing the only reason why it would even be here. --- dom/events/Clipboard.cpp | 46 +++++----------------------------------- 1 file changed, 5 insertions(+), 41 deletions(-) diff --git a/dom/events/Clipboard.cpp b/dom/events/Clipboard.cpp index 11b7388b8d..4bfa15b725 100644 --- a/dom/events/Clipboard.cpp +++ b/dom/events/Clipboard.cpp @@ -43,46 +43,9 @@ Clipboard::ReadHelper(JSContext* aCx, nsIPrincipal& aSubjectPrincipal, } // We always reject reading from clipboard for sec reasons. - // below code kept in place in case we change our minds on that but will require - // permissions. - // e.g. if(!nsContentUtils::IsCallerChrome()) would allow add-ons... - if (true) { - MOZ_LOG(GetClipboardLog(), LogLevel::Debug, ("Clipboard, ReadHelper, " - "Don't have permissions for reading\n")); - p->MaybeRejectWithUndefined(); - return p.forget(); - } - - // Want isExternal = true in order to use the data transfer object to perform a read - RefPtr dataTransfer = new DataTransfer(this, ePaste, /* is external */ true, - nsIClipboard::kGlobalClipboard); - - // Create a new runnable - RefPtr r = NS_NewRunnableFunction( - [p, dataTransfer, &aSubjectPrincipal, aClipboardReadType]() { - IgnoredErrorResult ier; - switch (aClipboardReadType) { - case eRead: - MOZ_LOG(GetClipboardLog(), LogLevel::Debug, - ("Clipboard, ReadHelper, read case\n")); - dataTransfer->FillAllExternalData(); - // If there are items on the clipboard, data transfer will contain those, - // else, data transfer will be empty and we will be resolving with an empty data transfer - p->MaybeResolve(dataTransfer); - break; - case eReadText: - MOZ_LOG(GetClipboardLog(), LogLevel::Debug, - ("Clipboard, ReadHelper, read text case\n")); - nsAutoString str; - dataTransfer->GetData(NS_LITERAL_STRING(kTextMime), str, aSubjectPrincipal, ier); - // Either resolve with a string extracted from data transfer item - // or resolve with an empty string if nothing was found - p->MaybeResolve(str); - break; - } - }); - // Dispatch the runnable - NS_DispatchToCurrentThread(r.forget()); + MOZ_LOG(GetClipboardLog(), LogLevel::Debug, ("Clipboard, ReadHelper, " + "Don't have permissions for reading\n")); + p->MaybeRejectWithUndefined(); return p.forget(); } @@ -162,7 +125,8 @@ Clipboard::WriteText(JSContext* aCx, const nsAString& aData, nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) { // We create a data transfer with text/plain format so that - // we can reuse Clipboard::Write(...) member function + // we can reuse the Clipboard::Write(...) member function + // We want isExternal = true in order to use the data transfer object to perform a write RefPtr dataTransfer = new DataTransfer(this, eCopy, /* is external */ true, /* clipboard type */ -1); From 543e41f3acaedc8c25be28a5e426cdfe5bb0d383 Mon Sep 17 00:00:00 2001 From: Gerald Squelart Date: Sun, 19 Nov 2023 13:10:29 +0100 Subject: [PATCH 3/9] Bug 1332825 - Use move semantics in MozPromise::All() and AllPromiseHolder. MozPromise::All sets up 'Then' lambdas on all sub-promises, each one taking the resolve/reject object by value. Since this value will not be used again in the lambda, it is safe to Move it, and from there MozPromiseHolder::Resolve/Reject can also Move it again into the holder storage, potentially saving two copies per Resolve/Reject. Also, once all sub-promises have been resolved, the resolve-values can be Move'd into the joining promise's Resolve function. --- xpcom/threads/MozPromise.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/xpcom/threads/MozPromise.h b/xpcom/threads/MozPromise.h index 8cc3d51ba0..f97f55bb8d 100644 --- a/xpcom/threads/MozPromise.h +++ b/xpcom/threads/MozPromise.h @@ -229,35 +229,35 @@ private: mResolveValues.SetLength(aDependentPromises); } - void Resolve(size_t aIndex, const ResolveValueType& aResolveValue) + void Resolve(size_t aIndex, ResolveValueType&& aResolveValue) { if (!mPromise) { // Already rejected. return; } - mResolveValues[aIndex].emplace(aResolveValue); + mResolveValues[aIndex].emplace(Move(aResolveValue)); if (--mOutstandingPromises == 0) { nsTArray resolveValues; resolveValues.SetCapacity(mResolveValues.Length()); for (size_t i = 0; i < mResolveValues.Length(); ++i) { - resolveValues.AppendElement(mResolveValues[i].ref()); + resolveValues.AppendElement(Move(mResolveValues[i].ref())); } - mPromise->Resolve(resolveValues, __func__); + mPromise->Resolve(Move(resolveValues), __func__); mPromise = nullptr; mResolveValues.Clear(); } } - void Reject(const RejectValueType& aRejectValue) + void Reject(RejectValueType&& aRejectValue) { if (!mPromise) { // Already rejected. return; } - mPromise->Reject(aRejectValue, __func__); + mPromise->Reject(Move(aRejectValue), __func__); mPromise = nullptr; mResolveValues.Clear(); } @@ -276,8 +276,8 @@ public: RefPtr holder = new AllPromiseHolder(aPromises.Length()); for (size_t i = 0; i < aPromises.Length(); ++i) { aPromises[i]->Then(aProcessingThread, __func__, - [holder, i] (ResolveValueType aResolveValue) -> void { holder->Resolve(i, aResolveValue); }, - [holder] (RejectValueType aRejectValue) -> void { holder->Reject(aRejectValue); } + [holder, i] (ResolveValueType aResolveValue) -> void { holder->Resolve(i, Move(aResolveValue)); }, + [holder] (RejectValueType aRejectValue) -> void { holder->Reject(Move(aRejectValue)); } ); } return holder->Promise(); From 7fce3acfa9b4d857a81c5be0e10b0fd147e0d252 Mon Sep 17 00:00:00 2001 From: Moonchild Date: Sun, 19 Nov 2023 16:22:59 +0100 Subject: [PATCH 4/9] Issue #2361 - Enable Navigator.clipboard by default. --- modules/libpref/init/all.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index f8014c2dfc..1dc38291cf 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -5281,7 +5281,6 @@ pref("media.sourceErrorDetails.enabled", false); #endif // Whether Navigator.Clipboard methods are a thing. -pref("dom.events.asyncClipboard", false); +pref("dom.events.asyncClipboard", true); // Whether arbitrary data transfer methods (not plaintext) are allowed. -pref("dom.events.asyncClipboard.dataTransfer", false); - +pref("dom.events.asyncClipboard.dataTransfer", true); From acd204e85e56ed2409df296aa18a594f43bb3533 Mon Sep 17 00:00:00 2001 From: Moonchild Date: Thu, 23 Nov 2023 14:05:37 +0100 Subject: [PATCH 5/9] [WebGL] Turn on more validation/error checking in webgl (when not on Win) --- dom/canvas/WebGLContext.cpp | 11 ++++++++--- dom/canvas/WebGLTextureUpload.cpp | 1 + modules/libpref/init/all.js | 7 +++++++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/dom/canvas/WebGLContext.cpp b/dom/canvas/WebGLContext.cpp index 51442cba4b..2e7ddb42e0 100644 --- a/dom/canvas/WebGLContext.cpp +++ b/dom/canvas/WebGLContext.cpp @@ -676,9 +676,11 @@ WebGLContext::CreateAndInitGL(bool forceEnabled, std::vector* const out_failReasons) { const gl::SurfaceCaps baseCaps = BaseCaps(mOptions, this); - gl::CreateContextFlags flags = gl::CreateContextFlags::NO_VALIDATION; - bool tryNativeGL = true; - bool tryANGLE = false; + gl::CreateContextFlags flags = gl::CreateContextFlags::NONE; + + if (Preferences::GetBool("webgl.gl_khr_no_validation", false)) { + flags |= gl::CreateContextFlags::NO_VALIDATION; + } if (forceEnabled) { flags |= gl::CreateContextFlags::FORCE_ENABLE_HARDWARE; @@ -694,6 +696,9 @@ WebGLContext::CreateAndInitGL(bool forceEnabled, const bool useEGL = PR_GetEnv("MOZ_WEBGL_FORCE_EGL"); + bool tryNativeGL = true; + bool tryANGLE = false; + #ifdef XP_WIN tryNativeGL = false; tryANGLE = true; diff --git a/dom/canvas/WebGLTextureUpload.cpp b/dom/canvas/WebGLTextureUpload.cpp index 661fb91ce2..6b864f2ff5 100644 --- a/dom/canvas/WebGLTextureUpload.cpp +++ b/dom/canvas/WebGLTextureUpload.cpp @@ -2188,6 +2188,7 @@ WebGLTexture::CopyTexImage2D(TexImageTarget target, GLint level, GLenum internal srcTotalWidth, srcTotalHeight, srcUsage, 0, 0, 0, width, height, dstUsage)) { + Truncate(); return; } diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 1dc38291cf..bfaa856536 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -4338,6 +4338,13 @@ pref("webgl.dxgl.enabled", true); pref("webgl.dxgl.needs-finish", false); #endif +// Disable ANGLE's validation layer? +#ifdef XP_WIN +pref("webgl.gl_khr_no_validation", true); +#else +pref("webgl.gl_khr_no_validation", false); +#endif + pref("gfx.offscreencanvas.enabled", false); // Stagefright prefs From 71ce058b03c8dcedb3a3aae9ace842332a4a4bfc Mon Sep 17 00:00:00 2001 From: Moonchild Date: Thu, 23 Nov 2023 14:44:33 +0100 Subject: [PATCH 6/9] [DOM] Check if rootDoc is secure context for web compat --- dom/security/nsMixedContentBlocker.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dom/security/nsMixedContentBlocker.cpp b/dom/security/nsMixedContentBlocker.cpp index 031bc27db7..f980acf018 100644 --- a/dom/security/nsMixedContentBlocker.cpp +++ b/dom/security/nsMixedContentBlocker.cpp @@ -729,10 +729,10 @@ nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect, docShell->GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot)); NS_ASSERTION(sameTypeRoot, "No root tree item from docshell!"); - // When navigating an iframe, the iframe may be https - // but its parents may not be. Check the parents to see if any of them are https. - // If none of the parents are https, allow the load. - if (aContentType == TYPE_SUBDOCUMENT && !rootHasSecureConnection) { + // When navigating an iframe, the iframe may be https but its parents may not + // be. Check the parents to see if any of them are https. If none of the + // parents are https, allow the load. + if (aContentType == TYPE_SUBDOCUMENT && !rootHasSecureConnection && !parentIsHttps) { bool httpsParentExists = false; From d55111c4fd1b20e2ec291788721a2adbe2370956 Mon Sep 17 00:00:00 2001 From: Moonchild Date: Thu, 23 Nov 2023 16:08:26 +0100 Subject: [PATCH 7/9] [Network] Fix relative URL path starting with multiple slashes --- netwerk/base/nsStandardURL.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/netwerk/base/nsStandardURL.cpp b/netwerk/base/nsStandardURL.cpp index aa60b52cd5..9334def6c7 100644 --- a/netwerk/base/nsStandardURL.cpp +++ b/netwerk/base/nsStandardURL.cpp @@ -2541,7 +2541,15 @@ nsStandardURL::Resolve(const nsACString &in, nsACString &out) // locate result path resultPath = PL_strstr(result, "://"); if (resultPath) { - resultPath = PL_strchr(resultPath + 3, '/'); + // If there are multiple slashes after :// we must ignore them + // otherwise net_CoalesceDirs may think the host is a part of the path. + resultPath += 3; + if (protocol.IsEmpty() && !SegmentIs(mScheme,"file")) { + while (*resultPath == '/') { + resultPath++; + } + } + resultPath = PL_strchr(resultPath, '/'); if (resultPath) net_CoalesceDirs(coalesceFlag,resultPath); } From 114daae894e927aa8d78333f8cf1fb5adc08ca1a Mon Sep 17 00:00:00 2001 From: Moonchild Date: Thu, 23 Nov 2023 17:32:44 +0100 Subject: [PATCH 8/9] [DOM] Improve MessagePort state machine. --- dom/messagechannel/MessagePort.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dom/messagechannel/MessagePort.cpp b/dom/messagechannel/MessagePort.cpp index 5fbd1e9bb9..ee537607bf 100644 --- a/dom/messagechannel/MessagePort.cpp +++ b/dom/messagechannel/MessagePort.cpp @@ -296,6 +296,11 @@ MessagePort::MessagePort(nsIGlobalObject* aGlobal) MessagePort::~MessagePort() { CloseForced(); + MOZ_ASSERT(!mActor); + if (mActor) { + mActor->SetPort(nullptr); + mActor = nullptr; + } MOZ_ASSERT(!mWorkerHolder); } @@ -370,6 +375,7 @@ MessagePort::Initialize(const nsID& aUUID, nsAutoPtr workerHolder(new MessagePortWorkerHolder(this)); if (NS_WARN_IF(!workerHolder->HoldWorker(workerPrivate, Closing))) { + CloseForced(); aRv.Throw(NS_ERROR_FAILURE); return; } From 56bcdf7ca0e7dedb58fefb9ce440433f98245286 Mon Sep 17 00:00:00 2001 From: Moonchild Date: Thu, 23 Nov 2023 18:05:58 +0100 Subject: [PATCH 9/9] [WebGL] Flip the validation state for gl_KHR_no_validation. The original state was inverted due to confusion due to a double negative (not:no_error). This validation should only be enabled on Windows (for now). Future tracking and discussion in BZ 1862039 --- modules/libpref/init/all.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index bfaa856536..344bb532b2 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -4340,9 +4340,9 @@ pref("webgl.dxgl.needs-finish", false); // Disable ANGLE's validation layer? #ifdef XP_WIN -pref("webgl.gl_khr_no_validation", true); -#else pref("webgl.gl_khr_no_validation", false); +#else +pref("webgl.gl_khr_no_validation", true); #endif pref("gfx.offscreencanvas.enabled", false);