dom/events/DOMEventTargetHelper.cpp

branch
TOR_BUG_9701
changeset 8
97036ab72558
equal deleted inserted replaced
-1:000000000000 0:8bc827b36b2a
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
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
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #include "nsContentUtils.h"
7 #include "nsIDocument.h"
8 #include "prprf.h"
9 #include "nsGlobalWindow.h"
10 #include "ScriptSettings.h"
11 #include "mozilla/DOMEventTargetHelper.h"
12 #include "mozilla/EventDispatcher.h"
13 #include "mozilla/EventListenerManager.h"
14 #include "mozilla/Likely.h"
15
16 namespace mozilla {
17
18 using namespace dom;
19
20 NS_IMPL_CYCLE_COLLECTION_CLASS(DOMEventTargetHelper)
21
22 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(DOMEventTargetHelper)
23 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
24 NS_IMPL_CYCLE_COLLECTION_TRACE_END
25
26 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(DOMEventTargetHelper)
27 if (MOZ_UNLIKELY(cb.WantDebugInfo())) {
28 char name[512];
29 nsAutoString uri;
30 if (tmp->mOwnerWindow && tmp->mOwnerWindow->GetExtantDoc()) {
31 tmp->mOwnerWindow->GetExtantDoc()->GetDocumentURI(uri);
32 }
33 PR_snprintf(name, sizeof(name), "DOMEventTargetHelper %s",
34 NS_ConvertUTF16toUTF8(uri).get());
35 cb.DescribeRefCountedNode(tmp->mRefCnt.get(), name);
36 } else {
37 NS_IMPL_CYCLE_COLLECTION_DESCRIBE(DOMEventTargetHelper, tmp->mRefCnt.get())
38 }
39
40 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
41 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mListenerManager)
42 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
43
44 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMEventTargetHelper)
45 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
46 NS_IMPL_CYCLE_COLLECTION_UNLINK(mListenerManager)
47 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
48
49 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(DOMEventTargetHelper)
50 if (tmp->IsBlack()) {
51 if (tmp->mListenerManager) {
52 tmp->mListenerManager->MarkForCC();
53 }
54 return true;
55 }
56 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
57
58 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(DOMEventTargetHelper)
59 return tmp->IsBlackAndDoesNotNeedTracing(tmp);
60 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
61
62 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(DOMEventTargetHelper)
63 return tmp->IsBlack();
64 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
65
66 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMEventTargetHelper)
67 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
68 NS_INTERFACE_MAP_ENTRY(nsISupports)
69 NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
70 NS_INTERFACE_MAP_ENTRY(dom::EventTarget)
71 NS_INTERFACE_MAP_ENTRY(DOMEventTargetHelper)
72 NS_INTERFACE_MAP_END
73
74 NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMEventTargetHelper)
75 NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(DOMEventTargetHelper,
76 LastRelease())
77
78 NS_IMPL_DOMTARGET_DEFAULTS(DOMEventTargetHelper)
79
80 DOMEventTargetHelper::~DOMEventTargetHelper()
81 {
82 if (nsPIDOMWindow* owner = GetOwner()) {
83 static_cast<nsGlobalWindow*>(owner)->RemoveEventTargetObject(this);
84 }
85 if (mListenerManager) {
86 mListenerManager->Disconnect();
87 }
88 ReleaseWrapper(this);
89 }
90
91 void
92 DOMEventTargetHelper::BindToOwner(nsPIDOMWindow* aOwner)
93 {
94 MOZ_ASSERT(!aOwner || aOwner->IsInnerWindow());
95 nsCOMPtr<nsIGlobalObject> glob = do_QueryInterface(aOwner);
96 BindToOwner(glob);
97 }
98
99 void
100 DOMEventTargetHelper::BindToOwner(nsIGlobalObject* aOwner)
101 {
102 if (mParentObject) {
103 if (mOwnerWindow) {
104 static_cast<nsGlobalWindow*>(mOwnerWindow)->RemoveEventTargetObject(this);
105 mOwnerWindow = nullptr;
106 }
107 mParentObject = nullptr;
108 mHasOrHasHadOwnerWindow = false;
109 }
110 if (aOwner) {
111 mParentObject = aOwner;
112 // Let's cache the result of this QI for fast access and off main thread usage
113 mOwnerWindow = nsCOMPtr<nsPIDOMWindow>(do_QueryInterface(aOwner)).get();
114 if (mOwnerWindow) {
115 mHasOrHasHadOwnerWindow = true;
116 static_cast<nsGlobalWindow*>(mOwnerWindow)->AddEventTargetObject(this);
117 }
118 }
119 }
120
121 void
122 DOMEventTargetHelper::BindToOwner(DOMEventTargetHelper* aOther)
123 {
124 if (mOwnerWindow) {
125 static_cast<nsGlobalWindow*>(mOwnerWindow)->RemoveEventTargetObject(this);
126 mOwnerWindow = nullptr;
127 mParentObject = nullptr;
128 mHasOrHasHadOwnerWindow = false;
129 }
130 if (aOther) {
131 mHasOrHasHadOwnerWindow = aOther->HasOrHasHadOwner();
132 if (aOther->GetParentObject()) {
133 mParentObject = aOther->GetParentObject();
134 // Let's cache the result of this QI for fast access and off main thread usage
135 mOwnerWindow = nsCOMPtr<nsPIDOMWindow>(do_QueryInterface(mParentObject)).get();
136 if (mOwnerWindow) {
137 mHasOrHasHadOwnerWindow = true;
138 static_cast<nsGlobalWindow*>(mOwnerWindow)->AddEventTargetObject(this);
139 }
140 }
141 }
142 }
143
144 void
145 DOMEventTargetHelper::DisconnectFromOwner()
146 {
147 mOwnerWindow = nullptr;
148 mParentObject = nullptr;
149 // Event listeners can't be handled anymore, so we can release them here.
150 if (mListenerManager) {
151 mListenerManager->Disconnect();
152 mListenerManager = nullptr;
153 }
154 }
155
156 NS_IMETHODIMP
157 DOMEventTargetHelper::RemoveEventListener(const nsAString& aType,
158 nsIDOMEventListener* aListener,
159 bool aUseCapture)
160 {
161 EventListenerManager* elm = GetExistingListenerManager();
162 if (elm) {
163 elm->RemoveEventListener(aType, aListener, aUseCapture);
164 }
165
166 return NS_OK;
167 }
168
169 NS_IMPL_REMOVE_SYSTEM_EVENT_LISTENER(DOMEventTargetHelper)
170
171 NS_IMETHODIMP
172 DOMEventTargetHelper::AddEventListener(const nsAString& aType,
173 nsIDOMEventListener* aListener,
174 bool aUseCapture,
175 bool aWantsUntrusted,
176 uint8_t aOptionalArgc)
177 {
178 NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1,
179 "Won't check if this is chrome, you want to set "
180 "aWantsUntrusted to false or make the aWantsUntrusted "
181 "explicit by making aOptionalArgc non-zero.");
182
183 if (aOptionalArgc < 2) {
184 nsresult rv = WantsUntrusted(&aWantsUntrusted);
185 NS_ENSURE_SUCCESS(rv, rv);
186 }
187
188 EventListenerManager* elm = GetOrCreateListenerManager();
189 NS_ENSURE_STATE(elm);
190 elm->AddEventListener(aType, aListener, aUseCapture, aWantsUntrusted);
191 return NS_OK;
192 }
193
194 void
195 DOMEventTargetHelper::AddEventListener(const nsAString& aType,
196 EventListener* aListener,
197 bool aUseCapture,
198 const Nullable<bool>& aWantsUntrusted,
199 ErrorResult& aRv)
200 {
201 bool wantsUntrusted;
202 if (aWantsUntrusted.IsNull()) {
203 nsresult rv = WantsUntrusted(&wantsUntrusted);
204 if (NS_FAILED(rv)) {
205 aRv.Throw(rv);
206 return;
207 }
208 } else {
209 wantsUntrusted = aWantsUntrusted.Value();
210 }
211
212 EventListenerManager* elm = GetOrCreateListenerManager();
213 if (!elm) {
214 aRv.Throw(NS_ERROR_UNEXPECTED);
215 return;
216 }
217 elm->AddEventListener(aType, aListener, aUseCapture, wantsUntrusted);
218 }
219
220 NS_IMETHODIMP
221 DOMEventTargetHelper::AddSystemEventListener(const nsAString& aType,
222 nsIDOMEventListener* aListener,
223 bool aUseCapture,
224 bool aWantsUntrusted,
225 uint8_t aOptionalArgc)
226 {
227 NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1,
228 "Won't check if this is chrome, you want to set "
229 "aWantsUntrusted to false or make the aWantsUntrusted "
230 "explicit by making aOptionalArgc non-zero.");
231
232 if (aOptionalArgc < 2) {
233 nsresult rv = WantsUntrusted(&aWantsUntrusted);
234 NS_ENSURE_SUCCESS(rv, rv);
235 }
236
237 return NS_AddSystemEventListener(this, aType, aListener, aUseCapture,
238 aWantsUntrusted);
239 }
240
241 NS_IMETHODIMP
242 DOMEventTargetHelper::DispatchEvent(nsIDOMEvent* aEvent, bool* aRetVal)
243 {
244 nsEventStatus status = nsEventStatus_eIgnore;
245 nsresult rv =
246 EventDispatcher::DispatchDOMEvent(this, nullptr, aEvent, nullptr, &status);
247
248 *aRetVal = (status != nsEventStatus_eConsumeNoDefault);
249 return rv;
250 }
251
252 nsresult
253 DOMEventTargetHelper::DispatchTrustedEvent(const nsAString& aEventName)
254 {
255 nsCOMPtr<nsIDOMEvent> event;
256 NS_NewDOMEvent(getter_AddRefs(event), this, nullptr, nullptr);
257 nsresult rv = event->InitEvent(aEventName, false, false);
258 NS_ENSURE_SUCCESS(rv, rv);
259
260 return DispatchTrustedEvent(event);
261 }
262
263 nsresult
264 DOMEventTargetHelper::DispatchTrustedEvent(nsIDOMEvent* event)
265 {
266 event->SetTrusted(true);
267
268 bool dummy;
269 return DispatchEvent(event, &dummy);
270 }
271
272 nsresult
273 DOMEventTargetHelper::SetEventHandler(nsIAtom* aType,
274 JSContext* aCx,
275 const JS::Value& aValue)
276 {
277 nsRefPtr<EventHandlerNonNull> handler;
278 JS::Rooted<JSObject*> callable(aCx);
279 if (aValue.isObject() &&
280 JS_ObjectIsCallable(aCx, callable = &aValue.toObject())) {
281 handler = new EventHandlerNonNull(callable, dom::GetIncumbentGlobal());
282 }
283 SetEventHandler(aType, EmptyString(), handler);
284 return NS_OK;
285 }
286
287 void
288 DOMEventTargetHelper::GetEventHandler(nsIAtom* aType,
289 JSContext* aCx,
290 JS::Value* aValue)
291 {
292 EventHandlerNonNull* handler = GetEventHandler(aType, EmptyString());
293 if (handler) {
294 *aValue = JS::ObjectValue(*handler->Callable());
295 } else {
296 *aValue = JS::NullValue();
297 }
298 }
299
300 nsresult
301 DOMEventTargetHelper::PreHandleEvent(EventChainPreVisitor& aVisitor)
302 {
303 aVisitor.mCanHandle = true;
304 aVisitor.mParentTarget = nullptr;
305 return NS_OK;
306 }
307
308 nsresult
309 DOMEventTargetHelper::PostHandleEvent(EventChainPostVisitor& aVisitor)
310 {
311 return NS_OK;
312 }
313
314 nsresult
315 DOMEventTargetHelper::DispatchDOMEvent(WidgetEvent* aEvent,
316 nsIDOMEvent* aDOMEvent,
317 nsPresContext* aPresContext,
318 nsEventStatus* aEventStatus)
319 {
320 return EventDispatcher::DispatchDOMEvent(this, aEvent, aDOMEvent,
321 aPresContext, aEventStatus);
322 }
323
324 EventListenerManager*
325 DOMEventTargetHelper::GetOrCreateListenerManager()
326 {
327 if (!mListenerManager) {
328 mListenerManager = new EventListenerManager(this);
329 }
330
331 return mListenerManager;
332 }
333
334 EventListenerManager*
335 DOMEventTargetHelper::GetExistingListenerManager() const
336 {
337 return mListenerManager;
338 }
339
340 nsIScriptContext*
341 DOMEventTargetHelper::GetContextForEventHandlers(nsresult* aRv)
342 {
343 *aRv = CheckInnerWindowCorrectness();
344 if (NS_FAILED(*aRv)) {
345 return nullptr;
346 }
347 nsPIDOMWindow* owner = GetOwner();
348 return owner ? static_cast<nsGlobalWindow*>(owner)->GetContextInternal()
349 : nullptr;
350 }
351
352 nsresult
353 DOMEventTargetHelper::WantsUntrusted(bool* aRetVal)
354 {
355 nsresult rv;
356 nsIScriptContext* context = GetContextForEventHandlers(&rv);
357 NS_ENSURE_SUCCESS(rv, rv);
358 nsCOMPtr<nsIDocument> doc =
359 nsContentUtils::GetDocumentFromScriptContext(context);
360 // We can let listeners on workers to always handle all the events.
361 *aRetVal = (doc && !nsContentUtils::IsChromeDoc(doc)) || !NS_IsMainThread();
362 return rv;
363 }
364
365 void
366 DOMEventTargetHelper::EventListenerAdded(nsIAtom* aType)
367 {
368 ErrorResult rv;
369 EventListenerWasAdded(Substring(nsDependentAtomString(aType), 2), rv);
370 }
371
372 void
373 DOMEventTargetHelper::EventListenerRemoved(nsIAtom* aType)
374 {
375 ErrorResult rv;
376 EventListenerWasRemoved(Substring(nsDependentAtomString(aType), 2), rv);
377 }
378
379 } // namespace mozilla

mercurial