Bumping manifests a=b2g-bump
[gecko.git] / dom / events / DOMEventTargetHelper.cpp
blob0b8efa35584245814140488d929fd86eff5bb6cd
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/. */
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"
16 namespace mozilla {
18 using namespace dom;
20 NS_IMPL_CYCLE_COLLECTION_CLASS(DOMEventTargetHelper)
22 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(DOMEventTargetHelper)
23 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
24 NS_IMPL_CYCLE_COLLECTION_TRACE_END
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);
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())
40 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
41 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mListenerManager)
42 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
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
49 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(DOMEventTargetHelper)
50 if (tmp->IsBlack()) {
51 if (tmp->mListenerManager) {
52 tmp->mListenerManager->MarkForCC();
54 return true;
56 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
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
62 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(DOMEventTargetHelper)
63 return tmp->IsBlack();
64 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
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
74 NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMEventTargetHelper)
75 NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(DOMEventTargetHelper,
76 LastRelease())
78 NS_IMPL_DOMTARGET_DEFAULTS(DOMEventTargetHelper)
80 DOMEventTargetHelper::~DOMEventTargetHelper()
82 if (nsPIDOMWindow* owner = GetOwner()) {
83 static_cast<nsGlobalWindow*>(owner)->RemoveEventTargetObject(this);
85 if (mListenerManager) {
86 mListenerManager->Disconnect();
88 ReleaseWrapper(this);
91 void
92 DOMEventTargetHelper::BindToOwner(nsPIDOMWindow* aOwner)
94 MOZ_ASSERT_IF(aOwner, aOwner->IsInnerWindow());
95 nsCOMPtr<nsIGlobalObject> glob = do_QueryInterface(aOwner);
96 BindToOwner(glob);
99 void
100 DOMEventTargetHelper::BindToOwner(nsIGlobalObject* aOwner)
102 if (mParentObject) {
103 if (mOwnerWindow) {
104 static_cast<nsGlobalWindow*>(mOwnerWindow)->RemoveEventTargetObject(this);
105 mOwnerWindow = nullptr;
107 mParentObject = nullptr;
108 mHasOrHasHadOwnerWindow = false;
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 MOZ_ASSERT(mOwnerWindow->IsInnerWindow());
116 mHasOrHasHadOwnerWindow = true;
117 static_cast<nsGlobalWindow*>(mOwnerWindow)->AddEventTargetObject(this);
122 void
123 DOMEventTargetHelper::BindToOwner(DOMEventTargetHelper* aOther)
125 if (mOwnerWindow) {
126 static_cast<nsGlobalWindow*>(mOwnerWindow)->RemoveEventTargetObject(this);
127 mOwnerWindow = nullptr;
128 mParentObject = nullptr;
129 mHasOrHasHadOwnerWindow = false;
131 if (aOther) {
132 mHasOrHasHadOwnerWindow = aOther->HasOrHasHadOwner();
133 if (aOther->GetParentObject()) {
134 mParentObject = aOther->GetParentObject();
135 // Let's cache the result of this QI for fast access and off main thread usage
136 mOwnerWindow = nsCOMPtr<nsPIDOMWindow>(do_QueryInterface(mParentObject)).get();
137 if (mOwnerWindow) {
138 MOZ_ASSERT(mOwnerWindow->IsInnerWindow());
139 mHasOrHasHadOwnerWindow = true;
140 static_cast<nsGlobalWindow*>(mOwnerWindow)->AddEventTargetObject(this);
146 void
147 DOMEventTargetHelper::DisconnectFromOwner()
149 mOwnerWindow = nullptr;
150 mParentObject = nullptr;
151 // Event listeners can't be handled anymore, so we can release them here.
152 if (mListenerManager) {
153 mListenerManager->Disconnect();
154 mListenerManager = nullptr;
158 NS_IMETHODIMP
159 DOMEventTargetHelper::RemoveEventListener(const nsAString& aType,
160 nsIDOMEventListener* aListener,
161 bool aUseCapture)
163 EventListenerManager* elm = GetExistingListenerManager();
164 if (elm) {
165 elm->RemoveEventListener(aType, aListener, aUseCapture);
168 return NS_OK;
171 NS_IMPL_REMOVE_SYSTEM_EVENT_LISTENER(DOMEventTargetHelper)
173 NS_IMETHODIMP
174 DOMEventTargetHelper::AddEventListener(const nsAString& aType,
175 nsIDOMEventListener* aListener,
176 bool aUseCapture,
177 bool aWantsUntrusted,
178 uint8_t aOptionalArgc)
180 NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1,
181 "Won't check if this is chrome, you want to set "
182 "aWantsUntrusted to false or make the aWantsUntrusted "
183 "explicit by making aOptionalArgc non-zero.");
185 if (aOptionalArgc < 2) {
186 nsresult rv = WantsUntrusted(&aWantsUntrusted);
187 NS_ENSURE_SUCCESS(rv, rv);
190 EventListenerManager* elm = GetOrCreateListenerManager();
191 NS_ENSURE_STATE(elm);
192 elm->AddEventListener(aType, aListener, aUseCapture, aWantsUntrusted);
193 return NS_OK;
196 void
197 DOMEventTargetHelper::AddEventListener(const nsAString& aType,
198 EventListener* aListener,
199 bool aUseCapture,
200 const Nullable<bool>& aWantsUntrusted,
201 ErrorResult& aRv)
203 bool wantsUntrusted;
204 if (aWantsUntrusted.IsNull()) {
205 nsresult rv = WantsUntrusted(&wantsUntrusted);
206 if (NS_FAILED(rv)) {
207 aRv.Throw(rv);
208 return;
210 } else {
211 wantsUntrusted = aWantsUntrusted.Value();
214 EventListenerManager* elm = GetOrCreateListenerManager();
215 if (!elm) {
216 aRv.Throw(NS_ERROR_UNEXPECTED);
217 return;
219 elm->AddEventListener(aType, aListener, aUseCapture, wantsUntrusted);
222 NS_IMETHODIMP
223 DOMEventTargetHelper::AddSystemEventListener(const nsAString& aType,
224 nsIDOMEventListener* aListener,
225 bool aUseCapture,
226 bool aWantsUntrusted,
227 uint8_t aOptionalArgc)
229 NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1,
230 "Won't check if this is chrome, you want to set "
231 "aWantsUntrusted to false or make the aWantsUntrusted "
232 "explicit by making aOptionalArgc non-zero.");
234 if (aOptionalArgc < 2) {
235 nsresult rv = WantsUntrusted(&aWantsUntrusted);
236 NS_ENSURE_SUCCESS(rv, rv);
239 return NS_AddSystemEventListener(this, aType, aListener, aUseCapture,
240 aWantsUntrusted);
243 NS_IMETHODIMP
244 DOMEventTargetHelper::DispatchEvent(nsIDOMEvent* aEvent, bool* aRetVal)
246 nsEventStatus status = nsEventStatus_eIgnore;
247 nsresult rv =
248 EventDispatcher::DispatchDOMEvent(this, nullptr, aEvent, nullptr, &status);
250 *aRetVal = (status != nsEventStatus_eConsumeNoDefault);
251 return rv;
254 nsresult
255 DOMEventTargetHelper::DispatchTrustedEvent(const nsAString& aEventName)
257 nsCOMPtr<nsIDOMEvent> event;
258 NS_NewDOMEvent(getter_AddRefs(event), this, nullptr, nullptr);
259 nsresult rv = event->InitEvent(aEventName, false, false);
260 NS_ENSURE_SUCCESS(rv, rv);
262 return DispatchTrustedEvent(event);
265 nsresult
266 DOMEventTargetHelper::DispatchTrustedEvent(nsIDOMEvent* event)
268 event->SetTrusted(true);
270 bool dummy;
271 return DispatchEvent(event, &dummy);
274 nsresult
275 DOMEventTargetHelper::SetEventHandler(nsIAtom* aType,
276 JSContext* aCx,
277 const JS::Value& aValue)
279 nsRefPtr<EventHandlerNonNull> handler;
280 JS::Rooted<JSObject*> callable(aCx);
281 if (aValue.isObject() && JS::IsCallable(callable = &aValue.toObject())) {
282 handler = new EventHandlerNonNull(callable, dom::GetIncumbentGlobal());
284 SetEventHandler(aType, EmptyString(), handler);
285 return NS_OK;
288 void
289 DOMEventTargetHelper::GetEventHandler(nsIAtom* aType,
290 JSContext* aCx,
291 JS::Value* aValue)
293 EventHandlerNonNull* handler = GetEventHandler(aType, EmptyString());
294 if (handler) {
295 *aValue = JS::ObjectValue(*handler->Callable());
296 } else {
297 *aValue = JS::NullValue();
301 nsresult
302 DOMEventTargetHelper::PreHandleEvent(EventChainPreVisitor& aVisitor)
304 aVisitor.mCanHandle = true;
305 aVisitor.mParentTarget = nullptr;
306 return NS_OK;
309 nsresult
310 DOMEventTargetHelper::PostHandleEvent(EventChainPostVisitor& aVisitor)
312 return NS_OK;
315 nsresult
316 DOMEventTargetHelper::DispatchDOMEvent(WidgetEvent* aEvent,
317 nsIDOMEvent* aDOMEvent,
318 nsPresContext* aPresContext,
319 nsEventStatus* aEventStatus)
321 return EventDispatcher::DispatchDOMEvent(this, aEvent, aDOMEvent,
322 aPresContext, aEventStatus);
325 EventListenerManager*
326 DOMEventTargetHelper::GetOrCreateListenerManager()
328 if (!mListenerManager) {
329 mListenerManager = new EventListenerManager(this);
332 return mListenerManager;
335 EventListenerManager*
336 DOMEventTargetHelper::GetExistingListenerManager() const
338 return mListenerManager;
341 nsIScriptContext*
342 DOMEventTargetHelper::GetContextForEventHandlers(nsresult* aRv)
344 *aRv = CheckInnerWindowCorrectness();
345 if (NS_FAILED(*aRv)) {
346 return nullptr;
348 nsPIDOMWindow* owner = GetOwner();
349 return owner ? static_cast<nsGlobalWindow*>(owner)->GetContextInternal()
350 : nullptr;
353 nsresult
354 DOMEventTargetHelper::WantsUntrusted(bool* aRetVal)
356 nsresult rv;
357 nsIScriptContext* context = GetContextForEventHandlers(&rv);
358 NS_ENSURE_SUCCESS(rv, rv);
359 nsCOMPtr<nsIDocument> doc =
360 nsContentUtils::GetDocumentFromScriptContext(context);
361 // We can let listeners on workers to always handle all the events.
362 *aRetVal = (doc && !nsContentUtils::IsChromeDoc(doc)) || !NS_IsMainThread();
363 return rv;
366 void
367 DOMEventTargetHelper::EventListenerAdded(nsIAtom* aType)
369 ErrorResult rv;
370 EventListenerWasAdded(Substring(nsDependentAtomString(aType), 2), rv);
373 void
374 DOMEventTargetHelper::EventListenerRemoved(nsIAtom* aType)
376 ErrorResult rv;
377 EventListenerWasRemoved(Substring(nsDependentAtomString(aType), 2), rv);
380 } // namespace mozilla