1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
7 #include "EventWithOptionsRunnable.h"
8 #include "WorkerScope.h"
9 #include "mozilla/dom/WorkerRunnable.h"
10 #include "mozilla/dom/StructuredCloneHolder.h"
11 #include "js/StructuredClone.h"
12 #include "js/RootingAPI.h"
14 #include "nsJSPrincipals.h"
15 #include "nsContentUtils.h"
17 #include "MainThreadUtils.h"
18 #include "mozilla/Assertions.h"
19 #include "nsGlobalWindowInner.h"
20 #include "mozilla/DOMEventTargetHelper.h"
21 #include "mozilla/ErrorResult.h"
22 #include "nsIGlobalObject.h"
24 #include "js/GlobalObject.h"
25 #include "xpcpublic.h"
26 #include "mozilla/dom/MessagePortBinding.h"
27 #include "mozilla/dom/MessagePort.h"
28 #include "mozilla/OwningNonNull.h"
29 #include "mozilla/RefPtr.h"
30 #include "mozilla/dom/Event.h"
31 #include "mozilla/dom/WorkerCommon.h"
33 namespace mozilla::dom
{
34 EventWithOptionsRunnable::EventWithOptionsRunnable(Worker
& aWorker
,
36 : WorkerDebuggeeRunnable(aName
),
37 StructuredCloneHolder(CloningSupported
, TransferringSupported
,
38 StructuredCloneScope::SameProcess
) {}
40 EventWithOptionsRunnable::~EventWithOptionsRunnable() = default;
42 void EventWithOptionsRunnable::InitOptions(
43 JSContext
* aCx
, JS::Handle
<JS::Value
> aOptions
,
44 const Sequence
<JSObject
*>& aTransferable
, ErrorResult
& aRv
) {
45 JS::Rooted
<JS::Value
> transferable(aCx
, JS::UndefinedValue());
47 aRv
= nsContentUtils::CreateJSValueFromSequenceOfObject(aCx
, aTransferable
,
49 if (NS_WARN_IF(aRv
.Failed())) {
53 JS::CloneDataPolicy clonePolicy
;
54 // DedicatedWorkers are always part of the same agent cluster.
55 clonePolicy
.allowIntraClusterClonableSharedObjects();
57 MOZ_ASSERT(NS_IsMainThread());
58 nsGlobalWindowInner
* win
= nsContentUtils::IncumbentInnerWindow();
59 if (win
&& win
->IsSharedMemoryAllowed()) {
60 clonePolicy
.allowSharedMemoryObjects();
63 Write(aCx
, aOptions
, transferable
, clonePolicy
, aRv
);
66 // Cargo-culted from MesssageEventRunnable.
67 bool EventWithOptionsRunnable::BuildAndFireEvent(
68 JSContext
* aCx
, WorkerPrivate
* aWorkerPrivate
,
69 DOMEventTargetHelper
* aTarget
) {
70 IgnoredErrorResult rv
;
71 nsCOMPtr
<nsIGlobalObject
> parent
= aTarget
->GetParentObject();
73 // For some workers without window, parent is null and we try to find it
74 // from the JS Context.
76 JS::Rooted
<JSObject
*> globalObject(aCx
, JS::CurrentGlobalOrNull(aCx
));
77 if (NS_WARN_IF(!globalObject
)) {
78 rv
.ThrowDataCloneError("failed to get global object");
79 OptionsDeserializeFailed(rv
);
83 parent
= xpc::NativeGlobal(globalObject
);
84 if (NS_WARN_IF(!parent
)) {
85 rv
.ThrowDataCloneError("failed to get parent");
86 OptionsDeserializeFailed(rv
);
93 JS::Rooted
<JS::Value
> options(aCx
);
95 JS::CloneDataPolicy cloneDataPolicy
;
96 if (parent
->GetClientInfo().isSome() &&
97 parent
->GetClientInfo()->AgentClusterId().isSome() &&
98 parent
->GetClientInfo()->AgentClusterId()->Equals(
99 aWorkerPrivate
->AgentClusterId())) {
100 cloneDataPolicy
.allowIntraClusterClonableSharedObjects();
103 if (aWorkerPrivate
->IsSharedMemoryAllowed()) {
104 cloneDataPolicy
.allowSharedMemoryObjects();
107 Read(parent
, aCx
, &options
, cloneDataPolicy
, rv
);
109 if (NS_WARN_IF(rv
.Failed())) {
110 OptionsDeserializeFailed(rv
);
114 Sequence
<OwningNonNull
<MessagePort
>> ports
;
115 if (NS_WARN_IF(!TakeTransferredPortsAsSequence(ports
))) {
116 // TODO: Is this an appropriate type? What does this actually do?
117 rv
.ThrowDataCloneError("TakeTransferredPortsAsSequence failed");
118 OptionsDeserializeFailed(rv
);
122 RefPtr
<dom::Event
> event
= BuildEvent(aCx
, parent
, aTarget
, options
);
124 if (NS_WARN_IF(!event
)) {
128 aTarget
->DispatchEvent(*event
);
132 bool EventWithOptionsRunnable::WorkerRun(JSContext
* aCx
,
133 WorkerPrivate
* aWorkerPrivate
) {
134 MOZ_ASSERT(aWorkerPrivate
== GetWorkerPrivateFromContext(aCx
));
135 MOZ_ASSERT(aWorkerPrivate
->GlobalScope());
137 // If the worker start shutting down, don't dispatch the event.
139 aWorkerPrivate
->GlobalScope()->CheckCurrentGlobalCorrectness())) {
143 return BuildAndFireEvent(aCx
, aWorkerPrivate
, aWorkerPrivate
->GlobalScope());
146 } // namespace mozilla::dom