Bug 1732219 - Add API for fetching the preview image. r=geckoview-reviewers,agi,mconley
[gecko.git] / dom / workers / Worker.cpp
blob042c5d3fbe12ef4d66dfea3c8d589da06dbac4c8
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=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 http://mozilla.org/MPL/2.0/. */
7 #include "Worker.h"
9 #include "MessageEventRunnable.h"
10 #include "mozilla/dom/WorkerBinding.h"
11 #include "mozilla/ProfilerLabels.h"
12 #include "mozilla/ProfilerMarkers.h"
13 #include "mozilla/TimelineConsumers.h"
14 #include "mozilla/Unused.h"
15 #include "mozilla/WorkerTimelineMarker.h"
16 #include "nsContentUtils.h"
17 #include "nsGlobalWindowOuter.h"
18 #include "WorkerPrivate.h"
20 #ifdef XP_WIN
21 # undef PostMessage
22 #endif
24 namespace mozilla {
25 namespace dom {
27 /* static */
28 already_AddRefed<Worker> Worker::Constructor(const GlobalObject& aGlobal,
29 const nsAString& aScriptURL,
30 const WorkerOptions& aOptions,
31 ErrorResult& aRv) {
32 JSContext* cx = aGlobal.Context();
34 nsCOMPtr<nsIGlobalObject> globalObject =
35 do_QueryInterface(aGlobal.GetAsSupports());
37 if (globalObject->AsInnerWindow() &&
38 !globalObject->AsInnerWindow()->IsCurrentInnerWindow()) {
39 aRv.ThrowInvalidStateError(
40 "Cannot create worker for a going to be discarded document");
41 return nullptr;
44 RefPtr<WorkerPrivate> workerPrivate = WorkerPrivate::Constructor(
45 cx, aScriptURL, false /* aIsChromeWorker */, WorkerKindDedicated,
46 aOptions.mName, VoidCString(), nullptr /*aLoadInfo */, aRv);
47 if (NS_WARN_IF(aRv.Failed())) {
48 return nullptr;
51 RefPtr<Worker> worker = new Worker(globalObject, workerPrivate.forget());
52 return worker.forget();
55 Worker::Worker(nsIGlobalObject* aGlobalObject,
56 already_AddRefed<WorkerPrivate> aWorkerPrivate)
57 : DOMEventTargetHelper(aGlobalObject),
58 mWorkerPrivate(std::move(aWorkerPrivate)) {
59 MOZ_ASSERT(mWorkerPrivate);
60 mWorkerPrivate->SetParentEventTargetRef(this);
63 Worker::~Worker() { Terminate(); }
65 JSObject* Worker::WrapObject(JSContext* aCx,
66 JS::Handle<JSObject*> aGivenProto) {
67 JS::Rooted<JSObject*> wrapper(aCx,
68 Worker_Binding::Wrap(aCx, this, aGivenProto));
69 if (wrapper) {
70 // Most DOM objects don't assume they have a reflector. If they don't have
71 // one and need one, they create it. But in workers code, we assume that the
72 // reflector is always present. In order to guarantee that it's always
73 // present, we have to preserve it. Otherwise the GC will happily collect it
74 // as needed.
75 MOZ_ALWAYS_TRUE(TryPreserveWrapper(wrapper));
78 return wrapper;
81 void Worker::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
82 const Sequence<JSObject*>& aTransferable,
83 ErrorResult& aRv) {
84 NS_ASSERT_OWNINGTHREAD(Worker);
86 if (!mWorkerPrivate || mWorkerPrivate->ParentStatusProtected() > Running) {
87 return;
90 JS::Rooted<JS::Value> transferable(aCx, JS::UndefinedValue());
92 aRv = nsContentUtils::CreateJSValueFromSequenceOfObject(aCx, aTransferable,
93 &transferable);
94 if (NS_WARN_IF(aRv.Failed())) {
95 return;
98 NS_ConvertUTF16toUTF8 nameOrScriptURL(mWorkerPrivate->WorkerName().IsEmpty()
99 ? mWorkerPrivate->ScriptURL()
100 : mWorkerPrivate->WorkerName());
101 AUTO_PROFILER_MARKER_TEXT("Worker.postMessage", DOM, {}, nameOrScriptURL);
102 uint32_t flags = uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS);
103 if (mWorkerPrivate->IsChromeWorker()) {
104 flags |= uint32_t(js::ProfilingStackFrame::Flags::NONSENSITIVE);
106 mozilla::AutoProfilerLabel PROFILER_RAII(
107 "Worker.postMessage", nameOrScriptURL.get(),
108 JS::ProfilingCategoryPair::DOM, flags);
110 RefPtr<MessageEventRunnable> runnable = new MessageEventRunnable(
111 mWorkerPrivate, WorkerRunnable::WorkerThreadModifyBusyCount);
113 UniquePtr<AbstractTimelineMarker> start;
114 UniquePtr<AbstractTimelineMarker> end;
115 RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
116 bool isTimelineRecording = timelines && !timelines->IsEmpty();
118 if (isTimelineRecording) {
119 start = MakeUnique<WorkerTimelineMarker>(
120 NS_IsMainThread()
121 ? ProfileTimelineWorkerOperationType::SerializeDataOnMainThread
122 : ProfileTimelineWorkerOperationType::SerializeDataOffMainThread,
123 MarkerTracingType::START);
126 JS::CloneDataPolicy clonePolicy;
127 // DedicatedWorkers are always part of the same agent cluster.
128 clonePolicy.allowIntraClusterClonableSharedObjects();
130 if (NS_IsMainThread()) {
131 nsGlobalWindowInner* win = nsContentUtils::CallerInnerWindow();
132 if (win && win->IsSharedMemoryAllowed()) {
133 clonePolicy.allowSharedMemoryObjects();
135 } else {
136 WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
137 if (worker && worker->IsSharedMemoryAllowed()) {
138 clonePolicy.allowSharedMemoryObjects();
142 runnable->Write(aCx, aMessage, transferable, clonePolicy, aRv);
144 if (isTimelineRecording) {
145 end = MakeUnique<WorkerTimelineMarker>(
146 NS_IsMainThread()
147 ? ProfileTimelineWorkerOperationType::SerializeDataOnMainThread
148 : ProfileTimelineWorkerOperationType::SerializeDataOffMainThread,
149 MarkerTracingType::END);
150 timelines->AddMarkerForAllObservedDocShells(start);
151 timelines->AddMarkerForAllObservedDocShells(end);
154 if (NS_WARN_IF(aRv.Failed())) {
155 return;
158 // The worker could have closed between the time we entered this function and
159 // checked ParentStatusProtected and now, which could cause the dispatch to
160 // fail.
161 Unused << NS_WARN_IF(!runnable->Dispatch());
164 void Worker::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
165 const StructuredSerializeOptions& aOptions,
166 ErrorResult& aRv) {
167 PostMessage(aCx, aMessage, aOptions.mTransfer, aRv);
170 void Worker::Terminate() {
171 NS_ASSERT_OWNINGTHREAD(Worker);
173 if (mWorkerPrivate) {
174 mWorkerPrivate->Cancel();
175 mWorkerPrivate = nullptr;
179 NS_IMPL_CYCLE_COLLECTION_CLASS(Worker)
181 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(Worker, DOMEventTargetHelper)
182 if (tmp->mWorkerPrivate) {
183 tmp->mWorkerPrivate->Traverse(cb);
185 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
187 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(Worker, DOMEventTargetHelper)
188 tmp->Terminate();
189 NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_PTR
190 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
192 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(Worker, DOMEventTargetHelper)
193 NS_IMPL_CYCLE_COLLECTION_TRACE_END
195 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Worker)
196 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
198 NS_IMPL_ADDREF_INHERITED(Worker, DOMEventTargetHelper)
199 NS_IMPL_RELEASE_INHERITED(Worker, DOMEventTargetHelper)
201 } // namespace dom
202 } // namespace mozilla