/src/mozilla-central/dom/workers/MessageEventRunnable.cpp
Line | Count | Source (jump to first uncovered line) |
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/. */ |
6 | | |
7 | | #include "MessageEventRunnable.h" |
8 | | |
9 | | #include "mozilla/dom/MessageEvent.h" |
10 | | #include "mozilla/dom/MessageEventBinding.h" |
11 | | #include "mozilla/TimelineConsumers.h" |
12 | | #include "mozilla/WorkerTimelineMarker.h" |
13 | | #include "nsQueryObject.h" |
14 | | #include "WorkerPrivate.h" |
15 | | #include "WorkerScope.h" |
16 | | |
17 | | namespace mozilla { |
18 | | namespace dom { |
19 | | |
20 | | MessageEventRunnable::MessageEventRunnable(WorkerPrivate* aWorkerPrivate, |
21 | | TargetAndBusyBehavior aBehavior) |
22 | | : WorkerRunnable(aWorkerPrivate, aBehavior) |
23 | | , StructuredCloneHolder(CloningSupported, TransferringSupported, |
24 | | StructuredCloneScope::SameProcessDifferentThread) |
25 | 0 | { |
26 | 0 | } |
27 | | |
28 | | bool |
29 | | MessageEventRunnable::DispatchDOMEvent(JSContext* aCx, |
30 | | WorkerPrivate* aWorkerPrivate, |
31 | | DOMEventTargetHelper* aTarget, |
32 | | bool aIsMainThread) |
33 | 0 | { |
34 | 0 | nsCOMPtr<nsIGlobalObject> parent = do_QueryInterface(aTarget->GetParentObject()); |
35 | 0 |
|
36 | 0 | // For some workers without window, parent is null and we try to find it |
37 | 0 | // from the JS Context. |
38 | 0 | if (!parent) { |
39 | 0 | JS::Rooted<JSObject*> globalObject(aCx, JS::CurrentGlobalOrNull(aCx)); |
40 | 0 | if (NS_WARN_IF(!globalObject)) { |
41 | 0 | return false; |
42 | 0 | } |
43 | 0 | |
44 | 0 | parent = xpc::NativeGlobal(globalObject); |
45 | 0 | if (NS_WARN_IF(!parent)) { |
46 | 0 | return false; |
47 | 0 | } |
48 | 0 | } |
49 | 0 | |
50 | 0 | MOZ_ASSERT(parent); |
51 | 0 |
|
52 | 0 | JS::Rooted<JS::Value> messageData(aCx); |
53 | 0 | IgnoredErrorResult rv; |
54 | 0 |
|
55 | 0 | UniquePtr<AbstractTimelineMarker> start; |
56 | 0 | UniquePtr<AbstractTimelineMarker> end; |
57 | 0 | RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get(); |
58 | 0 | bool isTimelineRecording = timelines && !timelines->IsEmpty(); |
59 | 0 |
|
60 | 0 | if (isTimelineRecording) { |
61 | 0 | start = MakeUnique<WorkerTimelineMarker>(aIsMainThread |
62 | 0 | ? ProfileTimelineWorkerOperationType::DeserializeDataOnMainThread |
63 | 0 | : ProfileTimelineWorkerOperationType::DeserializeDataOffMainThread, |
64 | 0 | MarkerTracingType::START); |
65 | 0 | } |
66 | 0 |
|
67 | 0 | Read(parent, aCx, &messageData, rv); |
68 | 0 |
|
69 | 0 | if (isTimelineRecording) { |
70 | 0 | end = MakeUnique<WorkerTimelineMarker>(aIsMainThread |
71 | 0 | ? ProfileTimelineWorkerOperationType::DeserializeDataOnMainThread |
72 | 0 | : ProfileTimelineWorkerOperationType::DeserializeDataOffMainThread, |
73 | 0 | MarkerTracingType::END); |
74 | 0 | timelines->AddMarkerForAllObservedDocShells(start); |
75 | 0 | timelines->AddMarkerForAllObservedDocShells(end); |
76 | 0 | } |
77 | 0 |
|
78 | 0 | if (NS_WARN_IF(rv.Failed())) { |
79 | 0 | DispatchError(aCx, aTarget); |
80 | 0 | return false; |
81 | 0 | } |
82 | 0 | |
83 | 0 | Sequence<OwningNonNull<MessagePort>> ports; |
84 | 0 | if (!TakeTransferredPortsAsSequence(ports)) { |
85 | 0 | DispatchError(aCx, aTarget); |
86 | 0 | return false; |
87 | 0 | } |
88 | 0 | |
89 | 0 | RefPtr<MessageEvent> event = new MessageEvent(aTarget, nullptr, nullptr); |
90 | 0 | event->InitMessageEvent(nullptr, |
91 | 0 | NS_LITERAL_STRING("message"), |
92 | 0 | CanBubble::eNo, |
93 | 0 | Cancelable::eNo, |
94 | 0 | messageData, |
95 | 0 | EmptyString(), |
96 | 0 | EmptyString(), |
97 | 0 | nullptr, |
98 | 0 | ports); |
99 | 0 |
|
100 | 0 | event->SetTrusted(true); |
101 | 0 |
|
102 | 0 | aTarget->DispatchEvent(*event); |
103 | 0 |
|
104 | 0 | return true; |
105 | 0 | } |
106 | | |
107 | | bool |
108 | | MessageEventRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) |
109 | 0 | { |
110 | 0 | if (mBehavior == ParentThreadUnchangedBusyCount) { |
111 | 0 | // Don't fire this event if the JS object has been disconnected from the |
112 | 0 | // private object. |
113 | 0 | if (!aWorkerPrivate->IsAcceptingEvents()) { |
114 | 0 | return true; |
115 | 0 | } |
116 | 0 | |
117 | 0 | if (aWorkerPrivate->IsFrozen() || |
118 | 0 | aWorkerPrivate->IsParentWindowPaused()) { |
119 | 0 | MOZ_ASSERT(!IsDebuggerRunnable()); |
120 | 0 | aWorkerPrivate->QueueRunnable(this); |
121 | 0 | return true; |
122 | 0 | } |
123 | 0 |
|
124 | 0 | aWorkerPrivate->AssertInnerWindowIsCorrect(); |
125 | 0 |
|
126 | 0 | return DispatchDOMEvent(aCx, aWorkerPrivate, |
127 | 0 | aWorkerPrivate->ParentEventTargetRef(), |
128 | 0 | !aWorkerPrivate->GetParent()); |
129 | 0 | } |
130 | 0 | |
131 | 0 | MOZ_ASSERT(aWorkerPrivate == GetWorkerPrivateFromContext(aCx)); |
132 | 0 |
|
133 | 0 | return DispatchDOMEvent(aCx, aWorkerPrivate, aWorkerPrivate->GlobalScope(), |
134 | 0 | false); |
135 | 0 | } |
136 | | |
137 | | void |
138 | | MessageEventRunnable::DispatchError(JSContext* aCx, |
139 | | DOMEventTargetHelper* aTarget) |
140 | 0 | { |
141 | 0 | RootedDictionary<MessageEventInit> init(aCx); |
142 | 0 | init.mBubbles = false; |
143 | 0 | init.mCancelable = false; |
144 | 0 |
|
145 | 0 | RefPtr<Event> event = |
146 | 0 | MessageEvent::Constructor(aTarget, NS_LITERAL_STRING("messageerror"), init); |
147 | 0 | event->SetTrusted(true); |
148 | 0 |
|
149 | 0 | aTarget->DispatchEvent(*event); |
150 | 0 | } |
151 | | |
152 | | } // dom namespace |
153 | | } // mozilla namespace |