diff options
author | Moonchild <moonchild@palemoon.org> | 2023-04-09 13:44:46 +0000 |
---|---|---|
committer | Moonchild <moonchild@palemoon.org> | 2023-04-09 13:44:46 +0000 |
commit | bfeb62ceece166cc90de95f394c0313f35ac0fd1 (patch) | |
tree | c61991a79bfcee2ee57a5168ce87a8451adc45c6 /dom | |
parent | b62bf0c4b7e70f3bfcc1915526e158712aef1211 (diff) | |
parent | ae19a0513ee353dbdee92de16fc7c1e83516a40f (diff) | |
download | uxp-bfeb62ceece166cc90de95f394c0313f35ac0fd1.tar.gz |
Merge pull request 'Implement `self.structuredClone()`' (#2206) from FranklinDM/UXP-contrib:work_js-structuredclone into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/2206
Diffstat (limited to 'dom')
26 files changed, 344 insertions, 147 deletions
diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index 990e1bc589..86e52984af 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -47,6 +47,7 @@ #include "mozilla/dom/HTMLTemplateElement.h" #include "mozilla/dom/ipc/BlobChild.h" #include "mozilla/dom/ipc/BlobParent.h" +#include "mozilla/dom/MessagePort.h" #include "mozilla/dom/Promise.h" #include "mozilla/dom/ScriptSettings.h" #include "mozilla/dom/TabParent.h" @@ -9991,3 +9992,71 @@ nsContentUtils::GetClosestNonNativeAnonymousAncestor(Element* aElement) } return e; } + +/* static */ nsresult +nsContentUtils::CreateJSValueFromSequenceOfObject(JSContext* aCx, + const Sequence<JSObject*>& aTransfer, + JS::MutableHandle<JS::Value> aValue) +{ + if (aTransfer.IsEmpty()) { + return NS_OK; + } + + JS::Rooted<JSObject*> array(aCx, JS_NewArrayObject(aCx, aTransfer.Length())); + if (!array) { + return NS_ERROR_OUT_OF_MEMORY; + } + + for (uint32_t i = 0; i < aTransfer.Length(); ++i) { + JS::Rooted<JSObject*> object(aCx, aTransfer[i]); + if (!object) { + continue; + } + + if (NS_WARN_IF(!JS_DefineElement(aCx, array, i, object, + JSPROP_ENUMERATE))) { + return NS_ERROR_OUT_OF_MEMORY; + } + } + + aValue.setObject(*array); + return NS_OK; +} + +/* static */ +void nsContentUtils::StructuredClone(JSContext* aCx, + nsIGlobalObject* aGlobal, + JS::Handle<JS::Value> aValue, + const StructuredSerializeOptions& aOptions, + JS::MutableHandle<JS::Value> aRv, + ErrorResult& aError) { + JS::Rooted<JS::Value> transferArray(aCx, JS::UndefinedValue()); + aError = nsContentUtils::CreateJSValueFromSequenceOfObject( + aCx, aOptions.mTransfer, &transferArray); + if (NS_WARN_IF(aError.Failed())) { + return; + } + + JS::CloneDataPolicy clonePolicy; + // FIXME: Uncomment once bug 1609990 and bug 1611855 lands. + //clonePolicy.allowIntraClusterClonableSharedObjects(); + //clonePolicy.allowSharedMemoryObjects(); + + StructuredCloneHolder holder(StructuredCloneHolder::CloningSupported, + StructuredCloneHolder::TransferringSupported, + JS::StructuredCloneScope::SameProcessDifferentThread); + holder.Write(aCx, aValue, transferArray, clonePolicy, aError); + if (NS_WARN_IF(aError.Failed())) { + return; + } + + // TODO: Pass clonePolicy. + //holder.Read(this, aCx, aRv, clonePolicy, aError); + holder.Read(aGlobal, aCx, aRv, aError); + if (NS_WARN_IF(aError.Failed())) { + return; + } + + nsTArray<RefPtr<MessagePort>> ports = holder.TakeTransferredPorts(); + Unused << ports; +} diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h index a0c602f61a..58f9f56546 100644 --- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h @@ -132,6 +132,7 @@ class nsIContentParent; class TabChild; class Selection; class TabParent; +struct StructuredSerializeOptions; } // namespace dom namespace ipc { @@ -2812,6 +2813,23 @@ public: static bool IsCustomElementsEnabled() { return sIsCustomElementsEnabled; } + static nsresult + CreateJSValueFromSequenceOfObject(JSContext* aCx, + const mozilla::dom::Sequence<JSObject*>& aTransfer, + JS::MutableHandle<JS::Value> aValue); + + /** + * This implements the structured cloning algorithm as described by + * https://html.spec.whatwg.org/#structured-cloning. + */ + static void + StructuredClone(JSContext* aCx, + nsIGlobalObject* aGlobal, + JS::Handle<JS::Value> aValue, + const mozilla::dom::StructuredSerializeOptions& aOptions, + JS::MutableHandle<JS::Value> aRv, + mozilla::ErrorResult& aError); + private: static bool InitializeEventTable(); diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 01023f3a2d..a816efc7cd 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -8891,30 +8891,33 @@ nsGlobalWindow::PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage, } void -nsGlobalWindow::PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage, +nsGlobalWindow::PostMessageMoz(JSContext* aCx, + JS::Handle<JS::Value> aMessage, const nsAString& aTargetOrigin, - const Optional<Sequence<JS::Value>>& aTransfer, + const Sequence<JSObject*>& aTransfer, nsIPrincipal& aSubjectPrincipal, - ErrorResult& aError) + ErrorResult& aRv) { JS::Rooted<JS::Value> transferArray(aCx, JS::UndefinedValue()); - if (aTransfer.WasPassed()) { - const Sequence<JS::Value >& values = aTransfer.Value(); - - // The input sequence only comes from the generated bindings code, which - // ensures it is rooted. - JS::HandleValueArray elements = - JS::HandleValueArray::fromMarkedLocation(values.Length(), values.Elements()); - - transferArray = JS::ObjectOrNullValue(JS_NewArrayObject(aCx, elements)); - if (transferArray.isNull()) { - aError.Throw(NS_ERROR_OUT_OF_MEMORY); - return; - } + aRv = nsContentUtils::CreateJSValueFromSequenceOfObject(aCx, aTransfer, + &transferArray); + if (NS_WARN_IF(aRv.Failed())) { + return; } PostMessageMoz(aCx, aMessage, aTargetOrigin, transferArray, - aSubjectPrincipal, aError); + aSubjectPrincipal, aRv); +} + +void +nsGlobalWindow::PostMessageMoz(JSContext* aCx, + JS::Handle<JS::Value> aMessage, + const WindowPostMessageOptions& aOptions, + nsIPrincipal& aSubjectPrincipal, + ErrorResult& aRv) +{ + PostMessageMoz(aCx, aMessage, aOptions.mTargetOrigin, aOptions.mTransfer, + aSubjectPrincipal, aRv); } class nsCloseEvent : public Runnable { @@ -14638,6 +14641,17 @@ nsGlobalWindow::CreateImageBitmap(const ImageBitmapSource& aImage, } } +// https://html.spec.whatwg.org/#structured-cloning +void +nsGlobalWindow::StructuredClone(JSContext* aCx, + JS::Handle<JS::Value> aValue, + const StructuredSerializeOptions& aOptions, + JS::MutableHandle<JS::Value> aRv, + ErrorResult& aError) +{ + nsContentUtils::StructuredClone(aCx, this, aValue, aOptions, aRv, aError); +} + // Helper called by methods that move/resize the window, // to ensure the presContext (if any) is aware of resolution // change that may happen in multi-monitor configuration. diff --git a/dom/base/nsGlobalWindow.h b/dom/base/nsGlobalWindow.h index e593890af0..63bb574dd4 100644 --- a/dom/base/nsGlobalWindow.h +++ b/dom/base/nsGlobalWindow.h @@ -135,6 +135,7 @@ class TabGroup; class Timeout; class U2F; class WakeLock; +struct WindowPostMessageOptions; class Worklet; namespace cache { class CacheStorage; @@ -934,7 +935,12 @@ public: void Print(mozilla::ErrorResult& aError); void PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage, const nsAString& aTargetOrigin, - const mozilla::dom::Optional<mozilla::dom::Sequence<JS::Value > >& aTransfer, + const mozilla::dom::Sequence<JSObject*>& aTransfer, + nsIPrincipal& aSubjectPrincipal, + mozilla::ErrorResult& aRv); + void PostMessageMoz(JSContext* aCx, + JS::Handle<JS::Value> aMessage, + const mozilla::dom::WindowPostMessageOptions& aOptions, nsIPrincipal& aSubjectPrincipal, mozilla::ErrorResult& aError); int32_t SetTimeout(JSContext* aCx, mozilla::dom::Function& aFunction, @@ -1178,6 +1184,10 @@ public: const mozilla::dom::Sequence<mozilla::dom::ChannelPixelLayout>& aLayout, mozilla::ErrorResult& aRv); + void StructuredClone(JSContext* aCx, JS::Handle<JS::Value> aValue, + const mozilla::dom::StructuredSerializeOptions& aOptions, + JS::MutableHandle<JS::Value> aRv, + mozilla::ErrorResult& aError); // ChromeWindow bits. Do NOT call these unless your window is in // fact an nsGlobalChromeWindow. diff --git a/dom/messagechannel/MessagePort.cpp b/dom/messagechannel/MessagePort.cpp index 6f7a1abc19..5fbd1e9bb9 100644 --- a/dom/messagechannel/MessagePort.cpp +++ b/dom/messagechannel/MessagePort.cpp @@ -394,52 +394,39 @@ MessagePort::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) } void -MessagePort::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage, - const Optional<Sequence<JS::Value>>& aTransferable, +MessagePort::PostMessage(JSContext* aCx, + JS::Handle<JS::Value> aMessage, + const Sequence<JSObject*>& aTransferable, ErrorResult& aRv) { // We *must* clone the data here, or the JS::Value could be modified // by script - JS::Rooted<JS::Value> transferable(aCx, JS::UndefinedValue()); - if (aTransferable.WasPassed()) { - const Sequence<JS::Value>& realTransferable = aTransferable.Value(); - - // Here we want to check if the transerable object list contains - // this port. No other checks are done. - for (const JS::Value& value : realTransferable) { - if (!value.isObject()) { - continue; - } - - JS::Rooted<JSObject*> object(aCx, &value.toObject()); - - MessagePort* port = nullptr; - nsresult rv = UNWRAP_OBJECT(MessagePort, &object, port); - if (NS_FAILED(rv)) { - continue; - } - - if (port == this) { - aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR); - return; - } + // Here we want to check if the transferable object list contains + // this port. + for (uint32_t i = 0; i < aTransferable.Length(); ++i) { + JSObject* rawObject = aTransferable[i]; + if (!rawObject) { + continue; } - // The input sequence only comes from the generated bindings code, which - // ensures it is rooted. - JS::HandleValueArray elements = - JS::HandleValueArray::fromMarkedLocation(realTransferable.Length(), - realTransferable.Elements()); + JS::Rooted<JSObject*> object(aCx, rawObject); - JSObject* array = - JS_NewArrayObject(aCx, elements); - if (!array) { - aRv.Throw(NS_ERROR_OUT_OF_MEMORY); + MessagePort* port = nullptr; + nsresult rv = UNWRAP_OBJECT(MessagePort, &object, port); + if (NS_SUCCEEDED(rv) && port == this) { + aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR); return; } + } - transferable.setObject(*array); + JS::Rooted<JS::Value> transferable(aCx, JS::UndefinedValue()); + + aRv = nsContentUtils::CreateJSValueFromSequenceOfObject(aCx, + aTransferable, + &transferable); + if (NS_WARN_IF(aRv.Failed())) { + return; } RefPtr<SharedMessagePortMessage> data = new SharedMessagePortMessage(); @@ -509,6 +496,14 @@ MessagePort::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage, } void +MessagePort::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage, + const StructuredSerializeOptions& aOptions, + ErrorResult& aRv) +{ + PostMessage(aCx, aMessage, aOptions.mTransfer, aRv); +} + +void MessagePort::Start() { if (mMessageQueueEnabled) { diff --git a/dom/messagechannel/MessagePort.h b/dom/messagechannel/MessagePort.h index 0ed2af11c1..b832872e1f 100644 --- a/dom/messagechannel/MessagePort.h +++ b/dom/messagechannel/MessagePort.h @@ -26,6 +26,7 @@ class MessagePortIdentifier; class MessagePortMessage; class PostMessageRunnable; class SharedMessagePortMessage; +struct StructuredSerializeOptions; namespace workers { class WorkerHolder; @@ -62,7 +63,12 @@ public: void PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage, - const Optional<Sequence<JS::Value>>& aTransferable, + const Sequence<JSObject*>& aTransferable, + ErrorResult& aRv); + + void + PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage, + const StructuredSerializeOptions& aOptions, ErrorResult& aRv); void Start(); diff --git a/dom/tests/mochitest/whatwg/test_postMessage_origin.xhtml b/dom/tests/mochitest/whatwg/test_postMessage_origin.xhtml index f6a9198968..e48bee136d 100644 --- a/dom/tests/mochitest/whatwg/test_postMessage_origin.xhtml +++ b/dom/tests/mochitest/whatwg/test_postMessage_origin.xhtml @@ -383,13 +383,6 @@ var tests = hasWrongReturnOriginBug: true }, - // 55 - { - args: ["NOT-RECEIVED", undefined], - source: "sameDomain", - name: "SyntaxError", - code: DOMException.SYNTAX_ERR - }, ]; function allTests(callback) diff --git a/dom/webidl/Client.webidl b/dom/webidl/Client.webidl index 3e79c6a635..c961c2b31f 100644 --- a/dom/webidl/Client.webidl +++ b/dom/webidl/Client.webidl @@ -15,7 +15,9 @@ interface Client { readonly attribute DOMString id; [Throws] - void postMessage(any message, optional sequence<Transferable> transfer); + void postMessage(any message, sequence<object> transferable); + [Throws] + void postMessage(any message, optional StructuredSerializeOptions options); }; [Exposed=ServiceWorker] diff --git a/dom/webidl/DedicatedWorkerGlobalScope.webidl b/dom/webidl/DedicatedWorkerGlobalScope.webidl index 26dca58dab..80c7c8decb 100644 --- a/dom/webidl/DedicatedWorkerGlobalScope.webidl +++ b/dom/webidl/DedicatedWorkerGlobalScope.webidl @@ -16,7 +16,9 @@ Exposed=DedicatedWorker] interface DedicatedWorkerGlobalScope : WorkerGlobalScope { [Throws] - void postMessage(any message, optional sequence<any> transfer); + void postMessage(any message, sequence<object> transfer); + [Throws] + void postMessage(any message, optional StructuredSerializeOptions options); attribute EventHandler onmessage; }; diff --git a/dom/webidl/MessagePort.webidl b/dom/webidl/MessagePort.webidl index 59c61a7149..0b36c47d94 100644 --- a/dom/webidl/MessagePort.webidl +++ b/dom/webidl/MessagePort.webidl @@ -10,7 +10,9 @@ [Exposed=(Window,Worker,System)] interface MessagePort : EventTarget { [Throws] - void postMessage(any message, optional sequence<Transferable> transferable); + void postMessage(any message, sequence<object> transferable); + [Throws] + void postMessage(any message, optional StructuredSerializeOptions options); void start(); void close(); @@ -19,3 +21,8 @@ interface MessagePort : EventTarget { attribute EventHandler onmessage; }; // MessagePort implements Transferable; + +// Used to declare which objects should be transferred. +dictionary StructuredSerializeOptions { + sequence<object> transfer = []; +};
\ No newline at end of file diff --git a/dom/webidl/ServiceWorker.webidl b/dom/webidl/ServiceWorker.webidl index 8c3749e940..ff80fafc21 100644 --- a/dom/webidl/ServiceWorker.webidl +++ b/dom/webidl/ServiceWorker.webidl @@ -19,9 +19,10 @@ interface ServiceWorker : EventTarget { attribute EventHandler onstatechange; - // FIXME(catalinb): Should inherit this from Worker. [Throws] - void postMessage(any message, optional sequence<Transferable> transferable); + void postMessage(any message, sequence<object> transferable); + [Throws] + void postMessage(any message, optional StructuredSerializeOptions options); }; ServiceWorker implements AbstractWorker; diff --git a/dom/webidl/Window.webidl b/dom/webidl/Window.webidl index 6020f71dce..2ba9f4f124 100644 --- a/dom/webidl/Window.webidl +++ b/dom/webidl/Window.webidl @@ -22,7 +22,6 @@ interface IID; interface nsIBrowserDOMWindow; interface nsIMessageBroadcaster; interface nsIDOMCrypto; -typedef any Transferable; // http://www.whatwg.org/specs/web-apps/current-work/ [PrimaryGlobal, LegacyUnenumerableNamedProperties, NeedResolve] @@ -81,7 +80,9 @@ typedef any Transferable; [Throws, UnsafeInPrerendering] void print(); [Throws, CrossOriginCallable, NeedsSubjectPrincipal] - void postMessage(any message, DOMString targetOrigin, optional sequence<Transferable> transfer); + void postMessage(any message, DOMString targetOrigin, optional sequence<object> transfer = []); + [Throws, CrossOriginCallable, NeedsSubjectPrincipal] + void postMessage(any message, optional WindowPostMessageOptions options); // also has obsolete members }; @@ -487,3 +488,7 @@ callback IdleRequestCallback = void (IdleDeadline deadline); partial interface Window { [ChromeOnly] readonly attribute boolean isSecureContextIfOpenerIgnored; }; + +dictionary WindowPostMessageOptions : StructuredSerializeOptions { + USVString targetOrigin = "/"; +}; diff --git a/dom/webidl/WindowOrWorkerGlobalScope.webidl b/dom/webidl/WindowOrWorkerGlobalScope.webidl index 652a46ffcb..9e639db5f4 100644 --- a/dom/webidl/WindowOrWorkerGlobalScope.webidl +++ b/dom/webidl/WindowOrWorkerGlobalScope.webidl @@ -44,6 +44,10 @@ interface WindowOrWorkerGlobalScope { Promise<ImageBitmap> createImageBitmap(ImageBitmapSource aImage); [Throws] Promise<ImageBitmap> createImageBitmap(ImageBitmapSource aImage, long aSx, long aSy, long aSw, long aSh); + + // structured cloning + [Throws] + any structuredClone(any value, optional StructuredSerializeOptions options); }; // https://fetch.spec.whatwg.org/#fetch-method diff --git a/dom/webidl/Worker.webidl b/dom/webidl/Worker.webidl index 158a502d60..c13357cd7e 100644 --- a/dom/webidl/Worker.webidl +++ b/dom/webidl/Worker.webidl @@ -19,7 +19,9 @@ interface Worker : EventTarget { void terminate(); [Throws] - void postMessage(any message, optional sequence<any> transfer); + void postMessage(any message, sequence<object> transfer); + [Throws] + void postMessage(any message, optional StructuredSerializeOptions options); attribute EventHandler onmessage; }; diff --git a/dom/workers/ServiceWorker.cpp b/dom/workers/ServiceWorker.cpp index 16dd28b8ad..f2a39ea9c2 100644 --- a/dom/workers/ServiceWorker.cpp +++ b/dom/workers/ServiceWorker.cpp @@ -14,6 +14,7 @@ #include "mozilla/Preferences.h" #include "mozilla/dom/Promise.h" +#include "mozilla/dom/MessagePortBinding.h" #include "mozilla/dom/ServiceWorkerGlobalScopeBinding.h" #ifdef XP_WIN @@ -77,7 +78,7 @@ ServiceWorker::GetScriptURL(nsString& aURL) const void ServiceWorker::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage, - const Optional<Sequence<JS::Value>>& aTransferable, + const Sequence<JSObject*>& aTransferable, ErrorResult& aRv) { if (State() == ServiceWorkerState::Redundant) { @@ -97,6 +98,15 @@ ServiceWorker::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage, aRv = workerPrivate->SendMessageEvent(aCx, aMessage, aTransferable, Move(clientInfo)); } +void +ServiceWorker::PostMessage(JSContext* aCx, + JS::Handle<JS::Value> aMessage, + const StructuredSerializeOptions& aOptions, + ErrorResult& aRv) +{ + PostMessage(aCx, aMessage, aOptions.mTransfer, aRv); +} + } // namespace workers } // namespace dom } // namespace mozilla diff --git a/dom/workers/ServiceWorker.h b/dom/workers/ServiceWorker.h index 3a3cce8260..eb14fc4293 100644 --- a/dom/workers/ServiceWorker.h +++ b/dom/workers/ServiceWorker.h @@ -15,6 +15,8 @@ class nsPIDOMWindowInner; namespace mozilla { namespace dom { +struct StructuredSerializeOptions; + namespace workers { class ServiceWorkerInfo; @@ -63,7 +65,13 @@ public: void PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage, - const Optional<Sequence<JS::Value>>& aTransferable, + const Sequence<JSObject*>& aTransferable, + ErrorResult& aRv); + + void + PostMessage(JSContext* aCx, + JS::Handle<JS::Value> aMessage, + const StructuredSerializeOptions& aOptions, ErrorResult& aRv); private: diff --git a/dom/workers/ServiceWorkerClient.cpp b/dom/workers/ServiceWorkerClient.cpp index 1f845a947b..e8b8341e21 100644 --- a/dom/workers/ServiceWorkerClient.cpp +++ b/dom/workers/ServiceWorkerClient.cpp @@ -11,6 +11,7 @@ #include "mozilla/dom/Navigator.h" #include "mozilla/dom/ServiceWorkerMessageEvent.h" #include "mozilla/dom/ServiceWorkerMessageEventBinding.h" +#include "mozilla/dom/MessagePortBinding.h" #include "nsGlobalWindow.h" #include "nsIBrowserDOMWindow.h" #include "nsIDocument.h" @@ -190,7 +191,7 @@ private: void ServiceWorkerClient::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage, - const Optional<Sequence<JS::Value>>& aTransferable, + const Sequence<JSObject*>& aTransferable, ErrorResult& aRv) { WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); @@ -198,20 +199,11 @@ ServiceWorkerClient::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage, workerPrivate->AssertIsOnWorkerThread(); JS::Rooted<JS::Value> transferable(aCx, JS::UndefinedValue()); - if (aTransferable.WasPassed()) { - const Sequence<JS::Value>& realTransferable = aTransferable.Value(); - - JS::HandleValueArray elements = - JS::HandleValueArray::fromMarkedLocation(realTransferable.Length(), - realTransferable.Elements()); - - JSObject* array = JS_NewArrayObject(aCx, elements); - if (!array) { - aRv.Throw(NS_ERROR_OUT_OF_MEMORY); - return; - } - - transferable.setObject(*array); + aRv = nsContentUtils::CreateJSValueFromSequenceOfObject(aCx, + aTransferable, + &transferable); + if (NS_WARN_IF(aRv.Failed())) { + return; } RefPtr<ServiceWorkerClientPostMessageRunnable> runnable = @@ -229,3 +221,11 @@ ServiceWorkerClient::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage, } } +void +ServiceWorkerClient::PostMessage(JSContext* aCx, + JS::Handle<JS::Value> aMessage, + const StructuredSerializeOptions& aOptions, + ErrorResult& aRv) +{ + PostMessage(aCx, aMessage, aOptions.mTransfer, aRv); +} diff --git a/dom/workers/ServiceWorkerClient.h b/dom/workers/ServiceWorkerClient.h index 46bcdbc4c4..7f89ee611a 100644 --- a/dom/workers/ServiceWorkerClient.h +++ b/dom/workers/ServiceWorkerClient.h @@ -91,7 +91,13 @@ public: void PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage, - const Optional<Sequence<JS::Value>>& aTransferable, + const Sequence<JSObject*>& aTransferable, + ErrorResult& aRv); + + void + PostMessage(JSContext* aCx, + JS::Handle<JS::Value> aMessage, + const StructuredSerializeOptions& aOptions, ErrorResult& aRv); JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; diff --git a/dom/workers/ServiceWorkerPrivate.cpp b/dom/workers/ServiceWorkerPrivate.cpp index 2f5b8f7500..fe6ec138b7 100644 --- a/dom/workers/ServiceWorkerPrivate.cpp +++ b/dom/workers/ServiceWorkerPrivate.cpp @@ -141,7 +141,7 @@ NS_IMPL_ISUPPORTS0(MessageWaitUntilHandler) nsresult ServiceWorkerPrivate::SendMessageEvent(JSContext* aCx, JS::Handle<JS::Value> aMessage, - const Optional<Sequence<JS::Value>>& aTransferable, + const Sequence<JSObject*>& aTransferable, UniquePtr<ServiceWorkerClientInfo>&& aClientInfo) { ErrorResult rv(SpawnWorkerIfNeeded(MessageEvent, nullptr)); diff --git a/dom/workers/ServiceWorkerPrivate.h b/dom/workers/ServiceWorkerPrivate.h index 8ce021c8cf..c2d5abfd6c 100644 --- a/dom/workers/ServiceWorkerPrivate.h +++ b/dom/workers/ServiceWorkerPrivate.h @@ -74,7 +74,7 @@ public: nsresult SendMessageEvent(JSContext* aCx, JS::Handle<JS::Value> aMessage, - const Optional<Sequence<JS::Value>>& aTransferable, + const Sequence<JSObject*>& aTransferable, UniquePtr<ServiceWorkerClientInfo>&& aClientInfo); // This is used to validate the worker script and continue the installation diff --git a/dom/workers/SharedWorker.cpp b/dom/workers/SharedWorker.cpp index 97df0f57fd..2fae19f291 100644 --- a/dom/workers/SharedWorker.cpp +++ b/dom/workers/SharedWorker.cpp @@ -22,6 +22,7 @@ using mozilla::dom::Optional; using mozilla::dom::Sequence; using mozilla::dom::MessagePort; +using mozilla::dom::StructuredSerializeOptions; using namespace mozilla; USING_WORKERS_NAMESPACE @@ -142,7 +143,7 @@ SharedWorker::Close() void SharedWorker::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage, - const Optional<Sequence<JS::Value>>& aTransferable, + const Sequence<JSObject*>& aTransferable, ErrorResult& aRv) { AssertIsOnMainThread(); @@ -152,6 +153,15 @@ SharedWorker::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage, mMessagePort->PostMessage(aCx, aMessage, aTransferable, aRv); } +void +SharedWorker::PostMessage(JSContext* aCx, + JS::Handle<JS::Value> aMessage, + const StructuredSerializeOptions& aOptions, + ErrorResult& aRv) +{ + PostMessage(aCx, aMessage, aOptions.mTransfer, aRv); +} + NS_IMPL_ADDREF_INHERITED(SharedWorker, DOMEventTargetHelper) NS_IMPL_RELEASE_INHERITED(SharedWorker, DOMEventTargetHelper) diff --git a/dom/workers/SharedWorker.h b/dom/workers/SharedWorker.h index 4820b4e7c1..e85fc2609a 100644 --- a/dom/workers/SharedWorker.h +++ b/dom/workers/SharedWorker.h @@ -94,8 +94,15 @@ private: // Only called by MessagePort. void - PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage, - const Optional<Sequence<JS::Value>>& aTransferable, + PostMessage(JSContext* aCx, + JS::Handle<JS::Value> aMessage, + const Sequence<JSObject*>& aTransferable, + ErrorResult& aRv); + + void + PostMessage(JSContext* aCx, + JS::Handle<JS::Value> aMessage, + const StructuredSerializeOptions& aOptions, ErrorResult& aRv); }; diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp index cf270703e0..a7a4929f3b 100644 --- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -3006,13 +3006,12 @@ WorkerPrivateParent<Derived>::ForgetMainThreadObjects( template <class Derived> void -WorkerPrivateParent<Derived>::PostMessageInternal( - JSContext* aCx, - JS::Handle<JS::Value> aMessage, - const Optional<Sequence<JS::Value>>& aTransferable, - UniquePtr<ServiceWorkerClientInfo>&& aClientInfo, - PromiseNativeHandler* aHandler, - ErrorResult& aRv) +WorkerPrivateParent<Derived>::PostMessageInternal(JSContext* aCx, + JS::Handle<JS::Value> aMessage, + const Sequence<JSObject*>& aTransferable, + UniquePtr<ServiceWorkerClientInfo>&& aClientInfo, + PromiseNativeHandler* aHandler, + ErrorResult& aRv) { AssertIsOnParentThread(); @@ -3024,22 +3023,11 @@ WorkerPrivateParent<Derived>::PostMessageInternal( } JS::Rooted<JS::Value> transferable(aCx, JS::UndefinedValue()); - if (aTransferable.WasPassed()) { - const Sequence<JS::Value>& realTransferable = aTransferable.Value(); - - // The input sequence only comes from the generated bindings code, which - // ensures it is rooted. - JS::HandleValueArray elements = - JS::HandleValueArray::fromMarkedLocation(realTransferable.Length(), - realTransferable.Elements()); - - JSObject* array = - JS_NewArrayObject(aCx, elements); - if (!array) { - aRv.Throw(NS_ERROR_OUT_OF_MEMORY); - return; - } - transferable.setObject(*array); + aRv = nsContentUtils::CreateJSValueFromSequenceOfObject(aCx, + aTransferable, + &transferable); + if (NS_WARN_IF(aRv.Failed())) { + return; } RefPtr<MessageEventRunnable> runnable = @@ -3083,8 +3071,9 @@ WorkerPrivateParent<Derived>::PostMessageInternal( template <class Derived> void WorkerPrivateParent<Derived>::PostMessage( - JSContext* aCx, JS::Handle<JS::Value> aMessage, - const Optional<Sequence<JS::Value>>& aTransferable, + JSContext* aCx, + JS::Handle<JS::Value> aMessage, + const Sequence<JSObject*>& aTransferable, ErrorResult& aRv) { PostMessageInternal(aCx, aMessage, aTransferable, nullptr, nullptr, aRv); @@ -3092,9 +3081,21 @@ WorkerPrivateParent<Derived>::PostMessage( template <class Derived> void +WorkerPrivateParent<Derived>::PostMessage( + JSContext* aCx, + JS::Handle<JS::Value> aMessage, + const StructuredSerializeOptions& aOptions, + ErrorResult& aRv) +{ + PostMessageInternal(aCx, aMessage, aOptions.mTransfer, nullptr, nullptr, aRv); +} + +template <class Derived> +void WorkerPrivateParent<Derived>::PostMessageToServiceWorker( - JSContext* aCx, JS::Handle<JS::Value> aMessage, - const Optional<Sequence<JS::Value>>& aTransferable, + JSContext* aCx, + JS::Handle<JS::Value> aMessage, + const Sequence<JSObject*>& aTransferable, UniquePtr<ServiceWorkerClientInfo>&& aClientInfo, PromiseNativeHandler* aHandler, ErrorResult& aRv) @@ -5677,27 +5678,17 @@ void WorkerPrivate::PostMessageToParentInternal( JSContext* aCx, JS::Handle<JS::Value> aMessage, - const Optional<Sequence<JS::Value>>& aTransferable, + const Sequence<JSObject*>& aTransferable, ErrorResult& aRv) { AssertIsOnWorkerThread(); JS::Rooted<JS::Value> transferable(aCx, JS::UndefinedValue()); - if (aTransferable.WasPassed()) { - const Sequence<JS::Value>& realTransferable = aTransferable.Value(); - - // The input sequence only comes from the generated bindings code, which - // ensures it is rooted. - JS::HandleValueArray elements = - JS::HandleValueArray::fromMarkedLocation(realTransferable.Length(), - realTransferable.Elements()); - - JSObject* array = JS_NewArrayObject(aCx, elements); - if (!array) { - aRv = NS_ERROR_OUT_OF_MEMORY; - return; - } - transferable.setObject(*array); + aRv = nsContentUtils::CreateJSValueFromSequenceOfObject(aCx, + aTransferable, + &transferable); + if (NS_WARN_IF(aRv.Failed())) { + return; } RefPtr<MessageEventRunnable> runnable = diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h index b638c1ef11..0a71420047 100644 --- a/dom/workers/WorkerPrivate.h +++ b/dom/workers/WorkerPrivate.h @@ -68,6 +68,7 @@ class PromiseNativeHandler; class StructuredCloneHolder; class WorkerDebuggerGlobalScope; class WorkerGlobalScope; +struct StructuredSerializeOptions; } // namespace dom namespace ipc { class PrincipalInfo; @@ -287,7 +288,7 @@ private: void PostMessageInternal(JSContext* aCx, JS::Handle<JS::Value> aMessage, - const Optional<Sequence<JS::Value>>& aTransferable, + const Sequence<JSObject*>& aTransferable, UniquePtr<ServiceWorkerClientInfo>&& aClientInfo, PromiseNativeHandler* aHandler, ErrorResult& aRv); @@ -400,12 +401,18 @@ public: void PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage, - const Optional<Sequence<JS::Value>>& aTransferable, + const Sequence<JSObject*>& aTransferable, + ErrorResult& aRv); + + void + PostMessage(JSContext* aCx, + JS::Handle<JS::Value> aMessage, + const StructuredSerializeOptions& aOptions, ErrorResult& aRv); void PostMessageToServiceWorker(JSContext* aCx, JS::Handle<JS::Value> aMessage, - const Optional<Sequence<JS::Value>>& aTransferable, + const Sequence<JSObject*>& aTransferable, UniquePtr<ServiceWorkerClientInfo>&& aClientInfo, PromiseNativeHandler* aHandler, ErrorResult& aRv); @@ -1161,18 +1168,17 @@ public: void PostMessageToParent(JSContext* aCx, JS::Handle<JS::Value> aMessage, - const Optional<Sequence<JS::Value>>& aTransferable, + const Sequence<JSObject*>& aTransferable, ErrorResult& aRv) { PostMessageToParentInternal(aCx, aMessage, aTransferable, aRv); } void - PostMessageToParentMessagePort( - JSContext* aCx, - JS::Handle<JS::Value> aMessage, - const Optional<Sequence<JS::Value>>& aTransferable, - ErrorResult& aRv); + PostMessageToParentMessagePort(JSContext* aCx, + JS::Handle<JS::Value> aMessage, + const Sequence<JSObject*>& aTransferable, + ErrorResult& aRv); void EnterDebuggerEventLoop(); @@ -1471,7 +1477,7 @@ private: void PostMessageToParentInternal(JSContext* aCx, JS::Handle<JS::Value> aMessage, - const Optional<Sequence<JS::Value>>& aTransferable, + const Sequence<JSObject*>& aTransferable, ErrorResult& aRv); void diff --git a/dom/workers/WorkerScope.cpp b/dom/workers/WorkerScope.cpp index ec42364b52..637e441732 100644 --- a/dom/workers/WorkerScope.cpp +++ b/dom/workers/WorkerScope.cpp @@ -7,6 +7,7 @@ #include "jsapi.h" #include "mozilla/EventListenerManager.h" +#include "mozilla/Unused.h" #include "mozilla/dom/BindingDeclarations.h" #include "mozilla/dom/Console.h" #include "mozilla/dom/DedicatedWorkerGlobalScopeBinding.h" @@ -492,6 +493,15 @@ WorkerGlobalScope::CreateImageBitmap(const ImageBitmapSource& aImage, } } +// https://html.spec.whatwg.org/#structured-cloning +void WorkerGlobalScope::StructuredClone(JSContext* aCx, + JS::Handle<JS::Value> aValue, + const StructuredSerializeOptions& aOptions, + JS::MutableHandle<JS::Value> aRv, + ErrorResult& aError) { + nsContentUtils::StructuredClone(aCx, this, aValue, aOptions, aRv, aError); +} + DedicatedWorkerGlobalScope::DedicatedWorkerGlobalScope(WorkerPrivate* aWorkerPrivate) : WorkerGlobalScope(aWorkerPrivate) { @@ -535,13 +545,22 @@ DedicatedWorkerGlobalScope::WrapGlobalObject(JSContext* aCx, void DedicatedWorkerGlobalScope::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage, - const Optional<Sequence<JS::Value>>& aTransferable, + const Sequence<JSObject*>& aTransferable, ErrorResult& aRv) { mWorkerPrivate->AssertIsOnWorkerThread(); mWorkerPrivate->PostMessageToParent(aCx, aMessage, aTransferable, aRv); } +void +DedicatedWorkerGlobalScope::PostMessage(JSContext* aCx, + JS::Handle<JS::Value> aMessage, + const StructuredSerializeOptions& aOptions, + ErrorResult& aRv) +{ + PostMessage(aCx, aMessage, aOptions.mTransfer, aRv); +} + SharedWorkerGlobalScope::SharedWorkerGlobalScope(WorkerPrivate* aWorkerPrivate, const nsCString& aName) : WorkerGlobalScope(aWorkerPrivate), mName(aName) diff --git a/dom/workers/WorkerScope.h b/dom/workers/WorkerScope.h index 8d06152da2..01bae5cc11 100644 --- a/dom/workers/WorkerScope.h +++ b/dom/workers/WorkerScope.h @@ -24,6 +24,7 @@ class Function; class IDBFactory; enum class ImageBitmapFormat : uint32_t; class Performance; +struct StructuredSerializeOptions; class Promise; class RequestOrUSVString; class ServiceWorkerRegistration; @@ -182,6 +183,11 @@ public: const mozilla::dom::Sequence<mozilla::dom::ChannelPixelLayout>& aLayout, mozilla::ErrorResult& aRv); + void StructuredClone(JSContext* aCx, JS::Handle<JS::Value> aValue, + const StructuredSerializeOptions& aOptions, + JS::MutableHandle<JS::Value> aRv, + ErrorResult& aError); + bool WindowInteractionAllowed() const { @@ -215,7 +221,13 @@ public: void PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage, - const Optional<Sequence<JS::Value>>& aTransferable, + const Sequence<JSObject*>& aTransferable, + ErrorResult& aRv); + + void + PostMessage(JSContext* aCx, + JS::Handle<JS::Value> aMessage, + const StructuredSerializeOptions& aOptions, ErrorResult& aRv); IMPL_EVENT_HANDLER(message) |