|
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/. */ |
|
5 |
|
6 #include "SharedWorker.h" |
|
7 |
|
8 #include "nsPIDOMWindow.h" |
|
9 |
|
10 #include "mozilla/EventDispatcher.h" |
|
11 #include "mozilla/Preferences.h" |
|
12 #include "mozilla/dom/SharedWorkerBinding.h" |
|
13 #include "nsContentUtils.h" |
|
14 #include "nsIClassInfoImpl.h" |
|
15 #include "nsIDOMEvent.h" |
|
16 |
|
17 #include "MessagePort.h" |
|
18 #include "RuntimeService.h" |
|
19 #include "WorkerPrivate.h" |
|
20 |
|
21 using mozilla::dom::Optional; |
|
22 using mozilla::dom::Sequence; |
|
23 using namespace mozilla; |
|
24 |
|
25 USING_WORKERS_NAMESPACE |
|
26 |
|
27 SharedWorker::SharedWorker(nsPIDOMWindow* aWindow, |
|
28 WorkerPrivate* aWorkerPrivate) |
|
29 : DOMEventTargetHelper(aWindow), mWorkerPrivate(aWorkerPrivate), |
|
30 mSuspended(false) |
|
31 { |
|
32 AssertIsOnMainThread(); |
|
33 MOZ_ASSERT(aWorkerPrivate); |
|
34 |
|
35 mSerial = aWorkerPrivate->NextMessagePortSerial(); |
|
36 |
|
37 mMessagePort = new MessagePort(aWindow, this, mSerial); |
|
38 } |
|
39 |
|
40 SharedWorker::~SharedWorker() |
|
41 { |
|
42 AssertIsOnMainThread(); |
|
43 Close(); |
|
44 MOZ_ASSERT(!mWorkerPrivate); |
|
45 } |
|
46 |
|
47 // static |
|
48 already_AddRefed<SharedWorker> |
|
49 SharedWorker::Constructor(const GlobalObject& aGlobal, JSContext* aCx, |
|
50 const nsAString& aScriptURL, |
|
51 const mozilla::dom::Optional<nsAString>& aName, |
|
52 ErrorResult& aRv) |
|
53 { |
|
54 AssertIsOnMainThread(); |
|
55 |
|
56 RuntimeService* rts = RuntimeService::GetOrCreateService(); |
|
57 if (!rts) { |
|
58 aRv = NS_ERROR_NOT_AVAILABLE; |
|
59 return nullptr; |
|
60 } |
|
61 |
|
62 nsCString name; |
|
63 if (aName.WasPassed()) { |
|
64 name = NS_ConvertUTF16toUTF8(aName.Value()); |
|
65 } |
|
66 |
|
67 nsRefPtr<SharedWorker> sharedWorker; |
|
68 nsresult rv = rts->CreateSharedWorker(aGlobal, aScriptURL, name, |
|
69 getter_AddRefs(sharedWorker)); |
|
70 if (NS_FAILED(rv)) { |
|
71 aRv = rv; |
|
72 return nullptr; |
|
73 } |
|
74 |
|
75 return sharedWorker.forget(); |
|
76 } |
|
77 |
|
78 already_AddRefed<MessagePort> |
|
79 SharedWorker::Port() |
|
80 { |
|
81 AssertIsOnMainThread(); |
|
82 |
|
83 nsRefPtr<MessagePort> messagePort = mMessagePort; |
|
84 return messagePort.forget(); |
|
85 } |
|
86 |
|
87 void |
|
88 SharedWorker::Suspend() |
|
89 { |
|
90 AssertIsOnMainThread(); |
|
91 MOZ_ASSERT(!IsSuspended()); |
|
92 |
|
93 mSuspended = true; |
|
94 } |
|
95 |
|
96 void |
|
97 SharedWorker::Resume() |
|
98 { |
|
99 AssertIsOnMainThread(); |
|
100 MOZ_ASSERT(IsSuspended()); |
|
101 |
|
102 mSuspended = false; |
|
103 |
|
104 if (!mSuspendedEvents.IsEmpty()) { |
|
105 nsTArray<nsCOMPtr<nsIDOMEvent>> events; |
|
106 mSuspendedEvents.SwapElements(events); |
|
107 |
|
108 for (uint32_t index = 0; index < events.Length(); index++) { |
|
109 nsCOMPtr<nsIDOMEvent>& event = events[index]; |
|
110 MOZ_ASSERT(event); |
|
111 |
|
112 nsCOMPtr<nsIDOMEventTarget> target; |
|
113 if (NS_SUCCEEDED(event->GetTarget(getter_AddRefs(target)))) { |
|
114 bool ignored; |
|
115 if (NS_FAILED(target->DispatchEvent(event, &ignored))) { |
|
116 NS_WARNING("Failed to dispatch event!"); |
|
117 } |
|
118 } else { |
|
119 NS_WARNING("Failed to get target!"); |
|
120 } |
|
121 } |
|
122 } |
|
123 } |
|
124 |
|
125 void |
|
126 SharedWorker::QueueEvent(nsIDOMEvent* aEvent) |
|
127 { |
|
128 AssertIsOnMainThread(); |
|
129 MOZ_ASSERT(aEvent); |
|
130 MOZ_ASSERT(IsSuspended()); |
|
131 |
|
132 mSuspendedEvents.AppendElement(aEvent); |
|
133 } |
|
134 |
|
135 void |
|
136 SharedWorker::Close() |
|
137 { |
|
138 AssertIsOnMainThread(); |
|
139 |
|
140 if (mMessagePort) { |
|
141 mMessagePort->Close(); |
|
142 } |
|
143 |
|
144 if (mWorkerPrivate) { |
|
145 AutoSafeJSContext cx; |
|
146 NoteDeadWorker(cx); |
|
147 } |
|
148 } |
|
149 |
|
150 void |
|
151 SharedWorker::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage, |
|
152 const Optional<Sequence<JS::Value>>& aTransferable, |
|
153 ErrorResult& aRv) |
|
154 { |
|
155 AssertIsOnMainThread(); |
|
156 MOZ_ASSERT(mWorkerPrivate); |
|
157 MOZ_ASSERT(mMessagePort); |
|
158 |
|
159 mWorkerPrivate->PostMessageToMessagePort(aCx, mMessagePort->Serial(), |
|
160 aMessage, aTransferable, aRv); |
|
161 } |
|
162 |
|
163 void |
|
164 SharedWorker::NoteDeadWorker(JSContext* aCx) |
|
165 { |
|
166 AssertIsOnMainThread(); |
|
167 MOZ_ASSERT(mWorkerPrivate); |
|
168 |
|
169 mWorkerPrivate->UnregisterSharedWorker(aCx, this); |
|
170 mWorkerPrivate = nullptr; |
|
171 } |
|
172 |
|
173 NS_IMPL_ADDREF_INHERITED(SharedWorker, DOMEventTargetHelper) |
|
174 NS_IMPL_RELEASE_INHERITED(SharedWorker, DOMEventTargetHelper) |
|
175 |
|
176 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(SharedWorker) |
|
177 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) |
|
178 |
|
179 NS_IMPL_CYCLE_COLLECTION_CLASS(SharedWorker) |
|
180 |
|
181 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(SharedWorker, |
|
182 DOMEventTargetHelper) |
|
183 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessagePort) |
|
184 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSuspendedEvents) |
|
185 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END |
|
186 |
|
187 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(SharedWorker, |
|
188 DOMEventTargetHelper) |
|
189 tmp->Close(); |
|
190 NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessagePort) |
|
191 NS_IMPL_CYCLE_COLLECTION_UNLINK(mSuspendedEvents) |
|
192 NS_IMPL_CYCLE_COLLECTION_UNLINK_END |
|
193 |
|
194 JSObject* |
|
195 SharedWorker::WrapObject(JSContext* aCx) |
|
196 { |
|
197 AssertIsOnMainThread(); |
|
198 |
|
199 return SharedWorkerBinding::Wrap(aCx, this); |
|
200 } |
|
201 |
|
202 nsresult |
|
203 SharedWorker::PreHandleEvent(EventChainPreVisitor& aVisitor) |
|
204 { |
|
205 AssertIsOnMainThread(); |
|
206 |
|
207 nsIDOMEvent*& event = aVisitor.mDOMEvent; |
|
208 |
|
209 if (IsSuspended() && event) { |
|
210 QueueEvent(event); |
|
211 |
|
212 aVisitor.mCanHandle = false; |
|
213 aVisitor.mParentTarget = nullptr; |
|
214 return NS_OK; |
|
215 } |
|
216 |
|
217 return DOMEventTargetHelper::PreHandleEvent(aVisitor); |
|
218 } |