1 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
4 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "MessagePort.h"
8 #include "mozilla/dom/MessagePortBinding.h"
9 #include "nsDOMEvent.h"
10 #include "nsEventDispatcher.h"
12 #include "SharedWorker.h"
13 #include "WorkerPrivate.h"
15 using mozilla::dom::EventHandlerNonNull
;
16 using mozilla::dom::MessagePortBase
;
17 using mozilla::dom::Optional
;
18 using mozilla::dom::Sequence
;
20 USING_WORKERS_NAMESPACE
24 class DelayedEventRunnable MOZ_FINAL
: public WorkerRunnable
26 nsRefPtr
<MessagePort
> mMessagePort
;
27 nsTArray
<nsCOMPtr
<nsIDOMEvent
>> mEvents
;
30 DelayedEventRunnable(WorkerPrivate
* aWorkerPrivate
,
32 MessagePort
* aMessagePort
,
33 nsTArray
<nsCOMPtr
<nsIDOMEvent
>>& aEvents
)
34 : WorkerRunnable(aWorkerPrivate
, aTarget
,
35 aTarget
== WorkerThread
? ModifyBusyCount
: UnchangedBusyCount
,
37 mMessagePort(aMessagePort
)
39 AssertIsOnMainThread();
40 MOZ_ASSERT(aMessagePort
);
41 MOZ_ASSERT(aEvents
.Length());
43 mEvents
.SwapElements(aEvents
);
47 WorkerRun(JSContext
* aCx
, WorkerPrivate
* aWorkerPrivate
);
50 } // anonymous namespace
52 MessagePort::MessagePort(nsPIDOMWindow
* aWindow
, SharedWorker
* aSharedWorker
,
54 : MessagePortBase(aWindow
), mSharedWorker(aSharedWorker
),
55 mWorkerPrivate(nullptr), mSerial(aSerial
), mStarted(false)
57 AssertIsOnMainThread();
58 MOZ_ASSERT(aSharedWorker
);
62 MessagePort::MessagePort(WorkerPrivate
* aWorkerPrivate
, uint64_t aSerial
)
63 : mWorkerPrivate(aWorkerPrivate
), mSerial(aSerial
), mStarted(false)
65 aWorkerPrivate
->AssertIsOnWorkerThread();
69 MessagePort::~MessagePort()
75 MessagePort::PostMessageMoz(JSContext
* aCx
, JS::Handle
<JS::Value
> aMessage
,
76 const Optional
<Sequence
<JS::Value
>>& aTransferable
,
79 AssertCorrectThread();
82 aRv
= NS_ERROR_DOM_INVALID_STATE_ERR
;
87 mSharedWorker
->PostMessage(aCx
, aMessage
, aTransferable
, aRv
);
90 mWorkerPrivate
->PostMessageToParentMessagePort(aCx
, Serial(), aMessage
,
98 AssertCorrectThread();
101 NS_WARNING("Called start() after calling close()!");
111 if (!mQueuedEvents
.IsEmpty()) {
112 WorkerRunnable::Target target
= WorkerRunnable::WorkerThread
;
113 WorkerPrivate
* workerPrivate
= mWorkerPrivate
;
115 if (!workerPrivate
) {
116 target
= WorkerRunnable::ParentThread
;
117 workerPrivate
= mSharedWorker
->GetWorkerPrivate();
120 nsRefPtr
<DelayedEventRunnable
> runnable
=
121 new DelayedEventRunnable(workerPrivate
, target
, this, mQueuedEvents
);
122 runnable
->Dispatch(nullptr);
129 AssertCorrectThread();
137 MessagePort::QueueEvent(nsIDOMEvent
* aEvent
)
139 AssertCorrectThread();
141 MOZ_ASSERT(!IsClosed());
142 MOZ_ASSERT(!mStarted
);
144 mQueuedEvents
.AppendElement(aEvent
);
148 MessagePort::GetOnmessage()
150 AssertCorrectThread();
152 return NS_IsMainThread() ? GetEventHandler(nsGkAtoms::onmessage
, EmptyString())
153 : GetEventHandler(nullptr, NS_LITERAL_STRING("message"));
157 MessagePort::SetOnmessage(EventHandlerNonNull
* aCallback
)
159 AssertCorrectThread();
161 if (NS_IsMainThread()) {
162 SetEventHandler(nsGkAtoms::onmessage
, EmptyString(), aCallback
);
165 SetEventHandler(nullptr, NS_LITERAL_STRING("message"), aCallback
);
171 already_AddRefed
<MessagePortBase
>
174 NS_WARNING("Haven't implemented structured clone for these ports yet!");
179 MessagePort::CloseInternal()
181 AssertCorrectThread();
182 MOZ_ASSERT(!IsClosed());
183 MOZ_ASSERT_IF(mStarted
, mQueuedEvents
.IsEmpty());
185 NS_WARN_IF_FALSE(mStarted
, "Called close() before start()!");
188 mQueuedEvents
.Clear();
191 mSharedWorker
= nullptr;
192 mWorkerPrivate
= nullptr;
197 MessagePort::AssertCorrectThread() const
200 return; // Can't assert anything if we nulled out our pointers.
203 MOZ_ASSERT((mSharedWorker
|| mWorkerPrivate
) &&
204 !(mSharedWorker
&& mWorkerPrivate
));
207 AssertIsOnMainThread();
210 mWorkerPrivate
->AssertIsOnWorkerThread();
215 NS_IMPL_ADDREF_INHERITED(MessagePort
, nsDOMEventTargetHelper
)
216 NS_IMPL_RELEASE_INHERITED(MessagePort
, nsDOMEventTargetHelper
)
218 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(MessagePort
)
219 NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper
)
221 NS_IMPL_CYCLE_COLLECTION_CLASS(MessagePort
)
223 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(MessagePort
,
224 nsDOMEventTargetHelper
)
225 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSharedWorker
)
226 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mQueuedEvents
)
227 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
229 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(MessagePort
,
230 nsDOMEventTargetHelper
)
232 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
235 MessagePort::WrapObject(JSContext
* aCx
, JS::Handle
<JSObject
*> aScope
)
237 AssertCorrectThread();
239 return MessagePortBinding::Wrap(aCx
, aScope
, this);
243 MessagePort::PreHandleEvent(nsEventChainPreVisitor
& aVisitor
)
245 AssertCorrectThread();
247 nsIDOMEvent
*& event
= aVisitor
.mDOMEvent
;
250 bool preventDispatch
= false;
253 preventDispatch
= true;
254 } else if (NS_IsMainThread() && mSharedWorker
->IsSuspended()) {
255 mSharedWorker
->QueueEvent(event
);
256 preventDispatch
= true;
257 } else if (!mStarted
) {
259 preventDispatch
= true;
262 if (preventDispatch
) {
263 aVisitor
.mCanHandle
= false;
264 aVisitor
.mParentTarget
= nullptr;
269 return nsDOMEventTargetHelper::PreHandleEvent(aVisitor
);
273 DelayedEventRunnable::WorkerRun(JSContext
* aCx
, WorkerPrivate
* aWorkerPrivate
)
275 MOZ_ASSERT(mMessagePort
);
276 mMessagePort
->AssertCorrectThread();
277 MOZ_ASSERT(mEvents
.Length());
280 for (uint32_t i
= 0; i
< mEvents
.Length(); i
++) {
281 mMessagePort
->DispatchEvent(mEvents
[i
], &ignored
);